summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/index.php17
-rw-r--r--src/license.txt385
-rw-r--r--src/readme.html95
-rw-r--r--src/wp-activate.php119
-rw-r--r--src/wp-admin/about.php173
-rw-r--r--src/wp-admin/admin-ajax.php77
-rw-r--r--src/wp-admin/admin-footer.php42
-rw-r--r--src/wp-admin/admin-functions.php15
-rw-r--r--src/wp-admin/admin-header.php138
-rw-r--r--src/wp-admin/admin-post.php31
-rw-r--r--src/wp-admin/admin.php230
-rw-r--r--src/wp-admin/async-upload.php98
-rw-r--r--src/wp-admin/comment.php294
-rw-r--r--src/wp-admin/credits.php161
-rw-r--r--src/wp-admin/css/color-picker-rtl.css27
-rw-r--r--src/wp-admin/css/color-picker.css107
-rw-r--r--src/wp-admin/css/colors-classic.css2259
-rw-r--r--src/wp-admin/css/colors-fresh.css2148
-rw-r--r--src/wp-admin/css/customize-controls-rtl.css77
-rw-r--r--src/wp-admin/css/customize-controls.css440
-rw-r--r--src/wp-admin/css/farbtastic.css52
-rw-r--r--src/wp-admin/css/ie-rtl.css240
-rw-r--r--src/wp-admin/css/ie.css642
-rw-r--r--src/wp-admin/css/install.css261
-rw-r--r--src/wp-admin/css/media-rtl.css71
-rw-r--r--src/wp-admin/css/media.css353
-rw-r--r--src/wp-admin/css/wp-admin-rtl.css2931
-rw-r--r--src/wp-admin/css/wp-admin.css9459
-rw-r--r--src/wp-admin/custom-background.php426
-rw-r--r--src/wp-admin/custom-header.php1015
-rw-r--r--src/wp-admin/customize.php210
-rw-r--r--src/wp-admin/edit-comments.php255
-rw-r--r--src/wp-admin/edit-form-advanced.php475
-rw-r--r--src/wp-admin/edit-form-comment.php146
-rw-r--r--src/wp-admin/edit-link-form.php138
-rw-r--r--src/wp-admin/edit-tag-form.php96
-rw-r--r--src/wp-admin/edit-tags.php420
-rw-r--r--src/wp-admin/edit.php300
-rw-r--r--src/wp-admin/export.php220
-rw-r--r--src/wp-admin/freedoms.php57
-rw-r--r--src/wp-admin/images/align-center-2x.pngbin0 -> 147 bytes
-rw-r--r--src/wp-admin/images/align-center.pngbin0 -> 546 bytes
-rw-r--r--src/wp-admin/images/align-left-2x.pngbin0 -> 143 bytes
-rw-r--r--src/wp-admin/images/align-left.pngbin0 -> 554 bytes
-rw-r--r--src/wp-admin/images/align-none-2x.pngbin0 -> 121 bytes
-rw-r--r--src/wp-admin/images/align-none.pngbin0 -> 417 bytes
-rw-r--r--src/wp-admin/images/align-right-2x.pngbin0 -> 142 bytes
-rw-r--r--src/wp-admin/images/align-right.pngbin0 -> 509 bytes
-rw-r--r--src/wp-admin/images/arrows-2x.pngbin0 -> 863 bytes
-rw-r--r--src/wp-admin/images/arrows-dark-2x.pngbin0 -> 719 bytes
-rw-r--r--src/wp-admin/images/arrows-dark-vs-2x.pngbin0 -> 761 bytes
-rw-r--r--src/wp-admin/images/arrows-dark-vs.pngbin0 -> 243 bytes
-rw-r--r--src/wp-admin/images/arrows-dark.pngbin0 -> 243 bytes
-rw-r--r--src/wp-admin/images/arrows-pr-2x.pngbin0 -> 723 bytes
-rw-r--r--src/wp-admin/images/arrows-pr.pngbin0 -> 461 bytes
-rw-r--r--src/wp-admin/images/arrows-vs-2x.pngbin0 -> 723 bytes
-rw-r--r--src/wp-admin/images/arrows-vs.pngbin0 -> 243 bytes
-rw-r--r--src/wp-admin/images/arrows.pngbin0 -> 243 bytes
-rw-r--r--src/wp-admin/images/bubble_bg-2x.gifbin0 -> 507 bytes
-rw-r--r--src/wp-admin/images/bubble_bg-rtl-2x.gifbin0 -> 499 bytes
-rw-r--r--src/wp-admin/images/bubble_bg-rtl.gifbin0 -> 400 bytes
-rw-r--r--src/wp-admin/images/bubble_bg.gifbin0 -> 395 bytes
-rw-r--r--src/wp-admin/images/comment-grey-bubble-2x.pngbin0 -> 259 bytes
-rw-r--r--src/wp-admin/images/comment-grey-bubble.pngbin0 -> 114 bytes
-rw-r--r--src/wp-admin/images/date-button-2x.gifbin0 -> 992 bytes
-rw-r--r--src/wp-admin/images/date-button.gifbin0 -> 400 bytes
-rw-r--r--src/wp-admin/images/generic.pngbin0 -> 719 bytes
-rw-r--r--src/wp-admin/images/icons32-2x.pngbin0 -> 35645 bytes
-rw-r--r--src/wp-admin/images/icons32-vs-2x.pngbin0 -> 37994 bytes
-rw-r--r--src/wp-admin/images/icons32-vs.pngbin0 -> 12920 bytes
-rw-r--r--src/wp-admin/images/icons32.pngbin0 -> 12989 bytes
-rw-r--r--src/wp-admin/images/imgedit-icons-2x.pngbin0 -> 14853 bytes
-rw-r--r--src/wp-admin/images/imgedit-icons.pngbin0 -> 6989 bytes
-rw-r--r--src/wp-admin/images/list-2x.pngbin0 -> 1523 bytes
-rw-r--r--src/wp-admin/images/list.pngbin0 -> 1003 bytes
-rw-r--r--src/wp-admin/images/loading.gifbin0 -> 2530 bytes
-rw-r--r--src/wp-admin/images/lock-2x.pngbin0 -> 716 bytes
-rw-r--r--src/wp-admin/images/lock.pngbin0 -> 338 bytes
-rw-r--r--src/wp-admin/images/marker.pngbin0 -> 377 bytes
-rw-r--r--src/wp-admin/images/mask.pngbin0 -> 2001 bytes
-rw-r--r--src/wp-admin/images/media-button-2x.pngbin0 -> 850 bytes
-rw-r--r--src/wp-admin/images/media-button-image.gifbin0 -> 206 bytes
-rw-r--r--src/wp-admin/images/media-button-music.gifbin0 -> 205 bytes
-rw-r--r--src/wp-admin/images/media-button-other.gifbin0 -> 245 bytes
-rw-r--r--src/wp-admin/images/media-button-video.gifbin0 -> 139 bytes
-rw-r--r--src/wp-admin/images/media-button.pngbin0 -> 323 bytes
-rw-r--r--src/wp-admin/images/menu-2x.pngbin0 -> 30324 bytes
-rw-r--r--src/wp-admin/images/menu-shadow-rtl.pngbin0 -> 92 bytes
-rw-r--r--src/wp-admin/images/menu-shadow.pngbin0 -> 89 bytes
-rw-r--r--src/wp-admin/images/menu-vs-2x.pngbin0 -> 29592 bytes
-rw-r--r--src/wp-admin/images/menu-vs.pngbin0 -> 9320 bytes
-rw-r--r--src/wp-admin/images/menu.pngbin0 -> 9165 bytes
-rw-r--r--src/wp-admin/images/no.pngbin0 -> 755 bytes
-rw-r--r--src/wp-admin/images/post-formats-vs.pngbin0 -> 2794 bytes
-rw-r--r--src/wp-admin/images/post-formats.pngbin0 -> 2220 bytes
-rw-r--r--src/wp-admin/images/post-formats32-vs.pngbin0 -> 7512 bytes
-rw-r--r--src/wp-admin/images/post-formats32.pngbin0 -> 7829 bytes
-rw-r--r--src/wp-admin/images/press-this-2x.pngbin0 -> 755 bytes
-rw-r--r--src/wp-admin/images/press-this.pngbin0 -> 417 bytes
-rw-r--r--src/wp-admin/images/resize-2x.gifbin0 -> 234 bytes
-rw-r--r--src/wp-admin/images/resize-rtl-2x.gifbin0 -> 232 bytes
-rw-r--r--src/wp-admin/images/resize-rtl.gifbin0 -> 1418 bytes
-rw-r--r--src/wp-admin/images/resize.gifbin0 -> 71 bytes
-rw-r--r--src/wp-admin/images/se.pngbin0 -> 120 bytes
-rw-r--r--src/wp-admin/images/sort-2x.gifbin0 -> 97 bytes
-rw-r--r--src/wp-admin/images/sort.gifbin0 -> 54 bytes
-rw-r--r--src/wp-admin/images/stars-2x.pngbin0 -> 1257 bytes
-rw-r--r--src/wp-admin/images/stars-rtl-2x.pngbin0 -> 3212 bytes
-rw-r--r--src/wp-admin/images/stars-rtl.pngbin0 -> 926 bytes
-rw-r--r--src/wp-admin/images/stars.pngbin0 -> 924 bytes
-rw-r--r--src/wp-admin/images/welcome-icons-2x.pngbin0 -> 6349 bytes
-rw-r--r--src/wp-admin/images/welcome-icons.pngbin0 -> 2152 bytes
-rw-r--r--src/wp-admin/images/wheel.pngbin0 -> 11505 bytes
-rw-r--r--src/wp-admin/images/wordpress-logo-2x.pngbin0 -> 4867 bytes
-rw-r--r--src/wp-admin/images/wordpress-logo.pngbin0 -> 2480 bytes
-rw-r--r--src/wp-admin/images/wp-badge-2x.pngbin0 -> 28160 bytes
-rw-r--r--src/wp-admin/images/wp-badge.pngbin0 -> 12099 bytes
-rw-r--r--src/wp-admin/images/wp-logo-2x.pngbin0 -> 1806 bytes
-rw-r--r--src/wp-admin/images/wp-logo-vs-2x.pngbin0 -> 2087 bytes
-rw-r--r--src/wp-admin/images/wp-logo-vs.pngbin0 -> 751 bytes
-rw-r--r--src/wp-admin/images/wp-logo.pngbin0 -> 661 bytes
-rw-r--r--src/wp-admin/images/wpspin_light-2x.gifbin0 -> 9097 bytes
-rw-r--r--src/wp-admin/images/wpspin_light.gifbin0 -> 2193 bytes
-rw-r--r--src/wp-admin/images/xit-2x.gifbin0 -> 823 bytes
-rw-r--r--src/wp-admin/images/xit.gifbin0 -> 182 bytes
-rw-r--r--src/wp-admin/images/yes.pngbin0 -> 539 bytes
-rw-r--r--src/wp-admin/import.php133
-rw-r--r--src/wp-admin/includes/admin.php72
-rw-r--r--src/wp-admin/includes/ajax-actions.php2125
-rw-r--r--src/wp-admin/includes/bookmark.php290
-rw-r--r--src/wp-admin/includes/class-ftp-pure.php190
-rw-r--r--src/wp-admin/includes/class-ftp-sockets.php250
-rw-r--r--src/wp-admin/includes/class-ftp.php907
-rw-r--r--src/wp-admin/includes/class-pclzip.php5687
-rw-r--r--src/wp-admin/includes/class-wp-comments-list-table.php561
-rw-r--r--src/wp-admin/includes/class-wp-filesystem-base.php333
-rw-r--r--src/wp-admin/includes/class-wp-filesystem-direct.php363
-rw-r--r--src/wp-admin/includes/class-wp-filesystem-ftpext.php393
-rw-r--r--src/wp-admin/includes/class-wp-filesystem-ftpsockets.php333
-rw-r--r--src/wp-admin/includes/class-wp-filesystem-ssh2.php386
-rw-r--r--src/wp-admin/includes/class-wp-importer.php302
-rw-r--r--src/wp-admin/includes/class-wp-links-list-table.php189
-rw-r--r--src/wp-admin/includes/class-wp-list-table.php920
-rw-r--r--src/wp-admin/includes/class-wp-media-list-table.php431
-rw-r--r--src/wp-admin/includes/class-wp-ms-sites-list-table.php344
-rw-r--r--src/wp-admin/includes/class-wp-ms-themes-list-table.php356
-rw-r--r--src/wp-admin/includes/class-wp-ms-users-list-table.php272
-rw-r--r--src/wp-admin/includes/class-wp-plugin-install-list-table.php238
-rw-r--r--src/wp-admin/includes/class-wp-plugins-list-table.php437
-rw-r--r--src/wp-admin/includes/class-wp-posts-list-table.php1071
-rw-r--r--src/wp-admin/includes/class-wp-terms-list-table.php378
-rw-r--r--src/wp-admin/includes/class-wp-theme-install-list-table.php394
-rw-r--r--src/wp-admin/includes/class-wp-themes-list-table.php253
-rw-r--r--src/wp-admin/includes/class-wp-upgrader.php1691
-rw-r--r--src/wp-admin/includes/class-wp-users-list-table.php324
-rw-r--r--src/wp-admin/includes/comment.php158
-rw-r--r--src/wp-admin/includes/continents-cities.php493
-rw-r--r--src/wp-admin/includes/dashboard.php1307
-rw-r--r--src/wp-admin/includes/deprecated.php1025
-rw-r--r--src/wp-admin/includes/export.php436
-rw-r--r--src/wp-admin/includes/file.php1071
-rw-r--r--src/wp-admin/includes/image-edit.php731
-rw-r--r--src/wp-admin/includes/image.php450
-rw-r--r--src/wp-admin/includes/import.php186
-rw-r--r--src/wp-admin/includes/list-table.php113
-rw-r--r--src/wp-admin/includes/media.php2659
-rw-r--r--src/wp-admin/includes/menu.php229
-rw-r--r--src/wp-admin/includes/meta-boxes.php1000
-rw-r--r--src/wp-admin/includes/misc.php667
-rw-r--r--src/wp-admin/includes/ms-deprecated.php78
-rw-r--r--src/wp-admin/includes/ms.php677
-rw-r--r--src/wp-admin/includes/nav-menu.php1288
-rw-r--r--src/wp-admin/includes/plugin-install.php407
-rw-r--r--src/wp-admin/includes/plugin.php1763
-rw-r--r--src/wp-admin/includes/post.php1429
-rw-r--r--src/wp-admin/includes/revision.php209
-rw-r--r--src/wp-admin/includes/schema.php975
-rw-r--r--src/wp-admin/includes/screen.php1080
-rw-r--r--src/wp-admin/includes/taxonomy.php252
-rw-r--r--src/wp-admin/includes/template.php1980
-rw-r--r--src/wp-admin/includes/theme-install.php194
-rw-r--r--src/wp-admin/includes/theme.php296
-rw-r--r--src/wp-admin/includes/update-core.php896
-rw-r--r--src/wp-admin/includes/update.php310
-rw-r--r--src/wp-admin/includes/upgrade.php2006
-rw-r--r--src/wp-admin/includes/user.php372
-rw-r--r--src/wp-admin/includes/widgets.php228
-rw-r--r--src/wp-admin/index.php136
-rw-r--r--src/wp-admin/install-helper.php198
-rw-r--r--src/wp-admin/install.php256
-rw-r--r--src/wp-admin/js/accordion.js55
-rw-r--r--src/wp-admin/js/cat.js5
-rw-r--r--src/wp-admin/js/categories.js0
-rw-r--r--src/wp-admin/js/color-picker.js132
-rw-r--r--src/wp-admin/js/comment.js49
-rw-r--r--src/wp-admin/js/common.js433
-rw-r--r--src/wp-admin/js/custom-background.js74
-rw-r--r--src/wp-admin/js/custom-fields.js0
-rw-r--r--src/wp-admin/js/custom-header.js60
-rw-r--r--src/wp-admin/js/customize-controls.js1004
-rw-r--r--src/wp-admin/js/dashboard.js117
-rw-r--r--src/wp-admin/js/edit-comments.js607
-rw-r--r--src/wp-admin/js/editor.js245
-rw-r--r--src/wp-admin/js/farbtastic.js276
-rw-r--r--src/wp-admin/js/gallery.js199
-rw-r--r--src/wp-admin/js/image-edit.js573
-rw-r--r--src/wp-admin/js/inline-edit-post.js331
-rw-r--r--src/wp-admin/js/inline-edit-tax.js118
-rw-r--r--src/wp-admin/js/iris.min.js4
-rw-r--r--src/wp-admin/js/link.js67
-rw-r--r--src/wp-admin/js/media-gallery.js25
-rw-r--r--src/wp-admin/js/media-upload.js88
-rw-r--r--src/wp-admin/js/media.js124
-rw-r--r--src/wp-admin/js/nav-menu.js1171
-rw-r--r--src/wp-admin/js/password-strength-meter.js36
-rw-r--r--src/wp-admin/js/plugin-install.js53
-rw-r--r--src/wp-admin/js/post.js921
-rw-r--r--src/wp-admin/js/postbox.js186
-rw-r--r--src/wp-admin/js/revisions.js1080
-rw-r--r--src/wp-admin/js/set-post-thumbnail.js21
-rw-r--r--src/wp-admin/js/tags.js68
-rw-r--r--src/wp-admin/js/theme-preview.js56
-rw-r--r--src/wp-admin/js/theme.js279
-rw-r--r--src/wp-admin/js/user-profile.js78
-rw-r--r--src/wp-admin/js/user-suggest.js13
-rw-r--r--src/wp-admin/js/widgets.js289
-rw-r--r--src/wp-admin/js/word-count.js42
-rw-r--r--src/wp-admin/js/wp-fullscreen.js725
-rw-r--r--src/wp-admin/js/xfn.js16
-rw-r--r--src/wp-admin/link-add.php29
-rw-r--r--src/wp-admin/link-manager.php100
-rw-r--r--src/wp-admin/link-parse-opml.php96
-rw-r--r--src/wp-admin/link.php120
-rw-r--r--src/wp-admin/load-scripts.php162
-rw-r--r--src/wp-admin/load-styles.php151
-rw-r--r--src/wp-admin/maint/repair.php114
-rw-r--r--src/wp-admin/media-new.php85
-rw-r--r--src/wp-admin/media-upload.php58
-rw-r--r--src/wp-admin/media.php147
-rw-r--r--src/wp-admin/menu-header.php189
-rw-r--r--src/wp-admin/menu.php242
-rw-r--r--src/wp-admin/moderation.php12
-rw-r--r--src/wp-admin/ms-admin.php13
-rw-r--r--src/wp-admin/ms-delete-site.php84
-rw-r--r--src/wp-admin/ms-edit.php13
-rw-r--r--src/wp-admin/ms-options.php12
-rw-r--r--src/wp-admin/ms-sites.php13
-rw-r--r--src/wp-admin/ms-themes.php13
-rw-r--r--src/wp-admin/ms-upgrade-network.php13
-rw-r--r--src/wp-admin/ms-users.php13
-rw-r--r--src/wp-admin/my-sites.php120
-rw-r--r--src/wp-admin/nav-menus.php764
-rw-r--r--src/wp-admin/network.php542
-rw-r--r--src/wp-admin/network/about.php16
-rw-r--r--src/wp-admin/network/admin.php24
-rw-r--r--src/wp-admin/network/credits.php16
-rw-r--r--src/wp-admin/network/edit.php27
-rw-r--r--src/wp-admin/network/freedoms.php16
-rw-r--r--src/wp-admin/network/index.php82
-rw-r--r--src/wp-admin/network/menu.php63
-rw-r--r--src/wp-admin/network/plugin-editor.php16
-rw-r--r--src/wp-admin/network/plugin-install.php19
-rw-r--r--src/wp-admin/network/plugins.php16
-rw-r--r--src/wp-admin/network/profile.php16
-rw-r--r--src/wp-admin/network/settings.php303
-rw-r--r--src/wp-admin/network/setup.php16
-rw-r--r--src/wp-admin/network/site-info.php180
-rw-r--r--src/wp-admin/network/site-new.php153
-rw-r--r--src/wp-admin/network/site-settings.php155
-rw-r--r--src/wp-admin/network/site-themes.php182
-rw-r--r--src/wp-admin/network/site-users.php310
-rw-r--r--src/wp-admin/network/sites.php257
-rw-r--r--src/wp-admin/network/theme-editor.php16
-rw-r--r--src/wp-admin/network/theme-install.php19
-rw-r--r--src/wp-admin/network/themes.php275
-rw-r--r--src/wp-admin/network/update-core.php16
-rw-r--r--src/wp-admin/network/update.php19
-rw-r--r--src/wp-admin/network/upgrade.php99
-rw-r--r--src/wp-admin/network/user-edit.php16
-rw-r--r--src/wp-admin/network/user-new.php107
-rw-r--r--src/wp-admin/network/users.php299
-rw-r--r--src/wp-admin/options-discussion.php252
-rw-r--r--src/wp-admin/options-general.php327
-rw-r--r--src/wp-admin/options-head.php18
-rw-r--r--src/wp-admin/options-media.php137
-rw-r--r--src/wp-admin/options-permalink.php285
-rw-r--r--src/wp-admin/options-reading.php170
-rw-r--r--src/wp-admin/options-writing.php181
-rw-r--r--src/wp-admin/options.php231
-rw-r--r--src/wp-admin/plugin-editor.php265
-rw-r--r--src/wp-admin/plugin-install.php72
-rw-r--r--src/wp-admin/plugins.php437
-rw-r--r--src/wp-admin/post-new.php66
-rw-r--r--src/wp-admin/post.php312
-rw-r--r--src/wp-admin/press-this.php653
-rw-r--r--src/wp-admin/profile.php18
-rw-r--r--src/wp-admin/revision.php210
-rw-r--r--src/wp-admin/setup-config.php295
-rw-r--r--src/wp-admin/theme-editor.php246
-rw-r--r--src/wp-admin/theme-install.php86
-rw-r--r--src/wp-admin/themes.php311
-rw-r--r--src/wp-admin/tools.php71
-rw-r--r--src/wp-admin/update-core.php546
-rw-r--r--src/wp-admin/update.php257
-rw-r--r--src/wp-admin/upgrade-functions.php12
-rw-r--r--src/wp-admin/upgrade.php115
-rw-r--r--src/wp-admin/upload.php250
-rw-r--r--src/wp-admin/user-edit.php442
-rw-r--r--src/wp-admin/user-new.php389
-rw-r--r--src/wp-admin/user/about.php13
-rw-r--r--src/wp-admin/user/admin.php25
-rw-r--r--src/wp-admin/user/credits.php13
-rw-r--r--src/wp-admin/user/freedoms.php13
-rw-r--r--src/wp-admin/user/index.php12
-rw-r--r--src/wp-admin/user/menu.php22
-rw-r--r--src/wp-admin/user/profile.php12
-rw-r--r--src/wp-admin/user/user-edit.php12
-rw-r--r--src/wp-admin/users.php458
-rw-r--r--src/wp-admin/widgets.php399
-rw-r--r--src/wp-blog-header.php18
-rw-r--r--src/wp-comments-post.php99
-rw-r--r--src/wp-config-sample.php90
-rw-r--r--src/wp-content/index.php2
-rw-r--r--src/wp-content/plugins/hello.php82
-rw-r--r--src/wp-content/plugins/index.php3
-rw-r--r--src/wp-content/themes/index.php3
-rw-r--r--src/wp-content/themes/twentyeleven/404.php48
-rw-r--r--src/wp-content/themes/twentyeleven/archive.php72
-rw-r--r--src/wp-content/themes/twentyeleven/author.php89
-rw-r--r--src/wp-content/themes/twentyeleven/category.php65
-rw-r--r--src/wp-content/themes/twentyeleven/colors/dark.css623
-rw-r--r--src/wp-content/themes/twentyeleven/comments.php78
-rw-r--r--src/wp-content/themes/twentyeleven/content-aside.php46
-rw-r--r--src/wp-content/themes/twentyeleven/content-featured.php47
-rw-r--r--src/wp-content/themes/twentyeleven/content-gallery.php88
-rw-r--r--src/wp-content/themes/twentyeleven/content-image.php70
-rw-r--r--src/wp-content/themes/twentyeleven/content-intro.php21
-rw-r--r--src/wp-content/themes/twentyeleven/content-link.php46
-rw-r--r--src/wp-content/themes/twentyeleven/content-page.php23
-rw-r--r--src/wp-content/themes/twentyeleven/content-quote.php74
-rw-r--r--src/wp-content/themes/twentyeleven/content-single.php71
-rw-r--r--src/wp-content/themes/twentyeleven/content-status.php47
-rw-r--r--src/wp-content/themes/twentyeleven/content.php84
-rw-r--r--src/wp-content/themes/twentyeleven/editor-style-rtl.css24
-rw-r--r--src/wp-content/themes/twentyeleven/editor-style.css312
-rw-r--r--src/wp-content/themes/twentyeleven/footer.php35
-rw-r--r--src/wp-content/themes/twentyeleven/functions.php671
-rw-r--r--src/wp-content/themes/twentyeleven/header.php139
-rw-r--r--src/wp-content/themes/twentyeleven/image.php104
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark-rtl.pngbin0 -> 255 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark.pngbin0 -> 237 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-rtl.pngbin0 -> 257 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor.pngbin0 -> 239 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-dark-rtl.pngbin0 -> 272 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-dark.pngbin0 -> 348 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow-rtl.pngbin0 -> 271 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-arrow.pngbin0 -> 250 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-bubble-dark-rtl.pngbin0 -> 856 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-bubble-dark.pngbin0 -> 872 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-bubble-rtl.pngbin0 -> 783 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/comment-bubble.pngbin0 -> 791 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpgbin0 -> 6420 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/chessboard.jpgbin0 -> 52548 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpgbin0 -> 4584 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/hanoi.jpgbin0 -> 39868 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpgbin0 -> 8195 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/lanterns.jpgbin0 -> 91152 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpgbin0 -> 3770 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpgbin0 -> 38272 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpgbin0 -> 6035 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/shore.jpgbin0 -> 77120 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpgbin0 -> 6385 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/trolley.jpgbin0 -> 62046 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpgbin0 -> 6460 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/wheel.jpgbin0 -> 59833 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpgbin0 -> 4297 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/headers/willow.jpgbin0 -> 64681 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/search.pngbin0 -> 440 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/images/wordpress.pngbin0 -> 794 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/inc/images/content-sidebar.pngbin0 -> 209 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/inc/images/content.pngbin0 -> 185 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/inc/images/dark.pngbin0 -> 5243 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/inc/images/light.pngbin0 -> 5354 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/inc/images/sidebar-content.pngbin0 -> 209 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/inc/theme-customizer.js12
-rw-r--r--src/wp-content/themes/twentyeleven/inc/theme-options.css35
-rw-r--r--src/wp-content/themes/twentyeleven/inc/theme-options.js52
-rw-r--r--src/wp-content/themes/twentyeleven/inc/theme-options.php531
-rw-r--r--src/wp-content/themes/twentyeleven/inc/widgets.php157
-rw-r--r--src/wp-content/themes/twentyeleven/index.php52
-rw-r--r--src/wp-content/themes/twentyeleven/js/html5.js6
-rw-r--r--src/wp-content/themes/twentyeleven/js/showcase.js17
-rw-r--r--src/wp-content/themes/twentyeleven/languages/twentyeleven.pot653
-rw-r--r--src/wp-content/themes/twentyeleven/license.txt281
-rw-r--r--src/wp-content/themes/twentyeleven/page.php31
-rw-r--r--src/wp-content/themes/twentyeleven/readme.txt5
-rw-r--r--src/wp-content/themes/twentyeleven/rtl.css582
-rw-r--r--src/wp-content/themes/twentyeleven/screenshot.pngbin0 -> 197796 bytes
-rw-r--r--src/wp-content/themes/twentyeleven/search.php57
-rw-r--r--src/wp-content/themes/twentyeleven/searchform.php14
-rw-r--r--src/wp-content/themes/twentyeleven/showcase.php227
-rw-r--r--src/wp-content/themes/twentyeleven/sidebar-footer.php42
-rw-r--r--src/wp-content/themes/twentyeleven/sidebar-page.php28
-rw-r--r--src/wp-content/themes/twentyeleven/sidebar.php36
-rw-r--r--src/wp-content/themes/twentyeleven/single.php32
-rw-r--r--src/wp-content/themes/twentyeleven/style.css2721
-rw-r--r--src/wp-content/themes/twentyeleven/tag.php65
-rw-r--r--src/wp-content/themes/twentyfourteen/404.php34
-rw-r--r--src/wp-content/themes/twentyfourteen/archive.php91
-rw-r--r--src/wp-content/themes/twentyfourteen/comments.php76
-rw-r--r--src/wp-content/themes/twentyfourteen/content-featured-post.php45
-rw-r--r--src/wp-content/themes/twentyfourteen/content-page.php27
-rw-r--r--src/wp-content/themes/twentyfourteen/content-post-format.php83
-rw-r--r--src/wp-content/themes/twentyfourteen/content-recent-formatted-post.php54
-rw-r--r--src/wp-content/themes/twentyfourteen/content-single.php83
-rw-r--r--src/wp-content/themes/twentyfourteen/content.php76
-rw-r--r--src/wp-content/themes/twentyfourteen/featured-content.php19
-rw-r--r--src/wp-content/themes/twentyfourteen/fonts/copying.txt7
-rw-r--r--src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.eotbin0 -> 5076 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.svg72
-rw-r--r--src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.ttfbin0 -> 9552 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.woffbin0 -> 6080 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/footer.php27
-rw-r--r--src/wp-content/themes/twentyfourteen/full-width-page.php65
-rw-r--r--src/wp-content/themes/twentyfourteen/functions.php446
-rw-r--r--src/wp-content/themes/twentyfourteen/header.php197
-rw-r--r--src/wp-content/themes/twentyfourteen/image.php120
-rw-r--r--src/wp-content/themes/twentyfourteen/images/pattern-dark.pngbin0 -> 963 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/images/pattern.pngbin0 -> 962 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/images/placeholder.pngbin0 -> 3466 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/inc/custom-header.php171
-rw-r--r--src/wp-content/themes/twentyfourteen/inc/customizer.php187
-rw-r--r--src/wp-content/themes/twentyfourteen/inc/template-tags.php208
-rw-r--r--src/wp-content/themes/twentyfourteen/index.php84
-rw-r--r--src/wp-content/themes/twentyfourteen/js/customizer.js19
-rw-r--r--src/wp-content/themes/twentyfourteen/js/html5.js7
-rw-r--r--src/wp-content/themes/twentyfourteen/js/keyboard-image-navigation.js14
-rw-r--r--src/wp-content/themes/twentyfourteen/js/theme.js128
-rw-r--r--src/wp-content/themes/twentyfourteen/languages/twentyfourteen.pot539
-rw-r--r--src/wp-content/themes/twentyfourteen/no-results.php34
-rw-r--r--src/wp-content/themes/twentyfourteen/page.php76
-rw-r--r--src/wp-content/themes/twentyfourteen/recent-formatted-posts.php120
-rw-r--r--src/wp-content/themes/twentyfourteen/rtl.css859
-rw-r--r--src/wp-content/themes/twentyfourteen/screenshot.pngbin0 -> 3861 bytes
-rw-r--r--src/wp-content/themes/twentyfourteen/search.php41
-rw-r--r--src/wp-content/themes/twentyfourteen/searchform.php13
-rw-r--r--src/wp-content/themes/twentyfourteen/sidebar-content.php33
-rw-r--r--src/wp-content/themes/twentyfourteen/sidebar-footer.php47
-rw-r--r--src/wp-content/themes/twentyfourteen/sidebar.php43
-rw-r--r--src/wp-content/themes/twentyfourteen/single.php35
-rw-r--r--src/wp-content/themes/twentyfourteen/style.css3381
-rw-r--r--src/wp-content/themes/twentyten/404.php30
-rw-r--r--src/wp-content/themes/twentyten/archive.php61
-rw-r--r--src/wp-content/themes/twentyten/attachment.php26
-rw-r--r--src/wp-content/themes/twentyten/author.php60
-rw-r--r--src/wp-content/themes/twentyten/category.php34
-rw-r--r--src/wp-content/themes/twentyten/comments.php77
-rw-r--r--src/wp-content/themes/twentyten/editor-style-rtl.css29
-rw-r--r--src/wp-content/themes/twentyten/editor-style.css297
-rw-r--r--src/wp-content/themes/twentyten/footer.php50
-rw-r--r--src/wp-content/themes/twentyten/functions.php556
-rw-r--r--src/wp-content/themes/twentyten/header.php108
-rw-r--r--src/wp-content/themes/twentyten/images/headers/berries-thumbnail.jpgbin0 -> 5626 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/berries.jpgbin0 -> 60505 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/cherryblossoms-thumbnail.jpgbin0 -> 6418 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/cherryblossoms.jpgbin0 -> 81579 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/concave-thumbnail.jpgbin0 -> 5692 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/concave.jpgbin0 -> 38292 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/fern-thumbnail.jpgbin0 -> 5496 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/fern.jpgbin0 -> 24856 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/forestfloor-thumbnail.jpgbin0 -> 6646 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/forestfloor.jpgbin0 -> 64595 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/inkwell-thumbnail.jpgbin0 -> 4039 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/inkwell.jpgbin0 -> 39133 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/path-thumbnail.jpgbin0 -> 4536 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/path.jpgbin0 -> 51488 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/sunset-thumbnail.jpgbin0 -> 2194 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/headers/sunset.jpgbin0 -> 22115 bytes
-rw-r--r--src/wp-content/themes/twentyten/images/wordpress.pngbin0 -> 794 bytes
-rw-r--r--src/wp-content/themes/twentyten/index.php32
-rw-r--r--src/wp-content/themes/twentyten/languages/twentyten.pot409
-rw-r--r--src/wp-content/themes/twentyten/license.txt281
-rw-r--r--src/wp-content/themes/twentyten/loop-attachment.php117
-rw-r--r--src/wp-content/themes/twentyten/loop-page.php36
-rw-r--r--src/wp-content/themes/twentyten/loop-single.php67
-rw-r--r--src/wp-content/themes/twentyten/loop.php180
-rw-r--r--src/wp-content/themes/twentyten/onecolumn-page.php31
-rw-r--r--src/wp-content/themes/twentyten/page.php32
-rw-r--r--src/wp-content/themes/twentyten/rtl.css285
-rw-r--r--src/wp-content/themes/twentyten/screenshot.pngbin0 -> 256242 bytes
-rw-r--r--src/wp-content/themes/twentyten/search.php37
-rw-r--r--src/wp-content/themes/twentyten/sidebar-footer.php60
-rw-r--r--src/wp-content/themes/twentyten/sidebar.php56
-rw-r--r--src/wp-content/themes/twentyten/single.php27
-rw-r--r--src/wp-content/themes/twentyten/style.css1378
-rw-r--r--src/wp-content/themes/twentyten/tag.php30
-rw-r--r--src/wp-content/themes/twentythirteen/404.php31
-rw-r--r--src/wp-content/themes/twentythirteen/archive.php55
-rw-r--r--src/wp-content/themes/twentythirteen/author-bio.php24
-rw-r--r--src/wp-content/themes/twentythirteen/author.php60
-rw-r--r--src/wp-content/themes/twentythirteen/category.php41
-rw-r--r--src/wp-content/themes/twentythirteen/comments.php59
-rw-r--r--src/wp-content/themes/twentythirteen/content-aside.php31
-rw-r--r--src/wp-content/themes/twentythirteen/content-audio.php37
-rw-r--r--src/wp-content/themes/twentythirteen/content-chat.php31
-rw-r--r--src/wp-content/themes/twentythirteen/content-gallery.php45
-rw-r--r--src/wp-content/themes/twentythirteen/content-image.php41
-rw-r--r--src/wp-content/themes/twentythirteen/content-link.php36
-rw-r--r--src/wp-content/themes/twentythirteen/content-none.php31
-rw-r--r--src/wp-content/themes/twentythirteen/content-quote.php27
-rw-r--r--src/wp-content/themes/twentythirteen/content-status.php25
-rw-r--r--src/wp-content/themes/twentythirteen/content-video.php41
-rw-r--r--src/wp-content/themes/twentythirteen/content.php55
-rw-r--r--src/wp-content/themes/twentythirteen/css/editor-style.css578
-rw-r--r--src/wp-content/themes/twentythirteen/css/ie.css284
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/COPYING.txt9
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/LICENSE.txt339
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.eotbin0 -> 10388 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.svg105
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.ttfbin0 -> 19864 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.woffbin0 -> 12156 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/fonts/genericons.css157
-rw-r--r--src/wp-content/themes/twentythirteen/footer.php27
-rw-r--r--src/wp-content/themes/twentythirteen/functions.php526
-rw-r--r--src/wp-content/themes/twentythirteen/header.php51
-rw-r--r--src/wp-content/themes/twentythirteen/image.php82
-rw-r--r--src/wp-content/themes/twentythirteen/images/dotted-line-2x.pngbin0 -> 86 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/dotted-line-light-2x.pngbin0 -> 85 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/dotted-line-light.pngbin0 -> 80 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/dotted-line.pngbin0 -> 80 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/headers/circle-thumbnail.pngbin0 -> 8001 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/headers/circle.pngbin0 -> 33848 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/headers/diamond-thumbnail.pngbin0 -> 1847 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/headers/diamond.pngbin0 -> 14266 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/headers/star-thumbnail.pngbin0 -> 4039 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/headers/star.pngbin0 -> 22620 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/search-icon-2x.pngbin0 -> 829 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/images/search-icon.pngbin0 -> 422 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/inc/back-compat.php68
-rw-r--r--src/wp-content/themes/twentythirteen/inc/custom-header.php215
-rw-r--r--src/wp-content/themes/twentythirteen/index.php38
-rw-r--r--src/wp-content/themes/twentythirteen/js/functions.js81
-rw-r--r--src/wp-content/themes/twentythirteen/js/html5.js7
-rw-r--r--src/wp-content/themes/twentythirteen/js/theme-customizer.js40
-rw-r--r--src/wp-content/themes/twentythirteen/languages/twentythirteen.pot329
-rw-r--r--src/wp-content/themes/twentythirteen/page.php50
-rw-r--r--src/wp-content/themes/twentythirteen/rtl.css766
-rw-r--r--src/wp-content/themes/twentythirteen/screenshot.pngbin0 -> 54593 bytes
-rw-r--r--src/wp-content/themes/twentythirteen/search.php36
-rw-r--r--src/wp-content/themes/twentythirteen/sidebar-main.php18
-rw-r--r--src/wp-content/themes/twentythirteen/sidebar.php20
-rw-r--r--src/wp-content/themes/twentythirteen/single.php28
-rw-r--r--src/wp-content/themes/twentythirteen/style.css3121
-rw-r--r--src/wp-content/themes/twentythirteen/tag.php43
-rw-r--r--src/wp-content/themes/twentythirteen/taxonomy-post_format.php41
-rw-r--r--src/wp-content/themes/twentytwelve/404.php29
-rw-r--r--src/wp-content/themes/twentytwelve/archive.php63
-rw-r--r--src/wp-content/themes/twentytwelve/author.php74
-rw-r--r--src/wp-content/themes/twentytwelve/category.php51
-rw-r--r--src/wp-content/themes/twentytwelve/comments.php60
-rw-r--r--src/wp-content/themes/twentytwelve/content-aside.php28
-rw-r--r--src/wp-content/themes/twentytwelve/content-image.php28
-rw-r--r--src/wp-content/themes/twentytwelve/content-link.php26
-rw-r--r--src/wp-content/themes/twentytwelve/content-none.php20
-rw-r--r--src/wp-content/themes/twentytwelve/content-page.php26
-rw-r--r--src/wp-content/themes/twentytwelve/content-quote.php25
-rw-r--r--src/wp-content/themes/twentytwelve/content-status.php32
-rw-r--r--src/wp-content/themes/twentytwelve/content.php64
-rw-r--r--src/wp-content/themes/twentytwelve/css/ie.css243
-rw-r--r--src/wp-content/themes/twentytwelve/editor-style-rtl.css28
-rw-r--r--src/wp-content/themes/twentytwelve/editor-style.css342
-rw-r--r--src/wp-content/themes/twentytwelve/footer.php24
-rw-r--r--src/wp-content/themes/twentytwelve/functions.php486
-rw-r--r--src/wp-content/themes/twentytwelve/header.php54
-rw-r--r--src/wp-content/themes/twentytwelve/image.php106
-rw-r--r--src/wp-content/themes/twentytwelve/inc/custom-header.php165
-rw-r--r--src/wp-content/themes/twentytwelve/index.php66
-rw-r--r--src/wp-content/themes/twentytwelve/js/html5.js7
-rw-r--r--src/wp-content/themes/twentytwelve/js/navigation.js33
-rw-r--r--src/wp-content/themes/twentytwelve/js/theme-customizer.js64
-rw-r--r--src/wp-content/themes/twentytwelve/languages/twentytwelve.pot353
-rw-r--r--src/wp-content/themes/twentytwelve/page-templates/front-page.php35
-rw-r--r--src/wp-content/themes/twentytwelve/page-templates/full-width.php30
-rw-r--r--src/wp-content/themes/twentytwelve/page.php29
-rw-r--r--src/wp-content/themes/twentytwelve/rtl.css237
-rw-r--r--src/wp-content/themes/twentytwelve/screenshot.pngbin0 -> 171045 bytes
-rw-r--r--src/wp-content/themes/twentytwelve/search.php49
-rw-r--r--src/wp-content/themes/twentytwelve/sidebar-front.php35
-rw-r--r--src/wp-content/themes/twentytwelve/sidebar.php17
-rw-r--r--src/wp-content/themes/twentytwelve/single.php33
-rw-r--r--src/wp-content/themes/twentytwelve/style.css1742
-rw-r--r--src/wp-content/themes/twentytwelve/tag.php51
-rw-r--r--src/wp-cron.php104
-rw-r--r--src/wp-includes/ID3/getid3.lib.php1341
-rw-r--r--src/wp-includes/ID3/getid3.php1776
-rw-r--r--src/wp-includes/ID3/license.commercial.txt27
-rw-r--r--src/wp-includes/ID3/license.txt28
-rw-r--r--src/wp-includes/ID3/module.audio-video.asf.php2019
-rw-r--r--src/wp-includes/ID3/module.audio-video.flv.php729
-rw-r--r--src/wp-includes/ID3/module.audio-video.matroska.php1765
-rw-r--r--src/wp-includes/ID3/module.audio-video.quicktime.php2221
-rw-r--r--src/wp-includes/ID3/module.audio-video.riff.php2435
-rw-r--r--src/wp-includes/ID3/module.audio.ac3.php473
-rw-r--r--src/wp-includes/ID3/module.audio.dts.php290
-rw-r--r--src/wp-includes/ID3/module.audio.flac.php442
-rw-r--r--src/wp-includes/ID3/module.audio.mp3.php2009
-rw-r--r--src/wp-includes/ID3/module.audio.ogg.php671
-rw-r--r--src/wp-includes/ID3/module.tag.apetag.php370
-rw-r--r--src/wp-includes/ID3/module.tag.id3v1.php359
-rw-r--r--src/wp-includes/ID3/module.tag.id3v2.php3414
-rw-r--r--src/wp-includes/ID3/module.tag.lyrics3.php294
-rw-r--r--src/wp-includes/ID3/readme.txt603
-rw-r--r--src/wp-includes/SimplePie/Author.php157
-rw-r--r--src/wp-includes/SimplePie/Cache.php133
-rw-r--r--src/wp-includes/SimplePie/Cache/Base.php114
-rw-r--r--src/wp-includes/SimplePie/Cache/DB.php137
-rw-r--r--src/wp-includes/SimplePie/Cache/File.php173
-rw-r--r--src/wp-includes/SimplePie/Cache/Memcache.php183
-rw-r--r--src/wp-includes/SimplePie/Cache/MySQL.php438
-rw-r--r--src/wp-includes/SimplePie/Caption.php210
-rw-r--r--src/wp-includes/SimplePie/Category.php157
-rw-r--r--src/wp-includes/SimplePie/Content/Type/Sniffer.php332
-rw-r--r--src/wp-includes/SimplePie/Copyright.php130
-rw-r--r--src/wp-includes/SimplePie/Core.php57
-rw-r--r--src/wp-includes/SimplePie/Credit.php156
-rw-r--r--src/wp-includes/SimplePie/Decode/HTML/Entities.php617
-rw-r--r--src/wp-includes/SimplePie/Enclosure.php1380
-rw-r--r--src/wp-includes/SimplePie/Exception.php52
-rw-r--r--src/wp-includes/SimplePie/File.php292
-rw-r--r--src/wp-includes/SimplePie/HTTP/Parser.php500
-rw-r--r--src/wp-includes/SimplePie/IRI.php1238
-rw-r--r--src/wp-includes/SimplePie/Item.php2964
-rw-r--r--src/wp-includes/SimplePie/Locator.php372
-rw-r--r--src/wp-includes/SimplePie/Misc.php2247
-rw-r--r--src/wp-includes/SimplePie/Net/IPv6.php276
-rw-r--r--src/wp-includes/SimplePie/Parse/Date.php983
-rw-r--r--src/wp-includes/SimplePie/Parser.php407
-rw-r--r--src/wp-includes/SimplePie/Rating.php129
-rw-r--r--src/wp-includes/SimplePie/Registry.php225
-rw-r--r--src/wp-includes/SimplePie/Restriction.php155
-rw-r--r--src/wp-includes/SimplePie/Sanitize.php554
-rw-r--r--src/wp-includes/SimplePie/Source.php611
-rw-r--r--src/wp-includes/SimplePie/XML/Declaration/Parser.php362
-rw-r--r--src/wp-includes/SimplePie/gzdecode.php371
-rw-r--r--src/wp-includes/Text/Diff.php450
-rw-r--r--src/wp-includes/Text/Diff/Engine/native.php436
-rw-r--r--src/wp-includes/Text/Diff/Engine/shell.php162
-rw-r--r--src/wp-includes/Text/Diff/Engine/string.php248
-rw-r--r--src/wp-includes/Text/Diff/Engine/xdiff.php64
-rw-r--r--src/wp-includes/Text/Diff/Renderer.php235
-rw-r--r--src/wp-includes/Text/Diff/Renderer/inline.php206
-rw-r--r--src/wp-includes/admin-bar.php792
-rw-r--r--src/wp-includes/atomlib.php352
-rw-r--r--src/wp-includes/author-template.php392
-rw-r--r--src/wp-includes/bookmark-template.php257
-rw-r--r--src/wp-includes/bookmark.php387
-rw-r--r--src/wp-includes/cache.php653
-rw-r--r--src/wp-includes/canonical.php536
-rw-r--r--src/wp-includes/capabilities.php1468
-rw-r--r--src/wp-includes/category-template.php1191
-rw-r--r--src/wp-includes/category.php336
-rw-r--r--src/wp-includes/class-IXR.php1070
-rw-r--r--src/wp-includes/class-feed.php130
-rw-r--r--src/wp-includes/class-http.php1977
-rw-r--r--src/wp-includes/class-json.php936
-rw-r--r--src/wp-includes/class-oembed.php351
-rw-r--r--src/wp-includes/class-phpass.php260
-rw-r--r--src/wp-includes/class-phpmailer.php2826
-rw-r--r--src/wp-includes/class-pop3.php652
-rw-r--r--src/wp-includes/class-simplepie.php3119
-rw-r--r--src/wp-includes/class-smtp.php1003
-rw-r--r--src/wp-includes/class-snoopy.php1256
-rw-r--r--src/wp-includes/class-wp-admin-bar.php492
-rw-r--r--src/wp-includes/class-wp-ajax-response.php139
-rw-r--r--src/wp-includes/class-wp-customize-control.php817
-rw-r--r--src/wp-includes/class-wp-customize-manager.php1059
-rw-r--r--src/wp-includes/class-wp-customize-section.php93
-rw-r--r--src/wp-includes/class-wp-customize-setting.php439
-rw-r--r--src/wp-includes/class-wp-editor.php887
-rw-r--r--src/wp-includes/class-wp-embed.php277
-rw-r--r--src/wp-includes/class-wp-error.php208
-rw-r--r--src/wp-includes/class-wp-http-ixr-client.php92
-rw-r--r--src/wp-includes/class-wp-image-editor-gd.php422
-rw-r--r--src/wp-includes/class-wp-image-editor-imagick.php477
-rw-r--r--src/wp-includes/class-wp-image-editor.php403
-rw-r--r--src/wp-includes/class-wp-theme.php1200
-rw-r--r--src/wp-includes/class-wp-walker.php397
-rw-r--r--src/wp-includes/class-wp-xmlrpc-server.php5522
-rw-r--r--src/wp-includes/class-wp.php645
-rw-r--r--src/wp-includes/class.wp-dependencies.php261
-rw-r--r--src/wp-includes/class.wp-scripts.php217
-rw-r--r--src/wp-includes/class.wp-styles.php170
-rw-r--r--src/wp-includes/comment-template.php1682
-rw-r--r--src/wp-includes/comment.php2083
-rw-r--r--src/wp-includes/compat.php96
-rw-r--r--src/wp-includes/cron.php414
-rw-r--r--src/wp-includes/css/admin-bar-rtl.css201
-rw-r--r--src/wp-includes/css/admin-bar.css689
-rw-r--r--src/wp-includes/css/buttons.css288
-rw-r--r--src/wp-includes/css/editor.css2289
-rw-r--r--src/wp-includes/css/jquery-ui-dialog.css307
-rw-r--r--src/wp-includes/css/media-views-rtl.css312
-rw-r--r--src/wp-includes/css/media-views.css1673
-rw-r--r--src/wp-includes/css/wp-auth-check.css94
-rw-r--r--src/wp-includes/css/wp-pointer.css228
-rw-r--r--src/wp-includes/default-constants.php309
-rw-r--r--src/wp-includes/default-filters.php308
-rw-r--r--src/wp-includes/default-widgets.php1206
-rw-r--r--src/wp-includes/deprecated.php3380
-rw-r--r--src/wp-includes/feed-atom-comments.php86
-rw-r--r--src/wp-includes/feed-atom.php55
-rw-r--r--src/wp-includes/feed-rdf.php54
-rw-r--r--src/wp-includes/feed-rss.php31
-rw-r--r--src/wp-includes/feed-rss2-comments.php65
-rw-r--r--src/wp-includes/feed-rss2.php61
-rw-r--r--src/wp-includes/feed.php552
-rw-r--r--src/wp-includes/formatting.php3432
-rw-r--r--src/wp-includes/functions.php4043
-rw-r--r--src/wp-includes/functions.wp-scripts.php205
-rw-r--r--src/wp-includes/functions.wp-styles.php218
-rw-r--r--src/wp-includes/general-template.php2339
-rw-r--r--src/wp-includes/http.php519
-rw-r--r--src/wp-includes/images/admin-bar-sprite-2x.pngbin0 -> 4122 bytes
-rw-r--r--src/wp-includes/images/admin-bar-sprite.pngbin0 -> 2470 bytes
-rw-r--r--src/wp-includes/images/arrow-pointer-blue-2x.pngbin0 -> 52574 bytes
-rw-r--r--src/wp-includes/images/arrow-pointer-blue.pngbin0 -> 793 bytes
-rw-r--r--src/wp-includes/images/blank.gifbin0 -> 43 bytes
-rw-r--r--src/wp-includes/images/crystal/archive.pngbin0 -> 2897 bytes
-rw-r--r--src/wp-includes/images/crystal/audio.pngbin0 -> 2595 bytes
-rw-r--r--src/wp-includes/images/crystal/code.pngbin0 -> 1604 bytes
-rw-r--r--src/wp-includes/images/crystal/default.pngbin0 -> 490 bytes
-rw-r--r--src/wp-includes/images/crystal/document.pngbin0 -> 2230 bytes
-rw-r--r--src/wp-includes/images/crystal/interactive.pngbin0 -> 2680 bytes
-rw-r--r--src/wp-includes/images/crystal/license.txt9
-rw-r--r--src/wp-includes/images/crystal/spreadsheet.pngbin0 -> 2680 bytes
-rw-r--r--src/wp-includes/images/crystal/text.pngbin0 -> 707 bytes
-rw-r--r--src/wp-includes/images/crystal/video.pngbin0 -> 1339 bytes
-rw-r--r--src/wp-includes/images/down_arrow-2x.gifbin0 -> 83 bytes
-rw-r--r--src/wp-includes/images/down_arrow.gifbin0 -> 60 bytes
-rw-r--r--src/wp-includes/images/icon-pointer-flag-2x.pngbin0 -> 1369 bytes
-rw-r--r--src/wp-includes/images/icon-pointer-flag.pngbin0 -> 783 bytes
-rw-r--r--src/wp-includes/images/rss-2x.pngbin0 -> 1306 bytes
-rw-r--r--src/wp-includes/images/rss.pngbin0 -> 608 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_arrow.gifbin0 -> 170 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_biggrin.gifbin0 -> 172 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_confused.gifbin0 -> 171 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_cool.gifbin0 -> 172 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_cry.gifbin0 -> 498 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_eek.gifbin0 -> 170 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_evil.gifbin0 -> 236 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_exclaim.gifbin0 -> 236 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_idea.gifbin0 -> 176 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_lol.gifbin0 -> 336 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_mad.gifbin0 -> 174 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_mrgreen.gifbin0 -> 349 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_neutral.gifbin0 -> 171 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_question.gifbin0 -> 248 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_razz.gifbin0 -> 176 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_redface.gifbin0 -> 650 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_rolleyes.gifbin0 -> 485 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_sad.gifbin0 -> 171 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_smile.gifbin0 -> 174 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_surprised.gifbin0 -> 174 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_twisted.gifbin0 -> 238 bytes
-rw-r--r--src/wp-includes/images/smilies/icon_wink.gifbin0 -> 170 bytes
-rw-r--r--src/wp-includes/images/toggle-arrow-2x.pngbin0 -> 354 bytes
-rw-r--r--src/wp-includes/images/toggle-arrow.pngbin0 -> 333 bytes
-rw-r--r--src/wp-includes/images/uploader-icons-2x.pngbin0 -> 3915 bytes
-rw-r--r--src/wp-includes/images/uploader-icons.pngbin0 -> 1593 bytes
-rw-r--r--src/wp-includes/images/wlw/wp-comments.pngbin0 -> 1373 bytes
-rw-r--r--src/wp-includes/images/wlw/wp-icon.pngbin0 -> 664 bytes
-rw-r--r--src/wp-includes/images/wlw/wp-watermark.pngbin0 -> 5102 bytes
-rw-r--r--src/wp-includes/images/wpicons-2x.pngbin0 -> 125467 bytes
-rw-r--r--src/wp-includes/images/wpicons.pngbin0 -> 16089 bytes
-rw-r--r--src/wp-includes/images/wpmini-blue-2x.pngbin0 -> 2087 bytes
-rw-r--r--src/wp-includes/images/wpmini-blue.pngbin0 -> 751 bytes
-rw-r--r--src/wp-includes/images/wpspin-2x.gifbin0 -> 9097 bytes
-rw-r--r--src/wp-includes/images/wpspin.gifbin0 -> 2193 bytes
-rw-r--r--src/wp-includes/images/xit-2x.gifbin0 -> 823 bytes
-rw-r--r--src/wp-includes/images/xit.gifbin0 -> 182 bytes
-rw-r--r--src/wp-includes/js/admin-bar.js343
-rw-r--r--src/wp-includes/js/autosave.js702
-rw-r--r--src/wp-includes/js/backbone.min.js7
-rw-r--r--src/wp-includes/js/colorpicker.js707
-rw-r--r--src/wp-includes/js/comment-reply.js48
-rw-r--r--src/wp-includes/js/crop/cropper.css165
-rw-r--r--src/wp-includes/js/crop/cropper.js516
-rw-r--r--src/wp-includes/js/crop/marqueeHoriz.gifbin0 -> 277 bytes
-rw-r--r--src/wp-includes/js/crop/marqueeVert.gifbin0 -> 293 bytes
-rw-r--r--src/wp-includes/js/customize-base.js585
-rw-r--r--src/wp-includes/js/customize-loader.js164
-rw-r--r--src/wp-includes/js/customize-preview.js146
-rw-r--r--src/wp-includes/js/heartbeat.js461
-rw-r--r--src/wp-includes/js/hoverIntent.js115
-rw-r--r--src/wp-includes/js/imgareaselect/border-anim-h.gifbin0 -> 178 bytes
-rw-r--r--src/wp-includes/js/imgareaselect/border-anim-v.gifbin0 -> 178 bytes
-rw-r--r--src/wp-includes/js/imgareaselect/imgareaselect.css41
-rw-r--r--src/wp-includes/js/imgareaselect/jquery.imgareaselect.js1198
-rw-r--r--src/wp-includes/js/imgareaselect/jquery.imgareaselect.min.js1
-rw-r--r--src/wp-includes/js/jcrop/Jcrop.gifbin0 -> 323 bytes
-rw-r--r--src/wp-includes/js/jcrop/jquery.Jcrop.min.css28
-rw-r--r--src/wp-includes/js/jcrop/jquery.Jcrop.min.js22
-rw-r--r--src/wp-includes/js/jquery/jquery-migrate.js521
-rw-r--r--src/wp-includes/js/jquery/jquery-migrate.min.js2
-rw-r--r--src/wp-includes/js/jquery/jquery.color.min.js2
-rw-r--r--src/wp-includes/js/jquery/jquery.form.js825
-rw-r--r--src/wp-includes/js/jquery/jquery.form.min.js11
-rw-r--r--src/wp-includes/js/jquery/jquery.hotkeys.js131
-rw-r--r--src/wp-includes/js/jquery/jquery.hotkeys.min.js1
-rw-r--r--src/wp-includes/js/jquery/jquery.js7
-rw-r--r--src/wp-includes/js/jquery/jquery.masonry.min.js10
-rw-r--r--src/wp-includes/js/jquery/jquery.query.js11
-rw-r--r--src/wp-includes/js/jquery/jquery.schedule.js36
-rw-r--r--src/wp-includes/js/jquery/jquery.serialize-object.js31
-rw-r--r--src/wp-includes/js/jquery/jquery.table-hotkeys.js99
-rw-r--r--src/wp-includes/js/jquery/jquery.table-hotkeys.min.js1
-rw-r--r--src/wp-includes/js/jquery/jquery.ui.touch-punch.js11
-rw-r--r--src/wp-includes/js/jquery/suggest.js315
-rw-r--r--src/wp-includes/js/jquery/suggest.min.js1
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.accordion.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.button.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.core.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js5
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.dialog.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.draggable.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.droppable.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.effect.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.menu.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.mouse.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.position.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.resizable.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.selectable.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.slider.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.sortable.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.spinner.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.tabs.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js4
-rw-r--r--src/wp-includes/js/jquery/ui/jquery.ui.widget.min.js4
-rw-r--r--src/wp-includes/js/json2.js480
-rw-r--r--src/wp-includes/js/mce-view.js349
-rw-r--r--src/wp-includes/js/media-editor.js708
-rw-r--r--src/wp-includes/js/media-models.js862
-rw-r--r--src/wp-includes/js/media-views.js3966
-rw-r--r--src/wp-includes/js/mediaelement/background.pngbin0 -> 166 bytes
-rw-r--r--src/wp-includes/js/mediaelement/bigplay.pngbin0 -> 3001 bytes
-rw-r--r--src/wp-includes/js/mediaelement/bigplay.svg1
-rw-r--r--src/wp-includes/js/mediaelement/controls.pngbin0 -> 1892 bytes
-rw-r--r--src/wp-includes/js/mediaelement/controls.svg1
-rw-r--r--src/wp-includes/js/mediaelement/flashmediaelement.swfbin0 -> 29142 bytes
-rw-r--r--src/wp-includes/js/mediaelement/loading.gifbin0 -> 6224 bytes
-rw-r--r--src/wp-includes/js/mediaelement/mediaelement-and-player.min.js173
-rw-r--r--src/wp-includes/js/mediaelement/mediaelementplayer.min.css1
-rw-r--r--src/wp-includes/js/mediaelement/silverlightmediaelement.xapbin0 -> 12461 bytes
-rw-r--r--src/wp-includes/js/mediaelement/wp-mediaelement.css15
-rw-r--r--src/wp-includes/js/mediaelement/wp-mediaelement.js15
-rw-r--r--src/wp-includes/js/plupload/changelog.txt241
-rw-r--r--src/wp-includes/js/plupload/handlers.js491
-rw-r--r--src/wp-includes/js/plupload/license.txt339
-rw-r--r--src/wp-includes/js/plupload/plupload.flash.js1
-rw-r--r--src/wp-includes/js/plupload/plupload.flash.swfbin0 -> 18958 bytes
-rw-r--r--src/wp-includes/js/plupload/plupload.html4.js1
-rw-r--r--src/wp-includes/js/plupload/plupload.html5.js1
-rw-r--r--src/wp-includes/js/plupload/plupload.js2
-rw-r--r--src/wp-includes/js/plupload/plupload.silverlight.js1
-rw-r--r--src/wp-includes/js/plupload/plupload.silverlight.xapbin0 -> 44139 bytes
-rw-r--r--src/wp-includes/js/plupload/wp-plupload.js343
-rw-r--r--src/wp-includes/js/quicktags.js620
-rw-r--r--src/wp-includes/js/shortcode.js342
-rw-r--r--src/wp-includes/js/swfobject.js4
-rw-r--r--src/wp-includes/js/swfupload/handlers.js375
-rw-r--r--src/wp-includes/js/swfupload/handlers.min.js1
-rw-r--r--src/wp-includes/js/swfupload/license.txt32
-rw-r--r--src/wp-includes/js/swfupload/plugins/swfupload.cookies.js53
-rw-r--r--src/wp-includes/js/swfupload/plugins/swfupload.queue.js98
-rw-r--r--src/wp-includes/js/swfupload/plugins/swfupload.speed.js342
-rw-r--r--src/wp-includes/js/swfupload/plugins/swfupload.swfobject.js105
-rw-r--r--src/wp-includes/js/swfupload/swfupload.js980
-rw-r--r--src/wp-includes/js/swfupload/swfupload.swfbin0 -> 13133 bytes
-rw-r--r--src/wp-includes/js/thickbox/loadingAnimation.gifbin0 -> 15238 bytes
-rw-r--r--src/wp-includes/js/thickbox/macFFBgHack.pngbin0 -> 94 bytes
-rw-r--r--src/wp-includes/js/thickbox/tb-close-2x.pngbin0 -> 412 bytes
-rw-r--r--src/wp-includes/js/thickbox/tb-close.pngbin0 -> 387 bytes
-rw-r--r--src/wp-includes/js/thickbox/thickbox.css178
-rw-r--r--src/wp-includes/js/thickbox/thickbox.js319
-rw-r--r--src/wp-includes/js/tinymce/langs/wp-langs-en.js504
-rw-r--r--src/wp-includes/js/tinymce/langs/wp-langs.php565
-rw-r--r--src/wp-includes/js/tinymce/license.txt504
-rw-r--r--src/wp-includes/js/tinymce/mark_loaded_src.js20
-rw-r--r--src/wp-includes/js/tinymce/plugins/directionality/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/directionality/editor_plugin_src.js85
-rw-r--r--src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin_src.js159
-rw-r--r--src/wp-includes/js/tinymce/plugins/fullscreen/fullscreen.htm110
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin_src.js699
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gifbin0 -> 810 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gifbin0 -> 272 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gifbin0 -> 989 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gifbin0 -> 907 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gifbin0 -> 909 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/drag.gifbin0 -> 51 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gifbin0 -> 769 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gifbin0 -> 84 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css126
-rw-r--r--src/wp-includes/js/tinymce/plugins/inlinepopups/template.htm387
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/css/media.css17
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/editor_plugin_src.js897
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/js/embed.js73
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/js/media.js513
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/media.htm922
-rw-r--r--src/wp-includes/js/tinymce/plugins/media/moxieplayer.swf1
-rw-r--r--src/wp-includes/js/tinymce/plugins/paste/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js885
-rw-r--r--src/wp-includes/js/tinymce/plugins/paste/js/pastetext.js36
-rw-r--r--src/wp-includes/js/tinymce/plugins/paste/js/pasteword.js51
-rw-r--r--src/wp-includes/js/tinymce/plugins/paste/pastetext.htm27
-rw-r--r--src/wp-includes/js/tinymce/plugins/paste/pasteword.htm21
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt33
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php71
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php161
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php82
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php117
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php62
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php595
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php268
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/config.php27
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/css/content.css1
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin_src.js436
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/img/wline.gifbin0 -> 46 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php98
-rw-r--r--src/wp-includes/js/tinymce/plugins/spellchecker/rpc.php112
-rw-r--r--src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js1
-rw-r--r--src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js122
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js437
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/img/audio.gifbin0 -> 146 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/img/image.gifbin0 -> 95 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/img/media.gifbin0 -> 149 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/img/page.gifbin0 -> 108 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/img/trans.gifbin0 -> 43 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wordpress/img/video.gifbin0 -> 93 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin_src.js80
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpdialogs/js/popup.js432
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog.js28
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css443
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html274
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js325
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete-2x.pngbin0 -> 5064 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete.pngbin0 -> 1386 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/img/image-2x.pngbin0 -> 2687 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/img/image.pngbin0 -> 946 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.js613
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpfullscreen/css/wp-fullscreen.css13
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin_src.js189
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpgallery/editor_plugin_src.js156
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpgallery/img/delete-2x.pngbin0 -> 5064 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpgallery/img/delete.pngbin0 -> 1386 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpgallery/img/edit-2x.pngbin0 -> 4924 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpgallery/img/edit.pngbin0 -> 1590 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpgallery/img/t.gifbin0 -> 43 bytes
-rw-r--r--src/wp-includes/js/tinymce/plugins/wplink/editor_plugin_src.js59
-rw-r--r--src/wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js188
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/about.htm52
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/anchor.htm26
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/charmap.htm55
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/color_picker.htm70
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/editor_template.js1
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/editor_template_src.js1490
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/image.htm80
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/colorpicker.jpgbin0 -> 2584 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/flash.gifbin0 -> 239 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/gotmoxie.pngbin0 -> 892 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/icons.gifbin0 -> 11982 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/iframe.gifbin0 -> 600 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/pagebreak.gifbin0 -> 325 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/quicktime.gifbin0 -> 301 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/realmedia.gifbin0 -> 439 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/shockwave.gifbin0 -> 384 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/trans.gifbin0 -> 43 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/video.gifbin0 -> 597 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/img/windowsmedia.gifbin0 -> 415 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/about.js73
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/anchor.js56
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/charmap.js363
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/color_picker.js345
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/image.js253
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/link.js159
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/js/source_editor.js78
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/link.htm57
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/shortcuts.htm47
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/content.css50
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/dialog.css118
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/img/buttons.pngbin0 -> 3133 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/img/items.gifbin0 -> 64 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gifbin0 -> 68 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_check.gifbin0 -> 70 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/img/progress.gifbin0 -> 1787 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/img/tabs.gifbin0 -> 1322 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/default/ui.css219
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/content.css24
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/dialog.css106
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/ui.css106
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/content.css48
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/dialog.css118
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.pngbin0 -> 2766 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.pngbin0 -> 651 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.pngbin0 -> 2084 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui.css222
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_black.css8
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css5
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css132
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/dialog.css140
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/embedded.pngbin0 -> 27345 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/gallery.pngbin0 -> 26240 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/more_bug.gifbin0 -> 146 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/page_bug.gifbin0 -> 176 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/tabs.gifbin0 -> 1322 bytes
-rw-r--r--src/wp-includes/js/tinymce/themes/advanced/source_editor.htm25
-rw-r--r--src/wp-includes/js/tinymce/tiny_mce.js1
-rw-r--r--src/wp-includes/js/tinymce/tiny_mce_popup.js5
-rw-r--r--src/wp-includes/js/tinymce/utils/editable_selects.js70
-rw-r--r--src/wp-includes/js/tinymce/utils/form_utils.js210
-rw-r--r--src/wp-includes/js/tinymce/utils/mctabs.js162
-rw-r--r--src/wp-includes/js/tinymce/utils/validate.js252
-rw-r--r--src/wp-includes/js/tinymce/wp-mce-help.php281
-rw-r--r--src/wp-includes/js/tinymce/wp-tinymce-schema.js940
-rw-r--r--src/wp-includes/js/tinymce/wp-tinymce.js.gzbin0 -> 115941 bytes
-rw-r--r--src/wp-includes/js/tinymce/wp-tinymce.php38
-rw-r--r--src/wp-includes/js/tw-sack.js193
-rw-r--r--src/wp-includes/js/underscore.min.js5
-rw-r--r--src/wp-includes/js/utils.js171
-rw-r--r--src/wp-includes/js/wp-ajax-response.js64
-rw-r--r--src/wp-includes/js/wp-auth-check.js106
-rw-r--r--src/wp-includes/js/wp-backbone.js384
-rw-r--r--src/wp-includes/js/wp-list-revisions.js24
-rw-r--r--src/wp-includes/js/wp-lists.js464
-rw-r--r--src/wp-includes/js/wp-pointer.js281
-rw-r--r--src/wp-includes/js/wp-util.js105
-rw-r--r--src/wp-includes/js/wplink.js608
-rw-r--r--src/wp-includes/kses.php1473
-rw-r--r--src/wp-includes/l10n.php575
-rw-r--r--src/wp-includes/link-template.php2442
-rw-r--r--src/wp-includes/load.php760
-rw-r--r--src/wp-includes/locale.php356
-rw-r--r--src/wp-includes/media-template.php496
-rw-r--r--src/wp-includes/media.php2029
-rw-r--r--src/wp-includes/meta.php914
-rw-r--r--src/wp-includes/ms-blogs.php783
-rw-r--r--src/wp-includes/ms-default-constants.php151
-rw-r--r--src/wp-includes/ms-default-filters.php69
-rw-r--r--src/wp-includes/ms-deprecated.php318
-rw-r--r--src/wp-includes/ms-files.php82
-rw-r--r--src/wp-includes/ms-functions.php1982
-rw-r--r--src/wp-includes/ms-load.php258
-rw-r--r--src/wp-includes/ms-settings.php136
-rw-r--r--src/wp-includes/nav-menu-template.php509
-rw-r--r--src/wp-includes/nav-menu.php794
-rw-r--r--src/wp-includes/option.php1059
-rw-r--r--src/wp-includes/pluggable-deprecated.php192
-rw-r--r--src/wp-includes/pluggable.php1750
-rw-r--r--src/wp-includes/plugin.php790
-rw-r--r--src/wp-includes/pomo/entry.php78
-rw-r--r--src/wp-includes/pomo/mo.php257
-rw-r--r--src/wp-includes/pomo/po.php384
-rw-r--r--src/wp-includes/pomo/streams.php209
-rw-r--r--src/wp-includes/pomo/translations.php275
-rw-r--r--src/wp-includes/post-formats.php243
-rw-r--r--src/wp-includes/post-template.php1458
-rw-r--r--src/wp-includes/post-thumbnail-template.php99
-rw-r--r--src/wp-includes/post.php4966
-rw-r--r--src/wp-includes/query.php3679
-rw-r--r--src/wp-includes/registration-functions.php7
-rw-r--r--src/wp-includes/registration.php7
-rw-r--r--src/wp-includes/revision.php603
-rw-r--r--src/wp-includes/rewrite.php2006
-rw-r--r--src/wp-includes/rss-functions.php9
-rw-r--r--src/wp-includes/rss.php932
-rw-r--r--src/wp-includes/script-loader.php917
-rw-r--r--src/wp-includes/shortcodes.php377
-rw-r--r--src/wp-includes/taxonomy.php3388
-rw-r--r--src/wp-includes/template-loader.php49
-rw-r--r--src/wp-includes/template.php411
-rw-r--r--src/wp-includes/theme-compat/comments-popup.php129
-rw-r--r--src/wp-includes/theme-compat/comments.php101
-rw-r--r--src/wp-includes/theme-compat/footer.php30
-rw-r--r--src/wp-includes/theme-compat/header.php49
-rw-r--r--src/wp-includes/theme-compat/sidebar.php83
-rw-r--r--src/wp-includes/theme.php1730
-rw-r--r--src/wp-includes/update.php449
-rw-r--r--src/wp-includes/user.php1552
-rw-r--r--src/wp-includes/vars.php127
-rw-r--r--src/wp-includes/version.php35
-rw-r--r--src/wp-includes/widgets.php1263
-rw-r--r--src/wp-includes/wlwmanifest.xml43
-rw-r--r--src/wp-includes/wp-db.php1746
-rw-r--r--src/wp-includes/wp-diff.php500
-rw-r--r--src/wp-links-opml.php59
-rw-r--r--src/wp-load.php63
-rw-r--r--src/wp-login.php770
-rw-r--r--src/wp-mail.php230
-rw-r--r--src/wp-settings.php329
-rw-r--r--src/wp-signup.php584
-rw-r--r--src/wp-trackback.php110
-rw-r--r--src/xmlrpc.php86
1120 files changed, 314984 insertions, 0 deletions
diff --git a/src/index.php b/src/index.php
new file mode 100644
index 0000000000..1e3364ad1b
--- /dev/null
+++ b/src/index.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Front to the WordPress application. This file doesn't do anything, but loads
+ * wp-blog-header.php which does and tells WordPress to load the theme.
+ *
+ * @package WordPress
+ */
+
+/**
+ * Tells WordPress to load the WordPress theme and output it.
+ *
+ * @var bool
+ */
+define('WP_USE_THEMES', true);
+
+/** Loads the WordPress Environment and Template */
+require('./wp-blog-header.php');
diff --git a/src/license.txt b/src/license.txt
new file mode 100644
index 0000000000..06c105b129
--- /dev/null
+++ b/src/license.txt
@@ -0,0 +1,385 @@
+WordPress - Web publishing software
+
+Copyright 2013 by the contributors
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+This program incorporates work covered by the following copyright and
+permission notices:
+
+ b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com -
+ http://tidakada.com
+
+ Wherever third party code has been used, credit has been given in the code's
+ comments.
+
+ b2 is released under the GPL
+
+and
+
+ WordPress - Web publishing software
+
+ Copyright 2003-2010 by the contributors
+
+ WordPress is released under the GPL
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+
+WRITTEN OFFER
+
+The source code for any program binaries or compressed scripts that are
+included with WordPress can be freely obtained at the following URL:
+
+ http://wordpress.org/download/source/
diff --git a/src/readme.html b/src/readme.html
new file mode 100644
index 0000000000..1dde82294f
--- /dev/null
+++ b/src/readme.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>WordPress &#8250; ReadMe</title>
+ <link rel="stylesheet" href="wp-admin/css/install.css?ver=20100228" type="text/css" />
+</head>
+<body>
+<h1 id="logo">
+ <a href="http://wordpress.org/"><img alt="WordPress" src="wp-admin/images/wordpress-logo.png" /></a>
+ <br /> Version 3.6
+</h1>
+<p style="text-align: center">Semantic Personal Publishing Platform</p>
+
+<h1>First Things First</h1>
+<p>Welcome. WordPress is a very special project to me. Every developer and contributor adds something unique to the mix, and together we create something beautiful that I&#8217;m proud to be a part of. Thousands of hours have gone into WordPress, and we&#8217;re dedicated to making it better every day. Thank you for making it part of your world.</p>
+<p style="text-align: right">&#8212; Matt Mullenweg</p>
+
+<h1>Installation: Famous 5-minute install</h1>
+<ol>
+ <li>Unzip the package in an empty directory and upload everything.</li>
+ <li>Open <span class="file"><a href="wp-admin/install.php">wp-admin/install.php</a></span> in your browser. It will take you through the process to set up a <code>wp-config.php</code> file with your database connection details.
+ <ol>
+ <li>If for some reason this doesn&#8217;t work, don&#8217;t worry. It doesn&#8217;t work on all web hosts. Open up <code>wp-config-sample.php</code> with a text editor like WordPad or similar and fill in your database connection details.</li>
+ <li>Save the file as <code>wp-config.php</code> and upload it.</li>
+ <li>Open <span class="file"><a href="wp-admin/install.php">wp-admin/install.php</a></span> in your browser.</li>
+ </ol>
+ </li>
+ <li>Once the configuration file is set up, the installer will set up the tables needed for your blog. If there is an error, double check your <code>wp-config.php</code> file, and try again. If it fails again, please go to the <a href="http://wordpress.org/support/" title="WordPress support">support forums</a> with as much data as you can gather.</li>
+ <li><strong>If you did not enter a password, note the password given to you.</strong> If you did not provide a username, it will be <code>admin</code>.</li>
+ <li>The installer should then send you to the <a href="wp-login.php">login page</a>. Sign in with the username and password you chose during the installation. If a password was generated for you, you can then click on &#8220;Profile&#8221; to change the password.</li>
+</ol>
+
+<h1>Updating</h1>
+<h2>Using the Automatic Updater</h2>
+<p>If you are updating from version 2.7 or higher, you can use the automatic updater:</p>
+<ol>
+ <li>Open <span class="file"><a href="wp-admin/update-core.php">wp-admin/update-core.php</a></span> in your browser and follow the instructions.</li>
+ <li>You wanted more, perhaps? That&#8217;s it!</li>
+</ol>
+
+<h2>Updating Manually</h2>
+<ol>
+ <li>Before you update anything, make sure you have backup copies of any files you may have modified such as <code>index.php</code>.</li>
+ <li>Delete your old WordPress files, saving ones you&#8217;ve modified.</li>
+ <li>Upload the new files.</li>
+ <li>Point your browser to <span class="file"><a href="wp-admin/upgrade.php">/wp-admin/upgrade.php</a>.</span></li>
+</ol>
+
+<h1>Migrating from other systems</h1>
+<p>WordPress can <a href="http://codex.wordpress.org/Importing_Content">import from a number of systems</a>. First you need to get WordPress installed and working as described above, before using <a href="wp-admin/import.php" title="Import to WordPress">our import tools</a>.</p>
+
+<h1>System Requirements</h1>
+<ul>
+ <li><a href="http://php.net/">PHP</a> version <strong>5.2.4</strong> or higher.</li>
+ <li><a href="http://www.mysql.com/">MySQL</a> version <strong>5.0</strong> or higher.</li>
+</ul>
+
+<h2>System Recommendations</h2>
+<ul>
+ <li>The <a href="http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html">mod_rewrite</a> Apache module.</li>
+ <li>A link to <a href="http://wordpress.org/">http://wordpress.org</a> on your site.</li>
+</ul>
+
+<h1>Online Resources</h1>
+<p>If you have any questions that aren&#8217;t addressed in this document, please take advantage of WordPress&#8217; numerous online resources:</p>
+<dl>
+ <dt><a href="http://codex.wordpress.org/">The WordPress Codex</a></dt>
+ <dd>The Codex is the encyclopedia of all things WordPress. It is the most comprehensive source of information for WordPress available.</dd>
+ <dt><a href="http://wordpress.org/news/">The WordPress Blog</a></dt>
+ <dd>This is where you&#8217;ll find the latest updates and news related to WordPress. Recent WordPress news appears in your administrative dashboard by default.</dd>
+ <dt><a href="http://planet.wordpress.org/">WordPress Planet</a></dt>
+ <dd>The WordPress Planet is a news aggregator that brings together posts from WordPress blogs around the web.</dd>
+ <dt><a href="http://wordpress.org/support/">WordPress Support Forums</a></dt>
+ <dd>If you&#8217;ve looked everywhere and still can&#8217;t find an answer, the support forums are very active and have a large community ready to help. To help them help you be sure to use a descriptive thread title and describe your question in as much detail as possible.</dd>
+ <dt><a href="http://codex.wordpress.org/IRC">WordPress <abbr title="Internet Relay Chat">IRC</abbr> Channel</a></dt>
+ <dd>There is an online chat channel that is used for discussion among people who use WordPress and occasionally support topics. The above wiki page should point you in the right direction. (<a href="irc://irc.freenode.net/wordpress">irc.freenode.net #wordpress</a>)</dd>
+</dl>
+
+<h1>Final Notes</h1>
+<ul>
+ <li>If you have any suggestions, ideas, or comments, or if you (gasp!) found a bug, join us in the <a href="http://wordpress.org/support/">Support Forums</a>.</li>
+ <li>WordPress has a robust plugin <abbr title="application programming interface">API</abbr> that makes extending the code easy. If you are a developer interested in utilizing this, see the <a href="http://codex.wordpress.org/Plugin_API" title="WordPress plugin API">plugin documentation in the Codex</a>. You shouldn&#8217;t modify any of the core code.</li>
+</ul>
+
+<h1>Share the Love</h1>
+<p>WordPress has no multi-million dollar marketing campaign or celebrity sponsors, but we do have something even better&#8212;you. If you enjoy WordPress please consider telling a friend, setting it up for someone less knowledgable than yourself, or writing the author of a media article that overlooks us.</p>
+
+<p>WordPress is the official continuation of <a href="http://cafelog.com/">b2/caf&#233;log</a>, which came from Michel V. The work has been continued by the <a href="http://wordpress.org/about/">WordPress developers</a>. If you would like to support WordPress, please consider <a href="http://wordpress.org/donate/" title="Donate to WordPress">donating</a>.</p>
+
+<h1>License</h1>
+<p>WordPress is free software, and is released under the terms of the <abbr title="GNU General Public License">GPL</abbr> version 2 or (at your option) any later version. See <a href="license.txt">license.txt</a>.</p>
+
+</body>
+</html>
diff --git a/src/wp-activate.php b/src/wp-activate.php
new file mode 100644
index 0000000000..6a474b12fb
--- /dev/null
+++ b/src/wp-activate.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Confirms that the activation key that is sent in an email after a user signs
+ * up for a new blog matches the key for that user and then displays confirmation.
+ *
+ * @package WordPress
+ */
+
+define( 'WP_INSTALLING', true );
+
+/** Sets up the WordPress Environment. */
+require( dirname(__FILE__) . '/wp-load.php' );
+
+require( './wp-blog-header.php' );
+
+if ( !is_multisite() ) {
+ wp_redirect( site_url( '/wp-login.php?action=register' ) );
+ die();
+}
+
+if ( is_object( $wp_object_cache ) )
+ $wp_object_cache->cache_enabled = false;
+
+do_action( 'activate_header' );
+
+/**
+ * Adds an action hook specific to this page that fires on wp_head
+ *
+ * @since MU
+ */
+function do_activate_header() {
+ do_action( 'activate_wp_head' );
+}
+add_action( 'wp_head', 'do_activate_header' );
+
+/**
+ * Loads styles specific to this page.
+ *
+ * @since MU
+ */
+function wpmu_activate_stylesheet() {
+ ?>
+ <style type="text/css">
+ form { margin-top: 2em; }
+ #submit, #key { width: 90%; font-size: 24px; }
+ #language { margin-top: .5em; }
+ .error { background: #f66; }
+ span.h3 { padding: 0 8px; font-size: 1.3em; font-family: "Lucida Grande", Verdana, Arial, "Bitstream Vera Sans", sans-serif; font-weight: bold; color: #333; }
+ </style>
+ <?php
+}
+add_action( 'wp_head', 'wpmu_activate_stylesheet' );
+
+get_header();
+?>
+
+<div id="content" class="widecolumn">
+ <?php if ( empty($_GET['key']) && empty($_POST['key']) ) { ?>
+
+ <h2><?php _e('Activation Key Required') ?></h2>
+ <form name="activateform" id="activateform" method="post" action="<?php echo network_site_url('wp-activate.php'); ?>">
+ <p>
+ <label for="key"><?php _e('Activation Key:') ?></label>
+ <br /><input type="text" name="key" id="key" value="" size="50" />
+ </p>
+ <p class="submit">
+ <input id="submit" type="submit" name="Submit" class="submit" value="<?php esc_attr_e('Activate') ?>" />
+ </p>
+ </form>
+
+ <?php } else {
+
+ $key = !empty($_GET['key']) ? $_GET['key'] : $_POST['key'];
+ $result = wpmu_activate_signup($key);
+ if ( is_wp_error($result) ) {
+ if ( 'already_active' == $result->get_error_code() || 'blog_taken' == $result->get_error_code() ) {
+ $signup = $result->get_error_data();
+ ?>
+ <h2><?php _e('Your account is now active!'); ?></h2>
+ <?php
+ echo '<p class="lead-in">';
+ if ( $signup->domain . $signup->path == '' ) {
+ printf( __('Your account has been activated. You may now <a href="%1$s">log in</a> to the site using your chosen username of &#8220;%2$s&#8221;. Please check your email inbox at %3$s for your password and login instructions. If you do not receive an email, please check your junk or spam folder. If you still do not receive an email within an hour, you can <a href="%4$s">reset your password</a>.'), network_site_url( 'wp-login.php', 'login' ), $signup->user_login, $signup->user_email, wp_lostpassword_url() );
+ } else {
+ printf( __('Your site at <a href="%1$s">%2$s</a> is active. You may now log in to your site using your chosen username of &#8220;%3$s&#8221;. Please check your email inbox at %4$s for your password and login instructions. If you do not receive an email, please check your junk or spam folder. If you still do not receive an email within an hour, you can <a href="%5$s">reset your password</a>.'), 'http://' . $signup->domain, $signup->domain, $signup->user_login, $signup->user_email, wp_lostpassword_url() );
+ }
+ echo '</p>';
+ } else {
+ ?>
+ <h2><?php _e('An error occurred during the activation'); ?></h2>
+ <?php
+ echo '<p>'.$result->get_error_message().'</p>';
+ }
+ } else {
+ extract($result);
+ $url = get_blogaddress_by_id( (int) $blog_id);
+ $user = get_userdata( (int) $user_id);
+ ?>
+ <h2><?php _e('Your account is now active!'); ?></h2>
+
+ <div id="signup-welcome">
+ <p><span class="h3"><?php _e('Username:'); ?></span> <?php echo $user->user_login ?></p>
+ <p><span class="h3"><?php _e('Password:'); ?></span> <?php echo $password; ?></p>
+ </div>
+
+ <?php if ( $url != network_home_url('', 'http') ) : ?>
+ <p class="view"><?php printf( __('Your account is now activated. <a href="%1$s">View your site</a> or <a href="%2$s">Log in</a>'), $url, $url . 'wp-login.php' ); ?></p>
+ <?php else: ?>
+ <p class="view"><?php printf( __('Your account is now activated. <a href="%1$s">Log in</a> or go back to the <a href="%2$s">homepage</a>.' ), network_site_url('wp-login.php', 'login'), network_home_url() ); ?></p>
+ <?php endif;
+ }
+ }
+ ?>
+</div>
+<script type="text/javascript">
+ var key_input = document.getElementById('key');
+ key_input && key_input.focus();
+</script>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-admin/about.php b/src/wp-admin/about.php
new file mode 100644
index 0000000000..8b155d21b4
--- /dev/null
+++ b/src/wp-admin/about.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * About This Version administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+$title = __( 'About' );
+
+list( $display_version ) = explode( '-', $wp_version );
+
+include( ABSPATH . 'wp-admin/admin-header.php' );
+?>
+<div class="wrap about-wrap">
+
+<h1><?php printf( __( 'Welcome to WordPress %s' ), $display_version ); ?></h1>
+
+<div class="about-text"><?php printf( __( 'Thank you for updating to the latest version. WordPress %s makes your writing experience even better.' ), $display_version ); ?></div>
+
+<div class="wp-badge"><?php printf( __( 'Version %s' ), $display_version ); ?></div>
+
+<h2 class="nav-tab-wrapper">
+ <a href="about.php" class="nav-tab nav-tab-active">
+ <?php _e( 'What&#8217;s New' ); ?>
+ </a><a href="credits.php" class="nav-tab">
+ <?php _e( 'Credits' ); ?>
+ </a><a href="freedoms.php" class="nav-tab">
+ <?php _e( 'Freedoms' ); ?>
+ </a>
+</h2>
+
+<div class="changelog">
+ <h3><?php _e( 'Colorful New Theme' ); ?></h3>
+
+ <div class="feature-section images-stagger-right">
+ <img alt="" src="<?php echo is_ssl() ? 'https://' : '//s.'; ?>wordpress.org/images/core/3.6/twentythirteen.png" class="image-66" />
+ <h4><?php _e( 'Introducing Twenty Thirteen' ); ?></h4>
+ <p><?php printf( __( "The new default theme puts focus on your content with a colorful, single-column design made for media-rich blogging." ) ); ?></p>
+ <p><?php _e( 'Inspired by modern art, Twenty Thirteen features quirky details, beautiful typography, and bold, high-contrast colors &mdash; all with a flexible layout that looks great on any device, big or small.' ); ?></p>
+ </div>
+</div>
+
+<div class="changelog">
+ <h3><?php _e( 'Write with Confidence' ); ?></h3>
+
+ <div class="feature-section images-stagger-right">
+ <img alt="" src="<?php echo is_ssl() ? 'https://' : '//s.'; ?>wordpress.org/images/core/3.6/revisions.png" class="image-66" />
+ <h4><?php _e( 'Explore Revisions' ); ?></h4>
+ <p></p>
+ <p><?php _e( 'From the first word you write, WordPress saves every change. Each revision is always at your fingertips. Text is highlighted as you scroll through revisions at lightning speed, so you can see what changes have been made along the way.' ); ?></p>
+ <p><?php _e( 'It&#8217;s easy to compare two revisions from any point in time, and to restore a revision and go back to writing. Now you can be confident that no mistake is permanent.' ); ?></p>
+ </div>
+
+ <div class="feature-section col two-col">
+ <div>
+ <h4><?php _e( 'Improved Autosaves' ); ?></h4>
+ <p><?php _e( 'Never lose a word you&#8217;ve written. Autosaving is now even better; whether your power goes out, your browser crashes, or you lose your internet connection, your content is safe.' ); ?></p>
+ </div>
+ <div class="last-feature">
+ <h4><?php _e( 'Better Post Locking' ); ?></h4>
+ <p><?php _e( 'Always know who&#8217;s editing with live updates that appear in the list of posts. And if someone leaves for lunch with a post open, you can take over where they left off.' ); ?></p>
+ </div>
+ </div>
+</div>
+
+<div class="changelog">
+ <h3><?php _e( 'Support for Audio and Video' ); ?></h3>
+
+ <div class="feature-section images-stagger-right">
+ <div class="video image-66"><?php
+ $sample_video = ( is_ssl() ? 'https://' : 'http://s.' ) . 'wordpress.org/images/core/3.6/sample-video';
+ $args = array(
+ 'mp4' => "$sample_video.mp4",
+ 'ogv' => "$sample_video.ogv",
+ 'width' => 625,
+ 'height' => 360,
+ );
+ // Opera 12 (Presto, pre-Chromium) fails to load ogv properly
+ // when combined with ME.js. Works fine in Opera 15.
+ // Don't serve ogv to Opera 12 to avoid complete brokeness.
+ if ( $GLOBALS['is_opera'] )
+ unset( $args['ogv'] );
+ // Our current ME.js API is limited to shortcodes in posts.
+ echo wp_video_shortcode( $args );
+ ?></div>
+ <h4><?php _e( 'New Media Player' ); ?></h4>
+ <p><?php _e( 'Share your audio and video with the new built-in HTML5 media player. Upload files using the media manager and embed them in your posts.' ); ?></p>
+
+ <h4><?php _e( 'Embed Music from Spotify, Rdio, and SoundCloud' ); ?></h4>
+ <p><?php _e( 'Embed songs and albums from your favorite artists, or playlists you&#8217;ve mixed yourself. It&#8217;s as simple as pasting a URL into a post on its own line.' ); ?></p>
+ <p><?php printf( __( '(Love another service? Check out all of the <a href="%s">embeds</a> that WordPress supports.)' ), 'http://codex.wordpress.org/Embeds' ); ?></p>
+ </div>
+</div>
+
+<div class="changelog">
+ <h3><?php _e( 'Under the Hood' ); ?></h3>
+
+ <div class="feature-section col three-col">
+ <div>
+ <h4><?php _e( 'Audio/Video API' ); ?></h4>
+ <p><?php _e( 'The new audio/video APIs give developers access to powerful media metadata, like ID3 tags.' ); ?></p>
+ </div>
+ <div>
+ <h4><?php _e( 'Semantic Markup' ); ?></h4>
+ <p><?php _e( 'Themes can now choose improved HTML5 markup for comment forms, search forms, and comment lists.' ); ?></p>
+ </div>
+ <div class="last-feature">
+ <h4><?php _e( 'JavaScript Utilities' ); ?></h4>
+ <p><?php _e( 'Handy JavaScript utilities ease common tasks like Ajax requests, templating, and Backbone view management.' ); ?></p>
+ </div>
+ </div>
+
+ <div class="feature-section col three-col">
+ <div>
+ <h4><?php _e( 'Shortcode Improvements' ); ?></h4>
+ <p><?php _e( 'Search content for shortcodes with <code>has_shortcode()</code> and adjust shortcode attributes with a new filter.' ); ?></p>
+ </div>
+ <div>
+ <h4><?php _e( 'Revision Control' ); ?></h4>
+ <p><?php _e( 'Fine-grained revision controls allow you to keep a different number of revisions for each post type.' ); ?></p>
+ </div>
+ <div class="last-feature">
+ <h4><?php _e( 'External Libraries' ); ?></h4>
+ <p><?php
+ /* translators: placeholders 2, 3 and 4 are version numbers */
+ printf( __( 'New and updated libraries: <a href="%1$s">MediaElement.js</a>, jQuery %2$s, jQuery UI %3$s, jQuery Migrate, Backbone %4$s.' ), 'http://mediaelementjs.com/', '1.10.2', '1.10.3', '1.0' ); ?></p>
+ </div>
+ </div>
+</div>
+
+<div class="return-to-dashboard">
+ <?php if ( current_user_can( 'update_core' ) && isset( $_GET['updated'] ) ) : ?>
+ <a href="<?php echo esc_url( self_admin_url( 'update-core.php' ) ); ?>"><?php
+ is_multisite() ? _e( 'Return to Updates' ) : _e( 'Return to Dashboard &rarr; Updates' );
+ ?></a> |
+ <?php endif; ?>
+ <a href="<?php echo esc_url( self_admin_url() ); ?>"><?php
+ is_blog_admin() ? _e( 'Go to Dashboard &rarr; Home' ) : _e( 'Go to Dashboard' ); ?></a>
+</div>
+
+</div>
+<?php
+
+include( ABSPATH . 'wp-admin/admin-footer.php' );
+
+// These are strings we may use to describe maintenance/security releases, where we aim for no new strings.
+return;
+
+_n_noop( 'Maintenance Release', 'Maintenance Releases' );
+_n_noop( 'Security Release', 'Security Releases' );
+_n_noop( 'Maintenance and Security Release', 'Maintenance and Security Releases' );
+
+/* translators: 1: WordPress version number. */
+_n_noop( '<strong>Version %1$s</strong> addressed a security issue.',
+ '<strong>Version %1$s</strong> addressed some security issues.' );
+
+/* translators: 1: WordPress version number, 2: plural number of bugs. */
+_n_noop( '<strong>Version %1$s</strong> addressed %2$s bug.',
+ '<strong>Version %1$s</strong> addressed %2$s bugs.' );
+
+/* translators: 1: WordPress version number, 2: plural number of bugs. Singular security issue. */
+_n_noop( '<strong>Version %1$s</strong> addressed a security issue and fixed %2$s bug.',
+ '<strong>Version %1$s</strong> addressed a security issue and fixed %2$s bugs.' );
+
+/* translators: 1: WordPress version number, 2: plural number of bugs. More than one security issue. */
+_n_noop( '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bug.',
+ '<strong>Version %1$s</strong> addressed some security issues and fixed %2$s bugs.' );
+
+__( 'For more information, see <a href="%s">the release notes</a>.' );
diff --git a/src/wp-admin/admin-ajax.php b/src/wp-admin/admin-ajax.php
new file mode 100644
index 0000000000..c638d78aad
--- /dev/null
+++ b/src/wp-admin/admin-ajax.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * WordPress AJAX Process Execution.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ *
+ * @link http://codex.wordpress.org/AJAX_in_Plugins
+ */
+
+/**
+ * Executing AJAX process.
+ *
+ * @since 2.1.0
+ */
+define( 'DOING_AJAX', true );
+define( 'WP_ADMIN', true );
+
+/** Load WordPress Bootstrap */
+require_once( dirname( dirname( __FILE__ ) ) . '/wp-load.php' );
+
+/** Allow for cross-domain requests (from the frontend). */
+send_origin_headers();
+
+// Require an action parameter
+if ( empty( $_REQUEST['action'] ) )
+ die( '0' );
+
+/** Load WordPress Administration APIs */
+require_once( ABSPATH . 'wp-admin/includes/admin.php' );
+
+/** Load Ajax Handlers for WordPress Core */
+require_once( ABSPATH . 'wp-admin/includes/ajax-actions.php' );
+
+@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
+@header( 'X-Robots-Tag: noindex' );
+
+send_nosniff_header();
+nocache_headers();
+
+do_action( 'admin_init' );
+
+$core_actions_get = array(
+ 'fetch-list', 'ajax-tag-search', 'wp-compression-test', 'imgedit-preview', 'oembed-cache',
+ 'autocomplete-user', 'dashboard-widgets', 'logged-in',
+);
+
+$core_actions_post = array(
+ 'oembed-cache', 'image-editor', 'delete-comment', 'delete-tag', 'delete-link',
+ 'delete-meta', 'delete-post', 'trash-post', 'untrash-post', 'delete-page', 'dim-comment',
+ 'add-link-category', 'add-tag', 'get-tagcloud', 'get-comments', 'replyto-comment',
+ 'edit-comment', 'add-menu-item', 'add-meta', 'add-user', 'autosave', 'closed-postboxes',
+ 'hidden-columns', 'update-welcome-panel', 'menu-get-metabox', 'wp-link-ajax',
+ 'menu-locations-save', 'menu-quick-search', 'meta-box-order', 'get-permalink',
+ 'sample-permalink', 'inline-save', 'inline-save-tax', 'find_posts', 'widgets-order',
+ 'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post',
+ 'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
+ 'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
+ 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs',
+);
+
+// Register core Ajax calls.
+if ( ! empty( $_GET['action'] ) && in_array( $_GET['action'], $core_actions_get ) )
+ add_action( 'wp_ajax_' . $_GET['action'], 'wp_ajax_' . str_replace( '-', '_', $_GET['action'] ), 1 );
+
+if ( ! empty( $_POST['action'] ) && in_array( $_POST['action'], $core_actions_post ) )
+ add_action( 'wp_ajax_' . $_POST['action'], 'wp_ajax_' . str_replace( '-', '_', $_POST['action'] ), 1 );
+
+add_action( 'wp_ajax_nopriv_heartbeat', 'wp_ajax_nopriv_heartbeat', 1 );
+
+if ( is_user_logged_in() )
+ do_action( 'wp_ajax_' . $_REQUEST['action'] ); // Authenticated actions
+else
+ do_action( 'wp_ajax_nopriv_' . $_REQUEST['action'] ); // Non-admin actions
+
+// Default status
+die( '0' );
diff --git a/src/wp-admin/admin-footer.php b/src/wp-admin/admin-footer.php
new file mode 100644
index 0000000000..3818ab411e
--- /dev/null
+++ b/src/wp-admin/admin-footer.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * WordPress Administration Template Footer
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// don't load directly
+if ( !defined('ABSPATH') )
+ die('-1');
+?>
+
+<div class="clear"></div></div><!-- wpbody-content -->
+<div class="clear"></div></div><!-- wpbody -->
+<div class="clear"></div></div><!-- wpcontent -->
+
+<div id="wpfooter">
+<?php do_action( 'in_admin_footer' ); ?>
+<p id="footer-left" class="alignleft"><?php
+echo apply_filters( 'admin_footer_text', '<span id="footer-thankyou">' . __( 'Thank you for creating with <a href="http://wordpress.org/">WordPress</a>.' ) . '</span>' );
+?></p>
+<p id="footer-upgrade" class="alignright"><?php echo apply_filters( 'update_footer', '' ); ?></p>
+<div class="clear"></div>
+</div>
+<?php
+do_action('admin_footer', '');
+do_action('admin_print_footer_scripts');
+do_action("admin_footer-" . $GLOBALS['hook_suffix']);
+
+// get_site_option() won't exist when auto upgrading from <= 2.7
+if ( function_exists('get_site_option') ) {
+ if ( false === get_site_option('can_compress_scripts') )
+ compression_test();
+}
+
+?>
+
+<div class="clear"></div></div><!-- wpwrap -->
+<script type="text/javascript">if(typeof wpOnload=='function')wpOnload();</script>
+</body>
+</html>
diff --git a/src/wp-admin/admin-functions.php b/src/wp-admin/admin-functions.php
new file mode 100644
index 0000000000..f596749089
--- /dev/null
+++ b/src/wp-admin/admin-functions.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Administration Functions
+ *
+ * This file is deprecated, use 'wp-admin/includes/admin.php' instead.
+ *
+ * @deprecated 2.5
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+_deprecated_file( basename(__FILE__), '2.5', 'wp-admin/includes/admin.php' );
+
+/** WordPress Administration API: Includes all Administration functions. */
+require_once(ABSPATH . 'wp-admin/includes/admin.php');
diff --git a/src/wp-admin/admin-header.php b/src/wp-admin/admin-header.php
new file mode 100644
index 0000000000..00ad299695
--- /dev/null
+++ b/src/wp-admin/admin-header.php
@@ -0,0 +1,138 @@
+<?php
+/**
+ * WordPress Administration Template Header
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+@header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
+if ( ! defined( 'WP_ADMIN' ) )
+ require_once( './admin.php' );
+
+// In case admin-header.php is included in a function.
+global $title, $hook_suffix, $current_screen, $wp_locale, $pagenow, $wp_version,
+ $current_site, $update_title, $total_update_count, $parent_file;
+
+// Catch plugins that include admin-header.php before admin.php completes.
+if ( empty( $current_screen ) )
+ set_current_screen();
+
+get_admin_page_title();
+$title = esc_html( strip_tags( $title ) );
+
+if ( is_network_admin() )
+ $admin_title = __( 'Network Admin' );
+elseif ( is_user_admin() )
+ $admin_title = __( 'Global Dashboard' );
+else
+ $admin_title = get_bloginfo( 'name' );
+
+if ( $admin_title == $title )
+ $admin_title = sprintf( __( '%1$s &#8212; WordPress' ), $title );
+else
+ $admin_title = sprintf( __( '%1$s &lsaquo; %2$s &#8212; WordPress' ), $title, $admin_title );
+
+$admin_title = apply_filters( 'admin_title', $admin_title, $title );
+
+wp_user_settings();
+
+_wp_admin_html_begin();
+?>
+<title><?php echo $admin_title; ?></title>
+<?php
+
+wp_enqueue_style( 'colors' );
+wp_enqueue_style( 'ie' );
+wp_enqueue_script('utils');
+
+$admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
+?>
+<script type="text/javascript">
+addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
+var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
+ pagenow = '<?php echo $current_screen->id; ?>',
+ typenow = '<?php echo $current_screen->post_type; ?>',
+ adminpage = '<?php echo $admin_body_class; ?>',
+ thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
+ decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
+ isRtl = <?php echo (int) is_rtl(); ?>;
+</script>
+<?php
+
+do_action('admin_enqueue_scripts', $hook_suffix);
+do_action("admin_print_styles-$hook_suffix");
+do_action('admin_print_styles');
+do_action("admin_print_scripts-$hook_suffix");
+do_action('admin_print_scripts');
+do_action("admin_head-$hook_suffix");
+do_action('admin_head');
+
+if ( get_user_setting('mfold') == 'f' )
+ $admin_body_class .= ' folded';
+
+if ( !get_user_setting('unfold') )
+ $admin_body_class .= ' auto-fold';
+
+if ( is_admin_bar_showing() )
+ $admin_body_class .= ' admin-bar';
+
+if ( is_rtl() )
+ $admin_body_class .= ' rtl';
+
+$admin_body_class .= ' branch-' . str_replace( array( '.', ',' ), '-', floatval( $wp_version ) );
+$admin_body_class .= ' version-' . str_replace( '.', '-', preg_replace( '/^([.0-9]+).*/', '$1', $wp_version ) );
+$admin_body_class .= ' admin-color-' . sanitize_html_class( get_user_option( 'admin_color' ), 'fresh' );
+$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+
+if ( wp_is_mobile() )
+ $admin_body_class .= ' mobile';
+
+$admin_body_class .= ' no-customize-support';
+
+?>
+</head>
+<body class="wp-admin wp-core-ui no-js <?php echo apply_filters( 'admin_body_class', '' ) . " $admin_body_class"; ?>">
+<script type="text/javascript">
+ document.body.className = document.body.className.replace('no-js','js');
+</script>
+
+<?php
+// Make sure the customize body classes are correct as early as possible.
+if ( current_user_can( 'edit_theme_options' ) )
+ wp_customize_support_script();
+?>
+
+<div id="wpwrap">
+<a tabindex="1" href="#wpbody-content" class="screen-reader-shortcut"><?php _e('Skip to main content'); ?></a>
+<?php require(ABSPATH . 'wp-admin/menu-header.php'); ?>
+<div id="wpcontent">
+
+<?php
+do_action('in_admin_header');
+?>
+
+<div id="wpbody">
+<?php
+unset($title_class, $blog_name, $total_update_count, $update_title);
+
+$current_screen->set_parentage( $parent_file );
+
+?>
+
+<div id="wpbody-content" aria-label="<?php esc_attr_e('Main content'); ?>" tabindex="0">
+<?php
+
+$current_screen->render_screen_meta();
+
+if ( is_network_admin() )
+ do_action('network_admin_notices');
+elseif ( is_user_admin() )
+ do_action('user_admin_notices');
+else
+ do_action('admin_notices');
+
+do_action('all_admin_notices');
+
+if ( $parent_file == 'options-general.php' )
+ require(ABSPATH . 'wp-admin/options-head.php');
diff --git a/src/wp-admin/admin-post.php b/src/wp-admin/admin-post.php
new file mode 100644
index 0000000000..f4af998e33
--- /dev/null
+++ b/src/wp-admin/admin-post.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * WordPress Administration Generic POST Handler.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** We are located in WordPress Administration Screens */
+define('WP_ADMIN', true);
+
+if ( defined('ABSPATH') )
+ require_once(ABSPATH . 'wp-load.php');
+else
+ require_once('../wp-load.php');
+
+require_once(ABSPATH . 'wp-admin/includes/admin.php');
+
+nocache_headers();
+
+do_action('admin_init');
+
+$action = 'admin_post';
+
+if ( !wp_validate_auth_cookie() )
+ $action .= '_nopriv';
+
+if ( !empty($_REQUEST['action']) )
+ $action .= '_' . $_REQUEST['action'];
+
+do_action($action);
diff --git a/src/wp-admin/admin.php b/src/wp-admin/admin.php
new file mode 100644
index 0000000000..4e739c3c8d
--- /dev/null
+++ b/src/wp-admin/admin.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * WordPress Administration Bootstrap
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * In WordPress Administration Screens
+ *
+ * @since 2.3.2
+ */
+if ( ! defined('WP_ADMIN') )
+ define('WP_ADMIN', true);
+
+if ( ! defined('WP_NETWORK_ADMIN') )
+ define('WP_NETWORK_ADMIN', false);
+
+if ( ! defined('WP_USER_ADMIN') )
+ define('WP_USER_ADMIN', false);
+
+if ( ! WP_NETWORK_ADMIN && ! WP_USER_ADMIN ) {
+ define('WP_BLOG_ADMIN', true);
+}
+
+if ( isset($_GET['import']) && !defined('WP_LOAD_IMPORTERS') )
+ define('WP_LOAD_IMPORTERS', true);
+
+require_once(dirname(dirname(__FILE__)) . '/wp-load.php');
+
+nocache_headers();
+
+if ( get_option('db_upgraded') ) {
+ flush_rewrite_rules();
+ update_option( 'db_upgraded', false );
+
+ /**
+ * Runs on the next page load after successful upgrade
+ *
+ * @since 2.8
+ */
+ do_action('after_db_upgrade');
+} elseif ( get_option('db_version') != $wp_db_version && empty($_POST) ) {
+ if ( !is_multisite() ) {
+ wp_redirect( admin_url( 'upgrade.php?_wp_http_referer=' . urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
+ exit;
+ } elseif ( apply_filters( 'do_mu_upgrade', true ) ) {
+ /**
+ * On really small MU installs run the upgrader every time,
+ * else run it less often to reduce load.
+ *
+ * @since 2.8.4b
+ */
+ $c = get_blog_count();
+ // If 50 or fewer sites, run every time. Else, run "about ten percent" of the time. Shh, don't check that math.
+ if ( $c <= 50 || ( $c > 50 && mt_rand( 0, (int)( $c / 50 ) ) == 1 ) ) {
+ require_once( ABSPATH . WPINC . '/http.php' );
+ $response = wp_remote_get( admin_url( 'upgrade.php?step=1' ), array( 'timeout' => 120, 'httpversion' => '1.1' ) );
+ do_action( 'after_mu_upgrade', $response );
+ unset($response);
+ }
+ unset($c);
+ }
+}
+
+require_once(ABSPATH . 'wp-admin/includes/admin.php');
+
+auth_redirect();
+
+// Schedule trash collection
+if ( !wp_next_scheduled('wp_scheduled_delete') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'daily', 'wp_scheduled_delete');
+
+set_screen_options();
+
+$date_format = get_option('date_format');
+$time_format = get_option('time_format');
+
+wp_enqueue_script( 'common' );
+
+$editing = false;
+
+if ( isset($_GET['page']) ) {
+ $plugin_page = wp_unslash( $_GET['page'] );
+ $plugin_page = plugin_basename($plugin_page);
+}
+
+if ( isset( $_REQUEST['post_type'] ) && post_type_exists( $_REQUEST['post_type'] ) )
+ $typenow = $_REQUEST['post_type'];
+else
+ $typenow = '';
+
+if ( isset( $_REQUEST['taxonomy'] ) && taxonomy_exists( $_REQUEST['taxonomy'] ) )
+ $taxnow = $_REQUEST['taxonomy'];
+else
+ $taxnow = '';
+
+if ( WP_NETWORK_ADMIN )
+ require(ABSPATH . 'wp-admin/network/menu.php');
+elseif ( WP_USER_ADMIN )
+ require(ABSPATH . 'wp-admin/user/menu.php');
+else
+ require(ABSPATH . 'wp-admin/menu.php');
+
+if ( current_user_can( 'manage_options' ) )
+ @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+
+do_action('admin_init');
+
+if ( isset($plugin_page) ) {
+ if ( !empty($typenow) )
+ $the_parent = $pagenow . '?post_type=' . $typenow;
+ else
+ $the_parent = $pagenow;
+ if ( ! $page_hook = get_plugin_page_hook($plugin_page, $the_parent) ) {
+ $page_hook = get_plugin_page_hook($plugin_page, $plugin_page);
+ // backwards compatibility for plugins using add_management_page
+ if ( empty( $page_hook ) && 'edit.php' == $pagenow && '' != get_plugin_page_hook($plugin_page, 'tools.php') ) {
+ // There could be plugin specific params on the URL, so we need the whole query string
+ if ( !empty($_SERVER[ 'QUERY_STRING' ]) )
+ $query_string = $_SERVER[ 'QUERY_STRING' ];
+ else
+ $query_string = 'page=' . $plugin_page;
+ wp_redirect( admin_url('tools.php?' . $query_string) );
+ exit;
+ }
+ }
+ unset($the_parent);
+}
+
+$hook_suffix = '';
+if ( isset($page_hook) )
+ $hook_suffix = $page_hook;
+else if ( isset($plugin_page) )
+ $hook_suffix = $plugin_page;
+else if ( isset($pagenow) )
+ $hook_suffix = $pagenow;
+
+set_current_screen();
+
+// Handle plugin admin pages.
+if ( isset($plugin_page) ) {
+ if ( $page_hook ) {
+ do_action('load-' . $page_hook);
+ if (! isset($_GET['noheader']))
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ do_action($page_hook);
+ } else {
+ if ( validate_file($plugin_page) )
+ wp_die(__('Invalid plugin page'));
+
+ if ( !( file_exists(WP_PLUGIN_DIR . "/$plugin_page") && is_file(WP_PLUGIN_DIR . "/$plugin_page") ) && !( file_exists(WPMU_PLUGIN_DIR . "/$plugin_page") && is_file(WPMU_PLUGIN_DIR . "/$plugin_page") ) )
+ wp_die(sprintf(__('Cannot load %s.'), htmlentities($plugin_page)));
+
+ do_action('load-' . $plugin_page);
+
+ if ( !isset($_GET['noheader']))
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ if ( file_exists(WPMU_PLUGIN_DIR . "/$plugin_page") )
+ include(WPMU_PLUGIN_DIR . "/$plugin_page");
+ else
+ include(WP_PLUGIN_DIR . "/$plugin_page");
+ }
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ exit();
+} else if (isset($_GET['import'])) {
+
+ $importer = $_GET['import'];
+
+ if ( ! current_user_can('import') )
+ wp_die(__('You are not allowed to import.'));
+
+ if ( validate_file($importer) ) {
+ wp_redirect( admin_url( 'import.php?invalid=' . $importer ) );
+ exit;
+ }
+
+ if ( ! isset($wp_importers[$importer]) || ! is_callable($wp_importers[$importer][2]) ) {
+ wp_redirect( admin_url( 'import.php?invalid=' . $importer ) );
+ exit;
+ }
+
+ do_action( 'load-importer-' . $importer );
+
+ $parent_file = 'tools.php';
+ $submenu_file = 'import.php';
+ $title = __('Import');
+
+ if (! isset($_GET['noheader']))
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
+
+ define('WP_IMPORTING', true);
+
+ if ( apply_filters( 'force_filtered_html_on_import', false ) )
+ kses_init_filters(); // Always filter imported data with kses on multisite.
+
+ call_user_func($wp_importers[$importer][2]);
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ // Make sure rules are flushed
+ flush_rewrite_rules(false);
+
+ exit();
+} else {
+ do_action("load-$pagenow");
+ // Backwards compatibility with old load-page-new.php, load-page.php,
+ // and load-categories.php actions.
+ if ( $typenow == 'page' ) {
+ if ( $pagenow == 'post-new.php' )
+ do_action( 'load-page-new.php' );
+ elseif ( $pagenow == 'post.php' )
+ do_action( 'load-page.php' );
+ } elseif ( $pagenow == 'edit-tags.php' ) {
+ if ( $taxnow == 'category' )
+ do_action( 'load-categories.php' );
+ elseif ( $taxnow == 'link_category' )
+ do_action( 'load-edit-link-categories.php' );
+ }
+}
+
+if ( !empty($_REQUEST['action']) )
+ do_action('admin_action_' . $_REQUEST['action']);
diff --git a/src/wp-admin/async-upload.php b/src/wp-admin/async-upload.php
new file mode 100644
index 0000000000..296342eaa1
--- /dev/null
+++ b/src/wp-admin/async-upload.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Accepts file uploads from swfupload or other asynchronous upload methods.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+define('WP_ADMIN', true);
+
+if ( defined('ABSPATH') )
+ require_once(ABSPATH . 'wp-load.php');
+else
+ require_once('../wp-load.php');
+
+if ( ! ( isset( $_REQUEST['action'] ) && 'upload-attachment' == $_REQUEST['action'] ) ) {
+ // Flash often fails to send cookies with the POST or upload, so we need to pass it in GET or POST instead
+ if ( is_ssl() && empty($_COOKIE[SECURE_AUTH_COOKIE]) && !empty($_REQUEST['auth_cookie']) )
+ $_COOKIE[SECURE_AUTH_COOKIE] = $_REQUEST['auth_cookie'];
+ elseif ( empty($_COOKIE[AUTH_COOKIE]) && !empty($_REQUEST['auth_cookie']) )
+ $_COOKIE[AUTH_COOKIE] = $_REQUEST['auth_cookie'];
+ if ( empty($_COOKIE[LOGGED_IN_COOKIE]) && !empty($_REQUEST['logged_in_cookie']) )
+ $_COOKIE[LOGGED_IN_COOKIE] = $_REQUEST['logged_in_cookie'];
+ unset($current_user);
+}
+
+require_once('./admin.php');
+
+if ( !current_user_can('upload_files') )
+ wp_die(__('You do not have permission to upload files.'));
+
+header('Content-Type: text/html; charset=' . get_option('blog_charset'));
+
+if ( isset( $_REQUEST['action'] ) && 'upload-attachment' === $_REQUEST['action'] ) {
+ define( 'DOING_AJAX', true );
+ include ABSPATH . 'wp-admin/includes/ajax-actions.php';
+
+ send_nosniff_header();
+ nocache_headers();
+
+ wp_ajax_upload_attachment();
+ die( '0' );
+}
+
+// just fetch the detail form for that attachment
+if ( isset($_REQUEST['attachment_id']) && ($id = intval($_REQUEST['attachment_id'])) && $_REQUEST['fetch'] ) {
+ $post = get_post( $id );
+ if ( 'attachment' != $post->post_type )
+ wp_die( __( 'Unknown post type.' ) );
+ if ( ! current_user_can( 'edit_post', $id ) )
+ wp_die( __( 'You are not allowed to edit this item.' ) );
+
+ switch ( $_REQUEST['fetch'] ) {
+ case 3 :
+ if ( $thumb_url = wp_get_attachment_image_src( $id, 'thumbnail', true ) )
+ echo '<img class="pinkynail" src="' . esc_url( $thumb_url[0] ) . '" alt="" />';
+ echo '<a class="edit-attachment" href="' . esc_url( get_edit_post_link( $id ) ) . '" target="_blank">' . _x( 'Edit', 'media item' ) . '</a>';
+ $title = $post->post_title ? $post->post_title : wp_basename( $post->guid ); // title shouldn't ever be empty, but use filename just in cas.e
+ echo '<div class="filename new"><span class="title">' . esc_html( wp_html_excerpt( $title, 60, '&hellip;' ) ) . '</span></div>';
+ break;
+ case 2 :
+ add_filter('attachment_fields_to_edit', 'media_single_attachment_fields_to_edit', 10, 2);
+ echo get_media_item($id, array( 'send' => false, 'delete' => true ));
+ break;
+ default:
+ add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2);
+ echo get_media_item($id);
+ break;
+ }
+ exit;
+}
+
+check_admin_referer('media-form');
+
+$post_id = 0;
+if ( isset( $_REQUEST['post_id'] ) ) {
+ $post_id = absint( $_REQUEST['post_id'] );
+ if ( ! get_post( $post_id ) || ! current_user_can( 'edit_post', $post_id ) )
+ $post_id = 0;
+}
+
+$id = media_handle_upload( 'async-upload', $post_id );
+if ( is_wp_error($id) ) {
+ echo '<div class="error-div">
+ <a class="dismiss" href="#" onclick="jQuery(this).parents(\'div.media-item\').slideUp(200, function(){jQuery(this).remove();});">' . __('Dismiss') . '</a>
+ <strong>' . sprintf(__('&#8220;%s&#8221; has failed to upload due to an error'), esc_html($_FILES['async-upload']['name']) ) . '</strong><br />' .
+ esc_html($id->get_error_message()) . '</div>';
+ exit;
+}
+
+if ( $_REQUEST['short'] ) {
+ // short form response - attachment ID only
+ echo $id;
+} else {
+ // long form response - big chunk o html
+ $type = $_REQUEST['type'];
+ echo apply_filters("async_upload_{$type}", $id);
+}
diff --git a/src/wp-admin/comment.php b/src/wp-admin/comment.php
new file mode 100644
index 0000000000..de5483e286
--- /dev/null
+++ b/src/wp-admin/comment.php
@@ -0,0 +1,294 @@
+<?php
+/**
+ * Comment Management Screen
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Bootstrap */
+require_once('./admin.php');
+
+$parent_file = 'edit-comments.php';
+$submenu_file = 'edit-comments.php';
+
+wp_reset_vars( array('action') );
+
+if ( isset( $_POST['deletecomment'] ) )
+ $action = 'deletecomment';
+
+if ( 'cdc' == $action )
+ $action = 'delete';
+elseif ( 'mac' == $action )
+ $action = 'approve';
+
+if ( isset( $_GET['dt'] ) ) {
+ if ( 'spam' == $_GET['dt'] )
+ $action = 'spam';
+ elseif ( 'trash' == $_GET['dt'] )
+ $action = 'trash';
+}
+
+/**
+ * Display error message at bottom of comments.
+ *
+ * @param string $msg Error Message. Assumed to contain HTML and be sanitized.
+ */
+function comment_footer_die( $msg ) {
+ echo "<div class='wrap'><p>$msg</p></div>";
+ include('./admin-footer.php');
+ die;
+}
+
+switch( $action ) {
+
+case 'editcomment' :
+ $title = __('Edit Comment');
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __( 'You can edit the information left in a comment if needed. This is often useful when you notice that a commenter has made a typographical error.' ) . '</p>' .
+ '<p>' . __( 'You can also moderate the comment from this screen using the Status box, where you can also change the timestamp of the comment.' ) . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Administration_Screens#Comments" target="_blank">Documentation on Comments</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+ );
+
+ wp_enqueue_script('comment');
+ require_once('./admin-header.php');
+
+ $comment_id = absint( $_GET['c'] );
+
+ if ( !$comment = get_comment( $comment_id ) )
+ comment_footer_die( __('Oops, no comment with this ID.') . sprintf(' <a href="%s">' . __('Go back') . '</a>.', 'javascript:history.go(-1)') );
+
+ if ( !current_user_can( 'edit_comment', $comment_id ) )
+ comment_footer_die( __('You are not allowed to edit this comment.') );
+
+ if ( 'trash' == $comment->comment_approved )
+ comment_footer_die( __('This comment is in the Trash. Please move it out of the Trash if you want to edit it.') );
+
+ $comment = get_comment_to_edit( $comment_id );
+
+ include('./edit-form-comment.php');
+
+ break;
+
+case 'delete' :
+case 'approve' :
+case 'trash' :
+case 'spam' :
+
+ $title = __('Moderate Comment');
+
+ $comment_id = absint( $_GET['c'] );
+
+ if ( !$comment = get_comment_to_edit( $comment_id ) ) {
+ wp_redirect( admin_url('edit-comments.php?error=1') );
+ die();
+ }
+
+ if ( !current_user_can( 'edit_comment', $comment->comment_ID ) ) {
+ wp_redirect( admin_url('edit-comments.php?error=2') );
+ die();
+ }
+
+ // No need to re-approve/re-trash/re-spam a comment.
+ if ( $action == str_replace( '1', 'approve', $comment->comment_approved ) ) {
+ wp_redirect( admin_url( 'edit-comments.php?same=' . $comment_id ) );
+ die();
+ }
+
+ require_once('./admin-header.php');
+
+ $formaction = $action . 'comment';
+ $nonce_action = 'approve' == $action ? 'approve-comment_' : 'delete-comment_';
+ $nonce_action .= $comment_id;
+
+?>
+<div class='wrap'>
+
+<div class="narrow">
+
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<?php
+switch ( $action ) {
+ case 'spam' :
+ $caution_msg = __('You are about to mark the following comment as spam:');
+ $button = __('Spam Comment');
+ break;
+ case 'trash' :
+ $caution_msg = __('You are about to move the following comment to the Trash:');
+ $button = __('Trash Comment');
+ break;
+ case 'delete' :
+ $caution_msg = __('You are about to delete the following comment:');
+ $button = __('Permanently Delete Comment');
+ break;
+ default :
+ $caution_msg = __('You are about to approve the following comment:');
+ $button = __('Approve Comment');
+ break;
+}
+
+if ( $comment->comment_approved != '0' ) { // if not unapproved
+ $message = '';
+ switch ( $comment->comment_approved ) {
+ case '1' :
+ $message = __('This comment is currently approved.');
+ break;
+ case 'spam' :
+ $message = __('This comment is currently marked as spam.');
+ break;
+ case 'trash' :
+ $message = __('This comment is currently in the Trash.');
+ break;
+ }
+ if ( $message )
+ echo '<div class="updated"><p>' . $message . '</p></div>';
+}
+?>
+<p><strong><?php _e('Caution:'); ?></strong> <?php echo $caution_msg; ?></p>
+
+<table class="form-table comment-ays">
+<tr class="alt">
+<th scope="row"><?php _e('Author'); ?></th>
+<td><?php echo $comment->comment_author; ?></td>
+</tr>
+<?php if ( $comment->comment_author_email ) { ?>
+<tr>
+<th scope="row"><?php _e('E-mail'); ?></th>
+<td><?php echo $comment->comment_author_email; ?></td>
+</tr>
+<?php } ?>
+<?php if ( $comment->comment_author_url ) { ?>
+<tr>
+<th scope="row"><?php _e('URL'); ?></th>
+<td><a href="<?php echo $comment->comment_author_url; ?>"><?php echo $comment->comment_author_url; ?></a></td>
+</tr>
+<?php } ?>
+<tr>
+<th scope="row" valign="top"><?php /* translators: field name in comment form */ _ex('Comment', 'noun'); ?></th>
+<td><?php echo $comment->comment_content; ?></td>
+</tr>
+</table>
+
+<p><?php _e('Are you sure you want to do this?'); ?></p>
+
+<form action='comment.php' method='get'>
+
+<table width="100%">
+<tr>
+<td><a class="button" href="<?php echo admin_url('edit-comments.php'); ?>"><?php esc_attr_e('No'); ?></a></td>
+<td class="textright"><?php submit_button( $button, 'button' ); ?></td>
+</tr>
+</table>
+
+<?php wp_nonce_field( $nonce_action ); ?>
+<input type='hidden' name='action' value='<?php echo esc_attr($formaction); ?>' />
+<input type='hidden' name='c' value='<?php echo esc_attr($comment->comment_ID); ?>' />
+<input type='hidden' name='noredir' value='1' />
+</form>
+
+</div>
+</div>
+<?php
+ break;
+
+case 'deletecomment' :
+case 'trashcomment' :
+case 'untrashcomment' :
+case 'spamcomment' :
+case 'unspamcomment' :
+case 'approvecomment' :
+case 'unapprovecomment' :
+ $comment_id = absint( $_REQUEST['c'] );
+
+ if ( in_array( $action, array( 'approvecomment', 'unapprovecomment' ) ) )
+ check_admin_referer( 'approve-comment_' . $comment_id );
+ else
+ check_admin_referer( 'delete-comment_' . $comment_id );
+
+ $noredir = isset($_REQUEST['noredir']);
+
+ if ( !$comment = get_comment($comment_id) )
+ comment_footer_die( __('Oops, no comment with this ID.') . sprintf(' <a href="%s">' . __('Go back') . '</a>.', 'edit-comments.php') );
+ if ( !current_user_can( 'edit_comment', $comment->comment_ID ) )
+ comment_footer_die( __('You are not allowed to edit comments on this post.') );
+
+ if ( '' != wp_get_referer() && ! $noredir && false === strpos(wp_get_referer(), 'comment.php') )
+ $redir = wp_get_referer();
+ elseif ( '' != wp_get_original_referer() && ! $noredir )
+ $redir = wp_get_original_referer();
+ elseif ( in_array( $action, array( 'approvecomment', 'unapprovecomment' ) ) )
+ $redir = admin_url('edit-comments.php?p=' . absint( $comment->comment_post_ID ) );
+ else
+ $redir = admin_url('edit-comments.php');
+
+ $redir = remove_query_arg( array('spammed', 'unspammed', 'trashed', 'untrashed', 'deleted', 'ids', 'approved', 'unapproved'), $redir );
+
+ switch ( $action ) {
+ case 'deletecomment' :
+ wp_delete_comment( $comment_id );
+ $redir = add_query_arg( array('deleted' => '1'), $redir );
+ break;
+ case 'trashcomment' :
+ wp_trash_comment($comment_id);
+ $redir = add_query_arg( array('trashed' => '1', 'ids' => $comment_id), $redir );
+ break;
+ case 'untrashcomment' :
+ wp_untrash_comment($comment_id);
+ $redir = add_query_arg( array('untrashed' => '1'), $redir );
+ break;
+ case 'spamcomment' :
+ wp_spam_comment($comment_id);
+ $redir = add_query_arg( array('spammed' => '1', 'ids' => $comment_id), $redir );
+ break;
+ case 'unspamcomment' :
+ wp_unspam_comment($comment_id);
+ $redir = add_query_arg( array('unspammed' => '1'), $redir );
+ break;
+ case 'approvecomment' :
+ wp_set_comment_status( $comment_id, 'approve' );
+ $redir = add_query_arg( array( 'approved' => 1 ), $redir );
+ break;
+ case 'unapprovecomment' :
+ wp_set_comment_status( $comment_id, 'hold' );
+ $redir = add_query_arg( array( 'unapproved' => 1 ), $redir );
+ break;
+ }
+
+ wp_redirect( $redir );
+ die;
+ break;
+
+case 'editedcomment' :
+
+ $comment_id = absint( $_POST['comment_ID'] );
+ $comment_post_id = absint( $_POST['comment_post_ID'] );
+
+ check_admin_referer( 'update-comment_' . $comment_id );
+
+ edit_comment();
+
+ $location = ( empty( $_POST['referredby'] ) ? "edit-comments.php?p=$comment_post_id" : $_POST['referredby'] ) . '#comment-' . $comment_id;
+ $location = apply_filters( 'comment_edit_redirect', $location, $comment_id );
+ wp_redirect( $location );
+
+ exit();
+ break;
+
+default:
+ wp_die( __('Unknown action.') );
+ break;
+
+} // end switch
+
+include('./admin-footer.php');
diff --git a/src/wp-admin/credits.php b/src/wp-admin/credits.php
new file mode 100644
index 0000000000..7052357b8b
--- /dev/null
+++ b/src/wp-admin/credits.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * Credits administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+$title = __( 'Credits' );
+
+function wp_credits() {
+ global $wp_version;
+ $locale = get_locale();
+
+ $results = get_site_transient( 'wordpress_credits_' . $locale );
+
+ if ( ! is_array( $results )
+ || ( isset( $results['data']['version'] ) && strpos( $wp_version, $results['data']['version'] ) !== 0 )
+ ) {
+ $response = wp_remote_get( "http://api.wordpress.org/core/credits/1.0/?version=$wp_version&locale=$locale" );
+
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
+ return false;
+
+ $results = maybe_unserialize( wp_remote_retrieve_body( $response ) );
+
+ if ( ! is_array( $results ) )
+ return false;
+
+ set_site_transient( 'wordpress_credits_' . $locale, $results, DAY_IN_SECONDS );
+ }
+
+ return $results;
+}
+
+function _wp_credits_add_profile_link( &$display_name, $username, $profiles ) {
+ $display_name = '<a href="' . esc_url( sprintf( $profiles, $username ) ) . '">' . esc_html( $display_name ) . '</a>';
+}
+
+function _wp_credits_build_object_link( &$data ) {
+ $data = '<a href="' . esc_url( $data[1] ) . '">' . $data[0] . '</a>';
+}
+
+list( $display_version ) = explode( '-', $wp_version );
+
+include( ABSPATH . 'wp-admin/admin-header.php' );
+?>
+<div class="wrap about-wrap">
+
+<h1><?php printf( __( 'Welcome to WordPress %s' ), $display_version ); ?></h1>
+
+<div class="about-text"><?php printf( __( 'Thank you for updating to the latest version. WordPress %s makes your writing experience even better.' ), $display_version ); ?></div>
+
+<div class="wp-badge"><?php printf( __( 'Version %s' ), $display_version ); ?></div>
+
+<h2 class="nav-tab-wrapper">
+ <a href="about.php" class="nav-tab">
+ <?php _e( 'What&#8217;s New' ); ?>
+ </a><a href="credits.php" class="nav-tab nav-tab-active">
+ <?php _e( 'Credits' ); ?>
+ </a><a href="freedoms.php" class="nav-tab">
+ <?php _e( 'Freedoms' ); ?>
+ </a>
+</h2>
+
+<?php
+
+$credits = wp_credits();
+
+if ( ! $credits ) {
+ echo '<p class="about-description">' . sprintf( __( 'WordPress is created by a <a href="%1$s">worldwide team</a> of passionate individuals. <a href="%2$s">Get involved in WordPress</a>.' ),
+ 'http://wordpress.org/about/',
+ /* translators: Url to the codex documentation on contributing to WordPress used on the credits page */
+ __( 'http://codex.wordpress.org/Contributing_to_WordPress' ) ) . '</p>';
+ include( ABSPATH . 'wp-admin/admin-footer.php' );
+ exit;
+}
+
+echo '<p class="about-description">' . __( 'WordPress is created by a worldwide team of passionate individuals.' ) . "</p>\n";
+
+$gravatar = is_ssl() ? 'https://secure.gravatar.com/avatar/' : 'http://0.gravatar.com/avatar/';
+
+foreach ( $credits['groups'] as $group_slug => $group_data ) {
+ if ( $group_data['name'] ) {
+ if ( 'Translators' == $group_data['name'] ) {
+ // Considered a special slug in the API response. (Also, will never be returned for en_US.)
+ $title = _x( 'Translators', 'Translate this to be the equivalent of English Translators in your language for the credits page Translators section' );
+ } elseif ( isset( $group_data['placeholders'] ) ) {
+ $title = vsprintf( translate( $group_data['name'] ), $group_data['placeholders'] );
+ } else {
+ $title = translate( $group_data['name'] );
+ }
+
+ echo '<h4 class="wp-people-group">' . $title . "</h4>\n";
+ }
+
+ if ( ! empty( $group_data['shuffle'] ) )
+ shuffle( $group_data['data'] ); // We were going to sort by ability to pronounce "hierarchical," but that wouldn't be fair to Matt.
+
+ switch ( $group_data['type'] ) {
+ case 'list' :
+ array_walk( $group_data['data'], '_wp_credits_add_profile_link', $credits['data']['profiles'] );
+ echo '<p class="wp-credits-list">' . wp_sprintf( '%l.', $group_data['data'] ) . "</p>\n\n";
+ break;
+ case 'libraries' :
+ array_walk( $group_data['data'], '_wp_credits_build_object_link' );
+ echo '<p class="wp-credits-list">' . wp_sprintf( '%l.', $group_data['data'] ) . "</p>\n\n";
+ break;
+ default:
+ $compact = 'compact' == $group_data['type'];
+ $classes = 'wp-people-group ' . ( $compact ? 'compact' : '' );
+ echo '<ul class="' . $classes . '" id="wp-people-group-' . $group_slug . '">' . "\n";
+ foreach ( $group_data['data'] as $person_data ) {
+ echo '<li class="wp-person" id="wp-person-' . $person_data[2] . '">' . "\n\t";
+ echo '<a href="' . sprintf( $credits['data']['profiles'], $person_data[2] ) . '">';
+ $size = 'compact' == $group_data['type'] ? '30' : '60';
+ echo '<img src="' . $gravatar . $person_data[1] . '?s=' . $size . '" class="gravatar" alt="' . esc_attr( $person_data[0] ) . '" /></a>' . "\n\t";
+ echo '<a class="web" href="' . sprintf( $credits['data']['profiles'], $person_data[2] ) . '">' . $person_data[0] . "</a>\n\t";
+ if ( ! $compact )
+ echo '<span class="title">' . translate( $person_data[3] ) . "</span>\n";
+ echo "</li>\n";
+ }
+ echo "</ul>\n";
+ break;
+ }
+}
+
+?>
+<p class="clear"><?php printf( __( 'Want to see your name in lights on this page? <a href="%s">Get involved in WordPress</a>.' ),
+ /* translators: Url to the codex documentation on contributing to WordPress used on the credits page */
+ __( 'http://codex.wordpress.org/Contributing_to_WordPress' ) ); ?></p>
+
+</div>
+<?php
+
+include( ABSPATH . 'wp-admin/admin-footer.php' );
+
+return;
+
+// These are strings returned by the API that we want to be translatable
+__( 'Project Leaders' );
+__( 'Extended Core Team' );
+__( 'Core Developers' );
+__( 'Recent Rockstars' );
+__( 'Core Contributors to WordPress %s' );
+__( 'Contributing Developers' );
+__( 'Cofounder, Project Lead' );
+__( 'Lead Developer' );
+__( 'User Experience Lead' );
+__( 'Core Developer' );
+__( 'Core Committer' );
+__( 'Guest Committer' );
+__( 'Developer' );
+__( 'Designer' );
+__( 'XML-RPC' );
+__( 'Internationalization' );
+__( 'External Libraries' );
+__( 'Icon Design' );
diff --git a/src/wp-admin/css/color-picker-rtl.css b/src/wp-admin/css/color-picker-rtl.css
new file mode 100644
index 0000000000..8c8869daa7
--- /dev/null
+++ b/src/wp-admin/css/color-picker-rtl.css
@@ -0,0 +1,27 @@
+.wp-color-result {
+ margin: 0 0 6px 6px;
+ padding-left: 0;
+ padding-right: 30px;
+}
+
+.wp-color-result:after {
+ border-radius: 0 0 1px 1px;
+ border-left: 0;
+ border-right: 1px solid #bbb;
+ left: auto;
+ right: 0;
+}
+
+.wp-color-result:hover {
+ border-color: #aaa;
+}
+
+.wp-color-result:hover:after {
+ border-left: 0;
+ border-right: 1px solid #999;
+}
+
+.wp-picker-container .button {
+ margin-left: 0;
+ margin-right: 6px;
+}
diff --git a/src/wp-admin/css/color-picker.css b/src/wp-admin/css/color-picker.css
new file mode 100644
index 0000000000..925d890bb5
--- /dev/null
+++ b/src/wp-admin/css/color-picker.css
@@ -0,0 +1,107 @@
+.wp-color-picker {
+ width: 80px;
+}
+
+.wp-picker-container .hidden {
+ display: none;
+}
+
+.wp-color-result {
+ background-color: #f9f9f9;
+ border: 1px solid #bbb;
+ border-radius: 2px;
+ cursor: pointer;
+ display: inline-block;
+ height: 22px;
+ margin: 0 6px 6px 0px;
+ position: relative;
+ top: 1px;
+ user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ vertical-align: bottom;
+ display: inline-block;
+ padding-left: 30px;
+}
+
+.wp-color-result:after {
+ background: #f3f3f3;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#f4f4f4));
+ background-image: -webkit-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: -moz-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: -o-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: linear-gradient(to bottom, #fefefe, #f4f4f4);
+ color: #333;
+ text-shadow: 0 1px 0 #fff;
+ border-radius: 0 1px 1px 0;
+ border-left: 1px solid #bbb;
+ content: attr( title );
+ display: block;
+ font-size: 11px;
+ line-height: 22px;
+ padding: 0 6px;
+ position: relative;
+ right: 0;
+ text-align: center;
+ top: 0;
+}
+
+.wp-color-result:hover {
+ border-color: #aaa;
+ -webkit-box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.2 );
+ box-shadow: 0 1px 1px rgba( 0, 0, 0, 0.1 );
+}
+
+.wp-color-result:hover:after {
+ color: #222;
+ border-color: #aaa;
+ border-left: 1px solid #999;
+}
+
+.wp-color-result.wp-picker-open {
+ top: 0;
+}
+
+.wp-color-result.wp-picker-open:after {
+ content: attr( data-current );
+}
+
+.wp-picker-container, .wp-picker-container:active {
+ display: inline-block;
+ outline: 0;
+}
+
+.wp-color-result:focus {
+ border-color: #888;
+ -webkit-box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.2 );
+ box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.2 );
+}
+
+.wp-color-result:focus:after {
+ border-color: #888;
+}
+
+.wp-picker-open + .wp-picker-input-wrap {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.wp-picker-container .button {
+ margin-left: 6px;
+}
+
+.wp-picker-container .iris-square-slider .ui-slider-handle:focus {
+ background-color: #555
+}
+
+.wp-picker-container .iris-picker {
+ border-color: #dfdfdf;
+ margin-top: 6px;
+}
+
+input[type="text"].iris-error {
+ background-color: #ffebe8;
+ border-color: #c00;
+ color: #000;
+}
diff --git a/src/wp-admin/css/colors-classic.css b/src/wp-admin/css/colors-classic.css
new file mode 100644
index 0000000000..2dbbb30a50
--- /dev/null
+++ b/src/wp-admin/css/colors-classic.css
@@ -0,0 +1,2259 @@
+/*------------------------------------------------------------------------------
+
+
+Howdy! This is the CSS file that controls the
+Blue (classic) color style on the WordPress Dashboard.
+
+This file contains both LTR and RTL styles.
+
+
+TABLE OF CONTENTS:
+------------------
+ 1.0 - Left to Right Styles
+ 2.0 - Right to Left Styles
+
+
+------------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+ 1.0 - Left to Right Styles
+------------------------------------------------------------------------------*/
+
+.find-box-search,
+.find-box-buttons {
+ background-color: #eff8ff;
+ border-top: 1px solid #dce6f8;
+}
+
+.find-box {
+ background-color: #5589aa;
+}
+
+.find-box-head {
+ color: #fff;
+}
+
+.find-box-inside {
+ background-color: #fff;
+}
+
+a.page-numbers:hover {
+ border-color: #999;
+}
+
+body,
+#wpbody,
+.form-table .pre,
+.ui-autocomplete li a {
+ color: #333;
+}
+
+body > #upload-menu {
+ border-bottom-color: #fff;
+}
+
+#postcustomstuff table,
+#your-profile fieldset,
+#rightnow,
+div.dashboard-widget,
+#dashboard-widgets p.dashboard-widget-links {
+ border-color: #d1e5ee;
+}
+
+#poststuff .inside label.spam,
+#poststuff .inside label.deleted {
+ color: red;
+}
+
+#poststuff .inside label.waiting {
+ color: orange;
+}
+
+#poststuff .inside label.approved {
+ color: green;
+}
+
+#postcustomstuff table {
+ border-color: #dfdfdf;
+ background-color: #f9f9f9;
+}
+
+#postcustomstuff thead th {
+ background-color: #f1f1f1;
+}
+
+table.widefat {
+ border-color: #d1e5ee;
+ background-color: #fff;
+}
+
+div.dashboard-widget-error {
+ background-color: #c43;
+}
+
+div.dashboard-widget-notice {
+ background-color: #cfe1ef;
+}
+
+div.dashboard-widget-submit {
+ border-top-color: #ccc;
+}
+
+ul.category-tabs li {
+ border-color: transparent;
+}
+
+div.tabs-panel,
+.wp-tab-panel,
+ul.add-menu-item-tabs li.tabs,
+.wp-tab-active {
+ border-color: #d1e5ee;
+ background-color: #fff;
+}
+
+ul.category-tabs li.tabs {
+ border-color: #d1e5ee #d1e5ee #fff;
+}
+
+ul.category-tabs li.tabs,
+ul.add-menu-item-tabs li.tabs,
+.wp-tab-active {
+ background-color: #fff;
+}
+
+kbd,
+code {
+ background: #eff8ff;
+}
+
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="file"],
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="tel"],
+input[type="url"],
+select {
+ border-color: #d1e5ee;
+}
+
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="file"]:focus,
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+select:focus {
+ border-color: #b0c8d7;
+}
+
+input.disabled,
+textarea.disabled {
+ background-color: #ccc;
+}
+
+#plugin-information .action-button a,
+#plugin-information .action-button a:hover,
+#plugin-information .action-button a:visited {
+ color: #fff;
+}
+
+.revisions-meta,
+.widget .widget-top,
+.postbox h3,
+.stuffbox h3,
+.widefat thead tr th,
+.widefat tfoot tr th,
+h3.dashboard-widget-title,
+h3.dashboard-widget-title span,
+h3.dashboard-widget-title small,
+.sidebar-name,
+#nav-menu-header,
+#nav-menu-footer,
+.menu-item-handle,
+#fullscreen-topbar {
+ background: #f5fafd;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eff8ff), to(#f7fcfe));
+ background-image: -webkit-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -moz-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -o-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: linear-gradient(to top, #eff8ff, #f7fcfe);
+}
+
+.widget .widget-top,
+.postbox h3,
+.stuffbox h3 {
+ border-bottom-color: #d1e5ee;
+ text-shadow: #fff 0 1px 0;
+ -webkit-box-shadow: 0 1px 0 #fff;
+ box-shadow: 0 1px 0 #fff;
+}
+
+.form-table th,
+.form-wrap label {
+ color: #222;
+ text-shadow: #fff 0 1px 0;
+}
+
+.description,
+.form-wrap p {
+ color: #666;
+}
+
+strong .post-com-count span {
+ background-color: #21759b;
+}
+
+.sorthelper {
+ background-color: #ccf3fa;
+}
+
+.ac_match,
+.subsubsub a.current {
+ color: #000;
+}
+
+.wrap h2 {
+ color: #174f69;
+}
+
+.wrap .add-new-h2,
+.wrap .add-new-h2:active {
+ background: #f1f1f1;
+}
+
+.subtitle {
+ color: #777;
+}
+
+.ac_over {
+ background-color: #f0f0b8;
+}
+
+.ac_results {
+ background-color: #fff;
+ border-color: #b0c8d7;
+}
+
+.ac_results li {
+ color: #101010;
+}
+
+.alternate,
+.alt {
+ background-color: #f7fcfe;
+}
+
+.available-theme a.screenshot {
+ background-color: #eff8ff;
+ border-color: #acd;
+}
+
+#current-theme {
+ border-bottom-color: #d1e5ee;
+}
+
+.bar {
+ background-color: #e8e8e8;
+ border-right-color: #99d;
+}
+
+#media-upload,
+#media-upload .media-item .slidetoggle {
+ background: #fff;
+}
+
+#media-upload .slidetoggle {
+ border-top-color: #dfdfdf;
+}
+
+div.error,
+.login #login_error {
+ background-color: #ffebe8;
+ border-color: #c00;
+}
+
+div.error a {
+ color: #c00;
+}
+
+.form-invalid {
+ background-color: #ffebe8 !important;
+}
+
+.form-invalid input,
+.form-invalid select {
+ border-color: #c00 !important;
+}
+
+.submit,
+#commentsdiv #add-new-comment {
+ border-color: #dfdfdf;
+}
+
+.highlight {
+ background-color: #e4f2fd;
+ color: #000;
+}
+
+.howto,
+.nonessential,
+#edit-slug-box,
+.form-input-tip,
+.subsubsub {
+ color: #666;
+}
+
+.media-upload-form label.form-help,
+td.help {
+ color: #9a9a9a;
+}
+
+.ui-autocomplete {
+ border-color: #b0c8d7;
+ background-color: #eff8ff;
+}
+
+.ui-autocomplete li a.ui-state-focus {
+ background-color: #def1ff;
+}
+
+.post-com-count {
+ color: #fff;
+}
+
+.post-com-count span {
+ background-color: #bbb;
+ color: #fff;
+}
+
+.post-com-count:hover span {
+ background-color: #d54e21;
+}
+
+.quicktags, .search {
+ background-color: #ccc;
+ color: #000;
+}
+
+.side-info h5 {
+ border-bottom-color: #dadada;
+}
+
+.side-info ul {
+ color: #666;
+}
+
+a:hover,
+a:active {
+ color: #d54e21;
+}
+
+a:focus {
+ color: #124964;
+}
+
+#adminmenu a:hover,
+#adminmenu li.menu-top > a:focus,
+#adminmenu .wp-submenu a:hover,
+#the-comment-list .comment a:hover,
+#rightnow a:hover,
+#media-upload a.del-link:hover,
+div.dashboard-widget-submit input:hover,
+.subsubsub a:hover,
+.subsubsub a.current:hover,
+.ui-tabs-nav a:hover,
+.plugins .inactive a:hover,
+#all-plugins-table .plugins .inactive a:hover,
+#search-plugins-table .plugins .inactive a:hover {
+ color: #d54e21;
+}
+
+#the-comment-list .comment-item,
+#dashboard-widgets #dashboard_quick_press form p.submit {
+ border-color: #dfdfdf;
+}
+
+#side-sortables .category-tabs .tabs a,
+#side-sortables .add-menu-item-tabs .tabs a,
+.wp-tab-bar .wp-tab-active a {
+ color: #333;
+}
+
+#dashboard_right_now .table_content,
+#dashboard_right_now .table_discussion {
+ border-top-color: #d1e5ee;
+}
+
+#rightnow .rbutton {
+ background-color: #ebebeb;
+ color: #264761;
+}
+
+.submitbox .submit {
+ background-color: #464646;
+ color: #ccc;
+}
+
+.plugins a.delete:hover,
+#all-plugins-table .plugins a.delete:hover,
+#search-plugins-table .plugins a.delete:hover,
+.submitbox .submitdelete {
+ color: #f00;
+ border-bottom-color: #f00;
+}
+
+.submitbox .submitdelete:hover,
+#media-items a.delete:hover,
+#media-items a.delete-permanently:hover {
+ color: #fff;
+ background-color: #f00;
+ border-bottom-color: #f00;
+}
+
+#normal-sortables .submitbox .submitdelete:hover {
+ color: #000;
+ background-color: #f00;
+ border-bottom-color: #f00;
+}
+
+.tablenav .dots {
+ border-color: transparent;
+}
+
+.tablenav .next,
+.tablenav .prev {
+ border-color: transparent;
+ color: #21759b;
+}
+
+.tablenav .next:hover,
+.tablenav .prev:hover {
+ border-color: transparent;
+ color: #d54e21;
+}
+
+div.updated,
+.login .message {
+ background-color: #ffffe0;
+ border-color: #e6db55;
+}
+
+.update-message {
+ color: #000;
+}
+
+a.page-numbers {
+ border-bottom-color: #b8d3e2;
+}
+
+.commentlist li {
+ border-bottom-color: #ccc;
+}
+
+.widefat td,
+.widefat th {
+ border-top-color: #fff;
+ border-bottom-color: #d0dfe9;
+}
+
+.widefat th {
+ text-shadow: rgba(255,255,255,0.8) 0 1px 0;
+}
+
+.widefat td {
+ color: #555;
+}
+.widefat p,
+.widefat ol,
+.widefat ul {
+ color: #333;
+}
+
+.widefat thead tr th,
+.widefat tfoot tr th,
+h3.dashboard-widget-title,
+h3.dashboard-widget-title span,
+h3.dashboard-widget-title small {
+ color: #333;
+}
+
+th.sortable a:hover,
+th.sortable a:active,
+th.sortable a:focus {
+ color: #333;
+}
+
+th.sortable a:focus {
+ background: #e1e1e1;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#dcdcdc), to(#e9e9e9));
+ background-image: -webkit-linear-gradient(bottom, #dcdcdc, #e9e9e9);
+ background-image: -moz-linear-gradient(bottom, #dcdcdc, #e9e9e9);
+ background-image: -o-linear-gradient(bottom, #dcdcdc, #e9e9e9);
+ background-image: linear-gradient(to top, #dcdcdc, #e9e9e9);
+}
+
+h3.dashboard-widget-title small a {
+ color: #d7d7d7;
+}
+
+h3.dashboard-widget-title small a:hover {
+ color: #fff;
+}
+
+a,
+#adminmenu a,
+#the-comment-list p.comment-author strong a,
+#media-upload a.del-link,
+#media-items a.delete,
+#media-items a.delete-permanently,
+.plugins a.delete,
+.ui-tabs-nav a {
+ color: #21759b;
+}
+
+#adminmenu .awaiting-mod,
+#adminmenu .update-plugins,
+#sidemenu a .update-plugins,
+#rightnow .reallynow {
+ background-color: #464646;
+ color: #fff;
+ -webkit-box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+ box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+}
+#plugin-information .action-button {
+ background-color: #d54e21;
+ color: #fff;
+}
+
+#adminmenu li.current a .awaiting-mod,
+#adminmenu li a.wp-has-current-submenu .update-plugins{
+ background-color: #464646;
+ color: #fff;
+ -webkit-box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+ box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+}
+
+div#media-upload-header,
+div#plugin-information-header {
+ background-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+#currenttheme img {
+ border-color: #666;
+}
+
+#dashboard_secondary div.dashboard-widget-content ul li a {
+ background-color: #f9f9f9;
+}
+
+input.readonly, textarea.readonly {
+ background-color: #ddd;
+}
+
+#editable-post-name {
+ background-color: #fffbcc;
+}
+
+#edit-slug-box strong,
+.tablenav .displaying-num,
+#submitted-on,
+.submitted-on {
+ color: #777;
+}
+
+.login #nav a,
+.login #backtoblog a {
+ color: #21759b !important;
+}
+
+.login #nav a:hover,
+.login #backtoblog a:hover {
+ color: #d54e21 !important;
+}
+
+#wpfooter {
+ color: #777;
+ border-color: #b0c8d7;
+}
+
+.imgedit-group,
+#media-items .media-item,
+.media-item .describe {
+ border-color: #dfdfdf;
+}
+
+.checkbox,
+.side-info,
+.plugins tr,
+#your-profile #rich_editing {
+ background-color: #fcfcfc;
+}
+
+.plugins .inactive,
+.plugins .inactive th,
+.plugins .inactive td,
+tr.inactive + tr.plugin-update-tr .plugin-update {
+ background-color: #f7fcfe;
+}
+
+.plugin-update-tr .update-message {
+ background-color: #fffbe4;
+ border-color: #dfdfdf;
+}
+
+.plugins .active,
+.plugins .active th,
+.plugins .active td {
+ color: #000;
+}
+
+.plugins .inactive a {
+ color: #579;
+}
+
+#the-comment-list tr.undo,
+#the-comment-list div.undo {
+ background-color: #f4f4f4;
+}
+
+#the-comment-list .unapproved {
+ background-color: #ffffe0;
+}
+
+#the-comment-list .approve a {
+ color: #006505;
+}
+
+#the-comment-list .unapprove a {
+ color: #d98500;
+}
+
+table.widefat span.delete a,
+table.widefat span.trash a,
+table.widefat span.spam a,
+#dashboard_recent_comments .delete a,
+#dashboard_recent_comments .trash a,
+#dashboard_recent_comments .spam a {
+ color: #bc0b0b;
+}
+
+.welcome-panel {
+ background: #f5fafd;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eff8ff), to(#f7fcfe));
+ background-image: -webkit-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -moz-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -o-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: linear-gradient(to top, #eff8ff, #f7fcfe);
+ border-color: #d1e5ee;
+}
+.welcome-panel p {
+ color: #777;
+}
+.welcome-panel-column p {
+ color: #464646;
+}
+.welcome-panel h3 {
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.widget,
+#widget-list .widget-top,
+.postbox,
+#titlediv,
+#poststuff .postarea,
+.stuffbox {
+ border-color: #d1e5ee;
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.widget,
+#widget-list .widget-top,
+.postbox,
+.menu-item-settings {
+ background: #f5fafd;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eff8ff), to(#f7fcfe));
+ background-image: -webkit-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -moz-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -o-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: linear-gradient(to top, #eff8ff, #f7fcfe);
+}
+
+.postbox h3 {
+ color: #174f69;
+}
+
+.widget .widget-top {
+ color: #174f69;
+}
+
+.js .sidebar-name:hover h3,
+.js .postbox h3:hover {
+ color: #000;
+}
+
+.curtime #timestamp {
+ background-image: url(../images/date-button.gif);
+}
+
+#quicktags #ed_link {
+ color: #00f;
+}
+
+#rightnow .youhave {
+ background-color: #f0f6fb;
+}
+
+#rightnow a {
+ color: #448abd;
+}
+
+.tagchecklist span a,
+#bulk-titles div a {
+ background: url(../images/xit.gif) no-repeat;
+}
+
+.tagchecklist span a:hover,
+#bulk-titles div a:hover {
+ background: url(../images/xit.gif) no-repeat -10px 0;
+}
+
+#update-nag, .update-nag {
+ background-color: #fffbcc;
+ border-color: #e6db55;
+ color: #555;
+}
+
+#screen-meta {
+ background-color: #eff8ff;
+ border-color: #d1e5ee;
+ -webkit-box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.05 );
+ box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.05 );
+}
+
+#contextual-help-back {
+ background: #fff;
+}
+
+.contextual-help-tabs a:hover {
+ background-color: #ceeaff;
+ color: #333;
+}
+
+#contextual-help-back,
+.contextual-help-tabs .active {
+ border-color: #d1e5ee;
+}
+
+.contextual-help-tabs .active,
+.contextual-help-tabs .active a,
+.contextual-help-tabs .active a:hover {
+ background: #fff;
+ color: #000;
+}
+
+/* screen options and help tabs */
+#screen-options-link-wrap,
+#contextual-help-link-wrap {
+ border-right: 1px solid #d1e5ee;
+ border-left: 1px solid #d1e5ee;
+ border-bottom: 1px solid #d1e5ee;
+ background: #eff8ff;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#def1ff), to(#eff8ff));
+ background-image: -webkit-linear-gradient(bottom, #def1ff, #eff8ff);
+ background-image: -moz-linear-gradient(bottom, #def1ff, #eff8ff);
+ background-image: -o-linear-gradient(bottom, #def1ff, #eff8ff);
+ background-image: linear-gradient(to top, #def1ff, #eff8ff);
+}
+
+#screen-meta-links a {
+ color: #606060;
+ background: transparent url(../images/arrows.png) no-repeat right 4px;
+}
+
+#screen-meta-links a:hover,
+#screen-meta-links a:active {
+ color: #000;
+ background-color: transparent;
+}
+
+#screen-meta-links a.screen-meta-active {
+ background-position: right -31px;
+}
+
+/* end screen options and help tabs */
+
+.login #backtoblog a {
+ color: #464646;
+}
+
+#wphead {
+ border-bottom: 1px solid #d0dfe9;
+}
+
+#wphead h1 a {
+ color: #174f69;
+}
+
+#wpfooter a:link,
+#wpfooter a:visited {
+ text-decoration: none;
+}
+
+#wpfooter a:hover {
+ color: #000;
+ text-decoration: underline;
+}
+
+.file-error,
+abbr.required,
+.widget-control-remove:hover,
+table.widefat .delete a:hover,
+table.widefat .trash a:hover,
+table.widefat .spam a:hover,
+#dashboard_recent_comments .delete a:hover,
+#dashboard_recent_comments .trash a:hover
+#dashboard_recent_comments .spam a:hover {
+ color: #f00;
+}
+
+#pass-strength-result {
+ background-color: #eee;
+ border-color: #ddd !important;
+}
+
+#pass-strength-result.bad {
+ background-color: #ffb78c;
+ border-color: #ff853c !important;
+}
+
+#pass-strength-result.good {
+ background-color: #ffec8b;
+ border-color: #fc0 !important;
+}
+
+#pass-strength-result.short {
+ background-color: #ffa0a0;
+ border-color: #f04040 !important;
+}
+
+#pass-strength-result.strong {
+ background-color: #c3ff88;
+ border-color: #8dff1c !important;
+}
+
+/* editors */
+#poststuff .wp-editor-wrap .wp_themeSkin .mceStatusbar {
+ border-color: #d0dfe9;
+ background-color: #eff8ff;
+}
+
+#poststuff .wp-editor-wrap .wp_themeSkin .mceStatusbar * {
+ color: #555;
+}
+
+#poststuff #editor-toolbar .active {
+ border-color: #d0dfe9 #d0dfe9 #eff8ff;
+ background-color: #eff8ff;
+ color: #333;
+}
+
+.wp-editor-wrap .wp-editor-container,
+.wp-editor-wrap .wp_themeSkin table.mceLayout {
+ border-color: #d1e5ee #d1e5ee #d0dfe9;
+}
+
+#editorcontainer {
+ border-color: #d1e5ee #d1e5ee #d0dfe9;
+}
+
+#post-status-info {
+ border-color: #d0dfe9 #d1e5ee #d1e5ee;
+}
+
+/* TinyMCE */
+
+.wp-admin .wp-editor-wrap .wp-switch-editor {
+ background-color: #d3e9f2;
+ border-color: #d1e5ee #d1e5ee #d3e9f2;
+ color: #174F69;
+}
+
+.wp-admin .wp-editor-wrap .wp-switch-editor:active {
+ background-color: #f5fafd;
+}
+
+.wp-admin .wp-editor-wrap.tmce-active .switch-tmce,
+.wp-admin .wp-editor-wrap.html-active .switch-html {
+ background: #f7fcfe;
+ border-color: #d1e5ee #d1e5ee #f7fcfe;
+}
+
+.wp-admin .wp-editor-wrap .quicktags-toolbar,
+.wp-admin .wp-editor-wrap .wp_themeSkin tr.mceFirst td.mceToolbar {
+ border-color: #d0dfe9;
+ background-color: #f5fafd;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eff8ff), to(#f7fcfe));
+ background-image: -webkit-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -moz-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: -o-linear-gradient(bottom, #eff8ff, #f7fcfe);
+ background-image: linear-gradient(to top, #eff8ff, #f7fcfe);
+}
+
+.wp-admin .wp_themeSkin table.mceListBox {
+ border-color: #d1e5ee;
+}
+
+.wp-admin .wp_themeSkin table.mceListBoxEnabled:hover,
+.wp-admin .wp_themeSkin table.mceListBoxEnabled:active,
+.wp-admin .wp_themeSkin table.mceListBoxHover,
+.wp-admin .wp_themeSkin table.mceListBoxHover:active,
+.wp-admin .wp_themeSkin table.mceListBoxSelected {
+ border-color: #b8cfdf;
+}
+
+.wp-admin .wp_themeSkin a.mceButtonEnabled:hover,
+.wp-admin .wp_themeSkin table.mceSplitButton:hover {
+ border-color: #c3d2dc;
+ background: #f4f9fc;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#f4f9fc), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #f4f9fc, #fff);
+ background-image: -moz-linear-gradient(bottom, #f4f9fc, #fff);
+ background-image: -o-linear-gradient(bottom, #f4f9fc, #fff);
+ background-image: linear-gradient(to top, #f4f9fc, #fff);
+}
+
+.wp-admin .wp_themeSkin a.mceButton:active,
+.wp-admin .wp_themeSkin a.mceButtonEnabled:active,
+.wp-admin .wp_themeSkin a.mceButtonSelected:active,
+.wp-admin .wp_themeSkin a.mceButtonActive,
+.wp-admin .wp_themeSkin a.mceButtonActive:active,
+.wp-admin .wp_themeSkin a.mceButtonActive:hover,
+.wp-admin .wp_themeSkin .mceSplitButtonSelected table,
+.wp-admin .wp_themeSkin .mceSplitButtonSelected table:hover {
+ border-color: #8f9da9 #c3d2dc #c3d2dc #8f9da9;
+ background: #f4f9fc;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#fff), to(#f4f9fc));
+ background-image: -webkit-linear-gradient(bottom, #fff, #f4f9fc);
+ background-image: -moz-linear-gradient(bottom, #fff, #f4f9fc);
+ background-image: -o-linear-gradient(bottom, #fff, #f4f9fc);
+ background-image: linear-gradient(to top, #fff, #f4f9fc);
+}
+
+.wp-admin .wp_themeSkin .mceSplitButtonSelected table a.mceOpen,
+.wp-admin .wp_themeSkin .mceSplitButtonSelected table a.mceAction {
+ border-color: #8f9da9 #c3d2dc #c3d2dc #8f9da9;
+}
+
+.wp-admin .wp_themeSkin .mceSplitButton:hover a {
+ border-color: #c3d2dc;
+}
+/* end TinyMCE */
+
+.editwidget .widget-inside {
+ border-color: #d0dfe9;
+}
+
+#titlediv #title {
+ background-color: #fff;
+}
+
+#tTips p#tTips_inside {
+ background-color: #ddd;
+ color: #333;
+}
+
+#poststuff .inside .the-tagcloud {
+ border-color: #ddd;
+}
+
+/* menu */
+#adminmenuback,
+#adminmenuwrap {
+ background-color: #eff8ff;
+ border-color: #d1e5ee;
+}
+
+#adminmenushadow,
+#adminmenuback {
+ background-image: url(../images/menu-shadow.png);
+ background-position: top right;
+ background-repeat: repeat-y;
+}
+
+#adminmenu li.wp-menu-separator {
+ background: #d1e5ee;
+ border-color: #bed1dd;
+}
+
+#adminmenu div.separator {
+ border-color: #d1e5ee;
+}
+
+#adminmenu a.menu-top,
+#adminmenu .wp-submenu .wp-submenu-head {
+ border-top-color: #fff;
+ border-bottom-color: #cae6ff;
+}
+
+#adminmenu li.wp-menu-open {
+ border-color: #d1e5ee;
+}
+
+#adminmenu li.menu-top:hover,
+#adminmenu li.opensub > a.menu-top,
+#adminmenu li > a.menu-top:focus {
+ background-color: #e0f1ff;
+ color: #d54e21;
+ text-shadow: 0 1px 0 rgba( 255, 255, 255, 0.4 );
+}
+
+/* So it doesn't get applied to the number spans (comments, updates, etc) */
+#adminmenu li.menu-top:hover > a span,
+#adminmenu li.menu-top > a:focus span {
+ text-shadow: none;
+}
+
+#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
+#adminmenu li.current a.menu-top,
+.folded #adminmenu li.wp-has-current-submenu,
+.folded #adminmenu li.current.menu-top,
+#adminmenu .wp-menu-arrow,
+#adminmenu .wp-has-current-submenu .wp-submenu .wp-submenu-head {
+ background: #5589aa;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#5589aa), to(#619bbb));
+ background-image: -webkit-linear-gradient(bottom, #5589aa, #619bbb);
+ background-image: -moz-linear-gradient(bottom, #5589aa, #619bbb);
+ background-image: -o-linear-gradient(bottom, #5589aa, #619bbb);
+ background-image: linear-gradient(to top, #5589aa, #619bbb);
+}
+
+#adminmenu .wp-menu-arrow div {
+ background: #5589aa;
+ background-image: -webkit-gradient(linear, right bottom, left top, from(#5589aa), to(#619bbb));
+ background-image: -webkit-linear-gradient(bottom right, #5589aa, #619bbb);
+ background-image: -moz-linear-gradient(bottom right, #5589aa, #619bbb);
+ background-image: -o-linear-gradient(bottom right, #5589aa, #619bbb);
+ background-image: linear-gradient(to top left, #5589aa, #619bbb);
+}
+
+#adminmenu li.wp-not-current-submenu .wp-menu-arrow {
+ border-top-color: #fff;
+ border-bottom-color: #cae6ff;
+ background: #e0f1ff;
+}
+
+#adminmenu li.wp-not-current-submenu .wp-menu-arrow div {
+ background: #e0f1ff;
+ border-color: #cae6ff;
+}
+
+.folded #adminmenu li.menu-top li:hover a {
+ background-image: none;
+}
+
+#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
+#adminmenu li.current a.menu-top,
+#adminmenu .wp-has-current-submenu .wp-submenu .wp-submenu-head {
+ text-shadow: 0 -1px 0 #333;
+ color: #fff;
+ border-top-color: #5a8fad;
+ border-bottom-color: #5589aa;
+}
+
+.folded #adminmenu li.wp-has-current-submenu,
+.folded #adminmenu li.current.menu-top {
+ border-top-color: #5a8fad;
+ border-bottom-color: #5589aa;
+}
+
+#adminmenu .wp-submenu a:hover,
+#adminmenu .wp-submenu a:focus {
+ background-color: #eff8ff;
+ color: #333;
+}
+
+#adminmenu .wp-submenu li.current,
+#adminmenu .wp-submenu li.current a,
+#adminmenu .wp-submenu li.current a:hover {
+ color: #333;
+}
+
+#adminmenu .wp-submenu,
+.folded #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ background-color: #fff;
+ border-color: #d0dfe9;
+ -webkit-box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+ box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+}
+
+#adminmenu .wp-submenu .wp-submenu-head {
+ background-color: #e0f1ff;
+ color: #333;
+}
+
+/* collapse menu button */
+#collapse-menu {
+ color: #a0c3d5;
+ border-top-color: #f9f9f9;
+}
+
+#collapse-menu:hover {
+ color: #5a8fad;
+}
+
+#collapse-button {
+ border-color: #d0dfe9;
+ background: #eff8ff;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eff8ff), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #eff8ff, #fff);
+ background-image: -moz-linear-gradient(bottom, #eff8ff, #fff);
+ background-image: -o-linear-gradient(bottom, #eff8ff, #fff);
+ background-image: linear-gradient(to top, #eff8ff, #fff);
+}
+
+#collapse-menu:hover #collapse-button {
+ border-color: #a0c3d5;
+}
+
+#collapse-button div {
+ background: transparent url(../images/arrows-vs.png) no-repeat 0 -72px;
+}
+
+.folded #collapse-button div {
+ background-position: 0 -108px;
+}
+
+/* Auto-folding of the admin menu */
+@media only screen and (max-width: 900px) {
+ .auto-fold #adminmenu li.wp-has-current-submenu,
+ .auto-fold #adminmenu li.current.menu-top {
+ background-color: #5589aa;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#5589aa), to(#619bbb));
+ background-image: -webkit-linear-gradient(bottom, #5589aa, #619bbb);
+ background-image: -moz-linear-gradient(bottom, #5589aa, #619bbb);
+ background-image: -o-linear-gradient(bottom, #5589aa, #619bbb);
+ background-image: linear-gradient(bottom, #5589aa, #619bbb);
+ }
+
+ .auto-fold #adminmenu li.wp-has-current-submenu,
+ .auto-fold #adminmenu li.current.menu-top {
+ border-top-color: #5a8fad;
+ border-bottom-color: #5589aa;
+ }
+
+ .auto-fold #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu .wp-submenu {
+ background-color: #fff;
+ border-color: #d0dfe9;
+ -webkit-box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+ box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+ }
+
+ .auto-fold #collapse-button div {
+ background-position: 0 -108px;
+ }
+}
+
+/* menu and screen icons */
+.icon16,
+.icon32,
+div.wp-menu-image {
+ background-color: transparent;
+ background-repeat: no-repeat;
+}
+
+.icon16.icon-dashboard,
+.menu-icon-dashboard div.wp-menu-image,
+.icon16.icon-post,
+.menu-icon-post div.wp-menu-image,
+.icon16.icon-media,
+.menu-icon-media div.wp-menu-image,
+.icon16.icon-links,
+.menu-icon-links div.wp-menu-image,
+.icon16.icon-page,
+.menu-icon-page div.wp-menu-image,
+.icon16.icon-comments,
+.menu-icon-comments div.wp-menu-image,
+.icon16.icon-appearance,
+.menu-icon-appearance div.wp-menu-image,
+.icon16.icon-plugins,
+.menu-icon-plugins div.wp-menu-image,
+.icon16.icon-users,
+.menu-icon-users div.wp-menu-image,
+.icon16.icon-tools,
+.menu-icon-tools div.wp-menu-image,
+.icon16.icon-settings,
+.menu-icon-settings div.wp-menu-image,
+.icon16.icon-site,
+.menu-icon-site div.wp-menu-image,
+.icon16.icon-generic,
+.menu-icon-generic div.wp-menu-image {
+ background-image: url(../images/menu-vs.png?ver=20121105);
+}
+
+.icon16.icon-dashboard,
+#adminmenu .menu-icon-dashboard div.wp-menu-image {
+ background-position: -59px -33px;
+}
+
+#adminmenu .menu-icon-dashboard:hover div.wp-menu-image,
+#adminmenu .menu-icon-dashboard.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-dashboard.current div.wp-menu-image {
+ background-position: -59px -1px;
+}
+
+.icon16.icon-post,
+#adminmenu .menu-icon-post div.wp-menu-image {
+ background-position: -269px -33px;
+}
+
+#adminmenu .menu-icon-post:hover div.wp-menu-image,
+#adminmenu .menu-icon-post.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-post.current div.wp-menu-image {
+ background-position: -269px -1px;
+}
+
+.icon16.icon-media,
+#adminmenu .menu-icon-media div.wp-menu-image {
+ background-position: -119px -33px;
+}
+
+#adminmenu .menu-icon-media:hover div.wp-menu-image,
+#adminmenu .menu-icon-media.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-media.current div.wp-menu-image {
+ background-position: -119px -1px;
+}
+
+.icon16.icon-links,
+#adminmenu .menu-icon-links div.wp-menu-image {
+ background-position: -89px -33px;
+}
+
+#adminmenu .menu-icon-links:hover div.wp-menu-image,
+#adminmenu .menu-icon-links.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-links.current div.wp-menu-image {
+ background-position: -89px -1px;
+}
+
+.icon16.icon-page,
+#adminmenu .menu-icon-page div.wp-menu-image {
+ background-position: -149px -33px;
+}
+
+#adminmenu .menu-icon-page:hover div.wp-menu-image,
+#adminmenu .menu-icon-page.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-page.current div.wp-menu-image {
+ background-position: -149px -1px;
+}
+
+.icon16.icon-comments,
+#adminmenu .menu-icon-comments div.wp-menu-image {
+ background-position: -29px -33px;
+}
+
+#adminmenu .menu-icon-comments:hover div.wp-menu-image,
+#adminmenu .menu-icon-comments.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-comments.current div.wp-menu-image {
+ background-position: -29px -1px;
+}
+
+.icon16.icon-appearance,
+#adminmenu .menu-icon-appearance div.wp-menu-image {
+ background-position: 1px -33px;
+}
+
+#adminmenu .menu-icon-appearance:hover div.wp-menu-image,
+#adminmenu .menu-icon-appearance.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-appearance.current div.wp-menu-image {
+ background-position: 1px -1px;
+}
+
+.icon16.icon-plugins,
+#adminmenu .menu-icon-plugins div.wp-menu-image {
+ background-position: -179px -33px;
+}
+
+#adminmenu .menu-icon-plugins:hover div.wp-menu-image,
+#adminmenu .menu-icon-plugins.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-plugins.current div.wp-menu-image {
+ background-position: -179px -1px;
+}
+
+.icon16.icon-users,
+#adminmenu .menu-icon-users div.wp-menu-image {
+ background-position: -300px -33px;
+}
+
+#adminmenu .menu-icon-users:hover div.wp-menu-image,
+#adminmenu .menu-icon-users.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-users.current div.wp-menu-image {
+ background-position: -300px -1px;
+}
+
+.icon16.icon-tools,
+#adminmenu .menu-icon-tools div.wp-menu-image {
+ background-position: -209px -33px;
+}
+
+#adminmenu .menu-icon-tools:hover div.wp-menu-image,
+#adminmenu .menu-icon-tools.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-tools.current div.wp-menu-image {
+ background-position: -209px -1px;
+}
+
+.icon16.icon-settings,
+#adminmenu .menu-icon-settings div.wp-menu-image {
+ background-position: -239px -33px;
+}
+
+#adminmenu .menu-icon-settings:hover div.wp-menu-image,
+#adminmenu .menu-icon-settings.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-settings.current div.wp-menu-image {
+ background-position: -239px -1px;
+}
+
+.icon16.icon-site,
+#adminmenu .menu-icon-site div.wp-menu-image {
+ background-position: -359px -33px;
+}
+
+#adminmenu .menu-icon-site:hover div.wp-menu-image,
+#adminmenu .menu-icon-site.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-site.current div.wp-menu-image {
+ background-position: -359px -1px;
+}
+
+.icon16.icon-generic,
+#adminmenu .menu-icon-generic div.wp-menu-image {
+ background-position: -330px -33px;
+}
+
+#adminmenu .menu-icon-generic:hover div.wp-menu-image,
+#adminmenu .menu-icon-generic.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-generic.current div.wp-menu-image {
+ background-position: -330px -1px;
+}
+/* end menu and screen icons */
+
+/* Screen Icons */
+.icon32.icon-post,
+#icon-edit,
+#icon-post,
+.icon32.icon-dashboard,
+#icon-index,
+.icon32.icon-media,
+#icon-upload,
+.icon32.icon-links,
+#icon-link-manager,
+#icon-link,
+#icon-link-category,
+.icon32.icon-page,
+#icon-edit-pages,
+#icon-page,
+.icon32.icon-comments,
+#icon-edit-comments,
+.icon32.icon-appearance,
+#icon-themes,
+.icon32.icon-plugins,
+#icon-plugins,
+.icon32.icon-users,
+#icon-users,
+#icon-profile,
+#icon-user-edit,
+.icon32.icon-tools,
+#icon-tools,
+#icon-admin,
+.icon32.icon-settings,
+#icon-options-general,
+.icon32.icon-site,
+#icon-ms-admin,
+.icon32.icon-generic,
+#icon-generic {
+ background-image: url(../images/icons32-vs.png?ver=20121105);
+}
+
+.icon32.icon-post,
+#icon-edit,
+#icon-post {
+ background-position: -552px -5px;
+}
+
+.icon32.icon-dashboard,
+#icon-index {
+ background-position: -137px -5px;
+}
+
+.icon32.icon-media,
+#icon-upload {
+ background-position: -251px -5px;
+}
+
+.icon32.icon-links,
+#icon-link-manager,
+#icon-link,
+#icon-link-category {
+ background-position: -190px -5px;
+}
+
+.icon32.icon-page,
+#icon-edit-pages,
+#icon-page {
+ background-position: -312px -5px;
+}
+
+.icon32.icon-comments,
+#icon-edit-comments {
+ background-position: -72px -5px;
+}
+
+.icon32.icon-appearance,
+#icon-themes {
+ background-position: -11px -5px;
+}
+
+.icon32.icon-plugins,
+#icon-plugins {
+ background-position: -370px -5px;
+}
+
+.icon32.icon-users,
+#icon-users,
+#icon-profile,
+#icon-user-edit {
+ background-position: -600px -5px;
+}
+
+.icon32.icon-tools,
+#icon-tools,
+#icon-admin {
+ background-position: -432px -5px;
+}
+
+.icon32.icon-settings,
+#icon-options-general {
+ background-position: -492px -5px;
+}
+
+.icon32.icon-site,
+#icon-ms-admin {
+ background-position: -659px -5px;
+}
+
+.icon32.icon-generic,
+#icon-generic {
+ background-position: -708px -5px;
+}
+
+/* end screen icons */
+
+/* Post format icons */
+
+.post-format-icon {
+ background: url(../images/post-formats-vs.png) no-repeat;
+}
+
+/* Diff */
+table.diff .diff-deletedline {
+ background-color: #ffe9e9;
+}
+
+table.diff .diff-deletedline del {
+ background-color: #faa;
+}
+
+table.diff .diff-addedline {
+ background-color: #e9ffe9;
+}
+
+table.diff .diff-addedline ins {
+ background-color: #afa;
+}
+
+.revisions-meta {
+ border: 1px solid #d1e5ee;
+}
+
+.revisions-controls {
+ background: #fff;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0%,rgba(255,255,255,1)), color-stop(30px,rgba(255,255,255,1)), color-stop(100%,rgba(255,255,255,1)));
+ background: -webkit-linear-gradient(bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+ background: -moz-linear-gradient(bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+ background: -o-linear-gradient(bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+ background: linear-gradient(to top, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+}
+
+.revisions-tooltip,
+.revisions-tooltip-arrow span {
+ border-color: #d1e5ee;
+ background-color: #fff;
+}
+
+.revisions-tickmarks > div {
+ border-color: #d1e5ee;
+}
+
+/* jQuery UI Slider */
+.wp-slider.ui-slider {
+ border-color: #d1e5ee;
+}
+
+.wp-slider .ui-slider-handle {
+ color: #333;
+ border-color: none;
+}
+
+.wp-slider .ui-slider-handle {
+ border-color: #d0dfe9;
+ background: #eff8ff;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eff8ff), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #eff8ff, #fff);
+ background-image: -moz-linear-gradient(bottom, #eff8ff, #fff);
+ background-image: -o-linear-gradient(bottom, #eff8ff, #fff);
+ background-image: linear-gradient(to top, #eff8ff, #fff);
+}
+
+.wp-slider .ui-slider-handle:hover,
+.wp-slider .ui-slider-handle:focus {
+ border-color: #a0c3d5;
+}
+
+.wp-slider .ui-slider-handle.ui-state-hover,
+.wp-slider .ui-slider-handle.ui-state-focus {
+ border-color: #a0c3d5;
+ outline: none;
+}
+
+/* edit image */
+#sidemenu a {
+ background-color: #f9f9f9;
+ border-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+#sidemenu a.current {
+ background-color: #fff;
+ border-color: #dfdfdf #dfdfdf #fff;
+ color: #d54e21;
+}
+
+#replyerror {
+ border-color: #ddd;
+ background-color: #f9f9f9;
+}
+
+/* table vim shortcuts */
+.vim-current,
+.vim-current th,
+.vim-current td {
+ background-color: #e4f2fd !important;
+}
+
+/* Install Plugins */
+#plugin-information .fyi ul {
+ background-color: #eaf3fa;
+}
+
+#plugin-information .fyi h2.mainheader {
+ background-color: #cee1ef;
+}
+
+#plugin-information pre,
+#plugin-information code {
+ background-color: #ededff;
+}
+
+#plugin-information pre {
+ border: 1px solid #ccc;
+}
+
+/* inline editor */
+#bulk-titles {
+ border-color: #ddd;
+}
+
+.inline-editor div.title {
+ background-color: #eaf3fa;
+}
+
+.inline-editor ul.cat-checklist {
+ background-color: #fff;
+ border-color: #ddd;
+}
+
+.inline-editor .quick-edit-save {
+ background-color: #f1f1f1;
+}
+
+fieldset.inline-edit-col-right .inline-edit-col {
+ border-color: #dfdfdf;
+}
+
+.attention {
+ color: #d54e21;
+}
+
+.js .meta-box-sortables .postbox:hover .handlediv {
+ background: transparent url(../images/arrows-vs.png) no-repeat 6px 7px;
+}
+
+.tablenav .tablenav-pages {
+ color: #555;
+}
+
+.tablenav .tablenav-pages a {
+ border-color: #d1e5ee;
+ background: #eee;
+ -moz-box-shadow: inset 0 1px 0 #fff;
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+}
+
+.tablenav .tablenav-pages a:hover,
+.tablenav .tablenav-pages a:focus {
+ color: #d54e21;
+}
+
+.tablenav .tablenav-pages a.disabled,
+.tablenav .tablenav-pages a.disabled:hover,
+.tablenav .tablenav-pages a.disabled:focus {
+ color: #aaa;
+}
+
+.tablenav .tablenav-pages .current {
+ background: #dfdfdf;
+ border-color: #d3d3d3;
+}
+
+#availablethemes,
+#availablethemes td {
+ border-color: #acd;
+}
+
+#current-theme img {
+ border-color: #b0c8d7;
+}
+
+#TB_window #TB_title a.tb-theme-preview-link,
+#TB_window #TB_title a.tb-theme-preview-link:visited {
+ color: #999;
+}
+
+#TB_window #TB_title a.tb-theme-preview-link:hover,
+#TB_window #TB_title a.tb-theme-preview-link:focus {
+ color: #ccc;
+}
+
+.misc-pub-section {
+ border-top-color: #fff;
+ border-bottom-color: #d1e5ee;
+}
+
+#minor-publishing {
+ border-bottom-color: #cae6ff;
+}
+
+#post-body .misc-pub-section {
+ border-left-color: #eee;
+}
+
+.post-com-count span {
+ background-color: #bbb;
+}
+
+.form-table .color-palette td {
+ border-color: #fff;
+}
+
+.sortable-placeholder {
+ border-color: #bbb;
+ background-color: #f5f5f5;
+}
+
+#post-body ul.category-tabs li.tabs a,
+#post-body ul.add-menu-item-tabs li.tabs a,
+body.press-this ul.category-tabs li.tabs a {
+ color: #333;
+}
+
+.view-switch #view-switch-list,
+.view-switch #view-switch-excerpt {
+ background-color: transparent;
+ background-image: url('../images/list.png');
+ background-repeat: no-repeat;
+}
+
+.view-switch #view-switch-list {
+ background-position: 0 0;
+}
+
+.view-switch .current #view-switch-list {
+ background-position: -40px 0;
+}
+
+.view-switch #view-switch-excerpt {
+ background-position: -20px 0;
+}
+
+.view-switch .current #view-switch-excerpt {
+ background-position: -60px 0;
+}
+
+#header-logo {
+ background: transparent url(../images/wp-logo-vs.png?ver=20101102) no-repeat scroll center center;
+}
+
+.popular-tags,
+.feature-filter {
+ background-color: #fff;
+ border-color: #d1e5ee;
+}
+
+div.widgets-sortables,
+#widgets-left .inactive,
+#available-widgets .widget-holder {
+ background-color: #f7fcfe;
+ border-color: #d0dfe9;
+}
+
+#available-widgets .widget-description {
+ color: #555;
+}
+
+.sidebar-name {
+ color: #464646;
+ text-shadow: #fff 0 1px 0;
+ border-color: #d0dfe9;
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+}
+
+.js .sidebar-name:hover,
+.js #removing-widget {
+ color: #d54e21;
+}
+
+#removing-widget span {
+ color: black;
+}
+
+.js .sidebar-name-arrow {
+ background: transparent url(../images/arrows-vs.png) no-repeat 5px 9px;
+}
+
+.js .sidebar-name:hover .sidebar-name-arrow {
+ background: transparent url(../images/arrows-dark-vs.png) no-repeat 5px 9px;
+}
+
+.in-widget-title {
+ color: #606060;
+}
+
+.deleting .widget-title * {
+ color: #aaa;
+}
+
+.imgedit-menu div {
+ border-color: #d5d5d5;
+ background-color: #f1f1f1;
+}
+
+.imgedit-menu div:hover {
+ border-color: #c1c1c1;
+ background-color: #eaeaea;
+}
+
+.imgedit-menu div.disabled {
+ border-color: #ccc;
+ background-color: #ddd;
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+}
+
+#dashboard_recent_comments div.undo {
+ border-top-color: #dfdfdf;
+}
+
+.comment-ays,
+.comment-ays th {
+ border-color: #ddd;
+}
+
+.comment-ays th {
+ background-color: #f1f1f1;
+}
+
+/* added from nav-menu.css */
+#menu-management .menu-edit {
+ border-color: #d0dfe9;
+}
+
+#post-body {
+ background: #fff;
+ border-top-color: #fff;
+ border-bottom-color: #d0dfe9;
+}
+
+#nav-menu-header {
+ border-bottom-color: #d0dfe9;
+}
+
+#nav-menu-footer {
+ border-top-color: #fff;
+}
+
+#menu-management .nav-tabs-arrow a {
+ color: #c1c1c1;
+}
+
+#menu-management .nav-tabs-arrow a:hover {
+ color: #d54e21;
+}
+
+#menu-management .nav-tabs-arrow a:active {
+ color: #464646;
+}
+
+#menu-management .nav-tab-active {
+ border-color: #dfdfdf;
+}
+
+#menu-management .nav-tab {
+ background: #f7fcfe;
+ border-color: #d0dfe9;
+}
+
+.js .input-with-default-title {
+ color: #aaa;
+}
+
+#cancel-save {
+ color: #f00;
+}
+
+#cancel-save:hover {
+ background-color: #f00;
+ color: #fff;
+}
+
+.list-container {
+ border-color: #dfdfdf;
+}
+
+.menu-item-handle {
+ border-color: #d0dfe9;
+}
+
+.menu li.deleting .menu-item-handle {
+ background-color: #f66;
+ text-shadow: #ccc;
+}
+
+.item-type { /* Menu item controls */
+ color: #999;
+}
+
+.item-controls .menu-item-delete:hover {
+ color: #f00;
+}
+
+.nav-menus-php .item-edit {
+ background: transparent url(../images/arrows-vs.png) no-repeat 8px 10px;
+ border-bottom-color: #eff8ff;
+}
+
+.nav-menus-php .item-edit:hover {
+ background: transparent url(../images/arrows-dark-vs.png) no-repeat 8px 10px;
+}
+
+.menu-item-settings { /* Menu editing */
+ border-color: #d0dfe9;
+}
+
+.link-to-original {
+ color: #777;
+ border-color: #d0dfe9;
+}
+
+#cancel-save:hover {
+ color: #fff !important;
+}
+
+#update-menu-item {
+ color: #fff !important;
+}
+
+#update-menu-item:hover,
+#update-menu-item:active,
+#update-menu-item:focus {
+ color: #eaf2fa !important;
+ border-color: #13455b !important;
+}
+
+.submitbox .submitcancel {
+ color: #21759b;
+ border-bottom-color: #21759b;
+}
+
+.submitbox .submitcancel:hover {
+ background: #21759b;
+ color: #fff;
+}
+/* end added from nav-menu.css */
+
+.nav-tab {
+ border-color: #d1e5ee #d1e5ee #fff;
+}
+
+.nav-tab:hover,
+.nav-tab-active {
+ border-color: #acd #acd #fff;
+}
+
+h2.nav-tab-wrapper, h3.nav-tab-wrapper {
+ border-bottom-color: #acd;
+}
+
+#menu-management .nav-tab-active,
+.menu-item-handle,
+.menu-item-settings {
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+}
+
+#menu-management .nav-tab-active {
+ background: #f7fcfe;
+ border-bottom-color: #f7fcfe;
+}
+
+#upload-form label {
+ color: #777;
+}
+
+/* custom header & background pages */
+
+/* full screen */
+.fullscreen-overlay {
+ background: #fff;
+}
+
+.wp-fullscreen-focus #wp-fullscreen-title,
+.wp-fullscreen-focus #wp-fullscreen-container {
+ border-color: #bed1dd;
+}
+
+#fullscreen-topbar {
+ border-bottom-color: #d1e5ee;
+}
+
+/* Begin About Pages */
+
+.about-wrap h1 {
+ color: #333;
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.about-text {
+ color: #777;
+}
+
+.wp-badge {
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(22, 57, 81, 0.3);
+}
+
+.about-wrap h2 .nav-tab {
+ color: #21759b;
+}
+
+.about-wrap h2 .nav-tab:hover {
+ color: #d54e21;
+}
+
+.about-wrap h2 .nav-tab-active,
+.about-wrap h2 .nav-tab-active:hover {
+ color: #333;
+}
+
+.about-wrap h2 .nav-tab-active {
+ text-shadow: 1px 1px 1px #fff;
+ color: #464646;
+}
+
+.about-wrap h3 {
+ color: #333;
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.about-wrap .feature-section h4 {
+ color: #464646;
+}
+
+.about-wrap .feature-section img {
+ background: #fff;
+ border: 1px #ccc solid;
+ -webkit-box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.3 );
+ box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.3 );
+}
+
+.about-wrap h4.wp-people-group {
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.about-wrap .point-releases {
+ border-bottom: 1px solid #dfdfdf;
+}
+
+.about-wrap .point-releases h3 {
+ border-top: 1px solid #dfdfdf;
+}
+
+.about-wrap .point-releases h3:first-child {
+ border: 0;
+}
+
+.about-wrap li.wp-person img.gravatar {
+ -webkit-box-shadow: 0 0 4px rgba( 0, 0, 0, 0.4 );
+ box-shadow: 0 0 4px rgba( 0, 0, 0, 0.4 );
+}
+
+.about-wrap li.wp-person .title {
+ color: #464646;
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.freedoms-php .about-wrap ol li {
+ color: #999;
+}
+
+.freedoms-php .about-wrap ol p {
+ color: #464646;
+}
+
+/* End About Pages */
+
+
+/*------------------------------------------------------------------------------
+ 2.0 - Right to Left Styles
+------------------------------------------------------------------------------*/
+
+.rtl .bar {
+ border-right-color: transparent;
+ border-left-color: #99d;
+}
+
+.rtl #screen-meta-links a.show-settings {
+ background-position: left 3px;
+}
+
+.rtl #screen-meta-links a.show-settings.screen-meta-active {
+ background-position: left -33px;
+}
+
+/* Menu */
+.rtl #adminmenushadow,
+.rtl #adminmenuback {
+ background-image: url(../images/menu-shadow-rtl.png);
+ background-position: top left;
+}
+
+.rtl #adminmenu .wp-submenu .wp-submenu-head {
+ border-right-color: transparent;
+ border-left-color: #d1e5ee;
+}
+
+.rtl #adminmenu .wp-submenu,
+.rtl.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ -webkit-box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+ box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+}
+
+.rtl #adminmenu .wp-has-current-submenu .wp-submenu {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+/* Collapse Menu Button */
+.rtl #collapse-button div {
+ background-position: 0 -108px;
+}
+
+.rtl.folded #collapse-button div {
+ background-position: 0 -72px;
+}
+
+/* Auto-folding of the admin menu for RTL */
+@media only screen and (max-width: 900px) {
+ .rtl.auto-fold #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+ .rtl.auto-fold #adminmenu .wp-has-current-submenu .wp-submenu {
+ -webkit-box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+ box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+ }
+
+ .rtl.auto-fold #collapse-button div {
+ background-position: 0 -72px;
+ }
+}
+
+/* edit image */
+.js.rtl .meta-box-sortables .postbox:hover .handlediv {
+ background: transparent url(../images/arrows-vs.png) no-repeat 6px 7px;
+}
+
+.rtl #post-body .misc-pub-section {
+ border-right-color: transparent;
+ border-left-color: #d1e5ee;
+}
+
+.js.rtl .sidebar-name-arrow {
+ background: transparent url(../images/arrows-vs.png) no-repeat 5px 9px;
+}
+
+.js.rtl .sidebar-name:hover .sidebar-name-arrow {
+ background: transparent url(../images/arrows-dark-vs.png) no-repeat 5px 9px;
+}
+
+/**
+ * HiDPI Displays
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+
+ .curtime #timestamp {
+ background-image: url("../images/date-button-2x.gif?ver=20120916");
+ background-size: 16px auto;
+ }
+
+ .tagchecklist span a,
+ #bulk-titles div a,
+ .tagchecklist span a:hover,
+ #bulk-titles div a:hover {
+ background-image: url("../images/xit-2x.gif?ver=20120916");
+ background-size: 20px auto;
+ }
+
+ #screen-meta-links a.show-settings,
+ #screen-meta-links a.show-settings.screen-meta-active,
+ #adminmenu .wp-has-submenu:hover .wp-menu-toggle,
+ #adminmenu .wp-menu-open .wp-menu-toggle,
+ #collapse-button div,
+ .nav-menus-php .item-edit,
+ .js .meta-box-sortables .postbox:hover .handlediv,
+ .sidebar-name-arrow,
+ .rtl #adminmenu .wp-has-submenu:hover .wp-menu-toggle,
+ .rtl #adminmenu .wp-menu-open .wp-menu-toggle,
+ .js.rtl .meta-box-sortables .postbox:hover .handlediv,
+ .rtl .sidebar-name-arrow {
+ background-image: url("../images/arrows-vs-2x.png?ver=20120916");
+ background-size: 15px 123px;
+ }
+
+ #adminmenu li.wp-has-current-submenu.wp-menu-open .wp-menu-toggle,
+ #adminmenu li.wp-has-current-submenu:hover .wp-menu-toggle,
+ .nav-menus-php .item-edit:hover,
+ .sidebar-name:hover .sidebar-name-arrow,
+ .rtl #adminmenu li.wp-has-current-submenu.wp-menu-open .wp-menu-toggle,
+ .rtl #adminmenu li.wp-has-current-submenu:hover .wp-menu-toggle,
+ .rtl .sidebar-name:hover .sidebar-name-arrow {
+ background-image: url("../images/arrows-dark-vs-2x.png?ver=20120916");
+ background-size: 15px 123px;
+ }
+
+ .view-switch #view-switch-list,
+ .view-switch #view-switch-excerpt {
+ background-image: url("../images/list-2x.png?ver=20120916");
+ background-size: 80px 20px;
+ }
+
+ .icon32.icon-post,
+ #icon-edit,
+ #icon-post,
+ .icon32.icon-dashboard,
+ #icon-index,
+ .icon32.icon-media,
+ #icon-upload,
+ .icon32.icon-links,
+ #icon-link-manager,
+ #icon-link,
+ #icon-link-category,
+ .icon32.icon-page,
+ #icon-edit-pages,
+ #icon-page,
+ .icon32.icon-comments,
+ #icon-edit-comments,
+ .icon32.icon-appearance,
+ #icon-themes,
+ .icon32.icon-plugins,
+ #icon-plugins,
+ .icon32.icon-users,
+ #icon-users,
+ #icon-profile,
+ #icon-user-edit,
+ .icon32.icon-tools,
+ #icon-tools,
+ #icon-admin,
+ .icon32.icon-settings,
+ #icon-options-general,
+ .icon32.icon-site,
+ #icon-ms-admin,
+ .icon32.icon-generic,
+ #icon-generic {
+ background-image: url(../images/icons32-vs-2x.png?ver=20121105);
+ background-size: 756px 45px;
+ }
+
+ .icon16.icon-dashboard,
+ .menu-icon-dashboard div.wp-menu-image,
+ .icon16.icon-post,
+ .menu-icon-post div.wp-menu-image,
+ .icon16.icon-media,
+ .menu-icon-media div.wp-menu-image,
+ .icon16.icon-links,
+ .menu-icon-links div.wp-menu-image,
+ .icon16.icon-page,
+ .menu-icon-page div.wp-menu-image,
+ .icon16.icon-comments,
+ .menu-icon-comments div.wp-menu-image,
+ .icon16.icon-appearance,
+ .menu-icon-appearance div.wp-menu-image,
+ .icon16.icon-plugins,
+ .menu-icon-plugins div.wp-menu-image,
+ .icon16.icon-users,
+ .menu-icon-users div.wp-menu-image,
+ .icon16.icon-tools,
+ .menu-icon-tools div.wp-menu-image,
+ .icon16.icon-settings,
+ .menu-icon-settings div.wp-menu-image,
+ .icon16.icon-site,
+ .menu-icon-site div.wp-menu-image,
+ .icon16.icon-generic,
+ .menu-icon-generic div.wp-menu-image {
+ background-image: url('../images/menu-vs-2x.png?ver=20121105');
+ background-size: 390px 64px;
+ }
+
+ #header-logo {
+ background-image: url('../images/wp-logo-vs-2x.png?ver=20120916');
+ background-size: 16px auto;
+ }
+
+ /* 16px post formats */
+ .post-format-icon {
+ background-image: url(../images/post-formats32-vs.png);
+ background-size: 16px 304px;
+ }
+
+}
diff --git a/src/wp-admin/css/colors-fresh.css b/src/wp-admin/css/colors-fresh.css
new file mode 100644
index 0000000000..92d8332daf
--- /dev/null
+++ b/src/wp-admin/css/colors-fresh.css
@@ -0,0 +1,2148 @@
+/*------------------------------------------------------------------------------
+
+
+Howdy! This is the CSS file that controls the
+Gray (fresh) color style on the WordPress Dashboard.
+
+This file contains both LTR and RTL styles.
+
+
+TABLE OF CONTENTS:
+------------------
+ 1.0 - Left to Right Styles
+ 2.0 - Right to Left Styles
+
+
+------------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+ 1.0 - Left to Right Styles
+------------------------------------------------------------------------------*/
+
+.find-box-search,
+.find-box-buttons {
+ background-color: #f7f7f7;
+ border-top: 1px solid #ddd;
+}
+
+.find-box {
+ background-color: #444;
+}
+
+.find-box-head {
+ color: #eee;
+}
+
+.find-box-inside {
+ background-color: #fff;
+}
+
+a.page-numbers:hover {
+ border-color: #999;
+}
+
+body,
+#wpbody,
+.form-table .pre,
+.ui-autocomplete li a {
+ color: #333;
+}
+
+body > #upload-menu {
+ border-bottom-color: #fff;
+}
+
+#postcustomstuff table,
+#your-profile fieldset,
+#rightnow,
+div.dashboard-widget,
+#dashboard-widgets p.dashboard-widget-links {
+ border-color: #ccc;
+}
+
+#poststuff .inside label.spam,
+#poststuff .inside label.deleted {
+ color: red;
+}
+
+#poststuff .inside label.waiting {
+ color: orange;
+}
+
+#poststuff .inside label.approved {
+ color: green;
+}
+
+#postcustomstuff table {
+ border-color: #dfdfdf;
+ background-color: #f9f9f9;
+}
+
+#postcustomstuff thead th {
+ background-color: #f1f1f1;
+}
+
+table.widefat {
+ border-color: #dfdfdf;
+ background-color: #f9f9f9;
+}
+
+div.dashboard-widget-error {
+ background-color: #c43;
+}
+
+div.dashboard-widget-notice {
+ background-color: #cfe1ef;
+}
+
+div.dashboard-widget-submit {
+ border-top-color: #ccc;
+}
+
+ul.category-tabs li {
+ border-color: transparent;
+}
+
+div.tabs-panel,
+.wp-tab-panel,
+ul.add-menu-item-tabs li.tabs,
+.wp-tab-active {
+ border-color: #dfdfdf;
+ background-color: #fff;
+}
+
+ul.category-tabs li.tabs {
+ border-color: #dfdfdf #dfdfdf #fff;
+}
+
+ul.category-tabs li.tabs,
+ul.add-menu-item-tabs li.tabs,
+.wp-tab-active {
+ background-color: #fff;
+}
+
+kbd,
+code {
+ background: #eaeaea;
+}
+
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="file"],
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="tel"],
+input[type="url"],
+select {
+ border-color: #dfdfdf;
+}
+
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="file"]:focus,
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+select:focus {
+ border-color: #aaa;
+}
+
+input.disabled,
+textarea.disabled {
+ background-color: #ccc;
+}
+
+#plugin-information .action-button a,
+#plugin-information .action-button a:hover,
+#plugin-information .action-button a:visited {
+ color: #fff;
+}
+
+.revisions-meta,
+.widget .widget-top,
+.postbox h3,
+.stuffbox h3,
+.widefat thead tr th,
+.widefat tfoot tr th,
+h3.dashboard-widget-title,
+h3.dashboard-widget-title span,
+h3.dashboard-widget-title small,
+.sidebar-name,
+#nav-menu-header,
+#nav-menu-footer,
+.menu-item-handle {
+ background: #f1f1f1;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#ececec), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: -moz-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: -o-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: linear-gradient(to top, #ececec, #f9f9f9);
+}
+
+
+
+.widget .widget-top,
+.postbox h3,
+.stuffbox h3 {
+ border-bottom-color: #dfdfdf;
+ text-shadow: #fff 0 1px 0;
+ -webkit-box-shadow: 0 1px 0 #fff;
+ box-shadow: 0 1px 0 #fff;
+}
+
+.form-table th,
+.form-wrap label {
+ color: #222;
+ text-shadow: #fff 0 1px 0;
+}
+
+.description,
+.form-wrap p {
+ color: #666;
+}
+
+strong .post-com-count span {
+ background-color: #21759b;
+}
+
+.sorthelper {
+ background-color: #ccf3fa;
+}
+
+.ac_match,
+.subsubsub a.current {
+ color: #000;
+}
+
+.wrap h2 {
+ color: #464646;
+}
+
+.wrap .add-new-h2,
+.wrap .add-new-h2:active {
+ background: #f1f1f1;
+}
+
+.subtitle {
+ color: #777;
+}
+
+.ac_over {
+ background-color: #f0f0b8;
+}
+
+.ac_results {
+ background-color: #fff;
+ border-color: #808080;
+}
+
+.ac_results li {
+ color: #101010;
+}
+
+.alternate,
+.alt {
+ background-color: #fcfcfc;
+}
+
+.available-theme a.screenshot {
+ background-color: #f1f1f1;
+ border-color: #ddd;
+}
+
+#current-theme {
+ border-bottom-color: #dfdfdf;
+}
+
+.bar {
+ background-color: #e8e8e8;
+ border-right-color: #99d;
+}
+
+#media-upload,
+#media-upload .media-item .slidetoggle {
+ background: #fff;
+}
+
+#media-upload .slidetoggle {
+ border-top-color: #dfdfdf;
+}
+
+div.error,
+.login #login_error {
+ background-color: #ffebe8;
+ border-color: #c00;
+}
+
+div.error a {
+ color: #c00;
+}
+
+.form-invalid {
+ background-color: #ffebe8 !important;
+}
+
+.form-invalid input,
+.form-invalid select {
+ border-color: #c00 !important;
+}
+
+.submit,
+#commentsdiv #add-new-comment {
+ border-color: #dfdfdf;
+}
+
+.highlight {
+ background-color: #e4f2fd;
+ color: #000;
+}
+
+.howto,
+.nonessential,
+#edit-slug-box,
+.form-input-tip,
+.subsubsub {
+ color: #666;
+}
+
+.media-upload-form label.form-help,
+td.help {
+ color: #9a9a9a;
+}
+
+.ui-autocomplete {
+ border-color: #aaa;
+ background-color: #efefef;
+}
+
+.ui-autocomplete li a.ui-state-focus {
+ background-color: #ddd;
+}
+
+.post-com-count {
+ color: #fff;
+}
+
+.post-com-count span {
+ background-color: #bbb;
+ color: #fff;
+}
+
+.post-com-count:hover span {
+ background-color: #d54e21;
+}
+
+.quicktags, .search {
+ background-color: #ccc;
+ color: #000;
+}
+
+.side-info h5 {
+ border-bottom-color: #dadada;
+}
+
+.side-info ul {
+ color: #666;
+}
+
+a:hover,
+a:active {
+ color: #d54e21;
+}
+
+a:focus {
+ color: #124964;
+}
+
+#adminmenu a:hover,
+#adminmenu li.menu-top > a:focus,
+#adminmenu .wp-submenu a:hover,
+#the-comment-list .comment a:hover,
+#rightnow a:hover,
+#media-upload a.del-link:hover,
+div.dashboard-widget-submit input:hover,
+.subsubsub a:hover,
+.subsubsub a.current:hover,
+.ui-tabs-nav a:hover,
+.plugins .inactive a:hover,
+#all-plugins-table .plugins .inactive a:hover,
+#search-plugins-table .plugins .inactive a:hover {
+ color: #d54e21;
+}
+
+#the-comment-list .comment-item,
+#dashboard-widgets #dashboard_quick_press form p.submit {
+ border-color: #dfdfdf;
+}
+
+#side-sortables .category-tabs .tabs a,
+#side-sortables .add-menu-item-tabs .tabs a,
+.wp-tab-bar .wp-tab-active a {
+ color: #333;
+}
+
+#rightnow .rbutton {
+ background-color: #ebebeb;
+ color: #264761;
+}
+
+#dashboard_right_now .table_content,
+#dashboard_right_now .table_discussion {
+ border-top-color: #ececec;
+}
+
+.submitbox .submit {
+ background-color: #464646;
+ color: #ccc;
+}
+
+.plugins a.delete:hover,
+#all-plugins-table .plugins a.delete:hover,
+#search-plugins-table .plugins a.delete:hover,
+.submitbox .submitdelete {
+ color: #f00;
+ border-bottom-color: #f00;
+}
+
+.submitbox .submitdelete:hover,
+#media-items a.delete:hover,
+#media-items a.delete-permanently:hover,
+#nav-menu-footer .menu-delete:hover {
+ color: #fff;
+ background-color: #f00;
+ border-bottom-color: #f00;
+}
+
+#normal-sortables .submitbox .submitdelete:hover {
+ color: #000;
+ background-color: #f00;
+ border-bottom-color: #f00;
+}
+
+.tablenav .dots {
+ border-color: transparent;
+}
+
+.tablenav .next,
+.tablenav .prev {
+ border-color: transparent;
+ color: #21759b;
+}
+
+.tablenav .next:hover,
+.tablenav .prev:hover {
+ border-color: transparent;
+ color: #d54e21;
+}
+
+div.updated,
+.login .message {
+ background-color: #ffffe0;
+ border-color: #e6db55;
+}
+
+.update-message {
+ color: #000;
+}
+
+a.page-numbers {
+ border-bottom-color: #b8d3e2;
+}
+
+.commentlist li {
+ border-bottom-color: #ccc;
+}
+
+.widefat td,
+.widefat th {
+ border-top-color: #fff;
+ border-bottom-color: #dfdfdf;
+}
+
+.widefat th {
+ text-shadow: rgba(255,255,255,0.8) 0 1px 0;
+}
+
+.widefat td {
+ color: #555;
+}
+.widefat p,
+.widefat ol,
+.widefat ul {
+ color: #333;
+}
+
+.widefat thead tr th,
+.widefat tfoot tr th,
+h3.dashboard-widget-title,
+h3.dashboard-widget-title span,
+h3.dashboard-widget-title small {
+ color: #333;
+}
+
+th.sortable a:hover,
+th.sortable a:active,
+th.sortable a:focus {
+ color: #333;
+}
+
+th.sortable a:focus {
+ background: #e1e1e1;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#dcdcdc), to(#e9e9e9));
+ background-image: -webkit-linear-gradient(bottom, #dcdcdc, #e9e9e9);
+ background-image: -moz-linear-gradient(bottom, #dcdcdc, #e9e9e9);
+ background-image: -o-linear-gradient(bottom, #dcdcdc, #e9e9e9);
+ background-image: linear-gradient(to top, #dcdcdc, #e9e9e9);
+}
+
+h3.dashboard-widget-title small a {
+ color: #d7d7d7;
+}
+
+h3.dashboard-widget-title small a:hover {
+ color: #fff;
+}
+
+a,
+#adminmenu a,
+#the-comment-list p.comment-author strong a,
+#media-upload a.del-link,
+#media-items a.delete,
+#media-items a.delete-permanently,
+.plugins a.delete,
+.ui-tabs-nav a {
+ color: #21759b;
+}
+
+#adminmenu .awaiting-mod,
+#adminmenu .update-plugins,
+#sidemenu a .update-plugins,
+#rightnow .reallynow {
+ background-color: #464646;
+ color: #fff;
+ -webkit-box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+ box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+}
+#plugin-information .action-button {
+ background-color: #d54e21;
+ color: #fff;
+}
+
+#adminmenu li.current a .awaiting-mod,
+#adminmenu li a.wp-has-current-submenu .update-plugins{
+ background-color: #464646;
+ color: #fff;
+ -webkit-box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+ box-shadow: rgba(255,255,255,0.5) 0 1px 0;
+}
+
+div#media-upload-header,
+div#plugin-information-header {
+ background-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+#currenttheme img {
+ border-color: #666;
+}
+
+#dashboard_secondary div.dashboard-widget-content ul li a {
+ background-color: #f9f9f9;
+}
+
+input.readonly, textarea.readonly {
+ background-color: #ddd;
+}
+
+#editable-post-name {
+ background-color: #fffbcc;
+}
+
+#edit-slug-box strong,
+.tablenav .displaying-num,
+#submitted-on,
+.submitted-on {
+ color: #777;
+}
+
+.login #nav a,
+.login #backtoblog a {
+ color: #21759b !important;
+}
+
+.login #nav a:hover,
+.login #backtoblog a:hover {
+ color: #d54e21 !important;
+}
+
+#wpfooter {
+ color: #777;
+ border-color: #dfdfdf;
+}
+
+.imgedit-group,
+#media-items .media-item,
+.media-item .describe {
+ border-color: #dfdfdf;
+}
+
+.checkbox,
+.side-info,
+.plugins tr,
+#your-profile #rich_editing {
+ background-color: #fcfcfc;
+}
+
+.plugins .inactive,
+.plugins .inactive th,
+.plugins .inactive td,
+tr.inactive + tr.plugin-update-tr .plugin-update {
+ background-color: #f4f4f4;
+}
+
+.plugin-update-tr .update-message {
+ background-color: #fffbe4;
+ border-color: #dfdfdf;
+}
+
+.plugins .active,
+.plugins .active th,
+.plugins .active td {
+ color: #000;
+}
+
+.plugins .inactive a {
+ color: #579;
+}
+
+#the-comment-list tr.undo,
+#the-comment-list div.undo {
+ background-color: #f4f4f4;
+}
+
+#the-comment-list .unapproved {
+ background-color: #ffffe0;
+}
+
+#the-comment-list .approve a {
+ color: #006505;
+}
+
+#the-comment-list .unapprove a {
+ color: #d98500;
+}
+
+table.widefat span.delete a,
+table.widefat span.trash a,
+table.widefat span.spam a,
+#dashboard_recent_comments .delete a,
+#dashboard_recent_comments .trash a,
+#dashboard_recent_comments .spam a {
+ color: #bc0b0b;
+}
+
+.welcome-panel {
+ background: #f5f5f5;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#f5f5f5), to(#fafafa));
+ background-image: -webkit-linear-gradient(bottom, #f5f5f5, #fafafa);
+ background-image: -moz-linear-gradient(bottom, #f5f5f5, #fafafa);
+ background-image: -o-linear-gradient(bottom, #f5f5f5, #fafafa);
+ background-image: linear-gradient(to top, #f5f5f5, #fafafa);
+ border-color: #dfdfdf;
+}
+.welcome-panel p {
+ color: #777;
+}
+.welcome-panel-column p {
+ color: #464646;
+}
+.welcome-panel h3 {
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.widget,
+#widget-list .widget-top,
+.postbox,
+#titlediv,
+#poststuff .postarea,
+.stuffbox {
+ border-color: #dfdfdf;
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.widget,
+#widget-list .widget-top,
+.postbox,
+.menu-item-settings {
+ background: #f5f5f5;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#f5f5f5), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(bottom, #f5f5f5, #f9f9f9);
+ background-image: -moz-linear-gradient(bottom, #f5f5f5, #f9f9f9);
+ background-image: -o-linear-gradient(bottom, #f5f5f5, #f9f9f9);
+ background-image: linear-gradient(to top, #f5f5f5, #f9f9f9);
+}
+
+.postbox h3 {
+ color: #464646;
+}
+
+.widget .widget-top {
+ color: #222;
+}
+
+.js .sidebar-name:hover h3,
+.js .postbox h3:hover {
+ color: #000;
+}
+
+.curtime #timestamp {
+ background-image: url(../images/date-button.gif);
+}
+
+#rightnow .youhave {
+ background-color: #f0f6fb;
+}
+
+#rightnow a {
+ color: #448abd;
+}
+
+.tagchecklist span a,
+#bulk-titles div a {
+ background: url(../images/xit.gif) no-repeat;
+}
+
+.tagchecklist span a:hover,
+#bulk-titles div a:hover {
+ background: url(../images/xit.gif) no-repeat -10px 0;
+}
+
+#update-nag, .update-nag {
+ background-color: #fffbcc;
+ border-color: #e6db55;
+ color: #555;
+}
+
+#screen-meta {
+ background-color: #f1f1f1;
+ border-color: #ccc;
+ -webkit-box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.05 );
+ box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.05 );
+}
+
+#contextual-help-back {
+ background: #fff;
+}
+
+.contextual-help-tabs a:hover {
+ color: #333;
+}
+
+#contextual-help-back,
+.contextual-help-tabs .active {
+ border-color: #ccc;
+}
+
+.contextual-help-tabs .active,
+.contextual-help-tabs .active a,
+.contextual-help-tabs .active a:hover {
+ background: #fff;
+ color: #333;
+}
+
+/* screen options and help tabs */
+#screen-options-link-wrap,
+#contextual-help-link-wrap {
+ border-right: 1px solid #ccc;
+ border-left: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ background: #e3e3e3;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#f1f1f1));
+ background-image: -webkit-linear-gradient(bottom, #dfdfdf, #f1f1f1);
+ background-image: -moz-linear-gradient(bottom, #dfdfdf, #f1f1f1);
+ background-image: -o-linear-gradient(bottom, #dfdfdf, #f1f1f1);
+ background-image: linear-gradient(to top, #dfdfdf, #f1f1f1);
+}
+
+#screen-meta-links a {
+ color: #777;
+ background: transparent url(../images/arrows.png) no-repeat right 4px;
+}
+
+#screen-meta-links a:hover,
+#screen-meta-links a:active {
+ color: #333;
+ background-color: transparent;
+}
+
+#screen-meta-links a.screen-meta-active {
+ background-position: right -31px;
+}
+
+/* end screen options and help tabs */
+
+.login #backtoblog a {
+ color: #464646;
+}
+
+#wphead {
+ border-bottom: #dfdfdf 1px solid;
+}
+
+#wphead h1 a {
+ color: #464646;
+}
+
+#wpfooter a:link,
+#wpfooter a:visited {
+ text-decoration: none;
+}
+
+#wpfooter a:hover {
+ text-decoration: underline;
+}
+
+.file-error,
+abbr.required,
+.widget-control-remove:hover,
+table.widefat .delete a:hover,
+table.widefat .trash a:hover,
+table.widefat .spam a:hover,
+#dashboard_recent_comments .delete a:hover,
+#dashboard_recent_comments .trash a:hover
+#dashboard_recent_comments .spam a:hover {
+ color: #f00;
+}
+
+#pass-strength-result {
+ background-color: #eee;
+ border-color: #ddd !important;
+}
+
+#pass-strength-result.bad {
+ background-color: #ffb78c;
+ border-color: #ff853c !important;
+}
+
+#pass-strength-result.good {
+ background-color: #ffec8b;
+ border-color: #fc0 !important;
+}
+
+#pass-strength-result.short {
+ background-color: #ffa0a0;
+ border-color: #f04040 !important;
+}
+
+#pass-strength-result.strong {
+ background-color: #c3ff88;
+ border-color: #8dff1c !important;
+}
+
+#post-status-info {
+ border-color: #dfdfdf #ccc #ccc;
+ background-color: #eaeaea;
+}
+
+.editwidget .widget-inside {
+ border-color: #dfdfdf;
+}
+
+#titlediv #title {
+ background-color: #fff;
+}
+
+#tTips p#tTips_inside {
+ background-color: #ddd;
+ color: #333;
+}
+
+#poststuff .inside .the-tagcloud {
+ border-color: #ddd;
+}
+
+/* menu */
+#adminmenuback,
+#adminmenuwrap {
+ background-color: #ececec;
+ border-color: #ccc;
+}
+
+#adminmenushadow,
+#adminmenuback {
+ background-image: url(../images/menu-shadow.png);
+ background-position: top right;
+ background-repeat: repeat-y;
+}
+
+#adminmenu li.wp-menu-separator {
+ background: #dfdfdf;
+ border-color: #cfcfcf;
+}
+
+#adminmenu div.separator {
+ border-color: #e1e1e1;
+}
+
+#adminmenu a.menu-top,
+#adminmenu .wp-submenu .wp-submenu-head {
+ border-top-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+#adminmenu li.wp-menu-open {
+ border-color: #dfdfdf;
+}
+
+#adminmenu li.menu-top:hover,
+#adminmenu li.opensub > a.menu-top,
+#adminmenu li > a.menu-top:focus {
+ background-color: #e4e4e4;
+ color: #d54e21;
+ text-shadow: 0 1px 0 rgba( 255, 255, 255, 0.4 );
+}
+
+/* So it doesn't get applied to the number spans (comments, updates, etc) */
+#adminmenu li.menu-top:hover > a span,
+#adminmenu li.menu-top > a:focus span {
+ text-shadow: none;
+}
+
+#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
+#adminmenu li.current a.menu-top,
+.folded #adminmenu li.wp-has-current-submenu,
+.folded #adminmenu li.current.menu-top,
+#adminmenu .wp-menu-arrow,
+#adminmenu .wp-has-current-submenu .wp-submenu .wp-submenu-head {
+ background: #777;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#6d6d6d), to(#808080));
+ background-image: -webkit-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: -moz-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: -o-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: linear-gradient(to top, #6d6d6d, #808080);
+}
+
+#adminmenu .wp-menu-arrow div {
+ background: #777;
+ background-image: -webkit-gradient(linear, right bottom, left top, from(#6d6d6d), to(#808080));
+ background-image: -webkit-linear-gradient(bottom right, #6d6d6d, #808080);
+ background-image: -moz-linear-gradient(bottom right, #6d6d6d, #808080);
+ background-image: -o-linear-gradient(bottom right, #6d6d6d, #808080);
+ background-image: linear-gradient(to top left, #6d6d6d, #808080);
+}
+
+#adminmenu li.wp-not-current-submenu .wp-menu-arrow {
+ border-top-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+ background: #e4e4e4;
+}
+
+#adminmenu li.wp-not-current-submenu .wp-menu-arrow div {
+ background: #e4e4e4;
+ border-color: #ccc;
+}
+
+.folded #adminmenu li.menu-top li:hover a {
+ background-image: none;
+}
+
+#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
+#adminmenu li.current a.menu-top,
+#adminmenu .wp-has-current-submenu .wp-submenu .wp-submenu-head {
+ text-shadow: 0 -1px 0 #333;
+ color: #fff;
+ border-top-color: #808080;
+ border-bottom-color: #6d6d6d;
+}
+
+.folded #adminmenu li.wp-has-current-submenu,
+.folded #adminmenu li.current.menu-top {
+ border-top-color: #808080;
+ border-bottom-color: #6d6d6d;
+}
+
+#adminmenu .wp-submenu a:hover,
+#adminmenu .wp-submenu a:focus {
+ background-color: #eaf2fa;
+ color: #333;
+}
+
+#adminmenu .wp-submenu li.current,
+#adminmenu .wp-submenu li.current a,
+#adminmenu .wp-submenu li.current a:hover {
+ color: #333;
+}
+
+#adminmenu .wp-submenu,
+.folded #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ background-color: #fff;
+ border-color: #dfdfdf;
+ -webkit-box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+ box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+}
+
+#adminmenu .wp-submenu .wp-submenu-head {
+ background-color: #e4e4e4;
+ color: #333;
+}
+
+/* collapse menu button */
+#collapse-menu {
+ color: #aaa;
+ border-top-color: #f9f9f9;
+}
+
+#collapse-menu:hover {
+ color: #999;
+}
+
+#collapse-button {
+ border-color: #ccc;
+ background: #f4f4f4;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #dfdfdf, #fff);
+ background-image: -moz-linear-gradient(bottom, #dfdfdf, #fff);
+ background-image: -o-linear-gradient(bottom, #dfdfdf, #fff);
+ background-image: linear-gradient(to top, #dfdfdf, #fff);
+}
+
+#collapse-menu:hover #collapse-button {
+ border-color: #aaa;
+}
+
+#collapse-button div {
+ background: transparent url(../images/arrows.png) no-repeat 0 -72px;
+}
+
+.folded #collapse-button div {
+ background-position: 0 -108px;
+}
+
+/* Auto-folding of the admin menu */
+@media only screen and (max-width: 900px) {
+ .auto-fold #adminmenu li.wp-has-current-submenu,
+ .auto-fold #adminmenu li.current.menu-top {
+ background-color: #777;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#6d6d6d), to(#808080));
+ background-image: -webkit-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: -moz-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: -o-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: linear-gradient(bottom, #6d6d6d, #808080);
+ }
+
+ .auto-fold #adminmenu li.wp-has-current-submenu,
+ .auto-fold #adminmenu li.current.menu-top {
+ border-top-color: #808080;
+ border-bottom-color: #6d6d6d;
+ }
+
+ .auto-fold #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu .wp-submenu {
+ background-color: #fff;
+ border-color: #dfdfdf;
+ -webkit-box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+ box-shadow: 2px 3px 6px rgba(0, 0, 0, 0.4);
+ }
+
+ .auto-fold #collapse-button div {
+ background-position: 0 -108px;
+ }
+}
+
+/* menu and screen icons */
+.icon16,
+.icon32,
+div.wp-menu-image {
+ background-color: transparent;
+ background-repeat: no-repeat;
+}
+
+.icon16.icon-dashboard,
+.menu-icon-dashboard div.wp-menu-image,
+.icon16.icon-post,
+.menu-icon-post div.wp-menu-image,
+.icon16.icon-media,
+.menu-icon-media div.wp-menu-image,
+.icon16.icon-links,
+.menu-icon-links div.wp-menu-image,
+.icon16.icon-page,
+.menu-icon-page div.wp-menu-image,
+.icon16.icon-comments,
+.menu-icon-comments div.wp-menu-image,
+.icon16.icon-appearance,
+.menu-icon-appearance div.wp-menu-image,
+.icon16.icon-plugins,
+.menu-icon-plugins div.wp-menu-image,
+.icon16.icon-users,
+.menu-icon-users div.wp-menu-image,
+.icon16.icon-tools,
+.menu-icon-tools div.wp-menu-image,
+.icon16.icon-settings,
+.menu-icon-settings div.wp-menu-image,
+.icon16.icon-site,
+.menu-icon-site div.wp-menu-image,
+.icon16.icon-generic,
+.menu-icon-generic div.wp-menu-image {
+ background-image: url(../images/menu.png?ver=20121105);
+}
+
+.icon16.icon-dashboard,
+#adminmenu .menu-icon-dashboard div.wp-menu-image {
+ background-position: -59px -33px;
+}
+
+#adminmenu .menu-icon-dashboard:hover div.wp-menu-image,
+#adminmenu .menu-icon-dashboard.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-dashboard.current div.wp-menu-image {
+ background-position: -59px -1px;
+}
+
+.icon16.icon-post,
+#adminmenu .menu-icon-post div.wp-menu-image {
+ background-position: -269px -33px;
+}
+
+#adminmenu .menu-icon-post:hover div.wp-menu-image,
+#adminmenu .menu-icon-post.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-post.current div.wp-menu-image {
+ background-position: -269px -1px;
+}
+
+.icon16.icon-media,
+#adminmenu .menu-icon-media div.wp-menu-image {
+ background-position: -119px -33px;
+}
+
+#adminmenu .menu-icon-media:hover div.wp-menu-image,
+#adminmenu .menu-icon-media.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-media.current div.wp-menu-image {
+ background-position: -119px -1px;
+}
+
+.icon16.icon-links,
+#adminmenu .menu-icon-links div.wp-menu-image {
+ background-position: -89px -33px;
+}
+
+#adminmenu .menu-icon-links:hover div.wp-menu-image,
+#adminmenu .menu-icon-links.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-links.current div.wp-menu-image {
+ background-position: -89px -1px;
+}
+
+.icon16.icon-page,
+#adminmenu .menu-icon-page div.wp-menu-image {
+ background-position: -149px -33px;
+}
+
+#adminmenu .menu-icon-page:hover div.wp-menu-image,
+#adminmenu .menu-icon-page.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-page.current div.wp-menu-image {
+ background-position: -149px -1px;
+}
+
+.icon16.icon-comments,
+#adminmenu .menu-icon-comments div.wp-menu-image {
+ background-position: -29px -33px;
+}
+
+#adminmenu .menu-icon-comments:hover div.wp-menu-image,
+#adminmenu .menu-icon-comments.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-comments.current div.wp-menu-image {
+ background-position: -29px -1px;
+}
+
+.icon16.icon-appearance,
+#adminmenu .menu-icon-appearance div.wp-menu-image {
+ background-position: 1px -33px;
+}
+
+#adminmenu .menu-icon-appearance:hover div.wp-menu-image,
+#adminmenu .menu-icon-appearance.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-appearance.current div.wp-menu-image {
+ background-position: 1px -1px;
+}
+
+.icon16.icon-plugins,
+#adminmenu .menu-icon-plugins div.wp-menu-image {
+ background-position: -179px -33px;
+}
+
+#adminmenu .menu-icon-plugins:hover div.wp-menu-image,
+#adminmenu .menu-icon-plugins.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-plugins.current div.wp-menu-image {
+ background-position: -179px -1px;
+}
+
+.icon16.icon-users,
+#adminmenu .menu-icon-users div.wp-menu-image {
+ background-position: -300px -33px;
+}
+
+#adminmenu .menu-icon-users:hover div.wp-menu-image,
+#adminmenu .menu-icon-users.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-users.current div.wp-menu-image {
+ background-position: -300px -1px;
+}
+
+.icon16.icon-tools,
+#adminmenu .menu-icon-tools div.wp-menu-image {
+ background-position: -209px -33px;
+}
+
+#adminmenu .menu-icon-tools:hover div.wp-menu-image,
+#adminmenu .menu-icon-tools.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-tools.current div.wp-menu-image {
+ background-position: -209px -1px;
+}
+
+.icon16.icon-settings,
+#adminmenu .menu-icon-settings div.wp-menu-image {
+ background-position: -239px -33px;
+}
+
+#adminmenu .menu-icon-settings:hover div.wp-menu-image,
+#adminmenu .menu-icon-settings.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-settings.current div.wp-menu-image {
+ background-position: -239px -1px;
+}
+
+.icon16.icon-site,
+#adminmenu .menu-icon-site div.wp-menu-image {
+ background-position: -359px -33px;
+}
+
+#adminmenu .menu-icon-site:hover div.wp-menu-image,
+#adminmenu .menu-icon-site.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-site.current div.wp-menu-image {
+ background-position: -359px -1px;
+}
+
+.icon16.icon-generic,
+#adminmenu .menu-icon-generic div.wp-menu-image {
+ background-position: -330px -33px;
+}
+
+#adminmenu .menu-icon-generic:hover div.wp-menu-image,
+#adminmenu .menu-icon-generic.wp-has-current-submenu div.wp-menu-image,
+#adminmenu .menu-icon-generic.current div.wp-menu-image {
+ background-position: -330px -1px;
+}
+
+/* end menu and screen icons */
+
+/* Screen Icons */
+.icon32.icon-post,
+#icon-edit,
+#icon-post,
+.icon32.icon-dashboard,
+#icon-index,
+.icon32.icon-media,
+#icon-upload,
+.icon32.icon-links,
+#icon-link-manager,
+#icon-link,
+#icon-link-category,
+.icon32.icon-page,
+#icon-edit-pages,
+#icon-page,
+.icon32.icon-comments,
+#icon-edit-comments,
+.icon32.icon-appearance,
+#icon-themes,
+.icon32.icon-plugins,
+#icon-plugins,
+.icon32.icon-users,
+#icon-users,
+#icon-profile,
+#icon-user-edit,
+.icon32.icon-tools,
+#icon-tools,
+#icon-admin,
+.icon32.icon-settings,
+#icon-options-general,
+.icon32.icon-site,
+#icon-ms-admin,
+.icon32.icon-generic,
+#icon-generic {
+ background-image: url(../images/icons32.png?ver=20121105);
+}
+
+.icon32.icon-post,
+#icon-edit,
+#icon-post {
+ background-position: -552px -5px;
+}
+
+.icon32.icon-dashboard,
+#icon-index {
+ background-position: -137px -5px;
+}
+
+.icon32.icon-media,
+#icon-upload {
+ background-position: -251px -5px;
+}
+
+.icon32.icon-links,
+#icon-link-manager,
+#icon-link,
+#icon-link-category {
+ background-position: -190px -5px;
+}
+
+.icon32.icon-page,
+#icon-edit-pages,
+#icon-page {
+ background-position: -312px -5px;
+}
+
+.icon32.icon-comments,
+#icon-edit-comments {
+ background-position: -72px -5px;
+}
+
+.icon32.icon-appearance,
+#icon-themes {
+ background-position: -11px -5px;
+}
+
+.icon32.icon-plugins,
+#icon-plugins {
+ background-position: -370px -5px;
+}
+
+.icon32.icon-users,
+#icon-users,
+#icon-profile,
+#icon-user-edit {
+ background-position: -600px -5px;
+}
+
+.icon32.icon-tools,
+#icon-tools,
+#icon-admin {
+ background-position: -432px -5px;
+}
+
+.icon32.icon-settings,
+#icon-options-general {
+ background-position: -492px -5px;
+}
+
+.icon32.icon-site,
+#icon-ms-admin {
+ background-position: -659px -5px;
+}
+
+.icon32.icon-generic,
+#icon-generic {
+ background-position: -708px -5px;
+}
+
+/* end screen icons */
+
+/* Post format icons */
+
+.post-format-icon {
+ background: url(../images/post-formats.png) no-repeat;
+}
+
+/* Diff */
+table.diff .diff-deletedline {
+ background-color: #ffe9e9;
+}
+
+table.diff .diff-deletedline del {
+ background-color: #faa;
+}
+
+table.diff .diff-addedline {
+ background-color: #e9ffe9;
+}
+
+table.diff .diff-addedline ins {
+ background-color: #afa;
+}
+
+.revisions-meta {
+ border: 1px solid #dfdfdf;
+}
+
+.revisions-controls {
+ background: #fff;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0%,rgba(255,255,255,1)), color-stop(30px,rgba(255,255,255,1)), color-stop(100%,rgba(255,255,255,1)));
+ background: -webkit-linear-gradient(bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+ background: -moz-linear-gradient(bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+ background: -o-linear-gradient(bottom, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+ background: linear-gradient(to top, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 30px, rgba(255,255,255,1) 100%);
+}
+
+.revisions-tooltip,
+.revisions-tooltip-arrow span {
+ border-color: #d7d7d7;
+ background-color: #fff;
+}
+
+.revisions-tickmarks > div {
+ border-color: #aaa;
+}
+
+/* jQuery UI Slider */
+.wp-slider.ui-slider {
+ border-color: #d7d7d7;
+}
+
+.wp-slider .ui-slider-handle {
+ border-color: #ccc;
+ border-radius: 50%;
+ background: #f4f4f4;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#dfdfdf), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #dfdfdf, #fff);
+ background-image: -moz-linear-gradient(bottom, #dfdfdf, #fff);
+ background-image: -o-linear-gradient(bottom, #dfdfdf, #fff);
+ background-image: linear-gradient(to top, #dfdfdf, #fff);
+ color: #333;
+}
+
+.wp-slider .ui-slider-handle:hover,
+.wp-slider .ui-slider-handle:focus {
+ border-color: #aaa;
+}
+
+.wp-slider .ui-slider-handle.ui-state-hover,
+.wp-slider .ui-slider-handle.ui-state-focus {
+ border-color: #aaa;
+ outline: none;
+}
+
+/* edit image */
+#sidemenu a {
+ background-color: #f9f9f9;
+ border-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+#sidemenu a.current {
+ background-color: #fff;
+ border-color: #dfdfdf #dfdfdf #fff;
+ color: #d54e21;
+}
+
+#replyerror {
+ border-color: #ddd;
+ background-color: #f9f9f9;
+}
+
+/* table vim shortcuts */
+.vim-current,
+.vim-current th,
+.vim-current td {
+ background-color: #E4F2FD !important;
+}
+
+/* Install Plugins */
+#plugin-information .fyi ul {
+ background-color: #eaf3fa;
+}
+
+#plugin-information .fyi h2.mainheader {
+ background-color: #cee1ef;
+}
+
+#plugin-information pre,
+#plugin-information code {
+ background-color: #ededff;
+}
+
+#plugin-information pre {
+ border: 1px solid #ccc;
+}
+
+/* inline editor */
+#bulk-titles {
+ border-color: #ddd;
+}
+
+.inline-editor div.title {
+ background-color: #eaf3fa;
+}
+
+.inline-editor ul.cat-checklist {
+ background-color: #fff;
+ border-color: #ddd;
+}
+
+.inline-editor .quick-edit-save {
+ background-color: #f1f1f1;
+}
+
+fieldset.inline-edit-col-right .inline-edit-col {
+ border-color: #dfdfdf;
+}
+
+.attention {
+ color: #d54e21;
+}
+
+.js .meta-box-sortables .postbox:hover .handlediv {
+ background: transparent url(../images/arrows.png) no-repeat 6px 7px;
+}
+
+.tablenav .tablenav-pages {
+ color: #555;
+}
+
+.tablenav .tablenav-pages a {
+ border-color: #e3e3e3;
+ background: #eee;
+ -moz-box-shadow: inset 0 1px 0 #fff;
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+}
+
+.tablenav .tablenav-pages a:hover,
+.tablenav .tablenav-pages a:focus {
+ color: #d54e21;
+}
+
+.tablenav .tablenav-pages a.disabled,
+.tablenav .tablenav-pages a.disabled:hover,
+.tablenav .tablenav-pages a.disabled:focus {
+ color: #aaa;
+}
+
+.tablenav .tablenav-pages .current {
+ background: #dfdfdf;
+ border-color: #d3d3d3;
+}
+
+#availablethemes,
+#availablethemes td {
+ border-color: #ddd;
+}
+
+#current-theme img {
+ border-color: #999;
+}
+
+#TB_window #TB_title a.tb-theme-preview-link,
+#TB_window #TB_title a.tb-theme-preview-link:visited {
+ color: #999;
+}
+
+#TB_window #TB_title a.tb-theme-preview-link:hover,
+#TB_window #TB_title a.tb-theme-preview-link:focus {
+ color: #ccc;
+}
+
+.misc-pub-section {
+ border-top-color: #fff;
+ border-bottom-color: #dfdfdf;
+}
+
+#minor-publishing {
+ border-bottom-color: #dfdfdf;
+}
+
+#post-body .misc-pub-section {
+ border-left-color: #eee;
+}
+
+.post-com-count span {
+ background-color: #bbb;
+}
+
+.form-table .color-palette td {
+ border-color: #fff;
+}
+
+.sortable-placeholder {
+ border-color: #bbb;
+ background-color: #f5f5f5;
+}
+
+#post-body ul.category-tabs li.tabs a,
+#post-body ul.add-menu-item-tabs li.tabs a,
+body.press-this ul.category-tabs li.tabs a {
+ color: #333;
+}
+
+.view-switch #view-switch-list,
+.view-switch #view-switch-excerpt {
+ background-color: transparent;
+ background-image: url('../images/list.png');
+ background-repeat: no-repeat;
+}
+
+.view-switch #view-switch-list {
+ background-position: 0 0;
+}
+
+.view-switch .current #view-switch-list {
+ background-position: -40px 0;
+}
+
+.view-switch #view-switch-excerpt {
+ background-position: -20px 0;
+}
+
+.view-switch .current #view-switch-excerpt {
+ background-position: -60px 0;
+}
+
+#header-logo {
+ background: transparent url(../images/wp-logo.png?ver=20110504) no-repeat scroll center center;
+}
+
+.popular-tags,
+.feature-filter {
+ background-color: #fff;
+ border-color: #dfdfdf;
+}
+
+div.widgets-sortables,
+#widgets-left .inactive,
+#available-widgets .widget-holder {
+ background-color: #fcfcfc;
+ border-color: #dfdfdf;
+}
+
+#available-widgets .widget-description {
+ color: #555;
+}
+
+.sidebar-name {
+ color: #464646;
+ text-shadow: #fff 0 1px 0;
+ border-color: #dfdfdf;
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+}
+
+.js .sidebar-name:hover,
+.js #removing-widget {
+ color: #d54e21;
+}
+
+#removing-widget span {
+ color: black;
+}
+
+.js .sidebar-name-arrow {
+ background: transparent url(../images/arrows.png) no-repeat 5px 9px;
+}
+
+.js .sidebar-name:hover .sidebar-name-arrow {
+ background: transparent url(../images/arrows-dark.png) no-repeat 5px 9px;
+}
+
+.in-widget-title {
+ color: #606060;
+}
+
+.deleting .widget-title * {
+ color: #aaa;
+}
+
+.imgedit-menu div {
+ border-color: #d5d5d5;
+ background-color: #f1f1f1;
+}
+
+.imgedit-menu div:hover {
+ border-color: #c1c1c1;
+ background-color: #eaeaea;
+}
+
+.imgedit-menu div.disabled {
+ border-color: #ccc;
+ background-color: #ddd;
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+}
+
+#dashboard_recent_comments div.undo {
+ border-top-color: #dfdfdf;
+}
+
+.comment-ays,
+.comment-ays th {
+ border-color: #ddd;
+}
+
+.comment-ays th {
+ background-color: #f1f1f1;
+}
+
+/* added from nav-menu.css */
+#menu-management .menu-edit {
+ border-color: #dfdfdf;
+}
+
+#post-body {
+ background: #fff;
+ border-top-color: #fff;
+ border-bottom-color: #dfdfdf;
+}
+
+#nav-menu-header {
+ border-bottom-color: #dfdfdf;
+}
+
+#nav-menu-footer {
+ border-top-color: #fff;
+}
+
+#menu-management .nav-tabs-arrow a {
+ color: #c1c1c1;
+}
+
+#menu-management .nav-tabs-arrow a:hover {
+ color: #d54e21;
+}
+
+#menu-management .nav-tabs-arrow a:active {
+ color: #464646;
+}
+
+#menu-management .nav-tab-active {
+ border-color: #dfdfdf;
+}
+
+#menu-management .nav-tab {
+ background: #fbfbfb;
+ border-color: #dfdfdf;
+}
+
+.js .input-with-default-title {
+ color: #aaa;
+}
+
+#cancel-save {
+ color: #f00;
+}
+
+#cancel-save:hover {
+ background-color: #f00;
+ color: #fff;
+}
+
+.list-container,
+.menu-item-handle {
+ border-color: #dfdfdf;
+}
+
+.menu li.deleting .menu-item-handle {
+ background-color: #f66;
+ text-shadow: #ccc;
+}
+
+.item-type { /* Menu item controls */
+ color: #999;
+}
+
+.item-controls .menu-item-delete:hover {
+ color: #f00;
+}
+
+.nav-menus-php .item-edit {
+ background: transparent url(../images/arrows.png) no-repeat 8px 10px;
+ border-bottom-color: #eee;
+}
+
+.nav-menus-php .item-edit:hover {
+ background: transparent url(../images/arrows-dark.png) no-repeat 8px 10px;
+}
+
+.menu-item-settings { /* Menu editing */
+ border-color: #dfdfdf;
+}
+
+.link-to-original {
+ color: #777;
+ border-color: #dfdfdf;
+}
+
+#cancel-save:hover {
+ color: #fff !important;
+}
+
+#update-menu-item {
+ color: #fff !important;
+}
+
+#update-menu-item:hover,
+#update-menu-item:active,
+#update-menu-item:focus {
+ color: #eaf2fa !important;
+ border-color: #13455b !important;
+}
+
+.submitbox .submitcancel {
+ color: #21759b;
+ border-bottom-color: #21759b;
+}
+
+.submitbox .submitcancel:hover {
+ background: #21759b;
+ color: #fff;
+}
+
+.manage-menus {
+ border: 1px solid #eeeeee;
+ background: #fbfbfb;
+}
+
+.theme-location-set {
+ color: #999999;
+}
+
+.nav-menus-php .delete-action a {
+ color: #bc0b0b;
+}
+
+.is-submenu {
+ color: #999999;
+}
+/* end added from nav-menu.css */
+
+.nav-tab {
+ border-color: #dfdfdf #dfdfdf #fff;
+}
+
+.nav-tab:hover,
+.nav-tab-active {
+ border-color: #ccc #ccc #fff;
+}
+
+h2.nav-tab-wrapper, h3.nav-tab-wrapper {
+ border-bottom-color: #ccc;
+}
+
+#menu-management .nav-tab-active,
+.menu-item-handle,
+.menu-item-settings {
+ -webkit-box-shadow: inset 0 1px 0 #fff;
+ box-shadow: inset 0 1px 0 #fff;
+}
+
+#menu-management .nav-tab-active {
+ background: #f9f9f9;
+ border-bottom-color: #f9f9f9;
+}
+
+#upload-form label {
+ color: #777;
+}
+
+/* Begin About Pages */
+
+.about-wrap h1 {
+ color: #333;
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.about-text {
+ color: #777;
+}
+
+.wp-badge {
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(22, 57, 81, 0.3);
+}
+
+.about-wrap h2 .nav-tab {
+ color: #21759b;
+}
+
+.about-wrap h2 .nav-tab:hover {
+ color: #d54e21;
+}
+
+.about-wrap h2 .nav-tab-active,
+.about-wrap h2 .nav-tab-active:hover {
+ color: #333;
+}
+
+.about-wrap h2 .nav-tab-active {
+ text-shadow: 1px 1px 1px #fff;
+ color: #464646;
+}
+
+.about-wrap h3 {
+ color: #333;
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.about-wrap .feature-section h4 {
+ color: #464646;
+}
+
+.about-wrap .feature-section img {
+ background: #fff;
+ border: 1px #ccc solid;
+ -webkit-box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.3 );
+ box-shadow: 0 1px 3px rgba( 0, 0, 0, 0.3 );
+}
+
+.about-wrap h4.wp-people-group {
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.about-wrap .point-releases {
+ border-bottom: 1px solid #dfdfdf;
+}
+
+.about-wrap .point-releases h3 {
+ border-top: 1px solid #dfdfdf;
+}
+
+.about-wrap .point-releases h3:first-child {
+ border: 0;
+}
+
+.about-wrap li.wp-person img.gravatar {
+ -webkit-box-shadow: 0 0 4px rgba( 0, 0, 0, 0.4 );
+ box-shadow: 0 0 4px rgba( 0, 0, 0, 0.4 );
+}
+
+.about-wrap li.wp-person .title {
+ color: #464646;
+ text-shadow: 1px 1px 1px #fff;
+}
+
+.freedoms-php .about-wrap ol li {
+ color: #999;
+}
+
+.freedoms-php .about-wrap ol p {
+ color: #464646;
+}
+
+/* End About Pages */
+
+
+/*------------------------------------------------------------------------------
+ 2.0 - Right to Left Styles
+------------------------------------------------------------------------------*/
+
+.rtl .bar {
+ border-right-color: transparent;
+ border-left-color: #99d;
+}
+
+.rtl #screen-meta-links a.show-settings {
+ background-position: left 3px;
+}
+
+.rtl #screen-meta-links a.show-settings.screen-meta-active {
+ background-position: left -33px;
+}
+
+/* Menu */
+.rtl #adminmenushadow,
+.rtl #adminmenuback {
+ background-image: url(../images/menu-shadow-rtl.png);
+ background-position: top left;
+}
+
+.rtl #adminmenu .wp-submenu .wp-submenu-head {
+ border-right-color: transparent;
+ border-left-color: #dfdfdf;
+}
+
+.rtl #adminmenu .wp-submenu,
+.rtl.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ -webkit-box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+ box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+}
+
+.rtl #adminmenu .wp-has-current-submenu .wp-submenu {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+/* Collapse Menu Button */
+.rtl #collapse-button div {
+ background-position: 0 -108px;
+}
+
+.rtl.folded #collapse-button div {
+ background-position: 0 -72px;
+}
+
+/* Auto-folding of the admin menu for RTL */
+@media only screen and (max-width: 900px) {
+ .rtl.auto-fold #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+ .rtl.auto-fold #adminmenu .wp-has-current-submenu .wp-submenu {
+ -webkit-box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+ box-shadow: -2px 2px 5px rgba( 0, 0, 0, 0.4 );
+ }
+
+ .rtl.auto-fold #collapse-button div {
+ background-position: 0 -72px;
+ }
+}
+
+/* Edit Image */
+.js.rtl .meta-box-sortables .postbox:hover .handlediv {
+ background: transparent url(../images/arrows.png) no-repeat 6px 7px;
+}
+
+.rtl #post-body .misc-pub-section {
+ border-right-color: transparent;
+ border-left-color: #eee;
+}
+
+.js.rtl .sidebar-name-arrow {
+ background: transparent url(../images/arrows.png) no-repeat 5px 9px;
+}
+
+.js.rtl .sidebar-name:hover .sidebar-name-arrow {
+ background: transparent url(../images/arrows-dark.png) no-repeat 5px 9px;
+}
+
+/**
+ * HiDPI Displays
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+
+ .curtime #timestamp {
+ background-image: url("../images/date-button-2x.gif?ver=20120916");
+ background-size: 16px auto;
+ }
+
+ .tagchecklist span a,
+ #bulk-titles div a,
+ .tagchecklist span a:hover,
+ #bulk-titles div a:hover {
+ background-image: url("../images/xit-2x.gif?ver=20120916");
+ background-size: 20px auto;
+ }
+
+ #screen-meta-links a.show-settings,
+ #screen-meta-links a.show-settings.screen-meta-active,
+ #adminmenu .wp-has-submenu:hover .wp-menu-toggle,
+ #adminmenu .wp-menu-open .wp-menu-toggle,
+ #collapse-button div,
+ .nav-menus-php .item-edit,
+ .js .meta-box-sortables .postbox:hover .handlediv,
+ .sidebar-name-arrow,
+ .rtl #adminmenu .wp-has-submenu:hover .wp-menu-toggle,
+ .rtl #adminmenu .wp-menu-open .wp-menu-toggle,
+ .js.rtl .meta-box-sortables .postbox:hover .handlediv,
+ .rtl .sidebar-name-arrow {
+ background-image: url("../images/arrows-2x.png?ver=20120916");
+ background-size: 15px 123px;
+ }
+
+ #adminmenu li.wp-has-current-submenu.wp-menu-open .wp-menu-toggle,
+ #adminmenu li.wp-has-current-submenu:hover .wp-menu-toggle,
+ .sidebar-name:hover .sidebar-name-arrow,
+ .nav-menus-php .item-edit:hover,
+ .rtl #adminmenu li.wp-has-current-submenu.wp-menu-open .wp-menu-toggle,
+ .rtl #adminmenu li.wp-has-current-submenu:hover .wp-menu-toggle,
+ .rtl .sidebar-name:hover .sidebar-name-arrow {
+ background-image: url("../images/arrows-dark-2x.png?ver=20120916");
+ background-size: 15px 123px;
+ }
+
+ .view-switch #view-switch-list,
+ .view-switch #view-switch-excerpt {
+ background-image: url("../images/list-2x.png?ver=20120916");
+ background-size: 80px 20px;
+ }
+
+ .icon32.icon-post,
+ #icon-edit,
+ #icon-post,
+ .icon32.icon-dashboard,
+ #icon-index,
+ .icon32.icon-media,
+ #icon-upload,
+ .icon32.icon-links,
+ #icon-link-manager,
+ #icon-link,
+ #icon-link-category,
+ .icon32.icon-page,
+ #icon-edit-pages,
+ #icon-page,
+ .icon32.icon-comments,
+ #icon-edit-comments,
+ .icon32.icon-appearance,
+ #icon-themes,
+ .icon32.icon-plugins,
+ #icon-plugins,
+ .icon32.icon-users,
+ #icon-users,
+ #icon-profile,
+ #icon-user-edit,
+ .icon32.icon-tools,
+ #icon-tools,
+ #icon-admin,
+ .icon32.icon-settings,
+ #icon-options-general,
+ .icon32.icon-site,
+ #icon-ms-admin,
+ .icon32.icon-generic,
+ #icon-generic {
+ background-image: url(../images/icons32-2x.png?ver=20121105);
+ background-size: 756px 45px;
+ }
+
+ .icon16.icon-dashboard,
+ .menu-icon-dashboard div.wp-menu-image,
+ .icon16.icon-post,
+ .menu-icon-post div.wp-menu-image,
+ .icon16.icon-media,
+ .menu-icon-media div.wp-menu-image,
+ .icon16.icon-links,
+ .menu-icon-links div.wp-menu-image,
+ .icon16.icon-page,
+ .menu-icon-page div.wp-menu-image,
+ .icon16.icon-comments,
+ .menu-icon-comments div.wp-menu-image,
+ .icon16.icon-appearance,
+ .menu-icon-appearance div.wp-menu-image,
+ .icon16.icon-plugins,
+ .menu-icon-plugins div.wp-menu-image,
+ .icon16.icon-users,
+ .menu-icon-users div.wp-menu-image,
+ .icon16.icon-tools,
+ .menu-icon-tools div.wp-menu-image,
+ .icon16.icon-settings,
+ .menu-icon-settings div.wp-menu-image,
+ .icon16.icon-site,
+ .menu-icon-site div.wp-menu-image,
+ .icon16.icon-generic,
+ .menu-icon-generic div.wp-menu-image {
+ background-image: url('../images/menu-2x.png?ver=20121105');
+ background-size: 390px 64px;
+ }
+
+ #header-logo {
+ background-image: url('../images/wp-logo-2x.png?ver=20120916');
+ background-size: 16px auto;
+ }
+
+ /* 16px post formats */
+ .post-format-icon {
+ background-image: url(../images/post-formats32.png);
+ background-size: 16px 304px;
+ }
+
+}
diff --git a/src/wp-admin/css/customize-controls-rtl.css b/src/wp-admin/css/customize-controls-rtl.css
new file mode 100644
index 0000000000..236d85d8ce
--- /dev/null
+++ b/src/wp-admin/css/customize-controls-rtl.css
@@ -0,0 +1,77 @@
+#customize-header-actions .button-primary {
+ float: left;
+}
+
+#customize-header-actions .spinner {
+ float: left;
+ margin-right: 0;
+ margin-left: 4px;
+}
+
+.customize-control {
+ float: right;
+}
+
+.customize-control-radio input,
+.customize-control-checkbox input {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+/*
+ * Dropdowns
+ */
+.accordion-section .dropdown {
+ float: right;
+}
+
+.accordion-section .dropdown-content {
+ float: right;
+ margin-right: 0px;
+ margin-left: 16px;
+ -webkit-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+
+.customize-control .dropdown-arrow {
+ right: auto;
+ left: 0;
+
+ border-color: #ccc;
+ border-style: solid;
+ border-width: 1px 0 1px 1px;
+ -webkit-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+
+.customize-control .dropdown-arrow:after {
+ right: auto;
+ left: 4px;
+}
+
+/*
+ * Color Picker
+ */
+.customize-control-color .dropdown {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+.accordion-section input[type="text"].color-picker-hex {
+ direction: ltr;
+}
+
+/*
+ * Image Picker
+ */
+.accordion-section .customize-control-image .actions {
+ text-align: left;
+}
+
+.customize-control-image .library,
+.customize-control-image .actions,
+.accordion-section .customize-control-image .library ul,
+.accordion-section .customize-control-image .library li,
+.accordion-section .customize-control-image .library-content {
+ float: right;
+}
diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
new file mode 100644
index 0000000000..14f6f212d1
--- /dev/null
+++ b/src/wp-admin/css/customize-controls.css
@@ -0,0 +1,440 @@
+body {
+ overflow: hidden;
+}
+
+#customize-controls a {
+ text-decoration: none;
+}
+
+#customize-info .accordion-section-content {
+ background: transparent;
+}
+
+#customize-info .preview-notice {
+ font-size: 13px;
+ line-height: 24px;
+ color: #999;
+}
+
+#customize-info .theme-name {
+ font-size: 20px;
+ font-weight: 200;
+ line-height: 24px;
+ color: #333;
+ display: block;
+ text-shadow: 0 1px 0 #fff;
+}
+
+#customize-info .theme-screenshot {
+ width: 258px;
+ border: 1px solid #ccc;
+}
+
+#customize-info .theme-description {
+ margin-top: 1em;
+ color: #777;
+ line-height: 20px;
+}
+
+#customize-controls .submit {
+ text-align: center;
+}
+
+#customize-theme-controls > ul,
+#customize-theme-controls .accordion-section-content {
+ margin: 0;
+}
+
+#customize-header-actions .button-primary {
+ float: right;
+ margin-top: 10px;
+}
+
+#customize-header-actions .spinner {
+ margin-top: 16px;
+ margin-right: 4px;
+}
+
+.saving #customize-header-actions .spinner {
+ display: block;
+}
+
+.customize-control {
+ width: 100%;
+ float: left;
+ clear: both;
+ margin-bottom: 8px;
+}
+
+.customize-control-title {
+ display: block;
+ line-height: 24px;
+ font-weight: bold;
+}
+
+.customize-control select,
+.customize-control input[type="text"],
+.customize-control input[type="radio"],
+.customize-control input[type="checkbox"],
+.customize-control-color .color-picker,
+.customize-control-checkbox label,
+.customize-control-upload div {
+ line-height: 28px;
+}
+
+.customize-control input[type="text"] {
+ width: 98%;
+ line-height: 18px;
+ margin: 0;
+}
+
+.customize-control select {
+ min-width: 50%;
+ max-width: 100%;
+ height: 28px;
+ line-height: 28px;
+}
+
+.customize-control-checkbox input {
+ margin-right: 5px;
+}
+
+.customize-control-radio {
+ padding: 5px 0 10px;
+}
+
+.customize-control-radio .customize-control-title {
+ margin-bottom: 0;
+ line-height: 22px;
+}
+
+.customize-control-radio label {
+ line-height: 20px;
+}
+
+.customize-control-radio input {
+ margin-right: 5px;
+}
+
+#customize-preview iframe {
+ width: 100%;
+ height: 100%;
+}
+
+#customize-theme-controls .accordion-section-title:hover:after,
+#customize-theme-controls .accordion-section-title:focus:after {
+ border-color: #eee transparent;
+}
+
+#customize-theme-controls .control-section:hover .accordion-section-title,
+#customize-theme-controls .control-section .accordion-section-title:hover,
+#customize-theme-controls .control-section.open .accordion-section-title,
+#customize-theme-controls .control-section .accordion-section-title:focus {
+ color: #fff;
+ text-shadow: 0 -1px 0 #333;
+ background: #808080;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#6d6d6d), to(#808080));
+ background-image: -webkit-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: -moz-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: -o-linear-gradient(bottom, #6d6d6d, #808080);
+ background-image: linear-gradient(to top, #6d6d6d, #808080);
+ border-left: 1px solid #808080;
+ border-right: 1px solid #808080;
+}
+
+#customize-theme-controls .control-section.accordion-section:hover,
+#customize-theme-controls .control-section.accordion-section.open {
+ border-top-color: #808080;
+}
+
+#customize-theme-controls .control-section.open .accordion-section-title {
+ border-bottom: 1px solid #6d6d6d;
+}
+
+/*
+ * Style for custom settings
+ */
+
+/*
+ * Dropdowns
+ */
+.accordion-section .dropdown {
+ float: left;
+ display: block;
+ position: relative;
+ cursor: pointer;
+
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.accordion-section .dropdown-content {
+ overflow: hidden;
+ float: left;
+ min-width: 30px;
+ height: 16px;
+ line-height: 16px;
+ margin-right: 16px;
+ padding: 4px 5px;
+ background-color: #eee;
+ border: 1px solid #ccc;
+ -webkit-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.customize-control .dropdown-arrow {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ width: 15px;
+
+ border-color: #ccc;
+ border-style: solid;
+ border-width: 1px 1px 1px 0;
+ -webkit-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+
+.customize-control .dropdown-arrow:after {
+ content: '';
+ width: 0;
+ height: 0;
+ border-color: #ccc transparent;
+ border-style: solid;
+ border-width: 4px 4px 0 4px;
+ position: absolute;
+ top: 50%;
+ margin-top: -1px;
+ right: 4px;
+ z-index: 1;
+}
+
+.accordion-section .dropdown:hover .dropdown-content,
+.customize-control .dropdown:hover .dropdown-arrow {
+ border-color: #aaa;
+}
+
+.accordion-section .dropdown:hover .dropdown-arrow:after {
+ border-color: #aaa transparent;
+}
+
+.customize-control .dropdown-status {
+ display: none;
+ max-width: 112px;
+ color: #777;
+}
+
+/*
+ * Color Picker
+ */
+.customize-control-color .color-picker-hex {
+ display: none;
+}
+
+.customize-control-color.open .color-picker-hex {
+ display: block;
+}
+
+.customize-control-color .dropdown {
+ margin-right: 5px;
+ margin-bottom: 5px;
+}
+
+.customize-control-color .dropdown .dropdown-content {
+ background-color: #fff;
+ border: 1px solid rgba( 0, 0, 0, 0.15 );
+}
+
+.customize-control-color .dropdown:hover .dropdown-content {
+ border-color: rgba( 0, 0, 0, 0.25 );
+}
+
+.accordion-section input[type="text"].color-picker-hex {
+ width: 65px;
+ font-family: monospace;
+ text-align: center;
+ line-height: 16px;
+}
+
+/* The centered cursor overlaps the placeholder in webkit. Hide it when selected. */
+.accordion-section input[type="text"].color-picker-hex:focus::-webkit-input-placeholder {
+ color: transparent;
+}
+.accordion-section input[type="text"].color-picker-hex:-moz-placeholder {
+ color: #999;
+}
+
+/*
+ * Image Picker
+ */
+.customize-control-image .library,
+.customize-control-image .actions {
+ display: none;
+ float: left;
+ width: 100%;
+}
+
+.customize-control-image.open .library,
+.customize-control-image.open .actions {
+ display: block;
+}
+
+.accordion-section .customize-control-image .dropdown-content {
+ height: auto;
+ min-height: 24px;
+ min-width: 40px;
+ padding: 0;
+}
+
+.accordion-section .customize-control-image .dropdown-status {
+ padding: 4px 5px;
+}
+
+.accordion-section .customize-control-image .preview-thumbnail img {
+ display: block;
+ width: 100%;
+ max-width: 122px;
+ max-height: 98px;
+ margin: 0 auto;
+}
+
+.accordion-section .customize-control-image .actions {
+ text-align: right;
+}
+
+.accordion-section .customize-control-image .library ul {
+ border-bottom: 1px solid #dfdfdf;
+ float: left;
+ width: 100%;
+ margin: 10px 0 0;
+}
+
+.accordion-section .customize-control-image .library li {
+ color: #999;
+ float: left;
+ padding: 3px 5px;
+ margin: 0;
+ border-style: solid;
+ border-color: transparent;
+ border-width: 1px 1px 0 1px;
+}
+
+.accordion-section .customize-control-image .library li.library-selected {
+ margin-bottom: -1px;
+ padding-bottom: 4px;
+
+ color: #777;
+ background: #fdfdfd;
+ border-color: #dfdfdf;
+ -webkit-border-radius: 3px 3px 0 0;
+ border-radius: 3px 3px 0 0 ;
+}
+
+.accordion-section .customize-control-image .library-content {
+ display: none;
+ width: 100%;
+ float: left;
+ padding: 10px 0;
+}
+
+.accordion-section .customize-control-image .library-content.library-selected {
+ display: block;
+}
+
+.accordion-section .customize-control-image .library .thumbnail {
+ display: block;
+ width: 100%;
+}
+
+.accordion-section .customize-control-image .library .thumbnail:hover img {
+ border-color: #21759b;
+}
+
+.accordion-section .customize-control-image .library .thumbnail img {
+ display: block;
+ max-width: 90%;
+ max-height: 80px;
+
+ margin: 5px auto;
+ padding: 4px;
+ background: #fff;
+ border: 1px solid #dfdfdf;
+}
+
+.accordion-section .customize-control-upload .upload-fallback,
+.accordion-section .customize-control-image .upload-fallback {
+ display: none;
+}
+
+.accordion-section .customize-control-upload .upload-dropzone,
+.accordion-section .customize-control-image .upload-dropzone {
+ display: none;
+ padding: 15px 10px;
+ border: 3px dashed #dfdfdf;
+ margin: 5px auto;
+ text-align: center;
+ color: #777;
+ position: relative;
+ cursor: default;
+}
+
+.accordion-section .customize-control-upload .upload-dropzone.supports-drag-drop,
+.accordion-section .customize-control-image .upload-dropzone.supports-drag-drop {
+ display: block;
+ -webkit-transition: border-color 0.1s;
+ -moz-transition: border-color 0.1s;
+ -ms-transition: border-color 0.1s;
+ -o-transition: border-color 0.1s;
+ transition: border-color 0.1s;
+}
+
+.accordion-section .customize-control-upload .library ul li,
+.accordion-section .customize-control-image .library ul li {
+ cursor: pointer;
+}
+
+.accordion-section .customize-control-upload .upload-dropzone.supports-drag-drop.drag-over,
+.accordion-section .customize-control-image .upload-dropzone.supports-drag-drop.drag-over {
+ border-color: #83b4d8;
+}
+
+/**
+ * iOS can't scroll iframes,
+ * instead it expands the iframe size to match the size of the content
+ */
+.ios .wp-full-overlay {
+ position: relative;
+}
+
+.ios #customize-preview {
+ position: relative;
+}
+
+.ios #customize-controls .wp-full-overlay-sidebar-content {
+ -webkit-overflow-scrolling: touch;
+}
+
+/**
+ * Handle cheaters.
+ */
+body.cheatin {
+ min-width: 0;
+ background: #f9f9f9;
+ padding: 50px;
+}
+
+body.cheatin p {
+ max-width: 700px;
+ margin: 0 auto;
+ padding: 2em;
+ font-size: 14px;
+ background: #fff;
+ border: 1px solid #dfdfdf;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
diff --git a/src/wp-admin/css/farbtastic.css b/src/wp-admin/css/farbtastic.css
new file mode 100644
index 0000000000..ef1129c0de
--- /dev/null
+++ b/src/wp-admin/css/farbtastic.css
@@ -0,0 +1,52 @@
+
+.farbtastic {
+ position: relative;
+}
+
+.farbtastic * {
+ position: absolute;
+ cursor: crosshair;
+}
+
+.farbtastic,
+.farbtastic .wheel {
+ width: 195px;
+ height: 195px;
+}
+
+.farbtastic .color,
+.farbtastic .overlay {
+ top: 47px;
+ left: 47px;
+ width: 101px;
+ height: 101px;
+}
+
+.farbtastic .wheel {
+ background: url(../images/wheel.png) no-repeat;
+ width: 195px;
+ height: 195px;
+}
+
+.farbtastic .overlay {
+ background: url(../images/mask.png) no-repeat;
+}
+
+.farbtastic .marker {
+ width: 17px;
+ height: 17px;
+ margin: -8px 0 0 -8px;
+ overflow: hidden;
+ background: url(../images/marker.png) no-repeat;
+}
+
+/* farbtastic-rtl */
+.rtl .farbtastic .color,
+.rtl .farbtastic .overlay {
+ left: 0;
+ right: 47px;
+}
+
+.rtl .farbtastic .marker {
+ margin: -8px -8px 0 0;
+}
diff --git a/src/wp-admin/css/ie-rtl.css b/src/wp-admin/css/ie-rtl.css
new file mode 100644
index 0000000000..b947f0b200
--- /dev/null
+++ b/src/wp-admin/css/ie-rtl.css
@@ -0,0 +1,240 @@
+
+body {
+ direction: rtl;
+ width: 99.5%;
+}
+
+.rtl #adminmenuback {
+ left: auto;
+ right: 0;
+ background-image: none;
+}
+
+.rtl #adminmenuback,
+.rtl #adminmenuwrap {
+ border-width: 0 0 0 1px;
+}
+
+#plupload-upload-ui {
+ zoom: 1;
+}
+
+.post-com-count-wrapper a.post-com-count {
+ float: none;
+}
+
+#adminmenu .wp-submenu ul {
+ width: 99%;
+}
+
+#adminmenu .wp-submenu .wp-submenu .wp-submenu,
+#adminmenu .wp-menu-open .wp-submenu .wp-submenu {
+ border: 1px solid #dfdfdf;
+}
+
+.folded #adminmenu .wp-submenu {
+ right: 30px;
+}
+
+#wpcontent #adminmenu .wp-submenu li.wp-submenu-head {
+ padding: 3px 10px 4px 4px;
+}
+
+div.quicktags-toolbar input {
+ min-width: 0;
+}
+
+.inline-edit-row fieldset label span.title {
+ float: right;
+}
+
+.inline-edit-row fieldset label span.input-text-wrap {
+ margin-right: 0;
+}
+
+p.search-box {
+ float: left;
+}
+
+#bh {
+ margin: 7px 10px 0 0;
+ float: left;
+}
+
+.postbox div.inside,
+.wp-editor-wrap .wp-editor-container .wp-editor-area,
+#nav-menu-theme-locations .howto select {
+ width: 97.5%;
+}
+
+/* without this dashboard widgets appear in one column for some screen widths */
+div#dashboard-widgets {
+ padding-right: 0;
+ padding-left: 1px;
+}
+
+.tagchecklist span a {
+ margin: 4px -9px 0 0;
+}
+
+.widefat th input {
+ margin: 0 5px 0 0;
+}
+
+/* ---------- add by navid */
+#TB_window {
+ width: 670px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-right: 335px !important;
+}
+
+#dashboard_plugins {
+ direction: ltr;
+}
+
+#dashboard_plugins h3.hndle {
+ direction: rtl;
+}
+
+#dashboard_incoming_links ul li,
+#dashboard_secondary ul li,
+#dashboard_primary ul li,
+p.row-actions {
+ width: 100%;
+}
+
+#post-status-info {
+ height: 25px;
+}
+
+p.submit { /* quick edit and reply in edit-comments.php */
+ height:22px;
+}
+
+.available-theme .action-links li {
+ padding-left: 7px;
+ margin-left: 7px;
+}
+
+form#widgets-filter { /* fix widget page */
+ position: static;
+}
+
+/* nav menus
+.menu-max-depth-0 #menu-management { width: 460px; }
+.menu-max-depth-1 #menu-management { width: 490px; }
+.menu-max-depth-2 #menu-management { width: 520px; }
+.menu-max-depth-3 #menu-management { width: 550px; }
+.menu-max-depth-4 #menu-management { width: 580px; }
+.menu-max-depth-5 #menu-management { width: 610px; }
+.menu-max-depth-6 #menu-management { width: 640px; }
+.menu-max-depth-7 #menu-management { width: 670px; }
+.menu-max-depth-8 #menu-management { width: 700px; }
+.menu-max-depth-9 #menu-management { width: 730px; }
+.menu-max-depth-10 #menu-management { width: 760px; }
+.menu-max-depth-11 #menu-management { width: 790px; }
+*/
+.menu-item-depth-0 { margin-left: 0px; }
+.menu-item-depth-1 { margin-left: -30px; }
+.menu-item-depth-2 { margin-left: -60px; }
+.menu-item-depth-3 { margin-left: -90px; }
+.menu-item-depth-4 { margin-left: -120px; }
+.menu-item-depth-5 { margin-left: -150px; }
+.menu-item-depth-6 { margin-left: -180px; }
+.menu-item-depth-7 { margin-left: -210px; }
+.menu-item-depth-8 { margin-left: -240px; }
+.menu-item-depth-9 { margin-left: -270px; }
+.menu-item-depth-10 { margin-left: -300px; }
+.menu-item-depth-11 { margin-left: -330px; }
+
+/*
+#menu-to-edit li dl {
+ padding: 0 !important;
+ margin: 0 !important;
+}
+
+.ui-sortable-helper .menu-item-transport {
+ margin-top: 13px;
+}
+
+.ui-sortable-helper .menu-item-transport .menu-item-transport {
+ margin-top: 0;
+}
+*/
+
+#menu-management,
+.nav-menus-php .menu-edit,
+#nav-menu-header .submitbox {
+ zoom: 1;
+}
+
+.nav-menus-php label {
+ max-width: 90% !important;
+}
+
+p.button-controls,
+.nav-menus-php .tabs-panel {
+ max-width: 90%;
+}
+
+.nav-menus-php .major-publishing-actions .publishing-action {
+ float: none;
+}
+
+#wpbody #nav-menu-header label {
+ float: none;
+}
+
+#nav-menu-header {
+ margin-top: -10px;
+}
+
+#nav-menu-footer {
+ margin-bottom: -20px;
+}
+
+#update-nav-menu .publishing-action {
+ max-width: 200px;
+}
+
+#nav-menus-frame #update-nav-menu .delete-action {
+ margin-top: -25px;
+ float: left;
+}
+
+#menu-to-edit li {
+ margin-top: -10px;
+ margin-bottom: -10px;
+}
+
+.sortable-placeholder {
+ margin-top: 0 !important;
+ margin-left: 0 !important;
+ margin-bottom: 13px !important;
+ padding: 0 !important;
+}
+
+.auto-add-pages {
+ clear: both;
+ float: none;
+}
+
+#nav-menus-frame .open-label span {
+ float: none;
+ display: inline-block;
+}
+
+#nav-menus-frame .delete-action {
+ float: none;
+}
+
+#title-wrap #title-prompt-text {
+ right: 0;
+}
+
+.screen-reader-text {
+ right: auto;
+ text-indent: -1000em;
+} \ No newline at end of file
diff --git a/src/wp-admin/css/ie.css b/src/wp-admin/css/ie.css
new file mode 100644
index 0000000000..98b7b379b5
--- /dev/null
+++ b/src/wp-admin/css/ie.css
@@ -0,0 +1,642 @@
+/* Fixes for IE 7 bugs */
+
+#dashboard-widgets form .input-text-wrap input,
+#dashboard-widgets form .textarea-wrap textarea {
+ width: 99%;
+}
+
+#dashboard-widgets form #title {
+ width: 98%;
+}
+
+.wp-editor-wrap .wp-editor-container textarea.wp-editor-area {
+ width: 97%;
+}
+
+#post-body.columns-2 #postbox-container-1 {
+ padding-left: 19px;
+}
+
+.welcome-panel .wp-badge {
+ position: absolute;
+}
+
+.welcome-panel .welcome-panel-column:first-child {
+ width: 35%;
+}
+
+#wp-fullscreen-title {
+ width: 97%;
+}
+
+#wp_mce_fullscreen_ifr {
+ background-color: #f9f9f9;
+}
+
+#wp-fullscreen-tagline {
+ color: #888;
+ font-size: 14px;
+}
+
+#adminmenushadow {
+ display: none;
+}
+
+#adminmenuback {
+ left: 0;
+ background-image: none;
+}
+
+#adminmenuwrap {
+ position: static;
+}
+
+#adminmenu {
+ position: relative;
+}
+
+#adminmenu,
+#adminmenu a {
+ cursor: pointer;
+}
+
+#adminmenu li.wp-menu-separator,
+#adminmenu li.wp-menu-separator-last {
+ font-size: 1px;
+ line-height: 1;
+}
+
+#adminmenu a.menu-top {
+ border-bottom: 0 none;
+ border-top: 1px solid #ddd;
+}
+
+#adminmenu .separator {
+ font-size: 1px;
+ line-height: 1px;
+}
+
+#adminmenu .wp-submenu ul {
+ margin: 0;
+}
+
+.folded #adminmenu .wp-submenu {
+ border-top-color: transparent;
+}
+
+#adminmenu .wp-submenu .wp-submenu-head {
+ border-top-color: #ddd;
+}
+
+.folded #adminmenu .wp-submenu ul {
+ margin-left: 5px;
+}
+
+#adminmenu li.menu-top {
+ margin-bottom: -2px;
+}
+
+#adminmenu .wp-menu-arrow {
+ display: none !important;
+}
+
+.js.folded #adminmenu li.menu-top {
+ display: block;
+ zoom: 100%;
+}
+
+ul#adminmenu {
+ z-index: 99;
+}
+
+#adminmenu li.menu-top a.menu-top {
+ min-width: auto;
+ width: auto;
+}
+
+#wpcontent #adminmenu li.wp-has-current-submenu a.wp-has-submenu {
+ font-style: normal;
+}
+
+#wpcontent #adminmenu .wp-submenu li {
+ padding: 0;
+}
+
+#collapse-menu {
+ line-height: 23px;
+}
+
+#wpadminbar .ab-comments-icon {
+ padding-top: 7px;
+}
+
+table.fixed th,
+table.fixed td {
+ border-top: 1px solid #ddd;
+}
+
+#wpbody-content input.button,
+#wpbody-content input.button-primary,
+#wpbody-content input.button-secondary {
+ overflow: visible;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit #publish {
+ float: none;
+}
+
+#dashboard-widgets h3 a {
+ height: 14px;
+ line-height: 14px;
+}
+
+#dashboard_browser_nag {
+ color: #fff;
+}
+
+#dashboard_browser_nag .browser-icon {
+ position: relative;
+}
+
+.tablenav-pages .current-page {
+ vertical-align: middle;
+}
+
+#wpbody-content .postbox {
+ border: 1px solid #dfdfdf;
+}
+
+#wpbody-content .postbox h3 {
+ margin-bottom: -1px;
+}
+
+.major-publishing-actions,
+.wp-submenu,
+.wp-submenu li,
+#template,
+#template div,
+#editcat,
+#addcat {
+ zoom: 100%;
+}
+
+.wp-menu-arrow {
+ height: 28px;
+}
+
+.submitbox {
+ margin-top: 10px;
+}
+
+/* Inline Editor */
+#wpbody-content .quick-edit-row-post .inline-edit-col-left {
+ width: 39%;
+}
+
+#wpbody-content .inline-edit-row-post .inline-edit-col-center {
+ width: 19%;
+}
+
+#wpbody-content .quick-edit-row-page .inline-edit-col-left {
+ width: 49%;
+}
+
+#wpbody-content .bulk-edit-row .inline-edit-col-left {
+ width: 29%;
+}
+
+.inline-edit-row p.submit {
+ zoom: 100%;
+}
+
+.inline-edit-row fieldset label span.title {
+ display: block;
+ float: left;
+ width: 5em;
+}
+
+.inline-edit-row fieldset label span.input-text-wrap {
+ margin-left: 0;
+ zoom: 100%;
+}
+
+#wpbody-content .inline-edit-row fieldset label span.input-text-wrap input {
+ line-height: 130%;
+}
+
+#wpbody-content .inline-edit-row .input-text-wrap input {
+ width: 95%;
+}
+
+#wpbody-content .inline-edit-row .input-text-wrap input.inline-edit-password-input {
+ width: 8em;
+}
+/* end Inline Editor */
+
+#titlediv #title {
+ width: 98%;
+}
+
+.button,
+input[type="reset"],
+input[type="button"],
+input[type="submit"] {
+ padding: 0 8px;
+ line-height: 20px;
+ height: auto;
+}
+
+.button.button-large,
+input[type="reset"].button-large,
+input[type="button"].button-large,
+input[type="submit"].button-large {
+ padding: 0 10px;
+ line-height: 24px;
+ height: auto;
+}
+
+.button.button-small,
+input[type="reset"].button-small,
+input[type="button"].button-small,
+input[type="submit"].button-small {
+ padding: 0 6px;
+ line-height: 16px;
+ height: auto;
+}
+
+a.button {
+ margin: 1px;
+ padding: 1px 9px 2px;
+}
+
+a.button.button-large {
+ padding: 1px 11px 2px;
+}
+
+a.button.button-small {
+ padding: 1px 7px 2px;
+}
+
+#screen-options-wrap {
+ overflow: hidden;
+}
+
+#the-comment-list .comment-item,
+#post-status-info,
+#wpwrap,
+#wrap,
+#postdivrich,
+#postdiv,
+#poststuff,
+.metabox-holder,
+#titlediv,
+#post-body,
+#editorcontainer,
+.tablenav,
+.widget-liquid-left,
+.widget-liquid-right,
+#widgets-left,
+.widgets-sortables,
+#dragHelper,
+.widget .widget-top,
+.widget-control-actions,
+.tagchecklist,
+#col-container,
+#col-left,
+#col-right,
+.fileedit-sub {
+ display: block;
+ zoom: 100%;
+}
+
+p.search-box {
+ position: static;
+ float: right;
+ margin: -3px 0 4px;
+}
+
+#widget-list .widget,
+.feature-filter .feature-group li {
+ display: inline;
+}
+
+.feature-filter .feature-group li input {
+ vertical-align: middle;
+}
+
+#editorcontainer #content {
+ overflow: auto;
+ margin: auto;
+ width: 98%;
+}
+
+form#template div {
+ width: 100%;
+}
+
+.wp-editor-container .quicktags-toolbar input {
+ overflow: visible;
+ padding: 0 4px;
+}
+
+#poststuff h2 {
+ font-size: 1.6em;
+}
+
+#poststuff .inside #parent_id,
+#poststuff .inside #page_template,
+.inline-edit-row #post_parent,
+.inline-edit-row select[name="page_template"] {
+ width: 250px;
+}
+
+#submitdiv input,
+#submitdiv select,
+#submitdiv a.button {
+ position: relative;
+}
+
+#bh {
+ margin: 7px 10px 0 0;
+ float: right;
+}
+
+/* without this dashboard widgets appear in one column for some screen widths */
+div#dashboard-widgets {
+ padding-right: 1px;
+}
+
+.tagchecklist span, .tagchecklist span a {
+ display: inline-block;
+ display: block;
+}
+
+.tagchecklist span a {
+ margin: 4px 0 0 -9px;
+}
+
+.tablenav .button-secondary,
+.nav .button-secondary {
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+
+.tablenav select {
+ font-size: 13px;
+ display: inline-block;
+ vertical-align: top;
+ margin-top: 2px;
+}
+
+.tablenav .actions select {
+ width: 155px;
+}
+
+.subsubsub li {
+ display: inline;
+}
+
+a.post-state-format {
+ text-indent: 0;
+ line-height: 0;
+ font-size: 0;
+}
+
+table.ie-fixed {
+ table-layout: fixed;
+}
+
+.widefat tr,
+.widefat th {
+ margin-bottom: 0;
+ border-spacing: 0;
+}
+
+.widefat th input {
+ margin: 0 0 0 5px;
+}
+
+.widefat thead .check-column,
+.widefat tfoot .check-column {
+ padding-top: 6px;
+}
+
+.widefat tbody th.check-column,
+.media.widefat tbody th.check-column {
+ padding: 4px 0 0;
+}
+
+.widefat {
+ empty-cells: show;
+ border-collapse: collapse;
+}
+
+.tablenav a.button-secondary {
+ display: inline-block;
+ padding: 2px 5px;
+}
+
+.inactive-sidebar .widgets-sortables {
+ padding-bottom: 8px;
+}
+
+#available-widgets .widget-holder {
+ padding-bottom: 65px;
+}
+
+#widgets-left .inactive {
+ padding-bottom: 10px;
+}
+
+.widget-liquid-right .widget,
+.inactive-sidebar .widget {
+ position: relative;
+}
+
+.inactive-sidebar .widget {
+ display: block;
+ float: left;
+}
+
+#wpcontent .button-primary-disabled {
+ color: #9FD0D5;
+ background: #298CBA;
+}
+
+#the-comment-list .unapproved tr,
+#the-comment-list .unapproved td {
+ background-color: #ffffe0;
+}
+
+.imgedit-submit {
+ width: 300px;
+}
+
+#nav-menus-frame,
+#wpbody,
+.menu li {
+ zoom: 100%;
+}
+
+#update-nav-menu #post-body {
+ overflow:hidden;
+}
+
+.menu li {
+ min-width: 100%;
+}
+
+.menu li.sortable-placeholder {
+ min-width: 400px;
+}
+
+.about-wrap img.element-screenshot {
+ padding: 2px;
+}
+
+.about-wrap .feature-section img,
+.about-wrap .feature-section .image-mask {
+ border-width: 1px;
+ border-style: solid;
+}
+
+.about-wrap .feature-section.three-col img {
+ margin-left: 0;
+}
+
+.available-theme {
+ display: inline;
+}
+
+.available-theme ul {
+ margin: 0;
+}
+
+.available-theme .action-links li {
+ padding-right: 7px;
+ margin-right: 7px;
+}
+
+.about-wrap .three-col-images img {
+ margin: 0 0.6% 10px;
+}
+
+.about-wrap .three-col-images .last-feature,
+.about-wrap .three-col-images .first-feature {
+ float: none;
+}
+
+/* IE6 leftovers */
+* html .row-actions {
+ visibility: visible;
+}
+
+* html div.widget-liquid-left,
+* html div.widget-liquid-right {
+ display: block;
+ position: relative;
+}
+
+* html #editorcontainer {
+ padding: 0;
+}
+
+* html #poststuff h2 {
+ margin-left: 0;
+}
+
+* html .stuffbox,
+* html .stuffbox input,
+* html .stuffbox textarea {
+ border: 1px solid #DFDFDF;
+}
+
+* html .feature-filter .feature-group li {
+ width: 145px;
+}
+
+* html div.widget-liquid-left {
+ width: 99%;
+}
+
+* html .widgets-sortables {
+ height: 50px;
+}
+
+* html a#content_resize {
+ right: -2px;
+}
+
+* html .widget-title h4 {
+ width: 205px;
+}
+
+* html #removing-widget .in-widget-title {
+ display: none;
+}
+
+* html .media-item .pinkynail {
+ height: 32px;
+ width: 40px;
+}
+
+* html .describe .field input.text,
+* html .describe .field textarea {
+ width: 440px;
+}
+
+* html input {
+ border: 1px solid #dfdfdf;
+}
+
+* html .edit-box {
+ display: inline;
+}
+
+* html .postbox-container .meta-box-sortables {
+ height: 300px;
+}
+
+* html #wpbody-content #screen-options-link-wrap {
+ display: inline-block;
+ width: 150px;
+ text-align: center;
+}
+
+* html #wpbody-content #contextual-help-link-wrap {
+ display: inline-block;
+ width: 100px;
+ text-align: center;
+}
+
+* html #adminmenu {
+ margin-left: -80px;
+}
+
+* html .folded #adminmenu {
+ margin-left: -22px;
+}
+
+* html #wpcontent #adminmenu li.menu-top {
+ display: inline;
+ padding: 0;
+ margin: 0;
+}
+
+* html #wpfooter {
+ margin: 0;
+}
+
+* html #adminmenu div.wp-menu-image {
+ height: 29px;
+}
+
+.revisions-tickmarks,
+.revisions-tooltip {
+ display: none !important;
+}
+
+.revisions.pinned .revisions-controls {
+ position: relative;
+}
+
diff --git a/src/wp-admin/css/install.css b/src/wp-admin/css/install.css
new file mode 100644
index 0000000000..1b33764ab2
--- /dev/null
+++ b/src/wp-admin/css/install.css
@@ -0,0 +1,261 @@
+html {
+ background: #f9f9f9;
+}
+
+body {
+ background: #fff;
+ color: #333;
+ font-family: sans-serif;
+ margin: 2em auto;
+ padding: 1em 2em;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ border: 1px solid #dfdfdf;
+ max-width: 700px;
+}
+
+a {
+ color: #21759b;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #d54e21;
+}
+
+h1 {
+ border-bottom: 1px solid #dadada;
+ clear: both;
+ color: #666;
+ font: 24px Georgia, "Times New Roman", Times, serif;
+ margin: 30px 0 0 0;
+ padding: 0;
+ padding-bottom: 7px;
+}
+
+h2 {
+ font-size: 16px;
+}
+
+p, li, dd, dt {
+ padding-bottom: 2px;
+ font-size: 14px;
+ line-height: 1.5;
+}
+
+code, .code {
+ font-size: 14px;
+}
+
+ul, ol, dl {
+ padding: 5px 5px 5px 22px;
+}
+
+a img {
+ border:0
+}
+abbr {
+ border: 0;
+ font-variant: normal;
+}
+#logo {
+ margin: 6px 0 14px 0;
+ border-bottom: none;
+ text-align:center
+}
+#logo a {
+ background-image: url('../images/wordpress-logo.png?ver=20120216');
+ background-size: 274px 63px;
+ background-position: top center;
+ background-repeat: no-repeat;
+ height: 67px;
+ text-indent: -9999px;
+ outline: none;
+ overflow: hidden;
+ display: block;
+}
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ #logo a {
+ background-image: url('../images/wordpress-logo-2x.png?ver=20120412');
+ background-size: 274px 63px;
+ }
+}
+.step {
+ margin: 20px 0 15px;
+}
+.step, th {
+ text-align: left;
+ padding: 0;
+}
+.step .button-large {
+ font-size: 14px;
+}
+textarea {
+ border: 1px solid #dfdfdf;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ font-family: sans-serif;
+ width: 695px;
+}
+
+.form-table {
+ border-collapse: collapse;
+ margin-top: 1em;
+ width: 100%;
+}
+
+.form-table td {
+ margin-bottom: 9px;
+ padding: 10px 20px 10px 0;
+ border-bottom: 8px solid #fff;
+ font-size: 14px;
+ vertical-align: top
+}
+
+.form-table th {
+ font-size: 14px;
+ text-align: left;
+ padding: 16px 20px 10px 0;
+ border-bottom: 8px solid #fff;
+ width: 140px;
+ vertical-align: top;
+}
+
+.form-table code {
+ line-height: 18px;
+ font-size: 14px;
+}
+
+.form-table p {
+ margin: 4px 0 0 0;
+ font-size: 11px;
+}
+
+.form-table input {
+ line-height: 20px;
+ font-size: 15px;
+ padding: 2px;
+ border: 1px #dfdfdf solid;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ font-family: sans-serif;
+}
+
+.form-table input[type=text],
+.form-table input[type=password] {
+ width: 206px;
+}
+
+.form-table th p {
+ font-weight: normal;
+}
+
+.form-table.install-success td {
+ vertical-align: middle;
+ padding: 16px 20px 10px 0;
+}
+
+.form-table.install-success td p {
+ margin: 0;
+ font-size: 14px;
+}
+
+.form-table.install-success td code {
+ margin: 0;
+ font-size: 18px;
+}
+
+#error-page {
+ margin-top: 50px;
+}
+
+#error-page p {
+ font-size: 14px;
+ line-height: 18px;
+ margin: 25px 0 20px;
+}
+
+#error-page code, .code {
+ font-family: Consolas, Monaco, monospace;
+}
+
+#pass-strength-result {
+ background-color: #eee;
+ border-color: #ddd !important;
+ border-style: solid;
+ border-width: 1px;
+ margin: 5px 5px 5px 0;
+ padding: 5px;
+ text-align: center;
+ width: 200px;
+ display: none;
+}
+
+#pass-strength-result.bad {
+ background-color: #ffb78c;
+ border-color: #ff853c !important;
+}
+
+#pass-strength-result.good {
+ background-color: #ffec8b;
+ border-color: #ffcc00 !important;
+}
+
+#pass-strength-result.short {
+ background-color: #ffa0a0;
+ border-color: #f04040 !important;
+}
+
+#pass-strength-result.strong {
+ background-color: #c3ff88;
+ border-color: #8dff1c !important;
+}
+
+.message {
+ border: 1px solid #e6db55;
+ padding: 0.3em 0.6em;
+ margin: 5px 0 15px;
+ background-color: #ffffe0;
+}
+
+/* install-rtl */
+body.rtl {
+ font-family: Tahoma, arial;
+}
+
+.rtl h1 {
+ font-family: arial;
+ margin: 5px -4px 0 0;
+}
+
+.rtl ul,
+.rtl ol {
+ padding: 5px 22px 5px 5px;
+}
+
+.rtl .step,
+.rtl th,
+.rtl .form-table th {
+ text-align: right;
+}
+
+.rtl .submit input,
+.rtl .button,
+.rtl .button-secondary {
+ margin-right: 0;
+}
+
+.rtl #dbname,
+.rtl #uname,
+.rtl #pwd,
+.rtl #dbhost,
+.rtl #prefix,
+.rtl #user_login,
+.rtl #admin_email,
+.rtl #pass1,
+.rtl #pass2 {
+ direction: ltr;
+}
diff --git a/src/wp-admin/css/media-rtl.css b/src/wp-admin/css/media-rtl.css
new file mode 100644
index 0000000000..0c3ccb3cac
--- /dev/null
+++ b/src/wp-admin/css/media-rtl.css
@@ -0,0 +1,71 @@
+body#media-upload ul#sidemenu {
+ left: auto;
+ right: 0;
+}
+#search-filter {
+ text-align: left;
+}
+/* specific to the image upload form */
+.align .field label {
+ padding: 0 23px 0 0;
+ margin: 0 3px 0 1em;
+}
+.image-align-none-label, .image-align-left-label, .image-align-center-label, .image-align-right-label {
+ background-position: center right;
+}
+tr.image-size label {
+ margin: 0 5px 0 0;
+}
+.file-error {
+ margin: 0 50px 5px 0;
+}
+.progress {
+ left: auto;
+ right: 0;
+}
+.describe td {
+ padding: 0 0 0 5px;
+}
+
+/* Specific to Uploader */
+#media-upload .describe th.label {
+ text-align: right;
+}
+.menu_order {
+ float: left;
+}
+.media-upload-form label.form-help, td.help, #media-upload p.help, #media-upload label.help {
+ font-family: Tahoma, Arial;
+}
+#gallery-settings #basic th.label {
+ padding: 5px 0 5px 5px;
+}
+#gallery-settings .title, h3.media-title {
+ font-family: Tahoma, Arial;
+}
+#gallery-settings .describe th.label {
+ text-align: right;
+}
+#gallery-settings label,
+#gallery-settings legend {
+ margin-right: 0;
+ margin-left: 15px;
+}
+#gallery-settings .align .field label {
+ margin: 0 3px 0 1em;
+}
+#sort-buttons {
+ margin: 3px 0 -8px 25px;
+ text-align: left;
+}
+
+#sort-buttons #asc,
+#sort-buttons #showall {
+ padding-left: 0;
+ padding-right: 5px;
+}
+
+#sort-buttons span {
+ margin-right: 0;
+ margin-left: 25px;
+}
diff --git a/src/wp-admin/css/media.css b/src/wp-admin/css/media.css
new file mode 100644
index 0000000000..85adbf3066
--- /dev/null
+++ b/src/wp-admin/css/media.css
@@ -0,0 +1,353 @@
+/* Styles for the media library iframe (not used on the Library screen) */
+
+div#media-upload-header {
+ margin: 0;
+ padding: 5px 5px 0;
+ font-weight: bold;
+ position: relative;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+body#media-upload ul#sidemenu {
+ font-weight: normal;
+ margin: 0 5px;
+ left: 0;
+ bottom: -1px;
+ float: none;
+ overflow: hidden;
+}
+
+form {
+ margin: 1em;
+}
+
+#search-filter {
+ text-align: right;
+}
+
+th {
+ position: relative;
+}
+
+.media-upload-form label.form-help, td.help {
+ font-family: sans-serif;
+ font-style: italic;
+ font-weight: normal;
+}
+
+.media-upload-form p.help {
+ margin: 0;
+ padding: 0;
+}
+
+.media-upload-form fieldset {
+ width: 100%;
+ border: none;
+ text-align: justify;
+ margin: 0 0 1em 0;
+ padding: 0;
+}
+
+/* specific to the image upload form */
+
+.image-align-none-label {
+ background: url(../images/align-none.png) no-repeat center left;
+}
+
+.image-align-left-label {
+ background: url(../images/align-left.png) no-repeat center left;
+}
+
+.image-align-center-label {
+ background: url(../images/align-center.png) no-repeat center left;
+}
+
+.image-align-right-label {
+ background: url(../images/align-right.png) no-repeat center left;
+}
+
+tr.image-size td {
+ width: 460px;
+}
+
+tr.image-size div.image-size-item {
+ margin: 0 0 5px;
+}
+
+#library-form .progress,
+#gallery-form .progress,
+.insert-gallery,
+.describe.startopen,
+.describe.startclosed {
+ display: none;
+}
+
+.media-item .thumbnail {
+ max-width: 128px;
+ max-height: 128px;
+}
+
+thead.media-item-info tr {
+ background-color: transparent;
+}
+
+.form-table thead.media-item-info {
+ border: 8px solid #fff;
+}
+
+abbr.required {
+ text-decoration: none;
+ border: none;
+}
+
+.describe label {
+ display: inline;
+}
+
+.describe td.error {
+ padding: 2px 8px;
+}
+
+.describe td.A1 {
+ width: 132px;
+}
+
+.describe input[type="text"],
+.describe textarea {
+ width: 460px;
+ border-width: 1px;
+ border-style: solid;
+}
+
+/* Specific to Uploader */
+
+#media-upload p.ml-submit {
+ padding: 1em 0;
+}
+
+#media-upload p.help,
+#media-upload label.help {
+ font-family: sans-serif;
+ font-style: italic;
+ font-weight: normal;
+}
+
+#media-upload .ui-sortable .media-item {
+ cursor: move;
+}
+
+#media-upload tr.image-size {
+ margin-bottom: 1em;
+ height: 3em;
+}
+
+#media-upload #filter {
+ width: 623px;
+}
+
+#media-upload #filter .subsubsub {
+ margin: 8px 0;
+}
+
+#filter .tablenav select {
+ border-style: solid;
+ border-width: 1px;
+ padding: 2px;
+ vertical-align: top;
+ width: auto;
+}
+
+#media-upload .del-attachment {
+ display: none;
+ margin: 5px 0;
+}
+
+.menu_order {
+ float: right;
+ font-size: 11px;
+ margin: 10px 10px 0;
+}
+
+.menu_order_input {
+ border: 1px solid #ddd;
+ font-size: 10px;
+ padding: 1px;
+ width: 23px;
+}
+
+.ui-sortable-helper {
+ background-color: #fff;
+ border: 1px solid #aaa;
+ opacity: 0.6;
+ filter: alpha(opacity=60);
+}
+
+#media-upload th.order-head {
+ width: 20%;
+ text-align: center;
+}
+
+#media-upload th.actions-head {
+ width: 25%;
+ text-align: center;
+}
+
+#media-upload a.wp-post-thumbnail {
+ margin: 0 20px;
+}
+
+#media-upload .widefat {
+ width: 626px;
+ border-style: solid solid none;
+}
+
+.sorthelper {
+ height: 37px;
+ width: 623px;
+ display: block;
+}
+
+#gallery-settings th.label {
+ width: 160px;
+}
+
+#gallery-settings #basic th.label {
+ padding: 5px 5px 5px 0;
+}
+
+#gallery-settings .title {
+ clear: both;
+ padding: 0 0 3px;
+ font-size: 1.6em;
+ border-bottom: 1px solid #DADADA;
+}
+
+h3.media-title {
+ font-size: 1.6em;
+}
+
+h4.media-sub-title {
+ border-bottom: 1px solid #DADADA;
+ font-size: 1.3em;
+ margin: 12px;
+ padding: 0 0 3px;
+}
+
+#gallery-settings .title,
+h3.media-title,
+h4.media-sub-title {
+ font-family: Georgia,"Times New Roman",Times,serif;
+ font-weight: normal;
+ color: #5A5A5A;
+}
+
+#gallery-settings .describe td {
+ vertical-align: middle;
+ height: 3em;
+}
+
+#gallery-settings .describe th.label {
+ padding-top: .5em;
+ text-align: left;
+}
+
+#gallery-settings .describe {
+ padding: 5px;
+ width: 615px;
+ clear: both;
+ cursor: default;
+}
+
+#gallery-settings .describe select {
+ width: 15em;
+}
+
+#gallery-settings .describe select option,
+#gallery-settings .describe td {
+ padding: 0;
+}
+
+#gallery-settings label,
+#gallery-settings legend {
+ font-size: 13px;
+ color: #464646;
+ margin-right: 15px;
+}
+
+#gallery-settings .align .field label {
+ margin: 0 1em 0 3px;
+}
+
+#gallery-settings p.ml-submit {
+ border-top: 1px solid #dfdfdf;
+}
+
+#gallery-settings select#columns {
+ width: 6em;
+}
+
+#sort-buttons {
+ font-size: 0.8em;
+ margin: 3px 25px -8px 0;
+ text-align: right;
+ max-width: 625px;
+}
+
+#sort-buttons a {
+ text-decoration: none;
+}
+
+#sort-buttons #asc,
+#sort-buttons #showall {
+ padding-left: 5px;
+}
+
+#sort-buttons span {
+ margin-right: 25px;
+}
+
+p.media-types {
+ margin: 1em;
+}
+
+tr.not-image {
+ display: none;
+}
+
+table.not-image tr.not-image {
+ display: table-row;
+}
+
+table.not-image tr.image-only {
+ display: none;
+}
+
+/**
+ * HiDPI Displays
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+
+ .image-align-none-label {
+ background-image: url("../images/align-none-2x.png?ver=20120916");
+ background-size: 21px 15px;
+ }
+
+ .image-align-left-label {
+ background-image: url("../images/align-left-2x.png?ver=20120916");
+ background-size: 22px 15px;
+ }
+
+ .image-align-center-label {
+ background-image: url("../images/align-center-2x.png?ver=20120916");
+ background-size: 21px 15px;
+ }
+
+ .image-align-right-label {
+ background-image: url("../images/align-right-2x.png?ver=20120916");
+ background-size: 22px 15px;
+ }
+}
diff --git a/src/wp-admin/css/wp-admin-rtl.css b/src/wp-admin/css/wp-admin-rtl.css
new file mode 100644
index 0000000000..3061592a5f
--- /dev/null
+++ b/src/wp-admin/css/wp-admin-rtl.css
@@ -0,0 +1,2931 @@
+/*------------------------------------------------------------------------------
+
+
+Hello, this is the RTL version of the main WordPress admin CSS file.
+All the important stuff is in here.
+
+
+TABLE OF CONTENTS:
+------------------
+ 1.0 - Text Elements
+ 2.0 - Forms
+ 3.0 - Actions
+ 4.0 - Notifications
+ 5.0 - TinyMCE
+ 6.0 - Admin Header
+ 6.1 - Screen Options Tabs
+ 7.0 - Main Navigation
+ 8.0 - Layout Blocks
+ 9.0 - Dashboard
+10.0 - List Posts
+ 10.1 - Inline Editing
+11.0 - Write/Edit Post Screen
+ 11.1 - Custom Fields
+ 11.2 - Post Revisions
+ 11.3 - Featured Images
+ 11.4 - Post formats
+12.0 - Categories
+13.0 - Tags
+14.0 - Media Screen
+ 14.1 - Media Uploader
+ 14.2 - Image Editor
+15.0 - Comments Screen
+16.0 - Themes
+ 16.1 - Custom Header
+ 16.2 - Custom Background
+ 16.3 - Tabbed Admin Screen Interface
+17.0 - Plugins
+18.0 - Users
+19.0 - Tools
+20.0 - Settings
+21.0 - Admin Footer
+22.0 - About Pages
+23.0 - Misc
+24.0 - Dead
+25.0 - TinyMCE tweaks
+26.0 - Full Overlay w/ Sidebar
+27.0 - Customize Loader
+28.0 - Nav Menus
+29.0 - HiDPI
+
+
+------------------------------------------------------------------------------*/
+
+
+/*------------------------------------------------------------------------------
+ 1.0 - Text Styles
+------------------------------------------------------------------------------*/
+
+ol {
+ margin-left: 0;
+ margin-right: 2em;
+}
+
+.code, code {
+ font-family: monospace;
+ direction: ltr;
+}
+
+.quicktags, .search {
+ font: 12px Tahoma, Arial, sans-serif;
+}
+
+.icon32 {
+ float: right;
+ margin-right: 0;
+ margin-left: 8px;
+}
+
+.icon16 {
+ float: right;
+ margin-right: -8px;
+ margin-left: 0;
+}
+
+.howto {
+ font-style: normal;
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+p.install-help {
+ font-style: normal;
+}
+
+
+/*------------------------------------------------------------------------------
+ 2.0 - Forms
+------------------------------------------------------------------------------*/
+
+#doaction,
+#doaction2,
+#post-query-submit {
+ margin-right: 0;
+ margin-left: 8px;
+}
+
+#timezone_string option {
+ margin-left: 0;
+ margin-right: 1em;
+}
+
+#pass-strength-result {
+ float: right;
+ margin: 13px 1px 5px 5px;
+}
+
+p.search-box {
+ float: left;
+}
+
+.search-box input[name="s"],
+#search-plugins input[name="s"],
+.tagsdiv .newtag {
+ float: right;
+ margin-right: 0;
+ margin-left: 4px;
+}
+
+input[type=password] {
+ direction: ltr;
+}
+
+input[type="text"].ui-autocomplete-loading {
+ background: transparent url('../images/loading.gif') no-repeat left center;
+}
+
+ul#add-to-blog-users {
+ margin: 0 14px 0 0;
+}
+
+.ui-autocomplete li {
+ text-align: right;
+}
+
+/*------------------------------------------------------------------------------
+ 3.0 - Actions
+------------------------------------------------------------------------------*/
+
+#delete-action {
+ float: right;
+}
+
+#publishing-action {
+ float: left;
+ text-align: left;
+}
+
+#publishing-action .spinner {
+ float: right;
+}
+
+#post-body .misc-pub-section {
+ border-right: 0;
+ border-left-width: 1px;
+ border-left-style: solid;
+}
+
+#post-body .misc-pub-section-last {
+ border-left: 0;
+}
+
+#minor-publishing-actions {
+ padding: 10px 8px 2px 10px;
+ text-align: left;
+}
+
+#save-post {
+ float: right;
+}
+
+.preview {
+ float: left;
+}
+
+#sticky-span {
+ margin-left: 0;
+ margin-right: 18px;
+}
+
+.side-info ul {
+ padding-left: 0;
+ padding-right: 18px;
+}
+
+td.action-links,
+th.action-links {
+ text-align: left;
+}
+
+
+/*------------------------------------------------------------------------------
+ 4.0 - Notifications
+------------------------------------------------------------------------------*/
+
+form.upgrade .hint {
+ font-style: normal;
+}
+
+#ajax-response.alignleft {
+ margin-left: 0;
+ margin-right: 2em;
+}
+
+
+/*------------------------------------------------------------------------------
+ 5.0 - TinyMCE
+------------------------------------------------------------------------------*/
+
+#quicktags {
+ background-position: right top;
+}
+
+#ed_reply_toolbar input {
+ margin: 1px 1px 1px 2px;
+}
+
+/*------------------------------------------------------------------------------
+ 6.0 - Admin Header
+------------------------------------------------------------------------------*/
+#wphead {
+ height: 32px;
+ margin-left: 15px;
+ margin-right: 2px;
+}
+
+#header-logo {
+ float: right;
+}
+
+#wphead h1 {
+ float: right;
+}
+
+/*------------------------------------------------------------------------------
+ 6.1 - Screen Options Tabs
+------------------------------------------------------------------------------*/
+
+#screen-meta-links {
+ margin-right: 0;
+ margin-left: 24px;
+}
+
+#screen-meta {
+ margin-right: 5px;
+ margin-left: 15px;
+}
+
+#screen-options-link-wrap,
+#contextual-help-link-wrap {
+ float: left;
+ margin-left: 0;
+ margin-right: 6px;
+}
+
+#screen-meta-links a.show-settings {
+ padding-right: 6px;
+ padding-left: 16px;
+}
+
+.toggle-arrow {
+ background-position: top right;
+}
+.toggle-arrow-active {
+ background-position: bottom right;
+}
+
+.metabox-prefs label {
+ padding-right: 0;
+ padding-left: 15px;
+}
+
+.metabox-prefs label input {
+ margin-right: 2px;
+ margin-left: 5px;
+}
+
+/*------------------------------------------------------------------------------
+ 6.2 - Help Menu
+------------------------------------------------------------------------------*/
+
+#contextual-help-wrap {
+ margin-left: 0;
+ margin-right: -4px;
+}
+
+#contextual-help-back {
+ left: 170px;
+ right: 150px;
+}
+
+#contextual-help-wrap.no-sidebar #contextual-help-back {
+ left: 0;
+ right: 150px;
+
+ border-right-width: 1px;
+ border-left-width: 0;
+ -webkit-border-bottom-right-radius: 0;
+ border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 2px;
+ border-bottom-left-radius: 2px;
+}
+
+.contextual-help-tabs {
+ float: right;
+}
+
+.contextual-help-tabs a {
+ padding-left: 5px;
+ padding-right: 12px;
+}
+
+.contextual-help-tabs .active {
+ margin-right: 0;
+ margin-left: -1px;
+}
+
+.contextual-help-tabs .active,
+.contextual-help-tabs-wrap {
+ border-left: 0;
+ border-right-width: 1px;
+}
+
+.help-tab-content {
+ margin-right: 0;
+ margin-left: 22px;
+}
+
+.help-tab-content li {
+ margin-left: 0;
+ margin-right: 18px;
+}
+
+.contextual-help-sidebar {
+ float: left;
+ padding-right: 12px;
+ padding-left: 8px;
+}
+
+/*------------------------------------------------------------------------------
+ 7.0 - Main Navigation (Right Menu) (RTL: Left Menu)
+------------------------------------------------------------------------------*/
+
+.folded #wpcontent {
+ margin-left: 0;
+ margin-right: 52px;
+}
+
+.folded.wp-admin #wpfooter {
+ margin-left: 15px;
+ margin-right: 52px;
+}
+
+#adminmenuback,
+#adminmenuwrap {
+ border-width: 0 0 0 1px;
+}
+
+#adminmenushadow {
+ right: auto;
+ left: 0;
+}
+
+#adminmenu li .wp-submenu {
+ left: auto;
+ right: 146px;
+}
+
+
+.folded #adminmenu .wp-submenu.sub-open,
+.folded #adminmenu .opensub .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu.sub-open,
+.folded #adminmenu .wp-has-current-submenu.opensub .wp-submenu,
+.folded #adminmenu a.menu-top:focus + .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu,
+.no-js.folded #adminmenu .wp-has-submenu:hover .wp-submenu {
+ left: auto;
+ right: 32px;
+}
+
+#adminmenu div.wp-menu-image,
+.folded #adminmenu div.wp-menu-image {
+ float: right;
+ width: 30px;
+}
+
+#adminmenu .wp-submenu a,
+#adminmenu li li a,
+.folded #adminmenu .wp-not-current-submenu li a {
+ padding-left: 0;
+ padding-right: 12px;
+}
+
+#adminmenu .wp-not-current-submenu li a {
+ padding-left: 0;
+ padding-right: 18px;
+}
+
+.wp-menu-arrow {
+ right: 0;
+
+ -moz-transform: translate( -139px );
+ -webkit-transform: translate( -139px );
+ -o-transform: translate( -139px );
+ -ms-transform: translate( -139px );
+ transform: translate( -139px );
+}
+
+.ie8 .wp-menu-arrow {
+ right: -20px;
+}
+
+#adminmenu .wp-menu-arrow div {
+ left: -8px;
+ width: 16px;
+}
+
+#adminmenu li.wp-not-current-submenu .wp-menu-arrow {
+ -moz-transform: translate( -138px );
+ -webkit-transform: translate( -138px );
+ -o-transform: translate( -138px );
+ -ms-transform: translate( -138px );
+ transform: translate( -138px );
+}
+
+.folded #adminmenu li .wp-menu-arrow {
+ -moz-transform: translate( -26px );
+ -webkit-transform: translate( -26px );
+ -o-transform: translate( -26px );
+ -ms-transform: translate( -26px );
+ transform: translate( -26px );
+}
+
+#adminmenu .wp-not-current-submenu .wp-menu-arrow div {
+ border-style: solid solid none none;
+ border-width: 1px 1px 0 0;
+}
+
+#adminmenu .wp-menu-image img {
+ padding: 7px 7px 0 0;
+}
+
+#adminmenu .wp-submenu .wp-submenu-head {
+ padding: 5px 10px 5px 4px;
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 3px;
+}
+
+.folded #adminmenu li.wp-has-current-submenu .wp-submenu {
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 3px;
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-top-left-radius: 3px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 3px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 3px;
+}
+
+#adminmenu .awaiting-mod,
+#adminmenu span.update-plugins,
+#sidemenu li a span.update-plugins {
+ font-family: Tahoma, Arial, sans-serif;
+ margin-left: 0;
+ margin-right: 7px;
+}
+
+#collapse-button {
+ float: right;
+}
+
+/* Auto-folding of the admin menu */
+@media only screen and (max-width: 900px) {
+ .auto-fold #wpcontent {
+ margin-left: 0;
+ margin-right: 52px;
+ }
+
+ .auto-fold.wp-admin #wpfooter {
+ margin-left: 15px;
+ margin-right: 52px;
+ }
+
+ .auto-fold #adminmenu div.wp-menu-image {
+ float: right;
+ width: 30px;
+ }
+
+ .auto-fold #adminmenu .wp-submenu.sub-open,
+ .auto-fold #adminmenu .opensub .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu .wp-submenu.sub-open,
+ .auto-fold #adminmenu .wp-has-current-submenu.opensub .wp-submenu,
+ .auto-fold #adminmenu a.menu-top:focus + .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu,
+ .no-js.auto-fold #adminmenu .wp-has-submenu:hover .wp-submenu {
+ left: auto;
+ right: 32px;
+ }
+
+ .auto-fold #adminmenu .wp-not-current-submenu li a {
+ padding-left: 0;
+ padding-right: 12px;
+ }
+
+ .auto-fold #adminmenu li .wp-menu-arrow {
+ -moz-transform: translate( -27px );
+ -webkit-transform: translate( -27px );
+ -o-transform: translate( -27px );
+ -ms-transform: translate( -27px );
+ transform: translate( -27px );
+ }
+
+ .auto-fold #adminmenu li.wp-has-current-submenu .wp-submenu {
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 3px;
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-top-left-radius: 3px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 3px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 3px;
+ }
+}
+
+/* List table styles */
+.post-com-count-wrapper {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.post-com-count {
+ background-image: url('../images/bubble_bg-rtl.gif');
+}
+
+.column-response .post-com-count {
+ float: right;
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+.response-links {
+ float: right;
+}
+
+
+/*------------------------------------------------------------------------------
+ 8.0 - Layout Blocks
+------------------------------------------------------------------------------*/
+
+.widefat th {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.postbox-container {
+ float: right;
+}
+
+#post-body-content {
+ float: right;
+}
+
+#poststuff #post-body.columns-2 {
+ margin-left: 300px;
+ margin-right: 0;
+}
+
+#post-body.columns-2 #postbox-container-1 {
+ float: left;
+ margin-left: -300px;
+ margin-right: 0;
+}
+
+@media only screen and (max-width: 850px) {
+ #wpbody-content #post-body.columns-2 #postbox-container-1 {
+ margin-left: 0;
+ }
+}
+
+.postbox .handlediv {
+ float: left;
+}
+
+/*------------------------------------------------------------------------------
+ 9.0 - Dashboard
+------------------------------------------------------------------------------*/
+
+#the-comment-list p.comment-author img {
+ float: right;
+ margin-right: 0;
+ margin-left: 8px;
+}
+
+/* Browser Nag */
+#dashboard_browser_nag p.browser-update-nag.has-browser-icon {
+ padding-right: 0;
+ padding-left: 125px;
+}
+
+/* Welcome Panel */
+.welcome-panel .welcome-panel-close {
+ right: auto;
+ left: 10px;
+}
+
+.welcome-panel .welcome-panel-close:before {
+ left: auto;
+ right: -12px;
+}
+
+.welcome-panel-content {
+ margin-left: 0;
+ margin-right: 13px;
+}
+
+.welcome-panel .welcome-panel-column {
+ float: right;
+}
+
+.welcome-panel .welcome-panel-column ul {
+ margin-right: 0;
+ margin-left: 1em;
+}
+
+.welcome-panel .welcome-panel-column li {
+ padding-left: 0;
+ padding-right: 2px;
+}
+
+.welcome-panel .welcome-add-page {
+ background-position: right 2px;
+}
+
+.welcome-panel .welcome-edit-page {
+ background-position: right -90px;
+}
+
+.welcome-panel .welcome-learn-more {
+ background-position: right -136px;
+}
+
+.welcome-panel .welcome-comments {
+ background-position: right -182px;
+}
+
+.welcome-panel .welcome-view-site {
+ background-position: right -274px;
+}
+
+.welcome-panel .welcome-widgets-menus {
+ background-position: right -229px;
+ line-height: 14px;
+}
+
+.welcome-panel .welcome-write-blog {
+ background-position: right -44px;
+}
+
+.welcome-panel .welcome-icon {
+ padding: 2px 32px 8px 0;
+}
+
+@media screen and (max-width: 870px) {
+ .welcome-panel .welcome-panel-column li {
+ margin-right: 0;
+ margin-left: 13px;
+ }
+
+ .welcome-panel .welcome-icon {
+ padding-right: 25px;
+ padding-left: 0;
+ }
+}
+
+/*------------------------------------------------------------------------------
+ 10.0 - List Posts (/Pages/etc)
+------------------------------------------------------------------------------*/
+
+.fixed .column-comments {
+ text-align: right;
+}
+
+.fixed .column-comments .vers {
+ padding-left: 0;
+ padding-right: 3px;
+}
+
+.fixed .column-comments a {
+ float: right;
+}
+
+.fixed .column-menus {
+ text-align: right;
+}
+
+.sorting-indicator {
+ margin-left: 0;
+ margin-right: 7px;
+}
+
+tr.wp-locked .locked-indicator {
+ margin: -2px 6px 0 0;
+}
+
+th.sortable a span,
+th.sorted a span {
+ float: right;
+}
+
+/* Bulk Actions */
+
+.tablenav-pages a {
+ margin-right: 0;
+ margin-left: 1px;
+}
+.tablenav-pages .next-page {
+ margin-left: 0;
+ margin-right: 2px;
+}
+
+.tablenav a.button-secondary {
+ margin: 3px 0 0 8px;
+}
+
+.tablenav .tablenav-pages {
+ float: left;
+}
+
+.tablenav .displaying-num {
+ margin-right: 0;
+ margin-left: 10px;
+ font-family: Tahoma, Arial, sans-serif;
+ font-style: normal;
+}
+
+.tablenav .actions {
+ padding: 2px 0 0 8px;
+}
+
+.tablenav .actions select {
+ float: right;
+ margin-right: 0;
+ margin-left: 6px;
+}
+
+.tablenav .delete {
+ margin-right: 0;
+ margin-left: 20px;
+}
+
+.view-switch {
+ float: left;
+}
+
+.filter {
+ float: right;
+ margin: -5px 10px 0 0;
+}
+
+.filter .subsubsub {
+ margin-left: 0;
+ margin-right: -10px;
+}
+
+#posts-filter fieldset {
+ float: right;
+ margin: 0 0 1em 1.5ex;
+}
+
+#posts-filter fieldset legend {
+ padding: 0 1px .2em 0;
+}
+
+/*------------------------------------------------------------------------------
+ 10.1 - Inline Editing
+------------------------------------------------------------------------------*/
+
+#wpbody-content .inline-edit-row fieldset {
+ float: right;
+}
+
+#wpbody-content .quick-edit-row-page fieldset.inline-edit-col-right .inline-edit-col {
+ border-width: 0 1px 0 0;
+}
+
+#wpbody-content .bulk-edit-row .inline-edit-col-bottom {
+ float: left;
+}
+
+.inline-edit-row fieldset label span.title {
+ float: right;
+}
+
+.inline-edit-row fieldset label span.input-text-wrap {
+ margin-left: 0;
+ margin-right: 5em;
+}
+
+.quick-edit-row-post fieldset.inline-edit-col-right label span.title {
+ padding-right: 0;
+ padding-left: 0.5em;
+}
+
+#wpbody-content .quick-edit-row fieldset .inline-edit-group label.alignleft:first-child {
+ margin-right: 0;
+ margin-left: 0.5em
+}
+
+/* Styling */
+
+.inline-edit-row fieldset span.title,
+.inline-edit-row fieldset span.checkbox-title {
+ font-family: Tahoma, Arial, sans-serif;
+ font-style: normal;
+}
+
+.inline-edit-row fieldset .inline-edit-date {
+ float: right;
+}
+
+.inline-edit-row fieldset ul.cat-checklist label,
+.inline-edit-row #bulk-titles div {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.quick-edit-row-post fieldset label.inline-edit-status {
+ float: right;
+}
+
+#bulk-titles div a {
+ float: right;
+ margin: 3px -2px 0 3px;
+ overflow: hidden;
+ text-indent: -9999px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 11.0 - Write/Edit Post Screen
+------------------------------------------------------------------------------*/
+
+#save-action .spinner,
+#show-comments a,
+#show-comments .spinner {
+ float: right;
+}
+
+#titlediv #title-prompt-text,
+#wp-fullscreen-title-prompt-text {
+ right: 0;
+}
+
+#sample-permalink {
+ direction: ltr;
+}
+
+#sample-permalink #editable-post-name {
+ unicode-bidi: embed;
+}
+
+#wp-fullscreen-title-prompt-text {
+ left: auto;
+ right: 0;
+}
+
+#wp-fullscreen-save .spinner,
+#wp-fullscreen-save .fs-saved {
+ float: left;
+}
+
+#edit-slug-box .cancel {
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+.postarea h3 label {
+ float: right;
+}
+
+.submitbox .submit {
+ text-align: right;
+}
+
+.inside-submitbox #post_status {
+ margin: 2px -2px 2px 0;
+}
+
+.submitbox .submit input {
+ margin-right: 0;
+ margin-left: 4px;
+}
+
+#normal-sortables .postbox .submit {
+ float: left;
+}
+
+.taxonomy div.tabs-panel {
+ margin: 0 125px 0 5px;
+}
+
+#side-sortables .comments-box thead th,
+#normal-sortables .comments-box thead th {
+ font-style: normal;
+}
+
+#commentsdiv .spinner {
+ padding-left: 0;
+ padding-right: 5px;
+}
+
+#post-body .add-menu-item-tabs li.tabs {
+ border-width: 1px 1px 1px 0;
+ margin-right: 0;
+ margin-left: -1px;
+}
+
+/* Global classes */
+
+#post-body .tagsdiv #newtag {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+.autosave-info {
+ padding: 2px 2px 2px 15px;
+ text-align: left;
+}
+
+#post-body .wp_themeSkin .mceStatusbar a.mceResize {
+ background: transparent url('../images/resize-rtl.gif') no-repeat scroll left bottom;
+ cursor: sw-resize;
+}
+
+.curtime #timestamp {
+ background-position: right top;
+ padding-left: 0;
+ padding-right: 18px;
+}
+
+.compat-attachment-fields th {
+ padding-right: 0;
+ padding-left: 10px;
+}
+
+#post-lock-dialog .post-locked-message a.button {
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+#post-lock-dialog .post-locked-avatar {
+ float: right;
+ margin: 0 0 20px 20px;
+}
+
+#post-lock-dialog .locked-saving img {
+ float: right;
+ margin-right: 0;
+ margin-left: 3px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 11.1 - Custom Fields
+------------------------------------------------------------------------------*/
+
+/* No RTL for now, this space intentionally left blank */
+
+/*------------------------------------------------------------------------------
+ 11.2 - Post Revisions
+------------------------------------------------------------------------------*/
+.wp-slider .ui-slider-handle.from-handle:before,
+.wp-slider .ui-slider-handle.to-handle:before {
+ height: 8px;
+ width: 7px;
+}
+
+.wp-slider .ui-slider-handle.from-handle:before {
+ background-position: -5px -10px;
+ left: 6px;
+}
+
+.wp-slider .ui-slider-handle.to-handle:before {
+ background-position: -4px -29px;
+ left: 6px;
+}
+
+.revision-toggle-compare-mode {
+ right: auto;
+ left: 0;
+}
+
+.revisions .loading-indicator {
+ margin-right: -90px;
+}
+
+body.folded .revisions .loading-indicator {
+ margin-right: -32px;
+}
+
+.revisions-next {
+ float: left;
+}
+
+.revisions-previous {
+ float: right;
+}
+
+.diff-title strong {
+ text-align: left;
+ float: right;
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+.revisions-controls .author-card .avatar,
+.revisions-controls .author-card .author-info {
+ float: right;
+}
+
+.diff-meta input.restore-revision {
+ float: left;
+}
+
+.diff-col-title-added,
+.diff-col-title-removed {
+ text-align: right;
+ float: right;
+}
+
+.revisions-tooltip {
+ margin-left: 0;
+ margin-right: -69px;
+}
+
+.revisions-tooltip.flipped {
+ margin-right: 0;
+ margin-left: -70px;
+}
+
+.ie8 .revisions-tooltip {
+ margin-right: -75px;
+}
+
+.ie8 .revisions-tooltip.flipped {
+ margin-left: -63px;
+}
+
+.revisions-tooltip-arrow {
+ right: 0;
+ margin-left: 0;
+ margin-right: 35px;
+}
+
+.revisions-tooltip.flipped .revisions-tooltip-arrow {
+ margin-right: 0;
+ margin-left: 35px;
+ right: auto;
+ left: 0;
+}
+
+.revisions-tooltip-arrow > span {
+ left: auto;
+ right: 20px;
+}
+
+.revisions-tooltip.flipped .revisions-tooltip-arrow > span {
+ right: auto;
+ left: 20px;
+}
+
+.ie8 .revisions-tooltip-arrow > span {
+ right: 21px;
+}
+
+.revisions-tickmarks > div {
+ float: right;
+ border-width: 0 0 0 1px;
+}
+
+/*------------------------------------------------------------------------------
+ 11.3 - Featured Images
+------------------------------------------------------------------------------*/
+
+#select-featured-image a {
+ float: right;
+}
+
+/*------------------------------------------------------------------------------
+ 11.4 - Post formats
+------------------------------------------------------------------------------*/
+
+a.post-state-format {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+label.post-format-icon {
+ margin-left: 0;
+ margin-right: 5px;
+ padding-left: 0px;
+ padding-right: 21px;
+}
+
+.post-format-icon.post-format-standard {
+ background-position: 100% 0;
+}
+
+.post-format-icon.post-format-image {
+ background-position: 100% -32px;
+}
+
+.post-format-icon.post-format-gallery {
+ background-position: 100% -64px;
+}
+
+.post-format-icon.post-format-audio {
+ background-position: 100% -96px;
+}
+
+.post-format-icon.post-format-video {
+ background-position: 100% -128px;
+}
+
+.post-format-icon.post-format-chat {
+ background-position: 100% -160px;
+}
+
+.post-format-icon.post-format-status {
+ background-position: 100% -192px;
+}
+
+.post-format-icon.post-format-aside {
+ background-position: 100% -224px;
+}
+
+.post-format-icon.post-format-quote {
+ background-position: 100% -256px;
+}
+
+.post-format-icon.post-format-link {
+ background-position: 100% -288px;
+}
+
+/*------------------------------------------------------------------------------
+ 12.0 - Categories
+------------------------------------------------------------------------------*/
+
+.category-adder {
+ margin-left: 0;
+ margin-right: 120px;
+}
+
+#post-body ul.add-menu-item-tabs {
+ float: right;
+ text-align: left;
+ /* Negative margin for the sake of those without JS: all tabs display */
+ margin: 0 5px 0 -120px;
+}
+
+#post-body ul.add-menu-item-tabs li.tabs {
+ -webkit-border-top-left-radius: 0;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-bottom-right-radius: 3px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 3px;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 3px;
+}
+
+#front-page-warning,
+#front-static-pages ul,
+ul.export-filters,
+.inline-editor ul.cat-checklist ul,
+.categorydiv ul.categorychecklist ul,
+.customlinkdiv ul.categorychecklist ul,
+.posttypediv ul.categorychecklist ul,
+.taxonomydiv ul.categorychecklist ul {
+ margin-left: 0;
+ margin-right: 18px;
+}
+
+#post-body .add-menu-item-tabs li.tabs {
+ border-style: solid solid solid none;
+ border-width: 1px 1px 1px 0;
+ margin-right: 0;
+ margin-left: -1px;
+}
+
+p.help,
+p.description,
+span.description,
+.form-wrap p {
+ font-style: normal;
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+/*------------------------------------------------------------------------------
+ 13.0 - Tags
+------------------------------------------------------------------------------*/
+
+.taghint {
+ margin: 15px 12px -24px 0;
+}
+
+#poststuff .tagsdiv .howto {
+ margin: 0 8px 6px 0;
+}
+
+.ac_results li {
+ text-align: right;
+}
+
+.links-table th {
+ text-align: right;
+}
+
+/*------------------------------------------------------------------------------
+ 14.0 - Media Screen
+------------------------------------------------------------------------------*/
+
+#wpbody-content .describe th {
+ text-align: right;
+
+}
+
+.describe .media-item-info .A1B1 {
+ padding: 0 10px 0 0;
+}
+
+.media-upload-form td label {
+ margin-left: 6px;
+ margin-right: 2px;
+}
+
+.media-upload-form .align .field label {
+ padding: 0 23px 0 0;
+ margin: 0 3px 0 1em;
+}
+
+.media-upload-form tr.image-size label {
+ margin: 0 5px 0 0;
+}
+
+#wpbody-content .describe p.help {
+ padding: 0 5px 0 0;
+}
+
+.media-item .edit-attachment,
+.media-item .error-div a.dismiss,
+.describe-toggle-on,
+.describe-toggle-off {
+ float: left;
+ margin-right: 0;
+ margin-left: 15px;
+}
+
+.media-item .error-div a.dismiss {
+ padding: 0 15px 0 0;
+}
+
+.media-item .error-div {
+ padding-left: 0;
+ padding-right: 10px;
+}
+
+.media-item .pinkynail {
+ float: right;
+}
+
+.media-item .describe td {
+ padding: 0 0 8px 8px;
+}
+
+.media-item .progress {
+ float: left;
+ margin: 6px 0 0 10px;
+}
+
+/*------------------------------------------------------------------------------
+ 14.1 - Media Uploader
+------------------------------------------------------------------------------*/
+
+#find-posts-input {
+ float: right;
+}
+
+#find-posts-search {
+ float: right;
+ margin-right: 3px;
+ margin-left: 4px;
+}
+
+.find-box-search .spinner {
+ left: auto;
+ right: 115px;
+}
+
+#find-posts-response .found-radio {
+ padding: 5px 8px 0 0;
+}
+
+.find-box-search label {
+ padding-right: 0;
+ padding-left: 6px;
+}
+
+.find-box #resize-se {
+ right: auto;
+ left: 1px;
+}
+
+form.upgrade .hint {
+ font-style: normal;
+}
+
+
+/*------------------------------------------------------------------------------
+ 14.2 - Image Editor
+------------------------------------------------------------------------------*/
+
+.wp_attachment_image .button,
+.A1B1 .button {
+ float: right;
+}
+
+.wp_attachment_image .spinner,
+.A1B1 .spinner {
+ float: right;
+}
+
+.imgedit-menu div {
+ float: right;
+}
+
+.imgedit-crop {
+ margin: 0;
+}
+
+.imgedit-rleft,
+.imgedit-flipv,
+.imgedit-undo {
+ margin: 0 8px 0 3px;
+}
+
+.imgedit-rright,
+.imgedit-fliph,
+.imgedit-redo {
+ margin: 0 3px;
+}
+
+.imgedit-applyto img {
+ margin: 0 0 0 8px;
+}
+
+.imgedit-help {
+ font-style: normal;
+}
+
+.imgedit-submit-btn {
+ margin-left: 0;
+ margin-right: 20px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 15.0 - Comments Screen
+------------------------------------------------------------------------------*/
+
+.form-table th {
+ text-align: right;
+}
+
+.form-table input.tog {
+ margin-right: 0;
+ margin-left: 2px;
+ float: right;
+}
+
+.form-table table.color-palette {
+ float: right;
+}
+
+/* reply to comments */
+
+#replysubmit .spinner,
+.inline-edit-save .spinner {
+ float: left;
+}
+
+#replysubmit .button {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+#edithead .inside {
+ float: right;
+ padding: 3px 5px 2px 0;
+}
+
+.comment-ays th {
+ border-right-style: none;
+ border-left-style: solid;
+ border-right-width: 0;
+ border-left-width: 1px;
+}
+
+.spam-undo-inside .avatar,
+.trash-undo-inside .avatar {
+ margin-left: 8px;
+}
+
+#comment-status-radio input {
+ margin: 2px 0 5px 3px;
+}
+
+/*------------------------------------------------------------------------------
+ 16.0 - Themes
+------------------------------------------------------------------------------*/
+
+h3.available-themes {
+ float: right;
+}
+
+.available-theme {
+ margin-right: 0;
+ margin-left: 10px;
+ padding: 20px 0 20px 20px;
+}
+
+#current-theme .theme-info li,
+.theme-options li,
+.available-theme .action-links li {
+ float: right;
+ padding-right: 0;
+ padding-left: 10px;
+ margin-right: 0;
+ margin-left: 10px;
+ border-right: none;
+ border-left: 1px solid #dfdfdf;
+}
+
+.available-theme .action-links li {
+ padding-left: 8px;
+ margin-left: 8px;
+}
+
+.ie8 .available-theme .action-links li {
+ padding-left: 7px;
+ margin-left: 7px;
+}
+
+#current-theme .theme-info li:last-child,
+.theme-options li:last-child,
+.available-theme .action-links li:last-child {
+ padding-left: 0;
+ margin-right: 0;
+ border-left: 0;
+}
+
+.available-theme .action-links .delete-theme {
+ float: left;
+ margin-left: 0;
+ margin-right: 8px;
+}
+
+.available-theme .action-links p {
+ float: right;
+}
+
+#current-theme.has-screenshot {
+ padding-left: 0;
+ padding-right: 330px;
+}
+
+#current-theme h4 span {
+ margin-left: 0;
+ margin-right: 20px;
+}
+
+#current-theme img {
+ float: right;
+ width: 300px;
+ margin-left: 0;
+ margin-right: -330px;
+}
+
+.theme-options .load-customize {
+ margin-right: 0;
+ margin-left: 30px;
+ float: right;
+}
+
+.theme-options span {
+ float: right;
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+.theme-options ul {
+ float: right;
+}
+
+/* Allow for three-up on 1024px wide screens, e.g. tablets */
+@media only screen and (max-width: 1200px) {
+ #current-theme.has-screenshot {
+ padding-right: 270px;
+ }
+
+ #current-theme img {
+ margin-right: -270px;
+ width: 240px;
+ }
+}
+
+#broken-themes {
+ text-align: right;
+}
+
+/*------------------------------------------------------------------------------
+ 16.1 - Custom Header Screen
+------------------------------------------------------------------------------*/
+
+.appearance_page_custom-header .available-headers .default-header {
+ float: right;
+ margin: 0 0 20px 20px;
+}
+
+.appearance_page_custom-header .random-header {
+ margin: 0 0 20px 20px;
+}
+
+.appearance_page_custom-header .available-headers label input,
+.appearance_page_custom-header .random-header label input {
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+/*------------------------------------------------------------------------------
+ 16.2 - Custom Background Screen
+------------------------------------------------------------------------------*/
+
+/* No RTL for now, this space intentionally left blank */
+
+
+/*------------------------------------------------------------------------------
+ 16.3 - Tabbed Admin Screen Interface (Experimental)
+------------------------------------------------------------------------------*/
+
+.nav-tab {
+ margin: 0 0 -1px 6px;
+}
+
+h2 .nav-tab {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+
+/*------------------------------------------------------------------------------
+ 17.0 - Plugins
+------------------------------------------------------------------------------*/
+
+.plugins .desc ul,
+.plugins .desc ol {
+ margin: 0 2em 0 0;
+}
+
+#wpbody-content .plugins .plugin-title, #wpbody-content .plugins .theme-title {
+ padding-right: 0;
+ padding-left: 12px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 18.0 - Users
+------------------------------------------------------------------------------*/
+
+#profile-page .form-table #rich_editing {
+ margin-right: 0;
+ margin-left: 5px
+}
+
+#profile-page #pass1,
+#profile-page #pass2,
+#profile-page #user_login {
+ direction: ltr;
+}
+
+#your-profile legend {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+/*------------------------------------------------------------------------------
+ 19.0 - Tools
+------------------------------------------------------------------------------*/
+
+.pressthis a span {
+ background-position: right 5px;
+ padding: 8px 27px 8px 11px;
+}
+
+.pressthis a:after {
+ right: auto;
+ left: 10px;
+ background: transparent;
+ transform: skew(-20deg) rotate(-6deg);
+ -webkit-transform: skew(-20deg) rotate(-6deg);
+ -moz-transform: skew(-20deg) rotate(-6deg);
+}
+
+
+.pressthis a:hover:after {
+ transform: skew(-20deg) rotate(-9deg);
+ -webkit-transform: skew(-20deg) rotate(-9deg);
+ -moz-transform: skew(-20deg) rotate(-9deg);
+}
+
+/*------------------------------------------------------------------------------
+ 20.0 - Settings
+------------------------------------------------------------------------------*/
+
+#utc-time, #local-time {
+ padding-left: 0;
+ padding-right: 25px;
+ font-style: normal;
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+#permalink_structure {
+ float: right;
+}
+
+.options-permalink-php code {
+ unicode-bidi: embed;
+}
+
+.options-permalink-php #rules {
+ direction: ltr;
+}
+
+/*------------------------------------------------------------------------------
+ 21.0 - Admin Footer
+------------------------------------------------------------------------------*/
+
+#wpfooter {
+ margin-left: 20px;
+}
+
+#wpcontent,
+#wpfooter {
+ margin-right: 165px;
+}
+
+/*------------------------------------------------------------------------------
+ 22.0 - About Pages
+------------------------------------------------------------------------------*/
+
+.wrap.about-wrap {
+ margin-left: 40px;
+ margin-right: 20px;
+}
+
+.about-wrap h1,
+.about-text {
+ margin-right: 0;
+ margin-left: 200px;
+}
+
+.about-wrap h2.nav-tab-wrapper {
+ padding-left: 0px;
+ padding-right: 6px;
+}
+
+.about-wrap .wp-badge {
+ right: auto;
+ left: 0;
+}
+
+.about-wrap h2 .nav-tab {
+ margin-right: 0;
+ margin-left: 3px;
+}
+
+.about-wrap .changelog li {
+ margin-left: 0;
+ margin-right: 3em;
+}
+
+.about-wrap .three-col-images .last-feature {
+ float: left;
+}
+
+.about-wrap .three-col-images .first-feature {
+ float: right;
+}
+
+.about-wrap .feature-section.three-col div {
+ margin-right: 0;
+ margin-left: 4.999999999%;
+ float: right;
+}
+
+.about-wrap .feature-section.three-col h4 {
+ text-align: right;
+}
+
+.about-wrap .feature-section.three-col img {
+ margin-right: 5px;
+ margin-left: 0;
+}
+
+.about-wrap .feature-section.three-col .last-feature {
+ margin-left: 0;
+}
+
+.about-wrap .feature-section img {
+ margin: 0 0 10px 0.7%;
+}
+
+.about-wrap .feature-section.images-stagger-right img,
+.about-wrap .feature-section.images-stagger-right .video {
+ float: left;
+ margin: 0 2em 12px 5px;
+}
+
+.about-wrap .feature-section.images-stagger-left img {
+ float: right;
+ margin: 0 5px 12px 2em;
+}
+
+.about-wrap li.wp-person,
+.about-wrap li.wp-person img.gravatar {
+ float: right;
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+@media only screen and (max-width: 900px) {
+ .about-wrap .feature-section.images-stagger-right .video.image-66 {
+ margin-right: 3px;
+ }
+}
+
+@media only screen and (max-width: 768px) {
+ .about-wrap .feature-section .image-66 {
+ float: none;
+ }
+
+ .about-wrap .feature-section.images-stagger-right .image-66 {
+ margin-right: 3px;
+ }
+
+ .about-wrap .feature-section.images-stagger-left .image-66 {
+ margin-left: 3px;
+ }
+}
+
+/*------------------------------------------------------------------------------
+ 23.0 - Misc
+------------------------------------------------------------------------------*/
+
+#template div {
+ margin-right: 0;
+ margin-left: 190px;
+}
+
+.column-author img, .column-username img {
+ float: right;
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+.tagchecklist {
+ margin-left: 0;
+ margin-right: 14px;
+}
+
+.tagchecklist strong {
+ margin-left: 0;
+ margin-right: -8px;
+}
+
+.tagchecklist span {
+ margin-right: 0;
+ margin-left: 25px;
+ float: right;
+
+}
+.tagchecklist span a {
+ margin: 6px -9px 0pt 0pt;
+ float: right;
+}
+
+#poststuff h2 {
+ clear: right;
+}
+
+#poststuff h3,
+.metabox-holder h3 {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.tool-box .title {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+#sidemenu {
+ margin: -30px 315px 0 15px;
+ float: left;
+ padding-left: 0;
+ padding-right: 10px;
+}
+#sidemenu a {
+ float: right;
+}
+
+table .vers,
+table .column-visible,
+table .column-rating {
+ text-align: right;
+}
+
+.screen-meta-toggle {
+ right: auto;
+ left: 15px;
+}
+
+.screen-reader-text,
+.screen-reader-text span,
+.ui-helper-hidden-accessible {
+ left: auto;
+ right: -1000em;
+}
+
+.screen-reader-shortcut:focus {
+ left: auto;
+ right: 6px;
+}
+
+/*------------------------------------------------------------------------------
+ 24.0 - Dead
+------------------------------------------------------------------------------*/
+
+/* - Not used anywhere in WordPress - verify and then deprecate
+------------------------------------------------------------------------------*/
+
+/* No RTL for now, this space intentionally left blank */
+
+
+/* - Only used once or twice in all of WP - deprecate for global style
+------------------------------------------------------------------------------*/
+
+* html #template div {margin-left: 0;}
+
+/* - Used - but could/should be deprecated with a CSS reset
+------------------------------------------------------------------------------*/
+/* No RTL for now, this space intentionally left blank */
+
+
+/*------------------------------------------------------------------------------
+ 25.0 - TinyMCE tweaks
+ Small tweaks for until tinymce css files are proprely RTLized
+------------------------------------------------------------------------------*/
+#editorcontainer .wp_themeSkin .mceStatusbar {
+ padding-left: 0;
+ padding-right: 5px;
+}
+
+#editorcontainer .wp_themeSkin .mceStatusbar div {
+ float: right;
+}
+
+#editorcontainer .wp_themeSkin .mceStatusbar a.mceResize {
+ float: left;
+}
+
+#content-resize-handle {
+ background: transparent url('../images/resize-rtl.gif') no-repeat scroll left bottom;
+ right: auto;
+ left: 2px;
+ cursor: sw-resize;
+}
+
+/*------------------------------------------------------------------------------
+ 26.0 - Full Overlay w/ Sidebar
+------------------------------------------------------------------------------*/
+.wp-full-overlay .wp-full-overlay-sidebar {
+ margin: 0;
+ left: auto;
+ right: 0;
+ border-right: 0;
+ border-left: 1px solid rgba( 0, 0, 0, 0.2 );
+}
+
+.wp-full-overlay-sidebar:after {
+ right: auto;
+ left: 0;
+ box-shadow: inset 5px 0 4px -4px rgba(0, 0, 0, 0.1);
+}
+
+.wp-full-overlay.collapsed,
+.wp-full-overlay.expanded .wp-full-overlay-sidebar {
+ margin-right: 0 !important;
+}
+
+.wp-full-overlay.expanded {
+ margin-right: 300px;
+ margin-left: 0;
+}
+
+.wp-full-overlay.collapsed .wp-full-overlay-sidebar {
+ margin-right: -300px;
+ margin-left: 0;
+}
+
+/* Collapse Button */
+.wp-full-overlay a.collapse-sidebar {
+ left: auto;
+ right: 0;
+ margin-left: 0;
+ margin-right: 15px;
+}
+
+.wp-full-overlay.collapsed .collapse-sidebar {
+ right: 100%;
+}
+
+.wp-full-overlay .collapse-sidebar-arrow {
+ margin-right: 2px;
+ margin-left: 0;
+ background: transparent url('../images/arrows.png') no-repeat 1px -108px;
+}
+
+.wp-full-overlay.collapsed .collapse-sidebar-arrow {
+ background-position: 0 -72px;
+}
+
+.wp-full-overlay .collapse-sidebar-label {
+ right: 100%;
+ left: auto;
+ margin-right: 10px;
+ margin-left: 0;
+}
+
+/*------------------------------------------------------------------------------
+ 27.0 - Customize Loader
+------------------------------------------------------------------------------*/
+.install-theme-info .theme-install {
+ float: left;
+}
+
+/* MERGED */
+
+/* global */
+
+/* 2 column liquid layout */
+
+#wpcontent {
+ margin-left: 0;
+ margin-right: 165px;
+}
+
+#wpbody-content {
+ float: right;
+}
+
+#adminmenuwrap {
+ float: right;
+}
+
+#adminmenu {
+ clear: right;
+}
+
+/* inner 2 column liquid layout */
+.inner-sidebar {
+ float: left;
+ clear: left;
+}
+
+.has-right-sidebar #post-body {
+ float: right;
+ clear: right;
+ margin-right: 0;
+ margin-left: -340px;
+}
+
+.has-right-sidebar #post-body-content {
+ margin-right: 0;
+ margin-left: 300px;
+}
+
+/* 2 columns main area */
+
+#col-right {
+ float: left;
+ clear: left;
+}
+
+/* utility classes*/
+.alignleft {
+ float: right;
+}
+
+.alignright {
+ float: left;
+}
+
+.textleft {
+ text-align: right;
+}
+
+.textright {
+ text-align: left;
+}
+
+/* styles for use by people extending the WordPress interface */
+
+body,
+td,
+textarea,
+input,
+select {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+ul.ul-disc,
+ul.ul-square,
+ol.ol-decimal {
+ margin-left: 0;
+ margin-right: 1.8em;
+}
+
+.subsubsub {
+ float: right;
+}
+
+.widefat thead th:first-of-type {
+ -webkit-border-top-left-radius: 0;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 3px;
+}
+
+.widefat thead th:last-of-type {
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 3px;
+}
+.widefat tfoot th:first-of-type {
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 3px;
+}
+.widefat tfoot th:last-of-type {
+ -webkit-border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 3px;
+}
+
+.widefat th {
+ text-align: right;
+}
+
+.widefat th input {
+ margin: 0 8px 0 0;
+}
+
+.wrap {
+ margin-right: 0;
+ margin-left: 15px;
+}
+
+.wrap h2,
+.subtitle {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.wrap h2 {
+ padding-right: 0;
+ padding-left: 15px;
+}
+
+.subtitle {
+ padding-left: 0;
+ padding-right: 25px;
+}
+
+.wrap .add-new-h2 {
+ font-family: Tahoma, Arial, sans-serif;
+ margin-left: 0;
+ margin-right: 4px;
+}
+
+.wrap h2.long-header {
+ padding-left: 0;
+}
+
+/* dashboard */
+#dashboard-widgets-wrap .has-sidebar {
+ margin-right: 0;
+ margin-left: -51%;
+}
+
+#dashboard-widgets-wrap .has-sidebar .has-sidebar-content {
+ margin-right: 0;
+ margin-left: 51%;
+}
+
+.view-all {
+ right: auto;
+ left: 0;
+}
+
+#dashboard_right_now p.sub,
+#dashboard-widgets h4,
+a.rsswidget,
+#dashboard_plugins h4,
+#dashboard_plugins h5,
+#dashboard_recent_comments .comment-meta .approve,
+#dashboard_right_now td.b,
+#dashboard_right_now .versions a {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+#dashboard_right_now p.sub {
+ left:auto;
+ right:15px;
+}
+
+#dashboard_right_now td.b {
+ padding-right: 0;
+ padding-left: 6px;
+ text-align: left;
+}
+
+#dashboard_right_now .t {
+ padding-right: 0;
+ padding-left: 12px;
+}
+
+#dashboard_right_now .table_content {
+ float:right;
+}
+
+#dashboard_right_now .table_discussion {
+ float:left;
+}
+
+#dashboard_right_now a.button {
+ float: left;
+ clear: left;
+}
+
+#dashboard_plugins .inside span {
+ padding-left: 0;
+ padding-right: 5px;
+}
+
+#dashboard-widgets h3 .postbox-title-action {
+ right: auto;
+ left: 10px;
+}
+
+.js #dashboard-widgets h3 .postbox-title-action {
+ right: auto;
+ left: 30px;
+}
+
+#the-comment-list .pingback {
+ padding-left: 0 !important;
+ padding-right: 9px !important;
+}
+
+/* Recent Comments */
+#the-comment-list .comment-item {
+ padding: 1em 70px 1em 10px;
+}
+
+#the-comment-list .comment-item .avatar {
+ float: right;
+ margin-left: 0;
+ margin-right: -60px;
+}
+
+/* Feeds */
+.rss-widget cite {
+ text-align: left;
+}
+
+.rss-widget span.rss-date {
+ font-family: Tahoma, Arial, sans-serif;
+ margin-left: 0;
+ margin-right: 3px;
+}
+
+/* QuickPress */
+#dashboard-widgets #dashboard_quick_press form p.submit input {
+ float: right;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit #save-post {
+ margin: 0 1px 0 0.7em;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit #publish {
+ float: left;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit .spinner {
+ margin: 4px 0 0 6px;
+}
+
+/* Recent Drafts */
+#dashboard_recent_drafts h4 abbr {
+ font-family: Tahoma, Arial, sans-serif;
+ margin-left:0;
+ margin-right: 3px;
+}
+
+/* login */
+body.login {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.login form {
+ margin-right: 8px;
+ margin-left: 0;
+}
+
+.login form .forgetmenot {
+ float: right;
+}
+
+.login form .submit {
+ float: left;
+}
+
+#login form .submit input {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.login #nav,
+.login #backtoblog {
+ margin: 0 16px 0 0;
+}
+
+#login_error,
+.login .message {
+ margin: 0 8px 16px 0;
+}
+
+.login #user_pass,
+.login #user_login,
+.login #user_email {
+ margin-left: 6px;
+ margin-right: 0;
+ direction: ltr;
+}
+
+.login h1 a {
+ text-decoration: none;
+}
+
+.login .button-primary {
+ float: left;
+}
+
+/* nav-menu */
+#nav-menus-frame {
+ margin-right: 300px;
+ margin-left: 0;
+}
+
+#wpbody-content #menu-settings-column {
+ margin-right: -300px;
+ margin-left: 0;
+ float: right;
+}
+
+.menu-location-menus select {
+ float: right;
+}
+
+.locations-row-links {
+ float: right;
+ margin: 4px 6px 0 0;
+}
+
+.locations-add-menu-link {
+ direction: rtl;
+}
+
+.locations-edit-menu-link {
+ border-left: 1px solid #CCCCCC;
+ border-right: 0;
+ padding-left: 6px;
+ padding-right: 0;
+ float: right;
+}
+
+/* Menu Container */
+#menu-management-liquid {
+ float: right;
+}
+
+#menu-management {
+ margin-left: 20px;
+ margin-right: 0;
+}
+
+.post-body-plain {
+ padding: 10px 0 0 10px;
+}
+
+/* Menu Tabs */
+
+#menu-management .nav-tabs-arrow-left {
+ right: 0;
+ left:auto;
+}
+
+#menu-management .nav-tabs-arrow-right {
+ left: 0;
+ right:auto;
+ text-align: left;
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+#menu-management .nav-tabs {
+ padding-right: 20px;
+ padding-left: 10px;
+}
+
+.js #menu-management .nav-tabs {
+ float: right;
+ margin-right: 0px;
+ margin-left: -400px;
+}
+
+#select-nav-menu-container {
+ text-align: left;
+}
+
+#wpbody .open-label {
+ float:right;
+}
+
+#wpbody .open-label span {
+ padding-left: 10px;
+ padding-right:0;
+}
+
+.js .input-with-default-title {
+ font-style: normal;
+ font-weight: bold;
+}
+
+/* Add Menu Item Boxes */
+.postbox .howto input,
+.accordion-container .howto input {
+ float: left;
+}
+
+#nav-menu-theme-locations .button-controls {
+ text-align: left;
+}
+
+/* Button Primary Actions */
+
+.meta-sep,
+.submitcancel {
+ float: right;
+}
+
+#cancel-save {
+ margin-left: 0;
+ margin-right: 20px;
+}
+
+.button.right, .button-secondary.right, .button-primary.right {
+ float: left;
+}
+
+/* Button Secondary Actions */
+.list-controls {
+ float: right;
+}
+.add-to-menu {
+ float: left;
+}
+
+/* Custom Links */
+#add-custom-link label span {
+ float: right;
+ padding-left: 5px;
+ padding-right: 0;
+}
+
+.nav-menus-php .howto span {
+ float: right;
+}
+
+.list li .menu-item-title input {
+ margin-left: 3px;
+ margin-right: 0;
+}
+
+/* Nav Menu */
+.menu-item-handle {
+ padding-right: 10px;
+ padding-left: 0;
+}
+.menu-item-edit-active .menu-item-handle {
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.menu-item-handle .item-title {
+ margin-left:13em;
+ margin-right:0;
+ overflow: hidden;
+}
+.menu-item-handle .item-edit {
+ right: auto;
+ left: -20px;
+}
+
+.menu-item-handle .menu-item-title {
+ float: right;
+}
+
+.menu-item-settings .field-move a,
+.menu-item-settings .field-move span {
+ float: right;
+ margin-left: 4px;
+}
+
+/* WARNING: The factor of 30px is hardcoded into the nav-menus javascript. */
+.menu-item-depth-0 { margin-right: 0px; margin-left:0;}
+.menu-item-depth-1 { margin-right: 30px; margin-left:0;}
+.menu-item-depth-2 { margin-right: 60px; margin-left:0;}
+.menu-item-depth-3 { margin-right: 90px; margin-left:0;}
+.menu-item-depth-4 { margin-right: 120px; margin-left:0;}
+.menu-item-depth-5 { margin-right: 150px; margin-left:0;}
+.menu-item-depth-6 { margin-right: 180px; margin-left:0;}
+.menu-item-depth-7 { margin-right: 210px; margin-left:0;}
+.menu-item-depth-8 { margin-right: 240px; margin-left:0;}
+.menu-item-depth-9 { margin-right: 270px; margin-left:0;}
+.menu-item-depth-10 { margin-right: 300px; margin-left:0;}
+.menu-item-depth-11 { margin-right: 330px; margin-left:0;}
+
+.menu-item-depth-0 .menu-item-transport { margin-right: 0px; margin-left:0;}
+.menu-item-depth-1 .menu-item-transport { margin-right: -30px; margin-left:0;}
+.menu-item-depth-2 .menu-item-transport { margin-right: -60px; margin-left:0;}
+.menu-item-depth-3 .menu-item-transport { margin-right: -90px; margin-left:0;}
+.menu-item-depth-4 .menu-item-transport { margin-right: -120px; margin-left:0;}
+.menu-item-depth-5 .menu-item-transport { margin-right: -150px; margin-left:0;}
+.menu-item-depth-6 .menu-item-transport { margin-right: -180px; margin-left:0;}
+.menu-item-depth-7 .menu-item-transport { margin-right: -210px; margin-left:0;}
+.menu-item-depth-8 .menu-item-transport { margin-right: -240px; margin-left:0;}
+.menu-item-depth-9 .menu-item-transport { margin-right: -270px; margin-left:0;}
+.menu-item-depth-10 .menu-item-transport { margin-right: -300px; margin-left:0;}
+.menu-item-depth-11 .menu-item-transport { margin-right: -330px; margin-left:0;}
+
+/* Menu item controls */
+.item-type {
+ padding-left: 10px;
+ padding-right:0;
+}
+
+.item-controls {
+ left: 20px;
+ right: auto;
+}
+
+.item-controls .item-order {
+ padding-left: 10px;
+ padding-right: 0;
+}
+
+.item-edit {
+ left: -20px;
+ right:auto;
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 0;
+}
+
+/* Menu editing */
+.menu-item-settings {
+ padding: 10px 10px 10px 0;
+ border-width: 0 1px 1px 1px;
+}
+
+#custom-menu-item-url {
+ direction: ltr;
+}
+
+.link-to-original {
+ font-style: normal;
+ font-weight: bold;
+}
+
+.link-to-original a {
+ padding-right: 4px;
+ padding-left:0;
+}
+
+.menu-item-settings .description-thin,
+.menu-item-settings .description-wide {
+ margin-left: 10px;
+ margin-right:0;
+ float: right;
+}
+
+/* Major/minor publishing actions (classes) */
+.major-publishing-actions .publishing-action {
+ text-align: left;
+ float: left;
+}
+
+.major-publishing-actions .delete-action {
+ text-align: right;
+ float: right;
+ padding-left: 15px;
+ padding-right:0;
+}
+
+.menu-name-label {
+ margin-left: 15px;
+ margin-right:0;
+}
+
+/* Star ratings */
+div.star-holder {
+ background: url('../images/stars-rtl.png?ver=20121108') repeat-x bottom right;
+}
+div.star-holder .star-rating {
+ background: url('../images/stars-rtl.png?ver=20121108') repeat-x top right;
+ float: right;
+}
+
+#plugin-information .wrap {
+ margin: 4px 15px 0 0;
+}
+
+#plugin-information ul#sidemenu {
+ left: auto;
+ right: 0;
+}
+
+#plugin-information .fyi {
+ float: right;
+}
+
+#plugin-information #section-screenshots li p {
+ padding-left: 0;
+ padding-right: 20px;
+}
+
+#plugin-information .updated,
+#plugin-information .error {
+ clear: none;
+ direction: rtl;
+}
+
+#plugin-information #section-holder .section {
+ direction: ltr;
+}
+
+/* Editor/Main Column */
+.posting {
+ margin-left: 212px;
+ margin-right: 0;
+ position: relative;
+}
+
+h3.tb {
+ margin-left: 0;
+ margin-right: 5px;
+}
+
+#publish {
+ float: left;
+}
+
+.postbox .handlediv {
+ float: left;
+}
+
+.actions li {
+ float: right;
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+#extra-fields .actions {
+ margin: -23px 0 0 -7px;
+}
+
+/* Photo Styles */
+#img_container a {
+ float: right;
+}
+
+#category-add input,
+#category-add select {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+/* Tags */
+#tagsdiv #newtag {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+#tagadd {
+ margin-left: 0;
+ margin-right: 3px;
+}
+
+#tagchecklist span {
+ margin-left: .5em;
+ margin-right: 10px;
+ float: right;
+}
+#tagchecklist span a {
+ margin: 6px -9px 0 0;
+ float: right;
+}
+
+.submit input,
+.button,
+.button-primary,
+.button-secondary,
+#postcustomstuff .submit input {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.ac_results li {
+ text-align: right;
+}
+
+#TB_ajaxContent #options {
+ right: auto;
+ left: 25px;
+}
+
+#TB_closeAjaxWindow {
+ float: left;
+}
+
+#TB_ajaxWindowTitle {
+ float: right;
+}
+
+#post_status {
+ margin-left: 0;
+ margin-right: 10px;
+}
+
+/* theme-editor, plugin-editor */
+#templateside {
+ float: left;
+}
+
+#template textarea,
+#docs-list {
+ direction: ltr;
+}
+
+/* theme-install */
+.theme-details .theme-version {
+ float: right;
+}
+
+.theme-details .star-holder {
+ float: left;
+}
+
+.feature-filter .feature-group {
+ float: right;
+}
+
+.feature-filter .feature-group li {
+ padding-right: 0;
+ padding-left: 25px;
+}
+
+/* widgets */
+/* 2 column liquid layout */
+div.widget-liquid-left {
+ float: right;
+ clear: right;
+ margin-right: 0;
+ margin-left: -325px;
+}
+
+div#widgets-left {
+ margin-right: 5px;
+ margin-left: 325px;
+}
+
+div.widget-liquid-right {
+ float: left;
+ clear: left;
+}
+
+.inactive-sidebar .widget {
+ float: right;
+}
+
+div.sidebar-name h3 {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+#widget-list .widget {
+ float: right;
+}
+
+.inactive-sidebar .widget-placeholder {
+ float: right;
+}
+
+.widget-top .widget-title-action {
+ float: left;
+}
+
+.widget-control-edit {
+ padding: 0 0 0 8px;
+}
+
+.sidebar-name-arrow {
+ float: left;
+}
+
+/* Press This */
+.press-this-sidebar {
+ float: left;
+}
+
+.press-this #header-logo,
+.press-this #wphead h1 {
+ float: right;
+}
+
+/* RTL */
+.ltr {
+ direction: ltr;
+}
+
+.control-section .accordion-section-title {
+ font-family: Tahoma, Arial, sans-serif;
+}
+
+.js .accordion-section-title:after {
+ right: auto;
+ left: 20px;
+}
+
+/*------------------------------------------------------------------------------
+ 28.0 - Nav Menus
+------------------------------------------------------------------------------*/
+.nav-menus-php .major-publishing-actions .publishing-action {
+ float: left;
+}
+
+.menu-settings dd {
+ float: right;
+}
+
+.manage-menus span {
+ float: right;
+}
+
+.manage-menus select {
+ float: right;
+ margin-right: 0;
+ margin-left: 6px;
+}
+
+.manage-menus .submit-btn {
+ float: right;
+}
+
+.manage-menus .selected-menu {
+ float: right;
+ margin: 5px 0 0 6px;
+}
+
+.nav-menus-php .add-new-menu-action {
+ float: right;
+ margin: 4px 6px 0 0;
+}
+
+.nav-menus-php .meta-sep,
+.nav-menus-php .submitdelete,
+.nav-menus-php .submitcancel {
+ float: right;
+}
+
+.is-submenu {
+ float: right;
+ margin-right: 8px;
+}
+
+/*------------------------------------------------------------------------------
+ 29.0 - HiDPI
+------------------------------------------------------------------------------*/
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ .post-com-count {
+ background-image: url('../images/bubble_bg-rtl-2x.gif');
+ background-size: 18px 100px;
+ }
+
+ #content-resize-handle, #post-body .wp_themeSkin .mceStatusbar a.mceResize {
+ background: transparent url('../images/resize-rtl-2x.gif') no-repeat scroll right bottom;
+ background-size: 11px 11px;
+ }
+
+ .wp-full-overlay .collapse-sidebar-arrow {
+ background-image: url('../images/arrows-2x.png');
+ background-size: 15px 123px;
+ }
+
+ div.star-holder {
+ background: url('../images/stars-rtl-2x.png?ver=20121108') repeat-x bottom right;
+ background-size: 21px 37px;
+ }
+
+ div.star-holder .star-rating {
+ background: url('../images/stars-rtl-2x.png?ver=20121108') repeat-x top right;
+ background-size: 21px 37px;
+ }
+
+ #post-body .wp_themeSkin .mceStatusbar a.mceResize,
+ #content-resize-handle {
+ background: transparent url('../images/resize-rtl-2x.gif') no-repeat scroll left bottom;
+ }
+
+ .wp-slider .ui-slider-handle:before {
+ background-image: url(../images/arrows-pr-2x.png);
+ background-size: 16px 102px;
+ }
+
+}
+
+/* =Localized CSS
+-------------------------------------------------------------- */
+
+/* he_IL: Remove Tahoma from the font stack. Arial is best for Hebrew. */
+body.locale-he-il,
+.locale-he-il .quicktags, .locale-he-il .search,
+.locale-he-il .howto,
+.locale-he-il #adminmenu .awaiting-mod,
+.locale-he-il #adminmenu span.update-plugins,
+.locale-he-il #sidemenu li a span.update-plugins,
+.locale-he-il .post-com-count-wrapper,
+.locale-he-il .widefat th,
+.locale-he-il .tablenav .displaying-num,
+.locale-he-il .inline-edit-row fieldset span.title,
+.locale-he-il .inline-edit-row fieldset span.checkbox-title,
+.locale-he-il .inline-edit-row fieldset ul.cat-checklist label,
+.locale-he-il .inline-edit-row #bulk-titles div,
+.locale-he-il p.help,
+.locale-he-il p.description,
+.locale-he-il span.description,
+.locale-he-il .form-wrap p,
+.locale-he-il h2 .nav-tab,
+.locale-he-il #your-profile legend,
+.locale-he-il #utc-time, .locale-he-il #local-time,
+.locale-he-il #poststuff h3,
+.locale-he-il .metabox-holder h3,
+.locale-he-il .tool-box .title,
+.locale-he-il td,
+.locale-he-il textarea,
+.locale-he-il input,
+.locale-he-il select,
+.locale-he-il .wrap h2,
+.locale-he-il .subtitle,
+.locale-he-il .wrap .add-new-h2,
+.locale-he-il #dashboard_right_now p.sub,
+.locale-he-il #dashboard-widgets h4,
+.locale-he-il a.rsswidget,
+.locale-he-il #dashboard_plugins h4,
+.locale-he-il #dashboard_plugins h5,
+.locale-he-il #dashboard_recent_comments .comment-meta .approve,
+.locale-he-il #dashboard_right_now td.b,
+.locale-he-il #dashboard_right_now .versions a,
+.locale-he-il .rss-widget span.rss-date,
+.locale-he-il #dashboard_recent_drafts h4 abbr,
+body.login.locale-he-il,
+.locale-he-il #login form .submit input,
+.locale-he-il #menu-management .nav-tabs-arrow-right,
+.locale-he-il #category-add input,
+.locale-he-il #category-add select,
+.locale-he-il .submit input,
+.locale-he-il .button,
+.locale-he-il .button-primary,
+.locale-he-il .button-secondary,
+.locale-he-il #postcustomstuff .submit input,
+.locale-he-il div.sidebar-name h3 {
+ font-family: Arial, sans-serif;
+}
+
+/* he_IL: Have <em> be bold rather than italic. */
+.locale-he-il em {
+ font-style: normal;
+ font-weight: bold;
+}
diff --git a/src/wp-admin/css/wp-admin.css b/src/wp-admin/css/wp-admin.css
new file mode 100644
index 0000000000..95c0482b48
--- /dev/null
+++ b/src/wp-admin/css/wp-admin.css
@@ -0,0 +1,9459 @@
+/*------------------------------------------------------------------------------
+
+
+Hello, this is the main WordPress admin CSS file.
+All the important stuff is in here.
+
+
+TABLE OF CONTENTS:
+------------------
+ 1.0 - Text Elements
+ 2.0 - Forms
+ 3.0 - Actions
+ 4.0 - Notifications
+ 5.0 - TinyMCE
+ 6.0 - Admin Header
+ 6.1 - Screen Options Tabs
+ 6.2 - Help Menu
+ 7.0 - Main Navigation
+ 8.0 - Layout Blocks
+ 9.0 - Dashboard
+10.0 - List Posts
+ 10.1 - Inline Editing
+11.0 - Write/Edit Post Screen
+ 11.1 - Custom Fields
+ 11.2 - Post Revisions
+ 11.3 - Featured Images
+ 11.4 - Post Format Selection
+12.0 - Categories
+13.0 - Tags
+14.0 - Media Screen
+ 14.1 - Media Library
+ 14.2 - Image Editor
+15.0 - Comments Screen
+16.0 - Themes
+ 16.1 - Custom Header
+ 16.2 - Custom Background
+ 16.3 - Tabbed Admin Screen Interface
+17.0 - Plugins
+18.0 - Users
+19.0 - Tools
+20.0 - Settings
+21.0 - Admin Footer
+22.0 - About Pages
+23.0 - Full Overlay w/ Sidebar
+24.0 - Customize Loader
+25.0 - Misc
+
+------------------------------------------------------------------------*/
+
+/* 2 column liquid layout */
+#wpwrap {
+ height: auto;
+ min-height: 100%;
+ width: 100%;
+ position: relative;
+}
+
+#wpcontent {
+ height: 100%;
+}
+
+#wpcontent,
+#wpfooter {
+ margin-left: 165px;
+}
+
+.folded #wpcontent,
+.folded #wpfooter {
+ margin-left: 52px;
+}
+
+#wpbody-content {
+ padding-bottom: 65px;
+ float: left;
+ width: 100%;
+}
+
+#adminmenuback,
+#adminmenuwrap,
+#adminmenu,
+#adminmenu .wp-submenu {
+ width: 145px;
+}
+
+#adminmenuback {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ z-index: -1;
+}
+
+#adminmenu {
+ clear: left;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.folded #adminmenuback,
+.folded #adminmenuwrap,
+.folded #adminmenu,
+.folded #adminmenu li.menu-top {
+ width: 32px;
+}
+
+/* inner 2 column liquid layout */
+
+.inner-sidebar {
+ float: right;
+ clear: right;
+ display: none;
+ width: 281px;
+ position: relative;
+}
+
+.columns-2 .inner-sidebar {
+ margin-right: auto;
+ width: 286px;
+ display: block;
+}
+
+.inner-sidebar #side-sortables,
+.columns-2 .inner-sidebar #side-sortables {
+ min-height: 300px;
+ width: 280px;
+ padding: 0;
+}
+
+.has-right-sidebar .inner-sidebar {
+ display: block;
+}
+
+.has-right-sidebar #post-body {
+ float: left;
+ clear: left;
+ width: 100%;
+ margin-right: -2000px;
+}
+
+.has-right-sidebar #post-body-content {
+ margin-right: 300px;
+ float: none;
+ width: auto;
+}
+
+/* 2 columns main area */
+
+#col-container,
+#col-left,
+#col-right {
+ overflow: hidden;
+ padding: 0;
+ margin: 0;
+}
+
+#col-left {
+ width: 35%;
+}
+
+#col-right {
+ float: right;
+ clear: right;
+ width: 65%;
+}
+
+.col-wrap {
+ padding: 0 7px;
+}
+
+/* utility classes */
+.alignleft {
+ float: left;
+}
+
+.alignright {
+ float: right;
+}
+
+.textleft {
+ text-align: left;
+}
+
+.textright {
+ text-align: right;
+}
+
+.clear {
+ clear: both;
+}
+
+/* Hide visually but not from screen readers */
+.screen-reader-text,
+.screen-reader-text span,
+.ui-helper-hidden-accessible {
+ position: absolute;
+ left: -1000em;
+ top: -1000em;
+ height: 1px;
+ width: 1px;
+ overflow: hidden;
+}
+
+.screen-reader-shortcut {
+ position: absolute;
+ top: -1000em;
+}
+
+.screen-reader-shortcut:focus {
+ left: 6px;
+ top: -21px;
+ height: auto;
+ width: auto;
+ display: block;
+ font-size: 14px;
+ font-weight: bold;
+ padding: 15px 23px 14px;
+ background: #f1f1f1;
+ color: #21759b;
+ border-radius: 3px;
+ z-index: 100000;
+ line-height: normal;
+ -webkit-box-shadow: 0 0 2px 2px rgba(0,0,0,.6);
+ box-shadow: 0 0 2px 2px rgba(0,0,0,.6);
+ text-decoration: none;
+}
+
+.hidden,
+.js .closed .inside,
+.js .hide-if-js,
+.no-js .hide-if-no-js,
+.js.wp-core-ui .hide-if-js,
+.js .wp-core-ui .hide-if-js,
+.no-js.wp-core-ui .hide-if-no-js,
+.no-js .wp-core-ui .hide-if-no-js {
+ display: none;
+}
+
+/* include margin and padding in the width calculation of input and textarea */
+input[type="text"],
+input[type="password"],
+input[type="number"],
+input[type="search"],
+input[type="email"],
+input[type="url"],
+textarea {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box; /* ie8 only */
+ box-sizing: border-box;
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ vertical-align: text-top;
+ padding: 0;
+ margin: 1px 0 0;
+}
+
+input[type="search"] {
+ -webkit-appearance: textfield;
+}
+
+input[type="search"]::-webkit-search-decoration {
+ display: none;
+}
+
+/* general */
+html,
+body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: sans-serif;
+ font-size: 12px;
+ line-height: 1.4em;
+ min-width: 600px;
+}
+
+body.iframe {
+ min-width: 0;
+ padding-top: 1px;
+}
+
+body.login {
+ background: #fbfbfb;
+ min-width: 0;
+}
+
+iframe,
+img {
+ border: 0;
+}
+
+td,
+textarea,
+input,
+select,
+button {
+ font-family: inherit;
+ font-size: inherit;
+ font-weight: inherit;
+}
+
+td,
+textarea {
+ line-height: inherit;
+}
+
+input,
+select {
+ line-height: 15px;
+}
+
+a,
+input[type="text"],
+input[type="password"],
+input[type="number"],
+input[type="search"],
+input[type="email"],
+input[type="url"],
+select,
+textarea,
+div {
+ outline: 0;
+}
+
+a:focus,
+a:active {
+ outline: thin dotted;
+}
+
+#adminmenu a:focus,
+#adminmenu a:active,
+.screen-reader-text:focus {
+ outline: none;
+}
+
+blockquote,
+q {
+ quotes: none;
+}
+
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+ content: '';
+ content: none;
+}
+
+p {
+ margin: 1em 0;
+}
+
+blockquote {
+ margin: 1em;
+}
+
+label {
+ cursor: pointer;
+}
+
+li,
+dd {
+ margin-bottom: 6px;
+}
+
+textarea,
+input,
+select {
+ margin: 1px;
+ padding: 3px;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ display: block;
+ font-weight: bold;
+}
+
+h1 {
+ font-size: 2em;
+ margin: .67em 0;
+}
+
+h2 {
+ font-size: 1.5em;
+ margin: .83em 0;
+}
+
+h3 {
+ font-size: 1.17em;
+ margin: 1em 0;
+}
+
+h4 {
+ font-size: 1em;
+ margin: 1.33em 0;
+}
+
+h5 {
+ font-size: 0.83em;
+ margin: 1.67em 0;
+}
+
+h6 {
+ font-size: 0.67em;
+ margin: 2.33em 0;
+}
+
+ul,
+ol {
+ padding: 0;
+}
+
+ul {
+ list-style: none;
+}
+
+ol {
+ list-style-type: decimal;
+ margin-left: 2em;
+}
+
+ul.ul-disc {
+ list-style: disc outside;
+}
+
+ul.ul-square {
+ list-style: square outside;
+}
+
+ol.ol-decimal {
+ list-style: decimal outside;
+}
+
+ul.ul-disc,
+ul.ul-square,
+ol.ol-decimal {
+ margin-left: 1.8em;
+}
+
+ul.ul-disc > li,
+ul.ul-square > li,
+ol.ol-decimal > li {
+ margin: 0 0 0.5em;
+}
+
+.code,
+code {
+ font-family: Consolas, Monaco, monospace;
+}
+
+kbd,
+code {
+ padding: 1px 3px;
+ margin: 0 1px;
+ font-size: 11px;
+}
+
+.subsubsub {
+ list-style: none;
+ margin: 8px 0 5px;
+ padding: 0;
+ font-size: 12px;
+ float: left;
+}
+
+.subsubsub a {
+ line-height: 2;
+ padding: .2em;
+ text-decoration: none;
+}
+
+.subsubsub a .count,
+.subsubsub a.current .count {
+ color: #999;
+ font-weight: normal;
+}
+
+.subsubsub a.current {
+ font-weight: bold;
+ border: none;
+}
+
+.subsubsub li {
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+
+.widefat,
+div.updated,
+div.error,
+.wrap .add-new-h2,
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="file"],
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="tel"],
+input[type="url"],
+select,
+.tablenav .tablenav-pages a,
+.tablenav-pages span.current,
+#titlediv #title,
+.postbox,
+#postcustomstuff table,
+#postcustomstuff input,
+#postcustomstuff textarea,
+.imgedit-menu div,
+.plugin-update-tr .update-message,
+#poststuff .inside .the-tagcloud,
+.login form,
+#login_error,
+.login .message,
+#menu-management .menu-edit,
+.nav-menus-php .list-container,
+.menu-item-handle,
+.link-to-original,
+.nav-menus-php .major-publishing-actions .form-invalid,
+.press-this #message,
+#TB_window,
+.tbtitle,
+.highlight,
+.feature-filter,
+#widget-list .widget-top,
+.editwidget .widget-inside {
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ border-width: 1px;
+ border-style: solid;
+}
+
+/* .widefat - main style for tables */
+.widefat {
+ border-spacing: 0;
+ width: 100%;
+ clear: both;
+ margin: 0;
+}
+
+.widefat * {
+ word-wrap: break-word;
+}
+
+.widefat a {
+ text-decoration: none;
+}
+
+.widefat thead th:first-of-type {
+ -webkit-border-top-left-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.widefat thead th:last-of-type {
+ -webkit-border-top-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+.widefat tfoot th:first-of-type {
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.widefat tfoot th:last-of-type {
+ -webkit-border-bottom-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+.widefat td,
+.widefat th {
+ border-width: 1px 0;
+ border-style: solid;
+}
+.widefat tfoot th {
+ border-bottom: none;
+}
+
+.widefat .no-items td {
+ border-bottom-width: 0;
+}
+
+.widefat td {
+ font-size: 12px;
+ padding: 4px 7px 2px;
+ vertical-align: top;
+}
+
+.widefat td p,
+.widefat td ol,
+.widefat td ul {
+ font-size: 12px;
+}
+
+.widefat th {
+ padding: 7px 7px 8px;
+ text-align: left;
+ line-height: 1.3em;
+ font-size: 14px;
+}
+
+.widefat th input {
+ margin: 0 0 0 8px;
+ padding: 0;
+ vertical-align: text-top;
+}
+
+.widefat .check-column {
+ width: 2.2em;
+ padding: 6px 0 25px;
+ vertical-align: top;
+}
+
+.widefat tbody th.check-column {
+ padding: 9px 0 22px;
+}
+
+.widefat.media .check-column {
+ padding-top: 8px;
+}
+
+.widefat thead .check-column,
+.widefat tfoot .check-column {
+ padding: 10px 0 0;
+}
+
+.no-js .widefat thead .check-column input,
+.no-js .widefat tfoot .check-column input {
+ display: none;
+}
+
+.widefat .num,
+.column-comments,
+.column-links,
+.column-posts {
+ text-align: center;
+}
+
+.widefat th#comments {
+ vertical-align: middle;
+}
+
+.wrap {
+ margin: 4px 15px 0 0;
+}
+
+div.updated,
+div.error {
+ padding: 0 0.6em;
+ margin: 5px 15px 2px;
+}
+
+div.updated p,
+div.error p {
+ margin: 0.5em 0;
+ padding: 2px;
+}
+
+.wrap div.updated,
+.wrap div.error,
+.media-upload-form div.error {
+ margin: 5px 0 15px;
+}
+
+.wrap h2,
+.subtitle {
+ font-weight: normal;
+ margin: 0;
+ text-shadow: #fff 0 1px 0;
+}
+
+.wrap h2 {
+ font-size: 23px;
+ padding: 9px 15px 4px 0;
+ line-height: 29px;
+}
+
+.subtitle {
+ font-size: 14px;
+ padding-left: 25px;
+}
+
+.wrap .add-new-h2 {
+ font-family: sans-serif;
+ margin-left: 4px;
+ padding: 3px 8px;
+ position: relative;
+ top: -3px;
+ text-decoration: none;
+ font-size: 12px;
+ border: 0 none;
+}
+
+.wrap h2.long-header {
+ padding-right: 0;
+}
+
+html,
+.wp-dialog {
+ background-color: #fff;
+}
+
+textarea,
+input[type="text"],
+input[type="password"],
+input[type="file"],
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="tel"],
+input[type="url"],
+select {
+ background-color: #fff;
+ color: #333;
+}
+
+select {
+ color: #000;
+}
+
+select[disabled] {
+ color: #7f7f7f;
+}
+
+select:focus {
+ border-color: #aaa;
+}
+
+textarea:focus,
+input[type="text"]:focus,
+input[type="password"]:focus,
+input[type="file"]:focus,
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+select:focus {
+ -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
+ box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
+}
+
+input[readonly] {
+ background-color: #eee;
+}
+
+:-moz-placeholder,
+.wp-core-ui :-moz-placeholder {
+ color: #a9a9a9;
+}
+
+/*------------------------------------------------------------------------------
+ 1.0 - Text Styles
+------------------------------------------------------------------------------*/
+
+div.sidebar-name h3,
+#menu-management .nav-tab,
+#dashboard_plugins h5,
+a.rsswidget,
+#dashboard_right_now td.b,
+#dashboard-widgets h4,
+.tool-box .title,
+#poststuff h3,
+.metabox-holder h3,
+.pressthis a,
+#your-profile legend,
+.inline-edit-row fieldset span.title,
+.inline-edit-row fieldset span.checkbox-title,
+.tablenav .displaying-num,
+.widefat th,
+.quicktags,
+.search {
+ font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
+}
+
+h2 .nav-tab,
+.wrap h2,
+.subtitle,
+.login form .input {
+ font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
+}
+
+.quicktags,
+.search {
+ font-size: 12px;
+}
+
+.icon32 {
+ float: left;
+ height: 34px;
+ margin: 7px 8px 0 0;
+ width: 36px;
+}
+
+.icon16 {
+ height: 18px;
+ width: 18px;
+ padding: 6px 6px;
+ margin: -6px 0 0 -8px;
+ float: left;
+}
+
+.key-labels label {
+ line-height: 24px;
+}
+
+.pre {
+ /* https://developer.mozilla.org/en-US/docs/CSS/white-space */
+ white-space: pre-wrap; /* css-3 */
+ word-wrap: break-word; /* IE 5.5 - 7 */
+}
+
+.howto {
+ font-style: italic;
+ display: block;
+ font-family: sans-serif;
+}
+
+p.install-help {
+ margin: 8px 0;
+ font-style: italic;
+}
+
+.no-break {
+ white-space: nowrap;
+}
+
+/*------------------------------------------------------------------------------
+ 2.0 - Forms
+------------------------------------------------------------------------------*/
+
+
+.wp-admin select {
+ padding: 2px;
+ height: 2em;
+}
+
+.wp-admin select[multiple] {
+ height: auto;
+}
+
+.submit {
+ padding: 1.5em 0;
+ margin: 5px 0;
+ -webkit-border-bottom-left-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+form p.submit a.cancel:hover {
+ text-decoration: none;
+}
+
+#minor-publishing-actions input,
+#major-publishing-actions input,
+#minor-publishing-actions .preview {
+ text-align: center;
+}
+
+textarea.all-options,
+input.all-options {
+ width: 250px;
+}
+
+input.large-text,
+textarea.large-text {
+ width: 99%;
+}
+
+input.regular-text,
+#adduser .form-field input {
+ width: 25em;
+}
+
+input.small-text {
+ width: 50px;
+}
+
+input[type="number"].small-text {
+ width: 60px;
+}
+
+#doaction,
+#doaction2,
+#post-query-submit {
+ margin: 1px 8px 0 0;
+}
+
+.tablenav #changeit,
+.tablenav #delete_all,
+.tablenav #clear-recent-list {
+ margin-top: 1px;
+}
+
+.tablenav .actions select {
+ float: left;
+ margin-right: 6px;
+ max-width: 200px;
+}
+
+.ie8 .tablenav .actions select {
+ width: 155px;
+}
+
+.ie8 .tablenav .actions select#cat {
+ width: 200px;
+}
+
+#timezone_string option {
+ margin-left: 1em;
+}
+
+label,
+#your-profile label + a {
+ vertical-align: middle;
+}
+
+#misc-publishing-actions label {
+ vertical-align: baseline;
+}
+
+#pass-strength-result {
+ border-style: solid;
+ border-width: 1px;
+ float: left;
+ margin: 13px 5px 5px 1px;
+ padding: 3px 5px;
+ text-align: center;
+ width: 200px;
+ display: none;
+}
+.indicator-hint {
+ padding-top: 8px;
+}
+
+p.search-box {
+ float: right;
+ margin: 0;
+}
+
+.search-box input[name="s"],
+#search-plugins input[name="s"],
+.tagsdiv .newtag {
+ float: left;
+ height: 2em;
+ margin: 0 4px 0 0;
+}
+
+input[type="text"].ui-autocomplete-loading {
+ background: transparent url('../images/loading.gif') no-repeat right center;
+ visibility: visible;
+}
+
+ul#add-to-blog-users {
+ margin: 0 0 0 14px;
+}
+
+.ui-autocomplete-input.open {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.ui-autocomplete {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ position: absolute;
+ z-index: 10000;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-width: 1px;
+ border-style: solid;
+}
+
+.ui-autocomplete li {
+ margin-bottom: 0;
+ white-space: nowrap;
+ text-align: left;
+}
+
+.ui-autocomplete li a {
+ display: block;
+ height: 100%;
+ padding: 4px 10px;
+}
+
+.ui-autocomplete li a.ui-state-focus {
+ cursor: pointer;
+}
+
+/*------------------------------------------------------------------------------
+ 3.0 - Actions
+------------------------------------------------------------------------------*/
+
+#major-publishing-actions {
+ padding: 10px 10px 8px;
+ clear: both;
+ border-top: 1px solid #f5f5f5;
+ margin-top: -2px;
+}
+
+#delete-action {
+ line-height: 25px;
+ vertical-align: middle;
+ text-align: left;
+ float: left;
+}
+
+#publishing-action {
+ text-align: right;
+ float: right;
+ line-height: 23px;
+}
+
+#publishing-action .spinner {
+ float: left;
+}
+
+#misc-publishing-actions {
+ padding: 6px 0 0;
+}
+
+.misc-pub-section {
+ padding: 6px 10px 8px;
+ border-width: 1px 0;
+ border-style: solid;
+}
+
+.misc-pub-section:first-child {
+ border-top-width: 0;
+}
+
+.misc-pub-section-last {
+ border-bottom-width: 0;
+}
+
+#minor-publishing-actions {
+ padding: 10px 10px 2px 8px;
+ text-align: right;
+}
+
+#minor-publishing {
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ -webkit-box-shadow: 0 1px 0 #fff;
+ box-shadow: 0 1px 0 #fff;
+}
+
+#save-post {
+ float: left;
+}
+
+.preview {
+ float: right;
+}
+
+#sticky-span {
+ margin-left: 18px;
+}
+
+.side-info {
+ margin: 0;
+ padding: 4px;
+ font-size: 11px;
+}
+
+.side-info h5 {
+ padding-bottom: 7px;
+ font-size: 14px;
+ margin: 12px 2px 5px;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+.side-info ul {
+ margin: 0;
+ padding-left: 18px;
+ list-style: square;
+}
+
+.approve,
+.unapproved .unapprove {
+ display: none;
+}
+
+.unapproved .approve,
+.spam .approve,
+.trash .approve {
+ display: inline;
+}
+
+td.action-links,
+th.action-links {
+ text-align: right;
+}
+
+
+/*------------------------------------------------------------------------------
+ 4.0 - Notifications
+------------------------------------------------------------------------------*/
+
+#update-nag,
+.update-nag {
+ line-height: 19px;
+ padding: 5px 0;
+ font-size: 12px;
+ text-align: center;
+ margin: -1px 15px 0 5px;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+.plugins .plugin-update {
+ padding: 0;
+}
+
+.plugin-update .update-message {
+ margin: 0 10px 8px 31px;
+ font-weight: bold;
+}
+
+ul#dismissed-updates {
+ display: none;
+}
+
+form.upgrade {
+ margin-top: 8px;
+}
+
+form.upgrade .hint {
+ font-style: italic;
+ font-size: 85%;
+ margin: -0.5em 0 2em 0;
+}
+
+.update-php .spinner {
+ float: none;
+ margin: -4px 0;
+}
+
+#ajax-loading,
+.ajax-loading,
+.ajax-feedback,
+.imgedit-wait-spin,
+.list-ajax-loading { /* deprecated */
+ visibility: hidden;
+}
+
+#ajax-response.alignleft {
+ margin-left: 2em;
+}
+
+
+/*------------------------------------------------------------------------------
+ 6.0 - Admin Header
+------------------------------------------------------------------------------*/
+#adminmenu a,
+#sidemenu a,
+#taglist a,
+#catlist a {
+ text-decoration: none;
+}
+
+/*------------------------------------------------------------------------------
+ 6.1 - Screen Options Tabs
+------------------------------------------------------------------------------*/
+
+#screen-options-wrap,
+#contextual-help-wrap {
+ margin: 0;
+ padding: 8px 20px 12px;
+ position: relative;
+}
+
+#contextual-help-wrap {
+ overflow: auto;
+}
+
+#screen-meta .screen-reader-text {
+ visibility: hidden;
+}
+
+#screen-meta-links {
+ margin: 0 24px 0 0;
+}
+
+#screen-meta-links a:focus {
+ -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
+ box-shadow: 1px 1px 1px rgba(0,0,0,0.4);
+ outline: none;
+}
+
+/* screen options and help tabs revert */
+#screen-meta {
+ display: none;
+ position: relative;
+ margin: 0 15px 0 5px;
+ border-width: 0 1px 1px;
+ border-style: none solid solid;
+}
+
+#screen-options-link-wrap,
+#contextual-help-link-wrap {
+ float: right;
+ height: 23px;
+ padding: 0;
+ margin: 0 0 0 6px;
+ font-family: sans-serif;
+}
+
+#screen-options-link-wrap,
+#contextual-help-link-wrap,
+#screen-meta {
+ -webkit-border-bottom-left-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+#screen-meta-links .screen-meta-toggle {
+ position: relative;
+ top: -1px;
+}
+
+#screen-meta-links a.show-settings {
+ text-decoration: none;
+ z-index: 1;
+ padding: 1px 16px 0 6px;
+ height: 22px;
+ line-height: 22px;
+ font-size: 12px;
+ display: block;
+ text-shadow: rgba(255,255,255,0.7) 0 1px 0;
+}
+
+#screen-meta-links a.show-settings:hover {
+ text-decoration: none;
+}
+/* end screen options and help tabs */
+
+.toggle-arrow {
+ background-repeat: no-repeat;
+ background-position: top left;
+ background-color: transparent;
+ height: 22px;
+ line-height: 22px;
+ display: block;
+}
+
+.toggle-arrow-active {
+ background-position: bottom left;
+}
+
+#screen-options-wrap h5,
+#contextual-help-wrap h5 {
+ margin: 8px 0;
+ font-size: 13px;
+}
+
+.metabox-prefs label {
+ display: inline-block;
+ padding-right: 15px;
+ white-space: nowrap;
+ line-height: 30px;
+}
+
+.metabox-prefs label input {
+ margin: 0 5px 0 2px;
+}
+
+.metabox-prefs .columns-prefs label input {
+ margin: 0 2px;
+}
+
+.metabox-prefs label a {
+ display: none;
+}
+
+/*------------------------------------------------------------------------------
+ 6.2 - Help Menu
+------------------------------------------------------------------------------*/
+
+#contextual-help-wrap {
+ padding: 0;
+ margin-left: -4px;
+}
+
+#contextual-help-columns {
+ position: relative;
+}
+
+#contextual-help-back {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 150px;
+ right: 170px;
+ border-width: 0 1px;
+ border-style: solid;
+}
+
+#contextual-help-wrap.no-sidebar #contextual-help-back {
+ right: 0;
+
+ border-right-width: 0;
+ -webkit-border-bottom-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+}
+
+.contextual-help-tabs {
+ float: left;
+ width: 150px;
+ margin: 0;
+}
+
+.contextual-help-tabs ul {
+ margin: 1em 0;
+}
+
+.contextual-help-tabs li {
+ margin-bottom: 0;
+ list-style-type: none;
+ border-style: solid;
+ border-width: 1px 0;
+ border-color: transparent;
+}
+
+.contextual-help-tabs a {
+ display: block;
+ padding: 5px 5px 5px 12px;
+ line-height: 18px;
+ text-decoration: none;
+}
+
+.contextual-help-tabs .active {
+ padding: 0;
+ margin: 0 -1px 0 0;
+ border-width: 1px 0 1px 1px;
+ border-style: solid;
+}
+
+.contextual-help-tabs-wrap {
+ padding: 0 20px;
+ overflow: auto;
+}
+
+.help-tab-content {
+ display: none;
+ margin: 0 22px 12px 0;
+ line-height: 1.6em;
+}
+
+.help-tab-content.active {
+ display: block;
+}
+
+.help-tab-content ul li {
+ list-style-type: disc;
+ margin-left: 18px;
+}
+
+.contextual-help-sidebar {
+ width: 150px;
+ float: right;
+ padding: 0 8px 0 12px;
+ overflow: auto;
+}
+
+
+/*------------------------------------------------------------------------------
+ 7.0 - Main Navigation (Left Menu)
+------------------------------------------------------------------------------*/
+
+#adminmenuback,
+#adminmenuwrap {
+ border-width: 0 1px 0 0;
+ border-style: solid;
+}
+
+#adminmenuwrap {
+ position: relative;
+ float: left;
+}
+
+#adminmenushadow {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 6px;
+ z-index: 20;
+}
+
+/* side admin menu */
+#adminmenu * {
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+#adminmenu li {
+ margin: 0;
+ padding: 0;
+ cursor: pointer;
+}
+
+#adminmenu a {
+ display: block;
+ line-height: 18px;
+ padding: 2px 5px;
+}
+
+#adminmenu li.menu-top {
+ min-height: 28px;
+ position: relative;
+}
+
+#adminmenu .wp-submenu {
+ list-style: none;
+ padding: 4px 0;
+ margin: 0;
+ position: absolute;
+ top: -1000em;
+ left: 146px;
+ z-index: 1000;
+ overflow: visible;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+.js #adminmenu .sub-open,
+.js #adminmenu .opensub .wp-submenu,
+#adminmenu a.menu-top:focus + .wp-submenu,
+.no-js li.wp-has-submenu:hover .wp-submenu {
+ top: -1px;
+}
+
+#adminmenu .wp-has-current-submenu .wp-submenu,
+.no-js li.wp-has-current-submenu:hover .wp-submenu,
+#adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+#adminmenu .wp-has-current-submenu .wp-submenu.sub-open,
+#adminmenu .wp-has-current-submenu.opensub .wp-submenu {
+ position: relative;
+ z-index: 3;
+ top: auto;
+ left: auto;
+ right: auto;
+ bottom: auto;
+ border: 0 none;
+
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.folded #adminmenu .wp-submenu.sub-open,
+.folded #adminmenu .opensub .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu.sub-open,
+.folded #adminmenu .wp-has-current-submenu.opensub .wp-submenu,
+.folded #adminmenu a.menu-top:focus + .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu,
+.no-js.folded #adminmenu .wp-has-submenu:hover .wp-submenu {
+ top: -1px;
+ left: 32px;
+}
+
+.folded #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+.folded #adminmenu .wp-has-current-submenu .wp-submenu {
+ border-width: 1px;
+ border-style: solid;
+ position: absolute;
+ top: -1000em;
+}
+
+#adminmenu .wp-submenu a {
+ font-size: 12px;
+ line-height: 18px;
+ margin: 0;
+ padding-left: 12px;
+}
+
+#adminmenu .wp-not-current-submenu li > a {
+ padding-left: 16px;
+}
+
+#adminmenu .wp-has-current-submenu ul > li > a,
+.folded #adminmenu li.menu-top .wp-submenu > li > a {
+ padding-left: 12px;
+}
+
+#adminmenu a.menu-top,
+#adminmenu .wp-submenu-head {
+ font-size: 13px;
+ font-weight: bold;
+ line-height: 18px;
+ padding: 0;
+}
+
+#adminmenu .wp-submenu-head,
+.folded #adminmenu .wp-menu-name {
+ display: none;
+}
+
+.folded #adminmenu .wp-submenu-head {
+ display: block;
+}
+
+#adminmenu .wp-submenu li {
+ padding: 0;
+ margin: 0;
+ overflow: hidden;
+}
+
+#adminmenu a.menu-top {
+ border-width: 1px 0;
+ border-style: solid none;
+}
+
+#adminmenu .wp-menu-image img {
+ padding: 7px 0 0 7px;
+ opacity: 0.6;
+ filter: alpha(opacity=60);
+}
+
+#adminmenu div.wp-menu-name {
+ padding: 5px;
+}
+
+#adminmenu div.wp-menu-image {
+ float: left;
+ width: 28px;
+ height: 28px;
+}
+
+.folded #adminmenu div.wp-menu-image {
+ width: 32px;
+ position: absolute;
+ z-index: 25;
+}
+
+.folded #adminmenu a.menu-top {
+ height: 28px;
+}
+
+.wp-menu-arrow {
+ z-index: 25;
+ position: absolute;
+ right: 100%;
+ margin: 0;
+ height: 30px;
+ width: 6px;
+
+ -moz-transform: translate( 146px );
+ -webkit-transform: translate( 146px );
+ -o-transform: translate( 146px );
+ -ms-transform: translate( 146px );
+ transform: translate( 146px );
+}
+
+#adminmenu .wp-menu-arrow div {
+ display: none;
+ position: absolute;
+ top: 7px;
+ left: -1px;
+ width: 14px;
+ height: 15px;
+
+ -moz-transform: matrix( -0.6, 1, 0.6, 1, 0, 0 );
+ -webkit-transform: matrix( -0.6, 1, 0.6, 1, 0, 0 );
+ -o-transform: matrix( -0.6, 1, 0.6, 1, 0, 0 );
+ -ms-transform: matrix( -0.6, 1, 0.6, 1, 0, 0 );
+ transform: matrix( -0.6, 1, 0.6, 1, 0, 0 );
+}
+
+#adminmenu li.wp-not-current-submenu .wp-menu-arrow {
+ -moz-transform: translate( 145px );
+ -webkit-transform: translate( 145px );
+ -o-transform: translate( 145px );
+ -ms-transform: translate( 145px );
+ transform: translate( 145px );
+ height: 28px;
+ border-width: 1px 0;
+ border-style: solid;
+ top: 0;
+}
+
+.folded #adminmenu li .wp-menu-arrow {
+ -moz-transform: translate( 32px );
+ -webkit-transform: translate( 32px );
+ -o-transform: translate( 32px );
+ -ms-transform: translate( 32px );
+ transform: translate( 32px );
+}
+
+#adminmenu li.current .wp-menu-arrow,
+#adminmenu li.wp-has-current-submenu .wp-menu-arrow,
+#adminmenu li.wp-has-current-submenu .wp-menu-arrow div,
+#adminmenu li.wp-has-submenu .wp-menu-arrow div,
+#adminmenu li.current .wp-menu-arrow div,
+.no-js #adminmenu li.wp-has-submenu:hover .wp-menu-arrow,
+#adminmenu li.wp-has-submenu.opensub .wp-menu-arrow,
+#adminmenu a.wp-has-submenu:focus .wp-menu-arrow,
+#adminmenu a:hover .wp-menu-arrow {
+ display: block;
+}
+
+#adminmenu li.current .wp-menu-arrow,
+#adminmenu li.wp-menu-open .wp-menu-arrow {
+ top: 0;
+}
+
+.no-js #adminmenu li.wp-has-submenu:hover .wp-menu-arrow,
+#adminmenu li.wp-has-submenu.opensub .wp-menu-arrow,
+#adminmenu a.wp-has-submenu:focus .wp-menu-arrow {
+ z-index: 1001;
+}
+
+.ie8 #adminmenu li.menu-top:hover .wp-menu-arrow {
+ display: none;
+}
+
+#adminmenu .wp-not-current-submenu .wp-menu-arrow div {
+ width: 15px;
+ top: 6px;
+ border-width: 0 0 1px 1px;
+ border-style: solid;
+}
+
+.wp-menu-arrow,
+.folded #adminmenu li .wp-menu-arrow div,
+.no-js #adminmenu li.wp-not-current-submenu:hover .wp-menu-arrow {
+ display: none;
+}
+
+.folded #adminmenu li.current .wp-menu-arrow,
+.folded #adminmenu li.current .wp-menu-arrow div,
+.folded #adminmenu li.wp-has-current-submenu .wp-menu-arrow div,
+.folded #adminmenu li.wp-menu-open .wp-menu-arrow,
+.folded #adminmenu li a:focus .wp-menu-arrow {
+ display: block;
+}
+
+#adminmenu li.menu-top:hover .wp-menu-image img,
+#adminmenu li.wp-has-current-submenu .wp-menu-image img {
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+
+#adminmenu li.wp-menu-separator {
+ height: 3px;
+ padding: 0;
+ margin: 0;
+ border-width: 1px 0;
+ border-style: solid;
+ cursor: inherit;
+}
+
+#adminmenu div.separator {
+ height: 1px;
+ padding: 0;
+ border-width: 1px 0 0 0;
+ border-style: solid;
+}
+
+#adminmenu .wp-submenu .wp-submenu-head {
+ padding: 5px 4px 5px 10px;
+ margin: -4px -1px 4px;
+ border-width: 1px 0;
+ border-style: solid;
+ -webkit-border-top-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+#adminmenu li.wp-menu-open {
+ border-width: 0 0 1px;
+ border-style: solid;
+}
+
+#adminmenu li.current,
+.folded #adminmenu li.wp-menu-open {
+ border: 0 none;
+}
+
+.folded #adminmenu li.wp-has-current-submenu {
+ margin-bottom: 1px;
+}
+
+.folded #adminmenu .wp-has-current-submenu.menu-top-last {
+ margin-bottom: 0;
+}
+
+#adminmenu .awaiting-mod,
+#adminmenu span.update-plugins,
+#sidemenu li a span.update-plugins {
+ position: absolute;
+ font-family: sans-serif;
+ font-size: 9px;
+ line-height: 17px;
+ font-weight: bold;
+ margin-top: 1px;
+ margin-left: 7px;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+ z-index: 26;
+}
+
+#adminmenu li .awaiting-mod span,
+#adminmenu li span.update-plugins span,
+#sidemenu li a span.update-plugins span {
+ display: block;
+ padding: 0 6px;
+}
+
+#adminmenu li span.count-0,
+#sidemenu li a .count-0 {
+ display: none;
+}
+
+#collapse-menu {
+ font-size: 12px;
+ line-height: 34px;
+ border-width: 1px 0 0;
+ border-style: solid;
+}
+
+.folded #collapse-menu span {
+ display: none;
+}
+
+#collapse-button,
+#collapse-button div {
+ width: 15px;
+ height: 15px;
+}
+
+#collapse-button {
+ float: left;
+ margin: 8px 6px;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+}
+
+/* Auto-folding of the admin menu */
+@media only screen and (max-width: 900px) {
+ .auto-fold #wpcontent,
+ .auto-fold #wpfooter {
+ margin-left: 52px;
+ }
+
+ .auto-fold #adminmenuback,
+ .auto-fold #adminmenuwrap,
+ .auto-fold #adminmenu,
+ .auto-fold #adminmenu li.menu-top {
+ width: 32px;
+ }
+
+ .auto-fold #adminmenu .wp-submenu.sub-open,
+ .auto-fold #adminmenu .opensub .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu .wp-submenu.sub-open,
+ .auto-fold #adminmenu .wp-has-current-submenu.opensub .wp-submenu,
+ .auto-fold #adminmenu a.menu-top:focus + .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu a.menu-top:focus + .wp-submenu {
+ top: -1px;
+ left: 32px;
+ }
+
+ .auto-fold #adminmenu a.wp-has-current-submenu:focus + .wp-submenu,
+ .auto-fold #adminmenu .wp-has-current-submenu .wp-submenu {
+ border-width: 1px;
+ border-style: solid;
+ position: absolute;
+ top: -1000em;
+ }
+
+ .auto-fold #adminmenu li.menu-top .wp-submenu > li > a {
+ padding-left: 12px;
+ }
+
+ .auto-fold #adminmenu .wp-menu-name {
+ display: none;
+ }
+
+ .auto-fold #adminmenu .wp-submenu-head {
+ display: block;
+ }
+
+ .auto-fold #adminmenu div.wp-menu-image {
+ width: 32px;
+ position: absolute;
+ z-index: 25;
+ }
+
+ .auto-fold #adminmenu a.menu-top {
+ height: 28px;
+ }
+
+ .auto-fold #adminmenu li .wp-menu-arrow {
+ -moz-transform: translate( 32px );
+ -webkit-transform: translate( 32px );
+ -o-transform: translate( 32px );
+ -ms-transform: translate( 32px );
+ transform: translate( 32px );
+ }
+
+ .auto-fold #adminmenu li .wp-menu-arrow div {
+ display: none;
+ }
+
+ .auto-fold #adminmenu li.current .wp-menu-arrow,
+ .auto-fold #adminmenu li.current .wp-menu-arrow div,
+ .auto-fold #adminmenu li.wp-has-current-submenu .wp-menu-arrow div,
+ .auto-fold #adminmenu li.wp-menu-open .wp-menu-arrow,
+ .auto-fold #adminmenu li a:focus .wp-menu-arrow {
+ display: block;
+ }
+
+ .auto-fold #adminmenu li.wp-menu-open {
+ border: 0 none;
+ }
+
+ .auto-fold #adminmenu li.wp-has-current-submenu {
+ margin-bottom: 1px;
+ }
+
+ .auto-fold #adminmenu .wp-has-current-submenu.menu-top-last {
+ margin-bottom: 0;
+ }
+
+ .auto-fold #collapse-menu span {
+ display: none;
+ }
+
+}
+
+/* List table styles */
+.post-com-count-wrapper {
+ min-width: 22px;
+ font-family: sans-serif;
+}
+
+.post-com-count {
+ background-image: url('../images/bubble_bg.gif');
+ height: 1.3em;
+ line-height: 1.1em;
+ display: block;
+ text-decoration: none;
+ padding: 0 0 6px;
+ cursor: pointer;
+ background-position: center -80px;
+ background-repeat: no-repeat;
+}
+
+.post-com-count span {
+ font-size: 11px;
+ font-weight: bold;
+ height: 1.4em;
+ line-height: 1.4em;
+ min-width: 0.7em;
+ padding: 0 6px;
+ display: inline-block;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+}
+
+strong .post-com-count {
+ background-position: center -55px;
+}
+
+.post-com-count:hover {
+ background-position: center -3px;
+}
+
+.column-response .post-com-count {
+ float: left;
+ margin-right: 5px;
+ text-align: center;
+}
+
+.response-links {
+ float: left;
+}
+
+#the-comment-list .attachment-80x60 {
+ padding: 4px 8px;
+}
+
+th .comment-grey-bubble {
+ background-image: url('../images/comment-grey-bubble.png');
+ background-repeat: no-repeat;
+ height: 12px;
+ width: 12px;
+}
+
+/*------------------------------------------------------------------------------
+ 8.0 - Layout Blocks
+------------------------------------------------------------------------------*/
+
+html.wp-toolbar {
+ padding-top: 28px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.narrow {
+ width: 70%;
+ margin-bottom: 40px;
+}
+
+.narrow p {
+ line-height: 150%;
+}
+
+.widefat th,
+.widefat td {
+ overflow: hidden;
+}
+
+.widefat th {
+ font-weight: normal;
+}
+
+.widefat td p {
+ margin: 2px 0 0.8em;
+}
+
+.widefat .column-comment p {
+ margin: 0.6em 0;
+}
+
+/* Screens with postboxes */
+.postbox-container {
+ float: left;
+}
+
+#dashboard-widgets.columns-1 .postbox-container {
+ width: 100%;
+}
+
+#dashboard-widgets.columns-2 .postbox-container {
+ width: 49.5%;
+}
+
+#dashboard-widgets.columns-2 #postbox-container-2,
+#dashboard-widgets.columns-2 #postbox-container-3,
+#dashboard-widgets.columns-2 #postbox-container-4 {
+ float: right;
+ width: 50.5%;
+}
+
+#dashboard-widgets.columns-3 .postbox-container {
+ width: 33.5%;
+}
+
+#dashboard-widgets.columns-3 #postbox-container-1 {
+ width: 33%;
+}
+
+#dashboard-widgets.columns-3 #postbox-container-3,
+#dashboard-widgets.columns-3 #postbox-container-4 {
+ float: right;
+}
+
+#dashboard-widgets.columns-4 .postbox-container {
+ width: 25%;
+}
+
+.postbox-container .meta-box-sortables {
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.metabox-holder .postbox-container .empty-container {
+ border: 3px dashed #CCCCCC;
+ height: 250px;
+}
+
+.metabox-holder.columns-1 .postbox-container .empty-container,
+.columns-2 #postbox-container-3 .empty-container,
+.columns-2 #postbox-container-4 .empty-container,
+.columns-3 #postbox-container-4 .empty-container {
+ border: 0 none;
+ height: 0;
+ min-height: 0;
+}
+
+#poststuff {
+ padding-top: 10px;
+}
+
+#poststuff #post-body {
+ padding: 0;
+}
+
+#post-body-content {
+ width: 100%;
+ float: left;
+}
+
+#poststuff .postbox-container {
+ width: 100%;
+}
+
+#poststuff #post-body.columns-2 {
+ margin-right: 300px;
+}
+
+#post-body.columns-2 #postbox-container-1 {
+ float: right;
+ margin-right: -300px;
+ width: 280px;
+}
+
+#post-body.columns-2 #side-sortables {
+ min-height: 250px;
+}
+
+/* one column on the dash */
+@media only screen and (max-width: 799px) {
+ #wpbody-content #dashboard-widgets .postbox-container {
+ width: 100%;
+ }
+
+ #wpbody-content .metabox-holder .postbox-container .empty-container {
+ border: 0 none;
+ height: 0;
+ min-height: 0;
+ }
+}
+
+/* two columns on the dash, but keep the setting if one is selected */
+@media only screen and (min-width: 800px) and (max-width: 1200px) {
+ #wpbody-content #dashboard-widgets .postbox-container {
+ width: 49.5%;
+ }
+
+ #wpbody-content #dashboard-widgets #postbox-container-2,
+ #wpbody-content #dashboard-widgets #postbox-container-3,
+ #wpbody-content #dashboard-widgets #postbox-container-4 {
+ float: right;
+ width: 50.5%;
+ }
+
+ #dashboard-widgets #postbox-container-3 .empty-container,
+ #dashboard-widgets #postbox-container-4 .empty-container {
+ border: 0 none;
+ height: 0;
+ min-height: 0;
+ }
+
+ #wpbody #wpbody-content #dashboard-widgets.columns-1 .postbox-container {
+ width: 100%;
+ }
+
+ #wpbody #wpbody-content .metabox-holder.columns-1 .postbox-container .empty-container {
+ border: 0 none;
+ height: 0;
+ min-height: 0;
+ }
+
+ /* show the radio buttons for column prefs only for one or two columns */
+ .index-php .screen-layout,
+ .index-php .columns-prefs {
+ display: block;
+ }
+
+ .columns-prefs .columns-prefs-3,
+ .columns-prefs .columns-prefs-4 {
+ display: none;
+ }
+}
+
+/* one column on the post write/edit screen */
+@media only screen and (max-width: 850px) {
+ #wpbody-content #poststuff #post-body {
+ margin: 0;
+ }
+
+ #wpbody-content #post-body.columns-2 #postbox-container-1 {
+ margin-right: 0;
+ width: 100%;
+ }
+
+ #poststuff #postbox-container-1 .empty-container,
+ #poststuff #postbox-container-1 #side-sortables:empty {
+ border: 0 none;
+ height: 0;
+ min-height: 0;
+ }
+
+ #poststuff #post-body.columns-2 #side-sortables {
+ min-height: 0;
+ }
+
+ /* hide the radio buttons for column prefs */
+ .screen-layout,
+ .columns-prefs {
+ display: none;
+ }
+}
+
+.postbox .hndle {
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+.js .postbox .hndle {
+ cursor: move;
+}
+
+.postbox.closed .hndle {
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.hndle a {
+ font-size: 11px;
+ font-weight: normal;
+}
+
+.postbox .handlediv {
+ float: right;
+ width: 27px;
+ height: 30px;
+}
+
+.js .postbox .handlediv {
+ cursor: pointer;
+}
+
+.sortable-placeholder {
+ border-width: 1px;
+ border-style: dashed;
+ margin-bottom: 20px;
+}
+
+.widget,
+.postbox,
+.stuffbox {
+ margin-bottom: 20px;
+ padding: 0;
+ border-width: 1px;
+ border-style: solid;
+ line-height: 1;
+}
+
+.widget .widget-top,
+.postbox h3,
+.stuffbox h3 {
+ margin-top: 1px;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.js .widget .widget-top,
+.js .postbox h3 {
+ cursor: move;
+}
+
+.postbox .inside,
+.stuffbox .inside {
+ padding: 0 12px 0 10px;
+ line-height: 1.4em;
+}
+
+.postbox .inside {
+ margin: 10px 0;
+ position: relative;
+}
+
+.postbox.closed h3 {
+ border: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.postbox table.form-table {
+ margin-bottom: 0;
+}
+
+.temp-border {
+ border: 1px dotted #ccc;
+}
+
+.columns-prefs label {
+ padding: 0 5px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 9.0 - Dashboard
+------------------------------------------------------------------------------*/
+
+#dashboard-widgets-wrap {
+ margin: 0 -8px;
+}
+
+#wpbody-content .metabox-holder {
+ padding-top: 10px;
+}
+
+#dashboard-widgets .meta-box-sortables {
+ margin: 0 8px;
+}
+
+#dashboard_recent_comments div.undo {
+ border-top-style: solid;
+ border-top-width: 1px;
+ margin: 0 -10px;
+ padding: 3px 8px;
+ font-size: 11px;
+}
+
+#the-comment-list td.comment p.comment-author {
+ margin-top: 0;
+ margin-left: 0;
+}
+
+#the-comment-list p.comment-author img {
+ float: left;
+ margin-right: 8px;
+}
+
+#the-comment-list p.comment-author strong a {
+ border: none;
+}
+
+#the-comment-list td {
+ vertical-align: top;
+}
+
+#the-comment-list td.comment {
+ word-wrap: break-word;
+}
+
+/* Welcome Panel */
+.welcome-panel {
+ position: relative;
+ overflow: auto;
+ margin: 20px 0;
+ padding: 23px 10px 12px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 3px;
+ font-size: 13px;
+ line-height: 2.1em;
+}
+
+.welcome-panel h3 {
+ margin: 0;
+ font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
+ font-size: 21px;
+ font-weight: normal;
+ line-height: 1.2;
+}
+.welcome-panel h4 {
+ margin: 1.33em 0 0;
+ font-size: 13px;
+}
+
+.welcome-panel .about-description {
+ font-size: 16px;
+ margin: 0;
+}
+
+.welcome-panel .welcome-panel-close {
+ position: absolute;
+ top: 5px;
+ right: 10px;
+ padding: 8px 3px;
+ font-size: 13px;
+ text-decoration: none;
+ line-height: 1;
+}
+
+.welcome-panel .welcome-panel-close:before {
+ content: ' ';
+ position: absolute;
+ left: -12px;
+ width: 10px;
+ height: 100%;
+ background: url('../images/xit.gif') 0 17% no-repeat;
+}
+
+.welcome-panel .welcome-panel-close:hover:before {
+ background-position: 100% 17%;
+}
+
+.wp-core-ui .welcome-panel .button.button-hero {
+ margin: 15px 0 3px;
+}
+
+.welcome-panel-content {
+ margin-left: 13px;
+ max-width: 1500px;
+}
+
+.welcome-panel .welcome-panel-column-container {
+ clear: both;
+ overflow: hidden;
+ position: relative;
+}
+
+.welcome-panel .welcome-panel-column {
+ width: 32%;
+ min-width: 200px;
+ float: left;
+}
+
+.ie8 .welcome-panel .welcome-panel-column {
+ min-width: 230px;
+}
+
+.welcome-panel .welcome-panel-column:first-child {
+ width: 36%;
+}
+
+.welcome-panel-column p {
+ margin-top: 7px;
+}
+
+.welcome-panel .welcome-icon {
+ display: block;
+ padding: 2px 0 8px 32px;
+ background-image: url('../images/welcome-icons.png');
+ background-repeat: no-repeat;
+ background-size: 16px;
+}
+
+.welcome-panel .welcome-add-page {
+ background-position: 0 2px;
+}
+
+.welcome-panel .welcome-edit-page {
+ background-position: 0 -90px;
+}
+
+.welcome-panel .welcome-learn-more {
+ background-position: 0 -136px;
+}
+
+.welcome-panel .welcome-comments {
+ background-position: 0 -182px;
+}
+
+.welcome-panel .welcome-view-site {
+ background-position: 0 -274px;
+}
+
+.welcome-panel .welcome-widgets-menus {
+ background-position: 1px -229px;
+ line-height: 14px;
+}
+
+.welcome-panel .welcome-write-blog {
+ background-position: 0 -44px;
+}
+
+.welcome-panel .welcome-panel-column ul {
+ margin: 0.8em 1em 1em 0;
+}
+
+.welcome-panel .welcome-panel-column li {
+ line-height: 16px;
+ list-style-type: none;
+}
+
+@media screen and (max-width: 870px) {
+ .welcome-panel .welcome-panel-column,
+ .welcome-panel .welcome-panel-column:first-child {
+ display: block;
+ float: none;
+ width: 100%;
+ }
+
+ .welcome-panel .welcome-panel-column li {
+ display: inline-block;
+ margin-right: 13px;
+ }
+
+ .welcome-panel .welcome-panel-column ul {
+ margin: 0.4em 0 0;
+ }
+
+ .welcome-panel .welcome-icon {
+ padding-left: 25px;
+ }
+}
+
+/*------------------------------------------------------------------------------
+ 10.0 - List Posts (/Pages/etc)
+------------------------------------------------------------------------------*/
+
+table.fixed {
+ table-layout: fixed;
+}
+
+.fixed .column-rating,
+.fixed .column-visible {
+ width: 8%;
+}
+
+.fixed .column-posts,
+.fixed .column-date,
+.fixed .column-parent,
+.fixed .column-links,
+.fixed .column-author,
+.fixed .column-format {
+ width: 10%;
+}
+
+.fixed .column-response,
+.fixed .column-categories,
+.fixed .column-tags,
+.fixed .column-rel,
+.fixed .column-role {
+ width: 15%;
+}
+
+.fixed .column-slug {
+ width: 25%;
+}
+
+.fixed .column-locations {
+ width: 35%;
+}
+
+.fixed .column-comments {
+ width: 4em;
+ padding: 8px 0;
+ text-align: left;
+}
+
+.fixed .column-comments .vers {
+ padding-left: 3px;
+}
+
+.fixed .column-comments a {
+ float: left;
+}
+
+.fixed .column-icon {
+ width: 80px;
+}
+
+#comments-form .fixed .column-author {
+ width: 20%;
+}
+
+#commentsdiv.postbox .inside {
+ margin: 0;
+ padding: 0;
+}
+
+#commentsdiv .inside .row-actions {
+ line-height:18px;
+}
+
+#commentsdiv .inside .column-author {
+ width: 25%;
+}
+
+#commentsdiv .column-comment p {
+ margin: 0.6em 0;
+ padding: 0;
+}
+
+#commentsdiv #replyrow td {
+ padding: 0;
+}
+
+#commentsdiv p {
+ padding: 8px 10px;
+ margin: 0;
+}
+
+#commentsdiv #add-new-comment {
+ border-width: 0 0 1px;
+ border-style: none none solid;
+}
+
+#commentsdiv .comments-box {
+ border: 0 none;
+}
+
+#commentsdiv .comments-box thead th {
+ background: transparent;
+ padding: 0 7px 4px;
+ font-style: italic;
+}
+
+#commentsdiv .comments-box tr:last-child td {
+ border-bottom: 0 none;
+}
+
+#commentsdiv .spinner {
+ padding-left: 5px;
+}
+
+.sorting-indicator {
+ display: none;
+ width: 7px;
+ height: 4px;
+ margin-top: 8px;
+ margin-left: 7px;
+ background-image: url('../images/sort.gif');
+ background-repeat: no-repeat;
+}
+
+tr.wp-locked .locked-indicator {
+ background: url('../images/lock.png') no-repeat;
+ margin: -2px 0 0 6px;
+ height: 20px;
+ width: 16px;
+}
+
+tr.wp-locked .check-column label,
+tr.wp-locked .check-column input[type="checkbox"],
+tr.wp-locked .row-actions .inline,
+tr.wp-locked .row-actions .trash {
+ display: none;
+}
+
+tr .locked-info {
+ height: 0;
+ opacity: 0;
+}
+
+tr.wp-locked .locked-info {
+ height: auto;
+ opacity: 1;
+}
+
+tr.locked-info, tr.wp-locked .locked-info {
+ -webkit-transition: height 1s, opacity 500ms;
+ -moz-transition: height 1s, opacity 500ms;
+ -ms-transition: height 1s, opacity 500ms;
+ -o-transition: height 1s, opacity 500ms;
+ transition: height 1s, opacity 500ms;
+}
+
+.fixed .column-comments .sorting-indicator {
+ margin-top: 3px;
+}
+
+#menu-locations-wrap .widefat {
+ width: 60%;
+}
+
+.widefat th.sortable,
+.widefat th.sorted {
+ padding: 0;
+}
+
+th.sortable a,
+th.sorted a {
+ display: block;
+ overflow: hidden;
+ padding: 7px 7px 8px;
+}
+
+.fixed .column-comments.sortable a,
+.fixed .column-comments.sorted a {
+ padding: 8px 0;
+}
+
+th.sortable a span,
+th.sorted a span {
+ float: left;
+ cursor: pointer;
+}
+
+th.sorted.asc .sorting-indicator,
+th.desc:hover span.sorting-indicator {
+ display: block;
+ background-position: 0 0;
+}
+
+th.sorted.desc .sorting-indicator,
+th.asc:hover span.sorting-indicator {
+ display: block;
+ background-position: -7px 0;
+}
+
+/* Bulk Actions */
+.tablenav-pages a {
+ border-bottom-style: solid;
+ border-bottom-width: 2px;
+ font-weight: bold;
+ margin-right: 1px;
+ padding: 0 2px;
+}
+.tablenav-pages .current-page {
+ text-align: center;
+}
+.tablenav-pages .next-page {
+ margin-left: 2px;
+}
+
+.tablenav a.button-secondary {
+ display: block;
+ margin: 3px 8px 0 0;
+}
+
+.tablenav {
+ clear: both;
+ height: 30px;
+ margin: 6px 0 4px;
+ vertical-align: middle;
+}
+
+.tablenav.themes {
+ max-width: 98%;
+}
+
+.tablenav .tablenav-pages {
+ float: right;
+ display: block;
+ cursor: default;
+ height: 30px;
+ line-height: 30px;
+ font-size: 12px;
+}
+
+.tablenav .no-pages,
+.tablenav .one-page .pagination-links {
+ display: none;
+}
+
+.tablenav .tablenav-pages a,
+.tablenav-pages span.current {
+ text-decoration: none;
+ padding: 3px 6px;
+}
+
+.tablenav .tablenav-pages a.disabled:hover ,
+.tablenav .tablenav-pages a.disabled:active {
+ cursor: default;
+}
+
+.tablenav .displaying-num {
+ margin-right: 10px;
+ font-size: 12px;
+ font-style: italic;
+}
+
+.tablenav .actions {
+ overflow: hidden;
+ padding: 2px 8px 0 0;
+}
+
+.tablenav .delete {
+ margin-right: 20px;
+}
+
+.view-switch {
+ float: right;
+ margin: 6px 8px 0;
+}
+
+.view-switch a {
+ text-decoration: none;
+}
+
+.filter {
+ float: left;
+ margin: -5px 0 0 10px;
+}
+
+.filter .subsubsub {
+ margin-left: -10px;
+ margin-top: 13px;
+}
+.screen-per-page {
+ width: 4em;
+}
+
+#posts-filter fieldset {
+ float: left;
+ margin: 0 1.5ex 1em 0;
+ padding: 0;
+}
+
+#posts-filter fieldset legend {
+ padding: 0 0 .2em 1px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 10.1 - Inline Editing
+------------------------------------------------------------------------------*/
+
+/*
+.quick-edit* is for Quick Edit
+.bulk-edit* is for Bulk Edit
+.inline-edit* is for everything
+*/
+
+/* Layout */
+
+#wpbody-content .inline-edit-row fieldset {
+ font-size: 12px;
+ float: left;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+tr.inline-edit-row td,
+#wpbody-content .inline-edit-row fieldset .inline-edit-col {
+ padding: 0 0.5em;
+}
+
+#wpbody-content .quick-edit-row-page fieldset.inline-edit-col-right .inline-edit-col {
+ border-width: 0 0 0 1px;
+ border-style: none none none solid;
+}
+
+#wpbody-content .quick-edit-row-post .inline-edit-col-left {
+ width: 40%;
+}
+
+#wpbody-content .quick-edit-row-post .inline-edit-col-right {
+ width: 39%;
+}
+
+#wpbody-content .inline-edit-row-post .inline-edit-col-center {
+ width: 20%;
+}
+
+#wpbody-content .quick-edit-row-page .inline-edit-col-left {
+ width: 50%;
+}
+
+#wpbody-content .quick-edit-row-page .inline-edit-col-right,
+#wpbody-content .bulk-edit-row-post .inline-edit-col-right {
+ width: 49%;
+}
+
+#wpbody-content .bulk-edit-row .inline-edit-col-left {
+ width: 30%;
+}
+
+#wpbody-content .bulk-edit-row-page .inline-edit-col-right {
+ width: 69%;
+}
+
+#wpbody-content .bulk-edit-row .inline-edit-col-bottom {
+ float: right;
+ width: 69%;
+}
+
+#wpbody-content .inline-edit-row-page .inline-edit-col-right {
+ margin-top: 27px;
+}
+
+.inline-edit-row fieldset .inline-edit-group {
+ clear: both;
+}
+
+.inline-edit-row fieldset .inline-edit-group:after {
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
+.inline-edit-row p.submit {
+ clear: both;
+ padding: 0.5em;
+ margin: 0.5em 0 0;
+}
+
+.inline-edit-row span.error {
+ line-height: 22px;
+ margin: 0 15px;
+ padding: 3px 5px;
+}
+
+/* Positioning */
+.inline-edit-row h4 {
+ margin: .2em 0;
+ padding: 0;
+ line-height: 23px;
+}
+.inline-edit-row fieldset span.title,
+.inline-edit-row fieldset span.checkbox-title {
+ margin: 0;
+ padding: 0;
+ line-height: 27px;
+}
+
+.inline-edit-row fieldset label,
+.inline-edit-row fieldset span.inline-edit-categories-label {
+ display: block;
+ margin: .2em 0;
+}
+
+.inline-edit-row fieldset label.inline-edit-tags {
+ margin-top: 0;
+}
+
+.inline-edit-row fieldset label.inline-edit-tags span.title {
+ margin: .2em 0;
+ width: auto;
+}
+
+.inline-edit-row fieldset label span.title {
+ display: block;
+ float: left;
+ width: 5em;
+}
+
+.inline-edit-row fieldset label span.input-text-wrap {
+ display: block;
+ margin-left: 5em;
+}
+
+.quick-edit-row-post fieldset.inline-edit-col-right label span.title {
+ width: auto;
+ padding-right: 0.5em;
+}
+
+.inline-edit-row .input-text-wrap input[type=text] {
+ width: 100%;
+}
+
+.inline-edit-row fieldset label input[type=checkbox] {
+ vertical-align: text-bottom;
+}
+
+.inline-edit-row fieldset label textarea {
+ width: 100%;
+ height: 4em;
+}
+
+#wpbody-content .bulk-edit-row fieldset .inline-edit-group label {
+ max-width: 50%;
+}
+
+#wpbody-content .quick-edit-row fieldset .inline-edit-group label.alignleft:first-child {
+ margin-right: 0.5em
+}
+
+.inline-edit-col-right .input-text-wrap input.inline-edit-menu-order-input {
+ width: 6em;
+}
+
+.inline-edit-save .spinner {
+ padding: 4px 10px 0;
+ vertical-align: top;
+ float: right;
+}
+
+/* Styling */
+.inline-edit-row h4 {
+ text-transform: uppercase;
+}
+
+.inline-edit-row fieldset span.title,
+.inline-edit-row fieldset span.checkbox-title {
+ font-style: italic;
+ line-height: 1.8em;
+}
+
+/* Specific Elements */
+.inline-edit-row fieldset input[type="text"],
+.inline-edit-row fieldset textarea {
+ border-style: solid;
+ border-width: 1px;
+}
+
+.inline-edit-row fieldset .inline-edit-date {
+ float: left;
+}
+
+.inline-edit-row fieldset input[name=jj],
+.inline-edit-row fieldset input[name=hh],
+.inline-edit-row fieldset input[name=mn] {
+ font-size: 12px;
+ width: 2.1em;
+}
+
+.inline-edit-row fieldset input[name=aa] {
+ font-size: 12px;
+ width: 3.5em;
+}
+
+.inline-edit-row fieldset label input.inline-edit-password-input {
+ width: 8em;
+}
+
+ul.cat-checklist {
+ height: 12em;
+ border-style: solid;
+ border-width: 1px;
+ overflow-y: scroll;
+ padding: 0 5px;
+ margin: 0;
+}
+
+#bulk-titles {
+ display: block;
+ height: 12em;
+ border-style: solid;
+ border-width: 1px;
+ overflow-y: scroll;
+ padding: 0 5px;
+ margin: 0 0 5px;
+}
+
+.inline-edit-row fieldset ul.cat-checklist li,
+.inline-edit-row fieldset ul.cat-checklist input {
+ margin: 0;
+}
+
+.inline-edit-row fieldset ul.cat-checklist label,
+.inline-edit-row #bulk-titles div {
+ font-family: sans-serif;
+ font-style: normal;
+ font-size: 11px;
+}
+
+.inline-edit-row fieldset label input.inline-edit-menu-order-input {
+ width: 3em;
+}
+
+.inline-edit-row fieldset label input.inline-edit-slug-input {
+ width: 75%;
+}
+
+.quick-edit-row-post fieldset label.inline-edit-status {
+ float: left;
+}
+
+#bulk-titles {
+ line-height: 140%;
+}
+#bulk-titles div {
+ margin: 0.2em 0.3em;
+}
+
+#bulk-titles div a {
+ cursor: pointer;
+ display: block;
+ float: left;
+ height: 10px;
+ margin: 3px 3px 0 -2px;
+ overflow: hidden;
+ position: relative;
+ text-indent: -9999px;
+ width: 10px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 11.0 - Write/Edit Post Screen
+------------------------------------------------------------------------------*/
+
+#show-comments {
+ overflow: hidden;
+}
+
+#save-action .spinner,
+#show-comments a,
+#show-comments .spinner {
+ float: left;
+}
+
+#lost-connection-notice .spinner {
+ display: block;
+ float: left;
+ margin: 0 5px 0 0;
+}
+
+.rtl #lost-connection-notice .spinner {
+ float: right;
+ margin: 0 0 0 5px;
+}
+
+#titlediv {
+ position: relative;
+ margin-bottom: 5px;
+}
+
+#titlediv label {
+ cursor: text;
+}
+
+#titlediv div.inside {
+ margin: 0;
+}
+
+#poststuff #titlewrap {
+ border: 0;
+ padding: 0;
+}
+
+#titlediv #title {
+ padding: 3px 8px;
+ font-size: 1.7em;
+ line-height: 100%;
+ height: 1.7em;
+ width: 100%;
+ outline: none;
+ margin: 1px 0;
+}
+
+#titlediv #title-prompt-text,
+#wp-fullscreen-title-prompt-text {
+ color: #bbb;
+ position: absolute;
+ font-size: 1.7em;
+ padding: 11px 10px;
+}
+
+#wp-fullscreen-save .fs-saved {
+ color: #999;
+ float: right;
+ margin-top: 4px;
+}
+
+#wp-fullscreen-title-prompt-text {
+ padding: 11px;
+}
+
+#poststuff .inside-submitbox,
+#side-sortables .inside-submitbox {
+ margin: 0 3px;
+ font-size: 11px;
+}
+
+input#link_description,
+input#link_url {
+ width: 98%;
+}
+
+#pending {
+ background: 0 none;
+ border: 0 none;
+ padding: 0;
+ font-size: 11px;
+ margin-top: -1px;
+}
+
+#edit-slug-box {
+ line-height: 24px;
+ min-height: 25px; /* Yes, line-height + 1 */
+ margin-top: 5px;
+ padding-right: 6px;
+}
+
+#edit-slug-box .cancel {
+ margin-right: 10px;
+ font-size: 11px;
+}
+
+#editable-post-name-full {
+ display: none;
+}
+
+#editable-post-name input {
+ width: 16em;
+}
+
+.postarea h3 label {
+ float: left;
+}
+
+.submitbox .submit {
+ text-align: left;
+ padding: 12px 10px 10px;
+ font-size: 11px;
+}
+
+.submitbox .submitdelete {
+ text-decoration: none;
+ padding: 1px 2px;
+}
+
+.submitbox .submitdelete,
+.submitbox .submit a:hover {
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+.submitbox .submit input {
+ margin-bottom: 8px;
+ margin-right: 4px;
+ padding: 6px;
+}
+
+.inside-submitbox #post_status {
+ margin: 2px 0 2px -2px;
+}
+
+#post-status-select {
+ line-height: 2.5em;
+ margin-top: 3px;
+}
+
+/* Post Screen */
+#post-body #normal-sortables {
+ min-height: 50px;
+}
+
+.postbox {
+ position: relative;
+ min-width: 255px;
+}
+
+#trackback_url {
+ width: 99%;
+}
+
+#normal-sortables .postbox .submit {
+ background: transparent none;
+ border: 0 none;
+ float: right;
+ padding: 0 12px;
+ margin:0;
+}
+
+.category-add input[type="text"],
+.category-add select {
+ width: 100%;
+ max-width: 260px;
+}
+
+.press-this #side-sortables .category-tabs li,
+ul.category-tabs li,
+#side-sortables .add-menu-item-tabs li,
+.wp-tab-bar li {
+ display: inline;
+ line-height: 1.35em;
+}
+
+.no-js .category-tabs li.hide-if-no-js {
+ display: none;
+}
+
+.category-tabs a,
+#side-sortables .add-menu-item-tabs a,
+.wp-tab-bar a {
+ text-decoration: none;
+}
+
+.category-tabs {
+ margin: 8px 0 3px;
+}
+
+#category-adder h4 {
+ margin: 10px 0;
+}
+
+#side-sortables .add-menu-item-tabs,
+.wp-tab-bar {
+ margin-bottom: 3px;
+}
+
+#normal-sortables .postbox #replyrow .submit {
+ float: none;
+ margin: 0;
+ padding: 0 7px 5px;
+}
+
+#side-sortables .submitbox .submit input,
+#side-sortables .submitbox .submit .preview,
+#side-sortables .submitbox .submit a.preview:hover {
+ border: 0 none;
+}
+
+#side-sortables .inside-submitbox .insidebox,
+.stuffbox .insidebox {
+ margin: 11px 0;
+}
+
+ul.category-tabs,
+ul.add-menu-item-tabs,
+ul.wp-tab-bar {
+ margin-top: 12px;
+}
+
+ul.category-tabs li {
+ border-style: solid;
+ border-width: 1px;
+ position: relative;
+}
+
+ul.add-menu-item-tabs li.tabs,
+.wp-tab-active {
+ border-style: solid solid none;
+ border-width: 1px 1px 0;
+}
+
+#post-body .add-menu-item-tabs li.tabs {
+ border-style: solid none solid solid;
+ border-width: 1px 0 1px 1px;
+ margin-right: -1px;
+}
+
+ul.category-tabs li,
+ul.add-menu-item-tabs li,
+ul.wp-tab-bar li {
+ padding: 3px 5px 5px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+/* positioning etc. */
+form#tags-filter {
+ position: relative;
+}
+
+/* Edit posts */
+td.post-title strong,
+td.plugin-title strong {
+ display: block;
+ margin-bottom: .2em;
+}
+
+td.post-title p,
+td.plugin-title p {
+ margin: 6px 0;
+}
+
+/* Global classes */
+.wp-hidden-children .wp-hidden-child,
+.ui-tabs-hide {
+ display: none;
+}
+
+.commentlist .avatar {
+ vertical-align: text-top;
+}
+
+#post-body .tagsdiv #newtag {
+ margin-right: 5px;
+ width: 16em;
+}
+
+#side-sortables input#post_password {
+ width: 94%
+}
+
+#side-sortables .tagsdiv #newtag {
+ width: 68%;
+}
+
+#post-status-info {
+ border-width: 0 1px 1px;
+ border-style: none solid solid;
+ width: 100%;
+ -webkit-border-bottom-left-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+#post-status-info td {
+ font-size: 12px;
+}
+
+.autosave-info {
+ padding: 2px 15px;
+ text-align: right;
+}
+
+#editorcontent #post-status-info {
+ border: none;
+}
+
+#post-body .wp_themeSkin .mceStatusbar a.mceResize {
+ display: block;
+ background: transparent url('../images/resize.gif') no-repeat scroll right bottom;
+ width: 12px;
+ cursor: se-resize;
+ margin: 0 1px;
+ position: relative;
+ top: -2px;
+}
+
+#post-body .postarea .wp_themeSkin .mceStatusbar a.mceResize {
+ top: 20px;
+}
+
+#content-resize-handle {
+ background: transparent url('../images/resize.gif') no-repeat scroll right bottom;
+ width: 12px;
+ cursor: se-resize;
+ position: absolute;
+ right: 2px;
+ height: 19px;
+}
+
+.press-this #content-resize-handle {
+ bottom: 2px;
+}
+
+.tmce-active #content-resize-handle {
+ display: none;
+}
+
+#wp-word-count {
+ display: block;
+ padding: 2px 10px;
+}
+
+#timestampdiv select {
+ height: 20px;
+ line-height: 14px;
+ padding: 0;
+ vertical-align: top;
+}
+
+#aa, #jj, #hh, #mn {
+ padding: 1px;
+ font-size: 12px;
+}
+
+#jj, #hh, #mn {
+ width: 2em;
+}
+
+#aa {
+ width: 3.4em;
+}
+
+.curtime #timestamp {
+ background-repeat: no-repeat;
+ background-position: left center;
+ padding: 2px 0 1px 20px;
+}
+
+#timestampdiv {
+ padding-top: 5px;
+ line-height: 23px;
+}
+
+#timestampdiv p {
+ margin: 8px 0 6px;
+}
+
+#timestampdiv input {
+ border-width: 1px;
+ border-style: solid;
+}
+
+.notification-dialog {
+ position: fixed;
+ top: 30%;
+ left: 50%;
+ width: 450px;
+ margin-left: -225px;
+ background: #fff;
+ line-height: 1.5;
+ z-index: 1000005;
+}
+
+.notification-dialog-background {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: #000;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+ z-index: 1000000;
+}
+
+#post-lock-dialog .post-locked-message,
+#post-lock-dialog .post-taken-over {
+ margin: 25px;
+}
+
+#post-lock-dialog .post-locked-message a.button {
+ margin-right: 10px;
+}
+
+#post-lock-dialog .post-locked-avatar {
+ float: left;
+ margin: 0 20px 20px 0;
+}
+
+#post-lock-dialog .wp-tab-first {
+ outline: 0;
+}
+
+#post-lock-dialog .locked-saving img {
+ float: left;
+ margin-right: 3px;
+}
+
+#post-lock-dialog.saving .locked-saving,
+#post-lock-dialog.saved .locked-saved {
+ display: inline;
+}
+
+/*------------------------------------------------------------------------------
+ 11.1 - Custom Fields
+------------------------------------------------------------------------------*/
+
+#postcustomstuff thead th {
+ padding: 5px 8px 8px;
+}
+
+#postcustom #postcustomstuff .submit {
+ border: 0 none;
+ float: none;
+ padding: 0 8px 8px;
+}
+
+#side-sortables #postcustom #postcustomstuff .submit {
+ margin: 0;
+ padding: 0;
+}
+
+#side-sortables #postcustom #postcustomstuff #the-list textarea {
+ height: 85px;
+}
+
+#side-sortables #postcustom #postcustomstuff td.left input,
+#side-sortables #postcustom #postcustomstuff td.left select,
+#side-sortables #postcustomstuff #newmetaleft a {
+ margin: 3px 3px 0;
+}
+
+#postcustomstuff table {
+ margin: 0;
+ width: 100%;
+ border-width: 1px;
+ border-style: solid;
+ border-spacing: 0;
+}
+
+#postcustomstuff tr {
+ vertical-align: top;
+}
+
+#postcustomstuff table input,
+#postcustomstuff table select,
+#postcustomstuff table textarea {
+ width: 96%;
+ margin: 8px;
+}
+
+#side-sortables #postcustomstuff table input,
+#side-sortables #postcustomstuff table select,
+#side-sortables #postcustomstuff table textarea {
+ margin: 3px;
+}
+
+#postcustomstuff th.left,
+#postcustomstuff td.left {
+ width: 38%;
+}
+
+#postcustomstuff .submit input {
+ margin: 0;
+ width: auto;
+}
+
+#postcustomstuff #newmetaleft a {
+ display: inline-block;
+ margin: 0 8px 8px;
+ text-decoration: none;
+}
+
+.no-js #postcustomstuff #enternew {
+ display: none;
+}
+
+#post-body-content .compat-attachment-fields {
+ margin-bottom: 20px;
+}
+
+.compat-attachment-fields th {
+ padding-top: 5px;
+ padding-right: 10px;
+}
+
+/*------------------------------------------------------------------------------
+ 11.2 - Post Revisions
+------------------------------------------------------------------------------*/
+.revisions-control-frame,
+.revisions-diff-frame {
+ position: relative;
+}
+
+.revisions-controls {
+ padding-top: 40px;
+ height: 100px;
+ z-index: 1;
+}
+
+.revisions-controls input[type="checkbox"] {
+ position: relative;
+ top: -1px;
+ vertical-align: text-bottom;
+}
+
+.revisions.pinned .revisions-controls {
+ position: fixed;
+ top: 0;
+ padding-bottom: 10px;
+}
+
+.revisions-tickmarks {
+ position: relative;
+ margin: 0 auto;
+ height: 0.8em;
+ top: 7px;
+ max-width: 70%;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.revisions-tickmarks > div {
+ position: absolute;
+ height: 100%;
+ border-style: solid;
+ border-width: 0 1px 0 0;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.revisions-tickmarks > div:first-child {
+ border-width: 0;
+}
+
+.comparing-two-revisions .revisions-controls {
+ height: 140px;
+}
+
+.revisions .diff-error {
+ position: absolute;
+ text-align: center;
+ margin: 0 auto;
+ width: 100%;
+ display: none;
+}
+
+.revisions.diff-error .diff-error {
+ display: block;
+}
+
+.revisions .loading-indicator {
+ position: fixed;
+ vertical-align: middle;
+ opacity: 0;
+ width: 100%;
+ top: 50%;
+ margin-left: -90px;
+ -webkit-transition: opacity 0.5s;
+ -moz-transition: opacity 0.5s;
+ -ms-transition: opacity 0.5s;
+ -o-transition: opacity 0.5s;
+ transition: opacity 0.5s;
+ filter: alpha(opacity=0); /* ie8 and earlier */
+}
+
+body.folded .revisions .loading-indicator {
+ margin-left: -32px;
+}
+
+.revisions .loading-indicator span.spinner {
+ display: block;
+ margin: 0 auto;
+ float: none;
+}
+
+.revisions.loading .loading-indicator {
+ opacity: 1;
+ filter: alpha(opacity=100); /* ie8 and earlier */
+}
+
+.revisions .diff {
+ -webkit-transition: opacity 0.5s;
+ -moz-transition: opacity 0.5s;
+ -ms-transition: opacity 0.5s;
+ -o-transition: opacity 0.5s;
+ transition: opacity 0.5s;
+}
+
+.revisions.loading .diff {
+ opacity: 0.5;
+ filter: alpha(opacity=50); /* ie8 and earlier */
+}
+
+.revisions.diff-error .diff {
+ visibility: hidden;
+}
+
+.revisions-meta {
+ margin-top: 15px;
+}
+
+.revision-toggle-compare-mode {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+
+.comparing-two-revisions .revisions-previous,
+.comparing-two-revisions .revisions-next,
+.revisions-meta .diff-meta-to strong {
+ display: none;
+}
+
+.revisions-controls .author-card .date {
+ color: #777;
+}
+
+.revisions-controls .author-card.autosave {
+ color: #d54e21;
+}
+
+.revisions-controls .author-card .author-name {
+ font-weight: bold;
+}
+
+.comparing-two-revisions .diff-meta-to strong {
+ display: block;
+}
+
+.revisions-previous,
+.revisions-next {
+ position: relative;
+ z-index: 1;
+}
+
+.revisions-previous {
+ float: left;
+}
+
+.revisions-next {
+ float: right;
+}
+
+.revisions-controls .wp-slider {
+ max-width: 70%;
+ margin: 0 auto;
+ top: -3px;
+}
+
+/* Revision meta box */
+.post-revisions li img,
+#revisions-meta-restored img {
+ vertical-align: middle;
+}
+
+table.diff {
+ table-layout: fixed;
+ width: 100%;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+table.diff col.content {
+ width: auto;
+}
+
+table.diff col.content.diffsplit {
+ width: 48%;
+}
+
+table.diff col.diffsplit.middle {
+ width: auto;
+}
+
+table.diff col.ltype {
+ width: 30px;
+}
+
+table.diff tr {
+ background-color: transparent;
+}
+
+table.diff td,
+table.diff th {
+ padding: .5em;
+ font-family: Consolas, Monaco, monospace;
+}
+
+table.diff .diff-deletedline del,
+table.diff .diff-addedline ins {
+ text-decoration: none;
+}
+
+.diff-meta {
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ padding: 5px;
+ clear: both;
+ min-height: 32px;
+}
+
+.diff-title strong {
+ line-height: 32px;
+ min-width: 60px;
+ text-align: right;
+ float: left;
+ margin-right: 5px;
+}
+
+.revisions-controls .author-card .avatar,
+.revisions-controls .author-card .author-info {
+ float: left;
+ margin-left: 6px;
+ margin-right: 6px;
+}
+
+.revisions-controls .author-card .byline {
+ display: block;
+ font-size: 12px;
+}
+
+.revisions-controls .author-card .avatar {
+ vertical-align: middle;
+}
+
+.diff-meta input.restore-revision {
+ float: right;
+ margin-left: 6px;
+ margin-right: 6px;
+ margin-top: 4px;
+}
+
+.diff-meta-from {
+ display: none;
+}
+
+.comparing-two-revisions .diff-meta-from {
+ display: block;
+}
+
+.revisions-tooltip {
+ position: absolute;
+ bottom: 105px;
+ margin-right: 0;
+ margin-left: -69px;
+ z-index: 0;
+ max-width: 350px;
+ min-width: 130px;
+ padding: 8px 4px;
+ display: none;
+ opacity: 0;
+}
+
+.revisions-tooltip.flipped {
+ margin-left: 0;
+ margin-right: -70px;
+}
+
+.revisions.pinned .revisions-tooltip {
+ display: none !important;
+}
+
+.comparing-two-revisions .revisions-tooltip {
+ bottom: 145px;
+}
+
+.revisions-tooltip-arrow {
+ width: 70px;
+ height: 15px;
+ overflow: hidden;
+ position: absolute;
+ left: 0;
+ margin-left: 35px;
+ bottom: -15px;
+}
+
+.revisions-tooltip.flipped .revisions-tooltip-arrow {
+ margin-left: 0;
+ margin-right: 35px;
+ left: auto;
+ right: 0;
+}
+
+.revisions-tooltip-arrow > span {
+ content: "";
+ position: absolute;
+ left: 20px;
+ top: -20px;
+ width: 25px;
+ height: 25px;
+ -webkit-transform: rotate(45deg);
+ -moz-transform: rotate(45deg);
+ -ms-transform: rotate(45deg);
+ -o-transform: rotate(45deg);
+ tranform: rotate(45deg);
+}
+
+.revisions-tooltip.flipped .revisions-tooltip-arrow > span {
+ left: auto;
+ right: 20px;
+}
+
+.ie8 .revisions-tooltip-arrow > span {
+ left: 15px;
+ top: -25px;
+ -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)";
+}
+
+.ie8 .revisions-tooltip.flipped .revisions-tooltip-arrow > span {
+ right: 25px;
+}
+
+.revisions-tooltip,
+.revisions-tooltip-arrow > span {
+ border-width: 1px;
+ border-style: solid;
+}
+
+div.revisions-controls > .wp-slider > .ui-slider-handle {
+ margin-left: -10px;
+}
+
+ /* jQuery UI Slider */
+.wp-slider.ui-slider {
+ position: relative;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 3px;
+ text-align: left;
+ cursor: pointer;
+}
+
+.wp-slider .ui-slider-handle {
+ position: absolute;
+ z-index: 2;
+ margin-top: -3px;
+ width: 19px;
+ height: 19px;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 50%;
+}
+
+.wp-slider .ui-slider-handle:before {
+ content: "";
+ position: absolute;
+ top: 6px;
+ left: 3px;
+ height: 8px;
+ width: 13px;
+ background: url(../images/arrows-pr.png) no-repeat -2px -47px;
+}
+
+.wp-slider .ui-slider-handle.from-handle:before,
+.wp-slider .ui-slider-handle.to-handle:before {
+ height: 8px;
+ width: 7px;
+}
+
+.wp-slider .ui-slider-handle.from-handle:before {
+ background-position: -5px -84px;
+ left: 7px;
+}
+
+.wp-slider .ui-slider-handle.to-handle:before {
+ background-position: -4px -65px;
+ left: 5px;
+}
+
+.wp-slider .ui-slider-range {
+ position: absolute;
+ font-size: .7em;
+ display: block;
+ border: 0;
+ background-color: transparent;
+ background-image: none;
+}
+
+.wp-slider.ui-slider-horizontal {
+ height: .8em;
+}
+
+.wp-slider.ui-slider-horizontal .ui-slider-handle {
+ top: -.25em;
+ margin-left: -.6em;
+}
+
+.wp-slider.ui-slider-horizontal .ui-slider-range {
+ top: 0;
+ height: 100%;
+}
+
+.wp-slider.ui-slider-horizontal .ui-slider-range-min {
+ left: 0;
+}
+
+.wp-slider.ui-slider-horizontal .ui-slider-range-max {
+ right: 0;
+}
+
+
+/*------------------------------------------------------------------------------
+ 11.3 - Featured Images
+------------------------------------------------------------------------------*/
+
+#select-featured-image {
+ padding: 4px 0;
+ overflow: hidden;
+}
+
+#select-featured-image img {
+ max-width: 100%;
+ height: auto;
+ margin-bottom: 10px;
+}
+
+#select-featured-image a {
+ float: left;
+ clear: both;
+}
+
+#select-featured-image .remove {
+ display: none;
+ margin-top: 10px;
+}
+
+.js #select-featured-image.has-featured-image .remove {
+ display: inline-block;
+}
+
+.no-js #select-featured-image .choose {
+ display: none;
+}
+
+/*------------------------------------------------------------------------------
+ 11.4 - Post formats
+------------------------------------------------------------------------------*/
+
+a.post-state-format {
+ overflow: hidden;
+ display: inline-block;
+ vertical-align: middle;
+ height: 16px;
+ width: 16px;
+ margin-right: 5px;
+ background-repeat: no-repeat;
+ text-indent: -999em;
+}
+
+#post-formats-select {
+ line-height: 2em;
+}
+
+label.post-format-icon {
+ margin-left: 5px;
+ padding: 2px 0 2px 21px;
+}
+
+.post-format-icon.post-format-standard {
+ background-position: 0 0;
+}
+
+.post-format-icon.post-format-image {
+ background-position: 0 -32px;
+}
+
+.post-format-icon.post-format-gallery {
+ background-position: 0 -64px;
+}
+
+.post-format-icon.post-format-audio {
+ background-position: 0 -96px;
+}
+
+.post-format-icon.post-format-video {
+ background-position: 0 -128px;
+}
+
+.post-format-icon.post-format-chat {
+ background-position: 0 -160px;
+}
+
+.post-format-icon.post-format-status {
+ background-position: 0 -192px;
+}
+
+.post-format-icon.post-format-aside {
+ background-position: 0 -224px;
+}
+
+.post-format-icon.post-format-quote {
+ background-position: 0 -256px;
+}
+
+.post-format-icon.post-format-link {
+ background-position: 0 -288px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 12.0 - Categories
+------------------------------------------------------------------------------*/
+
+.category-adder {
+ margin-left: 120px;
+ padding: 4px 0;
+}
+
+.category-adder h4 {
+ margin: 0 0 8px;
+}
+
+#side-sortables .category-adder {
+ margin: 0;
+}
+
+#post-body ul.add-menu-item-tabs {
+ float: left;
+ width: 120px;
+ text-align: right;
+ /* Negative margin for the sake of those without JS: all tabs display */
+ margin: 0 -120px 0 5px;
+ padding: 0;
+}
+
+#post-body ul.add-menu-item-tabs li {
+ padding: 8px;
+}
+
+#post-body ul.add-menu-item-tabs li.tabs {
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+.wp-tab-panel,
+.categorydiv div.tabs-panel,
+.customlinkdiv div.tabs-panel,
+.posttypediv div.tabs-panel,
+.taxonomydiv div.tabs-panel {
+ min-height: 42px;
+ max-height: 200px;
+ overflow: auto;
+ padding: 0 0.9em;
+ border-style: solid;
+ border-width: 1px;
+}
+
+div.tabs-panel-active {
+ display:block;
+}
+
+div.tabs-panel-inactive {
+ display:none;
+}
+
+#front-page-warning,
+#front-static-pages ul,
+ul.export-filters,
+.inline-editor ul.cat-checklist ul,
+.categorydiv ul.categorychecklist ul,
+.customlinkdiv ul.categorychecklist ul,
+.posttypediv ul.categorychecklist ul,
+.taxonomydiv ul.categorychecklist ul {
+ margin-left: 18px;
+}
+
+ul.categorychecklist li {
+ margin: 0;
+ padding: 0;
+ line-height: 19px;
+ word-wrap: break-word;
+}
+
+.categorydiv .tabs-panel,
+.customlinkdiv .tabs-panel,
+.posttypediv .tabs-panel,
+.taxonomydiv .tabs-panel {
+ border-width: 3px;
+ border-style: solid;
+}
+
+.form-wrap p,
+.form-wrap label {
+ font-size: 11px;
+}
+
+.form-wrap label {
+ display: block;
+ padding: 2px;
+ font-size: 12px;
+}
+
+.form-field input,
+.form-field textarea {
+ border-style: solid;
+ border-width: 1px;
+ width: 95%;
+}
+
+p.description,
+.form-wrap p {
+ margin: 2px 0 5px;
+}
+
+p.help,
+p.description,
+span.description,
+.form-wrap p {
+ font-size: 12px;
+ font-style: italic;
+ font-family: sans-serif;
+}
+
+.form-wrap .form-field {
+ margin: 0 0 10px;
+ padding: 8px 0;
+}
+
+.form-wrap .form-field #parent {
+ max-width: 100%;
+}
+
+.col-wrap h3 {
+ margin: 12px 0;
+ font-size: 1.1em;
+}
+
+.col-wrap p.submit {
+ margin-top: -10px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 13.0 - Tags
+------------------------------------------------------------------------------*/
+
+#poststuff .taghint {
+ color: #aaa;
+ margin: 15px 0 -24px 12px;
+}
+
+#poststuff .tagsdiv .howto {
+ margin: 0 0 6px 8px;
+}
+
+.ajaxtag .newtag {
+ position: relative;
+}
+
+.tagsdiv .newtag {
+ width: 180px;
+}
+
+.tagsdiv .the-tags {
+ display: block;
+ height: 60px;
+ margin: 0 auto;
+ overflow: auto;
+ width: 260px;
+}
+
+#post-body-content .tagsdiv .the-tags {
+ margin: 0 5px;
+}
+
+p.popular-tags {
+ -webkit-border-radius: 8px;
+ border-radius: 8px;
+ border-width: 1px;
+ border-style: solid;
+ line-height: 2em;
+ max-width: 1000px;
+ padding: 8px 12px 12px;
+ text-align: justify;
+}
+
+p.popular-tags a {
+ padding: 0 3px;
+}
+
+.tagcloud {
+ width: 97%;
+ margin: 0 0 40px;
+ text-align: justify;
+}
+
+.tagcloud h3 {
+ margin: 2px 0 12px;
+}
+
+.ac_results {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ position: absolute;
+ z-index: 10000;
+ display: none;
+ border-width: 1px;
+ border-style: solid;
+}
+
+.ac_results li {
+ padding: 2px 5px;
+ white-space: nowrap;
+ text-align: left;
+}
+
+.ac_over {
+ cursor: pointer;
+}
+
+.ac_match {
+ text-decoration: underline;
+}
+
+/* links tables */
+table.links-table {
+ width: 100%;
+}
+
+.links-table th {
+ font-weight: normal;
+ text-align: left;
+ vertical-align: top;
+ min-width: 80px;
+ width: 20%;
+ word-wrap: break-word;
+}
+
+.links-table th,
+.links-table td {
+ padding: 5px 0;
+}
+
+.links-table td label {
+ margin-right: 8px;
+}
+
+.links-table td input[type="text"],
+.links-table td textarea {
+ width: 100%;
+}
+
+.links-table #link_rel {
+ max-width: 280px;
+}
+
+/*------------------------------------------------------------------------------
+ 14.0 - Media Screen
+------------------------------------------------------------------------------*/
+
+.media-item .describe {
+ border-collapse: collapse;
+ width: 100%;
+ border-top-style: solid;
+ border-top-width: 1px;
+ clear: both;
+ cursor: default;
+}
+
+.media-item.media-blank .describe {
+ border: 0;
+}
+
+.media-item .describe th {
+ vertical-align: top;
+ text-align: left;
+ padding: 5px 10px 10px;
+ width: 140px;
+}
+
+.media-item .describe .align th {
+ padding-top: 0;
+}
+
+.media-item .media-item-info tr {
+ background-color: transparent;
+}
+
+.media-item .describe td {
+ padding: 0 8px 8px 0;
+ vertical-align: top;
+}
+
+.media-item thead.media-item-info td {
+ padding: 4px 10px 0;
+}
+
+.media-item .media-item-info .A1B1 {
+ padding: 0 0 0 10px;
+}
+
+.media-item td.savesend {
+ padding-bottom: 15px;
+}
+
+.media-item .thumbnail {
+ max-height: 128px;
+ max-width: 128px;
+}
+
+#wpbody-content #async-upload-wrap a {
+ display: none;
+}
+
+.media-upload-form {
+ margin-top: 20px;
+}
+
+.media-upload-form td label {
+ margin-right: 6px;
+ margin-left: 2px;
+}
+
+.media-upload-form .align .field label {
+ display: inline;
+ padding: 0 0 0 23px;
+ margin: 0 1em 0 3px;
+ font-weight: bold;
+}
+
+.media-upload-form tr.image-size label {
+ margin: 0 0 0 5px;
+ font-weight: bold;
+}
+
+.media-upload-form th.label label {
+ font-weight: bold;
+ margin: 0.5em;
+ font-size: 13px;
+}
+
+.media-upload-form th.label label span {
+ padding: 0 5px;
+}
+
+abbr.required {
+ border: medium none;
+ text-decoration: none;
+}
+
+.media-item .describe input[type="text"],
+.media-item .describe textarea {
+ width: 460px;
+}
+
+.media-item .describe p.help {
+ margin: 0;
+ padding: 0 0 0 5px;
+}
+
+.media-item .edit-attachment,
+.describe-toggle-on,
+.describe-toggle-off {
+ display: block;
+ line-height: 36px;
+ float: right;
+ margin-right: 15px;
+}
+
+.media-item .describe-toggle-off,
+.media-item.open .describe-toggle-on {
+ display: none;
+}
+
+.media-item.open .describe-toggle-off {
+ display: block;
+}
+
+#media-items .media-item {
+ border-style: solid;
+ border-width: 1px;
+ min-height: 36px;
+ position: relative;
+ margin-top: -1px;
+ width: 100%;
+}
+
+#media-items {
+ width: 623px;
+}
+
+.media-new-php #media-items {
+ margin: 1em 0;
+}
+
+#media-items:empty {
+ border: 0 none;
+}
+
+.media-item .filename {
+ line-height: 36px;
+ overflow: hidden;
+ padding: 0 10px;
+}
+
+.media-item .error-div {
+ padding-left: 10px;
+}
+
+.media-item .pinkynail {
+ float: left;
+ margin: 2px 2px 0;
+ max-width: 40px;
+ max-height: 32px;
+}
+
+.media-item .startopen,
+.media-item .startclosed {
+ display: none;
+}
+
+.media-item .original {
+ position: relative;
+ height: 34px;
+}
+
+.media-item .progress {
+ float: right;
+ height: 22px;
+ margin: 6px 10px 0 0;
+ width: 200px;
+ line-height: 2em;
+ padding: 0;
+ overflow: hidden;
+ margin-bottom: 2px;
+ border: 1px solid #d1d1d1;
+ background: #f7f7f7;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#fff), to(#f7f7f7));
+ background-image: -webkit-linear-gradient(bottom, #fff, #f7f7f7);
+ background-image: -moz-linear-gradient(bottom, #fff, #f7f7f7);
+ background-image: -o-linear-gradient(bottom, #fff, #f7f7f7);
+ background-image: linear-gradient(to top, #fff, #f7f7f7);
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 0 3px rgba(0,0,0,0.1);
+ box-shadow: inset 0 0 3px rgba(0,0,0,0.1);
+}
+
+.media-item .bar {
+ z-index: 9;
+ width: 0;
+ height: 100%;
+ margin-top: -24px;
+ background-color: #8cc1e9;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#72a7cf), to(#8cc1e9));
+ background-image: -webkit-linear-gradient(bottom, #72a7cf, #8cc1e9);
+ background-image: -moz-linear-gradient(bottom, #72a7cf, #8cc1e9);
+ background-image: -o-linear-gradient(bottom, #72a7cf, #8cc1e9);
+ background-image: linear-gradient(to top, #72a7cf, #8cc1e9);
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.3);
+ box-shadow: 0 0 3px rgba(0,0,0,0.3);
+}
+
+.media-item .progress .percent {
+ z-index: 10;
+ position: relative;
+ width: 200px;
+ padding: 0 8px;
+ text-shadow: 0 1px 0 rgba(255,255,255,0.4);
+ color: rgba(0,0,0,0.6);
+}
+
+.upload-php .fixed .column-parent {
+ width: 15%;
+}
+
+.js .html-uploader #plupload-upload-ui {
+ display: none;
+}
+
+.js .html-uploader #html-upload-ui {
+ display: block;
+}
+
+.media-upload-form .media-item.error {
+ margin: 0;
+ padding: 0;
+}
+
+.media-upload-form .media-item.error p,
+.media-item .error-div {
+ line-height: 16px;
+ margin: 5px 10px;
+ padding: 0;
+}
+
+.media-item .error-div a.dismiss {
+ display: block;
+ float: right;
+ margin: 5px 4px 0 15px;
+}
+
+/*------------------------------------------------------------------------------
+ 14.1 - Media Library
+------------------------------------------------------------------------------*/
+
+.find-box {
+ width: 600px;
+ height: 300px;
+ overflow: hidden;
+ padding: 33px 0 51px;
+ position: absolute;
+ z-index: 1000;
+}
+
+.find-box-head {
+ cursor: move;
+ font-weight: bold;
+ height: 2em;
+ line-height: 2em;
+ padding: 1px 12px;
+ position: absolute;
+ top: 5px;
+ width: 100%;
+}
+
+.find-box-inside {
+ overflow: auto;
+ padding: 6px;
+ height: 100%;
+}
+
+.find-box-search {
+ overflow: hidden;
+ padding: 9px;
+ position: relative;
+}
+
+.find-box-search .spinner {
+ float: none;
+ left: 125px;
+ position: absolute;
+ top: 9px;
+}
+
+#find-posts-input {
+ float: left;
+ width: 140px;
+ height: 24px;
+}
+
+#find-posts-search {
+ float: left;
+ margin: 1px 4px 0 3px;
+}
+
+#find-posts-response {
+ margin: 8px 0;
+ padding: 0 1px 6px;
+}
+
+#find-posts-response table {
+ width: 100%;
+}
+
+#find-posts-response .found-radio {
+ padding: 3px 0 0 8px;
+ width: 15px;
+}
+
+.find-box-buttons {
+ padding: 8px;
+ overflow: hidden;
+}
+
+.find-box #resize-se {
+ position: absolute;
+ right: 1px;
+ bottom: 1px;
+}
+
+.ui-find-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ background-color: #000;
+ opacity: 0.6;
+ filter: alpha(opacity=60);
+}
+
+ul#dismissed-updates {
+ display: none;
+}
+
+form.upgrade {
+ margin-top: 8px;
+}
+
+form.upgrade .hint {
+ font-style: italic;
+ font-size: 85%;
+ margin: -0.5em 0 2em 0;
+}
+
+#poststuff .inside .the-tagcloud {
+ margin: 5px 0 10px;
+ padding: 8px;
+ border-width: 1px;
+ border-style: solid;
+ line-height: 1.8em;
+ word-spacing: 3px;
+ -webkit-border-radius: 6px;
+ border-radius: 6px;
+}
+
+.drag-drop #drag-drop-area {
+ border: 4px dashed #DDDDDD;
+ height: 200px;
+}
+
+.drag-drop .drag-drop-inside {
+ margin: 70px auto 0;
+ width: 250px;
+}
+
+.drag-drop-inside p {
+ color: #aaa;
+ font-size: 14px;
+ margin: 5px 0;
+ display: none;
+}
+
+.drag-drop .drag-drop-inside p {
+ text-align: center;
+}
+
+.drag-drop-inside p.drag-drop-info {
+ font-size: 20px;
+}
+
+.drag-drop .drag-drop-inside p,
+.drag-drop-inside p.drag-drop-buttons {
+ display: block;
+}
+
+/*
+#drag-drop-area:-moz-drag-over {
+ border-color: #83b4d8;
+}
+borger color while dragging a file over the uploader drop area */
+.drag-drop.drag-over #drag-drop-area {
+ border-color: #83b4d8;
+}
+
+#plupload-upload-ui {
+ position: relative;
+}
+
+
+/*------------------------------------------------------------------------------
+ 14.2 - Image Editor
+------------------------------------------------------------------------------*/
+
+.describe .image-editor {
+ vertical-align: top;
+}
+
+.imgedit-wrap {
+ position: relative;
+}
+
+.imgedit-settings p {
+ margin: 8px 0;
+}
+
+.post-php .imgedit-wrap table {
+ width: 100%;
+}
+
+.describe .imgedit-wrap table td,
+.wp_attachment_holder .imgedit-wrap table td {
+ vertical-align: top;
+ padding-top: 0;
+}
+
+.describe .imgedit-wrap table td.imgedit-settings {
+ padding: 0 5px;
+}
+
+.wp_attachment_holder .imgedit-wrap table td.imgedit-settings {
+ width: 250px;
+}
+
+td.imgedit-settings input {
+ margin-top: 0;
+ vertical-align: middle;
+}
+
+.imgedit-wait {
+ position: absolute;
+ top: 0;
+ background: #fff url(../images/wpspin_light.gif) no-repeat scroll 22px 10px;
+ background-size: 16px 16px;
+ opacity: 0.7;
+ filter: alpha(opacity=70);
+ width: 100%;
+ height: 500px;
+ display: none;
+}
+
+.spinner {
+ background: url(../images/wpspin_light.gif) no-repeat;
+ background-size: 16px 16px;
+ display: none;
+ float: right;
+ opacity: 0.7;
+ filter: alpha(opacity=70);
+ width: 16px;
+ height: 16px;
+ margin: 5px 5px 0;
+}
+
+.no-float {
+ float: none;
+}
+
+.media-disabled,
+.imgedit-settings .disabled {
+ color: grey;
+}
+
+.wp_attachment_image,
+.A1B1 {
+ overflow: hidden;
+}
+
+.wp_attachment_image .button,
+.A1B1 .button {
+ float: left;
+}
+
+.no-js .wp_attachment_image .button {
+ display: none;
+}
+
+.wp_attachment_image .spinner,
+.A1B1 .spinner {
+ float: left;
+ padding: 0 4px 4px;
+ vertical-align: bottom;
+}
+
+.imgedit-menu {
+ margin: 0 0 12px;
+ min-width: 300px;
+}
+
+.imgedit-menu div {
+ float: left;
+ width: 32px;
+ height: 32px;
+}
+
+.imgedit-crop-wrap {
+ position: relative;
+}
+
+.imgedit-crop {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -9px -31px;
+ margin: 0 8px 0 0;
+}
+
+.imgedit-crop.disabled:hover {
+ background-position: -9px -31px;
+}
+
+.imgedit-crop:hover {
+ background-position: -9px -1px;
+}
+
+.imgedit-rleft {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -46px -31px;
+ margin: 0 3px;
+}
+
+.imgedit-rleft.disabled:hover {
+ background-position: -46px -31px;
+}
+
+.imgedit-rleft:hover {
+ background-position: -46px -1px;
+}
+
+.imgedit-rright {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -77px -31px;
+ margin: 0 8px 0 3px;
+}
+
+.imgedit-rright.disabled:hover {
+ background-position: -77px -31px;
+}
+
+.imgedit-rright:hover {
+ background-position: -77px -1px;
+}
+
+.imgedit-flipv {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -115px -31px;
+ margin: 0 3px;
+}
+
+.imgedit-flipv.disabled:hover {
+ background-position: -115px -31px;
+}
+
+.imgedit-flipv:hover {
+ background-position: -115px -1px;
+}
+
+.imgedit-fliph {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -147px -31px;
+ margin: 0 8px 0 3px;
+}
+
+.imgedit-fliph.disabled:hover {
+ background-position: -147px -31px;
+}
+
+.imgedit-fliph:hover {
+ background-position: -147px -1px;
+}
+
+.imgedit-undo {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -184px -31px;
+ margin: 0 3px;
+}
+
+.imgedit-undo.disabled:hover {
+ background-position: -184px -31px;
+}
+
+.imgedit-undo:hover {
+ background-position: -184px -1px;
+}
+
+.imgedit-redo {
+ background: transparent url('../images/imgedit-icons.png') no-repeat scroll -215px -31px;
+ margin: 0 8px 0 3px;
+}
+
+.imgedit-redo.disabled:hover {
+ background-position: -215px -31px;
+}
+
+.imgedit-redo:hover {
+ background-position: -215px -1px;
+}
+
+.imgedit-applyto img {
+ margin: 0 8px 0 0;
+}
+
+.imgedit-group-top {
+ margin: 5px 0;
+}
+
+.imgedit-applyto .imgedit-label {
+ padding: 2px 0 0;
+ display: block;
+}
+
+.imgedit-help {
+ display: none;
+ font-style: italic;
+ margin-bottom: 8px;
+}
+
+a.imgedit-help-toggle {
+ text-decoration: none;
+}
+
+.form-table td.imgedit-response {
+ padding: 0;
+}
+
+.imgedit-submit {
+ margin: 8px 0;
+}
+
+.imgedit-submit-btn {
+ margin-left: 20px;
+}
+
+.imgedit-wrap .nowrap {
+ white-space: nowrap;
+}
+
+span.imgedit-scale-warn {
+ color: red;
+ font-size: 20px;
+ font-style: normal;
+ visibility: hidden;
+ vertical-align: middle;
+}
+
+.imgedit-group {
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ margin-bottom: 8px;
+ padding: 2px 10px;
+}
+
+/*------------------------------------------------------------------------------
+ 15.0 - Comments Screen
+------------------------------------------------------------------------------*/
+
+.form-table {
+ border-collapse: collapse;
+ margin-top: 0.5em;
+ width: 100%;
+ margin-bottom: -8px;
+ clear: both;
+}
+
+.form-table td {
+ margin-bottom: 9px;
+ padding: 8px 10px;
+ line-height: 20px;
+ font-size: 12px;
+}
+
+.form-table th,
+.form-wrap label {
+ font-weight: normal;
+ text-shadow: #fff 0 1px 0;
+}
+
+.form-table th {
+ vertical-align: top;
+ text-align: left;
+ padding: 10px;
+ width: 200px;
+}
+
+.form-table th.th-full {
+ width: auto;
+}
+
+.form-table div.color-option {
+ display: block;
+ clear: both;
+ margin-top: 12px;
+}
+
+.form-table input.tog {
+ margin-top: 2px;
+ margin-right: 2px;
+ float: left;
+}
+
+.form-table td p {
+ margin-top: 4px;
+}
+
+.form-table table.color-palette {
+ vertical-align: bottom;
+ float: left;
+ margin: -12px 3px 11px;
+}
+
+.form-table .color-palette td {
+ border-width: 1px 1px 0;
+ border-style: solid solid none;
+ height: 10px;
+ line-height: 20px;
+ width: 10px;
+}
+
+.commentlist li {
+ padding: 1em 1em .2em;
+ margin: 0;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+.commentlist li li {
+ border-bottom: 0;
+ padding: 0;
+}
+
+.commentlist p {
+ padding: 0;
+ margin: 0 0 .8em;
+}
+
+/* reply to comments */
+#replyrow input {
+ border-width: 1px;
+ border-style: solid;
+}
+
+#replyrow td {
+ padding: 2px;
+}
+
+#replysubmit {
+ margin: 0;
+ padding: 0 5px 3px;
+ text-align: center;
+}
+
+#replysubmit .spinner {
+ padding: 2px 0 0;
+ vertical-align: top;
+ float: right;
+}
+
+#replysubmit .button {
+ margin-right: 5px;
+}
+
+#replysubmit .error {
+ color: red;
+ line-height: 21px;
+ text-align: center;
+}
+
+#replyrow h5 {
+ margin: .2em 0 0;
+ padding: 0 5px;
+ line-height: 1.4em;
+ font-size: 1em;
+}
+
+#edithead .inside {
+ float: left;
+ padding: 3px 0 2px 5px;
+ margin: 0;
+ text-align: center;
+}
+
+#edithead .inside input {
+ width: 180px;
+}
+
+#edithead label {
+ padding: 2px 0;
+}
+
+#replycontainer {
+ padding: 5px;
+}
+
+#replycontent {
+ height: 120px;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.comment-php .wp-editor-area {
+ height: 200px;
+}
+
+.comment-ays {
+ margin-bottom: 0;
+ border-style: solid;
+ border-width: 1px;
+}
+
+.comment-ays th {
+ border-right-style: solid;
+ border-right-width: 1px;
+}
+
+.trash-undo-inside,
+.spam-undo-inside {
+ margin: 1px 8px 1px 0;
+ line-height: 16px;
+}
+
+.spam-undo-inside .avatar,
+.trash-undo-inside .avatar {
+ height: 20px;
+ width: 20px;
+ margin-right: 8px;
+ vertical-align: middle;
+}
+
+.stuffbox .editcomment {
+ clear: none;
+}
+
+#comment-status-radio p {
+ margin: 3px 0 5px;
+}
+
+#comment-status-radio input {
+ margin: 2px 3px 5px 0;
+ vertical-align: middle;
+}
+
+#comment-status-radio label {
+ padding: 5px 0;
+}
+
+.commentlist .avatar {
+ vertical-align: text-top;
+}
+
+
+/*------------------------------------------------------------------------------
+ 16.0 - Themes
+------------------------------------------------------------------------------*/
+
+.theme-install-php .tablenav {
+ height: auto;
+}
+
+.theme-install-php .spinner {
+ margin-top: 9px;
+}
+
+h3.available-themes {
+ margin: 0.3em 0 1em;
+ float: left;
+}
+
+.available-theme {
+ display: inline-block;
+ margin-right: 10px;
+ overflow: hidden;
+ padding: 20px 20px 20px 0;
+ vertical-align: top;
+ width: 300px;
+}
+
+.available-theme .screenshot {
+ width: 300px;
+ height: 225px;
+ display: block;
+ border-width: 1px;
+ border-style: solid;
+ margin-bottom: 10px;
+ overflow: hidden;
+}
+
+.available-theme img {
+ width: 300px;
+}
+
+.available-theme h3 {
+ margin: 15px 0 0;
+}
+
+.available-theme .theme-author {
+ line-height: 18px;
+}
+
+.available-theme .action-links {
+ margin-top: 10px;
+ overflow: hidden;
+}
+
+.available-theme a.screenshot:focus {
+ border-color: #777;
+}
+
+#current-theme .theme-info li,
+.theme-options li,
+.available-theme .action-links li {
+ float: left;
+ padding-right: 10px;
+ margin-right: 10px;
+ border-right: 1px solid #dfdfdf;
+}
+
+.available-theme .action-links li {
+ padding-right: 8px;
+ margin-right: 8px;
+}
+
+.ie8 .available-theme .action-links li {
+ padding-right: 7px;
+ margin-right: 7px;
+}
+
+#current-theme .theme-info li:last-child,
+.theme-options li:last-child,
+.available-theme .action-links li:last-child {
+ padding-right: 0;
+ margin-right: 0;
+ border-right: 0;
+}
+
+.available-theme .action-links .delete-theme {
+ float: right;
+ margin-left: 8px;
+ margin-right: 0;
+}
+
+.available-theme .action-links .delete-theme a {
+ color: red;
+ padding: 2px;
+}
+
+.available-theme .action-links .delete-theme a:hover {
+ background: red;
+ color: #fff;
+ text-decoration: none;
+}
+
+.available-theme .action-links p {
+ float: left;
+}
+
+#current-theme {
+ margin: 20px 0 10px;
+ padding: 0 0 20px;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ overflow: hidden;
+}
+
+#current-theme.has-screenshot {
+ padding-left: 330px;
+}
+
+#current-theme h3 {
+ margin: 0;
+ font-size: 12px;
+ font-weight: normal;
+ color: #999;
+}
+
+#current-theme h4 {
+ margin: 3px 0 16px;
+ font-size: 20px;
+}
+
+#current-theme h4 span {
+ margin-left: 20px;
+ font-size: 12px;
+ font-weight: normal;
+}
+
+#current-theme a {
+ border-bottom: none;
+}
+
+#current-theme .theme-info {
+ margin: 1em 0;
+ overflow: hidden;
+}
+
+#current-theme .theme-description {
+ margin-top: 5px;
+ max-width: 600px;
+ line-height: 1.6em;
+}
+
+#current-theme img {
+ float: left;
+ width: 300px;
+ margin-left: -330px;
+
+ border-width: 1px;
+ border-style: solid;
+}
+
+.theme-options {
+ overflow: hidden;
+ font-size: 14px;
+ padding-bottom: 10px;
+}
+
+.theme-options .load-customize {
+ margin-right: 30px;
+ float: left;
+}
+
+.theme-options span {
+ float: left;
+ margin-right: 10px;
+ text-transform: uppercase;
+ font-size: 11px;
+ line-height: 18px;
+ color: #999;
+}
+
+.theme-options ul {
+ float: left;
+ margin: 0;
+}
+
+/* Allow for three-up in small windows when sidebar is collapsed */
+@media only screen and (max-width: 1200px) {
+ .folded .available-theme,
+ .folded .available-theme .screenshot {
+ width: 300px;
+ }
+
+ .folded .available-theme .screenshot {
+ height: 225px;
+ }
+
+ .folded #current-theme img {
+ width: 300px;
+ }
+
+ .folded #current-theme.has-screenshot {
+ padding-left: 330px;
+ }
+
+ .folded #current-theme img {
+ margin-left: -330px;
+ }
+}
+
+/* Adjust three-up display in smaller windows when sidebar is collapsed */
+@media only screen and (max-width: 1079px) {
+ .folded .available-theme,
+ .folded .available-theme .screenshot {
+ width: 270px;
+ }
+
+ .folded .available-theme .screenshot {
+ height: 203px;
+ }
+
+ .folded #current-theme img {
+ width: 270px;
+ }
+
+ .folded #current-theme.has-screenshot {
+ padding-left: 300px;
+ }
+
+ .folded #current-theme img {
+ margin-left: -300px;
+ }
+}
+
+/* Allow for three-up on 1024px wide screens, e.g. tablets */
+@media only screen and (max-width: 1200px) {
+ .available-theme,
+ .available-theme .screenshot,
+ #current-theme img {
+ width: 240px;
+ }
+
+ .available-theme .screenshot {
+ height: 180px;
+ }
+
+ .available-theme img {
+ width: 100%;
+ }
+
+ #current-theme.has-screenshot {
+ padding-left: 270px;
+ }
+
+ #current-theme img {
+ margin-left: -270px;
+ }
+}
+
+#post-body ul.add-menu-item-tabs li.tabs a,
+#TB_window #TB_title a.tb-theme-preview-link,
+#TB_window #TB_title a.tb-theme-preview-link:visited {
+ font-weight: bold;
+ text-decoration: none;
+}
+
+#TB_window #TB_title {
+ background-color: #222;
+ color: #cfcfcf;
+}
+
+#broken-themes {
+ text-align: left;
+ width: 50%;
+ border-spacing: 3px;
+ padding: 3px;
+}
+
+.theme-install-php h4 {
+ margin: 2.5em 0 8px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 16.1 - Custom Header Screen
+------------------------------------------------------------------------------*/
+
+.appearance_page_custom-header #headimg {
+ border: 1px solid #DFDFDF;
+ overflow: hidden;
+ width: 100%;
+}
+
+.appearance_page_custom-header #upload-form p label {
+ font-size: 12px;
+}
+
+.appearance_page_custom-header .available-headers .default-header {
+ float: left;
+ margin: 0 20px 20px 0;
+}
+
+.appearance_page_custom-header .random-header {
+ clear: both;
+ margin: 0 20px 20px 0;
+ vertical-align: middle;
+}
+
+.appearance_page_custom-header .available-headers label input,
+.appearance_page_custom-header .random-header label input {
+ margin-right: 10px;
+}
+
+.appearance_page_custom-header .available-headers label img {
+ vertical-align: middle;
+}
+
+
+/*------------------------------------------------------------------------------
+ 16.2 - Custom Background Screen
+------------------------------------------------------------------------------*/
+
+div#custom-background-image {
+ min-height: 100px;
+ border: 1px solid #dfdfdf;
+}
+
+div#custom-background-image img {
+ max-width: 400px;
+ max-height: 300px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 16.3 - Tabbed Admin Screen Interface (Experimental)
+------------------------------------------------------------------------------*/
+
+.nav-tab {
+ border-style: solid;
+ border-width: 1px 1px 0;
+ color: #aaa;
+ text-shadow: #fff 0 1px 0;
+ font-size: 12px;
+ line-height: 16px;
+ display: inline-block;
+ padding: 4px 14px 6px;
+ text-decoration: none;
+ margin: 0 6px -1px 0;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+.nav-tab-active {
+ border-width: 1px;
+ color: #464646;
+}
+
+h2.nav-tab-wrapper, h3.nav-tab-wrapper {
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ padding-bottom: 0;
+}
+
+h2 .nav-tab {
+ padding: 4px 10px 6px;
+ font-weight: 200;
+ font-size: 20px;
+ line-height: 24px;
+
+}
+
+
+/*------------------------------------------------------------------------------
+ 17.0 - Plugins
+------------------------------------------------------------------------------*/
+
+#dashboard_right_now .versions .b,
+#post-status-display,
+#post-visibility-display,
+#adminmenu .wp-submenu li.current,
+#adminmenu .wp-submenu li.current a,
+#adminmenu .wp-submenu li.current a:hover,
+.media-item .percent,
+.plugins .name,
+#pass-strength-result.strong,
+#pass-strength-result.short,
+#ed_reply_toolbar #ed_reply_strong,
+.item-controls .item-order a,
+.feature-filter .feature-name {
+ font-weight: bold;
+}
+
+.plugins p {
+ margin: 0 4px;
+ padding: 0;
+}
+
+.plugins .desc p {
+ margin: 0 0 8px;
+}
+
+.plugins td.desc {
+ line-height: 1.5em;
+}
+
+.plugins .desc ul,
+.plugins .desc ol {
+ margin: 0 0 0 2em;
+}
+
+.plugins .desc ul {
+ list-style-type: disc;
+}
+
+.plugins .row-actions-visible {
+ padding: 0;
+}
+
+.plugins tbody th.check-column {
+ padding: 7px 0;
+}
+
+.plugins .inactive td,
+.plugins .inactive th,
+.plugins .active td,
+.plugins .active th {
+ border-top-style: solid;
+ border-top-width: 1px;
+ padding: 5px 7px 0;
+}
+
+.plugins .update th,
+.plugins .update td {
+ border-bottom: 0;
+}
+.plugin-update-tr td {
+ border-top: 0;
+}
+
+#wpbody-content .plugins .plugin-title,
+#wpbody-content .plugins .theme-title {
+ padding-right: 12px;
+ white-space:nowrap;
+}
+
+.plugins .second,
+.plugins .row-actions-visible {
+ padding: 0 0 5px;
+}
+
+.plugins .update .second,
+.plugins .update .row-actions-visible {
+ padding-bottom: 0;
+}
+
+.plugins-php .widefat tfoot th,
+.plugins-php .widefat tfoot td {
+ border-top-style: solid;
+ border-top-width: 1px;
+}
+
+.plugin-update-tr .update-message {
+ margin: 5px;
+ padding: 3px 5px;
+}
+
+.plugin-install-php h4 {
+ margin: 2.5em 0 8px;
+}
+
+
+/*------------------------------------------------------------------------------
+ 18.0 - Users
+------------------------------------------------------------------------------*/
+
+#profile-page .form-table textarea {
+ width: 500px;
+ margin-bottom: 6px;
+}
+
+#profile-page .form-table #rich_editing {
+ margin-right: 5px
+}
+
+#your-profile legend {
+ font-size: 22px;
+}
+
+#your-profile #rich_editing {
+ border: none;
+}
+
+#display_name {
+ width: 15em;
+}
+
+#createuser .form-field input {
+ width: 25em;
+}
+
+/*------------------------------------------------------------------------------
+ 19.0 - Tools
+------------------------------------------------------------------------------*/
+
+.pressthis {
+ margin: 20px 0;
+}
+
+.pressthis a,
+.pressthis a:hover,
+.pressthis a:focus,
+.pressthis a:active {
+ display: inline-block;
+ position: relative;
+ cursor: move;
+ color: #333;
+ background: #e6e6e6;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(7%, #e6e6e6), color-stop(77%, #d8d8d8));
+ background-image: -webkit-linear-gradient(bottom, #e6e6e6 7%, #d8d8d8 77%);
+ background-image: -moz-linear-gradient(bottom, #e6e6e6 7%, #d8d8d8 77%);
+ background-image: -o-linear-gradient(bottom, #e6e6e6 7%, #d8d8d8 77%);
+ background-image: linear-gradient(to top, #e6e6e6 7%, #d8d8d8 77%);
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ border: 1px solid #b4b4b4;
+ font-style: normal;
+ line-height: 16px;
+ font-size: 14px;
+ text-decoration: none;
+ text-shadow: 0 1px 0px #fff;
+}
+
+.pressthis a:active {
+ outline: none;
+}
+
+.pressthis a:hover:after {
+ -webkit-transform: skew(20deg) rotate(9deg);
+ -moz-transform: skew(20deg) rotate(9deg);
+ transform: skew(20deg) rotate(9deg);
+ -webkit-box-shadow: 0 10px 8px rgba(0, 0, 0, 0.7);
+ box-shadow: 0 10px 8px rgba(0, 0, 0, 0.7);
+}
+
+.pressthis a span {
+ background: url(../images/press-this.png?v=20120502) no-repeat 0px 5px;
+ background-size: 24px 20px;
+ padding: 8px 11px 8px 27px;
+ margin: 0 5px;
+ display: inline-block;
+}
+
+.pressthis a:after {
+ content: '';
+ width: 70%;
+ height: 55%;
+ z-index: -1;
+ position: absolute;
+ right: 10px;
+ bottom: 9px;
+ background: transparent;
+
+ -webkit-transform: skew(20deg) rotate(6deg);
+ -moz-transform: skew(20deg) rotate(6deg);
+ transform: skew(20deg) rotate(6deg);
+ -webkit-box-shadow: 0 10px 8px rgba(0, 0, 0, 0.6);
+ box-shadow: 0 10px 8px rgba(0, 0, 0, 0.6);
+}
+
+/*------------------------------------------------------------------------------
+ 20.0 - Settings
+------------------------------------------------------------------------------*/
+
+#utc-time, #local-time {
+ padding-left: 25px;
+ font-style: italic;
+ font-family: sans-serif;
+}
+
+.defaultavatarpicker .avatar {
+ margin: 2px 0;
+ vertical-align: middle;
+}
+
+.options-general-php .spinner {
+ float: none;
+ margin: -3px 3px;
+}
+
+/*------------------------------------------------------------------------------
+ 21.0 - Admin Footer
+------------------------------------------------------------------------------*/
+
+#wpfooter {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ padding: 10px 0;
+ margin-right: 20px;
+ border-top-width: 1px;
+ border-top-style: solid;
+}
+
+#wpfooter p {
+ margin: 0;
+ line-height: 20px;
+}
+
+#wpfooter a {
+ text-decoration: none;
+}
+
+#wpfooter a:hover {
+ text-decoration: underline;
+}
+
+/*------------------------------------------------------------------------------
+ 22.0 - About Pages
+------------------------------------------------------------------------------*/
+
+.about-wrap {
+ position: relative;
+ margin: 25px 40px 0 20px;
+ max-width: 1050px; /* readability */
+
+ font-size: 15px;
+}
+
+.about-wrap div.updated,
+.about-wrap div.error {
+ display: none !important;
+}
+
+/* Typography */
+
+.about-wrap p {
+ line-height: 1.6em;
+}
+
+.about-wrap h1 {
+ margin: 0.2em 200px 0 0;
+ line-height: 1.2em;
+ font-size: 2.8em;
+ font-weight: 200;
+}
+
+.about-text,
+.about-description,
+.about-wrap li.wp-person a.web {
+ font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", sans-serif;
+ font-weight: normal;
+ line-height: 1.6em;
+ font-size: 20px;
+}
+
+.about-description {
+ margin-top: 1.4em;
+}
+
+.about-text {
+ margin: 1em 200px 1.4em 0;
+ min-height: 60px;
+ font-size: 24px;
+}
+
+.about-wrap h3 {
+ font-size: 24px;
+ margin-bottom: 1em;
+ padding-top: 20px;
+}
+
+.about-wrap .feature-section {
+ padding-bottom: 20px;
+}
+
+.about-wrap .feature-section h4 {
+ margin-bottom: 0.6em;
+}
+
+.about-wrap .feature-section p {
+ margin-top: 0.6em;
+}
+
+.about-wrap code {
+ font-size: 14px;
+}
+
+/* Point Releases */
+
+.about-wrap .point-releases {
+ margin-top: 5px;
+}
+
+.about-wrap .changelog.point-releases h3 {
+ padding-top: 35px;
+}
+
+.about-wrap .changelog.point-releases h3:first-child {
+ padding-top: 7px;
+}
+
+/* WordPress Version Badge */
+
+.wp-badge {
+ padding-top: 142px;
+ height: 50px;
+ width: 173px;
+ font-weight: bold;
+ font-size: 14px;
+ text-align: center;
+ margin: 0 -5px;
+ background: url('../images/wp-badge.png?ver=20111120') no-repeat;
+}
+
+.about-wrap .wp-badge {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+
+/* Tabs */
+
+.about-wrap h2.nav-tab-wrapper {
+ padding-left: 6px;
+}
+
+.about-wrap h2 .nav-tab {
+ padding: 4px 10px 6px;
+ margin: 0 3px -1px 0;
+ font-size: 18px;
+ vertical-align: top;
+}
+
+.about-wrap h2 .nav-tab-active {
+ font-weight: bold;
+ padding-top: 3px;
+}
+
+/* Changelog / Update screen */
+
+.about-wrap .feature-section img,
+.about-wrap .feature-section .video {
+ border: none;
+ margin: 0 1.94% 10px 0;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.about-wrap .feature-section .video video {
+ max-width: 100%;
+}
+
+.about-wrap .feature-section.three-col img {
+ margin: 0.5em 0 0.5em 5px;
+ max-width: 100%;
+ float: none;
+}
+
+.ie8 .about-wrap .feature-section.three-col img {
+ margin-left: 0;
+}
+
+.about-wrap .feature-section.images-stagger-right img,
+.about-wrap .feature-section.images-stagger-right .video {
+ float: right;
+ margin: 0 5px 12px 2em;
+}
+
+.about-wrap .feature-section.images-stagger-left img {
+ float: left;
+ margin: 0 2em 12px 5px;
+}
+
+.about-wrap .feature-section .image-100 {
+ margin: 0 0 2em 0;
+ width: 100%;
+}
+
+.about-wrap .feature-section .image-66 {
+ width: 65%;
+}
+
+.about-wrap .feature-section .image-66.video {
+ max-width: 600px;
+}
+
+.about-wrap .feature-section .image-50 {
+ max-width: 50%;
+}
+
+.about-wrap .feature-section img.image-30 {
+ max-width: 31.2381%;
+}
+
+.ie8 .about-wrap .feature-section img {
+ border-width: 1px;
+ border-style: solid;
+}
+
+.about-wrap .images-stagger-right img.image-30:nth-child(2) {
+ margin-left: 1em;
+}
+
+.about-wrap .feature-section.col {
+ margin-bottom: 0;
+}
+
+.about-wrap .feature-section.col h4 {
+ margin: 0 0 0.6em 0;
+}
+
+.about-wrap .feature-section.col .last-feature {
+ margin-right: 0;
+}
+
+.about-wrap .feature-section.two-col div {
+ width: 47%;
+ margin-right: 4.999999999%;
+ float: left;
+}
+
+.about-wrap .feature-section.three-col div {
+ width: 30%;
+ margin-right: 4.999999999%;
+ float: left;
+}
+
+.about-wrap .three-col-images {
+ text-align: center;
+}
+
+.about-wrap .three-col-images img {
+ margin: 0 0 10px;
+}
+
+.about-wrap .three-col-images .last-feature {
+ float: right;
+}
+
+.about-wrap .three-col-images .first-feature {
+ float: left;
+}
+
+.about-wrap .changelog .feature-section {
+ overflow: hidden;
+}
+
+.about-wrap .changelog li {
+ list-style-type: disc;
+ margin-left: 3em;
+}
+
+@media only screen and (max-width: 900px) {
+ .about-wrap .feature-section.images-stagger-left img,
+ .about-wrap .feature-section.images-stagger-right img,
+ .about-wrap .feature-section.images-stagger-right .video {
+ clear: both;
+ }
+
+ .about-wrap .feature-section .video.image-66 {
+ float: none;
+ width: 98%;
+ max-width: 98%;
+ }
+
+ .about-wrap .feature-section.images-stagger-right .video.image-66 {
+ margin-left: 3px;
+ }
+}
+
+@media only screen and (max-width: 768px) {
+ .about-wrap .feature-section .image-66 {
+ float: none;
+ width: 98%;
+ max-width: 98%;
+ }
+
+ .about-wrap .feature-section.images-stagger-right .image-66 {
+ margin-left: 3px;
+ }
+
+ .about-wrap .feature-section.images-stagger-left .image-66 {
+ margin-right: 3px;
+ }
+}
+
+/* Return to Dashboard Home link */
+
+.about-wrap .return-to-dashboard {
+ margin: 30px 0 0 -5px;
+ font-size: 14px;
+ font-weight: bold;
+}
+
+.about-wrap .return-to-dashboard a {
+ text-decoration: none;
+ padding: 0 5px;
+}
+
+/* Credits */
+
+.about-wrap h4.wp-people-group {
+ margin-top: 2.6em;
+ font-size: 16px;
+}
+
+.about-wrap ul.wp-people-group {
+ overflow: hidden;
+ padding: 0 5px;
+ margin: 0 -15px 0 -5px;
+}
+
+.about-wrap ul.compact {
+ margin-bottom: 0
+}
+
+.about-wrap li.wp-person {
+ float: left;
+ margin-right: 10px;
+}
+
+.about-wrap li.wp-person img.gravatar {
+ float: left;
+ margin: 0 10px 10px 0;
+ padding: 2px;
+ width: 60px;
+ height: 60px;
+}
+
+.about-wrap ul.compact li.wp-person img.gravatar {
+ width: 30px;
+ height: 30px;
+}
+
+.about-wrap li.wp-person {
+ height: 70px;
+ width: 280px;
+ padding-bottom: 15px;
+}
+
+.about-wrap ul.compact li.wp-person {
+ height: auto;
+ width: 180px;
+ padding-bottom: 0;
+ margin-bottom: 0;
+}
+
+.about-wrap #wp-people-group-validators + p.wp-credits-list {
+ margin-top: 0;
+}
+
+.about-wrap li.wp-person a.web {
+ display: block;
+ margin: 6px 0 2px;
+ font-size: 16px;
+ text-decoration: none;
+}
+
+.about-wrap p.wp-credits-list a {
+ white-space: nowrap;
+}
+
+/* Freedoms */
+
+.freedoms-php .about-wrap ol {
+ margin: 40px 60px;
+}
+
+.freedoms-php .about-wrap ol li {
+ list-style-type: decimal;
+ font-weight: bold;
+}
+
+.freedoms-php .about-wrap ol p {
+ font-weight: normal;
+ margin: 0.6em 0;
+}
+
+/*------------------------------------------------------------------------------
+ 23.0 - Full Overlay w/ Sidebar
+------------------------------------------------------------------------------*/
+
+body.full-overlay-active {
+ overflow: hidden;
+}
+
+.wp-full-overlay {
+ background: #fff;
+ z-index: 500000;
+ position: fixed;
+ overflow: visible;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100%;
+ min-width: 0;
+}
+
+.wp-full-overlay-sidebar {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+
+ position: fixed;
+ width: 300px;
+ height: 100%;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ padding: 0;
+ margin: 0;
+ z-index: 10;
+ overflow: auto;
+ background: #f5f5f5;
+ border-right: 1px solid rgba( 0, 0, 0, 0.2 );
+}
+
+.wp-full-overlay.collapsed .wp-full-overlay-sidebar {
+ overflow: visible;
+}
+
+.wp-full-overlay.collapsed,
+.wp-full-overlay.expanded .wp-full-overlay-sidebar {
+ margin-left: 0 !important;
+}
+
+.wp-full-overlay.expanded {
+ margin-left: 300px;
+}
+
+.wp-full-overlay.collapsed .wp-full-overlay-sidebar {
+ margin-left: -300px;
+}
+
+.wp-full-overlay-sidebar:after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ width: 3px;
+ box-shadow: -5px 0 4px -4px rgba(0, 0, 0, 0.1) inset;
+ z-index: 1000;
+}
+
+.wp-full-overlay-main {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ height: 100%;
+}
+
+.wp-full-overlay-sidebar .wp-full-overlay-header {
+ position: absolute;
+ left: 0;
+ right: 0;
+ height: 45px;
+ padding: 0 20px;
+ line-height: 45px;
+ z-index: 10;
+ margin: 0;
+}
+
+.wp-full-overlay-sidebar .wp-full-overlay-header {
+ border-top: 0;
+ border-bottom: 1px solid #fff;
+ box-shadow: inset 0 -1px 0 0px #dfdfdf;
+}
+
+.wp-full-overlay-sidebar .wp-full-overlay-footer {
+ bottom: 0;
+ border-bottom: 0;
+ border-top: 1px solid #dfdfdf;
+ box-shadow: inset 0 1px 0 0px #fff;
+}
+
+.wp-full-overlay-sidebar .wp-full-overlay-sidebar-content {
+ position: absolute;
+ top: 45px;
+ bottom: 45px;
+ left: 0;
+ right: 0;
+ overflow: auto;
+}
+
+.wp-full-overlay-sidebar-content .accordion-section:first-child {
+ border-top: 1px solid #fff;
+}
+
+/* Close Link */
+.wp-full-overlay .close-full-overlay {
+ text-decoration: none;
+}
+
+/* Collapse Button */
+.wp-full-overlay a.collapse-sidebar {
+ position: absolute;
+ bottom: 12px;
+ left: 0;
+ z-index: 50;
+ display: block;
+ width: 19px;
+ height: 19px;
+ margin-left: 15px;
+ padding: 0;
+ border-radius: 50%;
+ text-decoration: none;
+}
+
+.wp-full-overlay.collapsed .collapse-sidebar {
+ position: absolute;
+ left: 100%;
+}
+
+.wp-full-overlay .collapse-sidebar-arrow {
+ position: absolute;
+ margin-top: 2px;
+ margin-left: 2px;
+ display: block;
+ width: 15px;
+ height: 15px;
+ background: transparent url('../images/arrows.png') no-repeat -1px -73px;
+}
+
+.wp-full-overlay.collapsed .collapse-sidebar-arrow {
+ background-position: -1px -109px;
+}
+
+.wp-full-overlay .collapse-sidebar-label {
+ position: absolute;
+ left: 100%;
+ color: #808080;
+ line-height: 20px;
+ margin-left: 10px;
+}
+
+.wp-full-overlay.collapsed .collapse-sidebar-label {
+ display: none;
+}
+
+.wp-full-overlay .collapse-sidebar:hover .collapse-sidebar-label {
+ color: #666;
+}
+
+/* Animations */
+.wp-full-overlay,
+.wp-full-overlay-sidebar,
+.wp-full-overlay .collapse-sidebar,
+.wp-full-overlay-main {
+ -webkit-transition-property: left, right, top, bottom, width, margin;
+ -moz-transition-property: left, right, top, bottom, width, margin;
+ -ms-transition-property: left, right, top, bottom, width, margin;
+ -o-transition-property: left, right, top, bottom, width, margin;
+ transition-property: left, right, top, bottom, width, margin;
+
+ -webkit-transition-duration: 0.2s;
+ -moz-transition-duration: 0.2s;
+ -ms-transition-duration: 0.2s;
+ -o-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+}
+
+
+/*------------------------------------------------------------------------------
+ 24.0 - Customize Loader
+------------------------------------------------------------------------------*/
+
+.no-customize-support .hide-if-no-customize,
+.customize-support .hide-if-customize,
+.no-customize-support.wp-core-ui .hide-if-no-customize,
+.no-customize-support .wp-core-ui .hide-if-no-customize,
+.customize-support.wp-core-ui .hide-if-customize,
+.customize-support .wp-core-ui .hide-if-customize {
+ display: none;
+}
+
+#customize-container {
+ display: none;
+ background: #fff;
+ z-index: 500000;
+ position: fixed;
+ overflow: visible;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 100%;
+}
+
+.customize-active #customize-container {
+ display: block;
+}
+
+.customize-loading #customize-container iframe {
+ opacity: 0;
+}
+
+.customize-loading #customize-container {
+ background: #fff url("../images/wpspin_light.gif") no-repeat fixed center center;
+ background-size: 16px 16px;
+}
+
+#customize-container iframe,
+#theme-installer iframe {
+ height: 100%;
+ width: 100%;
+ z-index: 20;
+
+ -webkit-transition: opacity 0.3s;
+ -moz-transition: opacity 0.3s;
+ -ms-transition: opacity 0.3s;
+ -o-transition: opacity 0.3s;
+ transition: opacity 0.3s;
+}
+
+#customize-container .collapse-sidebar {
+ bottom: 16px;
+}
+
+#theme-installer {
+ display: none;
+}
+
+#theme-installer.single-theme {
+ display: block;
+}
+
+.install-theme-info {
+ display: none;
+ padding: 10px 20px 20px;
+}
+
+.single-theme .install-theme-info {
+ padding-top: 15px;
+}
+
+#theme-installer .install-theme-info {
+ display: block;
+}
+
+.install-theme-info .theme-install {
+ float: right;
+ margin-top: 18px;
+}
+
+.install-theme-info .theme-name {
+ font-size: 16px;
+ line-height: 24px;
+ margin-bottom: 0;
+}
+
+.install-theme-info .theme-screenshot {
+ margin-top: 15px;
+ width: 258px;
+ border: 1px solid #ccc;
+}
+
+.install-theme-info .theme-details {
+ overflow: hidden;
+}
+
+.theme-details .theme-version {
+ margin: 15px 0;
+ float: left;
+}
+
+.theme-details .star-holder {
+ margin: 14px 0;
+ float: right;
+}
+
+.theme-details .theme-description {
+ float: left;
+ color: #777;
+ line-height: 20px;
+}
+
+/*------------------------------------------------------------------------------
+ 25.0 - Misc
+------------------------------------------------------------------------------*/
+
+#excerpt,
+.attachmentlinks {
+ margin: 0;
+ height: 4em;
+ width: 98%;
+}
+
+#template div {
+ margin-right: 190px;
+}
+
+p.pagenav {
+ margin: 0;
+ display: inline;
+}
+
+.pagenav span {
+ font-weight: bold;
+ margin: 0 6px;
+}
+
+.row-title {
+ font-size: 13px !important;
+ font-weight: bold;
+}
+
+.column-author img, .column-username img {
+ float: left;
+ margin-right: 10px;
+ margin-top: 1px;
+}
+
+.row-actions {
+ visibility: hidden;
+ padding: 2px 0 0;
+}
+
+.mobile .row-actions {
+ visibility: visible;
+}
+
+tr:hover .row-actions,
+div.comment-item:hover .row-actions {
+ visibility: visible;
+}
+
+.row-actions-visible {
+ padding: 2px 0 0;
+}
+
+.form-table .pre {
+ padding: 8px;
+ margin: 0;
+}
+
+table.form-table td .updated {
+ font-size: 13px;
+}
+
+.tagchecklist {
+ margin-left: 14px;
+ font-size: 12px;
+ overflow: auto;
+}
+.tagchecklist strong {
+ margin-left: -8px;
+ position: absolute;
+}
+.tagchecklist span {
+ margin-right: 25px;
+ display: block;
+ float: left;
+ font-size: 11px;
+ line-height: 1.8em;
+ white-space: nowrap;
+ cursor: default;
+}
+.tagchecklist span a {
+ margin: 6px 0pt 0pt -9px;
+ cursor: pointer;
+ width: 10px;
+ height: 10px;
+ display: block;
+ float: left;
+ text-indent: -9999px;
+ overflow: hidden;
+ position: absolute;
+}
+
+#poststuff h2 {
+ margin-top: 20px;
+ font-size: 1.5em;
+ margin-bottom: 15px;
+ padding: 0 0 3px;
+ clear: left;
+}
+
+#poststuff h3,
+.metabox-holder h3 {
+ font-size: 15px;
+ font-weight: normal;
+ padding: 7px 10px;
+ margin: 0;
+ line-height: 1;
+}
+
+#poststuff .inside {
+ margin: 6px 0 8px;
+}
+
+#poststuff .inside #parent_id,
+#poststuff .inside #page_template {
+ max-width: 100%;
+}
+
+.inline-edit-row #post_parent,
+.inline-edit-row select[name="page_template"] {
+ max-width: 80%;
+}
+
+.ie8 #poststuff .inside #parent_id,
+.ie8 #poststuff .inside #page_template,
+.ie8 .inline-edit-row #post_parent,
+.ie8 .inline-edit-row select[name="page_template"] {
+ width: 250px;
+}
+
+#post-visibility-select {
+ line-height: 1.5em;
+ margin-top: 3px;
+}
+
+#poststuff #submitdiv .inside {
+ margin: 0;
+ padding: 0;
+}
+
+.edit-form-section {
+ margin-bottom: 20px;
+}
+
+#templateside ul li a {
+ text-decoration: none;
+}
+
+.tool-box .title {
+ margin: 8px 0;
+ font-size: 18px;
+ font-weight: normal;
+ line-height: 24px;
+}
+
+#sidemenu {
+ margin: -30px 15px 0 315px;
+ list-style: none;
+ position: relative;
+ float: right;
+ padding-left: 10px;
+ font-size: 12px;
+}
+
+#sidemenu a {
+ padding: 0 7px;
+ display: block;
+ float: left;
+ line-height: 28px;
+ border-top-width: 1px;
+ border-top-style: solid;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+}
+
+#sidemenu li {
+ display: inline;
+ line-height: 200%;
+ list-style: none;
+ text-align: center;
+ white-space: nowrap;
+ margin: 0;
+ padding: 0;
+}
+
+#sidemenu a.current {
+ font-weight: normal;
+ padding-left: 6px;
+ padding-right: 6px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-width: 1px;
+ border-style: solid;
+}
+
+#sidemenu li a .count-0 {
+ display: none;
+}
+
+.plugin-install #description,
+.plugin-install-network #description {
+ width: 60%;
+}
+
+table .vers,
+table .column-visible,
+table .column-rating {
+ text-align: left;
+}
+
+.error-message {
+ color: red;
+ font-weight: bold;
+}
+
+/* Scrollbar fix for bulk upgrade iframe */
+body.iframe {
+ height: 98%;
+}
+
+
+/* - Only used once or twice in all of WP - deprecate for global style
+------------------------------------------------------------------------------*/
+td.media-icon {
+ text-align: center;
+ width: 80px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+}
+
+td.media-icon img {
+ max-width: 80px;
+ max-height: 60px;
+}
+
+#howto {
+ font-size: 11px;
+ margin: 0 5px;
+ display: block;
+}
+
+.importers td {
+ padding-right: 14px;
+}
+
+.importers {
+ font-size: 16px;
+ width: auto;
+}
+
+#namediv table {
+ width: 100%;
+}
+
+#namediv td.first {
+ width: 10px;
+ white-space: nowrap;
+}
+
+#namediv input {
+ width: 98%;
+}
+
+#namediv p {
+ margin: 10px 0;
+}
+
+#submitdiv h3 {
+ margin-bottom: 0 !important;
+}
+
+/* - Used - but could/should be deprecated with a CSS reset
+------------------------------------------------------------------------------*/
+.zerosize {
+ height: 0;
+ width: 0;
+ margin: 0;
+ border: 0;
+ padding: 0;
+ overflow: hidden;
+ position: absolute;
+}
+
+br.clear {
+ height: 2px;
+ line-height: 2px;
+}
+
+.checkbox {
+ border: none;
+ margin: 0;
+ padding: 0;
+}
+
+fieldset {
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+.post-categories {
+ display: inline;
+ margin: 0;
+ padding: 0;
+}
+
+.post-categories li {
+ display: inline;
+}
+
+
+/*-----------------------------------------------------------------------------
+ MERGED
+-------------------------------------------------------------------------------*/
+
+/* dashboard */
+.edit-box {
+ display: none;
+}
+
+h3:hover .edit-box {
+ display: inline;
+}
+
+#dashboard-widgets form .input-text-wrap input {
+ width: 100%;
+}
+
+#dashboard-widgets form .textarea-wrap textarea {
+ width: 100%;
+}
+
+#dashboard-widgets .postbox form .submit {
+ float: none;
+ margin: .5em 0 0;
+ padding: 0;
+ border: none;
+}
+
+#dashboard-widgets-wrap #dashboard-widgets .postbox form .submit #publish {
+ min-width: 0;
+}
+
+#dashboard-widgets a {
+ text-decoration: none;
+}
+
+#dashboard-widgets h3 a {
+ text-decoration: underline;
+}
+
+#dashboard-widgets h3 .postbox-title-action {
+ position: absolute;
+ right: 10px;
+ padding: 0;
+ top: 5px;
+}
+
+.js #dashboard-widgets h3 .postbox-title-action {
+ right: 30px;
+}
+
+#dashboard-widgets h4 {
+ font-weight: normal;
+ font-size: 13px;
+ margin: 0 0 .2em;
+ padding: 0;
+}
+
+/* Right Now */
+#dashboard_right_now p.sub,
+#dashboard_right_now .table, #dashboard_right_now .versions {
+ margin: -12px;
+}
+
+#dashboard_right_now .inside {
+ font-size: 12px;
+ padding-top: 20px;
+}
+
+#dashboard_right_now p.sub {
+ padding: 5px 0 15px;
+ color: #8f8f8f;
+ font-size: 14px;
+ position: absolute;
+ top: -17px;
+ left: 15px;
+}
+
+#dashboard_right_now .table {
+ margin: 0;
+ padding: 0;
+ position: relative;
+}
+
+#dashboard_right_now .table_content {
+ float: left;
+ border-top-width: 1px;
+ border-top-style: solid;
+ width: 45%;
+}
+
+#dashboard_right_now .table_discussion {
+ float: right;
+ border-top-width: 1px;
+ border-top-style: solid;
+ width: 45%;
+}
+
+#dashboard_right_now table td {
+ padding: 3px 0;
+ white-space: nowrap;
+}
+
+#dashboard_right_now table tr.first td {
+ border-top: none;
+}
+
+#dashboard_right_now td.b {
+ padding-right: 6px;
+ text-align: right;
+ font-size: 14px;
+ width: 1%;
+}
+
+#dashboard_right_now td.b a {
+ font-size: 18px;
+}
+
+#dashboard_right_now td.b a:hover {
+ color: #d54e21;
+}
+
+#dashboard_right_now .t {
+ font-size: 12px;
+ padding-right: 12px;
+ padding-top: 6px;
+ color: #777;
+}
+
+#dashboard_right_now .t a {
+ white-space: nowrap;
+}
+
+#dashboard_right_now .spam {
+ color: red;
+}
+
+#dashboard_right_now .waiting {
+ color: #e66f00;
+}
+
+#dashboard_right_now .approved {
+ color: green;
+}
+
+#dashboard_right_now .versions {
+ padding: 6px 10px 12px;
+ clear: both;
+}
+
+#dashboard_right_now a.button {
+ float: right;
+ clear: right;
+ position: relative;
+ top: -5px;
+}
+
+/* Recent Comments */
+#dashboard_recent_comments h3 {
+ margin-bottom: 0;
+}
+
+#dashboard_recent_comments .inside {
+ margin-top: 0;
+}
+
+#dashboard_recent_comments .comment-meta .approve {
+ font-style: italic;
+ font-family: sans-serif;
+ font-size: 10px;
+}
+
+#dashboard_recent_comments .subsubsub {
+ float: none;
+ white-space: normal;
+}
+
+#the-comment-list {
+ position: relative;
+}
+
+#the-comment-list .comment-item {
+ padding: 1em 10px;
+ border-top: 1px solid;
+}
+
+#the-comment-list .pingback {
+ padding-left: 9px !important;
+}
+
+#the-comment-list .comment-item,
+#the-comment-list #replyrow {
+ margin: 0 -10px;
+}
+
+#the-comment-list .comment-item:first-child {
+ border-top: none;
+}
+
+#the-comment-list .comment-item .avatar {
+ float: left;
+ margin: 0 10px 5px 0;
+}
+
+#the-comment-list .comment-item h4 {
+ line-height: 1.7em;
+ margin-top: -0.4em;
+ color: #777;
+}
+
+#the-comment-list .comment-item h4 cite {
+ font-style: normal;
+ font-weight: normal;
+}
+
+#the-comment-list .comment-item blockquote,
+#the-comment-list .comment-item blockquote p {
+ margin: 0;
+ padding: 0;
+ display: inline;
+}
+
+#dashboard_recent_comments #the-comment-list .trackback blockquote,
+#dashboard_recent_comments #the-comment-list .pingback blockquote {
+ display: block;
+}
+
+#the-comment-list .comment-item p.row-actions {
+ margin: 3px 0 0;
+ padding: 0;
+ font-size: 12px;
+}
+
+/* QuickPress */
+.no-js #dashboard_quick_press {
+ display: none;
+}
+
+#dashboard_quick_press .easy-blogging {
+ padding: 0 8px;
+ text-align: left;
+}
+
+#dashboard_quick_press .input-text-wrap {
+ position: relative;
+}
+
+#dashboard_quick_press .prompt {
+ color: #bbb;
+ position: absolute;
+}
+
+#dashboard_quick_press div.updated {
+ padding: 0 5px;
+}
+
+#title-wrap label,
+#tags-input-wrap label {
+ cursor: text;
+}
+
+#title-wrap #title {
+ padding: 2px 6px;
+ font-size: 1.3em;
+ line-height: 100%;
+ outline: none;
+}
+
+#tags-input-wrap #tags-input {
+ outline: none;
+}
+
+#title-wrap #title-prompt-text {
+ font-size: 1.3em;
+ padding: 5px 8px;
+}
+
+#tags-input-wrap #tags-input-prompt-text {
+ font-size: 1em;
+ padding: 4px 8px;
+}
+
+#dashboard_quick_press .input-text-wrap,
+#dashboard_quick_press .textarea-wrap {
+ margin: 0 0 1em 0;
+}
+
+#dashboard_quick_press .wp-media-buttons {
+ margin: 0 0 .2em 1px;
+ padding: 0;
+}
+
+#dashboard_quick_press .wp-media-buttons a {
+ color: #777;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit input {
+ float: left;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit #save-post {
+ margin: 0 0.7em 0 1px;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit #publish {
+ float: right;
+}
+
+#dashboard-widgets #dashboard_quick_press form p.submit .spinner {
+ vertical-align: middle;
+ margin: 4px 6px 0 0;
+}
+
+/* Recent Drafts */
+#dashboard_recent_drafts ul,
+#dashboard_recent_drafts p {
+ margin: 0;
+ padding: 0;
+ word-wrap: break-word;
+}
+
+#dashboard_recent_drafts ul {
+ list-style: none;
+}
+
+#dashboard_recent_drafts ul li {
+ margin-bottom: 1em;
+}
+
+#dashboard_recent_drafts h4 {
+ line-height: 1.7em;
+ word-wrap: break-word;
+}
+
+#dashboard_recent_drafts h4 abbr {
+ font-weight: normal;
+ font-family: sans-serif;
+ font-size: 12px;
+ color: #999;
+ margin-left: 3px;
+}
+
+/* Feeds */
+.rss-widget ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+a.rsswidget {
+ font-size: 13px;
+ line-height: 1.7em;
+}
+
+.rss-widget ul li {
+ line-height: 1.5em;
+ margin-bottom: 12px;
+}
+
+.rss-widget span.rss-date {
+ color: #999;
+ font-size: 12px;
+ margin-left: 3px;
+}
+
+.rss-widget cite {
+ display: block;
+ text-align: right;
+ margin: 0 0 1em;
+ padding: 0;
+}
+
+.rss-widget cite:before {
+ content: '\2014';
+}
+
+/* Plugins */
+#dashboard_plugins h4 {
+ line-height: 1.7em;
+}
+
+#dashboard_plugins h5 {
+ font-weight: normal;
+ font-size: 13px;
+ margin: 0;
+ display: inline;
+ line-height: 1.4em;
+}
+
+#dashboard_plugins h5 a {
+ line-height: 1.4em;
+}
+
+#dashboard_plugins .inside span {
+ font-size: 12px;
+ padding-left: 5px;
+}
+
+#dashboard_plugins p {
+ margin: 0.3em 0 1.4em;
+ line-height: 1.4em;
+}
+
+.dashboard-comment-wrap {
+ overflow: hidden;
+ word-wrap: break-word;
+}
+
+/* Browser Nag */
+#dashboard_browser_nag a.update-browser-link {
+ font-size: 1.2em;
+ font-weight: bold;
+}
+
+#dashboard_browser_nag a {
+ text-decoration: underline;
+}
+
+#dashboard_browser_nag p.browser-update-nag.has-browser-icon {
+ padding-right: 125px;
+}
+
+#dashboard_browser_nag .browser-icon {
+ margin-top: -35px;
+}
+
+#dashboard_browser_nag.postbox.browser-insecure {
+ background-color: #ac1b1b;
+ border-color: #ac1b1b;
+}
+
+#dashboard_browser_nag.postbox {
+ background-color: #e29808;
+ background-image: none;
+ border-color: #edc048;
+ color: #fff;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+#dashboard_browser_nag.postbox.browser-insecure h3 {
+ border-bottom-color: #cd5a5a;
+ color: #fff;
+}
+
+#dashboard_browser_nag.postbox h3 {
+ border-bottom-color: #f6e2ac;
+ text-shadow: none;
+ background: transparent none;
+ color: #fff;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+#dashboard_browser_nag a {
+ color: #fff;
+}
+
+#dashboard_browser_nag.browser-insecure a.browse-happy-link,
+#dashboard_browser_nag.browser-insecure a.update-browser-link {
+ text-shadow: #871b15 0 1px 0;
+}
+
+#dashboard_browser_nag a.browse-happy-link,
+#dashboard_browser_nag a.update-browser-link {
+ text-shadow: #d29a04 0 1px 0;
+}
+
+
+/* login */
+
+.login * {
+ margin: 0;
+ padding: 0;
+}
+
+.login form {
+ margin-left: 8px;
+ padding: 26px 24px 46px;
+ font-weight: normal;
+ background: #fff;
+ border: 1px solid #e5e5e5;
+ -webkit-box-shadow: rgba(200, 200, 200, 0.7) 0px 4px 10px -1px;
+ box-shadow: rgba(200, 200, 200, 0.7) 0px 4px 10px -1px;
+}
+
+.login form .forgetmenot {
+ font-weight: normal;
+ float: left;
+ margin-bottom: 0;
+}
+
+.login .button-primary {
+ float: right;
+}
+
+#login form p {
+ margin-bottom: 0;
+}
+
+#login form p.submit {
+ padding: 0;
+}
+
+.login label {
+ color: #777;
+ font-size: 14px;
+}
+
+.login form .forgetmenot label {
+ font-size: 12px;
+ line-height: 19px;
+}
+
+.login h1 a {
+ background-image: url('../images/wordpress-logo.png?ver=20120216');
+ background-size: 274px 63px;
+ background-position: top center;
+ background-repeat: no-repeat;
+ width: 326px;
+ height: 67px;
+ text-indent: -9999px;
+ outline: none;
+ overflow: hidden;
+ padding-bottom: 15px;
+ display: block;
+}
+
+#login {
+ width: 320px;
+ padding: 114px 0 0;
+ margin: auto;
+}
+
+#login_error,
+.login .message {
+ margin: 0 0 16px 8px;
+ padding: 12px;
+}
+
+.login #nav,
+.login #backtoblog {
+ text-shadow: #fff 0 1px 0;
+ margin: 0 0 0 16px;
+ padding: 16px 16px 0;
+}
+
+#backtoblog {
+ padding: 12px 16px 0;
+}
+
+.login form .input,
+.login input[type="text"] {
+ color: #555;
+ font-weight: 200;
+ font-size: 24px;
+ line-height: 1;
+ width: 100%;
+ padding: 3px;
+ margin-top: 2px;
+ margin-right: 6px;
+ margin-bottom: 16px;
+ border: 1px solid #e5e5e5;
+ background: #fbfbfb;
+ outline: none;
+ -webkit-box-shadow: inset 1px 1px 2px rgba(200, 200, 200, 0.2);
+ box-shadow: inset 1px 1px 2px rgba(200, 200, 200, 0.2);
+}
+
+.login #pass-strength-result {
+ width: 250px;
+ font-weight: bold;
+ border-style: solid;
+ border-width: 1px;
+ margin: 12px 0 6px;
+ padding: 6px 5px;
+ text-align: center;
+}
+
+.mobile #login {
+ padding: 20px 0;
+}
+
+.mobile #login form,
+.mobile #login .message,
+.mobile #login_error {
+ margin-left: 0;
+}
+
+.mobile #login #nav,
+.mobile #login #backtoblog {
+ margin-left: 8px;
+}
+
+.mobile #login h1 a {
+ width: auto;
+}
+
+body.interim-login {
+ height: auto;
+}
+
+.interim-login #login {
+ padding: 0;
+ margin: 5px auto 20px;
+}
+
+.interim-login.login h1 a {
+ width: auto;
+}
+
+.interim-login #login_error,
+.interim-login.login .message {
+ margin: 0 0 16px;
+}
+
+.interim-login.login form {
+ margin: 0;
+}
+
+/* ms */
+/* Dashboard: MS Specific Data */
+#dashboard_right_now p.musub {
+ margin-top: 12px;
+ border-top: 1px solid #ececec;
+ padding-left: 16px;
+ position: static;
+}
+
+.rtl #dashboard_right_now p.musub {
+ padding-left: 0;
+ padding-right: 16px;
+}
+
+#dashboard_right_now td.b a.musublink {
+ font-size: 16px;
+}
+
+#dashboard_right_now div.musubtable {
+ border-top: none;
+}
+
+#dashboard_right_now div.musubtable .t {
+ white-space: normal;
+}
+
+/* Background Color for Site Status */
+.wp-list-table .site-deleted {
+ background: #ff8573;
+}
+.wp-list-table .site-spammed {
+ background: #faafaa;
+}
+.wp-list-table .site-archived {
+ background: #ffebe8;
+}
+.wp-list-table .site-mature {
+ background: #fecac2;
+}
+
+/* nav-menu */
+
+.no-js #message {
+ display: block;
+}
+
+#nav-menu-meta ul.outer-border {
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.accordion-section ul.category-tabs,
+.accordion-section ul.add-menu-item-tabs,
+.accordion-section ul.wp-tab-bar {
+ margin: 0;
+}
+
+.accordion-section .categorychecklist {
+ margin: 13px 0;
+}
+
+#nav-menu-meta .accordion-section-content {
+ padding: 18px 13px;
+}
+
+#nav-menu-meta .button-controls {
+ margin-bottom: 0;
+}
+
+#nav-menus-frame {
+ margin-left: 300px;
+ margin-top: 23px;
+}
+
+#wpbody-content #menu-settings-column {
+ display:inline;
+ width:281px;
+ margin-left: -300px;
+ clear: both;
+ float: left;
+ padding-top: 0;
+}
+
+#menu-settings-column .inside {
+ clear: both;
+ margin: 10px 0 0;
+}
+
+.metabox-holder-disabled .postbox,
+.metabox-holder-disabled .accordion-section-content {
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+
+.metabox-holder-disabled .button-controls .select-all {
+ display: none;
+}
+
+#wpbody {
+ position: relative;
+}
+
+.blank-slate .menu-name {
+ height: 2em;
+}
+
+.blank-slate .menu-settings {
+ border: none;
+ margin-top: 0;
+ padding-top: 0;
+ overflow: hidden;
+}
+
+.is-submenu {
+ font-style: italic;
+ font-weight: normal;
+ margin-left: 4px;
+}
+
+.manage-menus {
+ margin-top: 23px;
+ padding: 10px;
+ overflow: hidden;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.manage-menus select {
+ float: left;
+ margin-right: 6px;
+}
+
+.manage-menus .selected-menu {
+ float: left;
+ margin: 5px 6px 0 0;
+}
+
+.manage-menus .submit-btn {
+ float: left;
+ margin-top: 1px;
+}
+
+.menu-edit p {
+ margin: .3em 0 .6em;
+}
+
+.menu-edit #post-body-content h3 {
+ margin: 0 0 10px;
+}
+
+.menu-settings {
+ margin-top: 2em;
+ overflow: hidden;
+}
+
+.menu-settings dl {
+ margin: 0 0 10px;
+ overflow: hidden;
+ position: relative;
+}
+
+.menu-settings dd {
+ float: left;
+ margin: 0;
+ width: 60%;
+}
+
+.menu-edit .checkbox-input {
+ margin-top: 4px;
+}
+
+.theme-location-set {
+ font-size: 11px;
+}
+
+/* Menu Container */
+#menu-management-liquid {
+ float: left;
+ min-width: 100%;
+ margin-top: 3px;
+}
+
+#menu-management {
+ position: relative;
+ margin-right: 20px;
+ margin-top: -3px;
+ width: 100%;
+}
+
+#menu-management .menu-edit {
+ margin-bottom: 20px;
+}
+
+.nav-menus-php #post-body {
+ padding: 0 10px 10px;
+ border-width: 1px 0;
+ border-style: solid;
+}
+
+#nav-menu-header,
+#nav-menu-footer {
+ padding: 0 10px;
+}
+
+#nav-menu-header {
+ border-bottom: 1px solid;
+ margin-bottom: 13px;
+}
+
+#nav-menu-header .menu-name-label {
+ margin-top: 2px;
+}
+
+#nav-menu-footer {
+ border-top: 1px solid;
+}
+
+.nav-menus-php #post-body div.updated,
+.nav-menus-php #post-body div.error {
+ margin: 0;
+}
+
+.nav-menus-php #post-body-content {
+ position: relative;
+ float: none;
+}
+
+#menu-management .menu-add-new abbr {
+ font-weight:bold;
+}
+
+#select-nav-menu-container {
+ text-align: right;
+ padding: 0 10px 3px 10px;
+ margin-bottom: 5px;
+}
+
+#select-nav-menu {
+ width: 100px;
+ display: inline;
+}
+
+#menu-name-label {
+ margin-top: -2px;
+}
+
+.widefat td.menu-location-menus {
+ padding-bottom: 5px;
+}
+
+.menu-location-menus select {
+ float: left;
+}
+
+#locations-nav-menu-wrapper {
+ padding: 5px 0;
+}
+
+.locations-nav-menu-select select {
+ float: left;
+ width: 160px;
+ margin-right: 5px;
+}
+
+.locations-row-links {
+ float: left;
+ margin: 6px 0 0 6px;
+}
+
+.locations-edit-menu-link,
+.locations-add-menu-link {
+ margin: 0 3px;
+}
+
+.locations-edit-menu-link {
+ padding-right: 3px;
+ border-right: 1px solid #ccc;
+}
+
+#wpbody .open-label {
+ display: block;
+ float:left;
+}
+
+#wpbody .open-label span {
+ padding-right: 10px;
+}
+
+.js .input-with-default-title {
+ font-style: italic;
+}
+
+#menu-management .inside {
+ padding: 0 10px;
+}
+
+/* Add Menu Item Boxes */
+.postbox .howto input,
+.accordion-container .howto input {
+ width: 180px;
+ float: right;
+}
+
+.accordion-container .outer-border {
+ margin: 0;
+}
+
+#nav-menu-meta .accordion-container .top {
+ border-top: 1px solid #dfdfdf;
+}
+
+#nav-menu-meta .accordion-container .accordion-section:first-child,
+#nav-menu-meta .accordion-container .accordion-section:first-child h3,
+#nav-menu-meta .accordion-container .top,
+#nav-menu-meta .accordion-container .top h3 {
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+
+#nav-menu-meta .accordion-container .accordion-section:last-child,
+#nav-menu-meta .accordion-container .accordion-section:last-child .accordion-section-content,
+#nav-menu-meta .accordion-container .bottom,
+#nav-menu-meta .accordion-container .bottom:not(.open) h3 {
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+.customlinkdiv .howto input {
+ width: 180px;
+}
+
+.customlinkdiv p {
+ margin-top: 0
+}
+
+#nav-menu-theme-locations .howto select {
+ width: 100%;
+}
+
+#nav-menu-theme-locations .button-controls {
+ text-align: right;
+}
+
+.add-menu-item-view-all {
+ height: 400px;
+}
+
+/* Button Primary Actions */
+#menu-container .submit {
+ margin: 0 0 10px;
+ padding: 0;
+}
+
+.nav-menus-php .add-new-menu-action {
+ float: left;
+ margin: 6px 0 0 6px;
+ line-height: 15px;
+}
+
+.nav-menus-php .meta-sep,
+.nav-menus-php .submitdelete,
+.nav-menus-php .submitcancel {
+ display: block;
+ float: left;
+ margin: 4px 0;
+ line-height: 15px;
+}
+
+.meta-sep {
+ padding: 0 2px;
+}
+
+#cancel-save {
+ text-decoration: underline;
+ font-size: 12px;
+ margin-left: 20px;
+ margin-top: 5px;
+}
+
+.button.right, .button-secondary.right, .button-primary.right {
+ float: right;
+}
+
+/* Button Secondary Actions */
+.list-controls {
+ float: left;
+ margin-top: 5px;
+}
+
+.add-to-menu {
+ float: right;
+}
+
+.postbox .spinner {
+ display: none;
+ vertical-align: middle;
+}
+
+.button-controls {
+ clear:both;
+ margin: 10px 0;
+}
+
+.show-all,
+.hide-all {
+ cursor: pointer;
+}
+
+.hide-all {
+ display: none;
+}
+
+/* Create Menu */
+#menu-name {
+ width: 270px;
+}
+
+#manage-menu .inside {
+ padding: 0px 0px;
+}
+
+/* Custom Links */
+#available-links dt {
+ display: block;
+}
+
+#add-custom-link .howto {
+ font-size: 12px;
+}
+
+#add-custom-link label span {
+ display: block;
+ float: left;
+ margin-top: 5px;
+ padding-right: 5px;
+}
+
+.menu-item-textbox {
+ width: 180px;
+}
+
+.nav-menus-php .howto span {
+ margin-top: 4px;
+ display: block;
+ float: left;
+}
+
+/* Menu item types */
+.quick-search {
+ width: 190px;
+}
+
+.nav-menus-php .list-wrap {
+ display: none;
+ clear: both;
+ margin-bottom: 10px;
+}
+
+.nav-menus-php .list-container {
+ max-height: 200px;
+ overflow-y: auto;
+ padding: 10px 10px 5px;
+}
+
+.nav-menus-php .postbox p.submit {
+ margin-bottom: 0;
+}
+
+/* Listings */
+.nav-menus-php .list li {
+ display: none;
+ margin: 0;
+ margin-bottom: 5px;
+}
+
+.nav-menus-php .list li .menu-item-title {
+ cursor: pointer;
+ display: block;
+}
+
+.nav-menus-php .list li .menu-item-title input {
+ margin-right: 3px;
+ margin-top: -3px;
+}
+
+/* Nav Menu */
+#menu-container .inside {
+ padding-bottom: 10px;
+}
+
+.menu {
+ padding-top:1em;
+}
+
+#menu-to-edit {
+ margin: 0;
+ padding: 0.1em 0;
+}
+
+.menu ul {
+ width: 100%;
+}
+
+.menu li {
+ margin-bottom: 0;
+ position:relative;
+}
+
+.menu-item-bar {
+ clear:both;
+ line-height:1.5em;
+ position:relative;
+ margin: 9px 0 0;
+}
+
+.menu-item-handle {
+ border: 1px solid #dfdfdf;
+ position: relative;
+ padding-left: 10px;
+ height: auto;
+ width: 400px;
+ line-height: 35px;
+ text-shadow: 0 1px 0 #FFFFFF;
+ overflow: hidden;
+ word-wrap: break-word;
+}
+
+#menu-to-edit .menu-item-invalid .menu-item-handle {
+ background: #f6c9cc;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#f6c9cc), to(#fdf8ff));
+ background-image: -webkit-linear-gradient(bottom, #f6c9cc, #fdf8ff);
+ background-image: -moz-linear-gradient(bottom, #f6c9cc, #fdf8ff);
+ background-image: -o-linear-gradient(bottom, #f6c9cc, #fdf8ff);
+ background-image: linear-gradient(to top, #f6c9cc, #fdf8ff);
+}
+
+.menu-item-edit-active .menu-item-handle {
+ -webkit-border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.no-js .menu-item-edit-active .item-edit {
+ display: none;
+}
+
+.js .menu-item-handle {
+ cursor: move;
+}
+
+.menu li.deleting .menu-item-handle {
+ background-image: none;
+ text-shadow: 0 0 0;
+}
+
+.menu-item-handle .item-title {
+ font-size: 12px;
+ font-weight: bold;
+ padding: 7px 0;
+ line-height: 20px;
+ display:block;
+ margin-right:13em;
+}
+
+/* Sortables */
+li.menu-item.ui-sortable-helper dl {
+ margin-top: 0;
+}
+
+li.menu-item.ui-sortable-helper .menu-item-transport dl {
+ margin-top: 13px;
+}
+
+.menu .sortable-placeholder {
+ height: 35px;
+ width: 410px;
+ margin-top: 13px;
+}
+
+/* WARNING: The factor of 30px is hardcoded into the nav-menus javascript. */
+.menu-item-depth-0 { margin-left: 0px; }
+.menu-item-depth-1 { margin-left: 30px; }
+.menu-item-depth-2 { margin-left: 60px; }
+.menu-item-depth-3 { margin-left: 90px; }
+.menu-item-depth-4 { margin-left: 120px; }
+.menu-item-depth-5 { margin-left: 150px; }
+.menu-item-depth-6 { margin-left: 180px; }
+.menu-item-depth-7 { margin-left: 210px; }
+.menu-item-depth-8 { margin-left: 240px; }
+.menu-item-depth-9 { margin-left: 270px; }
+.menu-item-depth-10 { margin-left: 300px; }
+.menu-item-depth-11 { margin-left: 330px; }
+
+.menu-item-depth-0 .menu-item-transport { margin-left: 0px; }
+.menu-item-depth-1 .menu-item-transport { margin-left: -30px; }
+.menu-item-depth-2 .menu-item-transport { margin-left: -60px; }
+.menu-item-depth-3 .menu-item-transport { margin-left: -90px; }
+.menu-item-depth-4 .menu-item-transport { margin-left: -120px; }
+.menu-item-depth-5 .menu-item-transport { margin-left: -150px; }
+.menu-item-depth-6 .menu-item-transport { margin-left: -180px; }
+.menu-item-depth-7 .menu-item-transport { margin-left: -210px; }
+.menu-item-depth-8 .menu-item-transport { margin-left: -240px; }
+.menu-item-depth-9 .menu-item-transport { margin-left: -270px; }
+.menu-item-depth-10 .menu-item-transport { margin-left: -300px; }
+.menu-item-depth-11 .menu-item-transport { margin-left: -330px; }
+
+body.menu-max-depth-0 { min-width: 950px !important; }
+body.menu-max-depth-1 { min-width: 980px !important; }
+body.menu-max-depth-2 { min-width: 1010px !important; }
+body.menu-max-depth-3 { min-width: 1040px !important; }
+body.menu-max-depth-4 { min-width: 1070px !important; }
+body.menu-max-depth-5 { min-width: 1100px !important; }
+body.menu-max-depth-6 { min-width: 1130px !important; }
+body.menu-max-depth-7 { min-width: 1160px !important; }
+body.menu-max-depth-8 { min-width: 1190px !important; }
+body.menu-max-depth-9 { min-width: 1220px !important; }
+body.menu-max-depth-10 { min-width: 1250px !important; }
+body.menu-max-depth-11 { min-width: 1280px !important; }
+
+/* Menu item controls */
+.item-type {
+ font-size: 12px;
+ padding-right: 10px;
+}
+
+.item-controls {
+ font-size: 12px;
+ position: absolute;
+ right: 20px;
+ top: -1px;
+}
+
+.item-controls a {
+ text-decoration: none;
+}
+
+.item-controls a:hover {
+ cursor: pointer;
+}
+
+.item-controls .item-order {
+ padding-right: 10px;
+}
+
+.nav-menus-php .item-edit {
+ position: absolute;
+ right: -20px;
+ top: 0;
+ display: block;
+ width: 30px;
+ height: 36px;
+ overflow: hidden;
+ text-indent:-999em;
+ border-bottom: 1px solid;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+/* Menu editing */
+.menu-instructions-inactive {
+ display: none;
+}
+
+.menu-item-settings {
+ display: block;
+ width: 400px;
+ padding: 10px 0 10px 10px;
+ border: solid;
+ border-width: 0 1px 1px 1px;
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+.menu-item-settings .field-move a {
+ display: none;
+ margin: 0 2px;
+}
+
+.menu-item-edit-active .menu-item-settings {
+ display: block;
+}
+
+.menu-item-edit-inactive .menu-item-settings {
+ display: none;
+}
+
+.add-menu-item-pagelinks {
+ margin: .5em auto;
+ text-align: center;
+}
+
+.link-to-original {
+ display: block;
+ margin: 0 0 10px;
+ padding: 3px 5px 5px;
+ font-size: 12px;
+ font-style: italic;
+}
+
+.link-to-original a {
+ padding-left: 4px;
+ font-style: normal;
+}
+
+.hidden-field {
+ display: none;
+}
+
+.menu-item-settings .description-thin,
+.menu-item-settings .description-wide {
+ margin-right: 10px;
+ float: left;
+}
+
+.description-thin {
+ width: 190px;
+ height: 40px;
+}
+
+.description-wide {
+ width: 390px;
+}
+
+.menu-item-actions {
+ padding-top: 15px;
+}
+
+#cancel-save {
+ cursor: pointer;
+}
+
+/* Major/minor publishing actions (classes) */
+.nav-menus-php .major-publishing-actions {
+ clear: both;
+ padding: 3px 0 5px;
+}
+
+.nav-menus-php .major-publishing-actions .publishing-action {
+ text-align: right;
+ float: right;
+ line-height: 23px;
+ margin: 2px 0 1px;
+}
+
+.nav-menus-php .blank-slate .menu-settings {
+ display: none;
+}
+
+.nav-menus-php .delete-action {
+ float: left;
+ margin-top: 2px;
+}
+
+.nav-menus-php .submitbox .submitcancel {
+ border-bottom: 1px solid;
+ padding: 1px 2px;
+ text-decoration: none;
+}
+
+.nav-menus-php .major-publishing-actions .form-invalid {
+ padding-left: 4px;
+ margin-left: -4px;
+ border: 0 none;
+}
+
+/* Clearfix */
+#menu-item-name-wrap:after,
+#menu-item-url-wrap:after,
+#menu-name-label:after,
+#menu-settings-column .inside:after,
+#nav-menus-frame:after,
+.nav-menus-php #post-body-content:after,
+.nav-menus-php .button-controls:after,
+.nav-menus-php .major-publishing-actions:after,
+.nav-menus-php .menu-item-settings:after {
+ clear: both;
+ content: ".";
+ display: block;
+ height: 0;
+ visibility: hidden;
+}
+
+#nav-menus-frame,
+.button-controls,
+#menu-item-url-wrap,
+#menu-item-name-wrap {
+ display: block;
+}
+
+/* Star ratings */
+div.star-holder {
+ position: relative;
+ height: 17px;
+ width: 100px;
+ background: url('../images/stars.png?ver=20121108') repeat-x bottom left;
+}
+
+div.star-holder .star-rating {
+ background: url('../images/stars.png?ver=20121108') repeat-x top left;
+ height: 17px;
+ float: left;
+}
+
+div.action-links {
+ font-weight: normal;
+ margin: 6px 0 0;
+}
+
+/* Header on thickbox */
+#plugin-information-header {
+ margin: 0;
+ padding: 0 5px;
+ font-weight: bold;
+ position: relative;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ height: 2.5em;
+}
+#plugin-information ul#sidemenu {
+ font-weight: normal;
+ margin: 0 5px;
+ position: absolute;
+ left: 0;
+ bottom: -1px;
+}
+
+/* Install sidemenu */
+#plugin-information p.action-button {
+ width: 100%;
+ padding-bottom: 0;
+ margin-bottom: 0;
+ margin-top: 10px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+#plugin-information .action-button a {
+ text-align: center;
+ font-weight: bold;
+ text-decoration: none;
+ display: block;
+ line-height: 2em;
+}
+
+#plugin-information h2 {
+ clear: none !important;
+ margin-right: 200px;
+}
+
+#plugin-information .fyi {
+ margin: 0 10px 50px;
+ width: 210px;
+}
+
+#plugin-information .fyi h2 {
+ font-size: 0.9em;
+ margin-bottom: 0;
+ margin-right: 0;
+}
+
+#plugin-information .fyi h2.mainheader {
+ padding: 5px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-left-radius: 3px;
+}
+
+#plugin-information .fyi ul {
+ padding: 10px 5px 10px 7px;
+ margin: 0;
+ list-style: none;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+#plugin-information .fyi li {
+ margin-right: 0;
+}
+
+#plugin-information #section-holder {
+ padding: 10px;
+}
+
+#plugin-information .section ul,
+#plugin-information .section ol {
+ margin-left: 16px;
+ list-style-type: square;
+ list-style-image: none;
+}
+
+#plugin-information #section-screenshots ol {
+ list-style: none;
+ margin: 0;
+}
+
+#plugin-information #section-screenshots li img {
+ vertical-align: text-top;
+ max-width: 100%;
+ width: auto;
+ height: auto;
+}
+
+#plugin-information #section-screenshots li p {
+ font-style: italic;
+ padding-left: 20px;
+ padding-bottom: 2em;
+}
+
+#plugin-information #section-screenshots ol,
+#plugin-information .updated,
+#plugin-information pre {
+ margin-right: 215px;
+}
+
+#plugin-information pre {
+ padding: 7px;
+ overflow: auto;
+}
+
+/* press-this */
+body.press-this {
+ color: #333;
+ margin: 0;
+ padding: 0;
+ min-width: 675px;
+ min-height: 400px;
+}
+
+img {
+ border: none;
+}
+
+/* Header */
+.press-this #wphead {
+ height: 32px;
+ margin-left: 0;
+ margin-right: 0;
+ margin-bottom: 5px;
+}
+
+.press-this #header-logo {
+ float: left;
+ margin: 7px 7px 0;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.press-this #wphead h1 {
+ font-weight: normal;
+ font-size: 16px;
+ line-height: 32px;
+ margin: 0;
+ float: left;
+}
+
+.press-this #wphead h1 a {
+ text-decoration: none;
+}
+
+.press-this #wphead h1 a:hover {
+ text-decoration: underline;
+}
+
+.press-this #message {
+ margin: 10px 0;
+}
+
+.press-this-sidebar {
+ float: right;
+ width: 200px;
+ padding-top: 10px;
+}
+
+.press-this #title {
+ margin-left: 0;
+ margin-right: 0;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.press-this .tagchecklist span a {
+ background: transparent url(../images/xit.gif) no-repeat 0 0;
+}
+
+.press-this #titlediv {
+ margin: 0;
+}
+
+.press-this .wp-media-buttons {
+ cursor: default;
+ padding: 8px 8px 0;
+}
+
+.press-this .howto {
+ margin-top: 2px;
+ margin-bottom: 3px;
+ font-size: 12px;
+ font-style: italic;
+ display: block;
+}
+
+/* Editor/Main Column */
+.press-this #poststuff {
+ margin: 0 10px 10px;
+ padding: 0;
+}
+
+.press-this #photo-add-url-div input[type="text"] {
+ width: 220px;
+}
+
+#poststuff #editor-toolbar {
+ height: 30px;
+}
+
+div.zerosize {
+ border: 0 none;
+ height: 0;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ width: 0;
+}
+
+.posting {
+ margin-right: 212px;
+ position: relative;
+}
+
+.press-this .inner-sidebar {
+ width: 200px;
+}
+
+.press-this .inner-sidebar .sleeve {
+ padding-top: 5px;
+}
+
+.press-this #submitdiv p {
+ margin: 0;
+ padding: 6px;
+}
+
+.press-this #submitdiv #publishing-actions {
+ border-bottom: 1px solid #dfdfdf;
+}
+
+.press-this #publish {
+ float: right;
+}
+
+.press-this #poststuff h2,
+.press-this #poststuff h3 {
+ font-size: 14px;
+ line-height: 1;
+}
+
+.press-this #tagsdiv-post_tag h3,
+.press-this #categorydiv h3 {
+ cursor: pointer;
+}
+
+.press-this #submitdiv h3 {
+ cursor: default;
+}
+
+h3.tb {
+ text-shadow: 0 1px 0 #fff;
+ font-weight: bold;
+ font-size: 12px;
+ margin-left: 5px;
+}
+
+#TB_window {
+ border: 1px solid #333;
+}
+
+.press-this .postbox,
+.press-this .stuffbox {
+ margin-bottom: 10px;
+ min-width: 0;
+}
+
+.js .postbox:hover .handlediv,
+.js .stuffbox:hover .handlediv {
+ background: transparent url(../images/arrows.png) no-repeat 6px 7px;
+}
+
+.press-this #submitdiv:hover .handlediv {
+ background: none;
+}
+
+.tbtitle {
+ font-size: 1.7em;
+ outline: none;
+ padding: 3px 4px;
+ border-color: #dfdfdf;
+}
+
+.press-this .actions {
+ float: right;
+ margin: -19px 0 0;
+}
+
+.press-this #extra-fields .actions {
+ margin: -32px -7px 0 0;
+}
+
+.press-this .actions li {
+ float: left;
+ list-style: none;
+ margin-right: 10px;
+}
+
+#extra-fields .button {
+ margin-right: 5px;
+}
+
+/* Photo Styles */
+#photo_saving {
+ margin: 0 8px 8px;
+ vertical-align: middle;
+}
+
+#img_container_container {
+ overflow: auto;
+}
+
+#extra-fields {
+ margin-top: 10px;
+ position: relative;
+}
+
+#extra-fields h2 {
+ margin: 12px;
+}
+
+#waiting {
+ margin-top: 10px;
+ overflow: hidden;
+}
+
+#waiting span {
+ float: right;
+ margin: 0 0 0 5px;
+}
+
+#waiting .spinner {
+ display: block;
+}
+
+#extra-fields .postbox {
+ margin-bottom: 5px;
+}
+
+#extra-fields .titlewrap {
+ padding: 0;
+ overflow: auto;
+ height: 100px;
+}
+
+#img_container a {
+ display: block;
+ float: left;
+ overflow: hidden;
+}
+
+#img_container img,
+#img_container a {
+ width: 68px;
+ height: 68px;
+}
+
+#img_container img {
+ border: none;
+ background-color: #f4f4f4;
+ cursor: pointer;
+}
+
+#img_container a,
+#img_container a:link,
+#img_container a:visited {
+ border: 1px solid #ccc;
+ display: block;
+ position: relative;
+}
+
+#img_container a:hover,
+#img_container a:active {
+ border-color: #000;
+ z-index: 1000;
+ border-width: 2px;
+ margin: -1px;
+}
+
+/* Video */
+#embed-code {
+ width: 100%;
+ height: 98px;
+}
+
+/* Categories */
+.press-this .categorydiv div.tabs-panel {
+ height: 100px;
+}
+
+/* Tags */
+.press-this .tagsdiv .newtag {
+ width: 120px;
+}
+
+.press-this #content {
+ margin: 5px 0;
+ padding: 0 5px;
+ border: 0 none;
+ height: 345px;
+ font-family: Consolas, Monaco, monospace;
+ font-size: 13px;
+ line-height: 19px;
+ background: transparent;
+}
+
+/* Submit */
+.press-this #publishing-actions .spinner {
+ display: inline;
+ vertical-align: middle;
+}
+
+#TB_ajaxContent #options {
+ position: absolute;
+ top: 20px;
+ right: 25px;
+ padding: 5px;
+}
+
+#TB_ajaxContent h3 {
+ margin-bottom: .25em;
+}
+
+.error a {
+ text-decoration: underline;
+}
+
+.updated a {
+ text-decoration: none;
+ padding-bottom: 2px;
+}
+
+/* tag hints */
+.taghint {
+ color: #aaa;
+ margin: -17px 0 0 7px;
+ visibility: hidden;
+}
+
+input.newtag ~ div.taghint {
+ visibility: visible;
+}
+
+input.newtag:focus ~ div.taghint {
+ visibility: hidden;
+}
+
+/* TinyMCE */
+#mce_fullscreen_container {
+ background: #fff;
+}
+
+#photo-add-url-div input[type="text"] {
+ width: 300px;
+}
+
+/* theme-editor */
+.alignleft h3 {
+ margin: 0;
+}
+
+h3 span {
+ font-weight: normal;
+}
+
+#template textarea {
+ font-family: Consolas, Monaco, monospace;
+ font-size: 12px;
+ width: 97%;
+ background: #f9f9f9;
+ outline: none;
+}
+
+#template p {
+ width: 97%;
+}
+
+#templateside {
+ float: right;
+ width: 190px;
+ word-wrap: break-word;
+}
+
+#templateside h3,
+#postcustomstuff p.submit {
+ margin: 0;
+}
+
+#templateside h4 {
+ margin: 1em 0 0;
+}
+
+#templateside ol,
+#templateside ul {
+ margin: .5em;
+ padding: 0;
+}
+
+#templateside li {
+ margin: 4px 0;
+}
+
+#templateside ul li a span.highlight {
+ display:block;
+}
+
+.nonessential {
+ font-size: 11px;
+ font-style: italic;
+ padding-left: 12px;
+}
+
+.highlight {
+ padding: 3px 3px 3px 12px;
+ margin-left: -12px;
+ font-weight: bold;
+ border: 0 none;
+}
+
+#documentation {
+ margin-top: 10px;
+}
+#documentation label {
+ line-height: 22px;
+ vertical-align: top;
+ font-weight: bold;
+}
+
+.fileedit-sub {
+ padding: 10px 0 8px;
+ line-height: 180%;
+}
+
+#filter-box {
+ clear: both;
+}
+
+.feature-filter {
+ padding: 8px 12px 0;
+}
+
+.feature-filter .feature-group {
+ float: left;
+ margin: 5px 10px 10px;
+}
+
+.feature-filter .feature-group li {
+ display: inline-block;
+ vertical-align: top;
+ list-style-type: none;
+ padding-right: 25px;
+ width: 150px;
+}
+
+.feature-container {
+ width: 100%;
+ overflow: auto;
+ margin-bottom: 10px;
+}
+
+/* widgets */
+
+/* 2 column liquid layout */
+div.widget-liquid-left {
+ float: left;
+ clear: left;
+ width: 100%;
+ margin-right: -325px;
+}
+
+div#widgets-left {
+ margin-left: 5px;
+ margin-right: 325px;
+}
+
+div#widgets-right {
+ width: 285px;
+ margin: 0 auto;
+}
+
+div.widget-liquid-right {
+ float: right;
+ clear: right;
+ width: 300px;
+}
+
+.widget-liquid-right .widget,
+.inactive-sidebar .widget,
+.widget-liquid-right .sidebar-description {
+ width: 250px;
+ margin: 0 auto 20px;
+ overflow: hidden;
+}
+
+.widget-liquid-right .sidebar-description {
+ margin-bottom: 10px;
+}
+
+.inactive-sidebar .widget {
+ margin: 0 10px 20px;
+ display: inline-block;
+}
+
+div.sidebar-name h3 {
+ font-weight: normal;
+ font-size: 15px;
+ margin: 0;
+ padding: 8px 10px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+div.sidebar-name {
+ font-size: 13px;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+
+.js .sidebar-name {
+ cursor: pointer;
+}
+
+.js .closed .sidebar-name {
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+.widget-liquid-right .widgets-sortables,
+#widgets-left .widget-holder {
+ border-width: 0 1px 1px;
+ border-style: none solid solid;
+ -webkit-border-bottom-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+.js .closed .widgets-sortables,
+.js .closed .widget-holder {
+ display: none;
+}
+
+.widget-liquid-right .widgets-sortables {
+ padding: 15px 0 0;
+}
+
+#available-widgets .widget-holder {
+ padding: 7px 5px 0;
+}
+
+#available-widgets .widget {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.inactive-sidebar {
+ padding: 5px 5px 0;
+}
+
+#widget-list .widget {
+ width: 250px;
+ margin: 0 10px 15px;
+ border: 0 none;
+ background: transparent;
+ display: inline-block;
+ vertical-align: top;
+}
+
+#widget-list .widget-description {
+ padding: 5px 8px;
+}
+
+.widget-placeholder {
+ border-width: 1px;
+ border-style: dashed;
+ margin: 0 auto 20px;
+ height: 27px;
+ width: 250px;
+}
+
+.inactive-sidebar .widget-placeholder {
+ margin: 0 10px 20px;
+ float: left;
+}
+
+div.widgets-holder-wrap {
+ padding: 0;
+ margin: 10px 0 20px;
+}
+
+#widgets-left #available-widgets {
+ background-color: transparent;
+ border: 0 none;
+}
+
+ul#widget-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ min-height: 100px;
+}
+
+.widget .widget-top {
+ margin-bottom: -1px;
+ font-size: 12px;
+ font-weight: bold;
+ height: 26px;
+ overflow: hidden;
+}
+
+.widget-top .widget-title {
+ padding: 7px 9px;
+}
+
+.widget-top .widget-title-action {
+ float: right;
+}
+
+a.widget-action {
+ display: block;
+ width: 24px;
+ height: 26px;
+}
+
+#available-widgets a.widget-action {
+ display: none;
+}
+
+.widget-top a.widget-action {
+ background: transparent url(../images/arrows.png) no-repeat 4px 6px;
+}
+
+.widget-top a.widget-action:hover {
+ background: transparent url(../images/arrows-dark.png) no-repeat 4px 6px;
+}
+
+.widget .widget-inside,
+.widget .widget-description {
+ padding: 12px 12px 10px;
+ font-size: 12px;
+ line-height: 16px;
+}
+
+.widget-inside,
+.widget-description {
+ display: none;
+}
+
+#available-widgets .widget-description {
+ display: block;
+}
+
+.widget .widget-inside p {
+ margin: 0 0 1em;
+ padding: 0;
+}
+
+.widget-title h4 {
+ margin: 0;
+ padding-bottom: 0.2em;
+ line-height: 1;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.widgets-sortables {
+ min-height: 90px;
+}
+
+.widget-control-actions {
+ margin-top: 8px;
+}
+
+.widget-control-actions a {
+ text-decoration: none;
+}
+
+.widget-control-actions a:hover {
+ text-decoration: underline;
+}
+
+.widget-control-actions div.alignleft {
+ margin-top: 6px;
+}
+
+div#sidebar-info {
+ padding: 0 1em;
+ margin-bottom: 1em;
+ font-size: 12px;
+}
+
+.widget-title a,
+.widget-title a:hover {
+ text-decoration: none;
+ border-bottom: none;
+}
+
+.widget-control-edit {
+ display: block;
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 26px;
+ padding: 0 8px 0 0;
+}
+
+a.widget-control-edit {
+ text-decoration: none;
+}
+
+.widget-control-edit .add,
+.widget-control-edit .edit {
+ display: none;
+}
+
+#available-widgets .widget-control-edit .add,
+#widgets-right .widget-control-edit .edit,
+.inactive-sidebar .widget-control-edit .edit {
+ display: inline;
+}
+
+.editwidget {
+ margin: 0 auto 15px;
+}
+
+.editwidget .widget-inside {
+ display: block;
+ padding: 10px;
+}
+
+.inactive p.description {
+ margin: 5px 15px 10px;
+}
+
+#available-widgets p.description {
+ margin: 0 12px 12px;
+}
+
+.widget-position {
+ margin-top: 8px;
+}
+
+.inactive {
+ padding-top: 2px;
+}
+
+.sidebar-name .spinner {
+ float: none;
+ margin: 0 3px -3px;
+}
+
+.sidebar-name-arrow {
+ float: right;
+ height: 29px;
+ width: 26px;
+}
+
+.widget-title .in-widget-title {
+ font-size: 12px;
+ white-space: nowrap;
+}
+
+#removing-widget {
+ display: none;
+ font-weight: normal;
+ padding-left: 15px;
+ font-size: 12px;
+ line-height: 1;
+}
+
+.widget-control-noform,
+#access-off,
+.widgets_access .widget-action,
+.widgets_access .sidebar-name-arrow,
+.widgets_access #access-on,
+.widgets_access .widget-holder .description {
+ display: none;
+}
+
+.widgets_access .widget-holder,
+.widgets_access #widget-list {
+ padding-top: 10px;
+}
+
+.widgets_access #access-off {
+ display: inline;
+}
+
+.widgets_access #wpbody-content .widget-title-action,
+.widgets_access #wpbody-content .widget-control-edit,
+.widgets_access .closed .widgets-sortables,
+.widgets_access .closed .widget-holder {
+ display: block;
+}
+
+.widgets_access .closed .sidebar-name {
+ -webkit-border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.widgets_access .sidebar-name,
+.widgets_access .widget .widget-top {
+ cursor: default;
+}
+
+/* Enable draggable on IE10 touch events until it's rolled into jQuery UI core */
+.ui-sortable,
+.ui-draggable {
+ -ms-touch-action: none;
+}
+
+/* Accordion */
+
+.accordion-section {
+ border-top: 1px solid #fff;
+ border-bottom: 1px solid #dfdfdf;
+ margin: 0;
+}
+
+.accordion-section:first-child {
+ border-top: 1px solid #dfdfdf;
+}
+
+.accordion-section:last-child {
+ box-shadow: 0 1px 0 0px #fff;
+}
+
+.accordion-section.open .accordion-section-content,
+.no-js .accordion-section .accordion-section-content {
+ display: block;
+}
+
+.accordion-section.open:hover {
+ border-bottom-color: #dfdfdf;
+}
+
+.accordion-section-content {
+ display: none;
+ padding: 10px 20px 15px;
+ overflow: hidden;
+ background: #fdfdfd;
+ border-left: 1px solid #dfdfdf;
+ border-right: 1px solid #dfdfdf;
+}
+
+.accordion-section-title {
+ margin: 0;
+ padding: 15px 20px;
+ position: relative;
+ border-left: 1px solid #dfdfdf;
+ border-right: 1px solid #dfdfdf;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
+}
+
+.js .accordion-section-title {
+ cursor: pointer;
+}
+
+.js .accordion-section-title:after {
+ content: '';
+ width: 0;
+ height: 0;
+ border-color: #ccc transparent;
+ border-style: solid;
+ border-width: 6px 6px 0;
+ position: absolute;
+ top: 25px;
+ right: 20px;
+ z-index: 1;
+}
+
+.accordion-section-title:focus {
+ outline: none;
+}
+
+.accordion-section-title:hover:after,
+.accordion-section-title:focus:after {
+ border-color: #aaa transparent;
+}
+
+.cannot-expand .accordion-section-title {
+ cursor: auto;
+}
+
+.cannot-expand .accordion-section-title:after {
+ display: none;
+}
+
+.control-section .accordion-section-title {
+ padding: 10px 20px;
+ color: #464646;
+ font-size: 15px;
+ font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
+ font-weight: normal;
+ text-shadow: 0 1px 0 #fff;
+ background: #f5f5f5;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#eee), to(#f5f5f5));
+ background-image: -webkit-linear-gradient(bottom, #eee, #f5f5f5);
+ background-image: -moz-linear-gradient(bottom, #eee, #f5f5f5);
+ background-image: -o-linear-gradient(bottom, #eee, #f5f5f5);
+ background-image: linear-gradient(to top, #eee, #f5f5f5);
+}
+
+.control-section .accordion-section-title:after {
+ top: 15px;
+}
+
+.js .control-section:hover .accordion-section-title,
+.js .control-section .accordion-section-title:hover,
+.js .control-section.open .accordion-section-title,
+.js .control-section .accordion-section-title:focus {
+ color: #000;
+ background: #f9f9f9;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#ececec), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: -moz-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: -o-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: linear-gradient(to top, #ececec, #f9f9f9);
+}
+
+.control-section.open .accordion-section-title {
+ border-bottom: 1px solid #dfdfdf;
+}
+
+/* =Media Queries
+-------------------------------------------------------------- */
+
+@media only screen and (max-width: 768px) {
+ /* categories */
+ #col-left {
+ width: 100%;
+ }
+
+ #col-right {
+ width: 100%;
+ }
+}
+
+@media only screen and (min-width: 769px) {
+ /* categories */
+ #col-left {
+ width: 35%;
+ }
+
+ #col-right {
+ width: 65%;
+ }
+}
+
+@media only screen and (max-width: 860px) {
+
+ /* categories */
+ #col-left {
+ width: 35%;
+ }
+
+ #col-right {
+ width: 65%;
+ }
+}
+
+@media only screen and (min-width: 980px) {
+
+ /* categories */
+ #col-left {
+ width: 35%;
+ }
+
+ #col-right {
+ width: 65%;
+ }
+}
+
+@media only screen and (max-width: 768px) {
+ /* categories */
+ #col-left {
+ width: 100%;
+ }
+
+ #col-right {
+ width: 100%;
+ }
+
+ .form-field input,
+ .form-field textarea {
+ width: 99%;
+ }
+
+ .form-wrap .form-field {
+ padding:0;
+ }
+
+ /* users */
+ #profile-page .form-table textarea {
+ max-width: 400px;
+ width: auto;
+ }
+}
+
+/**
+ * HiDPI Displays
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+
+ .press-this .tagchecklist span a {
+ background-image: url('../images/xit-2x.gif');
+ background-size: 20px auto;
+ }
+
+ .js .postbox:hover .handlediv,
+ .js .stuffbox:hover .handlediv,
+ .widget-top a.widget-action {
+ background-image: url('../images/arrows-2x.png');
+ background-size: 15px 123px;
+ }
+
+ .widget-top a.widget-action:hover {
+ background-image: url('../images/arrows-dark-2x.png');
+ background-size: 15px 123px;
+ }
+
+ .post-com-count {
+ background-image: url('../images/bubble_bg-2x.gif');
+ background-size: 18px 100px;
+ }
+
+ tr.wp-locked .locked-indicator {
+ background-image: url('../images/lock-2x.png');
+ background-size: 16px 16px;
+ }
+
+ th .comment-grey-bubble {
+ background-image: url('../images/comment-grey-bubble-2x.png');
+ background-size: 12px 12px;
+ }
+
+ .sorting-indicator {
+ background-image: url('../images/sort-2x.gif?ver=20130102');
+ background-size: 14px 4px;
+ }
+
+ #content-resize-handle,
+ #post-body .wp_themeSkin .mceStatusbar a.mceResize {
+ background: transparent url('../images/resize-2x.gif') no-repeat scroll right bottom;
+ background-size: 11px 11px;
+ }
+
+ div.star-holder {
+ background: url('../images/stars-2x.png?ver=20121108') repeat-x bottom left;
+ background-size: 21px 37px;
+ }
+
+ div.star-holder .star-rating {
+ background: url('../images/stars-2x.png?ver=20121108') repeat-x top left;
+ background-size: 21px 37px;
+ }
+
+ .welcome-panel .welcome-panel-close:before {
+ background-image: url('../images/xit-2x.gif');
+ background-size: 20px auto;
+ }
+
+ .welcome-panel .welcome-icon {
+ background-image: url('../images/welcome-icons-2x.png');
+ }
+
+ .login h1 a {
+ background-image: url('../images/wordpress-logo-2x.png?ver=20120412');
+ background-size: 274px 63px;
+ }
+
+ .wp-badge {
+ background-image: url('../images/wp-badge-2x.png?ver=20120516');
+ background-size: 173px 194px;
+ }
+
+ .wp-full-overlay .collapse-sidebar-arrow {
+ background-image: url('../images/arrows-2x.png');
+ background-size: 15px 123px;
+ }
+
+ .pressthis a span {
+ background-image: url(../images/press-this-2x.png?v=20121105);
+ }
+
+ .imgedit-crop,
+ .imgedit-rleft,
+ .imgedit-rright,
+ .imgedit-flipv,
+ .imgedit-fliph,
+ .imgedit-undo,
+ .imgedit-redo {
+ background-image: url('../images/imgedit-icons-2x.png');
+ background-size: 260px 64px;
+ }
+
+ .spinner,
+ .imgedit-wait,
+ .customize-loading #customize-container {
+ background-image: url(../images/wpspin_light-2x.gif);
+ }
+
+ .wp-slider .ui-slider-handle:before {
+ background-image: url(../images/arrows-pr-2x.png);
+ background-size: 16px 102px;
+ }
+
+}
+
+/* =Localized CSS
+-------------------------------------------------------------- */
+
+/* zh_CN: Remove italic properties. */
+.locale-zh-cn .howto,
+.locale-zh-cn .tablenav .displaying-num,
+.locale-zh-cn .js .input-with-default-title,
+.locale-zh-cn .link-to-original,
+.locale-zh-cn .inline-edit-row fieldset span.title,
+.locale-zh-cn .inline-edit-row fieldset span.checkbox-title,
+.locale-zh-cn #utc-time,
+.locale-zh-cn #local-time,
+.locale-zh-cn p.install-help,
+.locale-zh-cn p.help,
+.locale-zh-cn p.description,
+.locale-zh-cn span.description,
+.locale-zh-cn .form-wrap p {
+ font-style: normal;
+}
+
+/* zh_CN: Enlarge dashboard widget 'Configure' link */
+.locale-zh-cn .hdnle a { font-size: 12px; }
+
+/* zn_CH: Enlarge font size, set font-size: normal */
+.locale-zh-cn form.upgrade .hint { font-style: normal; font-size: 100%; }
+
+/* Zn_CH: Distraction free writing.
+ * More beautiful font for "Just write."
+ * Larger text for HTML/Visual mode.
+ */
+.locale-zh-cn #wp-fullscreen-tagline { font-family: KaiTi, "楷体", sans-serif; }
+.locale-zh-cn #wp-fullscreen-modes a { font-size: 12px; }
+
+/* zh_CN: Enlarge font-size. */
+.locale-zh-cn #sort-buttons { font-size: 1em !important; }
+
+/* ru_RU: Text needs more room to breathe. */
+.locale-ru-ru .inline-edit-row fieldset label span.title {
+ width: auto; /* default 5em */
+ min-width: 5em;
+}
+.locale-ru-ru.press-this .posting {
+ margin-right: 257px; /* default 212px + 45px */
+}
+.locale-ru-ru.press-this #photo-add-url-div input[type="text"] {
+ width: 255px; /* default 300px - 45px */
+}
+.locale-ru-ru.press-this #side-sortables {
+ width: 245px; /* default 200px + 45px */
+}
+.locale-ru-ru #customize-header-actions .button {
+ padding: 0 8px 1px; /* default 0 10px 1px; */
+}
+
+/* lt_LT: QuickEdit */
+.locale-lt-lt .inline-edit-row fieldset label span.title {
+ width: 8em;
+}
+.locale-lt-lt .inline-edit-row fieldset label span.input-text-wrap {
+ margin-left: 8em;
+}
diff --git a/src/wp-admin/custom-background.php b/src/wp-admin/custom-background.php
new file mode 100644
index 0000000000..ac2941f28a
--- /dev/null
+++ b/src/wp-admin/custom-background.php
@@ -0,0 +1,426 @@
+<?php
+/**
+ * The custom background script.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * The custom background class.
+ *
+ * @since 3.0.0
+ * @package WordPress
+ * @subpackage Administration
+ */
+class Custom_Background {
+
+ /**
+ * Callback for administration header.
+ *
+ * @var callback
+ * @since 3.0.0
+ * @access private
+ */
+ var $admin_header_callback;
+
+ /**
+ * Callback for header div.
+ *
+ * @var callback
+ * @since 3.0.0
+ * @access private
+ */
+ var $admin_image_div_callback;
+
+ /**
+ * Holds the page menu hook.
+ *
+ * @var string
+ * @since 3.0.0
+ * @access private
+ */
+ var $page = '';
+
+ /**
+ * Constructor - Register administration header callback.
+ *
+ * @since 3.0.0
+ * @param callback $admin_header_callback
+ * @param callback $admin_image_div_callback Optional custom image div output callback.
+ * @return Custom_Background
+ */
+ function __construct($admin_header_callback = '', $admin_image_div_callback = '') {
+ $this->admin_header_callback = $admin_header_callback;
+ $this->admin_image_div_callback = $admin_image_div_callback;
+
+ add_action( 'admin_menu', array( $this, 'init' ) );
+ add_action( 'wp_ajax_set-background-image', array( $this, 'wp_set_background_image' ) );
+ }
+
+ /**
+ * Set up the hooks for the Custom Background admin page.
+ *
+ * @since 3.0.0
+ */
+ function init() {
+ if ( ! current_user_can('edit_theme_options') )
+ return;
+
+ $this->page = $page = add_theme_page(__('Background'), __('Background'), 'edit_theme_options', 'custom-background', array(&$this, 'admin_page'));
+
+ add_action("load-$page", array(&$this, 'admin_load'));
+ add_action("load-$page", array(&$this, 'take_action'), 49);
+ add_action("load-$page", array(&$this, 'handle_upload'), 49);
+
+ if ( $this->admin_header_callback )
+ add_action("admin_head-$page", $this->admin_header_callback, 51);
+ }
+
+ /**
+ * Set up the enqueue for the CSS & JavaScript files.
+ *
+ * @since 3.0.0
+ */
+ function admin_load() {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __( 'You can customize the look of your site without touching any of your theme&#8217;s code by using a custom background. Your background can be an image or a color.' ) . '</p>' .
+ '<p>' . __( 'To use a background image, simply upload it or choose an image that has already been uploaded to your Media Library by clicking the &#8220;Choose Image&#8221; button. You can display a single instance of your image, or tile it to fill the screen. You can have your background fixed in place, so your site content moves on top of it, or you can have it scroll with your site.' ) . '</p>' .
+ '<p>' . __( 'You can also choose a background color by clicking the Select Color button and either typing in a legitimate HTML hex value, e.g. &#8220;#ff0000&#8221; for red, or by choosing a color using the color picker.' ) . '</p>' .
+ '<p>' . __( 'Don&#8217;t forget to click on the Save Changes button when you are finished.' ) . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Appearance_Background_Screen" target="_blank">Documentation on Custom Background</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+ );
+
+ wp_enqueue_media();
+ wp_enqueue_script('custom-background');
+ wp_enqueue_style('wp-color-picker');
+ }
+
+ /**
+ * Execute custom background modification.
+ *
+ * @since 3.0.0
+ */
+ function take_action() {
+
+ if ( empty($_POST) )
+ return;
+
+ if ( isset($_POST['reset-background']) ) {
+ check_admin_referer('custom-background-reset', '_wpnonce-custom-background-reset');
+ remove_theme_mod('background_image');
+ remove_theme_mod('background_image_thumb');
+ $this->updated = true;
+ return;
+ }
+
+ if ( isset($_POST['remove-background']) ) {
+ // @TODO: Uploaded files are not removed here.
+ check_admin_referer('custom-background-remove', '_wpnonce-custom-background-remove');
+ set_theme_mod('background_image', '');
+ set_theme_mod('background_image_thumb', '');
+ $this->updated = true;
+ wp_safe_redirect( $_POST['_wp_http_referer'] );
+ return;
+ }
+
+ if ( isset($_POST['background-repeat']) ) {
+ check_admin_referer('custom-background');
+ if ( in_array($_POST['background-repeat'], array('repeat', 'no-repeat', 'repeat-x', 'repeat-y')) )
+ $repeat = $_POST['background-repeat'];
+ else
+ $repeat = 'repeat';
+ set_theme_mod('background_repeat', $repeat);
+ }
+
+ if ( isset($_POST['background-position-x']) ) {
+ check_admin_referer('custom-background');
+ if ( in_array($_POST['background-position-x'], array('center', 'right', 'left')) )
+ $position = $_POST['background-position-x'];
+ else
+ $position = 'left';
+ set_theme_mod('background_position_x', $position);
+ }
+
+ if ( isset($_POST['background-attachment']) ) {
+ check_admin_referer('custom-background');
+ if ( in_array($_POST['background-attachment'], array('fixed', 'scroll')) )
+ $attachment = $_POST['background-attachment'];
+ else
+ $attachment = 'fixed';
+ set_theme_mod('background_attachment', $attachment);
+ }
+
+ if ( isset($_POST['background-color']) ) {
+ check_admin_referer('custom-background');
+ $color = preg_replace('/[^0-9a-fA-F]/', '', $_POST['background-color']);
+ if ( strlen($color) == 6 || strlen($color) == 3 )
+ set_theme_mod('background_color', $color);
+ else
+ set_theme_mod('background_color', '');
+ }
+
+ $this->updated = true;
+ }
+
+ /**
+ * Display the custom background page.
+ *
+ * @since 3.0.0
+ */
+ function admin_page() {
+?>
+<div class="wrap" id="custom-background">
+<?php screen_icon(); ?>
+<h2><?php _e('Custom Background'); ?></h2>
+<?php if ( !empty($this->updated) ) { ?>
+<div id="message" class="updated">
+<p><?php printf( __( 'Background updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) ); ?></p>
+</div>
+<?php }
+
+ if ( $this->admin_image_div_callback ) {
+ call_user_func($this->admin_image_div_callback);
+ } else {
+?>
+<h3><?php _e('Background Image'); ?></h3>
+<table class="form-table">
+<tbody>
+<tr valign="top">
+<th scope="row"><?php _e('Preview'); ?></th>
+<td>
+<?php
+$background_styles = '';
+if ( $bgcolor = get_background_color() )
+ $background_styles .= 'background-color: #' . $bgcolor . ';';
+
+if ( get_background_image() ) {
+ $background_image_thumb = esc_url( set_url_scheme( get_theme_mod( 'background_image_thumb', str_replace( '%', '%%', get_background_image() ) ) ) );
+ // background-image URL must be single quote, see below
+ $background_styles .= ' background-image: url(\'' . $background_image_thumb . '\');'
+ . ' background-repeat: ' . get_theme_mod('background_repeat', 'repeat') . ';'
+ . ' background-position: top ' . get_theme_mod('background_position_x', 'left');
+}
+?>
+<div id="custom-background-image" style="<?php echo $background_styles; ?>"><?php // must be double quote, see above ?>
+<?php if ( get_background_image() ) { ?>
+<img class="custom-background-image" src="<?php echo $background_image_thumb; ?>" style="visibility:hidden;" alt="" /><br />
+<img class="custom-background-image" src="<?php echo $background_image_thumb; ?>" style="visibility:hidden;" alt="" />
+<?php } ?>
+</div>
+<?php } ?>
+</td>
+</tr>
+<?php if ( get_background_image() ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e('Remove Image'); ?></th>
+<td>
+<form method="post" action="">
+<?php wp_nonce_field('custom-background-remove', '_wpnonce-custom-background-remove'); ?>
+<?php submit_button( __( 'Remove Background Image' ), 'button', 'remove-background', false ); ?><br/>
+<?php _e('This will remove the background image. You will not be able to restore any customizations.') ?>
+</form>
+</td>
+</tr>
+<?php endif; ?>
+
+<?php $default_image = get_theme_support( 'custom-background', 'default-image' ); ?>
+<?php if ( $default_image && get_background_image() != $default_image ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e('Restore Original Image'); ?></th>
+<td>
+<form method="post" action="">
+<?php wp_nonce_field('custom-background-reset', '_wpnonce-custom-background-reset'); ?>
+<?php submit_button( __( 'Restore Original Image' ), 'button', 'reset-background', false ); ?><br/>
+<?php _e('This will restore the original background image. You will not be able to restore any customizations.') ?>
+</form>
+</td>
+</tr>
+
+<?php endif; ?>
+<tr valign="top">
+<th scope="row"><?php _e('Select Image'); ?></th>
+<td><form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="">
+ <p>
+ <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
+ <input type="file" id="upload" name="import" />
+ <input type="hidden" name="action" value="save" />
+ <?php wp_nonce_field( 'custom-background-upload', '_wpnonce-custom-background-upload' ); ?>
+ <?php submit_button( __( 'Upload' ), 'button', 'submit', false ); ?>
+ </p>
+ <p>
+ <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br />
+ <a id="choose-from-library-link" class="button"
+ data-choose="<?php esc_attr_e( 'Choose a Background Image' ); ?>"
+ data-update="<?php esc_attr_e( 'Set as background' ); ?>"><?php _e( 'Choose Image' ); ?></a>
+ </p>
+ </form>
+</td>
+</tr>
+</tbody>
+</table>
+
+<h3><?php _e('Display Options') ?></h3>
+<form method="post" action="">
+<table class="form-table">
+<tbody>
+<?php if ( get_background_image() ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Position' ); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e( 'Background Position' ); ?></span></legend>
+<label>
+<input name="background-position-x" type="radio" value="left"<?php checked('left', get_theme_mod('background_position_x', 'left')); ?> />
+<?php _e('Left') ?>
+</label>
+<label>
+<input name="background-position-x" type="radio" value="center"<?php checked('center', get_theme_mod('background_position_x', 'left')); ?> />
+<?php _e('Center') ?>
+</label>
+<label>
+<input name="background-position-x" type="radio" value="right"<?php checked('right', get_theme_mod('background_position_x', 'left')); ?> />
+<?php _e('Right') ?>
+</label>
+</fieldset></td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><?php _e( 'Repeat' ); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e( 'Background Repeat' ); ?></span></legend>
+<label><input type="radio" name="background-repeat" value="no-repeat"<?php checked('no-repeat', get_theme_mod('background_repeat', 'repeat')); ?> /> <?php _e('No Repeat'); ?></label>
+ <label><input type="radio" name="background-repeat" value="repeat"<?php checked('repeat', get_theme_mod('background_repeat', 'repeat')); ?> /> <?php _e('Tile'); ?></label>
+ <label><input type="radio" name="background-repeat" value="repeat-x"<?php checked('repeat-x', get_theme_mod('background_repeat', 'repeat')); ?> /> <?php _e('Tile Horizontally'); ?></label>
+ <label><input type="radio" name="background-repeat" value="repeat-y"<?php checked('repeat-y', get_theme_mod('background_repeat', 'repeat')); ?> /> <?php _e('Tile Vertically'); ?></label>
+</fieldset></td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><?php _ex( 'Attachment', 'Background Attachment' ); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e( 'Background Attachment' ); ?></span></legend>
+<label>
+<input name="background-attachment" type="radio" value="scroll" <?php checked('scroll', get_theme_mod('background_attachment', 'scroll')); ?> />
+<?php _e('Scroll') ?>
+</label>
+<label>
+<input name="background-attachment" type="radio" value="fixed" <?php checked('fixed', get_theme_mod('background_attachment', 'scroll')); ?> />
+<?php _e('Fixed') ?>
+</label>
+</fieldset></td>
+</tr>
+<?php endif; // get_background_image() ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Background Color' ); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e( 'Background Color' ); ?></span></legend>
+<?php
+$default_color = '';
+if ( current_theme_supports( 'custom-background', 'default-color' ) )
+ $default_color = ' data-default-color="#' . esc_attr( get_theme_support( 'custom-background', 'default-color' ) ) . '"';
+?>
+<input type="text" name="background-color" id="background-color" value="#<?php echo esc_attr( get_background_color() ); ?>"<?php echo $default_color ?> />
+</fieldset></td>
+</tr>
+</tbody>
+</table>
+
+<?php wp_nonce_field('custom-background'); ?>
+<?php submit_button( null, 'primary', 'save-background-options' ); ?>
+</form>
+
+</div>
+<?php
+ }
+
+ /**
+ * Handle an Image upload for the background image.
+ *
+ * @since 3.0.0
+ */
+ function handle_upload() {
+
+ if ( empty($_FILES) )
+ return;
+
+ check_admin_referer('custom-background-upload', '_wpnonce-custom-background-upload');
+ $overrides = array('test_form' => false);
+
+ $uploaded_file = $_FILES['import'];
+ $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'], false );
+ if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) )
+ wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
+
+ $file = wp_handle_upload($uploaded_file, $overrides);
+
+ if ( isset($file['error']) )
+ wp_die( $file['error'] );
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $filename = basename($file);
+
+ // Construct the object array
+ $object = array(
+ 'post_title' => $filename,
+ 'post_content' => $url,
+ 'post_mime_type' => $type,
+ 'guid' => $url,
+ 'context' => 'custom-background'
+ );
+
+ // Save the data
+ $id = wp_insert_attachment($object, $file);
+
+ // Add the meta-data
+ wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
+ update_post_meta( $id, '_wp_attachment_is_custom_background', get_option('stylesheet' ) );
+
+ set_theme_mod('background_image', esc_url_raw($url));
+
+ $thumbnail = wp_get_attachment_image_src( $id, 'thumbnail' );
+ set_theme_mod('background_image_thumb', esc_url_raw( $thumbnail[0] ) );
+
+ do_action('wp_create_file_in_uploads', $file, $id); // For replication
+ $this->updated = true;
+ }
+
+ /**
+ * Unused since 3.5.0.
+ *
+ * @since 3.4.0
+ */
+ function attachment_fields_to_edit( $form_fields ) {
+ return $form_fields;
+ }
+
+ /**
+ * Unused since 3.5.0.
+ *
+ * @since 3.4.0
+ */
+ function filter_upload_tabs( $tabs ) {
+ return $tabs;
+ }
+
+ public function wp_set_background_image() {
+ if ( ! current_user_can('edit_theme_options') || ! isset( $_POST['attachment_id'] ) ) exit;
+ $attachment_id = absint($_POST['attachment_id']);
+ $sizes = array_keys(apply_filters( 'image_size_names_choose', array('thumbnail' => __('Thumbnail'), 'medium' => __('Medium'), 'large' => __('Large'), 'full' => __('Full Size')) ));
+ $size = 'thumbnail';
+ if ( in_array( $_POST['size'], $sizes ) )
+ $size = esc_attr( $_POST['size'] );
+
+ update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', get_option('stylesheet' ) );
+ $url = wp_get_attachment_image_src( $attachment_id, $size );
+ $thumbnail = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );
+ set_theme_mod( 'background_image', esc_url_raw( $url[0] ) );
+ set_theme_mod( 'background_image_thumb', esc_url_raw( $thumbnail[0] ) );
+ exit;
+ }
+}
diff --git a/src/wp-admin/custom-header.php b/src/wp-admin/custom-header.php
new file mode 100644
index 0000000000..12288430cd
--- /dev/null
+++ b/src/wp-admin/custom-header.php
@@ -0,0 +1,1015 @@
+<?php
+/**
+ * The custom header image script.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * The custom header image class.
+ *
+ * @since 2.1.0
+ * @package WordPress
+ * @subpackage Administration
+ */
+class Custom_Image_Header {
+
+ /**
+ * Callback for administration header.
+ *
+ * @var callback
+ * @since 2.1.0
+ * @access private
+ */
+ var $admin_header_callback;
+
+ /**
+ * Callback for header div.
+ *
+ * @var callback
+ * @since 3.0.0
+ * @access private
+ */
+ var $admin_image_div_callback;
+
+ /**
+ * Holds default headers.
+ *
+ * @var array
+ * @since 3.0.0
+ * @access private
+ */
+ var $default_headers = array();
+
+ /**
+ * Holds custom headers uploaded by the user
+ *
+ * @var array
+ * @since 3.2.0
+ * @access private
+ */
+ var $uploaded_headers = array();
+
+ /**
+ * Holds the page menu hook.
+ *
+ * @var string
+ * @since 3.0.0
+ * @access private
+ */
+ var $page = '';
+
+ /**
+ * Constructor - Register administration header callback.
+ *
+ * @since 2.1.0
+ * @param callback $admin_header_callback
+ * @param callback $admin_image_div_callback Optional custom image div output callback.
+ * @return Custom_Image_Header
+ */
+ function __construct($admin_header_callback, $admin_image_div_callback = '') {
+ $this->admin_header_callback = $admin_header_callback;
+ $this->admin_image_div_callback = $admin_image_div_callback;
+
+ add_action( 'admin_menu', array( $this, 'init' ) );
+ }
+
+ /**
+ * Set up the hooks for the Custom Header admin page.
+ *
+ * @since 2.1.0
+ */
+ function init() {
+ if ( ! current_user_can('edit_theme_options') )
+ return;
+
+ $this->page = $page = add_theme_page(__('Header'), __('Header'), 'edit_theme_options', 'custom-header', array(&$this, 'admin_page'));
+
+ add_action("admin_print_scripts-$page", array(&$this, 'js_includes'));
+ add_action("admin_print_styles-$page", array(&$this, 'css_includes'));
+ add_action("admin_head-$page", array(&$this, 'help') );
+ add_action("admin_head-$page", array(&$this, 'take_action'), 50);
+ add_action("admin_head-$page", array(&$this, 'js'), 50);
+ if ( $this->admin_header_callback )
+ add_action("admin_head-$page", $this->admin_header_callback, 51);
+ }
+
+ /**
+ * Adds contextual help.
+ *
+ * @since 3.0.0
+ */
+ function help() {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __( 'This screen is used to customize the header section of your theme.') . '</p>' .
+ '<p>' . __( 'You can choose from the theme&#8217;s default header images, or use one of your own. You can also customize how your Site Title and Tagline are displayed.') . '<p>'
+ ) );
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'set-header-image',
+ 'title' => __('Header Image'),
+ 'content' =>
+ '<p>' . __( 'You can set a custom image header for your site. Simply upload the image and crop it, and the new header will go live immediately. Alternatively, you can use an image that has already been uploaded to your Media Library by clicking the &#8220;Choose Image&#8221; button.' ) . '</p>' .
+ '<p>' . __( 'Some themes come with additional header images bundled. If you see multiple images displayed, select the one you&#8217;d like and click the &#8220;Save Changes&#8221; button.' ) . '</p>' .
+ '<p>' . __( 'If your theme has more than one default header image, or you have uploaded more than one custom header image, you have the option of having WordPress display a randomly different image on each page of your site. Click the &#8220;Random&#8221; radio button next to the Uploaded Images or Default Images section to enable this feature.') . '</p>' .
+ '<p>' . __( 'If you don&#8217;t want a header image to be displayed on your site at all, click the &#8220;Remove Header Image&#8221; button at the bottom of the Header Image section of this page. If you want to re-enable the header image later, you just have to select one of the other image options and click &#8220;Save Changes&#8221;.') . '</p>'
+ ) );
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'set-header-text',
+ 'title' => __('Header Text'),
+ 'content' =>
+ '<p>' . sprintf( __( 'For most themes, the header text is your Site Title and Tagline, as defined in the <a href="%1$s">General Settings</a> section.' ), admin_url( 'options-general.php' ) ) . '<p>' .
+ '<p>' . __( 'In the Header Text section of this page, you can choose whether to display this text or hide it. You can also choose a color for the text by clicking the Select Color button and either typing in a legitimate HTML hex value, e.g. &#8220;#ff0000&#8221; for red, or by choosing a color using the color picker.' ) . '</p>' .
+ '<p>' . __( 'Don&#8217;t forget to click &#8220;Save Changes&#8221; when you&#8217;re done!') . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Appearance_Header_Screen" target="_blank">Documentation on Custom Header</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+ );
+ }
+
+ /**
+ * Get the current step.
+ *
+ * @since 2.6.0
+ *
+ * @return int Current step
+ */
+ function step() {
+ if ( ! isset( $_GET['step'] ) )
+ return 1;
+
+ $step = (int) $_GET['step'];
+ if ( $step < 1 || 3 < $step ||
+ ( 2 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce-custom-header-upload'], 'custom-header-upload' ) ) ||
+ ( 3 == $step && ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'custom-header-crop-image' ) )
+ )
+ return 1;
+
+ return $step;
+ }
+
+ /**
+ * Set up the enqueue for the JavaScript files.
+ *
+ * @since 2.1.0
+ */
+ function js_includes() {
+ $step = $this->step();
+
+ if ( ( 1 == $step || 3 == $step ) ) {
+ wp_enqueue_media();
+ wp_enqueue_script( 'custom-header' );
+ if ( current_theme_supports( 'custom-header', 'header-text' ) )
+ wp_enqueue_script( 'wp-color-picker' );
+ } elseif ( 2 == $step ) {
+ wp_enqueue_script('imgareaselect');
+ }
+ }
+
+ /**
+ * Set up the enqueue for the CSS files
+ *
+ * @since 2.7
+ */
+ function css_includes() {
+ $step = $this->step();
+
+ if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) )
+ wp_enqueue_style( 'wp-color-picker' );
+ elseif ( 2 == $step )
+ wp_enqueue_style('imgareaselect');
+ }
+
+ /**
+ * Execute custom header modification.
+ *
+ * @since 2.6.0
+ */
+ function take_action() {
+ if ( ! current_user_can('edit_theme_options') )
+ return;
+
+ if ( empty( $_POST ) )
+ return;
+
+ $this->updated = true;
+
+ if ( isset( $_POST['resetheader'] ) ) {
+ check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
+ $this->reset_header_image();
+ return;
+ }
+
+ if ( isset( $_POST['removeheader'] ) ) {
+ check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
+ $this->remove_header_image();
+ return;
+ }
+
+ if ( isset( $_POST['text-color'] ) && ! isset( $_POST['display-header-text'] ) ) {
+ check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
+ set_theme_mod( 'header_textcolor', 'blank' );
+ } elseif ( isset( $_POST['text-color'] ) ) {
+ check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
+ $_POST['text-color'] = str_replace( '#', '', $_POST['text-color'] );
+ $color = preg_replace('/[^0-9a-fA-F]/', '', $_POST['text-color']);
+ if ( strlen($color) == 6 || strlen($color) == 3 )
+ set_theme_mod('header_textcolor', $color);
+ elseif ( ! $color )
+ set_theme_mod( 'header_textcolor', 'blank' );
+ }
+
+ if ( isset( $_POST['default-header'] ) ) {
+ check_admin_referer( 'custom-header-options', '_wpnonce-custom-header-options' );
+ $this->set_header_image( $_POST['default-header'] );
+ return;
+ }
+ }
+
+ /**
+ * Process the default headers
+ *
+ * @since 3.0.0
+ */
+ function process_default_headers() {
+ global $_wp_default_headers;
+
+ if ( !empty($this->headers) )
+ return;
+
+ if ( !isset($_wp_default_headers) )
+ return;
+
+ $this->default_headers = $_wp_default_headers;
+ $template_directory_uri = get_template_directory_uri();
+ $stylesheet_directory_uri = get_stylesheet_directory_uri();
+ foreach ( array_keys($this->default_headers) as $header ) {
+ $this->default_headers[$header]['url'] = sprintf( $this->default_headers[$header]['url'], $template_directory_uri, $stylesheet_directory_uri );
+ $this->default_headers[$header]['thumbnail_url'] = sprintf( $this->default_headers[$header]['thumbnail_url'], $template_directory_uri, $stylesheet_directory_uri );
+ }
+
+ }
+
+ /**
+ * Display UI for selecting one of several default headers.
+ *
+ * Show the random image option if this theme has multiple header images.
+ * Random image option is on by default if no header has been set.
+ *
+ * @since 3.0.0
+ */
+ function show_header_selector( $type = 'default' ) {
+ if ( 'default' == $type ) {
+ $headers = $this->default_headers;
+ } else {
+ $headers = get_uploaded_header_images();
+ $type = 'uploaded';
+ }
+
+ if ( 1 < count( $headers ) ) {
+ echo '<div class="random-header">';
+ echo '<label><input name="default-header" type="radio" value="random-' . $type . '-image"' . checked( is_random_header_image( $type ), true, false ) . ' />';
+ echo __( '<strong>Random:</strong> Show a different image on each page.' );
+ echo '</label>';
+ echo '</div>';
+ }
+
+ echo '<div class="available-headers">';
+ foreach ( $headers as $header_key => $header ) {
+ $header_thumbnail = $header['thumbnail_url'];
+ $header_url = $header['url'];
+ $header_desc = empty( $header['description'] ) ? '' : $header['description'];
+ echo '<div class="default-header">';
+ echo '<label><input name="default-header" type="radio" value="' . esc_attr( $header_key ) . '" ' . checked( $header_url, get_theme_mod( 'header_image' ), false ) . ' />';
+ $width = '';
+ if ( !empty( $header['attachment_id'] ) )
+ $width = ' width="230"';
+ echo '<img src="' . set_url_scheme( $header_thumbnail ) . '" alt="' . esc_attr( $header_desc ) .'" title="' . esc_attr( $header_desc ) . '"' . $width . ' /></label>';
+ echo '</div>';
+ }
+ echo '<div class="clear"></div></div>';
+ }
+
+ /**
+ * Execute Javascript depending on step.
+ *
+ * @since 2.1.0
+ */
+ function js() {
+ $step = $this->step();
+ if ( ( 1 == $step || 3 == $step ) && current_theme_supports( 'custom-header', 'header-text' ) )
+ $this->js_1();
+ elseif ( 2 == $step )
+ $this->js_2();
+ }
+
+ /**
+ * Display Javascript based on Step 1 and 3.
+ *
+ * @since 2.6.0
+ */
+ function js_1() { ?>
+<script type="text/javascript">
+/* <![CDATA[ */
+(function($){
+ var default_color = '#<?php echo get_theme_support( 'custom-header', 'default-text-color' ); ?>',
+ header_text_fields;
+
+ function pickColor(color) {
+ $('#name').css('color', color);
+ $('#desc').css('color', color);
+ $('#text-color').val(color);
+ }
+
+ function toggle_text() {
+ var checked = $('#display-header-text').prop('checked'),
+ text_color;
+ header_text_fields.toggle( checked );
+ if ( ! checked )
+ return;
+ text_color = $('#text-color');
+ if ( '' == text_color.val().replace('#', '') ) {
+ text_color.val( default_color );
+ pickColor( default_color );
+ } else {
+ pickColor( text_color.val() );
+ }
+ }
+
+ $(document).ready(function() {
+ var text_color = $('#text-color');
+ header_text_fields = $('.displaying-header-text');
+ text_color.wpColorPicker({
+ change: function( event, ui ) {
+ pickColor( text_color.wpColorPicker('color') );
+ },
+ clear: function() {
+ pickColor( '' );
+ }
+ });
+ $('#display-header-text').click( toggle_text );
+ <?php if ( ! display_header_text() ) : ?>
+ toggle_text();
+ <?php endif; ?>
+ });
+})(jQuery);
+/* ]]> */
+</script>
+<?php
+ }
+
+ /**
+ * Display Javascript based on Step 2.
+ *
+ * @since 2.6.0
+ */
+ function js_2() { ?>
+<script type="text/javascript">
+/* <![CDATA[ */
+ function onEndCrop( coords ) {
+ jQuery( '#x1' ).val(coords.x);
+ jQuery( '#y1' ).val(coords.y);
+ jQuery( '#width' ).val(coords.w);
+ jQuery( '#height' ).val(coords.h);
+ }
+
+ jQuery(document).ready(function() {
+ var xinit = <?php echo absint( get_theme_support( 'custom-header', 'width' ) ); ?>;
+ var yinit = <?php echo absint( get_theme_support( 'custom-header', 'height' ) ); ?>;
+ var ratio = xinit / yinit;
+ var ximg = jQuery('img#upload').width();
+ var yimg = jQuery('img#upload').height();
+
+ if ( yimg < yinit || ximg < xinit ) {
+ if ( ximg / yimg > ratio ) {
+ yinit = yimg;
+ xinit = yinit * ratio;
+ } else {
+ xinit = ximg;
+ yinit = xinit / ratio;
+ }
+ }
+
+ jQuery('img#upload').imgAreaSelect({
+ handles: true,
+ keys: true,
+ show: true,
+ x1: 0,
+ y1: 0,
+ x2: xinit,
+ y2: yinit,
+ <?php
+ if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
+ ?>
+ aspectRatio: xinit + ':' + yinit,
+ <?php
+ }
+ if ( ! current_theme_supports( 'custom-header', 'flex-height' ) ) {
+ ?>
+ maxHeight: <?php echo get_theme_support( 'custom-header', 'height' ); ?>,
+ <?php
+ }
+ if ( ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
+ ?>
+ maxWidth: <?php echo get_theme_support( 'custom-header', 'width' ); ?>,
+ <?php
+ }
+ ?>
+ onInit: function () {
+ jQuery('#width').val(xinit);
+ jQuery('#height').val(yinit);
+ },
+ onSelectChange: function(img, c) {
+ jQuery('#x1').val(c.x1);
+ jQuery('#y1').val(c.y1);
+ jQuery('#width').val(c.width);
+ jQuery('#height').val(c.height);
+ }
+ });
+ });
+/* ]]> */
+</script>
+<?php
+ }
+
+ /**
+ * Display first step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ function step_1() {
+ $this->process_default_headers();
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php _e('Custom Header'); ?></h2>
+
+<?php if ( ! empty( $this->updated ) ) { ?>
+<div id="message" class="updated">
+<p><?php printf( __( 'Header updated. <a href="%s">Visit your site</a> to see how it looks.' ), home_url( '/' ) ); ?></p>
+</div>
+<?php } ?>
+
+<h3><?php _e( 'Header Image' ); ?></h3>
+
+<table class="form-table">
+<tbody>
+
+<tr valign="top">
+<th scope="row"><?php _e( 'Preview' ); ?></th>
+<td>
+ <?php if ( $this->admin_image_div_callback ) {
+ call_user_func( $this->admin_image_div_callback );
+ } else {
+ $custom_header = get_custom_header();
+ $header_image_style = 'background-image:url(' . esc_url( get_header_image() ) . ');';
+ if ( $custom_header->width )
+ $header_image_style .= 'max-width:' . $custom_header->width . 'px;';
+ if ( $custom_header->height )
+ $header_image_style .= 'height:' . $custom_header->height . 'px;';
+ ?>
+ <div id="headimg" style="<?php echo $header_image_style; ?>">
+ <?php
+ if ( display_header_text() )
+ $style = ' style="color:#' . get_header_textcolor() . ';"';
+ else
+ $style = ' style="display:none;"';
+ ?>
+ <h1><a id="name" class="displaying-header-text" <?php echo $style; ?> onclick="return false;" href="<?php bloginfo('url'); ?>"><?php bloginfo( 'name' ); ?></a></h1>
+ <div id="desc" class="displaying-header-text" <?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
+ </div>
+ <?php } ?>
+</td>
+</tr>
+<?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Select Image' ); ?></th>
+<td>
+ <p><?php _e( 'You can select an image to be shown at the top of your site by uploading from your computer or choosing from your media library. After selecting an image you will be able to crop it.' ); ?><br />
+ <?php
+ if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) {
+ printf( __( 'Images of exactly <strong>%1$d &times; %2$d pixels</strong> will be used as-is.' ) . '<br />', get_theme_support( 'custom-header', 'width' ), get_theme_support( 'custom-header', 'height' ) );
+ } elseif ( current_theme_supports( 'custom-header', 'flex-height' ) ) {
+ if ( ! current_theme_supports( 'custom-header', 'flex-width' ) )
+ printf( __( 'Images should be at least <strong>%1$d pixels</strong> wide.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
+ } elseif ( current_theme_supports( 'custom-header', 'flex-width' ) ) {
+ if ( ! current_theme_supports( 'custom-header', 'flex-height' ) )
+ printf( __( 'Images should be at least <strong>%1$d pixels</strong> tall.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
+ }
+ if ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) {
+ if ( current_theme_supports( 'custom-header', 'width' ) )
+ printf( __( 'Suggested width is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'width' ) );
+ if ( current_theme_supports( 'custom-header', 'height' ) )
+ printf( __( 'Suggested height is <strong>%1$d pixels</strong>.' ) . ' ', get_theme_support( 'custom-header', 'height' ) );
+ }
+ ?></p>
+ <form enctype="multipart/form-data" id="upload-form" class="wp-upload-form" method="post" action="<?php echo esc_url( add_query_arg( 'step', 2 ) ) ?>">
+ <p>
+ <label for="upload"><?php _e( 'Choose an image from your computer:' ); ?></label><br />
+ <input type="file" id="upload" name="import" />
+ <input type="hidden" name="action" value="save" />
+ <?php wp_nonce_field( 'custom-header-upload', '_wpnonce-custom-header-upload' ); ?>
+ <?php submit_button( __( 'Upload' ), 'button', 'submit', false ); ?>
+ </p>
+ <?php
+ $modal_update_href = esc_url( add_query_arg( array(
+ 'page' => 'custom-header',
+ 'step' => 2,
+ '_wpnonce-custom-header-upload' => wp_create_nonce('custom-header-upload'),
+ ), admin_url('themes.php') ) );
+ ?>
+ <p>
+ <label for="choose-from-library-link"><?php _e( 'Or choose an image from your media library:' ); ?></label><br />
+ <a id="choose-from-library-link" class="button"
+ data-update-link="<?php echo esc_attr( $modal_update_href ); ?>"
+ data-choose="<?php esc_attr_e( 'Choose a Custom Header' ); ?>"
+ data-update="<?php esc_attr_e( 'Set as header' ); ?>"><?php _e( 'Choose Image' ); ?></a>
+ </p>
+ </form>
+</td>
+</tr>
+<?php endif; ?>
+</tbody>
+</table>
+
+<form method="post" action="<?php echo esc_url( add_query_arg( 'step', 1 ) ) ?>">
+<table class="form-table">
+<tbody>
+ <?php if ( get_uploaded_header_images() ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Uploaded Images' ); ?></th>
+<td>
+ <p><?php _e( 'You can choose one of your previously uploaded headers, or show a random one.' ) ?></p>
+ <?php
+ $this->show_header_selector( 'uploaded' );
+ ?>
+</td>
+</tr>
+ <?php endif;
+ if ( ! empty( $this->default_headers ) ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Default Images' ); ?></th>
+<td>
+<?php if ( current_theme_supports( 'custom-header', 'uploads' ) ) : ?>
+ <p><?php _e( 'If you don&lsquo;t want to upload your own image, you can use one of these cool headers, or show a random one.' ) ?></p>
+<?php else: ?>
+ <p><?php _e( 'You can use one of these cool headers or show a random one on each page.' ) ?></p>
+<?php endif; ?>
+ <?php
+ $this->show_header_selector( 'default' );
+ ?>
+</td>
+</tr>
+ <?php endif;
+ if ( get_header_image() ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Remove Image' ); ?></th>
+<td>
+ <p><?php _e( 'This will remove the header image. You will not be able to restore any customizations.' ) ?></p>
+ <?php submit_button( __( 'Remove Header Image' ), 'button', 'removeheader', false ); ?>
+</td>
+</tr>
+ <?php endif;
+
+ $default_image = get_theme_support( 'custom-header', 'default-image' );
+ if ( $default_image && get_header_image() != $default_image ) : ?>
+<tr valign="top">
+<th scope="row"><?php _e( 'Reset Image' ); ?></th>
+<td>
+ <p><?php _e( 'This will restore the original header image. You will not be able to restore any customizations.' ) ?></p>
+ <?php submit_button( __( 'Restore Original Header Image' ), 'button', 'resetheader', false ); ?>
+</td>
+</tr>
+ <?php endif; ?>
+</tbody>
+</table>
+
+<?php if ( current_theme_supports( 'custom-header', 'header-text' ) ) : ?>
+
+<h3><?php _e( 'Header Text' ); ?></h3>
+
+<table class="form-table">
+<tbody>
+<tr valign="top">
+<th scope="row"><?php _e( 'Header Text' ); ?></th>
+<td>
+ <p>
+ <label><input type="checkbox" name="display-header-text" id="display-header-text"<?php checked( display_header_text() ); ?> /> <?php _e( 'Show header text with your image.' ); ?></label>
+ </p>
+</td>
+</tr>
+
+<tr valign="top" class="displaying-header-text">
+<th scope="row"><?php _e( 'Text Color' ); ?></th>
+<td>
+ <p>
+<?php
+$header_textcolor = display_header_text() ? get_header_textcolor() : get_theme_support( 'custom-header', 'default-text-color' );
+$default_color = '';
+if ( current_theme_supports( 'custom-header', 'default-text-color' ) ) {
+ $default_color = '#' . get_theme_support( 'custom-header', 'default-text-color' );
+ $default_color_attr = ' data-default-color="' . esc_attr( $default_color ) . '"';
+ echo '<input type="text" name="text-color" id="text-color" value="#' . esc_attr( $header_textcolor ) . '"' . $default_color_attr . ' />';
+ if ( $default_color )
+ echo ' <span class="description hide-if-js">' . sprintf( _x( 'Default: %s', 'color' ), $default_color ) . '</span>';
+}
+?>
+ </p>
+</td>
+</tr>
+</tbody>
+</table>
+<?php endif;
+
+do_action( 'custom_header_options' );
+
+wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?>
+
+<?php submit_button( null, 'primary', 'save-header-options' ); ?>
+</form>
+</div>
+
+<?php }
+
+ /**
+ * Display second step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ function step_2() {
+ check_admin_referer('custom-header-upload', '_wpnonce-custom-header-upload');
+ if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ if ( empty( $_POST ) && isset( $_GET['file'] ) ) {
+ $attachment_id = absint( $_GET['file'] );
+ $file = get_attached_file( $attachment_id, true );
+ $url = wp_get_attachment_image_src( $attachment_id, 'full');
+ $url = $url[0];
+ } elseif ( isset( $_POST ) ) {
+ extract($this->step_2_manage_upload());
+ }
+
+ if ( file_exists( $file ) ) {
+ list( $width, $height, $type, $attr ) = getimagesize( $file );
+ } else {
+ $data = wp_get_attachment_metadata( $attachment_id );
+ $height = isset( $data[ 'height' ] ) ? $data[ 'height' ] : 0;
+ $width = isset( $data[ 'width' ] ) ? $data[ 'width' ] : 0;
+ unset( $data );
+ }
+
+ $max_width = 0;
+ // For flex, limit size of image displayed to 1500px unless theme says otherwise
+ if ( current_theme_supports( 'custom-header', 'flex-width' ) )
+ $max_width = 1500;
+
+ if ( current_theme_supports( 'custom-header', 'max-width' ) )
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
+
+ // If flexible height isn't supported and the image is the exact right size
+ if ( ! current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' )
+ && $width == get_theme_support( 'custom-header', 'width' ) && $height == get_theme_support( 'custom-header', 'height' ) )
+ {
+ // Add the meta-data
+ if ( file_exists( $file ) )
+ wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
+
+ $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
+
+ do_action('wp_create_file_in_uploads', $file, $attachment_id); // For replication
+ return $this->finished();
+ } elseif ( $width > $max_width ) {
+ $oitar = $width / $max_width;
+ $image = wp_crop_image($attachment_id, 0, 0, $width, $height, $max_width, $height / $oitar, false, str_replace(basename($file), 'midsize-'.basename($file), $file));
+ if ( ! $image || is_wp_error( $image ) )
+ wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
+
+ $image = apply_filters('wp_create_file_in_uploads', $image, $attachment_id); // For replication
+
+ $url = str_replace(basename($url), basename($image), $url);
+ $width = $width / $oitar;
+ $height = $height / $oitar;
+ } else {
+ $oitar = 1;
+ }
+ ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php _e( 'Crop Header Image' ); ?></h2>
+
+<form method="post" action="<?php echo esc_url(add_query_arg('step', 3)); ?>">
+ <p class="hide-if-no-js"><?php _e('Choose the part of the image you want to use as your header.'); ?></p>
+ <p class="hide-if-js"><strong><?php _e( 'You need Javascript to choose a part of the image.'); ?></strong></p>
+
+ <div id="crop_image" style="position: relative">
+ <img src="<?php echo esc_url( $url ); ?>" id="upload" width="<?php echo $width; ?>" height="<?php echo $height; ?>" />
+ </div>
+
+ <input type="hidden" name="x1" id="x1" value="0"/>
+ <input type="hidden" name="y1" id="y1" value="0"/>
+ <input type="hidden" name="width" id="width" value="<?php echo esc_attr( $width ); ?>"/>
+ <input type="hidden" name="height" id="height" value="<?php echo esc_attr( $height ); ?>"/>
+ <input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr( $attachment_id ); ?>" />
+ <input type="hidden" name="oitar" id="oitar" value="<?php echo esc_attr( $oitar ); ?>" />
+ <?php if ( empty( $_POST ) && isset( $_GET['file'] ) ) { ?>
+ <input type="hidden" name="create-new-attachment" value="true" />
+ <?php } ?>
+ <?php wp_nonce_field( 'custom-header-crop-image' ) ?>
+
+ <p class="submit">
+ <?php submit_button( __( 'Crop and Publish' ), 'primary', 'submit', false ); ?>
+ <?php
+ if ( isset( $oitar ) && 1 == $oitar && ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
+ submit_button( __( 'Skip Cropping, Publish Image as Is' ), 'secondary', 'skip-cropping', false );
+ ?>
+ </p>
+</form>
+</div>
+ <?php
+ }
+
+
+ /**
+ * Upload the file to be cropped in the second step.
+ *
+ * @since 3.4.0
+ */
+ function step_2_manage_upload() {
+ $overrides = array('test_form' => false);
+
+ $uploaded_file = $_FILES['import'];
+ $wp_filetype = wp_check_filetype_and_ext( $uploaded_file['tmp_name'], $uploaded_file['name'], false );
+ if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) )
+ wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
+
+ $file = wp_handle_upload($uploaded_file, $overrides);
+
+ if ( isset($file['error']) )
+ wp_die( $file['error'], __( 'Image Upload Error' ) );
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $filename = basename($file);
+
+ // Construct the object array
+ $object = array(
+ 'post_title' => $filename,
+ 'post_content' => $url,
+ 'post_mime_type' => $type,
+ 'guid' => $url,
+ 'context' => 'custom-header'
+ );
+
+ // Save the data
+ $attachment_id = wp_insert_attachment( $object, $file );
+ return compact( 'attachment_id', 'file', 'filename', 'url', 'type' );
+ }
+
+ /**
+ * Display third step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ function step_3() {
+ check_admin_referer( 'custom-header-crop-image' );
+
+ if ( ! current_theme_supports( 'custom-header', 'uploads' ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ if ( ! empty( $_POST['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ if ( $_POST['oitar'] > 1 ) {
+ $_POST['x1'] = $_POST['x1'] * $_POST['oitar'];
+ $_POST['y1'] = $_POST['y1'] * $_POST['oitar'];
+ $_POST['width'] = $_POST['width'] * $_POST['oitar'];
+ $_POST['height'] = $_POST['height'] * $_POST['oitar'];
+ }
+
+ $attachment_id = absint( $_POST['attachment_id'] );
+ $original = get_attached_file($attachment_id);
+
+
+ $max_width = 0;
+ // For flex, limit size of image displayed to 1500px unless theme says otherwise
+ if ( current_theme_supports( 'custom-header', 'flex-width' ) )
+ $max_width = 1500;
+
+ if ( current_theme_supports( 'custom-header', 'max-width' ) )
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) );
+ $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) );
+
+ if ( ( current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) || $_POST['width'] > $max_width )
+ $dst_height = absint( $_POST['height'] * ( $max_width / $_POST['width'] ) );
+ elseif ( current_theme_supports( 'custom-header', 'flex-height' ) && current_theme_supports( 'custom-header', 'flex-width' ) )
+ $dst_height = absint( $_POST['height'] );
+ else
+ $dst_height = get_theme_support( 'custom-header', 'height' );
+
+ if ( ( current_theme_supports( 'custom-header', 'flex-width' ) && ! current_theme_supports( 'custom-header', 'flex-height' ) ) || $_POST['width'] > $max_width )
+ $dst_width = absint( $_POST['width'] * ( $max_width / $_POST['width'] ) );
+ elseif ( current_theme_supports( 'custom-header', 'flex-width' ) && current_theme_supports( 'custom-header', 'flex-height' ) )
+ $dst_width = absint( $_POST['width'] );
+ else
+ $dst_width = get_theme_support( 'custom-header', 'width' );
+
+ if ( empty( $_POST['skip-cropping'] ) )
+ $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $dst_width, $dst_height );
+ elseif ( ! empty( $_POST['create-new-attachment'] ) )
+ $cropped = _copy_image_file( $attachment_id );
+ else
+ $cropped = get_attached_file( $attachment_id );
+
+ if ( ! $cropped || is_wp_error( $cropped ) )
+ wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) );
+
+ $cropped = apply_filters('wp_create_file_in_uploads', $cropped, $attachment_id); // For replication
+
+ $parent = get_post($attachment_id);
+ $parent_url = $parent->guid;
+ $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
+
+ $size = @getimagesize( $cropped );
+ $image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
+
+ // Construct the object array
+ $object = array(
+ 'ID' => $attachment_id,
+ 'post_title' => basename($cropped),
+ 'post_content' => $url,
+ 'post_mime_type' => $image_type,
+ 'guid' => $url,
+ 'context' => 'custom-header'
+ );
+ if ( ! empty( $_POST['create-new-attachment'] ) )
+ unset( $object['ID'] );
+
+ // Update the attachment
+ $attachment_id = wp_insert_attachment( $object, $cropped );
+ wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $cropped ) );
+
+ $width = $dst_width;
+ $height = $dst_height;
+ $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) );
+
+ // cleanup
+ $medium = str_replace( basename( $original ), 'midsize-' . basename( $original ), $original );
+ if ( file_exists( $medium ) )
+ @unlink( apply_filters( 'wp_delete_file', $medium ) );
+ if ( empty( $_POST['create-new-attachment'] ) && empty( $_POST['skip-cropping'] ) )
+ @unlink( apply_filters( 'wp_delete_file', $original ) );
+
+ return $this->finished();
+ }
+
+ /**
+ * Display last step of custom header image page.
+ *
+ * @since 2.1.0
+ */
+ function finished() {
+ $this->updated = true;
+ $this->step_1();
+ }
+
+ /**
+ * Display the page based on the current step.
+ *
+ * @since 2.1.0
+ */
+ function admin_page() {
+ if ( ! current_user_can('edit_theme_options') )
+ wp_die(__('You do not have permission to customize headers.'));
+ $step = $this->step();
+ if ( 2 == $step )
+ $this->step_2();
+ elseif ( 3 == $step )
+ $this->step_3();
+ else
+ $this->step_1();
+ }
+
+ /**
+ * Unused since 3.5.0.
+ *
+ * @since 3.4.0
+ */
+ function attachment_fields_to_edit( $form_fields ) {
+ return $form_fields;
+ }
+
+ /**
+ * Unused since 3.5.0.
+ *
+ * @since 3.4.0
+ */
+ function filter_upload_tabs( $tabs ) {
+ return $tabs;
+ }
+
+ /**
+ * Choose a header image, selected from existing uploaded and default headers,
+ * or provide an array of uploaded header data (either new, or from media library).
+ *
+ * @param mixed $choice Which header image to select. Allows for values of 'random-default-image',
+ * for randomly cycling among the default images; 'random-uploaded-image', for randomly cycling
+ * among the uploaded images; the key of a default image registered for that theme; and
+ * the key of an image uploaded for that theme (the basename of the URL).
+ * Or an array of arguments: attachment_id, url, width, height. All are required.
+ *
+ * @since 3.4.0
+ */
+ final public function set_header_image( $choice ) {
+ if ( is_array( $choice ) || is_object( $choice ) ) {
+ $choice = (array) $choice;
+ if ( ! isset( $choice['attachment_id'] ) || ! isset( $choice['url'] ) )
+ return;
+
+ $choice['url'] = esc_url_raw( $choice['url'] );
+
+ $header_image_data = (object) array(
+ 'attachment_id' => $choice['attachment_id'],
+ 'url' => $choice['url'],
+ 'thumbnail_url' => $choice['url'],
+ 'height' => $choice['height'],
+ 'width' => $choice['width'],
+ );
+
+ update_post_meta( $choice['attachment_id'], '_wp_attachment_is_custom_header', get_stylesheet() );
+ set_theme_mod( 'header_image', $choice['url'] );
+ set_theme_mod( 'header_image_data', $header_image_data );
+ return;
+ }
+
+ if ( in_array( $choice, array( 'remove-header', 'random-default-image', 'random-uploaded-image' ) ) ) {
+ set_theme_mod( 'header_image', $choice );
+ remove_theme_mod( 'header_image_data' );
+ return;
+ }
+
+ $uploaded = get_uploaded_header_images();
+ if ( $uploaded && isset( $uploaded[ $choice ] ) ) {
+ $header_image_data = $uploaded[ $choice ];
+
+ } else {
+ $this->process_default_headers();
+ if ( isset( $this->default_headers[ $choice ] ) )
+ $header_image_data = $this->default_headers[ $choice ];
+ else
+ return;
+ }
+
+ set_theme_mod( 'header_image', esc_url_raw( $header_image_data['url'] ) );
+ set_theme_mod( 'header_image_data', $header_image_data );
+ }
+
+ /**
+ * Remove a header image.
+ *
+ * @since 3.4.0
+ */
+ final public function remove_header_image() {
+ return $this->set_header_image( 'remove-header' );
+ }
+
+ /**
+ * Reset a header image to the default image for the theme.
+ *
+ * This method does not do anything if the theme does not have a default header image.
+ *
+ * @since 3.4.0
+ */
+ final public function reset_header_image() {
+ $this->process_default_headers();
+ $default = get_theme_support( 'custom-header', 'default-image' );
+
+ if ( ! $default )
+ return $this->remove_header_image();
+
+ $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
+
+ $default_data = array();
+ foreach ( $this->default_headers as $header => $details ) {
+ if ( $details['url'] == $default ) {
+ $default_data = $details;
+ break;
+ }
+ }
+
+ set_theme_mod( 'header_image', $default );
+ set_theme_mod( 'header_image_data', (object) $default_data );
+ }
+}
diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php
new file mode 100644
index 0000000000..a9e05c2fd5
--- /dev/null
+++ b/src/wp-admin/customize.php
@@ -0,0 +1,210 @@
+<?php
+/**
+ * Customize Controls
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+
+define( 'IFRAME_REQUEST', true );
+
+require_once( './admin.php' );
+if ( ! current_user_can( 'edit_theme_options' ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+wp_reset_vars( array( 'url', 'return' ) );
+$url = urldecode( $url );
+$url = wp_validate_redirect( $url, home_url( '/' ) );
+if ( $return )
+ $return = wp_validate_redirect( urldecode( $return ) );
+if ( ! $return )
+ $return = $url;
+
+global $wp_scripts, $wp_customize;
+
+$registered = $wp_scripts->registered;
+$wp_scripts = new WP_Scripts;
+$wp_scripts->registered = $registered;
+
+add_action( 'customize_controls_print_scripts', 'print_head_scripts', 20 );
+add_action( 'customize_controls_print_footer_scripts', '_wp_footer_scripts' );
+add_action( 'customize_controls_print_styles', 'print_admin_styles', 20 );
+
+do_action( 'customize_controls_init' );
+
+wp_enqueue_script( 'customize-controls' );
+wp_enqueue_style( 'customize-controls' );
+
+wp_enqueue_script( 'accordion' );
+
+do_action( 'customize_controls_enqueue_scripts' );
+
+// Let's roll.
+@header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
+
+wp_user_settings();
+_wp_admin_html_begin();
+
+$body_class = 'wp-core-ui js';
+
+if ( wp_is_mobile() ) :
+ $body_class .= ' mobile';
+
+ ?><meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=0.8, minimum-scale=0.5, maximum-scale=1.2"><?php
+endif;
+
+$is_ios = wp_is_mobile() && preg_match( '/iPad|iPod|iPhone/', $_SERVER['HTTP_USER_AGENT'] );
+
+if ( $is_ios )
+ $body_class .= ' ios';
+
+if ( is_rtl() )
+ $body_class .= ' rtl';
+$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+
+$admin_title = sprintf( __( '%1$s &#8212; WordPress' ), strip_tags( sprintf( __( 'Customize %s' ), $wp_customize->theme()->display('Name') ) ) );
+?><title><?php echo $admin_title; ?></title><?php
+
+do_action( 'customize_controls_print_styles' );
+do_action( 'customize_controls_print_scripts' );
+?>
+</head>
+<body class="<?php echo esc_attr( $body_class ); ?>">
+<div class="wp-full-overlay expanded">
+ <form id="customize-controls" class="wrap wp-full-overlay-sidebar">
+
+ <div id="customize-header-actions" class="wp-full-overlay-header">
+ <?php
+ $save_text = $wp_customize->is_theme_active() ? __( 'Save &amp; Publish' ) : __( 'Save &amp; Activate' );
+ submit_button( $save_text, 'primary save', 'save', false );
+ ?>
+ <span class="spinner"></span>
+ <a class="back button" href="<?php echo esc_url( $return ? $return : admin_url( 'themes.php' ) ); ?>">
+ <?php _e( 'Cancel' ); ?>
+ </a>
+ </div>
+
+ <?php
+ $screenshot = $wp_customize->theme()->get_screenshot();
+ $cannot_expand = ! ( $screenshot || $wp_customize->theme()->get('Description') );
+ ?>
+
+ <div class="wp-full-overlay-sidebar-content accordion-container" tabindex="-1">
+ <div id="customize-info" class="accordion-section <?php if ( $cannot_expand ) echo ' cannot-expand'; ?>">
+ <div class="accordion-section-title" aria-label="<?php esc_attr_e( 'Theme Customizer Options' ); ?>" tabindex="0">
+ <span class="preview-notice"><?php
+ /* translators: %s is the theme name in the Customize/Live Preview pane */
+ echo sprintf( __( 'You are previewing %s' ), '<strong class="theme-name">' . $wp_customize->theme()->display('Name') . '</strong>' );
+ ?></span>
+ </div>
+ <?php if ( ! $cannot_expand ) : ?>
+ <div class="accordion-section-content">
+ <?php if ( $screenshot ) : ?>
+ <img class="theme-screenshot" src="<?php echo esc_url( $screenshot ); ?>" />
+ <?php endif; ?>
+
+ <?php if ( $wp_customize->theme()->get('Description') ): ?>
+ <div class="theme-description"><?php echo $wp_customize->theme()->display('Description'); ?></div>
+ <?php endif; ?>
+ </div>
+ <?php endif; ?>
+ </div>
+
+ <div id="customize-theme-controls"><ul>
+ <?php
+ foreach ( $wp_customize->sections() as $section )
+ $section->maybe_render();
+ ?>
+ </ul></div>
+ </div>
+
+ <div id="customize-footer-actions" class="wp-full-overlay-footer">
+ <a href="#" class="collapse-sidebar button-secondary" title="<?php esc_attr_e('Collapse Sidebar'); ?>">
+ <span class="collapse-sidebar-arrow"></span>
+ <span class="collapse-sidebar-label"><?php _e('Collapse'); ?></span>
+ </a>
+ </div>
+ </form>
+ <div id="customize-preview" class="wp-full-overlay-main"></div>
+ <?php
+
+ do_action( 'customize_controls_print_footer_scripts' );
+
+ // If the frontend and the admin are served from the same domain, load the
+ // preview over ssl if the customizer is being loaded over ssl. This avoids
+ // insecure content warnings. This is not attempted if the admin and frontend
+ // are on different domains to avoid the case where the frontend doesn't have
+ // ssl certs. Domain mapping plugins can allow other urls in these conditions
+ // using the customize_allowed_urls filter.
+
+ $allowed_urls = array( home_url('/') );
+ $admin_origin = parse_url( admin_url() );
+ $home_origin = parse_url( home_url() );
+ $cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
+
+ if ( is_ssl() && ! $cross_domain )
+ $allowed_urls[] = home_url( '/', 'https' );
+
+ $allowed_urls = array_unique( apply_filters( 'customize_allowed_urls', $allowed_urls ) );
+
+ $fallback_url = add_query_arg( array(
+ 'preview' => 1,
+ 'template' => $wp_customize->get_template(),
+ 'stylesheet' => $wp_customize->get_stylesheet(),
+ 'preview_iframe' => true,
+ 'TB_iframe' => 'true'
+ ), home_url( '/' ) );
+
+ $login_url = add_query_arg( array(
+ 'interim-login' => 1,
+ 'customize-login' => 1
+ ), wp_login_url() );
+
+ $settings = array(
+ 'theme' => array(
+ 'stylesheet' => $wp_customize->get_stylesheet(),
+ 'active' => $wp_customize->is_theme_active(),
+ ),
+ 'url' => array(
+ 'preview' => esc_url( $url ? $url : home_url( '/' ) ),
+ 'parent' => esc_url( admin_url() ),
+ 'activated' => admin_url( 'themes.php?activated=true&previewed' ),
+ 'ajax' => esc_url( admin_url( 'admin-ajax.php', 'relative' ) ),
+ 'allowed' => array_map( 'esc_url', $allowed_urls ),
+ 'isCrossDomain' => $cross_domain,
+ 'fallback' => $fallback_url,
+ 'home' => esc_url( home_url( '/' ) ),
+ 'login' => $login_url,
+ ),
+ 'browser' => array(
+ 'mobile' => wp_is_mobile(),
+ 'ios' => $is_ios,
+ ),
+ 'settings' => array(),
+ 'controls' => array(),
+ 'nonce' => array(
+ 'save' => wp_create_nonce( 'save-customize_' . $wp_customize->get_stylesheet() ),
+ 'preview' => wp_create_nonce( 'preview-customize_' . $wp_customize->get_stylesheet() )
+ ),
+ );
+
+ foreach ( $wp_customize->settings() as $id => $setting ) {
+ $settings['settings'][ $id ] = array(
+ 'value' => $setting->js_value(),
+ 'transport' => $setting->transport,
+ );
+ }
+
+ foreach ( $wp_customize->controls() as $id => $control ) {
+ $control->to_json();
+ $settings['controls'][ $id ] = $control->json;
+ }
+
+ ?>
+ <script type="text/javascript">
+ var _wpCustomizeSettings = <?php echo json_encode( $settings ); ?>;
+ </script>
+</div>
+</body>
+</html>
diff --git a/src/wp-admin/edit-comments.php b/src/wp-admin/edit-comments.php
new file mode 100644
index 0000000000..889270938b
--- /dev/null
+++ b/src/wp-admin/edit-comments.php
@@ -0,0 +1,255 @@
+<?php
+/**
+ * Edit Comments Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+if ( !current_user_can('edit_posts') )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+$wp_list_table = _get_list_table('WP_Comments_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+
+$doaction = $wp_list_table->current_action();
+
+if ( $doaction ) {
+ check_admin_referer( 'bulk-comments' );
+
+ if ( 'delete_all' == $doaction && !empty( $_REQUEST['pagegen_timestamp'] ) ) {
+ $comment_status = wp_unslash( $_REQUEST['comment_status'] );
+ $delete_time = wp_unslash( $_REQUEST['pagegen_timestamp'] );
+ $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_approved = %s AND %s > comment_date_gmt", $comment_status, $delete_time ) );
+ $doaction = 'delete';
+ } elseif ( isset( $_REQUEST['delete_comments'] ) ) {
+ $comment_ids = $_REQUEST['delete_comments'];
+ $doaction = ( $_REQUEST['action'] != -1 ) ? $_REQUEST['action'] : $_REQUEST['action2'];
+ } elseif ( isset( $_REQUEST['ids'] ) ) {
+ $comment_ids = array_map( 'absint', explode( ',', $_REQUEST['ids'] ) );
+ } elseif ( wp_get_referer() ) {
+ wp_safe_redirect( wp_get_referer() );
+ exit;
+ }
+
+ $approved = $unapproved = $spammed = $unspammed = $trashed = $untrashed = $deleted = 0;
+
+ $redirect_to = remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'spammed', 'unspammed', 'approved', 'unapproved', 'ids' ), wp_get_referer() );
+ $redirect_to = add_query_arg( 'paged', $pagenum, $redirect_to );
+
+ foreach ( $comment_ids as $comment_id ) { // Check the permissions on each
+ if ( !current_user_can( 'edit_comment', $comment_id ) )
+ continue;
+
+ switch ( $doaction ) {
+ case 'approve' :
+ wp_set_comment_status( $comment_id, 'approve' );
+ $approved++;
+ break;
+ case 'unapprove' :
+ wp_set_comment_status( $comment_id, 'hold' );
+ $unapproved++;
+ break;
+ case 'spam' :
+ wp_spam_comment( $comment_id );
+ $spammed++;
+ break;
+ case 'unspam' :
+ wp_unspam_comment( $comment_id );
+ $unspammed++;
+ break;
+ case 'trash' :
+ wp_trash_comment( $comment_id );
+ $trashed++;
+ break;
+ case 'untrash' :
+ wp_untrash_comment( $comment_id );
+ $untrashed++;
+ break;
+ case 'delete' :
+ wp_delete_comment( $comment_id );
+ $deleted++;
+ break;
+ }
+ }
+
+ if ( $approved )
+ $redirect_to = add_query_arg( 'approved', $approved, $redirect_to );
+ if ( $unapproved )
+ $redirect_to = add_query_arg( 'unapproved', $unapproved, $redirect_to );
+ if ( $spammed )
+ $redirect_to = add_query_arg( 'spammed', $spammed, $redirect_to );
+ if ( $unspammed )
+ $redirect_to = add_query_arg( 'unspammed', $unspammed, $redirect_to );
+ if ( $trashed )
+ $redirect_to = add_query_arg( 'trashed', $trashed, $redirect_to );
+ if ( $untrashed )
+ $redirect_to = add_query_arg( 'untrashed', $untrashed, $redirect_to );
+ if ( $deleted )
+ $redirect_to = add_query_arg( 'deleted', $deleted, $redirect_to );
+ if ( $trashed || $spammed )
+ $redirect_to = add_query_arg( 'ids', join( ',', $comment_ids ), $redirect_to );
+
+ wp_safe_redirect( $redirect_to );
+ exit;
+} elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
+ wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ exit;
+}
+
+$wp_list_table->prepare_items();
+
+wp_enqueue_script('admin-comments');
+enqueue_comment_hotkeys_js();
+
+if ( $post_id )
+ $title = sprintf( __( 'Comments on &#8220;%s&#8221;' ), wp_html_excerpt( _draft_or_post_title( $post_id ), 50, '&hellip;' ) );
+else
+ $title = __('Comments');
+
+add_screen_option( 'per_page', array('label' => _x( 'Comments', 'comments per page (screen options)' )) );
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __( 'You can manage comments made on your site similar to the way you manage posts and other content. This screen is customizable in the same ways as other management screens, and you can act on comments using the on-hover action links or the Bulk Actions.' ) . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'moderating-comments',
+'title' => __('Moderating Comments'),
+'content' =>
+ '<p>' . __( 'A yellow row means the comment is waiting for you to moderate it.' ) . '</p>' .
+ '<p>' . __( 'In the <strong>Author</strong> column, in addition to the author&#8217;s name, email address, and blog URL, the commenter&#8217;s IP address is shown. Clicking on this link will show you all the comments made from this IP address.' ) . '</p>' .
+ '<p>' . __( 'In the <strong>Comment</strong> column, above each comment it says &#8220;Submitted on,&#8221; followed by the date and time the comment was left on your site. Clicking on the date/time link will take you to that comment on your live site. Hovering over any comment gives you options to approve, reply (and approve), quick edit, edit, spam mark, or trash that comment.' ) . '</p>' .
+ '<p>' . __( 'In the <strong>In Response To</strong> column, there are three elements. The text is the name of the post that inspired the comment, and links to the post editor for that entry. The View Post link leads to that post on your live site. The small bubble with the number in it shows the number of approved comments that post has received. If the bubble is gray, you have moderated all comments for that post. If it is blue, there are pending comments. Clicking the bubble will filter the comments screen to show only comments on that post.' ) . '</p>' .
+ '<p>' . __( 'Many people take advantage of keyboard shortcuts to moderate their comments more quickly. Use the link to the side to learn more.' ) . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Administration_Screens#Comments" target="_blank">Documentation on Comments</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Comment_Spam" target="_blank">Documentation on Comment Spam</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Keyboard_Shortcuts" target="_blank">Documentation on Keyboard Shortcuts</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+);
+
+require_once('./admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php
+if ( $post_id )
+ echo sprintf( __( 'Comments on &#8220;%s&#8221;' ),
+ sprintf( '<a href="%s">%s</a>',
+ get_edit_post_link( $post_id ),
+ wp_html_excerpt( _draft_or_post_title( $post_id ), 50, '&hellip;' )
+ )
+ );
+else
+ echo __('Comments');
+
+if ( isset($_REQUEST['s']) && $_REQUEST['s'] )
+ printf( '<span class="subtitle">' . sprintf( __( 'Search results for &#8220;%s&#8221;' ), wp_html_excerpt( esc_html( wp_unslash( $_REQUEST['s'] ) ), 50, '&hellip;' ) ) . '</span>' ); ?>
+</h2>
+
+<?php
+if ( isset( $_REQUEST['error'] ) ) {
+ $error = (int) $_REQUEST['error'];
+ $error_msg = '';
+ switch ( $error ) {
+ case 1 :
+ $error_msg = __( 'Oops, no comment with this ID.' );
+ break;
+ case 2 :
+ $error_msg = __( 'You are not allowed to edit comments on this post.' );
+ break;
+ }
+ if ( $error_msg )
+ echo '<div id="moderated" class="error"><p>' . $error_msg . '</p></div>';
+}
+
+if ( isset($_REQUEST['approved']) || isset($_REQUEST['deleted']) || isset($_REQUEST['trashed']) || isset($_REQUEST['untrashed']) || isset($_REQUEST['spammed']) || isset($_REQUEST['unspammed']) || isset($_REQUEST['same']) ) {
+ $approved = isset( $_REQUEST['approved'] ) ? (int) $_REQUEST['approved'] : 0;
+ $deleted = isset( $_REQUEST['deleted'] ) ? (int) $_REQUEST['deleted'] : 0;
+ $trashed = isset( $_REQUEST['trashed'] ) ? (int) $_REQUEST['trashed'] : 0;
+ $untrashed = isset( $_REQUEST['untrashed'] ) ? (int) $_REQUEST['untrashed'] : 0;
+ $spammed = isset( $_REQUEST['spammed'] ) ? (int) $_REQUEST['spammed'] : 0;
+ $unspammed = isset( $_REQUEST['unspammed'] ) ? (int) $_REQUEST['unspammed'] : 0;
+ $same = isset( $_REQUEST['same'] ) ? (int) $_REQUEST['same'] : 0;
+
+ if ( $approved > 0 || $deleted > 0 || $trashed > 0 || $untrashed > 0 || $spammed > 0 || $unspammed > 0 || $same > 0 ) {
+ if ( $approved > 0 )
+ $messages[] = sprintf( _n( '%s comment approved', '%s comments approved', $approved ), $approved );
+
+ if ( $spammed > 0 ) {
+ $ids = isset($_REQUEST['ids']) ? $_REQUEST['ids'] : 0;
+ $messages[] = sprintf( _n( '%s comment marked as spam.', '%s comments marked as spam.', $spammed ), $spammed ) . ' <a href="' . esc_url( wp_nonce_url( "edit-comments.php?doaction=undo&action=unspam&ids=$ids", "bulk-comments" ) ) . '">' . __('Undo') . '</a><br />';
+ }
+
+ if ( $unspammed > 0 )
+ $messages[] = sprintf( _n( '%s comment restored from the spam', '%s comments restored from the spam', $unspammed ), $unspammed );
+
+ if ( $trashed > 0 ) {
+ $ids = isset($_REQUEST['ids']) ? $_REQUEST['ids'] : 0;
+ $messages[] = sprintf( _n( '%s comment moved to the Trash.', '%s comments moved to the Trash.', $trashed ), $trashed ) . ' <a href="' . esc_url( wp_nonce_url( "edit-comments.php?doaction=undo&action=untrash&ids=$ids", "bulk-comments" ) ) . '">' . __('Undo') . '</a><br />';
+ }
+
+ if ( $untrashed > 0 )
+ $messages[] = sprintf( _n( '%s comment restored from the Trash', '%s comments restored from the Trash', $untrashed ), $untrashed );
+
+ if ( $deleted > 0 )
+ $messages[] = sprintf( _n( '%s comment permanently deleted', '%s comments permanently deleted', $deleted ), $deleted );
+
+ if ( $same > 0 && $comment = get_comment( $same ) ) {
+ switch ( $comment->comment_approved ) {
+ case '1' :
+ $messages[] = __('This comment is already approved.') . ' <a href="' . esc_url( admin_url( "comment.php?action=editcomment&c=$same" ) ) . '">' . __( 'Edit comment' ) . '</a>';
+ break;
+ case 'trash' :
+ $messages[] = __( 'This comment is already in the Trash.' ) . ' <a href="' . esc_url( admin_url( 'edit-comments.php?comment_status=trash' ) ) . '"> ' . __( 'View Trash' ) . '</a>';
+ break;
+ case 'spam' :
+ $messages[] = __( 'This comment is already marked as spam.' ) . ' <a href="' . esc_url( admin_url( "comment.php?action=editcomment&c=$same" ) ) . '">' . __( 'Edit comment' ) . '</a>';
+ break;
+ }
+ }
+
+ echo '<div id="moderated" class="updated"><p>' . implode( "<br/>\n", $messages ) . '</p></div>';
+ }
+}
+?>
+
+<?php $wp_list_table->views(); ?>
+
+<form id="comments-form" action="" method="get">
+
+<?php $wp_list_table->search_box( __( 'Search Comments' ), 'comment' ); ?>
+
+<?php if ( $post_id ) : ?>
+<input type="hidden" name="p" value="<?php echo esc_attr( intval( $post_id ) ); ?>" />
+<?php endif; ?>
+<input type="hidden" name="comment_status" value="<?php echo esc_attr($comment_status); ?>" />
+<input type="hidden" name="pagegen_timestamp" value="<?php echo esc_attr(current_time('mysql', 1)); ?>" />
+
+<input type="hidden" name="_total" value="<?php echo esc_attr( $wp_list_table->get_pagination_arg('total_items') ); ?>" />
+<input type="hidden" name="_per_page" value="<?php echo esc_attr( $wp_list_table->get_pagination_arg('per_page') ); ?>" />
+<input type="hidden" name="_page" value="<?php echo esc_attr( $wp_list_table->get_pagination_arg('page') ); ?>" />
+
+<?php if ( isset($_REQUEST['paged']) ) { ?>
+ <input type="hidden" name="paged" value="<?php echo esc_attr( absint( $_REQUEST['paged'] ) ); ?>" />
+<?php } ?>
+
+<?php $wp_list_table->display(); ?>
+</form>
+</div>
+
+<div id="ajax-response"></div>
+
+<?php
+wp_comment_reply('-1', true, 'detail');
+wp_comment_trashnotice();
+include('./admin-footer.php'); ?>
diff --git a/src/wp-admin/edit-form-advanced.php b/src/wp-admin/edit-form-advanced.php
new file mode 100644
index 0000000000..e656dd5d60
--- /dev/null
+++ b/src/wp-admin/edit-form-advanced.php
@@ -0,0 +1,475 @@
+<?php
+/**
+ * Post advanced form for inclusion in the administration panels.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// don't load directly
+if ( !defined('ABSPATH') )
+ die('-1');
+
+wp_enqueue_script('post');
+
+if ( wp_is_mobile() )
+ wp_enqueue_script( 'jquery-touch-punch' );
+
+/**
+ * Post ID global
+ * @name $post_ID
+ * @var int
+ */
+$post_ID = isset($post_ID) ? (int) $post_ID : 0;
+$user_ID = isset($user_ID) ? (int) $user_ID : 0;
+$action = isset($action) ? $action : '';
+
+if ( post_type_supports($post_type, 'editor') || post_type_supports($post_type, 'thumbnail') ) {
+ add_thickbox();
+ wp_enqueue_media( array( 'post' => $post_ID ) );
+}
+
+// Add the local autosave notice HTML
+add_action( 'admin_footer', '_local_storage_notice' );
+
+$messages = array();
+$messages['post'] = array(
+ 0 => '', // Unused. Messages start at index 1.
+ 1 => sprintf( __('Post updated. <a href="%s">View post</a>'), esc_url( get_permalink($post_ID) ) ),
+ 2 => __('Custom field updated.'),
+ 3 => __('Custom field deleted.'),
+ 4 => __('Post updated.'),
+ /* translators: %s: date and time of the revision */
+ 5 => isset($_GET['revision']) ? sprintf( __('Post restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
+ 6 => sprintf( __('Post published. <a href="%s">View post</a>'), esc_url( get_permalink($post_ID) ) ),
+ 7 => __('Post saved.'),
+ 8 => sprintf( __('Post submitted. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+ 9 => sprintf( __('Post scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview post</a>'),
+ // translators: Publish box date format, see http://php.net/date
+ date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
+ 10 => sprintf( __('Post draft updated. <a target="_blank" href="%s">Preview post</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+);
+$messages['page'] = array(
+ 0 => '', // Unused. Messages start at index 1.
+ 1 => sprintf( __('Page updated. <a href="%s">View page</a>'), esc_url( get_permalink($post_ID) ) ),
+ 2 => __('Custom field updated.'),
+ 3 => __('Custom field deleted.'),
+ 4 => __('Page updated.'),
+ 5 => isset($_GET['revision']) ? sprintf( __('Page restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
+ 6 => sprintf( __('Page published. <a href="%s">View page</a>'), esc_url( get_permalink($post_ID) ) ),
+ 7 => __('Page saved.'),
+ 8 => sprintf( __('Page submitted. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+ 9 => sprintf( __('Page scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview page</a>'), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
+ 10 => sprintf( __('Page draft updated. <a target="_blank" href="%s">Preview page</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
+);
+$messages['attachment'] = array_fill( 1, 10, __( 'Media attachment updated.' ) ); // Hack, for now.
+
+$messages = apply_filters( 'post_updated_messages', $messages );
+
+$message = false;
+if ( isset($_GET['message']) ) {
+ $_GET['message'] = absint( $_GET['message'] );
+ if ( isset($messages[$post_type][$_GET['message']]) )
+ $message = $messages[$post_type][$_GET['message']];
+ elseif ( !isset($messages[$post_type]) && isset($messages['post'][$_GET['message']]) )
+ $message = $messages['post'][$_GET['message']];
+}
+
+$notice = false;
+$form_extra = '';
+if ( 'auto-draft' == $post->post_status ) {
+ if ( 'edit' == $action )
+ $post->post_title = '';
+ $autosave = false;
+ $form_extra .= "<input type='hidden' id='auto_draft' name='auto_draft' value='1' />";
+} else {
+ $autosave = wp_get_post_autosave( $post_ID );
+}
+
+$form_action = 'editpost';
+$nonce_action = 'update-post_' . $post_ID;
+$form_extra .= "<input type='hidden' id='post_ID' name='post_ID' value='" . esc_attr($post_ID) . "' />";
+
+// Detect if there exists an autosave newer than the post and if that autosave is different than the post
+if ( $autosave && mysql2date( 'U', $autosave->post_modified_gmt, false ) > mysql2date( 'U', $post->post_modified_gmt, false ) ) {
+ foreach ( _wp_post_revision_fields() as $autosave_field => $_autosave_field ) {
+ if ( normalize_whitespace( $autosave->$autosave_field ) != normalize_whitespace( $post->$autosave_field ) ) {
+ $notice = sprintf( __( 'There is an autosave of this post that is more recent than the version below. <a href="%s">View the autosave</a>' ), get_edit_post_link( $autosave->ID ) );
+ break;
+ }
+ }
+ // If this autosave isn't different from the current post, begone.
+ if ( ! $notice )
+ wp_delete_post_revision( $autosave->ID );
+ unset($autosave_field, $_autosave_field);
+}
+
+$post_type_object = get_post_type_object($post_type);
+
+// All meta boxes should be defined and added before the first do_meta_boxes() call (or potentially during the do_meta_boxes action).
+require_once('./includes/meta-boxes.php');
+
+
+$publish_callback_args = null;
+if ( post_type_supports($post_type, 'revisions') && 'auto-draft' != $post->post_status ) {
+ $revisions = wp_get_post_revisions( $post_ID );
+
+ // Check if the revisions have been upgraded
+ if ( ! empty( $revisions ) && _wp_get_post_revision_version( end( $revisions ) ) < 1 )
+ _wp_upgrade_revisions_of_post( $post, $revisions );
+
+ // We should aim to show the revisions metabox only when there are revisions.
+ if ( count( $revisions ) > 1 ) {
+ reset( $revisions ); // Reset pointer for key()
+ $publish_callback_args = array( 'revisions_count' => count( $revisions ), 'revision_id' => key( $revisions ) );
+ add_meta_box('revisionsdiv', __('Revisions'), 'post_revisions_meta_box', null, 'normal', 'core');
+ }
+}
+
+if ( 'attachment' == $post_type ) {
+ wp_enqueue_script( 'image-edit' );
+ wp_enqueue_style( 'imgareaselect' );
+ add_meta_box( 'submitdiv', __('Save'), 'attachment_submit_meta_box', null, 'side', 'core' );
+ add_action( 'edit_form_after_title', 'edit_form_image_editor' );
+} else {
+ add_meta_box( 'submitdiv', __( 'Publish' ), 'post_submit_meta_box', null, 'side', 'core', $publish_callback_args );
+}
+
+if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post_type, 'post-formats' ) )
+ add_meta_box( 'formatdiv', _x( 'Format', 'post format' ), 'post_format_meta_box', null, 'side', 'core' );
+
+// all taxonomies
+foreach ( get_object_taxonomies( $post ) as $tax_name ) {
+ $taxonomy = get_taxonomy($tax_name);
+ if ( ! $taxonomy->show_ui )
+ continue;
+
+ $label = $taxonomy->labels->name;
+
+ if ( !is_taxonomy_hierarchical($tax_name) )
+ add_meta_box('tagsdiv-' . $tax_name, $label, 'post_tags_meta_box', null, 'side', 'core', array( 'taxonomy' => $tax_name ));
+ else
+ add_meta_box($tax_name . 'div', $label, 'post_categories_meta_box', null, 'side', 'core', array( 'taxonomy' => $tax_name ));
+}
+
+if ( post_type_supports($post_type, 'page-attributes') )
+ add_meta_box('pageparentdiv', 'page' == $post_type ? __('Page Attributes') : __('Attributes'), 'page_attributes_meta_box', null, 'side', 'core');
+
+$audio_post_support = $video_post_support = false;
+$theme_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' );
+if ( 'attachment' === $post_type && ! empty( $post->post_mime_type ) ) {
+ $audio_post_support = 0 === strpos( $post->post_mime_type, 'audio/' ) && current_theme_supports( 'post-thumbnails', 'attachment:audio' ) && post_type_supports( 'attachment:audio', 'thumbnail' );
+ $video_post_support = 0 === strpos( $post->post_mime_type, 'video/' ) && current_theme_supports( 'post-thumbnails', 'attachment:video' ) && post_type_supports( 'attachment:video', 'thumbnail' );
+}
+
+if ( $theme_support || $audio_post_support || $video_post_support )
+ add_meta_box('postimagediv', __('Featured Image'), 'post_thumbnail_meta_box', null, 'side', 'low');
+
+if ( post_type_supports($post_type, 'excerpt') )
+ add_meta_box('postexcerpt', __('Excerpt'), 'post_excerpt_meta_box', null, 'normal', 'core');
+
+if ( post_type_supports($post_type, 'trackbacks') )
+ add_meta_box('trackbacksdiv', __('Send Trackbacks'), 'post_trackback_meta_box', null, 'normal', 'core');
+
+if ( post_type_supports($post_type, 'custom-fields') )
+ add_meta_box('postcustom', __('Custom Fields'), 'post_custom_meta_box', null, 'normal', 'core');
+
+do_action('dbx_post_advanced', $post);
+if ( post_type_supports($post_type, 'comments') )
+ add_meta_box('commentstatusdiv', __('Discussion'), 'post_comment_status_meta_box', null, 'normal', 'core');
+
+if ( ( 'publish' == get_post_status( $post ) || 'private' == get_post_status( $post ) ) && post_type_supports($post_type, 'comments') )
+ add_meta_box('commentsdiv', __('Comments'), 'post_comment_meta_box', null, 'normal', 'core');
+
+if ( ! ( 'pending' == get_post_status( $post ) && ! current_user_can( $post_type_object->cap->publish_posts ) ) )
+ add_meta_box('slugdiv', __('Slug'), 'post_slug_meta_box', null, 'normal', 'core');
+
+if ( post_type_supports($post_type, 'author') ) {
+ if ( is_super_admin() || current_user_can( $post_type_object->cap->edit_others_posts ) )
+ add_meta_box('authordiv', __('Author'), 'post_author_meta_box', null, 'normal', 'core');
+}
+
+do_action('add_meta_boxes', $post_type, $post);
+do_action('add_meta_boxes_' . $post_type, $post);
+
+do_action('do_meta_boxes', $post_type, 'normal', $post);
+do_action('do_meta_boxes', $post_type, 'advanced', $post);
+do_action('do_meta_boxes', $post_type, 'side', $post);
+
+add_screen_option('layout_columns', array('max' => 2, 'default' => 2) );
+
+if ( 'post' == $post_type ) {
+ $customize_display = '<p>' . __('The title field and the big Post Editing Area are fixed in place, but you can reposition all the other boxes using drag and drop. You can also minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.') . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'customize-display',
+ 'title' => __('Customizing This Display'),
+ 'content' => $customize_display,
+ ) );
+
+ $title_and_editor = '<p>' . __('<strong>Title</strong> - Enter a title for your post. After you enter a title, you&#8217;ll see the permalink below, which you can edit.') . '</p>';
+ $title_and_editor .= '<p>' . __('<strong>Post editor</strong> - Enter the text for your post. There are two modes of editing: Visual and Text. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The Text mode allows you to enter HTML along with your post text. Line breaks will be converted to paragraphs automatically. You can insert media files by clicking the icons above the post editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in Text mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular post editor.') . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'title-post-editor',
+ 'title' => __('Title and Post Editor'),
+ 'content' => $title_and_editor,
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p>' . sprintf(__('You can also create posts with the <a href="%s">Press This bookmarklet</a>.'), 'options-writing.php') . '</p>' .
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Posts_Add_New_Screen" target="_blank">Documentation on Writing and Editing Posts</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+} elseif ( 'page' == $post_type ) {
+ $about_pages = '<p>' . __('Pages are similar to Posts in that they have a title, body text, and associated metadata, but they are different in that they are not part of the chronological blog stream, kind of like permanent posts. Pages are not categorized or tagged, but can have a hierarchy. You can nest Pages under other Pages by making one the &#8220;Parent&#8221; of the other, creating a group of Pages.') . '</p>' .
+ '<p>' . __('Creating a Page is very similar to creating a Post, and the screens can be customized in the same way using drag and drop, the Screen Options tab, and expanding/collapsing boxes as you choose. This screen also has the distraction-free writing space, available in both the Visual and Text modes via the Fullscreen buttons. The Page editor mostly works the same as the Post editor, but there are some Page-specific features in the Page Attributes box:') . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'about-pages',
+ 'title' => __('About Pages'),
+ 'content' => $about_pages,
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Pages_Add_New_Screen" target="_blank">Documentation on Adding New Pages</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Pages_Screen#Editing_Individual_Pages" target="_blank">Documentation on Editing Pages</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+} elseif ( 'attachment' == $post_type ) {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen allows you to edit four fields for metadata in a file within the media library.') . '</p>' .
+ '<p>' . __('For images only, you can click on Edit Image under the thumbnail to expand out an inline image editor with icons for cropping, rotating, or flipping the image as well as for undoing and redoing. The boxes on the right give you more options for scaling the image, for cropping it, and for cropping the thumbnail in a different way than you crop the original image. You can click on Help in those boxes to get more information.') . '</p>' .
+ '<p>' . __('Note that you crop the image by clicking on it (the Crop icon is already selected) and dragging the cropping frame to select the desired part. Then click Save to retain the cropping.') . '</p>' .
+ '<p>' . __('Remember to click Update Media to save metadata entered or changed.') . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Media_Add_New_Screen#Edit_Media" target="_blank">Documentation on Edit Media</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+}
+
+if ( 'post' == $post_type || 'page' == $post_type ) {
+ $inserting_media = '<p>' . __( 'You can upload and insert media (images, audio, documents, etc.) by clicking the Add Media button. You can select from the images and files already uploaded to the Media Library, or upload new media to add to your page or post. To create an image gallery, select the images to add and click the &#8220;Create a new gallery&#8221; button.' ) . '</p>';
+ $inserting_media .= '<p>' . __( 'You can also embed media from many popular websites including Twitter, YouTube, Flickr and others by pasting the media URL on its own line into the content of your post/page. Please refer to the Codex to <a href="http://codex.wordpress.org/Embeds">learn more about embeds</a>.' ) . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'inserting-media',
+ 'title' => __( 'Inserting Media' ),
+ 'content' => $inserting_media,
+ ) );
+}
+
+if ( 'post' == $post_type ) {
+ $publish_box = '<p>' . __('Several boxes on this screen contain settings for how your content will be published, including:') . '</p>';
+ $publish_box .= '<ul><li>' . __('<strong>Publish</strong> - You can set the terms of publishing your post in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a post or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a post to be published in the future or backdate a post.') . '</li>';
+
+ if ( current_theme_supports( 'post-formats' ) && post_type_supports( 'post', 'post-formats' ) ) {
+ $publish_box .= '<li>' . __( '<strong>Format</strong> - Post Formats designate how your theme will display a specific post. For example, you could have a <em>standard</em> blog post with a title and paragraphs, or a short <em>aside</em> that omits the title and contains a short text blurb. Please refer to the Codex for <a href="http://codex.wordpress.org/Post_Formats#Supported_Formats">descriptions of each post format</a>. Your theme could enable all or some of 10 possible formats.' ) . '</li>';
+ }
+
+ if ( current_theme_supports( 'post-thumbnails' ) && post_type_supports( 'post', 'thumbnail' ) ) {
+ $publish_box .= '<li>' . __('<strong>Featured Image</strong> - This allows you to associate an image with your post without inserting it. This is usually useful only if your theme makes use of the featured image as a post thumbnail on the home page, a custom header, etc.') . '</li>';
+ }
+
+ $publish_box .= '</ul>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'publish-box',
+ 'title' => __('Publish Settings'),
+ 'content' => $publish_box,
+ ) );
+
+ $discussion_settings = '<p>' . __('<strong>Send Trackbacks</strong> - Trackbacks are a way to notify legacy blog systems that you&#8217;ve linked to them. Enter the URL(s) you want to send trackbacks. If you link to other WordPress sites they&#8217;ll be notified automatically using pingbacks, and this field is unnecessary.') . '</p>';
+ $discussion_settings .= '<p>' . __('<strong>Discussion</strong> - You can turn comments and pings on or off, and if there are comments on the post, you can see them here and moderate them.') . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'discussion-settings',
+ 'title' => __('Discussion Settings'),
+ 'content' => $discussion_settings,
+ ) );
+} elseif ( 'page' == $post_type ) {
+ $page_attributes = '<p>' . __('<strong>Parent</strong> - You can arrange your pages in hierarchies. For example, you could have an &#8220;About&#8221; page that has &#8220;Life Story&#8221; and &#8220;My Dog&#8221; pages under it. There are no limits to how many levels you can nest pages.') . '</p>' .
+ '<p>' . __('<strong>Template</strong> - Some themes have custom templates you can use for certain pages that might have additional features or custom layouts. If so, you&#8217;ll see them in this dropdown menu.') . '</p>' .
+ '<p>' . __('<strong>Order</strong> - Pages are usually ordered alphabetically, but you can choose your own order by entering a number (1 for first, etc.) in this field.') . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'page-attributes',
+ 'title' => __('Page Attributes'),
+ 'content' => $page_attributes,
+ ) );
+}
+
+require_once('./admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php
+echo esc_html( $title );
+if ( isset( $post_new_file ) && current_user_can( $post_type_object->cap->create_posts ) )
+ echo ' <a href="' . esc_url( $post_new_file ) . '" class="add-new-h2">' . esc_html( $post_type_object->labels->add_new ) . '</a>';
+?></h2>
+<?php if ( $notice ) : ?>
+<div id="notice" class="error"><p id="has-newer-autosave"><?php echo $notice ?></p></div>
+<?php endif; ?>
+<?php if ( $message ) : ?>
+<div id="message" class="updated"><p><?php echo $message; ?></p></div>
+<?php endif; ?>
+<div id="lost-connection-notice" class="error hidden">
+ <p><span class="spinner"></span> <?php _e( '<strong>Connection lost.</strong> Saving has been disabled until you&#8217;re reconnected.' ); ?>
+ <span class="hide-if-no-sessionstorage"><?php _e( 'We&#8217;re backing up this post in your browser, just in case.' ); ?></span>
+ </p>
+</div>
+
+<form name="post" action="post.php" method="post" id="post"<?php do_action('post_edit_form_tag', $post); ?>>
+<?php wp_nonce_field($nonce_action); ?>
+<input type="hidden" id="user-id" name="user_ID" value="<?php echo (int) $user_ID ?>" />
+<input type="hidden" id="hiddenaction" name="action" value="<?php echo esc_attr( $form_action ) ?>" />
+<input type="hidden" id="originalaction" name="originalaction" value="<?php echo esc_attr( $form_action ) ?>" />
+<input type="hidden" id="post_author" name="post_author" value="<?php echo esc_attr( $post->post_author ); ?>" />
+<input type="hidden" id="post_type" name="post_type" value="<?php echo esc_attr( $post_type ) ?>" />
+<input type="hidden" id="original_post_status" name="original_post_status" value="<?php echo esc_attr( $post->post_status) ?>" />
+<input type="hidden" id="referredby" name="referredby" value="<?php echo esc_url(wp_get_referer()); ?>" />
+<?php if ( ! empty( $active_post_lock ) ) { ?>
+<input type="hidden" id="active_post_lock" value="<?php echo esc_attr( implode( ':', $active_post_lock ) ); ?>" />
+<?php
+}
+if ( 'draft' != get_post_status( $post ) )
+ wp_original_referer_field(true, 'previous');
+
+echo $form_extra;
+
+wp_nonce_field( 'autosave', 'autosavenonce', false );
+wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
+wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
+?>
+
+<?php do_action( 'edit_form_top', $post ); ?>
+
+<div id="poststuff">
+<div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
+<div id="post-body-content">
+
+<?php if ( post_type_supports($post_type, 'title') ) { ?>
+<div id="titlediv">
+<div id="titlewrap">
+ <label class="screen-reader-text" id="title-prompt-text" for="title"><?php echo apply_filters( 'enter_title_here', __( 'Enter title here' ), $post ); ?></label>
+ <input type="text" name="post_title" size="30" value="<?php echo esc_attr( htmlspecialchars( $post->post_title ) ); ?>" id="title" autocomplete="off" />
+</div>
+<div class="inside">
+<?php
+$sample_permalink_html = $post_type_object->public ? get_sample_permalink_html($post->ID) : '';
+$shortlink = wp_get_shortlink($post->ID, 'post');
+if ( !empty($shortlink) )
+ $sample_permalink_html .= '<input id="shortlink" type="hidden" value="' . esc_attr($shortlink) . '" /><a href="#" class="button button-small" onclick="prompt(&#39;URL:&#39;, jQuery(\'#shortlink\').val()); return false;">' . __('Get Shortlink') . '</a>';
+
+if ( $post_type_object->public && ! ( 'pending' == get_post_status( $post ) && !current_user_can( $post_type_object->cap->publish_posts ) ) ) {
+ $has_sample_permalink = $sample_permalink_html && 'auto-draft' != $post->post_status;
+?>
+ <div id="edit-slug-box" class="hide-if-no-js">
+ <?php
+ if ( $has_sample_permalink )
+ echo $sample_permalink_html;
+ ?>
+ </div>
+<?php
+}
+?>
+</div>
+<?php
+wp_nonce_field( 'samplepermalink', 'samplepermalinknonce', false );
+?>
+</div><!-- /titlediv -->
+<?php
+}
+
+do_action( 'edit_form_after_title', $post );
+
+if ( post_type_supports($post_type, 'editor') ) {
+?>
+<div id="postdivrich" class="postarea edit-form-section">
+
+<?php wp_editor( $post->post_content, 'content', array(
+ 'dfw' => true,
+ 'tabfocus_elements' => 'insert-media-button,save-post',
+ 'editor_height' => 360,
+) ); ?>
+<table id="post-status-info" cellspacing="0"><tbody><tr>
+ <td id="wp-word-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></td>
+ <td class="autosave-info">
+ <span class="autosave-message">&nbsp;</span>
+<?php
+ if ( 'auto-draft' != $post->post_status ) {
+ echo '<span id="last-edit">';
+ if ( $last_user = get_userdata( get_post_meta( $post_ID, '_edit_last', true ) ) ) {
+ printf(__('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), mysql2date(get_option('date_format'), $post->post_modified), mysql2date(get_option('time_format'), $post->post_modified));
+ } else {
+ printf(__('Last edited on %1$s at %2$s'), mysql2date(get_option('date_format'), $post->post_modified), mysql2date(get_option('time_format'), $post->post_modified));
+ }
+ echo '</span>';
+ } ?>
+ </td>
+</tr></tbody></table>
+
+</div>
+<?php }
+
+do_action( 'edit_form_after_editor', $post );
+?>
+</div><!-- /post-body-content -->
+
+<div id="postbox-container-1" class="postbox-container">
+<?php
+
+if ( 'page' == $post_type )
+ do_action('submitpage_box', $post);
+else
+ do_action('submitpost_box', $post);
+
+do_meta_boxes($post_type, 'side', $post);
+
+?>
+</div>
+<div id="postbox-container-2" class="postbox-container">
+<?php
+
+do_meta_boxes(null, 'normal', $post);
+
+if ( 'page' == $post_type )
+ do_action('edit_page_form', $post);
+else
+ do_action('edit_form_advanced', $post);
+
+do_meta_boxes(null, 'advanced', $post);
+
+?>
+</div>
+<?php
+
+do_action('dbx_post_sidebar', $post);
+
+?>
+</div><!-- /post-body -->
+<br class="clear" />
+</div><!-- /poststuff -->
+</form>
+</div>
+
+<?php
+if ( post_type_supports( $post_type, 'comments' ) )
+ wp_comment_reply();
+?>
+
+<?php if ( (isset($post->post_title) && '' == $post->post_title) || (isset($_GET['message']) && 2 > $_GET['message']) ) : ?>
+<script type="text/javascript">
+try{document.post.title.focus();}catch(e){}
+</script>
+<?php endif; ?>
diff --git a/src/wp-admin/edit-form-comment.php b/src/wp-admin/edit-form-comment.php
new file mode 100644
index 0000000000..d9a0523edf
--- /dev/null
+++ b/src/wp-admin/edit-form-comment.php
@@ -0,0 +1,146 @@
+<?php
+/**
+ * Edit comment form for inclusion in another file.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// don't load directly
+if ( !defined('ABSPATH') )
+ die('-1');
+?>
+<form name="post" action="comment.php" method="post" id="post">
+<?php wp_nonce_field('update-comment_' . $comment->comment_ID) ?>
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php _e('Edit Comment'); ?></h2>
+
+<div id="poststuff">
+<input type="hidden" name="user_ID" value="<?php echo (int) $user_ID; ?>" />
+<input type="hidden" name="action" value="editedcomment" />
+<input type="hidden" name="comment_ID" value="<?php echo esc_attr( $comment->comment_ID ); ?>" />
+<input type="hidden" name="comment_post_ID" value="<?php echo esc_attr( $comment->comment_post_ID ); ?>" />
+
+<div id="post-body" class="metabox-holder columns-2">
+<div id="post-body-content" class="edit-form-section">
+<div id="namediv" class="stuffbox">
+<h3><label for="name"><?php _e( 'Author' ) ?></label></h3>
+<div class="inside">
+<table class="form-table editcomment">
+<tbody>
+<tr valign="top">
+ <td class="first"><?php _e( 'Name:' ); ?></td>
+ <td><input type="text" name="newcomment_author" size="30" value="<?php echo esc_attr( $comment->comment_author ); ?>" id="name" /></td>
+</tr>
+<tr valign="top">
+ <td class="first">
+ <?php
+ if ( $comment->comment_author_email ) {
+ printf( __( 'E-mail (%s):' ), get_comment_author_email_link( __( 'send e-mail' ), '', '' ) );
+ } else {
+ _e( 'E-mail:' );
+ }
+?></td>
+ <td><input type="text" name="newcomment_author_email" size="30" value="<?php echo $comment->comment_author_email; ?>" id="email" /></td>
+</tr>
+<tr valign="top">
+ <td class="first">
+ <?php
+ if ( ! empty( $comment->comment_author_url ) && 'http://' != $comment->comment_author_url ) {
+ $link = '<a href="' . $comment->comment_author_url . '" rel="external nofollow" target="_blank">' . __('visit site') . '</a>';
+ printf( __( 'URL (%s):' ), apply_filters('get_comment_author_link', $link ) );
+ } else {
+ _e( 'URL:' );
+ } ?></td>
+ <td><input type="text" id="newcomment_author_url" name="newcomment_author_url" size="30" class="code" value="<?php echo esc_attr($comment->comment_author_url); ?>" /></td>
+</tr>
+</tbody>
+</table>
+<br />
+</div>
+</div>
+
+<div id="postdiv" class="postarea">
+<?php
+ $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
+ wp_editor( $comment->comment_content, 'content', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings ) );
+ wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
+</div>
+</div><!-- /post-body-content -->
+
+<div id="postbox-container-1" class="postbox-container">
+<div id="submitdiv" class="stuffbox" >
+<h3><span class='hndle'><?php _e('Status') ?></span></h3>
+<div class="inside">
+<div class="submitbox" id="submitcomment">
+<div id="minor-publishing">
+
+<div id="minor-publishing-actions">
+<div id="preview-action">
+<a class="preview button" href="<?php echo get_comment_link(); ?>" target="_blank"><?php _e('View Comment'); ?></a>
+</div>
+<div class="clear"></div>
+</div>
+
+<div id="misc-publishing-actions">
+
+<div class="misc-pub-section" id="comment-status-radio">
+<label class="approved"><input type="radio"<?php checked( $comment->comment_approved, '1' ); ?> name="comment_status" value="1" /><?php /* translators: comment type radio button */ _ex('Approved', 'adjective') ?></label><br />
+<label class="waiting"><input type="radio"<?php checked( $comment->comment_approved, '0' ); ?> name="comment_status" value="0" /><?php /* translators: comment type radio button */ _ex('Pending', 'adjective') ?></label><br />
+<label class="spam"><input type="radio"<?php checked( $comment->comment_approved, 'spam' ); ?> name="comment_status" value="spam" /><?php /* translators: comment type radio button */ _ex('Spam', 'adjective'); ?></label>
+</div>
+
+<div class="misc-pub-section curtime">
+<?php
+// translators: Publish box date format, see http://php.net/date
+$datef = __( 'M j, Y @ G:i' );
+$stamp = __('Submitted on: <b>%1$s</b>');
+$date = date_i18n( $datef, strtotime( $comment->comment_date ) );
+?>
+<span id="timestamp"><?php printf($stamp, $date); ?></span>&nbsp;<a href="#edit_timestamp" class="edit-timestamp hide-if-no-js"><?php _e('Edit') ?></a>
+<div id='timestampdiv' class='hide-if-js'><?php touch_time(('editcomment' == $action), 0); ?></div>
+</div>
+</div> <!-- misc actions -->
+<div class="clear"></div>
+</div>
+
+<div id="major-publishing-actions">
+<div id="delete-action">
+<?php echo "<a class='submitdelete deletion' href='" . wp_nonce_url("comment.php?action=" . ( !EMPTY_TRASH_DAYS ? 'deletecomment' : 'trashcomment' ) . "&amp;c=$comment->comment_ID&amp;_wp_original_http_referer=" . urlencode(wp_get_referer()), 'delete-comment_' . $comment->comment_ID) . "'>" . ( !EMPTY_TRASH_DAYS ? __('Delete Permanently') : __('Move to Trash') ) . "</a>\n"; ?>
+</div>
+<div id="publishing-action">
+<?php submit_button( __( 'Update' ), 'primary', 'save', false ); ?>
+</div>
+<div class="clear"></div>
+</div>
+</div>
+</div>
+</div><!-- /submitdiv -->
+</div>
+
+<div id="postbox-container-2" class="postbox-container">
+<?php
+
+do_action('add_meta_boxes', 'comment', $comment);
+do_action('add_meta_boxes_comment', $comment);
+
+do_meta_boxes(null, 'normal', $comment);
+
+?>
+</div>
+
+<input type="hidden" name="c" value="<?php echo esc_attr($comment->comment_ID) ?>" />
+<input type="hidden" name="p" value="<?php echo esc_attr($comment->comment_post_ID) ?>" />
+<input name="referredby" type="hidden" id="referredby" value="<?php echo esc_url( wp_get_referer() ); ?>" />
+<?php wp_original_referer_field(true, 'previous'); ?>
+<input type="hidden" name="noredir" value="1" />
+
+</div><!-- /post-body -->
+</div>
+</div>
+</form>
+
+<script type="text/javascript">
+try{document.post.name.focus();}catch(e){}
+</script>
diff --git a/src/wp-admin/edit-link-form.php b/src/wp-admin/edit-link-form.php
new file mode 100644
index 0000000000..0aca6e7bc1
--- /dev/null
+++ b/src/wp-admin/edit-link-form.php
@@ -0,0 +1,138 @@
+<?php
+/**
+ * Edit links form for inclusion in administration panels.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// don't load directly
+if ( !defined('ABSPATH') )
+ die('-1');
+
+if ( ! empty($link_id) ) {
+ $heading = sprintf( __( '<a href="%s">Links</a> / Edit Link' ), 'link-manager.php' );
+ $submit_text = __('Update Link');
+ $form = '<form name="editlink" id="editlink" method="post" action="link.php">';
+ $nonce_action = 'update-bookmark_' . $link_id;
+} else {
+ $heading = sprintf( __( '<a href="%s">Links</a> / Add New Link' ), 'link-manager.php' );
+ $submit_text = __('Add Link');
+ $form = '<form name="addlink" id="addlink" method="post" action="link.php">';
+ $nonce_action = 'add-bookmark';
+}
+
+require_once('./includes/meta-boxes.php');
+
+add_meta_box('linksubmitdiv', __('Save'), 'link_submit_meta_box', null, 'side', 'core');
+add_meta_box('linkcategorydiv', __('Categories'), 'link_categories_meta_box', null, 'normal', 'core');
+add_meta_box('linktargetdiv', __('Target'), 'link_target_meta_box', null, 'normal', 'core');
+add_meta_box('linkxfndiv', __('Link Relationship (XFN)'), 'link_xfn_meta_box', null, 'normal', 'core');
+add_meta_box('linkadvanceddiv', __('Advanced'), 'link_advanced_meta_box', null, 'normal', 'core');
+
+do_action('add_meta_boxes', 'link', $link);
+do_action('add_meta_boxes_link', $link);
+
+do_action('do_meta_boxes', 'link', 'normal', $link);
+do_action('do_meta_boxes', 'link', 'advanced', $link);
+do_action('do_meta_boxes', 'link', 'side', $link);
+
+add_screen_option('layout_columns', array('max' => 2, 'default' => 2) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __( 'You can add or edit links on this screen by entering information in each of the boxes. Only the link&#8217;s web address and name (the text you want to display on your site as the link) are required fields.' ) . '</p>' .
+ '<p>' . __( 'The boxes for link name, web address, and description have fixed positions, while the others may be repositioned using drag and drop. You can also hide boxes you don&#8217;t use in the Screen Options tab, or minimize boxes by clicking on the title bar of the box.' ) . '</p>' .
+ '<p>' . __( 'XFN stands for <a href="http://gmpg.org/xfn/" target="_blank">XHTML Friends Network</a>, which is optional. WordPress allows the generation of XFN attributes to show how you are related to the authors/owners of the site to which you are linking.' ) . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Links_Add_New_Screen" target="_blank">Documentation on Creating Links</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+);
+
+require_once ('admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?> <a href="link-add.php" class="add-new-h2"><?php echo esc_html_x('Add New', 'link'); ?></a></h2>
+
+<?php if ( isset( $_GET['added'] ) ) : ?>
+<div id="message" class="updated"><p><?php _e('Link added.'); ?></p></div>
+<?php endif; ?>
+
+<?php
+if ( !empty($form) )
+ echo $form;
+if ( !empty($link_added) )
+ echo $link_added;
+
+wp_nonce_field( $nonce_action );
+wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
+wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
+
+<div id="poststuff">
+
+<div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
+<div id="post-body-content">
+<div id="namediv" class="stuffbox">
+<h3><label for="link_name"><?php _ex('Name', 'link name') ?></label></h3>
+<div class="inside">
+ <input type="text" name="link_name" size="30" value="<?php echo esc_attr($link->link_name); ?>" id="link_name" />
+ <p><?php _e('Example: Nifty blogging software'); ?></p>
+</div>
+</div>
+
+<div id="addressdiv" class="stuffbox">
+<h3><label for="link_url"><?php _e('Web Address') ?></label></h3>
+<div class="inside">
+ <input type="text" name="link_url" size="30" class="code" value="<?php echo esc_attr($link->link_url); ?>" id="link_url" />
+ <p><?php _e('Example: <code>http://wordpress.org/</code> &#8212; don&#8217;t forget the <code>http://</code>'); ?></p>
+</div>
+</div>
+
+<div id="descriptiondiv" class="stuffbox">
+<h3><label for="link_description"><?php _e('Description') ?></label></h3>
+<div class="inside">
+ <input type="text" name="link_description" size="30" value="<?php echo isset($link->link_description) ? esc_attr($link->link_description) : ''; ?>" id="link_description" />
+ <p><?php _e('This will be shown when someone hovers over the link in the blogroll, or optionally below the link.'); ?></p>
+</div>
+</div>
+</div><!-- /post-body-content -->
+
+<div id="postbox-container-1" class="postbox-container">
+<?php
+
+do_action('submitlink_box');
+$side_meta_boxes = do_meta_boxes( 'link', 'side', $link );
+
+?>
+</div>
+<div id="postbox-container-2" class="postbox-container">
+<?php
+
+do_meta_boxes(null, 'normal', $link);
+
+do_meta_boxes(null, 'advanced', $link);
+
+?>
+</div>
+<?php
+
+if ( $link_id ) : ?>
+<input type="hidden" name="action" value="save" />
+<input type="hidden" name="link_id" value="<?php echo (int) $link_id; ?>" />
+<input type="hidden" name="cat_id" value="<?php echo (int) $cat_id ?>" />
+<?php else: ?>
+<input type="hidden" name="action" value="add" />
+<?php endif; ?>
+
+</div>
+</div>
+
+</form>
+</div>
diff --git a/src/wp-admin/edit-tag-form.php b/src/wp-admin/edit-tag-form.php
new file mode 100644
index 0000000000..034642ad5b
--- /dev/null
+++ b/src/wp-admin/edit-tag-form.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Edit tag form for inclusion in administration panels.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// don't load directly
+if ( !defined('ABSPATH') )
+ die('-1');
+
+if ( empty($tag_ID) ) { ?>
+ <div id="message" class="updated"><p><strong><?php _e( 'You did not select an item for editing.' ); ?></strong></p></div>
+<?php
+ return;
+}
+
+// Back compat hooks
+if ( 'category' == $taxonomy )
+ do_action('edit_category_form_pre', $tag );
+elseif ( 'link_category' == $taxonomy )
+ do_action('edit_link_category_form_pre', $tag );
+else
+ do_action('edit_tag_form_pre', $tag);
+
+do_action($taxonomy . '_pre_edit_form', $tag, $taxonomy); ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo $tax->labels->edit_item; ?></h2>
+<div id="ajax-response"></div>
+<form name="edittag" id="edittag" method="post" action="edit-tags.php" class="validate">
+<input type="hidden" name="action" value="editedtag" />
+<input type="hidden" name="tag_ID" value="<?php echo esc_attr($tag->term_id) ?>" />
+<input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy) ?>" />
+<?php wp_original_referer_field(true, 'previous'); wp_nonce_field('update-tag_' . $tag_ID); ?>
+ <table class="form-table">
+ <tr class="form-field form-required">
+ <th scope="row" valign="top"><label for="name"><?php _ex('Name', 'Taxonomy Name'); ?></label></th>
+ <td><input name="name" id="name" type="text" value="<?php if ( isset( $tag->name ) ) echo esc_attr($tag->name); ?>" size="40" aria-required="true" />
+ <p class="description"><?php _e('The name is how it appears on your site.'); ?></p></td>
+ </tr>
+<?php if ( !global_terms_enabled() ) { ?>
+ <tr class="form-field">
+ <th scope="row" valign="top"><label for="slug"><?php _ex('Slug', 'Taxonomy Slug'); ?></label></th>
+ <td><input name="slug" id="slug" type="text" value="<?php if ( isset( $tag->slug ) ) echo esc_attr(apply_filters('editable_slug', $tag->slug)); ?>" size="40" />
+ <p class="description"><?php _e('The &#8220;slug&#8221; is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.'); ?></p></td>
+ </tr>
+<?php } ?>
+<?php if ( is_taxonomy_hierarchical($taxonomy) ) : ?>
+ <tr class="form-field">
+ <th scope="row" valign="top"><label for="parent"><?php _ex('Parent', 'Taxonomy Parent'); ?></label></th>
+ <td>
+ <?php wp_dropdown_categories(array('hide_empty' => 0, 'hide_if_empty' => false, 'name' => 'parent', 'orderby' => 'name', 'taxonomy' => $taxonomy, 'selected' => $tag->parent, 'exclude_tree' => $tag->term_id, 'hierarchical' => true, 'show_option_none' => __('None'))); ?>
+ <?php if ( 'category' == $taxonomy ) : ?>
+ <p class="description"><?php _e('Categories, unlike tags, can have a hierarchy. You might have a Jazz category, and under that have children categories for Bebop and Big Band. Totally optional.'); ?></p>
+ <?php endif; ?>
+ </td>
+ </tr>
+<?php endif; // is_taxonomy_hierarchical() ?>
+ <tr class="form-field">
+ <th scope="row" valign="top"><label for="description"><?php _ex('Description', 'Taxonomy Description'); ?></label></th>
+ <td><textarea name="description" id="description" rows="5" cols="50" class="large-text"><?php echo $tag->description; // textarea_escaped ?></textarea><br />
+ <span class="description"><?php _e('The description is not prominent by default; however, some themes may show it.'); ?></span></td>
+ </tr>
+ <?php
+ // Back compat hooks
+ if ( 'category' == $taxonomy )
+ do_action('edit_category_form_fields', $tag);
+ elseif ( 'link_category' == $taxonomy )
+ do_action('edit_link_category_form_fields', $tag);
+ else
+ do_action('edit_tag_form_fields', $tag);
+
+ do_action($taxonomy . '_edit_form_fields', $tag, $taxonomy);
+ ?>
+ </table>
+<?php
+// Back compat hooks
+if ( 'category' == $taxonomy )
+ do_action('edit_category_form', $tag);
+elseif ( 'link_category' == $taxonomy )
+ do_action('edit_link_category_form', $tag);
+else
+ do_action('edit_tag_form', $tag);
+
+do_action($taxonomy . '_edit_form', $tag, $taxonomy);
+
+submit_button( __('Update') );
+?>
+</form>
+</div>
+<script type="text/javascript">
+try{document.forms.edittag.name.focus();}catch(e){}
+</script>
diff --git a/src/wp-admin/edit-tags.php b/src/wp-admin/edit-tags.php
new file mode 100644
index 0000000000..8375202df2
--- /dev/null
+++ b/src/wp-admin/edit-tags.php
@@ -0,0 +1,420 @@
+<?php
+/**
+ * Edit Tags Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! $taxnow )
+ wp_die( __( 'Invalid taxonomy' ) );
+
+$tax = get_taxonomy( $taxnow );
+
+if ( ! $tax )
+ wp_die( __( 'Invalid taxonomy' ) );
+
+if ( ! current_user_can( $tax->cap->manage_terms ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+$wp_list_table = _get_list_table('WP_Terms_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+
+$title = $tax->labels->name;
+
+if ( 'post' != $post_type ) {
+ $parent_file = ( 'attachment' == $post_type ) ? 'upload.php' : "edit.php?post_type=$post_type";
+ $submenu_file = "edit-tags.php?taxonomy=$taxonomy&amp;post_type=$post_type";
+} else if ( 'link_category' == $tax->name ) {
+ $parent_file = 'link-manager.php';
+ $submenu_file = 'edit-tags.php?taxonomy=link_category';
+} else {
+ $parent_file = 'edit.php';
+ $submenu_file = "edit-tags.php?taxonomy=$taxonomy";
+}
+
+add_screen_option( 'per_page', array( 'label' => $title, 'default' => 20, 'option' => 'edit_' . $tax->name . '_per_page' ) );
+
+switch ( $wp_list_table->current_action() ) {
+
+case 'add-tag':
+
+ check_admin_referer( 'add-tag', '_wpnonce_add-tag' );
+
+ if ( !current_user_can( $tax->cap->edit_terms ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ $ret = wp_insert_term( $_POST['tag-name'], $taxonomy, $_POST );
+ $location = 'edit-tags.php?taxonomy=' . $taxonomy;
+ if ( 'post' != $post_type )
+ $location .= '&post_type=' . $post_type;
+
+ if ( $referer = wp_get_original_referer() ) {
+ if ( false !== strpos( $referer, 'edit-tags.php' ) )
+ $location = $referer;
+ }
+
+ if ( $ret && !is_wp_error( $ret ) )
+ $location = add_query_arg( 'message', 1, $location );
+ else
+ $location = add_query_arg( 'message', 4, $location );
+ wp_redirect( $location );
+ exit;
+break;
+
+case 'delete':
+ $location = 'edit-tags.php?taxonomy=' . $taxonomy;
+ if ( 'post' != $post_type )
+ $location .= '&post_type=' . $post_type;
+ if ( $referer = wp_get_referer() ) {
+ if ( false !== strpos( $referer, 'edit-tags.php' ) )
+ $location = $referer;
+ }
+
+ if ( !isset( $_REQUEST['tag_ID'] ) ) {
+ wp_redirect( $location );
+ exit;
+ }
+
+ $tag_ID = (int) $_REQUEST['tag_ID'];
+ check_admin_referer( 'delete-tag_' . $tag_ID );
+
+ if ( !current_user_can( $tax->cap->delete_terms ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ wp_delete_term( $tag_ID, $taxonomy );
+
+ $location = add_query_arg( 'message', 2, $location );
+ wp_redirect( $location );
+ exit;
+
+break;
+
+case 'bulk-delete':
+ check_admin_referer( 'bulk-tags' );
+
+ if ( !current_user_can( $tax->cap->delete_terms ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ $tags = (array) $_REQUEST['delete_tags'];
+ foreach ( $tags as $tag_ID ) {
+ wp_delete_term( $tag_ID, $taxonomy );
+ }
+
+ $location = 'edit-tags.php?taxonomy=' . $taxonomy;
+ if ( 'post' != $post_type )
+ $location .= '&post_type=' . $post_type;
+ if ( $referer = wp_get_referer() ) {
+ if ( false !== strpos( $referer, 'edit-tags.php' ) )
+ $location = $referer;
+ }
+
+ $location = add_query_arg( 'message', 6, $location );
+ wp_redirect( $location );
+ exit;
+
+break;
+
+case 'edit':
+ $title = $tax->labels->edit_item;
+
+ $tag_ID = (int) $_REQUEST['tag_ID'];
+
+ $tag = get_term( $tag_ID, $taxonomy, OBJECT, 'edit' );
+ if ( ! $tag )
+ wp_die( __( 'You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?' ) );
+ require_once ( 'admin-header.php' );
+ include( './edit-tag-form.php' );
+
+break;
+
+case 'editedtag':
+ $tag_ID = (int) $_POST['tag_ID'];
+ check_admin_referer( 'update-tag_' . $tag_ID );
+
+ if ( !current_user_can( $tax->cap->edit_terms ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ $tag = get_term( $tag_ID, $taxonomy );
+ if ( ! $tag )
+ wp_die( __( 'You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?' ) );
+
+ $ret = wp_update_term( $tag_ID, $taxonomy, $_POST );
+
+ $location = 'edit-tags.php?taxonomy=' . $taxonomy;
+ if ( 'post' != $post_type )
+ $location .= '&post_type=' . $post_type;
+
+ if ( $referer = wp_get_original_referer() ) {
+ if ( false !== strpos( $referer, 'edit-tags.php' ) )
+ $location = $referer;
+ }
+
+ if ( $ret && !is_wp_error( $ret ) )
+ $location = add_query_arg( 'message', 3, $location );
+ else
+ $location = add_query_arg( 'message', 5, $location );
+
+ wp_redirect( $location );
+ exit;
+break;
+
+default:
+if ( ! empty($_REQUEST['_wp_http_referer']) ) {
+ $location = remove_query_arg( array('_wp_http_referer', '_wpnonce'), wp_unslash($_SERVER['REQUEST_URI']) );
+
+ if ( ! empty( $_REQUEST['paged'] ) )
+ $location = add_query_arg( 'paged', (int) $_REQUEST['paged'] );
+
+ wp_redirect( $location );
+ exit;
+}
+
+$wp_list_table->prepare_items();
+$total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
+
+if ( $pagenum > $total_pages && $total_pages > 0 ) {
+ wp_redirect( add_query_arg( 'paged', $total_pages ) );
+ exit;
+}
+
+wp_enqueue_script('admin-tags');
+if ( current_user_can($tax->cap->edit_terms) )
+ wp_enqueue_script('inline-edit-tax');
+
+if ( 'category' == $taxonomy || 'link_category' == $taxonomy || 'post_tag' == $taxonomy ) {
+ $help ='';
+ if ( 'category' == $taxonomy )
+ $help = '<p>' . sprintf(__( 'You can use categories to define sections of your site and group related posts. The default category is &#8220;Uncategorized&#8221; until you change it in your <a href="%s">writing settings</a>.' ) , 'options-writing.php' ) . '</p>';
+ elseif ( 'link_category' == $taxonomy )
+ $help = '<p>' . __( 'You can create groups of links by using Link Categories. Link Category names must be unique and Link Categories are separate from the categories you use for posts.' ) . '</p>';
+ else
+ $help = '<p>' . __( 'You can assign keywords to your posts using <strong>tags</strong>. Unlike categories, tags have no hierarchy, meaning there&#8217;s no relationship from one tag to another.' ) . '</p>';
+
+ if ( 'link_category' == $taxonomy )
+ $help .= '<p>' . __( 'You can delete Link Categories in the Bulk Action pull-down, but that action does not delete the links within the category. Instead, it moves them to the default Link Category.' ) . '</p>';
+ else
+ $help .='<p>' . __( 'What&#8217;s the difference between categories and tags? Normally, tags are ad-hoc keywords that identify important information in your post (names, subjects, etc) that may or may not recur in other posts, while categories are pre-determined sections. If you think of your site like a book, the categories are like the Table of Contents and the tags are like the terms in the index.' ) . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $help,
+ ) );
+
+ if ( 'category' == $taxonomy || 'post_tag' == $taxonomy ) {
+ if ( 'category' == $taxonomy )
+ $help = '<p>' . __( 'When adding a new category on this screen, you&#8217;ll fill in the following fields:' ) . '</p>';
+ else
+ $help = '<p>' . __( 'When adding a new tag on this screen, you&#8217;ll fill in the following fields:' ) . '</p>';
+
+ $help .= '<ul>' .
+ '<li>' . __( '<strong>Name</strong> - The name is how it appears on your site.' ) . '</li>';
+
+ if ( ! global_terms_enabled() )
+ $help .= '<li>' . __( '<strong>Slug</strong> - The &#8220;slug&#8221; is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.' ) . '</li>';
+
+ if ( 'category' == $taxonomy )
+ $help .= '<li>' . __( '<strong>Parent</strong> - Categories, unlike tags, can have a hierarchy. You might have a Jazz category, and under that have child categories for Bebop and Big Band. Totally optional. To create a subcategory, just choose another category from the Parent dropdown.' ) . '</li>';
+
+ $help .= '<li>' . __( '<strong>Description</strong> - The description is not prominent by default; however, some themes may display it.' ) . '</li>' .
+ '</ul>' .
+ '<p>' . __( 'You can change the display of this screen using the Screen Options tab to set how many items are displayed per screen and to display/hide columns in the table.' ) . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'adding-terms',
+ 'title' => 'category' == $taxonomy ? __( 'Adding Categories' ) : __( 'Adding Tags' ),
+ 'content' => $help,
+ ) );
+ }
+
+ $help = '<p><strong>' . __( 'For more information:' ) . '</strong></p>';
+
+ if ( 'category' == $taxonomy )
+ $help .= '<p>' . __( '<a href="http://codex.wordpress.org/Posts_Categories_Screen" target="_blank">Documentation on Categories</a>' ) . '</p>';
+ elseif ( 'link_category' == $taxonomy )
+ $help .= '<p>' . __( '<a href="http://codex.wordpress.org/Links_Link_Categories_Screen" target="_blank">Documentation on Link Categories</a>' ) . '</p>';
+ else
+ $help .= '<p>' . __( '<a href="http://codex.wordpress.org/Posts_Tags_Screen" target="_blank">Documentation on Tags</a>' ) . '</p>';
+
+ $help .= '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>';
+
+ get_current_screen()->set_help_sidebar( $help );
+
+ unset( $help );
+}
+
+require_once ('admin-header.php');
+
+if ( !current_user_can($tax->cap->edit_terms) )
+ wp_die( __('You are not allowed to edit this item.') );
+
+$messages[1] = __('Item added.');
+$messages[2] = __('Item deleted.');
+$messages[3] = __('Item updated.');
+$messages[4] = __('Item not added.');
+$messages[5] = __('Item not updated.');
+$messages[6] = __('Items deleted.');
+
+?>
+
+<div class="wrap nosubsub">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title );
+if ( !empty($_REQUEST['s']) )
+ printf( '<span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', esc_html( wp_unslash($_REQUEST['s']) ) ); ?>
+</h2>
+
+<?php if ( isset($_REQUEST['message']) && ( $msg = (int) $_REQUEST['message'] ) ) : ?>
+<div id="message" class="updated"><p><?php echo $messages[$msg]; ?></p></div>
+<?php $_SERVER['REQUEST_URI'] = remove_query_arg(array('message'), $_SERVER['REQUEST_URI']);
+endif; ?>
+<div id="ajax-response"></div>
+
+<form class="search-form" action="" method="get">
+<input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy); ?>" />
+<input type="hidden" name="post_type" value="<?php echo esc_attr($post_type); ?>" />
+
+<?php $wp_list_table->search_box( $tax->labels->search_items, 'tag' ); ?>
+
+</form>
+<br class="clear" />
+
+<div id="col-container">
+
+<div id="col-right">
+<div class="col-wrap">
+<form id="posts-filter" action="" method="post">
+<input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy); ?>" />
+<input type="hidden" name="post_type" value="<?php echo esc_attr($post_type); ?>" />
+
+<?php $wp_list_table->display(); ?>
+
+<br class="clear" />
+</form>
+
+<?php if ( 'category' == $taxonomy ) : ?>
+<div class="form-wrap">
+<p><?php printf(__('<strong>Note:</strong><br />Deleting a category does not delete the posts in that category. Instead, posts that were only assigned to the deleted category are set to the category <strong>%s</strong>.'), apply_filters('the_category', get_cat_name(get_option('default_category')))) ?></p>
+<?php if ( current_user_can( 'import' ) ) : ?>
+<p><?php printf(__('Categories can be selectively converted to tags using the <a href="%s">category to tag converter</a>.'), 'import.php') ?></p>
+<?php endif; ?>
+</div>
+<?php elseif ( 'post_tag' == $taxonomy && current_user_can( 'import' ) ) : ?>
+<div class="form-wrap">
+<p><?php printf(__('Tags can be selectively converted to categories using the <a href="%s">tag to category converter</a>.'), 'import.php') ;?></p>
+</div>
+<?php endif;
+do_action('after-' . $taxonomy . '-table', $taxonomy);
+?>
+
+</div>
+</div><!-- /col-right -->
+
+<div id="col-left">
+<div class="col-wrap">
+
+<?php
+
+if ( !is_null( $tax->labels->popular_items ) ) {
+ if ( current_user_can( $tax->cap->edit_terms ) )
+ $tag_cloud = wp_tag_cloud( array( 'taxonomy' => $taxonomy, 'echo' => false, 'link' => 'edit' ) );
+ else
+ $tag_cloud = wp_tag_cloud( array( 'taxonomy' => $taxonomy, 'echo' => false ) );
+
+ if ( $tag_cloud ) :
+ ?>
+<div class="tagcloud">
+<h3><?php echo $tax->labels->popular_items; ?></h3>
+<?php echo $tag_cloud; unset( $tag_cloud ); ?>
+</div>
+<?php
+endif;
+}
+
+if ( current_user_can($tax->cap->edit_terms) ) {
+ // Back compat hooks. Deprecated in preference to {$taxonomy}_pre_add_form
+ if ( 'category' == $taxonomy )
+ do_action('add_category_form_pre', (object)array('parent' => 0) );
+ elseif ( 'link_category' == $taxonomy )
+ do_action('add_link_category_form_pre', (object)array('parent' => 0) );
+ else
+ do_action('add_tag_form_pre', $taxonomy);
+
+ do_action($taxonomy . '_pre_add_form', $taxonomy);
+?>
+
+<div class="form-wrap">
+<h3><?php echo $tax->labels->add_new_item; ?></h3>
+<form id="addtag" method="post" action="edit-tags.php" class="validate">
+<input type="hidden" name="action" value="add-tag" />
+<input type="hidden" name="screen" value="<?php echo esc_attr($current_screen->id); ?>" />
+<input type="hidden" name="taxonomy" value="<?php echo esc_attr($taxonomy); ?>" />
+<input type="hidden" name="post_type" value="<?php echo esc_attr($post_type); ?>" />
+<?php wp_nonce_field('add-tag', '_wpnonce_add-tag'); ?>
+
+<div class="form-field form-required">
+ <label for="tag-name"><?php _ex('Name', 'Taxonomy Name'); ?></label>
+ <input name="tag-name" id="tag-name" type="text" value="" size="40" aria-required="true" />
+ <p><?php _e('The name is how it appears on your site.'); ?></p>
+</div>
+<?php if ( ! global_terms_enabled() ) : ?>
+<div class="form-field">
+ <label for="tag-slug"><?php _ex('Slug', 'Taxonomy Slug'); ?></label>
+ <input name="slug" id="tag-slug" type="text" value="" size="40" />
+ <p><?php _e('The &#8220;slug&#8221; is the URL-friendly version of the name. It is usually all lowercase and contains only letters, numbers, and hyphens.'); ?></p>
+</div>
+<?php endif; // global_terms_enabled() ?>
+<?php if ( is_taxonomy_hierarchical($taxonomy) ) : ?>
+<div class="form-field">
+ <label for="parent"><?php _ex('Parent', 'Taxonomy Parent'); ?></label>
+ <?php wp_dropdown_categories(array('hide_empty' => 0, 'hide_if_empty' => false, 'taxonomy' => $taxonomy, 'name' => 'parent', 'orderby' => 'name', 'hierarchical' => true, 'show_option_none' => __('None'))); ?>
+ <?php if ( 'category' == $taxonomy ) : // @todo: Generic text for hierarchical taxonomies ?>
+ <p><?php _e('Categories, unlike tags, can have a hierarchy. You might have a Jazz category, and under that have children categories for Bebop and Big Band. Totally optional.'); ?></p>
+ <?php endif; ?>
+</div>
+<?php endif; // is_taxonomy_hierarchical() ?>
+<div class="form-field">
+ <label for="tag-description"><?php _ex('Description', 'Taxonomy Description'); ?></label>
+ <textarea name="description" id="tag-description" rows="5" cols="40"></textarea>
+ <p><?php _e('The description is not prominent by default; however, some themes may show it.'); ?></p>
+</div>
+
+<?php
+if ( ! is_taxonomy_hierarchical($taxonomy) )
+ do_action('add_tag_form_fields', $taxonomy);
+do_action($taxonomy . '_add_form_fields', $taxonomy);
+
+submit_button( $tax->labels->add_new_item );
+
+// Back compat hooks. Deprecated in preference to {$taxonomy}_add_form
+if ( 'category' == $taxonomy )
+ do_action('edit_category_form', (object)array('parent' => 0) );
+elseif ( 'link_category' == $taxonomy )
+ do_action('edit_link_category_form', (object)array('parent' => 0) );
+else
+ do_action('add_tag_form', $taxonomy);
+
+do_action($taxonomy . '_add_form', $taxonomy);
+?>
+</form></div>
+<?php } ?>
+
+</div>
+</div><!-- /col-left -->
+
+</div><!-- /col-container -->
+</div><!-- /wrap -->
+<script type="text/javascript">
+try{document.forms.addtag['tag-name'].focus();}catch(e){}
+</script>
+<?php $wp_list_table->inline_edit(); ?>
+
+<?php
+break;
+}
+
+include('./admin-footer.php');
diff --git a/src/wp-admin/edit.php b/src/wp-admin/edit.php
new file mode 100644
index 0000000000..65fd03426a
--- /dev/null
+++ b/src/wp-admin/edit.php
@@ -0,0 +1,300 @@
+<?php
+/**
+ * Edit Posts Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! $typenow )
+ wp_die( __( 'Invalid post type' ) );
+
+$post_type = $typenow;
+$post_type_object = get_post_type_object( $post_type );
+
+if ( ! $post_type_object )
+ wp_die( __( 'Invalid post type' ) );
+
+if ( ! current_user_can( $post_type_object->cap->edit_posts ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+$wp_list_table = _get_list_table('WP_Posts_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+
+// Back-compat for viewing comments of an entry
+foreach ( array( 'p', 'attachment_id', 'page_id' ) as $_redirect ) {
+ if ( ! empty( $_REQUEST[ $_redirect ] ) ) {
+ wp_redirect( admin_url( 'edit-comments.php?p=' . absint( $_REQUEST[ $_redirect ] ) ) );
+ exit;
+ }
+}
+unset( $_redirect );
+
+if ( 'post' != $post_type ) {
+ $parent_file = "edit.php?post_type=$post_type";
+ $submenu_file = "edit.php?post_type=$post_type";
+ $post_new_file = "post-new.php?post_type=$post_type";
+} else {
+ $parent_file = 'edit.php';
+ $submenu_file = 'edit.php';
+ $post_new_file = 'post-new.php';
+}
+
+$doaction = $wp_list_table->current_action();
+
+if ( $doaction ) {
+ check_admin_referer('bulk-posts');
+
+ $sendback = remove_query_arg( array('trashed', 'untrashed', 'deleted', 'locked', 'ids'), wp_get_referer() );
+ if ( ! $sendback )
+ $sendback = admin_url( $parent_file );
+ $sendback = add_query_arg( 'paged', $pagenum, $sendback );
+ if ( strpos($sendback, 'post.php') !== false )
+ $sendback = admin_url($post_new_file);
+
+ if ( 'delete_all' == $doaction ) {
+ $post_status = preg_replace('/[^a-z0-9_-]+/i', '', $_REQUEST['post_status']);
+ if ( get_post_status_object($post_status) ) // Check the post status exists first
+ $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type=%s AND post_status = %s", $post_type, $post_status ) );
+ $doaction = 'delete';
+ } elseif ( isset( $_REQUEST['media'] ) ) {
+ $post_ids = $_REQUEST['media'];
+ } elseif ( isset( $_REQUEST['ids'] ) ) {
+ $post_ids = explode( ',', $_REQUEST['ids'] );
+ } elseif ( !empty( $_REQUEST['post'] ) ) {
+ $post_ids = array_map('intval', $_REQUEST['post']);
+ }
+
+ if ( !isset( $post_ids ) ) {
+ wp_redirect( $sendback );
+ exit;
+ }
+
+ switch ( $doaction ) {
+ case 'trash':
+ $trashed = $locked = 0;
+
+ foreach( (array) $post_ids as $post_id ) {
+ if ( !current_user_can( 'delete_post', $post_id) )
+ wp_die( __('You are not allowed to move this item to the Trash.') );
+
+ if ( wp_check_post_lock( $post_id ) ) {
+ $locked++;
+ continue;
+ }
+
+ if ( !wp_trash_post($post_id) )
+ wp_die( __('Error in moving to Trash.') );
+
+ $trashed++;
+ }
+
+ $sendback = add_query_arg( array('trashed' => $trashed, 'ids' => join(',', $post_ids), 'locked' => $locked ), $sendback );
+ break;
+ case 'untrash':
+ $untrashed = 0;
+ foreach( (array) $post_ids as $post_id ) {
+ if ( !current_user_can( 'delete_post', $post_id) )
+ wp_die( __('You are not allowed to restore this item from the Trash.') );
+
+ if ( !wp_untrash_post($post_id) )
+ wp_die( __('Error in restoring from Trash.') );
+
+ $untrashed++;
+ }
+ $sendback = add_query_arg('untrashed', $untrashed, $sendback);
+ break;
+ case 'delete':
+ $deleted = 0;
+ foreach( (array) $post_ids as $post_id ) {
+ $post_del = get_post($post_id);
+
+ if ( !current_user_can( 'delete_post', $post_id ) )
+ wp_die( __('You are not allowed to delete this item.') );
+
+ if ( $post_del->post_type == 'attachment' ) {
+ if ( ! wp_delete_attachment($post_id) )
+ wp_die( __('Error in deleting.') );
+ } else {
+ if ( !wp_delete_post($post_id) )
+ wp_die( __('Error in deleting.') );
+ }
+ $deleted++;
+ }
+ $sendback = add_query_arg('deleted', $deleted, $sendback);
+ break;
+ case 'edit':
+ if ( isset($_REQUEST['bulk_edit']) ) {
+ $done = bulk_edit_posts($_REQUEST);
+
+ if ( is_array($done) ) {
+ $done['updated'] = count( $done['updated'] );
+ $done['skipped'] = count( $done['skipped'] );
+ $done['locked'] = count( $done['locked'] );
+ $sendback = add_query_arg( $done, $sendback );
+ }
+ }
+ break;
+ }
+
+ $sendback = remove_query_arg( array('action', 'action2', 'tags_input', 'post_author', 'comment_status', 'ping_status', '_status', 'post', 'bulk_edit', 'post_view'), $sendback );
+
+ wp_redirect($sendback);
+ exit();
+} elseif ( ! empty($_REQUEST['_wp_http_referer']) ) {
+ wp_redirect( remove_query_arg( array('_wp_http_referer', '_wpnonce'), wp_unslash($_SERVER['REQUEST_URI']) ) );
+ exit;
+}
+
+$wp_list_table->prepare_items();
+
+wp_enqueue_script('inline-edit-post');
+
+$title = $post_type_object->labels->name;
+
+if ( 'post' == $post_type ) {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen provides access to all of your posts. You can customize the display of this screen to suit your workflow.') . '</p>'
+ ) );
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'screen-content',
+ 'title' => __('Screen Content'),
+ 'content' =>
+ '<p>' . __('You can customize the display of this screen&#8217;s contents in a number of ways:') . '</p>' .
+ '<ul>' .
+ '<li>' . __('You can hide/display columns based on your needs and decide how many posts to list per screen using the Screen Options tab.') . '</li>' .
+ '<li>' . __('You can filter the list of posts by post status using the text links in the upper left to show All, Published, Draft, or Trashed posts. The default view is to show all posts.') . '</li>' .
+ '<li>' . __('You can view posts in a simple title list or with an excerpt. Choose the view you prefer by clicking on the icons at the top of the list on the right.') . '</li>' .
+ '<li>' . __('You can refine the list to show only posts in a specific category or from a specific month by using the dropdown menus above the posts list. Click the Filter button after making your selection. You also can refine the list by clicking on the post author, category or tag in the posts list.') . '</li>' .
+ '</ul>'
+ ) );
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'action-links',
+ 'title' => __('Available Actions'),
+ 'content' =>
+ '<p>' . __('Hovering over a row in the posts list will display action links that allow you to manage your post. You can perform the following actions:') . '</p>' .
+ '<ul>' .
+ '<li>' . __('<strong>Edit</strong> takes you to the editing screen for that post. You can also reach that screen by clicking on the post title.') . '</li>' .
+ '<li>' . __('<strong>Quick Edit</strong> provides inline access to the metadata of your post, allowing you to update post details without leaving this screen.') . '</li>' .
+ '<li>' . __('<strong>Trash</strong> removes your post from this list and places it in the trash, from which you can permanently delete it.') . '</li>' .
+ '<li>' . __('<strong>Preview</strong> will show you what your draft post will look like if you publish it. View will take you to your live site to view the post. Which link is available depends on your post&#8217;s status.') . '</li>' .
+ '</ul>'
+ ) );
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'bulk-actions',
+ 'title' => __('Bulk Actions'),
+ 'content' =>
+ '<p>' . __('You can also edit or move multiple posts to the trash at once. Select the posts you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.') . '</p>' .
+ '<p>' . __('When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected posts at once. To remove a post from the grouping, just click the x next to its name in the Bulk Edit area that appears.') . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Posts_Screen" target="_blank">Documentation on Managing Posts</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+
+} elseif ( 'page' == $post_type ) {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('Pages are similar to posts in that they have a title, body text, and associated metadata, but they are different in that they are not part of the chronological blog stream, kind of like permanent posts. Pages are not categorized or tagged, but can have a hierarchy. You can nest pages under other pages by making one the &#8220;Parent&#8221; of the other, creating a group of pages.') . '</p>'
+ ) );
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'managing-pages',
+ 'title' => __('Managing Pages'),
+ 'content' =>
+ '<p>' . __('Managing pages is very similar to managing posts, and the screens can be customized in the same way.') . '</p>' .
+ '<p>' . __('You can also perform the same types of actions, including narrowing the list by using the filters, acting on a page using the action links that appear when you hover over a row, or using the Bulk Actions menu to edit the metadata for multiple pages at once.') . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Pages_Screen" target="_blank">Documentation on Managing Pages</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+}
+
+add_screen_option( 'per_page', array( 'label' => $title, 'default' => 20, 'option' => 'edit_' . $post_type . '_per_page' ) );
+
+require_once('./admin-header.php');
+?>
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php
+echo esc_html( $post_type_object->labels->name );
+if ( current_user_can( $post_type_object->cap->create_posts ) )
+ echo ' <a href="' . esc_url( $post_new_file ) . '" class="add-new-h2">' . esc_html( $post_type_object->labels->add_new ) . '</a>';
+if ( ! empty( $_REQUEST['s'] ) )
+ printf( ' <span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', get_search_query() );
+?></h2>
+
+<?php if ( isset( $_REQUEST['locked'] ) || isset( $_REQUEST['updated'] ) || isset( $_REQUEST['deleted'] ) || isset( $_REQUEST['trashed'] ) || isset( $_REQUEST['untrashed'] ) ) {
+ $messages = array();
+?>
+<div id="message" class="updated"><p>
+<?php if ( isset( $_REQUEST['updated'] ) && $updated = absint( $_REQUEST['updated'] ) ) {
+ $messages[] = sprintf( _n( '%s post updated.', '%s posts updated.', $updated ), number_format_i18n( $updated ) );
+}
+
+if ( isset( $_REQUEST['locked'] ) && $locked = absint( $_REQUEST['locked'] ) ) {
+ $messages[] = sprintf( _n( '%s item not updated, somebody is editing it.', '%s items not updated, somebody is editing them.', $locked ), number_format_i18n( $locked ) );
+}
+
+if ( isset( $_REQUEST['deleted'] ) && $deleted = absint( $_REQUEST['deleted'] ) ) {
+ $messages[] = sprintf( _n( 'Item permanently deleted.', '%s items permanently deleted.', $deleted ), number_format_i18n( $deleted ) );
+}
+
+if ( isset( $_REQUEST['trashed'] ) && $trashed = absint( $_REQUEST['trashed'] ) ) {
+ $messages[] = sprintf( _n( 'Item moved to the Trash.', '%s items moved to the Trash.', $trashed ), number_format_i18n( $trashed ) );
+ $ids = isset($_REQUEST['ids']) ? $_REQUEST['ids'] : 0;
+ $messages[] = '<a href="' . esc_url( wp_nonce_url( "edit.php?post_type=$post_type&doaction=undo&action=untrash&ids=$ids", "bulk-posts" ) ) . '">' . __('Undo') . '</a>';
+}
+
+if ( isset( $_REQUEST['untrashed'] ) && $untrashed = absint( $_REQUEST['untrashed'] ) ) {
+ $messages[] = sprintf( _n( 'Item restored from the Trash.', '%s items restored from the Trash.', $untrashed ), number_format_i18n( $untrashed ) );
+}
+
+if ( $messages )
+ echo join( ' ', $messages );
+unset( $messages );
+
+$_SERVER['REQUEST_URI'] = remove_query_arg( array( 'locked', 'skipped', 'updated', 'deleted', 'trashed', 'untrashed' ), $_SERVER['REQUEST_URI'] );
+?>
+</p></div>
+<?php } ?>
+
+<?php $wp_list_table->views(); ?>
+
+<form id="posts-filter" action="" method="get">
+
+<?php $wp_list_table->search_box( $post_type_object->labels->search_items, 'post' ); ?>
+
+<input type="hidden" name="post_status" class="post_status_page" value="<?php echo !empty($_REQUEST['post_status']) ? esc_attr($_REQUEST['post_status']) : 'all'; ?>" />
+<input type="hidden" name="post_type" class="post_type_page" value="<?php echo $post_type; ?>" />
+<?php if ( ! empty( $_REQUEST['show_sticky'] ) ) { ?>
+<input type="hidden" name="show_sticky" value="1" />
+<?php } ?>
+
+<?php $wp_list_table->display(); ?>
+
+</form>
+
+<?php
+if ( $wp_list_table->has_items() )
+ $wp_list_table->inline_edit();
+?>
+
+<div id="ajax-response"></div>
+<br class="clear" />
+</div>
+
+<?php
+include('./admin-footer.php');
diff --git a/src/wp-admin/export.php b/src/wp-admin/export.php
new file mode 100644
index 0000000000..fc491b3b3a
--- /dev/null
+++ b/src/wp-admin/export.php
@@ -0,0 +1,220 @@
+<?php
+/**
+ * WordPress Export Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Bootstrap */
+require_once ('admin.php');
+
+if ( !current_user_can('export') )
+ wp_die(__('You do not have sufficient permissions to export the content of this site.'));
+
+/** Load WordPress export API */
+require_once('./includes/export.php');
+$title = __('Export');
+
+/**
+ * Display JavaScript on the page.
+ *
+ * @since 3.5.0
+ */
+function export_add_js() {
+?>
+<script type="text/javascript">
+//<![CDATA[
+ jQuery(document).ready(function($){
+ var form = $('#export-filters'),
+ filters = form.find('.export-filters');
+ filters.hide();
+ form.find('input:radio').change(function() {
+ filters.slideUp('fast');
+ switch ( $(this).val() ) {
+ case 'posts': $('#post-filters').slideDown(); break;
+ case 'pages': $('#page-filters').slideDown(); break;
+ }
+ });
+ });
+//]]>
+</script>
+<?php
+}
+add_action( 'admin_head', 'export_add_js' );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('You can export a file of your site&#8217;s content in order to import it into another installation or platform. The export file will be an XML file format called WXR. Posts, pages, comments, custom fields, categories, and tags can be included. You can choose for the WXR file to include only certain posts or pages by setting the dropdown filters to limit the export by category, author, date range by month, or publishing status.') . '</p>' .
+ '<p>' . __('Once generated, your WXR file can be imported by another WordPress site or by another blogging platform able to access this format.') . '</p>',
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Tools_Export_Screen" target="_blank">Documentation on Export</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( isset( $_GET['download'] ) ) {
+ $args = array();
+
+ if ( ! isset( $_GET['content'] ) || 'all' == $_GET['content'] ) {
+ $args['content'] = 'all';
+ } else if ( 'posts' == $_GET['content'] ) {
+ $args['content'] = 'post';
+
+ if ( $_GET['cat'] )
+ $args['category'] = (int) $_GET['cat'];
+
+ if ( $_GET['post_author'] )
+ $args['author'] = (int) $_GET['post_author'];
+
+ if ( $_GET['post_start_date'] || $_GET['post_end_date'] ) {
+ $args['start_date'] = $_GET['post_start_date'];
+ $args['end_date'] = $_GET['post_end_date'];
+ }
+
+ if ( $_GET['post_status'] )
+ $args['status'] = $_GET['post_status'];
+ } else if ( 'pages' == $_GET['content'] ) {
+ $args['content'] = 'page';
+
+ if ( $_GET['page_author'] )
+ $args['author'] = (int) $_GET['page_author'];
+
+ if ( $_GET['page_start_date'] || $_GET['page_end_date'] ) {
+ $args['start_date'] = $_GET['page_start_date'];
+ $args['end_date'] = $_GET['page_end_date'];
+ }
+
+ if ( $_GET['page_status'] )
+ $args['status'] = $_GET['page_status'];
+ } else {
+ $args['content'] = $_GET['content'];
+ }
+
+ $args = apply_filters( 'export_args', $args );
+
+ export_wp( $args );
+ die();
+}
+
+require_once ('admin-header.php');
+
+function export_date_options( $post_type = 'post' ) {
+ global $wpdb, $wp_locale;
+
+ $months = $wpdb->get_results( $wpdb->prepare( "
+ SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
+ FROM $wpdb->posts
+ WHERE post_type = %s AND post_status != 'auto-draft'
+ ORDER BY post_date DESC
+ ", $post_type ) );
+
+ $month_count = count( $months );
+ if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
+ return;
+
+ foreach ( $months as $date ) {
+ if ( 0 == $date->year )
+ continue;
+
+ $month = zeroise( $date->month, 2 );
+ echo '<option value="' . $date->year . '-' . $month . '">' . $wp_locale->get_month( $month ) . ' ' . $date->year . '</option>';
+ }
+}
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<p><?php _e('When you click the button below WordPress will create an XML file for you to save to your computer.'); ?></p>
+<p><?php _e('This format, which we call WordPress eXtended RSS or WXR, will contain your posts, pages, comments, custom fields, categories, and tags.'); ?></p>
+<p><?php _e('Once you&#8217;ve saved the download file, you can use the Import function in another WordPress installation to import the content from this site.'); ?></p>
+
+<h3><?php _e( 'Choose what to export' ); ?></h3>
+<form action="" method="get" id="export-filters">
+<input type="hidden" name="download" value="true" />
+<p><label><input type="radio" name="content" value="all" checked="checked" /> <?php _e( 'All content' ); ?></label></p>
+<p class="description"><?php _e( 'This will contain all of your posts, pages, comments, custom fields, terms, navigation menus and custom posts.' ); ?></p>
+
+<p><label><input type="radio" name="content" value="posts" /> <?php _e( 'Posts' ); ?></label></p>
+<ul id="post-filters" class="export-filters">
+ <li>
+ <label><?php _e( 'Categories:' ); ?></label>
+ <?php wp_dropdown_categories( array( 'show_option_all' => __('All') ) ); ?>
+ </li>
+ <li>
+ <label><?php _e( 'Authors:' ); ?></label>
+<?php
+ $authors = $wpdb->get_col( "SELECT DISTINCT post_author FROM {$wpdb->posts} WHERE post_type = 'post'" );
+ wp_dropdown_users( array( 'include' => $authors, 'name' => 'post_author', 'multi' => true, 'show_option_all' => __('All') ) );
+?>
+ </li>
+ <li>
+ <label><?php _e( 'Date range:' ); ?></label>
+ <select name="post_start_date">
+ <option value="0"><?php _e( 'Start Date' ); ?></option>
+ <?php export_date_options(); ?>
+ </select>
+ <select name="post_end_date">
+ <option value="0"><?php _e( 'End Date' ); ?></option>
+ <?php export_date_options(); ?>
+ </select>
+ </li>
+ <li>
+ <label><?php _e( 'Status:' ); ?></label>
+ <select name="post_status">
+ <option value="0"><?php _e( 'All' ); ?></option>
+ <?php $post_stati = get_post_stati( array( 'internal' => false ), 'objects' );
+ foreach ( $post_stati as $status ) : ?>
+ <option value="<?php echo esc_attr( $status->name ); ?>"><?php echo esc_html( $status->label ); ?></option>
+ <?php endforeach; ?>
+ </select>
+ </li>
+</ul>
+
+<p><label><input type="radio" name="content" value="pages" /> <?php _e( 'Pages' ); ?></label></p>
+<ul id="page-filters" class="export-filters">
+ <li>
+ <label><?php _e( 'Authors:' ); ?></label>
+<?php
+ $authors = $wpdb->get_col( "SELECT DISTINCT post_author FROM {$wpdb->posts} WHERE post_type = 'page'" );
+ wp_dropdown_users( array( 'include' => $authors, 'name' => 'page_author', 'multi' => true, 'show_option_all' => __('All') ) );
+?>
+ </li>
+ <li>
+ <label><?php _e( 'Date range:' ); ?></label>
+ <select name="page_start_date">
+ <option value="0"><?php _e( 'Start Date' ); ?></option>
+ <?php export_date_options( 'page' ); ?>
+ </select>
+ <select name="page_end_date">
+ <option value="0"><?php _e( 'End Date' ); ?></option>
+ <?php export_date_options( 'page' ); ?>
+ </select>
+ </li>
+ <li>
+ <label><?php _e( 'Status:' ); ?></label>
+ <select name="page_status">
+ <option value="0"><?php _e( 'All' ); ?></option>
+ <?php foreach ( $post_stati as $status ) : ?>
+ <option value="<?php echo esc_attr( $status->name ); ?>"><?php echo esc_html( $status->label ); ?></option>
+ <?php endforeach; ?>
+ </select>
+ </li>
+</ul>
+
+<?php foreach ( get_post_types( array( '_builtin' => false, 'can_export' => true ), 'objects' ) as $post_type ) : ?>
+<p><label><input type="radio" name="content" value="<?php echo esc_attr( $post_type->name ); ?>" /> <?php echo esc_html( $post_type->label ); ?></label></p>
+<?php endforeach; ?>
+
+<?php do_action( 'export_filters' ) ?>
+
+<?php submit_button( __('Download Export File') ); ?>
+</form>
+</div>
+
+<?php include('admin-footer.php'); ?>
diff --git a/src/wp-admin/freedoms.php b/src/wp-admin/freedoms.php
new file mode 100644
index 0000000000..d7accd1b5a
--- /dev/null
+++ b/src/wp-admin/freedoms.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Your Rights administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+$title = __( 'Freedoms' );
+
+list( $display_version ) = explode( '-', $wp_version );
+
+include( ABSPATH . 'wp-admin/admin-header.php' );
+?>
+<div class="wrap about-wrap">
+
+<h1><?php printf( __( 'Welcome to WordPress %s' ), $display_version ); ?></h1>
+
+<div class="about-text"><?php printf( __( 'Thank you for updating to the latest version. WordPress %s makes your writing experience even better.' ), $display_version ); ?></div>
+
+<div class="wp-badge"><?php printf( __( 'Version %s' ), $display_version ); ?></div>
+
+<h2 class="nav-tab-wrapper">
+ <a href="about.php" class="nav-tab">
+ <?php _e( 'What&#8217;s New' ); ?>
+ </a><a href="credits.php" class="nav-tab">
+ <?php _e( 'Credits' ); ?>
+ </a><a href="freedoms.php" class="nav-tab nav-tab-active">
+ <?php _e( 'Freedoms' ); ?>
+ </a>
+</h2>
+
+<p class="about-description"><?php printf( __( 'WordPress is Free and open source software, built by a distributed community of mostly volunteer developers from around the world. WordPress comes with some awesome, worldview-changing rights courtesy of its <a href="%s">license</a>, the GPL.' ), 'http://wordpress.org/about/license/' ); ?></p>
+
+<ol start="0">
+ <li><p><?php _e( 'You have the freedom to run the program, for any purpose.' ); ?></p></li>
+ <li><p><?php _e( 'You have access to the source code, the freedom to study how the program works, and the freedom to change it to make it do what you wish.' ); ?></p></li>
+ <li><p><?php _e( 'You have the freedom to redistribute copies of the original program so you can help your neighbor.' ); ?></p></li>
+ <li><p><?php _e( 'You have the freedom to distribute copies of your modified versions to others. By doing this you can give the whole community a chance to benefit from your changes.' ); ?></p></li>
+</ol>
+
+<p><?php printf( __( 'WordPress grows when people like you tell their friends about it, and the thousands of businesses and services that are built on and around WordPress share that fact with their users. We&#8217;re flattered every time someone spreads the good word, just make sure to <a href="%s">check out our trademark guidelines</a> first.' ), 'http://wordpressfoundation.org/trademark-policy/' ); ?></p>
+
+<p><?php
+
+$plugins_url = current_user_can( 'activate_plugins' ) ? admin_url( 'plugins.php' ) : 'http://wordpress.org/plugins/';
+$themes_url = current_user_can( 'switch_themes' ) ? admin_url( 'themes.php' ) : 'http://wordpress.org/themes/';
+
+printf( __( 'Every plugin and theme in WordPress.org&#8217;s directory is 100%% GPL or a similarly free and compatible license, so you can feel safe finding <a href="%1$s">plugins</a> and <a href="%2$s">themes</a> there. If you get a plugin or theme from another source, make sure to <a href="%3$s">ask them if it&#8217;s GPL</a> first. If they don&#8217;t respect the WordPress license, we don&#8217;t recommend them.' ), $plugins_url, $themes_url, 'http://wordpress.org/about/license/' ); ?></p>
+
+<p><?php _e( 'Don&#8217;t you wish all software came with these freedoms? So do we! For more information, check out the <a href="http://www.fsf.org/">Free Software Foundation</a>.' ); ?></p>
+
+</div>
+<?php include( ABSPATH . 'wp-admin/admin-footer.php' ); ?>
diff --git a/src/wp-admin/images/align-center-2x.png b/src/wp-admin/images/align-center-2x.png
new file mode 100644
index 0000000000..0b6273445a
--- /dev/null
+++ b/src/wp-admin/images/align-center-2x.png
Binary files differ
diff --git a/src/wp-admin/images/align-center.png b/src/wp-admin/images/align-center.png
new file mode 100644
index 0000000000..e7bc807880
--- /dev/null
+++ b/src/wp-admin/images/align-center.png
Binary files differ
diff --git a/src/wp-admin/images/align-left-2x.png b/src/wp-admin/images/align-left-2x.png
new file mode 100644
index 0000000000..1b2d428333
--- /dev/null
+++ b/src/wp-admin/images/align-left-2x.png
Binary files differ
diff --git a/src/wp-admin/images/align-left.png b/src/wp-admin/images/align-left.png
new file mode 100644
index 0000000000..b438f7e003
--- /dev/null
+++ b/src/wp-admin/images/align-left.png
Binary files differ
diff --git a/src/wp-admin/images/align-none-2x.png b/src/wp-admin/images/align-none-2x.png
new file mode 100644
index 0000000000..a64a0bed51
--- /dev/null
+++ b/src/wp-admin/images/align-none-2x.png
Binary files differ
diff --git a/src/wp-admin/images/align-none.png b/src/wp-admin/images/align-none.png
new file mode 100644
index 0000000000..b72df64716
--- /dev/null
+++ b/src/wp-admin/images/align-none.png
Binary files differ
diff --git a/src/wp-admin/images/align-right-2x.png b/src/wp-admin/images/align-right-2x.png
new file mode 100644
index 0000000000..013150513b
--- /dev/null
+++ b/src/wp-admin/images/align-right-2x.png
Binary files differ
diff --git a/src/wp-admin/images/align-right.png b/src/wp-admin/images/align-right.png
new file mode 100644
index 0000000000..86a1b2e876
--- /dev/null
+++ b/src/wp-admin/images/align-right.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-2x.png b/src/wp-admin/images/arrows-2x.png
new file mode 100644
index 0000000000..0b0c53d1a6
--- /dev/null
+++ b/src/wp-admin/images/arrows-2x.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-dark-2x.png b/src/wp-admin/images/arrows-dark-2x.png
new file mode 100644
index 0000000000..86be981f0c
--- /dev/null
+++ b/src/wp-admin/images/arrows-dark-2x.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-dark-vs-2x.png b/src/wp-admin/images/arrows-dark-vs-2x.png
new file mode 100644
index 0000000000..c509a4ea8a
--- /dev/null
+++ b/src/wp-admin/images/arrows-dark-vs-2x.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-dark-vs.png b/src/wp-admin/images/arrows-dark-vs.png
new file mode 100644
index 0000000000..3c48995f35
--- /dev/null
+++ b/src/wp-admin/images/arrows-dark-vs.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-dark.png b/src/wp-admin/images/arrows-dark.png
new file mode 100644
index 0000000000..8ab73468aa
--- /dev/null
+++ b/src/wp-admin/images/arrows-dark.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-pr-2x.png b/src/wp-admin/images/arrows-pr-2x.png
new file mode 100644
index 0000000000..a384c4028d
--- /dev/null
+++ b/src/wp-admin/images/arrows-pr-2x.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-pr.png b/src/wp-admin/images/arrows-pr.png
new file mode 100644
index 0000000000..b2b909b080
--- /dev/null
+++ b/src/wp-admin/images/arrows-pr.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-vs-2x.png b/src/wp-admin/images/arrows-vs-2x.png
new file mode 100644
index 0000000000..be558778d9
--- /dev/null
+++ b/src/wp-admin/images/arrows-vs-2x.png
Binary files differ
diff --git a/src/wp-admin/images/arrows-vs.png b/src/wp-admin/images/arrows-vs.png
new file mode 100644
index 0000000000..4f1421d51b
--- /dev/null
+++ b/src/wp-admin/images/arrows-vs.png
Binary files differ
diff --git a/src/wp-admin/images/arrows.png b/src/wp-admin/images/arrows.png
new file mode 100644
index 0000000000..9e4a96cd28
--- /dev/null
+++ b/src/wp-admin/images/arrows.png
Binary files differ
diff --git a/src/wp-admin/images/bubble_bg-2x.gif b/src/wp-admin/images/bubble_bg-2x.gif
new file mode 100644
index 0000000000..ae29abb12b
--- /dev/null
+++ b/src/wp-admin/images/bubble_bg-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/bubble_bg-rtl-2x.gif b/src/wp-admin/images/bubble_bg-rtl-2x.gif
new file mode 100644
index 0000000000..38747a0897
--- /dev/null
+++ b/src/wp-admin/images/bubble_bg-rtl-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/bubble_bg-rtl.gif b/src/wp-admin/images/bubble_bg-rtl.gif
new file mode 100644
index 0000000000..5cfbefeeb0
--- /dev/null
+++ b/src/wp-admin/images/bubble_bg-rtl.gif
Binary files differ
diff --git a/src/wp-admin/images/bubble_bg.gif b/src/wp-admin/images/bubble_bg.gif
new file mode 100644
index 0000000000..315ab527fa
--- /dev/null
+++ b/src/wp-admin/images/bubble_bg.gif
Binary files differ
diff --git a/src/wp-admin/images/comment-grey-bubble-2x.png b/src/wp-admin/images/comment-grey-bubble-2x.png
new file mode 100644
index 0000000000..fafc74dd61
--- /dev/null
+++ b/src/wp-admin/images/comment-grey-bubble-2x.png
Binary files differ
diff --git a/src/wp-admin/images/comment-grey-bubble.png b/src/wp-admin/images/comment-grey-bubble.png
new file mode 100644
index 0000000000..558ee8f32d
--- /dev/null
+++ b/src/wp-admin/images/comment-grey-bubble.png
Binary files differ
diff --git a/src/wp-admin/images/date-button-2x.gif b/src/wp-admin/images/date-button-2x.gif
new file mode 100644
index 0000000000..95839c9aff
--- /dev/null
+++ b/src/wp-admin/images/date-button-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/date-button.gif b/src/wp-admin/images/date-button.gif
new file mode 100644
index 0000000000..33ecd66e11
--- /dev/null
+++ b/src/wp-admin/images/date-button.gif
Binary files differ
diff --git a/src/wp-admin/images/generic.png b/src/wp-admin/images/generic.png
new file mode 100644
index 0000000000..00575a078f
--- /dev/null
+++ b/src/wp-admin/images/generic.png
Binary files differ
diff --git a/src/wp-admin/images/icons32-2x.png b/src/wp-admin/images/icons32-2x.png
new file mode 100644
index 0000000000..67893fed3e
--- /dev/null
+++ b/src/wp-admin/images/icons32-2x.png
Binary files differ
diff --git a/src/wp-admin/images/icons32-vs-2x.png b/src/wp-admin/images/icons32-vs-2x.png
new file mode 100644
index 0000000000..512aea86ed
--- /dev/null
+++ b/src/wp-admin/images/icons32-vs-2x.png
Binary files differ
diff --git a/src/wp-admin/images/icons32-vs.png b/src/wp-admin/images/icons32-vs.png
new file mode 100644
index 0000000000..c967844650
--- /dev/null
+++ b/src/wp-admin/images/icons32-vs.png
Binary files differ
diff --git a/src/wp-admin/images/icons32.png b/src/wp-admin/images/icons32.png
new file mode 100644
index 0000000000..af061c1abb
--- /dev/null
+++ b/src/wp-admin/images/icons32.png
Binary files differ
diff --git a/src/wp-admin/images/imgedit-icons-2x.png b/src/wp-admin/images/imgedit-icons-2x.png
new file mode 100644
index 0000000000..814da5e262
--- /dev/null
+++ b/src/wp-admin/images/imgedit-icons-2x.png
Binary files differ
diff --git a/src/wp-admin/images/imgedit-icons.png b/src/wp-admin/images/imgedit-icons.png
new file mode 100644
index 0000000000..ca0b88d339
--- /dev/null
+++ b/src/wp-admin/images/imgedit-icons.png
Binary files differ
diff --git a/src/wp-admin/images/list-2x.png b/src/wp-admin/images/list-2x.png
new file mode 100644
index 0000000000..05c6eb37ff
--- /dev/null
+++ b/src/wp-admin/images/list-2x.png
Binary files differ
diff --git a/src/wp-admin/images/list.png b/src/wp-admin/images/list.png
new file mode 100644
index 0000000000..85d1295e81
--- /dev/null
+++ b/src/wp-admin/images/list.png
Binary files differ
diff --git a/src/wp-admin/images/loading.gif b/src/wp-admin/images/loading.gif
new file mode 100644
index 0000000000..85b99d46b9
--- /dev/null
+++ b/src/wp-admin/images/loading.gif
Binary files differ
diff --git a/src/wp-admin/images/lock-2x.png b/src/wp-admin/images/lock-2x.png
new file mode 100644
index 0000000000..46c5a482b7
--- /dev/null
+++ b/src/wp-admin/images/lock-2x.png
Binary files differ
diff --git a/src/wp-admin/images/lock.png b/src/wp-admin/images/lock.png
new file mode 100644
index 0000000000..e17cc7dcb6
--- /dev/null
+++ b/src/wp-admin/images/lock.png
Binary files differ
diff --git a/src/wp-admin/images/marker.png b/src/wp-admin/images/marker.png
new file mode 100644
index 0000000000..fae4b6da39
--- /dev/null
+++ b/src/wp-admin/images/marker.png
Binary files differ
diff --git a/src/wp-admin/images/mask.png b/src/wp-admin/images/mask.png
new file mode 100644
index 0000000000..0fc9cbe630
--- /dev/null
+++ b/src/wp-admin/images/mask.png
Binary files differ
diff --git a/src/wp-admin/images/media-button-2x.png b/src/wp-admin/images/media-button-2x.png
new file mode 100644
index 0000000000..b8f8ed4df8
--- /dev/null
+++ b/src/wp-admin/images/media-button-2x.png
Binary files differ
diff --git a/src/wp-admin/images/media-button-image.gif b/src/wp-admin/images/media-button-image.gif
new file mode 100644
index 0000000000..5e7e4265f8
--- /dev/null
+++ b/src/wp-admin/images/media-button-image.gif
Binary files differ
diff --git a/src/wp-admin/images/media-button-music.gif b/src/wp-admin/images/media-button-music.gif
new file mode 100644
index 0000000000..0254a08811
--- /dev/null
+++ b/src/wp-admin/images/media-button-music.gif
Binary files differ
diff --git a/src/wp-admin/images/media-button-other.gif b/src/wp-admin/images/media-button-other.gif
new file mode 100644
index 0000000000..414a95785b
--- /dev/null
+++ b/src/wp-admin/images/media-button-other.gif
Binary files differ
diff --git a/src/wp-admin/images/media-button-video.gif b/src/wp-admin/images/media-button-video.gif
new file mode 100644
index 0000000000..50ac6e0283
--- /dev/null
+++ b/src/wp-admin/images/media-button-video.gif
Binary files differ
diff --git a/src/wp-admin/images/media-button.png b/src/wp-admin/images/media-button.png
new file mode 100644
index 0000000000..752ee45232
--- /dev/null
+++ b/src/wp-admin/images/media-button.png
Binary files differ
diff --git a/src/wp-admin/images/menu-2x.png b/src/wp-admin/images/menu-2x.png
new file mode 100644
index 0000000000..0038190a54
--- /dev/null
+++ b/src/wp-admin/images/menu-2x.png
Binary files differ
diff --git a/src/wp-admin/images/menu-shadow-rtl.png b/src/wp-admin/images/menu-shadow-rtl.png
new file mode 100644
index 0000000000..fa9830cfce
--- /dev/null
+++ b/src/wp-admin/images/menu-shadow-rtl.png
Binary files differ
diff --git a/src/wp-admin/images/menu-shadow.png b/src/wp-admin/images/menu-shadow.png
new file mode 100644
index 0000000000..b48c8c8520
--- /dev/null
+++ b/src/wp-admin/images/menu-shadow.png
Binary files differ
diff --git a/src/wp-admin/images/menu-vs-2x.png b/src/wp-admin/images/menu-vs-2x.png
new file mode 100644
index 0000000000..17309fccd0
--- /dev/null
+++ b/src/wp-admin/images/menu-vs-2x.png
Binary files differ
diff --git a/src/wp-admin/images/menu-vs.png b/src/wp-admin/images/menu-vs.png
new file mode 100644
index 0000000000..afdb3d3f01
--- /dev/null
+++ b/src/wp-admin/images/menu-vs.png
Binary files differ
diff --git a/src/wp-admin/images/menu.png b/src/wp-admin/images/menu.png
new file mode 100644
index 0000000000..52189c2aff
--- /dev/null
+++ b/src/wp-admin/images/menu.png
Binary files differ
diff --git a/src/wp-admin/images/no.png b/src/wp-admin/images/no.png
new file mode 100644
index 0000000000..59c35bdccc
--- /dev/null
+++ b/src/wp-admin/images/no.png
Binary files differ
diff --git a/src/wp-admin/images/post-formats-vs.png b/src/wp-admin/images/post-formats-vs.png
new file mode 100644
index 0000000000..c8e7e8d3fd
--- /dev/null
+++ b/src/wp-admin/images/post-formats-vs.png
Binary files differ
diff --git a/src/wp-admin/images/post-formats.png b/src/wp-admin/images/post-formats.png
new file mode 100644
index 0000000000..2d749bef6a
--- /dev/null
+++ b/src/wp-admin/images/post-formats.png
Binary files differ
diff --git a/src/wp-admin/images/post-formats32-vs.png b/src/wp-admin/images/post-formats32-vs.png
new file mode 100644
index 0000000000..af2c59fe03
--- /dev/null
+++ b/src/wp-admin/images/post-formats32-vs.png
Binary files differ
diff --git a/src/wp-admin/images/post-formats32.png b/src/wp-admin/images/post-formats32.png
new file mode 100644
index 0000000000..ccafc80d79
--- /dev/null
+++ b/src/wp-admin/images/post-formats32.png
Binary files differ
diff --git a/src/wp-admin/images/press-this-2x.png b/src/wp-admin/images/press-this-2x.png
new file mode 100644
index 0000000000..c6b948c877
--- /dev/null
+++ b/src/wp-admin/images/press-this-2x.png
Binary files differ
diff --git a/src/wp-admin/images/press-this.png b/src/wp-admin/images/press-this.png
new file mode 100644
index 0000000000..01e27a2c18
--- /dev/null
+++ b/src/wp-admin/images/press-this.png
Binary files differ
diff --git a/src/wp-admin/images/resize-2x.gif b/src/wp-admin/images/resize-2x.gif
new file mode 100644
index 0000000000..9682579077
--- /dev/null
+++ b/src/wp-admin/images/resize-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/resize-rtl-2x.gif b/src/wp-admin/images/resize-rtl-2x.gif
new file mode 100644
index 0000000000..1ca2a631b7
--- /dev/null
+++ b/src/wp-admin/images/resize-rtl-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/resize-rtl.gif b/src/wp-admin/images/resize-rtl.gif
new file mode 100644
index 0000000000..95e7b32a4a
--- /dev/null
+++ b/src/wp-admin/images/resize-rtl.gif
Binary files differ
diff --git a/src/wp-admin/images/resize.gif b/src/wp-admin/images/resize.gif
new file mode 100644
index 0000000000..6a1b41cdaf
--- /dev/null
+++ b/src/wp-admin/images/resize.gif
Binary files differ
diff --git a/src/wp-admin/images/se.png b/src/wp-admin/images/se.png
new file mode 100644
index 0000000000..eb487b4636
--- /dev/null
+++ b/src/wp-admin/images/se.png
Binary files differ
diff --git a/src/wp-admin/images/sort-2x.gif b/src/wp-admin/images/sort-2x.gif
new file mode 100644
index 0000000000..ed5cf4b531
--- /dev/null
+++ b/src/wp-admin/images/sort-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/sort.gif b/src/wp-admin/images/sort.gif
new file mode 100644
index 0000000000..2a5a6e8ceb
--- /dev/null
+++ b/src/wp-admin/images/sort.gif
Binary files differ
diff --git a/src/wp-admin/images/stars-2x.png b/src/wp-admin/images/stars-2x.png
new file mode 100644
index 0000000000..15aa9debfd
--- /dev/null
+++ b/src/wp-admin/images/stars-2x.png
Binary files differ
diff --git a/src/wp-admin/images/stars-rtl-2x.png b/src/wp-admin/images/stars-rtl-2x.png
new file mode 100644
index 0000000000..9790115e83
--- /dev/null
+++ b/src/wp-admin/images/stars-rtl-2x.png
Binary files differ
diff --git a/src/wp-admin/images/stars-rtl.png b/src/wp-admin/images/stars-rtl.png
new file mode 100644
index 0000000000..372b36b24d
--- /dev/null
+++ b/src/wp-admin/images/stars-rtl.png
Binary files differ
diff --git a/src/wp-admin/images/stars.png b/src/wp-admin/images/stars.png
new file mode 100644
index 0000000000..c01ada13ee
--- /dev/null
+++ b/src/wp-admin/images/stars.png
Binary files differ
diff --git a/src/wp-admin/images/welcome-icons-2x.png b/src/wp-admin/images/welcome-icons-2x.png
new file mode 100644
index 0000000000..c095cf5b09
--- /dev/null
+++ b/src/wp-admin/images/welcome-icons-2x.png
Binary files differ
diff --git a/src/wp-admin/images/welcome-icons.png b/src/wp-admin/images/welcome-icons.png
new file mode 100644
index 0000000000..571593e2cc
--- /dev/null
+++ b/src/wp-admin/images/welcome-icons.png
Binary files differ
diff --git a/src/wp-admin/images/wheel.png b/src/wp-admin/images/wheel.png
new file mode 100644
index 0000000000..7e53103ed9
--- /dev/null
+++ b/src/wp-admin/images/wheel.png
Binary files differ
diff --git a/src/wp-admin/images/wordpress-logo-2x.png b/src/wp-admin/images/wordpress-logo-2x.png
new file mode 100644
index 0000000000..6679e11d24
--- /dev/null
+++ b/src/wp-admin/images/wordpress-logo-2x.png
Binary files differ
diff --git a/src/wp-admin/images/wordpress-logo.png b/src/wp-admin/images/wordpress-logo.png
new file mode 100644
index 0000000000..63b0379613
--- /dev/null
+++ b/src/wp-admin/images/wordpress-logo.png
Binary files differ
diff --git a/src/wp-admin/images/wp-badge-2x.png b/src/wp-admin/images/wp-badge-2x.png
new file mode 100644
index 0000000000..6dfb577e85
--- /dev/null
+++ b/src/wp-admin/images/wp-badge-2x.png
Binary files differ
diff --git a/src/wp-admin/images/wp-badge.png b/src/wp-admin/images/wp-badge.png
new file mode 100644
index 0000000000..ce675451ea
--- /dev/null
+++ b/src/wp-admin/images/wp-badge.png
Binary files differ
diff --git a/src/wp-admin/images/wp-logo-2x.png b/src/wp-admin/images/wp-logo-2x.png
new file mode 100644
index 0000000000..a8dad4f3e4
--- /dev/null
+++ b/src/wp-admin/images/wp-logo-2x.png
Binary files differ
diff --git a/src/wp-admin/images/wp-logo-vs-2x.png b/src/wp-admin/images/wp-logo-vs-2x.png
new file mode 100644
index 0000000000..3bfb20a06d
--- /dev/null
+++ b/src/wp-admin/images/wp-logo-vs-2x.png
Binary files differ
diff --git a/src/wp-admin/images/wp-logo-vs.png b/src/wp-admin/images/wp-logo-vs.png
new file mode 100644
index 0000000000..a619762050
--- /dev/null
+++ b/src/wp-admin/images/wp-logo-vs.png
Binary files differ
diff --git a/src/wp-admin/images/wp-logo.png b/src/wp-admin/images/wp-logo.png
new file mode 100644
index 0000000000..1324b6a89b
--- /dev/null
+++ b/src/wp-admin/images/wp-logo.png
Binary files differ
diff --git a/src/wp-admin/images/wpspin_light-2x.gif b/src/wp-admin/images/wpspin_light-2x.gif
new file mode 100644
index 0000000000..fe2d5c0fcb
--- /dev/null
+++ b/src/wp-admin/images/wpspin_light-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/wpspin_light.gif b/src/wp-admin/images/wpspin_light.gif
new file mode 100644
index 0000000000..e10b97ff9d
--- /dev/null
+++ b/src/wp-admin/images/wpspin_light.gif
Binary files differ
diff --git a/src/wp-admin/images/xit-2x.gif b/src/wp-admin/images/xit-2x.gif
new file mode 100644
index 0000000000..64ab2ce789
--- /dev/null
+++ b/src/wp-admin/images/xit-2x.gif
Binary files differ
diff --git a/src/wp-admin/images/xit.gif b/src/wp-admin/images/xit.gif
new file mode 100644
index 0000000000..80c251fdd7
--- /dev/null
+++ b/src/wp-admin/images/xit.gif
Binary files differ
diff --git a/src/wp-admin/images/yes.png b/src/wp-admin/images/yes.png
new file mode 100644
index 0000000000..fbb39836bb
--- /dev/null
+++ b/src/wp-admin/images/yes.png
Binary files differ
diff --git a/src/wp-admin/import.php b/src/wp-admin/import.php
new file mode 100644
index 0000000000..72b9142f45
--- /dev/null
+++ b/src/wp-admin/import.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Import WordPress Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+define('WP_LOAD_IMPORTERS', true);
+
+/** Load WordPress Bootstrap */
+require_once ('admin.php');
+
+if ( !current_user_can('import') )
+ wp_die(__('You do not have sufficient permissions to import content in this site.'));
+
+$title = __('Import');
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('This screen lists links to plugins to import data from blogging/content management platforms. Choose the platform you want to import from, and click Install Now when you are prompted in the popup window. If your platform is not listed, click the link to search the plugin directory for other importer plugins to see if there is one for your platform.') . '</p>' .
+ '<p>' . __('In previous versions of WordPress, all importers were built-in. They have been turned into plugins since most people only use them once or infrequently.') . '</p>',
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Tools_Import_Screen" target="_blank">Documentation on Import</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( current_user_can( 'install_plugins' ) )
+ $popular_importers = wp_get_popular_importers();
+else
+ $popular_importers = array();
+
+// Detect and redirect invalid importers like 'movabletype', which is registered as 'mt'
+if ( ! empty( $_GET['invalid'] ) && isset( $popular_importers[ $_GET['invalid'] ] ) ) {
+ $importer_id = $popular_importers[ $_GET['invalid'] ]['importer-id'];
+ if ( $importer_id != $_GET['invalid'] ) { // Prevent redirect loops.
+ wp_redirect( admin_url( 'admin.php?import=' . $importer_id ) );
+ exit;
+ }
+ unset( $importer_id );
+}
+
+add_thickbox();
+wp_enqueue_script( 'plugin-install' );
+
+require_once ('admin-header.php');
+$parent_file = 'tools.php';
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+<?php if ( ! empty( $_GET['invalid'] ) ) : ?>
+ <div class="error"><p><strong><?php _e('ERROR:')?></strong> <?php printf( __('The <strong>%s</strong> importer is invalid or is not installed.'), esc_html( $_GET['invalid'] ) ); ?></p></div>
+<?php endif; ?>
+<p><?php _e('If you have posts or comments in another system, WordPress can import those into this site. To get started, choose a system to import from below:'); ?></p>
+
+<?php
+
+$importers = get_importers();
+
+// If a popular importer is not registered, create a dummy registration that links to the plugin installer.
+foreach ( $popular_importers as $pop_importer => $pop_data ) {
+ if ( isset( $importers[ $pop_importer ] ) )
+ continue;
+ if ( isset( $importers[ $pop_data['importer-id'] ] ) )
+ continue;
+ $importers[ $pop_data['importer-id'] ] = array( $pop_data['name'], $pop_data['description'], 'install' => $pop_data['plugin-slug'] );
+}
+
+if ( empty( $importers ) ) {
+ echo '<p>' . __('No importers are available.') . '</p>'; // TODO: make more helpful
+} else {
+ uasort($importers, create_function('$a, $b', 'return strnatcasecmp($a[0], $b[0]);'));
+?>
+<table class="widefat importers" cellspacing="0">
+
+<?php
+ $alt = '';
+ foreach ($importers as $importer_id => $data) {
+ $action = '';
+ if ( isset( $data['install'] ) ) {
+ $plugin_slug = $data['install'];
+ if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_slug ) ) {
+ // Looks like Importer is installed, But not active
+ $plugins = get_plugins( '/' . $plugin_slug );
+ if ( !empty($plugins) ) {
+ $keys = array_keys($plugins);
+ $plugin_file = $plugin_slug . '/' . $keys[0];
+ $action = '<a href="' . esc_url(wp_nonce_url(admin_url('plugins.php?action=activate&plugin=' . $plugin_file . '&from=import'), 'activate-plugin_' . $plugin_file)) .
+ '"title="' . esc_attr__('Activate importer') . '"">' . $data[0] . '</a>';
+ }
+ }
+ if ( empty($action) ) {
+ if ( is_main_site() ) {
+ $action = '<a href="' . esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_slug .
+ '&from=import&TB_iframe=true&width=600&height=550' ) ) . '" class="thickbox" title="' .
+ esc_attr__('Install importer') . '">' . $data[0] . '</a>';
+ } else {
+ $action = $data[0];
+ $data[1] = sprintf( __( 'This importer is not installed. Please install importers from <a href="%s">the main site</a>.' ), get_admin_url( $current_site->blog_id, 'import.php' ) );
+ }
+ }
+ } else {
+ $action = "<a href='" . esc_url( "admin.php?import=$importer_id" ) . "' title='" . esc_attr( wptexturize( strip_tags( $data[1] ) ) ) ."'>{$data[0]}</a>";
+ }
+
+ $alt = $alt ? '' : ' class="alternate"';
+ echo "
+ <tr$alt>
+ <td class='import-system row-title'>$action</td>
+ <td class='desc'>{$data[1]}</td>
+ </tr>";
+ }
+?>
+
+</table>
+<?php
+}
+
+if ( current_user_can('install_plugins') )
+ echo '<p>' . sprintf( __('If the importer you need is not listed, <a href="%s">search the plugin directory</a> to see if an importer is available.'), esc_url( network_admin_url( 'plugin-install.php?tab=search&type=tag&s=importer' ) ) ) . '</p>';
+?>
+
+</div>
+
+<?php
+
+include ('admin-footer.php');
diff --git a/src/wp-admin/includes/admin.php b/src/wp-admin/includes/admin.php
new file mode 100644
index 0000000000..439fcdb81e
--- /dev/null
+++ b/src/wp-admin/includes/admin.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Includes all of the WordPress Administration API files.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+if ( ! defined('WP_ADMIN') ) {
+ // This file is being included from a file other than wp-admin/admin.php, so
+ // some setup was skipped. Make sure the admin message catalog is loaded since
+ // load_default_textdomain() will not have done so in this context.
+ load_textdomain( 'default', WP_LANG_DIR . '/admin-' . get_locale() . '.mo' );
+}
+
+/** WordPress Bookmark Administration API */
+require_once(ABSPATH . 'wp-admin/includes/bookmark.php');
+
+/** WordPress Comment Administration API */
+require_once(ABSPATH . 'wp-admin/includes/comment.php');
+
+/** WordPress Administration File API */
+require_once(ABSPATH . 'wp-admin/includes/file.php');
+
+/** WordPress Image Administration API */
+require_once(ABSPATH . 'wp-admin/includes/image.php');
+
+/** WordPress Media Administration API */
+require_once(ABSPATH . 'wp-admin/includes/media.php');
+
+/** WordPress Import Administration API */
+require_once(ABSPATH . 'wp-admin/includes/import.php');
+
+/** WordPress Misc Administration API */
+require_once(ABSPATH . 'wp-admin/includes/misc.php');
+
+/** WordPress Plugin Administration API */
+require_once(ABSPATH . 'wp-admin/includes/plugin.php');
+
+/** WordPress Post Administration API */
+require_once(ABSPATH . 'wp-admin/includes/post.php');
+
+/** WordPress Administration Screen API */
+require_once(ABSPATH . 'wp-admin/includes/screen.php');
+
+/** WordPress Taxonomy Administration API */
+require_once(ABSPATH . 'wp-admin/includes/taxonomy.php');
+
+/** WordPress Template Administration API */
+require_once(ABSPATH . 'wp-admin/includes/template.php');
+
+/** WordPress List Table Administration API and base class */
+require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
+require_once(ABSPATH . 'wp-admin/includes/list-table.php');
+
+/** WordPress Theme Administration API */
+require_once(ABSPATH . 'wp-admin/includes/theme.php');
+
+/** WordPress User Administration API */
+require_once(ABSPATH . 'wp-admin/includes/user.php');
+
+/** WordPress Update Administration API */
+require_once(ABSPATH . 'wp-admin/includes/update.php');
+
+/** WordPress Deprecated Administration API */
+require_once(ABSPATH . 'wp-admin/includes/deprecated.php');
+
+/** WordPress Multisite support API */
+if ( is_multisite() ) {
+ require_once(ABSPATH . 'wp-admin/includes/ms.php');
+ require_once(ABSPATH . 'wp-admin/includes/ms-deprecated.php');
+}
diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
new file mode 100644
index 0000000000..734409fe1f
--- /dev/null
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -0,0 +1,2125 @@
+<?php
+/**
+ * WordPress Core Ajax Handlers.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/*
+ * No-privilege Ajax handlers.
+ */
+
+/**
+ * Heartbeat API (experimental)
+ *
+ * Runs when the user is not logged in.
+ */
+function wp_ajax_nopriv_heartbeat() {
+ $response = array();
+
+ // screen_id is the same as $current_screen->id and the JS global 'pagenow'
+ if ( ! empty($_POST['screen_id']) )
+ $screen_id = sanitize_key($_POST['screen_id']);
+ else
+ $screen_id = 'front';
+
+ if ( ! empty($_POST['data']) ) {
+ $data = wp_unslash( (array) $_POST['data'] );
+ $response = apply_filters( 'heartbeat_nopriv_received', $response, $data, $screen_id );
+ }
+
+ $response = apply_filters( 'heartbeat_nopriv_send', $response, $screen_id );
+
+ // Allow the transport to be replaced with long-polling easily
+ do_action( 'heartbeat_nopriv_tick', $response, $screen_id );
+
+ // send the current time according to the server
+ $response['server_time'] = time();
+
+ wp_send_json($response);
+}
+
+/*
+ * GET-based Ajax handlers.
+ */
+function wp_ajax_fetch_list() {
+ global $wp_list_table;
+
+ $list_class = $_GET['list_args']['class'];
+ check_ajax_referer( "fetch-list-$list_class", '_ajax_fetch_list_nonce' );
+
+ $wp_list_table = _get_list_table( $list_class, array( 'screen' => $_GET['list_args']['screen']['id'] ) );
+ if ( ! $wp_list_table )
+ wp_die( 0 );
+
+ if ( ! $wp_list_table->ajax_user_can() )
+ wp_die( -1 );
+
+ $wp_list_table->ajax_response();
+
+ wp_die( 0 );
+}
+function wp_ajax_ajax_tag_search() {
+ global $wpdb;
+
+ if ( isset( $_GET['tax'] ) ) {
+ $taxonomy = sanitize_key( $_GET['tax'] );
+ $tax = get_taxonomy( $taxonomy );
+ if ( ! $tax )
+ wp_die( 0 );
+ if ( ! current_user_can( $tax->cap->assign_terms ) )
+ wp_die( -1 );
+ } else {
+ wp_die( 0 );
+ }
+
+ $s = wp_unslash( $_GET['q'] );
+
+ $comma = _x( ',', 'tag delimiter' );
+ if ( ',' !== $comma )
+ $s = str_replace( $comma, ',', $s );
+ if ( false !== strpos( $s, ',' ) ) {
+ $s = explode( ',', $s );
+ $s = $s[count( $s ) - 1];
+ }
+ $s = trim( $s );
+ if ( strlen( $s ) < 2 )
+ wp_die(); // require 2 chars for matching
+
+ $results = $wpdb->get_col( $wpdb->prepare( "SELECT t.name FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.name LIKE (%s)", $taxonomy, '%' . like_escape( $s ) . '%' ) );
+
+ echo join( $results, "\n" );
+ wp_die();
+}
+
+function wp_ajax_wp_compression_test() {
+ if ( !current_user_can( 'manage_options' ) )
+ wp_die( -1 );
+
+ if ( ini_get('zlib.output_compression') || 'ob_gzhandler' == ini_get('output_handler') ) {
+ update_site_option('can_compress_scripts', 0);
+ wp_die( 0 );
+ }
+
+ if ( isset($_GET['test']) ) {
+ header( 'Expires: Wed, 11 Jan 1984 05:00:00 GMT' );
+ header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
+ header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
+ header( 'Pragma: no-cache' );
+ header('Content-Type: application/x-javascript; charset=UTF-8');
+ $force_gzip = ( defined('ENFORCE_GZIP') && ENFORCE_GZIP );
+ $test_str = '"wpCompressionTest Lorem ipsum dolor sit amet consectetuer mollis sapien urna ut a. Eu nonummy condimentum fringilla tempor pretium platea vel nibh netus Maecenas. Hac molestie amet justo quis pellentesque est ultrices interdum nibh Morbi. Cras mattis pretium Phasellus ante ipsum ipsum ut sociis Suspendisse Lorem. Ante et non molestie. Porta urna Vestibulum egestas id congue nibh eu risus gravida sit. Ac augue auctor Ut et non a elit massa id sodales. Elit eu Nulla at nibh adipiscing mattis lacus mauris at tempus. Netus nibh quis suscipit nec feugiat eget sed lorem et urna. Pellentesque lacus at ut massa consectetuer ligula ut auctor semper Pellentesque. Ut metus massa nibh quam Curabitur molestie nec mauris congue. Volutpat molestie elit justo facilisis neque ac risus Ut nascetur tristique. Vitae sit lorem tellus et quis Phasellus lacus tincidunt nunc Fusce. Pharetra wisi Suspendisse mus sagittis libero lacinia Integer consequat ac Phasellus. Et urna ac cursus tortor aliquam Aliquam amet tellus volutpat Vestibulum. Justo interdum condimentum In augue congue tellus sollicitudin Quisque quis nibh."';
+
+ if ( 1 == $_GET['test'] ) {
+ echo $test_str;
+ wp_die();
+ } elseif ( 2 == $_GET['test'] ) {
+ if ( !isset($_SERVER['HTTP_ACCEPT_ENCODING']) )
+ wp_die( -1 );
+ if ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
+ header('Content-Encoding: deflate');
+ $out = gzdeflate( $test_str, 1 );
+ } elseif ( false !== stripos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
+ header('Content-Encoding: gzip');
+ $out = gzencode( $test_str, 1 );
+ } else {
+ wp_die( -1 );
+ }
+ echo $out;
+ wp_die();
+ } elseif ( 'no' == $_GET['test'] ) {
+ update_site_option('can_compress_scripts', 0);
+ } elseif ( 'yes' == $_GET['test'] ) {
+ update_site_option('can_compress_scripts', 1);
+ }
+ }
+
+ wp_die( 0 );
+}
+
+function wp_ajax_imgedit_preview() {
+ $post_id = intval($_GET['postid']);
+ if ( empty($post_id) || !current_user_can('edit_post', $post_id) )
+ wp_die( -1 );
+
+ check_ajax_referer( "image_editor-$post_id" );
+
+ include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
+ if ( ! stream_preview_image($post_id) )
+ wp_die( -1 );
+
+ wp_die();
+}
+
+function wp_ajax_oembed_cache() {
+ global $wp_embed;
+
+ $return = ( $wp_embed->cache_oembed( $_GET['post'] ) ) ? '1' : '0';
+ wp_die( $return );
+}
+
+function wp_ajax_autocomplete_user() {
+ if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) )
+ wp_die( -1 );
+
+ if ( ! is_super_admin() && ! apply_filters( 'autocomplete_users_for_site_admins', false ) )
+ wp_die( -1 );
+
+ $return = array();
+
+ // Check the type of request
+ if ( isset( $_REQUEST['autocomplete_type'] ) )
+ $type = $_REQUEST['autocomplete_type'];
+ else
+ $type = 'add';
+
+ // Exclude current users of this blog
+ if ( isset( $_REQUEST['site_id'] ) )
+ $id = absint( $_REQUEST['site_id'] );
+ else
+ $id = get_current_blog_id();
+
+ $include_blog_users = ( $type == 'search' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
+ $exclude_blog_users = ( $type == 'add' ? get_users( array( 'blog_id' => $id, 'fields' => 'ID' ) ) : array() );
+
+ $users = get_users( array(
+ 'blog_id' => false,
+ 'search' => '*' . $_REQUEST['term'] . '*',
+ 'include' => $include_blog_users,
+ 'exclude' => $exclude_blog_users,
+ 'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ),
+ ) );
+
+ foreach ( $users as $user ) {
+ $return[] = array(
+ /* translators: 1: user_login, 2: user_email */
+ 'label' => sprintf( __( '%1$s (%2$s)' ), $user->user_login, $user->user_email ),
+ 'value' => $user->user_login,
+ );
+ }
+
+ wp_die( json_encode( $return ) );
+}
+
+function wp_ajax_dashboard_widgets() {
+ require_once ABSPATH . 'wp-admin/includes/dashboard.php';
+
+ switch ( $_GET['widget'] ) {
+ case 'dashboard_incoming_links' :
+ wp_dashboard_incoming_links();
+ break;
+ case 'dashboard_primary' :
+ wp_dashboard_primary();
+ break;
+ case 'dashboard_secondary' :
+ wp_dashboard_secondary();
+ break;
+ case 'dashboard_plugins' :
+ wp_dashboard_plugins();
+ break;
+ }
+ wp_die();
+}
+
+function wp_ajax_logged_in() {
+ wp_die( 1 );
+}
+
+/*
+ * Ajax helper.
+ */
+
+/**
+ * Sends back current comment total and new page links if they need to be updated.
+ *
+ * Contrary to normal success AJAX response ("1"), die with time() on success.
+ *
+ * @since 2.7
+ *
+ * @param int $comment_id
+ * @return die
+ */
+function _wp_ajax_delete_comment_response( $comment_id, $delta = -1 ) {
+ $total = (int) @$_POST['_total'];
+ $per_page = (int) @$_POST['_per_page'];
+ $page = (int) @$_POST['_page'];
+ $url = esc_url_raw( @$_POST['_url'] );
+ // JS didn't send us everything we need to know. Just die with success message
+ if ( !$total || !$per_page || !$page || !$url )
+ wp_die( time() );
+
+ $total += $delta;
+ if ( $total < 0 )
+ $total = 0;
+
+ // Only do the expensive stuff on a page-break, and about 1 other time per page
+ if ( 0 == $total % $per_page || 1 == mt_rand( 1, $per_page ) ) {
+ $post_id = 0;
+ $status = 'total_comments'; // What type of comment count are we looking for?
+ $parsed = parse_url( $url );
+ if ( isset( $parsed['query'] ) ) {
+ parse_str( $parsed['query'], $query_vars );
+ if ( !empty( $query_vars['comment_status'] ) )
+ $status = $query_vars['comment_status'];
+ if ( !empty( $query_vars['p'] ) )
+ $post_id = (int) $query_vars['p'];
+ }
+
+ $comment_count = wp_count_comments($post_id);
+
+ if ( isset( $comment_count->$status ) ) // We're looking for a known type of comment count
+ $total = $comment_count->$status;
+ // else use the decremented value from above
+ }
+
+ $time = time(); // The time since the last comment count
+
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'comment',
+ 'id' => $comment_id, // here for completeness - not used
+ 'supplemental' => array(
+ 'total_items_i18n' => sprintf( _n( '1 item', '%s items', $total ), number_format_i18n( $total ) ),
+ 'total_pages' => ceil( $total / $per_page ),
+ 'total_pages_i18n' => number_format_i18n( ceil( $total / $per_page ) ),
+ 'total' => $total,
+ 'time' => $time
+ )
+ ) );
+ $x->send();
+}
+
+/*
+ * POST-based Ajax handlers.
+ */
+
+function _wp_ajax_add_hierarchical_term() {
+ $action = $_POST['action'];
+ $taxonomy = get_taxonomy(substr($action, 4));
+ check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
+ if ( !current_user_can( $taxonomy->cap->edit_terms ) )
+ wp_die( -1 );
+ $names = explode(',', $_POST['new'.$taxonomy->name]);
+ $parent = isset($_POST['new'.$taxonomy->name.'_parent']) ? (int) $_POST['new'.$taxonomy->name.'_parent'] : 0;
+ if ( 0 > $parent )
+ $parent = 0;
+ if ( $taxonomy->name == 'category' )
+ $post_category = isset($_POST['post_category']) ? (array) $_POST['post_category'] : array();
+ else
+ $post_category = ( isset($_POST['tax_input']) && isset($_POST['tax_input'][$taxonomy->name]) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
+ $checked_categories = array_map( 'absint', (array) $post_category );
+ $popular_ids = wp_popular_terms_checklist($taxonomy->name, 0, 10, false);
+
+ foreach ( $names as $cat_name ) {
+ $cat_name = trim($cat_name);
+ $category_nicename = sanitize_title($cat_name);
+ if ( '' === $category_nicename )
+ continue;
+ if ( !$cat_id = term_exists( $cat_name, $taxonomy->name, $parent ) )
+ $cat_id = wp_insert_term( $cat_name, $taxonomy->name, array( 'parent' => $parent ) );
+ if ( is_wp_error( $cat_id ) )
+ continue;
+ else if ( is_array( $cat_id ) )
+ $cat_id = $cat_id['term_id'];
+ $checked_categories[] = $cat_id;
+ if ( $parent ) // Do these all at once in a second
+ continue;
+ ob_start();
+ wp_terms_checklist( 0, array( 'taxonomy' => $taxonomy->name, 'descendants_and_self' => $cat_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids ));
+ $data = ob_get_contents();
+ ob_end_clean();
+ $add = array(
+ 'what' => $taxonomy->name,
+ 'id' => $cat_id,
+ 'data' => str_replace( array("\n", "\t"), '', $data),
+ 'position' => -1
+ );
+ }
+
+ if ( $parent ) { // Foncy - replace the parent and all its children
+ $parent = get_term( $parent, $taxonomy->name );
+ $term_id = $parent->term_id;
+
+ while ( $parent->parent ) { // get the top parent
+ $parent = get_term( $parent->parent, $taxonomy->name );
+ if ( is_wp_error( $parent ) )
+ break;
+ $term_id = $parent->term_id;
+ }
+
+ ob_start();
+ wp_terms_checklist( 0, array('taxonomy' => $taxonomy->name, 'descendants_and_self' => $term_id, 'selected_cats' => $checked_categories, 'popular_cats' => $popular_ids));
+ $data = ob_get_contents();
+ ob_end_clean();
+ $add = array(
+ 'what' => $taxonomy->name,
+ 'id' => $term_id,
+ 'data' => str_replace( array("\n", "\t"), '', $data),
+ 'position' => -1
+ );
+ }
+
+ ob_start();
+ wp_dropdown_categories( array(
+ 'taxonomy' => $taxonomy->name, 'hide_empty' => 0, 'name' => 'new'.$taxonomy->name.'_parent', 'orderby' => 'name',
+ 'hierarchical' => 1, 'show_option_none' => '&mdash; '.$taxonomy->labels->parent_item.' &mdash;'
+ ) );
+ $sup = ob_get_contents();
+ ob_end_clean();
+ $add['supplemental'] = array( 'newcat_parent' => $sup );
+
+ $x = new WP_Ajax_Response( $add );
+ $x->send();
+}
+
+function wp_ajax_delete_comment() {
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ if ( !$comment = get_comment( $id ) )
+ wp_die( time() );
+ if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
+ wp_die( -1 );
+
+ check_ajax_referer( "delete-comment_$id" );
+ $status = wp_get_comment_status( $comment->comment_ID );
+
+ $delta = -1;
+ if ( isset($_POST['trash']) && 1 == $_POST['trash'] ) {
+ if ( 'trash' == $status )
+ wp_die( time() );
+ $r = wp_trash_comment( $comment->comment_ID );
+ } elseif ( isset($_POST['untrash']) && 1 == $_POST['untrash'] ) {
+ if ( 'trash' != $status )
+ wp_die( time() );
+ $r = wp_untrash_comment( $comment->comment_ID );
+ if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'trash' ) // undo trash, not in trash
+ $delta = 1;
+ } elseif ( isset($_POST['spam']) && 1 == $_POST['spam'] ) {
+ if ( 'spam' == $status )
+ wp_die( time() );
+ $r = wp_spam_comment( $comment->comment_ID );
+ } elseif ( isset($_POST['unspam']) && 1 == $_POST['unspam'] ) {
+ if ( 'spam' != $status )
+ wp_die( time() );
+ $r = wp_unspam_comment( $comment->comment_ID );
+ if ( ! isset( $_POST['comment_status'] ) || $_POST['comment_status'] != 'spam' ) // undo spam, not in spam
+ $delta = 1;
+ } elseif ( isset($_POST['delete']) && 1 == $_POST['delete'] ) {
+ $r = wp_delete_comment( $comment->comment_ID );
+ } else {
+ wp_die( -1 );
+ }
+
+ if ( $r ) // Decide if we need to send back '1' or a more complicated response including page links and comment counts
+ _wp_ajax_delete_comment_response( $comment->comment_ID, $delta );
+ wp_die( 0 );
+}
+
+function wp_ajax_delete_tag() {
+ $tag_id = (int) $_POST['tag_ID'];
+ check_ajax_referer( "delete-tag_$tag_id" );
+
+ $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
+ $tax = get_taxonomy($taxonomy);
+
+ if ( !current_user_can( $tax->cap->delete_terms ) )
+ wp_die( -1 );
+
+ $tag = get_term( $tag_id, $taxonomy );
+ if ( !$tag || is_wp_error( $tag ) )
+ wp_die( 1 );
+
+ if ( wp_delete_term($tag_id, $taxonomy))
+ wp_die( 1 );
+ else
+ wp_die( 0 );
+}
+
+function wp_ajax_delete_link() {
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ check_ajax_referer( "delete-bookmark_$id" );
+ if ( !current_user_can( 'manage_links' ) )
+ wp_die( -1 );
+
+ $link = get_bookmark( $id );
+ if ( !$link || is_wp_error( $link ) )
+ wp_die( 1 );
+
+ if ( wp_delete_link( $id ) )
+ wp_die( 1 );
+ else
+ wp_die( 0 );
+}
+
+function wp_ajax_delete_meta() {
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ check_ajax_referer( "delete-meta_$id" );
+ if ( !$meta = get_metadata_by_mid( 'post', $id ) )
+ wp_die( 1 );
+
+ if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $meta->post_id, $meta->meta_key ) )
+ wp_die( -1 );
+ if ( delete_meta( $meta->meta_id ) )
+ wp_die( 1 );
+ wp_die( 0 );
+}
+
+function wp_ajax_delete_post( $action ) {
+ if ( empty( $action ) )
+ $action = 'delete-post';
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ check_ajax_referer( "{$action}_$id" );
+ if ( !current_user_can( 'delete_post', $id ) )
+ wp_die( -1 );
+
+ if ( !get_post( $id ) )
+ wp_die( 1 );
+
+ if ( wp_delete_post( $id ) )
+ wp_die( 1 );
+ else
+ wp_die( 0 );
+}
+
+function wp_ajax_trash_post( $action ) {
+ if ( empty( $action ) )
+ $action = 'trash-post';
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ check_ajax_referer( "{$action}_$id" );
+ if ( !current_user_can( 'delete_post', $id ) )
+ wp_die( -1 );
+
+ if ( !get_post( $id ) )
+ wp_die( 1 );
+
+ if ( 'trash-post' == $action )
+ $done = wp_trash_post( $id );
+ else
+ $done = wp_untrash_post( $id );
+
+ if ( $done )
+ wp_die( 1 );
+
+ wp_die( 0 );
+}
+
+function wp_ajax_untrash_post( $action ) {
+ if ( empty( $action ) )
+ $action = 'untrash-post';
+ wp_ajax_trash_post( $action );
+}
+
+function wp_ajax_delete_page( $action ) {
+ if ( empty( $action ) )
+ $action = 'delete-page';
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ check_ajax_referer( "{$action}_$id" );
+ if ( !current_user_can( 'delete_page', $id ) )
+ wp_die( -1 );
+
+ if ( ! get_post( $id ) )
+ wp_die( 1 );
+
+ if ( wp_delete_post( $id ) )
+ wp_die( 1 );
+ else
+ wp_die( 0 );
+}
+
+function wp_ajax_dim_comment() {
+ $id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0;
+
+ if ( !$comment = get_comment( $id ) ) {
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'comment',
+ 'id' => new WP_Error('invalid_comment', sprintf(__('Comment %d does not exist'), $id))
+ ) );
+ $x->send();
+ }
+
+ if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) && ! current_user_can( 'moderate_comments' ) )
+ wp_die( -1 );
+
+ $current = wp_get_comment_status( $comment->comment_ID );
+ if ( $_POST['new'] == $current )
+ wp_die( time() );
+
+ check_ajax_referer( "approve-comment_$id" );
+ if ( in_array( $current, array( 'unapproved', 'spam' ) ) )
+ $result = wp_set_comment_status( $comment->comment_ID, 'approve', true );
+ else
+ $result = wp_set_comment_status( $comment->comment_ID, 'hold', true );
+
+ if ( is_wp_error($result) ) {
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'comment',
+ 'id' => $result
+ ) );
+ $x->send();
+ }
+
+ // Decide if we need to send back '1' or a more complicated response including page links and comment counts
+ _wp_ajax_delete_comment_response( $comment->comment_ID );
+ wp_die( 0 );
+}
+
+function wp_ajax_add_link_category( $action ) {
+ if ( empty( $action ) )
+ $action = 'add-link-category';
+ check_ajax_referer( $action );
+ if ( !current_user_can( 'manage_categories' ) )
+ wp_die( -1 );
+ $names = explode(',', wp_unslash( $_POST['newcat'] ) );
+ $x = new WP_Ajax_Response();
+ foreach ( $names as $cat_name ) {
+ $cat_name = trim($cat_name);
+ $slug = sanitize_title($cat_name);
+ if ( '' === $slug )
+ continue;
+ if ( !$cat_id = term_exists( $cat_name, 'link_category' ) )
+ $cat_id = wp_insert_term( $cat_name, 'link_category' );
+ if ( is_wp_error( $cat_id ) )
+ continue;
+ else if ( is_array( $cat_id ) )
+ $cat_id = $cat_id['term_id'];
+ $cat_name = esc_html( $cat_name );
+ $x->add( array(
+ 'what' => 'link-category',
+ 'id' => $cat_id,
+ 'data' => "<li id='link-category-$cat_id'><label for='in-link-category-$cat_id' class='selectit'><input value='" . esc_attr($cat_id) . "' type='checkbox' checked='checked' name='link_category[]' id='in-link-category-$cat_id'/> $cat_name</label></li>",
+ 'position' => -1
+ ) );
+ }
+ $x->send();
+}
+
+function wp_ajax_add_tag() {
+ global $wp_list_table;
+
+ check_ajax_referer( 'add-tag', '_wpnonce_add-tag' );
+ $post_type = !empty($_POST['post_type']) ? $_POST['post_type'] : 'post';
+ $taxonomy = !empty($_POST['taxonomy']) ? $_POST['taxonomy'] : 'post_tag';
+ $tax = get_taxonomy($taxonomy);
+
+ if ( !current_user_can( $tax->cap->edit_terms ) )
+ wp_die( -1 );
+
+ $x = new WP_Ajax_Response();
+
+ $tag = wp_insert_term($_POST['tag-name'], $taxonomy, $_POST );
+
+ if ( !$tag || is_wp_error($tag) || (!$tag = get_term( $tag['term_id'], $taxonomy )) ) {
+ $message = __('An error has occurred. Please reload the page and try again.');
+ if ( is_wp_error($tag) && $tag->get_error_message() )
+ $message = $tag->get_error_message();
+
+ $x->add( array(
+ 'what' => 'taxonomy',
+ 'data' => new WP_Error('error', $message )
+ ) );
+ $x->send();
+ }
+
+ $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => $_POST['screen'] ) );
+
+ $level = 0;
+ if ( is_taxonomy_hierarchical($taxonomy) ) {
+ $level = count( get_ancestors( $tag->term_id, $taxonomy ) );
+ ob_start();
+ $wp_list_table->single_row( $tag, $level );
+ $noparents = ob_get_clean();
+ }
+
+ ob_start();
+ $wp_list_table->single_row( $tag );
+ $parents = ob_get_clean();
+
+ $x->add( array(
+ 'what' => 'taxonomy',
+ 'supplemental' => compact('parents', 'noparents')
+ ) );
+ $x->add( array(
+ 'what' => 'term',
+ 'position' => $level,
+ 'supplemental' => (array) $tag
+ ) );
+ $x->send();
+}
+
+function wp_ajax_get_tagcloud() {
+ if ( isset( $_POST['tax'] ) ) {
+ $taxonomy = sanitize_key( $_POST['tax'] );
+ $tax = get_taxonomy( $taxonomy );
+ if ( ! $tax )
+ wp_die( 0 );
+ if ( ! current_user_can( $tax->cap->assign_terms ) )
+ wp_die( -1 );
+ } else {
+ wp_die( 0 );
+ }
+
+ $tags = get_terms( $taxonomy, array( 'number' => 45, 'orderby' => 'count', 'order' => 'DESC' ) );
+
+ if ( empty( $tags ) )
+ wp_die( $tax->labels->not_found );
+
+ if ( is_wp_error( $tags ) )
+ wp_die( $tags->get_error_message() );
+
+ foreach ( $tags as $key => $tag ) {
+ $tags[ $key ]->link = '#';
+ $tags[ $key ]->id = $tag->term_id;
+ }
+
+ // We need raw tag names here, so don't filter the output
+ $return = wp_generate_tag_cloud( $tags, array('filter' => 0) );
+
+ if ( empty($return) )
+ wp_die( 0 );
+
+ echo $return;
+
+ wp_die();
+}
+
+function wp_ajax_get_comments( $action ) {
+ global $wp_list_table, $post_id;
+ if ( empty( $action ) )
+ $action = 'get-comments';
+
+ check_ajax_referer( $action );
+
+ $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
+
+ if ( !current_user_can( 'edit_post', $post_id ) )
+ wp_die( -1 );
+
+ $wp_list_table->prepare_items();
+
+ if ( !$wp_list_table->has_items() )
+ wp_die( 1 );
+
+ $x = new WP_Ajax_Response();
+ ob_start();
+ foreach ( $wp_list_table->items as $comment ) {
+ if ( ! current_user_can( 'edit_comment', $comment->comment_ID ) )
+ continue;
+ get_comment( $comment );
+ $wp_list_table->single_row( $comment );
+ }
+ $comment_list_item = ob_get_contents();
+ ob_end_clean();
+
+ $x->add( array(
+ 'what' => 'comments',
+ 'data' => $comment_list_item
+ ) );
+ $x->send();
+}
+
+function wp_ajax_replyto_comment( $action ) {
+ global $wp_list_table, $wpdb;
+ if ( empty( $action ) )
+ $action = 'replyto-comment';
+
+ check_ajax_referer( $action, '_ajax_nonce-replyto-comment' );
+
+ $comment_post_ID = (int) $_POST['comment_post_ID'];
+ $post = get_post( $comment_post_ID );
+ if ( ! $post )
+ wp_die( -1 );
+
+ if ( !current_user_can( 'edit_post', $comment_post_ID ) )
+ wp_die( -1 );
+
+ if ( empty( $post->post_status ) )
+ wp_die( 1 );
+ elseif ( in_array($post->post_status, array('draft', 'pending', 'trash') ) )
+ wp_die( __('ERROR: you are replying to a comment on a draft post.') );
+
+ $user = wp_get_current_user();
+ if ( $user->exists() ) {
+ $user_ID = $user->ID;
+ $comment_author = wp_slash( $user->display_name );
+ $comment_author_email = wp_slash( $user->user_email );
+ $comment_author_url = wp_slash( $user->user_url );
+ $comment_content = trim($_POST['content']);
+ if ( current_user_can( 'unfiltered_html' ) ) {
+ if ( wp_create_nonce( 'unfiltered-html-comment' ) != $_POST['_wp_unfiltered_html_comment'] ) {
+ kses_remove_filters(); // start with a clean slate
+ kses_init_filters(); // set up the filters
+ }
+ }
+ } else {
+ wp_die( __( 'Sorry, you must be logged in to reply to a comment.' ) );
+ }
+
+ if ( '' == $comment_content )
+ wp_die( __( 'ERROR: please type a comment.' ) );
+
+ $comment_parent = absint($_POST['comment_ID']);
+ $comment_auto_approved = false;
+ $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
+
+ // automatically approve parent comment
+ if ( !empty($_POST['approve_parent']) ) {
+ $parent = get_comment( $comment_parent );
+
+ if ( $parent && $parent->comment_approved === '0' && $parent->comment_post_ID == $comment_post_ID ) {
+ if ( wp_set_comment_status( $parent->comment_ID, 'approve' ) )
+ $comment_auto_approved = true;
+ }
+ }
+
+ $comment_id = wp_new_comment( $commentdata );
+ $comment = get_comment($comment_id);
+ if ( ! $comment ) wp_die( 1 );
+
+ $position = ( isset($_POST['position']) && (int) $_POST['position'] ) ? (int) $_POST['position'] : '-1';
+
+ ob_start();
+ if ( 'dashboard' == $_REQUEST['mode'] ) {
+ require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
+ _wp_dashboard_recent_comments_row( $comment );
+ } else {
+ if ( 'single' == $_REQUEST['mode'] ) {
+ $wp_list_table = _get_list_table('WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
+ } else {
+ $wp_list_table = _get_list_table('WP_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
+ }
+ $wp_list_table->single_row( $comment );
+ }
+ $comment_list_item = ob_get_contents();
+ ob_end_clean();
+
+ $response = array(
+ 'what' => 'comment',
+ 'id' => $comment->comment_ID,
+ 'data' => $comment_list_item,
+ 'position' => $position
+ );
+
+ if ( $comment_auto_approved )
+ $response['supplemental'] = array( 'parent_approved' => $parent->comment_ID );
+
+ $x = new WP_Ajax_Response();
+ $x->add( $response );
+ $x->send();
+}
+
+function wp_ajax_edit_comment() {
+ global $wp_list_table;
+
+ check_ajax_referer( 'replyto-comment', '_ajax_nonce-replyto-comment' );
+
+ $comment_id = (int) $_POST['comment_ID'];
+ if ( ! current_user_can( 'edit_comment', $comment_id ) )
+ wp_die( -1 );
+
+ if ( '' == $_POST['content'] )
+ wp_die( __( 'ERROR: please type a comment.' ) );
+
+ $_POST['comment_status'] = $_POST['status'];
+ edit_comment();
+
+ $position = ( isset($_POST['position']) && (int) $_POST['position']) ? (int) $_POST['position'] : '-1';
+ $comments_status = isset($_POST['comments_listing']) ? $_POST['comments_listing'] : '';
+
+ $checkbox = ( isset($_POST['checkbox']) && true == $_POST['checkbox'] ) ? 1 : 0;
+ $wp_list_table = _get_list_table( $checkbox ? 'WP_Comments_List_Table' : 'WP_Post_Comments_List_Table', array( 'screen' => 'edit-comments' ) );
+
+ $comment = get_comment( $comment_id );
+
+ ob_start();
+ $wp_list_table->single_row( $comment );
+ $comment_list_item = ob_get_contents();
+ ob_end_clean();
+
+ $x = new WP_Ajax_Response();
+
+ $x->add( array(
+ 'what' => 'edit_comment',
+ 'id' => $comment->comment_ID,
+ 'data' => $comment_list_item,
+ 'position' => $position
+ ));
+
+ $x->send();
+}
+
+function wp_ajax_add_menu_item() {
+ check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
+
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ wp_die( -1 );
+
+ require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
+
+ // For performance reasons, we omit some object properties from the checklist.
+ // The following is a hacky way to restore them when adding non-custom items.
+
+ $menu_items_data = array();
+ foreach ( (array) $_POST['menu-item'] as $menu_item_data ) {
+ if (
+ ! empty( $menu_item_data['menu-item-type'] ) &&
+ 'custom' != $menu_item_data['menu-item-type'] &&
+ ! empty( $menu_item_data['menu-item-object-id'] )
+ ) {
+ switch( $menu_item_data['menu-item-type'] ) {
+ case 'post_type' :
+ $_object = get_post( $menu_item_data['menu-item-object-id'] );
+ break;
+
+ case 'taxonomy' :
+ $_object = get_term( $menu_item_data['menu-item-object-id'], $menu_item_data['menu-item-object'] );
+ break;
+ }
+
+ $_menu_items = array_map( 'wp_setup_nav_menu_item', array( $_object ) );
+ $_menu_item = array_shift( $_menu_items );
+
+ // Restore the missing menu item properties
+ $menu_item_data['menu-item-description'] = $_menu_item->description;
+ }
+
+ $menu_items_data[] = $menu_item_data;
+ }
+
+ $item_ids = wp_save_nav_menu_items( 0, $menu_items_data );
+ if ( is_wp_error( $item_ids ) )
+ wp_die( 0 );
+
+ $menu_items = array();
+
+ foreach ( (array) $item_ids as $menu_item_id ) {
+ $menu_obj = get_post( $menu_item_id );
+ if ( ! empty( $menu_obj->ID ) ) {
+ $menu_obj = wp_setup_nav_menu_item( $menu_obj );
+ $menu_obj->label = $menu_obj->title; // don't show "(pending)" in ajax-added items
+ $menu_items[] = $menu_obj;
+ }
+ }
+
+ $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $_POST['menu'] );
+
+ if ( ! class_exists( $walker_class_name ) )
+ wp_die( 0 );
+
+ if ( ! empty( $menu_items ) ) {
+ $args = array(
+ 'after' => '',
+ 'before' => '',
+ 'link_after' => '',
+ 'link_before' => '',
+ 'walker' => new $walker_class_name,
+ );
+ echo walk_nav_menu_tree( $menu_items, 0, (object) $args );
+ }
+ wp_die();
+}
+
+function wp_ajax_add_meta() {
+ check_ajax_referer( 'add-meta', '_ajax_nonce-add-meta' );
+ $c = 0;
+ $pid = (int) $_POST['post_id'];
+ $post = get_post( $pid );
+
+ if ( isset($_POST['metakeyselect']) || isset($_POST['metakeyinput']) ) {
+ if ( !current_user_can( 'edit_post', $pid ) )
+ wp_die( -1 );
+ if ( isset($_POST['metakeyselect']) && '#NONE#' == $_POST['metakeyselect'] && empty($_POST['metakeyinput']) )
+ wp_die( 1 );
+ if ( $post->post_status == 'auto-draft' ) {
+ $save_POST = $_POST; // Backup $_POST
+ $_POST = array(); // Make it empty for edit_post()
+ $_POST['action'] = 'draft'; // Warning fix
+ $_POST['post_ID'] = $pid;
+ $_POST['post_type'] = $post->post_type;
+ $_POST['post_status'] = 'draft';
+ $now = current_time('timestamp', 1);
+ $_POST['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( get_option( 'date_format' ), $now ), date( get_option( 'time_format' ), $now ) );
+
+ if ( $pid = edit_post() ) {
+ if ( is_wp_error( $pid ) ) {
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'meta',
+ 'data' => $pid
+ ) );
+ $x->send();
+ }
+ $_POST = $save_POST; // Now we can restore original $_POST again
+ if ( !$mid = add_meta( $pid ) )
+ wp_die( __( 'Please provide a custom field value.' ) );
+ } else {
+ wp_die( 0 );
+ }
+ } else if ( !$mid = add_meta( $pid ) ) {
+ wp_die( __( 'Please provide a custom field value.' ) );
+ }
+
+ $meta = get_metadata_by_mid( 'post', $mid );
+ $pid = (int) $meta->post_id;
+ $meta = get_object_vars( $meta );
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'meta',
+ 'id' => $mid,
+ 'data' => _list_meta_row( $meta, $c ),
+ 'position' => 1,
+ 'supplemental' => array('postid' => $pid)
+ ) );
+ } else { // Update?
+ $mid = (int) key( $_POST['meta'] );
+ $key = wp_unslash( $_POST['meta'][$mid]['key'] );
+ $value = wp_unslash( $_POST['meta'][$mid]['value'] );
+ if ( '' == trim($key) )
+ wp_die( __( 'Please provide a custom field name.' ) );
+ if ( '' == trim($value) )
+ wp_die( __( 'Please provide a custom field value.' ) );
+ if ( ! $meta = get_metadata_by_mid( 'post', $mid ) )
+ wp_die( 0 ); // if meta doesn't exist
+ if ( is_protected_meta( $meta->meta_key, 'post' ) || is_protected_meta( $key, 'post' ) ||
+ ! current_user_can( 'edit_post_meta', $meta->post_id, $meta->meta_key ) ||
+ ! current_user_can( 'edit_post_meta', $meta->post_id, $key ) )
+ wp_die( -1 );
+ if ( $meta->meta_value != $value || $meta->meta_key != $key ) {
+ if ( !$u = update_metadata_by_mid( 'post', $mid, $value, $key ) )
+ wp_die( 0 ); // We know meta exists; we also know it's unchanged (or DB error, in which case there are bigger problems).
+ }
+
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'meta',
+ 'id' => $mid, 'old_id' => $mid,
+ 'data' => _list_meta_row( array(
+ 'meta_key' => $key,
+ 'meta_value' => $value,
+ 'meta_id' => $mid
+ ), $c ),
+ 'position' => 0,
+ 'supplemental' => array('postid' => $meta->post_id)
+ ) );
+ }
+ $x->send();
+}
+
+function wp_ajax_add_user( $action ) {
+ global $wp_list_table;
+ if ( empty( $action ) )
+ $action = 'add-user';
+
+ check_ajax_referer( $action );
+ if ( ! current_user_can('create_users') )
+ wp_die( -1 );
+ if ( ! $user_id = edit_user() ) {
+ wp_die( 0 );
+ } elseif ( is_wp_error( $user_id ) ) {
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'user',
+ 'id' => $user_id
+ ) );
+ $x->send();
+ }
+ $user_object = get_userdata( $user_id );
+
+ $wp_list_table = _get_list_table('WP_Users_List_Table');
+
+ $role = current( $user_object->roles );
+
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'user',
+ 'id' => $user_id,
+ 'data' => $wp_list_table->single_row( $user_object, '', $role ),
+ 'supplemental' => array(
+ 'show-link' => sprintf(__( 'User <a href="#%s">%s</a> added' ), "user-$user_id", $user_object->user_login),
+ 'role' => $role,
+ )
+ ) );
+ $x->send();
+}
+
+function wp_ajax_autosave() {
+ define( 'DOING_AUTOSAVE', true );
+
+ check_ajax_referer( 'autosave', 'autosavenonce' );
+
+ $_POST['post_category'] = explode(",", $_POST['catslist']);
+ if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
+ unset($_POST['post_category']);
+
+ $data = '';
+ $supplemental = array();
+ $id = $revision_id = 0;
+
+ $post_id = (int) $_POST['post_id'];
+ $_POST['ID'] = $_POST['post_ID'] = $post_id;
+ $post = get_post($post_id);
+ if ( 'auto-draft' == $post->post_status )
+ $_POST['post_status'] = 'draft';
+
+ if ( 'page' == $post->post_type ) {
+ if ( !current_user_can('edit_page', $post->ID) )
+ wp_die( __( 'You are not allowed to edit this page.' ) );
+ } else {
+ if ( !current_user_can('edit_post', $post->ID) )
+ wp_die( __( 'You are not allowed to edit this post.' ) );
+ }
+
+ if ( ! empty( $_POST['autosave'] ) ) {
+ if ( ! wp_check_post_lock( $post->ID ) && get_current_user_id() == $post->post_author && ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) ) {
+ // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked
+ $id = edit_post();
+ } else {
+ // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user.
+ $revision_id = wp_create_post_autosave( $post->ID );
+ if ( is_wp_error($revision_id) )
+ $id = $revision_id;
+ else
+ $id = $post->ID;
+ }
+
+ if ( ! is_wp_error($id) ) {
+ /* translators: draft saved date format, see http://php.net/date */
+ $draft_saved_date_format = __('g:i:s a');
+ /* translators: %s: date and time */
+ $data = sprintf( __('Draft saved at %s.'), date_i18n( $draft_saved_date_format ) );
+ }
+ } else {
+ if ( ! empty( $_POST['auto_draft'] ) )
+ $id = 0; // This tells us it didn't actually save
+ else
+ $id = $post->ID;
+ }
+
+ // @todo Consider exposing any errors, rather than having 'Saving draft...'
+ $x = new WP_Ajax_Response( array(
+ 'what' => 'autosave',
+ 'id' => $id,
+ 'data' => $data,
+ 'supplemental' => $supplemental
+ ) );
+ $x->send();
+}
+
+function wp_ajax_closed_postboxes() {
+ check_ajax_referer( 'closedpostboxes', 'closedpostboxesnonce' );
+ $closed = isset( $_POST['closed'] ) ? explode( ',', $_POST['closed']) : array();
+ $closed = array_filter($closed);
+
+ $hidden = isset( $_POST['hidden'] ) ? explode( ',', $_POST['hidden']) : array();
+ $hidden = array_filter($hidden);
+
+ $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
+
+ if ( $page != sanitize_key( $page ) )
+ wp_die( 0 );
+
+ if ( ! $user = wp_get_current_user() )
+ wp_die( -1 );
+
+ if ( is_array($closed) )
+ update_user_option($user->ID, "closedpostboxes_$page", $closed, true);
+
+ if ( is_array($hidden) ) {
+ $hidden = array_diff( $hidden, array('submitdiv', 'linksubmitdiv', 'manage-menu', 'create-menu') ); // postboxes that are always shown
+ update_user_option($user->ID, "metaboxhidden_$page", $hidden, true);
+ }
+
+ wp_die( 1 );
+}
+
+function wp_ajax_hidden_columns() {
+ check_ajax_referer( 'screen-options-nonce', 'screenoptionnonce' );
+ $hidden = isset( $_POST['hidden'] ) ? $_POST['hidden'] : '';
+ $hidden = explode( ',', $_POST['hidden'] );
+ $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
+
+ if ( $page != sanitize_key( $page ) )
+ wp_die( 0 );
+
+ if ( ! $user = wp_get_current_user() )
+ wp_die( -1 );
+
+ if ( is_array($hidden) )
+ update_user_option($user->ID, "manage{$page}columnshidden", $hidden, true);
+
+ wp_die( 1 );
+}
+
+function wp_ajax_update_welcome_panel() {
+ check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' );
+
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ wp_die( -1 );
+
+ update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 );
+
+ wp_die( 1 );
+}
+
+function wp_ajax_menu_get_metabox() {
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ wp_die( -1 );
+
+ require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
+
+ if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) {
+ $type = 'posttype';
+ $callback = 'wp_nav_menu_item_post_type_meta_box';
+ $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
+ } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) {
+ $type = 'taxonomy';
+ $callback = 'wp_nav_menu_item_taxonomy_meta_box';
+ $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' );
+ }
+
+ if ( ! empty( $_POST['item-object'] ) && isset( $items[$_POST['item-object']] ) ) {
+ $item = apply_filters( 'nav_menu_meta_box_object', $items[ $_POST['item-object'] ] );
+ ob_start();
+ call_user_func_array($callback, array(
+ null,
+ array(
+ 'id' => 'add-' . $item->name,
+ 'title' => $item->labels->name,
+ 'callback' => $callback,
+ 'args' => $item,
+ )
+ ));
+
+ $markup = ob_get_clean();
+
+ echo json_encode(array(
+ 'replace-id' => $type . '-' . $item->name,
+ 'markup' => $markup,
+ ));
+ }
+
+ wp_die();
+}
+
+function wp_ajax_wp_link_ajax() {
+ check_ajax_referer( 'internal-linking', '_ajax_linking_nonce' );
+
+ $args = array();
+
+ if ( isset( $_POST['search'] ) )
+ $args['s'] = wp_unslash( $_POST['search'] );
+ $args['pagenum'] = ! empty( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;
+
+ require(ABSPATH . WPINC . '/class-wp-editor.php');
+ $results = _WP_Editors::wp_link_query( $args );
+
+ if ( ! isset( $results ) )
+ wp_die( 0 );
+
+ echo json_encode( $results );
+ echo "\n";
+
+ wp_die();
+}
+
+function wp_ajax_menu_locations_save() {
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ wp_die( -1 );
+ check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' );
+ if ( ! isset( $_POST['menu-locations'] ) )
+ wp_die( 0 );
+ set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) );
+ wp_die( 1 );
+}
+
+function wp_ajax_meta_box_order() {
+ check_ajax_referer( 'meta-box-order' );
+ $order = isset( $_POST['order'] ) ? (array) $_POST['order'] : false;
+ $page_columns = isset( $_POST['page_columns'] ) ? $_POST['page_columns'] : 'auto';
+
+ if ( $page_columns != 'auto' )
+ $page_columns = (int) $page_columns;
+
+ $page = isset( $_POST['page'] ) ? $_POST['page'] : '';
+
+ if ( $page != sanitize_key( $page ) )
+ wp_die( 0 );
+
+ if ( ! $user = wp_get_current_user() )
+ wp_die( -1 );
+
+ if ( $order )
+ update_user_option($user->ID, "meta-box-order_$page", $order, true);
+
+ if ( $page_columns )
+ update_user_option($user->ID, "screen_layout_$page", $page_columns, true);
+
+ wp_die( 1 );
+}
+
+function wp_ajax_menu_quick_search() {
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ wp_die( -1 );
+
+ require_once ABSPATH . 'wp-admin/includes/nav-menu.php';
+
+ _wp_ajax_menu_quick_search( $_POST );
+
+ wp_die();
+}
+
+function wp_ajax_get_permalink() {
+ check_ajax_referer( 'getpermalink', 'getpermalinknonce' );
+ $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
+ wp_die( add_query_arg( array( 'preview' => 'true' ), get_permalink( $post_id ) ) );
+}
+
+function wp_ajax_sample_permalink() {
+ check_ajax_referer( 'samplepermalink', 'samplepermalinknonce' );
+ $post_id = isset($_POST['post_id'])? intval($_POST['post_id']) : 0;
+ $title = isset($_POST['new_title'])? $_POST['new_title'] : '';
+ $slug = isset($_POST['new_slug'])? $_POST['new_slug'] : null;
+ wp_die( get_sample_permalink_html( $post_id, $title, $slug ) );
+}
+
+function wp_ajax_inline_save() {
+ global $wp_list_table;
+
+ check_ajax_referer( 'inlineeditnonce', '_inline_edit' );
+
+ if ( ! isset($_POST['post_ID']) || ! ( $post_ID = (int) $_POST['post_ID'] ) )
+ wp_die();
+
+ if ( 'page' == $_POST['post_type'] ) {
+ if ( ! current_user_can( 'edit_page', $post_ID ) )
+ wp_die( __( 'You are not allowed to edit this page.' ) );
+ } else {
+ if ( ! current_user_can( 'edit_post', $post_ID ) )
+ wp_die( __( 'You are not allowed to edit this post.' ) );
+ }
+
+ if ( $last = wp_check_post_lock( $post_ID ) ) {
+ $last_user = get_userdata( $last );
+ $last_user_name = $last_user ? $last_user->display_name : __( 'Someone' );
+ printf( $_POST['post_type'] == 'page' ? __( 'Saving is disabled: %s is currently editing this page.' ) : __( 'Saving is disabled: %s is currently editing this post.' ), esc_html( $last_user_name ) );
+ wp_die();
+ }
+
+ $data = &$_POST;
+
+ $post = get_post( $post_ID, ARRAY_A );
+ $post = wp_slash($post); //since it is from db
+
+ $data['content'] = $post['post_content'];
+ $data['excerpt'] = $post['post_excerpt'];
+
+ // rename
+ $data['user_ID'] = $GLOBALS['user_ID'];
+
+ if ( isset($data['post_parent']) )
+ $data['parent_id'] = $data['post_parent'];
+
+ // status
+ if ( isset($data['keep_private']) && 'private' == $data['keep_private'] )
+ $data['post_status'] = 'private';
+ else
+ $data['post_status'] = $data['_status'];
+
+ if ( empty($data['comment_status']) )
+ $data['comment_status'] = 'closed';
+ if ( empty($data['ping_status']) )
+ $data['ping_status'] = 'closed';
+
+ // Hack: wp_unique_post_slug() doesn't work for drafts, so we will fake that our post is published.
+ if ( ! empty( $data['post_name'] ) && in_array( $post['post_status'], array( 'draft', 'pending' ) ) ) {
+ $post['post_status'] = 'publish';
+ $data['post_name'] = wp_unique_post_slug( $data['post_name'], $post['ID'], $post['post_status'], $post['post_type'], $post['post_parent'] );
+ }
+
+ // update the post
+ edit_post();
+
+ $wp_list_table = _get_list_table( 'WP_Posts_List_Table', array( 'screen' => $_POST['screen'] ) );
+
+ $mode = $_POST['post_view'];
+
+ $level = 0;
+ $request_post = array( get_post( $_POST['post_ID'] ) );
+ $parent = $request_post[0]->post_parent;
+
+ while ( $parent > 0 ) {
+ $parent_post = get_post( $parent );
+ $parent = $parent_post->post_parent;
+ $level++;
+ }
+
+ $wp_list_table->display_rows( array( get_post( $_POST['post_ID'] ) ), $level );
+
+ wp_die();
+}
+
+function wp_ajax_inline_save_tax() {
+ global $wp_list_table;
+
+ check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' );
+
+ $taxonomy = sanitize_key( $_POST['taxonomy'] );
+ $tax = get_taxonomy( $taxonomy );
+ if ( ! $tax )
+ wp_die( 0 );
+
+ if ( ! current_user_can( $tax->cap->edit_terms ) )
+ wp_die( -1 );
+
+ $wp_list_table = _get_list_table( 'WP_Terms_List_Table', array( 'screen' => 'edit-' . $taxonomy ) );
+
+ if ( ! isset($_POST['tax_ID']) || ! ( $id = (int) $_POST['tax_ID'] ) )
+ wp_die( -1 );
+
+ $tag = get_term( $id, $taxonomy );
+ $_POST['description'] = $tag->description;
+
+ $updated = wp_update_term($id, $taxonomy, $_POST);
+ if ( $updated && !is_wp_error($updated) ) {
+ $tag = get_term( $updated['term_id'], $taxonomy );
+ if ( !$tag || is_wp_error( $tag ) ) {
+ if ( is_wp_error($tag) && $tag->get_error_message() )
+ wp_die( $tag->get_error_message() );
+ wp_die( __( 'Item not updated.' ) );
+ }
+ } else {
+ if ( is_wp_error($updated) && $updated->get_error_message() )
+ wp_die( $updated->get_error_message() );
+ wp_die( __( 'Item not updated.' ) );
+ }
+ $level = 0;
+ $parent = $tag->parent;
+ while ( $parent > 0 ) {
+ $parent_tag = get_term( $parent, $taxonomy );
+ $parent = $parent_tag->parent;
+ $level++;
+ }
+ $wp_list_table->single_row( $tag, $level );
+ wp_die();
+}
+
+function wp_ajax_find_posts() {
+ global $wpdb;
+
+ check_ajax_referer( 'find-posts' );
+
+ $post_types = get_post_types( array( 'public' => true ), 'objects' );
+ unset( $post_types['attachment'] );
+
+ $s = wp_unslash( $_POST['ps'] );
+ $searchand = $search = '';
+ $args = array(
+ 'post_type' => array_keys( $post_types ),
+ 'post_status' => 'any',
+ 'posts_per_page' => 50,
+ );
+ if ( '' !== $s )
+ $args['s'] = $s;
+
+ $posts = get_posts( $args );
+
+ if ( ! $posts )
+ wp_die( __('No items found.') );
+
+ $html = '<table class="widefat" cellspacing="0"><thead><tr><th class="found-radio"><br /></th><th>'.__('Title').'</th><th class="no-break">'.__('Type').'</th><th class="no-break">'.__('Date').'</th><th class="no-break">'.__('Status').'</th></tr></thead><tbody>';
+ foreach ( $posts as $post ) {
+ $title = trim( $post->post_title ) ? $post->post_title : __( '(no title)' );
+
+ switch ( $post->post_status ) {
+ case 'publish' :
+ case 'private' :
+ $stat = __('Published');
+ break;
+ case 'future' :
+ $stat = __('Scheduled');
+ break;
+ case 'pending' :
+ $stat = __('Pending Review');
+ break;
+ case 'draft' :
+ $stat = __('Draft');
+ break;
+ }
+
+ if ( '0000-00-00 00:00:00' == $post->post_date ) {
+ $time = '';
+ } else {
+ /* translators: date format in table columns, see http://php.net/date */
+ $time = mysql2date(__('Y/m/d'), $post->post_date);
+ }
+
+ $html .= '<tr class="found-posts"><td class="found-radio"><input type="radio" id="found-'.$post->ID.'" name="found_post_id" value="' . esc_attr($post->ID) . '"></td>';
+ $html .= '<td><label for="found-'.$post->ID.'">' . esc_html( $title ) . '</label></td><td class="no-break">' . esc_html( $post_types[$post->post_type]->labels->singular_name ) . '</td><td class="no-break">'.esc_html( $time ) . '</td><td class="no-break">' . esc_html( $stat ). ' </td></tr>' . "\n\n";
+ }
+
+ $html .= '</tbody></table>';
+
+ $x = new WP_Ajax_Response();
+ $x->add( array(
+ 'data' => $html
+ ));
+ $x->send();
+}
+
+function wp_ajax_widgets_order() {
+ check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
+
+ if ( !current_user_can('edit_theme_options') )
+ wp_die( -1 );
+
+ unset( $_POST['savewidgets'], $_POST['action'] );
+
+ // save widgets order for all sidebars
+ if ( is_array($_POST['sidebars']) ) {
+ $sidebars = array();
+ foreach ( $_POST['sidebars'] as $key => $val ) {
+ $sb = array();
+ if ( !empty($val) ) {
+ $val = explode(',', $val);
+ foreach ( $val as $k => $v ) {
+ if ( strpos($v, 'widget-') === false )
+ continue;
+
+ $sb[$k] = substr($v, strpos($v, '_') + 1);
+ }
+ }
+ $sidebars[$key] = $sb;
+ }
+ wp_set_sidebars_widgets($sidebars);
+ wp_die( 1 );
+ }
+
+ wp_die( -1 );
+}
+
+function wp_ajax_save_widget() {
+ global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
+
+ check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' );
+
+ if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) )
+ wp_die( -1 );
+
+ unset( $_POST['savewidgets'], $_POST['action'] );
+
+ do_action('load-widgets.php');
+ do_action('widgets.php');
+ do_action('sidebar_admin_setup');
+
+ $id_base = $_POST['id_base'];
+ $widget_id = $_POST['widget-id'];
+ $sidebar_id = $_POST['sidebar'];
+ $multi_number = !empty($_POST['multi_number']) ? (int) $_POST['multi_number'] : 0;
+ $settings = isset($_POST['widget-' . $id_base]) && is_array($_POST['widget-' . $id_base]) ? $_POST['widget-' . $id_base] : false;
+ $error = '<p>' . __('An error has occurred. Please reload the page and try again.') . '</p>';
+
+ $sidebars = wp_get_sidebars_widgets();
+ $sidebar = isset($sidebars[$sidebar_id]) ? $sidebars[$sidebar_id] : array();
+
+ // delete
+ if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
+
+ if ( !isset($wp_registered_widgets[$widget_id]) )
+ wp_die( $error );
+
+ $sidebar = array_diff( $sidebar, array($widget_id) );
+ $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
+ } elseif ( $settings && preg_match( '/__i__|%i%/', key($settings) ) ) {
+ if ( !$multi_number )
+ wp_die( $error );
+
+ $_POST['widget-' . $id_base] = array( $multi_number => array_shift($settings) );
+ $widget_id = $id_base . '-' . $multi_number;
+ $sidebar[] = $widget_id;
+ }
+ $_POST['widget-id'] = $sidebar;
+
+ foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
+
+ if ( $name == $id_base ) {
+ if ( !is_callable( $control['callback'] ) )
+ continue;
+
+ ob_start();
+ call_user_func_array( $control['callback'], $control['params'] );
+ ob_end_clean();
+ break;
+ }
+ }
+
+ if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
+ $sidebars[$sidebar_id] = $sidebar;
+ wp_set_sidebars_widgets($sidebars);
+ echo "deleted:$widget_id";
+ wp_die();
+ }
+
+ if ( !empty($_POST['add_new']) )
+ wp_die();
+
+ if ( $form = $wp_registered_widget_controls[$widget_id] )
+ call_user_func_array( $form['callback'], $form['params'] );
+
+ wp_die();
+}
+
+function wp_ajax_upload_attachment() {
+ check_ajax_referer( 'media-form' );
+
+ if ( ! current_user_can( 'upload_files' ) )
+ wp_die();
+
+ if ( isset( $_REQUEST['post_id'] ) ) {
+ $post_id = $_REQUEST['post_id'];
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ wp_die();
+ } else {
+ $post_id = null;
+ }
+
+ $post_data = isset( $_REQUEST['post_data'] ) ? $_REQUEST['post_data'] : array();
+
+ // If the context is custom header or background, make sure the uploaded file is an image.
+ if ( isset( $post_data['context'] ) && in_array( $post_data['context'], array( 'custom-header', 'custom-background' ) ) ) {
+ $wp_filetype = wp_check_filetype_and_ext( $_FILES['async-upload']['tmp_name'], $_FILES['async-upload']['name'], false );
+ if ( ! wp_match_mime_types( 'image', $wp_filetype['type'] ) ) {
+ echo json_encode( array(
+ 'success' => false,
+ 'data' => array(
+ 'message' => __( 'The uploaded file is not a valid image. Please try again.' ),
+ 'filename' => $_FILES['async-upload']['name'],
+ )
+ ) );
+
+ wp_die();
+ }
+ }
+
+ $attachment_id = media_handle_upload( 'async-upload', $post_id, $post_data );
+
+ if ( is_wp_error( $attachment_id ) ) {
+ echo json_encode( array(
+ 'success' => false,
+ 'data' => array(
+ 'message' => $attachment_id->get_error_message(),
+ 'filename' => $_FILES['async-upload']['name'],
+ )
+ ) );
+
+ wp_die();
+ }
+
+ if ( isset( $post_data['context'] ) && isset( $post_data['theme'] ) ) {
+ if ( 'custom-background' === $post_data['context'] )
+ update_post_meta( $attachment_id, '_wp_attachment_is_custom_background', $post_data['theme'] );
+
+ if ( 'custom-header' === $post_data['context'] )
+ update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', $post_data['theme'] );
+ }
+
+ if ( ! $attachment = wp_prepare_attachment_for_js( $attachment_id ) )
+ wp_die();
+
+ echo json_encode( array(
+ 'success' => true,
+ 'data' => $attachment,
+ ) );
+
+ wp_die();
+}
+
+function wp_ajax_image_editor() {
+ $attachment_id = intval($_POST['postid']);
+ if ( empty($attachment_id) || !current_user_can('edit_post', $attachment_id) )
+ wp_die( -1 );
+
+ check_ajax_referer( "image_editor-$attachment_id" );
+ include_once( ABSPATH . 'wp-admin/includes/image-edit.php' );
+
+ $msg = false;
+ switch ( $_POST['do'] ) {
+ case 'save' :
+ $msg = wp_save_image($attachment_id);
+ $msg = json_encode($msg);
+ wp_die( $msg );
+ break;
+ case 'scale' :
+ $msg = wp_save_image($attachment_id);
+ break;
+ case 'restore' :
+ $msg = wp_restore_image($attachment_id);
+ break;
+ }
+
+ wp_image_editor($attachment_id, $msg);
+ wp_die();
+}
+
+function wp_ajax_set_post_thumbnail() {
+ $json = ! empty( $_REQUEST['json'] ); // New-style request
+
+ $post_ID = intval( $_POST['post_id'] );
+ if ( ! current_user_can( 'edit_post', $post_ID ) )
+ wp_die( -1 );
+
+ $thumbnail_id = intval( $_POST['thumbnail_id'] );
+
+ if ( $json )
+ check_ajax_referer( "update-post_$post_ID" );
+ else
+ check_ajax_referer( "set_post_thumbnail-$post_ID" );
+
+ if ( $thumbnail_id == '-1' ) {
+ if ( delete_post_thumbnail( $post_ID ) ) {
+ $return = _wp_post_thumbnail_html( null, $post_ID );
+ $json ? wp_send_json_success( $return ) : wp_die( $return );
+ } else {
+ wp_die( 0 );
+ }
+ }
+
+ if ( set_post_thumbnail( $post_ID, $thumbnail_id ) ) {
+ $return = _wp_post_thumbnail_html( $thumbnail_id, $post_ID );
+ $json ? wp_send_json_success( $return ) : wp_die( $return );
+ }
+
+ wp_die( 0 );
+}
+
+function wp_ajax_date_format() {
+ wp_die( date_i18n( sanitize_option( 'date_format', $_POST['date'] ) ) );
+}
+
+function wp_ajax_time_format() {
+ wp_die( date_i18n( sanitize_option( 'time_format', $_POST['date'] ) ) );
+}
+
+function wp_ajax_wp_fullscreen_save_post() {
+ $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
+
+ $post = $post_type = null;
+
+ if ( $post_id )
+ $post = get_post( $post_id );
+
+ if ( $post )
+ $post_type = $post->post_type;
+ elseif ( isset( $_POST['post_type'] ) && post_type_exists( $_POST['post_type'] ) )
+ $post_type = $_POST['post_type'];
+
+ check_ajax_referer('update-post_' . $post_id, '_wpnonce');
+
+ $post_id = edit_post();
+
+ if ( is_wp_error($post_id) ) {
+ if ( $post_id->get_error_message() )
+ $message = $post_id->get_error_message();
+ else
+ $message = __('Save failed');
+
+ echo json_encode( array( 'message' => $message, 'last_edited' => '' ) );
+ wp_die();
+ } else {
+ $message = __('Saved.');
+ }
+
+ if ( $post ) {
+ $last_date = mysql2date( get_option('date_format'), $post->post_modified );
+ $last_time = mysql2date( get_option('time_format'), $post->post_modified );
+ } else {
+ $last_date = date_i18n( get_option('date_format') );
+ $last_time = date_i18n( get_option('time_format') );
+ }
+
+ if ( $last_id = get_post_meta($post_id, '_edit_last', true) ) {
+ $last_user = get_userdata($last_id);
+ $last_edited = sprintf( __('Last edited by %1$s on %2$s at %3$s'), esc_html( $last_user->display_name ), $last_date, $last_time );
+ } else {
+ $last_edited = sprintf( __('Last edited on %1$s at %2$s'), $last_date, $last_time );
+ }
+
+ echo json_encode( array( 'message' => $message, 'last_edited' => $last_edited ) );
+ wp_die();
+}
+
+function wp_ajax_wp_remove_post_lock() {
+ if ( empty( $_POST['post_ID'] ) || empty( $_POST['active_post_lock'] ) )
+ wp_die( 0 );
+ $post_id = (int) $_POST['post_ID'];
+ if ( ! $post = get_post( $post_id ) )
+ wp_die( 0 );
+
+ check_ajax_referer( 'update-post_' . $post_id );
+
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ wp_die( -1 );
+
+ $active_lock = array_map( 'absint', explode( ':', $_POST['active_post_lock'] ) );
+ if ( $active_lock[1] != get_current_user_id() )
+ wp_die( 0 );
+
+ $new_lock = ( time() - apply_filters( 'wp_check_post_lock_window', 120 ) + 5 ) . ':' . $active_lock[1];
+ update_post_meta( $post_id, '_edit_lock', $new_lock, implode( ':', $active_lock ) );
+ wp_die( 1 );
+}
+
+function wp_ajax_dismiss_wp_pointer() {
+ $pointer = $_POST['pointer'];
+ if ( $pointer != sanitize_key( $pointer ) )
+ wp_die( 0 );
+
+// check_ajax_referer( 'dismiss-pointer_' . $pointer );
+
+ $dismissed = array_filter( explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) ) );
+
+ if ( in_array( $pointer, $dismissed ) )
+ wp_die( 0 );
+
+ $dismissed[] = $pointer;
+ $dismissed = implode( ',', $dismissed );
+
+ update_user_meta( get_current_user_id(), 'dismissed_wp_pointers', $dismissed );
+ wp_die( 1 );
+}
+
+/**
+ * Get an attachment.
+ *
+ * @since 3.5.0
+ */
+function wp_ajax_get_attachment() {
+ if ( ! isset( $_REQUEST['id'] ) )
+ wp_send_json_error();
+
+ if ( ! $id = absint( $_REQUEST['id'] ) )
+ wp_send_json_error();
+
+ if ( ! $post = get_post( $id ) )
+ wp_send_json_error();
+
+ if ( 'attachment' != $post->post_type )
+ wp_send_json_error();
+
+ if ( ! current_user_can( 'upload_files' ) )
+ wp_send_json_error();
+
+ if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
+ wp_send_json_error();
+
+ wp_send_json_success( $attachment );
+}
+
+/**
+ * Query for attachments.
+ *
+ * @since 3.5.0
+ */
+function wp_ajax_query_attachments() {
+ if ( ! current_user_can( 'upload_files' ) )
+ wp_send_json_error();
+
+ $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array();
+ $query = array_intersect_key( $query, array_flip( array(
+ 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type',
+ 'post_parent', 'post__in', 'post__not_in',
+ ) ) );
+
+ $query['post_type'] = 'attachment';
+ $query['post_status'] = 'inherit';
+ if ( current_user_can( get_post_type_object( 'attachment' )->cap->read_private_posts ) )
+ $query['post_status'] .= ',private';
+
+ $query = new WP_Query( $query );
+
+ $posts = array_map( 'wp_prepare_attachment_for_js', $query->posts );
+ $posts = array_filter( $posts );
+
+ wp_send_json_success( $posts );
+}
+
+/**
+ * Save attachment attributes.
+ *
+ * @since 3.5.0
+ */
+function wp_ajax_save_attachment() {
+ if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
+ wp_send_json_error();
+
+ if ( ! $id = absint( $_REQUEST['id'] ) )
+ wp_send_json_error();
+
+ check_ajax_referer( 'update-post_' . $id, 'nonce' );
+
+ if ( ! current_user_can( 'edit_post', $id ) )
+ wp_send_json_error();
+
+ $changes = $_REQUEST['changes'];
+ $post = get_post( $id, ARRAY_A );
+
+ if ( 'attachment' != $post['post_type'] )
+ wp_send_json_error();
+
+ if ( isset( $changes['title'] ) )
+ $post['post_title'] = $changes['title'];
+
+ if ( isset( $changes['caption'] ) )
+ $post['post_excerpt'] = $changes['caption'];
+
+ if ( isset( $changes['description'] ) )
+ $post['post_content'] = $changes['description'];
+
+ if ( isset( $changes['alt'] ) ) {
+ $alt = wp_unslash( $changes['alt'] );
+ if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
+ $alt = wp_strip_all_tags( $alt, true );
+ update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
+ }
+ }
+
+ wp_update_post( $post );
+ wp_send_json_success();
+}
+
+/**
+ * Save backwards compatible attachment attributes.
+ *
+ * @since 3.5.0
+ */
+function wp_ajax_save_attachment_compat() {
+ if ( ! isset( $_REQUEST['id'] ) )
+ wp_send_json_error();
+
+ if ( ! $id = absint( $_REQUEST['id'] ) )
+ wp_send_json_error();
+
+ if ( empty( $_REQUEST['attachments'] ) || empty( $_REQUEST['attachments'][ $id ] ) )
+ wp_send_json_error();
+ $attachment_data = $_REQUEST['attachments'][ $id ];
+
+ check_ajax_referer( 'update-post_' . $id, 'nonce' );
+
+ if ( ! current_user_can( 'edit_post', $id ) )
+ wp_send_json_error();
+
+ $post = get_post( $id, ARRAY_A );
+
+ if ( 'attachment' != $post['post_type'] )
+ wp_send_json_error();
+
+ $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
+
+ if ( isset( $post['errors'] ) ) {
+ $errors = $post['errors']; // @todo return me and display me!
+ unset( $post['errors'] );
+ }
+
+ wp_update_post( $post );
+
+ foreach ( get_attachment_taxonomies( $post ) as $taxonomy ) {
+ if ( isset( $attachment_data[ $taxonomy ] ) )
+ wp_set_object_terms( $id, array_map( 'trim', preg_split( '/,+/', $attachment_data[ $taxonomy ] ) ), $taxonomy, false );
+ }
+
+ if ( ! $attachment = wp_prepare_attachment_for_js( $id ) )
+ wp_send_json_error();
+
+ wp_send_json_success( $attachment );
+}
+
+function wp_ajax_save_attachment_order() {
+ if ( ! isset( $_REQUEST['post_id'] ) )
+ wp_send_json_error();
+
+ if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
+ wp_send_json_error();
+
+ if ( empty( $_REQUEST['attachments'] ) )
+ wp_send_json_error();
+
+ check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
+
+ $attachments = $_REQUEST['attachments'];
+
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ wp_send_json_error();
+
+ $post = get_post( $post_id, ARRAY_A );
+
+ foreach ( $attachments as $attachment_id => $menu_order ) {
+ if ( ! current_user_can( 'edit_post', $attachment_id ) )
+ continue;
+ if ( ! $attachment = get_post( $attachment_id ) )
+ continue;
+ if ( 'attachment' != $attachment->post_type )
+ continue;
+
+ wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
+ }
+
+ wp_send_json_success();
+}
+
+/**
+ * Generates the HTML to send an attachment to the editor.
+ * Backwards compatible with the media_send_to_editor filter and the chain
+ * of filters that follow.
+ *
+ * @since 3.5.0
+ */
+function wp_ajax_send_attachment_to_editor() {
+ check_ajax_referer( 'media-send-to-editor', 'nonce' );
+
+ $attachment = wp_unslash( $_POST['attachment'] );
+
+ $id = intval( $attachment['id'] );
+
+ if ( ! $post = get_post( $id ) )
+ wp_send_json_error();
+
+ if ( 'attachment' != $post->post_type )
+ wp_send_json_error();
+
+ if ( current_user_can( 'edit_post', $id ) ) {
+ // If this attachment is unattached, attach it. Primarily a back compat thing.
+ if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) {
+ wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) );
+ }
+ }
+
+ $rel = $url = '';
+ $html = $title = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
+ if ( ! empty( $attachment['url'] ) ) {
+ $url = $attachment['url'];
+ if ( strpos( $url, 'attachment_id') || get_attachment_link( $id ) == $url )
+ $rel = ' rel="attachment wp-att-' . $id . '"';
+ $html = '<a href="' . esc_url( $url ) . '"' . $rel . '>' . $html . '</a>';
+ }
+
+ remove_filter( 'media_send_to_editor', 'image_media_send_to_editor' );
+
+ if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) {
+ $align = isset( $attachment['align'] ) ? $attachment['align'] : 'none';
+ $size = isset( $attachment['image-size'] ) ? $attachment['image-size'] : 'medium';
+ $alt = isset( $attachment['image_alt'] ) ? $attachment['image_alt'] : '';
+ $caption = isset( $attachment['post_excerpt'] ) ? $attachment['post_excerpt'] : '';
+ $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
+ $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
+ } elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 ) ) {
+ $html = stripslashes_deep( $_POST['html'] );
+ }
+
+ $html = apply_filters( 'media_send_to_editor', $html, $id, $attachment );
+
+ wp_send_json_success( $html );
+}
+
+/**
+ * Generates the HTML to send a non-image embed link to the editor.
+ *
+ * Backwards compatible with the following filters:
+ * - file_send_to_editor_url
+ * - audio_send_to_editor_url
+ * - video_send_to_editor_url
+ *
+ * @since 3.5.0
+ */
+function wp_ajax_send_link_to_editor() {
+ check_ajax_referer( 'media-send-to-editor', 'nonce' );
+
+ if ( ! $src = wp_unslash( $_POST['src'] ) )
+ wp_send_json_error();
+
+ if ( ! strpos( $src, '://' ) )
+ $src = 'http://' . $src;
+
+ if ( ! $src = esc_url_raw( $src ) )
+ wp_send_json_error();
+
+ if ( ! $title = trim( wp_unslash( $_POST['title'] ) ) )
+ $title = wp_basename( $src );
+
+ $html = '';
+ if ( $title )
+ $html = '<a href="' . esc_url( $src ) . '">' . $title . '</a>';
+
+ // Figure out what filter to run:
+ $type = 'file';
+ if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
+ && ( 'audio' == $ext_type || 'video' == $ext_type ) )
+ $type = $ext_type;
+
+ $html = apply_filters( $type . '_send_to_editor_url', $html, $src, $title );
+
+ wp_send_json_success( $html );
+}
+
+/**
+ * Heartbeat API (experimental)
+ *
+ * Runs when the user is logged in.
+ */
+function wp_ajax_heartbeat() {
+ if ( empty( $_POST['_nonce'] ) )
+ wp_send_json_error();
+
+ $response = array();
+
+ if ( false === wp_verify_nonce( $_POST['_nonce'], 'heartbeat-nonce' ) ) {
+ // User is logged in but nonces have expired.
+ $response['nonces_expired'] = true;
+ wp_send_json($response);
+ }
+
+ // screen_id is the same as $current_screen->id and the JS global 'pagenow'
+ if ( ! empty($_POST['screen_id']) )
+ $screen_id = sanitize_key($_POST['screen_id']);
+ else
+ $screen_id = 'front';
+
+ if ( ! empty($_POST['data']) ) {
+ $data = (array) $_POST['data'];
+ $response = apply_filters( 'heartbeat_received', $response, $data, $screen_id );
+ }
+
+ $response = apply_filters( 'heartbeat_send', $response, $screen_id );
+
+ // Allow the transport to be replaced with long-polling easily
+ do_action( 'heartbeat_tick', $response, $screen_id );
+
+ // Send the current time according to the server
+ $response['server_time'] = time();
+
+ wp_send_json($response);
+}
+
+function wp_ajax_get_revision_diffs() {
+ require ABSPATH . 'wp-admin/includes/revision.php';
+
+ if ( ! $post = get_post( (int) $_REQUEST['post_id'] ) )
+ wp_send_json_error();
+
+ if ( ! current_user_can( 'read_post', $post->ID ) )
+ wp_send_json_error();
+
+ // Really just pre-loading the cache here.
+ if ( ! $revisions = wp_get_post_revisions( $post->ID, array( 'check_enabled' => false ) ) )
+ wp_send_json_error();
+
+ $return = array();
+ @set_time_limit( 0 );
+
+ foreach ( $_REQUEST['compare'] as $compare_key ) {
+ list( $compare_from, $compare_to ) = explode( ':', $compare_key ); // from:to
+
+ $return[] = array(
+ 'id' => $compare_key,
+ 'fields' => wp_get_revision_ui_diff( $post, $compare_from, $compare_to ),
+ );
+ }
+ wp_send_json_success( $return );
+}
diff --git a/src/wp-admin/includes/bookmark.php b/src/wp-admin/includes/bookmark.php
new file mode 100644
index 0000000000..0897fdc5a4
--- /dev/null
+++ b/src/wp-admin/includes/bookmark.php
@@ -0,0 +1,290 @@
+<?php
+/**
+ * WordPress Bookmark Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Add a link to using values provided in $_POST.
+ *
+ * @since 2.0.0
+ *
+ * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success.
+ */
+function add_link() {
+ return edit_link();
+}
+
+/**
+ * Update or insert a link using values provided in $_POST.
+ *
+ * @since 2.0.0
+ *
+ * @param int $link_id Optional. ID of the link to edit.
+ * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success.
+ */
+function edit_link( $link_id = 0 ) {
+ if ( !current_user_can( 'manage_links' ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ $_POST['link_url'] = esc_html( $_POST['link_url'] );
+ $_POST['link_url'] = esc_url($_POST['link_url']);
+ $_POST['link_name'] = esc_html( $_POST['link_name'] );
+ $_POST['link_image'] = esc_html( $_POST['link_image'] );
+ $_POST['link_rss'] = esc_url($_POST['link_rss']);
+ if ( !isset($_POST['link_visible']) || 'N' != $_POST['link_visible'] )
+ $_POST['link_visible'] = 'Y';
+
+ if ( !empty( $link_id ) ) {
+ $_POST['link_id'] = $link_id;
+ return wp_update_link( $_POST );
+ } else {
+ return wp_insert_link( $_POST );
+ }
+}
+
+/**
+ * Retrieve the default link for editing.
+ *
+ * @since 2.0.0
+ *
+ * @return object Default link
+ */
+function get_default_link_to_edit() {
+ $link = new stdClass;
+ if ( isset( $_GET['linkurl'] ) )
+ $link->link_url = esc_url( wp_unslash( $_GET['linkurl'] ) );
+ else
+ $link->link_url = '';
+
+ if ( isset( $_GET['name'] ) )
+ $link->link_name = esc_attr( wp_unslash( $_GET['name'] ) );
+ else
+ $link->link_name = '';
+
+ $link->link_visible = 'Y';
+
+ return $link;
+}
+
+/**
+ * Delete link specified from database
+ *
+ * @since 2.0.0
+ *
+ * @param int $link_id ID of the link to delete
+ * @return bool True
+ */
+function wp_delete_link( $link_id ) {
+ global $wpdb;
+
+ do_action( 'delete_link', $link_id );
+
+ wp_delete_object_term_relationships( $link_id, 'link_category' );
+
+ $wpdb->delete( $wpdb->links, array( 'link_id' => $link_id ) );
+
+ do_action( 'deleted_link', $link_id );
+
+ clean_bookmark_cache( $link_id );
+
+ return true;
+}
+
+/**
+ * Retrieves the link categories associated with the link specified.
+ *
+ * @since 2.1.0
+ *
+ * @param int $link_id Link ID to look up
+ * @return array The requested link's categories
+ */
+function wp_get_link_cats( $link_id = 0 ) {
+
+ $cats = wp_get_object_terms( $link_id, 'link_category', array('fields' => 'ids') );
+
+ return array_unique( $cats );
+}
+
+/**
+ * Retrieve link data based on ID.
+ *
+ * @since 2.0.0
+ *
+ * @param int $link_id ID of link to retrieve
+ * @return object Link for editing
+ */
+function get_link_to_edit( $link_id ) {
+ return get_bookmark( $link_id, OBJECT, 'edit' );
+}
+
+/**
+ * This function inserts/updates links into/in the database.
+ *
+ * @since 2.0.0
+ *
+ * @param array $linkdata Elements that make up the link to insert.
+ * @param bool $wp_error Optional. If true return WP_Error object on failure.
+ * @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success.
+ */
+function wp_insert_link( $linkdata, $wp_error = false ) {
+ global $wpdb;
+
+ $defaults = array( 'link_id' => 0, 'link_name' => '', 'link_url' => '', 'link_rating' => 0 );
+
+ $linkdata = wp_parse_args( $linkdata, $defaults );
+ $linkdata = sanitize_bookmark( $linkdata, 'db' );
+
+ extract( wp_unslash( $linkdata ), EXTR_SKIP );
+
+ $update = false;
+
+ if ( !empty( $link_id ) )
+ $update = true;
+
+ if ( trim( $link_name ) == '' ) {
+ if ( trim( $link_url ) != '' ) {
+ $link_name = $link_url;
+ } else {
+ return 0;
+ }
+ }
+
+ if ( trim( $link_url ) == '' )
+ return 0;
+
+ if ( empty( $link_rating ) )
+ $link_rating = 0;
+
+ if ( empty( $link_image ) )
+ $link_image = '';
+
+ if ( empty( $link_target ) )
+ $link_target = '';
+
+ if ( empty( $link_visible ) )
+ $link_visible = 'Y';
+
+ if ( empty( $link_owner ) )
+ $link_owner = get_current_user_id();
+
+ if ( empty( $link_notes ) )
+ $link_notes = '';
+
+ if ( empty( $link_description ) )
+ $link_description = '';
+
+ if ( empty( $link_rss ) )
+ $link_rss = '';
+
+ if ( empty( $link_rel ) )
+ $link_rel = '';
+
+ // Make sure we set a valid category
+ if ( ! isset( $link_category ) || 0 == count( $link_category ) || !is_array( $link_category ) ) {
+ $link_category = array( get_option( 'default_link_category' ) );
+ }
+
+ if ( $update ) {
+ if ( false === $wpdb->update( $wpdb->links, compact('link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_rating', 'link_rel', 'link_notes', 'link_rss'), compact('link_id') ) ) {
+ if ( $wp_error )
+ return new WP_Error( 'db_update_error', __( 'Could not update link in the database' ), $wpdb->last_error );
+ else
+ return 0;
+ }
+ } else {
+ if ( false === $wpdb->insert( $wpdb->links, compact('link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss') ) ) {
+ if ( $wp_error )
+ return new WP_Error( 'db_insert_error', __( 'Could not insert link into the database' ), $wpdb->last_error );
+ else
+ return 0;
+ }
+ $link_id = (int) $wpdb->insert_id;
+ }
+
+ wp_set_link_cats( $link_id, $link_category );
+
+ if ( $update )
+ do_action( 'edit_link', $link_id );
+ else
+ do_action( 'add_link', $link_id );
+
+ clean_bookmark_cache( $link_id );
+
+ return $link_id;
+}
+
+/**
+ * Update link with the specified link categories.
+ *
+ * @since 2.1.0
+ *
+ * @param int $link_id ID of link to update
+ * @param array $link_categories Array of categories to
+ */
+function wp_set_link_cats( $link_id = 0, $link_categories = array() ) {
+ // If $link_categories isn't already an array, make it one:
+ if ( !is_array( $link_categories ) || 0 == count( $link_categories ) )
+ $link_categories = array( get_option( 'default_link_category' ) );
+
+ $link_categories = array_map( 'intval', $link_categories );
+ $link_categories = array_unique( $link_categories );
+
+ wp_set_object_terms( $link_id, $link_categories, 'link_category' );
+
+ clean_bookmark_cache( $link_id );
+}
+
+/**
+ * Update a link in the database.
+ *
+ * @since 2.0.0
+ *
+ * @param array $linkdata Link data to update.
+ * @return int|WP_Error Value 0 or WP_Error on failure. The updated link ID on success.
+ */
+function wp_update_link( $linkdata ) {
+ $link_id = (int) $linkdata['link_id'];
+
+ $link = get_bookmark( $link_id, ARRAY_A );
+
+ // Escape data pulled from DB.
+ $link = wp_slash( $link );
+
+ // Passed link category list overwrites existing category list if not empty.
+ if ( isset( $linkdata['link_category'] ) && is_array( $linkdata['link_category'] )
+ && 0 != count( $linkdata['link_category'] ) )
+ $link_cats = $linkdata['link_category'];
+ else
+ $link_cats = $link['link_category'];
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $linkdata = array_merge( $link, $linkdata );
+ $linkdata['link_category'] = $link_cats;
+
+ return wp_insert_link( $linkdata );
+}
+
+/**
+ * @since 3.5.0
+ * @access private
+ */
+function wp_link_manager_disabled_message() {
+ global $pagenow;
+ if ( 'link-manager.php' != $pagenow && 'link-add.php' != $pagenow && 'link.php' != $pagenow )
+ return;
+
+ add_filter( 'pre_option_link_manager_enabled', '__return_true', 100 );
+ $really_can_manage_links = current_user_can( 'manage_links' );
+ remove_filter( 'pre_option_link_manager_enabled', '__return_true', 100 );
+
+ if ( $really_can_manage_links && current_user_can( 'install_plugins' ) ) {
+ $link = network_admin_url( 'plugin-install.php?tab=search&amp;s=Link+Manager' );
+ wp_die( sprintf( __( 'If you are looking to use the link manager, please install the <a href="%s">Link Manager</a> plugin.' ), $link ) );
+ }
+
+ wp_die( __( 'You do not have sufficient permissions to edit the links for this site.' ) );
+}
+add_action( 'admin_page_access_denied', 'wp_link_manager_disabled_message' );
diff --git a/src/wp-admin/includes/class-ftp-pure.php b/src/wp-admin/includes/class-ftp-pure.php
new file mode 100644
index 0000000000..c765d553eb
--- /dev/null
+++ b/src/wp-admin/includes/class-ftp-pure.php
@@ -0,0 +1,190 @@
+<?php
+/**
+ * PemFTP - A Ftp implementation in pure PHP
+ *
+ * @package PemFTP
+ * @since 2.5
+ *
+ * @version 1.0
+ * @copyright Alexey Dotsenko
+ * @author Alexey Dotsenko
+ * @link http://www.phpclasses.org/browse/package/1743.html Site
+ * @license LGPL http://www.opensource.org/licenses/lgpl-license.html
+ */
+
+/**
+ * FTP implementation using fsockopen to connect.
+ *
+ * @package PemFTP
+ * @subpackage Pure
+ * @since 2.5
+ *
+ * @version 1.0
+ * @copyright Alexey Dotsenko
+ * @author Alexey Dotsenko
+ * @link http://www.phpclasses.org/browse/package/1743.html Site
+ * @license LGPL http://www.opensource.org/licenses/lgpl-license.html
+ */
+class ftp extends ftp_base {
+
+ function ftp($verb=FALSE, $le=FALSE) {
+ $this->__construct($verb, $le);
+ }
+
+ function __construct($verb=FALSE, $le=FALSE) {
+ parent::__construct(false, $verb, $le);
+ }
+
+// <!-- --------------------------------------------------------------------------------------- -->
+// <!-- Private functions -->
+// <!-- --------------------------------------------------------------------------------------- -->
+
+ function _settimeout($sock) {
+ if(!@stream_set_timeout($sock, $this->_timeout)) {
+ $this->PushError('_settimeout','socket set send timeout');
+ $this->_quit();
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ function _connect($host, $port) {
+ $this->SendMSG("Creating socket");
+ $sock = @fsockopen($host, $port, $errno, $errstr, $this->_timeout);
+ if (!$sock) {
+ $this->PushError('_connect','socket connect failed', $errstr." (".$errno.")");
+ return FALSE;
+ }
+ $this->_connected=true;
+ return $sock;
+ }
+
+ function _readmsg($fnction="_readmsg"){
+ if(!$this->_connected) {
+ $this->PushError($fnction, 'Connect first');
+ return FALSE;
+ }
+ $result=true;
+ $this->_message="";
+ $this->_code=0;
+ $go=true;
+ do {
+ $tmp=@fgets($this->_ftp_control_sock, 512);
+ if($tmp===false) {
+ $go=$result=false;
+ $this->PushError($fnction,'Read failed');
+ } else {
+ $this->_message.=$tmp;
+ if(preg_match("/^([0-9]{3})(-(.*[".CRLF."]{1,2})+\\1)? [^".CRLF."]+[".CRLF."]{1,2}$/", $this->_message, $regs)) $go=false;
+ }
+ } while($go);
+ if($this->LocalEcho) echo "GET < ".rtrim($this->_message, CRLF).CRLF;
+ $this->_code=(int)$regs[1];
+ return $result;
+ }
+
+ function _exec($cmd, $fnction="_exec") {
+ if(!$this->_ready) {
+ $this->PushError($fnction,'Connect first');
+ return FALSE;
+ }
+ if($this->LocalEcho) echo "PUT > ",$cmd,CRLF;
+ $status=@fputs($this->_ftp_control_sock, $cmd.CRLF);
+ if($status===false) {
+ $this->PushError($fnction,'socket write failed');
+ return FALSE;
+ }
+ $this->_lastaction=time();
+ if(!$this->_readmsg($fnction)) return FALSE;
+ return TRUE;
+ }
+
+ function _data_prepare($mode=FTP_ASCII) {
+ if(!$this->_settype($mode)) return FALSE;
+ if($this->_passive) {
+ if(!$this->_exec("PASV", "pasv")) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ return FALSE;
+ }
+ $ip_port = explode(",", ereg_replace("^.+ \\(?([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)\\)?.*".CRLF."$", "\\1", $this->_message));
+ $this->_datahost=$ip_port[0].".".$ip_port[1].".".$ip_port[2].".".$ip_port[3];
+ $this->_dataport=(((int)$ip_port[4])<<8) + ((int)$ip_port[5]);
+ $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
+ $this->_ftp_data_sock=@fsockopen($this->_datahost, $this->_dataport, $errno, $errstr, $this->_timeout);
+ if(!$this->_ftp_data_sock) {
+ $this->PushError("_data_prepare","fsockopen fails", $errstr." (".$errno.")");
+ $this->_data_close();
+ return FALSE;
+ }
+ else $this->_ftp_data_sock;
+ } else {
+ $this->SendMSG("Only passive connections available!");
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ function _data_read($mode=FTP_ASCII, $fp=NULL) {
+ if(is_resource($fp)) $out=0;
+ else $out="";
+ if(!$this->_passive) {
+ $this->SendMSG("Only passive connections available!");
+ return FALSE;
+ }
+ while (!feof($this->_ftp_data_sock)) {
+ $block=fread($this->_ftp_data_sock, $this->_ftp_buff_size);
+ if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_local], $block);
+ if(is_resource($fp)) $out+=fwrite($fp, $block, strlen($block));
+ else $out.=$block;
+ }
+ return $out;
+ }
+
+ function _data_write($mode=FTP_ASCII, $fp=NULL) {
+ if(is_resource($fp)) $out=0;
+ else $out="";
+ if(!$this->_passive) {
+ $this->SendMSG("Only passive connections available!");
+ return FALSE;
+ }
+ if(is_resource($fp)) {
+ while(!feof($fp)) {
+ $block=fread($fp, $this->_ftp_buff_size);
+ if(!$this->_data_write_block($mode, $block)) return false;
+ }
+ } elseif(!$this->_data_write_block($mode, $fp)) return false;
+ return TRUE;
+ }
+
+ function _data_write_block($mode, $block) {
+ if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_remote], $block);
+ do {
+ if(($t=@fwrite($this->_ftp_data_sock, $block))===FALSE) {
+ $this->PushError("_data_write","Can't write to socket");
+ return FALSE;
+ }
+ $block=substr($block, $t);
+ } while(!empty($block));
+ return true;
+ }
+
+ function _data_close() {
+ @fclose($this->_ftp_data_sock);
+ $this->SendMSG("Disconnected data from remote host");
+ return TRUE;
+ }
+
+ function _quit($force=FALSE) {
+ if($this->_connected or $force) {
+ @fclose($this->_ftp_control_sock);
+ $this->_connected=false;
+ $this->SendMSG("Socket closed");
+ }
+ }
+}
+
+?>
diff --git a/src/wp-admin/includes/class-ftp-sockets.php b/src/wp-admin/includes/class-ftp-sockets.php
new file mode 100644
index 0000000000..abdf0db682
--- /dev/null
+++ b/src/wp-admin/includes/class-ftp-sockets.php
@@ -0,0 +1,250 @@
+<?php
+/**
+ * PemFTP - A Ftp implementation in pure PHP
+ *
+ * @package PemFTP
+ * @since 2.5
+ *
+ * @version 1.0
+ * @copyright Alexey Dotsenko
+ * @author Alexey Dotsenko
+ * @link http://www.phpclasses.org/browse/package/1743.html Site
+ * @license LGPL http://www.opensource.org/licenses/lgpl-license.html
+ */
+
+/**
+ * Socket Based FTP implementation
+ *
+ * @package PemFTP
+ * @subpackage Socket
+ * @since 2.5
+ *
+ * @version 1.0
+ * @copyright Alexey Dotsenko
+ * @author Alexey Dotsenko
+ * @link http://www.phpclasses.org/browse/package/1743.html Site
+ * @license LGPL http://www.opensource.org/licenses/lgpl-license.html
+ */
+class ftp extends ftp_base {
+
+ function ftp($verb=FALSE, $le=FALSE) {
+ $this->__construct($verb, $le);
+ }
+
+ function __construct($verb=FALSE, $le=FALSE) {
+ parent::__construct(true, $verb, $le);
+ }
+
+// <!-- --------------------------------------------------------------------------------------- -->
+// <!-- Private functions -->
+// <!-- --------------------------------------------------------------------------------------- -->
+
+ function _settimeout($sock) {
+ if(!@socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>$this->_timeout, "usec"=>0))) {
+ $this->PushError('_connect','socket set receive timeout',socket_strerror(socket_last_error($sock)));
+ @socket_close($sock);
+ return FALSE;
+ }
+ if(!@socket_set_option($sock, SOL_SOCKET , SO_SNDTIMEO, array("sec"=>$this->_timeout, "usec"=>0))) {
+ $this->PushError('_connect','socket set send timeout',socket_strerror(socket_last_error($sock)));
+ @socket_close($sock);
+ return FALSE;
+ }
+ return true;
+ }
+
+ function _connect($host, $port) {
+ $this->SendMSG("Creating socket");
+ if(!($sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) {
+ $this->PushError('_connect','socket create failed',socket_strerror(socket_last_error($sock)));
+ return FALSE;
+ }
+ if(!$this->_settimeout($sock)) return FALSE;
+ $this->SendMSG("Connecting to \"".$host.":".$port."\"");
+ if (!($res = @socket_connect($sock, $host, $port))) {
+ $this->PushError('_connect','socket connect failed',socket_strerror(socket_last_error($sock)));
+ @socket_close($sock);
+ return FALSE;
+ }
+ $this->_connected=true;
+ return $sock;
+ }
+
+ function _readmsg($fnction="_readmsg"){
+ if(!$this->_connected) {
+ $this->PushError($fnction,'Connect first');
+ return FALSE;
+ }
+ $result=true;
+ $this->_message="";
+ $this->_code=0;
+ $go=true;
+ do {
+ $tmp=@socket_read($this->_ftp_control_sock, 4096, PHP_BINARY_READ);
+ if($tmp===false) {
+ $go=$result=false;
+ $this->PushError($fnction,'Read failed', socket_strerror(socket_last_error($this->_ftp_control_sock)));
+ } else {
+ $this->_message.=$tmp;
+ $go = !preg_match("/^([0-9]{3})(-.+\\1)? [^".CRLF."]+".CRLF."$/Us", $this->_message, $regs);
+ }
+ } while($go);
+ if($this->LocalEcho) echo "GET < ".rtrim($this->_message, CRLF).CRLF;
+ $this->_code=(int)$regs[1];
+ return $result;
+ }
+
+ function _exec($cmd, $fnction="_exec") {
+ if(!$this->_ready) {
+ $this->PushError($fnction,'Connect first');
+ return FALSE;
+ }
+ if($this->LocalEcho) echo "PUT > ",$cmd,CRLF;
+ $status=@socket_write($this->_ftp_control_sock, $cmd.CRLF);
+ if($status===false) {
+ $this->PushError($fnction,'socket write failed', socket_strerror(socket_last_error($this->stream)));
+ return FALSE;
+ }
+ $this->_lastaction=time();
+ if(!$this->_readmsg($fnction)) return FALSE;
+ return TRUE;
+ }
+
+ function _data_prepare($mode=FTP_ASCII) {
+ if(!$this->_settype($mode)) return FALSE;
+ $this->SendMSG("Creating data socket");
+ $this->_ftp_data_sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
+ if ($this->_ftp_data_sock < 0) {
+ $this->PushError('_data_prepare','socket create failed',socket_strerror(socket_last_error($this->_ftp_data_sock)));
+ return FALSE;
+ }
+ if(!$this->_settimeout($this->_ftp_data_sock)) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if($this->_passive) {
+ if(!$this->_exec("PASV", "pasv")) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ return FALSE;
+ }
+ $ip_port = explode(",", ereg_replace("^.+ \\(?([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)\\)?.*".CRLF."$", "\\1", $this->_message));
+ $this->_datahost=$ip_port[0].".".$ip_port[1].".".$ip_port[2].".".$ip_port[3];
+ $this->_dataport=(((int)$ip_port[4])<<8) + ((int)$ip_port[5]);
+ $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
+ if(!@socket_connect($this->_ftp_data_sock, $this->_datahost, $this->_dataport)) {
+ $this->PushError("_data_prepare","socket_connect", socket_strerror(socket_last_error($this->_ftp_data_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ else $this->_ftp_temp_sock=$this->_ftp_data_sock;
+ } else {
+ if(!@socket_getsockname($this->_ftp_control_sock, $addr, $port)) {
+ $this->PushError("_data_prepare","can't get control socket information", socket_strerror(socket_last_error($this->_ftp_control_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!@socket_bind($this->_ftp_data_sock,$addr)){
+ $this->PushError("_data_prepare","can't bind data socket", socket_strerror(socket_last_error($this->_ftp_data_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!@socket_listen($this->_ftp_data_sock)) {
+ $this->PushError("_data_prepare","can't listen data socket", socket_strerror(socket_last_error($this->_ftp_data_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!@socket_getsockname($this->_ftp_data_sock, $this->_datahost, $this->_dataport)) {
+ $this->PushError("_data_prepare","can't get data socket information", socket_strerror(socket_last_error($this->_ftp_data_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_exec('PORT '.str_replace('.',',',$this->_datahost.'.'.($this->_dataport>>8).'.'.($this->_dataport&0x00FF)), "_port")) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ function _data_read($mode=FTP_ASCII, $fp=NULL) {
+ $NewLine=$this->_eol_code[$this->OS_local];
+ if(is_resource($fp)) $out=0;
+ else $out="";
+ if(!$this->_passive) {
+ $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
+ $this->_ftp_temp_sock=socket_accept($this->_ftp_data_sock);
+ if($this->_ftp_temp_sock===FALSE) {
+ $this->PushError("_data_read","socket_accept", socket_strerror(socket_last_error($this->_ftp_temp_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ }
+
+ while(($block=@socket_read($this->_ftp_temp_sock, $this->_ftp_buff_size, PHP_BINARY_READ))!==false) {
+ if($block==="") break;
+ if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_local], $block);
+ if(is_resource($fp)) $out+=fwrite($fp, $block, strlen($block));
+ else $out.=$block;
+ }
+ return $out;
+ }
+
+ function _data_write($mode=FTP_ASCII, $fp=NULL) {
+ $NewLine=$this->_eol_code[$this->OS_local];
+ if(is_resource($fp)) $out=0;
+ else $out="";
+ if(!$this->_passive) {
+ $this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
+ $this->_ftp_temp_sock=socket_accept($this->_ftp_data_sock);
+ if($this->_ftp_temp_sock===FALSE) {
+ $this->PushError("_data_write","socket_accept", socket_strerror(socket_last_error($this->_ftp_temp_sock)));
+ $this->_data_close();
+ return false;
+ }
+ }
+ if(is_resource($fp)) {
+ while(!feof($fp)) {
+ $block=fread($fp, $this->_ftp_buff_size);
+ if(!$this->_data_write_block($mode, $block)) return false;
+ }
+ } elseif(!$this->_data_write_block($mode, $fp)) return false;
+ return true;
+ }
+
+ function _data_write_block($mode, $block) {
+ if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_remote], $block);
+ do {
+ if(($t=@socket_write($this->_ftp_temp_sock, $block))===FALSE) {
+ $this->PushError("_data_write","socket_write", socket_strerror(socket_last_error($this->_ftp_temp_sock)));
+ $this->_data_close();
+ return FALSE;
+ }
+ $block=substr($block, $t);
+ } while(!empty($block));
+ return true;
+ }
+
+ function _data_close() {
+ @socket_close($this->_ftp_temp_sock);
+ @socket_close($this->_ftp_data_sock);
+ $this->SendMSG("Disconnected data from remote host");
+ return TRUE;
+ }
+
+ function _quit() {
+ if($this->_connected) {
+ @socket_close($this->_ftp_control_sock);
+ $this->_connected=false;
+ $this->SendMSG("Socket closed");
+ }
+ }
+}
+?>
diff --git a/src/wp-admin/includes/class-ftp.php b/src/wp-admin/includes/class-ftp.php
new file mode 100644
index 0000000000..f068f157bd
--- /dev/null
+++ b/src/wp-admin/includes/class-ftp.php
@@ -0,0 +1,907 @@
+<?php
+/**
+ * PemFTP - A Ftp implementation in pure PHP
+ *
+ * @package PemFTP
+ * @since 2.5
+ *
+ * @version 1.0
+ * @copyright Alexey Dotsenko
+ * @author Alexey Dotsenko
+ * @link http://www.phpclasses.org/browse/package/1743.html Site
+ * @license LGPL http://www.opensource.org/licenses/lgpl-license.html
+ */
+
+/**
+ * Defines the newline characters, if not defined already.
+ *
+ * This can be redefined.
+ *
+ * @since 2.5
+ * @var string
+ */
+if(!defined('CRLF')) define('CRLF',"\r\n");
+
+/**
+ * Sets whatever to autodetect ASCII mode.
+ *
+ * This can be redefined.
+ *
+ * @since 2.5
+ * @var int
+ */
+if(!defined("FTP_AUTOASCII")) define("FTP_AUTOASCII", -1);
+
+/**
+ *
+ * This can be redefined.
+ * @since 2.5
+ * @var int
+ */
+if(!defined("FTP_BINARY")) define("FTP_BINARY", 1);
+
+/**
+ *
+ * This can be redefined.
+ * @since 2.5
+ * @var int
+ */
+if(!defined("FTP_ASCII")) define("FTP_ASCII", 0);
+
+/**
+ * Whether to force FTP.
+ *
+ * This can be redefined.
+ *
+ * @since 2.5
+ * @var bool
+ */
+if(!defined('FTP_FORCE')) define('FTP_FORCE', true);
+
+/**
+ * @since 2.5
+ * @var string
+ */
+define('FTP_OS_Unix','u');
+
+/**
+ * @since 2.5
+ * @var string
+ */
+define('FTP_OS_Windows','w');
+
+/**
+ * @since 2.5
+ * @var string
+ */
+define('FTP_OS_Mac','m');
+
+/**
+ * PemFTP base class
+ *
+ */
+class ftp_base {
+ /* Public variables */
+ var $LocalEcho;
+ var $Verbose;
+ var $OS_local;
+ var $OS_remote;
+
+ /* Private variables */
+ var $_lastaction;
+ var $_errors;
+ var $_type;
+ var $_umask;
+ var $_timeout;
+ var $_passive;
+ var $_host;
+ var $_fullhost;
+ var $_port;
+ var $_datahost;
+ var $_dataport;
+ var $_ftp_control_sock;
+ var $_ftp_data_sock;
+ var $_ftp_temp_sock;
+ var $_ftp_buff_size;
+ var $_login;
+ var $_password;
+ var $_connected;
+ var $_ready;
+ var $_code;
+ var $_message;
+ var $_can_restore;
+ var $_port_available;
+ var $_curtype;
+ var $_features;
+
+ var $_error_array;
+ var $AuthorizedTransferMode;
+ var $OS_FullName;
+ var $_eol_code;
+ var $AutoAsciiExt;
+
+ /* Constructor */
+ function ftp_base($port_mode=FALSE) {
+ $this->__construct($port_mode);
+ }
+
+ function __construct($port_mode=FALSE, $verb=FALSE, $le=FALSE) {
+ $this->LocalEcho=$le;
+ $this->Verbose=$verb;
+ $this->_lastaction=NULL;
+ $this->_error_array=array();
+ $this->_eol_code=array(FTP_OS_Unix=>"\n", FTP_OS_Mac=>"\r", FTP_OS_Windows=>"\r\n");
+ $this->AuthorizedTransferMode=array(FTP_AUTOASCII, FTP_ASCII, FTP_BINARY);
+ $this->OS_FullName=array(FTP_OS_Unix => 'UNIX', FTP_OS_Windows => 'WINDOWS', FTP_OS_Mac => 'MACOS');
+ $this->AutoAsciiExt=array("ASP","BAT","C","CPP","CSS","CSV","JS","H","HTM","HTML","SHTML","INI","LOG","PHP3","PHTML","PL","PERL","SH","SQL","TXT");
+ $this->_port_available=($port_mode==TRUE);
+ $this->SendMSG("Staring FTP client class".($this->_port_available?"":" without PORT mode support"));
+ $this->_connected=FALSE;
+ $this->_ready=FALSE;
+ $this->_can_restore=FALSE;
+ $this->_code=0;
+ $this->_message="";
+ $this->_ftp_buff_size=4096;
+ $this->_curtype=NULL;
+ $this->SetUmask(0022);
+ $this->SetType(FTP_AUTOASCII);
+ $this->SetTimeout(30);
+ $this->Passive(!$this->_port_available);
+ $this->_login="anonymous";
+ $this->_password="anon@ftp.com";
+ $this->_features=array();
+ $this->OS_local=FTP_OS_Unix;
+ $this->OS_remote=FTP_OS_Unix;
+ $this->features=array();
+ if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $this->OS_local=FTP_OS_Windows;
+ elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'MAC') $this->OS_local=FTP_OS_Mac;
+ }
+
+// <!-- --------------------------------------------------------------------------------------- -->
+// <!-- Public functions -->
+// <!-- --------------------------------------------------------------------------------------- -->
+
+ function parselisting($line) {
+ $is_windows = ($this->OS_remote == FTP_OS_Windows);
+ if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/",$line,$lucifer)) {
+ $b = array();
+ if ($lucifer[3]<70) { $lucifer[3]+=2000; } else { $lucifer[3]+=1900; } // 4digit year fix
+ $b['isdir'] = ($lucifer[7]=="<DIR>");
+ if ( $b['isdir'] )
+ $b['type'] = 'd';
+ else
+ $b['type'] = 'f';
+ $b['size'] = $lucifer[7];
+ $b['month'] = $lucifer[1];
+ $b['day'] = $lucifer[2];
+ $b['year'] = $lucifer[3];
+ $b['hour'] = $lucifer[4];
+ $b['minute'] = $lucifer[5];
+ $b['time'] = @mktime($lucifer[4]+(strcasecmp($lucifer[6],"PM")==0?12:0),$lucifer[5],0,$lucifer[1],$lucifer[2],$lucifer[3]);
+ $b['am/pm'] = $lucifer[6];
+ $b['name'] = $lucifer[8];
+ } else if (!$is_windows && $lucifer=preg_split("/[ ]/",$line,9,PREG_SPLIT_NO_EMPTY)) {
+ //echo $line."\n";
+ $lcount=count($lucifer);
+ if ($lcount<8) return '';
+ $b = array();
+ $b['isdir'] = $lucifer[0]{0} === "d";
+ $b['islink'] = $lucifer[0]{0} === "l";
+ if ( $b['isdir'] )
+ $b['type'] = 'd';
+ elseif ( $b['islink'] )
+ $b['type'] = 'l';
+ else
+ $b['type'] = 'f';
+ $b['perms'] = $lucifer[0];
+ $b['number'] = $lucifer[1];
+ $b['owner'] = $lucifer[2];
+ $b['group'] = $lucifer[3];
+ $b['size'] = $lucifer[4];
+ if ($lcount==8) {
+ sscanf($lucifer[5],"%d-%d-%d",$b['year'],$b['month'],$b['day']);
+ sscanf($lucifer[6],"%d:%d",$b['hour'],$b['minute']);
+ $b['time'] = @mktime($b['hour'],$b['minute'],0,$b['month'],$b['day'],$b['year']);
+ $b['name'] = $lucifer[7];
+ } else {
+ $b['month'] = $lucifer[5];
+ $b['day'] = $lucifer[6];
+ if (preg_match("/([0-9]{2}):([0-9]{2})/",$lucifer[7],$l2)) {
+ $b['year'] = date("Y");
+ $b['hour'] = $l2[1];
+ $b['minute'] = $l2[2];
+ } else {
+ $b['year'] = $lucifer[7];
+ $b['hour'] = 0;
+ $b['minute'] = 0;
+ }
+ $b['time'] = strtotime(sprintf("%d %s %d %02d:%02d",$b['day'],$b['month'],$b['year'],$b['hour'],$b['minute']));
+ $b['name'] = $lucifer[8];
+ }
+ }
+
+ return $b;
+ }
+
+ function SendMSG($message = "", $crlf=true) {
+ if ($this->Verbose) {
+ echo $message.($crlf?CRLF:"");
+ flush();
+ }
+ return TRUE;
+ }
+
+ function SetType($mode=FTP_AUTOASCII) {
+ if(!in_array($mode, $this->AuthorizedTransferMode)) {
+ $this->SendMSG("Wrong type");
+ return FALSE;
+ }
+ $this->_type=$mode;
+ $this->SendMSG("Transfer type: ".($this->_type==FTP_BINARY?"binary":($this->_type==FTP_ASCII?"ASCII":"auto ASCII") ) );
+ return TRUE;
+ }
+
+ function _settype($mode=FTP_ASCII) {
+ if($this->_ready) {
+ if($mode==FTP_BINARY) {
+ if($this->_curtype!=FTP_BINARY) {
+ if(!$this->_exec("TYPE I", "SetType")) return FALSE;
+ $this->_curtype=FTP_BINARY;
+ }
+ } elseif($this->_curtype!=FTP_ASCII) {
+ if(!$this->_exec("TYPE A", "SetType")) return FALSE;
+ $this->_curtype=FTP_ASCII;
+ }
+ } else return FALSE;
+ return TRUE;
+ }
+
+ function Passive($pasv=NULL) {
+ if(is_null($pasv)) $this->_passive=!$this->_passive;
+ else $this->_passive=$pasv;
+ if(!$this->_port_available and !$this->_passive) {
+ $this->SendMSG("Only passive connections available!");
+ $this->_passive=TRUE;
+ return FALSE;
+ }
+ $this->SendMSG("Passive mode ".($this->_passive?"on":"off"));
+ return TRUE;
+ }
+
+ function SetServer($host, $port=21, $reconnect=true) {
+ if(!is_long($port)) {
+ $this->verbose=true;
+ $this->SendMSG("Incorrect port syntax");
+ return FALSE;
+ } else {
+ $ip=@gethostbyname($host);
+ $dns=@gethostbyaddr($host);
+ if(!$ip) $ip=$host;
+ if(!$dns) $dns=$host;
+ // Validate the IPAddress PHP4 returns -1 for invalid, PHP5 false
+ // -1 === "255.255.255.255" which is the broadcast address which is also going to be invalid
+ $ipaslong = ip2long($ip);
+ if ( ($ipaslong == false) || ($ipaslong === -1) ) {
+ $this->SendMSG("Wrong host name/address \"".$host."\"");
+ return FALSE;
+ }
+ $this->_host=$ip;
+ $this->_fullhost=$dns;
+ $this->_port=$port;
+ $this->_dataport=$port-1;
+ }
+ $this->SendMSG("Host \"".$this->_fullhost."(".$this->_host."):".$this->_port."\"");
+ if($reconnect){
+ if($this->_connected) {
+ $this->SendMSG("Reconnecting");
+ if(!$this->quit(FTP_FORCE)) return FALSE;
+ if(!$this->connect()) return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ function SetUmask($umask=0022) {
+ $this->_umask=$umask;
+ umask($this->_umask);
+ $this->SendMSG("UMASK 0".decoct($this->_umask));
+ return TRUE;
+ }
+
+ function SetTimeout($timeout=30) {
+ $this->_timeout=$timeout;
+ $this->SendMSG("Timeout ".$this->_timeout);
+ if($this->_connected)
+ if(!$this->_settimeout($this->_ftp_control_sock)) return FALSE;
+ return TRUE;
+ }
+
+ function connect($server=NULL) {
+ if(!empty($server)) {
+ if(!$this->SetServer($server)) return false;
+ }
+ if($this->_ready) return true;
+ $this->SendMsg('Local OS : '.$this->OS_FullName[$this->OS_local]);
+ if(!($this->_ftp_control_sock = $this->_connect($this->_host, $this->_port))) {
+ $this->SendMSG("Error : Cannot connect to remote host \"".$this->_fullhost." :".$this->_port."\"");
+ return FALSE;
+ }
+ $this->SendMSG("Connected to remote host \"".$this->_fullhost.":".$this->_port."\". Waiting for greeting.");
+ do {
+ if(!$this->_readmsg()) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ $this->_lastaction=time();
+ } while($this->_code<200);
+ $this->_ready=true;
+ $syst=$this->systype();
+ if(!$syst) $this->SendMSG("Can't detect remote OS");
+ else {
+ if(preg_match("/win|dos|novell/i", $syst[0])) $this->OS_remote=FTP_OS_Windows;
+ elseif(preg_match("/os/i", $syst[0])) $this->OS_remote=FTP_OS_Mac;
+ elseif(preg_match("/(li|u)nix/i", $syst[0])) $this->OS_remote=FTP_OS_Unix;
+ else $this->OS_remote=FTP_OS_Mac;
+ $this->SendMSG("Remote OS: ".$this->OS_FullName[$this->OS_remote]);
+ }
+ if(!$this->features()) $this->SendMSG("Can't get features list. All supported - disabled");
+ else $this->SendMSG("Supported features: ".implode(", ", array_keys($this->_features)));
+ return TRUE;
+ }
+
+ function quit($force=false) {
+ if($this->_ready) {
+ if(!$this->_exec("QUIT") and !$force) return FALSE;
+ if(!$this->_checkCode() and !$force) return FALSE;
+ $this->_ready=false;
+ $this->SendMSG("Session finished");
+ }
+ $this->_quit();
+ return TRUE;
+ }
+
+ function login($user=NULL, $pass=NULL) {
+ if(!is_null($user)) $this->_login=$user;
+ else $this->_login="anonymous";
+ if(!is_null($pass)) $this->_password=$pass;
+ else $this->_password="anon@anon.com";
+ if(!$this->_exec("USER ".$this->_login, "login")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ if($this->_code!=230) {
+ if(!$this->_exec((($this->_code==331)?"PASS ":"ACCT ").$this->_password, "login")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ }
+ $this->SendMSG("Authentication succeeded");
+ if(empty($this->_features)) {
+ if(!$this->features()) $this->SendMSG("Can't get features list. All supported - disabled");
+ else $this->SendMSG("Supported features: ".implode(", ", array_keys($this->_features)));
+ }
+ return TRUE;
+ }
+
+ function pwd() {
+ if(!$this->_exec("PWD", "pwd")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return ereg_replace("^[0-9]{3} \"(.+)\".+", "\\1", $this->_message);
+ }
+
+ function cdup() {
+ if(!$this->_exec("CDUP", "cdup")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return true;
+ }
+
+ function chdir($pathname) {
+ if(!$this->_exec("CWD ".$pathname, "chdir")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return TRUE;
+ }
+
+ function rmdir($pathname) {
+ if(!$this->_exec("RMD ".$pathname, "rmdir")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return TRUE;
+ }
+
+ function mkdir($pathname) {
+ if(!$this->_exec("MKD ".$pathname, "mkdir")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return TRUE;
+ }
+
+ function rename($from, $to) {
+ if(!$this->_exec("RNFR ".$from, "rename")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ if($this->_code==350) {
+ if(!$this->_exec("RNTO ".$to, "rename")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ } else return FALSE;
+ return TRUE;
+ }
+
+ function filesize($pathname) {
+ if(!isset($this->_features["SIZE"])) {
+ $this->PushError("filesize", "not supported by server");
+ return FALSE;
+ }
+ if(!$this->_exec("SIZE ".$pathname, "filesize")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return ereg_replace("^[0-9]{3} ([0-9]+)".CRLF, "\\1", $this->_message);
+ }
+
+ function abort() {
+ if(!$this->_exec("ABOR", "abort")) return FALSE;
+ if(!$this->_checkCode()) {
+ if($this->_code!=426) return FALSE;
+ if(!$this->_readmsg("abort")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ }
+ return true;
+ }
+
+ function mdtm($pathname) {
+ if(!isset($this->_features["MDTM"])) {
+ $this->PushError("mdtm", "not supported by server");
+ return FALSE;
+ }
+ if(!$this->_exec("MDTM ".$pathname, "mdtm")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ $mdtm = ereg_replace("^[0-9]{3} ([0-9]+)".CRLF, "\\1", $this->_message);
+ $date = sscanf($mdtm, "%4d%2d%2d%2d%2d%2d");
+ $timestamp = mktime($date[3], $date[4], $date[5], $date[1], $date[2], $date[0]);
+ return $timestamp;
+ }
+
+ function systype() {
+ if(!$this->_exec("SYST", "systype")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ $DATA = explode(" ", $this->_message);
+ return array($DATA[1], $DATA[3]);
+ }
+
+ function delete($pathname) {
+ if(!$this->_exec("DELE ".$pathname, "delete")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return TRUE;
+ }
+
+ function site($command, $fnction="site") {
+ if(!$this->_exec("SITE ".$command, $fnction)) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return TRUE;
+ }
+
+ function chmod($pathname, $mode) {
+ if(!$this->site( sprintf('CHMOD %o %s', $mode, $pathname), "chmod")) return FALSE;
+ return TRUE;
+ }
+
+ function restore($from) {
+ if(!isset($this->_features["REST"])) {
+ $this->PushError("restore", "not supported by server");
+ return FALSE;
+ }
+ if($this->_curtype!=FTP_BINARY) {
+ $this->PushError("restore", "can't restore in ASCII mode");
+ return FALSE;
+ }
+ if(!$this->_exec("REST ".$from, "resore")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return TRUE;
+ }
+
+ function features() {
+ if(!$this->_exec("FEAT", "features")) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ $f=preg_split("/[".CRLF."]+/", preg_replace("/[0-9]{3}[ -].*[".CRLF."]+/", "", $this->_message), -1, PREG_SPLIT_NO_EMPTY);
+ $this->_features=array();
+ foreach($f as $k=>$v) {
+ $v=explode(" ", trim($v));
+ $this->_features[array_shift($v)]=$v;
+ }
+ return true;
+ }
+
+ function rawlist($pathname="", $arg="") {
+ return $this->_list(($arg?" ".$arg:"").($pathname?" ".$pathname:""), "LIST", "rawlist");
+ }
+
+ function nlist($pathname="") {
+ return $this->_list(($arg?" ".$arg:"").($pathname?" ".$pathname:""), "NLST", "nlist");
+ }
+
+ function is_exists($pathname) {
+ return $this->file_exists($pathname);
+ }
+
+ function file_exists($pathname) {
+ $exists=true;
+ if(!$this->_exec("RNFR ".$pathname, "rename")) $exists=FALSE;
+ else {
+ if(!$this->_checkCode()) $exists=FALSE;
+ $this->abort();
+ }
+ if($exists) $this->SendMSG("Remote file ".$pathname." exists");
+ else $this->SendMSG("Remote file ".$pathname." does not exist");
+ return $exists;
+ }
+
+ function fget($fp, $remotefile,$rest=0) {
+ if($this->_can_restore and $rest!=0) fseek($fp, $rest);
+ $pi=pathinfo($remotefile);
+ if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
+ else $mode=FTP_BINARY;
+ if(!$this->_data_prepare($mode)) {
+ return FALSE;
+ }
+ if($this->_can_restore and $rest!=0) $this->restore($rest);
+ if(!$this->_exec("RETR ".$remotefile, "get")) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ return FALSE;
+ }
+ $out=$this->_data_read($mode, $fp);
+ $this->_data_close();
+ if(!$this->_readmsg()) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return $out;
+ }
+
+ function get($remotefile, $localfile=NULL, $rest=0) {
+ if(is_null($localfile)) $localfile=$remotefile;
+ if (@file_exists($localfile)) $this->SendMSG("Warning : local file will be overwritten");
+ $fp = @fopen($localfile, "w");
+ if (!$fp) {
+ $this->PushError("get","can't open local file", "Cannot create \"".$localfile."\"");
+ return FALSE;
+ }
+ if($this->_can_restore and $rest!=0) fseek($fp, $rest);
+ $pi=pathinfo($remotefile);
+ if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
+ else $mode=FTP_BINARY;
+ if(!$this->_data_prepare($mode)) {
+ fclose($fp);
+ return FALSE;
+ }
+ if($this->_can_restore and $rest!=0) $this->restore($rest);
+ if(!$this->_exec("RETR ".$remotefile, "get")) {
+ $this->_data_close();
+ fclose($fp);
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ fclose($fp);
+ return FALSE;
+ }
+ $out=$this->_data_read($mode, $fp);
+ fclose($fp);
+ $this->_data_close();
+ if(!$this->_readmsg()) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return $out;
+ }
+
+ function fput($remotefile, $fp) {
+ if($this->_can_restore and $rest!=0) fseek($fp, $rest);
+ $pi=pathinfo($remotefile);
+ if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
+ else $mode=FTP_BINARY;
+ if(!$this->_data_prepare($mode)) {
+ return FALSE;
+ }
+ if($this->_can_restore and $rest!=0) $this->restore($rest);
+ if(!$this->_exec("STOR ".$remotefile, "put")) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ return FALSE;
+ }
+ $ret=$this->_data_write($mode, $fp);
+ $this->_data_close();
+ if(!$this->_readmsg()) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return $ret;
+ }
+
+ function put($localfile, $remotefile=NULL, $rest=0) {
+ if(is_null($remotefile)) $remotefile=$localfile;
+ if (!file_exists($localfile)) {
+ $this->PushError("put","can't open local file", "No such file or directory \"".$localfile."\"");
+ return FALSE;
+ }
+ $fp = @fopen($localfile, "r");
+
+ if (!$fp) {
+ $this->PushError("put","can't open local file", "Cannot read file \"".$localfile."\"");
+ return FALSE;
+ }
+ if($this->_can_restore and $rest!=0) fseek($fp, $rest);
+ $pi=pathinfo($localfile);
+ if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
+ else $mode=FTP_BINARY;
+ if(!$this->_data_prepare($mode)) {
+ fclose($fp);
+ return FALSE;
+ }
+ if($this->_can_restore and $rest!=0) $this->restore($rest);
+ if(!$this->_exec("STOR ".$remotefile, "put")) {
+ $this->_data_close();
+ fclose($fp);
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ fclose($fp);
+ return FALSE;
+ }
+ $ret=$this->_data_write($mode, $fp);
+ fclose($fp);
+ $this->_data_close();
+ if(!$this->_readmsg()) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ return $ret;
+ }
+
+ function mput($local=".", $remote=NULL, $continious=false) {
+ $local=realpath($local);
+ if(!@file_exists($local)) {
+ $this->PushError("mput","can't open local folder", "Cannot stat folder \"".$local."\"");
+ return FALSE;
+ }
+ if(!is_dir($local)) return $this->put($local, $remote);
+ if(empty($remote)) $remote=".";
+ elseif(!$this->file_exists($remote) and !$this->mkdir($remote)) return FALSE;
+ if($handle = opendir($local)) {
+ $list=array();
+ while (false !== ($file = readdir($handle))) {
+ if ($file != "." && $file != "..") $list[]=$file;
+ }
+ closedir($handle);
+ } else {
+ $this->PushError("mput","can't open local folder", "Cannot read folder \"".$local."\"");
+ return FALSE;
+ }
+ if(empty($list)) return TRUE;
+ $ret=true;
+ foreach($list as $el) {
+ if(is_dir($local."/".$el)) $t=$this->mput($local."/".$el, $remote."/".$el);
+ else $t=$this->put($local."/".$el, $remote."/".$el);
+ if(!$t) {
+ $ret=FALSE;
+ if(!$continious) break;
+ }
+ }
+ return $ret;
+
+ }
+
+ function mget($remote, $local=".", $continious=false) {
+ $list=$this->rawlist($remote, "-lA");
+ if($list===false) {
+ $this->PushError("mget","can't read remote folder list", "Can't read remote folder \"".$remote."\" contents");
+ return FALSE;
+ }
+ if(empty($list)) return true;
+ if(!@file_exists($local)) {
+ if(!@mkdir($local)) {
+ $this->PushError("mget","can't create local folder", "Cannot create folder \"".$local."\"");
+ return FALSE;
+ }
+ }
+ foreach($list as $k=>$v) {
+ $list[$k]=$this->parselisting($v);
+ if($list[$k]["name"]=="." or $list[$k]["name"]=="..") unset($list[$k]);
+ }
+ $ret=true;
+ foreach($list as $el) {
+ if($el["type"]=="d") {
+ if(!$this->mget($remote."/".$el["name"], $local."/".$el["name"], $continious)) {
+ $this->PushError("mget", "can't copy folder", "Can't copy remote folder \"".$remote."/".$el["name"]."\" to local \"".$local."/".$el["name"]."\"");
+ $ret=false;
+ if(!$continious) break;
+ }
+ } else {
+ if(!$this->get($remote."/".$el["name"], $local."/".$el["name"])) {
+ $this->PushError("mget", "can't copy file", "Can't copy remote file \"".$remote."/".$el["name"]."\" to local \"".$local."/".$el["name"]."\"");
+ $ret=false;
+ if(!$continious) break;
+ }
+ }
+ @chmod($local."/".$el["name"], $el["perms"]);
+ $t=strtotime($el["date"]);
+ if($t!==-1 and $t!==false) @touch($local."/".$el["name"], $t);
+ }
+ return $ret;
+ }
+
+ function mdel($remote, $continious=false) {
+ $list=$this->rawlist($remote, "-la");
+ if($list===false) {
+ $this->PushError("mdel","can't read remote folder list", "Can't read remote folder \"".$remote."\" contents");
+ return false;
+ }
+
+ foreach($list as $k=>$v) {
+ $list[$k]=$this->parselisting($v);
+ if($list[$k]["name"]=="." or $list[$k]["name"]=="..") unset($list[$k]);
+ }
+ $ret=true;
+
+ foreach($list as $el) {
+ if ( empty($el) )
+ continue;
+
+ if($el["type"]=="d") {
+ if(!$this->mdel($remote."/".$el["name"], $continious)) {
+ $ret=false;
+ if(!$continious) break;
+ }
+ } else {
+ if (!$this->delete($remote."/".$el["name"])) {
+ $this->PushError("mdel", "can't delete file", "Can't delete remote file \"".$remote."/".$el["name"]."\"");
+ $ret=false;
+ if(!$continious) break;
+ }
+ }
+ }
+
+ if(!$this->rmdir($remote)) {
+ $this->PushError("mdel", "can't delete folder", "Can't delete remote folder \"".$remote."/".$el["name"]."\"");
+ $ret=false;
+ }
+ return $ret;
+ }
+
+ function mmkdir($dir, $mode = 0777) {
+ if(empty($dir)) return FALSE;
+ if($this->is_exists($dir) or $dir == "/" ) return TRUE;
+ if(!$this->mmkdir(dirname($dir), $mode)) return false;
+ $r=$this->mkdir($dir, $mode);
+ $this->chmod($dir,$mode);
+ return $r;
+ }
+
+ function glob($pattern, $handle=NULL) {
+ $path=$output=null;
+ if(PHP_OS=='WIN32') $slash='\\';
+ else $slash='/';
+ $lastpos=strrpos($pattern,$slash);
+ if(!($lastpos===false)) {
+ $path=substr($pattern,0,-$lastpos-1);
+ $pattern=substr($pattern,$lastpos);
+ } else $path=getcwd();
+ if(is_array($handle) and !empty($handle)) {
+ while($dir=each($handle)) {
+ if($this->glob_pattern_match($pattern,$dir))
+ $output[]=$dir;
+ }
+ } else {
+ $handle=@opendir($path);
+ if($handle===false) return false;
+ while($dir=readdir($handle)) {
+ if($this->glob_pattern_match($pattern,$dir))
+ $output[]=$dir;
+ }
+ closedir($handle);
+ }
+ if(is_array($output)) return $output;
+ return false;
+ }
+
+ function glob_pattern_match($pattern,$string) {
+ $out=null;
+ $chunks=explode(';',$pattern);
+ foreach($chunks as $pattern) {
+ $escape=array('$','^','.','{','}','(',')','[',']','|');
+ while(strpos($pattern,'**')!==false)
+ $pattern=str_replace('**','*',$pattern);
+ foreach($escape as $probe)
+ $pattern=str_replace($probe,"\\$probe",$pattern);
+ $pattern=str_replace('?*','*',
+ str_replace('*?','*',
+ str_replace('*',".*",
+ str_replace('?','.{1,1}',$pattern))));
+ $out[]=$pattern;
+ }
+ if(count($out)==1) return($this->glob_regexp("^$out[0]$",$string));
+ else {
+ foreach($out as $tester)
+ if($this->my_regexp("^$tester$",$string)) return true;
+ }
+ return false;
+ }
+
+ function glob_regexp($pattern,$probe) {
+ $sensitive=(PHP_OS!='WIN32');
+ return ($sensitive?
+ ereg($pattern,$probe):
+ eregi($pattern,$probe)
+ );
+ }
+
+ function dirlist($remote) {
+ $list=$this->rawlist($remote, "-la");
+ if($list===false) {
+ $this->PushError("dirlist","can't read remote folder list", "Can't read remote folder \"".$remote."\" contents");
+ return false;
+ }
+
+ $dirlist = array();
+ foreach($list as $k=>$v) {
+ $entry=$this->parselisting($v);
+ if ( empty($entry) )
+ continue;
+
+ if($entry["name"]=="." or $entry["name"]=="..")
+ continue;
+
+ $dirlist[$entry['name']] = $entry;
+ }
+
+ return $dirlist;
+ }
+// <!-- --------------------------------------------------------------------------------------- -->
+// <!-- Private functions -->
+// <!-- --------------------------------------------------------------------------------------- -->
+ function _checkCode() {
+ return ($this->_code<400 and $this->_code>0);
+ }
+
+ function _list($arg="", $cmd="LIST", $fnction="_list") {
+ if(!$this->_data_prepare()) return false;
+ if(!$this->_exec($cmd.$arg, $fnction)) {
+ $this->_data_close();
+ return FALSE;
+ }
+ if(!$this->_checkCode()) {
+ $this->_data_close();
+ return FALSE;
+ }
+ $out="";
+ if($this->_code<200) {
+ $out=$this->_data_read();
+ $this->_data_close();
+ if(!$this->_readmsg()) return FALSE;
+ if(!$this->_checkCode()) return FALSE;
+ if($out === FALSE ) return FALSE;
+ $out=preg_split("/[".CRLF."]+/", $out, -1, PREG_SPLIT_NO_EMPTY);
+// $this->SendMSG(implode($this->_eol_code[$this->OS_local], $out));
+ }
+ return $out;
+ }
+
+// <!-- --------------------------------------------------------------------------------------- -->
+// <!-- Partie : gestion des erreurs -->
+// <!-- --------------------------------------------------------------------------------------- -->
+// Gnre une erreur pour traitement externe la classe
+ function PushError($fctname,$msg,$desc=false){
+ $error=array();
+ $error['time']=time();
+ $error['fctname']=$fctname;
+ $error['msg']=$msg;
+ $error['desc']=$desc;
+ if($desc) $tmp=' ('.$desc.')'; else $tmp='';
+ $this->SendMSG($fctname.': '.$msg.$tmp);
+ return(array_push($this->_error_array,$error));
+ }
+
+// Rcupre une erreur externe
+ function PopError(){
+ if(count($this->_error_array)) return(array_pop($this->_error_array));
+ else return(false);
+ }
+}
+
+$mod_sockets = extension_loaded( 'sockets' );
+if ( ! $mod_sockets && function_exists( 'dl' ) && is_callable( 'dl' ) ) {
+ $prefix = ( PHP_SHLIB_SUFFIX == 'dll' ) ? 'php_' : '';
+ @dl( $prefix . 'sockets.' . PHP_SHLIB_SUFFIX );
+ $mod_sockets = extension_loaded( 'sockets' );
+}
+
+require_once "class-ftp-" . ( $mod_sockets ? "sockets" : "pure" ) . ".php";
+?>
diff --git a/src/wp-admin/includes/class-pclzip.php b/src/wp-admin/includes/class-pclzip.php
new file mode 100644
index 0000000000..5e6a619bc2
--- /dev/null
+++ b/src/wp-admin/includes/class-pclzip.php
@@ -0,0 +1,5687 @@
+<?php
+// --------------------------------------------------------------------------------
+// PhpConcept Library - Zip Module 2.8.2
+// --------------------------------------------------------------------------------
+// License GNU/LGPL - Vincent Blavet - August 2009
+// http://www.phpconcept.net
+// --------------------------------------------------------------------------------
+//
+// Presentation :
+// PclZip is a PHP library that manage ZIP archives.
+// So far tests show that archives generated by PclZip are readable by
+// WinZip application and other tools.
+//
+// Description :
+// See readme.txt and http://www.phpconcept.net
+//
+// Warning :
+// This library and the associated files are non commercial, non professional
+// work.
+// It should not have unexpected results. However if any damage is caused by
+// this software the author can not be responsible.
+// The use of this software is at the risk of the user.
+//
+// --------------------------------------------------------------------------------
+// $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
+// --------------------------------------------------------------------------------
+
+ // ----- Constants
+ if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
+ define( 'PCLZIP_READ_BLOCK_SIZE', 2048 );
+ }
+
+ // ----- File list separator
+ // In version 1.x of PclZip, the separator for file list is a space
+ // (which is not a very smart choice, specifically for windows paths !).
+ // A better separator should be a comma (,). This constant gives you the
+ // abilty to change that.
+ // However notice that changing this value, may have impact on existing
+ // scripts, using space separated filenames.
+ // Recommanded values for compatibility with older versions :
+ //define( 'PCLZIP_SEPARATOR', ' ' );
+ // Recommanded values for smart separation of filenames.
+ if (!defined('PCLZIP_SEPARATOR')) {
+ define( 'PCLZIP_SEPARATOR', ',' );
+ }
+
+ // ----- Error configuration
+ // 0 : PclZip Class integrated error handling
+ // 1 : PclError external library error handling. By enabling this
+ // you must ensure that you have included PclError library.
+ // [2,...] : reserved for futur use
+ if (!defined('PCLZIP_ERROR_EXTERNAL')) {
+ define( 'PCLZIP_ERROR_EXTERNAL', 0 );
+ }
+
+ // ----- Optional static temporary directory
+ // By default temporary files are generated in the script current
+ // path.
+ // If defined :
+ // - MUST BE terminated by a '/'.
+ // - MUST be a valid, already created directory
+ // Samples :
+ // define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );
+ // define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );
+ if (!defined('PCLZIP_TEMPORARY_DIR')) {
+ define( 'PCLZIP_TEMPORARY_DIR', '' );
+ }
+
+ // ----- Optional threshold ratio for use of temporary files
+ // Pclzip sense the size of the file to add/extract and decide to
+ // use or not temporary file. The algorythm is looking for
+ // memory_limit of PHP and apply a ratio.
+ // threshold = memory_limit * ratio.
+ // Recommended values are under 0.5. Default 0.47.
+ // Samples :
+ // define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );
+ if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
+ define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.47 );
+ }
+
+// --------------------------------------------------------------------------------
+// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
+// --------------------------------------------------------------------------------
+
+ // ----- Global variables
+ $g_pclzip_version = "2.8.2";
+
+ // ----- Error codes
+ // -1 : Unable to open file in binary write mode
+ // -2 : Unable to open file in binary read mode
+ // -3 : Invalid parameters
+ // -4 : File does not exist
+ // -5 : Filename is too long (max. 255)
+ // -6 : Not a valid zip file
+ // -7 : Invalid extracted file size
+ // -8 : Unable to create directory
+ // -9 : Invalid archive extension
+ // -10 : Invalid archive format
+ // -11 : Unable to delete file (unlink)
+ // -12 : Unable to rename file (rename)
+ // -13 : Invalid header checksum
+ // -14 : Invalid archive size
+ define( 'PCLZIP_ERR_USER_ABORTED', 2 );
+ define( 'PCLZIP_ERR_NO_ERROR', 0 );
+ define( 'PCLZIP_ERR_WRITE_OPEN_FAIL', -1 );
+ define( 'PCLZIP_ERR_READ_OPEN_FAIL', -2 );
+ define( 'PCLZIP_ERR_INVALID_PARAMETER', -3 );
+ define( 'PCLZIP_ERR_MISSING_FILE', -4 );
+ define( 'PCLZIP_ERR_FILENAME_TOO_LONG', -5 );
+ define( 'PCLZIP_ERR_INVALID_ZIP', -6 );
+ define( 'PCLZIP_ERR_BAD_EXTRACTED_FILE', -7 );
+ define( 'PCLZIP_ERR_DIR_CREATE_FAIL', -8 );
+ define( 'PCLZIP_ERR_BAD_EXTENSION', -9 );
+ define( 'PCLZIP_ERR_BAD_FORMAT', -10 );
+ define( 'PCLZIP_ERR_DELETE_FILE_FAIL', -11 );
+ define( 'PCLZIP_ERR_RENAME_FILE_FAIL', -12 );
+ define( 'PCLZIP_ERR_BAD_CHECKSUM', -13 );
+ define( 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14 );
+ define( 'PCLZIP_ERR_MISSING_OPTION_VALUE', -15 );
+ define( 'PCLZIP_ERR_INVALID_OPTION_VALUE', -16 );
+ define( 'PCLZIP_ERR_ALREADY_A_DIRECTORY', -17 );
+ define( 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18 );
+ define( 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19 );
+ define( 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20 );
+ define( 'PCLZIP_ERR_DIRECTORY_RESTRICTION', -21 );
+
+ // ----- Options values
+ define( 'PCLZIP_OPT_PATH', 77001 );
+ define( 'PCLZIP_OPT_ADD_PATH', 77002 );
+ define( 'PCLZIP_OPT_REMOVE_PATH', 77003 );
+ define( 'PCLZIP_OPT_REMOVE_ALL_PATH', 77004 );
+ define( 'PCLZIP_OPT_SET_CHMOD', 77005 );
+ define( 'PCLZIP_OPT_EXTRACT_AS_STRING', 77006 );
+ define( 'PCLZIP_OPT_NO_COMPRESSION', 77007 );
+ define( 'PCLZIP_OPT_BY_NAME', 77008 );
+ define( 'PCLZIP_OPT_BY_INDEX', 77009 );
+ define( 'PCLZIP_OPT_BY_EREG', 77010 );
+ define( 'PCLZIP_OPT_BY_PREG', 77011 );
+ define( 'PCLZIP_OPT_COMMENT', 77012 );
+ define( 'PCLZIP_OPT_ADD_COMMENT', 77013 );
+ define( 'PCLZIP_OPT_PREPEND_COMMENT', 77014 );
+ define( 'PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015 );
+ define( 'PCLZIP_OPT_REPLACE_NEWER', 77016 );
+ define( 'PCLZIP_OPT_STOP_ON_ERROR', 77017 );
+ // Having big trouble with crypt. Need to multiply 2 long int
+ // which is not correctly supported by PHP ...
+ //define( 'PCLZIP_OPT_CRYPT', 77018 );
+ define( 'PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019 );
+ define( 'PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020 );
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020 ); // alias
+ define( 'PCLZIP_OPT_TEMP_FILE_ON', 77021 );
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021 ); // alias
+ define( 'PCLZIP_OPT_TEMP_FILE_OFF', 77022 );
+ define( 'PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022 ); // alias
+
+ // ----- File description attributes
+ define( 'PCLZIP_ATT_FILE_NAME', 79001 );
+ define( 'PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002 );
+ define( 'PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003 );
+ define( 'PCLZIP_ATT_FILE_MTIME', 79004 );
+ define( 'PCLZIP_ATT_FILE_CONTENT', 79005 );
+ define( 'PCLZIP_ATT_FILE_COMMENT', 79006 );
+
+ // ----- Call backs values
+ define( 'PCLZIP_CB_PRE_EXTRACT', 78001 );
+ define( 'PCLZIP_CB_POST_EXTRACT', 78002 );
+ define( 'PCLZIP_CB_PRE_ADD', 78003 );
+ define( 'PCLZIP_CB_POST_ADD', 78004 );
+ /* For futur use
+ define( 'PCLZIP_CB_PRE_LIST', 78005 );
+ define( 'PCLZIP_CB_POST_LIST', 78006 );
+ define( 'PCLZIP_CB_PRE_DELETE', 78007 );
+ define( 'PCLZIP_CB_POST_DELETE', 78008 );
+ */
+
+ // --------------------------------------------------------------------------------
+ // Class : PclZip
+ // Description :
+ // PclZip is the class that represent a Zip archive.
+ // The public methods allow the manipulation of the archive.
+ // Attributes :
+ // Attributes must not be accessed directly.
+ // Methods :
+ // PclZip() : Object creator
+ // create() : Creates the Zip archive
+ // listContent() : List the content of the Zip archive
+ // extract() : Extract the content of the archive
+ // properties() : List the properties of the archive
+ // --------------------------------------------------------------------------------
+ class PclZip
+ {
+ // ----- Filename of the zip file
+ var $zipname = '';
+
+ // ----- File descriptor of the zip file
+ var $zip_fd = 0;
+
+ // ----- Internal error handling
+ var $error_code = 1;
+ var $error_string = '';
+
+ // ----- Current status of the magic_quotes_runtime
+ // This value store the php configuration for magic_quotes
+ // The class can then disable the magic_quotes and reset it after
+ var $magic_quotes_status;
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZip()
+ // Description :
+ // Creates a PclZip object and set the name of the associated Zip archive
+ // filename.
+ // Note that no real action is taken, if the archive does not exist it is not
+ // created. Use create() for that.
+ // --------------------------------------------------------------------------------
+ function PclZip($p_zipname)
+ {
+
+ // ----- Tests the zlib
+ if (!function_exists('gzopen'))
+ {
+ die('Abort '.basename(__FILE__).' : Missing zlib extensions');
+ }
+
+ // ----- Set the attributes
+ $this->zipname = $p_zipname;
+ $this->zip_fd = 0;
+ $this->magic_quotes_status = -1;
+
+ // ----- Return
+ return;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // create($p_filelist, $p_add_dir="", $p_remove_dir="")
+ // create($p_filelist, $p_option, $p_option_value, ...)
+ // Description :
+ // This method supports two different synopsis. The first one is historical.
+ // This method creates a Zip Archive. The Zip file is created in the
+ // filesystem. The files and directories indicated in $p_filelist
+ // are added in the archive. See the parameters description for the
+ // supported format of $p_filelist.
+ // When a directory is in the list, the directory and its content is added
+ // in the archive.
+ // In this synopsis, the function takes an optional variable list of
+ // options. See bellow the supported options.
+ // Parameters :
+ // $p_filelist : An array containing file or directory names, or
+ // a string containing one filename or one directory name, or
+ // a string containing a list of filenames and/or directory
+ // names separated by spaces.
+ // $p_add_dir : A path to add before the real path of the archived file,
+ // in order to have it memorized in the archive.
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
+ // in order to have a shorter path memorized in the archive.
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+ // is removed first, before $p_add_dir is added.
+ // Options :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_COMMENT :
+ // PCLZIP_CB_PRE_ADD :
+ // PCLZIP_CB_POST_ADD :
+ // Return Values :
+ // 0 on failure,
+ // The list of the added files, with a status of the add action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function create($p_filelist)
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Set default values
+ $v_options = array();
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove from the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_ADD => 'optional',
+ PCLZIP_CB_POST_ADD => 'optional',
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
+ PCLZIP_OPT_COMMENT => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ //, PCLZIP_OPT_CRYPT => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+ "Invalid number / type of arguments");
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Init
+ $v_string_list = array();
+ $v_att_list = array();
+ $v_filedescr_list = array();
+ $p_result_list = array();
+
+ // ----- Look if the $p_filelist is really an array
+ if (is_array($p_filelist)) {
+
+ // ----- Look if the first element is also an array
+ // This will mean that this is a file description entry
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+ $v_att_list = $p_filelist;
+ }
+
+ // ----- The list is a list of string names
+ else {
+ $v_string_list = $p_filelist;
+ }
+ }
+
+ // ----- Look if the $p_filelist is a string
+ else if (is_string($p_filelist)) {
+ // ----- Create a list from the string
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+ }
+
+ // ----- Invalid variable type for $p_filelist
+ else {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
+ return 0;
+ }
+
+ // ----- Reformat the string list
+ if (sizeof($v_string_list) != 0) {
+ foreach ($v_string_list as $v_string) {
+ if ($v_string != '') {
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+ }
+ else {
+ }
+ }
+ }
+
+ // ----- For each file in the list check the attributes
+ $v_supported_attributes
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
+ );
+ foreach ($v_att_list as $v_entry) {
+ $v_result = $this->privFileDescrParseAtt($v_entry,
+ $v_filedescr_list[],
+ $v_options,
+ $v_supported_attributes);
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Expand the filelist (expand directories)
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Call the create fct
+ $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Return
+ return $p_result_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // add($p_filelist, $p_add_dir="", $p_remove_dir="")
+ // add($p_filelist, $p_option, $p_option_value, ...)
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This methods add the list of files in an existing archive.
+ // If a file with the same name already exists, it is added at the end of the
+ // archive, the first one is still present.
+ // If the archive does not exist, it is created.
+ // Parameters :
+ // $p_filelist : An array containing file or directory names, or
+ // a string containing one filename or one directory name, or
+ // a string containing a list of filenames and/or directory
+ // names separated by spaces.
+ // $p_add_dir : A path to add before the real path of the archived file,
+ // in order to have it memorized in the archive.
+ // $p_remove_dir : A path to remove from the real path of the file to archive,
+ // in order to have a shorter path memorized in the archive.
+ // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
+ // is removed first, before $p_add_dir is added.
+ // Options :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_COMMENT :
+ // PCLZIP_OPT_ADD_COMMENT :
+ // PCLZIP_OPT_PREPEND_COMMENT :
+ // PCLZIP_CB_PRE_ADD :
+ // PCLZIP_CB_POST_ADD :
+ // Return Values :
+ // 0 on failure,
+ // The list of the added files, with a status of the add action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function add($p_filelist)
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Set default values
+ $v_options = array();
+ $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove form the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_ADD => 'optional',
+ PCLZIP_CB_POST_ADD => 'optional',
+ PCLZIP_OPT_NO_COMPRESSION => 'optional',
+ PCLZIP_OPT_COMMENT => 'optional',
+ PCLZIP_OPT_ADD_COMMENT => 'optional',
+ PCLZIP_OPT_PREPEND_COMMENT => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ //, PCLZIP_OPT_CRYPT => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Init
+ $v_string_list = array();
+ $v_att_list = array();
+ $v_filedescr_list = array();
+ $p_result_list = array();
+
+ // ----- Look if the $p_filelist is really an array
+ if (is_array($p_filelist)) {
+
+ // ----- Look if the first element is also an array
+ // This will mean that this is a file description entry
+ if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
+ $v_att_list = $p_filelist;
+ }
+
+ // ----- The list is a list of string names
+ else {
+ $v_string_list = $p_filelist;
+ }
+ }
+
+ // ----- Look if the $p_filelist is a string
+ else if (is_string($p_filelist)) {
+ // ----- Create a list from the string
+ $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
+ }
+
+ // ----- Invalid variable type for $p_filelist
+ else {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
+ return 0;
+ }
+
+ // ----- Reformat the string list
+ if (sizeof($v_string_list) != 0) {
+ foreach ($v_string_list as $v_string) {
+ $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
+ }
+ }
+
+ // ----- For each file in the list check the attributes
+ $v_supported_attributes
+ = array ( PCLZIP_ATT_FILE_NAME => 'mandatory'
+ ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional'
+ ,PCLZIP_ATT_FILE_MTIME => 'optional'
+ ,PCLZIP_ATT_FILE_CONTENT => 'optional'
+ ,PCLZIP_ATT_FILE_COMMENT => 'optional'
+ );
+ foreach ($v_att_list as $v_entry) {
+ $v_result = $this->privFileDescrParseAtt($v_entry,
+ $v_filedescr_list[],
+ $v_options,
+ $v_supported_attributes);
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Expand the filelist (expand directories)
+ $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Call the create fct
+ $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Return
+ return $p_result_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : listContent()
+ // Description :
+ // This public method, gives the list of the files and directories, with their
+ // properties.
+ // The properties of each entries in the list are (used also in other functions) :
+ // filename : Name of the file. For a create or add action it is the filename
+ // given by the user. For an extract function it is the filename
+ // of the extracted file.
+ // stored_filename : Name of the file / directory stored in the archive.
+ // size : Size of the stored file.
+ // compressed_size : Size of the file's data compressed in the archive
+ // (without the headers overhead)
+ // mtime : Last known modification date of the file (UNIX timestamp)
+ // comment : Comment associated with the file
+ // folder : true | false
+ // index : index of the file in the archive
+ // status : status of the action (depending of the action) :
+ // Values are :
+ // ok : OK !
+ // filtered : the file / dir is not extracted (filtered by user)
+ // already_a_directory : the file can not be extracted because a
+ // directory with the same name already exists
+ // write_protected : the file can not be extracted because a file
+ // with the same name already exists and is
+ // write protected
+ // newer_exist : the file was not extracted because a newer file exists
+ // path_creation_fail : the file is not extracted because the folder
+ // does not exist and can not be created
+ // write_error : the file was not extracted because there was a
+ // error while writing the file
+ // read_error : the file was not extracted because there was a error
+ // while reading the file
+ // invalid_header : the file was not extracted because of an archive
+ // format error (bad file header)
+ // Note that each time a method can continue operating when there
+ // is an action error on a file, the error is only logged in the file status.
+ // Return Values :
+ // 0 on an unrecoverable failure,
+ // The list of the files in the archive.
+ // --------------------------------------------------------------------------------
+ function listContent()
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Call the extracting fct
+ $p_list = array();
+ if (($v_result = $this->privList($p_list)) != 1)
+ {
+ unset($p_list);
+ return(0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // extract($p_path="./", $p_remove_path="")
+ // extract([$p_option, $p_option_value, ...])
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This method extract all the files / directories from the archive to the
+ // folder indicated in $p_path.
+ // If you want to ignore the 'root' part of path of the memorized files
+ // you can indicate this in the optional $p_remove_path parameter.
+ // By default, if a newer file with the same name already exists, the
+ // file is not extracted.
+ //
+ // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
+ // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
+ // at the end of the path value of PCLZIP_OPT_PATH.
+ // Parameters :
+ // $p_path : Path where the files and directories are to be extracted
+ // $p_remove_path : First part ('root' part) of the memorized path
+ // (if any similar) to remove while extracting.
+ // Options :
+ // PCLZIP_OPT_PATH :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_CB_PRE_EXTRACT :
+ // PCLZIP_CB_POST_EXTRACT :
+ // Return Values :
+ // 0 or a negative value on failure,
+ // The list of the extracted files, with a status of the action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function extract()
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+// $v_path = "./";
+ $v_path = '';
+ $v_remove_path = "";
+ $v_remove_all_path = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Default values for option
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+
+ // ----- Look for arguments
+ if ($v_size > 0) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
+ PCLZIP_CB_POST_EXTRACT => 'optional',
+ PCLZIP_OPT_SET_CHMOD => 'optional',
+ PCLZIP_OPT_BY_NAME => 'optional',
+ PCLZIP_OPT_BY_EREG => 'optional',
+ PCLZIP_OPT_BY_PREG => 'optional',
+ PCLZIP_OPT_BY_INDEX => 'optional',
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+ PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Set the arguments
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
+ $v_path = $v_options[PCLZIP_OPT_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+ // ----- Check for '/' in last path char
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+ $v_path .= '/';
+ }
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_remove_path = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Trace
+
+ // ----- Call the extracting fct
+ $p_list = array();
+ $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
+ $v_remove_all_path, $v_options);
+ if ($v_result < 1) {
+ unset($p_list);
+ return(0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // extractByIndex($p_index, $p_path="./", $p_remove_path="")
+ // extractByIndex($p_index, [$p_option, $p_option_value, ...])
+ // Description :
+ // This method supports two synopsis. The first one is historical.
+ // This method is doing a partial extract of the archive.
+ // The extracted files or folders are identified by their index in the
+ // archive (from 0 to n).
+ // Note that if the index identify a folder, only the folder entry is
+ // extracted, not all the files included in the archive.
+ // Parameters :
+ // $p_index : A single index (integer) or a string of indexes of files to
+ // extract. The form of the string is "0,4-6,8-12" with only numbers
+ // and '-' for range or ',' to separate ranges. No spaces or ';'
+ // are allowed.
+ // $p_path : Path where the files and directories are to be extracted
+ // $p_remove_path : First part ('root' part) of the memorized path
+ // (if any similar) to remove while extracting.
+ // Options :
+ // PCLZIP_OPT_PATH :
+ // PCLZIP_OPT_ADD_PATH :
+ // PCLZIP_OPT_REMOVE_PATH :
+ // PCLZIP_OPT_REMOVE_ALL_PATH :
+ // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
+ // not as files.
+ // The resulting content is in a new field 'content' in the file
+ // structure.
+ // This option must be used alone (any other options are ignored).
+ // PCLZIP_CB_PRE_EXTRACT :
+ // PCLZIP_CB_POST_EXTRACT :
+ // Return Values :
+ // 0 on failure,
+ // The list of the extracted files, with a status of the action.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ //function extractByIndex($p_index, options...)
+ function extractByIndex($p_index)
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+// $v_path = "./";
+ $v_path = '';
+ $v_remove_path = "";
+ $v_remove_all_path = false;
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Default values for option
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+
+ // ----- Look for arguments
+ if ($v_size > 1) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Remove form the options list the first argument
+ array_shift($v_arg_list);
+ $v_size--;
+
+ // ----- Look for first arg
+ if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_PATH => 'optional',
+ PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
+ PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
+ PCLZIP_OPT_ADD_PATH => 'optional',
+ PCLZIP_CB_PRE_EXTRACT => 'optional',
+ PCLZIP_CB_POST_EXTRACT => 'optional',
+ PCLZIP_OPT_SET_CHMOD => 'optional',
+ PCLZIP_OPT_REPLACE_NEWER => 'optional'
+ ,PCLZIP_OPT_STOP_ON_ERROR => 'optional'
+ ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
+ PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
+ PCLZIP_OPT_TEMP_FILE_ON => 'optional',
+ PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
+ ));
+ if ($v_result != 1) {
+ return 0;
+ }
+
+ // ----- Set the arguments
+ if (isset($v_options[PCLZIP_OPT_PATH])) {
+ $v_path = $v_options[PCLZIP_OPT_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
+ // ----- Check for '/' in last path char
+ if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
+ $v_path .= '/';
+ }
+ $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
+ }
+ if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
+ $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE;
+ }
+ else {
+ }
+ }
+
+ // ----- Look for 2 args
+ // Here we need to support the first historic synopsis of the
+ // method.
+ else {
+
+ // ----- Get the first argument
+ $v_path = $v_arg_list[0];
+
+ // ----- Look for the optional second argument
+ if ($v_size == 2) {
+ $v_remove_path = $v_arg_list[1];
+ }
+ else if ($v_size > 2) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
+
+ // ----- Return
+ return 0;
+ }
+ }
+ }
+
+ // ----- Trace
+
+ // ----- Trick
+ // Here I want to reuse extractByRule(), so I need to parse the $p_index
+ // with privParseOptions()
+ $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
+ $v_options_trick = array();
+ $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
+ array (PCLZIP_OPT_BY_INDEX => 'optional' ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
+
+ // ----- Look for default option values
+ $this->privOptionDefaultThreshold($v_options);
+
+ // ----- Call the extracting fct
+ if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
+ return(0);
+ }
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function :
+ // delete([$p_option, $p_option_value, ...])
+ // Description :
+ // This method removes files from the archive.
+ // If no parameters are given, then all the archive is emptied.
+ // Parameters :
+ // None or optional arguments.
+ // Options :
+ // PCLZIP_OPT_BY_INDEX :
+ // PCLZIP_OPT_BY_NAME :
+ // PCLZIP_OPT_BY_EREG :
+ // PCLZIP_OPT_BY_PREG :
+ // Return Values :
+ // 0 on failure,
+ // The list of the files which are still present in the archive.
+ // (see PclZip::listContent() for list entry format)
+ // --------------------------------------------------------------------------------
+ function delete()
+ {
+ $v_result=1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Set default values
+ $v_options = array();
+
+ // ----- Look for variable options arguments
+ $v_size = func_num_args();
+
+ // ----- Look for arguments
+ if ($v_size > 0) {
+ // ----- Get the arguments
+ $v_arg_list = func_get_args();
+
+ // ----- Parse the options
+ $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
+ array (PCLZIP_OPT_BY_NAME => 'optional',
+ PCLZIP_OPT_BY_EREG => 'optional',
+ PCLZIP_OPT_BY_PREG => 'optional',
+ PCLZIP_OPT_BY_INDEX => 'optional' ));
+ if ($v_result != 1) {
+ return 0;
+ }
+ }
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Call the delete fct
+ $v_list = array();
+ if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
+ $this->privSwapBackMagicQuotes();
+ unset($v_list);
+ return(0);
+ }
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : deleteByIndex()
+ // Description :
+ // ***** Deprecated *****
+ // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
+ // --------------------------------------------------------------------------------
+ function deleteByIndex($p_index)
+ {
+
+ $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
+
+ // ----- Return
+ return $p_list;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : properties()
+ // Description :
+ // This method gives the properties of the archive.
+ // The properties are :
+ // nb : Number of files in the archive
+ // comment : Comment associated with the archive file
+ // status : not_exist, ok
+ // Parameters :
+ // None
+ // Return Values :
+ // 0 on failure,
+ // An array with the archive properties.
+ // --------------------------------------------------------------------------------
+ function properties()
+ {
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ $this->privSwapBackMagicQuotes();
+ return(0);
+ }
+
+ // ----- Default properties
+ $v_prop = array();
+ $v_prop['comment'] = '';
+ $v_prop['nb'] = 0;
+ $v_prop['status'] = 'not_exist';
+
+ // ----- Look if file exists
+ if (@is_file($this->zipname))
+ {
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
+ {
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
+
+ // ----- Return
+ return 0;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return 0;
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Set the user attributes
+ $v_prop['comment'] = $v_central_dir['comment'];
+ $v_prop['nb'] = $v_central_dir['entries'];
+ $v_prop['status'] = 'ok';
+ }
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_prop;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : duplicate()
+ // Description :
+ // This method creates an archive by copying the content of an other one. If
+ // the archive already exist, it is replaced by the new one without any warning.
+ // Parameters :
+ // $p_archive : The filename of a valid archive, or
+ // a valid PclZip object.
+ // Return Values :
+ // 1 on success.
+ // 0 or a negative value on error (error code).
+ // --------------------------------------------------------------------------------
+ function duplicate($p_archive)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Look if the $p_archive is a PclZip object
+ if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip'))
+ {
+
+ // ----- Duplicate the archive
+ $v_result = $this->privDuplicate($p_archive->zipname);
+ }
+
+ // ----- Look if the $p_archive is a string (so a filename)
+ else if (is_string($p_archive))
+ {
+
+ // ----- Check that $p_archive is a valid zip file
+ // TBC : Should also check the archive format
+ if (!is_file($p_archive)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
+ $v_result = PCLZIP_ERR_MISSING_FILE;
+ }
+ else {
+ // ----- Duplicate the archive
+ $v_result = $this->privDuplicate($p_archive);
+ }
+ }
+
+ // ----- Invalid variable
+ else
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : merge()
+ // Description :
+ // This method merge the $p_archive_to_add archive at the end of the current
+ // one ($this).
+ // If the archive ($this) does not exist, the merge becomes a duplicate.
+ // If the $p_archive_to_add archive does not exist, the merge is a success.
+ // Parameters :
+ // $p_archive_to_add : It can be directly the filename of a valid zip archive,
+ // or a PclZip object archive.
+ // Return Values :
+ // 1 on success,
+ // 0 or negative values on error (see below).
+ // --------------------------------------------------------------------------------
+ function merge($p_archive_to_add)
+ {
+ $v_result = 1;
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Check archive
+ if (!$this->privCheckFormat()) {
+ return(0);
+ }
+
+ // ----- Look if the $p_archive_to_add is a PclZip object
+ if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip'))
+ {
+
+ // ----- Merge the archive
+ $v_result = $this->privMerge($p_archive_to_add);
+ }
+
+ // ----- Look if the $p_archive_to_add is a string (so a filename)
+ else if (is_string($p_archive_to_add))
+ {
+
+ // ----- Create a temporary archive
+ $v_object_archive = new PclZip($p_archive_to_add);
+
+ // ----- Merge the archive
+ $v_result = $this->privMerge($v_object_archive);
+ }
+
+ // ----- Invalid variable
+ else
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
+ $v_result = PCLZIP_ERR_INVALID_PARAMETER;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+
+
+ // --------------------------------------------------------------------------------
+ // Function : errorCode()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function errorCode()
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ return(PclErrorCode());
+ }
+ else {
+ return($this->error_code);
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorName()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function errorName($p_with_code=false)
+ {
+ $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
+ PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
+ PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
+ PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
+ PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
+ PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
+ PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
+ PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
+ PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
+ PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
+ PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
+ PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
+ PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
+ PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
+ PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
+ PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
+ PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
+ PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
+ PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION'
+ ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE'
+ ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
+ );
+
+ if (isset($v_name[$this->error_code])) {
+ $v_value = $v_name[$this->error_code];
+ }
+ else {
+ $v_value = 'NoName';
+ }
+
+ if ($p_with_code) {
+ return($v_value.' ('.$this->error_code.')');
+ }
+ else {
+ return($v_value);
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : errorInfo()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function errorInfo($p_full=false)
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ return(PclErrorString());
+ }
+ else {
+ if ($p_full) {
+ return($this->errorName(true)." : ".$this->error_string);
+ }
+ else {
+ return($this->error_string." [code ".$this->error_code."]");
+ }
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+
+// --------------------------------------------------------------------------------
+// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
+// ***** *****
+// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
+// --------------------------------------------------------------------------------
+
+
+
+ // --------------------------------------------------------------------------------
+ // Function : privCheckFormat()
+ // Description :
+ // This method check that the archive exists and is a valid zip archive.
+ // Several level of check exists. (futur)
+ // Parameters :
+ // $p_level : Level of check. Default 0.
+ // 0 : Check the first bytes (magic codes) (default value))
+ // 1 : 0 + Check the central directory (futur)
+ // 2 : 1 + Check each file header (futur)
+ // Return Values :
+ // true on success,
+ // false on error, the error code is set.
+ // --------------------------------------------------------------------------------
+ function privCheckFormat($p_level=0)
+ {
+ $v_result = true;
+
+ // ----- Reset the file system cache
+ clearstatcache();
+
+ // ----- Reset the error handler
+ $this->privErrorReset();
+
+ // ----- Look if the file exits
+ if (!is_file($this->zipname)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
+ return(false);
+ }
+
+ // ----- Check that the file is readeable
+ if (!is_readable($this->zipname)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
+ return(false);
+ }
+
+ // ----- Check the magic code
+ // TBC
+
+ // ----- Check the central header
+ // TBC
+
+ // ----- Check each file header
+ // TBC
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privParseOptions()
+ // Description :
+ // This internal methods reads the variable list of arguments ($p_options_list,
+ // $p_size) and generate an array with the options and values ($v_result_list).
+ // $v_requested_options contains the options that can be present and those that
+ // must be present.
+ // $v_requested_options is an array, with the option value as key, and 'optional',
+ // or 'mandatory' as value.
+ // Parameters :
+ // See above.
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false)
+ {
+ $v_result=1;
+
+ // ----- Read the options
+ $i=0;
+ while ($i<$p_size) {
+
+ // ----- Check if the option is supported
+ if (!isset($v_requested_options[$p_options_list[$i]])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for next option
+ switch ($p_options_list[$i]) {
+ // ----- Look for options that request a path value
+ case PCLZIP_OPT_PATH :
+ case PCLZIP_OPT_REMOVE_PATH :
+ case PCLZIP_OPT_ADD_PATH :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
+ $i++;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+ return PclZip::errorCode();
+ }
+
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+ return PclZip::errorCode();
+ }
+
+ // ----- Check the value
+ $v_value = $p_options_list[$i+1];
+ if ((!is_integer($v_value)) || ($v_value<0)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value (and convert it in bytes)
+ $v_result_list[$p_options_list[$i]] = $v_value*1048576;
+ $i++;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_ON :
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
+ return PclZip::errorCode();
+ }
+
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ case PCLZIP_OPT_TEMP_FILE_OFF :
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
+ return PclZip::errorCode();
+ }
+ // ----- Check for incompatible options
+ if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
+ return PclZip::errorCode();
+ }
+
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if ( is_string($p_options_list[$i+1])
+ && ($p_options_list[$i+1] != '')) {
+ $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE);
+ $i++;
+ }
+ else {
+ }
+ break;
+
+ // ----- Look for options that request an array of string for value
+ case PCLZIP_OPT_BY_NAME :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
+ }
+ else if (is_array($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that request an EREG or PREG expression
+ case PCLZIP_OPT_BY_EREG :
+ // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
+ // to PCLZIP_OPT_BY_PREG
+ $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
+ case PCLZIP_OPT_BY_PREG :
+ //case PCLZIP_OPT_CRYPT :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that takes a string
+ case PCLZIP_OPT_COMMENT :
+ case PCLZIP_OPT_ADD_COMMENT :
+ case PCLZIP_OPT_PREPEND_COMMENT :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
+ "Missing parameter value for option '"
+ .PclZipUtilOptionText($p_options_list[$i])
+ ."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ if (is_string($p_options_list[$i+1])) {
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
+ "Wrong parameter value for option '"
+ .PclZipUtilOptionText($p_options_list[$i])
+ ."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $i++;
+ break;
+
+ // ----- Look for options that request an array of index
+ case PCLZIP_OPT_BY_INDEX :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_work_list = array();
+ if (is_string($p_options_list[$i+1])) {
+
+ // ----- Remove spaces
+ $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
+
+ // ----- Parse items
+ $v_work_list = explode(",", $p_options_list[$i+1]);
+ }
+ else if (is_integer($p_options_list[$i+1])) {
+ $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
+ }
+ else if (is_array($p_options_list[$i+1])) {
+ $v_work_list = $p_options_list[$i+1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Reduce the index list
+ // each index item in the list must be a couple with a start and
+ // an end value : [0,3], [5-5], [8-10], ...
+ // ----- Check the format of each item
+ $v_sort_flag=false;
+ $v_sort_value=0;
+ for ($j=0; $j<sizeof($v_work_list); $j++) {
+ // ----- Explode the item
+ $v_item_list = explode("-", $v_work_list[$j]);
+ $v_size_item_list = sizeof($v_item_list);
+
+ // ----- TBC : Here we might check that each item is a
+ // real integer ...
+
+ // ----- Look for single value
+ if ($v_size_item_list == 1) {
+ // ----- Set the option value
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
+ }
+ elseif ($v_size_item_list == 2) {
+ // ----- Set the option value
+ $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
+ $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
+ }
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Look for list sort
+ if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
+ $v_sort_flag=true;
+
+ // ----- TBC : An automatic sort should be writen ...
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
+ }
+
+ // ----- Sort the items
+ if ($v_sort_flag) {
+ // TBC : To Be Completed
+ }
+
+ // ----- Next option
+ $i++;
+ break;
+
+ // ----- Look for options that request no value
+ case PCLZIP_OPT_REMOVE_ALL_PATH :
+ case PCLZIP_OPT_EXTRACT_AS_STRING :
+ case PCLZIP_OPT_NO_COMPRESSION :
+ case PCLZIP_OPT_EXTRACT_IN_OUTPUT :
+ case PCLZIP_OPT_REPLACE_NEWER :
+ case PCLZIP_OPT_STOP_ON_ERROR :
+ $v_result_list[$p_options_list[$i]] = true;
+ break;
+
+ // ----- Look for options that request an octal value
+ case PCLZIP_OPT_SET_CHMOD :
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
+ $i++;
+ break;
+
+ // ----- Look for options that request a call-back
+ case PCLZIP_CB_PRE_EXTRACT :
+ case PCLZIP_CB_POST_EXTRACT :
+ case PCLZIP_CB_PRE_ADD :
+ case PCLZIP_CB_POST_ADD :
+ /* for futur use
+ case PCLZIP_CB_PRE_DELETE :
+ case PCLZIP_CB_POST_DELETE :
+ case PCLZIP_CB_PRE_LIST :
+ case PCLZIP_CB_POST_LIST :
+ */
+ // ----- Check the number of parameters
+ if (($i+1) >= $p_size) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Get the value
+ $v_function_name = $p_options_list[$i+1];
+
+ // ----- Check that the value is a valid existing function
+ if (!function_exists($v_function_name)) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Set the attribute
+ $v_result_list[$p_options_list[$i]] = $v_function_name;
+ $i++;
+ break;
+
+ default :
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+ "Unknown parameter '"
+ .$p_options_list[$i]."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Next options
+ $i++;
+ }
+
+ // ----- Look for mandatory options
+ if ($v_requested_options !== false) {
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
+ // ----- Look for mandatory option
+ if ($v_requested_options[$key] == 'mandatory') {
+ // ----- Look if present
+ if (!isset($v_result_list[$key])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+ }
+ }
+
+ // ----- Look for default values
+ if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
+
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privOptionDefaultThreshold()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privOptionDefaultThreshold(&$p_options)
+ {
+ $v_result=1;
+
+ if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+ || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
+ return $v_result;
+ }
+
+ // ----- Get 'memory_limit' configuration value
+ $v_memory_limit = ini_get('memory_limit');
+ $v_memory_limit = trim($v_memory_limit);
+ $last = strtolower(substr($v_memory_limit, -1));
+
+ if($last == 'g')
+ //$v_memory_limit = $v_memory_limit*1024*1024*1024;
+ $v_memory_limit = $v_memory_limit*1073741824;
+ if($last == 'm')
+ //$v_memory_limit = $v_memory_limit*1024*1024;
+ $v_memory_limit = $v_memory_limit*1048576;
+ if($last == 'k')
+ $v_memory_limit = $v_memory_limit*1024;
+
+ $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
+
+
+ // ----- Sanity check : No threshold if value lower than 1M
+ if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
+ unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privFileDescrParseAtt()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false)
+ {
+ $v_result=1;
+
+ // ----- For each file in the list check the attributes
+ foreach ($p_file_list as $v_key => $v_value) {
+
+ // ----- Check if the option is supported
+ if (!isset($v_requested_options[$v_key])) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for attribute
+ switch ($v_key) {
+ case PCLZIP_ATT_FILE_NAME :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['filename'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ break;
+
+ case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['new_short_name'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+ break;
+
+ case PCLZIP_ATT_FILE_NEW_FULL_NAME :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
+
+ if ($p_filedescr['new_full_name'] == '') {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+ break;
+
+ // ----- Look for options that takes a string
+ case PCLZIP_ATT_FILE_COMMENT :
+ if (!is_string($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['comment'] = $v_value;
+ break;
+
+ case PCLZIP_ATT_FILE_MTIME :
+ if (!is_integer($v_value)) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
+ return PclZip::errorCode();
+ }
+
+ $p_filedescr['mtime'] = $v_value;
+ break;
+
+ case PCLZIP_ATT_FILE_CONTENT :
+ $p_filedescr['content'] = $v_value;
+ break;
+
+ default :
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
+ "Unknown parameter '".$v_key."'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for mandatory options
+ if ($v_requested_options !== false) {
+ for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
+ // ----- Look for mandatory option
+ if ($v_requested_options[$key] == 'mandatory') {
+ // ----- Look if present
+ if (!isset($p_file_list[$key])) {
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
+ return PclZip::errorCode();
+ }
+ }
+ }
+ }
+
+ // end foreach
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privFileDescrExpand()
+ // Description :
+ // This method look for each item of the list to see if its a file, a folder
+ // or a string to be added as file. For any other type of files (link, other)
+ // just ignore the item.
+ // Then prepare the information that will be stored for that file.
+ // When its a folder, expand the folder with all the files that are in that
+ // folder (recursively).
+ // Parameters :
+ // Return Values :
+ // 1 on success.
+ // 0 on failure.
+ // --------------------------------------------------------------------------------
+ function privFileDescrExpand(&$p_filedescr_list, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Create a result list
+ $v_result_list = array();
+
+ // ----- Look each entry
+ for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
+
+ // ----- Get filedescr
+ $v_descr = $p_filedescr_list[$i];
+
+ // ----- Reduce the filename
+ $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
+ $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
+
+ // ----- Look for real file or folder
+ if (file_exists($v_descr['filename'])) {
+ if (@is_file($v_descr['filename'])) {
+ $v_descr['type'] = 'file';
+ }
+ else if (@is_dir($v_descr['filename'])) {
+ $v_descr['type'] = 'folder';
+ }
+ else if (@is_link($v_descr['filename'])) {
+ // skip
+ continue;
+ }
+ else {
+ // skip
+ continue;
+ }
+ }
+
+ // ----- Look for string added as file
+ else if (isset($v_descr['content'])) {
+ $v_descr['type'] = 'virtual_file';
+ }
+
+ // ----- Missing file
+ else {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Calculate the stored filename
+ $this->privCalculateStoredFilename($v_descr, $p_options);
+
+ // ----- Add the descriptor in result list
+ $v_result_list[sizeof($v_result_list)] = $v_descr;
+
+ // ----- Look for folder
+ if ($v_descr['type'] == 'folder') {
+ // ----- List of items in folder
+ $v_dirlist_descr = array();
+ $v_dirlist_nb = 0;
+ if ($v_folder_handler = @opendir($v_descr['filename'])) {
+ while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
+
+ // ----- Skip '.' and '..'
+ if (($v_item_handler == '.') || ($v_item_handler == '..')) {
+ continue;
+ }
+
+ // ----- Compose the full filename
+ $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
+
+ // ----- Look for different stored filename
+ // Because the name of the folder was changed, the name of the
+ // files/sub-folders also change
+ if (($v_descr['stored_filename'] != $v_descr['filename'])
+ && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
+ if ($v_descr['stored_filename'] != '') {
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
+ }
+ else {
+ $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
+ }
+ }
+
+ $v_dirlist_nb++;
+ }
+
+ @closedir($v_folder_handler);
+ }
+ else {
+ // TBC : unable to open folder in read mode
+ }
+
+ // ----- Expand each element of the list
+ if ($v_dirlist_nb != 0) {
+ // ----- Expand
+ if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Concat the resulting list
+ $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
+ }
+ else {
+ }
+
+ // ----- Free local array
+ unset($v_dirlist_descr);
+ }
+ }
+
+ // ----- Get the result list
+ $p_filedescr_list = $v_result_list;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCreate()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_list_detail = array();
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the file in write mode
+ if (($v_result = $this->privOpenFd('wb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Add the list of files
+ $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAdd()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_list_detail = array();
+
+ // ----- Look if the archive exists or is empty
+ if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0))
+ {
+
+ // ----- Do a create
+ $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
+
+ // ----- Return
+ return $v_result;
+ }
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('rb')) != 1)
+ {
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Creates a temporay file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
+ {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = $v_central_dir['offset'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Swap the file descriptor
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+ // the following methods on the temporary fil and not the real archive
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Add the files
+ $v_header_list = array();
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
+ {
+ fclose($v_zip_temp_fd);
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($this->zip_fd);
+
+ // ----- Copy the block of file headers from the old archive
+ $v_size = $v_central_dir['size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Create the Central Dir files header
+ for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++)
+ {
+ // ----- Create the file header
+ if ($v_header_list[$i]['status'] == 'ok') {
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ fclose($v_zip_temp_fd);
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ $v_count++;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = $v_central_dir['comment'];
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+ if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
+ $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
+ }
+ if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($this->zip_fd)-$v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1)
+ {
+ // ----- Reset the file list
+ unset($v_header_list);
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Swap back the file descriptor
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privOpenFd()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privOpenFd($p_mode)
+ {
+ $v_result=1;
+
+ // ----- Look if already open
+ if ($this->zip_fd != 0)
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0)
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCloseFd()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privCloseFd()
+ {
+ $v_result=1;
+
+ if ($this->zip_fd != 0)
+ @fclose($this->zip_fd);
+ $this->zip_fd = 0;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddList()
+ // Description :
+ // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
+ // different from the real path of the file. This is usefull if you want to have PclTar
+ // running in any directory, and memorize relative path from an other directory.
+ // Parameters :
+ // $p_list : An array containing the file or directory names to add in the tar
+ // $p_result_list : list of added files with their properties (specially the status field)
+ // $p_add_dir : Path to add in the filename path archived
+ // $p_remove_dir : Path to remove in the filename path archived
+ // Return Values :
+ // --------------------------------------------------------------------------------
+// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
+ function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Add the files
+ $v_header_list = array();
+ if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($this->zip_fd);
+
+ // ----- Create the Central Dir files header
+ for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++)
+ {
+ // ----- Create the file header
+ if ($v_header_list[$i]['status'] == 'ok') {
+ if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ // ----- Return
+ return $v_result;
+ }
+ $v_count++;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+ // ----- Zip file comment
+ $v_comment = '';
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($this->zip_fd)-$v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1)
+ {
+ // ----- Reset the file list
+ unset($v_header_list);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFileList()
+ // Description :
+ // Parameters :
+ // $p_filedescr_list : An array containing the file description
+ // or directory names to add in the zip
+ // $p_result_list : list of added files with their properties (specially the status field)
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_header = array();
+
+ // ----- Recuperate the current number of elt in list
+ $v_nb = sizeof($p_result_list);
+
+ // ----- Loop on the files
+ for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
+ // ----- Format the filename
+ $p_filedescr_list[$j]['filename']
+ = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
+
+
+ // ----- Skip empty file names
+ // TBC : Can this be possible ? not checked in DescrParseAtt ?
+ if ($p_filedescr_list[$j]['filename'] == "") {
+ continue;
+ }
+
+ // ----- Check the filename
+ if ( ($p_filedescr_list[$j]['type'] != 'virtual_file')
+ && (!file_exists($p_filedescr_list[$j]['filename']))) {
+ PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
+ return PclZip::errorCode();
+ }
+
+ // ----- Look if it is a file or a dir with no all path remove option
+ // or a dir with all its path removed
+// if ( (is_file($p_filedescr_list[$j]['filename']))
+// || ( is_dir($p_filedescr_list[$j]['filename'])
+ if ( ($p_filedescr_list[$j]['type'] == 'file')
+ || ($p_filedescr_list[$j]['type'] == 'virtual_file')
+ || ( ($p_filedescr_list[$j]['type'] == 'folder')
+ && ( !isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
+ || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
+ ) {
+
+ // ----- Add the file
+ $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
+ $p_options);
+ if ($v_result != 1) {
+ return $v_result;
+ }
+
+ // ----- Store the file infos
+ $p_result_list[$v_nb++] = $v_header;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAddFile($p_filedescr, &$p_header, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Working variable
+ $p_filename = $p_filedescr['filename'];
+
+ // TBC : Already done in the fileAtt check ... ?
+ if ($p_filename == "") {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for a stored different filename
+ /* TBC : Removed
+ if (isset($p_filedescr['stored_filename'])) {
+ $v_stored_filename = $p_filedescr['stored_filename'];
+ }
+ else {
+ $v_stored_filename = $p_filedescr['stored_filename'];
+ }
+ */
+
+ // ----- Set the file properties
+ clearstatcache();
+ $p_header['version'] = 20;
+ $p_header['version_extracted'] = 10;
+ $p_header['flag'] = 0;
+ $p_header['compression'] = 0;
+ $p_header['crc'] = 0;
+ $p_header['compressed_size'] = 0;
+ $p_header['filename_len'] = strlen($p_filename);
+ $p_header['extra_len'] = 0;
+ $p_header['disk'] = 0;
+ $p_header['internal'] = 0;
+ $p_header['offset'] = 0;
+ $p_header['filename'] = $p_filename;
+// TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
+ $p_header['stored_filename'] = $p_filedescr['stored_filename'];
+ $p_header['extra'] = '';
+ $p_header['status'] = 'ok';
+ $p_header['index'] = -1;
+
+ // ----- Look for regular file
+ if ($p_filedescr['type']=='file') {
+ $p_header['external'] = 0x00000000;
+ $p_header['size'] = filesize($p_filename);
+ }
+
+ // ----- Look for regular folder
+ else if ($p_filedescr['type']=='folder') {
+ $p_header['external'] = 0x00000010;
+ $p_header['mtime'] = filemtime($p_filename);
+ $p_header['size'] = filesize($p_filename);
+ }
+
+ // ----- Look for virtual file
+ else if ($p_filedescr['type'] == 'virtual_file') {
+ $p_header['external'] = 0x00000000;
+ $p_header['size'] = strlen($p_filedescr['content']);
+ }
+
+
+ // ----- Look for filetime
+ if (isset($p_filedescr['mtime'])) {
+ $p_header['mtime'] = $p_filedescr['mtime'];
+ }
+ else if ($p_filedescr['type'] == 'virtual_file') {
+ $p_header['mtime'] = time();
+ }
+ else {
+ $p_header['mtime'] = filemtime($p_filename);
+ }
+
+ // ------ Look for file comment
+ if (isset($p_filedescr['comment'])) {
+ $p_header['comment_len'] = strlen($p_filedescr['comment']);
+ $p_header['comment'] = $p_filedescr['comment'];
+ }
+ else {
+ $p_header['comment_len'] = 0;
+ $p_header['comment'] = '';
+ }
+
+ // ----- Look for pre-add callback
+ if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_header['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
+ $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
+ }
+ }
+
+ // ----- Look for empty stored filename
+ if ($p_header['stored_filename'] == "") {
+ $p_header['status'] = "filtered";
+ }
+
+ // ----- Check the path length
+ if (strlen($p_header['stored_filename']) > 0xFF) {
+ $p_header['status'] = 'filename_too_long';
+ }
+
+ // ----- Look if no error, or file not skipped
+ if ($p_header['status'] == 'ok') {
+
+ // ----- Look for a file
+ if ($p_filedescr['type'] == 'file') {
+ // ----- Look for using temporary file to zip
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) {
+ $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
+ return $v_result;
+ }
+ }
+
+ // ----- Use "in memory" zip algo
+ else {
+
+ // ----- Open the source file
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file content
+ $v_content = @fread($v_file, $p_header['size']);
+
+ // ----- Close the file
+ @fclose($v_file);
+
+ // ----- Calculate the CRC
+ $p_header['crc'] = @crc32($v_content);
+
+ // ----- Look for no compression
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+ // ----- Set header parameters
+ $p_header['compressed_size'] = $p_header['size'];
+ $p_header['compression'] = 0;
+ }
+
+ // ----- Look for normal compression
+ else {
+ // ----- Compress the content
+ $v_content = @gzdeflate($v_content);
+
+ // ----- Set header parameters
+ $p_header['compressed_size'] = strlen($v_content);
+ $p_header['compression'] = 8;
+ }
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ @fclose($v_file);
+ return $v_result;
+ }
+
+ // ----- Write the compressed (or not) content
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+
+ }
+
+ }
+
+ // ----- Look for a virtual file (a file from string)
+ else if ($p_filedescr['type'] == 'virtual_file') {
+
+ $v_content = $p_filedescr['content'];
+
+ // ----- Calculate the CRC
+ $p_header['crc'] = @crc32($v_content);
+
+ // ----- Look for no compression
+ if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
+ // ----- Set header parameters
+ $p_header['compressed_size'] = $p_header['size'];
+ $p_header['compression'] = 0;
+ }
+
+ // ----- Look for normal compression
+ else {
+ // ----- Compress the content
+ $v_content = @gzdeflate($v_content);
+
+ // ----- Set header parameters
+ $p_header['compressed_size'] = strlen($v_content);
+ $p_header['compression'] = 8;
+ }
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ @fclose($v_file);
+ return $v_result;
+ }
+
+ // ----- Write the compressed (or not) content
+ @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
+ }
+
+ // ----- Look for a directory
+ else if ($p_filedescr['type'] == 'folder') {
+ // ----- Look for directory last '/'
+ if (@substr($p_header['stored_filename'], -1) != '/') {
+ $p_header['stored_filename'] .= '/';
+ }
+
+ // ----- Set the file properties
+ $p_header['size'] = 0;
+ //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
+ $p_header['external'] = 0x00000010; // Value for a folder : to be checked
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1)
+ {
+ return $v_result;
+ }
+ }
+ }
+
+ // ----- Look for post-add callback
+ if (isset($p_options[PCLZIP_CB_POST_ADD])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_header, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Ignored
+ $v_result = 1;
+ }
+
+ // ----- Update the informations
+ // Nothing can be modified
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privAddFileUsingTempFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
+ {
+ $v_result=PCLZIP_ERR_NO_ERROR;
+
+ // ----- Working variable
+ $p_filename = $p_filedescr['filename'];
+
+
+ // ----- Open the source file
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
+ return PclZip::errorCode();
+ }
+
+ // ----- Creates a compressed temporary file
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
+ if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
+ fclose($v_file);
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = filesize($p_filename);
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_file, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @gzputs($v_file_compressed, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close the file
+ @fclose($v_file);
+ @gzclose($v_file_compressed);
+
+ // ----- Check the minimum file size
+ if (filesize($v_gzip_temp_name) < 18) {
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the compressed attributes
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the gzip file header
+ $v_binary_data = @fread($v_file_compressed, 10);
+ $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
+
+ // ----- Check some parameters
+ $v_data_header['os'] = bin2hex($v_data_header['os']);
+
+ // ----- Read the gzip file footer
+ @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
+ $v_binary_data = @fread($v_file_compressed, 8);
+ $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
+
+ // ----- Set the attributes
+ $p_header['compression'] = ord($v_data_header['cm']);
+ //$p_header['mtime'] = $v_data_header['mtime'];
+ $p_header['crc'] = $v_data_footer['crc'];
+ $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
+
+ // ----- Close the file
+ @fclose($v_file_compressed);
+
+ // ----- Call the header generation
+ if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
+ return $v_result;
+ }
+
+ // ----- Add the compressed data
+ if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0)
+ {
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ fseek($v_file_compressed, 10);
+ $v_size = $p_header['compressed_size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($v_file_compressed, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close the file
+ @fclose($v_file_compressed);
+
+ // ----- Unlink the temporary file
+ @unlink($v_gzip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCalculateStoredFilename()
+ // Description :
+ // Based on file descriptor properties and global options, this method
+ // calculate the filename that will be stored in the archive.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privCalculateStoredFilename(&$p_filedescr, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Working variables
+ $p_filename = $p_filedescr['filename'];
+ if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
+ $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
+ }
+ else {
+ $p_add_dir = '';
+ }
+ if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
+ $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
+ }
+ else {
+ $p_remove_dir = '';
+ }
+ if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
+ $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
+ }
+ else {
+ $p_remove_all_dir = 0;
+ }
+
+
+ // ----- Look for full name change
+ if (isset($p_filedescr['new_full_name'])) {
+ // ----- Remove drive letter if any
+ $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
+ }
+
+ // ----- Look for path and/or short name change
+ else {
+
+ // ----- Look for short name change
+ // Its when we cahnge just the filename but not the path
+ if (isset($p_filedescr['new_short_name'])) {
+ $v_path_info = pathinfo($p_filename);
+ $v_dir = '';
+ if ($v_path_info['dirname'] != '') {
+ $v_dir = $v_path_info['dirname'].'/';
+ }
+ $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
+ }
+ else {
+ // ----- Calculate the stored filename
+ $v_stored_filename = $p_filename;
+ }
+
+ // ----- Look for all path to remove
+ if ($p_remove_all_dir) {
+ $v_stored_filename = basename($p_filename);
+ }
+ // ----- Look for partial path remove
+ else if ($p_remove_dir != "") {
+ if (substr($p_remove_dir, -1) != '/')
+ $p_remove_dir .= "/";
+
+ if ( (substr($p_filename, 0, 2) == "./")
+ || (substr($p_remove_dir, 0, 2) == "./")) {
+
+ if ( (substr($p_filename, 0, 2) == "./")
+ && (substr($p_remove_dir, 0, 2) != "./")) {
+ $p_remove_dir = "./".$p_remove_dir;
+ }
+ if ( (substr($p_filename, 0, 2) != "./")
+ && (substr($p_remove_dir, 0, 2) == "./")) {
+ $p_remove_dir = substr($p_remove_dir, 2);
+ }
+ }
+
+ $v_compare = PclZipUtilPathInclusion($p_remove_dir,
+ $v_stored_filename);
+ if ($v_compare > 0) {
+ if ($v_compare == 2) {
+ $v_stored_filename = "";
+ }
+ else {
+ $v_stored_filename = substr($v_stored_filename,
+ strlen($p_remove_dir));
+ }
+ }
+ }
+
+ // ----- Remove drive letter if any
+ $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
+
+ // ----- Look for path to add
+ if ($p_add_dir != "") {
+ if (substr($p_add_dir, -1) == "/")
+ $v_stored_filename = $p_add_dir.$v_stored_filename;
+ else
+ $v_stored_filename = $p_add_dir."/".$v_stored_filename;
+ }
+ }
+
+ // ----- Filename (reduce the path of stored name)
+ $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
+ $p_filedescr['stored_filename'] = $v_stored_filename;
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privWriteFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // ----- Store the offset position of the file
+ $p_header['offset'] = ftell($this->zip_fd);
+
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
+ $v_date = getdate($p_header['mtime']);
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
+ $p_header['version_extracted'], $p_header['flag'],
+ $p_header['compression'], $v_mtime, $v_mdate,
+ $p_header['crc'], $p_header['compressed_size'],
+ $p_header['size'],
+ strlen($p_header['stored_filename']),
+ $p_header['extra_len']);
+
+ // ----- Write the first 148 bytes of the header in the archive
+ fputs($this->zip_fd, $v_binary_data, 30);
+
+ // ----- Write the variable fields
+ if (strlen($p_header['stored_filename']) != 0)
+ {
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+ }
+ if ($p_header['extra_len'] != 0)
+ {
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteCentralFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privWriteCentralFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // TBC
+ //for(reset($p_header); $key = key($p_header); next($p_header)) {
+ //}
+
+ // ----- Transform UNIX mtime to DOS format mdate/mtime
+ $v_date = getdate($p_header['mtime']);
+ $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
+ $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
+
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
+ $p_header['version'], $p_header['version_extracted'],
+ $p_header['flag'], $p_header['compression'],
+ $v_mtime, $v_mdate, $p_header['crc'],
+ $p_header['compressed_size'], $p_header['size'],
+ strlen($p_header['stored_filename']),
+ $p_header['extra_len'], $p_header['comment_len'],
+ $p_header['disk'], $p_header['internal'],
+ $p_header['external'], $p_header['offset']);
+
+ // ----- Write the 42 bytes of the header in the zip file
+ fputs($this->zip_fd, $v_binary_data, 46);
+
+ // ----- Write the variable fields
+ if (strlen($p_header['stored_filename']) != 0)
+ {
+ fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
+ }
+ if ($p_header['extra_len'] != 0)
+ {
+ fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
+ }
+ if ($p_header['comment_len'] != 0)
+ {
+ fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privWriteCentralHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
+ {
+ $v_result=1;
+
+ // ----- Packed data
+ $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
+ $p_nb_entries, $p_size,
+ $p_offset, strlen($p_comment));
+
+ // ----- Write the 22 bytes of the header in the zip file
+ fputs($this->zip_fd, $v_binary_data, 22);
+
+ // ----- Write the variable fields
+ if (strlen($p_comment) != 0)
+ {
+ fputs($this->zip_fd, $p_comment, strlen($p_comment));
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privList()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privList(&$p_list)
+ {
+ $v_result=1;
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Open the zip file
+ if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0)
+ {
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of Central Dir
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_central_dir['offset']))
+ {
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read each entry
+ for ($i=0; $i<$v_central_dir['entries']; $i++)
+ {
+ // ----- Read the file header
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+ $v_header['index'] = $i;
+
+ // ----- Get the only interesting attributes
+ $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
+ unset($v_header);
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Magic quotes trick
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privConvertHeader2FileInfo()
+ // Description :
+ // This function takes the file informations from the central directory
+ // entries and extract the interesting parameters that will be given back.
+ // The resulting file infos are set in the array $p_info
+ // $p_info['filename'] : Filename with full path. Given by user (add),
+ // extracted in the filesystem (extract).
+ // $p_info['stored_filename'] : Stored filename in the archive.
+ // $p_info['size'] = Size of the file.
+ // $p_info['compressed_size'] = Compressed size of the file.
+ // $p_info['mtime'] = Last modification date of the file.
+ // $p_info['comment'] = Comment associated with the file.
+ // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
+ // $p_info['status'] = status of the action on the file.
+ // $p_info['crc'] = CRC of the file content.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privConvertHeader2FileInfo($p_header, &$p_info)
+ {
+ $v_result=1;
+
+ // ----- Get the interesting attributes
+ $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
+ $p_info['filename'] = $v_temp_path;
+ $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
+ $p_info['stored_filename'] = $v_temp_path;
+ $p_info['size'] = $p_header['size'];
+ $p_info['compressed_size'] = $p_header['compressed_size'];
+ $p_info['mtime'] = $p_header['mtime'];
+ $p_info['comment'] = $p_header['comment'];
+ $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
+ $p_info['index'] = $p_header['index'];
+ $p_info['status'] = $p_header['status'];
+ $p_info['crc'] = $p_header['crc'];
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractByRule()
+ // Description :
+ // Extract a file or directory depending of rules (by index, by name, ...)
+ // Parameters :
+ // $p_file_list : An array where will be placed the properties of each
+ // extracted file
+ // $p_path : Path to add while writing the extracted files
+ // $p_remove_path : Path to remove (from the file memorized path) while writing the
+ // extracted files. If the path does not match the file path,
+ // the file is extracted with its memorized path.
+ // $p_remove_path does not apply to 'list' mode.
+ // $p_path and $p_remove_path are commulative.
+ // Return Values :
+ // 1 on success,0 or less on error (see error code list)
+ // --------------------------------------------------------------------------------
+ function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Magic quotes trick
+ $this->privDisableMagicQuotes();
+
+ // ----- Check the path
+ if ( ($p_path == "")
+ || ( (substr($p_path, 0, 1) != "/")
+ && (substr($p_path, 0, 3) != "../")
+ && (substr($p_path,1,2)!=":/")))
+ $p_path = "./".$p_path;
+
+ // ----- Reduce the path last (and duplicated) '/'
+ if (($p_path != "./") && ($p_path != "/"))
+ {
+ // ----- Look for the path end '/'
+ while (substr($p_path, -1) == "/")
+ {
+ $p_path = substr($p_path, 0, strlen($p_path)-1);
+ }
+ }
+
+ // ----- Look for path to remove format (should end by /)
+ if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
+ {
+ $p_remove_path .= '/';
+ }
+ $p_remove_path_size = strlen($p_remove_path);
+
+ // ----- Open the zip file
+ if (($v_result = $this->privOpenFd('rb')) != 1)
+ {
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Start at beginning of Central Dir
+ $v_pos_entry = $v_central_dir['offset'];
+
+ // ----- Read each entry
+ $j_start = 0;
+ for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
+ {
+
+ // ----- Read next Central dir entry
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_pos_entry))
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file header
+ $v_header = array();
+ if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Store the index
+ $v_header['index'] = $i;
+
+ // ----- Store the file position
+ $v_pos_entry = ftell($this->zip_fd);
+
+ // ----- Look for the specific extract rules
+ $v_extract = false;
+
+ // ----- Look for extract by name rule
+ if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
+ && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+ // ----- Look if the filename is in the list
+ for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
+
+ // ----- Look for a directory
+ if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
+
+ // ----- Look if the directory is in the filename path
+ if ( (strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
+ && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_extract = true;
+ }
+ }
+ // ----- Look for a filename
+ elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+ $v_extract = true;
+ }
+ }
+ }
+
+ // ----- Look for extract by ereg rule
+ // ereg() is deprecated with PHP 5.3
+ /*
+ else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
+ $v_extract = true;
+ }
+ }
+ */
+
+ // ----- Look for extract by preg rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
+ && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
+ $v_extract = true;
+ }
+ }
+
+ // ----- Look for extract by index rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
+ && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+ // ----- Look if the index is in the list
+ for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
+
+ if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+ $v_extract = true;
+ }
+ if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+ $j_start = $j+1;
+ }
+
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
+ break;
+ }
+ }
+ }
+
+ // ----- Look for no rule, which means extract all the archive
+ else {
+ $v_extract = true;
+ }
+
+ // ----- Check compression method
+ if ( ($v_extract)
+ && ( ($v_header['compression'] != 8)
+ && ($v_header['compression'] != 0))) {
+ $v_header['status'] = 'unsupported_compression';
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
+ "Filename '".$v_header['stored_filename']."' is "
+ ."compressed by an unsupported compression "
+ ."method (".$v_header['compression'].") ");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Check encrypted files
+ if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
+ $v_header['status'] = 'unsupported_encryption';
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ $this->privSwapBackMagicQuotes();
+
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
+ "Unsupported encryption for "
+ ." filename '".$v_header['stored_filename']
+ ."'");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look for real extraction
+ if (($v_extract) && ($v_header['status'] != 'ok')) {
+ $v_result = $this->privConvertHeader2FileInfo($v_header,
+ $p_file_list[$v_nb_extracted++]);
+ if ($v_result != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ $v_extract = false;
+ }
+
+ // ----- Look for real extraction
+ if ($v_extract)
+ {
+
+ // ----- Go to the file position
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_header['offset']))
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Look for extraction as string
+ if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
+
+ $v_string = '';
+
+ // ----- Extracting the file
+ $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Set the file content
+ $p_file_list[$v_nb_extracted]['content'] = $v_string;
+
+ // ----- Next extracted file
+ $v_nb_extracted++;
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ // ----- Look for extraction in standard output
+ elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
+ && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
+ // ----- Extracting the file in standard output
+ $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result;
+ }
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ // ----- Look for normal extraction
+ else {
+ // ----- Extracting the file
+ $v_result1 = $this->privExtractFile($v_header,
+ $p_path, $p_remove_path,
+ $p_remove_all_path,
+ $p_options);
+ if ($v_result1 < 1) {
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+ return $v_result1;
+ }
+
+ // ----- Get the only interesting attributes
+ if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ return $v_result;
+ }
+
+ // ----- Look for user callback abort
+ if ($v_result1 == 2) {
+ break;
+ }
+ }
+ }
+ }
+
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $this->privSwapBackMagicQuotes();
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ //
+ // 1 : ... ?
+ // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
+ // --------------------------------------------------------------------------------
+ function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Read the file header
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for all path to remove
+ if ($p_remove_all_path == true) {
+ // ----- Look for folder entry that not need to be extracted
+ if (($p_entry['external']&0x00000010)==0x00000010) {
+
+ $p_entry['status'] = "filtered";
+
+ return $v_result;
+ }
+
+ // ----- Get the basename of the path
+ $p_entry['filename'] = basename($p_entry['filename']);
+ }
+
+ // ----- Look for path to remove
+ else if ($p_remove_path != "")
+ {
+ if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2)
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "filtered";
+
+ // ----- Return
+ return $v_result;
+ }
+
+ $p_remove_path_size = strlen($p_remove_path);
+ if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path)
+ {
+
+ // ----- Remove the path
+ $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
+
+ }
+ }
+
+ // ----- Add the path
+ if ($p_path != '') {
+ $p_entry['filename'] = $p_path."/".$p_entry['filename'];
+ }
+
+ // ----- Check a base_dir_restriction
+ if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
+ $v_inclusion
+ = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
+ $p_entry['filename']);
+ if ($v_inclusion == 0) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
+ "Filename '".$p_entry['filename']."' is "
+ ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Look for specific actions while the file exist
+ if (file_exists($p_entry['filename']))
+ {
+
+ // ----- Look if file is a directory
+ if (is_dir($p_entry['filename']))
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "already_a_directory";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
+ "Filename '".$p_entry['filename']."' is "
+ ."already used by an existing directory");
+
+ return PclZip::errorCode();
+ }
+ }
+ // ----- Look if file is write protected
+ else if (!is_writeable($p_entry['filename']))
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_protected";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
+ "Filename '".$p_entry['filename']."' exists "
+ ."and is write protected");
+
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Look if the extracted file is older
+ else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
+ {
+ // ----- Change the file status
+ if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
+ && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
+ }
+ else {
+ $p_entry['status'] = "newer_exist";
+
+ // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
+ // For historical reason first PclZip implementation does not stop
+ // when this kind of error occurs.
+ if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
+ && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
+
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
+ "Newer version of '".$p_entry['filename']."' exists "
+ ."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
+
+ return PclZip::errorCode();
+ }
+ }
+ }
+ else {
+ }
+ }
+
+ // ----- Check the directory availability and create it if necessary
+ else {
+ if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
+ $v_dir_to_check = $p_entry['filename'];
+ else if (!strstr($p_entry['filename'], "/"))
+ $v_dir_to_check = "";
+ else
+ $v_dir_to_check = dirname($p_entry['filename']);
+
+ if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "path_creation_fail";
+
+ // ----- Return
+ //return $v_result;
+ $v_result = 1;
+ }
+ }
+ }
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external']&0x00000010)==0x00000010))
+ {
+ // ----- Look for not compressed file
+ if ($p_entry['compression'] == 0) {
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
+ {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_error";
+
+ // ----- Return
+ return $v_result;
+ }
+
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['compressed_size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ /* Try to speed up the code
+ $v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_binary_data, $v_read_size);
+ */
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Closing the destination file
+ fclose($v_dest_file);
+
+ // ----- Change the file mtime
+ touch($p_entry['filename'], $p_entry['mtime']);
+
+
+ }
+ else {
+ // ----- TBC
+ // Need to be finished
+ if (($p_entry['flag'] & 1) == 1) {
+ PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Look for using temporary file to unzip
+ if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
+ && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
+ || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
+ && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
+ $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
+ if ($v_result < PCLZIP_ERR_NO_ERROR) {
+ return $v_result;
+ }
+ }
+
+ // ----- Look for extract in memory
+ else {
+
+
+ // ----- Read the compressed file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ $v_file_content = @gzinflate($v_buffer);
+ unset($v_buffer);
+ if ($v_file_content === FALSE) {
+
+ // ----- Change the file status
+ // TBC
+ $p_entry['status'] = "error";
+
+ return $v_result;
+ }
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+
+ // ----- Change the file status
+ $p_entry['status'] = "write_error";
+
+ return $v_result;
+ }
+
+ // ----- Write the uncompressed data
+ @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
+ unset($v_file_content);
+
+ // ----- Closing the destination file
+ @fclose($v_dest_file);
+
+ }
+
+ // ----- Change the file mtime
+ @touch($p_entry['filename'], $p_entry['mtime']);
+ }
+
+ // ----- Look for chmod option
+ if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
+
+ // ----- Change the mode of the file
+ @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
+ }
+
+ }
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+ }
+
+ // ----- Look for post-extract callback
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileUsingTempFile()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privExtractFileUsingTempFile(&$p_entry, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Creates a temporary file
+ $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
+ if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
+ fclose($v_file);
+ PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Write gz file format header
+ $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
+ @fwrite($v_dest_file, $v_binary_data, 10);
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['compressed_size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Write gz file format footer
+ $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
+ @fwrite($v_dest_file, $v_binary_data, 8);
+
+ // ----- Close the temporary file
+ @fclose($v_dest_file);
+
+ // ----- Opening destination file
+ if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
+ $p_entry['status'] = "write_error";
+ return $v_result;
+ }
+
+ // ----- Open the temporary gz file
+ if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
+ @fclose($v_dest_file);
+ $p_entry['status'] = "read_error";
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
+ return PclZip::errorCode();
+ }
+
+
+ // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
+ $v_size = $p_entry['size'];
+ while ($v_size != 0) {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($v_src_file, $v_read_size);
+ //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
+ @fwrite($v_dest_file, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+ @fclose($v_dest_file);
+ @gzclose($v_src_file);
+
+ // ----- Delete the temporary file
+ @unlink($v_gzip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileInOutput()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privExtractFileInOutput(&$p_entry, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Read the file header
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
+ return $v_result;
+ }
+
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+ // ----- Trace
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external']&0x00000010)==0x00000010)) {
+ // ----- Look for not compressed file
+ if ($p_entry['compressed_size'] == $p_entry['size']) {
+
+ // ----- Read the file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Send the file to the output
+ echo $v_buffer;
+ unset($v_buffer);
+ }
+ else {
+
+ // ----- Read the compressed file in a buffer (one shot)
+ $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ $v_file_content = gzinflate($v_buffer);
+ unset($v_buffer);
+
+ // ----- Send the file to the output
+ echo $v_file_content;
+ unset($v_file_content);
+ }
+ }
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+ }
+
+ // ----- Look for post-extract callback
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privExtractFileAsString()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)
+ {
+ $v_result=1;
+
+ // ----- Read the file header
+ $v_header = array();
+ if (($v_result = $this->privReadFileHeader($v_header)) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+
+ // ----- Check that the file header is coherent with $p_entry info
+ if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
+ // TBC
+ }
+
+ // ----- Look for pre-extract callback
+ if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
+ if ($v_result == 0) {
+ // ----- Change the file status
+ $p_entry['status'] = "skipped";
+ $v_result = 1;
+ }
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ // ----- This status is internal and will be changed in 'skipped'
+ $p_entry['status'] = "aborted";
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+
+ // ----- Update the informations
+ // Only some fields can be modified
+ $p_entry['filename'] = $v_local_header['filename'];
+ }
+
+
+ // ----- Look if extraction should be done
+ if ($p_entry['status'] == 'ok') {
+
+ // ----- Do the extraction (if not a folder)
+ if (!(($p_entry['external']&0x00000010)==0x00000010)) {
+ // ----- Look for not compressed file
+ // if ($p_entry['compressed_size'] == $p_entry['size'])
+ if ($p_entry['compression'] == 0) {
+
+ // ----- Reading the file
+ $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
+ }
+ else {
+
+ // ----- Reading the file
+ $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
+
+ // ----- Decompress the file
+ if (($p_string = @gzinflate($v_data)) === FALSE) {
+ // TBC
+ }
+ }
+
+ // ----- Trace
+ }
+ else {
+ // TBC : error : can not extract a folder in a string
+ }
+
+ }
+
+ // ----- Change abort status
+ if ($p_entry['status'] == "aborted") {
+ $p_entry['status'] = "skipped";
+ }
+
+ // ----- Look for post-extract callback
+ elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
+
+ // ----- Generate a local information
+ $v_local_header = array();
+ $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
+
+ // ----- Swap the content to header
+ $v_local_header['content'] = $p_string;
+ $p_string = '';
+
+ // ----- Call the callback
+ // Here I do not use call_user_func() because I need to send a reference to the
+ // header.
+ $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
+
+ // ----- Swap back the content to header
+ $p_string = $v_local_header['content'];
+ unset($v_local_header['content']);
+
+ // ----- Look for abort result
+ if ($v_result == 2) {
+ $v_result = PCLZIP_ERR_USER_ABORTED;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privReadFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // ----- Read the 4 bytes signature
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] != 0x04034b50)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the first 42 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 26);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 26)
+ {
+ $p_header['filename'] = "";
+ $p_header['status'] = "invalid_header";
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
+
+ // ----- Get filename
+ $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
+
+ // ----- Get extra_fields
+ if ($v_data['extra_len'] != 0) {
+ $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
+ }
+ else {
+ $p_header['extra'] = '';
+ }
+
+ // ----- Extract properties
+ $p_header['version_extracted'] = $v_data['version'];
+ $p_header['compression'] = $v_data['compression'];
+ $p_header['size'] = $v_data['size'];
+ $p_header['compressed_size'] = $v_data['compressed_size'];
+ $p_header['crc'] = $v_data['crc'];
+ $p_header['flag'] = $v_data['flag'];
+ $p_header['filename_len'] = $v_data['filename_len'];
+
+ // ----- Recuperate date in UNIX format
+ $p_header['mdate'] = $v_data['mdate'];
+ $p_header['mtime'] = $v_data['mtime'];
+ if ($p_header['mdate'] && $p_header['mtime'])
+ {
+ // ----- Extract time
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+ $v_seconde = ($p_header['mtime'] & 0x001F)*2;
+
+ // ----- Extract date
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+ $v_day = $p_header['mdate'] & 0x001F;
+
+ // ----- Get UNIX date format
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+ }
+ else
+ {
+ $p_header['mtime'] = time();
+ }
+
+ // TBC
+ //for(reset($v_data); $key = key($v_data); next($v_data)) {
+ //}
+
+ // ----- Set the stored filename
+ $p_header['stored_filename'] = $p_header['filename'];
+
+ // ----- Set the status field
+ $p_header['status'] = "ok";
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadCentralFileHeader()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privReadCentralFileHeader(&$p_header)
+ {
+ $v_result=1;
+
+ // ----- Read the 4 bytes signature
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] != 0x02014b50)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the first 42 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 42);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 42)
+ {
+ $p_header['filename'] = "";
+ $p_header['status'] = "invalid_header";
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);
+
+ // ----- Get filename
+ if ($p_header['filename_len'] != 0)
+ $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
+ else
+ $p_header['filename'] = '';
+
+ // ----- Get extra
+ if ($p_header['extra_len'] != 0)
+ $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
+ else
+ $p_header['extra'] = '';
+
+ // ----- Get comment
+ if ($p_header['comment_len'] != 0)
+ $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
+ else
+ $p_header['comment'] = '';
+
+ // ----- Extract properties
+
+ // ----- Recuperate date in UNIX format
+ //if ($p_header['mdate'] && $p_header['mtime'])
+ // TBC : bug : this was ignoring time with 0/0/0
+ if (1)
+ {
+ // ----- Extract time
+ $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
+ $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
+ $v_seconde = ($p_header['mtime'] & 0x001F)*2;
+
+ // ----- Extract date
+ $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
+ $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
+ $v_day = $p_header['mdate'] & 0x001F;
+
+ // ----- Get UNIX date format
+ $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
+
+ }
+ else
+ {
+ $p_header['mtime'] = time();
+ }
+
+ // ----- Set the stored filename
+ $p_header['stored_filename'] = $p_header['filename'];
+
+ // ----- Set default status to ok
+ $p_header['status'] = 'ok';
+
+ // ----- Look if it is a directory
+ if (substr($p_header['filename'], -1) == '/') {
+ //$p_header['external'] = 0x41FF0010;
+ $p_header['external'] = 0x00000010;
+ }
+
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privCheckFileHeaders()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // 1 on success,
+ // 0 on error;
+ // --------------------------------------------------------------------------------
+ function privCheckFileHeaders(&$p_local_header, &$p_central_header)
+ {
+ $v_result=1;
+
+ // ----- Check the static values
+ // TBC
+ if ($p_local_header['filename'] != $p_central_header['filename']) {
+ }
+ if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
+ }
+ if ($p_local_header['flag'] != $p_central_header['flag']) {
+ }
+ if ($p_local_header['compression'] != $p_central_header['compression']) {
+ }
+ if ($p_local_header['mtime'] != $p_central_header['mtime']) {
+ }
+ if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
+ }
+
+ // ----- Look for flag bit 3
+ if (($p_local_header['flag'] & 8) == 8) {
+ $p_local_header['size'] = $p_central_header['size'];
+ $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
+ $p_local_header['crc'] = $p_central_header['crc'];
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privReadEndCentralDir()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privReadEndCentralDir(&$p_central_dir)
+ {
+ $v_result=1;
+
+ // ----- Go to the end of the zip file
+ $v_size = filesize($this->zipname);
+ @fseek($this->zip_fd, $v_size);
+ if (@ftell($this->zip_fd) != $v_size)
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- First try : look if this is an archive with no commentaries (most of the time)
+ // in this case the end of central dir is at 22 bytes of the file end
+ $v_found = 0;
+ if ($v_size > 26) {
+ @fseek($this->zip_fd, $v_size-22);
+ if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22))
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read for bytes
+ $v_binary_data = @fread($this->zip_fd, 4);
+ $v_data = @unpack('Vid', $v_binary_data);
+
+ // ----- Check signature
+ if ($v_data['id'] == 0x06054b50) {
+ $v_found = 1;
+ }
+
+ $v_pos = ftell($this->zip_fd);
+ }
+
+ // ----- Go back to the maximum possible size of the Central Dir End Record
+ if (!$v_found) {
+ $v_maximum_size = 65557; // 0xFFFF + 22;
+ if ($v_maximum_size > $v_size)
+ $v_maximum_size = $v_size;
+ @fseek($this->zip_fd, $v_size-$v_maximum_size);
+ if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size))
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\'');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read byte per byte in order to find the signature
+ $v_pos = ftell($this->zip_fd);
+ $v_bytes = 0x00000000;
+ while ($v_pos < $v_size)
+ {
+ // ----- Read a byte
+ $v_byte = @fread($this->zip_fd, 1);
+
+ // ----- Add the byte
+ //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
+ // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
+ // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
+ $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
+
+ // ----- Compare the bytes
+ if ($v_bytes == 0x504b0506)
+ {
+ $v_pos++;
+ break;
+ }
+
+ $v_pos++;
+ }
+
+ // ----- Look if not found end of central dir
+ if ($v_pos == $v_size)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Read the first 18 bytes of the header
+ $v_binary_data = fread($this->zip_fd, 18);
+
+ // ----- Look for invalid block size
+ if (strlen($v_binary_data) != 18)
+ {
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data));
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Extract the values
+ $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
+
+ // ----- Check the global size
+ if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
+
+ // ----- Removed in release 2.2 see readme file
+ // The check of the file size is a little too strict.
+ // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
+ // While decrypted, zip has training 0 bytes
+ if (0) {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
+ 'The central dir is not at the end of the archive.'
+ .' Some trailing bytes exists after the archive.');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+ }
+
+ // ----- Get comment
+ if ($v_data['comment_size'] != 0) {
+ $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
+ }
+ else
+ $p_central_dir['comment'] = '';
+
+ $p_central_dir['entries'] = $v_data['entries'];
+ $p_central_dir['disk_entries'] = $v_data['disk_entries'];
+ $p_central_dir['offset'] = $v_data['offset'];
+ $p_central_dir['size'] = $v_data['size'];
+ $p_central_dir['disk'] = $v_data['disk'];
+ $p_central_dir['disk_start'] = $v_data['disk_start'];
+
+ // TBC
+ //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
+ //}
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDeleteByRule()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privDeleteByRule(&$p_result_list, &$p_options)
+ {
+ $v_result=1;
+ $v_list_detail = array();
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('rb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privCloseFd();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Scan all the files
+ // ----- Start at beginning of Central Dir
+ $v_pos_entry = $v_central_dir['offset'];
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_pos_entry))
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read each entry
+ $v_header_list = array();
+ $j_start = 0;
+ for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++)
+ {
+
+ // ----- Read the file header
+ $v_header_list[$v_nb_extracted] = array();
+ if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1)
+ {
+ // ----- Close the zip file
+ $this->privCloseFd();
+
+ return $v_result;
+ }
+
+
+ // ----- Store the index
+ $v_header_list[$v_nb_extracted]['index'] = $i;
+
+ // ----- Look for the specific extract rules
+ $v_found = false;
+
+ // ----- Look for extract by name rule
+ if ( (isset($p_options[PCLZIP_OPT_BY_NAME]))
+ && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
+
+ // ----- Look if the filename is in the list
+ for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
+
+ // ----- Look for a directory
+ if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
+
+ // ----- Look if the directory is in the filename path
+ if ( (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
+ && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_found = true;
+ }
+ elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */
+ && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {
+ $v_found = true;
+ }
+ }
+ // ----- Look for a filename
+ elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
+ $v_found = true;
+ }
+ }
+ }
+
+ // ----- Look for extract by ereg rule
+ // ereg() is deprecated with PHP 5.3
+ /*
+ else if ( (isset($p_options[PCLZIP_OPT_BY_EREG]))
+ && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
+
+ if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+ $v_found = true;
+ }
+ }
+ */
+
+ // ----- Look for extract by preg rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_PREG]))
+ && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
+
+ if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
+ $v_found = true;
+ }
+ }
+
+ // ----- Look for extract by index rule
+ else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX]))
+ && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
+
+ // ----- Look if the index is in the list
+ for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
+
+ if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
+ $v_found = true;
+ }
+ if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
+ $j_start = $j+1;
+ }
+
+ if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
+ break;
+ }
+ }
+ }
+ else {
+ $v_found = true;
+ }
+
+ // ----- Look for deletion
+ if ($v_found)
+ {
+ unset($v_header_list[$v_nb_extracted]);
+ }
+ else
+ {
+ $v_nb_extracted++;
+ }
+ }
+
+ // ----- Look if something need to be deleted
+ if ($v_nb_extracted > 0) {
+
+ // ----- Creates a temporay file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+ // ----- Creates a temporary zip archive
+ $v_temp_zip = new PclZip($v_zip_temp_name);
+
+ // ----- Open the temporary zip file in write mode
+ if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
+ $this->privCloseFd();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Look which file need to be kept
+ for ($i=0; $i<sizeof($v_header_list); $i++) {
+
+ // ----- Calculate the position of the header
+ @rewind($this->zip_fd);
+ if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Read the file header
+ $v_local_header = array();
+ if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Check that local file header is same as central file header
+ if ($this->privCheckFileHeaders($v_local_header,
+ $v_header_list[$i]) != 1) {
+ // TBC
+ }
+ unset($v_local_header);
+
+ // ----- Write the file header
+ if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read/write the data block
+ if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {
+ // ----- Close the zip file
+ $this->privCloseFd();
+ $v_temp_zip->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($v_temp_zip->zip_fd);
+
+ // ----- Re-Create the Central Dir files header
+ for ($i=0; $i<sizeof($v_header_list); $i++) {
+ // ----- Create the file header
+ if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Transform the header to a 'usable' info
+ $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
+ }
+
+
+ // ----- Zip file comment
+ $v_comment = '';
+ if (isset($p_options[PCLZIP_OPT_COMMENT])) {
+ $v_comment = $p_options[PCLZIP_OPT_COMMENT];
+ }
+
+ // ----- Calculate the size of the central header
+ $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset;
+
+ // ----- Create the central dir footer
+ if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {
+ // ----- Reset the file list
+ unset($v_header_list);
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+ @unlink($v_zip_temp_name);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Close
+ $v_temp_zip->privCloseFd();
+ $this->privCloseFd();
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Destroy the temporary archive
+ unset($v_temp_zip);
+ }
+
+ // ----- Remove every files : reset the file
+ else if ($v_central_dir['entries'] != 0) {
+ $this->privCloseFd();
+
+ if (($v_result = $this->privOpenFd('wb')) != 1) {
+ return $v_result;
+ }
+
+ if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {
+ return $v_result;
+ }
+
+ $this->privCloseFd();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDirCheck()
+ // Description :
+ // Check if a directory exists, if not it creates it and all the parents directory
+ // which may be useful.
+ // Parameters :
+ // $p_dir : Directory path to check.
+ // Return Values :
+ // 1 : OK
+ // -1 : Unable to create directory
+ // --------------------------------------------------------------------------------
+ function privDirCheck($p_dir, $p_is_dir=false)
+ {
+ $v_result = 1;
+
+
+ // ----- Remove the final '/'
+ if (($p_is_dir) && (substr($p_dir, -1)=='/'))
+ {
+ $p_dir = substr($p_dir, 0, strlen($p_dir)-1);
+ }
+
+ // ----- Check the directory availability
+ if ((is_dir($p_dir)) || ($p_dir == ""))
+ {
+ return 1;
+ }
+
+ // ----- Extract parent directory
+ $p_parent_dir = dirname($p_dir);
+
+ // ----- Just a check
+ if ($p_parent_dir != $p_dir)
+ {
+ // ----- Look for parent directory
+ if ($p_parent_dir != "")
+ {
+ if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
+ {
+ return $v_result;
+ }
+ }
+ }
+
+ // ----- Create the directory
+ if (!@mkdir($p_dir, 0777))
+ {
+ // ----- Error log
+ PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privMerge()
+ // Description :
+ // If $p_archive_to_add does not exist, the function exit with a success result.
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privMerge(&$p_archive_to_add)
+ {
+ $v_result=1;
+
+ // ----- Look if the archive_to_add exists
+ if (!is_file($p_archive_to_add->zipname))
+ {
+
+ // ----- Nothing to merge, so merge is a success
+ $v_result = 1;
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Look if the archive exists
+ if (!is_file($this->zipname))
+ {
+
+ // ----- Do a duplicate
+ $v_result = $this->privDuplicate($p_archive_to_add->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('rb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir = array();
+ if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
+ {
+ $this->privCloseFd();
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($this->zip_fd);
+
+ // ----- Open the archive_to_add file
+ if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
+ {
+ $this->privCloseFd();
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Read the central directory informations
+ $v_central_dir_to_add = array();
+ if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
+ {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ return $v_result;
+ }
+
+ // ----- Go to beginning of File
+ @rewind($p_archive_to_add->zip_fd);
+
+ // ----- Creates a temporay file
+ $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
+ {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = $v_central_dir['offset'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Copy the files from the archive_to_add into the temporary file
+ $v_size = $v_central_dir_to_add['offset'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Store the offset of the central dir
+ $v_offset = @ftell($v_zip_temp_fd);
+
+ // ----- Copy the block of file headers from the old archive
+ $v_size = $v_central_dir['size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($this->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Copy the block of file headers from the archive_to_add
+ $v_size = $v_central_dir_to_add['size'];
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
+ @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Merge the file comments
+ $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
+
+ // ----- Calculate the size of the (new) central header
+ $v_size = @ftell($v_zip_temp_fd)-$v_offset;
+
+ // ----- Swap the file descriptor
+ // Here is a trick : I swap the temporary fd with the zip fd, in order to use
+ // the following methods on the temporary fil and not the real archive fd
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Create the central dir footer
+ if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
+ {
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+ @fclose($v_zip_temp_fd);
+ $this->zip_fd = null;
+
+ // ----- Reset the file list
+ unset($v_header_list);
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Swap back the file descriptor
+ $v_swap = $this->zip_fd;
+ $this->zip_fd = $v_zip_temp_fd;
+ $v_zip_temp_fd = $v_swap;
+
+ // ----- Close
+ $this->privCloseFd();
+ $p_archive_to_add->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Delete the zip file
+ // TBC : I should test the result ...
+ @unlink($this->zipname);
+
+ // ----- Rename the temporary file
+ // TBC : I should test the result ...
+ //@rename($v_zip_temp_name, $this->zipname);
+ PclZipUtilRename($v_zip_temp_name, $this->zipname);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDuplicate()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privDuplicate($p_archive_filename)
+ {
+ $v_result=1;
+
+ // ----- Look if the $p_archive_filename exists
+ if (!is_file($p_archive_filename))
+ {
+
+ // ----- Nothing to duplicate, so duplicate is a success.
+ $v_result = 1;
+
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the zip file
+ if (($v_result=$this->privOpenFd('wb')) != 1)
+ {
+ // ----- Return
+ return $v_result;
+ }
+
+ // ----- Open the temporary file in write mode
+ if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
+ {
+ $this->privCloseFd();
+
+ PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
+
+ // ----- Return
+ return PclZip::errorCode();
+ }
+
+ // ----- Copy the files from the archive to the temporary file
+ // TBC : Here I should better append the file and go back to erase the central dir
+ $v_size = filesize($p_archive_filename);
+ while ($v_size != 0)
+ {
+ $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = fread($v_zip_temp_fd, $v_read_size);
+ @fwrite($this->zip_fd, $v_buffer, $v_read_size);
+ $v_size -= $v_read_size;
+ }
+
+ // ----- Close
+ $this->privCloseFd();
+
+ // ----- Close the temporary file
+ @fclose($v_zip_temp_fd);
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privErrorLog()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privErrorLog($p_error_code=0, $p_error_string='')
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ PclError($p_error_code, $p_error_string);
+ }
+ else {
+ $this->error_code = $p_error_code;
+ $this->error_string = $p_error_string;
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privErrorReset()
+ // Description :
+ // Parameters :
+ // --------------------------------------------------------------------------------
+ function privErrorReset()
+ {
+ if (PCLZIP_ERROR_EXTERNAL == 1) {
+ PclErrorReset();
+ }
+ else {
+ $this->error_code = 0;
+ $this->error_string = '';
+ }
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privDisableMagicQuotes()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privDisableMagicQuotes()
+ {
+ $v_result=1;
+
+ // ----- Look if function exists
+ if ( (!function_exists("get_magic_quotes_runtime"))
+ || (!function_exists("set_magic_quotes_runtime"))) {
+ return $v_result;
+ }
+
+ // ----- Look if already done
+ if ($this->magic_quotes_status != -1) {
+ return $v_result;
+ }
+
+ // ----- Get and memorize the magic_quote value
+ $this->magic_quotes_status = @get_magic_quotes_runtime();
+
+ // ----- Disable magic_quotes
+ if ($this->magic_quotes_status == 1) {
+ @set_magic_quotes_runtime(0);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : privSwapBackMagicQuotes()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function privSwapBackMagicQuotes()
+ {
+ $v_result=1;
+
+ // ----- Look if function exists
+ if ( (!function_exists("get_magic_quotes_runtime"))
+ || (!function_exists("set_magic_quotes_runtime"))) {
+ return $v_result;
+ }
+
+ // ----- Look if something to do
+ if ($this->magic_quotes_status != -1) {
+ return $v_result;
+ }
+
+ // ----- Swap back magic_quotes
+ if ($this->magic_quotes_status == 1) {
+ @set_magic_quotes_runtime($this->magic_quotes_status);
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ }
+ // End of class
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilPathReduction()
+ // Description :
+ // Parameters :
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function PclZipUtilPathReduction($p_dir)
+ {
+ $v_result = "";
+
+ // ----- Look for not empty path
+ if ($p_dir != "") {
+ // ----- Explode path by directory names
+ $v_list = explode("/", $p_dir);
+
+ // ----- Study directories from last to first
+ $v_skip = 0;
+ for ($i=sizeof($v_list)-1; $i>=0; $i--) {
+ // ----- Look for current path
+ if ($v_list[$i] == ".") {
+ // ----- Ignore this directory
+ // Should be the first $i=0, but no check is done
+ }
+ else if ($v_list[$i] == "..") {
+ $v_skip++;
+ }
+ else if ($v_list[$i] == "") {
+ // ----- First '/' i.e. root slash
+ if ($i == 0) {
+ $v_result = "/".$v_result;
+ if ($v_skip > 0) {
+ // ----- It is an invalid path, so the path is not modified
+ // TBC
+ $v_result = $p_dir;
+ $v_skip = 0;
+ }
+ }
+ // ----- Last '/' i.e. indicates a directory
+ else if ($i == (sizeof($v_list)-1)) {
+ $v_result = $v_list[$i];
+ }
+ // ----- Double '/' inside the path
+ else {
+ // ----- Ignore only the double '//' in path,
+ // but not the first and last '/'
+ }
+ }
+ else {
+ // ----- Look for item to skip
+ if ($v_skip > 0) {
+ $v_skip--;
+ }
+ else {
+ $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
+ }
+ }
+ }
+
+ // ----- Look for skip
+ if ($v_skip > 0) {
+ while ($v_skip > 0) {
+ $v_result = '../'.$v_result;
+ $v_skip--;
+ }
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilPathInclusion()
+ // Description :
+ // This function indicates if the path $p_path is under the $p_dir tree. Or,
+ // said in an other way, if the file or sub-dir $p_path is inside the dir
+ // $p_dir.
+ // The function indicates also if the path is exactly the same as the dir.
+ // This function supports path with duplicated '/' like '//', but does not
+ // support '.' or '..' statements.
+ // Parameters :
+ // Return Values :
+ // 0 if $p_path is not inside directory $p_dir
+ // 1 if $p_path is inside directory $p_dir
+ // 2 if $p_path is exactly the same as $p_dir
+ // --------------------------------------------------------------------------------
+ function PclZipUtilPathInclusion($p_dir, $p_path)
+ {
+ $v_result = 1;
+
+ // ----- Look for path beginning by ./
+ if ( ($p_dir == '.')
+ || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
+ $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
+ }
+ if ( ($p_path == '.')
+ || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
+ $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
+ }
+
+ // ----- Explode dir and path by directory separator
+ $v_list_dir = explode("/", $p_dir);
+ $v_list_dir_size = sizeof($v_list_dir);
+ $v_list_path = explode("/", $p_path);
+ $v_list_path_size = sizeof($v_list_path);
+
+ // ----- Study directories paths
+ $i = 0;
+ $j = 0;
+ while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {
+
+ // ----- Look for empty dir (path reduction)
+ if ($v_list_dir[$i] == '') {
+ $i++;
+ continue;
+ }
+ if ($v_list_path[$j] == '') {
+ $j++;
+ continue;
+ }
+
+ // ----- Compare the items
+ if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) {
+ $v_result = 0;
+ }
+
+ // ----- Next items
+ $i++;
+ $j++;
+ }
+
+ // ----- Look if everything seems to be the same
+ if ($v_result) {
+ // ----- Skip all the empty items
+ while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++;
+ while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++;
+
+ if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
+ // ----- There are exactly the same
+ $v_result = 2;
+ }
+ else if ($i < $v_list_dir_size) {
+ // ----- The path is shorter than the dir
+ $v_result = 0;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilCopyBlock()
+ // Description :
+ // Parameters :
+ // $p_mode : read/write compression mode
+ // 0 : src & dest normal
+ // 1 : src gzip, dest normal
+ // 2 : src normal, dest gzip
+ // 3 : src & dest gzip
+ // Return Values :
+ // --------------------------------------------------------------------------------
+ function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0)
+ {
+ $v_result = 1;
+
+ if ($p_mode==0)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_src, $v_read_size);
+ @fwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+ else if ($p_mode==1)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($p_src, $v_read_size);
+ @fwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+ else if ($p_mode==2)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @fread($p_src, $v_read_size);
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+ else if ($p_mode==3)
+ {
+ while ($p_size != 0)
+ {
+ $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);
+ $v_buffer = @gzread($p_src, $v_read_size);
+ @gzwrite($p_dest, $v_buffer, $v_read_size);
+ $p_size -= $v_read_size;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilRename()
+ // Description :
+ // This function tries to do a simple rename() function. If it fails, it
+ // tries to copy the $p_src file in a new $p_dest file and then unlink the
+ // first one.
+ // Parameters :
+ // $p_src : Old filename
+ // $p_dest : New filename
+ // Return Values :
+ // 1 on success, 0 on failure.
+ // --------------------------------------------------------------------------------
+ function PclZipUtilRename($p_src, $p_dest)
+ {
+ $v_result = 1;
+
+ // ----- Try to rename the files
+ if (!@rename($p_src, $p_dest)) {
+
+ // ----- Try to copy & unlink the src
+ if (!@copy($p_src, $p_dest)) {
+ $v_result = 0;
+ }
+ else if (!@unlink($p_src)) {
+ $v_result = 0;
+ }
+ }
+
+ // ----- Return
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilOptionText()
+ // Description :
+ // Translate option value in text. Mainly for debug purpose.
+ // Parameters :
+ // $p_option : the option value.
+ // Return Values :
+ // The option text value.
+ // --------------------------------------------------------------------------------
+ function PclZipUtilOptionText($p_option)
+ {
+
+ $v_list = get_defined_constants();
+ for (reset($v_list); $v_key = key($v_list); next($v_list)) {
+ $v_prefix = substr($v_key, 0, 10);
+ if (( ($v_prefix == 'PCLZIP_OPT')
+ || ($v_prefix == 'PCLZIP_CB_')
+ || ($v_prefix == 'PCLZIP_ATT'))
+ && ($v_list[$v_key] == $p_option)) {
+ return $v_key;
+ }
+ }
+
+ $v_result = 'Unknown';
+
+ return $v_result;
+ }
+ // --------------------------------------------------------------------------------
+
+ // --------------------------------------------------------------------------------
+ // Function : PclZipUtilTranslateWinPath()
+ // Description :
+ // Translate windows path by replacing '\' by '/' and optionally removing
+ // drive letter.
+ // Parameters :
+ // $p_path : path to translate.
+ // $p_remove_disk_letter : true | false
+ // Return Values :
+ // The path translated.
+ // --------------------------------------------------------------------------------
+ function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true)
+ {
+ if (stristr(php_uname(), 'windows')) {
+ // ----- Look for potential disk letter
+ if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
+ $p_path = substr($p_path, $v_position+1);
+ }
+ // ----- Change potential windows directory separator
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
+ $p_path = strtr($p_path, '\\', '/');
+ }
+ }
+ return $p_path;
+ }
+ // --------------------------------------------------------------------------------
+
+
+?>
diff --git a/src/wp-admin/includes/class-wp-comments-list-table.php b/src/wp-admin/includes/class-wp-comments-list-table.php
new file mode 100644
index 0000000000..23f3169d04
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-comments-list-table.php
@@ -0,0 +1,561 @@
+<?php
+/**
+ * Comments and Post Comments List Table classes.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ */
+
+/**
+ * Comments List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Comments_List_Table extends WP_List_Table {
+
+ var $checkbox = true;
+
+ var $pending_count = array();
+
+ function __construct( $args = array() ) {
+ global $post_id;
+
+ $post_id = isset( $_REQUEST['p'] ) ? absint( $_REQUEST['p'] ) : 0;
+
+ if ( get_option('show_avatars') )
+ add_filter( 'comment_author', 'floated_admin_avatar' );
+
+ parent::__construct( array(
+ 'plural' => 'comments',
+ 'singular' => 'comment',
+ 'ajax' => true,
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+ }
+
+ function ajax_user_can() {
+ return current_user_can('edit_posts');
+ }
+
+ function prepare_items() {
+ global $post_id, $comment_status, $search, $comment_type;
+
+ $comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all';
+ if ( !in_array( $comment_status, array( 'all', 'moderated', 'approved', 'spam', 'trash' ) ) )
+ $comment_status = 'all';
+
+ $comment_type = !empty( $_REQUEST['comment_type'] ) ? $_REQUEST['comment_type'] : '';
+
+ $search = ( isset( $_REQUEST['s'] ) ) ? $_REQUEST['s'] : '';
+
+ $user_id = ( isset( $_REQUEST['user_id'] ) ) ? $_REQUEST['user_id'] : '';
+
+ $orderby = ( isset( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : '';
+ $order = ( isset( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : '';
+
+ $comments_per_page = $this->get_per_page( $comment_status );
+
+ $doing_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
+
+ if ( isset( $_REQUEST['number'] ) ) {
+ $number = (int) $_REQUEST['number'];
+ }
+ else {
+ $number = $comments_per_page + min( 8, $comments_per_page ); // Grab a few extra
+ }
+
+ $page = $this->get_pagenum();
+
+ if ( isset( $_REQUEST['start'] ) ) {
+ $start = $_REQUEST['start'];
+ } else {
+ $start = ( $page - 1 ) * $comments_per_page;
+ }
+
+ if ( $doing_ajax && isset( $_REQUEST['offset'] ) ) {
+ $start += $_REQUEST['offset'];
+ }
+
+ $status_map = array(
+ 'moderated' => 'hold',
+ 'approved' => 'approve',
+ 'all' => '',
+ );
+
+ $args = array(
+ 'status' => isset( $status_map[$comment_status] ) ? $status_map[$comment_status] : $comment_status,
+ 'search' => $search,
+ 'user_id' => $user_id,
+ 'offset' => $start,
+ 'number' => $number,
+ 'post_id' => $post_id,
+ 'type' => $comment_type,
+ 'orderby' => $orderby,
+ 'order' => $order,
+ );
+
+ $_comments = get_comments( $args );
+
+ update_comment_cache( $_comments );
+
+ $this->items = array_slice( $_comments, 0, $comments_per_page );
+ $this->extra_items = array_slice( $_comments, $comments_per_page );
+
+ $total_comments = get_comments( array_merge( $args, array('count' => true, 'offset' => 0, 'number' => 0) ) );
+
+ $_comment_post_ids = array();
+ foreach ( $_comments as $_c ) {
+ $_comment_post_ids[] = $_c->comment_post_ID;
+ }
+
+ $_comment_post_ids = array_unique( $_comment_post_ids );
+
+ $this->pending_count = get_pending_comments_num( $_comment_post_ids );
+
+ $this->set_pagination_args( array(
+ 'total_items' => $total_comments,
+ 'per_page' => $comments_per_page,
+ ) );
+ }
+
+ function get_per_page( $comment_status = 'all' ) {
+ $comments_per_page = $this->get_items_per_page( 'edit_comments_per_page' );
+ $comments_per_page = apply_filters( 'comments_per_page', $comments_per_page, $comment_status );
+ return $comments_per_page;
+ }
+
+ function no_items() {
+ global $comment_status;
+
+ if ( 'moderated' == $comment_status )
+ _e( 'No comments awaiting moderation.' );
+ else
+ _e( 'No comments found.' );
+ }
+
+ function get_views() {
+ global $post_id, $comment_status, $comment_type;
+
+ $status_links = array();
+ $num_comments = ( $post_id ) ? wp_count_comments( $post_id ) : wp_count_comments();
+ //, number_format_i18n($num_comments->moderated) ), "<span class='comment-count'>" . number_format_i18n($num_comments->moderated) . "</span>"),
+ //, number_format_i18n($num_comments->spam) ), "<span class='spam-comment-count'>" . number_format_i18n($num_comments->spam) . "</span>")
+ $stati = array(
+ 'all' => _nx_noop('All', 'All', 'comments'), // singular not used
+ 'moderated' => _n_noop('Pending <span class="count">(<span class="pending-count">%s</span>)</span>', 'Pending <span class="count">(<span class="pending-count">%s</span>)</span>'),
+ 'approved' => _n_noop('Approved', 'Approved'), // singular not used
+ 'spam' => _n_noop('Spam <span class="count">(<span class="spam-count">%s</span>)</span>', 'Spam <span class="count">(<span class="spam-count">%s</span>)</span>'),
+ 'trash' => _n_noop('Trash <span class="count">(<span class="trash-count">%s</span>)</span>', 'Trash <span class="count">(<span class="trash-count">%s</span>)</span>')
+ );
+
+ if ( !EMPTY_TRASH_DAYS )
+ unset($stati['trash']);
+
+ $link = 'edit-comments.php';
+ if ( !empty($comment_type) && 'all' != $comment_type )
+ $link = add_query_arg( 'comment_type', $comment_type, $link );
+
+ foreach ( $stati as $status => $label ) {
+ $class = ( $status == $comment_status ) ? ' class="current"' : '';
+
+ if ( !isset( $num_comments->$status ) )
+ $num_comments->$status = 10;
+ $link = add_query_arg( 'comment_status', $status, $link );
+ if ( $post_id )
+ $link = add_query_arg( 'p', absint( $post_id ), $link );
+ /*
+ // I toyed with this, but decided against it. Leaving it in here in case anyone thinks it is a good idea. ~ Mark
+ if ( !empty( $_REQUEST['s'] ) )
+ $link = add_query_arg( 's', esc_attr( wp_unslash( $_REQUEST['s'] ) ), $link );
+ */
+ $status_links[$status] = "<a href='$link'$class>" . sprintf(
+ translate_nooped_plural( $label, $num_comments->$status ),
+ number_format_i18n( $num_comments->$status )
+ ) . '</a>';
+ }
+
+ $status_links = apply_filters( 'comment_status_links', $status_links );
+ return $status_links;
+ }
+
+ function get_bulk_actions() {
+ global $comment_status;
+
+ $actions = array();
+ if ( in_array( $comment_status, array( 'all', 'approved' ) ) )
+ $actions['unapprove'] = __( 'Unapprove' );
+ if ( in_array( $comment_status, array( 'all', 'moderated' ) ) )
+ $actions['approve'] = __( 'Approve' );
+ if ( in_array( $comment_status, array( 'all', 'moderated', 'approved' ) ) )
+ $actions['spam'] = _x( 'Mark as Spam', 'comment' );
+
+ if ( 'trash' == $comment_status )
+ $actions['untrash'] = __( 'Restore' );
+ elseif ( 'spam' == $comment_status )
+ $actions['unspam'] = _x( 'Not Spam', 'comment' );
+
+ if ( in_array( $comment_status, array( 'trash', 'spam' ) ) || !EMPTY_TRASH_DAYS )
+ $actions['delete'] = __( 'Delete Permanently' );
+ else
+ $actions['trash'] = __( 'Move to Trash' );
+
+ return $actions;
+ }
+
+ function extra_tablenav( $which ) {
+ global $comment_status, $comment_type;
+?>
+ <div class="alignleft actions">
+<?php
+ if ( 'top' == $which ) {
+?>
+ <select name="comment_type">
+ <option value=""><?php _e( 'Show all comment types' ); ?></option>
+<?php
+ $comment_types = apply_filters( 'admin_comment_types_dropdown', array(
+ 'comment' => __( 'Comments' ),
+ 'pings' => __( 'Pings' ),
+ ) );
+
+ foreach ( $comment_types as $type => $label )
+ echo "\t<option value='" . esc_attr( $type ) . "'" . selected( $comment_type, $type, false ) . ">$label</option>\n";
+ ?>
+ </select>
+<?php
+ do_action( 'restrict_manage_comments' );
+ submit_button( __( 'Filter' ), 'button', false, false, array( 'id' => 'post-query-submit' ) );
+ }
+
+ if ( ( 'spam' == $comment_status || 'trash' == $comment_status ) && current_user_can( 'moderate_comments' ) ) {
+ wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
+ $title = ( 'spam' == $comment_status ) ? esc_attr__( 'Empty Spam' ) : esc_attr__( 'Empty Trash' );
+ submit_button( $title, 'apply', 'delete_all', false );
+ }
+ do_action( 'manage_comments_nav', $comment_status );
+ echo '</div>';
+ }
+
+ function current_action() {
+ if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
+ return 'delete_all';
+
+ return parent::current_action();
+ }
+
+ function get_columns() {
+ global $post_id;
+
+ $columns = array();
+
+ if ( $this->checkbox )
+ $columns['cb'] = '<input type="checkbox" />';
+
+ $columns['author'] = __( 'Author' );
+ $columns['comment'] = _x( 'Comment', 'column name' );
+
+ if ( !$post_id )
+ $columns['response'] = _x( 'In Response To', 'column name' );
+
+ return $columns;
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'author' => 'comment_author',
+ 'response' => 'comment_post_ID'
+ );
+ }
+
+ function display() {
+ extract( $this->_args );
+
+ wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
+
+ $this->display_tablenav( 'top' );
+
+?>
+<table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
+ <thead>
+ <tr>
+ <?php $this->print_column_headers(); ?>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr>
+ <?php $this->print_column_headers( false ); ?>
+ </tr>
+ </tfoot>
+
+ <tbody id="the-comment-list" data-wp-lists="list:comment">
+ <?php $this->display_rows_or_placeholder(); ?>
+ </tbody>
+
+ <tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;">
+ <?php $this->items = $this->extra_items; $this->display_rows(); ?>
+ </tbody>
+</table>
+<?php
+
+ $this->display_tablenav( 'bottom' );
+ }
+
+ function single_row( $a_comment ) {
+ global $post, $comment;
+
+ $comment = $a_comment;
+ $the_comment_class = join( ' ', get_comment_class( wp_get_comment_status( $comment->comment_ID ) ) );
+
+ $post = get_post( $comment->comment_post_ID );
+
+ $this->user_can = current_user_can( 'edit_comment', $comment->comment_ID );
+
+ echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>";
+ $this->single_row_columns( $comment );
+ echo "</tr>\n";
+ }
+
+ function column_cb( $comment ) {
+ if ( $this->user_can ) { ?>
+ <label class="screen-reader-text" for="cb-select-<?php echo $comment->comment_ID; ?>"><?php _e( 'Select comment' ); ?></label>
+ <input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" />
+ <?php
+ }
+ }
+
+ function column_comment( $comment ) {
+ global $comment_status;
+ $post = get_post();
+
+ $user_can = $this->user_can;
+
+ $comment_url = esc_url( get_comment_link( $comment->comment_ID ) );
+ $the_comment_status = wp_get_comment_status( $comment->comment_ID );
+
+ if ( $user_can ) {
+ $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
+ $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
+
+ $url = "comment.php?c=$comment->comment_ID";
+
+ $approve_url = esc_url( $url . "&action=approvecomment&$approve_nonce" );
+ $unapprove_url = esc_url( $url . "&action=unapprovecomment&$approve_nonce" );
+ $spam_url = esc_url( $url . "&action=spamcomment&$del_nonce" );
+ $unspam_url = esc_url( $url . "&action=unspamcomment&$del_nonce" );
+ $trash_url = esc_url( $url . "&action=trashcomment&$del_nonce" );
+ $untrash_url = esc_url( $url . "&action=untrashcomment&$del_nonce" );
+ $delete_url = esc_url( $url . "&action=deletecomment&$del_nonce" );
+ }
+
+ echo '<div class="submitted-on">';
+ /* translators: 2: comment date, 3: comment time */
+ printf( __( 'Submitted on <a href="%1$s">%2$s at %3$s</a>' ), $comment_url,
+ /* translators: comment date format. See http://php.net/date */
+ get_comment_date( __( 'Y/m/d' ) ),
+ get_comment_date( get_option( 'time_format' ) )
+ );
+
+ if ( $comment->comment_parent ) {
+ $parent = get_comment( $comment->comment_parent );
+ $parent_link = esc_url( get_comment_link( $comment->comment_parent ) );
+ $name = get_comment_author( $parent->comment_ID );
+ printf( ' | '.__( 'In reply to <a href="%1$s">%2$s</a>.' ), $parent_link, $name );
+ }
+
+ echo '</div>';
+ comment_text();
+ if ( $user_can ) { ?>
+ <div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden">
+ <textarea class="comment" rows="1" cols="1"><?php echo esc_textarea( apply_filters( 'comment_edit_pre', $comment->comment_content ) ); ?></textarea>
+ <div class="author-email"><?php echo esc_attr( $comment->comment_author_email ); ?></div>
+ <div class="author"><?php echo esc_attr( $comment->comment_author ); ?></div>
+ <div class="author-url"><?php echo esc_attr( $comment->comment_author_url ); ?></div>
+ <div class="comment_status"><?php echo $comment->comment_approved; ?></div>
+ </div>
+ <?php
+ }
+
+ if ( $user_can ) {
+ // preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash
+ $actions = array(
+ 'approve' => '', 'unapprove' => '',
+ 'reply' => '',
+ 'quickedit' => '',
+ 'edit' => '',
+ 'spam' => '', 'unspam' => '',
+ 'trash' => '', 'untrash' => '', 'delete' => ''
+ );
+
+ if ( $comment_status && 'all' != $comment_status ) { // not looking at all comments
+ if ( 'approved' == $the_comment_status )
+ $actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=unapproved' class='vim-u vim-destructive' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
+ else if ( 'unapproved' == $the_comment_status )
+ $actions['approve'] = "<a href='$approve_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=approved' class='vim-a vim-destructive' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
+ } else {
+ $actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
+ $actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
+ }
+
+ if ( 'spam' != $the_comment_status && 'trash' != $the_comment_status ) {
+ $actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' title='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
+ } elseif ( 'spam' == $the_comment_status ) {
+ $actions['unspam'] = "<a href='$unspam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:unspam=1' class='vim-z vim-destructive'>" . _x( 'Not Spam', 'comment' ) . '</a>';
+ } elseif ( 'trash' == $the_comment_status ) {
+ $actions['untrash'] = "<a href='$untrash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:untrash=1' class='vim-z vim-destructive'>" . __( 'Restore' ) . '</a>';
+ }
+
+ if ( 'spam' == $the_comment_status || 'trash' == $the_comment_status || !EMPTY_TRASH_DAYS ) {
+ $actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::delete=1' class='delete vim-d vim-destructive'>" . __( 'Delete Permanently' ) . '</a>';
+ } else {
+ $actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x( 'Trash', 'verb' ) . '</a>';
+ }
+
+ if ( 'spam' != $the_comment_status && 'trash' != $the_comment_status ) {
+ $actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' title='" . esc_attr__( 'Edit comment' ) . "'>". __( 'Edit' ) . '</a>';
+ $actions['quickedit'] = '<a onclick="commentReply.open( \''.$comment->comment_ID.'\',\''.$post->ID.'\',\'edit\' );return false;" class="vim-q" title="'.esc_attr__( 'Quick Edit' ).'" href="#">' . __( 'Quick&nbsp;Edit' ) . '</a>';
+ $actions['reply'] = '<a onclick="commentReply.open( \''.$comment->comment_ID.'\',\''.$post->ID.'\' );return false;" class="vim-r" title="'.esc_attr__( 'Reply to this comment' ).'" href="#">' . __( 'Reply' ) . '</a>';
+ }
+
+ $actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment );
+
+ $i = 0;
+ echo '<div class="row-actions">';
+ foreach ( $actions as $action => $link ) {
+ ++$i;
+ ( ( ( 'approve' == $action || 'unapprove' == $action ) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
+
+ // Reply and quickedit need a hide-if-no-js span when not added with ajax
+ if ( ( 'reply' == $action || 'quickedit' == $action ) && ! defined('DOING_AJAX') )
+ $action .= ' hide-if-no-js';
+ elseif ( ( $action == 'untrash' && $the_comment_status == 'trash' ) || ( $action == 'unspam' && $the_comment_status == 'spam' ) ) {
+ if ( '1' == get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) )
+ $action .= ' approve';
+ else
+ $action .= ' unapprove';
+ }
+
+ echo "<span class='$action'>$sep$link</span>";
+ }
+ echo '</div>';
+ }
+ }
+
+ function column_author( $comment ) {
+ global $comment_status;
+
+ $author_url = get_comment_author_url();
+ if ( 'http://' == $author_url )
+ $author_url = '';
+ $author_url_display = preg_replace( '|http://(www\.)?|i', '', $author_url );
+ if ( strlen( $author_url_display ) > 50 )
+ $author_url_display = substr( $author_url_display, 0, 49 ) . '&hellip;';
+
+ echo "<strong>"; comment_author(); echo '</strong><br />';
+ if ( !empty( $author_url ) )
+ echo "<a title='$author_url' href='$author_url'>$author_url_display</a><br />";
+
+ if ( $this->user_can ) {
+ if ( !empty( $comment->comment_author_email ) ) {
+ comment_author_email_link();
+ echo '<br />';
+ }
+ echo '<a href="edit-comments.php?s=';
+ comment_author_IP();
+ echo '&amp;mode=detail';
+ if ( 'spam' == $comment_status )
+ echo '&amp;comment_status=spam';
+ echo '">';
+ comment_author_IP();
+ echo '</a>';
+ }
+ }
+
+ function column_date( $comment ) {
+ return get_comment_date( __( 'Y/m/d \a\t g:ia' ) );
+ }
+
+ function column_response( $comment ) {
+ $post = get_post();
+
+ if ( isset( $this->pending_count[$post->ID] ) ) {
+ $pending_comments = $this->pending_count[$post->ID];
+ } else {
+ $_pending_count_temp = get_pending_comments_num( array( $post->ID ) );
+ $pending_comments = $this->pending_count[$post->ID] = $_pending_count_temp[$post->ID];
+ }
+
+ if ( current_user_can( 'edit_post', $post->ID ) ) {
+ $post_link = "<a href='" . get_edit_post_link( $post->ID ) . "'>";
+ $post_link .= get_the_title( $post->ID ) . '</a>';
+ } else {
+ $post_link = get_the_title( $post->ID );
+ }
+
+ echo '<div class="response-links"><span class="post-com-count-wrapper">';
+ echo $post_link . '<br />';
+ $this->comments_bubble( $post->ID, $pending_comments );
+ echo '</span> ';
+ $post_type_object = get_post_type_object( $post->post_type );
+ echo "<a href='" . get_permalink( $post->ID ) . "'>" . $post_type_object->labels->view_item . '</a>';
+ echo '</div>';
+ if ( 'attachment' == $post->post_type && ( $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ) ) )
+ echo $thumb;
+ }
+
+ function column_default( $comment, $column_name ) {
+ do_action( 'manage_comments_custom_column', $column_name, $comment->comment_ID );
+ }
+}
+
+/**
+ * Post Comments List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ *
+ * @see WP_Comments_Table
+ */
+class WP_Post_Comments_List_Table extends WP_Comments_List_Table {
+
+ function get_column_info() {
+ $this->_column_headers = array(
+ array(
+ 'author' => __( 'Author' ),
+ 'comment' => _x( 'Comment', 'column name' ),
+ ),
+ array(),
+ array(),
+ );
+
+ return $this->_column_headers;
+ }
+
+ function get_table_classes() {
+ $classes = parent::get_table_classes();
+ $classes[] = 'comments-box';
+ return $classes;
+ }
+
+ function display( $output_empty = false ) {
+ extract( $this->_args );
+
+ wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
+?>
+<table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0" style="display:none;">
+ <tbody id="the-comment-list"<?php if ( $singular ) echo " data-wp-lists='list:$singular'"; ?>>
+ <?php if ( ! $output_empty ) $this->display_rows_or_placeholder(); ?>
+ </tbody>
+</table>
+<?php
+ }
+
+ function get_per_page( $comment_status = false ) {
+ return 10;
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-filesystem-base.php b/src/wp-admin/includes/class-wp-filesystem-base.php
new file mode 100644
index 0000000000..d64fe4bba4
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-filesystem-base.php
@@ -0,0 +1,333 @@
+<?php
+/**
+ * Base WordPress Filesystem.
+ *
+ * @package WordPress
+ * @subpackage Filesystem
+ */
+
+/**
+ * Base WordPress Filesystem class for which Filesystem implementations extend
+ *
+ * @since 2.5
+ */
+class WP_Filesystem_Base {
+ /**
+ * Whether to display debug data for the connection.
+ *
+ * @since 2.5
+ * @access public
+ * @var bool
+ */
+ var $verbose = false;
+ /**
+ * Cached list of local filepaths to mapped remote filepaths.
+ *
+ * @since 2.7
+ * @access private
+ * @var array
+ */
+ var $cache = array();
+
+ /**
+ * The Access method of the current connection, Set automatically.
+ *
+ * @since 2.5
+ * @access public
+ * @var string
+ */
+ var $method = '';
+
+ /**
+ * Returns the path on the remote filesystem of ABSPATH
+ *
+ * @since 2.7
+ * @access public
+ * @return string The location of the remote path.
+ */
+ function abspath() {
+ $folder = $this->find_folder(ABSPATH);
+ //Perhaps the FTP folder is rooted at the WordPress install, Check for wp-includes folder in root, Could have some false positives, but rare.
+ if ( ! $folder && $this->is_dir('/wp-includes') )
+ $folder = '/';
+ return $folder;
+ }
+ /**
+ * Returns the path on the remote filesystem of WP_CONTENT_DIR
+ *
+ * @since 2.7
+ * @access public
+ * @return string The location of the remote path.
+ */
+ function wp_content_dir() {
+ return $this->find_folder(WP_CONTENT_DIR);
+ }
+ /**
+ * Returns the path on the remote filesystem of WP_PLUGIN_DIR
+ *
+ * @since 2.7
+ * @access public
+ *
+ * @return string The location of the remote path.
+ */
+ function wp_plugins_dir() {
+ return $this->find_folder(WP_PLUGIN_DIR);
+ }
+ /**
+ * Returns the path on the remote filesystem of the Themes Directory
+ *
+ * @since 2.7
+ * @access public
+ *
+ * @return string The location of the remote path.
+ */
+ function wp_themes_dir() {
+ return $this->wp_content_dir() . 'themes/';
+ }
+ /**
+ * Returns the path on the remote filesystem of WP_LANG_DIR
+ *
+ * @since 3.2.0
+ * @access public
+ *
+ * @return string The location of the remote path.
+ */
+ function wp_lang_dir() {
+ return $this->find_folder(WP_LANG_DIR);
+ }
+
+ /**
+ * Locates a folder on the remote filesystem.
+ *
+ * Deprecated; use WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir() methods instead.
+ *
+ * @since 2.5
+ * @deprecated 2.7
+ * @access public
+ *
+ * @param string $base The folder to start searching from
+ * @param bool $echo True to display debug information
+ * @return string The location of the remote path.
+ */
+ function find_base_dir($base = '.', $echo = false) {
+ _deprecated_function(__FUNCTION__, '2.7', 'WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir()' );
+ $this->verbose = $echo;
+ return $this->abspath();
+ }
+ /**
+ * Locates a folder on the remote filesystem.
+ *
+ * Deprecated; use WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir() methods instead.
+ *
+ * @since 2.5
+ * @deprecated 2.7
+ * @access public
+ *
+ * @param string $base The folder to start searching from
+ * @param bool $echo True to display debug information
+ * @return string The location of the remote path.
+ */
+ function get_base_dir($base = '.', $echo = false) {
+ _deprecated_function(__FUNCTION__, '2.7', 'WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir()' );
+ $this->verbose = $echo;
+ return $this->abspath();
+ }
+
+ /**
+ * Locates a folder on the remote filesystem.
+ *
+ * Assumes that on Windows systems, Stripping off the Drive letter is OK
+ * Sanitizes \\ to / in windows filepaths.
+ *
+ * @since 2.7
+ * @access public
+ *
+ * @param string $folder the folder to locate
+ * @return string The location of the remote path.
+ */
+ function find_folder($folder) {
+
+ if ( strpos($this->method, 'ftp') !== false ) {
+ $constant_overrides = array( 'FTP_BASE' => ABSPATH, 'FTP_CONTENT_DIR' => WP_CONTENT_DIR, 'FTP_PLUGIN_DIR' => WP_PLUGIN_DIR, 'FTP_LANG_DIR' => WP_LANG_DIR );
+ foreach ( $constant_overrides as $constant => $dir )
+ if ( defined($constant) && $folder === $dir )
+ return trailingslashit(constant($constant));
+ } elseif ( 'direct' == $this->method ) {
+ $folder = str_replace('\\', '/', $folder); //Windows path sanitisation
+ return trailingslashit($folder);
+ }
+
+ $folder = preg_replace('|^([a-z]{1}):|i', '', $folder); //Strip out windows drive letter if it's there.
+ $folder = str_replace('\\', '/', $folder); //Windows path sanitisation
+
+ if ( isset($this->cache[ $folder ] ) )
+ return $this->cache[ $folder ];
+
+ if ( $this->exists($folder) ) { //Folder exists at that absolute path.
+ $folder = trailingslashit($folder);
+ $this->cache[ $folder ] = $folder;
+ return $folder;
+ }
+ if ( $return = $this->search_for_folder($folder) )
+ $this->cache[ $folder ] = $return;
+ return $return;
+ }
+
+ /**
+ * Locates a folder on the remote filesystem.
+ *
+ * Expects Windows sanitized path
+ *
+ * @since 2.7
+ * @access private
+ *
+ * @param string $folder the folder to locate
+ * @param string $base the folder to start searching from
+ * @param bool $loop if the function has recursed, Internal use only
+ * @return string The location of the remote path.
+ */
+ function search_for_folder($folder, $base = '.', $loop = false ) {
+ if ( empty( $base ) || '.' == $base )
+ $base = trailingslashit($this->cwd());
+
+ $folder = untrailingslashit($folder);
+
+ $folder_parts = explode('/', $folder);
+ $last_index = array_pop( array_keys( $folder_parts ) );
+ $last_path = $folder_parts[ $last_index ];
+
+ $files = $this->dirlist( $base );
+
+ foreach ( $folder_parts as $index => $key ) {
+ if ( $index == $last_index )
+ continue; //We want this to be caught by the next code block.
+
+ //Working from /home/ to /user/ to /wordpress/ see if that file exists within the current folder,
+ // If it's found, change into it and follow through looking for it.
+ // If it cant find WordPress down that route, it'll continue onto the next folder level, and see if that matches, and so on.
+ // If it reaches the end, and still cant find it, it'll return false for the entire function.
+ if ( isset($files[ $key ]) ){
+ //Lets try that folder:
+ $newdir = trailingslashit(path_join($base, $key));
+ if ( $this->verbose )
+ printf( __('Changing to %s') . '<br/>', $newdir );
+ // only search for the remaining path tokens in the directory, not the full path again
+ $newfolder = implode( '/', array_slice( $folder_parts, $index + 1 ) );
+ if ( $ret = $this->search_for_folder( $newfolder, $newdir, $loop) )
+ return $ret;
+ }
+ }
+
+ //Only check this as a last resort, to prevent locating the incorrect install. All above procedures will fail quickly if this is the right branch to take.
+ if (isset( $files[ $last_path ] ) ) {
+ if ( $this->verbose )
+ printf( __('Found %s') . '<br/>', $base . $last_path );
+ return trailingslashit($base . $last_path);
+ }
+ if ( $loop )
+ return false; //Prevent this function from looping again.
+ //As an extra last resort, Change back to / if the folder wasn't found. This comes into effect when the CWD is /home/user/ but WP is at /var/www/.... mainly dedicated setups.
+ return $this->search_for_folder($folder, '/', true);
+
+ }
+
+ /**
+ * Returns the *nix style file permissions for a file
+ *
+ * From the PHP documentation page for fileperms()
+ *
+ * @link http://docs.php.net/fileperms
+ * @since 2.5
+ * @access public
+ *
+ * @param string $file string filename
+ * @return string *nix style representation of permissions
+ */
+ function gethchmod($file){
+ $perms = $this->getchmod($file);
+ if (($perms & 0xC000) == 0xC000) // Socket
+ $info = 's';
+ elseif (($perms & 0xA000) == 0xA000) // Symbolic Link
+ $info = 'l';
+ elseif (($perms & 0x8000) == 0x8000) // Regular
+ $info = '-';
+ elseif (($perms & 0x6000) == 0x6000) // Block special
+ $info = 'b';
+ elseif (($perms & 0x4000) == 0x4000) // Directory
+ $info = 'd';
+ elseif (($perms & 0x2000) == 0x2000) // Character special
+ $info = 'c';
+ elseif (($perms & 0x1000) == 0x1000) // FIFO pipe
+ $info = 'p';
+ else // Unknown
+ $info = 'u';
+
+ // Owner
+ $info .= (($perms & 0x0100) ? 'r' : '-');
+ $info .= (($perms & 0x0080) ? 'w' : '-');
+ $info .= (($perms & 0x0040) ?
+ (($perms & 0x0800) ? 's' : 'x' ) :
+ (($perms & 0x0800) ? 'S' : '-'));
+
+ // Group
+ $info .= (($perms & 0x0020) ? 'r' : '-');
+ $info .= (($perms & 0x0010) ? 'w' : '-');
+ $info .= (($perms & 0x0008) ?
+ (($perms & 0x0400) ? 's' : 'x' ) :
+ (($perms & 0x0400) ? 'S' : '-'));
+
+ // World
+ $info .= (($perms & 0x0004) ? 'r' : '-');
+ $info .= (($perms & 0x0002) ? 'w' : '-');
+ $info .= (($perms & 0x0001) ?
+ (($perms & 0x0200) ? 't' : 'x' ) :
+ (($perms & 0x0200) ? 'T' : '-'));
+ return $info;
+ }
+
+ /**
+ * Converts *nix style file permissions to a octal number.
+ *
+ * Converts '-rw-r--r--' to 0644
+ * From "info at rvgate dot nl"'s comment on the PHP documentation for chmod()
+ *
+ * @link http://docs.php.net/manual/en/function.chmod.php#49614
+ * @since 2.5
+ * @access public
+ *
+ * @param string $mode string *nix style file permission
+ * @return int octal representation
+ */
+ function getnumchmodfromh($mode) {
+ $realmode = '';
+ $legal = array('', 'w', 'r', 'x', '-');
+ $attarray = preg_split('//', $mode);
+
+ for ($i=0; $i < count($attarray); $i++)
+ if ($key = array_search($attarray[$i], $legal))
+ $realmode .= $legal[$key];
+
+ $mode = str_pad($realmode, 10, '-', STR_PAD_LEFT);
+ $trans = array('-'=>'0', 'r'=>'4', 'w'=>'2', 'x'=>'1');
+ $mode = strtr($mode,$trans);
+
+ $newmode = $mode[0];
+ $newmode .= $mode[1] + $mode[2] + $mode[3];
+ $newmode .= $mode[4] + $mode[5] + $mode[6];
+ $newmode .= $mode[7] + $mode[8] + $mode[9];
+ return $newmode;
+ }
+
+ /**
+ * Determines if the string provided contains binary characters.
+ *
+ * @since 2.7
+ * @access private
+ *
+ * @param string $text String to test against
+ * @return bool true if string is binary, false otherwise
+ */
+ function is_binary( $text ) {
+ return (bool) preg_match('|[^\x20-\x7E]|', $text); //chr(32)..chr(127)
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-filesystem-direct.php b/src/wp-admin/includes/class-wp-filesystem-direct.php
new file mode 100644
index 0000000000..e25c9ef8d7
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-filesystem-direct.php
@@ -0,0 +1,363 @@
+<?php
+/**
+ * WordPress Direct Filesystem.
+ *
+ * @package WordPress
+ * @subpackage Filesystem
+ */
+
+/**
+ * WordPress Filesystem Class for direct PHP file and folder manipulation.
+ *
+ * @since 2.5
+ * @package WordPress
+ * @subpackage Filesystem
+ * @uses WP_Filesystem_Base Extends class
+ */
+class WP_Filesystem_Direct extends WP_Filesystem_Base {
+ var $errors = null;
+ /**
+ * constructor
+ *
+ * @param mixed $arg ignored argument
+ */
+ function __construct($arg) {
+ $this->method = 'direct';
+ $this->errors = new WP_Error();
+ }
+ /**
+ * connect filesystem.
+ *
+ * @return bool Returns true on success or false on failure (always true for WP_Filesystem_Direct).
+ */
+ function connect() {
+ return true;
+ }
+ /**
+ * Reads entire file into a string
+ *
+ * @param string $file Name of the file to read.
+ * @return string|bool The function returns the read data or false on failure.
+ */
+ function get_contents($file) {
+ return @file_get_contents($file);
+ }
+ /**
+ * Reads entire file into an array
+ *
+ * @param string $file Path to the file.
+ * @return array|bool the file contents in an array or false on failure.
+ */
+ function get_contents_array($file) {
+ return @file($file);
+ }
+ /**
+ * Write a string to a file
+ *
+ * @param string $file Remote path to the file where to write the data.
+ * @param string $contents The data to write.
+ * @param int $mode (optional) The file permissions as octal number, usually 0644.
+ * @return bool False upon failure.
+ */
+ function put_contents($file, $contents, $mode = false ) {
+ if ( ! ($fp = @fopen($file, 'w')) )
+ return false;
+ @fwrite($fp, $contents);
+ @fclose($fp);
+ $this->chmod($file, $mode);
+ return true;
+ }
+ /**
+ * Gets the current working directory
+ *
+ * @return string|bool the current working directory on success, or false on failure.
+ */
+ function cwd() {
+ return @getcwd();
+ }
+ /**
+ * Change directory
+ *
+ * @param string $dir The new current directory.
+ * @return bool Returns true on success or false on failure.
+ */
+ function chdir($dir) {
+ return @chdir($dir);
+ }
+ /**
+ * Changes file group
+ *
+ * @param string $file Path to the file.
+ * @param mixed $group A group name or number.
+ * @param bool $recursive (optional) If set True changes file group recursively. Defaults to False.
+ * @return bool Returns true on success or false on failure.
+ */
+ function chgrp($file, $group, $recursive = false) {
+ if ( ! $this->exists($file) )
+ return false;
+ if ( ! $recursive )
+ return @chgrp($file, $group);
+ if ( ! $this->is_dir($file) )
+ return @chgrp($file, $group);
+ //Is a directory, and we want recursive
+ $file = trailingslashit($file);
+ $filelist = $this->dirlist($file);
+ foreach ($filelist as $filename)
+ $this->chgrp($file . $filename, $group, $recursive);
+
+ return true;
+ }
+ /**
+ * Changes filesystem permissions
+ *
+ * @param string $file Path to the file.
+ * @param int $mode (optional) The permissions as octal number, usually 0644 for files, 0755 for dirs.
+ * @param bool $recursive (optional) If set True changes file group recursively. Defaults to False.
+ * @return bool Returns true on success or false on failure.
+ */
+ function chmod($file, $mode = false, $recursive = false) {
+ if ( ! $mode ) {
+ if ( $this->is_file($file) )
+ $mode = FS_CHMOD_FILE;
+ elseif ( $this->is_dir($file) )
+ $mode = FS_CHMOD_DIR;
+ else
+ return false;
+ }
+
+ if ( ! $recursive || ! $this->is_dir($file) )
+ return @chmod($file, $mode);
+ //Is a directory, and we want recursive
+ $file = trailingslashit($file);
+ $filelist = $this->dirlist($file);
+ foreach ( (array)$filelist as $filename => $filemeta)
+ $this->chmod($file . $filename, $mode, $recursive);
+
+ return true;
+ }
+ /**
+ * Changes file owner
+ *
+ * @param string $file Path to the file.
+ * @param mixed $owner A user name or number.
+ * @param bool $recursive (optional) If set True changes file owner recursively. Defaults to False.
+ * @return bool Returns true on success or false on failure.
+ */
+ function chown($file, $owner, $recursive = false) {
+ if ( ! $this->exists($file) )
+ return false;
+ if ( ! $recursive )
+ return @chown($file, $owner);
+ if ( ! $this->is_dir($file) )
+ return @chown($file, $owner);
+ //Is a directory, and we want recursive
+ $filelist = $this->dirlist($file);
+ foreach ($filelist as $filename) {
+ $this->chown($file . '/' . $filename, $owner, $recursive);
+ }
+ return true;
+ }
+ /**
+ * Gets file owner
+ *
+ * @param string $file Path to the file.
+ * @return string Username of the user.
+ */
+ function owner($file) {
+ $owneruid = @fileowner($file);
+ if ( ! $owneruid )
+ return false;
+ if ( ! function_exists('posix_getpwuid') )
+ return $owneruid;
+ $ownerarray = posix_getpwuid($owneruid);
+ return $ownerarray['name'];
+ }
+ /**
+ * Gets file permissions
+ *
+ * FIXME does not handle errors in fileperms()
+ *
+ * @param string $file Path to the file.
+ * @return string Mode of the file (last 4 digits).
+ */
+ function getchmod($file) {
+ return substr(decoct(@fileperms($file)),3);
+ }
+ function group($file) {
+ $gid = @filegroup($file);
+ if ( ! $gid )
+ return false;
+ if ( ! function_exists('posix_getgrgid') )
+ return $gid;
+ $grouparray = posix_getgrgid($gid);
+ return $grouparray['name'];
+ }
+
+ function copy($source, $destination, $overwrite = false, $mode = false) {
+ if ( ! $overwrite && $this->exists($destination) )
+ return false;
+
+ $rtval = copy($source, $destination);
+ if ( $mode )
+ $this->chmod($destination, $mode);
+ return $rtval;
+ }
+
+ function move($source, $destination, $overwrite = false) {
+ if ( ! $overwrite && $this->exists($destination) )
+ return false;
+
+ // try using rename first. if that fails (for example, source is read only) try copy
+ if ( @rename($source, $destination) )
+ return true;
+
+ if ( $this->copy($source, $destination, $overwrite) && $this->exists($destination) ) {
+ $this->delete($source);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function delete($file, $recursive = false, $type = false) {
+ if ( empty($file) ) //Some filesystems report this as /, which can cause non-expected recursive deletion of all files in the filesystem.
+ return false;
+ $file = str_replace('\\', '/', $file); //for win32, occasional problems deleting files otherwise
+
+ if ( 'f' == $type || $this->is_file($file) )
+ return @unlink($file);
+ if ( ! $recursive && $this->is_dir($file) )
+ return @rmdir($file);
+
+ //At this point it's a folder, and we're in recursive mode
+ $file = trailingslashit($file);
+ $filelist = $this->dirlist($file, true);
+
+ $retval = true;
+ if ( is_array($filelist) ) //false if no files, So check first.
+ foreach ($filelist as $filename => $fileinfo)
+ if ( ! $this->delete($file . $filename, $recursive, $fileinfo['type']) )
+ $retval = false;
+
+ if ( file_exists($file) && ! @rmdir($file) )
+ $retval = false;
+ return $retval;
+ }
+
+ function exists($file) {
+ return @file_exists($file);
+ }
+
+ function is_file($file) {
+ return @is_file($file);
+ }
+
+ function is_dir($path) {
+ return @is_dir($path);
+ }
+
+ function is_readable($file) {
+ return @is_readable($file);
+ }
+
+ function is_writable($file) {
+ return @is_writable($file);
+ }
+
+ function atime($file) {
+ return @fileatime($file);
+ }
+
+ function mtime($file) {
+ return @filemtime($file);
+ }
+ function size($file) {
+ return @filesize($file);
+ }
+
+ function touch($file, $time = 0, $atime = 0) {
+ if ($time == 0)
+ $time = time();
+ if ($atime == 0)
+ $atime = time();
+ return @touch($file, $time, $atime);
+ }
+
+ function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
+ // safe mode fails with a trailing slash under certain PHP versions.
+ $path = untrailingslashit($path);
+ if ( empty($path) )
+ return false;
+
+ if ( ! $chmod )
+ $chmod = FS_CHMOD_DIR;
+
+ if ( ! @mkdir($path) )
+ return false;
+ $this->chmod($path, $chmod);
+ if ( $chown )
+ $this->chown($path, $chown);
+ if ( $chgrp )
+ $this->chgrp($path, $chgrp);
+ return true;
+ }
+
+ function rmdir($path, $recursive = false) {
+ return $this->delete($path, $recursive);
+ }
+
+ function dirlist($path, $include_hidden = true, $recursive = false) {
+ if ( $this->is_file($path) ) {
+ $limit_file = basename($path);
+ $path = dirname($path);
+ } else {
+ $limit_file = false;
+ }
+
+ if ( ! $this->is_dir($path) )
+ return false;
+
+ $dir = @dir($path);
+ if ( ! $dir )
+ return false;
+
+ $ret = array();
+
+ while (false !== ($entry = $dir->read()) ) {
+ $struc = array();
+ $struc['name'] = $entry;
+
+ if ( '.' == $struc['name'] || '..' == $struc['name'] )
+ continue;
+
+ if ( ! $include_hidden && '.' == $struc['name'][0] )
+ continue;
+
+ if ( $limit_file && $struc['name'] != $limit_file)
+ continue;
+
+ $struc['perms'] = $this->gethchmod($path.'/'.$entry);
+ $struc['permsn'] = $this->getnumchmodfromh($struc['perms']);
+ $struc['number'] = false;
+ $struc['owner'] = $this->owner($path.'/'.$entry);
+ $struc['group'] = $this->group($path.'/'.$entry);
+ $struc['size'] = $this->size($path.'/'.$entry);
+ $struc['lastmodunix']= $this->mtime($path.'/'.$entry);
+ $struc['lastmod'] = date('M j',$struc['lastmodunix']);
+ $struc['time'] = date('h:i:s',$struc['lastmodunix']);
+ $struc['type'] = $this->is_dir($path.'/'.$entry) ? 'd' : 'f';
+
+ if ( 'd' == $struc['type'] ) {
+ if ( $recursive )
+ $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
+ else
+ $struc['files'] = array();
+ }
+
+ $ret[ $struc['name'] ] = $struc;
+ }
+ $dir->close();
+ unset($dir);
+ return $ret;
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-filesystem-ftpext.php b/src/wp-admin/includes/class-wp-filesystem-ftpext.php
new file mode 100644
index 0000000000..d087189147
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-filesystem-ftpext.php
@@ -0,0 +1,393 @@
+<?php
+/**
+ * WordPress FTP Filesystem.
+ *
+ * @package WordPress
+ * @subpackage Filesystem
+ */
+
+/**
+ * WordPress Filesystem Class for implementing FTP.
+ *
+ * @since 2.5
+ * @package WordPress
+ * @subpackage Filesystem
+ * @uses WP_Filesystem_Base Extends class
+ */
+class WP_Filesystem_FTPext extends WP_Filesystem_Base {
+ var $link;
+ var $errors = null;
+ var $options = array();
+
+ function __construct($opt='') {
+ $this->method = 'ftpext';
+ $this->errors = new WP_Error();
+
+ //Check if possible to use ftp functions.
+ if ( ! extension_loaded('ftp') ) {
+ $this->errors->add('no_ftp_ext', __('The ftp PHP extension is not available'));
+ return false;
+ }
+
+ // Set defaults:
+ //This Class uses the timeout on a per-connection basis, Others use it on a per-action basis.
+
+ if ( ! defined('FS_TIMEOUT') )
+ define('FS_TIMEOUT', 240);
+
+ if ( empty($opt['port']) )
+ $this->options['port'] = 21;
+ else
+ $this->options['port'] = $opt['port'];
+
+ if ( empty($opt['hostname']) )
+ $this->errors->add('empty_hostname', __('FTP hostname is required'));
+ else
+ $this->options['hostname'] = $opt['hostname'];
+
+ if ( ! empty($opt['base']) )
+ $this->wp_base = $opt['base'];
+
+ // Check if the options provided are OK.
+ if ( empty($opt['username']) )
+ $this->errors->add('empty_username', __('FTP username is required'));
+ else
+ $this->options['username'] = $opt['username'];
+
+ if ( empty($opt['password']) )
+ $this->errors->add('empty_password', __('FTP password is required'));
+ else
+ $this->options['password'] = $opt['password'];
+
+ $this->options['ssl'] = false;
+ if ( isset($opt['connection_type']) && 'ftps' == $opt['connection_type'] )
+ $this->options['ssl'] = true;
+ }
+
+ function connect() {
+ if ( isset($this->options['ssl']) && $this->options['ssl'] && function_exists('ftp_ssl_connect') )
+ $this->link = @ftp_ssl_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
+ else
+ $this->link = @ftp_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
+
+ if ( ! $this->link ) {
+ $this->errors->add('connect', sprintf(__('Failed to connect to FTP Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
+ return false;
+ }
+
+ if ( ! @ftp_login($this->link,$this->options['username'], $this->options['password']) ) {
+ $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
+ return false;
+ }
+
+ //Set the Connection to use Passive FTP
+ @ftp_pasv( $this->link, true );
+ if ( @ftp_get_option($this->link, FTP_TIMEOUT_SEC) < FS_TIMEOUT )
+ @ftp_set_option($this->link, FTP_TIMEOUT_SEC, FS_TIMEOUT);
+
+ return true;
+ }
+
+ function get_contents($file, $type = '', $resumepos = 0 ) {
+ if ( empty($type) )
+ $type = FTP_BINARY;
+
+ $tempfile = wp_tempnam($file);
+ $temp = fopen($tempfile, 'w+');
+
+ if ( ! $temp )
+ return false;
+
+ if ( ! @ftp_fget($this->link, $temp, $file, $type, $resumepos) )
+ return false;
+
+ fseek($temp, 0); //Skip back to the start of the file being written to
+ $contents = '';
+
+ while ( ! feof($temp) )
+ $contents .= fread($temp, 8192);
+
+ fclose($temp);
+ unlink($tempfile);
+ return $contents;
+ }
+ function get_contents_array($file) {
+ return explode("\n", $this->get_contents($file));
+ }
+
+ function put_contents($file, $contents, $mode = false ) {
+ $tempfile = wp_tempnam($file);
+ $temp = fopen($tempfile, 'w+');
+ if ( ! $temp )
+ return false;
+
+ fwrite($temp, $contents);
+ fseek($temp, 0); //Skip back to the start of the file being written to
+
+ $type = $this->is_binary($contents) ? FTP_BINARY : FTP_ASCII;
+ $ret = @ftp_fput($this->link, $file, $temp, $type);
+
+ fclose($temp);
+ unlink($tempfile);
+
+ $this->chmod($file, $mode);
+
+ return $ret;
+ }
+ function cwd() {
+ $cwd = @ftp_pwd($this->link);
+ if ( $cwd )
+ $cwd = trailingslashit($cwd);
+ return $cwd;
+ }
+ function chdir($dir) {
+ return @ftp_chdir($this->link, $dir);
+ }
+ function chgrp($file, $group, $recursive = false ) {
+ return false;
+ }
+ function chmod($file, $mode = false, $recursive = false) {
+ if ( ! $mode ) {
+ if ( $this->is_file($file) )
+ $mode = FS_CHMOD_FILE;
+ elseif ( $this->is_dir($file) )
+ $mode = FS_CHMOD_DIR;
+ else
+ return false;
+ }
+
+ // chmod any sub-objects if recursive.
+ if ( $recursive && $this->is_dir($file) ) {
+ $filelist = $this->dirlist($file);
+ foreach ( (array)$filelist as $filename => $filemeta )
+ $this->chmod($file . '/' . $filename, $mode, $recursive);
+ }
+
+ // chmod the file or directory
+ if ( ! function_exists('ftp_chmod') )
+ return (bool)@ftp_site($this->link, sprintf('CHMOD %o %s', $mode, $file));
+ return (bool)@ftp_chmod($this->link, $mode, $file);
+ }
+ function chown($file, $owner, $recursive = false ) {
+ return false;
+ }
+ function owner($file) {
+ $dir = $this->dirlist($file);
+ return $dir[$file]['owner'];
+ }
+ function getchmod($file) {
+ $dir = $this->dirlist($file);
+ return $dir[$file]['permsn'];
+ }
+ function group($file) {
+ $dir = $this->dirlist($file);
+ return $dir[$file]['group'];
+ }
+ function copy($source, $destination, $overwrite = false, $mode = false) {
+ if ( ! $overwrite && $this->exists($destination) )
+ return false;
+ $content = $this->get_contents($source);
+ if ( false === $content)
+ return false;
+ return $this->put_contents($destination, $content, $mode);
+ }
+ function move($source, $destination, $overwrite = false) {
+ return ftp_rename($this->link, $source, $destination);
+ }
+
+ function delete($file, $recursive = false, $type = false) {
+ if ( empty($file) )
+ return false;
+ if ( 'f' == $type || $this->is_file($file) )
+ return @ftp_delete($this->link, $file);
+ if ( !$recursive )
+ return @ftp_rmdir($this->link, $file);
+
+ $filelist = $this->dirlist( trailingslashit($file) );
+ if ( !empty($filelist) )
+ foreach ( $filelist as $delete_file )
+ $this->delete( trailingslashit($file) . $delete_file['name'], $recursive, $delete_file['type'] );
+ return @ftp_rmdir($this->link, $file);
+ }
+
+ function exists($file) {
+ $list = @ftp_nlist($this->link, $file);
+ return !empty($list); //empty list = no file, so invert.
+ }
+ function is_file($file) {
+ return $this->exists($file) && !$this->is_dir($file);
+ }
+ function is_dir($path) {
+ $cwd = $this->cwd();
+ $result = @ftp_chdir($this->link, trailingslashit($path) );
+ if ( $result && $path == $this->cwd() || $this->cwd() != $cwd ) {
+ @ftp_chdir($this->link, $cwd);
+ return true;
+ }
+ return false;
+ }
+ function is_readable($file) {
+ //Get dir list, Check if the file is readable by the current user??
+ return true;
+ }
+ function is_writable($file) {
+ //Get dir list, Check if the file is writable by the current user??
+ return true;
+ }
+ function atime($file) {
+ return false;
+ }
+ function mtime($file) {
+ return ftp_mdtm($this->link, $file);
+ }
+ function size($file) {
+ return ftp_size($this->link, $file);
+ }
+ function touch($file, $time = 0, $atime = 0) {
+ return false;
+ }
+ function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
+ $path = untrailingslashit($path);
+ if ( empty($path) )
+ return false;
+
+ if ( !@ftp_mkdir($this->link, $path) )
+ return false;
+ $this->chmod($path, $chmod);
+ if ( $chown )
+ $this->chown($path, $chown);
+ if ( $chgrp )
+ $this->chgrp($path, $chgrp);
+ return true;
+ }
+ function rmdir($path, $recursive = false) {
+ return $this->delete($path, $recursive);
+ }
+
+ function parselisting($line) {
+ static $is_windows;
+ if ( is_null($is_windows) )
+ $is_windows = stripos( ftp_systype($this->link), 'win') !== false;
+
+ if ( $is_windows && preg_match('/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/', $line, $lucifer) ) {
+ $b = array();
+ if ( $lucifer[3] < 70 )
+ $lucifer[3] +=2000;
+ else
+ $lucifer[3] += 1900; // 4digit year fix
+ $b['isdir'] = ( $lucifer[7] == '<DIR>');
+ if ( $b['isdir'] )
+ $b['type'] = 'd';
+ else
+ $b['type'] = 'f';
+ $b['size'] = $lucifer[7];
+ $b['month'] = $lucifer[1];
+ $b['day'] = $lucifer[2];
+ $b['year'] = $lucifer[3];
+ $b['hour'] = $lucifer[4];
+ $b['minute'] = $lucifer[5];
+ $b['time'] = @mktime($lucifer[4] + (strcasecmp($lucifer[6], "PM") == 0 ? 12 : 0), $lucifer[5], 0, $lucifer[1], $lucifer[2], $lucifer[3]);
+ $b['am/pm'] = $lucifer[6];
+ $b['name'] = $lucifer[8];
+ } elseif ( !$is_windows && $lucifer = preg_split('/[ ]/', $line, 9, PREG_SPLIT_NO_EMPTY)) {
+ //echo $line."\n";
+ $lcount = count($lucifer);
+ if ( $lcount < 8 )
+ return '';
+ $b = array();
+ $b['isdir'] = $lucifer[0]{0} === 'd';
+ $b['islink'] = $lucifer[0]{0} === 'l';
+ if ( $b['isdir'] )
+ $b['type'] = 'd';
+ elseif ( $b['islink'] )
+ $b['type'] = 'l';
+ else
+ $b['type'] = 'f';
+ $b['perms'] = $lucifer[0];
+ $b['number'] = $lucifer[1];
+ $b['owner'] = $lucifer[2];
+ $b['group'] = $lucifer[3];
+ $b['size'] = $lucifer[4];
+ if ( $lcount == 8 ) {
+ sscanf($lucifer[5], '%d-%d-%d', $b['year'], $b['month'], $b['day']);
+ sscanf($lucifer[6], '%d:%d', $b['hour'], $b['minute']);
+ $b['time'] = @mktime($b['hour'], $b['minute'], 0, $b['month'], $b['day'], $b['year']);
+ $b['name'] = $lucifer[7];
+ } else {
+ $b['month'] = $lucifer[5];
+ $b['day'] = $lucifer[6];
+ if ( preg_match('/([0-9]{2}):([0-9]{2})/', $lucifer[7], $l2) ) {
+ $b['year'] = date("Y");
+ $b['hour'] = $l2[1];
+ $b['minute'] = $l2[2];
+ } else {
+ $b['year'] = $lucifer[7];
+ $b['hour'] = 0;
+ $b['minute'] = 0;
+ }
+ $b['time'] = strtotime( sprintf('%d %s %d %02d:%02d', $b['day'], $b['month'], $b['year'], $b['hour'], $b['minute']) );
+ $b['name'] = $lucifer[8];
+ }
+ }
+
+ // Replace symlinks formatted as "source -> target" with just the source name
+ if ( $b['islink'] )
+ $b['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $b['name'] );
+
+ return $b;
+ }
+
+ function dirlist($path = '.', $include_hidden = true, $recursive = false) {
+ if ( $this->is_file($path) ) {
+ $limit_file = basename($path);
+ $path = dirname($path) . '/';
+ } else {
+ $limit_file = false;
+ }
+
+ $pwd = @ftp_pwd($this->link);
+ if ( ! @ftp_chdir($this->link, $path) ) // Cant change to folder = folder doesn't exist
+ return false;
+ $list = @ftp_rawlist($this->link, '-a', false);
+ @ftp_chdir($this->link, $pwd);
+
+ if ( empty($list) ) // Empty array = non-existent folder (real folder will show . at least)
+ return false;
+
+ $dirlist = array();
+ foreach ( $list as $k => $v ) {
+ $entry = $this->parselisting($v);
+ if ( empty($entry) )
+ continue;
+
+ if ( '.' == $entry['name'] || '..' == $entry['name'] )
+ continue;
+
+ if ( ! $include_hidden && '.' == $entry['name'][0] )
+ continue;
+
+ if ( $limit_file && $entry['name'] != $limit_file)
+ continue;
+
+ $dirlist[ $entry['name'] ] = $entry;
+ }
+
+ $ret = array();
+ foreach ( (array)$dirlist as $struc ) {
+ if ( 'd' == $struc['type'] ) {
+ if ( $recursive )
+ $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
+ else
+ $struc['files'] = array();
+ }
+
+ $ret[ $struc['name'] ] = $struc;
+ }
+ return $ret;
+ }
+
+ function __destruct() {
+ if ( $this->link )
+ ftp_close($this->link);
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-filesystem-ftpsockets.php b/src/wp-admin/includes/class-wp-filesystem-ftpsockets.php
new file mode 100644
index 0000000000..728385b70b
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-filesystem-ftpsockets.php
@@ -0,0 +1,333 @@
+<?php
+/**
+ * WordPress FTP Sockets Filesystem.
+ *
+ * @package WordPress
+ * @subpackage Filesystem
+ */
+
+/**
+ * WordPress Filesystem Class for implementing FTP Sockets.
+ *
+ * @since 2.5
+ * @package WordPress
+ * @subpackage Filesystem
+ * @uses WP_Filesystem_Base Extends class
+ */
+class WP_Filesystem_ftpsockets extends WP_Filesystem_Base {
+ var $ftp = false;
+ var $errors = null;
+ var $options = array();
+
+ function __construct($opt = '') {
+ $this->method = 'ftpsockets';
+ $this->errors = new WP_Error();
+
+ //Check if possible to use ftp functions.
+ if ( ! @include_once ABSPATH . 'wp-admin/includes/class-ftp.php' )
+ return false;
+ $this->ftp = new ftp();
+
+ //Set defaults:
+ if ( empty($opt['port']) )
+ $this->options['port'] = 21;
+ else
+ $this->options['port'] = $opt['port'];
+
+ if ( empty($opt['hostname']) )
+ $this->errors->add('empty_hostname', __('FTP hostname is required'));
+ else
+ $this->options['hostname'] = $opt['hostname'];
+
+ if ( ! empty($opt['base']) )
+ $this->wp_base = $opt['base'];
+
+ // Check if the options provided are OK.
+ if ( empty ($opt['username']) )
+ $this->errors->add('empty_username', __('FTP username is required'));
+ else
+ $this->options['username'] = $opt['username'];
+
+ if ( empty ($opt['password']) )
+ $this->errors->add('empty_password', __('FTP password is required'));
+ else
+ $this->options['password'] = $opt['password'];
+ }
+
+ function connect() {
+ if ( ! $this->ftp )
+ return false;
+
+ $this->ftp->setTimeout(FS_CONNECT_TIMEOUT);
+
+ if ( ! $this->ftp->SetServer($this->options['hostname'], $this->options['port']) ) {
+ $this->errors->add('connect', sprintf(__('Failed to connect to FTP Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
+ return false;
+ }
+
+ if ( ! $this->ftp->connect() ) {
+ $this->errors->add('connect', sprintf(__('Failed to connect to FTP Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
+ return false;
+ }
+
+ if ( ! $this->ftp->login($this->options['username'], $this->options['password']) ) {
+ $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
+ return false;
+ }
+
+ $this->ftp->SetType(FTP_AUTOASCII);
+ $this->ftp->Passive(true);
+ $this->ftp->setTimeout(FS_TIMEOUT);
+ return true;
+ }
+
+ function get_contents($file, $type = '', $resumepos = 0) {
+ if ( ! $this->exists($file) )
+ return false;
+
+ if ( empty($type) )
+ $type = FTP_AUTOASCII;
+ $this->ftp->SetType($type);
+
+ $temp = wp_tempnam( $file );
+
+ if ( ! $temphandle = fopen($temp, 'w+') )
+ return false;
+
+ if ( ! $this->ftp->fget($temphandle, $file) ) {
+ fclose($temphandle);
+ unlink($temp);
+ return ''; //Blank document, File does exist, It's just blank.
+ }
+
+ fseek($temphandle, 0); //Skip back to the start of the file being written to
+ $contents = '';
+
+ while ( ! feof($temphandle) )
+ $contents .= fread($temphandle, 8192);
+
+ fclose($temphandle);
+ unlink($temp);
+ return $contents;
+ }
+
+ function get_contents_array($file) {
+ return explode("\n", $this->get_contents($file) );
+ }
+
+ function put_contents($file, $contents, $mode = false ) {
+ $temp = wp_tempnam( $file );
+ if ( ! $temphandle = @fopen($temp, 'w+') ) {
+ unlink($temp);
+ return false;
+ }
+
+ fwrite($temphandle, $contents);
+ fseek($temphandle, 0); //Skip back to the start of the file being written to
+
+ $type = $this->is_binary($contents) ? FTP_BINARY : FTP_ASCII;
+ $this->ftp->SetType($type);
+
+ $ret = $this->ftp->fput($file, $temphandle);
+
+ fclose($temphandle);
+ unlink($temp);
+
+ $this->chmod($file, $mode);
+
+ return $ret;
+ }
+
+ function cwd() {
+ $cwd = $this->ftp->pwd();
+ if ( $cwd )
+ $cwd = trailingslashit($cwd);
+ return $cwd;
+ }
+
+ function chdir($file) {
+ return $this->ftp->chdir($file);
+ }
+
+ function chgrp($file, $group, $recursive = false ) {
+ return false;
+ }
+
+ function chmod($file, $mode = false, $recursive = false ) {
+ if ( ! $mode ) {
+ if ( $this->is_file($file) )
+ $mode = FS_CHMOD_FILE;
+ elseif ( $this->is_dir($file) )
+ $mode = FS_CHMOD_DIR;
+ else
+ return false;
+ }
+
+ // chmod any sub-objects if recursive.
+ if ( $recursive && $this->is_dir($file) ) {
+ $filelist = $this->dirlist($file);
+ foreach ( (array)$filelist as $filename => $filemeta )
+ $this->chmod($file . '/' . $filename, $mode, $recursive);
+ }
+
+ // chmod the file or directory
+ return $this->ftp->chmod($file, $mode);
+ }
+
+ function chown($file, $owner, $recursive = false ) {
+ return false;
+ }
+
+ function owner($file) {
+ $dir = $this->dirlist($file);
+ return $dir[$file]['owner'];
+ }
+
+ function getchmod($file) {
+ $dir = $this->dirlist($file);
+ return $dir[$file]['permsn'];
+ }
+
+ function group($file) {
+ $dir = $this->dirlist($file);
+ return $dir[$file]['group'];
+ }
+
+ function copy($source, $destination, $overwrite = false, $mode = false) {
+ if ( ! $overwrite && $this->exists($destination) )
+ return false;
+
+ $content = $this->get_contents($source);
+ if ( false === $content )
+ return false;
+
+ return $this->put_contents($destination, $content, $mode);
+ }
+
+ function move($source, $destination, $overwrite = false ) {
+ return $this->ftp->rename($source, $destination);
+ }
+
+ function delete($file, $recursive = false, $type = false) {
+ if ( empty($file) )
+ return false;
+ if ( 'f' == $type || $this->is_file($file) )
+ return $this->ftp->delete($file);
+ if ( !$recursive )
+ return $this->ftp->rmdir($file);
+
+ return $this->ftp->mdel($file);
+ }
+
+ function exists($file) {
+ return $this->ftp->is_exists($file);
+ }
+
+ function is_file($file) {
+ if ( $this->is_dir($file) )
+ return false;
+ if ( $this->exists($file) )
+ return true;
+ return false;
+ }
+
+ function is_dir($path) {
+ $cwd = $this->cwd();
+ if ( $this->chdir($path) ) {
+ $this->chdir($cwd);
+ return true;
+ }
+ return false;
+ }
+
+ function is_readable($file) {
+ //Get dir list, Check if the file is writable by the current user??
+ return true;
+ }
+
+ function is_writable($file) {
+ //Get dir list, Check if the file is writable by the current user??
+ return true;
+ }
+
+ function atime($file) {
+ return false;
+ }
+
+ function mtime($file) {
+ return $this->ftp->mdtm($file);
+ }
+
+ function size($file) {
+ return $this->ftp->filesize($file);
+ }
+
+ function touch($file, $time = 0, $atime = 0 ) {
+ return false;
+ }
+
+ function mkdir($path, $chmod = false, $chown = false, $chgrp = false ) {
+ $path = untrailingslashit($path);
+ if ( empty($path) )
+ return false;
+
+ if ( ! $this->ftp->mkdir($path) )
+ return false;
+ if ( ! $chmod )
+ $chmod = FS_CHMOD_DIR;
+ $this->chmod($path, $chmod);
+ if ( $chown )
+ $this->chown($path, $chown);
+ if ( $chgrp )
+ $this->chgrp($path, $chgrp);
+ return true;
+ }
+
+ function rmdir($path, $recursive = false ) {
+ $this->delete($path, $recursive);
+ }
+
+ function dirlist($path = '.', $include_hidden = true, $recursive = false ) {
+ if ( $this->is_file($path) ) {
+ $limit_file = basename($path);
+ $path = dirname($path) . '/';
+ } else {
+ $limit_file = false;
+ }
+
+ $list = $this->ftp->dirlist($path);
+ if ( empty($list) && !$this->exists($path) )
+ return false;
+
+ $ret = array();
+ foreach ( $list as $struc ) {
+
+ if ( '.' == $struc['name'] || '..' == $struc['name'] )
+ continue;
+
+ if ( ! $include_hidden && '.' == $struc['name'][0] )
+ continue;
+
+ if ( $limit_file && $struc['name'] != $limit_file )
+ continue;
+
+ if ( 'd' == $struc['type'] ) {
+ if ( $recursive )
+ $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
+ else
+ $struc['files'] = array();
+ }
+
+ // Replace symlinks formatted as "source -> target" with just the source name
+ if ( $struc['islink'] )
+ $struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] );
+
+ $ret[ $struc['name'] ] = $struc;
+ }
+ return $ret;
+ }
+
+ function __destruct() {
+ $this->ftp->quit();
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-filesystem-ssh2.php b/src/wp-admin/includes/class-wp-filesystem-ssh2.php
new file mode 100644
index 0000000000..8ff3cb18e7
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-filesystem-ssh2.php
@@ -0,0 +1,386 @@
+<?php
+/**
+ * WordPress SSH2 Filesystem.
+ *
+ * @package WordPress
+ * @subpackage Filesystem
+ */
+
+/**
+ * WordPress Filesystem Class for implementing SSH2.
+ *
+ * To use this class you must follow these steps for PHP 5.2.6+
+ *
+ * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes
+ *
+ * Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work)
+ *
+ * cd /usr/src
+ * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz
+ * tar -zxvf libssh2-0.14.tar.gz
+ * cd libssh2-0.14/
+ * ./configure
+ * make all install
+ *
+ * Note: Do not leave the directory yet!
+ *
+ * Enter: pecl install -f ssh2
+ *
+ * Copy the ssh.so file it creates to your PHP Module Directory.
+ * Open up your PHP.INI file and look for where extensions are placed.
+ * Add in your PHP.ini file: extension=ssh2.so
+ *
+ * Restart Apache!
+ * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp exist.
+ *
+ * Note: as of WordPress 2.8, This utilises the PHP5+ function 'stream_get_contents'
+ *
+ * @since 2.7
+ * @package WordPress
+ * @subpackage Filesystem
+ * @uses WP_Filesystem_Base Extends class
+ */
+class WP_Filesystem_SSH2 extends WP_Filesystem_Base {
+
+ var $link = false;
+ var $sftp_link = false;
+ var $keys = false;
+ var $errors = array();
+ var $options = array();
+
+ function __construct($opt='') {
+ $this->method = 'ssh2';
+ $this->errors = new WP_Error();
+
+ //Check if possible to use ssh2 functions.
+ if ( ! extension_loaded('ssh2') ) {
+ $this->errors->add('no_ssh2_ext', __('The ssh2 PHP extension is not available'));
+ return false;
+ }
+ if ( !function_exists('stream_get_contents') ) {
+ $this->errors->add('ssh2_php_requirement', __('The ssh2 PHP extension is available, however, we require the PHP5 function <code>stream_get_contents()</code>'));
+ return false;
+ }
+
+ // Set defaults:
+ if ( empty($opt['port']) )
+ $this->options['port'] = 22;
+ else
+ $this->options['port'] = $opt['port'];
+
+ if ( empty($opt['hostname']) )
+ $this->errors->add('empty_hostname', __('SSH2 hostname is required'));
+ else
+ $this->options['hostname'] = $opt['hostname'];
+
+ if ( ! empty($opt['base']) )
+ $this->wp_base = $opt['base'];
+
+ // Check if the options provided are OK.
+ if ( !empty ($opt['public_key']) && !empty ($opt['private_key']) ) {
+ $this->options['public_key'] = $opt['public_key'];
+ $this->options['private_key'] = $opt['private_key'];
+
+ $this->options['hostkey'] = array('hostkey' => 'ssh-rsa');
+
+ $this->keys = true;
+ } elseif ( empty ($opt['username']) ) {
+ $this->errors->add('empty_username', __('SSH2 username is required'));
+ }
+
+ if ( !empty($opt['username']) )
+ $this->options['username'] = $opt['username'];
+
+ if ( empty ($opt['password']) ) {
+ if ( !$this->keys ) //password can be blank if we are using keys
+ $this->errors->add('empty_password', __('SSH2 password is required'));
+ } else {
+ $this->options['password'] = $opt['password'];
+ }
+
+ }
+
+ function connect() {
+ if ( ! $this->keys ) {
+ $this->link = @ssh2_connect($this->options['hostname'], $this->options['port']);
+ } else {
+ $this->link = @ssh2_connect($this->options['hostname'], $this->options['port'], $this->options['hostkey']);
+ }
+
+ if ( ! $this->link ) {
+ $this->errors->add('connect', sprintf(__('Failed to connect to SSH2 Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
+ return false;
+ }
+
+ if ( !$this->keys ) {
+ if ( ! @ssh2_auth_password($this->link, $this->options['username'], $this->options['password']) ) {
+ $this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
+ return false;
+ }
+ } else {
+ if ( ! @ssh2_auth_pubkey_file($this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
+ $this->errors->add('auth', sprintf(__('Public and Private keys incorrect for %s'), $this->options['username']));
+ return false;
+ }
+ }
+
+ $this->sftp_link = ssh2_sftp($this->link);
+
+ return true;
+ }
+
+ function run_command( $command, $returnbool = false) {
+
+ if ( ! $this->link )
+ return false;
+
+ if ( ! ($stream = ssh2_exec($this->link, $command)) ) {
+ $this->errors->add('command', sprintf(__('Unable to perform command: %s'), $command));
+ } else {
+ stream_set_blocking( $stream, true );
+ stream_set_timeout( $stream, FS_TIMEOUT );
+ $data = stream_get_contents( $stream );
+ fclose( $stream );
+
+ if ( $returnbool )
+ return ( $data === false ) ? false : '' != trim($data);
+ else
+ return $data;
+ }
+ return false;
+ }
+
+ function get_contents($file, $type = '', $resumepos = 0 ) {
+ $file = ltrim($file, '/');
+ return file_get_contents('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function get_contents_array($file) {
+ $file = ltrim($file, '/');
+ return file('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function put_contents($file, $contents, $mode = false ) {
+ $file = ltrim($file, '/');
+ $ret = file_put_contents('ssh2.sftp://' . $this->sftp_link . '/' . $file, $contents);
+
+ $this->chmod($file, $mode);
+
+ return false !== $ret;
+ }
+
+ function cwd() {
+ $cwd = $this->run_command('pwd');
+ if ( $cwd )
+ $cwd = trailingslashit($cwd);
+ return $cwd;
+ }
+
+ function chdir($dir) {
+ return $this->run_command('cd ' . $dir, true);
+ }
+
+ function chgrp($file, $group, $recursive = false ) {
+ if ( ! $this->exists($file) )
+ return false;
+ if ( ! $recursive || ! $this->is_dir($file) )
+ return $this->run_command(sprintf('chgrp %s %s', escapeshellarg($group), escapeshellarg($file)), true);
+ return $this->run_command(sprintf('chgrp -R %s %s', escapeshellarg($group), escapeshellarg($file)), true);
+ }
+
+ function chmod($file, $mode = false, $recursive = false) {
+ if ( ! $this->exists($file) )
+ return false;
+
+ if ( ! $mode ) {
+ if ( $this->is_file($file) )
+ $mode = FS_CHMOD_FILE;
+ elseif ( $this->is_dir($file) )
+ $mode = FS_CHMOD_DIR;
+ else
+ return false;
+ }
+
+ if ( ! $recursive || ! $this->is_dir($file) )
+ return $this->run_command(sprintf('chmod %o %s', $mode, escapeshellarg($file)), true);
+ return $this->run_command(sprintf('chmod -R %o %s', $mode, escapeshellarg($file)), true);
+ }
+
+ function chown($file, $owner, $recursive = false ) {
+ if ( ! $this->exists($file) )
+ return false;
+ if ( ! $recursive || ! $this->is_dir($file) )
+ return $this->run_command(sprintf('chown %s %s', escapeshellarg($owner), escapeshellarg($file)), true);
+ return $this->run_command(sprintf('chown -R %s %s', escapeshellarg($owner), escapeshellarg($file)), true);
+ }
+
+ function owner($file) {
+ $owneruid = @fileowner('ssh2.sftp://' . $this->sftp_link . '/' . ltrim($file, '/'));
+ if ( ! $owneruid )
+ return false;
+ if ( ! function_exists('posix_getpwuid') )
+ return $owneruid;
+ $ownerarray = posix_getpwuid($owneruid);
+ return $ownerarray['name'];
+ }
+
+ function getchmod($file) {
+ return substr(decoct(@fileperms( 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim($file, '/') )),3);
+ }
+
+ function group($file) {
+ $gid = @filegroup('ssh2.sftp://' . $this->sftp_link . '/' . ltrim($file, '/'));
+ if ( ! $gid )
+ return false;
+ if ( ! function_exists('posix_getgrgid') )
+ return $gid;
+ $grouparray = posix_getgrgid($gid);
+ return $grouparray['name'];
+ }
+
+ function copy($source, $destination, $overwrite = false, $mode = false) {
+ if ( ! $overwrite && $this->exists($destination) )
+ return false;
+ $content = $this->get_contents($source);
+ if ( false === $content)
+ return false;
+ return $this->put_contents($destination, $content, $mode);
+ }
+
+ function move($source, $destination, $overwrite = false) {
+ return @ssh2_sftp_rename($this->link, $source, $destination);
+ }
+
+ function delete($file, $recursive = false, $type = false) {
+ if ( 'f' == $type || $this->is_file($file) )
+ return ssh2_sftp_unlink($this->sftp_link, $file);
+ if ( ! $recursive )
+ return ssh2_sftp_rmdir($this->sftp_link, $file);
+ $filelist = $this->dirlist($file);
+ if ( is_array($filelist) ) {
+ foreach ( $filelist as $filename => $fileinfo) {
+ $this->delete($file . '/' . $filename, $recursive, $fileinfo['type']);
+ }
+ }
+ return ssh2_sftp_rmdir($this->sftp_link, $file);
+ }
+
+ function exists($file) {
+ $file = ltrim($file, '/');
+ return file_exists('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function is_file($file) {
+ $file = ltrim($file, '/');
+ return is_file('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function is_dir($path) {
+ $path = ltrim($path, '/');
+ return is_dir('ssh2.sftp://' . $this->sftp_link . '/' . $path);
+ }
+
+ function is_readable($file) {
+ $file = ltrim($file, '/');
+ return is_readable('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function is_writable($file) {
+ $file = ltrim($file, '/');
+ return is_writable('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function atime($file) {
+ $file = ltrim($file, '/');
+ return fileatime('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function mtime($file) {
+ $file = ltrim($file, '/');
+ return filemtime('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function size($file) {
+ $file = ltrim($file, '/');
+ return filesize('ssh2.sftp://' . $this->sftp_link . '/' . $file);
+ }
+
+ function touch($file, $time = 0, $atime = 0) {
+ //Not implemented.
+ }
+
+ function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
+ $path = untrailingslashit($path);
+ if ( empty($path) )
+ return false;
+
+ if ( ! $chmod )
+ $chmod = FS_CHMOD_DIR;
+ if ( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) )
+ return false;
+ if ( $chown )
+ $this->chown($path, $chown);
+ if ( $chgrp )
+ $this->chgrp($path, $chgrp);
+ return true;
+ }
+
+ function rmdir($path, $recursive = false) {
+ return $this->delete($path, $recursive);
+ }
+
+ function dirlist($path, $include_hidden = true, $recursive = false) {
+ if ( $this->is_file($path) ) {
+ $limit_file = basename($path);
+ $path = dirname($path);
+ } else {
+ $limit_file = false;
+ }
+
+ if ( ! $this->is_dir($path) )
+ return false;
+
+ $ret = array();
+ $dir = @dir('ssh2.sftp://' . $this->sftp_link .'/' . ltrim($path, '/') );
+
+ if ( ! $dir )
+ return false;
+
+ while (false !== ($entry = $dir->read()) ) {
+ $struc = array();
+ $struc['name'] = $entry;
+
+ if ( '.' == $struc['name'] || '..' == $struc['name'] )
+ continue; //Do not care about these folders.
+
+ if ( ! $include_hidden && '.' == $struc['name'][0] )
+ continue;
+
+ if ( $limit_file && $struc['name'] != $limit_file )
+ continue;
+
+ $struc['perms'] = $this->gethchmod($path.'/'.$entry);
+ $struc['permsn'] = $this->getnumchmodfromh($struc['perms']);
+ $struc['number'] = false;
+ $struc['owner'] = $this->owner($path.'/'.$entry);
+ $struc['group'] = $this->group($path.'/'.$entry);
+ $struc['size'] = $this->size($path.'/'.$entry);
+ $struc['lastmodunix']= $this->mtime($path.'/'.$entry);
+ $struc['lastmod'] = date('M j',$struc['lastmodunix']);
+ $struc['time'] = date('h:i:s',$struc['lastmodunix']);
+ $struc['type'] = $this->is_dir($path.'/'.$entry) ? 'd' : 'f';
+
+ if ( 'd' == $struc['type'] ) {
+ if ( $recursive )
+ $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
+ else
+ $struc['files'] = array();
+ }
+
+ $ret[ $struc['name'] ] = $struc;
+ }
+ $dir->close();
+ unset($dir);
+ return $ret;
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-importer.php b/src/wp-admin/includes/class-wp-importer.php
new file mode 100644
index 0000000000..b017c84fcd
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-importer.php
@@ -0,0 +1,302 @@
+<?php
+/**
+ * WP_Importer base class
+ */
+class WP_Importer {
+ /**
+ * Class Constructor
+ *
+ * @return void
+ */
+ function __construct() {}
+
+ /**
+ * Returns array with imported permalinks from WordPress database
+ *
+ * @param string $bid
+ * @return array
+ */
+ function get_imported_posts( $importer_name, $bid ) {
+ global $wpdb;
+
+ $hashtable = array();
+
+ $limit = 100;
+ $offset = 0;
+
+ // Grab all posts in chunks
+ do {
+ $meta_key = $importer_name . '_' . $bid . '_permalink';
+ $sql = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '%s' LIMIT %d,%d", $meta_key, $offset, $limit );
+ $results = $wpdb->get_results( $sql );
+
+ // Increment offset
+ $offset = ( $limit + $offset );
+
+ if ( !empty( $results ) ) {
+ foreach ( $results as $r ) {
+ // Set permalinks into array
+ $hashtable[$r->meta_value] = intval( $r->post_id );
+ }
+ }
+ } while ( count( $results ) == $limit );
+
+ // unset to save memory
+ unset( $results, $r );
+
+ return $hashtable;
+ }
+
+ /**
+ * Return count of imported permalinks from WordPress database
+ *
+ * @param string $bid
+ * @return int
+ */
+ function count_imported_posts( $importer_name, $bid ) {
+ global $wpdb;
+
+ $count = 0;
+
+ // Get count of permalinks
+ $meta_key = $importer_name . '_' . $bid . '_permalink';
+ $sql = $wpdb->prepare( "SELECT COUNT( post_id ) AS cnt FROM $wpdb->postmeta WHERE meta_key = '%s'", $meta_key );
+
+ $result = $wpdb->get_results( $sql );
+
+ if ( !empty( $result ) )
+ $count = intval( $result[0]->cnt );
+
+ // unset to save memory
+ unset( $results );
+
+ return $count;
+ }
+
+ /**
+ * Set array with imported comments from WordPress database
+ *
+ * @param string $bid
+ * @return array
+ */
+ function get_imported_comments( $bid ) {
+ global $wpdb;
+
+ $hashtable = array();
+
+ $limit = 100;
+ $offset = 0;
+
+ // Grab all comments in chunks
+ do {
+ $sql = $wpdb->prepare( "SELECT comment_ID, comment_agent FROM $wpdb->comments LIMIT %d,%d", $offset, $limit );
+ $results = $wpdb->get_results( $sql );
+
+ // Increment offset
+ $offset = ( $limit + $offset );
+
+ if ( !empty( $results ) ) {
+ foreach ( $results as $r ) {
+ // Explode comment_agent key
+ list ( $ca_bid, $source_comment_id ) = explode( '-', $r->comment_agent );
+ $source_comment_id = intval( $source_comment_id );
+
+ // Check if this comment came from this blog
+ if ( $bid == $ca_bid ) {
+ $hashtable[$source_comment_id] = intval( $r->comment_ID );
+ }
+ }
+ }
+ } while ( count( $results ) == $limit );
+
+ // unset to save memory
+ unset( $results, $r );
+
+ return $hashtable;
+ }
+
+ function set_blog( $blog_id ) {
+ if ( is_numeric( $blog_id ) ) {
+ $blog_id = (int) $blog_id;
+ } else {
+ $blog = 'http://' . preg_replace( '#^https?://#', '', $blog_id );
+ if ( ( !$parsed = parse_url( $blog ) ) || empty( $parsed['host'] ) ) {
+ fwrite( STDERR, "Error: can not determine blog_id from $blog_id\n" );
+ exit();
+ }
+ if ( empty( $parsed['path'] ) )
+ $parsed['path'] = '/';
+ $blog = get_blog_details( array( 'domain' => $parsed['host'], 'path' => $parsed['path'] ) );
+ if ( !$blog ) {
+ fwrite( STDERR, "Error: Could not find blog\n" );
+ exit();
+ }
+ $blog_id = (int) $blog->blog_id;
+ }
+
+ if ( function_exists( 'is_multisite' ) ) {
+ if ( is_multisite() )
+ switch_to_blog( $blog_id );
+ }
+
+ return $blog_id;
+ }
+
+ function set_user( $user_id ) {
+ if ( is_numeric( $user_id ) ) {
+ $user_id = (int) $user_id;
+ } else {
+ $user_id = (int) username_exists( $user_id );
+ }
+
+ if ( !$user_id || !wp_set_current_user( $user_id ) ) {
+ fwrite( STDERR, "Error: can not find user\n" );
+ exit();
+ }
+
+ return $user_id;
+ }
+
+ /**
+ * Sort by strlen, longest string first
+ *
+ * @param string $a
+ * @param string $b
+ * @return int
+ */
+ function cmpr_strlen( $a, $b ) {
+ return strlen( $b ) - strlen( $a );
+ }
+
+ /**
+ * GET URL
+ *
+ * @param string $url
+ * @param string $username
+ * @param string $password
+ * @param bool $head
+ * @return array
+ */
+ function get_page( $url, $username = '', $password = '', $head = false ) {
+ // Increase the timeout
+ add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
+
+ $headers = array();
+ $args = array();
+ if ( true === $head )
+ $args['method'] = 'HEAD';
+ if ( !empty( $username ) && !empty( $password ) )
+ $headers['Authorization'] = 'Basic ' . base64_encode( "$username:$password" );
+
+ $args['headers'] = $headers;
+
+ return wp_safe_remote_request( $url, $args );
+ }
+
+ /**
+ * Bump up the request timeout for http requests
+ *
+ * @param int $val
+ * @return int
+ */
+ function bump_request_timeout( $val ) {
+ return 60;
+ }
+
+ /**
+ * Check if user has exceeded disk quota
+ *
+ * @return bool
+ */
+ function is_user_over_quota() {
+ if ( function_exists( 'upload_is_user_over_quota' ) ) {
+ if ( upload_is_user_over_quota( 1 ) ) {
+ echo "Sorry, you have used your upload quota.\n";
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Replace newlines, tabs, and multiple spaces with a single space
+ *
+ * @param string $string
+ * @return string
+ */
+ function min_whitespace( $string ) {
+ return preg_replace( '|[\r\n\t ]+|', ' ', $string );
+ }
+
+ /**
+ * Reset global variables that grow out of control during imports
+ *
+ * @return void
+ */
+ function stop_the_insanity() {
+ global $wpdb, $wp_actions;
+ // Or define( 'WP_IMPORTING', true );
+ $wpdb->queries = array();
+ // Reset $wp_actions to keep it from growing out of control
+ $wp_actions = array();
+ }
+}
+
+/**
+ * Returns value of command line params.
+ * Exits when a required param is not set.
+ *
+ * @param string $param
+ * @param bool $required
+ * @return mixed
+ */
+function get_cli_args( $param, $required = false ) {
+ $args = $_SERVER['argv'];
+
+ $out = array();
+
+ $last_arg = null;
+ $return = null;
+
+ $il = sizeof( $args );
+
+ for ( $i = 1, $il; $i < $il; $i++ ) {
+ if ( (bool) preg_match( "/^--(.+)/", $args[$i], $match ) ) {
+ $parts = explode( "=", $match[1] );
+ $key = preg_replace( "/[^a-z0-9]+/", "", $parts[0] );
+
+ if ( isset( $parts[1] ) ) {
+ $out[$key] = $parts[1];
+ } else {
+ $out[$key] = true;
+ }
+
+ $last_arg = $key;
+ } else if ( (bool) preg_match( "/^-([a-zA-Z0-9]+)/", $args[$i], $match ) ) {
+ for ( $j = 0, $jl = strlen( $match[1] ); $j < $jl; $j++ ) {
+ $key = $match[1]{$j};
+ $out[$key] = true;
+ }
+
+ $last_arg = $key;
+ } else if ( $last_arg !== null ) {
+ $out[$last_arg] = $args[$i];
+ }
+ }
+
+ // Check array for specified param
+ if ( isset( $out[$param] ) ) {
+ // Set return value
+ $return = $out[$param];
+ }
+
+ // Check for missing required param
+ if ( !isset( $out[$param] ) && $required ) {
+ // Display message and exit
+ echo "\"$param\" parameter is required but was not specified\n";
+ exit();
+ }
+
+ return $return;
+}
diff --git a/src/wp-admin/includes/class-wp-links-list-table.php b/src/wp-admin/includes/class-wp-links-list-table.php
new file mode 100644
index 0000000000..e1c5f18b1b
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-links-list-table.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ * Links Manager List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Links_List_Table extends WP_List_Table {
+
+ function __construct( $args = array() ) {
+ parent::__construct( array(
+ 'plural' => 'bookmarks',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+ }
+
+ function ajax_user_can() {
+ return current_user_can( 'manage_links' );
+ }
+
+ function prepare_items() {
+ global $cat_id, $s, $orderby, $order;
+
+ wp_reset_vars( array( 'action', 'cat_id', 'link_id', 'orderby', 'order', 's' ) );
+
+ $args = array( 'hide_invisible' => 0, 'hide_empty' => 0 );
+
+ if ( 'all' != $cat_id )
+ $args['category'] = $cat_id;
+ if ( !empty( $s ) )
+ $args['search'] = $s;
+ if ( !empty( $orderby ) )
+ $args['orderby'] = $orderby;
+ if ( !empty( $order ) )
+ $args['order'] = $order;
+
+ $this->items = get_bookmarks( $args );
+ }
+
+ function no_items() {
+ _e( 'No links found.' );
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+ $actions['delete'] = __( 'Delete' );
+
+ return $actions;
+ }
+
+ function extra_tablenav( $which ) {
+ global $cat_id;
+
+ if ( 'top' != $which )
+ return;
+?>
+ <div class="alignleft actions">
+<?php
+ $dropdown_options = array(
+ 'selected' => $cat_id,
+ 'name' => 'cat_id',
+ 'taxonomy' => 'link_category',
+ 'show_option_all' => __( 'View all categories' ),
+ 'hide_empty' => true,
+ 'hierarchical' => 1,
+ 'show_count' => 0,
+ 'orderby' => 'name',
+ );
+ wp_dropdown_categories( $dropdown_options );
+ submit_button( __( 'Filter' ), 'button', false, false, array( 'id' => 'post-query-submit' ) );
+?>
+ </div>
+<?php
+ }
+
+ function get_columns() {
+ return array(
+ 'cb' => '<input type="checkbox" />',
+ 'name' => _x( 'Name', 'link name' ),
+ 'url' => __( 'URL' ),
+ 'categories' => __( 'Categories' ),
+ 'rel' => __( 'Relationship' ),
+ 'visible' => __( 'Visible' ),
+ 'rating' => __( 'Rating' )
+ );
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'name' => 'name',
+ 'url' => 'url',
+ 'visible' => 'visible',
+ 'rating' => 'rating'
+ );
+ }
+
+ function display_rows() {
+ global $cat_id;
+
+ $alt = 0;
+
+ foreach ( $this->items as $link ) {
+ $link = sanitize_bookmark( $link );
+ $link->link_name = esc_attr( $link->link_name );
+ $link->link_category = wp_get_link_cats( $link->link_id );
+
+ $short_url = url_shorten( $link->link_url );
+
+ $visible = ( $link->link_visible == 'Y' ) ? __( 'Yes' ) : __( 'No' );
+ $rating = $link->link_rating;
+ $style = ( $alt++ % 2 ) ? '' : ' class="alternate"';
+
+ $edit_link = get_edit_bookmark_link( $link );
+?>
+ <tr id="link-<?php echo $link->link_id; ?>" valign="middle" <?php echo $style; ?>>
+<?php
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $class = "class='column-$column_name'";
+
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ $attributes = $class . $style;
+
+ switch ( $column_name ) {
+ case 'cb': ?>
+ <th scope="row" class="check-column">
+ <label class="screen-reader-text" for="cb-select-<?php echo $link->link_id; ?>"><?php echo sprintf( __( 'Select %s' ), $link->link_name ); ?></label>
+ <input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" />
+ </th>
+ <?php
+ break;
+
+ case 'name':
+ echo "<td $attributes><strong><a class='row-title' href='$edit_link' title='" . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $link->link_name ) ) . "'>$link->link_name</a></strong><br />";
+
+ $actions = array();
+ $actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+ $actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url( "link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id ) . "' onclick=\"if ( confirm( '" . esc_js( sprintf( __( "You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete." ), $link->link_name ) ) . "' ) ) { return true;}return false;\">" . __( 'Delete' ) . "</a>";
+ echo $this->row_actions( $actions );
+
+ echo '</td>';
+ break;
+ case 'url':
+ echo "<td $attributes><a href='$link->link_url' title='". esc_attr( sprintf( __( 'Visit %s' ), $link->link_name ) )."'>$short_url</a></td>";
+ break;
+ case 'categories':
+ ?><td <?php echo $attributes ?>><?php
+ $cat_names = array();
+ foreach ( $link->link_category as $category ) {
+ $cat = get_term( $category, 'link_category', OBJECT, 'display' );
+ if ( is_wp_error( $cat ) )
+ echo $cat->get_error_message();
+ $cat_name = $cat->name;
+ if ( $cat_id != $category )
+ $cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>";
+ $cat_names[] = $cat_name;
+ }
+ echo implode( ', ', $cat_names );
+ ?></td><?php
+ break;
+ case 'rel':
+ ?><td <?php echo $attributes ?>><?php echo empty( $link->link_rel ) ? '<br />' : $link->link_rel; ?></td><?php
+ break;
+ case 'visible':
+ ?><td <?php echo $attributes ?>><?php echo $visible; ?></td><?php
+ break;
+ case 'rating':
+ ?><td <?php echo $attributes ?>><?php echo $rating; ?></td><?php
+ break;
+ default:
+ ?>
+ <td <?php echo $attributes ?>><?php do_action( 'manage_link_custom_column', $column_name, $link->link_id ); ?></td>
+ <?php
+ break;
+ }
+ }
+?>
+ </tr>
+<?php
+ }
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-list-table.php b/src/wp-admin/includes/class-wp-list-table.php
new file mode 100644
index 0000000000..22c35f5edc
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-list-table.php
@@ -0,0 +1,920 @@
+<?php
+/**
+ * Base class for displaying a list of items in an ajaxified HTML table.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ */
+
+/**
+ * Base class for displaying a list of items in an ajaxified HTML table.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_List_Table {
+
+ /**
+ * The current list of items
+ *
+ * @since 3.1.0
+ * @var array
+ * @access protected
+ */
+ var $items;
+
+ /**
+ * Various information about the current table
+ *
+ * @since 3.1.0
+ * @var array
+ * @access private
+ */
+ var $_args;
+
+ /**
+ * Various information needed for displaying the pagination
+ *
+ * @since 3.1.0
+ * @var array
+ * @access private
+ */
+ var $_pagination_args = array();
+
+ /**
+ * The current screen
+ *
+ * @since 3.1.0
+ * @var object
+ * @access protected
+ */
+ var $screen;
+
+ /**
+ * Cached bulk actions
+ *
+ * @since 3.1.0
+ * @var array
+ * @access private
+ */
+ var $_actions;
+
+ /**
+ * Cached pagination output
+ *
+ * @since 3.1.0
+ * @var string
+ * @access private
+ */
+ var $_pagination;
+
+ /**
+ * Constructor. The child class should call this constructor from its own constructor
+ *
+ * @param array $args An associative array with information about the current table
+ * @access protected
+ */
+ function __construct( $args = array() ) {
+ $args = wp_parse_args( $args, array(
+ 'plural' => '',
+ 'singular' => '',
+ 'ajax' => false,
+ 'screen' => null,
+ ) );
+
+ $this->screen = convert_to_screen( $args['screen'] );
+
+ add_filter( "manage_{$this->screen->id}_columns", array( &$this, 'get_columns' ), 0 );
+
+ if ( !$args['plural'] )
+ $args['plural'] = $this->screen->base;
+
+ $args['plural'] = sanitize_key( $args['plural'] );
+ $args['singular'] = sanitize_key( $args['singular'] );
+
+ $this->_args = $args;
+
+ if ( $args['ajax'] ) {
+ // wp_enqueue_script( 'list-table' );
+ add_action( 'admin_footer', array( &$this, '_js_vars' ) );
+ }
+ }
+
+ /**
+ * Checks the current user's permissions
+ * @uses wp_die()
+ *
+ * @since 3.1.0
+ * @access public
+ * @abstract
+ */
+ function ajax_user_can() {
+ die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
+ }
+
+ /**
+ * Prepares the list of items for displaying.
+ * @uses WP_List_Table::set_pagination_args()
+ *
+ * @since 3.1.0
+ * @access public
+ * @abstract
+ */
+ function prepare_items() {
+ die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
+ }
+
+ /**
+ * An internal method that sets all the necessary pagination arguments
+ *
+ * @param array $args An associative array with information about the pagination
+ * @access protected
+ */
+ function set_pagination_args( $args ) {
+ $args = wp_parse_args( $args, array(
+ 'total_items' => 0,
+ 'total_pages' => 0,
+ 'per_page' => 0,
+ ) );
+
+ if ( !$args['total_pages'] && $args['per_page'] > 0 )
+ $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
+
+ // redirect if page number is invalid and headers are not already sent
+ if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
+ wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
+ exit;
+ }
+
+ $this->_pagination_args = $args;
+ }
+
+ /**
+ * Access the pagination args
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @param string $key
+ * @return array
+ */
+ function get_pagination_arg( $key ) {
+ if ( 'page' == $key )
+ return $this->get_pagenum();
+
+ if ( isset( $this->_pagination_args[$key] ) )
+ return $this->_pagination_args[$key];
+ }
+
+ /**
+ * Whether the table has items to display or not
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return bool
+ */
+ function has_items() {
+ return !empty( $this->items );
+ }
+
+ /**
+ * Message to be displayed when there are no items
+ *
+ * @since 3.1.0
+ * @access public
+ */
+ function no_items() {
+ _e( 'No items found.' );
+ }
+
+ /**
+ * Display the search box.
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @param string $text The search button text
+ * @param string $input_id The search input id
+ */
+ function search_box( $text, $input_id ) {
+ if ( empty( $_REQUEST['s'] ) && !$this->has_items() )
+ return;
+
+ $input_id = $input_id . '-search-input';
+
+ if ( ! empty( $_REQUEST['orderby'] ) )
+ echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
+ if ( ! empty( $_REQUEST['order'] ) )
+ echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
+ if ( ! empty( $_REQUEST['post_mime_type'] ) )
+ echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
+ if ( ! empty( $_REQUEST['detached'] ) )
+ echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
+?>
+<p class="search-box">
+ <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
+ <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>" />
+ <?php submit_button( $text, 'button', false, false, array('id' => 'search-submit') ); ?>
+</p>
+<?php
+ }
+
+ /**
+ * Get an associative array ( id => link ) with the list
+ * of views available on this table.
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return array
+ */
+ function get_views() {
+ return array();
+ }
+
+ /**
+ * Display the list of views available on this table.
+ *
+ * @since 3.1.0
+ * @access public
+ */
+ function views() {
+ $views = $this->get_views();
+ $views = apply_filters( 'views_' . $this->screen->id, $views );
+
+ if ( empty( $views ) )
+ return;
+
+ echo "<ul class='subsubsub'>\n";
+ foreach ( $views as $class => $view ) {
+ $views[ $class ] = "\t<li class='$class'>$view";
+ }
+ echo implode( " |</li>\n", $views ) . "</li>\n";
+ echo "</ul>";
+ }
+
+ /**
+ * Get an associative array ( option_name => option_title ) with the list
+ * of bulk actions available on this table.
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return array
+ */
+ function get_bulk_actions() {
+ return array();
+ }
+
+ /**
+ * Display the bulk actions dropdown.
+ *
+ * @since 3.1.0
+ * @access public
+ */
+ function bulk_actions() {
+ if ( is_null( $this->_actions ) ) {
+ $no_new_actions = $this->_actions = $this->get_bulk_actions();
+ // This filter can currently only be used to remove actions.
+ $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions );
+ $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
+ $two = '';
+ } else {
+ $two = '2';
+ }
+
+ if ( empty( $this->_actions ) )
+ return;
+
+ echo "<select name='action$two'>\n";
+ echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions' ) . "</option>\n";
+
+ foreach ( $this->_actions as $name => $title ) {
+ $class = 'edit' == $name ? ' class="hide-if-no-js"' : '';
+
+ echo "\t<option value='$name'$class>$title</option>\n";
+ }
+
+ echo "</select>\n";
+
+ submit_button( __( 'Apply' ), 'action', false, false, array( 'id' => "doaction$two" ) );
+ echo "\n";
+ }
+
+ /**
+ * Get the current action selected from the bulk actions dropdown.
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return string|bool The action name or False if no action was selected
+ */
+ function current_action() {
+ if ( isset( $_REQUEST['action'] ) && -1 != $_REQUEST['action'] )
+ return $_REQUEST['action'];
+
+ if ( isset( $_REQUEST['action2'] ) && -1 != $_REQUEST['action2'] )
+ return $_REQUEST['action2'];
+
+ return false;
+ }
+
+ /**
+ * Generate row actions div
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @param array $actions The list of actions
+ * @param bool $always_visible Whether the actions should be always visible
+ * @return string
+ */
+ function row_actions( $actions, $always_visible = false ) {
+ $action_count = count( $actions );
+ $i = 0;
+
+ if ( !$action_count )
+ return '';
+
+ $out = '<div class="' . ( $always_visible ? 'row-actions-visible' : 'row-actions' ) . '">';
+ foreach ( $actions as $action => $link ) {
+ ++$i;
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
+ $out .= "<span class='$action'>$link$sep</span>";
+ }
+ $out .= '</div>';
+
+ return $out;
+ }
+
+ /**
+ * Display a monthly dropdown for filtering items
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function months_dropdown( $post_type ) {
+ global $wpdb, $wp_locale;
+
+ $months = $wpdb->get_results( $wpdb->prepare( "
+ SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
+ FROM $wpdb->posts
+ WHERE post_type = %s
+ ORDER BY post_date DESC
+ ", $post_type ) );
+
+ $month_count = count( $months );
+
+ if ( !$month_count || ( 1 == $month_count && 0 == $months[0]->month ) )
+ return;
+
+ $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
+?>
+ <select name='m'>
+ <option<?php selected( $m, 0 ); ?> value='0'><?php _e( 'Show all dates' ); ?></option>
+<?php
+ foreach ( $months as $arc_row ) {
+ if ( 0 == $arc_row->year )
+ continue;
+
+ $month = zeroise( $arc_row->month, 2 );
+ $year = $arc_row->year;
+
+ printf( "<option %s value='%s'>%s</option>\n",
+ selected( $m, $year . $month, false ),
+ esc_attr( $arc_row->year . $month ),
+ /* translators: 1: month name, 2: 4-digit year */
+ sprintf( __( '%1$s %2$d' ), $wp_locale->get_month( $month ), $year )
+ );
+ }
+?>
+ </select>
+<?php
+ }
+
+ /**
+ * Display a view switcher
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function view_switcher( $current_mode ) {
+ $modes = array(
+ 'list' => __( 'List View' ),
+ 'excerpt' => __( 'Excerpt View' )
+ );
+
+?>
+ <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>" />
+ <div class="view-switch">
+<?php
+ foreach ( $modes as $mode => $title ) {
+ $class = ( $current_mode == $mode ) ? 'class="current"' : '';
+ echo "<a href='" . esc_url( add_query_arg( 'mode', $mode, $_SERVER['REQUEST_URI'] ) ) . "' $class><img id='view-switch-$mode' src='" . esc_url( includes_url( 'images/blank.gif' ) ) . "' width='20' height='20' title='$title' alt='$title' /></a>\n";
+ }
+ ?>
+ </div>
+<?php
+ }
+
+ /**
+ * Display a comment count bubble
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @param int $post_id
+ * @param int $pending_comments
+ */
+ function comments_bubble( $post_id, $pending_comments ) {
+ $pending_phrase = sprintf( __( '%s pending' ), number_format( $pending_comments ) );
+
+ if ( $pending_comments )
+ echo '<strong>';
+
+ echo "<a href='" . esc_url( add_query_arg( 'p', $post_id, admin_url( 'edit-comments.php' ) ) ) . "' title='" . esc_attr( $pending_phrase ) . "' class='post-com-count'><span class='comment-count'>" . number_format_i18n( get_comments_number() ) . "</span></a>";
+
+ if ( $pending_comments )
+ echo '</strong>';
+ }
+
+ /**
+ * Get the current page number
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return int
+ */
+ function get_pagenum() {
+ $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
+
+ if( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] )
+ $pagenum = $this->_pagination_args['total_pages'];
+
+ return max( 1, $pagenum );
+ }
+
+ /**
+ * Get number of items to display on a single page
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return int
+ */
+ function get_items_per_page( $option, $default = 20 ) {
+ $per_page = (int) get_user_option( $option );
+ if ( empty( $per_page ) || $per_page < 1 )
+ $per_page = $default;
+
+ return (int) apply_filters( $option, $per_page );
+ }
+
+ /**
+ * Display the pagination.
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function pagination( $which ) {
+ if ( empty( $this->_pagination_args ) )
+ return;
+
+ extract( $this->_pagination_args, EXTR_SKIP );
+
+ $output = '<span class="displaying-num">' . sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) ) . '</span>';
+
+ $current = $this->get_pagenum();
+
+ $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+
+ $current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
+
+ $page_links = array();
+
+ $disable_first = $disable_last = '';
+ if ( $current == 1 )
+ $disable_first = ' disabled';
+ if ( $current == $total_pages )
+ $disable_last = ' disabled';
+
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
+ 'first-page' . $disable_first,
+ esc_attr__( 'Go to the first page' ),
+ esc_url( remove_query_arg( 'paged', $current_url ) ),
+ '&laquo;'
+ );
+
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
+ 'prev-page' . $disable_first,
+ esc_attr__( 'Go to the previous page' ),
+ esc_url( add_query_arg( 'paged', max( 1, $current-1 ), $current_url ) ),
+ '&lsaquo;'
+ );
+
+ if ( 'bottom' == $which )
+ $html_current_page = $current;
+ else
+ $html_current_page = sprintf( "<input class='current-page' title='%s' type='text' name='paged' value='%s' size='%d' />",
+ esc_attr__( 'Current page' ),
+ $current,
+ strlen( $total_pages )
+ );
+
+ $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
+ $page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span>';
+
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
+ 'next-page' . $disable_last,
+ esc_attr__( 'Go to the next page' ),
+ esc_url( add_query_arg( 'paged', min( $total_pages, $current+1 ), $current_url ) ),
+ '&rsaquo;'
+ );
+
+ $page_links[] = sprintf( "<a class='%s' title='%s' href='%s'>%s</a>",
+ 'last-page' . $disable_last,
+ esc_attr__( 'Go to the last page' ),
+ esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
+ '&raquo;'
+ );
+
+ $pagination_links_class = 'pagination-links';
+ if ( ! empty( $infinite_scroll ) )
+ $pagination_links_class = ' hide-if-js';
+ $output .= "\n<span class='$pagination_links_class'>" . join( "\n", $page_links ) . '</span>';
+
+ if ( $total_pages )
+ $page_class = $total_pages < 2 ? ' one-page' : '';
+ else
+ $page_class = ' no-pages';
+
+ $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
+
+ echo $this->_pagination;
+ }
+
+ /**
+ * Get a list of columns. The format is:
+ * 'internal-name' => 'Title'
+ *
+ * @since 3.1.0
+ * @access protected
+ * @abstract
+ *
+ * @return array
+ */
+ function get_columns() {
+ die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
+ }
+
+ /**
+ * Get a list of sortable columns. The format is:
+ * 'internal-name' => 'orderby'
+ * or
+ * 'internal-name' => array( 'orderby', true )
+ *
+ * The second format will make the initial sorting order be descending
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return array
+ */
+ function get_sortable_columns() {
+ return array();
+ }
+
+ /**
+ * Get a list of all, hidden and sortable columns, with filter applied
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return array
+ */
+ function get_column_info() {
+ if ( isset( $this->_column_headers ) )
+ return $this->_column_headers;
+
+ $columns = get_column_headers( $this->screen );
+ $hidden = get_hidden_columns( $this->screen );
+
+ $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $this->get_sortable_columns() );
+
+ $sortable = array();
+ foreach ( $_sortable as $id => $data ) {
+ if ( empty( $data ) )
+ continue;
+
+ $data = (array) $data;
+ if ( !isset( $data[1] ) )
+ $data[1] = false;
+
+ $sortable[$id] = $data;
+ }
+
+ $this->_column_headers = array( $columns, $hidden, $sortable );
+
+ return $this->_column_headers;
+ }
+
+ /**
+ * Return number of visible columns
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return int
+ */
+ function get_column_count() {
+ list ( $columns, $hidden ) = $this->get_column_info();
+ $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
+ return count( $columns ) - count( $hidden );
+ }
+
+ /**
+ * Print column headers, accounting for hidden and sortable columns.
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @param bool $with_id Whether to set the id attribute or not
+ */
+ function print_column_headers( $with_id = true ) {
+ list( $columns, $hidden, $sortable ) = $this->get_column_info();
+
+ $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ $current_url = remove_query_arg( 'paged', $current_url );
+
+ if ( isset( $_GET['orderby'] ) )
+ $current_orderby = $_GET['orderby'];
+ else
+ $current_orderby = '';
+
+ if ( isset( $_GET['order'] ) && 'desc' == $_GET['order'] )
+ $current_order = 'desc';
+ else
+ $current_order = 'asc';
+
+ if ( ! empty( $columns['cb'] ) ) {
+ static $cb_counter = 1;
+ $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>'
+ . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />';
+ $cb_counter++;
+ }
+
+ foreach ( $columns as $column_key => $column_display_name ) {
+ $class = array( 'manage-column', "column-$column_key" );
+
+ $style = '';
+ if ( in_array( $column_key, $hidden ) )
+ $style = 'display:none;';
+
+ $style = ' style="' . $style . '"';
+
+ if ( 'cb' == $column_key )
+ $class[] = 'check-column';
+ elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) )
+ $class[] = 'num';
+
+ if ( isset( $sortable[$column_key] ) ) {
+ list( $orderby, $desc_first ) = $sortable[$column_key];
+
+ if ( $current_orderby == $orderby ) {
+ $order = 'asc' == $current_order ? 'desc' : 'asc';
+ $class[] = 'sorted';
+ $class[] = $current_order;
+ } else {
+ $order = $desc_first ? 'desc' : 'asc';
+ $class[] = 'sortable';
+ $class[] = $desc_first ? 'asc' : 'desc';
+ }
+
+ $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
+ }
+
+ $id = $with_id ? "id='$column_key'" : '';
+
+ if ( !empty( $class ) )
+ $class = "class='" . join( ' ', $class ) . "'";
+
+ echo "<th scope='col' $id $class $style>$column_display_name</th>";
+ }
+ }
+
+ /**
+ * Display the table
+ *
+ * @since 3.1.0
+ * @access public
+ */
+ function display() {
+ extract( $this->_args );
+
+ $this->display_tablenav( 'top' );
+
+?>
+<table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>" cellspacing="0">
+ <thead>
+ <tr>
+ <?php $this->print_column_headers(); ?>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr>
+ <?php $this->print_column_headers( false ); ?>
+ </tr>
+ </tfoot>
+
+ <tbody id="the-list"<?php if ( $singular ) echo " data-wp-lists='list:$singular'"; ?>>
+ <?php $this->display_rows_or_placeholder(); ?>
+ </tbody>
+</table>
+<?php
+ $this->display_tablenav( 'bottom' );
+ }
+
+ /**
+ * Get a list of CSS classes for the <table> tag
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @return array
+ */
+ function get_table_classes() {
+ return array( 'widefat', 'fixed', $this->_args['plural'] );
+ }
+
+ /**
+ * Generate the table navigation above or below the table
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function display_tablenav( $which ) {
+ if ( 'top' == $which )
+ wp_nonce_field( 'bulk-' . $this->_args['plural'] );
+?>
+ <div class="tablenav <?php echo esc_attr( $which ); ?>">
+
+ <div class="alignleft actions">
+ <?php $this->bulk_actions(); ?>
+ </div>
+<?php
+ $this->extra_tablenav( $which );
+ $this->pagination( $which );
+?>
+
+ <br class="clear" />
+ </div>
+<?php
+ }
+
+ /**
+ * Extra controls to be displayed between bulk actions and pagination
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function extra_tablenav( $which ) {}
+
+ /**
+ * Generate the <tbody> part of the table
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function display_rows_or_placeholder() {
+ if ( $this->has_items() ) {
+ $this->display_rows();
+ } else {
+ list( $columns, $hidden ) = $this->get_column_info();
+ echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
+ $this->no_items();
+ echo '</td></tr>';
+ }
+ }
+
+ /**
+ * Generate the table rows
+ *
+ * @since 3.1.0
+ * @access protected
+ */
+ function display_rows() {
+ foreach ( $this->items as $item )
+ $this->single_row( $item );
+ }
+
+ /**
+ * Generates content for a single row of the table
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @param object $item The current item
+ */
+ function single_row( $item ) {
+ static $row_class = '';
+ $row_class = ( $row_class == '' ? ' class="alternate"' : '' );
+
+ echo '<tr' . $row_class . '>';
+ $this->single_row_columns( $item );
+ echo '</tr>';
+ }
+
+ /**
+ * Generates the columns for a single row of the table
+ *
+ * @since 3.1.0
+ * @access protected
+ *
+ * @param object $item The current item
+ */
+ function single_row_columns( $item ) {
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $class = "class='$column_name column-$column_name'";
+
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ $attributes = "$class$style";
+
+ if ( 'cb' == $column_name ) {
+ echo '<th scope="row" class="check-column">';
+ echo $this->column_cb( $item );
+ echo '</th>';
+ }
+ elseif ( method_exists( $this, 'column_' . $column_name ) ) {
+ echo "<td $attributes>";
+ echo call_user_func( array( &$this, 'column_' . $column_name ), $item );
+ echo "</td>";
+ }
+ else {
+ echo "<td $attributes>";
+ echo $this->column_default( $item, $column_name );
+ echo "</td>";
+ }
+ }
+ }
+
+ /**
+ * Handle an incoming ajax request (called from admin-ajax.php)
+ *
+ * @since 3.1.0
+ * @access public
+ */
+ function ajax_response() {
+ $this->prepare_items();
+
+ extract( $this->_args );
+ extract( $this->_pagination_args, EXTR_SKIP );
+
+ ob_start();
+ if ( ! empty( $_REQUEST['no_placeholder'] ) )
+ $this->display_rows();
+ else
+ $this->display_rows_or_placeholder();
+
+ $rows = ob_get_clean();
+
+ $response = array( 'rows' => $rows );
+
+ if ( isset( $total_items ) )
+ $response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) );
+
+ if ( isset( $total_pages ) ) {
+ $response['total_pages'] = $total_pages;
+ $response['total_pages_i18n'] = number_format_i18n( $total_pages );
+ }
+
+ die( json_encode( $response ) );
+ }
+
+ /**
+ * Send required variables to JavaScript land
+ *
+ * @access private
+ */
+ function _js_vars() {
+ $args = array(
+ 'class' => get_class( $this ),
+ 'screen' => array(
+ 'id' => $this->screen->id,
+ 'base' => $this->screen->base,
+ )
+ );
+
+ printf( "<script type='text/javascript'>list_args = %s;</script>\n", json_encode( $args ) );
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-media-list-table.php b/src/wp-admin/includes/class-wp-media-list-table.php
new file mode 100644
index 0000000000..67fd187cf6
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-media-list-table.php
@@ -0,0 +1,431 @@
+<?php
+/**
+ * Media Library List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Media_List_Table extends WP_List_Table {
+
+ function __construct( $args = array() ) {
+ $this->detached = isset( $_REQUEST['detached'] ) || isset( $_REQUEST['find_detached'] );
+
+ parent::__construct( array(
+ 'plural' => 'media',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+ }
+
+ function ajax_user_can() {
+ return current_user_can('upload_files');
+ }
+
+ function prepare_items() {
+ global $lost, $wpdb, $wp_query, $post_mime_types, $avail_post_mime_types;
+
+ $q = $_REQUEST;
+
+ if ( !empty( $lost ) )
+ $q['post__in'] = implode( ',', $lost );
+
+ list( $post_mime_types, $avail_post_mime_types ) = wp_edit_attachments_query( $q );
+
+ $this->is_trash = isset( $_REQUEST['status'] ) && 'trash' == $_REQUEST['status'];
+
+ $this->set_pagination_args( array(
+ 'total_items' => $wp_query->found_posts,
+ 'total_pages' => $wp_query->max_num_pages,
+ 'per_page' => $wp_query->query_vars['posts_per_page'],
+ ) );
+ }
+
+ function get_views() {
+ global $wpdb, $post_mime_types, $avail_post_mime_types;
+
+ $type_links = array();
+ $_num_posts = (array) wp_count_attachments();
+ $_total_posts = array_sum($_num_posts) - $_num_posts['trash'];
+ $total_orphans = $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' AND post_parent < 1" );
+ $matches = wp_match_mime_types(array_keys($post_mime_types), array_keys($_num_posts));
+ foreach ( $matches as $type => $reals )
+ foreach ( $reals as $real )
+ $num_posts[$type] = ( isset( $num_posts[$type] ) ) ? $num_posts[$type] + $_num_posts[$real] : $_num_posts[$real];
+
+ $class = ( empty($_GET['post_mime_type']) && !$this->detached && !isset($_GET['status']) ) ? ' class="current"' : '';
+ $type_links['all'] = "<a href='upload.php'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $_total_posts, 'uploaded files' ), number_format_i18n( $_total_posts ) ) . '</a>';
+ foreach ( $post_mime_types as $mime_type => $label ) {
+ $class = '';
+
+ if ( !wp_match_mime_types($mime_type, $avail_post_mime_types) )
+ continue;
+
+ if ( !empty($_GET['post_mime_type']) && wp_match_mime_types($mime_type, $_GET['post_mime_type']) )
+ $class = ' class="current"';
+ if ( !empty( $num_posts[$mime_type] ) )
+ $type_links[$mime_type] = "<a href='upload.php?post_mime_type=$mime_type'$class>" . sprintf( translate_nooped_plural( $label[2], $num_posts[$mime_type] ), number_format_i18n( $num_posts[$mime_type] )) . '</a>';
+ }
+ $type_links['detached'] = '<a href="upload.php?detached=1"' . ( $this->detached ? ' class="current"' : '' ) . '>' . sprintf( _nx( 'Unattached <span class="count">(%s)</span>', 'Unattached <span class="count">(%s)</span>', $total_orphans, 'detached files' ), number_format_i18n( $total_orphans ) ) . '</a>';
+
+ if ( !empty($_num_posts['trash']) )
+ $type_links['trash'] = '<a href="upload.php?status=trash"' . ( (isset($_GET['status']) && $_GET['status'] == 'trash' ) ? ' class="current"' : '') . '>' . sprintf( _nx( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>', $_num_posts['trash'], 'uploaded files' ), number_format_i18n( $_num_posts['trash'] ) ) . '</a>';
+
+ return $type_links;
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+ $actions['delete'] = __( 'Delete Permanently' );
+ if ( $this->detached )
+ $actions['attach'] = __( 'Attach to a post' );
+
+ return $actions;
+ }
+
+ function extra_tablenav( $which ) {
+?>
+ <div class="alignleft actions">
+<?php
+ if ( 'top' == $which && !is_singular() && !$this->detached && !$this->is_trash ) {
+ $this->months_dropdown( 'attachment' );
+
+ do_action( 'restrict_manage_posts' );
+ submit_button( __( 'Filter' ), 'button', false, false, array( 'id' => 'post-query-submit' ) );
+ }
+
+ if ( $this->detached ) {
+ submit_button( __( 'Scan for lost attachments' ), 'secondary', 'find_detached', false );
+ } elseif ( $this->is_trash && current_user_can( 'edit_others_posts' ) ) {
+ submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
+ } ?>
+ </div>
+<?php
+ }
+
+ function current_action() {
+ if ( isset( $_REQUEST['find_detached'] ) )
+ return 'find_detached';
+
+ if ( isset( $_REQUEST['found_post_id'] ) && isset( $_REQUEST['media'] ) )
+ return 'attach';
+
+ if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
+ return 'delete_all';
+
+ return parent::current_action();
+ }
+
+ function has_items() {
+ return have_posts();
+ }
+
+ function no_items() {
+ _e( 'No media attachments found.' );
+ }
+
+ function get_columns() {
+ $posts_columns = array();
+ $posts_columns['cb'] = '<input type="checkbox" />';
+ $posts_columns['icon'] = '';
+ /* translators: column name */
+ $posts_columns['title'] = _x( 'File', 'column name' );
+ $posts_columns['author'] = __( 'Author' );
+
+ $taxonomies = array();
+
+ $taxonomies = get_taxonomies_for_attachments( 'objects' );
+ $taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
+
+ $taxonomies = apply_filters( 'manage_taxonomies_for_attachment_columns', $taxonomies, 'attachment' );
+ $taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( 'category' == $taxonomy )
+ $column_key = 'categories';
+ elseif ( 'post_tag' == $taxonomy )
+ $column_key = 'tags';
+ else
+ $column_key = 'taxonomy-' . $taxonomy;
+
+ $posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
+ }
+
+ /* translators: column name */
+ if ( !$this->detached ) {
+ $posts_columns['parent'] = _x( 'Uploaded to', 'column name' );
+ if ( post_type_supports( 'attachment', 'comments' ) )
+ $posts_columns['comments'] = '<span class="vers"><div title="' . esc_attr__( 'Comments' ) . '" class="comment-grey-bubble"></div></span>';
+ }
+ /* translators: column name */
+ $posts_columns['date'] = _x( 'Date', 'column name' );
+ $posts_columns = apply_filters( 'manage_media_columns', $posts_columns, $this->detached );
+
+ return $posts_columns;
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'title' => 'title',
+ 'author' => 'author',
+ 'parent' => 'parent',
+ 'comments' => 'comment_count',
+ 'date' => array( 'date', true ),
+ );
+ }
+
+ function display_rows() {
+ global $post;
+
+ add_filter( 'the_title','esc_html' );
+ $alt = '';
+
+ while ( have_posts() ) : the_post();
+ $user_can_edit = current_user_can( 'edit_post', $post->ID );
+
+ if ( $this->is_trash && $post->post_status != 'trash'
+ || !$this->is_trash && $post->post_status == 'trash' )
+ continue;
+
+ $alt = ( 'alternate' == $alt ) ? '' : 'alternate';
+ $post_owner = ( get_current_user_id() == $post->post_author ) ? 'self' : 'other';
+ $att_title = _draft_or_post_title();
+?>
+ <tr id='post-<?php echo $post->ID; ?>' class='<?php echo trim( $alt . ' author-' . $post_owner . ' status-' . $post->post_status ); ?>' valign="top">
+<?php
+
+list( $columns, $hidden ) = $this->get_column_info();
+foreach ( $columns as $column_name => $column_display_name ) {
+ $class = "class='$column_name column-$column_name'";
+
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ $attributes = $class . $style;
+
+ switch ( $column_name ) {
+
+ case 'cb':
+?>
+ <th scope="row" class="check-column">
+ <?php if ( $user_can_edit ) { ?>
+ <label class="screen-reader-text" for="cb-select-<?php the_ID(); ?>"><?php echo sprintf( __( 'Select %s' ), $att_title );?></label>
+ <input type="checkbox" name="media[]" id="cb-select-<?php the_ID(); ?>" value="<?php the_ID(); ?>" />
+ <?php } ?>
+ </th>
+<?php
+ break;
+
+ case 'icon':
+ $attributes = 'class="column-icon media-icon"' . $style;
+?>
+ <td <?php echo $attributes ?>><?php
+ if ( $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ) ) {
+ if ( $this->is_trash || ! $user_can_edit ) {
+ echo $thumb;
+ } else {
+?>
+ <a href="<?php echo get_edit_post_link( $post->ID, true ); ?>" title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ); ?>">
+ <?php echo $thumb; ?>
+ </a>
+
+<?php }
+ }
+?>
+ </td>
+<?php
+ break;
+
+ case 'title':
+?>
+ <td <?php echo $attributes ?>><strong>
+ <?php if ( $this->is_trash || ! $user_can_edit ) {
+ echo $att_title;
+ } else { ?>
+ <a href="<?php echo get_edit_post_link( $post->ID, true ); ?>"
+ title="<?php echo esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ); ?>">
+ <?php echo $att_title; ?></a>
+ <?php };
+ _media_states( $post ); ?></strong>
+ <p>
+<?php
+ if ( preg_match( '/^.*?\.(\w+)$/', get_attached_file( $post->ID ), $matches ) )
+ echo esc_html( strtoupper( $matches[1] ) );
+ else
+ echo strtoupper( str_replace( 'image/', '', get_post_mime_type() ) );
+?>
+ </p>
+<?php
+ echo $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
+?>
+ </td>
+<?php
+ break;
+
+ case 'author':
+?>
+ <td <?php echo $attributes ?>><?php
+ printf( '<a href="%s">%s</a>',
+ esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
+ get_the_author()
+ );
+ ?></td>
+<?php
+ break;
+
+ case 'desc':
+?>
+ <td <?php echo $attributes ?>><?php echo has_excerpt() ? $post->post_excerpt : ''; ?></td>
+<?php
+ break;
+
+ case 'date':
+ if ( '0000-00-00 00:00:00' == $post->post_date ) {
+ $h_time = __( 'Unpublished' );
+ } else {
+ $m_time = $post->post_date;
+ $time = get_post_time( 'G', true, $post, false );
+ if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
+ if ( $t_diff < 0 )
+ $h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
+ else
+ $h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
+ } else {
+ $h_time = mysql2date( __( 'Y/m/d' ), $m_time );
+ }
+ }
+?>
+ <td <?php echo $attributes ?>><?php echo $h_time ?></td>
+<?php
+ break;
+
+ case 'parent':
+ if ( $post->post_parent > 0 && get_post( $post->post_parent ) ) {
+ $title = _draft_or_post_title( $post->post_parent );
+?>
+ <td <?php echo $attributes ?>><strong>
+ <?php if ( current_user_can( 'edit_post', $post->post_parent ) ) { ?>
+ <a href="<?php echo get_edit_post_link( $post->post_parent ); ?>">
+ <?php echo $title ?></a><?php
+ } else {
+ echo $title;
+ } ?></strong>,
+ <?php echo get_the_time( __( 'Y/m/d' ) ); ?>
+ </td>
+<?php
+ } else {
+?>
+ <td <?php echo $attributes ?>><?php _e( '(Unattached)' ); ?><br />
+ <?php if ( $user_can_edit ) { ?>
+ <a class="hide-if-no-js"
+ onclick="findPosts.open( 'media[]','<?php echo $post->ID ?>' ); return false;"
+ href="#the-list">
+ <?php _e( 'Attach' ); ?></a>
+ <?php } ?></td>
+<?php
+ }
+ break;
+
+ case 'comments':
+ $attributes = 'class="comments column-comments num"' . $style;
+?>
+ <td <?php echo $attributes ?>>
+ <div class="post-com-count-wrapper">
+<?php
+ $pending_comments = get_pending_comments_num( $post->ID );
+
+ $this->comments_bubble( $post->ID, $pending_comments );
+?>
+ </div>
+ </td>
+<?php
+ break;
+
+ default:
+ if ( 'categories' == $column_name )
+ $taxonomy = 'category';
+ elseif ( 'tags' == $column_name )
+ $taxonomy = 'post_tag';
+ elseif ( 0 === strpos( $column_name, 'taxonomy-' ) )
+ $taxonomy = substr( $column_name, 9 );
+ else
+ $taxonomy = false;
+
+ if ( $taxonomy ) {
+ $taxonomy_object = get_taxonomy( $taxonomy );
+ echo '<td ' . $attributes . '>';
+ if ( $terms = get_the_terms( $post->ID, $taxonomy ) ) {
+ $out = array();
+ foreach ( $terms as $t ) {
+ $posts_in_term_qv = array();
+ $posts_in_term_qv['taxonomy'] = $taxonomy;
+ $posts_in_term_qv['term'] = $t->slug;
+
+ $out[] = sprintf( '<a href="%s">%s</a>',
+ esc_url( add_query_arg( $posts_in_term_qv, 'upload.php' ) ),
+ esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
+ );
+ }
+ /* translators: used between list items, there is a space after the comma */
+ echo join( __( ', ' ), $out );
+ } else {
+ echo '&#8212;';
+ }
+ echo '</td>';
+ break;
+ }
+?>
+ <td <?php echo $attributes ?>>
+ <?php do_action( 'manage_media_custom_column', $column_name, $post->ID ); ?>
+ </td>
+<?php
+ break;
+ }
+}
+?>
+ </tr>
+<?php endwhile;
+ }
+
+ function _get_row_actions( $post, $att_title ) {
+ $actions = array();
+
+ if ( $this->detached ) {
+ if ( current_user_can( 'edit_post', $post->ID ) )
+ $actions['edit'] = '<a href="' . get_edit_post_link( $post->ID, true ) . '">' . __( 'Edit' ) . '</a>';
+ if ( current_user_can( 'delete_post', $post->ID ) )
+ if ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
+ $actions['trash'] = "<a class='submitdelete' href='" . wp_nonce_url( "post.php?action=trash&amp;post=$post->ID", 'trash-post_' . $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
+ } else {
+ $delete_ays = !MEDIA_TRASH ? " onclick='return showNotice.warn();'" : '';
+ $actions['delete'] = "<a class='submitdelete'$delete_ays href='" . wp_nonce_url( "post.php?action=delete&amp;post=$post->ID", 'delete-post_' . $post->ID ) . "'>" . __( 'Delete Permanently' ) . "</a>";
+ }
+ $actions['view'] = '<a href="' . get_permalink( $post->ID ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $att_title ) ) . '" rel="permalink">' . __( 'View' ) . '</a>';
+ if ( current_user_can( 'edit_post', $post->ID ) )
+ $actions['attach'] = '<a href="#the-list" onclick="findPosts.open( \'media[]\',\''.$post->ID.'\' );return false;" class="hide-if-no-js">'.__( 'Attach' ).'</a>';
+ }
+ else {
+ if ( current_user_can( 'edit_post', $post->ID ) && !$this->is_trash )
+ $actions['edit'] = '<a href="' . get_edit_post_link( $post->ID, true ) . '">' . __( 'Edit' ) . '</a>';
+ if ( current_user_can( 'delete_post', $post->ID ) ) {
+ if ( $this->is_trash )
+ $actions['untrash'] = "<a class='submitdelete' href='" . wp_nonce_url( "post.php?action=untrash&amp;post=$post->ID", 'untrash-post_' . $post->ID ) . "'>" . __( 'Restore' ) . "</a>";
+ elseif ( EMPTY_TRASH_DAYS && MEDIA_TRASH )
+ $actions['trash'] = "<a class='submitdelete' href='" . wp_nonce_url( "post.php?action=trash&amp;post=$post->ID", 'trash-post_' . $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
+ if ( $this->is_trash || !EMPTY_TRASH_DAYS || !MEDIA_TRASH ) {
+ $delete_ays = ( !$this->is_trash && !MEDIA_TRASH ) ? " onclick='return showNotice.warn();'" : '';
+ $actions['delete'] = "<a class='submitdelete'$delete_ays href='" . wp_nonce_url( "post.php?action=delete&amp;post=$post->ID", 'delete-post_' . $post->ID ) . "'>" . __( 'Delete Permanently' ) . "</a>";
+ }
+ }
+ if ( !$this->is_trash ) {
+ $title =_draft_or_post_title( $post->post_parent );
+ $actions['view'] = '<a href="' . get_permalink( $post->ID ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $title ) ) . '" rel="permalink">' . __( 'View' ) . '</a>';
+ }
+ }
+
+ $actions = apply_filters( 'media_row_actions', $actions, $post, $this->detached );
+
+ return $actions;
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-ms-sites-list-table.php b/src/wp-admin/includes/class-wp-ms-sites-list-table.php
new file mode 100644
index 0000000000..b9d68a1f35
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-ms-sites-list-table.php
@@ -0,0 +1,344 @@
+<?php
+/**
+ * Sites List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_MS_Sites_List_Table extends WP_List_Table {
+
+ function __construct( $args = array() ) {
+ parent::__construct( array(
+ 'plural' => 'sites',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+ }
+
+ function ajax_user_can() {
+ return current_user_can( 'manage_sites' );
+ }
+
+ function prepare_items() {
+ global $s, $mode, $wpdb, $current_site;
+
+ $mode = ( empty( $_REQUEST['mode'] ) ) ? 'list' : $_REQUEST['mode'];
+
+ $per_page = $this->get_items_per_page( 'sites_network_per_page' );
+
+ $pagenum = $this->get_pagenum();
+
+ $s = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST[ 's' ] ) ) : '';
+ $wild = '';
+ if ( false !== strpos($s, '*') ) {
+ $wild = '%';
+ $s = trim($s, '*');
+ }
+
+ $like_s = esc_sql( like_escape( $s ) );
+
+ // If the network is large and a search is not being performed, show only the latest blogs with no paging in order
+ // to avoid expensive count queries.
+ if ( !$s && wp_is_large_network() ) {
+ if ( !isset($_REQUEST['orderby']) )
+ $_GET['orderby'] = $_REQUEST['orderby'] = '';
+ if ( !isset($_REQUEST['order']) )
+ $_GET['order'] = $_REQUEST['order'] = 'DESC';
+ }
+
+ $query = "SELECT * FROM {$wpdb->blogs} WHERE site_id = '{$wpdb->siteid}' ";
+
+ if ( empty($s) ) {
+ // Nothing to do.
+ } elseif ( preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $s ) ||
+ preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
+ preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
+ preg_match( '/^[0-9]{1,3}\.$/', $s ) ) {
+ // IPv4 address
+ $reg_blog_ids = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->registration_log} WHERE {$wpdb->registration_log}.IP LIKE ( '{$like_s}$wild' )" );
+
+ if ( !$reg_blog_ids )
+ $reg_blog_ids = array( 0 );
+
+ $query = "SELECT *
+ FROM {$wpdb->blogs}
+ WHERE site_id = '{$wpdb->siteid}'
+ AND {$wpdb->blogs}.blog_id IN (" . implode( ', ', $reg_blog_ids ) . ")";
+ } else {
+ if ( is_numeric($s) && empty( $wild ) ) {
+ $query .= " AND ( {$wpdb->blogs}.blog_id = '{$like_s}' )";
+ } elseif ( is_subdomain_install() ) {
+ $blog_s = str_replace( '.' . $current_site->domain, '', $like_s );
+ $blog_s .= $wild . '.' . $current_site->domain;
+ $query .= " AND ( {$wpdb->blogs}.domain LIKE '$blog_s' ) ";
+ } else {
+ if ( $like_s != trim('/', $current_site->path) )
+ $blog_s = $current_site->path . $like_s . $wild . '/';
+ else
+ $blog_s = $like_s;
+ $query .= " AND ( {$wpdb->blogs}.path LIKE '$blog_s' )";
+ }
+ }
+
+ $order_by = isset( $_REQUEST['orderby'] ) ? $_REQUEST['orderby'] : '';
+ if ( $order_by == 'registered' ) {
+ $query .= ' ORDER BY registered ';
+ } elseif ( $order_by == 'lastupdated' ) {
+ $query .= ' ORDER BY last_updated ';
+ } elseif ( $order_by == 'blogname' ) {
+ if ( is_subdomain_install() )
+ $query .= ' ORDER BY domain ';
+ else
+ $query .= ' ORDER BY path ';
+ } elseif ( $order_by == 'blog_id' ) {
+ $query .= ' ORDER BY blog_id ';
+ } else {
+ $order_by = null;
+ }
+
+ if ( isset( $order_by ) ) {
+ $order = ( isset( $_REQUEST['order'] ) && 'DESC' == strtoupper( $_REQUEST['order'] ) ) ? "DESC" : "ASC";
+ $query .= $order;
+ }
+
+ // Don't do an unbounded count on large networks
+ if ( ! wp_is_large_network() )
+ $total = $wpdb->get_var( str_replace( 'SELECT *', 'SELECT COUNT( blog_id )', $query ) );
+
+ $query .= " LIMIT " . intval( ( $pagenum - 1 ) * $per_page ) . ", " . intval( $per_page );
+ $this->items = $wpdb->get_results( $query, ARRAY_A );
+
+ if ( wp_is_large_network() )
+ $total = count($this->items);
+
+ $this->set_pagination_args( array(
+ 'total_items' => $total,
+ 'per_page' => $per_page,
+ ) );
+ }
+
+ function no_items() {
+ _e( 'No sites found.' );
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+ if ( current_user_can( 'delete_sites' ) )
+ $actions['delete'] = __( 'Delete' );
+ $actions['spam'] = _x( 'Mark as Spam', 'site' );
+ $actions['notspam'] = _x( 'Not Spam', 'site' );
+
+ return $actions;
+ }
+
+ function pagination( $which ) {
+ global $mode;
+
+ parent::pagination( $which );
+
+ if ( 'top' == $which )
+ $this->view_switcher( $mode );
+ }
+
+ function get_columns() {
+ $blogname_columns = ( is_subdomain_install() ) ? __( 'Domain' ) : __( 'Path' );
+ $sites_columns = array(
+ 'cb' => '<input type="checkbox" />',
+ 'blogname' => $blogname_columns,
+ 'lastupdated' => __( 'Last Updated' ),
+ 'registered' => _x( 'Registered', 'site' ),
+ 'users' => __( 'Users' )
+ );
+
+ if ( has_filter( 'wpmublogsaction' ) )
+ $sites_columns['plugins'] = __( 'Actions' );
+
+ $sites_columns = apply_filters( 'wpmu_blogs_columns', $sites_columns );
+
+ return $sites_columns;
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'blogname' => 'blogname',
+ 'lastupdated' => 'lastupdated',
+ 'registered' => 'blog_id',
+ );
+ }
+
+ function display_rows() {
+ global $current_site, $mode;
+
+ $status_list = array(
+ 'archived' => array( 'site-archived', __( 'Archived' ) ),
+ 'spam' => array( 'site-spammed', _x( 'Spam', 'site' ) ),
+ 'deleted' => array( 'site-deleted', __( 'Deleted' ) ),
+ 'mature' => array( 'site-mature', __( 'Mature' ) )
+ );
+
+ $class = '';
+ foreach ( $this->items as $blog ) {
+ $class = ( 'alternate' == $class ) ? '' : 'alternate';
+ reset( $status_list );
+
+ $blog_states = array();
+ foreach ( $status_list as $status => $col ) {
+ if ( get_blog_status( $blog['blog_id'], $status ) == 1 ) {
+ $class = $col[0];
+ $blog_states[] = $col[1];
+ }
+ }
+ $blog_state = '';
+ if ( ! empty( $blog_states ) ) {
+ $state_count = count( $blog_states );
+ $i = 0;
+ $blog_state .= ' - ';
+ foreach ( $blog_states as $state ) {
+ ++$i;
+ ( $i == $state_count ) ? $sep = '' : $sep = ', ';
+ $blog_state .= "<span class='post-state'>$state$sep</span>";
+ }
+ }
+ echo "<tr class='$class'>";
+
+ $blogname = ( is_subdomain_install() ) ? str_replace( '.'.$current_site->domain, '', $blog['domain'] ) : $blog['path'];
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ switch ( $column_name ) {
+ case 'cb': ?>
+ <th scope="row" class="check-column">
+ <label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>"><?php printf( __( 'Select %s' ), $blogname ); ?></label>
+ <input type="checkbox" id="blog_<?php echo $blog['blog_id'] ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ) ?>" />
+ </th>
+ <?php
+ break;
+
+ case 'id':?>
+ <th valign="top" scope="row">
+ <?php echo $blog['blog_id'] ?>
+ </th>
+ <?php
+ break;
+
+ case 'blogname':
+ echo "<td class='column-$column_name $column_name'$style>"; ?>
+ <a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ); ?>" class="edit"><?php echo $blogname . $blog_state; ?></a>
+ <?php
+ if ( 'list' != $mode ) {
+ switch_to_blog( $blog['blog_id'] );
+ echo '<p>' . sprintf( _x( '%1$s &#8211; <em>%2$s</em>', '%1$s: site name. %2$s: site tagline.' ), get_option( 'blogname' ), get_option( 'blogdescription ' ) ) . '</p>';
+ restore_current_blog();
+ }
+
+ // Preordered.
+ $actions = array(
+ 'edit' => '', 'backend' => '',
+ 'activate' => '', 'deactivate' => '',
+ 'archive' => '', 'unarchive' => '',
+ 'spam' => '', 'unspam' => '',
+ 'delete' => '',
+ 'visit' => '',
+ );
+
+ $actions['edit'] = '<span class="edit"><a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a></span>';
+ $actions['backend'] = "<span class='backend'><a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a></span>';
+ if ( $current_site->blog_id != $blog['blog_id'] ) {
+ if ( get_blog_status( $blog['blog_id'], 'deleted' ) == '1' )
+ $actions['activate'] = '<span class="activate"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=activateblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to activate the site %s' ), $blogname ) ) ), 'confirm' ) ) . '">' . __( 'Activate' ) . '</a></span>';
+ else
+ $actions['deactivate'] = '<span class="activate"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deactivateblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to deactivate the site %s' ), $blogname ) ) ), 'confirm') ) . '">' . __( 'Deactivate' ) . '</a></span>';
+
+ if ( get_blog_status( $blog['blog_id'], 'archived' ) == '1' )
+ $actions['unarchive'] = '<span class="archive"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unarchiveblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to unarchive the site %s.' ), $blogname ) ) ), 'confirm') ) . '">' . __( 'Unarchive' ) . '</a></span>';
+ else
+ $actions['archive'] = '<span class="archive"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=archiveblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to archive the site %s.' ), $blogname ) ) ), 'confirm') ) . '">' . _x( 'Archive', 'verb; site' ) . '</a></span>';
+
+ if ( get_blog_status( $blog['blog_id'], 'spam' ) == '1' )
+ $actions['unspam'] = '<span class="spam"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unspamblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to unspam the site %s.' ), $blogname ) ) ), 'confirm') ) . '">' . _x( 'Not Spam', 'site' ) . '</a></span>';
+ else
+ $actions['spam'] = '<span class="spam"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=spamblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to mark the site %s as spam.' ), $blogname ) ) ), 'confirm') ) . '">' . _x( 'Spam', 'site' ) . '</a></span>';
+
+ if ( current_user_can( 'delete_site', $blog['blog_id'] ) )
+ $actions['delete'] = '<span class="delete"><a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deleteblog&amp;id=' . $blog['blog_id'] . '&amp;msg=' . urlencode( sprintf( __( 'You are about to delete the site %s.' ), $blogname ) ) ), 'confirm') ) . '">' . __( 'Delete' ) . '</a></span>';
+ }
+
+ $actions['visit'] = "<span class='view'><a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='permalink'>" . __( 'Visit' ) . '</a></span>';
+
+ $actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
+ echo $this->row_actions( $actions );
+ ?>
+ </td>
+ <?php
+ break;
+
+ case 'lastupdated':
+ echo "<td valign='top' class='$column_name column-$column_name'$style>";
+ if ( 'list' == $mode )
+ $date = 'Y/m/d';
+ else
+ $date = 'Y/m/d \<\b\r \/\> g:i:s a';
+ echo ( $blog['last_updated'] == '0000-00-00 00:00:00' ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] ); ?>
+ </td>
+ <?php
+ break;
+ case 'registered':
+ echo "<td valign='top' class='$column_name column-$column_name'$style>";
+ if ( $blog['registered'] == '0000-00-00 00:00:00' )
+ echo '&#x2014;';
+ else
+ echo mysql2date( $date, $blog['registered'] );
+ ?>
+ </td>
+ <?php
+ break;
+ case 'users':
+ echo "<td valign='top' class='$column_name column-$column_name'$style>";
+ $blogusers = get_users( array( 'blog_id' => $blog['blog_id'], 'number' => 6) );
+ if ( is_array( $blogusers ) ) {
+ $blogusers_warning = '';
+ if ( count( $blogusers ) > 5 ) {
+ $blogusers = array_slice( $blogusers, 0, 5 );
+ $blogusers_warning = __( 'Only showing first 5 users.' ) . ' <a href="' . esc_url( network_admin_url( 'site-users.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'More' ) . '</a>';
+ }
+ foreach ( $blogusers as $user_object ) {
+ echo '<a href="' . esc_url( network_admin_url( 'user-edit.php?user_id=' . $user_object->ID ) ) . '">' . esc_html( $user_object->user_login ) . '</a> ';
+ if ( 'list' != $mode )
+ echo '( ' . $user_object->user_email . ' )';
+ echo '<br />';
+ }
+ if ( $blogusers_warning != '' )
+ echo '<strong>' . $blogusers_warning . '</strong><br />';
+ }
+ ?>
+ </td>
+ <?php
+ break;
+
+ case 'plugins': ?>
+ <?php if ( has_filter( 'wpmublogsaction' ) ) {
+ echo "<td valign='top' class='$column_name column-$column_name'$style>";
+ do_action( 'wpmublogsaction', $blog['blog_id'] ); ?>
+ </td>
+ <?php }
+ break;
+
+ default:
+ echo "<td class='$column_name column-$column_name'$style>";
+ do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
+ echo "</td>";
+ break;
+ }
+ }
+ ?>
+ </tr>
+ <?php
+ }
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-ms-themes-list-table.php b/src/wp-admin/includes/class-wp-ms-themes-list-table.php
new file mode 100644
index 0000000000..1d61af9f82
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-ms-themes-list-table.php
@@ -0,0 +1,356 @@
+<?php
+/**
+ * MS Themes List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_MS_Themes_List_Table extends WP_List_Table {
+
+ var $site_id;
+ var $is_site_themes;
+
+ function __construct( $args = array() ) {
+ global $status, $page;
+
+ parent::__construct( array(
+ 'plural' => 'themes',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+
+ $status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
+ if ( !in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ) ) )
+ $status = 'all';
+
+ $page = $this->get_pagenum();
+
+ $this->is_site_themes = ( 'site-themes-network' == $this->screen->id ) ? true : false;
+
+ if ( $this->is_site_themes )
+ $this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+ }
+
+ function get_table_classes() {
+ return array( 'widefat', 'plugins' ); // todo: remove and add CSS for .themes
+ }
+
+ function ajax_user_can() {
+ if ( $this->is_site_themes )
+ return current_user_can( 'manage_sites' );
+ else
+ return current_user_can( 'manage_network_themes' );
+ }
+
+ function prepare_items() {
+ global $status, $totals, $page, $orderby, $order, $s;
+
+ wp_reset_vars( array( 'orderby', 'order', 's' ) );
+
+ $themes = array(
+ 'all' => apply_filters( 'all_themes', wp_get_themes() ),
+ 'search' => array(),
+ 'enabled' => array(),
+ 'disabled' => array(),
+ 'upgrade' => array(),
+ 'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
+ );
+
+ if ( $this->is_site_themes ) {
+ $themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
+ $allowed_where = 'site';
+ } else {
+ $themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
+ $allowed_where = 'network';
+ }
+
+ $maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current = get_site_transient( 'update_themes' );
+
+ foreach ( (array) $themes['all'] as $key => $theme ) {
+ if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
+ unset( $themes['all'][ $key ] );
+ continue;
+ }
+
+ if ( $maybe_update && isset( $current->response[ $key ] ) ) {
+ $themes['all'][ $key ]->update = true;
+ $themes['upgrade'][ $key ] = $themes['all'][ $key ];
+ }
+
+ $filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
+ $themes[ $filter ][ $key ] = $themes['all'][ $key ];
+ }
+
+ if ( $s ) {
+ $status = 'search';
+ $themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( &$this, '_search_callback' ) );
+ }
+
+ $totals = array();
+ foreach ( $themes as $type => $list )
+ $totals[ $type ] = count( $list );
+
+ if ( empty( $themes[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
+ $status = 'all';
+
+ $this->items = $themes[ $status ];
+ WP_Theme::sort_by_name( $this->items );
+
+ $this->has_items = ! empty( $themes['all'] );
+ $total_this_page = $totals[ $status ];
+
+ if ( $orderby ) {
+ $orderby = ucfirst( $orderby );
+ $order = strtoupper( $order );
+
+ if ( $orderby == 'Name' ) {
+ if ( 'ASC' == $order )
+ $this->items = array_reverse( $this->items );
+ } else {
+ uasort( $this->items, array( &$this, '_order_callback' ) );
+ }
+ }
+
+ $start = ( $page - 1 ) * $themes_per_page;
+
+ if ( $total_this_page > $themes_per_page )
+ $this->items = array_slice( $this->items, $start, $themes_per_page, true );
+
+ $this->set_pagination_args( array(
+ 'total_items' => $total_this_page,
+ 'per_page' => $themes_per_page,
+ ) );
+ }
+
+ function _search_callback( $theme ) {
+ static $term;
+ if ( is_null( $term ) )
+ $term = wp_unslash( $_REQUEST['s'] );
+
+ foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) {
+ // Don't mark up; Do translate.
+ if ( false !== stripos( $theme->display( $field, false, true ), $term ) )
+ return true;
+ }
+
+ if ( false !== stripos( $theme->get_stylesheet(), $term ) )
+ return true;
+
+ if ( false !== stripos( $theme->get_template(), $term ) )
+ return true;
+
+ return false;
+ }
+
+ // Not used by any core columns.
+ function _order_callback( $theme_a, $theme_b ) {
+ global $orderby, $order;
+
+ $a = $theme_a[ $orderby ];
+ $b = $theme_b[ $orderby ];
+
+ if ( $a == $b )
+ return 0;
+
+ if ( 'DESC' == $order )
+ return ( $a < $b ) ? 1 : -1;
+ else
+ return ( $a < $b ) ? -1 : 1;
+ }
+
+ function no_items() {
+ if ( ! $this->has_items )
+ _e( 'No themes found.' );
+ else
+ _e( 'You do not appear to have any themes available at this time.' );
+ }
+
+ function get_columns() {
+ global $status;
+
+ return array(
+ 'cb' => '<input type="checkbox" />',
+ 'name' => __( 'Theme' ),
+ 'description' => __( 'Description' ),
+ );
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'name' => 'name',
+ );
+ }
+
+ function get_views() {
+ global $totals, $status;
+
+ $status_links = array();
+ foreach ( $totals as $type => $count ) {
+ if ( !$count )
+ continue;
+
+ switch ( $type ) {
+ case 'all':
+ $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' );
+ break;
+ case 'enabled':
+ $text = _n( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count );
+ break;
+ case 'disabled':
+ $text = _n( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count );
+ break;
+ case 'upgrade':
+ $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
+ break;
+ case 'broken' :
+ $text = _n( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count );
+ break;
+ }
+
+ if ( $this->is_site_themes )
+ $url = 'site-themes.php?id=' . $this->site_id;
+ else
+ $url = 'themes.php';
+
+ if ( 'search' != $type ) {
+ $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
+ esc_url( add_query_arg('theme_status', $type, $url) ),
+ ( $type == $status ) ? ' class="current"' : '',
+ sprintf( $text, number_format_i18n( $count ) )
+ );
+ }
+ }
+
+ return $status_links;
+ }
+
+ function get_bulk_actions() {
+ global $status;
+
+ $actions = array();
+ if ( 'enabled' != $status )
+ $actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
+ if ( 'disabled' != $status )
+ $actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
+ if ( ! $this->is_site_themes ) {
+ if ( current_user_can( 'update_themes' ) )
+ $actions['update-selected'] = __( 'Update' );
+ if ( current_user_can( 'delete_themes' ) )
+ $actions['delete-selected'] = __( 'Delete' );
+ }
+ return $actions;
+ }
+
+ function display_rows() {
+ foreach ( $this->items as $theme )
+ $this->single_row( $theme );
+ }
+
+ function single_row( $theme ) {
+ global $status, $page, $s, $totals;
+
+ $context = $status;
+
+ if ( $this->is_site_themes ) {
+ $url = "site-themes.php?id={$this->site_id}&amp;";
+ $allowed = $theme->is_allowed( 'site', $this->site_id );
+ } else {
+ $url = 'themes.php?';
+ $allowed = $theme->is_allowed( 'network' );
+ }
+
+ // preorder
+ $actions = array(
+ 'enable' => '',
+ 'disable' => '',
+ 'edit' => '',
+ 'delete' => ''
+ );
+
+ $stylesheet = $theme->get_stylesheet();
+ $theme_key = urlencode( $stylesheet );
+
+ if ( ! $allowed ) {
+ if ( ! $theme->errors() )
+ $actions['enable'] = '<a href="' . esc_url( wp_nonce_url($url . 'action=enable&amp;theme=' . $theme_key . '&amp;paged=' . $page . '&amp;s=' . $s, 'enable-theme_' . $stylesheet ) ) . '" title="' . esc_attr__('Enable this theme') . '" class="edit">' . ( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) ) . '</a>';
+ } else {
+ $actions['disable'] = '<a href="' . esc_url( wp_nonce_url($url . 'action=disable&amp;theme=' . $theme_key . '&amp;paged=' . $page . '&amp;s=' . $s, 'disable-theme_' . $stylesheet ) ) . '" title="' . esc_attr__('Disable this theme') . '">' . ( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) ) . '</a>';
+ }
+
+ if ( current_user_can('edit_themes') )
+ $actions['edit'] = '<a href="' . esc_url('theme-editor.php?theme=' . $theme_key ) . '" title="' . esc_attr__('Open this theme in the Theme Editor') . '" class="edit">' . __('Edit') . '</a>';
+
+ if ( ! $allowed && current_user_can( 'delete_themes' ) && ! $this->is_site_themes && $stylesheet != get_option( 'stylesheet' ) && $stylesheet != get_option( 'template' ) )
+ $actions['delete'] = '<a href="' . esc_url( wp_nonce_url( 'themes.php?action=delete-selected&amp;checked[]=' . $theme_key . '&amp;theme_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-themes' ) ) . '" title="' . esc_attr__( 'Delete this theme' ) . '" class="delete">' . __( 'Delete' ) . '</a>';
+
+ $actions = apply_filters( 'theme_action_links', array_filter( $actions ), $stylesheet, $theme, $context );
+ $actions = apply_filters( "theme_action_links_$stylesheet", $actions, $stylesheet, $theme, $context );
+
+ $class = ! $allowed ? 'inactive' : 'active';
+ $checkbox_id = "checkbox_" . md5( $theme->get('Name') );
+ $checkbox = "<input type='checkbox' name='checked[]' value='" . esc_attr( $stylesheet ) . "' id='" . $checkbox_id . "' /><label class='screen-reader-text' for='" . $checkbox_id . "' >" . __('Select') . " " . $theme->display('Name') . "</label>";
+
+ $id = sanitize_html_class( $theme->get_stylesheet() );
+
+ if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) )
+ $class .= ' update';
+
+ echo "<tr id='$id' class='$class'>";
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ switch ( $column_name ) {
+ case 'cb':
+ echo "<th scope='row' class='check-column'>$checkbox</th>";
+ break;
+ case 'name':
+ echo "<td class='theme-title'$style><strong>" . $theme->display('Name') . "</strong>";
+ echo $this->row_actions( $actions, true );
+ echo "</td>";
+ break;
+ case 'description':
+ echo "<td class='column-description desc'$style>";
+ if ( $theme->errors() ) {
+ $pre = $status == 'broken' ? '' : __( 'Broken Theme:' ) . ' ';
+ echo '<p><strong class="attention">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
+ }
+ echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div>
+ <div class='$class second theme-version-author-uri'>";
+
+ $theme_meta = array();
+
+ if ( $theme->get('Version') )
+ $theme_meta[] = sprintf( __( 'Version %s' ), $theme->display('Version') );
+
+ $theme_meta[] = sprintf( __( 'By %s' ), $theme->display('Author') );
+
+ if ( $theme->get('ThemeURI') )
+ $theme_meta[] = '<a href="' . $theme->display('ThemeURI') . '" title="' . esc_attr__( 'Visit theme homepage' ) . '">' . __( 'Visit Theme Site' ) . '</a>';
+
+ $theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
+ echo implode( ' | ', $theme_meta );
+
+ echo "</div></td>";
+ break;
+
+ default:
+ echo "<td class='$column_name column-$column_name'$style>";
+ do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
+ echo "</td>";
+ }
+ }
+
+ echo "</tr>";
+
+ if ( $this->is_site_themes )
+ remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' );
+ do_action( 'after_theme_row', $stylesheet, $theme, $status );
+ do_action( "after_theme_row_$stylesheet", $stylesheet, $theme, $status );
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-ms-users-list-table.php b/src/wp-admin/includes/class-wp-ms-users-list-table.php
new file mode 100644
index 0000000000..ab1ee3620e
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-ms-users-list-table.php
@@ -0,0 +1,272 @@
+<?php
+/**
+ * Multisite Users List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_MS_Users_List_Table extends WP_List_Table {
+
+ function ajax_user_can() {
+ return current_user_can( 'manage_network_users' );
+ }
+
+ function prepare_items() {
+ global $usersearch, $role, $wpdb, $mode;
+
+ $usersearch = isset( $_REQUEST['s'] ) ? $_REQUEST['s'] : '';
+
+ $users_per_page = $this->get_items_per_page( 'users_network_per_page' );
+
+ $role = isset( $_REQUEST['role'] ) ? $_REQUEST['role'] : '';
+
+ $paged = $this->get_pagenum();
+
+ $args = array(
+ 'number' => $users_per_page,
+ 'offset' => ( $paged-1 ) * $users_per_page,
+ 'search' => $usersearch,
+ 'blog_id' => 0,
+ 'fields' => 'all_with_meta'
+ );
+
+ if ( wp_is_large_network( 'users' ) )
+ $args['search'] = ltrim( $args['search'], '*' );
+
+ if ( $role == 'super' ) {
+ $logins = implode( "', '", get_super_admins() );
+ $args['include'] = $wpdb->get_col( "SELECT ID FROM $wpdb->users WHERE user_login IN ('$logins')" );
+ }
+
+ // If the network is large and a search is not being performed, show only the latest users with no paging in order
+ // to avoid expensive count queries.
+ if ( !$usersearch && wp_is_large_network( 'users' ) ) {
+ if ( !isset($_REQUEST['orderby']) )
+ $_GET['orderby'] = $_REQUEST['orderby'] = 'id';
+ if ( !isset($_REQUEST['order']) )
+ $_GET['order'] = $_REQUEST['order'] = 'DESC';
+ $args['count_total'] = false;
+ }
+
+ if ( isset( $_REQUEST['orderby'] ) )
+ $args['orderby'] = $_REQUEST['orderby'];
+
+ if ( isset( $_REQUEST['order'] ) )
+ $args['order'] = $_REQUEST['order'];
+
+ $mode = empty( $_REQUEST['mode'] ) ? 'list' : $_REQUEST['mode'];
+
+ // Query the user IDs for this page
+ $wp_user_search = new WP_User_Query( $args );
+
+ $this->items = $wp_user_search->get_results();
+
+ $this->set_pagination_args( array(
+ 'total_items' => $wp_user_search->get_total(),
+ 'per_page' => $users_per_page,
+ ) );
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+ if ( current_user_can( 'delete_users' ) )
+ $actions['delete'] = __( 'Delete' );
+ $actions['spam'] = _x( 'Mark as Spam', 'user' );
+ $actions['notspam'] = _x( 'Not Spam', 'user' );
+
+ return $actions;
+ }
+
+ function no_items() {
+ _e( 'No users found.' );
+ }
+
+ function get_views() {
+ global $wp_roles, $role;
+
+ $total_users = get_user_count();
+ $super_admins = get_super_admins();
+ $total_admins = count( $super_admins );
+
+ $current_role = false;
+ $class = $role != 'super' ? ' class="current"' : '';
+ $role_links = array();
+ $role_links['all'] = "<a href='" . network_admin_url('users.php') . "'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
+ $class = $role == 'super' ? ' class="current"' : '';
+ $role_links['super'] = "<a href='" . network_admin_url('users.php?role=super') . "'$class>" . sprintf( _n( 'Super Admin <span class="count">(%s)</span>', 'Super Admins <span class="count">(%s)</span>', $total_admins ), number_format_i18n( $total_admins ) ) . '</a>';
+
+ return $role_links;
+ }
+
+ function pagination( $which ) {
+ global $mode;
+
+ parent::pagination ( $which );
+
+ if ( 'top' == $which )
+ $this->view_switcher( $mode );
+ }
+
+ function get_columns() {
+ $users_columns = array(
+ 'cb' => '<input type="checkbox" />',
+ 'username' => __( 'Username' ),
+ 'name' => __( 'Name' ),
+ 'email' => __( 'E-mail' ),
+ 'registered' => _x( 'Registered', 'user' ),
+ 'blogs' => __( 'Sites' )
+ );
+ $users_columns = apply_filters( 'wpmu_users_columns', $users_columns );
+
+ return $users_columns;
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'username' => 'login',
+ 'name' => 'name',
+ 'email' => 'email',
+ 'registered' => 'id',
+ );
+ }
+
+ function display_rows() {
+ global $current_site, $mode;
+
+ $alt = '';
+ $super_admins = get_super_admins();
+ foreach ( $this->items as $user ) {
+ $alt = ( 'alternate' == $alt ) ? '' : 'alternate';
+
+ $status_list = array( 'spam' => 'site-spammed', 'deleted' => 'site-deleted' );
+
+ foreach ( $status_list as $status => $col ) {
+ if ( $user->$status )
+ $alt .= " $col";
+ }
+
+ ?>
+ <tr class="<?php echo $alt; ?>">
+ <?php
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) :
+ $class = "class='$column_name column-$column_name'";
+
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ $attributes = "$class$style";
+
+ switch ( $column_name ) {
+ case 'cb': ?>
+ <th scope="row" class="check-column">
+ <label class="screen-reader-text" for="blog_<?php echo $user->ID; ?>"><?php echo sprintf( __( 'Select %s' ), $user->user_login ); ?></label>
+ <input type="checkbox" id="blog_<?php echo $user->ID ?>" name="allusers[]" value="<?php echo esc_attr( $user->ID ) ?>" />
+ </th>
+ <?php
+ break;
+
+ case 'username':
+ $avatar = get_avatar( $user->user_email, 32 );
+ $edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
+
+ echo "<td $attributes>"; ?>
+ <?php echo $avatar; ?><strong><a href="<?php echo $edit_link; ?>" class="edit"><?php echo $user->user_login; ?></a><?php
+ if ( in_array( $user->user_login, $super_admins ) )
+ echo ' - ' . __( 'Super Admin' );
+ ?></strong>
+ <br/>
+ <?php
+ $actions = array();
+ $actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+
+ if ( current_user_can( 'delete_user', $user->ID ) && ! in_array( $user->user_login, $super_admins ) ) {
+ $actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'deleteuser' ) . '&amp;action=deleteuser&amp;id=' . $user->ID ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
+ }
+
+ $actions = apply_filters( 'ms_user_row_actions', $actions, $user );
+ echo $this->row_actions( $actions );
+ ?>
+ </td>
+ <?php
+ break;
+
+ case 'name':
+ echo "<td $attributes>$user->first_name $user->last_name</td>";
+ break;
+
+ case 'email':
+ echo "<td $attributes><a href='mailto:$user->user_email'>$user->user_email</a></td>";
+ break;
+
+ case 'registered':
+ if ( 'list' == $mode )
+ $date = 'Y/m/d';
+ else
+ $date = 'Y/m/d \<\b\r \/\> g:i:s a';
+
+ echo "<td $attributes>" . mysql2date( $date, $user->user_registered ) . "</td>";
+ break;
+
+ case 'blogs':
+ $blogs = get_blogs_of_user( $user->ID, true );
+ echo "<td $attributes>";
+ if ( is_array( $blogs ) ) {
+ foreach ( (array) $blogs as $key => $val ) {
+ if ( !can_edit_network( $val->site_id ) )
+ continue;
+
+ $path = ( $val->path == '/' ) ? '' : $val->path;
+ echo '<span class="site-' . $val->site_id . '" >';
+ echo '<a href="'. esc_url( network_admin_url( 'site-info.php?id=' . $val->userblog_id ) ) .'">' . str_replace( '.' . $current_site->domain, '', $val->domain . $path ) . '</a>';
+ echo ' <small class="row-actions">';
+ $actions = array();
+ $actions['edit'] = '<a href="'. esc_url( network_admin_url( 'site-info.php?id=' . $val->userblog_id ) ) .'">' . __( 'Edit' ) . '</a>';
+
+ $class = '';
+ if ( get_blog_status( $val->userblog_id, 'spam' ) == 1 )
+ $class .= 'site-spammed ';
+ if ( get_blog_status( $val->userblog_id, 'mature' ) == 1 )
+ $class .= 'site-mature ';
+ if ( get_blog_status( $val->userblog_id, 'deleted' ) == 1 )
+ $class .= 'site-deleted ';
+ if ( get_blog_status( $val->userblog_id, 'archived' ) == 1 )
+ $class .= 'site-archived ';
+
+ $actions['view'] = '<a class="' . $class . '" href="' . esc_url( get_home_url( $val->userblog_id ) ) . '">' . __( 'View' ) . '</a>';
+
+ $actions = apply_filters('ms_user_list_site_actions', $actions, $val->userblog_id);
+
+ $i=0;
+ $action_count = count( $actions );
+ foreach ( $actions as $action => $link ) {
+ ++$i;
+ ( $i == $action_count ) ? $sep = '' : $sep = ' | ';
+ echo "<span class='$action'>$link$sep</span>";
+ }
+ echo '</small></span><br/>';
+ }
+ }
+ ?>
+ </td>
+ <?php
+ break;
+
+ default:
+ echo "<td $attributes>";
+ echo apply_filters( 'manage_users_custom_column', '', $column_name, $user->ID );
+ echo "</td>";
+ break;
+ }
+ endforeach
+ ?>
+ </tr>
+ <?php
+ }
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-plugin-install-list-table.php b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
new file mode 100644
index 0000000000..76ef2ce2c1
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
@@ -0,0 +1,238 @@
+<?php
+/**
+ * Plugin Installer List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Plugin_Install_List_Table extends WP_List_Table {
+
+ function ajax_user_can() {
+ return current_user_can('install_plugins');
+ }
+
+ function prepare_items() {
+ include( ABSPATH . 'wp-admin/includes/plugin-install.php' );
+
+ global $tabs, $tab, $paged, $type, $term;
+
+ wp_reset_vars( array( 'tab' ) );
+
+ $paged = $this->get_pagenum();
+
+ $per_page = 30;
+
+ // These are the tabs which are shown on the page
+ $tabs = array();
+ $tabs['dashboard'] = __( 'Search' );
+ if ( 'search' == $tab )
+ $tabs['search'] = __( 'Search Results' );
+ $tabs['upload'] = __( 'Upload' );
+ $tabs['featured'] = _x( 'Featured', 'Plugin Installer' );
+ $tabs['popular'] = _x( 'Popular', 'Plugin Installer' );
+ $tabs['new'] = _x( 'Newest', 'Plugin Installer' );
+ $tabs['favorites'] = _x( 'Favorites', 'Plugin Installer' );
+
+ $nonmenu_tabs = array( 'plugin-information' ); //Valid actions to perform which do not have a Menu item.
+
+ $tabs = apply_filters( 'install_plugins_tabs', $tabs );
+ $nonmenu_tabs = apply_filters( 'install_plugins_nonmenu_tabs', $nonmenu_tabs );
+
+ // If a non-valid menu tab has been selected, And it's not a non-menu action.
+ if ( empty( $tab ) || ( !isset( $tabs[ $tab ] ) && !in_array( $tab, (array) $nonmenu_tabs ) ) )
+ $tab = key( $tabs );
+
+ $args = array( 'page' => $paged, 'per_page' => $per_page );
+
+ switch ( $tab ) {
+ case 'search':
+ $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
+ $term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : '';
+
+ switch ( $type ) {
+ case 'tag':
+ $args['tag'] = sanitize_title_with_dashes( $term );
+ break;
+ case 'term':
+ $args['search'] = $term;
+ break;
+ case 'author':
+ $args['author'] = $term;
+ break;
+ }
+
+ add_action( 'install_plugins_table_header', 'install_search_form', 10, 0 );
+ break;
+
+ case 'featured':
+ case 'popular':
+ case 'new':
+ $args['browse'] = $tab;
+ break;
+
+ case 'favorites':
+ $user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
+ update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
+ if ( $user )
+ $args['user'] = $user;
+ else
+ $args = false;
+
+ add_action( 'install_plugins_favorites', 'install_plugins_favorites_form', 9, 0 );
+ break;
+
+ default:
+ $args = false;
+ }
+
+ if ( !$args )
+ return;
+
+ $api = plugins_api( 'query_plugins', $args );
+
+ if ( is_wp_error( $api ) )
+ wp_die( $api->get_error_message() . '</p> <p class="hide-if-no-js"><a href="#" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a>' );
+
+ $this->items = $api->plugins;
+
+ $this->set_pagination_args( array(
+ 'total_items' => $api->info['results'],
+ 'per_page' => $per_page,
+ ) );
+ }
+
+ function no_items() {
+ _e( 'No plugins match your request.' );
+ }
+
+ function get_views() {
+ global $tabs, $tab;
+
+ $display_tabs = array();
+ foreach ( (array) $tabs as $action => $text ) {
+ $class = ( $action == $tab ) ? ' class="current"' : '';
+ $href = self_admin_url('plugin-install.php?tab=' . $action);
+ $display_tabs['plugin-install-'.$action] = "<a href='$href'$class>$text</a>";
+ }
+
+ return $display_tabs;
+ }
+
+ function display_tablenav( $which ) {
+ if ( 'top' == $which ) { ?>
+ <div class="tablenav top">
+ <div class="alignleft actions">
+ <?php do_action( 'install_plugins_table_header' ); ?>
+ </div>
+ <?php $this->pagination( $which ); ?>
+ <br class="clear" />
+ </div>
+ <?php } else { ?>
+ <div class="tablenav bottom">
+ <?php $this->pagination( $which ); ?>
+ <br class="clear" />
+ </div>
+ <?php
+ }
+ }
+
+ function get_table_classes() {
+ extract( $this->_args );
+
+ return array( 'widefat', $plural );
+ }
+
+ function get_columns() {
+ return array(
+ 'name' => _x( 'Name', 'plugin name' ),
+ 'version' => __( 'Version' ),
+ 'rating' => __( 'Rating' ),
+ 'description' => __( 'Description' ),
+ );
+ }
+
+ function display_rows() {
+ $plugins_allowedtags = array(
+ 'a' => array( 'href' => array(),'title' => array(), 'target' => array() ),
+ 'abbr' => array( 'title' => array() ),'acronym' => array( 'title' => array() ),
+ 'code' => array(), 'pre' => array(), 'em' => array(),'strong' => array(),
+ 'ul' => array(), 'ol' => array(), 'li' => array(), 'p' => array(), 'br' => array()
+ );
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ $style = array();
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $style[ $column_name ] = in_array( $column_name, $hidden ) ? 'style="display:none;"' : '';
+ }
+
+ foreach ( (array) $this->items as $plugin ) {
+ if ( is_object( $plugin ) )
+ $plugin = (array) $plugin;
+
+ $title = wp_kses( $plugin['name'], $plugins_allowedtags );
+ //Limit description to 400char, and remove any HTML.
+ $description = strip_tags( $plugin['description'] );
+ if ( strlen( $description ) > 400 )
+ $description = mb_substr( $description, 0, 400 ) . '&#8230;';
+ //remove any trailing entities
+ $description = preg_replace( '/&[^;\s]{0,6}$/', '', $description );
+ //strip leading/trailing & multiple consecutive lines
+ $description = trim( $description );
+ $description = preg_replace( "|(\r?\n)+|", "\n", $description );
+ //\n => <br>
+ $description = nl2br( $description );
+ $version = wp_kses( $plugin['version'], $plugins_allowedtags );
+
+ $name = strip_tags( $title . ' ' . $version );
+
+ $author = $plugin['author'];
+ if ( ! empty( $plugin['author'] ) )
+ $author = ' <cite>' . sprintf( __( 'By %s' ), $author ) . '.</cite>';
+
+ $author = wp_kses( $author, $plugins_allowedtags );
+
+ $action_links = array();
+ $action_links[] = '<a href="' . self_admin_url( 'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
+ '&amp;TB_iframe=true&amp;width=600&amp;height=550' ) . '" class="thickbox" title="' .
+ esc_attr( sprintf( __( 'More information about %s' ), $name ) ) . '">' . __( 'Details' ) . '</a>';
+
+ if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
+ $status = install_plugin_install_status( $plugin );
+
+ switch ( $status['status'] ) {
+ case 'install':
+ if ( $status['url'] )
+ $action_links[] = '<a class="install-now" href="' . $status['url'] . '" title="' . esc_attr( sprintf( __( 'Install %s' ), $name ) ) . '">' . __( 'Install Now' ) . '</a>';
+ break;
+ case 'update_available':
+ if ( $status['url'] )
+ $action_links[] = '<a href="' . $status['url'] . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $status['version'] ) ) . '">' . sprintf( __( 'Update Now' ), $status['version'] ) . '</a>';
+ break;
+ case 'latest_installed':
+ case 'newer_installed':
+ $action_links[] = '<span title="' . esc_attr__( 'This plugin is already installed and is up to date' ) . ' ">' . _x( 'Installed', 'plugin' ) . '</span>';
+ break;
+ }
+ }
+
+ $action_links = apply_filters( 'plugin_install_action_links', $action_links, $plugin );
+ ?>
+ <tr>
+ <td class="name column-name"<?php echo $style['name']; ?>><strong><?php echo $title; ?></strong>
+ <div class="action-links"><?php if ( !empty( $action_links ) ) echo implode( ' | ', $action_links ); ?></div>
+ </td>
+ <td class="vers column-version"<?php echo $style['version']; ?>><?php echo $version; ?></td>
+ <td class="vers column-rating"<?php echo $style['rating']; ?>>
+ <div class="star-holder" title="<?php printf( _n( '(based on %s rating)', '(based on %s ratings)', $plugin['num_ratings'] ), number_format_i18n( $plugin['num_ratings'] ) ) ?>">
+ <div class="star star-rating" style="width: <?php echo esc_attr( str_replace( ',', '.', $plugin['rating'] ) ); ?>px"></div>
+ </div>
+ </td>
+ <td class="desc column-description"<?php echo $style['description']; ?>><?php echo $description, $author; ?></td>
+ </tr>
+ <?php
+ }
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php
new file mode 100644
index 0000000000..ae1d1b8d8d
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-plugins-list-table.php
@@ -0,0 +1,437 @@
+<?php
+/**
+ * Plugins List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Plugins_List_Table extends WP_List_Table {
+
+ function __construct( $args = array() ) {
+ global $status, $page;
+
+ parent::__construct( array(
+ 'plural' => 'plugins',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+
+ $status = 'all';
+ if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) )
+ $status = $_REQUEST['plugin_status'];
+
+ if ( isset($_REQUEST['s']) )
+ $_SERVER['REQUEST_URI'] = add_query_arg('s', wp_unslash($_REQUEST['s']) );
+
+ $page = $this->get_pagenum();
+ }
+
+ function get_table_classes() {
+ return array( 'widefat', $this->_args['plural'] );
+ }
+
+ function ajax_user_can() {
+ return current_user_can('activate_plugins');
+ }
+
+ function prepare_items() {
+ global $status, $plugins, $totals, $page, $orderby, $order, $s;
+
+ wp_reset_vars( array( 'orderby', 'order', 's' ) );
+
+ $plugins = array(
+ 'all' => apply_filters( 'all_plugins', get_plugins() ),
+ 'search' => array(),
+ 'active' => array(),
+ 'inactive' => array(),
+ 'recently_activated' => array(),
+ 'upgrade' => array(),
+ 'mustuse' => array(),
+ 'dropins' => array()
+ );
+
+ $screen = $this->screen;
+
+ if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
+ if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) )
+ $plugins['mustuse'] = get_mu_plugins();
+ if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) )
+ $plugins['dropins'] = get_dropins();
+
+ if ( current_user_can( 'update_plugins' ) ) {
+ $current = get_site_transient( 'update_plugins' );
+ foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
+ if ( isset( $current->response[ $plugin_file ] ) ) {
+ $plugins['all'][ $plugin_file ]['update'] = true;
+ $plugins['upgrade'][ $plugin_file ] = $plugins['all'][ $plugin_file ];
+ }
+ }
+ }
+ }
+
+ set_transient( 'plugin_slugs', array_keys( $plugins['all'] ), DAY_IN_SECONDS );
+
+ if ( ! $screen->in_admin( 'network' ) ) {
+ $recently_activated = get_option( 'recently_activated', array() );
+
+ foreach ( $recently_activated as $key => $time )
+ if ( $time + WEEK_IN_SECONDS < time() )
+ unset( $recently_activated[$key] );
+ update_option( 'recently_activated', $recently_activated );
+ }
+
+ foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
+ // Filter into individual sections
+ if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) ) {
+ unset( $plugins['all'][ $plugin_file ] );
+ } elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
+ unset( $plugins['all'][ $plugin_file ] );
+ } elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
+ || ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
+ $plugins['active'][ $plugin_file ] = $plugin_data;
+ } else {
+ if ( ! $screen->in_admin( 'network' ) && isset( $recently_activated[ $plugin_file ] ) ) // Was the plugin recently activated?
+ $plugins['recently_activated'][ $plugin_file ] = $plugin_data;
+ $plugins['inactive'][ $plugin_file ] = $plugin_data;
+ }
+ }
+
+ if ( $s ) {
+ $status = 'search';
+ $plugins['search'] = array_filter( $plugins['all'], array( &$this, '_search_callback' ) );
+ }
+
+ $totals = array();
+ foreach ( $plugins as $type => $list )
+ $totals[ $type ] = count( $list );
+
+ if ( empty( $plugins[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
+ $status = 'all';
+
+ $this->items = array();
+ foreach ( $plugins[ $status ] as $plugin_file => $plugin_data ) {
+ // Translate, Don't Apply Markup, Sanitize HTML
+ $this->items[$plugin_file] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, false, true );
+ }
+
+ $total_this_page = $totals[ $status ];
+
+ if ( $orderby ) {
+ $orderby = ucfirst( $orderby );
+ $order = strtoupper( $order );
+
+ uasort( $this->items, array( &$this, '_order_callback' ) );
+ }
+
+ $plugins_per_page = $this->get_items_per_page( str_replace( '-', '_', $screen->id . '_per_page' ), 999 );
+
+ $start = ( $page - 1 ) * $plugins_per_page;
+
+ if ( $total_this_page > $plugins_per_page )
+ $this->items = array_slice( $this->items, $start, $plugins_per_page );
+
+ $this->set_pagination_args( array(
+ 'total_items' => $total_this_page,
+ 'per_page' => $plugins_per_page,
+ ) );
+ }
+
+ function _search_callback( $plugin ) {
+ static $term;
+ if ( is_null( $term ) )
+ $term = wp_unslash( $_REQUEST['s'] );
+
+ foreach ( $plugin as $value )
+ if ( stripos( $value, $term ) !== false )
+ return true;
+
+ return false;
+ }
+
+ function _order_callback( $plugin_a, $plugin_b ) {
+ global $orderby, $order;
+
+ $a = $plugin_a[$orderby];
+ $b = $plugin_b[$orderby];
+
+ if ( $a == $b )
+ return 0;
+
+ if ( 'DESC' == $order )
+ return ( $a < $b ) ? 1 : -1;
+ else
+ return ( $a < $b ) ? -1 : 1;
+ }
+
+ function no_items() {
+ global $plugins;
+
+ if ( !empty( $plugins['all'] ) )
+ _e( 'No plugins found.' );
+ else
+ _e( 'You do not appear to have any plugins available at this time.' );
+ }
+
+ function get_columns() {
+ global $status;
+
+ return array(
+ 'cb' => !in_array( $status, array( 'mustuse', 'dropins' ) ) ? '<input type="checkbox" />' : '',
+ 'name' => __( 'Plugin' ),
+ 'description' => __( 'Description' ),
+ );
+ }
+
+ function get_sortable_columns() {
+ return array();
+ }
+
+ function get_views() {
+ global $totals, $status;
+
+ $status_links = array();
+ foreach ( $totals as $type => $count ) {
+ if ( !$count )
+ continue;
+
+ switch ( $type ) {
+ case 'all':
+ $text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'plugins' );
+ break;
+ case 'active':
+ $text = _n( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', $count );
+ break;
+ case 'recently_activated':
+ $text = _n( 'Recently Active <span class="count">(%s)</span>', 'Recently Active <span class="count">(%s)</span>', $count );
+ break;
+ case 'inactive':
+ $text = _n( 'Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', $count );
+ break;
+ case 'mustuse':
+ $text = _n( 'Must-Use <span class="count">(%s)</span>', 'Must-Use <span class="count">(%s)</span>', $count );
+ break;
+ case 'dropins':
+ $text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
+ break;
+ case 'upgrade':
+ $text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
+ break;
+ }
+
+ if ( 'search' != $type ) {
+ $status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
+ add_query_arg('plugin_status', $type, 'plugins.php'),
+ ( $type == $status ) ? ' class="current"' : '',
+ sprintf( $text, number_format_i18n( $count ) )
+ );
+ }
+ }
+
+ return $status_links;
+ }
+
+ function get_bulk_actions() {
+ global $status;
+
+ $actions = array();
+
+ if ( 'active' != $status )
+ $actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
+
+ if ( 'inactive' != $status && 'recent' != $status )
+ $actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
+
+ if ( !is_multisite() || $this->screen->in_admin( 'network' ) ) {
+ if ( current_user_can( 'update_plugins' ) )
+ $actions['update-selected'] = __( 'Update' );
+ if ( current_user_can( 'delete_plugins' ) && ( 'active' != $status ) )
+ $actions['delete-selected'] = __( 'Delete' );
+ }
+
+ return $actions;
+ }
+
+ function bulk_actions() {
+ global $status;
+
+ if ( in_array( $status, array( 'mustuse', 'dropins' ) ) )
+ return;
+
+ parent::bulk_actions();
+ }
+
+ function extra_tablenav( $which ) {
+ global $status;
+
+ if ( ! in_array($status, array('recently_activated', 'mustuse', 'dropins') ) )
+ return;
+
+ echo '<div class="alignleft actions">';
+
+ if ( ! $this->screen->in_admin( 'network' ) && 'recently_activated' == $status )
+ submit_button( __( 'Clear List' ), 'button', 'clear-recent-list', false );
+ elseif ( 'top' == $which && 'mustuse' == $status )
+ echo '<p>' . sprintf( __( 'Files in the <code>%s</code> directory are executed automatically.' ), str_replace( ABSPATH, '/', WPMU_PLUGIN_DIR ) ) . '</p>';
+ elseif ( 'top' == $which && 'dropins' == $status )
+ echo '<p>' . sprintf( __( 'Drop-ins are advanced plugins in the <code>%s</code> directory that replace WordPress functionality when present.' ), str_replace( ABSPATH, '', WP_CONTENT_DIR ) ) . '</p>';
+
+ echo '</div>';
+ }
+
+ function current_action() {
+ if ( isset($_POST['clear-recent-list']) )
+ return 'clear-recent-list';
+
+ return parent::current_action();
+ }
+
+ function display_rows() {
+ global $status;
+
+ if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ) ) )
+ return;
+
+ foreach ( $this->items as $plugin_file => $plugin_data )
+ $this->single_row( array( $plugin_file, $plugin_data ) );
+ }
+
+ function single_row( $item ) {
+ global $status, $page, $s, $totals;
+
+ list( $plugin_file, $plugin_data ) = $item;
+ $context = $status;
+ $screen = $this->screen;
+
+ // preorder
+ $actions = array(
+ 'deactivate' => '',
+ 'activate' => '',
+ 'edit' => '',
+ 'delete' => '',
+ );
+
+ if ( 'mustuse' == $context ) {
+ $is_active = true;
+ } elseif ( 'dropins' == $context ) {
+ $dropins = _get_dropins();
+ $plugin_name = $plugin_file;
+ if ( $plugin_file != $plugin_data['Name'] )
+ $plugin_name .= '<br/>' . $plugin_data['Name'];
+ if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant
+ $is_active = true;
+ $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
+ } elseif ( constant( $dropins[ $plugin_file ][1] ) ) { // Constant is true
+ $is_active = true;
+ $description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
+ } else {
+ $is_active = false;
+ $description = '<p><strong>' . $dropins[ $plugin_file ][0] . ' <span class="attention">' . __('Inactive:') . '</span></strong> ' . sprintf( __( 'Requires <code>%s</code> in <code>wp-config.php</code>.' ), "define('" . $dropins[ $plugin_file ][1] . "', true);" ) . '</p>';
+ }
+ if ( $plugin_data['Description'] )
+ $description .= '<p>' . $plugin_data['Description'] . '</p>';
+ } else {
+ if ( $screen->in_admin( 'network' ) )
+ $is_active = is_plugin_active_for_network( $plugin_file );
+ else
+ $is_active = is_plugin_active( $plugin_file );
+
+ if ( $screen->in_admin( 'network' ) ) {
+ if ( $is_active ) {
+ if ( current_user_can( 'manage_network_plugins' ) )
+ $actions['deactivate'] = '<a href="' . wp_nonce_url('plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Deactivate this plugin') . '">' . __('Network Deactivate') . '</a>';
+ } else {
+ if ( current_user_can( 'manage_network_plugins' ) )
+ $actions['activate'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin for all sites in this network') . '" class="edit">' . __('Network Activate') . '</a>';
+ if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) )
+ $actions['delete'] = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins') . '" title="' . esc_attr__('Delete this plugin') . '" class="delete">' . __('Delete') . '</a>';
+ }
+ } else {
+ if ( $is_active ) {
+ $actions['deactivate'] = '<a href="' . wp_nonce_url('plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Deactivate this plugin') . '">' . __('Deactivate') . '</a>';
+ } else {
+ $actions['activate'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" class="edit">' . __('Activate') . '</a>';
+
+ if ( ! is_multisite() && current_user_can('delete_plugins') )
+ $actions['delete'] = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins') . '" title="' . esc_attr__('Delete this plugin') . '" class="delete">' . __('Delete') . '</a>';
+ } // end if $is_active
+ } // end if $screen->in_admin( 'network' )
+
+ if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can('edit_plugins') && is_writable(WP_PLUGIN_DIR . '/' . $plugin_file) )
+ $actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" title="' . esc_attr__('Open this file in the Plugin Editor') . '" class="edit">' . __('Edit') . '</a>';
+ } // end if $context
+
+ $prefix = $screen->in_admin( 'network' ) ? 'network_admin_' : '';
+ $actions = apply_filters( $prefix . 'plugin_action_links', array_filter( $actions ), $plugin_file, $plugin_data, $context );
+ $actions = apply_filters( $prefix . "plugin_action_links_$plugin_file", $actions, $plugin_file, $plugin_data, $context );
+
+ $class = $is_active ? 'active' : 'inactive';
+ $checkbox_id = "checkbox_" . md5($plugin_data['Name']);
+ if ( in_array( $status, array( 'mustuse', 'dropins' ) ) ) {
+ $checkbox = '';
+ } else {
+ $checkbox = "<label class='screen-reader-text' for='" . $checkbox_id . "' >" . sprintf( __( 'Select %s' ), $plugin_data['Name'] ) . "</label>"
+ . "<input type='checkbox' name='checked[]' value='" . esc_attr( $plugin_file ) . "' id='" . $checkbox_id . "' />";
+ }
+ if ( 'dropins' != $context ) {
+ $description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
+ $plugin_name = $plugin_data['Name'];
+ }
+
+ $id = sanitize_title( $plugin_name );
+ if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) )
+ $class .= ' update';
+
+ echo "<tr id='$id' class='$class'>";
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ switch ( $column_name ) {
+ case 'cb':
+ echo "<th scope='row' class='check-column'>$checkbox</th>";
+ break;
+ case 'name':
+ echo "<td class='plugin-title'$style><strong>$plugin_name</strong>";
+ echo $this->row_actions( $actions, true );
+ echo "</td>";
+ break;
+ case 'description':
+ echo "<td class='column-description desc'$style>
+ <div class='plugin-description'>$description</div>
+ <div class='$class second plugin-version-author-uri'>";
+
+ $plugin_meta = array();
+ if ( !empty( $plugin_data['Version'] ) )
+ $plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
+ if ( !empty( $plugin_data['Author'] ) ) {
+ $author = $plugin_data['Author'];
+ if ( !empty( $plugin_data['AuthorURI'] ) )
+ $author = '<a href="' . $plugin_data['AuthorURI'] . '" title="' . esc_attr__( 'Visit author homepage' ) . '">' . $plugin_data['Author'] . '</a>';
+ $plugin_meta[] = sprintf( __( 'By %s' ), $author );
+ }
+ if ( ! empty( $plugin_data['PluginURI'] ) )
+ $plugin_meta[] = '<a href="' . $plugin_data['PluginURI'] . '" title="' . esc_attr__( 'Visit plugin site' ) . '">' . __( 'Visit plugin site' ) . '</a>';
+
+ $plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
+ echo implode( ' | ', $plugin_meta );
+
+ echo "</div></td>";
+ break;
+ default:
+ echo "<td class='$column_name column-$column_name'$style>";
+ do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
+ echo "</td>";
+ }
+ }
+
+ echo "</tr>";
+
+ do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
+ do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $status );
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-posts-list-table.php b/src/wp-admin/includes/class-wp-posts-list-table.php
new file mode 100644
index 0000000000..b3ce8029bc
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-posts-list-table.php
@@ -0,0 +1,1071 @@
+<?php
+/**
+ * Posts List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Posts_List_Table extends WP_List_Table {
+
+ /**
+ * Whether the items should be displayed hierarchically or linearly
+ *
+ * @since 3.1.0
+ * @var bool
+ * @access protected
+ */
+ var $hierarchical_display;
+
+ /**
+ * Holds the number of pending comments for each post
+ *
+ * @since 3.1.0
+ * @var int
+ * @access protected
+ */
+ var $comment_pending_count;
+
+ /**
+ * Holds the number of posts for this user
+ *
+ * @since 3.1.0
+ * @var int
+ * @access private
+ */
+ var $user_posts_count;
+
+ /**
+ * Holds the number of posts which are sticky.
+ *
+ * @since 3.1.0
+ * @var int
+ * @access private
+ */
+ var $sticky_posts_count = 0;
+
+ function __construct( $args = array() ) {
+ global $post_type_object, $wpdb;
+
+ parent::__construct( array(
+ 'plural' => 'posts',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+
+ $post_type = $this->screen->post_type;
+ $post_type_object = get_post_type_object( $post_type );
+
+ if ( !current_user_can( $post_type_object->cap->edit_others_posts ) ) {
+ $this->user_posts_count = $wpdb->get_var( $wpdb->prepare( "
+ SELECT COUNT( 1 ) FROM $wpdb->posts
+ WHERE post_type = %s AND post_status NOT IN ( 'trash', 'auto-draft' )
+ AND post_author = %d
+ ", $post_type, get_current_user_id() ) );
+
+ if ( $this->user_posts_count && empty( $_REQUEST['post_status'] ) && empty( $_REQUEST['all_posts'] ) && empty( $_REQUEST['author'] ) && empty( $_REQUEST['show_sticky'] ) )
+ $_GET['author'] = get_current_user_id();
+ }
+
+ if ( 'post' == $post_type && $sticky_posts = get_option( 'sticky_posts' ) ) {
+ $sticky_posts = implode( ', ', array_map( 'absint', (array) $sticky_posts ) );
+ $this->sticky_posts_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( 1 ) FROM $wpdb->posts WHERE post_type = %s AND post_status != 'trash' AND ID IN ($sticky_posts)", $post_type ) );
+ }
+ }
+
+ function ajax_user_can() {
+ return current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_posts );
+ }
+
+ function prepare_items() {
+ global $avail_post_stati, $wp_query, $per_page, $mode;
+
+ $avail_post_stati = wp_edit_posts_query();
+
+ $this->hierarchical_display = ( is_post_type_hierarchical( $this->screen->post_type ) && 'menu_order title' == $wp_query->query['orderby'] );
+
+ $total_items = $this->hierarchical_display ? $wp_query->post_count : $wp_query->found_posts;
+
+ $post_type = $this->screen->post_type;
+ $per_page = $this->get_items_per_page( 'edit_' . $post_type . '_per_page' );
+ $per_page = apply_filters( 'edit_posts_per_page', $per_page, $post_type );
+
+ if ( $this->hierarchical_display )
+ $total_pages = ceil( $total_items / $per_page );
+ else
+ $total_pages = $wp_query->max_num_pages;
+
+ $mode = empty( $_REQUEST['mode'] ) ? 'list' : $_REQUEST['mode'];
+
+ $this->is_trash = isset( $_REQUEST['post_status'] ) && $_REQUEST['post_status'] == 'trash';
+
+ $this->set_pagination_args( array(
+ 'total_items' => $total_items,
+ 'total_pages' => $total_pages,
+ 'per_page' => $per_page
+ ) );
+ }
+
+ function has_items() {
+ return have_posts();
+ }
+
+ function no_items() {
+ if ( isset( $_REQUEST['post_status'] ) && 'trash' == $_REQUEST['post_status'] )
+ echo get_post_type_object( $this->screen->post_type )->labels->not_found_in_trash;
+ else
+ echo get_post_type_object( $this->screen->post_type )->labels->not_found;
+ }
+
+ function get_views() {
+ global $locked_post_status, $avail_post_stati;
+
+ $post_type = $this->screen->post_type;
+
+ if ( !empty($locked_post_status) )
+ return array();
+
+ $status_links = array();
+ $num_posts = wp_count_posts( $post_type, 'readable' );
+ $class = '';
+ $allposts = '';
+
+ $current_user_id = get_current_user_id();
+
+ if ( $this->user_posts_count ) {
+ if ( isset( $_GET['author'] ) && ( $_GET['author'] == $current_user_id ) )
+ $class = ' class="current"';
+ $status_links['mine'] = "<a href='edit.php?post_type=$post_type&author=$current_user_id'$class>" . sprintf( _nx( 'Mine <span class="count">(%s)</span>', 'Mine <span class="count">(%s)</span>', $this->user_posts_count, 'posts' ), number_format_i18n( $this->user_posts_count ) ) . '</a>';
+ $allposts = '&all_posts=1';
+ }
+
+ $total_posts = array_sum( (array) $num_posts );
+
+ // Subtract post types that are not included in the admin all list.
+ foreach ( get_post_stati( array('show_in_admin_all_list' => false) ) as $state )
+ $total_posts -= $num_posts->$state;
+
+ $class = empty( $class ) && empty( $_REQUEST['post_status'] ) && empty( $_REQUEST['show_sticky'] ) ? ' class="current"' : '';
+ $status_links['all'] = "<a href='edit.php?post_type=$post_type{$allposts}'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_posts, 'posts' ), number_format_i18n( $total_posts ) ) . '</a>';
+
+ foreach ( get_post_stati(array('show_in_admin_status_list' => true), 'objects') as $status ) {
+ $class = '';
+
+ $status_name = $status->name;
+
+ if ( !in_array( $status_name, $avail_post_stati ) )
+ continue;
+
+ if ( empty( $num_posts->$status_name ) )
+ continue;
+
+ if ( isset($_REQUEST['post_status']) && $status_name == $_REQUEST['post_status'] )
+ $class = ' class="current"';
+
+ $status_links[$status_name] = "<a href='edit.php?post_status=$status_name&amp;post_type=$post_type'$class>" . sprintf( translate_nooped_plural( $status->label_count, $num_posts->$status_name ), number_format_i18n( $num_posts->$status_name ) ) . '</a>';
+ }
+
+ if ( ! empty( $this->sticky_posts_count ) ) {
+ $class = ! empty( $_REQUEST['show_sticky'] ) ? ' class="current"' : '';
+
+ $sticky_link = array( 'sticky' => "<a href='edit.php?post_type=$post_type&amp;show_sticky=1'$class>" . sprintf( _nx( 'Sticky <span class="count">(%s)</span>', 'Sticky <span class="count">(%s)</span>', $this->sticky_posts_count, 'posts' ), number_format_i18n( $this->sticky_posts_count ) ) . '</a>' );
+
+ // Sticky comes after Publish, or if not listed, after All.
+ $split = 1 + array_search( ( isset( $status_links['publish'] ) ? 'publish' : 'all' ), array_keys( $status_links ) );
+ $status_links = array_merge( array_slice( $status_links, 0, $split ), $sticky_link, array_slice( $status_links, $split ) );
+ }
+
+ return $status_links;
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+
+ if ( $this->is_trash )
+ $actions['untrash'] = __( 'Restore' );
+ else
+ $actions['edit'] = __( 'Edit' );
+
+ if ( $this->is_trash || !EMPTY_TRASH_DAYS )
+ $actions['delete'] = __( 'Delete Permanently' );
+ else
+ $actions['trash'] = __( 'Move to Trash' );
+
+ return $actions;
+ }
+
+ function extra_tablenav( $which ) {
+ global $cat;
+?>
+ <div class="alignleft actions">
+<?php
+ if ( 'top' == $which && !is_singular() ) {
+
+ $this->months_dropdown( $this->screen->post_type );
+
+ if ( is_object_in_taxonomy( $this->screen->post_type, 'category' ) ) {
+ $dropdown_options = array(
+ 'show_option_all' => __( 'View all categories' ),
+ 'hide_empty' => 0,
+ 'hierarchical' => 1,
+ 'show_count' => 0,
+ 'orderby' => 'name',
+ 'selected' => $cat
+ );
+ wp_dropdown_categories( $dropdown_options );
+ }
+ do_action( 'restrict_manage_posts' );
+ submit_button( __( 'Filter' ), 'button', false, false, array( 'id' => 'post-query-submit' ) );
+ }
+
+ if ( $this->is_trash && current_user_can( get_post_type_object( $this->screen->post_type )->cap->edit_others_posts ) ) {
+ submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
+ }
+?>
+ </div>
+<?php
+ }
+
+ function current_action() {
+ if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
+ return 'delete_all';
+
+ return parent::current_action();
+ }
+
+ function pagination( $which ) {
+ global $mode;
+
+ parent::pagination( $which );
+
+ if ( 'top' == $which && ! is_post_type_hierarchical( $this->screen->post_type ) )
+ $this->view_switcher( $mode );
+ }
+
+ function get_table_classes() {
+ return array( 'widefat', 'fixed', is_post_type_hierarchical( $this->screen->post_type ) ? 'pages' : 'posts' );
+ }
+
+ function get_columns() {
+ $post_type = $this->screen->post_type;
+
+ $posts_columns = array();
+
+ $posts_columns['cb'] = '<input type="checkbox" />';
+
+ /* translators: manage posts column name */
+ $posts_columns['title'] = _x( 'Title', 'column name' );
+
+ if ( post_type_supports( $post_type, 'author' ) )
+ $posts_columns['author'] = __( 'Author' );
+
+ $taxonomies = array();
+
+ $taxonomies = get_object_taxonomies( $post_type, 'objects' );
+ $taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
+
+ $taxonomies = apply_filters( "manage_taxonomies_for_{$post_type}_columns", $taxonomies, $post_type );
+ $taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( 'category' == $taxonomy )
+ $column_key = 'categories';
+ elseif ( 'post_tag' == $taxonomy )
+ $column_key = 'tags';
+ else
+ $column_key = 'taxonomy-' . $taxonomy;
+
+ $posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
+ }
+
+ $post_status = !empty( $_REQUEST['post_status'] ) ? $_REQUEST['post_status'] : 'all';
+ if ( post_type_supports( $post_type, 'comments' ) && !in_array( $post_status, array( 'pending', 'draft', 'future' ) ) )
+ $posts_columns['comments'] = '<span class="vers"><div title="' . esc_attr__( 'Comments' ) . '" class="comment-grey-bubble"></div></span>';
+
+ $posts_columns['date'] = __( 'Date' );
+
+ if ( 'page' == $post_type )
+ $posts_columns = apply_filters( 'manage_pages_columns', $posts_columns );
+ else
+ $posts_columns = apply_filters( 'manage_posts_columns', $posts_columns, $post_type );
+ $posts_columns = apply_filters( "manage_{$post_type}_posts_columns", $posts_columns );
+
+ return $posts_columns;
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'title' => 'title',
+ 'parent' => 'parent',
+ 'comments' => 'comment_count',
+ 'date' => array( 'date', true )
+ );
+ }
+
+ function display_rows( $posts = array(), $level = 0 ) {
+ global $wp_query, $per_page;
+
+ if ( empty( $posts ) )
+ $posts = $wp_query->posts;
+
+ add_filter( 'the_title', 'esc_html' );
+
+ if ( $this->hierarchical_display ) {
+ $this->_display_rows_hierarchical( $posts, $this->get_pagenum(), $per_page );
+ } else {
+ $this->_display_rows( $posts, $level );
+ }
+ }
+
+ function _display_rows( $posts, $level = 0 ) {
+ global $mode;
+
+ // Create array of post IDs.
+ $post_ids = array();
+
+ foreach ( $posts as $a_post )
+ $post_ids[] = $a_post->ID;
+
+ $this->comment_pending_count = get_pending_comments_num( $post_ids );
+
+ foreach ( $posts as $post )
+ $this->single_row( $post, $level );
+ }
+
+ function _display_rows_hierarchical( $pages, $pagenum = 1, $per_page = 20 ) {
+ global $wpdb;
+
+ $level = 0;
+
+ if ( ! $pages ) {
+ $pages = get_pages( array( 'sort_column' => 'menu_order' ) );
+
+ if ( ! $pages )
+ return false;
+ }
+
+ /*
+ * arrange pages into two parts: top level pages and children_pages
+ * children_pages is two dimensional array, eg.
+ * children_pages[10][] contains all sub-pages whose parent is 10.
+ * It only takes O( N ) to arrange this and it takes O( 1 ) for subsequent lookup operations
+ * If searching, ignore hierarchy and treat everything as top level
+ */
+ if ( empty( $_REQUEST['s'] ) ) {
+
+ $top_level_pages = array();
+ $children_pages = array();
+
+ foreach ( $pages as $page ) {
+
+ // catch and repair bad pages
+ if ( $page->post_parent == $page->ID ) {
+ $page->post_parent = 0;
+ $wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'ID' => $page->ID ) );
+ clean_post_cache( $page );
+ }
+
+ if ( 0 == $page->post_parent )
+ $top_level_pages[] = $page;
+ else
+ $children_pages[ $page->post_parent ][] = $page;
+ }
+
+ $pages = &$top_level_pages;
+ }
+
+ $count = 0;
+ $start = ( $pagenum - 1 ) * $per_page;
+ $end = $start + $per_page;
+
+ foreach ( $pages as $page ) {
+ if ( $count >= $end )
+ break;
+
+ if ( $count >= $start ) {
+ echo "\t";
+ $this->single_row( $page, $level );
+ }
+
+ $count++;
+
+ if ( isset( $children_pages ) )
+ $this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page );
+ }
+
+ // if it is the last pagenum and there are orphaned pages, display them with paging as well
+ if ( isset( $children_pages ) && $count < $end ){
+ foreach ( $children_pages as $orphans ){
+ foreach ( $orphans as $op ) {
+ if ( $count >= $end )
+ break;
+
+ if ( $count >= $start ) {
+ echo "\t";
+ $this->single_row( $op, 0 );
+ }
+
+ $count++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Given a top level page ID, display the nested hierarchy of sub-pages
+ * together with paging support
+ *
+ * @since 3.1.0 (Standalone function exists since 2.6.0)
+ *
+ * @param array $children_pages
+ * @param int $count
+ * @param int $parent
+ * @param int $level
+ * @param int $pagenum
+ * @param int $per_page
+ */
+ function _page_rows( &$children_pages, &$count, $parent, $level, $pagenum, $per_page ) {
+
+ if ( ! isset( $children_pages[$parent] ) )
+ return;
+
+ $start = ( $pagenum - 1 ) * $per_page;
+ $end = $start + $per_page;
+
+ foreach ( $children_pages[$parent] as $page ) {
+
+ if ( $count >= $end )
+ break;
+
+ // If the page starts in a subtree, print the parents.
+ if ( $count == $start && $page->post_parent > 0 ) {
+ $my_parents = array();
+ $my_parent = $page->post_parent;
+ while ( $my_parent ) {
+ $my_parent = get_post( $my_parent );
+ $my_parents[] = $my_parent;
+ if ( !$my_parent->post_parent )
+ break;
+ $my_parent = $my_parent->post_parent;
+ }
+ $num_parents = count( $my_parents );
+ while ( $my_parent = array_pop( $my_parents ) ) {
+ echo "\t";
+ $this->single_row( $my_parent, $level - $num_parents );
+ $num_parents--;
+ }
+ }
+
+ if ( $count >= $start ) {
+ echo "\t";
+ $this->single_row( $page, $level );
+ }
+
+ $count++;
+
+ $this->_page_rows( $children_pages, $count, $page->ID, $level + 1, $pagenum, $per_page );
+ }
+
+ unset( $children_pages[$parent] ); //required in order to keep track of orphans
+ }
+
+ function single_row( $post, $level = 0 ) {
+ global $mode;
+ static $alternate;
+
+ $global_post = get_post();
+ $GLOBALS['post'] = $post;
+ setup_postdata( $post );
+
+ $edit_link = get_edit_post_link( $post->ID );
+ $title = _draft_or_post_title();
+ $post_type_object = get_post_type_object( $post->post_type );
+ $can_edit_post = current_user_can( 'edit_post', $post->ID );
+
+ $alternate = 'alternate' == $alternate ? '' : 'alternate';
+ $classes = $alternate . ' iedit author-' . ( get_current_user_id() == $post->post_author ? 'self' : 'other' );
+
+ $lock_holder = wp_check_post_lock( $post->ID );
+ if ( $lock_holder ) {
+ $classes .= ' wp-locked';
+ $lock_holder = get_userdata( $lock_holder );
+ }
+ ?>
+ <tr id="post-<?php echo $post->ID; ?>" class="<?php echo implode( ' ', get_post_class( $classes, $post->ID ) ); ?>" valign="top">
+ <?php
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $class = "class=\"$column_name column-$column_name\"";
+
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ $attributes = "$class$style";
+
+ switch ( $column_name ) {
+
+ case 'cb':
+ ?>
+ <th scope="row" class="check-column">
+ <?php
+ if ( $can_edit_post ) {
+
+ ?>
+ <label class="screen-reader-text" for="cb-select-<?php the_ID(); ?>"><?php printf( __( 'Select %s' ), $title ); ?></label>
+ <input id="cb-select-<?php the_ID(); ?>" type="checkbox" name="post[]" value="<?php the_ID(); ?>" />
+ <div class="locked-indicator"></div>
+ <?php
+ }
+ ?>
+ </th>
+ <?php
+ break;
+
+ case 'title':
+ $attributes = 'class="post-title page-title column-title"' . $style;
+ if ( $this->hierarchical_display ) {
+ if ( 0 == $level && (int) $post->post_parent > 0 ) {
+ //sent level 0 by accident, by default, or because we don't know the actual level
+ $find_main_page = (int) $post->post_parent;
+ while ( $find_main_page > 0 ) {
+ $parent = get_post( $find_main_page );
+
+ if ( is_null( $parent ) )
+ break;
+
+ $level++;
+ $find_main_page = (int) $parent->post_parent;
+
+ if ( !isset( $parent_name ) )
+ $parent_name = apply_filters( 'the_title', $parent->post_title, $parent->ID );
+ }
+ }
+ }
+
+ $pad = str_repeat( '&#8212; ', $level );
+ echo "<td $attributes><strong>";
+
+ if ( $format = get_post_format( $post->ID ) ) {
+ $label = get_post_format_string( $format );
+
+ echo '<a href="' . esc_url( add_query_arg( array( 'post_format' => $format, 'post_type' => $post->post_type ), 'edit.php' ) ) . '" class="post-state-format post-format-icon post-format-' . $format . '" title="' . $label . '">' . $label . ":</a> ";
+ }
+
+ if ( $can_edit_post && $post->post_status != 'trash' ) {
+ echo '<a class="row-title" href="' . $edit_link . '" title="' . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $title ) ) . '">' . $pad . $title . '</a>';
+ } else {
+ echo $pad . $title;
+ }
+ _post_states( $post );
+
+ if ( isset( $parent_name ) )
+ echo ' | ' . $post_type_object->labels->parent_item_colon . ' ' . esc_html( $parent_name );
+
+ echo "</strong>\n";
+
+ if ( $can_edit_post && $post->post_status != 'trash' ) {
+ if ( $lock_holder ) {
+ $locked_avatar = get_avatar( $lock_holder->ID, 18 );
+ $locked_text = esc_html( sprintf( __( '%s is currently editing' ), $lock_holder->display_name ) );
+ } else {
+ $locked_avatar = $locked_text = '';
+ }
+
+ echo '<div class="locked-info"><span class="locked-avatar">' . $locked_avatar . '</span> <span class="locked-text">' . $locked_text . "</span></div>\n";
+ }
+
+ if ( ! $this->hierarchical_display && 'excerpt' == $mode && current_user_can( 'read_post', $post->ID ) )
+ the_excerpt();
+
+ $actions = array();
+ if ( $can_edit_post && 'trash' != $post->post_status ) {
+ $actions['edit'] = '<a href="' . get_edit_post_link( $post->ID, true ) . '" title="' . esc_attr( __( 'Edit this item' ) ) . '">' . __( 'Edit' ) . '</a>';
+ $actions['inline hide-if-no-js'] = '<a href="#" class="editinline" title="' . esc_attr( __( 'Edit this item inline' ) ) . '">' . __( 'Quick&nbsp;Edit' ) . '</a>';
+ }
+ if ( current_user_can( 'delete_post', $post->ID ) ) {
+ if ( 'trash' == $post->post_status )
+ $actions['untrash'] = "<a title='" . esc_attr( __( 'Restore this item from the Trash' ) ) . "' href='" . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . "'>" . __( 'Restore' ) . "</a>";
+ elseif ( EMPTY_TRASH_DAYS )
+ $actions['trash'] = "<a class='submitdelete' title='" . esc_attr( __( 'Move this item to the Trash' ) ) . "' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
+ if ( 'trash' == $post->post_status || !EMPTY_TRASH_DAYS )
+ $actions['delete'] = "<a class='submitdelete' title='" . esc_attr( __( 'Delete this item permanently' ) ) . "' href='" . get_delete_post_link( $post->ID, '', true ) . "'>" . __( 'Delete Permanently' ) . "</a>";
+ }
+ if ( $post_type_object->public ) {
+ if ( in_array( $post->post_status, array( 'pending', 'draft', 'future' ) ) ) {
+ if ( $can_edit_post )
+ $actions['view'] = '<a href="' . esc_url( apply_filters( 'preview_post_link', set_url_scheme( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) ) ) ) . '" title="' . esc_attr( sprintf( __( 'Preview &#8220;%s&#8221;' ), $title ) ) . '" rel="permalink">' . __( 'Preview' ) . '</a>';
+ } elseif ( 'trash' != $post->post_status ) {
+ $actions['view'] = '<a href="' . get_permalink( $post->ID ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $title ) ) . '" rel="permalink">' . __( 'View' ) . '</a>';
+ }
+ }
+
+ $actions = apply_filters( is_post_type_hierarchical( $post->post_type ) ? 'page_row_actions' : 'post_row_actions', $actions, $post );
+ echo $this->row_actions( $actions );
+
+ get_inline_data( $post );
+ echo '</td>';
+ break;
+
+ case 'date':
+ if ( '0000-00-00 00:00:00' == $post->post_date ) {
+ $t_time = $h_time = __( 'Unpublished' );
+ $time_diff = 0;
+ } else {
+ $t_time = get_the_time( __( 'Y/m/d g:i:s A' ) );
+ $m_time = $post->post_date;
+ $time = get_post_time( 'G', true, $post );
+
+ $time_diff = time() - $time;
+
+ if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS )
+ $h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
+ else
+ $h_time = mysql2date( __( 'Y/m/d' ), $m_time );
+ }
+
+ echo '<td ' . $attributes . '>';
+ if ( 'excerpt' == $mode )
+ echo apply_filters( 'post_date_column_time', $t_time, $post, $column_name, $mode );
+ else
+ echo '<abbr title="' . $t_time . '">' . apply_filters( 'post_date_column_time', $h_time, $post, $column_name, $mode ) . '</abbr>';
+ echo '<br />';
+ if ( 'publish' == $post->post_status ) {
+ _e( 'Published' );
+ } elseif ( 'future' == $post->post_status ) {
+ if ( $time_diff > 0 )
+ echo '<strong class="attention">' . __( 'Missed schedule' ) . '</strong>';
+ else
+ _e( 'Scheduled' );
+ } else {
+ _e( 'Last Modified' );
+ }
+ echo '</td>';
+ break;
+
+ case 'comments':
+ ?>
+ <td <?php echo $attributes ?>><div class="post-com-count-wrapper">
+ <?php
+ $pending_comments = isset( $this->comment_pending_count[$post->ID] ) ? $this->comment_pending_count[$post->ID] : 0;
+
+ $this->comments_bubble( $post->ID, $pending_comments );
+ ?>
+ </div></td>
+ <?php
+ break;
+
+ case 'author':
+ ?>
+ <td <?php echo $attributes ?>><?php
+ printf( '<a href="%s">%s</a>',
+ esc_url( add_query_arg( array( 'post_type' => $post->post_type, 'author' => get_the_author_meta( 'ID' ) ), 'edit.php' )),
+ get_the_author()
+ );
+ ?></td>
+ <?php
+ break;
+
+ default:
+ if ( 'categories' == $column_name )
+ $taxonomy = 'category';
+ elseif ( 'tags' == $column_name )
+ $taxonomy = 'post_tag';
+ elseif ( 0 === strpos( $column_name, 'taxonomy-' ) )
+ $taxonomy = substr( $column_name, 9 );
+ else
+ $taxonomy = false;
+
+ if ( $taxonomy ) {
+ $taxonomy_object = get_taxonomy( $taxonomy );
+ echo '<td ' . $attributes . '>';
+ if ( $terms = get_the_terms( $post->ID, $taxonomy ) ) {
+ $out = array();
+ foreach ( $terms as $t ) {
+ $posts_in_term_qv = array();
+ if ( 'post' != $post->post_type )
+ $posts_in_term_qv['post_type'] = $post->post_type;
+ if ( $taxonomy_object->query_var ) {
+ $posts_in_term_qv[ $taxonomy_object->query_var ] = $t->slug;
+ } else {
+ $posts_in_term_qv['taxonomy'] = $taxonomy;
+ $posts_in_term_qv['term'] = $t->slug;
+ }
+
+ $out[] = sprintf( '<a href="%s">%s</a>',
+ esc_url( add_query_arg( $posts_in_term_qv, 'edit.php' ) ),
+ esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
+ );
+ }
+ /* translators: used between list items, there is a space after the comma */
+ echo join( __( ', ' ), $out );
+ } else {
+ echo '&#8212;';
+ }
+ echo '</td>';
+ break;
+ }
+ ?>
+ <td <?php echo $attributes ?>><?php
+ if ( is_post_type_hierarchical( $post->post_type ) )
+ do_action( 'manage_pages_custom_column', $column_name, $post->ID );
+ else
+ do_action( 'manage_posts_custom_column', $column_name, $post->ID );
+ do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID );
+ ?></td>
+ <?php
+ break;
+ }
+ }
+ ?>
+ </tr>
+ <?php
+ $GLOBALS['post'] = $global_post;
+ }
+
+ /**
+ * Outputs the hidden row displayed when inline editing
+ *
+ * @since 3.1.0
+ */
+ function inline_edit() {
+ global $mode;
+
+ $screen = $this->screen;
+
+ $post = get_default_post_to_edit( $screen->post_type );
+ $post_type_object = get_post_type_object( $screen->post_type );
+
+ $taxonomy_names = get_object_taxonomies( $screen->post_type );
+ $hierarchical_taxonomies = array();
+ $flat_taxonomies = array();
+ foreach ( $taxonomy_names as $taxonomy_name ) {
+ $taxonomy = get_taxonomy( $taxonomy_name );
+
+ if ( !$taxonomy->show_ui )
+ continue;
+
+ if ( $taxonomy->hierarchical )
+ $hierarchical_taxonomies[] = $taxonomy;
+ else
+ $flat_taxonomies[] = $taxonomy;
+ }
+
+ $m = ( isset( $mode ) && 'excerpt' == $mode ) ? 'excerpt' : 'list';
+ $can_publish = current_user_can( $post_type_object->cap->publish_posts );
+ $core_columns = array( 'cb' => true, 'date' => true, 'title' => true, 'categories' => true, 'tags' => true, 'comments' => true, 'author' => true );
+
+ ?>
+
+ <form method="get" action=""><table style="display: none"><tbody id="inlineedit">
+ <?php
+ $hclass = count( $hierarchical_taxonomies ) ? 'post' : 'page';
+ $bulk = 0;
+ while ( $bulk < 2 ) { ?>
+
+ <tr id="<?php echo $bulk ? 'bulk-edit' : 'inline-edit'; ?>" class="inline-edit-row inline-edit-row-<?php echo "$hclass inline-edit-" . $screen->post_type;
+ echo $bulk ? " bulk-edit-row bulk-edit-row-$hclass bulk-edit-{$screen->post_type}" : " quick-edit-row quick-edit-row-$hclass inline-edit-{$screen->post_type}";
+ ?>" style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
+
+ <fieldset class="inline-edit-col-left"><div class="inline-edit-col">
+ <h4><?php echo $bulk ? __( 'Bulk Edit' ) : __( 'Quick Edit' ); ?></h4>
+ <?php
+
+ if ( post_type_supports( $screen->post_type, 'title' ) ) :
+ if ( $bulk ) : ?>
+ <div id="bulk-title-div">
+ <div id="bulk-titles"></div>
+ </div>
+
+ <?php else : // $bulk ?>
+
+ <label>
+ <span class="title"><?php _e( 'Title' ); ?></span>
+ <span class="input-text-wrap"><input type="text" name="post_title" class="ptitle" value="" /></span>
+ </label>
+
+ <label>
+ <span class="title"><?php _e( 'Slug' ); ?></span>
+ <span class="input-text-wrap"><input type="text" name="post_name" value="" /></span>
+ </label>
+
+ <?php endif; // $bulk
+ endif; // post_type_supports title ?>
+
+ <?php if ( !$bulk ) : ?>
+ <label><span class="title"><?php _e( 'Date' ); ?></span></label>
+ <div class="inline-edit-date">
+ <?php touch_time( 1, 1, 0, 1 ); ?>
+ </div>
+ <br class="clear" />
+ <?php endif; // $bulk
+
+ if ( post_type_supports( $screen->post_type, 'author' ) ) :
+ $authors_dropdown = '';
+
+ if ( is_super_admin() || current_user_can( $post_type_object->cap->edit_others_posts ) ) :
+ $users_opt = array(
+ 'hide_if_only_one_author' => false,
+ 'who' => 'authors',
+ 'name' => 'post_author',
+ 'class'=> 'authors',
+ 'multi' => 1,
+ 'echo' => 0
+ );
+ if ( $bulk )
+ $users_opt['show_option_none'] = __( '&mdash; No Change &mdash;' );
+
+ if ( $authors = wp_dropdown_users( $users_opt ) ) :
+ $authors_dropdown = '<label class="inline-edit-author">';
+ $authors_dropdown .= '<span class="title">' . __( 'Author' ) . '</span>';
+ $authors_dropdown .= $authors;
+ $authors_dropdown .= '</label>';
+ endif;
+ endif; // authors
+ ?>
+
+ <?php if ( !$bulk ) echo $authors_dropdown;
+ endif; // post_type_supports author
+
+ if ( !$bulk ) :
+ ?>
+
+ <div class="inline-edit-group">
+ <label class="alignleft">
+ <span class="title"><?php _e( 'Password' ); ?></span>
+ <span class="input-text-wrap"><input type="text" name="post_password" class="inline-edit-password-input" value="" /></span>
+ </label>
+
+ <em style="margin:5px 10px 0 0" class="alignleft">
+ <?php
+ /* translators: Between password field and private checkbox on post quick edit interface */
+ echo __( '&ndash;OR&ndash;' );
+ ?>
+ </em>
+ <label class="alignleft inline-edit-private">
+ <input type="checkbox" name="keep_private" value="private" />
+ <span class="checkbox-title"><?php echo __( 'Private' ); ?></span>
+ </label>
+ </div>
+
+ <?php endif; ?>
+
+ </div></fieldset>
+
+ <?php if ( count( $hierarchical_taxonomies ) && !$bulk ) : ?>
+
+ <fieldset class="inline-edit-col-center inline-edit-categories"><div class="inline-edit-col">
+
+ <?php foreach ( $hierarchical_taxonomies as $taxonomy ) : ?>
+
+ <span class="title inline-edit-categories-label"><?php echo esc_html( $taxonomy->labels->name ) ?></span>
+ <input type="hidden" name="<?php echo ( $taxonomy->name == 'category' ) ? 'post_category[]' : 'tax_input[' . esc_attr( $taxonomy->name ) . '][]'; ?>" value="0" />
+ <ul class="cat-checklist <?php echo esc_attr( $taxonomy->name )?>-checklist">
+ <?php wp_terms_checklist( null, array( 'taxonomy' => $taxonomy->name ) ) ?>
+ </ul>
+
+ <?php endforeach; //$hierarchical_taxonomies as $taxonomy ?>
+
+ </div></fieldset>
+
+ <?php endif; // count( $hierarchical_taxonomies ) && !$bulk ?>
+
+ <fieldset class="inline-edit-col-right"><div class="inline-edit-col">
+
+ <?php
+ if ( post_type_supports( $screen->post_type, 'author' ) && $bulk )
+ echo $authors_dropdown;
+
+ if ( post_type_supports( $screen->post_type, 'page-attributes' ) ) :
+
+ if ( $post_type_object->hierarchical ) :
+ ?>
+ <label>
+ <span class="title"><?php _e( 'Parent' ); ?></span>
+ <?php
+ $dropdown_args = array(
+ 'post_type' => $post_type_object->name,
+ 'selected' => $post->post_parent,
+ 'name' => 'post_parent',
+ 'show_option_none' => __( 'Main Page (no parent)' ),
+ 'option_none_value' => 0,
+ 'sort_column' => 'menu_order, post_title',
+ );
+
+ if ( $bulk )
+ $dropdown_args['show_option_no_change'] = __( '&mdash; No Change &mdash;' );
+ $dropdown_args = apply_filters( 'quick_edit_dropdown_pages_args', $dropdown_args );
+ wp_dropdown_pages( $dropdown_args );
+ ?>
+ </label>
+
+ <?php
+ endif; // hierarchical
+
+ if ( !$bulk ) : ?>
+
+ <label>
+ <span class="title"><?php _e( 'Order' ); ?></span>
+ <span class="input-text-wrap"><input type="text" name="menu_order" class="inline-edit-menu-order-input" value="<?php echo $post->menu_order ?>" /></span>
+ </label>
+
+ <?php endif; // !$bulk
+
+ if ( 'page' == $screen->post_type ) :
+ ?>
+
+ <label>
+ <span class="title"><?php _e( 'Template' ); ?></span>
+ <select name="page_template">
+ <?php if ( $bulk ) : ?>
+ <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
+ <?php endif; // $bulk ?>
+ <option value="default"><?php _e( 'Default Template' ); ?></option>
+ <?php page_template_dropdown() ?>
+ </select>
+ </label>
+
+ <?php
+ endif; // page post_type
+ endif; // page-attributes
+ ?>
+
+ <?php if ( count( $flat_taxonomies ) && !$bulk ) : ?>
+
+ <?php foreach ( $flat_taxonomies as $taxonomy ) : ?>
+ <?php if ( current_user_can( $taxonomy->cap->assign_terms ) ) : ?>
+ <label class="inline-edit-tags">
+ <span class="title"><?php echo esc_html( $taxonomy->labels->name ) ?></span>
+ <textarea cols="22" rows="1" name="tax_input[<?php echo esc_attr( $taxonomy->name )?>]" class="tax_input_<?php echo esc_attr( $taxonomy->name )?>"></textarea>
+ </label>
+ <?php endif; ?>
+
+ <?php endforeach; //$flat_taxonomies as $taxonomy ?>
+
+ <?php endif; // count( $flat_taxonomies ) && !$bulk ?>
+
+ <?php if ( post_type_supports( $screen->post_type, 'comments' ) || post_type_supports( $screen->post_type, 'trackbacks' ) ) :
+ if ( $bulk ) : ?>
+
+ <div class="inline-edit-group">
+ <?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?>
+ <label class="alignleft">
+ <span class="title"><?php _e( 'Comments' ); ?></span>
+ <select name="comment_status">
+ <option value=""><?php _e( '&mdash; No Change &mdash;' ); ?></option>
+ <option value="open"><?php _e( 'Allow' ); ?></option>
+ <option value="closed"><?php _e( 'Do not allow' ); ?></option>
+ </select>
+ </label>
+ <?php endif; if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?>
+ <label class="alignright">
+ <span class="title"><?php _e( 'Pings' ); ?></span>
+ <select name="ping_status">
+ <option value=""><?php _e( '&mdash; No Change &mdash;' ); ?></option>
+ <option value="open"><?php _e( 'Allow' ); ?></option>
+ <option value="closed"><?php _e( 'Do not allow' ); ?></option>
+ </select>
+ </label>
+ <?php endif; ?>
+ </div>
+
+ <?php else : // $bulk ?>
+
+ <div class="inline-edit-group">
+ <?php if ( post_type_supports( $screen->post_type, 'comments' ) ) : ?>
+ <label class="alignleft">
+ <input type="checkbox" name="comment_status" value="open" />
+ <span class="checkbox-title"><?php _e( 'Allow Comments' ); ?></span>
+ </label>
+ <?php endif; if ( post_type_supports( $screen->post_type, 'trackbacks' ) ) : ?>
+ <label class="alignleft">
+ <input type="checkbox" name="ping_status" value="open" />
+ <span class="checkbox-title"><?php _e( 'Allow Pings' ); ?></span>
+ </label>
+ <?php endif; ?>
+ </div>
+
+ <?php endif; // $bulk
+ endif; // post_type_supports comments or pings ?>
+
+ <div class="inline-edit-group">
+ <label class="inline-edit-status alignleft">
+ <span class="title"><?php _e( 'Status' ); ?></span>
+ <select name="_status">
+ <?php if ( $bulk ) : ?>
+ <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
+ <?php endif; // $bulk ?>
+ <?php if ( $can_publish ) : // Contributors only get "Unpublished" and "Pending Review" ?>
+ <option value="publish"><?php _e( 'Published' ); ?></option>
+ <option value="future"><?php _e( 'Scheduled' ); ?></option>
+ <?php if ( $bulk ) : ?>
+ <option value="private"><?php _e( 'Private' ) ?></option>
+ <?php endif; // $bulk ?>
+ <?php endif; ?>
+ <option value="pending"><?php _e( 'Pending Review' ); ?></option>
+ <option value="draft"><?php _e( 'Draft' ); ?></option>
+ </select>
+ </label>
+
+ <?php if ( 'post' == $screen->post_type && $can_publish && current_user_can( $post_type_object->cap->edit_others_posts ) ) : ?>
+
+ <?php if ( $bulk ) : ?>
+
+ <label class="alignright">
+ <span class="title"><?php _e( 'Sticky' ); ?></span>
+ <select name="sticky">
+ <option value="-1"><?php _e( '&mdash; No Change &mdash;' ); ?></option>
+ <option value="sticky"><?php _e( 'Sticky' ); ?></option>
+ <option value="unsticky"><?php _e( 'Not Sticky' ); ?></option>
+ </select>
+ </label>
+
+ <?php else : // $bulk ?>
+
+ <label class="alignleft">
+ <input type="checkbox" name="sticky" value="sticky" />
+ <span class="checkbox-title"><?php _e( 'Make this post sticky' ); ?></span>
+ </label>
+
+ <?php endif; // $bulk ?>
+
+ <?php endif; // 'post' && $can_publish && current_user_can( 'edit_others_cap' ) ?>
+
+ </div>
+ </div></fieldset>
+
+ <?php
+ list( $columns ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ if ( isset( $core_columns[$column_name] ) )
+ continue;
+ do_action( $bulk ? 'bulk_edit_custom_box' : 'quick_edit_custom_box', $column_name, $screen->post_type );
+ }
+ ?>
+ <p class="submit inline-edit-save">
+ <a accesskey="c" href="#inline-edit" class="button-secondary cancel alignleft"><?php _e( 'Cancel' ); ?></a>
+ <?php if ( ! $bulk ) {
+ wp_nonce_field( 'inlineeditnonce', '_inline_edit', false );
+ ?>
+ <a accesskey="s" href="#inline-edit" class="button-primary save alignright"><?php _e( 'Update' ); ?></a>
+ <span class="spinner"></span>
+ <?php } else {
+ submit_button( __( 'Update' ), 'button-primary alignright', 'bulk_edit', false, array( 'accesskey' => 's' ) );
+ } ?>
+ <input type="hidden" name="post_view" value="<?php echo esc_attr( $m ); ?>" />
+ <input type="hidden" name="screen" value="<?php echo esc_attr( $screen->id ); ?>" />
+ <span class="error" style="display:none"></span>
+ <br class="clear" />
+ </p>
+ </td></tr>
+ <?php
+ $bulk++;
+ }
+?>
+ </tbody></table></form>
+<?php
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-terms-list-table.php b/src/wp-admin/includes/class-wp-terms-list-table.php
new file mode 100644
index 0000000000..f44b626616
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-terms-list-table.php
@@ -0,0 +1,378 @@
+<?php
+/**
+ * Terms List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Terms_List_Table extends WP_List_Table {
+
+ var $callback_args;
+
+ function __construct( $args = array() ) {
+ global $post_type, $taxonomy, $action, $tax;
+
+ parent::__construct( array(
+ 'plural' => 'tags',
+ 'singular' => 'tag',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+
+ $action = $this->screen->action;
+ $post_type = $this->screen->post_type;
+ $taxonomy = $this->screen->taxonomy;
+
+ if ( empty( $taxonomy ) )
+ $taxonomy = 'post_tag';
+
+ if ( ! taxonomy_exists( $taxonomy ) )
+ wp_die( __( 'Invalid taxonomy' ) );
+
+ $tax = get_taxonomy( $taxonomy );
+
+ // @todo Still needed? Maybe just the show_ui part.
+ if ( empty( $post_type ) || !in_array( $post_type, get_post_types( array( 'show_ui' => true ) ) ) )
+ $post_type = 'post';
+
+ }
+
+ function ajax_user_can() {
+ return current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->manage_terms );
+ }
+
+ function prepare_items() {
+ $tags_per_page = $this->get_items_per_page( 'edit_' . $this->screen->taxonomy . '_per_page' );
+
+ if ( 'post_tag' == $this->screen->taxonomy ) {
+ $tags_per_page = apply_filters( 'edit_tags_per_page', $tags_per_page );
+ $tags_per_page = apply_filters( 'tagsperpage', $tags_per_page ); // Old filter
+ } elseif ( 'category' == $this->screen->taxonomy ) {
+ $tags_per_page = apply_filters( 'edit_categories_per_page', $tags_per_page ); // Old filter
+ }
+
+ $search = !empty( $_REQUEST['s'] ) ? trim( wp_unslash( $_REQUEST['s'] ) ) : '';
+
+ $args = array(
+ 'search' => $search,
+ 'page' => $this->get_pagenum(),
+ 'number' => $tags_per_page,
+ );
+
+ if ( !empty( $_REQUEST['orderby'] ) )
+ $args['orderby'] = trim( wp_unslash( $_REQUEST['orderby'] ) );
+
+ if ( !empty( $_REQUEST['order'] ) )
+ $args['order'] = trim( wp_unslash( $_REQUEST['order'] ) );
+
+ $this->callback_args = $args;
+
+ $this->set_pagination_args( array(
+ 'total_items' => wp_count_terms( $this->screen->taxonomy, compact( 'search' ) ),
+ 'per_page' => $tags_per_page,
+ ) );
+ }
+
+ function has_items() {
+ // todo: populate $this->items in prepare_items()
+ return true;
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+ $actions['delete'] = __( 'Delete' );
+
+ return $actions;
+ }
+
+ function current_action() {
+ if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['delete_tags'] ) && ( 'delete' == $_REQUEST['action'] || 'delete' == $_REQUEST['action2'] ) )
+ return 'bulk-delete';
+
+ return parent::current_action();
+ }
+
+ function get_columns() {
+ $columns = array(
+ 'cb' => '<input type="checkbox" />',
+ 'name' => _x( 'Name', 'term name' ),
+ 'description' => __( 'Description' ),
+ 'slug' => __( 'Slug' ),
+ );
+
+ if ( 'link_category' == $this->screen->taxonomy ) {
+ $columns['links'] = __( 'Links' );
+ } else {
+ $post_type_object = get_post_type_object( $this->screen->post_type );
+ $columns['posts'] = $post_type_object ? $post_type_object->labels->name : __( 'Posts' );
+ }
+
+ return $columns;
+ }
+
+ function get_sortable_columns() {
+ return array(
+ 'name' => 'name',
+ 'description' => 'description',
+ 'slug' => 'slug',
+ 'posts' => 'count',
+ 'links' => 'count'
+ );
+ }
+
+ function display_rows_or_placeholder() {
+ $taxonomy = $this->screen->taxonomy;
+
+ $args = wp_parse_args( $this->callback_args, array(
+ 'page' => 1,
+ 'number' => 20,
+ 'search' => '',
+ 'hide_empty' => 0
+ ) );
+
+ extract( $args, EXTR_SKIP );
+
+ $args['offset'] = $offset = ( $page - 1 ) * $number;
+
+ // convert it to table rows
+ $count = 0;
+
+ $terms = array();
+
+ if ( is_taxonomy_hierarchical( $taxonomy ) && !isset( $orderby ) ) {
+ // We'll need the full set of terms then.
+ $args['number'] = $args['offset'] = 0;
+ }
+ $terms = get_terms( $taxonomy, $args );
+
+ if ( empty( $terms ) ) {
+ list( $columns, $hidden ) = $this->get_column_info();
+ echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
+ $this->no_items();
+ echo '</td></tr>';
+ return;
+ }
+
+ if ( is_taxonomy_hierarchical( $taxonomy ) && !isset( $orderby ) ) {
+ if ( !empty( $search ) ) // Ignore children on searches.
+ $children = array();
+ else
+ $children = _get_term_hierarchy( $taxonomy );
+
+ // Some funky recursion to get the job done( Paging & parents mainly ) is contained within, Skip it for non-hierarchical taxonomies for performance sake
+ $this->_rows( $taxonomy, $terms, $children, $offset, $number, $count );
+ } else {
+ $terms = get_terms( $taxonomy, $args );
+ foreach ( $terms as $term )
+ $this->single_row( $term );
+ $count = $number; // Only displaying a single page.
+ }
+ }
+
+ function _rows( $taxonomy, $terms, &$children, $start, $per_page, &$count, $parent = 0, $level = 0 ) {
+
+ $end = $start + $per_page;
+
+ foreach ( $terms as $key => $term ) {
+
+ if ( $count >= $end )
+ break;
+
+ if ( $term->parent != $parent && empty( $_REQUEST['s'] ) )
+ continue;
+
+ // If the page starts in a subtree, print the parents.
+ if ( $count == $start && $term->parent > 0 && empty( $_REQUEST['s'] ) ) {
+ $my_parents = $parent_ids = array();
+ $p = $term->parent;
+ while ( $p ) {
+ $my_parent = get_term( $p, $taxonomy );
+ $my_parents[] = $my_parent;
+ $p = $my_parent->parent;
+ if ( in_array( $p, $parent_ids ) ) // Prevent parent loops.
+ break;
+ $parent_ids[] = $p;
+ }
+ unset( $parent_ids );
+
+ $num_parents = count( $my_parents );
+ while ( $my_parent = array_pop( $my_parents ) ) {
+ echo "\t";
+ $this->single_row( $my_parent, $level - $num_parents );
+ $num_parents--;
+ }
+ }
+
+ if ( $count >= $start ) {
+ echo "\t";
+ $this->single_row( $term, $level );
+ }
+
+ ++$count;
+
+ unset( $terms[$key] );
+
+ if ( isset( $children[$term->term_id] ) && empty( $_REQUEST['s'] ) )
+ $this->_rows( $taxonomy, $terms, $children, $start, $per_page, $count, $term->term_id, $level + 1 );
+ }
+ }
+
+ function single_row( $tag, $level = 0 ) {
+ static $row_class = '';
+ $row_class = ( $row_class == '' ? ' class="alternate"' : '' );
+
+ $this->level = $level;
+
+ echo '<tr id="tag-' . $tag->term_id . '"' . $row_class . '>';
+ $this->single_row_columns( $tag );
+ echo '</tr>';
+ }
+
+ function column_cb( $tag ) {
+ $default_term = get_option( 'default_' . $this->screen->taxonomy );
+
+ if ( current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->delete_terms ) && $tag->term_id != $default_term )
+ return '<label class="screen-reader-text" for="cb-select-' . $tag->term_id . '">' . sprintf( __( 'Select %s' ), $tag->name ) . '</label>'
+ . '<input type="checkbox" name="delete_tags[]" value="' . $tag->term_id . '" id="cb-select-' . $tag->term_id . '" />';
+
+ return '&nbsp;';
+ }
+
+ function column_name( $tag ) {
+ $taxonomy = $this->screen->taxonomy;
+ $tax = get_taxonomy( $taxonomy );
+
+ $default_term = get_option( 'default_' . $taxonomy );
+
+ $pad = str_repeat( '&#8212; ', max( 0, $this->level ) );
+ $name = apply_filters( 'term_name', $pad . ' ' . $tag->name, $tag );
+ $qe_data = get_term( $tag->term_id, $taxonomy, OBJECT, 'edit' );
+ $edit_link = esc_url( get_edit_term_link( $tag->term_id, $taxonomy, $this->screen->post_type ) );
+
+ $out = '<strong><a class="row-title" href="' . $edit_link . '" title="' . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $name ) ) . '">' . $name . '</a></strong><br />';
+
+ $actions = array();
+ if ( current_user_can( $tax->cap->edit_terms ) ) {
+ $actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+ $actions['inline hide-if-no-js'] = '<a href="#" class="editinline">' . __( 'Quick&nbsp;Edit' ) . '</a>';
+ }
+ if ( current_user_can( $tax->cap->delete_terms ) && $tag->term_id != $default_term )
+ $actions['delete'] = "<a class='delete-tag' href='" . wp_nonce_url( "edit-tags.php?action=delete&amp;taxonomy=$taxonomy&amp;tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ) . "'>" . __( 'Delete' ) . "</a>";
+ if ( $tax->public )
+ $actions['view'] = '<a href="' . get_term_link( $tag ) . '">' . __( 'View' ) . '</a>';
+
+ $actions = apply_filters( 'tag_row_actions', $actions, $tag );
+ $actions = apply_filters( "{$taxonomy}_row_actions", $actions, $tag );
+
+ $out .= $this->row_actions( $actions );
+ $out .= '<div class="hidden" id="inline_' . $qe_data->term_id . '">';
+ $out .= '<div class="name">' . $qe_data->name . '</div>';
+ $out .= '<div class="slug">' . apply_filters( 'editable_slug', $qe_data->slug ) . '</div>';
+ $out .= '<div class="parent">' . $qe_data->parent . '</div></div>';
+
+ return $out;
+ }
+
+ function column_description( $tag ) {
+ return $tag->description;
+ }
+
+ function column_slug( $tag ) {
+ return apply_filters( 'editable_slug', $tag->slug );
+ }
+
+ function column_posts( $tag ) {
+ $count = number_format_i18n( $tag->count );
+
+ $tax = get_taxonomy( $this->screen->taxonomy );
+
+ $ptype_object = get_post_type_object( $this->screen->post_type );
+ if ( ! $ptype_object->show_ui )
+ return $count;
+
+ if ( $tax->query_var ) {
+ $args = array( $tax->query_var => $tag->slug );
+ } else {
+ $args = array( 'taxonomy' => $tax->name, 'term' => $tag->slug );
+ }
+
+ if ( 'post' != $this->screen->post_type )
+ $args['post_type'] = $this->screen->post_type;
+
+ if ( 'attachment' == $this->screen->post_type )
+ return "<a href='" . esc_url ( add_query_arg( $args, 'upload.php' ) ) . "'>$count</a>";
+
+ return "<a href='" . esc_url ( add_query_arg( $args, 'edit.php' ) ) . "'>$count</a>";
+ }
+
+ function column_links( $tag ) {
+ $count = number_format_i18n( $tag->count );
+ if ( $count )
+ $count = "<a href='link-manager.php?cat_id=$tag->term_id'>$count</a>";
+ return $count;
+ }
+
+ function column_default( $tag, $column_name ) {
+ return apply_filters( "manage_{$this->screen->taxonomy}_custom_column", '', $column_name, $tag->term_id );
+ }
+
+ /**
+ * Outputs the hidden row displayed when inline editing
+ *
+ * @since 3.1.0
+ */
+ function inline_edit() {
+ $tax = get_taxonomy( $this->screen->taxonomy );
+
+ if ( ! current_user_can( $tax->cap->edit_terms ) )
+ return;
+?>
+
+ <form method="get" action=""><table style="display: none"><tbody id="inlineedit">
+ <tr id="inline-edit" class="inline-edit-row" style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
+
+ <fieldset><div class="inline-edit-col">
+ <h4><?php _e( 'Quick Edit' ); ?></h4>
+
+ <label>
+ <span class="title"><?php _ex( 'Name', 'term name' ); ?></span>
+ <span class="input-text-wrap"><input type="text" name="name" class="ptitle" value="" /></span>
+ </label>
+ <?php if ( !global_terms_enabled() ) { ?>
+ <label>
+ <span class="title"><?php _e( 'Slug' ); ?></span>
+ <span class="input-text-wrap"><input type="text" name="slug" class="ptitle" value="" /></span>
+ </label>
+ <?php } ?>
+ </div></fieldset>
+ <?php
+
+ $core_columns = array( 'cb' => true, 'description' => true, 'name' => true, 'slug' => true, 'posts' => true );
+
+ list( $columns ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ if ( isset( $core_columns[$column_name] ) )
+ continue;
+
+ do_action( 'quick_edit_custom_box', $column_name, 'edit-tags', $this->screen->taxonomy );
+ }
+
+ ?>
+
+ <p class="inline-edit-save submit">
+ <a accesskey="c" href="#inline-edit" class="cancel button-secondary alignleft"><?php _e( 'Cancel' ); ?></a>
+ <a accesskey="s" href="#inline-edit" class="save button-primary alignright"><?php echo $tax->labels->update_item; ?></a>
+ <span class="spinner"></span>
+ <span class="error" style="display:none;"></span>
+ <?php wp_nonce_field( 'taxinlineeditnonce', '_inline_edit', false ); ?>
+ <input type="hidden" name="taxonomy" value="<?php echo esc_attr( $this->screen->taxonomy ); ?>" />
+ <input type="hidden" name="post_type" value="<?php echo esc_attr( $this->screen->post_type ); ?>" />
+ <br class="clear" />
+ </p>
+ </td></tr>
+ </tbody></table></form>
+ <?php
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-theme-install-list-table.php b/src/wp-admin/includes/class-wp-theme-install-list-table.php
new file mode 100644
index 0000000000..8a46199f16
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-theme-install-list-table.php
@@ -0,0 +1,394 @@
+<?php
+/**
+ * Theme Installer List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Theme_Install_List_Table extends WP_Themes_List_Table {
+
+ var $features = array();
+
+ function ajax_user_can() {
+ return current_user_can( 'install_themes' );
+ }
+
+ function prepare_items() {
+ include( ABSPATH . 'wp-admin/includes/theme-install.php' );
+
+ global $tabs, $tab, $paged, $type, $theme_field_defaults;
+ wp_reset_vars( array( 'tab' ) );
+
+ $search_terms = array();
+ $search_string = '';
+ if ( ! empty( $_REQUEST['s'] ) ){
+ $search_string = strtolower( wp_unslash( $_REQUEST['s'] ) );
+ $search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', $search_string ) ) ) );
+ }
+
+ if ( ! empty( $_REQUEST['features'] ) )
+ $this->features = $_REQUEST['features'];
+
+ $paged = $this->get_pagenum();
+
+ $per_page = 36;
+
+ // These are the tabs which are shown on the page,
+ $tabs = array();
+ $tabs['dashboard'] = __( 'Search' );
+ if ( 'search' == $tab )
+ $tabs['search'] = __( 'Search Results' );
+ $tabs['upload'] = __( 'Upload' );
+ $tabs['featured'] = _x( 'Featured','Theme Installer' );
+ //$tabs['popular'] = _x( 'Popular','Theme Installer' );
+ $tabs['new'] = _x( 'Newest','Theme Installer' );
+ $tabs['updated'] = _x( 'Recently Updated','Theme Installer' );
+
+ $nonmenu_tabs = array( 'theme-information' ); // Valid actions to perform which do not have a Menu item.
+
+ $tabs = apply_filters( 'install_themes_tabs', $tabs );
+ $nonmenu_tabs = apply_filters( 'install_themes_nonmenu_tabs', $nonmenu_tabs );
+
+ // If a non-valid menu tab has been selected, And it's not a non-menu action.
+ if ( empty( $tab ) || ( ! isset( $tabs[ $tab ] ) && ! in_array( $tab, (array) $nonmenu_tabs ) ) )
+ $tab = key( $tabs );
+
+ $args = array( 'page' => $paged, 'per_page' => $per_page, 'fields' => $theme_field_defaults );
+
+ switch ( $tab ) {
+ case 'search':
+ $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
+ switch ( $type ) {
+ case 'tag':
+ $args['tag'] = array_map( 'sanitize_key', $search_terms );
+ break;
+ case 'term':
+ $args['search'] = $search_string;
+ break;
+ case 'author':
+ $args['author'] = $search_string;
+ break;
+ }
+
+ if ( ! empty( $this->features ) ) {
+ $args['tag'] = $this->features;
+ $_REQUEST['s'] = implode( ',', $this->features );
+ $_REQUEST['type'] = 'tag';
+ }
+
+ add_action( 'install_themes_table_header', 'install_theme_search_form', 10, 0 );
+ break;
+
+ case 'featured':
+ //case 'popular':
+ case 'new':
+ case 'updated':
+ $args['browse'] = $tab;
+ break;
+
+ default:
+ $args = false;
+ }
+
+ if ( ! $args )
+ return;
+
+ $api = themes_api( 'query_themes', $args );
+
+ if ( is_wp_error( $api ) )
+ wp_die( $api->get_error_message() . '</p> <p><a href="#" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a>' );
+
+ $this->items = $api->themes;
+
+ $this->set_pagination_args( array(
+ 'total_items' => $api->info['results'],
+ 'per_page' => $per_page,
+ 'infinite_scroll' => true,
+ ) );
+ }
+
+ function no_items() {
+ _e( 'No themes match your request.' );
+ }
+
+ function get_views() {
+ global $tabs, $tab;
+
+ $display_tabs = array();
+ foreach ( (array) $tabs as $action => $text ) {
+ $class = ( $action == $tab ) ? ' class="current"' : '';
+ $href = self_admin_url('theme-install.php?tab=' . $action);
+ $display_tabs['theme-install-'.$action] = "<a href='$href'$class>$text</a>";
+ }
+
+ return $display_tabs;
+ }
+
+ function display() {
+ wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
+?>
+ <div class="tablenav top themes">
+ <div class="alignleft actions">
+ <?php do_action( 'install_themes_table_header' ); ?>
+ </div>
+ <?php $this->pagination( 'top' ); ?>
+ <br class="clear" />
+ </div>
+
+ <div id="availablethemes">
+ <?php $this->display_rows_or_placeholder(); ?>
+ </div>
+
+ <?php
+ parent::tablenav( 'bottom' );
+ }
+
+ function display_rows() {
+ $themes = $this->items;
+ foreach ( $themes as $theme ) {
+ ?>
+ <div class="available-theme installable-theme"><?php
+ $this->single_row( $theme );
+ ?></div>
+ <?php } // end foreach $theme_names
+
+ $this->theme_installer();
+ }
+
+ /*
+ * Prints a theme from the WordPress.org API.
+ *
+ * @param object $theme An object that contains theme data returned by the WordPress.org API.
+ *
+ * Example theme data:
+ * object(stdClass)[59]
+ * public 'name' => string 'Magazine Basic'
+ * public 'slug' => string 'magazine-basic'
+ * public 'version' => string '1.1'
+ * public 'author' => string 'tinkerpriest'
+ * public 'preview_url' => string 'http://wp-themes.com/?magazine-basic'
+ * public 'screenshot_url' => string 'http://wp-themes.com/wp-content/themes/magazine-basic/screenshot.png'
+ * public 'rating' => float 80
+ * public 'num_ratings' => int 1
+ * public 'homepage' => string 'http://wordpress.org/themes/magazine-basic'
+ * public 'description' => string 'A basic magazine style layout with a fully customizable layout through a backend interface. Designed by <a href="http://bavotasan.com">c.bavota</a> of <a href="http://tinkerpriestmedia.com">Tinker Priest Media</a>.'
+ * public 'download_link' => string 'http://wordpress.org/themes/download/magazine-basic.1.1.zip'
+ */
+ function single_row( $theme ) {
+ global $themes_allowedtags;
+
+ if ( empty( $theme ) )
+ return;
+
+ $name = wp_kses( $theme->name, $themes_allowedtags );
+ $author = wp_kses( $theme->author, $themes_allowedtags );
+
+ $preview_title = sprintf( __('Preview &#8220;%s&#8221;'), $name );
+ $preview_url = add_query_arg( array(
+ 'tab' => 'theme-information',
+ 'theme' => $theme->slug,
+ ) );
+
+ $actions = array();
+
+ $install_url = add_query_arg( array(
+ 'action' => 'install-theme',
+ 'theme' => $theme->slug,
+ ), self_admin_url( 'update.php' ) );
+
+ $update_url = add_query_arg( array(
+ 'action' => 'upgrade-theme',
+ 'theme' => $theme->slug,
+ ), self_admin_url( 'update.php' ) );
+
+ $status = $this->_get_theme_status( $theme );
+
+ switch ( $status ) {
+ default:
+ case 'install':
+ $actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Install %s' ), $name ) ) . '">' . __( 'Install Now' ) . '</a>';
+ break;
+ case 'update_available':
+ $actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
+ break;
+ case 'newer_installed':
+ case 'latest_installed':
+ $actions[] = '<span class="install-now" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
+ break;
+ }
+
+ $actions[] = '<a class="install-theme-preview" href="' . esc_url( $preview_url ) . '" title="' . esc_attr( sprintf( __( 'Preview %s' ), $name ) ) . '">' . __( 'Preview' ) . '</a>';
+
+ $actions = apply_filters( 'theme_install_actions', $actions, $theme );
+
+ ?>
+ <a class="screenshot install-theme-preview" href="<?php echo esc_url( $preview_url ); ?>" title="<?php echo esc_attr( $preview_title ); ?>">
+ <img src='<?php echo esc_url( $theme->screenshot_url ); ?>' width='150' />
+ </a>
+
+ <h3><?php echo $name; ?></h3>
+ <div class="theme-author"><?php printf( __( 'By %s' ), $author ); ?></div>
+
+ <div class="action-links">
+ <ul>
+ <?php foreach ( $actions as $action ): ?>
+ <li><?php echo $action; ?></li>
+ <?php endforeach; ?>
+ <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e('Details') ?></a></li>
+ </ul>
+ </div>
+
+ <?php
+ $this->install_theme_info( $theme );
+ }
+
+ /*
+ * Prints the wrapper for the theme installer.
+ */
+ function theme_installer() {
+ ?>
+ <div id="theme-installer" class="wp-full-overlay expanded">
+ <div class="wp-full-overlay-sidebar">
+ <div class="wp-full-overlay-header">
+ <a href="#" class="close-full-overlay"><?php _e( '&larr; Close' ); ?></a>
+ </div>
+ <div class="wp-full-overlay-sidebar-content">
+ <div class="install-theme-info"></div>
+ </div>
+ <div class="wp-full-overlay-footer">
+ <a href="#" class="collapse-sidebar button-secondary" title="<?php esc_attr_e('Collapse Sidebar'); ?>">
+ <span class="collapse-sidebar-label"><?php _e('Collapse'); ?></span>
+ <span class="collapse-sidebar-arrow"></span>
+ </a>
+ </div>
+ </div>
+ <div class="wp-full-overlay-main"></div>
+ </div>
+ <?php
+ }
+
+ /*
+ * Prints the wrapper for the theme installer with a provided theme's data.
+ * Used to make the theme installer work for no-js.
+ *
+ * @param object $theme - A WordPress.org Theme API object.
+ */
+ function theme_installer_single( $theme ) {
+ ?>
+ <div id="theme-installer" class="wp-full-overlay single-theme">
+ <div class="wp-full-overlay-sidebar">
+ <?php $this->install_theme_info( $theme ); ?>
+ </div>
+ <div class="wp-full-overlay-main">
+ <iframe src="<?php echo esc_url( $theme->preview_url ); ?>"></iframe>
+ </div>
+ </div>
+ <?php
+ }
+
+ /*
+ * Prints the info for a theme (to be used in the theme installer modal).
+ *
+ * @param object $theme - A WordPress.org Theme API object.
+ */
+ function install_theme_info( $theme ) {
+ global $themes_allowedtags;
+
+ if ( empty( $theme ) )
+ return;
+
+ $name = wp_kses( $theme->name, $themes_allowedtags );
+ $author = wp_kses( $theme->author, $themes_allowedtags );
+
+ $num_ratings = sprintf( _n( '(based on %s rating)', '(based on %s ratings)', $theme->num_ratings ), number_format_i18n( $theme->num_ratings ) );
+
+ $install_url = add_query_arg( array(
+ 'action' => 'install-theme',
+ 'theme' => $theme->slug,
+ ), self_admin_url( 'update.php' ) );
+
+ $update_url = add_query_arg( array(
+ 'action' => 'upgrade-theme',
+ 'theme' => $theme->slug,
+ ), self_admin_url( 'update.php' ) );
+
+ $status = $this->_get_theme_status( $theme );
+
+ ?>
+ <div class="install-theme-info"><?php
+ switch ( $status ) {
+ default:
+ case 'install':
+ echo '<a class="theme-install button-primary" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '">' . __( 'Install' ) . '</a>';
+ break;
+ case 'update_available':
+ echo '<a class="theme-install button-primary" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
+ break;
+ case 'newer_installed':
+ case 'latest_installed':
+ echo '<span class="theme-install" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
+ break;
+ } ?>
+ <h3 class="theme-name"><?php echo $name; ?></h3>
+ <span class="theme-by"><?php printf( __( 'By %s' ), $author ); ?></span>
+ <?php if ( isset( $theme->screenshot_url ) ): ?>
+ <img class="theme-screenshot" src="<?php echo esc_url( $theme->screenshot_url ); ?>" />
+ <?php endif; ?>
+ <div class="theme-details">
+ <div class="star-holder" title="<?php echo esc_attr( $num_ratings ); ?>">
+ <div class="star-rating" style="width:<?php echo esc_attr( intval( $theme->rating ) . 'px' ); ?>;"></div>
+ </div>
+ <div class="theme-version">
+ <strong><?php _e('Version:') ?> </strong>
+ <?php echo wp_kses( $theme->version, $themes_allowedtags ); ?>
+ </div>
+ <div class="theme-description">
+ <?php echo wp_kses( $theme->description, $themes_allowedtags ); ?>
+ </div>
+ </div>
+ <input class="theme-preview-url" type="hidden" value="<?php echo esc_url( $theme->preview_url ); ?>" />
+ </div>
+ <?php
+ }
+
+ /**
+ * Send required variables to JavaScript land
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @uses $tab Global; current tab within Themes->Install screen
+ * @uses $type Global; type of search.
+ */
+ function _js_vars( $extra_args = array() ) {
+ global $tab, $type;
+ parent::_js_vars( compact( 'tab', 'type' ) );
+ }
+
+ /**
+ * Check to see if the theme is already installed.
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @param object $theme - A WordPress.org Theme API object.
+ * @return string Theme status.
+ */
+ private function _get_theme_status( $theme ) {
+ $status = 'install';
+
+ $installed_theme = wp_get_theme( $theme->slug );
+ if ( $installed_theme->exists() ) {
+ if ( version_compare( $installed_theme->get('Version'), $theme->version, '=' ) )
+ $status = 'latest_installed';
+ elseif ( version_compare( $installed_theme->get('Version'), $theme->version, '>' ) )
+ $status = 'newer_installed';
+ else
+ $status = 'update_available';
+ }
+
+ return $status;
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-themes-list-table.php b/src/wp-admin/includes/class-wp-themes-list-table.php
new file mode 100644
index 0000000000..684bd8be00
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-themes-list-table.php
@@ -0,0 +1,253 @@
+<?php
+/**
+ * Themes List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Themes_List_Table extends WP_List_Table {
+
+ protected $search_terms = array();
+ var $features = array();
+
+ function __construct( $args = array() ) {
+ parent::__construct( array(
+ 'ajax' => true,
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+ }
+
+ function ajax_user_can() {
+ // Do not check edit_theme_options here. AJAX calls for available themes require switch_themes.
+ return current_user_can( 'switch_themes' );
+ }
+
+ function prepare_items() {
+ $themes = wp_get_themes( array( 'allowed' => true ) );
+
+ if ( ! empty( $_REQUEST['s'] ) )
+ $this->search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', strtolower( wp_unslash( $_REQUEST['s'] ) ) ) ) ) );
+
+ if ( ! empty( $_REQUEST['features'] ) )
+ $this->features = $_REQUEST['features'];
+
+ if ( $this->search_terms || $this->features ) {
+ foreach ( $themes as $key => $theme ) {
+ if ( ! $this->search_theme( $theme ) )
+ unset( $themes[ $key ] );
+ }
+ }
+
+ unset( $themes[ get_option( 'stylesheet' ) ] );
+ WP_Theme::sort_by_name( $themes );
+
+ $per_page = 36;
+ $page = $this->get_pagenum();
+
+ $start = ( $page - 1 ) * $per_page;
+
+ $this->items = array_slice( $themes, $start, $per_page, true );
+
+ $this->set_pagination_args( array(
+ 'total_items' => count( $themes ),
+ 'per_page' => $per_page,
+ 'infinite_scroll' => true,
+ ) );
+ }
+
+ function no_items() {
+ if ( $this->search_terms || $this->features ) {
+ _e( 'No items found.' );
+ return;
+ }
+
+ if ( is_multisite() ) {
+ if ( current_user_can( 'install_themes' ) && current_user_can( 'manage_network_themes' ) ) {
+ printf( __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%1$s">enable</a> or <a href="%2$s">install</a> more themes.' ), network_admin_url( 'site-themes.php?id=' . $GLOBALS['blog_id'] ), network_admin_url( 'theme-install.php' ) );
+
+ return;
+ } elseif ( current_user_can( 'manage_network_themes' ) ) {
+ printf( __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%1$s">enable</a> more themes.' ), network_admin_url( 'site-themes.php?id=' . $GLOBALS['blog_id'] ) );
+
+ return;
+ }
+ // else, fallthrough. install_themes doesn't help if you can't enable it.
+ } else {
+ if ( current_user_can( 'install_themes' ) ) {
+ printf( __( 'You only have one theme installed right now. Live a little! You can choose from over 1,000 free themes in the WordPress.org Theme Directory at any time: just click on the <a href="%s">Install Themes</a> tab above.' ), admin_url( 'theme-install.php' ) );
+
+ return;
+ }
+ }
+ // Fallthrough.
+ printf( __( 'Only the current theme is available to you. Contact the %s administrator for information about accessing additional themes.' ), get_site_option( 'site_name' ) );
+ }
+
+ function tablenav( $which = 'top' ) {
+ if ( $this->get_pagination_arg( 'total_pages' ) <= 1 )
+ return;
+ ?>
+ <div class="tablenav themes <?php echo $which; ?>">
+ <?php $this->pagination( $which ); ?>
+ <span class="spinner"></span>
+ <br class="clear" />
+ </div>
+ <?php
+ }
+
+ function display() {
+ wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
+?>
+ <?php $this->tablenav( 'top' ); ?>
+
+ <div id="availablethemes">
+ <?php $this->display_rows_or_placeholder(); ?>
+ </div>
+
+ <?php $this->tablenav( 'bottom' ); ?>
+<?php
+ }
+
+ function get_columns() {
+ return array();
+ }
+
+ function display_rows() {
+ $themes = $this->items;
+
+ foreach ( $themes as $theme ):
+ ?><div class="available-theme"><?php
+
+ $template = $theme->get_template();
+ $stylesheet = $theme->get_stylesheet();
+ $title = $theme->display('Name');
+ $version = $theme->display('Version');
+ $author = $theme->display('Author');
+
+ $activate_link = wp_nonce_url( "themes.php?action=activate&amp;template=" . urlencode( $template ) . "&amp;stylesheet=" . urlencode( $stylesheet ), 'switch-theme_' . $stylesheet );
+
+ $preview_link = esc_url( add_query_arg(
+ array( 'preview' => 1, 'template' => urlencode( $template ), 'stylesheet' => urlencode( $stylesheet ), 'preview_iframe' => true, 'TB_iframe' => 'true' ),
+ home_url( '/' ) ) );
+
+ $actions = array();
+ $actions['activate'] = '<a href="' . $activate_link . '" class="activatelink" title="'
+ . esc_attr( sprintf( __( 'Activate &#8220;%s&#8221;' ), $title ) ) . '">' . __( 'Activate' ) . '</a>';
+
+ $actions['preview'] = '<a href="' . $preview_link . '" class="hide-if-customize" title="'
+ . esc_attr( sprintf( __( 'Preview &#8220;%s&#8221;' ), $title ) ) . '">' . __( 'Preview' ) . '</a>';
+
+ if ( current_user_can( 'edit_theme_options' ) )
+ $actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="load-customize hide-if-no-customize">'
+ . __( 'Live Preview' ) . '</a>';
+
+ if ( ! is_multisite() && current_user_can( 'delete_themes' ) )
+ $actions['delete'] = '<a class="submitdelete deletion" href="' . wp_nonce_url( 'themes.php?action=delete&amp;stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet )
+ . '" onclick="' . "return confirm( '" . esc_js( sprintf( __( "You are about to delete this theme '%s'\n 'Cancel' to stop, 'OK' to delete." ), $title ) )
+ . "' );" . '">' . __( 'Delete' ) . '</a>';
+
+ $actions = apply_filters( 'theme_action_links', $actions, $theme );
+ $delete_action = isset( $actions['delete'] ) ? '<div class="delete-theme">' . $actions['delete'] . '</div>' : '';
+ unset( $actions['delete'] );
+
+ ?>
+
+ <a href="<?php echo $preview_link; ?>" class="screenshot hide-if-customize">
+ <?php if ( $screenshot = $theme->get_screenshot() ) : ?>
+ <img src="<?php echo esc_url( $screenshot ); ?>" alt="" />
+ <?php endif; ?>
+ </a>
+ <a href="<?php echo wp_customize_url( $stylesheet ); ?>" class="screenshot load-customize hide-if-no-customize">
+ <?php if ( $screenshot = $theme->get_screenshot() ) : ?>
+ <img src="<?php echo esc_url( $screenshot ); ?>" alt="" />
+ <?php endif; ?>
+ </a>
+
+ <h3><?php echo $title; ?></h3>
+ <div class="theme-author"><?php printf( __( 'By %s' ), $author ); ?></div>
+ <div class="action-links">
+ <ul>
+ <?php foreach ( $actions as $action ): ?>
+ <li><?php echo $action; ?></li>
+ <?php endforeach; ?>
+ <li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e('Details') ?></a></li>
+ </ul>
+ <?php echo $delete_action; ?>
+
+ <?php theme_update_available( $theme ); ?>
+ </div>
+
+ <div class="themedetaildiv hide-if-js">
+ <p><strong><?php _e('Version: '); ?></strong><?php echo $version; ?></p>
+ <p><?php echo $theme->display('Description'); ?></p>
+ <?php if ( $theme->parent() ) {
+ printf( ' <p class="howto">' . __( 'This <a href="%1$s">child theme</a> requires its parent theme, %2$s.' ) . '</p>',
+ __( 'http://codex.wordpress.org/Child_Themes' ),
+ $theme->parent()->display( 'Name' ) );
+ } ?>
+ </div>
+
+ </div>
+ <?php
+ endforeach;
+ }
+
+ function search_theme( $theme ) {
+ // Search the features
+ foreach ( $this->features as $word ) {
+ if ( ! in_array( $word, $theme->get('Tags') ) )
+ return false;
+ }
+
+ // Match all phrases
+ foreach ( $this->search_terms as $word ) {
+ if ( in_array( $word, $theme->get('Tags') ) )
+ continue;
+
+ foreach ( array( 'Name', 'Description', 'Author', 'AuthorURI' ) as $header ) {
+ // Don't mark up; Do translate.
+ if ( false !== stripos( $theme->display( $header, false, true ), $word ) )
+ continue 2;
+ }
+
+ if ( false !== stripos( $theme->get_stylesheet(), $word ) )
+ continue;
+
+ if ( false !== stripos( $theme->get_template(), $word ) )
+ continue;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Send required variables to JavaScript land
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @uses $this->features Array of all feature search terms.
+ * @uses get_pagenum()
+ * @uses _pagination_args['total_pages']
+ */
+ function _js_vars( $extra_args = array() ) {
+ $search_string = isset( $_REQUEST['s'] ) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
+
+ $args = array(
+ 'search' => $search_string,
+ 'features' => $this->features,
+ 'paged' => $this->get_pagenum(),
+ 'total_pages' => ! empty( $this->_pagination_args['total_pages'] ) ? $this->_pagination_args['total_pages'] : 1,
+ );
+
+ if ( is_array( $extra_args ) )
+ $args = array_merge( $args, $extra_args );
+
+ printf( "<script type='text/javascript'>var theme_list_args = %s;</script>\n", json_encode( $args ) );
+ parent::_js_vars();
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-upgrader.php b/src/wp-admin/includes/class-wp-upgrader.php
new file mode 100644
index 0000000000..6c399c7ec0
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-upgrader.php
@@ -0,0 +1,1691 @@
+<?php
+/**
+ * A File upgrader class for WordPress.
+ *
+ * This set of classes are designed to be used to upgrade/install a local set of files on the filesystem via the Filesystem Abstraction classes.
+ *
+ * @link http://trac.wordpress.org/ticket/7875 consolidate plugin/theme/core upgrade/install functions
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+
+/**
+ * WordPress Upgrader class for Upgrading/Installing a local set of files via the Filesystem Abstraction classes from a Zip file.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class WP_Upgrader {
+ var $strings = array();
+ var $skin = null;
+ var $result = array();
+
+ function __construct($skin = null) {
+ if ( null == $skin )
+ $this->skin = new WP_Upgrader_Skin();
+ else
+ $this->skin = $skin;
+ }
+
+ function init() {
+ $this->skin->set_upgrader($this);
+ $this->generic_strings();
+ }
+
+ function generic_strings() {
+ $this->strings['bad_request'] = __('Invalid Data provided.');
+ $this->strings['fs_unavailable'] = __('Could not access filesystem.');
+ $this->strings['fs_error'] = __('Filesystem error.');
+ $this->strings['fs_no_root_dir'] = __('Unable to locate WordPress Root directory.');
+ $this->strings['fs_no_content_dir'] = __('Unable to locate WordPress Content directory (wp-content).');
+ $this->strings['fs_no_plugins_dir'] = __('Unable to locate WordPress Plugin directory.');
+ $this->strings['fs_no_themes_dir'] = __('Unable to locate WordPress Theme directory.');
+ /* translators: %s: directory name */
+ $this->strings['fs_no_folder'] = __('Unable to locate needed folder (%s).');
+
+ $this->strings['download_failed'] = __('Download failed.');
+ $this->strings['installing_package'] = __('Installing the latest version&#8230;');
+ $this->strings['no_files'] = __('The package contains no files.');
+ $this->strings['folder_exists'] = __('Destination folder already exists.');
+ $this->strings['mkdir_failed'] = __('Could not create directory.');
+ $this->strings['incompatible_archive'] = __('The package could not be installed.');
+
+ $this->strings['maintenance_start'] = __('Enabling Maintenance mode&#8230;');
+ $this->strings['maintenance_end'] = __('Disabling Maintenance mode&#8230;');
+ }
+
+ function fs_connect( $directories = array() ) {
+ global $wp_filesystem;
+
+ if ( false === ($credentials = $this->skin->request_filesystem_credentials()) )
+ return false;
+
+ if ( ! WP_Filesystem($credentials) ) {
+ $error = true;
+ if ( is_object($wp_filesystem) && $wp_filesystem->errors->get_error_code() )
+ $error = $wp_filesystem->errors;
+ $this->skin->request_filesystem_credentials($error); //Failed to connect, Error and request again
+ return false;
+ }
+
+ if ( ! is_object($wp_filesystem) )
+ return new WP_Error('fs_unavailable', $this->strings['fs_unavailable'] );
+
+ if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
+ return new WP_Error('fs_error', $this->strings['fs_error'], $wp_filesystem->errors);
+
+ foreach ( (array)$directories as $dir ) {
+ switch ( $dir ) {
+ case ABSPATH:
+ if ( ! $wp_filesystem->abspath() )
+ return new WP_Error('fs_no_root_dir', $this->strings['fs_no_root_dir']);
+ break;
+ case WP_CONTENT_DIR:
+ if ( ! $wp_filesystem->wp_content_dir() )
+ return new WP_Error('fs_no_content_dir', $this->strings['fs_no_content_dir']);
+ break;
+ case WP_PLUGIN_DIR:
+ if ( ! $wp_filesystem->wp_plugins_dir() )
+ return new WP_Error('fs_no_plugins_dir', $this->strings['fs_no_plugins_dir']);
+ break;
+ case WP_CONTENT_DIR . '/themes':
+ if ( ! $wp_filesystem->find_folder(WP_CONTENT_DIR . '/themes') )
+ return new WP_Error('fs_no_themes_dir', $this->strings['fs_no_themes_dir']);
+ break;
+ default:
+ if ( ! $wp_filesystem->find_folder($dir) )
+ return new WP_Error( 'fs_no_folder', sprintf( $this->strings['fs_no_folder'], esc_html( basename( $dir ) ) ) );
+ break;
+ }
+ }
+ return true;
+ } //end fs_connect();
+
+ function download_package($package) {
+
+ if ( ! preg_match('!^(http|https|ftp)://!i', $package) && file_exists($package) ) //Local file or remote?
+ return $package; //must be a local file..
+
+ if ( empty($package) )
+ return new WP_Error('no_package', $this->strings['no_package']);
+
+ $this->skin->feedback('downloading_package', $package);
+
+ $download_file = download_url($package);
+
+ if ( is_wp_error($download_file) )
+ return new WP_Error('download_failed', $this->strings['download_failed'], $download_file->get_error_message());
+
+ return $download_file;
+ }
+
+ function unpack_package($package, $delete_package = true) {
+ global $wp_filesystem;
+
+ $this->skin->feedback('unpack_package');
+
+ $upgrade_folder = $wp_filesystem->wp_content_dir() . 'upgrade/';
+
+ //Clean up contents of upgrade directory beforehand.
+ $upgrade_files = $wp_filesystem->dirlist($upgrade_folder);
+ if ( !empty($upgrade_files) ) {
+ foreach ( $upgrade_files as $file )
+ $wp_filesystem->delete($upgrade_folder . $file['name'], true);
+ }
+
+ //We need a working directory
+ $working_dir = $upgrade_folder . basename($package, '.zip');
+
+ // Clean up working directory
+ if ( $wp_filesystem->is_dir($working_dir) )
+ $wp_filesystem->delete($working_dir, true);
+
+ // Unzip package to working directory
+ $result = unzip_file($package, $working_dir); //TODO optimizations, Copy when Move/Rename would suffice?
+
+ // Once extracted, delete the package if required.
+ if ( $delete_package )
+ unlink($package);
+
+ if ( is_wp_error($result) ) {
+ $wp_filesystem->delete($working_dir, true);
+ if ( 'incompatible_archive' == $result->get_error_code() ) {
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $result->get_error_data() );
+ }
+ return $result;
+ }
+
+ return $working_dir;
+ }
+
+ function install_package($args = array()) {
+ global $wp_filesystem;
+ $defaults = array( 'source' => '', 'destination' => '', //Please always pass these
+ 'clear_destination' => false, 'clear_working' => false,
+ 'abort_if_destination_exists' => true,
+ 'hook_extra' => array());
+
+ $args = wp_parse_args($args, $defaults);
+ extract($args);
+
+ @set_time_limit( 300 );
+
+ if ( empty($source) || empty($destination) )
+ return new WP_Error('bad_request', $this->strings['bad_request']);
+
+ $this->skin->feedback('installing_package');
+
+ $res = apply_filters('upgrader_pre_install', true, $hook_extra);
+ if ( is_wp_error($res) )
+ return $res;
+
+ //Retain the Original source and destinations
+ $remote_source = $source;
+ $local_destination = $destination;
+
+ $source_files = array_keys( $wp_filesystem->dirlist($remote_source) );
+ $remote_destination = $wp_filesystem->find_folder($local_destination);
+
+ //Locate which directory to copy to the new folder, This is based on the actual folder holding the files.
+ if ( 1 == count($source_files) && $wp_filesystem->is_dir( trailingslashit($source) . $source_files[0] . '/') ) //Only one folder? Then we want its contents.
+ $source = trailingslashit($source) . trailingslashit($source_files[0]);
+ elseif ( count($source_files) == 0 )
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], $this->strings['no_files'] ); //There are no files?
+ else //It's only a single file, the upgrader will use the foldername of this file as the destination folder. foldername is based on zip filename.
+ $source = trailingslashit($source);
+
+ //Hook ability to change the source file location..
+ $source = apply_filters('upgrader_source_selection', $source, $remote_source, $this);
+ if ( is_wp_error($source) )
+ return $source;
+
+ //Has the source location changed? If so, we need a new source_files list.
+ if ( $source !== $remote_source )
+ $source_files = array_keys( $wp_filesystem->dirlist($source) );
+
+ //Protection against deleting files in any important base directories.
+ if ( in_array( $destination, array(ABSPATH, WP_CONTENT_DIR, WP_PLUGIN_DIR, WP_CONTENT_DIR . '/themes') ) ) {
+ $remote_destination = trailingslashit($remote_destination) . trailingslashit(basename($source));
+ $destination = trailingslashit($destination) . trailingslashit(basename($source));
+ }
+
+ if ( $clear_destination ) {
+ //We're going to clear the destination if there's something there
+ $this->skin->feedback('remove_old');
+ $removed = true;
+ if ( $wp_filesystem->exists($remote_destination) )
+ $removed = $wp_filesystem->delete($remote_destination, true);
+ $removed = apply_filters('upgrader_clear_destination', $removed, $local_destination, $remote_destination, $hook_extra);
+
+ if ( is_wp_error($removed) )
+ return $removed;
+ else if ( ! $removed )
+ return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);
+ } elseif ( $abort_if_destination_exists && $wp_filesystem->exists($remote_destination) ) {
+ //If we're not clearing the destination folder and something exists there already, Bail.
+ //But first check to see if there are actually any files in the folder.
+ $_files = $wp_filesystem->dirlist($remote_destination);
+ if ( ! empty($_files) ) {
+ $wp_filesystem->delete($remote_source, true); //Clear out the source files.
+ return new WP_Error('folder_exists', $this->strings['folder_exists'], $remote_destination );
+ }
+ }
+
+ //Create destination if needed
+ if ( !$wp_filesystem->exists($remote_destination) )
+ if ( !$wp_filesystem->mkdir($remote_destination, FS_CHMOD_DIR) )
+ return new WP_Error('mkdir_failed', $this->strings['mkdir_failed'], $remote_destination);
+
+ // Copy new version of item into place.
+ $result = copy_dir($source, $remote_destination);
+ if ( is_wp_error($result) ) {
+ if ( $clear_working )
+ $wp_filesystem->delete($remote_source, true);
+ return $result;
+ }
+
+ //Clear the Working folder?
+ if ( $clear_working )
+ $wp_filesystem->delete($remote_source, true);
+
+ $destination_name = basename( str_replace($local_destination, '', $destination) );
+ if ( '.' == $destination_name )
+ $destination_name = '';
+
+ $this->result = compact('local_source', 'source', 'source_name', 'source_files', 'destination', 'destination_name', 'local_destination', 'remote_destination', 'clear_destination', 'delete_source_dir');
+
+ $res = apply_filters('upgrader_post_install', true, $hook_extra, $this->result);
+ if ( is_wp_error($res) ) {
+ $this->result = $res;
+ return $res;
+ }
+
+ //Bombard the calling function will all the info which we've just used.
+ return $this->result;
+ }
+
+ function run($options) {
+
+ $defaults = array( 'package' => '', //Please always pass this.
+ 'destination' => '', //And this
+ 'clear_destination' => false,
+ 'abort_if_destination_exists' => true, // Abort if the Destination directory exists, Pass clear_destination as false please
+ 'clear_working' => true,
+ 'is_multi' => false,
+ 'hook_extra' => array() //Pass any extra $hook_extra args here, this will be passed to any hooked filters.
+ );
+
+ $options = wp_parse_args($options, $defaults);
+ extract($options);
+
+ //Connect to the Filesystem first.
+ $res = $this->fs_connect( array(WP_CONTENT_DIR, $destination) );
+ if ( ! $res ) //Mainly for non-connected filesystem.
+ return false;
+
+ if ( is_wp_error($res) ) {
+ $this->skin->error($res);
+ return $res;
+ }
+
+ if ( !$is_multi ) // call $this->header separately if running multiple times
+ $this->skin->header();
+
+ $this->skin->before();
+
+ //Download the package (Note, This just returns the filename of the file if the package is a local file)
+ $download = $this->download_package( $package );
+ if ( is_wp_error($download) ) {
+ $this->skin->error($download);
+ $this->skin->after();
+ return $download;
+ }
+
+ $delete_package = ($download != $package); // Do not delete a "local" file
+
+ //Unzips the file into a temporary directory
+ $working_dir = $this->unpack_package( $download, $delete_package );
+ if ( is_wp_error($working_dir) ) {
+ $this->skin->error($working_dir);
+ $this->skin->after();
+ return $working_dir;
+ }
+
+ //With the given options, this installs it to the destination directory.
+ $result = $this->install_package( array(
+ 'source' => $working_dir,
+ 'destination' => $destination,
+ 'clear_destination' => $clear_destination,
+ 'abort_if_destination_exists' => $abort_if_destination_exists,
+ 'clear_working' => $clear_working,
+ 'hook_extra' => $hook_extra
+ ) );
+ $this->skin->set_result($result);
+ if ( is_wp_error($result) ) {
+ $this->skin->error($result);
+ $this->skin->feedback('process_failed');
+ } else {
+ //Install Succeeded
+ $this->skin->feedback('process_success');
+ }
+ $this->skin->after();
+
+ if ( !$is_multi )
+ $this->skin->footer();
+
+ return $result;
+ }
+
+ function maintenance_mode($enable = false) {
+ global $wp_filesystem;
+ $file = $wp_filesystem->abspath() . '.maintenance';
+ if ( $enable ) {
+ $this->skin->feedback('maintenance_start');
+ // Create maintenance file to signal that we are upgrading
+ $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
+ $wp_filesystem->delete($file);
+ $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE);
+ } else if ( !$enable && $wp_filesystem->exists($file) ) {
+ $this->skin->feedback('maintenance_end');
+ $wp_filesystem->delete($file);
+ }
+ }
+
+}
+
+/**
+ * Plugin Upgrader class for WordPress Plugins, It is designed to upgrade/install plugins from a local zip, remote zip URL, or uploaded zip file.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Plugin_Upgrader extends WP_Upgrader {
+
+ var $result;
+ var $bulk = false;
+ var $show_before = '';
+
+ function upgrade_strings() {
+ $this->strings['up_to_date'] = __('The plugin is at the latest version.');
+ $this->strings['no_package'] = __('Update package not available.');
+ $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
+ $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
+ $this->strings['remove_old'] = __('Removing the old version of the plugin&#8230;');
+ $this->strings['remove_old_failed'] = __('Could not remove the old plugin.');
+ $this->strings['process_failed'] = __('Plugin update failed.');
+ $this->strings['process_success'] = __('Plugin updated successfully.');
+ }
+
+ function install_strings() {
+ $this->strings['no_package'] = __('Install package not available.');
+ $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>&#8230;');
+ $this->strings['unpack_package'] = __('Unpacking the package&#8230;');
+ $this->strings['installing_package'] = __('Installing the plugin&#8230;');
+ $this->strings['no_files'] = __('The plugin contains no files.');
+ $this->strings['process_failed'] = __('Plugin install failed.');
+ $this->strings['process_success'] = __('Plugin installed successfully.');
+ }
+
+ function install($package) {
+
+ $this->init();
+ $this->install_strings();
+
+ add_filter('upgrader_source_selection', array(&$this, 'check_package') );
+
+ $this->run(array(
+ 'package' => $package,
+ 'destination' => WP_PLUGIN_DIR,
+ 'clear_destination' => false, //Do not overwrite files.
+ 'clear_working' => true,
+ 'hook_extra' => array()
+ ));
+
+ remove_filter('upgrader_source_selection', array(&$this, 'check_package') );
+
+ if ( ! $this->result || is_wp_error($this->result) )
+ return $this->result;
+
+ // Force refresh of plugin update information
+ delete_site_transient('update_plugins');
+ wp_cache_delete( 'plugins', 'plugins' );
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'install', 'type' => 'plugin' ), $package );
+
+ return true;
+ }
+
+ function upgrade($plugin) {
+
+ $this->init();
+ $this->upgrade_strings();
+
+ $current = get_site_transient( 'update_plugins' );
+ if ( !isset( $current->response[ $plugin ] ) ) {
+ $this->skin->before();
+ $this->skin->set_result(false);
+ $this->skin->error('up_to_date');
+ $this->skin->after();
+ return false;
+ }
+
+ // Get the URL to the zip file
+ $r = $current->response[ $plugin ];
+
+ add_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'), 10, 2);
+ add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4);
+ //'source_selection' => array(&$this, 'source_selection'), //there's a trac ticket to move up the directory for zip's which are made a bit differently, useful for non-.org plugins.
+
+ $this->run(array(
+ 'package' => $r->package,
+ 'destination' => WP_PLUGIN_DIR,
+ 'clear_destination' => true,
+ 'clear_working' => true,
+ 'hook_extra' => array(
+ 'plugin' => $plugin
+ )
+ ));
+
+ // Cleanup our hooks, in case something else does a upgrade on this connection.
+ remove_filter('upgrader_pre_install', array(&$this, 'deactivate_plugin_before_upgrade'));
+ remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'));
+
+ if ( ! $this->result || is_wp_error($this->result) )
+ return $this->result;
+
+ // Force refresh of plugin update information
+ delete_site_transient('update_plugins');
+ wp_cache_delete( 'plugins', 'plugins' );
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'plugin' ), $plugin );
+ }
+
+ function bulk_upgrade($plugins) {
+
+ $this->init();
+ $this->bulk = true;
+ $this->upgrade_strings();
+
+ $current = get_site_transient( 'update_plugins' );
+
+ add_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'), 10, 4);
+
+ $this->skin->header();
+
+ // Connect to the Filesystem first.
+ $res = $this->fs_connect( array(WP_CONTENT_DIR, WP_PLUGIN_DIR) );
+ if ( ! $res ) {
+ $this->skin->footer();
+ return false;
+ }
+
+ $this->skin->bulk_header();
+
+ // Only start maintenance mode if running in Multisite OR the plugin is in use
+ $maintenance = is_multisite(); // @TODO: This should only kick in for individual sites if at all possible.
+ foreach ( $plugins as $plugin )
+ $maintenance = $maintenance || (is_plugin_active($plugin) && isset($current->response[ $plugin ]) ); // Only activate Maintenance mode if a plugin is active AND has an update available
+ if ( $maintenance )
+ $this->maintenance_mode(true);
+
+ $results = array();
+
+ $this->update_count = count($plugins);
+ $this->update_current = 0;
+ foreach ( $plugins as $plugin ) {
+ $this->update_current++;
+ $this->skin->plugin_info = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin, false, true);
+
+ if ( !isset( $current->response[ $plugin ] ) ) {
+ $this->skin->set_result(true);
+ $this->skin->before();
+ $this->skin->feedback('up_to_date');
+ $this->skin->after();
+ $results[$plugin] = true;
+ continue;
+ }
+
+ // Get the URL to the zip file
+ $r = $current->response[ $plugin ];
+
+ $this->skin->plugin_active = is_plugin_active($plugin);
+
+ $result = $this->run(array(
+ 'package' => $r->package,
+ 'destination' => WP_PLUGIN_DIR,
+ 'clear_destination' => true,
+ 'clear_working' => true,
+ 'is_multi' => true,
+ 'hook_extra' => array(
+ 'plugin' => $plugin
+ )
+ ));
+
+ $results[$plugin] = $this->result;
+
+ // Prevent credentials auth screen from displaying multiple times
+ if ( false === $result )
+ break;
+ } //end foreach $plugins
+
+ $this->maintenance_mode(false);
+
+ $this->skin->bulk_footer();
+
+ $this->skin->footer();
+
+ // Cleanup our hooks, in case something else does a upgrade on this connection.
+ remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_plugin'));
+
+ // Force refresh of plugin update information
+ delete_site_transient('update_plugins');
+ wp_cache_delete( 'plugins', 'plugins' );
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'plugin', 'bulk' => true ), $plugins );
+
+ return $results;
+ }
+
+ function check_package($source) {
+ global $wp_filesystem;
+
+ if ( is_wp_error($source) )
+ return $source;
+
+ $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source);
+ if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation.
+ return $source;
+
+ // Check the folder contains at least 1 valid plugin.
+ $plugins_found = false;
+ foreach ( glob( $working_directory . '*.php' ) as $file ) {
+ $info = get_plugin_data($file, false, false);
+ if ( !empty( $info['Name'] ) ) {
+ $plugins_found = true;
+ break;
+ }
+ }
+
+ if ( ! $plugins_found )
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __('No valid plugins were found.') );
+
+ return $source;
+ }
+
+ //return plugin info.
+ function plugin_info() {
+ if ( ! is_array($this->result) )
+ return false;
+ if ( empty($this->result['destination_name']) )
+ return false;
+
+ $plugin = get_plugins('/' . $this->result['destination_name']); //Ensure to pass with leading slash
+ if ( empty($plugin) )
+ return false;
+
+ $pluginfiles = array_keys($plugin); //Assume the requested plugin is the first in the list
+
+ return $this->result['destination_name'] . '/' . $pluginfiles[0];
+ }
+
+ //Hooked to pre_install
+ function deactivate_plugin_before_upgrade($return, $plugin) {
+
+ if ( is_wp_error($return) ) //Bypass.
+ return $return;
+
+ $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
+ if ( empty($plugin) )
+ return new WP_Error('bad_request', $this->strings['bad_request']);
+
+ if ( is_plugin_active($plugin) ) {
+ //Deactivate the plugin silently, Prevent deactivation hooks from running.
+ deactivate_plugins($plugin, true);
+ }
+ }
+
+ //Hooked to upgrade_clear_destination
+ function delete_old_plugin($removed, $local_destination, $remote_destination, $plugin) {
+ global $wp_filesystem;
+
+ if ( is_wp_error($removed) )
+ return $removed; //Pass errors through.
+
+ $plugin = isset($plugin['plugin']) ? $plugin['plugin'] : '';
+ if ( empty($plugin) )
+ return new WP_Error('bad_request', $this->strings['bad_request']);
+
+ $plugins_dir = $wp_filesystem->wp_plugins_dir();
+ $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin) );
+
+ if ( ! $wp_filesystem->exists($this_plugin_dir) ) //If it's already vanished.
+ return $removed;
+
+ // If plugin is in its own directory, recursively delete the directory.
+ if ( strpos($plugin, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory separator AND that it's not the root plugin folder
+ $deleted = $wp_filesystem->delete($this_plugin_dir, true);
+ else
+ $deleted = $wp_filesystem->delete($plugins_dir . $plugin);
+
+ if ( ! $deleted )
+ return new WP_Error('remove_old_failed', $this->strings['remove_old_failed']);
+
+ return true;
+ }
+}
+
+/**
+ * Theme Upgrader class for WordPress Themes, It is designed to upgrade/install themes from a local zip, remote zip URL, or uploaded zip file.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Theme_Upgrader extends WP_Upgrader {
+
+ var $result;
+ var $bulk = false;
+
+ function upgrade_strings() {
+ $this->strings['up_to_date'] = __('The theme is at the latest version.');
+ $this->strings['no_package'] = __('Update package not available.');
+ $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
+ $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
+ $this->strings['remove_old'] = __('Removing the old version of the theme&#8230;');
+ $this->strings['remove_old_failed'] = __('Could not remove the old theme.');
+ $this->strings['process_failed'] = __('Theme update failed.');
+ $this->strings['process_success'] = __('Theme updated successfully.');
+ }
+
+ function install_strings() {
+ $this->strings['no_package'] = __('Install package not available.');
+ $this->strings['downloading_package'] = __('Downloading install package from <span class="code">%s</span>&#8230;');
+ $this->strings['unpack_package'] = __('Unpacking the package&#8230;');
+ $this->strings['installing_package'] = __('Installing the theme&#8230;');
+ $this->strings['no_files'] = __('The theme contains no files.');
+ $this->strings['process_failed'] = __('Theme install failed.');
+ $this->strings['process_success'] = __('Theme installed successfully.');
+ /* translators: 1: theme name, 2: version */
+ $this->strings['process_success_specific'] = __('Successfully installed the theme <strong>%1$s %2$s</strong>.');
+ $this->strings['parent_theme_search'] = __('This theme requires a parent theme. Checking if it is installed&#8230;');
+ /* translators: 1: theme name, 2: version */
+ $this->strings['parent_theme_prepare_install'] = __('Preparing to install <strong>%1$s %2$s</strong>&#8230;');
+ /* translators: 1: theme name, 2: version */
+ $this->strings['parent_theme_currently_installed'] = __('The parent theme, <strong>%1$s %2$s</strong>, is currently installed.');
+ /* translators: 1: theme name, 2: version */
+ $this->strings['parent_theme_install_success'] = __('Successfully installed the parent theme, <strong>%1$s %2$s</strong>.');
+ $this->strings['parent_theme_not_found'] = __('<strong>The parent theme could not be found.</strong> You will need to install the parent theme, <strong>%s</strong>, before you can use this child theme.');
+ }
+
+ function check_parent_theme_filter($install_result, $hook_extra, $child_result) {
+ // Check to see if we need to install a parent theme
+ $theme_info = $this->theme_info();
+
+ if ( ! $theme_info->parent() )
+ return $install_result;
+
+ $this->skin->feedback( 'parent_theme_search' );
+
+ if ( ! $theme_info->parent()->errors() ) {
+ $this->skin->feedback( 'parent_theme_currently_installed', $theme_info->parent()->display('Name'), $theme_info->parent()->display('Version') );
+ // We already have the theme, fall through.
+ return $install_result;
+ }
+
+ // We don't have the parent theme, lets install it
+ $api = themes_api('theme_information', array('slug' => $theme_info->get('Template'), 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
+
+ if ( ! $api || is_wp_error($api) ) {
+ $this->skin->feedback( 'parent_theme_not_found', $theme_info->get('Template') );
+ // Don't show activate or preview actions after install
+ add_filter('install_theme_complete_actions', array(&$this, 'hide_activate_preview_actions') );
+ return $install_result;
+ }
+
+ // Backup required data we're going to override:
+ $child_api = $this->skin->api;
+ $child_success_message = $this->strings['process_success'];
+
+ // Override them
+ $this->skin->api = $api;
+ $this->strings['process_success_specific'] = $this->strings['parent_theme_install_success'];//, $api->name, $api->version);
+
+ $this->skin->feedback('parent_theme_prepare_install', $api->name, $api->version);
+
+ add_filter('install_theme_complete_actions', '__return_false', 999); // Don't show any actions after installing the theme.
+
+ // Install the parent theme
+ $parent_result = $this->run( array(
+ 'package' => $api->download_link,
+ 'destination' => WP_CONTENT_DIR . '/themes',
+ 'clear_destination' => false, //Do not overwrite files.
+ 'clear_working' => true
+ ) );
+
+ if ( is_wp_error($parent_result) )
+ add_filter('install_theme_complete_actions', array(&$this, 'hide_activate_preview_actions') );
+
+ // Start cleaning up after the parents installation
+ remove_filter('install_theme_complete_actions', '__return_false', 999);
+
+ // Reset child's result and data
+ $this->result = $child_result;
+ $this->skin->api = $child_api;
+ $this->strings['process_success'] = $child_success_message;
+
+ return $install_result;
+ }
+
+ function hide_activate_preview_actions($actions) {
+ unset($actions['activate'], $actions['preview']);
+ return $actions;
+ }
+
+ function install($package) {
+
+ $this->init();
+ $this->install_strings();
+
+ add_filter('upgrader_source_selection', array(&$this, 'check_package') );
+ add_filter('upgrader_post_install', array(&$this, 'check_parent_theme_filter'), 10, 3);
+
+ $options = array(
+ 'package' => $package,
+ 'destination' => WP_CONTENT_DIR . '/themes',
+ 'clear_destination' => false, //Do not overwrite files.
+ 'clear_working' => true
+ );
+
+ $this->run($options);
+
+ remove_filter('upgrader_source_selection', array(&$this, 'check_package') );
+ remove_filter('upgrader_post_install', array(&$this, 'check_parent_theme_filter'));
+
+ if ( ! $this->result || is_wp_error($this->result) )
+ return $this->result;
+
+ // Force refresh of theme update information
+ wp_clean_themes_cache();
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'install', 'type' => 'theme' ), $package );
+
+ return true;
+ }
+
+ function upgrade($theme) {
+
+ $this->init();
+ $this->upgrade_strings();
+
+ // Is an update available?
+ $current = get_site_transient( 'update_themes' );
+ if ( !isset( $current->response[ $theme ] ) ) {
+ $this->skin->before();
+ $this->skin->set_result(false);
+ $this->skin->error('up_to_date');
+ $this->skin->after();
+ return false;
+ }
+
+ $r = $current->response[ $theme ];
+
+ add_filter('upgrader_pre_install', array(&$this, 'current_before'), 10, 2);
+ add_filter('upgrader_post_install', array(&$this, 'current_after'), 10, 2);
+ add_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'), 10, 4);
+
+ $options = array(
+ 'package' => $r['package'],
+ 'destination' => WP_CONTENT_DIR . '/themes',
+ 'clear_destination' => true,
+ 'clear_working' => true,
+ 'hook_extra' => array(
+ 'theme' => $theme
+ )
+ );
+
+ $this->run($options);
+
+ remove_filter('upgrader_pre_install', array(&$this, 'current_before'));
+ remove_filter('upgrader_post_install', array(&$this, 'current_after'));
+ remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'));
+
+ if ( ! $this->result || is_wp_error($this->result) )
+ return $this->result;
+
+ // Force refresh of theme update information
+ wp_clean_themes_cache();
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'theme' ), $theme );
+
+ return true;
+ }
+
+ function bulk_upgrade($themes) {
+
+ $this->init();
+ $this->bulk = true;
+ $this->upgrade_strings();
+
+ $current = get_site_transient( 'update_themes' );
+
+ add_filter('upgrader_pre_install', array(&$this, 'current_before'), 10, 2);
+ add_filter('upgrader_post_install', array(&$this, 'current_after'), 10, 2);
+ add_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'), 10, 4);
+
+ $this->skin->header();
+
+ // Connect to the Filesystem first.
+ $res = $this->fs_connect( array(WP_CONTENT_DIR) );
+ if ( ! $res ) {
+ $this->skin->footer();
+ return false;
+ }
+
+ $this->skin->bulk_header();
+
+ // Only start maintenance mode if running in Multisite OR the theme is in use
+ $maintenance = is_multisite(); // @TODO: This should only kick in for individual sites if at all possible.
+ foreach ( $themes as $theme )
+ $maintenance = $maintenance || $theme == get_stylesheet() || $theme == get_template();
+ if ( $maintenance )
+ $this->maintenance_mode(true);
+
+ $results = array();
+
+ $this->update_count = count($themes);
+ $this->update_current = 0;
+ foreach ( $themes as $theme ) {
+ $this->update_current++;
+
+ $this->skin->theme_info = $this->theme_info($theme);
+
+ if ( !isset( $current->response[ $theme ] ) ) {
+ $this->skin->set_result(true);
+ $this->skin->before();
+ $this->skin->feedback('up_to_date');
+ $this->skin->after();
+ $results[$theme] = true;
+ continue;
+ }
+
+ // Get the URL to the zip file
+ $r = $current->response[ $theme ];
+
+ $options = array(
+ 'package' => $r['package'],
+ 'destination' => WP_CONTENT_DIR . '/themes',
+ 'clear_destination' => true,
+ 'clear_working' => true,
+ 'hook_extra' => array(
+ 'theme' => $theme
+ )
+ );
+
+ $result = $this->run($options);
+
+ $results[$theme] = $this->result;
+
+ // Prevent credentials auth screen from displaying multiple times
+ if ( false === $result )
+ break;
+ } //end foreach $plugins
+
+ $this->maintenance_mode(false);
+
+ $this->skin->bulk_footer();
+
+ $this->skin->footer();
+
+ // Cleanup our hooks, in case something else does a upgrade on this connection.
+ remove_filter('upgrader_pre_install', array(&$this, 'current_before'));
+ remove_filter('upgrader_post_install', array(&$this, 'current_after'));
+ remove_filter('upgrader_clear_destination', array(&$this, 'delete_old_theme'));
+
+ // Force refresh of theme update information
+ wp_clean_themes_cache();
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'theme', 'bulk' => true ), $themes );
+
+ return $results;
+ }
+
+ function check_package($source) {
+ global $wp_filesystem;
+
+ if ( is_wp_error($source) )
+ return $source;
+
+ // Check the folder contains a valid theme
+ $working_directory = str_replace( $wp_filesystem->wp_content_dir(), trailingslashit(WP_CONTENT_DIR), $source);
+ if ( ! is_dir($working_directory) ) // Sanity check, if the above fails, lets not prevent installation.
+ return $source;
+
+ // A proper archive should have a style.css file in the single subdirectory
+ if ( ! file_exists( $working_directory . 'style.css' ) )
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __('The theme is missing the <code>style.css</code> stylesheet.') );
+
+ $info = get_file_data( $working_directory . 'style.css', array( 'Name' => 'Theme Name', 'Template' => 'Template' ) );
+
+ if ( empty( $info['Name'] ) )
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __("The <code>style.css</code> stylesheet doesn't contain a valid theme header.") );
+
+ // If it's not a child theme, it must have at least an index.php to be legit.
+ if ( empty( $info['Template'] ) && ! file_exists( $working_directory . 'index.php' ) )
+ return new WP_Error( 'incompatible_archive', $this->strings['incompatible_archive'], __('The theme is missing the <code>index.php</code> file.') );
+
+ return $source;
+ }
+
+ function current_before($return, $theme) {
+
+ if ( is_wp_error($return) )
+ return $return;
+
+ $theme = isset($theme['theme']) ? $theme['theme'] : '';
+
+ if ( $theme != get_stylesheet() ) //If not current
+ return $return;
+ //Change to maintenance mode now.
+ if ( ! $this->bulk )
+ $this->maintenance_mode(true);
+
+ return $return;
+ }
+
+ function current_after($return, $theme) {
+ if ( is_wp_error($return) )
+ return $return;
+
+ $theme = isset($theme['theme']) ? $theme['theme'] : '';
+
+ if ( $theme != get_stylesheet() ) // If not current
+ return $return;
+
+ // Ensure stylesheet name hasn't changed after the upgrade:
+ if ( $theme == get_stylesheet() && $theme != $this->result['destination_name'] ) {
+ wp_clean_themes_cache();
+ $stylesheet = $this->result['destination_name'];
+ switch_theme( $stylesheet );
+ }
+
+ //Time to remove maintenance mode
+ if ( ! $this->bulk )
+ $this->maintenance_mode(false);
+ return $return;
+ }
+
+ function delete_old_theme($removed, $local_destination, $remote_destination, $theme) {
+ global $wp_filesystem;
+
+ $theme = isset($theme['theme']) ? $theme['theme'] : '';
+
+ if ( is_wp_error($removed) || empty($theme) )
+ return $removed; //Pass errors through.
+
+ $themes_dir = $wp_filesystem->wp_themes_dir();
+ if ( $wp_filesystem->exists( trailingslashit($themes_dir) . $theme ) )
+ if ( ! $wp_filesystem->delete( trailingslashit($themes_dir) . $theme, true ) )
+ return false;
+ return true;
+ }
+
+ function theme_info($theme = null) {
+
+ if ( empty($theme) ) {
+ if ( !empty($this->result['destination_name']) )
+ $theme = $this->result['destination_name'];
+ else
+ return false;
+ }
+ return wp_get_theme( $theme, WP_CONTENT_DIR . '/themes/' );
+ }
+
+}
+
+/**
+ * Core Upgrader class for WordPress. It allows for WordPress to upgrade itself in combination with the wp-admin/includes/update-core.php file
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Core_Upgrader extends WP_Upgrader {
+
+ function upgrade_strings() {
+ $this->strings['up_to_date'] = __('WordPress is at the latest version.');
+ $this->strings['no_package'] = __('Update package not available.');
+ $this->strings['downloading_package'] = __('Downloading update from <span class="code">%s</span>&#8230;');
+ $this->strings['unpack_package'] = __('Unpacking the update&#8230;');
+ $this->strings['copy_failed'] = __('Could not copy files.');
+ $this->strings['copy_failed_space'] = __('Could not copy files. You may have run out of disk space.' );
+ }
+
+ function upgrade($current) {
+ global $wp_filesystem, $wp_version;
+
+ $this->init();
+ $this->upgrade_strings();
+
+ // Is an update available?
+ if ( !isset( $current->response ) || $current->response == 'latest' )
+ return new WP_Error('up_to_date', $this->strings['up_to_date']);
+
+ $res = $this->fs_connect( array(ABSPATH, WP_CONTENT_DIR) );
+ if ( is_wp_error($res) )
+ return $res;
+
+ $wp_dir = trailingslashit($wp_filesystem->abspath());
+
+ // If partial update is returned from the API, use that, unless we're doing a reinstall.
+ // If we cross the new_bundled version number, then use the new_bundled zip.
+ // Don't though if the constant is set to skip bundled items.
+ // If the API returns a no_content zip, go with it. Finally, default to the full zip.
+ if ( $current->packages->partial && 'reinstall' != $current->response && $wp_version == $current->partial_version )
+ $to_download = 'partial';
+ elseif ( $current->packages->new_bundled && version_compare( $wp_version, $current->new_bundled, '<' )
+ && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) )
+ $to_download = 'new_bundled';
+ elseif ( $current->packages->no_content )
+ $to_download = 'no_content';
+ else
+ $to_download = 'full';
+
+ $download = $this->download_package( $current->packages->$to_download );
+ if ( is_wp_error($download) )
+ return $download;
+
+ $working_dir = $this->unpack_package( $download );
+ if ( is_wp_error($working_dir) )
+ return $working_dir;
+
+ // Copy update-core.php from the new version into place.
+ if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) {
+ $wp_filesystem->delete($working_dir, true);
+ return new WP_Error('copy_failed', $this->strings['copy_failed']);
+ }
+ $wp_filesystem->chmod($wp_dir . 'wp-admin/includes/update-core.php', FS_CHMOD_FILE);
+
+ require(ABSPATH . 'wp-admin/includes/update-core.php');
+
+ if ( ! function_exists( 'update_core' ) )
+ return new WP_Error( 'copy_failed_space', $this->strings['copy_failed_space'] );
+
+ $result = update_core( $working_dir, $wp_dir );
+ do_action( 'upgrader_process_complete', $this, array( 'action' => 'update', 'type' => 'core' ), $result );
+ return $result;
+ }
+
+}
+
+/**
+ * Generic Skin for the WordPress Upgrader classes. This skin is designed to be extended for specific purposes.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class WP_Upgrader_Skin {
+
+ var $upgrader;
+ var $done_header = false;
+ var $result = false;
+
+ function __construct($args = array()) {
+ $defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false );
+ $this->options = wp_parse_args($args, $defaults);
+ }
+
+ function set_upgrader(&$upgrader) {
+ if ( is_object($upgrader) )
+ $this->upgrader =& $upgrader;
+ $this->add_strings();
+ }
+
+ function add_strings() {
+ }
+
+ function set_result($result) {
+ $this->result = $result;
+ }
+
+ function request_filesystem_credentials($error = false) {
+ $url = $this->options['url'];
+ $context = $this->options['context'];
+ if ( !empty($this->options['nonce']) )
+ $url = wp_nonce_url($url, $this->options['nonce']);
+ return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now.
+ }
+
+ function header() {
+ if ( $this->done_header )
+ return;
+ $this->done_header = true;
+ echo '<div class="wrap">';
+ screen_icon();
+ echo '<h2>' . $this->options['title'] . '</h2>';
+ }
+ function footer() {
+ echo '</div>';
+ }
+
+ function error($errors) {
+ if ( ! $this->done_header )
+ $this->header();
+ if ( is_string($errors) ) {
+ $this->feedback($errors);
+ } elseif ( is_wp_error($errors) && $errors->get_error_code() ) {
+ foreach ( $errors->get_error_messages() as $message ) {
+ if ( $errors->get_error_data() )
+ $this->feedback($message . ' ' . esc_html( $errors->get_error_data() ) );
+ else
+ $this->feedback($message);
+ }
+ }
+ }
+
+ function feedback($string) {
+ if ( isset( $this->upgrader->strings[$string] ) )
+ $string = $this->upgrader->strings[$string];
+
+ if ( strpos($string, '%') !== false ) {
+ $args = func_get_args();
+ $args = array_splice($args, 1);
+ if ( $args ) {
+ $args = array_map( 'strip_tags', $args );
+ $args = array_map( 'esc_html', $args );
+ $string = vsprintf($string, $args);
+ }
+ }
+ if ( empty($string) )
+ return;
+ show_message($string);
+ }
+ function before() {}
+ function after() {}
+
+}
+
+/**
+ * Plugin Upgrader Skin for WordPress Plugin Upgrades.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Plugin_Upgrader_Skin extends WP_Upgrader_Skin {
+ var $plugin = '';
+ var $plugin_active = false;
+ var $plugin_network_active = false;
+
+ function __construct($args = array()) {
+ $defaults = array( 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => __('Update Plugin') );
+ $args = wp_parse_args($args, $defaults);
+
+ $this->plugin = $args['plugin'];
+
+ $this->plugin_active = is_plugin_active( $this->plugin );
+ $this->plugin_network_active = is_plugin_active_for_network( $this->plugin );
+
+ parent::__construct($args);
+ }
+
+ function after() {
+ $this->plugin = $this->upgrader->plugin_info();
+ if ( !empty($this->plugin) && !is_wp_error($this->result) && $this->plugin_active ){
+ echo '<iframe style="border:0;overflow:hidden" width="100%" height="170px" src="' . wp_nonce_url('update.php?action=activate-plugin&networkwide=' . $this->plugin_network_active . '&plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin) .'"></iframe>';
+ }
+
+ $update_actions = array(
+ 'activate_plugin' => '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin) . '" title="' . esc_attr__('Activate this plugin') . '" target="_parent">' . __('Activate Plugin') . '</a>',
+ 'plugins_page' => '<a href="' . self_admin_url('plugins.php') . '" title="' . esc_attr__('Go to plugins page') . '" target="_parent">' . __('Return to Plugins page') . '</a>'
+ );
+ if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugins' ) )
+ unset( $update_actions['activate_plugin'] );
+
+ $update_actions = apply_filters('update_plugin_complete_actions', $update_actions, $this->plugin);
+ if ( ! empty($update_actions) )
+ $this->feedback(implode(' | ', (array)$update_actions));
+ }
+
+ function before() {
+ if ( $this->upgrader->show_before ) {
+ echo $this->upgrader->show_before;
+ $this->upgrader->show_before = '';
+ }
+ }
+}
+
+/**
+ * Plugin Upgrader Skin for WordPress Plugin Upgrades.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 3.0.0
+ */
+class Bulk_Upgrader_Skin extends WP_Upgrader_Skin {
+ var $in_loop = false;
+ var $error = false;
+
+ function __construct($args = array()) {
+ $defaults = array( 'url' => '', 'nonce' => '' );
+ $args = wp_parse_args($args, $defaults);
+
+ parent::__construct($args);
+ }
+
+ function add_strings() {
+ $this->upgrader->strings['skin_upgrade_start'] = __('The update process is starting. This process may take a while on some hosts, so please be patient.');
+ $this->upgrader->strings['skin_update_failed_error'] = __('An error occurred while updating %1$s: <strong>%2$s</strong>');
+ $this->upgrader->strings['skin_update_failed'] = __('The update of %1$s failed.');
+ $this->upgrader->strings['skin_update_successful'] = __('%1$s updated successfully.').' <a onclick="%2$s" href="#" class="hide-if-no-js"><span>'.__('Show Details').'</span><span class="hidden">'.__('Hide Details').'</span>.</a>';
+ $this->upgrader->strings['skin_upgrade_end'] = __('All updates have been completed.');
+ }
+
+ function feedback($string) {
+ if ( isset( $this->upgrader->strings[$string] ) )
+ $string = $this->upgrader->strings[$string];
+
+ if ( strpos($string, '%') !== false ) {
+ $args = func_get_args();
+ $args = array_splice($args, 1);
+ if ( $args ) {
+ $args = array_map( 'strip_tags', $args );
+ $args = array_map( 'esc_html', $args );
+ $string = vsprintf($string, $args);
+ }
+ }
+ if ( empty($string) )
+ return;
+ if ( $this->in_loop )
+ echo "$string<br />\n";
+ else
+ echo "<p>$string</p>\n";
+ }
+
+ function header() {
+ // Nothing, This will be displayed within a iframe.
+ }
+
+ function footer() {
+ // Nothing, This will be displayed within a iframe.
+ }
+ function error($error) {
+ if ( is_string($error) && isset( $this->upgrader->strings[$error] ) )
+ $this->error = $this->upgrader->strings[$error];
+
+ if ( is_wp_error($error) ) {
+ foreach ( $error->get_error_messages() as $emessage ) {
+ if ( $error->get_error_data() )
+ $messages[] = $emessage . ' ' . esc_html( $error->get_error_data() );
+ else
+ $messages[] = $emessage;
+ }
+ $this->error = implode(', ', $messages);
+ }
+ echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>';
+ }
+
+ function bulk_header() {
+ $this->feedback('skin_upgrade_start');
+ }
+
+ function bulk_footer() {
+ $this->feedback('skin_upgrade_end');
+ }
+
+ function before($title = '') {
+ $this->in_loop = true;
+ printf( '<h4>' . $this->upgrader->strings['skin_before_update_header'] . ' <span class="spinner waiting-' . $this->upgrader->update_current . '"></span></h4>', $title, $this->upgrader->update_current, $this->upgrader->update_count);
+ echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').css("display", "inline-block");</script>';
+ echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr($this->upgrader->update_current) . '"><p>';
+ $this->flush_output();
+ }
+
+ function after($title = '') {
+ echo '</p></div>';
+ if ( $this->error || ! $this->result ) {
+ if ( $this->error )
+ echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed_error'], $title, $this->error) . '</p></div>';
+ else
+ echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed'], $title) . '</p></div>';
+
+ echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').show();</script>';
+ }
+ if ( $this->result && ! is_wp_error( $this->result ) ) {
+ if ( ! $this->error )
+ echo '<div class="updated"><p>' . sprintf($this->upgrader->strings['skin_update_successful'], $title, 'jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').toggle();jQuery(\'span\', this).toggle(); return false;') . '</p></div>';
+ echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>';
+ }
+
+ $this->reset();
+ $this->flush_output();
+ }
+
+ function reset() {
+ $this->in_loop = false;
+ $this->error = false;
+ }
+
+ function flush_output() {
+ wp_ob_end_flush_all();
+ flush();
+ }
+}
+
+class Bulk_Plugin_Upgrader_Skin extends Bulk_Upgrader_Skin {
+ var $plugin_info = array(); // Plugin_Upgrader::bulk() will fill this in.
+
+ function __construct($args = array()) {
+ parent::__construct($args);
+ }
+
+ function add_strings() {
+ parent::add_strings();
+ $this->upgrader->strings['skin_before_update_header'] = __('Updating Plugin %1$s (%2$d/%3$d)');
+ }
+
+ function before($title = '') {
+ parent::before($this->plugin_info['Title']);
+ }
+
+ function after($title = '') {
+ parent::after($this->plugin_info['Title']);
+ }
+ function bulk_footer() {
+ parent::bulk_footer();
+ $update_actions = array(
+ 'plugins_page' => '<a href="' . self_admin_url('plugins.php') . '" title="' . esc_attr__('Go to plugins page') . '" target="_parent">' . __('Return to Plugins page') . '</a>',
+ 'updates_page' => '<a href="' . self_admin_url('update-core.php') . '" title="' . esc_attr__('Go to WordPress Updates page') . '" target="_parent">' . __('Return to WordPress Updates') . '</a>'
+ );
+ if ( ! current_user_can( 'activate_plugins' ) )
+ unset( $update_actions['plugins_page'] );
+
+ $update_actions = apply_filters('update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info);
+ if ( ! empty($update_actions) )
+ $this->feedback(implode(' | ', (array)$update_actions));
+ }
+}
+
+class Bulk_Theme_Upgrader_Skin extends Bulk_Upgrader_Skin {
+ var $theme_info = array(); // Theme_Upgrader::bulk() will fill this in.
+
+ function __construct($args = array()) {
+ parent::__construct($args);
+ }
+
+ function add_strings() {
+ parent::add_strings();
+ $this->upgrader->strings['skin_before_update_header'] = __('Updating Theme %1$s (%2$d/%3$d)');
+ }
+
+ function before($title = '') {
+ parent::before( $this->theme_info->display('Name') );
+ }
+
+ function after($title = '') {
+ parent::after( $this->theme_info->display('Name') );
+ }
+
+ function bulk_footer() {
+ parent::bulk_footer();
+ $update_actions = array(
+ 'themes_page' => '<a href="' . self_admin_url('themes.php') . '" title="' . esc_attr__('Go to themes page') . '" target="_parent">' . __('Return to Themes page') . '</a>',
+ 'updates_page' => '<a href="' . self_admin_url('update-core.php') . '" title="' . esc_attr__('Go to WordPress Updates page') . '" target="_parent">' . __('Return to WordPress Updates') . '</a>'
+ );
+ if ( ! current_user_can( 'switch_themes' ) && ! current_user_can( 'edit_theme_options' ) )
+ unset( $update_actions['themes_page'] );
+
+ $update_actions = apply_filters('update_bulk_theme_complete_actions', $update_actions, $this->theme_info );
+ if ( ! empty($update_actions) )
+ $this->feedback(implode(' | ', (array)$update_actions));
+ }
+}
+
+/**
+ * Plugin Installer Skin for WordPress Plugin Installer.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Plugin_Installer_Skin extends WP_Upgrader_Skin {
+ var $api;
+ var $type;
+
+ function __construct($args = array()) {
+ $defaults = array( 'type' => 'web', 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => '' );
+ $args = wp_parse_args($args, $defaults);
+
+ $this->type = $args['type'];
+ $this->api = isset($args['api']) ? $args['api'] : array();
+
+ parent::__construct($args);
+ }
+
+ function before() {
+ if ( !empty($this->api) )
+ $this->upgrader->strings['process_success'] = sprintf( __('Successfully installed the plugin <strong>%s %s</strong>.'), $this->api->name, $this->api->version);
+ }
+
+ function after() {
+
+ $plugin_file = $this->upgrader->plugin_info();
+
+ $install_actions = array();
+
+ $from = isset($_GET['from']) ? wp_unslash( $_GET['from'] ) : 'plugins';
+
+ if ( 'import' == $from )
+ $install_actions['activate_plugin'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;from=import&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" target="_parent">' . __('Activate Plugin &amp; Run Importer') . '</a>';
+ else
+ $install_actions['activate_plugin'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin') . '" target="_parent">' . __('Activate Plugin') . '</a>';
+
+ if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
+ $install_actions['network_activate'] = '<a href="' . wp_nonce_url('plugins.php?action=activate&amp;networkwide=1&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file) . '" title="' . esc_attr__('Activate this plugin for all sites in this network') . '" target="_parent">' . __('Network Activate') . '</a>';
+ unset( $install_actions['activate_plugin'] );
+ }
+
+ if ( 'import' == $from )
+ $install_actions['importers_page'] = '<a href="' . admin_url('import.php') . '" title="' . esc_attr__('Return to Importers') . '" target="_parent">' . __('Return to Importers') . '</a>';
+ else if ( $this->type == 'web' )
+ $install_actions['plugins_page'] = '<a href="' . self_admin_url('plugin-install.php') . '" title="' . esc_attr__('Return to Plugin Installer') . '" target="_parent">' . __('Return to Plugin Installer') . '</a>';
+ else
+ $install_actions['plugins_page'] = '<a href="' . self_admin_url('plugins.php') . '" title="' . esc_attr__('Return to Plugins page') . '" target="_parent">' . __('Return to Plugins page') . '</a>';
+
+ if ( ! $this->result || is_wp_error($this->result) ) {
+ unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
+ } elseif ( ! current_user_can( 'activate_plugins' ) ) {
+ unset( $install_actions['activate_plugin'] );
+ }
+
+ $install_actions = apply_filters('install_plugin_complete_actions', $install_actions, $this->api, $plugin_file);
+ if ( ! empty($install_actions) )
+ $this->feedback(implode(' | ', (array)$install_actions));
+ }
+}
+
+/**
+ * Theme Installer Skin for the WordPress Theme Installer.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Theme_Installer_Skin extends WP_Upgrader_Skin {
+ var $api;
+ var $type;
+
+ function __construct($args = array()) {
+ $defaults = array( 'type' => 'web', 'url' => '', 'theme' => '', 'nonce' => '', 'title' => '' );
+ $args = wp_parse_args($args, $defaults);
+
+ $this->type = $args['type'];
+ $this->api = isset($args['api']) ? $args['api'] : array();
+
+ parent::__construct($args);
+ }
+
+ function before() {
+ if ( !empty($this->api) )
+ $this->upgrader->strings['process_success'] = sprintf( $this->upgrader->strings['process_success_specific'], $this->api->name, $this->api->version);
+ }
+
+ function after() {
+ if ( empty($this->upgrader->result['destination_name']) )
+ return;
+
+ $theme_info = $this->upgrader->theme_info();
+ if ( empty( $theme_info ) )
+ return;
+
+ $name = $theme_info->display('Name');
+ $stylesheet = $this->upgrader->result['destination_name'];
+ $template = $theme_info->get_template();
+
+ $preview_link = add_query_arg( array(
+ 'preview' => 1,
+ 'template' => urlencode( $template ),
+ 'stylesheet' => urlencode( $stylesheet ),
+ ), trailingslashit( home_url() ) );
+
+ $activate_link = add_query_arg( array(
+ 'action' => 'activate',
+ 'template' => urlencode( $template ),
+ 'stylesheet' => urlencode( $stylesheet ),
+ ), admin_url('themes.php') );
+ $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
+
+ $install_actions = array();
+ $install_actions['preview'] = '<a href="' . esc_url( $preview_link ) . '" class="hide-if-customize" title="' . esc_attr( sprintf( __('Preview &#8220;%s&#8221;'), $name ) ) . '">' . __('Preview') . '</a>';
+ $install_actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize" title="' . esc_attr( sprintf( __('Preview &#8220;%s&#8221;'), $name ) ) . '">' . __('Live Preview') . '</a>';
+ $install_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink" title="' . esc_attr( sprintf( __('Activate &#8220;%s&#8221;'), $name ) ) . '">' . __('Activate') . '</a>';
+
+ if ( is_network_admin() && current_user_can( 'manage_network_themes' ) )
+ $install_actions['network_enable'] = '<a href="' . esc_url( wp_nonce_url( 'themes.php?action=enable&amp;theme=' . urlencode( $stylesheet ), 'enable-theme_' . $stylesheet ) ) . '" title="' . esc_attr__( 'Enable this theme for all sites in this network' ) . '" target="_parent">' . __( 'Network Enable' ) . '</a>';
+
+ if ( $this->type == 'web' )
+ $install_actions['themes_page'] = '<a href="' . self_admin_url('theme-install.php') . '" title="' . esc_attr__('Return to Theme Installer') . '" target="_parent">' . __('Return to Theme Installer') . '</a>';
+ elseif ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) )
+ $install_actions['themes_page'] = '<a href="' . self_admin_url('themes.php') . '" title="' . esc_attr__('Themes page') . '" target="_parent">' . __('Return to Themes page') . '</a>';
+
+ if ( ! $this->result || is_wp_error($this->result) || is_network_admin() || ! current_user_can( 'switch_themes' ) )
+ unset( $install_actions['activate'], $install_actions['preview'] );
+
+ $install_actions = apply_filters('install_theme_complete_actions', $install_actions, $this->api, $stylesheet, $theme_info);
+ if ( ! empty($install_actions) )
+ $this->feedback(implode(' | ', (array)$install_actions));
+ }
+}
+
+/**
+ * Theme Upgrader Skin for WordPress Theme Upgrades.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class Theme_Upgrader_Skin extends WP_Upgrader_Skin {
+ var $theme = '';
+
+ function __construct($args = array()) {
+ $defaults = array( 'url' => '', 'theme' => '', 'nonce' => '', 'title' => __('Update Theme') );
+ $args = wp_parse_args($args, $defaults);
+
+ $this->theme = $args['theme'];
+
+ parent::__construct($args);
+ }
+
+ function after() {
+
+ $update_actions = array();
+ if ( ! empty( $this->upgrader->result['destination_name'] ) && $theme_info = $this->upgrader->theme_info() ) {
+ $name = $theme_info->display('Name');
+ $stylesheet = $this->upgrader->result['destination_name'];
+ $template = $theme_info->get_template();
+
+ $preview_link = add_query_arg( array(
+ 'preview' => 1,
+ 'template' => urlencode( $template ),
+ 'stylesheet' => urlencode( $stylesheet ),
+ ), trailingslashit( home_url() ) );
+
+ $activate_link = add_query_arg( array(
+ 'action' => 'activate',
+ 'template' => urlencode( $template ),
+ 'stylesheet' => urlencode( $stylesheet ),
+ ), admin_url('themes.php') );
+ $activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
+
+ if ( get_stylesheet() == $stylesheet ) {
+ if ( current_user_can( 'edit_theme_options' ) )
+ $update_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize" title="' . esc_attr( sprintf( __('Customize &#8220;%s&#8221;'), $name ) ) . '">' . __('Customize') . '</a>';
+ } elseif ( current_user_can( 'switch_themes' ) ) {
+ $update_actions['preview'] = '<a href="' . esc_url( $preview_link ) . '" class="hide-if-customize" title="' . esc_attr( sprintf( __('Preview &#8220;%s&#8221;'), $name ) ) . '">' . __('Preview') . '</a>';
+ $update_actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize" title="' . esc_attr( sprintf( __('Preview &#8220;%s&#8221;'), $name ) ) . '">' . __('Live Preview') . '</a>';
+ $update_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink" title="' . esc_attr( sprintf( __('Activate &#8220;%s&#8221;'), $name ) ) . '">' . __('Activate') . '</a>';
+ }
+
+ if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() )
+ unset( $update_actions['preview'], $update_actions['activate'] );
+ }
+
+ $update_actions['themes_page'] = '<a href="' . self_admin_url('themes.php') . '" title="' . esc_attr__('Return to Themes page') . '" target="_parent">' . __('Return to Themes page') . '</a>';
+
+ $update_actions = apply_filters('update_theme_complete_actions', $update_actions, $this->theme);
+ if ( ! empty($update_actions) )
+ $this->feedback(implode(' | ', (array)$update_actions));
+ }
+}
+
+/**
+ * Upgrade Skin helper for File uploads. This class handles the upload process and passes it as if it's a local file to the Upgrade/Installer functions.
+ *
+ * @TODO More Detailed docs, for methods as well.
+ *
+ * @package WordPress
+ * @subpackage Upgrader
+ * @since 2.8.0
+ */
+class File_Upload_Upgrader {
+ var $package;
+ var $filename;
+ var $id = 0;
+
+ function __construct($form, $urlholder) {
+
+ if ( empty($_FILES[$form]['name']) && empty($_GET[$urlholder]) )
+ wp_die(__('Please select a file'));
+
+ //Handle a newly uploaded file, Else assume it's already been uploaded
+ if ( ! empty($_FILES) ) {
+ $overrides = array( 'test_form' => false, 'test_type' => false );
+ $file = wp_handle_upload( $_FILES[$form], $overrides );
+
+ if ( isset( $file['error'] ) )
+ wp_die( $file['error'] );
+
+ $this->filename = $_FILES[$form]['name'];
+ $this->package = $file['file'];
+
+ // Construct the object array
+ $object = array(
+ 'post_title' => $this->filename,
+ 'post_content' => $file['url'],
+ 'post_mime_type' => $file['type'],
+ 'guid' => $file['url'],
+ 'context' => 'upgrader',
+ 'post_status' => 'private'
+ );
+
+ // Save the data
+ $this->id = wp_insert_attachment( $object, $file['file'] );
+
+ // schedule a cleanup for 2 hours from now in case of failed install
+ wp_schedule_single_event( time() + 7200, 'upgrader_scheduled_cleanup', array( $this->id ) );
+
+ } elseif ( is_numeric( $_GET[$urlholder] ) ) {
+ // Numeric Package = previously uploaded file, see above.
+ $this->id = (int) $_GET[$urlholder];
+ $attachment = get_post( $this->id );
+ if ( empty($attachment) )
+ wp_die(__('Please select a file'));
+
+ $this->filename = $attachment->post_title;
+ $this->package = get_attached_file( $attachment->ID );
+ } else {
+ // Else, It's set to something, Back compat for plugins using the old (pre-3.3) File_Uploader handler.
+ if ( ! ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) )
+ wp_die( $uploads['error'] );
+
+ $this->filename = $_GET[$urlholder];
+ $this->package = $uploads['basedir'] . '/' . $this->filename;
+ }
+ }
+
+ function cleanup() {
+ if ( $this->id )
+ wp_delete_attachment( $this->id );
+
+ elseif ( file_exists( $this->package ) )
+ return @unlink( $this->package );
+
+ return true;
+ }
+}
diff --git a/src/wp-admin/includes/class-wp-users-list-table.php b/src/wp-admin/includes/class-wp-users-list-table.php
new file mode 100644
index 0000000000..48c9c0c256
--- /dev/null
+++ b/src/wp-admin/includes/class-wp-users-list-table.php
@@ -0,0 +1,324 @@
+<?php
+/**
+ * Users List Table class.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ * @access private
+ */
+class WP_Users_List_Table extends WP_List_Table {
+
+ var $site_id;
+ var $is_site_users;
+
+ function __construct( $args = array() ) {
+ parent::__construct( array(
+ 'singular' => 'user',
+ 'plural' => 'users',
+ 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
+ ) );
+
+ $this->is_site_users = 'site-users-network' == $this->screen->id;
+
+ if ( $this->is_site_users )
+ $this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+ }
+
+ function ajax_user_can() {
+ if ( $this->is_site_users )
+ return current_user_can( 'manage_sites' );
+ else
+ return current_user_can( 'list_users' );
+ }
+
+ function prepare_items() {
+ global $role, $usersearch;
+
+ $usersearch = isset( $_REQUEST['s'] ) ? trim( $_REQUEST['s'] ) : '';
+
+ $role = isset( $_REQUEST['role'] ) ? $_REQUEST['role'] : '';
+
+ $per_page = ( $this->is_site_users ) ? 'site_users_network_per_page' : 'users_per_page';
+ $users_per_page = $this->get_items_per_page( $per_page );
+
+ $paged = $this->get_pagenum();
+
+ $args = array(
+ 'number' => $users_per_page,
+ 'offset' => ( $paged-1 ) * $users_per_page,
+ 'role' => $role,
+ 'search' => $usersearch,
+ 'fields' => 'all_with_meta'
+ );
+
+ if ( '' !== $args['search'] )
+ $args['search'] = '*' . $args['search'] . '*';
+
+ if ( $this->is_site_users )
+ $args['blog_id'] = $this->site_id;
+
+ if ( isset( $_REQUEST['orderby'] ) )
+ $args['orderby'] = $_REQUEST['orderby'];
+
+ if ( isset( $_REQUEST['order'] ) )
+ $args['order'] = $_REQUEST['order'];
+
+ // Query the user IDs for this page
+ $wp_user_search = new WP_User_Query( $args );
+
+ $this->items = $wp_user_search->get_results();
+
+ $this->set_pagination_args( array(
+ 'total_items' => $wp_user_search->get_total(),
+ 'per_page' => $users_per_page,
+ ) );
+ }
+
+ function no_items() {
+ _e( 'No matching users were found.' );
+ }
+
+ function get_views() {
+ global $wp_roles, $role;
+
+ if ( $this->is_site_users ) {
+ $url = 'site-users.php?id=' . $this->site_id;
+ switch_to_blog( $this->site_id );
+ $users_of_blog = count_users();
+ restore_current_blog();
+ } else {
+ $url = 'users.php';
+ $users_of_blog = count_users();
+ }
+ $total_users = $users_of_blog['total_users'];
+ $avail_roles =& $users_of_blog['avail_roles'];
+ unset($users_of_blog);
+
+ $current_role = false;
+ $class = empty($role) ? ' class="current"' : '';
+ $role_links = array();
+ $role_links['all'] = "<a href='$url'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
+ foreach ( $wp_roles->get_names() as $this_role => $name ) {
+ if ( !isset($avail_roles[$this_role]) )
+ continue;
+
+ $class = '';
+
+ if ( $this_role == $role ) {
+ $current_role = $role;
+ $class = ' class="current"';
+ }
+
+ $name = translate_user_role( $name );
+ /* translators: User role name with count */
+ $name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles[$this_role] ) );
+ $role_links[$this_role] = "<a href='" . esc_url( add_query_arg( 'role', $this_role, $url ) ) . "'$class>$name</a>";
+ }
+
+ return $role_links;
+ }
+
+ function get_bulk_actions() {
+ $actions = array();
+
+ if ( is_multisite() ) {
+ if ( current_user_can( 'remove_users' ) )
+ $actions['remove'] = __( 'Remove' );
+ } else {
+ if ( current_user_can( 'delete_users' ) )
+ $actions['delete'] = __( 'Delete' );
+ }
+
+ return $actions;
+ }
+
+ function extra_tablenav( $which ) {
+ if ( 'top' != $which )
+ return;
+ ?>
+ <div class="alignleft actions">
+ <?php if ( current_user_can( 'promote_users' ) ) : ?>
+ <label class="screen-reader-text" for="new_role"><?php _e( 'Change role to&hellip;' ) ?></label>
+ <select name="new_role" id="new_role">
+ <option value=''><?php _e( 'Change role to&hellip;' ) ?></option>
+ <?php wp_dropdown_roles(); ?>
+ </select>
+ <?php
+ submit_button( __( 'Change' ), 'button', 'changeit', false );
+ endif;
+
+ do_action( 'restrict_manage_users' );
+ echo '</div>';
+ }
+
+ function current_action() {
+ if ( isset($_REQUEST['changeit']) && !empty($_REQUEST['new_role']) )
+ return 'promote';
+
+ return parent::current_action();
+ }
+
+ function get_columns() {
+ $c = array(
+ 'cb' => '<input type="checkbox" />',
+ 'username' => __( 'Username' ),
+ 'name' => __( 'Name' ),
+ 'email' => __( 'E-mail' ),
+ 'role' => __( 'Role' ),
+ 'posts' => __( 'Posts' )
+ );
+
+ if ( $this->is_site_users )
+ unset( $c['posts'] );
+
+ return $c;
+ }
+
+ function get_sortable_columns() {
+ $c = array(
+ 'username' => 'login',
+ 'name' => 'name',
+ 'email' => 'email',
+ );
+
+ if ( $this->is_site_users )
+ unset( $c['posts'] );
+
+ return $c;
+ }
+
+ function display_rows() {
+ // Query the post counts for this page
+ if ( ! $this->is_site_users )
+ $post_counts = count_many_users_posts( array_keys( $this->items ) );
+
+ $editable_roles = array_keys( get_editable_roles() );
+
+ $style = '';
+ foreach ( $this->items as $userid => $user_object ) {
+ if ( count( $user_object->roles ) <= 1 ) {
+ $role = reset( $user_object->roles );
+ } elseif ( $roles = array_intersect( array_values( $user_object->roles ), $editable_roles ) ) {
+ $role = reset( $roles );
+ } else {
+ $role = reset( $user_object->roles );
+ }
+
+ if ( is_multisite() && empty( $user_object->allcaps ) )
+ continue;
+
+ $style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
+ echo "\n\t" . $this->single_row( $user_object, $style, $role, isset( $post_counts ) ? $post_counts[ $userid ] : 0 );
+ }
+ }
+
+ /**
+ * Generate HTML for a single row on the users.php admin panel.
+ *
+ * @since 2.1.0
+ *
+ * @param object $user_object
+ * @param string $style Optional. Attributes added to the TR element. Must be sanitized.
+ * @param string $role Key for the $wp_roles array.
+ * @param int $numposts Optional. Post count to display for this user. Defaults to zero, as in, a new user has made zero posts.
+ * @return string
+ */
+ function single_row( $user_object, $style = '', $role = '', $numposts = 0 ) {
+ global $wp_roles;
+
+ if ( !( is_object( $user_object ) && is_a( $user_object, 'WP_User' ) ) )
+ $user_object = get_userdata( (int) $user_object );
+ $user_object->filter = 'display';
+ $email = $user_object->user_email;
+
+ if ( $this->is_site_users )
+ $url = "site-users.php?id={$this->site_id}&amp;";
+ else
+ $url = 'users.php?';
+
+ $checkbox = '';
+ // Check if the user for this row is editable
+ if ( current_user_can( 'list_users' ) ) {
+ // Set up the user editing link
+ $edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user_object->ID ) ) );
+
+ // Set up the hover actions for this user
+ $actions = array();
+
+ if ( current_user_can( 'edit_user', $user_object->ID ) ) {
+ $edit = "<strong><a href=\"$edit_link\">$user_object->user_login</a></strong><br />";
+ $actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
+ } else {
+ $edit = "<strong>$user_object->user_login</strong><br />";
+ }
+
+ if ( !is_multisite() && get_current_user_id() != $user_object->ID && current_user_can( 'delete_user', $user_object->ID ) )
+ $actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url( "users.php?action=delete&amp;user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Delete' ) . "</a>";
+ if ( is_multisite() && get_current_user_id() != $user_object->ID && current_user_can( 'remove_user', $user_object->ID ) )
+ $actions['remove'] = "<a class='submitdelete' href='" . wp_nonce_url( $url."action=remove&amp;user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Remove' ) . "</a>";
+ $actions = apply_filters( 'user_row_actions', $actions, $user_object );
+ $edit .= $this->row_actions( $actions );
+
+ // Set up the checkbox ( because the user is editable, otherwise it's empty )
+ $checkbox = '<label class="screen-reader-text" for="cb-select-' . $user_object->ID . '">' . sprintf( __( 'Select %s' ), $user_object->user_login ) . '</label>'
+ . "<input type='checkbox' name='users[]' id='user_{$user_object->ID}' class='$role' value='{$user_object->ID}' />";
+
+ } else {
+ $edit = '<strong>' . $user_object->user_login . '</strong>';
+ }
+ $role_name = isset( $wp_roles->role_names[$role] ) ? translate_user_role( $wp_roles->role_names[$role] ) : __( 'None' );
+ $avatar = get_avatar( $user_object->ID, 32 );
+
+ $r = "<tr id='user-$user_object->ID'$style>";
+
+ list( $columns, $hidden ) = $this->get_column_info();
+
+ foreach ( $columns as $column_name => $column_display_name ) {
+ $class = "class=\"$column_name column-$column_name\"";
+
+ $style = '';
+ if ( in_array( $column_name, $hidden ) )
+ $style = ' style="display:none;"';
+
+ $attributes = "$class$style";
+
+ switch ( $column_name ) {
+ case 'cb':
+ $r .= "<th scope='row' class='check-column'>$checkbox</th>";
+ break;
+ case 'username':
+ $r .= "<td $attributes>$avatar $edit</td>";
+ break;
+ case 'name':
+ $r .= "<td $attributes>$user_object->first_name $user_object->last_name</td>";
+ break;
+ case 'email':
+ $r .= "<td $attributes><a href='mailto:$email' title='" . esc_attr( sprintf( __( 'E-mail: %s' ), $email ) ) . "'>$email</a></td>";
+ break;
+ case 'role':
+ $r .= "<td $attributes>$role_name</td>";
+ break;
+ case 'posts':
+ $attributes = 'class="posts column-posts num"' . $style;
+ $r .= "<td $attributes>";
+ if ( $numposts > 0 ) {
+ $r .= "<a href='edit.php?author=$user_object->ID' title='" . esc_attr__( 'View posts by this author' ) . "' class='edit'>";
+ $r .= $numposts;
+ $r .= '</a>';
+ } else {
+ $r .= 0;
+ }
+ $r .= "</td>";
+ break;
+ default:
+ $r .= "<td $attributes>";
+ $r .= apply_filters( 'manage_users_custom_column', '', $column_name, $user_object->ID );
+ $r .= "</td>";
+ }
+ }
+ $r .= '</tr>';
+
+ return $r;
+ }
+}
diff --git a/src/wp-admin/includes/comment.php b/src/wp-admin/includes/comment.php
new file mode 100644
index 0000000000..1620755b68
--- /dev/null
+++ b/src/wp-admin/includes/comment.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ * WordPress Comment Administration API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Determine if a comment exists based on author and date.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @param string $comment_author Author of the comment
+ * @param string $comment_date Date of the comment
+ * @return mixed Comment post ID on success.
+ */
+function comment_exists($comment_author, $comment_date) {
+ global $wpdb;
+
+ $comment_author = stripslashes($comment_author);
+ $comment_date = stripslashes($comment_date);
+
+ return $wpdb->get_var( $wpdb->prepare("SELECT comment_post_ID FROM $wpdb->comments
+ WHERE comment_author = %s AND comment_date = %s", $comment_author, $comment_date) );
+}
+
+/**
+ * Update a comment with values provided in $_POST.
+ *
+ * @since 2.0.0
+ */
+function edit_comment() {
+
+ if ( ! current_user_can( 'edit_comment', (int) $_POST['comment_ID'] ) )
+ wp_die ( __( 'You are not allowed to edit comments on this post.' ) );
+
+ $_POST['comment_author'] = $_POST['newcomment_author'];
+ $_POST['comment_author_email'] = $_POST['newcomment_author_email'];
+ $_POST['comment_author_url'] = $_POST['newcomment_author_url'];
+ $_POST['comment_approved'] = $_POST['comment_status'];
+ $_POST['comment_content'] = $_POST['content'];
+ $_POST['comment_ID'] = (int) $_POST['comment_ID'];
+
+ foreach ( array ('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
+ if ( !empty( $_POST['hidden_' . $timeunit] ) && $_POST['hidden_' . $timeunit] != $_POST[$timeunit] ) {
+ $_POST['edit_date'] = '1';
+ break;
+ }
+ }
+
+ if ( !empty ( $_POST['edit_date'] ) ) {
+ $aa = $_POST['aa'];
+ $mm = $_POST['mm'];
+ $jj = $_POST['jj'];
+ $hh = $_POST['hh'];
+ $mn = $_POST['mn'];
+ $ss = $_POST['ss'];
+ $jj = ($jj > 31 ) ? 31 : $jj;
+ $hh = ($hh > 23 ) ? $hh -24 : $hh;
+ $mn = ($mn > 59 ) ? $mn -60 : $mn;
+ $ss = ($ss > 59 ) ? $ss -60 : $ss;
+ $_POST['comment_date'] = "$aa-$mm-$jj $hh:$mn:$ss";
+ }
+
+ wp_update_comment( $_POST );
+}
+
+/**
+ * Returns a comment object based on comment ID.
+ *
+ * @since 2.0.0
+ *
+ * @param int $id ID of comment to retrieve.
+ * @return bool|object Comment if found. False on failure.
+ */
+function get_comment_to_edit( $id ) {
+ if ( !$comment = get_comment($id) )
+ return false;
+
+ $comment->comment_ID = (int) $comment->comment_ID;
+ $comment->comment_post_ID = (int) $comment->comment_post_ID;
+
+ $comment->comment_content = format_to_edit( $comment->comment_content );
+ $comment->comment_content = apply_filters( 'comment_edit_pre', $comment->comment_content);
+
+ $comment->comment_author = format_to_edit( $comment->comment_author );
+ $comment->comment_author_email = format_to_edit( $comment->comment_author_email );
+ $comment->comment_author_url = format_to_edit( $comment->comment_author_url );
+ $comment->comment_author_url = esc_url($comment->comment_author_url);
+
+ return $comment;
+}
+
+/**
+ * Get the number of pending comments on a post or posts
+ *
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $post_id Either a single Post ID or an array of Post IDs
+ * @return int|array Either a single Posts pending comments as an int or an array of ints keyed on the Post IDs
+ */
+function get_pending_comments_num( $post_id ) {
+ global $wpdb;
+
+ $single = false;
+ if ( !is_array($post_id) ) {
+ $post_id_array = (array) $post_id;
+ $single = true;
+ } else {
+ $post_id_array = $post_id;
+ }
+ $post_id_array = array_map('intval', $post_id_array);
+ $post_id_in = "'" . implode("', '", $post_id_array) . "'";
+
+ $pending = $wpdb->get_results( "SELECT comment_post_ID, COUNT(comment_ID) as num_comments FROM $wpdb->comments WHERE comment_post_ID IN ( $post_id_in ) AND comment_approved = '0' GROUP BY comment_post_ID", ARRAY_A );
+
+ if ( $single ) {
+ if ( empty($pending) )
+ return 0;
+ else
+ return absint($pending[0]['num_comments']);
+ }
+
+ $pending_keyed = array();
+
+ // Default to zero pending for all posts in request
+ foreach ( $post_id_array as $id )
+ $pending_keyed[$id] = 0;
+
+ if ( !empty($pending) )
+ foreach ( $pending as $pend )
+ $pending_keyed[$pend['comment_post_ID']] = absint($pend['num_comments']);
+
+ return $pending_keyed;
+}
+
+/**
+ * Add avatars to relevant places in admin, or try to.
+ *
+ * @since 2.5.0
+ * @uses $comment
+ *
+ * @param string $name User name.
+ * @return string Avatar with Admin name.
+ */
+function floated_admin_avatar( $name ) {
+ global $comment;
+ $avatar = get_avatar( $comment, 32 );
+ return "$avatar $name";
+}
+
+function enqueue_comment_hotkeys_js() {
+ if ( 'true' == get_user_option( 'comment_shortcuts' ) )
+ wp_enqueue_script( 'jquery-table-hotkeys' );
+}
diff --git a/src/wp-admin/includes/continents-cities.php b/src/wp-admin/includes/continents-cities.php
new file mode 100644
index 0000000000..0ebc4f3fce
--- /dev/null
+++ b/src/wp-admin/includes/continents-cities.php
@@ -0,0 +1,493 @@
+<?php
+
+/* Continent and city translations for timezone selection.
+ * This file is not included anywhere. It exists solely for use by xgettext.
+ */
+
+__('Africa', 'continents-cities');
+__('Abidjan', 'continents-cities');
+__('Accra', 'continents-cities');
+__('Addis Ababa', 'continents-cities');
+__('Algiers', 'continents-cities');
+__('Asmara', 'continents-cities');
+__('Asmera', 'continents-cities');
+__('Bamako', 'continents-cities');
+__('Bangui', 'continents-cities');
+__('Banjul', 'continents-cities');
+__('Bissau', 'continents-cities');
+__('Blantyre', 'continents-cities');
+__('Brazzaville', 'continents-cities');
+__('Bujumbura', 'continents-cities');
+__('Cairo', 'continents-cities');
+__('Casablanca', 'continents-cities');
+__('Ceuta', 'continents-cities');
+__('Conakry', 'continents-cities');
+__('Dakar', 'continents-cities');
+__('Dar es Salaam', 'continents-cities');
+__('Djibouti', 'continents-cities');
+__('Douala', 'continents-cities');
+__('El Aaiun', 'continents-cities');
+__('Freetown', 'continents-cities');
+__('Gaborone', 'continents-cities');
+__('Harare', 'continents-cities');
+__('Johannesburg', 'continents-cities');
+__('Kampala', 'continents-cities');
+__('Khartoum', 'continents-cities');
+__('Kigali', 'continents-cities');
+__('Kinshasa', 'continents-cities');
+__('Lagos', 'continents-cities');
+__('Libreville', 'continents-cities');
+__('Lome', 'continents-cities');
+__('Luanda', 'continents-cities');
+__('Lubumbashi', 'continents-cities');
+__('Lusaka', 'continents-cities');
+__('Malabo', 'continents-cities');
+__('Maputo', 'continents-cities');
+__('Maseru', 'continents-cities');
+__('Mbabane', 'continents-cities');
+__('Mogadishu', 'continents-cities');
+__('Monrovia', 'continents-cities');
+__('Nairobi', 'continents-cities');
+__('Ndjamena', 'continents-cities');
+__('Niamey', 'continents-cities');
+__('Nouakchott', 'continents-cities');
+__('Ouagadougou', 'continents-cities');
+__('Porto-Novo', 'continents-cities');
+__('Sao Tome', 'continents-cities');
+__('Timbuktu', 'continents-cities');
+__('Tripoli', 'continents-cities');
+__('Tunis', 'continents-cities');
+__('Windhoek', 'continents-cities');
+__('America', 'continents-cities');
+__('Adak', 'continents-cities');
+__('Anchorage', 'continents-cities');
+__('Anguilla', 'continents-cities');
+__('Antigua', 'continents-cities');
+__('Araguaina', 'continents-cities');
+__('Argentina', 'continents-cities');
+__('Buenos Aires', 'continents-cities');
+__('Catamarca', 'continents-cities');
+__('ComodRivadavia', 'continents-cities');
+__('Cordoba', 'continents-cities');
+__('Jujuy', 'continents-cities');
+__('La Rioja', 'continents-cities');
+__('Mendoza', 'continents-cities');
+__('Rio Gallegos', 'continents-cities');
+__('San Juan', 'continents-cities');
+__('San Luis', 'continents-cities');
+__('Tucuman', 'continents-cities');
+__('Ushuaia', 'continents-cities');
+__('Aruba', 'continents-cities');
+__('Asuncion', 'continents-cities');
+__('Atikokan', 'continents-cities');
+__('Atka', 'continents-cities');
+__('Bahia', 'continents-cities');
+__('Barbados', 'continents-cities');
+__('Belem', 'continents-cities');
+__('Belize', 'continents-cities');
+__('Blanc-Sablon', 'continents-cities');
+__('Boa Vista', 'continents-cities');
+__('Bogota', 'continents-cities');
+__('Boise', 'continents-cities');
+__('Cambridge Bay', 'continents-cities');
+__('Campo Grande', 'continents-cities');
+__('Cancun', 'continents-cities');
+__('Caracas', 'continents-cities');
+__('Cayenne', 'continents-cities');
+__('Cayman', 'continents-cities');
+__('Chicago', 'continents-cities');
+__('Chihuahua', 'continents-cities');
+__('Coral Harbour', 'continents-cities');
+__('Costa Rica', 'continents-cities');
+__('Cuiaba', 'continents-cities');
+__('Curacao', 'continents-cities');
+__('Danmarkshavn', 'continents-cities');
+__('Dawson', 'continents-cities');
+__('Dawson Creek', 'continents-cities');
+__('Denver', 'continents-cities');
+__('Detroit', 'continents-cities');
+__('Dominica', 'continents-cities');
+__('Edmonton', 'continents-cities');
+__('Eirunepe', 'continents-cities');
+__('El Salvador', 'continents-cities');
+__('Ensenada', 'continents-cities');
+__('Fort Wayne', 'continents-cities');
+__('Fortaleza', 'continents-cities');
+__('Glace Bay', 'continents-cities');
+__('Godthab', 'continents-cities');
+__('Goose Bay', 'continents-cities');
+__('Grand Turk', 'continents-cities');
+__('Grenada', 'continents-cities');
+__('Guadeloupe', 'continents-cities');
+__('Guatemala', 'continents-cities');
+__('Guayaquil', 'continents-cities');
+__('Guyana', 'continents-cities');
+__('Halifax', 'continents-cities');
+__('Havana', 'continents-cities');
+__('Hermosillo', 'continents-cities');
+__('Indiana', 'continents-cities');
+__('Indianapolis', 'continents-cities');
+__('Knox', 'continents-cities');
+__('Marengo', 'continents-cities');
+__('Petersburg', 'continents-cities');
+__('Tell City', 'continents-cities');
+__('Vevay', 'continents-cities');
+__('Vincennes', 'continents-cities');
+__('Winamac', 'continents-cities');
+__('Inuvik', 'continents-cities');
+__('Iqaluit', 'continents-cities');
+__('Jamaica', 'continents-cities');
+__('Juneau', 'continents-cities');
+__('Kentucky', 'continents-cities');
+__('Louisville', 'continents-cities');
+__('Monticello', 'continents-cities');
+__('Knox IN', 'continents-cities');
+__('La Paz', 'continents-cities');
+__('Lima', 'continents-cities');
+__('Los Angeles', 'continents-cities');
+__('Maceio', 'continents-cities');
+__('Managua', 'continents-cities');
+__('Manaus', 'continents-cities');
+__('Marigot', 'continents-cities');
+__('Martinique', 'continents-cities');
+__('Mazatlan', 'continents-cities');
+__('Menominee', 'continents-cities');
+__('Merida', 'continents-cities');
+__('Mexico City', 'continents-cities');
+__('Miquelon', 'continents-cities');
+__('Moncton', 'continents-cities');
+__('Monterrey', 'continents-cities');
+__('Montevideo', 'continents-cities');
+__('Montreal', 'continents-cities');
+__('Montserrat', 'continents-cities');
+__('Nassau', 'continents-cities');
+__('New York', 'continents-cities');
+__('Nipigon', 'continents-cities');
+__('Nome', 'continents-cities');
+__('Noronha', 'continents-cities');
+__('North Dakota', 'continents-cities');
+__('Center', 'continents-cities');
+__('New Salem', 'continents-cities');
+__('Panama', 'continents-cities');
+__('Pangnirtung', 'continents-cities');
+__('Paramaribo', 'continents-cities');
+__('Phoenix', 'continents-cities');
+__('Port-au-Prince', 'continents-cities');
+__('Port of Spain', 'continents-cities');
+__('Porto Acre', 'continents-cities');
+__('Porto Velho', 'continents-cities');
+__('Puerto Rico', 'continents-cities');
+__('Rainy River', 'continents-cities');
+__('Rankin Inlet', 'continents-cities');
+__('Recife', 'continents-cities');
+__('Regina', 'continents-cities');
+__('Resolute', 'continents-cities');
+__('Rio Branco', 'continents-cities');
+__('Rosario', 'continents-cities');
+__('Santiago', 'continents-cities');
+__('Santo Domingo', 'continents-cities');
+__('Sao Paulo', 'continents-cities');
+__('Scoresbysund', 'continents-cities');
+__('Shiprock', 'continents-cities');
+__('St Barthelemy', 'continents-cities');
+__('St Johns', 'continents-cities');
+__('St Kitts', 'continents-cities');
+__('St Lucia', 'continents-cities');
+__('St Thomas', 'continents-cities');
+__('St Vincent', 'continents-cities');
+__('Swift Current', 'continents-cities');
+__('Tegucigalpa', 'continents-cities');
+__('Thule', 'continents-cities');
+__('Thunder Bay', 'continents-cities');
+__('Tijuana', 'continents-cities');
+__('Toronto', 'continents-cities');
+__('Tortola', 'continents-cities');
+__('Vancouver', 'continents-cities');
+__('Virgin', 'continents-cities');
+__('Whitehorse', 'continents-cities');
+__('Winnipeg', 'continents-cities');
+__('Yakutat', 'continents-cities');
+__('Yellowknife', 'continents-cities');
+__('Antarctica', 'continents-cities');
+__('Casey', 'continents-cities');
+__('Davis', 'continents-cities');
+__('DumontDUrville', 'continents-cities');
+__('Mawson', 'continents-cities');
+__('McMurdo', 'continents-cities');
+__('Palmer', 'continents-cities');
+__('Rothera', 'continents-cities');
+__('South Pole', 'continents-cities');
+__('Syowa', 'continents-cities');
+__('Vostok', 'continents-cities');
+__('Arctic', 'continents-cities');
+__('Longyearbyen', 'continents-cities');
+__('Asia', 'continents-cities');
+__('Aden', 'continents-cities');
+__('Almaty', 'continents-cities');
+__('Amman', 'continents-cities');
+__('Anadyr', 'continents-cities');
+__('Aqtau', 'continents-cities');
+__('Aqtobe', 'continents-cities');
+__('Ashgabat', 'continents-cities');
+__('Ashkhabad', 'continents-cities');
+__('Baghdad', 'continents-cities');
+__('Bahrain', 'continents-cities');
+__('Baku', 'continents-cities');
+__('Bangkok', 'continents-cities');
+__('Beirut', 'continents-cities');
+__('Bishkek', 'continents-cities');
+__('Brunei', 'continents-cities');
+__('Calcutta', 'continents-cities');
+__('Choibalsan', 'continents-cities');
+__('Chongqing', 'continents-cities');
+__('Chungking', 'continents-cities');
+__('Colombo', 'continents-cities');
+__('Dacca', 'continents-cities');
+__('Damascus', 'continents-cities');
+__('Dhaka', 'continents-cities');
+__('Dili', 'continents-cities');
+__('Dubai', 'continents-cities');
+__('Dushanbe', 'continents-cities');
+__('Gaza', 'continents-cities');
+__('Harbin', 'continents-cities');
+__('Ho Chi Minh', 'continents-cities');
+__('Hong Kong', 'continents-cities');
+__('Hovd', 'continents-cities');
+__('Irkutsk', 'continents-cities');
+__('Istanbul', 'continents-cities');
+__('Jakarta', 'continents-cities');
+__('Jayapura', 'continents-cities');
+__('Jerusalem', 'continents-cities');
+__('Kabul', 'continents-cities');
+__('Kamchatka', 'continents-cities');
+__('Karachi', 'continents-cities');
+__('Kashgar', 'continents-cities');
+__('Katmandu', 'continents-cities');
+__('Kolkata', 'continents-cities');
+__('Krasnoyarsk', 'continents-cities');
+__('Kuala Lumpur', 'continents-cities');
+__('Kuching', 'continents-cities');
+__('Kuwait', 'continents-cities');
+__('Macao', 'continents-cities');
+__('Macau', 'continents-cities');
+__('Magadan', 'continents-cities');
+__('Makassar', 'continents-cities');
+__('Manila', 'continents-cities');
+__('Muscat', 'continents-cities');
+__('Nicosia', 'continents-cities');
+__('Novosibirsk', 'continents-cities');
+__('Omsk', 'continents-cities');
+__('Oral', 'continents-cities');
+__('Phnom Penh', 'continents-cities');
+__('Pontianak', 'continents-cities');
+__('Pyongyang', 'continents-cities');
+__('Qatar', 'continents-cities');
+__('Qyzylorda', 'continents-cities');
+__('Rangoon', 'continents-cities');
+__('Riyadh', 'continents-cities');
+__('Saigon', 'continents-cities');
+__('Sakhalin', 'continents-cities');
+__('Samarkand', 'continents-cities');
+__('Seoul', 'continents-cities');
+__('Shanghai', 'continents-cities');
+__('Singapore', 'continents-cities');
+__('Taipei', 'continents-cities');
+__('Tashkent', 'continents-cities');
+__('Tbilisi', 'continents-cities');
+__('Tehran', 'continents-cities');
+__('Tel Aviv', 'continents-cities');
+__('Thimbu', 'continents-cities');
+__('Thimphu', 'continents-cities');
+__('Tokyo', 'continents-cities');
+__('Ujung Pandang', 'continents-cities');
+__('Ulaanbaatar', 'continents-cities');
+__('Ulan Bator', 'continents-cities');
+__('Urumqi', 'continents-cities');
+__('Vientiane', 'continents-cities');
+__('Vladivostok', 'continents-cities');
+__('Yakutsk', 'continents-cities');
+__('Yekaterinburg', 'continents-cities');
+__('Yerevan', 'continents-cities');
+__('Atlantic', 'continents-cities');
+__('Azores', 'continents-cities');
+__('Bermuda', 'continents-cities');
+__('Canary', 'continents-cities');
+__('Cape Verde', 'continents-cities');
+__('Faeroe', 'continents-cities');
+__('Faroe', 'continents-cities');
+__('Jan Mayen', 'continents-cities');
+__('Madeira', 'continents-cities');
+__('Reykjavik', 'continents-cities');
+__('South Georgia', 'continents-cities');
+__('St Helena', 'continents-cities');
+__('Stanley', 'continents-cities');
+__('Australia', 'continents-cities');
+__('ACT', 'continents-cities');
+__('Adelaide', 'continents-cities');
+__('Brisbane', 'continents-cities');
+__('Broken Hill', 'continents-cities');
+__('Canberra', 'continents-cities');
+__('Currie', 'continents-cities');
+__('Darwin', 'continents-cities');
+__('Eucla', 'continents-cities');
+__('Hobart', 'continents-cities');
+__('LHI', 'continents-cities');
+__('Lindeman', 'continents-cities');
+__('Lord Howe', 'continents-cities');
+__('Melbourne', 'continents-cities');
+__('North', 'continents-cities');
+__('NSW', 'continents-cities');
+__('Perth', 'continents-cities');
+__('Queensland', 'continents-cities');
+__('South', 'continents-cities');
+__('Sydney', 'continents-cities');
+__('Tasmania', 'continents-cities');
+__('Victoria', 'continents-cities');
+__('West', 'continents-cities');
+__('Yancowinna', 'continents-cities');
+__('Etc', 'continents-cities');
+__('GMT', 'continents-cities');
+__('GMT+0', 'continents-cities');
+__('GMT+1', 'continents-cities');
+__('GMT+10', 'continents-cities');
+__('GMT+11', 'continents-cities');
+__('GMT+12', 'continents-cities');
+__('GMT+2', 'continents-cities');
+__('GMT+3', 'continents-cities');
+__('GMT+4', 'continents-cities');
+__('GMT+5', 'continents-cities');
+__('GMT+6', 'continents-cities');
+__('GMT+7', 'continents-cities');
+__('GMT+8', 'continents-cities');
+__('GMT+9', 'continents-cities');
+__('GMT-0', 'continents-cities');
+__('GMT-1', 'continents-cities');
+__('GMT-10', 'continents-cities');
+__('GMT-11', 'continents-cities');
+__('GMT-12', 'continents-cities');
+__('GMT-13', 'continents-cities');
+__('GMT-14', 'continents-cities');
+__('GMT-2', 'continents-cities');
+__('GMT-3', 'continents-cities');
+__('GMT-4', 'continents-cities');
+__('GMT-5', 'continents-cities');
+__('GMT-6', 'continents-cities');
+__('GMT-7', 'continents-cities');
+__('GMT-8', 'continents-cities');
+__('GMT-9', 'continents-cities');
+__('GMT0', 'continents-cities');
+__('Greenwich', 'continents-cities');
+__('UCT', 'continents-cities');
+__('Universal', 'continents-cities');
+__('UTC', 'continents-cities');
+__('Zulu', 'continents-cities');
+__('Europe', 'continents-cities');
+__('Amsterdam', 'continents-cities');
+__('Andorra', 'continents-cities');
+__('Athens', 'continents-cities');
+__('Belfast', 'continents-cities');
+__('Belgrade', 'continents-cities');
+__('Berlin', 'continents-cities');
+__('Bratislava', 'continents-cities');
+__('Brussels', 'continents-cities');
+__('Bucharest', 'continents-cities');
+__('Budapest', 'continents-cities');
+__('Chisinau', 'continents-cities');
+__('Copenhagen', 'continents-cities');
+__('Dublin', 'continents-cities');
+__('Gibraltar', 'continents-cities');
+__('Guernsey', 'continents-cities');
+__('Helsinki', 'continents-cities');
+__('Isle of Man', 'continents-cities');
+__('Jersey', 'continents-cities');
+__('Kaliningrad', 'continents-cities');
+__('Kiev', 'continents-cities');
+__('Lisbon', 'continents-cities');
+__('Ljubljana', 'continents-cities');
+__('London', 'continents-cities');
+__('Luxembourg', 'continents-cities');
+__('Madrid', 'continents-cities');
+__('Malta', 'continents-cities');
+__('Mariehamn', 'continents-cities');
+__('Minsk', 'continents-cities');
+__('Monaco', 'continents-cities');
+__('Moscow', 'continents-cities');
+__('Oslo', 'continents-cities');
+__('Paris', 'continents-cities');
+__('Podgorica', 'continents-cities');
+__('Prague', 'continents-cities');
+__('Riga', 'continents-cities');
+__('Rome', 'continents-cities');
+__('Samara', 'continents-cities');
+__('San Marino', 'continents-cities');
+__('Sarajevo', 'continents-cities');
+__('Simferopol', 'continents-cities');
+__('Skopje', 'continents-cities');
+__('Sofia', 'continents-cities');
+__('Stockholm', 'continents-cities');
+__('Tallinn', 'continents-cities');
+__('Tirane', 'continents-cities');
+__('Tiraspol', 'continents-cities');
+__('Uzhgorod', 'continents-cities');
+__('Vaduz', 'continents-cities');
+__('Vatican', 'continents-cities');
+__('Vienna', 'continents-cities');
+__('Vilnius', 'continents-cities');
+__('Volgograd', 'continents-cities');
+__('Warsaw', 'continents-cities');
+__('Zagreb', 'continents-cities');
+__('Zaporozhye', 'continents-cities');
+__('Zurich', 'continents-cities');
+__('Indian', 'continents-cities');
+__('Antananarivo', 'continents-cities');
+__('Chagos', 'continents-cities');
+__('Christmas', 'continents-cities');
+__('Cocos', 'continents-cities');
+__('Comoro', 'continents-cities');
+__('Kerguelen', 'continents-cities');
+__('Mahe', 'continents-cities');
+__('Maldives', 'continents-cities');
+__('Mauritius', 'continents-cities');
+__('Mayotte', 'continents-cities');
+__('Reunion', 'continents-cities');
+__('Pacific', 'continents-cities');
+__('Apia', 'continents-cities');
+__('Auckland', 'continents-cities');
+__('Chatham', 'continents-cities');
+__('Easter', 'continents-cities');
+__('Efate', 'continents-cities');
+__('Enderbury', 'continents-cities');
+__('Fakaofo', 'continents-cities');
+__('Fiji', 'continents-cities');
+__('Funafuti', 'continents-cities');
+__('Galapagos', 'continents-cities');
+__('Gambier', 'continents-cities');
+__('Guadalcanal', 'continents-cities');
+__('Guam', 'continents-cities');
+__('Honolulu', 'continents-cities');
+__('Johnston', 'continents-cities');
+__('Kiritimati', 'continents-cities');
+__('Kosrae', 'continents-cities');
+__('Kwajalein', 'continents-cities');
+__('Majuro', 'continents-cities');
+__('Marquesas', 'continents-cities');
+__('Midway', 'continents-cities');
+__('Nauru', 'continents-cities');
+__('Niue', 'continents-cities');
+__('Norfolk', 'continents-cities');
+__('Noumea', 'continents-cities');
+__('Pago Pago', 'continents-cities');
+__('Palau', 'continents-cities');
+__('Pitcairn', 'continents-cities');
+__('Ponape', 'continents-cities');
+__('Port Moresby', 'continents-cities');
+__('Rarotonga', 'continents-cities');
+__('Saipan', 'continents-cities');
+__('Samoa', 'continents-cities');
+__('Tahiti', 'continents-cities');
+__('Tarawa', 'continents-cities');
+__('Tongatapu', 'continents-cities');
+__('Truk', 'continents-cities');
+__('Wake', 'continents-cities');
+__('Wallis', 'continents-cities');
+__('Yap', 'continents-cities');
diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php
new file mode 100644
index 0000000000..657402f942
--- /dev/null
+++ b/src/wp-admin/includes/dashboard.php
@@ -0,0 +1,1307 @@
+<?php
+/**
+ * WordPress Dashboard Widget Administration Screen API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Registers dashboard widgets.
+ *
+ * Handles POST data, sets up filters.
+ *
+ * @since 2.5.0
+ */
+function wp_dashboard_setup() {
+ global $wp_registered_widgets, $wp_registered_widget_controls, $wp_dashboard_control_callbacks;
+ $wp_dashboard_control_callbacks = array();
+ $screen = get_current_screen();
+
+ $update = false;
+ $widget_options = get_option( 'dashboard_widget_options' );
+ if ( !$widget_options || !is_array($widget_options) )
+ $widget_options = array();
+
+ /* Register Widgets and Controls */
+
+ $response = wp_check_browser_version();
+
+ if ( $response && $response['upgrade'] ) {
+ add_filter( 'postbox_classes_dashboard_dashboard_browser_nag', 'dashboard_browser_nag_class' );
+ if ( $response['insecure'] )
+ wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'You are using an insecure browser!' ), 'wp_dashboard_browser_nag' );
+ else
+ wp_add_dashboard_widget( 'dashboard_browser_nag', __( 'Your browser is out of date!' ), 'wp_dashboard_browser_nag' );
+ }
+
+ // Right Now
+ if ( is_blog_admin() && current_user_can('edit_posts') )
+ wp_add_dashboard_widget( 'dashboard_right_now', __( 'Right Now' ), 'wp_dashboard_right_now' );
+
+ if ( is_network_admin() )
+ wp_add_dashboard_widget( 'network_dashboard_right_now', __( 'Right Now' ), 'wp_network_dashboard_right_now' );
+
+ // Recent Comments Widget
+ if ( is_blog_admin() && current_user_can('moderate_comments') ) {
+ if ( !isset( $widget_options['dashboard_recent_comments'] ) || !isset( $widget_options['dashboard_recent_comments']['items'] ) ) {
+ $update = true;
+ $widget_options['dashboard_recent_comments'] = array(
+ 'items' => 5,
+ );
+ }
+ $recent_comments_title = __( 'Recent Comments' );
+ wp_add_dashboard_widget( 'dashboard_recent_comments', $recent_comments_title, 'wp_dashboard_recent_comments', 'wp_dashboard_recent_comments_control' );
+ }
+
+ // Incoming Links Widget
+ if ( is_blog_admin() && current_user_can('publish_posts') ) {
+ if ( !isset( $widget_options['dashboard_incoming_links'] ) || !isset( $widget_options['dashboard_incoming_links']['home'] ) || $widget_options['dashboard_incoming_links']['home'] != get_option('home') ) {
+ $update = true;
+ $num_items = isset($widget_options['dashboard_incoming_links']['items']) ? $widget_options['dashboard_incoming_links']['items'] : 10;
+ $widget_options['dashboard_incoming_links'] = array(
+ 'home' => get_option('home'),
+ 'link' => apply_filters( 'dashboard_incoming_links_link', 'http://blogsearch.google.com/blogsearch?scoring=d&partner=wordpress&q=link:' . trailingslashit( get_option('home') ) ),
+ 'url' => isset($widget_options['dashboard_incoming_links']['url']) ? apply_filters( 'dashboard_incoming_links_feed', $widget_options['dashboard_incoming_links']['url'] ) : apply_filters( 'dashboard_incoming_links_feed', 'http://blogsearch.google.com/blogsearch_feeds?scoring=d&ie=utf-8&num=' . $num_items . '&output=rss&partner=wordpress&q=link:' . trailingslashit( get_option('home') ) ),
+ 'items' => $num_items,
+ 'show_date' => isset($widget_options['dashboard_incoming_links']['show_date']) ? $widget_options['dashboard_incoming_links']['show_date'] : false
+ );
+ }
+ wp_add_dashboard_widget( 'dashboard_incoming_links', __( 'Incoming Links' ), 'wp_dashboard_incoming_links', 'wp_dashboard_incoming_links_control' );
+ }
+
+ // WP Plugins Widget
+ if ( ( ! is_multisite() && is_blog_admin() && current_user_can( 'install_plugins' ) ) || ( is_network_admin() && current_user_can( 'manage_network_plugins' ) && current_user_can( 'install_plugins' ) ) )
+ wp_add_dashboard_widget( 'dashboard_plugins', __( 'Plugins' ), 'wp_dashboard_plugins' );
+
+ // QuickPress Widget
+ if ( is_blog_admin() && current_user_can('edit_posts') )
+ wp_add_dashboard_widget( 'dashboard_quick_press', __( 'QuickPress' ), 'wp_dashboard_quick_press' );
+
+ // Recent Drafts
+ if ( is_blog_admin() && current_user_can('edit_posts') )
+ wp_add_dashboard_widget( 'dashboard_recent_drafts', __('Recent Drafts'), 'wp_dashboard_recent_drafts' );
+
+ // Primary feed (Dev Blog) Widget
+ if ( !isset( $widget_options['dashboard_primary'] ) ) {
+ $update = true;
+ $widget_options['dashboard_primary'] = array(
+ 'link' => apply_filters( 'dashboard_primary_link', __( 'http://wordpress.org/news/' ) ),
+ 'url' => apply_filters( 'dashboard_primary_feed', __( 'http://wordpress.org/news/feed/' ) ),
+ 'title' => apply_filters( 'dashboard_primary_title', __( 'WordPress Blog' ) ),
+ 'items' => 2,
+ 'show_summary' => 1,
+ 'show_author' => 0,
+ 'show_date' => 1,
+ );
+ }
+ wp_add_dashboard_widget( 'dashboard_primary', $widget_options['dashboard_primary']['title'], 'wp_dashboard_primary', 'wp_dashboard_primary_control' );
+
+ // Secondary Feed (Planet) Widget
+ if ( !isset( $widget_options['dashboard_secondary'] ) ) {
+ $update = true;
+ $widget_options['dashboard_secondary'] = array(
+ 'link' => apply_filters( 'dashboard_secondary_link', __( 'http://planet.wordpress.org/' ) ),
+ 'url' => apply_filters( 'dashboard_secondary_feed', __( 'http://planet.wordpress.org/feed/' ) ),
+ 'title' => apply_filters( 'dashboard_secondary_title', __( 'Other WordPress News' ) ),
+ 'items' => 5,
+ 'show_summary' => 0,
+ 'show_author' => 0,
+ 'show_date' => 0,
+ );
+ }
+ wp_add_dashboard_widget( 'dashboard_secondary', $widget_options['dashboard_secondary']['title'], 'wp_dashboard_secondary', 'wp_dashboard_secondary_control' );
+
+ // Hook to register new widgets
+ // Filter widget order
+ if ( is_network_admin() ) {
+ do_action( 'wp_network_dashboard_setup' );
+ $dashboard_widgets = apply_filters( 'wp_network_dashboard_widgets', array() );
+ } elseif ( is_user_admin() ) {
+ do_action( 'wp_user_dashboard_setup' );
+ $dashboard_widgets = apply_filters( 'wp_user_dashboard_widgets', array() );
+ } else {
+ do_action( 'wp_dashboard_setup' );
+ $dashboard_widgets = apply_filters( 'wp_dashboard_widgets', array() );
+ }
+
+ foreach ( $dashboard_widgets as $widget_id ) {
+ $name = empty( $wp_registered_widgets[$widget_id]['all_link'] ) ? $wp_registered_widgets[$widget_id]['name'] : $wp_registered_widgets[$widget_id]['name'] . " <a href='{$wp_registered_widgets[$widget_id]['all_link']}' class='edit-box open-box'>" . __('View all') . '</a>';
+ wp_add_dashboard_widget( $widget_id, $name, $wp_registered_widgets[$widget_id]['callback'], $wp_registered_widget_controls[$widget_id]['callback'] );
+ }
+
+ if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget_id']) ) {
+ check_admin_referer( 'edit-dashboard-widget_' . $_POST['widget_id'], 'dashboard-widget-nonce' );
+ ob_start(); // hack - but the same hack wp-admin/widgets.php uses
+ wp_dashboard_trigger_widget_control( $_POST['widget_id'] );
+ ob_end_clean();
+ wp_redirect( remove_query_arg( 'edit' ) );
+ exit;
+ }
+
+ if ( $update )
+ update_option( 'dashboard_widget_options', $widget_options );
+
+ do_action('do_meta_boxes', $screen->id, 'normal', '');
+ do_action('do_meta_boxes', $screen->id, 'side', '');
+}
+
+function wp_add_dashboard_widget( $widget_id, $widget_name, $callback, $control_callback = null ) {
+ $screen = get_current_screen();
+ global $wp_dashboard_control_callbacks;
+
+ if ( $control_callback && current_user_can( 'edit_dashboard' ) && is_callable( $control_callback ) ) {
+ $wp_dashboard_control_callbacks[$widget_id] = $control_callback;
+ if ( isset( $_GET['edit'] ) && $widget_id == $_GET['edit'] ) {
+ list($url) = explode( '#', add_query_arg( 'edit', false ), 2 );
+ $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( $url ) . '">' . __( 'Cancel' ) . '</a></span>';
+ $callback = '_wp_dashboard_control_callback';
+ } else {
+ list($url) = explode( '#', add_query_arg( 'edit', $widget_id ), 2 );
+ $widget_name .= ' <span class="postbox-title-action"><a href="' . esc_url( "$url#$widget_id" ) . '" class="edit-box open-box">' . __( 'Configure' ) . '</a></span>';
+ }
+ }
+
+ if ( is_blog_admin () )
+ $side_widgets = array('dashboard_quick_press', 'dashboard_recent_drafts', 'dashboard_primary', 'dashboard_secondary');
+ else if (is_network_admin() )
+ $side_widgets = array('dashboard_primary', 'dashboard_secondary');
+ else
+ $side_widgets = array();
+
+ $location = 'normal';
+ if ( in_array($widget_id, $side_widgets) )
+ $location = 'side';
+
+ $priority = 'core';
+ if ( 'dashboard_browser_nag' === $widget_id )
+ $priority = 'high';
+
+ add_meta_box( $widget_id, $widget_name, $callback, $screen, $location, $priority );
+}
+
+function _wp_dashboard_control_callback( $dashboard, $meta_box ) {
+ echo '<form action="" method="post" class="dashboard-widget-control-form">';
+ wp_dashboard_trigger_widget_control( $meta_box['id'] );
+ wp_nonce_field( 'edit-dashboard-widget_' . $meta_box['id'], 'dashboard-widget-nonce' );
+ echo '<input type="hidden" name="widget_id" value="' . esc_attr($meta_box['id']) . '" />';
+ submit_button( __('Submit') );
+ echo '</form>';
+}
+
+/**
+ * Displays the dashboard.
+ *
+ * @since 2.5.0
+ */
+function wp_dashboard() {
+ $screen = get_current_screen();
+ $class = 'columns-' . get_current_screen()->get_columns();
+
+?>
+<div id="dashboard-widgets" class="metabox-holder <?php echo $class; ?>">
+ <div id='postbox-container-1' class='postbox-container'>
+ <?php do_meta_boxes( $screen->id, 'normal', '' ); ?>
+ </div>
+ <div id='postbox-container-2' class='postbox-container'>
+ <?php do_meta_boxes( $screen->id, 'side', '' ); ?>
+ </div>
+ <div id='postbox-container-3' class='postbox-container'>
+ <?php do_meta_boxes( $screen->id, 'column3', '' ); ?>
+ </div>
+ <div id='postbox-container-4' class='postbox-container'>
+ <?php do_meta_boxes( $screen->id, 'column4', '' ); ?>
+ </div>
+</div>
+
+<?php
+ wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
+ wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
+
+}
+
+/* Dashboard Widgets */
+
+function wp_dashboard_right_now() {
+ global $wp_registered_sidebars;
+
+ $num_posts = wp_count_posts( 'post' );
+ $num_pages = wp_count_posts( 'page' );
+
+ $num_cats = wp_count_terms('category');
+
+ $num_tags = wp_count_terms('post_tag');
+
+ $num_comm = wp_count_comments();
+
+ echo "\n\t".'<div class="table table_content">';
+ echo "\n\t".'<p class="sub">' . __('Content') . '</p>'."\n\t".'<table>';
+ echo "\n\t".'<tr class="first">';
+
+ // Posts
+ $num = number_format_i18n( $num_posts->publish );
+ $text = _n( 'Post', 'Posts', intval($num_posts->publish) );
+ if ( current_user_can( 'edit_posts' ) ) {
+ $num = "<a href='edit.php'>$num</a>";
+ $text = "<a href='edit.php'>$text</a>";
+ }
+ echo '<td class="first b b-posts">' . $num . '</td>';
+ echo '<td class="t posts">' . $text . '</td>';
+
+ echo '</tr><tr>';
+ /* TODO: Show status breakdown on hover
+ if ( $can_edit_pages && !empty($num_pages->publish) ) { // how many pages is not exposed in feeds. Don't show if !current_user_can
+ $post_type_texts[] = '<a href="edit-pages.php">'.sprintf( _n( '%s page', '%s pages', $num_pages->publish ), number_format_i18n( $num_pages->publish ) ).'</a>';
+ }
+ if ( $can_edit_posts && !empty($num_posts->draft) ) {
+ $post_type_texts[] = '<a href="edit.php?post_status=draft">'.sprintf( _n( '%s draft', '%s drafts', $num_posts->draft ), number_format_i18n( $num_posts->draft ) ).'</a>';
+ }
+ if ( $can_edit_posts && !empty($num_posts->future) ) {
+ $post_type_texts[] = '<a href="edit.php?post_status=future">'.sprintf( _n( '%s scheduled post', '%s scheduled posts', $num_posts->future ), number_format_i18n( $num_posts->future ) ).'</a>';
+ }
+ if ( current_user_can('publish_posts') && !empty($num_posts->pending) ) {
+ $pending_text = sprintf( _n( 'There is <a href="%1$s">%2$s post</a> pending your review.', 'There are <a href="%1$s">%2$s posts</a> pending your review.', $num_posts->pending ), 'edit.php?post_status=pending', number_format_i18n( $num_posts->pending ) );
+ } else {
+ $pending_text = '';
+ }
+ */
+
+ // Pages
+ $num = number_format_i18n( $num_pages->publish );
+ $text = _n( 'Page', 'Pages', $num_pages->publish );
+ if ( current_user_can( 'edit_pages' ) ) {
+ $num = "<a href='edit.php?post_type=page'>$num</a>";
+ $text = "<a href='edit.php?post_type=page'>$text</a>";
+ }
+ echo '<td class="first b b_pages">' . $num . '</td>';
+ echo '<td class="t pages">' . $text . '</td>';
+
+ echo '</tr><tr>';
+
+ // Categories
+ $num = number_format_i18n( $num_cats );
+ $text = _n( 'Category', 'Categories', $num_cats );
+ if ( current_user_can( 'manage_categories' ) ) {
+ $num = "<a href='edit-tags.php?taxonomy=category'>$num</a>";
+ $text = "<a href='edit-tags.php?taxonomy=category'>$text</a>";
+ }
+ echo '<td class="first b b-cats">' . $num . '</td>';
+ echo '<td class="t cats">' . $text . '</td>';
+
+ echo '</tr><tr>';
+
+ // Tags
+ $num = number_format_i18n( $num_tags );
+ $text = _n( 'Tag', 'Tags', $num_tags );
+ if ( current_user_can( 'manage_categories' ) ) {
+ $num = "<a href='edit-tags.php'>$num</a>";
+ $text = "<a href='edit-tags.php'>$text</a>";
+ }
+ echo '<td class="first b b-tags">' . $num . '</td>';
+ echo '<td class="t tags">' . $text . '</td>';
+
+ echo "</tr>";
+ do_action('right_now_content_table_end');
+ echo "\n\t</table>\n\t</div>";
+
+ echo "\n\t".'<div class="table table_discussion">';
+ echo "\n\t".'<p class="sub">' . __('Discussion') . '</p>'."\n\t".'<table>';
+ echo "\n\t".'<tr class="first">';
+
+ // Total Comments
+ $num = '<span class="total-count">' . number_format_i18n($num_comm->total_comments) . '</span>';
+ $text = _n( 'Comment', 'Comments', $num_comm->total_comments );
+ if ( current_user_can( 'moderate_comments' ) ) {
+ $num = '<a href="edit-comments.php">' . $num . '</a>';
+ $text = '<a href="edit-comments.php">' . $text . '</a>';
+ }
+ echo '<td class="b b-comments">' . $num . '</td>';
+ echo '<td class="last t comments">' . $text . '</td>';
+
+ echo '</tr><tr>';
+
+ // Approved Comments
+ $num = '<span class="approved-count">' . number_format_i18n($num_comm->approved) . '</span>';
+ $text = _nx( 'Approved', 'Approved', $num_comm->approved, 'Right Now' );
+ if ( current_user_can( 'moderate_comments' ) ) {
+ $num = "<a href='edit-comments.php?comment_status=approved'>$num</a>";
+ $text = "<a class='approved' href='edit-comments.php?comment_status=approved'>$text</a>";
+ }
+ echo '<td class="b b_approved">' . $num . '</td>';
+ echo '<td class="last t">' . $text . '</td>';
+
+ echo "</tr>\n\t<tr>";
+
+ // Pending Comments
+ $num = '<span class="pending-count">' . number_format_i18n($num_comm->moderated) . '</span>';
+ $text = _n( 'Pending', 'Pending', $num_comm->moderated );
+ if ( current_user_can( 'moderate_comments' ) ) {
+ $num = "<a href='edit-comments.php?comment_status=moderated'>$num</a>";
+ $text = "<a class='waiting' href='edit-comments.php?comment_status=moderated'>$text</a>";
+ }
+ echo '<td class="b b-waiting">' . $num . '</td>';
+ echo '<td class="last t">' . $text . '</td>';
+
+ echo "</tr>\n\t<tr>";
+
+ // Spam Comments
+ $num = number_format_i18n($num_comm->spam);
+ $text = _nx( 'Spam', 'Spam', $num_comm->spam, 'comment' );
+ if ( current_user_can( 'moderate_comments' ) ) {
+ $num = "<a href='edit-comments.php?comment_status=spam'><span class='spam-count'>$num</span></a>";
+ $text = "<a class='spam' href='edit-comments.php?comment_status=spam'>$text</a>";
+ }
+ echo '<td class="b b-spam">' . $num . '</td>';
+ echo '<td class="last t">' . $text . '</td>';
+
+ echo "</tr>";
+ do_action('right_now_table_end');
+ do_action('right_now_discussion_table_end');
+ echo "\n\t</table>\n\t</div>";
+
+ echo "\n\t".'<div class="versions">';
+ $theme = wp_get_theme();
+
+ echo "\n\t<p>";
+
+ if ( $theme->errors() ) {
+ if ( ! is_multisite() || is_super_admin() )
+ echo '<span class="error-message">' . __('ERROR: The themes directory is either empty or doesn&#8217;t exist. Please check your installation.') . '</span>';
+ } elseif ( ! empty($wp_registered_sidebars) ) {
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ $num_widgets = 0;
+ foreach ( (array) $sidebars_widgets as $k => $v ) {
+ if ( 'wp_inactive_widgets' == $k || 'orphaned_widgets' == substr( $k, 0, 16 ) )
+ continue;
+ if ( is_array($v) )
+ $num_widgets = $num_widgets + count($v);
+ }
+ $num = number_format_i18n( $num_widgets );
+
+ $switch_themes = $theme->display('Name');
+ if ( current_user_can( 'switch_themes') )
+ $switch_themes = '<a href="themes.php">' . $switch_themes . '</a>';
+ if ( current_user_can( 'edit_theme_options' ) ) {
+ printf(_n('Theme <span class="b">%1$s</span> with <span class="b"><a href="widgets.php">%2$s Widget</a></span>', 'Theme <span class="b">%1$s</span> with <span class="b"><a href="widgets.php">%2$s Widgets</a></span>', $num_widgets), $switch_themes, $num);
+ } else {
+ printf(_n('Theme <span class="b">%1$s</span> with <span class="b">%2$s Widget</span>', 'Theme <span class="b">%1$s</span> with <span class="b">%2$s Widgets</span>', $num_widgets), $switch_themes, $num);
+ }
+ } else {
+ if ( current_user_can( 'switch_themes' ) )
+ printf( __('Theme <span class="b"><a href="themes.php">%1$s</a></span>'), $theme->display('Name') );
+ else
+ printf( __('Theme <span class="b">%1$s</span>'), $theme->display('Name') );
+ }
+ echo '</p>';
+
+ // Check if search engines are asked not to index this site.
+ if ( !is_network_admin() && !is_user_admin() && current_user_can('manage_options') && '1' != get_option('blog_public') ) {
+ $title = apply_filters('privacy_on_link_title', __('Your site is asking search engines not to index its content') );
+ $content = apply_filters('privacy_on_link_text', __('Search Engines Discouraged') );
+
+ echo "<p><a href='options-reading.php' title='$title'>$content</a></p>";
+ }
+
+ update_right_now_message();
+
+ echo "\n\t".'<br class="clear" /></div>';
+ do_action( 'rightnow_end' );
+ do_action( 'activity_box_end' );
+}
+
+function wp_network_dashboard_right_now() {
+ $actions = array();
+ if ( current_user_can('create_sites') )
+ $actions['create-site'] = '<a href="' . network_admin_url('site-new.php') . '">' . __( 'Create a New Site' ) . '</a>';
+ if ( current_user_can('create_users') )
+ $actions['create-user'] = '<a href="' . network_admin_url('user-new.php') . '">' . __( 'Create a New User' ) . '</a>';
+
+ $c_users = get_user_count();
+ $c_blogs = get_blog_count();
+
+ $user_text = sprintf( _n( '%s user', '%s users', $c_users ), number_format_i18n( $c_users ) );
+ $blog_text = sprintf( _n( '%s site', '%s sites', $c_blogs ), number_format_i18n( $c_blogs ) );
+
+ $sentence = sprintf( __( 'You have %1$s and %2$s.' ), $blog_text, $user_text );
+
+ if ( $actions ) {
+ echo '<ul class="subsubsub">';
+ foreach ( $actions as $class => $action ) {
+ $actions[ $class ] = "\t<li class='$class'>$action";
+ }
+ echo implode( " |</li>\n", $actions ) . "</li>\n";
+ echo '</ul>';
+ }
+?>
+ <br class="clear" />
+
+ <p class="youhave"><?php echo $sentence; ?></p>
+ <?php do_action( 'wpmuadminresult', '' ); ?>
+
+ <form action="<?php echo network_admin_url('users.php'); ?>" method="get">
+ <p>
+ <input type="search" name="s" value="" size="30" autocomplete="off" />
+ <?php submit_button( __( 'Search Users' ), 'button', 'submit', false, array( 'id' => 'submit_users' ) ); ?>
+ </p>
+ </form>
+
+ <form action="<?php echo network_admin_url('sites.php'); ?>" method="get">
+ <p>
+ <input type="search" name="s" value="" size="30" autocomplete="off" />
+ <?php submit_button( __( 'Search Sites' ), 'button', 'submit', false, array( 'id' => 'submit_sites' ) ); ?>
+ </p>
+ </form>
+<?php
+ do_action( 'mu_rightnow_end' );
+ do_action( 'mu_activity_box_end' );
+}
+
+function wp_dashboard_quick_press() {
+ global $post_ID;
+
+ $drafts = false;
+ if ( 'post' === strtolower( $_SERVER['REQUEST_METHOD'] ) && isset( $_POST['action'] ) && 0 === strpos( $_POST['action'], 'post-quickpress' ) && (int) $_POST['post_ID'] ) {
+ $view = get_permalink( $_POST['post_ID'] );
+ $edit = esc_url( get_edit_post_link( $_POST['post_ID'] ) );
+ if ( 'post-quickpress-publish' == $_POST['action'] ) {
+ if ( current_user_can('publish_posts') )
+ printf( '<div class="updated"><p>' . __( 'Post published. <a href="%s">View post</a> | <a href="%s">Edit post</a>' ) . '</p></div>', esc_url( $view ), $edit );
+ else
+ printf( '<div class="updated"><p>' . __( 'Post submitted. <a href="%s">Preview post</a> | <a href="%s">Edit post</a>' ) . '</p></div>', esc_url( add_query_arg( 'preview', 1, $view ) ), $edit );
+ } else {
+ printf( '<div class="updated"><p>' . __( 'Draft saved. <a href="%s">Preview post</a> | <a href="%s">Edit post</a>' ) . '</p></div>', esc_url( add_query_arg( 'preview', 1, $view ) ), $edit );
+ $drafts_query = new WP_Query( array(
+ 'post_type' => 'post',
+ 'post_status' => 'draft',
+ 'author' => $GLOBALS['current_user']->ID,
+ 'posts_per_page' => 1,
+ 'orderby' => 'modified',
+ 'order' => 'DESC'
+ ) );
+
+ if ( $drafts_query->posts )
+ $drafts =& $drafts_query->posts;
+ }
+ printf('<p class="easy-blogging">' . __('You can also try %s, easy blogging from anywhere on the Web.') . '</p>', '<a href="' . esc_url( admin_url( 'tools.php' ) ) . '">' . __('Press This') . '</a>' );
+ $_REQUEST = array(); // hack for get_default_post_to_edit()
+ }
+
+ /* Check if a new auto-draft (= no new post_ID) is needed or if the old can be used */
+ $last_post_id = (int) get_user_option( 'dashboard_quick_press_last_post_id' ); // Get the last post_ID
+ if ( $last_post_id ) {
+ $post = get_post( $last_post_id );
+ if ( empty( $post ) || $post->post_status != 'auto-draft' ) { // auto-draft doesn't exists anymore
+ $post = get_default_post_to_edit('post', true);
+ update_user_option( get_current_user_id(), 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID
+ } else {
+ $post->post_title = ''; // Remove the auto draft title
+ }
+ } else {
+ $post = get_default_post_to_edit( 'post' , true);
+ $user_id = get_current_user_id();
+ // Don't create an option if this is a super admin who does not belong to this site.
+ if ( ! ( is_super_admin( $user_id ) && ! in_array( get_current_blog_id(), array_keys( get_blogs_of_user( $user_id ) ) ) ) )
+ update_user_option( $user_id, 'dashboard_quick_press_last_post_id', (int) $post->ID ); // Save post_ID
+ }
+
+ $post_ID = (int) $post->ID;
+
+ $media_settings = array(
+ 'id' => $post->ID,
+ 'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
+ );
+
+ if ( current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' ) ) {
+ $featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
+ $media_settings['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
+ }
+?>
+
+ <form name="post" action="<?php echo esc_url( admin_url( 'post.php' ) ); ?>" method="post" id="quick-press">
+ <div class="input-text-wrap" id="title-wrap">
+ <label class="screen-reader-text prompt" for="title" id="title-prompt-text"><?php _e( 'Enter title here' ); ?></label>
+ <input type="text" name="post_title" id="title" autocomplete="off" value="<?php echo esc_attr( $post->post_title ); ?>" />
+ </div>
+
+ <?php if ( current_user_can( 'upload_files' ) ) : ?>
+ <div id="wp-content-wrap" class="wp-editor-wrap hide-if-no-js wp-media-buttons">
+ <?php do_action( 'media_buttons', 'content' ); ?>
+ </div>
+ <?php endif; ?>
+
+ <div class="textarea-wrap">
+ <label class="screen-reader-text" for="content"><?php _e( 'Content' ); ?></label>
+ <textarea name="content" id="content" class="mceEditor" rows="3" cols="15"><?php echo esc_textarea( $post->post_content ); ?></textarea>
+ </div>
+
+ <script type="text/javascript">
+ edCanvas = document.getElementById('content');
+ edInsertContent = null;
+ <?php if ( $_POST ) : ?>
+ wp.media.editor.remove('content');
+ wp.media.view.settings.post = <?php echo json_encode( $media_settings ); // big juicy hack. ?>;
+ wp.media.editor.add('content');
+ <?php endif; ?>
+ </script>
+
+ <div class="input-text-wrap" id="tags-input-wrap">
+ <label class="screen-reader-text prompt" for="tags-input" id="tags-input-prompt-text"><?php _e( 'Tags (separate with commas)' ); ?></label>
+ <input type="text" name="tags_input" id="tags-input" value="<?php echo get_tags_to_edit( $post->ID ); ?>" />
+ </div>
+
+ <p class="submit">
+ <span id="publishing-action">
+ <input type="submit" name="publish" id="publish" accesskey="p" class="button-primary" value="<?php current_user_can('publish_posts') ? esc_attr_e('Publish') : esc_attr_e('Submit for Review'); ?>" />
+ <span class="spinner"></span>
+ </span>
+ <input type="hidden" name="action" id="quickpost-action" value="post-quickpress-save" />
+ <input type="hidden" name="post_ID" value="<?php echo $post_ID; ?>" />
+ <input type="hidden" name="post_type" value="post" />
+ <?php wp_nonce_field('add-post'); ?>
+ <?php submit_button( __( 'Save Draft' ), 'button', 'save', false, array( 'id' => 'save-post' ) ); ?>
+ <input type="reset" value="<?php esc_attr_e( 'Reset' ); ?>" class="button" />
+ <br class="clear" />
+ </p>
+
+ </form>
+
+<?php
+ if ( $drafts )
+ wp_dashboard_recent_drafts( $drafts );
+}
+
+function wp_dashboard_recent_drafts( $drafts = false ) {
+ if ( !$drafts ) {
+ $drafts_query = new WP_Query( array(
+ 'post_type' => 'post',
+ 'post_status' => 'draft',
+ 'author' => $GLOBALS['current_user']->ID,
+ 'posts_per_page' => 5,
+ 'orderby' => 'modified',
+ 'order' => 'DESC'
+ ) );
+ $drafts =& $drafts_query->posts;
+ }
+
+ if ( $drafts && is_array( $drafts ) ) {
+ $list = array();
+ foreach ( $drafts as $draft ) {
+ $url = get_edit_post_link( $draft->ID );
+ $title = _draft_or_post_title( $draft->ID );
+ $item = "<h4><a href='$url' title='" . sprintf( __( 'Edit &#8220;%s&#8221;' ), esc_attr( $title ) ) . "'>" . esc_html($title) . "</a> <abbr title='" . get_the_time(__('Y/m/d g:i:s A'), $draft) . "'>" . get_the_time( get_option( 'date_format' ), $draft ) . '</abbr></h4>';
+ if ( $the_content = wp_trim_words( $draft->post_content, 10 ) )
+ $item .= '<p>' . $the_content . '</p>';
+ $list[] = $item;
+ }
+?>
+ <ul>
+ <li><?php echo join( "</li>\n<li>", $list ); ?></li>
+ </ul>
+ <p class="textright"><a href="edit.php?post_status=draft" ><?php _e('View all'); ?></a></p>
+<?php
+ } else {
+ _e('There are no drafts at the moment');
+ }
+}
+
+/**
+ * Display recent comments dashboard widget content.
+ *
+ * @since 2.5.0
+ */
+function wp_dashboard_recent_comments() {
+ global $wpdb;
+
+ // Select all comment types and filter out spam later for better query performance.
+ $comments = array();
+ $start = 0;
+
+ $widgets = get_option( 'dashboard_widget_options' );
+ $total_items = isset( $widgets['dashboard_recent_comments'] ) && isset( $widgets['dashboard_recent_comments']['items'] )
+ ? absint( $widgets['dashboard_recent_comments']['items'] ) : 5;
+
+ $comments_query = array( 'number' => $total_items * 5, 'offset' => 0 );
+ if ( ! current_user_can( 'edit_posts' ) )
+ $comments_query['status'] = 'approve';
+
+ while ( count( $comments ) < $total_items && $possible = get_comments( $comments_query ) ) {
+ foreach ( $possible as $comment ) {
+ if ( ! current_user_can( 'read_post', $comment->comment_post_ID ) )
+ continue;
+ $comments[] = $comment;
+ if ( count( $comments ) == $total_items )
+ break 2;
+ }
+ $comments_query['offset'] += $comments_query['number'];
+ $comments_query['number'] = $total_items * 10;
+ }
+
+ if ( $comments ) {
+ echo '<div id="the-comment-list" data-wp-lists="list:comment">';
+ foreach ( $comments as $comment )
+ _wp_dashboard_recent_comments_row( $comment );
+ echo '</div>';
+
+ if ( current_user_can('edit_posts') )
+ _get_list_table('WP_Comments_List_Table')->views();
+
+ wp_comment_reply( -1, false, 'dashboard', false );
+ wp_comment_trashnotice();
+ } else {
+ echo '<p>' . __( 'No comments yet.' ) . '</p>';
+ }
+}
+
+function _wp_dashboard_recent_comments_row( &$comment, $show_date = true ) {
+ $GLOBALS['comment'] =& $comment;
+
+ $comment_post_url = get_edit_post_link( $comment->comment_post_ID );
+ $comment_post_title = strip_tags(get_the_title( $comment->comment_post_ID ));
+ $comment_post_link = "<a href='$comment_post_url'>$comment_post_title</a>";
+ $comment_link = '<a class="comment-link" href="' . esc_url(get_comment_link()) . '">#</a>';
+
+ $actions_string = '';
+ if ( current_user_can( 'edit_comment', $comment->comment_ID ) ) {
+ // preorder it: Approve | Reply | Edit | Spam | Trash
+ $actions = array(
+ 'approve' => '', 'unapprove' => '',
+ 'reply' => '',
+ 'edit' => '',
+ 'spam' => '',
+ 'trash' => '', 'delete' => ''
+ );
+
+ $del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
+ $approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
+
+ $approve_url = esc_url( "comment.php?action=approvecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$approve_nonce" );
+ $unapprove_url = esc_url( "comment.php?action=unapprovecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$approve_nonce" );
+ $spam_url = esc_url( "comment.php?action=spamcomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
+ $trash_url = esc_url( "comment.php?action=trashcomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
+ $delete_url = esc_url( "comment.php?action=deletecomment&p=$comment->comment_post_ID&c=$comment->comment_ID&$del_nonce" );
+
+ $actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' title='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
+ $actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' title='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
+ $actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' title='" . esc_attr__('Edit comment') . "'>". __('Edit') . '</a>';
+ $actions['reply'] = '<a onclick="commentReply.open(\''.$comment->comment_ID.'\',\''.$comment->comment_post_ID.'\');return false;" class="vim-r hide-if-no-js" title="'.esc_attr__('Reply to this comment').'" href="#">' . __('Reply') . '</a>';
+ $actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' title='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
+ if ( !EMPTY_TRASH_DAYS )
+ $actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive'>" . __('Delete Permanently') . '</a>';
+ else
+ $actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' title='" . esc_attr__( 'Move this comment to the trash' ) . "'>" . _x('Trash', 'verb') . '</a>';
+
+ $actions = apply_filters( 'comment_row_actions', array_filter($actions), $comment );
+
+ $i = 0;
+ foreach ( $actions as $action => $link ) {
+ ++$i;
+ ( ( ('approve' == $action || 'unapprove' == $action) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
+
+ // Reply and quickedit need a hide-if-no-js span
+ if ( 'reply' == $action || 'quickedit' == $action )
+ $action .= ' hide-if-no-js';
+
+ $actions_string .= "<span class='$action'>$sep$link</span>";
+ }
+ }
+
+?>
+
+ <div id="comment-<?php echo $comment->comment_ID; ?>" <?php comment_class( array( 'comment-item', wp_get_comment_status($comment->comment_ID) ) ); ?>>
+ <?php if ( !$comment->comment_type || 'comment' == $comment->comment_type ) : ?>
+
+ <?php echo get_avatar( $comment, 50 ); ?>
+
+ <div class="dashboard-comment-wrap">
+ <h4 class="comment-meta">
+ <?php printf( /* translators: 1: comment author, 2: post link, 3: notification if the comment is pending */__( 'From %1$s on %2$s%3$s' ),
+ '<cite class="comment-author">' . get_comment_author_link() . '</cite>', $comment_post_link.' '.$comment_link, ' <span class="approve">' . __( '[Pending]' ) . '</span>' ); ?>
+ </h4>
+
+ <?php
+ else :
+ switch ( $comment->comment_type ) :
+ case 'pingback' :
+ $type = __( 'Pingback' );
+ break;
+ case 'trackback' :
+ $type = __( 'Trackback' );
+ break;
+ default :
+ $type = ucwords( $comment->comment_type );
+ endswitch;
+ $type = esc_html( $type );
+ ?>
+ <div class="dashboard-comment-wrap">
+ <?php /* translators: %1$s is type of comment, %2$s is link to the post */ ?>
+ <h4 class="comment-meta"><?php printf( _x( '%1$s on %2$s', 'dashboard' ), "<strong>$type</strong>", $comment_post_link." ".$comment_link ); ?></h4>
+ <p class="comment-author"><?php comment_author_link(); ?></p>
+
+ <?php endif; // comment_type ?>
+ <blockquote><p><?php comment_excerpt(); ?></p></blockquote>
+ <p class="row-actions"><?php echo $actions_string; ?></p>
+ </div>
+ </div>
+<?php
+}
+
+/**
+ * The recent comments dashboard widget control.
+ *
+ * @since 3.0.0
+ */
+function wp_dashboard_recent_comments_control() {
+ if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
+ $widget_options = array();
+
+ if ( !isset($widget_options['dashboard_recent_comments']) )
+ $widget_options['dashboard_recent_comments'] = array();
+
+ if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget-recent-comments']) ) {
+ $number = absint( $_POST['widget-recent-comments']['items'] );
+ $widget_options['dashboard_recent_comments']['items'] = $number;
+ update_option( 'dashboard_widget_options', $widget_options );
+ }
+
+ $number = isset( $widget_options['dashboard_recent_comments']['items'] ) ? (int) $widget_options['dashboard_recent_comments']['items'] : '';
+
+ echo '<p><label for="comments-number">' . __('Number of comments to show:') . '</label>';
+ echo '<input id="comments-number" name="widget-recent-comments[items]" type="text" value="' . $number . '" size="3" /></p>';
+}
+
+function wp_dashboard_incoming_links() {
+ wp_dashboard_cached_rss_widget( 'dashboard_incoming_links', 'wp_dashboard_incoming_links_output' );
+}
+
+/**
+ * Display incoming links dashboard widget content.
+ *
+ * @since 2.5.0
+ */
+function wp_dashboard_incoming_links_output() {
+ $widgets = get_option( 'dashboard_widget_options' );
+ @extract( @$widgets['dashboard_incoming_links'], EXTR_SKIP );
+ $rss = fetch_feed( $url );
+
+ if ( is_wp_error($rss) ) {
+ if ( is_admin() || current_user_can('manage_options') ) {
+ echo '<p>';
+ printf(__('<strong>RSS Error</strong>: %s'), $rss->get_error_message());
+ echo '</p>';
+ }
+ return;
+ }
+
+ if ( !$rss->get_item_quantity() ) {
+ echo '<p>' . __('This dashboard widget queries <a href="http://blogsearch.google.com/">Google Blog Search</a> so that when another blog links to your site it will show up here. It has found no incoming links&hellip; yet. It&#8217;s okay &#8212; there is no rush.') . "</p>\n";
+ $rss->__destruct();
+ unset($rss);
+ return;
+ }
+
+ echo "<ul>\n";
+
+ if ( !isset($items) )
+ $items = 10;
+
+ foreach ( $rss->get_items(0, $items) as $item ) {
+ $publisher = '';
+ $site_link = '';
+ $link = '';
+ $content = '';
+ $date = '';
+ $link = esc_url( strip_tags( $item->get_link() ) );
+
+ $author = $item->get_author();
+ if ( $author ) {
+ $site_link = esc_url( strip_tags( $author->get_link() ) );
+
+ if ( !$publisher = esc_html( strip_tags( $author->get_name() ) ) )
+ $publisher = __( 'Somebody' );
+ } else {
+ $publisher = __( 'Somebody' );
+ }
+ if ( $site_link )
+ $publisher = "<a href='$site_link'>$publisher</a>";
+ else
+ $publisher = "<strong>$publisher</strong>";
+
+ $content = $item->get_content();
+ $content = wp_html_excerpt( $content, 50, ' &hellip;' );
+
+ if ( $link )
+ /* translators: incoming links feed, %1$s is other person, %3$s is content */
+ $text = __( '%1$s linked here <a href="%2$s">saying</a>, "%3$s"' );
+ else
+ /* translators: incoming links feed, %1$s is other person, %3$s is content */
+ $text = __( '%1$s linked here saying, "%3$s"' );
+
+ if ( !empty( $show_date ) ) {
+ if ( $link )
+ /* translators: incoming links feed, %1$s is other person, %3$s is content, %4$s is the date */
+ $text = __( '%1$s linked here <a href="%2$s">saying</a>, "%3$s" on %4$s' );
+ else
+ /* translators: incoming links feed, %1$s is other person, %3$s is content, %4$s is the date */
+ $text = __( '%1$s linked here saying, "%3$s" on %4$s' );
+ $date = esc_html( strip_tags( $item->get_date() ) );
+ $date = strtotime( $date );
+ $date = gmdate( get_option( 'date_format' ), $date );
+ }
+
+ echo "\t<li>" . sprintf( $text, $publisher, $link, $content, $date ) . "</li>\n";
+ }
+
+ echo "</ul>\n";
+ $rss->__destruct();
+ unset($rss);
+}
+
+function wp_dashboard_incoming_links_control() {
+ wp_dashboard_rss_control( 'dashboard_incoming_links', array( 'title' => false, 'show_summary' => false, 'show_author' => false ) );
+}
+
+function wp_dashboard_primary() {
+ wp_dashboard_cached_rss_widget( 'dashboard_primary', 'wp_dashboard_rss_output' );
+}
+
+function wp_dashboard_primary_control() {
+ wp_dashboard_rss_control( 'dashboard_primary' );
+}
+
+/**
+ * Display primary dashboard RSS widget feed.
+ *
+ * @since 2.5.0
+ *
+ * @param string $widget_id
+ */
+function wp_dashboard_rss_output( $widget_id ) {
+ $widgets = get_option( 'dashboard_widget_options' );
+ echo '<div class="rss-widget">';
+ wp_widget_rss_output( $widgets[$widget_id] );
+ echo "</div>";
+}
+
+function wp_dashboard_secondary() {
+ wp_dashboard_cached_rss_widget( 'dashboard_secondary', 'wp_dashboard_secondary_output' );
+}
+
+function wp_dashboard_secondary_control() {
+ wp_dashboard_rss_control( 'dashboard_secondary' );
+}
+
+/**
+ * Display secondary dashboard RSS widget feed.
+ *
+ * @since 2.5.0
+ *
+ * @return unknown
+ */
+function wp_dashboard_secondary_output() {
+ $widgets = get_option( 'dashboard_widget_options' );
+ @extract( @$widgets['dashboard_secondary'], EXTR_SKIP );
+ $rss = @fetch_feed( $url );
+
+ if ( is_wp_error($rss) ) {
+ if ( is_admin() || current_user_can('manage_options') ) {
+ echo '<div class="rss-widget"><p>';
+ printf(__('<strong>RSS Error</strong>: %s'), $rss->get_error_message());
+ echo '</p></div>';
+ }
+ } elseif ( !$rss->get_item_quantity() ) {
+ $rss->__destruct();
+ unset($rss);
+ return false;
+ } else {
+ echo '<div class="rss-widget">';
+ wp_widget_rss_output( $rss, $widgets['dashboard_secondary'] );
+ echo '</div>';
+ $rss->__destruct();
+ unset($rss);
+ }
+}
+
+function wp_dashboard_plugins() {
+ wp_dashboard_cached_rss_widget( 'dashboard_plugins', 'wp_dashboard_plugins_output', array(
+ 'http://wordpress.org/plugins/rss/browse/popular/',
+ 'http://wordpress.org/plugins/rss/browse/new/'
+ ) );
+}
+
+/**
+ * Display plugins most popular, newest plugins, and recently updated widget text.
+ *
+ * @since 2.5.0
+ */
+function wp_dashboard_plugins_output() {
+ $popular = fetch_feed( 'http://wordpress.org/plugins/rss/browse/popular/' );
+ $new = fetch_feed( 'http://wordpress.org/plugins/rss/browse/new/' );
+
+ if ( false === $plugin_slugs = get_transient( 'plugin_slugs' ) ) {
+ $plugin_slugs = array_keys( get_plugins() );
+ set_transient( 'plugin_slugs', $plugin_slugs, DAY_IN_SECONDS );
+ }
+
+ foreach ( array( 'popular' => __('Most Popular'), 'new' => __('Newest Plugins') ) as $feed => $label ) {
+ if ( is_wp_error($$feed) || !$$feed->get_item_quantity() )
+ continue;
+
+ $items = $$feed->get_items(0, 5);
+
+ // Pick a random, non-installed plugin
+ while ( true ) {
+ // Abort this foreach loop iteration if there's no plugins left of this type
+ if ( 0 == count($items) )
+ continue 2;
+
+ $item_key = array_rand($items);
+ $item = $items[$item_key];
+
+ list($link, $frag) = explode( '#', $item->get_link() );
+
+ $link = esc_url($link);
+ if ( preg_match( '|/([^/]+?)/?$|', $link, $matches ) )
+ $slug = $matches[1];
+ else {
+ unset( $items[$item_key] );
+ continue;
+ }
+
+ // Is this random plugin's slug already installed? If so, try again.
+ reset( $plugin_slugs );
+ foreach ( $plugin_slugs as $plugin_slug ) {
+ if ( $slug == substr( $plugin_slug, 0, strlen( $slug ) ) ) {
+ unset( $items[$item_key] );
+ continue 2;
+ }
+ }
+
+ // If we get to this point, then the random plugin isn't installed and we can stop the while().
+ break;
+ }
+
+ // Eliminate some common badly formed plugin descriptions
+ while ( ( null !== $item_key = array_rand($items) ) && false !== strpos( $items[$item_key]->get_description(), 'Plugin Name:' ) )
+ unset($items[$item_key]);
+
+ if ( !isset($items[$item_key]) )
+ continue;
+
+ $title = esc_html( $item->get_title() );
+
+ $description = esc_html( strip_tags(@html_entity_decode($item->get_description(), ENT_QUOTES, get_option('blog_charset'))) );
+
+ $ilink = wp_nonce_url('plugin-install.php?tab=plugin-information&plugin=' . $slug, 'install-plugin_' . $slug) .
+ '&amp;TB_iframe=true&amp;width=600&amp;height=800';
+
+ echo "<h4>$label</h4>\n";
+ echo "<h5><a href='$link'>$title</a></h5>&nbsp;<span>(<a href='$ilink' class='thickbox' title='$title'>" . __( 'Install' ) . "</a>)</span>\n";
+ echo "<p>$description</p>\n";
+
+ $$feed->__destruct();
+ unset($$feed);
+ }
+}
+
+/**
+ * Checks to see if all of the feed url in $check_urls are cached.
+ *
+ * If $check_urls is empty, look for the rss feed url found in the dashboard
+ * widget options of $widget_id. If cached, call $callback, a function that
+ * echoes out output for this widget. If not cache, echo a "Loading..." stub
+ * which is later replaced by AJAX call (see top of /wp-admin/index.php)
+ *
+ * @since 2.5.0
+ *
+ * @param string $widget_id
+ * @param callback $callback
+ * @param array $check_urls RSS feeds
+ * @return bool False on failure. True on success.
+ */
+function wp_dashboard_cached_rss_widget( $widget_id, $callback, $check_urls = array() ) {
+ $loading = '<p class="widget-loading hide-if-no-js">' . __( 'Loading&#8230;' ) . '</p><p class="hide-if-js">' . __( 'This widget requires JavaScript.' ) . '</p>';
+ $doing_ajax = ( defined('DOING_AJAX') && DOING_AJAX );
+
+ if ( empty($check_urls) ) {
+ $widgets = get_option( 'dashboard_widget_options' );
+ if ( empty($widgets[$widget_id]['url']) && ! $doing_ajax ) {
+ echo $loading;
+ return false;
+ }
+ $check_urls = array( $widgets[$widget_id]['url'] );
+ }
+
+ $cache_key = 'dash_' . md5( $widget_id );
+ if ( false !== ( $output = get_transient( $cache_key ) ) ) {
+ echo $output;
+ return true;
+ }
+
+ if ( ! $doing_ajax ) {
+ echo $loading;
+ return false;
+ }
+
+ if ( $callback && is_callable( $callback ) ) {
+ $args = array_slice( func_get_args(), 2 );
+ array_unshift( $args, $widget_id );
+ ob_start();
+ call_user_func_array( $callback, $args );
+ set_transient( $cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS ); // Default lifetime in cache of 12 hours (same as the feeds)
+ }
+
+ return true;
+}
+
+/* Dashboard Widgets Controls */
+
+// Calls widget_control callback
+/**
+ * Calls widget control callback.
+ *
+ * @since 2.5.0
+ *
+ * @param int $widget_control_id Registered Widget ID.
+ */
+function wp_dashboard_trigger_widget_control( $widget_control_id = false ) {
+ global $wp_dashboard_control_callbacks;
+
+ if ( is_scalar($widget_control_id) && $widget_control_id && isset($wp_dashboard_control_callbacks[$widget_control_id]) && is_callable($wp_dashboard_control_callbacks[$widget_control_id]) ) {
+ call_user_func( $wp_dashboard_control_callbacks[$widget_control_id], '', array( 'id' => $widget_control_id, 'callback' => $wp_dashboard_control_callbacks[$widget_control_id] ) );
+ }
+}
+
+/**
+ * The RSS dashboard widget control.
+ *
+ * Sets up $args to be used as input to wp_widget_rss_form(). Handles POST data
+ * from RSS-type widgets.
+ *
+ * @since 2.5.0
+ *
+ * @param string $widget_id
+ * @param array $form_inputs
+ */
+function wp_dashboard_rss_control( $widget_id, $form_inputs = array() ) {
+ if ( !$widget_options = get_option( 'dashboard_widget_options' ) )
+ $widget_options = array();
+
+ if ( !isset($widget_options[$widget_id]) )
+ $widget_options[$widget_id] = array();
+
+ $number = 1; // Hack to use wp_widget_rss_form()
+ $widget_options[$widget_id]['number'] = $number;
+
+ if ( 'POST' == $_SERVER['REQUEST_METHOD'] && isset($_POST['widget-rss'][$number]) ) {
+ $_POST['widget-rss'][$number] = wp_unslash( $_POST['widget-rss'][$number] );
+ $widget_options[$widget_id] = wp_widget_rss_process( $_POST['widget-rss'][$number] );
+ // title is optional. If black, fill it if possible
+ if ( !$widget_options[$widget_id]['title'] && isset($_POST['widget-rss'][$number]['title']) ) {
+ $rss = fetch_feed($widget_options[$widget_id]['url']);
+ if ( is_wp_error($rss) ) {
+ $widget_options[$widget_id]['title'] = htmlentities(__('Unknown Feed'));
+ } else {
+ $widget_options[$widget_id]['title'] = htmlentities(strip_tags($rss->get_title()));
+ $rss->__destruct();
+ unset($rss);
+ }
+ }
+ update_option( 'dashboard_widget_options', $widget_options );
+ $cache_key = 'dash_' . md5( $widget_id );
+ delete_transient( $cache_key );
+ }
+
+ wp_widget_rss_form( $widget_options[$widget_id], $form_inputs );
+}
+
+/**
+ * Display file upload quota on dashboard.
+ *
+ * Runs on the activity_box_end hook in wp_dashboard_right_now().
+ *
+ * @since 3.0.0
+ *
+ * @return bool True if not multisite, user can't upload files, or the space check option is disabled.
+*/
+function wp_dashboard_quota() {
+ if ( !is_multisite() || !current_user_can('upload_files') || get_site_option( 'upload_space_check_disabled' ) )
+ return true;
+
+ $quota = get_space_allowed();
+ $used = get_space_used();
+
+ if ( $used > $quota )
+ $percentused = '100';
+ else
+ $percentused = ( $used / $quota ) * 100;
+ $used_color = ( $percentused >= 70 ) ? ' spam' : '';
+ $used = round( $used, 2 );
+ $percentused = number_format( $percentused );
+
+ ?>
+ <p class="sub musub"><?php _e( 'Storage Space' ); ?></p>
+ <div class="table table_content musubtable">
+ <table>
+ <tr class="first">
+ <td class="first b b-posts"><?php printf( __( '<a href="%1$s" title="Manage Uploads" class="musublink">%2$sMB</a>' ), esc_url( admin_url( 'upload.php' ) ), number_format_i18n( $quota ) ); ?></td>
+ <td class="t posts"><?php _e( 'Space Allowed' ); ?></td>
+ </tr>
+ </table>
+ </div>
+ <div class="table table_discussion musubtable">
+ <table>
+ <tr class="first">
+ <td class="b b-comments"><?php printf( __( '<a href="%1$s" title="Manage Uploads" class="musublink">%2$sMB (%3$s%%)</a>' ), esc_url( admin_url( 'upload.php' ) ), number_format_i18n( $used, 2 ), $percentused ); ?></td>
+ <td class="last t comments<?php echo $used_color;?>"><?php _e( 'Space Used' );?></td>
+ </tr>
+ </table>
+ </div>
+ <br class="clear" />
+ <?php
+}
+add_action( 'activity_box_end', 'wp_dashboard_quota' );
+
+// Display Browser Nag Meta Box
+function wp_dashboard_browser_nag() {
+ $notice = '';
+ $response = wp_check_browser_version();
+
+ if ( $response ) {
+ if ( $response['insecure'] ) {
+ $msg = sprintf( __( "It looks like you're using an insecure version of <a href='%s'>%s</a>. Using an outdated browser makes your computer unsafe. For the best WordPress experience, please update your browser." ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ) );
+ } else {
+ $msg = sprintf( __( "It looks like you're using an old version of <a href='%s'>%s</a>. For the best WordPress experience, please update your browser." ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ) );
+ }
+
+ $browser_nag_class = '';
+ if ( !empty( $response['img_src'] ) ) {
+ $img_src = ( is_ssl() && ! empty( $response['img_src_ssl'] ) )? $response['img_src_ssl'] : $response['img_src'];
+
+ $notice .= '<div class="alignright browser-icon"><a href="' . esc_attr($response['update_url']) . '"><img src="' . esc_attr( $img_src ) . '" alt="" /></a></div>';
+ $browser_nag_class = ' has-browser-icon';
+ }
+ $notice .= "<p class='browser-update-nag{$browser_nag_class}'>{$msg}</p>";
+
+ $browsehappy = 'http://browsehappy.com/';
+ $locale = get_locale();
+ if ( 'en_US' !== $locale )
+ $browsehappy = add_query_arg( 'locale', $locale, $browsehappy );
+
+ $notice .= '<p>' . sprintf( __( '<a href="%1$s" class="update-browser-link">Update %2$s</a> or learn how to <a href="%3$s" class="browse-happy-link">browse happy</a>' ), esc_attr( $response['update_url'] ), esc_html( $response['name'] ), esc_url( $browsehappy ) ) . '</p>';
+ $notice .= '<p class="hide-if-no-js"><a href="" class="dismiss">' . __( 'Dismiss' ) . '</a></p>';
+ $notice .= '<div class="clear"></div>';
+ }
+
+ echo apply_filters( 'browse-happy-notice', $notice, $response );
+}
+
+function dashboard_browser_nag_class( $classes ) {
+ $response = wp_check_browser_version();
+
+ if ( $response && $response['insecure'] )
+ $classes[] = 'browser-insecure';
+
+ return $classes;
+}
+
+/**
+ * Check if the user needs a browser update
+ *
+ * @since 3.2.0
+ *
+ * @return array|bool False on failure, array of browser data on success.
+ */
+function wp_check_browser_version() {
+ if ( empty( $_SERVER['HTTP_USER_AGENT'] ) )
+ return false;
+
+ $key = md5( $_SERVER['HTTP_USER_AGENT'] );
+
+ if ( false === ($response = get_site_transient('browser_' . $key) ) ) {
+ global $wp_version;
+
+ $options = array(
+ 'body' => array( 'useragent' => $_SERVER['HTTP_USER_AGENT'] ),
+ 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url()
+ );
+
+ $response = wp_remote_post( 'http://api.wordpress.org/core/browse-happy/1.0/', $options );
+
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
+ return false;
+
+ /**
+ * Response should be an array with:
+ * 'name' - string - A user friendly browser name
+ * 'version' - string - The most recent version of the browser
+ * 'current_version' - string - The version of the browser the user is using
+ * 'upgrade' - boolean - Whether the browser needs an upgrade
+ * 'insecure' - boolean - Whether the browser is deemed insecure
+ * 'upgrade_url' - string - The url to visit to upgrade
+ * 'img_src' - string - An image representing the browser
+ * 'img_src_ssl' - string - An image (over SSL) representing the browser
+ */
+ $response = maybe_unserialize( wp_remote_retrieve_body( $response ) );
+
+ if ( ! is_array( $response ) )
+ return false;
+
+ set_site_transient( 'browser_' . $key, $response, WEEK_IN_SECONDS );
+ }
+
+ return $response;
+}
+
+/**
+ * Empty function usable by plugins to output empty dashboard widget (to be populated later by JS).
+ */
+function wp_dashboard_empty() {}
+
+/**
+ * Displays a welcome panel to introduce users to WordPress.
+ *
+ * @since 3.3.0
+ */
+function wp_welcome_panel() {
+ ?>
+ <div class="welcome-panel-content">
+ <h3><?php _e( 'Welcome to WordPress!' ); ?></h3>
+ <p class="about-description"><?php _e( 'We&#8217;ve assembled some links to get you started:' ); ?></p>
+ <div class="welcome-panel-column-container">
+ <div class="welcome-panel-column">
+ <h4><?php _e( 'Get Started' ); ?></h4>
+ <a class="button button-primary button-hero load-customize hide-if-no-customize" href="<?php echo wp_customize_url(); ?>"><?php _e( 'Customize Your Site' ); ?></a>
+ <a class="button button-primary button-hero hide-if-customize" href="<?php echo admin_url( 'themes.php' ); ?>"><?php _e( 'Customize Your Site' ); ?></a>
+ <?php if ( current_user_can( 'install_themes' ) || ( current_user_can( 'switch_themes' ) && count( wp_get_themes( array( 'allowed' => true ) ) ) > 1 ) ) : ?>
+ <p class="hide-if-no-customize"><?php printf( __( 'or, <a href="%s">change your theme completely</a>' ), admin_url( 'themes.php' ) ); ?></p>
+ <?php endif; ?>
+ </div>
+ <div class="welcome-panel-column">
+ <h4><?php _e( 'Next Steps' ); ?></h4>
+ <ul>
+ <?php if ( 'page' == get_option( 'show_on_front' ) && ! get_option( 'page_for_posts' ) ) : ?>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-edit-page">' . __( 'Edit your front page' ) . '</a>', get_edit_post_link( get_option( 'page_on_front' ) ) ); ?></li>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-add-page">' . __( 'Add additional pages' ) . '</a>', admin_url( 'post-new.php?post_type=page' ) ); ?></li>
+ <?php elseif ( 'page' == get_option( 'show_on_front' ) ) : ?>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-edit-page">' . __( 'Edit your front page' ) . '</a>', get_edit_post_link( get_option( 'page_on_front' ) ) ); ?></li>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-add-page">' . __( 'Add additional pages' ) . '</a>', admin_url( 'post-new.php?post_type=page' ) ); ?></li>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-write-blog">' . __( 'Add a blog post' ) . '</a>', admin_url( 'post-new.php' ) ); ?></li>
+ <?php else : ?>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-write-blog">' . __( 'Write your first blog post' ) . '</a>', admin_url( 'post-new.php' ) ); ?></li>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-add-page">' . __( 'Add an About page' ) . '</a>', admin_url( 'post-new.php?post_type=page' ) ); ?></li>
+ <?php endif; ?>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-view-site">' . __( 'View your site' ) . '</a>', home_url( '/' ) ); ?></li>
+ </ul>
+ </div>
+ <div class="welcome-panel-column welcome-panel-last">
+ <h4><?php _e( 'More Actions' ); ?></h4>
+ <ul>
+ <li><?php printf( '<div class="welcome-icon welcome-widgets-menus">' . __( 'Manage <a href="%1$s">widgets</a> or <a href="%2$s">menus</a>' ) . '</div>', admin_url( 'widgets.php' ), admin_url( 'nav-menus.php' ) ); ?></li>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-comments">' . __( 'Turn comments on or off' ) . '</a>', admin_url( 'options-discussion.php' ) ); ?></li>
+ <li><?php printf( '<a href="%s" class="welcome-icon welcome-learn-more">' . __( 'Learn more about getting started' ) . '</a>', __( 'http://codex.wordpress.org/First_Steps_With_WordPress' ) ); ?></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <?php
+}
diff --git a/src/wp-admin/includes/deprecated.php b/src/wp-admin/includes/deprecated.php
new file mode 100644
index 0000000000..399577ed4b
--- /dev/null
+++ b/src/wp-admin/includes/deprecated.php
@@ -0,0 +1,1025 @@
+<?php
+/**
+ * Deprecated admin functions from past WordPress versions. You shouldn't use these
+ * functions and look for the alternatives instead. The functions will be removed
+ * in a later version.
+ *
+ * @package WordPress
+ * @subpackage Deprecated
+ */
+
+/*
+ * Deprecated functions come here to die.
+ */
+
+/**
+ * @since 2.1
+ * @deprecated 2.1
+ * @deprecated Use wp_editor().
+ * @see wp_editor()
+ */
+function tinymce_include() {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_editor()' );
+
+ wp_tiny_mce();
+}
+
+/**
+ * Unused Admin function.
+ *
+ * @since 2.0
+ * @deprecated 2.5
+ *
+ */
+function documentation_link() {
+ _deprecated_function( __FUNCTION__, '2.5' );
+ return;
+}
+
+/**
+ * Calculates the new dimensions for a downsampled image.
+ *
+ * @since 2.0.0
+ * @deprecated 3.0.0
+ * @deprecated Use wp_constrain_dimensions()
+ * @see wp_constrain_dimensions()
+ *
+ * @param int $width Current width of the image
+ * @param int $height Current height of the image
+ * @param int $wmax Maximum wanted width
+ * @param int $hmax Maximum wanted height
+ * @return array Shrunk dimensions (width, height).
+ */
+function wp_shrink_dimensions( $width, $height, $wmax = 128, $hmax = 96 ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'wp_constrain_dimensions()' );
+ return wp_constrain_dimensions( $width, $height, $wmax, $hmax );
+}
+
+/**
+ * Calculated the new dimensions for a downsampled image.
+ *
+ * @since 2.0.0
+ * @deprecated 3.5.0
+ * @deprecated Use wp_constrain_dimensions()
+ * @see wp_constrain_dimensions()
+ *
+ * @param int $width Current width of the image
+ * @param int $height Current height of the image
+ * @return array Shrunk dimensions (width, height).
+ */
+function get_udims( $width, $height ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'wp_constrain_dimensions()' );
+ return wp_constrain_dimensions( $width, $height, 128, 96 );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 0.71
+ * @deprecated 2.6.0
+ * @deprecated Use wp_category_checklist()
+ * @see wp_category_checklist()
+ *
+ * @param unknown_type $default
+ * @param unknown_type $parent
+ * @param unknown_type $popular_ids
+ */
+function dropdown_categories( $default = 0, $parent = 0, $popular_ids = array() ) {
+ _deprecated_function( __FUNCTION__, '2.6', 'wp_category_checklist()' );
+ global $post_ID;
+ wp_category_checklist( $post_ID );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.1.0
+ * @deprecated 2.6.0
+ * @deprecated Use wp_link_category_checklist()
+ * @see wp_link_category_checklist()
+ *
+ * @param unknown_type $default
+ */
+function dropdown_link_categories( $default = 0 ) {
+ _deprecated_function( __FUNCTION__, '2.6', 'wp_link_category_checklist()' );
+ global $link_id;
+ wp_link_category_checklist( $link_id );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.2.0
+ * @deprecated 3.0.0
+ * @deprecated Use wp_dropdown_categories()
+ * @see wp_dropdown_categories()
+ *
+ * @param unknown_type $currentcat
+ * @param unknown_type $currentparent
+ * @param unknown_type $parent
+ * @param unknown_type $level
+ * @param unknown_type $categories
+ * @return unknown
+ */
+function wp_dropdown_cats( $currentcat = 0, $currentparent = 0, $parent = 0, $level = 0, $categories = 0 ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'wp_dropdown_categories()' );
+ if (!$categories )
+ $categories = get_categories( array('hide_empty' => 0) );
+
+ if ( $categories ) {
+ foreach ( $categories as $category ) {
+ if ( $currentcat != $category->term_id && $parent == $category->parent) {
+ $pad = str_repeat( '&#8211; ', $level );
+ $category->name = esc_html( $category->name );
+ echo "\n\t<option value='$category->term_id'";
+ if ( $currentparent == $category->term_id )
+ echo " selected='selected'";
+ echo ">$pad$category->name</option>";
+ wp_dropdown_cats( $currentcat, $currentparent, $category->term_id, $level +1, $categories );
+ }
+ }
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Register a setting and its sanitization callback
+ *
+ * @since 2.7.0
+ * @deprecated 3.0.0
+ * @deprecated Use register_setting()
+ * @see register_setting()
+ *
+ * @param string $option_group A settings group name. Should correspond to a whitelisted option key name.
+ * Default whitelisted option key names include "general," "discussion," and "reading," among others.
+ * @param string $option_name The name of an option to sanitize and save.
+ * @param unknown_type $sanitize_callback A callback function that sanitizes the option's value.
+ * @return unknown
+ */
+function add_option_update_handler( $option_group, $option_name, $sanitize_callback = '' ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'register_setting()' );
+ return register_setting( $option_group, $option_name, $sanitize_callback );
+}
+
+/**
+ * Unregister a setting
+ *
+ * @since 2.7.0
+ * @deprecated 3.0.0
+ * @deprecated Use unregister_setting()
+ * @see unregister_setting()
+ *
+ * @param unknown_type $option_group
+ * @param unknown_type $option_name
+ * @param unknown_type $sanitize_callback
+ * @return unknown
+ */
+function remove_option_update_handler( $option_group, $option_name, $sanitize_callback = '' ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'unregister_setting()' );
+ return unregister_setting( $option_group, $option_name, $sanitize_callback );
+}
+
+/**
+ * Determines the language to use for CodePress syntax highlighting.
+ *
+ * @since 2.8.0
+ * @deprecated 3.0.0
+ *
+ * @param string $filename
+**/
+function codepress_get_lang( $filename ) {
+ _deprecated_function( __FUNCTION__, '3.0' );
+ return;
+}
+
+/**
+ * Adds Javascript required to make CodePress work on the theme/plugin editors.
+ *
+ * @since 2.8.0
+ * @deprecated 3.0.0
+**/
+function codepress_footer_js() {
+ _deprecated_function( __FUNCTION__, '3.0' );
+ return;
+}
+
+/**
+ * Determine whether to use CodePress.
+ *
+ * @since 2.8
+ * @deprecated 3.0.0
+**/
+function use_codepress() {
+ _deprecated_function( __FUNCTION__, '3.0' );
+ return;
+}
+
+/**
+ * @deprecated 3.1.0
+ *
+ * @return array List of user IDs.
+ */
+function get_author_user_ids() {
+ _deprecated_function( __FUNCTION__, '3.1', 'get_users()' );
+
+ global $wpdb;
+ if ( !is_multisite() )
+ $level_key = $wpdb->get_blog_prefix() . 'user_level';
+ else
+ $level_key = $wpdb->get_blog_prefix() . 'capabilities'; // wpmu site admins don't have user_levels
+
+ return $wpdb->get_col( $wpdb->prepare("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value != '0'", $level_key) );
+}
+
+/**
+ * @deprecated 3.1.0
+ *
+ * @param int $user_id User ID.
+ * @return array|bool List of editable authors. False if no editable users.
+ */
+function get_editable_authors( $user_id ) {
+ _deprecated_function( __FUNCTION__, '3.1', 'get_users()' );
+
+ global $wpdb;
+
+ $editable = get_editable_user_ids( $user_id );
+
+ if ( !$editable ) {
+ return false;
+ } else {
+ $editable = join(',', $editable);
+ $authors = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($editable) ORDER BY display_name" );
+ }
+
+ return apply_filters('get_editable_authors', $authors);
+}
+
+/**
+ * @deprecated 3.1.0
+ *
+ * @param int $user_id User ID.
+ * @param bool $exclude_zeros Optional, default is true. Whether to exclude zeros.
+ * @return unknown
+ */
+function get_editable_user_ids( $user_id, $exclude_zeros = true, $post_type = 'post' ) {
+ _deprecated_function( __FUNCTION__, '3.1', 'get_users()' );
+
+ global $wpdb;
+
+ if ( ! $user = get_userdata( $user_id ) )
+ return array();
+ $post_type_obj = get_post_type_object($post_type);
+
+ if ( ! $user->has_cap($post_type_obj->cap->edit_others_posts) ) {
+ if ( $user->has_cap($post_type_obj->cap->edit_posts) || ! $exclude_zeros )
+ return array($user->ID);
+ else
+ return array();
+ }
+
+ if ( !is_multisite() )
+ $level_key = $wpdb->get_blog_prefix() . 'user_level';
+ else
+ $level_key = $wpdb->get_blog_prefix() . 'capabilities'; // wpmu site admins don't have user_levels
+
+ $query = $wpdb->prepare("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s", $level_key);
+ if ( $exclude_zeros )
+ $query .= " AND meta_value != '0'";
+
+ return $wpdb->get_col( $query );
+}
+
+/**
+ * @deprecated 3.1.0
+ */
+function get_nonauthor_user_ids() {
+ _deprecated_function( __FUNCTION__, '3.1', 'get_users()' );
+
+ global $wpdb;
+
+ if ( !is_multisite() )
+ $level_key = $wpdb->get_blog_prefix() . 'user_level';
+ else
+ $level_key = $wpdb->get_blog_prefix() . 'capabilities'; // wpmu site admins don't have user_levels
+
+ return $wpdb->get_col( $wpdb->prepare("SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value = '0'", $level_key) );
+}
+
+if ( !class_exists('WP_User_Search') ) :
+/**
+ * WordPress User Search class.
+ *
+ * @since 2.1.0
+ * @deprecated 3.1.0
+ */
+class WP_User_Search {
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var unknown_type
+ */
+ var $results;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var unknown_type
+ */
+ var $search_term;
+
+ /**
+ * Page number.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var int
+ */
+ var $page;
+
+ /**
+ * Role name that users have.
+ *
+ * @since 2.5.0
+ * @access private
+ * @var string
+ */
+ var $role;
+
+ /**
+ * Raw page number.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var int|bool
+ */
+ var $raw_page;
+
+ /**
+ * Amount of users to display per page.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var int
+ */
+ var $users_per_page = 50;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var unknown_type
+ */
+ var $first_user;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var int
+ */
+ var $last_user;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var string
+ */
+ var $query_limit;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 3.0.0
+ * @access private
+ * @var string
+ */
+ var $query_orderby;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 3.0.0
+ * @access private
+ * @var string
+ */
+ var $query_from;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 3.0.0
+ * @access private
+ * @var string
+ */
+ var $query_where;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var int
+ */
+ var $total_users_for_query = 0;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var bool
+ */
+ var $too_many_total_users = false;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.1.0
+ * @access private
+ * @var unknown_type
+ */
+ var $search_errors;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 2.7.0
+ * @access private
+ * @var unknown_type
+ */
+ var $paging_text;
+
+ /**
+ * PHP4 Constructor - Sets up the object properties.
+ *
+ * @since 2.1.0
+ *
+ * @param string $search_term Search terms string.
+ * @param int $page Optional. Page ID.
+ * @param string $role Role name.
+ * @return WP_User_Search
+ */
+ function WP_User_Search ($search_term = '', $page = '', $role = '') {
+ _deprecated_function( __FUNCTION__, '3.1', 'WP_User_Query' );
+
+ $this->search_term = wp_unslash( $search_term );
+ $this->raw_page = ( '' == $page ) ? false : (int) $page;
+ $this->page = (int) ( '' == $page ) ? 1 : $page;
+ $this->role = $role;
+
+ $this->prepare_query();
+ $this->query();
+ $this->do_paging();
+ }
+
+ /**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ * @access public
+ */
+ function prepare_query() {
+ global $wpdb;
+ $this->first_user = ($this->page - 1) * $this->users_per_page;
+
+ $this->query_limit = $wpdb->prepare(" LIMIT %d, %d", $this->first_user, $this->users_per_page);
+ $this->query_orderby = ' ORDER BY user_login';
+
+ $search_sql = '';
+ if ( $this->search_term ) {
+ $searches = array();
+ $search_sql = 'AND (';
+ foreach ( array('user_login', 'user_nicename', 'user_email', 'user_url', 'display_name') as $col )
+ $searches[] = $wpdb->prepare( $col . ' LIKE %s', '%' . like_escape($this->search_term) . '%' );
+ $search_sql .= implode(' OR ', $searches);
+ $search_sql .= ')';
+ }
+
+ $this->query_from = " FROM $wpdb->users";
+ $this->query_where = " WHERE 1=1 $search_sql";
+
+ if ( $this->role ) {
+ $this->query_from .= " INNER JOIN $wpdb->usermeta ON $wpdb->users.ID = $wpdb->usermeta.user_id";
+ $this->query_where .= $wpdb->prepare(" AND $wpdb->usermeta.meta_key = '{$wpdb->prefix}capabilities' AND $wpdb->usermeta.meta_value LIKE %s", '%' . $this->role . '%');
+ } elseif ( is_multisite() ) {
+ $level_key = $wpdb->prefix . 'capabilities'; // wpmu site admins don't have user_levels
+ $this->query_from .= ", $wpdb->usermeta";
+ $this->query_where .= " AND $wpdb->users.ID = $wpdb->usermeta.user_id AND meta_key = '{$level_key}'";
+ }
+
+ do_action_ref_array( 'pre_user_search', array( &$this ) );
+ }
+
+ /**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ * @access public
+ */
+ function query() {
+ global $wpdb;
+
+ $this->results = $wpdb->get_col("SELECT DISTINCT($wpdb->users.ID)" . $this->query_from . $this->query_where . $this->query_orderby . $this->query_limit);
+
+ if ( $this->results )
+ $this->total_users_for_query = $wpdb->get_var("SELECT COUNT(DISTINCT($wpdb->users.ID))" . $this->query_from . $this->query_where); // no limit
+ else
+ $this->search_errors = new WP_Error('no_matching_users_found', __('No matching users were found!'));
+ }
+
+ /**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ * @access public
+ */
+ function prepare_vars_for_template_usage() {}
+
+ /**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ * @access public
+ */
+ function do_paging() {
+ if ( $this->total_users_for_query > $this->users_per_page ) { // have to page the results
+ $args = array();
+ if( ! empty($this->search_term) )
+ $args['usersearch'] = urlencode($this->search_term);
+ if( ! empty($this->role) )
+ $args['role'] = urlencode($this->role);
+
+ $this->paging_text = paginate_links( array(
+ 'total' => ceil($this->total_users_for_query / $this->users_per_page),
+ 'current' => $this->page,
+ 'base' => 'users.php?%_%',
+ 'format' => 'userspage=%#%',
+ 'add_args' => $args
+ ) );
+ if ( $this->paging_text ) {
+ $this->paging_text = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
+ number_format_i18n( ( $this->page - 1 ) * $this->users_per_page + 1 ),
+ number_format_i18n( min( $this->page * $this->users_per_page, $this->total_users_for_query ) ),
+ number_format_i18n( $this->total_users_for_query ),
+ $this->paging_text
+ );
+ }
+ }
+ }
+
+ /**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return unknown
+ */
+ function get_results() {
+ return (array) $this->results;
+ }
+
+ /**
+ * Displaying paging text.
+ *
+ * @see do_paging() Builds paging text.
+ *
+ * @since 2.1.0
+ * @access public
+ */
+ function page_links() {
+ echo $this->paging_text;
+ }
+
+ /**
+ * Whether paging is enabled.
+ *
+ * @see do_paging() Builds paging text.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return bool
+ */
+ function results_are_paged() {
+ if ( $this->paging_text )
+ return true;
+ return false;
+ }
+
+ /**
+ * Whether there are search terms.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return bool
+ */
+ function is_search() {
+ if ( $this->search_term )
+ return true;
+ return false;
+ }
+}
+endif;
+
+/**
+ * Retrieve editable posts from other users.
+ *
+ * @deprecated 3.1.0
+ *
+ * @param int $user_id User ID to not retrieve posts from.
+ * @param string $type Optional, defaults to 'any'. Post type to retrieve, can be 'draft' or 'pending'.
+ * @return array List of posts from others.
+ */
+function get_others_unpublished_posts($user_id, $type='any') {
+ _deprecated_function( __FUNCTION__, '3.1' );
+
+ global $wpdb;
+
+ $editable = get_editable_user_ids( $user_id );
+
+ if ( in_array($type, array('draft', 'pending')) )
+ $type_sql = " post_status = '$type' ";
+ else
+ $type_sql = " ( post_status = 'draft' OR post_status = 'pending' ) ";
+
+ $dir = ( 'pending' == $type ) ? 'ASC' : 'DESC';
+
+ if ( !$editable ) {
+ $other_unpubs = '';
+ } else {
+ $editable = join(',', $editable);
+ $other_unpubs = $wpdb->get_results( $wpdb->prepare("SELECT ID, post_title, post_author FROM $wpdb->posts WHERE post_type = 'post' AND $type_sql AND post_author IN ($editable) AND post_author != %d ORDER BY post_modified $dir", $user_id) );
+ }
+
+ return apply_filters('get_others_drafts', $other_unpubs);
+}
+
+/**
+ * Retrieve drafts from other users.
+ *
+ * @deprecated 3.1.0
+ *
+ * @param int $user_id User ID.
+ * @return array List of drafts from other users.
+ */
+function get_others_drafts($user_id) {
+ _deprecated_function( __FUNCTION__, '3.1' );
+
+ return get_others_unpublished_posts($user_id, 'draft');
+}
+
+/**
+ * Retrieve pending review posts from other users.
+ *
+ * @deprecated 3.1.0
+ *
+ * @param int $user_id User ID.
+ * @return array List of posts with pending review post type from other users.
+ */
+function get_others_pending($user_id) {
+ _deprecated_function( __FUNCTION__, '3.1' );
+
+ return get_others_unpublished_posts($user_id, 'pending');
+}
+
+/**
+ * Output the QuickPress dashboard widget.
+ *
+ * @since 3.0.0
+ * @deprecated 3.2.0
+ * @deprecated Use wp_dashboard_quick_press()
+ * @see wp_dashboard_quick_press()
+ */
+function wp_dashboard_quick_press_output() {
+ _deprecated_function( __FUNCTION__, '3.2', 'wp_dashboard_quick_press()' );
+ wp_dashboard_quick_press();
+}
+
+/**
+ * @since 2.7.0
+ * @deprecated 3.3
+ * @deprecated Use wp_editor()
+ * @see wp_editor()
+ */
+function wp_tiny_mce( $teeny = false, $settings = false ) {
+ _deprecated_function( __FUNCTION__, '3.3', 'wp_editor()' );
+
+ static $num = 1;
+
+ if ( ! class_exists('_WP_Editors' ) )
+ require_once( ABSPATH . WPINC . '/class-wp-editor.php' );
+
+ $editor_id = 'content' . $num++;
+
+ $set = array(
+ 'teeny' => $teeny,
+ 'tinymce' => $settings ? $settings : true,
+ 'quicktags' => false
+ );
+
+ $set = _WP_Editors::parse_settings($editor_id, $set);
+ _WP_Editors::editor_settings($editor_id, $set);
+}
+
+/**
+ * @deprecated 3.3.0
+ * @deprecated Use wp_editor()
+ * @see wp_editor()
+ */
+function wp_preload_dialogs() {
+ _deprecated_function( __FUNCTION__, '3.3', 'wp_editor()' );
+}
+
+/**
+ * @deprecated 3.3.0
+ * @deprecated Use wp_editor()
+ * @see wp_editor()
+ */
+function wp_print_editor_js() {
+ _deprecated_function( __FUNCTION__, '3.3', 'wp_editor()' );
+}
+
+/**
+ * @deprecated 3.3.0
+ * @deprecated Use wp_editor()
+ * @see wp_editor()
+ */
+function wp_quicktags() {
+ _deprecated_function( __FUNCTION__, '3.3', 'wp_editor()' );
+}
+
+/**
+ * Returns the screen layout options.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ * @deprecated Use $current_screen->render_screen_layout()
+ * @see WP_Screen::render_screen_layout()
+ */
+function screen_layout( $screen ) {
+ _deprecated_function( __FUNCTION__, '3.3', '$current_screen->render_screen_layout()' );
+
+ $current_screen = get_current_screen();
+
+ if ( ! $current_screen )
+ return '';
+
+ ob_start();
+ $current_screen->render_screen_layout();
+ return ob_get_clean();
+}
+
+/**
+ * Returns the screen's per-page options.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ * @deprecated Use $current_screen->render_per_page_options()
+ * @see WP_Screen::render_per_page_options()
+ */
+function screen_options( $screen ) {
+ _deprecated_function( __FUNCTION__, '3.3', '$current_screen->render_per_page_options()' );
+
+ $current_screen = get_current_screen();
+
+ if ( ! $current_screen )
+ return '';
+
+ ob_start();
+ $current_screen->render_per_page_options();
+ return ob_get_clean();
+}
+
+/**
+ * Renders the screen's help.
+ *
+ * @since 2.7.0
+ * @deprecated 3.3.0
+ * @deprecated Use $current_screen->render_screen_meta()
+ * @see WP_Screen::render_screen_meta()
+ */
+function screen_meta( $screen ) {
+ $current_screen = get_current_screen();
+ $current_screen->render_screen_meta();
+}
+
+/**
+ * Favorite actions were deprecated in version 3.2. Use the admin bar instead.
+ *
+ * @since 2.7.0
+ * @deprecated 3.2.0
+ */
+function favorite_actions() {
+ _deprecated_function( __FUNCTION__, '3.2', 'WP_Admin_Bar' );
+}
+
+function media_upload_image() {
+ __deprecated_function( __FUNCTION__, '3.3', 'wp_media_upload_handler()' );
+ return wp_media_upload_handler();
+}
+
+function media_upload_audio() {
+ __deprecated_function( __FUNCTION__, '3.3', 'wp_media_upload_handler()' );
+ return wp_media_upload_handler();
+}
+
+function media_upload_video() {
+ __deprecated_function( __FUNCTION__, '3.3', 'wp_media_upload_handler()' );
+ return wp_media_upload_handler();
+}
+
+function media_upload_file() {
+ __deprecated_function( __FUNCTION__, '3.3', 'wp_media_upload_handler()' );
+ return wp_media_upload_handler();
+}
+
+function type_url_form_image() {
+ __deprecated_function( __FUNCTION__, '3.3', "wp_media_insert_url_form('image')" );
+ return wp_media_insert_url_form( 'image' );
+}
+
+function type_url_form_audio() {
+ __deprecated_function( __FUNCTION__, '3.3', "wp_media_insert_url_form('audio')" );
+ return wp_media_insert_url_form( 'audio' );
+}
+
+function type_url_form_video() {
+ __deprecated_function( __FUNCTION__, '3.3', "wp_media_insert_url_form('video')" );
+ return wp_media_insert_url_form( 'video' );
+}
+
+function type_url_form_file() {
+ __deprecated_function( __FUNCTION__, '3.3', "wp_media_insert_url_form('file')" );
+ return wp_media_insert_url_form( 'file' );
+}
+
+/**
+ * Add contextual help text for a page.
+ *
+ * Creates an 'Overview' help tab.
+ *
+ * @since 2.7.0
+ * @deprecated 3.3.0
+ * @deprecated Use get_current_screen()->add_help_tab()
+ * @see WP_Screen
+ *
+ * @param string $screen The handle for the screen to add help to. This is usually the hook name returned by the add_*_page() functions.
+ * @param string $help The content of an 'Overview' help tab.
+ */
+function add_contextual_help( $screen, $help ) {
+ _deprecated_function( __FUNCTION__, '3.3', 'get_current_screen()->add_help_tab()' );
+
+ if ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ WP_Screen::add_old_compat_help( $screen, $help );
+}
+
+/**
+ * Get the allowed themes for the current blog.
+ *
+ * @since 3.0.0
+ * @deprecated 3.4.0
+ * @deprecated Use wp_get_themes()
+ * @see wp_get_themes()
+ *
+ * @return array $themes Array of allowed themes.
+ */
+function get_allowed_themes() {
+ _deprecated_function( __FUNCTION__, '3.4', "wp_get_themes( array( 'allowed' => true ) )" );
+
+ $themes = wp_get_themes( array( 'allowed' => true ) );
+
+ $wp_themes = array();
+ foreach ( $themes as $theme ) {
+ $wp_themes[ $theme->get('Name') ] = $theme;
+ }
+
+ return $wp_themes;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.5.0
+ *
+ * @return unknown
+ */
+function get_broken_themes() {
+ _deprecated_function( __FUNCTION__, '3.4', "wp_get_themes( array( 'errors' => true )" );
+
+ $themes = wp_get_themes( array( 'errors' => true ) );
+ $broken = array();
+ foreach ( $themes as $theme ) {
+ $name = $theme->get('Name');
+ $broken[ $name ] = array(
+ 'Name' => $name,
+ 'Title' => $name,
+ 'Description' => $theme->errors()->get_error_message(),
+ );
+ }
+ return $broken;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @return unknown
+ */
+function current_theme_info() {
+ _deprecated_function( __FUNCTION__, '3.4', 'wp_get_theme()' );
+
+ return wp_get_theme();
+}
+
+/**
+ * This was once used to display an 'Insert into Post' button. Now it is deprecated and stubbed.
+ *
+ * @deprecated 3.5.0
+ */
+function _insert_into_post_button( $type ) {
+ _deprecated_function( __FUNCTION__, '3.5' );
+}
+
+/**
+ * This was once used to display a media button. Now it is deprecated and stubbed.
+ *
+ * @deprecated 3.5.0
+ */
+function _media_button($title, $icon, $type, $id) {
+ _deprecated_function( __FUNCTION__, '3.5' );
+}
+
+/**
+ * Get an existing post and format it for editing.
+ *
+ * @since 2.0.0
+ * @deprecated 3.5.0
+ *
+ * @param int $id
+ * @return object
+ */
+function get_post_to_edit( $id ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'get_post()' );
+
+ return get_post( $id, OBJECT, 'edit' );
+}
+
+/**
+ * Get the default page information to use.
+ *
+ * @since 2.5.0
+ * @deprecated 3.5.0
+ * @deprecated Use get_default_post_to_edit()
+ *
+ * @return WP_Post Post object containing all the default post data as attributes
+ */
+function get_default_page_to_edit() {
+ _deprecated_function( __FUNCTION__, '3.5', "get_default_post_to_edit( 'page' )" );
+
+ $page = get_default_post_to_edit();
+ $page->post_type = 'page';
+ return $page;
+}
+
+/**
+ * This was once used to create a thumbnail from an Image given a maximum side size.
+ *
+ * @since 1.2.0
+ * @deprecated 3.5.0
+ * @deprecated Use image_resize()
+ * @see image_resize()
+ *
+ * @param mixed $file Filename of the original image, Or attachment id.
+ * @param int $max_side Maximum length of a single side for the thumbnail.
+ * @param mixed $deprecated Never used.
+ * @return string Thumbnail path on success, Error string on failure.
+ */
+function wp_create_thumbnail( $file, $max_side, $deprecated = '' ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'image_resize()' );
+ return apply_filters( 'wp_create_thumbnail', image_resize( $file, $max_side, $max_side ) );
+}
diff --git a/src/wp-admin/includes/export.php b/src/wp-admin/includes/export.php
new file mode 100644
index 0000000000..ae08c3c17d
--- /dev/null
+++ b/src/wp-admin/includes/export.php
@@ -0,0 +1,436 @@
+<?php
+/**
+ * WordPress Export Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Version number for the export format.
+ *
+ * Bump this when something changes that might affect compatibility.
+ *
+ * @since 2.5.0
+ */
+define( 'WXR_VERSION', '1.2' );
+
+/**
+ * Generates the WXR export file for download
+ *
+ * @since 2.1.0
+ *
+ * @param array $args Filters defining what should be included in the export
+ */
+function export_wp( $args = array() ) {
+ global $wpdb, $post;
+
+ $defaults = array( 'content' => 'all', 'author' => false, 'category' => false,
+ 'start_date' => false, 'end_date' => false, 'status' => false,
+ );
+ $args = wp_parse_args( $args, $defaults );
+
+ do_action( 'export_wp' );
+
+ $sitename = sanitize_key( get_bloginfo( 'name' ) );
+ if ( ! empty($sitename) ) $sitename .= '.';
+ $filename = $sitename . 'wordpress.' . date( 'Y-m-d' ) . '.xml';
+
+ header( 'Content-Description: File Transfer' );
+ header( 'Content-Disposition: attachment; filename=' . $filename );
+ header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
+
+ if ( 'all' != $args['content'] && post_type_exists( $args['content'] ) ) {
+ $ptype = get_post_type_object( $args['content'] );
+ if ( ! $ptype->can_export )
+ $args['content'] = 'post';
+
+ $where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['content'] );
+ } else {
+ $post_types = get_post_types( array( 'can_export' => true ) );
+ $esses = array_fill( 0, count($post_types), '%s' );
+ $where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types );
+ }
+
+ if ( $args['status'] && ( 'post' == $args['content'] || 'page' == $args['content'] ) )
+ $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] );
+ else
+ $where .= " AND {$wpdb->posts}.post_status != 'auto-draft'";
+
+ $join = '';
+ if ( $args['category'] && 'post' == $args['content'] ) {
+ if ( $term = term_exists( $args['category'], 'category' ) ) {
+ $join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
+ $where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] );
+ }
+ }
+
+ if ( 'post' == $args['content'] || 'page' == $args['content'] ) {
+ if ( $args['author'] )
+ $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] );
+
+ if ( $args['start_date'] )
+ $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime($args['start_date']) ) );
+
+ if ( $args['end_date'] )
+ $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime('+1 month', strtotime($args['end_date'])) ) );
+ }
+
+ // grab a snapshot of post IDs, just in case it changes during the export
+ $post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" );
+
+ // get the requested terms ready, empty unless posts filtered by category or all content
+ $cats = $tags = $terms = array();
+ if ( isset( $term ) && $term ) {
+ $cat = get_term( $term['term_id'], 'category' );
+ $cats = array( $cat->term_id => $cat );
+ unset( $term, $cat );
+ } else if ( 'all' == $args['content'] ) {
+ $categories = (array) get_categories( array( 'get' => 'all' ) );
+ $tags = (array) get_tags( array( 'get' => 'all' ) );
+
+ $custom_taxonomies = get_taxonomies( array( '_builtin' => false ) );
+ $custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) );
+
+ // put categories in order with no child going before its parent
+ while ( $cat = array_shift( $categories ) ) {
+ if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) )
+ $cats[$cat->term_id] = $cat;
+ else
+ $categories[] = $cat;
+ }
+
+ // put terms in order with no child going before its parent
+ while ( $t = array_shift( $custom_terms ) ) {
+ if ( $t->parent == 0 || isset( $terms[$t->parent] ) )
+ $terms[$t->term_id] = $t;
+ else
+ $custom_terms[] = $t;
+ }
+
+ unset( $categories, $custom_taxonomies, $custom_terms );
+ }
+
+ /**
+ * Wrap given string in XML CDATA tag.
+ *
+ * @since 2.1.0
+ *
+ * @param string $str String to wrap in XML CDATA tag.
+ * @return string
+ */
+ function wxr_cdata( $str ) {
+ if ( seems_utf8( $str ) == false )
+ $str = utf8_encode( $str );
+
+ // $str = ent2ncr(esc_html($str));
+ $str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>';
+
+ return $str;
+ }
+
+ /**
+ * Return the URL of the site
+ *
+ * @since 2.5.0
+ *
+ * @return string Site URL.
+ */
+ function wxr_site_url() {
+ // ms: the base url
+ if ( is_multisite() )
+ return network_home_url();
+ // wp: the blog url
+ else
+ return get_bloginfo_rss( 'url' );
+ }
+
+ /**
+ * Output a cat_name XML tag from a given category object
+ *
+ * @since 2.1.0
+ *
+ * @param object $category Category Object
+ */
+ function wxr_cat_name( $category ) {
+ if ( empty( $category->name ) )
+ return;
+
+ echo '<wp:cat_name>' . wxr_cdata( $category->name ) . '</wp:cat_name>';
+ }
+
+ /**
+ * Output a category_description XML tag from a given category object
+ *
+ * @since 2.1.0
+ *
+ * @param object $category Category Object
+ */
+ function wxr_category_description( $category ) {
+ if ( empty( $category->description ) )
+ return;
+
+ echo '<wp:category_description>' . wxr_cdata( $category->description ) . '</wp:category_description>';
+ }
+
+ /**
+ * Output a tag_name XML tag from a given tag object
+ *
+ * @since 2.3.0
+ *
+ * @param object $tag Tag Object
+ */
+ function wxr_tag_name( $tag ) {
+ if ( empty( $tag->name ) )
+ return;
+
+ echo '<wp:tag_name>' . wxr_cdata( $tag->name ) . '</wp:tag_name>';
+ }
+
+ /**
+ * Output a tag_description XML tag from a given tag object
+ *
+ * @since 2.3.0
+ *
+ * @param object $tag Tag Object
+ */
+ function wxr_tag_description( $tag ) {
+ if ( empty( $tag->description ) )
+ return;
+
+ echo '<wp:tag_description>' . wxr_cdata( $tag->description ) . '</wp:tag_description>';
+ }
+
+ /**
+ * Output a term_name XML tag from a given term object
+ *
+ * @since 2.9.0
+ *
+ * @param object $term Term Object
+ */
+ function wxr_term_name( $term ) {
+ if ( empty( $term->name ) )
+ return;
+
+ echo '<wp:term_name>' . wxr_cdata( $term->name ) . '</wp:term_name>';
+ }
+
+ /**
+ * Output a term_description XML tag from a given term object
+ *
+ * @since 2.9.0
+ *
+ * @param object $term Term Object
+ */
+ function wxr_term_description( $term ) {
+ if ( empty( $term->description ) )
+ return;
+
+ echo '<wp:term_description>' . wxr_cdata( $term->description ) . '</wp:term_description>';
+ }
+
+ /**
+ * Output list of authors with posts
+ *
+ * @since 3.1.0
+ */
+ function wxr_authors_list() {
+ global $wpdb;
+
+ $authors = array();
+ $results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft'" );
+ foreach ( (array) $results as $result )
+ $authors[] = get_userdata( $result->post_author );
+
+ $authors = array_filter( $authors );
+
+ foreach ( $authors as $author ) {
+ echo "\t<wp:author>";
+ echo '<wp:author_id>' . $author->ID . '</wp:author_id>';
+ echo '<wp:author_login>' . $author->user_login . '</wp:author_login>';
+ echo '<wp:author_email>' . $author->user_email . '</wp:author_email>';
+ echo '<wp:author_display_name>' . wxr_cdata( $author->display_name ) . '</wp:author_display_name>';
+ echo '<wp:author_first_name>' . wxr_cdata( $author->user_firstname ) . '</wp:author_first_name>';
+ echo '<wp:author_last_name>' . wxr_cdata( $author->user_lastname ) . '</wp:author_last_name>';
+ echo "</wp:author>\n";
+ }
+ }
+
+ /**
+ * Ouput all navigation menu terms
+ *
+ * @since 3.1.0
+ */
+ function wxr_nav_menu_terms() {
+ $nav_menus = wp_get_nav_menus();
+ if ( empty( $nav_menus ) || ! is_array( $nav_menus ) )
+ return;
+
+ foreach ( $nav_menus as $menu ) {
+ echo "\t<wp:term><wp:term_id>{$menu->term_id}</wp:term_id><wp:term_taxonomy>nav_menu</wp:term_taxonomy><wp:term_slug>{$menu->slug}</wp:term_slug>";
+ wxr_term_name( $menu );
+ echo "</wp:term>\n";
+ }
+ }
+
+ /**
+ * Output list of taxonomy terms, in XML tag format, associated with a post
+ *
+ * @since 2.3.0
+ */
+ function wxr_post_taxonomy() {
+ $post = get_post();
+
+ $taxonomies = get_object_taxonomies( $post->post_type );
+ if ( empty( $taxonomies ) )
+ return;
+ $terms = wp_get_object_terms( $post->ID, $taxonomies );
+
+ foreach ( (array) $terms as $term ) {
+ echo "\t\t<category domain=\"{$term->taxonomy}\" nicename=\"{$term->slug}\">" . wxr_cdata( $term->name ) . "</category>\n";
+ }
+ }
+
+ function wxr_filter_postmeta( $return_me, $meta_key ) {
+ if ( '_edit_lock' == $meta_key )
+ $return_me = true;
+ return $return_me;
+ }
+ add_filter( 'wxr_export_skip_postmeta', 'wxr_filter_postmeta', 10, 2 );
+
+ echo '<?xml version="1.0" encoding="' . get_bloginfo('charset') . "\" ?>\n";
+
+ ?>
+<!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. -->
+<!-- It contains information about your site's posts, pages, comments, categories, and other content. -->
+<!-- You may use this file to transfer that content from one site to another. -->
+<!-- This file is not intended to serve as a complete backup of your site. -->
+
+<!-- To import this information into a WordPress site follow these steps: -->
+<!-- 1. Log in to that site as an administrator. -->
+<!-- 2. Go to Tools: Import in the WordPress admin panel. -->
+<!-- 3. Install the "WordPress" importer from the list. -->
+<!-- 4. Activate & Run Importer. -->
+<!-- 5. Upload this file using the form provided on that page. -->
+<!-- 6. You will first be asked to map the authors in this export file to users -->
+<!-- on the site. For each author, you may choose to map to an -->
+<!-- existing user on the site or to create a new user. -->
+<!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. -->
+<!-- contained in this file into your site. -->
+
+<?php the_generator( 'export' ); ?>
+<rss version="2.0"
+ xmlns:excerpt="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/excerpt/"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:wp="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/"
+>
+
+<channel>
+ <title><?php bloginfo_rss( 'name' ); ?></title>
+ <link><?php bloginfo_rss( 'url' ); ?></link>
+ <description><?php bloginfo_rss( 'description' ); ?></description>
+ <pubDate><?php echo date( 'D, d M Y H:i:s +0000' ); ?></pubDate>
+ <language><?php bloginfo_rss( 'language' ); ?></language>
+ <wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version>
+ <wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url>
+ <wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url>
+
+<?php wxr_authors_list(); ?>
+
+<?php foreach ( $cats as $c ) : ?>
+ <wp:category><wp:term_id><?php echo $c->term_id ?></wp:term_id><wp:category_nicename><?php echo $c->slug; ?></wp:category_nicename><wp:category_parent><?php echo $c->parent ? $cats[$c->parent]->slug : ''; ?></wp:category_parent><?php wxr_cat_name( $c ); ?><?php wxr_category_description( $c ); ?></wp:category>
+<?php endforeach; ?>
+<?php foreach ( $tags as $t ) : ?>
+ <wp:tag><wp:term_id><?php echo $t->term_id ?></wp:term_id><wp:tag_slug><?php echo $t->slug; ?></wp:tag_slug><?php wxr_tag_name( $t ); ?><?php wxr_tag_description( $t ); ?></wp:tag>
+<?php endforeach; ?>
+<?php foreach ( $terms as $t ) : ?>
+ <wp:term><wp:term_id><?php echo $t->term_id ?></wp:term_id><wp:term_taxonomy><?php echo $t->taxonomy; ?></wp:term_taxonomy><wp:term_slug><?php echo $t->slug; ?></wp:term_slug><wp:term_parent><?php echo $t->parent ? $terms[$t->parent]->slug : ''; ?></wp:term_parent><?php wxr_term_name( $t ); ?><?php wxr_term_description( $t ); ?></wp:term>
+<?php endforeach; ?>
+<?php if ( 'all' == $args['content'] ) wxr_nav_menu_terms(); ?>
+
+ <?php do_action( 'rss2_head' ); ?>
+
+<?php if ( $post_ids ) {
+ global $wp_query;
+ $wp_query->in_the_loop = true; // Fake being in the loop.
+
+ // fetch 20 posts at a time rather than loading the entire table into memory
+ while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) {
+ $where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')';
+ $posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
+
+ // Begin Loop
+ foreach ( $posts as $post ) {
+ setup_postdata( $post );
+ $is_sticky = is_sticky( $post->ID ) ? 1 : 0;
+?>
+ <item>
+ <title><?php echo apply_filters( 'the_title_rss', $post->post_title ); ?></title>
+ <link><?php the_permalink_rss() ?></link>
+ <pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
+ <dc:creator><?php echo get_the_author_meta( 'login' ); ?></dc:creator>
+ <guid isPermaLink="false"><?php the_guid(); ?></guid>
+ <description></description>
+ <content:encoded><?php echo wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) ); ?></content:encoded>
+ <excerpt:encoded><?php echo wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) ); ?></excerpt:encoded>
+ <wp:post_id><?php echo $post->ID; ?></wp:post_id>
+ <wp:post_date><?php echo $post->post_date; ?></wp:post_date>
+ <wp:post_date_gmt><?php echo $post->post_date_gmt; ?></wp:post_date_gmt>
+ <wp:comment_status><?php echo $post->comment_status; ?></wp:comment_status>
+ <wp:ping_status><?php echo $post->ping_status; ?></wp:ping_status>
+ <wp:post_name><?php echo $post->post_name; ?></wp:post_name>
+ <wp:status><?php echo $post->post_status; ?></wp:status>
+ <wp:post_parent><?php echo $post->post_parent; ?></wp:post_parent>
+ <wp:menu_order><?php echo $post->menu_order; ?></wp:menu_order>
+ <wp:post_type><?php echo $post->post_type; ?></wp:post_type>
+ <wp:post_password><?php echo $post->post_password; ?></wp:post_password>
+ <wp:is_sticky><?php echo $is_sticky; ?></wp:is_sticky>
+<?php if ( $post->post_type == 'attachment' ) : ?>
+ <wp:attachment_url><?php echo wp_get_attachment_url( $post->ID ); ?></wp:attachment_url>
+<?php endif; ?>
+<?php wxr_post_taxonomy(); ?>
+<?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
+ foreach ( $postmeta as $meta ) :
+ if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) )
+ continue;
+ ?>
+ <wp:postmeta>
+ <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key>
+ <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value>
+ </wp:postmeta>
+<?php endforeach; ?>
+<?php $comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) );
+ foreach ( $comments as $c ) : ?>
+ <wp:comment>
+ <wp:comment_id><?php echo $c->comment_ID; ?></wp:comment_id>
+ <wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author>
+ <wp:comment_author_email><?php echo $c->comment_author_email; ?></wp:comment_author_email>
+ <wp:comment_author_url><?php echo esc_url_raw( $c->comment_author_url ); ?></wp:comment_author_url>
+ <wp:comment_author_IP><?php echo $c->comment_author_IP; ?></wp:comment_author_IP>
+ <wp:comment_date><?php echo $c->comment_date; ?></wp:comment_date>
+ <wp:comment_date_gmt><?php echo $c->comment_date_gmt; ?></wp:comment_date_gmt>
+ <wp:comment_content><?php echo wxr_cdata( $c->comment_content ) ?></wp:comment_content>
+ <wp:comment_approved><?php echo $c->comment_approved; ?></wp:comment_approved>
+ <wp:comment_type><?php echo $c->comment_type; ?></wp:comment_type>
+ <wp:comment_parent><?php echo $c->comment_parent; ?></wp:comment_parent>
+ <wp:comment_user_id><?php echo $c->user_id; ?></wp:comment_user_id>
+<?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) );
+ foreach ( $c_meta as $meta ) : ?>
+ <wp:commentmeta>
+ <wp:meta_key><?php echo $meta->meta_key; ?></wp:meta_key>
+ <wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value>
+ </wp:commentmeta>
+<?php endforeach; ?>
+ </wp:comment>
+<?php endforeach; ?>
+ </item>
+<?php
+ }
+ }
+} ?>
+</channel>
+</rss>
+<?php
+}
diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php
new file mode 100644
index 0000000000..ca424264bc
--- /dev/null
+++ b/src/wp-admin/includes/file.php
@@ -0,0 +1,1071 @@
+<?php
+/**
+ * Functions for reading, writing, modifying, and deleting files on the file system.
+ * Includes functionality for theme-specific files as well as operations for uploading,
+ * archiving, and rendering output when necessary.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** The descriptions for theme files. */
+$wp_file_descriptions = array(
+ 'index.php' => __( 'Main Index Template' ),
+ 'style.css' => __( 'Stylesheet' ),
+ 'editor-style.css' => __( 'Visual Editor Stylesheet' ),
+ 'editor-style-rtl.css' => __( 'Visual Editor RTL Stylesheet' ),
+ 'rtl.css' => __( 'RTL Stylesheet' ),
+ 'comments.php' => __( 'Comments' ),
+ 'comments-popup.php' => __( 'Popup Comments' ),
+ 'footer.php' => __( 'Footer' ),
+ 'header.php' => __( 'Header' ),
+ 'sidebar.php' => __( 'Sidebar' ),
+ 'archive.php' => __( 'Archives' ),
+ 'author.php' => __( 'Author Template' ),
+ 'tag.php' => __( 'Tag Template' ),
+ 'category.php' => __( 'Category Template' ),
+ 'page.php' => __( 'Page Template' ),
+ 'search.php' => __( 'Search Results' ),
+ 'searchform.php' => __( 'Search Form' ),
+ 'single.php' => __( 'Single Post' ),
+ '404.php' => __( '404 Template' ),
+ 'link.php' => __( 'Links Template' ),
+ 'functions.php' => __( 'Theme Functions' ),
+ 'attachment.php' => __( 'Attachment Template' ),
+ 'image.php' => __('Image Attachment Template'),
+ 'video.php' => __('Video Attachment Template'),
+ 'audio.php' => __('Audio Attachment Template'),
+ 'application.php' => __('Application Attachment Template'),
+ 'my-hacks.php' => __( 'my-hacks.php (legacy hacks support)' ),
+ '.htaccess' => __( '.htaccess (for rewrite rules )' ),
+ // Deprecated files
+ 'wp-layout.css' => __( 'Stylesheet' ),
+ 'wp-comments.php' => __( 'Comments Template' ),
+ 'wp-comments-popup.php' => __( 'Popup Comments Template' ),
+);
+
+/**
+ * Get the description for standard WordPress theme files and other various standard
+ * WordPress files
+ *
+ * @since 1.5.0
+ *
+ * @uses _cleanup_header_comment
+ * @uses $wp_file_descriptions
+ * @param string $file Filesystem path or filename
+ * @return string Description of file from $wp_file_descriptions or basename of $file if description doesn't exist
+ */
+function get_file_description( $file ) {
+ global $wp_file_descriptions;
+
+ if ( isset( $wp_file_descriptions[basename( $file )] ) ) {
+ return $wp_file_descriptions[basename( $file )];
+ }
+ elseif ( file_exists( $file ) && is_file( $file ) ) {
+ $template_data = implode( '', file( $file ) );
+ if ( preg_match( '|Template Name:(.*)$|mi', $template_data, $name ))
+ return sprintf( __( '%s Page Template' ), _cleanup_header_comment($name[1]) );
+ }
+
+ return trim( basename( $file ) );
+}
+
+/**
+ * Get the absolute filesystem path to the root of the WordPress installation
+ *
+ * @since 1.5.0
+ *
+ * @uses get_option
+ * @return string Full filesystem path to the root of the WordPress installation
+ */
+function get_home_path() {
+ $home = get_option( 'home' );
+ $siteurl = get_option( 'siteurl' );
+ if ( ! empty( $home ) && 0 !== strcasecmp( $home, $siteurl ) ) {
+ $wp_path_rel_to_home = str_ireplace( $home, '', $siteurl ); /* $siteurl - $home */
+ $pos = strripos( str_replace( '\\', '/', $_SERVER['SCRIPT_FILENAME'] ), trailingslashit( $wp_path_rel_to_home ) );
+ $home_path = substr( $_SERVER['SCRIPT_FILENAME'], 0, $pos );
+ $home_path = trailingslashit( $home_path );
+ } else {
+ $home_path = ABSPATH;
+ }
+
+ return str_replace( '\\', '/', $home_path );
+}
+
+/**
+ * Get the real file system path to a file to edit within the admin
+ *
+ * If the $file is index.php or .htaccess this function will assume it is relative
+ * to the install root, otherwise it is assumed the file is relative to the wp-content
+ * directory
+ *
+ * @since 1.5.0
+ *
+ * @uses get_home_path
+ * @uses WP_CONTENT_DIR full filesystem path to the wp-content directory
+ * @param string $file filesystem path relative to the WordPress install directory or to the wp-content directory
+ * @return string full file system path to edit
+ */
+function get_real_file_to_edit( $file ) {
+ if ('index.php' == $file || '.htaccess' == $file ) {
+ $real_file = get_home_path() . $file;
+ } else {
+ $real_file = WP_CONTENT_DIR . $file;
+ }
+
+ return $real_file;
+}
+
+/**
+ * Returns a listing of all files in the specified folder and all subdirectories up to 100 levels deep.
+ * The depth of the recursiveness can be controlled by the $levels param.
+ *
+ * @since 2.6.0
+ *
+ * @param string $folder Full path to folder
+ * @param int $levels (optional) Levels of folders to follow, Default: 100 (PHP Loop limit).
+ * @return bool|array False on failure, Else array of files
+ */
+function list_files( $folder = '', $levels = 100 ) {
+ if ( empty($folder) )
+ return false;
+
+ if ( ! $levels )
+ return false;
+
+ $files = array();
+ if ( $dir = @opendir( $folder ) ) {
+ while (($file = readdir( $dir ) ) !== false ) {
+ if ( in_array($file, array('.', '..') ) )
+ continue;
+ if ( is_dir( $folder . '/' . $file ) ) {
+ $files2 = list_files( $folder . '/' . $file, $levels - 1);
+ if ( $files2 )
+ $files = array_merge($files, $files2 );
+ else
+ $files[] = $folder . '/' . $file . '/';
+ } else {
+ $files[] = $folder . '/' . $file;
+ }
+ }
+ }
+ @closedir( $dir );
+ return $files;
+}
+
+/**
+ * Returns a filename of a Temporary unique file.
+ * Please note that the calling function must unlink() this itself.
+ *
+ * The filename is based off the passed parameter or defaults to the current unix timestamp,
+ * while the directory can either be passed as well, or by leaving it blank, default to a writable temporary directory.
+ *
+ * @since 2.6.0
+ *
+ * @param string $filename (optional) Filename to base the Unique file off
+ * @param string $dir (optional) Directory to store the file in
+ * @return string a writable filename
+ */
+function wp_tempnam($filename = '', $dir = '') {
+ if ( empty($dir) )
+ $dir = get_temp_dir();
+ $filename = basename($filename);
+ if ( empty($filename) )
+ $filename = time();
+
+ $filename = preg_replace('|\..*$|', '.tmp', $filename);
+ $filename = $dir . wp_unique_filename($dir, $filename);
+ touch($filename);
+ return $filename;
+}
+
+/**
+ * Make sure that the file that was requested to edit, is allowed to be edited
+ *
+ * Function will die if if you are not allowed to edit the file
+ *
+ * @since 1.5.0
+ *
+ * @uses wp_die
+ * @uses validate_file
+ * @param string $file file the users is attempting to edit
+ * @param array $allowed_files Array of allowed files to edit, $file must match an entry exactly
+ * @return null
+ */
+function validate_file_to_edit( $file, $allowed_files = '' ) {
+ $code = validate_file( $file, $allowed_files );
+
+ if (!$code )
+ return $file;
+
+ switch ( $code ) {
+ case 1 :
+ wp_die( __('Sorry, can&#8217;t edit files with &#8220;..&#8221; in the name. If you are trying to edit a file in your WordPress home directory, you can just type the name of the file in.' ));
+
+ //case 2 :
+ // wp_die( __('Sorry, can&#8217;t call files with their real path.' ));
+
+ case 3 :
+ wp_die( __('Sorry, that file cannot be edited.' ));
+ }
+}
+
+/**
+ * Handle PHP uploads in WordPress, sanitizing file names, checking extensions for mime type,
+ * and moving the file to the appropriate directory within the uploads directory.
+ *
+ * @since 2.0
+ *
+ * @uses wp_handle_upload_error
+ * @uses apply_filters
+ * @uses is_multisite
+ * @uses wp_check_filetype_and_ext
+ * @uses current_user_can
+ * @uses wp_upload_dir
+ * @uses wp_unique_filename
+ * @uses delete_transient
+ * @param array $file Reference to a single element of $_FILES. Call the function once for each uploaded file.
+ * @param array $overrides Optional. An associative array of names=>values to override default variables with extract( $overrides, EXTR_OVERWRITE ).
+ * @param string $time Optional. Time formatted in 'yyyy/mm'.
+ * @return array On success, returns an associative array of file attributes. On failure, returns $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).
+ */
+function wp_handle_upload( &$file, $overrides = false, $time = null ) {
+ // The default error handler.
+ if ( ! function_exists( 'wp_handle_upload_error' ) ) {
+ function wp_handle_upload_error( &$file, $message ) {
+ return array( 'error'=>$message );
+ }
+ }
+
+ $file = apply_filters( 'wp_handle_upload_prefilter', $file );
+
+ // You may define your own function and pass the name in $overrides['upload_error_handler']
+ $upload_error_handler = 'wp_handle_upload_error';
+
+ // You may have had one or more 'wp_handle_upload_prefilter' functions error out the file. Handle that gracefully.
+ if ( isset( $file['error'] ) && !is_numeric( $file['error'] ) && $file['error'] )
+ return $upload_error_handler( $file, $file['error'] );
+
+ // You may define your own function and pass the name in $overrides['unique_filename_callback']
+ $unique_filename_callback = null;
+
+ // $_POST['action'] must be set and its value must equal $overrides['action'] or this:
+ $action = 'wp_handle_upload';
+
+ // Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
+ $upload_error_strings = array( false,
+ __( "The uploaded file exceeds the upload_max_filesize directive in php.ini." ),
+ __( "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form." ),
+ __( "The uploaded file was only partially uploaded." ),
+ __( "No file was uploaded." ),
+ '',
+ __( "Missing a temporary folder." ),
+ __( "Failed to write file to disk." ),
+ __( "File upload stopped by extension." ));
+
+ // All tests are on by default. Most can be turned off by $overrides[{test_name}] = false;
+ $test_form = true;
+ $test_size = true;
+ $test_upload = true;
+
+ // If you override this, you must provide $ext and $type!!!!
+ $test_type = true;
+ $mimes = false;
+
+ // Install user overrides. Did we mention that this voids your warranty?
+ if ( is_array( $overrides ) )
+ extract( $overrides, EXTR_OVERWRITE );
+
+ // A correct form post will pass this test.
+ if ( $test_form && (!isset( $_POST['action'] ) || ($_POST['action'] != $action ) ) )
+ return call_user_func($upload_error_handler, $file, __( 'Invalid form submission.' ));
+
+ // A successful upload will pass this test. It makes no sense to override this one.
+ if ( $file['error'] > 0 )
+ return call_user_func($upload_error_handler, $file, $upload_error_strings[$file['error']] );
+
+ // A non-empty file will pass this test.
+ if ( $test_size && !($file['size'] > 0 ) ) {
+ if ( is_multisite() )
+ $error_msg = __( 'File is empty. Please upload something more substantial.' );
+ else
+ $error_msg = __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' );
+ return call_user_func($upload_error_handler, $file, $error_msg);
+ }
+
+ // A properly uploaded file will pass this test. There should be no reason to override this one.
+ if ( $test_upload && ! @ is_uploaded_file( $file['tmp_name'] ) )
+ return call_user_func($upload_error_handler, $file, __( 'Specified file failed upload test.' ));
+
+ // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
+ if ( $test_type ) {
+ $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes );
+
+ extract( $wp_filetype );
+
+ // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
+ if ( $proper_filename )
+ $file['name'] = $proper_filename;
+
+ if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
+ return call_user_func($upload_error_handler, $file, __( 'Sorry, this file type is not permitted for security reasons.' ));
+
+ if ( !$ext )
+ $ext = ltrim(strrchr($file['name'], '.'), '.');
+
+ if ( !$type )
+ $type = $file['type'];
+ } else {
+ $type = '';
+ }
+
+ // A writable uploads dir will pass this test. Again, there's no point overriding this one.
+ if ( ! ( ( $uploads = wp_upload_dir($time) ) && false === $uploads['error'] ) )
+ return call_user_func($upload_error_handler, $file, $uploads['error'] );
+
+ $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );
+
+ // Move the file to the uploads dir
+ $new_file = $uploads['path'] . "/$filename";
+ if ( false === @ move_uploaded_file( $file['tmp_name'], $new_file ) ) {
+ if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
+ $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
+ else
+ $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
+
+ return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $error_path ) );
+ }
+
+ // Set correct file permissions
+ $stat = stat( dirname( $new_file ));
+ $perms = $stat['mode'] & 0000666;
+ @ chmod( $new_file, $perms );
+
+ // Compute the URL
+ $url = $uploads['url'] . "/$filename";
+
+ if ( is_multisite() )
+ delete_transient( 'dirsize_cache' );
+
+ return apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $type ), 'upload' );
+}
+
+/**
+ * Handle sideloads, which is the process of retrieving a media item from another server instead of
+ * a traditional media upload. This process involves sanitizing the filename, checking extensions
+ * for mime type, and moving the file to the appropriate directory within the uploads directory.
+ *
+ * @since 2.6.0
+ *
+ * @uses wp_handle_upload_error
+ * @uses apply_filters
+ * @uses wp_check_filetype_and_ext
+ * @uses current_user_can
+ * @uses wp_upload_dir
+ * @uses wp_unique_filename
+ * @param array $file an array similar to that of a PHP $_FILES POST array
+ * @param array $overrides Optional. An associative array of names=>values to override default variables with extract( $overrides, EXTR_OVERWRITE ).
+ * @param string $time Optional. Time formatted in 'yyyy/mm'.
+ * @return array On success, returns an associative array of file attributes. On failure, returns $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).
+ */
+function wp_handle_sideload( &$file, $overrides = false, $time = null ) {
+ // The default error handler.
+ if (! function_exists( 'wp_handle_upload_error' ) ) {
+ function wp_handle_upload_error( &$file, $message ) {
+ return array( 'error'=>$message );
+ }
+ }
+
+ // You may define your own function and pass the name in $overrides['upload_error_handler']
+ $upload_error_handler = 'wp_handle_upload_error';
+
+ // You may define your own function and pass the name in $overrides['unique_filename_callback']
+ $unique_filename_callback = null;
+
+ // $_POST['action'] must be set and its value must equal $overrides['action'] or this:
+ $action = 'wp_handle_sideload';
+
+ // Courtesy of php.net, the strings that describe the error indicated in $_FILES[{form field}]['error'].
+ $upload_error_strings = array( false,
+ __( "The uploaded file exceeds the <code>upload_max_filesize</code> directive in <code>php.ini</code>." ),
+ __( "The uploaded file exceeds the <em>MAX_FILE_SIZE</em> directive that was specified in the HTML form." ),
+ __( "The uploaded file was only partially uploaded." ),
+ __( "No file was uploaded." ),
+ '',
+ __( "Missing a temporary folder." ),
+ __( "Failed to write file to disk." ),
+ __( "File upload stopped by extension." ));
+
+ // All tests are on by default. Most can be turned off by $overrides[{test_name}] = false;
+ $test_form = true;
+ $test_size = true;
+
+ // If you override this, you must provide $ext and $type!!!!
+ $test_type = true;
+ $mimes = false;
+
+ // Install user overrides. Did we mention that this voids your warranty?
+ if ( is_array( $overrides ) )
+ extract( $overrides, EXTR_OVERWRITE );
+
+ // A correct form post will pass this test.
+ if ( $test_form && (!isset( $_POST['action'] ) || ($_POST['action'] != $action ) ) )
+ return $upload_error_handler( $file, __( 'Invalid form submission.' ));
+
+ // A successful upload will pass this test. It makes no sense to override this one.
+ if ( ! empty( $file['error'] ) )
+ return $upload_error_handler( $file, $upload_error_strings[$file['error']] );
+
+ // A non-empty file will pass this test.
+ if ( $test_size && !(filesize($file['tmp_name']) > 0 ) )
+ return $upload_error_handler( $file, __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini.' ));
+
+ // A properly uploaded file will pass this test. There should be no reason to override this one.
+ if (! @ is_file( $file['tmp_name'] ) )
+ return $upload_error_handler( $file, __( 'Specified file does not exist.' ));
+
+ // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
+ if ( $test_type ) {
+ $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes );
+
+ extract( $wp_filetype );
+
+ // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
+ if ( $proper_filename )
+ $file['name'] = $proper_filename;
+
+ if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
+ return $upload_error_handler( $file, __( 'Sorry, this file type is not permitted for security reasons.' ));
+
+ if ( !$ext )
+ $ext = ltrim(strrchr($file['name'], '.'), '.');
+
+ if ( !$type )
+ $type = $file['type'];
+ }
+
+ // A writable uploads dir will pass this test. Again, there's no point overriding this one.
+ if ( ! ( ( $uploads = wp_upload_dir( $time ) ) && false === $uploads['error'] ) )
+ return $upload_error_handler( $file, $uploads['error'] );
+
+ $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );
+
+ // Strip the query strings.
+ $filename = str_replace('?','-', $filename);
+ $filename = str_replace('&','-', $filename);
+
+ // Move the file to the uploads dir
+ $new_file = $uploads['path'] . "/$filename";
+ if ( false === @ rename( $file['tmp_name'], $new_file ) ) {
+ if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
+ $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
+ else
+ $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
+ return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $error_path ) );
+ }
+
+ // Set correct file permissions
+ $stat = stat( dirname( $new_file ));
+ $perms = $stat['mode'] & 0000666;
+ @ chmod( $new_file, $perms );
+
+ // Compute the URL
+ $url = $uploads['url'] . "/$filename";
+
+ $return = apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $type ), 'sideload' );
+
+ return $return;
+}
+
+/**
+ * Downloads a url to a local temporary file using the WordPress HTTP Class.
+ * Please note, That the calling function must unlink() the file.
+ *
+ * @since 2.5.0
+ *
+ * @param string $url the URL of the file to download
+ * @param int $timeout The timeout for the request to download the file default 300 seconds
+ * @return mixed WP_Error on failure, string Filename on success.
+ */
+function download_url( $url, $timeout = 300 ) {
+ //WARNING: The file is not automatically deleted, The script must unlink() the file.
+ if ( ! $url )
+ return new WP_Error('http_no_url', __('Invalid URL Provided.'));
+
+ $tmpfname = wp_tempnam($url);
+ if ( ! $tmpfname )
+ return new WP_Error('http_no_file', __('Could not create Temporary file.'));
+
+ $response = wp_safe_remote_get( $url, array( 'timeout' => $timeout, 'stream' => true, 'filename' => $tmpfname ) );
+
+ if ( is_wp_error( $response ) ) {
+ unlink( $tmpfname );
+ return $response;
+ }
+
+ if ( 200 != wp_remote_retrieve_response_code( $response ) ){
+ unlink( $tmpfname );
+ return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ) );
+ }
+
+ return $tmpfname;
+}
+
+/**
+ * Unzips a specified ZIP file to a location on the Filesystem via the WordPress Filesystem Abstraction.
+ * Assumes that WP_Filesystem() has already been called and set up. Does not extract a root-level __MACOSX directory, if present.
+ *
+ * Attempts to increase the PHP Memory limit to 256M before uncompressing,
+ * However, The most memory required shouldn't be much larger than the Archive itself.
+ *
+ * @since 2.5.0
+ *
+ * @param string $file Full path and filename of zip archive
+ * @param string $to Full path on the filesystem to extract archive to
+ * @return mixed WP_Error on failure, True on success
+ */
+function unzip_file($file, $to) {
+ global $wp_filesystem;
+
+ if ( ! $wp_filesystem || !is_object($wp_filesystem) )
+ return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
+
+ // Unzip can use a lot of memory, but not this much hopefully
+ @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+
+ $needed_dirs = array();
+ $to = trailingslashit($to);
+
+ // Determine any parent dir's needed (of the upgrade directory)
+ if ( ! $wp_filesystem->is_dir($to) ) { //Only do parents if no children exist
+ $path = preg_split('![/\\\]!', untrailingslashit($to));
+ for ( $i = count($path); $i >= 0; $i-- ) {
+ if ( empty($path[$i]) )
+ continue;
+
+ $dir = implode('/', array_slice($path, 0, $i+1) );
+ if ( preg_match('!^[a-z]:$!i', $dir) ) // Skip it if it looks like a Windows Drive letter.
+ continue;
+
+ if ( ! $wp_filesystem->is_dir($dir) )
+ $needed_dirs[] = $dir;
+ else
+ break; // A folder exists, therefor, we dont need the check the levels below this
+ }
+ }
+
+ if ( class_exists('ZipArchive') && apply_filters('unzip_file_use_ziparchive', true ) ) {
+ $result = _unzip_file_ziparchive($file, $to, $needed_dirs);
+ if ( true === $result ) {
+ return $result;
+ } elseif ( is_wp_error($result) ) {
+ if ( 'incompatible_archive' != $result->get_error_code() )
+ return $result;
+ }
+ }
+ // Fall through to PclZip if ZipArchive is not available, or encountered an error opening the file.
+ return _unzip_file_pclzip($file, $to, $needed_dirs);
+}
+
+/**
+ * This function should not be called directly, use unzip_file instead. Attempts to unzip an archive using the ZipArchive class.
+ * Assumes that WP_Filesystem() has already been called and set up.
+ *
+ * @since 3.0.0
+ * @see unzip_file
+ * @access private
+ *
+ * @param string $file Full path and filename of zip archive
+ * @param string $to Full path on the filesystem to extract archive to
+ * @param array $needed_dirs A partial list of required folders needed to be created.
+ * @return mixed WP_Error on failure, True on success
+ */
+function _unzip_file_ziparchive($file, $to, $needed_dirs = array() ) {
+ global $wp_filesystem;
+
+ $z = new ZipArchive();
+
+ // PHP4-compat - php4 classes can't contain constants
+ $zopen = $z->open($file, /* ZIPARCHIVE::CHECKCONS */ 4);
+ if ( true !== $zopen )
+ return new WP_Error('incompatible_archive', __('Incompatible Archive.'));
+
+ for ( $i = 0; $i < $z->numFiles; $i++ ) {
+ if ( ! $info = $z->statIndex($i) )
+ return new WP_Error('stat_failed', __('Could not retrieve file from archive.'));
+
+ if ( '__MACOSX/' === substr($info['name'], 0, 9) ) // Skip the OS X-created __MACOSX directory
+ continue;
+
+ if ( '/' == substr($info['name'], -1) ) // directory
+ $needed_dirs[] = $to . untrailingslashit($info['name']);
+ else
+ $needed_dirs[] = $to . untrailingslashit(dirname($info['name']));
+ }
+
+ $needed_dirs = array_unique($needed_dirs);
+ foreach ( $needed_dirs as $dir ) {
+ // Check the parent folders of the folders all exist within the creation array.
+ if ( untrailingslashit($to) == $dir ) // Skip over the working directory, We know this exists (or will exist)
+ continue;
+ if ( strpos($dir, $to) === false ) // If the directory is not within the working directory, Skip it
+ continue;
+
+ $parent_folder = dirname($dir);
+ while ( !empty($parent_folder) && untrailingslashit($to) != $parent_folder && !in_array($parent_folder, $needed_dirs) ) {
+ $needed_dirs[] = $parent_folder;
+ $parent_folder = dirname($parent_folder);
+ }
+ }
+ asort($needed_dirs);
+
+ // Create those directories if need be:
+ foreach ( $needed_dirs as $_dir ) {
+ if ( ! $wp_filesystem->mkdir($_dir, FS_CHMOD_DIR) && ! $wp_filesystem->is_dir($_dir) ) // Only check to see if the Dir exists upon creation failure. Less I/O this way.
+ return new WP_Error('mkdir_failed', __('Could not create directory.'), $_dir);
+ }
+ unset($needed_dirs);
+
+ for ( $i = 0; $i < $z->numFiles; $i++ ) {
+ if ( ! $info = $z->statIndex($i) )
+ return new WP_Error('stat_failed', __('Could not retrieve file from archive.'));
+
+ if ( '/' == substr($info['name'], -1) ) // directory
+ continue;
+
+ if ( '__MACOSX/' === substr($info['name'], 0, 9) ) // Don't extract the OS X-created __MACOSX directory files
+ continue;
+
+ $contents = $z->getFromIndex($i);
+ if ( false === $contents )
+ return new WP_Error('extract_failed', __('Could not extract file from archive.'), $info['name']);
+
+ if ( ! $wp_filesystem->put_contents( $to . $info['name'], $contents, FS_CHMOD_FILE) )
+ return new WP_Error('copy_failed', __('Could not copy file.'), $to . $info['name']);
+ }
+
+ $z->close();
+
+ return true;
+}
+
+/**
+ * This function should not be called directly, use unzip_file instead. Attempts to unzip an archive using the PclZip library.
+ * Assumes that WP_Filesystem() has already been called and set up.
+ *
+ * @since 3.0.0
+ * @see unzip_file
+ * @access private
+ *
+ * @param string $file Full path and filename of zip archive
+ * @param string $to Full path on the filesystem to extract archive to
+ * @param array $needed_dirs A partial list of required folders needed to be created.
+ * @return mixed WP_Error on failure, True on success
+ */
+function _unzip_file_pclzip($file, $to, $needed_dirs = array()) {
+ global $wp_filesystem;
+
+ // See #15789 - PclZip uses string functions on binary data, If it's overloaded with Multibyte safe functions the results are incorrect.
+ if ( ini_get('mbstring.func_overload') && function_exists('mb_internal_encoding') ) {
+ $previous_encoding = mb_internal_encoding();
+ mb_internal_encoding('ISO-8859-1');
+ }
+
+ require_once(ABSPATH . 'wp-admin/includes/class-pclzip.php');
+
+ $archive = new PclZip($file);
+
+ $archive_files = $archive->extract(PCLZIP_OPT_EXTRACT_AS_STRING);
+
+ if ( isset($previous_encoding) )
+ mb_internal_encoding($previous_encoding);
+
+ // Is the archive valid?
+ if ( !is_array($archive_files) )
+ return new WP_Error('incompatible_archive', __('Incompatible Archive.'), $archive->errorInfo(true));
+
+ if ( 0 == count($archive_files) )
+ return new WP_Error('empty_archive', __('Empty archive.'));
+
+ // Determine any children directories needed (From within the archive)
+ foreach ( $archive_files as $file ) {
+ if ( '__MACOSX/' === substr($file['filename'], 0, 9) ) // Skip the OS X-created __MACOSX directory
+ continue;
+
+ $needed_dirs[] = $to . untrailingslashit( $file['folder'] ? $file['filename'] : dirname($file['filename']) );
+ }
+
+ $needed_dirs = array_unique($needed_dirs);
+ foreach ( $needed_dirs as $dir ) {
+ // Check the parent folders of the folders all exist within the creation array.
+ if ( untrailingslashit($to) == $dir ) // Skip over the working directory, We know this exists (or will exist)
+ continue;
+ if ( strpos($dir, $to) === false ) // If the directory is not within the working directory, Skip it
+ continue;
+
+ $parent_folder = dirname($dir);
+ while ( !empty($parent_folder) && untrailingslashit($to) != $parent_folder && !in_array($parent_folder, $needed_dirs) ) {
+ $needed_dirs[] = $parent_folder;
+ $parent_folder = dirname($parent_folder);
+ }
+ }
+ asort($needed_dirs);
+
+ // Create those directories if need be:
+ foreach ( $needed_dirs as $_dir ) {
+ if ( ! $wp_filesystem->mkdir($_dir, FS_CHMOD_DIR) && ! $wp_filesystem->is_dir($_dir) ) // Only check to see if the dir exists upon creation failure. Less I/O this way.
+ return new WP_Error('mkdir_failed', __('Could not create directory.'), $_dir);
+ }
+ unset($needed_dirs);
+
+ // Extract the files from the zip
+ foreach ( $archive_files as $file ) {
+ if ( $file['folder'] )
+ continue;
+
+ if ( '__MACOSX/' === substr($file['filename'], 0, 9) ) // Don't extract the OS X-created __MACOSX directory files
+ continue;
+
+ if ( ! $wp_filesystem->put_contents( $to . $file['filename'], $file['content'], FS_CHMOD_FILE) )
+ return new WP_Error('copy_failed', __('Could not copy file.'), $to . $file['filename']);
+ }
+ return true;
+}
+
+/**
+ * Copies a directory from one location to another via the WordPress Filesystem Abstraction.
+ * Assumes that WP_Filesystem() has already been called and setup.
+ *
+ * @since 2.5.0
+ *
+ * @param string $from source directory
+ * @param string $to destination directory
+ * @param array $skip_list a list of files/folders to skip copying
+ * @return mixed WP_Error on failure, True on success.
+ */
+function copy_dir($from, $to, $skip_list = array() ) {
+ global $wp_filesystem;
+
+ $dirlist = $wp_filesystem->dirlist($from);
+
+ $from = trailingslashit($from);
+ $to = trailingslashit($to);
+
+ $skip_regex = '';
+ foreach ( (array)$skip_list as $key => $skip_file )
+ $skip_regex .= preg_quote($skip_file, '!') . '|';
+
+ if ( !empty($skip_regex) )
+ $skip_regex = '!(' . rtrim($skip_regex, '|') . ')$!i';
+
+ foreach ( (array) $dirlist as $filename => $fileinfo ) {
+ if ( !empty($skip_regex) )
+ if ( preg_match($skip_regex, $from . $filename) )
+ continue;
+
+ if ( 'f' == $fileinfo['type'] ) {
+ if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE) ) {
+ // If copy failed, chmod file to 0644 and try again.
+ $wp_filesystem->chmod($to . $filename, 0644);
+ if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE) )
+ return new WP_Error('copy_failed', __('Could not copy file.'), $to . $filename);
+ }
+ } elseif ( 'd' == $fileinfo['type'] ) {
+ if ( !$wp_filesystem->is_dir($to . $filename) ) {
+ if ( !$wp_filesystem->mkdir($to . $filename, FS_CHMOD_DIR) )
+ return new WP_Error('mkdir_failed', __('Could not create directory.'), $to . $filename);
+ }
+ $result = copy_dir($from . $filename, $to . $filename, $skip_list);
+ if ( is_wp_error($result) )
+ return $result;
+ }
+ }
+ return true;
+}
+
+/**
+ * Initialises and connects the WordPress Filesystem Abstraction classes.
+ * This function will include the chosen transport and attempt connecting.
+ *
+ * Plugins may add extra transports, And force WordPress to use them by returning the filename via the 'filesystem_method_file' filter.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args (optional) Connection args, These are passed directly to the WP_Filesystem_*() classes.
+ * @param string $context (optional) Context for get_filesystem_method(), See function declaration for more information.
+ * @return boolean false on failure, true on success
+ */
+function WP_Filesystem( $args = false, $context = false ) {
+ global $wp_filesystem;
+
+ require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
+
+ $method = get_filesystem_method($args, $context);
+
+ if ( ! $method )
+ return false;
+
+ if ( ! class_exists("WP_Filesystem_$method") ) {
+ $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method);
+ if ( ! file_exists($abstraction_file) )
+ return;
+
+ require_once($abstraction_file);
+ }
+ $method = "WP_Filesystem_$method";
+
+ $wp_filesystem = new $method($args);
+
+ //Define the timeouts for the connections. Only available after the construct is called to allow for per-transport overriding of the default.
+ if ( ! defined('FS_CONNECT_TIMEOUT') )
+ define('FS_CONNECT_TIMEOUT', 30);
+ if ( ! defined('FS_TIMEOUT') )
+ define('FS_TIMEOUT', 30);
+
+ if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
+ return false;
+
+ if ( !$wp_filesystem->connect() )
+ return false; //There was an error connecting to the server.
+
+ // Set the permission constants if not already set.
+ if ( ! defined('FS_CHMOD_DIR') )
+ define('FS_CHMOD_DIR', 0755 );
+ if ( ! defined('FS_CHMOD_FILE') )
+ define('FS_CHMOD_FILE', 0644 );
+
+ return true;
+}
+
+/**
+ * Determines which Filesystem Method to use.
+ * The priority of the Transports are: Direct, SSH2, FTP PHP Extension, FTP Sockets (Via Sockets class, or fsockopen())
+ *
+ * Note that the return value of this function can be overridden in 2 ways
+ * - By defining FS_METHOD in your <code>wp-config.php</code> file
+ * - By using the filesystem_method filter
+ * Valid values for these are: 'direct', 'ssh', 'ftpext' or 'ftpsockets'
+ * Plugins may also define a custom transport handler, See the WP_Filesystem function for more information.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Connection details.
+ * @param string $context Full path to the directory that is tested for being writable.
+ * @return string The transport to use, see description for valid return values.
+ */
+function get_filesystem_method($args = array(), $context = false) {
+ $method = defined('FS_METHOD') ? FS_METHOD : false; //Please ensure that this is either 'direct', 'ssh', 'ftpext' or 'ftpsockets'
+
+ if ( ! $method && function_exists('getmyuid') && function_exists('fileowner') ){
+ if ( !$context )
+ $context = WP_CONTENT_DIR;
+ $context = trailingslashit($context);
+ $temp_file_name = $context . 'temp-write-test-' . time();
+ $temp_handle = @fopen($temp_file_name, 'w');
+ if ( $temp_handle ) {
+ if ( getmyuid() == @fileowner($temp_file_name) )
+ $method = 'direct';
+ @fclose($temp_handle);
+ @unlink($temp_file_name);
+ }
+ }
+
+ if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents') ) $method = 'ssh2';
+ if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
+ if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
+ return apply_filters('filesystem_method', $method, $args);
+}
+
+/**
+ * Displays a form to the user to request for their FTP/SSH details in order to connect to the filesystem.
+ * All chosen/entered details are saved, Excluding the Password.
+ *
+ * Hostnames may be in the form of hostname:portnumber (eg: wordpress.org:2467) to specify an alternate FTP/SSH port.
+ *
+ * Plugins may override this form by returning true|false via the <code>request_filesystem_credentials</code> filter.
+ *
+ * @since 2.5.0
+ *
+ * @param string $form_post the URL to post the form to
+ * @param string $type the chosen Filesystem method in use
+ * @param boolean $error if the current request has failed to connect
+ * @param string $context The directory which is needed access to, The write-test will be performed on this directory by get_filesystem_method()
+ * @param string $extra_fields Extra POST fields which should be checked for to be included in the post.
+ * @return boolean False on failure. True on success.
+ */
+function request_filesystem_credentials($form_post, $type = '', $error = false, $context = false, $extra_fields = null) {
+ $req_cred = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields );
+ if ( '' !== $req_cred )
+ return $req_cred;
+
+ if ( empty($type) )
+ $type = get_filesystem_method(array(), $context);
+
+ if ( 'direct' == $type )
+ return true;
+
+ if ( is_null( $extra_fields ) )
+ $extra_fields = array( 'version', 'locale' );
+
+ $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
+
+ // If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
+ $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? wp_unslash( $_POST['hostname'] ) : $credentials['hostname']);
+ $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? wp_unslash( $_POST['username'] ) : $credentials['username']);
+ $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? wp_unslash( $_POST['password'] ) : '');
+
+ // Check to see if we are setting the public/private keys for ssh
+ $credentials['public_key'] = defined('FTP_PUBKEY') ? FTP_PUBKEY : (!empty($_POST['public_key']) ? wp_unslash( $_POST['public_key'] ) : '');
+ $credentials['private_key'] = defined('FTP_PRIKEY') ? FTP_PRIKEY : (!empty($_POST['private_key']) ? wp_unslash( $_POST['private_key'] ) : '');
+
+ //sanitize the hostname, Some people might pass in odd-data:
+ $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
+
+ if ( strpos($credentials['hostname'], ':') ) {
+ list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
+ if ( ! is_numeric($credentials['port']) )
+ unset($credentials['port']);
+ } else {
+ unset($credentials['port']);
+ }
+
+ if ( (defined('FTP_SSH') && FTP_SSH) || (defined('FS_METHOD') && 'ssh' == FS_METHOD) )
+ $credentials['connection_type'] = 'ssh';
+ else if ( (defined('FTP_SSL') && FTP_SSL) && 'ftpext' == $type ) //Only the FTP Extension understands SSL
+ $credentials['connection_type'] = 'ftps';
+ else if ( !empty($_POST['connection_type']) )
+ $credentials['connection_type'] = wp_unslash( $_POST['connection_type'] );
+ else if ( !isset($credentials['connection_type']) ) //All else fails (And it's not defaulted to something else saved), Default to FTP
+ $credentials['connection_type'] = 'ftp';
+
+ if ( ! $error &&
+ (
+ ( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
+ ( 'ssh' == $credentials['connection_type'] && !empty($credentials['public_key']) && !empty($credentials['private_key']) )
+ ) ) {
+ $stored_credentials = $credentials;
+ if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
+ $stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
+
+ unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
+ update_option('ftp_credentials', $stored_credentials);
+ return $credentials;
+ }
+ $hostname = '';
+ $username = '';
+ $password = '';
+ $connection_type = '';
+ if ( !empty($credentials) )
+ extract($credentials, EXTR_OVERWRITE);
+ if ( $error ) {
+ $error_string = __('<strong>ERROR:</strong> There was an error connecting to the server, Please verify the settings are correct.');
+ if ( is_wp_error($error) )
+ $error_string = esc_html( $error->get_error_message() );
+ echo '<div id="message" class="error"><p>' . $error_string . '</p></div>';
+ }
+
+ $types = array();
+ if ( extension_loaded('ftp') || extension_loaded('sockets') || function_exists('fsockopen') )
+ $types[ 'ftp' ] = __('FTP');
+ if ( extension_loaded('ftp') ) //Only this supports FTPS
+ $types[ 'ftps' ] = __('FTPS (SSL)');
+ if ( extension_loaded('ssh2') && function_exists('stream_get_contents') )
+ $types[ 'ssh' ] = __('SSH2');
+
+ $types = apply_filters('fs_ftp_connection_types', $types, $credentials, $type, $error, $context);
+
+?>
+<script type="text/javascript">
+<!--
+jQuery(function($){
+ jQuery("#ssh").click(function () {
+ jQuery("#ssh_keys").show();
+ });
+ jQuery("#ftp, #ftps").click(function () {
+ jQuery("#ssh_keys").hide();
+ });
+ jQuery('form input[value=""]:first').focus();
+});
+-->
+</script>
+<form action="<?php echo esc_url( $form_post ) ?>" method="post">
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php _e('Connection Information') ?></h2>
+<p><?php
+ $label_user = __('Username');
+ $label_pass = __('Password');
+ _e('To perform the requested action, WordPress needs to access your web server.');
+ echo ' ';
+ if ( ( isset( $types['ftp'] ) || isset( $types['ftps'] ) ) ) {
+ if ( isset( $types['ssh'] ) ) {
+ _e('Please enter your FTP or SSH credentials to proceed.');
+ $label_user = __('FTP/SSH Username');
+ $label_pass = __('FTP/SSH Password');
+ } else {
+ _e('Please enter your FTP credentials to proceed.');
+ $label_user = __('FTP Username');
+ $label_pass = __('FTP Password');
+ }
+ echo ' ';
+ }
+ _e('If you do not remember your credentials, you should contact your web host.');
+?></p>
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><label for="hostname"><?php _e('Hostname') ?></label></th>
+<td><input name="hostname" type="text" id="hostname" value="<?php echo esc_attr($hostname); if ( !empty($port) ) echo ":$port"; ?>"<?php disabled( defined('FTP_HOST') ); ?> size="40" /></td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><label for="username"><?php echo $label_user; ?></label></th>
+<td><input name="username" type="text" id="username" value="<?php echo esc_attr($username) ?>"<?php disabled( defined('FTP_USER') ); ?> size="40" /></td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><label for="password"><?php echo $label_pass; ?></label></th>
+<td><input name="password" type="password" id="password" value="<?php if ( defined('FTP_PASS') ) echo '*****'; ?>"<?php disabled( defined('FTP_PASS') ); ?> size="40" /></td>
+</tr>
+
+<?php if ( isset($types['ssh']) ) : ?>
+<tr id="ssh_keys" valign="top" style="<?php if ( 'ssh' != $connection_type ) echo 'display:none' ?>">
+<th scope="row"><?php _e('Authentication Keys') ?>
+<div class="key-labels textright">
+<label for="public_key"><?php _e('Public Key:') ?></label ><br />
+<label for="private_key"><?php _e('Private Key:') ?></label>
+</div></th>
+<td><br /><input name="public_key" type="text" id="public_key" value="<?php echo esc_attr($public_key) ?>"<?php disabled( defined('FTP_PUBKEY') ); ?> size="40" /><br /><input name="private_key" type="text" id="private_key" value="<?php echo esc_attr($private_key) ?>"<?php disabled( defined('FTP_PRIKEY') ); ?> size="40" />
+<div><?php _e('Enter the location on the server where the keys are located. If a passphrase is needed, enter that in the password field above.') ?></div></td>
+</tr>
+<?php endif; ?>
+
+<tr valign="top">
+<th scope="row"><?php _e('Connection Type') ?></th>
+<td>
+<fieldset><legend class="screen-reader-text"><span><?php _e('Connection Type') ?></span></legend>
+<?php
+ $disabled = disabled( (defined('FTP_SSL') && FTP_SSL) || (defined('FTP_SSH') && FTP_SSH), true, false );
+ foreach ( $types as $name => $text ) : ?>
+ <label for="<?php echo esc_attr($name) ?>">
+ <input type="radio" name="connection_type" id="<?php echo esc_attr($name) ?>" value="<?php echo esc_attr($name) ?>"<?php checked($name, $connection_type); echo $disabled; ?> />
+ <?php echo $text ?>
+ </label>
+ <?php endforeach; ?>
+</fieldset>
+</td>
+</tr>
+</table>
+
+<?php
+foreach ( (array) $extra_fields as $field ) {
+ if ( isset( $_POST[ $field ] ) )
+ echo '<input type="hidden" name="' . esc_attr( $field ) . '" value="' . esc_attr( wp_unslash( $_POST[ $field ] ) ) . '" />';
+}
+submit_button( __( 'Proceed' ), 'button', 'upgrade' );
+?>
+</div>
+</form>
+<?php
+ return false;
+}
diff --git a/src/wp-admin/includes/image-edit.php b/src/wp-admin/includes/image-edit.php
new file mode 100644
index 0000000000..9d717d7ea4
--- /dev/null
+++ b/src/wp-admin/includes/image-edit.php
@@ -0,0 +1,731 @@
+<?php
+/**
+ * WordPress Image Editor
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+function wp_image_editor($post_id, $msg = false) {
+ $nonce = wp_create_nonce("image_editor-$post_id");
+ $meta = wp_get_attachment_metadata($post_id);
+ $thumb = image_get_intermediate_size($post_id, 'thumbnail');
+ $sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
+ $note = '';
+
+ if ( isset( $meta['width'], $meta['height'] ) )
+ $big = max( $meta['width'], $meta['height'] );
+ else
+ die( __('Image data does not exist. Please re-upload the image.') );
+
+ $sizer = $big > 400 ? 400 / $big : 1;
+
+ $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
+ $can_restore = false;
+ if ( ! empty( $backup_sizes ) && isset( $backup_sizes['full-orig'], $meta['file'] ) )
+ $can_restore = $backup_sizes['full-orig']['file'] != basename( $meta['file'] );
+
+ if ( $msg ) {
+ if ( isset($msg->error) )
+ $note = "<div class='error'><p>$msg->error</p></div>";
+ elseif ( isset($msg->msg) )
+ $note = "<div class='updated'><p>$msg->msg</p></div>";
+ }
+
+ ?>
+ <div class="imgedit-wrap">
+ <?php echo $note; ?>
+ <table id="imgedit-panel-<?php echo $post_id; ?>"><tbody>
+ <tr><td>
+ <div class="imgedit-menu">
+ <div onclick="imageEdit.crop(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-crop disabled" title="<?php esc_attr_e( 'Crop' ); ?>"></div><?php
+
+ // On some setups GD library does not provide imagerotate() - Ticket #11536
+ if ( wp_image_editor_supports( array( 'mime_type' => get_post_mime_type( $post_id ), 'methods' => array( 'rotate' ) ) ) ) { ?>
+ <div class="imgedit-rleft" onclick="imageEdit.rotate( 90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate counter-clockwise' ); ?>"></div>
+ <div class="imgedit-rright" onclick="imageEdit.rotate(-90, <?php echo "$post_id, '$nonce'"; ?>, this)" title="<?php esc_attr_e( 'Rotate clockwise' ); ?>"></div>
+<?php } else {
+ $note_no_rotate = esc_attr__('Image rotation is not supported by your web host.');
+?>
+ <div class="imgedit-rleft disabled" title="<?php echo $note_no_rotate; ?>"></div>
+ <div class="imgedit-rright disabled" title="<?php echo $note_no_rotate; ?>"></div>
+<?php } ?>
+
+ <div onclick="imageEdit.flip(1, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-flipv" title="<?php esc_attr_e( 'Flip vertically' ); ?>"></div>
+ <div onclick="imageEdit.flip(2, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-fliph" title="<?php esc_attr_e( 'Flip horizontally' ); ?>"></div>
+
+ <div id="image-undo-<?php echo $post_id; ?>" onclick="imageEdit.undo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-undo disabled" title="<?php esc_attr_e( 'Undo' ); ?>"></div>
+ <div id="image-redo-<?php echo $post_id; ?>" onclick="imageEdit.redo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-redo disabled" title="<?php esc_attr_e( 'Redo' ); ?>"></div>
+ <br class="clear" />
+ </div>
+
+ <input type="hidden" id="imgedit-sizer-<?php echo $post_id; ?>" value="<?php echo $sizer; ?>" />
+ <input type="hidden" id="imgedit-minthumb-<?php echo $post_id; ?>" value="<?php echo ( get_option('thumbnail_size_w') . ':' . get_option('thumbnail_size_h') ); ?>" />
+ <input type="hidden" id="imgedit-history-<?php echo $post_id; ?>" value="" />
+ <input type="hidden" id="imgedit-undone-<?php echo $post_id; ?>" value="0" />
+ <input type="hidden" id="imgedit-selection-<?php echo $post_id; ?>" value="" />
+ <input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
+ <input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
+
+ <div id="imgedit-crop-<?php echo $post_id; ?>" class="imgedit-crop-wrap">
+ <img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand(1, 99999); ?>" />
+ </div>
+
+ <div class="imgedit-submit">
+ <input type="button" onclick="imageEdit.close(<?php echo $post_id; ?>, 1)" class="button" value="<?php esc_attr_e( 'Cancel' ); ?>" />
+ <input type="button" onclick="imageEdit.save(<?php echo "$post_id, '$nonce'"; ?>)" disabled="disabled" class="button-primary imgedit-submit-btn" value="<?php esc_attr_e( 'Save' ); ?>" />
+ </div>
+ </td>
+
+ <td class="imgedit-settings">
+ <div class="imgedit-group">
+ <div class="imgedit-group-top">
+ <a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><strong><?php _e('Scale Image'); ?></strong></a>
+ <div class="imgedit-help">
+ <p><?php _e('You can proportionally scale the original image. For best results the scaling should be done before performing any other operations on it like crop, rotate, etc. Note that images can only be scaled down, not up.'); ?></p>
+ <?php if ( isset( $meta['width'], $meta['height'] ) ): ?>
+ <p><?php printf( __('Original dimensions %s'), $meta['width'] . '&times;' . $meta['height'] ); ?></p>
+ <?php endif ?>
+ <div class="imgedit-submit">
+ <span class="nowrap"><input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" style="width:4em;" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />&times;<input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" style="width:4em;" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
+ <span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span></span>
+ <input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
+ </div>
+ </div>
+ </div>
+
+<?php if ( $can_restore ) { ?>
+
+ <div class="imgedit-group-top">
+ <a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><strong><?php _e('Restore Original Image'); ?></strong></a>
+ <div class="imgedit-help">
+ <p><?php _e('Discard any changes and restore the original image.');
+
+ if ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE )
+ echo ' '.__('Previously edited copies of the image will not be deleted.');
+
+ ?></p>
+ <div class="imgedit-submit">
+ <input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'restore')" class="button-primary" value="<?php esc_attr_e( 'Restore image' ); ?>" <?php echo $can_restore; ?> />
+ </div>
+ </div>
+ </div>
+
+<?php } ?>
+
+ </div>
+
+ <div class="imgedit-group">
+ <div class="imgedit-group-top">
+ <strong><?php _e('Image Crop'); ?></strong>
+ <a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><?php _e('(help)'); ?></a>
+ <div class="imgedit-help">
+ <p><?php _e('The image can be cropped by clicking on it and dragging to select the desired part. While dragging the dimensions of the selection are displayed below.'); ?></p>
+
+ <p><strong><?php _e('Crop Aspect Ratio'); ?></strong><br />
+ <?php _e('You can specify the crop selection aspect ratio then hold down the Shift key while dragging to lock it. The values can be 1:1 (square), 4:3, 16:9, etc. If there is a selection, specifying aspect ratio will set it immediately.'); ?></p>
+
+ <p><strong><?php _e('Crop Selection'); ?></strong><br />
+ <?php _e('Once started, the selection can be adjusted by entering new values (in pixels). Note that these values are scaled to approximately match the original image dimensions. The minimum selection size equals the thumbnail size as set in the Media settings.'); ?></p>
+ </div>
+ </div>
+
+ <p>
+ <?php _e('Aspect ratio:'); ?>
+ <span class="nowrap">
+ <input type="text" id="imgedit-crop-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 0, this)" style="width:3em;" />
+ :
+ <input type="text" id="imgedit-crop-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 1, this)" style="width:3em;" />
+ </span>
+ </p>
+
+ <p id="imgedit-crop-sel-<?php echo $post_id; ?>">
+ <?php _e('Selection:'); ?>
+ <span class="nowrap">
+ <input type="text" id="imgedit-sel-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" style="width:4em;" />
+ :
+ <input type="text" id="imgedit-sel-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" style="width:4em;" />
+ </span>
+ </p>
+ </div>
+
+ <?php if ( $thumb && $sub_sizes ) {
+ $thumb_img = wp_constrain_dimensions( $thumb['width'], $thumb['height'], 160, 120 );
+ ?>
+
+ <div class="imgedit-group imgedit-applyto">
+ <div class="imgedit-group-top">
+ <strong><?php _e('Thumbnail Settings'); ?></strong>
+ <a class="imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" href="#"><?php _e('(help)'); ?></a>
+ <p class="imgedit-help"><?php _e('The thumbnail image can be cropped differently. For example it can be square or contain only a portion of the original image to showcase it better. Here you can select whether to apply changes to all image sizes or make the thumbnail different.'); ?></p>
+ </div>
+
+ <p>
+ <img src="<?php echo $thumb['url']; ?>" width="<?php echo $thumb_img[0]; ?>" height="<?php echo $thumb_img[1]; ?>" class="imgedit-size-preview" alt="" /><br /><?php _e('Current thumbnail'); ?>
+ </p>
+
+ <p id="imgedit-save-target-<?php echo $post_id; ?>">
+ <strong><?php _e('Apply changes to:'); ?></strong><br />
+
+ <label class="imgedit-label">
+ <input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="all" checked="checked" />
+ <?php _e('All image sizes'); ?></label>
+
+ <label class="imgedit-label">
+ <input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="thumbnail" />
+ <?php _e('Thumbnail'); ?></label>
+
+ <label class="imgedit-label">
+ <input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="nothumb" />
+ <?php _e('All sizes except thumbnail'); ?></label>
+ </p>
+ </div>
+
+ <?php } ?>
+
+ </td></tr>
+ </tbody></table>
+ <div class="imgedit-wait" id="imgedit-wait-<?php echo $post_id; ?>"></div>
+ <script type="text/javascript">jQuery( function() { imageEdit.init(<?php echo $post_id; ?>); });</script>
+ <div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e("There are unsaved changes that will be lost. 'OK' to continue, 'Cancel' to return to the Image Editor."); ?></div>
+ </div>
+<?php
+}
+
+/**
+ * Streams image in WP_Image_Editor to browser.
+ * Provided for backcompat reasons
+ *
+ * @param WP_Image_Editor $image
+ * @param string $mime_type
+ * @param int $post_id
+ * @return boolean
+ */
+function wp_stream_image( $image, $mime_type, $post_id ) {
+ if ( $image instanceof WP_Image_Editor ) {
+ $image = apply_filters('image_editor_save_pre', $image, $post_id);
+
+ if ( is_wp_error( $image->stream( $mime_type ) ) )
+ return false;
+
+ return true;
+ } else {
+ _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
+
+ $image = apply_filters('image_save_pre', $image, $post_id);
+
+ switch ( $mime_type ) {
+ case 'image/jpeg':
+ header( 'Content-Type: image/jpeg' );
+ return imagejpeg( $image, null, 90 );
+ case 'image/png':
+ header( 'Content-Type: image/png' );
+ return imagepng( $image );
+ case 'image/gif':
+ header( 'Content-Type: image/gif' );
+ return imagegif( $image );
+ default:
+ return false;
+ }
+ }
+}
+
+/**
+ * Saves Image to File
+ *
+ * @param string $filename
+ * @param WP_Image_Editor $image
+ * @param string $mime_type
+ * @param int $post_id
+ * @return boolean
+ */
+function wp_save_image_file( $filename, $image, $mime_type, $post_id ) {
+ if ( $image instanceof WP_Image_Editor ) {
+ $image = apply_filters('image_editor_save_pre', $image, $post_id);
+ $saved = apply_filters('wp_save_image_editor_file', null, $filename, $image, $mime_type, $post_id);
+
+ if ( null !== $saved )
+ return $saved;
+
+ return $image->save( $filename, $mime_type );
+ } else {
+ _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
+
+ $image = apply_filters('image_save_pre', $image, $post_id);
+ $saved = apply_filters('wp_save_image_file', null, $filename, $image, $mime_type, $post_id);
+
+ if ( null !== $saved )
+ return $saved;
+
+ switch ( $mime_type ) {
+ case 'image/jpeg':
+ return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
+ case 'image/png':
+ return imagepng( $image, $filename );
+ case 'image/gif':
+ return imagegif( $image, $filename );
+ default:
+ return false;
+ }
+ }
+}
+
+function _image_get_preview_ratio($w, $h) {
+ $max = max($w, $h);
+ return $max > 400 ? (400 / $max) : 1;
+}
+
+// @TODO: Returns GD resource, but is NOT public
+function _rotate_image_resource($img, $angle) {
+ _deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::rotate' ) );
+ if ( function_exists('imagerotate') ) {
+ $rotated = imagerotate($img, $angle, 0);
+ if ( is_resource($rotated) ) {
+ imagedestroy($img);
+ $img = $rotated;
+ }
+ }
+ return $img;
+}
+
+/**
+ * @TODO: Only used within image_edit_apply_changes
+ * and receives/returns GD Resource.
+ * Consider removal.
+ *
+ * @param GD_Resource $img
+ * @param boolean $horz
+ * @param boolean $vert
+ * @return GD_Resource
+ */
+function _flip_image_resource($img, $horz, $vert) {
+ _deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::flip' ) );
+ $w = imagesx($img);
+ $h = imagesy($img);
+ $dst = wp_imagecreatetruecolor($w, $h);
+ if ( is_resource($dst) ) {
+ $sx = $vert ? ($w - 1) : 0;
+ $sy = $horz ? ($h - 1) : 0;
+ $sw = $vert ? -$w : $w;
+ $sh = $horz ? -$h : $h;
+
+ if ( imagecopyresampled($dst, $img, 0, 0, $sx, $sy, $w, $h, $sw, $sh) ) {
+ imagedestroy($img);
+ $img = $dst;
+ }
+ }
+ return $img;
+}
+
+/**
+ * @TODO: Only used within image_edit_apply_changes
+ * and receives/returns GD Resource.
+ * Consider removal.
+ *
+ * @param GD_Resource $img
+ * @param float $x
+ * @param float $y
+ * @param float $w
+ * @param float $h
+ * @return GD_Resource
+ */
+function _crop_image_resource($img, $x, $y, $w, $h) {
+ $dst = wp_imagecreatetruecolor($w, $h);
+ if ( is_resource($dst) ) {
+ if ( imagecopy($dst, $img, 0, 0, $x, $y, $w, $h) ) {
+ imagedestroy($img);
+ $img = $dst;
+ }
+ }
+ return $img;
+}
+
+/**
+ * Performs group of changes on Editor specified.
+ *
+ * @param WP_Image_Editor $image
+ * @param type $changes
+ * @return WP_Image_Editor
+ */
+function image_edit_apply_changes( $image, $changes ) {
+ if ( is_resource( $image ) )
+ _deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
+
+ if ( !is_array($changes) )
+ return $image;
+
+ // expand change operations
+ foreach ( $changes as $key => $obj ) {
+ if ( isset($obj->r) ) {
+ $obj->type = 'rotate';
+ $obj->angle = $obj->r;
+ unset($obj->r);
+ } elseif ( isset($obj->f) ) {
+ $obj->type = 'flip';
+ $obj->axis = $obj->f;
+ unset($obj->f);
+ } elseif ( isset($obj->c) ) {
+ $obj->type = 'crop';
+ $obj->sel = $obj->c;
+ unset($obj->c);
+ }
+ $changes[$key] = $obj;
+ }
+
+ // combine operations
+ if ( count($changes) > 1 ) {
+ $filtered = array($changes[0]);
+ for ( $i = 0, $j = 1; $j < count($changes); $j++ ) {
+ $combined = false;
+ if ( $filtered[$i]->type == $changes[$j]->type ) {
+ switch ( $filtered[$i]->type ) {
+ case 'rotate':
+ $filtered[$i]->angle += $changes[$j]->angle;
+ $combined = true;
+ break;
+ case 'flip':
+ $filtered[$i]->axis ^= $changes[$j]->axis;
+ $combined = true;
+ break;
+ }
+ }
+ if ( !$combined )
+ $filtered[++$i] = $changes[$j];
+ }
+ $changes = $filtered;
+ unset($filtered);
+ }
+
+ // image resource before applying the changes
+ if ( $image instanceof WP_Image_Editor )
+ $image = apply_filters('wp_image_editor_before_change', $image, $changes);
+ elseif ( is_resource( $image ) )
+ $image = apply_filters('image_edit_before_change', $image, $changes);
+
+ foreach ( $changes as $operation ) {
+ switch ( $operation->type ) {
+ case 'rotate':
+ if ( $operation->angle != 0 ) {
+ if ( $image instanceof WP_Image_Editor )
+ $image->rotate( $operation->angle );
+ else
+ $image = _rotate_image_resource( $image, $operation->angle );
+ }
+ break;
+ case 'flip':
+ if ( $operation->axis != 0 )
+ if ( $image instanceof WP_Image_Editor )
+ $image->flip( ($operation->axis & 1) != 0, ($operation->axis & 2) != 0 );
+ else
+ $image = _flip_image_resource( $image, ( $operation->axis & 1 ) != 0, ( $operation->axis & 2 ) != 0 );
+ break;
+ case 'crop':
+ $sel = $operation->sel;
+
+ if ( $image instanceof WP_Image_Editor ) {
+ $size = $image->get_size();
+ $w = $size['width'];
+ $h = $size['height'];
+
+ $scale = 1 / _image_get_preview_ratio( $w, $h ); // discard preview scaling
+ $image->crop( $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
+ } else {
+ $scale = 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // discard preview scaling
+ $image = _crop_image_resource( $image, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
+ }
+ break;
+ }
+ }
+
+ return $image;
+}
+
+
+/**
+ * Streams image in post to browser, along with enqueued changes
+ * in $_REQUEST['history']
+ *
+ * @param int $post_id
+ * @return boolean
+ */
+function stream_preview_image( $post_id ) {
+ $post = get_post( $post_id );
+ @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+
+ $img = wp_get_image_editor( _load_image_to_edit_path( $post_id ) );
+
+ if ( is_wp_error( $img ) )
+ return false;
+
+ $changes = !empty($_REQUEST['history']) ? json_decode( wp_unslash($_REQUEST['history']) ) : null;
+ if ( $changes )
+ $img = image_edit_apply_changes( $img, $changes );
+
+ // scale the image
+ $size = $img->get_size();
+ $w = $size['width'];
+ $h = $size['height'];
+
+ $ratio = _image_get_preview_ratio( $w, $h );
+ $w2 = $w * $ratio;
+ $h2 = $h * $ratio;
+
+ if ( is_wp_error( $img->resize( $w2, $h2 ) ) )
+ return false;
+
+ return wp_stream_image( $img, $post->post_mime_type, $post_id );
+}
+
+function wp_restore_image($post_id) {
+ $meta = wp_get_attachment_metadata($post_id);
+ $file = get_attached_file($post_id);
+ $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
+ $restored = false;
+ $msg = new stdClass;
+
+ if ( !is_array($backup_sizes) ) {
+ $msg->error = __('Cannot load image metadata.');
+ return $msg;
+ }
+
+ $parts = pathinfo($file);
+ $suffix = time() . rand(100, 999);
+ $default_sizes = get_intermediate_image_sizes();
+
+ if ( isset($backup_sizes['full-orig']) && is_array($backup_sizes['full-orig']) ) {
+ $data = $backup_sizes['full-orig'];
+
+ if ( $parts['basename'] != $data['file'] ) {
+ if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ) {
+ // delete only if it's edited image
+ if ( preg_match('/-e[0-9]{13}\./', $parts['basename']) ) {
+ $delpath = apply_filters('wp_delete_file', $file);
+ @unlink($delpath);
+ }
+ } elseif ( isset( $meta['width'], $meta['height'] ) ) {
+ $backup_sizes["full-$suffix"] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $parts['basename']);
+ }
+ }
+
+ $restored_file = path_join($parts['dirname'], $data['file']);
+ $restored = update_attached_file($post_id, $restored_file);
+
+ $meta['file'] = _wp_relative_upload_path( $restored_file );
+ $meta['width'] = $data['width'];
+ $meta['height'] = $data['height'];
+ }
+
+ foreach ( $default_sizes as $default_size ) {
+ if ( isset($backup_sizes["$default_size-orig"]) ) {
+ $data = $backup_sizes["$default_size-orig"];
+ if ( isset($meta['sizes'][$default_size]) && $meta['sizes'][$default_size]['file'] != $data['file'] ) {
+ if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ) {
+ // delete only if it's edited image
+ if ( preg_match('/-e[0-9]{13}-/', $meta['sizes'][$default_size]['file']) ) {
+ $delpath = apply_filters( 'wp_delete_file', path_join($parts['dirname'], $meta['sizes'][$default_size]['file']) );
+ @unlink($delpath);
+ }
+ } else {
+ $backup_sizes["$default_size-{$suffix}"] = $meta['sizes'][$default_size];
+ }
+ }
+
+ $meta['sizes'][$default_size] = $data;
+ } else {
+ unset($meta['sizes'][$default_size]);
+ }
+ }
+
+ if ( !wp_update_attachment_metadata($post_id, $meta) || !update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes) ) {
+ $msg->error = __('Cannot save image metadata.');
+ return $msg;
+ }
+
+ if ( !$restored )
+ $msg->error = __('Image metadata is inconsistent.');
+ else
+ $msg->msg = __('Image restored successfully.');
+
+ return $msg;
+}
+
+/**
+ * Saves image to post along with enqueued changes
+ * in $_REQUEST['history']
+ *
+ * @param int $post_id
+ * @return \stdClass
+ */
+function wp_save_image( $post_id ) {
+ $return = new stdClass;
+ $success = $delete = $scaled = $nocrop = false;
+ $post = get_post( $post_id );
+
+ $img = wp_get_image_editor( _load_image_to_edit_path( $post_id, 'full' ) );
+ if ( is_wp_error( $img ) ) {
+ $return->error = esc_js( __('Unable to create new image.') );
+ return $return;
+ }
+
+ $fwidth = !empty($_REQUEST['fwidth']) ? intval($_REQUEST['fwidth']) : 0;
+ $fheight = !empty($_REQUEST['fheight']) ? intval($_REQUEST['fheight']) : 0;
+ $target = !empty($_REQUEST['target']) ? preg_replace('/[^a-z0-9_-]+/i', '', $_REQUEST['target']) : '';
+ $scale = !empty($_REQUEST['do']) && 'scale' == $_REQUEST['do'];
+
+ if ( $scale && $fwidth > 0 && $fheight > 0 ) {
+ $size = $img->get_size();
+ $sX = $size['width'];
+ $sY = $size['height'];
+
+ // check if it has roughly the same w / h ratio
+ $diff = round($sX / $sY, 2) - round($fwidth / $fheight, 2);
+ if ( -0.1 < $diff && $diff < 0.1 ) {
+ // scale the full size image
+ if ( $img->resize( $fwidth, $fheight ) )
+ $scaled = true;
+ }
+
+ if ( !$scaled ) {
+ $return->error = esc_js( __('Error while saving the scaled image. Please reload the page and try again.') );
+ return $return;
+ }
+ } elseif ( !empty($_REQUEST['history']) ) {
+ $changes = json_decode( wp_unslash($_REQUEST['history']) );
+ if ( $changes )
+ $img = image_edit_apply_changes($img, $changes);
+ } else {
+ $return->error = esc_js( __('Nothing to save, the image has not changed.') );
+ return $return;
+ }
+
+ $meta = wp_get_attachment_metadata($post_id);
+ $backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
+
+ if ( !is_array($meta) ) {
+ $return->error = esc_js( __('Image data does not exist. Please re-upload the image.') );
+ return $return;
+ }
+
+ if ( !is_array($backup_sizes) )
+ $backup_sizes = array();
+
+ // generate new filename
+ $path = get_attached_file($post_id);
+ $path_parts = pathinfo( $path );
+ $filename = $path_parts['filename'];
+ $suffix = time() . rand(100, 999);
+
+ if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE &&
+ isset($backup_sizes['full-orig']) && $backup_sizes['full-orig']['file'] != $path_parts['basename'] ) {
+
+ if ( 'thumbnail' == $target )
+ $new_path = "{$path_parts['dirname']}/{$filename}-temp.{$path_parts['extension']}";
+ else
+ $new_path = $path;
+ } else {
+ while( true ) {
+ $filename = preg_replace( '/-e([0-9]+)$/', '', $filename );
+ $filename .= "-e{$suffix}";
+ $new_filename = "{$filename}.{$path_parts['extension']}";
+ $new_path = "{$path_parts['dirname']}/$new_filename";
+ if ( file_exists($new_path) )
+ $suffix++;
+ else
+ break;
+ }
+ }
+
+ // save the full-size file, also needed to create sub-sizes
+ if ( !wp_save_image_file($new_path, $img, $post->post_mime_type, $post_id) ) {
+ $return->error = esc_js( __('Unable to save the image.') );
+ return $return;
+ }
+
+ if ( 'nothumb' == $target || 'all' == $target || 'full' == $target || $scaled ) {
+ $tag = false;
+ if ( isset($backup_sizes['full-orig']) ) {
+ if ( ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE ) && $backup_sizes['full-orig']['file'] != $path_parts['basename'] )
+ $tag = "full-$suffix";
+ } else {
+ $tag = 'full-orig';
+ }
+
+ if ( $tag )
+ $backup_sizes[$tag] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $path_parts['basename']);
+
+ $success = update_attached_file( $post_id, $new_path );
+
+ $meta['file'] = _wp_relative_upload_path( $new_path );
+
+ $size = $img->get_size();
+ $meta['width'] = $size['width'];
+ $meta['height'] = $size['height'];
+
+ if ( $success && ('nothumb' == $target || 'all' == $target) ) {
+ $sizes = get_intermediate_image_sizes();
+ if ( 'nothumb' == $target )
+ $sizes = array_diff( $sizes, array('thumbnail') );
+ }
+
+ $return->fw = $meta['width'];
+ $return->fh = $meta['height'];
+ } elseif ( 'thumbnail' == $target ) {
+ $sizes = array( 'thumbnail' );
+ $success = $delete = $nocrop = true;
+ }
+
+ if ( isset( $sizes ) ) {
+ $_sizes = array();
+
+ foreach ( $sizes as $size ) {
+ $tag = false;
+ if ( isset( $meta['sizes'][$size] ) ) {
+ if ( isset($backup_sizes["$size-orig"]) ) {
+ if ( ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE ) && $backup_sizes["$size-orig"]['file'] != $meta['sizes'][$size]['file'] )
+ $tag = "$size-$suffix";
+ } else {
+ $tag = "$size-orig";
+ }
+
+ if ( $tag )
+ $backup_sizes[$tag] = $meta['sizes'][$size];
+ }
+
+ $crop = $nocrop ? false : get_option("{$size}_crop");
+ $_sizes[ $size ] = array( 'width' => get_option("{$size}_size_w"), 'height' => get_option("{$size}_size_h"), 'crop' => $crop );
+ }
+
+ $meta['sizes'] = array_merge( $meta['sizes'], $img->multi_resize( $_sizes ) );
+ }
+
+ unset( $img );
+
+ if ( $success ) {
+ wp_update_attachment_metadata( $post_id, $meta );
+ update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes);
+
+ if ( $target == 'thumbnail' || $target == 'all' || $target == 'full' ) {
+ // Check if it's an image edit from attachment edit screen
+ if ( ! empty( $_REQUEST['context'] ) && 'edit-attachment' == $_REQUEST['context'] ) {
+ $thumb_url = wp_get_attachment_image_src( $post_id, array( 900, 600 ), true );
+ $return->thumbnail = $thumb_url[0];
+ } else {
+ $file_url = wp_get_attachment_url($post_id);
+ if ( $thumb = $meta['sizes']['thumbnail'] )
+ $return->thumbnail = path_join( dirname($file_url), $thumb['file'] );
+ else
+ $return->thumbnail = "$file_url?w=128&h=128";
+ }
+ }
+ } else {
+ $delete = true;
+ }
+
+ if ( $delete ) {
+ $delpath = apply_filters('wp_delete_file', $new_path);
+ @unlink( $delpath );
+ }
+
+ $return->msg = esc_js( __('Image saved') );
+ return $return;
+}
diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php
new file mode 100644
index 0000000000..f2e636bbb8
--- /dev/null
+++ b/src/wp-admin/includes/image.php
@@ -0,0 +1,450 @@
+<?php
+/**
+ * File contains all the administration image manipulation functions.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Crop an Image to a given size.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $src The source file or Attachment ID.
+ * @param int $src_x The start x position to crop from.
+ * @param int $src_y The start y position to crop from.
+ * @param int $src_w The width to crop.
+ * @param int $src_h The height to crop.
+ * @param int $dst_w The destination width.
+ * @param int $dst_h The destination height.
+ * @param int $src_abs Optional. If the source crop points are absolute.
+ * @param string $dst_file Optional. The destination file to write to.
+ * @return string|WP_Error New filepath on success, WP_Error on failure.
+ */
+function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) {
+ $src_file = $src;
+ if ( is_numeric( $src ) ) { // Handle int as attachment ID
+ $src_file = get_attached_file( $src );
+
+ if ( ! file_exists( $src_file ) ) {
+ // If the file doesn't exist, attempt a url fopen on the src link.
+ // This can occur with certain file replication plugins.
+ $src = _load_image_to_edit_path( $src, 'full' );
+ } else {
+ $src = $src_file;
+ }
+ }
+
+ $editor = wp_get_image_editor( $src );
+ if ( is_wp_error( $editor ) )
+ return $editor;
+
+ $src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs );
+ if ( is_wp_error( $src ) )
+ return $src;
+
+ if ( ! $dst_file )
+ $dst_file = str_replace( basename( $src_file ), 'cropped-' . basename( $src_file ), $src_file );
+
+ // The directory containing the original file may no longer exist when
+ // using a replication plugin.
+ wp_mkdir_p( dirname( $dst_file ) );
+
+ $dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
+
+ $result = $editor->save( $dst_file );
+ if ( is_wp_error( $result ) )
+ return $result;
+
+ return $dst_file;
+}
+
+/**
+ * Generate post thumbnail attachment meta data.
+ *
+ * @since 2.1.0
+ *
+ * @param int $attachment_id Attachment Id to process.
+ * @param string $file Filepath of the Attached image.
+ * @return mixed Metadata for attachment.
+ */
+function wp_generate_attachment_metadata( $attachment_id, $file ) {
+ $attachment = get_post( $attachment_id );
+
+ $metadata = array();
+ $support = false;
+ if ( preg_match('!^image/!', get_post_mime_type( $attachment )) && file_is_displayable_image($file) ) {
+ $imagesize = getimagesize( $file );
+ $metadata['width'] = $imagesize[0];
+ $metadata['height'] = $imagesize[1];
+
+ // Make the file path relative to the upload dir
+ $metadata['file'] = _wp_relative_upload_path($file);
+
+ // make thumbnails and other intermediate sizes
+ global $_wp_additional_image_sizes;
+
+ $sizes = array();
+ foreach ( get_intermediate_image_sizes() as $s ) {
+ $sizes[$s] = array( 'width' => '', 'height' => '', 'crop' => false );
+ if ( isset( $_wp_additional_image_sizes[$s]['width'] ) )
+ $sizes[$s]['width'] = intval( $_wp_additional_image_sizes[$s]['width'] ); // For theme-added sizes
+ else
+ $sizes[$s]['width'] = get_option( "{$s}_size_w" ); // For default sizes set in options
+ if ( isset( $_wp_additional_image_sizes[$s]['height'] ) )
+ $sizes[$s]['height'] = intval( $_wp_additional_image_sizes[$s]['height'] ); // For theme-added sizes
+ else
+ $sizes[$s]['height'] = get_option( "{$s}_size_h" ); // For default sizes set in options
+ if ( isset( $_wp_additional_image_sizes[$s]['crop'] ) )
+ $sizes[$s]['crop'] = intval( $_wp_additional_image_sizes[$s]['crop'] ); // For theme-added sizes
+ else
+ $sizes[$s]['crop'] = get_option( "{$s}_crop" ); // For default sizes set in options
+ }
+
+ $sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes );
+
+ if ( $sizes ) {
+ $editor = wp_get_image_editor( $file );
+
+ if ( ! is_wp_error( $editor ) )
+ $metadata['sizes'] = $editor->multi_resize( $sizes );
+ } else {
+ $metadata['sizes'] = array();
+ }
+
+ // fetch additional metadata from exif/iptc
+ $image_meta = wp_read_image_metadata( $file );
+ if ( $image_meta )
+ $metadata['image_meta'] = $image_meta;
+
+ } elseif ( preg_match( '#^video/#', get_post_mime_type( $attachment ) ) ) {
+ $metadata = wp_read_video_metadata( $file );
+ $support = current_theme_supports( 'post-thumbnails', 'attachment:video' ) && post_type_supports( 'attachment:video', 'thumbnail' );
+ } elseif ( preg_match( '#^audio/#', get_post_mime_type( $attachment ) ) ) {
+ $metadata = wp_read_audio_metadata( $file );
+ $support = current_theme_supports( 'post-thumbnails', 'attachment:audio' ) && post_type_supports( 'attachment:audio', 'thumbnail' );
+ }
+
+ if ( $support && ! empty( $metadata['image']['data'] ) ) {
+ $ext = '.jpg';
+ switch ( $metadata['image']['mime'] ) {
+ case 'image/gif':
+ $ext = '.gif';
+ break;
+ case 'image/png':
+ $ext = '.png';
+ break;
+ }
+ $basename = str_replace( '.', '-', basename( $file ) ) . '-image' . $ext;
+ $uploaded = wp_upload_bits( $basename, '', $metadata['image']['data'] );
+ if ( false === $uploaded['error'] ) {
+ $attachment = array(
+ 'post_mime_type' => $metadata['image']['mime'],
+ 'post_type' => 'attachment',
+ 'post_content' => '',
+ );
+ $sub_attachment_id = wp_insert_attachment( $attachment, $uploaded['file'] );
+ $attach_data = wp_generate_attachment_metadata( $sub_attachment_id, $uploaded['file'] );
+ wp_update_attachment_metadata( $sub_attachment_id, $attach_data );
+ update_post_meta( $attachment_id, '_thumbnail_id', $sub_attachment_id );
+ }
+ }
+ // remove the blob of binary data from the array
+ unset( $metadata['image']['data'] );
+
+ return apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id );
+}
+
+/**
+ * Convert a fraction string to a decimal.
+ *
+ * @since 2.5.0
+ *
+ * @param string $str
+ * @return int|float
+ */
+function wp_exif_frac2dec($str) {
+ @list( $n, $d ) = explode( '/', $str );
+ if ( !empty($d) )
+ return $n / $d;
+ return $str;
+}
+
+/**
+ * Convert the exif date format to a unix timestamp.
+ *
+ * @since 2.5.0
+ *
+ * @param string $str
+ * @return int
+ */
+function wp_exif_date2ts($str) {
+ @list( $date, $time ) = explode( ' ', trim($str) );
+ @list( $y, $m, $d ) = explode( ':', $date );
+
+ return strtotime( "{$y}-{$m}-{$d} {$time}" );
+}
+
+/**
+ * Get extended image metadata, exif or iptc as available.
+ *
+ * Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso
+ * created_timestamp, focal_length, shutter_speed, and title.
+ *
+ * The IPTC metadata that is retrieved is APP13, credit, byline, created date
+ * and time, caption, copyright, and title. Also includes FNumber, Model,
+ * DateTimeDigitized, FocalLength, ISOSpeedRatings, and ExposureTime.
+ *
+ * @todo Try other exif libraries if available.
+ * @since 2.5.0
+ *
+ * @param string $file
+ * @return bool|array False on failure. Image metadata array on success.
+ */
+function wp_read_image_metadata( $file ) {
+ if ( ! file_exists( $file ) )
+ return false;
+
+ list( , , $sourceImageType ) = getimagesize( $file );
+
+ // exif contains a bunch of data we'll probably never need formatted in ways
+ // that are difficult to use. We'll normalize it and just extract the fields
+ // that are likely to be useful. Fractions and numbers are converted to
+ // floats, dates to unix timestamps, and everything else to strings.
+ $meta = array(
+ 'aperture' => 0,
+ 'credit' => '',
+ 'camera' => '',
+ 'caption' => '',
+ 'created_timestamp' => 0,
+ 'copyright' => '',
+ 'focal_length' => 0,
+ 'iso' => 0,
+ 'shutter_speed' => 0,
+ 'title' => '',
+ );
+
+ // read iptc first, since it might contain data not available in exif such
+ // as caption, description etc
+ if ( is_callable( 'iptcparse' ) ) {
+ getimagesize( $file, $info );
+
+ if ( ! empty( $info['APP13'] ) ) {
+ $iptc = iptcparse( $info['APP13'] );
+
+ // headline, "A brief synopsis of the caption."
+ if ( ! empty( $iptc['2#105'][0] ) )
+ $meta['title'] = trim( $iptc['2#105'][0] );
+ // title, "Many use the Title field to store the filename of the image, though the field may be used in many ways."
+ elseif ( ! empty( $iptc['2#005'][0] ) )
+ $meta['title'] = trim( $iptc['2#005'][0] );
+
+ if ( ! empty( $iptc['2#120'][0] ) ) { // description / legacy caption
+ $caption = trim( $iptc['2#120'][0] );
+ if ( empty( $meta['title'] ) ) {
+ // Assume the title is stored in 2:120 if it's short.
+ if ( strlen( $caption ) < 80 )
+ $meta['title'] = $caption;
+ else
+ $meta['caption'] = $caption;
+ } elseif ( $caption != $meta['title'] ) {
+ $meta['caption'] = $caption;
+ }
+ }
+
+ if ( ! empty( $iptc['2#110'][0] ) ) // credit
+ $meta['credit'] = trim( $iptc['2#110'][0] );
+ elseif ( ! empty( $iptc['2#080'][0] ) ) // creator / legacy byline
+ $meta['credit'] = trim( $iptc['2#080'][0] );
+
+ if ( ! empty( $iptc['2#055'][0] ) and ! empty( $iptc['2#060'][0] ) ) // created date and time
+ $meta['created_timestamp'] = strtotime( $iptc['2#055'][0] . ' ' . $iptc['2#060'][0] );
+
+ if ( ! empty( $iptc['2#116'][0] ) ) // copyright
+ $meta['copyright'] = trim( $iptc['2#116'][0] );
+ }
+ }
+
+ // fetch additional info from exif if available
+ if ( is_callable( 'exif_read_data' ) && in_array( $sourceImageType, apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ) ) ) {
+ $exif = @exif_read_data( $file );
+
+ if ( !empty( $exif['Title'] ) )
+ $meta['title'] = trim( $exif['Title'] );
+
+ if ( ! empty( $exif['ImageDescription'] ) ) {
+ if ( empty( $meta['title'] ) && strlen( $exif['ImageDescription'] ) < 80 ) {
+ // Assume the title is stored in ImageDescription
+ $meta['title'] = trim( $exif['ImageDescription'] );
+ if ( ! empty( $exif['COMPUTED']['UserComment'] ) && trim( $exif['COMPUTED']['UserComment'] ) != $meta['title'] )
+ $meta['caption'] = trim( $exif['COMPUTED']['UserComment'] );
+ } elseif ( trim( $exif['ImageDescription'] ) != $meta['title'] ) {
+ $meta['caption'] = trim( $exif['ImageDescription'] );
+ }
+ } elseif ( ! empty( $exif['Comments'] ) && trim( $exif['Comments'] ) != $meta['title'] ) {
+ $meta['caption'] = trim( $exif['Comments'] );
+ }
+
+ if ( ! empty( $exif['Artist'] ) )
+ $meta['credit'] = trim( $exif['Artist'] );
+ elseif ( ! empty($exif['Author'] ) )
+ $meta['credit'] = trim( $exif['Author'] );
+
+ if ( ! empty( $exif['Copyright'] ) )
+ $meta['copyright'] = trim( $exif['Copyright'] );
+ if ( ! empty($exif['FNumber'] ) )
+ $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
+ if ( ! empty($exif['Model'] ) )
+ $meta['camera'] = trim( $exif['Model'] );
+ if ( ! empty($exif['DateTimeDigitized'] ) )
+ $meta['created_timestamp'] = wp_exif_date2ts($exif['DateTimeDigitized'] );
+ if ( ! empty($exif['FocalLength'] ) )
+ $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
+ if ( ! empty($exif['ISOSpeedRatings'] ) ) {
+ $meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings'];
+ $meta['iso'] = trim( $meta['iso'] );
+ }
+ if ( ! empty($exif['ExposureTime'] ) )
+ $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
+ }
+
+ foreach ( array( 'title', 'caption', 'credit', 'copyright', 'camera', 'iso' ) as $key ) {
+ if ( $meta[ $key ] && ! seems_utf8( $meta[ $key ] ) )
+ $meta[ $key ] = utf8_encode( $meta[ $key ] );
+ }
+
+ return apply_filters( 'wp_read_image_metadata', $meta, $file, $sourceImageType );
+
+}
+
+/**
+ * Validate that file is an image.
+ *
+ * @since 2.5.0
+ *
+ * @param string $path File path to test if valid image.
+ * @return bool True if valid image, false if not valid image.
+ */
+function file_is_valid_image($path) {
+ $size = @getimagesize($path);
+ return !empty($size);
+}
+
+/**
+ * Validate that file is suitable for displaying within a web page.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'file_is_displayable_image' on $result and $path.
+ *
+ * @param string $path File path to test.
+ * @return bool True if suitable, false if not suitable.
+ */
+function file_is_displayable_image($path) {
+ $info = @getimagesize($path);
+ if ( empty($info) )
+ $result = false;
+ elseif ( !in_array($info[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG)) ) // only gif, jpeg and png images can reliably be displayed
+ $result = false;
+ else
+ $result = true;
+
+ return apply_filters('file_is_displayable_image', $result, $path);
+}
+
+/**
+ * Load an image resource for editing.
+ *
+ * @since 2.9.0
+ *
+ * @param string $attachment_id Attachment ID.
+ * @param string $mime_type Image mime type.
+ * @param string $size Optional. Image size, defaults to 'full'.
+ * @return resource|false The resulting image resource on success, false on failure.
+ */
+function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) {
+ $filepath = _load_image_to_edit_path( $attachment_id, $size );
+ if ( empty( $filepath ) )
+ return false;
+
+ switch ( $mime_type ) {
+ case 'image/jpeg':
+ $image = imagecreatefromjpeg($filepath);
+ break;
+ case 'image/png':
+ $image = imagecreatefrompng($filepath);
+ break;
+ case 'image/gif':
+ $image = imagecreatefromgif($filepath);
+ break;
+ default:
+ $image = false;
+ break;
+ }
+ if ( is_resource($image) ) {
+ $image = apply_filters('load_image_to_edit', $image, $attachment_id, $size);
+ if ( function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
+ imagealphablending($image, false);
+ imagesavealpha($image, true);
+ }
+ }
+ return $image;
+}
+
+/**
+ * Retrieve the path or url of an attachment's attached file.
+ *
+ * If the attached file is not present on the local filesystem (usually due to replication plugins),
+ * then the url of the file is returned if url fopen is supported.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string $attachment_id Attachment ID.
+ * @param string $size Optional. Image size, defaults to 'full'.
+ * @return string|false File path or url on success, false on failure.
+ */
+function _load_image_to_edit_path( $attachment_id, $size = 'full' ) {
+ $filepath = get_attached_file( $attachment_id );
+
+ if ( $filepath && file_exists( $filepath ) ) {
+ if ( 'full' != $size && ( $data = image_get_intermediate_size( $attachment_id, $size ) ) ) {
+ $filepath = apply_filters( 'load_image_to_edit_filesystempath', path_join( dirname( $filepath ), $data['file'] ), $attachment_id, $size );
+ }
+ } elseif ( function_exists( 'fopen' ) && function_exists( 'ini_get' ) && true == ini_get( 'allow_url_fopen' ) ) {
+ $filepath = apply_filters( 'load_image_to_edit_attachmenturl', wp_get_attachment_url( $attachment_id ), $attachment_id, $size );
+ }
+
+ return apply_filters( 'load_image_to_edit_path', $filepath, $attachment_id, $size );
+}
+
+/**
+ * Copy an existing image file.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string $attachment_id Attachment ID.
+ * @return string|false New file path on success, false on failure.
+ */
+function _copy_image_file( $attachment_id ) {
+ $dst_file = $src_file = get_attached_file( $attachment_id );
+ if ( ! file_exists( $src_file ) )
+ $src_file = _load_image_to_edit_path( $attachment_id );
+
+ if ( $src_file ) {
+ $dst_file = str_replace( basename( $dst_file ), 'copy-' . basename( $dst_file ), $dst_file );
+ $dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
+
+ // The directory containing the original file may no longer exist when
+ // using a replication plugin.
+ wp_mkdir_p( dirname( $dst_file ) );
+
+ if ( ! @copy( $src_file, $dst_file ) )
+ $dst_file = false;
+ } else {
+ $dst_file = false;
+ }
+
+ return $dst_file;
+}
diff --git a/src/wp-admin/includes/import.php b/src/wp-admin/includes/import.php
new file mode 100644
index 0000000000..69f7ebe6a3
--- /dev/null
+++ b/src/wp-admin/includes/import.php
@@ -0,0 +1,186 @@
+<?php
+/**
+ * WordPress Administration Importer API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Retrieve list of importers.
+ *
+ * @since 2.0.0
+ *
+ * @return array
+ */
+function get_importers() {
+ global $wp_importers;
+ if ( is_array($wp_importers) )
+ uasort($wp_importers, create_function('$a, $b', 'return strcmp($a[0], $b[0]);'));
+ return $wp_importers;
+}
+
+/**
+ * Register importer for WordPress.
+ *
+ * @since 2.0.0
+ *
+ * @param string $id Importer tag. Used to uniquely identify importer.
+ * @param string $name Importer name and title.
+ * @param string $description Importer description.
+ * @param callback $callback Callback to run.
+ * @return WP_Error Returns WP_Error when $callback is WP_Error.
+ */
+function register_importer( $id, $name, $description, $callback ) {
+ global $wp_importers;
+ if ( is_wp_error( $callback ) )
+ return $callback;
+ $wp_importers[$id] = array ( $name, $description, $callback );
+}
+
+/**
+ * Cleanup importer.
+ *
+ * Removes attachment based on ID.
+ *
+ * @since 2.0.0
+ *
+ * @param string $id Importer ID.
+ */
+function wp_import_cleanup( $id ) {
+ wp_delete_attachment( $id );
+}
+
+/**
+ * Handle importer uploading and add attachment.
+ *
+ * @since 2.0.0
+ *
+ * @return array Uploaded file's details on success, error message on failure
+ */
+function wp_import_handle_upload() {
+ if ( !isset($_FILES['import']) ) {
+ $file['error'] = __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' );
+ return $file;
+ }
+
+ $overrides = array( 'test_form' => false, 'test_type' => false );
+ $_FILES['import']['name'] .= '.txt';
+ $file = wp_handle_upload( $_FILES['import'], $overrides );
+
+ if ( isset( $file['error'] ) )
+ return $file;
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $filename = basename( $file );
+
+ // Construct the object array
+ $object = array( 'post_title' => $filename,
+ 'post_content' => $url,
+ 'post_mime_type' => $type,
+ 'guid' => $url,
+ 'context' => 'import',
+ 'post_status' => 'private'
+ );
+
+ // Save the data
+ $id = wp_insert_attachment( $object, $file );
+
+ // schedule a cleanup for one day from now in case of failed import or missing wp_import_cleanup() call
+ wp_schedule_single_event( time() + DAY_IN_SECONDS, 'importer_scheduled_cleanup', array( $id ) );
+
+ return array( 'file' => $file, 'id' => $id );
+}
+
+/**
+ * Returns a list from WordPress.org of popular importer plugins.
+ *
+ * @since 3.5.0
+ *
+ * @return array Importers with metadata for each.
+ */
+function wp_get_popular_importers() {
+ include ABSPATH . WPINC . '/version.php'; // include an unmodified $wp_version
+
+ $locale = get_locale();
+ $popular_importers = get_site_transient( 'popular_importers_' . $locale );
+
+ if ( ! $popular_importers ) {
+ $url = add_query_arg( 'locale', get_locale(), 'http://api.wordpress.org/core/importers/1.0/' );
+ $options = array( 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url() );
+ $response = wp_remote_get( $url, $options );
+ $popular_importers = maybe_unserialize( wp_remote_retrieve_body( $response ) );
+
+ if ( is_array( $popular_importers ) )
+ set_site_transient( 'popular_importers_' . $locale, $popular_importers, 2 * DAY_IN_SECONDS );
+ else
+ $popular_importers = false;
+ }
+
+ if ( is_array( $popular_importers ) ) {
+ // If the data was received as translated, return it as-is.
+ if ( $popular_importers['translated'] )
+ return $popular_importers['importers'];
+
+ foreach ( $popular_importers['importers'] as &$importer ) {
+ $importer['description'] = translate( $importer['description'] );
+ if ( $importer['name'] != 'WordPress' )
+ $importer['name'] = translate( $importer['name'] );
+ }
+ return $popular_importers['importers'];
+ }
+
+ return array(
+ // slug => name, description, plugin slug, and register_importer() slug
+ 'blogger' => array(
+ 'name' => __( 'Blogger' ),
+ 'description' => __( 'Install the Blogger importer to import posts, comments, and users from a Blogger blog.' ),
+ 'plugin-slug' => 'blogger-importer',
+ 'importer-id' => 'blogger',
+ ),
+ 'wpcat2tag' => array(
+ 'name' => __( 'Categories and Tags Converter' ),
+ 'description' => __( 'Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.' ),
+ 'plugin-slug' => 'wpcat2tag-importer',
+ 'importer-id' => 'wp-cat2tag',
+ ),
+ 'livejournal' => array(
+ 'name' => __( 'LiveJournal' ),
+ 'description' => __( 'Install the LiveJournal importer to import posts from LiveJournal using their API.' ),
+ 'plugin-slug' => 'livejournal-importer',
+ 'importer-id' => 'livejournal',
+ ),
+ 'movabletype' => array(
+ 'name' => __( 'Movable Type and TypePad' ),
+ 'description' => __( 'Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.' ),
+ 'plugin-slug' => 'movabletype-importer',
+ 'importer-id' => 'mt',
+ ),
+ 'opml' => array(
+ 'name' => __( 'Blogroll' ),
+ 'description' => __( 'Install the blogroll importer to import links in OPML format.' ),
+ 'plugin-slug' => 'opml-importer',
+ 'importer-id' => 'opml',
+ ),
+ 'rss' => array(
+ 'name' => __( 'RSS' ),
+ 'description' => __( 'Install the RSS importer to import posts from an RSS feed.' ),
+ 'plugin-slug' => 'rss-importer',
+ 'importer-id' => 'rss',
+ ),
+ 'tumblr' => array(
+ 'name' => __( 'Tumblr' ),
+ 'description' => __( 'Install the Tumblr importer to import posts &amp; media from Tumblr using their API.' ),
+ 'plugin-slug' => 'tumblr-importer',
+ 'importer-id' => 'tumblr',
+ ),
+ 'wordpress' => array(
+ 'name' => 'WordPress',
+ 'description' => __( 'Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' ),
+ 'plugin-slug' => 'wordpress-importer',
+ 'importer-id' => 'wordpress',
+ ),
+ );
+}
diff --git a/src/wp-admin/includes/list-table.php b/src/wp-admin/includes/list-table.php
new file mode 100644
index 0000000000..071df0dcc5
--- /dev/null
+++ b/src/wp-admin/includes/list-table.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * Helper functions for displaying a list of items in an ajaxified HTML table.
+ *
+ * @package WordPress
+ * @subpackage List_Table
+ * @since 3.1.0
+ */
+
+/**
+ * Fetch an instance of a WP_List_Table class.
+ *
+ * @access private
+ * @since 3.1.0
+ *
+ * @param string $class The type of the list table, which is the class name.
+ * @param array $args Optional. Arguments to pass to the class. Accepts 'screen'.
+ * @return object|bool Object on success, false if the class does not exist.
+ */
+function _get_list_table( $class, $args = array() ) {
+ $core_classes = array(
+ //Site Admin
+ 'WP_Posts_List_Table' => 'posts',
+ 'WP_Media_List_Table' => 'media',
+ 'WP_Terms_List_Table' => 'terms',
+ 'WP_Users_List_Table' => 'users',
+ 'WP_Comments_List_Table' => 'comments',
+ 'WP_Post_Comments_List_Table' => 'comments',
+ 'WP_Links_List_Table' => 'links',
+ 'WP_Plugin_Install_List_Table' => 'plugin-install',
+ 'WP_Themes_List_Table' => 'themes',
+ 'WP_Theme_Install_List_Table' => array( 'themes', 'theme-install' ),
+ 'WP_Plugins_List_Table' => 'plugins',
+ // Network Admin
+ 'WP_MS_Sites_List_Table' => 'ms-sites',
+ 'WP_MS_Users_List_Table' => 'ms-users',
+ 'WP_MS_Themes_List_Table' => 'ms-themes',
+ );
+
+ if ( isset( $core_classes[ $class ] ) ) {
+ foreach ( (array) $core_classes[ $class ] as $required )
+ require_once( ABSPATH . 'wp-admin/includes/class-wp-' . $required . '-list-table.php' );
+
+ if ( isset( $args['screen'] ) )
+ $args['screen'] = convert_to_screen( $args['screen'] );
+ elseif ( isset( $GLOBALS['hook_suffix'] ) )
+ $args['screen'] = get_current_screen();
+ else
+ $args['screen'] = null;
+
+ return new $class( $args );
+ }
+
+ return false;
+}
+
+/**
+ * Register column headers for a particular screen.
+ *
+ * @since 2.7.0
+ *
+ * @param string $screen The handle for the screen to add help to. This is usually the hook name returned by the add_*_page() functions.
+ * @param array $columns An array of columns with column IDs as the keys and translated column names as the values
+ * @see get_column_headers(), print_column_headers(), get_hidden_columns()
+ */
+function register_column_headers($screen, $columns) {
+ $wp_list_table = new _WP_List_Table_Compat($screen, $columns);
+}
+
+/**
+ * Prints column headers for a particular screen.
+ *
+ * @since 2.7.0
+ */
+function print_column_headers($screen, $id = true) {
+ $wp_list_table = new _WP_List_Table_Compat($screen);
+
+ $wp_list_table->print_column_headers($id);
+}
+
+/**
+ * Helper class to be used only by back compat functions
+ *
+ * @since 3.1.0
+ */
+class _WP_List_Table_Compat extends WP_List_Table {
+ var $_screen;
+ var $_columns;
+
+ function _WP_List_Table_Compat( $screen, $columns = array() ) {
+ if ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ $this->_screen = $screen;
+
+ if ( !empty( $columns ) ) {
+ $this->_columns = $columns;
+ add_filter( 'manage_' . $screen->id . '_columns', array( &$this, 'get_columns' ), 0 );
+ }
+ }
+
+ function get_column_info() {
+ $columns = get_column_headers( $this->_screen );
+ $hidden = get_hidden_columns( $this->_screen );
+ $sortable = array();
+
+ return array( $columns, $hidden, $sortable );
+ }
+
+ function get_columns() {
+ return $this->_columns;
+ }
+}
diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php
new file mode 100644
index 0000000000..4b6417f861
--- /dev/null
+++ b/src/wp-admin/includes/media.php
@@ -0,0 +1,2659 @@
+<?php
+/**
+ * WordPress Administration Media API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Defines the default media upload tabs
+ *
+ * @since 2.5.0
+ *
+ * @return array default tabs
+ */
+function media_upload_tabs() {
+ $_default_tabs = array(
+ 'type' => __('From Computer'), // handler action suffix => tab text
+ 'type_url' => __('From URL'),
+ 'gallery' => __('Gallery'),
+ 'library' => __('Media Library')
+ );
+
+ return apply_filters('media_upload_tabs', $_default_tabs);
+}
+
+/**
+ * Adds the gallery tab back to the tabs array if post has image attachments
+ *
+ * @since 2.5.0
+ *
+ * @param array $tabs
+ * @return array $tabs with gallery if post has image attachment
+ */
+function update_gallery_tab($tabs) {
+ global $wpdb;
+
+ if ( !isset($_REQUEST['post_id']) ) {
+ unset($tabs['gallery']);
+ return $tabs;
+ }
+
+ $post_id = intval($_REQUEST['post_id']);
+
+ if ( $post_id )
+ $attachments = intval( $wpdb->get_var( $wpdb->prepare( "SELECT count(*) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' AND post_parent = %d", $post_id ) ) );
+
+ if ( empty($attachments) ) {
+ unset($tabs['gallery']);
+ return $tabs;
+ }
+
+ $tabs['gallery'] = sprintf(__('Gallery (%s)'), "<span id='attachments-count'>$attachments</span>");
+
+ return $tabs;
+}
+add_filter('media_upload_tabs', 'update_gallery_tab');
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ */
+function the_media_upload_tabs() {
+ global $redir_tab;
+ $tabs = media_upload_tabs();
+ $default = 'type';
+
+ if ( !empty($tabs) ) {
+ echo "<ul id='sidemenu'>\n";
+ if ( isset($redir_tab) && array_key_exists($redir_tab, $tabs) )
+ $current = $redir_tab;
+ elseif ( isset($_GET['tab']) && array_key_exists($_GET['tab'], $tabs) )
+ $current = $_GET['tab'];
+ else
+ $current = apply_filters('media_upload_default_tab', $default);
+
+ foreach ( $tabs as $callback => $text ) {
+ $class = '';
+
+ if ( $current == $callback )
+ $class = " class='current'";
+
+ $href = add_query_arg(array('tab' => $callback, 's' => false, 'paged' => false, 'post_mime_type' => false, 'm' => false));
+ $link = "<a href='" . esc_url($href) . "'$class>$text</a>";
+ echo "\t<li id='" . esc_attr("tab-$callback") . "'>$link</li>\n";
+ }
+ echo "</ul>\n";
+ }
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param integer $id image attachment id
+ * @param string $caption image caption
+ * @param string $alt image alt attribute
+ * @param string $title image title attribute
+ * @param string $align image css alignment property
+ * @param string $url image src url
+ * @param string|bool $rel image rel attribute
+ * @param string $size image size (thumbnail, medium, large, full or added with add_image_size() )
+ * @return string the html to insert into editor
+ */
+function get_image_send_to_editor($id, $caption, $title, $align, $url='', $rel = false, $size='medium', $alt = '') {
+
+ $html = get_image_tag($id, $alt, '', $align, $size);
+
+ $rel = $rel ? ' rel="attachment wp-att-' . esc_attr($id).'"' : '';
+
+ if ( $url )
+ $html = '<a href="' . esc_attr($url) . "\"$rel>$html</a>";
+
+ $html = apply_filters( 'image_send_to_editor', $html, $id, $caption, $title, $align, $url, $size, $alt );
+
+ return $html;
+}
+
+/**
+ * Adds image shortcode with caption to editor
+ *
+ * @since 2.6.0
+ *
+ * @param string $html
+ * @param integer $id
+ * @param string $caption image caption
+ * @param string $alt image alt attribute
+ * @param string $title image title attribute
+ * @param string $align image css alignment property
+ * @param string $url image src url
+ * @param string $size image size (thumbnail, medium, large, full or added with add_image_size() )
+ * @return string
+ */
+function image_add_caption( $html, $id, $caption, $title, $align, $url, $size, $alt = '' ) {
+
+ if ( empty($caption) || apply_filters( 'disable_captions', '' ) )
+ return $html;
+
+ $id = ( 0 < (int) $id ) ? 'attachment_' . $id : '';
+
+ if ( ! preg_match( '/width=["\']([0-9]+)/', $html, $matches ) )
+ return $html;
+
+ $width = $matches[1];
+
+ $caption = str_replace( array("\r\n", "\r"), "\n", $caption);
+ $caption = preg_replace_callback( '/<[a-zA-Z0-9]+(?: [^<>]+>)*/', '_cleanup_image_add_caption', $caption );
+ // convert any remaining line breaks to <br>
+ $caption = preg_replace( '/[ \n\t]*\n[ \t]*/', '<br />', $caption );
+
+ $html = preg_replace( '/(class=["\'][^\'"]*)align(none|left|right|center)\s?/', '$1', $html );
+ if ( empty($align) )
+ $align = 'none';
+
+ $shcode = '[caption id="' . $id . '" align="align' . $align . '" width="' . $width . '"]' . $html . ' ' . $caption . '[/caption]';
+
+ return apply_filters( 'image_add_caption_shortcode', $shcode, $html );
+}
+add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
+
+/**
+ * Private preg_replace callback used in image_add_caption()
+ *
+ * @access private
+ * @since 3.4.0
+ */
+function _cleanup_image_add_caption( $matches ) {
+ // remove any line breaks from inside the tags
+ return preg_replace( '/[\r\n\t]+/', ' ', $matches[0] );
+}
+
+/**
+ * Adds image html to editor
+ *
+ * @since 2.5.0
+ *
+ * @param string $html
+ */
+function media_send_to_editor($html) {
+?>
+<script type="text/javascript">
+/* <![CDATA[ */
+var win = window.dialogArguments || opener || parent || top;
+win.send_to_editor('<?php echo addslashes($html); ?>');
+/* ]]> */
+</script>
+<?php
+ exit;
+}
+
+/**
+ * This handles the file upload POST itself, creating the attachment post.
+ *
+ * @since 2.5.0
+ *
+ * @param string $file_id Index into the {@link $_FILES} array of the upload
+ * @param int $post_id The post ID the media is associated with
+ * @param array $post_data allows you to overwrite some of the attachment
+ * @param array $overrides allows you to override the {@link wp_handle_upload()} behavior
+ * @return int the ID of the attachment
+ */
+function media_handle_upload($file_id, $post_id, $post_data = array(), $overrides = array( 'test_form' => false )) {
+
+ $time = current_time('mysql');
+ if ( $post = get_post($post_id) ) {
+ if ( substr( $post->post_date, 0, 4 ) > 0 )
+ $time = $post->post_date;
+ }
+
+ $name = $_FILES[$file_id]['name'];
+ $file = wp_handle_upload($_FILES[$file_id], $overrides, $time);
+
+ if ( isset($file['error']) )
+ return new WP_Error( 'upload_error', $file['error'] );
+
+ $name_parts = pathinfo($name);
+ $name = trim( substr( $name, 0, -(1 + strlen($name_parts['extension'])) ) );
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $title = $name;
+ $content = '';
+
+ if ( preg_match( '#^audio#', $type ) ) {
+ $meta = wp_read_audio_metadata( $file );
+
+ if ( ! empty( $meta['title'] ) )
+ $title = $meta['title'];
+
+ $content = '';
+
+ if ( ! empty( $title ) ) {
+
+ if ( ! empty( $meta['album'] ) && ! empty( $meta['artist'] ) ) {
+ /* translators: 1: audio track title, 2: album title, 3: artist name */
+ $content .= sprintf( __( '"%1$s" from %2$s by %3$s.' ), $title, $meta['album'], $meta['artist'] );
+ } else if ( ! empty( $meta['album'] ) ) {
+ /* translators: 1: audio track title, 2: album title */
+ $content .= sprintf( __( '"%1$s" from %2$s.' ), $title, $meta['album'] );
+ } else if ( ! empty( $meta['artist'] ) ) {
+ /* translators: 1: audio track title, 2: artist name */
+ $content .= sprintf( __( '"%1$s" by %2$s.' ), $title, $meta['artist'] );
+ } else {
+ $content .= sprintf( __( '"%s".' ), $title );
+ }
+
+ } else if ( ! empty( $meta['album'] ) ) {
+
+ if ( ! empty( $meta['artist'] ) ) {
+ /* translators: 1: audio album title, 2: artist name */
+ $content .= sprintf( __( '%1$s by %2$s.' ), $meta['album'], $meta['artist'] );
+ } else {
+ $content .= $meta['album'] . '.';
+ }
+
+ } else if ( ! empty( $meta['artist'] ) ) {
+
+ $content .= $meta['artist'] . '.';
+
+ }
+
+ if ( ! empty( $meta['year'] ) )
+ $content .= ' ' . sprintf( __( 'Released: %d.' ), $meta['year'] );
+
+ if ( ! empty( $meta['track_number'] ) ) {
+ $track_number = explode( '/', $meta['track_number'] );
+ if ( isset( $track_number[1] ) )
+ $content .= ' ' . sprintf( __( 'Track %1$s of %2$s.' ), number_format_i18n( $track_number[0] ), number_format_i18n( $track_number[1] ) );
+ else
+ $content .= ' ' . sprintf( __( 'Track %1$s.' ), number_format_i18n( $track_number[0] ) );
+ }
+
+ if ( ! empty( $meta['genre'] ) )
+ $content .= ' ' . sprintf( __( 'Genre: %s.' ), $meta['genre'] );
+
+ // use image exif/iptc data for title and caption defaults if possible
+ } elseif ( $image_meta = @wp_read_image_metadata( $file ) ) {
+ if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) )
+ $title = $image_meta['title'];
+ if ( trim( $image_meta['caption'] ) )
+ $content = $image_meta['caption'];
+ }
+
+ // Construct the attachment array
+ $attachment = array_merge( array(
+ 'post_mime_type' => $type,
+ 'guid' => $url,
+ 'post_parent' => $post_id,
+ 'post_title' => $title,
+ 'post_content' => $content,
+ ), $post_data );
+
+ // This should never be set as it would then overwrite an existing attachment.
+ if ( isset( $attachment['ID'] ) )
+ unset( $attachment['ID'] );
+
+ // Save the data
+ $id = wp_insert_attachment($attachment, $file, $post_id);
+ if ( !is_wp_error($id) ) {
+ wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
+ }
+
+ return $id;
+
+}
+
+/**
+ * This handles a sideloaded file in the same way as an uploaded file is handled by {@link media_handle_upload()}
+ *
+ * @since 2.6.0
+ *
+ * @param array $file_array Array similar to a {@link $_FILES} upload array
+ * @param int $post_id The post ID the media is associated with
+ * @param string $desc Description of the sideloaded file
+ * @param array $post_data allows you to overwrite some of the attachment
+ * @return int|object The ID of the attachment or a WP_Error on failure
+ */
+function media_handle_sideload($file_array, $post_id, $desc = null, $post_data = array()) {
+ $overrides = array('test_form'=>false);
+
+ $time = current_time( 'mysql' );
+ if ( $post = get_post( $post_id ) ) {
+ if ( substr( $post->post_date, 0, 4 ) > 0 )
+ $time = $post->post_date;
+ }
+
+ $file = wp_handle_sideload( $file_array, $overrides, $time );
+ if ( isset($file['error']) )
+ return new WP_Error( 'upload_error', $file['error'] );
+
+ $url = $file['url'];
+ $type = $file['type'];
+ $file = $file['file'];
+ $title = preg_replace('/\.[^.]+$/', '', basename($file));
+ $content = '';
+
+ // use image exif/iptc data for title and caption defaults if possible
+ if ( $image_meta = @wp_read_image_metadata($file) ) {
+ if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) )
+ $title = $image_meta['title'];
+ if ( trim( $image_meta['caption'] ) )
+ $content = $image_meta['caption'];
+ }
+
+ if ( isset( $desc ) )
+ $title = $desc;
+
+ // Construct the attachment array
+ $attachment = array_merge( array(
+ 'post_mime_type' => $type,
+ 'guid' => $url,
+ 'post_parent' => $post_id,
+ 'post_title' => $title,
+ 'post_content' => $content,
+ ), $post_data );
+
+ // This should never be set as it would then overwrite an existing attachment.
+ if ( isset( $attachment['ID'] ) )
+ unset( $attachment['ID'] );
+
+ // Save the attachment metadata
+ $id = wp_insert_attachment($attachment, $file, $post_id);
+ if ( !is_wp_error($id) )
+ wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
+
+ return $id;
+}
+
+/**
+ * Adds the iframe to display content for the media upload page
+ *
+ * @since 2.5.0
+ *
+ * @param array $content_func
+ */
+function wp_iframe($content_func /* ... */) {
+ _wp_admin_html_begin();
+?>
+<title><?php bloginfo('name') ?> &rsaquo; <?php _e('Uploads'); ?> &#8212; <?php _e('WordPress'); ?></title>
+<?php
+
+wp_enqueue_style( 'colors' );
+// Check callback name for 'media'
+if ( ( is_array( $content_func ) && ! empty( $content_func[1] ) && 0 === strpos( (string) $content_func[1], 'media' ) )
+ || ( ! is_array( $content_func ) && 0 === strpos( $content_func, 'media' ) ) )
+ wp_enqueue_style( 'media' );
+wp_enqueue_style( 'ie' );
+?>
+<script type="text/javascript">
+//<![CDATA[
+addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
+var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>', pagenow = 'media-upload-popup', adminpage = 'media-upload-popup',
+isRtl = <?php echo (int) is_rtl(); ?>;
+//]]>
+</script>
+<?php
+do_action('admin_enqueue_scripts', 'media-upload-popup');
+do_action('admin_print_styles-media-upload-popup');
+do_action('admin_print_styles');
+do_action('admin_print_scripts-media-upload-popup');
+do_action('admin_print_scripts');
+do_action('admin_head-media-upload-popup');
+do_action('admin_head');
+
+if ( is_string($content_func) )
+ do_action( "admin_head_{$content_func}" );
+?>
+</head>
+<body<?php if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-core-ui no-js">
+<script type="text/javascript">
+document.body.className = document.body.className.replace('no-js', 'js');
+</script>
+<?php
+ $args = func_get_args();
+ $args = array_slice($args, 1);
+ call_user_func_array($content_func, $args);
+
+ do_action('admin_print_footer_scripts');
+?>
+<script type="text/javascript">if(typeof wpOnload=='function')wpOnload();</script>
+</body>
+</html>
+<?php
+}
+
+/**
+ * Adds the media button to the editor
+ *
+ * @since 2.5.0
+ *
+ * @param string $editor_id
+ */
+function media_buttons($editor_id = 'content') {
+ $post = get_post();
+ if ( ! $post && ! empty( $GLOBALS['post_ID'] ) )
+ $post = $GLOBALS['post_ID'];
+
+ wp_enqueue_media( array(
+ 'post' => $post
+ ) );
+
+ $img = '<span class="wp-media-buttons-icon"></span> ';
+
+ echo '<a href="#" id="insert-media-button" class="button insert-media add_media" data-editor="' . esc_attr( $editor_id ) . '" title="' . esc_attr__( 'Add Media' ) . '">' . $img . __( 'Add Media' ) . '</a>';
+
+ // Don't use this filter. Want to add a button? Use the media_buttons action.
+ $legacy_filter = apply_filters('media_buttons_context', ''); // deprecated
+
+ if ( $legacy_filter ) {
+ // #WP22559. Close <a> if a plugin started by closing <a> to open their own <a> tag.
+ if ( 0 === stripos( trim( $legacy_filter ), '</a>' ) )
+ $legacy_filter .= '</a>';
+ echo $legacy_filter;
+ }
+}
+add_action( 'media_buttons', 'media_buttons' );
+
+function get_upload_iframe_src( $type = null, $post_id = null, $tab = null ) {
+ global $post_ID;
+
+ if ( empty( $post_id ) )
+ $post_id = $post_ID;
+
+ $upload_iframe_src = add_query_arg( 'post_id', (int) $post_id, admin_url('media-upload.php') );
+
+ if ( $type && 'media' != $type )
+ $upload_iframe_src = add_query_arg('type', $type, $upload_iframe_src);
+
+ if ( ! empty( $tab ) )
+ $upload_iframe_src = add_query_arg('tab', $tab, $upload_iframe_src);
+
+ $upload_iframe_src = apply_filters($type . '_upload_iframe_src', $upload_iframe_src);
+
+ return add_query_arg('TB_iframe', true, $upload_iframe_src);
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @return mixed void|object WP_Error on failure
+ */
+function media_upload_form_handler() {
+ check_admin_referer('media-form');
+
+ $errors = null;
+
+ if ( isset($_POST['send']) ) {
+ $keys = array_keys($_POST['send']);
+ $send_id = (int) array_shift($keys);
+ }
+
+ if ( !empty($_POST['attachments']) ) foreach ( $_POST['attachments'] as $attachment_id => $attachment ) {
+ $post = $_post = get_post($attachment_id, ARRAY_A);
+
+ if ( !current_user_can( 'edit_post', $attachment_id ) )
+ continue;
+
+ if ( isset($attachment['post_content']) )
+ $post['post_content'] = $attachment['post_content'];
+ if ( isset($attachment['post_title']) )
+ $post['post_title'] = $attachment['post_title'];
+ if ( isset($attachment['post_excerpt']) )
+ $post['post_excerpt'] = $attachment['post_excerpt'];
+ if ( isset($attachment['menu_order']) )
+ $post['menu_order'] = $attachment['menu_order'];
+
+ if ( isset($send_id) && $attachment_id == $send_id ) {
+ if ( isset($attachment['post_parent']) )
+ $post['post_parent'] = $attachment['post_parent'];
+ }
+
+ $post = apply_filters('attachment_fields_to_save', $post, $attachment);
+
+ if ( isset($attachment['image_alt']) ) {
+ $image_alt = wp_unslash( $attachment['image_alt'] );
+ if ( $image_alt != get_post_meta($attachment_id, '_wp_attachment_image_alt', true) ) {
+ $image_alt = wp_strip_all_tags( $image_alt, true );
+ // update_meta expects slashed
+ update_post_meta( $attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
+ }
+ }
+
+ if ( isset($post['errors']) ) {
+ $errors[$attachment_id] = $post['errors'];
+ unset($post['errors']);
+ }
+
+ if ( $post != $_post )
+ wp_update_post($post);
+
+ foreach ( get_attachment_taxonomies($post) as $t ) {
+ if ( isset($attachment[$t]) )
+ wp_set_object_terms($attachment_id, array_map('trim', preg_split('/,+/', $attachment[$t])), $t, false);
+ }
+ }
+
+ if ( isset($_POST['insert-gallery']) || isset($_POST['update-gallery']) ) { ?>
+ <script type="text/javascript">
+ /* <![CDATA[ */
+ var win = window.dialogArguments || opener || parent || top;
+ win.tb_remove();
+ /* ]]> */
+ </script>
+ <?php
+ exit;
+ }
+
+ if ( isset($send_id) ) {
+ $attachment = wp_unslash( $_POST['attachments'][$send_id] );
+
+ $html = isset( $attachment['post_title'] ) ? $attachment['post_title'] : '';
+ if ( !empty($attachment['url']) ) {
+ $rel = '';
+ if ( strpos($attachment['url'], 'attachment_id') || get_attachment_link($send_id) == $attachment['url'] )
+ $rel = " rel='attachment wp-att-" . esc_attr($send_id) . "'";
+ $html = "<a href='{$attachment['url']}'$rel>$html</a>";
+ }
+
+ $html = apply_filters('media_send_to_editor', $html, $send_id, $attachment);
+ return media_send_to_editor($html);
+ }
+
+ return $errors;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @return mixed
+ */
+function wp_media_upload_handler() {
+ $errors = array();
+ $id = 0;
+
+ if ( isset($_POST['html-upload']) && !empty($_FILES) ) {
+ check_admin_referer('media-form');
+ // Upload File button was clicked
+ $id = media_handle_upload('async-upload', $_REQUEST['post_id']);
+ unset($_FILES);
+ if ( is_wp_error($id) ) {
+ $errors['upload_error'] = $id;
+ $id = false;
+ }
+ }
+
+ if ( !empty($_POST['insertonlybutton']) ) {
+ $src = $_POST['src'];
+ if ( !empty($src) && !strpos($src, '://') )
+ $src = "http://$src";
+
+ if ( isset( $_POST['media_type'] ) && 'image' != $_POST['media_type'] ) {
+ $title = esc_html( wp_unslash( $_POST['title'] ) );
+ if ( empty( $title ) )
+ $title = esc_html( basename( $src ) );
+
+ if ( $title && $src )
+ $html = "<a href='" . esc_url($src) . "'>$title</a>";
+
+ $type = 'file';
+ if ( ( $ext = preg_replace( '/^.+?\.([^.]+)$/', '$1', $src ) ) && ( $ext_type = wp_ext2type( $ext ) )
+ && ( 'audio' == $ext_type || 'video' == $ext_type ) )
+ $type = $ext_type;
+
+ $html = apply_filters( $type . '_send_to_editor_url', $html, esc_url_raw( $src ), $title );
+ } else {
+ $align = '';
+ $alt = esc_attr( wp_unslash( $_POST['alt'] ) );
+ if ( isset($_POST['align']) ) {
+ $align = esc_attr( wp_unslash( $_POST['align'] ) );
+ $class = " class='align$align'";
+ }
+ if ( !empty($src) )
+ $html = "<img src='" . esc_url($src) . "' alt='$alt'$class />";
+
+ $html = apply_filters( 'image_send_to_editor_url', $html, esc_url_raw( $src ), $alt, $align );
+ }
+
+ return media_send_to_editor($html);
+ }
+
+ if ( !empty($_POST) ) {
+ $return = media_upload_form_handler();
+
+ if ( is_string($return) )
+ return $return;
+ if ( is_array($return) )
+ $errors = $return;
+ }
+
+ if ( isset($_POST['save']) ) {
+ $errors['upload_notice'] = __('Saved.');
+ return media_upload_gallery();
+ }
+
+ if ( isset($_GET['tab']) && $_GET['tab'] == 'type_url' ) {
+ $type = 'image';
+ if ( isset( $_GET['type'] ) && in_array( $_GET['type'], array( 'video', 'audio', 'file' ) ) )
+ $type = $_GET['type'];
+ return wp_iframe( 'media_upload_type_url_form', $type, $errors, $id );
+ }
+
+ return wp_iframe( 'media_upload_type_form', 'image', $errors, $id );
+}
+
+/**
+ * Download an image from the specified URL and attach it to a post.
+ *
+ * @since 2.6.0
+ *
+ * @param string $file The URL of the image to download
+ * @param int $post_id The post ID the media is to be associated with
+ * @param string $desc Optional. Description of the image
+ * @return string|WP_Error Populated HTML img tag on success
+ */
+function media_sideload_image($file, $post_id, $desc = null) {
+ if ( ! empty($file) ) {
+ // Download file to temp location
+ $tmp = download_url( $file );
+
+ // Set variables for storage
+ // fix file filename for query strings
+ preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
+ $file_array['name'] = basename($matches[0]);
+ $file_array['tmp_name'] = $tmp;
+
+ // If error storing temporarily, unlink
+ if ( is_wp_error( $tmp ) ) {
+ @unlink($file_array['tmp_name']);
+ $file_array['tmp_name'] = '';
+ }
+
+ // do the validation and storage stuff
+ $id = media_handle_sideload( $file_array, $post_id, $desc );
+ // If error storing permanently, unlink
+ if ( is_wp_error($id) ) {
+ @unlink($file_array['tmp_name']);
+ return $id;
+ }
+
+ $src = wp_get_attachment_url( $id );
+ }
+
+ // Finally check to make sure the file has been saved, then return the html
+ if ( ! empty($src) ) {
+ $alt = isset($desc) ? esc_attr($desc) : '';
+ $html = "<img src='$src' alt='$alt' />";
+ return $html;
+ }
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @return unknown
+ */
+function media_upload_gallery() {
+ $errors = array();
+
+ if ( !empty($_POST) ) {
+ $return = media_upload_form_handler();
+
+ if ( is_string($return) )
+ return $return;
+ if ( is_array($return) )
+ $errors = $return;
+ }
+
+ wp_enqueue_script('admin-gallery');
+ return wp_iframe( 'media_upload_gallery_form', $errors );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @return unknown
+ */
+function media_upload_library() {
+ $errors = array();
+ if ( !empty($_POST) ) {
+ $return = media_upload_form_handler();
+
+ if ( is_string($return) )
+ return $return;
+ if ( is_array($return) )
+ $errors = $return;
+ }
+
+ return wp_iframe( 'media_upload_library_form', $errors );
+}
+
+/**
+ * Retrieve HTML for the image alignment radio buttons with the specified one checked.
+ *
+ * @since 2.7.0
+ *
+ * @param object $post
+ * @param string $checked
+ * @return string
+ */
+function image_align_input_fields( $post, $checked = '' ) {
+
+ if ( empty($checked) )
+ $checked = get_user_setting('align', 'none');
+
+ $alignments = array('none' => __('None'), 'left' => __('Left'), 'center' => __('Center'), 'right' => __('Right'));
+ if ( !array_key_exists( (string) $checked, $alignments ) )
+ $checked = 'none';
+
+ $out = array();
+ foreach ( $alignments as $name => $label ) {
+ $name = esc_attr($name);
+ $out[] = "<input type='radio' name='attachments[{$post->ID}][align]' id='image-align-{$name}-{$post->ID}' value='$name'".
+ ( $checked == $name ? " checked='checked'" : "" ) .
+ " /><label for='image-align-{$name}-{$post->ID}' class='align image-align-{$name}-label'>$label</label>";
+ }
+ return join("\n", $out);
+}
+
+/**
+ * Retrieve HTML for the size radio buttons with the specified one checked.
+ *
+ * @since 2.7.0
+ *
+ * @param object $post
+ * @param bool|string $check
+ * @return array
+ */
+function image_size_input_fields( $post, $check = '' ) {
+
+ // get a list of the actual pixel dimensions of each possible intermediate version of this image
+ $size_names = apply_filters( 'image_size_names_choose', array('thumbnail' => __('Thumbnail'), 'medium' => __('Medium'), 'large' => __('Large'), 'full' => __('Full Size')) );
+
+ if ( empty($check) )
+ $check = get_user_setting('imgsize', 'medium');
+
+ foreach ( $size_names as $size => $label ) {
+ $downsize = image_downsize($post->ID, $size);
+ $checked = '';
+
+ // is this size selectable?
+ $enabled = ( $downsize[3] || 'full' == $size );
+ $css_id = "image-size-{$size}-{$post->ID}";
+ // if this size is the default but that's not available, don't select it
+ if ( $size == $check ) {
+ if ( $enabled )
+ $checked = " checked='checked'";
+ else
+ $check = '';
+ } elseif ( !$check && $enabled && 'thumbnail' != $size ) {
+ // if $check is not enabled, default to the first available size that's bigger than a thumbnail
+ $check = $size;
+ $checked = " checked='checked'";
+ }
+
+ $html = "<div class='image-size-item'><input type='radio' " . disabled( $enabled, false, false ) . "name='attachments[$post->ID][image-size]' id='{$css_id}' value='{$size}'$checked />";
+
+ $html .= "<label for='{$css_id}'>$label</label>";
+ // only show the dimensions if that choice is available
+ if ( $enabled )
+ $html .= " <label for='{$css_id}' class='help'>" . sprintf( "(%d&nbsp;&times;&nbsp;%d)", $downsize[1], $downsize[2] ). "</label>";
+
+ $html .= '</div>';
+
+ $out[] = $html;
+ }
+
+ return array(
+ 'label' => __('Size'),
+ 'input' => 'html',
+ 'html' => join("\n", $out),
+ );
+}
+
+/**
+ * Retrieve HTML for the Link URL buttons with the default link type as specified.
+ *
+ * @since 2.7.0
+ *
+ * @param object $post
+ * @param string $url_type
+ * @return string
+ */
+function image_link_input_fields($post, $url_type = '') {
+
+ $file = wp_get_attachment_url($post->ID);
+ $link = get_attachment_link($post->ID);
+
+ if ( empty($url_type) )
+ $url_type = get_user_setting('urlbutton', 'post');
+
+ $url = '';
+ if ( $url_type == 'file' )
+ $url = $file;
+ elseif ( $url_type == 'post' )
+ $url = $link;
+
+ return "
+ <input type='text' class='text urlfield' name='attachments[$post->ID][url]' value='" . esc_attr($url) . "' /><br />
+ <button type='button' class='button urlnone' data-link-url=''>" . __('None') . "</button>
+ <button type='button' class='button urlfile' data-link-url='" . esc_attr($file) . "'>" . __('File URL') . "</button>
+ <button type='button' class='button urlpost' data-link-url='" . esc_attr($link) . "'>" . __('Attachment Post URL') . "</button>
+";
+}
+
+function wp_caption_input_textarea($edit_post) {
+ // post data is already escaped
+ $name = "attachments[{$edit_post->ID}][post_excerpt]";
+
+ return '<textarea name="' . $name . '" id="' . $name . '">' . $edit_post->post_excerpt . '</textarea>';
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param array $form_fields
+ * @param object $post
+ * @return array
+ */
+function image_attachment_fields_to_edit($form_fields, $post) {
+ return $form_fields;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param array $form_fields
+ * @param object $post {@internal $post not used}}
+ * @return array
+ */
+function media_single_attachment_fields_to_edit( $form_fields, $post ) {
+ unset($form_fields['url'], $form_fields['align'], $form_fields['image-size']);
+ return $form_fields;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.8.0
+ *
+ * @param array $form_fields
+ * @param object $post {@internal $post not used}}
+ * @return array
+ */
+function media_post_single_attachment_fields_to_edit( $form_fields, $post ) {
+ unset($form_fields['image_url']);
+ return $form_fields;
+}
+
+/**
+ * Filters input from media_upload_form_handler() and assigns a default
+ * post_title from the file name if none supplied.
+ *
+ * Illustrates the use of the attachment_fields_to_save filter
+ * which can be used to add default values to any field before saving to DB.
+ *
+ * @since 2.5.0
+ *
+ * @param object $post
+ * @param array $attachment {@internal $attachment not used}}
+ * @return array
+ */
+function image_attachment_fields_to_save($post, $attachment) {
+ if ( substr($post['post_mime_type'], 0, 5) == 'image' ) {
+ if ( strlen(trim($post['post_title'])) == 0 ) {
+ $post['post_title'] = preg_replace('/\.\w+$/', '', basename($post['guid']));
+ $post['errors']['post_title']['errors'][] = __('Empty Title filled from filename.');
+ }
+ }
+
+ return $post;
+}
+
+add_filter('attachment_fields_to_save', 'image_attachment_fields_to_save', 10, 2);
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param string $html
+ * @param integer $attachment_id
+ * @param array $attachment
+ * @return array
+ */
+function image_media_send_to_editor($html, $attachment_id, $attachment) {
+ $post = get_post($attachment_id);
+ if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
+ $url = $attachment['url'];
+ $align = !empty($attachment['align']) ? $attachment['align'] : 'none';
+ $size = !empty($attachment['image-size']) ? $attachment['image-size'] : 'medium';
+ $alt = !empty($attachment['image_alt']) ? $attachment['image_alt'] : '';
+ $rel = ( $url == get_attachment_link($attachment_id) );
+
+ return get_image_send_to_editor($attachment_id, $attachment['post_excerpt'], $attachment['post_title'], $align, $url, $rel, $size, $alt);
+ }
+
+ return $html;
+}
+
+add_filter('media_send_to_editor', 'image_media_send_to_editor', 10, 3);
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param object $post
+ * @param array $errors
+ * @return array
+ */
+function get_attachment_fields_to_edit($post, $errors = null) {
+ if ( is_int($post) )
+ $post = get_post($post);
+ if ( is_array($post) )
+ $post = new WP_Post( (object) $post );
+
+ $image_url = wp_get_attachment_url($post->ID);
+
+ $edit_post = sanitize_post($post, 'edit');
+
+ $form_fields = array(
+ 'post_title' => array(
+ 'label' => __('Title'),
+ 'value' => $edit_post->post_title
+ ),
+ 'image_alt' => array(),
+ 'post_excerpt' => array(
+ 'label' => __('Caption'),
+ 'input' => 'html',
+ 'html' => wp_caption_input_textarea($edit_post)
+ ),
+ 'post_content' => array(
+ 'label' => __('Description'),
+ 'value' => $edit_post->post_content,
+ 'input' => 'textarea'
+ ),
+ 'url' => array(
+ 'label' => __('Link URL'),
+ 'input' => 'html',
+ 'html' => image_link_input_fields($post, get_option('image_default_link_type')),
+ 'helps' => __('Enter a link URL or click above for presets.')
+ ),
+ 'menu_order' => array(
+ 'label' => __('Order'),
+ 'value' => $edit_post->menu_order
+ ),
+ 'image_url' => array(
+ 'label' => __('File URL'),
+ 'input' => 'html',
+ 'html' => "<input type='text' class='text urlfield' readonly='readonly' name='attachments[$post->ID][url]' value='" . esc_attr($image_url) . "' /><br />",
+ 'value' => wp_get_attachment_url($post->ID),
+ 'helps' => __('Location of the uploaded file.')
+ )
+ );
+
+ foreach ( get_attachment_taxonomies($post) as $taxonomy ) {
+ $t = (array) get_taxonomy($taxonomy);
+ if ( ! $t['public'] || ! $t['show_ui'] )
+ continue;
+ if ( empty($t['label']) )
+ $t['label'] = $taxonomy;
+ if ( empty($t['args']) )
+ $t['args'] = array();
+
+ $terms = get_object_term_cache($post->ID, $taxonomy);
+ if ( false === $terms )
+ $terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
+
+ $values = array();
+
+ foreach ( $terms as $term )
+ $values[] = $term->slug;
+ $t['value'] = join(', ', $values);
+
+ $form_fields[$taxonomy] = $t;
+ }
+
+ // Merge default fields with their errors, so any key passed with the error (e.g. 'error', 'helps', 'value') will replace the default
+ // The recursive merge is easily traversed with array casting: foreach( (array) $things as $thing )
+ $form_fields = array_merge_recursive($form_fields, (array) $errors);
+
+ // This was formerly in image_attachment_fields_to_edit().
+ if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
+ $alt = get_post_meta($post->ID, '_wp_attachment_image_alt', true);
+ if ( empty($alt) )
+ $alt = '';
+
+ $form_fields['post_title']['required'] = true;
+
+ $form_fields['image_alt'] = array(
+ 'value' => $alt,
+ 'label' => __('Alternative Text'),
+ 'helps' => __('Alt text for the image, e.g. &#8220;The Mona Lisa&#8221;')
+ );
+
+ $form_fields['align'] = array(
+ 'label' => __('Alignment'),
+ 'input' => 'html',
+ 'html' => image_align_input_fields($post, get_option('image_default_align')),
+ );
+
+ $form_fields['image-size'] = image_size_input_fields( $post, get_option('image_default_size', 'medium') );
+
+ } else {
+ unset( $form_fields['image_alt'] );
+ }
+
+ $form_fields = apply_filters('attachment_fields_to_edit', $form_fields, $post);
+
+ return $form_fields;
+}
+
+/**
+ * Retrieve HTML for media items of post gallery.
+ *
+ * The HTML markup retrieved will be created for the progress of SWF Upload
+ * component. Will also create link for showing and hiding the form to modify
+ * the image attachment.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @param array $errors Errors for attachment, if any.
+ * @return string
+ */
+function get_media_items( $post_id, $errors ) {
+ $attachments = array();
+ if ( $post_id ) {
+ $post = get_post($post_id);
+ if ( $post && $post->post_type == 'attachment' )
+ $attachments = array($post->ID => $post);
+ else
+ $attachments = get_children( array( 'post_parent' => $post_id, 'post_type' => 'attachment', 'orderby' => 'menu_order ASC, ID', 'order' => 'DESC') );
+ } else {
+ if ( is_array($GLOBALS['wp_the_query']->posts) )
+ foreach ( $GLOBALS['wp_the_query']->posts as $attachment )
+ $attachments[$attachment->ID] = $attachment;
+ }
+
+ $output = '';
+ foreach ( (array) $attachments as $id => $attachment ) {
+ if ( $attachment->post_status == 'trash' )
+ continue;
+ if ( $item = get_media_item( $id, array( 'errors' => isset($errors[$id]) ? $errors[$id] : null) ) )
+ $output .= "\n<div id='media-item-$id' class='media-item child-of-$attachment->post_parent preloaded'><div class='progress hidden'><div class='bar'></div></div><div id='media-upload-error-$id' class='hidden'></div><div class='filename hidden'></div>$item\n</div>";
+ }
+
+ return $output;
+}
+
+/**
+ * Retrieve HTML form for modifying the image attachment.
+ *
+ * @since 2.5.0
+ *
+ * @param int $attachment_id Attachment ID for modification.
+ * @param string|array $args Optional. Override defaults.
+ * @return string HTML form for attachment.
+ */
+function get_media_item( $attachment_id, $args = null ) {
+ global $redir_tab;
+
+ if ( ( $attachment_id = intval( $attachment_id ) ) && $thumb_url = wp_get_attachment_image_src( $attachment_id, 'thumbnail', true ) )
+ $thumb_url = $thumb_url[0];
+ else
+ $thumb_url = false;
+
+ $post = get_post( $attachment_id );
+ $current_post_id = !empty( $_GET['post_id'] ) ? (int) $_GET['post_id'] : 0;
+
+ $default_args = array( 'errors' => null, 'send' => $current_post_id ? post_type_supports( get_post_type( $current_post_id ), 'editor' ) : true, 'delete' => true, 'toggle' => true, 'show_title' => true );
+ $args = wp_parse_args( $args, $default_args );
+ $args = apply_filters( 'get_media_item_args', $args );
+ extract( $args, EXTR_SKIP );
+
+ $toggle_on = __( 'Show' );
+ $toggle_off = __( 'Hide' );
+
+ $filename = esc_html( wp_basename( $post->guid ) );
+ $title = esc_attr( $post->post_title );
+
+ if ( $_tags = get_the_tags( $attachment_id ) ) {
+ foreach ( $_tags as $tag )
+ $tags[] = $tag->name;
+ $tags = esc_attr( join( ', ', $tags ) );
+ }
+
+ $post_mime_types = get_post_mime_types();
+ $keys = array_keys( wp_match_mime_types( array_keys( $post_mime_types ), $post->post_mime_type ) );
+ $type = array_shift( $keys );
+ $type_html = "<input type='hidden' id='type-of-$attachment_id' value='" . esc_attr( $type ) . "' />";
+
+ $form_fields = get_attachment_fields_to_edit( $post, $errors );
+
+ if ( $toggle ) {
+ $class = empty( $errors ) ? 'startclosed' : 'startopen';
+ $toggle_links = "
+ <a class='toggle describe-toggle-on' href='#'>$toggle_on</a>
+ <a class='toggle describe-toggle-off' href='#'>$toggle_off</a>";
+ } else {
+ $class = '';
+ $toggle_links = '';
+ }
+
+ $display_title = ( !empty( $title ) ) ? $title : $filename; // $title shouldn't ever be empty, but just in case
+ $display_title = $show_title ? "<div class='filename new'><span class='title'>" . wp_html_excerpt( $display_title, 60, '&hellip;' ) . "</span></div>" : '';
+
+ $gallery = ( ( isset( $_REQUEST['tab'] ) && 'gallery' == $_REQUEST['tab'] ) || ( isset( $redir_tab ) && 'gallery' == $redir_tab ) );
+ $order = '';
+
+ foreach ( $form_fields as $key => $val ) {
+ if ( 'menu_order' == $key ) {
+ if ( $gallery )
+ $order = "<div class='menu_order'> <input class='menu_order_input' type='text' id='attachments[$attachment_id][menu_order]' name='attachments[$attachment_id][menu_order]' value='" . esc_attr( $val['value'] ). "' /></div>";
+ else
+ $order = "<input type='hidden' name='attachments[$attachment_id][menu_order]' value='" . esc_attr( $val['value'] ) . "' />";
+
+ unset( $form_fields['menu_order'] );
+ break;
+ }
+ }
+
+ $media_dims = '';
+ $meta = wp_get_attachment_metadata( $post->ID );
+ if ( isset( $meta['width'], $meta['height'] ) )
+ $media_dims .= "<span id='media-dims-$post->ID'>{$meta['width']}&nbsp;&times;&nbsp;{$meta['height']}</span> ";
+ $media_dims = apply_filters( 'media_meta', $media_dims, $post );
+
+ $image_edit_button = '';
+ if ( wp_attachment_is_image( $post->ID ) && wp_image_editor_supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
+ $nonce = wp_create_nonce( "image_editor-$post->ID" );
+ $image_edit_button = "<input type='button' id='imgedit-open-btn-$post->ID' onclick='imageEdit.open( $post->ID, \"$nonce\" )' class='button' value='" . esc_attr__( 'Edit Image' ) . "' /> <span class='spinner'></span>";
+ }
+
+ $attachment_url = get_permalink( $attachment_id );
+
+ $item = "
+ $type_html
+ $toggle_links
+ $order
+ $display_title
+ <table class='slidetoggle describe $class'>
+ <thead class='media-item-info' id='media-head-$post->ID'>
+ <tr valign='top'>
+ <td class='A1B1' id='thumbnail-head-$post->ID'>
+ <p><a href='$attachment_url' target='_blank'><img class='thumbnail' src='$thumb_url' alt='' /></a></p>
+ <p>$image_edit_button</p>
+ </td>
+ <td>
+ <p><strong>" . __('File name:') . "</strong> $filename</p>
+ <p><strong>" . __('File type:') . "</strong> $post->post_mime_type</p>
+ <p><strong>" . __('Upload date:') . "</strong> " . mysql2date( get_option('date_format'), $post->post_date ). '</p>';
+ if ( !empty( $media_dims ) )
+ $item .= "<p><strong>" . __('Dimensions:') . "</strong> $media_dims</p>\n";
+
+ $item .= "</td></tr>\n";
+
+ $item .= "
+ </thead>
+ <tbody>
+ <tr><td colspan='2' class='imgedit-response' id='imgedit-response-$post->ID'></td></tr>
+ <tr><td style='display:none' colspan='2' class='image-editor' id='image-editor-$post->ID'></td></tr>\n";
+
+ $defaults = array(
+ 'input' => 'text',
+ 'required' => false,
+ 'value' => '',
+ 'extra_rows' => array(),
+ );
+
+ if ( $send )
+ $send = get_submit_button( __( 'Insert into Post' ), 'button', "send[$attachment_id]", false );
+ if ( $delete && current_user_can( 'delete_post', $attachment_id ) ) {
+ if ( !EMPTY_TRASH_DAYS ) {
+ $delete = "<a href='" . wp_nonce_url( "post.php?action=delete&amp;post=$attachment_id", 'delete-post_' . $attachment_id ) . "' id='del[$attachment_id]' class='delete-permanently'>" . __( 'Delete Permanently' ) . '</a>';
+ } elseif ( !MEDIA_TRASH ) {
+ $delete = "<a href='#' class='del-link' onclick=\"document.getElementById('del_attachment_$attachment_id').style.display='block';return false;\">" . __( 'Delete' ) . "</a>
+ <div id='del_attachment_$attachment_id' class='del-attachment' style='display:none;'><p>" . sprintf( __( 'You are about to delete <strong>%s</strong>.' ), $filename ) . "</p>
+ <a href='" . wp_nonce_url( "post.php?action=delete&amp;post=$attachment_id", 'delete-post_' . $attachment_id ) . "' id='del[$attachment_id]' class='button'>" . __( 'Continue' ) . "</a>
+ <a href='#' class='button' onclick=\"this.parentNode.style.display='none';return false;\">" . __( 'Cancel' ) . "</a>
+ </div>";
+ } else {
+ $delete = "<a href='" . wp_nonce_url( "post.php?action=trash&amp;post=$attachment_id", 'trash-post_' . $attachment_id ) . "' id='del[$attachment_id]' class='delete'>" . __( 'Move to Trash' ) . "</a>
+ <a href='" . wp_nonce_url( "post.php?action=untrash&amp;post=$attachment_id", 'untrash-post_' . $attachment_id ) . "' id='undo[$attachment_id]' class='undo hidden'>" . __( 'Undo' ) . "</a>";
+ }
+ } else {
+ $delete = '';
+ }
+
+ $thumbnail = '';
+ $calling_post_id = 0;
+ if ( isset( $_GET['post_id'] ) )
+ $calling_post_id = absint( $_GET['post_id'] );
+ elseif ( isset( $_POST ) && count( $_POST ) ) // Like for async-upload where $_GET['post_id'] isn't set
+ $calling_post_id = $post->post_parent;
+ if ( 'image' == $type && $calling_post_id && current_theme_supports( 'post-thumbnails', get_post_type( $calling_post_id ) )
+ && post_type_supports( get_post_type( $calling_post_id ), 'thumbnail' ) && get_post_thumbnail_id( $calling_post_id ) != $attachment_id ) {
+ $ajax_nonce = wp_create_nonce( "set_post_thumbnail-$calling_post_id" );
+ $thumbnail = "<a class='wp-post-thumbnail' id='wp-post-thumbnail-" . $attachment_id . "' href='#' onclick='WPSetAsThumbnail(\"$attachment_id\", \"$ajax_nonce\");return false;'>" . esc_html__( "Use as featured image" ) . "</a>";
+ }
+
+ if ( ( $send || $thumbnail || $delete ) && !isset( $form_fields['buttons'] ) )
+ $form_fields['buttons'] = array( 'tr' => "\t\t<tr class='submit'><td></td><td class='savesend'>$send $thumbnail $delete</td></tr>\n" );
+
+ $hidden_fields = array();
+
+ foreach ( $form_fields as $id => $field ) {
+ if ( $id[0] == '_' )
+ continue;
+
+ if ( !empty( $field['tr'] ) ) {
+ $item .= $field['tr'];
+ continue;
+ }
+
+ $field = array_merge( $defaults, $field );
+ $name = "attachments[$attachment_id][$id]";
+
+ if ( $field['input'] == 'hidden' ) {
+ $hidden_fields[$name] = $field['value'];
+ continue;
+ }
+
+ $required = $field['required'] ? '<span class="alignright"><abbr title="required" class="required">*</abbr></span>' : '';
+ $aria_required = $field['required'] ? " aria-required='true' " : '';
+ $class = $id;
+ $class .= $field['required'] ? ' form-required' : '';
+
+ $item .= "\t\t<tr class='$class'>\n\t\t\t<th valign='top' scope='row' class='label'><label for='$name'><span class='alignleft'>{$field['label']}</span>$required<br class='clear' /></label></th>\n\t\t\t<td class='field'>";
+ if ( !empty( $field[ $field['input'] ] ) )
+ $item .= $field[ $field['input'] ];
+ elseif ( $field['input'] == 'textarea' ) {
+ if ( 'post_content' == $id && user_can_richedit() ) {
+ // sanitize_post() skips the post_content when user_can_richedit
+ $field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
+ }
+ // post_excerpt is already escaped by sanitize_post() in get_attachment_fields_to_edit()
+ $item .= "<textarea id='$name' name='$name' $aria_required>" . $field['value'] . '</textarea>';
+ } else {
+ $item .= "<input type='text' class='text' id='$name' name='$name' value='" . esc_attr( $field['value'] ) . "' $aria_required />";
+ }
+ if ( !empty( $field['helps'] ) )
+ $item .= "<p class='help'>" . join( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
+ $item .= "</td>\n\t\t</tr>\n";
+
+ $extra_rows = array();
+
+ if ( !empty( $field['errors'] ) )
+ foreach ( array_unique( (array) $field['errors'] ) as $error )
+ $extra_rows['error'][] = $error;
+
+ if ( !empty( $field['extra_rows'] ) )
+ foreach ( $field['extra_rows'] as $class => $rows )
+ foreach ( (array) $rows as $html )
+ $extra_rows[$class][] = $html;
+
+ foreach ( $extra_rows as $class => $rows )
+ foreach ( $rows as $html )
+ $item .= "\t\t<tr><td></td><td class='$class'>$html</td></tr>\n";
+ }
+
+ if ( !empty( $form_fields['_final'] ) )
+ $item .= "\t\t<tr class='final'><td colspan='2'>{$form_fields['_final']}</td></tr>\n";
+ $item .= "\t</tbody>\n";
+ $item .= "\t</table>\n";
+
+ foreach ( $hidden_fields as $name => $value )
+ $item .= "\t<input type='hidden' name='$name' id='$name' value='" . esc_attr( $value ) . "' />\n";
+
+ if ( $post->post_parent < 1 && isset( $_REQUEST['post_id'] ) ) {
+ $parent = (int) $_REQUEST['post_id'];
+ $parent_name = "attachments[$attachment_id][post_parent]";
+ $item .= "\t<input type='hidden' name='$parent_name' id='$parent_name' value='$parent' />\n";
+ }
+
+ return $item;
+}
+
+function get_compat_media_markup( $attachment_id, $args = null ) {
+ $post = get_post( $attachment_id );
+
+ $default_args = array(
+ 'errors' => null,
+ 'in_modal' => false,
+ );
+
+ $user_can_edit = current_user_can( 'edit_post', $attachment_id );
+
+ $args = wp_parse_args( $args, $default_args );
+ $args = apply_filters( 'get_media_item_args', $args );
+
+ $form_fields = array();
+
+ if ( $args['in_modal'] ) {
+ foreach ( get_attachment_taxonomies($post) as $taxonomy ) {
+ $t = (array) get_taxonomy($taxonomy);
+ if ( ! $t['public'] || ! $t['show_ui'] )
+ continue;
+ if ( empty($t['label']) )
+ $t['label'] = $taxonomy;
+ if ( empty($t['args']) )
+ $t['args'] = array();
+
+ $terms = get_object_term_cache($post->ID, $taxonomy);
+ if ( false === $terms )
+ $terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
+
+ $values = array();
+
+ foreach ( $terms as $term )
+ $values[] = $term->slug;
+ $t['value'] = join(', ', $values);
+ $t['taxonomy'] = true;
+
+ $form_fields[$taxonomy] = $t;
+ }
+ }
+
+ // Merge default fields with their errors, so any key passed with the error (e.g. 'error', 'helps', 'value') will replace the default
+ // The recursive merge is easily traversed with array casting: foreach( (array) $things as $thing )
+ $form_fields = array_merge_recursive($form_fields, (array) $args['errors'] );
+
+ $form_fields = apply_filters( 'attachment_fields_to_edit', $form_fields, $post );
+
+ unset( $form_fields['image-size'], $form_fields['align'], $form_fields['image_alt'],
+ $form_fields['post_title'], $form_fields['post_excerpt'], $form_fields['post_content'],
+ $form_fields['url'], $form_fields['menu_order'], $form_fields['image_url'] );
+
+ $media_meta = apply_filters( 'media_meta', '', $post );
+
+ $defaults = array(
+ 'input' => 'text',
+ 'required' => false,
+ 'value' => '',
+ 'extra_rows' => array(),
+ 'show_in_edit' => true,
+ 'show_in_modal' => true,
+ );
+
+ $hidden_fields = array();
+
+ $item = '';
+ foreach ( $form_fields as $id => $field ) {
+ if ( $id[0] == '_' )
+ continue;
+
+ $name = "attachments[$attachment_id][$id]";
+ $id_attr = "attachments-$attachment_id-$id";
+
+ if ( !empty( $field['tr'] ) ) {
+ $item .= $field['tr'];
+ continue;
+ }
+
+ $field = array_merge( $defaults, $field );
+
+ if ( ( ! $field['show_in_edit'] && ! $args['in_modal'] ) || ( ! $field['show_in_modal'] && $args['in_modal'] ) )
+ continue;
+
+ if ( $field['input'] == 'hidden' ) {
+ $hidden_fields[$name] = $field['value'];
+ continue;
+ }
+
+ $readonly = ! $user_can_edit && ! empty( $field['taxonomy'] ) ? " readonly='readonly' " : '';
+ $required = $field['required'] ? '<span class="alignright"><abbr title="required" class="required">*</abbr></span>' : '';
+ $aria_required = $field['required'] ? " aria-required='true' " : '';
+ $class = 'compat-field-' . $id;
+ $class .= $field['required'] ? ' form-required' : '';
+
+ $item .= "\t\t<tr class='$class'>";
+ $item .= "\t\t\t<th valign='top' scope='row' class='label'><label for='$id_attr'><span class='alignleft'>{$field['label']}</span>$required<br class='clear' /></label>";
+ $item .= "</th>\n\t\t\t<td class='field'>";
+
+ if ( !empty( $field[ $field['input'] ] ) )
+ $item .= $field[ $field['input'] ];
+ elseif ( $field['input'] == 'textarea' ) {
+ if ( 'post_content' == $id && user_can_richedit() ) {
+ // sanitize_post() skips the post_content when user_can_richedit
+ $field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
+ }
+ $item .= "<textarea id='$id_attr' name='$name' $aria_required>" . $field['value'] . '</textarea>';
+ } else {
+ $item .= "<input type='text' class='text' id='$id_attr' name='$name' value='" . esc_attr( $field['value'] ) . "' $readonly $aria_required />";
+ }
+ if ( !empty( $field['helps'] ) )
+ $item .= "<p class='help'>" . join( "</p>\n<p class='help'>", array_unique( (array) $field['helps'] ) ) . '</p>';
+ $item .= "</td>\n\t\t</tr>\n";
+
+ $extra_rows = array();
+
+ if ( !empty( $field['errors'] ) )
+ foreach ( array_unique( (array) $field['errors'] ) as $error )
+ $extra_rows['error'][] = $error;
+
+ if ( !empty( $field['extra_rows'] ) )
+ foreach ( $field['extra_rows'] as $class => $rows )
+ foreach ( (array) $rows as $html )
+ $extra_rows[$class][] = $html;
+
+ foreach ( $extra_rows as $class => $rows )
+ foreach ( $rows as $html )
+ $item .= "\t\t<tr><td></td><td class='$class'>$html</td></tr>\n";
+ }
+
+ if ( !empty( $form_fields['_final'] ) )
+ $item .= "\t\t<tr class='final'><td colspan='2'>{$form_fields['_final']}</td></tr>\n";
+ if ( $item )
+ $item = '<table class="compat-attachment-fields">' . $item . '</table>';
+
+ foreach ( $hidden_fields as $hidden_field => $value ) {
+ $item .= '<input type="hidden" name="' . esc_attr( $hidden_field ) . '" value="' . esc_attr( $value ) . '" />' . "\n";
+ }
+
+ if ( $item )
+ $item = '<input type="hidden" name="attachments[' . $attachment_id . '][menu_order]" value="' . esc_attr( $post->menu_order ) . '" />' . $item;
+
+ return array(
+ 'item' => $item,
+ 'meta' => $media_meta,
+ );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ */
+function media_upload_header() {
+ $post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
+ echo '<script type="text/javascript">post_id = ' . $post_id . ";</script>\n";
+ if ( empty( $_GET['chromeless'] ) ) {
+ echo '<div id="media-upload-header">';
+ the_media_upload_tabs();
+ echo '</div>';
+ }
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param unknown_type $errors
+ */
+function media_upload_form( $errors = null ) {
+ global $type, $tab, $is_IE, $is_opera;
+
+ if ( ! _device_can_upload() ) {
+ echo '<p>' . sprintf( __('The web browser on your device cannot be used to upload files. You may be able to use the <a href="%s">native app for your device</a> instead.'), 'http://wordpress.org/mobile/' ) . '</p>';
+ return;
+ }
+
+ $upload_action_url = admin_url('async-upload.php');
+ $post_id = isset($_REQUEST['post_id']) ? intval($_REQUEST['post_id']) : 0;
+ $_type = isset($type) ? $type : '';
+ $_tab = isset($tab) ? $tab : '';
+
+ $upload_size_unit = $max_upload_size = wp_max_upload_size();
+ $sizes = array( 'KB', 'MB', 'GB' );
+
+ for ( $u = -1; $upload_size_unit > 1024 && $u < count( $sizes ) - 1; $u++ ) {
+ $upload_size_unit /= 1024;
+ }
+
+ if ( $u < 0 ) {
+ $upload_size_unit = 0;
+ $u = 0;
+ } else {
+ $upload_size_unit = (int) $upload_size_unit;
+ }
+?>
+
+<div id="media-upload-notice"><?php
+
+ if (isset($errors['upload_notice']) )
+ echo $errors['upload_notice'];
+
+?></div>
+<div id="media-upload-error"><?php
+
+ if (isset($errors['upload_error']) && is_wp_error($errors['upload_error']))
+ echo $errors['upload_error']->get_error_message();
+
+?></div>
+<?php
+if ( is_multisite() && !is_upload_space_available() ) {
+ do_action( 'upload_ui_over_quota' );
+ return;
+}
+
+do_action('pre-upload-ui');
+
+$post_params = array(
+ "post_id" => $post_id,
+ "_wpnonce" => wp_create_nonce('media-form'),
+ "type" => $_type,
+ "tab" => $_tab,
+ "short" => "1",
+);
+
+$post_params = apply_filters( 'upload_post_params', $post_params ); // hook change! old name: 'swfupload_post_params'
+
+$plupload_init = array(
+ 'runtimes' => 'html5,silverlight,flash,html4',
+ 'browse_button' => 'plupload-browse-button',
+ 'container' => 'plupload-upload-ui',
+ 'drop_element' => 'drag-drop-area',
+ 'file_data_name' => 'async-upload',
+ 'multiple_queues' => true,
+ 'max_file_size' => $max_upload_size . 'b',
+ 'url' => $upload_action_url,
+ 'flash_swf_url' => includes_url('js/plupload/plupload.flash.swf'),
+ 'silverlight_xap_url' => includes_url('js/plupload/plupload.silverlight.xap'),
+ 'filters' => array( array('title' => __( 'Allowed Files' ), 'extensions' => '*') ),
+ 'multipart' => true,
+ 'urlstream_upload' => true,
+ 'multipart_params' => $post_params
+);
+
+// Multi-file uploading doesn't currently work in iOS Safari,
+// single-file allows the built-in camera to be used as source for images
+if ( wp_is_mobile() )
+ $plupload_init['multi_selection'] = false;
+
+$plupload_init = apply_filters( 'plupload_init', $plupload_init );
+
+?>
+
+<script type="text/javascript">
+<?php
+// Verify size is an int. If not return default value.
+$large_size_h = absint( get_option('large_size_h') );
+if( !$large_size_h )
+ $large_size_h = 1024;
+$large_size_w = absint( get_option('large_size_w') );
+if( !$large_size_w )
+ $large_size_w = 1024;
+?>
+var resize_height = <?php echo $large_size_h; ?>, resize_width = <?php echo $large_size_w; ?>,
+wpUploaderInit = <?php echo json_encode($plupload_init); ?>;
+</script>
+
+<div id="plupload-upload-ui" class="hide-if-no-js">
+<?php do_action('pre-plupload-upload-ui'); // hook change, old name: 'pre-flash-upload-ui' ?>
+<div id="drag-drop-area">
+ <div class="drag-drop-inside">
+ <p class="drag-drop-info"><?php _e('Drop files here'); ?></p>
+ <p><?php _ex('or', 'Uploader: Drop files here - or - Select Files'); ?></p>
+ <p class="drag-drop-buttons"><input id="plupload-browse-button" type="button" value="<?php esc_attr_e('Select Files'); ?>" class="button" /></p>
+ </div>
+</div>
+<?php do_action('post-plupload-upload-ui'); // hook change, old name: 'post-flash-upload-ui' ?>
+</div>
+
+<div id="html-upload-ui" class="hide-if-js">
+<?php do_action('pre-html-upload-ui'); ?>
+ <p id="async-upload-wrap">
+ <label class="screen-reader-text" for="async-upload"><?php _e('Upload'); ?></label>
+ <input type="file" name="async-upload" id="async-upload" />
+ <?php submit_button( __( 'Upload' ), 'button', 'html-upload', false ); ?>
+ <a href="#" onclick="try{top.tb_remove();}catch(e){}; return false;"><?php _e('Cancel'); ?></a>
+ </p>
+ <div class="clear"></div>
+<?php do_action('post-html-upload-ui'); ?>
+</div>
+
+<span class="max-upload-size"><?php printf( __( 'Maximum upload file size: %d%s.' ), esc_html($upload_size_unit), esc_html($sizes[$u]) ); ?></span>
+<?php
+if ( ($is_IE || $is_opera) && $max_upload_size > 100 * 1024 * 1024 ) { ?>
+ <span class="big-file-warning"><?php _e('Your browser has some limitations uploading large files with the multi-file uploader. Please use the browser uploader for files over 100MB.'); ?></span>
+<?php }
+
+ do_action('post-upload-ui');
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param string $type
+ * @param object $errors
+ * @param integer $id
+ */
+function media_upload_type_form($type = 'file', $errors = null, $id = null) {
+
+ media_upload_header();
+
+ $post_id = isset( $_REQUEST['post_id'] )? intval( $_REQUEST['post_id'] ) : 0;
+
+ $form_action_url = admin_url("media-upload.php?type=$type&tab=type&post_id=$post_id");
+ $form_action_url = apply_filters('media_upload_form_url', $form_action_url, $type);
+ $form_class = 'media-upload-form type-form validate';
+
+ if ( get_user_setting('uploader') )
+ $form_class .= ' html-uploader';
+?>
+
+<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="<?php echo $type; ?>-form">
+<?php submit_button( '', 'hidden', 'save', false ); ?>
+<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
+<?php wp_nonce_field('media-form'); ?>
+
+<h3 class="media-title"><?php _e('Add media files from your computer'); ?></h3>
+
+<?php media_upload_form( $errors ); ?>
+
+<script type="text/javascript">
+//<![CDATA[
+jQuery(function($){
+ var preloaded = $(".media-item.preloaded");
+ if ( preloaded.length > 0 ) {
+ preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
+ }
+ updateMediaForm();
+});
+//]]>
+</script>
+<div id="media-items"><?php
+
+if ( $id ) {
+ if ( !is_wp_error($id) ) {
+ add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2);
+ echo get_media_items( $id, $errors );
+ } else {
+ echo '<div id="media-upload-error">'.esc_html($id->get_error_message()).'</div></div>';
+ exit;
+ }
+}
+?></div>
+
+<p class="savebutton ml-submit">
+<?php submit_button( __( 'Save all changes' ), 'button', 'save', false ); ?>
+</p>
+</form>
+<?php
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param string $type
+ * @param object $errors
+ * @param integer $id
+ */
+function media_upload_type_url_form($type = null, $errors = null, $id = null) {
+ if ( null === $type )
+ $type = 'image';
+
+ media_upload_header();
+
+ $post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
+
+ $form_action_url = admin_url("media-upload.php?type=$type&tab=type&post_id=$post_id");
+ $form_action_url = apply_filters('media_upload_form_url', $form_action_url, $type);
+ $form_class = 'media-upload-form type-form validate';
+
+ if ( get_user_setting('uploader') )
+ $form_class .= ' html-uploader';
+?>
+
+<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="<?php echo $type; ?>-form">
+<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
+<?php wp_nonce_field('media-form'); ?>
+
+<h3 class="media-title"><?php _e('Insert media from another website'); ?></h3>
+
+<script type="text/javascript">
+//<![CDATA[
+var addExtImage = {
+
+ width : '',
+ height : '',
+ align : 'alignnone',
+
+ insert : function() {
+ var t = this, html, f = document.forms[0], cls, title = '', alt = '', caption = '';
+
+ if ( '' == f.src.value || '' == t.width )
+ return false;
+
+ if ( f.alt.value )
+ alt = f.alt.value.replace(/'/g, '&#039;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+
+<?php if ( ! apply_filters( 'disable_captions', '' ) ) { ?>
+ if ( f.caption.value ) {
+ caption = f.caption.value.replace(/\r\n|\r/g, '\n');
+ caption = caption.replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
+ return a.replace(/[\r\n\t]+/, ' ');
+ });
+
+ caption = caption.replace(/\s*\n\s*/g, '<br />');
+ }
+<?php } ?>
+
+ cls = caption ? '' : ' class="'+t.align+'"';
+
+ html = '<img alt="'+alt+'" src="'+f.src.value+'"'+cls+' width="'+t.width+'" height="'+t.height+'" />';
+
+ if ( f.url.value ) {
+ url = f.url.value.replace(/'/g, '&#039;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ html = '<a href="'+url+'">'+html+'</a>';
+ }
+
+ if ( caption )
+ html = '[caption id="" align="'+t.align+'" width="'+t.width+'"]'+html+caption+'[/caption]';
+
+ var win = window.dialogArguments || opener || parent || top;
+ win.send_to_editor(html);
+ return false;
+ },
+
+ resetImageData : function() {
+ var t = addExtImage;
+
+ t.width = t.height = '';
+ document.getElementById('go_button').style.color = '#bbb';
+ if ( ! document.forms[0].src.value )
+ document.getElementById('status_img').innerHTML = '*';
+ else document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/no.png' ) ); ?>" alt="" />';
+ },
+
+ updateImageData : function() {
+ var t = addExtImage;
+
+ t.width = t.preloadImg.width;
+ t.height = t.preloadImg.height;
+ document.getElementById('go_button').style.color = '#333';
+ document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/yes.png' ) ); ?>" alt="" />';
+ },
+
+ getImageData : function() {
+ if ( jQuery('table.describe').hasClass('not-image') )
+ return;
+
+ var t = addExtImage, src = document.forms[0].src.value;
+
+ if ( ! src ) {
+ t.resetImageData();
+ return false;
+ }
+
+ document.getElementById('status_img').innerHTML = '<img src="<?php echo esc_url( admin_url( 'images/wpspin_light.gif' ) ); ?>" alt="" width="16" />';
+ t.preloadImg = new Image();
+ t.preloadImg.onload = t.updateImageData;
+ t.preloadImg.onerror = t.resetImageData;
+ t.preloadImg.src = src;
+ }
+}
+
+jQuery(document).ready( function($) {
+ $('.media-types input').click( function() {
+ $('table.describe').toggleClass('not-image', $('#not-image').prop('checked') );
+ });
+});
+
+//]]>
+</script>
+
+<div id="media-items">
+<div class="media-item media-blank">
+<?php echo apply_filters( 'type_url_form_media', wp_media_insert_url_form( $type ) ); ?>
+</div>
+</div>
+</form>
+<?php
+}
+
+/**
+ * Adds gallery form to upload iframe
+ *
+ * @since 2.5.0
+ *
+ * @param array $errors
+ */
+function media_upload_gallery_form($errors) {
+ global $redir_tab, $type;
+
+ $redir_tab = 'gallery';
+ media_upload_header();
+
+ $post_id = intval($_REQUEST['post_id']);
+ $form_action_url = admin_url("media-upload.php?type=$type&tab=gallery&post_id=$post_id");
+ $form_action_url = apply_filters('media_upload_form_url', $form_action_url, $type);
+ $form_class = 'media-upload-form validate';
+
+ if ( get_user_setting('uploader') )
+ $form_class .= ' html-uploader';
+?>
+
+<script type="text/javascript">
+<!--
+jQuery(function($){
+ var preloaded = $(".media-item.preloaded");
+ if ( preloaded.length > 0 ) {
+ preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
+ updateMediaForm();
+ }
+});
+-->
+</script>
+<div id="sort-buttons" class="hide-if-no-js">
+<span>
+<?php _e('All Tabs:'); ?>
+<a href="#" id="showall"><?php _e('Show'); ?></a>
+<a href="#" id="hideall" style="display:none;"><?php _e('Hide'); ?></a>
+</span>
+<?php _e('Sort Order:'); ?>
+<a href="#" id="asc"><?php _e('Ascending'); ?></a> |
+<a href="#" id="desc"><?php _e('Descending'); ?></a> |
+<a href="#" id="clear"><?php _ex('Clear', 'verb'); ?></a>
+</div>
+<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="gallery-form">
+<?php wp_nonce_field('media-form'); ?>
+<?php //media_upload_form( $errors ); ?>
+<table class="widefat" cellspacing="0">
+<thead><tr>
+<th><?php _e('Media'); ?></th>
+<th class="order-head"><?php _e('Order'); ?></th>
+<th class="actions-head"><?php _e('Actions'); ?></th>
+</tr></thead>
+</table>
+<div id="media-items">
+<?php add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2); ?>
+<?php echo get_media_items($post_id, $errors); ?>
+</div>
+
+<p class="ml-submit">
+<?php submit_button( __( 'Save all changes' ), 'button savebutton', 'save', false, array( 'id' => 'save-all', 'style' => 'display: none;' ) ); ?>
+<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
+<input type="hidden" name="type" value="<?php echo esc_attr( $GLOBALS['type'] ); ?>" />
+<input type="hidden" name="tab" value="<?php echo esc_attr( $GLOBALS['tab'] ); ?>" />
+</p>
+
+<div id="gallery-settings" style="display:none;">
+<div class="title"><?php _e('Gallery Settings'); ?></div>
+<table id="basic" class="describe"><tbody>
+ <tr>
+ <th scope="row" class="label">
+ <label>
+ <span class="alignleft"><?php _e('Link thumbnails to:'); ?></span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="radio" name="linkto" id="linkto-file" value="file" />
+ <label for="linkto-file" class="radio"><?php _e('Image File'); ?></label>
+
+ <input type="radio" checked="checked" name="linkto" id="linkto-post" value="post" />
+ <label for="linkto-post" class="radio"><?php _e('Attachment Page'); ?></label>
+ </td>
+ </tr>
+
+ <tr>
+ <th scope="row" class="label">
+ <label>
+ <span class="alignleft"><?php _e('Order images by:'); ?></span>
+ </label>
+ </th>
+ <td class="field">
+ <select id="orderby" name="orderby">
+ <option value="menu_order" selected="selected"><?php _e('Menu order'); ?></option>
+ <option value="title"><?php _e('Title'); ?></option>
+ <option value="post_date"><?php _e('Date/Time'); ?></option>
+ <option value="rand"><?php _e('Random'); ?></option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <th scope="row" class="label">
+ <label>
+ <span class="alignleft"><?php _e('Order:'); ?></span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="radio" checked="checked" name="order" id="order-asc" value="asc" />
+ <label for="order-asc" class="radio"><?php _e('Ascending'); ?></label>
+
+ <input type="radio" name="order" id="order-desc" value="desc" />
+ <label for="order-desc" class="radio"><?php _e('Descending'); ?></label>
+ </td>
+ </tr>
+
+ <tr>
+ <th scope="row" class="label">
+ <label>
+ <span class="alignleft"><?php _e('Gallery columns:'); ?></span>
+ </label>
+ </th>
+ <td class="field">
+ <select id="columns" name="columns">
+ <option value="1">1</option>
+ <option value="2">2</option>
+ <option value="3" selected="selected">3</option>
+ <option value="4">4</option>
+ <option value="5">5</option>
+ <option value="6">6</option>
+ <option value="7">7</option>
+ <option value="8">8</option>
+ <option value="9">9</option>
+ </select>
+ </td>
+ </tr>
+</tbody></table>
+
+<p class="ml-submit">
+<input type="button" class="button" style="display:none;" onMouseDown="wpgallery.update();" name="insert-gallery" id="insert-gallery" value="<?php esc_attr_e( 'Insert gallery' ); ?>" />
+<input type="button" class="button" style="display:none;" onMouseDown="wpgallery.update();" name="update-gallery" id="update-gallery" value="<?php esc_attr_e( 'Update gallery settings' ); ?>" />
+</p>
+</div>
+</form>
+<?php
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param array $errors
+ */
+function media_upload_library_form($errors) {
+ global $wpdb, $wp_query, $wp_locale, $type, $tab, $post_mime_types;
+
+ media_upload_header();
+
+ $post_id = isset( $_REQUEST['post_id'] ) ? intval( $_REQUEST['post_id'] ) : 0;
+
+ $form_action_url = admin_url("media-upload.php?type=$type&tab=library&post_id=$post_id");
+ $form_action_url = apply_filters('media_upload_form_url', $form_action_url, $type);
+ $form_class = 'media-upload-form validate';
+
+ if ( get_user_setting('uploader') )
+ $form_class .= ' html-uploader';
+
+ $_GET['paged'] = isset( $_GET['paged'] ) ? intval($_GET['paged']) : 0;
+ if ( $_GET['paged'] < 1 )
+ $_GET['paged'] = 1;
+ $start = ( $_GET['paged'] - 1 ) * 10;
+ if ( $start < 1 )
+ $start = 0;
+ add_filter( 'post_limits', create_function( '$a', "return 'LIMIT $start, 10';" ) );
+
+ list($post_mime_types, $avail_post_mime_types) = wp_edit_attachments_query();
+
+?>
+
+<form id="filter" action="" method="get">
+<input type="hidden" name="type" value="<?php echo esc_attr( $type ); ?>" />
+<input type="hidden" name="tab" value="<?php echo esc_attr( $tab ); ?>" />
+<input type="hidden" name="post_id" value="<?php echo (int) $post_id; ?>" />
+<input type="hidden" name="post_mime_type" value="<?php echo isset( $_GET['post_mime_type'] ) ? esc_attr( $_GET['post_mime_type'] ) : ''; ?>" />
+<input type="hidden" name="context" value="<?php echo isset( $_GET['context'] ) ? esc_attr( $_GET['context'] ) : ''; ?>" />
+
+<p id="media-search" class="search-box">
+ <label class="screen-reader-text" for="media-search-input"><?php _e('Search Media');?>:</label>
+ <input type="search" id="media-search-input" name="s" value="<?php the_search_query(); ?>" />
+ <?php submit_button( __( 'Search Media' ), 'button', '', false ); ?>
+</p>
+
+<ul class="subsubsub">
+<?php
+$type_links = array();
+$_num_posts = (array) wp_count_attachments();
+$matches = wp_match_mime_types(array_keys($post_mime_types), array_keys($_num_posts));
+foreach ( $matches as $_type => $reals )
+ foreach ( $reals as $real )
+ if ( isset($num_posts[$_type]) )
+ $num_posts[$_type] += $_num_posts[$real];
+ else
+ $num_posts[$_type] = $_num_posts[$real];
+// If available type specified by media button clicked, filter by that type
+if ( empty($_GET['post_mime_type']) && !empty($num_posts[$type]) ) {
+ $_GET['post_mime_type'] = $type;
+ list($post_mime_types, $avail_post_mime_types) = wp_edit_attachments_query();
+}
+if ( empty($_GET['post_mime_type']) || $_GET['post_mime_type'] == 'all' )
+ $class = ' class="current"';
+else
+ $class = '';
+$type_links[] = "<li><a href='" . esc_url(add_query_arg(array('post_mime_type'=>'all', 'paged'=>false, 'm'=>false))) . "'$class>".__('All Types')."</a>";
+foreach ( $post_mime_types as $mime_type => $label ) {
+ $class = '';
+
+ if ( !wp_match_mime_types($mime_type, $avail_post_mime_types) )
+ continue;
+
+ if ( isset($_GET['post_mime_type']) && wp_match_mime_types($mime_type, $_GET['post_mime_type']) )
+ $class = ' class="current"';
+
+ $type_links[] = "<li><a href='" . esc_url(add_query_arg(array('post_mime_type'=>$mime_type, 'paged'=>false))) . "'$class>" . sprintf( translate_nooped_plural( $label[2], $num_posts[$mime_type] ), "<span id='$mime_type-counter'>" . number_format_i18n( $num_posts[$mime_type] ) . '</span>') . '</a>';
+}
+echo implode(' | </li>', apply_filters( 'media_upload_mime_type_links', $type_links ) ) . '</li>';
+unset($type_links);
+?>
+</ul>
+
+<div class="tablenav">
+
+<?php
+$page_links = paginate_links( array(
+ 'base' => add_query_arg( 'paged', '%#%' ),
+ 'format' => '',
+ 'prev_text' => __('&laquo;'),
+ 'next_text' => __('&raquo;'),
+ 'total' => ceil($wp_query->found_posts / 10),
+ 'current' => $_GET['paged']
+));
+
+if ( $page_links )
+ echo "<div class='tablenav-pages'>$page_links</div>";
+?>
+
+<div class="alignleft actions">
+<?php
+
+$arc_query = "SELECT DISTINCT YEAR(post_date) AS yyear, MONTH(post_date) AS mmonth FROM $wpdb->posts WHERE post_type = 'attachment' ORDER BY post_date DESC";
+
+$arc_result = $wpdb->get_results( $arc_query );
+
+$month_count = count($arc_result);
+
+if ( $month_count && !( 1 == $month_count && 0 == $arc_result[0]->mmonth ) ) { ?>
+<select name='m'>
+<option<?php selected( @$_GET['m'], 0 ); ?> value='0'><?php _e('Show all dates'); ?></option>
+<?php
+foreach ($arc_result as $arc_row) {
+ if ( $arc_row->yyear == 0 )
+ continue;
+ $arc_row->mmonth = zeroise( $arc_row->mmonth, 2 );
+
+ if ( isset($_GET['m']) && ( $arc_row->yyear . $arc_row->mmonth == $_GET['m'] ) )
+ $default = ' selected="selected"';
+ else
+ $default = '';
+
+ echo "<option$default value='" . esc_attr( $arc_row->yyear . $arc_row->mmonth ) . "'>";
+ echo esc_html( $wp_locale->get_month($arc_row->mmonth) . " $arc_row->yyear" );
+ echo "</option>\n";
+}
+?>
+</select>
+<?php } ?>
+
+<?php submit_button( __( 'Filter &#187;' ), 'button', 'post-query-submit', false ); ?>
+
+</div>
+
+<br class="clear" />
+</div>
+</form>
+
+<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( $form_action_url ); ?>" class="<?php echo $form_class; ?>" id="library-form">
+
+<?php wp_nonce_field('media-form'); ?>
+<?php //media_upload_form( $errors ); ?>
+
+<script type="text/javascript">
+<!--
+jQuery(function($){
+ var preloaded = $(".media-item.preloaded");
+ if ( preloaded.length > 0 ) {
+ preloaded.each(function(){prepareMediaItem({id:this.id.replace(/[^0-9]/g, '')},'');});
+ updateMediaForm();
+ }
+});
+-->
+</script>
+
+<div id="media-items">
+<?php add_filter('attachment_fields_to_edit', 'media_post_single_attachment_fields_to_edit', 10, 2); ?>
+<?php echo get_media_items(null, $errors); ?>
+</div>
+<p class="ml-submit">
+<?php submit_button( __( 'Save all changes' ), 'button savebutton', 'save', false ); ?>
+<input type="hidden" name="post_id" id="post_id" value="<?php echo (int) $post_id; ?>" />
+</p>
+</form>
+<?php
+}
+
+/**
+ * Creates the form for external url
+ *
+ * @since 2.7.0
+ *
+ * @param string $default_view
+ * @return string the form html
+ */
+function wp_media_insert_url_form( $default_view = 'image' ) {
+ if ( !apply_filters( 'disable_captions', '' ) ) {
+ $caption = '
+ <tr class="image-only">
+ <th valign="top" scope="row" class="label">
+ <label for="caption"><span class="alignleft">' . __('Image Caption') . '</span></label>
+ </th>
+ <td class="field"><textarea id="caption" name="caption"></textarea></td>
+ </tr>
+';
+ } else {
+ $caption = '';
+ }
+
+ $default_align = get_option('image_default_align');
+ if ( empty($default_align) )
+ $default_align = 'none';
+
+ if ( 'image' == $default_view ) {
+ $view = 'image-only';
+ $table_class = '';
+ } else {
+ $view = $table_class = 'not-image';
+ }
+
+ return '
+ <p class="media-types"><label><input type="radio" name="media_type" value="image" id="image-only"' . checked( 'image-only', $view, false ) . ' /> ' . __( 'Image' ) . '</label> &nbsp; &nbsp; <label><input type="radio" name="media_type" value="generic" id="not-image"' . checked( 'not-image', $view, false ) . ' /> ' . __( 'Audio, Video, or Other File' ) . '</label></p>
+ <table class="describe ' . $table_class . '"><tbody>
+ <tr>
+ <th valign="top" scope="row" class="label" style="width:130px;">
+ <label for="src"><span class="alignleft">' . __('URL') . '</span></label>
+ <span class="alignright"><abbr id="status_img" title="required" class="required">*</abbr></span>
+ </th>
+ <td class="field"><input id="src" name="src" value="" type="text" aria-required="true" onblur="addExtImage.getImageData()" /></td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="title"><span class="alignleft">' . __('Title') . '</span></label>
+ <span class="alignright"><abbr title="required" class="required">*</abbr></span>
+ </th>
+ <td class="field"><input id="title" name="title" value="" type="text" aria-required="true" /></td>
+ </tr>
+
+ <tr class="not-image"><td></td><td><p class="help">' . __('Link text, e.g. &#8220;Ransom Demands (PDF)&#8221;') . '</p></td></tr>
+
+ <tr class="image-only">
+ <th valign="top" scope="row" class="label">
+ <label for="alt"><span class="alignleft">' . __('Alternative Text') . '</span></label>
+ </th>
+ <td class="field"><input id="alt" name="alt" value="" type="text" aria-required="true" />
+ <p class="help">' . __('Alt text for the image, e.g. &#8220;The Mona Lisa&#8221;') . '</p></td>
+ </tr>
+ ' . $caption . '
+ <tr class="align image-only">
+ <th valign="top" scope="row" class="label"><p><label for="align">' . __('Alignment') . '</label></p></th>
+ <td class="field">
+ <input name="align" id="align-none" value="none" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'none' ? ' checked="checked"' : '').' />
+ <label for="align-none" class="align image-align-none-label">' . __('None') . '</label>
+ <input name="align" id="align-left" value="left" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'left' ? ' checked="checked"' : '').' />
+ <label for="align-left" class="align image-align-left-label">' . __('Left') . '</label>
+ <input name="align" id="align-center" value="center" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'center' ? ' checked="checked"' : '').' />
+ <label for="align-center" class="align image-align-center-label">' . __('Center') . '</label>
+ <input name="align" id="align-right" value="right" onclick="addExtImage.align=\'align\'+this.value" type="radio"' . ($default_align == 'right' ? ' checked="checked"' : '').' />
+ <label for="align-right" class="align image-align-right-label">' . __('Right') . '</label>
+ </td>
+ </tr>
+
+ <tr class="image-only">
+ <th valign="top" scope="row" class="label">
+ <label for="url"><span class="alignleft">' . __('Link Image To:') . '</span></label>
+ </th>
+ <td class="field"><input id="url" name="url" value="" type="text" /><br />
+
+ <button type="button" class="button" value="" onclick="document.forms[0].url.value=null">' . __('None') . '</button>
+ <button type="button" class="button" value="" onclick="document.forms[0].url.value=document.forms[0].src.value">' . __('Link to image') . '</button>
+ <p class="help">' . __('Enter a link URL or click above for presets.') . '</p></td>
+ </tr>
+ <tr class="image-only">
+ <td></td>
+ <td>
+ <input type="button" class="button" id="go_button" style="color:#bbb;" onclick="addExtImage.insert()" value="' . esc_attr__('Insert into Post') . '" />
+ </td>
+ </tr>
+ <tr class="not-image">
+ <td></td>
+ <td>
+ ' . get_submit_button( __( 'Insert into Post' ), 'button', 'insertonlybutton', false ) . '
+ </td>
+ </tr>
+ </tbody></table>
+';
+
+}
+
+/**
+ * Displays the multi-file uploader message.
+ *
+ * @since 2.6.0
+ */
+function media_upload_flash_bypass() {
+ $browser_uploader = admin_url( 'media-new.php?browser-uploader' );
+
+ if ( $post = get_post() )
+ $browser_uploader .= '&amp;post_id=' . intval( $post->ID );
+ elseif ( ! empty( $GLOBALS['post_ID'] ) )
+ $browser_uploader .= '&amp;post_id=' . intval( $GLOBALS['post_ID'] );
+
+ ?>
+ <p class="upload-flash-bypass">
+ <?php printf( __( 'You are using the multi-file uploader. Problems? Try the <a href="%1$s" target="%2$s">browser uploader</a> instead.' ), $browser_uploader, '_blank' ); ?>
+ </p>
+ <?php
+}
+add_action('post-plupload-upload-ui', 'media_upload_flash_bypass');
+
+/**
+ * Displays the browser's built-in uploader message.
+ *
+ * @since 2.6.0
+ */
+function media_upload_html_bypass() {
+ ?>
+ <p class="upload-html-bypass hide-if-no-js">
+ <?php _e('You are using the browser&#8217;s built-in file uploader. The WordPress uploader includes multiple file selection and drag and drop capability. <a href="#">Switch to the multi-file uploader</a>.'); ?>
+ </p>
+ <?php
+}
+add_action('post-html-upload-ui', 'media_upload_html_bypass');
+
+/**
+ * Used to display a "After a file has been uploaded..." help message.
+ *
+ * @since 3.3.0
+ */
+function media_upload_text_after() {}
+
+/**
+ * Displays the checkbox to scale images.
+ *
+ * @since 3.3.0
+ */
+function media_upload_max_image_resize() {
+ $checked = get_user_setting('upload_resize') ? ' checked="true"' : '';
+ $a = $end = '';
+
+ if ( current_user_can( 'manage_options' ) ) {
+ $a = '<a href="' . esc_url( admin_url( 'options-media.php' ) ) . '" target="_blank">';
+ $end = '</a>';
+ }
+?>
+<p class="hide-if-no-js"><label>
+<input name="image_resize" type="checkbox" id="image_resize" value="true"<?php echo $checked; ?> />
+<?php
+ /* translators: %1$s is link start tag, %2$s is link end tag, %3$d is width, %4$d is height*/
+ printf( __( 'Scale images to match the large size selected in %1$simage options%2$s (%3$d &times; %4$d).' ), $a, $end, (int) get_option( 'large_size_w', '1024' ), (int) get_option( 'large_size_h', '1024' ) );
+?>
+</label></p>
+<?php
+}
+
+/**
+ * Displays the out of storage quota message in Multisite.
+ *
+ * @since 3.5.0
+ */
+function multisite_over_quota_message() {
+ echo '<p>' . sprintf( __( 'Sorry, you have used all of your storage quota of %s MB.' ), get_space_allowed() ) . '</p>';
+}
+
+/**
+ * Displays the image and editor in the post editor
+ *
+ * @since 3.5.0
+ */
+function edit_form_image_editor( $post ) {
+ $open = isset( $_GET['image-editor'] );
+ if ( $open )
+ require_once ABSPATH . 'wp-admin/includes/image-edit.php';
+
+ $thumb_url = false;
+ if ( $attachment_id = intval( $post->ID ) )
+ $thumb_url = wp_get_attachment_image_src( $attachment_id, array( 900, 450 ), true );
+
+ $filename = esc_html( basename( $post->guid ) );
+ $title = esc_attr( $post->post_title );
+ $alt_text = get_post_meta( $post->ID, '_wp_attachment_image_alt', true );
+
+ $att_url = wp_get_attachment_url( $post->ID ); ?>
+ <div class="wp_attachment_holder">
+ <?php
+ if ( wp_attachment_is_image( $post->ID ) ) :
+ $image_edit_button = '';
+ if ( wp_image_editor_supports( array( 'mime_type' => $post->post_mime_type ) ) ) {
+ $nonce = wp_create_nonce( "image_editor-$post->ID" );
+ $image_edit_button = "<input type='button' id='imgedit-open-btn-$post->ID' onclick='imageEdit.open( $post->ID, \"$nonce\" )' class='button' value='" . esc_attr__( 'Edit Image' ) . "' /> <span class='spinner'></span>";
+ }
+ ?>
+
+ <div class="imgedit-response" id="imgedit-response-<?php echo $attachment_id; ?>"></div>
+
+ <div<?php if ( $open ) echo ' style="display:none"'; ?> class="wp_attachment_image" id="media-head-<?php echo $attachment_id; ?>">
+ <p id="thumbnail-head-<?php echo $attachment_id; ?>"><img class="thumbnail" src="<?php echo set_url_scheme( $thumb_url[0] ); ?>" style="max-width:100%" alt="" /></p>
+ <p><?php echo $image_edit_button; ?></p>
+ </div>
+ <div<?php if ( ! $open ) echo ' style="display:none"'; ?> class="image-editor" id="image-editor-<?php echo $attachment_id; ?>">
+ <?php if ( $open ) wp_image_editor( $attachment_id ); ?>
+ </div>
+ <?php
+ elseif ( $attachment_id && 0 === strpos( $post->post_mime_type, 'audio/' ) ):
+
+ echo wp_audio_shortcode( array( 'src' => $att_url ) );
+
+ elseif ( $attachment_id && 0 === strpos( $post->post_mime_type, 'video/' ) ):
+
+ $meta = wp_get_attachment_metadata( $attachment_id );
+ $w = ! empty( $meta['width'] ) ? min( $meta['width'], 600 ) : 0;
+ $h = 0;
+ if ( ! empty( $meta['height'] ) )
+ $h = $meta['height'];
+ if ( $h && $w < $meta['width'] )
+ $h = round( ( $meta['height'] * $w ) / $meta['width'] );
+
+ $attr = array( 'src' => $att_url );
+
+ if ( ! empty( $meta['width' ] ) )
+ $attr['width'] = $w;
+
+ if ( ! empty( $meta['height'] ) )
+ $attr['height'] = $h;
+
+ echo wp_video_shortcode( $attr );
+
+ endif; ?>
+ </div>
+ <div class="wp_attachment_details edit-form-section">
+ <p>
+ <label for="attachment_caption"><strong><?php _e( 'Caption' ); ?></strong></label><br />
+ <textarea class="widefat" name="excerpt" id="attachment_caption"><?php echo $post->post_excerpt; ?></textarea>
+ </p>
+
+ <?php if ( 'image' === substr( $post->post_mime_type, 0, 5 ) ) : ?>
+ <p>
+ <label for="attachment_alt"><strong><?php _e( 'Alternative Text' ); ?></strong></label><br />
+ <input type="text" class="widefat" name="_wp_attachment_image_alt" id="attachment_alt" value="<?php echo esc_attr( $alt_text ); ?>" />
+ </p>
+ <?php endif; ?>
+
+ <?php
+ $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
+ $editor_args = array(
+ 'textarea_name' => 'content',
+ 'textarea_rows' => 5,
+ 'media_buttons' => false,
+ 'tinymce' => false,
+ 'quicktags' => $quicktags_settings,
+ );
+ ?>
+
+ <label for="content"><strong><?php _e( 'Description' ); ?></strong></label>
+ <?php wp_editor( $post->post_content, 'attachment_content', $editor_args ); ?>
+
+ </div>
+ <?php
+ $extras = get_compat_media_markup( $post->ID );
+ echo $extras['item'];
+ echo '<input type="hidden" id="image-edit-context" value="edit-attachment" />' . "\n";
+}
+
+/**
+ * Displays non-editable attachment metadata in the publish metabox
+ *
+ * @since 3.5.0
+ */
+function attachment_submitbox_metadata() {
+ $post = get_post();
+
+ $filename = esc_html( wp_basename( $post->guid ) );
+
+ $media_dims = '';
+ $meta = wp_get_attachment_metadata( $post->ID );
+ if ( isset( $meta['width'], $meta['height'] ) )
+ $media_dims .= "<span id='media-dims-$post->ID'>{$meta['width']}&nbsp;&times;&nbsp;{$meta['height']}</span> ";
+ $media_dims = apply_filters( 'media_meta', $media_dims, $post );
+
+ $att_url = wp_get_attachment_url( $post->ID );
+?>
+ <div class="misc-pub-section">
+ <label for="attachment_url"><?php _e( 'File URL:' ); ?></label>
+ <input type="text" class="widefat urlfield" readonly="readonly" name="attachment_url" value="<?php echo esc_attr($att_url); ?>" />
+ </div>
+ <div class="misc-pub-section">
+ <?php _e( 'File name:' ); ?> <strong><?php echo $filename; ?></strong>
+ </div>
+ <div class="misc-pub-section">
+ <?php _e( 'File type:' ); ?> <strong><?php
+ if ( preg_match( '/^.*?\.(\w+)$/', get_attached_file( $post->ID ), $matches ) )
+ echo esc_html( strtoupper( $matches[1] ) );
+ else
+ echo strtoupper( str_replace( 'image/', '', $post->post_mime_type ) );
+ ?></strong>
+ </div>
+
+<?php
+ if ( preg_match( '#^audio|video#', $post->post_mime_type ) ):
+
+ $fields = array(
+ 'mime_type' => __( 'Mime-type:' ),
+ 'year' => __( 'Year:' ),
+ 'genre' => __( 'Genre:' ),
+ 'length_formatted' => __( 'Length:' ),
+ );
+
+ foreach ( $fields as $key => $label ):
+ if ( ! empty( $meta[$key] ) ) : ?>
+ <div class="misc-pub-section">
+ <?php echo $label ?> <strong><?php echo esc_html( $meta[$key] ); ?></strong>
+ </div>
+ <?php
+ endif;
+ endforeach;
+
+ if ( ! empty( $meta['bitrate'] ) ) : ?>
+ <div class="misc-pub-section">
+ <?php _e( 'Bitrate:' ); ?> <strong><?php
+ echo round( $meta['bitrate'] / 1000 ), 'kb/s';
+
+ if ( ! empty( $meta['bitrate_mode'] ) )
+ echo ' ', strtoupper( $meta['bitrate_mode'] );
+
+ ?></strong>
+ </div>
+ <?php
+ endif;
+
+ $audio_fields = array(
+ 'dataformat' => __( 'Audio Format:' ),
+ 'codec' => __( 'Audio Codec:' )
+ );
+
+ foreach ( $audio_fields as $key => $label ):
+ if ( ! empty( $meta['audio'][$key] ) ) : ?>
+ <div class="misc-pub-section">
+ <?php echo $label; ?> <strong><?php echo esc_html( $meta['audio'][$key] ); ?></strong>
+ </div>
+ <?php
+ endif;
+ endforeach;
+
+ endif;
+
+ if ( $media_dims ) : ?>
+ <div class="misc-pub-section">
+ <?php _e( 'Dimensions:' ); ?> <strong><?php echo $media_dims; ?></strong>
+ </div>
+<?php
+ endif;
+}
+
+add_filter( 'async_upload_image', 'get_media_item', 10, 2 );
+add_filter( 'async_upload_audio', 'get_media_item', 10, 2 );
+add_filter( 'async_upload_video', 'get_media_item', 10, 2 );
+add_filter( 'async_upload_file', 'get_media_item', 10, 2 );
+
+add_action( 'media_upload_image', 'wp_media_upload_handler' );
+add_action( 'media_upload_audio', 'wp_media_upload_handler' );
+add_action( 'media_upload_video', 'wp_media_upload_handler' );
+add_action( 'media_upload_file', 'wp_media_upload_handler' );
+
+add_filter( 'media_upload_gallery', 'media_upload_gallery' );
+add_filter( 'media_upload_library', 'media_upload_library' );
+
+add_action( 'attachment_submitbox_misc_actions', 'attachment_submitbox_metadata' );
+
+/**
+ * Parse ID3v2, ID3v1, and getID3 comments to extract usable data
+ *
+ * @since 3.6.0
+ *
+ * @param array $metadata An existing array with data
+ * @param array $data Data supplied by ID3 tags
+ */
+function wp_add_id3_tag_data( &$metadata, $data ) {
+ foreach ( array( 'id3v2', 'id3v1' ) as $version ) {
+ if ( ! empty( $data[$version]['comments'] ) ) {
+ foreach ( $data[$version]['comments'] as $key => $list ) {
+ if ( ! empty( $list ) ) {
+ $metadata[$key] = reset( $list );
+ // fix bug in byte stream analysis
+ if ( 'terms_of_use' === $key && 0 === strpos( $metadata[$key], 'yright notice.' ) )
+ $metadata[$key] = 'Cop' . $metadata[$key];
+ }
+ }
+ break;
+ }
+ }
+
+ if ( ! empty( $data['id3v2']['APIC'] ) ) {
+ $image = reset( $data['id3v2']['APIC']);
+ if ( ! empty( $image['data'] ) ) {
+ $metadata['image'] = array(
+ 'data' => $image['data'],
+ 'mime' => $image['image_mime'],
+ 'width' => $image['image_width'],
+ 'height' => $image['image_height']
+ );
+ }
+ } elseif ( ! empty( $data['comments']['picture'] ) ) {
+ $image = reset( $data['comments']['picture'] );
+ if ( ! empty( $image['data'] ) ) {
+ $metadata['image'] = array(
+ 'data' => $image['data'],
+ 'mime' => $image['image_mime']
+ );
+ }
+ }
+}
+
+/**
+ * Retrieve metadata from a video file's ID3 tags
+ *
+ * @since 3.6.0
+ *
+ * @param string $file Path to file.
+ * @return array|boolean Returns array of metadata, if found.
+ */
+function wp_read_video_metadata( $file ) {
+ if ( ! file_exists( $file ) )
+ return false;
+
+ $metadata = array();
+
+ if ( ! class_exists( 'getID3' ) )
+ require( ABSPATH . WPINC . '/ID3/getid3.php' );
+ $id3 = new getID3();
+ $data = $id3->analyze( $file );
+
+ if ( isset( $data['video']['lossless'] ) )
+ $metadata['lossless'] = $data['video']['lossless'];
+ if ( ! empty( $data['video']['bitrate'] ) )
+ $metadata['bitrate'] = (int) $data['video']['bitrate'];
+ if ( ! empty( $data['video']['bitrate_mode'] ) )
+ $metadata['bitrate_mode'] = $data['video']['bitrate_mode'];
+ if ( ! empty( $data['filesize'] ) )
+ $metadata['filesize'] = (int) $data['filesize'];
+ if ( ! empty( $data['mime_type'] ) )
+ $metadata['mime_type'] = $data['mime_type'];
+ if ( ! empty( $data['playtime_seconds'] ) )
+ $metadata['length'] = (int) ceil( $data['playtime_seconds'] );
+ if ( ! empty( $data['playtime_string'] ) )
+ $metadata['length_formatted'] = $data['playtime_string'];
+ if ( ! empty( $data['video']['resolution_x'] ) )
+ $metadata['width'] = (int) $data['video']['resolution_x'];
+ if ( ! empty( $data['video']['resolution_y'] ) )
+ $metadata['height'] = (int) $data['video']['resolution_y'];
+ if ( ! empty( $data['fileformat'] ) )
+ $metadata['fileformat'] = $data['fileformat'];
+ if ( ! empty( $data['video']['dataformat'] ) )
+ $metadata['dataformat'] = $data['video']['dataformat'];
+ if ( ! empty( $data['video']['encoder'] ) )
+ $metadata['encoder'] = $data['video']['encoder'];
+ if ( ! empty( $data['video']['codec'] ) )
+ $metadata['codec'] = $data['video']['codec'];
+
+ if ( ! empty( $data['audio'] ) ) {
+ unset( $data['audio']['streams'] );
+ $metadata['audio'] = $data['audio'];
+ }
+
+ wp_add_id3_tag_data( $metadata, $data );
+
+ return $metadata;
+}
+
+/**
+ * Retrieve metadata from a audio file's ID3 tags
+ *
+ * @since 3.6.0
+ *
+ * @param string $file Path to file.
+ * @return array|boolean Returns array of metadata, if found.
+ */
+function wp_read_audio_metadata( $file ) {
+ if ( ! file_exists( $file ) )
+ return false;
+ $metadata = array();
+
+ if ( ! class_exists( 'getID3' ) )
+ require( ABSPATH . WPINC . '/ID3/getid3.php' );
+ $id3 = new getID3();
+ $data = $id3->analyze( $file );
+
+ if ( ! empty( $data['audio'] ) ) {
+ unset( $data['audio']['streams'] );
+ $metadata = $data['audio'];
+ }
+
+ if ( ! empty( $data['fileformat'] ) )
+ $metadata['fileformat'] = $data['fileformat'];
+ if ( ! empty( $data['filesize'] ) )
+ $metadata['filesize'] = (int) $data['filesize'];
+ if ( ! empty( $data['mime_type'] ) )
+ $metadata['mime_type'] = $data['mime_type'];
+ if ( ! empty( $data['playtime_seconds'] ) )
+ $metadata['length'] = (int) ceil( $data['playtime_seconds'] );
+ if ( ! empty( $data['playtime_string'] ) )
+ $metadata['length_formatted'] = $data['playtime_string'];
+
+ wp_add_id3_tag_data( $metadata, $data );
+
+ return $metadata;
+}
diff --git a/src/wp-admin/includes/menu.php b/src/wp-admin/includes/menu.php
new file mode 100644
index 0000000000..e315c7666b
--- /dev/null
+++ b/src/wp-admin/includes/menu.php
@@ -0,0 +1,229 @@
+<?php
+
+/**
+ * Build Administration Menu.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+if ( is_network_admin() )
+ do_action('_network_admin_menu');
+elseif ( is_user_admin() )
+ do_action('_user_admin_menu');
+else
+ do_action('_admin_menu');
+
+// Create list of page plugin hook names.
+foreach ($menu as $menu_page) {
+ if ( false !== $pos = strpos($menu_page[2], '?') ) {
+ // Handle post_type=post|page|foo pages.
+ $hook_name = substr($menu_page[2], 0, $pos);
+ $hook_args = substr($menu_page[2], $pos + 1);
+ wp_parse_str($hook_args, $hook_args);
+ // Set the hook name to be the post type.
+ if ( isset($hook_args['post_type']) )
+ $hook_name = $hook_args['post_type'];
+ else
+ $hook_name = basename($hook_name, '.php');
+ unset($hook_args);
+ } else {
+ $hook_name = basename($menu_page[2], '.php');
+ }
+ $hook_name = sanitize_title($hook_name);
+
+ if ( isset($compat[$hook_name]) )
+ $hook_name = $compat[$hook_name];
+ elseif ( !$hook_name )
+ continue;
+
+ $admin_page_hooks[$menu_page[2]] = $hook_name;
+}
+unset($menu_page, $compat);
+
+$_wp_submenu_nopriv = array();
+$_wp_menu_nopriv = array();
+// Loop over submenus and remove pages for which the user does not have privs.
+foreach ( array( 'submenu' ) as $sub_loop ) {
+ foreach ($$sub_loop as $parent => $sub) {
+ foreach ($sub as $index => $data) {
+ if ( ! current_user_can($data[1]) ) {
+ unset(${$sub_loop}[$parent][$index]);
+ $_wp_submenu_nopriv[$parent][$data[2]] = true;
+ }
+ }
+ unset($index, $data);
+
+ if ( empty(${$sub_loop}[$parent]) )
+ unset(${$sub_loop}[$parent]);
+ }
+ unset($sub, $parent);
+}
+unset($sub_loop);
+
+// Loop over the top-level menu.
+// Menus for which the original parent is not accessible due to lack of privs will have the next
+// submenu in line be assigned as the new menu parent.
+foreach ( $menu as $id => $data ) {
+ if ( empty($submenu[$data[2]]) )
+ continue;
+ $subs = $submenu[$data[2]];
+ $first_sub = array_shift($subs);
+ $old_parent = $data[2];
+ $new_parent = $first_sub[2];
+ // If the first submenu is not the same as the assigned parent,
+ // make the first submenu the new parent.
+ if ( $new_parent != $old_parent ) {
+ $_wp_real_parent_file[$old_parent] = $new_parent;
+ $menu[$id][2] = $new_parent;
+
+ foreach ($submenu[$old_parent] as $index => $data) {
+ $submenu[$new_parent][$index] = $submenu[$old_parent][$index];
+ unset($submenu[$old_parent][$index]);
+ }
+ unset($submenu[$old_parent], $index);
+
+ if ( isset($_wp_submenu_nopriv[$old_parent]) )
+ $_wp_submenu_nopriv[$new_parent] = $_wp_submenu_nopriv[$old_parent];
+ }
+}
+unset($id, $data, $subs, $first_sub, $old_parent, $new_parent);
+
+if ( is_network_admin() )
+ do_action('network_admin_menu', '');
+elseif ( is_user_admin() )
+ do_action('user_admin_menu', '');
+else
+ do_action('admin_menu', '');
+
+// Remove menus that have no accessible submenus and require privs that the user does not have.
+// Run re-parent loop again.
+foreach ( $menu as $id => $data ) {
+ if ( ! current_user_can($data[1]) )
+ $_wp_menu_nopriv[$data[2]] = true;
+
+ // If there is only one submenu and it is has same destination as the parent,
+ // remove the submenu.
+ if ( ! empty( $submenu[$data[2]] ) && 1 == count ( $submenu[$data[2]] ) ) {
+ $subs = $submenu[$data[2]];
+ $first_sub = array_shift($subs);
+ if ( $data[2] == $first_sub[2] )
+ unset( $submenu[$data[2]] );
+ }
+
+ // If submenu is empty...
+ if ( empty($submenu[$data[2]]) ) {
+ // And user doesn't have privs, remove menu.
+ if ( isset( $_wp_menu_nopriv[$data[2]] ) ) {
+ unset($menu[$id]);
+ }
+ }
+}
+unset($id, $data, $subs, $first_sub);
+
+// Remove any duplicated separators
+$separator_found = false;
+foreach ( $menu as $id => $data ) {
+ if ( 0 == strcmp('wp-menu-separator', $data[4] ) ) {
+ if (false == $separator_found) {
+ $separator_found = true;
+ } else {
+ unset($menu[$id]);
+ $separator_found = false;
+ }
+ } else {
+ $separator_found = false;
+ }
+}
+unset($id, $data);
+
+function add_cssclass($add, $class) {
+ $class = empty($class) ? $add : $class .= ' ' . $add;
+ return $class;
+}
+
+function add_menu_classes($menu) {
+
+ $first = $lastorder = false;
+ $i = 0;
+ $mc = count($menu);
+ foreach ( $menu as $order => $top ) {
+ $i++;
+
+ if ( 0 == $order ) { // dashboard is always shown/single
+ $menu[0][4] = add_cssclass('menu-top-first', $top[4]);
+ $lastorder = 0;
+ continue;
+ }
+
+ if ( 0 === strpos($top[2], 'separator') && false !== $lastorder ) { // if separator
+ $first = true;
+ $c = $menu[$lastorder][4];
+ $menu[$lastorder][4] = add_cssclass('menu-top-last', $c);
+ continue;
+ }
+
+ if ( $first ) {
+ $c = $menu[$order][4];
+ $menu[$order][4] = add_cssclass('menu-top-first', $c);
+ $first = false;
+ }
+
+ if ( $mc == $i ) { // last item
+ $c = $menu[$order][4];
+ $menu[$order][4] = add_cssclass('menu-top-last', $c);
+ }
+
+ $lastorder = $order;
+ }
+
+ return apply_filters( 'add_menu_classes', $menu );
+}
+
+uksort($menu, "strnatcasecmp"); // make it all pretty
+
+if ( apply_filters('custom_menu_order', false) ) {
+ $menu_order = array();
+ foreach ( $menu as $menu_item ) {
+ $menu_order[] = $menu_item[2];
+ }
+ unset($menu_item);
+ $default_menu_order = $menu_order;
+ $menu_order = apply_filters('menu_order', $menu_order);
+ $menu_order = array_flip($menu_order);
+ $default_menu_order = array_flip($default_menu_order);
+
+ function sort_menu($a, $b) {
+ global $menu_order, $default_menu_order;
+ $a = $a[2];
+ $b = $b[2];
+ if ( isset($menu_order[$a]) && !isset($menu_order[$b]) ) {
+ return -1;
+ } elseif ( !isset($menu_order[$a]) && isset($menu_order[$b]) ) {
+ return 1;
+ } elseif ( isset($menu_order[$a]) && isset($menu_order[$b]) ) {
+ if ( $menu_order[$a] == $menu_order[$b] )
+ return 0;
+ return ($menu_order[$a] < $menu_order[$b]) ? -1 : 1;
+ } else {
+ return ($default_menu_order[$a] <= $default_menu_order[$b]) ? -1 : 1;
+ }
+ }
+
+ usort($menu, 'sort_menu');
+ unset($menu_order, $default_menu_order);
+}
+
+// Remove the last menu item if it is a separator.
+$last_menu_key = array_keys( $menu );
+$last_menu_key = array_pop( $last_menu_key );
+if ( !empty( $menu ) && 'wp-menu-separator' == $menu[ $last_menu_key ][ 4 ] )
+ unset( $menu[ $last_menu_key ] );
+unset( $last_menu_key );
+
+if ( !user_can_access_admin_page() ) {
+ do_action('admin_page_access_denied');
+ wp_die( __('You do not have sufficient permissions to access this page.') );
+}
+
+$menu = add_menu_classes($menu);
diff --git a/src/wp-admin/includes/meta-boxes.php b/src/wp-admin/includes/meta-boxes.php
new file mode 100644
index 0000000000..cefa5a96ba
--- /dev/null
+++ b/src/wp-admin/includes/meta-boxes.php
@@ -0,0 +1,1000 @@
+<?php
+
+// -- Post related Meta Boxes
+
+/**
+ * Display post submit form fields.
+ *
+ * @since 2.7.0
+ *
+ * @param object $post
+ */
+function post_submit_meta_box($post, $args = array() ) {
+ global $action;
+
+ $post_type = $post->post_type;
+ $post_type_object = get_post_type_object($post_type);
+ $can_publish = current_user_can($post_type_object->cap->publish_posts);
+?>
+<div class="submitbox" id="submitpost">
+
+<div id="minor-publishing">
+
+<?php // Hidden submit button early on so that the browser chooses the right button when form is submitted with Return key ?>
+<div style="display:none;">
+<?php submit_button( __( 'Save' ), 'button', 'save' ); ?>
+</div>
+
+<div id="minor-publishing-actions">
+<div id="save-action">
+<?php if ( 'publish' != $post->post_status && 'future' != $post->post_status && 'pending' != $post->post_status ) { ?>
+<input <?php if ( 'private' == $post->post_status ) { ?>style="display:none"<?php } ?> type="submit" name="save" id="save-post" value="<?php esc_attr_e('Save Draft'); ?>" class="button" />
+<?php } elseif ( 'pending' == $post->post_status && $can_publish ) { ?>
+<input type="submit" name="save" id="save-post" value="<?php esc_attr_e('Save as Pending'); ?>" class="button" />
+<?php } ?>
+<span class="spinner"></span>
+</div>
+<?php if ( $post_type_object->public ) : ?>
+<div id="preview-action">
+<?php
+if ( 'publish' == $post->post_status ) {
+ $preview_link = esc_url( get_permalink( $post->ID ) );
+ $preview_button = __( 'Preview Changes' );
+} else {
+ $preview_link = set_url_scheme( get_permalink( $post->ID ) );
+ $preview_link = esc_url( apply_filters( 'preview_post_link', add_query_arg( 'preview', 'true', $preview_link ) ) );
+ $preview_button = __( 'Preview' );
+}
+?>
+<a class="preview button" href="<?php echo $preview_link; ?>" target="wp-preview" id="post-preview"><?php echo $preview_button; ?></a>
+<input type="hidden" name="wp-preview" id="wp-preview" value="" />
+</div>
+<?php endif; // public post type ?>
+<div class="clear"></div>
+</div><!-- #minor-publishing-actions -->
+
+<div id="misc-publishing-actions">
+
+<div class="misc-pub-section"><label for="post_status"><?php _e('Status:') ?></label>
+<span id="post-status-display">
+<?php
+switch ( $post->post_status ) {
+ case 'private':
+ _e('Privately Published');
+ break;
+ case 'publish':
+ _e('Published');
+ break;
+ case 'future':
+ _e('Scheduled');
+ break;
+ case 'pending':
+ _e('Pending Review');
+ break;
+ case 'draft':
+ case 'auto-draft':
+ _e('Draft');
+ break;
+}
+?>
+</span>
+<?php if ( 'publish' == $post->post_status || 'private' == $post->post_status || $can_publish ) { ?>
+<a href="#post_status" <?php if ( 'private' == $post->post_status ) { ?>style="display:none;" <?php } ?>class="edit-post-status hide-if-no-js"><?php _e('Edit') ?></a>
+
+<div id="post-status-select" class="hide-if-js">
+<input type="hidden" name="hidden_post_status" id="hidden_post_status" value="<?php echo esc_attr( ('auto-draft' == $post->post_status ) ? 'draft' : $post->post_status); ?>" />
+<select name='post_status' id='post_status'>
+<?php if ( 'publish' == $post->post_status ) : ?>
+<option<?php selected( $post->post_status, 'publish' ); ?> value='publish'><?php _e('Published') ?></option>
+<?php elseif ( 'private' == $post->post_status ) : ?>
+<option<?php selected( $post->post_status, 'private' ); ?> value='publish'><?php _e('Privately Published') ?></option>
+<?php elseif ( 'future' == $post->post_status ) : ?>
+<option<?php selected( $post->post_status, 'future' ); ?> value='future'><?php _e('Scheduled') ?></option>
+<?php endif; ?>
+<option<?php selected( $post->post_status, 'pending' ); ?> value='pending'><?php _e('Pending Review') ?></option>
+<?php if ( 'auto-draft' == $post->post_status ) : ?>
+<option<?php selected( $post->post_status, 'auto-draft' ); ?> value='draft'><?php _e('Draft') ?></option>
+<?php else : ?>
+<option<?php selected( $post->post_status, 'draft' ); ?> value='draft'><?php _e('Draft') ?></option>
+<?php endif; ?>
+</select>
+ <a href="#post_status" class="save-post-status hide-if-no-js button"><?php _e('OK'); ?></a>
+ <a href="#post_status" class="cancel-post-status hide-if-no-js"><?php _e('Cancel'); ?></a>
+</div>
+
+<?php } ?>
+</div><!-- .misc-pub-section -->
+
+<div class="misc-pub-section" id="visibility">
+<?php _e('Visibility:'); ?> <span id="post-visibility-display"><?php
+
+if ( 'private' == $post->post_status ) {
+ $post->post_password = '';
+ $visibility = 'private';
+ $visibility_trans = __('Private');
+} elseif ( !empty( $post->post_password ) ) {
+ $visibility = 'password';
+ $visibility_trans = __('Password protected');
+} elseif ( $post_type == 'post' && is_sticky( $post->ID ) ) {
+ $visibility = 'public';
+ $visibility_trans = __('Public, Sticky');
+} else {
+ $visibility = 'public';
+ $visibility_trans = __('Public');
+}
+
+echo esc_html( $visibility_trans ); ?></span>
+<?php if ( $can_publish ) { ?>
+<a href="#visibility" class="edit-visibility hide-if-no-js"><?php _e('Edit'); ?></a>
+
+<div id="post-visibility-select" class="hide-if-js">
+<input type="hidden" name="hidden_post_password" id="hidden-post-password" value="<?php echo esc_attr($post->post_password); ?>" />
+<?php if ($post_type == 'post'): ?>
+<input type="checkbox" style="display:none" name="hidden_post_sticky" id="hidden-post-sticky" value="sticky" <?php checked(is_sticky($post->ID)); ?> />
+<?php endif; ?>
+<input type="hidden" name="hidden_post_visibility" id="hidden-post-visibility" value="<?php echo esc_attr( $visibility ); ?>" />
+<input type="radio" name="visibility" id="visibility-radio-public" value="public" <?php checked( $visibility, 'public' ); ?> /> <label for="visibility-radio-public" class="selectit"><?php _e('Public'); ?></label><br />
+<?php if ( $post_type == 'post' && current_user_can( 'edit_others_posts' ) ) : ?>
+<span id="sticky-span"><input id="sticky" name="sticky" type="checkbox" value="sticky" <?php checked( is_sticky( $post->ID ) ); ?> /> <label for="sticky" class="selectit"><?php _e( 'Stick this post to the front page' ); ?></label><br /></span>
+<?php endif; ?>
+<input type="radio" name="visibility" id="visibility-radio-password" value="password" <?php checked( $visibility, 'password' ); ?> /> <label for="visibility-radio-password" class="selectit"><?php _e('Password protected'); ?></label><br />
+<span id="password-span"><label for="post_password"><?php _e('Password:'); ?></label> <input type="text" name="post_password" id="post_password" value="<?php echo esc_attr($post->post_password); ?>" /><br /></span>
+<input type="radio" name="visibility" id="visibility-radio-private" value="private" <?php checked( $visibility, 'private' ); ?> /> <label for="visibility-radio-private" class="selectit"><?php _e('Private'); ?></label><br />
+
+<p>
+ <a href="#visibility" class="save-post-visibility hide-if-no-js button"><?php _e('OK'); ?></a>
+ <a href="#visibility" class="cancel-post-visibility hide-if-no-js"><?php _e('Cancel'); ?></a>
+</p>
+</div>
+<?php } ?>
+
+</div><!-- .misc-pub-section -->
+
+<?php
+// translators: Publish box date format, see http://php.net/date
+$datef = __( 'M j, Y @ G:i' );
+if ( 0 != $post->ID ) {
+ if ( 'future' == $post->post_status ) { // scheduled for publishing at a future date
+ $stamp = __('Scheduled for: <b>%1$s</b>');
+ } else if ( 'publish' == $post->post_status || 'private' == $post->post_status ) { // already published
+ $stamp = __('Published on: <b>%1$s</b>');
+ } else if ( '0000-00-00 00:00:00' == $post->post_date_gmt ) { // draft, 1 or more saves, no date specified
+ $stamp = __('Publish <b>immediately</b>');
+ } else if ( time() < strtotime( $post->post_date_gmt . ' +0000' ) ) { // draft, 1 or more saves, future date specified
+ $stamp = __('Schedule for: <b>%1$s</b>');
+ } else { // draft, 1 or more saves, date specified
+ $stamp = __('Publish on: <b>%1$s</b>');
+ }
+ $date = date_i18n( $datef, strtotime( $post->post_date ) );
+} else { // draft (no saves, and thus no date specified)
+ $stamp = __('Publish <b>immediately</b>');
+ $date = date_i18n( $datef, strtotime( current_time('mysql') ) );
+}
+
+if ( ! empty( $args['args']['revisions_count'] ) ) :
+ $revisions_to_keep = wp_revisions_to_keep( $post );
+?>
+<div class="misc-pub-section num-revisions">
+<?php
+ if ( $revisions_to_keep > 0 && $revisions_to_keep <= $args['args']['revisions_count'] ) {
+ echo '<span title="' . esc_attr( sprintf( __( 'Your site is configured to keep only the last %s revisions.' ),
+ number_format_i18n( $revisions_to_keep ) ) ) . '">';
+ printf( __( 'Revisions: %s' ), '<b>' . number_format_i18n( $args['args']['revisions_count'] ) . '+</b>' );
+ echo '</span>';
+ } else {
+ printf( __( 'Revisions: %s' ), '<b>' . number_format_i18n( $args['args']['revisions_count'] ) . '</b>' );
+ }
+?>
+ <a class="hide-if-no-js" href="<?php echo esc_url( get_edit_post_link( $args['args']['revision_id'] ) ); ?>"><?php _ex( 'Browse', 'revisions' ); ?></a>
+</div>
+<?php endif;
+
+if ( $can_publish ) : // Contributors don't get to choose the date of publish ?>
+<div class="misc-pub-section curtime">
+ <span id="timestamp">
+ <?php printf($stamp, $date); ?></span>
+ <a href="#edit_timestamp" class="edit-timestamp hide-if-no-js"><?php _e('Edit') ?></a>
+ <div id="timestampdiv" class="hide-if-js"><?php touch_time(($action == 'edit'), 1); ?></div>
+</div><?php // /misc-pub-section ?>
+<?php endif; ?>
+
+<?php do_action('post_submitbox_misc_actions'); ?>
+</div>
+<div class="clear"></div>
+</div>
+
+<div id="major-publishing-actions">
+<?php do_action('post_submitbox_start'); ?>
+<div id="delete-action">
+<?php
+if ( current_user_can( "delete_post", $post->ID ) ) {
+ if ( !EMPTY_TRASH_DAYS )
+ $delete_text = __('Delete Permanently');
+ else
+ $delete_text = __('Move to Trash');
+ ?>
+<a class="submitdelete deletion" href="<?php echo get_delete_post_link($post->ID); ?>"><?php echo $delete_text; ?></a><?php
+} ?>
+</div>
+
+<div id="publishing-action">
+<span class="spinner"></span>
+<?php
+if ( !in_array( $post->post_status, array('publish', 'future', 'private') ) || 0 == $post->ID ) {
+ if ( $can_publish ) :
+ if ( !empty($post->post_date_gmt) && time() < strtotime( $post->post_date_gmt . ' +0000' ) ) : ?>
+ <input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Schedule') ?>" />
+ <?php submit_button( __( 'Schedule' ), 'primary button-large', 'publish', false, array( 'accesskey' => 'p' ) ); ?>
+<?php else : ?>
+ <input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Publish') ?>" />
+ <?php submit_button( __( 'Publish' ), 'primary button-large', 'publish', false, array( 'accesskey' => 'p' ) ); ?>
+<?php endif;
+ else : ?>
+ <input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Submit for Review') ?>" />
+ <?php submit_button( __( 'Submit for Review' ), 'primary button-large', 'publish', false, array( 'accesskey' => 'p' ) ); ?>
+<?php
+ endif;
+} else { ?>
+ <input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Update') ?>" />
+ <input name="save" type="submit" class="button button-primary button-large" id="publish" accesskey="p" value="<?php esc_attr_e('Update') ?>" />
+<?php
+} ?>
+</div>
+<div class="clear"></div>
+</div>
+</div>
+
+<?php
+}
+
+/**
+ * Display attachment submit form fields.
+ *
+ * @since 3.5.0
+ *
+ * @param object $post
+ */
+function attachment_submit_meta_box( $post ) {
+ global $action;
+
+ $post_type = $post->post_type;
+ $post_type_object = get_post_type_object($post_type);
+ $can_publish = current_user_can($post_type_object->cap->publish_posts);
+?>
+<div class="submitbox" id="submitpost">
+
+<div id="minor-publishing">
+
+<?php // Hidden submit button early on so that the browser chooses the right button when form is submitted with Return key ?>
+<div style="display:none;">
+<?php submit_button( __( 'Save' ), 'button', 'save' ); ?>
+</div>
+
+
+<div id="misc-publishing-actions">
+ <?php
+ // translators: Publish box date format, see http://php.net/date
+ $datef = __( 'M j, Y @ G:i' );
+ $stamp = __('Uploaded on: <b>%1$s</b>');
+ $date = date_i18n( $datef, strtotime( $post->post_date ) );
+ ?>
+ <div class="misc-pub-section curtime">
+ <span id="timestamp"><?php printf($stamp, $date); ?></span>
+ </div><!-- .misc-pub-section -->
+
+ <?php do_action('attachment_submitbox_misc_actions'); ?>
+</div><!-- #misc-publishing-actions -->
+<div class="clear"></div>
+</div><!-- #minor-publishing -->
+
+<div id="major-publishing-actions">
+ <div id="delete-action">
+ <?php
+ if ( current_user_can( 'delete_post', $post->ID ) )
+ if ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
+ echo "<a class='submitdelete deletion' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash' ) . "</a>";
+ } else {
+ $delete_ays = ! MEDIA_TRASH ? " onclick='return showNotice.warn();'" : '';
+ echo "<a class='submitdelete deletion'$delete_ays href='" . get_delete_post_link( $post->ID, null, true ) . "'>" . __( 'Delete Permanently' ) . "</a>";
+ }
+ ?>
+ </div>
+
+ <div id="publishing-action">
+ <span class="spinner"></span>
+ <input name="original_publish" type="hidden" id="original_publish" value="<?php esc_attr_e('Update') ?>" />
+ <input name="save" type="submit" class="button-primary button-large" id="publish" accesskey="p" value="<?php esc_attr_e('Update') ?>" />
+ </div>
+ <div class="clear"></div>
+</div><!-- #major-publishing-actions -->
+
+</div>
+
+<?php
+}
+
+/**
+ * Display post format form elements.
+ *
+ * @since 3.1.0
+ *
+ * @param object $post
+ */
+function post_format_meta_box( $post, $box ) {
+ if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) ) :
+ $post_formats = get_theme_support( 'post-formats' );
+
+ if ( is_array( $post_formats[0] ) ) :
+ $post_format = get_post_format( $post->ID );
+ if ( !$post_format )
+ $post_format = '0';
+ // Add in the current one if it isn't there yet, in case the current theme doesn't support it
+ if ( $post_format && !in_array( $post_format, $post_formats[0] ) )
+ $post_formats[0][] = $post_format;
+ ?>
+ <div id="post-formats-select">
+ <input type="radio" name="post_format" class="post-format" id="post-format-0" value="0" <?php checked( $post_format, '0' ); ?> /> <label for="post-format-0" class="post-format-icon post-format-standard"><?php echo get_post_format_string( 'standard' ); ?></label>
+ <?php foreach ( $post_formats[0] as $format ) : ?>
+ <br /><input type="radio" name="post_format" class="post-format" id="post-format-<?php echo esc_attr( $format ); ?>" value="<?php echo esc_attr( $format ); ?>" <?php checked( $post_format, $format ); ?> /> <label for="post-format-<?php echo esc_attr( $format ); ?>" class="post-format-icon post-format-<?php echo esc_attr( $format ); ?>"><?php echo esc_html( get_post_format_string( $format ) ); ?></label>
+ <?php endforeach; ?><br />
+ </div>
+ <?php endif; endif;
+}
+
+/**
+ * Display post tags form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_tags_meta_box($post, $box) {
+ $defaults = array('taxonomy' => 'post_tag');
+ if ( !isset($box['args']) || !is_array($box['args']) )
+ $args = array();
+ else
+ $args = $box['args'];
+ extract( wp_parse_args($args, $defaults), EXTR_SKIP );
+ $tax_name = esc_attr($taxonomy);
+ $taxonomy = get_taxonomy($taxonomy);
+ $user_can_assign_terms = current_user_can( $taxonomy->cap->assign_terms );
+ $comma = _x( ',', 'tag delimiter' );
+?>
+<div class="tagsdiv" id="<?php echo $tax_name; ?>">
+ <div class="jaxtag">
+ <div class="nojs-tags hide-if-js">
+ <p><?php echo $taxonomy->labels->add_or_remove_items; ?></p>
+ <textarea name="<?php echo "tax_input[$tax_name]"; ?>" rows="3" cols="20" class="the-tags" id="tax-input-<?php echo $tax_name; ?>" <?php disabled( ! $user_can_assign_terms ); ?>><?php echo str_replace( ',', $comma . ' ', get_terms_to_edit( $post->ID, $tax_name ) ); // textarea_escaped by esc_attr() ?></textarea></div>
+ <?php if ( $user_can_assign_terms ) : ?>
+ <div class="ajaxtag hide-if-no-js">
+ <label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $box['title']; ?></label>
+ <div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div>
+ <p><input type="text" id="new-tag-<?php echo $tax_name; ?>" name="newtag[<?php echo $tax_name; ?>]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
+ <input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" /></p>
+ </div>
+ <p class="howto"><?php echo $taxonomy->labels->separate_items_with_commas; ?></p>
+ <?php endif; ?>
+ </div>
+ <div class="tagchecklist"></div>
+</div>
+<?php if ( $user_can_assign_terms ) : ?>
+<p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php echo $taxonomy->labels->choose_from_most_used; ?></a></p>
+<?php endif; ?>
+<?php
+}
+
+/**
+ * Display post categories form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_categories_meta_box( $post, $box ) {
+ $defaults = array('taxonomy' => 'category');
+ if ( !isset($box['args']) || !is_array($box['args']) )
+ $args = array();
+ else
+ $args = $box['args'];
+ extract( wp_parse_args($args, $defaults), EXTR_SKIP );
+ $tax = get_taxonomy($taxonomy);
+
+ ?>
+ <div id="taxonomy-<?php echo $taxonomy; ?>" class="categorydiv">
+ <ul id="<?php echo $taxonomy; ?>-tabs" class="category-tabs">
+ <li class="tabs"><a href="#<?php echo $taxonomy; ?>-all"><?php echo $tax->labels->all_items; ?></a></li>
+ <li class="hide-if-no-js"><a href="#<?php echo $taxonomy; ?>-pop"><?php _e( 'Most Used' ); ?></a></li>
+ </ul>
+
+ <div id="<?php echo $taxonomy; ?>-pop" class="tabs-panel" style="display: none;">
+ <ul id="<?php echo $taxonomy; ?>checklist-pop" class="categorychecklist form-no-clear" >
+ <?php $popular_ids = wp_popular_terms_checklist($taxonomy); ?>
+ </ul>
+ </div>
+
+ <div id="<?php echo $taxonomy; ?>-all" class="tabs-panel">
+ <?php
+ $name = ( $taxonomy == 'category' ) ? 'post_category' : 'tax_input[' . $taxonomy . ']';
+ echo "<input type='hidden' name='{$name}[]' value='0' />"; // Allows for an empty term set to be sent. 0 is an invalid Term ID and will be ignored by empty() checks.
+ ?>
+ <ul id="<?php echo $taxonomy; ?>checklist" data-wp-lists="list:<?php echo $taxonomy?>" class="categorychecklist form-no-clear">
+ <?php wp_terms_checklist($post->ID, array( 'taxonomy' => $taxonomy, 'popular_cats' => $popular_ids ) ) ?>
+ </ul>
+ </div>
+ <?php if ( current_user_can($tax->cap->edit_terms) ) : ?>
+ <div id="<?php echo $taxonomy; ?>-adder" class="wp-hidden-children">
+ <h4>
+ <a id="<?php echo $taxonomy; ?>-add-toggle" href="#<?php echo $taxonomy; ?>-add" class="hide-if-no-js">
+ <?php
+ /* translators: %s: add new taxonomy label */
+ printf( __( '+ %s' ), $tax->labels->add_new_item );
+ ?>
+ </a>
+ </h4>
+ <p id="<?php echo $taxonomy; ?>-add" class="category-add wp-hidden-child">
+ <label class="screen-reader-text" for="new<?php echo $taxonomy; ?>"><?php echo $tax->labels->add_new_item; ?></label>
+ <input type="text" name="new<?php echo $taxonomy; ?>" id="new<?php echo $taxonomy; ?>" class="form-required form-input-tip" value="<?php echo esc_attr( $tax->labels->new_item_name ); ?>" aria-required="true"/>
+ <label class="screen-reader-text" for="new<?php echo $taxonomy; ?>_parent">
+ <?php echo $tax->labels->parent_item_colon; ?>
+ </label>
+ <?php wp_dropdown_categories( array( 'taxonomy' => $taxonomy, 'hide_empty' => 0, 'name' => 'new'.$taxonomy.'_parent', 'orderby' => 'name', 'hierarchical' => 1, 'show_option_none' => '&mdash; ' . $tax->labels->parent_item . ' &mdash;' ) ); ?>
+ <input type="button" id="<?php echo $taxonomy; ?>-add-submit" data-wp-lists="add:<?php echo $taxonomy ?>checklist:<?php echo $taxonomy ?>-add" class="button category-add-submit" value="<?php echo esc_attr( $tax->labels->add_new_item ); ?>" />
+ <?php wp_nonce_field( 'add-'.$taxonomy, '_ajax_nonce-add-'.$taxonomy, false ); ?>
+ <span id="<?php echo $taxonomy; ?>-ajax-response"></span>
+ </p>
+ </div>
+ <?php endif; ?>
+ </div>
+ <?php
+}
+
+/**
+ * Display post excerpt form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_excerpt_meta_box($post) {
+?>
+<label class="screen-reader-text" for="excerpt"><?php _e('Excerpt') ?></label><textarea rows="1" cols="40" name="excerpt" id="excerpt"><?php echo $post->post_excerpt; // textarea_escaped ?></textarea>
+<p><?php _e('Excerpts are optional hand-crafted summaries of your content that can be used in your theme. <a href="http://codex.wordpress.org/Excerpt" target="_blank">Learn more about manual excerpts.</a>'); ?></p>
+<?php
+}
+
+/**
+ * Display trackback links form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_trackback_meta_box($post) {
+ $form_trackback = '<input type="text" name="trackback_url" id="trackback_url" class="code" value="'. esc_attr( str_replace("\n", ' ', $post->to_ping) ) .'" />';
+ if ('' != $post->pinged) {
+ $pings = '<p>'. __('Already pinged:') . '</p><ul>';
+ $already_pinged = explode("\n", trim($post->pinged));
+ foreach ($already_pinged as $pinged_url) {
+ $pings .= "\n\t<li>" . esc_html($pinged_url) . "</li>";
+ }
+ $pings .= '</ul>';
+ }
+
+?>
+<p><label for="trackback_url"><?php _e('Send trackbacks to:'); ?></label> <?php echo $form_trackback; ?><br /> (<?php _e('Separate multiple URLs with spaces'); ?>)</p>
+<p><?php _e('Trackbacks are a way to notify legacy blog systems that you&#8217;ve linked to them. If you link other WordPress sites they&#8217;ll be notified automatically using <a href="http://codex.wordpress.org/Introduction_to_Blogging#Managing_Comments" target="_blank">pingbacks</a>, no other action necessary.'); ?></p>
+<?php
+if ( ! empty($pings) )
+ echo $pings;
+}
+
+/**
+ * Display custom fields form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_custom_meta_box($post) {
+?>
+<div id="postcustomstuff">
+<div id="ajax-response"></div>
+<?php
+$metadata = has_meta($post->ID);
+foreach ( $metadata as $key => $value ) {
+ if ( is_protected_meta( $metadata[ $key ][ 'meta_key' ], 'post' ) || ! current_user_can( 'edit_post_meta', $post->ID, $metadata[ $key ][ 'meta_key' ] ) )
+ unset( $metadata[ $key ] );
+}
+list_meta( $metadata );
+meta_form(); ?>
+</div>
+<p><?php _e('Custom fields can be used to add extra metadata to a post that you can <a href="http://codex.wordpress.org/Using_Custom_Fields" target="_blank">use in your theme</a>.'); ?></p>
+<?php
+}
+
+/**
+ * Display comments status form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_comment_status_meta_box($post) {
+?>
+<input name="advanced_view" type="hidden" value="1" />
+<p class="meta-options">
+ <label for="comment_status" class="selectit"><input name="comment_status" type="checkbox" id="comment_status" value="open" <?php checked($post->comment_status, 'open'); ?> /> <?php _e( 'Allow comments.' ) ?></label><br />
+ <label for="ping_status" class="selectit"><input name="ping_status" type="checkbox" id="ping_status" value="open" <?php checked($post->ping_status, 'open'); ?> /> <?php printf( __( 'Allow <a href="%s" target="_blank">trackbacks and pingbacks</a> on this page.' ), __( 'http://codex.wordpress.org/Introduction_to_Blogging#Managing_Comments' ) ); ?></label>
+ <?php do_action('post_comment_status_meta_box-options', $post); ?>
+</p>
+<?php
+}
+
+/**
+ * Display comments for post table header
+ *
+ * @since 3.0.0
+ *
+ * @param array $result table header rows
+ * @return array
+ */
+function post_comment_meta_box_thead($result) {
+ unset($result['cb'], $result['response']);
+ return $result;
+}
+
+/**
+ * Display comments for post.
+ *
+ * @since 2.8.0
+ *
+ * @param object $post
+ */
+function post_comment_meta_box( $post ) {
+ global $wpdb;
+
+ wp_nonce_field( 'get-comments', 'add_comment_nonce', false );
+ ?>
+ <p class="hide-if-no-js" id="add-new-comment"><a href="#commentstatusdiv" onclick="commentReply.addcomment(<?php echo $post->ID; ?>);return false;"><?php _e('Add comment'); ?></a></p>
+ <?php
+
+ $total = get_comments( array( 'post_id' => $post->ID, 'number' => 1, 'count' => true ) );
+ $wp_list_table = _get_list_table('WP_Post_Comments_List_Table');
+ $wp_list_table->display( true );
+
+ if ( 1 > $total ) {
+ echo '<p id="no-comments">' . __('No comments yet.') . '</p>';
+ } else {
+ $hidden = get_hidden_meta_boxes( get_current_screen() );
+ if ( ! in_array('commentsdiv', $hidden) ) {
+ ?>
+ <script type="text/javascript">jQuery(document).ready(function(){commentsBox.get(<?php echo $total; ?>, 10);});</script>
+ <?php
+ }
+
+ ?>
+ <p class="hide-if-no-js" id="show-comments"><a href="#commentstatusdiv" onclick="commentsBox.get(<?php echo $total; ?>);return false;"><?php _e('Show comments'); ?></a> <span class="spinner"></span></p>
+ <?php
+ }
+
+ wp_comment_trashnotice();
+}
+
+/**
+ * Display slug form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_slug_meta_box($post) {
+?>
+<label class="screen-reader-text" for="post_name"><?php _e('Slug') ?></label><input name="post_name" type="text" size="13" id="post_name" value="<?php echo esc_attr( apply_filters('editable_slug', $post->post_name) ); ?>" />
+<?php
+}
+
+/**
+ * Display form field with list of authors.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_author_meta_box($post) {
+ global $user_ID;
+?>
+<label class="screen-reader-text" for="post_author_override"><?php _e('Author'); ?></label>
+<?php
+ wp_dropdown_users( array(
+ 'who' => 'authors',
+ 'name' => 'post_author_override',
+ 'selected' => empty($post->ID) ? $user_ID : $post->post_author,
+ 'include_selected' => true
+ ) );
+}
+
+/**
+ * Display list of revisions.
+ *
+ * @since 2.6.0
+ *
+ * @param object $post
+ */
+function post_revisions_meta_box( $post ) {
+ wp_list_post_revisions( $post );
+}
+
+// -- Page related Meta Boxes
+
+/**
+ * Display page attributes form fields.
+ *
+ * @since 2.7.0
+ *
+ * @param object $post
+ */
+function page_attributes_meta_box($post) {
+ $post_type_object = get_post_type_object($post->post_type);
+ if ( $post_type_object->hierarchical ) {
+ $dropdown_args = array(
+ 'post_type' => $post->post_type,
+ 'exclude_tree' => $post->ID,
+ 'selected' => $post->post_parent,
+ 'name' => 'parent_id',
+ 'show_option_none' => __('(no parent)'),
+ 'sort_column' => 'menu_order, post_title',
+ 'echo' => 0,
+ );
+
+ $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post );
+ $pages = wp_dropdown_pages( $dropdown_args );
+ if ( ! empty($pages) ) {
+?>
+<p><strong><?php _e('Parent') ?></strong></p>
+<label class="screen-reader-text" for="parent_id"><?php _e('Parent') ?></label>
+<?php echo $pages; ?>
+<?php
+ } // end empty pages check
+ } // end hierarchical check.
+ if ( 'page' == $post->post_type && 0 != count( get_page_templates() ) ) {
+ $template = !empty($post->page_template) ? $post->page_template : false;
+ ?>
+<p><strong><?php _e('Template') ?></strong></p>
+<label class="screen-reader-text" for="page_template"><?php _e('Page Template') ?></label><select name="page_template" id="page_template">
+<option value='default'><?php _e('Default Template'); ?></option>
+<?php page_template_dropdown($template); ?>
+</select>
+<?php
+ } ?>
+<p><strong><?php _e('Order') ?></strong></p>
+<p><label class="screen-reader-text" for="menu_order"><?php _e('Order') ?></label><input name="menu_order" type="text" size="4" id="menu_order" value="<?php echo esc_attr($post->menu_order) ?>" /></p>
+<p><?php if ( 'page' == $post->post_type ) _e( 'Need help? Use the Help tab in the upper right of your screen.' ); ?></p>
+<?php
+}
+
+// -- Link related Meta Boxes
+
+/**
+ * Display link create form fields.
+ *
+ * @since 2.7.0
+ *
+ * @param object $link
+ */
+function link_submit_meta_box($link) {
+?>
+<div class="submitbox" id="submitlink">
+
+<div id="minor-publishing">
+
+<?php // Hidden submit button early on so that the browser chooses the right button when form is submitted with Return key ?>
+<div style="display:none;">
+<?php submit_button( __( 'Save' ), 'button', 'save', false ); ?>
+</div>
+
+<div id="minor-publishing-actions">
+<div id="preview-action">
+<?php if ( !empty($link->link_id) ) { ?>
+ <a class="preview button" href="<?php echo $link->link_url; ?>" target="_blank"><?php _e('Visit Link'); ?></a>
+<?php } ?>
+</div>
+<div class="clear"></div>
+</div>
+
+<div id="misc-publishing-actions">
+<div class="misc-pub-section">
+ <label for="link_private" class="selectit"><input id="link_private" name="link_visible" type="checkbox" value="N" <?php checked($link->link_visible, 'N'); ?> /> <?php _e('Keep this link private') ?></label>
+</div>
+</div>
+
+</div>
+
+<div id="major-publishing-actions">
+<?php do_action('post_submitbox_start'); ?>
+<div id="delete-action">
+<?php
+if ( !empty($_GET['action']) && 'edit' == $_GET['action'] && current_user_can('manage_links') ) { ?>
+ <a class="submitdelete deletion" href="<?php echo wp_nonce_url("link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id); ?>" onclick="if ( confirm('<?php echo esc_js(sprintf(__("You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete."), $link->link_name )); ?>') ) {return true;}return false;"><?php _e('Delete'); ?></a>
+<?php } ?>
+</div>
+
+<div id="publishing-action">
+<?php if ( !empty($link->link_id) ) { ?>
+ <input name="save" type="submit" class="button-large button-primary" id="publish" accesskey="p" value="<?php esc_attr_e('Update Link') ?>" />
+<?php } else { ?>
+ <input name="save" type="submit" class="button-large button-primary" id="publish" accesskey="p" value="<?php esc_attr_e('Add Link') ?>" />
+<?php } ?>
+</div>
+<div class="clear"></div>
+</div>
+<?php do_action('submitlink_box'); ?>
+<div class="clear"></div>
+</div>
+<?php
+}
+
+/**
+ * Display link categories form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $link
+ */
+function link_categories_meta_box($link) {
+?>
+<div id="taxonomy-linkcategory" class="categorydiv">
+ <ul id="category-tabs" class="category-tabs">
+ <li class="tabs"><a href="#categories-all"><?php _e( 'All Categories' ); ?></a></li>
+ <li class="hide-if-no-js"><a href="#categories-pop"><?php _e( 'Most Used' ); ?></a></li>
+ </ul>
+
+ <div id="categories-all" class="tabs-panel">
+ <ul id="categorychecklist" data-wp-lists="list:category" class="categorychecklist form-no-clear">
+ <?php
+ if ( isset($link->link_id) )
+ wp_link_category_checklist($link->link_id);
+ else
+ wp_link_category_checklist();
+ ?>
+ </ul>
+ </div>
+
+ <div id="categories-pop" class="tabs-panel" style="display: none;">
+ <ul id="categorychecklist-pop" class="categorychecklist form-no-clear">
+ <?php wp_popular_terms_checklist('link_category'); ?>
+ </ul>
+ </div>
+
+ <div id="category-adder" class="wp-hidden-children">
+ <h4><a id="category-add-toggle" href="#category-add"><?php _e( '+ Add New Category' ); ?></a></h4>
+ <p id="link-category-add" class="wp-hidden-child">
+ <label class="screen-reader-text" for="newcat"><?php _e( '+ Add New Category' ); ?></label>
+ <input type="text" name="newcat" id="newcat" class="form-required form-input-tip" value="<?php esc_attr_e( 'New category name' ); ?>" aria-required="true" />
+ <input type="button" id="link-category-add-submit" data-wp-lists="add:categorychecklist:link-category-add" class="button" value="<?php esc_attr_e( 'Add' ); ?>" />
+ <?php wp_nonce_field( 'add-link-category', '_ajax_nonce', false ); ?>
+ <span id="category-ajax-response"></span>
+ </p>
+ </div>
+</div>
+<?php
+}
+
+/**
+ * Display form fields for changing link target.
+ *
+ * @since 2.6.0
+ *
+ * @param object $link
+ */
+function link_target_meta_box($link) { ?>
+<fieldset><legend class="screen-reader-text"><span><?php _e('Target') ?></span></legend>
+<p><label for="link_target_blank" class="selectit">
+<input id="link_target_blank" type="radio" name="link_target" value="_blank" <?php echo ( isset( $link->link_target ) && ($link->link_target == '_blank') ? 'checked="checked"' : ''); ?> />
+<?php _e('<code>_blank</code> &mdash; new window or tab.'); ?></label></p>
+<p><label for="link_target_top" class="selectit">
+<input id="link_target_top" type="radio" name="link_target" value="_top" <?php echo ( isset( $link->link_target ) && ($link->link_target == '_top') ? 'checked="checked"' : ''); ?> />
+<?php _e('<code>_top</code> &mdash; current window or tab, with no frames.'); ?></label></p>
+<p><label for="link_target_none" class="selectit">
+<input id="link_target_none" type="radio" name="link_target" value="" <?php echo ( isset( $link->link_target ) && ($link->link_target == '') ? 'checked="checked"' : ''); ?> />
+<?php _e('<code>_none</code> &mdash; same window or tab.'); ?></label></p>
+</fieldset>
+<p><?php _e('Choose the target frame for your link.'); ?></p>
+<?php
+}
+
+/**
+ * Display checked checkboxes attribute for xfn microformat options.
+ *
+ * @since 1.0.1
+ *
+ * @param string $class
+ * @param string $value
+ * @param mixed $deprecated Never used.
+ */
+function xfn_check( $class, $value = '', $deprecated = '' ) {
+ global $link;
+
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '0.0' ); // Never implemented
+
+ $link_rel = isset( $link->link_rel ) ? $link->link_rel : ''; // In PHP 5.3: $link_rel = $link->link_rel ?: '';
+ $rels = preg_split('/\s+/', $link_rel);
+
+ if ('' != $value && in_array($value, $rels) ) {
+ echo ' checked="checked"';
+ }
+
+ if ('' == $value) {
+ if ('family' == $class && strpos($link_rel, 'child') === false && strpos($link_rel, 'parent') === false && strpos($link_rel, 'sibling') === false && strpos($link_rel, 'spouse') === false && strpos($link_rel, 'kin') === false) echo ' checked="checked"';
+ if ('friendship' == $class && strpos($link_rel, 'friend') === false && strpos($link_rel, 'acquaintance') === false && strpos($link_rel, 'contact') === false) echo ' checked="checked"';
+ if ('geographical' == $class && strpos($link_rel, 'co-resident') === false && strpos($link_rel, 'neighbor') === false) echo ' checked="checked"';
+ if ('identity' == $class && in_array('me', $rels) ) echo ' checked="checked"';
+ }
+}
+
+/**
+ * Display xfn form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $link
+ */
+function link_xfn_meta_box($link) {
+?>
+<table class="links-table" cellspacing="0">
+ <tr>
+ <th scope="row"><label for="link_rel"><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('rel:') ?></label></th>
+ <td><input type="text" name="link_rel" id="link_rel" value="<?php echo ( isset( $link->link_rel ) ? esc_attr($link->link_rel) : ''); ?>" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('identity') ?></th>
+ <td><fieldset><legend class="screen-reader-text"><span><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('identity') ?></span></legend>
+ <label for="me">
+ <input type="checkbox" name="identity" value="me" id="me" <?php xfn_check('identity', 'me'); ?> />
+ <?php _e('another web address of mine') ?></label>
+ </fieldset></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('friendship') ?></th>
+ <td><fieldset><legend class="screen-reader-text"><span><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('friendship') ?></span></legend>
+ <label for="contact">
+ <input class="valinp" type="radio" name="friendship" value="contact" id="contact" <?php xfn_check('friendship', 'contact'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('contact') ?>
+ </label>
+ <label for="acquaintance">
+ <input class="valinp" type="radio" name="friendship" value="acquaintance" id="acquaintance" <?php xfn_check('friendship', 'acquaintance'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('acquaintance') ?>
+ </label>
+ <label for="friend">
+ <input class="valinp" type="radio" name="friendship" value="friend" id="friend" <?php xfn_check('friendship', 'friend'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('friend') ?>
+ </label>
+ <label for="friendship">
+ <input name="friendship" type="radio" class="valinp" value="" id="friendship" <?php xfn_check('friendship'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('none') ?>
+ </label>
+ </fieldset></td>
+ </tr>
+ <tr>
+ <th scope="row"> <?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('physical') ?> </th>
+ <td><fieldset><legend class="screen-reader-text"><span><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('physical') ?></span></legend>
+ <label for="met">
+ <input class="valinp" type="checkbox" name="physical" value="met" id="met" <?php xfn_check('physical', 'met'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('met') ?>
+ </label>
+ </fieldset></td>
+ </tr>
+ <tr>
+ <th scope="row"> <?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('professional') ?> </th>
+ <td><fieldset><legend class="screen-reader-text"><span><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('professional') ?></span></legend>
+ <label for="co-worker">
+ <input class="valinp" type="checkbox" name="professional" value="co-worker" id="co-worker" <?php xfn_check('professional', 'co-worker'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('co-worker') ?>
+ </label>
+ <label for="colleague">
+ <input class="valinp" type="checkbox" name="professional" value="colleague" id="colleague" <?php xfn_check('professional', 'colleague'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('colleague') ?>
+ </label>
+ </fieldset></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('geographical') ?></th>
+ <td><fieldset><legend class="screen-reader-text"><span> <?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('geographical') ?> </span></legend>
+ <label for="co-resident">
+ <input class="valinp" type="radio" name="geographical" value="co-resident" id="co-resident" <?php xfn_check('geographical', 'co-resident'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('co-resident') ?>
+ </label>
+ <label for="neighbor">
+ <input class="valinp" type="radio" name="geographical" value="neighbor" id="neighbor" <?php xfn_check('geographical', 'neighbor'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('neighbor') ?>
+ </label>
+ <label for="geographical">
+ <input class="valinp" type="radio" name="geographical" value="" id="geographical" <?php xfn_check('geographical'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('none') ?>
+ </label>
+ </fieldset></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('family') ?></th>
+ <td><fieldset><legend class="screen-reader-text"><span> <?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('family') ?> </span></legend>
+ <label for="child">
+ <input class="valinp" type="radio" name="family" value="child" id="child" <?php xfn_check('family', 'child'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('child') ?>
+ </label>
+ <label for="kin">
+ <input class="valinp" type="radio" name="family" value="kin" id="kin" <?php xfn_check('family', 'kin'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('kin') ?>
+ </label>
+ <label for="parent">
+ <input class="valinp" type="radio" name="family" value="parent" id="parent" <?php xfn_check('family', 'parent'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('parent') ?>
+ </label>
+ <label for="sibling">
+ <input class="valinp" type="radio" name="family" value="sibling" id="sibling" <?php xfn_check('family', 'sibling'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('sibling') ?>
+ </label>
+ <label for="spouse">
+ <input class="valinp" type="radio" name="family" value="spouse" id="spouse" <?php xfn_check('family', 'spouse'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('spouse') ?>
+ </label>
+ <label for="family">
+ <input class="valinp" type="radio" name="family" value="" id="family" <?php xfn_check('family'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('none') ?>
+ </label>
+ </fieldset></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('romantic') ?></th>
+ <td><fieldset><legend class="screen-reader-text"><span> <?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('romantic') ?> </span></legend>
+ <label for="muse">
+ <input class="valinp" type="checkbox" name="romantic" value="muse" id="muse" <?php xfn_check('romantic', 'muse'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('muse') ?>
+ </label>
+ <label for="crush">
+ <input class="valinp" type="checkbox" name="romantic" value="crush" id="crush" <?php xfn_check('romantic', 'crush'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('crush') ?>
+ </label>
+ <label for="date">
+ <input class="valinp" type="checkbox" name="romantic" value="date" id="date" <?php xfn_check('romantic', 'date'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('date') ?>
+ </label>
+ <label for="romantic">
+ <input class="valinp" type="checkbox" name="romantic" value="sweetheart" id="romantic" <?php xfn_check('romantic', 'sweetheart'); ?> />&nbsp;<?php /* translators: xfn: http://gmpg.org/xfn/ */ _e('sweetheart') ?>
+ </label>
+ </fieldset></td>
+ </tr>
+
+</table>
+<p><?php _e('If the link is to a person, you can specify your relationship with them using the above form. If you would like to learn more about the idea check out <a href="http://gmpg.org/xfn/">XFN</a>.'); ?></p>
+<?php
+}
+
+/**
+ * Display advanced link options form fields.
+ *
+ * @since 2.6.0
+ *
+ * @param object $link
+ */
+function link_advanced_meta_box($link) {
+?>
+<table class="links-table" cellpadding="0">
+ <tr>
+ <th scope="row"><label for="link_image"><?php _e('Image Address') ?></label></th>
+ <td><input type="text" name="link_image" class="code" id="link_image" value="<?php echo ( isset( $link->link_image ) ? esc_attr($link->link_image) : ''); ?>" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="rss_uri"><?php _e('RSS Address') ?></label></th>
+ <td><input name="link_rss" class="code" type="text" id="rss_uri" value="<?php echo ( isset( $link->link_rss ) ? esc_attr($link->link_rss) : ''); ?>" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="link_notes"><?php _e('Notes') ?></label></th>
+ <td><textarea name="link_notes" id="link_notes" rows="10"><?php echo ( isset( $link->link_notes ) ? $link->link_notes : ''); // textarea_escaped ?></textarea></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="link_rating"><?php _e('Rating') ?></label></th>
+ <td><select name="link_rating" id="link_rating" size="1">
+ <?php
+ for ( $r = 0; $r <= 10; $r++ ) {
+ echo '<option value="' . $r . '"';
+ if ( isset($link->link_rating) && $link->link_rating == $r )
+ echo ' selected="selected"';
+ echo('>' . $r . '</option>');
+ }
+ ?></select>&nbsp;<?php _e('(Leave at 0 for no rating.)') ?>
+ </td>
+ </tr>
+</table>
+<?php
+}
+
+/**
+ * Display post thumbnail meta box.
+ *
+ * @since 2.9.0
+ */
+function post_thumbnail_meta_box( $post ) {
+ $thumbnail_id = get_post_meta( $post->ID, '_thumbnail_id', true );
+ echo _wp_post_thumbnail_html( $thumbnail_id, $post->ID );
+}
diff --git a/src/wp-admin/includes/misc.php b/src/wp-admin/includes/misc.php
new file mode 100644
index 0000000000..5b609e45ba
--- /dev/null
+++ b/src/wp-admin/includes/misc.php
@@ -0,0 +1,667 @@
+<?php
+/**
+ * Misc WordPress Administration API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @return unknown
+ */
+function got_mod_rewrite() {
+ $got_rewrite = apache_mod_loaded('mod_rewrite', true);
+ return apply_filters('got_rewrite', $got_rewrite);
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $filename
+ * @param unknown_type $marker
+ * @return array An array of strings from a file (.htaccess ) from between BEGIN and END markers.
+ */
+function extract_from_markers( $filename, $marker ) {
+ $result = array ();
+
+ if (!file_exists( $filename ) ) {
+ return $result;
+ }
+
+ if ( $markerdata = explode( "\n", implode( '', file( $filename ) ) ));
+ {
+ $state = false;
+ foreach ( $markerdata as $markerline ) {
+ if (strpos($markerline, '# END ' . $marker) !== false)
+ $state = false;
+ if ( $state )
+ $result[] = $markerline;
+ if (strpos($markerline, '# BEGIN ' . $marker) !== false)
+ $state = true;
+ }
+ }
+
+ return $result;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * Inserts an array of strings into a file (.htaccess ), placing it between
+ * BEGIN and END markers. Replaces existing marked info. Retains surrounding
+ * data. Creates file if none exists.
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $filename
+ * @param unknown_type $marker
+ * @param unknown_type $insertion
+ * @return bool True on write success, false on failure.
+ */
+function insert_with_markers( $filename, $marker, $insertion ) {
+ if (!file_exists( $filename ) || is_writeable( $filename ) ) {
+ if (!file_exists( $filename ) ) {
+ $markerdata = '';
+ } else {
+ $markerdata = explode( "\n", implode( '', file( $filename ) ) );
+ }
+
+ if ( !$f = @fopen( $filename, 'w' ) )
+ return false;
+
+ $foundit = false;
+ if ( $markerdata ) {
+ $state = true;
+ foreach ( $markerdata as $n => $markerline ) {
+ if (strpos($markerline, '# BEGIN ' . $marker) !== false)
+ $state = false;
+ if ( $state ) {
+ if ( $n + 1 < count( $markerdata ) )
+ fwrite( $f, "{$markerline}\n" );
+ else
+ fwrite( $f, "{$markerline}" );
+ }
+ if (strpos($markerline, '# END ' . $marker) !== false) {
+ fwrite( $f, "# BEGIN {$marker}\n" );
+ if ( is_array( $insertion ))
+ foreach ( $insertion as $insertline )
+ fwrite( $f, "{$insertline}\n" );
+ fwrite( $f, "# END {$marker}\n" );
+ $state = true;
+ $foundit = true;
+ }
+ }
+ }
+ if (!$foundit) {
+ fwrite( $f, "\n# BEGIN {$marker}\n" );
+ foreach ( $insertion as $insertline )
+ fwrite( $f, "{$insertline}\n" );
+ fwrite( $f, "# END {$marker}\n" );
+ }
+ fclose( $f );
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Updates the htaccess file with the current rules if it is writable.
+ *
+ * Always writes to the file if it exists and is writable to ensure that we
+ * blank out old rules.
+ *
+ * @since 1.5.0
+ */
+function save_mod_rewrite_rules() {
+ if ( is_multisite() )
+ return;
+
+ global $wp_rewrite;
+
+ $home_path = get_home_path();
+ $htaccess_file = $home_path.'.htaccess';
+
+ // If the file doesn't already exist check for write access to the directory and whether we have some rules.
+ // else check for write access to the file.
+ if ((!file_exists($htaccess_file) && is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks()) || is_writable($htaccess_file)) {
+ if ( got_mod_rewrite() ) {
+ $rules = explode( "\n", $wp_rewrite->mod_rewrite_rules() );
+ return insert_with_markers( $htaccess_file, 'WordPress', $rules );
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Updates the IIS web.config file with the current rules if it is writable.
+ * If the permalinks do not require rewrite rules then the rules are deleted from the web.config file.
+ *
+ * @since 2.8.0
+ *
+ * @return bool True if web.config was updated successfully
+ */
+function iis7_save_url_rewrite_rules(){
+ if ( is_multisite() )
+ return;
+
+ global $wp_rewrite;
+
+ $home_path = get_home_path();
+ $web_config_file = $home_path . 'web.config';
+
+ // Using win_is_writable() instead of is_writable() because of a bug in Windows PHP
+ if ( iis7_supports_permalinks() && ( ( ! file_exists($web_config_file) && win_is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks() ) || win_is_writable($web_config_file) ) ) {
+ $rule = $wp_rewrite->iis7_url_rewrite_rules(false, '', '');
+ if ( ! empty($rule) ) {
+ return iis7_add_rewrite_rule($web_config_file, $rule);
+ } else {
+ return iis7_delete_rewrite_rule($web_config_file);
+ }
+ }
+ return false;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $file
+ */
+function update_recently_edited( $file ) {
+ $oldfiles = (array ) get_option( 'recently_edited' );
+ if ( $oldfiles ) {
+ $oldfiles = array_reverse( $oldfiles );
+ $oldfiles[] = $file;
+ $oldfiles = array_reverse( $oldfiles );
+ $oldfiles = array_unique( $oldfiles );
+ if ( 5 < count( $oldfiles ))
+ array_pop( $oldfiles );
+ } else {
+ $oldfiles[] = $file;
+ }
+ update_option( 'recently_edited', $oldfiles );
+}
+
+/**
+ * If siteurl, home or page_on_front changed, flush rewrite rules.
+ *
+ * @since 2.1.0
+ *
+ * @param string $old_value
+ * @param string $value
+ */
+function update_home_siteurl( $old_value, $value ) {
+ if ( defined( "WP_INSTALLING" ) )
+ return;
+
+ // If home changed, write rewrite rules to new location.
+ flush_rewrite_rules();
+}
+
+add_action( 'update_option_home', 'update_home_siteurl', 10, 2 );
+add_action( 'update_option_siteurl', 'update_home_siteurl', 10, 2 );
+add_action( 'update_option_page_on_front', 'update_home_siteurl', 10, 2 );
+
+/**
+ * Shorten an URL, to be used as link text
+ *
+ * @since 1.2.1
+ *
+ * @param string $url
+ * @return string
+ */
+function url_shorten( $url ) {
+ $short_url = str_replace( array( 'http://', 'www.' ), '', $url );
+ $short_url = untrailingslashit( $short_url );
+ if ( strlen( $short_url ) > 35 )
+ $short_url = substr( $short_url, 0, 32 ) . '&hellip;';
+ return $short_url;
+}
+
+/**
+ * Resets global variables based on $_GET and $_POST
+ *
+ * This function resets global variables based on the names passed
+ * in the $vars array to the value of $_POST[$var] or $_GET[$var] or ''
+ * if neither is defined.
+ *
+ * @since 2.0.0
+ *
+ * @param array $vars An array of globals to reset.
+ */
+function wp_reset_vars( $vars ) {
+ for ( $i=0; $i<count( $vars ); $i += 1 ) {
+ $var = $vars[$i];
+ global $$var;
+
+ if ( empty( $_POST[$var] ) ) {
+ if ( empty( $_GET[$var] ) )
+ $$var = '';
+ else
+ $$var = $_GET[$var];
+ } else {
+ $$var = $_POST[$var];
+ }
+ }
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.1.0
+ *
+ * @param unknown_type $message
+ */
+function show_message($message) {
+ if ( is_wp_error($message) ){
+ if ( $message->get_error_data() )
+ $message = $message->get_error_message() . ': ' . $message->get_error_data();
+ else
+ $message = $message->get_error_message();
+ }
+ echo "<p>$message</p>\n";
+ wp_ob_end_flush_all();
+ flush();
+}
+
+function wp_doc_link_parse( $content ) {
+ if ( !is_string( $content ) || empty( $content ) )
+ return array();
+
+ if ( !function_exists('token_get_all') )
+ return array();
+
+ $tokens = token_get_all( $content );
+ $functions = array();
+ $ignore_functions = array();
+ for ( $t = 0, $count = count( $tokens ); $t < $count; $t++ ) {
+ if ( !is_array( $tokens[$t] ) ) continue;
+ if ( T_STRING == $tokens[$t][0] && ( '(' == $tokens[ $t + 1 ] || '(' == $tokens[ $t + 2 ] ) ) {
+ // If it's a function or class defined locally, there's not going to be any docs available
+ if ( ( isset( $tokens[ $t - 2 ][1] ) && in_array( $tokens[ $t - 2 ][1], array( 'function', 'class' ) ) ) || ( isset( $tokens[ $t - 2 ][0] ) && T_OBJECT_OPERATOR == $tokens[ $t - 1 ][0] ) ) {
+ $ignore_functions[] = $tokens[$t][1];
+ }
+ // Add this to our stack of unique references
+ $functions[] = $tokens[$t][1];
+ }
+ }
+
+ $functions = array_unique( $functions );
+ sort( $functions );
+ $ignore_functions = apply_filters( 'documentation_ignore_functions', $ignore_functions );
+ $ignore_functions = array_unique( $ignore_functions );
+
+ $out = array();
+ foreach ( $functions as $function ) {
+ if ( in_array( $function, $ignore_functions ) )
+ continue;
+ $out[] = $function;
+ }
+
+ return $out;
+}
+
+/**
+ * Saves option for number of rows when listing posts, pages, comments, etc.
+ *
+ * @since 2.8
+**/
+function set_screen_options() {
+
+ if ( isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options']) ) {
+ check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
+
+ if ( !$user = wp_get_current_user() )
+ return;
+ $option = $_POST['wp_screen_options']['option'];
+ $value = $_POST['wp_screen_options']['value'];
+
+ if ( $option != sanitize_key( $option ) )
+ return;
+
+ $map_option = $option;
+ $type = str_replace('edit_', '', $map_option);
+ $type = str_replace('_per_page', '', $type);
+ if ( in_array( $type, get_taxonomies() ) )
+ $map_option = 'edit_tags_per_page';
+ elseif ( in_array( $type, get_post_types() ) )
+ $map_option = 'edit_per_page';
+ else
+ $option = str_replace('-', '_', $option);
+
+ switch ( $map_option ) {
+ case 'edit_per_page':
+ case 'users_per_page':
+ case 'edit_comments_per_page':
+ case 'upload_per_page':
+ case 'edit_tags_per_page':
+ case 'plugins_per_page':
+ // Network admin
+ case 'sites_network_per_page':
+ case 'users_network_per_page':
+ case 'site_users_network_per_page':
+ case 'plugins_network_per_page':
+ case 'themes_network_per_page':
+ case 'site_themes_network_per_page':
+ $value = (int) $value;
+ if ( $value < 1 || $value > 999 )
+ return;
+ break;
+ default:
+ $value = apply_filters('set-screen-option', false, $option, $value);
+ if ( false === $value )
+ return;
+ break;
+ }
+
+ update_user_meta($user->ID, $option, $value);
+ wp_safe_redirect( remove_query_arg( array('pagenum', 'apage', 'paged'), wp_get_referer() ) );
+ exit;
+ }
+}
+
+/**
+ * Check if rewrite rule for WordPress already exists in the IIS 7+ configuration file
+ *
+ * @since 2.8.0
+ *
+ * @return bool
+ * @param string $filename The file path to the configuration file
+ */
+function iis7_rewrite_rule_exists($filename) {
+ if ( ! file_exists($filename) )
+ return false;
+ if ( ! class_exists('DOMDocument') )
+ return false;
+
+ $doc = new DOMDocument();
+ if ( $doc->load($filename) === false )
+ return false;
+ $xpath = new DOMXPath($doc);
+ $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')]');
+ if ( $rules->length == 0 )
+ return false;
+ else
+ return true;
+}
+
+/**
+ * Delete WordPress rewrite rule from web.config file if it exists there
+ *
+ * @since 2.8.0
+ *
+ * @param string $filename Name of the configuration file
+ * @return bool
+ */
+function iis7_delete_rewrite_rule($filename) {
+ // If configuration file does not exist then rules also do not exist so there is nothing to delete
+ if ( ! file_exists($filename) )
+ return true;
+
+ if ( ! class_exists('DOMDocument') )
+ return false;
+
+ $doc = new DOMDocument();
+ $doc->preserveWhiteSpace = false;
+
+ if ( $doc -> load($filename) === false )
+ return false;
+ $xpath = new DOMXPath($doc);
+ $rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')]');
+ if ( $rules->length > 0 ) {
+ $child = $rules->item(0);
+ $parent = $child->parentNode;
+ $parent->removeChild($child);
+ $doc->formatOutput = true;
+ saveDomDocument($doc, $filename);
+ }
+ return true;
+}
+
+/**
+ * Add WordPress rewrite rule to the IIS 7+ configuration file.
+ *
+ * @since 2.8.0
+ *
+ * @param string $filename The file path to the configuration file
+ * @param string $rewrite_rule The XML fragment with URL Rewrite rule
+ * @return bool
+ */
+function iis7_add_rewrite_rule($filename, $rewrite_rule) {
+ if ( ! class_exists('DOMDocument') )
+ return false;
+
+ // If configuration file does not exist then we create one.
+ if ( ! file_exists($filename) ) {
+ $fp = fopen( $filename, 'w');
+ fwrite($fp, '<configuration/>');
+ fclose($fp);
+ }
+
+ $doc = new DOMDocument();
+ $doc->preserveWhiteSpace = false;
+
+ if ( $doc->load($filename) === false )
+ return false;
+
+ $xpath = new DOMXPath($doc);
+
+ // First check if the rule already exists as in that case there is no need to re-add it
+ $wordpress_rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')]');
+ if ( $wordpress_rules->length > 0 )
+ return true;
+
+ // Check the XPath to the rewrite rule and create XML nodes if they do not exist
+ $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite/rules');
+ if ( $xmlnodes->length > 0 ) {
+ $rules_node = $xmlnodes->item(0);
+ } else {
+ $rules_node = $doc->createElement('rules');
+
+ $xmlnodes = $xpath->query('/configuration/system.webServer/rewrite');
+ if ( $xmlnodes->length > 0 ) {
+ $rewrite_node = $xmlnodes->item(0);
+ $rewrite_node->appendChild($rules_node);
+ } else {
+ $rewrite_node = $doc->createElement('rewrite');
+ $rewrite_node->appendChild($rules_node);
+
+ $xmlnodes = $xpath->query('/configuration/system.webServer');
+ if ( $xmlnodes->length > 0 ) {
+ $system_webServer_node = $xmlnodes->item(0);
+ $system_webServer_node->appendChild($rewrite_node);
+ } else {
+ $system_webServer_node = $doc->createElement('system.webServer');
+ $system_webServer_node->appendChild($rewrite_node);
+
+ $xmlnodes = $xpath->query('/configuration');
+ if ( $xmlnodes->length > 0 ) {
+ $config_node = $xmlnodes->item(0);
+ $config_node->appendChild($system_webServer_node);
+ } else {
+ $config_node = $doc->createElement('configuration');
+ $doc->appendChild($config_node);
+ $config_node->appendChild($system_webServer_node);
+ }
+ }
+ }
+ }
+
+ $rule_fragment = $doc->createDocumentFragment();
+ $rule_fragment->appendXML($rewrite_rule);
+ $rules_node->appendChild($rule_fragment);
+
+ $doc->encoding = "UTF-8";
+ $doc->formatOutput = true;
+ saveDomDocument($doc, $filename);
+
+ return true;
+}
+
+/**
+ * Saves the XML document into a file
+ *
+ * @since 2.8.0
+ *
+ * @param DOMDocument $doc
+ * @param string $filename
+ */
+function saveDomDocument($doc, $filename) {
+ $config = $doc->saveXML();
+ $config = preg_replace("/([^\r])\n/", "$1\r\n", $config);
+ $fp = fopen($filename, 'w');
+ fwrite($fp, $config);
+ fclose($fp);
+}
+
+/**
+ * Display the default admin color scheme picker (Used in user-edit.php)
+ *
+ * @since 3.0.0
+ */
+function admin_color_scheme_picker() {
+ global $_wp_admin_css_colors, $user_id; ?>
+<fieldset><legend class="screen-reader-text"><span><?php _e('Admin Color Scheme')?></span></legend>
+<?php
+$current_color = get_user_option('admin_color', $user_id);
+if ( empty($current_color) )
+ $current_color = 'fresh';
+foreach ( $_wp_admin_css_colors as $color => $color_info ): ?>
+<div class="color-option"><input name="admin_color" id="admin_color_<?php echo esc_attr( $color ); ?>" type="radio" value="<?php echo esc_attr( $color ); ?>" class="tog" <?php checked($color, $current_color); ?> />
+ <table class="color-palette">
+ <tr>
+ <?php foreach ( $color_info->colors as $html_color ): ?>
+ <td style="background-color: <?php echo esc_attr( $html_color ); ?>" title="<?php echo esc_attr( $color ); ?>">&nbsp;</td>
+ <?php endforeach; ?>
+ </tr>
+ </table>
+
+ <label for="admin_color_<?php echo esc_attr( $color ); ?>"><?php echo esc_html( $color_info->name ); ?></label>
+</div>
+ <?php endforeach; ?>
+</fieldset>
+<?php
+}
+
+function _ipad_meta() {
+ if ( wp_is_mobile() ) {
+ ?>
+ <meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1">
+ <?php
+ }
+}
+add_action('admin_head', '_ipad_meta');
+
+/**
+ * Check lock status for posts displayed on the Posts screen
+ *
+ * @since 3.6
+ */
+function wp_check_locked_posts( $response, $data, $screen_id ) {
+ $checked = array();
+
+ if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) {
+ foreach ( $data['wp-check-locked-posts'] as $key ) {
+ if ( ! $post_id = absint( substr( $key, 5 ) ) )
+ continue;
+
+ if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) && current_user_can( 'edit_post', $post_id ) ) {
+ $send = array( 'text' => sprintf( __( '%s is currently editing' ), $user->display_name ) );
+
+ if ( ( $avatar = get_avatar( $user->ID, 18 ) ) && preg_match( "|src='([^']+)'|", $avatar, $matches ) )
+ $send['avatar_src'] = $matches[1];
+
+ $checked[$key] = $send;
+ }
+ }
+ }
+
+ if ( ! empty( $checked ) )
+ $response['wp-check-locked-posts'] = $checked;
+
+ return $response;
+}
+add_filter( 'heartbeat_received', 'wp_check_locked_posts', 10, 3 );
+
+/**
+ * Check lock status on the New/Edit Post screen and refresh the lock
+ *
+ * @since 3.6
+ */
+function wp_refresh_post_lock( $response, $data, $screen_id ) {
+ if ( array_key_exists( 'wp-refresh-post-lock', $data ) ) {
+ $received = $data['wp-refresh-post-lock'];
+ $send = array();
+
+ if ( ! $post_id = absint( $received['post_id'] ) )
+ return $response;
+
+ if ( ! current_user_can('edit_post', $post_id) )
+ return $response;
+
+ if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
+ $error = array(
+ 'text' => sprintf( __( '%s has taken over and is currently editing.' ), $user->display_name )
+ );
+
+ if ( $avatar = get_avatar( $user->ID, 64 ) ) {
+ if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) )
+ $error['avatar_src'] = $matches[1];
+ }
+
+ $send['lock_error'] = $error;
+ } else {
+ if ( $new_lock = wp_set_post_lock( $post_id ) )
+ $send['new_lock'] = implode( ':', $new_lock );
+ }
+
+ $response['wp-refresh-post-lock'] = $send;
+ }
+
+ return $response;
+}
+add_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10, 3 );
+
+/**
+ * Check nonce expiration on the New/Edit Post screen and refresh if needed
+ *
+ * @since 3.6
+ */
+function wp_refresh_post_nonces( $response, $data, $screen_id ) {
+ if ( array_key_exists( 'wp-refresh-post-nonces', $data ) ) {
+ $received = $data['wp-refresh-post-nonces'];
+ $response['wp-refresh-post-nonces'] = array( 'check' => 1 );
+
+ if ( ! $post_id = absint( $received['post_id'] ) )
+ return $response;
+
+ if ( ! current_user_can( 'edit_post', $post_id ) || empty( $received['post_nonce'] ) )
+ return $response;
+
+ if ( 2 === wp_verify_nonce( $received['post_nonce'], 'update-post_' . $post_id ) ) {
+ $response['wp-refresh-post-nonces'] = array(
+ 'replace' => array(
+ 'autosavenonce' => wp_create_nonce('autosave'),
+ 'getpermalinknonce' => wp_create_nonce('getpermalink'),
+ 'samplepermalinknonce' => wp_create_nonce('samplepermalink'),
+ 'closedpostboxesnonce' => wp_create_nonce('closedpostboxes'),
+ '_ajax_linking_nonce' => wp_create_nonce( 'internal-linking' ),
+ '_wpnonce' => wp_create_nonce( 'update-post_' . $post_id ),
+ ),
+ 'heartbeatNonce' => wp_create_nonce( 'heartbeat-nonce' ),
+ );
+ }
+ }
+
+ return $response;
+}
+add_filter( 'heartbeat_received', 'wp_refresh_post_nonces', 10, 3 );
diff --git a/src/wp-admin/includes/ms-deprecated.php b/src/wp-admin/includes/ms-deprecated.php
new file mode 100644
index 0000000000..702e3e13cf
--- /dev/null
+++ b/src/wp-admin/includes/ms-deprecated.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Deprecated multisite admin functions from past WordPress versions and WordPress MU.
+ * You shouldn't use these functions and look for the alternatives instead. The functions
+ * will be removed in a later version.
+ *
+ * @package WordPress
+ * @subpackage Deprecated
+ * @since 3.0.0
+ */
+
+/**
+ * @deprecated 3.0.0
+ */
+function wpmu_menu() {
+ _deprecated_function(__FUNCTION__, '3.0' );
+ // deprecated. See #11763
+}
+
+/**
+ * Determines if the available space defined by the admin has been exceeded by the user.
+ *
+ * @deprecated 3.0.0
+ * @see is_upload_space_available()
+ */
+function wpmu_checkAvailableSpace() {
+ _deprecated_function(__FUNCTION__, '3.0', 'is_upload_space_available()' );
+
+ if ( !is_upload_space_available() )
+ wp_die( __('Sorry, you must delete files before you can upload any more.') );
+}
+
+/**
+ * @deprecated 3.0.0
+ */
+function mu_options( $options ) {
+ _deprecated_function(__FUNCTION__, '3.0' );
+ return $options;
+}
+
+/**
+ * @deprecated 3.0.0
+ * @see activate_plugin()
+ */
+function activate_sitewide_plugin() {
+ _deprecated_function(__FUNCTION__, '3.0', 'activate_plugin()' );
+ return false;
+}
+
+/**
+ * @deprecated 3.0.0
+ * @see deactivate_sitewide_plugin()
+ */
+function deactivate_sitewide_plugin( $plugin = false ) {
+ _deprecated_function(__FUNCTION__, '3.0', 'deactivate_plugin()' );
+ return;
+}
+
+/**
+ * @deprecated 3.0.0
+ * @see is_network_only_plugin()
+ */
+function is_wpmu_sitewide_plugin( $file ) {
+ _deprecated_function(__FUNCTION__, '3.0', 'is_network_only_plugin()' );
+ return is_network_only_plugin( $file );
+}
+
+function get_site_allowed_themes() {
+ _deprecated_function( __FUNCTION__, '3.4', 'WP_Theme::get_allowed_on_network()' );
+ return array_map( 'intval', WP_Theme::get_allowed_on_network() );
+}
+
+function wpmu_get_blog_allowedthemes( $blog_id = 0 ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'WP_Theme::get_allowed_on_site()' );
+ return array_map( 'intval', WP_Theme::get_allowed_on_site( $blog_id ) );
+}
+
+function ms_deprecated_blogs_file() {} \ No newline at end of file
diff --git a/src/wp-admin/includes/ms.php b/src/wp-admin/includes/ms.php
new file mode 100644
index 0000000000..8d7bf3fa1d
--- /dev/null
+++ b/src/wp-admin/includes/ms.php
@@ -0,0 +1,677 @@
+<?php
+/**
+ * Multisite administration functions.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/**
+ * Determine if uploaded file exceeds space quota.
+ *
+ * @since 3.0.0
+ *
+ * @param array $file $_FILES array for a given file.
+ * @return array $_FILES array with 'error' key set if file exceeds quota. 'error' is empty otherwise.
+ */
+function check_upload_size( $file ) {
+ if ( get_site_option( 'upload_space_check_disabled' ) )
+ return $file;
+
+ if ( $file['error'] != '0' ) // there's already an error
+ return $file;
+
+ if ( defined( 'WP_IMPORTING' ) )
+ return $file;
+
+ $space_left = get_upload_space_available();
+
+ $file_size = filesize( $file['tmp_name'] );
+ if ( $space_left < $file_size )
+ $file['error'] = sprintf( __( 'Not enough space to upload. %1$s KB needed.' ), number_format( ($file_size - $space_left) /1024 ) );
+ if ( $file_size > ( 1024 * get_site_option( 'fileupload_maxk', 1500 ) ) )
+ $file['error'] = sprintf(__('This file is too big. Files must be less than %1$s KB in size.'), get_site_option( 'fileupload_maxk', 1500 ) );
+ if ( upload_is_user_over_quota( false ) ) {
+ $file['error'] = __( 'You have used your space quota. Please delete files before uploading.' );
+ }
+ if ( $file['error'] != '0' && !isset($_POST['html-upload']) )
+ wp_die( $file['error'] . ' <a href="javascript:history.go(-1)">' . __( 'Back' ) . '</a>' );
+
+ return $file;
+}
+add_filter( 'wp_handle_upload_prefilter', 'check_upload_size' );
+
+/**
+ * Delete a blog
+ *
+ * @since 3.0.0
+ *
+ * @param int $blog_id Blog ID
+ * @param bool $drop True if blog's table should be dropped. Default is false.
+ * @return void
+ */
+function wpmu_delete_blog( $blog_id, $drop = false ) {
+ global $wpdb, $current_site;
+
+ $switch = false;
+ if ( get_current_blog_id() != $blog_id ) {
+ $switch = true;
+ switch_to_blog( $blog_id );
+ }
+
+ $blog = get_blog_details( $blog_id );
+
+ do_action( 'delete_blog', $blog_id, $drop );
+
+ $users = get_users( array( 'blog_id' => $blog_id, 'fields' => 'ids' ) );
+
+ // Remove users from this blog.
+ if ( ! empty( $users ) ) {
+ foreach ( $users as $user_id ) {
+ remove_user_from_blog( $user_id, $blog_id );
+ }
+ }
+
+ update_blog_status( $blog_id, 'deleted', 1 );
+
+ // Don't destroy the initial, main, or root blog.
+ if ( $drop && ( 1 == $blog_id || is_main_site( $blog_id ) || ( $blog->path == $current_site->path && $blog->domain == $current_site->domain ) ) )
+ $drop = false;
+
+ if ( $drop ) {
+ $drop_tables = apply_filters( 'wpmu_drop_tables', $wpdb->tables( 'blog' ), $blog_id );
+
+ foreach ( (array) $drop_tables as $table ) {
+ $wpdb->query( "DROP TABLE IF EXISTS `$table`" );
+ }
+
+ $wpdb->delete( $wpdb->blogs, array( 'blog_id' => $blog_id ) );
+
+ $uploads = wp_upload_dir();
+ $dir = apply_filters( 'wpmu_delete_blog_upload_dir', $uploads['basedir'], $blog_id );
+ $dir = rtrim( $dir, DIRECTORY_SEPARATOR );
+ $top_dir = $dir;
+ $stack = array($dir);
+ $index = 0;
+
+ while ( $index < count( $stack ) ) {
+ # Get indexed directory from stack
+ $dir = $stack[$index];
+
+ $dh = @opendir( $dir );
+ if ( $dh ) {
+ while ( ( $file = @readdir( $dh ) ) !== false ) {
+ if ( $file == '.' || $file == '..' )
+ continue;
+
+ if ( @is_dir( $dir . DIRECTORY_SEPARATOR . $file ) )
+ $stack[] = $dir . DIRECTORY_SEPARATOR . $file;
+ else if ( @is_file( $dir . DIRECTORY_SEPARATOR . $file ) )
+ @unlink( $dir . DIRECTORY_SEPARATOR . $file );
+ }
+ @closedir( $dh );
+ }
+ $index++;
+ }
+
+ $stack = array_reverse( $stack ); // Last added dirs are deepest
+ foreach( (array) $stack as $dir ) {
+ if ( $dir != $top_dir)
+ @rmdir( $dir );
+ }
+
+ clean_blog_cache( $blog );
+ }
+
+ if ( $switch )
+ restore_current_blog();
+}
+
+// @todo Merge with wp_delete_user() ?
+function wpmu_delete_user( $id ) {
+ global $wpdb;
+
+ $id = (int) $id;
+ $user = new WP_User( $id );
+
+ if ( !$user->exists() )
+ return false;
+
+ do_action( 'wpmu_delete_user', $id );
+
+ $blogs = get_blogs_of_user( $id );
+
+ if ( ! empty( $blogs ) ) {
+ foreach ( $blogs as $blog ) {
+ switch_to_blog( $blog->userblog_id );
+ remove_user_from_blog( $id, $blog->userblog_id );
+
+ $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
+ foreach ( (array) $post_ids as $post_id ) {
+ wp_delete_post( $post_id );
+ }
+
+ // Clean links
+ $link_ids = $wpdb->get_col( $wpdb->prepare( "SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id ) );
+
+ if ( $link_ids ) {
+ foreach ( $link_ids as $link_id )
+ wp_delete_link( $link_id );
+ }
+
+ restore_current_blog();
+ }
+ }
+
+ $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
+ foreach ( $meta as $mid )
+ delete_metadata_by_mid( 'user', $mid );
+
+ $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
+
+ clean_user_cache( $user );
+
+ // allow for commit transaction
+ do_action( 'deleted_user', $id );
+
+ return true;
+}
+
+function update_option_new_admin_email( $old_value, $value ) {
+ $email = get_option( 'admin_email' );
+ if ( $value == get_option( 'admin_email' ) || !is_email( $value ) )
+ return;
+
+ $hash = md5( $value. time() .mt_rand() );
+ $new_admin_email = array(
+ 'hash' => $hash,
+ 'newemail' => $value
+ );
+ update_option( 'adminhash', $new_admin_email );
+
+ $content = apply_filters( 'new_admin_email_content', __( "Dear user,
+
+You recently requested to have the administration email address on
+your site changed.
+If this is correct, please click on the following link to change it:
+###ADMIN_URL###
+
+You can safely ignore and delete this email if you do not want to
+take this action.
+
+This email has been sent to ###EMAIL###
+
+Regards,
+All at ###SITENAME###
+###SITEURL### "), $new_admin_email );
+
+ $content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'options.php?adminhash='.$hash ) ), $content );
+ $content = str_replace( '###EMAIL###', $value, $content );
+ $content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
+ $content = str_replace( '###SITEURL###', network_home_url(), $content );
+
+ wp_mail( $value, sprintf( __( '[%s] New Admin Email Address' ), get_option( 'blogname' ) ), $content );
+}
+add_action( 'update_option_new_admin_email', 'update_option_new_admin_email', 10, 2 );
+add_action( 'add_option_new_admin_email', 'update_option_new_admin_email', 10, 2 );
+
+function send_confirmation_on_profile_email() {
+ global $errors, $wpdb;
+ $current_user = wp_get_current_user();
+ if ( ! is_object($errors) )
+ $errors = new WP_Error();
+
+ if ( $current_user->ID != $_POST['user_id'] )
+ return false;
+
+ if ( $current_user->user_email != $_POST['email'] ) {
+ if ( !is_email( $_POST['email'] ) ) {
+ $errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address isn&#8217;t correct." ), array( 'form-field' => 'email' ) );
+ return;
+ }
+
+ if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_email FROM {$wpdb->users} WHERE user_email=%s", $_POST['email'] ) ) ) {
+ $errors->add( 'user_email', __( "<strong>ERROR</strong>: The email address is already used." ), array( 'form-field' => 'email' ) );
+ delete_option( $current_user->ID . '_new_email' );
+ return;
+ }
+
+ $hash = md5( $_POST['email'] . time() . mt_rand() );
+ $new_user_email = array(
+ 'hash' => $hash,
+ 'newemail' => $_POST['email']
+ );
+ update_option( $current_user->ID . '_new_email', $new_user_email );
+
+ $content = apply_filters( 'new_user_email_content', __( "Dear user,
+
+You recently requested to have the email address on your account changed.
+If this is correct, please click on the following link to change it:
+###ADMIN_URL###
+
+You can safely ignore and delete this email if you do not want to
+take this action.
+
+This email has been sent to ###EMAIL###
+
+Regards,
+All at ###SITENAME###
+###SITEURL###" ), $new_user_email );
+
+ $content = str_replace( '###ADMIN_URL###', esc_url( admin_url( 'profile.php?newuseremail='.$hash ) ), $content );
+ $content = str_replace( '###EMAIL###', $_POST['email'], $content);
+ $content = str_replace( '###SITENAME###', get_site_option( 'site_name' ), $content );
+ $content = str_replace( '###SITEURL###', network_home_url(), $content );
+
+ wp_mail( $_POST['email'], sprintf( __( '[%s] New Email Address' ), get_option( 'blogname' ) ), $content );
+ $_POST['email'] = $current_user->user_email;
+ }
+}
+add_action( 'personal_options_update', 'send_confirmation_on_profile_email' );
+
+function new_user_email_admin_notice() {
+ if ( strpos( $_SERVER['PHP_SELF'], 'profile.php' ) && isset( $_GET['updated'] ) && $email = get_option( get_current_user_id() . '_new_email' ) )
+ echo "<div class='update-nag'>" . sprintf( __( "Your email address has not been updated yet. Please check your inbox at %s for a confirmation email." ), $email['newemail'] ) . "</div>";
+}
+add_action( 'admin_notices', 'new_user_email_admin_notice' );
+
+/**
+ * Check whether a blog has used its allotted upload space.
+ *
+ * @since MU
+ *
+ * @param bool $echo Optional. If $echo is set and the quota is exceeded, a warning message is echoed. Default is true.
+ * @return int
+ */
+function upload_is_user_over_quota( $echo = true ) {
+ if ( get_site_option( 'upload_space_check_disabled' ) )
+ return false;
+
+ $space_allowed = get_space_allowed();
+ if ( empty( $space_allowed ) || !is_numeric( $space_allowed ) )
+ $space_allowed = 10; // Default space allowed is 10 MB
+
+ $space_used = get_space_used();
+
+ if ( ( $space_allowed - $space_used ) < 0 ) {
+ if ( $echo )
+ _e( 'Sorry, you have used your space allocation. Please delete some files to upload more files.' );
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Displays the amount of disk space used by the current blog. Not used in core.
+ *
+ * @since MU
+ */
+function display_space_usage() {
+ $space_allowed = get_space_allowed();
+ $space_used = get_space_used();
+
+ $percent_used = ( $space_used / $space_allowed ) * 100;
+
+ if ( $space_allowed > 1000 ) {
+ $space = number_format( $space_allowed / 1024 );
+ /* translators: Gigabytes */
+ $space .= __( 'GB' );
+ } else {
+ $space = number_format( $space_allowed );
+ /* translators: Megabytes */
+ $space .= __( 'MB' );
+ }
+ ?>
+ <strong><?php printf( __( 'Used: %1$s%% of %2$s' ), number_format( $percent_used ), $space ); ?></strong>
+ <?php
+}
+
+/**
+ * Get the remaining upload space for this blog.
+ *
+ * @since MU
+ * @uses upload_is_user_over_quota()
+ * @uses get_space_allowed()
+ * @uses get_upload_space_available()
+ *
+ * @param int $size Current max size in bytes
+ * @return int Max size in bytes
+ */
+function fix_import_form_size( $size ) {
+ if ( upload_is_user_over_quota( false ) == true )
+ return 0;
+
+ $available = get_upload_space_available();
+ return min( $size, $available );
+}
+
+// Edit blog upload space setting on Edit Blog page
+function upload_space_setting( $id ) {
+ switch_to_blog( $id );
+ $quota = get_option( 'blog_upload_space' );
+ restore_current_blog();
+
+ if ( !$quota )
+ $quota = '';
+
+ ?>
+ <tr>
+ <th><?php _e( 'Site Upload Space Quota '); ?></th>
+ <td><input type="number" step="1" min="0" style="width: 100px" name="option[blog_upload_space]" value="<?php echo $quota; ?>" /> <?php _e( 'MB (Leave blank for network default)' ); ?></td>
+ </tr>
+ <?php
+}
+add_action( 'wpmueditblogaction', 'upload_space_setting' );
+
+function update_user_status( $id, $pref, $value, $deprecated = null ) {
+ global $wpdb;
+
+ if ( null !== $deprecated )
+ _deprecated_argument( __FUNCTION__, '3.1' );
+
+ $wpdb->update( $wpdb->users, array( sanitize_key( $pref ) => $value ), array( 'ID' => $id ) );
+
+ $user = new WP_User( $id );
+ clean_user_cache( $user );
+
+ if ( $pref == 'spam' ) {
+ if ( $value == 1 )
+ do_action( 'make_spam_user', $id );
+ else
+ do_action( 'make_ham_user', $id );
+ }
+
+ return $value;
+}
+
+function refresh_user_details( $id ) {
+ $id = (int) $id;
+
+ if ( !$user = get_userdata( $id ) )
+ return false;
+
+ clean_user_cache( $user );
+
+ return $id;
+}
+
+function format_code_lang( $code = '' ) {
+ $code = strtolower( substr( $code, 0, 2 ) );
+ $lang_codes = array(
+ 'aa' => 'Afar', 'ab' => 'Abkhazian', 'af' => 'Afrikaans', 'ak' => 'Akan', 'sq' => 'Albanian', 'am' => 'Amharic', 'ar' => 'Arabic', 'an' => 'Aragonese', 'hy' => 'Armenian', 'as' => 'Assamese', 'av' => 'Avaric', 'ae' => 'Avestan', 'ay' => 'Aymara', 'az' => 'Azerbaijani', 'ba' => 'Bashkir', 'bm' => 'Bambara', 'eu' => 'Basque', 'be' => 'Belarusian', 'bn' => 'Bengali',
+ 'bh' => 'Bihari', 'bi' => 'Bislama', 'bs' => 'Bosnian', 'br' => 'Breton', 'bg' => 'Bulgarian', 'my' => 'Burmese', 'ca' => 'Catalan; Valencian', 'ch' => 'Chamorro', 'ce' => 'Chechen', 'zh' => 'Chinese', 'cu' => 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic', 'cv' => 'Chuvash', 'kw' => 'Cornish', 'co' => 'Corsican', 'cr' => 'Cree',
+ 'cs' => 'Czech', 'da' => 'Danish', 'dv' => 'Divehi; Dhivehi; Maldivian', 'nl' => 'Dutch; Flemish', 'dz' => 'Dzongkha', 'en' => 'English', 'eo' => 'Esperanto', 'et' => 'Estonian', 'ee' => 'Ewe', 'fo' => 'Faroese', 'fj' => 'Fijjian', 'fi' => 'Finnish', 'fr' => 'French', 'fy' => 'Western Frisian', 'ff' => 'Fulah', 'ka' => 'Georgian', 'de' => 'German', 'gd' => 'Gaelic; Scottish Gaelic',
+ 'ga' => 'Irish', 'gl' => 'Galician', 'gv' => 'Manx', 'el' => 'Greek, Modern', 'gn' => 'Guarani', 'gu' => 'Gujarati', 'ht' => 'Haitian; Haitian Creole', 'ha' => 'Hausa', 'he' => 'Hebrew', 'hz' => 'Herero', 'hi' => 'Hindi', 'ho' => 'Hiri Motu', 'hu' => 'Hungarian', 'ig' => 'Igbo', 'is' => 'Icelandic', 'io' => 'Ido', 'ii' => 'Sichuan Yi', 'iu' => 'Inuktitut', 'ie' => 'Interlingue',
+ 'ia' => 'Interlingua (International Auxiliary Language Association)', 'id' => 'Indonesian', 'ik' => 'Inupiaq', 'it' => 'Italian', 'jv' => 'Javanese', 'ja' => 'Japanese', 'kl' => 'Kalaallisut; Greenlandic', 'kn' => 'Kannada', 'ks' => 'Kashmiri', 'kr' => 'Kanuri', 'kk' => 'Kazakh', 'km' => 'Central Khmer', 'ki' => 'Kikuyu; Gikuyu', 'rw' => 'Kinyarwanda', 'ky' => 'Kirghiz; Kyrgyz',
+ 'kv' => 'Komi', 'kg' => 'Kongo', 'ko' => 'Korean', 'kj' => 'Kuanyama; Kwanyama', 'ku' => 'Kurdish', 'lo' => 'Lao', 'la' => 'Latin', 'lv' => 'Latvian', 'li' => 'Limburgan; Limburger; Limburgish', 'ln' => 'Lingala', 'lt' => 'Lithuanian', 'lb' => 'Luxembourgish; Letzeburgesch', 'lu' => 'Luba-Katanga', 'lg' => 'Ganda', 'mk' => 'Macedonian', 'mh' => 'Marshallese', 'ml' => 'Malayalam',
+ 'mi' => 'Maori', 'mr' => 'Marathi', 'ms' => 'Malay', 'mg' => 'Malagasy', 'mt' => 'Maltese', 'mo' => 'Moldavian', 'mn' => 'Mongolian', 'na' => 'Nauru', 'nv' => 'Navajo; Navaho', 'nr' => 'Ndebele, South; South Ndebele', 'nd' => 'Ndebele, North; North Ndebele', 'ng' => 'Ndonga', 'ne' => 'Nepali', 'nn' => 'Norwegian Nynorsk; Nynorsk, Norwegian', 'nb' => 'Bokmål, Norwegian, Norwegian Bokmål',
+ 'no' => 'Norwegian', 'ny' => 'Chichewa; Chewa; Nyanja', 'oc' => 'Occitan, Provençal', 'oj' => 'Ojibwa', 'or' => 'Oriya', 'om' => 'Oromo', 'os' => 'Ossetian; Ossetic', 'pa' => 'Panjabi; Punjabi', 'fa' => 'Persian', 'pi' => 'Pali', 'pl' => 'Polish', 'pt' => 'Portuguese', 'ps' => 'Pushto', 'qu' => 'Quechua', 'rm' => 'Romansh', 'ro' => 'Romanian', 'rn' => 'Rundi', 'ru' => 'Russian',
+ 'sg' => 'Sango', 'sa' => 'Sanskrit', 'sr' => 'Serbian', 'hr' => 'Croatian', 'si' => 'Sinhala; Sinhalese', 'sk' => 'Slovak', 'sl' => 'Slovenian', 'se' => 'Northern Sami', 'sm' => 'Samoan', 'sn' => 'Shona', 'sd' => 'Sindhi', 'so' => 'Somali', 'st' => 'Sotho, Southern', 'es' => 'Spanish; Castilian', 'sc' => 'Sardinian', 'ss' => 'Swati', 'su' => 'Sundanese', 'sw' => 'Swahili',
+ 'sv' => 'Swedish', 'ty' => 'Tahitian', 'ta' => 'Tamil', 'tt' => 'Tatar', 'te' => 'Telugu', 'tg' => 'Tajik', 'tl' => 'Tagalog', 'th' => 'Thai', 'bo' => 'Tibetan', 'ti' => 'Tigrinya', 'to' => 'Tonga (Tonga Islands)', 'tn' => 'Tswana', 'ts' => 'Tsonga', 'tk' => 'Turkmen', 'tr' => 'Turkish', 'tw' => 'Twi', 'ug' => 'Uighur; Uyghur', 'uk' => 'Ukrainian', 'ur' => 'Urdu', 'uz' => 'Uzbek',
+ 've' => 'Venda', 'vi' => 'Vietnamese', 'vo' => 'Volapük', 'cy' => 'Welsh','wa' => 'Walloon','wo' => 'Wolof', 'xh' => 'Xhosa', 'yi' => 'Yiddish', 'yo' => 'Yoruba', 'za' => 'Zhuang; Chuang', 'zu' => 'Zulu' );
+ $lang_codes = apply_filters( 'lang_codes', $lang_codes, $code );
+ return strtr( $code, $lang_codes );
+}
+
+function sync_category_tag_slugs( $term, $taxonomy ) {
+ if ( global_terms_enabled() && ( $taxonomy == 'category' || $taxonomy == 'post_tag' ) ) {
+ if ( is_object( $term ) ) {
+ $term->slug = sanitize_title( $term->name );
+ } else {
+ $term['slug'] = sanitize_title( $term['name'] );
+ }
+ }
+ return $term;
+}
+add_filter( 'get_term', 'sync_category_tag_slugs', 10, 2 );
+
+function _access_denied_splash() {
+ if ( ! is_user_logged_in() || is_network_admin() )
+ return;
+
+ $blogs = get_blogs_of_user( get_current_user_id() );
+
+ if ( wp_list_filter( $blogs, array( 'userblog_id' => get_current_blog_id() ) ) )
+ return;
+
+ $blog_name = get_bloginfo( 'name' );
+
+ if ( empty( $blogs ) )
+ wp_die( sprintf( __( 'You attempted to access the "%1$s" dashboard, but you do not currently have privileges on this site. If you believe you should be able to access the "%1$s" dashboard, please contact your network administrator.' ), $blog_name ) );
+
+ $output = '<p>' . sprintf( __( 'You attempted to access the "%1$s" dashboard, but you do not currently have privileges on this site. If you believe you should be able to access the "%1$s" dashboard, please contact your network administrator.' ), $blog_name ) . '</p>';
+ $output .= '<p>' . __( 'If you reached this screen by accident and meant to visit one of your own sites, here are some shortcuts to help you find your way.' ) . '</p>';
+
+ $output .= '<h3>' . __('Your Sites') . '</h3>';
+ $output .= '<table>';
+
+ foreach ( $blogs as $blog ) {
+ $output .= "<tr>";
+ $output .= "<td valign='top'>";
+ $output .= "{$blog->blogname}";
+ $output .= "</td>";
+ $output .= "<td valign='top'>";
+ $output .= "<a href='" . esc_url( get_admin_url( $blog->userblog_id ) ) . "'>" . __( 'Visit Dashboard' ) . "</a> | <a href='" . esc_url( get_home_url( $blog->userblog_id ) ). "'>" . __( 'View Site' ) . "</a>" ;
+ $output .= "</td>";
+ $output .= "</tr>";
+ }
+ $output .= '</table>';
+
+ wp_die( $output );
+}
+add_action( 'admin_page_access_denied', '_access_denied_splash', 99 );
+
+function check_import_new_users( $permission ) {
+ if ( !is_super_admin() )
+ return false;
+ return true;
+}
+add_filter( 'import_allow_create_users', 'check_import_new_users' );
+// See "import_allow_fetch_attachments" and "import_attachment_size_limit" filters too.
+
+function mu_dropdown_languages( $lang_files = array(), $current = '' ) {
+ $flag = false;
+ $output = array();
+
+ foreach ( (array) $lang_files as $val ) {
+ $code_lang = basename( $val, '.mo' );
+
+ if ( $code_lang == 'en_US' ) { // American English
+ $flag = true;
+ $ae = __( 'American English' );
+ $output[$ae] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . $ae . '</option>';
+ } elseif ( $code_lang == 'en_GB' ) { // British English
+ $flag = true;
+ $be = __( 'British English' );
+ $output[$be] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . $be . '</option>';
+ } else {
+ $translated = format_code_lang( $code_lang );
+ $output[$translated] = '<option value="' . esc_attr( $code_lang ) . '"' . selected( $current, $code_lang, false ) . '> ' . esc_html ( $translated ) . '</option>';
+ }
+
+ }
+
+ if ( $flag === false ) // WordPress english
+ $output[] = '<option value=""' . selected( $current, '', false ) . '>' . __( 'English' ) . "</option>";
+
+ // Order by name
+ uksort( $output, 'strnatcasecmp' );
+
+ $output = apply_filters( 'mu_dropdown_languages', $output, $lang_files, $current );
+ echo implode( "\n\t", $output );
+}
+
+function site_admin_notice() {
+ global $wp_db_version;
+ if ( !is_super_admin() )
+ return false;
+ if ( get_site_option( 'wpmu_upgrade_site' ) != $wp_db_version )
+ echo "<div class='update-nag'>" . sprintf( __( 'Thank you for Updating! Please visit the <a href="%s">Upgrade Network</a> page to update all your sites.' ), esc_url( network_admin_url( 'upgrade.php' ) ) ) . "</div>";
+}
+add_action( 'admin_notices', 'site_admin_notice' );
+add_action( 'network_admin_notices', 'site_admin_notice' );
+
+function avoid_blog_page_permalink_collision( $data, $postarr ) {
+ if ( is_subdomain_install() )
+ return $data;
+ if ( $data['post_type'] != 'page' )
+ return $data;
+ if ( !isset( $data['post_name'] ) || $data['post_name'] == '' )
+ return $data;
+ if ( !is_main_site() )
+ return $data;
+
+ $post_name = $data['post_name'];
+ $c = 0;
+ while( $c < 10 && get_id_from_blogname( $post_name ) ) {
+ $post_name .= mt_rand( 1, 10 );
+ $c ++;
+ }
+ if ( $post_name != $data['post_name'] ) {
+ $data['post_name'] = $post_name;
+ }
+ return $data;
+}
+add_filter( 'wp_insert_post_data', 'avoid_blog_page_permalink_collision', 10, 2 );
+
+function choose_primary_blog() {
+ ?>
+ <table class="form-table">
+ <tr>
+ <?php /* translators: My sites label */ ?>
+ <th scope="row"><?php _e( 'Primary Site' ); ?></th>
+ <td>
+ <?php
+ $all_blogs = get_blogs_of_user( get_current_user_id() );
+ $primary_blog = get_user_meta( get_current_user_id(), 'primary_blog', true );
+ if ( count( $all_blogs ) > 1 ) {
+ $found = false;
+ ?>
+ <select name="primary_blog">
+ <?php foreach( (array) $all_blogs as $blog ) {
+ if ( $primary_blog == $blog->userblog_id )
+ $found = true;
+ ?><option value="<?php echo $blog->userblog_id ?>"<?php selected( $primary_blog, $blog->userblog_id ); ?>><?php echo esc_url( get_home_url( $blog->userblog_id ) ) ?></option><?php
+ } ?>
+ </select>
+ <?php
+ if ( !$found ) {
+ $blog = array_shift( $all_blogs );
+ update_user_meta( get_current_user_id(), 'primary_blog', $blog->userblog_id );
+ }
+ } elseif ( count( $all_blogs ) == 1 ) {
+ $blog = array_shift( $all_blogs );
+ echo $blog->domain;
+ if ( $primary_blog != $blog->userblog_id ) // Set the primary blog again if it's out of sync with blog list.
+ update_user_meta( get_current_user_id(), 'primary_blog', $blog->userblog_id );
+ } else {
+ echo "N/A";
+ }
+ ?>
+ </td>
+ </tr>
+ <?php if ( in_array( get_site_option( 'registration' ), array( 'all', 'blog' ) ) ) : ?>
+ <tr>
+ <th scope="row" colspan="2" class="th-full">
+ <a href="<?php echo apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) ); ?>"><?php _e( 'Create a New Site' ); ?></a>
+ </th>
+ </tr>
+ <?php endif; ?>
+ </table>
+ <?php
+}
+
+/**
+ * Grants super admin privileges.
+ *
+ * @since 3.0.0
+ * @param int $user_id
+ */
+function grant_super_admin( $user_id ) {
+ global $super_admins;
+
+ // If global super_admins override is defined, there is nothing to do here.
+ if ( isset($super_admins) )
+ return false;
+
+ do_action( 'grant_super_admin', $user_id );
+
+ // Directly fetch site_admins instead of using get_super_admins()
+ $super_admins = get_site_option( 'site_admins', array( 'admin' ) );
+
+ $user = get_userdata( $user_id );
+ if ( $user && ! in_array( $user->user_login, $super_admins ) ) {
+ $super_admins[] = $user->user_login;
+ update_site_option( 'site_admins' , $super_admins );
+ do_action( 'granted_super_admin', $user_id );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Revokes super admin privileges.
+ *
+ * @since 3.0.0
+ * @param int $user_id
+ */
+function revoke_super_admin( $user_id ) {
+ global $super_admins;
+
+ // If global super_admins override is defined, there is nothing to do here.
+ if ( isset($super_admins) )
+ return false;
+
+ do_action( 'revoke_super_admin', $user_id );
+
+ // Directly fetch site_admins instead of using get_super_admins()
+ $super_admins = get_site_option( 'site_admins', array( 'admin' ) );
+
+ $user = get_userdata( $user_id );
+ if ( $user && $user->user_email != get_site_option( 'admin_email' ) ) {
+ if ( false !== ( $key = array_search( $user->user_login, $super_admins ) ) ) {
+ unset( $super_admins[$key] );
+ update_site_option( 'site_admins', $super_admins );
+ do_action( 'revoked_super_admin', $user_id );
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Whether or not we can edit this network from this page
+ *
+ * By default editing of network is restricted to the Network Admin for that site_id this allows for this to be overridden
+ *
+ * @since 3.1.0
+ * @param integer $site_id The network/site id to check.
+ */
+function can_edit_network( $site_id ) {
+ global $wpdb;
+
+ if ($site_id == $wpdb->siteid )
+ $result = true;
+ else
+ $result = false;
+
+ return apply_filters( 'can_edit_network', $result, $site_id );
+}
+
+/**
+ * Thickbox image paths for Network Admin.
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _thickbox_path_admin_subfolder() {
+?>
+<script type="text/javascript">
+//<![CDATA[
+var tb_pathToImage = "../../wp-includes/js/thickbox/loadingAnimation.gif";
+//]]>
+</script>
+<?php
+}
diff --git a/src/wp-admin/includes/nav-menu.php b/src/wp-admin/includes/nav-menu.php
new file mode 100644
index 0000000000..7e9fe6ad64
--- /dev/null
+++ b/src/wp-admin/includes/nav-menu.php
@@ -0,0 +1,1288 @@
+<?php
+
+/**
+ * Create HTML list of nav menu input items.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ * @uses Walker_Nav_Menu
+ */
+class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
+ /**
+ * @see Walker_Nav_Menu::start_lvl()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference.
+ */
+ function start_lvl( &$output, $depth = 0, $args = array() ) {}
+
+ /**
+ * @see Walker_Nav_Menu::end_lvl()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference.
+ */
+ function end_lvl( &$output, $depth = 0, $args = array() ) {}
+
+ /**
+ * @see Walker::start_el()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $item Menu item data object.
+ * @param int $depth Depth of menu item. Used for padding.
+ * @param object $args
+ */
+ function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
+ global $_wp_nav_menu_max_depth;
+ $_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;
+
+ $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
+
+ ob_start();
+ $item_id = esc_attr( $item->ID );
+ $removed_args = array(
+ 'action',
+ 'customlink-tab',
+ 'edit-menu-item',
+ 'menu-item',
+ 'page-tab',
+ '_wpnonce',
+ );
+
+ $original_title = '';
+ if ( 'taxonomy' == $item->type ) {
+ $original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' );
+ if ( is_wp_error( $original_title ) )
+ $original_title = false;
+ } elseif ( 'post_type' == $item->type ) {
+ $original_object = get_post( $item->object_id );
+ $original_title = $original_object->post_title;
+ }
+
+ $classes = array(
+ 'menu-item menu-item-depth-' . $depth,
+ 'menu-item-' . esc_attr( $item->object ),
+ 'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'),
+ );
+
+ $title = $item->title;
+
+ if ( ! empty( $item->_invalid ) ) {
+ $classes[] = 'menu-item-invalid';
+ /* translators: %s: title of menu item which is invalid */
+ $title = sprintf( __( '%s (Invalid)' ), $item->title );
+ } elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) {
+ $classes[] = 'pending';
+ /* translators: %s: title of menu item in draft status */
+ $title = sprintf( __('%s (Pending)'), $item->title );
+ }
+
+ $title = ( ! isset( $item->label ) || '' == $item->label ) ? $title : $item->label;
+
+ $submenu_text = '';
+ if ( 0 == $depth )
+ $submenu_text = 'style="display: none;"';
+
+ ?>
+ <li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
+ <dl class="menu-item-bar">
+ <dt class="menu-item-handle">
+ <span class="item-title"><span class="menu-item-title"><?php echo esc_html( $title ); ?></span> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span>
+ <span class="item-controls">
+ <span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
+ <span class="item-order hide-if-js">
+ <a href="<?php
+ echo wp_nonce_url(
+ add_query_arg(
+ array(
+ 'action' => 'move-up-menu-item',
+ 'menu-item' => $item_id,
+ ),
+ remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
+ ),
+ 'move-menu_item'
+ );
+ ?>" class="item-move-up"><abbr title="<?php esc_attr_e('Move up'); ?>">&#8593;</abbr></a>
+ |
+ <a href="<?php
+ echo wp_nonce_url(
+ add_query_arg(
+ array(
+ 'action' => 'move-down-menu-item',
+ 'menu-item' => $item_id,
+ ),
+ remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
+ ),
+ 'move-menu_item'
+ );
+ ?>" class="item-move-down"><abbr title="<?php esc_attr_e('Move down'); ?>">&#8595;</abbr></a>
+ </span>
+ <a class="item-edit" id="edit-<?php echo $item_id; ?>" title="<?php esc_attr_e('Edit Menu Item'); ?>" href="<?php
+ echo ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? admin_url( 'nav-menus.php' ) : add_query_arg( 'edit-menu-item', $item_id, remove_query_arg( $removed_args, admin_url( 'nav-menus.php#menu-item-settings-' . $item_id ) ) );
+ ?>"><?php _e( 'Edit Menu Item' ); ?></a>
+ </span>
+ </dt>
+ </dl>
+
+ <div class="menu-item-settings" id="menu-item-settings-<?php echo $item_id; ?>">
+ <?php if( 'custom' == $item->type ) : ?>
+ <p class="field-url description description-wide">
+ <label for="edit-menu-item-url-<?php echo $item_id; ?>">
+ <?php _e( 'URL' ); ?><br />
+ <input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>" class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->url ); ?>" />
+ </label>
+ </p>
+ <?php endif; ?>
+ <p class="description description-thin">
+ <label for="edit-menu-item-title-<?php echo $item_id; ?>">
+ <?php _e( 'Navigation Label' ); ?><br />
+ <input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->title ); ?>" />
+ </label>
+ </p>
+ <p class="description description-thin">
+ <label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
+ <?php _e( 'Title Attribute' ); ?><br />
+ <input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_excerpt ); ?>" />
+ </label>
+ </p>
+ <p class="field-link-target description">
+ <label for="edit-menu-item-target-<?php echo $item_id; ?>">
+ <input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank" name="menu-item-target[<?php echo $item_id; ?>]"<?php checked( $item->target, '_blank' ); ?> />
+ <?php _e( 'Open link in a new window/tab' ); ?>
+ </label>
+ </p>
+ <p class="field-css-classes description description-thin">
+ <label for="edit-menu-item-classes-<?php echo $item_id; ?>">
+ <?php _e( 'CSS Classes (optional)' ); ?><br />
+ <input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>" class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]" value="<?php echo esc_attr( implode(' ', $item->classes ) ); ?>" />
+ </label>
+ </p>
+ <p class="field-xfn description description-thin">
+ <label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
+ <?php _e( 'Link Relationship (XFN)' ); ?><br />
+ <input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
+ </label>
+ </p>
+ <p class="field-description description description-wide">
+ <label for="edit-menu-item-description-<?php echo $item_id; ?>">
+ <?php _e( 'Description' ); ?><br />
+ <textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
+ <span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
+ </label>
+ </p>
+
+ <p class="field-move hide-if-no-js description description-wide">
+ <label>
+ <span><?php _e( 'Move' ); ?></span>
+ <a href="#" class="menus-move-up"><?php _e( 'Up one' ); ?></a>
+ <a href="#" class="menus-move-down"><?php _e( 'Down one' ); ?></a>
+ <a href="#" class="menus-move-left"></a>
+ <a href="#" class="menus-move-right"></a>
+ <a href="#" class="menus-move-top"><?php _e( 'To the top' ); ?></a>
+ </label>
+ </p>
+
+ <div class="menu-item-actions description-wide submitbox">
+ <?php if( 'custom' != $item->type && $original_title !== false ) : ?>
+ <p class="link-to-original">
+ <?php printf( __('Original: %s'), '<a href="' . esc_attr( $item->url ) . '">' . esc_html( $original_title ) . '</a>' ); ?>
+ </p>
+ <?php endif; ?>
+ <a class="item-delete submitdelete deletion" id="delete-<?php echo $item_id; ?>" href="<?php
+ echo wp_nonce_url(
+ add_query_arg(
+ array(
+ 'action' => 'delete-menu-item',
+ 'menu-item' => $item_id,
+ ),
+ admin_url( 'nav-menus.php' )
+ ),
+ 'delete-menu_item_' . $item_id
+ ); ?>"><?php _e( 'Remove' ); ?></a> <span class="meta-sep hide-if-no-js"> | </span> <a class="item-cancel submitcancel hide-if-no-js" id="cancel-<?php echo $item_id; ?>" href="<?php echo esc_url( add_query_arg( array( 'edit-menu-item' => $item_id, 'cancel' => time() ), admin_url( 'nav-menus.php' ) ) );
+ ?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancel'); ?></a>
+ </div>
+
+ <input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo $item_id; ?>]" value="<?php echo $item_id; ?>" />
+ <input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object_id ); ?>" />
+ <input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object ); ?>" />
+ <input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_item_parent ); ?>" />
+ <input class="menu-item-data-position" type="hidden" name="menu-item-position[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_order ); ?>" />
+ <input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->type ); ?>" />
+ </div><!-- .menu-item-settings-->
+ <ul class="menu-item-transport"></ul>
+ <?php
+ $output .= ob_get_clean();
+ }
+}
+
+/**
+ * Create HTML list of nav menu input items.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ * @uses Walker_Nav_Menu
+ */
+class Walker_Nav_Menu_Checklist extends Walker_Nav_Menu {
+ function __construct( $fields = false ) {
+ if ( $fields ) {
+ $this->db_fields = $fields;
+ }
+ }
+
+ function start_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat( "\t", $depth );
+ $output .= "\n$indent<ul class='children'>\n";
+ }
+
+ function end_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat( "\t", $depth );
+ $output .= "\n$indent</ul>";
+ }
+
+ /**
+ * @see Walker::start_el()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $item Menu item data object.
+ * @param int $depth Depth of menu item. Used for padding.
+ * @param object $args
+ */
+ function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
+ global $_nav_menu_placeholder;
+
+ $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
+ $possible_object_id = isset( $item->post_type ) && 'nav_menu_item' == $item->post_type ? $item->object_id : $_nav_menu_placeholder;
+ $possible_db_id = ( ! empty( $item->ID ) ) && ( 0 < $possible_object_id ) ? (int) $item->ID : 0;
+
+ $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
+
+ $output .= $indent . '<li>';
+ $output .= '<label class="menu-item-title">';
+ $output .= '<input type="checkbox" class="menu-item-checkbox';
+ if ( property_exists( $item, 'front_or_home' ) && $item->front_or_home ) {
+ $title = sprintf( _x( 'Home: %s', 'nav menu front page title' ), $item->post_title );
+ $output .= ' add-to-top';
+ } elseif ( property_exists( $item, 'label' ) ) {
+ $title = $item->label;
+ }
+ $output .= '" name="menu-item[' . $possible_object_id . '][menu-item-object-id]" value="'. esc_attr( $item->object_id ) .'" /> ';
+ $output .= isset( $title ) ? esc_html( $title ) : esc_html( $item->title );
+ $output .= '</label>';
+
+ // Menu item hidden fields
+ $output .= '<input type="hidden" class="menu-item-db-id" name="menu-item[' . $possible_object_id . '][menu-item-db-id]" value="' . $possible_db_id . '" />';
+ $output .= '<input type="hidden" class="menu-item-object" name="menu-item[' . $possible_object_id . '][menu-item-object]" value="'. esc_attr( $item->object ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-parent-id" name="menu-item[' . $possible_object_id . '][menu-item-parent-id]" value="'. esc_attr( $item->menu_item_parent ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-type" name="menu-item[' . $possible_object_id . '][menu-item-type]" value="'. esc_attr( $item->type ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-title" name="menu-item[' . $possible_object_id . '][menu-item-title]" value="'. esc_attr( $item->title ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-url" name="menu-item[' . $possible_object_id . '][menu-item-url]" value="'. esc_attr( $item->url ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-target" name="menu-item[' . $possible_object_id . '][menu-item-target]" value="'. esc_attr( $item->target ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-attr_title" name="menu-item[' . $possible_object_id . '][menu-item-attr_title]" value="'. esc_attr( $item->attr_title ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-classes" name="menu-item[' . $possible_object_id . '][menu-item-classes]" value="'. esc_attr( implode( ' ', $item->classes ) ) .'" />';
+ $output .= '<input type="hidden" class="menu-item-xfn" name="menu-item[' . $possible_object_id . '][menu-item-xfn]" value="'. esc_attr( $item->xfn ) .'" />';
+ }
+}
+
+/**
+ * Prints the appropriate response to a menu quick search.
+ *
+ * @since 3.0.0
+ *
+ * @param array $request The unsanitized request values.
+ */
+function _wp_ajax_menu_quick_search( $request = array() ) {
+ $args = array();
+ $type = isset( $request['type'] ) ? $request['type'] : '';
+ $object_type = isset( $request['object_type'] ) ? $request['object_type'] : '';
+ $query = isset( $request['q'] ) ? $request['q'] : '';
+ $response_format = isset( $request['response-format'] ) && in_array( $request['response-format'], array( 'json', 'markup' ) ) ? $request['response-format'] : 'json';
+
+ if ( 'markup' == $response_format ) {
+ $args['walker'] = new Walker_Nav_Menu_Checklist;
+ }
+
+ if ( 'get-post-item' == $type ) {
+ if ( post_type_exists( $object_type ) ) {
+ if ( isset( $request['ID'] ) ) {
+ $object_id = (int) $request['ID'];
+ if ( 'markup' == $response_format ) {
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_post( $object_id ) ) ), 0, (object) $args );
+ } elseif ( 'json' == $response_format ) {
+ $post_obj = get_post( $object_id );
+ echo json_encode(
+ array(
+ 'ID' => $object_id,
+ 'post_title' => get_the_title( $object_id ),
+ 'post_type' => get_post_type( $object_id ),
+ )
+ );
+ echo "\n";
+ }
+ }
+ } elseif ( taxonomy_exists( $object_type ) ) {
+ if ( isset( $request['ID'] ) ) {
+ $object_id = (int) $request['ID'];
+ if ( 'markup' == $response_format ) {
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_term( $object_id, $object_type ) ) ), 0, (object) $args );
+ } elseif ( 'json' == $response_format ) {
+ $post_obj = get_term( $object_id, $object_type );
+ echo json_encode(
+ array(
+ 'ID' => $object_id,
+ 'post_title' => $post_obj->name,
+ 'post_type' => $object_type,
+ )
+ );
+ echo "\n";
+ }
+ }
+
+ }
+
+ } elseif ( preg_match('/quick-search-(posttype|taxonomy)-([a-zA-Z_-]*\b)/', $type, $matches) ) {
+ if ( 'posttype' == $matches[1] && get_post_type_object( $matches[2] ) ) {
+ query_posts(array(
+ 'posts_per_page' => 10,
+ 'post_type' => $matches[2],
+ 's' => $query,
+ ));
+ if ( ! have_posts() )
+ return;
+ while ( have_posts() ) {
+ the_post();
+ if ( 'markup' == $response_format ) {
+ $var_by_ref = get_the_ID();
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( get_post( $var_by_ref ) ) ), 0, (object) $args );
+ } elseif ( 'json' == $response_format ) {
+ echo json_encode(
+ array(
+ 'ID' => get_the_ID(),
+ 'post_title' => get_the_title(),
+ 'post_type' => get_post_type(),
+ )
+ );
+ echo "\n";
+ }
+ }
+ } elseif ( 'taxonomy' == $matches[1] ) {
+ $terms = get_terms( $matches[2], array(
+ 'name__like' => $query,
+ 'number' => 10,
+ ));
+ if ( empty( $terms ) || is_wp_error( $terms ) )
+ return;
+ foreach( (array) $terms as $term ) {
+ if ( 'markup' == $response_format ) {
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', array( $term ) ), 0, (object) $args );
+ } elseif ( 'json' == $response_format ) {
+ echo json_encode(
+ array(
+ 'ID' => $term->term_id,
+ 'post_title' => $term->name,
+ 'post_type' => $matches[2],
+ )
+ );
+ echo "\n";
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Register nav menu metaboxes and advanced menu items
+ *
+ * @since 3.0.0
+ **/
+function wp_nav_menu_setup() {
+ // Register meta boxes
+ wp_nav_menu_post_type_meta_boxes();
+ add_meta_box( 'add-custom-links', __( 'Links' ), 'wp_nav_menu_item_link_meta_box', 'nav-menus', 'side', 'default' );
+ wp_nav_menu_taxonomy_meta_boxes();
+
+ // Register advanced menu items (columns)
+ add_filter( 'manage_nav-menus_columns', 'wp_nav_menu_manage_columns' );
+
+ // If first time editing, disable advanced items by default.
+ if( false === get_user_option( 'managenav-menuscolumnshidden' ) ) {
+ $user = wp_get_current_user();
+ update_user_option($user->ID, 'managenav-menuscolumnshidden',
+ array( 0 => 'link-target', 1 => 'css-classes', 2 => 'xfn', 3 => 'description', ),
+ true);
+ }
+}
+
+/**
+ * Limit the amount of meta boxes to just links, pages and cats for first time users.
+ *
+ * @since 3.0.0
+ **/
+function wp_initial_nav_menu_meta_boxes() {
+ global $wp_meta_boxes;
+
+ if ( get_user_option( 'metaboxhidden_nav-menus' ) !== false || ! is_array($wp_meta_boxes) )
+ return;
+
+ $initial_meta_boxes = array( 'nav-menu-theme-locations', 'add-page', 'add-custom-links', 'add-category' );
+ $hidden_meta_boxes = array();
+
+ foreach ( array_keys($wp_meta_boxes['nav-menus']) as $context ) {
+ foreach ( array_keys($wp_meta_boxes['nav-menus'][$context]) as $priority ) {
+ foreach ( $wp_meta_boxes['nav-menus'][$context][$priority] as $box ) {
+ if ( in_array( $box['id'], $initial_meta_boxes ) ) {
+ unset( $box['id'] );
+ } else {
+ $hidden_meta_boxes[] = $box['id'];
+ }
+ }
+ }
+ }
+
+ $user = wp_get_current_user();
+ update_user_option( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes, true );
+}
+
+/**
+ * Creates metaboxes for any post type menu item.
+ *
+ * @since 3.0.0
+ */
+function wp_nav_menu_post_type_meta_boxes() {
+ $post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
+
+ if ( ! $post_types )
+ return;
+
+ foreach ( $post_types as $post_type ) {
+ $post_type = apply_filters( 'nav_menu_meta_box_object', $post_type );
+ if ( $post_type ) {
+ $id = $post_type->name;
+ // give pages a higher priority
+ $priority = ( 'page' == $post_type->name ? 'core' : 'default' );
+ add_meta_box( "add-{$id}", $post_type->labels->name, 'wp_nav_menu_item_post_type_meta_box', 'nav-menus', 'side', $priority, $post_type );
+ }
+ }
+}
+
+/**
+ * Creates metaboxes for any taxonomy menu item.
+ *
+ * @since 3.0.0
+ */
+function wp_nav_menu_taxonomy_meta_boxes() {
+ $taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' );
+
+ if ( !$taxonomies )
+ return;
+
+ foreach ( $taxonomies as $tax ) {
+ $tax = apply_filters( 'nav_menu_meta_box_object', $tax );
+ if ( $tax ) {
+ $id = $tax->name;
+ add_meta_box( "add-{$id}", $tax->labels->name, 'wp_nav_menu_item_taxonomy_meta_box', 'nav-menus', 'side', 'default', $tax );
+ }
+ }
+}
+
+/**
+ * Displays a metabox for the nav menu theme locations.
+ *
+ * @since 3.0.0
+ */
+function wp_nav_menu_locations_meta_box() {
+ global $nav_menu_selected_id;
+
+ if ( ! current_theme_supports( 'menus' ) ) {
+ // We must only support widgets. Leave a message and bail.
+ echo '<p class="howto">' . __('The current theme does not natively support menus, but you can use the &#8220;Custom Menu&#8221; widget to add any menus you create here to the theme&#8217;s sidebar.') . '</p>';
+ return;
+ }
+
+ $locations = get_registered_nav_menus();
+ $menus = wp_get_nav_menus();
+ $menu_locations = get_nav_menu_locations();
+ $num_locations = count( array_keys($locations) );
+
+ echo '<p class="howto">' . _n( 'Select a menu to use within your theme.', 'Select the menus you will use in your theme.', $num_locations ) . '</p>';
+
+ foreach ( $locations as $location => $description ) {
+ ?>
+ <p>
+ <label class="howto" for="locations-<?php echo $location; ?>">
+ <span><?php echo $description; ?></span>
+ <select name="menu-locations[<?php echo $location; ?>]" id="locations-<?php echo $location; ?>">
+ <option value="0"></option>
+ <?php foreach ( $menus as $menu ) : ?>
+ <option<?php selected( isset( $menu_locations[ $location ] ) && $menu_locations[ $location ] == $menu->term_id ); ?>
+ value="<?php echo $menu->term_id; ?>"><?php echo wp_html_excerpt( $menu->name, 40, '&hellip;' ); ?></option>
+ <?php endforeach; ?>
+ </select>
+ </label>
+ </p>
+ <?php
+ }
+ ?>
+ <p class="button-controls">
+ <?php submit_button( __( 'Save' ), 'primary right', 'nav-menu-locations', false, wp_nav_menu_disabled_check( $nav_menu_selected_id ) ); ?>
+ <span class="spinner"></span>
+ </p>
+ <?php
+}
+
+/**
+ * Check whether to disable the Menu Locations meta box submit button
+ *
+ * @since 3.6.0
+ *
+ * @uses global $one_theme_location_no_menus to determine if no menus exist
+ * @uses disabled() to output the disabled attribute in $other_attributes param in submit_button()
+ *
+ * @param int|string $nav_menu_selected_id (id, name or slug) of the currently-selected menu
+ * @return string Disabled attribute if at least one menu exists, false if not
+*/
+function wp_nav_menu_disabled_check( $nav_menu_selected_id ) {
+ global $one_theme_location_no_menus;
+
+ if ( $one_theme_location_no_menus )
+ return false;
+
+ return disabled( $nav_menu_selected_id, 0 );
+}
+
+/**
+ * Displays a metabox for the custom links menu item.
+ *
+ * @since 3.0.0
+ */
+function wp_nav_menu_item_link_meta_box() {
+ global $_nav_menu_placeholder, $nav_menu_selected_id;
+
+ $_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1;
+
+ ?>
+ <div class="customlinkdiv" id="customlinkdiv">
+ <input type="hidden" value="custom" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" />
+ <p id="menu-item-url-wrap">
+ <label class="howto" for="custom-menu-item-url">
+ <span><?php _e('URL'); ?></span>
+ <input id="custom-menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" type="text" class="code menu-item-textbox" value="http://" />
+ </label>
+ </p>
+
+ <p id="menu-item-name-wrap">
+ <label class="howto" for="custom-menu-item-name">
+ <span><?php _e( 'Link Text' ); ?></span>
+ <input id="custom-menu-item-name" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" type="text" class="regular-text menu-item-textbox input-with-default-title" title="<?php esc_attr_e('Menu Item'); ?>" />
+ </label>
+ </p>
+
+ <p class="button-controls">
+ <span class="add-to-menu">
+ <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e('Add to Menu'); ?>" name="add-custom-menu-item" id="submit-customlinkdiv" />
+ <span class="spinner"></span>
+ </span>
+ </p>
+
+ </div><!-- /.customlinkdiv -->
+ <?php
+}
+
+/**
+ * Displays a metabox for a post type menu item.
+ *
+ * @since 3.0.0
+ *
+ * @param string $object Not used.
+ * @param string $post_type The post type object.
+ */
+function wp_nav_menu_item_post_type_meta_box( $object, $post_type ) {
+ global $_nav_menu_placeholder, $nav_menu_selected_id;
+
+ $post_type_name = $post_type['args']->name;
+
+ // paginate browsing for large numbers of post objects
+ $per_page = 50;
+ $pagenum = isset( $_REQUEST[$post_type_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
+ $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
+
+ $args = array(
+ 'offset' => $offset,
+ 'order' => 'ASC',
+ 'orderby' => 'title',
+ 'posts_per_page' => $per_page,
+ 'post_type' => $post_type_name,
+ 'suppress_filters' => true,
+ 'update_post_term_cache' => false,
+ 'update_post_meta_cache' => false
+ );
+
+ if ( isset( $post_type['args']->_default_query ) )
+ $args = array_merge($args, (array) $post_type['args']->_default_query );
+
+ // @todo transient caching of these results with proper invalidation on updating of a post of this type
+ $get_posts = new WP_Query;
+ $posts = $get_posts->query( $args );
+ if ( ! $get_posts->post_count ) {
+ echo '<p>' . __( 'No items.' ) . '</p>';
+ return;
+ }
+
+ $post_type_object = get_post_type_object($post_type_name);
+
+ $num_pages = $get_posts->max_num_pages;
+
+ $page_links = paginate_links( array(
+ 'base' => add_query_arg(
+ array(
+ $post_type_name . '-tab' => 'all',
+ 'paged' => '%#%',
+ 'item-type' => 'post_type',
+ 'item-object' => $post_type_name,
+ )
+ ),
+ 'format' => '',
+ 'prev_text' => __('&laquo;'),
+ 'next_text' => __('&raquo;'),
+ 'total' => $num_pages,
+ 'current' => $pagenum
+ ));
+
+ if ( !$posts )
+ $error = '<li id="error">'. $post_type['args']->labels->not_found .'</li>';
+
+ $db_fields = false;
+ if ( is_post_type_hierarchical( $post_type_name ) ) {
+ $db_fields = array( 'parent' => 'post_parent', 'id' => 'ID' );
+ }
+
+ $walker = new Walker_Nav_Menu_Checklist( $db_fields );
+
+ $current_tab = 'most-recent';
+ if ( isset( $_REQUEST[$post_type_name . '-tab'] ) && in_array( $_REQUEST[$post_type_name . '-tab'], array('all', 'search') ) ) {
+ $current_tab = $_REQUEST[$post_type_name . '-tab'];
+ }
+
+ if ( ! empty( $_REQUEST['quick-search-posttype-' . $post_type_name] ) ) {
+ $current_tab = 'search';
+ }
+
+ $removed_args = array(
+ 'action',
+ 'customlink-tab',
+ 'edit-menu-item',
+ 'menu-item',
+ 'page-tab',
+ '_wpnonce',
+ );
+
+ ?>
+ <div id="posttype-<?php echo $post_type_name; ?>" class="posttypediv">
+ <ul id="posttype-<?php echo $post_type_name; ?>-tabs" class="posttype-tabs add-menu-item-tabs">
+ <li <?php echo ( 'most-recent' == $current_tab ? ' class="tabs"' : '' ); ?>>
+ <a class="nav-tab-link" data-type="tabs-panel-posttype-<?php echo esc_attr( $post_type_name ); ?>-most-recent" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($post_type_name . '-tab', 'most-recent', remove_query_arg($removed_args))); ?>#tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent">
+ <?php _e( 'Most Recent' ); ?>
+ </a>
+ </li>
+ <li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>>
+ <a class="nav-tab-link" data-type="<?php echo esc_attr( $post_type_name ); ?>-all" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($post_type_name . '-tab', 'all', remove_query_arg($removed_args))); ?>#<?php echo $post_type_name; ?>-all">
+ <?php _e( 'View All' ); ?>
+ </a>
+ </li>
+ <li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>>
+ <a class="nav-tab-link" data-type="tabs-panel-posttype-<?php echo esc_attr( $post_type_name ); ?>-search" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($post_type_name . '-tab', 'search', remove_query_arg($removed_args))); ?>#tabs-panel-posttype-<?php echo $post_type_name; ?>-search">
+ <?php _e( 'Search'); ?>
+ </a>
+ </li>
+ </ul><!-- .posttype-tabs -->
+
+ <div id="tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent" class="tabs-panel <?php
+ echo ( 'most-recent' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
+ ?>">
+ <ul id="<?php echo $post_type_name; ?>checklist-most-recent" class="categorychecklist form-no-clear">
+ <?php
+ $recent_args = array_merge( $args, array( 'orderby' => 'post_date', 'order' => 'DESC', 'posts_per_page' => 15 ) );
+ $most_recent = $get_posts->query( $recent_args );
+ $args['walker'] = $walker;
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $most_recent), 0, (object) $args );
+ ?>
+ </ul>
+ </div><!-- /.tabs-panel -->
+
+ <div class="tabs-panel <?php
+ echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
+ ?>" id="tabs-panel-posttype-<?php echo $post_type_name; ?>-search">
+ <?php
+ if ( isset( $_REQUEST['quick-search-posttype-' . $post_type_name] ) ) {
+ $searched = esc_attr( $_REQUEST['quick-search-posttype-' . $post_type_name] );
+ $search_results = get_posts( array( 's' => $searched, 'post_type' => $post_type_name, 'fields' => 'all', 'order' => 'DESC', ) );
+ } else {
+ $searched = '';
+ $search_results = array();
+ }
+ ?>
+ <p class="quick-search-wrap">
+ <input type="search" class="quick-search input-with-default-title" title="<?php esc_attr_e('Search'); ?>" value="<?php echo $searched; ?>" name="quick-search-posttype-<?php echo $post_type_name; ?>" />
+ <span class="spinner"></span>
+ <?php submit_button( __( 'Search' ), 'button-small quick-search-submit button-secondary hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-posttype-' . $post_type_name ) ); ?>
+ </p>
+
+ <ul id="<?php echo $post_type_name; ?>-search-checklist" data-wp-lists="list:<?php echo $post_type_name?>" class="categorychecklist form-no-clear">
+ <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
+ <?php
+ $args['walker'] = $walker;
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $search_results), 0, (object) $args );
+ ?>
+ <?php elseif ( is_wp_error( $search_results ) ) : ?>
+ <li><?php echo $search_results->get_error_message(); ?></li>
+ <?php elseif ( ! empty( $searched ) ) : ?>
+ <li><?php _e('No results found.'); ?></li>
+ <?php endif; ?>
+ </ul>
+ </div><!-- /.tabs-panel -->
+
+ <div id="<?php echo $post_type_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
+ echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
+ ?>">
+ <?php if ( ! empty( $page_links ) ) : ?>
+ <div class="add-menu-item-pagelinks">
+ <?php echo $page_links; ?>
+ </div>
+ <?php endif; ?>
+ <ul id="<?php echo $post_type_name; ?>checklist" data-wp-lists="list:<?php echo $post_type_name?>" class="categorychecklist form-no-clear">
+ <?php
+ $args['walker'] = $walker;
+
+ // if we're dealing with pages, let's put a checkbox for the front page at the top of the list
+ if ( 'page' == $post_type_name ) {
+ $front_page = 'page' == get_option('show_on_front') ? (int) get_option( 'page_on_front' ) : 0;
+ if ( ! empty( $front_page ) ) {
+ $front_page_obj = get_post( $front_page );
+ $front_page_obj->front_or_home = true;
+ array_unshift( $posts, $front_page_obj );
+ } else {
+ $_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
+ array_unshift( $posts, (object) array(
+ 'front_or_home' => true,
+ 'ID' => 0,
+ 'object_id' => $_nav_menu_placeholder,
+ 'post_content' => '',
+ 'post_excerpt' => '',
+ 'post_parent' => '',
+ 'post_title' => _x('Home', 'nav menu home label'),
+ 'post_type' => 'nav_menu_item',
+ 'type' => 'custom',
+ 'url' => home_url('/'),
+ ) );
+ }
+ }
+
+ $posts = apply_filters( 'nav_menu_items_'.$post_type_name, $posts, $args, $post_type );
+ $checkbox_items = walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $posts), 0, (object) $args );
+
+ if ( 'all' == $current_tab && ! empty( $_REQUEST['selectall'] ) ) {
+ $checkbox_items = preg_replace('/(type=(.)checkbox(\2))/', '$1 checked=$2checked$2', $checkbox_items);
+
+ }
+
+ echo $checkbox_items;
+ ?>
+ </ul>
+ <?php if ( ! empty( $page_links ) ) : ?>
+ <div class="add-menu-item-pagelinks">
+ <?php echo $page_links; ?>
+ </div>
+ <?php endif; ?>
+ </div><!-- /.tabs-panel -->
+
+ <p class="button-controls">
+ <span class="list-controls">
+ <a href="<?php
+ echo esc_url( add_query_arg(
+ array(
+ $post_type_name . '-tab' => 'all',
+ 'selectall' => 1,
+ ),
+ remove_query_arg( $removed_args )
+ ));
+ ?>#posttype-<?php echo $post_type_name; ?>" class="select-all"><?php _e('Select All'); ?></a>
+ </span>
+
+ <span class="add-to-menu">
+ <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( __( 'Add to Menu' ) ); ?>" name="add-post-type-menu-item" id="<?php esc_attr_e( 'submit-posttype-' . $post_type_name ); ?>" />
+ <span class="spinner"></span>
+ </span>
+ </p>
+
+ </div><!-- /.posttypediv -->
+ <?php
+}
+
+/**
+ * Displays a metabox for a taxonomy menu item.
+ *
+ * @since 3.0.0
+ *
+ * @param string $object Not used.
+ * @param string $taxonomy The taxonomy object.
+ */
+function wp_nav_menu_item_taxonomy_meta_box( $object, $taxonomy ) {
+ global $nav_menu_selected_id;
+ $taxonomy_name = $taxonomy['args']->name;
+
+ // paginate browsing for large numbers of objects
+ $per_page = 50;
+ $pagenum = isset( $_REQUEST[$taxonomy_name . '-tab'] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
+ $offset = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
+
+ $args = array(
+ 'child_of' => 0,
+ 'exclude' => '',
+ 'hide_empty' => false,
+ 'hierarchical' => 1,
+ 'include' => '',
+ 'number' => $per_page,
+ 'offset' => $offset,
+ 'order' => 'ASC',
+ 'orderby' => 'name',
+ 'pad_counts' => false,
+ );
+
+ $terms = get_terms( $taxonomy_name, $args );
+
+ if ( ! $terms || is_wp_error($terms) ) {
+ echo '<p>' . __( 'No items.' ) . '</p>';
+ return;
+ }
+
+ $num_pages = ceil( wp_count_terms( $taxonomy_name , array_merge( $args, array('number' => '', 'offset' => '') ) ) / $per_page );
+
+ $page_links = paginate_links( array(
+ 'base' => add_query_arg(
+ array(
+ $taxonomy_name . '-tab' => 'all',
+ 'paged' => '%#%',
+ 'item-type' => 'taxonomy',
+ 'item-object' => $taxonomy_name,
+ )
+ ),
+ 'format' => '',
+ 'prev_text' => __('&laquo;'),
+ 'next_text' => __('&raquo;'),
+ 'total' => $num_pages,
+ 'current' => $pagenum
+ ));
+
+ $db_fields = false;
+ if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
+ $db_fields = array( 'parent' => 'parent', 'id' => 'term_id' );
+ }
+
+ $walker = new Walker_Nav_Menu_Checklist( $db_fields );
+
+ $current_tab = 'most-used';
+ if ( isset( $_REQUEST[$taxonomy_name . '-tab'] ) && in_array( $_REQUEST[$taxonomy_name . '-tab'], array('all', 'most-used', 'search') ) ) {
+ $current_tab = $_REQUEST[$taxonomy_name . '-tab'];
+ }
+
+ if ( ! empty( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
+ $current_tab = 'search';
+ }
+
+ $removed_args = array(
+ 'action',
+ 'customlink-tab',
+ 'edit-menu-item',
+ 'menu-item',
+ 'page-tab',
+ '_wpnonce',
+ );
+
+ ?>
+ <div id="taxonomy-<?php echo $taxonomy_name; ?>" class="taxonomydiv">
+ <ul id="taxonomy-<?php echo $taxonomy_name; ?>-tabs" class="taxonomy-tabs add-menu-item-tabs">
+ <li <?php echo ( 'most-used' == $current_tab ? ' class="tabs"' : '' ); ?>>
+ <a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-pop" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'most-used', remove_query_arg($removed_args))); ?>#tabs-panel-<?php echo $taxonomy_name; ?>-pop">
+ <?php _e( 'Most Used' ); ?>
+ </a>
+ </li>
+ <li <?php echo ( 'all' == $current_tab ? ' class="tabs"' : '' ); ?>>
+ <a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-all" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'all', remove_query_arg($removed_args))); ?>#tabs-panel-<?php echo $taxonomy_name; ?>-all">
+ <?php _e( 'View All' ); ?>
+ </a>
+ </li>
+ <li <?php echo ( 'search' == $current_tab ? ' class="tabs"' : '' ); ?>>
+ <a class="nav-tab-link" data-type="tabs-panel-search-taxonomy-<?php echo esc_attr( $taxonomy_name ); ?>" href="<?php if ( $nav_menu_selected_id ) echo esc_url(add_query_arg($taxonomy_name . '-tab', 'search', remove_query_arg($removed_args))); ?>#tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
+ <?php _e( 'Search' ); ?>
+ </a>
+ </li>
+ </ul><!-- .taxonomy-tabs -->
+
+ <div id="tabs-panel-<?php echo $taxonomy_name; ?>-pop" class="tabs-panel <?php
+ echo ( 'most-used' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
+ ?>">
+ <ul id="<?php echo $taxonomy_name; ?>checklist-pop" class="categorychecklist form-no-clear" >
+ <?php
+ $popular_terms = get_terms( $taxonomy_name, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
+ $args['walker'] = $walker;
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $popular_terms), 0, (object) $args );
+ ?>
+ </ul>
+ </div><!-- /.tabs-panel -->
+
+ <div id="tabs-panel-<?php echo $taxonomy_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php
+ echo ( 'all' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
+ ?>">
+ <?php if ( ! empty( $page_links ) ) : ?>
+ <div class="add-menu-item-pagelinks">
+ <?php echo $page_links; ?>
+ </div>
+ <?php endif; ?>
+ <ul id="<?php echo $taxonomy_name; ?>checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
+ <?php
+ $args['walker'] = $walker;
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $terms), 0, (object) $args );
+ ?>
+ </ul>
+ <?php if ( ! empty( $page_links ) ) : ?>
+ <div class="add-menu-item-pagelinks">
+ <?php echo $page_links; ?>
+ </div>
+ <?php endif; ?>
+ </div><!-- /.tabs-panel -->
+
+ <div class="tabs-panel <?php
+ echo ( 'search' == $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' );
+ ?>" id="tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
+ <?php
+ if ( isset( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] ) ) {
+ $searched = esc_attr( $_REQUEST['quick-search-taxonomy-' . $taxonomy_name] );
+ $search_results = get_terms( $taxonomy_name, array( 'name__like' => $searched, 'fields' => 'all', 'orderby' => 'count', 'order' => 'DESC', 'hierarchical' => false ) );
+ } else {
+ $searched = '';
+ $search_results = array();
+ }
+ ?>
+ <p class="quick-search-wrap">
+ <input type="search" class="quick-search input-with-default-title" title="<?php esc_attr_e('Search'); ?>" value="<?php echo $searched; ?>" name="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" />
+ <span class="spinner"></span>
+ <?php submit_button( __( 'Search' ), 'button-small quick-search-submit button-secondary hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-taxonomy-' . $taxonomy_name ) ); ?>
+ </p>
+
+ <ul id="<?php echo $taxonomy_name; ?>-search-checklist" data-wp-lists="list:<?php echo $taxonomy_name?>" class="categorychecklist form-no-clear">
+ <?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
+ <?php
+ $args['walker'] = $walker;
+ echo walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $search_results), 0, (object) $args );
+ ?>
+ <?php elseif ( is_wp_error( $search_results ) ) : ?>
+ <li><?php echo $search_results->get_error_message(); ?></li>
+ <?php elseif ( ! empty( $searched ) ) : ?>
+ <li><?php _e('No results found.'); ?></li>
+ <?php endif; ?>
+ </ul>
+ </div><!-- /.tabs-panel -->
+
+ <p class="button-controls">
+ <span class="list-controls">
+ <a href="<?php
+ echo esc_url(add_query_arg(
+ array(
+ $taxonomy_name . '-tab' => 'all',
+ 'selectall' => 1,
+ ),
+ remove_query_arg($removed_args)
+ ));
+ ?>#taxonomy-<?php echo $taxonomy_name; ?>" class="select-all"><?php _e('Select All'); ?></a>
+ </span>
+
+ <span class="add-to-menu">
+ <input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( __( 'Add to Menu' ) ); ?>" name="add-taxonomy-menu-item" id="<?php esc_attr_e( 'submit-taxonomy-' . $taxonomy_name ); ?>" />
+ <span class="spinner"></span>
+ </span>
+ </p>
+
+ </div><!-- /.taxonomydiv -->
+ <?php
+}
+
+/**
+ * Save posted nav menu item data.
+ *
+ * @since 3.0.0
+ *
+ * @param int $menu_id The menu ID for which to save this item. $menu_id of 0 makes a draft, orphaned menu item.
+ * @param array $menu_data The unsanitized posted menu item data.
+ * @return array The database IDs of the items saved
+ */
+function wp_save_nav_menu_items( $menu_id = 0, $menu_data = array() ) {
+ $menu_id = (int) $menu_id;
+ $items_saved = array();
+
+ if ( 0 == $menu_id || is_nav_menu( $menu_id ) ) {
+
+ // Loop through all the menu items' POST values
+ foreach( (array) $menu_data as $_possible_db_id => $_item_object_data ) {
+ if (
+ empty( $_item_object_data['menu-item-object-id'] ) && // checkbox is not checked
+ (
+ ! isset( $_item_object_data['menu-item-type'] ) || // and item type either isn't set
+ in_array( $_item_object_data['menu-item-url'], array( 'http://', '' ) ) || // or URL is the default
+ ! ( 'custom' == $_item_object_data['menu-item-type'] && ! isset( $_item_object_data['menu-item-db-id'] ) ) || // or it's not a custom menu item (but not the custom home page)
+ ! empty( $_item_object_data['menu-item-db-id'] ) // or it *is* a custom menu item that already exists
+ )
+ ) {
+ continue; // then this potential menu item is not getting added to this menu
+ }
+
+ // if this possible menu item doesn't actually have a menu database ID yet
+ if (
+ empty( $_item_object_data['menu-item-db-id'] ) ||
+ ( 0 > $_possible_db_id ) ||
+ $_possible_db_id != $_item_object_data['menu-item-db-id']
+ ) {
+ $_actual_db_id = 0;
+ } else {
+ $_actual_db_id = (int) $_item_object_data['menu-item-db-id'];
+ }
+
+ $args = array(
+ 'menu-item-db-id' => ( isset( $_item_object_data['menu-item-db-id'] ) ? $_item_object_data['menu-item-db-id'] : '' ),
+ 'menu-item-object-id' => ( isset( $_item_object_data['menu-item-object-id'] ) ? $_item_object_data['menu-item-object-id'] : '' ),
+ 'menu-item-object' => ( isset( $_item_object_data['menu-item-object'] ) ? $_item_object_data['menu-item-object'] : '' ),
+ 'menu-item-parent-id' => ( isset( $_item_object_data['menu-item-parent-id'] ) ? $_item_object_data['menu-item-parent-id'] : '' ),
+ 'menu-item-position' => ( isset( $_item_object_data['menu-item-position'] ) ? $_item_object_data['menu-item-position'] : '' ),
+ 'menu-item-type' => ( isset( $_item_object_data['menu-item-type'] ) ? $_item_object_data['menu-item-type'] : '' ),
+ 'menu-item-title' => ( isset( $_item_object_data['menu-item-title'] ) ? $_item_object_data['menu-item-title'] : '' ),
+ 'menu-item-url' => ( isset( $_item_object_data['menu-item-url'] ) ? $_item_object_data['menu-item-url'] : '' ),
+ 'menu-item-description' => ( isset( $_item_object_data['menu-item-description'] ) ? $_item_object_data['menu-item-description'] : '' ),
+ 'menu-item-attr-title' => ( isset( $_item_object_data['menu-item-attr-title'] ) ? $_item_object_data['menu-item-attr-title'] : '' ),
+ 'menu-item-target' => ( isset( $_item_object_data['menu-item-target'] ) ? $_item_object_data['menu-item-target'] : '' ),
+ 'menu-item-classes' => ( isset( $_item_object_data['menu-item-classes'] ) ? $_item_object_data['menu-item-classes'] : '' ),
+ 'menu-item-xfn' => ( isset( $_item_object_data['menu-item-xfn'] ) ? $_item_object_data['menu-item-xfn'] : '' ),
+ );
+
+ $items_saved[] = wp_update_nav_menu_item( $menu_id, $_actual_db_id, $args );
+
+ }
+ }
+ return $items_saved;
+}
+
+/**
+ * Adds custom arguments to some of the meta box object types.
+ *
+ * @since 3.0.0
+ *
+ * @access private
+ *
+ * @param object $object The post type or taxonomy meta-object.
+ * @return object The post type of taxonomy object.
+ */
+function _wp_nav_menu_meta_box_object( $object = null ) {
+ if ( isset( $object->name ) ) {
+
+ if ( 'page' == $object->name ) {
+ $object->_default_query = array(
+ 'orderby' => 'menu_order title',
+ 'post_status' => 'publish',
+ );
+
+ // posts should show only published items
+ } elseif ( 'post' == $object->name ) {
+ $object->_default_query = array(
+ 'post_status' => 'publish',
+ );
+
+ // cats should be in reverse chronological order
+ } elseif ( 'category' == $object->name ) {
+ $object->_default_query = array(
+ 'orderby' => 'id',
+ 'order' => 'DESC',
+ );
+
+ // custom post types should show only published items
+ } else {
+ $object->_default_query = array(
+ 'post_status' => 'publish',
+ );
+ }
+ }
+
+ return $object;
+}
+
+/**
+ * Returns the menu formatted to edit.
+ *
+ * @since 3.0.0
+ *
+ * @param string $menu_id The ID of the menu to format.
+ * @return string|WP_Error $output The menu formatted to edit or error object on failure.
+ */
+function wp_get_nav_menu_to_edit( $menu_id = 0 ) {
+ $menu = wp_get_nav_menu_object( $menu_id );
+
+ // If the menu exists, get its items.
+ if ( is_nav_menu( $menu ) ) {
+ $menu_items = wp_get_nav_menu_items( $menu->term_id, array('post_status' => 'any') );
+ $result = '<div id="menu-instructions" class="post-body-plain';
+ $result .= ( ! empty($menu_items) ) ? ' menu-instructions-inactive">' : '">';
+ $result .= '<p>' . __( 'Add menu items from the column on the left.' ) . '</p>';
+ $result .= '</div>';
+
+ if( empty($menu_items) )
+ return $result . ' <ul class="menu" id="menu-to-edit"> </ul>';
+
+ $walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $menu_id );
+
+ if ( class_exists( $walker_class_name ) )
+ $walker = new $walker_class_name;
+ else
+ return new WP_Error( 'menu_walker_not_exist', sprintf( __('The Walker class named <strong>%s</strong> does not exist.'), $walker_class_name ) );
+
+ $some_pending_menu_items = $some_invalid_menu_items = false;
+ foreach( (array) $menu_items as $menu_item ) {
+ if ( isset( $menu_item->post_status ) && 'draft' == $menu_item->post_status )
+ $some_pending_menu_items = true;
+ if ( ! empty( $menu_item->_invalid ) )
+ $some_invalid_menu_items = true;
+ }
+
+ if ( $some_pending_menu_items )
+ $result .= '<div class="updated inline"><p>' . __('Click Save Menu to make pending menu items public.') . '</p></div>';
+
+ if ( $some_invalid_menu_items )
+ $result .= '<div class="error inline"><p>' . __('There are some invalid menu items. Please check or delete them.') . '</p></div>';
+
+ $result .= '<ul class="menu" id="menu-to-edit"> ';
+ $result .= walk_nav_menu_tree( array_map('wp_setup_nav_menu_item', $menu_items), 0, (object) array('walker' => $walker ) );
+ $result .= ' </ul> ';
+ return $result;
+ } elseif ( is_wp_error( $menu ) ) {
+ return $menu;
+ }
+
+}
+
+/**
+ * Returns the columns for the nav menus page.
+ *
+ * @since 3.0.0
+ *
+ * @return string|WP_Error $output The menu formatted to edit or error object on failure.
+ */
+function wp_nav_menu_manage_columns() {
+ return array(
+ '_title' => __('Show advanced menu properties'),
+ 'cb' => '<input type="checkbox" />',
+ 'link-target' => __('Link Target'),
+ 'css-classes' => __('CSS Classes'),
+ 'xfn' => __('Link Relationship (XFN)'),
+ 'description' => __('Description'),
+ );
+}
+
+/**
+ * Deletes orphaned draft menu items
+ *
+ * @access private
+ * @since 3.0.0
+ *
+ */
+function _wp_delete_orphaned_draft_menu_items() {
+ global $wpdb;
+ $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
+
+ // delete orphaned draft menu items
+ $menu_items_to_delete = $wpdb->get_col($wpdb->prepare("SELECT ID FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE post_type = 'nav_menu_item' AND post_status = 'draft' AND meta_key = '_menu_item_orphaned' AND meta_value < '%d'", $delete_timestamp ) );
+
+ foreach( (array) $menu_items_to_delete as $menu_item_id )
+ wp_delete_post( $menu_item_id, true );
+}
+add_action('admin_head-nav-menus.php', '_wp_delete_orphaned_draft_menu_items');
+
+/**
+ * Saves nav menu items
+ *
+ * @since 3.6.0
+ *
+ * @uses wp_get_nav_menu_items() to retrieve the nav menu's menu items
+ * @uses wp_defer_term_counter() to enable then disable term counting
+ *
+ * @param int|string $nav_menu_selected_id (id, slug, or name ) of the currently-selected menu
+ * @param string $nav_menu_selected_title Title of the currently-selected menu
+ * @return array $messages The menu updated message
+ */
+function wp_nav_menu_update_menu_items ( $nav_menu_selected_id, $nav_menu_selected_title ) {
+ $unsorted_menu_items = wp_get_nav_menu_items( $nav_menu_selected_id, array( 'orderby' => 'ID', 'output' => ARRAY_A, 'output_key' => 'ID', 'post_status' => 'draft,publish' ) );
+
+ $menu_items = array();
+ // Index menu items by db ID
+ foreach ( $unsorted_menu_items as $_item )
+ $menu_items[$_item->db_id] = $_item;
+
+ $post_fields = array(
+ 'menu-item-db-id', 'menu-item-object-id', 'menu-item-object',
+ 'menu-item-parent-id', 'menu-item-position', 'menu-item-type',
+ 'menu-item-title', 'menu-item-url', 'menu-item-description',
+ 'menu-item-attr-title', 'menu-item-target', 'menu-item-classes', 'menu-item-xfn'
+ );
+
+ wp_defer_term_counting( true );
+ // Loop through all the menu items' POST variables
+ if ( ! empty( $_POST['menu-item-db-id'] ) ) {
+ foreach( (array) $_POST['menu-item-db-id'] as $_key => $k ) {
+
+ // Menu item title can't be blank
+ if ( ! isset( $_POST['menu-item-title'][ $_key ] ) || '' == $_POST['menu-item-title'][ $_key ] )
+ continue;
+
+ $args = array();
+ foreach ( $post_fields as $field )
+ $args[$field] = isset( $_POST[$field][$_key] ) ? $_POST[$field][$_key] : '';
+
+ $menu_item_db_id = wp_update_nav_menu_item( $nav_menu_selected_id, ( $_POST['menu-item-db-id'][$_key] != $_key ? 0 : $_key ), $args );
+
+ if ( is_wp_error( $menu_item_db_id ) )
+ $messages[] = '<div id="message" class="error"><p>' . $menu_item_db_id->get_error_message() . '</p></div>';
+ elseif ( isset( $menu_items[$menu_item_db_id] ) )
+ unset( $menu_items[$menu_item_db_id] );
+ }
+ }
+
+ // Remove menu items from the menu that weren't in $_POST
+ if ( ! empty( $menu_items ) ) {
+ foreach ( array_keys( $menu_items ) as $menu_item_id ) {
+ if ( is_nav_menu_item( $menu_item_id ) ) {
+ wp_delete_post( $menu_item_id );
+ }
+ }
+ }
+
+ // Store 'auto-add' pages.
+ $auto_add = ! empty( $_POST['auto-add-pages'] );
+ $nav_menu_option = (array) get_option( 'nav_menu_options' );
+ if ( ! isset( $nav_menu_option['auto_add'] ) )
+ $nav_menu_option['auto_add'] = array();
+ if ( $auto_add ) {
+ if ( ! in_array( $nav_menu_selected_id, $nav_menu_option['auto_add'] ) )
+ $nav_menu_option['auto_add'][] = $nav_menu_selected_id;
+ } else {
+ if ( false !== ( $key = array_search( $nav_menu_selected_id, $nav_menu_option['auto_add'] ) ) )
+ unset( $nav_menu_option['auto_add'][$key] );
+ }
+ // Remove nonexistent/deleted menus
+ $nav_menu_option['auto_add'] = array_intersect( $nav_menu_option['auto_add'], wp_get_nav_menus( array( 'fields' => 'ids' ) ) );
+ update_option( 'nav_menu_options', $nav_menu_option );
+
+ wp_defer_term_counting( false );
+
+ do_action( 'wp_update_nav_menu', $nav_menu_selected_id );
+
+ $messages[] = '<div id="message" class="updated"><p>' . sprintf( __( '<strong>%1$s</strong> has been updated.' ), $nav_menu_selected_title ) . '</p></div>';
+ unset( $menu_items, $unsorted_menu_items );
+
+ return $messages;
+}
diff --git a/src/wp-admin/includes/plugin-install.php b/src/wp-admin/includes/plugin-install.php
new file mode 100644
index 0000000000..1c07b6856c
--- /dev/null
+++ b/src/wp-admin/includes/plugin-install.php
@@ -0,0 +1,407 @@
+<?php
+/**
+ * WordPress Plugin Install Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Retrieve plugin installer pages from WordPress Plugins API.
+ *
+ * It is possible for a plugin to override the Plugin API result with three
+ * filters. Assume this is for plugins, which can extend on the Plugin Info to
+ * offer more choices. This is very powerful and must be used with care, when
+ * overriding the filters.
+ *
+ * The first filter, 'plugins_api_args', is for the args and gives the action as
+ * the second parameter. The hook for 'plugins_api_args' must ensure that an
+ * object is returned.
+ *
+ * The second filter, 'plugins_api', is the result that would be returned.
+ *
+ * @since 2.7.0
+ *
+ * @param string $action
+ * @param array|object $args Optional. Arguments to serialize for the Plugin Info API.
+ * @return object plugins_api response object on success, WP_Error on failure.
+ */
+function plugins_api($action, $args = null) {
+
+ if ( is_array($args) )
+ $args = (object)$args;
+
+ if ( !isset($args->per_page) )
+ $args->per_page = 24;
+
+ // Allows a plugin to override the WordPress.org API entirely.
+ // Use the filter 'plugins_api_result' to merely add results.
+ // Please ensure that a object is returned from the following filters.
+ $args = apply_filters('plugins_api_args', $args, $action);
+ $res = apply_filters('plugins_api', false, $action, $args);
+
+ if ( false === $res ) {
+ $request = wp_remote_post('http://api.wordpress.org/plugins/info/1.0/', array( 'timeout' => 15, 'body' => array('action' => $action, 'request' => serialize($args))) );
+ if ( is_wp_error($request) ) {
+ $res = new WP_Error('plugins_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="http://wordpress.org/support/">support forums</a>.' ), $request->get_error_message() );
+ } else {
+ $res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
+ if ( ! is_object( $res ) && ! is_array( $res ) )
+ $res = new WP_Error('plugins_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="http://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body( $request ) );
+ }
+ } elseif ( !is_wp_error($res) ) {
+ $res->external = true;
+ }
+
+ return apply_filters('plugins_api_result', $res, $action, $args);
+}
+
+/**
+ * Retrieve popular WordPress plugin tags.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args
+ * @return array
+ */
+function install_popular_tags( $args = array() ) {
+ $key = md5(serialize($args));
+ if ( false !== ($tags = get_site_transient('poptags_' . $key) ) )
+ return $tags;
+
+ $tags = plugins_api('hot_tags', $args);
+
+ if ( is_wp_error($tags) )
+ return $tags;
+
+ set_site_transient( 'poptags_' . $key, $tags, 3 * HOUR_IN_SECONDS );
+
+ return $tags;
+}
+
+function install_dashboard() {
+ ?>
+ <p><?php printf( __( 'Plugins extend and expand the functionality of WordPress. You may automatically install plugins from the <a href="%1$s">WordPress Plugin Directory</a> or upload a plugin in .zip format via <a href="%2$s">this page</a>.' ), 'http://wordpress.org/plugins/', self_admin_url( 'plugin-install.php?tab=upload' ) ); ?></p>
+
+ <h4><?php _e('Search') ?></h4>
+ <?php install_search_form( false ); ?>
+
+ <h4><?php _e('Popular tags') ?></h4>
+ <p class="install-help"><?php _e('You may also browse based on the most popular tags in the Plugin Directory:') ?></p>
+ <?php
+
+ $api_tags = install_popular_tags();
+
+ echo '<p class="popular-tags">';
+ if ( is_wp_error($api_tags) ) {
+ echo $api_tags->get_error_message();
+ } else {
+ //Set up the tags in a way which can be interpreted by wp_generate_tag_cloud()
+ $tags = array();
+ foreach ( (array)$api_tags as $tag )
+ $tags[ $tag['name'] ] = (object) array(
+ 'link' => esc_url( self_admin_url('plugin-install.php?tab=search&type=tag&s=' . urlencode($tag['name'])) ),
+ 'name' => $tag['name'],
+ 'id' => sanitize_title_with_dashes($tag['name']),
+ 'count' => $tag['count'] );
+ echo wp_generate_tag_cloud($tags, array( 'single_text' => __('%s plugin'), 'multiple_text' => __('%s plugins') ) );
+ }
+ echo '</p><br class="clear" />';
+}
+add_action('install_plugins_dashboard', 'install_dashboard');
+
+/**
+ * Display search form for searching plugins.
+ *
+ * @since 2.7.0
+ */
+function install_search_form( $type_selector = true ) {
+ $type = isset($_REQUEST['type']) ? wp_unslash( $_REQUEST['type'] ) : 'term';
+ $term = isset($_REQUEST['s']) ? wp_unslash( $_REQUEST['s'] ) : '';
+
+ ?><form id="search-plugins" method="get" action="">
+ <input type="hidden" name="tab" value="search" />
+ <?php if ( $type_selector ) : ?>
+ <select name="type" id="typeselector">
+ <option value="term"<?php selected('term', $type) ?>><?php _e('Keyword'); ?></option>
+ <option value="author"<?php selected('author', $type) ?>><?php _e('Author'); ?></option>
+ <option value="tag"<?php selected('tag', $type) ?>><?php _ex('Tag', 'Plugin Installer'); ?></option>
+ </select>
+ <?php endif; ?>
+ <input type="search" name="s" value="<?php echo esc_attr($term) ?>" autofocus="autofocus" />
+ <label class="screen-reader-text" for="plugin-search-input"><?php _e('Search Plugins'); ?></label>
+ <?php submit_button( __( 'Search Plugins' ), 'button', 'plugin-search-input', false ); ?>
+ </form><?php
+}
+
+/**
+ * Upload from zip
+ * @since 2.8.0
+ *
+ * @param string $page
+ */
+function install_plugins_upload( $page = 1 ) {
+?>
+ <h4><?php _e('Install a plugin in .zip format'); ?></h4>
+ <p class="install-help"><?php _e('If you have a plugin in a .zip format, you may install it by uploading it here.'); ?></p>
+ <form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-plugin'); ?>">
+ <?php wp_nonce_field( 'plugin-upload'); ?>
+ <label class="screen-reader-text" for="pluginzip"><?php _e('Plugin zip file'); ?></label>
+ <input type="file" id="pluginzip" name="pluginzip" />
+ <?php submit_button( __( 'Install Now' ), 'button', 'install-plugin-submit', false ); ?>
+ </form>
+<?php
+}
+add_action('install_plugins_upload', 'install_plugins_upload', 10, 1);
+
+/**
+ * Show a username form for the favorites page
+ * @since 3.5.0
+ *
+ */
+function install_plugins_favorites_form() {
+ $user = ! empty( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
+ ?>
+ <p class="install-help"><?php _e( 'If you have marked plugins as favorites on WordPress.org, you can browse them here.' ); ?></p>
+ <form method="get" action="">
+ <input type="hidden" name="tab" value="favorites" />
+ <p>
+ <label for="user"><?php _e( 'Your WordPress.org username:' ); ?></label>
+ <input type="search" id="user" name="user" value="<?php echo esc_attr( $user ); ?>" />
+ <input type="submit" class="button" value="<?php esc_attr_e( 'Get Favorites' ); ?>" />
+ </p>
+ </form>
+ <?php
+}
+
+/**
+ * Display plugin content based on plugin list.
+ *
+ * @since 2.7.0
+ */
+function display_plugins_table() {
+ global $wp_list_table;
+
+ if ( current_filter() == 'install_plugins_favorites' && empty( $_GET['user'] ) && ! get_user_option( 'wporg_favorites' ) )
+ return;
+
+ $wp_list_table->display();
+}
+add_action( 'install_plugins_search', 'display_plugins_table' );
+add_action( 'install_plugins_featured', 'display_plugins_table' );
+add_action( 'install_plugins_popular', 'display_plugins_table' );
+add_action( 'install_plugins_new', 'display_plugins_table' );
+add_action( 'install_plugins_favorites', 'display_plugins_table' );
+
+/**
+ * Determine the status we can perform on a plugin.
+ *
+ * @since 3.0.0
+ */
+function install_plugin_install_status($api, $loop = false) {
+ // this function is called recursively, $loop prevents further loops.
+ if ( is_array($api) )
+ $api = (object) $api;
+
+ //Default to a "new" plugin
+ $status = 'install';
+ $url = false;
+
+ //Check to see if this plugin is known to be installed, and has an update awaiting it.
+ $update_plugins = get_site_transient('update_plugins');
+ if ( isset( $update_plugins->response ) ) {
+ foreach ( (array)$update_plugins->response as $file => $plugin ) {
+ if ( $plugin->slug === $api->slug ) {
+ $status = 'update_available';
+ $update_file = $file;
+ $version = $plugin->new_version;
+ if ( current_user_can('update_plugins') )
+ $url = wp_nonce_url(self_admin_url('update.php?action=upgrade-plugin&plugin=' . $update_file), 'upgrade-plugin_' . $update_file);
+ break;
+ }
+ }
+ }
+
+ if ( 'install' == $status ) {
+ if ( is_dir( WP_PLUGIN_DIR . '/' . $api->slug ) ) {
+ $installed_plugin = get_plugins('/' . $api->slug);
+ if ( empty($installed_plugin) ) {
+ if ( current_user_can('install_plugins') )
+ $url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $api->slug), 'install-plugin_' . $api->slug);
+ } else {
+ $key = array_keys( $installed_plugin );
+ $key = array_shift( $key ); //Use the first plugin regardless of the name, Could have issues for multiple-plugins in one directory if they share different version numbers
+ if ( version_compare($api->version, $installed_plugin[ $key ]['Version'], '=') ){
+ $status = 'latest_installed';
+ } elseif ( version_compare($api->version, $installed_plugin[ $key ]['Version'], '<') ) {
+ $status = 'newer_installed';
+ $version = $installed_plugin[ $key ]['Version'];
+ } else {
+ //If the above update check failed, Then that probably means that the update checker has out-of-date information, force a refresh
+ if ( ! $loop ) {
+ delete_site_transient('update_plugins');
+ wp_update_plugins();
+ return install_plugin_install_status($api, true);
+ }
+ }
+ }
+ } else {
+ // "install" & no directory with that slug
+ if ( current_user_can('install_plugins') )
+ $url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $api->slug), 'install-plugin_' . $api->slug);
+ }
+ }
+ if ( isset($_GET['from']) )
+ $url .= '&amp;from=' . urlencode( wp_unslash( $_GET['from'] ) );
+
+ return compact('status', 'url', 'version');
+}
+
+/**
+ * Display plugin information in dialog box form.
+ *
+ * @since 2.7.0
+ */
+function install_plugin_information() {
+ global $tab;
+
+ $api = plugins_api('plugin_information', array('slug' => wp_unslash( $_REQUEST['plugin'] ) ));
+
+ if ( is_wp_error($api) )
+ wp_die($api);
+
+ $plugins_allowedtags = array(
+ 'a' => array( 'href' => array(), 'title' => array(), 'target' => array() ),
+ 'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ),
+ 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(),
+ 'div' => array(), 'p' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(),
+ 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(),
+ 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() )
+ );
+
+ $plugins_section_titles = array(
+ 'description' => _x('Description', 'Plugin installer section title'),
+ 'installation' => _x('Installation', 'Plugin installer section title'),
+ 'faq' => _x('FAQ', 'Plugin installer section title'),
+ 'screenshots' => _x('Screenshots', 'Plugin installer section title'),
+ 'changelog' => _x('Changelog', 'Plugin installer section title'),
+ 'other_notes' => _x('Other Notes', 'Plugin installer section title')
+ );
+
+ //Sanitize HTML
+ foreach ( (array)$api->sections as $section_name => $content )
+ $api->sections[$section_name] = wp_kses($content, $plugins_allowedtags);
+ foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
+ if ( isset( $api->$key ) )
+ $api->$key = wp_kses( $api->$key, $plugins_allowedtags );
+ }
+
+ $section = isset($_REQUEST['section']) ? wp_unslash( $_REQUEST['section'] ) : 'description'; //Default to the Description tab, Do not translate, API returns English.
+ if ( empty($section) || ! isset($api->sections[ $section ]) )
+ $section = array_shift( $section_titles = array_keys((array)$api->sections) );
+
+ iframe_header( __('Plugin Install') );
+ echo "<div id='$tab-header'>\n";
+ echo "<ul id='sidemenu'>\n";
+ foreach ( (array)$api->sections as $section_name => $content ) {
+
+ if ( isset( $plugins_section_titles[ $section_name ] ) )
+ $title = $plugins_section_titles[ $section_name ];
+ else
+ $title = ucwords( str_replace( '_', ' ', $section_name ) );
+
+ $class = ( $section_name == $section ) ? ' class="current"' : '';
+ $href = add_query_arg( array('tab' => $tab, 'section' => $section_name) );
+ $href = esc_url($href);
+ $san_section = esc_attr( $section_name );
+ echo "\t<li><a name='$san_section' href='$href' $class>$title</a></li>\n";
+ }
+ echo "</ul>\n";
+ echo "</div>\n";
+ ?>
+ <div class="alignright fyi">
+ <?php if ( ! empty($api->download_link) && ( current_user_can('install_plugins') || current_user_can('update_plugins') ) ) : ?>
+ <p class="action-button">
+ <?php
+ $status = install_plugin_install_status($api);
+ switch ( $status['status'] ) {
+ case 'install':
+ if ( $status['url'] )
+ echo '<a href="' . $status['url'] . '" target="_parent">' . __('Install Now') . '</a>';
+ break;
+ case 'update_available':
+ if ( $status['url'] )
+ echo '<a href="' . $status['url'] . '" target="_parent">' . __('Install Update Now') .'</a>';
+ break;
+ case 'newer_installed':
+ echo '<a>' . sprintf(__('Newer Version (%s) Installed'), $status['version']) . '</a>';
+ break;
+ case 'latest_installed':
+ echo '<a>' . __('Latest Version Installed') . '</a>';
+ break;
+ }
+ ?>
+ </p>
+ <?php endif; ?>
+ <h2 class="mainheader"><?php /* translators: For Your Information */ _e('FYI') ?></h2>
+ <ul>
+<?php if ( ! empty($api->version) ) : ?>
+ <li><strong><?php _e('Version:') ?></strong> <?php echo $api->version ?></li>
+<?php endif; if ( ! empty($api->author) ) : ?>
+ <li><strong><?php _e('Author:') ?></strong> <?php echo links_add_target($api->author, '_blank') ?></li>
+<?php endif; if ( ! empty($api->last_updated) ) : ?>
+ <li><strong><?php _e('Last Updated:') ?></strong> <span title="<?php echo $api->last_updated ?>"><?php
+ printf( __('%s ago'), human_time_diff(strtotime($api->last_updated)) ) ?></span></li>
+<?php endif; if ( ! empty($api->requires) ) : ?>
+ <li><strong><?php _e('Requires WordPress Version:') ?></strong> <?php printf(__('%s or higher'), $api->requires) ?></li>
+<?php endif; if ( ! empty($api->tested) ) : ?>
+ <li><strong><?php _e('Compatible up to:') ?></strong> <?php echo $api->tested ?></li>
+<?php endif; if ( ! empty($api->downloaded) ) : ?>
+ <li><strong><?php _e('Downloaded:') ?></strong> <?php printf(_n('%s time', '%s times', $api->downloaded), number_format_i18n($api->downloaded)) ?></li>
+<?php endif; if ( ! empty($api->slug) && empty($api->external) ) : ?>
+ <li><a target="_blank" href="http://wordpress.org/plugins/<?php echo $api->slug ?>/"><?php _e('WordPress.org Plugin Page &#187;') ?></a></li>
+<?php endif; if ( ! empty($api->homepage) ) : ?>
+ <li><a target="_blank" href="<?php echo $api->homepage ?>"><?php _e('Plugin Homepage &#187;') ?></a></li>
+<?php endif; ?>
+ </ul>
+ <?php if ( ! empty($api->rating) ) : ?>
+ <h2><?php _e('Average Rating') ?></h2>
+ <div class="star-holder" title="<?php printf(_n('(based on %s rating)', '(based on %s ratings)', $api->num_ratings), number_format_i18n($api->num_ratings)); ?>">
+ <div class="star star-rating" style="width: <?php echo esc_attr( str_replace( ',', '.', $api->rating ) ); ?>px"></div>
+ </div>
+ <small><?php printf(_n('(based on %s rating)', '(based on %s ratings)', $api->num_ratings), number_format_i18n($api->num_ratings)); ?></small>
+ <?php endif; ?>
+ </div>
+ <div id="section-holder" class="wrap">
+ <?php
+ if ( !empty($api->tested) && version_compare( substr($GLOBALS['wp_version'], 0, strlen($api->tested)), $api->tested, '>') )
+ echo '<div class="updated"><p>' . __('<strong>Warning:</strong> This plugin has <strong>not been tested</strong> with your current version of WordPress.') . '</p></div>';
+
+ else if ( !empty($api->requires) && version_compare( substr($GLOBALS['wp_version'], 0, strlen($api->requires)), $api->requires, '<') )
+ echo '<div class="updated"><p>' . __('<strong>Warning:</strong> This plugin has <strong>not been marked as compatible</strong> with your version of WordPress.') . '</p></div>';
+
+ foreach ( (array)$api->sections as $section_name => $content ) {
+
+ if ( isset( $plugins_section_titles[ $section_name ] ) )
+ $title = $plugins_section_titles[ $section_name ];
+ else
+ $title = ucwords( str_replace( '_', ' ', $section_name ) );
+
+ $content = links_add_base_url($content, 'http://wordpress.org/plugins/' . $api->slug . '/');
+ $content = links_add_target($content, '_blank');
+
+ $san_section = esc_attr( $section_name );
+
+ $display = ( $section_name == $section ) ? 'block' : 'none';
+
+ echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
+ echo "\t\t<h2 class='long-header'>$title</h2>";
+ echo $content;
+ echo "\t</div>\n";
+ }
+ echo "</div>\n";
+
+ iframe_footer();
+ exit;
+}
+add_action('install_plugins_pre_plugin-information', 'install_plugin_information');
diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php
new file mode 100644
index 0000000000..109e66d8b7
--- /dev/null
+++ b/src/wp-admin/includes/plugin.php
@@ -0,0 +1,1763 @@
+<?php
+/**
+ * WordPress Plugin Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Parse the plugin contents to retrieve plugin's metadata.
+ *
+ * The metadata of the plugin's data searches for the following in the plugin's
+ * header. All plugin data must be on its own line. For plugin description, it
+ * must not have any newlines or only parts of the description will be displayed
+ * and the same goes for the plugin data. The below is formatted for printing.
+ *
+ * <code>
+ * /*
+ * Plugin Name: Name of Plugin
+ * Plugin URI: Link to plugin information
+ * Description: Plugin Description
+ * Author: Plugin author's name
+ * Author URI: Link to the author's web site
+ * Version: Must be set in the plugin for WordPress 2.3+
+ * Text Domain: Optional. Unique identifier, should be same as the one used in
+ * plugin_text_domain()
+ * Domain Path: Optional. Only useful if the translations are located in a
+ * folder above the plugin's base path. For example, if .mo files are
+ * located in the locale folder then Domain Path will be "/locale/" and
+ * must have the first slash. Defaults to the base folder the plugin is
+ * located in.
+ * Network: Optional. Specify "Network: true" to require that a plugin is activated
+ * across all sites in an installation. This will prevent a plugin from being
+ * activated on a single site when Multisite is enabled.
+ * * / # Remove the space to close comment
+ * </code>
+ *
+ * Plugin data returned array contains the following:
+ * 'Name' - Name of the plugin, must be unique.
+ * 'Title' - Title of the plugin and the link to the plugin's web site.
+ * 'Description' - Description of what the plugin does and/or notes
+ * from the author.
+ * 'Author' - The author's name
+ * 'AuthorURI' - The authors web site address.
+ * 'Version' - The plugin version number.
+ * 'PluginURI' - Plugin web site address.
+ * 'TextDomain' - Plugin's text domain for localization.
+ * 'DomainPath' - Plugin's relative directory path to .mo files.
+ * 'Network' - Boolean. Whether the plugin can only be activated network wide.
+ *
+ * Some users have issues with opening large files and manipulating the contents
+ * for want is usually the first 1kiB or 2kiB. This function stops pulling in
+ * the plugin contents when it has all of the required plugin data.
+ *
+ * The first 8kiB of the file will be pulled in and if the plugin data is not
+ * within that first 8kiB, then the plugin author should correct their plugin
+ * and move the plugin data headers to the top.
+ *
+ * The plugin file is assumed to have permissions to allow for scripts to read
+ * the file. This is not checked however and the file is only opened for
+ * reading.
+ *
+ * @link http://trac.wordpress.org/ticket/5651 Previous Optimizations.
+ * @link http://trac.wordpress.org/ticket/7372 Further and better Optimizations.
+ * @since 1.5.0
+ *
+ * @param string $plugin_file Path to the plugin file
+ * @param bool $markup Optional. If the returned data should have HTML markup applied. Defaults to true.
+ * @param bool $translate Optional. If the returned data should be translated. Defaults to true.
+ * @return array See above for description.
+ */
+function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
+
+ $default_headers = array(
+ 'Name' => 'Plugin Name',
+ 'PluginURI' => 'Plugin URI',
+ 'Version' => 'Version',
+ 'Description' => 'Description',
+ 'Author' => 'Author',
+ 'AuthorURI' => 'Author URI',
+ 'TextDomain' => 'Text Domain',
+ 'DomainPath' => 'Domain Path',
+ 'Network' => 'Network',
+ // Site Wide Only is deprecated in favor of Network.
+ '_sitewide' => 'Site Wide Only',
+ );
+
+ $plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
+
+ // Site Wide Only is the old header for Network
+ if ( ! $plugin_data['Network'] && $plugin_data['_sitewide'] ) {
+ _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The <code>%1$s</code> plugin header is deprecated. Use <code>%2$s</code> instead.' ), 'Site Wide Only: true', 'Network: true' ) );
+ $plugin_data['Network'] = $plugin_data['_sitewide'];
+ }
+ $plugin_data['Network'] = ( 'true' == strtolower( $plugin_data['Network'] ) );
+ unset( $plugin_data['_sitewide'] );
+
+ if ( $markup || $translate ) {
+ $plugin_data = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup, $translate );
+ } else {
+ $plugin_data['Title'] = $plugin_data['Name'];
+ $plugin_data['AuthorName'] = $plugin_data['Author'];
+ }
+
+ return $plugin_data;
+}
+
+/**
+ * Sanitizes plugin data, optionally adds markup, optionally translates.
+ *
+ * @since 2.7.0
+ * @access private
+ * @see get_plugin_data()
+ */
+function _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup = true, $translate = true ) {
+
+ // Translate fields
+ if ( $translate ) {
+ if ( $textdomain = $plugin_data['TextDomain'] ) {
+ if ( $plugin_data['DomainPath'] )
+ load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) . $plugin_data['DomainPath'] );
+ else
+ load_plugin_textdomain( $textdomain, false, dirname( $plugin_file ) );
+ } elseif ( in_array( basename( $plugin_file ), array( 'hello.php', 'akismet.php' ) ) ) {
+ $textdomain = 'default';
+ }
+ if ( $textdomain ) {
+ foreach ( array( 'Name', 'PluginURI', 'Description', 'Author', 'AuthorURI', 'Version' ) as $field )
+ $plugin_data[ $field ] = translate( $plugin_data[ $field ], $textdomain );
+ }
+ }
+
+ // Sanitize fields
+ $allowed_tags = $allowed_tags_in_links = array(
+ 'abbr' => array( 'title' => true ),
+ 'acronym' => array( 'title' => true ),
+ 'code' => true,
+ 'em' => true,
+ 'strong' => true,
+ );
+ $allowed_tags['a'] = array( 'href' => true, 'title' => true );
+
+ // Name is marked up inside <a> tags. Don't allow these.
+ // Author is too, but some plugins have used <a> here (omitting Author URI).
+ $plugin_data['Name'] = wp_kses( $plugin_data['Name'], $allowed_tags_in_links );
+ $plugin_data['Author'] = wp_kses( $plugin_data['Author'], $allowed_tags );
+
+ $plugin_data['Description'] = wp_kses( $plugin_data['Description'], $allowed_tags );
+ $plugin_data['Version'] = wp_kses( $plugin_data['Version'], $allowed_tags );
+
+ $plugin_data['PluginURI'] = esc_url( $plugin_data['PluginURI'] );
+ $plugin_data['AuthorURI'] = esc_url( $plugin_data['AuthorURI'] );
+
+ $plugin_data['Title'] = $plugin_data['Name'];
+ $plugin_data['AuthorName'] = $plugin_data['Author'];
+
+ // Apply markup
+ if ( $markup ) {
+ if ( $plugin_data['PluginURI'] && $plugin_data['Name'] )
+ $plugin_data['Title'] = '<a href="' . $plugin_data['PluginURI'] . '" title="' . esc_attr__( 'Visit plugin homepage' ) . '">' . $plugin_data['Name'] . '</a>';
+
+ if ( $plugin_data['AuthorURI'] && $plugin_data['Author'] )
+ $plugin_data['Author'] = '<a href="' . $plugin_data['AuthorURI'] . '" title="' . esc_attr__( 'Visit author homepage' ) . '">' . $plugin_data['Author'] . '</a>';
+
+ $plugin_data['Description'] = wptexturize( $plugin_data['Description'] );
+
+ if ( $plugin_data['Author'] )
+ $plugin_data['Description'] .= ' <cite>' . sprintf( __('By %s.'), $plugin_data['Author'] ) . '</cite>';
+ }
+
+ return $plugin_data;
+}
+
+/**
+ * Get a list of a plugin's files.
+ *
+ * @since 2.8.0
+ *
+ * @param string $plugin Plugin ID
+ * @return array List of files relative to the plugin root.
+ */
+function get_plugin_files($plugin) {
+ $plugin_file = WP_PLUGIN_DIR . '/' . $plugin;
+ $dir = dirname($plugin_file);
+ $plugin_files = array($plugin);
+ if ( is_dir($dir) && $dir != WP_PLUGIN_DIR ) {
+ $plugins_dir = @ opendir( $dir );
+ if ( $plugins_dir ) {
+ while (($file = readdir( $plugins_dir ) ) !== false ) {
+ if ( substr($file, 0, 1) == '.' )
+ continue;
+ if ( is_dir( $dir . '/' . $file ) ) {
+ $plugins_subdir = @ opendir( $dir . '/' . $file );
+ if ( $plugins_subdir ) {
+ while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
+ if ( substr($subfile, 0, 1) == '.' )
+ continue;
+ $plugin_files[] = plugin_basename("$dir/$file/$subfile");
+ }
+ @closedir( $plugins_subdir );
+ }
+ } else {
+ if ( plugin_basename("$dir/$file") != $plugin )
+ $plugin_files[] = plugin_basename("$dir/$file");
+ }
+ }
+ @closedir( $plugins_dir );
+ }
+ }
+
+ return $plugin_files;
+}
+
+/**
+ * Check the plugins directory and retrieve all plugin files with plugin data.
+ *
+ * WordPress only supports plugin files in the base plugins directory
+ * (wp-content/plugins) and in one directory above the plugins directory
+ * (wp-content/plugins/my-plugin). The file it looks for has the plugin data and
+ * must be found in those two locations. It is recommended that do keep your
+ * plugin files in directories.
+ *
+ * The file with the plugin data is the file that will be included and therefore
+ * needs to have the main execution for the plugin. This does not mean
+ * everything must be contained in the file and it is recommended that the file
+ * be split for maintainability. Keep everything in one file for extreme
+ * optimization purposes.
+ *
+ * @since 1.5.0
+ *
+ * @param string $plugin_folder Optional. Relative path to single plugin folder.
+ * @return array Key is the plugin file path and the value is an array of the plugin data.
+ */
+function get_plugins($plugin_folder = '') {
+
+ if ( ! $cache_plugins = wp_cache_get('plugins', 'plugins') )
+ $cache_plugins = array();
+
+ if ( isset($cache_plugins[ $plugin_folder ]) )
+ return $cache_plugins[ $plugin_folder ];
+
+ $wp_plugins = array ();
+ $plugin_root = WP_PLUGIN_DIR;
+ if ( !empty($plugin_folder) )
+ $plugin_root .= $plugin_folder;
+
+ // Files in wp-content/plugins directory
+ $plugins_dir = @ opendir( $plugin_root);
+ $plugin_files = array();
+ if ( $plugins_dir ) {
+ while (($file = readdir( $plugins_dir ) ) !== false ) {
+ if ( substr($file, 0, 1) == '.' )
+ continue;
+ if ( is_dir( $plugin_root.'/'.$file ) ) {
+ $plugins_subdir = @ opendir( $plugin_root.'/'.$file );
+ if ( $plugins_subdir ) {
+ while (($subfile = readdir( $plugins_subdir ) ) !== false ) {
+ if ( substr($subfile, 0, 1) == '.' )
+ continue;
+ if ( substr($subfile, -4) == '.php' )
+ $plugin_files[] = "$file/$subfile";
+ }
+ closedir( $plugins_subdir );
+ }
+ } else {
+ if ( substr($file, -4) == '.php' )
+ $plugin_files[] = $file;
+ }
+ }
+ closedir( $plugins_dir );
+ }
+
+ if ( empty($plugin_files) )
+ return $wp_plugins;
+
+ foreach ( $plugin_files as $plugin_file ) {
+ if ( !is_readable( "$plugin_root/$plugin_file" ) )
+ continue;
+
+ $plugin_data = get_plugin_data( "$plugin_root/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
+
+ if ( empty ( $plugin_data['Name'] ) )
+ continue;
+
+ $wp_plugins[plugin_basename( $plugin_file )] = $plugin_data;
+ }
+
+ uasort( $wp_plugins, '_sort_uname_callback' );
+
+ $cache_plugins[ $plugin_folder ] = $wp_plugins;
+ wp_cache_set('plugins', $cache_plugins, 'plugins');
+
+ return $wp_plugins;
+}
+
+/**
+ * Check the mu-plugins directory and retrieve all mu-plugin files with any plugin data.
+ *
+ * WordPress only includes mu-plugin files in the base mu-plugins directory (wp-content/mu-plugins).
+ *
+ * @since 3.0.0
+ * @return array Key is the mu-plugin file path and the value is an array of the mu-plugin data.
+ */
+function get_mu_plugins() {
+ $wp_plugins = array();
+ // Files in wp-content/mu-plugins directory
+ $plugin_files = array();
+
+ if ( ! is_dir( WPMU_PLUGIN_DIR ) )
+ return $wp_plugins;
+ if ( $plugins_dir = @ opendir( WPMU_PLUGIN_DIR ) ) {
+ while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
+ if ( substr( $file, -4 ) == '.php' )
+ $plugin_files[] = $file;
+ }
+ } else {
+ return $wp_plugins;
+ }
+
+ @closedir( $plugins_dir );
+
+ if ( empty($plugin_files) )
+ return $wp_plugins;
+
+ foreach ( $plugin_files as $plugin_file ) {
+ if ( !is_readable( WPMU_PLUGIN_DIR . "/$plugin_file" ) )
+ continue;
+
+ $plugin_data = get_plugin_data( WPMU_PLUGIN_DIR . "/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
+
+ if ( empty ( $plugin_data['Name'] ) )
+ $plugin_data['Name'] = $plugin_file;
+
+ $wp_plugins[ $plugin_file ] = $plugin_data;
+ }
+
+ if ( isset( $wp_plugins['index.php'] ) && filesize( WPMU_PLUGIN_DIR . '/index.php') <= 30 ) // silence is golden
+ unset( $wp_plugins['index.php'] );
+
+ uasort( $wp_plugins, '_sort_uname_callback' );
+
+ return $wp_plugins;
+}
+
+/**
+ * Callback to sort array by a 'Name' key.
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _sort_uname_callback( $a, $b ) {
+ return strnatcasecmp( $a['Name'], $b['Name'] );
+}
+
+/**
+ * Check the wp-content directory and retrieve all drop-ins with any plugin data.
+ *
+ * @since 3.0.0
+ * @return array Key is the file path and the value is an array of the plugin data.
+ */
+function get_dropins() {
+ $dropins = array();
+ $plugin_files = array();
+
+ $_dropins = _get_dropins();
+
+ // These exist in the wp-content directory
+ if ( $plugins_dir = @ opendir( WP_CONTENT_DIR ) ) {
+ while ( ( $file = readdir( $plugins_dir ) ) !== false ) {
+ if ( isset( $_dropins[ $file ] ) )
+ $plugin_files[] = $file;
+ }
+ } else {
+ return $dropins;
+ }
+
+ @closedir( $plugins_dir );
+
+ if ( empty($plugin_files) )
+ return $dropins;
+
+ foreach ( $plugin_files as $plugin_file ) {
+ if ( !is_readable( WP_CONTENT_DIR . "/$plugin_file" ) )
+ continue;
+ $plugin_data = get_plugin_data( WP_CONTENT_DIR . "/$plugin_file", false, false ); //Do not apply markup/translate as it'll be cached.
+ if ( empty( $plugin_data['Name'] ) )
+ $plugin_data['Name'] = $plugin_file;
+ $dropins[ $plugin_file ] = $plugin_data;
+ }
+
+ uksort( $dropins, 'strnatcasecmp' );
+
+ return $dropins;
+}
+
+/**
+ * Returns drop-ins that WordPress uses.
+ *
+ * Includes Multisite drop-ins only when is_multisite()
+ *
+ * @since 3.0.0
+ * @return array Key is file name. The value is an array, with the first value the
+ * purpose of the drop-in and the second value the name of the constant that must be
+ * true for the drop-in to be used, or true if no constant is required.
+ */
+function _get_dropins() {
+ $dropins = array(
+ 'advanced-cache.php' => array( __( 'Advanced caching plugin.' ), 'WP_CACHE' ), // WP_CACHE
+ 'db.php' => array( __( 'Custom database class.' ), true ), // auto on load
+ 'db-error.php' => array( __( 'Custom database error message.' ), true ), // auto on error
+ 'install.php' => array( __( 'Custom install script.' ), true ), // auto on install
+ 'maintenance.php' => array( __( 'Custom maintenance message.' ), true ), // auto on maintenance
+ 'object-cache.php' => array( __( 'External object cache.' ), true ), // auto on load
+ );
+
+ if ( is_multisite() ) {
+ $dropins['sunrise.php' ] = array( __( 'Executed before Multisite is loaded.' ), 'SUNRISE' ); // SUNRISE
+ $dropins['blog-deleted.php' ] = array( __( 'Custom site deleted message.' ), true ); // auto on deleted blog
+ $dropins['blog-inactive.php' ] = array( __( 'Custom site inactive message.' ), true ); // auto on inactive blog
+ $dropins['blog-suspended.php'] = array( __( 'Custom site suspended message.' ), true ); // auto on archived or spammed blog
+ }
+
+ return $dropins;
+}
+
+/**
+ * Check whether the plugin is active by checking the active_plugins list.
+ *
+ * @since 2.5.0
+ *
+ * @param string $plugin Base plugin path from plugins directory.
+ * @return bool True, if in the active plugins list. False, not in the list.
+ */
+function is_plugin_active( $plugin ) {
+ return in_array( $plugin, (array) get_option( 'active_plugins', array() ) ) || is_plugin_active_for_network( $plugin );
+}
+
+/**
+ * Check whether the plugin is inactive.
+ *
+ * Reverse of is_plugin_active(). Used as a callback.
+ *
+ * @since 3.1.0
+ * @see is_plugin_active()
+ *
+ * @param string $plugin Base plugin path from plugins directory.
+ * @return bool True if inactive. False if active.
+ */
+function is_plugin_inactive( $plugin ) {
+ return ! is_plugin_active( $plugin );
+}
+
+/**
+ * Check whether the plugin is active for the entire network.
+ *
+ * @since 3.0.0
+ *
+ * @param string $plugin Base plugin path from plugins directory.
+ * @return bool True, if active for the network, otherwise false.
+ */
+function is_plugin_active_for_network( $plugin ) {
+ if ( !is_multisite() )
+ return false;
+
+ $plugins = get_site_option( 'active_sitewide_plugins');
+ if ( isset($plugins[$plugin]) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Checks for "Network: true" in the plugin header to see if this should
+ * be activated only as a network wide plugin. The plugin would also work
+ * when Multisite is not enabled.
+ *
+ * Checks for "Site Wide Only: true" for backwards compatibility.
+ *
+ * @since 3.0.0
+ *
+ * @param string $plugin Plugin to check
+ * @return bool True if plugin is network only, false otherwise.
+ */
+function is_network_only_plugin( $plugin ) {
+ $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
+ if ( $plugin_data )
+ return $plugin_data['Network'];
+ return false;
+}
+
+/**
+ * Attempts activation of plugin in a "sandbox" and redirects on success.
+ *
+ * A plugin that is already activated will not attempt to be activated again.
+ *
+ * The way it works is by setting the redirection to the error before trying to
+ * include the plugin file. If the plugin fails, then the redirection will not
+ * be overwritten with the success message. Also, the options will not be
+ * updated and the activation hook will not be called on plugin error.
+ *
+ * It should be noted that in no way the below code will actually prevent errors
+ * within the file. The code should not be used elsewhere to replicate the
+ * "sandbox", which uses redirection to work.
+ * {@source 13 1}
+ *
+ * If any errors are found or text is outputted, then it will be captured to
+ * ensure that the success redirection will update the error redirection.
+ *
+ * @since 2.5.0
+ *
+ * @param string $plugin Plugin path to main plugin file with plugin data.
+ * @param string $redirect Optional. URL to redirect to.
+ * @param bool $network_wide Whether to enable the plugin for all sites in the
+ * network or just the current site. Multisite only. Default is false.
+ * @param bool $silent Prevent calling activation hooks. Optional, default is false.
+ * @return WP_Error|null WP_Error on invalid file or null on success.
+ */
+function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silent = false ) {
+ $plugin = plugin_basename( trim( $plugin ) );
+
+ if ( is_multisite() && ( $network_wide || is_network_only_plugin($plugin) ) ) {
+ $network_wide = true;
+ $current = get_site_option( 'active_sitewide_plugins', array() );
+ $_GET['networkwide'] = 1; // Back compat for plugins looking for this value.
+ } else {
+ $current = get_option( 'active_plugins', array() );
+ }
+
+ $valid = validate_plugin($plugin);
+ if ( is_wp_error($valid) )
+ return $valid;
+
+ if ( !in_array($plugin, $current) ) {
+ if ( !empty($redirect) )
+ wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error
+ ob_start();
+ include_once(WP_PLUGIN_DIR . '/' . $plugin);
+
+ if ( ! $silent ) {
+ do_action( 'activate_plugin', $plugin, $network_wide );
+ do_action( 'activate_' . $plugin, $network_wide );
+ }
+
+ if ( $network_wide ) {
+ $current[$plugin] = time();
+ update_site_option( 'active_sitewide_plugins', $current );
+ } else {
+ $current[] = $plugin;
+ sort($current);
+ update_option('active_plugins', $current);
+ }
+
+ if ( ! $silent ) {
+ do_action( 'activated_plugin', $plugin, $network_wide );
+ }
+
+ if ( ob_get_length() > 0 ) {
+ $output = ob_get_clean();
+ return new WP_Error('unexpected_output', __('The plugin generated unexpected output.'), $output);
+ }
+ ob_end_clean();
+ }
+
+ return null;
+}
+
+/**
+ * Deactivate a single plugin or multiple plugins.
+ *
+ * The deactivation hook is disabled by the plugin upgrader by using the $silent
+ * parameter.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $plugins Single plugin or list of plugins to deactivate.
+ * @param bool $silent Prevent calling deactivation hooks. Default is false.
+ * @param mixed $network_wide Whether to deactivate the plugin for all sites in the network.
+ * A value of null (the default) will deactivate plugins for both the site and the network.
+ */
+function deactivate_plugins( $plugins, $silent = false, $network_wide = null ) {
+ if ( is_multisite() )
+ $network_current = get_site_option( 'active_sitewide_plugins', array() );
+ $current = get_option( 'active_plugins', array() );
+ $do_blog = $do_network = false;
+
+ foreach ( (array) $plugins as $plugin ) {
+ $plugin = plugin_basename( trim( $plugin ) );
+ if ( ! is_plugin_active($plugin) )
+ continue;
+
+ $network_deactivating = false !== $network_wide && is_plugin_active_for_network( $plugin );
+
+ if ( ! $silent )
+ do_action( 'deactivate_plugin', $plugin, $network_deactivating );
+
+ if ( false !== $network_wide ) {
+ if ( is_plugin_active_for_network( $plugin ) ) {
+ $do_network = true;
+ unset( $network_current[ $plugin ] );
+ } elseif ( $network_wide ) {
+ continue;
+ }
+ }
+
+ if ( true !== $network_wide ) {
+ $key = array_search( $plugin, $current );
+ if ( false !== $key ) {
+ $do_blog = true;
+ unset( $current[ $key ] );
+ }
+ }
+
+ if ( ! $silent ) {
+ do_action( 'deactivate_' . $plugin, $network_deactivating );
+ do_action( 'deactivated_plugin', $plugin, $network_deactivating );
+ }
+ }
+
+ if ( $do_blog )
+ update_option('active_plugins', $current);
+ if ( $do_network )
+ update_site_option( 'active_sitewide_plugins', $network_current );
+}
+
+/**
+ * Activate multiple plugins.
+ *
+ * When WP_Error is returned, it does not mean that one of the plugins had
+ * errors. It means that one or more of the plugins file path was invalid.
+ *
+ * The execution will be halted as soon as one of the plugins has an error.
+ *
+ * @since 2.6.0
+ *
+ * @param string|array $plugins
+ * @param string $redirect Redirect to page after successful activation.
+ * @param bool $network_wide Whether to enable the plugin for all sites in the network.
+ * @param bool $silent Prevent calling activation hooks. Default is false.
+ * @return bool|WP_Error True when finished or WP_Error if there were errors during a plugin activation.
+ */
+function activate_plugins( $plugins, $redirect = '', $network_wide = false, $silent = false ) {
+ if ( !is_array($plugins) )
+ $plugins = array($plugins);
+
+ $errors = array();
+ foreach ( $plugins as $plugin ) {
+ if ( !empty($redirect) )
+ $redirect = add_query_arg('plugin', $plugin, $redirect);
+ $result = activate_plugin($plugin, $redirect, $network_wide, $silent);
+ if ( is_wp_error($result) )
+ $errors[$plugin] = $result;
+ }
+
+ if ( !empty($errors) )
+ return new WP_Error('plugins_invalid', __('One of the plugins is invalid.'), $errors);
+
+ return true;
+}
+
+/**
+ * Remove directory and files of a plugin for a single or list of plugin(s).
+ *
+ * If the plugins parameter list is empty, false will be returned. True when
+ * completed.
+ *
+ * @since 2.6.0
+ *
+ * @param array $plugins List of plugin
+ * @param string $redirect Redirect to page when complete.
+ * @return mixed
+ */
+function delete_plugins($plugins, $redirect = '' ) {
+ global $wp_filesystem;
+
+ if ( empty($plugins) )
+ return false;
+
+ $checked = array();
+ foreach( $plugins as $plugin )
+ $checked[] = 'checked[]=' . $plugin;
+
+ ob_start();
+ $url = wp_nonce_url('plugins.php?action=delete-selected&verify-delete=1&' . implode('&', $checked), 'bulk-plugins');
+ if ( false === ($credentials = request_filesystem_credentials($url)) ) {
+ $data = ob_get_contents();
+ ob_end_clean();
+ if ( ! empty($data) ){
+ include_once( ABSPATH . 'wp-admin/admin-header.php');
+ echo $data;
+ include( ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ }
+ return;
+ }
+
+ if ( ! WP_Filesystem($credentials) ) {
+ request_filesystem_credentials($url, '', true); //Failed to connect, Error and request again
+ $data = ob_get_contents();
+ ob_end_clean();
+ if ( ! empty($data) ){
+ include_once( ABSPATH . 'wp-admin/admin-header.php');
+ echo $data;
+ include( ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ }
+ return;
+ }
+
+ if ( ! is_object($wp_filesystem) )
+ return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
+
+ if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
+ return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors);
+
+ //Get the base plugin folder
+ $plugins_dir = $wp_filesystem->wp_plugins_dir();
+ if ( empty($plugins_dir) )
+ return new WP_Error('fs_no_plugins_dir', __('Unable to locate WordPress Plugin directory.'));
+
+ $plugins_dir = trailingslashit( $plugins_dir );
+
+ $errors = array();
+
+ foreach( $plugins as $plugin_file ) {
+ // Run Uninstall hook
+ if ( is_uninstallable_plugin( $plugin_file ) )
+ uninstall_plugin($plugin_file);
+
+ $this_plugin_dir = trailingslashit( dirname($plugins_dir . $plugin_file) );
+ // If plugin is in its own directory, recursively delete the directory.
+ if ( strpos($plugin_file, '/') && $this_plugin_dir != $plugins_dir ) //base check on if plugin includes directory separator AND that it's not the root plugin folder
+ $deleted = $wp_filesystem->delete($this_plugin_dir, true);
+ else
+ $deleted = $wp_filesystem->delete($plugins_dir . $plugin_file);
+
+ if ( ! $deleted )
+ $errors[] = $plugin_file;
+ }
+
+ if ( ! empty($errors) )
+ return new WP_Error('could_not_remove_plugin', sprintf(__('Could not fully remove the plugin(s) %s.'), implode(', ', $errors)) );
+
+ // Force refresh of plugin update information
+ if ( $current = get_site_transient('update_plugins') ) {
+ unset( $current->response[ $plugin_file ] );
+ set_site_transient('update_plugins', $current);
+ }
+
+ return true;
+}
+
+/**
+ * Validate active plugins
+ *
+ * Validate all active plugins, deactivates invalid and
+ * returns an array of deactivated ones.
+ *
+ * @since 2.5.0
+ * @return array invalid plugins, plugin as key, error as value
+ */
+function validate_active_plugins() {
+ $plugins = get_option( 'active_plugins', array() );
+ // validate vartype: array
+ if ( ! is_array( $plugins ) ) {
+ update_option( 'active_plugins', array() );
+ $plugins = array();
+ }
+
+ if ( is_multisite() && is_super_admin() ) {
+ $network_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
+ $plugins = array_merge( $plugins, array_keys( $network_plugins ) );
+ }
+
+ if ( empty( $plugins ) )
+ return;
+
+ $invalid = array();
+
+ // invalid plugins get deactivated
+ foreach ( $plugins as $plugin ) {
+ $result = validate_plugin( $plugin );
+ if ( is_wp_error( $result ) ) {
+ $invalid[$plugin] = $result;
+ deactivate_plugins( $plugin, true );
+ }
+ }
+ return $invalid;
+}
+
+/**
+ * Validate the plugin path.
+ *
+ * Checks that the file exists and {@link validate_file() is valid file}.
+ *
+ * @since 2.5.0
+ *
+ * @param string $plugin Plugin Path
+ * @return WP_Error|int 0 on success, WP_Error on failure.
+ */
+function validate_plugin($plugin) {
+ if ( validate_file($plugin) )
+ return new WP_Error('plugin_invalid', __('Invalid plugin path.'));
+ if ( ! file_exists(WP_PLUGIN_DIR . '/' . $plugin) )
+ return new WP_Error('plugin_not_found', __('Plugin file does not exist.'));
+
+ $installed_plugins = get_plugins();
+ if ( ! isset($installed_plugins[$plugin]) )
+ return new WP_Error('no_plugin_header', __('The plugin does not have a valid header.'));
+ return 0;
+}
+
+/**
+ * Whether the plugin can be uninstalled.
+ *
+ * @since 2.7.0
+ *
+ * @param string $plugin Plugin path to check.
+ * @return bool Whether plugin can be uninstalled.
+ */
+function is_uninstallable_plugin($plugin) {
+ $file = plugin_basename($plugin);
+
+ $uninstallable_plugins = (array) get_option('uninstall_plugins');
+ if ( isset( $uninstallable_plugins[$file] ) || file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Uninstall a single plugin.
+ *
+ * Calls the uninstall hook, if it is available.
+ *
+ * @since 2.7.0
+ *
+ * @param string $plugin Relative plugin path from Plugin Directory.
+ */
+function uninstall_plugin($plugin) {
+ $file = plugin_basename($plugin);
+
+ $uninstallable_plugins = (array) get_option('uninstall_plugins');
+ if ( file_exists( WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php' ) ) {
+ if ( isset( $uninstallable_plugins[$file] ) ) {
+ unset($uninstallable_plugins[$file]);
+ update_option('uninstall_plugins', $uninstallable_plugins);
+ }
+ unset($uninstallable_plugins);
+
+ define('WP_UNINSTALL_PLUGIN', $file);
+ include WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php';
+
+ return true;
+ }
+
+ if ( isset( $uninstallable_plugins[$file] ) ) {
+ $callable = $uninstallable_plugins[$file];
+ unset($uninstallable_plugins[$file]);
+ update_option('uninstall_plugins', $uninstallable_plugins);
+ unset($uninstallable_plugins);
+
+ include WP_PLUGIN_DIR . '/' . $file;
+
+ add_action( 'uninstall_' . $file, $callable );
+ do_action( 'uninstall_' . $file );
+ }
+}
+
+//
+// Menu
+//
+
+/**
+ * Add a top level menu page
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ * @param string $icon_url The url to the icon to be used for this menu. Using 'none' would leave div.wp-menu-image empty
+ * so an icon can be added as background with CSS.
+ * @param int $position The position in the menu order this one should appear
+ *
+ * @return string The resulting page's hook_suffix
+ */
+function add_menu_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '', $position = null ) {
+ global $menu, $admin_page_hooks, $_registered_pages, $_parent_pages;
+
+ $menu_slug = plugin_basename( $menu_slug );
+
+ $admin_page_hooks[$menu_slug] = sanitize_title( $menu_title );
+
+ $hookname = get_plugin_page_hookname( $menu_slug, '' );
+
+ if ( !empty( $function ) && !empty( $hookname ) && current_user_can( $capability ) )
+ add_action( $hookname, $function );
+
+ if ( empty($icon_url) ) {
+ $icon_url = 'none';
+ $icon_class = 'menu-icon-generic ';
+ } else {
+ $icon_url = set_url_scheme( $icon_url );
+ $icon_class = '';
+ }
+
+ $new_menu = array( $menu_title, $capability, $menu_slug, $page_title, 'menu-top ' . $icon_class . $hookname, $hookname, $icon_url );
+
+ if ( null === $position )
+ $menu[] = $new_menu;
+ else
+ $menu[$position] = $new_menu;
+
+ $_registered_pages[$hookname] = true;
+
+ // No parent as top level
+ $_parent_pages[$menu_slug] = false;
+
+ return $hookname;
+}
+
+/**
+ * Add a top level menu page in the 'objects' section
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ * @param string $icon_url The url to the icon to be used for this menu
+ *
+ * @return string The resulting page's hook_suffix
+ */
+function add_object_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') {
+ global $_wp_last_object_menu;
+
+ $_wp_last_object_menu++;
+
+ return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_object_menu);
+}
+
+/**
+ * Add a top level menu page in the 'utility' section
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ * @param string $icon_url The url to the icon to be used for this menu
+ *
+ * @return string The resulting page's hook_suffix
+ */
+function add_utility_page( $page_title, $menu_title, $capability, $menu_slug, $function = '', $icon_url = '') {
+ global $_wp_last_utility_menu;
+
+ $_wp_last_utility_menu++;
+
+ return add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $_wp_last_utility_menu);
+}
+
+/**
+ * Add a sub menu page
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $parent_slug The slug name for the parent menu (or the file name of a standard WordPress admin page)
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ global $submenu;
+ global $menu;
+ global $_wp_real_parent_file;
+ global $_wp_submenu_nopriv;
+ global $_registered_pages;
+ global $_parent_pages;
+
+ $menu_slug = plugin_basename( $menu_slug );
+ $parent_slug = plugin_basename( $parent_slug);
+
+ if ( isset( $_wp_real_parent_file[$parent_slug] ) )
+ $parent_slug = $_wp_real_parent_file[$parent_slug];
+
+ if ( !current_user_can( $capability ) ) {
+ $_wp_submenu_nopriv[$parent_slug][$menu_slug] = true;
+ return false;
+ }
+
+ // If the parent doesn't already have a submenu, add a link to the parent
+ // as the first item in the submenu. If the submenu file is the same as the
+ // parent file someone is trying to link back to the parent manually. In
+ // this case, don't automatically add a link back to avoid duplication.
+ if (!isset( $submenu[$parent_slug] ) && $menu_slug != $parent_slug ) {
+ foreach ( (array)$menu as $parent_menu ) {
+ if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) )
+ $submenu[$parent_slug][] = $parent_menu;
+ }
+ }
+
+ $submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title );
+
+ $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug);
+ if (!empty ( $function ) && !empty ( $hookname ))
+ add_action( $hookname, $function );
+
+ $_registered_pages[$hookname] = true;
+ // backwards-compatibility for plugins using add_management page. See wp-admin/admin.php for redirect from edit.php to tools.php
+ if ( 'tools.php' == $parent_slug )
+ $_registered_pages[get_plugin_page_hookname( $menu_slug, 'edit.php')] = true;
+
+ // No parent as top level
+ $_parent_pages[$menu_slug] = $parent_slug;
+
+ return $hookname;
+}
+
+/**
+ * Add sub menu page to the tools main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_management_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'tools.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the options main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_options_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'options-general.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the themes main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_theme_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'themes.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the plugins main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_plugins_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'plugins.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the Users/Profile main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_users_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ if ( current_user_can('edit_users') )
+ $parent = 'users.php';
+ else
+ $parent = 'profile.php';
+ return add_submenu_page( $parent, $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+/**
+ * Add sub menu page to the Dashboard main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_dashboard_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'index.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the posts main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_posts_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'edit.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the media main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_media_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'upload.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the links main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+ */
+function add_links_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'link-manager.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the pages main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+*/
+function add_pages_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'edit.php?post_type=page', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Add sub menu page to the comments main menu.
+ *
+ * This function takes a capability which will be used to determine whether
+ * or not a page is included in the menu.
+ *
+ * The function which is hooked in to handle the output of the page must check
+ * that the user has the required capability as well.
+ *
+ * @param string $page_title The text to be displayed in the title tags of the page when the menu is selected
+ * @param string $menu_title The text to be used for the menu
+ * @param string $capability The capability required for this menu to be displayed to the user.
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param callback $function The function to be called to output the content for this page.
+ *
+ * @return string|bool The resulting page's hook_suffix, or false if the user does not have the capability required.
+*/
+function add_comments_page( $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
+ return add_submenu_page( 'edit-comments.php', $page_title, $menu_title, $capability, $menu_slug, $function );
+}
+
+/**
+ * Remove a top level admin menu
+ *
+ * @since 3.1.0
+ *
+ * @param string $menu_slug The slug of the menu
+ * @return array|bool The removed menu on success, False if not found
+ */
+function remove_menu_page( $menu_slug ) {
+ global $menu;
+
+ foreach ( $menu as $i => $item ) {
+ if ( $menu_slug == $item[2] ) {
+ unset( $menu[$i] );
+ return $item;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Remove an admin submenu
+ *
+ * @since 3.1.0
+ *
+ * @param string $menu_slug The slug for the parent menu
+ * @param string $submenu_slug The slug of the submenu
+ * @return array|bool The removed submenu on success, False if not found
+ */
+function remove_submenu_page( $menu_slug, $submenu_slug ) {
+ global $submenu;
+
+ if ( !isset( $submenu[$menu_slug] ) )
+ return false;
+
+ foreach ( $submenu[$menu_slug] as $i => $item ) {
+ if ( $submenu_slug == $item[2] ) {
+ unset( $submenu[$menu_slug][$i] );
+ return $item;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Get the url to access a particular menu page based on the slug it was registered with.
+ *
+ * If the slug hasn't been registered properly no url will be returned
+ *
+ * @since 3.0
+ *
+ * @param string $menu_slug The slug name to refer to this menu by (should be unique for this menu)
+ * @param bool $echo Whether or not to echo the url - default is true
+ * @return string the url
+ */
+function menu_page_url($menu_slug, $echo = true) {
+ global $_parent_pages;
+
+ if ( isset( $_parent_pages[$menu_slug] ) ) {
+ $parent_slug = $_parent_pages[$menu_slug];
+ if ( $parent_slug && ! isset( $_parent_pages[$parent_slug] ) ) {
+ $url = admin_url( add_query_arg( 'page', $menu_slug, $parent_slug ) );
+ } else {
+ $url = admin_url( 'admin.php?page=' . $menu_slug );
+ }
+ } else {
+ $url = '';
+ }
+
+ $url = esc_url($url);
+
+ if ( $echo )
+ echo $url;
+
+ return $url;
+}
+
+//
+// Pluggable Menu Support -- Private
+//
+
+function get_admin_page_parent( $parent = '' ) {
+ global $parent_file;
+ global $menu;
+ global $submenu;
+ global $pagenow;
+ global $typenow;
+ global $plugin_page;
+ global $_wp_real_parent_file;
+ global $_wp_menu_nopriv;
+ global $_wp_submenu_nopriv;
+
+ if ( !empty ( $parent ) && 'admin.php' != $parent ) {
+ if ( isset( $_wp_real_parent_file[$parent] ) )
+ $parent = $_wp_real_parent_file[$parent];
+ return $parent;
+ }
+
+ /*
+ if ( !empty ( $parent_file ) ) {
+ if ( isset( $_wp_real_parent_file[$parent_file] ) )
+ $parent_file = $_wp_real_parent_file[$parent_file];
+
+ return $parent_file;
+ }
+ */
+
+ if ( $pagenow == 'admin.php' && isset( $plugin_page ) ) {
+ foreach ( (array)$menu as $parent_menu ) {
+ if ( $parent_menu[2] == $plugin_page ) {
+ $parent_file = $plugin_page;
+ if ( isset( $_wp_real_parent_file[$parent_file] ) )
+ $parent_file = $_wp_real_parent_file[$parent_file];
+ return $parent_file;
+ }
+ }
+ if ( isset( $_wp_menu_nopriv[$plugin_page] ) ) {
+ $parent_file = $plugin_page;
+ if ( isset( $_wp_real_parent_file[$parent_file] ) )
+ $parent_file = $_wp_real_parent_file[$parent_file];
+ return $parent_file;
+ }
+ }
+
+ if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) ) {
+ $parent_file = $pagenow;
+ if ( isset( $_wp_real_parent_file[$parent_file] ) )
+ $parent_file = $_wp_real_parent_file[$parent_file];
+ return $parent_file;
+ }
+
+ foreach (array_keys( (array)$submenu ) as $parent) {
+ foreach ( $submenu[$parent] as $submenu_array ) {
+ if ( isset( $_wp_real_parent_file[$parent] ) )
+ $parent = $_wp_real_parent_file[$parent];
+ if ( !empty($typenow) && ($submenu_array[2] == "$pagenow?post_type=$typenow") ) {
+ $parent_file = $parent;
+ return $parent;
+ } elseif ( $submenu_array[2] == $pagenow && empty($typenow) && ( empty($parent_file) || false === strpos($parent_file, '?') ) ) {
+ $parent_file = $parent;
+ return $parent;
+ } else
+ if ( isset( $plugin_page ) && ($plugin_page == $submenu_array[2] ) ) {
+ $parent_file = $parent;
+ return $parent;
+ }
+ }
+ }
+
+ if ( empty($parent_file) )
+ $parent_file = '';
+ return '';
+}
+
+function get_admin_page_title() {
+ global $title;
+ global $menu;
+ global $submenu;
+ global $pagenow;
+ global $plugin_page;
+ global $typenow;
+
+ if ( ! empty ( $title ) )
+ return $title;
+
+ $hook = get_plugin_page_hook( $plugin_page, $pagenow );
+
+ $parent = $parent1 = get_admin_page_parent();
+
+ if ( empty ( $parent) ) {
+ foreach ( (array)$menu as $menu_array ) {
+ if ( isset( $menu_array[3] ) ) {
+ if ( $menu_array[2] == $pagenow ) {
+ $title = $menu_array[3];
+ return $menu_array[3];
+ } else
+ if ( isset( $plugin_page ) && ($plugin_page == $menu_array[2] ) && ($hook == $menu_array[3] ) ) {
+ $title = $menu_array[3];
+ return $menu_array[3];
+ }
+ } else {
+ $title = $menu_array[0];
+ return $title;
+ }
+ }
+ } else {
+ foreach ( array_keys( $submenu ) as $parent ) {
+ foreach ( $submenu[$parent] as $submenu_array ) {
+ if ( isset( $plugin_page ) &&
+ ( $plugin_page == $submenu_array[2] ) &&
+ (
+ ( $parent == $pagenow ) ||
+ ( $parent == $plugin_page ) ||
+ ( $plugin_page == $hook ) ||
+ ( $pagenow == 'admin.php' && $parent1 != $submenu_array[2] ) ||
+ ( !empty($typenow) && $parent == $pagenow . '?post_type=' . $typenow)
+ )
+ ) {
+ $title = $submenu_array[3];
+ return $submenu_array[3];
+ }
+
+ if ( $submenu_array[2] != $pagenow || isset( $_GET['page'] ) ) // not the current page
+ continue;
+
+ if ( isset( $submenu_array[3] ) ) {
+ $title = $submenu_array[3];
+ return $submenu_array[3];
+ } else {
+ $title = $submenu_array[0];
+ return $title;
+ }
+ }
+ }
+ if ( empty ( $title ) ) {
+ foreach ( $menu as $menu_array ) {
+ if ( isset( $plugin_page ) &&
+ ( $plugin_page == $menu_array[2] ) &&
+ ( $pagenow == 'admin.php' ) &&
+ ( $parent1 == $menu_array[2] ) )
+ {
+ $title = $menu_array[3];
+ return $menu_array[3];
+ }
+ }
+ }
+ }
+
+ return $title;
+}
+
+function get_plugin_page_hook( $plugin_page, $parent_page ) {
+ $hook = get_plugin_page_hookname( $plugin_page, $parent_page );
+ if ( has_action($hook) )
+ return $hook;
+ else
+ return null;
+}
+
+function get_plugin_page_hookname( $plugin_page, $parent_page ) {
+ global $admin_page_hooks;
+
+ $parent = get_admin_page_parent( $parent_page );
+
+ $page_type = 'admin';
+ if ( empty ( $parent_page ) || 'admin.php' == $parent_page || isset( $admin_page_hooks[$plugin_page] ) ) {
+ if ( isset( $admin_page_hooks[$plugin_page] ) )
+ $page_type = 'toplevel';
+ else
+ if ( isset( $admin_page_hooks[$parent] ))
+ $page_type = $admin_page_hooks[$parent];
+ } else if ( isset( $admin_page_hooks[$parent] ) ) {
+ $page_type = $admin_page_hooks[$parent];
+ }
+
+ $plugin_name = preg_replace( '!\.php!', '', $plugin_page );
+
+ return $page_type . '_page_' . $plugin_name;
+}
+
+function user_can_access_admin_page() {
+ global $pagenow;
+ global $menu;
+ global $submenu;
+ global $_wp_menu_nopriv;
+ global $_wp_submenu_nopriv;
+ global $plugin_page;
+ global $_registered_pages;
+
+ $parent = get_admin_page_parent();
+
+ if ( !isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$parent][$pagenow] ) )
+ return false;
+
+ if ( isset( $plugin_page ) ) {
+ if ( isset( $_wp_submenu_nopriv[$parent][$plugin_page] ) )
+ return false;
+
+ $hookname = get_plugin_page_hookname($plugin_page, $parent);
+
+ if ( !isset($_registered_pages[$hookname]) )
+ return false;
+ }
+
+ if ( empty( $parent) ) {
+ if ( isset( $_wp_menu_nopriv[$pagenow] ) )
+ return false;
+ if ( isset( $_wp_submenu_nopriv[$pagenow][$pagenow] ) )
+ return false;
+ if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$pagenow][$plugin_page] ) )
+ return false;
+ if ( isset( $plugin_page ) && isset( $_wp_menu_nopriv[$plugin_page] ) )
+ return false;
+ foreach (array_keys( $_wp_submenu_nopriv ) as $key ) {
+ if ( isset( $_wp_submenu_nopriv[$key][$pagenow] ) )
+ return false;
+ if ( isset( $plugin_page ) && isset( $_wp_submenu_nopriv[$key][$plugin_page] ) )
+ return false;
+ }
+ return true;
+ }
+
+ if ( isset( $plugin_page ) && ( $plugin_page == $parent ) && isset( $_wp_menu_nopriv[$plugin_page] ) )
+ return false;
+
+ if ( isset( $submenu[$parent] ) ) {
+ foreach ( $submenu[$parent] as $submenu_array ) {
+ if ( isset( $plugin_page ) && ( $submenu_array[2] == $plugin_page ) ) {
+ if ( current_user_can( $submenu_array[1] ))
+ return true;
+ else
+ return false;
+ } else if ( $submenu_array[2] == $pagenow ) {
+ if ( current_user_can( $submenu_array[1] ))
+ return true;
+ else
+ return false;
+ }
+ }
+ }
+
+ foreach ( $menu as $menu_array ) {
+ if ( $menu_array[2] == $parent) {
+ if ( current_user_can( $menu_array[1] ))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/* Whitelist functions */
+
+/**
+ * Register a setting and its sanitization callback
+ *
+ * @since 2.7.0
+ *
+ * @param string $option_group A settings group name. Should correspond to a whitelisted option key name.
+ * Default whitelisted option key names include "general," "discussion," and "reading," among others.
+ * @param string $option_name The name of an option to sanitize and save.
+ * @param unknown_type $sanitize_callback A callback function that sanitizes the option's value.
+ * @return unknown
+ */
+function register_setting( $option_group, $option_name, $sanitize_callback = '' ) {
+ global $new_whitelist_options;
+
+ if ( 'misc' == $option_group ) {
+ _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
+ $option_group = 'general';
+ }
+
+ if ( 'privacy' == $option_group ) {
+ _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
+ $option_group = 'reading';
+ }
+
+ $new_whitelist_options[ $option_group ][] = $option_name;
+ if ( $sanitize_callback != '' )
+ add_filter( "sanitize_option_{$option_name}", $sanitize_callback );
+}
+
+/**
+ * Unregister a setting
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $option_group
+ * @param unknown_type $option_name
+ * @param unknown_type $sanitize_callback
+ * @return unknown
+ */
+function unregister_setting( $option_group, $option_name, $sanitize_callback = '' ) {
+ global $new_whitelist_options;
+
+ if ( 'misc' == $option_group ) {
+ _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
+ $option_group = 'general';
+ }
+
+ if ( 'privacy' == $option_group ) {
+ _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
+ $option_group = 'reading';
+ }
+
+ $pos = array_search( $option_name, (array) $new_whitelist_options );
+ if ( $pos !== false )
+ unset( $new_whitelist_options[ $option_group ][ $pos ] );
+ if ( $sanitize_callback != '' )
+ remove_filter( "sanitize_option_{$option_name}", $sanitize_callback );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $options
+ * @return unknown
+ */
+function option_update_filter( $options ) {
+ global $new_whitelist_options;
+
+ if ( is_array( $new_whitelist_options ) )
+ $options = add_option_whitelist( $new_whitelist_options, $options );
+
+ return $options;
+}
+add_filter( 'whitelist_options', 'option_update_filter' );
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $new_options
+ * @param unknown_type $options
+ * @return unknown
+ */
+function add_option_whitelist( $new_options, $options = '' ) {
+ if ( $options == '' )
+ global $whitelist_options;
+ else
+ $whitelist_options = $options;
+
+ foreach ( $new_options as $page => $keys ) {
+ foreach ( $keys as $key ) {
+ if ( !isset($whitelist_options[ $page ]) || !is_array($whitelist_options[ $page ]) ) {
+ $whitelist_options[ $page ] = array();
+ $whitelist_options[ $page ][] = $key;
+ } else {
+ $pos = array_search( $key, $whitelist_options[ $page ] );
+ if ( $pos === false )
+ $whitelist_options[ $page ][] = $key;
+ }
+ }
+ }
+
+ return $whitelist_options;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $del_options
+ * @param unknown_type $options
+ * @return unknown
+ */
+function remove_option_whitelist( $del_options, $options = '' ) {
+ if ( $options == '' )
+ global $whitelist_options;
+ else
+ $whitelist_options = $options;
+
+ foreach ( $del_options as $page => $keys ) {
+ foreach ( $keys as $key ) {
+ if ( isset($whitelist_options[ $page ]) && is_array($whitelist_options[ $page ]) ) {
+ $pos = array_search( $key, $whitelist_options[ $page ] );
+ if ( $pos !== false )
+ unset( $whitelist_options[ $page ][ $pos ] );
+ }
+ }
+ }
+
+ return $whitelist_options;
+}
+
+/**
+ * Output nonce, action, and option_page fields for a settings page.
+ *
+ * @since 2.7.0
+ *
+ * @param string $option_group A settings group name. This should match the group name used in register_setting().
+ */
+function settings_fields($option_group) {
+ echo "<input type='hidden' name='option_page' value='" . esc_attr($option_group) . "' />";
+ echo '<input type="hidden" name="action" value="update" />';
+ wp_nonce_field("$option_group-options");
+}
diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php
new file mode 100644
index 0000000000..aecc433ce1
--- /dev/null
+++ b/src/wp-admin/includes/post.php
@@ -0,0 +1,1429 @@
+<?php
+/**
+ * WordPress Post Administration API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Rename $_POST data from form names to DB post columns.
+ *
+ * Manipulates $_POST directly.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param bool $update Are we updating a pre-existing post?
+ * @param array $post_data Array of post data. Defaults to the contents of $_POST.
+ * @return object|bool WP_Error on failure, true on success.
+ */
+function _wp_translate_postdata( $update = false, $post_data = null ) {
+
+ if ( empty($post_data) )
+ $post_data = &$_POST;
+
+ if ( $update )
+ $post_data['ID'] = (int) $post_data['post_ID'];
+
+ $ptype = get_post_type_object( $post_data['post_type'] );
+
+ if ( $update && ! current_user_can( 'edit_post', $post_data['ID'] ) ) {
+ if ( 'page' == $post_data['post_type'] )
+ return new WP_Error( 'edit_others_pages', __( 'You are not allowed to edit pages as this user.' ) );
+ else
+ return new WP_Error( 'edit_others_posts', __( 'You are not allowed to edit posts as this user.' ) );
+ } elseif ( ! $update && ! current_user_can( $ptype->cap->create_posts ) ) {
+ if ( 'page' == $post_data['post_type'] )
+ return new WP_Error( 'edit_others_pages', __( 'You are not allowed to create pages as this user.' ) );
+ else
+ return new WP_Error( 'edit_others_posts', __( 'You are not allowed to create posts as this user.' ) );
+ }
+
+ if ( isset( $post_data['content'] ) )
+ $post_data['post_content'] = $post_data['content'];
+
+ if ( isset( $post_data['excerpt'] ) )
+ $post_data['post_excerpt'] = $post_data['excerpt'];
+
+ if ( isset( $post_data['parent_id'] ) )
+ $post_data['post_parent'] = (int) $post_data['parent_id'];
+
+ if ( isset($post_data['trackback_url']) )
+ $post_data['to_ping'] = $post_data['trackback_url'];
+
+ if ( !isset($post_data['user_ID']) )
+ $post_data['user_ID'] = $GLOBALS['user_ID'];
+
+ if (!empty ( $post_data['post_author_override'] ) ) {
+ $post_data['post_author'] = (int) $post_data['post_author_override'];
+ } else {
+ if (!empty ( $post_data['post_author'] ) ) {
+ $post_data['post_author'] = (int) $post_data['post_author'];
+ } else {
+ $post_data['post_author'] = (int) $post_data['user_ID'];
+ }
+ }
+
+ if ( isset( $post_data['user_ID'] ) && ( $post_data['post_author'] != $post_data['user_ID'] )
+ && ! current_user_can( $ptype->cap->edit_others_posts ) ) {
+ if ( $update ) {
+ if ( 'page' == $post_data['post_type'] )
+ return new WP_Error( 'edit_others_pages', __( 'You are not allowed to edit pages as this user.' ) );
+ else
+ return new WP_Error( 'edit_others_posts', __( 'You are not allowed to edit posts as this user.' ) );
+ } else {
+ if ( 'page' == $post_data['post_type'] )
+ return new WP_Error( 'edit_others_pages', __( 'You are not allowed to create pages as this user.' ) );
+ else
+ return new WP_Error( 'edit_others_posts', __( 'You are not allowed to create posts as this user.' ) );
+ }
+ }
+
+ if ( ! empty( $post_data['post_status'] ) )
+ $post_data['post_status'] = sanitize_key( $post_data['post_status'] );
+
+ // What to do based on which button they pressed
+ if ( isset($post_data['saveasdraft']) && '' != $post_data['saveasdraft'] )
+ $post_data['post_status'] = 'draft';
+ if ( isset($post_data['saveasprivate']) && '' != $post_data['saveasprivate'] )
+ $post_data['post_status'] = 'private';
+ if ( isset($post_data['publish']) && ( '' != $post_data['publish'] ) && ( !isset($post_data['post_status']) || $post_data['post_status'] != 'private' ) )
+ $post_data['post_status'] = 'publish';
+ if ( isset($post_data['advanced']) && '' != $post_data['advanced'] )
+ $post_data['post_status'] = 'draft';
+ if ( isset($post_data['pending']) && '' != $post_data['pending'] )
+ $post_data['post_status'] = 'pending';
+
+ if ( isset( $post_data['ID'] ) )
+ $post_id = $post_data['ID'];
+ else
+ $post_id = false;
+ $previous_status = $post_id ? get_post_field( 'post_status', $post_id ) : false;
+
+ $published_statuses = array( 'publish', 'future' );
+
+ // Posts 'submitted for approval' present are submitted to $_POST the same as if they were being published.
+ // Change status from 'publish' to 'pending' if user lacks permissions to publish or to resave published posts.
+ if ( isset($post_data['post_status']) && (in_array( $post_data['post_status'], $published_statuses ) && !current_user_can( $ptype->cap->publish_posts )) )
+ if ( ! in_array( $previous_status, $published_statuses ) || !current_user_can( 'edit_post', $post_id ) )
+ $post_data['post_status'] = 'pending';
+
+ if ( ! isset($post_data['post_status']) )
+ $post_data['post_status'] = $previous_status;
+
+ if (!isset( $post_data['comment_status'] ))
+ $post_data['comment_status'] = 'closed';
+
+ if (!isset( $post_data['ping_status'] ))
+ $post_data['ping_status'] = 'closed';
+
+ foreach ( array('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
+ if ( !empty( $post_data['hidden_' . $timeunit] ) && $post_data['hidden_' . $timeunit] != $post_data[$timeunit] ) {
+ $post_data['edit_date'] = '1';
+ break;
+ }
+ }
+
+ if ( !empty( $post_data['edit_date'] ) ) {
+ $aa = $post_data['aa'];
+ $mm = $post_data['mm'];
+ $jj = $post_data['jj'];
+ $hh = $post_data['hh'];
+ $mn = $post_data['mn'];
+ $ss = $post_data['ss'];
+ $aa = ($aa <= 0 ) ? date('Y') : $aa;
+ $mm = ($mm <= 0 ) ? date('n') : $mm;
+ $jj = ($jj > 31 ) ? 31 : $jj;
+ $jj = ($jj <= 0 ) ? date('j') : $jj;
+ $hh = ($hh > 23 ) ? $hh -24 : $hh;
+ $mn = ($mn > 59 ) ? $mn -60 : $mn;
+ $ss = ($ss > 59 ) ? $ss -60 : $ss;
+ $post_data['post_date'] = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa, $mm, $jj, $hh, $mn, $ss );
+ $valid_date = wp_checkdate( $mm, $jj, $aa, $post_data['post_date'] );
+ if ( !$valid_date ) {
+ return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
+ }
+ $post_data['post_date_gmt'] = get_gmt_from_date( $post_data['post_date'] );
+ }
+
+ return $post_data;
+}
+
+/**
+ * Update an existing post with values provided in $_POST.
+ *
+ * @since 1.5.0
+ *
+ * @param array $post_data Optional.
+ * @return int Post ID.
+ */
+function edit_post( $post_data = null ) {
+
+ if ( empty($post_data) )
+ $post_data = &$_POST;
+
+ // Clear out any data in internal vars.
+ unset( $post_data['filter'] );
+
+ $post_ID = (int) $post_data['post_ID'];
+ $post = get_post( $post_ID );
+ $post_data['post_type'] = $post->post_type;
+ $post_data['post_mime_type'] = $post->post_mime_type;
+
+ $ptype = get_post_type_object($post_data['post_type']);
+ if ( !current_user_can( 'edit_post', $post_ID ) ) {
+ if ( 'page' == $post_data['post_type'] )
+ wp_die( __('You are not allowed to edit this page.' ));
+ else
+ wp_die( __('You are not allowed to edit this post.' ));
+ }
+
+ $post_data = _wp_translate_postdata( true, $post_data );
+ if ( is_wp_error($post_data) )
+ wp_die( $post_data->get_error_message() );
+ if ( ( empty( $post_data['action'] ) || 'autosave' != $post_data['action'] ) && 'auto-draft' == $post_data['post_status'] ) {
+ $post_data['post_status'] = 'draft';
+ }
+
+ if ( isset($post_data['visibility']) ) {
+ switch ( $post_data['visibility'] ) {
+ case 'public' :
+ $post_data['post_password'] = '';
+ break;
+ case 'password' :
+ unset( $post_data['sticky'] );
+ break;
+ case 'private' :
+ $post_data['post_status'] = 'private';
+ $post_data['post_password'] = '';
+ unset( $post_data['sticky'] );
+ break;
+ }
+ }
+
+ // Post Formats
+ if ( isset( $post_data['post_format'] ) )
+ set_post_format( $post_ID, $post_data['post_format'] );
+
+ $format_meta_urls = array( 'url', 'link_url', 'quote_source_url' );
+ foreach ( $format_meta_urls as $format_meta_url ) {
+ $keyed = '_format_' . $format_meta_url;
+ if ( isset( $post_data[ $keyed ] ) )
+ update_post_meta( $post_ID, $keyed, wp_slash( esc_url_raw( wp_unslash( $post_data[ $keyed ] ) ) ) );
+ }
+
+ $format_keys = array( 'quote', 'quote_source_name', 'image', 'gallery', 'audio_embed', 'video_embed' );
+
+ foreach ( $format_keys as $key ) {
+ $keyed = '_format_' . $key;
+ if ( isset( $post_data[ $keyed ] ) ) {
+ if ( current_user_can( 'unfiltered_html' ) )
+ update_post_meta( $post_ID, $keyed, $post_data[ $keyed ] );
+ else
+ update_post_meta( $post_ID, $keyed, wp_filter_post_kses( $post_data[ $keyed ] ) );
+ }
+ }
+
+ // Meta Stuff
+ if ( isset($post_data['meta']) && $post_data['meta'] ) {
+ foreach ( $post_data['meta'] as $key => $value ) {
+ if ( !$meta = get_post_meta_by_id( $key ) )
+ continue;
+ if ( $meta->post_id != $post_ID )
+ continue;
+ if ( is_protected_meta( $value['key'], 'post' ) || ! current_user_can( 'edit_post_meta', $post_ID, $value['key'] ) )
+ continue;
+ update_meta( $key, $value['key'], $value['value'] );
+ }
+ }
+
+ if ( isset($post_data['deletemeta']) && $post_data['deletemeta'] ) {
+ foreach ( $post_data['deletemeta'] as $key => $value ) {
+ if ( !$meta = get_post_meta_by_id( $key ) )
+ continue;
+ if ( $meta->post_id != $post_ID )
+ continue;
+ if ( is_protected_meta( $meta->meta_key, 'post' ) || ! current_user_can( 'delete_post_meta', $post_ID, $meta->meta_key ) )
+ continue;
+ delete_meta( $key );
+ }
+ }
+
+ // Attachment stuff
+ if ( 'attachment' == $post_data['post_type'] ) {
+ if ( isset( $post_data[ '_wp_attachment_image_alt' ] ) ) {
+ $image_alt = wp_unslash( $post_data['_wp_attachment_image_alt'] );
+ if ( $image_alt != get_post_meta( $post_ID, '_wp_attachment_image_alt', true ) ) {
+ $image_alt = wp_strip_all_tags( $image_alt, true );
+ // update_meta expects slashed
+ update_post_meta( $post_ID, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
+ }
+ }
+
+ $attachment_data = isset( $post_data['attachments'][ $post_ID ] ) ? $post_data['attachments'][ $post_ID ] : array();
+ $post_data = apply_filters( 'attachment_fields_to_save', $post_data, $attachment_data );
+ }
+
+ add_meta( $post_ID );
+
+ update_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
+
+ wp_update_post( $post_data );
+
+ // Now that we have an ID we can fix any attachment anchor hrefs
+ _fix_attachment_links( $post_ID );
+
+ wp_set_post_lock( $post_ID );
+
+ if ( current_user_can( $ptype->cap->edit_others_posts ) ) {
+ if ( ! empty( $post_data['sticky'] ) )
+ stick_post( $post_ID );
+ else
+ unstick_post( $post_ID );
+ }
+
+ return $post_ID;
+}
+
+/**
+ * Process the post data for the bulk editing of posts.
+ *
+ * Updates all bulk edited posts/pages, adding (but not removing) tags and
+ * categories. Skips pages when they would be their own parent or child.
+ *
+ * @since 2.7.0
+ *
+ * @param array $post_data Optional, the array of post data to process if not provided will use $_POST superglobal.
+ * @return array
+ */
+function bulk_edit_posts( $post_data = null ) {
+ global $wpdb;
+
+ if ( empty($post_data) )
+ $post_data = &$_POST;
+
+ if ( isset($post_data['post_type']) )
+ $ptype = get_post_type_object($post_data['post_type']);
+ else
+ $ptype = get_post_type_object('post');
+
+ if ( !current_user_can( $ptype->cap->edit_posts ) ) {
+ if ( 'page' == $ptype->name )
+ wp_die( __('You are not allowed to edit pages.'));
+ else
+ wp_die( __('You are not allowed to edit posts.'));
+ }
+
+ if ( -1 == $post_data['_status'] ) {
+ $post_data['post_status'] = null;
+ unset($post_data['post_status']);
+ } else {
+ $post_data['post_status'] = $post_data['_status'];
+ }
+ unset($post_data['_status']);
+
+ $post_IDs = array_map( 'intval', (array) $post_data['post'] );
+
+ $reset = array( 'post_author', 'post_status', 'post_password', 'post_parent', 'page_template', 'comment_status', 'ping_status', 'keep_private', 'tax_input', 'post_category', 'sticky' );
+ foreach ( $reset as $field ) {
+ if ( isset($post_data[$field]) && ( '' == $post_data[$field] || -1 == $post_data[$field] ) )
+ unset($post_data[$field]);
+ }
+
+ if ( isset($post_data['post_category']) ) {
+ if ( is_array($post_data['post_category']) && ! empty($post_data['post_category']) )
+ $new_cats = array_map( 'absint', $post_data['post_category'] );
+ else
+ unset($post_data['post_category']);
+ }
+
+ $tax_input = array();
+ if ( isset($post_data['tax_input'])) {
+ foreach ( $post_data['tax_input'] as $tax_name => $terms ) {
+ if ( empty($terms) )
+ continue;
+ if ( is_taxonomy_hierarchical( $tax_name ) ) {
+ $tax_input[ $tax_name ] = array_map( 'absint', $terms );
+ } else {
+ $comma = _x( ',', 'tag delimiter' );
+ if ( ',' !== $comma )
+ $terms = str_replace( $comma, ',', $terms );
+ $tax_input[ $tax_name ] = explode( ',', trim( $terms, " \n\t\r\0\x0B," ) );
+ }
+ }
+ }
+
+ if ( isset($post_data['post_parent']) && ($parent = (int) $post_data['post_parent']) ) {
+ $pages = $wpdb->get_results("SELECT ID, post_parent FROM $wpdb->posts WHERE post_type = 'page'");
+ $children = array();
+
+ for ( $i = 0; $i < 50 && $parent > 0; $i++ ) {
+ $children[] = $parent;
+
+ foreach ( $pages as $page ) {
+ if ( $page->ID == $parent ) {
+ $parent = $page->post_parent;
+ break;
+ }
+ }
+ }
+ }
+
+ $updated = $skipped = $locked = array();
+ foreach ( $post_IDs as $post_ID ) {
+ $post_type_object = get_post_type_object( get_post_type( $post_ID ) );
+
+ if ( !isset( $post_type_object ) || ( isset($children) && in_array($post_ID, $children) ) || !current_user_can( 'edit_post', $post_ID ) ) {
+ $skipped[] = $post_ID;
+ continue;
+ }
+
+ if ( wp_check_post_lock( $post_ID ) ) {
+ $locked[] = $post_ID;
+ continue;
+ }
+
+ $post = get_post( $post_ID );
+ $tax_names = get_object_taxonomies( $post );
+ foreach ( $tax_names as $tax_name ) {
+ $taxonomy_obj = get_taxonomy($tax_name);
+ if ( isset( $tax_input[$tax_name]) && current_user_can( $taxonomy_obj->cap->assign_terms ) )
+ $new_terms = $tax_input[$tax_name];
+ else
+ $new_terms = array();
+
+ if ( $taxonomy_obj->hierarchical )
+ $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'ids') );
+ else
+ $current_terms = (array) wp_get_object_terms( $post_ID, $tax_name, array('fields' => 'names') );
+
+ $post_data['tax_input'][$tax_name] = array_merge( $current_terms, $new_terms );
+ }
+
+ if ( isset($new_cats) && in_array( 'category', $tax_names ) ) {
+ $cats = (array) wp_get_post_categories($post_ID);
+ $post_data['post_category'] = array_unique( array_merge($cats, $new_cats) );
+ unset( $post_data['tax_input']['category'] );
+ }
+
+ $post_data['post_mime_type'] = $post->post_mime_type;
+ $post_data['guid'] = $post->guid;
+
+ $post_data['ID'] = $post_ID;
+ $updated[] = wp_update_post( $post_data );
+
+ if ( isset( $post_data['sticky'] ) && current_user_can( $ptype->cap->edit_others_posts ) ) {
+ if ( 'sticky' == $post_data['sticky'] )
+ stick_post( $post_ID );
+ else
+ unstick_post( $post_ID );
+ }
+ }
+
+ return array( 'updated' => $updated, 'skipped' => $skipped, 'locked' => $locked );
+}
+
+/**
+ * Default post information to use when populating the "Write Post" form.
+ *
+ * @since 2.0.0
+ *
+ * @param string $post_type A post type string, defaults to 'post'.
+ * @return WP_Post Post object containing all the default post data as attributes
+ */
+function get_default_post_to_edit( $post_type = 'post', $create_in_db = false ) {
+ global $wpdb;
+
+ $post_title = '';
+ if ( !empty( $_REQUEST['post_title'] ) )
+ $post_title = esc_html( wp_unslash( $_REQUEST['post_title'] ));
+
+ $post_content = '';
+ if ( !empty( $_REQUEST['content'] ) )
+ $post_content = esc_html( wp_unslash( $_REQUEST['content'] ));
+
+ $post_excerpt = '';
+ if ( !empty( $_REQUEST['excerpt'] ) )
+ $post_excerpt = esc_html( wp_unslash( $_REQUEST['excerpt'] ));
+
+ if ( $create_in_db ) {
+ $post_id = wp_insert_post( array( 'post_title' => __( 'Auto Draft' ), 'post_type' => $post_type, 'post_status' => 'auto-draft' ) );
+ $post = get_post( $post_id );
+ if ( current_theme_supports( 'post-formats' ) && post_type_supports( $post->post_type, 'post-formats' ) && get_option( 'default_post_format' ) )
+ set_post_format( $post, get_option( 'default_post_format' ) );
+ } else {
+ $post = new stdClass;
+ $post->ID = 0;
+ $post->post_author = '';
+ $post->post_date = '';
+ $post->post_date_gmt = '';
+ $post->post_password = '';
+ $post->post_type = $post_type;
+ $post->post_status = 'draft';
+ $post->to_ping = '';
+ $post->pinged = '';
+ $post->comment_status = get_option( 'default_comment_status' );
+ $post->ping_status = get_option( 'default_ping_status' );
+ $post->post_pingback = get_option( 'default_pingback_flag' );
+ $post->post_category = get_option( 'default_category' );
+ $post->page_template = 'default';
+ $post->post_parent = 0;
+ $post->menu_order = 0;
+ $post = new WP_Post( $post );
+ }
+
+ $post->post_content = apply_filters( 'default_content', $post_content, $post );
+ $post->post_title = apply_filters( 'default_title', $post_title, $post );
+ $post->post_excerpt = apply_filters( 'default_excerpt', $post_excerpt, $post );
+ $post->post_name = '';
+
+ return $post;
+}
+
+/**
+ * Determine if a post exists based on title, content, and date
+ *
+ * @since 2.0.0
+ *
+ * @param string $title Post title
+ * @param string $content Optional post content
+ * @param string $date Optional post date
+ * @return int Post ID if post exists, 0 otherwise.
+ */
+function post_exists($title, $content = '', $date = '') {
+ global $wpdb;
+
+ $post_title = wp_unslash( sanitize_post_field( 'post_title', $title, 0, 'db' ) );
+ $post_content = wp_unslash( sanitize_post_field( 'post_content', $content, 0, 'db' ) );
+ $post_date = wp_unslash( sanitize_post_field( 'post_date', $date, 0, 'db' ) );
+
+ $query = "SELECT ID FROM $wpdb->posts WHERE 1=1";
+ $args = array();
+
+ if ( !empty ( $date ) ) {
+ $query .= ' AND post_date = %s';
+ $args[] = $post_date;
+ }
+
+ if ( !empty ( $title ) ) {
+ $query .= ' AND post_title = %s';
+ $args[] = $post_title;
+ }
+
+ if ( !empty ( $content ) ) {
+ $query .= 'AND post_content = %s';
+ $args[] = $post_content;
+ }
+
+ if ( !empty ( $args ) )
+ return (int) $wpdb->get_var( $wpdb->prepare($query, $args) );
+
+ return 0;
+}
+
+/**
+ * Creates a new post from the "Write Post" form using $_POST information.
+ *
+ * @since 2.1.0
+ *
+ * @return unknown
+ */
+function wp_write_post() {
+ global $user_ID;
+
+ if ( isset($_POST['post_type']) )
+ $ptype = get_post_type_object($_POST['post_type']);
+ else
+ $ptype = get_post_type_object('post');
+
+ if ( !current_user_can( $ptype->cap->edit_posts ) ) {
+ if ( 'page' == $ptype->name )
+ return new WP_Error( 'edit_pages', __( 'You are not allowed to create pages on this site.' ) );
+ else
+ return new WP_Error( 'edit_posts', __( 'You are not allowed to create posts or drafts on this site.' ) );
+ }
+
+ $_POST['post_mime_type'] = '';
+
+ // Clear out any data in internal vars.
+ unset( $_POST['filter'] );
+
+ // Edit don't write if we have a post id.
+ if ( isset( $_POST['post_ID'] ) )
+ return edit_post();
+
+ $translated = _wp_translate_postdata( false );
+ if ( is_wp_error($translated) )
+ return $translated;
+
+ if ( isset($_POST['visibility']) ) {
+ switch ( $_POST['visibility'] ) {
+ case 'public' :
+ $_POST['post_password'] = '';
+ break;
+ case 'password' :
+ unset( $_POST['sticky'] );
+ break;
+ case 'private' :
+ $_POST['post_status'] = 'private';
+ $_POST['post_password'] = '';
+ unset( $_POST['sticky'] );
+ break;
+ }
+ }
+
+ // Create the post.
+ $post_ID = wp_insert_post( $_POST );
+ if ( is_wp_error( $post_ID ) )
+ return $post_ID;
+
+ if ( empty($post_ID) )
+ return 0;
+
+ add_meta( $post_ID );
+
+ add_post_meta( $post_ID, '_edit_last', $GLOBALS['current_user']->ID );
+
+ // Now that we have an ID we can fix any attachment anchor hrefs
+ _fix_attachment_links( $post_ID );
+
+ wp_set_post_lock( $post_ID );
+
+ return $post_ID;
+}
+
+/**
+ * Calls wp_write_post() and handles the errors.
+ *
+ * @since 2.0.0
+
+ * @uses wp_write_post()
+ * @uses is_wp_error()
+ * @uses wp_die()
+ * @return unknown
+ */
+function write_post() {
+ $result = wp_write_post();
+ if ( is_wp_error( $result ) )
+ wp_die( $result->get_error_message() );
+ else
+ return $result;
+}
+
+//
+// Post Meta
+//
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.2.0
+ *
+ * @param unknown_type $post_ID
+ * @return unknown
+ */
+function add_meta( $post_ID ) {
+ global $wpdb;
+ $post_ID = (int) $post_ID;
+
+ $metakeyselect = isset($_POST['metakeyselect']) ? wp_unslash( trim( $_POST['metakeyselect'] ) ) : '';
+ $metakeyinput = isset($_POST['metakeyinput']) ? wp_unslash( trim( $_POST['metakeyinput'] ) ) : '';
+ $metavalue = isset($_POST['metavalue']) ? $_POST['metavalue'] : '';
+ if ( is_string( $metavalue ) )
+ $metavalue = trim( $metavalue );
+
+ if ( ('0' === $metavalue || ! empty ( $metavalue ) ) && ( ( ( '#NONE#' != $metakeyselect ) && !empty ( $metakeyselect) ) || !empty ( $metakeyinput ) ) ) {
+ // We have a key/value pair. If both the select and the
+ // input for the key have data, the input takes precedence:
+
+ if ( '#NONE#' != $metakeyselect )
+ $metakey = $metakeyselect;
+
+ if ( $metakeyinput )
+ $metakey = $metakeyinput; // default
+
+ if ( is_protected_meta( $metakey, 'post' ) || ! current_user_can( 'add_post_meta', $post_ID, $metakey ) )
+ return false;
+
+ $metakey = wp_slash( $metakey );
+
+ return add_post_meta( $post_ID, $metakey, $metavalue );
+ }
+
+ return false;
+} // add_meta
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.2.0
+ *
+ * @param unknown_type $mid
+ * @return unknown
+ */
+function delete_meta( $mid ) {
+ return delete_metadata_by_mid( 'post' , $mid );
+}
+
+/**
+ * Get a list of previously defined keys.
+ *
+ * @since 1.2.0
+ *
+ * @return unknown
+ */
+function get_meta_keys() {
+ global $wpdb;
+
+ $keys = $wpdb->get_col( "
+ SELECT meta_key
+ FROM $wpdb->postmeta
+ GROUP BY meta_key
+ ORDER BY meta_key" );
+
+ return $keys;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.1.0
+ *
+ * @param unknown_type $mid
+ * @return unknown
+ */
+function get_post_meta_by_id( $mid ) {
+ return get_metadata_by_mid( 'post', $mid );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * Some postmeta stuff.
+ *
+ * @since 1.2.0
+ *
+ * @param unknown_type $postid
+ * @return unknown
+ */
+function has_meta( $postid ) {
+ global $wpdb;
+
+ return $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value, meta_id, post_id
+ FROM $wpdb->postmeta WHERE post_id = %d
+ ORDER BY meta_key,meta_id", $postid), ARRAY_A );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.2.0
+ *
+ * @param unknown_type $meta_id
+ * @param unknown_type $meta_key Expect Slashed
+ * @param unknown_type $meta_value Expect Slashed
+ * @return unknown
+ */
+function update_meta( $meta_id, $meta_key, $meta_value ) {
+ $meta_key = wp_unslash( $meta_key );
+ $meta_value = wp_unslash( $meta_value );
+
+ return update_metadata_by_mid( 'post', $meta_id, $meta_value, $meta_key );
+}
+
+//
+// Private
+//
+
+/**
+ * Replace hrefs of attachment anchors with up-to-date permalinks.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param unknown_type $post_ID
+ * @return unknown
+ */
+function _fix_attachment_links( $post_ID ) {
+ $post = get_post( $post_ID, ARRAY_A );
+ $content = $post['post_content'];
+
+ // quick sanity check, don't run if no pretty permalinks or post is not published
+ if ( !get_option('permalink_structure') || $post['post_status'] != 'publish' )
+ return;
+
+ // Short if there aren't any links or no '?attachment_id=' strings (strpos cannot be zero)
+ if ( !strpos($content, '?attachment_id=') || !preg_match_all( '/<a ([^>]+)>[\s\S]+?<\/a>/', $content, $link_matches ) )
+ return;
+
+ $site_url = get_bloginfo('url');
+ $site_url = substr( $site_url, (int) strpos($site_url, '://') ); // remove the http(s)
+ $replace = '';
+
+ foreach ( $link_matches[1] as $key => $value ) {
+ if ( !strpos($value, '?attachment_id=') || !strpos($value, 'wp-att-')
+ || !preg_match( '/href=(["\'])[^"\']*\?attachment_id=(\d+)[^"\']*\\1/', $value, $url_match )
+ || !preg_match( '/rel=["\'][^"\']*wp-att-(\d+)/', $value, $rel_match ) )
+ continue;
+
+ $quote = $url_match[1]; // the quote (single or double)
+ $url_id = (int) $url_match[2];
+ $rel_id = (int) $rel_match[1];
+
+ if ( !$url_id || !$rel_id || $url_id != $rel_id || strpos($url_match[0], $site_url) === false )
+ continue;
+
+ $link = $link_matches[0][$key];
+ $replace = str_replace( $url_match[0], 'href=' . $quote . get_attachment_link( $url_id ) . $quote, $link );
+
+ $content = str_replace( $link, $replace, $content );
+ }
+
+ if ( $replace ) {
+ $post['post_content'] = $content;
+ // Escape data pulled from DB.
+ $post = add_magic_quotes($post);
+
+ return wp_update_post($post);
+ }
+}
+
+/**
+ * Move child posts to a new parent.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param unknown_type $old_ID
+ * @param unknown_type $new_ID
+ * @return unknown
+ */
+function _relocate_children( $old_ID, $new_ID ) {
+ global $wpdb;
+ $old_ID = (int) $old_ID;
+ $new_ID = (int) $new_ID;
+
+ $children = $wpdb->get_col( $wpdb->prepare("
+ SELECT post_id
+ FROM $wpdb->postmeta
+ WHERE meta_key = '_wp_attachment_temp_parent'
+ AND meta_value = %d", $old_ID) );
+
+ foreach ( $children as $child_id ) {
+ $wpdb->update($wpdb->posts, array('post_parent' => $new_ID), array('ID' => $child_id) );
+ delete_post_meta($child_id, '_wp_attachment_temp_parent');
+ }
+}
+
+/**
+ * Get all the possible statuses for a post_type
+ *
+ * @since 2.5.0
+ *
+ * @param string $type The post_type you want the statuses for
+ * @return array As array of all the statuses for the supplied post type
+ */
+function get_available_post_statuses($type = 'post') {
+ $stati = wp_count_posts($type);
+
+ return array_keys(get_object_vars($stati));
+}
+
+/**
+ * Run the wp query to fetch the posts for listing on the edit posts page
+ *
+ * @since 2.5.0
+ *
+ * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
+ * @return array
+ */
+function wp_edit_posts_query( $q = false ) {
+ if ( false === $q )
+ $q = $_GET;
+ $q['m'] = isset($q['m']) ? (int) $q['m'] : 0;
+ $q['cat'] = isset($q['cat']) ? (int) $q['cat'] : 0;
+ $post_stati = get_post_stati();
+
+ if ( isset($q['post_type']) && in_array( $q['post_type'], get_post_types() ) )
+ $post_type = $q['post_type'];
+ else
+ $post_type = 'post';
+
+ $avail_post_stati = get_available_post_statuses($post_type);
+
+ if ( isset($q['post_status']) && in_array( $q['post_status'], $post_stati ) ) {
+ $post_status = $q['post_status'];
+ $perm = 'readable';
+ }
+
+ if ( isset($q['orderby']) )
+ $orderby = $q['orderby'];
+ elseif ( isset($q['post_status']) && in_array($q['post_status'], array('pending', 'draft')) )
+ $orderby = 'modified';
+
+ if ( isset($q['order']) )
+ $order = $q['order'];
+ elseif ( isset($q['post_status']) && 'pending' == $q['post_status'] )
+ $order = 'ASC';
+
+ $per_page = 'edit_' . $post_type . '_per_page';
+ $posts_per_page = (int) get_user_option( $per_page );
+ if ( empty( $posts_per_page ) || $posts_per_page < 1 )
+ $posts_per_page = 20;
+
+ $posts_per_page = apply_filters( $per_page, $posts_per_page );
+ $posts_per_page = apply_filters( 'edit_posts_per_page', $posts_per_page, $post_type );
+
+ $query = compact('post_type', 'post_status', 'perm', 'order', 'orderby', 'posts_per_page');
+
+ // Hierarchical types require special args.
+ if ( is_post_type_hierarchical( $post_type ) && !isset($orderby) ) {
+ $query['orderby'] = 'menu_order title';
+ $query['order'] = 'asc';
+ $query['posts_per_page'] = -1;
+ $query['posts_per_archive_page'] = -1;
+ }
+
+ if ( ! empty( $q['show_sticky'] ) )
+ $query['post__in'] = (array) get_option( 'sticky_posts' );
+
+ wp( $query );
+
+ return $avail_post_stati;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param unknown_type $type
+ * @return unknown
+ */
+function get_available_post_mime_types($type = 'attachment') {
+ global $wpdb;
+
+ $types = $wpdb->get_col($wpdb->prepare("SELECT DISTINCT post_mime_type FROM $wpdb->posts WHERE post_type = %s", $type));
+ return $types;
+}
+
+/**
+ * Executes a query for attachments. An array of WP_Query arguments
+ * can be passed in, which will override the arguments set by this function.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'upload_per_page' on posts_per_page argument
+ *
+ * @param array|bool $q Array of query variables to use to build the query or false to use $_GET superglobal.
+ * @return array
+ */
+function wp_edit_attachments_query( $q = false ) {
+ if ( false === $q )
+ $q = $_GET;
+
+ $q['m'] = isset( $q['m'] ) ? (int) $q['m'] : 0;
+ $q['cat'] = isset( $q['cat'] ) ? (int) $q['cat'] : 0;
+ $q['post_type'] = 'attachment';
+ $post_type = get_post_type_object( 'attachment' );
+ $states = 'inherit';
+ if ( current_user_can( $post_type->cap->read_private_posts ) )
+ $states .= ',private';
+
+ $q['post_status'] = isset( $q['status'] ) && 'trash' == $q['status'] ? 'trash' : $states;
+ $media_per_page = (int) get_user_option( 'upload_per_page' );
+ if ( empty( $media_per_page ) || $media_per_page < 1 )
+ $media_per_page = 20;
+ $q['posts_per_page'] = apply_filters( 'upload_per_page', $media_per_page );
+
+ $post_mime_types = get_post_mime_types();
+ $avail_post_mime_types = get_available_post_mime_types('attachment');
+
+ if ( isset($q['post_mime_type']) && !array_intersect( (array) $q['post_mime_type'], array_keys($post_mime_types) ) )
+ unset($q['post_mime_type']);
+
+ if ( isset($q['detached']) )
+ add_filter('posts_where', '_edit_attachments_query_helper');
+
+ wp( $q );
+
+ if ( isset($q['detached']) )
+ remove_filter('posts_where', '_edit_attachments_query_helper');
+
+ return array($post_mime_types, $avail_post_mime_types);
+}
+
+function _edit_attachments_query_helper($where) {
+ global $wpdb;
+ return $where .= " AND {$wpdb->posts}.post_parent < 1";
+}
+
+/**
+ * Returns the list of classes to be used by a metabox
+ *
+ * @uses get_user_option()
+ * @since 2.5.0
+ *
+ * @param unknown_type $id
+ * @param unknown_type $page
+ * @return unknown
+ */
+function postbox_classes( $id, $page ) {
+ if ( isset( $_GET['edit'] ) && $_GET['edit'] == $id ) {
+ $classes = array( '' );
+ } elseif ( $closed = get_user_option('closedpostboxes_'.$page ) ) {
+ if ( !is_array( $closed ) ) {
+ $classes = array( '' );
+ } else {
+ $classes = in_array( $id, $closed ) ? array( 'closed' ) : array( '' );
+ }
+ } else {
+ $classes = array( '' );
+ }
+
+ $classes = apply_filters( "postbox_classes_{$page}_{$id}", $classes );
+ return implode( ' ', $classes );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param int|object $id Post ID or post object.
+ * @param string $title (optional) Title
+ * @param string $name (optional) Name
+ * @return array With two entries of type string
+ */
+function get_sample_permalink($id, $title = null, $name = null) {
+ $post = get_post($id);
+ if ( !$post->ID )
+ return array('', '');
+
+ $ptype = get_post_type_object($post->post_type);
+
+ $original_status = $post->post_status;
+ $original_date = $post->post_date;
+ $original_name = $post->post_name;
+
+ // Hack: get_permalink() would return ugly permalink for drafts, so we will fake that our post is published.
+ if ( in_array( $post->post_status, array( 'draft', 'pending' ) ) ) {
+ $post->post_status = 'publish';
+ $post->post_name = sanitize_title($post->post_name ? $post->post_name : $post->post_title, $post->ID);
+ }
+
+ // If the user wants to set a new name -- override the current one
+ // Note: if empty name is supplied -- use the title instead, see #6072
+ if ( !is_null($name) )
+ $post->post_name = sanitize_title($name ? $name : $title, $post->ID);
+
+ $post->post_name = wp_unique_post_slug($post->post_name, $post->ID, $post->post_status, $post->post_type, $post->post_parent);
+
+ $post->filter = 'sample';
+
+ $permalink = get_permalink($post, true);
+
+ // Replace custom post_type Token with generic pagename token for ease of use.
+ $permalink = str_replace("%$post->post_type%", '%pagename%', $permalink);
+
+ // Handle page hierarchy
+ if ( $ptype->hierarchical ) {
+ $uri = get_page_uri($post);
+ $uri = untrailingslashit($uri);
+ $uri = strrev( stristr( strrev( $uri ), '/' ) );
+ $uri = untrailingslashit($uri);
+ $uri = apply_filters( 'editable_slug', $uri );
+ if ( !empty($uri) )
+ $uri .= '/';
+ $permalink = str_replace('%pagename%', "{$uri}%pagename%", $permalink);
+ }
+
+ $permalink = array($permalink, apply_filters('editable_slug', $post->post_name));
+ $post->post_status = $original_status;
+ $post->post_date = $original_date;
+ $post->post_name = $original_name;
+ unset($post->filter);
+
+ return $permalink;
+}
+
+/**
+ * Returns the HTML of the sample permalink slug editor.
+ *
+ * @since 2.5.0
+ *
+ * @param int|object $id Post ID or post object.
+ * @param string $new_title Optional. New title.
+ * @param string $new_slug Optional. New slug.
+ * @return string The HTML of the sample permalink slug editor.
+ */
+function get_sample_permalink_html( $id, $new_title = null, $new_slug = null ) {
+ global $wpdb;
+ $post = get_post($id);
+
+ list($permalink, $post_name) = get_sample_permalink($post->ID, $new_title, $new_slug);
+
+ if ( 'publish' == get_post_status( $post ) ) {
+ $ptype = get_post_type_object($post->post_type);
+ $view_post = $ptype->labels->view_item;
+ $title = __('Click to edit this part of the permalink');
+ } else {
+ $title = __('Temporary permalink. Click to edit this part.');
+ }
+
+ if ( false === strpos($permalink, '%postname%') && false === strpos($permalink, '%pagename%') ) {
+ $return = '<strong>' . __('Permalink:') . "</strong>\n" . '<span id="sample-permalink" tabindex="-1">' . $permalink . "</span>\n";
+ if ( '' == get_option( 'permalink_structure' ) && current_user_can( 'manage_options' ) && !( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') ) )
+ $return .= '<span id="change-permalinks"><a href="options-permalink.php" class="button button-small" target="_blank">' . __('Change Permalinks') . "</a></span>\n";
+ if ( isset( $view_post ) )
+ $return .= "<span id='view-post-btn'><a href='$permalink' class='button button-small'>$view_post</a></span>\n";
+
+ $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
+
+ return $return;
+ }
+
+ if ( function_exists('mb_strlen') ) {
+ if ( mb_strlen($post_name) > 30 ) {
+ $post_name_abridged = mb_substr($post_name, 0, 14). '&hellip;' . mb_substr($post_name, -14);
+ } else {
+ $post_name_abridged = $post_name;
+ }
+ } else {
+ if ( strlen($post_name) > 30 ) {
+ $post_name_abridged = substr($post_name, 0, 14). '&hellip;' . substr($post_name, -14);
+ } else {
+ $post_name_abridged = $post_name;
+ }
+ }
+
+ $post_name_html = '<span id="editable-post-name" title="' . $title . '">' . $post_name_abridged . '</span>';
+ $display_link = str_replace(array('%pagename%','%postname%'), $post_name_html, $permalink);
+ $view_link = str_replace(array('%pagename%','%postname%'), $post_name, $permalink);
+ $return = '<strong>' . __('Permalink:') . "</strong>\n";
+ $return .= '<span id="sample-permalink" tabindex="-1">' . $display_link . "</span>\n";
+ $return .= '&lrm;'; // Fix bi-directional text display defect in RTL languages.
+ $return .= '<span id="edit-slug-buttons"><a href="#post_name" class="edit-slug button button-small hide-if-no-js" onclick="editPermalink(' . $id . '); return false;">' . __('Edit') . "</a></span>\n";
+ $return .= '<span id="editable-post-name-full">' . $post_name . "</span>\n";
+ if ( isset($view_post) )
+ $return .= "<span id='view-post-btn'><a href='$view_link' class='button button-small'>$view_post</a></span>\n";
+
+ $return = apply_filters('get_sample_permalink_html', $return, $id, $new_title, $new_slug);
+
+ return $return;
+}
+
+/**
+ * Output HTML for the post thumbnail meta-box.
+ *
+ * @since 2.9.0
+ *
+ * @param int $thumbnail_id ID of the attachment used for thumbnail
+ * @param mixed $post The post ID or object associated with the thumbnail, defaults to global $post.
+ * @return string html
+ */
+function _wp_post_thumbnail_html( $thumbnail_id = null, $post = null ) {
+ global $content_width, $_wp_additional_image_sizes;
+
+ $post = get_post( $post );
+
+ $upload_iframe_src = esc_url( get_upload_iframe_src('image', $post->ID ) );
+ $set_thumbnail_link = '<p class="hide-if-no-js"><a title="' . esc_attr__( 'Set featured image' ) . '" href="%s" id="set-post-thumbnail" class="thickbox">%s</a></p>';
+ $content = sprintf( $set_thumbnail_link, $upload_iframe_src, esc_html__( 'Set featured image' ) );
+
+ if ( $thumbnail_id && get_post( $thumbnail_id ) ) {
+ $old_content_width = $content_width;
+ $content_width = 266;
+ if ( !isset( $_wp_additional_image_sizes['post-thumbnail'] ) )
+ $thumbnail_html = wp_get_attachment_image( $thumbnail_id, array( $content_width, $content_width ) );
+ else
+ $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'post-thumbnail' );
+ if ( !empty( $thumbnail_html ) ) {
+ $ajax_nonce = wp_create_nonce( 'set_post_thumbnail-' . $post->ID );
+ $content = sprintf( $set_thumbnail_link, $upload_iframe_src, $thumbnail_html );
+ $content .= '<p class="hide-if-no-js"><a href="#" id="remove-post-thumbnail" onclick="WPRemoveThumbnail(\'' . $ajax_nonce . '\');return false;">' . esc_html__( 'Remove featured image' ) . '</a></p>';
+ }
+ $content_width = $old_content_width;
+ }
+
+ return apply_filters( 'admin_post_thumbnail_html', $content, $post->ID );
+}
+
+/**
+ * Check to see if the post is currently being edited by another user.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id ID of the post to check for editing
+ * @return bool|int False: not locked or locked by current user. Int: user ID of user with lock.
+ */
+function wp_check_post_lock( $post_id ) {
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) )
+ return false;
+
+ $lock = explode( ':', $lock );
+ $time = $lock[0];
+ $user = isset( $lock[1] ) ? $lock[1] : get_post_meta( $post->ID, '_edit_last', true );
+
+ $time_window = apply_filters( 'wp_check_post_lock_window', 120 );
+
+ if ( $time && $time > time() - $time_window && $user != get_current_user_id() )
+ return $user;
+ return false;
+}
+
+/**
+ * Mark the post as currently being edited by the current user
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id ID of the post to being edited
+ * @return bool|array Returns false if the post doesn't exist of there is no current user, or
+ * an array of the lock time and the user ID.
+ */
+function wp_set_post_lock( $post_id ) {
+ if ( !$post = get_post( $post_id ) )
+ return false;
+ if ( 0 == ($user_id = get_current_user_id()) )
+ return false;
+
+ $now = time();
+ $lock = "$now:$user_id";
+
+ update_post_meta( $post->ID, '_edit_lock', $lock );
+ return array( $now, $user_id );
+}
+
+/**
+ * Outputs the HTML for the notice to say that someone else is editing or has taken over editing of this post.
+ *
+ * @since 2.8.5
+ * @return none
+ */
+function _admin_notice_post_locked() {
+ if ( ! $post = get_post() )
+ return;
+
+ $user = null;
+ if ( $user_id = wp_check_post_lock( $post->ID ) )
+ $user = get_userdata( $user_id );
+
+ if ( $user ) {
+ if ( ! apply_filters( 'show_post_locked_dialog', true, $post, $user ) )
+ return;
+
+ $locked = true;
+ } else {
+ $locked = false;
+ }
+
+ if ( $locked && ( $sendback = wp_get_referer() ) &&
+ false === strpos( $sendback, 'post.php' ) && false === strpos( $sendback, 'post-new.php' ) ) {
+
+ $sendback_text = __('Go back');
+ } else {
+ $sendback = admin_url( 'edit.php' );
+
+ if ( 'post' != $post->post_type )
+ $sendback = add_query_arg( 'post_type', $post->post_type, $sendback );
+
+ $sendback_text = get_post_type_object( $post->post_type )->labels->all_items;
+ }
+
+ $hidden = $locked ? '' : ' hidden';
+
+ ?>
+ <div id="post-lock-dialog" class="notification-dialog-wrap<?php echo $hidden; ?>">
+ <div class="notification-dialog-background"></div>
+ <div class="notification-dialog">
+ <?php
+
+ if ( $locked ) {
+ if ( get_post_type_object( $post->post_type )->public ) {
+ $preview_link = set_url_scheme( add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ) );
+
+ if ( 'publish' == $post->post_status || $user->ID != $post->post_author ) {
+ // Latest content is in autosave
+ $nonce = wp_create_nonce( 'post_preview_' . $post->ID );
+ $preview_link = add_query_arg( array( 'preview_id' => $post->ID, 'preview_nonce' => $nonce ), $preview_link );
+ }
+ } else {
+ $preview_link = '';
+ }
+
+ $preview_link = apply_filters( 'preview_post_link', $preview_link );
+ $override = apply_filters( 'override_post_lock', true, $post, $user );
+ $tab_last = $override ? '' : ' wp-tab-last';
+
+ ?>
+ <div class="post-locked-message">
+ <div class="post-locked-avatar"><?php echo get_avatar( $user->ID, 64 ); ?></div>
+ <p class="currently-editing wp-tab-first" tabindex="0"><?php echo esc_html( sprintf( __( 'This content is currently locked. If you take over, %s will be blocked from continuing to edit.' ), $user->display_name ) ); ?></p>
+ <?php do_action( 'post_locked_dialog', $post ); ?>
+ <p>
+ <a class="button" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a>
+ <?php if ( $preview_link ) { ?>
+ <a class="button<?php echo $tab_last; ?>" href="<?php echo esc_url( $preview_link ); ?>"><?php _e('Preview'); ?></a>
+ <?php
+ }
+
+ // Allow plugins to prevent some users overriding the post lock
+ if ( $override ) {
+ ?>
+ <a class="button button-primary wp-tab-last" href="<?php echo esc_url( add_query_arg( 'get-post-lock', '1', get_edit_post_link( $post->ID, 'url' ) ) ); ?>"><?php _e('Take over'); ?></a>
+ <?php
+ }
+
+ ?>
+ </p>
+ </div>
+ <?php
+ } else {
+ ?>
+ <div class="post-taken-over">
+ <div class="post-locked-avatar"></div>
+ <p class="wp-tab-first" tabindex="0">
+ <span class="currently-editing"></span><br>
+ <span class="locked-saving hidden"><img src="images/wpspin_light-2x.gif" width="16" height="16" /> <?php _e('Saving revision...'); ?></span>
+ <span class="locked-saved hidden"><?php _e('Your latest changes were saved as a revision.'); ?></span>
+ </p>
+ <?php do_action( 'post_lock_lost_dialog', $post ); ?>
+ <p><a class="button button-primary wp-tab-last" href="<?php echo esc_url( $sendback ); ?>"><?php echo $sendback_text; ?></a></p>
+ </div>
+ <?php
+ }
+
+ ?>
+ </div>
+ </div>
+ <?php
+}
+
+/**
+ * Creates autosave data for the specified post from $_POST data.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses _wp_translate_postdata()
+ * @uses _wp_post_revision_fields()
+ *
+ * @return unknown
+ */
+function wp_create_post_autosave( $post_id ) {
+ $translated = _wp_translate_postdata( true );
+ if ( is_wp_error( $translated ) )
+ return $translated;
+
+ $post_author = get_current_user_id();
+
+ // Store one autosave per author. If there is already an autosave, overwrite it.
+ if ( $old_autosave = wp_get_post_autosave( $post_id, $post_author ) ) {
+ $new_autosave = _wp_post_revision_fields( $_POST, true );
+ $new_autosave['ID'] = $old_autosave->ID;
+ $new_autosave['post_author'] = $post_author;
+
+ // If the new autosave is the same content as the post, delete the old autosave.
+ $post = get_post( $post_id );
+ $autosave_is_different = false;
+ foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
+ if ( normalize_whitespace( $new_autosave[ $field ] ) != normalize_whitespace( $post->$field ) ) {
+ $autosave_is_different = true;
+ break;
+ }
+ }
+
+ if ( ! $autosave_is_different ) {
+ wp_delete_post_revision( $old_autosave->ID );
+ return;
+ }
+
+ return wp_update_post( $new_autosave );
+ }
+
+ // _wp_put_post_revision() expects unescaped.
+ $post_data = wp_unslash( $_POST );
+
+ // Otherwise create the new autosave as a special post revision
+ return _wp_put_post_revision( $post_data, true );
+}
+
+/**
+ * Save draft or manually autosave for showing preview.
+ *
+ * @package WordPress
+ * @since 2.7.0
+ *
+ * @uses get_post_status()
+ * @uses edit_post()
+ * @uses get_post()
+ * @uses current_user_can()
+ * @uses wp_die()
+ * @uses wp_create_post_autosave()
+ * @uses add_query_arg()
+ * @uses wp_create_nonce()
+ *
+ * @return str URL to redirect to show the preview
+ */
+function post_preview() {
+
+ $post_ID = (int) $_POST['post_ID'];
+ $status = get_post_status( $post_ID );
+ if ( 'auto-draft' == $status )
+ wp_die( __('Preview not available. Please save as a draft first.') );
+
+ if ( isset($_POST['catslist']) )
+ $_POST['post_category'] = explode(",", $_POST['catslist']);
+
+ if ( isset($_POST['tags_input']) )
+ $_POST['tags_input'] = explode(",", $_POST['tags_input']);
+
+ if ( $_POST['post_type'] == 'page' || empty($_POST['post_category']) )
+ unset($_POST['post_category']);
+
+ $_POST['ID'] = $post_ID;
+ $post = get_post($post_ID);
+
+ if ( 'page' == $post->post_type ) {
+ if ( ! current_user_can('edit_page', $post_ID) )
+ wp_die( __('You are not allowed to edit this page.') );
+ } else {
+ if ( ! current_user_can('edit_post', $post_ID) )
+ wp_die( __('You are not allowed to edit this post.') );
+ }
+
+ $user_id = get_current_user_id();
+ $locked = wp_check_post_lock( $post->ID );
+ if ( ! $locked && 'draft' == $post->post_status && $user_id == $post->post_author ) {
+ $id = edit_post();
+ } else { // Non drafts are not overwritten. The autosave is stored in a special post revision.
+ $id = wp_create_post_autosave( $post->ID );
+ if ( ! is_wp_error($id) )
+ $id = $post->ID;
+ }
+
+ if ( is_wp_error($id) )
+ wp_die( $id->get_error_message() );
+
+ if ( ! $locked && $_POST['post_status'] == 'draft' && $user_id == $post->post_author ) {
+ $url = add_query_arg( 'preview', 'true', get_permalink($id) );
+ } else {
+ $nonce = wp_create_nonce('post_preview_' . $id);
+ $args = array(
+ 'preview' => 'true',
+ 'preview_id' => $id,
+ 'preview_nonce' => $nonce,
+ );
+
+ if ( isset( $_POST['post_format'] ) )
+ $args['post_format'] = empty( $_POST['post_format'] ) ? 'standard' : sanitize_key( $_POST['post_format'] );
+
+ $url = add_query_arg( $args, get_permalink($id) );
+ }
+
+ return apply_filters( 'preview_post_link', $url );
+}
diff --git a/src/wp-admin/includes/revision.php b/src/wp-admin/includes/revision.php
new file mode 100644
index 0000000000..597ec1f02c
--- /dev/null
+++ b/src/wp-admin/includes/revision.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * WordPress Administration Revisions API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Get the revision UI diff.
+ *
+ * @since 3.6.0
+ *
+ * @param object $post The post object.
+ * @param int $compare_from The revision id to compare from.
+ * @param int $compare_to The revision id to come to.
+ *
+ * @return array|bool Associative array of a post's revisioned fields and their diffs.
+ * Or, false on failure.
+ */
+function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) {
+ if ( ! $post = get_post( $post ) )
+ return false;
+
+ if ( $compare_from ) {
+ if ( ! $compare_from = get_post( $compare_from ) )
+ return false;
+ } else {
+ // If we're dealing with the first revision...
+ $compare_from = false;
+ }
+
+ if ( ! $compare_to = get_post( $compare_to ) )
+ return false;
+
+ // If comparing revisions, make sure we're dealing with the right post parent.
+ // The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves.
+ if ( $compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID )
+ return false;
+ if ( $compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID )
+ return false;
+
+ if ( $compare_from && strtotime( $compare_from->post_date_gmt ) > strtotime( $compare_to->post_date_gmt ) ) {
+ $temp = $compare_from;
+ $compare_from = $compare_to;
+ $compare_to = $temp;
+ }
+
+ // Add default title if title field is empty
+ if ( $compare_from && empty( $compare_from->post_title ) )
+ $compare_from->post_title = __( '(no title)' );
+ if ( empty( $compare_to->post_title ) )
+ $compare_to->post_title = __( '(no title)' );
+
+ $return = array();
+
+ foreach ( _wp_post_revision_fields() as $field => $name ) {
+ $content_from = $compare_from ? apply_filters( "_wp_post_revision_field_$field", $compare_from->$field, $field, $compare_from, 'from' ) : '';
+ $content_to = apply_filters( "_wp_post_revision_field_$field", $compare_to->$field, $field, $compare_to, 'to' );
+
+ $diff = wp_text_diff( $content_from, $content_to, array( 'show_split_view' => true ) );
+
+ if ( ! $diff && 'post_title' === $field ) {
+ // It's a better user experience to still show the Title, even if it didn't change.
+ // No, you didn't see this.
+ $diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>';
+ $diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td><td></td><td>' . esc_html( $compare_to->post_title ) . '</td>';
+ $diff .= '</tr></tbody>';
+ $diff .= '</table>';
+ }
+
+ if ( $diff ) {
+ $return[] = array(
+ 'id' => $field,
+ 'name' => $name,
+ 'diff' => $diff,
+ );
+ }
+ }
+ return $return;
+}
+
+/**
+ * Prepare revisions for JavaScript.
+ *
+ * @since 3.6.0
+ *
+ * @param object $post The post object.
+ * @param int $selected_revision_id The selected revision id.
+ * @param int $from (optional) The revision id to compare from.
+ *
+ * @return array An associative array of revision data and related settings.
+ */
+function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) {
+ $post = get_post( $post );
+ $revisions = $authors = array();
+ $now_gmt = time();
+
+ $revisions = wp_get_post_revisions( $post->ID, array( 'order' => 'ASC', 'check_enabled' => false ) );
+ // If revisions are disabled, we only want autosaves and the current post.
+ if ( ! wp_revisions_enabled( $post ) ) {
+ foreach ( $revisions as $revision_id => $revision ) {
+ if ( ! wp_is_post_autosave( $revision ) )
+ unset( $revisions[ $revision_id ] );
+ }
+ $revisions = array( $post->ID => $post ) + $revisions;
+ }
+
+ $show_avatars = get_option( 'show_avatars' );
+
+ cache_users( wp_list_pluck( $revisions, 'post_author' ) );
+
+ $can_restore = current_user_can( 'edit_post', $post->ID );
+
+ foreach ( $revisions as $revision ) {
+ $modified = strtotime( $revision->post_modified );
+ $modified_gmt = strtotime( $revision->post_modified_gmt );
+ if ( $can_restore ) {
+ $restore_link = str_replace( '&amp;', '&', wp_nonce_url(
+ add_query_arg(
+ array( 'revision' => $revision->ID,
+ 'action' => 'restore' ),
+ admin_url( 'revision.php' )
+ ),
+ "restore-post_{$revision->ID}"
+ ) );
+ }
+
+ if ( ! isset( $authors[ $revision->post_author ] ) ) {
+ $authors[ $revision->post_author ] = array(
+ 'id' => (int) $revision->post_author,
+ 'avatar' => $show_avatars ? get_avatar( $revision->post_author, 32 ) : '',
+ 'name' => get_the_author_meta( 'display_name', $revision->post_author ),
+ );
+ }
+
+ $autosave = (bool) wp_is_post_autosave( $revision );
+ $current = ! $autosave && $revision->post_modified_gmt === $post->post_modified_gmt;
+ if ( $current && ! empty( $current_id ) ) {
+ // If multiple revisions have the same post_modified_gmt, highest ID is current.
+ if ( $current_id < $revision->ID ) {
+ $revisions[ $current_id ]['current'] = false;
+ $current_id = $revision->ID;
+ } else {
+ $current = false;
+ }
+ } elseif ( $current ) {
+ $current_id = $revision->ID;
+ }
+
+ $revisions[ $revision->ID ] = array(
+ 'id' => $revision->ID,
+ 'title' => get_the_title( $post->ID ),
+ 'author' => $authors[ $revision->post_author ],
+ 'date' => date_i18n( __( 'M j, Y @ G:i' ), $modified ),
+ 'dateShort' => date_i18n( _x( 'j M @ G:i', 'revision date short format' ), $modified ),
+ 'timeAgo' => sprintf( __( '%s ago' ), human_time_diff( $modified_gmt, $now_gmt ) ),
+ 'autosave' => $autosave,
+ 'current' => $current,
+ 'restoreUrl' => $can_restore ? $restore_link : false,
+ );
+ }
+
+ // If a post has been saved since the last revision (no revisioned fields were changed)
+ // we may not have a "current" revision. Mark the latest revision as "current".
+ if ( empty( $current_id ) ) {
+ if ( $revisions[ $revision->ID ]['autosave'] ) {
+ $revision = end( $revisions );
+ while ( $revision['autosave'] ) {
+ $revision = prev( $revisions );
+ }
+ $current_id = $revision['id'];
+ } else {
+ $current_id = $revision->ID;
+ }
+ $revisions[ $current_id ]['current'] = true;
+ }
+
+ // Now, grab the initial diff
+ $compare_two_mode = is_numeric( $from );
+ if ( ! $compare_two_mode ) {
+ $found = array_search( $selected_revision_id, array_keys( $revisions ) );
+ if ( $found ) {
+ $from = array_keys( array_slice( $revisions, $found - 1, 1, true ) );
+ $from = reset( $from );
+ } else {
+ $from = 0;
+ }
+ }
+
+ $from = absint( $from );
+
+ $diffs = array( array(
+ 'id' => $from . ':' . $selected_revision_id,
+ 'fields' => wp_get_revision_ui_diff( $post->ID, $from, $selected_revision_id ),
+ ));
+
+ return array(
+ 'postId' => $post->ID,
+ 'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ),
+ 'revisionData' => array_values( $revisions ),
+ 'to' => $selected_revision_id,
+ 'from' => $from,
+ 'diffData' => $diffs,
+ 'baseUrl' => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ),
+ 'compareTwoMode' => absint( $compare_two_mode ), // Apparently booleans are not allowed
+ 'revisionIds' => array_keys( $revisions ),
+ );
+}
diff --git a/src/wp-admin/includes/schema.php b/src/wp-admin/includes/schema.php
new file mode 100644
index 0000000000..162651a418
--- /dev/null
+++ b/src/wp-admin/includes/schema.php
@@ -0,0 +1,975 @@
+<?php
+/**
+ * WordPress Administration Scheme API
+ *
+ * Here we keep the DB structure and option values.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// Declare these as global in case schema.php is included from a function.
+global $wpdb, $wp_queries, $charset_collate;
+
+/**
+ * The database character collate.
+ * @var string
+ * @global string
+ * @name $charset_collate
+ */
+$charset_collate = $wpdb->get_charset_collate();
+
+/**
+ * Retrieve the SQL for creating database tables.
+ *
+ * @since 3.3.0
+ *
+ * @param string $scope Optional. The tables for which to retrieve SQL. Can be all, global, ms_global, or blog tables. Defaults to all.
+ * @param int $blog_id Optional. The blog ID for which to retrieve SQL. Default is the current blog ID.
+ * @return string The SQL needed to create the requested tables.
+ */
+function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
+ global $wpdb;
+
+ $charset_collate = '';
+
+ if ( ! empty($wpdb->charset) )
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
+ if ( ! empty($wpdb->collate) )
+ $charset_collate .= " COLLATE $wpdb->collate";
+
+ if ( $blog_id && $blog_id != $wpdb->blogid )
+ $old_blog_id = $wpdb->set_blog_id( $blog_id );
+
+ // Engage multisite if in the middle of turning it on from network.php.
+ $is_multisite = is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK );
+
+ // Blog specific tables.
+ $blog_tables = "CREATE TABLE $wpdb->terms (
+ term_id bigint(20) unsigned NOT NULL auto_increment,
+ name varchar(200) NOT NULL default '',
+ slug varchar(200) NOT NULL default '',
+ term_group bigint(10) NOT NULL default 0,
+ PRIMARY KEY (term_id),
+ UNIQUE KEY slug (slug),
+ KEY name (name)
+) $charset_collate;
+CREATE TABLE $wpdb->term_taxonomy (
+ term_taxonomy_id bigint(20) unsigned NOT NULL auto_increment,
+ term_id bigint(20) unsigned NOT NULL default 0,
+ taxonomy varchar(32) NOT NULL default '',
+ description longtext NOT NULL,
+ parent bigint(20) unsigned NOT NULL default 0,
+ count bigint(20) NOT NULL default 0,
+ PRIMARY KEY (term_taxonomy_id),
+ UNIQUE KEY term_id_taxonomy (term_id,taxonomy),
+ KEY taxonomy (taxonomy)
+) $charset_collate;
+CREATE TABLE $wpdb->term_relationships (
+ object_id bigint(20) unsigned NOT NULL default 0,
+ term_taxonomy_id bigint(20) unsigned NOT NULL default 0,
+ term_order int(11) NOT NULL default 0,
+ PRIMARY KEY (object_id,term_taxonomy_id),
+ KEY term_taxonomy_id (term_taxonomy_id)
+) $charset_collate;
+CREATE TABLE $wpdb->commentmeta (
+ meta_id bigint(20) unsigned NOT NULL auto_increment,
+ comment_id bigint(20) unsigned NOT NULL default '0',
+ meta_key varchar(255) default NULL,
+ meta_value longtext,
+ PRIMARY KEY (meta_id),
+ KEY comment_id (comment_id),
+ KEY meta_key (meta_key)
+) $charset_collate;
+CREATE TABLE $wpdb->comments (
+ comment_ID bigint(20) unsigned NOT NULL auto_increment,
+ comment_post_ID bigint(20) unsigned NOT NULL default '0',
+ comment_author tinytext NOT NULL,
+ comment_author_email varchar(100) NOT NULL default '',
+ comment_author_url varchar(200) NOT NULL default '',
+ comment_author_IP varchar(100) NOT NULL default '',
+ comment_date datetime NOT NULL default '0000-00-00 00:00:00',
+ comment_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
+ comment_content text NOT NULL,
+ comment_karma int(11) NOT NULL default '0',
+ comment_approved varchar(20) NOT NULL default '1',
+ comment_agent varchar(255) NOT NULL default '',
+ comment_type varchar(20) NOT NULL default '',
+ comment_parent bigint(20) unsigned NOT NULL default '0',
+ user_id bigint(20) unsigned NOT NULL default '0',
+ PRIMARY KEY (comment_ID),
+ KEY comment_post_ID (comment_post_ID),
+ KEY comment_approved_date_gmt (comment_approved,comment_date_gmt),
+ KEY comment_date_gmt (comment_date_gmt),
+ KEY comment_parent (comment_parent)
+) $charset_collate;
+CREATE TABLE $wpdb->links (
+ link_id bigint(20) unsigned NOT NULL auto_increment,
+ link_url varchar(255) NOT NULL default '',
+ link_name varchar(255) NOT NULL default '',
+ link_image varchar(255) NOT NULL default '',
+ link_target varchar(25) NOT NULL default '',
+ link_description varchar(255) NOT NULL default '',
+ link_visible varchar(20) NOT NULL default 'Y',
+ link_owner bigint(20) unsigned NOT NULL default '1',
+ link_rating int(11) NOT NULL default '0',
+ link_updated datetime NOT NULL default '0000-00-00 00:00:00',
+ link_rel varchar(255) NOT NULL default '',
+ link_notes mediumtext NOT NULL,
+ link_rss varchar(255) NOT NULL default '',
+ PRIMARY KEY (link_id),
+ KEY link_visible (link_visible)
+) $charset_collate;
+CREATE TABLE $wpdb->options (
+ option_id bigint(20) unsigned NOT NULL auto_increment,
+ option_name varchar(64) NOT NULL default '',
+ option_value longtext NOT NULL,
+ autoload varchar(20) NOT NULL default 'yes',
+ PRIMARY KEY (option_id),
+ UNIQUE KEY option_name (option_name)
+) $charset_collate;
+CREATE TABLE $wpdb->postmeta (
+ meta_id bigint(20) unsigned NOT NULL auto_increment,
+ post_id bigint(20) unsigned NOT NULL default '0',
+ meta_key varchar(255) default NULL,
+ meta_value longtext,
+ PRIMARY KEY (meta_id),
+ KEY post_id (post_id),
+ KEY meta_key (meta_key)
+) $charset_collate;
+CREATE TABLE $wpdb->posts (
+ ID bigint(20) unsigned NOT NULL auto_increment,
+ post_author bigint(20) unsigned NOT NULL default '0',
+ post_date datetime NOT NULL default '0000-00-00 00:00:00',
+ post_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
+ post_content longtext NOT NULL,
+ post_title text NOT NULL,
+ post_excerpt text NOT NULL,
+ post_status varchar(20) NOT NULL default 'publish',
+ comment_status varchar(20) NOT NULL default 'open',
+ ping_status varchar(20) NOT NULL default 'open',
+ post_password varchar(20) NOT NULL default '',
+ post_name varchar(200) NOT NULL default '',
+ to_ping text NOT NULL,
+ pinged text NOT NULL,
+ post_modified datetime NOT NULL default '0000-00-00 00:00:00',
+ post_modified_gmt datetime NOT NULL default '0000-00-00 00:00:00',
+ post_content_filtered longtext NOT NULL,
+ post_parent bigint(20) unsigned NOT NULL default '0',
+ guid varchar(255) NOT NULL default '',
+ menu_order int(11) NOT NULL default '0',
+ post_type varchar(20) NOT NULL default 'post',
+ post_mime_type varchar(100) NOT NULL default '',
+ comment_count bigint(20) NOT NULL default '0',
+ PRIMARY KEY (ID),
+ KEY post_name (post_name),
+ KEY type_status_date (post_type,post_status,post_date,ID),
+ KEY post_parent (post_parent),
+ KEY post_author (post_author)
+) $charset_collate;\n";
+
+ // Single site users table. The multisite flavor of the users table is handled below.
+ $users_single_table = "CREATE TABLE $wpdb->users (
+ ID bigint(20) unsigned NOT NULL auto_increment,
+ user_login varchar(60) NOT NULL default '',
+ user_pass varchar(64) NOT NULL default '',
+ user_nicename varchar(50) NOT NULL default '',
+ user_email varchar(100) NOT NULL default '',
+ user_url varchar(100) NOT NULL default '',
+ user_registered datetime NOT NULL default '0000-00-00 00:00:00',
+ user_activation_key varchar(60) NOT NULL default '',
+ user_status int(11) NOT NULL default '0',
+ display_name varchar(250) NOT NULL default '',
+ PRIMARY KEY (ID),
+ KEY user_login_key (user_login),
+ KEY user_nicename (user_nicename)
+) $charset_collate;\n";
+
+ // Multisite users table
+ $users_multi_table = "CREATE TABLE $wpdb->users (
+ ID bigint(20) unsigned NOT NULL auto_increment,
+ user_login varchar(60) NOT NULL default '',
+ user_pass varchar(64) NOT NULL default '',
+ user_nicename varchar(50) NOT NULL default '',
+ user_email varchar(100) NOT NULL default '',
+ user_url varchar(100) NOT NULL default '',
+ user_registered datetime NOT NULL default '0000-00-00 00:00:00',
+ user_activation_key varchar(60) NOT NULL default '',
+ user_status int(11) NOT NULL default '0',
+ display_name varchar(250) NOT NULL default '',
+ spam tinyint(2) NOT NULL default '0',
+ deleted tinyint(2) NOT NULL default '0',
+ PRIMARY KEY (ID),
+ KEY user_login_key (user_login),
+ KEY user_nicename (user_nicename)
+) $charset_collate;\n";
+
+ // usermeta
+ $usermeta_table = "CREATE TABLE $wpdb->usermeta (
+ umeta_id bigint(20) unsigned NOT NULL auto_increment,
+ user_id bigint(20) unsigned NOT NULL default '0',
+ meta_key varchar(255) default NULL,
+ meta_value longtext,
+ PRIMARY KEY (umeta_id),
+ KEY user_id (user_id),
+ KEY meta_key (meta_key)
+) $charset_collate;\n";
+
+ // Global tables
+ if ( $is_multisite )
+ $global_tables = $users_multi_table . $usermeta_table;
+ else
+ $global_tables = $users_single_table . $usermeta_table;
+
+ // Multisite global tables.
+ $ms_global_tables = "CREATE TABLE $wpdb->blogs (
+ blog_id bigint(20) NOT NULL auto_increment,
+ site_id bigint(20) NOT NULL default '0',
+ domain varchar(200) NOT NULL default '',
+ path varchar(100) NOT NULL default '',
+ registered datetime NOT NULL default '0000-00-00 00:00:00',
+ last_updated datetime NOT NULL default '0000-00-00 00:00:00',
+ public tinyint(2) NOT NULL default '1',
+ archived enum('0','1') NOT NULL default '0',
+ mature tinyint(2) NOT NULL default '0',
+ spam tinyint(2) NOT NULL default '0',
+ deleted tinyint(2) NOT NULL default '0',
+ lang_id int(11) NOT NULL default '0',
+ PRIMARY KEY (blog_id),
+ KEY domain (domain(50),path(5)),
+ KEY lang_id (lang_id)
+) $charset_collate;
+CREATE TABLE $wpdb->blog_versions (
+ blog_id bigint(20) NOT NULL default '0',
+ db_version varchar(20) NOT NULL default '',
+ last_updated datetime NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (blog_id),
+ KEY db_version (db_version)
+) $charset_collate;
+CREATE TABLE $wpdb->registration_log (
+ ID bigint(20) NOT NULL auto_increment,
+ email varchar(255) NOT NULL default '',
+ IP varchar(30) NOT NULL default '',
+ blog_id bigint(20) NOT NULL default '0',
+ date_registered datetime NOT NULL default '0000-00-00 00:00:00',
+ PRIMARY KEY (ID),
+ KEY IP (IP)
+) $charset_collate;
+CREATE TABLE $wpdb->site (
+ id bigint(20) NOT NULL auto_increment,
+ domain varchar(200) NOT NULL default '',
+ path varchar(100) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY domain (domain,path)
+) $charset_collate;
+CREATE TABLE $wpdb->sitemeta (
+ meta_id bigint(20) NOT NULL auto_increment,
+ site_id bigint(20) NOT NULL default '0',
+ meta_key varchar(255) default NULL,
+ meta_value longtext,
+ PRIMARY KEY (meta_id),
+ KEY meta_key (meta_key),
+ KEY site_id (site_id)
+) $charset_collate;
+CREATE TABLE $wpdb->signups (
+ domain varchar(200) NOT NULL default '',
+ path varchar(100) NOT NULL default '',
+ title longtext NOT NULL,
+ user_login varchar(60) NOT NULL default '',
+ user_email varchar(100) NOT NULL default '',
+ registered datetime NOT NULL default '0000-00-00 00:00:00',
+ activated datetime NOT NULL default '0000-00-00 00:00:00',
+ active tinyint(1) NOT NULL default '0',
+ activation_key varchar(50) NOT NULL default '',
+ meta longtext,
+ KEY activation_key (activation_key),
+ KEY domain (domain)
+) $charset_collate;";
+
+ switch ( $scope ) {
+ case 'blog' :
+ $queries = $blog_tables;
+ break;
+ case 'global' :
+ $queries = $global_tables;
+ if ( $is_multisite )
+ $queries .= $ms_global_tables;
+ break;
+ case 'ms_global' :
+ $queries = $ms_global_tables;
+ break;
+ default:
+ case 'all' :
+ $queries = $global_tables . $blog_tables;
+ if ( $is_multisite )
+ $queries .= $ms_global_tables;
+ break;
+ }
+
+ if ( isset( $old_blog_id ) )
+ $wpdb->set_blog_id( $old_blog_id );
+
+ return $queries;
+}
+
+// Populate for back compat.
+$wp_queries = wp_get_db_schema( 'all' );
+
+/**
+ * Create WordPress options and set the default values.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ * @uses $wp_db_version
+ */
+function populate_options() {
+ global $wpdb, $wp_db_version, $current_site, $wp_current_db_version;
+
+ $guessurl = wp_guess_url();
+
+ do_action('populate_options');
+
+ if ( ini_get('safe_mode') ) {
+ // Safe mode can break mkdir() so use a flat structure by default.
+ $uploads_use_yearmonth_folders = 0;
+ } else {
+ $uploads_use_yearmonth_folders = 1;
+ }
+
+ $template = WP_DEFAULT_THEME;
+ // If default theme is a child theme, we need to get its template
+ $theme = wp_get_theme( $template );
+ if ( ! $theme->errors() )
+ $template = $theme->get_template();
+
+ $timezone_string = '';
+ $gmt_offset = 0;
+ /* translators: default GMT offset or timezone string. Must be either a valid offset (-12 to 14)
+ or a valid timezone string (America/New_York). See http://us3.php.net/manual/en/timezones.php
+ for all timezone strings supported by PHP.
+ */
+ $offset_or_tz = _x( '0', 'default GMT offset or timezone string' );
+ if ( is_numeric( $offset_or_tz ) )
+ $gmt_offset = $offset_or_tz;
+ elseif ( $offset_or_tz && in_array( $offset_or_tz, timezone_identifiers_list() ) )
+ $timezone_string = $offset_or_tz;
+
+ $options = array(
+ 'siteurl' => $guessurl,
+ 'blogname' => __('My Site'),
+ /* translators: blog tagline */
+ 'blogdescription' => __('Just another WordPress site'),
+ 'users_can_register' => 0,
+ 'admin_email' => 'you@example.com',
+ /* translators: default start of the week. 0 = Sunday, 1 = Monday */
+ 'start_of_week' => _x( '1', 'start of week' ),
+ 'use_balanceTags' => 0,
+ 'use_smilies' => 1,
+ 'require_name_email' => 1,
+ 'comments_notify' => 1,
+ 'posts_per_rss' => 10,
+ 'rss_use_excerpt' => 0,
+ 'mailserver_url' => 'mail.example.com',
+ 'mailserver_login' => 'login@example.com',
+ 'mailserver_pass' => 'password',
+ 'mailserver_port' => 110,
+ 'default_category' => 1,
+ 'default_comment_status' => 'open',
+ 'default_ping_status' => 'open',
+ 'default_pingback_flag' => 1,
+ 'posts_per_page' => 10,
+ /* translators: default date format, see http://php.net/date */
+ 'date_format' => __('F j, Y'),
+ /* translators: default time format, see http://php.net/date */
+ 'time_format' => __('g:i a'),
+ /* translators: links last updated date format, see http://php.net/date */
+ 'links_updated_date_format' => __('F j, Y g:i a'),
+ 'links_recently_updated_prepend' => '<em>',
+ 'links_recently_updated_append' => '</em>',
+ 'links_recently_updated_time' => 120,
+ 'comment_moderation' => 0,
+ 'moderation_notify' => 1,
+ 'permalink_structure' => '',
+ 'gzipcompression' => 0,
+ 'hack_file' => 0,
+ 'blog_charset' => 'UTF-8',
+ 'moderation_keys' => '',
+ 'active_plugins' => array(),
+ 'home' => $guessurl,
+ 'category_base' => '',
+ 'ping_sites' => 'http://rpc.pingomatic.com/',
+ 'advanced_edit' => 0,
+ 'comment_max_links' => 2,
+ 'gmt_offset' => $gmt_offset,
+
+ // 1.5
+ 'default_email_category' => 1,
+ 'recently_edited' => '',
+ 'template' => $template,
+ 'stylesheet' => WP_DEFAULT_THEME,
+ 'comment_whitelist' => 1,
+ 'blacklist_keys' => '',
+ 'comment_registration' => 0,
+ 'html_type' => 'text/html',
+
+ // 1.5.1
+ 'use_trackback' => 0,
+
+ // 2.0
+ 'default_role' => 'subscriber',
+ 'db_version' => $wp_db_version,
+
+ // 2.0.1
+ 'uploads_use_yearmonth_folders' => $uploads_use_yearmonth_folders,
+ 'upload_path' => '',
+
+ // 2.1
+ 'blog_public' => '1',
+ 'default_link_category' => 2,
+ 'show_on_front' => 'posts',
+
+ // 2.2
+ 'tag_base' => '',
+
+ // 2.5
+ 'show_avatars' => '1',
+ 'avatar_rating' => 'G',
+ 'upload_url_path' => '',
+ 'thumbnail_size_w' => 150,
+ 'thumbnail_size_h' => 150,
+ 'thumbnail_crop' => 1,
+ 'medium_size_w' => 300,
+ 'medium_size_h' => 300,
+
+ // 2.6
+ 'avatar_default' => 'mystery',
+
+ // 2.7
+ 'large_size_w' => 1024,
+ 'large_size_h' => 1024,
+ 'image_default_link_type' => 'file',
+ 'image_default_size' => '',
+ 'image_default_align' => '',
+ 'close_comments_for_old_posts' => 0,
+ 'close_comments_days_old' => 14,
+ 'thread_comments' => 1,
+ 'thread_comments_depth' => 5,
+ 'page_comments' => 0,
+ 'comments_per_page' => 50,
+ 'default_comments_page' => 'newest',
+ 'comment_order' => 'asc',
+ 'sticky_posts' => array(),
+ 'widget_categories' => array(),
+ 'widget_text' => array(),
+ 'widget_rss' => array(),
+ 'uninstall_plugins' => array(),
+
+ // 2.8
+ 'timezone_string' => $timezone_string,
+
+ // 3.0
+ 'page_for_posts' => 0,
+ 'page_on_front' => 0,
+
+ // 3.1
+ 'default_post_format' => 0,
+
+ // 3.5
+ 'link_manager_enabled' => 0,
+ );
+
+ // 3.3
+ if ( ! is_multisite() ) {
+ $options['initial_db_version'] = ! empty( $wp_current_db_version ) && $wp_current_db_version < $wp_db_version
+ ? $wp_current_db_version : $wp_db_version;
+ }
+
+ // 3.0 multisite
+ if ( is_multisite() ) {
+ /* translators: blog tagline */
+ $options[ 'blogdescription' ] = sprintf(__('Just another %s site'), $current_site->site_name );
+ $options[ 'permalink_structure' ] = '/%year%/%monthnum%/%day%/%postname%/';
+ }
+
+ // Set autoload to no for these options
+ $fat_options = array( 'moderation_keys', 'recently_edited', 'blacklist_keys', 'uninstall_plugins' );
+
+ $keys = "'" . implode( "', '", array_keys( $options ) ) . "'";
+ $existing_options = $wpdb->get_col( "SELECT option_name FROM $wpdb->options WHERE option_name in ( $keys )" );
+
+ $insert = '';
+ foreach ( $options as $option => $value ) {
+ if ( in_array($option, $existing_options) )
+ continue;
+ if ( in_array($option, $fat_options) )
+ $autoload = 'no';
+ else
+ $autoload = 'yes';
+
+ if ( is_array($value) )
+ $value = serialize($value);
+ if ( !empty($insert) )
+ $insert .= ', ';
+ $insert .= $wpdb->prepare( "(%s, %s, %s)", $option, $value, $autoload );
+ }
+
+ if ( !empty($insert) )
+ $wpdb->query("INSERT INTO $wpdb->options (option_name, option_value, autoload) VALUES " . $insert);
+
+ // in case it is set, but blank, update "home"
+ if ( !__get_option('home') ) update_option('home', $guessurl);
+
+ // Delete unused options
+ $unusedoptions = array(
+ 'blodotgsping_url', 'bodyterminator', 'emailtestonly', 'phoneemail_separator', 'smilies_directory',
+ 'subjectprefix', 'use_bbcode', 'use_blodotgsping', 'use_phoneemail', 'use_quicktags', 'use_weblogsping',
+ 'weblogs_cache_file', 'use_preview', 'use_htmltrans', 'smilies_directory', 'fileupload_allowedusers',
+ 'use_phoneemail', 'default_post_status', 'default_post_category', 'archive_mode', 'time_difference',
+ 'links_minadminlevel', 'links_use_adminlevels', 'links_rating_type', 'links_rating_char',
+ 'links_rating_ignore_zero', 'links_rating_single_image', 'links_rating_image0', 'links_rating_image1',
+ 'links_rating_image2', 'links_rating_image3', 'links_rating_image4', 'links_rating_image5',
+ 'links_rating_image6', 'links_rating_image7', 'links_rating_image8', 'links_rating_image9',
+ 'weblogs_cacheminutes', 'comment_allowed_tags', 'search_engine_friendly_urls', 'default_geourl_lat',
+ 'default_geourl_lon', 'use_default_geourl', 'weblogs_xml_url', 'new_users_can_blog', '_wpnonce',
+ '_wp_http_referer', 'Update', 'action', 'rich_editing', 'autosave_interval', 'deactivated_plugins',
+ 'can_compress_scripts', 'page_uris', 'update_core', 'update_plugins', 'update_themes', 'doing_cron',
+ 'random_seed', 'rss_excerpt_length', 'secret', 'use_linksupdate', 'default_comment_status_page',
+ 'wporg_popular_tags', 'what_to_show', 'rss_language', 'language', 'enable_xmlrpc', 'enable_app',
+ 'embed_autourls', 'default_post_edit_rows',
+ );
+ foreach ( $unusedoptions as $option )
+ delete_option($option);
+
+ // delete obsolete magpie stuff
+ $wpdb->query("DELETE FROM $wpdb->options WHERE option_name REGEXP '^rss_[0-9a-f]{32}(_ts)?$'");
+}
+
+/**
+ * Execute WordPress role creation for the various WordPress versions.
+ *
+ * @since 2.0.0
+ */
+function populate_roles() {
+ populate_roles_160();
+ populate_roles_210();
+ populate_roles_230();
+ populate_roles_250();
+ populate_roles_260();
+ populate_roles_270();
+ populate_roles_280();
+ populate_roles_300();
+}
+
+/**
+ * Create the roles for WordPress 2.0
+ *
+ * @since 2.0.0
+ */
+function populate_roles_160() {
+ // Add roles
+
+ // Dummy gettext calls to get strings in the catalog.
+ /* translators: user role */
+ _x('Administrator', 'User role');
+ /* translators: user role */
+ _x('Editor', 'User role');
+ /* translators: user role */
+ _x('Author', 'User role');
+ /* translators: user role */
+ _x('Contributor', 'User role');
+ /* translators: user role */
+ _x('Subscriber', 'User role');
+
+ add_role('administrator', 'Administrator');
+ add_role('editor', 'Editor');
+ add_role('author', 'Author');
+ add_role('contributor', 'Contributor');
+ add_role('subscriber', 'Subscriber');
+
+ // Add caps for Administrator role
+ $role = get_role('administrator');
+ $role->add_cap('switch_themes');
+ $role->add_cap('edit_themes');
+ $role->add_cap('activate_plugins');
+ $role->add_cap('edit_plugins');
+ $role->add_cap('edit_users');
+ $role->add_cap('edit_files');
+ $role->add_cap('manage_options');
+ $role->add_cap('moderate_comments');
+ $role->add_cap('manage_categories');
+ $role->add_cap('manage_links');
+ $role->add_cap('upload_files');
+ $role->add_cap('import');
+ $role->add_cap('unfiltered_html');
+ $role->add_cap('edit_posts');
+ $role->add_cap('edit_others_posts');
+ $role->add_cap('edit_published_posts');
+ $role->add_cap('publish_posts');
+ $role->add_cap('edit_pages');
+ $role->add_cap('read');
+ $role->add_cap('level_10');
+ $role->add_cap('level_9');
+ $role->add_cap('level_8');
+ $role->add_cap('level_7');
+ $role->add_cap('level_6');
+ $role->add_cap('level_5');
+ $role->add_cap('level_4');
+ $role->add_cap('level_3');
+ $role->add_cap('level_2');
+ $role->add_cap('level_1');
+ $role->add_cap('level_0');
+
+ // Add caps for Editor role
+ $role = get_role('editor');
+ $role->add_cap('moderate_comments');
+ $role->add_cap('manage_categories');
+ $role->add_cap('manage_links');
+ $role->add_cap('upload_files');
+ $role->add_cap('unfiltered_html');
+ $role->add_cap('edit_posts');
+ $role->add_cap('edit_others_posts');
+ $role->add_cap('edit_published_posts');
+ $role->add_cap('publish_posts');
+ $role->add_cap('edit_pages');
+ $role->add_cap('read');
+ $role->add_cap('level_7');
+ $role->add_cap('level_6');
+ $role->add_cap('level_5');
+ $role->add_cap('level_4');
+ $role->add_cap('level_3');
+ $role->add_cap('level_2');
+ $role->add_cap('level_1');
+ $role->add_cap('level_0');
+
+ // Add caps for Author role
+ $role = get_role('author');
+ $role->add_cap('upload_files');
+ $role->add_cap('edit_posts');
+ $role->add_cap('edit_published_posts');
+ $role->add_cap('publish_posts');
+ $role->add_cap('read');
+ $role->add_cap('level_2');
+ $role->add_cap('level_1');
+ $role->add_cap('level_0');
+
+ // Add caps for Contributor role
+ $role = get_role('contributor');
+ $role->add_cap('edit_posts');
+ $role->add_cap('read');
+ $role->add_cap('level_1');
+ $role->add_cap('level_0');
+
+ // Add caps for Subscriber role
+ $role = get_role('subscriber');
+ $role->add_cap('read');
+ $role->add_cap('level_0');
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 2.1.
+ *
+ * @since 2.1.0
+ */
+function populate_roles_210() {
+ $roles = array('administrator', 'editor');
+ foreach ($roles as $role) {
+ $role = get_role($role);
+ if ( empty($role) )
+ continue;
+
+ $role->add_cap('edit_others_pages');
+ $role->add_cap('edit_published_pages');
+ $role->add_cap('publish_pages');
+ $role->add_cap('delete_pages');
+ $role->add_cap('delete_others_pages');
+ $role->add_cap('delete_published_pages');
+ $role->add_cap('delete_posts');
+ $role->add_cap('delete_others_posts');
+ $role->add_cap('delete_published_posts');
+ $role->add_cap('delete_private_posts');
+ $role->add_cap('edit_private_posts');
+ $role->add_cap('read_private_posts');
+ $role->add_cap('delete_private_pages');
+ $role->add_cap('edit_private_pages');
+ $role->add_cap('read_private_pages');
+ }
+
+ $role = get_role('administrator');
+ if ( ! empty($role) ) {
+ $role->add_cap('delete_users');
+ $role->add_cap('create_users');
+ }
+
+ $role = get_role('author');
+ if ( ! empty($role) ) {
+ $role->add_cap('delete_posts');
+ $role->add_cap('delete_published_posts');
+ }
+
+ $role = get_role('contributor');
+ if ( ! empty($role) ) {
+ $role->add_cap('delete_posts');
+ }
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 2.3.
+ *
+ * @since 2.3.0
+ */
+function populate_roles_230() {
+ $role = get_role( 'administrator' );
+
+ if ( !empty( $role ) ) {
+ $role->add_cap( 'unfiltered_upload' );
+ }
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 2.5.
+ *
+ * @since 2.5.0
+ */
+function populate_roles_250() {
+ $role = get_role( 'administrator' );
+
+ if ( !empty( $role ) ) {
+ $role->add_cap( 'edit_dashboard' );
+ }
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 2.6.
+ *
+ * @since 2.6.0
+ */
+function populate_roles_260() {
+ $role = get_role( 'administrator' );
+
+ if ( !empty( $role ) ) {
+ $role->add_cap( 'update_plugins' );
+ $role->add_cap( 'delete_plugins' );
+ }
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 2.7.
+ *
+ * @since 2.7.0
+ */
+function populate_roles_270() {
+ $role = get_role( 'administrator' );
+
+ if ( !empty( $role ) ) {
+ $role->add_cap( 'install_plugins' );
+ $role->add_cap( 'update_themes' );
+ }
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 2.8.
+ *
+ * @since 2.8.0
+ */
+function populate_roles_280() {
+ $role = get_role( 'administrator' );
+
+ if ( !empty( $role ) ) {
+ $role->add_cap( 'install_themes' );
+ }
+}
+
+/**
+ * Create and modify WordPress roles for WordPress 3.0.
+ *
+ * @since 3.0.0
+ */
+function populate_roles_300() {
+ $role = get_role( 'administrator' );
+
+ if ( !empty( $role ) ) {
+ $role->add_cap( 'update_core' );
+ $role->add_cap( 'list_users' );
+ $role->add_cap( 'remove_users' );
+
+ // Never used, will be removed. create_users or
+ // promote_users is the capability you're looking for.
+ $role->add_cap( 'add_users' );
+
+ $role->add_cap( 'promote_users' );
+ $role->add_cap( 'edit_theme_options' );
+ $role->add_cap( 'delete_themes' );
+ $role->add_cap( 'export' );
+ }
+}
+
+/**
+ * Install Network.
+ *
+ * @since 3.0.0
+ *
+ */
+if ( !function_exists( 'install_network' ) ) :
+function install_network() {
+ if ( ! defined( 'WP_INSTALLING_NETWORK' ) )
+ define( 'WP_INSTALLING_NETWORK', true );
+
+ dbDelta( wp_get_db_schema( 'global' ) );
+}
+endif;
+
+/**
+ * populate network settings
+ *
+ * @since 3.0.0
+ *
+ * @param int $network_id id of network to populate
+ * @return bool|WP_Error True on success, or WP_Error on warning (with the install otherwise successful,
+ * so the error code must be checked) or failure.
+ */
+function populate_network( $network_id = 1, $domain = '', $email = '', $site_name = '', $path = '/', $subdomain_install = false ) {
+ global $wpdb, $current_site, $wp_db_version, $wp_rewrite;
+
+ $errors = new WP_Error();
+ if ( '' == $domain )
+ $errors->add( 'empty_domain', __( 'You must provide a domain name.' ) );
+ if ( '' == $site_name )
+ $errors->add( 'empty_sitename', __( 'You must provide a name for your network of sites.' ) );
+
+ // check for network collision
+ if ( $network_id == $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->site WHERE id = %d", $network_id ) ) )
+ $errors->add( 'siteid_exists', __( 'The network already exists.' ) );
+
+ $site_user = get_user_by( 'email', $email );
+ if ( ! is_email( $email ) )
+ $errors->add( 'invalid_email', __( 'You must provide a valid e-mail address.' ) );
+
+ if ( $errors->get_error_code() )
+ return $errors;
+
+ // set up site tables
+ $template = get_option( 'template' );
+ $stylesheet = get_option( 'stylesheet' );
+ $allowed_themes = array( $stylesheet => true );
+ if ( $template != $stylesheet )
+ $allowed_themes[ $template ] = true;
+ if ( WP_DEFAULT_THEME != $stylesheet && WP_DEFAULT_THEME != $template )
+ $allowed_themes[ WP_DEFAULT_THEME ] = true;
+
+ if ( 1 == $network_id ) {
+ $wpdb->insert( $wpdb->site, array( 'domain' => $domain, 'path' => $path ) );
+ $network_id = $wpdb->insert_id;
+ } else {
+ $wpdb->insert( $wpdb->site, array( 'domain' => $domain, 'path' => $path, 'id' => $network_id ) );
+ }
+
+ if ( !is_multisite() ) {
+ $site_admins = array( $site_user->user_login );
+ $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) );
+ if ( $users ) {
+ foreach ( $users as $user ) {
+ if ( is_super_admin( $user->ID ) && !in_array( $user->user_login, $site_admins ) )
+ $site_admins[] = $user->user_login;
+ }
+ }
+ } else {
+ $site_admins = get_site_option( 'site_admins' );
+ }
+
+ $welcome_email = __( 'Dear User,
+
+Your new SITE_NAME site has been successfully set up at:
+BLOG_URL
+
+You can log in to the administrator account with the following information:
+Username: USERNAME
+Password: PASSWORD
+Log in here: BLOG_URLwp-login.php
+
+We hope you enjoy your new site. Thanks!
+
+--The Team @ SITE_NAME' );
+
+ $sitemeta = array(
+ 'site_name' => $site_name,
+ 'admin_email' => $site_user->user_email,
+ 'admin_user_id' => $site_user->ID,
+ 'registration' => 'none',
+ 'upload_filetypes' => 'jpg jpeg png gif mp3 mov avi wmv midi mid pdf',
+ 'blog_upload_space' => 100,
+ 'fileupload_maxk' => 1500,
+ 'site_admins' => $site_admins,
+ 'allowedthemes' => $allowed_themes,
+ 'illegal_names' => array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator', 'files' ),
+ 'wpmu_upgrade_site' => $wp_db_version,
+ 'welcome_email' => $welcome_email,
+ 'first_post' => __( 'Welcome to <a href="SITE_URL">SITE_NAME</a>. This is your first post. Edit or delete it, then start blogging!' ),
+ // @todo - network admins should have a method of editing the network siteurl (used for cookie hash)
+ 'siteurl' => get_option( 'siteurl' ) . '/',
+ 'add_new_users' => '0',
+ 'upload_space_check_disabled' => is_multisite() ? get_site_option( 'upload_space_check_disabled' ) : '1',
+ 'subdomain_install' => intval( $subdomain_install ),
+ 'global_terms_enabled' => global_terms_enabled() ? '1' : '0',
+ 'ms_files_rewriting' => is_multisite() ? get_site_option( 'ms_files_rewriting' ) : '0',
+ 'initial_db_version' => get_option( 'initial_db_version' ),
+ 'active_sitewide_plugins' => array(),
+ 'WPLANG' => get_locale(),
+ );
+ if ( ! $subdomain_install )
+ $sitemeta['illegal_names'][] = 'blog';
+
+ $insert = '';
+ foreach ( $sitemeta as $meta_key => $meta_value ) {
+ if ( is_array( $meta_value ) )
+ $meta_value = serialize( $meta_value );
+ if ( !empty( $insert ) )
+ $insert .= ', ';
+ $insert .= $wpdb->prepare( "( %d, %s, %s)", $network_id, $meta_key, $meta_value );
+ }
+ $wpdb->query( "INSERT INTO $wpdb->sitemeta ( site_id, meta_key, meta_value ) VALUES " . $insert );
+
+ // When upgrading from single to multisite, assume the current site will become the main site of the network.
+ // When using populate_network() to create another network in an existing multisite environment,
+ // skip these steps since the main site of the new network has not yet been created.
+ if ( ! is_multisite() ) {
+ $current_site = new stdClass;
+ $current_site->domain = $domain;
+ $current_site->path = $path;
+ $current_site->site_name = ucfirst( $domain );
+ $wpdb->insert( $wpdb->blogs, array( 'site_id' => $network_id, 'domain' => $domain, 'path' => $path, 'registered' => current_time( 'mysql' ) ) );
+ $current_site->blog_id = $blog_id = $wpdb->insert_id;
+ update_user_meta( $site_user->ID, 'source_domain', $domain );
+ update_user_meta( $site_user->ID, 'primary_blog', $blog_id );
+
+ if ( $subdomain_install )
+ $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' );
+ else
+ $wp_rewrite->set_permalink_structure( '/blog/%year%/%monthnum%/%day%/%postname%/' );
+
+ flush_rewrite_rules();
+ }
+
+ if ( $subdomain_install ) {
+ $vhost_ok = false;
+ $errstr = '';
+ $hostname = substr( md5( time() ), 0, 6 ) . '.' . $domain; // Very random hostname!
+ $page = wp_remote_get( 'http://' . $hostname, array( 'timeout' => 5, 'httpversion' => '1.1' ) );
+ if ( is_wp_error( $page ) )
+ $errstr = $page->get_error_message();
+ elseif ( 200 == wp_remote_retrieve_response_code( $page ) )
+ $vhost_ok = true;
+
+ if ( ! $vhost_ok ) {
+ $msg = '<p><strong>' . __( 'Warning! Wildcard DNS may not be configured correctly!' ) . '</strong></p>';
+ $msg .= '<p>' . sprintf( __( 'The installer attempted to contact a random hostname (<code>%1$s</code>) on your domain.' ), $hostname );
+ if ( ! empty ( $errstr ) )
+ $msg .= ' ' . sprintf( __( 'This resulted in an error message: %s' ), '<code>' . $errstr . '</code>' );
+ $msg .= '</p>';
+ $msg .= '<p>' . __( 'To use a subdomain configuration, you must have a wildcard entry in your DNS. This usually means adding a <code>*</code> hostname record pointing at your web server in your DNS configuration tool.' ) . '</p>';
+ $msg .= '<p>' . __( 'You can still use your site but any subdomain you create may not be accessible. If you know your DNS is correct, ignore this message.' ) . '</p>';
+ return new WP_Error( 'no_wildcard_dns', $msg );
+ }
+ }
+
+ return true;
+}
diff --git a/src/wp-admin/includes/screen.php b/src/wp-admin/includes/screen.php
new file mode 100644
index 0000000000..2ab5161bff
--- /dev/null
+++ b/src/wp-admin/includes/screen.php
@@ -0,0 +1,1080 @@
+<?php
+/**
+ * WordPress Administration Screen API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Get the column headers for a screen
+ *
+ * @since 2.7.0
+ *
+ * @param string|WP_Screen $screen The screen you want the headers for
+ * @return array Containing the headers in the format id => UI String
+ */
+function get_column_headers( $screen ) {
+ if ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ static $column_headers = array();
+
+ if ( ! isset( $column_headers[ $screen->id ] ) )
+ $column_headers[ $screen->id ] = apply_filters( 'manage_' . $screen->id . '_columns', array() );
+
+ return $column_headers[ $screen->id ];
+}
+
+/**
+ * Get a list of hidden columns.
+ *
+ * @since 2.7.0
+ *
+ * @param string|WP_Screen $screen The screen you want the hidden columns for
+ * @return array
+ */
+function get_hidden_columns( $screen ) {
+ if ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ return (array) get_user_option( 'manage' . $screen->id . 'columnshidden' );
+}
+
+/**
+ * Prints the meta box preferences for screen meta.
+ *
+ * @since 2.7.0
+ *
+ * @param string|WP_Screen $screen
+ */
+function meta_box_prefs( $screen ) {
+ global $wp_meta_boxes;
+
+ if ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ if ( empty($wp_meta_boxes[$screen->id]) )
+ return;
+
+ $hidden = get_hidden_meta_boxes($screen);
+
+ foreach ( array_keys($wp_meta_boxes[$screen->id]) as $context ) {
+ foreach ( array_keys($wp_meta_boxes[$screen->id][$context]) as $priority ) {
+ foreach ( $wp_meta_boxes[$screen->id][$context][$priority] as $box ) {
+ if ( false == $box || ! $box['title'] )
+ continue;
+ // Submit box cannot be hidden
+ if ( 'submitdiv' == $box['id'] || 'linksubmitdiv' == $box['id'] )
+ continue;
+ $box_id = $box['id'];
+ echo '<label for="' . $box_id . '-hide">';
+ echo '<input class="hide-postbox-tog" name="' . $box_id . '-hide" type="checkbox" id="' . $box_id . '-hide" value="' . $box_id . '"' . (! in_array($box_id, $hidden) ? ' checked="checked"' : '') . ' />';
+ echo "{$box['title']}</label>\n";
+ }
+ }
+ }
+}
+
+/**
+ * Get Hidden Meta Boxes
+ *
+ * @since 2.7.0
+ *
+ * @param string|WP_Screen $screen Screen identifier
+ * @return array Hidden Meta Boxes
+ */
+function get_hidden_meta_boxes( $screen ) {
+ if ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ $hidden = get_user_option( "metaboxhidden_{$screen->id}" );
+
+ $use_defaults = ! is_array( $hidden );
+
+ // Hide slug boxes by default
+ if ( $use_defaults ) {
+ $hidden = array();
+ if ( 'post' == $screen->base ) {
+ if ( 'post' == $screen->post_type || 'page' == $screen->post_type || 'attachment' == $screen->post_type )
+ $hidden = array('slugdiv', 'trackbacksdiv', 'postcustom', 'postexcerpt', 'commentstatusdiv', 'commentsdiv', 'authordiv', 'revisionsdiv');
+ else
+ $hidden = array( 'slugdiv' );
+ }
+ $hidden = apply_filters( 'default_hidden_meta_boxes', $hidden, $screen );
+ }
+
+ return apply_filters( 'hidden_meta_boxes', $hidden, $screen, $use_defaults );
+}
+
+/**
+ * Register and configure an admin screen option
+ *
+ * @since 3.1.0
+ *
+ * @param string $option An option name.
+ * @param mixed $args Option-dependent arguments.
+ */
+function add_screen_option( $option, $args = array() ) {
+ $current_screen = get_current_screen();
+
+ if ( ! $current_screen )
+ return;
+
+ $current_screen->add_option( $option, $args );
+}
+
+/**
+ * Displays a screen icon.
+ *
+ * @uses get_screen_icon()
+ * @since 2.7.0
+ *
+ * @param string|WP_Screen $screen Optional. Accepts a screen object (and defaults to the current screen object)
+ * which it uses to determine an icon HTML ID. Or, if a string is provided, it is used to form the icon HTML ID.
+ */
+function screen_icon( $screen = '' ) {
+ echo get_screen_icon( $screen );
+}
+
+/**
+ * Gets a screen icon.
+ *
+ * @since 3.2.0
+ *
+ * @global $post_ID
+ * @param string|WP_Screen $screen Optional. Accepts a screen object (and defaults to the current screen object)
+ * which it uses to determine an icon HTML ID. Or, if a string is provided, it is used to form the icon HTML ID.
+ * @return string HTML for the screen icon.
+ */
+function get_screen_icon( $screen = '' ) {
+ if ( empty( $screen ) )
+ $screen = get_current_screen();
+ elseif ( is_string( $screen ) )
+ $icon_id = $screen;
+
+ $class = 'icon32';
+
+ if ( empty( $icon_id ) ) {
+ if ( ! empty( $screen->parent_base ) )
+ $icon_id = $screen->parent_base;
+ else
+ $icon_id = $screen->base;
+
+ if ( 'page' == $screen->post_type )
+ $icon_id = 'edit-pages';
+
+ if ( $screen->post_type )
+ $class .= ' ' . sanitize_html_class( 'icon32-posts-' . $screen->post_type );
+ }
+
+ return '<div id="icon-' . esc_attr( $icon_id ) . '" class="' . $class . '"><br /></div>';
+}
+
+/**
+ * Get the current screen object
+ *
+ * @since 3.1.0
+ *
+ * @return WP_Screen Current screen object
+ */
+function get_current_screen() {
+ global $current_screen;
+
+ if ( ! isset( $current_screen ) )
+ return null;
+
+ return $current_screen;
+}
+
+/**
+ * Set the current screen object
+ *
+ * @since 3.0.0
+ * @uses $current_screen
+ *
+ * @param mixed $hook_name Optional. The hook name (also known as the hook suffix) used to determine the screen,
+ * or an existing screen object.
+ */
+function set_current_screen( $hook_name = '' ) {
+ WP_Screen::get( $hook_name )->set_current_screen();
+}
+
+/**
+ * A class representing the admin screen.
+ *
+ * @since 3.3.0
+ * @access public
+ */
+final class WP_Screen {
+ /**
+ * Any action associated with the screen. 'add' for *-add.php and *-new.php screens. Empty otherwise.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $action;
+
+ /**
+ * The base type of the screen. This is typically the same as $id but with any post types and taxonomies stripped.
+ * For example, for an $id of 'edit-post' the base is 'edit'.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $base;
+
+ /**
+ * The number of columns to display. Access with get_columns().
+ *
+ * @since 3.4.0
+ * @var int
+ * @access private
+ */
+ private $columns = 0;
+
+ /**
+ * The unique ID of the screen.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $id;
+
+ /**
+ * Which admin the screen is in. network | user | site | false
+ *
+ * @since 3.5.0
+ * @var string
+ * @access protected
+ */
+ protected $in_admin;
+
+ /**
+ * Whether the screen is in the network admin.
+ *
+ * Deprecated. Use in_admin() instead.
+ *
+ * @since 3.3.0
+ * @deprecated 3.5.0
+ * @var bool
+ * @access public
+ */
+ public $is_network;
+
+ /**
+ * Whether the screen is in the user admin.
+ *
+ * Deprecated. Use in_admin() instead.
+ *
+ * @since 3.3.0
+ * @deprecated 3.5.0
+ * @var bool
+ * @access public
+ */
+ public $is_user;
+
+ /**
+ * The base menu parent.
+ * This is derived from $parent_file by removing the query string and any .php extension.
+ * $parent_file values of 'edit.php?post_type=page' and 'edit.php?post_type=post' have a $parent_base of 'edit'.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $parent_base;
+
+ /**
+ * The parent_file for the screen per the admin menu system.
+ * Some $parent_file values are 'edit.php?post_type=page', 'edit.php', and 'options-general.php'.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $parent_file;
+
+ /**
+ * The post type associated with the screen, if any.
+ * The 'edit.php?post_type=page' screen has a post type of 'page'.
+ * The 'edit-tags.php?taxonomy=$taxonomy&post_type=page' screen has a post type of 'page'.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $post_type;
+
+ /**
+ * The taxonomy associated with the screen, if any.
+ * The 'edit-tags.php?taxonomy=category' screen has a taxonomy of 'category'.
+ * @since 3.3.0
+ * @var string
+ * @access public
+ */
+ public $taxonomy;
+
+ /**
+ * The help tab data associated with the screen, if any.
+ *
+ * @since 3.3.0
+ * @var array
+ * @access private
+ */
+ private $_help_tabs = array();
+
+ /**
+ * The help sidebar data associated with screen, if any.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access private
+ */
+ private $_help_sidebar = '';
+
+ /**
+ * Stores old string-based help.
+ */
+ private static $_old_compat_help = array();
+
+ /**
+ * The screen options associated with screen, if any.
+ *
+ * @since 3.3.0
+ * @var array
+ * @access private
+ */
+ private $_options = array();
+
+ /**
+ * The screen object registry.
+ *
+ * @since 3.3.0
+ * @var array
+ * @access private
+ */
+ private static $_registry = array();
+
+ /**
+ * Stores the result of the public show_screen_options function.
+ *
+ * @since 3.3.0
+ * @var bool
+ * @access private
+ */
+ private $_show_screen_options;
+
+ /**
+ * Stores the 'screen_settings' section of screen options.
+ *
+ * @since 3.3.0
+ * @var string
+ * @access private
+ */
+ private $_screen_settings;
+
+ /**
+ * Fetches a screen object.
+ *
+ * @since 3.3.0
+ * @access public
+ *
+ * @param string $hook_name Optional. The hook name (also known as the hook suffix) used to determine the screen.
+ * Defaults to the current $hook_suffix global.
+ * @return WP_Screen Screen object.
+ */
+ public static function get( $hook_name = '' ) {
+
+ if ( is_a( $hook_name, 'WP_Screen' ) )
+ return $hook_name;
+
+ $post_type = $taxonomy = null;
+ $in_admin = false;
+ $action = '';
+
+ if ( $hook_name )
+ $id = $hook_name;
+ else
+ $id = $GLOBALS['hook_suffix'];
+
+ // For those pesky meta boxes.
+ if ( $hook_name && post_type_exists( $hook_name ) ) {
+ $post_type = $id;
+ $id = 'post'; // changes later. ends up being $base.
+ } else {
+ if ( '.php' == substr( $id, -4 ) )
+ $id = substr( $id, 0, -4 );
+
+ if ( 'post-new' == $id || 'link-add' == $id || 'media-new' == $id || 'user-new' == $id ) {
+ $id = substr( $id, 0, -4 );
+ $action = 'add';
+ }
+ }
+
+ if ( ! $post_type && $hook_name ) {
+ if ( '-network' == substr( $id, -8 ) ) {
+ $id = substr( $id, 0, -8 );
+ $in_admin = 'network';
+ } elseif ( '-user' == substr( $id, -5 ) ) {
+ $id = substr( $id, 0, -5 );
+ $in_admin = 'user';
+ }
+
+ $id = sanitize_key( $id );
+ if ( 'edit-comments' != $id && 'edit-tags' != $id && 'edit-' == substr( $id, 0, 5 ) ) {
+ $maybe = substr( $id, 5 );
+ if ( taxonomy_exists( $maybe ) ) {
+ $id = 'edit-tags';
+ $taxonomy = $maybe;
+ } elseif ( post_type_exists( $maybe ) ) {
+ $id = 'edit';
+ $post_type = $maybe;
+ }
+ }
+
+ if ( ! $in_admin )
+ $in_admin = 'site';
+ } else {
+ if ( defined( 'WP_NETWORK_ADMIN' ) && WP_NETWORK_ADMIN )
+ $in_admin = 'network';
+ elseif ( defined( 'WP_USER_ADMIN' ) && WP_USER_ADMIN )
+ $in_admin = 'user';
+ else
+ $in_admin = 'site';
+ }
+
+ if ( 'index' == $id )
+ $id = 'dashboard';
+ elseif ( 'front' == $id )
+ $in_admin = false;
+
+ $base = $id;
+
+ // If this is the current screen, see if we can be more accurate for post types and taxonomies.
+ if ( ! $hook_name ) {
+ if ( isset( $_REQUEST['post_type'] ) )
+ $post_type = post_type_exists( $_REQUEST['post_type'] ) ? $_REQUEST['post_type'] : false;
+ if ( isset( $_REQUEST['taxonomy'] ) )
+ $taxonomy = taxonomy_exists( $_REQUEST['taxonomy'] ) ? $_REQUEST['taxonomy'] : false;
+
+ switch ( $base ) {
+ case 'post' :
+ if ( isset( $_GET['post'] ) )
+ $post_id = (int) $_GET['post'];
+ elseif ( isset( $_POST['post_ID'] ) )
+ $post_id = (int) $_POST['post_ID'];
+ else
+ $post_id = 0;
+
+ if ( $post_id ) {
+ $post = get_post( $post_id );
+ if ( $post )
+ $post_type = $post->post_type;
+ }
+ break;
+ case 'edit-tags' :
+ if ( null === $post_type && is_object_in_taxonomy( 'post', $taxonomy ? $taxonomy : 'post_tag' ) )
+ $post_type = 'post';
+ break;
+ }
+ }
+
+ switch ( $base ) {
+ case 'post' :
+ if ( null === $post_type )
+ $post_type = 'post';
+ $id = $post_type;
+ break;
+ case 'edit' :
+ if ( null === $post_type )
+ $post_type = 'post';
+ $id .= '-' . $post_type;
+ break;
+ case 'edit-tags' :
+ if ( null === $taxonomy )
+ $taxonomy = 'post_tag';
+ // The edit-tags ID does not contain the post type. Look for it in the request.
+ if ( null === $post_type ) {
+ $post_type = 'post';
+ if ( isset( $_REQUEST['post_type'] ) && post_type_exists( $_REQUEST['post_type'] ) )
+ $post_type = $_REQUEST['post_type'];
+ }
+
+ $id = 'edit-' . $taxonomy;
+ break;
+ }
+
+ if ( 'network' == $in_admin ) {
+ $id .= '-network';
+ $base .= '-network';
+ } elseif ( 'user' == $in_admin ) {
+ $id .= '-user';
+ $base .= '-user';
+ }
+
+ if ( isset( self::$_registry[ $id ] ) ) {
+ $screen = self::$_registry[ $id ];
+ if ( $screen === get_current_screen() )
+ return $screen;
+ } else {
+ $screen = new WP_Screen();
+ $screen->id = $id;
+ }
+
+ $screen->base = $base;
+ $screen->action = $action;
+ $screen->post_type = (string) $post_type;
+ $screen->taxonomy = (string) $taxonomy;
+ $screen->is_user = ( 'user' == $in_admin );
+ $screen->is_network = ( 'network' == $in_admin );
+ $screen->in_admin = $in_admin;
+
+ self::$_registry[ $id ] = $screen;
+
+ return $screen;
+ }
+
+ /**
+ * Makes the screen object the current screen.
+ *
+ * @see set_current_screen()
+ * @since 3.3.0
+ */
+ function set_current_screen() {
+ global $current_screen, $taxnow, $typenow;
+ $current_screen = $this;
+ $taxnow = $this->taxonomy;
+ $typenow = $this->post_type;
+ do_action( 'current_screen', $current_screen );
+ }
+
+ /**
+ * Constructor
+ *
+ * @since 3.3.0
+ * @access private
+ */
+ private function __construct() {}
+
+ /**
+ * Indicates whether the screen is in a particular admin
+ *
+ * @since 3.5.0
+ *
+ * @param string $admin The admin to check against (network | user | site).
+ * If empty any of the three admins will result in true.
+ * @return boolean True if the screen is in the indicated admin, false otherwise.
+ *
+ */
+ public function in_admin( $admin = null ) {
+ if ( empty( $admin ) )
+ return (bool) $this->in_admin;
+
+ return ( $admin == $this->in_admin );
+ }
+
+ /**
+ * Sets the old string-based contextual help for the screen.
+ *
+ * For backwards compatibility.
+ *
+ * @since 3.3.0
+ *
+ * @param WP_Screen $screen A screen object.
+ * @param string $help Help text.
+ */
+ static function add_old_compat_help( $screen, $help ) {
+ self::$_old_compat_help[ $screen->id ] = $help;
+ }
+
+ /**
+ * Set the parent information for the screen.
+ * This is called in admin-header.php after the menu parent for the screen has been determined.
+ *
+ * @since 3.3.0
+ *
+ * @param string $parent_file The parent file of the screen. Typically the $parent_file global.
+ */
+ function set_parentage( $parent_file ) {
+ $this->parent_file = $parent_file;
+ list( $this->parent_base ) = explode( '?', $parent_file );
+ $this->parent_base = str_replace( '.php', '', $this->parent_base );
+ }
+
+ /**
+ * Adds an option for the screen.
+ * Call this in template files after admin.php is loaded and before admin-header.php is loaded to add screen options.
+ *
+ * @since 3.3.0
+ *
+ * @param string $option Option ID
+ * @param mixed $args Option-dependent arguments.
+ */
+ public function add_option( $option, $args = array() ) {
+ $this->_options[ $option ] = $args;
+ }
+
+ /**
+ * Gets the arguments for an option for the screen.
+ *
+ * @since 3.3.0
+ *
+ * @param string $option Option ID.
+ * @param mixed $key Optional. Specific array key for when the option is an array.
+ */
+ public function get_option( $option, $key = false ) {
+ if ( ! isset( $this->_options[ $option ] ) )
+ return null;
+ if ( $key ) {
+ if ( isset( $this->_options[ $option ][ $key ] ) )
+ return $this->_options[ $option ][ $key ];
+ return null;
+ }
+ return $this->_options[ $option ];
+ }
+
+ /**
+ * Gets the help tabs registered for the screen.
+ *
+ * @since 3.4.0
+ *
+ * @return array Help tabs with arguments.
+ */
+ public function get_help_tabs() {
+ return $this->_help_tabs;
+ }
+
+ /**
+ * Gets the arguments for a help tab.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id Help Tab ID.
+ * @return array Help tab arguments.
+ */
+ public function get_help_tab( $id ) {
+ if ( ! isset( $this->_help_tabs[ $id ] ) )
+ return null;
+ return $this->_help_tabs[ $id ];
+ }
+
+ /**
+ * Add a help tab to the contextual help for the screen.
+ * Call this on the load-$pagenow hook for the relevant screen.
+ *
+ * @since 3.3.0
+ *
+ * @param array $args
+ * - string - title - Title for the tab.
+ * - string - id - Tab ID. Must be HTML-safe.
+ * - string - content - Help tab content in plain text or HTML. Optional.
+ * - callback - callback - A callback to generate the tab content. Optional.
+ *
+ */
+ public function add_help_tab( $args ) {
+ $defaults = array(
+ 'title' => false,
+ 'id' => false,
+ 'content' => '',
+ 'callback' => false,
+ );
+ $args = wp_parse_args( $args, $defaults );
+
+ $args['id'] = sanitize_html_class( $args['id'] );
+
+ // Ensure we have an ID and title.
+ if ( ! $args['id'] || ! $args['title'] )
+ return;
+
+ // Allows for overriding an existing tab with that ID.
+ $this->_help_tabs[ $args['id'] ] = $args;
+ }
+
+ /**
+ * Removes a help tab from the contextual help for the screen.
+ *
+ * @since 3.3.0
+ *
+ * @param string $id The help tab ID.
+ */
+ public function remove_help_tab( $id ) {
+ unset( $this->_help_tabs[ $id ] );
+ }
+
+ /**
+ * Removes all help tabs from the contextual help for the screen.
+ *
+ * @since 3.3.0
+ */
+ public function remove_help_tabs() {
+ $this->_help_tabs = array();
+ }
+
+ /**
+ * Gets the content from a contextual help sidebar.
+ *
+ * @since 3.4.0
+ *
+ * @return string Contents of the help sidebar.
+ */
+ public function get_help_sidebar() {
+ return $this->_help_sidebar;
+ }
+
+ /**
+ * Add a sidebar to the contextual help for the screen.
+ * Call this in template files after admin.php is loaded and before admin-header.php is loaded to add a sidebar to the contextual help.
+ *
+ * @since 3.3.0
+ *
+ * @param string $content Sidebar content in plain text or HTML.
+ */
+ public function set_help_sidebar( $content ) {
+ $this->_help_sidebar = $content;
+ }
+
+ /**
+ * Gets the number of layout columns the user has selected.
+ *
+ * The layout_columns option controls the max number and default number of
+ * columns. This method returns the number of columns within that range selected
+ * by the user via Screen Options. If no selection has been made, the default
+ * provisioned in layout_columns is returned. If the screen does not support
+ * selecting the number of layout columns, 0 is returned.
+ *
+ * @since 3.4.0
+ *
+ * @return int Number of columns to display.
+ */
+ public function get_columns() {
+ return $this->columns;
+ }
+
+ /**
+ * Render the screen's help section.
+ *
+ * This will trigger the deprecated filters for backwards compatibility.
+ *
+ * @since 3.3.0
+ */
+ public function render_screen_meta() {
+
+ // Call old contextual_help_list filter.
+ self::$_old_compat_help = apply_filters( 'contextual_help_list', self::$_old_compat_help, $this );
+
+ $old_help = isset( self::$_old_compat_help[ $this->id ] ) ? self::$_old_compat_help[ $this->id ] : '';
+ $old_help = apply_filters( 'contextual_help', $old_help, $this->id, $this );
+
+ // Default help only if there is no old-style block of text and no new-style help tabs.
+ if ( empty( $old_help ) && ! $this->get_help_tabs() ) {
+ $default_help = apply_filters( 'default_contextual_help', '' );
+ if ( $default_help )
+ $old_help = '<p>' . $default_help . '</p>';
+ }
+
+ if ( $old_help ) {
+ $this->add_help_tab( array(
+ 'id' => 'old-contextual-help',
+ 'title' => __('Overview'),
+ 'content' => $old_help,
+ ) );
+ }
+
+ $help_sidebar = $this->get_help_sidebar();
+
+ $help_class = 'hidden';
+ if ( ! $help_sidebar )
+ $help_class .= ' no-sidebar';
+
+ // Time to render!
+ ?>
+ <div id="screen-meta" class="metabox-prefs">
+
+ <div id="contextual-help-wrap" class="<?php echo esc_attr( $help_class ); ?>" tabindex="-1" aria-label="<?php esc_attr_e('Contextual Help Tab'); ?>">
+ <div id="contextual-help-back"></div>
+ <div id="contextual-help-columns">
+ <div class="contextual-help-tabs">
+ <ul>
+ <?php
+ $class = ' class="active"';
+ foreach ( $this->get_help_tabs() as $tab ) :
+ $link_id = "tab-link-{$tab['id']}";
+ $panel_id = "tab-panel-{$tab['id']}";
+ ?>
+
+ <li id="<?php echo esc_attr( $link_id ); ?>"<?php echo $class; ?>>
+ <a href="<?php echo esc_url( "#$panel_id" ); ?>" aria-controls="<?php echo esc_attr( $panel_id ); ?>">
+ <?php echo esc_html( $tab['title'] ); ?>
+ </a>
+ </li>
+ <?php
+ $class = '';
+ endforeach;
+ ?>
+ </ul>
+ </div>
+
+ <?php if ( $help_sidebar ) : ?>
+ <div class="contextual-help-sidebar">
+ <?php echo $help_sidebar; ?>
+ </div>
+ <?php endif; ?>
+
+ <div class="contextual-help-tabs-wrap">
+ <?php
+ $classes = 'help-tab-content active';
+ foreach ( $this->get_help_tabs() as $tab ):
+ $panel_id = "tab-panel-{$tab['id']}";
+ ?>
+
+ <div id="<?php echo esc_attr( $panel_id ); ?>" class="<?php echo $classes; ?>">
+ <?php
+ // Print tab content.
+ echo $tab['content'];
+
+ // If it exists, fire tab callback.
+ if ( ! empty( $tab['callback'] ) )
+ call_user_func_array( $tab['callback'], array( $this, $tab ) );
+ ?>
+ </div>
+ <?php
+ $classes = 'help-tab-content';
+ endforeach;
+ ?>
+ </div>
+ </div>
+ </div>
+ <?php
+ // Setup layout columns
+
+ // Back compat for plugins using the filter instead of add_screen_option()
+ $columns = apply_filters( 'screen_layout_columns', array(), $this->id, $this );
+
+ if ( ! empty( $columns ) && isset( $columns[ $this->id ] ) )
+ $this->add_option( 'layout_columns', array('max' => $columns[ $this->id ] ) );
+
+ if ( $this->get_option( 'layout_columns' ) ) {
+ $this->columns = (int) get_user_option("screen_layout_$this->id");
+
+ if ( ! $this->columns && $this->get_option( 'layout_columns', 'default' ) )
+ $this->columns = $this->get_option( 'layout_columns', 'default' );
+ }
+ $GLOBALS[ 'screen_layout_columns' ] = $this->columns; // Set the global for back-compat.
+
+ // Add screen options
+ if ( $this->show_screen_options() )
+ $this->render_screen_options();
+ ?>
+ </div>
+ <?php
+ if ( ! $this->get_help_tabs() && ! $this->show_screen_options() )
+ return;
+ ?>
+ <div id="screen-meta-links">
+ <?php if ( $this->get_help_tabs() ) : ?>
+ <div id="contextual-help-link-wrap" class="hide-if-no-js screen-meta-toggle">
+ <a href="#contextual-help-wrap" id="contextual-help-link" class="show-settings" aria-controls="contextual-help-wrap" aria-expanded="false"><?php _e( 'Help' ); ?></a>
+ </div>
+ <?php endif;
+ if ( $this->show_screen_options() ) : ?>
+ <div id="screen-options-link-wrap" class="hide-if-no-js screen-meta-toggle">
+ <a href="#screen-options-wrap" id="show-settings-link" class="show-settings" aria-controls="screen-options-wrap" aria-expanded="false"><?php _e( 'Screen Options' ); ?></a>
+ </div>
+ <?php endif; ?>
+ </div>
+ <?php
+ }
+
+ public function show_screen_options() {
+ global $wp_meta_boxes;
+
+ if ( is_bool( $this->_show_screen_options ) )
+ return $this->_show_screen_options;
+
+ $columns = get_column_headers( $this );
+
+ $show_screen = ! empty( $wp_meta_boxes[ $this->id ] ) || $columns || $this->get_option( 'per_page' );
+
+ switch ( $this->id ) {
+ case 'widgets':
+ $this->_screen_settings = '<p><a id="access-on" href="widgets.php?widgets-access=on">' . __('Enable accessibility mode') . '</a><a id="access-off" href="widgets.php?widgets-access=off">' . __('Disable accessibility mode') . "</a></p>\n";
+ break;
+ default:
+ $this->_screen_settings = '';
+ break;
+ }
+
+ $this->_screen_settings = apply_filters( 'screen_settings', $this->_screen_settings, $this );
+
+ if ( $this->_screen_settings || $this->_options )
+ $show_screen = true;
+
+ $this->_show_screen_options = apply_filters( 'screen_options_show_screen', $show_screen, $this );
+ return $this->_show_screen_options;
+ }
+
+ /**
+ * Render the screen options tab.
+ *
+ * @since 3.3.0
+ */
+ public function render_screen_options() {
+ global $wp_meta_boxes, $wp_list_table;
+
+ $columns = get_column_headers( $this );
+ $hidden = get_hidden_columns( $this );
+ $post = get_post();
+
+ ?>
+ <div id="screen-options-wrap" class="hidden" tabindex="-1" aria-label="<?php esc_attr_e('Screen Options Tab'); ?>">
+ <form id="adv-settings" action="" method="post">
+ <?php if ( isset( $wp_meta_boxes[ $this->id ] ) || $this->get_option( 'per_page' ) || ( $columns && empty( $columns['_title'] ) ) ) : ?>
+ <h5><?php _e( 'Show on screen' ); ?></h5>
+ <?php
+ endif;
+
+ if ( isset( $wp_meta_boxes[ $this->id ] ) ) : ?>
+ <div class="metabox-prefs">
+ <?php
+ meta_box_prefs( $this );
+
+ if ( 'dashboard' === $this->id && has_action( 'welcome_panel' ) && current_user_can( 'edit_theme_options' ) ) {
+ if ( isset( $_GET['welcome'] ) ) {
+ $welcome_checked = empty( $_GET['welcome'] ) ? 0 : 1;
+ update_user_meta( get_current_user_id(), 'show_welcome_panel', $welcome_checked );
+ } else {
+ $welcome_checked = get_user_meta( get_current_user_id(), 'show_welcome_panel', true );
+ if ( 2 == $welcome_checked && wp_get_current_user()->user_email != get_option( 'admin_email' ) )
+ $welcome_checked = false;
+ }
+ echo '<label for="wp_welcome_panel-hide">';
+ echo '<input type="checkbox" id="wp_welcome_panel-hide"' . checked( (bool) $welcome_checked, true, false ) . ' />';
+ echo _x( 'Welcome', 'Welcome panel' ) . "</label>\n";
+ }
+ ?>
+ <br class="clear" />
+ </div>
+ <?php endif;
+ if ( $columns ) :
+ if ( ! empty( $columns['_title'] ) ) : ?>
+ <h5><?php echo $columns['_title']; ?></h5>
+ <?php endif; ?>
+ <div class="metabox-prefs">
+ <?php
+ $special = array('_title', 'cb', 'comment', 'media', 'name', 'title', 'username', 'blogname');
+
+ foreach ( $columns as $column => $title ) {
+ // Can't hide these for they are special
+ if ( in_array( $column, $special ) )
+ continue;
+ if ( empty( $title ) )
+ continue;
+
+ if ( 'comments' == $column )
+ $title = __( 'Comments' );
+ $id = "$column-hide";
+ echo '<label for="' . $id . '">';
+ echo '<input class="hide-column-tog" name="' . $id . '" type="checkbox" id="' . $id . '" value="' . $column . '"' . checked( !in_array($column, $hidden), true, false ) . ' />';
+ echo "$title</label>\n";
+ }
+ ?>
+ <br class="clear" />
+ </div>
+ <?php endif;
+
+ $this->render_screen_layout();
+ $this->render_per_page_options();
+ echo $this->_screen_settings;
+
+ ?>
+ <div><?php wp_nonce_field( 'screen-options-nonce', 'screenoptionnonce', false ); ?></div>
+ </form>
+ </div>
+ <?php
+ }
+
+ /**
+ * Render the option for number of columns on the page
+ *
+ * @since 3.3.0
+ */
+ function render_screen_layout() {
+ if ( ! $this->get_option('layout_columns') )
+ return;
+
+ $screen_layout_columns = $this->get_columns();
+ $num = $this->get_option( 'layout_columns', 'max' );
+
+ ?>
+ <h5 class="screen-layout"><?php _e('Screen Layout'); ?></h5>
+ <div class='columns-prefs'><?php
+ _e('Number of Columns:');
+ for ( $i = 1; $i <= $num; ++$i ):
+ ?>
+ <label class="columns-prefs-<?php echo $i; ?>">
+ <input type='radio' name='screen_columns' value='<?php echo esc_attr( $i ); ?>'
+ <?php checked( $screen_layout_columns, $i ); ?> />
+ <?php echo esc_html( $i ); ?>
+ </label>
+ <?php
+ endfor; ?>
+ </div>
+ <?php
+ }
+
+ /**
+ * Render the items per page option
+ *
+ * @since 3.3.0
+ */
+ function render_per_page_options() {
+ if ( ! $this->get_option( 'per_page' ) )
+ return;
+
+ $per_page_label = $this->get_option( 'per_page', 'label' );
+
+ $option = $this->get_option( 'per_page', 'option' );
+ if ( ! $option )
+ $option = str_replace( '-', '_', "{$this->id}_per_page" );
+
+ $per_page = (int) get_user_option( $option );
+ if ( empty( $per_page ) || $per_page < 1 ) {
+ $per_page = $this->get_option( 'per_page', 'default' );
+ if ( ! $per_page )
+ $per_page = 20;
+ }
+
+ if ( 'edit_comments_per_page' == $option ) {
+ $comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all';
+ $per_page = apply_filters( 'comments_per_page', $per_page, $comment_status );
+ } elseif ( 'categories_per_page' == $option ) {
+ $per_page = apply_filters( 'edit_categories_per_page', $per_page );
+ } else {
+ $per_page = apply_filters( $option, $per_page );
+ }
+
+ // Back compat
+ if ( isset( $this->post_type ) )
+ $per_page = apply_filters( 'edit_posts_per_page', $per_page, $this->post_type );
+
+ ?>
+ <div class="screen-options">
+ <?php if ( $per_page_label ) : ?>
+ <input type="number" step="1" min="1" max="999" class="screen-per-page" name="wp_screen_options[value]"
+ id="<?php echo esc_attr( $option ); ?>" maxlength="3"
+ value="<?php echo esc_attr( $per_page ); ?>" />
+ <label for="<?php echo esc_attr( $option ); ?>">
+ <?php echo esc_html( $per_page_label ); ?>
+ </label>
+ <?php endif;
+
+ echo get_submit_button( __( 'Apply' ), 'button', 'screen-options-apply', false ); ?>
+ <input type='hidden' name='wp_screen_options[option]' value='<?php echo esc_attr($option); ?>' />
+ </div>
+ <?php
+ }
+}
diff --git a/src/wp-admin/includes/taxonomy.php b/src/wp-admin/includes/taxonomy.php
new file mode 100644
index 0000000000..fdc6d64d55
--- /dev/null
+++ b/src/wp-admin/includes/taxonomy.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * WordPress Taxonomy Administration API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+//
+// Category
+//
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @param unknown_type $cat_name
+ * @return unknown
+ */
+function category_exists($cat_name, $parent = 0) {
+ $id = term_exists($cat_name, 'category', $parent);
+ if ( is_array($id) )
+ $id = $id['term_id'];
+ return $id;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @param unknown_type $id
+ * @return unknown
+ */
+function get_category_to_edit( $id ) {
+ $category = get_category( $id, OBJECT, 'edit' );
+ return $category;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @param unknown_type $cat_name
+ * @param unknown_type $parent
+ * @return unknown
+ */
+function wp_create_category( $cat_name, $parent = 0 ) {
+ if ( $id = category_exists($cat_name, $parent) )
+ return $id;
+
+ return wp_insert_category( array('cat_name' => $cat_name, 'category_parent' => $parent) );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @param unknown_type $categories
+ * @param unknown_type $post_id
+ * @return unknown
+ */
+function wp_create_categories($categories, $post_id = '') {
+ $cat_ids = array ();
+ foreach ($categories as $category) {
+ if ($id = category_exists($category))
+ $cat_ids[] = $id;
+ else
+ if ($id = wp_create_category($category))
+ $cat_ids[] = $id;
+ }
+
+ if ( $post_id )
+ wp_set_post_categories($post_id, $cat_ids);
+
+ return $cat_ids;
+}
+
+/**
+ * Updates an existing Category or creates a new Category.
+ *
+ * @since 2.0.0
+ *
+ * @param mixed $catarr See defaults below. Set 'cat_ID' to a non-zero value to update an existing category. The 'taxonomy' key was added in 3.0.0.
+ * @param bool $wp_error Optional, since 2.5.0. Set this to true if the caller handles WP_Error return values.
+ * @return int|object The ID number of the new or updated Category on success. Zero or a WP_Error on failure, depending on param $wp_error.
+ */
+function wp_insert_category($catarr, $wp_error = false) {
+ $cat_defaults = array('cat_ID' => 0, 'taxonomy' => 'category', 'cat_name' => '', 'category_description' => '', 'category_nicename' => '', 'category_parent' => '');
+ $catarr = wp_parse_args($catarr, $cat_defaults);
+ extract($catarr, EXTR_SKIP);
+
+ if ( trim( $cat_name ) == '' ) {
+ if ( ! $wp_error )
+ return 0;
+ else
+ return new WP_Error( 'cat_name', __('You did not enter a category name.') );
+ }
+
+ $cat_ID = (int) $cat_ID;
+
+ // Are we updating or creating?
+ if ( !empty ($cat_ID) )
+ $update = true;
+ else
+ $update = false;
+
+ $name = $cat_name;
+ $description = $category_description;
+ $slug = $category_nicename;
+ $parent = $category_parent;
+
+ $parent = (int) $parent;
+ if ( $parent < 0 )
+ $parent = 0;
+
+ if ( empty( $parent ) || ! term_exists( $parent, $taxonomy ) || ( $cat_ID && term_is_ancestor_of( $cat_ID, $parent, $taxonomy ) ) )
+ $parent = 0;
+
+ $args = compact('name', 'slug', 'parent', 'description');
+
+ if ( $update )
+ $cat_ID = wp_update_term($cat_ID, $taxonomy, $args);
+ else
+ $cat_ID = wp_insert_term($cat_name, $taxonomy, $args);
+
+ if ( is_wp_error($cat_ID) ) {
+ if ( $wp_error )
+ return $cat_ID;
+ else
+ return 0;
+ }
+
+ return $cat_ID['term_id'];
+}
+
+/**
+ * Aliases wp_insert_category() with minimal args.
+ *
+ * If you want to update only some fields of an existing category, call this
+ * function with only the new values set inside $catarr.
+ *
+ * @since 2.0.0
+ *
+ * @param array $catarr The 'cat_ID' value is required. All other keys are optional.
+ * @return int|bool The ID number of the new or updated Category on success. Zero or FALSE on failure.
+ */
+function wp_update_category($catarr) {
+ $cat_ID = (int) $catarr['cat_ID'];
+
+ if ( isset($catarr['category_parent']) && ($cat_ID == $catarr['category_parent']) )
+ return false;
+
+ // First, get all of the original fields
+ $category = get_category($cat_ID, ARRAY_A);
+
+ // Escape data pulled from DB.
+ $category = wp_slash($category);
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $catarr = array_merge($category, $catarr);
+
+ return wp_insert_category($catarr);
+}
+
+//
+// Tags
+//
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.3.0
+ *
+ * @param unknown_type $tag_name
+ * @return unknown
+ */
+function tag_exists($tag_name) {
+ return term_exists($tag_name, 'post_tag');
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.3.0
+ *
+ * @param unknown_type $tag_name
+ * @return unknown
+ */
+function wp_create_tag($tag_name) {
+ return wp_create_term( $tag_name, 'post_tag');
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.3.0
+ *
+ * @param unknown_type $post_id
+ * @return unknown
+ */
+function get_tags_to_edit( $post_id, $taxonomy = 'post_tag' ) {
+ return get_terms_to_edit( $post_id, $taxonomy);
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.8.0
+ *
+ * @param unknown_type $post_id
+ * @return unknown
+ */
+function get_terms_to_edit( $post_id, $taxonomy = 'post_tag' ) {
+ $post_id = (int) $post_id;
+ if ( !$post_id )
+ return false;
+
+ $tags = wp_get_post_terms($post_id, $taxonomy, array());
+
+ if ( !$tags )
+ return false;
+
+ if ( is_wp_error($tags) )
+ return $tags;
+
+ foreach ( $tags as $tag )
+ $tag_names[] = $tag->name;
+ $tags_to_edit = join( ',', $tag_names );
+ $tags_to_edit = esc_attr( $tags_to_edit );
+ $tags_to_edit = apply_filters( 'terms_to_edit', $tags_to_edit, $taxonomy );
+
+ return $tags_to_edit;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.8.0
+ *
+ * @param unknown_type $tag_name
+ * @return unknown
+ */
+function wp_create_term($tag_name, $taxonomy = 'post_tag') {
+ if ( $id = term_exists($tag_name, $taxonomy) )
+ return $id;
+
+ return wp_insert_term($tag_name, $taxonomy);
+}
diff --git a/src/wp-admin/includes/template.php b/src/wp-admin/includes/template.php
new file mode 100644
index 0000000000..f8fac13914
--- /dev/null
+++ b/src/wp-admin/includes/template.php
@@ -0,0 +1,1980 @@
+<?php
+/**
+ * Template WordPress Administration API.
+ *
+ * A Big Mess. Also some neat functions that are nicely written.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+//
+// Category Checklists
+//
+
+/**
+ * Walker to output an unordered list of category checkbox <input> elements.
+ *
+ * @see Walker
+ * @see wp_category_checklist()
+ * @see wp_terms_checklist()
+ * @since 2.5.1
+ */
+class Walker_Category_Checklist extends Walker {
+ var $tree_type = 'category';
+ var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
+
+ function start_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent<ul class='children'>\n";
+ }
+
+ function end_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent</ul>\n";
+ }
+
+ function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
+ extract($args);
+ if ( empty($taxonomy) )
+ $taxonomy = 'category';
+
+ if ( $taxonomy == 'category' )
+ $name = 'post_category';
+ else
+ $name = 'tax_input['.$taxonomy.']';
+
+ $class = in_array( $category->term_id, $popular_cats ) ? ' class="popular-category"' : '';
+ $output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" . '<label class="selectit"><input value="' . $category->term_id . '" type="checkbox" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $category->term_id . '"' . checked( in_array( $category->term_id, $selected_cats ), true, false ) . disabled( empty( $args['disabled'] ), false, false ) . ' /> ' . esc_html( apply_filters('the_category', $category->name )) . '</label>';
+ }
+
+ function end_el( &$output, $category, $depth = 0, $args = array() ) {
+ $output .= "</li>\n";
+ }
+}
+
+/**
+ * Output an unordered list of checkbox <input> elements labelled
+ * with category names.
+ *
+ * @see wp_terms_checklist()
+ * @since 2.5.1
+ *
+ * @param int $post_id Mark categories associated with this post as checked. $selected_cats must not be an array.
+ * @param int $descendants_and_self ID of the category to output along with its descendents.
+ * @param bool|array $selected_cats List of categories to mark as checked.
+ * @param bool|array $popular_cats Override the list of categories that receive the "popular-category" class.
+ * @param object $walker Walker object to use to build the output.
+ * @param bool $checked_ontop Move checked items out of the hierarchy and to the top of the list.
+ */
+function wp_category_checklist( $post_id = 0, $descendants_and_self = 0, $selected_cats = false, $popular_cats = false, $walker = null, $checked_ontop = true ) {
+ wp_terms_checklist( $post_id, array(
+ 'taxonomy' => 'category',
+ 'descendants_and_self' => $descendants_and_self,
+ 'selected_cats' => $selected_cats,
+ 'popular_cats' => $popular_cats,
+ 'walker' => $walker,
+ 'checked_ontop' => $checked_ontop
+ ) );
+}
+
+/**
+ * Output an unordered list of checkbox <input> elements labelled
+ * with term names. Taxonomy independent version of wp_category_checklist().
+ *
+ * @since 3.0.0
+ *
+ * @param int $post_id
+ * @param array $args
+ */
+function wp_terms_checklist($post_id = 0, $args = array()) {
+ $defaults = array(
+ 'descendants_and_self' => 0,
+ 'selected_cats' => false,
+ 'popular_cats' => false,
+ 'walker' => null,
+ 'taxonomy' => 'category',
+ 'checked_ontop' => true
+ );
+ $args = apply_filters( 'wp_terms_checklist_args', $args, $post_id );
+
+ extract( wp_parse_args($args, $defaults), EXTR_SKIP );
+
+ if ( empty($walker) || !is_a($walker, 'Walker') )
+ $walker = new Walker_Category_Checklist;
+
+ $descendants_and_self = (int) $descendants_and_self;
+
+ $args = array('taxonomy' => $taxonomy);
+
+ $tax = get_taxonomy($taxonomy);
+ $args['disabled'] = !current_user_can($tax->cap->assign_terms);
+
+ if ( is_array( $selected_cats ) )
+ $args['selected_cats'] = $selected_cats;
+ elseif ( $post_id )
+ $args['selected_cats'] = wp_get_object_terms($post_id, $taxonomy, array_merge($args, array('fields' => 'ids')));
+ else
+ $args['selected_cats'] = array();
+
+ if ( is_array( $popular_cats ) )
+ $args['popular_cats'] = $popular_cats;
+ else
+ $args['popular_cats'] = get_terms( $taxonomy, array( 'fields' => 'ids', 'orderby' => 'count', 'order' => 'DESC', 'number' => 10, 'hierarchical' => false ) );
+
+ if ( $descendants_and_self ) {
+ $categories = (array) get_terms($taxonomy, array( 'child_of' => $descendants_and_self, 'hierarchical' => 0, 'hide_empty' => 0 ) );
+ $self = get_term( $descendants_and_self, $taxonomy );
+ array_unshift( $categories, $self );
+ } else {
+ $categories = (array) get_terms($taxonomy, array('get' => 'all'));
+ }
+
+ if ( $checked_ontop ) {
+ // Post process $categories rather than adding an exclude to the get_terms() query to keep the query the same across all posts (for any query cache)
+ $checked_categories = array();
+ $keys = array_keys( $categories );
+
+ foreach( $keys as $k ) {
+ if ( in_array( $categories[$k]->term_id, $args['selected_cats'] ) ) {
+ $checked_categories[] = $categories[$k];
+ unset( $categories[$k] );
+ }
+ }
+
+ // Put checked cats on top
+ echo call_user_func_array(array(&$walker, 'walk'), array($checked_categories, 0, $args));
+ }
+ // Then the rest of them
+ echo call_user_func_array(array(&$walker, 'walk'), array($categories, 0, $args));
+}
+
+/**
+ * Retrieve a list of the most popular terms from the specified taxonomy.
+ *
+ * If the $echo argument is true then the elements for a list of checkbox
+ * <input> elements labelled with the names of the selected terms is output.
+ * If the $post_ID global isn't empty then the terms associated with that
+ * post will be marked as checked.
+ *
+ * @since 2.5.0
+ *
+ * @param string $taxonomy Taxonomy to retrieve terms from.
+ * @param int $default Unused.
+ * @param int $number Number of terms to retrieve. Defaults to 10.
+ * @param bool $echo Optionally output the list as well. Defaults to true.
+ * @return array List of popular term IDs.
+ */
+function wp_popular_terms_checklist( $taxonomy, $default = 0, $number = 10, $echo = true ) {
+ $post = get_post();
+
+ if ( $post && $post->ID )
+ $checked_terms = wp_get_object_terms($post->ID, $taxonomy, array('fields'=>'ids'));
+ else
+ $checked_terms = array();
+
+ $terms = get_terms( $taxonomy, array( 'orderby' => 'count', 'order' => 'DESC', 'number' => $number, 'hierarchical' => false ) );
+
+ $tax = get_taxonomy($taxonomy);
+
+ $popular_ids = array();
+ foreach ( (array) $terms as $term ) {
+ $popular_ids[] = $term->term_id;
+ if ( !$echo ) // hack for AJAX use
+ continue;
+ $id = "popular-$taxonomy-$term->term_id";
+ $checked = in_array( $term->term_id, $checked_terms ) ? 'checked="checked"' : '';
+ ?>
+
+ <li id="<?php echo $id; ?>" class="popular-category">
+ <label class="selectit">
+ <input id="in-<?php echo $id; ?>" type="checkbox" <?php echo $checked; ?> value="<?php echo (int) $term->term_id; ?>" <?php disabled( ! current_user_can( $tax->cap->assign_terms ) ); ?> />
+ <?php echo esc_html( apply_filters( 'the_category', $term->name ) ); ?>
+ </label>
+ </li>
+
+ <?php
+ }
+ return $popular_ids;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.1
+ *
+ * @param unknown_type $link_id
+ */
+function wp_link_category_checklist( $link_id = 0 ) {
+ $default = 1;
+
+ if ( $link_id ) {
+ $checked_categories = wp_get_link_cats( $link_id );
+ // No selected categories, strange
+ if ( ! count( $checked_categories ) )
+ $checked_categories[] = $default;
+ } else {
+ $checked_categories[] = $default;
+ }
+
+ $categories = get_terms( 'link_category', array( 'orderby' => 'name', 'hide_empty' => 0 ) );
+
+ if ( empty( $categories ) )
+ return;
+
+ foreach ( $categories as $category ) {
+ $cat_id = $category->term_id;
+ $name = esc_html( apply_filters( 'the_category', $category->name ) );
+ $checked = in_array( $cat_id, $checked_categories ) ? ' checked="checked"' : '';
+ echo '<li id="link-category-', $cat_id, '"><label for="in-link-category-', $cat_id, '" class="selectit"><input value="', $cat_id, '" type="checkbox" name="link_category[]" id="in-link-category-', $cat_id, '"', $checked, '/> ', $name, "</label></li>";
+ }
+}
+
+// adds hidden fields with the data for use in the inline editor for posts and pages
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $post
+ */
+function get_inline_data($post) {
+ $post_type_object = get_post_type_object($post->post_type);
+ if ( ! current_user_can( 'edit_post', $post->ID ) )
+ return;
+
+ $title = esc_textarea( trim( $post->post_title ) );
+
+ echo '
+<div class="hidden" id="inline_' . $post->ID . '">
+ <div class="post_title">' . $title . '</div>
+ <div class="post_name">' . apply_filters('editable_slug', $post->post_name) . '</div>
+ <div class="post_author">' . $post->post_author . '</div>
+ <div class="comment_status">' . esc_html( $post->comment_status ) . '</div>
+ <div class="ping_status">' . esc_html( $post->ping_status ) . '</div>
+ <div class="_status">' . esc_html( $post->post_status ) . '</div>
+ <div class="jj">' . mysql2date( 'd', $post->post_date, false ) . '</div>
+ <div class="mm">' . mysql2date( 'm', $post->post_date, false ) . '</div>
+ <div class="aa">' . mysql2date( 'Y', $post->post_date, false ) . '</div>
+ <div class="hh">' . mysql2date( 'H', $post->post_date, false ) . '</div>
+ <div class="mn">' . mysql2date( 'i', $post->post_date, false ) . '</div>
+ <div class="ss">' . mysql2date( 's', $post->post_date, false ) . '</div>
+ <div class="post_password">' . esc_html( $post->post_password ) . '</div>';
+
+ if ( $post_type_object->hierarchical )
+ echo '<div class="post_parent">' . $post->post_parent . '</div>';
+
+ if ( $post->post_type == 'page' )
+ echo '<div class="page_template">' . esc_html( get_post_meta( $post->ID, '_wp_page_template', true ) ) . '</div>';
+
+ if ( post_type_supports( $post->post_type, 'page-attributes' ) )
+ echo '<div class="menu_order">' . $post->menu_order . '</div>';
+
+ $taxonomy_names = get_object_taxonomies( $post->post_type );
+ foreach ( $taxonomy_names as $taxonomy_name) {
+ $taxonomy = get_taxonomy( $taxonomy_name );
+
+ if ( $taxonomy->hierarchical && $taxonomy->show_ui ) {
+ echo '<div class="post_category" id="' . $taxonomy_name . '_' . $post->ID . '">'
+ . implode( ',', wp_get_object_terms( $post->ID, $taxonomy_name, array( 'fields' => 'ids' ) ) ) . '</div>';
+ } elseif ( $taxonomy->show_ui ) {
+ echo '<div class="tags_input" id="'.$taxonomy_name.'_'.$post->ID.'">'
+ . esc_html( str_replace( ',', ', ', get_terms_to_edit( $post->ID, $taxonomy_name ) ) ) . '</div>';
+ }
+ }
+
+ if ( !$post_type_object->hierarchical )
+ echo '<div class="sticky">' . (is_sticky($post->ID) ? 'sticky' : '') . '</div>';
+
+ if ( post_type_supports( $post->post_type, 'post-formats' ) )
+ echo '<div class="post_format">' . esc_html( get_post_format( $post->ID ) ) . '</div>';
+
+ echo '</div>';
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $position
+ * @param unknown_type $checkbox
+ * @param unknown_type $mode
+ */
+function wp_comment_reply($position = '1', $checkbox = false, $mode = 'single', $table_row = true) {
+ // allow plugin to replace the popup content
+ $content = apply_filters( 'wp_comment_reply', '', array('position' => $position, 'checkbox' => $checkbox, 'mode' => $mode) );
+
+ if ( ! empty($content) ) {
+ echo $content;
+ return;
+ }
+
+ if ( $mode == 'single' ) {
+ $wp_list_table = _get_list_table('WP_Post_Comments_List_Table');
+ } else {
+ $wp_list_table = _get_list_table('WP_Comments_List_Table');
+ }
+
+?>
+<form method="get" action="">
+<?php if ( $table_row ) : ?>
+<table style="display:none;"><tbody id="com-reply"><tr id="replyrow" style="display:none;"><td colspan="<?php echo $wp_list_table->get_column_count(); ?>" class="colspanchange">
+<?php else : ?>
+<div id="com-reply" style="display:none;"><div id="replyrow" style="display:none;">
+<?php endif; ?>
+ <div id="replyhead" style="display:none;"><h5><?php _e( 'Reply to Comment' ); ?></h5></div>
+ <div id="addhead" style="display:none;"><h5><?php _e('Add new Comment'); ?></h5></div>
+ <div id="edithead" style="display:none;">
+ <div class="inside">
+ <label for="author"><?php _e('Name') ?></label>
+ <input type="text" name="newcomment_author" size="50" value="" id="author" />
+ </div>
+
+ <div class="inside">
+ <label for="author-email"><?php _e('E-mail') ?></label>
+ <input type="text" name="newcomment_author_email" size="50" value="" id="author-email" />
+ </div>
+
+ <div class="inside">
+ <label for="author-url"><?php _e('URL') ?></label>
+ <input type="text" id="author-url" name="newcomment_author_url" size="103" value="" />
+ </div>
+ <div style="clear:both;"></div>
+ </div>
+
+ <div id="replycontainer">
+ <?php
+ $quicktags_settings = array( 'buttons' => 'strong,em,link,block,del,ins,img,ul,ol,li,code,close' );
+ wp_editor( '', 'replycontent', array( 'media_buttons' => false, 'tinymce' => false, 'quicktags' => $quicktags_settings ) );
+ ?>
+ </div>
+
+ <p id="replysubmit" class="submit">
+ <a href="#comments-form" class="save button-primary alignright">
+ <span id="addbtn" style="display:none;"><?php _e('Add Comment'); ?></span>
+ <span id="savebtn" style="display:none;"><?php _e('Update Comment'); ?></span>
+ <span id="replybtn" style="display:none;"><?php _e('Submit Reply'); ?></span></a>
+ <a href="#comments-form" class="cancel button-secondary alignleft"><?php _e('Cancel'); ?></a>
+ <span class="waiting spinner"></span>
+ <span class="error" style="display:none;"></span>
+ <br class="clear" />
+ </p>
+
+ <input type="hidden" name="user_ID" id="user_ID" value="<?php echo get_current_user_id(); ?>" />
+ <input type="hidden" name="action" id="action" value="" />
+ <input type="hidden" name="comment_ID" id="comment_ID" value="" />
+ <input type="hidden" name="comment_post_ID" id="comment_post_ID" value="" />
+ <input type="hidden" name="status" id="status" value="" />
+ <input type="hidden" name="position" id="position" value="<?php echo $position; ?>" />
+ <input type="hidden" name="checkbox" id="checkbox" value="<?php echo $checkbox ? 1 : 0; ?>" />
+ <input type="hidden" name="mode" id="mode" value="<?php echo esc_attr($mode); ?>" />
+ <?php
+ wp_nonce_field( 'replyto-comment', '_ajax_nonce-replyto-comment', false );
+ if ( current_user_can( 'unfiltered_html' ) )
+ wp_nonce_field( 'unfiltered-html-comment', '_wp_unfiltered_html_comment', false );
+ ?>
+<?php if ( $table_row ) : ?>
+</td></tr></tbody></table>
+<?php else : ?>
+</div></div>
+<?php endif; ?>
+</form>
+<?php
+}
+
+/**
+ * Output 'undo move to trash' text for comments
+ *
+ * @since 2.9.0
+ */
+function wp_comment_trashnotice() {
+?>
+<div class="hidden" id="trash-undo-holder">
+ <div class="trash-undo-inside"><?php printf(__('Comment by %s moved to the trash.'), '<strong></strong>'); ?> <span class="undo untrash"><a href="#"><?php _e('Undo'); ?></a></span></div>
+</div>
+<div class="hidden" id="spam-undo-holder">
+ <div class="spam-undo-inside"><?php printf(__('Comment by %s marked as spam.'), '<strong></strong>'); ?> <span class="undo unspam"><a href="#"><?php _e('Undo'); ?></a></span></div>
+</div>
+<?php
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.2.0
+ *
+ * @param unknown_type $meta
+ */
+function list_meta( $meta ) {
+ // Exit if no meta
+ if ( ! $meta ) {
+ echo '
+<table id="list-table" style="display: none;">
+ <thead>
+ <tr>
+ <th class="left">' . _x( 'Name', 'meta name' ) . '</th>
+ <th>' . __( 'Value' ) . '</th>
+ </tr>
+ </thead>
+ <tbody id="the-list" data-wp-lists="list:meta">
+ <tr><td></td></tr>
+ </tbody>
+</table>'; //TBODY needed for list-manipulation JS
+ return;
+ }
+ $count = 0;
+?>
+<table id="list-table">
+ <thead>
+ <tr>
+ <th class="left"><?php _ex( 'Name', 'meta name' ) ?></th>
+ <th><?php _e( 'Value' ) ?></th>
+ </tr>
+ </thead>
+ <tbody id='the-list' data-wp-lists='list:meta'>
+<?php
+ foreach ( $meta as $entry )
+ echo _list_meta_row( $entry, $count );
+?>
+ </tbody>
+</table>
+<?php
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param unknown_type $entry
+ * @param unknown_type $count
+ * @return unknown
+ */
+function _list_meta_row( $entry, &$count ) {
+ static $update_nonce = false;
+
+ if ( is_protected_meta( $entry['meta_key'], 'post' ) )
+ return;
+
+ if ( !$update_nonce )
+ $update_nonce = wp_create_nonce( 'add-meta' );
+
+ $r = '';
+ ++ $count;
+ if ( $count % 2 )
+ $style = 'alternate';
+ else
+ $style = '';
+
+ if ( is_serialized( $entry['meta_value'] ) ) {
+ if ( is_serialized_string( $entry['meta_value'] ) ) {
+ // this is a serialized string, so we should display it
+ $entry['meta_value'] = maybe_unserialize( $entry['meta_value'] );
+ } else {
+ // this is a serialized array/object so we should NOT display it
+ --$count;
+ return;
+ }
+ }
+
+ $entry['meta_key'] = esc_attr($entry['meta_key']);
+ $entry['meta_value'] = esc_textarea( $entry['meta_value'] ); // using a <textarea />
+ $entry['meta_id'] = (int) $entry['meta_id'];
+
+ $delete_nonce = wp_create_nonce( 'delete-meta_' . $entry['meta_id'] );
+
+ $r .= "\n\t<tr id='meta-{$entry['meta_id']}' class='$style'>";
+ $r .= "\n\t\t<td class='left'><label class='screen-reader-text' for='meta[{$entry['meta_id']}][key]'>" . __( 'Key' ) . "</label><input name='meta[{$entry['meta_id']}][key]' id='meta[{$entry['meta_id']}][key]' type='text' size='20' value='{$entry['meta_key']}' />";
+
+ $r .= "\n\t\t<div class='submit'>";
+ $r .= get_submit_button( __( 'Delete' ), 'deletemeta small', "deletemeta[{$entry['meta_id']}]", false, array( 'data-wp-lists' => "delete:the-list:meta-{$entry['meta_id']}::_ajax_nonce=$delete_nonce" ) );
+ $r .= "\n\t\t";
+ $r .= get_submit_button( __( 'Update' ), 'updatemeta small', "meta-{$entry['meta_id']}-submit", false, array( 'data-wp-lists' => "add:the-list:meta-{$entry['meta_id']}::_ajax_nonce-add-meta=$update_nonce" ) );
+ $r .= "</div>";
+ $r .= wp_nonce_field( 'change-meta', '_ajax_nonce', false, false );
+ $r .= "</td>";
+
+ $r .= "\n\t\t<td><label class='screen-reader-text' for='meta[{$entry['meta_id']}][value]'>" . __( 'Value' ) . "</label><textarea name='meta[{$entry['meta_id']}][value]' id='meta[{$entry['meta_id']}][value]' rows='2' cols='30'>{$entry['meta_value']}</textarea></td>\n\t</tr>";
+ return $r;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.2.0
+ */
+function meta_form() {
+ global $wpdb;
+ $limit = (int) apply_filters( 'postmeta_form_limit', 30 );
+ $keys = $wpdb->get_col( "
+ SELECT meta_key
+ FROM $wpdb->postmeta
+ GROUP BY meta_key
+ HAVING meta_key NOT LIKE '\_%'
+ ORDER BY meta_key
+ LIMIT $limit" );
+ if ( $keys )
+ natcasesort($keys);
+?>
+<p><strong><?php _e( 'Add New Custom Field:' ) ?></strong></p>
+<table id="newmeta">
+<thead>
+<tr>
+<th class="left"><label for="metakeyselect"><?php _ex( 'Name', 'meta name' ) ?></label></th>
+<th><label for="metavalue"><?php _e( 'Value' ) ?></label></th>
+</tr>
+</thead>
+
+<tbody>
+<tr>
+<td id="newmetaleft" class="left">
+<?php if ( $keys ) { ?>
+<select id="metakeyselect" name="metakeyselect">
+<option value="#NONE#"><?php _e( '&mdash; Select &mdash;' ); ?></option>
+<?php
+
+ foreach ( $keys as $key ) {
+ if ( is_protected_meta( $key, 'post' ) )
+ continue;
+ echo "\n<option value='" . esc_attr($key) . "'>" . esc_html($key) . "</option>";
+ }
+?>
+</select>
+<input class="hide-if-js" type="text" id="metakeyinput" name="metakeyinput" value="" />
+<a href="#postcustomstuff" class="hide-if-no-js" onclick="jQuery('#metakeyinput, #metakeyselect, #enternew, #cancelnew').toggle();return false;">
+<span id="enternew"><?php _e('Enter new'); ?></span>
+<span id="cancelnew" class="hidden"><?php _e('Cancel'); ?></span></a>
+<?php } else { ?>
+<input type="text" id="metakeyinput" name="metakeyinput" value="" />
+<?php } ?>
+</td>
+<td><textarea id="metavalue" name="metavalue" rows="2" cols="25"></textarea></td>
+</tr>
+
+<tr><td colspan="2">
+<div class="submit">
+<?php submit_button( __( 'Add Custom Field' ), 'secondary', 'addmeta', false, array( 'id' => 'newmeta-submit', 'data-wp-lists' => 'add:the-list:newmeta' ) ); ?>
+</div>
+<?php wp_nonce_field( 'add-meta', '_ajax_nonce-add-meta', false ); ?>
+</td></tr>
+</tbody>
+</table>
+<?php
+
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 0.71
+ *
+ * @param unknown_type $edit
+ * @param unknown_type $for_post
+ * @param unknown_type $tab_index
+ * @param unknown_type $multi
+ */
+function touch_time( $edit = 1, $for_post = 1, $tab_index = 0, $multi = 0 ) {
+ global $wp_locale, $comment;
+ $post = get_post();
+
+ if ( $for_post )
+ $edit = ! ( in_array($post->post_status, array('draft', 'pending') ) && (!$post->post_date_gmt || '0000-00-00 00:00:00' == $post->post_date_gmt ) );
+
+ $tab_index_attribute = '';
+ if ( (int) $tab_index > 0 )
+ $tab_index_attribute = " tabindex=\"$tab_index\"";
+
+ // echo '<label for="timestamp" style="display: block;"><input type="checkbox" class="checkbox" name="edit_date" value="1" id="timestamp"'.$tab_index_attribute.' /> '.__( 'Edit timestamp' ).'</label><br />';
+
+ $time_adj = current_time('timestamp');
+ $post_date = ($for_post) ? $post->post_date : $comment->comment_date;
+ $jj = ($edit) ? mysql2date( 'd', $post_date, false ) : gmdate( 'd', $time_adj );
+ $mm = ($edit) ? mysql2date( 'm', $post_date, false ) : gmdate( 'm', $time_adj );
+ $aa = ($edit) ? mysql2date( 'Y', $post_date, false ) : gmdate( 'Y', $time_adj );
+ $hh = ($edit) ? mysql2date( 'H', $post_date, false ) : gmdate( 'H', $time_adj );
+ $mn = ($edit) ? mysql2date( 'i', $post_date, false ) : gmdate( 'i', $time_adj );
+ $ss = ($edit) ? mysql2date( 's', $post_date, false ) : gmdate( 's', $time_adj );
+
+ $cur_jj = gmdate( 'd', $time_adj );
+ $cur_mm = gmdate( 'm', $time_adj );
+ $cur_aa = gmdate( 'Y', $time_adj );
+ $cur_hh = gmdate( 'H', $time_adj );
+ $cur_mn = gmdate( 'i', $time_adj );
+
+ $month = "<select " . ( $multi ? '' : 'id="mm" ' ) . "name=\"mm\"$tab_index_attribute>\n";
+ for ( $i = 1; $i < 13; $i = $i +1 ) {
+ $monthnum = zeroise($i, 2);
+ $month .= "\t\t\t" . '<option value="' . $monthnum . '"';
+ if ( $i == $mm )
+ $month .= ' selected="selected"';
+ /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */
+ $month .= '>' . sprintf( __( '%1$s-%2$s' ), $monthnum, $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) ) . "</option>\n";
+ }
+ $month .= '</select>';
+
+ $day = '<input type="text" ' . ( $multi ? '' : 'id="jj" ' ) . 'name="jj" value="' . $jj . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
+ $year = '<input type="text" ' . ( $multi ? '' : 'id="aa" ' ) . 'name="aa" value="' . $aa . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" />';
+ $hour = '<input type="text" ' . ( $multi ? '' : 'id="hh" ' ) . 'name="hh" value="' . $hh . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
+ $minute = '<input type="text" ' . ( $multi ? '' : 'id="mn" ' ) . 'name="mn" value="' . $mn . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
+
+ echo '<div class="timestamp-wrap">';
+ /* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
+ printf( __( '%1$s %2$s, %3$s @ %4$s : %5$s' ), $month, $day, $year, $hour, $minute );
+
+ echo '</div><input type="hidden" id="ss" name="ss" value="' . $ss . '" />';
+
+ if ( $multi ) return;
+
+ echo "\n\n";
+ foreach ( array('mm', 'jj', 'aa', 'hh', 'mn') as $timeunit ) {
+ echo '<input type="hidden" id="hidden_' . $timeunit . '" name="hidden_' . $timeunit . '" value="' . $$timeunit . '" />' . "\n";
+ $cur_timeunit = 'cur_' . $timeunit;
+ echo '<input type="hidden" id="'. $cur_timeunit . '" name="'. $cur_timeunit . '" value="' . $$cur_timeunit . '" />' . "\n";
+ }
+?>
+
+<p>
+<a href="#edit_timestamp" class="save-timestamp hide-if-no-js button"><?php _e('OK'); ?></a>
+<a href="#edit_timestamp" class="cancel-timestamp hide-if-no-js"><?php _e('Cancel'); ?></a>
+</p>
+<?php
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $default
+ */
+function page_template_dropdown( $default = '' ) {
+ $templates = get_page_templates();
+ ksort( $templates );
+ foreach (array_keys( $templates ) as $template )
+ : if ( $default == $templates[$template] )
+ $selected = " selected='selected'";
+ else
+ $selected = '';
+ echo "\n\t<option value='".$templates[$template]."' $selected>$template</option>";
+ endforeach;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $default
+ * @param unknown_type $parent
+ * @param unknown_type $level
+ * @return unknown
+ */
+function parent_dropdown( $default = 0, $parent = 0, $level = 0 ) {
+ global $wpdb;
+ $post = get_post();
+ $items = $wpdb->get_results( $wpdb->prepare("SELECT ID, post_parent, post_title FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' ORDER BY menu_order", $parent) );
+
+ if ( $items ) {
+ foreach ( $items as $item ) {
+ // A page cannot be its own parent.
+ if ( $post && $post->ID && $item->ID == $post->ID )
+ continue;
+
+ $pad = str_repeat( '&nbsp;', $level * 3 );
+ if ( $item->ID == $default)
+ $current = ' selected="selected"';
+ else
+ $current = '';
+
+ echo "\n\t<option class='level-$level' value='$item->ID'$current>$pad " . esc_html($item->post_title) . "</option>";
+ parent_dropdown( $default, $item->ID, $level +1 );
+ }
+ } else {
+ return false;
+ }
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.0.0
+ *
+ * @param unknown_type $id
+ * @return unknown
+ */
+function the_attachment_links( $id = false ) {
+ $id = (int) $id;
+ $post = get_post( $id );
+
+ if ( $post->post_type != 'attachment' )
+ return false;
+
+ $icon = wp_get_attachment_image( $post->ID, 'thumbnail', true );
+ $attachment_data = wp_get_attachment_metadata( $id );
+ $thumb = isset( $attachment_data['thumb'] );
+?>
+<form id="the-attachment-links">
+<table>
+ <col />
+ <col class="widefat" />
+ <tr>
+ <th scope="row"><?php _e( 'URL' ) ?></th>
+ <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><?php echo esc_textarea( wp_get_attachment_url() ); ?></textarea></td>
+ </tr>
+<?php if ( $icon ) : ?>
+ <tr>
+ <th scope="row"><?php $thumb ? _e( 'Thumbnail linked to file' ) : _e( 'Image linked to file' ); ?></th>
+ <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo wp_get_attachment_url(); ?>"><?php echo $icon ?></a></textarea></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php $thumb ? _e( 'Thumbnail linked to page' ) : _e( 'Image linked to page' ); ?></th>
+ <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo get_attachment_link( $post->ID ) ?>" rel="attachment wp-att-<?php echo $post->ID; ?>"><?php echo $icon ?></a></textarea></td>
+ </tr>
+<?php else : ?>
+ <tr>
+ <th scope="row"><?php _e( 'Link to file' ) ?></th>
+ <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo wp_get_attachment_url(); ?>" class="attachmentlink"><?php echo basename( wp_get_attachment_url() ); ?></a></textarea></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php _e( 'Link to page' ) ?></th>
+ <td><textarea rows="1" cols="40" type="text" class="attachmentlinks" readonly="readonly"><a href="<?php echo get_attachment_link( $post->ID ) ?>" rel="attachment wp-att-<?php echo $post->ID ?>"><?php the_title(); ?></a></textarea></td>
+ </tr>
+<?php endif; ?>
+</table>
+</form>
+<?php
+}
+
+/**
+ * Print out <option> html elements for role selectors
+ *
+ * @since 2.1.0
+ *
+ * @param string $selected slug for the role that should be already selected
+ */
+function wp_dropdown_roles( $selected = false ) {
+ $p = '';
+ $r = '';
+
+ $editable_roles = get_editable_roles();
+
+ foreach ( $editable_roles as $role => $details ) {
+ $name = translate_user_role($details['name'] );
+ if ( $selected == $role ) // preselect specified role
+ $p = "\n\t<option selected='selected' value='" . esc_attr($role) . "'>$name</option>";
+ else
+ $r .= "\n\t<option value='" . esc_attr($role) . "'>$name</option>";
+ }
+ echo $p . $r;
+}
+
+/**
+ * Outputs the form used by the importers to accept the data to be imported
+ *
+ * @since 2.0.0
+ *
+ * @param string $action The action attribute for the form.
+ */
+function wp_import_upload_form( $action ) {
+ $bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() );
+ $size = size_format( $bytes );
+ $upload_dir = wp_upload_dir();
+ if ( ! empty( $upload_dir['error'] ) ) :
+ ?><div class="error"><p><?php _e('Before you can upload your import file, you will need to fix the following error:'); ?></p>
+ <p><strong><?php echo $upload_dir['error']; ?></strong></p></div><?php
+ else :
+?>
+<form enctype="multipart/form-data" id="import-upload-form" method="post" class="wp-upload-form" action="<?php echo esc_url( wp_nonce_url( $action, 'import-upload' ) ); ?>">
+<p>
+<label for="upload"><?php _e( 'Choose a file from your computer:' ); ?></label> (<?php printf( __('Maximum size: %s' ), $size ); ?>)
+<input type="file" id="upload" name="import" size="25" />
+<input type="hidden" name="action" value="save" />
+<input type="hidden" name="max_file_size" value="<?php echo $bytes; ?>" />
+</p>
+<?php submit_button( __('Upload file and import'), 'button' ); ?>
+</form>
+<?php
+ endif;
+}
+
+/**
+ * Add a meta box to an edit form.
+ *
+ * @since 2.5.0
+ *
+ * @param string $id String for use in the 'id' attribute of tags.
+ * @param string $title Title of the meta box.
+ * @param string $callback Function that fills the box with the desired content. The function should echo its output.
+ * @param string|object $screen Optional. The screen on which to show the box (post, page, link). Defaults to current screen.
+ * @param string $context Optional. The context within the page where the boxes should show ('normal', 'advanced').
+ * @param string $priority Optional. The priority within the context where the boxes should show ('high', 'low').
+ * @param array $callback_args Optional. Data that should be set as the "args" property of the box array (which is the second parameter passed to your callback).
+ */
+function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
+ global $wp_meta_boxes;
+
+ if ( empty( $screen ) )
+ $screen = get_current_screen();
+ elseif ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ $page = $screen->id;
+
+ if ( !isset($wp_meta_boxes) )
+ $wp_meta_boxes = array();
+ if ( !isset($wp_meta_boxes[$page]) )
+ $wp_meta_boxes[$page] = array();
+ if ( !isset($wp_meta_boxes[$page][$context]) )
+ $wp_meta_boxes[$page][$context] = array();
+
+ foreach ( array_keys($wp_meta_boxes[$page]) as $a_context ) {
+ foreach ( array('high', 'core', 'default', 'low') as $a_priority ) {
+ if ( !isset($wp_meta_boxes[$page][$a_context][$a_priority][$id]) )
+ continue;
+
+ // If a core box was previously added or removed by a plugin, don't add.
+ if ( 'core' == $priority ) {
+ // If core box previously deleted, don't add
+ if ( false === $wp_meta_boxes[$page][$a_context][$a_priority][$id] )
+ return;
+ // If box was added with default priority, give it core priority to maintain sort order
+ if ( 'default' == $a_priority ) {
+ $wp_meta_boxes[$page][$a_context]['core'][$id] = $wp_meta_boxes[$page][$a_context]['default'][$id];
+ unset($wp_meta_boxes[$page][$a_context]['default'][$id]);
+ }
+ return;
+ }
+ // If no priority given and id already present, use existing priority
+ if ( empty($priority) ) {
+ $priority = $a_priority;
+ // else if we're adding to the sorted priority, we don't know the title or callback. Grab them from the previously added context/priority.
+ } elseif ( 'sorted' == $priority ) {
+ $title = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['title'];
+ $callback = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['callback'];
+ $callback_args = $wp_meta_boxes[$page][$a_context][$a_priority][$id]['args'];
+ }
+ // An id can be in only one priority and one context
+ if ( $priority != $a_priority || $context != $a_context )
+ unset($wp_meta_boxes[$page][$a_context][$a_priority][$id]);
+ }
+ }
+
+ if ( empty($priority) )
+ $priority = 'low';
+
+ if ( !isset($wp_meta_boxes[$page][$context][$priority]) )
+ $wp_meta_boxes[$page][$context][$priority] = array();
+
+ $wp_meta_boxes[$page][$context][$priority][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $callback_args);
+}
+
+/**
+ * Meta-Box template function
+ *
+ * @since 2.5.0
+ *
+ * @param string|object $screen Screen identifier
+ * @param string $context box context
+ * @param mixed $object gets passed to the box callback function as first parameter
+ * @return int number of meta_boxes
+ */
+function do_meta_boxes( $screen, $context, $object ) {
+ global $wp_meta_boxes;
+ static $already_sorted = false;
+
+ if ( empty( $screen ) )
+ $screen = get_current_screen();
+ elseif ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ $page = $screen->id;
+
+ $hidden = get_hidden_meta_boxes( $screen );
+
+ printf('<div id="%s-sortables" class="meta-box-sortables">', htmlspecialchars($context));
+
+ $i = 0;
+ do {
+ // Grab the ones the user has manually sorted. Pull them out of their previous context/priority and into the one the user chose
+ if ( !$already_sorted && $sorted = get_user_option( "meta-box-order_$page" ) ) {
+ foreach ( $sorted as $box_context => $ids ) {
+ foreach ( explode(',', $ids ) as $id ) {
+ if ( $id && 'dashboard_browser_nag' !== $id )
+ add_meta_box( $id, null, null, $screen, $box_context, 'sorted' );
+ }
+ }
+ }
+ $already_sorted = true;
+
+ if ( !isset($wp_meta_boxes) || !isset($wp_meta_boxes[$page]) || !isset($wp_meta_boxes[$page][$context]) )
+ break;
+
+ foreach ( array('high', 'sorted', 'core', 'default', 'low') as $priority ) {
+ if ( isset($wp_meta_boxes[$page][$context][$priority]) ) {
+ foreach ( (array) $wp_meta_boxes[$page][$context][$priority] as $box ) {
+ if ( false == $box || ! $box['title'] )
+ continue;
+ $i++;
+ $hidden_class = in_array($box['id'], $hidden) ? ' hide-if-js' : '';
+ echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes($box['id'], $page) . $hidden_class . '" ' . '>' . "\n";
+ if ( 'dashboard_browser_nag' != $box['id'] )
+ echo '<div class="handlediv" title="' . esc_attr__('Click to toggle') . '"><br /></div>';
+ echo "<h3 class='hndle'><span>{$box['title']}</span></h3>\n";
+ echo '<div class="inside">' . "\n";
+ call_user_func($box['callback'], $object, $box);
+ echo "</div>\n";
+ echo "</div>\n";
+ }
+ }
+ }
+ } while(0);
+
+ echo "</div>";
+
+ return $i;
+
+}
+
+/**
+ * Remove a meta box from an edit form.
+ *
+ * @since 2.6.0
+ *
+ * @param string $id String for use in the 'id' attribute of tags.
+ * @param string|object $screen The screen on which to show the box (post, page, link).
+ * @param string $context The context within the page where the boxes should show ('normal', 'advanced').
+ */
+function remove_meta_box($id, $screen, $context) {
+ global $wp_meta_boxes;
+
+ if ( empty( $screen ) )
+ $screen = get_current_screen();
+ elseif ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ $page = $screen->id;
+
+ if ( !isset($wp_meta_boxes) )
+ $wp_meta_boxes = array();
+ if ( !isset($wp_meta_boxes[$page]) )
+ $wp_meta_boxes[$page] = array();
+ if ( !isset($wp_meta_boxes[$page][$context]) )
+ $wp_meta_boxes[$page][$context] = array();
+
+ foreach ( array('high', 'core', 'default', 'low') as $priority )
+ $wp_meta_boxes[$page][$context][$priority][$id] = false;
+}
+
+/**
+ * Meta Box Accordion Template Function
+ *
+ * Largely made up of abstracted code from {@link do_meta_boxes()}, this
+ * function serves to build meta boxes as list items for display as
+ * a collapsible accordion.
+ *
+ * @since 3.6.0
+ *
+ * @uses global $wp_meta_boxes Used to retrieve registered meta boxes.
+ *
+ * @param string|object $screen The screen identifier.
+ * @param string $context The meta box context.
+ * @param mixed $object gets passed to the section callback function as first parameter.
+ * @return int number of meta boxes as accordion sections.
+ */
+function do_accordion_sections( $screen, $context, $object ) {
+ global $wp_meta_boxes;
+
+ wp_enqueue_script( 'accordion' );
+
+ if ( empty( $screen ) )
+ $screen = get_current_screen();
+ elseif ( is_string( $screen ) )
+ $screen = convert_to_screen( $screen );
+
+ $page = $screen->id;
+
+ $hidden = get_hidden_meta_boxes( $screen );
+ ?>
+ <div id="side-sortables" class="accordion-container">
+ <ul class="outer-border">
+ <?php
+ $i = 0;
+ $first_open = false;
+ do {
+ if ( ! isset( $wp_meta_boxes ) || ! isset( $wp_meta_boxes[$page] ) || ! isset( $wp_meta_boxes[$page][$context] ) )
+ break;
+
+ foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
+ if ( isset( $wp_meta_boxes[$page][$context][$priority] ) ) {
+ foreach ( $wp_meta_boxes[$page][$context][$priority] as $box ) {
+ if ( false == $box || ! $box['title'] )
+ continue;
+ $i++;
+ $hidden_class = in_array( $box['id'], $hidden ) ? 'hide-if-js' : '';
+
+ $open_class = '';
+ if ( ! $first_open && empty( $hidden_class ) ) {
+ $first_open = true;
+ $open_class = 'open';
+ }
+ ?>
+ <li class="control-section accordion-section <?php echo $hidden_class; ?> <?php echo $open_class; ?> <?php echo esc_attr( $box['id'] ); ?>" id="<?php echo esc_attr( $box['id'] ); ?>">
+ <h3 class="accordion-section-title hndle" tabindex="0" title="<?php echo esc_attr( $box['title'] ); ?>"><?php echo esc_html( $box['title'] ); ?></h3>
+ <div class="accordion-section-content <?php postbox_classes( $box['id'], $page ); ?>">
+ <div class="inside">
+ <?php call_user_func( $box['callback'], $object, $box ); ?>
+ </div><!-- .inside -->
+ </div><!-- .accordion-section-content -->
+ </li><!-- .accordion-section -->
+ <?php
+ }
+ }
+ }
+ } while(0);
+ ?>
+ </ul><!-- .outer-border -->
+ </div><!-- .accordion-container -->
+ <?php
+ return $i;
+}
+
+/**
+ * Add a new section to a settings page.
+ *
+ * Part of the Settings API. Use this to define new settings sections for an admin page.
+ * Show settings sections in your admin page callback function with do_settings_sections().
+ * Add settings fields to your section with add_settings_field()
+ *
+ * The $callback argument should be the name of a function that echoes out any
+ * content you want to show at the top of the settings section before the actual
+ * fields. It can output nothing if you want.
+ *
+ * @since 2.7.0
+ *
+ * @global $wp_settings_sections Storage array of all settings sections added to admin pages
+ *
+ * @param string $id Slug-name to identify the section. Used in the 'id' attribute of tags.
+ * @param string $title Formatted title of the section. Shown as the heading for the section.
+ * @param string $callback Function that echos out any content at the top of the section (between heading and fields).
+ * @param string $page The slug-name of the settings page on which to show the section. Built-in pages include 'general', 'reading', 'writing', 'discussion', 'media', etc. Create your own using add_options_page();
+ */
+function add_settings_section($id, $title, $callback, $page) {
+ global $wp_settings_sections;
+
+ if ( 'misc' == $page ) {
+ _deprecated_argument( __FUNCTION__, '3.0', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'misc' ) );
+ $page = 'general';
+ }
+
+ if ( 'privacy' == $page ) {
+ _deprecated_argument( __FUNCTION__, '3.5', sprintf( __( 'The "%s" options group has been removed. Use another settings group.' ), 'privacy' ) );
+ $page = 'reading';
+ }
+
+ if ( !isset($wp_settings_sections) )
+ $wp_settings_sections = array();
+ if ( !isset($wp_settings_sections[$page]) )
+ $wp_settings_sections[$page] = array();
+ if ( !isset($wp_settings_sections[$page][$id]) )
+ $wp_settings_sections[$page][$id] = array();
+
+ $wp_settings_sections[$page][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback);
+}
+
+/**
+ * Add a new field to a section of a settings page
+ *
+ * Part of the Settings API. Use this to define a settings field that will show
+ * as part of a settings section inside a settings page. The fields are shown using
+ * do_settings_fields() in do_settings-sections()
+ *
+ * The $callback argument should be the name of a function that echoes out the
+ * html input tags for this setting field. Use get_option() to retrieve existing
+ * values to show.
+ *
+ * @since 2.7.0
+ *
+ * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
+ *
+ * @param string $id Slug-name to identify the field. Used in the 'id' attribute of tags.
+ * @param string $title Formatted title of the field. Shown as the label for the field during output.
+ * @param string $callback Function that fills the field with the desired form inputs. The function should echo its output.
+ * @param string $page The slug-name of the settings page on which to show the section (general, reading, writing, ...).
+ * @param string $section The slug-name of the section of the settings page in which to show the box (default, ...).
+ * @param array $args Additional arguments
+ */
+function add_settings_field($id, $title, $callback, $page, $section = 'default', $args = array()) {
+ global $wp_settings_fields;
+
+ if ( 'misc' == $page ) {
+ _deprecated_argument( __FUNCTION__, '3.0', __( 'The miscellaneous options group has been removed. Use another settings group.' ) );
+ $page = 'general';
+ }
+
+ if ( 'privacy' == $page ) {
+ _deprecated_argument( __FUNCTION__, '3.5', __( 'The privacy options group has been removed. Use another settings group.' ) );
+ $page = 'reading';
+ }
+
+ if ( !isset($wp_settings_fields) )
+ $wp_settings_fields = array();
+ if ( !isset($wp_settings_fields[$page]) )
+ $wp_settings_fields[$page] = array();
+ if ( !isset($wp_settings_fields[$page][$section]) )
+ $wp_settings_fields[$page][$section] = array();
+
+ $wp_settings_fields[$page][$section][$id] = array('id' => $id, 'title' => $title, 'callback' => $callback, 'args' => $args);
+}
+
+/**
+ * Prints out all settings sections added to a particular settings page
+ *
+ * Part of the Settings API. Use this in a settings page callback function
+ * to output all the sections and fields that were added to that $page with
+ * add_settings_section() and add_settings_field()
+ *
+ * @global $wp_settings_sections Storage array of all settings sections added to admin pages
+ * @global $wp_settings_fields Storage array of settings fields and info about their pages/sections
+ * @since 2.7.0
+ *
+ * @param string $page The slug name of the page whos settings sections you want to output
+ */
+function do_settings_sections( $page ) {
+ global $wp_settings_sections, $wp_settings_fields;
+
+ if ( ! isset( $wp_settings_sections ) || !isset( $wp_settings_sections[$page] ) )
+ return;
+
+ foreach ( (array) $wp_settings_sections[$page] as $section ) {
+ if ( $section['title'] )
+ echo "<h3>{$section['title']}</h3>\n";
+
+ if ( $section['callback'] )
+ call_user_func( $section['callback'], $section );
+
+ if ( ! isset( $wp_settings_fields ) || !isset( $wp_settings_fields[$page] ) || !isset( $wp_settings_fields[$page][$section['id']] ) )
+ continue;
+ echo '<table class="form-table">';
+ do_settings_fields( $page, $section['id'] );
+ echo '</table>';
+ }
+}
+
+/**
+ * Print out the settings fields for a particular settings section
+ *
+ * Part of the Settings API. Use this in a settings page to output
+ * a specific section. Should normally be called by do_settings_sections()
+ * rather than directly.
+ *
+ * @global $wp_settings_fields Storage array of settings fields and their pages/sections
+ *
+ * @since 2.7.0
+ *
+ * @param string $page Slug title of the admin page who's settings fields you want to show.
+ * @param section $section Slug title of the settings section who's fields you want to show.
+ */
+function do_settings_fields($page, $section) {
+ global $wp_settings_fields;
+
+ if ( !isset($wp_settings_fields) || !isset($wp_settings_fields[$page]) || !isset($wp_settings_fields[$page][$section]) )
+ return;
+
+ foreach ( (array) $wp_settings_fields[$page][$section] as $field ) {
+ echo '<tr valign="top">';
+ if ( !empty($field['args']['label_for']) )
+ echo '<th scope="row"><label for="' . esc_attr( $field['args']['label_for'] ) . '">' . $field['title'] . '</label></th>';
+ else
+ echo '<th scope="row">' . $field['title'] . '</th>';
+ echo '<td>';
+ call_user_func($field['callback'], $field['args']);
+ echo '</td>';
+ echo '</tr>';
+ }
+}
+
+/**
+ * Register a settings error to be displayed to the user
+ *
+ * Part of the Settings API. Use this to show messages to users about settings validation
+ * problems, missing settings or anything else.
+ *
+ * Settings errors should be added inside the $sanitize_callback function defined in
+ * register_setting() for a given setting to give feedback about the submission.
+ *
+ * By default messages will show immediately after the submission that generated the error.
+ * Additional calls to settings_errors() can be used to show errors even when the settings
+ * page is first accessed.
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_settings_errors Storage array of errors registered during this pageload
+ *
+ * @param string $setting Slug title of the setting to which this error applies
+ * @param string $code Slug-name to identify the error. Used as part of 'id' attribute in HTML output.
+ * @param string $message The formatted message text to display to the user (will be shown inside styled <div> and <p>)
+ * @param string $type The type of message it is, controls HTML class. Use 'error' or 'updated'.
+ */
+function add_settings_error( $setting, $code, $message, $type = 'error' ) {
+ global $wp_settings_errors;
+
+ if ( !isset($wp_settings_errors) )
+ $wp_settings_errors = array();
+
+ $new_error = array(
+ 'setting' => $setting,
+ 'code' => $code,
+ 'message' => $message,
+ 'type' => $type
+ );
+ $wp_settings_errors[] = $new_error;
+}
+
+/**
+ * Fetch settings errors registered by add_settings_error()
+ *
+ * Checks the $wp_settings_errors array for any errors declared during the current
+ * pageload and returns them.
+ *
+ * If changes were just submitted ($_GET['settings-updated']) and settings errors were saved
+ * to the 'settings_errors' transient then those errors will be returned instead. This
+ * is used to pass errors back across pageloads.
+ *
+ * Use the $sanitize argument to manually re-sanitize the option before returning errors.
+ * This is useful if you have errors or notices you want to show even when the user
+ * hasn't submitted data (i.e. when they first load an options page, or in admin_notices action hook)
+ *
+ * @since 3.0.0
+ *
+ * @global array $wp_settings_errors Storage array of errors registered during this pageload
+ *
+ * @param string $setting Optional slug title of a specific setting who's errors you want.
+ * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
+ * @return array Array of settings errors
+ */
+function get_settings_errors( $setting = '', $sanitize = false ) {
+ global $wp_settings_errors;
+
+ // If $sanitize is true, manually re-run the sanitizisation for this option
+ // This allows the $sanitize_callback from register_setting() to run, adding
+ // any settings errors you want to show by default.
+ if ( $sanitize )
+ sanitize_option( $setting, get_option( $setting ) );
+
+ // If settings were passed back from options.php then use them
+ if ( isset( $_GET['settings-updated'] ) && $_GET['settings-updated'] && get_transient( 'settings_errors' ) ) {
+ $wp_settings_errors = array_merge( (array) $wp_settings_errors, get_transient( 'settings_errors' ) );
+ delete_transient( 'settings_errors' );
+ }
+
+ // Check global in case errors have been added on this pageload
+ if ( ! count( $wp_settings_errors ) )
+ return array();
+
+ // Filter the results to those of a specific setting if one was set
+ if ( $setting ) {
+ $setting_errors = array();
+ foreach ( (array) $wp_settings_errors as $key => $details ) {
+ if ( $setting == $details['setting'] )
+ $setting_errors[] = $wp_settings_errors[$key];
+ }
+ return $setting_errors;
+ }
+
+ return $wp_settings_errors;
+}
+
+/**
+ * Display settings errors registered by add_settings_error()
+ *
+ * Part of the Settings API. Outputs a <div> for each error retrieved by get_settings_errors().
+ *
+ * This is called automatically after a settings page based on the Settings API is submitted.
+ * Errors should be added during the validation callback function for a setting defined in register_setting()
+ *
+ * The $sanitize option is passed into get_settings_errors() and will re-run the setting sanitization
+ * on its current value.
+ *
+ * The $hide_on_update option will cause errors to only show when the settings page is first loaded.
+ * if the user has already saved new values it will be hidden to avoid repeating messages already
+ * shown in the default error reporting after submission. This is useful to show general errors like missing
+ * settings when the user arrives at the settings page.
+ *
+ * @since 3.0.0
+ *
+ * @param string $setting Optional slug title of a specific setting who's errors you want.
+ * @param boolean $sanitize Whether to re-sanitize the setting value before returning errors.
+ * @param boolean $hide_on_update If set to true errors will not be shown if the settings page has already been submitted.
+ */
+function settings_errors( $setting = '', $sanitize = false, $hide_on_update = false ) {
+
+ if ( $hide_on_update && ! empty( $_GET['settings-updated'] ) )
+ return;
+
+ $settings_errors = get_settings_errors( $setting, $sanitize );
+
+ if ( empty( $settings_errors ) )
+ return;
+
+ $output = '';
+ foreach ( $settings_errors as $key => $details ) {
+ $css_id = 'setting-error-' . $details['code'];
+ $css_class = $details['type'] . ' settings-error';
+ $output .= "<div id='$css_id' class='$css_class'> \n";
+ $output .= "<p><strong>{$details['message']}</strong></p>";
+ $output .= "</div> \n";
+ }
+ echo $output;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.7.0
+ *
+ * @param unknown_type $found_action
+ */
+function find_posts_div($found_action = '') {
+?>
+ <div id="find-posts" class="find-box" style="display:none;">
+ <div id="find-posts-head" class="find-box-head"><?php _e('Find Posts or Pages'); ?></div>
+ <div class="find-box-inside">
+ <div class="find-box-search">
+ <?php if ( $found_action ) { ?>
+ <input type="hidden" name="found_action" value="<?php echo esc_attr($found_action); ?>" />
+ <?php } ?>
+
+ <input type="hidden" name="affected" id="affected" value="" />
+ <?php wp_nonce_field( 'find-posts', '_ajax_nonce', false ); ?>
+ <label class="screen-reader-text" for="find-posts-input"><?php _e( 'Search' ); ?></label>
+ <input type="text" id="find-posts-input" name="ps" value="" />
+ <span class="spinner"></span>
+ <input type="button" id="find-posts-search" value="<?php esc_attr_e( 'Search' ); ?>" class="button" />
+ </div>
+ <div id="find-posts-response"></div>
+ </div>
+ <div class="find-box-buttons">
+ <input id="find-posts-close" type="button" class="button alignleft" value="<?php esc_attr_e('Close'); ?>" />
+ <?php submit_button( __( 'Select' ), 'button-primary alignright', 'find-posts-submit', false ); ?>
+ </div>
+ </div>
+<?php
+}
+
+/**
+ * Display the post password.
+ *
+ * The password is passed through {@link esc_attr()} to ensure that it
+ * is safe for placing in an html attribute.
+ *
+ * @uses attr
+ * @since 2.7.0
+ */
+function the_post_password() {
+ $post = get_post();
+ if ( isset( $post->post_password ) )
+ echo esc_attr( $post->post_password );
+}
+
+/**
+ * Get the post title.
+ *
+ * The post title is fetched and if it is blank then a default string is
+ * returned.
+ *
+ * @since 2.7.0
+ * @param mixed $post Post id or object. If not supplied the global $post is used.
+ * @return string The post title if set
+ */
+function _draft_or_post_title( $post = 0 ) {
+ $title = get_the_title( $post );
+ if ( empty( $title ) )
+ $title = __( '(no title)' );
+ return $title;
+}
+
+/**
+ * Display the search query.
+ *
+ * A simple wrapper to display the "s" parameter in a GET URI. This function
+ * should only be used when {@link the_search_query()} cannot.
+ *
+ * @uses attr
+ * @since 2.7.0
+ *
+ */
+function _admin_search_query() {
+ echo isset($_REQUEST['s']) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
+}
+
+/**
+ * Generic Iframe header for use with Thickbox
+ *
+ * @since 2.7.0
+ * @param string $title Title of the Iframe page.
+ * @param bool $limit_styles Limit styles to colour-related styles only (unless others are enqueued).
+ *
+ */
+function iframe_header( $title = '', $limit_styles = false ) {
+ show_admin_bar( false );
+ global $hook_suffix, $current_user, $admin_body_class, $wp_locale;
+ $admin_body_class = preg_replace('/[^a-z0-9_-]+/i', '-', $hook_suffix);
+
+ $current_screen = get_current_screen();
+
+ @header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
+ _wp_admin_html_begin();
+?>
+<title><?php bloginfo('name') ?> &rsaquo; <?php echo $title ?> &#8212; <?php _e('WordPress'); ?></title>
+<?php
+wp_enqueue_style( 'colors' );
+?>
+<script type="text/javascript">
+//<![CDATA[
+addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
+function tb_close(){var win=window.dialogArguments||opener||parent||top;win.tb_remove();}
+var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>',
+ pagenow = '<?php echo $current_screen->id; ?>',
+ typenow = '<?php echo $current_screen->post_type; ?>',
+ adminpage = '<?php echo $admin_body_class; ?>',
+ thousandsSeparator = '<?php echo addslashes( $wp_locale->number_format['thousands_sep'] ); ?>',
+ decimalPoint = '<?php echo addslashes( $wp_locale->number_format['decimal_point'] ); ?>',
+ isRtl = <?php echo (int) is_rtl(); ?>;
+//]]>
+</script>
+<?php
+do_action('admin_enqueue_scripts', $hook_suffix);
+do_action("admin_print_styles-$hook_suffix");
+do_action('admin_print_styles');
+do_action("admin_print_scripts-$hook_suffix");
+do_action('admin_print_scripts');
+do_action("admin_head-$hook_suffix");
+do_action('admin_head');
+
+$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+
+if ( is_rtl() )
+ $admin_body_class .= ' rtl';
+
+?>
+</head>
+<body<?php if ( isset($GLOBALS['body_id']) ) echo ' id="' . $GLOBALS['body_id'] . '"'; ?> class="wp-admin wp-core-ui no-js iframe <?php echo apply_filters( 'admin_body_class', '' ) . ' ' . $admin_body_class; ?>">
+<script type="text/javascript">
+//<![CDATA[
+(function(){
+var c = document.body.className;
+c = c.replace(/no-js/, 'js');
+document.body.className = c;
+})();
+//]]>
+</script>
+<?php
+}
+
+/**
+ * Generic Iframe footer for use with Thickbox
+ *
+ * @since 2.7.0
+ *
+ */
+function iframe_footer() {
+ //We're going to hide any footer output on iframe pages, but run the hooks anyway since they output Javascript or other needed content. ?>
+ <div class="hidden">
+<?php
+ do_action('admin_footer', '');
+ do_action('admin_print_footer_scripts'); ?>
+ </div>
+<script type="text/javascript">if(typeof wpOnload=="function")wpOnload();</script>
+</body>
+</html>
+<?php
+}
+
+function _post_states($post) {
+ $post_states = array();
+ if ( isset( $_REQUEST['post_status'] ) )
+ $post_status = $_REQUEST['post_status'];
+ else
+ $post_status = '';
+
+ if ( !empty($post->post_password) )
+ $post_states['protected'] = __('Password protected');
+ if ( 'private' == $post->post_status && 'private' != $post_status )
+ $post_states['private'] = __('Private');
+ if ( 'draft' == $post->post_status && 'draft' != $post_status )
+ $post_states['draft'] = __('Draft');
+ if ( 'pending' == $post->post_status && 'pending' != $post_status )
+ /* translators: post state */
+ $post_states['pending'] = _x('Pending', 'post state');
+ if ( is_sticky($post->ID) )
+ $post_states['sticky'] = __('Sticky');
+
+ $post_states = apply_filters( 'display_post_states', $post_states, $post );
+
+ if ( ! empty($post_states) ) {
+ $state_count = count($post_states);
+ $i = 0;
+ echo ' - ';
+ foreach ( $post_states as $state ) {
+ ++$i;
+ ( $i == $state_count ) ? $sep = '' : $sep = ', ';
+ echo "<span class='post-state'>$state$sep</span>";
+ }
+ }
+
+}
+
+function _media_states( $post ) {
+ $media_states = array();
+ $stylesheet = get_option('stylesheet');
+
+ if ( current_theme_supports( 'custom-header') ) {
+ $meta_header = get_post_meta($post->ID, '_wp_attachment_is_custom_header', true );
+ if ( ! empty( $meta_header ) && $meta_header == $stylesheet )
+ $media_states[] = __( 'Header Image' );
+ }
+
+ if ( current_theme_supports( 'custom-background') ) {
+ $meta_background = get_post_meta($post->ID, '_wp_attachment_is_custom_background', true );
+ if ( ! empty( $meta_background ) && $meta_background == $stylesheet )
+ $media_states[] = __( 'Background Image' );
+ }
+
+ $media_states = apply_filters( 'display_media_states', $media_states );
+
+ if ( ! empty( $media_states ) ) {
+ $state_count = count( $media_states );
+ $i = 0;
+ echo ' - ';
+ foreach ( $media_states as $state ) {
+ ++$i;
+ ( $i == $state_count ) ? $sep = '' : $sep = ', ';
+ echo "<span class='post-state'>$state$sep</span>";
+ }
+ }
+}
+
+/**
+ * Test support for compressing JavaScript from PHP
+ *
+ * Outputs JavaScript that tests if compression from PHP works as expected
+ * and sets an option with the result. Has no effect when the current user
+ * is not an administrator. To run the test again the option 'can_compress_scripts'
+ * has to be deleted.
+ *
+ * @since 2.8.0
+ */
+function compression_test() {
+?>
+ <script type="text/javascript">
+ /* <![CDATA[ */
+ var testCompression = {
+ get : function(test) {
+ var x;
+ if ( window.XMLHttpRequest ) {
+ x = new XMLHttpRequest();
+ } else {
+ try{x=new ActiveXObject('Msxml2.XMLHTTP');}catch(e){try{x=new ActiveXObject('Microsoft.XMLHTTP');}catch(e){};}
+ }
+
+ if (x) {
+ x.onreadystatechange = function() {
+ var r, h;
+ if ( x.readyState == 4 ) {
+ r = x.responseText.substr(0, 18);
+ h = x.getResponseHeader('Content-Encoding');
+ testCompression.check(r, h, test);
+ }
+ }
+
+ x.open('GET', ajaxurl + '?action=wp-compression-test&test='+test+'&'+(new Date()).getTime(), true);
+ x.send('');
+ }
+ },
+
+ check : function(r, h, test) {
+ if ( ! r && ! test )
+ this.get(1);
+
+ if ( 1 == test ) {
+ if ( h && ( h.match(/deflate/i) || h.match(/gzip/i) ) )
+ this.get('no');
+ else
+ this.get(2);
+
+ return;
+ }
+
+ if ( 2 == test ) {
+ if ( '"wpCompressionTest' == r )
+ this.get('yes');
+ else
+ this.get('no');
+ }
+ }
+ };
+ testCompression.check();
+ /* ]]> */
+ </script>
+<?php
+}
+
+/**
+ * Echos a submit button, with provided text and appropriate class
+ *
+ * @since 3.1.0
+ *
+ * @param string $text The text of the button (defaults to 'Save Changes')
+ * @param string $type The type of button. One of: primary, secondary, delete
+ * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
+ * is given in $other_attributes below, $name will be used as the button's id.
+ * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
+ * false otherwise. Defaults to true
+ * @param array|string $other_attributes Other attributes that should be output with the button,
+ * mapping attributes to their values, such as array( 'tabindex' => '1' ).
+ * These attributes will be output as attribute="value", such as tabindex="1".
+ * Defaults to no other attributes. Other attributes can also be provided as a
+ * string such as 'tabindex="1"', though the array format is typically cleaner.
+ */
+function submit_button( $text = null, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = null ) {
+ echo get_submit_button( $text, $type, $name, $wrap, $other_attributes );
+}
+
+/**
+ * Returns a submit button, with provided text and appropriate class
+ *
+ * @since 3.1.0
+ *
+ * @param string $text The text of the button (defaults to 'Save Changes')
+ * @param string $type The type of button. One of: primary, secondary, delete
+ * @param string $name The HTML name of the submit button. Defaults to "submit". If no id attribute
+ * is given in $other_attributes below, $name will be used as the button's id.
+ * @param bool $wrap True if the output button should be wrapped in a paragraph tag,
+ * false otherwise. Defaults to true
+ * @param array|string $other_attributes Other attributes that should be output with the button,
+ * mapping attributes to their values, such as array( 'tabindex' => '1' ).
+ * These attributes will be output as attribute="value", such as tabindex="1".
+ * Defaults to no other attributes. Other attributes can also be provided as a
+ * string such as 'tabindex="1"', though the array format is typically cleaner.
+ */
+function get_submit_button( $text = null, $type = 'primary large', $name = 'submit', $wrap = true, $other_attributes = null ) {
+ if ( ! is_array( $type ) )
+ $type = explode( ' ', $type );
+
+ $button_shorthand = array( 'primary', 'small', 'large' );
+ $classes = array( 'button' );
+ foreach ( $type as $t ) {
+ if ( 'secondary' === $t || 'button-secondary' === $t )
+ continue;
+ $classes[] = in_array( $t, $button_shorthand ) ? 'button-' . $t : $t;
+ }
+ $class = implode( ' ', array_unique( $classes ) );
+
+ if ( 'delete' === $type )
+ $class = 'button-secondary delete';
+
+ $text = $text ? $text : __( 'Save Changes' );
+
+ // Default the id attribute to $name unless an id was specifically provided in $other_attributes
+ $id = $name;
+ if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
+ $id = $other_attributes['id'];
+ unset( $other_attributes['id'] );
+ }
+
+ $attributes = '';
+ if ( is_array( $other_attributes ) ) {
+ foreach ( $other_attributes as $attribute => $value ) {
+ $attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
+ }
+ } else if ( !empty( $other_attributes ) ) { // Attributes provided as a string
+ $attributes = $other_attributes;
+ }
+
+ $button = '<input type="submit" name="' . esc_attr( $name ) . '" id="' . esc_attr( $id ) . '" class="' . esc_attr( $class );
+ $button .= '" value="' . esc_attr( $text ) . '" ' . $attributes . ' />';
+
+ if ( $wrap ) {
+ $button = '<p class="submit">' . $button . '</p>';
+ }
+
+ return $button;
+}
+
+function _wp_admin_html_begin() {
+ $admin_html_class = ( is_admin_bar_showing() ) ? 'wp-toolbar' : '';
+?>
+<!DOCTYPE html>
+<!--[if IE 8]>
+<html xmlns="http://www.w3.org/1999/xhtml" class="ie8 <?php echo $admin_html_class; ?>" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if !(IE 8) ]><!-->
+<html xmlns="http://www.w3.org/1999/xhtml" class="<?php echo $admin_html_class; ?>" <?php do_action('admin_xml_ns'); ?> <?php language_attributes(); ?>>
+<!--<![endif]-->
+<head>
+<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
+<?php
+}
+
+final class WP_Internal_Pointers {
+ /**
+ * Initializes the new feature pointers.
+ *
+ * @since 3.3.0
+ *
+ * All pointers can be disabled using the following:
+ * remove_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts' ) );
+ *
+ * Individual pointers (e.g. wp330_toolbar) can be disabled using the following:
+ * remove_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_wp330_toolbar' ) );
+ */
+ public static function enqueue_scripts( $hook_suffix ) {
+ /*
+ * Register feature pointers
+ * Format: array( hook_suffix => pointer_id )
+ */
+
+ $registered_pointers = array(
+ 'index.php' => 'wp330_toolbar',
+ 'post-new.php' => 'wp350_media',
+ 'post.php' => array( 'wp350_media', 'wp360_revisions' ),
+ 'edit.php' => 'wp360_locks',
+ 'themes.php' => array( 'wp330_saving_widgets', 'wp340_customize_current_theme_link' ),
+ 'appearance_page_custom-header' => 'wp340_choose_image_from_library',
+ 'appearance_page_custom-background' => 'wp340_choose_image_from_library',
+ );
+
+ // Check if screen related pointer is registered
+ if ( empty( $registered_pointers[ $hook_suffix ] ) )
+ return;
+
+ $pointers = (array) $registered_pointers[ $hook_suffix ];
+
+ $caps_required = array(
+ 'wp330_saving_widgets' => array( 'edit_theme_options', 'switch_themes' ),
+ 'wp340_customize_current_theme_link' => array( 'edit_theme_options' ),
+ 'wp340_choose_image_from_library' => array( 'edit_theme_options' ),
+ 'wp350_media' => array( 'upload_files' ),
+ );
+
+ // Get dismissed pointers
+ $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
+
+ $got_pointers = false;
+ foreach ( array_diff( $pointers, $dismissed ) as $pointer ) {
+ if ( isset( $caps_required[ $pointer ] ) ) {
+ foreach ( $caps_required[ $pointer ] as $cap ) {
+ if ( ! current_user_can( $cap ) )
+ continue 2;
+ }
+ }
+
+ // Bind pointer print function
+ add_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_' . $pointer ) );
+ $got_pointers = true;
+ }
+
+ if ( ! $got_pointers )
+ return;
+
+ // Add pointers script and style to queue
+ wp_enqueue_style( 'wp-pointer' );
+ wp_enqueue_script( 'wp-pointer' );
+ }
+
+ /**
+ * Print the pointer javascript data.
+ *
+ * @since 3.3.0
+ *
+ * @param string $pointer_id The pointer ID.
+ * @param string $selector The HTML elements, on which the pointer should be attached.
+ * @param array $args Arguments to be passed to the pointer JS (see wp-pointer.js).
+ */
+ private static function print_js( $pointer_id, $selector, $args ) {
+ if ( empty( $pointer_id ) || empty( $selector ) || empty( $args ) || empty( $args['content'] ) )
+ return;
+
+ ?>
+ <script type="text/javascript">
+ //<![CDATA[
+ (function($){
+ var options = <?php echo json_encode( $args ); ?>, setup;
+
+ if ( ! options )
+ return;
+
+ options = $.extend( options, {
+ close: function() {
+ $.post( ajaxurl, {
+ pointer: '<?php echo $pointer_id; ?>',
+ action: 'dismiss-wp-pointer'
+ });
+ }
+ });
+
+ setup = function() {
+ $('<?php echo $selector; ?>').pointer( options ).pointer('open');
+ };
+
+ if ( options.position && options.position.defer_loading )
+ $(window).bind( 'load.wp-pointers', setup );
+ else
+ $(document).ready( setup );
+
+ })( jQuery );
+ //]]>
+ </script>
+ <?php
+ }
+
+ public static function pointer_wp330_toolbar() {
+ $content = '<h3>' . __( 'New Feature: Toolbar' ) . '</h3>';
+ $content .= '<p>' . __( 'We&#8217;ve combined the admin bar and the old Dashboard header into one persistent toolbar. Hover over the toolbar items to see what&#8217;s new.' ) . '</p>';
+
+ if ( is_multisite() && is_super_admin() )
+ $content .= '<p>' . __( 'Network Admin is now located in the My Sites menu.' ) . '</p>';
+
+ WP_Internal_Pointers::print_js( 'wp330_toolbar', '#wpadminbar', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => 'top', 'align' => 'center' ),
+ ) );
+ }
+
+ /**
+ * Print 'Updated Media Uploader' for 3.3.0.
+ *
+ * @since 3.3.0
+ */
+ public static function pointer_wp330_media_uploader() {}
+
+ /**
+ * Print 'New Feature: Saving Widgets' for 3.3.0.
+ *
+ * @since 3.3.0
+ */
+ public static function pointer_wp330_saving_widgets() {
+ $content = '<h3>' . __( 'New Feature: Saving Widgets' ) . '</h3>';
+ $content .= '<p>' . __( 'If you change your mind and revert to your previous theme, we&#8217;ll put the widgets back the way you had them.' ) . '</p>';
+
+ WP_Internal_Pointers::print_js( 'wp330_saving_widgets', '#message2', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left' ),
+ ) );
+ }
+
+ /**
+ * Print 'New Feature: Current Theme Customize Link' for 3.4.0.
+ *
+ * @since 3.4.0
+ */
+ public static function pointer_wp340_customize_current_theme_link() {
+ $content = '<h3>' . __( 'New Feature: Customizer' ) . '</h3>';
+ $content .= '<p>' . __( 'Click Customize to change the header, background, title and menus of the current theme, all in one place.' ) . '</p>';
+ $content .= '<p>' . __( 'Click the Live Preview links in the Available Themes list below to customize and preview another theme before activating it.' ) . '</p>';
+
+ WP_Internal_Pointers::print_js( 'wp340_customize_current_theme_link', '#customize-current-theme-link', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left', 'offset' => is_rtl() ? '32 0' : '-32 0' ),
+ ) );
+ }
+
+ /**
+ * Print 'New Feature: Choose Image from Library' for 3.4.0.
+ *
+ * @since 3.4.0
+ */
+ public static function pointer_wp340_choose_image_from_library() {
+ $content = '<h3>' . __( 'New Feature: Choose Image from Library' ) . '</h3>';
+ $content .= '<p>' . __( 'Want to use an image you uploaded earlier? Select it from your media library instead of uploading it again.' ) . '</p>';
+
+ WP_Internal_Pointers::print_js( 'wp340_choose_image_from_library', '#choose-from-library-link', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right' : 'left', 'defer_loading' => true ),
+ ) );
+ }
+
+ public static function pointer_wp350_media() {
+ $content = '<h3>' . __( 'New Media Manager' ) . '</h3>';
+ $content .= '<p>' . __( 'Uploading files and creating image galleries has a whole new look. Check it out!' ) . '</p>';
+
+ self::print_js( 'wp350_media', '.insert-media', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => is_rtl() ? 'right' : 'left', 'align' => 'center' ),
+ ) );
+ }
+
+ public static function pointer_wp360_revisions() {
+ $content = '<h3>' . __( 'Compare Revisions' ) . '</h3>';
+ $content .= '<p>' . __( 'View, compare, and restore other versions of this content on the improved revisions screen.' ) . '</p>';
+
+ self::print_js( 'wp360_revisions', '.misc-pub-section.num-revisions', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => is_rtl() ? 'left' : 'right', 'align' => 'center', 'my' => is_rtl() ? 'left' : 'right-14px' ),
+ ) );
+ }
+
+ public static function pointer_wp360_locks() {
+ $content = '<h3>' . __( 'Edit Lock' ) . '</h3>';
+ $content .= '<p>' . __( 'Someone else is editing this. No need to refresh; the lock will disappear when they&#8217;re done.' ) . '</p>';
+
+ if ( ! is_multi_author() )
+ return;
+
+ self::print_js( 'wp360_locks', 'tr.wp-locked .locked-indicator', array(
+ 'content' => $content,
+ 'position' => array( 'edge' => 'left', 'align' => 'left' ),
+ ) );
+ }
+
+ /**
+ * Prevents new users from seeing existing 'new feature' pointers.
+ *
+ * @since 3.3.0
+ */
+ public static function dismiss_pointers_for_new_users( $user_id ) {
+ add_user_meta( $user_id, 'dismissed_wp_pointers', 'wp330_toolbar,wp330_saving_widgets,wp340_choose_image_from_library,wp340_customize_current_theme_link,wp350_media,wp360_revisions,wp360_locks' );
+ }
+}
+
+add_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts' ) );
+add_action( 'user_register', array( 'WP_Internal_Pointers', 'dismiss_pointers_for_new_users' ) );
+
+/**
+ * Convert a screen string to a screen object
+ *
+ * @since 3.0.0
+ *
+ * @param string $hook_name The hook name (also known as the hook suffix) used to determine the screen.
+ * @return WP_Screen Screen object.
+ */
+function convert_to_screen( $hook_name ) {
+ if ( ! class_exists( 'WP_Screen' ) ) {
+ _doing_it_wrong( 'convert_to_screen(), add_meta_box()', __( "Likely direct inclusion of wp-admin/includes/template.php in order to use add_meta_box(). This is very wrong. Hook the add_meta_box() call into the add_meta_boxes action instead." ), '3.3' );
+ return (object) array( 'id' => '_invalid', 'base' => '_are_belong_to_us' );
+ }
+
+ return WP_Screen::get( $hook_name );
+}
+
+/**
+ * Output the HTML for restoring the post data from DOM storage
+ *
+ * @since 3.6
+ * @access private
+ */
+function _local_storage_notice() {
+ ?>
+ <div id="local-storage-notice" class="hidden">
+ <p class="local-restore">
+ <?php _e('The backup of this post in your browser is different from the version below.'); ?>
+ <a class="restore-backup" href="#"><?php _e('Restore the backup.'); ?></a>
+ </p>
+ <p class="undo-restore hidden">
+ <?php _e('Post restored successfully.'); ?>
+ <a class="undo-restore-backup" href="#"><?php _e('Undo.'); ?></a>
+ </p>
+ </div>
+ <?php
+}
diff --git a/src/wp-admin/includes/theme-install.php b/src/wp-admin/includes/theme-install.php
new file mode 100644
index 0000000000..63be1d7e01
--- /dev/null
+++ b/src/wp-admin/includes/theme-install.php
@@ -0,0 +1,194 @@
+<?php
+/**
+ * WordPress Theme Install Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+$themes_allowedtags = array('a' => array('href' => array(), 'title' => array(), 'target' => array()),
+ 'abbr' => array('title' => array()), 'acronym' => array('title' => array()),
+ 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(),
+ 'div' => array(), 'p' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(),
+ 'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(),
+ 'img' => array('src' => array(), 'class' => array(), 'alt' => array())
+);
+
+$theme_field_defaults = array( 'description' => true, 'sections' => false, 'tested' => true, 'requires' => true,
+ 'rating' => true, 'downloaded' => true, 'downloadlink' => true, 'last_updated' => true, 'homepage' => true,
+ 'tags' => true, 'num_ratings' => true
+);
+
+/**
+ * Retrieve list of WordPress theme features (aka theme tags)
+ *
+ * @since 2.8.0
+ *
+ * @deprecated since 3.1.0 Use get_theme_feature_list() instead.
+ *
+ * @return array
+ */
+function install_themes_feature_list() {
+ _deprecated_function( __FUNCTION__, '3.1', 'get_theme_feature_list()' );
+
+ if ( !$cache = get_transient( 'wporg_theme_feature_list' ) )
+ set_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS );
+
+ if ( $cache )
+ return $cache;
+
+ $feature_list = themes_api( 'feature_list', array() );
+ if ( is_wp_error( $feature_list ) )
+ return array();
+
+ set_transient( 'wporg_theme_feature_list', $feature_list, 3 * HOUR_IN_SECONDS );
+
+ return $feature_list;
+}
+
+/**
+ * Display search form for searching themes.
+ *
+ * @since 2.8.0
+ */
+function install_theme_search_form( $type_selector = true ) {
+ $type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
+ $term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : '';
+ if ( ! $type_selector )
+ echo '<p class="install-help">' . __( 'Search for themes by keyword.' ) . '</p>';
+ ?>
+<form id="search-themes" method="get" action="">
+ <input type="hidden" name="tab" value="search" />
+ <?php if ( $type_selector ) : ?>
+ <label class="screen-reader-text" for="typeselector"><?php _e('Type of search'); ?></label>
+ <select name="type" id="typeselector">
+ <option value="term" <?php selected('term', $type) ?>><?php _e('Keyword'); ?></option>
+ <option value="author" <?php selected('author', $type) ?>><?php _e('Author'); ?></option>
+ <option value="tag" <?php selected('tag', $type) ?>><?php _ex('Tag', 'Theme Installer'); ?></option>
+ </select>
+ <label class="screen-reader-text" for="s"><?php
+ switch ( $type ) {
+ case 'term':
+ _e( 'Search by keyword' );
+ break;
+ case 'author':
+ _e( 'Search by author' );
+ break;
+ case 'tag':
+ _e( 'Search by tag' );
+ break;
+ }
+ ?></label>
+ <?php else : ?>
+ <label class="screen-reader-text" for="s"><?php _e('Search by keyword'); ?></label>
+ <?php endif; ?>
+ <input type="search" name="s" id="s" size="30" value="<?php echo esc_attr($term) ?>" autofocus="autofocus" />
+ <?php submit_button( __( 'Search' ), 'button', 'search', false ); ?>
+</form>
+<?php
+}
+
+/**
+ * Display tags filter for themes.
+ *
+ * @since 2.8.0
+ */
+function install_themes_dashboard() {
+ install_theme_search_form( false );
+?>
+<h4><?php _e('Feature Filter') ?></h4>
+<p class="install-help"><?php _e( 'Find a theme based on specific features.' ); ?></p>
+
+<form method="get" action="">
+ <input type="hidden" name="tab" value="search" />
+ <?php
+ $feature_list = get_theme_feature_list();
+ echo '<div class="feature-filter">';
+
+ foreach ( (array) $feature_list as $feature_name => $features ) {
+ $feature_name = esc_html( $feature_name );
+ echo '<div class="feature-name">' . $feature_name . '</div>';
+
+ echo '<ol class="feature-group">';
+ foreach ( $features as $feature => $feature_name ) {
+ $feature_name = esc_html( $feature_name );
+ $feature = esc_attr($feature);
+?>
+
+<li>
+ <input type="checkbox" name="features[]" id="feature-id-<?php echo $feature; ?>" value="<?php echo $feature; ?>" />
+ <label for="feature-id-<?php echo $feature; ?>"><?php echo $feature_name; ?></label>
+</li>
+
+<?php } ?>
+</ol>
+<br class="clear" />
+<?php
+ } ?>
+
+</div>
+<br class="clear" />
+<?php submit_button( __( 'Find Themes' ), 'button', 'search' ); ?>
+</form>
+<?php
+}
+add_action('install_themes_dashboard', 'install_themes_dashboard');
+
+function install_themes_upload($page = 1) {
+?>
+<h4><?php _e('Install a theme in .zip format'); ?></h4>
+<p class="install-help"><?php _e('If you have a theme in a .zip format, you may install it by uploading it here.'); ?></p>
+<form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-theme'); ?>">
+ <?php wp_nonce_field( 'theme-upload'); ?>
+ <input type="file" name="themezip" />
+ <?php submit_button( __( 'Install Now' ), 'button', 'install-theme-submit', false ); ?>
+</form>
+ <?php
+}
+add_action('install_themes_upload', 'install_themes_upload', 10, 1);
+
+/**
+ * Prints a theme on the Install Themes pages.
+ *
+ * @deprecated 3.4.0
+ */
+function display_theme( $theme ) {
+ _deprecated_function( __FUNCTION__, '3.4' );
+ global $wp_list_table;
+ $wp_list_table->single_row( $theme );
+}
+
+/**
+ * Display theme content based on theme list.
+ *
+ * @since 2.8.0
+ */
+function display_themes() {
+ global $wp_list_table;
+
+ $wp_list_table->display();
+}
+add_action('install_themes_search', 'display_themes');
+add_action('install_themes_featured', 'display_themes');
+add_action('install_themes_new', 'display_themes');
+add_action('install_themes_updated', 'display_themes');
+
+/**
+ * Display theme information in dialog box form.
+ *
+ * @since 2.8.0
+ */
+function install_theme_information() {
+ global $tab, $themes_allowedtags, $wp_list_table;
+
+ $theme = themes_api( 'theme_information', array( 'slug' => wp_unslash( $_REQUEST['theme'] ) ) );
+
+ if ( is_wp_error( $theme ) )
+ wp_die( $theme );
+
+ iframe_header( __('Theme Install') );
+ $wp_list_table->theme_installer_single( $theme );
+ iframe_footer();
+ exit;
+}
+add_action('install_themes_pre_theme-information', 'install_theme_information');
diff --git a/src/wp-admin/includes/theme.php b/src/wp-admin/includes/theme.php
new file mode 100644
index 0000000000..315f021386
--- /dev/null
+++ b/src/wp-admin/includes/theme.php
@@ -0,0 +1,296 @@
+<?php
+/**
+ * WordPress Theme Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Remove a theme
+ *
+ * @since 2.8.0
+ *
+ * @param string $stylesheet Stylesheet of the theme to delete
+ * @param string $redirect Redirect to page when complete.
+ * @return mixed
+ */
+function delete_theme($stylesheet, $redirect = '') {
+ global $wp_filesystem;
+
+ if ( empty($stylesheet) )
+ return false;
+
+ ob_start();
+ if ( empty( $redirect ) )
+ $redirect = wp_nonce_url('themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet);
+ if ( false === ($credentials = request_filesystem_credentials($redirect)) ) {
+ $data = ob_get_contents();
+ ob_end_clean();
+ if ( ! empty($data) ){
+ include_once( ABSPATH . 'wp-admin/admin-header.php');
+ echo $data;
+ include( ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ }
+ return;
+ }
+
+ if ( ! WP_Filesystem($credentials) ) {
+ request_filesystem_credentials($redirect, '', true); // Failed to connect, Error and request again
+ $data = ob_get_contents();
+ ob_end_clean();
+ if ( ! empty($data) ) {
+ include_once( ABSPATH . 'wp-admin/admin-header.php');
+ echo $data;
+ include( ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ }
+ return;
+ }
+
+ if ( ! is_object($wp_filesystem) )
+ return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
+
+ if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
+ return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors);
+
+ //Get the base plugin folder
+ $themes_dir = $wp_filesystem->wp_themes_dir();
+ if ( empty($themes_dir) )
+ return new WP_Error('fs_no_themes_dir', __('Unable to locate WordPress theme directory.'));
+
+ $themes_dir = trailingslashit( $themes_dir );
+ $theme_dir = trailingslashit($themes_dir . $stylesheet);
+ $deleted = $wp_filesystem->delete($theme_dir, true);
+
+ if ( ! $deleted )
+ return new WP_Error('could_not_remove_theme', sprintf(__('Could not fully remove the theme %s.'), $stylesheet) );
+
+ // Force refresh of theme update information
+ delete_site_transient('update_themes');
+
+ return true;
+}
+
+/**
+ * Get the Page Templates available in this theme
+ *
+ * @since 1.5.0
+ *
+ * @return array Key is the template name, value is the filename of the template
+ */
+function get_page_templates() {
+ return array_flip( wp_get_theme()->get_page_templates() );
+}
+
+/**
+ * Tidies a filename for url display by the theme editor.
+ *
+ * @since 2.9.0
+ * @access private
+ *
+ * @param string $fullpath Full path to the theme file
+ * @param string $containingfolder Path of the theme parent folder
+ * @return string
+ */
+function _get_template_edit_filename($fullpath, $containingfolder) {
+ return str_replace(dirname(dirname( $containingfolder )) , '', $fullpath);
+}
+
+/**
+ * Check if there is an update for a theme available.
+ *
+ * Will display link, if there is an update available.
+ *
+ * @since 2.7.0
+ *
+ * @param object $theme Theme data object.
+ * @return bool False if no valid info was passed.
+ */
+function theme_update_available( $theme ) {
+ static $themes_update;
+
+ if ( !current_user_can('update_themes' ) )
+ return;
+
+ if ( !isset($themes_update) )
+ $themes_update = get_site_transient('update_themes');
+
+ if ( ! is_a( $theme, 'WP_Theme' ) )
+ return;
+
+ $stylesheet = $theme->get_stylesheet();
+
+ if ( isset($themes_update->response[ $stylesheet ]) ) {
+ $update = $themes_update->response[ $stylesheet ];
+ $theme_name = $theme->display('Name');
+ $details_url = add_query_arg(array('TB_iframe' => 'true', 'width' => 1024, 'height' => 800), $update['url']); //Theme browser inside WP? replace this, Also, theme preview JS will override this on the available list.
+ $update_url = wp_nonce_url('update.php?action=upgrade-theme&amp;theme=' . urlencode($stylesheet), 'upgrade-theme_' . $stylesheet);
+ $update_onclick = 'onclick="if ( confirm(\'' . esc_js( __("Updating this theme will lose any customizations you have made. 'Cancel' to stop, 'OK' to update.") ) . '\') ) {return true;}return false;"';
+
+ if ( !is_multisite() ) {
+ if ( ! current_user_can('update_themes') )
+ printf( '<p><strong>' . __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%1$s">View version %3$s details</a>.') . '</strong></p>', $theme_name, $details_url, $update['new_version']);
+ else if ( empty($update['package']) )
+ printf( '<p><strong>' . __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%1$s">View version %3$s details</a>. <em>Automatic update is unavailable for this theme.</em>') . '</strong></p>', $theme_name, $details_url, $update['new_version']);
+ else
+ printf( '<p><strong>' . __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%1$s">View version %3$s details</a> or <a href="%4$s" %5$s>update now</a>.') . '</strong></p>', $theme_name, $details_url, $update['new_version'], $update_url, $update_onclick );
+ }
+ }
+}
+
+/**
+ * Retrieve list of WordPress theme features (aka theme tags)
+ *
+ * @since 3.1.0
+ *
+ * @param bool $api Optional. Whether try to fetch tags from the WP.org API. Defaults to true.
+ * @return array Array of features keyed by category with translations keyed by slug.
+ */
+function get_theme_feature_list( $api = true ) {
+ // Hard-coded list is used if api not accessible.
+ $features = array(
+ __( 'Colors' ) => array(
+ 'black' => __( 'Black' ),
+ 'blue' => __( 'Blue' ),
+ 'brown' => __( 'Brown' ),
+ 'gray' => __( 'Gray' ),
+ 'green' => __( 'Green' ),
+ 'orange' => __( 'Orange' ),
+ 'pink' => __( 'Pink' ),
+ 'purple' => __( 'Purple' ),
+ 'red' => __( 'Red' ),
+ 'silver' => __( 'Silver' ),
+ 'tan' => __( 'Tan' ),
+ 'white' => __( 'White' ),
+ 'yellow' => __( 'Yellow' ),
+ 'dark' => __( 'Dark' ),
+ 'light' => __( 'Light' ),
+ ),
+
+ __( 'Columns' ) => array(
+ 'one-column' => __( 'One Column' ),
+ 'two-columns' => __( 'Two Columns' ),
+ 'three-columns' => __( 'Three Columns' ),
+ 'four-columns' => __( 'Four Columns' ),
+ 'left-sidebar' => __( 'Left Sidebar' ),
+ 'right-sidebar' => __( 'Right Sidebar' ),
+ ),
+
+ __( 'Width' ) => array(
+ 'fixed-width' => __( 'Fixed Width' ),
+ 'flexible-width' => __( 'Flexible Width' ),
+ ),
+
+ __( 'Features' ) => array(
+ 'blavatar' => __( 'Blavatar' ),
+ 'buddypress' => __( 'BuddyPress' ),
+ 'custom-background' => __( 'Custom Background' ),
+ 'custom-colors' => __( 'Custom Colors' ),
+ 'custom-header' => __( 'Custom Header' ),
+ 'custom-menu' => __( 'Custom Menu' ),
+ 'editor-style' => __( 'Editor Style' ),
+ 'featured-image-header' => __( 'Featured Image Header' ),
+ 'featured-images' => __( 'Featured Images' ),
+ 'flexible-header' => __( 'Flexible Header' ),
+ 'front-page-post-form' => __( 'Front Page Posting' ),
+ 'full-width-template' => __( 'Full Width Template' ),
+ 'microformats' => __( 'Microformats' ),
+ 'post-formats' => __( 'Post Formats' ),
+ 'rtl-language-support' => __( 'RTL Language Support' ),
+ 'sticky-post' => __( 'Sticky Post' ),
+ 'theme-options' => __( 'Theme Options' ),
+ 'threaded-comments' => __( 'Threaded Comments' ),
+ 'translation-ready' => __( 'Translation Ready' ),
+ ),
+
+ __( 'Subject' ) => array(
+ 'holiday' => __( 'Holiday' ),
+ 'photoblogging' => __( 'Photoblogging' ),
+ 'seasonal' => __( 'Seasonal' ),
+ )
+ );
+
+ if ( ! $api || ! current_user_can( 'install_themes' ) )
+ return $features;
+
+ if ( !$feature_list = get_site_transient( 'wporg_theme_feature_list' ) )
+ set_site_transient( 'wporg_theme_feature_list', array(), 10800);
+
+ if ( !$feature_list ) {
+ $feature_list = themes_api( 'feature_list', array() );
+ if ( is_wp_error( $feature_list ) )
+ return $features;
+ }
+
+ if ( !$feature_list )
+ return $features;
+
+ set_site_transient( 'wporg_theme_feature_list', $feature_list, 10800 );
+
+ $category_translations = array( 'Colors' => __('Colors'), 'Columns' => __('Columns'), 'Width' => __('Width'),
+ 'Features' => __('Features'), 'Subject' => __('Subject') );
+
+ // Loop over the wporg canonical list and apply translations
+ $wporg_features = array();
+ foreach ( (array) $feature_list as $feature_category => $feature_items ) {
+ if ( isset($category_translations[$feature_category]) )
+ $feature_category = $category_translations[$feature_category];
+ $wporg_features[$feature_category] = array();
+
+ foreach ( $feature_items as $feature ) {
+ if ( isset($features[$feature_category][$feature]) )
+ $wporg_features[$feature_category][$feature] = $features[$feature_category][$feature];
+ else
+ $wporg_features[$feature_category][$feature] = $feature;
+ }
+ }
+
+ return $wporg_features;
+}
+
+/**
+ * Retrieve theme installer pages from WordPress Themes API.
+ *
+ * It is possible for a theme to override the Themes API result with three
+ * filters. Assume this is for themes, which can extend on the Theme Info to
+ * offer more choices. This is very powerful and must be used with care, when
+ * overridding the filters.
+ *
+ * The first filter, 'themes_api_args', is for the args and gives the action as
+ * the second parameter. The hook for 'themes_api_args' must ensure that an
+ * object is returned.
+ *
+ * The second filter, 'themes_api', is the result that would be returned.
+ *
+ * @since 2.8.0
+ *
+ * @param string $action
+ * @param array|object $args Optional. Arguments to serialize for the Theme Info API.
+ * @return mixed
+ */
+function themes_api($action, $args = null) {
+
+ if ( is_array($args) )
+ $args = (object)$args;
+
+ if ( !isset($args->per_page) )
+ $args->per_page = 24;
+
+ $args = apply_filters('themes_api_args', $args, $action); //NOTE: Ensure that an object is returned via this filter.
+ $res = apply_filters('themes_api', false, $action, $args); //NOTE: Allows a theme to completely override the builtin WordPress.org API.
+
+ if ( ! $res ) {
+ $request = wp_remote_post('http://api.wordpress.org/themes/info/1.0/', array( 'body' => array('action' => $action, 'request' => serialize($args))) );
+ if ( is_wp_error($request) ) {
+ $res = new WP_Error('themes_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="http://wordpress.org/support/">support forums</a>.' ), $request->get_error_message() );
+ } else {
+ $res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
+ if ( ! is_object( $res ) && ! is_array( $res ) )
+ $res = new WP_Error('themes_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="http://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body( $request ) );
+ }
+ }
+
+ return apply_filters('themes_api_result', $res, $action, $args);
+}
diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php
new file mode 100644
index 0000000000..85eb84062a
--- /dev/null
+++ b/src/wp-admin/includes/update-core.php
@@ -0,0 +1,896 @@
+<?php
+/**
+ * WordPress core upgrade functionality.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 2.7.0
+ */
+
+/**
+ * Stores files to be deleted.
+ *
+ * @since 2.7.0
+ * @global array $_old_files
+ * @var array
+ * @name $_old_files
+ */
+global $_old_files;
+
+$_old_files = array(
+// 2.0
+'wp-admin/import-b2.php',
+'wp-admin/import-blogger.php',
+'wp-admin/import-greymatter.php',
+'wp-admin/import-livejournal.php',
+'wp-admin/import-mt.php',
+'wp-admin/import-rss.php',
+'wp-admin/import-textpattern.php',
+'wp-admin/quicktags.js',
+'wp-images/fade-butt.png',
+'wp-images/get-firefox.png',
+'wp-images/header-shadow.png',
+'wp-images/smilies',
+'wp-images/wp-small.png',
+'wp-images/wpminilogo.png',
+'wp.php',
+// 2.0.8
+'wp-includes/js/tinymce/plugins/inlinepopups/readme.txt',
+// 2.1
+'wp-admin/edit-form-ajax-cat.php',
+'wp-admin/execute-pings.php',
+'wp-admin/inline-uploading.php',
+'wp-admin/link-categories.php',
+'wp-admin/list-manipulation.js',
+'wp-admin/list-manipulation.php',
+'wp-includes/comment-functions.php',
+'wp-includes/feed-functions.php',
+'wp-includes/functions-compat.php',
+'wp-includes/functions-formatting.php',
+'wp-includes/functions-post.php',
+'wp-includes/js/dbx-key.js',
+'wp-includes/js/tinymce/plugins/autosave/langs/cs.js',
+'wp-includes/js/tinymce/plugins/autosave/langs/sv.js',
+'wp-includes/links.php',
+'wp-includes/pluggable-functions.php',
+'wp-includes/template-functions-author.php',
+'wp-includes/template-functions-category.php',
+'wp-includes/template-functions-general.php',
+'wp-includes/template-functions-links.php',
+'wp-includes/template-functions-post.php',
+'wp-includes/wp-l10n.php',
+// 2.2
+'wp-admin/cat-js.php',
+'wp-admin/import/b2.php',
+'wp-includes/js/autosave-js.php',
+'wp-includes/js/list-manipulation-js.php',
+'wp-includes/js/wp-ajax-js.php',
+// 2.3
+'wp-admin/admin-db.php',
+'wp-admin/cat.js',
+'wp-admin/categories.js',
+'wp-admin/custom-fields.js',
+'wp-admin/dbx-admin-key.js',
+'wp-admin/edit-comments.js',
+'wp-admin/install-rtl.css',
+'wp-admin/install.css',
+'wp-admin/upgrade-schema.php',
+'wp-admin/upload-functions.php',
+'wp-admin/upload-rtl.css',
+'wp-admin/upload.css',
+'wp-admin/upload.js',
+'wp-admin/users.js',
+'wp-admin/widgets-rtl.css',
+'wp-admin/widgets.css',
+'wp-admin/xfn.js',
+'wp-includes/js/tinymce/license.html',
+// 2.5
+'wp-admin/css/upload.css',
+'wp-admin/images/box-bg-left.gif',
+'wp-admin/images/box-bg-right.gif',
+'wp-admin/images/box-bg.gif',
+'wp-admin/images/box-butt-left.gif',
+'wp-admin/images/box-butt-right.gif',
+'wp-admin/images/box-butt.gif',
+'wp-admin/images/box-head-left.gif',
+'wp-admin/images/box-head-right.gif',
+'wp-admin/images/box-head.gif',
+'wp-admin/images/heading-bg.gif',
+'wp-admin/images/login-bkg-bottom.gif',
+'wp-admin/images/login-bkg-tile.gif',
+'wp-admin/images/notice.gif',
+'wp-admin/images/toggle.gif',
+'wp-admin/includes/upload.php',
+'wp-admin/js/dbx-admin-key.js',
+'wp-admin/js/link-cat.js',
+'wp-admin/profile-update.php',
+'wp-admin/templates.php',
+'wp-includes/images/wlw/WpComments.png',
+'wp-includes/images/wlw/WpIcon.png',
+'wp-includes/images/wlw/WpWatermark.png',
+'wp-includes/js/dbx.js',
+'wp-includes/js/fat.js',
+'wp-includes/js/list-manipulation.js',
+'wp-includes/js/tinymce/langs/en.js',
+'wp-includes/js/tinymce/plugins/autosave/editor_plugin_src.js',
+'wp-includes/js/tinymce/plugins/autosave/langs',
+'wp-includes/js/tinymce/plugins/directionality/images',
+'wp-includes/js/tinymce/plugins/directionality/langs',
+'wp-includes/js/tinymce/plugins/inlinepopups/css',
+'wp-includes/js/tinymce/plugins/inlinepopups/images',
+'wp-includes/js/tinymce/plugins/inlinepopups/jscripts',
+'wp-includes/js/tinymce/plugins/paste/images',
+'wp-includes/js/tinymce/plugins/paste/jscripts',
+'wp-includes/js/tinymce/plugins/paste/langs',
+'wp-includes/js/tinymce/plugins/spellchecker/classes/HttpClient.class.php',
+'wp-includes/js/tinymce/plugins/spellchecker/classes/TinyGoogleSpell.class.php',
+'wp-includes/js/tinymce/plugins/spellchecker/classes/TinyPspell.class.php',
+'wp-includes/js/tinymce/plugins/spellchecker/classes/TinyPspellShell.class.php',
+'wp-includes/js/tinymce/plugins/spellchecker/css/spellchecker.css',
+'wp-includes/js/tinymce/plugins/spellchecker/images',
+'wp-includes/js/tinymce/plugins/spellchecker/langs',
+'wp-includes/js/tinymce/plugins/spellchecker/tinyspell.php',
+'wp-includes/js/tinymce/plugins/wordpress/images',
+'wp-includes/js/tinymce/plugins/wordpress/langs',
+'wp-includes/js/tinymce/plugins/wordpress/wordpress.css',
+'wp-includes/js/tinymce/plugins/wphelp',
+'wp-includes/js/tinymce/themes/advanced/css',
+'wp-includes/js/tinymce/themes/advanced/images',
+'wp-includes/js/tinymce/themes/advanced/jscripts',
+'wp-includes/js/tinymce/themes/advanced/langs',
+// 2.5.1
+'wp-includes/js/tinymce/tiny_mce_gzip.php',
+// 2.6
+'wp-admin/bookmarklet.php',
+'wp-includes/js/jquery/jquery.dimensions.min.js',
+'wp-includes/js/tinymce/plugins/wordpress/popups.css',
+'wp-includes/js/wp-ajax.js',
+// 2.7
+'wp-admin/css/press-this-ie-rtl.css',
+'wp-admin/css/press-this-ie.css',
+'wp-admin/css/upload-rtl.css',
+'wp-admin/edit-form.php',
+'wp-admin/images/comment-pill.gif',
+'wp-admin/images/comment-stalk-classic.gif',
+'wp-admin/images/comment-stalk-fresh.gif',
+'wp-admin/images/comment-stalk-rtl.gif',
+'wp-admin/images/del.png',
+'wp-admin/images/gear.png',
+'wp-admin/images/media-button-gallery.gif',
+'wp-admin/images/media-buttons.gif',
+'wp-admin/images/postbox-bg.gif',
+'wp-admin/images/tab.png',
+'wp-admin/images/tail.gif',
+'wp-admin/js/forms.js',
+'wp-admin/js/upload.js',
+'wp-admin/link-import.php',
+'wp-includes/images/audio.png',
+'wp-includes/images/css.png',
+'wp-includes/images/default.png',
+'wp-includes/images/doc.png',
+'wp-includes/images/exe.png',
+'wp-includes/images/html.png',
+'wp-includes/images/js.png',
+'wp-includes/images/pdf.png',
+'wp-includes/images/swf.png',
+'wp-includes/images/tar.png',
+'wp-includes/images/text.png',
+'wp-includes/images/video.png',
+'wp-includes/images/zip.png',
+'wp-includes/js/tinymce/tiny_mce_config.php',
+'wp-includes/js/tinymce/tiny_mce_ext.js',
+// 2.8
+'wp-admin/js/users.js',
+'wp-includes/js/swfupload/plugins/swfupload.documentready.js',
+'wp-includes/js/swfupload/plugins/swfupload.graceful_degradation.js',
+'wp-includes/js/swfupload/swfupload_f9.swf',
+'wp-includes/js/tinymce/plugins/autosave',
+'wp-includes/js/tinymce/plugins/paste/css',
+'wp-includes/js/tinymce/utils/mclayer.js',
+'wp-includes/js/tinymce/wordpress.css',
+// 2.8.5
+'wp-admin/import/btt.php',
+'wp-admin/import/jkw.php',
+// 2.9
+'wp-admin/js/page.dev.js',
+'wp-admin/js/page.js',
+'wp-admin/js/set-post-thumbnail-handler.dev.js',
+'wp-admin/js/set-post-thumbnail-handler.js',
+'wp-admin/js/slug.dev.js',
+'wp-admin/js/slug.js',
+'wp-includes/gettext.php',
+'wp-includes/js/tinymce/plugins/wordpress/js',
+'wp-includes/streams.php',
+// MU
+'README.txt',
+'htaccess.dist',
+'index-install.php',
+'wp-admin/css/mu-rtl.css',
+'wp-admin/css/mu.css',
+'wp-admin/images/site-admin.png',
+'wp-admin/includes/mu.php',
+'wp-admin/wpmu-admin.php',
+'wp-admin/wpmu-blogs.php',
+'wp-admin/wpmu-edit.php',
+'wp-admin/wpmu-options.php',
+'wp-admin/wpmu-themes.php',
+'wp-admin/wpmu-upgrade-site.php',
+'wp-admin/wpmu-users.php',
+'wp-includes/images/wordpress-mu.png',
+'wp-includes/wpmu-default-filters.php',
+'wp-includes/wpmu-functions.php',
+'wpmu-settings.php',
+// 3.0
+'wp-admin/categories.php',
+'wp-admin/edit-category-form.php',
+'wp-admin/edit-page-form.php',
+'wp-admin/edit-pages.php',
+'wp-admin/images/admin-header-footer.png',
+'wp-admin/images/browse-happy.gif',
+'wp-admin/images/ico-add.png',
+'wp-admin/images/ico-close.png',
+'wp-admin/images/ico-edit.png',
+'wp-admin/images/ico-viewpage.png',
+'wp-admin/images/fav-top.png',
+'wp-admin/images/screen-options-left.gif',
+'wp-admin/images/wp-logo-vs.gif',
+'wp-admin/images/wp-logo.gif',
+'wp-admin/import',
+'wp-admin/js/wp-gears.dev.js',
+'wp-admin/js/wp-gears.js',
+'wp-admin/options-misc.php',
+'wp-admin/page-new.php',
+'wp-admin/page.php',
+'wp-admin/rtl.css',
+'wp-admin/rtl.dev.css',
+'wp-admin/update-links.php',
+'wp-admin/wp-admin.css',
+'wp-admin/wp-admin.dev.css',
+'wp-includes/js/codepress',
+'wp-includes/js/codepress/engines/khtml.js',
+'wp-includes/js/codepress/engines/older.js',
+'wp-includes/js/jquery/autocomplete.dev.js',
+'wp-includes/js/jquery/autocomplete.js',
+'wp-includes/js/jquery/interface.js',
+'wp-includes/js/scriptaculous/prototype.js',
+'wp-includes/js/tinymce/wp-tinymce.js',
+// 3.1
+'wp-admin/edit-attachment-rows.php',
+'wp-admin/edit-link-categories.php',
+'wp-admin/edit-link-category-form.php',
+'wp-admin/edit-post-rows.php',
+'wp-admin/images/button-grad-active-vs.png',
+'wp-admin/images/button-grad-vs.png',
+'wp-admin/images/fav-arrow-vs-rtl.gif',
+'wp-admin/images/fav-arrow-vs.gif',
+'wp-admin/images/fav-top-vs.gif',
+'wp-admin/images/list-vs.png',
+'wp-admin/images/screen-options-right-up.gif',
+'wp-admin/images/screen-options-right.gif',
+'wp-admin/images/visit-site-button-grad-vs.gif',
+'wp-admin/images/visit-site-button-grad.gif',
+'wp-admin/link-category.php',
+'wp-admin/sidebar.php',
+'wp-includes/classes.php',
+'wp-includes/js/tinymce/blank.htm',
+'wp-includes/js/tinymce/plugins/media/css/content.css',
+'wp-includes/js/tinymce/plugins/media/img',
+'wp-includes/js/tinymce/plugins/safari',
+// 3.2
+'wp-admin/images/logo-login.gif',
+'wp-admin/images/star.gif',
+'wp-admin/js/list-table.dev.js',
+'wp-admin/js/list-table.js',
+'wp-includes/default-embeds.php',
+'wp-includes/js/tinymce/plugins/wordpress/img/help.gif',
+'wp-includes/js/tinymce/plugins/wordpress/img/more.gif',
+'wp-includes/js/tinymce/plugins/wordpress/img/toolbars.gif',
+'wp-includes/js/tinymce/themes/advanced/img/fm.gif',
+'wp-includes/js/tinymce/themes/advanced/img/sflogo.png',
+// 3.3
+'wp-admin/css/colors-classic-rtl.css',
+'wp-admin/css/colors-classic-rtl.dev.css',
+'wp-admin/css/colors-fresh-rtl.css',
+'wp-admin/css/colors-fresh-rtl.dev.css',
+'wp-admin/css/dashboard-rtl.css',
+'wp-admin/css/dashboard-rtl.dev.css',
+'wp-admin/css/dashboard.css',
+'wp-admin/css/dashboard.dev.css',
+'wp-admin/css/farbtastic-rtl.css',
+'wp-admin/css/global-rtl.css',
+'wp-admin/css/global-rtl.dev.css',
+'wp-admin/css/global.css',
+'wp-admin/css/global.dev.css',
+'wp-admin/css/install-rtl.css',
+'wp-admin/css/install-rtl.dev.css',
+'wp-admin/css/login-rtl.css',
+'wp-admin/css/login-rtl.dev.css',
+'wp-admin/css/login.css',
+'wp-admin/css/login.dev.css',
+'wp-admin/css/ms.css',
+'wp-admin/css/ms.dev.css',
+'wp-admin/css/nav-menu-rtl.css',
+'wp-admin/css/nav-menu-rtl.dev.css',
+'wp-admin/css/nav-menu.css',
+'wp-admin/css/nav-menu.dev.css',
+'wp-admin/css/plugin-install-rtl.css',
+'wp-admin/css/plugin-install-rtl.dev.css',
+'wp-admin/css/plugin-install.css',
+'wp-admin/css/plugin-install.dev.css',
+'wp-admin/css/press-this-rtl.css',
+'wp-admin/css/press-this-rtl.dev.css',
+'wp-admin/css/press-this.css',
+'wp-admin/css/press-this.dev.css',
+'wp-admin/css/theme-editor-rtl.css',
+'wp-admin/css/theme-editor-rtl.dev.css',
+'wp-admin/css/theme-editor.css',
+'wp-admin/css/theme-editor.dev.css',
+'wp-admin/css/theme-install-rtl.css',
+'wp-admin/css/theme-install-rtl.dev.css',
+'wp-admin/css/theme-install.css',
+'wp-admin/css/theme-install.dev.css',
+'wp-admin/css/widgets-rtl.css',
+'wp-admin/css/widgets-rtl.dev.css',
+'wp-admin/css/widgets.css',
+'wp-admin/css/widgets.dev.css',
+'wp-admin/includes/internal-linking.php',
+'wp-includes/images/admin-bar-sprite-rtl.png',
+'wp-includes/js/jquery/ui.button.js',
+'wp-includes/js/jquery/ui.core.js',
+'wp-includes/js/jquery/ui.dialog.js',
+'wp-includes/js/jquery/ui.draggable.js',
+'wp-includes/js/jquery/ui.droppable.js',
+'wp-includes/js/jquery/ui.mouse.js',
+'wp-includes/js/jquery/ui.position.js',
+'wp-includes/js/jquery/ui.resizable.js',
+'wp-includes/js/jquery/ui.selectable.js',
+'wp-includes/js/jquery/ui.sortable.js',
+'wp-includes/js/jquery/ui.tabs.js',
+'wp-includes/js/jquery/ui.widget.js',
+'wp-includes/js/l10n.dev.js',
+'wp-includes/js/l10n.js',
+'wp-includes/js/tinymce/plugins/wplink/css',
+'wp-includes/js/tinymce/plugins/wplink/img',
+'wp-includes/js/tinymce/plugins/wplink/js',
+'wp-includes/js/tinymce/themes/advanced/img/wpicons.png',
+'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/butt2.png',
+'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/button_bg.png',
+'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/down_arrow.gif',
+'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/fade-butt.png',
+'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/separator.gif',
+// Don't delete, yet: 'wp-rss.php',
+// Don't delete, yet: 'wp-rdf.php',
+// Don't delete, yet: 'wp-rss2.php',
+// Don't delete, yet: 'wp-commentsrss2.php',
+// Don't delete, yet: 'wp-atom.php',
+// Don't delete, yet: 'wp-feed.php',
+// 3.4
+'wp-admin/images/gray-star.png',
+'wp-admin/images/logo-login.png',
+'wp-admin/images/star.png',
+'wp-admin/index-extra.php',
+'wp-admin/network/index-extra.php',
+'wp-admin/user/index-extra.php',
+'wp-admin/images/screenshots/admin-flyouts.png',
+'wp-admin/images/screenshots/coediting.png',
+'wp-admin/images/screenshots/drag-and-drop.png',
+'wp-admin/images/screenshots/help-screen.png',
+'wp-admin/images/screenshots/media-icon.png',
+'wp-admin/images/screenshots/new-feature-pointer.png',
+'wp-admin/images/screenshots/welcome-screen.png',
+'wp-includes/css/editor-buttons.css',
+'wp-includes/css/editor-buttons.dev.css',
+'wp-includes/js/tinymce/plugins/paste/blank.htm',
+'wp-includes/js/tinymce/plugins/wordpress/css',
+'wp-includes/js/tinymce/plugins/wordpress/editor_plugin.dev.js',
+'wp-includes/js/tinymce/plugins/wordpress/img/embedded.png',
+'wp-includes/js/tinymce/plugins/wordpress/img/more_bug.gif',
+'wp-includes/js/tinymce/plugins/wordpress/img/page_bug.gif',
+'wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin.dev.js',
+'wp-includes/js/tinymce/plugins/wpeditimage/css/editimage-rtl.css',
+'wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin.dev.js',
+'wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin.dev.js',
+'wp-includes/js/tinymce/plugins/wpgallery/editor_plugin.dev.js',
+'wp-includes/js/tinymce/plugins/wpgallery/img/gallery.png',
+'wp-includes/js/tinymce/plugins/wplink/editor_plugin.dev.js',
+// Don't delete, yet: 'wp-pass.php',
+// Don't delete, yet: 'wp-register.php',
+// 3.5
+'wp-admin/gears-manifest.php',
+'wp-admin/includes/manifest.php',
+'wp-admin/images/archive-link.png',
+'wp-admin/images/blue-grad.png',
+'wp-admin/images/button-grad-active.png',
+'wp-admin/images/button-grad.png',
+'wp-admin/images/ed-bg-vs.gif',
+'wp-admin/images/ed-bg.gif',
+'wp-admin/images/fade-butt.png',
+'wp-admin/images/fav-arrow-rtl.gif',
+'wp-admin/images/fav-arrow.gif',
+'wp-admin/images/fav-vs.png',
+'wp-admin/images/fav.png',
+'wp-admin/images/gray-grad.png',
+'wp-admin/images/loading-publish.gif',
+'wp-admin/images/logo-ghost.png',
+'wp-admin/images/logo.gif',
+'wp-admin/images/menu-arrow-frame-rtl.png',
+'wp-admin/images/menu-arrow-frame.png',
+'wp-admin/images/menu-arrows.gif',
+'wp-admin/images/menu-bits-rtl-vs.gif',
+'wp-admin/images/menu-bits-rtl.gif',
+'wp-admin/images/menu-bits-vs.gif',
+'wp-admin/images/menu-bits.gif',
+'wp-admin/images/menu-dark-rtl-vs.gif',
+'wp-admin/images/menu-dark-rtl.gif',
+'wp-admin/images/menu-dark-vs.gif',
+'wp-admin/images/menu-dark.gif',
+'wp-admin/images/required.gif',
+'wp-admin/images/screen-options-toggle-vs.gif',
+'wp-admin/images/screen-options-toggle.gif',
+'wp-admin/images/toggle-arrow-rtl.gif',
+'wp-admin/images/toggle-arrow.gif',
+'wp-admin/images/upload-classic.png',
+'wp-admin/images/upload-fresh.png',
+'wp-admin/images/white-grad-active.png',
+'wp-admin/images/white-grad.png',
+'wp-admin/images/widgets-arrow-vs.gif',
+'wp-admin/images/widgets-arrow.gif',
+'wp-admin/images/wpspin_dark.gif',
+'wp-includes/images/upload.png',
+'wp-includes/js/prototype.js',
+'wp-includes/js/scriptaculous',
+'wp-admin/css/wp-admin-rtl.dev.css',
+'wp-admin/css/wp-admin.dev.css',
+'wp-admin/css/media-rtl.dev.css',
+'wp-admin/css/media.dev.css',
+'wp-admin/css/colors-classic.dev.css',
+'wp-admin/css/customize-controls-rtl.dev.css',
+'wp-admin/css/customize-controls.dev.css',
+'wp-admin/css/ie-rtl.dev.css',
+'wp-admin/css/ie.dev.css',
+'wp-admin/css/install.dev.css',
+'wp-admin/css/colors-fresh.dev.css',
+'wp-includes/js/customize-base.dev.js',
+'wp-includes/js/json2.dev.js',
+'wp-includes/js/comment-reply.dev.js',
+'wp-includes/js/customize-preview.dev.js',
+'wp-includes/js/wplink.dev.js',
+'wp-includes/js/tw-sack.dev.js',
+'wp-includes/js/wp-list-revisions.dev.js',
+'wp-includes/js/autosave.dev.js',
+'wp-includes/js/admin-bar.dev.js',
+'wp-includes/js/quicktags.dev.js',
+'wp-includes/js/wp-ajax-response.dev.js',
+'wp-includes/js/wp-pointer.dev.js',
+'wp-includes/js/hoverIntent.dev.js',
+'wp-includes/js/colorpicker.dev.js',
+'wp-includes/js/wp-lists.dev.js',
+'wp-includes/js/customize-loader.dev.js',
+'wp-includes/js/jquery/jquery.table-hotkeys.dev.js',
+'wp-includes/js/jquery/jquery.color.dev.js',
+'wp-includes/js/jquery/jquery.color.js',
+'wp-includes/js/jquery/jquery.hotkeys.dev.js',
+'wp-includes/js/jquery/jquery.form.dev.js',
+'wp-includes/js/jquery/suggest.dev.js',
+'wp-admin/js/xfn.dev.js',
+'wp-admin/js/set-post-thumbnail.dev.js',
+'wp-admin/js/comment.dev.js',
+'wp-admin/js/theme.dev.js',
+'wp-admin/js/cat.dev.js',
+'wp-admin/js/password-strength-meter.dev.js',
+'wp-admin/js/user-profile.dev.js',
+'wp-admin/js/theme-preview.dev.js',
+'wp-admin/js/post.dev.js',
+'wp-admin/js/media-upload.dev.js',
+'wp-admin/js/word-count.dev.js',
+'wp-admin/js/plugin-install.dev.js',
+'wp-admin/js/edit-comments.dev.js',
+'wp-admin/js/media-gallery.dev.js',
+'wp-admin/js/custom-fields.dev.js',
+'wp-admin/js/custom-background.dev.js',
+'wp-admin/js/common.dev.js',
+'wp-admin/js/inline-edit-tax.dev.js',
+'wp-admin/js/gallery.dev.js',
+'wp-admin/js/utils.dev.js',
+'wp-admin/js/widgets.dev.js',
+'wp-admin/js/wp-fullscreen.dev.js',
+'wp-admin/js/nav-menu.dev.js',
+'wp-admin/js/dashboard.dev.js',
+'wp-admin/js/link.dev.js',
+'wp-admin/js/user-suggest.dev.js',
+'wp-admin/js/postbox.dev.js',
+'wp-admin/js/tags.dev.js',
+'wp-admin/js/image-edit.dev.js',
+'wp-admin/js/media.dev.js',
+'wp-admin/js/customize-controls.dev.js',
+'wp-admin/js/inline-edit-post.dev.js',
+'wp-admin/js/categories.dev.js',
+'wp-admin/js/editor.dev.js',
+'wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.dev.js',
+'wp-includes/js/tinymce/plugins/wpdialogs/js/popup.dev.js',
+'wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog.dev.js',
+'wp-includes/js/plupload/handlers.dev.js',
+'wp-includes/js/plupload/wp-plupload.dev.js',
+'wp-includes/js/swfupload/handlers.dev.js',
+'wp-includes/js/jcrop/jquery.Jcrop.dev.js',
+'wp-includes/js/jcrop/jquery.Jcrop.js',
+'wp-includes/js/jcrop/jquery.Jcrop.css',
+'wp-includes/js/imgareaselect/jquery.imgareaselect.dev.js',
+'wp-includes/css/wp-pointer.dev.css',
+'wp-includes/css/editor.dev.css',
+'wp-includes/css/jquery-ui-dialog.dev.css',
+'wp-includes/css/admin-bar-rtl.dev.css',
+'wp-includes/css/admin-bar.dev.css',
+'wp-includes/js/jquery/ui/jquery.effects.clip.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.scale.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.blind.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.core.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.shake.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.fade.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.explode.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.slide.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.drop.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.highlight.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.bounce.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.pulsate.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.transfer.min.js',
+'wp-includes/js/jquery/ui/jquery.effects.fold.min.js',
+'wp-admin/images/screenshots/captions-1.png',
+'wp-admin/images/screenshots/captions-2.png',
+'wp-admin/images/screenshots/flex-header-1.png',
+'wp-admin/images/screenshots/flex-header-2.png',
+'wp-admin/images/screenshots/flex-header-3.png',
+'wp-admin/images/screenshots/flex-header-media-library.png',
+'wp-admin/images/screenshots/theme-customizer.png',
+'wp-admin/images/screenshots/twitter-embed-1.png',
+'wp-admin/images/screenshots/twitter-embed-2.png',
+'wp-admin/js/utils.js',
+'wp-admin/options-privacy.php',
+'wp-app.php',
+'wp-includes/class-wp-atom-server.php',
+'wp-includes/js/tinymce/themes/advanced/skins/wp_theme/ui.css',
+// 3.5.2
+'wp-includes/js/swfupload/swfupload-all.js',
+// 3.6
+'wp-admin/js/revisions-js.php',
+'wp-admin/images/screenshots',
+);
+
+/**
+ * Stores new files in wp-content to copy
+ *
+ * The contents of this array indicate any new bundled plugins/themes which
+ * should be installed with the WordPress Upgrade. These items will not be
+ * re-installed in future upgrades, this behaviour is controlled by the
+ * introduced version present here being older than the current installed version.
+ *
+ * The content of this array should follow the following format:
+ * Filename (relative to wp-content) => Introduced version
+ * Directories should be noted by suffixing it with a trailing slash (/)
+ *
+ * @since 3.2.0
+ * @global array $_new_bundled_files
+ * @var array
+ * @name $_new_bundled_files
+ */
+global $_new_bundled_files;
+
+$_new_bundled_files = array(
+ 'plugins/akismet/' => '2.0',
+ 'themes/twentyten/' => '3.0',
+ 'themes/twentyeleven/' => '3.2',
+ 'themes/twentytwelve/' => '3.5',
+ 'themes/twentythirteen/' => '3.6',
+);
+
+/**
+ * Upgrade the core of WordPress.
+ *
+ * This will create a .maintenance file at the base of the WordPress directory
+ * to ensure that people can not access the web site, when the files are being
+ * copied to their locations.
+ *
+ * The files in the {@link $_old_files} list will be removed and the new files
+ * copied from the zip file after the database is upgraded.
+ *
+ * The files in the {@link $_new_bundled_files} list will be added to the installation
+ * if the version is greater than or equal to the old version being upgraded.
+ *
+ * The steps for the upgrader for after the new release is downloaded and
+ * unzipped is:
+ * 1. Test unzipped location for select files to ensure that unzipped worked.
+ * 2. Create the .maintenance file in current WordPress base.
+ * 3. Copy new WordPress directory over old WordPress files.
+ * 4. Upgrade WordPress to new version.
+ * 4.1. Copy all files/folders other than wp-content
+ * 4.2. Copy any language files to WP_LANG_DIR (which may differ from WP_CONTENT_DIR
+ * 4.3. Copy any new bundled themes/plugins to their respective locations
+ * 5. Delete new WordPress directory path.
+ * 6. Delete .maintenance file.
+ * 7. Remove old files.
+ * 8. Delete 'update_core' option.
+ *
+ * There are several areas of failure. For instance if PHP times out before step
+ * 6, then you will not be able to access any portion of your site. Also, since
+ * the upgrade will not continue where it left off, you will not be able to
+ * automatically remove old files and remove the 'update_core' option. This
+ * isn't that bad.
+ *
+ * If the copy of the new WordPress over the old fails, then the worse is that
+ * the new WordPress directory will remain.
+ *
+ * If it is assumed that every file will be copied over, including plugins and
+ * themes, then if you edit the default theme, you should rename it, so that
+ * your changes remain.
+ *
+ * @since 2.7.0
+ *
+ * @param string $from New release unzipped path.
+ * @param string $to Path to old WordPress installation.
+ * @return WP_Error|null WP_Error on failure, null on success.
+ */
+function update_core($from, $to) {
+ global $wp_filesystem, $_old_files, $_new_bundled_files, $wpdb;
+
+ @set_time_limit( 300 );
+
+ // Sanity check the unzipped distribution
+ apply_filters( 'update_feedback', __('Verifying the unpacked files&#8230;') );
+ $distro = '';
+ $roots = array( '/wordpress/', '/wordpress-mu/' );
+ foreach ( $roots as $root ) {
+ if ( $wp_filesystem->exists( $from . $root . 'readme.html' ) && $wp_filesystem->exists( $from . $root . 'wp-includes/version.php' ) ) {
+ $distro = $root;
+ break;
+ }
+ }
+ if ( ! $distro ) {
+ $wp_filesystem->delete( $from, true );
+ return new WP_Error( 'insane_distro', __('The update could not be unpacked') );
+ }
+
+ // Import $wp_version, $required_php_version, and $required_mysql_version from the new version
+ // $wp_filesystem->wp_content_dir() returned unslashed pre-2.8
+ $versions_file = trailingslashit( $wp_filesystem->wp_content_dir() ) . 'upgrade/version-current.php';
+ if ( ! $wp_filesystem->copy( $from . $distro . 'wp-includes/version.php', $versions_file ) ) {
+ $wp_filesystem->delete( $from, true );
+ return new WP_Error( 'copy_failed', __('Could not copy file.') );
+ }
+
+ $wp_filesystem->chmod( $versions_file, FS_CHMOD_FILE );
+ require_once( WP_CONTENT_DIR . '/upgrade/version-current.php' );
+ $wp_filesystem->delete( $versions_file );
+
+ $php_version = phpversion();
+ $mysql_version = $wpdb->db_version();
+ $old_wp_version = $GLOBALS['wp_version']; // The version of WordPress we're updating from
+ $development_build = ( false !== strpos( $old_wp_version . $wp_version, '-' ) ); // a dash in the version indicates a Development release
+ $php_compat = version_compare( $php_version, $required_php_version, '>=' );
+ if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
+ $mysql_compat = true;
+ else
+ $mysql_compat = version_compare( $mysql_version, $required_mysql_version, '>=' );
+
+ if ( !$mysql_compat || !$php_compat )
+ $wp_filesystem->delete($from, true);
+
+ if ( !$mysql_compat && !$php_compat )
+ return new WP_Error( 'php_mysql_not_compatible', sprintf( __('The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.'), $wp_version, $required_php_version, $required_mysql_version, $php_version, $mysql_version ) );
+ elseif ( !$php_compat )
+ return new WP_Error( 'php_not_compatible', sprintf( __('The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher. You are running version %3$s.'), $wp_version, $required_php_version, $php_version ) );
+ elseif ( !$mysql_compat )
+ return new WP_Error( 'mysql_not_compatible', sprintf( __('The update cannot be installed because WordPress %1$s requires MySQL version %2$s or higher. You are running version %3$s.'), $wp_version, $required_mysql_version, $mysql_version ) );
+
+ apply_filters('update_feedback', __('Installing the latest version&#8230;'));
+
+ // Create maintenance file to signal that we are upgrading
+ $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
+ $maintenance_file = $to . '.maintenance';
+ $wp_filesystem->delete($maintenance_file);
+ $wp_filesystem->put_contents($maintenance_file, $maintenance_string, FS_CHMOD_FILE);
+
+ // Copy new versions of WP files into place.
+ $result = _copy_dir($from . $distro, $to, array('wp-content') );
+
+ // Custom Content Directory needs updating now.
+ // Copy Languages
+ if ( !is_wp_error($result) && $wp_filesystem->is_dir($from . $distro . 'wp-content/languages') ) {
+ if ( WP_LANG_DIR != ABSPATH . WPINC . '/languages' || @is_dir(WP_LANG_DIR) )
+ $lang_dir = WP_LANG_DIR;
+ else
+ $lang_dir = WP_CONTENT_DIR . '/languages';
+
+ if ( !@is_dir($lang_dir) && 0 === strpos($lang_dir, ABSPATH) ) { // Check the language directory exists first
+ $wp_filesystem->mkdir($to . str_replace(ABSPATH, '', $lang_dir), FS_CHMOD_DIR); // If it's within the ABSPATH we can handle it here, otherwise they're out of luck.
+ clearstatcache(); // for FTP, Need to clear the stat cache
+ }
+
+ if ( @is_dir($lang_dir) ) {
+ $wp_lang_dir = $wp_filesystem->find_folder($lang_dir);
+ if ( $wp_lang_dir )
+ $result = copy_dir($from . $distro . 'wp-content/languages/', $wp_lang_dir);
+ }
+ }
+
+ // 3.5 -> 3.5+ - an empty twentytwelve directory was created upon upgrade to 3.5 for some users, preventing installation of Twenty Twelve.
+ if ( '3.5' == $old_wp_version ) {
+ if ( is_dir( WP_CONTENT_DIR . '/themes/twentytwelve' ) && ! file_exists( WP_CONTENT_DIR . '/themes/twentytwelve/style.css' ) ) {
+ $wp_filesystem->delete( $wp_filesystem->wp_themes_dir() . 'twentytwelve/' );
+ }
+ }
+
+ // Copy New bundled plugins & themes
+ // This gives us the ability to install new plugins & themes bundled with future versions of WordPress whilst avoiding the re-install upon upgrade issue.
+ // $development_build controls us overwriting bundled themes and plugins when a non-stable release is being updated
+ if ( !is_wp_error($result) && ( ! defined('CORE_UPGRADE_SKIP_NEW_BUNDLED') || ! CORE_UPGRADE_SKIP_NEW_BUNDLED ) ) {
+ foreach ( (array) $_new_bundled_files as $file => $introduced_version ) {
+ // If a $development_build or if $introduced version is greater than what the site was previously running
+ if ( $development_build || version_compare( $introduced_version, $old_wp_version, '>' ) ) {
+ $directory = ('/' == $file[ strlen($file)-1 ]);
+ list($type, $filename) = explode('/', $file, 2);
+
+ // Check to see if the bundled items exist before attempting to copy them
+ if ( ! $wp_filesystem->exists( $from . $distro . 'wp-content/' . $file ) )
+ continue;
+
+ if ( 'plugins' == $type )
+ $dest = $wp_filesystem->wp_plugins_dir();
+ elseif ( 'themes' == $type )
+ $dest = trailingslashit($wp_filesystem->wp_themes_dir()); // Back-compat, ::wp_themes_dir() did not return trailingslash'd pre-3.2
+ else
+ continue;
+
+ if ( ! $directory ) {
+ if ( ! $development_build && $wp_filesystem->exists( $dest . $filename ) )
+ continue;
+
+ if ( ! $wp_filesystem->copy($from . $distro . 'wp-content/' . $file, $dest . $filename, FS_CHMOD_FILE) )
+ $result = new WP_Error('copy_failed', __('Could not copy file.'), $dest . $filename);
+ } else {
+ if ( ! $development_build && $wp_filesystem->is_dir( $dest . $filename ) )
+ continue;
+
+ $wp_filesystem->mkdir($dest . $filename, FS_CHMOD_DIR);
+ $_result = copy_dir( $from . $distro . 'wp-content/' . $file, $dest . $filename);
+ if ( is_wp_error($_result) ) //If a error occurs partway through this final step, keep the error flowing through, but keep process going.
+ $result = $_result;
+ }
+ }
+ } //end foreach
+ }
+
+ // Handle $result error from the above blocks
+ if ( is_wp_error($result) ) {
+ $wp_filesystem->delete($maintenance_file);
+ $wp_filesystem->delete($from, true);
+ return $result;
+ }
+
+ // Remove old files
+ foreach ( $_old_files as $old_file ) {
+ $old_file = $to . $old_file;
+ if ( !$wp_filesystem->exists($old_file) )
+ continue;
+ $wp_filesystem->delete($old_file, true);
+ }
+
+ // Upgrade DB with separate request
+ apply_filters('update_feedback', __('Upgrading database&#8230;'));
+ $db_upgrade_url = admin_url('upgrade.php?step=upgrade_db');
+ wp_remote_post($db_upgrade_url, array('timeout' => 60));
+
+ // Remove working directory
+ $wp_filesystem->delete($from, true);
+
+ // Force refresh of update information
+ if ( function_exists('delete_site_transient') )
+ delete_site_transient('update_core');
+ else
+ delete_option('update_core');
+
+ // Remove maintenance file, we're done.
+ $wp_filesystem->delete($maintenance_file);
+
+ // If we made it this far:
+ do_action( '_core_updated_successfully', $wp_version );
+
+ return $wp_version;
+}
+
+/**
+ * Copies a directory from one location to another via the WordPress Filesystem Abstraction.
+ * Assumes that WP_Filesystem() has already been called and setup.
+ *
+ * This is a temporary function for the 3.1 -> 3.2 upgrade only and will be removed in 3.3
+ *
+ * @ignore
+ * @since 3.2.0
+ * @see copy_dir()
+ *
+ * @param string $from source directory
+ * @param string $to destination directory
+ * @param array $skip_list a list of files/folders to skip copying
+ * @return mixed WP_Error on failure, True on success.
+ */
+function _copy_dir($from, $to, $skip_list = array() ) {
+ global $wp_filesystem;
+
+ $dirlist = $wp_filesystem->dirlist($from);
+
+ $from = trailingslashit($from);
+ $to = trailingslashit($to);
+
+ $skip_regex = '';
+ foreach ( (array)$skip_list as $key => $skip_file )
+ $skip_regex .= preg_quote($skip_file, '!') . '|';
+
+ if ( !empty($skip_regex) )
+ $skip_regex = '!(' . rtrim($skip_regex, '|') . ')$!i';
+
+ foreach ( (array) $dirlist as $filename => $fileinfo ) {
+ if ( !empty($skip_regex) )
+ if ( preg_match($skip_regex, $from . $filename) )
+ continue;
+
+ if ( 'f' == $fileinfo['type'] ) {
+ if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE) ) {
+ // If copy failed, chmod file to 0644 and try again.
+ $wp_filesystem->chmod($to . $filename, 0644);
+ if ( ! $wp_filesystem->copy($from . $filename, $to . $filename, true, FS_CHMOD_FILE) )
+ return new WP_Error('copy_failed', __('Could not copy file.'), $to . $filename);
+ }
+ } elseif ( 'd' == $fileinfo['type'] ) {
+ if ( !$wp_filesystem->is_dir($to . $filename) ) {
+ if ( !$wp_filesystem->mkdir($to . $filename, FS_CHMOD_DIR) )
+ return new WP_Error('mkdir_failed', __('Could not create directory.'), $to . $filename);
+ }
+ $result = _copy_dir($from . $filename, $to . $filename, $skip_list);
+ if ( is_wp_error($result) )
+ return $result;
+ }
+ }
+ return true;
+}
+
+/**
+ * Redirect to the About WordPress page after a successful upgrade.
+ *
+ * This function is only needed when the existing install is older than 3.4.0.
+ *
+ * @since 3.3.0
+ *
+ */
+function _redirect_to_about_wordpress( $new_version ) {
+ global $wp_version, $pagenow, $action;
+
+ if ( version_compare( $wp_version, '3.4-RC1', '>=' ) )
+ return;
+
+ // Ensure we only run this on the update-core.php page. wp_update_core() could be called in other contexts.
+ if ( 'update-core.php' != $pagenow )
+ return;
+
+ if ( 'do-core-upgrade' != $action && 'do-core-reinstall' != $action )
+ return;
+
+ // Load the updated default text localization domain for new strings
+ load_default_textdomain();
+
+ // See do_core_upgrade()
+ show_message( __('WordPress updated successfully') );
+
+ // self_admin_url() won't exist when upgrading from <= 3.0, so relative URLs are intentional.
+ show_message( '<span class="hide-if-no-js">' . sprintf( __( 'Welcome to WordPress %1$s. You will be redirected to the About WordPress screen. If not, click <a href="%2$s">here</a>.' ), $new_version, 'about.php?updated' ) . '</span>' );
+ show_message( '<span class="hide-if-js">' . sprintf( __( 'Welcome to WordPress %1$s. <a href="%2$s">Learn more</a>.' ), $new_version, 'about.php?updated' ) . '</span>' );
+ echo '</div>';
+ ?>
+<script type="text/javascript">
+window.location = 'about.php?updated';
+</script>
+ <?php
+
+ // Include admin-footer.php and exit
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+ exit();
+}
+add_action( '_core_updated_successfully', '_redirect_to_about_wordpress' );
diff --git a/src/wp-admin/includes/update.php b/src/wp-admin/includes/update.php
new file mode 100644
index 0000000000..5cca9dca6b
--- /dev/null
+++ b/src/wp-admin/includes/update.php
@@ -0,0 +1,310 @@
+<?php
+/**
+ * WordPress Administration Update API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// The admin side of our 1.1 update system
+
+/**
+ * Selects the first update version from the update_core option
+ *
+ * @return object the response from the API
+ */
+function get_preferred_from_update_core() {
+ $updates = get_core_updates();
+ if ( !is_array( $updates ) )
+ return false;
+ if ( empty( $updates ) )
+ return (object)array('response' => 'latest');
+ return $updates[0];
+}
+
+/**
+ * Get available core updates
+ *
+ * @param array $options Set $options['dismissed'] to true to show dismissed upgrades too,
+ * set $options['available'] to false to skip not-dismissed updates.
+ * @return array Array of the update objects
+ */
+function get_core_updates( $options = array() ) {
+ $options = array_merge( array('available' => true, 'dismissed' => false ), $options );
+ $dismissed = get_site_option( 'dismissed_update_core' );
+ if ( !is_array( $dismissed ) ) $dismissed = array();
+ $from_api = get_site_transient( 'update_core' );
+ if ( empty($from_api) )
+ return false;
+ if ( !isset( $from_api->updates ) || !is_array( $from_api->updates ) ) return false;
+ $updates = $from_api->updates;
+ if ( !is_array( $updates ) ) return false;
+ $result = array();
+ foreach($updates as $update) {
+ if ( array_key_exists( $update->current.'|'.$update->locale, $dismissed ) ) {
+ if ( $options['dismissed'] ) {
+ $update->dismissed = true;
+ $result[]= $update;
+ }
+ } else {
+ if ( $options['available'] ) {
+ $update->dismissed = false;
+ $result[]= $update;
+ }
+ }
+ }
+ return $result;
+}
+
+function dismiss_core_update( $update ) {
+ $dismissed = get_site_option( 'dismissed_update_core' );
+ $dismissed[ $update->current.'|'.$update->locale ] = true;
+ return update_site_option( 'dismissed_update_core', $dismissed );
+}
+
+function undismiss_core_update( $version, $locale ) {
+ $dismissed = get_site_option( 'dismissed_update_core' );
+ $key = $version.'|'.$locale;
+ if ( !isset( $dismissed[$key] ) ) return false;
+ unset( $dismissed[$key] );
+ return update_site_option( 'dismissed_update_core', $dismissed );
+}
+
+function find_core_update( $version, $locale ) {
+ $from_api = get_site_transient( 'update_core' );
+ if ( !is_array( $from_api->updates ) ) return false;
+ $updates = $from_api->updates;
+ foreach($updates as $update) {
+ if ( $update->current == $version && $update->locale == $locale )
+ return $update;
+ }
+ return false;
+}
+
+function core_update_footer( $msg = '' ) {
+ if ( !current_user_can('update_core') )
+ return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) );
+
+ $cur = get_preferred_from_update_core();
+ if ( ! is_object( $cur ) )
+ $cur = new stdClass;
+
+ if ( ! isset( $cur->current ) )
+ $cur->current = '';
+
+ if ( ! isset( $cur->url ) )
+ $cur->url = '';
+
+ if ( ! isset( $cur->response ) )
+ $cur->response = '';
+
+ switch ( $cur->response ) {
+ case 'development' :
+ return sprintf( __( 'You are using a development version (%1$s). Cool! Please <a href="%2$s">stay updated</a>.' ), get_bloginfo( 'version', 'display' ), network_admin_url( 'update-core.php' ) );
+ break;
+
+ case 'upgrade' :
+ return sprintf( '<strong>'.__( '<a href="%1$s">Get Version %2$s</a>' ).'</strong>', network_admin_url( 'update-core.php' ), $cur->current);
+ break;
+
+ case 'latest' :
+ default :
+ return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) );
+ break;
+ }
+}
+add_filter( 'update_footer', 'core_update_footer' );
+
+function update_nag() {
+ if ( is_multisite() && !current_user_can('update_core') )
+ return false;
+
+ global $pagenow;
+
+ if ( 'update-core.php' == $pagenow )
+ return;
+
+ $cur = get_preferred_from_update_core();
+
+ if ( ! isset( $cur->response ) || $cur->response != 'upgrade' )
+ return false;
+
+ if ( current_user_can('update_core') ) {
+ $msg = sprintf( __('<a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> is available! <a href="%2$s">Please update now</a>.'), $cur->current, network_admin_url( 'update-core.php' ) );
+ } else {
+ $msg = sprintf( __('<a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> is available! Please notify the site administrator.'), $cur->current );
+ }
+ echo "<div class='update-nag'>$msg</div>";
+}
+add_action( 'admin_notices', 'update_nag', 3 );
+add_action( 'network_admin_notices', 'update_nag', 3 );
+
+// Called directly from dashboard
+function update_right_now_message() {
+ $msg = sprintf( __( 'You are using <span class="b">WordPress %s</span>.' ), get_bloginfo( 'version', 'display' ) );
+
+ if ( current_user_can('update_core') ) {
+ $cur = get_preferred_from_update_core();
+
+ if ( isset( $cur->response ) && $cur->response == 'upgrade' )
+ $msg .= " <a href='" . network_admin_url( 'update-core.php' ) . "' class='button'>" . sprintf( __('Update to %s'), $cur->current ? $cur->current : __( 'Latest' ) ) . '</a>';
+ }
+
+ echo "<span id='wp-version-message'>$msg</span>";
+}
+
+function get_plugin_updates() {
+ $all_plugins = get_plugins();
+ $upgrade_plugins = array();
+ $current = get_site_transient( 'update_plugins' );
+ foreach ( (array)$all_plugins as $plugin_file => $plugin_data) {
+ if ( isset( $current->response[ $plugin_file ] ) ) {
+ $upgrade_plugins[ $plugin_file ] = (object) $plugin_data;
+ $upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ];
+ }
+ }
+
+ return $upgrade_plugins;
+}
+
+function wp_plugin_update_rows() {
+ if ( !current_user_can('update_plugins' ) )
+ return;
+
+ $plugins = get_site_transient( 'update_plugins' );
+ if ( isset($plugins->response) && is_array($plugins->response) ) {
+ $plugins = array_keys( $plugins->response );
+ foreach( $plugins as $plugin_file ) {
+ add_action( "after_plugin_row_$plugin_file", 'wp_plugin_update_row', 10, 2 );
+ }
+ }
+}
+add_action( 'admin_init', 'wp_plugin_update_rows' );
+
+function wp_plugin_update_row( $file, $plugin_data ) {
+ $current = get_site_transient( 'update_plugins' );
+ if ( !isset( $current->response[ $file ] ) )
+ return false;
+
+ $r = $current->response[ $file ];
+
+ $plugins_allowedtags = array('a' => array('href' => array(),'title' => array()),'abbr' => array('title' => array()),'acronym' => array('title' => array()),'code' => array(),'em' => array(),'strong' => array());
+ $plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags );
+
+ $details_url = self_admin_url('plugin-install.php?tab=plugin-information&plugin=' . $r->slug . '&section=changelog&TB_iframe=true&width=600&height=800');
+
+ $wp_list_table = _get_list_table('WP_Plugins_List_Table');
+
+ if ( is_network_admin() || !is_multisite() ) {
+ echo '<tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
+
+ if ( ! current_user_can('update_plugins') )
+ printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>.'), $plugin_name, esc_url($details_url), esc_attr($plugin_name), $r->new_version );
+ else if ( empty($r->package) )
+ printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>'), $plugin_name, esc_url($details_url), esc_attr($plugin_name), $r->new_version );
+ else
+ printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a> or <a href="%5$s">update now</a>.'), $plugin_name, esc_url($details_url), esc_attr($plugin_name), $r->new_version, wp_nonce_url( self_admin_url('update.php?action=upgrade-plugin&plugin=') . $file, 'upgrade-plugin_' . $file) );
+
+ do_action( "in_plugin_update_message-$file", $plugin_data, $r );
+
+ echo '</div></td></tr>';
+ }
+}
+
+function wp_update_plugin($plugin, $feedback = '') {
+ if ( !empty($feedback) )
+ add_filter('update_feedback', $feedback);
+
+ include ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ $upgrader = new Plugin_Upgrader();
+ return $upgrader->upgrade($plugin);
+}
+
+function get_theme_updates() {
+ $themes = wp_get_themes();
+ $current = get_site_transient('update_themes');
+
+ if ( ! isset( $current->response ) )
+ return array();
+
+ $update_themes = array();
+ foreach ( $current->response as $stylesheet => $data ) {
+ $update_themes[ $stylesheet ] = wp_get_theme( $stylesheet );
+ $update_themes[ $stylesheet ]->update = $data;
+ }
+
+ return $update_themes;
+}
+
+function wp_update_theme($theme, $feedback = '') {
+ if ( !empty($feedback) )
+ add_filter('update_feedback', $feedback);
+
+ include ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ $upgrader = new Theme_Upgrader();
+ return $upgrader->upgrade($theme);
+}
+
+function wp_theme_update_rows() {
+ if ( !current_user_can('update_themes' ) )
+ return;
+
+ $themes = get_site_transient( 'update_themes' );
+ if ( isset($themes->response) && is_array($themes->response) ) {
+ $themes = array_keys( $themes->response );
+
+ foreach( $themes as $theme ) {
+ add_action( "after_theme_row_$theme", 'wp_theme_update_row', 10, 2 );
+ }
+ }
+}
+add_action( 'admin_init', 'wp_theme_update_rows' );
+
+function wp_theme_update_row( $theme_key, $theme ) {
+ $current = get_site_transient( 'update_themes' );
+ if ( !isset( $current->response[ $theme_key ] ) )
+ return false;
+ $r = $current->response[ $theme_key ];
+ $themes_allowedtags = array('a' => array('href' => array(),'title' => array()),'abbr' => array('title' => array()),'acronym' => array('title' => array()),'code' => array(),'em' => array(),'strong' => array());
+ $theme_name = wp_kses( $theme['Name'], $themes_allowedtags );
+
+ $details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 1024, 'height' => 800 ), $current->response[ $theme_key ]['url'] );
+
+ $wp_list_table = _get_list_table('WP_MS_Themes_List_Table');
+
+ echo '<tr class="plugin-update-tr"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
+ if ( ! current_user_can('update_themes') )
+ printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>.'), $theme['Name'], esc_url($details_url), esc_attr($theme['Name']), $r->new_version );
+ else if ( empty( $r['package'] ) )
+ printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>'), $theme['Name'], esc_url($details_url), esc_attr($theme['Name']), $r['new_version'] );
+ else
+ printf( __('There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%3$s">View version %4$s details</a> or <a href="%5$s">update now</a>.'), $theme['Name'], esc_url($details_url), esc_attr($theme['Name']), $r['new_version'], wp_nonce_url( self_admin_url('update.php?action=upgrade-theme&theme=') . $theme_key, 'upgrade-theme_' . $theme_key) );
+
+ do_action( "in_theme_update_message-$theme_key", $theme, $r );
+
+ echo '</div></td></tr>';
+}
+
+function wp_update_core($current, $feedback = '') {
+ if ( !empty($feedback) )
+ add_filter('update_feedback', $feedback);
+
+ include ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ $upgrader = new Core_Upgrader();
+ return $upgrader->upgrade($current);
+
+}
+
+function maintenance_nag() {
+ global $upgrading;
+ if ( ! isset( $upgrading ) )
+ return false;
+
+ if ( current_user_can('update_core') )
+ $msg = sprintf( __('An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.'), 'update-core.php' );
+ else
+ $msg = __('An automated WordPress update has failed to complete! Please notify the site administrator.');
+
+ echo "<div class='update-nag'>$msg</div>";
+}
+add_action( 'admin_notices', 'maintenance_nag' );
diff --git a/src/wp-admin/includes/upgrade.php b/src/wp-admin/includes/upgrade.php
new file mode 100644
index 0000000000..0d17d8fce4
--- /dev/null
+++ b/src/wp-admin/includes/upgrade.php
@@ -0,0 +1,2006 @@
+<?php
+/**
+ * WordPress Upgrade API
+ *
+ * Most of the functions are pluggable and can be overwritten
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Include user install customize script. */
+if ( file_exists(WP_CONTENT_DIR . '/install.php') )
+ require (WP_CONTENT_DIR . '/install.php');
+
+/** WordPress Administration API */
+require_once(ABSPATH . 'wp-admin/includes/admin.php');
+
+/** WordPress Schema API */
+require_once(ABSPATH . 'wp-admin/includes/schema.php');
+
+if ( !function_exists('wp_install') ) :
+/**
+ * Installs the blog
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ *
+ * @param string $blog_title Blog title.
+ * @param string $user_name User's username.
+ * @param string $user_email User's email.
+ * @param bool $public Whether blog is public.
+ * @param null $deprecated Optional. Not used.
+ * @param string $user_password Optional. User's chosen password. Will default to a random password.
+ * @return array Array keys 'url', 'user_id', 'password', 'password_message'.
+ */
+function wp_install( $blog_title, $user_name, $user_email, $public, $deprecated = '', $user_password = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.6' );
+
+ wp_check_mysql_version();
+ wp_cache_flush();
+ make_db_current_silent();
+ populate_options();
+ populate_roles();
+
+ update_option('blogname', $blog_title);
+ update_option('admin_email', $user_email);
+ update_option('blog_public', $public);
+
+ $guessurl = wp_guess_url();
+
+ update_option('siteurl', $guessurl);
+
+ // If not a public blog, don't ping.
+ if ( ! $public )
+ update_option('default_pingback_flag', 0);
+
+ // Create default user. If the user already exists, the user tables are
+ // being shared among blogs. Just set the role in that case.
+ $user_id = username_exists($user_name);
+ $user_password = trim($user_password);
+ $email_password = false;
+ if ( !$user_id && empty($user_password) ) {
+ $user_password = wp_generate_password( 12, false );
+ $message = __('<strong><em>Note that password</em></strong> carefully! It is a <em>random</em> password that was generated just for you.');
+ $user_id = wp_create_user($user_name, $user_password, $user_email);
+ update_user_option($user_id, 'default_password_nag', true, true);
+ $email_password = true;
+ } else if ( !$user_id ) {
+ // Password has been provided
+ $message = '<em>'.__('Your chosen password.').'</em>';
+ $user_id = wp_create_user($user_name, $user_password, $user_email);
+ } else {
+ $message = __('User already exists. Password inherited.');
+ }
+
+ $user = new WP_User($user_id);
+ $user->set_role('administrator');
+
+ wp_install_defaults($user_id);
+
+ flush_rewrite_rules();
+
+ wp_new_blog_notification($blog_title, $guessurl, $user_id, ($email_password ? $user_password : __('The password you chose during the install.') ) );
+
+ wp_cache_flush();
+
+ return array('url' => $guessurl, 'user_id' => $user_id, 'password' => $user_password, 'password_message' => $message);
+}
+endif;
+
+if ( !function_exists('wp_install_defaults') ) :
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ *
+ * @param int $user_id User ID.
+ */
+function wp_install_defaults($user_id) {
+ global $wpdb, $wp_rewrite, $current_site, $table_prefix;
+
+ // Default category
+ $cat_name = __('Uncategorized');
+ /* translators: Default category slug */
+ $cat_slug = sanitize_title(_x('Uncategorized', 'Default category slug'));
+
+ if ( global_terms_enabled() ) {
+ $cat_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM {$wpdb->sitecategories} WHERE category_nicename = %s", $cat_slug ) );
+ if ( $cat_id == null ) {
+ $wpdb->insert( $wpdb->sitecategories, array('cat_ID' => 0, 'cat_name' => $cat_name, 'category_nicename' => $cat_slug, 'last_updated' => current_time('mysql', true)) );
+ $cat_id = $wpdb->insert_id;
+ }
+ update_option('default_category', $cat_id);
+ } else {
+ $cat_id = 1;
+ }
+
+ $wpdb->insert( $wpdb->terms, array('term_id' => $cat_id, 'name' => $cat_name, 'slug' => $cat_slug, 'term_group' => 0) );
+ $wpdb->insert( $wpdb->term_taxonomy, array('term_id' => $cat_id, 'taxonomy' => 'category', 'description' => '', 'parent' => 0, 'count' => 1));
+ $cat_tt_id = $wpdb->insert_id;
+
+ // First post
+ $now = date('Y-m-d H:i:s');
+ $now_gmt = gmdate('Y-m-d H:i:s');
+ $first_post_guid = get_option('home') . '/?p=1';
+
+ if ( is_multisite() ) {
+ $first_post = get_site_option( 'first_post' );
+
+ if ( empty($first_post) )
+ $first_post = __( 'Welcome to <a href="SITE_URL">SITE_NAME</a>. This is your first post. Edit or delete it, then start blogging!' );
+
+ $first_post = str_replace( "SITE_URL", esc_url( network_home_url() ), $first_post );
+ $first_post = str_replace( "SITE_NAME", $current_site->site_name, $first_post );
+ } else {
+ $first_post = __('Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!');
+ }
+
+ $wpdb->insert( $wpdb->posts, array(
+ 'post_author' => $user_id,
+ 'post_date' => $now,
+ 'post_date_gmt' => $now_gmt,
+ 'post_content' => $first_post,
+ 'post_excerpt' => '',
+ 'post_title' => __('Hello world!'),
+ /* translators: Default post slug */
+ 'post_name' => sanitize_title( _x('hello-world', 'Default post slug') ),
+ 'post_modified' => $now,
+ 'post_modified_gmt' => $now_gmt,
+ 'guid' => $first_post_guid,
+ 'comment_count' => 1,
+ 'to_ping' => '',
+ 'pinged' => '',
+ 'post_content_filtered' => ''
+ ));
+ $wpdb->insert( $wpdb->term_relationships, array('term_taxonomy_id' => $cat_tt_id, 'object_id' => 1) );
+
+ // Default comment
+ $first_comment_author = __('Mr WordPress');
+ $first_comment_url = 'http://wordpress.org/';
+ $first_comment = __('Hi, this is a comment.
+To delete a comment, just log in and view the post&#039;s comments. There you will have the option to edit or delete them.');
+ if ( is_multisite() ) {
+ $first_comment_author = get_site_option( 'first_comment_author', $first_comment_author );
+ $first_comment_url = get_site_option( 'first_comment_url', network_home_url() );
+ $first_comment = get_site_option( 'first_comment', $first_comment );
+ }
+ $wpdb->insert( $wpdb->comments, array(
+ 'comment_post_ID' => 1,
+ 'comment_author' => $first_comment_author,
+ 'comment_author_email' => '',
+ 'comment_author_url' => $first_comment_url,
+ 'comment_date' => $now,
+ 'comment_date_gmt' => $now_gmt,
+ 'comment_content' => $first_comment
+ ));
+
+ // First Page
+ $first_page = sprintf( __( "This is an example page. It's different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:
+
+<blockquote>Hi there! I'm a bike messenger by day, aspiring actor by night, and this is my blog. I live in Los Angeles, have a great dog named Jack, and I like pi&#241;a coladas. (And gettin' caught in the rain.)</blockquote>
+
+...or something like this:
+
+<blockquote>The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.</blockquote>
+
+As a new WordPress user, you should go to <a href=\"%s\">your dashboard</a> to delete this page and create new pages for your content. Have fun!" ), admin_url() );
+ if ( is_multisite() )
+ $first_page = get_site_option( 'first_page', $first_page );
+ $first_post_guid = get_option('home') . '/?page_id=2';
+ $wpdb->insert( $wpdb->posts, array(
+ 'post_author' => $user_id,
+ 'post_date' => $now,
+ 'post_date_gmt' => $now_gmt,
+ 'post_content' => $first_page,
+ 'post_excerpt' => '',
+ 'post_title' => __( 'Sample Page' ),
+ /* translators: Default page slug */
+ 'post_name' => __( 'sample-page' ),
+ 'post_modified' => $now,
+ 'post_modified_gmt' => $now_gmt,
+ 'guid' => $first_post_guid,
+ 'post_type' => 'page',
+ 'to_ping' => '',
+ 'pinged' => '',
+ 'post_content_filtered' => ''
+ ));
+ $wpdb->insert( $wpdb->postmeta, array( 'post_id' => 2, 'meta_key' => '_wp_page_template', 'meta_value' => 'default' ) );
+
+ // Set up default widgets for default theme.
+ update_option( 'widget_search', array ( 2 => array ( 'title' => '' ), '_multiwidget' => 1 ) );
+ update_option( 'widget_recent-posts', array ( 2 => array ( 'title' => '', 'number' => 5 ), '_multiwidget' => 1 ) );
+ update_option( 'widget_recent-comments', array ( 2 => array ( 'title' => '', 'number' => 5 ), '_multiwidget' => 1 ) );
+ update_option( 'widget_archives', array ( 2 => array ( 'title' => '', 'count' => 0, 'dropdown' => 0 ), '_multiwidget' => 1 ) );
+ update_option( 'widget_categories', array ( 2 => array ( 'title' => '', 'count' => 0, 'hierarchical' => 0, 'dropdown' => 0 ), '_multiwidget' => 1 ) );
+ update_option( 'widget_meta', array ( 2 => array ( 'title' => '' ), '_multiwidget' => 1 ) );
+ update_option( 'sidebars_widgets', array ( 'wp_inactive_widgets' => array (), 'sidebar-1' => array ( 0 => 'search-2', 1 => 'recent-posts-2', 2 => 'recent-comments-2', 3 => 'archives-2', 4 => 'categories-2', 5 => 'meta-2', ), 'sidebar-2' => array (),'array_version' => 3 ) );
+
+ if ( ! is_multisite() )
+ update_user_meta( $user_id, 'show_welcome_panel', 1 );
+ elseif ( ! is_super_admin( $user_id ) && ! metadata_exists( 'user', $user_id, 'show_welcome_panel' ) )
+ update_user_meta( $user_id, 'show_welcome_panel', 2 );
+
+ if ( is_multisite() ) {
+ // Flush rules to pick up the new page.
+ $wp_rewrite->init();
+ $wp_rewrite->flush_rules();
+
+ $user = new WP_User($user_id);
+ $wpdb->update( $wpdb->options, array('option_value' => $user->user_email), array('option_name' => 'admin_email') );
+
+ // Remove all perms except for the login user.
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix.'user_level') );
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix.'capabilities') );
+
+ // Delete any caps that snuck into the previously active blog. (Hardcoded to blog 1 for now.) TODO: Get previous_blog_id.
+ if ( !is_super_admin( $user_id ) && $user_id != 1 )
+ $wpdb->delete( $wpdb->usermeta, array( 'user_id' => $user_id , 'meta_key' => $wpdb->base_prefix.'1_capabilities' ) );
+ }
+}
+endif;
+
+if ( !function_exists('wp_new_blog_notification') ) :
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ *
+ * @param string $blog_title Blog title.
+ * @param string $blog_url Blog url.
+ * @param int $user_id User ID.
+ * @param string $password User's Password.
+ */
+function wp_new_blog_notification($blog_title, $blog_url, $user_id, $password) {
+ $user = new WP_User( $user_id );
+ $email = $user->user_email;
+ $name = $user->user_login;
+ $message = sprintf(__("Your new WordPress site has been successfully set up at:
+
+%1\$s
+
+You can log in to the administrator account with the following information:
+
+Username: %2\$s
+Password: %3\$s
+
+We hope you enjoy your new site. Thanks!
+
+--The WordPress Team
+http://wordpress.org/
+"), $blog_url, $name, $password);
+
+ @wp_mail($email, __('New WordPress Site'), $message);
+}
+endif;
+
+if ( !function_exists('wp_upgrade') ) :
+/**
+ * Run WordPress Upgrade functions.
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ *
+ * @return null
+ */
+function wp_upgrade() {
+ global $wp_current_db_version, $wp_db_version, $wpdb;
+
+ $wp_current_db_version = __get_option('db_version');
+
+ // We are up-to-date. Nothing to do.
+ if ( $wp_db_version == $wp_current_db_version )
+ return;
+
+ if ( ! is_blog_installed() )
+ return;
+
+ wp_check_mysql_version();
+ wp_cache_flush();
+ pre_schema_upgrade();
+ make_db_current_silent();
+ upgrade_all();
+ if ( is_multisite() && is_main_site() )
+ upgrade_network();
+ wp_cache_flush();
+
+ if ( is_multisite() ) {
+ if ( $wpdb->get_row( "SELECT blog_id FROM {$wpdb->blog_versions} WHERE blog_id = '{$wpdb->blogid}'" ) )
+ $wpdb->query( "UPDATE {$wpdb->blog_versions} SET db_version = '{$wp_db_version}' WHERE blog_id = '{$wpdb->blogid}'" );
+ else
+ $wpdb->query( "INSERT INTO {$wpdb->blog_versions} ( `blog_id` , `db_version` , `last_updated` ) VALUES ( '{$wpdb->blogid}', '{$wp_db_version}', NOW());" );
+ }
+}
+endif;
+
+/**
+ * Functions to be called in install and upgrade scripts.
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.0.1
+ */
+function upgrade_all() {
+ global $wp_current_db_version, $wp_db_version;
+ $wp_current_db_version = __get_option('db_version');
+
+ // We are up-to-date. Nothing to do.
+ if ( $wp_db_version == $wp_current_db_version )
+ return;
+
+ // If the version is not set in the DB, try to guess the version.
+ if ( empty($wp_current_db_version) ) {
+ $wp_current_db_version = 0;
+
+ // If the template option exists, we have 1.5.
+ $template = __get_option('template');
+ if ( !empty($template) )
+ $wp_current_db_version = 2541;
+ }
+
+ if ( $wp_current_db_version < 6039 )
+ upgrade_230_options_table();
+
+ populate_options();
+
+ if ( $wp_current_db_version < 2541 ) {
+ upgrade_100();
+ upgrade_101();
+ upgrade_110();
+ upgrade_130();
+ }
+
+ if ( $wp_current_db_version < 3308 )
+ upgrade_160();
+
+ if ( $wp_current_db_version < 4772 )
+ upgrade_210();
+
+ if ( $wp_current_db_version < 4351 )
+ upgrade_old_slugs();
+
+ if ( $wp_current_db_version < 5539 )
+ upgrade_230();
+
+ if ( $wp_current_db_version < 6124 )
+ upgrade_230_old_tables();
+
+ if ( $wp_current_db_version < 7499 )
+ upgrade_250();
+
+ if ( $wp_current_db_version < 7935 )
+ upgrade_252();
+
+ if ( $wp_current_db_version < 8201 )
+ upgrade_260();
+
+ if ( $wp_current_db_version < 8989 )
+ upgrade_270();
+
+ if ( $wp_current_db_version < 10360 )
+ upgrade_280();
+
+ if ( $wp_current_db_version < 11958 )
+ upgrade_290();
+
+ if ( $wp_current_db_version < 15260 )
+ upgrade_300();
+
+ if ( $wp_current_db_version < 19389 )
+ upgrade_330();
+
+ if ( $wp_current_db_version < 20080 )
+ upgrade_340();
+
+ if ( $wp_current_db_version < 22422 )
+ upgrade_350();
+
+ maybe_disable_link_manager();
+
+ maybe_disable_automattic_widgets();
+
+ update_option( 'db_version', $wp_db_version );
+ update_option( 'db_upgraded', true );
+}
+
+/**
+ * Execute changes made in WordPress 1.0.
+ *
+ * @since 1.0.0
+ */
+function upgrade_100() {
+ global $wpdb;
+
+ // Get the title and ID of every post, post_name to check if it already has a value
+ $posts = $wpdb->get_results("SELECT ID, post_title, post_name FROM $wpdb->posts WHERE post_name = ''");
+ if ($posts) {
+ foreach($posts as $post) {
+ if ('' == $post->post_name) {
+ $newtitle = sanitize_title($post->post_title);
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_name = %s WHERE ID = %d", $newtitle, $post->ID) );
+ }
+ }
+ }
+
+ $categories = $wpdb->get_results("SELECT cat_ID, cat_name, category_nicename FROM $wpdb->categories");
+ foreach ($categories as $category) {
+ if ('' == $category->category_nicename) {
+ $newtitle = sanitize_title($category->cat_name);
+ $wpdb->update( $wpdb->categories, array('category_nicename' => $newtitle), array('cat_ID' => $category->cat_ID) );
+ }
+ }
+
+ $wpdb->query("UPDATE $wpdb->options SET option_value = REPLACE(option_value, 'wp-links/links-images/', 'wp-images/links/')
+ WHERE option_name LIKE 'links_rating_image%'
+ AND option_value LIKE 'wp-links/links-images/%'");
+
+ $done_ids = $wpdb->get_results("SELECT DISTINCT post_id FROM $wpdb->post2cat");
+ if ($done_ids) :
+ foreach ($done_ids as $done_id) :
+ $done_posts[] = $done_id->post_id;
+ endforeach;
+ $catwhere = ' AND ID NOT IN (' . implode(',', $done_posts) . ')';
+ else:
+ $catwhere = '';
+ endif;
+
+ $allposts = $wpdb->get_results("SELECT ID, post_category FROM $wpdb->posts WHERE post_category != '0' $catwhere");
+ if ($allposts) :
+ foreach ($allposts as $post) {
+ // Check to see if it's already been imported
+ $cat = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->post2cat WHERE post_id = %d AND category_id = %d", $post->ID, $post->post_category) );
+ if (!$cat && 0 != $post->post_category) { // If there's no result
+ $wpdb->insert( $wpdb->post2cat, array('post_id' => $post->ID, 'category_id' => $post->post_category) );
+ }
+ }
+ endif;
+}
+
+/**
+ * Execute changes made in WordPress 1.0.1.
+ *
+ * @since 1.0.1
+ */
+function upgrade_101() {
+ global $wpdb;
+
+ // Clean up indices, add a few
+ add_clean_index($wpdb->posts, 'post_name');
+ add_clean_index($wpdb->posts, 'post_status');
+ add_clean_index($wpdb->categories, 'category_nicename');
+ add_clean_index($wpdb->comments, 'comment_approved');
+ add_clean_index($wpdb->comments, 'comment_post_ID');
+ add_clean_index($wpdb->links , 'link_category');
+ add_clean_index($wpdb->links , 'link_visible');
+}
+
+/**
+ * Execute changes made in WordPress 1.2.
+ *
+ * @since 1.2.0
+ */
+function upgrade_110() {
+ global $wpdb;
+
+ // Set user_nicename.
+ $users = $wpdb->get_results("SELECT ID, user_nickname, user_nicename FROM $wpdb->users");
+ foreach ($users as $user) {
+ if ('' == $user->user_nicename) {
+ $newname = sanitize_title($user->user_nickname);
+ $wpdb->update( $wpdb->users, array('user_nicename' => $newname), array('ID' => $user->ID) );
+ }
+ }
+
+ $users = $wpdb->get_results("SELECT ID, user_pass from $wpdb->users");
+ foreach ($users as $row) {
+ if (!preg_match('/^[A-Fa-f0-9]{32}$/', $row->user_pass)) {
+ $wpdb->update( $wpdb->users, array('user_pass' => md5($row->user_pass)), array('ID' => $row->ID) );
+ }
+ }
+
+ // Get the GMT offset, we'll use that later on
+ $all_options = get_alloptions_110();
+
+ $time_difference = $all_options->time_difference;
+
+ $server_time = time()+date('Z');
+ $weblogger_time = $server_time + $time_difference * HOUR_IN_SECONDS;
+ $gmt_time = time();
+
+ $diff_gmt_server = ($gmt_time - $server_time) / HOUR_IN_SECONDS;
+ $diff_weblogger_server = ($weblogger_time - $server_time) / HOUR_IN_SECONDS;
+ $diff_gmt_weblogger = $diff_gmt_server - $diff_weblogger_server;
+ $gmt_offset = -$diff_gmt_weblogger;
+
+ // Add a gmt_offset option, with value $gmt_offset
+ add_option('gmt_offset', $gmt_offset);
+
+ // Check if we already set the GMT fields (if we did, then
+ // MAX(post_date_gmt) can't be '0000-00-00 00:00:00'
+ // <michel_v> I just slapped myself silly for not thinking about it earlier
+ $got_gmt_fields = ! ($wpdb->get_var("SELECT MAX(post_date_gmt) FROM $wpdb->posts") == '0000-00-00 00:00:00');
+
+ if (!$got_gmt_fields) {
+
+ // Add or subtract time to all dates, to get GMT dates
+ $add_hours = intval($diff_gmt_weblogger);
+ $add_minutes = intval(60 * ($diff_gmt_weblogger - $add_hours));
+ $wpdb->query("UPDATE $wpdb->posts SET post_date_gmt = DATE_ADD(post_date, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)");
+ $wpdb->query("UPDATE $wpdb->posts SET post_modified = post_date");
+ $wpdb->query("UPDATE $wpdb->posts SET post_modified_gmt = DATE_ADD(post_modified, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE) WHERE post_modified != '0000-00-00 00:00:00'");
+ $wpdb->query("UPDATE $wpdb->comments SET comment_date_gmt = DATE_ADD(comment_date, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)");
+ $wpdb->query("UPDATE $wpdb->users SET user_registered = DATE_ADD(user_registered, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)");
+ }
+
+}
+
+/**
+ * Execute changes made in WordPress 1.5.
+ *
+ * @since 1.5.0
+ */
+function upgrade_130() {
+ global $wpdb;
+
+ // Remove extraneous backslashes.
+ $posts = $wpdb->get_results("SELECT ID, post_title, post_content, post_excerpt, guid, post_date, post_name, post_status, post_author FROM $wpdb->posts");
+ if ($posts) {
+ foreach($posts as $post) {
+ $post_content = addslashes(deslash($post->post_content));
+ $post_title = addslashes(deslash($post->post_title));
+ $post_excerpt = addslashes(deslash($post->post_excerpt));
+ if ( empty($post->guid) )
+ $guid = get_permalink($post->ID);
+ else
+ $guid = $post->guid;
+
+ $wpdb->update( $wpdb->posts, compact('post_title', 'post_content', 'post_excerpt', 'guid'), array('ID' => $post->ID) );
+
+ }
+ }
+
+ // Remove extraneous backslashes.
+ $comments = $wpdb->get_results("SELECT comment_ID, comment_author, comment_content FROM $wpdb->comments");
+ if ($comments) {
+ foreach($comments as $comment) {
+ $comment_content = deslash($comment->comment_content);
+ $comment_author = deslash($comment->comment_author);
+
+ $wpdb->update($wpdb->comments, compact('comment_content', 'comment_author'), array('comment_ID' => $comment->comment_ID) );
+ }
+ }
+
+ // Remove extraneous backslashes.
+ $links = $wpdb->get_results("SELECT link_id, link_name, link_description FROM $wpdb->links");
+ if ($links) {
+ foreach($links as $link) {
+ $link_name = deslash($link->link_name);
+ $link_description = deslash($link->link_description);
+
+ $wpdb->update( $wpdb->links, compact('link_name', 'link_description'), array('link_id' => $link->link_id) );
+ }
+ }
+
+ $active_plugins = __get_option('active_plugins');
+
+ // If plugins are not stored in an array, they're stored in the old
+ // newline separated format. Convert to new format.
+ if ( !is_array( $active_plugins ) ) {
+ $active_plugins = explode("\n", trim($active_plugins));
+ update_option('active_plugins', $active_plugins);
+ }
+
+ // Obsolete tables
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optionvalues');
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiontypes');
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiongroups');
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiongroup_options');
+
+ // Update comments table to use comment_type
+ $wpdb->query("UPDATE $wpdb->comments SET comment_type='trackback', comment_content = REPLACE(comment_content, '<trackback />', '') WHERE comment_content LIKE '<trackback />%'");
+ $wpdb->query("UPDATE $wpdb->comments SET comment_type='pingback', comment_content = REPLACE(comment_content, '<pingback />', '') WHERE comment_content LIKE '<pingback />%'");
+
+ // Some versions have multiple duplicate option_name rows with the same values
+ $options = $wpdb->get_results("SELECT option_name, COUNT(option_name) AS dupes FROM `$wpdb->options` GROUP BY option_name");
+ foreach ( $options as $option ) {
+ if ( 1 != $option->dupes ) { // Could this be done in the query?
+ $limit = $option->dupes - 1;
+ $dupe_ids = $wpdb->get_col( $wpdb->prepare("SELECT option_id FROM $wpdb->options WHERE option_name = %s LIMIT %d", $option->option_name, $limit) );
+ if ( $dupe_ids ) {
+ $dupe_ids = join($dupe_ids, ',');
+ $wpdb->query("DELETE FROM $wpdb->options WHERE option_id IN ($dupe_ids)");
+ }
+ }
+ }
+
+ make_site_theme();
+}
+
+/**
+ * Execute changes made in WordPress 2.0.
+ *
+ * @since 2.0.0
+ */
+function upgrade_160() {
+ global $wpdb, $wp_current_db_version;
+
+ populate_roles_160();
+
+ $users = $wpdb->get_results("SELECT * FROM $wpdb->users");
+ foreach ( $users as $user ) :
+ if ( !empty( $user->user_firstname ) )
+ update_user_meta( $user->ID, 'first_name', wp_slash($user->user_firstname) );
+ if ( !empty( $user->user_lastname ) )
+ update_user_meta( $user->ID, 'last_name', wp_slash($user->user_lastname) );
+ if ( !empty( $user->user_nickname ) )
+ update_user_meta( $user->ID, 'nickname', wp_slash($user->user_nickname) );
+ if ( !empty( $user->user_level ) )
+ update_user_meta( $user->ID, $wpdb->prefix . 'user_level', $user->user_level );
+ if ( !empty( $user->user_icq ) )
+ update_user_meta( $user->ID, 'icq', wp_slash($user->user_icq) );
+ if ( !empty( $user->user_aim ) )
+ update_user_meta( $user->ID, 'aim', wp_slash($user->user_aim) );
+ if ( !empty( $user->user_msn ) )
+ update_user_meta( $user->ID, 'msn', wp_slash($user->user_msn) );
+ if ( !empty( $user->user_yim ) )
+ update_user_meta( $user->ID, 'yim', wp_slash($user->user_icq) );
+ if ( !empty( $user->user_description ) )
+ update_user_meta( $user->ID, 'description', wp_slash($user->user_description) );
+
+ if ( isset( $user->user_idmode ) ):
+ $idmode = $user->user_idmode;
+ if ($idmode == 'nickname') $id = $user->user_nickname;
+ if ($idmode == 'login') $id = $user->user_login;
+ if ($idmode == 'firstname') $id = $user->user_firstname;
+ if ($idmode == 'lastname') $id = $user->user_lastname;
+ if ($idmode == 'namefl') $id = $user->user_firstname.' '.$user->user_lastname;
+ if ($idmode == 'namelf') $id = $user->user_lastname.' '.$user->user_firstname;
+ if (!$idmode) $id = $user->user_nickname;
+ $wpdb->update( $wpdb->users, array('display_name' => $id), array('ID' => $user->ID) );
+ endif;
+
+ // FIXME: RESET_CAPS is temporary code to reset roles and caps if flag is set.
+ $caps = get_user_meta( $user->ID, $wpdb->prefix . 'capabilities');
+ if ( empty($caps) || defined('RESET_CAPS') ) {
+ $level = get_user_meta($user->ID, $wpdb->prefix . 'user_level', true);
+ $role = translate_level_to_role($level);
+ update_user_meta( $user->ID, $wpdb->prefix . 'capabilities', array($role => true) );
+ }
+
+ endforeach;
+ $old_user_fields = array( 'user_firstname', 'user_lastname', 'user_icq', 'user_aim', 'user_msn', 'user_yim', 'user_idmode', 'user_ip', 'user_domain', 'user_browser', 'user_description', 'user_nickname', 'user_level' );
+ $wpdb->hide_errors();
+ foreach ( $old_user_fields as $old )
+ $wpdb->query("ALTER TABLE $wpdb->users DROP $old");
+ $wpdb->show_errors();
+
+ // populate comment_count field of posts table
+ $comments = $wpdb->get_results( "SELECT comment_post_ID, COUNT(*) as c FROM $wpdb->comments WHERE comment_approved = '1' GROUP BY comment_post_ID" );
+ if ( is_array( $comments ) )
+ foreach ($comments as $comment)
+ $wpdb->update( $wpdb->posts, array('comment_count' => $comment->c), array('ID' => $comment->comment_post_ID) );
+
+ // Some alpha versions used a post status of object instead of attachment and put
+ // the mime type in post_type instead of post_mime_type.
+ if ( $wp_current_db_version > 2541 && $wp_current_db_version <= 3091 ) {
+ $objects = $wpdb->get_results("SELECT ID, post_type FROM $wpdb->posts WHERE post_status = 'object'");
+ foreach ($objects as $object) {
+ $wpdb->update( $wpdb->posts, array( 'post_status' => 'attachment',
+ 'post_mime_type' => $object->post_type,
+ 'post_type' => ''),
+ array( 'ID' => $object->ID ) );
+
+ $meta = get_post_meta($object->ID, 'imagedata', true);
+ if ( ! empty($meta['file']) )
+ update_attached_file( $object->ID, $meta['file'] );
+ }
+ }
+}
+
+/**
+ * Execute changes made in WordPress 2.1.
+ *
+ * @since 2.1.0
+ */
+function upgrade_210() {
+ global $wpdb, $wp_current_db_version;
+
+ if ( $wp_current_db_version < 3506 ) {
+ // Update status and type.
+ $posts = $wpdb->get_results("SELECT ID, post_status FROM $wpdb->posts");
+
+ if ( ! empty($posts) ) foreach ($posts as $post) {
+ $status = $post->post_status;
+ $type = 'post';
+
+ if ( 'static' == $status ) {
+ $status = 'publish';
+ $type = 'page';
+ } else if ( 'attachment' == $status ) {
+ $status = 'inherit';
+ $type = 'attachment';
+ }
+
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_status = %s, post_type = %s WHERE ID = %d", $status, $type, $post->ID) );
+ }
+ }
+
+ if ( $wp_current_db_version < 3845 ) {
+ populate_roles_210();
+ }
+
+ if ( $wp_current_db_version < 3531 ) {
+ // Give future posts a post_status of future.
+ $now = gmdate('Y-m-d H:i:59');
+ $wpdb->query ("UPDATE $wpdb->posts SET post_status = 'future' WHERE post_status = 'publish' AND post_date_gmt > '$now'");
+
+ $posts = $wpdb->get_results("SELECT ID, post_date FROM $wpdb->posts WHERE post_status ='future'");
+ if ( !empty($posts) )
+ foreach ( $posts as $post )
+ wp_schedule_single_event(mysql2date('U', $post->post_date, false), 'publish_future_post', array($post->ID));
+ }
+}
+
+/**
+ * Execute changes made in WordPress 2.3.
+ *
+ * @since 2.3.0
+ */
+function upgrade_230() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 5200 ) {
+ populate_roles_230();
+ }
+
+ // Convert categories to terms.
+ $tt_ids = array();
+ $have_tags = false;
+ $categories = $wpdb->get_results("SELECT * FROM $wpdb->categories ORDER BY cat_ID");
+ foreach ($categories as $category) {
+ $term_id = (int) $category->cat_ID;
+ $name = $category->cat_name;
+ $description = $category->category_description;
+ $slug = $category->category_nicename;
+ $parent = $category->category_parent;
+ $term_group = 0;
+
+ // Associate terms with the same slug in a term group and make slugs unique.
+ if ( $exists = $wpdb->get_results( $wpdb->prepare("SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $slug) ) ) {
+ $term_group = $exists[0]->term_group;
+ $id = $exists[0]->term_id;
+ $num = 2;
+ do {
+ $alt_slug = $slug . "-$num";
+ $num++;
+ $slug_check = $wpdb->get_var( $wpdb->prepare("SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug) );
+ } while ( $slug_check );
+
+ $slug = $alt_slug;
+
+ if ( empty( $term_group ) ) {
+ $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms GROUP BY term_group") + 1;
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->terms SET term_group = %d WHERE term_id = %d", $term_group, $id) );
+ }
+ }
+
+ $wpdb->query( $wpdb->prepare("INSERT INTO $wpdb->terms (term_id, name, slug, term_group) VALUES
+ (%d, %s, %s, %d)", $term_id, $name, $slug, $term_group) );
+
+ $count = 0;
+ if ( !empty($category->category_count) ) {
+ $count = (int) $category->category_count;
+ $taxonomy = 'category';
+ $wpdb->query( $wpdb->prepare("INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, $count) );
+ $tt_ids[$term_id][$taxonomy] = (int) $wpdb->insert_id;
+ }
+
+ if ( !empty($category->link_count) ) {
+ $count = (int) $category->link_count;
+ $taxonomy = 'link_category';
+ $wpdb->query( $wpdb->prepare("INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, $count) );
+ $tt_ids[$term_id][$taxonomy] = (int) $wpdb->insert_id;
+ }
+
+ if ( !empty($category->tag_count) ) {
+ $have_tags = true;
+ $count = (int) $category->tag_count;
+ $taxonomy = 'post_tag';
+ $wpdb->insert( $wpdb->term_taxonomy, compact('term_id', 'taxonomy', 'description', 'parent', 'count') );
+ $tt_ids[$term_id][$taxonomy] = (int) $wpdb->insert_id;
+ }
+
+ if ( empty($count) ) {
+ $count = 0;
+ $taxonomy = 'category';
+ $wpdb->insert( $wpdb->term_taxonomy, compact('term_id', 'taxonomy', 'description', 'parent', 'count') );
+ $tt_ids[$term_id][$taxonomy] = (int) $wpdb->insert_id;
+ }
+ }
+
+ $select = 'post_id, category_id';
+ if ( $have_tags )
+ $select .= ', rel_type';
+
+ $posts = $wpdb->get_results("SELECT $select FROM $wpdb->post2cat GROUP BY post_id, category_id");
+ foreach ( $posts as $post ) {
+ $post_id = (int) $post->post_id;
+ $term_id = (int) $post->category_id;
+ $taxonomy = 'category';
+ if ( !empty($post->rel_type) && 'tag' == $post->rel_type)
+ $taxonomy = 'tag';
+ $tt_id = $tt_ids[$term_id][$taxonomy];
+ if ( empty($tt_id) )
+ continue;
+
+ $wpdb->insert( $wpdb->term_relationships, array('object_id' => $post_id, 'term_taxonomy_id' => $tt_id) );
+ }
+
+ // < 3570 we used linkcategories. >= 3570 we used categories and link2cat.
+ if ( $wp_current_db_version < 3570 ) {
+ // Create link_category terms for link categories. Create a map of link cat IDs
+ // to link_category terms.
+ $link_cat_id_map = array();
+ $default_link_cat = 0;
+ $tt_ids = array();
+ $link_cats = $wpdb->get_results("SELECT cat_id, cat_name FROM " . $wpdb->prefix . 'linkcategories');
+ foreach ( $link_cats as $category) {
+ $cat_id = (int) $category->cat_id;
+ $term_id = 0;
+ $name = wp_slash($category->cat_name);
+ $slug = sanitize_title($name);
+ $term_group = 0;
+
+ // Associate terms with the same slug in a term group and make slugs unique.
+ if ( $exists = $wpdb->get_results( $wpdb->prepare("SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $slug) ) ) {
+ $term_group = $exists[0]->term_group;
+ $term_id = $exists[0]->term_id;
+ }
+
+ if ( empty($term_id) ) {
+ $wpdb->insert( $wpdb->terms, compact('name', 'slug', 'term_group') );
+ $term_id = (int) $wpdb->insert_id;
+ }
+
+ $link_cat_id_map[$cat_id] = $term_id;
+ $default_link_cat = $term_id;
+
+ $wpdb->insert( $wpdb->term_taxonomy, array('term_id' => $term_id, 'taxonomy' => 'link_category', 'description' => '', 'parent' => 0, 'count' => 0) );
+ $tt_ids[$term_id] = (int) $wpdb->insert_id;
+ }
+
+ // Associate links to cats.
+ $links = $wpdb->get_results("SELECT link_id, link_category FROM $wpdb->links");
+ if ( !empty($links) ) foreach ( $links as $link ) {
+ if ( 0 == $link->link_category )
+ continue;
+ if ( ! isset($link_cat_id_map[$link->link_category]) )
+ continue;
+ $term_id = $link_cat_id_map[$link->link_category];
+ $tt_id = $tt_ids[$term_id];
+ if ( empty($tt_id) )
+ continue;
+
+ $wpdb->insert( $wpdb->term_relationships, array('object_id' => $link->link_id, 'term_taxonomy_id' => $tt_id) );
+ }
+
+ // Set default to the last category we grabbed during the upgrade loop.
+ update_option('default_link_category', $default_link_cat);
+ } else {
+ $links = $wpdb->get_results("SELECT link_id, category_id FROM $wpdb->link2cat GROUP BY link_id, category_id");
+ foreach ( $links as $link ) {
+ $link_id = (int) $link->link_id;
+ $term_id = (int) $link->category_id;
+ $taxonomy = 'link_category';
+ $tt_id = $tt_ids[$term_id][$taxonomy];
+ if ( empty($tt_id) )
+ continue;
+ $wpdb->insert( $wpdb->term_relationships, array('object_id' => $link_id, 'term_taxonomy_id' => $tt_id) );
+ }
+ }
+
+ if ( $wp_current_db_version < 4772 ) {
+ // Obsolete linkcategories table
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'linkcategories');
+ }
+
+ // Recalculate all counts
+ $terms = $wpdb->get_results("SELECT term_taxonomy_id, taxonomy FROM $wpdb->term_taxonomy");
+ foreach ( (array) $terms as $term ) {
+ if ( ('post_tag' == $term->taxonomy) || ('category' == $term->taxonomy) )
+ $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type = 'post' AND term_taxonomy_id = %d", $term->term_taxonomy_id) );
+ else
+ $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term->term_taxonomy_id) );
+ $wpdb->update( $wpdb->term_taxonomy, array('count' => $count), array('term_taxonomy_id' => $term->term_taxonomy_id) );
+ }
+}
+
+/**
+ * Remove old options from the database.
+ *
+ * @since 2.3.0
+ */
+function upgrade_230_options_table() {
+ global $wpdb;
+ $old_options_fields = array( 'option_can_override', 'option_type', 'option_width', 'option_height', 'option_description', 'option_admin_level' );
+ $wpdb->hide_errors();
+ foreach ( $old_options_fields as $old )
+ $wpdb->query("ALTER TABLE $wpdb->options DROP $old");
+ $wpdb->show_errors();
+}
+
+/**
+ * Remove old categories, link2cat, and post2cat database tables.
+ *
+ * @since 2.3.0
+ */
+function upgrade_230_old_tables() {
+ global $wpdb;
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'categories');
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'link2cat');
+ $wpdb->query('DROP TABLE IF EXISTS ' . $wpdb->prefix . 'post2cat');
+}
+
+/**
+ * Upgrade old slugs made in version 2.2.
+ *
+ * @since 2.2.0
+ */
+function upgrade_old_slugs() {
+ // upgrade people who were using the Redirect Old Slugs plugin
+ global $wpdb;
+ $wpdb->query("UPDATE $wpdb->postmeta SET meta_key = '_wp_old_slug' WHERE meta_key = 'old_slug'");
+}
+
+/**
+ * Execute changes made in WordPress 2.5.0.
+ *
+ * @since 2.5.0
+ */
+function upgrade_250() {
+ global $wp_current_db_version;
+
+ if ( $wp_current_db_version < 6689 ) {
+ populate_roles_250();
+ }
+
+}
+
+/**
+ * Execute changes made in WordPress 2.5.2.
+ *
+ * @since 2.5.2
+ */
+function upgrade_252() {
+ global $wpdb;
+
+ $wpdb->query("UPDATE $wpdb->users SET user_activation_key = ''");
+}
+
+/**
+ * Execute changes made in WordPress 2.6.
+ *
+ * @since 2.6.0
+ */
+function upgrade_260() {
+ global $wp_current_db_version;
+
+ if ( $wp_current_db_version < 8000 )
+ populate_roles_260();
+}
+
+/**
+ * Execute changes made in WordPress 2.7.
+ *
+ * @since 2.7.0
+ */
+function upgrade_270() {
+ global $wpdb, $wp_current_db_version;
+
+ if ( $wp_current_db_version < 8980 )
+ populate_roles_270();
+
+ // Update post_date for unpublished posts with empty timestamp
+ if ( $wp_current_db_version < 8921 )
+ $wpdb->query( "UPDATE $wpdb->posts SET post_date = post_modified WHERE post_date = '0000-00-00 00:00:00'" );
+}
+
+/**
+ * Execute changes made in WordPress 2.8.
+ *
+ * @since 2.8.0
+ */
+function upgrade_280() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 10360 )
+ populate_roles_280();
+ if ( is_multisite() ) {
+ $start = 0;
+ while( $rows = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options ORDER BY option_id LIMIT $start, 20" ) ) {
+ foreach( $rows as $row ) {
+ $value = $row->option_value;
+ if ( !@unserialize( $value ) )
+ $value = stripslashes( $value );
+ if ( $value !== $row->option_value ) {
+ update_option( $row->option_name, $value );
+ }
+ }
+ $start += 20;
+ }
+ refresh_blog_details( $wpdb->blogid );
+ }
+}
+
+/**
+ * Execute changes made in WordPress 2.9.
+ *
+ * @since 2.9.0
+ */
+function upgrade_290() {
+ global $wp_current_db_version;
+
+ if ( $wp_current_db_version < 11958 ) {
+ // Previously, setting depth to 1 would redundantly disable threading, but now 2 is the minimum depth to avoid confusion
+ if ( get_option( 'thread_comments_depth' ) == '1' ) {
+ update_option( 'thread_comments_depth', 2 );
+ update_option( 'thread_comments', 0 );
+ }
+ }
+}
+
+/**
+ * Execute changes made in WordPress 3.0.
+ *
+ * @since 3.0.0
+ */
+function upgrade_300() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 15093 )
+ populate_roles_300();
+
+ if ( $wp_current_db_version < 14139 && is_multisite() && is_main_site() && ! defined( 'MULTISITE' ) && get_site_option( 'siteurl' ) === false )
+ add_site_option( 'siteurl', '' );
+
+ // 3.0 screen options key name changes.
+ if ( is_main_site() && !defined('DO_NOT_UPGRADE_GLOBAL_TABLES') ) {
+ $prefix = like_escape($wpdb->base_prefix);
+ $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key LIKE '{$prefix}%meta-box-hidden%' OR meta_key LIKE '{$prefix}%closedpostboxes%' OR meta_key LIKE '{$prefix}%manage-%-columns-hidden%' OR meta_key LIKE '{$prefix}%meta-box-order%' OR meta_key LIKE '{$prefix}%metaboxorder%' OR meta_key LIKE '{$prefix}%screen_layout%'
+ OR meta_key = 'manageedittagscolumnshidden' OR meta_key='managecategoriescolumnshidden' OR meta_key = 'manageedit-tagscolumnshidden' OR meta_key = 'manageeditcolumnshidden' OR meta_key = 'categories_per_page' OR meta_key = 'edit_tags_per_page'" );
+ }
+
+}
+
+/**
+ * Execute changes made in WordPress 3.3.
+ *
+ * @since 3.3.0
+ */
+function upgrade_330() {
+ global $wp_current_db_version, $wpdb, $wp_registered_widgets, $sidebars_widgets;
+
+ if ( $wp_current_db_version < 19061 && is_main_site() && ! defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) {
+ $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key IN ('show_admin_bar_admin', 'plugins_last_view')" );
+ }
+
+ if ( $wp_current_db_version >= 11548 )
+ return;
+
+ $sidebars_widgets = get_option( 'sidebars_widgets', array() );
+ $_sidebars_widgets = array();
+
+ if ( isset($sidebars_widgets['wp_inactive_widgets']) || empty($sidebars_widgets) )
+ $sidebars_widgets['array_version'] = 3;
+ elseif ( !isset($sidebars_widgets['array_version']) )
+ $sidebars_widgets['array_version'] = 1;
+
+ switch ( $sidebars_widgets['array_version'] ) {
+ case 1 :
+ foreach ( (array) $sidebars_widgets as $index => $sidebar )
+ if ( is_array($sidebar) )
+ foreach ( (array) $sidebar as $i => $name ) {
+ $id = strtolower($name);
+ if ( isset($wp_registered_widgets[$id]) ) {
+ $_sidebars_widgets[$index][$i] = $id;
+ continue;
+ }
+ $id = sanitize_title($name);
+ if ( isset($wp_registered_widgets[$id]) ) {
+ $_sidebars_widgets[$index][$i] = $id;
+ continue;
+ }
+
+ $found = false;
+
+ foreach ( $wp_registered_widgets as $widget_id => $widget ) {
+ if ( strtolower($widget['name']) == strtolower($name) ) {
+ $_sidebars_widgets[$index][$i] = $widget['id'];
+ $found = true;
+ break;
+ } elseif ( sanitize_title($widget['name']) == sanitize_title($name) ) {
+ $_sidebars_widgets[$index][$i] = $widget['id'];
+ $found = true;
+ break;
+ }
+ }
+
+ if ( $found )
+ continue;
+
+ unset($_sidebars_widgets[$index][$i]);
+ }
+ $_sidebars_widgets['array_version'] = 2;
+ $sidebars_widgets = $_sidebars_widgets;
+ unset($_sidebars_widgets);
+
+ case 2 :
+ $sidebars_widgets = retrieve_widgets();
+ $sidebars_widgets['array_version'] = 3;
+ update_option( 'sidebars_widgets', $sidebars_widgets );
+ }
+}
+
+/**
+ * Execute changes made in WordPress 3.4.
+ *
+ * @since 3.4.0
+ */
+function upgrade_340() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 19798 ) {
+ $wpdb->hide_errors();
+ $wpdb->query( "ALTER TABLE $wpdb->options DROP COLUMN blog_id" );
+ $wpdb->show_errors();
+ }
+
+ if ( $wp_current_db_version < 19799 ) {
+ $wpdb->hide_errors();
+ $wpdb->query("ALTER TABLE $wpdb->comments DROP INDEX comment_approved");
+ $wpdb->show_errors();
+ }
+
+ if ( $wp_current_db_version < 20022 && is_main_site() && ! defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) {
+ $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key = 'themes_last_view'" );
+ }
+
+ if ( $wp_current_db_version < 20080 ) {
+ if ( 'yes' == $wpdb->get_var( "SELECT autoload FROM $wpdb->options WHERE option_name = 'uninstall_plugins'" ) ) {
+ $uninstall_plugins = get_option( 'uninstall_plugins' );
+ delete_option( 'uninstall_plugins' );
+ add_option( 'uninstall_plugins', $uninstall_plugins, null, 'no' );
+ }
+ }
+}
+
+/**
+ * Execute changes made in WordPress 3.5.
+ *
+ * @since 3.5.0
+ */
+function upgrade_350() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version < 22006 && $wpdb->get_var( "SELECT link_id FROM $wpdb->links LIMIT 1" ) )
+ update_option( 'link_manager_enabled', 1 ); // Previously set to 0 by populate_options()
+
+ if ( $wp_current_db_version < 21811 && is_main_site() && ! defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) {
+ $meta_keys = array();
+ foreach ( array_merge( get_post_types(), get_taxonomies() ) as $name ) {
+ if ( false !== strpos( $name, '-' ) )
+ $meta_keys[] = 'edit_' . str_replace( '-', '_', $name ) . '_per_page';
+ }
+ if ( $meta_keys ) {
+ $meta_keys = implode( "', '", $meta_keys );
+ $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key IN ('$meta_keys')" );
+ }
+ }
+
+ if ( $wp_current_db_version < 22422 && $term = get_term_by( 'slug', 'post-format-standard', 'post_format' ) )
+ wp_delete_term( $term->term_id, 'post_format' );
+}
+
+/**
+ * Execute network level changes
+ *
+ * @since 3.0.0
+ */
+function upgrade_network() {
+ global $wp_current_db_version, $wpdb;
+ // 2.8
+ if ( $wp_current_db_version < 11549 ) {
+ $wpmu_sitewide_plugins = get_site_option( 'wpmu_sitewide_plugins' );
+ $active_sitewide_plugins = get_site_option( 'active_sitewide_plugins' );
+ if ( $wpmu_sitewide_plugins ) {
+ if ( !$active_sitewide_plugins )
+ $sitewide_plugins = (array) $wpmu_sitewide_plugins;
+ else
+ $sitewide_plugins = array_merge( (array) $active_sitewide_plugins, (array) $wpmu_sitewide_plugins );
+
+ update_site_option( 'active_sitewide_plugins', $sitewide_plugins );
+ }
+ delete_site_option( 'wpmu_sitewide_plugins' );
+ delete_site_option( 'deactivated_sitewide_plugins' );
+
+ $start = 0;
+ while( $rows = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->sitemeta} ORDER BY meta_id LIMIT $start, 20" ) ) {
+ foreach( $rows as $row ) {
+ $value = $row->meta_value;
+ if ( !@unserialize( $value ) )
+ $value = stripslashes( $value );
+ if ( $value !== $row->meta_value ) {
+ update_site_option( $row->meta_key, $value );
+ }
+ }
+ $start += 20;
+ }
+ }
+
+ // 3.0
+ if ( $wp_current_db_version < 13576 )
+ update_site_option( 'global_terms_enabled', '1' );
+
+ // 3.3
+ if ( $wp_current_db_version < 19390 )
+ update_site_option( 'initial_db_version', $wp_current_db_version );
+
+ if ( $wp_current_db_version < 19470 ) {
+ if ( false === get_site_option( 'active_sitewide_plugins' ) )
+ update_site_option( 'active_sitewide_plugins', array() );
+ }
+
+ // 3.4
+ if ( $wp_current_db_version < 20148 ) {
+ // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name.
+ $allowedthemes = get_site_option( 'allowedthemes' );
+ $allowed_themes = get_site_option( 'allowed_themes' );
+ if ( false === $allowedthemes && is_array( $allowed_themes ) && $allowed_themes ) {
+ $converted = array();
+ $themes = wp_get_themes();
+ foreach ( $themes as $stylesheet => $theme_data ) {
+ if ( isset( $allowed_themes[ $theme_data->get('Name') ] ) )
+ $converted[ $stylesheet ] = true;
+ }
+ update_site_option( 'allowedthemes', $converted );
+ delete_site_option( 'allowed_themes' );
+ }
+ }
+
+ // 3.5
+ if ( $wp_current_db_version < 21823 )
+ update_site_option( 'ms_files_rewriting', '1' );
+
+ // 3.5.2
+ if ( $wp_current_db_version < 24448 ) {
+ $illegal_names = get_site_option( 'illegal_names' );
+ if ( is_array( $illegal_names ) && count( $illegal_names ) === 1 ) {
+ $illegal_name = reset( $illegal_names );
+ $illegal_names = explode( ' ', $illegal_name );
+ update_site_option( 'illegal_names', $illegal_names );
+ }
+ }
+}
+
+// The functions we use to actually do stuff
+
+// General
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.0.0
+ *
+ * @param string $table_name Database table name to create.
+ * @param string $create_ddl SQL statement to create table.
+ * @return bool If table already exists or was created by function.
+ */
+function maybe_create_table($table_name, $create_ddl) {
+ global $wpdb;
+ if ( $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name )
+ return true;
+ //didn't find it try to create it.
+ $q = $wpdb->query($create_ddl);
+ // we cannot directly tell that whether this succeeded!
+ if ( $wpdb->get_var("SHOW TABLES LIKE '$table_name'") == $table_name )
+ return true;
+ return false;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.0.1
+ *
+ * @param string $table Database table name.
+ * @param string $index Index name to drop.
+ * @return bool True, when finished.
+ */
+function drop_index($table, $index) {
+ global $wpdb;
+ $wpdb->hide_errors();
+ $wpdb->query("ALTER TABLE `$table` DROP INDEX `$index`");
+ // Now we need to take out all the extra ones we may have created
+ for ($i = 0; $i < 25; $i++) {
+ $wpdb->query("ALTER TABLE `$table` DROP INDEX `{$index}_$i`");
+ }
+ $wpdb->show_errors();
+ return true;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.0.1
+ *
+ * @param string $table Database table name.
+ * @param string $index Database table index column.
+ * @return bool True, when done with execution.
+ */
+function add_clean_index($table, $index) {
+ global $wpdb;
+ drop_index($table, $index);
+ $wpdb->query("ALTER TABLE `$table` ADD INDEX ( `$index` )");
+ return true;
+}
+
+/**
+ ** maybe_add_column()
+ ** Add column to db table if it doesn't exist.
+ ** Returns: true if already exists or on successful completion
+ ** false on error
+ */
+function maybe_add_column($table_name, $column_name, $create_ddl) {
+ global $wpdb;
+ foreach ($wpdb->get_col("DESC $table_name", 0) as $column ) {
+ if ($column == $column_name) {
+ return true;
+ }
+ }
+ //didn't find it try to create it.
+ $q = $wpdb->query($create_ddl);
+ // we cannot directly tell that whether this succeeded!
+ foreach ($wpdb->get_col("DESC $table_name", 0) as $column ) {
+ if ($column == $column_name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Retrieve all options as it was for 1.2.
+ *
+ * @since 1.2.0
+ *
+ * @return array List of options.
+ */
+function get_alloptions_110() {
+ global $wpdb;
+ $all_options = new stdClass;
+ if ( $options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" ) ) {
+ foreach ( $options as $option ) {
+ if ( 'siteurl' == $option->option_name || 'home' == $option->option_name || 'category_base' == $option->option_name )
+ $option->option_value = untrailingslashit( $option->option_value );
+ $all_options->{$option->option_name} = stripslashes( $option->option_value );
+ }
+ }
+ return $all_options;
+}
+
+/**
+ * Version of get_option that is private to install/upgrade.
+ *
+ * @since 1.5.1
+ * @access private
+ *
+ * @param string $setting Option name.
+ * @return mixed
+ */
+function __get_option($setting) {
+ global $wpdb;
+
+ if ( $setting == 'home' && defined( 'WP_HOME' ) )
+ return untrailingslashit( WP_HOME );
+
+ if ( $setting == 'siteurl' && defined( 'WP_SITEURL' ) )
+ return untrailingslashit( WP_SITEURL );
+
+ $option = $wpdb->get_var( $wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s", $setting ) );
+
+ if ( 'home' == $setting && '' == $option )
+ return __get_option( 'siteurl' );
+
+ if ( 'siteurl' == $setting || 'home' == $setting || 'category_base' == $setting || 'tag_base' == $setting )
+ $option = untrailingslashit( $option );
+
+ return maybe_unserialize( $option );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param string $content
+ * @return string
+ */
+function deslash($content) {
+ // Note: \\\ inside a regex denotes a single backslash.
+
+ // Replace one or more backslashes followed by a single quote with
+ // a single quote.
+ $content = preg_replace("/\\\+'/", "'", $content);
+
+ // Replace one or more backslashes followed by a double quote with
+ // a double quote.
+ $content = preg_replace('/\\\+"/', '"', $content);
+
+ // Replace one or more backslashes with one backslash.
+ $content = preg_replace("/\\\+/", "\\", $content);
+
+ return $content;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $queries
+ * @param unknown_type $execute
+ * @return unknown
+ */
+function dbDelta( $queries = '', $execute = true ) {
+ global $wpdb;
+
+ if ( in_array( $queries, array( '', 'all', 'blog', 'global', 'ms_global' ), true ) )
+ $queries = wp_get_db_schema( $queries );
+
+ // Separate individual queries into an array
+ if ( !is_array($queries) ) {
+ $queries = explode( ';', $queries );
+ $queries = array_filter( $queries );
+ }
+ $queries = apply_filters( 'dbdelta_queries', $queries );
+
+ $cqueries = array(); // Creation Queries
+ $iqueries = array(); // Insertion Queries
+ $for_update = array();
+
+ // Create a tablename index for an array ($cqueries) of queries
+ foreach($queries as $qry) {
+ if (preg_match("|CREATE TABLE ([^ ]*)|", $qry, $matches)) {
+ $cqueries[ trim( $matches[1], '`' ) ] = $qry;
+ $for_update[$matches[1]] = 'Created table '.$matches[1];
+ } else if (preg_match("|CREATE DATABASE ([^ ]*)|", $qry, $matches)) {
+ array_unshift($cqueries, $qry);
+ } else if (preg_match("|INSERT INTO ([^ ]*)|", $qry, $matches)) {
+ $iqueries[] = $qry;
+ } else if (preg_match("|UPDATE ([^ ]*)|", $qry, $matches)) {
+ $iqueries[] = $qry;
+ } else {
+ // Unrecognized query type
+ }
+ }
+ $cqueries = apply_filters( 'dbdelta_create_queries', $cqueries );
+ $iqueries = apply_filters( 'dbdelta_insert_queries', $iqueries );
+
+ $global_tables = $wpdb->tables( 'global' );
+ foreach ( $cqueries as $table => $qry ) {
+ // Upgrade global tables only for the main site. Don't upgrade at all if DO_NOT_UPGRADE_GLOBAL_TABLES is defined.
+ if ( in_array( $table, $global_tables ) && ( !is_main_site() || defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) )
+ continue;
+
+ // Fetch the table column structure from the database
+ $wpdb->suppress_errors();
+ $tablefields = $wpdb->get_results("DESCRIBE {$table};");
+ $wpdb->suppress_errors( false );
+
+ if ( ! $tablefields )
+ continue;
+
+ // Clear the field and index arrays
+ $cfields = $indices = array();
+ // Get all of the field names in the query from between the parens
+ preg_match("|\((.*)\)|ms", $qry, $match2);
+ $qryline = trim($match2[1]);
+
+ // Separate field lines into an array
+ $flds = explode("\n", $qryline);
+
+ //echo "<hr/><pre>\n".print_r(strtolower($table), true).":\n".print_r($cqueries, true)."</pre><hr/>";
+
+ // For every field line specified in the query
+ foreach ($flds as $fld) {
+ // Extract the field name
+ preg_match("|^([^ ]*)|", trim($fld), $fvals);
+ $fieldname = trim( $fvals[1], '`' );
+
+ // Verify the found field name
+ $validfield = true;
+ switch (strtolower($fieldname)) {
+ case '':
+ case 'primary':
+ case 'index':
+ case 'fulltext':
+ case 'unique':
+ case 'key':
+ $validfield = false;
+ $indices[] = trim(trim($fld), ", \n");
+ break;
+ }
+ $fld = trim($fld);
+
+ // If it's a valid field, add it to the field array
+ if ($validfield) {
+ $cfields[strtolower($fieldname)] = trim($fld, ", \n");
+ }
+ }
+
+ // For every field in the table
+ foreach ($tablefields as $tablefield) {
+ // If the table field exists in the field array...
+ if (array_key_exists(strtolower($tablefield->Field), $cfields)) {
+ // Get the field type from the query
+ preg_match("|".$tablefield->Field." ([^ ]*( unsigned)?)|i", $cfields[strtolower($tablefield->Field)], $matches);
+ $fieldtype = $matches[1];
+
+ // Is actual field type different from the field type in query?
+ if ($tablefield->Type != $fieldtype) {
+ // Add a query to change the column type
+ $cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN {$tablefield->Field} " . $cfields[strtolower($tablefield->Field)];
+ $for_update[$table.'.'.$tablefield->Field] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}";
+ }
+
+ // Get the default value from the array
+ //echo "{$cfields[strtolower($tablefield->Field)]}<br>";
+ if (preg_match("| DEFAULT '(.*?)'|i", $cfields[strtolower($tablefield->Field)], $matches)) {
+ $default_value = $matches[1];
+ if ($tablefield->Default != $default_value) {
+ // Add a query to change the column's default value
+ $cqueries[] = "ALTER TABLE {$table} ALTER COLUMN {$tablefield->Field} SET DEFAULT '{$default_value}'";
+ $for_update[$table.'.'.$tablefield->Field] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}";
+ }
+ }
+
+ // Remove the field from the array (so it's not added)
+ unset($cfields[strtolower($tablefield->Field)]);
+ } else {
+ // This field exists in the table, but not in the creation queries?
+ }
+ }
+
+ // For every remaining field specified for the table
+ foreach ($cfields as $fieldname => $fielddef) {
+ // Push a query line into $cqueries that adds the field to that table
+ $cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef";
+ $for_update[$table.'.'.$fieldname] = 'Added column '.$table.'.'.$fieldname;
+ }
+
+ // Index stuff goes here
+ // Fetch the table index structure from the database
+ $tableindices = $wpdb->get_results("SHOW INDEX FROM {$table};");
+
+ if ($tableindices) {
+ // Clear the index array
+ unset($index_ary);
+
+ // For every index in the table
+ foreach ($tableindices as $tableindex) {
+ // Add the index to the index data array
+ $keyname = $tableindex->Key_name;
+ $index_ary[$keyname]['columns'][] = array('fieldname' => $tableindex->Column_name, 'subpart' => $tableindex->Sub_part);
+ $index_ary[$keyname]['unique'] = ($tableindex->Non_unique == 0)?true:false;
+ }
+
+ // For each actual index in the index array
+ foreach ($index_ary as $index_name => $index_data) {
+ // Build a create string to compare to the query
+ $index_string = '';
+ if ($index_name == 'PRIMARY') {
+ $index_string .= 'PRIMARY ';
+ } else if($index_data['unique']) {
+ $index_string .= 'UNIQUE ';
+ }
+ $index_string .= 'KEY ';
+ if ($index_name != 'PRIMARY') {
+ $index_string .= $index_name;
+ }
+ $index_columns = '';
+ // For each column in the index
+ foreach ($index_data['columns'] as $column_data) {
+ if ($index_columns != '') $index_columns .= ',';
+ // Add the field to the column list string
+ $index_columns .= $column_data['fieldname'];
+ if ($column_data['subpart'] != '') {
+ $index_columns .= '('.$column_data['subpart'].')';
+ }
+ }
+ // Add the column list to the index create string
+ $index_string .= ' ('.$index_columns.')';
+ if (!(($aindex = array_search($index_string, $indices)) === false)) {
+ unset($indices[$aindex]);
+ //echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">{$table}:<br />Found index:".$index_string."</pre>\n";
+ }
+ //else echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">{$table}:<br /><b>Did not find index:</b>".$index_string."<br />".print_r($indices, true)."</pre>\n";
+ }
+ }
+
+ // For every remaining index specified for the table
+ foreach ( (array) $indices as $index ) {
+ // Push a query line into $cqueries that adds the index to that table
+ $cqueries[] = "ALTER TABLE {$table} ADD $index";
+ $for_update[] = 'Added index ' . $table . ' ' . $index;
+ }
+
+ // Remove the original table creation query from processing
+ unset( $cqueries[ $table ], $for_update[ $table ] );
+ }
+
+ $allqueries = array_merge($cqueries, $iqueries);
+ if ($execute) {
+ foreach ($allqueries as $query) {
+ //echo "<pre style=\"border:1px solid #ccc;margin-top:5px;\">".print_r($query, true)."</pre>\n";
+ $wpdb->query($query);
+ }
+ }
+
+ return $for_update;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ */
+function make_db_current( $tables = 'all' ) {
+ $alterations = dbDelta( $tables );
+ echo "<ol>\n";
+ foreach($alterations as $alteration) echo "<li>$alteration</li>\n";
+ echo "</ol>\n";
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ */
+function make_db_current_silent( $tables = 'all' ) {
+ $alterations = dbDelta( $tables );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $theme_name
+ * @param unknown_type $template
+ * @return unknown
+ */
+function make_site_theme_from_oldschool($theme_name, $template) {
+ $home_path = get_home_path();
+ $site_dir = WP_CONTENT_DIR . "/themes/$template";
+
+ if (! file_exists("$home_path/index.php"))
+ return false;
+
+ // Copy files from the old locations to the site theme.
+ // TODO: This does not copy arbitrary include dependencies. Only the
+ // standard WP files are copied.
+ $files = array('index.php' => 'index.php', 'wp-layout.css' => 'style.css', 'wp-comments.php' => 'comments.php', 'wp-comments-popup.php' => 'comments-popup.php');
+
+ foreach ($files as $oldfile => $newfile) {
+ if ($oldfile == 'index.php')
+ $oldpath = $home_path;
+ else
+ $oldpath = ABSPATH;
+
+ if ($oldfile == 'index.php') { // Check to make sure it's not a new index
+ $index = implode('', file("$oldpath/$oldfile"));
+ if (strpos($index, 'WP_USE_THEMES') !== false) {
+ if (! @copy(WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME . '/index.php', "$site_dir/$newfile"))
+ return false;
+ continue; // Don't copy anything
+ }
+ }
+
+ if (! @copy("$oldpath/$oldfile", "$site_dir/$newfile"))
+ return false;
+
+ chmod("$site_dir/$newfile", 0777);
+
+ // Update the blog header include in each file.
+ $lines = explode("\n", implode('', file("$site_dir/$newfile")));
+ if ($lines) {
+ $f = fopen("$site_dir/$newfile", 'w');
+
+ foreach ($lines as $line) {
+ if (preg_match('/require.*wp-blog-header/', $line))
+ $line = '//' . $line;
+
+ // Update stylesheet references.
+ $line = str_replace("<?php echo __get_option('siteurl'); ?>/wp-layout.css", "<?php bloginfo('stylesheet_url'); ?>", $line);
+
+ // Update comments template inclusion.
+ $line = str_replace("<?php include(ABSPATH . 'wp-comments.php'); ?>", "<?php comments_template(); ?>", $line);
+
+ fwrite($f, "{$line}\n");
+ }
+ fclose($f);
+ }
+ }
+
+ // Add a theme header.
+ $header = "/*\nTheme Name: $theme_name\nTheme URI: " . __get_option('siteurl') . "\nDescription: A theme automatically created by the update.\nVersion: 1.0\nAuthor: Moi\n*/\n";
+
+ $stylelines = file_get_contents("$site_dir/style.css");
+ if ($stylelines) {
+ $f = fopen("$site_dir/style.css", 'w');
+
+ fwrite($f, $header);
+ fwrite($f, $stylelines);
+ fclose($f);
+ }
+
+ return true;
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ *
+ * @param unknown_type $theme_name
+ * @param unknown_type $template
+ * @return unknown
+ */
+function make_site_theme_from_default($theme_name, $template) {
+ $site_dir = WP_CONTENT_DIR . "/themes/$template";
+ $default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME;
+
+ // Copy files from the default theme to the site theme.
+ //$files = array('index.php', 'comments.php', 'comments-popup.php', 'footer.php', 'header.php', 'sidebar.php', 'style.css');
+
+ $theme_dir = @ opendir($default_dir);
+ if ($theme_dir) {
+ while(($theme_file = readdir( $theme_dir )) !== false) {
+ if (is_dir("$default_dir/$theme_file"))
+ continue;
+ if (! @copy("$default_dir/$theme_file", "$site_dir/$theme_file"))
+ return;
+ chmod("$site_dir/$theme_file", 0777);
+ }
+ }
+ @closedir($theme_dir);
+
+ // Rewrite the theme header.
+ $stylelines = explode("\n", implode('', file("$site_dir/style.css")));
+ if ($stylelines) {
+ $f = fopen("$site_dir/style.css", 'w');
+
+ foreach ($stylelines as $line) {
+ if (strpos($line, 'Theme Name:') !== false) $line = 'Theme Name: ' . $theme_name;
+ elseif (strpos($line, 'Theme URI:') !== false) $line = 'Theme URI: ' . __get_option('url');
+ elseif (strpos($line, 'Description:') !== false) $line = 'Description: Your theme.';
+ elseif (strpos($line, 'Version:') !== false) $line = 'Version: 1';
+ elseif (strpos($line, 'Author:') !== false) $line = 'Author: You';
+ fwrite($f, $line . "\n");
+ }
+ fclose($f);
+ }
+
+ // Copy the images.
+ umask(0);
+ if (! mkdir("$site_dir/images", 0777)) {
+ return false;
+ }
+
+ $images_dir = @ opendir("$default_dir/images");
+ if ($images_dir) {
+ while(($image = readdir($images_dir)) !== false) {
+ if (is_dir("$default_dir/images/$image"))
+ continue;
+ if (! @copy("$default_dir/images/$image", "$site_dir/images/$image"))
+ return;
+ chmod("$site_dir/images/$image", 0777);
+ }
+ }
+ @closedir($images_dir);
+}
+
+// Create a site theme from the default theme.
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 1.5.0
+ *
+ * @return unknown
+ */
+function make_site_theme() {
+ // Name the theme after the blog.
+ $theme_name = __get_option('blogname');
+ $template = sanitize_title($theme_name);
+ $site_dir = WP_CONTENT_DIR . "/themes/$template";
+
+ // If the theme already exists, nothing to do.
+ if ( is_dir($site_dir)) {
+ return false;
+ }
+
+ // We must be able to write to the themes dir.
+ if (! is_writable(WP_CONTENT_DIR . "/themes")) {
+ return false;
+ }
+
+ umask(0);
+ if (! mkdir($site_dir, 0777)) {
+ return false;
+ }
+
+ if (file_exists(ABSPATH . 'wp-layout.css')) {
+ if (! make_site_theme_from_oldschool($theme_name, $template)) {
+ // TODO: rm -rf the site theme directory.
+ return false;
+ }
+ } else {
+ if (! make_site_theme_from_default($theme_name, $template))
+ // TODO: rm -rf the site theme directory.
+ return false;
+ }
+
+ // Make the new site theme active.
+ $current_template = __get_option('template');
+ if ($current_template == WP_DEFAULT_THEME) {
+ update_option('template', $template);
+ update_option('stylesheet', $template);
+ }
+ return $template;
+}
+
+/**
+ * Translate user level to user role name.
+ *
+ * @since 2.0.0
+ *
+ * @param int $level User level.
+ * @return string User role name.
+ */
+function translate_level_to_role($level) {
+ switch ($level) {
+ case 10:
+ case 9:
+ case 8:
+ return 'administrator';
+ case 7:
+ case 6:
+ case 5:
+ return 'editor';
+ case 4:
+ case 3:
+ case 2:
+ return 'author';
+ case 1:
+ return 'contributor';
+ case 0:
+ return 'subscriber';
+ }
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * {@internal Missing Long Description}}
+ *
+ * @since 2.1.0
+ */
+function wp_check_mysql_version() {
+ global $wpdb;
+ $result = $wpdb->check_database_version();
+ if ( is_wp_error( $result ) )
+ die( $result->get_error_message() );
+}
+
+/**
+ * Disables the Automattic widgets plugin, which was merged into core.
+ *
+ * @since 2.2.0
+ */
+function maybe_disable_automattic_widgets() {
+ $plugins = __get_option( 'active_plugins' );
+
+ foreach ( (array) $plugins as $plugin ) {
+ if ( basename( $plugin ) == 'widgets.php' ) {
+ array_splice( $plugins, array_search( $plugin, $plugins ), 1 );
+ update_option( 'active_plugins', $plugins );
+ break;
+ }
+ }
+}
+
+/**
+ * Disables the Link Manager on upgrade, if at the time of upgrade, no links exist in the DB.
+ *
+ * @since 3.5.0
+ */
+function maybe_disable_link_manager() {
+ global $wp_current_db_version, $wpdb;
+
+ if ( $wp_current_db_version >= 22006 && get_option( 'link_manager_enabled' ) && ! $wpdb->get_var( "SELECT link_id FROM $wpdb->links LIMIT 1" ) )
+ update_option( 'link_manager_enabled', 0 );
+}
+
+/**
+ * Runs before the schema is upgraded.
+ *
+ * @since 2.9.0
+ */
+function pre_schema_upgrade() {
+ global $wp_current_db_version, $wp_db_version, $wpdb;
+
+ // Upgrade versions prior to 2.9
+ if ( $wp_current_db_version < 11557 ) {
+ // Delete duplicate options. Keep the option with the highest option_id.
+ $wpdb->query("DELETE o1 FROM $wpdb->options AS o1 JOIN $wpdb->options AS o2 USING (`option_name`) WHERE o2.option_id > o1.option_id");
+
+ // Drop the old primary key and add the new.
+ $wpdb->query("ALTER TABLE $wpdb->options DROP PRIMARY KEY, ADD PRIMARY KEY(option_id)");
+
+ // Drop the old option_name index. dbDelta() doesn't do the drop.
+ $wpdb->query("ALTER TABLE $wpdb->options DROP INDEX option_name");
+ }
+
+}
+
+/**
+ * Install global terms.
+ *
+ * @since 3.0.0
+ *
+ */
+if ( !function_exists( 'install_global_terms' ) ) :
+function install_global_terms() {
+ global $wpdb, $charset_collate;
+ $ms_queries = "
+CREATE TABLE $wpdb->sitecategories (
+ cat_ID bigint(20) NOT NULL auto_increment,
+ cat_name varchar(55) NOT NULL default '',
+ category_nicename varchar(200) NOT NULL default '',
+ last_updated timestamp NOT NULL,
+ PRIMARY KEY (cat_ID),
+ KEY category_nicename (category_nicename),
+ KEY last_updated (last_updated)
+) $charset_collate;
+";
+// now create tables
+ dbDelta( $ms_queries );
+}
+endif;
diff --git a/src/wp-admin/includes/user.php b/src/wp-admin/includes/user.php
new file mode 100644
index 0000000000..9e9d94494c
--- /dev/null
+++ b/src/wp-admin/includes/user.php
@@ -0,0 +1,372 @@
+<?php
+/**
+ * WordPress user administration API.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Creates a new user from the "Users" form using $_POST information.
+ *
+ * @since 2.0
+ *
+ * @return null|WP_Error|int Null when adding user, WP_Error or User ID integer when no parameters.
+ */
+function add_user() {
+ return edit_user();
+}
+
+/**
+ * Edit user settings based on contents of $_POST
+ *
+ * Used on user-edit.php and profile.php to manage and process user options, passwords etc.
+ *
+ * @since 2.0
+ *
+ * @param int $user_id Optional. User ID.
+ * @return int user id of the updated user
+ */
+function edit_user( $user_id = 0 ) {
+ global $wp_roles, $wpdb;
+ $user = new stdClass;
+ if ( $user_id ) {
+ $update = true;
+ $user->ID = (int) $user_id;
+ $userdata = get_userdata( $user_id );
+ $user->user_login = wp_slash( $userdata->user_login );
+ } else {
+ $update = false;
+ }
+
+ if ( !$update && isset( $_POST['user_login'] ) )
+ $user->user_login = sanitize_user($_POST['user_login'], true);
+
+ $pass1 = $pass2 = '';
+ if ( isset( $_POST['pass1'] ) )
+ $pass1 = $_POST['pass1'];
+ if ( isset( $_POST['pass2'] ) )
+ $pass2 = $_POST['pass2'];
+
+ if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) {
+ $new_role = sanitize_text_field( $_POST['role'] );
+ $potential_role = isset($wp_roles->role_objects[$new_role]) ? $wp_roles->role_objects[$new_role] : false;
+ // Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
+ // Multisite super admins can freely edit their blog roles -- they possess all caps.
+ if ( ( is_multisite() && current_user_can( 'manage_sites' ) ) || $user_id != get_current_user_id() || ($potential_role && $potential_role->has_cap( 'edit_users' ) ) )
+ $user->role = $new_role;
+
+ // If the new role isn't editable by the logged-in user die with error
+ $editable_roles = get_editable_roles();
+ if ( ! empty( $new_role ) && empty( $editable_roles[$new_role] ) )
+ wp_die(__('You can&#8217;t give users that role.'));
+ }
+
+ if ( isset( $_POST['email'] ))
+ $user->user_email = sanitize_text_field( $_POST['email'] );
+ if ( isset( $_POST['url'] ) ) {
+ if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) {
+ $user->user_url = '';
+ } else {
+ $user->user_url = esc_url_raw( $_POST['url'] );
+ $protocols = implode( '|', array_map( 'preg_quote', wp_allowed_protocols() ) );
+ $user->user_url = preg_match('/^(' . $protocols . '):/is', $user->user_url) ? $user->user_url : 'http://'.$user->user_url;
+ }
+ }
+ if ( isset( $_POST['first_name'] ) )
+ $user->first_name = sanitize_text_field( $_POST['first_name'] );
+ if ( isset( $_POST['last_name'] ) )
+ $user->last_name = sanitize_text_field( $_POST['last_name'] );
+ if ( isset( $_POST['nickname'] ) )
+ $user->nickname = sanitize_text_field( $_POST['nickname'] );
+ if ( isset( $_POST['display_name'] ) )
+ $user->display_name = sanitize_text_field( $_POST['display_name'] );
+
+ if ( isset( $_POST['description'] ) )
+ $user->description = trim( $_POST['description'] );
+
+ foreach ( _wp_get_user_contactmethods( $user ) as $method => $name ) {
+ if ( isset( $_POST[$method] ))
+ $user->$method = sanitize_text_field( $_POST[$method] );
+ }
+
+ if ( $update ) {
+ $user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' == $_POST['rich_editing'] ? 'false' : 'true';
+ $user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
+ $user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false';
+ }
+
+ $user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
+
+ $user->use_ssl = 0;
+ if ( !empty($_POST['use_ssl']) )
+ $user->use_ssl = 1;
+
+ $errors = new WP_Error();
+
+ /* checking that username has been typed */
+ if ( $user->user_login == '' )
+ $errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
+
+ /* checking the password has been typed twice */
+ do_action_ref_array( 'check_passwords', array( $user->user_login, &$pass1, &$pass2 ) );
+
+ if ( $update ) {
+ if ( empty($pass1) && !empty($pass2) )
+ $errors->add( 'pass', __( '<strong>ERROR</strong>: You entered your new password only once.' ), array( 'form-field' => 'pass1' ) );
+ elseif ( !empty($pass1) && empty($pass2) )
+ $errors->add( 'pass', __( '<strong>ERROR</strong>: You entered your new password only once.' ), array( 'form-field' => 'pass2' ) );
+ } else {
+ if ( empty($pass1) )
+ $errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter your password.' ), array( 'form-field' => 'pass1' ) );
+ elseif ( empty($pass2) )
+ $errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter your password twice.' ), array( 'form-field' => 'pass2' ) );
+ }
+
+ /* Check for "\" in password */
+ if ( false !== strpos( wp_unslash( $pass1 ), "\\" ) )
+ $errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) );
+
+ /* checking the password has been typed twice the same */
+ if ( $pass1 != $pass2 )
+ $errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in the two password fields.' ), array( 'form-field' => 'pass1' ) );
+
+ if ( !empty( $pass1 ) )
+ $user->user_pass = $pass1;
+
+ if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
+ $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
+
+ if ( !$update && username_exists( $user->user_login ) )
+ $errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
+
+ /* checking e-mail address */
+ if ( empty( $user->user_email ) ) {
+ $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an e-mail address.' ), array( 'form-field' => 'email' ) );
+ } elseif ( !is_email( $user->user_email ) ) {
+ $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ), array( 'form-field' => 'email' ) );
+ } elseif ( ( $owner_id = email_exists($user->user_email) ) && ( !$update || ( $owner_id != $user->ID ) ) ) {
+ $errors->add( 'email_exists', __('<strong>ERROR</strong>: This email is already registered, please choose another one.'), array( 'form-field' => 'email' ) );
+ }
+
+ // Allow plugins to return their own errors.
+ do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );
+
+ if ( $errors->get_error_codes() )
+ return $errors;
+
+ if ( $update ) {
+ $user_id = wp_update_user( $user );
+ } else {
+ $user_id = wp_insert_user( $user );
+ wp_new_user_notification( $user_id, isset( $_POST['send_password'] ) ? wp_unslash( $pass1 ) : '' );
+ }
+ return $user_id;
+}
+
+/**
+ * Fetch a filtered list of user roles that the current user is
+ * allowed to edit.
+ *
+ * Simple function who's main purpose is to allow filtering of the
+ * list of roles in the $wp_roles object so that plugins can remove
+ * inappropriate ones depending on the situation or user making edits.
+ * Specifically because without filtering anyone with the edit_users
+ * capability can edit others to be administrators, even if they are
+ * only editors or authors. This filter allows admins to delegate
+ * user management.
+ *
+ * @since 2.8
+ *
+ * @return unknown
+ */
+function get_editable_roles() {
+ global $wp_roles;
+
+ $all_roles = $wp_roles->roles;
+ $editable_roles = apply_filters('editable_roles', $all_roles);
+
+ return $editable_roles;
+}
+
+/**
+ * Retrieve user data and filter it.
+ *
+ * @since 2.0.5
+ *
+ * @param int $user_id User ID.
+ * @return object WP_User object with user data.
+ */
+function get_user_to_edit( $user_id ) {
+ $user = get_userdata( $user_id );
+
+ $user->filter = 'edit';
+
+ return $user;
+}
+
+/**
+ * Retrieve the user's drafts.
+ *
+ * @since 2.0.0
+ *
+ * @param int $user_id User ID.
+ * @return array
+ */
+function get_users_drafts( $user_id ) {
+ global $wpdb;
+ $query = $wpdb->prepare("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'draft' AND post_author = %d ORDER BY post_modified DESC", $user_id);
+ $query = apply_filters('get_users_drafts', $query);
+ return $wpdb->get_results( $query );
+}
+
+/**
+ * Remove user and optionally reassign posts and links to another user.
+ *
+ * If the $reassign parameter is not assigned to an User ID, then all posts will
+ * be deleted of that user. The action 'delete_user' that is passed the User ID
+ * being deleted will be run after the posts are either reassigned or deleted.
+ * The user meta will also be deleted that are for that User ID.
+ *
+ * @since 2.0.0
+ *
+ * @param int $id User ID.
+ * @param int $reassign Optional. Reassign posts and links to new User ID.
+ * @return bool True when finished.
+ */
+function wp_delete_user( $id, $reassign = 'novalue' ) {
+ global $wpdb;
+
+ $id = (int) $id;
+ $user = new WP_User( $id );
+
+ if ( !$user->exists() )
+ return false;
+
+ // allow for transaction statement
+ do_action('delete_user', $id);
+
+ if ( 'novalue' === $reassign || null === $reassign ) {
+ $post_types_to_delete = array();
+ foreach ( get_post_types( array(), 'objects' ) as $post_type ) {
+ if ( $post_type->delete_with_user ) {
+ $post_types_to_delete[] = $post_type->name;
+ } elseif ( null === $post_type->delete_with_user && post_type_supports( $post_type->name, 'author' ) ) {
+ $post_types_to_delete[] = $post_type->name;
+ }
+ }
+
+ $post_types_to_delete = apply_filters( 'post_types_to_delete_with_user', $post_types_to_delete, $id );
+ $post_types_to_delete = implode( "', '", $post_types_to_delete );
+ $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $id ) );
+ if ( $post_ids ) {
+ foreach ( $post_ids as $post_id )
+ wp_delete_post( $post_id );
+ }
+
+ // Clean links
+ $link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
+
+ if ( $link_ids ) {
+ foreach ( $link_ids as $link_id )
+ wp_delete_link($link_id);
+ }
+ } else {
+ $reassign = (int) $reassign;
+ $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
+ $wpdb->update( $wpdb->posts, array('post_author' => $reassign), array('post_author' => $id) );
+ if ( ! empty( $post_ids ) ) {
+ foreach ( $post_ids as $post_id )
+ clean_post_cache( $post_id );
+ }
+ $link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
+ $wpdb->update( $wpdb->links, array('link_owner' => $reassign), array('link_owner' => $id) );
+ if ( ! empty( $link_ids ) ) {
+ foreach ( $link_ids as $link_id )
+ clean_bookmark_cache( $link_id );
+ }
+ }
+
+ // FINALLY, delete user
+ if ( is_multisite() ) {
+ remove_user_from_blog( $id, get_current_blog_id() );
+ } else {
+ $meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
+ foreach ( $meta as $mid )
+ delete_metadata_by_mid( 'user', $mid );
+
+ $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
+ }
+
+ clean_user_cache( $user );
+
+ // allow for commit transaction
+ do_action('deleted_user', $id);
+
+ return true;
+}
+
+/**
+ * Remove all capabilities from user.
+ *
+ * @since 2.1.0
+ *
+ * @param int $id User ID.
+ */
+function wp_revoke_user($id) {
+ $id = (int) $id;
+
+ $user = new WP_User($id);
+ $user->remove_all_caps();
+}
+
+add_action('admin_init', 'default_password_nag_handler');
+/**
+ * @since 2.8.0
+ */
+function default_password_nag_handler($errors = false) {
+ global $user_ID;
+ if ( ! get_user_option('default_password_nag') ) //Short circuit it.
+ return;
+
+ //get_user_setting = JS saved UI setting. else no-js-fallback code.
+ if ( 'hide' == get_user_setting('default_password_nag') || isset($_GET['default_password_nag']) && '0' == $_GET['default_password_nag'] ) {
+ delete_user_setting('default_password_nag');
+ update_user_option($user_ID, 'default_password_nag', false, true);
+ }
+}
+
+add_action('profile_update', 'default_password_nag_edit_user', 10, 2);
+/**
+ * @since 2.8.0
+ */
+function default_password_nag_edit_user($user_ID, $old_data) {
+ if ( ! get_user_option('default_password_nag', $user_ID) ) //Short circuit it.
+ return;
+
+ $new_data = get_userdata($user_ID);
+
+ if ( $new_data->user_pass != $old_data->user_pass ) { //Remove the nag if the password has been changed.
+ delete_user_setting('default_password_nag');
+ update_user_option($user_ID, 'default_password_nag', false, true);
+ }
+}
+
+add_action('admin_notices', 'default_password_nag');
+/**
+ * @since 2.8.0
+ */
+function default_password_nag() {
+ global $pagenow;
+ if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') ) //Short circuit it.
+ return;
+
+ echo '<div class="error default-password-nag">';
+ echo '<p>';
+ echo '<strong>' . __('Notice:') . '</strong> ';
+ _e('You&rsquo;re using the auto-generated password for your account. Would you like to change it to something easier to remember?');
+ echo '</p><p>';
+ printf( '<a href="%s">' . __('Yes, take me to my profile page') . '</a> | ', get_edit_profile_url( get_current_user_id() ) . '#password' );
+ printf( '<a href="%s" id="default-password-nag-no">' . __('No thanks, do not remind me again') . '</a>', '?default_password_nag=0' );
+ echo '</p></div>';
+}
diff --git a/src/wp-admin/includes/widgets.php b/src/wp-admin/includes/widgets.php
new file mode 100644
index 0000000000..dae95509aa
--- /dev/null
+++ b/src/wp-admin/includes/widgets.php
@@ -0,0 +1,228 @@
+<?php
+/**
+ * WordPress Widgets Administration API
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Display list of the available widgets.
+ *
+ * @since 2.5.0
+ */
+function wp_list_widgets() {
+ global $wp_registered_widgets, $sidebars_widgets, $wp_registered_widget_controls;
+
+ $sort = $wp_registered_widgets;
+ usort( $sort, '_sort_name_callback' );
+ $done = array();
+
+ foreach ( $sort as $widget ) {
+ if ( in_array( $widget['callback'], $done, true ) ) // We already showed this multi-widget
+ continue;
+
+ $sidebar = is_active_widget( $widget['callback'], $widget['id'], false, false );
+ $done[] = $widget['callback'];
+
+ if ( ! isset( $widget['params'][0] ) )
+ $widget['params'][0] = array();
+
+ $args = array( 'widget_id' => $widget['id'], 'widget_name' => $widget['name'], '_display' => 'template' );
+
+ if ( isset($wp_registered_widget_controls[$widget['id']]['id_base']) && isset($widget['params'][0]['number']) ) {
+ $id_base = $wp_registered_widget_controls[$widget['id']]['id_base'];
+ $args['_temp_id'] = "$id_base-__i__";
+ $args['_multi_num'] = next_widget_id_number($id_base);
+ $args['_add'] = 'multi';
+ } else {
+ $args['_add'] = 'single';
+ if ( $sidebar )
+ $args['_hide'] = '1';
+ }
+
+ $args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
+ call_user_func_array( 'wp_widget_control', $args );
+ }
+}
+
+/**
+ * Callback to sort array by a 'name' key.
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _sort_name_callback( $a, $b ) {
+ return strnatcasecmp( $a['name'], $b['name'] );
+}
+
+/**
+ * Show the widgets and their settings for a sidebar.
+ * Used in the admin widget config screen.
+ *
+ * @since 2.5.0
+ *
+ * @param string $sidebar id slug of the sidebar
+ */
+function wp_list_widget_controls( $sidebar ) {
+ add_filter( 'dynamic_sidebar_params', 'wp_list_widget_controls_dynamic_sidebar' );
+
+ echo "<div id='$sidebar' class='widgets-sortables'>\n";
+
+ $description = wp_sidebar_description( $sidebar );
+
+ if ( !empty( $description ) ) {
+ echo "<div class='sidebar-description'>\n";
+ echo "\t<p class='description'>$description</p>";
+ echo "</div>\n";
+ }
+
+ dynamic_sidebar( $sidebar );
+ echo "</div>\n";
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.5.0
+ *
+ * @param array $params
+ * @return array
+ */
+function wp_list_widget_controls_dynamic_sidebar( $params ) {
+ global $wp_registered_widgets;
+ static $i = 0;
+ $i++;
+
+ $widget_id = $params[0]['widget_id'];
+ $id = isset($params[0]['_temp_id']) ? $params[0]['_temp_id'] : $widget_id;
+ $hidden = isset($params[0]['_hide']) ? ' style="display:none;"' : '';
+
+ $params[0]['before_widget'] = "<div id='widget-{$i}_{$id}' class='widget'$hidden>";
+ $params[0]['after_widget'] = "</div>";
+ $params[0]['before_title'] = "%BEG_OF_TITLE%"; // deprecated
+ $params[0]['after_title'] = "%END_OF_TITLE%"; // deprecated
+ if ( is_callable( $wp_registered_widgets[$widget_id]['callback'] ) ) {
+ $wp_registered_widgets[$widget_id]['_callback'] = $wp_registered_widgets[$widget_id]['callback'];
+ $wp_registered_widgets[$widget_id]['callback'] = 'wp_widget_control';
+ }
+
+ return $params;
+}
+
+function next_widget_id_number($id_base) {
+ global $wp_registered_widgets;
+ $number = 1;
+
+ foreach ( $wp_registered_widgets as $widget_id => $widget ) {
+ if ( preg_match( '/' . $id_base . '-([0-9]+)$/', $widget_id, $matches ) )
+ $number = max($number, $matches[1]);
+ }
+ $number++;
+
+ return $number;
+}
+
+/**
+ * Meta widget used to display the control form for a widget.
+ *
+ * Called from dynamic_sidebar().
+ *
+ * @since 2.5.0
+ *
+ * @param array $sidebar_args
+ * @return array
+ */
+function wp_widget_control( $sidebar_args ) {
+ global $wp_registered_widgets, $wp_registered_widget_controls, $sidebars_widgets;
+
+ $widget_id = $sidebar_args['widget_id'];
+ $sidebar_id = isset($sidebar_args['id']) ? $sidebar_args['id'] : false;
+ $key = $sidebar_id ? array_search( $widget_id, $sidebars_widgets[$sidebar_id] ) : '-1'; // position of widget in sidebar
+ $control = isset($wp_registered_widget_controls[$widget_id]) ? $wp_registered_widget_controls[$widget_id] : array();
+ $widget = $wp_registered_widgets[$widget_id];
+
+ $id_format = $widget['id'];
+ $widget_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : '';
+ $id_base = isset($control['id_base']) ? $control['id_base'] : $widget_id;
+ $multi_number = isset($sidebar_args['_multi_num']) ? $sidebar_args['_multi_num'] : '';
+ $add_new = isset($sidebar_args['_add']) ? $sidebar_args['_add'] : '';
+
+ $query_arg = array( 'editwidget' => $widget['id'] );
+ if ( $add_new ) {
+ $query_arg['addnew'] = 1;
+ if ( $multi_number ) {
+ $query_arg['num'] = $multi_number;
+ $query_arg['base'] = $id_base;
+ }
+ } else {
+ $query_arg['sidebar'] = $sidebar_id;
+ $query_arg['key'] = $key;
+ }
+
+ // We aren't showing a widget control, we're outputting a template for a multi-widget control
+ if ( isset($sidebar_args['_display']) && 'template' == $sidebar_args['_display'] && $widget_number ) {
+ // number == -1 implies a template where id numbers are replaced by a generic '__i__'
+ $control['params'][0]['number'] = -1;
+ // with id_base widget id's are constructed like {$id_base}-{$id_number}
+ if ( isset($control['id_base']) )
+ $id_format = $control['id_base'] . '-__i__';
+ }
+
+ $wp_registered_widgets[$widget_id]['callback'] = $wp_registered_widgets[$widget_id]['_callback'];
+ unset($wp_registered_widgets[$widget_id]['_callback']);
+
+ $widget_title = esc_html( strip_tags( $sidebar_args['widget_name'] ) );
+ $has_form = 'noform';
+
+ echo $sidebar_args['before_widget']; ?>
+ <div class="widget-top">
+ <div class="widget-title-action">
+ <a class="widget-action hide-if-no-js" href="#available-widgets"></a>
+ <a class="widget-control-edit hide-if-js" href="<?php echo esc_url( add_query_arg( $query_arg ) ); ?>">
+ <span class="edit"><?php _ex( 'Edit', 'widget' ); ?></span>
+ <span class="add"><?php _ex( 'Add', 'widget' ); ?></span>
+ <span class="screen-reader-text"><?php echo $widget_title; ?></span>
+ </a>
+ </div>
+ <div class="widget-title"><h4><?php echo $widget_title ?><span class="in-widget-title"></span></h4></div>
+ </div>
+
+ <div class="widget-inside">
+ <form action="" method="post">
+ <div class="widget-content">
+<?php
+ if ( isset($control['callback']) )
+ $has_form = call_user_func_array( $control['callback'], $control['params'] );
+ else
+ echo "\t\t<p>" . __('There are no options for this widget.') . "</p>\n"; ?>
+ </div>
+ <input type="hidden" name="widget-id" class="widget-id" value="<?php echo esc_attr($id_format); ?>" />
+ <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" />
+ <input type="hidden" name="widget-width" class="widget-width" value="<?php if (isset( $control['width'] )) echo esc_attr($control['width']); ?>" />
+ <input type="hidden" name="widget-height" class="widget-height" value="<?php if (isset( $control['height'] )) echo esc_attr($control['height']); ?>" />
+ <input type="hidden" name="widget_number" class="widget_number" value="<?php echo esc_attr($widget_number); ?>" />
+ <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" />
+ <input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr($add_new); ?>" />
+
+ <div class="widget-control-actions">
+ <div class="alignleft">
+ <a class="widget-control-remove" href="#remove"><?php _e('Delete'); ?></a> |
+ <a class="widget-control-close" href="#close"><?php _e('Close'); ?></a>
+ </div>
+ <div class="alignright<?php if ( 'noform' === $has_form ) echo ' widget-control-noform'; ?>">
+ <?php submit_button( __( 'Save' ), 'button-primary widget-control-save right', 'savewidget', false, array( 'id' => 'widget-' . esc_attr( $id_format ) . '-savewidget' ) ); ?>
+ <span class="spinner"></span>
+ </div>
+ <br class="clear" />
+ </div>
+ </form>
+ </div>
+
+ <div class="widget-description">
+<?php echo ( $widget_description = wp_widget_description($widget_id) ) ? "$widget_description\n" : "$widget_title\n"; ?>
+ </div>
+<?php
+ echo $sidebar_args['after_widget'];
+ return $sidebar_args;
+}
diff --git a/src/wp-admin/index.php b/src/wp-admin/index.php
new file mode 100644
index 0000000000..b476267cb8
--- /dev/null
+++ b/src/wp-admin/index.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Dashboard Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Bootstrap */
+require_once('./admin.php');
+
+/** Load WordPress dashboard API */
+require_once(ABSPATH . 'wp-admin/includes/dashboard.php');
+
+wp_dashboard_setup();
+
+wp_enqueue_script( 'dashboard' );
+if ( current_user_can( 'edit_theme_options' ) )
+ wp_enqueue_script( 'customize-loader' );
+if ( current_user_can( 'install_plugins' ) )
+ wp_enqueue_script( 'plugin-install' );
+if ( current_user_can( 'upload_files' ) )
+ wp_enqueue_script( 'media-upload' );
+add_thickbox();
+
+if ( wp_is_mobile() )
+ wp_enqueue_script( 'jquery-touch-punch' );
+
+$title = __('Dashboard');
+$parent_file = 'index.php';
+
+if ( is_user_admin() )
+ add_screen_option('layout_columns', array('max' => 4, 'default' => 1) );
+else
+ add_screen_option('layout_columns', array('max' => 4, 'default' => 2) );
+
+$help = '<p>' . __( 'Welcome to your WordPress Dashboard! This is the screen you will see when you log in to your site, and gives you access to all the site management features of WordPress. You can get help for any screen by clicking the Help tab in the upper corner.' ) . '</p>';
+
+// Not using chaining here, so as to be parseable by PHP4.
+$screen = get_current_screen();
+
+$screen->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __( 'Overview' ),
+ 'content' => $help,
+) );
+
+// Help tabs
+
+$help = '<p>' . __('The left-hand navigation menu provides links to all of the WordPress administration screens, with submenu items displayed on hover. You can minimize this menu to a narrow icon strip by clicking on the Collapse Menu arrow at the bottom.') . '</p>';
+$help .= '<p>' . __('Links in the Toolbar at the top of the screen connect your dashboard and the front end of your site, and provide access to your profile and helpful WordPress information.') . '</p>';
+
+$screen->add_help_tab( array(
+ 'id' => 'help-navigation',
+ 'title' => __('Navigation'),
+ 'content' => $help,
+) );
+
+$help = '<p>' . __('You can use the following controls to arrange your Dashboard screen to suit your workflow. This is true on most other administration screens as well.') . '</p>';
+$help .= '<p>' . __('<strong>Screen Options</strong> - Use the Screen Options tab to choose which Dashboard boxes to show, and how many columns to display.') . '</p>';
+$help .= '<p>' . __('<strong>Drag and Drop</strong> - To rearrange the boxes, drag and drop by clicking on the title bar of the selected box and releasing when you see a gray dotted-line rectangle appear in the location you want to place the box.') . '</p>';
+$help .= '<p>' . __('<strong>Box Controls</strong> - Click the title bar of the box to expand or collapse it. In addition, some boxes have configurable content, and will show a &#8220;Configure&#8221; link in the title bar if you hover over it.') . '</p>';
+
+$screen->add_help_tab( array(
+ 'id' => 'help-layout',
+ 'title' => __('Layout'),
+ 'content' => $help,
+) );
+
+$help = '<p>' . __('The boxes on your Dashboard screen are:') . '</p>';
+if ( current_user_can( 'edit_posts' ) )
+ $help .= '<p>' . __('<strong>Right Now</strong> - Displays a summary of the content on your site and identifies which theme and version of WordPress you are using.') . '</p>';
+if ( current_user_can( 'moderate_comments' ) )
+ $help .= '<p>' . __('<strong>Recent Comments</strong> - Shows the most recent comments on your posts (configurable, up to 30) and allows you to moderate them.') . '</p>';
+if ( current_user_can( 'publish_posts' ) )
+ $help .= '<p>' . __('<strong>Incoming Links</strong> - Shows links to your site found by Google Blog Search.') . '</p>';
+if ( current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
+ $help .= '<p>' . __('<strong>QuickPress</strong> - Allows you to create a new post and either publish it or save it as a draft.') . '</p>';
+ $help .= '<p>' . __('<strong>Recent Drafts</strong> - Displays links to the 5 most recent draft posts you&#8217;ve started.') . '</p>';
+}
+$help .= '<p>' . __('<strong>WordPress Blog</strong> - Latest news from the official WordPress project.') . '</p>';
+$help .= '<p>' . __('<strong>Other WordPress News</strong> - Shows the <a href="http://planet.wordpress.org" target="_blank">WordPress Planet</a> feed. You can configure it to show a different feed of your choosing.') . '</p>';
+if ( ! is_multisite() && current_user_can( 'install_plugins' ) )
+ $help .= '<p>' . __('<strong>Plugins</strong> - Features the most popular, newest, and recently updated plugins from the WordPress.org Plugin Directory.') . '</p>';
+if ( current_user_can( 'edit_theme_options' ) )
+ $help .= '<p>' . __('<strong>Welcome</strong> - Shows links for some of the most common tasks when setting up a new site.') . '</p>';
+
+$screen->add_help_tab( array(
+ 'id' => 'help-content',
+ 'title' => __('Content'),
+ 'content' => $help,
+) );
+
+unset( $help );
+
+$screen->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Dashboard_Screen" target="_blank">Documentation on Dashboard</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+);
+
+include (ABSPATH . 'wp-admin/admin-header.php');
+
+$today = current_time('mysql', 1);
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<?php if ( has_action( 'welcome_panel' ) && current_user_can( 'edit_theme_options' ) ) :
+ $classes = 'welcome-panel';
+
+ $option = get_user_meta( get_current_user_id(), 'show_welcome_panel', true );
+ // 0 = hide, 1 = toggled to show or single site creator, 2 = multisite site owner
+ $hide = 0 == $option || ( 2 == $option && wp_get_current_user()->user_email != get_option( 'admin_email' ) );
+ if ( $hide )
+ $classes .= ' hidden'; ?>
+
+ <div id="welcome-panel" class="<?php echo esc_attr( $classes ); ?>">
+ <?php wp_nonce_field( 'welcome-panel-nonce', 'welcomepanelnonce', false ); ?>
+ <a class="welcome-panel-close" href="<?php echo esc_url( admin_url( '?welcome=0' ) ); ?>"><?php _e( 'Dismiss' ); ?></a>
+ <?php do_action( 'welcome_panel' ); ?>
+ </div>
+<?php endif; ?>
+
+<div id="dashboard-widgets-wrap">
+
+<?php wp_dashboard(); ?>
+
+<div class="clear"></div>
+</div><!-- dashboard-widgets-wrap -->
+
+</div><!-- wrap -->
+
+<?php require(ABSPATH . 'wp-admin/admin-footer.php'); ?>
diff --git a/src/wp-admin/install-helper.php b/src/wp-admin/install-helper.php
new file mode 100644
index 0000000000..c98b28cc30
--- /dev/null
+++ b/src/wp-admin/install-helper.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * Plugins may load this file to gain access to special helper functions for
+ * plugin installation. This file is not included by WordPress and it is
+ * recommended, to prevent fatal errors, that this file is included using
+ * require_once().
+ *
+ * These functions are not optimized for speed, but they should only be used
+ * once in a while, so speed shouldn't be a concern. If it is and you are
+ * needing to use these functions a lot, you might experience time outs. If you
+ * do, then it is advised to just write the SQL code yourself.
+ *
+ * <code>
+ * check_column('wp_links', 'link_description', 'mediumtext');
+ * if (check_column($wpdb->comments, 'comment_author', 'tinytext'))
+ * echo "ok\n";
+ *
+ * $error_count = 0;
+ * $tablename = $wpdb->links;
+ * // check the column
+ * if (!check_column($wpdb->links, 'link_description', 'varchar(255)')) {
+ * $ddl = "ALTER TABLE $wpdb->links MODIFY COLUMN link_description varchar(255) NOT NULL DEFAULT '' ";
+ * $q = $wpdb->query($ddl);
+ * }
+ *
+ * if (check_column($wpdb->links, 'link_description', 'varchar(255)')) {
+ * $res .= $tablename . ' - ok <br />';
+ * } else {
+ * $res .= 'There was a problem with ' . $tablename . '<br />';
+ * ++$error_count;
+ * }
+ * </code>
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ */
+
+/** Load WordPress Bootstrap */
+require_once(dirname(dirname(__FILE__)).'/wp-load.php');
+
+if ( ! function_exists('maybe_create_table') ) :
+/**
+ * Create database table, if it doesn't already exist.
+ *
+ * @since 1.0.0
+ * @package WordPress
+ * @subpackage Plugin
+ * @uses $wpdb
+ *
+ * @param string $table_name Database table name.
+ * @param string $create_ddl Create database table SQL.
+ * @return bool False on error, true if already exists or success.
+ */
+function maybe_create_table($table_name, $create_ddl) {
+ global $wpdb;
+ foreach ($wpdb->get_col("SHOW TABLES",0) as $table ) {
+ if ($table == $table_name) {
+ return true;
+ }
+ }
+ //didn't find it try to create it.
+ $wpdb->query($create_ddl);
+ // we cannot directly tell that whether this succeeded!
+ foreach ($wpdb->get_col("SHOW TABLES",0) as $table ) {
+ if ($table == $table_name) {
+ return true;
+ }
+ }
+ return false;
+}
+endif;
+
+if ( ! function_exists('maybe_add_column') ) :
+/**
+ * Add column to database table, if column doesn't already exist in table.
+ *
+ * @since 1.0.0
+ * @package WordPress
+ * @subpackage Plugin
+ * @uses $wpdb
+ *
+ * @param string $table_name Database table name
+ * @param string $column_name Table column name
+ * @param string $create_ddl SQL to add column to table.
+ * @return bool False on failure. True, if already exists or was successful.
+ */
+function maybe_add_column($table_name, $column_name, $create_ddl) {
+ global $wpdb;
+ foreach ($wpdb->get_col("DESC $table_name",0) as $column ) {
+
+ if ($column == $column_name) {
+ return true;
+ }
+ }
+ //didn't find it try to create it.
+ $wpdb->query($create_ddl);
+ // we cannot directly tell that whether this succeeded!
+ foreach ($wpdb->get_col("DESC $table_name",0) as $column ) {
+ if ($column == $column_name) {
+ return true;
+ }
+ }
+ return false;
+}
+endif;
+
+/**
+ * Drop column from database table, if it exists.
+ *
+ * @since 1.0.0
+ * @package WordPress
+ * @subpackage Plugin
+ * @uses $wpdb
+ *
+ * @param string $table_name Table name
+ * @param string $column_name Column name
+ * @param string $drop_ddl SQL statement to drop column.
+ * @return bool False on failure, true on success or doesn't exist.
+ */
+function maybe_drop_column($table_name, $column_name, $drop_ddl) {
+ global $wpdb;
+ foreach ($wpdb->get_col("DESC $table_name",0) as $column ) {
+ if ($column == $column_name) {
+ //found it try to drop it.
+ $wpdb->query($drop_ddl);
+ // we cannot directly tell that whether this succeeded!
+ foreach ($wpdb->get_col("DESC $table_name",0) as $column ) {
+ if ($column == $column_name) {
+ return false;
+ }
+ }
+ }
+ }
+ // else didn't find it
+ return true;
+}
+
+/**
+ * Check column matches criteria.
+ *
+ * Uses the SQL DESC for retrieving the table info for the column. It will help
+ * understand the parameters, if you do more research on what column information
+ * is returned by the SQL statement. Pass in null to skip checking that
+ * criteria.
+ *
+ * Column names returned from DESC table are case sensitive and are listed:
+ * Field
+ * Type
+ * Null
+ * Key
+ * Default
+ * Extra
+ *
+ * @since 1.0.0
+ * @package WordPress
+ * @subpackage Plugin
+ *
+ * @param string $table_name Table name
+ * @param string $col_name Column name
+ * @param string $col_type Column type
+ * @param bool $is_null Optional. Check is null.
+ * @param mixed $key Optional. Key info.
+ * @param mixed $default Optional. Default value.
+ * @param mixed $extra Optional. Extra value.
+ * @return bool True, if matches. False, if not matching.
+ */
+function check_column($table_name, $col_name, $col_type, $is_null = null, $key = null, $default = null, $extra = null) {
+ global $wpdb;
+ $diffs = 0;
+ $results = $wpdb->get_results("DESC $table_name");
+
+ foreach ($results as $row ) {
+
+ if ($row->Field == $col_name) {
+ // got our column, check the params
+ if (($col_type != null) && ($row->Type != $col_type)) {
+ ++$diffs;
+ }
+ if (($is_null != null) && ($row->Null != $is_null)) {
+ ++$diffs;
+ }
+ if (($key != null) && ($row->Key != $key)) {
+ ++$diffs;
+ }
+ if (($default != null) && ($row->Default != $default)) {
+ ++$diffs;
+ }
+ if (($extra != null) && ($row->Extra != $extra)) {
+ ++$diffs;
+ }
+ if ($diffs > 0) {
+ return false;
+ }
+ return true;
+ } // end if found our column
+ }
+ return false;
+}
diff --git a/src/wp-admin/install.php b/src/wp-admin/install.php
new file mode 100644
index 0000000000..5c0ea44226
--- /dev/null
+++ b/src/wp-admin/install.php
@@ -0,0 +1,256 @@
+<?php
+/**
+ * WordPress Installer
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+// Sanity check.
+if ( false ) {
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>Error: PHP is not running</title>
+</head>
+<body class="wp-core-ui">
+ <h1 id="logo"><a href="http://wordpress.org/">WordPress</a></h1>
+ <h2>Error: PHP is not running</h2>
+ <p>WordPress requires that your web server is running PHP. Your server does not have PHP installed, or PHP is turned off.</p>
+</body>
+</html>
+<?php
+}
+
+/**
+ * We are installing WordPress.
+ *
+ * @since 1.5.1
+ * @var bool
+ */
+define( 'WP_INSTALLING', true );
+
+/** Load WordPress Bootstrap */
+require_once( dirname( dirname( __FILE__ ) ) . '/wp-load.php' );
+
+/** Load WordPress Administration Upgrade API */
+require_once( dirname( __FILE__ ) . '/includes/upgrade.php' );
+
+/** Load wpdb */
+require_once(dirname(dirname(__FILE__)) . '/wp-includes/wp-db.php');
+
+$step = isset( $_GET['step'] ) ? (int) $_GET['step'] : 0;
+
+/**
+ * Display install header.
+ *
+ * @since 2.5.0
+ * @package WordPress
+ * @subpackage Installer
+ */
+function display_header() {
+ header( 'Content-Type: text/html; charset=utf-8' );
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title><?php _e( 'WordPress &rsaquo; Installation' ); ?></title>
+ <?php
+ wp_admin_css( 'install', true );
+ ?>
+</head>
+<body class="wp-core-ui<?php if ( is_rtl() ) echo ' rtl'; ?>">
+<h1 id="logo"><a href="<?php echo esc_url( __( 'http://wordpress.org/' ) ); ?>"><?php _e( 'WordPress' ); ?></a></h1>
+
+<?php
+} // end display_header()
+
+/**
+ * Display installer setup form.
+ *
+ * @since 2.8.0
+ * @package WordPress
+ * @subpackage Installer
+ */
+function display_setup_form( $error = null ) {
+ global $wpdb;
+ $user_table = ( $wpdb->get_var("SHOW TABLES LIKE '$wpdb->users'") != null );
+
+ // Ensure that Blogs appear in search engines by default
+ $blog_public = 1;
+ if ( ! empty( $_POST ) )
+ $blog_public = isset( $_POST['blog_public'] );
+
+ $weblog_title = isset( $_POST['weblog_title'] ) ? trim( wp_unslash( $_POST['weblog_title'] ) ) : '';
+ $user_name = isset($_POST['user_name']) ? trim( wp_unslash( $_POST['user_name'] ) ) : '';
+ $admin_password = isset($_POST['admin_password']) ? trim( wp_unslash( $_POST['admin_password'] ) ) : '';
+ $admin_email = isset( $_POST['admin_email'] ) ? trim( wp_unslash( $_POST['admin_email'] ) ) : '';
+
+ if ( ! is_null( $error ) ) {
+?>
+<p class="message"><?php printf( __( '<strong>ERROR</strong>: %s' ), $error ); ?></p>
+<?php } ?>
+<form id="setup" method="post" action="install.php?step=2">
+ <table class="form-table">
+ <tr>
+ <th scope="row"><label for="weblog_title"><?php _e( 'Site Title' ); ?></label></th>
+ <td><input name="weblog_title" type="text" id="weblog_title" size="25" value="<?php echo esc_attr( $weblog_title ); ?>" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="user_login"><?php _e('Username'); ?></label></th>
+ <td>
+ <?php
+ if ( $user_table ) {
+ _e('User(s) already exists.');
+ } else {
+ ?><input name="user_name" type="text" id="user_login" size="25" value="<?php echo esc_attr( sanitize_user( $user_name, true ) ); ?>" />
+ <p><?php _e( 'Usernames can have only alphanumeric characters, spaces, underscores, hyphens, periods and the @ symbol.' ); ?></p>
+ <?php
+ } ?>
+ </td>
+ </tr>
+ <?php if ( ! $user_table ) : ?>
+ <tr>
+ <th scope="row">
+ <label for="admin_password"><?php _e('Password, twice'); ?></label>
+ <p><?php _e('A password will be automatically generated for you if you leave this blank.'); ?></p>
+ </th>
+ <td>
+ <input name="admin_password" type="password" id="pass1" size="25" value="" />
+ <p><input name="admin_password2" type="password" id="pass2" size="25" value="" /></p>
+ <div id="pass-strength-result"><?php _e('Strength indicator'); ?></div>
+ <p><?php _e('Hint: The password should be at least seven characters long. To make it stronger, use upper and lower case letters, numbers and symbols like ! " ? $ % ^ &amp; ).'); ?></p>
+ </td>
+ </tr>
+ <?php endif; ?>
+ <tr>
+ <th scope="row"><label for="admin_email"><?php _e( 'Your E-mail' ); ?></label></th>
+ <td><input name="admin_email" type="text" id="admin_email" size="25" value="<?php echo esc_attr( $admin_email ); ?>" />
+ <p><?php _e( 'Double-check your email address before continuing.' ); ?></p></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="blog_public"><?php _e( 'Privacy' ); ?></label></th>
+ <td colspan="2"><label><input type="checkbox" name="blog_public" value="1" <?php checked( $blog_public ); ?> /> <?php _e( 'Allow search engines to index this site.' ); ?></label></td>
+ </tr>
+ </table>
+ <p class="step"><input type="submit" name="Submit" value="<?php esc_attr_e( 'Install WordPress' ); ?>" class="button button-large" /></p>
+</form>
+<?php
+} // end display_setup_form()
+
+// Let's check to make sure WP isn't already installed.
+if ( is_blog_installed() ) {
+ display_header();
+ die( '<h1>' . __( 'Already Installed' ) . '</h1><p>' . __( 'You appear to have already installed WordPress. To reinstall please clear your old database tables first.' ) . '</p><p class="step"><a href="../wp-login.php" class="button button-large">' . __( 'Log In' ) . '</a></p></body></html>' );
+}
+
+$php_version = phpversion();
+$mysql_version = $wpdb->db_version();
+$php_compat = version_compare( $php_version, $required_php_version, '>=' );
+$mysql_compat = version_compare( $mysql_version, $required_mysql_version, '>=' ) || file_exists( WP_CONTENT_DIR . '/db.php' );
+
+if ( !$mysql_compat && !$php_compat )
+ $compat = sprintf( __( 'You cannot install because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.' ), $wp_version, $required_php_version, $required_mysql_version, $php_version, $mysql_version );
+elseif ( !$php_compat )
+ $compat = sprintf( __( 'You cannot install because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires PHP version %2$s or higher. You are running version %3$s.' ), $wp_version, $required_php_version, $php_version );
+elseif ( !$mysql_compat )
+ $compat = sprintf( __( 'You cannot install because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires MySQL version %2$s or higher. You are running version %3$s.' ), $wp_version, $required_mysql_version, $mysql_version );
+
+if ( !$mysql_compat || !$php_compat ) {
+ display_header();
+ die( '<h1>' . __( 'Insufficient Requirements' ) . '</h1><p>' . $compat . '</p></body></html>' );
+}
+
+if ( ! is_string( $wpdb->base_prefix ) || '' === $wpdb->base_prefix ) {
+ display_header();
+ die( '<h1>' . __( 'Configuration Error' ) . '</h1><p>' . __( 'Your <code>wp-config.php</code> file has an empty database table prefix, which is not supported.' ) . '</p></body></html>' );
+}
+
+switch($step) {
+ case 0: // Step 1
+ case 1: // Step 1, direct link.
+ display_header();
+?>
+<h1><?php _ex( 'Welcome', 'Howdy' ); ?></h1>
+<p><?php printf( __( 'Welcome to the famous five minute WordPress installation process! You may want to browse the <a href="%s">ReadMe documentation</a> at your leisure. Otherwise, just fill in the information below and you&#8217;ll be on your way to using the most extendable and powerful personal publishing platform in the world.' ), '../readme.html' ); ?></p>
+
+<h1><?php _e( 'Information needed' ); ?></h1>
+<p><?php _e( 'Please provide the following information. Don&#8217;t worry, you can always change these settings later.' ); ?></p>
+
+<?php
+ display_setup_form();
+ break;
+ case 2:
+ if ( ! empty( $wpdb->error ) )
+ wp_die( $wpdb->error->get_error_message() );
+
+ display_header();
+ // Fill in the data we gathered
+ $weblog_title = isset( $_POST['weblog_title'] ) ? trim( wp_unslash( $_POST['weblog_title'] ) ) : '';
+ $user_name = isset($_POST['user_name']) ? trim( wp_unslash( $_POST['user_name'] ) ) : 'admin';
+ $admin_password = isset($_POST['admin_password']) ? wp_unslash( $_POST['admin_password'] ) : '';
+ $admin_password_check = isset($_POST['admin_password2']) ? wp_unslash( $_POST['admin_password2'] ) : '';
+ $admin_email = isset( $_POST['admin_email'] ) ?trim( wp_unslash( $_POST['admin_email'] ) ) : '';
+ $public = isset( $_POST['blog_public'] ) ? (int) $_POST['blog_public'] : 0;
+ // check e-mail address
+ $error = false;
+ if ( empty( $user_name ) ) {
+ // TODO: poka-yoke
+ display_setup_form( __('you must provide a valid username.') );
+ $error = true;
+ } elseif ( $user_name != sanitize_user( $user_name, true ) ) {
+ display_setup_form( __('the username you provided has invalid characters.') );
+ $error = true;
+ } elseif ( $admin_password != $admin_password_check ) {
+ // TODO: poka-yoke
+ display_setup_form( __( 'your passwords do not match. Please try again' ) );
+ $error = true;
+ } else if ( empty( $admin_email ) ) {
+ // TODO: poka-yoke
+ display_setup_form( __( 'you must provide an e-mail address.' ) );
+ $error = true;
+ } elseif ( ! is_email( $admin_email ) ) {
+ // TODO: poka-yoke
+ display_setup_form( __( 'that isn&#8217;t a valid e-mail address. E-mail addresses look like: <code>username@example.com</code>' ) );
+ $error = true;
+ }
+
+ if ( $error === false ) {
+ $wpdb->show_errors();
+ $result = wp_install($weblog_title, $user_name, $admin_email, $public, '', $admin_password);
+ extract( $result, EXTR_SKIP );
+?>
+
+<h1><?php _e( 'Success!' ); ?></h1>
+
+<p><?php _e( 'WordPress has been installed. Were you expecting more steps? Sorry to disappoint.' ); ?></p>
+
+<table class="form-table install-success">
+ <tr>
+ <th><?php _e( 'Username' ); ?></th>
+ <td><?php echo esc_html( sanitize_user( $user_name, true ) ); ?></td>
+ </tr>
+ <tr>
+ <th><?php _e( 'Password' ); ?></th>
+ <td><?php
+ if ( ! empty( $password ) && empty($admin_password_check) )
+ echo '<code>'. esc_html($password) .'</code><br />';
+ echo "<p>$password_message</p>"; ?>
+ </td>
+ </tr>
+</table>
+
+<p class="step"><a href="../wp-login.php" class="button button-large"><?php _e( 'Log In' ); ?></a></p>
+
+<?php
+ }
+ break;
+}
+?>
+<script type="text/javascript">var t = document.getElementById('weblog_title'); if (t){ t.focus(); }</script>
+<?php wp_print_scripts( 'user-profile' ); ?>
+</body>
+</html>
diff --git a/src/wp-admin/js/accordion.js b/src/wp-admin/js/accordion.js
new file mode 100644
index 0000000000..7bc99ccca8
--- /dev/null
+++ b/src/wp-admin/js/accordion.js
@@ -0,0 +1,55 @@
+( function( $ ){
+
+ $( document ).ready( function () {
+
+ // Expand/Collapse on click
+ $( '.accordion-container' ).on( 'click keydown', '.accordion-section-title', function( e ) {
+ if ( e.type === 'keydown' && 13 !== e.which ) // "return" key
+ return;
+ e.preventDefault(); // Keep this AFTER the key filter above
+
+ accordionSwitch( $( this ) );
+ });
+
+ // Re-initialize accordion when screen options are toggled
+ $( '.hide-postbox-tog' ).click( function () {
+ accordionInit();
+ });
+
+ });
+
+ var accordionOptions = $( '.accordion-container li.accordion-section' ),
+ sectionContent = $( '.accordion-section-content' );
+
+ function accordionInit () {
+ // Rounded corners
+ accordionOptions.removeClass( 'top bottom' );
+ accordionOptions.filter( ':visible' ).first().addClass( 'top' );
+ accordionOptions.filter( ':visible' ).last().addClass( 'bottom' ).find( sectionContent ).addClass( 'bottom' );
+ }
+
+ function accordionSwitch ( el ) {
+ var section = el.closest( '.accordion-section' ),
+ siblings = section.closest( '.accordion-container' ).find( '.open' ),
+ content = section.find( sectionContent );
+
+ if ( section.hasClass( 'cannot-expand' ) )
+ return;
+
+ if ( section.hasClass( 'open' ) ) {
+ section.toggleClass( 'open' );
+ content.toggle( true ).slideToggle( 150 );
+ } else {
+ siblings.removeClass( 'open' );
+ siblings.find( sectionContent ).show().slideUp( 150 );
+ content.toggle( false ).slideToggle( 150 );
+ section.toggleClass( 'open' );
+ }
+
+ accordionInit();
+ }
+
+ // Initialize the accordion (currently just corner fixes)
+ accordionInit();
+
+})(jQuery);
diff --git a/src/wp-admin/js/cat.js b/src/wp-admin/js/cat.js
new file mode 100644
index 0000000000..772ab5a28c
--- /dev/null
+++ b/src/wp-admin/js/cat.js
@@ -0,0 +1,5 @@
+jQuery(document).ready( function($) {
+ var myConfirm = function() { return '' !== $('#newcat').val(); };
+ $('#jaxcat').prepend('<span id="ajaxcat"><input type="text" name="newcat" id="newcat" size="16" autocomplete="off"/><input type="button" name="Button" data-wp-lists="add:categorychecklist:jaxcat" id="catadd" value="' + catL10n.add + '"/><input type="hidden"/><input type="hidden"/><span id="howto">' + catL10n.how + '</span></span><span id="cat-ajax-response"></span>');
+ $('#categorychecklist').wpList( { alt: '', response: 'cat-ajax-response', confirm: myConfirm } );
+} );
diff --git a/src/wp-admin/js/categories.js b/src/wp-admin/js/categories.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/wp-admin/js/categories.js
diff --git a/src/wp-admin/js/color-picker.js b/src/wp-admin/js/color-picker.js
new file mode 100644
index 0000000000..d564754787
--- /dev/null
+++ b/src/wp-admin/js/color-picker.js
@@ -0,0 +1,132 @@
+( function( $, undef ){
+
+ // html stuff
+ var _before = '<a tabindex="0" class="wp-color-result" />',
+ _after = '<div class="wp-picker-holder" />',
+ _wrap = '<div class="wp-picker-container" />',
+ _button = '<input type="button" class="button button-small hidden" />';
+
+ // jQuery UI Widget constructor
+ var ColorPicker = {
+ options: {
+ defaultColor: false,
+ change: false,
+ clear: false,
+ hide: true,
+ palettes: true
+ },
+ _create: function() {
+ // bail early for unsupported Iris.
+ if ( ! $.support.iris )
+ return;
+ var self = this;
+ var el = self.element;
+
+ $.extend( self.options, el.data() );
+
+ self.initialValue = el.val();
+
+ // Set up HTML structure, hide things
+ el.addClass( 'wp-color-picker' ).hide().wrap( _wrap );
+ self.wrap = el.parent();
+ self.toggler = $( _before ).insertBefore( el ).css( { backgroundColor: self.initialValue } ).attr( "title", wpColorPickerL10n.pick ).attr( "data-current", wpColorPickerL10n.current );
+ self.pickerContainer = $( _after ).insertAfter( el );
+ self.button = $( _button );
+
+ if ( self.options.defaultColor )
+ self.button.addClass( 'wp-picker-default' ).val( wpColorPickerL10n.defaultString );
+ else
+ self.button.addClass( 'wp-picker-clear' ).val( wpColorPickerL10n.clear );
+
+ el.wrap('<span class="wp-picker-input-wrap" />').after(self.button);
+
+ el.iris( {
+ target: self.pickerContainer,
+ hide: true,
+ width: 255,
+ mode: 'hsv',
+ palettes: self.options.palettes,
+ change: function( event, ui ) {
+ self.toggler.css( { backgroundColor: ui.color.toString() } );
+ // check for a custom cb
+ if ( $.isFunction( self.options.change ) )
+ self.options.change.call( this, event, ui );
+ }
+ } );
+ el.val( self.initialValue );
+ self._addListeners();
+ if ( ! self.options.hide )
+ self.toggler.click();
+ },
+ _addListeners: function() {
+ var self = this;
+
+ self.toggler.click( function( event ){
+ event.stopPropagation();
+ self.element.toggle().iris( 'toggle' );
+ self.button.toggleClass('hidden');
+ self.toggler.toggleClass( 'wp-picker-open' );
+
+ // close picker when you click outside it
+ if ( self.toggler.hasClass( 'wp-picker-open' ) )
+ $( "body" ).on( 'click', { wrap: self.wrap, toggler: self.toggler }, self._bodyListener );
+ else
+ $( "body" ).off( 'click', self._bodyListener );
+ });
+
+ self.element.change(function( event ) {
+ var me = $(this),
+ val = me.val();
+ // Empty = clear
+ if ( val === '' || val === '#' ) {
+ self.toggler.css('backgroundColor', '');
+ // fire clear callback if we have one
+ if ( $.isFunction( self.options.clear ) )
+ self.options.clear.call( this, event );
+ }
+ });
+
+ // open a keyboard-focused closed picker with space or enter
+ self.toggler.on('keyup', function( e ) {
+ if ( e.keyCode === 13 || e.keyCode === 32 ) {
+ e.preventDefault();
+ self.toggler.trigger('click').next().focus();
+ }
+ });
+
+ self.button.click( function( event ) {
+ var me = $(this);
+ if ( me.hasClass( 'wp-picker-clear' ) ) {
+ self.element.val( '' );
+ self.toggler.css('backgroundColor', '');
+ if ( $.isFunction( self.options.clear ) )
+ self.options.clear.call( this, event );
+ } else if ( me.hasClass( 'wp-picker-default' ) ) {
+ self.element.val( self.options.defaultColor ).change();
+ }
+ });
+ },
+ _bodyListener: function( event ) {
+ if ( ! event.data.wrap.find( event.target ).length )
+ event.data.toggler.click();
+ },
+ // $("#input").wpColorPicker('color') returns the current color
+ // $("#input").wpColorPicker('color', '#bada55') to set
+ color: function( newColor ) {
+ if ( newColor === undef )
+ return this.element.iris( "option", "color" );
+
+ this.element.iris( "option", "color", newColor );
+ },
+ //$("#input").wpColorPicker('defaultColor') returns the current default color
+ //$("#input").wpColorPicker('defaultColor', newDefaultColor) to set
+ defaultColor: function( newDefaultColor ) {
+ if ( newDefaultColor === undef )
+ return this.options.defaultColor;
+
+ this.options.defaultColor = newDefaultColor;
+ }
+ }
+
+ $.widget( 'wp.wpColorPicker', ColorPicker );
+}( jQuery ) ); \ No newline at end of file
diff --git a/src/wp-admin/js/comment.js b/src/wp-admin/js/comment.js
new file mode 100644
index 0000000000..f9d93bfaba
--- /dev/null
+++ b/src/wp-admin/js/comment.js
@@ -0,0 +1,49 @@
+jQuery(document).ready( function($) {
+
+ postboxes.add_postbox_toggles('comment');
+
+ var stamp = $('#timestamp').html();
+ $('.edit-timestamp').click(function () {
+ if ($('#timestampdiv').is(":hidden")) {
+ $('#timestampdiv').slideDown("normal");
+ $('.edit-timestamp').hide();
+ }
+ return false;
+ });
+
+ $('.cancel-timestamp').click(function() {
+ $('#timestampdiv').slideUp("normal");
+ $('#mm').val($('#hidden_mm').val());
+ $('#jj').val($('#hidden_jj').val());
+ $('#aa').val($('#hidden_aa').val());
+ $('#hh').val($('#hidden_hh').val());
+ $('#mn').val($('#hidden_mn').val());
+ $('#timestamp').html(stamp);
+ $('.edit-timestamp').show();
+ return false;
+ });
+
+ $('.save-timestamp').click(function () { // crazyhorse - multiple ok cancels
+ var aa = $('#aa').val(), mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val(),
+ newD = new Date( aa, mm - 1, jj, hh, mn );
+
+ if ( newD.getFullYear() != aa || (1 + newD.getMonth()) != mm || newD.getDate() != jj || newD.getMinutes() != mn ) {
+ $('.timestamp-wrap', '#timestampdiv').addClass('form-invalid');
+ return false;
+ } else {
+ $('.timestamp-wrap', '#timestampdiv').removeClass('form-invalid');
+ }
+
+ $('#timestampdiv').slideUp("normal");
+ $('.edit-timestamp').show();
+ $('#timestamp').html(
+ commentL10n.submittedOn + ' <b>' +
+ $( '#mm option[value="' + mm + '"]' ).text() + ' ' +
+ jj + ', ' +
+ aa + ' @ ' +
+ hh + ':' +
+ mn + '</b> '
+ );
+ return false;
+ });
+});
diff --git a/src/wp-admin/js/common.js b/src/wp-admin/js/common.js
new file mode 100644
index 0000000000..b1327f9973
--- /dev/null
+++ b/src/wp-admin/js/common.js
@@ -0,0 +1,433 @@
+var showNotice, adminMenu, columns, validateForm, screenMeta;
+(function($){
+// Removed in 3.3.
+// (perhaps) needed for back-compat
+adminMenu = {
+ init : function() {},
+ fold : function() {},
+ restoreMenuState : function() {},
+ toggle : function() {},
+ favorites : function() {}
+};
+
+// show/hide/save table columns
+columns = {
+ init : function() {
+ var that = this;
+ $('.hide-column-tog', '#adv-settings').click( function() {
+ var $t = $(this), column = $t.val();
+ if ( $t.prop('checked') )
+ that.checked(column);
+ else
+ that.unchecked(column);
+
+ columns.saveManageColumnsState();
+ });
+ },
+
+ saveManageColumnsState : function() {
+ var hidden = this.hidden();
+ $.post(ajaxurl, {
+ action: 'hidden-columns',
+ hidden: hidden,
+ screenoptionnonce: $('#screenoptionnonce').val(),
+ page: pagenow
+ });
+ },
+
+ checked : function(column) {
+ $('.column-' + column).show();
+ this.colSpanChange(+1);
+ },
+
+ unchecked : function(column) {
+ $('.column-' + column).hide();
+ this.colSpanChange(-1);
+ },
+
+ hidden : function() {
+ return $('.manage-column').filter(':hidden').map(function() { return this.id; }).get().join(',');
+ },
+
+ useCheckboxesForHidden : function() {
+ this.hidden = function(){
+ return $('.hide-column-tog').not(':checked').map(function() {
+ var id = this.id;
+ return id.substring( id, id.length - 5 );
+ }).get().join(',');
+ };
+ },
+
+ colSpanChange : function(diff) {
+ var $t = $('table').find('.colspanchange'), n;
+ if ( !$t.length )
+ return;
+ n = parseInt( $t.attr('colspan'), 10 ) + diff;
+ $t.attr('colspan', n.toString());
+ }
+}
+
+$(document).ready(function(){columns.init();});
+
+validateForm = function( form ) {
+ return !$( form ).find('.form-required').filter( function() { return $('input:visible', this).val() == ''; } ).addClass( 'form-invalid' ).find('input:visible').change( function() { $(this).closest('.form-invalid').removeClass( 'form-invalid' ); } ).size();
+}
+
+// stub for doing better warnings
+showNotice = {
+ warn : function() {
+ var msg = commonL10n.warnDelete || '';
+ if ( confirm(msg) ) {
+ return true;
+ }
+
+ return false;
+ },
+
+ note : function(text) {
+ alert(text);
+ }
+};
+
+screenMeta = {
+ element: null, // #screen-meta
+ toggles: null, // .screen-meta-toggle
+ page: null, // #wpcontent
+
+ init: function() {
+ this.element = $('#screen-meta');
+ this.toggles = $('.screen-meta-toggle a');
+ this.page = $('#wpcontent');
+
+ this.toggles.click( this.toggleEvent );
+ },
+
+ toggleEvent: function( e ) {
+ var panel = $( this.href.replace(/.+#/, '#') );
+ e.preventDefault();
+
+ if ( !panel.length )
+ return;
+
+ if ( panel.is(':visible') )
+ screenMeta.close( panel, $(this) );
+ else
+ screenMeta.open( panel, $(this) );
+ },
+
+ open: function( panel, link ) {
+
+ $('.screen-meta-toggle').not( link.parent() ).css('visibility', 'hidden');
+
+ panel.parent().show();
+ panel.slideDown( 'fast', function() {
+ panel.focus();
+ link.addClass('screen-meta-active').attr('aria-expanded', true);
+ });
+ },
+
+ close: function( panel, link ) {
+ panel.slideUp( 'fast', function() {
+ link.removeClass('screen-meta-active').attr('aria-expanded', false);
+ $('.screen-meta-toggle').css('visibility', '');
+ panel.parent().hide();
+ });
+ }
+};
+
+/**
+ * Help tabs.
+ */
+$('.contextual-help-tabs').delegate('a', 'click focus', function(e) {
+ var link = $(this),
+ panel;
+
+ e.preventDefault();
+
+ // Don't do anything if the click is for the tab already showing.
+ if ( link.is('.active a') )
+ return false;
+
+ // Links
+ $('.contextual-help-tabs .active').removeClass('active');
+ link.parent('li').addClass('active');
+
+ panel = $( link.attr('href') );
+
+ // Panels
+ $('.help-tab-content').not( panel ).removeClass('active').hide();
+ panel.addClass('active').show();
+});
+
+$(document).ready( function() {
+ var lastClicked = false, checks, first, last, checked, menu = $('#adminmenu'), mobileEvent,
+ pageInput = $('input.current-page'), currentPage = pageInput.val();
+
+ // when the menu is folded, make the fly-out submenu header clickable
+ menu.on('click.wp-submenu-head', '.wp-submenu-head', function(e){
+ $(e.target).parent().siblings('a').get(0).click();
+ });
+
+ $('#collapse-menu').on('click.collapse-menu', function(e){
+ var body = $( document.body ), respWidth;
+
+ // reset any compensation for submenus near the bottom of the screen
+ $('#adminmenu div.wp-submenu').css('margin-top', '');
+
+ // WebKit excludes the width of the vertical scrollbar when applying the CSS "@media screen and (max-width: ...)"
+ // and matches $(window).width().
+ // Firefox and IE > 8 include the scrollbar width, so after the jQuery normalization
+ // $(window).width() is 884px but window.innerWidth is 900px.
+ // (using window.innerWidth also excludes IE < 9)
+ respWidth = navigator.userAgent.indexOf('AppleWebKit/') > -1 ? $(window).width() : window.innerWidth;
+
+ if ( respWidth && respWidth < 900 ) {
+ if ( body.hasClass('auto-fold') ) {
+ body.removeClass('auto-fold').removeClass('folded');
+ setUserSetting('unfold', 1);
+ deleteUserSetting('mfold');
+ } else {
+ body.addClass('auto-fold');
+ deleteUserSetting('unfold');
+ }
+ } else {
+ if ( body.hasClass('folded') ) {
+ body.removeClass('folded');
+ deleteUserSetting('mfold');
+ } else {
+ body.addClass('folded');
+ setUserSetting('mfold', 'f');
+ }
+ }
+ });
+
+ if ( 'ontouchstart' in window || /IEMobile\/[1-9]/.test(navigator.userAgent) ) { // touch screen device
+ // iOS Safari works with touchstart, the rest work with click
+ mobileEvent = /Mobile\/.+Safari/.test(navigator.userAgent) ? 'touchstart' : 'click';
+
+ // close any open submenus when touch/click is not on the menu
+ $(document.body).on( mobileEvent+'.wp-mobile-hover', function(e) {
+ if ( !$(e.target).closest('#adminmenu').length )
+ menu.find('li.wp-has-submenu.opensub').removeClass('opensub');
+ });
+
+ menu.find('a.wp-has-submenu').on( mobileEvent+'.wp-mobile-hover', function(e) {
+ var el = $(this), parent = el.parent();
+
+ // Show the sub instead of following the link if:
+ // - the submenu is not open
+ // - the submenu is not shown inline or the menu is not folded
+ if ( !parent.hasClass('opensub') && ( !parent.hasClass('wp-menu-open') || parent.width() < 40 ) ) {
+ e.preventDefault();
+ menu.find('li.opensub').removeClass('opensub');
+ parent.addClass('opensub');
+ }
+ });
+ }
+
+ menu.find('li.wp-has-submenu').hoverIntent({
+ over: function(e){
+ var b, h, o, f, m = $(this).find('.wp-submenu'), menutop, wintop, maxtop, top = parseInt( m.css('top'), 10 );
+
+ if ( isNaN(top) || top > -5 ) // meaning the submenu is visible
+ return;
+
+ menutop = $(this).offset().top;
+ wintop = $(window).scrollTop();
+ maxtop = menutop - wintop - 30; // max = make the top of the sub almost touch admin bar
+
+ b = menutop + m.height() + 1; // Bottom offset of the menu
+ h = $('#wpwrap').height(); // Height of the entire page
+ o = 60 + b - h;
+ f = $(window).height() + wintop - 15; // The fold
+
+ if ( f < (b - o) )
+ o = b - f;
+
+ if ( o > maxtop )
+ o = maxtop;
+
+ if ( o > 1 )
+ m.css('margin-top', '-'+o+'px');
+ else
+ m.css('margin-top', '');
+
+ menu.find('li.menu-top').removeClass('opensub');
+ $(this).addClass('opensub');
+ },
+ out: function(){
+ $(this).removeClass('opensub').find('.wp-submenu').css('margin-top', '');
+ },
+ timeout: 200,
+ sensitivity: 7,
+ interval: 90
+ });
+
+ menu.on('focus.adminmenu', '.wp-submenu a', function(e){
+ $(e.target).closest('li.menu-top').addClass('opensub');
+ }).on('blur.adminmenu', '.wp-submenu a', function(e){
+ $(e.target).closest('li.menu-top').removeClass('opensub');
+ });
+
+ // Move .updated and .error alert boxes. Don't move boxes designed to be inline.
+ $('div.wrap h2:first').nextAll('div.updated, div.error').addClass('below-h2');
+ $('div.updated, div.error').not('.below-h2, .inline').insertAfter( $('div.wrap h2:first') );
+
+ // Init screen meta
+ screenMeta.init();
+
+ // check all checkboxes
+ $('tbody').children().children('.check-column').find(':checkbox').click( function(e) {
+ if ( 'undefined' == e.shiftKey ) { return true; }
+ if ( e.shiftKey ) {
+ if ( !lastClicked ) { return true; }
+ checks = $( lastClicked ).closest( 'form' ).find( ':checkbox' );
+ first = checks.index( lastClicked );
+ last = checks.index( this );
+ checked = $(this).prop('checked');
+ if ( 0 < first && 0 < last && first != last ) {
+ checks.slice( first, last ).prop( 'checked', function(){
+ if ( $(this).closest('tr').is(':visible') )
+ return checked;
+
+ return false;
+ });
+ }
+ }
+ lastClicked = this;
+
+ // toggle "check all" checkboxes
+ var unchecked = $(this).closest('tbody').find(':checkbox').filter(':visible').not(':checked');
+ $(this).closest('table').children('thead, tfoot').find(':checkbox').prop('checked', function() {
+ return ( 0 == unchecked.length );
+ });
+
+ return true;
+ });
+
+ $('thead, tfoot').find('.check-column :checkbox').click( function(e) {
+ var c = $(this).prop('checked'),
+ kbtoggle = 'undefined' == typeof toggleWithKeyboard ? false : toggleWithKeyboard,
+ toggle = e.shiftKey || kbtoggle;
+
+ $(this).closest( 'table' ).children( 'tbody' ).filter(':visible')
+ .children().children('.check-column').find(':checkbox')
+ .prop('checked', function() {
+ if ( $(this).is(':hidden') )
+ return false;
+ if ( toggle )
+ return $(this).prop( 'checked' );
+ else if (c)
+ return true;
+ return false;
+ });
+
+ $(this).closest('table').children('thead, tfoot').filter(':visible')
+ .children().children('.check-column').find(':checkbox')
+ .prop('checked', function() {
+ if ( toggle )
+ return false;
+ else if (c)
+ return true;
+ return false;
+ });
+ });
+
+ $('#default-password-nag-no').click( function() {
+ setUserSetting('default_password_nag', 'hide');
+ $('div.default-password-nag').hide();
+ return false;
+ });
+
+ // tab in textareas
+ $('#newcontent').bind('keydown.wpevent_InsertTab', function(e) {
+ var el = e.target, selStart, selEnd, val, scroll, sel;
+
+ if ( e.keyCode == 27 ) { // escape key
+ $(el).data('tab-out', true);
+ return;
+ }
+
+ if ( e.keyCode != 9 || e.ctrlKey || e.altKey || e.shiftKey ) // tab key
+ return;
+
+ if ( $(el).data('tab-out') ) {
+ $(el).data('tab-out', false);
+ return;
+ }
+
+ selStart = el.selectionStart;
+ selEnd = el.selectionEnd;
+ val = el.value;
+
+ try {
+ this.lastKey = 9; // not a standard DOM property, lastKey is to help stop Opera tab event. See blur handler below.
+ } catch(err) {}
+
+ if ( document.selection ) {
+ el.focus();
+ sel = document.selection.createRange();
+ sel.text = '\t';
+ } else if ( selStart >= 0 ) {
+ scroll = this.scrollTop;
+ el.value = val.substring(0, selStart).concat('\t', val.substring(selEnd) );
+ el.selectionStart = el.selectionEnd = selStart + 1;
+ this.scrollTop = scroll;
+ }
+
+ if ( e.stopPropagation )
+ e.stopPropagation();
+ if ( e.preventDefault )
+ e.preventDefault();
+ });
+
+ $('#newcontent').bind('blur.wpevent_InsertTab', function(e) {
+ if ( this.lastKey && 9 == this.lastKey )
+ this.focus();
+ });
+
+ if ( pageInput.length ) {
+ pageInput.closest('form').submit( function(e){
+
+ // Reset paging var for new filters/searches but not for bulk actions. See #17685.
+ if ( $('select[name="action"]').val() == -1 && $('select[name="action2"]').val() == -1 && pageInput.val() == currentPage )
+ pageInput.val('1');
+ });
+ }
+
+ // Scroll into view when focused
+ $('#contextual-help-link, #show-settings-link').on( 'focus.scroll-into-view', function(e){
+ if ( e.target.scrollIntoView )
+ e.target.scrollIntoView(false);
+ });
+
+ // Disable upload buttons until files are selected
+ (function(){
+ var button, input, form = $('form.wp-upload-form');
+ if ( ! form.length )
+ return;
+ button = form.find('input[type="submit"]');
+ input = form.find('input[type="file"]');
+
+ function toggleUploadButton() {
+ button.prop('disabled', '' === input.map( function() {
+ return $(this).val();
+ }).get().join(''));
+ }
+ toggleUploadButton();
+ input.on('change', toggleUploadButton);
+ })();
+});
+
+// internal use
+$(document).bind( 'wp_CloseOnEscape', function( e, data ) {
+ if ( typeof(data.cb) != 'function' )
+ return;
+
+ if ( typeof(data.condition) != 'function' || data.condition() )
+ data.cb();
+
+ return true;
+});
+
+})(jQuery);
diff --git a/src/wp-admin/js/custom-background.js b/src/wp-admin/js/custom-background.js
new file mode 100644
index 0000000000..c41ca6b00b
--- /dev/null
+++ b/src/wp-admin/js/custom-background.js
@@ -0,0 +1,74 @@
+(function($) {
+ $(document).ready(function() {
+ var bgImage = $("#custom-background-image"),
+ frame;
+
+ $('#background-color').wpColorPicker({
+ change: function( event, ui ) {
+ bgImage.css('background-color', ui.color.toString());
+ },
+ clear: function() {
+ bgImage.css('background-color', '');
+ }
+ });
+
+ $('input[name="background-position-x"]').change(function() {
+ bgImage.css('background-position', $(this).val() + ' top');
+ });
+
+ $('input[name="background-repeat"]').change(function() {
+ bgImage.css('background-repeat', $(this).val());
+ });
+
+ $('#choose-from-library-link').click( function( event ) {
+ var $el = $(this);
+
+ event.preventDefault();
+
+ // If the media frame already exists, reopen it.
+ if ( frame ) {
+ frame.open();
+ return;
+ }
+
+ // Create the media frame.
+ frame = wp.media.frames.customBackground = wp.media({
+ // Set the title of the modal.
+ title: $el.data('choose'),
+
+ // Tell the modal to show only images.
+ library: {
+ type: 'image'
+ },
+
+ // Customize the submit button.
+ button: {
+ // Set the text of the button.
+ text: $el.data('update'),
+ // Tell the button not to close the modal, since we're
+ // going to refresh the page when the image is selected.
+ close: false
+ }
+ });
+
+ // When an image is selected, run a callback.
+ frame.on( 'select', function() {
+ // Grab the selected attachment.
+ var attachment = frame.state().get('selection').first();
+
+ // Run an AJAX request to set the background image.
+ $.post( ajaxurl, {
+ action: 'set-background-image',
+ attachment_id: attachment.id,
+ size: 'full'
+ }).done( function() {
+ // When the request completes, reload the window.
+ window.location.reload();
+ });
+ });
+
+ // Finally, open the modal.
+ frame.open();
+ });
+ });
+})(jQuery); \ No newline at end of file
diff --git a/src/wp-admin/js/custom-fields.js b/src/wp-admin/js/custom-fields.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/wp-admin/js/custom-fields.js
diff --git a/src/wp-admin/js/custom-header.js b/src/wp-admin/js/custom-header.js
new file mode 100644
index 0000000000..d93ac3895c
--- /dev/null
+++ b/src/wp-admin/js/custom-header.js
@@ -0,0 +1,60 @@
+(function($) {
+ var frame;
+
+ $( function() {
+ // Fetch available headers and apply jQuery.masonry
+ // once the images have loaded.
+ var $headers = $('.available-headers');
+
+ $headers.imagesLoaded( function() {
+ $headers.masonry({
+ itemSelector: '.default-header',
+ isRTL: !! ( 'undefined' != typeof isRtl && isRtl )
+ });
+ });
+
+ // Build the choose from library frame.
+ $('#choose-from-library-link').click( function( event ) {
+ var $el = $(this);
+ event.preventDefault();
+
+ // If the media frame already exists, reopen it.
+ if ( frame ) {
+ frame.open();
+ return;
+ }
+
+ // Create the media frame.
+ frame = wp.media.frames.customHeader = wp.media({
+ // Set the title of the modal.
+ title: $el.data('choose'),
+
+ // Tell the modal to show only images.
+ library: {
+ type: 'image'
+ },
+
+ // Customize the submit button.
+ button: {
+ // Set the text of the button.
+ text: $el.data('update'),
+ // Tell the button not to close the modal, since we're
+ // going to refresh the page when the image is selected.
+ close: false
+ }
+ });
+
+ // When an image is selected, run a callback.
+ frame.on( 'select', function() {
+ // Grab the selected attachment.
+ var attachment = frame.state().get('selection').first(),
+ link = $el.data('updateLink');
+
+ // Tell the browser to navigate to the crop step.
+ window.location = link + '&file=' + attachment.id;
+ });
+
+ frame.open();
+ });
+ });
+}(jQuery));
diff --git a/src/wp-admin/js/customize-controls.js b/src/wp-admin/js/customize-controls.js
new file mode 100644
index 0000000000..01fffbac17
--- /dev/null
+++ b/src/wp-admin/js/customize-controls.js
@@ -0,0 +1,1004 @@
+(function( exports, $ ){
+ var api = wp.customize;
+
+ /*
+ * @param options
+ * - previewer - The Previewer instance to sync with.
+ * - transport - The transport to use for previewing. Supports 'refresh' and 'postMessage'.
+ */
+ api.Setting = api.Value.extend({
+ initialize: function( id, value, options ) {
+ var element;
+
+ api.Value.prototype.initialize.call( this, value, options );
+
+ this.id = id;
+ this.transport = this.transport || 'refresh';
+
+ this.bind( this.preview );
+ },
+ preview: function() {
+ switch ( this.transport ) {
+ case 'refresh':
+ return this.previewer.refresh();
+ case 'postMessage':
+ return this.previewer.send( 'setting', [ this.id, this() ] );
+ }
+ }
+ });
+
+ api.Control = api.Class.extend({
+ initialize: function( id, options ) {
+ var control = this,
+ nodes, radios, settings;
+
+ this.params = {};
+ $.extend( this, options || {} );
+
+ this.id = id;
+ this.selector = '#customize-control-' + id.replace( ']', '' ).replace( '[', '-' );
+ this.container = $( this.selector );
+
+ settings = $.map( this.params.settings, function( value ) {
+ return value;
+ });
+
+ api.apply( api, settings.concat( function() {
+ var key;
+
+ control.settings = {};
+ for ( key in control.params.settings ) {
+ control.settings[ key ] = api( control.params.settings[ key ] );
+ }
+
+ control.setting = control.settings['default'] || null;
+ control.ready();
+ }) );
+
+ control.elements = [];
+
+ nodes = this.container.find('[data-customize-setting-link]');
+ radios = {};
+
+ nodes.each( function() {
+ var node = $(this),
+ name;
+
+ if ( node.is(':radio') ) {
+ name = node.prop('name');
+ if ( radios[ name ] )
+ return;
+
+ radios[ name ] = true;
+ node = nodes.filter( '[name="' + name + '"]' );
+ }
+
+ api( node.data('customizeSettingLink'), function( setting ) {
+ var element = new api.Element( node );
+ control.elements.push( element );
+ element.sync( setting );
+ element.set( setting() );
+ });
+ });
+ },
+
+ ready: function() {},
+
+ dropdownInit: function() {
+ var control = this,
+ statuses = this.container.find('.dropdown-status'),
+ params = this.params,
+ update = function( to ) {
+ if ( typeof to === 'string' && params.statuses && params.statuses[ to ] )
+ statuses.html( params.statuses[ to ] ).show();
+ else
+ statuses.hide();
+ };
+
+ var toggleFreeze = false;
+
+ // Support the .dropdown class to open/close complex elements
+ this.container.on( 'click keydown', '.dropdown', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ event.preventDefault();
+
+ if (!toggleFreeze)
+ control.container.toggleClass('open');
+
+ if ( control.container.hasClass('open') )
+ control.container.parent().parent().find('li.library-selected').focus();
+
+ // Don't want to fire focus and click at same time
+ toggleFreeze = true;
+ setTimeout(function () {
+ toggleFreeze = false;
+ }, 400);
+ });
+
+ this.setting.bind( update );
+ update( this.setting() );
+ }
+ });
+
+ api.ColorControl = api.Control.extend({
+ ready: function() {
+ var control = this,
+ picker = this.container.find('.color-picker-hex');
+
+ picker.val( control.setting() ).wpColorPicker({
+ change: function( event, options ) {
+ control.setting.set( picker.wpColorPicker('color') );
+ },
+ clear: function() {
+ control.setting.set( false );
+ }
+ });
+ }
+ });
+
+ api.UploadControl = api.Control.extend({
+ ready: function() {
+ var control = this;
+
+ this.params.removed = this.params.removed || '';
+
+ this.success = $.proxy( this.success, this );
+
+ this.uploader = $.extend({
+ container: this.container,
+ browser: this.container.find('.upload'),
+ dropzone: this.container.find('.upload-dropzone'),
+ success: this.success,
+ plupload: {},
+ params: {}
+ }, this.uploader || {} );
+
+ if ( control.params.extensions ) {
+ control.uploader.plupload.filters = [{
+ title: api.l10n.allowedFiles,
+ extensions: control.params.extensions
+ }];
+ }
+
+ if ( control.params.context )
+ control.uploader.params['post_data[context]'] = this.params.context;
+
+ if ( api.settings.theme.stylesheet )
+ control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet;
+
+ this.uploader = new wp.Uploader( this.uploader );
+
+ this.remover = this.container.find('.remove');
+ this.remover.on( 'click keydown', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ control.setting.set( control.params.removed );
+ event.preventDefault();
+ });
+
+ this.removerVisibility = $.proxy( this.removerVisibility, this );
+ this.setting.bind( this.removerVisibility );
+ this.removerVisibility( this.setting.get() );
+ },
+ success: function( attachment ) {
+ this.setting.set( attachment.get('url') );
+ },
+ removerVisibility: function( to ) {
+ this.remover.toggle( to != this.params.removed );
+ }
+ });
+
+ api.ImageControl = api.UploadControl.extend({
+ ready: function() {
+ var control = this,
+ panels;
+
+ this.uploader = {
+ init: function( up ) {
+ var fallback, button;
+
+ if ( this.supports.dragdrop )
+ return;
+
+ // Maintain references while wrapping the fallback button.
+ fallback = control.container.find( '.upload-fallback' );
+ button = fallback.children().detach();
+
+ this.browser.detach().empty().append( button );
+ fallback.append( this.browser ).show();
+ }
+ };
+
+ api.UploadControl.prototype.ready.call( this );
+
+ this.thumbnail = this.container.find('.preview-thumbnail img');
+ this.thumbnailSrc = $.proxy( this.thumbnailSrc, this );
+ this.setting.bind( this.thumbnailSrc );
+
+ this.library = this.container.find('.library');
+
+ // Generate tab objects
+ this.tabs = {};
+ panels = this.library.find('.library-content');
+
+ this.library.children('ul').children('li').each( function() {
+ var link = $(this),
+ id = link.data('customizeTab'),
+ panel = panels.filter('[data-customize-tab="' + id + '"]');
+
+ control.tabs[ id ] = {
+ both: link.add( panel ),
+ link: link,
+ panel: panel
+ };
+ });
+
+ // Bind tab switch events
+ this.library.children('ul').on( 'click keydown', 'li', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ var id = $(this).data('customizeTab'),
+ tab = control.tabs[ id ];
+
+ event.preventDefault();
+
+ if ( tab.link.hasClass('library-selected') )
+ return;
+
+ control.selected.both.removeClass('library-selected');
+ control.selected = tab;
+ control.selected.both.addClass('library-selected');
+ });
+
+ // Bind events to switch image urls.
+ this.library.on( 'click keydown', 'a', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ var value = $(this).data('customizeImageValue');
+
+ if ( value ) {
+ control.setting.set( value );
+ event.preventDefault();
+ }
+ });
+
+ if ( this.tabs.uploaded ) {
+ this.tabs.uploaded.target = this.library.find('.uploaded-target');
+ if ( ! this.tabs.uploaded.panel.find('.thumbnail').length )
+ this.tabs.uploaded.both.addClass('hidden');
+ }
+
+ // Select a tab
+ panels.each( function() {
+ var tab = control.tabs[ $(this).data('customizeTab') ];
+
+ // Select the first visible tab.
+ if ( ! tab.link.hasClass('hidden') ) {
+ control.selected = tab;
+ tab.both.addClass('library-selected');
+ return false;
+ }
+ });
+
+ this.dropdownInit();
+ },
+ success: function( attachment ) {
+ api.UploadControl.prototype.success.call( this, attachment );
+
+ // Add the uploaded image to the uploaded tab.
+ if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) {
+ this.tabs.uploaded.both.removeClass('hidden');
+
+ // @todo: Do NOT store this on the attachment model. That is bad.
+ attachment.element = $( '<a href="#" class="thumbnail"></a>' )
+ .data( 'customizeImageValue', attachment.get('url') )
+ .append( '<img src="' + attachment.get('url')+ '" />' )
+ .appendTo( this.tabs.uploaded.target );
+ }
+ },
+ thumbnailSrc: function( to ) {
+ if ( /^(https?:)?\/\//.test( to ) )
+ this.thumbnail.prop( 'src', to ).show();
+ else
+ this.thumbnail.hide();
+ }
+ });
+
+ // Change objects contained within the main customize object to Settings.
+ api.defaultConstructor = api.Setting;
+
+ // Create the collection of Control objects.
+ api.control = new api.Values({ defaultConstructor: api.Control });
+
+ api.PreviewFrame = api.Messenger.extend({
+ sensitivity: 2000,
+
+ initialize: function( params, options ) {
+ var deferred = $.Deferred(),
+ self = this;
+
+ // This is the promise object.
+ deferred.promise( this );
+
+ this.container = params.container;
+ this.signature = params.signature;
+
+ $.extend( params, { channel: api.PreviewFrame.uuid() });
+
+ api.Messenger.prototype.initialize.call( this, params, options );
+
+ this.add( 'previewUrl', params.previewUrl );
+
+ this.query = $.extend( params.query || {}, { customize_messenger_channel: this.channel() });
+
+ this.run( deferred );
+ },
+
+ run: function( deferred ) {
+ var self = this,
+ loaded = false,
+ ready = false;
+
+ if ( this._ready )
+ this.unbind( 'ready', this._ready );
+
+ this._ready = function() {
+ ready = true;
+
+ if ( loaded )
+ deferred.resolveWith( self );
+ };
+
+ this.bind( 'ready', this._ready );
+
+ this.request = $.ajax( this.previewUrl(), {
+ type: 'POST',
+ data: this.query,
+ xhrFields: {
+ withCredentials: true
+ }
+ } );
+
+ this.request.fail( function() {
+ deferred.rejectWith( self, [ 'request failure' ] );
+ });
+
+ this.request.done( function( response ) {
+ var location = self.request.getResponseHeader('Location'),
+ signature = self.signature,
+ index;
+
+ // Check if the location response header differs from the current URL.
+ // If so, the request was redirected; try loading the requested page.
+ if ( location && location != self.previewUrl() ) {
+ deferred.rejectWith( self, [ 'redirect', location ] );
+ return;
+ }
+
+ // Check if the user is not logged in.
+ if ( '0' === response ) {
+ self.login( deferred );
+ return;
+ }
+
+ // Check for cheaters.
+ if ( '-1' === response ) {
+ deferred.rejectWith( self, [ 'cheatin' ] );
+ return;
+ }
+
+ // Check for a signature in the request.
+ index = response.lastIndexOf( signature );
+ if ( -1 === index || index < response.lastIndexOf('</html>') ) {
+ deferred.rejectWith( self, [ 'unsigned' ] );
+ return;
+ }
+
+ // Strip the signature from the request.
+ response = response.slice( 0, index ) + response.slice( index + signature.length );
+
+ // Create the iframe and inject the html content.
+ self.iframe = $('<iframe />').appendTo( self.container );
+
+ // Bind load event after the iframe has been added to the page;
+ // otherwise it will fire when injected into the DOM.
+ self.iframe.one( 'load', function() {
+ loaded = true;
+
+ if ( ready ) {
+ deferred.resolveWith( self );
+ } else {
+ setTimeout( function() {
+ deferred.rejectWith( self, [ 'ready timeout' ] );
+ }, self.sensitivity );
+ }
+ });
+
+ self.targetWindow( self.iframe[0].contentWindow );
+
+ self.targetWindow().document.open();
+ self.targetWindow().document.write( response );
+ self.targetWindow().document.close();
+ });
+ },
+
+ login: function( deferred ) {
+ var self = this,
+ reject;
+
+ reject = function() {
+ deferred.rejectWith( self, [ 'logged out' ] );
+ };
+
+ if ( this.triedLogin )
+ return reject();
+
+ // Check if we have an admin cookie.
+ $.get( api.settings.url.ajax, {
+ action: 'logged-in'
+ }).fail( reject ).done( function( response ) {
+ var iframe;
+
+ if ( '1' !== response )
+ reject();
+
+ iframe = $('<iframe src="' + self.previewUrl() + '" />').hide();
+ iframe.appendTo( self.container );
+ iframe.load( function() {
+ self.triedLogin = true;
+
+ iframe.remove();
+ self.run( deferred );
+ });
+ });
+ },
+
+ destroy: function() {
+ api.Messenger.prototype.destroy.call( this );
+ this.request.abort();
+
+ if ( this.iframe )
+ this.iframe.remove();
+
+ delete this.request;
+ delete this.iframe;
+ delete this.targetWindow;
+ }
+ });
+
+ (function(){
+ var uuid = 0;
+ api.PreviewFrame.uuid = function() {
+ return 'preview-' + uuid++;
+ };
+ }());
+
+ api.Previewer = api.Messenger.extend({
+ refreshBuffer: 250,
+
+ /**
+ * Requires params:
+ * - container - a selector or jQuery element
+ * - previewUrl - the URL of preview frame
+ */
+ initialize: function( params, options ) {
+ var self = this,
+ rscheme = /^https?/,
+ url;
+
+ $.extend( this, options || {} );
+
+ /*
+ * Wrap this.refresh to prevent it from hammering the servers:
+ *
+ * If refresh is called once and no other refresh requests are
+ * loading, trigger the request immediately.
+ *
+ * If refresh is called while another refresh request is loading,
+ * debounce the refresh requests:
+ * 1. Stop the loading request (as it is instantly outdated).
+ * 2. Trigger the new request once refresh hasn't been called for
+ * self.refreshBuffer milliseconds.
+ */
+ this.refresh = (function( self ) {
+ var refresh = self.refresh,
+ callback = function() {
+ timeout = null;
+ refresh.call( self );
+ },
+ timeout;
+
+ return function() {
+ if ( typeof timeout !== 'number' ) {
+ if ( self.loading ) {
+ self.abort();
+ } else {
+ return callback();
+ }
+ }
+
+ clearTimeout( timeout );
+ timeout = setTimeout( callback, self.refreshBuffer );
+ };
+ })( this );
+
+ this.container = api.ensure( params.container );
+ this.allowedUrls = params.allowedUrls;
+ this.signature = params.signature;
+
+ params.url = window.location.href;
+
+ api.Messenger.prototype.initialize.call( this, params );
+
+ this.add( 'scheme', this.origin() ).link( this.origin ).setter( function( to ) {
+ var match = to.match( rscheme );
+ return match ? match[0] : '';
+ });
+
+ // Limit the URL to internal, front-end links.
+ //
+ // If the frontend and the admin are served from the same domain, load the
+ // preview over ssl if the customizer is being loaded over ssl. This avoids
+ // insecure content warnings. This is not attempted if the admin and frontend
+ // are on different domains to avoid the case where the frontend doesn't have
+ // ssl certs.
+
+ this.add( 'previewUrl', params.previewUrl ).setter( function( to ) {
+ var result;
+
+ // Check for URLs that include "/wp-admin/" or end in "/wp-admin".
+ // Strip hashes and query strings before testing.
+ if ( /\/wp-admin(\/|$)/.test( to.replace(/[#?].*$/, '') ) )
+ return null;
+
+ // Attempt to match the URL to the control frame's scheme
+ // and check if it's allowed. If not, try the original URL.
+ $.each([ to.replace( rscheme, self.scheme() ), to ], function( i, url ) {
+ $.each( self.allowedUrls, function( i, allowed ) {
+ if ( 0 === url.indexOf( allowed ) ) {
+ result = url;
+ return false;
+ }
+ });
+ if ( result )
+ return false;
+ });
+
+ // If we found a matching result, return it. If not, bail.
+ return result ? result : null;
+ });
+
+ // Refresh the preview when the URL is changed (but not yet).
+ this.previewUrl.bind( this.refresh );
+
+ this.scroll = 0;
+ this.bind( 'scroll', function( distance ) {
+ this.scroll = distance;
+ });
+
+ // Update the URL when the iframe sends a URL message.
+ this.bind( 'url', this.previewUrl );
+ },
+
+ query: function() {},
+
+ abort: function() {
+ if ( this.loading ) {
+ this.loading.destroy();
+ delete this.loading;
+ }
+ },
+
+ refresh: function() {
+ var self = this;
+
+ this.abort();
+
+ this.loading = new api.PreviewFrame({
+ url: this.url(),
+ previewUrl: this.previewUrl(),
+ query: this.query() || {},
+ container: this.container,
+ signature: this.signature
+ });
+
+ this.loading.done( function() {
+ // 'this' is the loading frame
+ this.bind( 'synced', function() {
+ if ( self.preview )
+ self.preview.destroy();
+ self.preview = this;
+ delete self.loading;
+
+ self.targetWindow( this.targetWindow() );
+ self.channel( this.channel() );
+
+ self.send( 'active' );
+ });
+
+ this.send( 'sync', {
+ scroll: self.scroll,
+ settings: api.get()
+ });
+ });
+
+ this.loading.fail( function( reason, location ) {
+ if ( 'redirect' === reason && location )
+ self.previewUrl( location );
+
+ if ( 'logged out' === reason ) {
+ if ( self.preview ) {
+ self.preview.destroy();
+ delete self.preview;
+ }
+
+ self.login().done( self.refresh );
+ }
+
+ if ( 'cheatin' === reason )
+ self.cheatin();
+ });
+ },
+
+ login: function() {
+ var previewer = this,
+ deferred, messenger, iframe;
+
+ if ( this._login )
+ return this._login;
+
+ deferred = $.Deferred();
+ this._login = deferred.promise();
+
+ messenger = new api.Messenger({
+ channel: 'login',
+ url: api.settings.url.login
+ });
+
+ iframe = $('<iframe src="' + api.settings.url.login + '" />').appendTo( this.container );
+
+ messenger.targetWindow( iframe[0].contentWindow );
+
+ messenger.bind( 'login', function() {
+ iframe.remove();
+ messenger.destroy();
+ delete previewer._login;
+ deferred.resolve();
+ });
+
+ return this._login;
+ },
+
+ cheatin: function() {
+ $( document.body ).empty().addClass('cheatin').append( '<p>' + api.l10n.cheatin + '</p>' );
+ }
+ });
+
+ /* =====================================================================
+ * Ready.
+ * ===================================================================== */
+
+ api.controlConstructor = {
+ color: api.ColorControl,
+ upload: api.UploadControl,
+ image: api.ImageControl
+ };
+
+ $( function() {
+ api.settings = window._wpCustomizeSettings;
+ api.l10n = window._wpCustomizeControlsL10n;
+
+ // Check if we can run the customizer.
+ if ( ! api.settings )
+ return;
+
+ // Redirect to the fallback preview if any incompatibilities are found.
+ if ( ! $.support.postMessage || ( ! $.support.cors && api.settings.isCrossDomain ) )
+ return window.location = api.settings.url.fallback;
+
+ var body = $( document.body ),
+ overlay = body.children('.wp-full-overlay'),
+ query, previewer, parent;
+
+ // Prevent the form from saving when enter is pressed.
+ $('#customize-controls').on( 'keydown', function( e ) {
+ if ( $( e.target ).is('textarea') )
+ return;
+
+ if ( 13 === e.which ) // Enter
+ e.preventDefault();
+ });
+
+ // Initialize Previewer
+ previewer = new api.Previewer({
+ container: '#customize-preview',
+ form: '#customize-controls',
+ previewUrl: api.settings.url.preview,
+ allowedUrls: api.settings.url.allowed,
+ signature: 'WP_CUSTOMIZER_SIGNATURE'
+ }, {
+
+ nonce: api.settings.nonce,
+
+ query: function() {
+ return {
+ wp_customize: 'on',
+ theme: api.settings.theme.stylesheet,
+ customized: JSON.stringify( api.get() ),
+ nonce: this.nonce.preview
+ };
+ },
+
+ save: function() {
+ var self = this,
+ query = $.extend( this.query(), {
+ action: 'customize_save',
+ nonce: this.nonce.save
+ }),
+ request = $.post( api.settings.url.ajax, query );
+
+ api.trigger( 'save', request );
+
+ body.addClass('saving');
+
+ request.always( function() {
+ body.removeClass('saving');
+ });
+
+ request.done( function( response ) {
+ // Check if the user is logged out.
+ if ( '0' === response ) {
+ self.preview.iframe.hide();
+ self.login().done( function() {
+ self.save();
+ self.preview.iframe.show();
+ });
+ return;
+ }
+
+ // Check for cheaters.
+ if ( '-1' === response ) {
+ self.cheatin();
+ return;
+ }
+
+ api.trigger( 'saved' );
+ });
+ }
+ });
+
+ // Refresh the nonces if the preview sends updated nonces over.
+ previewer.bind( 'nonce', function( nonce ) {
+ $.extend( this.nonce, nonce );
+ });
+
+ $.each( api.settings.settings, function( id, data ) {
+ api.create( id, id, data.value, {
+ transport: data.transport,
+ previewer: previewer
+ } );
+ });
+
+ $.each( api.settings.controls, function( id, data ) {
+ var constructor = api.controlConstructor[ data.type ] || api.Control,
+ control;
+
+ control = api.control.add( id, new constructor( id, {
+ params: data,
+ previewer: previewer
+ } ) );
+ });
+
+ // Check if preview url is valid and load the preview frame.
+ if ( previewer.previewUrl() )
+ previewer.refresh();
+ else
+ previewer.previewUrl( api.settings.url.home );
+
+ // Save and activated states
+ (function() {
+ var state = new api.Values(),
+ saved = state.create('saved'),
+ activated = state.create('activated');
+
+ state.bind( 'change', function() {
+ var save = $('#save'),
+ back = $('.back');
+
+ if ( ! activated() ) {
+ save.val( api.l10n.activate ).prop( 'disabled', false );
+ back.text( api.l10n.cancel );
+
+ } else if ( saved() ) {
+ save.val( api.l10n.saved ).prop( 'disabled', true );
+ back.text( api.l10n.close );
+
+ } else {
+ save.val( api.l10n.save ).prop( 'disabled', false );
+ back.text( api.l10n.cancel );
+ }
+ });
+
+ // Set default states.
+ saved( true );
+ activated( api.settings.theme.active );
+
+ api.bind( 'change', function() {
+ state('saved').set( false );
+ });
+
+ api.bind( 'saved', function() {
+ state('saved').set( true );
+ state('activated').set( true );
+ });
+
+ activated.bind( function( to ) {
+ if ( to )
+ api.trigger( 'activated' );
+ });
+
+ // Expose states to the API.
+ api.state = state;
+ }());
+
+ // Button bindings.
+ $('#save').click( function( event ) {
+ previewer.save();
+ event.preventDefault();
+ }).keydown( function( event ) {
+ if ( 9 === event.which ) // tab
+ return;
+ if ( 13 === event.which ) // enter
+ previewer.save();
+ event.preventDefault();
+ });
+
+ $('.back').keydown( function( event ) {
+ if ( 9 === event.which ) // tab
+ return;
+ if ( 13 === event.which ) // enter
+ parent.send( 'close' );
+ event.preventDefault();
+ });
+
+ $('.upload-dropzone a.upload').keydown( function( event ) {
+ if ( 13 === event.which ) // enter
+ this.click();
+ });
+
+ $('.collapse-sidebar').on( 'click keydown', function( event ) {
+ if ( event.type === 'keydown' && 13 !== event.which ) // enter
+ return;
+
+ overlay.toggleClass( 'collapsed' ).toggleClass( 'expanded' );
+ event.preventDefault();
+ });
+
+ // Create a potential postMessage connection with the parent frame.
+ parent = new api.Messenger({
+ url: api.settings.url.parent,
+ channel: 'loader'
+ });
+
+ // If we receive a 'back' event, we're inside an iframe.
+ // Send any clicks to the 'Return' link to the parent page.
+ parent.bind( 'back', function() {
+ $('.back').on( 'click.back', function( event ) {
+ event.preventDefault();
+ parent.send( 'close' );
+ });
+ });
+
+ // Pass events through to the parent.
+ api.bind( 'saved', function() {
+ parent.send( 'saved' );
+ });
+
+ // When activated, let the loader handle redirecting the page.
+ // If no loader exists, redirect the page ourselves (if a url exists).
+ api.bind( 'activated', function() {
+ if ( parent.targetWindow() )
+ parent.send( 'activated', api.settings.url.activated );
+ else if ( api.settings.url.activated )
+ window.location = api.settings.url.activated;
+ });
+
+ // Initialize the connection with the parent frame.
+ parent.send( 'ready' );
+
+ // Control visibility for default controls
+ $.each({
+ 'background_image': {
+ controls: [ 'background_repeat', 'background_position_x', 'background_attachment' ],
+ callback: function( to ) { return !! to }
+ },
+ 'show_on_front': {
+ controls: [ 'page_on_front', 'page_for_posts' ],
+ callback: function( to ) { return 'page' === to }
+ },
+ 'header_textcolor': {
+ controls: [ 'header_textcolor' ],
+ callback: function( to ) { return 'blank' !== to }
+ }
+ }, function( settingId, o ) {
+ api( settingId, function( setting ) {
+ $.each( o.controls, function( i, controlId ) {
+ api.control( controlId, function( control ) {
+ var visibility = function( to ) {
+ control.container.toggle( o.callback( to ) );
+ };
+
+ visibility( setting.get() );
+ setting.bind( visibility );
+ });
+ });
+ });
+ });
+
+ // Juggle the two controls that use header_textcolor
+ api.control( 'display_header_text', function( control ) {
+ var last = '';
+
+ control.elements[0].unsync( api( 'header_textcolor' ) );
+
+ control.element = new api.Element( control.container.find('input') );
+ control.element.set( 'blank' !== control.setting() );
+
+ control.element.bind( function( to ) {
+ if ( ! to )
+ last = api( 'header_textcolor' ).get();
+
+ control.setting.set( to ? last : 'blank' );
+ });
+
+ control.setting.bind( function( to ) {
+ control.element.set( 'blank' !== to );
+ });
+ });
+
+ // Handle header image data
+ api.control( 'header_image', function( control ) {
+ control.setting.bind( function( to ) {
+ if ( to === control.params.removed )
+ control.settings.data.set( false );
+ });
+
+ control.library.on( 'click', 'a', function( event ) {
+ control.settings.data.set( $(this).data('customizeHeaderImageData') );
+ });
+
+ control.uploader.success = function( attachment ) {
+ var data;
+
+ api.ImageControl.prototype.success.call( control, attachment );
+
+ data = {
+ attachment_id: attachment.get('id'),
+ url: attachment.get('url'),
+ thumbnail_url: attachment.get('url'),
+ height: attachment.get('height'),
+ width: attachment.get('width')
+ };
+
+ attachment.element.data( 'customizeHeaderImageData', data );
+ control.settings.data.set( data );
+ };
+ });
+
+ api.trigger( 'ready' );
+
+ // Make sure left column gets focus
+ var topFocus = $('.back');
+ topFocus.focus();
+ setTimeout(function () {
+ topFocus.focus();
+ }, 200);
+
+ });
+
+})( wp, jQuery );
diff --git a/src/wp-admin/js/dashboard.js b/src/wp-admin/js/dashboard.js
new file mode 100644
index 0000000000..50a17f85eb
--- /dev/null
+++ b/src/wp-admin/js/dashboard.js
@@ -0,0 +1,117 @@
+var ajaxWidgets, ajaxPopulateWidgets, quickPressLoad;
+
+jQuery(document).ready( function($) {
+ /* Dashboard Welcome Panel */
+ var welcomePanel = $('#welcome-panel'),
+ welcomePanelHide = $('#wp_welcome_panel-hide'),
+ updateWelcomePanel = function( visible ) {
+ $.post( ajaxurl, {
+ action: 'update-welcome-panel',
+ visible: visible,
+ welcomepanelnonce: $('#welcomepanelnonce').val()
+ });
+ };
+
+ if ( welcomePanel.hasClass('hidden') && welcomePanelHide.prop('checked') )
+ welcomePanel.removeClass('hidden');
+
+ $('.welcome-panel-close, .welcome-panel-dismiss a', welcomePanel).click( function(e) {
+ e.preventDefault();
+ welcomePanel.addClass('hidden');
+ updateWelcomePanel( 0 );
+ $('#wp_welcome_panel-hide').prop('checked', false);
+ });
+
+ welcomePanelHide.click( function() {
+ welcomePanel.toggleClass('hidden', ! this.checked );
+ updateWelcomePanel( this.checked ? 1 : 0 );
+ });
+
+ // These widgets are sometimes populated via ajax
+ ajaxWidgets = [
+ 'dashboard_incoming_links',
+ 'dashboard_primary',
+ 'dashboard_secondary',
+ 'dashboard_plugins'
+ ];
+
+ ajaxPopulateWidgets = function(el) {
+ function show(i, id) {
+ var p, e = $('#' + id + ' div.inside:visible').find('.widget-loading');
+ if ( e.length ) {
+ p = e.parent();
+ setTimeout( function(){
+ p.load( ajaxurl + '?action=dashboard-widgets&widget=' + id, '', function() {
+ p.hide().slideDown('normal', function(){
+ $(this).css('display', '');
+ });
+ });
+ }, i * 500 );
+ }
+ }
+
+ if ( el ) {
+ el = el.toString();
+ if ( $.inArray(el, ajaxWidgets) != -1 )
+ show(0, el);
+ } else {
+ $.each( ajaxWidgets, show );
+ }
+ };
+ ajaxPopulateWidgets();
+
+ postboxes.add_postbox_toggles(pagenow, { pbshow: ajaxPopulateWidgets } );
+
+ /* QuickPress */
+ quickPressLoad = function() {
+ var act = $('#quickpost-action'), t;
+ t = $('#quick-press').submit( function() {
+ $('#dashboard_quick_press #publishing-action .spinner').show();
+ $('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', true);
+
+ if ( 'post' == act.val() ) {
+ act.val( 'post-quickpress-publish' );
+ }
+
+ $('#dashboard_quick_press div.inside').load( t.attr( 'action' ), t.serializeArray(), function() {
+ $('#dashboard_quick_press #publishing-action .spinner').hide();
+ $('#quick-press .submit input[type="submit"], #quick-press .submit input[type="reset"]').prop('disabled', false);
+ $('#dashboard_quick_press ul').next('p').remove();
+ $('#dashboard_quick_press ul').find('li').each( function() {
+ $('#dashboard_recent_drafts ul').prepend( this );
+ } ).end().remove();
+ quickPressLoad();
+ } );
+ return false;
+ } );
+
+ $('#publish').click( function() { act.val( 'post-quickpress-publish' ); } );
+
+ $('#title, #tags-input').each( function() {
+ var input = $(this), prompt = $('#' + this.id + '-prompt-text');
+
+ if ( '' === this.value )
+ prompt.removeClass('screen-reader-text');
+
+ prompt.click( function() {
+ $(this).addClass('screen-reader-text');
+ input.focus();
+ });
+
+ input.blur( function() {
+ if ( '' === this.value )
+ prompt.removeClass('screen-reader-text');
+ });
+
+ input.focus( function() {
+ prompt.addClass('screen-reader-text');
+ });
+ });
+
+ $('#quick-press').on( 'click focusin', function() {
+ wpActiveEditor = 'content';
+ });
+ };
+ quickPressLoad();
+
+} );
diff --git a/src/wp-admin/js/edit-comments.js b/src/wp-admin/js/edit-comments.js
new file mode 100644
index 0000000000..038a1e5689
--- /dev/null
+++ b/src/wp-admin/js/edit-comments.js
@@ -0,0 +1,607 @@
+var theList, theExtraList, toggleWithKeyboard = false;
+
+(function($) {
+var getCount, updateCount, updatePending, dashboardTotals;
+
+setCommentsList = function() {
+ var totalInput, perPageInput, pageInput, lastConfidentTime = 0, dimAfter, delBefore, updateTotalCount, delAfter, refillTheExtraList;
+
+ totalInput = $('input[name="_total"]', '#comments-form');
+ perPageInput = $('input[name="_per_page"]', '#comments-form');
+ pageInput = $('input[name="_page"]', '#comments-form');
+
+ dimAfter = function( r, settings ) {
+ var c = $('#' + settings.element), editRow, replyID, replyButton;
+
+ editRow = $('#replyrow');
+ replyID = $('#comment_ID', editRow).val();
+ replyButton = $('#replybtn', editRow);
+
+ if ( c.is('.unapproved') ) {
+ if ( settings.data.id == replyID )
+ replyButton.text(adminCommentsL10n.replyApprove);
+
+ c.find('div.comment_status').html('0');
+ } else {
+ if ( settings.data.id == replyID )
+ replyButton.text(adminCommentsL10n.reply);
+
+ c.find('div.comment_status').html('1');
+ }
+
+ var diff = $('#' + settings.element).is('.' + settings.dimClass) ? 1 : -1;
+ updatePending( diff );
+ };
+
+ // Send current total, page, per_page and url
+ delBefore = function( settings, list ) {
+ var wpListsData = $(settings.target).attr('data-wp-lists'), id, el, n, h, a, author, action = false;
+
+ settings.data._total = totalInput.val() || 0;
+ settings.data._per_page = perPageInput.val() || 0;
+ settings.data._page = pageInput.val() || 0;
+ settings.data._url = document.location.href;
+ settings.data.comment_status = $('input[name="comment_status"]', '#comments-form').val();
+
+ if ( wpListsData.indexOf(':trash=1') != -1 )
+ action = 'trash';
+ else if ( wpListsData.indexOf(':spam=1') != -1 )
+ action = 'spam';
+
+ if ( action ) {
+ id = wpListsData.replace(/.*?comment-([0-9]+).*/, '$1');
+ el = $('#comment-' + id);
+ note = $('#' + action + '-undo-holder').html();
+
+ el.find('.check-column :checkbox').prop('checked', false); // Uncheck the row so as not to be affected by Bulk Edits.
+
+ if ( el.siblings('#replyrow').length && commentReply.cid == id )
+ commentReply.close();
+
+ if ( el.is('tr') ) {
+ n = el.children(':visible').length;
+ author = $('.author strong', el).text();
+ h = $('<tr id="undo-' + id + '" class="undo un' + action + '" style="display:none;"><td colspan="' + n + '">' + note + '</td></tr>');
+ } else {
+ author = $('.comment-author', el).text();
+ h = $('<div id="undo-' + id + '" style="display:none;" class="undo un' + action + '">' + note + '</div>');
+ }
+
+ el.before(h);
+
+ $('strong', '#undo-' + id).text(author);
+ a = $('.undo a', '#undo-' + id);
+ a.attr('href', 'comment.php?action=un' + action + 'comment&c=' + id + '&_wpnonce=' + settings.data._ajax_nonce);
+ a.attr('data-wp-lists', 'delete:the-comment-list:comment-' + id + '::un' + action + '=1');
+ a.attr('class', 'vim-z vim-destructive');
+ $('.avatar', el).clone().prependTo('#undo-' + id + ' .' + action + '-undo-inside');
+
+ a.click(function(){
+ list.wpList.del(this);
+ $('#undo-' + id).css( {backgroundColor:'#ceb'} ).fadeOut(350, function(){
+ $(this).remove();
+ $('#comment-' + id).css('backgroundColor', '').fadeIn(300, function(){ $(this).show() });
+ });
+ return false;
+ });
+ }
+
+ return settings;
+ };
+
+ // Updates the current total (stored in the _total input)
+ updateTotalCount = function( total, time, setConfidentTime ) {
+ if ( time < lastConfidentTime )
+ return;
+
+ if ( setConfidentTime )
+ lastConfidentTime = time;
+
+ totalInput.val( total.toString() );
+ };
+
+ dashboardTotals = function(n) {
+ var dash = $('#dashboard_right_now'), total, appr, totalN, apprN;
+
+ n = n || 0;
+ if ( isNaN(n) || !dash.length )
+ return;
+
+ total = $('span.total-count', dash);
+ appr = $('span.approved-count', dash);
+ totalN = getCount(total);
+
+ totalN = totalN + n;
+ apprN = totalN - getCount( $('span.pending-count', dash) ) - getCount( $('span.spam-count', dash) );
+ updateCount(total, totalN);
+ updateCount(appr, apprN);
+ };
+
+ getCount = function(el) {
+ var n = parseInt( el.html().replace(/[^0-9]+/g, ''), 10 );
+ if ( isNaN(n) )
+ return 0;
+ return n;
+ };
+
+ updateCount = function(el, n) {
+ var n1 = '';
+ if ( isNaN(n) )
+ return;
+ n = n < 1 ? '0' : n.toString();
+ if ( n.length > 3 ) {
+ while ( n.length > 3 ) {
+ n1 = thousandsSeparator + n.substr(n.length - 3) + n1;
+ n = n.substr(0, n.length - 3);
+ }
+ n = n + n1;
+ }
+ el.html(n);
+ };
+
+ updatePending = function( diff ) {
+ $('span.pending-count').each(function() {
+ var a = $(this), n = getCount(a) + diff;
+ if ( n < 1 )
+ n = 0;
+ a.closest('.awaiting-mod')[ 0 == n ? 'addClass' : 'removeClass' ]('count-0');
+ updateCount( a, n );
+ });
+
+ dashboardTotals();
+ };
+
+ // In admin-ajax.php, we send back the unix time stamp instead of 1 on success
+ delAfter = function( r, settings ) {
+ var total, N, spam, trash, pending,
+ untrash = $(settings.target).parent().is('span.untrash'),
+ unspam = $(settings.target).parent().is('span.unspam'),
+ unapproved = $('#' + settings.element).is('.unapproved');
+
+ function getUpdate(s) {
+ if ( $(settings.target).parent().is('span.' + s) )
+ return 1;
+ else if ( $('#' + settings.element).is('.' + s) )
+ return -1;
+
+ return 0;
+ }
+
+ if ( untrash )
+ trash = -1;
+ else
+ trash = getUpdate('trash');
+
+ if ( unspam )
+ spam = -1;
+ else
+ spam = getUpdate('spam');
+
+ if ( $(settings.target).parent().is('span.unapprove') || ( ( untrash || unspam ) && unapproved ) ) {
+ // a comment was 'deleted' from another list (e.g. approved, spam, trash) and moved to pending,
+ // or a trash/spam of a pending comment was undone
+ pending = 1;
+ } else if ( unapproved ) {
+ // a pending comment was trashed/spammed/approved
+ pending = -1;
+ }
+
+ if ( pending )
+ updatePending(pending);
+
+ $('span.spam-count').each( function() {
+ var a = $(this), n = getCount(a) + spam;
+ updateCount(a, n);
+ });
+
+ $('span.trash-count').each( function() {
+ var a = $(this), n = getCount(a) + trash;
+ updateCount(a, n);
+ });
+
+ if ( $('#dashboard_right_now').length ) {
+ N = trash ? -1 * trash : 0;
+ dashboardTotals(N);
+ } else {
+ total = totalInput.val() ? parseInt( totalInput.val(), 10 ) : 0;
+ if ( $(settings.target).parent().is('span.undo') )
+ total++;
+ else
+ total--;
+
+ if ( total < 0 )
+ total = 0;
+
+ if ( ( 'object' == typeof r ) && lastConfidentTime < settings.parsed.responses[0].supplemental.time ) {
+ total_items_i18n = settings.parsed.responses[0].supplemental.total_items_i18n || '';
+ if ( total_items_i18n ) {
+ $('.displaying-num').text( total_items_i18n );
+ $('.total-pages').text( settings.parsed.responses[0].supplemental.total_pages_i18n );
+ $('.tablenav-pages').find('.next-page, .last-page').toggleClass('disabled', settings.parsed.responses[0].supplemental.total_pages == $('.current-page').val());
+ }
+ updateTotalCount( total, settings.parsed.responses[0].supplemental.time, true );
+ } else {
+ updateTotalCount( total, r, false );
+ }
+ }
+
+ if ( ! theExtraList || theExtraList.size() == 0 || theExtraList.children().size() == 0 || untrash || unspam ) {
+ return;
+ }
+
+ theList.get(0).wpList.add( theExtraList.children(':eq(0)').remove().clone() );
+
+ refillTheExtraList();
+ };
+
+ refillTheExtraList = function(ev) {
+ var args = $.query.get(), total_pages = $('.total-pages').text(), per_page = $('input[name="_per_page"]', '#comments-form').val();
+
+ if (! args.paged)
+ args.paged = 1;
+
+ if (args.paged > total_pages) {
+ return;
+ }
+
+ if (ev) {
+ theExtraList.empty();
+ args.number = Math.min(8, per_page); // see WP_Comments_List_Table::prepare_items() @ class-wp-comments-list-table.php
+ } else {
+ args.number = 1;
+ args.offset = Math.min(8, per_page) - 1; // fetch only the next item on the extra list
+ }
+
+ args.no_placeholder = true;
+
+ args.paged ++;
+
+ // $.query.get() needs some correction to be sent into an ajax request
+ if ( true === args.comment_type )
+ args.comment_type = '';
+
+ args = $.extend(args, {
+ 'action': 'fetch-list',
+ 'list_args': list_args,
+ '_ajax_fetch_list_nonce': $('#_ajax_fetch_list_nonce').val()
+ });
+
+ $.ajax({
+ url: ajaxurl,
+ global: false,
+ dataType: 'json',
+ data: args,
+ success: function(response) {
+ theExtraList.get(0).wpList.add( response.rows );
+ }
+ });
+ };
+
+ theExtraList = $('#the-extra-comment-list').wpList( { alt: '', delColor: 'none', addColor: 'none' } );
+ theList = $('#the-comment-list').wpList( { alt: '', delBefore: delBefore, dimAfter: dimAfter, delAfter: delAfter, addColor: 'none' } )
+ .bind('wpListDelEnd', function(e, s){
+ var wpListsData = $(s.target).attr('data-wp-lists'), id = s.element.replace(/[^0-9]+/g, '');
+
+ if ( wpListsData.indexOf(':trash=1') != -1 || wpListsData.indexOf(':spam=1') != -1 )
+ $('#undo-' + id).fadeIn(300, function(){ $(this).show() });
+ });
+};
+
+commentReply = {
+ cid : '',
+ act : '',
+
+ init : function() {
+ var row = $('#replyrow');
+
+ $('a.cancel', row).click(function() { return commentReply.revert(); });
+ $('a.save', row).click(function() { return commentReply.send(); });
+ $('input#author, input#author-email, input#author-url', row).keypress(function(e){
+ if ( e.which == 13 ) {
+ commentReply.send();
+ e.preventDefault();
+ return false;
+ }
+ });
+
+ // add events
+ $('#the-comment-list .column-comment > p').dblclick(function(){
+ commentReply.toggle($(this).parent());
+ });
+
+ $('#doaction, #doaction2, #post-query-submit').click(function(e){
+ if ( $('#the-comment-list #replyrow').length > 0 )
+ commentReply.close();
+ });
+
+ this.comments_listing = $('#comments-form > input[name="comment_status"]').val() || '';
+
+ /* $(listTable).bind('beforeChangePage', function(){
+ commentReply.close();
+ }); */
+ },
+
+ addEvents : function(r) {
+ r.each(function() {
+ $(this).find('.column-comment > p').dblclick(function(){
+ commentReply.toggle($(this).parent());
+ });
+ });
+ },
+
+ toggle : function(el) {
+ if ( $(el).css('display') != 'none' )
+ $(el).find('a.vim-q').click();
+ },
+
+ revert : function() {
+
+ if ( $('#the-comment-list #replyrow').length < 1 )
+ return false;
+
+ $('#replyrow').fadeOut('fast', function(){
+ commentReply.close();
+ });
+
+ return false;
+ },
+
+ close : function() {
+ var c, replyrow = $('#replyrow');
+
+ // replyrow is not showing?
+ if ( replyrow.parent().is('#com-reply') )
+ return;
+
+ if ( this.cid && this.act == 'edit-comment' ) {
+ c = $('#comment-' + this.cid);
+ c.fadeIn(300, function(){ c.show() }).css('backgroundColor', '');
+ }
+
+ // reset the Quicktags buttons
+ if ( typeof QTags != 'undefined' )
+ QTags.closeAllTags('replycontent');
+
+ $('#add-new-comment').css('display', '');
+
+ replyrow.hide();
+ $('#com-reply').append( replyrow );
+ $('#replycontent').css('height', '').val('');
+ $('#edithead input').val('');
+ $('.error', replyrow).html('').hide();
+ $('.spinner', replyrow).hide();
+
+ this.cid = '';
+ },
+
+ open : function(comment_id, post_id, action) {
+ var t = this, editRow, rowData, act, c = $('#comment-' + comment_id), h = c.height(), replyButton;
+
+ t.close();
+ t.cid = comment_id;
+
+ editRow = $('#replyrow');
+ rowData = $('#inline-'+comment_id);
+ action = action || 'replyto';
+ act = 'edit' == action ? 'edit' : 'replyto';
+ act = t.act = act + '-comment';
+
+ $('#action', editRow).val(act);
+ $('#comment_post_ID', editRow).val(post_id);
+ $('#comment_ID', editRow).val(comment_id);
+
+ if ( h > 120 )
+ $('#replycontent', editRow).css('height', (35+h) + 'px');
+
+ if ( action == 'edit' ) {
+ $('#author', editRow).val( $('div.author', rowData).text() );
+ $('#author-email', editRow).val( $('div.author-email', rowData).text() );
+ $('#author-url', editRow).val( $('div.author-url', rowData).text() );
+ $('#status', editRow).val( $('div.comment_status', rowData).text() );
+ $('#replycontent', editRow).val( $('textarea.comment', rowData).val() );
+ $('#edithead, #savebtn', editRow).show();
+ $('#replyhead, #replybtn, #addhead, #addbtn', editRow).hide();
+
+ c.after( editRow ).fadeOut('fast', function(){
+ $('#replyrow').fadeIn(300, function(){ $(this).show() });
+ });
+ } else if ( action == 'add' ) {
+ $('#addhead, #addbtn', editRow).show();
+ $('#replyhead, #replybtn, #edithead, #editbtn', editRow).hide();
+ $('#the-comment-list').prepend(editRow);
+ $('#replyrow').fadeIn(300);
+ } else {
+ replyButton = $('#replybtn', editRow);
+ $('#edithead, #savebtn, #addhead, #addbtn', editRow).hide();
+ $('#replyhead, #replybtn', editRow).show();
+ c.after(editRow);
+
+ if ( c.hasClass('unapproved') ) {
+ replyButton.text(adminCommentsL10n.replyApprove);
+ } else {
+ replyButton.text(adminCommentsL10n.reply);
+ }
+
+ $('#replyrow').fadeIn(300, function(){ $(this).show() });
+ }
+
+ setTimeout(function() {
+ var rtop, rbottom, scrollTop, vp, scrollBottom;
+
+ rtop = $('#replyrow').offset().top;
+ rbottom = rtop + $('#replyrow').height();
+ scrollTop = window.pageYOffset || document.documentElement.scrollTop;
+ vp = document.documentElement.clientHeight || self.innerHeight || 0;
+ scrollBottom = scrollTop + vp;
+
+ if ( scrollBottom - 20 < rbottom )
+ window.scroll(0, rbottom - vp + 35);
+ else if ( rtop - 20 < scrollTop )
+ window.scroll(0, rtop - 35);
+
+ $('#replycontent').focus().keyup(function(e){
+ if ( e.which == 27 )
+ commentReply.revert(); // close on Escape
+ });
+ }, 600);
+
+ return false;
+ },
+
+ send : function() {
+ var post = {};
+
+ $('#replysubmit .error').hide();
+ $('#replysubmit .spinner').show();
+
+ $('#replyrow input').not(':button').each(function() {
+ var t = $(this);
+ post[ t.attr('name') ] = t.val();
+ });
+
+ post.content = $('#replycontent').val();
+ post.id = post.comment_post_ID;
+ post.comments_listing = this.comments_listing;
+ post.p = $('[name="p"]').val();
+
+ if ( $('#comment-' + $('#comment_ID').val()).hasClass('unapproved') )
+ post.approve_parent = 1;
+
+ $.ajax({
+ type : 'POST',
+ url : ajaxurl,
+ data : post,
+ success : function(x) { commentReply.show(x); },
+ error : function(r) { commentReply.error(r); }
+ });
+
+ return false;
+ },
+
+ show : function(xml) {
+ var t = this, r, c, id, bg, pid;
+
+ if ( typeof(xml) == 'string' ) {
+ t.error({'responseText': xml});
+ return false;
+ }
+
+ r = wpAjax.parseAjaxResponse(xml);
+ if ( r.errors ) {
+ t.error({'responseText': wpAjax.broken});
+ return false;
+ }
+
+ t.revert();
+
+ r = r.responses[0];
+ c = r.data;
+ id = '#comment-' + r.id;
+
+ if ( 'edit-comment' == t.act )
+ $(id).remove();
+
+ if ( r.supplemental.parent_approved ) {
+ pid = $('#comment-' + r.supplemental.parent_approved);
+ updatePending( -1 );
+
+ if ( this.comments_listing == 'moderated' ) {
+ pid.animate( { 'backgroundColor':'#CCEEBB' }, 400, function(){
+ pid.fadeOut();
+ });
+ return;
+ }
+ }
+
+ $(c).hide()
+ $('#replyrow').after(c);
+ id = $(id);
+ t.addEvents(id);
+ bg = id.hasClass('unapproved') ? '#FFFFE0' : id.closest('.widefat, .postbox').css('backgroundColor');
+
+ id.animate( { 'backgroundColor':'#CCEEBB' }, 300 )
+ .animate( { 'backgroundColor': bg }, 300, function() {
+ if ( pid && pid.length ) {
+ pid.animate( { 'backgroundColor':'#CCEEBB' }, 300 )
+ .animate( { 'backgroundColor': bg }, 300 )
+ .removeClass('unapproved').addClass('approved')
+ .find('div.comment_status').html('1');
+ }
+ });
+
+ },
+
+ error : function(r) {
+ var er = r.statusText;
+
+ $('#replysubmit .spinner').hide();
+
+ if ( r.responseText )
+ er = r.responseText.replace( /<.[^<>]*?>/g, '' );
+
+ if ( er )
+ $('#replysubmit .error').html(er).show();
+
+ },
+
+ addcomment: function(post_id) {
+ var t = this;
+
+ $('#add-new-comment').fadeOut(200, function(){
+ t.open(0, post_id, 'add');
+ $('table.comments-box').css('display', '');
+ $('#no-comments').remove();
+ });
+ }
+};
+
+$(document).ready(function(){
+ var make_hotkeys_redirect, edit_comment, toggle_all, make_bulk;
+
+ setCommentsList();
+ commentReply.init();
+ $(document).delegate('span.delete a.delete', 'click', function(){return false;});
+
+ if ( typeof $.table_hotkeys != 'undefined' ) {
+ make_hotkeys_redirect = function(which) {
+ return function() {
+ var first_last, l;
+
+ first_last = 'next' == which? 'first' : 'last';
+ l = $('.tablenav-pages .'+which+'-page:not(.disabled)');
+ if (l.length)
+ window.location = l[0].href.replace(/\&hotkeys_highlight_(first|last)=1/g, '')+'&hotkeys_highlight_'+first_last+'=1';
+ }
+ };
+
+ edit_comment = function(event, current_row) {
+ window.location = $('span.edit a', current_row).attr('href');
+ };
+
+ toggle_all = function() {
+ toggleWithKeyboard = true;
+ $('input:checkbox', '#cb').click().prop('checked', false);
+ toggleWithKeyboard = false;
+ };
+
+ make_bulk = function(value) {
+ return function() {
+ var scope = $('select[name="action"]');
+ $('option[value="' + value + '"]', scope).prop('selected', true);
+ $('#doaction').click();
+ }
+ };
+
+ $.table_hotkeys(
+ $('table.widefat'),
+ ['a', 'u', 's', 'd', 'r', 'q', 'z', ['e', edit_comment], ['shift+x', toggle_all],
+ ['shift+a', make_bulk('approve')], ['shift+s', make_bulk('spam')],
+ ['shift+d', make_bulk('delete')], ['shift+t', make_bulk('trash')],
+ ['shift+z', make_bulk('untrash')], ['shift+u', make_bulk('unapprove')]],
+ { highlight_first: adminCommentsL10n.hotkeys_highlight_first, highlight_last: adminCommentsL10n.hotkeys_highlight_last,
+ prev_page_link_cb: make_hotkeys_redirect('prev'), next_page_link_cb: make_hotkeys_redirect('next') }
+ );
+ }
+});
+
+})(jQuery);
diff --git a/src/wp-admin/js/editor.js b/src/wp-admin/js/editor.js
new file mode 100644
index 0000000000..e54e836cc2
--- /dev/null
+++ b/src/wp-admin/js/editor.js
@@ -0,0 +1,245 @@
+
+var switchEditors = {
+
+ switchto: function(el) {
+ var aid = el.id, l = aid.length, id = aid.substr(0, l - 5), mode = aid.substr(l - 4);
+
+ this.go(id, mode);
+ },
+
+ go: function(id, mode) { // mode can be 'html', 'tmce', or 'toggle'; 'html' is used for the "Text" editor tab.
+ id = id || 'content';
+ mode = mode || 'toggle';
+
+ var t = this, ed = tinyMCE.get(id), wrap_id, txtarea_el, dom = tinymce.DOM;
+
+ wrap_id = 'wp-'+id+'-wrap';
+ txtarea_el = dom.get(id);
+
+ if ( 'toggle' == mode ) {
+ if ( ed && !ed.isHidden() )
+ mode = 'html';
+ else
+ mode = 'tmce';
+ }
+
+ if ( 'tmce' == mode || 'tinymce' == mode ) {
+ if ( ed && ! ed.isHidden() )
+ return false;
+
+ if ( typeof(QTags) != 'undefined' )
+ QTags.closeAllTags(id);
+
+ if ( tinyMCEPreInit.mceInit[id] && tinyMCEPreInit.mceInit[id].wpautop )
+ txtarea_el.value = t.wpautop( txtarea_el.value );
+
+ if ( ed ) {
+ ed.show();
+ } else {
+ ed = new tinymce.Editor(id, tinyMCEPreInit.mceInit[id]);
+ ed.render();
+ }
+
+ dom.removeClass(wrap_id, 'html-active');
+ dom.addClass(wrap_id, 'tmce-active');
+ setUserSetting('editor', 'tinymce');
+
+ } else if ( 'html' == mode ) {
+
+ if ( ed && ed.isHidden() )
+ return false;
+
+ if ( ed ) {
+ ed.hide();
+ } else {
+ // The TinyMCE instance doesn't exist, run the content through "pre_wpautop()" and show the textarea
+ if ( tinyMCEPreInit.mceInit[id] && tinyMCEPreInit.mceInit[id].wpautop )
+ txtarea_el.value = t.pre_wpautop( txtarea_el.value );
+
+ dom.setStyles(txtarea_el, {'display': '', 'visibility': ''});
+ }
+
+ dom.removeClass(wrap_id, 'tmce-active');
+ dom.addClass(wrap_id, 'html-active');
+ setUserSetting('editor', 'html');
+ }
+ return false;
+ },
+
+ _wp_Nop : function(content) {
+ var blocklist1, blocklist2, preserve_linebreaks = false, preserve_br = false;
+
+ // Protect pre|script tags
+ if ( content.indexOf('<pre') != -1 || content.indexOf('<script') != -1 ) {
+ preserve_linebreaks = true;
+ content = content.replace(/<(pre|script)[^>]*>[\s\S]+?<\/\1>/g, function(a) {
+ a = a.replace(/<br ?\/?>(\r\n|\n)?/g, '<wp-temp-lb>');
+ return a.replace(/<\/?p( [^>]*)?>(\r\n|\n)?/g, '<wp-temp-lb>');
+ });
+ }
+
+ // keep <br> tags inside captions and remove line breaks
+ if ( content.indexOf('[caption') != -1 ) {
+ preserve_br = true;
+ content = content.replace(/\[caption[\s\S]+?\[\/caption\]/g, function(a) {
+ return a.replace(/<br([^>]*)>/g, '<wp-temp-br$1>').replace(/[\r\n\t]+/, '');
+ });
+ }
+
+ // Pretty it up for the source editor
+ blocklist1 = 'blockquote|ul|ol|li|table|thead|tbody|tfoot|tr|th|td|div|h[1-6]|p|fieldset';
+ content = content.replace(new RegExp('\\s*</('+blocklist1+')>\\s*', 'g'), '</$1>\n');
+ content = content.replace(new RegExp('\\s*<((?:'+blocklist1+')(?: [^>]*)?)>', 'g'), '\n<$1>');
+
+ // Mark </p> if it has any attributes.
+ content = content.replace(/(<p [^>]+>.*?)<\/p>/g, '$1</p#>');
+
+ // Sepatate <div> containing <p>
+ content = content.replace(/<div( [^>]*)?>\s*<p>/gi, '<div$1>\n\n');
+
+ // Remove <p> and <br />
+ content = content.replace(/\s*<p>/gi, '');
+ content = content.replace(/\s*<\/p>\s*/gi, '\n\n');
+ content = content.replace(/\n[\s\u00a0]+\n/g, '\n\n');
+ content = content.replace(/\s*<br ?\/?>\s*/gi, '\n');
+
+ // Fix some block element newline issues
+ content = content.replace(/\s*<div/g, '\n<div');
+ content = content.replace(/<\/div>\s*/g, '</div>\n');
+ content = content.replace(/\s*\[caption([^\[]+)\[\/caption\]\s*/gi, '\n\n[caption$1[/caption]\n\n');
+ content = content.replace(/caption\]\n\n+\[caption/g, 'caption]\n\n[caption');
+
+ blocklist2 = 'blockquote|ul|ol|li|table|thead|tbody|tfoot|tr|th|td|h[1-6]|pre|fieldset';
+ content = content.replace(new RegExp('\\s*<((?:'+blocklist2+')(?: [^>]*)?)\\s*>', 'g'), '\n<$1>');
+ content = content.replace(new RegExp('\\s*</('+blocklist2+')>\\s*', 'g'), '</$1>\n');
+ content = content.replace(/<li([^>]*)>/g, '\t<li$1>');
+
+ if ( content.indexOf('<hr') != -1 ) {
+ content = content.replace(/\s*<hr( [^>]*)?>\s*/g, '\n\n<hr$1>\n\n');
+ }
+
+ if ( content.indexOf('<object') != -1 ) {
+ content = content.replace(/<object[\s\S]+?<\/object>/g, function(a){
+ return a.replace(/[\r\n]+/g, '');
+ });
+ }
+
+ // Unmark special paragraph closing tags
+ content = content.replace(/<\/p#>/g, '</p>\n');
+ content = content.replace(/\s*(<p [^>]+>[\s\S]*?<\/p>)/g, '\n$1');
+
+ // Trim whitespace
+ content = content.replace(/^\s+/, '');
+ content = content.replace(/[\s\u00a0]+$/, '');
+
+ // put back the line breaks in pre|script
+ if ( preserve_linebreaks )
+ content = content.replace(/<wp-temp-lb>/g, '\n');
+
+ // and the <br> tags in captions
+ if ( preserve_br )
+ content = content.replace(/<wp-temp-br([^>]*)>/g, '<br$1>');
+
+ return content;
+ },
+
+ _wp_Autop : function(pee) {
+ var preserve_linebreaks = false, preserve_br = false,
+ blocklist = 'table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|noscript|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary';
+
+ if ( pee.indexOf('<object') != -1 ) {
+ pee = pee.replace(/<object[\s\S]+?<\/object>/g, function(a){
+ return a.replace(/[\r\n]+/g, '');
+ });
+ }
+
+ pee = pee.replace(/<[^<>]+>/g, function(a){
+ return a.replace(/[\r\n]+/g, ' ');
+ });
+
+ // Protect pre|script tags
+ if ( pee.indexOf('<pre') != -1 || pee.indexOf('<script') != -1 ) {
+ preserve_linebreaks = true;
+ pee = pee.replace(/<(pre|script)[^>]*>[\s\S]+?<\/\1>/g, function(a) {
+ return a.replace(/(\r\n|\n)/g, '<wp-temp-lb>');
+ });
+ }
+
+ // keep <br> tags inside captions and convert line breaks
+ if ( pee.indexOf('[caption') != -1 ) {
+ preserve_br = true;
+ pee = pee.replace(/\[caption[\s\S]+?\[\/caption\]/g, function(a) {
+ // keep existing <br>
+ a = a.replace(/<br([^>]*)>/g, '<wp-temp-br$1>');
+ // no line breaks inside HTML tags
+ a = a.replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(b){
+ return b.replace(/[\r\n\t]+/, ' ');
+ });
+ // convert remaining line breaks to <br>
+ return a.replace(/\s*\n\s*/g, '<wp-temp-br />');
+ });
+ }
+
+ pee = pee + '\n\n';
+ pee = pee.replace(/<br \/>\s*<br \/>/gi, '\n\n');
+ pee = pee.replace(new RegExp('(<(?:'+blocklist+')(?: [^>]*)?>)', 'gi'), '\n$1');
+ pee = pee.replace(new RegExp('(</(?:'+blocklist+')>)', 'gi'), '$1\n\n');
+ pee = pee.replace(/<hr( [^>]*)?>/gi, '<hr$1>\n\n'); // hr is self closing block element
+ pee = pee.replace(/\r\n|\r/g, '\n');
+ pee = pee.replace(/\n\s*\n+/g, '\n\n');
+ pee = pee.replace(/([\s\S]+?)\n\n/g, '<p>$1</p>\n');
+ pee = pee.replace(/<p>\s*?<\/p>/gi, '');
+ pee = pee.replace(new RegExp('<p>\\s*(</?(?:'+blocklist+')(?: [^>]*)?>)\\s*</p>', 'gi'), "$1");
+ pee = pee.replace(/<p>(<li.+?)<\/p>/gi, '$1');
+ pee = pee.replace(/<p>\s*<blockquote([^>]*)>/gi, '<blockquote$1><p>');
+ pee = pee.replace(/<\/blockquote>\s*<\/p>/gi, '</p></blockquote>');
+ pee = pee.replace(new RegExp('<p>\\s*(</?(?:'+blocklist+')(?: [^>]*)?>)', 'gi'), "$1");
+ pee = pee.replace(new RegExp('(</?(?:'+blocklist+')(?: [^>]*)?>)\\s*</p>', 'gi'), "$1");
+ pee = pee.replace(/\s*\n/gi, '<br />\n');
+ pee = pee.replace(new RegExp('(</?(?:'+blocklist+')[^>]*>)\\s*<br />', 'gi'), "$1");
+ pee = pee.replace(/<br \/>(\s*<\/?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)>)/gi, '$1');
+ pee = pee.replace(/(?:<p>|<br ?\/?>)*\s*\[caption([^\[]+)\[\/caption\]\s*(?:<\/p>|<br ?\/?>)*/gi, '[caption$1[/caption]');
+
+ pee = pee.replace(/(<(?:div|th|td|form|fieldset|dd)[^>]*>)(.*?)<\/p>/g, function(a, b, c) {
+ if ( c.match(/<p( [^>]*)?>/) )
+ return a;
+
+ return b + '<p>' + c + '</p>';
+ });
+
+ // put back the line breaks in pre|script
+ if ( preserve_linebreaks )
+ pee = pee.replace(/<wp-temp-lb>/g, '\n');
+
+ if ( preserve_br )
+ pee = pee.replace(/<wp-temp-br([^>]*)>/g, '<br$1>');
+
+ return pee;
+ },
+
+ pre_wpautop : function(content) {
+ var t = this, o = { o: t, data: content, unfiltered: content },
+ q = typeof(jQuery) != 'undefined';
+
+ if ( q )
+ jQuery('body').trigger('beforePreWpautop', [o]);
+ o.data = t._wp_Nop(o.data);
+ if ( q )
+ jQuery('body').trigger('afterPreWpautop', [o]);
+
+ return o.data;
+ },
+
+ wpautop : function(pee) {
+ var t = this, o = { o: t, data: pee, unfiltered: pee },
+ q = typeof(jQuery) != 'undefined';
+
+ if ( q )
+ jQuery('body').trigger('beforeWpautop', [o]);
+ o.data = t._wp_Autop(o.data);
+ if ( q )
+ jQuery('body').trigger('afterWpautop', [o]);
+
+ return o.data;
+ }
+}
diff --git a/src/wp-admin/js/farbtastic.js b/src/wp-admin/js/farbtastic.js
new file mode 100644
index 0000000000..5404fb6e3d
--- /dev/null
+++ b/src/wp-admin/js/farbtastic.js
@@ -0,0 +1,276 @@
+/*!
+ * Farbtastic: jQuery color picker plug-in v1.3u
+ *
+ * Licensed under the GPL license:
+ * http://www.gnu.org/licenses/gpl.html
+ */
+(function($) {
+
+$.fn.farbtastic = function (options) {
+ $.farbtastic(this, options);
+ return this;
+};
+
+$.farbtastic = function (container, callback) {
+ var container = $(container).get(0);
+ return container.farbtastic || (container.farbtastic = new $._farbtastic(container, callback));
+};
+
+$._farbtastic = function (container, callback) {
+ // Store farbtastic object
+ var fb = this;
+
+ // Insert markup
+ $(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
+ var e = $('.farbtastic', container);
+ fb.wheel = $('.wheel', container).get(0);
+ // Dimensions
+ fb.radius = 84;
+ fb.square = 100;
+ fb.width = 194;
+
+ // Fix background PNGs in IE6
+ if (navigator.appVersion.match(/MSIE [0-6]\./)) {
+ $('*', e).each(function () {
+ if (this.currentStyle.backgroundImage != 'none') {
+ var image = this.currentStyle.backgroundImage;
+ image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
+ $(this).css({
+ 'backgroundImage': 'none',
+ 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+ });
+ }
+ });
+ }
+
+ /**
+ * Link to the given element(s) or callback.
+ */
+ fb.linkTo = function (callback) {
+ // Unbind previous nodes
+ if (typeof fb.callback == 'object') {
+ $(fb.callback).unbind('keyup', fb.updateValue);
+ }
+
+ // Reset color
+ fb.color = null;
+
+ // Bind callback or elements
+ if (typeof callback == 'function') {
+ fb.callback = callback;
+ }
+ else if (typeof callback == 'object' || typeof callback == 'string') {
+ fb.callback = $(callback);
+ fb.callback.bind('keyup', fb.updateValue);
+ if (fb.callback.get(0).value) {
+ fb.setColor(fb.callback.get(0).value);
+ }
+ }
+ return this;
+ };
+ fb.updateValue = function (event) {
+ if (this.value && this.value != fb.color) {
+ fb.setColor(this.value);
+ }
+ };
+
+ /**
+ * Change color with HTML syntax #123456
+ */
+ fb.setColor = function (color) {
+ var unpack = fb.unpack(color);
+ if (fb.color != color && unpack) {
+ fb.color = color;
+ fb.rgb = unpack;
+ fb.hsl = fb.RGBToHSL(fb.rgb);
+ fb.updateDisplay();
+ }
+ return this;
+ };
+
+ /**
+ * Change color with HSL triplet [0..1, 0..1, 0..1]
+ */
+ fb.setHSL = function (hsl) {
+ fb.hsl = hsl;
+ fb.rgb = fb.HSLToRGB(hsl);
+ fb.color = fb.pack(fb.rgb);
+ fb.updateDisplay();
+ return this;
+ };
+
+ /////////////////////////////////////////////////////
+
+ /**
+ * Retrieve the coordinates of the given event relative to the center
+ * of the widget.
+ */
+ fb.widgetCoords = function (event) {
+ var offset = $(fb.wheel).offset();
+ return { x: (event.pageX - offset.left) - fb.width / 2, y: (event.pageY - offset.top) - fb.width / 2 };
+ };
+
+ /**
+ * Mousedown handler
+ */
+ fb.mousedown = function (event) {
+ // Capture mouse
+ if (!document.dragging) {
+ $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);
+ document.dragging = true;
+ }
+
+ // Check which area is being dragged
+ var pos = fb.widgetCoords(event);
+ fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
+
+ // Process
+ fb.mousemove(event);
+ return false;
+ };
+
+ /**
+ * Mousemove handler
+ */
+ fb.mousemove = function (event) {
+ // Get coordinates relative to color picker center
+ var pos = fb.widgetCoords(event);
+
+ // Set new HSL parameters
+ if (fb.circleDrag) {
+ var hue = Math.atan2(pos.x, -pos.y) / 6.28;
+ if (hue < 0) hue += 1;
+ fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
+ }
+ else {
+ var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
+ var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
+ fb.setHSL([fb.hsl[0], sat, lum]);
+ }
+ return false;
+ };
+
+ /**
+ * Mouseup handler
+ */
+ fb.mouseup = function () {
+ // Uncapture mouse
+ $(document).unbind('mousemove', fb.mousemove);
+ $(document).unbind('mouseup', fb.mouseup);
+ document.dragging = false;
+ };
+
+ /**
+ * Update the markers and styles
+ */
+ fb.updateDisplay = function () {
+ // Markers
+ var angle = fb.hsl[0] * 6.28;
+ $('.h-marker', e).css({
+ left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
+ top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
+ });
+
+ $('.sl-marker', e).css({
+ left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
+ top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
+ });
+
+ // Saturation/Luminance gradient
+ $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
+
+ // Linked elements or callback
+ if (typeof fb.callback == 'object') {
+ // Set background/foreground color
+ $(fb.callback).css({
+ backgroundColor: fb.color,
+ color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
+ });
+
+ // Change linked value
+ $(fb.callback).each(function() {
+ if (this.value && this.value != fb.color) {
+ this.value = fb.color;
+ }
+ });
+ }
+ else if (typeof fb.callback == 'function') {
+ fb.callback.call(fb, fb.color);
+ }
+ };
+
+ /* Various color utility functions */
+ fb.pack = function (rgb) {
+ var r = Math.round(rgb[0] * 255);
+ var g = Math.round(rgb[1] * 255);
+ var b = Math.round(rgb[2] * 255);
+ return '#' + (r < 16 ? '0' : '') + r.toString(16) +
+ (g < 16 ? '0' : '') + g.toString(16) +
+ (b < 16 ? '0' : '') + b.toString(16);
+ };
+
+ fb.unpack = function (color) {
+ if (color.length == 7) {
+ return [parseInt('0x' + color.substring(1, 3)) / 255,
+ parseInt('0x' + color.substring(3, 5)) / 255,
+ parseInt('0x' + color.substring(5, 7)) / 255];
+ }
+ else if (color.length == 4) {
+ return [parseInt('0x' + color.substring(1, 2)) / 15,
+ parseInt('0x' + color.substring(2, 3)) / 15,
+ parseInt('0x' + color.substring(3, 4)) / 15];
+ }
+ };
+
+ fb.HSLToRGB = function (hsl) {
+ var m1, m2, r, g, b;
+ var h = hsl[0], s = hsl[1], l = hsl[2];
+ m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
+ m1 = l * 2 - m2;
+ return [this.hueToRGB(m1, m2, h+0.33333),
+ this.hueToRGB(m1, m2, h),
+ this.hueToRGB(m1, m2, h-0.33333)];
+ };
+
+ fb.hueToRGB = function (m1, m2, h) {
+ h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
+ if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
+ if (h * 2 < 1) return m2;
+ if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
+ return m1;
+ };
+
+ fb.RGBToHSL = function (rgb) {
+ var min, max, delta, h, s, l;
+ var r = rgb[0], g = rgb[1], b = rgb[2];
+ min = Math.min(r, Math.min(g, b));
+ max = Math.max(r, Math.max(g, b));
+ delta = max - min;
+ l = (min + max) / 2;
+ s = 0;
+ if (l > 0 && l < 1) {
+ s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
+ }
+ h = 0;
+ if (delta > 0) {
+ if (max == r && max != g) h += (g - b) / delta;
+ if (max == g && max != b) h += (2 + (b - r) / delta);
+ if (max == b && max != r) h += (4 + (r - g) / delta);
+ h /= 6;
+ }
+ return [h, s, l];
+ };
+
+ // Install mousedown handler (the others are set on the document on-demand)
+ $('*', e).mousedown(fb.mousedown);
+
+ // Init color
+ fb.setColor('#000000');
+
+ // Set linked elements/callback
+ if (callback) {
+ fb.linkTo(callback);
+ }
+};
+
+})(jQuery); \ No newline at end of file
diff --git a/src/wp-admin/js/gallery.js b/src/wp-admin/js/gallery.js
new file mode 100644
index 0000000000..d7b4bb1910
--- /dev/null
+++ b/src/wp-admin/js/gallery.js
@@ -0,0 +1,199 @@
+jQuery(document).ready(function($) {
+ var gallerySortable, gallerySortableInit, w, desc = false;
+
+ gallerySortableInit = function() {
+ gallerySortable = $('#media-items').sortable( {
+ items: 'div.media-item',
+ placeholder: 'sorthelper',
+ axis: 'y',
+ distance: 2,
+ handle: 'div.filename',
+ stop: function(e, ui) {
+ // When an update has occurred, adjust the order for each item
+ var all = $('#media-items').sortable('toArray'), len = all.length;
+ $.each(all, function(i, id) {
+ var order = desc ? (len - i) : (1 + i);
+ $('#' + id + ' .menu_order input').val(order);
+ });
+ }
+ } );
+ }
+
+ sortIt = function() {
+ var all = $('.menu_order_input'), len = all.length;
+ all.each(function(i){
+ var order = desc ? (len - i) : (1 + i);
+ $(this).val(order);
+ });
+ }
+
+ clearAll = function(c) {
+ c = c || 0;
+ $('.menu_order_input').each(function(){
+ if ( this.value == '0' || c ) this.value = '';
+ });
+ }
+
+ $('#asc').click(function(){desc = false; sortIt(); return false;});
+ $('#desc').click(function(){desc = true; sortIt(); return false;});
+ $('#clear').click(function(){clearAll(1); return false;});
+ $('#showall').click(function(){
+ $('#sort-buttons span a').toggle();
+ $('a.describe-toggle-on').hide();
+ $('a.describe-toggle-off, table.slidetoggle').show();
+ $('img.pinkynail').toggle(false);
+ return false;
+ });
+ $('#hideall').click(function(){
+ $('#sort-buttons span a').toggle();
+ $('a.describe-toggle-on').show();
+ $('a.describe-toggle-off, table.slidetoggle').hide();
+ $('img.pinkynail').toggle(true);
+ return false;
+ });
+
+ // initialize sortable
+ gallerySortableInit();
+ clearAll();
+
+ if ( $('#media-items>*').length > 1 ) {
+ w = wpgallery.getWin();
+
+ $('#save-all, #gallery-settings').show();
+ if ( typeof w.tinyMCE != 'undefined' && w.tinyMCE.activeEditor && ! w.tinyMCE.activeEditor.isHidden() ) {
+ wpgallery.mcemode = true;
+ wpgallery.init();
+ } else {
+ $('#insert-gallery').show();
+ }
+ }
+});
+
+jQuery(window).unload( function () { tinymce = tinyMCE = wpgallery = null; } ); // Cleanup
+
+/* gallery settings */
+var tinymce = null, tinyMCE, wpgallery;
+
+wpgallery = {
+ mcemode : false,
+ editor : {},
+ dom : {},
+ is_update : false,
+ el : {},
+
+ I : function(e) {
+ return document.getElementById(e);
+ },
+
+ init: function() {
+ var t = this, li, q, i, it, w = t.getWin();
+
+ if ( ! t.mcemode ) return;
+
+ li = ('' + document.location.search).replace(/^\?/, '').split('&');
+ q = {};
+ for (i=0; i<li.length; i++) {
+ it = li[i].split('=');
+ q[unescape(it[0])] = unescape(it[1]);
+ }
+
+ if (q.mce_rdomain)
+ document.domain = q.mce_rdomain;
+
+ // Find window & API
+ tinymce = w.tinymce;
+ tinyMCE = w.tinyMCE;
+ t.editor = tinymce.EditorManager.activeEditor;
+
+ t.setup();
+ },
+
+ getWin : function() {
+ return window.dialogArguments || opener || parent || top;
+ },
+
+ setup : function() {
+ var t = this, a, ed = t.editor, g, columns, link, order, orderby;
+ if ( ! t.mcemode ) return;
+
+ t.el = ed.selection.getNode();
+
+ if ( t.el.nodeName != 'IMG' || ! ed.dom.hasClass(t.el, 'wpGallery') ) {
+ if ( (g = ed.dom.select('img.wpGallery')) && g[0] ) {
+ t.el = g[0];
+ } else {
+ if ( getUserSetting('galfile') == '1' ) t.I('linkto-file').checked = "checked";
+ if ( getUserSetting('galdesc') == '1' ) t.I('order-desc').checked = "checked";
+ if ( getUserSetting('galcols') ) t.I('columns').value = getUserSetting('galcols');
+ if ( getUserSetting('galord') ) t.I('orderby').value = getUserSetting('galord');
+ jQuery('#insert-gallery').show();
+ return;
+ }
+ }
+
+ a = ed.dom.getAttrib(t.el, 'title');
+ a = ed.dom.decode(a);
+
+ if ( a ) {
+ jQuery('#update-gallery').show();
+ t.is_update = true;
+
+ columns = a.match(/columns=['"]([0-9]+)['"]/);
+ link = a.match(/link=['"]([^'"]+)['"]/i);
+ order = a.match(/order=['"]([^'"]+)['"]/i);
+ orderby = a.match(/orderby=['"]([^'"]+)['"]/i);
+
+ if ( link && link[1] ) t.I('linkto-file').checked = "checked";
+ if ( order && order[1] ) t.I('order-desc').checked = "checked";
+ if ( columns && columns[1] ) t.I('columns').value = ''+columns[1];
+ if ( orderby && orderby[1] ) t.I('orderby').value = orderby[1];
+ } else {
+ jQuery('#insert-gallery').show();
+ }
+ },
+
+ update : function() {
+ var t = this, ed = t.editor, all = '', s;
+
+ if ( ! t.mcemode || ! t.is_update ) {
+ s = '[gallery'+t.getSettings()+']';
+ t.getWin().send_to_editor(s);
+ return;
+ }
+
+ if (t.el.nodeName != 'IMG') return;
+
+ all = ed.dom.decode(ed.dom.getAttrib(t.el, 'title'));
+ all = all.replace(/\s*(order|link|columns|orderby)=['"]([^'"]+)['"]/gi, '');
+ all += t.getSettings();
+
+ ed.dom.setAttrib(t.el, 'title', all);
+ t.getWin().tb_remove();
+ },
+
+ getSettings : function() {
+ var I = this.I, s = '';
+
+ if ( I('linkto-file').checked ) {
+ s += ' link="file"';
+ setUserSetting('galfile', '1');
+ }
+
+ if ( I('order-desc').checked ) {
+ s += ' order="DESC"';
+ setUserSetting('galdesc', '1');
+ }
+
+ if ( I('columns').value != 3 ) {
+ s += ' columns="'+I('columns').value+'"';
+ setUserSetting('galcols', I('columns').value);
+ }
+
+ if ( I('orderby').value != 'menu_order' ) {
+ s += ' orderby="'+I('orderby').value+'"';
+ setUserSetting('galord', I('orderby').value);
+ }
+
+ return s;
+ }
+};
diff --git a/src/wp-admin/js/image-edit.js b/src/wp-admin/js/image-edit.js
new file mode 100644
index 0000000000..b11e2d3ab0
--- /dev/null
+++ b/src/wp-admin/js/image-edit.js
@@ -0,0 +1,573 @@
+var imageEdit;
+
+(function($) {
+imageEdit = {
+ iasapi : {},
+ hold : {},
+ postid : '',
+
+ intval : function(f) {
+ return f | 0;
+ },
+
+ setDisabled : function(el, s) {
+ if ( s ) {
+ el.removeClass('disabled');
+ $('input', el).removeAttr('disabled');
+ } else {
+ el.addClass('disabled');
+ $('input', el).prop('disabled', true);
+ }
+ },
+
+ init : function(postid, nonce) {
+ var t = this, old = $('#image-editor-' + t.postid),
+ x = t.intval( $('#imgedit-x-' + postid).val() ),
+ y = t.intval( $('#imgedit-y-' + postid).val() );
+
+ if ( t.postid != postid && old.length )
+ t.close(t.postid);
+
+ t.hold['w'] = t.hold['ow'] = x;
+ t.hold['h'] = t.hold['oh'] = y;
+ t.hold['xy_ratio'] = x / y;
+ t.hold['sizer'] = parseFloat( $('#imgedit-sizer-' + postid).val() );
+ t.postid = postid;
+ $('#imgedit-response-' + postid).empty();
+
+ $('input[type="text"]', '#imgedit-panel-' + postid).keypress(function(e) {
+ var k = e.keyCode;
+
+ if ( 36 < k && k < 41 )
+ $(this).blur()
+
+ if ( 13 == k ) {
+ e.preventDefault();
+ e.stopPropagation();
+ return false;
+ }
+ });
+ },
+
+ toggleEditor : function(postid, toggle) {
+ var wait = $('#imgedit-wait-' + postid);
+
+ if ( toggle )
+ wait.height( $('#imgedit-panel-' + postid).height() ).fadeIn('fast');
+ else
+ wait.fadeOut('fast');
+ },
+
+ toggleHelp : function(el) {
+ $(el).siblings('.imgedit-help').slideToggle('fast');
+ return false;
+ },
+
+ getTarget : function(postid) {
+ return $('input[name="imgedit-target-' + postid + '"]:checked', '#imgedit-save-target-' + postid).val() || 'full';
+ },
+
+ scaleChanged : function(postid, x) {
+ var w = $('#imgedit-scale-width-' + postid), h = $('#imgedit-scale-height-' + postid),
+ warn = $('#imgedit-scale-warn-' + postid), w1 = '', h1 = '';
+
+ if ( x ) {
+ h1 = (w.val() != '') ? Math.round( w.val() / this.hold['xy_ratio'] ) : '';
+ h.val( h1 );
+ } else {
+ w1 = (h.val() != '') ? Math.round( h.val() * this.hold['xy_ratio'] ) : '';
+ w.val( w1 );
+ }
+
+ if ( ( h1 && h1 > this.hold['oh'] ) || ( w1 && w1 > this.hold['ow'] ) )
+ warn.css('visibility', 'visible');
+ else
+ warn.css('visibility', 'hidden');
+ },
+
+ getSelRatio : function(postid) {
+ var x = this.hold['w'], y = this.hold['h'],
+ X = this.intval( $('#imgedit-crop-width-' + postid).val() ),
+ Y = this.intval( $('#imgedit-crop-height-' + postid).val() );
+
+ if ( X && Y )
+ return X + ':' + Y;
+
+ if ( x && y )
+ return x + ':' + y;
+
+ return '1:1';
+ },
+
+ filterHistory : function(postid, setSize) {
+ // apply undo state to history
+ var history = $('#imgedit-history-' + postid).val(), pop, n, o, i, op = [];
+
+ if ( history != '' ) {
+ history = JSON.parse(history);
+ pop = this.intval( $('#imgedit-undone-' + postid).val() );
+ if ( pop > 0 ) {
+ while ( pop > 0 ) {
+ history.pop();
+ pop--;
+ }
+ }
+
+ if ( setSize ) {
+ if ( !history.length ) {
+ this.hold['w'] = this.hold['ow'];
+ this.hold['h'] = this.hold['oh'];
+ return '';
+ }
+
+ // restore
+ o = history[history.length - 1];
+ o = o.c || o.r || o.f || false;
+
+ if ( o ) {
+ this.hold['w'] = o.fw;
+ this.hold['h'] = o.fh;
+ }
+ }
+
+ // filter the values
+ for ( n in history ) {
+ i = history[n];
+ if ( i.hasOwnProperty('c') ) {
+ op[n] = { 'c': { 'x': i.c.x, 'y': i.c.y, 'w': i.c.w, 'h': i.c.h } };
+ } else if ( i.hasOwnProperty('r') ) {
+ op[n] = { 'r': i.r.r };
+ } else if ( i.hasOwnProperty('f') ) {
+ op[n] = { 'f': i.f.f };
+ }
+ }
+ return JSON.stringify(op);
+ }
+ return '';
+ },
+
+ refreshEditor : function(postid, nonce, callback) {
+ var t = this, data, img;
+
+ t.toggleEditor(postid, 1);
+ data = {
+ 'action': 'imgedit-preview',
+ '_ajax_nonce': nonce,
+ 'postid': postid,
+ 'history': t.filterHistory(postid, 1),
+ 'rand': t.intval(Math.random() * 1000000)
+ };
+
+ img = $('<img id="image-preview-' + postid + '" />');
+ img.load( function() {
+ var max1, max2, parent = $('#imgedit-crop-' + postid), t = imageEdit;
+
+ parent.empty().append(img);
+
+ // w, h are the new full size dims
+ max1 = Math.max( t.hold.w, t.hold.h );
+ max2 = Math.max( $(img).width(), $(img).height() );
+ t.hold['sizer'] = max1 > max2 ? max2 / max1 : 1;
+
+ t.initCrop(postid, img, parent);
+ t.setCropSelection(postid, 0);
+
+ if ( (typeof callback != "unknown") && callback != null )
+ callback();
+
+ if ( $('#imgedit-history-' + postid).val() && $('#imgedit-undone-' + postid).val() == 0 )
+ $('input.imgedit-submit-btn', '#imgedit-panel-' + postid).removeAttr('disabled');
+ else
+ $('input.imgedit-submit-btn', '#imgedit-panel-' + postid).prop('disabled', true);
+
+ t.toggleEditor(postid, 0);
+ }).error(function(){
+ $('#imgedit-crop-' + postid).empty().append('<div class="error"><p>' + imageEditL10n.error + '</p></div>');
+ t.toggleEditor(postid, 0);
+ }).attr('src', ajaxurl + '?' + $.param(data));
+ },
+
+ action : function(postid, nonce, action) {
+ var t = this, data, w, h, fw, fh;
+
+ if ( t.notsaved(postid) )
+ return false;
+
+ data = {
+ 'action': 'image-editor',
+ '_ajax_nonce': nonce,
+ 'postid': postid
+ };
+
+ if ( 'scale' == action ) {
+ w = $('#imgedit-scale-width-' + postid),
+ h = $('#imgedit-scale-height-' + postid),
+ fw = t.intval(w.val()),
+ fh = t.intval(h.val());
+
+ if ( fw < 1 ) {
+ w.focus();
+ return false;
+ } else if ( fh < 1 ) {
+ h.focus();
+ return false;
+ }
+
+ if ( fw == t.hold.ow || fh == t.hold.oh )
+ return false;
+
+ data['do'] = 'scale';
+ data['fwidth'] = fw;
+ data['fheight'] = fh;
+ } else if ( 'restore' == action ) {
+ data['do'] = 'restore';
+ } else {
+ return false;
+ }
+
+ t.toggleEditor(postid, 1);
+ $.post(ajaxurl, data, function(r) {
+ $('#image-editor-' + postid).empty().append(r);
+ t.toggleEditor(postid, 0);
+ });
+ },
+
+ save : function(postid, nonce) {
+ var data, target = this.getTarget(postid), history = this.filterHistory(postid, 0);
+
+ if ( '' == history )
+ return false;
+
+ this.toggleEditor(postid, 1);
+ data = {
+ 'action': 'image-editor',
+ '_ajax_nonce': nonce,
+ 'postid': postid,
+ 'history': history,
+ 'target': target,
+ 'context': $('#image-edit-context').length ? $('#image-edit-context').val() : null,
+ 'do': 'save'
+ };
+
+ $.post(ajaxurl, data, function(r) {
+ var ret = JSON.parse(r);
+
+ if ( ret.error ) {
+ $('#imgedit-response-' + postid).html('<div class="error"><p>' + ret.error + '</p><div>');
+ imageEdit.close(postid);
+ return;
+ }
+
+ if ( ret.fw && ret.fh )
+ $('#media-dims-' + postid).html( ret.fw + ' &times; ' + ret.fh );
+
+ if ( ret.thumbnail )
+ $('.thumbnail', '#thumbnail-head-' + postid).attr('src', ''+ret.thumbnail);
+
+ if ( ret.msg )
+ $('#imgedit-response-' + postid).html('<div class="updated"><p>' + ret.msg + '</p></div>');
+
+ imageEdit.close(postid);
+ });
+ },
+
+ open : function(postid, nonce) {
+ var data, elem = $('#image-editor-' + postid), head = $('#media-head-' + postid),
+ btn = $('#imgedit-open-btn-' + postid), spin = btn.siblings('.spinner');
+
+ btn.prop('disabled', true);
+ spin.show();
+
+ data = {
+ 'action': 'image-editor',
+ '_ajax_nonce': nonce,
+ 'postid': postid,
+ 'do': 'open'
+ };
+
+ elem.load(ajaxurl, data, function() {
+ elem.fadeIn('fast');
+ head.fadeOut('fast', function(){
+ btn.removeAttr('disabled');
+ spin.hide();
+ });
+ });
+ },
+
+ imgLoaded : function(postid) {
+ var img = $('#image-preview-' + postid), parent = $('#imgedit-crop-' + postid);
+
+ this.initCrop(postid, img, parent);
+ this.setCropSelection(postid, 0);
+ this.toggleEditor(postid, 0);
+ },
+
+ initCrop : function(postid, image, parent) {
+ var t = this, selW = $('#imgedit-sel-width-' + postid),
+ selH = $('#imgedit-sel-height-' + postid);
+
+ t.iasapi = $(image).imgAreaSelect({
+ parent: parent,
+ instance: true,
+ handles: true,
+ keys: true,
+ minWidth: 3,
+ minHeight: 3,
+
+ onInit: function(img, c) {
+ parent.children().mousedown(function(e){
+ var ratio = false, sel, defRatio;
+
+ if ( e.shiftKey ) {
+ sel = t.iasapi.getSelection();
+ defRatio = t.getSelRatio(postid);
+ ratio = ( sel && sel.width && sel.height ) ? sel.width + ':' + sel.height : defRatio;
+ }
+
+ t.iasapi.setOptions({
+ aspectRatio: ratio
+ });
+ });
+ },
+
+ onSelectStart: function(img, c) {
+ imageEdit.setDisabled($('#imgedit-crop-sel-' + postid), 1);
+ },
+
+ onSelectEnd: function(img, c) {
+ imageEdit.setCropSelection(postid, c);
+ },
+
+ onSelectChange: function(img, c) {
+ var sizer = imageEdit.hold.sizer;
+ selW.val( imageEdit.round(c.width / sizer) );
+ selH.val( imageEdit.round(c.height / sizer) );
+ }
+ });
+ },
+
+ setCropSelection : function(postid, c) {
+ var sel, min = $('#imgedit-minthumb-' + postid).val() || '128:128',
+ sizer = this.hold['sizer'];
+ min = min.split(':');
+ c = c || 0;
+
+ if ( !c || ( c.width < 3 && c.height < 3 ) ) {
+ this.setDisabled($('.imgedit-crop', '#imgedit-panel-' + postid), 0);
+ this.setDisabled($('#imgedit-crop-sel-' + postid), 0);
+ $('#imgedit-sel-width-' + postid).val('');
+ $('#imgedit-sel-height-' + postid).val('');
+ $('#imgedit-selection-' + postid).val('');
+ return false;
+ }
+
+ if ( c.width < (min[0] * sizer) && c.height < (min[1] * sizer) ) {
+ this.setDisabled($('.imgedit-crop', '#imgedit-panel-' + postid), 0);
+ $('#imgedit-selection-' + postid).val('');
+ return false;
+ }
+
+ sel = { 'x': c.x1, 'y': c.y1, 'w': c.width, 'h': c.height };
+ this.setDisabled($('.imgedit-crop', '#imgedit-panel-' + postid), 1);
+ $('#imgedit-selection-' + postid).val( JSON.stringify(sel) );
+ },
+
+ close : function(postid, warn) {
+ warn = warn || false;
+
+ if ( warn && this.notsaved(postid) )
+ return false;
+
+ this.iasapi = {};
+ this.hold = {};
+ $('#image-editor-' + postid).fadeOut('fast', function() {
+ $('#media-head-' + postid).fadeIn('fast');
+ $(this).empty();
+ });
+ },
+
+ notsaved : function(postid) {
+ var h = $('#imgedit-history-' + postid).val(),
+ history = (h != '') ? JSON.parse(h) : new Array(),
+ pop = this.intval( $('#imgedit-undone-' + postid).val() );
+
+ if ( pop < history.length ) {
+ if ( confirm( $('#imgedit-leaving-' + postid).html() ) )
+ return false;
+ return true;
+ }
+ return false;
+ },
+
+ addStep : function(op, postid, nonce) {
+ var t = this, elem = $('#imgedit-history-' + postid),
+ history = (elem.val() != '') ? JSON.parse(elem.val()) : new Array(),
+ undone = $('#imgedit-undone-' + postid),
+ pop = t.intval(undone.val());
+
+ while ( pop > 0 ) {
+ history.pop();
+ pop--;
+ }
+ undone.val(0); // reset
+
+ history.push(op);
+ elem.val( JSON.stringify(history) );
+
+ t.refreshEditor(postid, nonce, function() {
+ t.setDisabled($('#image-undo-' + postid), true);
+ t.setDisabled($('#image-redo-' + postid), false);
+ });
+ },
+
+ rotate : function(angle, postid, nonce, t) {
+ if ( $(t).hasClass('disabled') )
+ return false;
+
+ this.addStep({ 'r': { 'r': angle, 'fw': this.hold['h'], 'fh': this.hold['w'] }}, postid, nonce);
+ },
+
+ flip : function (axis, postid, nonce, t) {
+ if ( $(t).hasClass('disabled') )
+ return false;
+
+ this.addStep({ 'f': { 'f': axis, 'fw': this.hold['w'], 'fh': this.hold['h'] }}, postid, nonce);
+ },
+
+ crop : function (postid, nonce, t) {
+ var sel = $('#imgedit-selection-' + postid).val(),
+ w = this.intval( $('#imgedit-sel-width-' + postid).val() ),
+ h = this.intval( $('#imgedit-sel-height-' + postid).val() );
+
+ if ( $(t).hasClass('disabled') || sel == '' )
+ return false;
+
+ sel = JSON.parse(sel);
+ if ( sel.w > 0 && sel.h > 0 && w > 0 && h > 0 ) {
+ sel['fw'] = w;
+ sel['fh'] = h;
+ this.addStep({ 'c': sel }, postid, nonce);
+ }
+ },
+
+ undo : function (postid, nonce) {
+ var t = this, button = $('#image-undo-' + postid), elem = $('#imgedit-undone-' + postid),
+ pop = t.intval( elem.val() ) + 1;
+
+ if ( button.hasClass('disabled') )
+ return;
+
+ elem.val(pop);
+ t.refreshEditor(postid, nonce, function() {
+ var elem = $('#imgedit-history-' + postid),
+ history = (elem.val() != '') ? JSON.parse(elem.val()) : new Array();
+
+ t.setDisabled($('#image-redo-' + postid), true);
+ t.setDisabled(button, pop < history.length);
+ });
+ },
+
+ redo : function(postid, nonce) {
+ var t = this, button = $('#image-redo-' + postid), elem = $('#imgedit-undone-' + postid),
+ pop = t.intval( elem.val() ) - 1;
+
+ if ( button.hasClass('disabled') )
+ return;
+
+ elem.val(pop);
+ t.refreshEditor(postid, nonce, function() {
+ t.setDisabled($('#image-undo-' + postid), true);
+ t.setDisabled(button, pop > 0);
+ });
+ },
+
+ setNumSelection : function(postid) {
+ var sel, elX = $('#imgedit-sel-width-' + postid), elY = $('#imgedit-sel-height-' + postid),
+ x = this.intval( elX.val() ), y = this.intval( elY.val() ),
+ img = $('#image-preview-' + postid), imgh = img.height(), imgw = img.width(),
+ sizer = this.hold['sizer'], x1, y1, x2, y2, ias = this.iasapi;
+
+ if ( x < 1 ) {
+ elX.val('');
+ return false;
+ }
+
+ if ( y < 1 ) {
+ elY.val('');
+ return false;
+ }
+
+ if ( x && y && ( sel = ias.getSelection() ) ) {
+ x2 = sel.x1 + Math.round( x * sizer );
+ y2 = sel.y1 + Math.round( y * sizer );
+ x1 = sel.x1;
+ y1 = sel.y1;
+
+ if ( x2 > imgw ) {
+ x1 = 0;
+ x2 = imgw;
+ elX.val( Math.round( x2 / sizer ) );
+ }
+
+ if ( y2 > imgh ) {
+ y1 = 0;
+ y2 = imgh;
+ elY.val( Math.round( y2 / sizer ) );
+ }
+
+ ias.setSelection( x1, y1, x2, y2 );
+ ias.update();
+ this.setCropSelection(postid, ias.getSelection());
+ }
+ },
+
+ round : function(num) {
+ var s;
+ num = Math.round(num);
+
+ if ( this.hold.sizer > 0.6 )
+ return num;
+
+ s = num.toString().slice(-1);
+
+ if ( '1' == s )
+ return num - 1;
+ else if ( '9' == s )
+ return num + 1;
+
+ return num;
+ },
+
+ setRatioSelection : function(postid, n, el) {
+ var sel, r, x = this.intval( $('#imgedit-crop-width-' + postid).val() ),
+ y = this.intval( $('#imgedit-crop-height-' + postid).val() ),
+ h = $('#image-preview-' + postid).height();
+
+ if ( !this.intval( $(el).val() ) ) {
+ $(el).val('');
+ return;
+ }
+
+ if ( x && y ) {
+ this.iasapi.setOptions({
+ aspectRatio: x + ':' + y
+ });
+
+ if ( sel = this.iasapi.getSelection(true) ) {
+ r = Math.ceil( sel.y1 + ((sel.x2 - sel.x1) / (x / y)) );
+
+ if ( r > h ) {
+ r = h;
+ if ( n )
+ $('#imgedit-crop-height-' + postid).val('');
+ else
+ $('#imgedit-crop-width-' + postid).val('');
+ }
+
+ this.iasapi.setSelection( sel.x1, sel.y1, sel.x2, r );
+ this.iasapi.update();
+ }
+ }
+ }
+}
+})(jQuery);
diff --git a/src/wp-admin/js/inline-edit-post.js b/src/wp-admin/js/inline-edit-post.js
new file mode 100644
index 0000000000..8076c31e09
--- /dev/null
+++ b/src/wp-admin/js/inline-edit-post.js
@@ -0,0 +1,331 @@
+(function($) {
+inlineEditPost = {
+
+ init : function(){
+ var t = this, qeRow = $('#inline-edit'), bulkRow = $('#bulk-edit');
+
+ t.type = $('table.widefat').hasClass('pages') ? 'page' : 'post';
+ t.what = '#post-';
+
+ // prepare the edit rows
+ qeRow.keyup(function(e){
+ if (e.which == 27)
+ return inlineEditPost.revert();
+ });
+ bulkRow.keyup(function(e){
+ if (e.which == 27)
+ return inlineEditPost.revert();
+ });
+
+ $('a.cancel', qeRow).click(function(){
+ return inlineEditPost.revert();
+ });
+ $('a.save', qeRow).click(function(){
+ return inlineEditPost.save(this);
+ });
+ $('td', qeRow).keydown(function(e){
+ if ( e.which == 13 )
+ return inlineEditPost.save(this);
+ });
+
+ $('a.cancel', bulkRow).click(function(){
+ return inlineEditPost.revert();
+ });
+
+ $('#inline-edit .inline-edit-private input[value="private"]').click( function(){
+ var pw = $('input.inline-edit-password-input');
+ if ( $(this).prop('checked') ) {
+ pw.val('').prop('disabled', true);
+ } else {
+ pw.prop('disabled', false);
+ }
+ });
+
+ // add events
+ $('#the-list').on('click', 'a.editinline', function(){
+ inlineEditPost.edit(this);
+ return false;
+ });
+
+ $('#bulk-title-div').parents('fieldset').after(
+ $('#inline-edit fieldset.inline-edit-categories').clone()
+ ).siblings( 'fieldset:last' ).prepend(
+ $('#inline-edit label.inline-edit-tags').clone()
+ );
+
+ $('select[name="_status"] option[value="future"]', bulkRow).remove();
+
+ $('#doaction, #doaction2').click(function(e){
+ var n = $(this).attr('id').substr(2);
+ if ( $('select[name="'+n+'"]').val() == 'edit' ) {
+ e.preventDefault();
+ t.setBulk();
+ } else if ( $('form#posts-filter tr.inline-editor').length > 0 ) {
+ t.revert();
+ }
+ });
+
+ $('#post-query-submit').mousedown(function(e){
+ t.revert();
+ $('select[name^="action"]').val('-1');
+ });
+ },
+
+ toggle : function(el){
+ var t = this;
+ $(t.what+t.getId(el)).css('display') == 'none' ? t.revert() : t.edit(el);
+ },
+
+ setBulk : function(){
+ var te = '', type = this.type, tax, c = true;
+ this.revert();
+
+ $('#bulk-edit td').attr('colspan', $('.widefat:first thead th:visible').length);
+ $('table.widefat tbody').prepend( $('#bulk-edit') );
+ $('#bulk-edit').addClass('inline-editor').show();
+
+ $('tbody th.check-column input[type="checkbox"]').each(function(i){
+ if ( $(this).prop('checked') ) {
+ c = false;
+ var id = $(this).val(), theTitle;
+ theTitle = $('#inline_'+id+' .post_title').html() || inlineEditL10n.notitle;
+ te += '<div id="ttle'+id+'"><a id="_'+id+'" class="ntdelbutton" title="'+inlineEditL10n.ntdeltitle+'">X</a>'+theTitle+'</div>';
+ }
+ });
+
+ if ( c )
+ return this.revert();
+
+ $('#bulk-titles').html(te);
+ $('#bulk-titles a').click(function(){
+ var id = $(this).attr('id').substr(1);
+
+ $('table.widefat input[value="' + id + '"]').prop('checked', false);
+ $('#ttle'+id).remove();
+ });
+
+ // enable autocomplete for tags
+ if ( 'post' == type ) {
+ // support multi taxonomies?
+ tax = 'post_tag';
+ $('tr.inline-editor textarea[name="tax_input['+tax+']"]').suggest( ajaxurl + '?action=ajax-tag-search&tax=' + tax, { delay: 500, minchars: 2, multiple: true, multipleSep: inlineEditL10n.comma + ' ' } );
+ }
+ $('html, body').animate( { scrollTop: 0 }, 'fast' );
+ },
+
+ edit : function(id) {
+ var t = this, fields, editRow, rowData, status, pageOpt, pageLevel, nextPage, pageLoop = true, nextLevel, cur_format, f;
+ t.revert();
+
+ if ( typeof(id) == 'object' )
+ id = t.getId(id);
+
+ fields = ['post_title', 'post_name', 'post_author', '_status', 'jj', 'mm', 'aa', 'hh', 'mn', 'ss', 'post_password', 'post_format', 'menu_order'];
+ if ( t.type == 'page' )
+ fields.push('post_parent', 'page_template');
+
+ // add the new blank row
+ editRow = $('#inline-edit').clone(true);
+ $('td', editRow).attr('colspan', $('.widefat:first thead th:visible').length);
+
+ if ( $(t.what+id).hasClass('alternate') )
+ $(editRow).addClass('alternate');
+ $(t.what+id).hide().after(editRow);
+
+ // populate the data
+ rowData = $('#inline_'+id);
+ if ( !$(':input[name="post_author"] option[value="' + $('.post_author', rowData).text() + '"]', editRow).val() ) {
+ // author no longer has edit caps, so we need to add them to the list of authors
+ $(':input[name="post_author"]', editRow).prepend('<option value="' + $('.post_author', rowData).text() + '">' + $('#' + t.type + '-' + id + ' .author').text() + '</option>');
+ }
+ if ( $(':input[name="post_author"] option', editRow).length == 1 ) {
+ $('label.inline-edit-author', editRow).hide();
+ }
+
+ // hide unsupported formats, but leave the current format alone
+ cur_format = $('.post_format', rowData).text();
+ $('option.unsupported', editRow).each(function() {
+ var $this = $(this);
+ if ( $this.val() != cur_format )
+ $this.remove();
+ });
+
+ for ( f = 0; f < fields.length; f++ ) {
+ $(':input[name="' + fields[f] + '"]', editRow).val( $('.'+fields[f], rowData).text() );
+ }
+
+ if ( $('.comment_status', rowData).text() == 'open' )
+ $('input[name="comment_status"]', editRow).prop("checked", true);
+ if ( $('.ping_status', rowData).text() == 'open' )
+ $('input[name="ping_status"]', editRow).prop("checked", true);
+ if ( $('.sticky', rowData).text() == 'sticky' )
+ $('input[name="sticky"]', editRow).prop("checked", true);
+
+ // hierarchical taxonomies
+ $('.post_category', rowData).each(function(){
+ var term_ids = $(this).text();
+
+ if ( term_ids ) {
+ taxname = $(this).attr('id').replace('_'+id, '');
+ $('ul.'+taxname+'-checklist :checkbox', editRow).val(term_ids.split(','));
+ }
+ });
+
+ //flat taxonomies
+ $('.tags_input', rowData).each(function(){
+ var terms = $(this).text(),
+ taxname = $(this).attr('id').replace('_' + id, ''),
+ textarea = $('textarea.tax_input_' + taxname, editRow),
+ comma = inlineEditL10n.comma;
+
+ if ( terms ) {
+ if ( ',' !== comma )
+ terms = terms.replace(/,/g, comma);
+ textarea.val(terms);
+ }
+
+ textarea.suggest( ajaxurl + '?action=ajax-tag-search&tax=' + taxname, { delay: 500, minchars: 2, multiple: true, multipleSep: inlineEditL10n.comma + ' ' } );
+ });
+
+ // handle the post status
+ status = $('._status', rowData).text();
+ if ( 'future' != status )
+ $('select[name="_status"] option[value="future"]', editRow).remove();
+
+ if ( 'private' == status ) {
+ $('input[name="keep_private"]', editRow).prop("checked", true);
+ $('input.inline-edit-password-input').val('').prop('disabled', true);
+ }
+
+ // remove the current page and children from the parent dropdown
+ pageOpt = $('select[name="post_parent"] option[value="' + id + '"]', editRow);
+ if ( pageOpt.length > 0 ) {
+ pageLevel = pageOpt[0].className.split('-')[1];
+ nextPage = pageOpt;
+ while ( pageLoop ) {
+ nextPage = nextPage.next('option');
+ if (nextPage.length == 0) break;
+ nextLevel = nextPage[0].className.split('-')[1];
+ if ( nextLevel <= pageLevel ) {
+ pageLoop = false;
+ } else {
+ nextPage.remove();
+ nextPage = pageOpt;
+ }
+ }
+ pageOpt.remove();
+ }
+
+ $(editRow).attr('id', 'edit-'+id).addClass('inline-editor').show();
+ $('.ptitle', editRow).focus();
+
+ return false;
+ },
+
+ save : function(id) {
+ var params, fields, page = $('.post_status_page').val() || '';
+
+ if ( typeof(id) == 'object' )
+ id = this.getId(id);
+
+ $('table.widefat .spinner').show();
+
+ params = {
+ action: 'inline-save',
+ post_type: typenow,
+ post_ID: id,
+ edit_date: 'true',
+ post_status: page
+ };
+
+ fields = $('#edit-'+id+' :input').serialize();
+ params = fields + '&' + $.param(params);
+
+ // make ajax request
+ $.post( ajaxurl, params,
+ function(r) {
+ $('table.widefat .spinner').hide();
+
+ if (r) {
+ if ( -1 != r.indexOf('<tr') ) {
+ $(inlineEditPost.what+id).remove();
+ $('#edit-'+id).before(r).remove();
+ $(inlineEditPost.what+id).hide().fadeIn();
+ } else {
+ r = r.replace( /<.[^<>]*?>/g, '' );
+ $('#edit-'+id+' .inline-edit-save .error').html(r).show();
+ }
+ } else {
+ $('#edit-'+id+' .inline-edit-save .error').html(inlineEditL10n.error).show();
+ }
+ }
+ , 'html');
+ return false;
+ },
+
+ revert : function(){
+ var id = $('table.widefat tr.inline-editor').attr('id');
+
+ if ( id ) {
+ $('table.widefat .spinner').hide();
+
+ if ( 'bulk-edit' == id ) {
+ $('table.widefat #bulk-edit').removeClass('inline-editor').hide();
+ $('#bulk-titles').html('');
+ $('#inlineedit').append( $('#bulk-edit') );
+ } else {
+ $('#'+id).remove();
+ id = id.substr( id.lastIndexOf('-') + 1 );
+ $(this.what+id).show();
+ }
+ }
+
+ return false;
+ },
+
+ getId : function(o) {
+ var id = $(o).closest('tr').attr('id'),
+ parts = id.split('-');
+ return parts[parts.length - 1];
+ }
+};
+
+$( document ).ready( function(){ inlineEditPost.init(); } );
+
+// Show/hide locks on posts
+$( document ).on( 'heartbeat-tick.wp-check-locked-posts', function( e, data ) {
+ var locked = data['wp-check-locked-posts'] || {};
+
+ $('#the-list tr').each( function(i, el) {
+ var key = el.id, row = $(el), lock_data, avatar;
+
+ if ( locked.hasOwnProperty( key ) ) {
+ if ( ! row.hasClass('wp-locked') ) {
+ lock_data = locked[key];
+ row.find('.column-title .locked-text').text( lock_data.text );
+ row.find('.check-column checkbox').prop('checked', false);
+
+ if ( lock_data.avatar_src ) {
+ avatar = $('<img class="avatar avatar-18 photo" width="18" height="18" />').attr( 'src', lock_data.avatar_src.replace(/&amp;/g, '&') );
+ row.find('.column-title .locked-avatar').empty().append( avatar );
+ }
+ row.addClass('wp-locked');
+ }
+ } else if ( row.hasClass('wp-locked') ) {
+ // Make room for the CSS animation
+ row.removeClass('wp-locked').delay(1000).find('.locked-info span').empty();
+ }
+ });
+}).on( 'heartbeat-send.wp-check-locked-posts', function( e, data ) {
+ var check = [];
+
+ $('#the-list tr').each( function(i, el) {
+ if ( el.id )
+ check.push( el.id );
+ });
+
+ if ( check.length )
+ data['wp-check-locked-posts'] = check;
+});
+
+}(jQuery));
diff --git a/src/wp-admin/js/inline-edit-tax.js b/src/wp-admin/js/inline-edit-tax.js
new file mode 100644
index 0000000000..6d5293ac3c
--- /dev/null
+++ b/src/wp-admin/js/inline-edit-tax.js
@@ -0,0 +1,118 @@
+
+(function($) {
+inlineEditTax = {
+
+ init : function() {
+ var t = this, row = $('#inline-edit');
+
+ t.type = $('#the-list').attr('data-wp-lists').substr(5);
+ t.what = '#'+t.type+'-';
+
+ $('#the-list').on('click', 'a.editinline', function(){
+ inlineEditTax.edit(this);
+ return false;
+ });
+
+ // prepare the edit row
+ row.keyup(function(e) { if(e.which == 27) return inlineEditTax.revert(); });
+
+ $('a.cancel', row).click(function() { return inlineEditTax.revert(); });
+ $('a.save', row).click(function() { return inlineEditTax.save(this); });
+ $('input, select', row).keydown(function(e) { if(e.which == 13) return inlineEditTax.save(this); });
+
+ $('#posts-filter input[type="submit"]').mousedown(function(e){
+ t.revert();
+ });
+ },
+
+ toggle : function(el) {
+ var t = this;
+ $(t.what+t.getId(el)).css('display') == 'none' ? t.revert() : t.edit(el);
+ },
+
+ edit : function(id) {
+ var t = this, editRow;
+ t.revert();
+
+ if ( typeof(id) == 'object' )
+ id = t.getId(id);
+
+ editRow = $('#inline-edit').clone(true), rowData = $('#inline_'+id);
+ $('td', editRow).attr('colspan', $('.widefat:first thead th:visible').length);
+
+ if ( $(t.what+id).hasClass('alternate') )
+ $(editRow).addClass('alternate');
+
+ $(t.what+id).hide().after(editRow);
+
+ $(':input[name="name"]', editRow).val( $('.name', rowData).text() );
+ $(':input[name="slug"]', editRow).val( $('.slug', rowData).text() );
+
+ $(editRow).attr('id', 'edit-'+id).addClass('inline-editor').show();
+ $('.ptitle', editRow).eq(0).focus();
+
+ return false;
+ },
+
+ save : function(id) {
+ var params, fields, tax = $('input[name="taxonomy"]').val() || '';
+
+ if( typeof(id) == 'object' )
+ id = this.getId(id);
+
+ $('table.widefat .spinner').show();
+
+ params = {
+ action: 'inline-save-tax',
+ tax_type: this.type,
+ tax_ID: id,
+ taxonomy: tax
+ };
+
+ fields = $('#edit-'+id+' :input').serialize();
+ params = fields + '&' + $.param(params);
+
+ // make ajax request
+ $.post( ajaxurl, params,
+ function(r) {
+ var row, new_id;
+ $('table.widefat .spinner').hide();
+
+ if (r) {
+ if ( -1 != r.indexOf('<tr') ) {
+ $(inlineEditTax.what+id).remove();
+ new_id = $(r).attr('id');
+
+ $('#edit-'+id).before(r).remove();
+ row = new_id ? $('#'+new_id) : $(inlineEditTax.what+id);
+ row.hide().fadeIn();
+ } else
+ $('#edit-'+id+' .inline-edit-save .error').html(r).show();
+ } else
+ $('#edit-'+id+' .inline-edit-save .error').html(inlineEditL10n.error).show();
+ }
+ );
+ return false;
+ },
+
+ revert : function() {
+ var id = $('table.widefat tr.inline-editor').attr('id');
+
+ if ( id ) {
+ $('table.widefat .spinner').hide();
+ $('#'+id).remove();
+ id = id.substr( id.lastIndexOf('-') + 1 );
+ $(this.what+id).show();
+ }
+
+ return false;
+ },
+
+ getId : function(o) {
+ var id = o.tagName == 'TR' ? o.id : $(o).parents('tr').attr('id'), parts = id.split('-');
+ return parts[parts.length - 1];
+ }
+};
+
+$(document).ready(function(){inlineEditTax.init();});
+})(jQuery);
diff --git a/src/wp-admin/js/iris.min.js b/src/wp-admin/js/iris.min.js
new file mode 100644
index 0000000000..9e7d7eace3
--- /dev/null
+++ b/src/wp-admin/js/iris.min.js
@@ -0,0 +1,4 @@
+/*! Iris Color Picker - v1.0.3 - 2013-02-15
+* https://github.com/Automattic/Iris
+* Copyright (c) 2013 Matt Wiebe; Licensed GPLv2 */
+(function(e,t){function c(){var t,n;r?i="filter":(t=e('<div id="iris-gradtest" />'),n="linear-gradient(top,#fff,#000)",e.each(s,function(e,r){t.css("backgroundImage",r+n);if(t.css("backgroundImage").match("gradient"))return i=e,!1}),i===!1&&(t.css("background","-webkit-gradient(linear,0% 0%,0% 100%,from(#fff),to(#000))"),t.css("backgroundImage").match("gradient")&&(i="webkit")),t.remove())}function h(t,n){return t=t==="top"?"top":"left",n=e.isArray(n)?n:Array.prototype.slice.call(arguments,1),i==="webkit"?d(t,n):s[i]+"linear-gradient("+t+", "+n.join(", ")+")"}function p(t,n){var r,i,s,o,u,a,f,l,c;t=t==="top"?"top":"left",n=e.isArray(n)?n:Array.prototype.slice.call(arguments,1),r=t==="top"?0:1,i=e(this),s=n.length-1,o="filter",u=r===1?"left":"top",a=r===1?"right":"bottom",f=r===1?"height":"width",l='<div class="iris-ie-gradient-shim" style="position:absolute;'+f+":100%;"+u+":%start%;"+a+":%end%;"+o+':%filter%;" data-color:"%color%"></div>',c="",i.css("position")==="static"&&i.css({position:"relative"}),n=v(n),e.each(n,function(e,t){var i,o,u;if(e===s)return!1;i=n[e+1];if(t.stop===i.stop)return;o=100-parseFloat(i.stop)+"%",t.octoHex=(new Color(t.color)).toIEOctoHex(),i.octoHex=(new Color(i.color)).toIEOctoHex(),u="progid:DXImageTransform.Microsoft.Gradient(GradientType="+r+", StartColorStr='"+t.octoHex+"', EndColorStr='"+i.octoHex+"')",c+=l.replace("%start%",t.stop).replace("%end%",o).replace("%filter%",u)}),i.find(".iris-ie-gradient-shim").remove(),e(c).prependTo(i)}function d(t,n){var r=[];return t=t==="top"?"0% 0%,0% 100%,":"0% 100%,100% 100%,",n=v(n),e.each(n,function(e,t){r.push("color-stop("+parseFloat(t.stop)/100+", "+t.color+")")}),"-webkit-gradient(linear,"+t+r.join(",")+")"}function v(t){var n=[],r=[],i=[],s=t.length-1;return e.each(t,function(e,t){var i=t,s=!1,o=t.match(/1?[0-9]{1,2}%$/);o&&(i=t.replace(/\s?1?[0-9]{1,2}%$/,""),s=o.shift()),n.push(i),r.push(s)}),r[0]===!1&&(r[0]="0%"),r[s]===!1&&(r[s]="100%"),r=m(r),e.each(r,function(e){i[e]={color:n[e],stop:r[e]}}),i}function m(t){var n=0,r=t.length-1,i=0,s=!1,o,u,a,f;if(t.length<=2||e.inArray(!1,t)<0)return t;while(i<t.length-1)!s&&t[i]===!1?(n=i-1,s=!0):s&&t[i]!==!1&&(r=i,i=t.length),i++;u=r-n,f=parseInt(t[n].replace("%"),10),o=(parseFloat(t[r].replace("%"))-f)/u,i=n+1,a=1;while(i<r)t[i]=f+a*o+"%",a++,i++;return m(t)}var n,r,i,s,o,u,a,f,l;n='<div class="iris-picker"><div class="iris-picker-inner"><div class="iris-square"><a class="iris-square-value" href="#"><span class="iris-square-handle ui-slider-handle"></span></a><div class="iris-square-inner iris-square-horiz"></div><div class="iris-square-inner iris-square-vert"></div></div><div class="iris-slider iris-strip"><div class="iris-slider-offset"></div></div></div></div>',a=navigator.userAgent.toLowerCase(),f=navigator.appName==="Microsoft Internet Explorer",l=f?parseFloat(a.match(/msie ([0-9]{1,}[\.0-9]{0,})/)[1]):0,r=f&&l<10,i=!1,s=["-moz-","-webkit-","-o-","-ms-"],o='.iris-picker{display:block;position:relative}.iris-picker,.iris-picker *{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input + .iris-picker{margin-top:4px}.iris-error{background-color:#ffafaf}.iris-border{border-radius:3px;border:1px solid #aaa;width:200px;background-color:#fff}.iris-picker-inner{position:absolute;top:0;right:0;left:0;bottom:0}.iris-border .iris-picker-inner{top:10px;right:10px;left:10px;bottom:10px}.iris-picker .iris-square-inner{position:absolute;left:0;right:0;top:0;bottom:0}.iris-picker .iris-square,.iris-picker .iris-slider,.iris-picker .iris-square-inner,.iris-picker .iris-palette{border-radius:3px;box-shadow:inset 0 0 5px rgba(0,0,0,0.4);height:100%;width:12.5%;float:left;margin-right:5%}.iris-picker .iris-square{width:76%;margin-right:10%;position:relative}.iris-picker .iris-square-inner{width:auto;margin:0}.iris-ie-9 .iris-square,.iris-ie-9 .iris-slider,.iris-ie-9 .iris-square-inner,.iris-ie-9 .iris-palette{box-shadow:none;border-radius:0}.iris-ie-9 .iris-square,.iris-ie-9 .iris-slider,.iris-ie-9 .iris-palette{outline:1px solid rgba(0,0,0,.1)}.iris-ie-lt9 .iris-square,.iris-ie-lt9 .iris-slider,.iris-ie-lt9 .iris-square-inner,.iris-ie-lt9 .iris-palette{outline:1px solid #aaa}.iris-ie-lt9 .iris-square .ui-slider-handle{outline:1px solid #aaa;background-color:#fff;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)"}.iris-ie-lt9 .iris-square .iris-square-handle{background:none;border:3px solid #fff;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"}.iris-picker .iris-strip{margin-right:0;position:relative}.iris-picker .iris-strip .ui-slider-handle{position:absolute;background:none;right:-3px;left:-3px;border:4px solid #aaa;border-width:4px 3px;width:auto;height:6px;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.2);opacity:.9;z-index:5;cursor:ns-resize}.iris-strip .ui-slider-handle:before{content:" ";position:absolute;left:-2px;right:-2px;top:-3px;bottom:-3px;border:2px solid #fff;border-radius:3px}.iris-picker .iris-slider-offset{position:absolute;top:11px;left:0;right:0;bottom:-3px}.iris-picker .iris-square-handle{background:transparent;border:5px solid #aaa;border-radius:50%;border-color:rgba(128,128,128,.5);box-shadow:none;width:12px;height:12px;position:absolute;left:-10px;top:-10px;cursor:move;opacity:1;z-index:10}.iris-picker .ui-state-focus .iris-square-handle{opacity:.8}.iris-picker .iris-square-handle:hover{border-color:#999}.iris-picker .iris-square-value:focus .iris-square-handle{box-shadow:0 0 2px rgba(0,0,0,.75);opacity:.8}.iris-picker .iris-square-handle:hover::after{border-color:#fff}.iris-picker .iris-square-handle::after{position:absolute;bottom:-4px;right:-4px;left:-4px;top:-4px;border:3px solid #f9f9f9;border-color:rgba(255,255,255,.8);border-radius:50%;content:" "}.iris-picker .iris-square-value{width:8px;height:8px;position:absolute}.iris-ie-lt9 .iris-square-value,.iris-mozilla .iris-square-value{width:1px;height:1px}.iris-palette-container{position:absolute;bottom:0;left:0;margin:0;padding:0}.iris-border .iris-palette-container{left:10px;bottom:10px}.iris-picker .iris-palette{margin:0;cursor:pointer}';if(r&&l<=7){e.fn.iris=e.noop,e.support.iris=!1;return}e.support.iris=!0,e.fn.gradient=function(t){var n=arguments;return this.each(function(){r?p.apply(this,n):e(this).css("backgroundImage",h.apply(this,n))})},e.fn.raninbowGradient=function(t,n){var r,i,s,o;t=t||"top",r=e.extend({},{s:100,l:50},n),i="hsl(%h%,"+r.s+"%,"+r.l+"%)",s=0,o=[];while(s<=360)o.push(i.replace("%h%",s)),s+=30;return this.each(function(){e(this).gradient(t,o)})},u={options:{color:!1,mode:"hsl",controls:{horiz:"s",vert:"l",strip:"h"},hide:!0,border:!0,target:!1,width:200,palettes:!1},_color:"",_palettes:["#000","#fff","#d33","#d93","#ee2","#81d742","#1e73be","#8224e3"],_inited:!1,_defaultHSLControls:{horiz:"s",vert:"l",strip:"h"},_defaultHSVControls:{horiz:"h",vert:"v",strip:"s"},_scale:{h:360,s:100,l:100,v:100},_create:function(){var t=this,r=t.element,s=t.options.color||r.val(),o;i===!1&&c(),r.is("input")?(t.options.target?t.picker=e(n).appendTo(t.options.target):t.picker=e(n).insertAfter(r),t._addInputListeners(r)):(r.append(n),t.picker=r.find(".iris-picker")),f?l===9?t.picker.addClass("iris-ie-9"):l<=8&&t.picker.addClass("iris-ie-lt9"):a.indexOf("compatible")<0&&a.indexOf("khtml")<0&&a.match(/mozilla/)&&t.picker.addClass("iris-mozilla"),t.options.palettes&&t._addPalettes(),t._color=(new Color(s)).setHSpace(t.options.mode),t.options.color=t._color.toString(),t.controls={square:t.picker.find(".iris-square"),squareDrag:t.picker.find(".iris-square-value"),horiz:t.picker.find(".iris-square-horiz"),vert:t.picker.find(".iris-square-vert"),strip:t.picker.find(".iris-strip"),stripSlider:t.picker.find(".iris-strip .iris-slider-offset")},t.options.mode==="hsv"&&t._has("l",t.options.controls)?t.options.controls=t._defaultHSVControls:t.options.mode==="hsl"&&t._has("v",t.options.controls)&&(t.options.controls=t._defaultHSLControls),t.hue=t._color.h(),t.options.hide&&t.picker.hide(),t.options.border&&t.picker.addClass("iris-border"),t._initControls(),t.active="external",t._dimensions(),t._change()},_has:function(t,n){var r=!1;return e.each(n,function(e,n){if(t===n)return r=!0,!1}),r},_addPalettes:function(){var t=e("<div class='iris-palette-container' />"),n=e("<a class='iris-palette' tabindex='0' />"),r=e.isArray(this.options.palettes)?this.options.palettes:this._palettes;this.picker.find(".iris-palette-container").length&&(t=this.picker.find(".iris-palette-container").detach().html("")),e.each(r,function(e,r){n.clone().data("color",r).css("backgroundColor",r).appendTo(t).height(10).width(10)}),this.picker.append(t)},_paint:function(){var e=this;e._paintDimension("top","strip"),e._paintDimension("top","vert"),e._paintDimension("left","horiz")},_paintDimension:function(e,t){var n=this,r=n._color,i=n.options.mode,s=n._getHSpaceColor(),o=n.controls[t],u=n.options.controls,a;if(t===n.active||n.active==="square"&&t!=="strip")return;switch(u[t]){case"h":if(i==="hsv"){s=r.clone();switch(t){case"horiz":s[u.vert](100);break;case"vert":s[u.horiz](100);break;case"strip":s.setHSpace("hsl")}a=s.toHsl()}else t==="strip"?a={s:s.s,l:s.l}:a={s:100,l:s.l};o.raninbowGradient(e,a);break;case"s":i==="hsv"?t==="vert"?a=[r.clone().a(0).s(0).toCSS("rgba"),r.clone().a(1).s(0).toCSS("rgba")]:t==="strip"?a=[r.clone().s(100).toCSS("hsl"),r.clone().s(0).toCSS("hsl")]:t==="horiz"&&(a=["#fff","hsl("+s.h+",100%,50%)"]):t==="vert"&&n.options.controls.horiz==="h"?a=["hsla(0, 0%, "+s.l+"%, 0)","hsla(0, 0%, "+s.l+"%, 1)"]:a=["hsl("+s.h+",0%,50%)","hsl("+s.h+",100%,50%)"],o.gradient(e,a);break;case"l":t==="strip"?a=["hsl("+s.h+",100%,100%)","hsl("+s.h+", "+s.s+"%,50%)","hsl("+s.h+",100%,0%)"]:a=["#fff","rgba(255,255,255,0) 50%","rgba(0,0,0,0) 50%","rgba(0,0,0,1)"],o.gradient(e,a);break;case"v":t==="strip"?a=[r.clone().v(100).toCSS(),r.clone().v(0).toCSS()]:a=["rgba(0,0,0,0)","#000"],o.gradient(e,a);break;default:}},_getHSpaceColor:function(){return this.options.mode==="hsv"?this._color.toHsv():this._color.toHsl()},_dimensions:function(t){var n=this,r=n.options,i=n.picker.find(".iris-picker-inner"),s=n.controls,o=s.square,u=n.picker.find(".iris-strip"),a="77.5%",f="12%",l=20,c=r.border?r.width-l:r.width,h,p=e.isArray(r.palettes)?r.palettes.length:n._palettes.length,d,v,m;t&&(o.css("width",""),u.css("width",""),n.picker.css({width:"",height:""})),a=c*(parseFloat(a)/100),f=c*(parseFloat(f)/100),h=r.border?a+l:a,o.width(a).height(a),u.height(a).width(f),n.picker.css({width:r.width,height:h});if(!r.palettes)return;d=a*2/100,m=a-(p-1)*d,v=m/p,n.picker.find(".iris-palette").each(function(t,n){var r=t===0?0:d;e(this).css({width:v,height:v,marginLeft:r})}),n.picker.css("paddingBottom",v+d),u.height(v+d+a)},_addInputListeners:function(e){var t=this,n=100,r=function(n){var r=new Color(e.val()),i=e.val().replace(/^#/,"");e.removeClass("iris-error"),r.error?i!==""&&e.addClass("iris-error"):r.toString()!==t._color.toString()&&(n.type!=="keyup"||!i.match(/^[0-9a-fA-F]{3}$/))&&t._setOption("color",r.toString())};e.on("change",r).on("keyup",t._debounce(r,n)),t.options.hide&&e.one("focus",function(){t.show()})},_initControls:function(){var t=this,n=t.controls,r=n.square,i=t.options.controls,s=t._scale[i.strip];n.stripSlider.slider({orientation:"vertical",max:s,slide:function(e,n){t.active="strip",i.strip==="h"&&(n.value=s-n.value),t._color[i.strip](n.value),t._change.apply(t,arguments)}}),n.squareDrag.draggable({containment:"parent",zIndex:1e3,cursor:"move",drag:function(e,n){t._squareDrag(e,n)},start:function(){r.addClass("iris-dragging"),e(this).addClass("ui-state-focus")},stop:function(){r.removeClass("iris-dragging"),e(this).removeClass("ui-state-focus")}}).on("mousedown mouseup",function(n){var r="ui-state-focus";n.preventDefault(),n.type==="mousedown"?(t.picker.find("."+r).removeClass(r).blur(),e(this).addClass(r).focus()):e(this).removeClass(r)}).on("keydown",function(e){var r=n.square,i=n.squareDrag,s=i.position(),o=t.options.width/100;e.altKey&&(o*=10);switch(e.keyCode){case 37:s.left-=o;break;case 38:s.top-=o;break;case 39:s.left+=o;break;case 40:s.top+=o;break;default:return!0}s.left=Math.max(0,Math.min(s.left,r.width())),s.top=Math.max(0,Math.min(s.top,r.height())),i.css(s),t._squareDrag(e,{position:s}),e.preventDefault()}),r.mousedown(function(n){var r,i;if(n.which!==1)return;if(!e(n.target).is("div"))return;r=t.controls.square.offset(),i={top:n.pageY-r.top,left:n.pageX-r.left},n.preventDefault(),t._squareDrag(n,{position:i}),n.target=t.controls.squareDrag.get(0),t.controls.squareDrag.css(i).trigger(n)}),t.options.palettes&&t._paletteListeners()},_paletteListeners:function(){var t=this;t.picker.find(".iris-palette-container").on("click.palette",".iris-palette",function(n){t._color.fromCSS(e(this).data("color")),t.active="external",t._change()}).on("keydown.palette",".iris-palette",function(t){if(t.keyCode!==13&&t.keyCode!==32)return!0;t.stopPropagation(),e(this).click()})},_squareDrag:function(e,t){var n=this,r=n.options.controls,i=n._squareDimensions(),s=Math.round((i.h-t.position.top)/i.h*n._scale[r.vert]),o=n._scale[r.horiz]-Math.round((i.w-t.position.left)/i.w*n._scale[r.horiz]);n._color[r.horiz](o)[r.vert](s),n.active="square",n._change.apply(n,arguments)},_setOption:function(t,n){var r=this,i=r.options[t],s=!1,o,u,a;r.options[t]=n;switch(t){case"color":n=""+n,o=n.replace(/^#/,""),u=(new Color(n)).setHSpace(r.options.mode),u.error?r.options[t]=i:(r._color=u,r.options.color=r.options[t]=r._color.toString(),r.active="external",r._change());break;case"palettes":s=!0,n?r._addPalettes():r.picker.find(".iris-palette-container").remove(),i||r._paletteListeners();break;case"width":s=!0;break;case"border":s=!0,a=n?"addClass":"removeClass",r.picker[a]("iris-border");break;case"mode":case"controls":if(i===n)return;return a=r.element,i=r.options,i.hide=!r.picker.is(":visible"),r.destroy(),r.picker.remove(),e(r.element).iris(i)}s&&r._dimensions(!0)},_squareDimensions:function(e){var n=this.controls.square,r,i;return e!==t&&n.data("dimensions")?n.data("dimensions"):(i=this.controls.squareDrag,r={w:n.width(),h:n.height()},n.data("dimensions",r),r)},_isNonHueControl:function(e,t){return e==="square"&&this.options.controls.strip==="h"?!0:t==="external"||t==="h"&&e==="strip"?!1:!0},_change:function(t,n){var r=this,i=r.controls,s=r._getHSpaceColor(),o=r._color.toString(),u=["square","strip"],a=r.options.controls,f=a[r.active]||"external",l=r.hue;r.active==="strip"?u=[]:r.active!=="external"&&u.pop(),e.each(u,function(e,t){var n,o,u;if(t!==r.active)switch(t){case"strip":n=a.strip==="h"?r._scale[a.strip]-s[a.strip]:s[a.strip],i.stripSlider.slider("value",n);break;case"square":o=r._squareDimensions(),u={left:s[a.horiz]/r._scale[a.horiz]*o.w,top:o.h-s[a.vert]/r._scale[a.vert]*o.h},r.controls.squareDrag.css(u)}}),s.h!==l&&r._isNonHueControl(r.active,f)&&r._color.h(l),r.hue=r._color.h(),r.options.color=r._color.toString(),r._inited&&r._trigger("change",{type:r.active},{color:r._color}),r.element.is(":input")&&!r._color.error&&(r.element.removeClass("iris-error"),r.element.val()!==r._color.toString()&&r.element.val(r._color.toString())),r._paint(),r._inited=!0,r.active=!1},_debounce:function(e,t,n){var r,i;return function(){var s=this,o=arguments,u,a;return u=function(){r=null,n||(i=e.apply(s,o))},a=n&&!r,clearTimeout(r),r=setTimeout(u,t),a&&(i=e.apply(s,o)),i}},show:function(){this.picker.show()},hide:function(){this.picker.hide()},toggle:function(){this.picker.toggle()},color:function(e){if(e===!0)return this._color.clone();if(e===t)return this._color.toString();this.option("color",e)}},e.widget("a8c.iris",u),e('<style id="iris-css">'+o+"</style>").appendTo("head")})(jQuery),function(e,t){var n=function(e,t){return this instanceof n?this._init(e,t):new n(e,t)};n.fn=n.prototype={_color:0,_alpha:1,error:!1,_hsl:{h:0,s:0,l:0},_hsv:{h:0,s:0,v:0},_hSpace:"hsl",_init:function(e){var n="noop";switch(typeof e){case"object":return e.a!==t&&this.a(e.a),n=e.r!==t?"fromRgb":e.l!==t?"fromHsl":e.v!==t?"fromHsv":n,this[n](e);case"string":return this.fromCSS(e);case"number":return this.fromInt(parseInt(e,10))}return this},_error:function(){return this.error=!0,this},clone:function(){var e=new n(this.toInt()),t=["_alpha","_hSpace","_hsl","_hsv","error"];for(var r=t.length-1;r>=0;r--)e[t[r]]=this[t[r]];return e},setHSpace:function(e){return this._hSpace=e==="hsv"?e:"hsl",this},noop:function(){return this},fromCSS:function(e){var t,n,r=/^(rgb|hs(l|v))a?\(/;this.error=!1,e=e.replace(/^\s+/,"").replace(/\s+$/,"").replace(/;$/,"");if(e.match(r)&&e.match(/\)$/)){n=e.replace(/(\s|%)/g,"").replace(r,"").replace(/,?\);?$/,"").split(",");if(n.length<3)return this._error();if(n.length===4){this.a(parseFloat(n.pop()));if(this.error)return this}for(var i=n.length-1;i>=0;i--){n[i]=parseInt(n[i],10);if(isNaN(n[i]))return this._error()}return e.match(/^rgb/)?this.fromRgb({r:n[0],g:n[1],b:n[2]}):e.match(/^hsv/)?this.fromHsv({h:n[0],s:n[1],v:n[2]}):this.fromHsl({h:n[0],s:n[1],l:n[2]})}return this.fromHex(e)},fromRgb:function(e,n){return typeof e!="object"||e.r===t||e.g===t||e.b===t?this._error():(this.error=!1,this.fromInt(parseInt((e.r<<16)+(e.g<<8)+e.b,10),n))},fromHex:function(e){return e=e.replace(/^#/,"").replace(/^0x/,""),e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),this.error=!/^[0-9A-F]{6}$/i.test(e),this.fromInt(parseInt(e,16))},fromHsl:function(e){var n,r,i,s,o,u,a,f;return typeof e!="object"||e.h===t||e.s===t||e.l===t?this._error():(this._hsl=e,this._hSpace="hsl",u=e.h/360,a=e.s/100,f=e.l/100,a===0?n=r=i=f:(s=f<.5?f*(1+a):f+a-f*a,o=2*f-s,n=this.hue2rgb(o,s,u+1/3),r=this.hue2rgb(o,s,u),i=this.hue2rgb(o,s,u-1/3)),this.fromRgb({r:n*255,g:r*255,b:i*255},!0))},fromHsv:function(e){var n,r,i,s,o,u,a,f,l,c,h;if(typeof e!="object"||e.h===t||e.s===t||e.v===t)return this._error();this._hsv=e,this._hSpace="hsv",n=e.h/360,r=e.s/100,i=e.v/100,a=Math.floor(n*6),f=n*6-a,l=i*(1-r),c=i*(1-f*r),h=i*(1-(1-f)*r);switch(a%6){case 0:s=i,o=h,u=l;break;case 1:s=c,o=i,u=l;break;case 2:s=l,o=i,u=h;break;case 3:s=l,o=c,u=i;break;case 4:s=h,o=l,u=i;break;case 5:s=i,o=l,u=c}return this.fromRgb({r:s*255,g:o*255,b:u*255},!0)},fromInt:function(e,n){return this._color=parseInt(e,10),isNaN(this._color)&&(this._color=0),this._color>16777215?this._color=16777215:this._color<0&&(this._color=0),n===t&&(this._hsv.h=this._hsv.s=this._hsl.h=this._hsl.s=0),this},hue2rgb:function(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+(t-e)*6*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e},toString:function(){var e=parseInt(this._color,10).toString(16);if(this.error)return"";if(e.length<6)for(var t=6-e.length-1;t>=0;t--)e="0"+e;return"#"+e},toCSS:function(e,t){e=e||"hex",t=parseFloat(t||this._alpha);switch(e){case"rgb":case"rgba":var n=this.toRgb();return t<1?"rgba( "+n.r+", "+n.g+", "+n.b+", "+t+" )":"rgb( "+n.r+", "+n.g+", "+n.b+" )";case"hsl":case"hsla":var r=this.toHsl();return t<1?"hsla( "+r.h+", "+r.s+"%, "+r.l+"%, "+t+" )":"hsl( "+r.h+", "+r.s+"%, "+r.l+"% )";default:return this.toString()}},toRgb:function(){return{r:255&this._color>>16,g:255&this._color>>8,b:255&this._color}},toHsl:function(){var e=this.toRgb(),t=e.r/255,n=e.g/255,r=e.b/255,i=Math.max(t,n,r),s=Math.min(t,n,r),o,u,a=(i+s)/2;if(i===s)o=u=0;else{var f=i-s;u=a>.5?f/(2-i-s):f/(i+s);switch(i){case t:o=(n-r)/f+(n<r?6:0);break;case n:o=(r-t)/f+2;break;case r:o=(t-n)/f+4}o/=6}return o=Math.round(o*360),o===0&&this._hsl.h!==o&&(o=this._hsl.h),u=Math.round(u*100),u===0&&this._hsl.s&&(u=this._hsl.s),{h:o,s:u,l:Math.round(a*100)}},toHsv:function(){var e=this.toRgb(),t=e.r/255,n=e.g/255,r=e.b/255,i=Math.max(t,n,r),s=Math.min(t,n,r),o,u,a=i,f=i-s;u=i===0?0:f/i;if(i===s)o=u=0;else{switch(i){case t:o=(n-r)/f+(n<r?6:0);break;case n:o=(r-t)/f+2;break;case r:o=(t-n)/f+4}o/=6}return o=Math.round(o*360),o===0&&this._hsv.h!==o&&(o=this._hsv.h),u=Math.round(u*100),u===0&&this._hsv.s&&(u=this._hsv.s),{h:o,s:u,v:Math.round(a*100)}},toInt:function(){return this._color},toIEOctoHex:function(){var e=this.toString(),t=parseInt(255*this._alpha,10).toString(16);return t.length===1&&(t="0"+t),"#"+t+e.replace(/^#/,"")},toLuminosity:function(){var e=this.toRgb();return.2126*Math.pow(e.r/255,2.2)+.7152*Math.pow(e.g/255,2.2)+.0722*Math.pow(e.b/255,2.2)},getDistanceLuminosityFrom:function(e){if(e instanceof n){var t=this.toLuminosity(),r=e.toLuminosity();return t>r?(t+.05)/(r+.05):(r+.05)/(t+.05)}throw"getDistanceLuminosityFrom requires a Color object"},getMaxContrastColor:function(){var e=this.toLuminosity(),t=e>=.5?"000000":"ffffff";return new n(t)},getGrayscaleContrastingColor:function(e){if(!e)return this.getMaxContrastColor();var t=e<5?5:e,n=this.getMaxContrastColor();e=n.getDistanceLuminosityFrom(this);if(e<=t)return n;var r=0===n.toInt()?1:-1;while(e>t)n=n.incrementLightness(r),e=n.getDistanceLuminosityFrom(this);return n},getReadableContrastingColor:function(e,r){if(!e instanceof n)return this;var i=r===t?5:r,s=e.getDistanceLuminosityFrom(this),o=e.getMaxContrastColor(),u=o.getDistanceLuminosityFrom(e);if(u<=i)return o;if(s>=i)return this;var a=0===o.toInt()?-1:1;while(s<i){this.incrementLightness(a),s=this.getDistanceLuminosityFrom(e);if(this._color===0||this._color===16777215)break}return this},a:function(e){if(e===t)return this._alpha;var n=parseFloat(e);return isNaN(n)?this._error():(this._alpha=n,this)},darken:function(e){return e=e||5,this.l(-e,!0)},lighten:function(e){return e=e||5,this.l(e,!0)},saturate:function(e){return e=e||15,this.s(e,!0)},desaturate:function(e){return e=e||15,this.s(-e,!0)},toGrayscale:function(){return this.setHSpace("hsl").s(0)},getComplement:function(){return this.h(180,!0)},getSplitComplement:function(e){e=e||1;var t=180+e*30;return this.h(t,!0)},getAnalog:function(e){e=e||1;var t=e*30;return this.h(t,!0)},getTetrad:function(e){e=e||1;var t=e*60;return this.h(t,!0)},getTriad:function(e){e=e||1;var t=e*120;return this.h(t,!0)},_partial:function(e){var n=r[e];return function(r,i){var s=this._spaceFunc("to",n.space);return r===t?s[e]:(i===!0&&(r=s[e]+r),n.mod&&(r%=n.mod),n.range&&(r=r<n.range[0]?n.range[0]:r>n.range[1]?n.range[1]:r),s[e]=r,this._spaceFunc("from",n.space,s))}},_spaceFunc:function(e,t,n){var r=t||this._hSpace,i=e+r.charAt(0).toUpperCase()+r.substr(1);return this[i](n)}};var r={h:{mod:360},s:{range:[0,100]},l:{space:"hsl",range:[0,100]},v:{space:"hsv",range:[0,100]},r:{space:"rgb",range:[0,255]},g:{space:"rgb",range:[0,255]},b:{space:"rgb",range:[0,255]}};for(var i in r)r.hasOwnProperty(i)&&(n.fn[i]=n.fn._partial(i));e.Color=n}(typeof exports=="object"&&exports||this); \ No newline at end of file
diff --git a/src/wp-admin/js/link.js b/src/wp-admin/js/link.js
new file mode 100644
index 0000000000..bf5e67ede6
--- /dev/null
+++ b/src/wp-admin/js/link.js
@@ -0,0 +1,67 @@
+jQuery(document).ready( function($) {
+
+ var newCat, noSyncChecks = false, syncChecks, catAddAfter;
+
+ $('#link_name').focus();
+ // postboxes
+ postboxes.add_postbox_toggles('link');
+
+ // category tabs
+ $('#category-tabs a').click(function(){
+ var t = $(this).attr('href');
+ $(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
+ $('.tabs-panel').hide();
+ $(t).show();
+ if ( '#categories-all' == t )
+ deleteUserSetting('cats');
+ else
+ setUserSetting('cats','pop');
+ return false;
+ });
+ if ( getUserSetting('cats') )
+ $('#category-tabs a[href="#categories-pop"]').click();
+
+ // Ajax Cat
+ newCat = $('#newcat').one( 'focus', function() { $(this).val( '' ).removeClass( 'form-input-tip' ) } );
+ $('#link-category-add-submit').click( function() { newCat.focus(); } );
+ syncChecks = function() {
+ if ( noSyncChecks )
+ return;
+ noSyncChecks = true;
+ var th = $(this), c = th.is(':checked'), id = th.val().toString();
+ $('#in-link-category-' + id + ', #in-popular-link_category-' + id).prop( 'checked', c );
+ noSyncChecks = false;
+ };
+
+ catAddAfter = function( r, s ) {
+ $(s.what + ' response_data', r).each( function() {
+ var t = $($(this).text());
+ t.find( 'label' ).each( function() {
+ var th = $(this), val = th.find('input').val(), id = th.find('input')[0].id, name = $.trim( th.text() ), o;
+ $('#' + id).change( syncChecks );
+ o = $( '<option value="' + parseInt( val, 10 ) + '"></option>' ).text( name );
+ } );
+ } );
+ };
+
+ $('#categorychecklist').wpList( {
+ alt: '',
+ what: 'link-category',
+ response: 'category-ajax-response',
+ addAfter: catAddAfter
+ } );
+
+ $('a[href="#categories-all"]').click(function(){deleteUserSetting('cats');});
+ $('a[href="#categories-pop"]').click(function(){setUserSetting('cats','pop');});
+ if ( 'pop' == getUserSetting('cats') )
+ $('a[href="#categories-pop"]').click();
+
+ $('#category-add-toggle').click( function() {
+ $(this).parents('div:first').toggleClass( 'wp-hidden-children' );
+ $('#category-tabs a[href="#categories-all"]').click();
+ $('#newcategory').focus();
+ return false;
+ } );
+
+ $('.categorychecklist :checkbox').change( syncChecks ).filter( ':checked' ).change();
+});
diff --git a/src/wp-admin/js/media-gallery.js b/src/wp-admin/js/media-gallery.js
new file mode 100644
index 0000000000..38e4f7b481
--- /dev/null
+++ b/src/wp-admin/js/media-gallery.js
@@ -0,0 +1,25 @@
+jQuery(function($){
+ $( 'body' ).bind( 'click.wp-gallery', function(e){
+ var target = $( e.target ), id, img_size;
+
+ if ( target.hasClass( 'wp-set-header' ) ) {
+ ( window.dialogArguments || opener || parent || top ).location.href = target.data( 'location' );
+ e.preventDefault();
+ } else if ( target.hasClass( 'wp-set-background' ) ) {
+ id = target.data( 'attachment-id' );
+ img_size = $( 'input[name="attachments[' + id + '][image-size]"]:checked').val();
+
+ jQuery.post(ajaxurl, {
+ action: 'set-background-image',
+ attachment_id: id,
+ size: img_size
+ }, function(){
+ var win = window.dialogArguments || opener || parent || top;
+ win.tb_remove();
+ win.location.reload();
+ });
+
+ e.preventDefault();
+ }
+ });
+});
diff --git a/src/wp-admin/js/media-upload.js b/src/wp-admin/js/media-upload.js
new file mode 100644
index 0000000000..9fc2e8197d
--- /dev/null
+++ b/src/wp-admin/js/media-upload.js
@@ -0,0 +1,88 @@
+// send html to the post editor
+
+var wpActiveEditor;
+
+function send_to_editor(h) {
+ var ed, mce = typeof(tinymce) != 'undefined', qt = typeof(QTags) != 'undefined';
+
+ if ( !wpActiveEditor ) {
+ if ( mce && tinymce.activeEditor ) {
+ ed = tinymce.activeEditor;
+ wpActiveEditor = ed.id;
+ } else if ( !qt ) {
+ return false;
+ }
+ } else if ( mce ) {
+ if ( tinymce.activeEditor && (tinymce.activeEditor.id == 'mce_fullscreen' || tinymce.activeEditor.id == 'wp_mce_fullscreen') )
+ ed = tinymce.activeEditor;
+ else
+ ed = tinymce.get(wpActiveEditor);
+ }
+
+ if ( ed && !ed.isHidden() ) {
+ // restore caret position on IE
+ if ( tinymce.isIE && ed.windowManager.insertimagebookmark )
+ ed.selection.moveToBookmark(ed.windowManager.insertimagebookmark);
+
+ if ( h.indexOf('[caption') !== -1 ) {
+ if ( ed.wpSetImgCaption )
+ h = ed.wpSetImgCaption(h);
+ } else if ( h.indexOf('[gallery') !== -1 ) {
+ if ( ed.plugins.wpgallery )
+ h = ed.plugins.wpgallery._do_gallery(h);
+ } else if ( h.indexOf('[embed') === 0 ) {
+ if ( ed.plugins.wordpress )
+ h = ed.plugins.wordpress._setEmbed(h);
+ }
+
+ ed.execCommand('mceInsertContent', false, h);
+ } else if ( qt ) {
+ QTags.insertContent(h);
+ } else {
+ document.getElementById(wpActiveEditor).value += h;
+ }
+
+ try{tb_remove();}catch(e){};
+}
+
+// thickbox settings
+var tb_position;
+(function($) {
+ tb_position = function() {
+ var tbWindow = $('#TB_window'), width = $(window).width(), H = $(window).height(), W = ( 720 < width ) ? 720 : width, adminbar_height = 0;
+
+ if ( $('body.admin-bar').length )
+ adminbar_height = 28;
+
+ if ( tbWindow.size() ) {
+ tbWindow.width( W - 50 ).height( H - 45 - adminbar_height );
+ $('#TB_iframeContent').width( W - 50 ).height( H - 75 - adminbar_height );
+ tbWindow.css({'margin-left': '-' + parseInt((( W - 50 ) / 2),10) + 'px'});
+ if ( typeof document.body.style.maxWidth != 'undefined' )
+ tbWindow.css({'top': 20 + adminbar_height + 'px','margin-top':'0'});
+ };
+
+ return $('a.thickbox').each( function() {
+ var href = $(this).attr('href');
+ if ( ! href ) return;
+ href = href.replace(/&width=[0-9]+/g, '');
+ href = href.replace(/&height=[0-9]+/g, '');
+ $(this).attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 - adminbar_height ) );
+ });
+ };
+
+ $(window).resize(function(){ tb_position(); });
+
+ // store caret position in IE
+ $(document).ready(function($){
+ $('a.thickbox').click(function(){
+ var ed;
+
+ if ( typeof(tinymce) != 'undefined' && tinymce.isIE && ( ed = tinymce.get(wpActiveEditor) ) && !ed.isHidden() ) {
+ ed.focus();
+ ed.windowManager.insertimagebookmark = ed.selection.getBookmark();
+ }
+ });
+ });
+
+})(jQuery);
diff --git a/src/wp-admin/js/media.js b/src/wp-admin/js/media.js
new file mode 100644
index 0000000000..b4ed0fb6ce
--- /dev/null
+++ b/src/wp-admin/js/media.js
@@ -0,0 +1,124 @@
+
+var findPosts;
+(function($){
+ findPosts = {
+ open : function(af_name, af_val) {
+ var st = document.documentElement.scrollTop || $(document).scrollTop(),
+ overlay = $( '.ui-find-overlay' );
+
+ if ( overlay.length == 0 ) {
+ $( 'body' ).append( '<div class="ui-find-overlay"></div>' );
+ findPosts.overlay();
+ }
+
+ overlay.show();
+
+ if ( af_name && af_val ) {
+ $('#affected').attr('name', af_name).val(af_val);
+ }
+ $('#find-posts').show().draggable({
+ handle: '#find-posts-head'
+ }).css({'top':st + 50 + 'px','left':'50%','marginLeft':'-328px'});
+
+ $('#find-posts-input').focus().keyup(function(e){
+ if (e.which == 27) { findPosts.close(); } // close on Escape
+ });
+
+ // Pull some results up by default
+ findPosts.send();
+
+ return false;
+ },
+
+ close : function() {
+ $('#find-posts-response').html('');
+ $('#find-posts').draggable('destroy').hide();
+ $( '.ui-find-overlay' ).hide();
+ },
+
+ overlay : function() {
+ $( '.ui-find-overlay' ).css(
+ { 'z-index': '999', 'width': $( document ).width() + 'px', 'height': $( document ).height() + 'px' }
+ ).on('click', function () {
+ findPosts.close();
+ });
+ },
+
+ send : function() {
+ var post = {
+ ps: $('#find-posts-input').val(),
+ action: 'find_posts',
+ _ajax_nonce: $('#_ajax_nonce').val()
+ },
+ spinner = $( '.find-box-search .spinner' );
+
+ spinner.show();
+
+ $.ajax({
+ type : 'POST',
+ url : ajaxurl,
+ data : post,
+ success : function(x) { findPosts.show(x); spinner.hide(); },
+ error : function(r) { findPosts.error(r); spinner.hide(); }
+ });
+ },
+
+ show : function(x) {
+
+ if ( typeof(x) == 'string' ) {
+ this.error({'responseText': x});
+ return;
+ }
+
+ var r = wpAjax.parseAjaxResponse(x);
+
+ if ( r.errors ) {
+ this.error({'responseText': wpAjax.broken});
+ }
+ r = r.responses[0];
+ $('#find-posts-response').html(r.data);
+
+ // Enable whole row to be clicked
+ $( '.found-posts td' ).on( 'click', function () {
+ $( this ).parent().find( '.found-radio input' ).prop( 'checked', true );
+ });
+ },
+
+ error : function(r) {
+ var er = r.statusText;
+
+ if ( r.responseText ) {
+ er = r.responseText.replace( /<.[^<>]*?>/g, '' );
+ }
+ if ( er ) {
+ $('#find-posts-response').html(er);
+ }
+ }
+ };
+
+ $(document).ready(function() {
+ $('#find-posts-submit').click(function(e) {
+ if ( '' == $('#find-posts-response').html() )
+ e.preventDefault();
+ });
+ $( '#find-posts .find-box-search :input' ).keypress( function( event ) {
+ if ( 13 == event.which ) {
+ findPosts.send();
+ return false;
+ }
+ } );
+ $( '#find-posts-search' ).click( findPosts.send );
+ $( '#find-posts-close' ).click( findPosts.close );
+ $('#doaction, #doaction2').click(function(e){
+ $('select[name^="action"]').each(function(){
+ if ( $(this).val() == 'attach' ) {
+ e.preventDefault();
+ findPosts.open();
+ }
+ });
+ });
+ });
+ $(window).resize(function() {
+ findPosts.overlay();
+ });
+})(jQuery);
diff --git a/src/wp-admin/js/nav-menu.js b/src/wp-admin/js/nav-menu.js
new file mode 100644
index 0000000000..4c6efec3df
--- /dev/null
+++ b/src/wp-admin/js/nav-menu.js
@@ -0,0 +1,1171 @@
+/**
+ * WordPress Administration Navigation Menu
+ * Interface JS functions
+ *
+ * @version 2.0.0
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+var wpNavMenu;
+
+(function($) {
+
+ var api = wpNavMenu = {
+
+ options : {
+ menuItemDepthPerLevel : 30, // Do not use directly. Use depthToPx and pxToDepth instead.
+ globalMaxDepth : 11
+ },
+
+ menuList : undefined, // Set in init.
+ targetList : undefined, // Set in init.
+ menusChanged : false,
+ isRTL: !! ( 'undefined' != typeof isRtl && isRtl ),
+ negateIfRTL: ( 'undefined' != typeof isRtl && isRtl ) ? -1 : 1,
+
+ // Functions that run on init.
+ init : function() {
+ api.menuList = $('#menu-to-edit');
+ api.targetList = api.menuList;
+
+ this.jQueryExtensions();
+
+ this.attachMenuEditListeners();
+
+ this.setupInputWithDefaultTitle();
+ this.attachQuickSearchListeners();
+ this.attachThemeLocationsListeners();
+
+ this.attachTabsPanelListeners();
+
+ this.attachUnsavedChangesListener();
+
+ if ( api.menuList.length )
+ this.initSortables();
+
+ if ( menus.oneThemeLocationNoMenus )
+ $( '#posttype-page' ).addSelectedToMenu( api.addMenuItemToBottom );
+
+ this.initManageLocations();
+
+ this.initAccessibility();
+
+ this.initToggles();
+ },
+
+ jQueryExtensions : function() {
+ // jQuery extensions
+ $.fn.extend({
+ menuItemDepth : function() {
+ var margin = api.isRTL ? this.eq(0).css('margin-right') : this.eq(0).css('margin-left');
+ return api.pxToDepth( margin && -1 != margin.indexOf('px') ? margin.slice(0, -2) : 0 );
+ },
+ updateDepthClass : function(current, prev) {
+ return this.each(function(){
+ var t = $(this);
+ prev = prev || t.menuItemDepth();
+ $(this).removeClass('menu-item-depth-'+ prev )
+ .addClass('menu-item-depth-'+ current );
+ });
+ },
+ shiftDepthClass : function(change) {
+ return this.each(function(){
+ var t = $(this),
+ depth = t.menuItemDepth();
+ $(this).removeClass('menu-item-depth-'+ depth )
+ .addClass('menu-item-depth-'+ (depth + change) );
+ });
+ },
+ childMenuItems : function() {
+ var result = $();
+ this.each(function(){
+ var t = $(this), depth = t.menuItemDepth(), next = t.next();
+ while( next.length && next.menuItemDepth() > depth ) {
+ result = result.add( next );
+ next = next.next();
+ }
+ });
+ return result;
+ },
+ shiftHorizontally : function( dir ) {
+ return this.each(function(){
+ var t = $(this),
+ depth = t.menuItemDepth(),
+ newDepth = depth + dir;
+
+ // Change .menu-item-depth-n class
+ t.moveHorizontally( newDepth, depth );
+ });
+ },
+ moveHorizontally : function( newDepth, depth ) {
+ return this.each(function(){
+ var t = $(this),
+ children = t.childMenuItems(),
+ diff = newDepth - depth,
+ subItemText = t.find('.is-submenu');
+
+ // Change .menu-item-depth-n class
+ t.updateDepthClass( newDepth, depth ).updateParentMenuItemDBId();
+
+ // If it has children, move those too
+ if ( children ) {
+ children.each(function( index ) {
+ var t = $(this),
+ thisDepth = t.menuItemDepth(),
+ newDepth = thisDepth + diff;
+ t.updateDepthClass(newDepth, thisDepth).updateParentMenuItemDBId();
+ });
+ }
+
+ // Show "Sub item" helper text
+ if (0 === newDepth)
+ subItemText.hide();
+ else
+ subItemText.show();
+ });
+ },
+ updateParentMenuItemDBId : function() {
+ return this.each(function(){
+ var item = $(this),
+ input = item.find( '.menu-item-data-parent-id' ),
+ depth = parseInt( item.menuItemDepth() ),
+ parentDepth = depth - 1,
+ parent = item.prevAll( '.menu-item-depth-' + parentDepth ).first();
+
+ if ( 0 == depth ) { // Item is on the top level, has no parent
+ input.val(0);
+ } else { // Find the parent item, and retrieve its object id.
+ input.val( parent.find( '.menu-item-data-db-id' ).val() );
+ }
+ });
+ },
+ hideAdvancedMenuItemFields : function() {
+ return this.each(function(){
+ var that = $(this);
+ $('.hide-column-tog').not(':checked').each(function(){
+ that.find('.field-' + $(this).val() ).addClass('hidden-field');
+ });
+ });
+ },
+ /**
+ * Adds selected menu items to the menu.
+ *
+ * @param jQuery metabox The metabox jQuery object.
+ */
+ addSelectedToMenu : function(processMethod) {
+ if ( 0 == $('#menu-to-edit').length ) {
+ return false;
+ }
+
+ return this.each(function() {
+ var t = $(this), menuItems = {},
+ checkboxes = ( menus.oneThemeLocationNoMenus && 0 == t.find('.tabs-panel-active .categorychecklist li input:checked').length ) ? t.find('#page-all li input[type="checkbox"]') : t.find('.tabs-panel-active .categorychecklist li input:checked'),
+ re = new RegExp('menu-item\\[(\[^\\]\]*)');
+
+ processMethod = processMethod || api.addMenuItemToBottom;
+
+ // If no items are checked, bail.
+ if ( !checkboxes.length )
+ return false;
+
+ // Show the ajax spinner
+ t.find('.spinner').show();
+
+ // Retrieve menu item data
+ $(checkboxes).each(function(){
+ var t = $(this),
+ listItemDBIDMatch = re.exec( t.attr('name') ),
+ listItemDBID = 'undefined' == typeof listItemDBIDMatch[1] ? 0 : parseInt(listItemDBIDMatch[1], 10);
+ if ( this.className && -1 != this.className.indexOf('add-to-top') )
+ processMethod = api.addMenuItemToTop;
+ menuItems[listItemDBID] = t.closest('li').getItemData( 'add-menu-item', listItemDBID );
+ });
+
+ // Add the items
+ api.addItemToMenu(menuItems, processMethod, function(){
+ // Deselect the items and hide the ajax spinner
+ checkboxes.removeAttr('checked');
+ t.find('.spinner').hide();
+ });
+ });
+ },
+ getItemData : function( itemType, id ) {
+ itemType = itemType || 'menu-item';
+
+ var itemData = {}, i,
+ fields = [
+ 'menu-item-db-id',
+ 'menu-item-object-id',
+ 'menu-item-object',
+ 'menu-item-parent-id',
+ 'menu-item-position',
+ 'menu-item-type',
+ 'menu-item-title',
+ 'menu-item-url',
+ 'menu-item-description',
+ 'menu-item-attr-title',
+ 'menu-item-target',
+ 'menu-item-classes',
+ 'menu-item-xfn'
+ ];
+
+ if( !id && itemType == 'menu-item' ) {
+ id = this.find('.menu-item-data-db-id').val();
+ }
+
+ if( !id ) return itemData;
+
+ this.find('input').each(function() {
+ var field;
+ i = fields.length;
+ while ( i-- ) {
+ if( itemType == 'menu-item' )
+ field = fields[i] + '[' + id + ']';
+ else if( itemType == 'add-menu-item' )
+ field = 'menu-item[' + id + '][' + fields[i] + ']';
+
+ if (
+ this.name &&
+ field == this.name
+ ) {
+ itemData[fields[i]] = this.value;
+ }
+ }
+ });
+
+ return itemData;
+ },
+ setItemData : function( itemData, itemType, id ) { // Can take a type, such as 'menu-item', or an id.
+ itemType = itemType || 'menu-item';
+
+ if( !id && itemType == 'menu-item' ) {
+ id = $('.menu-item-data-db-id', this).val();
+ }
+
+ if( !id ) return this;
+
+ this.find('input').each(function() {
+ var t = $(this), field;
+ $.each( itemData, function( attr, val ) {
+ if( itemType == 'menu-item' )
+ field = attr + '[' + id + ']';
+ else if( itemType == 'add-menu-item' )
+ field = 'menu-item[' + id + '][' + attr + ']';
+
+ if ( field == t.attr('name') ) {
+ t.val( val );
+ }
+ });
+ });
+ return this;
+ }
+ });
+ },
+
+ countMenuItems : function( depth ) {
+ return $( '.menu-item-depth-' + depth ).length;
+ },
+
+ moveMenuItem : function( $this, dir ) {
+
+ var menuItems = $('#menu-to-edit li');
+ menuItemsCount = menuItems.length,
+ thisItem = $this.parents( 'li.menu-item' ),
+ thisItemChildren = thisItem.childMenuItems(),
+ thisItemData = thisItem.getItemData(),
+ thisItemDepth = parseInt( thisItem.menuItemDepth() ),
+ thisItemPosition = parseInt( thisItem.index() ),
+ nextItem = thisItem.next(),
+ nextItemChildren = nextItem.childMenuItems(),
+ nextItemDepth = parseInt( nextItem.menuItemDepth() ) + 1,
+ prevItem = thisItem.prev(),
+ prevItemDepth = parseInt( prevItem.menuItemDepth() ),
+ prevItemId = prevItem.getItemData()['menu-item-db-id'];
+
+ switch ( dir ) {
+ case 'up':
+ var newItemPosition = thisItemPosition - 1;
+
+ // Already at top
+ if ( 0 === thisItemPosition )
+ break;
+
+ // If a sub item is moved to top, shift it to 0 depth
+ if ( 0 === newItemPosition && 0 !== thisItemDepth )
+ thisItem.moveHorizontally( 0, thisItemDepth );
+
+ // If prev item is sub item, shift to match depth
+ if ( 0 !== prevItemDepth )
+ thisItem.moveHorizontally( prevItemDepth, thisItemDepth );
+
+ // Does this item have sub items?
+ if ( thisItemChildren ) {
+ var items = thisItem.add( thisItemChildren );
+ // Move the entire block
+ items.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
+ } else {
+ thisItem.detach().insertBefore( menuItems.eq( newItemPosition ) ).updateParentMenuItemDBId();
+ }
+ break;
+ case 'down':
+ // Does this item have sub items?
+ if ( thisItemChildren ) {
+ var items = thisItem.add( thisItemChildren ),
+ nextItem = menuItems.eq( items.length + thisItemPosition ),
+ nextItemChildren = 0 !== nextItem.childMenuItems().length;
+
+ if ( nextItemChildren ) {
+ var newDepth = parseInt( nextItem.menuItemDepth() ) + 1;
+ thisItem.moveHorizontally( newDepth, thisItemDepth );
+ }
+
+ // Have we reached the bottom?
+ if ( menuItemsCount === thisItemPosition + items.length )
+ break;
+
+ items.detach().insertAfter( menuItems.eq( thisItemPosition + items.length ) ).updateParentMenuItemDBId();
+ } else {
+ // If next item has sub items, shift depth
+ if ( 0 !== nextItemChildren.length )
+ thisItem.moveHorizontally( nextItemDepth, thisItemDepth );
+
+ // Have we reached the bottom
+ if ( menuItemsCount === thisItemPosition + 1 )
+ break;
+ thisItem.detach().insertAfter( menuItems.eq( thisItemPosition + 1 ) ).updateParentMenuItemDBId();
+ }
+ break;
+ case 'top':
+ // Already at top
+ if ( 0 === thisItemPosition )
+ break;
+ // Does this item have sub items?
+ if ( thisItemChildren ) {
+ var items = thisItem.add( thisItemChildren );
+ // Move the entire block
+ items.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
+ } else {
+ thisItem.detach().insertBefore( menuItems.eq( 0 ) ).updateParentMenuItemDBId();
+ }
+ break;
+ case 'left':
+ // As far left as possible
+ if ( 0 === thisItemDepth )
+ break;
+ thisItem.shiftHorizontally( -1 );
+ break;
+ case 'right':
+ // Can't be sub item at top
+ if ( 0 === thisItemPosition )
+ break;
+ // Already sub item of prevItem
+ if ( thisItemData['menu-item-parent-id'] === prevItemId )
+ break;
+ thisItem.shiftHorizontally( 1 );
+ break;
+ }
+ $this.focus();
+ api.registerChange();
+ api.refreshKeyboardAccessibility();
+ api.refreshAdvancedAccessibility();
+ },
+
+ initAccessibility : function() {
+ api.refreshKeyboardAccessibility();
+ api.refreshAdvancedAccessibility();
+
+ // Events
+ $( '.menus-move-up' ).on( 'click', function ( e ) {
+ api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'up' );
+ e.preventDefault();
+ });
+ $( '.menus-move-down' ).on( 'click', function ( e ) {
+ api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'down' );
+ e.preventDefault();
+ });
+ $( '.menus-move-top' ).on( 'click', function ( e ) {
+ api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'top' );
+ e.preventDefault();
+ });
+ $( '.menus-move-left' ).on( 'click', function ( e ) {
+ api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'left' );
+ e.preventDefault();
+ });
+ $( '.menus-move-right' ).on( 'click', function ( e ) {
+ api.moveMenuItem( $( this ).parents( 'li.menu-item' ).find( 'a.item-edit' ), 'right' );
+ e.preventDefault();
+ });
+ },
+
+ refreshAdvancedAccessibility : function() {
+
+ // Hide all links by default
+ $( '.menu-item-settings .field-move a' ).hide();
+
+ $( '.item-edit' ).each( function() {
+ var $this = $(this),
+ movement = [],
+ availableMovement = '',
+ menuItem = $this.parents( 'li.menu-item' ).first(),
+ depth = menuItem.menuItemDepth(),
+ isPrimaryMenuItem = ( 0 === depth ),
+ itemName = $this.parents( '.menu-item-handle' ).find( '.menu-item-title' ).text(),
+ position = parseInt( menuItem.index() ),
+ prevItemDepth = ( isPrimaryMenuItem ) ? depth : parseInt( depth - 1 ),
+ prevItemNameLeft = menuItem.prevAll('.menu-item-depth-' + prevItemDepth).first().find( '.menu-item-title' ).text(),
+ prevItemNameRight = menuItem.prevAll('.menu-item-depth-' + depth).first().find( '.menu-item-title' ).text(),
+ totalMenuItems = $('#menu-to-edit li').length,
+ hasSameDepthSibling = menuItem.nextAll( '.menu-item-depth-' + depth ).length;
+
+ // Where can they move this menu item?
+ if ( 0 !== position ) {
+ var thisLink = menuItem.find( '.menus-move-up' );
+ thisLink.prop( 'title', menus.moveUp ).show();
+ }
+
+ if ( 0 !== position && isPrimaryMenuItem ) {
+ var thisLink = menuItem.find( '.menus-move-top' );
+ thisLink.prop( 'title', menus.moveToTop ).show();
+ }
+
+ if ( position + 1 !== totalMenuItems && 0 !== position ) {
+ var thisLink = menuItem.find( '.menus-move-down' );
+ thisLink.prop( 'title', menus.moveDown ).show();
+ }
+
+ if ( 0 === position && 0 !== hasSameDepthSibling ) {
+ var thisLink = menuItem.find( '.menus-move-down' );
+ thisLink.prop( 'title', menus.moveDown ).show();
+ }
+
+ if ( ! isPrimaryMenuItem ) {
+ var thisLink = menuItem.find( '.menus-move-left' ),
+ thisLinkText = menus.outFrom.replace( '%s', prevItemNameLeft );
+ thisLink.prop( 'title', menus.moveOutFrom.replace( '%s', prevItemNameLeft ) ).html( thisLinkText ).show();
+ }
+
+ if ( 0 !== position ) {
+ if ( menuItem.find( '.menu-item-data-parent-id' ).val() !== menuItem.prev().find( '.menu-item-data-db-id' ).val() ) {
+ var thisLink = menuItem.find( '.menus-move-right' ),
+ thisLinkText = menus.under.replace( '%s', prevItemNameRight );
+ thisLink.prop( 'title', menus.moveUnder.replace( '%s', prevItemNameRight ) ).html( thisLinkText ).show();
+ }
+ }
+
+ if ( isPrimaryMenuItem ) {
+ var primaryItems = $( '.menu-item-depth-0' ),
+ itemPosition = primaryItems.index( menuItem ) + 1,
+ totalMenuItems = primaryItems.length,
+
+ // String together help text for primary menu items
+ title = menus.menuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$d', totalMenuItems );
+ } else {
+ var parentItem = menuItem.prevAll( '.menu-item-depth-' + parseInt( depth - 1 ) ).first(),
+ parentItemId = parentItem.find( '.menu-item-data-db-id' ).val(),
+ parentItemName = parentItem.find( '.menu-item-title' ).text(),
+ subItems = $( '.menu-item .menu-item-data-parent-id[value="' + parentItemId + '"]' ),
+ itemPosition = $( subItems.parents('.menu-item').get().reverse() ).index( menuItem ) + 1;
+
+ // String together help text for sub menu items
+ title = menus.subMenuFocus.replace( '%1$s', itemName ).replace( '%2$d', itemPosition ).replace( '%3$s', parentItemName );
+ }
+
+ $this.prop('title', title).html( title );
+ });
+ },
+
+ refreshKeyboardAccessibility : function() {
+ $( '.item-edit' ).off( 'focus' ).on( 'focus', function(){
+ $(this).off( 'keydown' ).on( 'keydown', function(e){
+
+ var $this = $(this);
+
+ // Bail if it's not an arrow key
+ if ( 37 != e.which && 38 != e.which && 39 != e.which && 40 != e.which )
+ return;
+
+ // Avoid multiple keydown events
+ $this.off('keydown');
+
+ // Bail if there is only one menu item
+ if ( 1 === $('#menu-to-edit li').length )
+ return;
+
+ // If RTL, swap left/right arrows
+ var arrows = { '38' : 'up', '40' : 'down', '37' : 'left', '39' : 'right' };
+ if ( $('body').hasClass('rtl') )
+ arrows = { '38' : 'up', '40' : 'down', '39' : 'left', '37' : 'right' };
+
+ switch ( arrows[e.which] ) {
+ case 'up':
+ api.moveMenuItem( $this, 'up' );
+ break;
+ case 'down':
+ api.moveMenuItem( $this, 'down' );
+ break;
+ case 'left':
+ api.moveMenuItem( $this, 'left' );
+ break;
+ case 'right':
+ api.moveMenuItem( $this, 'right' );
+ break;
+ }
+ // Put focus back on same menu item
+ $( '#edit-' + thisItemData['menu-item-db-id'] ).focus();
+ return false;
+ });
+ });
+ },
+
+ initToggles : function() {
+ // init postboxes
+ postboxes.add_postbox_toggles('nav-menus');
+
+ // adjust columns functions for menus UI
+ columns.useCheckboxesForHidden();
+ columns.checked = function(field) {
+ $('.field-' + field).removeClass('hidden-field');
+ }
+ columns.unchecked = function(field) {
+ $('.field-' + field).addClass('hidden-field');
+ }
+ // hide fields
+ api.menuList.hideAdvancedMenuItemFields();
+
+ $('.hide-postbox-tog').click(function () {
+ var hidden = $( '.accordion-container li.accordion-section' ).filter(':hidden').map(function() { return this.id; }).get().join(',');
+ $.post(ajaxurl, {
+ action: 'closed-postboxes',
+ hidden: hidden,
+ closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
+ page: 'nav-menus'
+ });
+ });
+ },
+
+ initSortables : function() {
+ var currentDepth = 0, originalDepth, minDepth, maxDepth,
+ prev, next, prevBottom, nextThreshold, helperHeight, transport,
+ menuEdge = api.menuList.offset().left,
+ body = $('body'), maxChildDepth,
+ menuMaxDepth = initialMenuMaxDepth();
+
+ if( 0 != $( '#menu-to-edit li' ).length )
+ $( '.drag-instructions' ).show();
+
+ // Use the right edge if RTL.
+ menuEdge += api.isRTL ? api.menuList.width() : 0;
+
+ api.menuList.sortable({
+ handle: '.menu-item-handle',
+ placeholder: 'sortable-placeholder',
+ start: function(e, ui) {
+ var height, width, parent, children, tempHolder;
+
+ // handle placement for rtl orientation
+ if ( api.isRTL )
+ ui.item[0].style.right = 'auto';
+
+ transport = ui.item.children('.menu-item-transport');
+
+ // Set depths. currentDepth must be set before children are located.
+ originalDepth = ui.item.menuItemDepth();
+ updateCurrentDepth(ui, originalDepth);
+
+ // Attach child elements to parent
+ // Skip the placeholder
+ parent = ( ui.item.next()[0] == ui.placeholder[0] ) ? ui.item.next() : ui.item;
+ children = parent.childMenuItems();
+ transport.append( children );
+
+ // Update the height of the placeholder to match the moving item.
+ height = transport.outerHeight();
+ // If there are children, account for distance between top of children and parent
+ height += ( height > 0 ) ? (ui.placeholder.css('margin-top').slice(0, -2) * 1) : 0;
+ height += ui.helper.outerHeight();
+ helperHeight = height;
+ height -= 2; // Subtract 2 for borders
+ ui.placeholder.height(height);
+
+ // Update the width of the placeholder to match the moving item.
+ maxChildDepth = originalDepth;
+ children.each(function(){
+ var depth = $(this).menuItemDepth();
+ maxChildDepth = (depth > maxChildDepth) ? depth : maxChildDepth;
+ });
+ width = ui.helper.find('.menu-item-handle').outerWidth(); // Get original width
+ width += api.depthToPx(maxChildDepth - originalDepth); // Account for children
+ width -= 2; // Subtract 2 for borders
+ ui.placeholder.width(width);
+
+ // Update the list of menu items.
+ tempHolder = ui.placeholder.next();
+ tempHolder.css( 'margin-top', helperHeight + 'px' ); // Set the margin to absorb the placeholder
+ ui.placeholder.detach(); // detach or jQuery UI will think the placeholder is a menu item
+ $(this).sortable( "refresh" ); // The children aren't sortable. We should let jQ UI know.
+ ui.item.after( ui.placeholder ); // reattach the placeholder.
+ tempHolder.css('margin-top', 0); // reset the margin
+
+ // Now that the element is complete, we can update...
+ updateSharedVars(ui);
+ },
+ stop: function(e, ui) {
+ var children, depthChange = currentDepth - originalDepth;
+
+ // Return child elements to the list
+ children = transport.children().insertAfter(ui.item);
+
+ // Add "sub menu" description
+ var subMenuTitle = ui.item.find( '.item-title .is-submenu' );
+ if ( 0 < currentDepth )
+ subMenuTitle.show();
+ else
+ subMenuTitle.hide();
+
+ // Update depth classes
+ if( depthChange != 0 ) {
+ ui.item.updateDepthClass( currentDepth );
+ children.shiftDepthClass( depthChange );
+ updateMenuMaxDepth( depthChange );
+ }
+ // Register a change
+ api.registerChange();
+ // Update the item data.
+ ui.item.updateParentMenuItemDBId();
+
+ // address sortable's incorrectly-calculated top in opera
+ ui.item[0].style.top = 0;
+
+ // handle drop placement for rtl orientation
+ if ( api.isRTL ) {
+ ui.item[0].style.left = 'auto';
+ ui.item[0].style.right = 0;
+ }
+
+ api.refreshKeyboardAccessibility();
+ api.refreshAdvancedAccessibility();
+ },
+ change: function(e, ui) {
+ // Make sure the placeholder is inside the menu.
+ // Otherwise fix it, or we're in trouble.
+ if( ! ui.placeholder.parent().hasClass('menu') )
+ (prev.length) ? prev.after( ui.placeholder ) : api.menuList.prepend( ui.placeholder );
+
+ updateSharedVars(ui);
+ },
+ sort: function(e, ui) {
+ var offset = ui.helper.offset(),
+ edge = api.isRTL ? offset.left + ui.helper.width() : offset.left,
+ depth = api.negateIfRTL * api.pxToDepth( edge - menuEdge );
+ // Check and correct if depth is not within range.
+ // Also, if the dragged element is dragged upwards over
+ // an item, shift the placeholder to a child position.
+ if ( depth > maxDepth || offset.top < prevBottom ) depth = maxDepth;
+ else if ( depth < minDepth ) depth = minDepth;
+
+ if( depth != currentDepth )
+ updateCurrentDepth(ui, depth);
+
+ // If we overlap the next element, manually shift downwards
+ if( nextThreshold && offset.top + helperHeight > nextThreshold ) {
+ next.after( ui.placeholder );
+ updateSharedVars( ui );
+ $(this).sortable( "refreshPositions" );
+ }
+ }
+ });
+
+ function updateSharedVars(ui) {
+ var depth;
+
+ prev = ui.placeholder.prev();
+ next = ui.placeholder.next();
+
+ // Make sure we don't select the moving item.
+ if( prev[0] == ui.item[0] ) prev = prev.prev();
+ if( next[0] == ui.item[0] ) next = next.next();
+
+ prevBottom = (prev.length) ? prev.offset().top + prev.height() : 0;
+ nextThreshold = (next.length) ? next.offset().top + next.height() / 3 : 0;
+ minDepth = (next.length) ? next.menuItemDepth() : 0;
+
+ if( prev.length )
+ maxDepth = ( (depth = prev.menuItemDepth() + 1) > api.options.globalMaxDepth ) ? api.options.globalMaxDepth : depth;
+ else
+ maxDepth = 0;
+ }
+
+ function updateCurrentDepth(ui, depth) {
+ ui.placeholder.updateDepthClass( depth, currentDepth );
+ currentDepth = depth;
+ }
+
+ function initialMenuMaxDepth() {
+ if( ! body[0].className ) return 0;
+ var match = body[0].className.match(/menu-max-depth-(\d+)/);
+ return match && match[1] ? parseInt(match[1]) : 0;
+ }
+
+ function updateMenuMaxDepth( depthChange ) {
+ var depth, newDepth = menuMaxDepth;
+ if ( depthChange === 0 ) {
+ return;
+ } else if ( depthChange > 0 ) {
+ depth = maxChildDepth + depthChange;
+ if( depth > menuMaxDepth )
+ newDepth = depth;
+ } else if ( depthChange < 0 && maxChildDepth == menuMaxDepth ) {
+ while( ! $('.menu-item-depth-' + newDepth, api.menuList).length && newDepth > 0 )
+ newDepth--;
+ }
+ // Update the depth class.
+ body.removeClass( 'menu-max-depth-' + menuMaxDepth ).addClass( 'menu-max-depth-' + newDepth );
+ menuMaxDepth = newDepth;
+ }
+ },
+
+ initManageLocations : function () {
+ $('#menu-locations-wrap form').submit(function(){
+ window.onbeforeunload = null;
+ });
+ $('.menu-location-menus select').on('change', function () {
+ var editLink = $(this).closest('tr').find('.locations-edit-menu-link');
+ if ($(this).find('option:selected').data('orig'))
+ editLink.show();
+ else
+ editLink.hide();
+ });
+ },
+
+ attachMenuEditListeners : function() {
+ var that = this;
+ $('#update-nav-menu').bind('click', function(e) {
+ if ( e.target && e.target.className ) {
+ if ( -1 != e.target.className.indexOf('item-edit') ) {
+ return that.eventOnClickEditLink(e.target);
+ } else if ( -1 != e.target.className.indexOf('menu-save') ) {
+ return that.eventOnClickMenuSave(e.target);
+ } else if ( -1 != e.target.className.indexOf('menu-delete') ) {
+ return that.eventOnClickMenuDelete(e.target);
+ } else if ( -1 != e.target.className.indexOf('item-delete') ) {
+ return that.eventOnClickMenuItemDelete(e.target);
+ } else if ( -1 != e.target.className.indexOf('item-cancel') ) {
+ return that.eventOnClickCancelLink(e.target);
+ }
+ }
+ });
+ $('#add-custom-links input[type="text"]').keypress(function(e){
+ if ( e.keyCode === 13 ) {
+ e.preventDefault();
+ $("#submit-customlinkdiv").click();
+ }
+ });
+ },
+
+ /**
+ * An interface for managing default values for input elements
+ * that is both JS and accessibility-friendly.
+ *
+ * Input elements that add the class 'input-with-default-title'
+ * will have their values set to the provided HTML title when empty.
+ */
+ setupInputWithDefaultTitle : function() {
+ var name = 'input-with-default-title';
+
+ $('.' + name).each( function(){
+ var $t = $(this), title = $t.attr('title'), val = $t.val();
+ $t.data( name, title );
+
+ if( '' == val ) $t.val( title );
+ else if ( title == val ) return;
+ else $t.removeClass( name );
+ }).focus( function(){
+ var $t = $(this);
+ if( $t.val() == $t.data(name) )
+ $t.val('').removeClass( name );
+ }).blur( function(){
+ var $t = $(this);
+ if( '' == $t.val() )
+ $t.addClass( name ).val( $t.data(name) );
+ });
+
+ $( '.blank-slate .input-with-default-title' ).focus();
+ },
+
+ attachThemeLocationsListeners : function() {
+ var loc = $('#nav-menu-theme-locations'), params = {};
+ params['action'] = 'menu-locations-save';
+ params['menu-settings-column-nonce'] = $('#menu-settings-column-nonce').val();
+ loc.find('input[type="submit"]').click(function() {
+ loc.find('select').each(function() {
+ params[this.name] = $(this).val();
+ });
+ loc.find('.spinner').show();
+ $.post( ajaxurl, params, function(r) {
+ loc.find('.spinner').hide();
+ });
+ return false;
+ });
+ },
+
+ attachQuickSearchListeners : function() {
+ var searchTimer;
+
+ $('.quick-search').keypress(function(e){
+ var t = $(this);
+
+ if( 13 == e.which ) {
+ api.updateQuickSearchResults( t );
+ return false;
+ }
+
+ if( searchTimer ) clearTimeout(searchTimer);
+
+ searchTimer = setTimeout(function(){
+ api.updateQuickSearchResults( t );
+ }, 400);
+ }).attr('autocomplete','off');
+ },
+
+ updateQuickSearchResults : function(input) {
+ var panel, params,
+ minSearchLength = 2,
+ q = input.val();
+
+ if( q.length < minSearchLength ) return;
+
+ panel = input.parents('.tabs-panel');
+ params = {
+ 'action': 'menu-quick-search',
+ 'response-format': 'markup',
+ 'menu': $('#menu').val(),
+ 'menu-settings-column-nonce': $('#menu-settings-column-nonce').val(),
+ 'q': q,
+ 'type': input.attr('name')
+ };
+
+ $('.spinner', panel).show();
+
+ $.post( ajaxurl, params, function(menuMarkup) {
+ api.processQuickSearchQueryResponse(menuMarkup, params, panel);
+ });
+ },
+
+ addCustomLink : function( processMethod ) {
+ var url = $('#custom-menu-item-url').val(),
+ label = $('#custom-menu-item-name').val();
+
+ processMethod = processMethod || api.addMenuItemToBottom;
+
+ if ( '' == url || 'http://' == url )
+ return false;
+
+ // Show the ajax spinner
+ $('.customlinkdiv .spinner').show();
+ this.addLinkToMenu( url, label, processMethod, function() {
+ // Remove the ajax spinner
+ $('.customlinkdiv .spinner').hide();
+ // Set custom link form back to defaults
+ $('#custom-menu-item-name').val('').blur();
+ $('#custom-menu-item-url').val('http://');
+ });
+ },
+
+ addLinkToMenu : function(url, label, processMethod, callback) {
+ processMethod = processMethod || api.addMenuItemToBottom;
+ callback = callback || function(){};
+
+ api.addItemToMenu({
+ '-1': {
+ 'menu-item-type': 'custom',
+ 'menu-item-url': url,
+ 'menu-item-title': label
+ }
+ }, processMethod, callback);
+ },
+
+ addItemToMenu : function(menuItem, processMethod, callback) {
+ var menu = $('#menu').val(),
+ nonce = $('#menu-settings-column-nonce').val();
+
+ processMethod = processMethod || function(){};
+ callback = callback || function(){};
+
+ params = {
+ 'action': 'add-menu-item',
+ 'menu': menu,
+ 'menu-settings-column-nonce': nonce,
+ 'menu-item': menuItem
+ };
+
+ $.post( ajaxurl, params, function(menuMarkup) {
+ var ins = $('#menu-instructions');
+ processMethod(menuMarkup, params);
+ // Make it stand out a bit more visually, by adding a fadeIn
+ $( 'li.pending' ).hide().fadeIn('slow');
+ $( '.drag-instructions' ).show();
+ if( ! ins.hasClass( 'menu-instructions-inactive' ) && ins.siblings().length )
+ ins.addClass( 'menu-instructions-inactive' );
+ callback();
+ });
+ },
+
+ /**
+ * Process the add menu item request response into menu list item.
+ *
+ * @param string menuMarkup The text server response of menu item markup.
+ * @param object req The request arguments.
+ */
+ addMenuItemToBottom : function( menuMarkup, req ) {
+ $(menuMarkup).hideAdvancedMenuItemFields().appendTo( api.targetList );
+ api.refreshKeyboardAccessibility();
+ api.refreshAdvancedAccessibility();
+ },
+
+ addMenuItemToTop : function( menuMarkup, req ) {
+ $(menuMarkup).hideAdvancedMenuItemFields().prependTo( api.targetList );
+ api.refreshKeyboardAccessibility();
+ api.refreshAdvancedAccessibility();
+ },
+
+ attachUnsavedChangesListener : function() {
+ $('#menu-management input, #menu-management select, #menu-management, #menu-management textarea, .menu-location-menus select').change(function(){
+ api.registerChange();
+ });
+
+ if ( 0 != $('#menu-to-edit').length || 0 != $('.menu-location-menus select').length ) {
+ window.onbeforeunload = function(){
+ if ( api.menusChanged )
+ return navMenuL10n.saveAlert;
+ };
+ } else {
+ // Make the post boxes read-only, as they can't be used yet
+ $( '#menu-settings-column' ).find( 'input,select' ).end().find( 'a' ).attr( 'href', '#' ).unbind( 'click' );
+ }
+ },
+
+ registerChange : function() {
+ api.menusChanged = true;
+ },
+
+ attachTabsPanelListeners : function() {
+ $('#menu-settings-column').bind('click', function(e) {
+ var selectAreaMatch, panelId, wrapper, items,
+ target = $(e.target);
+
+ if ( target.hasClass('nav-tab-link') ) {
+
+ panelId = target.data( 'type' );
+
+ wrapper = target.parents('.accordion-section-content').first();
+
+ // upon changing tabs, we want to uncheck all checkboxes
+ $('input', wrapper).removeAttr('checked');
+
+ $('.tabs-panel-active', wrapper).removeClass('tabs-panel-active').addClass('tabs-panel-inactive');
+ $('#' + panelId, wrapper).removeClass('tabs-panel-inactive').addClass('tabs-panel-active');
+
+ $('.tabs', wrapper).removeClass('tabs');
+ target.parent().addClass('tabs');
+
+ // select the search bar
+ $('.quick-search', wrapper).focus();
+
+ e.preventDefault();
+ } else if ( target.hasClass('select-all') ) {
+ selectAreaMatch = /#(.*)$/.exec(e.target.href);
+ if ( selectAreaMatch && selectAreaMatch[1] ) {
+ items = $('#' + selectAreaMatch[1] + ' .tabs-panel-active .menu-item-title input');
+ if( items.length === items.filter(':checked').length )
+ items.removeAttr('checked');
+ else
+ items.prop('checked', true);
+ return false;
+ }
+ } else if ( target.hasClass('submit-add-to-menu') ) {
+ api.registerChange();
+
+ if ( e.target.id && 'submit-customlinkdiv' == e.target.id )
+ api.addCustomLink( api.addMenuItemToBottom );
+ else if ( e.target.id && -1 != e.target.id.indexOf('submit-') )
+ $('#' + e.target.id.replace(/submit-/, '')).addSelectedToMenu( api.addMenuItemToBottom );
+ return false;
+ } else if ( target.hasClass('page-numbers') ) {
+ $.post( ajaxurl, e.target.href.replace(/.*\?/, '').replace(/action=([^&]*)/, '') + '&action=menu-get-metabox',
+ function( resp ) {
+ if ( -1 == resp.indexOf('replace-id') )
+ return;
+
+ var metaBoxData = $.parseJSON(resp),
+ toReplace = document.getElementById(metaBoxData['replace-id']),
+ placeholder = document.createElement('div'),
+ wrap = document.createElement('div');
+
+ if ( ! metaBoxData['markup'] || ! toReplace )
+ return;
+
+ wrap.innerHTML = metaBoxData['markup'] ? metaBoxData['markup'] : '';
+
+ toReplace.parentNode.insertBefore( placeholder, toReplace );
+ placeholder.parentNode.removeChild( toReplace );
+
+ placeholder.parentNode.insertBefore( wrap, placeholder );
+
+ placeholder.parentNode.removeChild( placeholder );
+
+ }
+ );
+
+ return false;
+ }
+ });
+ },
+
+ eventOnClickEditLink : function(clickedEl) {
+ var settings, item,
+ matchedSection = /#(.*)$/.exec(clickedEl.href);
+ if ( matchedSection && matchedSection[1] ) {
+ settings = $('#'+matchedSection[1]);
+ item = settings.parent();
+ if( 0 != item.length ) {
+ if( item.hasClass('menu-item-edit-inactive') ) {
+ if( ! settings.data('menu-item-data') ) {
+ settings.data( 'menu-item-data', settings.getItemData() );
+ }
+ settings.slideDown('fast');
+ item.removeClass('menu-item-edit-inactive')
+ .addClass('menu-item-edit-active');
+ } else {
+ settings.slideUp('fast');
+ item.removeClass('menu-item-edit-active')
+ .addClass('menu-item-edit-inactive');
+ }
+ return false;
+ }
+ }
+ },
+
+ eventOnClickCancelLink : function(clickedEl) {
+ var settings = $( clickedEl ).closest( '.menu-item-settings' ),
+ thisMenuItem = $( clickedEl ).closest( '.menu-item' );
+ thisMenuItem.removeClass('menu-item-edit-active').addClass('menu-item-edit-inactive');
+ settings.setItemData( settings.data('menu-item-data') ).hide();
+ return false;
+ },
+
+ eventOnClickMenuSave : function(clickedEl) {
+ var locs = '',
+ menuName = $('#menu-name'),
+ menuNameVal = menuName.val();
+ // Cancel and warn if invalid menu name
+ if( !menuNameVal || menuNameVal == menuName.attr('title') || !menuNameVal.replace(/\s+/, '') ) {
+ menuName.parent().addClass('form-invalid');
+ return false;
+ }
+ // Copy menu theme locations
+ $('#nav-menu-theme-locations select').each(function() {
+ locs += '<input type="hidden" name="' + this.name + '" value="' + $(this).val() + '" />';
+ });
+ $('#update-nav-menu').append( locs );
+ // Update menu item position data
+ api.menuList.find('.menu-item-data-position').val( function(index) { return index + 1; } );
+ window.onbeforeunload = null;
+
+ return true;
+ },
+
+ eventOnClickMenuDelete : function(clickedEl) {
+ // Delete warning AYS
+ if ( confirm( navMenuL10n.warnDeleteMenu ) ) {
+ window.onbeforeunload = null;
+ return true;
+ }
+ return false;
+ },
+
+ eventOnClickMenuItemDelete : function(clickedEl) {
+ var itemID = parseInt(clickedEl.id.replace('delete-', ''), 10);
+ api.removeMenuItem( $('#menu-item-' + itemID) );
+ api.registerChange();
+ return false;
+ },
+
+ /**
+ * Process the quick search response into a search result
+ *
+ * @param string resp The server response to the query.
+ * @param object req The request arguments.
+ * @param jQuery panel The tabs panel we're searching in.
+ */
+ processQuickSearchQueryResponse : function(resp, req, panel) {
+ var matched, newID,
+ takenIDs = {},
+ form = document.getElementById('nav-menu-meta'),
+ pattern = new RegExp('menu-item\\[(\[^\\]\]*)', 'g'),
+ $items = $('<div>').html(resp).find('li'),
+ $item;
+
+ if( ! $items.length ) {
+ $('.categorychecklist', panel).html( '<li><p>' + navMenuL10n.noResultsFound + '</p></li>' );
+ $('.spinner', panel).hide();
+ return;
+ }
+
+ $items.each(function(){
+ $item = $(this);
+
+ // make a unique DB ID number
+ matched = pattern.exec($item.html());
+
+ if ( matched && matched[1] ) {
+ newID = matched[1];
+ while( form.elements['menu-item[' + newID + '][menu-item-type]'] || takenIDs[ newID ] ) {
+ newID--;
+ }
+
+ takenIDs[newID] = true;
+ if ( newID != matched[1] ) {
+ $item.html( $item.html().replace(new RegExp(
+ 'menu-item\\[' + matched[1] + '\\]', 'g'),
+ 'menu-item[' + newID + ']'
+ ) );
+ }
+ }
+ });
+
+ $('.categorychecklist', panel).html( $items );
+ $('.spinner', panel).hide();
+ },
+
+ removeMenuItem : function(el) {
+ var children = el.childMenuItems();
+
+ el.addClass('deleting').animate({
+ opacity : 0,
+ height: 0
+ }, 350, function() {
+ var ins = $('#menu-instructions');
+ el.remove();
+ children.shiftDepthClass( -1 ).updateParentMenuItemDBId();
+ if( 0 == $( '#menu-to-edit li' ).length ) {
+ $( '.drag-instructions' ).hide();
+ ins.removeClass( 'menu-instructions-inactive' );
+ }
+ });
+ },
+
+ depthToPx : function(depth) {
+ return depth * api.options.menuItemDepthPerLevel;
+ },
+
+ pxToDepth : function(px) {
+ return Math.floor(px / api.options.menuItemDepthPerLevel);
+ }
+
+ };
+
+ $(document).ready(function(){ wpNavMenu.init(); });
+
+})(jQuery);
diff --git a/src/wp-admin/js/password-strength-meter.js b/src/wp-admin/js/password-strength-meter.js
new file mode 100644
index 0000000000..0f07a93785
--- /dev/null
+++ b/src/wp-admin/js/password-strength-meter.js
@@ -0,0 +1,36 @@
+// Password strength meter
+function passwordStrength(password1, username, password2) {
+ var shortPass = 1, badPass = 2, goodPass = 3, strongPass = 4, mismatch = 5, symbolSize = 0, natLog, score;
+
+ // password 1 != password 2
+ if ( (password1 != password2) && password2.length > 0)
+ return mismatch
+
+ //password < 4
+ if ( password1.length < 4 )
+ return shortPass
+
+ //password1 == username
+ if ( password1.toLowerCase() == username.toLowerCase() )
+ return badPass;
+
+ if ( password1.match(/[0-9]/) )
+ symbolSize +=10;
+ if ( password1.match(/[a-z]/) )
+ symbolSize +=26;
+ if ( password1.match(/[A-Z]/) )
+ symbolSize +=26;
+ if ( password1.match(/[^a-zA-Z0-9]/) )
+ symbolSize +=31;
+
+ natLog = Math.log( Math.pow(symbolSize, password1.length) );
+ score = natLog / Math.LN2;
+
+ if (score < 40 )
+ return badPass
+
+ if (score < 56 )
+ return goodPass
+
+ return strongPass;
+}
diff --git a/src/wp-admin/js/plugin-install.js b/src/wp-admin/js/plugin-install.js
new file mode 100644
index 0000000000..26e9982e28
--- /dev/null
+++ b/src/wp-admin/js/plugin-install.js
@@ -0,0 +1,53 @@
+/* Plugin Browser Thickbox related JS*/
+var tb_position;
+jQuery(document).ready(function($) {
+ tb_position = function() {
+ var tbWindow = $('#TB_window'), width = $(window).width(), H = $(window).height(), W = ( 720 < width ) ? 720 : width, adminbar_height = 0;
+
+ if ( $('body.admin-bar').length )
+ adminbar_height = 28;
+
+ if ( tbWindow.size() ) {
+ tbWindow.width( W - 50 ).height( H - 45 - adminbar_height );
+ $('#TB_iframeContent').width( W - 50 ).height( H - 75 - adminbar_height );
+ tbWindow.css({'margin-left': '-' + parseInt((( W - 50 ) / 2),10) + 'px'});
+ if ( typeof document.body.style.maxWidth != 'undefined' )
+ tbWindow.css({'top': 20 + adminbar_height + 'px','margin-top':'0'});
+ };
+
+ return $('a.thickbox').each( function() {
+ var href = $(this).attr('href');
+ if ( ! href )
+ return;
+ href = href.replace(/&width=[0-9]+/g, '');
+ href = href.replace(/&height=[0-9]+/g, '');
+ $(this).attr( 'href', href + '&width=' + ( W - 80 ) + '&height=' + ( H - 85 - adminbar_height ) );
+ });
+ };
+
+ $(window).resize(function(){ tb_position(); });
+
+ $('#dashboard_plugins, .plugins').on( 'click', 'a.thickbox', function() {
+ tb_click.call(this);
+
+ $('#TB_title').css({'background-color':'#222','color':'#cfcfcf'});
+ $('#TB_ajaxWindowTitle').html('<strong>' + plugininstallL10n.plugin_information + '</strong>&nbsp;' + $(this).attr('title') );
+ return false;
+ });
+
+ /* Plugin install related JS*/
+ $('#plugin-information #sidemenu a').click( function() {
+ var tab = $(this).attr('name');
+ //Flip the tab
+ $('#plugin-information-header a.current').removeClass('current');
+ $(this).addClass('current');
+ //Flip the content.
+ $('#section-holder div.section').hide(); //Hide 'em all
+ $('#section-' + tab).show();
+ return false;
+ });
+
+ $('a.install-now').click( function() {
+ return confirm( plugininstallL10n.ays );
+ });
+});
diff --git a/src/wp-admin/js/post.js b/src/wp-admin/js/post.js
new file mode 100644
index 0000000000..7b7d4c3944
--- /dev/null
+++ b/src/wp-admin/js/post.js
@@ -0,0 +1,921 @@
+var tagBox, commentsBox, editPermalink, makeSlugeditClickable, WPSetThumbnailHTML, WPSetThumbnailID, WPRemoveThumbnail, wptitlehint;
+
+// return an array with any duplicate, whitespace or values removed
+function array_unique_noempty(a) {
+ var out = [];
+ jQuery.each( a, function(key, val) {
+ val = jQuery.trim(val);
+ if ( val && jQuery.inArray(val, out) == -1 )
+ out.push(val);
+ } );
+ return out;
+}
+
+(function($){
+
+tagBox = {
+ clean : function(tags) {
+ var comma = postL10n.comma;
+ if ( ',' !== comma )
+ tags = tags.replace(new RegExp(comma, 'g'), ',');
+ tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, '');
+ if ( ',' !== comma )
+ tags = tags.replace(/,/g, comma);
+ return tags;
+ },
+
+ parseTags : function(el) {
+ var id = el.id, num = id.split('-check-num-')[1], taxbox = $(el).closest('.tagsdiv'),
+ thetags = taxbox.find('.the-tags'), comma = postL10n.comma,
+ current_tags = thetags.val().split(comma), new_tags = [];
+ delete current_tags[num];
+
+ $.each( current_tags, function(key, val) {
+ val = $.trim(val);
+ if ( val ) {
+ new_tags.push(val);
+ }
+ });
+
+ thetags.val( this.clean( new_tags.join(comma) ) );
+
+ this.quickClicks(taxbox);
+ return false;
+ },
+
+ quickClicks : function(el) {
+ var thetags = $('.the-tags', el),
+ tagchecklist = $('.tagchecklist', el),
+ id = $(el).attr('id'),
+ current_tags, disabled;
+
+ if ( !thetags.length )
+ return;
+
+ disabled = thetags.prop('disabled');
+
+ current_tags = thetags.val().split(postL10n.comma);
+ tagchecklist.empty();
+
+ $.each( current_tags, function( key, val ) {
+ var span, xbutton;
+
+ val = $.trim( val );
+
+ if ( ! val )
+ return;
+
+ // Create a new span, and ensure the text is properly escaped.
+ span = $('<span />').text( val );
+
+ // If tags editing isn't disabled, create the X button.
+ if ( ! disabled ) {
+ xbutton = $( '<a id="' + id + '-check-num-' + key + '" class="ntdelbutton">X</a>' );
+ xbutton.click( function(){ tagBox.parseTags(this); });
+ span.prepend('&nbsp;').prepend( xbutton );
+ }
+
+ // Append the span to the tag list.
+ tagchecklist.append( span );
+ });
+ },
+
+ flushTags : function(el, a, f) {
+ a = a || false;
+ var tags = $('.the-tags', el),
+ newtag = $('input.newtag', el),
+ comma = postL10n.comma,
+ newtags, text;
+
+ text = a ? $(a).text() : newtag.val();
+ tagsval = tags.val();
+ newtags = tagsval ? tagsval + comma + text : text;
+
+ newtags = this.clean( newtags );
+ newtags = array_unique_noempty( newtags.split(comma) ).join(comma);
+ tags.val(newtags);
+ this.quickClicks(el);
+
+ if ( !a )
+ newtag.val('');
+ if ( 'undefined' == typeof(f) )
+ newtag.focus();
+
+ return false;
+ },
+
+ get : function(id) {
+ var tax = id.substr(id.indexOf('-')+1);
+
+ $.post(ajaxurl, {'action':'get-tagcloud', 'tax':tax}, function(r, stat) {
+ if ( 0 == r || 'success' != stat )
+ r = wpAjax.broken;
+
+ r = $('<p id="tagcloud-'+tax+'" class="the-tagcloud">'+r+'</p>');
+ $('a', r).click(function(){
+ tagBox.flushTags( $(this).closest('.inside').children('.tagsdiv'), this);
+ return false;
+ });
+
+ $('#'+id).after(r);
+ });
+ },
+
+ init : function() {
+ var t = this, ajaxtag = $('div.ajaxtag');
+
+ $('.tagsdiv').each( function() {
+ tagBox.quickClicks(this);
+ });
+
+ $('input.tagadd', ajaxtag).click(function(){
+ t.flushTags( $(this).closest('.tagsdiv') );
+ });
+
+ $('div.taghint', ajaxtag).click(function(){
+ $(this).css('visibility', 'hidden').parent().siblings('.newtag').focus();
+ });
+
+ $('input.newtag', ajaxtag).blur(function() {
+ if ( this.value == '' )
+ $(this).parent().siblings('.taghint').css('visibility', '');
+ }).focus(function(){
+ $(this).parent().siblings('.taghint').css('visibility', 'hidden');
+ }).keyup(function(e){
+ if ( 13 == e.which ) {
+ tagBox.flushTags( $(this).closest('.tagsdiv') );
+ return false;
+ }
+ }).keypress(function(e){
+ if ( 13 == e.which ) {
+ e.preventDefault();
+ return false;
+ }
+ }).each(function(){
+ var tax = $(this).closest('div.tagsdiv').attr('id');
+ $(this).suggest( ajaxurl + '?action=ajax-tag-search&tax=' + tax, { delay: 500, minchars: 2, multiple: true, multipleSep: postL10n.comma + ' ' } );
+ });
+
+ // save tags on post save/publish
+ $('#post').submit(function(){
+ $('div.tagsdiv').each( function() {
+ tagBox.flushTags(this, false, 1);
+ });
+ });
+
+ // tag cloud
+ $('a.tagcloud-link').click(function(){
+ tagBox.get( $(this).attr('id') );
+ $(this).unbind().click(function(){
+ $(this).siblings('.the-tagcloud').toggle();
+ return false;
+ });
+ return false;
+ });
+ }
+};
+
+commentsBox = {
+ st : 0,
+
+ get : function(total, num) {
+ var st = this.st, data;
+ if ( ! num )
+ num = 20;
+
+ this.st += num;
+ this.total = total;
+ $('#commentsdiv .spinner').show();
+
+ data = {
+ 'action' : 'get-comments',
+ 'mode' : 'single',
+ '_ajax_nonce' : $('#add_comment_nonce').val(),
+ 'p' : $('#post_ID').val(),
+ 'start' : st,
+ 'number' : num
+ };
+
+ $.post(ajaxurl, data,
+ function(r) {
+ r = wpAjax.parseAjaxResponse(r);
+ $('#commentsdiv .widefat').show();
+ $('#commentsdiv .spinner').hide();
+
+ if ( 'object' == typeof r && r.responses[0] ) {
+ $('#the-comment-list').append( r.responses[0].data );
+
+ theList = theExtraList = null;
+ $("a[className*=':']").unbind();
+
+ if ( commentsBox.st > commentsBox.total )
+ $('#show-comments').hide();
+ else
+ $('#show-comments').show().children('a').html(postL10n.showcomm);
+
+ return;
+ } else if ( 1 == r ) {
+ $('#show-comments').html(postL10n.endcomm);
+ return;
+ }
+
+ $('#the-comment-list').append('<tr><td colspan="2">'+wpAjax.broken+'</td></tr>');
+ }
+ );
+
+ return false;
+ }
+};
+
+WPSetThumbnailHTML = function(html){
+ $('.inside', '#postimagediv').html(html);
+};
+
+WPSetThumbnailID = function(id){
+ var field = $('input[value="_thumbnail_id"]', '#list-table');
+ if ( field.size() > 0 ) {
+ $('#meta\\[' + field.attr('id').match(/[0-9]+/) + '\\]\\[value\\]').text(id);
+ }
+};
+
+WPRemoveThumbnail = function(nonce){
+ $.post(ajaxurl, {
+ action:"set-post-thumbnail", post_id: $('#post_ID').val(), thumbnail_id: -1, _ajax_nonce: nonce, cookie: encodeURIComponent(document.cookie)
+ }, function(str){
+ if ( str == '0' ) {
+ alert( setPostThumbnailL10n.error );
+ } else {
+ WPSetThumbnailHTML(str);
+ }
+ }
+ );
+};
+
+$(document).on( 'heartbeat-send.refresh-lock', function( e, data ) {
+ var lock = $('#active_post_lock').val(),
+ post_id = $('#post_ID').val(),
+ send = {};
+
+ if ( ! post_id || ! $('#post-lock-dialog').length )
+ return;
+
+ send['post_id'] = post_id;
+
+ if ( lock )
+ send['lock'] = lock;
+
+ data['wp-refresh-post-lock'] = send;
+});
+
+// Post locks: update the lock string or show the dialog if somebody has taken over editing
+$(document).on( 'heartbeat-tick.refresh-lock', function( e, data ) {
+ var received, wrap, avatar;
+
+ if ( data['wp-refresh-post-lock'] ) {
+ received = data['wp-refresh-post-lock'];
+
+ if ( received.lock_error ) {
+ // show "editing taken over" message
+ wrap = $('#post-lock-dialog');
+
+ if ( wrap.length && ! wrap.is(':visible') ) {
+ if ( typeof autosave == 'function' ) {
+ $(document).on('autosave-disable-buttons.post-lock', function() {
+ wrap.addClass('saving');
+ }).on('autosave-enable-buttons.post-lock', function() {
+ wrap.removeClass('saving').addClass('saved');
+ window.onbeforeunload = null;
+ });
+
+ // Save the latest changes and disable
+ if ( ! autosave() )
+ window.onbeforeunload = null;
+
+ autosave = function(){};
+ }
+
+ if ( received.lock_error.avatar_src ) {
+ avatar = $('<img class="avatar avatar-64 photo" width="64" height="64" />').attr( 'src', received.lock_error.avatar_src.replace(/&amp;/g, '&') );
+ wrap.find('div.post-locked-avatar').empty().append( avatar );
+ }
+
+ wrap.show().find('.currently-editing').text( received.lock_error.text );
+ wrap.find('.wp-tab-first').focus();
+ }
+ } else if ( received.new_lock ) {
+ $('#active_post_lock').val( received.new_lock );
+ }
+ }
+});
+
+}(jQuery));
+
+(function($) {
+ var check, timeout;
+
+ function schedule() {
+ check = false;
+ window.clearTimeout( timeout );
+ timeout = window.setTimeout( function(){ check = true; }, 300000 );
+ }
+
+ $(document).on( 'heartbeat-send.wp-refresh-nonces', function( e, data ) {
+ var nonce, post_id;
+
+ if ( check ) {
+ if ( ( post_id = $('#post_ID').val() ) && ( nonce = $('#_wpnonce').val() ) ) {
+ data['wp-refresh-post-nonces'] = {
+ post_id: post_id,
+ post_nonce: nonce
+ };
+ }
+ }
+ }).on( 'heartbeat-tick.wp-refresh-nonces', function( e, data ) {
+ var nonces = data['wp-refresh-post-nonces'];
+
+ if ( nonces ) {
+ schedule();
+
+ if ( nonces.replace ) {
+ $.each( nonces.replace, function( selector, value ) {
+ $( '#' + selector ).val( value );
+ });
+ }
+
+ if ( nonces.heartbeatNonce )
+ window.heartbeatSettings.nonce = nonces.heartbeatNonce;
+ }
+ }).ready( function() {
+ schedule();
+ });
+}(jQuery));
+
+jQuery(document).ready( function($) {
+ var stamp, visibility, sticky = '', last = 0, co = $('#content');
+
+ postboxes.add_postbox_toggles(pagenow);
+
+ // Post locks: contain focus inside the dialog. If the dialog is shown, focus the first item.
+ $('#post-lock-dialog .notification-dialog').on( 'keydown', function(e) {
+ if ( e.which != 9 )
+ return;
+
+ var target = $(e.target);
+
+ if ( target.hasClass('wp-tab-first') && e.shiftKey ) {
+ $(this).find('.wp-tab-last').focus();
+ e.preventDefault();
+ } else if ( target.hasClass('wp-tab-last') && ! e.shiftKey ) {
+ $(this).find('.wp-tab-first').focus();
+ e.preventDefault();
+ }
+ }).filter(':visible').find('.wp-tab-first').focus();
+
+ // multi-taxonomies
+ if ( $('#tagsdiv-post_tag').length ) {
+ tagBox.init();
+ } else {
+ $('#side-sortables, #normal-sortables, #advanced-sortables').children('div.postbox').each(function(){
+ if ( this.id.indexOf('tagsdiv-') === 0 ) {
+ tagBox.init();
+ return false;
+ }
+ });
+ }
+
+ // categories
+ $('.categorydiv').each( function(){
+ var this_id = $(this).attr('id'), catAddBefore, catAddAfter, taxonomyParts, taxonomy, settingName;
+
+ taxonomyParts = this_id.split('-');
+ taxonomyParts.shift();
+ taxonomy = taxonomyParts.join('-');
+ settingName = taxonomy + '_tab';
+ if ( taxonomy == 'category' )
+ settingName = 'cats';
+
+ // TODO: move to jQuery 1.3+, support for multiple hierarchical taxonomies, see wp-lists.js
+ $('a', '#' + taxonomy + '-tabs').click( function(){
+ var t = $(this).attr('href');
+ $(this).parent().addClass('tabs').siblings('li').removeClass('tabs');
+ $('#' + taxonomy + '-tabs').siblings('.tabs-panel').hide();
+ $(t).show();
+ if ( '#' + taxonomy + '-all' == t )
+ deleteUserSetting(settingName);
+ else
+ setUserSetting(settingName, 'pop');
+ return false;
+ });
+
+ if ( getUserSetting(settingName) )
+ $('a[href="#' + taxonomy + '-pop"]', '#' + taxonomy + '-tabs').click();
+
+ // Ajax Cat
+ $('#new' + taxonomy).one( 'focus', function() { $(this).val( '' ).removeClass( 'form-input-tip' ) } );
+
+ $('#new' + taxonomy).keypress( function(event){
+ if( 13 === event.keyCode ) {
+ event.preventDefault();
+ $('#' + taxonomy + '-add-submit').click();
+ }
+ });
+ $('#' + taxonomy + '-add-submit').click( function(){ $('#new' + taxonomy).focus(); });
+
+ catAddBefore = function( s ) {
+ if ( !$('#new'+taxonomy).val() )
+ return false;
+ s.data += '&' + $( ':checked', '#'+taxonomy+'checklist' ).serialize();
+ $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', true );
+ return s;
+ };
+
+ catAddAfter = function( r, s ) {
+ var sup, drop = $('#new'+taxonomy+'_parent');
+
+ $( '#' + taxonomy + '-add-submit' ).prop( 'disabled', false );
+ if ( 'undefined' != s.parsed.responses[0] && (sup = s.parsed.responses[0].supplemental.newcat_parent) ) {
+ drop.before(sup);
+ drop.remove();
+ }
+ };
+
+ $('#' + taxonomy + 'checklist').wpList({
+ alt: '',
+ response: taxonomy + '-ajax-response',
+ addBefore: catAddBefore,
+ addAfter: catAddAfter
+ });
+
+ $('#' + taxonomy + '-add-toggle').click( function() {
+ $('#' + taxonomy + '-adder').toggleClass( 'wp-hidden-children' );
+ $('a[href="#' + taxonomy + '-all"]', '#' + taxonomy + '-tabs').click();
+ $('#new'+taxonomy).focus();
+ return false;
+ });
+
+ $('#' + taxonomy + 'checklist, #' + taxonomy + 'checklist-pop').on( 'click', 'li.popular-category > label input[type="checkbox"]', function() {
+ var t = $(this), c = t.is(':checked'), id = t.val();
+ if ( id && t.parents('#taxonomy-'+taxonomy).length )
+ $('#in-' + taxonomy + '-' + id + ', #in-popular-' + taxonomy + '-' + id).prop( 'checked', c );
+ });
+
+ }); // end cats
+
+ // Custom Fields
+ if ( $('#postcustom').length ) {
+ $('#the-list').wpList( { addAfter: function( xml, s ) {
+ $('table#list-table').show();
+ }, addBefore: function( s ) {
+ s.data += '&post_id=' + $('#post_ID').val();
+ return s;
+ }
+ });
+ }
+
+ // submitdiv
+ if ( $('#submitdiv').length ) {
+ stamp = $('#timestamp').html();
+ visibility = $('#post-visibility-display').html();
+
+ function updateVisibility() {
+ var pvSelect = $('#post-visibility-select');
+ if ( $('input:radio:checked', pvSelect).val() != 'public' ) {
+ $('#sticky').prop('checked', false);
+ $('#sticky-span').hide();
+ } else {
+ $('#sticky-span').show();
+ }
+ if ( $('input:radio:checked', pvSelect).val() != 'password' ) {
+ $('#password-span').hide();
+ } else {
+ $('#password-span').show();
+ }
+ }
+
+ function updateText() {
+
+ if ( ! $('#timestampdiv').length )
+ return true;
+
+ var attemptedDate, originalDate, currentDate, publishOn, postStatus = $('#post_status'),
+ optPublish = $('option[value="publish"]', postStatus), aa = $('#aa').val(),
+ mm = $('#mm').val(), jj = $('#jj').val(), hh = $('#hh').val(), mn = $('#mn').val();
+
+ attemptedDate = new Date( aa, mm - 1, jj, hh, mn );
+ originalDate = new Date( $('#hidden_aa').val(), $('#hidden_mm').val() -1, $('#hidden_jj').val(), $('#hidden_hh').val(), $('#hidden_mn').val() );
+ currentDate = new Date( $('#cur_aa').val(), $('#cur_mm').val() -1, $('#cur_jj').val(), $('#cur_hh').val(), $('#cur_mn').val() );
+
+ if ( attemptedDate.getFullYear() != aa || (1 + attemptedDate.getMonth()) != mm || attemptedDate.getDate() != jj || attemptedDate.getMinutes() != mn ) {
+ $('.timestamp-wrap', '#timestampdiv').addClass('form-invalid');
+ return false;
+ } else {
+ $('.timestamp-wrap', '#timestampdiv').removeClass('form-invalid');
+ }
+
+ if ( attemptedDate > currentDate && $('#original_post_status').val() != 'future' ) {
+ publishOn = postL10n.publishOnFuture;
+ $('#publish').val( postL10n.schedule );
+ } else if ( attemptedDate <= currentDate && $('#original_post_status').val() != 'publish' ) {
+ publishOn = postL10n.publishOn;
+ $('#publish').val( postL10n.publish );
+ } else {
+ publishOn = postL10n.publishOnPast;
+ $('#publish').val( postL10n.update );
+ }
+ if ( originalDate.toUTCString() == attemptedDate.toUTCString() ) { //hack
+ $('#timestamp').html(stamp);
+ } else {
+ $('#timestamp').html(
+ publishOn + ' <b>' +
+ postL10n.dateFormat.replace( '%1$s', $('option[value="' + $('#mm').val() + '"]', '#mm').text() )
+ .replace( '%2$s', jj )
+ .replace( '%3$s', aa )
+ .replace( '%4$s', hh )
+ .replace( '%5$s', mn )
+ + '</b> '
+ );
+ }
+
+ if ( $('input:radio:checked', '#post-visibility-select').val() == 'private' ) {
+ $('#publish').val( postL10n.update );
+ if ( optPublish.length == 0 ) {
+ postStatus.append('<option value="publish">' + postL10n.privatelyPublished + '</option>');
+ } else {
+ optPublish.html( postL10n.privatelyPublished );
+ }
+ $('option[value="publish"]', postStatus).prop('selected', true);
+ $('.edit-post-status', '#misc-publishing-actions').hide();
+ } else {
+ if ( $('#original_post_status').val() == 'future' || $('#original_post_status').val() == 'draft' ) {
+ if ( optPublish.length ) {
+ optPublish.remove();
+ postStatus.val($('#hidden_post_status').val());
+ }
+ } else {
+ optPublish.html( postL10n.published );
+ }
+ if ( postStatus.is(':hidden') )
+ $('.edit-post-status', '#misc-publishing-actions').show();
+ }
+ $('#post-status-display').html($('option:selected', postStatus).text());
+ if ( $('option:selected', postStatus).val() == 'private' || $('option:selected', postStatus).val() == 'publish' ) {
+ $('#save-post').hide();
+ } else {
+ $('#save-post').show();
+ if ( $('option:selected', postStatus).val() == 'pending' ) {
+ $('#save-post').show().val( postL10n.savePending );
+ } else {
+ $('#save-post').show().val( postL10n.saveDraft );
+ }
+ }
+ return true;
+ }
+
+ $('.edit-visibility', '#visibility').click(function () {
+ if ($('#post-visibility-select').is(":hidden")) {
+ updateVisibility();
+ $('#post-visibility-select').slideDown('fast');
+ $(this).hide();
+ }
+ return false;
+ });
+
+ $('.cancel-post-visibility', '#post-visibility-select').click(function () {
+ $('#post-visibility-select').slideUp('fast');
+ $('#visibility-radio-' + $('#hidden-post-visibility').val()).prop('checked', true);
+ $('#post_password').val($('#hidden-post-password').val());
+ $('#sticky').prop('checked', $('#hidden-post-sticky').prop('checked'));
+ $('#post-visibility-display').html(visibility);
+ $('.edit-visibility', '#visibility').show();
+ updateText();
+ return false;
+ });
+
+ $('.save-post-visibility', '#post-visibility-select').click(function () { // crazyhorse - multiple ok cancels
+ var pvSelect = $('#post-visibility-select');
+
+ pvSelect.slideUp('fast');
+ $('.edit-visibility', '#visibility').show();
+ updateText();
+
+ if ( $('input:radio:checked', pvSelect).val() != 'public' ) {
+ $('#sticky').prop('checked', false);
+ } // WEAPON LOCKED
+
+ if ( true == $('#sticky').prop('checked') ) {
+ sticky = 'Sticky';
+ } else {
+ sticky = '';
+ }
+
+ $('#post-visibility-display').html( postL10n[$('input:radio:checked', pvSelect).val() + sticky] );
+ return false;
+ });
+
+ $('input:radio', '#post-visibility-select').change(function() {
+ updateVisibility();
+ });
+
+ $('#timestampdiv').siblings('a.edit-timestamp').click(function() {
+ if ($('#timestampdiv').is(":hidden")) {
+ $('#timestampdiv').slideDown('fast');
+ $('#mm').focus();
+ $(this).hide();
+ }
+ return false;
+ });
+
+ $('.cancel-timestamp', '#timestampdiv').click(function() {
+ $('#timestampdiv').slideUp('fast');
+ $('#mm').val($('#hidden_mm').val());
+ $('#jj').val($('#hidden_jj').val());
+ $('#aa').val($('#hidden_aa').val());
+ $('#hh').val($('#hidden_hh').val());
+ $('#mn').val($('#hidden_mn').val());
+ $('#timestampdiv').siblings('a.edit-timestamp').show();
+ updateText();
+ return false;
+ });
+
+ $('.save-timestamp', '#timestampdiv').click(function () { // crazyhorse - multiple ok cancels
+ if ( updateText() ) {
+ $('#timestampdiv').slideUp('fast');
+ $('#timestampdiv').siblings('a.edit-timestamp').show();
+ }
+ return false;
+ });
+
+ $('#post').on( 'submit', function(e){
+ if ( ! updateText() ) {
+ e.preventDefault();
+ $('#timestampdiv').show();
+ $('#publishing-action .spinner').hide();
+ $('#publish').prop('disabled', false).removeClass('button-primary-disabled');
+ return false;
+ }
+ });
+
+ $('#post-status-select').siblings('a.edit-post-status').click(function() {
+ if ($('#post-status-select').is(":hidden")) {
+ $('#post-status-select').slideDown('fast');
+ $(this).hide();
+ }
+ return false;
+ });
+
+ $('.save-post-status', '#post-status-select').click(function() {
+ $('#post-status-select').slideUp('fast');
+ $('#post-status-select').siblings('a.edit-post-status').show();
+ updateText();
+ return false;
+ });
+
+ $('.cancel-post-status', '#post-status-select').click(function() {
+ $('#post-status-select').slideUp('fast');
+ $('#post_status').val($('#hidden_post_status').val());
+ $('#post-status-select').siblings('a.edit-post-status').show();
+ updateText();
+ return false;
+ });
+ } // end submitdiv
+
+ // permalink
+ if ( $('#edit-slug-box').length ) {
+ editPermalink = function(post_id) {
+ var i, c = 0, e = $('#editable-post-name'), revert_e = e.html(), real_slug = $('#post_name'), revert_slug = real_slug.val(), b = $('#edit-slug-buttons'), revert_b = b.html(), full = $('#editable-post-name-full').html();
+
+ $('#view-post-btn').hide();
+ b.html('<a href="#" class="save button button-small">'+postL10n.ok+'</a> <a class="cancel" href="#">'+postL10n.cancel+'</a>');
+ b.children('.save').click(function() {
+ var new_slug = e.children('input').val();
+ if ( new_slug == $('#editable-post-name-full').text() ) {
+ return $('.cancel', '#edit-slug-buttons').click();
+ }
+ $.post(ajaxurl, {
+ action: 'sample-permalink',
+ post_id: post_id,
+ new_slug: new_slug,
+ new_title: $('#title').val(),
+ samplepermalinknonce: $('#samplepermalinknonce').val()
+ }, function(data) {
+ var box = $('#edit-slug-box');
+ box.html(data);
+ if (box.hasClass('hidden')) {
+ box.fadeIn('fast', function () {
+ box.removeClass('hidden');
+ });
+ }
+ b.html(revert_b);
+ real_slug.val(new_slug);
+ makeSlugeditClickable();
+ $('#view-post-btn').show();
+ });
+ return false;
+ });
+
+ $('.cancel', '#edit-slug-buttons').click(function() {
+ $('#view-post-btn').show();
+ e.html(revert_e);
+ b.html(revert_b);
+ real_slug.val(revert_slug);
+ return false;
+ });
+
+ for ( i = 0; i < full.length; ++i ) {
+ if ( '%' == full.charAt(i) )
+ c++;
+ }
+
+ slug_value = ( c > full.length / 4 ) ? '' : full;
+ e.html('<input type="text" id="new-post-slug" value="'+slug_value+'" />').children('input').keypress(function(e) {
+ var key = e.keyCode || 0;
+ // on enter, just save the new slug, don't save the post
+ if ( 13 == key ) {
+ b.children('.save').click();
+ return false;
+ }
+ if ( 27 == key ) {
+ b.children('.cancel').click();
+ return false;
+ }
+ }).keyup(function(e) {
+ real_slug.val(this.value);
+ }).focus();
+ }
+
+ makeSlugeditClickable = function() {
+ $('#editable-post-name').click(function() {
+ $('#edit-slug-buttons').children('.edit-slug').click();
+ });
+ }
+ makeSlugeditClickable();
+ }
+
+ // word count
+ if ( typeof(wpWordCount) != 'undefined' ) {
+ $(document).triggerHandler('wpcountwords', [ co.val() ]);
+
+ co.keyup( function(e) {
+ var k = e.keyCode || e.charCode;
+
+ if ( k == last )
+ return true;
+
+ if ( 13 == k || 8 == last || 46 == last )
+ $(document).triggerHandler('wpcountwords', [ co.val() ]);
+
+ last = k;
+ return true;
+ });
+ }
+
+ wptitlehint = function(id) {
+ id = id || 'title';
+
+ var title = $('#' + id), titleprompt = $('#' + id + '-prompt-text');
+
+ if ( title.val() == '' )
+ titleprompt.removeClass('screen-reader-text');
+
+ titleprompt.click(function(){
+ $(this).addClass('screen-reader-text');
+ title.focus();
+ });
+
+ title.blur(function(){
+ if ( this.value == '' )
+ titleprompt.removeClass('screen-reader-text');
+ }).focus(function(){
+ titleprompt.addClass('screen-reader-text');
+ }).keydown(function(e){
+ titleprompt.addClass('screen-reader-text');
+ $(this).unbind(e);
+ });
+ }
+
+ wptitlehint();
+
+ // resizable textarea#content
+ (function() {
+ var textarea = $('textarea#content'), offset = null, el;
+ // No point for touch devices
+ if ( !textarea.length || 'ontouchstart' in window )
+ return;
+
+ function dragging(e) {
+ textarea.height( Math.max(50, offset + e.pageY) + 'px' );
+ return false;
+ }
+
+ function endDrag(e) {
+ var height;
+
+ textarea.focus();
+ $(document).unbind('mousemove', dragging).unbind('mouseup', endDrag);
+
+ height = parseInt( textarea.css('height'), 10 );
+
+ // sanity check
+ if ( height && height > 50 && height < 5000 )
+ setUserSetting( 'ed_size', height );
+ }
+
+ textarea.css('resize', 'none');
+ el = $('<div id="content-resize-handle"><br></div>');
+ $('#wp-content-wrap').append(el);
+ el.on('mousedown', function(e) {
+ offset = textarea.height() - e.pageY;
+ textarea.blur();
+ $(document).mousemove(dragging).mouseup(endDrag);
+ return false;
+ });
+ })();
+
+ if ( typeof(tinymce) != 'undefined' ) {
+ tinymce.onAddEditor.add(function(mce, ed){
+ // iOS expands the iframe to full height and the user cannot adjust it.
+ if ( ed.id != 'content' || tinymce.isIOS5 )
+ return;
+
+ function getHeight() {
+ var height, node = document.getElementById('content_ifr'),
+ ifr_height = node ? parseInt( node.style.height, 10 ) : 0,
+ tb_height = $('#content_tbl tr.mceFirst').height();
+
+ if ( !ifr_height || !tb_height )
+ return false;
+
+ // total height including toolbar and statusbar
+ height = ifr_height + tb_height + 21;
+ // textarea height = total height - 33px toolbar
+ height -= 33;
+
+ return height;
+ }
+
+ // resize TinyMCE to match the textarea height when switching Text -> Visual
+ ed.onLoadContent.add( function(ed, o) {
+ var ifr_height, node = document.getElementById('content'),
+ height = node ? parseInt( node.style.height, 10 ) : 0,
+ tb_height = $('#content_tbl tr.mceFirst').height() || 33;
+
+ // height cannot be under 50 or over 5000
+ if ( !height || height < 50 || height > 5000 )
+ height = 360; // default height for the main editor
+
+ if ( getUserSetting( 'ed_size' ) > 5000 )
+ setUserSetting( 'ed_size', 360 );
+
+ // compensate for padding and toolbars
+ ifr_height = ( height - tb_height ) + 12;
+
+ // sanity check
+ if ( ifr_height > 50 && ifr_height < 5000 ) {
+ $('#content_tbl').css('height', '' );
+ $('#content_ifr').css('height', ifr_height + 'px' );
+ }
+ });
+
+ // resize the textarea to match TinyMCE's height when switching Visual -> Text
+ ed.onSaveContent.add( function(ed, o) {
+ var height = getHeight();
+
+ if ( !height || height < 50 || height > 5000 )
+ return;
+
+ $('textarea#content').css( 'height', height + 'px' );
+ });
+
+ // save on resizing TinyMCE
+ ed.onPostRender.add(function() {
+ $('#content_resize').on('mousedown.wp-mce-resize', function(e){
+ $(document).on('mouseup.wp-mce-resize', function(e){
+ var height;
+
+ $(document).off('mouseup.wp-mce-resize');
+
+ height = getHeight();
+ // sanity check
+ if ( height && height > 50 && height < 5000 )
+ setUserSetting( 'ed_size', height );
+ });
+ });
+ });
+ });
+
+ // When changing post formats, change the editor body class
+ $('#post-formats-select input.post-format').on( 'change.set-editor-class', function( event ) {
+ var editor, body, format = this.id;
+
+ if ( format && $( this ).prop('checked') ) {
+ editor = tinymce.get( 'content' );
+
+ if ( editor ) {
+ body = editor.getBody();
+ body.className = body.className.replace( /\bpost-format-[^ ]+/, '' );
+ editor.dom.addClass( body, format == 'post-format-0' ? 'post-format-standard' : format );
+ }
+ }
+ });
+ }
+});
diff --git a/src/wp-admin/js/postbox.js b/src/wp-admin/js/postbox.js
new file mode 100644
index 0000000000..838db5d915
--- /dev/null
+++ b/src/wp-admin/js/postbox.js
@@ -0,0 +1,186 @@
+var postboxes;
+
+(function($) {
+ postboxes = {
+ add_postbox_toggles : function(page, args) {
+ var self = this;
+
+ self.init(page, args);
+
+ $('.postbox h3, .postbox .handlediv').bind('click.postboxes', function() {
+ var p = $(this).parent('.postbox'), id = p.attr('id');
+
+ if ( 'dashboard_browser_nag' == id )
+ return;
+
+ p.toggleClass('closed');
+
+ if ( page != 'press-this' )
+ self.save_state(page);
+
+ if ( id ) {
+ if ( !p.hasClass('closed') && $.isFunction(postboxes.pbshow) )
+ self.pbshow(id);
+ else if ( p.hasClass('closed') && $.isFunction(postboxes.pbhide) )
+ self.pbhide(id);
+ }
+ });
+
+ $('.postbox h3 a').click( function(e) {
+ e.stopPropagation();
+ });
+
+ $('.postbox a.dismiss').bind('click.postboxes', function(e) {
+ var hide_id = $(this).parents('.postbox').attr('id') + '-hide';
+ $( '#' + hide_id ).prop('checked', false).triggerHandler('click');
+ return false;
+ });
+
+ $('.hide-postbox-tog').bind('click.postboxes', function() {
+ var box = $(this).val();
+
+ if ( $(this).prop('checked') ) {
+ $('#' + box).show();
+ if ( $.isFunction( postboxes.pbshow ) )
+ self.pbshow( box );
+ } else {
+ $('#' + box).hide();
+ if ( $.isFunction( postboxes.pbhide ) )
+ self.pbhide( box );
+ }
+ self.save_state(page);
+ self._mark_area();
+ });
+
+ $('.columns-prefs input[type="radio"]').bind('click.postboxes', function(){
+ var n = parseInt($(this).val(), 10);
+
+ if ( n ) {
+ self._pb_edit(n);
+ self.save_order(page);
+ }
+ });
+ },
+
+ init : function(page, args) {
+ var isMobile = $(document.body).hasClass('mobile');
+
+ $.extend( this, args || {} );
+ $('#wpbody-content').css('overflow','hidden');
+ $('.meta-box-sortables').sortable({
+ placeholder: 'sortable-placeholder',
+ connectWith: '.meta-box-sortables',
+ items: '.postbox',
+ handle: '.hndle',
+ cursor: 'move',
+ delay: ( isMobile ? 200 : 0 ),
+ distance: 2,
+ tolerance: 'pointer',
+ forcePlaceholderSize: true,
+ helper: 'clone',
+ opacity: 0.65,
+ stop: function(e,ui) {
+ if ( $(this).find('#dashboard_browser_nag').is(':visible') && 'dashboard_browser_nag' != this.firstChild.id ) {
+ $(this).sortable('cancel');
+ return;
+ }
+
+ postboxes.save_order(page);
+ },
+ receive: function(e,ui) {
+ if ( 'dashboard_browser_nag' == ui.item[0].id )
+ $(ui.sender).sortable('cancel');
+
+ postboxes._mark_area();
+ }
+ });
+
+ if ( isMobile ) {
+ $(document.body).bind('orientationchange.postboxes', function(){ postboxes._pb_change(); });
+ this._pb_change();
+ }
+
+ this._mark_area();
+ },
+
+ save_state : function(page) {
+ var closed = $('.postbox').filter('.closed').map(function() { return this.id; }).get().join(','),
+ hidden = $('.postbox').filter(':hidden').map(function() { return this.id; }).get().join(',');
+
+ $.post(ajaxurl, {
+ action: 'closed-postboxes',
+ closed: closed,
+ hidden: hidden,
+ closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
+ page: page
+ });
+ },
+
+ save_order : function(page) {
+ var postVars, page_columns = $('.columns-prefs input:checked').val() || 0;
+
+ postVars = {
+ action: 'meta-box-order',
+ _ajax_nonce: $('#meta-box-order-nonce').val(),
+ page_columns: page_columns,
+ page: page
+ }
+ $('.meta-box-sortables').each( function() {
+ postVars["order[" + this.id.split('-')[0] + "]"] = $(this).sortable( 'toArray' ).join(',');
+ } );
+ $.post( ajaxurl, postVars );
+ },
+
+ _mark_area : function() {
+ var visible = $('div.postbox:visible').length, side = $('#post-body #side-sortables');
+
+ $('#dashboard-widgets .meta-box-sortables:visible').each(function(n, el){
+ var t = $(this);
+
+ if ( visible == 1 || t.children('.postbox:visible').length )
+ t.removeClass('empty-container');
+ else
+ t.addClass('empty-container');
+ });
+
+ if ( side.length ) {
+ if ( side.children('.postbox:visible').length )
+ side.removeClass('empty-container');
+ else if ( $('#postbox-container-1').css('width') == '280px' )
+ side.addClass('empty-container');
+ }
+ },
+
+ _pb_edit : function(n) {
+ var el = $('.metabox-holder').get(0);
+ el.className = el.className.replace(/columns-\d+/, 'columns-' + n);
+ },
+
+ _pb_change : function() {
+ var check = $( 'label.columns-prefs-1 input[type="radio"]' );
+
+ switch ( window.orientation ) {
+ case 90:
+ case -90:
+ if ( !check.length || !check.is(':checked') )
+ this._pb_edit(2);
+ break;
+ case 0:
+ case 180:
+ if ( $('#poststuff').length ) {
+ this._pb_edit(1);
+ } else {
+ if ( !check.length || !check.is(':checked') )
+ this._pb_edit(2);
+ }
+ break;
+ }
+ },
+
+ /* Callbacks */
+ pbshow : false,
+
+ pbhide : false
+ };
+
+}(jQuery));
diff --git a/src/wp-admin/js/revisions.js b/src/wp-admin/js/revisions.js
new file mode 100644
index 0000000000..6a8499f88e
--- /dev/null
+++ b/src/wp-admin/js/revisions.js
@@ -0,0 +1,1080 @@
+window.wp = window.wp || {};
+
+(function($) {
+ var revisions;
+
+ revisions = wp.revisions = { model: {}, view: {}, controller: {} };
+
+ // Link settings.
+ revisions.settings = _.isUndefined( _wpRevisionsSettings ) ? {} : _wpRevisionsSettings;
+
+ // For debugging
+ revisions.debug = false;
+
+ revisions.log = function() {
+ if ( window.console && revisions.debug )
+ console.log.apply( console, arguments );
+ };
+
+ // Handy functions to help with positioning
+ $.fn.allOffsets = function() {
+ var offset = this.offset() || {top: 0, left: 0}, win = $(window);
+ return _.extend( offset, {
+ right: win.width() - offset.left - this.outerWidth(),
+ bottom: win.height() - offset.top - this.outerHeight()
+ });
+ };
+
+ $.fn.allPositions = function() {
+ var position = this.position() || {top: 0, left: 0}, parent = this.parent();
+ return _.extend( position, {
+ right: parent.outerWidth() - position.left - this.outerWidth(),
+ bottom: parent.outerHeight() - position.top - this.outerHeight()
+ });
+ };
+
+ // wp_localize_script transforms top-level numbers into strings. Undo that.
+ if ( revisions.settings.to )
+ revisions.settings.to = parseInt( revisions.settings.to, 10 );
+ if ( revisions.settings.from )
+ revisions.settings.from = parseInt( revisions.settings.from, 10 );
+
+ // wp_localize_script does not allow for top-level booleans. Fix that.
+ if ( revisions.settings.compareTwoMode )
+ revisions.settings.compareTwoMode = revisions.settings.compareTwoMode === '1';
+
+ /**
+ * ========================================================================
+ * MODELS
+ * ========================================================================
+ */
+ revisions.model.Slider = Backbone.Model.extend({
+ defaults: {
+ value: null,
+ values: null,
+ min: 0,
+ max: 1,
+ step: 1,
+ range: false,
+ compareTwoMode: false
+ },
+
+ initialize: function( options ) {
+ this.frame = options.frame;
+ this.revisions = options.revisions;
+
+ // Listen for changes to the revisions or mode from outside
+ this.listenTo( this.frame, 'update:revisions', this.receiveRevisions );
+ this.listenTo( this.frame, 'change:compareTwoMode', this.updateMode );
+
+ // Listen for internal changes
+ this.listenTo( this, 'change:from', this.handleLocalChanges );
+ this.listenTo( this, 'change:to', this.handleLocalChanges );
+ this.listenTo( this, 'change:compareTwoMode', this.updateSliderSettings );
+ this.listenTo( this, 'update:revisions', this.updateSliderSettings );
+
+ // Listen for changes to the hovered revision
+ this.listenTo( this, 'change:hoveredRevision', this.hoverRevision );
+
+ this.set({
+ max: this.revisions.length - 1,
+ compareTwoMode: this.frame.get('compareTwoMode'),
+ from: this.frame.get('from'),
+ to: this.frame.get('to')
+ });
+ this.updateSliderSettings();
+ },
+
+ getSliderValue: function( a, b ) {
+ return isRtl ? this.revisions.length - this.revisions.indexOf( this.get(a) ) - 1 : this.revisions.indexOf( this.get(b) );
+ },
+
+ updateSliderSettings: function() {
+ if ( this.get('compareTwoMode') ) {
+ this.set({
+ values: [
+ this.getSliderValue( 'to', 'from' ),
+ this.getSliderValue( 'from', 'to' )
+ ],
+ value: null,
+ range: true // ensures handles cannot cross
+ });
+ } else {
+ this.set({
+ value: this.getSliderValue( 'to', 'to' ),
+ values: null,
+ range: false
+ });
+ }
+ this.trigger( 'update:slider' );
+ },
+
+ // Called when a revision is hovered
+ hoverRevision: function( model, value ) {
+ this.trigger( 'hovered:revision', value );
+ },
+
+ // Called when `compareTwoMode` changes
+ updateMode: function( model, value ) {
+ this.set({ compareTwoMode: value });
+ },
+
+ // Called when `from` or `to` changes in the local model
+ handleLocalChanges: function() {
+ this.frame.set({
+ from: this.get('from'),
+ to: this.get('to')
+ });
+ },
+
+ // Receives revisions changes from outside the model
+ receiveRevisions: function( from, to ) {
+ // Bail if nothing changed
+ if ( this.get('from') === from && this.get('to') === to )
+ return;
+
+ this.set({ from: from, to: to }, { silent: true });
+ this.trigger( 'update:revisions', from, to );
+ }
+
+ });
+
+ revisions.model.Tooltip = Backbone.Model.extend({
+ defaults: {
+ revision: null,
+ offset: {},
+ hovering: false, // Whether the mouse is hovering
+ scrubbing: false // Whether the mouse is scrubbing
+ },
+
+ initialize: function( options ) {
+ this.frame = options.frame;
+ this.revisions = options.revisions;
+ this.slider = options.slider;
+
+ this.listenTo( this.slider, 'hovered:revision', this.updateRevision );
+ this.listenTo( this.slider, 'change:hovering', this.setHovering );
+ this.listenTo( this.slider, 'change:scrubbing', this.setScrubbing );
+ },
+
+
+ updateRevision: function( revision ) {
+ this.set({ revision: revision });
+ },
+
+ setHovering: function( model, value ) {
+ this.set({ hovering: value });
+ },
+
+ setScrubbing: function( model, value ) {
+ this.set({ scrubbing: value });
+ }
+ });
+
+ revisions.model.Revision = Backbone.Model.extend({});
+
+ revisions.model.Revisions = Backbone.Collection.extend({
+ model: revisions.model.Revision,
+
+ initialize: function() {
+ _.bindAll( this, 'next', 'prev' );
+ },
+
+ next: function( revision ) {
+ var index = this.indexOf( revision );
+
+ if ( index !== -1 && index !== this.length - 1 )
+ return this.at( index + 1 );
+ },
+
+ prev: function( revision ) {
+ var index = this.indexOf( revision );
+
+ if ( index !== -1 && index !== 0 )
+ return this.at( index - 1 );
+ }
+ });
+
+ revisions.model.Field = Backbone.Model.extend({});
+
+ revisions.model.Fields = Backbone.Collection.extend({
+ model: revisions.model.Field
+ });
+
+ revisions.model.Diff = Backbone.Model.extend({
+ initialize: function( attributes, options ) {
+ var fields = this.get('fields');
+ this.unset('fields');
+
+ this.fields = new revisions.model.Fields( fields );
+ }
+ });
+
+ revisions.model.Diffs = Backbone.Collection.extend({
+ initialize: function( models, options ) {
+ _.bindAll( this, 'getClosestUnloaded' );
+ this.loadAll = _.once( this._loadAll );
+ this.revisions = options.revisions;
+ this.requests = {};
+ },
+
+ model: revisions.model.Diff,
+
+ ensure: function( id, context ) {
+ var diff = this.get( id );
+ var request = this.requests[ id ];
+ var deferred = $.Deferred();
+ var ids = {};
+ var from = id.split(':')[0];
+ var to = id.split(':')[1];
+ ids[id] = true;
+
+ wp.revisions.log( 'ensure', id );
+
+ this.trigger( 'ensure', ids, from, to, deferred.promise() );
+
+ if ( diff ) {
+ deferred.resolveWith( context, [ diff ] );
+ } else {
+ this.trigger( 'ensure:load', ids, from, to, deferred.promise() );
+ _.each( ids, _.bind( function( id ) {
+ // Remove anything that has an ongoing request
+ if ( this.requests[ id ] )
+ delete ids[ id ];
+ // Remove anything we already have
+ if ( this.get( id ) )
+ delete ids[ id ];
+ }, this ) );
+ if ( ! request ) {
+ // Always include the ID that started this ensure
+ ids[ id ] = true;
+ request = this.load( _.keys( ids ) );
+ }
+
+ request.done( _.bind( function() {
+ deferred.resolveWith( context, [ this.get( id ) ] );
+ }, this ) ).fail( _.bind( function() {
+ deferred.reject();
+ }) );
+ }
+
+ return deferred.promise();
+ },
+
+ // Returns an array of proximal diffs
+ getClosestUnloaded: function( ids, centerId ) {
+ var self = this;
+ return _.chain([0].concat( ids )).initial().zip( ids ).sortBy( function( pair ) {
+ return Math.abs( centerId - pair[1] );
+ }).map( function( pair ) {
+ return pair.join(':');
+ }).filter( function( diffId ) {
+ return _.isUndefined( self.get( diffId ) ) && ! self.requests[ diffId ];
+ }).value();
+ },
+
+ _loadAll: function( allRevisionIds, centerId, num ) {
+ var self = this, deferred = $.Deferred();
+ diffs = _.first( this.getClosestUnloaded( allRevisionIds, centerId ), num );
+ if ( _.size( diffs ) > 0 ) {
+ this.load( diffs ).done( function() {
+ self._loadAll( allRevisionIds, centerId, num ).done( function() {
+ deferred.resolve();
+ });
+ }).fail( function() {
+ if ( 1 === num ) { // Already tried 1. This just isn't working. Give up.
+ deferred.reject();
+ } else { // Request fewer diffs this time
+ self._loadAll( allRevisionIds, centerId, Math.ceil( num / 2 ) ).done( function() {
+ deferred.resolve();
+ });
+ }
+ });
+ } else {
+ deferred.resolve();
+ }
+ return deferred;
+ },
+
+ load: function( comparisons ) {
+ wp.revisions.log( 'load', comparisons );
+ // Our collection should only ever grow, never shrink, so remove: false
+ return this.fetch({ data: { compare: comparisons }, remove: false }).done( function(){
+ wp.revisions.log( 'load:complete', comparisons );
+ });
+ },
+
+ sync: function( method, model, options ) {
+ if ( 'read' === method ) {
+ options = options || {};
+ options.context = this;
+ options.data = _.extend( options.data || {}, {
+ action: 'get-revision-diffs',
+ post_id: revisions.settings.postId
+ });
+
+ var deferred = wp.ajax.send( options );
+ var requests = this.requests;
+
+ // Record that we're requesting each diff.
+ if ( options.data.compare ) {
+ _.each( options.data.compare, function( id ) {
+ requests[ id ] = deferred;
+ });
+ }
+
+ // When the request completes, clear the stored request.
+ deferred.always( function() {
+ if ( options.data.compare ) {
+ _.each( options.data.compare, function( id ) {
+ delete requests[ id ];
+ });
+ }
+ });
+
+ return deferred;
+
+ // Otherwise, fall back to `Backbone.sync()`.
+ } else {
+ return Backbone.Model.prototype.sync.apply( this, arguments );
+ }
+ }
+ });
+
+
+ revisions.model.FrameState = Backbone.Model.extend({
+ defaults: {
+ loading: false,
+ error: false,
+ compareTwoMode: false
+ },
+
+ initialize: function( attributes, options ) {
+ var properties = {};
+
+ _.bindAll( this, 'receiveDiff' );
+ this._debouncedEnsureDiff = _.debounce( this._ensureDiff, 200 );
+
+ this.revisions = options.revisions;
+ this.diffs = new revisions.model.Diffs( [], { revisions: this.revisions });
+
+ // Set the initial diffs collection provided through the settings
+ this.diffs.set( revisions.settings.diffData );
+
+ // Set up internal listeners
+ this.listenTo( this, 'change:from', this.changeRevisionHandler );
+ this.listenTo( this, 'change:to', this.changeRevisionHandler );
+ this.listenTo( this, 'change:compareTwoMode', this.changeMode );
+ this.listenTo( this, 'update:revisions', this.updatedRevisions );
+ this.listenTo( this.diffs, 'ensure:load', this.updateLoadingStatus );
+ this.listenTo( this, 'update:diff', this.updateLoadingStatus );
+
+ // Set the initial revisions, baseUrl, and mode as provided through settings
+ properties.to = this.revisions.get( revisions.settings.to );
+ properties.from = this.revisions.get( revisions.settings.from );
+ properties.compareTwoMode = revisions.settings.compareTwoMode;
+ properties.baseUrl = revisions.settings.baseUrl;
+ this.set( properties );
+
+ // Start the router if browser supports History API
+ if ( window.history && window.history.pushState ) {
+ this.router = new revisions.Router({ model: this });
+ Backbone.history.start({ pushState: true });
+ }
+ },
+
+ updateLoadingStatus: function() {
+ this.set( 'error', false );
+ this.set( 'loading', ! this.diff() );
+ },
+
+ changeMode: function( model, value ) {
+ // If we were on the first revision before switching, we have to bump them over one
+ if ( value && 0 === this.revisions.indexOf( this.get('to') ) ) {
+ this.set({
+ from: this.revisions.at(0),
+ to: this.revisions.at(1)
+ });
+ }
+ },
+
+ updatedRevisions: function( from, to ) {
+ if ( this.get( 'compareTwoMode' ) ) {
+ // TODO: compare-two loading strategy
+ } else {
+ this.diffs.loadAll( this.revisions.pluck('id'), to.id, 40 );
+ }
+ },
+
+ // Fetch the currently loaded diff.
+ diff: function() {
+ return this.diffs.get( this._diffId );
+ },
+
+ // So long as `from` and `to` are changed at the same time, the diff
+ // will only be updated once. This is because Backbone updates all of
+ // the changed attributes in `set`, and then fires the `change` events.
+ updateDiff: function( options ) {
+ var from, to, diffId, diff;
+
+ options = options || {};
+ from = this.get('from');
+ to = this.get('to');
+ diffId = ( from ? from.id : 0 ) + ':' + to.id;
+
+ // Check if we're actually changing the diff id.
+ if ( this._diffId === diffId )
+ return $.Deferred().reject().promise();
+
+ this._diffId = diffId;
+ this.trigger( 'update:revisions', from, to );
+
+ diff = this.diffs.get( diffId );
+
+ // If we already have the diff, then immediately trigger the update.
+ if ( diff ) {
+ this.receiveDiff( diff );
+ return $.Deferred().resolve().promise();
+ // Otherwise, fetch the diff.
+ } else {
+ if ( options.immediate ) {
+ return this._ensureDiff();
+ } else {
+ this._debouncedEnsureDiff();
+ return $.Deferred().reject().promise();
+ }
+ }
+ },
+
+ // A simple wrapper around `updateDiff` to prevent the change event's
+ // parameters from being passed through.
+ changeRevisionHandler: function( model, value, options ) {
+ this.updateDiff();
+ },
+
+ receiveDiff: function( diff ) {
+ // Did we actually get a diff?
+ if ( _.isUndefined( diff ) || _.isUndefined( diff.id ) ) {
+ this.set({
+ loading: false,
+ error: true
+ });
+ } else if ( this._diffId === diff.id ) { // Make sure the current diff didn't change
+ this.trigger( 'update:diff', diff );
+ }
+ },
+
+ _ensureDiff: function() {
+ return this.diffs.ensure( this._diffId, this ).always( this.receiveDiff );
+ }
+ });
+
+
+ /**
+ * ========================================================================
+ * VIEWS
+ * ========================================================================
+ */
+
+ // The frame view. This contains the entire page.
+ revisions.view.Frame = wp.Backbone.View.extend({
+ className: 'revisions',
+ template: wp.template('revisions-frame'),
+
+ initialize: function() {
+ this.listenTo( this.model, 'update:diff', this.renderDiff );
+ this.listenTo( this.model, 'change:compareTwoMode', this.updateCompareTwoMode );
+ this.listenTo( this.model, 'change:loading', this.updateLoadingStatus );
+ this.listenTo( this.model, 'change:error', this.updateErrorStatus );
+
+ this.views.set( '.revisions-control-frame', new revisions.view.Controls({
+ model: this.model
+ }) );
+ },
+
+ render: function() {
+ wp.Backbone.View.prototype.render.apply( this, arguments );
+
+ $('html').css( 'overflow-y', 'scroll' );
+ $('#wpbody-content .wrap').append( this.el );
+ this.updateCompareTwoMode();
+ this.renderDiff( this.model.diff() );
+ this.views.ready();
+
+ return this;
+ },
+
+ renderDiff: function( diff ) {
+ this.views.set( '.revisions-diff-frame', new revisions.view.Diff({
+ model: diff
+ }) );
+ },
+
+ updateLoadingStatus: function() {
+ this.$el.toggleClass( 'loading', this.model.get('loading') );
+ },
+
+ updateErrorStatus: function() {
+ this.$el.toggleClass( 'diff-error', this.model.get('error') );
+ },
+
+ updateCompareTwoMode: function() {
+ this.$el.toggleClass( 'comparing-two-revisions', this.model.get('compareTwoMode') );
+ }
+ });
+
+ // The control view.
+ // This contains the revision slider, previous/next buttons, the meta info and the compare checkbox.
+ revisions.view.Controls = wp.Backbone.View.extend({
+ className: 'revisions-controls',
+
+ initialize: function() {
+ _.bindAll( this, 'setWidth' );
+
+ // Add the button view
+ this.views.add( new revisions.view.Buttons({
+ model: this.model
+ }) );
+
+ // Add the checkbox view
+ this.views.add( new revisions.view.Checkbox({
+ model: this.model
+ }) );
+
+ // Prep the slider model
+ var slider = new revisions.model.Slider({
+ frame: this.model,
+ revisions: this.model.revisions
+ });
+
+ // Prep the tooltip model
+ var tooltip = new revisions.model.Tooltip({
+ frame: this.model,
+ revisions: this.model.revisions,
+ slider: slider
+ });
+
+ // Add the tooltip view
+ this.views.add( new revisions.view.Tooltip({
+ model: tooltip
+ }) );
+
+ // Add the tickmarks view
+ this.views.add( new revisions.view.Tickmarks({
+ model: tooltip
+ }) );
+
+ // Add the slider view
+ this.views.add( new revisions.view.Slider({
+ model: slider
+ }) );
+
+ // Add the Metabox view
+ this.views.add( new revisions.view.Metabox({
+ model: this.model
+ }) );
+ },
+
+ ready: function() {
+ this.top = this.$el.offset().top;
+ this.window = $(window);
+ this.window.on( 'scroll.wp.revisions', {controls: this}, function(e) {
+ var controls = e.data.controls;
+ var container = controls.$el.parent();
+ var scrolled = controls.window.scrollTop();
+ var frame = controls.views.parent;
+
+ if ( scrolled >= controls.top ) {
+ if ( ! frame.$el.hasClass('pinned') ) {
+ controls.setWidth();
+ container.css('height', container.height() + 'px' );
+ controls.window.on('resize.wp.revisions.pinning click.wp.revisions.pinning', {controls: controls}, function(e) {
+ e.data.controls.setWidth();
+ });
+ }
+ frame.$el.addClass('pinned');
+ } else if ( frame.$el.hasClass('pinned') ) {
+ controls.window.off('.wp.revisions.pinning');
+ controls.$el.css('width', 'auto');
+ frame.$el.removeClass('pinned');
+ container.css('height', 'auto');
+ controls.top = controls.$el.offset().top;
+ } else {
+ controls.top = controls.$el.offset().top;
+ }
+ });
+ },
+
+ setWidth: function() {
+ this.$el.css('width', this.$el.parent().width() + 'px');
+ }
+ });
+
+ // The tickmarks view
+ revisions.view.Tickmarks = wp.Backbone.View.extend({
+ className: 'revisions-tickmarks',
+ direction: isRtl ? 'right' : 'left',
+
+ initialize: function() {
+ this.listenTo( this.model, 'change:revision', this.reportTickPosition );
+ },
+
+ reportTickPosition: function( model, revision ) {
+ var offset, thisOffset, parentOffset, tick, index = this.model.revisions.indexOf( revision );
+ thisOffset = this.$el.allOffsets();
+ parentOffset = this.$el.parent().allOffsets();
+ if ( index === this.model.revisions.length - 1 ) {
+ // Last one
+ offset = {
+ rightPlusWidth: thisOffset.left - parentOffset.left + 1,
+ leftPlusWidth: thisOffset.right - parentOffset.right + 1
+ };
+ } else {
+ // Normal tick
+ tick = this.$('div:nth-of-type(' + (index + 1) + ')');
+ offset = tick.allPositions();
+ _.extend( offset, {
+ left: offset.left + thisOffset.left - parentOffset.left,
+ right: offset.right + thisOffset.right - parentOffset.right
+ });
+ _.extend( offset, {
+ leftPlusWidth: offset.left + tick.outerWidth(),
+ rightPlusWidth: offset.right + tick.outerWidth()
+ });
+ }
+ this.model.set({ offset: offset });
+ },
+
+ ready: function() {
+ var tickCount, tickWidth;
+ tickCount = this.model.revisions.length - 1;
+ tickWidth = 1 / tickCount;
+ this.$el.css('width', ( this.model.revisions.length * 50 ) + 'px');
+
+ _(tickCount).times( function( index ){
+ this.$el.append( '<div style="' + this.direction + ': ' + ( 100 * tickWidth * index ) + '%"></div>' );
+ }, this );
+ }
+ });
+
+ // The metabox view
+ revisions.view.Metabox = wp.Backbone.View.extend({
+ className: 'revisions-meta',
+
+ initialize: function() {
+ // Add the 'from' view
+ this.views.add( new revisions.view.MetaFrom({
+ model: this.model,
+ className: 'diff-meta diff-meta-from'
+ }) );
+
+ // Add the 'to' view
+ this.views.add( new revisions.view.MetaTo({
+ model: this.model
+ }) );
+ }
+ });
+
+ // The revision meta view (to be extended)
+ revisions.view.Meta = wp.Backbone.View.extend({
+ template: wp.template('revisions-meta'),
+
+ events: {
+ 'click .restore-revision': 'restoreRevision'
+ },
+
+ initialize: function() {
+ this.listenTo( this.model, 'update:revisions', this.render );
+ },
+
+ prepare: function() {
+ return _.extend( this.model.toJSON()[this.type] || {}, {
+ type: this.type
+ });
+ },
+
+ restoreRevision: function() {
+ document.location = this.model.get('to').attributes.restoreUrl;
+ }
+ });
+
+ // The revision meta 'from' view
+ revisions.view.MetaFrom = revisions.view.Meta.extend({
+ className: 'diff-meta diff-meta-from',
+ type: 'from'
+ });
+
+ // The revision meta 'to' view
+ revisions.view.MetaTo = revisions.view.Meta.extend({
+ className: 'diff-meta diff-meta-to',
+ type: 'to'
+ });
+
+ // The checkbox view.
+ revisions.view.Checkbox = wp.Backbone.View.extend({
+ className: 'revisions-checkbox',
+ template: wp.template('revisions-checkbox'),
+
+ events: {
+ 'click .compare-two-revisions': 'compareTwoToggle'
+ },
+
+ initialize: function() {
+ this.listenTo( this.model, 'change:compareTwoMode', this.updateCompareTwoMode );
+ },
+
+ ready: function() {
+ if ( this.model.revisions.length < 3 )
+ $('.revision-toggle-compare-mode').hide();
+ },
+
+ updateCompareTwoMode: function() {
+ this.$('.compare-two-revisions').prop( 'checked', this.model.get('compareTwoMode') );
+ },
+
+ // Toggle the compare two mode feature when the compare two checkbox is checked.
+ compareTwoToggle: function( event ) {
+ // Activate compare two mode?
+ this.model.set({ compareTwoMode: $('.compare-two-revisions').prop('checked') });
+ }
+ });
+
+ // The tooltip view.
+ // Encapsulates the tooltip.
+ revisions.view.Tooltip = wp.Backbone.View.extend({
+ className: 'revisions-tooltip',
+ template: wp.template('revisions-meta'),
+
+ initialize: function( options ) {
+ this.listenTo( this.model, 'change:offset', this.render );
+ this.listenTo( this.model, 'change:hovering', this.toggleVisibility );
+ this.listenTo( this.model, 'change:scrubbing', this.toggleVisibility );
+ },
+
+ prepare: function() {
+ if ( _.isNull( this.model.get('revision') ) )
+ return;
+ else
+ return _.extend( { type: 'tooltip' }, {
+ attributes: this.model.get('revision').toJSON()
+ });
+ },
+
+ render: function() {
+ var direction, directionVal, flipped, css = {}, position = this.model.revisions.indexOf( this.model.get('revision') ) + 1;
+ flipped = ( position / this.model.revisions.length ) > 0.5;
+ if ( isRtl ) {
+ direction = flipped ? 'left' : 'right';
+ directionVal = flipped ? 'leftPlusWidth' : direction;
+ } else {
+ direction = flipped ? 'right' : 'left';
+ directionVal = flipped ? 'rightPlusWidth' : direction;
+ }
+ otherDirection = 'right' === direction ? 'left': 'right';
+ wp.Backbone.View.prototype.render.apply( this, arguments );
+ css[direction] = this.model.get('offset')[directionVal] + 'px';
+ css[otherDirection] = '';
+ this.$el.toggleClass( 'flipped', flipped ).css( css );
+ },
+
+ visible: function() {
+ return this.model.get( 'scrubbing' ) || this.model.get( 'hovering' );
+ },
+
+ toggleVisibility: function( options ) {
+ if ( this.visible() )
+ this.$el.stop().show().fadeTo( 100 - this.el.style.opacity * 100, 1 );
+ else
+ this.$el.stop().fadeTo( this.el.style.opacity * 300, 0, function(){ $(this).hide(); } );
+ return;
+ }
+ });
+
+ // The buttons view.
+ // Encapsulates all of the configuration for the previous/next buttons.
+ revisions.view.Buttons = wp.Backbone.View.extend({
+ className: 'revisions-buttons',
+ template: wp.template('revisions-buttons'),
+
+ events: {
+ 'click .revisions-next .button': 'nextRevision',
+ 'click .revisions-previous .button': 'previousRevision'
+ },
+
+ initialize: function() {
+ this.listenTo( this.model, 'update:revisions', this.disabledButtonCheck );
+ },
+
+ ready: function() {
+ this.disabledButtonCheck();
+ },
+
+ // Go to a specific model index
+ gotoModel: function( toIndex ) {
+ var attributes = {
+ to: this.model.revisions.at( toIndex )
+ };
+ // If we're at the first revision, unset 'from'.
+ if ( toIndex )
+ attributes.from = this.model.revisions.at( toIndex - 1 );
+ else
+ this.model.unset('from', { silent: true });
+
+ this.model.set( attributes );
+ },
+
+ // Go to the 'next' revision
+ nextRevision: function() {
+ var toIndex = this.model.revisions.indexOf( this.model.get('to') ) + 1;
+ this.gotoModel( toIndex );
+ },
+
+ // Go to the 'previous' revision
+ previousRevision: function() {
+ var toIndex = this.model.revisions.indexOf( this.model.get('to') ) - 1;
+ this.gotoModel( toIndex );
+ },
+
+ // Check to see if the Previous or Next buttons need to be disabled or enabled.
+ disabledButtonCheck: function() {
+ var maxVal = this.model.revisions.length - 1,
+ minVal = 0,
+ next = $('.revisions-next .button'),
+ previous = $('.revisions-previous .button'),
+ val = this.model.revisions.indexOf( this.model.get('to') );
+
+ // Disable "Next" button if you're on the last node.
+ next.prop( 'disabled', ( maxVal === val ) );
+
+ // Disable "Previous" button if you're on the first node.
+ previous.prop( 'disabled', ( minVal === val ) );
+ }
+ });
+
+
+ // The slider view.
+ revisions.view.Slider = wp.Backbone.View.extend({
+ className: 'wp-slider',
+ direction: isRtl ? 'right' : 'left',
+
+ events: {
+ 'mousemove' : 'mouseMove'
+ },
+
+ initialize: function() {
+ _.bindAll( this, 'start', 'slide', 'stop', 'mouseMove', 'mouseEnter', 'mouseLeave' );
+ this.listenTo( this.model, 'update:slider', this.applySliderSettings );
+ },
+
+ ready: function() {
+ this.$el.css('width', ( this.model.revisions.length * 50 ) + 'px');
+ this.$el.slider( _.extend( this.model.toJSON(), {
+ start: this.start,
+ slide: this.slide,
+ stop: this.stop
+ }) );
+
+ this.$el.hoverIntent({
+ over: this.mouseEnter,
+ out: this.mouseLeave,
+ timeout: 800
+ });
+
+ this.applySliderSettings();
+ },
+
+ mouseMove: function( e ) {
+ var zoneCount = this.model.revisions.length - 1, // One fewer zone than models
+ sliderFrom = this.$el.allOffsets()[this.direction], // "From" edge of slider
+ sliderWidth = this.$el.width(), // Width of slider
+ tickWidth = sliderWidth / zoneCount, // Calculated width of zone
+ actualX = isRtl? $(window).width() - e.pageX : e.pageX; // Flipped for RTL - sliderFrom;
+ actualX = actualX - sliderFrom; // Offset of mouse position in slider
+ var currentModelIndex = Math.floor( ( actualX + ( tickWidth / 2 ) ) / tickWidth ); // Calculate the model index
+
+ // Ensure sane value for currentModelIndex.
+ if ( currentModelIndex < 0 )
+ currentModelIndex = 0;
+ else if ( currentModelIndex >= this.model.revisions.length )
+ currentModelIndex = this.model.revisions.length - 1;
+
+ // Update the tooltip mode
+ this.model.set({ hoveredRevision: this.model.revisions.at( currentModelIndex ) });
+ },
+
+ mouseLeave: function() {
+ this.model.set({ hovering: false });
+ },
+
+ mouseEnter: function() {
+ this.model.set({ hovering: true });
+ },
+
+ applySliderSettings: function() {
+ this.$el.slider( _.pick( this.model.toJSON(), 'value', 'values', 'range' ) );
+ var handles = this.$('a.ui-slider-handle');
+
+ if ( this.model.get('compareTwoMode') ) {
+ // in RTL mode the 'left handle' is the second in the slider, 'right' is first
+ handles.first()
+ .toggleClass( 'to-handle', !! isRtl )
+ .toggleClass( 'from-handle', ! isRtl );
+ handles.last()
+ .toggleClass( 'from-handle', !! isRtl )
+ .toggleClass( 'to-handle', ! isRtl );
+ } else {
+ handles.removeClass('from-handle to-handle');
+ }
+ },
+
+ start: function( event, ui ) {
+ this.model.set({ scrubbing: true });
+
+ // Track the mouse position to enable smooth dragging,
+ // overrides default jQuery UI step behavior.
+ $( window ).on( 'mousemove.wp.revisions', { view: this }, function( e ) {
+ var view = e.data.view,
+ leftDragBoundary = view.$el.offset().left,
+ sliderOffset = leftDragBoundary,
+ sliderRightEdge = leftDragBoundary + view.$el.width(),
+ rightDragBoundary = sliderRightEdge,
+ leftDragReset = '0',
+ rightDragReset = '100%',
+ handle = $( ui.handle );
+
+ // In two handle mode, ensure handles can't be dragged past each other.
+ // Adjust left/right boundaries and reset points.
+ if ( view.model.get('compareTwoMode') ) {
+ var handles = handle.parent().find('.ui-slider-handle');
+ if ( handle.is( handles.first() ) ) { // We're the left handle
+ rightDragBoundary = handles.last().offset().left;
+ rightDragReset = rightDragBoundary - sliderOffset;
+ } else { // We're the right handle
+ leftDragBoundary = handles.first().offset().left + handles.first().width();
+ leftDragReset = leftDragBoundary - sliderOffset;
+ }
+ }
+
+ // Follow mouse movements, as long as handle remains inside slider.
+ if ( e.pageX < leftDragBoundary ) {
+ handle.css( 'left', leftDragReset ); // Mouse to left of slider.
+ } else if ( e.pageX > rightDragBoundary ) {
+ handle.css( 'left', rightDragReset ); // Mouse to right of slider.
+ } else {
+ handle.css( 'left', e.pageX - sliderOffset ); // Mouse in slider.
+ }
+ } );
+ },
+
+ getPosition: function( position ) {
+ return isRtl ? this.model.revisions.length - position - 1: position;
+ },
+
+ // Responds to slide events
+ slide: function( event, ui ) {
+ var attributes, movedRevision;
+ // Compare two revisions mode
+ if ( this.model.get('compareTwoMode') ) {
+ // Prevent sliders from occupying same spot
+ if ( ui.values[1] === ui.values[0] )
+ return false;
+ if ( isRtl )
+ ui.values.reverse();
+ attributes = {
+ from: this.model.revisions.at( this.getPosition( ui.values[0] ) ),
+ to: this.model.revisions.at( this.getPosition( ui.values[1] ) )
+ };
+ } else {
+ attributes = {
+ to: this.model.revisions.at( this.getPosition( ui.value ) )
+ };
+ // If we're at the first revision, unset 'from'.
+ if ( this.getPosition( ui.value ) > 0 )
+ attributes.from = this.model.revisions.at( this.getPosition( ui.value ) - 1 );
+ else
+ attributes.from = undefined;
+ }
+ movedRevision = this.model.revisions.at( this.getPosition( ui.value ) );
+
+ // If we are scrubbing, a scrub to a revision is considered a hover
+ if ( this.model.get('scrubbing') )
+ attributes.hoveredRevision = movedRevision;
+
+ this.model.set( attributes );
+ },
+
+ stop: function( event, ui ) {
+ $( window ).off('mousemove.wp.revisions');
+ this.model.updateSliderSettings(); // To snap us back to a tick mark
+ this.model.set({ scrubbing: false });
+ }
+ });
+
+ // The diff view.
+ // This is the view for the current active diff.
+ revisions.view.Diff = wp.Backbone.View.extend({
+ className: 'revisions-diff',
+ template: wp.template('revisions-diff'),
+
+ // Generate the options to be passed to the template.
+ prepare: function() {
+ return _.extend({ fields: this.model.fields.toJSON() }, this.options );
+ }
+ });
+
+ // The revisions router
+ // takes URLs with #hash fragments and routes them
+ revisions.Router = Backbone.Router.extend({
+ initialize: function( options ) {
+ this.model = options.model;
+ this.routes = _.object([
+ [ this.baseUrl( '?from=:from&to=:to' ), 'handleRoute' ],
+ [ this.baseUrl( '?from=:from&to=:to' ), 'handleRoute' ]
+ ]);
+ // Maintain state and history when navigating
+ this.listenTo( this.model, 'update:diff', _.debounce( this.updateUrl, 250 ) );
+ this.listenTo( this.model, 'change:compareTwoMode', this.updateUrl );
+ },
+
+ baseUrl: function( url ) {
+ return this.model.get('baseUrl') + url;
+ },
+
+ updateUrl: function() {
+ var from = this.model.has('from') ? this.model.get('from').id : 0;
+ var to = this.model.get('to').id;
+ if ( this.model.get('compareTwoMode' ) )
+ this.navigate( this.baseUrl( '?from=' + from + '&to=' + to ) );
+ else
+ this.navigate( this.baseUrl( '?revision=' + to ) );
+ },
+
+ handleRoute: function( a, b ) {
+ var from, to, compareTwo = _.isUndefined( b );
+
+ if ( ! compareTwo ) {
+ b = this.model.revisions.get( a );
+ a = this.model.revisions.prev( b );
+ b = b ? b.id : 0;
+ a = a ? a.id : 0;
+ }
+
+ this.model.set({
+ from: this.model.revisions.get( parseInt( a, 10 ) ),
+ to: this.model.revisions.get( parseInt( a, 10 ) ),
+ compareTwoMode: compareTwo
+ });
+ }
+ });
+
+ // Initialize the revisions UI.
+ revisions.init = function() {
+ revisions.view.frame = new revisions.view.Frame({
+ model: new revisions.model.FrameState({}, {
+ revisions: new revisions.model.Revisions( revisions.settings.revisionData )
+ })
+ }).render();
+ };
+
+ $( revisions.init );
+}(jQuery));
diff --git a/src/wp-admin/js/set-post-thumbnail.js b/src/wp-admin/js/set-post-thumbnail.js
new file mode 100644
index 0000000000..e6ac87542c
--- /dev/null
+++ b/src/wp-admin/js/set-post-thumbnail.js
@@ -0,0 +1,21 @@
+function WPSetAsThumbnail(id, nonce){
+ var $link = jQuery('a#wp-post-thumbnail-' + id);
+
+ $link.text( setPostThumbnailL10n.saving );
+ jQuery.post(ajaxurl, {
+ action:"set-post-thumbnail", post_id: post_id, thumbnail_id: id, _ajax_nonce: nonce, cookie: encodeURIComponent(document.cookie)
+ }, function(str){
+ var win = window.dialogArguments || opener || parent || top;
+ $link.text( setPostThumbnailL10n.setThumbnail );
+ if ( str == '0' ) {
+ alert( setPostThumbnailL10n.error );
+ } else {
+ jQuery('a.wp-post-thumbnail').show();
+ $link.text( setPostThumbnailL10n.done );
+ $link.fadeOut( 2000 );
+ win.WPSetThumbnailID(id);
+ win.WPSetThumbnailHTML(str);
+ }
+ }
+ );
+}
diff --git a/src/wp-admin/js/tags.js b/src/wp-admin/js/tags.js
new file mode 100644
index 0000000000..c403ad8c24
--- /dev/null
+++ b/src/wp-admin/js/tags.js
@@ -0,0 +1,68 @@
+jQuery(document).ready(function($) {
+
+ $('#the-list').on('click', '.delete-tag', function(e){
+ var t = $(this), tr = t.parents('tr'), r = true, data;
+ if ( 'undefined' != showNotice )
+ r = showNotice.warn();
+ if ( r ) {
+ data = t.attr('href').replace(/[^?]*\?/, '').replace(/action=delete/, 'action=delete-tag');
+ $.post(ajaxurl, data, function(r){
+ if ( '1' == r ) {
+ $('#ajax-response').empty();
+ tr.fadeOut('normal', function(){ tr.remove(); });
+ // Remove the term from the parent box and tag cloud
+ $('select#parent option[value="' + data.match(/tag_ID=(\d+)/)[1] + '"]').remove();
+ $('a.tag-link-' + data.match(/tag_ID=(\d+)/)[1]).remove();
+ } else if ( '-1' == r ) {
+ $('#ajax-response').empty().append('<div class="error"><p>' + tagsl10n.noPerm + '</p></div>');
+ tr.children().css('backgroundColor', '');
+ } else {
+ $('#ajax-response').empty().append('<div class="error"><p>' + tagsl10n.broken + '</p></div>');
+ tr.children().css('backgroundColor', '');
+ }
+ });
+ tr.children().css('backgroundColor', '#f33');
+ }
+ return false;
+ });
+
+ $('#submit').click(function(){
+ var form = $(this).parents('form');
+
+ if ( !validateForm( form ) )
+ return false;
+
+ $.post(ajaxurl, $('#addtag').serialize(), function(r){
+ $('#ajax-response').empty();
+ var res = wpAjax.parseAjaxResponse(r, 'ajax-response');
+ if ( ! res || res.errors )
+ return;
+
+ var parent = form.find('select#parent').val();
+
+ if ( parent > 0 && $('#tag-' + parent ).length > 0 ) // If the parent exists on this page, insert it below. Else insert it at the top of the list.
+ $('.tags #tag-' + parent).after( res.responses[0].supplemental['noparents'] ); // As the parent exists, Insert the version with - - - prefixed
+ else
+ $('.tags').prepend( res.responses[0].supplemental['parents'] ); // As the parent is not visible, Insert the version with Parent - Child - ThisTerm
+
+ $('.tags .no-items').remove();
+
+ if ( form.find('select#parent') ) {
+ // Parents field exists, Add new term to the list.
+ var term = res.responses[1].supplemental;
+
+ // Create an indent for the Parent field
+ var indent = '';
+ for ( var i = 0; i < res.responses[1].position; i++ )
+ indent += '&nbsp;&nbsp;&nbsp;';
+
+ form.find('select#parent option:selected').after('<option value="' + term['term_id'] + '">' + indent + term['name'] + '</option>');
+ }
+
+ $('input[type="text"]:visible, textarea:visible', form).val('');
+ });
+
+ return false;
+ });
+
+});
diff --git a/src/wp-admin/js/theme-preview.js b/src/wp-admin/js/theme-preview.js
new file mode 100644
index 0000000000..b7959c501f
--- /dev/null
+++ b/src/wp-admin/js/theme-preview.js
@@ -0,0 +1,56 @@
+
+var thickDims, tbWidth, tbHeight;
+jQuery(document).ready(function($) {
+
+ thickDims = function() {
+ var tbWindow = $('#TB_window'), H = $(window).height(), W = $(window).width(), w, h;
+
+ w = (tbWidth && tbWidth < W - 90) ? tbWidth : W - 90;
+ h = (tbHeight && tbHeight < H - 60) ? tbHeight : H - 60;
+
+ if ( tbWindow.size() ) {
+ tbWindow.width(w).height(h);
+ $('#TB_iframeContent').width(w).height(h - 27);
+ tbWindow.css({'margin-left': '-' + parseInt((w / 2),10) + 'px'});
+ if ( typeof document.body.style.maxWidth != 'undefined' )
+ tbWindow.css({'top':'30px','margin-top':'0'});
+ }
+ };
+
+ thickDims();
+ $(window).resize( function() { thickDims() } );
+
+ $('a.thickbox-preview').click( function() {
+ tb_click.call(this);
+
+ var alink = $(this).parents('.available-theme').find('.activatelink'), link = '', href = $(this).attr('href'), url, text;
+
+ if ( tbWidth = href.match(/&tbWidth=[0-9]+/) )
+ tbWidth = parseInt(tbWidth[0].replace(/[^0-9]+/g, ''), 10);
+ else
+ tbWidth = $(window).width() - 90;
+
+ if ( tbHeight = href.match(/&tbHeight=[0-9]+/) )
+ tbHeight = parseInt(tbHeight[0].replace(/[^0-9]+/g, ''), 10);
+ else
+ tbHeight = $(window).height() - 60;
+
+ if ( alink.length ) {
+ url = alink.attr('href') || '';
+ text = alink.attr('title') || '';
+ link = '&nbsp; <a href="' + url + '" target="_top" class="tb-theme-preview-link">' + text + '</a>';
+ } else {
+ text = $(this).attr('title') || '';
+ link = '&nbsp; <span class="tb-theme-preview-link">' + text + '</span>';
+ }
+
+ $('#TB_title').css({'background-color':'#222','color':'#dfdfdf'});
+ $('#TB_closeAjaxWindow').css({'float':'left'});
+ $('#TB_ajaxWindowTitle').css({'float':'right'}).html(link);
+
+ $('#TB_iframeContent').width('100%');
+ thickDims();
+
+ return false;
+ } );
+});
diff --git a/src/wp-admin/js/theme.js b/src/wp-admin/js/theme.js
new file mode 100644
index 0000000000..0899ab72f0
--- /dev/null
+++ b/src/wp-admin/js/theme.js
@@ -0,0 +1,279 @@
+/**
+ * Theme Browsing
+ *
+ * Controls visibility of theme details on manage and install themes pages.
+ */
+jQuery( function($) {
+ $('#availablethemes').on( 'click', '.theme-detail', function (event) {
+ var theme = $(this).closest('.available-theme'),
+ details = theme.find('.themedetaildiv');
+
+ if ( ! details.length ) {
+ details = theme.find('.install-theme-info .theme-details');
+ details = details.clone().addClass('themedetaildiv').appendTo( theme ).hide();
+ }
+
+ details.toggle();
+ event.preventDefault();
+ });
+});
+
+/**
+ * Theme Browser Thickbox
+ *
+ * Aligns theme browser thickbox.
+ */
+var tb_position;
+jQuery(document).ready( function($) {
+ tb_position = function() {
+ var tbWindow = $('#TB_window'), width = $(window).width(), H = $(window).height(), W = ( 1040 < width ) ? 1040 : width, adminbar_height = 0;
+
+ if ( $('body.admin-bar').length )
+ adminbar_height = 28;
+
+ if ( tbWindow.size() ) {
+ tbWindow.width( W - 50 ).height( H - 45 - adminbar_height );
+ $('#TB_iframeContent').width( W - 50 ).height( H - 75 - adminbar_height );
+ tbWindow.css({'margin-left': '-' + parseInt( ( ( W - 50 ) / 2 ), 10 ) + 'px'});
+ if ( typeof document.body.style.maxWidth != 'undefined' )
+ tbWindow.css({'top': 20 + adminbar_height + 'px','margin-top':'0'});
+ };
+ };
+
+ $(window).resize(function(){ tb_position(); });
+});
+
+/**
+ * Theme Install
+ *
+ * Displays theme previews on theme install pages.
+ */
+jQuery( function($) {
+ if( ! window.postMessage )
+ return;
+
+ var preview = $('#theme-installer'),
+ info = preview.find('.install-theme-info'),
+ panel = preview.find('.wp-full-overlay-main'),
+ body = $( document.body );
+
+ preview.on( 'click', '.close-full-overlay', function( event ) {
+ preview.fadeOut( 200, function() {
+ panel.empty();
+ body.removeClass('theme-installer-active full-overlay-active');
+ });
+ event.preventDefault();
+ });
+
+ preview.on( 'click', '.collapse-sidebar', function( event ) {
+ preview.toggleClass( 'collapsed' ).toggleClass( 'expanded' );
+ event.preventDefault();
+ });
+
+ $('#availablethemes').on( 'click', '.install-theme-preview', function( event ) {
+ var src;
+
+ info.html( $(this).closest('.installable-theme').find('.install-theme-info').html() );
+ src = info.find( '.theme-preview-url' ).val();
+ panel.html( '<iframe src="' + src + '" />');
+ preview.fadeIn( 200, function() {
+ body.addClass('theme-installer-active full-overlay-active');
+ });
+ event.preventDefault();
+ });
+});
+
+var ThemeViewer;
+
+(function($){
+ ThemeViewer = function( args ) {
+
+ function init() {
+ $( '#filter-click, #mini-filter-click' ).unbind( 'click' ).click( function() {
+ $( '#filter-click' ).toggleClass( 'current' );
+ $( '#filter-box' ).slideToggle();
+ $( '#current-theme' ).slideToggle( 300 );
+ return false;
+ });
+
+ $( '#filter-box :checkbox' ).unbind( 'click' ).click( function() {
+ var count = $( '#filter-box :checked' ).length,
+ text = $( '#filter-click' ).text();
+
+ if ( text.indexOf( '(' ) != -1 )
+ text = text.substr( 0, text.indexOf( '(' ) );
+
+ if ( count == 0 )
+ $( '#filter-click' ).text( text );
+ else
+ $( '#filter-click' ).text( text + ' (' + count + ')' );
+ });
+
+ /* $('#filter-box :submit').unbind( 'click' ).click(function() {
+ var features = [];
+ $('#filter-box :checked').each(function() {
+ features.push($(this).val());
+ });
+
+ listTable.update_rows({'features': features}, true, function() {
+ $( '#filter-click' ).toggleClass( 'current' );
+ $( '#filter-box' ).slideToggle();
+ $( '#current-theme' ).slideToggle( 300 );
+ });
+
+ return false;
+ }); */
+ }
+
+ // These are the functions we expose
+ var api = {
+ init: init
+ };
+
+ return api;
+ }
+})(jQuery);
+
+jQuery( document ).ready( function($) {
+ theme_viewer = new ThemeViewer();
+ theme_viewer.init();
+});
+
+
+/**
+ * Class that provides infinite scroll for Themes admin screens
+ *
+ * @since 3.4
+ *
+ * @uses ajaxurl
+ * @uses list_args
+ * @uses theme_list_args
+ * @uses $('#_ajax_fetch_list_nonce').val()
+* */
+var ThemeScroller;
+(function($){
+ ThemeScroller = {
+ querying: false,
+ scrollPollingDelay: 500,
+ failedRetryDelay: 4000,
+ outListBottomThreshold: 300,
+
+ /**
+ * Initializer
+ *
+ * @since 3.4
+ * @access private
+ */
+ init: function() {
+ var self = this;
+
+ // Get out early if we don't have the required arguments.
+ if ( typeof ajaxurl === 'undefined' ||
+ typeof list_args === 'undefined' ||
+ typeof theme_list_args === 'undefined' ) {
+ $('.pagination-links').show();
+ return;
+ }
+
+ // Handle inputs
+ this.nonce = $('#_ajax_fetch_list_nonce').val();
+ this.nextPage = ( theme_list_args.paged + 1 );
+
+ // Cache jQuery selectors
+ this.$outList = $('#availablethemes');
+ this.$spinner = $('div.tablenav.bottom').children( '.spinner' );
+ this.$window = $(window);
+ this.$document = $(document);
+
+ /**
+ * If there are more pages to query, then start polling to track
+ * when user hits the bottom of the current page
+ */
+ if ( theme_list_args.total_pages >= this.nextPage )
+ this.pollInterval =
+ setInterval( function() {
+ return self.poll();
+ }, this.scrollPollingDelay );
+ },
+
+ /**
+ * Checks to see if user has scrolled to bottom of page.
+ * If so, requests another page of content from self.ajax().
+ *
+ * @since 3.4
+ * @access private
+ */
+ poll: function() {
+ var bottom = this.$document.scrollTop() + this.$window.innerHeight();
+
+ if ( this.querying ||
+ ( bottom < this.$outList.height() - this.outListBottomThreshold ) )
+ return;
+
+ this.ajax();
+ },
+
+ /**
+ * Applies results passed from this.ajax() to $outList
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @param results Array with results from this.ajax() query.
+ */
+ process: function( results ) {
+ if ( results === undefined ) {
+ clearInterval( this.pollInterval );
+ return;
+ }
+
+ if ( this.nextPage > theme_list_args.total_pages )
+ clearInterval( this.pollInterval );
+
+ if ( this.nextPage <= ( theme_list_args.total_pages + 1 ) )
+ this.$outList.append( results.rows );
+ },
+
+ /**
+ * Queries next page of themes
+ *
+ * @since 3.4
+ * @access private
+ */
+ ajax: function() {
+ var self = this;
+
+ this.querying = true;
+
+ var query = {
+ action: 'fetch-list',
+ paged: this.nextPage,
+ s: theme_list_args.search,
+ tab: theme_list_args.tab,
+ type: theme_list_args.type,
+ _ajax_fetch_list_nonce: this.nonce,
+ 'features[]': theme_list_args.features,
+ 'list_args': list_args
+ };
+
+ this.$spinner.show();
+ $.getJSON( ajaxurl, query )
+ .done( function( response ) {
+ self.nextPage++;
+ self.process( response );
+ self.$spinner.hide();
+ self.querying = false;
+ })
+ .fail( function() {
+ self.$spinner.hide();
+ self.querying = false;
+ setTimeout( function() { self.ajax(); }, self.failedRetryDelay );
+ });
+ }
+ }
+
+ $(document).ready( function($) {
+ ThemeScroller.init();
+ });
+
+})(jQuery);
diff --git a/src/wp-admin/js/user-profile.js b/src/wp-admin/js/user-profile.js
new file mode 100644
index 0000000000..bd48855250
--- /dev/null
+++ b/src/wp-admin/js/user-profile.js
@@ -0,0 +1,78 @@
+(function($){
+
+ function check_pass_strength() {
+ var pass1 = $('#pass1').val(), user = $('#user_login').val(), pass2 = $('#pass2').val(), strength;
+
+ $('#pass-strength-result').removeClass('short bad good strong');
+ if ( ! pass1 ) {
+ $('#pass-strength-result').html( pwsL10n.empty );
+ return;
+ }
+
+ strength = passwordStrength(pass1, user, pass2);
+
+ switch ( strength ) {
+ case 2:
+ $('#pass-strength-result').addClass('bad').html( pwsL10n['bad'] );
+ break;
+ case 3:
+ $('#pass-strength-result').addClass('good').html( pwsL10n['good'] );
+ break;
+ case 4:
+ $('#pass-strength-result').addClass('strong').html( pwsL10n['strong'] );
+ break;
+ case 5:
+ $('#pass-strength-result').addClass('short').html( pwsL10n['mismatch'] );
+ break;
+ default:
+ $('#pass-strength-result').addClass('short').html( pwsL10n['short'] );
+ }
+ }
+
+ $(document).ready( function() {
+ var select = $('#display_name');
+
+ $('#pass1').val('').keyup( check_pass_strength );
+ $('#pass2').val('').keyup( check_pass_strength );
+ $('#pass-strength-result').show();
+ $('.color-palette').click( function() {
+ $(this).siblings('input[name="admin_color"]').prop('checked', true);
+ });
+
+ if ( select.length ) {
+ $('#first_name, #last_name, #nickname').bind( 'blur.user_profile', function() {
+ var dub = [],
+ inputs = {
+ display_nickname : $('#nickname').val() || '',
+ display_username : $('#user_login').val() || '',
+ display_firstname : $('#first_name').val() || '',
+ display_lastname : $('#last_name').val() || ''
+ };
+
+ if ( inputs.display_firstname && inputs.display_lastname ) {
+ inputs['display_firstlast'] = inputs.display_firstname + ' ' + inputs.display_lastname;
+ inputs['display_lastfirst'] = inputs.display_lastname + ' ' + inputs.display_firstname;
+ }
+
+ $.each( $('option', select), function( i, el ){
+ dub.push( el.value );
+ });
+
+ $.each(inputs, function( id, value ) {
+ if ( ! value )
+ return;
+
+ var val = value.replace(/<\/?[a-z][^>]*>/gi, '');
+
+ if ( inputs[id].length && $.inArray( val, dub ) == -1 ) {
+ dub.push(val);
+ $('<option />', {
+ 'text': val
+ }).appendTo( select );
+ }
+ });
+ });
+ }
+ });
+
+})(jQuery);
diff --git a/src/wp-admin/js/user-suggest.js b/src/wp-admin/js/user-suggest.js
new file mode 100644
index 0000000000..0bcfada4ba
--- /dev/null
+++ b/src/wp-admin/js/user-suggest.js
@@ -0,0 +1,13 @@
+(function($) {
+ var id = 'undefined' !== typeof current_site_id ? '&site_id=' + current_site_id : '';
+ $(document).ready( function() {
+ $( '.wp-suggest-user' ).autocomplete({
+ source: ajaxurl + '?action=autocomplete-user&autocomplete_type=add' + id,
+ delay: 500,
+ minLength: 2,
+ position: ( 'undefined' !== typeof isRtl && isRtl ) ? { my: 'right top', at: 'right bottom', offset: '0, -1' } : { offset: '0, -1' },
+ open: function() { $(this).addClass('open'); },
+ close: function() { $(this).removeClass('open'); }
+ });
+ });
+})(jQuery); \ No newline at end of file
diff --git a/src/wp-admin/js/widgets.js b/src/wp-admin/js/widgets.js
new file mode 100644
index 0000000000..87be4ddfd5
--- /dev/null
+++ b/src/wp-admin/js/widgets.js
@@ -0,0 +1,289 @@
+var wpWidgets;
+(function($) {
+
+wpWidgets = {
+
+ init : function() {
+ var rem, sidebars = $('div.widgets-sortables'), isRTL = !! ( 'undefined' != typeof isRtl && isRtl ),
+ margin = ( isRtl ? 'marginRight' : 'marginLeft' ), the_id;
+
+ $('#widgets-right').children('.widgets-holder-wrap').children('.sidebar-name').click(function(){
+ var c = $(this).siblings('.widgets-sortables'), p = $(this).parent();
+ if ( !p.hasClass('closed') ) {
+ c.sortable('disable');
+ p.addClass('closed');
+ } else {
+ p.removeClass('closed');
+ c.sortable('enable').sortable('refresh');
+ }
+ });
+
+ $('#widgets-left').children('.widgets-holder-wrap').children('.sidebar-name').click(function() {
+ $(this).parent().toggleClass('closed');
+ });
+
+ sidebars.each(function(){
+ if ( $(this).parent().hasClass('inactive') )
+ return true;
+
+ var h = 50, H = $(this).children('.widget').length;
+ h = h + parseInt(H * 48, 10);
+ $(this).css( 'minHeight', h + 'px' );
+ });
+
+ $(document.body).bind('click.widgets-toggle', function(e){
+ var target = $(e.target), css = {}, widget, inside, w;
+
+ if ( target.parents('.widget-top').length && ! target.parents('#available-widgets').length ) {
+ widget = target.closest('div.widget');
+ inside = widget.children('.widget-inside');
+ w = parseInt( widget.find('input.widget-width').val(), 10 );
+
+ if ( inside.is(':hidden') ) {
+ if ( w > 250 && inside.closest('div.widgets-sortables').length ) {
+ css['width'] = w + 30 + 'px';
+ if ( inside.closest('div.widget-liquid-right').length )
+ css[margin] = 235 - w + 'px';
+ widget.css(css);
+ }
+ wpWidgets.fixLabels(widget);
+ inside.slideDown('fast');
+ } else {
+ inside.slideUp('fast', function() {
+ widget.css({'width':'', margin:''});
+ });
+ }
+ e.preventDefault();
+ } else if ( target.hasClass('widget-control-save') ) {
+ wpWidgets.save( target.closest('div.widget'), 0, 1, 0 );
+ e.preventDefault();
+ } else if ( target.hasClass('widget-control-remove') ) {
+ wpWidgets.save( target.closest('div.widget'), 1, 1, 0 );
+ e.preventDefault();
+ } else if ( target.hasClass('widget-control-close') ) {
+ wpWidgets.close( target.closest('div.widget') );
+ e.preventDefault();
+ }
+ });
+
+ sidebars.children('.widget').each(function() {
+ wpWidgets.appendTitle(this);
+ if ( $('p.widget-error', this).length )
+ $('a.widget-action', this).click();
+ });
+
+ $('#widget-list').children('.widget').draggable({
+ connectToSortable: 'div.widgets-sortables',
+ handle: '> .widget-top > .widget-title',
+ distance: 2,
+ helper: 'clone',
+ zIndex: 100,
+ containment: 'document',
+ start: function(e,ui) {
+ ui.helper.find('div.widget-description').hide();
+ the_id = this.id;
+ },
+ stop: function(e,ui) {
+ if ( rem )
+ $(rem).hide();
+
+ rem = '';
+ }
+ });
+
+ sidebars.sortable({
+ placeholder: 'widget-placeholder',
+ items: '> .widget',
+ handle: '> .widget-top > .widget-title',
+ cursor: 'move',
+ distance: 2,
+ containment: 'document',
+ start: function(e,ui) {
+ ui.item.children('.widget-inside').hide();
+ ui.item.css({margin:'', 'width':''});
+ },
+ stop: function(e,ui) {
+ if ( ui.item.hasClass('ui-draggable') && ui.item.data('draggable') )
+ ui.item.draggable('destroy');
+
+ if ( ui.item.hasClass('deleting') ) {
+ wpWidgets.save( ui.item, 1, 0, 1 ); // delete widget
+ ui.item.remove();
+ return;
+ }
+
+ var add = ui.item.find('input.add_new').val(),
+ n = ui.item.find('input.multi_number').val(),
+ id = the_id,
+ sb = $(this).attr('id');
+
+ ui.item.css({margin:'', 'width':''});
+ the_id = '';
+
+ if ( add ) {
+ if ( 'multi' == add ) {
+ ui.item.html( ui.item.html().replace(/<[^<>]+>/g, function(m){ return m.replace(/__i__|%i%/g, n); }) );
+ ui.item.attr( 'id', id.replace('__i__', n) );
+ n++;
+ $('div#' + id).find('input.multi_number').val(n);
+ } else if ( 'single' == add ) {
+ ui.item.attr( 'id', 'new-' + id );
+ rem = 'div#' + id;
+ }
+ wpWidgets.save( ui.item, 0, 0, 1 );
+ ui.item.find('input.add_new').val('');
+ ui.item.find('a.widget-action').click();
+ return;
+ }
+ wpWidgets.saveOrder(sb);
+ },
+ receive: function(e, ui) {
+ var sender = $(ui.sender);
+
+ if ( !$(this).is(':visible') || this.id.indexOf('orphaned_widgets') != -1 )
+ sender.sortable('cancel');
+
+ if ( sender.attr('id').indexOf('orphaned_widgets') != -1 && !sender.children('.widget').length ) {
+ sender.parents('.orphan-sidebar').slideUp(400, function(){ $(this).remove(); });
+ }
+ }
+ }).sortable('option', 'connectWith', 'div.widgets-sortables').parent().filter('.closed').children('.widgets-sortables').sortable('disable');
+
+ $('#available-widgets').droppable({
+ tolerance: 'pointer',
+ accept: function(o){
+ return $(o).parent().attr('id') != 'widget-list';
+ },
+ drop: function(e,ui) {
+ ui.draggable.addClass('deleting');
+ $('#removing-widget').hide().children('span').html('');
+ },
+ over: function(e,ui) {
+ ui.draggable.addClass('deleting');
+ $('div.widget-placeholder').hide();
+
+ if ( ui.draggable.hasClass('ui-sortable-helper') )
+ $('#removing-widget').show().children('span')
+ .html( ui.draggable.find('div.widget-title').children('h4').html() );
+ },
+ out: function(e,ui) {
+ ui.draggable.removeClass('deleting');
+ $('div.widget-placeholder').show();
+ $('#removing-widget').hide().children('span').html('');
+ }
+ });
+ },
+
+ saveOrder : function(sb) {
+ if ( sb )
+ $('#' + sb).closest('div.widgets-holder-wrap').find('.spinner').css('display', 'inline-block');
+
+ var a = {
+ action: 'widgets-order',
+ savewidgets: $('#_wpnonce_widgets').val(),
+ sidebars: []
+ };
+
+ $('div.widgets-sortables').each( function() {
+ if ( $(this).sortable )
+ a['sidebars[' + $(this).attr('id') + ']'] = $(this).sortable('toArray').join(',');
+ });
+
+ $.post( ajaxurl, a, function() {
+ $('.spinner').hide();
+ });
+
+ this.resize();
+ },
+
+ save : function(widget, del, animate, order) {
+ var sb = widget.closest('div.widgets-sortables').attr('id'), data = widget.find('form').serialize(), a;
+ widget = $(widget);
+ $('.spinner', widget).show();
+
+ a = {
+ action: 'save-widget',
+ savewidgets: $('#_wpnonce_widgets').val(),
+ sidebar: sb
+ };
+
+ if ( del )
+ a['delete_widget'] = 1;
+
+ data += '&' + $.param(a);
+
+ $.post( ajaxurl, data, function(r){
+ var id;
+
+ if ( del ) {
+ if ( !$('input.widget_number', widget).val() ) {
+ id = $('input.widget-id', widget).val();
+ $('#available-widgets').find('input.widget-id').each(function(){
+ if ( $(this).val() == id )
+ $(this).closest('div.widget').show();
+ });
+ }
+
+ if ( animate ) {
+ order = 0;
+ widget.slideUp('fast', function(){
+ $(this).remove();
+ wpWidgets.saveOrder();
+ });
+ } else {
+ widget.remove();
+ wpWidgets.resize();
+ }
+ } else {
+ $('.spinner').hide();
+ if ( r && r.length > 2 ) {
+ $('div.widget-content', widget).html(r);
+ wpWidgets.appendTitle(widget);
+ wpWidgets.fixLabels(widget);
+ }
+ }
+ if ( order )
+ wpWidgets.saveOrder();
+ });
+ },
+
+ appendTitle : function(widget) {
+ var title = $('input[id*="-title"]', widget).val() || '';
+
+ if ( title )
+ title = ': ' + title.replace(/<[^<>]+>/g, '').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+
+ $(widget).children('.widget-top').children('.widget-title').children()
+ .children('.in-widget-title').html(title);
+
+ },
+
+ resize : function() {
+ $('div.widgets-sortables').each(function(){
+ if ( $(this).parent().hasClass('inactive') )
+ return true;
+
+ var h = 50, H = $(this).children('.widget').length;
+ h = h + parseInt(H * 48, 10);
+ $(this).css( 'minHeight', h + 'px' );
+ });
+ },
+
+ fixLabels : function(widget) {
+ widget.children('.widget-inside').find('label').each(function(){
+ var f = $(this).attr('for');
+ if ( f && f == $('input', this).attr('id') )
+ $(this).removeAttr('for');
+ });
+ },
+
+ close : function(widget) {
+ widget.children('.widget-inside').slideUp('fast', function(){
+ widget.css({'width':'', margin:''});
+ });
+ }
+};
+
+$(document).ready(function($){ wpWidgets.init(); });
+
+})(jQuery);
diff --git a/src/wp-admin/js/word-count.js b/src/wp-admin/js/word-count.js
new file mode 100644
index 0000000000..b42f5c3b49
--- /dev/null
+++ b/src/wp-admin/js/word-count.js
@@ -0,0 +1,42 @@
+(function($,undefined) {
+ wpWordCount = {
+
+ settings : {
+ strip : /<[a-zA-Z\/][^<>]*>/g, // strip HTML tags
+ clean : /[0-9.(),;:!?%#$¿'"_+=\\/-]+/g, // regexp to remove punctuation, etc.
+ w : /\S\s+/g, // word-counting regexp
+ c : /\S/g // char-counting regexp for asian languages
+ },
+
+ block : 0,
+
+ wc : function(tx, type) {
+ var t = this, w = $('.word-count'), tc = 0;
+
+ if ( type === undefined )
+ type = wordCountL10n.type;
+ if ( type !== 'w' && type !== 'c' )
+ type = 'w';
+
+ if ( t.block )
+ return;
+
+ t.block = 1;
+
+ setTimeout( function() {
+ if ( tx ) {
+ tx = tx.replace( t.settings.strip, ' ' ).replace( /&nbsp;|&#160;/gi, ' ' );
+ tx = tx.replace( t.settings.clean, '' );
+ tx.replace( t.settings[type], function(){tc++;} );
+ }
+ w.html(tc.toString());
+
+ setTimeout( function() { t.block = 0; }, 2000 );
+ }, 1 );
+ }
+ }
+
+ $(document).bind( 'wpcountwords', function(e, txt) {
+ wpWordCount.wc(txt);
+ });
+}(jQuery));
diff --git a/src/wp-admin/js/wp-fullscreen.js b/src/wp-admin/js/wp-fullscreen.js
new file mode 100644
index 0000000000..4746b286a2
--- /dev/null
+++ b/src/wp-admin/js/wp-fullscreen.js
@@ -0,0 +1,725 @@
+/**
+ * PubSub
+ *
+ * A lightweight publish/subscribe implementation.
+ * Private use only!
+ */
+var PubSub, fullscreen, wptitlehint;
+
+PubSub = function() {
+ this.topics = {};
+};
+
+PubSub.prototype.subscribe = function( topic, callback ) {
+ if ( ! this.topics[ topic ] )
+ this.topics[ topic ] = [];
+
+ this.topics[ topic ].push( callback );
+ return callback;
+};
+
+PubSub.prototype.unsubscribe = function( topic, callback ) {
+ var i, l,
+ topics = this.topics[ topic ];
+
+ if ( ! topics )
+ return callback || [];
+
+ // Clear matching callbacks
+ if ( callback ) {
+ for ( i = 0, l = topics.length; i < l; i++ ) {
+ if ( callback == topics[i] )
+ topics.splice( i, 1 );
+ }
+ return callback;
+
+ // Clear all callbacks
+ } else {
+ this.topics[ topic ] = [];
+ return topics;
+ }
+};
+
+PubSub.prototype.publish = function( topic, args ) {
+ var i, l, broken,
+ topics = this.topics[ topic ];
+
+ if ( ! topics )
+ return;
+
+ args = args || [];
+
+ for ( i = 0, l = topics.length; i < l; i++ ) {
+ broken = ( topics[i].apply( null, args ) === false || broken );
+ }
+ return ! broken;
+};
+
+/**
+ * Distraction Free Writing
+ * (wp-fullscreen)
+ *
+ * Access the API globally using the fullscreen variable.
+ */
+
+(function($){
+ var api, ps, bounder, s;
+
+ // Initialize the fullscreen/api object
+ fullscreen = api = {};
+
+ // Create the PubSub (publish/subscribe) interface.
+ ps = api.pubsub = new PubSub();
+ timer = 0;
+ block = false;
+
+ s = api.settings = { // Settings
+ visible : false,
+ mode : 'tinymce',
+ editor_id : 'content',
+ title_id : '',
+ timer : 0,
+ toolbar_shown : false
+ }
+
+ /**
+ * Bounder
+ *
+ * Creates a function that publishes start/stop topics.
+ * Used to throttle events.
+ */
+ bounder = api.bounder = function( start, stop, delay, e ) {
+ var y, top;
+
+ delay = delay || 1250;
+
+ if ( e ) {
+ y = e.pageY || e.clientY || e.offsetY;
+ top = $(document).scrollTop();
+
+ if ( !e.isDefaultPrevented ) // test if e ic jQuery normalized
+ y = 135 + y;
+
+ if ( y - top > 120 )
+ return;
+ }
+
+ if ( block )
+ return;
+
+ block = true;
+
+ setTimeout( function() {
+ block = false;
+ }, 400 );
+
+ if ( s.timer )
+ clearTimeout( s.timer );
+ else
+ ps.publish( start );
+
+ function timed() {
+ ps.publish( stop );
+ s.timer = 0;
+ }
+
+ s.timer = setTimeout( timed, delay );
+ };
+
+ /**
+ * on()
+ *
+ * Turns fullscreen on.
+ *
+ * @param string mode Optional. Switch to the given mode before opening.
+ */
+ api.on = function() {
+ if ( s.visible )
+ return;
+
+ // Settings can be added or changed by defining "wp_fullscreen_settings" JS object.
+ if ( typeof(wp_fullscreen_settings) == 'object' )
+ $.extend( s, wp_fullscreen_settings );
+
+ s.editor_id = wpActiveEditor || 'content';
+
+ if ( $('input#title').length && s.editor_id == 'content' )
+ s.title_id = 'title';
+ else if ( $('input#' + s.editor_id + '-title').length ) // the title input field should have [editor_id]-title HTML ID to be auto detected
+ s.title_id = s.editor_id + '-title';
+ else
+ $('#wp-fullscreen-title, #wp-fullscreen-title-prompt-text').hide();
+
+ s.mode = $('#' + s.editor_id).is(':hidden') ? 'tinymce' : 'html';
+ s.qt_canvas = $('#' + s.editor_id).get(0);
+
+ if ( ! s.element )
+ api.ui.init();
+
+ s.is_mce_on = s.has_tinymce && typeof( tinyMCE.get(s.editor_id) ) != 'undefined';
+
+ api.ui.fade( 'show', 'showing', 'shown' );
+ };
+
+ /**
+ * off()
+ *
+ * Turns fullscreen off.
+ */
+ api.off = function() {
+ if ( ! s.visible )
+ return;
+
+ api.ui.fade( 'hide', 'hiding', 'hidden' );
+ };
+
+ /**
+ * switchmode()
+ *
+ * @return string - The current mode.
+ *
+ * @param string to - The fullscreen mode to switch to.
+ * @event switchMode
+ * @eventparam string to - The new mode.
+ * @eventparam string from - The old mode.
+ */
+ api.switchmode = function( to ) {
+ var from = s.mode;
+
+ if ( ! to || ! s.visible || ! s.has_tinymce )
+ return from;
+
+ // Don't switch if the mode is the same.
+ if ( from == to )
+ return from;
+
+ ps.publish( 'switchMode', [ from, to ] );
+ s.mode = to;
+ ps.publish( 'switchedMode', [ from, to ] );
+
+ return to;
+ };
+
+ /**
+ * General
+ */
+
+ api.save = function() {
+ var hidden = $('#hiddenaction'), old = hidden.val(), spinner = $('#wp-fullscreen-save .spinner'),
+ message = $('#wp-fullscreen-save span');
+
+ spinner.show();
+ api.savecontent();
+
+ hidden.val('wp-fullscreen-save-post');
+
+ $.post( ajaxurl, $('form#post').serialize(), function(r){
+ spinner.hide();
+ message.show();
+
+ setTimeout( function(){
+ message.fadeOut(1000);
+ }, 3000 );
+
+ if ( r.last_edited )
+ $('#wp-fullscreen-save input').attr( 'title', r.last_edited );
+
+ }, 'json');
+
+ hidden.val(old);
+ }
+
+ api.savecontent = function() {
+ var ed, content;
+
+ if ( s.title_id )
+ $('#' + s.title_id).val( $('#wp-fullscreen-title').val() );
+
+ if ( s.mode === 'tinymce' && (ed = tinyMCE.get('wp_mce_fullscreen')) ) {
+ content = ed.save();
+ } else {
+ content = $('#wp_mce_fullscreen').val();
+ }
+
+ $('#' + s.editor_id).val( content );
+ $(document).triggerHandler('wpcountwords', [ content ]);
+ }
+
+ set_title_hint = function( title ) {
+ if ( ! title.val().length )
+ title.siblings('label').css( 'visibility', '' );
+ else
+ title.siblings('label').css( 'visibility', 'hidden' );
+ }
+
+ api.dfw_width = function(n) {
+ var el = $('#wp-fullscreen-wrap'), w = el.width();
+
+ if ( !n ) { // reset to theme width
+ el.width( $('#wp-fullscreen-central-toolbar').width() );
+ deleteUserSetting('dfw_width');
+ return;
+ }
+
+ w = n + w;
+
+ if ( w < 200 || w > 1200 ) // sanity check
+ return;
+
+ el.width( w );
+ setUserSetting('dfw_width', w);
+ }
+
+ ps.subscribe( 'showToolbar', function() {
+ s.toolbars.removeClass('fade-1000').addClass('fade-300');
+ api.fade.In( s.toolbars, 300, function(){ ps.publish('toolbarShown'); }, true );
+ $('#wp-fullscreen-body').addClass('wp-fullscreen-focus');
+ s.toolbar_shown = true;
+ });
+
+ ps.subscribe( 'hideToolbar', function() {
+ s.toolbars.removeClass('fade-300').addClass('fade-1000');
+ api.fade.Out( s.toolbars, 1000, function(){ ps.publish('toolbarHidden'); }, true );
+ $('#wp-fullscreen-body').removeClass('wp-fullscreen-focus');
+ });
+
+ ps.subscribe( 'toolbarShown', function() {
+ s.toolbars.removeClass('fade-300');
+ });
+
+ ps.subscribe( 'toolbarHidden', function() {
+ s.toolbars.removeClass('fade-1000');
+ s.toolbar_shown = false;
+ });
+
+ ps.subscribe( 'show', function() { // This event occurs before the overlay blocks the UI.
+ var title;
+
+ if ( s.title_id ) {
+ title = $('#wp-fullscreen-title').val( $('#' + s.title_id).val() );
+ set_title_hint( title );
+ }
+
+ $('#wp-fullscreen-save input').attr( 'title', $('#last-edit').text() );
+
+ s.textarea_obj.value = s.qt_canvas.value;
+
+ if ( s.has_tinymce && s.mode === 'tinymce' )
+ tinyMCE.execCommand('wpFullScreenInit');
+
+ s.orig_y = $(window).scrollTop();
+ });
+
+ ps.subscribe( 'showing', function() { // This event occurs while the DFW overlay blocks the UI.
+ $( document.body ).addClass( 'fullscreen-active' );
+ api.refresh_buttons();
+
+ $( document ).bind( 'mousemove.fullscreen', function(e) { bounder( 'showToolbar', 'hideToolbar', 2000, e ); } );
+ bounder( 'showToolbar', 'hideToolbar', 2000 );
+
+ api.bind_resize();
+ setTimeout( api.resize_textarea, 200 );
+
+ // scroll to top so the user is not disoriented
+ scrollTo(0, 0);
+
+ // needed it for IE7 and compat mode
+ $('#wpadminbar').hide();
+ });
+
+ ps.subscribe( 'shown', function() { // This event occurs after the DFW overlay is shown
+ var interim_init;
+
+ s.visible = true;
+
+ // init the standard TinyMCE instance if missing
+ if ( s.has_tinymce && ! s.is_mce_on ) {
+
+ interim_init = function(mce, ed) {
+ var el = ed.getElement(), old_val = el.value, settings = tinyMCEPreInit.mceInit[s.editor_id];
+
+ if ( settings && settings.wpautop && typeof(switchEditors) != 'undefined' )
+ el.value = switchEditors.wpautop( el.value );
+
+ ed.onInit.add(function(ed) {
+ ed.hide();
+ ed.getElement().value = old_val;
+ tinymce.onAddEditor.remove(interim_init);
+ });
+ };
+
+ tinymce.onAddEditor.add(interim_init);
+ tinyMCE.init(tinyMCEPreInit.mceInit[s.editor_id]);
+
+ s.is_mce_on = true;
+ }
+
+ wpActiveEditor = 'wp_mce_fullscreen';
+ });
+
+ ps.subscribe( 'hide', function() { // This event occurs before the overlay blocks DFW.
+ var htmled_is_hidden = $('#' + s.editor_id).is(':hidden');
+ // Make sure the correct editor is displaying.
+ if ( s.has_tinymce && s.mode === 'tinymce' && !htmled_is_hidden ) {
+ switchEditors.go(s.editor_id, 'tmce');
+ } else if ( s.mode === 'html' && htmled_is_hidden ) {
+ switchEditors.go(s.editor_id, 'html');
+ }
+
+ // Save content must be after switchEditors or content will be overwritten. See #17229.
+ api.savecontent();
+
+ $( document ).unbind( '.fullscreen' );
+ $(s.textarea_obj).unbind('.grow');
+
+ if ( s.has_tinymce && s.mode === 'tinymce' )
+ tinyMCE.execCommand('wpFullScreenSave');
+
+ if ( s.title_id )
+ set_title_hint( $('#' + s.title_id) );
+
+ s.qt_canvas.value = s.textarea_obj.value;
+ });
+
+ ps.subscribe( 'hiding', function() { // This event occurs while the overlay blocks the DFW UI.
+
+ $( document.body ).removeClass( 'fullscreen-active' );
+ scrollTo(0, s.orig_y);
+ $('#wpadminbar').show();
+ });
+
+ ps.subscribe( 'hidden', function() { // This event occurs after DFW is removed.
+ s.visible = false;
+ $('#wp_mce_fullscreen, #wp-fullscreen-title').removeAttr('style');
+
+ if ( s.has_tinymce && s.is_mce_on )
+ tinyMCE.execCommand('wpFullScreenClose');
+
+ s.textarea_obj.value = '';
+ api.oldheight = 0;
+ wpActiveEditor = s.editor_id;
+ });
+
+ ps.subscribe( 'switchMode', function( from, to ) {
+ var ed;
+
+ if ( !s.has_tinymce || !s.is_mce_on )
+ return;
+
+ ed = tinyMCE.get('wp_mce_fullscreen');
+
+ if ( from === 'html' && to === 'tinymce' ) {
+
+ if ( tinyMCE.get(s.editor_id).getParam('wpautop') && typeof(switchEditors) != 'undefined' )
+ s.textarea_obj.value = switchEditors.wpautop( s.textarea_obj.value );
+
+ if ( 'undefined' == typeof(ed) )
+ tinyMCE.execCommand('wpFullScreenInit');
+ else
+ ed.show();
+
+ } else if ( from === 'tinymce' && to === 'html' ) {
+ if ( ed )
+ ed.hide();
+ }
+ });
+
+ ps.subscribe( 'switchedMode', function( from, to ) {
+ api.refresh_buttons(true);
+
+ if ( to === 'html' )
+ setTimeout( api.resize_textarea, 200 );
+ });
+
+ /**
+ * Buttons
+ */
+ api.b = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('Bold');
+ }
+
+ api.i = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('Italic');
+ }
+
+ api.ul = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('InsertUnorderedList');
+ }
+
+ api.ol = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('InsertOrderedList');
+ }
+
+ api.link = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('WP_Link');
+ else
+ wpLink.open();
+ }
+
+ api.unlink = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('unlink');
+ }
+
+ api.atd = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('mceWritingImprovementTool');
+ }
+
+ api.help = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('WP_Help');
+ }
+
+ api.blockquote = function() {
+ if ( s.has_tinymce && 'tinymce' === s.mode )
+ tinyMCE.execCommand('mceBlockQuote');
+ }
+
+ api.medialib = function() {
+ if ( typeof wp !== 'undefined' && wp.media && wp.media.editor )
+ wp.media.editor.open(s.editor_id);
+ }
+
+ api.refresh_buttons = function( fade ) {
+ fade = fade || false;
+
+ if ( s.mode === 'html' ) {
+ $('#wp-fullscreen-mode-bar').removeClass('wp-tmce-mode').addClass('wp-html-mode');
+
+ if ( fade )
+ $('#wp-fullscreen-button-bar').fadeOut( 150, function(){
+ $(this).addClass('wp-html-mode').fadeIn( 150 );
+ });
+ else
+ $('#wp-fullscreen-button-bar').addClass('wp-html-mode');
+
+ } else if ( s.mode === 'tinymce' ) {
+ $('#wp-fullscreen-mode-bar').removeClass('wp-html-mode').addClass('wp-tmce-mode');
+
+ if ( fade )
+ $('#wp-fullscreen-button-bar').fadeOut( 150, function(){
+ $(this).removeClass('wp-html-mode').fadeIn( 150 );
+ });
+ else
+ $('#wp-fullscreen-button-bar').removeClass('wp-html-mode');
+ }
+ }
+
+ /**
+ * UI Elements
+ *
+ * Used for transitioning between states.
+ */
+ api.ui = {
+ init: function() {
+ var topbar = $('#fullscreen-topbar'), txtarea = $('#wp_mce_fullscreen'), last = 0;
+
+ s.toolbars = topbar.add( $('#wp-fullscreen-status') );
+ s.element = $('#fullscreen-fader');
+ s.textarea_obj = txtarea[0];
+ s.has_tinymce = typeof(tinymce) != 'undefined';
+
+ if ( !s.has_tinymce )
+ $('#wp-fullscreen-mode-bar').hide();
+
+ if ( wptitlehint && $('#wp-fullscreen-title').length )
+ wptitlehint('wp-fullscreen-title');
+
+ $(document).keyup(function(e){
+ var c = e.keyCode || e.charCode, a, data;
+
+ if ( !fullscreen.settings.visible )
+ return true;
+
+ if ( navigator.platform && navigator.platform.indexOf('Mac') != -1 )
+ a = e.ctrlKey; // Ctrl key for Mac
+ else
+ a = e.altKey; // Alt key for Win & Linux
+
+ if ( 27 == c ) { // Esc
+ data = {
+ event: e,
+ what: 'dfw',
+ cb: fullscreen.off,
+ condition: function(){
+ if ( $('#TB_window').is(':visible') || $('.wp-dialog').is(':visible') )
+ return false;
+ return true;
+ }
+ };
+
+ if ( ! jQuery(document).triggerHandler( 'wp_CloseOnEscape', [data] ) )
+ fullscreen.off();
+ }
+
+ if ( a && (61 == c || 107 == c || 187 == c) ) // +
+ api.dfw_width(25);
+
+ if ( a && (45 == c || 109 == c || 189 == c) ) // -
+ api.dfw_width(-25);
+
+ if ( a && 48 == c ) // 0
+ api.dfw_width(0);
+
+ return false;
+ });
+
+ // word count in Text mode
+ if ( typeof(wpWordCount) != 'undefined' ) {
+
+ txtarea.keyup( function(e) {
+ var k = e.keyCode || e.charCode;
+
+ if ( k == last )
+ return true;
+
+ if ( 13 == k || 8 == last || 46 == last )
+ $(document).triggerHandler('wpcountwords', [ txtarea.val() ]);
+
+ last = k;
+ return true;
+ });
+ }
+
+ topbar.mouseenter(function(e){
+ s.toolbars.addClass('fullscreen-make-sticky');
+ $( document ).unbind( '.fullscreen' );
+ clearTimeout( s.timer );
+ s.timer = 0;
+ }).mouseleave(function(e){
+ s.toolbars.removeClass('fullscreen-make-sticky');
+
+ if ( s.visible )
+ $( document ).bind( 'mousemove.fullscreen', function(e) { bounder( 'showToolbar', 'hideToolbar', 2000, e ); } );
+ });
+ },
+
+ fade: function( before, during, after ) {
+ if ( ! s.element )
+ api.ui.init();
+
+ // If any callback bound to before returns false, bail.
+ if ( before && ! ps.publish( before ) )
+ return;
+
+ api.fade.In( s.element, 600, function() {
+ if ( during )
+ ps.publish( during );
+
+ api.fade.Out( s.element, 600, function() {
+ if ( after )
+ ps.publish( after );
+ })
+ });
+ }
+ };
+
+ api.fade = {
+ transitionend: 'transitionend webkitTransitionEnd oTransitionEnd',
+
+ // Sensitivity to allow browsers to render the blank element before animating.
+ sensitivity: 100,
+
+ In: function( element, speed, callback, stop ) {
+
+ callback = callback || $.noop;
+ speed = speed || 400;
+ stop = stop || false;
+
+ if ( api.fade.transitions ) {
+ if ( element.is(':visible') ) {
+ element.addClass( 'fade-trigger' );
+ return element;
+ }
+
+ element.show();
+ element.first().one( this.transitionend, function() {
+ callback();
+ });
+ setTimeout( function() { element.addClass( 'fade-trigger' ); }, this.sensitivity );
+ } else {
+ if ( stop )
+ element.stop();
+
+ element.css( 'opacity', 1 );
+ element.first().fadeIn( speed, callback );
+
+ if ( element.length > 1 )
+ element.not(':first').fadeIn( speed );
+ }
+
+ return element;
+ },
+
+ Out: function( element, speed, callback, stop ) {
+
+ callback = callback || $.noop;
+ speed = speed || 400;
+ stop = stop || false;
+
+ if ( ! element.is(':visible') )
+ return element;
+
+ if ( api.fade.transitions ) {
+ element.first().one( api.fade.transitionend, function() {
+ if ( element.hasClass('fade-trigger') )
+ return;
+
+ element.hide();
+ callback();
+ });
+ setTimeout( function() { element.removeClass( 'fade-trigger' ); }, this.sensitivity );
+ } else {
+ if ( stop )
+ element.stop();
+
+ element.first().fadeOut( speed, callback );
+
+ if ( element.length > 1 )
+ element.not(':first').fadeOut( speed );
+ }
+
+ return element;
+ },
+
+ transitions: (function() { // Check if the browser supports CSS 3.0 transitions
+ var s = document.documentElement.style;
+
+ return ( typeof ( s.WebkitTransition ) == 'string' ||
+ typeof ( s.MozTransition ) == 'string' ||
+ typeof ( s.OTransition ) == 'string' ||
+ typeof ( s.transition ) == 'string' );
+ })()
+ };
+
+ /**
+ * Resize API
+ *
+ * Automatically updates textarea height.
+ */
+
+ api.bind_resize = function() {
+ $(s.textarea_obj).bind('keypress.grow click.grow paste.grow', function(){
+ setTimeout( api.resize_textarea, 200 );
+ });
+ }
+
+ api.oldheight = 0;
+ api.resize_textarea = function() {
+ var txt = s.textarea_obj, newheight;
+
+ newheight = txt.scrollHeight > 300 ? txt.scrollHeight : 300;
+
+ if ( newheight != api.oldheight ) {
+ txt.style.height = newheight + 'px';
+ api.oldheight = newheight;
+ }
+ };
+
+})(jQuery);
diff --git a/src/wp-admin/js/xfn.js b/src/wp-admin/js/xfn.js
new file mode 100644
index 0000000000..6136db535f
--- /dev/null
+++ b/src/wp-admin/js/xfn.js
@@ -0,0 +1,16 @@
+jQuery(document).ready( function($) {
+ $('#link_rel').prop('readonly', true);
+ $('#linkxfndiv input').bind('click keyup', function() {
+ var isMe = $('#me').is(':checked'), inputs = '';
+ $('input.valinp').each( function() {
+ if (isMe) {
+ $(this).prop('disabled', true).parent().addClass('disabled');
+ } else {
+ $(this).removeAttr('disabled').parent().removeClass('disabled');
+ if ( $(this).is(':checked') && $(this).val() != '')
+ inputs += $(this).val() + ' ';
+ }
+ });
+ $('#link_rel').val( (isMe) ? 'me' : inputs.substr(0,inputs.length - 1) );
+ });
+});
diff --git a/src/wp-admin/link-add.php b/src/wp-admin/link-add.php
new file mode 100644
index 0000000000..6f9c5678e8
--- /dev/null
+++ b/src/wp-admin/link-add.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Add Link Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can('manage_links') )
+ wp_die(__('You do not have sufficient permissions to add links to this site.'));
+
+$title = __('Add New Link');
+$parent_file = 'link-manager.php';
+
+wp_reset_vars( array('action', 'cat_id', 'link_id' ) );
+
+wp_enqueue_script('link');
+wp_enqueue_script('xfn');
+
+if ( wp_is_mobile() )
+ wp_enqueue_script( 'jquery-touch-punch' );
+
+$link = get_default_link_to_edit();
+include('./edit-link-form.php');
+
+require('./admin-footer.php');
diff --git a/src/wp-admin/link-manager.php b/src/wp-admin/link-manager.php
new file mode 100644
index 0000000000..3154f8e3db
--- /dev/null
+++ b/src/wp-admin/link-manager.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Link Management Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once ('admin.php');
+if ( ! current_user_can( 'manage_links' ) )
+ wp_die( __( 'You do not have sufficient permissions to edit the links for this site.' ) );
+
+$wp_list_table = _get_list_table('WP_Links_List_Table');
+
+// Handle bulk deletes
+$doaction = $wp_list_table->current_action();
+
+if ( $doaction && isset( $_REQUEST['linkcheck'] ) ) {
+ check_admin_referer( 'bulk-bookmarks' );
+
+ if ( 'delete' == $doaction ) {
+ $bulklinks = (array) $_REQUEST['linkcheck'];
+ foreach ( $bulklinks as $link_id ) {
+ $link_id = (int) $link_id;
+
+ wp_delete_link( $link_id );
+ }
+
+ wp_redirect( add_query_arg('deleted', count( $bulklinks ), admin_url( 'link-manager.php' ) ) );
+ exit;
+ }
+} elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
+ wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ exit;
+}
+
+$wp_list_table->prepare_items();
+
+$title = __('Links');
+$this_file = $parent_file = 'link-manager.php';
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . sprintf(__('You can add links here to be displayed on your site, usually using <a href="%s">Widgets</a>. By default, links to several sites in the WordPress community are included as examples.'), 'widgets.php') . '</p>' .
+ '<p>' . __('Links may be separated into Link Categories; these are different than the categories used on your posts.') . '</p>' .
+ '<p>' . __('You can customize the display of this screen using the Screen Options tab and/or the dropdown filters above the links table.') . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'deleting-links',
+'title' => __('Deleting Links'),
+'content' =>
+ '<p>' . __('If you delete a link, it will be removed permanently, as Links do not have a Trash function yet.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Links_Screen" target="_blank">Documentation on Managing Links</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include_once ('./admin-header.php');
+
+if ( ! current_user_can('manage_links') )
+ wp_die(__("You do not have sufficient permissions to edit the links for this site."));
+
+?>
+
+<div class="wrap nosubsub">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?> <a href="link-add.php" class="add-new-h2"><?php echo esc_html_x('Add New', 'link'); ?></a> <?php
+if ( !empty($_REQUEST['s']) )
+ printf( '<span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', esc_html( wp_unslash($_REQUEST['s']) ) ); ?>
+</h2>
+
+<?php
+if ( isset($_REQUEST['deleted']) ) {
+ echo '<div id="message" class="updated"><p>';
+ $deleted = (int) $_REQUEST['deleted'];
+ printf(_n('%s link deleted.', '%s links deleted', $deleted), $deleted);
+ echo '</p></div>';
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('deleted'), $_SERVER['REQUEST_URI']);
+}
+?>
+
+<form id="posts-filter" action="" method="get">
+
+<?php $wp_list_table->search_box( __( 'Search Links' ), 'link' ); ?>
+
+<?php $wp_list_table->display(); ?>
+
+<div id="ajax-response"></div>
+</form>
+
+</div>
+
+<?php
+include('./admin-footer.php');
diff --git a/src/wp-admin/link-parse-opml.php b/src/wp-admin/link-parse-opml.php
new file mode 100644
index 0000000000..f24f420d83
--- /dev/null
+++ b/src/wp-admin/link-parse-opml.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Parse OPML XML files and store in globals.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+if ( ! defined('ABSPATH') )
+ die();
+
+global $opml, $map;
+
+// columns we wish to find are: link_url, link_name, link_target, link_description
+// we need to map XML attribute names to our columns
+$opml_map = array('URL' => 'link_url',
+ 'HTMLURL' => 'link_url',
+ 'TEXT' => 'link_name',
+ 'TITLE' => 'link_name',
+ 'TARGET' => 'link_target',
+ 'DESCRIPTION' => 'link_description',
+ 'XMLURL' => 'link_rss'
+);
+
+$map = $opml_map;
+
+/**
+ * XML callback function for the start of a new XML tag.
+ *
+ * @since 0.71
+ * @access private
+ *
+ * @uses $updated_timestamp Not used inside function.
+ * @uses $all_links Not used inside function.
+ * @uses $map Stores names of attributes to use.
+ * @global array $names
+ * @global array $urls
+ * @global array $targets
+ * @global array $descriptions
+ * @global array $feeds
+ *
+ * @param mixed $parser XML Parser resource.
+ * @param string $tagName XML element name.
+ * @param array $attrs XML element attributes.
+ */
+function startElement($parser, $tagName, $attrs) {
+ global $updated_timestamp, $all_links, $map;
+ global $names, $urls, $targets, $descriptions, $feeds;
+
+ if ($tagName == 'OUTLINE') {
+ foreach (array_keys($map) as $key) {
+ if (isset($attrs[$key])) {
+ $$map[$key] = $attrs[$key];
+ }
+ }
+
+ //echo("got data: link_url = [$link_url], link_name = [$link_name], link_target = [$link_target], link_description = [$link_description]<br />\n");
+
+ // save the data away.
+ $names[] = $link_name;
+ $urls[] = $link_url;
+ $targets[] = $link_target;
+ $feeds[] = $link_rss;
+ $descriptions[] = $link_description;
+ } // end if outline
+}
+
+/**
+ * XML callback function that is called at the end of a XML tag.
+ *
+ * @since 0.71
+ * @access private
+ * @package WordPress
+ * @subpackage Dummy
+ *
+ * @param mixed $parser XML Parser resource.
+ * @param string $tagName XML tag name.
+ */
+function endElement($parser, $tagName) {
+ // nothing to do.
+}
+
+// Create an XML parser
+$xml_parser = xml_parser_create();
+
+// Set the functions to handle opening and closing tags
+xml_set_element_handler($xml_parser, "startElement", "endElement");
+
+if (!xml_parse($xml_parser, $opml, true)) {
+ echo(sprintf(__('XML error: %1$s at line %2$s'),
+ xml_error_string(xml_get_error_code($xml_parser)),
+ xml_get_current_line_number($xml_parser)));
+}
+
+// Free up memory used by the XML parser
+xml_parser_free($xml_parser);
diff --git a/src/wp-admin/link.php b/src/wp-admin/link.php
new file mode 100644
index 0000000000..e696d45441
--- /dev/null
+++ b/src/wp-admin/link.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * Manage link administration actions.
+ *
+ * This page is accessed by the link management pages and handles the forms and
+ * AJAX processes for link actions.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once ('admin.php');
+
+wp_reset_vars( array( 'action', 'cat_id', 'link_id' ) );
+
+if ( ! current_user_can('manage_links') )
+ wp_link_manager_disabled_message();
+
+if ( !empty($_POST['deletebookmarks']) )
+ $action = 'deletebookmarks';
+if ( !empty($_POST['move']) )
+ $action = 'move';
+if ( !empty($_POST['linkcheck']) )
+ $linkcheck = $_POST['linkcheck'];
+
+$this_file = admin_url('link-manager.php');
+
+switch ($action) {
+ case 'deletebookmarks' :
+ check_admin_referer('bulk-bookmarks');
+
+ //for each link id (in $linkcheck[]) change category to selected value
+ if (count($linkcheck) == 0) {
+ wp_redirect($this_file);
+ exit;
+ }
+
+ $deleted = 0;
+ foreach ($linkcheck as $link_id) {
+ $link_id = (int) $link_id;
+
+ if ( wp_delete_link($link_id) )
+ $deleted++;
+ }
+
+ wp_redirect("$this_file?deleted=$deleted");
+ exit;
+ break;
+
+ case 'move' :
+ check_admin_referer('bulk-bookmarks');
+
+ //for each link id (in $linkcheck[]) change category to selected value
+ if (count($linkcheck) == 0) {
+ wp_redirect($this_file);
+ exit;
+ }
+ $all_links = join(',', $linkcheck);
+ // should now have an array of links we can change
+ //$q = $wpdb->query("update $wpdb->links SET link_category='$category' WHERE link_id IN ($all_links)");
+
+ wp_redirect($this_file);
+ exit;
+ break;
+
+ case 'add' :
+ check_admin_referer('add-bookmark');
+
+ $redir = wp_get_referer();
+ if ( add_link() )
+ $redir = add_query_arg( 'added', 'true', $redir );
+
+ wp_redirect( $redir );
+ exit;
+ break;
+
+ case 'save' :
+ $link_id = (int) $_POST['link_id'];
+ check_admin_referer('update-bookmark_' . $link_id);
+
+ edit_link($link_id);
+
+ wp_redirect($this_file);
+ exit;
+ break;
+
+ case 'delete' :
+ $link_id = (int) $_GET['link_id'];
+ check_admin_referer('delete-bookmark_' . $link_id);
+
+ wp_delete_link($link_id);
+
+ wp_redirect($this_file);
+ exit;
+ break;
+
+ case 'edit' :
+ wp_enqueue_script('link');
+ wp_enqueue_script('xfn');
+
+ if ( wp_is_mobile() )
+ wp_enqueue_script( 'jquery-touch-punch' );
+
+ $parent_file = 'link-manager.php';
+ $submenu_file = 'link-manager.php';
+ $title = __('Edit Link');
+
+ $link_id = (int) $_GET['link_id'];
+
+ if (!$link = get_link_to_edit($link_id))
+ wp_die(__('Link not found.'));
+
+ include ('edit-link-form.php');
+ include ('admin-footer.php');
+ break;
+
+ default :
+ break;
+}
diff --git a/src/wp-admin/load-scripts.php b/src/wp-admin/load-scripts.php
new file mode 100644
index 0000000000..8dfe3b18ad
--- /dev/null
+++ b/src/wp-admin/load-scripts.php
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * Disable error reporting
+ *
+ * Set this to error_reporting( E_ALL ) or error_reporting( E_ALL | E_STRICT ) for debugging
+ */
+error_reporting(0);
+
+/** Set ABSPATH for execution */
+define( 'ABSPATH', dirname(dirname(__FILE__)) . '/' );
+define( 'WPINC', 'wp-includes' );
+
+/**
+ * @ignore
+ */
+function __() {}
+
+/**
+ * @ignore
+ */
+function _x() {}
+
+/**
+ * @ignore
+ */
+function add_filter() {}
+
+/**
+ * @ignore
+ */
+function esc_attr() {}
+
+/**
+ * @ignore
+ */
+function apply_filters() {}
+
+/**
+ * @ignore
+ */
+function get_option() {}
+
+/**
+ * @ignore
+ */
+function is_lighttpd_before_150() {}
+
+/**
+ * @ignore
+ */
+function add_action() {}
+
+/**
+ * @ignore
+ */
+function did_action() {}
+
+/**
+ * @ignore
+ */
+function do_action_ref_array() {}
+
+/**
+ * @ignore
+ */
+function get_bloginfo() {}
+
+/**
+ * @ignore
+ */
+function is_admin() {return true;}
+
+/**
+ * @ignore
+ */
+function site_url() {}
+
+/**
+ * @ignore
+ */
+function admin_url() {}
+
+/**
+ * @ignore
+ */
+function home_url() {}
+
+/**
+ * @ignore
+ */
+function includes_url() {}
+
+/**
+ * @ignore
+ */
+function wp_guess_url() {}
+
+if ( ! function_exists( 'json_encode' ) ) :
+/**
+ * @ignore
+ */
+function json_encode() {}
+endif;
+
+function get_file($path) {
+
+ if ( function_exists('realpath') )
+ $path = realpath($path);
+
+ if ( ! $path || ! @is_file($path) )
+ return '';
+
+ return @file_get_contents($path);
+}
+
+$load = $_GET['load'];
+if ( is_array( $load ) )
+ $load = implode( '', $load );
+
+$load = preg_replace( '/[^a-z0-9,_-]+/i', '', $load );
+$load = array_unique( explode( ',', $load ) );
+
+if ( empty($load) )
+ exit;
+
+require(ABSPATH . WPINC . '/script-loader.php');
+require(ABSPATH . WPINC . '/version.php');
+
+$compress = ( isset($_GET['c']) && $_GET['c'] );
+$force_gzip = ( $compress && 'gzip' == $_GET['c'] );
+$expires_offset = 31536000; // 1 year
+$out = '';
+
+$wp_scripts = new WP_Scripts();
+wp_default_scripts($wp_scripts);
+
+foreach( $load as $handle ) {
+ if ( !array_key_exists($handle, $wp_scripts->registered) )
+ continue;
+
+ $path = ABSPATH . $wp_scripts->registered[$handle]->src;
+ $out .= get_file($path) . "\n";
+}
+
+header('Content-Type: application/x-javascript; charset=UTF-8');
+header('Expires: ' . gmdate( "D, d M Y H:i:s", time() + $expires_offset ) . ' GMT');
+header("Cache-Control: public, max-age=$expires_offset");
+
+if ( $compress && ! ini_get('zlib.output_compression') && 'ob_gzhandler' != ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) ) {
+ header('Vary: Accept-Encoding'); // Handle proxies
+ if ( false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
+ header('Content-Encoding: deflate');
+ $out = gzdeflate( $out, 3 );
+ } elseif ( false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
+ header('Content-Encoding: gzip');
+ $out = gzencode( $out, 3 );
+ }
+}
+
+echo $out;
+exit;
diff --git a/src/wp-admin/load-styles.php b/src/wp-admin/load-styles.php
new file mode 100644
index 0000000000..d2f8bfbdee
--- /dev/null
+++ b/src/wp-admin/load-styles.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * Disable error reporting
+ *
+ * Set this to error_reporting( E_ALL ) or error_reporting( E_ALL | E_STRICT ) for debugging
+ */
+error_reporting(0);
+
+/** Set ABSPATH for execution */
+define( 'ABSPATH', dirname(dirname(__FILE__)) . '/' );
+define( 'WPINC', 'wp-includes' );
+
+/**
+ * @ignore
+ */
+function __() {}
+
+/**
+ * @ignore
+ */
+function _x() {}
+
+/**
+ * @ignore
+ */
+function add_filter() {}
+
+/**
+ * @ignore
+ */
+function esc_attr() {}
+
+/**
+ * @ignore
+ */
+function apply_filters() {}
+
+/**
+ * @ignore
+ */
+function get_option() {}
+
+/**
+ * @ignore
+ */
+function is_lighttpd_before_150() {}
+
+/**
+ * @ignore
+ */
+function add_action() {}
+
+/**
+ * @ignore
+ */
+function do_action_ref_array() {}
+
+/**
+ * @ignore
+ */
+function get_bloginfo() {}
+
+/**
+ * @ignore
+ */
+function is_admin() {return true;}
+
+/**
+ * @ignore
+ */
+function site_url() {}
+
+/**
+ * @ignore
+ */
+function admin_url() {}
+
+/**
+ * @ignore
+ */
+function wp_guess_url() {}
+
+function get_file($path) {
+
+ if ( function_exists('realpath') )
+ $path = realpath($path);
+
+ if ( ! $path || ! @is_file($path) )
+ return '';
+
+ return @file_get_contents($path);
+}
+
+require(ABSPATH . '/wp-includes/script-loader.php');
+require(ABSPATH . '/wp-includes/version.php');
+
+$load = preg_replace( '/[^a-z0-9,_-]+/i', '', $_GET['load'] );
+$load = array_unique( explode( ',', $load ) );
+
+if ( empty($load) )
+ exit;
+
+$compress = ( isset($_GET['c']) && $_GET['c'] );
+$force_gzip = ( $compress && 'gzip' == $_GET['c'] );
+$rtl = ( isset($_GET['dir']) && 'rtl' == $_GET['dir'] );
+$expires_offset = 31536000; // 1 year
+$out = '';
+
+$wp_styles = new WP_Styles();
+wp_default_styles($wp_styles);
+
+foreach( $load as $handle ) {
+ if ( !array_key_exists($handle, $wp_styles->registered) )
+ continue;
+
+ $style = $wp_styles->registered[$handle];
+ $path = ABSPATH . $style->src;
+
+ $content = get_file($path) . "\n";
+
+ if ( $rtl && isset($style->extra['rtl']) && $style->extra['rtl'] ) {
+ $rtl_path = is_bool($style->extra['rtl']) ? str_replace( '.min.css', '-rtl.min.css', $path ) : ABSPATH . $style->extra['rtl'];
+ $content .= get_file($rtl_path) . "\n";
+ }
+
+ if ( strpos( $style->src, '/wp-includes/css/' ) === 0 ) {
+ $content = str_replace( '../images/', '../wp-includes/images/', $content );
+ $out .= str_replace( '../js/tinymce/', '../wp-includes/js/tinymce/', $content );
+ } else {
+ $out .= str_replace( '../images/', 'images/', $content );
+ }
+}
+
+header('Content-Type: text/css');
+header('Expires: ' . gmdate( "D, d M Y H:i:s", time() + $expires_offset ) . ' GMT');
+header("Cache-Control: public, max-age=$expires_offset");
+
+if ( $compress && ! ini_get('zlib.output_compression') && 'ob_gzhandler' != ini_get('output_handler') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) ) {
+ header('Vary: Accept-Encoding'); // Handle proxies
+ if ( false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') && function_exists('gzdeflate') && ! $force_gzip ) {
+ header('Content-Encoding: deflate');
+ $out = gzdeflate( $out, 3 );
+ } elseif ( false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && function_exists('gzencode') ) {
+ header('Content-Encoding: gzip');
+ $out = gzencode( $out, 3 );
+ }
+}
+
+echo $out;
+exit;
diff --git a/src/wp-admin/maint/repair.php b/src/wp-admin/maint/repair.php
new file mode 100644
index 0000000000..7cc13e11ac
--- /dev/null
+++ b/src/wp-admin/maint/repair.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Database Repair and Optimization Script.
+ *
+ * @package WordPress
+ * @subpackage Database
+ */
+define('WP_REPAIRING', true);
+
+require_once('../../wp-load.php');
+
+header( 'Content-Type: text/html; charset=utf-8' );
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title><?php _e( 'WordPress &rsaquo; Database Repair' ); ?></title>
+ <?php
+ wp_admin_css( 'install', true );
+ ?>
+</head>
+<body class="wp-core-ui">
+<h1 id="logo"><a href="<?php echo esc_url( __( 'http://wordpress.org/' ) ); ?>"><?php _e( 'WordPress' ); ?></a></h1>
+
+<?php
+
+if ( ! defined( 'WP_ALLOW_REPAIR' ) ) {
+ echo '<p>' . __( 'To allow use of this page to automatically repair database problems, please add the following line to your <code>wp-config.php</code> file. Once this line is added to your config, reload this page.' ) . "</p><code>define('WP_ALLOW_REPAIR', true);</code>";
+} elseif ( isset( $_GET['repair'] ) ) {
+ $optimize = 2 == $_GET['repair'];
+ $okay = true;
+ $problems = array();
+
+ $tables = $wpdb->tables();
+
+ // Sitecategories may not exist if global terms are disabled.
+ if ( is_multisite() && ! $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->sitecategories'" ) )
+ unset( $tables['sitecategories'] );
+
+ $tables = array_merge( $tables, (array) apply_filters( 'tables_to_repair', array() ) ); // Return tables with table prefixes.
+
+ // Loop over the tables, checking and repairing as needed.
+ foreach ( $tables as $table ) {
+ $check = $wpdb->get_row( "CHECK TABLE $table" );
+
+ echo '<p>';
+ if ( 'OK' == $check->Msg_text ) {
+ /* translators: %s: table name */
+ printf( __( 'The %s table is okay.' ), "<code>$table</code>" );
+ } else {
+ /* translators: 1: table name, 2: error message, */
+ printf( __( 'The %1$s table is not okay. It is reporting the following error: %2$s. WordPress will attempt to repair this table&hellip;' ) , "<code>$table</code>", "<code>$check->Msg_text</code>" );
+
+ $repair = $wpdb->get_row( "REPAIR TABLE $table" );
+
+ echo '<br />&nbsp;&nbsp;&nbsp;&nbsp;';
+ if ( 'OK' == $check->Msg_text ) {
+ /* translators: %s: table name */
+ printf( __( 'Successfully repaired the %s table.' ), "<code>$table</code>" );
+ } else {
+ /* translators: 1: table name, 2: error message, */
+ echo sprintf( __( 'Failed to repair the %1$s table. Error: %2$s' ), "<code>$table</code>", "<code>$check->Msg_text</code>" ) . '<br />';
+ $problems[$table] = $check->Msg_text;
+ $okay = false;
+ }
+ }
+
+ if ( $okay && $optimize ) {
+ $check = $wpdb->get_row( "ANALYZE TABLE $table" );
+
+ echo '<br />&nbsp;&nbsp;&nbsp;&nbsp;';
+ if ( 'Table is already up to date' == $check->Msg_text ) {
+ /* translators: %s: table name */
+ printf( __( 'The %s table is already optimized.' ), "<code>$table</code>" );
+ } else {
+ $check = $wpdb->get_row( "OPTIMIZE TABLE $table" );
+
+ echo '<br />&nbsp;&nbsp;&nbsp;&nbsp;';
+ if ( 'OK' == $check->Msg_text || 'Table is already up to date' == $check->Msg_text ) {
+ /* translators: %s: table name */
+ printf( __( 'Successfully optimized the %s table.' ), "<code>$table</code>" );
+ } else {
+ /* translators: 1: table name, 2: error message, */
+ printf( __( 'Failed to optimize the %1$s table. Error: %2$s' ), "<code>$table</code>", "<code>$check->Msg_text</code>" );
+ }
+ }
+ }
+ echo '</p>';
+ }
+
+ if ( $problems ) {
+ printf( '<p>' . __('Some database problems could not be repaired. Please copy-and-paste the following list of errors to the <a href="%s">WordPress support forums</a> to get additional assistance.') . '</p>', __( 'http://wordpress.org/support/forum/how-to-and-troubleshooting' ) );
+ $problem_output = '';
+ foreach ( $problems as $table => $problem )
+ $problem_output .= "$table: $problem\n";
+ echo '<p><textarea name="errors" id="errors" rows="20" cols="60">' . esc_textarea( $problem_output ) . '</textarea></p>';
+ } else {
+ echo '<p>' . __( 'Repairs complete. Please remove the following line from wp-config.php to prevent this page from being used by unauthorized users.' ) . "</p><code>define('WP_ALLOW_REPAIR', true);</code>";
+ }
+} else {
+ if ( isset( $_GET['referrer'] ) && 'is_blog_installed' == $_GET['referrer'] )
+ echo '<p>' . __( 'One or more database tables are unavailable. To allow WordPress to attempt to repair these tables, press the &#8220;Repair Database&#8221; button. Repairing can take a while, so please be patient.' ) . '</p>';
+ else
+ echo '<p>' . __( 'WordPress can automatically look for some common database problems and repair them. Repairing can take a while, so please be patient.' ) . '</p>';
+?>
+ <p class="step"><a class="button button-large" href="repair.php?repair=1"><?php _e( 'Repair Database' ); ?></a></p>
+ <p><?php _e( 'WordPress can also attempt to optimize the database. This improves performance in some situations. Repairing and optimizing the database can take a long time and the database will be locked while optimizing.' ); ?></p>
+ <p class="step"><a class="button button-large" href="repair.php?repair=2"><?php _e( 'Repair and Optimize Database' ); ?></a></p>
+<?php
+}
+?>
+</body>
+</html>
diff --git a/src/wp-admin/media-new.php b/src/wp-admin/media-new.php
new file mode 100644
index 0000000000..e428811957
--- /dev/null
+++ b/src/wp-admin/media-new.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Manage media uploaded file.
+ *
+ * There are many filters in here for media. Plugins can extend functionality
+ * by hooking into the filters.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if (!current_user_can('upload_files'))
+ wp_die(__('You do not have permission to upload files.'));
+
+wp_enqueue_script('plupload-handlers');
+
+$post_id = 0;
+if ( isset( $_REQUEST['post_id'] ) ) {
+ $post_id = absint( $_REQUEST['post_id'] );
+ if ( ! get_post( $post_id ) || ! current_user_can( 'edit_post', $post_id ) )
+ $post_id = 0;
+}
+
+if ( $_POST ) {
+ $location = 'upload.php';
+ if ( isset($_POST['html-upload']) && !empty($_FILES) ) {
+ check_admin_referer('media-form');
+ // Upload File button was clicked
+ $id = media_handle_upload( 'async-upload', $post_id );
+ if ( is_wp_error( $id ) )
+ $location .= '?message=3';
+ }
+ wp_redirect( admin_url( $location ) );
+ exit;
+}
+
+$title = __('Upload New Media');
+$parent_file = 'upload.php';
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __('You can upload media files here without creating a post first. This allows you to upload files to use with posts and pages later and/or to get a web link for a particular file that you can share. There are three options for uploading files:') . '</p>' .
+ '<ul>' .
+ '<li>' . __('<strong>Drag and drop</strong> your files into the area below. Multiple files are allowed.') . '</li>' .
+ '<li>' . __('Clicking <strong>Select Files</strong> opens a navigation window showing you files in your operating system. Selecting <strong>Open</strong> after clicking on the file you want activates a progress bar on the uploader screen.') . '</li>' .
+ '<li>' . __('Revert to the <strong>Browser Uploader</strong> by clicking the link below the drag and drop box.') . '</li>' .
+ '</ul>'
+) );
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Media_Add_New_Screen" target="_blank">Documentation on Uploading Media Files</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+require_once( ABSPATH . 'wp-admin/admin-header.php' );
+
+$form_class = 'media-upload-form type-form validate';
+
+if ( get_user_setting('uploader') || isset( $_GET['browser-uploader'] ) )
+ $form_class .= ' html-uploader';
+?>
+<div class="wrap">
+ <?php screen_icon(); ?>
+ <h2><?php echo esc_html( $title ); ?></h2>
+
+ <form enctype="multipart/form-data" method="post" action="<?php echo admin_url('media-new.php'); ?>" class="<?php echo esc_attr( $form_class ); ?>" id="file-form">
+
+ <?php media_upload_form(); ?>
+
+ <script type="text/javascript">
+ var post_id = <?php echo $post_id; ?>, shortform = 3;
+ </script>
+ <input type="hidden" name="post_id" id="post_id" value="<?php echo $post_id; ?>" />
+ <?php wp_nonce_field('media-form'); ?>
+ <div id="media-items" class="hide-if-no-js"></div>
+ </form>
+</div>
+
+<?php
+include( ABSPATH . 'wp-admin/admin-footer.php' );
diff --git a/src/wp-admin/media-upload.php b/src/wp-admin/media-upload.php
new file mode 100644
index 0000000000..96af66bb8d
--- /dev/null
+++ b/src/wp-admin/media-upload.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Manage media uploaded file.
+ *
+ * There are many filters in here for media. Plugins can extend functionality
+ * by hooking into the filters.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+if ( ! isset( $_GET['inline'] ) )
+ define( 'IFRAME_REQUEST' , true );
+
+/** Load WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if (!current_user_can('upload_files'))
+ wp_die(__('You do not have permission to upload files.'));
+
+wp_enqueue_script('plupload-handlers');
+wp_enqueue_script('image-edit');
+wp_enqueue_script('set-post-thumbnail' );
+wp_enqueue_style('imgareaselect');
+wp_enqueue_script( 'media-gallery' );
+
+@header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
+
+// IDs should be integers
+$ID = isset($ID) ? (int) $ID : 0;
+$post_id = isset($post_id)? (int) $post_id : 0;
+
+// Require an ID for the edit screen
+if ( isset($action) && $action == 'edit' && !$ID )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ if ( ! empty( $_REQUEST['post_id'] ) && ! current_user_can( 'edit_post' , $_REQUEST['post_id'] ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+ // upload type: image, video, file, ..?
+ if ( isset($_GET['type']) )
+ $type = strval($_GET['type']);
+ else
+ $type = apply_filters('media_upload_default_type', 'file');
+
+ // tab: gallery, library, or type-specific
+ if ( isset($_GET['tab']) )
+ $tab = strval($_GET['tab']);
+ else
+ $tab = apply_filters('media_upload_default_tab', 'type');
+
+ $body_id = 'media-upload';
+
+ // let the action code decide how to handle the request
+ if ( $tab == 'type' || $tab == 'type_url' || ! array_key_exists( $tab , media_upload_tabs() ) )
+ do_action("media_upload_$type");
+ else
+ do_action("media_upload_$tab");
diff --git a/src/wp-admin/media.php b/src/wp-admin/media.php
new file mode 100644
index 0000000000..15d4323876
--- /dev/null
+++ b/src/wp-admin/media.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Media management action handler.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+$parent_file = 'upload.php';
+$submenu_file = 'upload.php';
+
+wp_reset_vars(array('action'));
+
+switch( $action ) :
+case 'editattachment' :
+ $attachment_id = (int) $_POST['attachment_id'];
+ check_admin_referer('media-form');
+
+ if ( !current_user_can('edit_post', $attachment_id) )
+ wp_die ( __('You are not allowed to edit this attachment.') );
+
+ $errors = media_upload_form_handler();
+
+ if ( empty($errors) ) {
+ $location = 'media.php';
+ if ( $referer = wp_get_original_referer() ) {
+ if ( false !== strpos($referer, 'upload.php') || ( url_to_postid($referer) == $attachment_id ) )
+ $location = $referer;
+ }
+ if ( false !== strpos($location, 'upload.php') ) {
+ $location = remove_query_arg('message', $location);
+ $location = add_query_arg('posted', $attachment_id, $location);
+ } elseif ( false !== strpos($location, 'media.php') ) {
+ $location = add_query_arg('message', 'updated', $location);
+ }
+ wp_redirect($location);
+ exit;
+ }
+
+ // no break
+case 'edit' :
+ $title = __('Edit Media');
+
+ if ( empty($errors) )
+ $errors = null;
+
+ if ( empty( $_GET['attachment_id'] ) ) {
+ wp_redirect( admin_url('upload.php') );
+ exit();
+ }
+ $att_id = (int) $_GET['attachment_id'];
+
+ if ( !current_user_can('edit_post', $att_id) )
+ wp_die ( __('You are not allowed to edit this attachment.') );
+
+ $att = get_post($att_id);
+
+ if ( empty($att->ID) ) wp_die( __('You attempted to edit an attachment that doesn&#8217;t exist. Perhaps it was deleted?') );
+ if ( 'attachment' !== $att->post_type ) wp_die( __('You attempted to edit an item that isn&#8217;t an attachment. Please go back and try again.') );
+ if ( $att->post_status == 'trash' ) wp_die( __('You can&#8217;t edit this attachment because it is in the Trash. Please move it out of the Trash and try again.') );
+
+ add_filter('attachment_fields_to_edit', 'media_single_attachment_fields_to_edit', 10, 2);
+
+ wp_enqueue_script( 'wp-ajax-response' );
+ wp_enqueue_script('image-edit');
+ wp_enqueue_style('imgareaselect');
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen allows you to edit five fields for metadata in a file within the media library.') . '</p>' .
+ '<p>' . __('For images only, you can click on Edit Image under the thumbnail to expand out an inline image editor with icons for cropping, rotating, or flipping the image as well as for undoing and redoing. The boxes on the right give you more options for scaling the image, for cropping it, and for cropping the thumbnail in a different way than you crop the original image. You can click on Help in those boxes to get more information.') . '</p>' .
+ '<p>' . __('Note that you crop the image by clicking on it (the Crop icon is already selected) and dragging the cropping frame to select the desired part. Then click Save to retain the cropping.') . '</p>' .
+ '<p>' . __('Remember to click Update Media to save metadata entered or changed.') . '</p>'
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Media_Add_New_Screen#Edit_Media" target="_blank">Documentation on Edit Media</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+
+ require( './admin-header.php' );
+
+ $parent_file = 'upload.php';
+ $message = '';
+ $class = '';
+ if ( isset($_GET['message']) ) {
+ switch ( $_GET['message'] ) :
+ case 'updated' :
+ $message = __('Media attachment updated.');
+ $class = 'updated';
+ break;
+ endswitch;
+ }
+ if ( $message )
+ echo "<div id='message' class='$class'><p>$message</p></div>\n";
+
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2>
+<?php
+echo esc_html( $title );
+if ( current_user_can( 'upload_files' ) ) { ?>
+ <a href="media-new.php" class="add-new-h2"><?php echo esc_html_x('Add New', 'file'); ?></a>
+<?php } ?>
+</h2>
+
+<form method="post" action="" class="media-upload-form" id="media-single-form">
+<p class="submit" style="padding-bottom: 0;">
+<?php submit_button( __( 'Update Media' ), 'primary', 'save', false ); ?>
+</p>
+
+<div class="media-single">
+<div id='media-item-<?php echo $att_id; ?>' class='media-item'>
+<?php echo get_media_item( $att_id, array( 'toggle' => false, 'send' => false, 'delete' => false, 'show_title' => false, 'errors' => !empty($errors[$att_id]) ? $errors[$att_id] : null ) ); ?>
+</div>
+</div>
+
+<?php submit_button( __( 'Update Media' ), 'primary', 'save' ); ?>
+<input type="hidden" name="post_id" id="post_id" value="<?php echo isset($post_id) ? esc_attr($post_id) : ''; ?>" />
+<input type="hidden" name="attachment_id" id="attachment_id" value="<?php echo esc_attr($att_id); ?>" />
+<input type="hidden" name="action" value="editattachment" />
+<?php wp_original_referer_field(true, 'previous'); ?>
+<?php wp_nonce_field('media-form'); ?>
+
+</form>
+
+</div>
+
+<?php
+
+ require( './admin-footer.php' );
+
+ exit;
+
+default:
+ wp_redirect( admin_url('upload.php') );
+ exit;
+
+endswitch;
diff --git a/src/wp-admin/menu-header.php b/src/wp-admin/menu-header.php
new file mode 100644
index 0000000000..10ad1395ec
--- /dev/null
+++ b/src/wp-admin/menu-header.php
@@ -0,0 +1,189 @@
+<?php
+/**
+ * Displays Administration Menu.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * The current page.
+ *
+ * @global string $self
+ * @name $self
+ * @var string
+ */
+$self = preg_replace('|^.*/wp-admin/network/|i', '', $_SERVER['PHP_SELF']);
+$self = preg_replace('|^.*/wp-admin/|i', '', $self);
+$self = preg_replace('|^.*/plugins/|i', '', $self);
+$self = preg_replace('|^.*/mu-plugins/|i', '', $self);
+
+global $menu, $submenu, $parent_file; //For when admin-header is included from within a function.
+$parent_file = apply_filters("parent_file", $parent_file); // For plugins to move submenu tabs around.
+
+get_admin_page_parent();
+
+/**
+ * Display menu.
+ *
+ * @access private
+ * @since 2.7.0
+ *
+ * @param array $menu
+ * @param array $submenu
+ * @param bool $submenu_as_parent
+ */
+function _wp_menu_output( $menu, $submenu, $submenu_as_parent = true ) {
+ global $self, $parent_file, $submenu_file, $plugin_page, $typenow;
+
+ $first = true;
+ // 0 = name, 1 = capability, 2 = file, 3 = class, 4 = id, 5 = icon src
+ foreach ( $menu as $key => $item ) {
+ $admin_is_parent = false;
+ $class = array();
+ $aria_attributes = '';
+
+ if ( $first ) {
+ $class[] = 'wp-first-item';
+ $first = false;
+ }
+
+ $submenu_items = false;
+ if ( ! empty( $submenu[$item[2]] ) ) {
+ $class[] = 'wp-has-submenu';
+ $submenu_items = $submenu[$item[2]];
+ }
+
+ if ( ( $parent_file && $item[2] == $parent_file ) || ( empty($typenow) && $self == $item[2] ) ) {
+ $class[] = ! empty( $submenu_items ) ? 'wp-has-current-submenu wp-menu-open' : 'current';
+ } else {
+ $class[] = 'wp-not-current-submenu';
+ if ( ! empty( $submenu_items ) )
+ $aria_attributes .= 'aria-haspopup="true"';
+ }
+
+ if ( ! empty( $item[4] ) )
+ $class[] = $item[4];
+
+ $class = $class ? ' class="' . join( ' ', $class ) . '"' : '';
+ $id = ! empty( $item[5] ) ? ' id="' . preg_replace( '|[^a-zA-Z0-9_:.]|', '-', $item[5] ) . '"' : '';
+ $img = '';
+ // if the string 'none' (previously 'div') is passed instead of an URL, don't output the default menu image
+ // so an icon can be added to div.wp-menu-image as background with CSS.
+ if ( ! empty( $item[6] ) )
+ $img = ( 'none' === $item[6] || 'div' === $item[6] ) ? '<br />' : '<img src="' . $item[6] . '" alt="" />';
+ $arrow = '<div class="wp-menu-arrow"><div></div></div>';
+
+ $title = wptexturize( $item[0] );
+
+ echo "\n\t<li$class$id>";
+
+ if ( false !== strpos( $class, 'wp-menu-separator' ) ) {
+ echo '<div class="separator"></div>';
+ } elseif ( $submenu_as_parent && ! empty( $submenu_items ) ) {
+ $submenu_items = array_values( $submenu_items ); // Re-index.
+ $menu_hook = get_plugin_page_hook( $submenu_items[0][2], $item[2] );
+ $menu_file = $submenu_items[0][2];
+ if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
+ $menu_file = substr( $menu_file, 0, $pos );
+ if ( ! empty( $menu_hook ) || ( ( 'index.php' != $submenu_items[0][2] ) && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && ! file_exists( ABSPATH . "/wp-admin/$menu_file" ) ) ) {
+ $admin_is_parent = true;
+ echo "<a href='admin.php?page={$submenu_items[0][2]}'$class $aria_attributes>$arrow<div class='wp-menu-image'>$img</div><div class='wp-menu-name'>$title</div></a>";
+ } else {
+ echo "\n\t<a href='{$submenu_items[0][2]}'$class $aria_attributes>$arrow<div class='wp-menu-image'>$img</div><div class='wp-menu-name'>$title</div></a>";
+ }
+ } elseif ( ! empty( $item[2] ) && current_user_can( $item[1] ) ) {
+ $menu_hook = get_plugin_page_hook( $item[2], 'admin.php' );
+ $menu_file = $item[2];
+ if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
+ $menu_file = substr( $menu_file, 0, $pos );
+ if ( ! empty( $menu_hook ) || ( ( 'index.php' != $item[2] ) && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && ! file_exists( ABSPATH . "/wp-admin/$menu_file" ) ) ) {
+ $admin_is_parent = true;
+ echo "\n\t<a href='admin.php?page={$item[2]}'$class $aria_attributes>$arrow<div class='wp-menu-image'>$img</div><div class='wp-menu-name'>{$item[0]}</div></a>";
+ } else {
+ echo "\n\t<a href='{$item[2]}'$class $aria_attributes>$arrow<div class='wp-menu-image'>$img</div><div class='wp-menu-name'>{$item[0]}</div></a>";
+ }
+ }
+
+ if ( ! empty( $submenu_items ) ) {
+ echo "\n\t<ul class='wp-submenu wp-submenu-wrap'>";
+ echo "<li class='wp-submenu-head'>{$item[0]}</li>";
+
+ $first = true;
+ foreach ( $submenu_items as $sub_key => $sub_item ) {
+ if ( ! current_user_can( $sub_item[1] ) )
+ continue;
+
+ $class = array();
+ if ( $first ) {
+ $class[] = 'wp-first-item';
+ $first = false;
+ }
+
+ $menu_file = $item[2];
+
+ if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
+ $menu_file = substr( $menu_file, 0, $pos );
+
+ // Handle current for post_type=post|page|foo pages, which won't match $self.
+ $self_type = ! empty( $typenow ) ? $self . '?post_type=' . $typenow : 'nothing';
+
+ if ( isset( $submenu_file ) ) {
+ if ( $submenu_file == $sub_item[2] )
+ $class[] = 'current';
+ // If plugin_page is set the parent must either match the current page or not physically exist.
+ // This allows plugin pages with the same hook to exist under different parents.
+ } else if (
+ ( ! isset( $plugin_page ) && $self == $sub_item[2] ) ||
+ ( isset( $plugin_page ) && $plugin_page == $sub_item[2] && ( $item[2] == $self_type || $item[2] == $self || file_exists($menu_file) === false ) )
+ ) {
+ $class[] = 'current';
+ }
+
+ $class = $class ? ' class="' . join( ' ', $class ) . '"' : '';
+
+ $menu_hook = get_plugin_page_hook($sub_item[2], $item[2]);
+ $sub_file = $sub_item[2];
+ if ( false !== ( $pos = strpos( $sub_file, '?' ) ) )
+ $sub_file = substr($sub_file, 0, $pos);
+
+ $title = wptexturize($sub_item[0]);
+
+ if ( ! empty( $menu_hook ) || ( ( 'index.php' != $sub_item[2] ) && file_exists( WP_PLUGIN_DIR . "/$sub_file" ) && ! file_exists( ABSPATH . "/wp-admin/$sub_file" ) ) ) {
+ // If admin.php is the current page or if the parent exists as a file in the plugins or admin dir
+ if ( ( ! $admin_is_parent && file_exists( WP_PLUGIN_DIR . "/$menu_file" ) && ! is_dir( WP_PLUGIN_DIR . "/{$item[2]}" ) ) || file_exists( $menu_file ) )
+ $sub_item_url = add_query_arg( array( 'page' => $sub_item[2] ), $item[2] );
+ else
+ $sub_item_url = add_query_arg( array( 'page' => $sub_item[2] ), 'admin.php' );
+
+ $sub_item_url = esc_url( $sub_item_url );
+ echo "<li$class><a href='$sub_item_url'$class>$title</a></li>";
+ } else {
+ echo "<li$class><a href='{$sub_item[2]}'$class>$title</a></li>";
+ }
+ }
+ echo "</ul>";
+ }
+ echo "</li>";
+ }
+
+ echo '<li id="collapse-menu" class="hide-if-no-js"><div id="collapse-button"><div></div></div>';
+ echo '<span>' . esc_html__( 'Collapse menu' ) . '</span>';
+ echo '</li>';
+}
+
+?>
+
+<div id="adminmenuback"></div>
+<div id="adminmenuwrap">
+<div id="adminmenushadow"></div>
+<ul id="adminmenu" role="navigation">
+
+<?php
+
+_wp_menu_output( $menu, $submenu );
+do_action( 'adminmenu' );
+
+?>
+</ul>
+</div>
diff --git a/src/wp-admin/menu.php b/src/wp-admin/menu.php
new file mode 100644
index 0000000000..365b459544
--- /dev/null
+++ b/src/wp-admin/menu.php
@@ -0,0 +1,242 @@
+<?php
+/**
+ * Build Administration Menu.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * Constructs the admin menu bar.
+ *
+ * The elements in the array are :
+ * 0: Menu item name
+ * 1: Minimum level or capability required.
+ * 2: The URL of the item's file
+ * 3: Class
+ * 4: ID
+ * 5: Icon for top level menu
+ *
+ * @global array $menu
+ * @name $menu
+ * @var array
+ */
+
+$menu[2] = array( __('Dashboard'), 'read', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'none' );
+
+$submenu[ 'index.php' ][0] = array( __('Home'), 'read', 'index.php' );
+
+if ( is_multisite() ) {
+ $submenu[ 'index.php' ][5] = array( __('My Sites'), 'read', 'my-sites.php' );
+}
+
+if ( ! is_multisite() || is_super_admin() )
+ $update_data = wp_get_update_data();
+
+if ( ! is_multisite() ) {
+ if ( current_user_can( 'update_core' ) )
+ $cap = 'update_core';
+ elseif ( current_user_can( 'update_plugins' ) )
+ $cap = 'update_plugins';
+ else
+ $cap = 'update_themes';
+ $submenu[ 'index.php' ][10] = array( sprintf( __('Updates %s'), "<span class='update-plugins count-{$update_data['counts']['total']}' title='{$update_data['title']}'><span class='update-count'>" . number_format_i18n($update_data['counts']['total']) . "</span></span>" ), $cap, 'update-core.php');
+ unset( $cap );
+}
+
+$menu[4] = array( '', 'read', 'separator1', '', 'wp-menu-separator' );
+
+$menu[5] = array( __('Posts'), 'edit_posts', 'edit.php', '', 'open-if-no-js menu-top menu-icon-post', 'menu-posts', 'none' );
+ $submenu['edit.php'][5] = array( __('All Posts'), 'edit_posts', 'edit.php' );
+ /* translators: add new post */
+ $submenu['edit.php'][10] = array( _x('Add New', 'post'), get_post_type_object( 'post' )->cap->create_posts, 'post-new.php' );
+
+ $i = 15;
+ foreach ( get_taxonomies( array(), 'objects' ) as $tax ) {
+ if ( ! $tax->show_ui || ! in_array('post', (array) $tax->object_type, true) )
+ continue;
+
+ $submenu['edit.php'][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, 'edit-tags.php?taxonomy=' . $tax->name );
+ }
+ unset($tax);
+
+$menu[10] = array( __('Media'), 'upload_files', 'upload.php', '', 'menu-top menu-icon-media', 'menu-media', 'none' );
+ $submenu['upload.php'][5] = array( __('Library'), 'upload_files', 'upload.php');
+ /* translators: add new file */
+ $submenu['upload.php'][10] = array( _x('Add New', 'file'), 'upload_files', 'media-new.php');
+ foreach ( get_taxonomies_for_attachments( 'objects' ) as $tax ) {
+ if ( ! $tax->show_ui )
+ continue;
+
+ $submenu['upload.php'][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, 'edit-tags.php?taxonomy=' . $tax->name . '&amp;post_type=attachment' );
+ }
+ unset($tax);
+
+$menu[15] = array( __('Links'), 'manage_links', 'link-manager.php', '', 'menu-top menu-icon-links', 'menu-links', 'none' );
+ $submenu['link-manager.php'][5] = array( _x('All Links', 'admin menu'), 'manage_links', 'link-manager.php' );
+ /* translators: add new links */
+ $submenu['link-manager.php'][10] = array( _x('Add New', 'link'), 'manage_links', 'link-add.php' );
+ $submenu['link-manager.php'][15] = array( __('Link Categories'), 'manage_categories', 'edit-tags.php?taxonomy=link_category' );
+
+$menu[20] = array( __('Pages'), 'edit_pages', 'edit.php?post_type=page', '', 'menu-top menu-icon-page', 'menu-pages', 'none' );
+ $submenu['edit.php?post_type=page'][5] = array( __('All Pages'), 'edit_pages', 'edit.php?post_type=page' );
+ /* translators: add new page */
+ $submenu['edit.php?post_type=page'][10] = array( _x('Add New', 'page'), get_post_type_object( 'page' )->cap->create_posts, 'post-new.php?post_type=page' );
+ $i = 15;
+ foreach ( get_taxonomies( array(), 'objects' ) as $tax ) {
+ if ( ! $tax->show_ui || ! in_array('page', (array) $tax->object_type, true) )
+ continue;
+
+ $submenu['edit.php?post_type=page'][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, 'edit-tags.php?taxonomy=' . $tax->name . '&amp;post_type=page' );
+ }
+ unset($tax);
+
+$awaiting_mod = wp_count_comments();
+$awaiting_mod = $awaiting_mod->moderated;
+$menu[25] = array( sprintf( __('Comments %s'), "<span class='awaiting-mod count-$awaiting_mod'><span class='pending-count'>" . number_format_i18n($awaiting_mod) . "</span></span>" ), 'edit_posts', 'edit-comments.php', '', 'menu-top menu-icon-comments', 'menu-comments', 'none' );
+unset($awaiting_mod);
+
+$submenu[ 'edit-comments.php' ][0] = array( __('All Comments'), 'edit_posts', 'edit-comments.php' );
+
+$_wp_last_object_menu = 25; // The index of the last top-level menu in the object menu group
+
+foreach ( (array) get_post_types( array('show_ui' => true, '_builtin' => false, 'show_in_menu' => true ) ) as $ptype ) {
+ $ptype_obj = get_post_type_object( $ptype );
+ // Check if it should be a submenu.
+ if ( $ptype_obj->show_in_menu !== true )
+ continue;
+ $ptype_menu_position = is_int( $ptype_obj->menu_position ) ? $ptype_obj->menu_position : ++$_wp_last_object_menu; // If we're to use $_wp_last_object_menu, increment it first.
+ $ptype_for_id = sanitize_html_class( $ptype );
+ if ( is_string( $ptype_obj->menu_icon ) ) {
+ $menu_icon = esc_url( $ptype_obj->menu_icon );
+ $ptype_class = $ptype_for_id;
+ } else {
+ $menu_icon = 'none';
+ $ptype_class = 'post';
+ }
+
+ // if $ptype_menu_position is already populated or will be populated by a hard-coded value below, increment the position.
+ $core_menu_positions = array(59, 60, 65, 70, 75, 80, 85, 99);
+ while ( isset($menu[$ptype_menu_position]) || in_array($ptype_menu_position, $core_menu_positions) )
+ $ptype_menu_position++;
+
+ $menu[$ptype_menu_position] = array( esc_attr( $ptype_obj->labels->menu_name ), $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype", '', 'menu-top menu-icon-' . $ptype_class, 'menu-posts-' . $ptype_for_id, $menu_icon );
+ $submenu["edit.php?post_type=$ptype"][5] = array( $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype");
+ $submenu["edit.php?post_type=$ptype"][10] = array( $ptype_obj->labels->add_new, $ptype_obj->cap->create_posts, "post-new.php?post_type=$ptype" );
+
+ $i = 15;
+ foreach ( get_taxonomies( array(), 'objects' ) as $tax ) {
+ if ( ! $tax->show_ui || ! in_array($ptype, (array) $tax->object_type, true) )
+ continue;
+
+ $submenu["edit.php?post_type=$ptype"][$i++] = array( esc_attr( $tax->labels->menu_name ), $tax->cap->manage_terms, "edit-tags.php?taxonomy=$tax->name&amp;post_type=$ptype" );
+ }
+}
+unset($ptype, $ptype_obj, $ptype_class, $ptype_for_id, $ptype_menu_position, $menu_icon, $i, $tax);
+
+$menu[59] = array( '', 'read', 'separator2', '', 'wp-menu-separator' );
+
+$appearance_cap = current_user_can( 'switch_themes') ? 'switch_themes' : 'edit_theme_options';
+
+$menu[60] = array( __('Appearance'), $appearance_cap, 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' );
+ $submenu['themes.php'][5] = array( __( 'Themes' ), $appearance_cap, 'themes.php' );
+ $submenu['themes.php'][6] = array( __( 'Customize' ), 'edit_theme_options', 'customize.php', 'hide-if-no-customize' );
+ if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) )
+ $submenu['themes.php'][10] = array(__( 'Menus' ), 'edit_theme_options', 'nav-menus.php');
+
+unset( $appearance_cap );
+
+// Add 'Editor' to the bottom of the Appearance menu.
+if ( ! is_multisite() )
+ add_action('admin_menu', '_add_themes_utility_last', 101);
+function _add_themes_utility_last() {
+ // Must use API on the admin_menu hook, direct modification is only possible on/before the _admin_menu hook
+ add_submenu_page('themes.php', _x('Editor', 'theme editor'), _x('Editor', 'theme editor'), 'edit_themes', 'theme-editor.php');
+}
+
+$count = '';
+if ( ! is_multisite() && current_user_can( 'update_plugins' ) ) {
+ if ( ! isset( $update_data ) )
+ $update_data = wp_get_update_data();
+ $count = "<span class='update-plugins count-{$update_data['counts']['plugins']}'><span class='plugin-count'>" . number_format_i18n($update_data['counts']['plugins']) . "</span></span>";
+}
+
+$menu[65] = array( sprintf( __('Plugins %s'), $count ), 'activate_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'none' );
+
+$submenu['plugins.php'][5] = array( __('Installed Plugins'), 'activate_plugins', 'plugins.php' );
+
+ if ( ! is_multisite() ) {
+ /* translators: add new plugin */
+ $submenu['plugins.php'][10] = array( _x('Add New', 'plugin'), 'install_plugins', 'plugin-install.php' );
+ $submenu['plugins.php'][15] = array( _x('Editor', 'plugin editor'), 'edit_plugins', 'plugin-editor.php' );
+ }
+
+unset( $update_data );
+
+if ( current_user_can('list_users') )
+ $menu[70] = array( __('Users'), 'list_users', 'users.php', '', 'menu-top menu-icon-users', 'menu-users', 'none' );
+else
+ $menu[70] = array( __('Profile'), 'read', 'profile.php', '', 'menu-top menu-icon-users', 'menu-users', 'none' );
+
+if ( current_user_can('list_users') ) {
+ $_wp_real_parent_file['profile.php'] = 'users.php'; // Back-compat for plugins adding submenus to profile.php.
+ $submenu['users.php'][5] = array(__('All Users'), 'list_users', 'users.php');
+ if ( current_user_can('create_users') )
+ $submenu['users.php'][10] = array(_x('Add New', 'user'), 'create_users', 'user-new.php');
+ else
+ $submenu['users.php'][10] = array(_x('Add New', 'user'), 'promote_users', 'user-new.php');
+
+ $submenu['users.php'][15] = array(__('Your Profile'), 'read', 'profile.php');
+} else {
+ $_wp_real_parent_file['users.php'] = 'profile.php';
+ $submenu['profile.php'][5] = array(__('Your Profile'), 'read', 'profile.php');
+ if ( current_user_can('create_users') )
+ $submenu['profile.php'][10] = array(__('Add New User'), 'create_users', 'user-new.php');
+ else
+ $submenu['profile.php'][10] = array(__('Add New User'), 'promote_users', 'user-new.php');
+}
+
+$menu[75] = array( __('Tools'), 'edit_posts', 'tools.php', '', 'menu-top menu-icon-tools', 'menu-tools', 'none' );
+ $submenu['tools.php'][5] = array( __('Available Tools'), 'edit_posts', 'tools.php' );
+ $submenu['tools.php'][10] = array( __('Import'), 'import', 'import.php' );
+ $submenu['tools.php'][15] = array( __('Export'), 'export', 'export.php' );
+ if ( is_multisite() && !is_main_site() )
+ $submenu['tools.php'][25] = array( __('Delete Site'), 'manage_options', 'ms-delete-site.php' );
+ if ( ! is_multisite() && defined('WP_ALLOW_MULTISITE') && WP_ALLOW_MULTISITE )
+ $submenu['tools.php'][50] = array(__('Network Setup'), 'manage_options', 'network.php');
+
+$menu[80] = array( __('Settings'), 'manage_options', 'options-general.php', '', 'menu-top menu-icon-settings', 'menu-settings', 'none' );
+ $submenu['options-general.php'][10] = array(_x('General', 'settings screen'), 'manage_options', 'options-general.php');
+ $submenu['options-general.php'][15] = array(__('Writing'), 'manage_options', 'options-writing.php');
+ $submenu['options-general.php'][20] = array(__('Reading'), 'manage_options', 'options-reading.php');
+ $submenu['options-general.php'][25] = array(__('Discussion'), 'manage_options', 'options-discussion.php');
+ $submenu['options-general.php'][30] = array(__('Media'), 'manage_options', 'options-media.php');
+ $submenu['options-general.php'][40] = array(__('Permalinks'), 'manage_options', 'options-permalink.php');
+
+$_wp_last_utility_menu = 80; // The index of the last top-level menu in the utility menu group
+
+$menu[99] = array( '', 'read', 'separator-last', '', 'wp-menu-separator' );
+
+// Back-compat for old top-levels
+$_wp_real_parent_file['post.php'] = 'edit.php';
+$_wp_real_parent_file['post-new.php'] = 'edit.php';
+$_wp_real_parent_file['edit-pages.php'] = 'edit.php?post_type=page';
+$_wp_real_parent_file['page-new.php'] = 'edit.php?post_type=page';
+$_wp_real_parent_file['wpmu-admin.php'] = 'tools.php';
+$_wp_real_parent_file['ms-admin.php'] = 'tools.php';
+
+// ensure we're backwards compatible
+$compat = array(
+ 'index' => 'dashboard',
+ 'edit' => 'posts',
+ 'post' => 'posts',
+ 'upload' => 'media',
+ 'link-manager' => 'links',
+ 'edit-pages' => 'pages',
+ 'page' => 'pages',
+ 'edit-comments' => 'comments',
+ 'options-general' => 'settings',
+ 'themes' => 'appearance',
+ );
+
+require_once(ABSPATH . 'wp-admin/includes/menu.php');
diff --git a/src/wp-admin/moderation.php b/src/wp-admin/moderation.php
new file mode 100644
index 0000000000..9129795de6
--- /dev/null
+++ b/src/wp-admin/moderation.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Comment Moderation Administration Screen.
+ *
+ * Redirects to edit-comments.php?comment_status=moderated.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+require_once('../wp-load.php');
+wp_redirect( admin_url('edit-comments.php?comment_status=moderated') );
+exit;
diff --git a/src/wp-admin/ms-admin.php b/src/wp-admin/ms-admin.php
new file mode 100644
index 0000000000..fe5e19bc87
--- /dev/null
+++ b/src/wp-admin/ms-admin.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Multisite administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+wp_redirect( network_admin_url() );
+exit;
diff --git a/src/wp-admin/ms-delete-site.php b/src/wp-admin/ms-delete-site.php
new file mode 100644
index 0000000000..7d772c2658
--- /dev/null
+++ b/src/wp-admin/ms-delete-site.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Multisite delete site panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+if ( !is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+// @todo Create a delete blog cap.
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die(__( 'You do not have sufficient permissions to delete this site.'));
+
+if ( isset( $_GET['h'] ) && $_GET['h'] != '' && get_option( 'delete_blog_hash' ) != false ) {
+ if ( get_option( 'delete_blog_hash' ) == $_GET['h'] ) {
+ wpmu_delete_blog( $wpdb->blogid );
+ wp_die( sprintf( __( 'Thank you for using %s, your site has been deleted. Happy trails to you until we meet again.' ), $current_site->site_name ) );
+ } else {
+ wp_die( __( "I'm sorry, the link you clicked is stale. Please select another option." ) );
+ }
+}
+
+$blog = get_blog_details();
+
+$title = __( 'Delete Site' );
+$parent_file = 'tools.php';
+require_once( './admin-header.php' );
+
+echo '<div class="wrap">';
+screen_icon();
+echo '<h2>' . esc_html( $title ) . '</h2>';
+
+if ( isset( $_POST['action'] ) && $_POST['action'] == 'deleteblog' && isset( $_POST['confirmdelete'] ) && $_POST['confirmdelete'] == '1' ) {
+ check_admin_referer( 'delete-blog' );
+
+ $hash = wp_generate_password( 20, false );
+ update_option( 'delete_blog_hash', $hash );
+
+ $url_delete = esc_url( admin_url( 'ms-delete-site.php?h=' . $hash ) );
+
+ $content = apply_filters( 'delete_site_email_content', __( "Dear User,
+You recently clicked the 'Delete Site' link on your site and filled in a
+form on that page.
+If you really want to delete your site, click the link below. You will not
+be asked to confirm again so only click this link if you are absolutely certain:
+###URL_DELETE###
+
+If you delete your site, please consider opening a new site here
+some time in the future! (But remember your current site and username
+are gone forever.)
+
+Thanks for using the site,
+Webmaster
+###SITE_NAME###" ) );
+
+ $content = str_replace( '###URL_DELETE###', $url_delete, $content );
+ $content = str_replace( '###SITE_NAME###', $current_site->site_name, $content );
+
+ wp_mail( get_option( 'admin_email' ), "[ " . get_option( 'blogname' ) . " ] ".__( 'Delete My Site' ), $content );
+ ?>
+
+ <p><?php _e( 'Thank you. Please check your email for a link to confirm your action. Your site will not be deleted until this link is clicked. ') ?></p>
+
+<?php } else {
+ ?>
+ <p><?php printf( __( 'If you do not want to use your %s site any more, you can delete it using the form below. When you click <strong>Delete My Site Permanently</strong> you will be sent an email with a link in it. Click on this link to delete your site.'), $current_site->site_name); ?></p>
+ <p><?php _e( 'Remember, once deleted your site cannot be restored.' ) ?></p>
+
+ <form method="post" name="deletedirect">
+ <?php wp_nonce_field( 'delete-blog' ) ?>
+ <input type="hidden" name="action" value="deleteblog" />
+ <p><input id="confirmdelete" type="checkbox" name="confirmdelete" value="1" /> <label for="confirmdelete"><strong><?php printf( __( "I'm sure I want to permanently disable my site, and I am aware I can never get it back or use %s again." ), is_subdomain_install() ? $blog->domain : $blog->domain . $blog->path ); ?></strong></label></p>
+ <?php submit_button( __( 'Delete My Site Permanently' ) ); ?>
+ </form>
+ <?php
+}
+echo '</div>';
+
+include( './admin-footer.php' );
diff --git a/src/wp-admin/ms-edit.php b/src/wp-admin/ms-edit.php
new file mode 100644
index 0000000000..6e56e026a9
--- /dev/null
+++ b/src/wp-admin/ms-edit.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Action handler for Multisite administration panels.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+wp_redirect( network_admin_url() );
+exit;
diff --git a/src/wp-admin/ms-options.php b/src/wp-admin/ms-options.php
new file mode 100644
index 0000000000..784ac24f17
--- /dev/null
+++ b/src/wp-admin/ms-options.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Multisite network settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+wp_redirect( network_admin_url('settings.php') ); \ No newline at end of file
diff --git a/src/wp-admin/ms-sites.php b/src/wp-admin/ms-sites.php
new file mode 100644
index 0000000000..00502c915a
--- /dev/null
+++ b/src/wp-admin/ms-sites.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Multisite sites administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+wp_redirect( network_admin_url('sites.php') );
+exit;
diff --git a/src/wp-admin/ms-themes.php b/src/wp-admin/ms-themes.php
new file mode 100644
index 0000000000..ad873babb4
--- /dev/null
+++ b/src/wp-admin/ms-themes.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Multisite themes administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+wp_redirect( network_admin_url('themes.php') );
+exit;
diff --git a/src/wp-admin/ms-upgrade-network.php b/src/wp-admin/ms-upgrade-network.php
new file mode 100644
index 0000000000..3d36a2cc59
--- /dev/null
+++ b/src/wp-admin/ms-upgrade-network.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Multisite upgrade administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once('admin.php');
+
+wp_redirect( network_admin_url('upgrade.php') );
+exit;
diff --git a/src/wp-admin/ms-users.php b/src/wp-admin/ms-users.php
new file mode 100644
index 0000000000..a3be929ac7
--- /dev/null
+++ b/src/wp-admin/ms-users.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Multisite users administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+wp_redirect( network_admin_url('users.php') );
+exit;
diff --git a/src/wp-admin/my-sites.php b/src/wp-admin/my-sites.php
new file mode 100644
index 0000000000..2ef4ca77e8
--- /dev/null
+++ b/src/wp-admin/my-sites.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * My Sites dashboard.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+require_once( './admin.php' );
+
+if ( !is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can('read') )
+ wp_die( __( 'You do not have sufficient permissions to view this page.' ) );
+
+$action = isset( $_POST['action'] ) ? $_POST['action'] : 'splash';
+
+$blogs = get_blogs_of_user( $current_user->ID );
+
+$updated = false;
+if ( 'updateblogsettings' == $action && isset( $_POST['primary_blog'] ) ) {
+ check_admin_referer( 'update-my-sites' );
+
+ $blog = get_blog_details( (int) $_POST['primary_blog'] );
+ if ( $blog && isset( $blog->domain ) ) {
+ update_user_option( $current_user->ID, 'primary_blog', (int) $_POST['primary_blog'], true );
+ $updated = true;
+ } else {
+ wp_die( __( 'The primary site you chose does not exist.' ) );
+ }
+}
+
+$title = __( 'My Sites' );
+$parent_file = 'index.php';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen shows an individual user all of their sites in this network, and also allows that user to set a primary site. He or she can use the links under each site to visit either the frontend or the dashboard for that site.') . '</p>' .
+ '<p>' . __('Up until WordPress version 3.0, what is now called a Multisite Network had to be installed separately as WordPress MU (multi-user).') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Dashboard_My_Sites_Screen" target="_blank">Documentation on My Sites</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+require_once( './admin-header.php' );
+
+if ( $updated ) { ?>
+ <div id="message" class="updated"><p><strong><?php _e( 'Settings saved.' ); ?></strong></p></div>
+<?php } ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+<?php
+if ( empty( $blogs ) ) :
+ echo '<p>';
+ _e( 'You must be a member of at least one site to use this page.' );
+ echo '</p>';
+else :
+?>
+<form id="myblogs" action="" method="post">
+ <?php
+ choose_primary_blog();
+ do_action( 'myblogs_allblogs_options' );
+ ?>
+ <br clear="all" />
+ <table class="widefat fixed">
+ <?php
+ $settings_html = apply_filters( 'myblogs_options', '', 'global' );
+ if ( $settings_html != '' ) {
+ echo '<tr><td valign="top"><h3>' . __( 'Global Settings' ) . '</h3></td><td>';
+ echo $settings_html;
+ echo '</td></tr>';
+ }
+ reset( $blogs );
+ $num = count( $blogs );
+ $cols = 1;
+ if ( $num >= 20 )
+ $cols = 4;
+ elseif ( $num >= 10 )
+ $cols = 2;
+ $num_rows = ceil( $num / $cols );
+ $split = 0;
+ for ( $i = 1; $i <= $num_rows; $i++ ) {
+ $rows[] = array_slice( $blogs, $split, $cols );
+ $split = $split + $cols;
+ }
+
+ $c = '';
+ foreach ( $rows as $row ) {
+ $c = $c == 'alternate' ? '' : 'alternate';
+ echo "<tr class='$c'>";
+ $i = 0;
+ foreach ( $row as $user_blog ) {
+ $s = $i == 3 ? '' : 'border-right: 1px solid #ccc;';
+ echo "<td valign='top' style='$s'>";
+ echo "<h3>{$user_blog->blogname}</h3>";
+ echo "<p>" . apply_filters( 'myblogs_blog_actions', "<a href='" . esc_url( get_home_url( $user_blog->userblog_id ) ). "'>" . __( 'Visit' ) . "</a> | <a href='" . esc_url( get_admin_url( $user_blog->userblog_id ) ) . "'>" . __( 'Dashboard' ) . "</a>", $user_blog ) . "</p>";
+ echo apply_filters( 'myblogs_options', '', $user_blog );
+ echo "</td>";
+ $i++;
+ }
+ echo "</tr>";
+ }?>
+ </table>
+ <input type="hidden" name="action" value="updateblogsettings" />
+ <?php wp_nonce_field( 'update-my-sites' ); ?>
+ <?php submit_button(); ?>
+ </form>
+<?php endif; ?>
+ </div>
+<?php
+include( './admin-footer.php' );
diff --git a/src/wp-admin/nav-menus.php b/src/wp-admin/nav-menus.php
new file mode 100644
index 0000000000..d012487806
--- /dev/null
+++ b/src/wp-admin/nav-menus.php
@@ -0,0 +1,764 @@
+<?php
+/**
+ * WordPress Administration for Navigation Menus
+ * Interface functions
+ *
+ * @version 2.0.0
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+// Load all the nav menu interface functions
+require_once( ABSPATH . 'wp-admin/includes/nav-menu.php' );
+
+if ( ! current_theme_supports( 'menus' ) && ! current_theme_supports( 'widgets' ) )
+ wp_die( __( 'Your theme does not support navigation menus or widgets.' ) );
+
+// Permissions Check
+if ( ! current_user_can('edit_theme_options') )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+wp_enqueue_script( 'nav-menu' );
+
+if ( wp_is_mobile() )
+ wp_enqueue_script( 'jquery-touch-punch' );
+
+// Container for any messages displayed to the user
+$messages = array();
+
+// Container that stores the name of the active menu
+$nav_menu_selected_title = '';
+
+// The menu id of the current menu being edited
+$nav_menu_selected_id = isset( $_REQUEST['menu'] ) ? (int) $_REQUEST['menu'] : 0;
+
+// Get existing menu locations assignments
+$locations = get_registered_nav_menus();
+$menu_locations = get_nav_menu_locations();
+$num_locations = count( array_keys( $locations ) );
+
+// Allowed actions: add, update, delete
+$action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : 'edit';
+
+switch ( $action ) {
+ case 'add-menu-item':
+ check_admin_referer( 'add-menu_item', 'menu-settings-column-nonce' );
+ if ( isset( $_REQUEST['nav-menu-locations'] ) )
+ set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_REQUEST['menu-locations'] ) );
+ elseif ( isset( $_REQUEST['menu-item'] ) )
+ wp_save_nav_menu_items( $nav_menu_selected_id, $_REQUEST['menu-item'] );
+ break;
+ case 'move-down-menu-item' :
+ // moving down a menu item is the same as moving up the next in order
+ check_admin_referer( 'move-menu_item' );
+ $menu_item_id = isset( $_REQUEST['menu-item'] ) ? (int) $_REQUEST['menu-item'] : 0;
+ if ( is_nav_menu_item( $menu_item_id ) ) {
+ $menus = isset( $_REQUEST['menu'] ) ? array( (int) $_REQUEST['menu'] ) : wp_get_object_terms( $menu_item_id, 'nav_menu', array( 'fields' => 'ids' ) );
+ if ( ! is_wp_error( $menus ) && ! empty( $menus[0] ) ) {
+ $menu_id = (int) $menus[0];
+ $ordered_menu_items = wp_get_nav_menu_items( $menu_id );
+ $menu_item_data = (array) wp_setup_nav_menu_item( get_post( $menu_item_id ) );
+
+ // set up the data we need in one pass through the array of menu items
+ $dbids_to_orders = array();
+ $orders_to_dbids = array();
+ foreach( (array) $ordered_menu_items as $ordered_menu_item_object ) {
+ if ( isset( $ordered_menu_item_object->ID ) ) {
+ if ( isset( $ordered_menu_item_object->menu_order ) ) {
+ $dbids_to_orders[$ordered_menu_item_object->ID] = $ordered_menu_item_object->menu_order;
+ $orders_to_dbids[$ordered_menu_item_object->menu_order] = $ordered_menu_item_object->ID;
+ }
+ }
+ }
+
+ // get next in order
+ if (
+ isset( $orders_to_dbids[$dbids_to_orders[$menu_item_id] + 1] )
+ ) {
+ $next_item_id = $orders_to_dbids[$dbids_to_orders[$menu_item_id] + 1];
+ $next_item_data = (array) wp_setup_nav_menu_item( get_post( $next_item_id ) );
+
+ // if not siblings of same parent, bubble menu item up but keep order
+ if (
+ ! empty( $menu_item_data['menu_item_parent'] ) &&
+ (
+ empty( $next_item_data['menu_item_parent'] ) ||
+ $next_item_data['menu_item_parent'] != $menu_item_data['menu_item_parent']
+ )
+ ) {
+
+ $parent_db_id = in_array( $menu_item_data['menu_item_parent'], $orders_to_dbids ) ? (int) $menu_item_data['menu_item_parent'] : 0;
+
+ $parent_object = wp_setup_nav_menu_item( get_post( $parent_db_id ) );
+
+ if ( ! is_wp_error( $parent_object ) ) {
+ $parent_data = (array) $parent_object;
+ $menu_item_data['menu_item_parent'] = $parent_data['menu_item_parent'];
+ update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
+
+ }
+
+ // make menu item a child of its next sibling
+ } else {
+ $next_item_data['menu_order'] = $next_item_data['menu_order'] - 1;
+ $menu_item_data['menu_order'] = $menu_item_data['menu_order'] + 1;
+
+ $menu_item_data['menu_item_parent'] = $next_item_data['ID'];
+ update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
+
+ wp_update_post($menu_item_data);
+ wp_update_post($next_item_data);
+ }
+
+ // the item is last but still has a parent, so bubble up
+ } elseif (
+ ! empty( $menu_item_data['menu_item_parent'] ) &&
+ in_array( $menu_item_data['menu_item_parent'], $orders_to_dbids )
+ ) {
+ $menu_item_data['menu_item_parent'] = (int) get_post_meta( $menu_item_data['menu_item_parent'], '_menu_item_menu_item_parent', true);
+ update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
+ }
+ }
+ }
+
+ break;
+ case 'move-up-menu-item' :
+ check_admin_referer( 'move-menu_item' );
+ $menu_item_id = isset( $_REQUEST['menu-item'] ) ? (int) $_REQUEST['menu-item'] : 0;
+ if ( is_nav_menu_item( $menu_item_id ) ) {
+ $menus = isset( $_REQUEST['menu'] ) ? array( (int) $_REQUEST['menu'] ) : wp_get_object_terms( $menu_item_id, 'nav_menu', array( 'fields' => 'ids' ) );
+ if ( ! is_wp_error( $menus ) && ! empty( $menus[0] ) ) {
+ $menu_id = (int) $menus[0];
+ $ordered_menu_items = wp_get_nav_menu_items( $menu_id );
+ $menu_item_data = (array) wp_setup_nav_menu_item( get_post( $menu_item_id ) );
+
+ // set up the data we need in one pass through the array of menu items
+ $dbids_to_orders = array();
+ $orders_to_dbids = array();
+ foreach( (array) $ordered_menu_items as $ordered_menu_item_object ) {
+ if ( isset( $ordered_menu_item_object->ID ) ) {
+ if ( isset( $ordered_menu_item_object->menu_order ) ) {
+ $dbids_to_orders[$ordered_menu_item_object->ID] = $ordered_menu_item_object->menu_order;
+ $orders_to_dbids[$ordered_menu_item_object->menu_order] = $ordered_menu_item_object->ID;
+ }
+ }
+ }
+
+ // if this menu item is not first
+ if ( ! empty( $dbids_to_orders[$menu_item_id] ) && ! empty( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) ) {
+
+ // if this menu item is a child of the previous
+ if (
+ ! empty( $menu_item_data['menu_item_parent'] ) &&
+ in_array( $menu_item_data['menu_item_parent'], array_keys( $dbids_to_orders ) ) &&
+ isset( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) &&
+ ( $menu_item_data['menu_item_parent'] == $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] )
+ ) {
+ $parent_db_id = in_array( $menu_item_data['menu_item_parent'], $orders_to_dbids ) ? (int) $menu_item_data['menu_item_parent'] : 0;
+ $parent_object = wp_setup_nav_menu_item( get_post( $parent_db_id ) );
+
+ if ( ! is_wp_error( $parent_object ) ) {
+ $parent_data = (array) $parent_object;
+
+ // if there is something before the parent and parent a child of it, make menu item a child also of it
+ if (
+ ! empty( $dbids_to_orders[$parent_db_id] ) &&
+ ! empty( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1] ) &&
+ ! empty( $parent_data['menu_item_parent'] )
+ ) {
+ $menu_item_data['menu_item_parent'] = $parent_data['menu_item_parent'];
+
+ // else if there is something before parent and parent not a child of it, make menu item a child of that something's parent
+ } elseif (
+ ! empty( $dbids_to_orders[$parent_db_id] ) &&
+ ! empty( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1] )
+ ) {
+ $_possible_parent_id = (int) get_post_meta( $orders_to_dbids[$dbids_to_orders[$parent_db_id] - 1], '_menu_item_menu_item_parent', true);
+ if ( in_array( $_possible_parent_id, array_keys( $dbids_to_orders ) ) )
+ $menu_item_data['menu_item_parent'] = $_possible_parent_id;
+ else
+ $menu_item_data['menu_item_parent'] = 0;
+
+ // else there isn't something before the parent
+ } else {
+ $menu_item_data['menu_item_parent'] = 0;
+ }
+
+ // set former parent's [menu_order] to that of menu-item's
+ $parent_data['menu_order'] = $parent_data['menu_order'] + 1;
+
+ // set menu-item's [menu_order] to that of former parent
+ $menu_item_data['menu_order'] = $menu_item_data['menu_order'] - 1;
+
+ // save changes
+ update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
+ wp_update_post($menu_item_data);
+ wp_update_post($parent_data);
+ }
+
+ // else this menu item is not a child of the previous
+ } elseif (
+ empty( $menu_item_data['menu_order'] ) ||
+ empty( $menu_item_data['menu_item_parent'] ) ||
+ ! in_array( $menu_item_data['menu_item_parent'], array_keys( $dbids_to_orders ) ) ||
+ empty( $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] ) ||
+ $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1] != $menu_item_data['menu_item_parent']
+ ) {
+ // just make it a child of the previous; keep the order
+ $menu_item_data['menu_item_parent'] = (int) $orders_to_dbids[$dbids_to_orders[$menu_item_id] - 1];
+ update_post_meta( $menu_item_data['ID'], '_menu_item_menu_item_parent', (int) $menu_item_data['menu_item_parent'] );
+ wp_update_post($menu_item_data);
+ }
+ }
+ }
+ }
+ break;
+
+ case 'delete-menu-item':
+ $menu_item_id = (int) $_REQUEST['menu-item'];
+
+ check_admin_referer( 'delete-menu_item_' . $menu_item_id );
+
+ if ( is_nav_menu_item( $menu_item_id ) && wp_delete_post( $menu_item_id, true ) )
+ $messages[] = '<div id="message" class="updated"><p>' . __('The menu item has been successfully deleted.') . '</p></div>';
+ break;
+
+ case 'delete':
+ check_admin_referer( 'delete-nav_menu-' . $nav_menu_selected_id );
+ if ( is_nav_menu( $nav_menu_selected_id ) ) {
+ $deletion = wp_delete_nav_menu( $nav_menu_selected_id );
+ } else {
+ // Reset the selected menu
+ $nav_menu_selected_id = 0;
+ unset( $_REQUEST['menu'] );
+ }
+
+ if ( ! isset( $deletion ) )
+ break;
+
+ if ( is_wp_error( $deletion ) )
+ $messages[] = '<div id="message" class="error"><p>' . $deletion->get_error_message() . '</p></div>';
+ else
+ $messages[] = '<div id="message" class="updated"><p>' . __( 'The menu has been successfully deleted.' ) . '</p></div>';
+ break;
+
+ case 'delete_menus':
+ check_admin_referer( 'nav_menus_bulk_actions' );
+ foreach ( $_REQUEST['delete_menus'] as $menu_id_to_delete ) {
+ if ( ! is_nav_menu( $menu_id_to_delete ) )
+ continue;
+
+ $deletion = wp_delete_nav_menu( $menu_id_to_delete );
+ if ( is_wp_error( $deletion ) ) {
+ $messages[] = '<div id="message" class="error"><p>' . $deletion->get_error_message() . '</p></div>';
+ $deletion_error = true;
+ }
+ }
+
+ if ( empty( $deletion_error ) )
+ $messages[] = '<div id="message" class="updated"><p>' . __( 'Selected menus have been successfully deleted.' ) . '</p></div>';
+ break;
+
+ case 'update':
+ check_admin_referer( 'update-nav_menu', 'update-nav-menu-nonce' );
+
+ // Remove menu locations that have been unchecked
+ foreach ( $locations as $location => $description ) {
+ if ( ( empty( $_POST['menu-locations'] ) || empty( $_POST['menu-locations'][ $location ] ) ) && isset( $menu_locations[ $location ] ) && $menu_locations[ $location ] == $nav_menu_selected_id )
+ unset( $menu_locations[ $location ] );
+ }
+
+ // Merge new and existing menu locations if any new ones are set
+ if ( isset( $_POST['menu-locations'] ) ) {
+ $new_menu_locations = array_map( 'absint', $_POST['menu-locations'] );
+ $menu_locations = array_merge( $menu_locations, $new_menu_locations );
+ }
+
+ // Set menu locations
+ set_theme_mod( 'nav_menu_locations', $menu_locations );
+
+ // Add Menu
+ if ( 0 == $nav_menu_selected_id ) {
+ $new_menu_title = trim( esc_html( $_POST['menu-name'] ) );
+
+ if ( $new_menu_title ) {
+ $_nav_menu_selected_id = wp_update_nav_menu_object( 0, array('menu-name' => $new_menu_title) );
+
+ if ( is_wp_error( $_nav_menu_selected_id ) ) {
+ $messages[] = '<div id="message" class="error"><p>' . $_nav_menu_selected_id->get_error_message() . '</p></div>';
+ } else {
+ $_menu_object = wp_get_nav_menu_object( $_nav_menu_selected_id );
+ $nav_menu_selected_id = $_nav_menu_selected_id;
+ $nav_menu_selected_title = $_menu_object->name;
+ if ( isset( $_REQUEST['menu-item'] ) )
+ wp_save_nav_menu_items( $nav_menu_selected_id, absint( $_REQUEST['menu-item'] ) );
+ if ( isset( $_REQUEST['zero-menu-state'] ) ) {
+ // If there are menu items, add them
+ wp_nav_menu_update_menu_items( $nav_menu_selected_id, $nav_menu_selected_title );
+ // Auto-save nav_menu_locations
+ $locations = get_theme_mod( 'nav_menu_locations' );
+ foreach ( (array) $locations as $location => $menu_id ) {
+ $locations[ $location ] = $nav_menu_selected_id;
+ break; // There should only be 1
+ }
+ set_theme_mod( 'nav_menu_locations', $locations );
+ }
+ if ( isset( $_REQUEST['use-location'] ) ) {
+ $locations = get_theme_mod( 'nav_menu_locations' );
+ if ( isset( $locations[$_REQUEST['use-location']] ) )
+ $locations[$_REQUEST['use-location']] = $nav_menu_selected_id;
+ set_theme_mod( 'nav_menu_locations', $locations );
+ }
+ // $messages[] = '<div id="message" class="updated"><p>' . sprintf( __( '<strong>%s</strong> has been created.' ), $nav_menu_selected_title ) . '</p></div>';
+ wp_redirect( admin_url( 'nav-menus.php?menu=' . $_nav_menu_selected_id ) );
+ exit();
+ }
+ } else {
+ $messages[] = '<div id="message" class="error"><p>' . __( 'Please enter a valid menu name.' ) . '</p></div>';
+ }
+
+ // Update existing menu
+ } else {
+
+ $_menu_object = wp_get_nav_menu_object( $nav_menu_selected_id );
+
+ $menu_title = trim( esc_html( $_POST['menu-name'] ) );
+ if ( ! $menu_title ) {
+ $messages[] = '<div id="message" class="error"><p>' . __( 'Please enter a valid menu name.' ) . '</p></div>';
+ $menu_title = $_menu_object->name;
+ }
+
+ if ( ! is_wp_error( $_menu_object ) ) {
+ $_nav_menu_selected_id = wp_update_nav_menu_object( $nav_menu_selected_id, array( 'menu-name' => $menu_title ) );
+ if ( is_wp_error( $_nav_menu_selected_id ) ) {
+ $_menu_object = $_nav_menu_selected_id;
+ $messages[] = '<div id="message" class="error"><p>' . $_nav_menu_selected_id->get_error_message() . '</p></div>';
+ } else {
+ $_menu_object = wp_get_nav_menu_object( $_nav_menu_selected_id );
+ $nav_menu_selected_title = $_menu_object->name;
+ }
+ }
+
+ // Update menu items
+ if ( ! is_wp_error( $_menu_object ) ) {
+ $messages = array_merge( $messages, wp_nav_menu_update_menu_items( $nav_menu_selected_id, $nav_menu_selected_title ) );
+ }
+ }
+ break;
+ case 'locations':
+ if ( ! $num_locations ) {
+ wp_redirect( admin_url( 'nav-menus.php' ) );
+ exit();
+ }
+
+ add_filter( 'screen_options_show_screen', '__return_false' );
+
+ if ( isset( $_POST['menu-locations'] ) ) {
+ check_admin_referer( 'save-menu-locations' );
+
+ $new_menu_locations = array_map( 'absint', $_POST['menu-locations'] );
+ $menu_locations = array_merge( $menu_locations, $new_menu_locations );
+ // Set menu locations
+ set_theme_mod( 'nav_menu_locations', $menu_locations );
+
+ $messages[] = '<div id="message" class="updated"><p>' . __( 'Menu locations updated.' ) . '</p></div>';
+ }
+ break;
+}
+
+// Get all nav menus
+$nav_menus = wp_get_nav_menus( array('orderby' => 'name') );
+$menu_count = count( $nav_menus );
+
+// Are we on the add new screen?
+$add_new_screen = ( isset( $_GET['menu'] ) && 0 == $_GET['menu'] ) ? true : false;
+
+$locations_screen = ( isset( $_GET['action'] ) && 'locations' == $_GET['action'] ) ? true : false;
+
+// If we have one theme location, and zero menus, we take them right into editing their first menu
+$page_count = wp_count_posts( 'page' );
+$one_theme_location_no_menus = ( 1 == count( get_registered_nav_menus() ) && ! $add_new_screen && empty( $nav_menus ) && ! empty( $page_count->publish ) ) ? true : false;
+
+$nav_menus_l10n = array(
+ 'oneThemeLocationNoMenus' => $one_theme_location_no_menus,
+ 'moveUp' => __( 'Move up one' ),
+ 'moveDown' => __( 'Move down one' ),
+ 'moveToTop' => __( 'Move to the top' ),
+ /* translators: %s: previous item name */
+ 'moveUnder' => __( 'Move under %s' ),
+ /* translators: %s: previous item name */
+ 'moveOutFrom' => __( 'Move out from under %s' ),
+ /* translators: %s: previous item name */
+ 'under' => __( 'Under %s' ),
+ /* translators: %s: previous item name */
+ 'outFrom' => __( 'Out from under %s' ),
+ /* translators: 1: item name, 2: item position, 3: total number of items */
+ 'menuFocus' => __( '%1$s. Menu item %2$d of %3$d.' ),
+ /* translators: 1: item name, 2: item position, 3: parent item name */
+ 'subMenuFocus' => __( '%1$s. Sub item number %2$d under %3$s.' ),
+);
+wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n );
+
+// Redirect to add screen if there are no menus and this users has either zero, or more than 1 theme locations
+if ( 0 == $menu_count && ! $add_new_screen && ! $one_theme_location_no_menus )
+ wp_redirect( admin_url( 'nav-menus.php?action=edit&menu=0' ) );
+
+// Get recently edited nav menu
+$recently_edited = absint( get_user_option( 'nav_menu_recently_edited' ) );
+if ( empty( $recently_edited ) && is_nav_menu( $nav_menu_selected_id ) )
+ $recently_edited = $nav_menu_selected_id;
+
+// Use $recently_edited if none are selected
+if ( empty( $nav_menu_selected_id ) && ! isset( $_GET['menu'] ) && is_nav_menu( $recently_edited ) )
+ $nav_menu_selected_id = $recently_edited;
+
+// On deletion of menu, if another menu exists, show it
+if ( ! $add_new_screen && 0 < $menu_count && isset( $_GET['action'] ) && 'delete' == $_GET['action'] )
+ $nav_menu_selected_id = $nav_menus[0]->term_id;
+
+// Set $nav_menu_selected_id to 0 if no menus
+if ( $one_theme_location_no_menus ) {
+ $nav_menu_selected_id = 0;
+} elseif ( empty( $nav_menu_selected_id ) && ! empty( $nav_menus ) && ! $add_new_screen ) {
+ // if we have no selection yet, and we have menus, set to the first one in the list
+ $nav_menu_selected_id = $nav_menus[0]->term_id;
+}
+
+// Update the user's setting
+if ( $nav_menu_selected_id != $recently_edited && is_nav_menu( $nav_menu_selected_id ) )
+ update_user_meta( $current_user->ID, 'nav_menu_recently_edited', $nav_menu_selected_id );
+
+// If there's a menu, get its name.
+if ( ! $nav_menu_selected_title && is_nav_menu( $nav_menu_selected_id ) ) {
+ $_menu_object = wp_get_nav_menu_object( $nav_menu_selected_id );
+ $nav_menu_selected_title = ! is_wp_error( $_menu_object ) ? $_menu_object->name : '';
+}
+
+// Generate truncated menu names
+foreach( (array) $nav_menus as $key => $_nav_menu ) {
+ $nav_menus[$key]->truncated_name = wp_html_excerpt( $_nav_menu->name, 40, '&hellip;' );
+}
+
+// Retrieve menu locations
+if ( current_theme_supports( 'menus' ) ) {
+ $locations = get_registered_nav_menus();
+ $menu_locations = get_nav_menu_locations();
+}
+
+// Ensure the user will be able to scroll horizontally
+// by adding a class for the max menu depth.
+global $_wp_nav_menu_max_depth;
+$_wp_nav_menu_max_depth = 0;
+
+// Calling wp_get_nav_menu_to_edit generates $_wp_nav_menu_max_depth
+if ( is_nav_menu( $nav_menu_selected_id ) ) {
+ $menu_items = wp_get_nav_menu_items( $nav_menu_selected_id, array( 'post_status' => 'any' ) );
+ $edit_markup = wp_get_nav_menu_to_edit( $nav_menu_selected_id );
+}
+
+function wp_nav_menu_max_depth($classes) {
+ global $_wp_nav_menu_max_depth;
+ return "$classes menu-max-depth-$_wp_nav_menu_max_depth";
+}
+
+add_filter('admin_body_class', 'wp_nav_menu_max_depth');
+
+wp_nav_menu_setup();
+wp_initial_nav_menu_meta_boxes();
+
+if ( ! current_theme_supports( 'menus' ) && ! $num_locations )
+ $messages[] = '<div id="message" class="updated"><p>' . sprintf( __( 'Your theme does not natively support menus, but you can use them in sidebars by adding a &#8220;Custom Menu&#8221; widget on the <a href="%s">Widgets</a> screen.' ), admin_url( 'widgets.php' ) ) . '</p></div>';
+
+if ( ! $locations_screen ) : // Main tab
+ $overview = '<p>' . __( 'This screen is used for managing your custom navigation menus.' ) . '</p>';
+ $overview .= '<p>' . sprintf( __( 'Menus can be displayed in locations defined by your theme, even used in sidebars by adding a &#8220;Custom Menu&#8221; widget on the <a href="%1$s">Widgets</a> screen. If your theme does not support the custom menus feature (the default themes, %2$s and %3$s, do), you can learn about adding this support by following the Documentation link to the side.' ), admin_url( 'widgets.php' ), 'Twenty Thirteen', 'Twenty Twelve' ) . '</p>';
+ $overview .= '<p>' . __( 'From this screen you can:' ) . '</p>';
+ $overview .= '<ul><li>' . __( 'Create, edit, and delete menus' ) . '</li>';
+ $overview .= '<li>' . __( 'Add, organize, and modify individual menu items' ) . '</li></ul>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __( 'Overview' ),
+ 'content' => $overview
+ ) );
+
+ $menu_management = '<p>' . __( 'The menu management box at the top of the screen is used to control which menu is opened in the editor below.' ) . '</p>';
+ $menu_management .= '<ul><li>' . __( 'To edit an existing menu, <strong>choose a menu from the drop down and click Select</strong>' ) . '</li>';
+ $menu_management .= '<li>' . __( 'If you haven&#8217;t yet created any menus, <strong>click the &#8217;create a new menu&#8217; link</strong> to get started' ) . '</li></ul>';
+ $menu_management .= '<p>' . __( 'You can assign theme locations to individual menus by <strong>selecting the desired settings</strong> at the bottom of the menu editor. To assign menus to all theme locations at once, <strong>visit the Manage Locations tab</strong> at the top of the screen.' ) . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'menu-management',
+ 'title' => __( 'Menu Management' ),
+ 'content' => $menu_management
+ ) );
+
+ $editing_menus = '<p>' . __( 'Each custom menu may contain a mix of links to pages, categories, custom URLs or other content types. Menu links are added by selecting items from the expanding boxes in the left-hand column below.' ) . '</p>';
+ $editing_menus .= '<p>' . __( '<strong>Clicking the arrow to the right of any menu item</strong> in the editor will reveal a standard group of settings. Additional settings such as link target, CSS classes, link relationships, and link descriptions can be enabled and disabled via the Screen Options tab.' ) . '</p>';
+ $editing_menus .= '<ul><li>' . __( 'Add one or several items at once by <strong>selecting the checkbox next to each item and clicking Add to Menu</strong>' ) . '</li>';
+ $editing_menus .= '<li>' . __( 'To add a custom link, <strong>expand the Links section, enter a URL and link text, and click Add to Menu</strong>' ) .'</li>';
+ $editing_menus .= '<li>' . __( 'To reorganize menu items, <strong>drag and drop items with your mouse or use your keyboard</strong>. Drag or move a menu item a little to the right to make it a submenu' ) . '</li>';
+ $editing_menus .= '<li>' . __( 'Delete a menu item by <strong>expanding it and clicking the Remove link</strong>' ) . '</li></ul>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'editing-menus',
+ 'title' => __( 'Editing Menus' ),
+ 'content' => $editing_menus
+ ) );
+else : // Locations Tab
+ $locations_overview = '<p>' . __( 'This screen is used for globally assigning menus to locations defined by your theme.' ) . '</p>';
+ $locations_overview .= '<ul><li>' . __( 'To assign menus to one or more theme locations, <strong>select a menu from each location&#8217;s drop down.</strong> When you&#8217;re finished, <strong>click Save Changes</strong>' ) . '</li>';
+ $locations_overview .= '<li>' . __( 'To edit a menu currently assigned to a theme location, <strong>click the adjacent &#8217;Edit&#8217; link</strong>' ) . '</li>';
+ $locations_overview .= '<li>' . __( 'To add a new menu instead of assigning an existing one, <strong>click the &#8217;Use new menu&#8217; link</strong>. Your new menu will be automatically assigned to that theme location' ) . '</li></ul>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'locations-overview',
+ 'title' => __( 'Overview' ),
+ 'content' => $locations_overview
+ ) );
+endif;
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Appearance_Menus_Screen" target="_blank">Documentation on Menus</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+// Get the admin header
+require_once( './admin-header.php' );
+?>
+<div class="wrap">
+ <?php screen_icon(); ?>
+ <h2 class="nav-tab-wrapper">
+ <a href="<?php echo admin_url( 'nav-menus.php' ); ?>" class="nav-tab<?php if ( ! isset( $_GET['action'] ) || isset( $_GET['action'] ) && 'locations' != $_GET['action'] ) echo ' nav-tab-active'; ?>"><?php esc_html_e( 'Edit Menus' ); ?></a>
+ <?php if ( $num_locations && $menu_count ) : ?>
+ <a href="<?php echo esc_url( add_query_arg( array( 'action' => 'locations' ), admin_url( 'nav-menus.php' ) ) ); ?>" class="nav-tab<?php if ( $locations_screen ) echo ' nav-tab-active'; ?>"><?php esc_html_e( 'Manage Locations' ); ?></a>
+ <?php endif; ?>
+ </h2>
+ <?php
+ foreach( $messages as $message ) :
+ echo $message . "\n";
+ endforeach;
+ ?>
+ <?php
+ if ( $locations_screen ) :
+ echo '<p>' . sprintf( _n( 'Your theme supports %s menu. Select which menu you would like to use below.', 'Your theme supports %s menus. Select a menu to use for each theme location below.', $num_locations ), number_format_i18n( $num_locations ) ) . '</p>';
+ ?>
+ <div id="menu-locations-wrap">
+ <form method="post" action="<?php echo esc_url( add_query_arg( array( 'action' => 'locations' ), admin_url( 'nav-menus.php' ) ) ); ?>">
+ <table class="widefat fixed" cellspacing="0" id="menu-locations-table">
+ <thead>
+ <tr>
+ <th scope="col" class="manage-column column-locations"><?php _e( 'Theme Location' ); ?></th>
+ <th scope="col" class="manage-column column-menus"><?php _e( 'Assigned Menu' ); ?></th>
+ </tr>
+ </thead>
+ <!--<tfoot>
+ <tr>
+ <th scope="col" class="manage-column column-locations"><?php _e( 'Theme Location' ); ?></th>
+ <th scope="col" class="manage-column column-menus"><?php _e( 'Assigned Menu' ); ?></th>
+ </tr>
+ </tfoot>-->
+ <tbody class="menu-locations">
+ <?php foreach ( $locations as $_location => $_name ) { ?>
+ <tr id="menu-locations-row">
+ <td class="menu-location-title"><strong><?php echo $_name; ?></strong></td>
+ <td class="menu-location-menus">
+ <select name="menu-locations[<?php echo $_location; ?>]" id="locations-<?php echo $_location; ?>">
+ <option value="0"><?php printf( '&mdash; %s &mdash;', esc_html__( 'Select a Menu' ) ); ?></option>
+ <?php foreach ( $nav_menus as $menu ) : ?>
+ <?php $selected = isset( $menu_locations[$_location] ) && $menu_locations[$_location] == $menu->term_id; ?>
+ <option <?php if ( $selected ) echo 'data-orig="true"'; ?> <?php selected( $selected ); ?> value="<?php echo $menu->term_id; ?>">
+ <?php echo wp_html_excerpt( $menu->name, 40, '&hellip;' ); ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ <div class="locations-row-links">
+ <?php if ( isset( $menu_locations[ $_location ] ) && 0 != $menu_locations[ $_location ] ) : ?>
+ <span class="locations-edit-menu-link">
+ <a href="<?php echo esc_url( add_query_arg( array( 'action' => 'edit', 'menu' => $menu_locations[$_location] ), admin_url( 'nav-menus.php' ) ) ); ?>">
+ <?php _ex( 'Edit', 'menu' ); ?>
+ </a>
+ </span>
+ <?php endif; ?>
+ <span class="locations-add-menu-link">
+ <a href="<?php echo esc_url( add_query_arg( array( 'action' => 'edit', 'menu' => 0, 'use-location' => $_location ), admin_url( 'nav-menus.php' ) ) ); ?>">
+ <?php _ex( 'Use new menu', 'menu' ); ?>
+ </a>
+ </span>
+ </div><!-- #locations-row-links -->
+ </td><!-- .menu-location-menus -->
+ </tr><!-- #menu-locations-row -->
+ <?php } // foreach ?>
+ </tbody>
+ </table>
+ <p class="button-controls"><?php submit_button( __( 'Save Changes' ), 'primary left', 'nav-menu-locations', false ); ?></p>
+ <?php wp_nonce_field( 'save-menu-locations' ); ?>
+ <input type="hidden" name="menu" id="nav-menu-meta-object-id" value="<?php echo esc_attr( $nav_menu_selected_id ); ?>" />
+ </form>
+ </div><!-- #menu-locations-wrap -->
+ <?php do_action( 'after_menu_locations_table' ); ?>
+ <?php else : ?>
+ <div class="manage-menus">
+ <?php if ( $menu_count < 2 ) : ?>
+ <span class="add-edit-menu-action">
+ <?php printf( __( 'Edit your menu below, or <a href="%s">create a new menu</a>.' ), esc_url( add_query_arg( array( 'action' => 'edit', 'menu' => 0 ), admin_url( 'nav-menus.php' ) ) ) ); ?>
+ </span><!-- /add-edit-menu-action -->
+ <?php else : ?>
+ <form method="get" action="<?php echo admin_url( 'nav-menus.php' ); ?>">
+ <input type="hidden" name="action" value="edit" />
+ <label for="menu" class="selected-menu"><?php _e( 'Select a menu to edit:' ); ?></label>
+ <select name="menu" id="menu">
+ <?php if ( $add_new_screen ) : ?>
+ <option value="0" selected="selected"><?php _e( '-- Select --' ); ?></option>
+ <?php endif; ?>
+ <?php foreach( (array) $nav_menus as $_nav_menu ) : ?>
+ <option value="<?php echo esc_attr( $_nav_menu->term_id ); ?>" <?php selected( $_nav_menu->term_id, $nav_menu_selected_id ); ?>>
+ <?php
+ echo esc_html( $_nav_menu->truncated_name ) ;
+
+ if ( ! empty( $menu_locations ) && in_array( $_nav_menu->term_id, $menu_locations ) ) {
+ $locations_assigned_to_this_menu = array();
+ foreach ( array_keys( $menu_locations, $_nav_menu->term_id ) as $menu_location_key ) {
+ $locations_assigned_to_this_menu[] = $locations[ $menu_location_key ];
+ }
+ $assigned_locations = array_slice( $locations_assigned_to_this_menu, 0, absint( apply_filters( 'wp_nav_locations_listed_per_menu', 3 ) ) );
+
+ // Adds ellipses following the number of locations defined in $assigned_locations
+ printf( ' (%1$s%2$s)',
+ implode( ', ', $assigned_locations ),
+ count( $locations_assigned_to_this_menu ) > count( $assigned_locations ) ? ' &hellip;' : ''
+ );
+ }
+ ?>
+ </option>
+ <?php endforeach; ?>
+ </select>
+ <span class="submit-btn"><input type="submit" class="button-secondary" value="<?php _e( 'Select' ); ?>"></span>
+ <span class="add-new-menu-action">
+ <?php printf( __( 'or <a href="%s">create a new menu</a>.' ), esc_url( add_query_arg( array( 'action' => 'edit', 'menu' => 0 ), admin_url( 'nav-menus.php' ) ) ) ); ?>
+ </span><!-- /add-new-menu-action -->
+ </form>
+ <?php endif; ?>
+ </div><!-- /manage-menus -->
+ <div id="nav-menus-frame">
+ <div id="menu-settings-column" class="metabox-holder<?php if ( isset( $_GET['menu'] ) && '0' == $_GET['menu'] ) { echo ' metabox-holder-disabled'; } ?>">
+
+ <div class="clear"></div>
+
+ <form id="nav-menu-meta" action="" class="nav-menu-meta" method="post" enctype="multipart/form-data">
+ <input type="hidden" name="menu" id="nav-menu-meta-object-id" value="<?php echo esc_attr( $nav_menu_selected_id ); ?>" />
+ <input type="hidden" name="action" value="add-menu-item" />
+ <?php wp_nonce_field( 'add-menu_item', 'menu-settings-column-nonce' ); ?>
+ <?php do_accordion_sections( 'nav-menus', 'side', null ); ?>
+ </form>
+
+ </div><!-- /#menu-settings-column -->
+ <div id="menu-management-liquid">
+ <div id="menu-management">
+ <form id="update-nav-menu" action="" method="post" enctype="multipart/form-data">
+ <div class="menu-edit <?php if ( $add_new_screen ) echo 'blank-slate'; ?>">
+ <?php
+ wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
+ wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
+ wp_nonce_field( 'update-nav_menu', 'update-nav-menu-nonce' );
+
+ if ( $one_theme_location_no_menus ) { ?>
+ <input type="hidden" name="zero-menu-state" value="true" />
+ <?php } ?>
+ <input type="hidden" name="action" value="update" />
+ <input type="hidden" name="menu" id="menu" value="<?php echo esc_attr( $nav_menu_selected_id ); ?>" />
+ <div id="nav-menu-header">
+ <div class="major-publishing-actions">
+ <label class="menu-name-label howto open-label" for="menu-name">
+ <span><?php _e( 'Menu Name' ); ?></span>
+ <input name="menu-name" id="menu-name" type="text" class="menu-name regular-text menu-item-textbox input-with-default-title" title="<?php esc_attr_e( 'Enter menu name here' ); ?>" value="<?php if ( $one_theme_location_no_menus ) _e( 'Menu 1' ); else echo esc_attr( $nav_menu_selected_title ); ?>" />
+ </label>
+ <div class="publishing-action">
+ <?php submit_button( empty( $nav_menu_selected_id ) ? __( 'Create Menu' ) : __( 'Save Menu' ), 'button-primary menu-save', 'save_menu', false, array( 'id' => 'save_menu_header' ) ); ?>
+ </div><!-- END .publishing-action -->
+ </div><!-- END .major-publishing-actions -->
+ </div><!-- END .nav-menu-header -->
+ <div id="post-body">
+ <div id="post-body-content">
+ <?php if ( ! $add_new_screen ) : ?>
+ <h3><?php _e( 'Menu Structure' ); ?></h3>
+ <?php $starter_copy = ( $one_theme_location_no_menus ) ? __( 'Edit your default menu by adding or removing items. Drag each item into the order you prefer. Click Create Menu to save your changes.' ) : __( 'Drag each item into the order you prefer. Click the arrow on the right of the item to reveal additional configuration options.' ); ?>
+ <div class="drag-instructions post-body-plain" <?php if ( isset( $menu_items ) && 0 == count( $menu_items ) ) { ?>style="display: none;"<?php } ?>>
+ <p><?php echo $starter_copy; ?></p>
+ </div>
+ <?php
+ if ( isset( $edit_markup ) && ! is_wp_error( $edit_markup ) ) {
+ echo $edit_markup;
+ } else {
+ ?>
+ <ul class="menu" id="menu-to-edit"></ul>
+ <?php } ?>
+ <?php endif; ?>
+ <?php if ( $add_new_screen ) : ?>
+ <p class="post-body-plain"><?php _e( 'Give your menu a name above, then click Create Menu.' ); ?></p>
+ <?php if ( isset( $_GET['use-location'] ) ) : ?>
+ <input type="hidden" name="use-location" value="<?php echo esc_attr( $_GET['use-location'] ); ?>" />
+ <?php endif; ?>
+ <?php endif; ?>
+ <div class="menu-settings" <?php if ( $one_theme_location_no_menus ) { ?>style="display: none;"<?php } ?>>
+ <h3><?php _e( 'Menu Settings' ); ?></h3>
+ <?php
+ if ( ! isset( $auto_add ) ) {
+ $auto_add = get_option( 'nav_menu_options' );
+ if ( ! isset( $auto_add['auto_add'] ) )
+ $auto_add = false;
+ elseif ( false !== array_search( $nav_menu_selected_id, $auto_add['auto_add'] ) )
+ $auto_add = true;
+ else
+ $auto_add = false;
+ } ?>
+
+ <dl class="auto-add-pages">
+ <dt class="howto"><?php _e( 'Auto add pages' ); ?></dt>
+ <dd class="checkbox-input"><input type="checkbox"<?php checked( $auto_add ); ?> name="auto-add-pages" id="auto-add-pages" value="1" /> <label for="auto-add-pages"><?php printf( __('Automatically add new top-level pages to this menu' ), esc_url( admin_url( 'edit.php?post_type=page' ) ) ); ?></label></dd>
+ </dl>
+
+ <?php if ( current_theme_supports( 'menus' ) ) : ?>
+
+ <dl class="menu-theme-locations">
+ <dt class="howto"><?php _e( 'Theme locations' ); ?></dt>
+ <?php foreach ( $locations as $location => $description ) : ?>
+ <dd class="checkbox-input">
+ <input type="checkbox"<?php checked( isset( $menu_locations[ $location ] ) && $menu_locations[ $location ] == $nav_menu_selected_id ); ?> name="menu-locations[<?php echo esc_attr( $location ); ?>]" id="locations-<?php echo esc_attr( $location ); ?>" value="<?php echo esc_attr( $nav_menu_selected_id ); ?>" /> <label for="locations-<?php echo esc_attr( $location ); ?>"><?php echo $description; ?></label>
+ <?php if ( ! empty( $menu_locations[ $location ] ) && $menu_locations[ $location ] != $nav_menu_selected_id ) : ?>
+ <span class="theme-location-set"> <?php printf( __( "(Currently set to: %s)" ), wp_get_nav_menu_object( $menu_locations[ $location ] )->name ); ?> </span>
+ <?php endif; ?>
+ </dd>
+ <?php endforeach; ?>
+ </dl>
+
+ <?php endif; ?>
+
+ </div>
+ </div><!-- /#post-body-content -->
+ </div><!-- /#post-body -->
+ <div id="nav-menu-footer">
+ <div class="major-publishing-actions">
+ <?php if ( 0 != $menu_count && ! $add_new_screen ) : ?>
+ <span class="delete-action">
+ <a class="submitdelete deletion menu-delete" href="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'delete', 'menu' => $nav_menu_selected_id, admin_url() ) ), 'delete-nav_menu-' . $nav_menu_selected_id) ); ?>"><?php _e('Delete Menu'); ?></a>
+ </span><!-- END .delete-action -->
+ <?php endif; ?>
+ <div class="publishing-action">
+ <?php submit_button( empty( $nav_menu_selected_id ) ? __( 'Create Menu' ) : __( 'Save Menu' ), 'button-primary menu-save', 'save_menu', false, array( 'id' => 'save_menu_header' ) ); ?>
+ </div><!-- END .publishing-action -->
+ </div><!-- END .major-publishing-actions -->
+ </div><!-- /#nav-menu-footer -->
+ </div><!-- /.menu-edit -->
+ </form><!-- /#update-nav-menu -->
+ </div><!-- /#menu-management -->
+ </div><!-- /#menu-management-liquid -->
+ </div><!-- /#nav-menus-frame -->
+ <?php endif; ?>
+</div><!-- /.wrap-->
+<?php include( './admin-footer.php' ); ?>
diff --git a/src/wp-admin/network.php b/src/wp-admin/network.php
new file mode 100644
index 0000000000..c3dea68471
--- /dev/null
+++ b/src/wp-admin/network.php
@@ -0,0 +1,542 @@
+<?php
+/**
+ * Network installation administration panel.
+ *
+ * A multi-step process allowing the user to enable a network of WordPress sites.
+ *
+ * @since 3.0.0
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+define( 'WP_INSTALLING_NETWORK', true );
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_super_admin() )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+if ( is_multisite() ) {
+ if ( ! is_network_admin() ) {
+ wp_redirect( network_admin_url( 'setup.php' ) );
+ exit;
+ }
+ if ( ! defined( 'MULTISITE' ) )
+ wp_die( __( 'The Network creation panel is not for WordPress MU networks.' ) );
+}
+
+// We need to create references to ms global tables to enable Network.
+foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table )
+ $wpdb->$table = $prefixed_table;
+
+/**
+ * Check for an existing network.
+ *
+ * @since 3.0.0
+ * @return Whether a network exists.
+ */
+function network_domain_check() {
+ global $wpdb;
+ if ( $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->site'" ) )
+ return $wpdb->get_var( "SELECT domain FROM $wpdb->site ORDER BY id ASC LIMIT 1" );
+ return false;
+}
+
+/**
+ * Allow subdomain install
+ *
+ * @since 3.0.0
+ * @return bool Whether subdomain install is allowed
+ */
+function allow_subdomain_install() {
+ $domain = preg_replace( '|https?://([^/]+)|', '$1', get_option( 'home' ) );
+ if( parse_url( get_option( 'home' ), PHP_URL_PATH ) || 'localhost' == $domain || preg_match( '|^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$|', $domain ) )
+ return false;
+
+ return true;
+}
+/**
+ * Allow subdirectory install
+ *
+ * @since 3.0.0
+ * @return bool Whether subdirectory install is allowed
+ */
+function allow_subdirectory_install() {
+ global $wpdb;
+ if ( apply_filters( 'allow_subdirectory_install', false ) )
+ return true;
+
+ if ( defined( 'ALLOW_SUBDIRECTORY_INSTALL' ) && ALLOW_SUBDIRECTORY_INSTALL )
+ return true;
+
+ $post = $wpdb->get_row( "SELECT ID FROM $wpdb->posts WHERE post_date < DATE_SUB(NOW(), INTERVAL 1 MONTH) AND post_status = 'publish'" );
+ if ( empty( $post ) )
+ return true;
+
+ return false;
+}
+/**
+ * Get base domain of network.
+ *
+ * @since 3.0.0
+ * @return string Base domain.
+ */
+function get_clean_basedomain() {
+ if ( $existing_domain = network_domain_check() )
+ return $existing_domain;
+ $domain = preg_replace( '|https?://|', '', get_option( 'siteurl' ) );
+ if ( $slash = strpos( $domain, '/' ) )
+ $domain = substr( $domain, 0, $slash );
+ return $domain;
+}
+
+if ( ! network_domain_check() && ( ! defined( 'WP_ALLOW_MULTISITE' ) || ! WP_ALLOW_MULTISITE ) )
+ wp_die( __( 'You must define the <code>WP_ALLOW_MULTISITE</code> constant as true in your wp-config.php file to allow creation of a Network.' ) );
+
+if ( is_network_admin() ) {
+ $title = __( 'Network Setup' );
+ $parent_file = 'settings.php';
+} else {
+ $title = __( 'Create a Network of WordPress Sites' );
+ $parent_file = 'tools.php';
+}
+
+$network_help = '<p>' . __('This screen allows you to configure a network as having subdomains (<code>site1.example.com</code>) or subdirectories (<code>example.com/site1</code>). Subdomains require wildcard subdomains to be enabled in Apache and DNS records, if your host allows it.') . '</p>' .
+ '<p>' . __('Choose subdomains or subdirectories; this can only be switched afterwards by reconfiguring your install. Fill out the network details, and click install. If this does not work, you may have to add a wildcard DNS record (for subdomains) or change to another setting in Permalinks (for subdirectories).') . '</p>' .
+ '<p>' . __('The next screen for Network Setup will give you individually-generated lines of code to add to your wp-config.php and .htaccess files. Make sure the settings of your FTP client make files starting with a dot visible, so that you can find .htaccess; you may have to create this file if it really is not there. Make backup copies of those two files.') . '</p>' .
+ '<p>' . __('Add the designated lines of code to wp-config.php (just before <code>/*...stop editing...*/</code>) and <code>.htaccess</code> (replacing the existing WordPress rules).') . '</p>' .
+ '<p>' . __('Once you add this code and refresh your browser, multisite should be enabled. This screen, now in the Network Admin navigation menu, will keep an archive of the added code. You can toggle between Network Admin and Site Admin by clicking on the Network Admin or an individual site name under the My Sites dropdown in the Toolbar.') . '</p>' .
+ '<p>' . __('The choice of subdirectory sites is disabled if this setup is more than a month old because of permalink problems with &#8220;/blog/&#8221; from the main site. This disabling will be addressed in a future version.') . '</p>' .
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Create_A_Network" target="_blank">Documentation on Creating a Network</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Tools_Network_Screen" target="_blank">Documentation on the Network Screen</a>') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'network',
+ 'title' => __('Network'),
+ 'content' => $network_help,
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Create_A_Network" target="_blank">Documentation on Creating a Network</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Tools_Network_Screen" target="_blank">Documentation on the Network Screen</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include( ABSPATH . 'wp-admin/admin-header.php' );
+?>
+<div class="wrap">
+<?php screen_icon('tools'); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<?php
+/**
+ * Prints step 1 for Network installation process.
+ *
+ * @todo Realistically, step 1 should be a welcome screen explaining what a Network is and such. Navigating to Tools > Network
+ * should not be a sudden "Welcome to a new install process! Fill this out and click here." See also contextual help todo.
+ *
+ * @since 3.0.0
+ */
+function network_step1( $errors = false ) {
+ global $is_apache;
+
+ if ( defined('DO_NOT_UPGRADE_GLOBAL_TABLES') ) {
+ echo '<div class="error"><p><strong>' . __('ERROR:') . '</strong> ' . __( 'The constant DO_NOT_UPGRADE_GLOBAL_TABLES cannot be defined when creating a network.' ) . '</p></div>';
+ echo '</div>';
+ include ( ABSPATH . 'wp-admin/admin-footer.php' );
+ die();
+ }
+
+ $active_plugins = get_option( 'active_plugins' );
+ if ( ! empty( $active_plugins ) ) {
+ echo '<div class="updated"><p><strong>' . __('Warning:') . '</strong> ' . sprintf( __( 'Please <a href="%s">deactivate your plugins</a> before enabling the Network feature.' ), admin_url( 'plugins.php?plugin_status=active' ) ) . '</p></div><p>' . __( 'Once the network is created, you may reactivate your plugins.' ) . '</p>';
+ echo '</div>';
+ include( ABSPATH . 'wp-admin/admin-footer.php' );
+ die();
+ }
+
+ $hostname = get_clean_basedomain();
+ $has_ports = strstr( $hostname, ':' );
+ if ( ( false !== $has_ports && ! in_array( $has_ports, array( ':80', ':443' ) ) ) ) {
+ echo '<div class="error"><p><strong>' . __( 'ERROR:') . '</strong> ' . __( 'You cannot install a network of sites with your server address.' ) . '</p></div>';
+ echo '<p>' . sprintf( __( 'You cannot use port numbers such as <code>%s</code>.' ), $has_ports ) . '</p>';
+ echo '<a href="' . esc_url( admin_url() ) . '">' . __( 'Return to Dashboard' ) . '</a>';
+ echo '</div>';
+ include( ABSPATH . 'wp-admin/admin-footer.php' );
+ die();
+ }
+
+ echo '<form method="post" action="">';
+
+ wp_nonce_field( 'install-network-1' );
+
+ $error_codes = array();
+ if ( is_wp_error( $errors ) ) {
+ echo '<div class="error"><p><strong>' . __( 'ERROR: The network could not be created.' ) . '</strong></p>';
+ foreach ( $errors->get_error_messages() as $error )
+ echo "<p>$error</p>";
+ echo '</div>';
+ $error_codes = $errors->get_error_codes();
+ }
+
+ $site_name = ( ! empty( $_POST['sitename'] ) && ! in_array( 'empty_sitename', $error_codes ) ) ? $_POST['sitename'] : sprintf( _x('%s Sites', 'Default network name' ), get_option( 'blogname' ) );
+ $admin_email = ( ! empty( $_POST['email'] ) && ! in_array( 'invalid_email', $error_codes ) ) ? $_POST['email'] : get_option( 'admin_email' );
+ ?>
+ <p><?php _e( 'Welcome to the Network installation process!' ); ?></p>
+ <p><?php _e( 'Fill in the information below and you&#8217;ll be on your way to creating a network of WordPress sites. We will create configuration files in the next step.' ); ?></p>
+ <?php
+
+ if ( isset( $_POST['subdomain_install'] ) ) {
+ $subdomain_install = (bool) $_POST['subdomain_install'];
+ } elseif ( apache_mod_loaded('mod_rewrite') ) { // assume nothing
+ $subdomain_install = true;
+ } elseif ( !allow_subdirectory_install() ) {
+ $subdomain_install = true;
+ } else {
+ $subdomain_install = false;
+ if ( $got_mod_rewrite = got_mod_rewrite() ) // dangerous assumptions
+ echo '<div class="updated inline"><p><strong>' . __( 'Note:' ) . '</strong> ' . __( 'Please make sure the Apache <code>mod_rewrite</code> module is installed as it will be used at the end of this installation.' ) . '</p>';
+ elseif ( $is_apache )
+ echo '<div class="error inline"><p><strong>' . __( 'Warning!' ) . '</strong> ' . __( 'It looks like the Apache <code>mod_rewrite</code> module is not installed.' ) . '</p>';
+ if ( $got_mod_rewrite || $is_apache ) // Protect against mod_rewrite mimicry (but ! Apache)
+ echo '<p>' . __( 'If <code>mod_rewrite</code> is disabled, ask your administrator to enable that module, or look at the <a href="http://httpd.apache.org/docs/mod/mod_rewrite.html">Apache documentation</a> or <a href="http://www.google.com/search?q=apache+mod_rewrite">elsewhere</a> for help setting it up.' ) . '</p></div>';
+ }
+
+ if ( allow_subdomain_install() && allow_subdirectory_install() ) : ?>
+ <h3><?php esc_html_e( 'Addresses of Sites in your Network' ); ?></h3>
+ <p><?php _e( 'Please choose whether you would like sites in your WordPress network to use sub-domains or sub-directories. <strong>You cannot change this later.</strong>' ); ?></p>
+ <p><?php _e( 'You will need a wildcard DNS record if you are going to use the virtual host (sub-domain) functionality.' ); ?></p>
+ <?php // @todo: Link to an MS readme? ?>
+ <table class="form-table">
+ <tr>
+ <th><label><input type='radio' name='subdomain_install' value='1'<?php checked( $subdomain_install ); ?> /> <?php _e( 'Sub-domains' ); ?></label></th>
+ <td><?php printf( _x( 'like <code>site1.%1$s</code> and <code>site2.%1$s</code>', 'subdomain examples' ), $hostname ); ?></td>
+ </tr>
+ <tr>
+ <th><label><input type='radio' name='subdomain_install' value='0'<?php checked( ! $subdomain_install ); ?> /> <?php _e( 'Sub-directories' ); ?></label></th>
+ <td><?php printf( _x( 'like <code>%1$s/site1</code> and <code>%1$s/site2</code>', 'subdirectory examples' ), $hostname ); ?></td>
+ </tr>
+ </table>
+
+<?php
+ endif;
+
+ if ( WP_CONTENT_DIR != ABSPATH . 'wp-content' && ( allow_subdirectory_install() || ! allow_subdomain_install() ) )
+ echo '<div class="error inline"><p><strong>' . __('Warning!') . '</strong> ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</p></div>';
+
+ $is_www = ( 0 === strpos( $hostname, 'www.' ) );
+ if ( $is_www ) :
+ ?>
+ <h3><?php esc_html_e( 'Server Address' ); ?></h3>
+ <p><?php printf( __( 'We recommend you change your siteurl to <code>%1$s</code> before enabling the network feature. It will still be possible to visit your site using the <code>www</code> prefix with an address like <code>%2$s</code> but any links will not have the <code>www</code> prefix.' ), substr( $hostname, 4 ), $hostname ); ?></p>
+ <table class="form-table">
+ <tr>
+ <th scope='row'><?php esc_html_e( 'Server Address' ); ?></th>
+ <td>
+ <?php printf( __( 'The internet address of your network will be <code>%s</code>.' ), $hostname ); ?>
+ </td>
+ </tr>
+ </table>
+ <?php endif; ?>
+
+ <h3><?php esc_html_e( 'Network Details' ); ?></h3>
+ <table class="form-table">
+ <?php if ( 'localhost' == $hostname ) : ?>
+ <tr>
+ <th scope="row"><?php esc_html_e( 'Sub-directory Install' ); ?></th>
+ <td><?php
+ _e( 'Because you are using <code>localhost</code>, the sites in your WordPress network must use sub-directories. Consider using <code>localhost.localdomain</code> if you wish to use sub-domains.' );
+ // Uh oh:
+ if ( !allow_subdirectory_install() )
+ echo ' <strong>' . __( 'Warning!' ) . ' ' . __( 'The main site in a sub-directory install will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
+ ?></td>
+ </tr>
+ <?php elseif ( !allow_subdomain_install() ) : ?>
+ <tr>
+ <th scope="row"><?php esc_html_e( 'Sub-directory Install' ); ?></th>
+ <td><?php
+ _e( 'Because your install is in a directory, the sites in your WordPress network must use sub-directories.' );
+ // Uh oh:
+ if ( !allow_subdirectory_install() )
+ echo ' <strong>' . __( 'Warning!' ) . ' ' . __( 'The main site in a sub-directory install will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
+ ?></td>
+ </tr>
+ <?php elseif ( !allow_subdirectory_install() ) : ?>
+ <tr>
+ <th scope="row"><?php esc_html_e( 'Sub-domain Install' ); ?></th>
+ <td><?php _e( 'Because your install is not new, the sites in your WordPress network must use sub-domains.' );
+ echo ' <strong>' . __( 'The main site in a sub-directory install will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
+ ?></td>
+ </tr>
+ <?php endif; ?>
+ <?php if ( ! $is_www ) : ?>
+ <tr>
+ <th scope='row'><?php esc_html_e( 'Server Address' ); ?></th>
+ <td>
+ <?php printf( __( 'The internet address of your network will be <code>%s</code>.' ), $hostname ); ?>
+ </td>
+ </tr>
+ <?php endif; ?>
+ <tr>
+ <th scope='row'><?php esc_html_e( 'Network Title' ); ?></th>
+ <td>
+ <input name='sitename' type='text' size='45' value='<?php echo esc_attr( $site_name ); ?>' />
+ <br /><?php _e( 'What would you like to call your network?' ); ?>
+ </td>
+ </tr>
+ <tr>
+ <th scope='row'><?php esc_html_e( 'Admin E-mail Address' ); ?></th>
+ <td>
+ <input name='email' type='text' size='45' value='<?php echo esc_attr( $admin_email ); ?>' />
+ <br /><?php _e( 'Your email address.' ); ?>
+ </td>
+ </tr>
+ </table>
+ <?php submit_button( __( 'Install' ), 'primary', 'submit' ); ?>
+ </form>
+ <?php
+}
+
+/**
+ * Prints step 2 for Network installation process.
+ *
+ * @since 3.0.0
+ */
+function network_step2( $errors = false ) {
+ global $wpdb;
+
+ $hostname = get_clean_basedomain();
+ $slashed_home = trailingslashit( get_option( 'home' ) );
+ $base = parse_url( $slashed_home, PHP_URL_PATH );
+ $document_root_fix = str_replace( '\\', '/', realpath( $_SERVER['DOCUMENT_ROOT'] ) );
+ $abspath_fix = str_replace( '\\', '/', ABSPATH );
+ $home_path = 0 === strpos( $abspath_fix, $document_root_fix ) ? $document_root_fix . $base : get_home_path();
+ $wp_siteurl_subdir = preg_replace( '#^' . preg_quote( $home_path, '#' ) . '#', '', $abspath_fix );
+ $rewrite_base = ! empty( $wp_siteurl_subdir ) ? ltrim( trailingslashit( $wp_siteurl_subdir ), '/' ) : '';
+
+
+ $location_of_wp_config = ABSPATH;
+ if ( ! file_exists( ABSPATH . 'wp-config.php' ) && file_exists( dirname( ABSPATH ) . '/wp-config.php' ) )
+ $location_of_wp_config = trailingslashit( dirname( ABSPATH ) );
+
+ // Wildcard DNS message.
+ if ( is_wp_error( $errors ) )
+ echo '<div class="error">' . $errors->get_error_message() . '</div>';
+
+ if ( $_POST ) {
+ if ( allow_subdomain_install() )
+ $subdomain_install = allow_subdirectory_install() ? ! empty( $_POST['subdomain_install'] ) : true;
+ else
+ $subdomain_install = false;
+ } else {
+ if ( is_multisite() ) {
+ $subdomain_install = is_subdomain_install();
+?>
+ <p><?php _e( 'The original configuration steps are shown here for reference.' ); ?></p>
+<?php
+ } else {
+ $subdomain_install = (bool) $wpdb->get_var( "SELECT meta_value FROM $wpdb->sitemeta WHERE site_id = 1 AND meta_key = 'subdomain_install'" );
+?>
+ <div class="error"><p><strong><?php _e('Warning:'); ?></strong> <?php _e( 'An existing WordPress network was detected.' ); ?></p></div>
+ <p><?php _e( 'Please complete the configuration steps. To create a new network, you will need to empty or remove the network database tables.' ); ?></p>
+<?php
+ }
+ }
+
+ $subdir_match = $subdomain_install ? '' : '([_0-9a-zA-Z-]+/)?';
+ $subdir_replacement_01 = $subdomain_install ? '' : '$1';
+ $subdir_replacement_12 = $subdomain_install ? '$1' : '$2';
+
+ if ( $_POST || ! is_multisite() ) {
+?>
+ <h3><?php esc_html_e( 'Enabling the Network' ); ?></h3>
+ <p><?php _e( 'Complete the following steps to enable the features for creating a network of sites.' ); ?></p>
+ <div class="updated inline"><p><?php
+ if ( file_exists( $home_path . '.htaccess' ) )
+ printf( __( '<strong>Caution:</strong> We recommend you back up your existing <code>wp-config.php</code> and <code>%s</code> files.' ), '.htaccess' );
+ elseif ( file_exists( $home_path . 'web.config' ) )
+ printf( __( '<strong>Caution:</strong> We recommend you back up your existing <code>wp-config.php</code> and <code>%s</code> files.' ), 'web.config' );
+ else
+ _e( '<strong>Caution:</strong> We recommend you back up your existing <code>wp-config.php</code> file.' );
+ ?></p></div>
+<?php
+ }
+?>
+ <ol>
+ <li><p><?php printf( __( 'Add the following to your <code>wp-config.php</code> file in <code>%s</code> <strong>above</strong> the line reading <code>/* That&#8217;s all, stop editing! Happy blogging. */</code>:' ), $location_of_wp_config ); ?></p>
+ <textarea class="code" readonly="readonly" cols="100" rows="6">
+define('MULTISITE', true);
+define('SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?>);
+define('DOMAIN_CURRENT_SITE', '<?php echo $hostname; ?>');
+define('PATH_CURRENT_SITE', '<?php echo $base; ?>');
+define('SITE_ID_CURRENT_SITE', 1);
+define('BLOG_ID_CURRENT_SITE', 1);</textarea>
+<?php
+ $keys_salts = array( 'AUTH_KEY' => '', 'SECURE_AUTH_KEY' => '', 'LOGGED_IN_KEY' => '', 'NONCE_KEY' => '', 'AUTH_SALT' => '', 'SECURE_AUTH_SALT' => '', 'LOGGED_IN_SALT' => '', 'NONCE_SALT' => '' );
+ foreach ( $keys_salts as $c => $v ) {
+ if ( defined( $c ) )
+ unset( $keys_salts[ $c ] );
+ }
+
+ if ( ! empty( $keys_salts ) ) {
+ $keys_salts_str = '';
+ $from_api = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' );
+ if ( is_wp_error( $from_api ) ) {
+ foreach ( $keys_salts as $c => $v ) {
+ $keys_salts_str .= "\ndefine( '$c', '" . wp_generate_password( 64, true, true ) . "' );";
+ }
+ } else {
+ $from_api = explode( "\n", wp_remote_retrieve_body( $from_api ) );
+ foreach ( $keys_salts as $c => $v ) {
+ $keys_salts_str .= "\ndefine( '$c', '" . substr( array_shift( $from_api ), 28, 64 ) . "' );";
+ }
+ }
+ $num_keys_salts = count( $keys_salts );
+?>
+ <p><?php
+ echo _n( 'This unique authentication key is also missing from your <code>wp-config.php</code> file.', 'These unique authentication keys are also missing from your <code>wp-config.php</code> file.', $num_keys_salts ); ?> <?php _e( 'To make your installation more secure, you should also add:' ) ?></p>
+ <textarea class="code" readonly="readonly" cols="100" rows="<?php echo $num_keys_salts; ?>"><?php echo esc_textarea( $keys_salts_str ); ?></textarea>
+<?php
+ }
+?>
+</li>
+<?php
+ if ( iis7_supports_permalinks() ) :
+ // IIS doesn't support RewriteBase, all your RewriteBase are belong to us
+ $iis_subdir_match = ltrim( $base, '/' ) . $subdir_match;
+ $iis_rewrite_base = ltrim( $base, '/' ) . $rewrite_base;
+ $iis_subdir_replacement = $subdomain_install ? '' : '{R:1}';
+
+ $web_config_file = '<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+ <system.webServer>
+ <rewrite>
+ <rules>
+ <rule name="WordPress Rule 1" stopProcessing="true">
+ <match url="^index\.php$" ignoreCase="false" />
+ <action type="None" />
+ </rule>';
+ if ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
+ $web_config_file .= '
+ <rule name="WordPress Rule for Files" stopProcessing="true">
+ <match url="^' . $iis_subdir_match . 'files/(.+)" ignoreCase="false" />
+ <action type="Rewrite" url="' . $iis_rewrite_base . 'wp-includes/ms-files.php?file={R:1}" appendQueryString="false" />
+ </rule>';
+ }
+ $web_config_file .= '
+ <rule name="WordPress Rule 2" stopProcessing="true">
+ <match url="^' . $iis_subdir_match . 'wp-admin$" ignoreCase="false" />
+ <action type="Redirect" url="' . $iis_subdir_replacement . 'wp-admin/" redirectType="Permanent" />
+ </rule>
+ <rule name="WordPress Rule 3" stopProcessing="true">
+ <match url="^" ignoreCase="false" />
+ <conditions logicalGrouping="MatchAny">
+ <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
+ <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
+ </conditions>
+ <action type="None" />
+ </rule>
+ <rule name="WordPress Rule 4" stopProcessing="true">
+ <match url="^' . $iis_subdir_match . '(wp-(content|admin|includes).*)" ignoreCase="false" />
+ <action type="Rewrite" url="' . $iis_rewrite_base . '{R:1}" />
+ </rule>
+ <rule name="WordPress Rule 5" stopProcessing="true">
+ <match url="^' . $iis_subdir_match . '([_0-9a-zA-Z-]+/)?(.*\.php)$" ignoreCase="false" />
+ <action type="Rewrite" url="' . $iis_rewrite_base . '{R:2}" />
+ </rule>
+ <rule name="WordPress Rule 6" stopProcessing="true">
+ <match url="." ignoreCase="false" />
+ <action type="Rewrite" url="index.php" />
+ </rule>
+ </rules>
+ </rewrite>
+ </system.webServer>
+</configuration>';
+
+ ?>
+ <li><p><?php printf( __( 'Add the following to your <code>web.config</code> file in <code>%s</code>, replacing other WordPress rules:' ), $home_path ); ?></p>
+ <?php
+ if ( ! $subdomain_install && WP_CONTENT_DIR != ABSPATH . 'wp-content' )
+ echo '<p><strong>' . __('Warning:') . ' ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</strong></p>';
+ ?>
+ <textarea class="code" readonly="readonly" cols="100" rows="20"><?php echo esc_textarea( $web_config_file ); ?>
+ </textarea></li>
+ </ol>
+
+ <?php else : // end iis7_supports_permalinks(). construct an htaccess file instead:
+
+ $ms_files_rewriting = '';
+ if ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
+ $ms_files_rewriting = "\n# uploaded files\nRewriteRule ^";
+ $ms_files_rewriting .= $subdir_match . "files/(.+) {$rewrite_base}wp-includes/ms-files.php?file={$subdir_replacement_12} [L]" . "\n";
+ }
+
+ $htaccess_file = <<<EOF
+RewriteEngine On
+RewriteBase {$base}
+RewriteRule ^index\.php$ - [L]
+{$ms_files_rewriting}
+# add a trailing slash to /wp-admin
+RewriteRule ^{$subdir_match}wp-admin$ {$subdir_replacement_01}wp-admin/ [R=301,L]
+
+RewriteCond %{REQUEST_FILENAME} -f [OR]
+RewriteCond %{REQUEST_FILENAME} -d
+RewriteRule ^ - [L]
+RewriteRule ^{$subdir_match}(wp-(content|admin|includes).*) {$rewrite_base}{$subdir_replacement_12} [L]
+RewriteRule ^{$subdir_match}(.*\.php)$ {$rewrite_base}$subdir_replacement_12 [L]
+RewriteRule . index.php [L]
+EOF;
+
+ ?>
+ <li><p><?php printf( __( 'Add the following to your <code>.htaccess</code> file in <code>%s</code>, replacing other WordPress rules:' ), $home_path ); ?></p>
+ <?php
+ if ( ! $subdomain_install && WP_CONTENT_DIR != ABSPATH . 'wp-content' )
+ echo '<p><strong>' . __('Warning:') . ' ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</strong></p>';
+ ?>
+ <textarea class="code" readonly="readonly" cols="100" rows="<?php echo substr_count( $htaccess_file, "\n" ) + 1; ?>">
+<?php echo esc_textarea( $htaccess_file ); ?></textarea></li>
+ </ol>
+
+ <?php endif; // end IIS/Apache code branches.
+
+ if ( !is_multisite() ) { ?>
+ <p><?php printf( __( 'Once you complete these steps, your network is enabled and configured. You will have to log in again.') ); ?> <a href="<?php echo esc_url( site_url( 'wp-login.php' ) ); ?>"><?php _e( 'Log In' ); ?></a></p>
+<?php
+ }
+}
+
+if ( $_POST ) {
+
+ check_admin_referer( 'install-network-1' );
+
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
+ // create network tables
+ install_network();
+ $base = parse_url( trailingslashit( get_option( 'home' ) ), PHP_URL_PATH );
+ $subdomain_install = allow_subdomain_install() ? !empty( $_POST['subdomain_install'] ) : false;
+ if ( ! network_domain_check() ) {
+ $result = populate_network( 1, get_clean_basedomain(), sanitize_email( $_POST['email'] ), wp_unslash( $_POST['sitename'] ), $base, $subdomain_install );
+ if ( is_wp_error( $result ) ) {
+ if ( 1 == count( $result->get_error_codes() ) && 'no_wildcard_dns' == $result->get_error_code() )
+ network_step2( $result );
+ else
+ network_step1( $result );
+ } else {
+ network_step2();
+ }
+ } else {
+ network_step2();
+ }
+} elseif ( is_multisite() || network_domain_check() ) {
+ network_step2();
+} else {
+ network_step1();
+}
+?>
+</div>
+
+<?php include( ABSPATH . 'wp-admin/admin-footer.php' ); ?>
diff --git a/src/wp-admin/network/about.php b/src/wp-admin/network/about.php
new file mode 100644
index 0000000000..e8bbe999d0
--- /dev/null
+++ b/src/wp-admin/network/about.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Network About administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.4.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../about.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/admin.php b/src/wp-admin/network/admin.php
new file mode 100644
index 0000000000..01e6ea70c9
--- /dev/null
+++ b/src/wp-admin/network/admin.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * WordPress Network Administration Bootstrap
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+define( 'WP_NETWORK_ADMIN', true );
+
+/** Load WordPress Administration Bootstrap */
+require_once( dirname( dirname( __FILE__ ) ) . '/admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+$redirect_network_admin_request = ( ( $current_blog->domain != $current_site->domain ) || ( $current_blog->path != $current_site->path ) );
+$redirect_network_admin_request = apply_filters( 'redirect_network_admin_request', $redirect_network_admin_request );
+if ( $redirect_network_admin_request ) {
+ wp_redirect( network_admin_url() );
+ exit;
+}
+unset( $redirect_network_admin_request );
diff --git a/src/wp-admin/network/credits.php b/src/wp-admin/network/credits.php
new file mode 100644
index 0000000000..82caa3ad08
--- /dev/null
+++ b/src/wp-admin/network/credits.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Network Credits administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.4.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../credits.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/edit.php b/src/wp-admin/network/edit.php
new file mode 100644
index 0000000000..e76f25878c
--- /dev/null
+++ b/src/wp-admin/network/edit.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Action handler for Multisite administration panels.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( empty( $_GET['action'] ) ) {
+ wp_redirect( network_admin_url() );
+ exit;
+}
+
+do_action( 'wpmuadminedit' , '' );
+
+// Let plugins use us as a post handler easily
+do_action( 'network_admin_edit_' . $_GET['action'] );
+
+wp_redirect( network_admin_url() );
+exit();
diff --git a/src/wp-admin/network/freedoms.php b/src/wp-admin/network/freedoms.php
new file mode 100644
index 0000000000..a15a4c3fd3
--- /dev/null
+++ b/src/wp-admin/network/freedoms.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Network Freedoms administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.4.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../freedoms.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/index.php b/src/wp-admin/network/index.php
new file mode 100644
index 0000000000..96c2c248a6
--- /dev/null
+++ b/src/wp-admin/network/index.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Multisite administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+/** Load WordPress dashboard API */
+require_once( ABSPATH . 'wp-admin/includes/dashboard.php' );
+
+if ( !is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_network' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$title = __( 'Dashboard' );
+$parent_file = 'index.php';
+
+$overview = '<p>' . __( 'Welcome to your Network Admin. This area of the Administration Screens is used for managing all aspects of your Multisite Network.' ) . '</p>';
+$overview .= '<p>' . __( 'From here you can:' ) . '</p>';
+$overview .= '<ul><li>' . __( 'Add and manage sites or users' ) . '</li>';
+$overview .= '<li>' . __( 'Install and activate themes or plugins' ) . '</li>';
+$overview .= '<li>' . __( 'Update your network' ) . '</li>';
+$overview .= '<li>' . __( 'Modify global network settings' ) . '</li></ul>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __( 'Overview' ),
+ 'content' => $overview
+) );
+
+$quick_tasks = '<p>' . __( 'The Right Now widget on this screen provides current user and site counts on your network.' ) . '</p>';
+$quick_tasks .= '<ul><li>' . __( 'To add a new user <strong>click Create a New User</strong>' ) . '</li>';
+$quick_tasks .= '<li>' . __( 'To add a new site <strong>click Create a New Site</strong>' ) . '</li></ul>';
+$quick_tasks .= '<p>' . __( 'To search for a user or site, use the search boxes.' ) . '</p>';
+$quick_tasks .= '<ul><li>' . __( '<strong>To search for a user</strong> enter all or part of a username or email address' ) . '</li>';
+$quick_tasks .= '<li>' . __( '<strong>To search for a site</strong> enter the path or domain' ) . '</li></ul>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'quick-tasks',
+ 'title' => __( 'Quick Tasks' ),
+ 'content' => $quick_tasks
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin" target="_blank">Documentation on the Network Admin</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+wp_dashboard_setup();
+
+wp_enqueue_script( 'dashboard' );
+wp_enqueue_script( 'plugin-install' );
+add_thickbox();
+
+add_screen_option('layout_columns', array('max' => 4, 'default' => 2) );
+
+require_once( '../admin-header.php' );
+
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<div id="dashboard-widgets-wrap">
+
+<?php wp_dashboard(); ?>
+
+<div class="clear"></div>
+</div><!-- dashboard-widgets-wrap -->
+
+</div><!-- wrap -->
+
+<?php include( '../admin-footer.php' ); ?>
diff --git a/src/wp-admin/network/menu.php b/src/wp-admin/network/menu.php
new file mode 100644
index 0000000000..31d9b7204c
--- /dev/null
+++ b/src/wp-admin/network/menu.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Build Network Administration Menu.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/* translators: Network menu item */
+$menu[2] = array(__('Dashboard'), 'manage_network', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'div');
+
+$menu[4] = array( '', 'read', 'separator1', '', 'wp-menu-separator' );
+
+/* translators: Sites menu item */
+$menu[5] = array(__('Sites'), 'manage_sites', 'sites.php', '', 'menu-top menu-icon-site', 'menu-site', 'div');
+$submenu['sites.php'][5] = array( __('All Sites'), 'manage_sites', 'sites.php' );
+$submenu['sites.php'][10] = array( _x('Add New', 'site'), 'create_sites', 'site-new.php' );
+
+$menu[10] = array(__('Users'), 'manage_network_users', 'users.php', '', 'menu-top menu-icon-users', 'menu-users', 'div');
+$submenu['users.php'][5] = array( __('All Users'), 'manage_network_users', 'users.php' );
+$submenu['users.php'][10] = array( _x('Add New', 'user'), 'create_users', 'user-new.php' );
+
+$update_data = wp_get_update_data();
+
+if ( $update_data['counts']['themes'] ) {
+ $menu[15] = array(sprintf( __( 'Themes %s' ), "<span class='update-plugins count-{$update_data['counts']['themes']}'><span class='theme-count'>" . number_format_i18n( $update_data['counts']['themes'] ) . "</span></span>" ), 'manage_network_themes', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' );
+} else {
+ $menu[15] = array( __( 'Themes' ), 'manage_network_themes', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' );
+}
+$submenu['themes.php'][5] = array( __('Installed Themes'), 'manage_network_themes', 'themes.php' );
+$submenu['themes.php'][10] = array( _x('Add New', 'theme'), 'install_themes', 'theme-install.php' );
+$submenu['themes.php'][15] = array( _x('Editor', 'theme editor'), 'edit_themes', 'theme-editor.php' );
+
+if ( current_user_can( 'update_plugins' ) ) {
+ $menu[20] = array( sprintf( __( 'Plugins %s' ), "<span class='update-plugins count-{$update_data['counts']['plugins']}'><span class='plugin-count'>" . number_format_i18n( $update_data['counts']['plugins'] ) . "</span></span>" ), 'manage_network_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'div');
+} else {
+ $menu[20] = array( __('Plugins'), 'manage_network_plugins', 'plugins.php', '', 'menu-top menu-icon-plugins', 'menu-plugins', 'div' );
+}
+$submenu['plugins.php'][5] = array( __('Installed Plugins'), 'manage_network_plugins', 'plugins.php' );
+$submenu['plugins.php'][10] = array( _x('Add New', 'plugin'), 'install_plugins', 'plugin-install.php' );
+$submenu['plugins.php'][15] = array( _x('Editor', 'plugin editor'), 'edit_plugins', 'plugin-editor.php' );
+
+$menu[25] = array(__('Settings'), 'manage_network_options', 'settings.php', '', 'menu-top menu-icon-settings', 'menu-settings', 'div');
+if ( defined( 'MULTISITE' ) && defined( 'WP_ALLOW_MULTISITE' ) && WP_ALLOW_MULTISITE ) {
+ $submenu['settings.php'][5] = array( __('Network Settings'), 'manage_network_options', 'settings.php' );
+ $submenu['settings.php'][10] = array( __('Network Setup'), 'manage_network_options', 'setup.php' );
+}
+
+if ( $update_data['counts']['total'] ) {
+ $menu[30] = array( sprintf( __( 'Updates %s' ), "<span class='update-plugins count-{$update_data['counts']['total']}' title='{$update_data['title']}'><span class='update-count'>" . number_format_i18n($update_data['counts']['total']) . "</span></span>" ), 'manage_network', 'upgrade.php', '', 'menu-top menu-icon-tools', 'menu-update', 'div' );
+} else {
+ $menu[30] = array( __( 'Updates' ), 'manage_network', 'upgrade.php', '', 'menu-top menu-icon-tools', 'menu-update', 'div' );
+}
+
+unset($update_data);
+
+$submenu[ 'upgrade.php' ][10] = array( __( 'Available Updates' ), 'update_core', 'update-core.php' );
+$submenu[ 'upgrade.php' ][15] = array( __( 'Upgrade Network' ), 'manage_network', 'upgrade.php' );
+
+$menu[99] = array( '', 'read', 'separator-last', '', 'wp-menu-separator-last' );
+
+require_once(ABSPATH . 'wp-admin/includes/menu.php');
diff --git a/src/wp-admin/network/plugin-editor.php b/src/wp-admin/network/plugin-editor.php
new file mode 100644
index 0000000000..8850aa8f88
--- /dev/null
+++ b/src/wp-admin/network/plugin-editor.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Plugin editor network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../plugin-editor.php' );
diff --git a/src/wp-admin/network/plugin-install.php b/src/wp-admin/network/plugin-install.php
new file mode 100644
index 0000000000..5c6243f1cf
--- /dev/null
+++ b/src/wp-admin/network/plugin-install.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Install plugin network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+if ( isset( $_GET['tab'] ) && ( 'plugin-information' == $_GET['tab'] ) )
+ define( 'IFRAME_REQUEST', true );
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../plugin-install.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/plugins.php b/src/wp-admin/network/plugins.php
new file mode 100644
index 0000000000..514a22b41a
--- /dev/null
+++ b/src/wp-admin/network/plugins.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Network Plugins administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../plugins.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/profile.php b/src/wp-admin/network/profile.php
new file mode 100644
index 0000000000..c100e68865
--- /dev/null
+++ b/src/wp-admin/network/profile.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * User profile network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../profile.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/settings.php b/src/wp-admin/network/settings.php
new file mode 100644
index 0000000000..da4ac4d05c
--- /dev/null
+++ b/src/wp-admin/network/settings.php
@@ -0,0 +1,303 @@
+<?php
+/**
+ * Multisite network settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_network_options' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$title = __( 'Network Settings' );
+$parent_file = 'settings.php';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen sets and changes options for the network as a whole. The first site is the main site in the network and network options are pulled from that original site&#8217;s options.') . '</p>' .
+ '<p>' . __('Operational settings has fields for the network&#8217;s name and admin email.') . '</p>' .
+ '<p>' . __('Registration settings can disable/enable public signups. If you let others sign up for a site, install spam plugins. Spaces, not commas, should separate names banned as sites for this network.') . '</p>' .
+ '<p>' . __('New site settings are defaults applied when a new site is created in the network. These include welcome email for when a new site or user account is registered, and what&#8127;s put in the first post, page, comment, comment author, and comment URL.') . '</p>' .
+ '<p>' . __('Upload settings control the size of the uploaded files and the amount of available upload space for each site. You can change the default value for specific sites when you edit a particular site. Allowed file types are also listed (space separated only).') . '</p>' .
+ '<p>' . __('Menu setting enables/disables the plugin menus from appearing for non super admins, so that only super admins, not site admins, have access to activate plugins.') . '</p>' .
+ '<p>' . __('Super admins can no longer be added on the Options screen. You must now go to the list of existing users on Network Admin > Users and click on Username or the Edit action link below that name. This goes to an Edit User page where you can check a box to grant super admin privileges.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Settings_Screen" target="_blank">Documentation on Network Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( $_POST ) {
+ do_action( 'wpmuadminedit' , '' );
+
+ check_admin_referer( 'siteoptions' );
+
+ $checked_options = array( 'menu_items' => array(), 'registrationnotification' => 'no', 'upload_space_check_disabled' => 1, 'add_new_users' => 0 );
+ foreach ( $checked_options as $option_name => $option_unchecked_value ) {
+ if ( ! isset( $_POST[$option_name] ) )
+ $_POST[$option_name] = $option_unchecked_value;
+ }
+
+ $options = array(
+ 'registrationnotification', 'registration', 'add_new_users', 'menu_items',
+ 'upload_space_check_disabled', 'blog_upload_space', 'upload_filetypes', 'site_name',
+ 'first_post', 'first_page', 'first_comment', 'first_comment_url', 'first_comment_author',
+ 'welcome_email', 'welcome_user_email', 'fileupload_maxk', 'global_terms_enabled',
+ 'illegal_names', 'limited_email_domains', 'banned_email_domains', 'WPLANG', 'admin_email',
+ );
+
+ foreach ( $options as $option_name ) {
+ if ( ! isset($_POST[$option_name]) )
+ continue;
+ $value = wp_unslash( $_POST[$option_name] );
+ update_site_option( $option_name, $value );
+ }
+
+ // Update more options here
+ do_action( 'update_wpmu_options' );
+
+ wp_redirect( add_query_arg( 'updated', 'true', network_admin_url( 'settings.php' ) ) );
+ exit();
+}
+
+include( '../admin-header.php' );
+
+if ( isset( $_GET['updated'] ) ) {
+ ?><div id="message" class="updated"><p><?php _e( 'Options saved.' ) ?></p></div><?php
+}
+?>
+
+<div class="wrap">
+ <?php screen_icon('options-general'); ?>
+ <h2><?php echo esc_html( $title ); ?></h2>
+ <form method="post" action="settings.php">
+ <?php wp_nonce_field( 'siteoptions' ); ?>
+ <h3><?php _e( 'Operational Settings' ); ?></h3>
+ <table class="form-table">
+ <tr valign="top">
+ <th scope="row"><label for="site_name"><?php _e( 'Network Name' ) ?></label></th>
+ <td>
+ <input name="site_name" type="text" id="site_name" class="regular-text" value="<?php echo esc_attr( $current_site->site_name ) ?>" />
+ <br />
+ <?php _e( 'What you would like to call this network.' ) ?>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><label for="admin_email"><?php _e( 'Network Admin Email' ) ?></label></th>
+ <td>
+ <input name="admin_email" type="text" id="admin_email" class="regular-text" value="<?php echo esc_attr( get_site_option('admin_email') ) ?>" />
+ <br />
+ <?php printf( __( 'Registration and support emails will come from this address. An address such as <code>support@%s</code> is recommended.' ), $current_site->domain ); ?>
+ </td>
+ </tr>
+ </table>
+ <h3><?php _e( 'Registration Settings' ); ?></h3>
+ <table class="form-table">
+ <tr valign="top">
+ <th scope="row"><?php _e( 'Allow new registrations' ) ?></th>
+ <?php
+ if ( !get_site_option( 'registration' ) )
+ update_site_option( 'registration', 'none' );
+ $reg = get_site_option( 'registration' );
+ ?>
+ <td>
+ <label><input name="registration" type="radio" id="registration1" value="none"<?php checked( $reg, 'none') ?> /> <?php _e( 'Registration is disabled.' ); ?></label><br />
+ <label><input name="registration" type="radio" id="registration2" value="user"<?php checked( $reg, 'user') ?> /> <?php _e( 'User accounts may be registered.' ); ?></label><br />
+ <label><input name="registration" type="radio" id="registration3" value="blog"<?php checked( $reg, 'blog') ?> /> <?php _e( 'Logged in users may register new sites.' ); ?></label><br />
+ <label><input name="registration" type="radio" id="registration4" value="all"<?php checked( $reg, 'all') ?> /> <?php _e( 'Both sites and user accounts can be registered.' ); ?></label><br />
+ <?php if ( is_subdomain_install() )
+ _e( 'If registration is disabled, please set <code>NOBLOGREDIRECT</code> in <code>wp-config.php</code> to a URL you will redirect visitors to if they visit a non-existent site.' );
+ ?>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><?php _e( 'Registration notification' ) ?></th>
+ <?php
+ if ( !get_site_option( 'registrationnotification' ) )
+ update_site_option( 'registrationnotification', 'yes' );
+ ?>
+ <td>
+ <label><input name="registrationnotification" type="checkbox" id="registrationnotification" value="yes"<?php checked( get_site_option( 'registrationnotification' ), 'yes' ) ?> /> <?php _e( 'Send the network admin an email notification every time someone registers a site or user account.' ) ?></label>
+ </td>
+ </tr>
+
+ <tr valign="top" id="addnewusers">
+ <th scope="row"><?php _e( 'Add New Users' ) ?></th>
+ <td>
+ <label><input name="add_new_users" type="checkbox" id="add_new_users" value="1"<?php checked( get_site_option( 'add_new_users' ) ) ?> /> <?php _e( 'Allow site administrators to add new users to their site via the "Users &rarr; Add New" page.' ); ?></label>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><label for="illegal_names"><?php _e( 'Banned Names' ) ?></label></th>
+ <td>
+ <input name="illegal_names" type="text" id="illegal_names" class="large-text" value="<?php echo esc_attr( implode( " ", (array) get_site_option( 'illegal_names' ) ) ); ?>" size="45" />
+ <br />
+ <?php _e( 'Users are not allowed to register these sites. Separate names by spaces.' ) ?>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><label for="limited_email_domains"><?php _e( 'Limited Email Registrations' ) ?></label></th>
+ <td>
+ <?php $limited_email_domains = get_site_option( 'limited_email_domains' );
+ $limited_email_domains = str_replace( ' ', "\n", $limited_email_domains ); ?>
+ <textarea name="limited_email_domains" id="limited_email_domains" cols="45" rows="5">
+<?php echo esc_textarea( $limited_email_domains == '' ? '' : implode( "\n", (array) $limited_email_domains ) ); ?></textarea>
+ <br />
+ <?php _e( 'If you want to limit site registrations to certain domains. One domain per line.' ) ?>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><label for="banned_email_domains"><?php _e('Banned Email Domains') ?></label></th>
+ <td>
+ <textarea name="banned_email_domains" id="banned_email_domains" cols="45" rows="5">
+<?php echo esc_textarea( get_site_option( 'banned_email_domains' ) == '' ? '' : implode( "\n", (array) get_site_option( 'banned_email_domains' ) ) ); ?></textarea>
+ <br />
+ <?php _e( 'If you want to ban domains from site registrations. One domain per line.' ) ?>
+ </td>
+ </tr>
+
+ </table>
+ <h3><?php _e('New Site Settings'); ?></h3>
+ <table class="form-table">
+
+ <tr valign="top">
+ <th scope="row"><label for="welcome_email"><?php _e( 'Welcome Email' ) ?></label></th>
+ <td>
+ <textarea name="welcome_email" id="welcome_email" rows="5" cols="45" class="large-text">
+<?php echo esc_textarea( get_site_option( 'welcome_email' ) ) ?></textarea>
+ <br />
+ <?php _e( 'The welcome email sent to new site owners.' ) ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label for="welcome_user_email"><?php _e( 'Welcome User Email' ) ?></label></th>
+ <td>
+ <textarea name="welcome_user_email" id="welcome_user_email" rows="5" cols="45" class="large-text">
+<?php echo esc_textarea( get_site_option( 'welcome_user_email' ) ) ?></textarea>
+ <br />
+ <?php _e( 'The welcome email sent to new users.' ) ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label for="first_post"><?php _e( 'First Post' ) ?></label></th>
+ <td>
+ <textarea name="first_post" id="first_post" rows="5" cols="45" class="large-text">
+<?php echo esc_textarea( get_site_option( 'first_post' ) ) ?></textarea>
+ <br />
+ <?php _e( 'The first post on a new site.' ) ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label for="first_page"><?php _e( 'First Page' ) ?></label></th>
+ <td>
+ <textarea name="first_page" id="first_page" rows="5" cols="45" class="large-text">
+<?php echo esc_textarea( get_site_option( 'first_page' ) ) ?></textarea>
+ <br />
+ <?php _e( 'The first page on a new site.' ) ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label for="first_comment"><?php _e( 'First Comment' ) ?></label></th>
+ <td>
+ <textarea name="first_comment" id="first_comment" rows="5" cols="45" class="large-text">
+<?php echo esc_textarea( get_site_option( 'first_comment' ) ) ?></textarea>
+ <br />
+ <?php _e( 'The first comment on a new site.' ) ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label for="first_comment_author"><?php _e( 'First Comment Author' ) ?></label></th>
+ <td>
+ <input type="text" size="40" name="first_comment_author" id="first_comment_author" value="<?php echo get_site_option('first_comment_author') ?>" />
+ <br />
+ <?php _e( 'The author of the first comment on a new site.' ) ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row"><label for="first_comment_url"><?php _e( 'First Comment URL' ) ?></label></th>
+ <td>
+ <input type="text" size="40" name="first_comment_url" id="first_comment_url" value="<?php echo esc_attr( get_site_option( 'first_comment_url' ) ) ?>" />
+ <br />
+ <?php _e( 'The URL for the first comment on a new site.' ) ?>
+ </td>
+ </tr>
+ </table>
+ <h3><?php _e( 'Upload Settings' ); ?></h3>
+ <table class="form-table">
+ <tr valign="top">
+ <th scope="row"><?php _e( 'Site upload space' ) ?></th>
+ <td>
+ <label><input type="checkbox" id="upload_space_check_disabled" name="upload_space_check_disabled" value="0"<?php checked( get_site_option( 'upload_space_check_disabled' ), 0 ) ?>/> <?php printf( __( 'Limit total size of files uploaded to %s MB' ), '</label><label><input name="blog_upload_space" type="number" min="0" style="width: 100px" id="blog_upload_space" value="' . esc_attr( get_site_option('blog_upload_space', 100) ) . '" />' ); ?></label><br />
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><label for="upload_filetypes"><?php _e( 'Upload file types' ) ?></label></th>
+ <td><input name="upload_filetypes" type="text" id="upload_filetypes" class="large-text" value="<?php echo esc_attr( get_site_option('upload_filetypes', 'jpg jpeg png gif') ) ?>" size="45" /></td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row"><label for="fileupload_maxk"><?php _e( 'Max upload file size' ) ?></label></th>
+ <td><?php printf( _x( '%s KB', 'File size in kilobytes' ), '<input name="fileupload_maxk" type="number" min="0" style="width: 100px" id="fileupload_maxk" value="' . esc_attr( get_site_option( 'fileupload_maxk', 300 ) ) . '" />' ); ?></td>
+ </tr>
+ </table>
+
+<?php
+ $languages = get_available_languages();
+ if ( ! empty( $languages ) ) {
+ $lang = get_site_option( 'WPLANG' );
+?>
+ <h3><?php _e( 'Language Settings' ); ?></h3>
+ <table class="form-table">
+ <tr valign="top">
+ <th><label for="WPLANG"><?php _e( 'Default Language' ); ?></label></th>
+ <td>
+ <select name="WPLANG" id="WPLANG">
+ <?php mu_dropdown_languages( $languages, get_site_option( 'WPLANG' ) ); ?>
+ </select>
+ </td>
+ </tr>
+ </table>
+<?php
+ } // languages
+?>
+
+ <h3><?php _e( 'Menu Settings' ); ?></h3>
+ <table id="menu" class="form-table">
+ <tr valign="top">
+ <th scope="row"><?php _e( 'Enable administration menus' ); ?></th>
+ <td>
+ <?php
+ $menu_perms = get_site_option( 'menu_items' );
+ $menu_items = apply_filters( 'mu_menu_items', array( 'plugins' => __( 'Plugins' ) ) );
+ foreach ( (array) $menu_items as $key => $val ) {
+ echo "<label><input type='checkbox' name='menu_items[" . $key . "]' value='1'" . ( isset( $menu_perms[$key] ) ? checked( $menu_perms[$key], '1', false ) : '' ) . " /> " . esc_html( $val ) . "</label><br/>";
+ }
+ ?>
+ </td>
+ </tr>
+ </table>
+
+ <?php do_action( 'wpmu_options' ); // Add more options here ?>
+
+ <?php submit_button(); ?>
+ </form>
+</div>
+
+<?php include( '../admin-footer.php' ); ?>
diff --git a/src/wp-admin/network/setup.php b/src/wp-admin/network/setup.php
new file mode 100644
index 0000000000..e5d5880f9e
--- /dev/null
+++ b/src/wp-admin/network/setup.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Network Setup administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../network.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/site-info.php b/src/wp-admin/network/site-info.php
new file mode 100644
index 0000000000..7dd6aeb23a
--- /dev/null
+++ b/src/wp-admin/network/site-info.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * Edit Site Info Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_sites' ) )
+ wp_die( __( 'You do not have sufficient permissions to edit this site.' ) );
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('The menu is for editing information specific to individual sites, particularly if the admin area of a site is unavailable.') . '</p>' .
+ '<p>' . __('<strong>Info</strong> - The domain and path are rarely edited as this can cause the site to not work properly. The Registered date and Last Updated date are displayed. Network admins can mark a site as archived, spam, deleted and mature, to remove from public listings or disable.') . '</p>' .
+ '<p>' . __('<strong>Users</strong> - This displays the users associated with this site. You can also change their role, reset their password, or remove them from the site. Removing the user from the site does not remove the user from the network.') . '</p>' .
+ '<p>' . sprintf( __('<strong>Themes</strong> - This area shows themes that are not already enabled across the network. Enabling a theme in this menu makes it accessible to this site. It does not activate the theme, but allows it to show in the site&#8217;s Appearance menu. To enable a theme for the entire network, see the <a href="%s">Network Themes</a> screen.' ), network_admin_url( 'themes.php' ) ) . '</p>' .
+ '<p>' . __('<strong>Settings</strong> - This page shows a list of all settings associated with this site. Some are created by WordPress and others are created by plugins you activate. Note that some fields are grayed out and say Serialized Data. You cannot modify these values due to the way the setting is stored in the database.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Sites_Screen" target="_blank">Documentation on Site Management</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+
+if ( ! $id )
+ wp_die( __('Invalid site ID.') );
+
+$details = get_blog_details( $id );
+if ( !can_edit_network( $details->site_id ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$is_main_site = is_main_site( $id );
+
+if ( isset($_REQUEST['action']) && 'update-site' == $_REQUEST['action'] ) {
+ check_admin_referer( 'edit-site' );
+
+ switch_to_blog( $id );
+
+ if ( isset( $_POST['update_home_url'] ) && $_POST['update_home_url'] == 'update' ) {
+ $blog_address = get_blogaddress_by_domain( $_POST['blog']['domain'], $_POST['blog']['path'] );
+ if ( get_option( 'siteurl' ) != $blog_address )
+ update_option( 'siteurl', $blog_address );
+
+ if ( get_option( 'home' ) != $blog_address )
+ update_option( 'home', $blog_address );
+ }
+
+ // rewrite rules can't be flushed during switch to blog
+ delete_option( 'rewrite_rules' );
+
+ // update blogs table
+ $blog_data = wp_unslash( $_POST['blog'] );
+ $existing_details = get_blog_details( $id, false );
+ $blog_data_checkboxes = array( 'public', 'archived', 'spam', 'mature', 'deleted' );
+ foreach ( $blog_data_checkboxes as $c ) {
+ if ( ! in_array( $existing_details->$c, array( 0, 1 ) ) )
+ $blog_data[ $c ] = $existing_details->$c;
+ else
+ $blog_data[ $c ] = isset( $_POST['blog'][ $c ] ) ? 1 : 0;
+ }
+ update_blog_details( $id, $blog_data );
+
+ restore_current_blog();
+ wp_redirect( add_query_arg( array( 'update' => 'updated', 'id' => $id ), 'site-info.php') );
+ exit;
+}
+
+if ( isset($_GET['update']) ) {
+ $messages = array();
+ if ( 'updated' == $_GET['update'] )
+ $messages[] = __('Site info updated.');
+}
+
+$site_url_no_http = preg_replace( '#^http(s)?://#', '', get_blogaddress_by_id( $id ) );
+$title_site_url_linked = sprintf( __('Edit Site: <a href="%1$s">%2$s</a>'), get_blogaddress_by_id( $id ), $site_url_no_http );
+$title = sprintf( __('Edit Site: %s'), $site_url_no_http );
+
+$parent_file = 'sites.php';
+$submenu_file = 'sites.php';
+
+require('../admin-header.php');
+
+?>
+
+<div class="wrap">
+<?php screen_icon('ms-admin'); ?>
+<h2 id="edit-site"><?php echo $title_site_url_linked ?></h2>
+<h3 class="nav-tab-wrapper">
+<?php
+$tabs = array(
+ 'site-info' => array( 'label' => __( 'Info' ), 'url' => 'site-info.php' ),
+ 'site-users' => array( 'label' => __( 'Users' ), 'url' => 'site-users.php' ),
+ 'site-themes' => array( 'label' => __( 'Themes' ), 'url' => 'site-themes.php' ),
+ 'site-settings' => array( 'label' => __( 'Settings' ), 'url' => 'site-settings.php' ),
+);
+foreach ( $tabs as $tab_id => $tab ) {
+ $class = ( $tab['url'] == $pagenow ) ? ' nav-tab-active' : '';
+ echo '<a href="' . $tab['url'] . '?id=' . $id .'" class="nav-tab' . $class . '">' . esc_html( $tab['label'] ) . '</a>';
+}
+?>
+</h3>
+<?php
+if ( ! empty( $messages ) ) {
+ foreach ( $messages as $msg )
+ echo '<div id="message" class="updated"><p>' . $msg . '</p></div>';
+} ?>
+<form method="post" action="site-info.php?action=update-site">
+ <?php wp_nonce_field( 'edit-site' ); ?>
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+ <table class="form-table">
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Domain' ) ?></th>
+ <?php
+ $protocol = is_ssl() ? 'https://' : 'http://';
+ if ( $is_main_site ) { ?>
+ <td><code><?php echo $protocol; echo esc_attr( $details->domain ) ?></code></td>
+ <?php } else { ?>
+ <td><?php echo $protocol; ?><input name="blog[domain]" type="text" id="domain" value="<?php echo esc_attr( $details->domain ) ?>" size="33" /></td>
+ <?php } ?>
+ </tr>
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Path' ) ?></th>
+ <?php if ( $is_main_site ) { ?>
+ <td><code><?php echo esc_attr( $details->path ) ?></code></td>
+ <?php
+ } else {
+ switch_to_blog( $id );
+ ?>
+ <td><input name="blog[path]" type="text" id="path" value="<?php echo esc_attr( $details->path ) ?>" size="40" style='margin-bottom:5px;' />
+ <br /><input type="checkbox" style="width:20px;" name="update_home_url" value="update" <?php if ( get_option( 'siteurl' ) == untrailingslashit( get_blogaddress_by_id ($id ) ) || get_option( 'home' ) == untrailingslashit( get_blogaddress_by_id( $id ) ) ) echo 'checked="checked"'; ?> /> <?php _e( 'Update <code>siteurl</code> and <code>home</code> as well.' ); ?></td>
+ <?php
+ restore_current_blog();
+ } ?>
+ </tr>
+ <tr class="form-field">
+ <th scope="row"><?php _ex( 'Registered', 'site' ) ?></th>
+ <td><input name="blog[registered]" type="text" id="blog_registered" value="<?php echo esc_attr( $details->registered ) ?>" size="40" /></td>
+ </tr>
+ <tr class="form-field">
+ <th scope="row"><?php _e( 'Last Updated' ); ?></th>
+ <td><input name="blog[last_updated]" type="text" id="blog_last_updated" value="<?php echo esc_attr( $details->last_updated ) ?>" size="40" /></td>
+ </tr>
+ <?php
+ $attribute_fields = array( 'public' => __( 'Public' ) );
+ if ( ! $is_main_site ) {
+ $attribute_fields['archived'] = __( 'Archived' );
+ $attribute_fields['spam'] = _x( 'Spam', 'site' );
+ $attribute_fields['deleted'] = __( 'Deleted' );
+ }
+ $attribute_fields['mature'] = __( 'Mature' );
+ ?>
+ <tr>
+ <th scope="row"><?php _e( 'Attributes' ); ?></th>
+ <td>
+ <?php foreach ( $attribute_fields as $field_key => $field_label ) : ?>
+ <label><input type="checkbox" name="blog[<?php echo $field_key; ?>]" value="1" <?php checked( (bool) $details->$field_key, true ); disabled( ! in_array( $details->$field_key, array( 0, 1 ) ) ); ?> />
+ <?php echo $field_label; ?></label><br/>
+ <?php endforeach; ?>
+ </td>
+ </tr>
+ </table>
+ <?php submit_button(); ?>
+</form>
+
+</div>
+<?php
+require('../admin-footer.php');
diff --git a/src/wp-admin/network/site-new.php b/src/wp-admin/network/site-new.php
new file mode 100644
index 0000000000..9fc5eefd48
--- /dev/null
+++ b/src/wp-admin/network/site-new.php
@@ -0,0 +1,153 @@
+<?php
+/**
+ * Add Site Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_sites' ) )
+ wp_die( __( 'You do not have sufficient permissions to add sites to this network.' ) );
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen is for Super Admins to add new sites to the network. This is not affected by the registration settings.') . '</p>' .
+ '<p>' . __('If the admin email for the new site does not exist in the database, a new user will also be created.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Sites_Screen" target="_blank">Documentation on Site Management</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( isset($_REQUEST['action']) && 'add-site' == $_REQUEST['action'] ) {
+ check_admin_referer( 'add-blog', '_wpnonce_add-blog' );
+
+ if ( ! current_user_can( 'manage_sites' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+ if ( ! is_array( $_POST['blog'] ) )
+ wp_die( __( 'Can&#8217;t create an empty site.' ) );
+ $blog = $_POST['blog'];
+ $domain = '';
+ if ( preg_match( '|^([a-zA-Z0-9-])+$|', $blog['domain'] ) )
+ $domain = strtolower( $blog['domain'] );
+
+ // If not a subdomain install, make sure the domain isn't a reserved word
+ if ( ! is_subdomain_install() ) {
+ $subdirectory_reserved_names = apply_filters( 'subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' ) );
+ if ( in_array( $domain, $subdirectory_reserved_names ) )
+ wp_die( sprintf( __('The following words are reserved for use by WordPress functions and cannot be used as blog names: <code>%s</code>' ), implode( '</code>, <code>', $subdirectory_reserved_names ) ) );
+ }
+
+ $email = sanitize_email( $blog['email'] );
+ $title = $blog['title'];
+
+ if ( empty( $domain ) )
+ wp_die( __( 'Missing or invalid site address.' ) );
+ if ( empty( $email ) )
+ wp_die( __( 'Missing email address.' ) );
+ if ( !is_email( $email ) )
+ wp_die( __( 'Invalid email address.' ) );
+
+ if ( is_subdomain_install() ) {
+ $newdomain = $domain . '.' . preg_replace( '|^www\.|', '', $current_site->domain );
+ $path = $current_site->path;
+ } else {
+ $newdomain = $current_site->domain;
+ $path = $current_site->path . $domain . '/';
+ }
+
+ $password = 'N/A';
+ $user_id = email_exists($email);
+ if ( !$user_id ) { // Create a new user with a random password
+ $password = wp_generate_password( 12, false );
+ $user_id = wpmu_create_user( $domain, $password, $email );
+ if ( false == $user_id )
+ wp_die( __( 'There was an error creating the user.' ) );
+ else
+ wp_new_user_notification( $user_id, $password );
+ }
+
+ $wpdb->hide_errors();
+ $id = wpmu_create_blog( $newdomain, $path, $title, $user_id , array( 'public' => 1 ), $current_site->id );
+ $wpdb->show_errors();
+ if ( !is_wp_error( $id ) ) {
+ if ( !is_super_admin( $user_id ) && !get_user_option( 'primary_blog', $user_id ) )
+ update_user_option( $user_id, 'primary_blog', $id, true );
+ $content_mail = sprintf( __( 'New site created by %1$s
+
+Address: %2$s
+Name: %3$s' ), $current_user->user_login , get_site_url( $id ), wp_unslash( $title ) );
+ wp_mail( get_site_option('admin_email'), sprintf( __( '[%s] New Site Created' ), $current_site->site_name ), $content_mail, 'From: "Site Admin" <' . get_site_option( 'admin_email' ) . '>' );
+ wpmu_welcome_notification( $id, $user_id, $password, $title, array( 'public' => 1 ) );
+ wp_redirect( add_query_arg( array( 'update' => 'added', 'id' => $id ), 'site-new.php' ) );
+ exit;
+ } else {
+ wp_die( $id->get_error_message() );
+ }
+}
+
+if ( isset($_GET['update']) ) {
+ $messages = array();
+ if ( 'added' == $_GET['update'] )
+ $messages[] = sprintf( __( 'Site added. <a href="%1$s">Visit Dashboard</a> or <a href="%2$s">Edit Site</a>' ), esc_url( get_admin_url( absint( $_GET['id'] ) ) ), network_admin_url( 'site-info.php?id=' . absint( $_GET['id'] ) ) );
+}
+
+$title = __('Add New Site');
+$parent_file = 'sites.php';
+
+require('../admin-header.php');
+
+?>
+
+<div class="wrap">
+<?php screen_icon('ms-admin'); ?>
+<h2 id="add-new-site"><?php _e('Add New Site') ?></h2>
+<?php
+if ( ! empty( $messages ) ) {
+ foreach ( $messages as $msg )
+ echo '<div id="message" class="updated"><p>' . $msg . '</p></div>';
+} ?>
+<form method="post" action="<?php echo network_admin_url('site-new.php?action=add-site'); ?>">
+<?php wp_nonce_field( 'add-blog', '_wpnonce_add-blog' ) ?>
+ <table class="form-table">
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Site Address' ) ?></th>
+ <td>
+ <?php if ( is_subdomain_install() ) { ?>
+ <input name="blog[domain]" type="text" class="regular-text" title="<?php esc_attr_e( 'Domain' ) ?>"/><span class="no-break">.<?php echo preg_replace( '|^www\.|', '', $current_site->domain ); ?></span>
+ <?php } else {
+ echo $current_site->domain . $current_site->path ?><input name="blog[domain]" class="regular-text" type="text" title="<?php esc_attr_e( 'Domain' ) ?>"/>
+ <?php }
+ echo '<p>' . __( 'Only lowercase letters (a-z) and numbers are allowed.' ) . '</p>';
+ ?>
+ </td>
+ </tr>
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Site Title' ) ?></th>
+ <td><input name="blog[title]" type="text" class="regular-text" title="<?php esc_attr_e( 'Title' ) ?>"/></td>
+ </tr>
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Admin Email' ) ?></th>
+ <td><input name="blog[email]" type="text" class="regular-text" title="<?php esc_attr_e( 'Email' ) ?>"/></td>
+ </tr>
+ <tr class="form-field">
+ <td colspan="2"><?php _e( 'A new user will be created if the above email address is not in the database.' ) ?><br /><?php _e( 'The username and password will be mailed to this email address.' ) ?></td>
+ </tr>
+ </table>
+ <?php submit_button( __('Add Site'), 'primary', 'add-site' ); ?>
+ </form>
+</div>
+<?php
+require('../admin-footer.php');
diff --git a/src/wp-admin/network/site-settings.php b/src/wp-admin/network/site-settings.php
new file mode 100644
index 0000000000..c3aec75dee
--- /dev/null
+++ b/src/wp-admin/network/site-settings.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * Edit Site Settings Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_sites' ) )
+ wp_die( __( 'You do not have sufficient permissions to edit this site.' ) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('The menu is for editing information specific to individual sites, particularly if the admin area of a site is unavailable.') . '</p>' .
+ '<p>' . __('<strong>Info</strong> - The domain and path are rarely edited as this can cause the site to not work properly. The Registered date and Last Updated date are displayed. Network admins can mark a site as archived, spam, deleted and mature, to remove from public listings or disable.') . '</p>' .
+ '<p>' . __('<strong>Users</strong> - This displays the users associated with this site. You can also change their role, reset their password, or remove them from the site. Removing the user from the site does not remove the user from the network.') . '</p>' .
+ '<p>' . sprintf( __('<strong>Themes</strong> - This area shows themes that are not already enabled across the network. Enabling a theme in this menu makes it accessible to this site. It does not activate the theme, but allows it to show in the site&#8217;s Appearance menu. To enable a theme for the entire network, see the <a href="%s">Network Themes</a> screen.' ), network_admin_url( 'themes.php' ) ) . '</p>' .
+ '<p>' . __('<strong>Settings</strong> - This page shows a list of all settings associated with this site. Some are created by WordPress and others are created by plugins you activate. Note that some fields are grayed out and say Serialized Data. You cannot modify these values due to the way the setting is stored in the database.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Sites_Screen" target="_blank">Documentation on Site Management</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+
+if ( ! $id )
+ wp_die( __('Invalid site ID.') );
+
+$details = get_blog_details( $id );
+if ( !can_edit_network( $details->site_id ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$is_main_site = is_main_site( $id );
+
+if ( isset($_REQUEST['action']) && 'update-site' == $_REQUEST['action'] && is_array( $_POST['option'] ) ) {
+ check_admin_referer( 'edit-site' );
+
+ switch_to_blog( $id );
+
+ $skip_options = array( 'allowedthemes' ); // Don't update these options since they are handled elsewhere in the form.
+ foreach ( (array) $_POST['option'] as $key => $val ) {
+ $key = wp_unslash( $key );
+ $val = wp_unslash( $val );
+ if ( $key === 0 || is_array( $val ) || in_array($key, $skip_options) )
+ continue; // Avoids "0 is a protected WP option and may not be modified" error when edit blog options
+ update_option( $key, $val );
+ }
+
+ do_action( 'wpmu_update_blog_options' );
+ restore_current_blog();
+ wp_redirect( add_query_arg( array( 'update' => 'updated', 'id' => $id ), 'site-settings.php') );
+ exit;
+}
+
+if ( isset($_GET['update']) ) {
+ $messages = array();
+ if ( 'updated' == $_GET['update'] )
+ $messages[] = __('Site options updated.');
+}
+
+$site_url_no_http = preg_replace( '#^http(s)?://#', '', get_blogaddress_by_id( $id ) );
+$title_site_url_linked = sprintf( __('Edit Site: <a href="%1$s">%2$s</a>'), get_blogaddress_by_id( $id ), $site_url_no_http );
+$title = sprintf( __('Edit Site: %s'), $site_url_no_http );
+
+$parent_file = 'sites.php';
+$submenu_file = 'sites.php';
+
+require('../admin-header.php');
+
+?>
+
+<div class="wrap">
+<?php screen_icon('ms-admin'); ?>
+<h2 id="edit-site"><?php echo $title_site_url_linked ?></h2>
+<h3 class="nav-tab-wrapper">
+<?php
+$tabs = array(
+ 'site-info' => array( 'label' => __( 'Info' ), 'url' => 'site-info.php' ),
+ 'site-users' => array( 'label' => __( 'Users' ), 'url' => 'site-users.php' ),
+ 'site-themes' => array( 'label' => __( 'Themes' ), 'url' => 'site-themes.php' ),
+ 'site-settings' => array( 'label' => __( 'Settings' ), 'url' => 'site-settings.php' ),
+);
+foreach ( $tabs as $tab_id => $tab ) {
+ $class = ( $tab['url'] == $pagenow ) ? ' nav-tab-active' : '';
+ echo '<a href="' . $tab['url'] . '?id=' . $id .'" class="nav-tab' . $class . '">' . esc_html( $tab['label'] ) . '</a>';
+}
+?>
+</h3>
+<?php
+if ( ! empty( $messages ) ) {
+ foreach ( $messages as $msg )
+ echo '<div id="message" class="updated"><p>' . $msg . '</p></div>';
+} ?>
+<form method="post" action="site-settings.php?action=update-site">
+ <?php wp_nonce_field( 'edit-site' ); ?>
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+ <table class="form-table">
+ <?php
+ $blog_prefix = $wpdb->get_blog_prefix( $id );
+ $options = $wpdb->get_results( "SELECT * FROM {$blog_prefix}options WHERE option_name NOT LIKE '\_%' AND option_name NOT LIKE '%user_roles'" );
+ foreach ( $options as $option ) {
+ if ( $option->option_name == 'default_role' )
+ $editblog_default_role = $option->option_value;
+ $disabled = false;
+ $class = 'all-options';
+ if ( is_serialized( $option->option_value ) ) {
+ if ( is_serialized_string( $option->option_value ) ) {
+ $option->option_value = esc_html( maybe_unserialize( $option->option_value ) );
+ } else {
+ $option->option_value = 'SERIALIZED DATA';
+ $disabled = true;
+ $class = 'all-options disabled';
+ }
+ }
+ if ( strpos( $option->option_value, "\n" ) !== false ) {
+ ?>
+ <tr class="form-field">
+ <th scope="row"><?php echo ucwords( str_replace( "_", " ", $option->option_name ) ) ?></th>
+ <td><textarea class="<?php echo $class; ?>" rows="5" cols="40" name="option[<?php echo esc_attr( $option->option_name ) ?>]" id="<?php echo esc_attr( $option->option_name ) ?>"<?php disabled( $disabled ) ?>><?php echo esc_textarea( $option->option_value ) ?></textarea></td>
+ </tr>
+ <?php
+ } else {
+ ?>
+ <tr class="form-field">
+ <th scope="row"><?php echo esc_html( ucwords( str_replace( "_", " ", $option->option_name ) ) ); ?></th>
+ <?php if ( $is_main_site && in_array( $option->option_name, array( 'siteurl', 'home' ) ) ) { ?>
+ <td><code><?php echo esc_html( $option->option_value ) ?></code></td>
+ <?php } else { ?>
+ <td><input class="<?php echo $class; ?>" name="option[<?php echo esc_attr( $option->option_name ) ?>]" type="text" id="<?php echo esc_attr( $option->option_name ) ?>" value="<?php echo esc_attr( $option->option_value ) ?>" size="40" <?php disabled( $disabled ) ?> /></td>
+ <?php } ?>
+ </tr>
+ <?php
+ }
+ } // End foreach
+ do_action( 'wpmueditblogaction', $id );
+ ?>
+ </table>
+ <?php submit_button(); ?>
+</form>
+
+</div>
+<?php
+require('../admin-footer.php');
diff --git a/src/wp-admin/network/site-themes.php b/src/wp-admin/network/site-themes.php
new file mode 100644
index 0000000000..b47a0c694a
--- /dev/null
+++ b/src/wp-admin/network/site-themes.php
@@ -0,0 +1,182 @@
+<?php
+/**
+ * Edit Site Themes Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_sites' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage themes for this site.' ) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('The menu is for editing information specific to individual sites, particularly if the admin area of a site is unavailable.') . '</p>' .
+ '<p>' . __('<strong>Info</strong> - The domain and path are rarely edited as this can cause the site to not work properly. The Registered date and Last Updated date are displayed. Network admins can mark a site as archived, spam, deleted and mature, to remove from public listings or disable.') . '</p>' .
+ '<p>' . __('<strong>Users</strong> - This displays the users associated with this site. You can also change their role, reset their password, or remove them from the site. Removing the user from the site does not remove the user from the network.') . '</p>' .
+ '<p>' . sprintf( __('<strong>Themes</strong> - This area shows themes that are not already enabled across the network. Enabling a theme in this menu makes it accessible to this site. It does not activate the theme, but allows it to show in the site&#8217;s Appearance menu. To enable a theme for the entire network, see the <a href="%s">Network Themes</a> screen.' ), network_admin_url( 'themes.php' ) ) . '</p>' .
+ '<p>' . __('<strong>Settings</strong> - This page shows a list of all settings associated with this site. Some are created by WordPress and others are created by plugins you activate. Note that some fields are grayed out and say Serialized Data. You cannot modify these values due to the way the setting is stored in the database.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Sites_Screen" target="_blank">Documentation on Site Management</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$wp_list_table = _get_list_table('WP_MS_Themes_List_Table');
+
+$action = $wp_list_table->current_action();
+
+$s = isset($_REQUEST['s']) ? $_REQUEST['s'] : '';
+
+// Clean up request URI from temporary args for screen options/paging uri's to work as expected.
+$temp_args = array( 'enabled', 'disabled', 'error' );
+$_SERVER['REQUEST_URI'] = remove_query_arg( $temp_args, $_SERVER['REQUEST_URI'] );
+$referer = remove_query_arg( $temp_args, wp_get_referer() );
+
+$id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+
+if ( ! $id )
+ wp_die( __('Invalid site ID.') );
+
+$wp_list_table->prepare_items();
+
+$details = get_blog_details( $id );
+if ( !can_edit_network( $details->site_id ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$is_main_site = is_main_site( $id );
+
+if ( $action ) {
+ switch_to_blog( $id );
+ $allowed_themes = get_option( 'allowedthemes' );
+
+ switch ( $action ) {
+ case 'enable':
+ check_admin_referer( 'enable-theme_' . $_GET['theme'] );
+ $theme = $_GET['theme'];
+ $action = 'enabled';
+ $n = 1;
+ if ( !$allowed_themes )
+ $allowed_themes = array( $theme => true );
+ else
+ $allowed_themes[$theme] = true;
+ break;
+ case 'disable':
+ check_admin_referer( 'disable-theme_' . $_GET['theme'] );
+ $theme = $_GET['theme'];
+ $action = 'disabled';
+ $n = 1;
+ if ( !$allowed_themes )
+ $allowed_themes = array();
+ else
+ unset( $allowed_themes[$theme] );
+ break;
+ case 'enable-selected':
+ check_admin_referer( 'bulk-themes' );
+ if ( isset( $_POST['checked'] ) ) {
+ $themes = (array) $_POST['checked'];
+ $action = 'enabled';
+ $n = count( $themes );
+ foreach( (array) $themes as $theme )
+ $allowed_themes[ $theme ] = true;
+ } else {
+ $action = 'error';
+ $n = 'none';
+ }
+ break;
+ case 'disable-selected':
+ check_admin_referer( 'bulk-themes' );
+ if ( isset( $_POST['checked'] ) ) {
+ $themes = (array) $_POST['checked'];
+ $action = 'disabled';
+ $n = count( $themes );
+ foreach( (array) $themes as $theme )
+ unset( $allowed_themes[ $theme ] );
+ } else {
+ $action = 'error';
+ $n = 'none';
+ }
+ break;
+ }
+
+ update_option( 'allowedthemes', $allowed_themes );
+ restore_current_blog();
+
+ wp_safe_redirect( add_query_arg( array( 'id' => $id, $action => $n ), $referer ) );
+ exit;
+}
+
+if ( isset( $_GET['action'] ) && 'update-site' == $_GET['action'] ) {
+ wp_safe_redirect( $referer );
+ exit();
+}
+
+add_thickbox();
+add_screen_option( 'per_page', array( 'label' => _x( 'Themes', 'themes per page (screen options)' ) ) );
+
+$site_url_no_http = preg_replace( '#^http(s)?://#', '', get_blogaddress_by_id( $id ) );
+$title_site_url_linked = sprintf( __('Edit Site: <a href="%1$s">%2$s</a>'), get_blogaddress_by_id( $id ), $site_url_no_http );
+$title = sprintf( __('Edit Site: %s'), $site_url_no_http );
+
+$parent_file = 'sites.php';
+$submenu_file = 'sites.php';
+
+require('../admin-header.php'); ?>
+
+<div class="wrap">
+<?php screen_icon('ms-admin'); ?>
+<h2 id="edit-site"><?php echo $title_site_url_linked ?></h2>
+<h3 class="nav-tab-wrapper">
+<?php
+$tabs = array(
+ 'site-info' => array( 'label' => __( 'Info' ), 'url' => 'site-info.php' ),
+ 'site-users' => array( 'label' => __( 'Users' ), 'url' => 'site-users.php' ),
+ 'site-themes' => array( 'label' => __( 'Themes' ), 'url' => 'site-themes.php' ),
+ 'site-settings' => array( 'label' => __( 'Settings' ), 'url' => 'site-settings.php' ),
+);
+foreach ( $tabs as $tab_id => $tab ) {
+ $class = ( $tab['url'] == $pagenow ) ? ' nav-tab-active' : '';
+ echo '<a href="' . $tab['url'] . '?id=' . $id .'" class="nav-tab' . $class . '">' . esc_html( $tab['label'] ) . '</a>';
+}
+?>
+</h3><?php
+
+if ( isset( $_GET['enabled'] ) ) {
+ $_GET['enabled'] = absint( $_GET['enabled'] );
+ echo '<div id="message" class="updated"><p>' . sprintf( _n( 'Theme enabled.', '%s themes enabled.', $_GET['enabled'] ), number_format_i18n( $_GET['enabled'] ) ) . '</p></div>';
+} elseif ( isset( $_GET['disabled'] ) ) {
+ $_GET['disabled'] = absint( $_GET['disabled'] );
+ echo '<div id="message" class="updated"><p>' . sprintf( _n( 'Theme disabled.', '%s themes disabled.', $_GET['disabled'] ), number_format_i18n( $_GET['disabled'] ) ) . '</p></div>';
+} elseif ( isset( $_GET['error'] ) && 'none' == $_GET['error'] ) {
+ echo '<div id="message" class="error"><p>' . __( 'No theme selected.' ) . '</p></div>';
+} ?>
+
+<p><?php _e( 'Network enabled themes are not shown on this screen.' ) ?></p>
+
+<form method="get" action="">
+<?php $wp_list_table->search_box( __( 'Search Installed Themes' ), 'theme' ); ?>
+<input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+</form>
+
+<?php $wp_list_table->views(); ?>
+
+<form method="post" action="site-themes.php?action=update-site">
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+
+<?php $wp_list_table->display(); ?>
+
+</form>
+
+</div>
+<?php include(ABSPATH . 'wp-admin/admin-footer.php'); ?>
diff --git a/src/wp-admin/network/site-users.php b/src/wp-admin/network/site-users.php
new file mode 100644
index 0000000000..0c7a1c7296
--- /dev/null
+++ b/src/wp-admin/network/site-users.php
@@ -0,0 +1,310 @@
+<?php
+/**
+ * Edit Site Users Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can('manage_sites') )
+ wp_die(__('You do not have sufficient permissions to edit this site.'));
+
+$wp_list_table = _get_list_table('WP_Users_List_Table');
+$wp_list_table->prepare_items();
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('The menu is for editing information specific to individual sites, particularly if the admin area of a site is unavailable.') . '</p>' .
+ '<p>' . __('<strong>Info</strong> - The domain and path are rarely edited as this can cause the site to not work properly. The Registered date and Last Updated date are displayed. Network admins can mark a site as archived, spam, deleted and mature, to remove from public listings or disable.') . '</p>' .
+ '<p>' . __('<strong>Users</strong> - This displays the users associated with this site. You can also change their role, reset their password, or remove them from the site. Removing the user from the site does not remove the user from the network.') . '</p>' .
+ '<p>' . sprintf( __('<strong>Themes</strong> - This area shows themes that are not already enabled across the network. Enabling a theme in this menu makes it accessible to this site. It does not activate the theme, but allows it to show in the site&#8217;s Appearance menu. To enable a theme for the entire network, see the <a href="%s">Network Themes</a> screen.' ), network_admin_url( 'themes.php' ) ) . '</p>' .
+ '<p>' . __('<strong>Settings</strong> - This page shows a list of all settings associated with this site. Some are created by WordPress and others are created by plugins you activate. Note that some fields are grayed out and say Serialized Data. You cannot modify these values due to the way the setting is stored in the database.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Sites_Screen" target="_blank">Documentation on Site Management</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$_SERVER['REQUEST_URI'] = remove_query_arg( 'update', $_SERVER['REQUEST_URI'] );
+$referer = remove_query_arg( 'update', wp_get_referer() );
+
+$id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+
+if ( ! $id )
+ wp_die( __('Invalid site ID.') );
+
+$details = get_blog_details( $id );
+if ( ! can_edit_network( $details->site_id ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$is_main_site = is_main_site( $id );
+
+switch_to_blog( $id );
+
+$editblog_roles = $wp_roles->roles;
+
+$default_role = get_option( 'default_role' );
+
+$action = $wp_list_table->current_action();
+
+if ( $action ) {
+
+ switch ( $action ) {
+ case 'newuser':
+ check_admin_referer( 'add-user', '_wpnonce_add-new-user' );
+ $user = $_POST['user'];
+ if ( ! is_array( $_POST['user'] ) || empty( $user['username'] ) || empty( $user['email'] ) ) {
+ $update = 'err_new';
+ } else {
+ $password = wp_generate_password( 12, false);
+ $user_id = wpmu_create_user( esc_html( strtolower( $user['username'] ) ), $password, esc_html( $user['email'] ) );
+
+ if ( false == $user_id ) {
+ $update = 'err_new_dup';
+ } else {
+ wp_new_user_notification( $user_id, $password );
+ add_user_to_blog( $id, $user_id, $_POST['new_role'] );
+ $update = 'newuser';
+ }
+ }
+ break;
+
+ case 'adduser':
+ check_admin_referer( 'add-user', '_wpnonce_add-user' );
+ if ( !empty( $_POST['newuser'] ) ) {
+ $update = 'adduser';
+ $newuser = $_POST['newuser'];
+ $user = get_user_by( 'login', $newuser );
+ if ( $user && $user->exists() ) {
+ if ( ! is_user_member_of_blog( $user->ID, $id ) )
+ add_user_to_blog( $id, $user->ID, $_POST['new_role'] );
+ else
+ $update = 'err_add_member';
+ } else {
+ $update = 'err_add_notfound';
+ }
+ } else {
+ $update = 'err_add_notfound';
+ }
+ break;
+
+ case 'remove':
+ if ( ! current_user_can( 'remove_users' ) )
+ die(__('You can&#8217;t remove users.'));
+ check_admin_referer( 'bulk-users' );
+
+ $update = 'remove';
+ if ( isset( $_REQUEST['users'] ) ) {
+ $userids = $_REQUEST['users'];
+
+ foreach ( $userids as $user_id ) {
+ $user_id = (int) $user_id;
+ remove_user_from_blog( $user_id, $id );
+ }
+ } elseif ( isset( $_GET['user'] ) ) {
+ remove_user_from_blog( $_GET['user'] );
+ } else {
+ $update = 'err_remove';
+ }
+ break;
+
+ case 'promote':
+ check_admin_referer( 'bulk-users' );
+ $editable_roles = get_editable_roles();
+ if ( empty( $editable_roles[$_REQUEST['new_role']] ) )
+ wp_die(__('You can&#8217;t give users that role.'));
+
+ if ( isset( $_REQUEST['users'] ) ) {
+ $userids = $_REQUEST['users'];
+ $update = 'promote';
+ foreach ( $userids as $user_id ) {
+ $user_id = (int) $user_id;
+
+ // If the user doesn't already belong to the blog, bail.
+ if ( !is_user_member_of_blog( $user_id ) )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+ $user = get_userdata( $user_id );
+ $user->set_role( $_REQUEST['new_role'] );
+ }
+ } else {
+ $update = 'err_promote';
+ }
+ break;
+ }
+
+ wp_safe_redirect( add_query_arg( 'update', $update, $referer ) );
+ exit();
+}
+
+restore_current_blog();
+
+if ( isset( $_GET['action'] ) && 'update-site' == $_GET['action'] ) {
+ wp_safe_redirect( $referer );
+ exit();
+}
+
+add_screen_option( 'per_page', array( 'label' => _x( 'Users', 'users per page (screen options)' ) ) );
+
+$site_url_no_http = preg_replace( '#^http(s)?://#', '', get_blogaddress_by_id( $id ) );
+$title_site_url_linked = sprintf( __('Edit Site: <a href="%1$s">%2$s</a>'), get_blogaddress_by_id( $id ), $site_url_no_http );
+$title = sprintf( __('Edit Site: %s'), $site_url_no_http );
+
+$parent_file = 'sites.php';
+$submenu_file = 'sites.php';
+
+if ( ! wp_is_large_network( 'users' ) && apply_filters( 'show_network_site_users_add_existing_form', true ) )
+ wp_enqueue_script( 'user-suggest' );
+
+require('../admin-header.php'); ?>
+
+<script type='text/javascript'>
+/* <![CDATA[ */
+var current_site_id = <?php echo $id; ?>;
+/* ]]> */
+</script>
+
+
+<div class="wrap">
+<?php screen_icon('ms-admin'); ?>
+<h2 id="edit-site"><?php echo $title_site_url_linked ?></h2>
+<h3 class="nav-tab-wrapper">
+<?php
+$tabs = array(
+ 'site-info' => array( 'label' => __( 'Info' ), 'url' => 'site-info.php' ),
+ 'site-users' => array( 'label' => __( 'Users' ), 'url' => 'site-users.php' ),
+ 'site-themes' => array( 'label' => __( 'Themes' ), 'url' => 'site-themes.php' ),
+ 'site-settings' => array( 'label' => __( 'Settings' ), 'url' => 'site-settings.php' ),
+);
+foreach ( $tabs as $tab_id => $tab ) {
+ $class = ( $tab['url'] == $pagenow ) ? ' nav-tab-active' : '';
+ echo '<a href="' . $tab['url'] . '?id=' . $id .'" class="nav-tab' . $class . '">' . esc_html( $tab['label'] ) . '</a>';
+}
+?>
+</h3><?php
+
+if ( isset($_GET['update']) ) :
+ switch($_GET['update']) {
+ case 'adduser':
+ echo '<div id="message" class="updated"><p>' . __( 'User added.' ) . '</p></div>';
+ break;
+ case 'err_add_member':
+ echo '<div id="message" class="error"><p>' . __( 'User is already a member of this site.' ) . '</p></div>';
+ break;
+ case 'err_add_notfound':
+ echo '<div id="message" class="error"><p>' . __( 'Enter the username of an existing user.' ) . '</p></div>';
+ break;
+ case 'promote':
+ echo '<div id="message" class="updated"><p>' . __( 'Changed roles.' ) . '</p></div>';
+ break;
+ case 'err_promote':
+ echo '<div id="message" class="error"><p>' . __( 'Select a user to change role.' ) . '</p></div>';
+ break;
+ case 'remove':
+ echo '<div id="message" class="updated"><p>' . __( 'User removed from this site.' ) . '</p></div>';
+ break;
+ case 'err_remove':
+ echo '<div id="message" class="error"><p>' . __( 'Select a user to remove.' ) . '</p></div>';
+ break;
+ case 'newuser':
+ echo '<div id="message" class="updated"><p>' . __( 'User created.' ) . '</p></div>';
+ break;
+ case 'err_new':
+ echo '<div id="message" class="error"><p>' . __( 'Enter the username and email.' ) . '</p></div>';
+ break;
+ case 'err_new_dup':
+ echo '<div id="message" class="error"><p>' . __( 'Duplicated username or email address.' ) . '</p></div>';
+ break;
+ }
+endif; ?>
+
+<form class="search-form" action="" method="get">
+<?php $wp_list_table->search_box( __( 'Search Users' ), 'user' ); ?>
+<input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+</form>
+
+<?php $wp_list_table->views(); ?>
+
+<form method="post" action="site-users.php?action=update-site">
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+
+<?php $wp_list_table->display(); ?>
+
+</form>
+
+<?php do_action( 'network_site_users_after_list_table', '' );?>
+
+<?php if ( current_user_can( 'promote_users' ) && apply_filters( 'show_network_site_users_add_existing_form', true ) ) : ?>
+<h3 id="add-existing-user"><?php _e( 'Add Existing User' ); ?></h3>
+<form action="site-users.php?action=adduser" id="adduser" method="post">
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+ <table class="form-table">
+ <tr>
+ <th scope="row"><?php _e( 'Username' ); ?></th>
+ <td><input type="text" class="regular-text wp-suggest-user" name="newuser" id="newuser" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php _e( 'Role' ); ?></th>
+ <td><select name="new_role" id="new_role_0">
+ <?php
+ reset( $editblog_roles );
+ foreach ( $editblog_roles as $role => $role_assoc ) {
+ $name = translate_user_role( $role_assoc['name'] );
+ echo '<option ' . selected( $default_role, $role, false ) . ' value="' . esc_attr( $role ) . '">' . esc_html( $name ) . '</option>';
+ }
+ ?>
+ </select></td>
+ </tr>
+ </table>
+ <?php wp_nonce_field( 'add-user', '_wpnonce_add-user' ) ?>
+ <?php submit_button( __( 'Add User' ), 'primary', 'add-user', true, array( 'id' => 'submit-add-existing-user' ) ); ?>
+</form>
+<?php endif; ?>
+
+<?php if ( current_user_can( 'create_users' ) && apply_filters( 'show_network_site_users_add_new_form', true ) ) : ?>
+<h3 id="add-new-user"><?php _e( 'Add New User' ); ?></h3>
+<form action="<?php echo network_admin_url('site-users.php?action=newuser'); ?>" id="newuser" method="post">
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ) ?>" />
+ <table class="form-table">
+ <tr>
+ <th scope="row"><?php _e( 'Username' ) ?></th>
+ <td><input type="text" class="regular-text" name="user[username]" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php _e( 'Email' ) ?></th>
+ <td><input type="text" class="regular-text" name="user[email]" /></td>
+ </tr>
+ <tr>
+ <th scope="row"><?php _e( 'Role' ); ?></th>
+ <td><select name="new_role" id="new_role_0">
+ <?php
+ reset( $editblog_roles );
+ foreach ( $editblog_roles as $role => $role_assoc ) {
+ $name = translate_user_role( $role_assoc['name'] );
+ echo '<option ' . selected( $default_role, $role, false ) . ' value="' . esc_attr( $role ) . '">' . esc_html( $name ) . '</option>';
+ }
+ ?>
+ </select></td>
+ </tr>
+ <tr class="form-field">
+ <td colspan="2"><?php _e( 'Username and password will be mailed to the above email address.' ) ?></td>
+ </tr>
+ </table>
+ <?php wp_nonce_field( 'add-user', '_wpnonce_add-new-user' ) ?>
+ <?php submit_button( __( 'Add New User' ), 'primary', 'add-user', true, array( 'id' => 'submit-add-user' ) ); ?>
+</form>
+<?php endif; ?>
+</div>
+<?php
+require('../admin-footer.php');
diff --git a/src/wp-admin/network/sites.php b/src/wp-admin/network/sites.php
new file mode 100644
index 0000000000..93341c35e9
--- /dev/null
+++ b/src/wp-admin/network/sites.php
@@ -0,0 +1,257 @@
+<?php
+/**
+ * Multisite sites administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_sites' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+$wp_list_table = _get_list_table( 'WP_MS_Sites_List_Table' );
+$pagenum = $wp_list_table->get_pagenum();
+
+$title = __( 'Sites' );
+$parent_file = 'sites.php';
+
+add_screen_option( 'per_page', array( 'label' => _x( 'Sites', 'sites per page (screen options)' ) ) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('Add New takes you to the Add New Site screen. You can search for a site by Name, ID number, or IP address. Screen Options allows you to choose how many sites to display on one page.') . '</p>' .
+ '<p>' . __('This is the main table of all sites on this network. Switch between list and excerpt views by using the icons above the right side of the table.') . '</p>' .
+ '<p>' . __('Hovering over each site reveals seven options (three for the primary site):') . '</p>' .
+ '<ul><li>' . __('An Edit link to a separate Edit Site screen.') . '</li>' .
+ '<li>' . __('Dashboard leads to the Dashboard for that site.') . '</li>' .
+ '<li>' . __('Deactivate, Archive, and Spam which lead to confirmation screens. These actions can be reversed later.') . '</li>' .
+ '<li>' . __('Delete which is a permanent action after the confirmation screens.') . '</li>' .
+ '<li>' . __('Visit to go to the frontend site live.') . '</li></ul>' .
+ '<p>' . __('The site ID is used internally, and is not shown on the front end of the site or to users/viewers.') . '</p>' .
+ '<p>' . __('Clicking on bold headings can re-sort this table.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Sites_Screen" target="_blank">Documentation on Site Management</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
+
+if ( isset( $_GET['action'] ) ) {
+ do_action( 'wpmuadminedit' , '' );
+
+ if ( 'confirm' === $_GET['action'] ) {
+ check_admin_referer( 'confirm' );
+
+ if ( ! headers_sent() ) {
+ nocache_headers();
+ header( 'Content-Type: text/html; charset=utf-8' );
+ }
+ if ( $current_site->blog_id == $id )
+ wp_die( __( 'You are not allowed to change the current site.' ) );
+ ?>
+ <!DOCTYPE html>
+ <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+ <head>
+ <title><?php _e( 'WordPress &rsaquo; Confirm your action' ); ?></title>
+
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <?php
+ wp_admin_css( 'install', true );
+ wp_admin_css( 'ie', true );
+ ?>
+ </head>
+ <body class="wp-core-ui">
+ <h1 id="logo"><a href="<?php echo esc_url( __( 'http://wordpress.org/' ) ); ?>"><?php _e( 'WordPress' ); ?></a></h1>
+ <form action="sites.php?action=<?php echo esc_attr( $_GET['action2'] ) ?>" method="post">
+ <input type="hidden" name="action" value="<?php echo esc_attr( $_GET['action2'] ) ?>" />
+ <input type="hidden" name="id" value="<?php echo esc_attr( $id ); ?>" />
+ <input type="hidden" name="_wp_http_referer" value="<?php echo esc_attr( wp_get_referer() ); ?>" />
+ <?php wp_nonce_field( $_GET['action2'], '_wpnonce', false ); ?>
+ <p><?php echo esc_html( wp_unslash( $_GET['msg'] ) ); ?></p>
+ <?php submit_button( __('Confirm'), 'button' ); ?>
+ </form>
+ </body>
+ </html>
+ <?php
+ exit();
+ }
+
+ $updated_action = '';
+
+ $manage_actions = array( 'deleteblog', 'allblogs', 'archiveblog', 'unarchiveblog', 'activateblog', 'deactivateblog', 'unspamblog', 'spamblog', 'unmatureblog', 'matureblog' );
+ if ( in_array( $_GET['action'], $manage_actions ) ) {
+ $action = $_GET['action'];
+ if ( 'allblogs' === $action )
+ $action = 'bulk-sites';
+
+ check_admin_referer( $action );
+ }
+
+ switch ( $_GET['action'] ) {
+
+ case 'deleteblog':
+ if ( ! current_user_can( 'delete_sites' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+ $updated_action = 'not_deleted';
+ if ( $id != '0' && $id != $current_site->blog_id && current_user_can( 'delete_site', $id ) ) {
+ wpmu_delete_blog( $id, true );
+ $updated_action = 'delete';
+ }
+ break;
+
+ case 'allblogs':
+ if ( ( isset( $_POST['action'] ) || isset( $_POST['action2'] ) ) && isset( $_POST['allblogs'] ) ) {
+ $doaction = $_POST['action'] != -1 ? $_POST['action'] : $_POST['action2'];
+
+ foreach ( (array) $_POST['allblogs'] as $key => $val ) {
+ if ( $val != '0' && $val != $current_site->blog_id ) {
+ switch ( $doaction ) {
+ case 'delete':
+ if ( ! current_user_can( 'delete_site', $val ) )
+ wp_die( __( 'You are not allowed to delete the site.' ) );
+
+ $updated_action = 'all_delete';
+ wpmu_delete_blog( $val, true );
+ break;
+
+ case 'spam':
+ case 'notspam':
+ $updated_action = ( 'spam' === $doaction ) ? 'all_spam' : 'all_notspam';
+ update_blog_status( $val, 'spam', ( 'spam' === $doaction ) ? '1' : '0' );
+ break;
+ }
+ } else {
+ wp_die( __( 'You are not allowed to change the current site.' ) );
+ }
+ }
+ } else {
+ wp_redirect( network_admin_url( 'sites.php' ) );
+ exit();
+ }
+ break;
+
+ case 'archiveblog':
+ case 'unarchiveblog':
+ update_blog_status( $id, 'archived', ( 'archiveblog' === $_GET['action'] ) ? '1' : '0' );
+ break;
+
+ case 'activateblog':
+ update_blog_status( $id, 'deleted', '0' );
+ do_action( 'activate_blog', $id );
+ break;
+
+ case 'deactivateblog':
+ do_action( 'deactivate_blog', $id );
+ update_blog_status( $id, 'deleted', '1' );
+ break;
+
+ case 'unspamblog':
+ case 'spamblog':
+ update_blog_status( $id, 'spam', ( 'spamblog' === $_GET['action'] ) ? '1' : '0' );
+ break;
+
+ case 'unmatureblog':
+ case 'matureblog':
+ update_blog_status( $id, 'mature', ( 'matureblog' === $_GET['action'] ) ? '1' : '0' );
+ break;
+ }
+
+ if ( empty( $updated_action ) && in_array( $_GET['action'], $manage_actions ) )
+ $updated_action = $_GET['action'];
+
+ if ( ! empty( $updated_action ) ) {
+ wp_safe_redirect( add_query_arg( array( 'updated' => $updated_action ), wp_get_referer() ) );
+ exit();
+ }
+}
+
+$msg = '';
+if ( isset( $_GET['updated'] ) ) {
+ switch ( $_GET['updated'] ) {
+ case 'all_notspam':
+ $msg = __( 'Sites removed from spam.' );
+ break;
+ case 'all_spam':
+ $msg = __( 'Sites marked as spam.' );
+ break;
+ case 'all_delete':
+ $msg = __( 'Sites deleted.' );
+ break;
+ case 'delete':
+ $msg = __( 'Site deleted.' );
+ break;
+ case 'not_deleted':
+ $msg = __( 'You do not have permission to delete that site.' );
+ break;
+ case 'archiveblog':
+ $msg = __( 'Site archived.' );
+ break;
+ case 'unarchiveblog':
+ $msg = __( 'Site unarchived.' );
+ break;
+ case 'activateblog':
+ $msg = __( 'Site activated.' );
+ break;
+ case 'deactivateblog':
+ $msg = __( 'Site deactivated.' );
+ break;
+ case 'unspamblog':
+ $msg = __( 'Site removed from spam.' );
+ break;
+ case 'spamblog':
+ $msg = __( 'Site marked as spam.' );
+ break;
+ default:
+ $msg = apply_filters( 'network_sites_updated_message_' . $_GET['updated'], __( 'Settings saved.' ) );
+ break;
+ }
+
+ if ( ! empty( $msg ) )
+ $msg = '<div class="updated" id="message"><p>' . $msg . '</p></div>';
+}
+
+$wp_list_table->prepare_items();
+
+require_once( '../admin-header.php' );
+?>
+
+<div class="wrap">
+<?php screen_icon( 'ms-admin' ); ?>
+<h2><?php _e( 'Sites' ) ?>
+
+<?php if ( current_user_can( 'create_sites') ) : ?>
+ <a href="<?php echo network_admin_url('site-new.php'); ?>" class="add-new-h2"><?php echo esc_html_x( 'Add New', 'site' ); ?></a>
+<?php endif; ?>
+
+<?php if ( isset( $_REQUEST['s'] ) && $_REQUEST['s'] ) {
+ printf( '<span class="subtitle">' . __( 'Search results for &#8220;%s&#8221;' ) . '</span>', esc_html( $s ) );
+} ?>
+</h2>
+
+<?php echo $msg; ?>
+
+<form action="" method="get" id="ms-search">
+<?php $wp_list_table->search_box( __( 'Search Sites' ), 'site' ); ?>
+<input type="hidden" name="action" value="blogs" />
+</form>
+
+<form id="form-site-list" action="sites.php?action=allblogs" method="post">
+ <?php $wp_list_table->display(); ?>
+</form>
+</div>
+<?php
+
+require_once( '../admin-footer.php' ); ?>
diff --git a/src/wp-admin/network/theme-editor.php b/src/wp-admin/network/theme-editor.php
new file mode 100644
index 0000000000..f6ac9c2e08
--- /dev/null
+++ b/src/wp-admin/network/theme-editor.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Theme editor network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../theme-editor.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/theme-install.php b/src/wp-admin/network/theme-install.php
new file mode 100644
index 0000000000..bc4e6269aa
--- /dev/null
+++ b/src/wp-admin/network/theme-install.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Install theme network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+if ( isset( $_GET['tab'] ) && ( 'theme-information' == $_GET['tab'] ) )
+ define( 'IFRAME_REQUEST', true );
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../theme-install.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/themes.php b/src/wp-admin/network/themes.php
new file mode 100644
index 0000000000..711b44e0f2
--- /dev/null
+++ b/src/wp-admin/network/themes.php
@@ -0,0 +1,275 @@
+<?php
+/**
+ * Multisite themes administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( !current_user_can('manage_network_themes') )
+ wp_die( __( 'You do not have sufficient permissions to manage network themes.' ) );
+
+$wp_list_table = _get_list_table('WP_MS_Themes_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+
+$action = $wp_list_table->current_action();
+
+$s = isset($_REQUEST['s']) ? $_REQUEST['s'] : '';
+
+// Clean up request URI from temporary args for screen options/paging uri's to work as expected.
+$temp_args = array( 'enabled', 'disabled', 'deleted', 'error' );
+$_SERVER['REQUEST_URI'] = remove_query_arg( $temp_args, $_SERVER['REQUEST_URI'] );
+$referer = remove_query_arg( $temp_args, wp_get_referer() );
+
+if ( $action ) {
+ $allowed_themes = get_site_option( 'allowedthemes' );
+ switch ( $action ) {
+ case 'enable':
+ check_admin_referer('enable-theme_' . $_GET['theme']);
+ $allowed_themes[ $_GET['theme'] ] = true;
+ update_site_option( 'allowedthemes', $allowed_themes );
+ if ( false === strpos( $referer, '/network/themes.php' ) )
+ wp_redirect( network_admin_url( 'themes.php?enabled=1' ) );
+ else
+ wp_safe_redirect( add_query_arg( 'enabled', 1, $referer ) );
+ exit;
+ break;
+ case 'disable':
+ check_admin_referer('disable-theme_' . $_GET['theme']);
+ unset( $allowed_themes[ $_GET['theme'] ] );
+ update_site_option( 'allowedthemes', $allowed_themes );
+ wp_safe_redirect( add_query_arg( 'disabled', '1', $referer ) );
+ exit;
+ break;
+ case 'enable-selected':
+ check_admin_referer('bulk-themes');
+ $themes = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+ if ( empty($themes) ) {
+ wp_safe_redirect( add_query_arg( 'error', 'none', $referer ) );
+ exit;
+ }
+ foreach( (array) $themes as $theme )
+ $allowed_themes[ $theme ] = true;
+ update_site_option( 'allowedthemes', $allowed_themes );
+ wp_safe_redirect( add_query_arg( 'enabled', count( $themes ), $referer ) );
+ exit;
+ break;
+ case 'disable-selected':
+ check_admin_referer('bulk-themes');
+ $themes = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+ if ( empty($themes) ) {
+ wp_safe_redirect( add_query_arg( 'error', 'none', $referer ) );
+ exit;
+ }
+ foreach( (array) $themes as $theme )
+ unset( $allowed_themes[ $theme ] );
+ update_site_option( 'allowedthemes', $allowed_themes );
+ wp_safe_redirect( add_query_arg( 'disabled', count( $themes ), $referer ) );
+ exit;
+ break;
+ case 'update-selected' :
+ check_admin_referer( 'bulk-themes' );
+
+ if ( isset( $_GET['themes'] ) )
+ $themes = explode( ',', $_GET['themes'] );
+ elseif ( isset( $_POST['checked'] ) )
+ $themes = (array) $_POST['checked'];
+ else
+ $themes = array();
+
+ $title = __( 'Update Themes' );
+ $parent_file = 'themes.php';
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ echo '<div class="wrap">';
+ screen_icon();
+ echo '<h2>' . esc_html( $title ) . '</h2>';
+
+ $url = self_admin_url('update.php?action=update-selected-themes&amp;themes=' . urlencode( join(',', $themes) ));
+ $url = wp_nonce_url($url, 'bulk-update-themes');
+
+ echo "<iframe src='$url' style='width: 100%; height:100%; min-height:850px;'></iframe>";
+ echo '</div>';
+ require_once(ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ break;
+ case 'delete-selected':
+ if ( ! current_user_can( 'delete_themes' ) )
+ wp_die( __('You do not have sufficient permissions to delete themes for this site.') );
+ check_admin_referer( 'bulk-themes' );
+
+ $themes = isset( $_REQUEST['checked'] ) ? (array) $_REQUEST['checked'] : array();
+
+ unset( $themes[ get_option( 'stylesheet' ) ], $themes[ get_option( 'template' ) ] );
+
+ if ( empty( $themes ) ) {
+ wp_safe_redirect( add_query_arg( 'error', 'none', $referer ) );
+ exit;
+ }
+
+ $files_to_delete = $theme_info = array();
+ foreach ( $themes as $key => $theme ) {
+ $theme_info[ $theme ] = wp_get_theme( $theme );
+ $files_to_delete = array_merge( $files_to_delete, list_files( $theme_info[ $theme ]->get_stylesheet_directory() ) );
+ }
+
+ if ( empty( $themes ) ) {
+ wp_safe_redirect( add_query_arg( 'error', 'main', $referer ) );
+ exit;
+ }
+
+ include(ABSPATH . 'wp-admin/update.php');
+
+ $parent_file = 'themes.php';
+
+ if ( ! isset( $_REQUEST['verify-delete'] ) ) {
+ wp_enqueue_script( 'jquery' );
+ require_once( ABSPATH . 'wp-admin/admin-header.php' );
+ ?>
+ <div class="wrap">
+ <?php
+ $themes_to_delete = count( $themes );
+ screen_icon();
+ echo '<h2>' . _n( 'Delete Theme', 'Delete Themes', $themes_to_delete ) . '</h2>';
+ ?>
+ <div class="error"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php echo _n( 'This theme may be active on other sites in the network.', 'These themes may be active on other sites in the network.', $themes_to_delete ); ?></p></div>
+ <p><?php echo _n( 'You are about to remove the following theme:', 'You are about to remove the following themes:', $themes_to_delete ); ?></p>
+ <ul class="ul-disc">
+ <?php foreach ( $theme_info as $theme )
+ echo '<li>', sprintf( __('<strong>%1$s</strong> by <em>%2$s</em>' ), $theme->display('Name'), $theme->display('Author') ), '</li>'; /* translators: 1: theme name, 2: theme author */ ?>
+ </ul>
+ <p><?php _e('Are you sure you wish to delete these themes?'); ?></p>
+ <form method="post" action="<?php echo esc_url($_SERVER['REQUEST_URI']); ?>" style="display:inline;">
+ <input type="hidden" name="verify-delete" value="1" />
+ <input type="hidden" name="action" value="delete-selected" />
+ <?php
+ foreach ( (array) $themes as $theme )
+ echo '<input type="hidden" name="checked[]" value="' . esc_attr($theme) . '" />';
+ ?>
+ <?php wp_nonce_field('bulk-themes') ?>
+ <?php submit_button( _n( 'Yes, Delete this theme', 'Yes, Delete these themes', $themes_to_delete ), 'button', 'submit', false ); ?>
+ </form>
+ <form method="post" action="<?php echo esc_url(wp_get_referer()); ?>" style="display:inline;">
+ <?php submit_button( __( 'No, Return me to the theme list' ), 'button', 'submit', false ); ?>
+ </form>
+
+ <p><a href="#" onclick="jQuery('#files-list').toggle(); return false;"><?php _e('Click to view entire list of files which will be deleted'); ?></a></p>
+ <div id="files-list" style="display:none;">
+ <ul class="code">
+ <?php
+ foreach ( (array) $files_to_delete as $file )
+ echo '<li>' . esc_html( str_replace( WP_CONTENT_DIR . "/themes", '', $file) ) . '</li>';
+ ?>
+ </ul>
+ </div>
+ </div>
+ <?php
+ require_once(ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ } // Endif verify-delete
+
+ foreach ( $themes as $theme ) {
+ $delete_result = delete_theme( $theme, esc_url( add_query_arg( array(
+ 'verify-delete' => 1,
+ 'action' => 'delete-selected',
+ 'checked' => $_REQUEST['checked'],
+ '_wpnonce' => $_REQUEST['_wpnonce']
+ ), network_admin_url( 'themes.php' ) ) ) );
+ }
+
+ $paged = ( $_REQUEST['paged'] ) ? $_REQUEST['paged'] : 1;
+ wp_redirect( add_query_arg( array(
+ 'deleted' => count( $themes ),
+ 'paged' => $paged,
+ 's' => $s
+ ), network_admin_url( 'themes.php' ) ) );
+ exit;
+ break;
+ }
+}
+
+$wp_list_table->prepare_items();
+
+add_thickbox();
+
+add_screen_option( 'per_page', array('label' => _x( 'Themes', 'themes per page (screen options)' )) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This screen enables and disables the inclusion of themes available to choose in the Appearance menu for each site. It does not activate or deactivate which theme a site is currently using.') . '</p>' .
+ '<p>' . __('If the network admin disables a theme that is in use, it can still remain selected on that site. If another theme is chosen, the disabled theme will not appear in the site&#8217;s Appearance > Themes screen.') . '</p>' .
+ '<p>' . __('Themes can be enabled on a site by site basis by the network admin on the Edit Site screen (which has a Themes tab); get there via the Edit action link on the All Sites screen. Only network admins are able to install or edit themes.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Themes_Screen" target="_blank">Documentation on Network Themes</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$title = __('Themes');
+$parent_file = 'themes.php';
+
+wp_enqueue_script( 'theme' );
+
+require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+?>
+
+<div class="wrap">
+<?php screen_icon('themes'); ?>
+<h2><?php echo esc_html( $title ); if ( current_user_can('install_themes') ) { ?> <a href="theme-install.php" class="add-new-h2"><?php echo esc_html_x('Add New', 'theme'); ?></a><?php }
+if ( $s )
+ printf( '<span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', esc_html( $s ) ); ?>
+</h2>
+
+<?php
+if ( isset( $_GET['enabled'] ) ) {
+ $_GET['enabled'] = absint( $_GET['enabled'] );
+ echo '<div id="message" class="updated"><p>' . sprintf( _n( 'Theme enabled.', '%s themes enabled.', $_GET['enabled'] ), number_format_i18n( $_GET['enabled'] ) ) . '</p></div>';
+} elseif ( isset( $_GET['disabled'] ) ) {
+ $_GET['disabled'] = absint( $_GET['disabled'] );
+ echo '<div id="message" class="updated"><p>' . sprintf( _n( 'Theme disabled.', '%s themes disabled.', $_GET['disabled'] ), number_format_i18n( $_GET['disabled'] ) ) . '</p></div>';
+} elseif ( isset( $_GET['deleted'] ) ) {
+ $_GET['deleted'] = absint( $_GET['deleted'] );
+ echo '<div id="message" class="updated"><p>' . sprintf( _nx( 'Theme deleted.', '%s themes deleted.', $_GET['deleted'], 'network' ), number_format_i18n( $_GET['deleted'] ) ) . '</p></div>';
+} elseif ( isset( $_GET['error'] ) && 'none' == $_GET['error'] ) {
+ echo '<div id="message" class="error"><p>' . __( 'No theme selected.' ) . '</p></div>';
+} elseif ( isset( $_GET['error'] ) && 'main' == $_GET['error'] ) {
+ echo '<div class="error"><p>' . __( 'You cannot delete a theme while it is active on the main site.' ) . '</p></div>';
+}
+
+?>
+
+<form method="get" action="">
+<?php $wp_list_table->search_box( __( 'Search Installed Themes' ), 'theme' ); ?>
+</form>
+
+<?php
+$wp_list_table->views();
+
+if ( 'broken' == $status )
+ echo '<p class="clear">' . __('The following themes are installed but incomplete. Themes must have a stylesheet and a template.') . '</p>';
+?>
+
+<form method="post" action="">
+<input type="hidden" name="theme_status" value="<?php echo esc_attr($status) ?>" />
+<input type="hidden" name="paged" value="<?php echo esc_attr($page) ?>" />
+
+<?php $wp_list_table->display(); ?>
+</form>
+
+</div>
+
+<?php
+include(ABSPATH . 'wp-admin/admin-footer.php');
diff --git a/src/wp-admin/network/update-core.php b/src/wp-admin/network/update-core.php
new file mode 100644
index 0000000000..d4f9c7680a
--- /dev/null
+++ b/src/wp-admin/network/update-core.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Updates network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../update-core.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/update.php b/src/wp-admin/network/update.php
new file mode 100644
index 0000000000..b2c6177fbc
--- /dev/null
+++ b/src/wp-admin/network/update.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Update/Install Plugin/Theme network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+if ( isset( $_GET['action'] ) && in_array( $_GET['action'], array( 'update-selected', 'activate-plugin', 'update-selected-themes' ) ) )
+ define( 'IFRAME_REQUEST', true );
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../update.php' );
diff --git a/src/wp-admin/network/upgrade.php b/src/wp-admin/network/upgrade.php
new file mode 100644
index 0000000000..74156547e9
--- /dev/null
+++ b/src/wp-admin/network/upgrade.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Multisite upgrade administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require_once( ABSPATH . WPINC . '/http.php' );
+
+$title = __( 'Upgrade Network' );
+$parent_file = 'upgrade.php';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('Only use this screen once you have updated to a new version of WordPress through Updates/Available Updates (via the Network Administration navigation menu or the Toolbar). Clicking the Upgrade Network button will step through each site in the network, five at a time, and make sure any database updates are applied.') . '</p>' .
+ '<p>' . __('If a version update to core has not happened, clicking this button won&#8217;t affect anything.') . '</p>' .
+ '<p>' . __('If this process fails for any reason, users logging in to their sites will force the same update.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Updates_Screen" target="_blank">Documentation on Upgrade Network</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+require_once('../admin-header.php');
+
+if ( ! current_user_can( 'manage_network' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+echo '<div class="wrap">';
+screen_icon('tools');
+echo '<h2>' . __( 'Upgrade Network' ) . '</h2>';
+
+$action = isset($_GET['action']) ? $_GET['action'] : 'show';
+
+switch ( $action ) {
+ case "upgrade":
+ $n = ( isset($_GET['n']) ) ? intval($_GET['n']) : 0;
+
+ if ( $n < 5 ) {
+ global $wp_db_version;
+ update_site_option( 'wpmu_upgrade_site', $wp_db_version );
+ }
+
+ $blogs = $wpdb->get_results( "SELECT * FROM {$wpdb->blogs} WHERE site_id = '{$wpdb->siteid}' AND spam = '0' AND deleted = '0' AND archived = '0' ORDER BY registered DESC LIMIT {$n}, 5", ARRAY_A );
+ if ( empty( $blogs ) ) {
+ echo '<p>' . __( 'All done!' ) . '</p>';
+ break;
+ }
+ echo "<ul>";
+ foreach ( (array) $blogs as $details ) {
+ switch_to_blog( $details['blog_id'] );
+ $siteurl = site_url();
+ $upgrade_url = admin_url( 'upgrade.php?step=upgrade_db' );
+ restore_current_blog();
+ echo "<li>$siteurl</li>";
+ $response = wp_remote_get( $upgrade_url, array( 'timeout' => 120, 'httpversion' => '1.1' ) );
+ if ( is_wp_error( $response ) )
+ wp_die( sprintf( __( 'Warning! Problem updating %1$s. Your server may not be able to connect to sites running on it. Error message: <em>%2$s</em>' ), $siteurl, $response->get_error_message() ) );
+ do_action( 'after_mu_upgrade', $response );
+ do_action( 'wpmu_upgrade_site', $details[ 'blog_id' ] );
+ }
+ echo "</ul>";
+ ?><p><?php _e( 'If your browser doesn&#8217;t start loading the next page automatically, click this link:' ); ?> <a class="button" href="upgrade.php?action=upgrade&amp;n=<?php echo ($n + 5) ?>"><?php _e("Next Sites"); ?></a></p>
+ <script type='text/javascript'>
+ <!--
+ function nextpage() {
+ location.href = "upgrade.php?action=upgrade&n=<?php echo ($n + 5) ?>";
+ }
+ setTimeout( "nextpage()", 250 );
+ //-->
+ </script><?php
+ break;
+ case 'show':
+ default:
+ ?>
+ <h3><?php _e( 'Database Upgrade Required' ); ?></h3>
+ <p><?php _e( 'WordPress has been updated! Before we send you on your way, we need to individually upgrade the sites in your network.' ); ?></p>
+ <p><?php _e( 'The upgrade process may take a little while, so please be patient.' ); ?></p>
+ <p><a class="button" href="upgrade.php?action=upgrade"><?php _e( 'Upgrade Network' ); ?></a></p>
+ <?php
+ do_action( 'wpmu_upgrade_page' );
+ break;
+}
+?>
+</div>
+
+<?php include('../admin-footer.php'); ?>
diff --git a/src/wp-admin/network/user-edit.php b/src/wp-admin/network/user-edit.php
new file mode 100644
index 0000000000..0b2cfd26f4
--- /dev/null
+++ b/src/wp-admin/network/user-edit.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Edit user network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+require( '../user-edit.php' ); \ No newline at end of file
diff --git a/src/wp-admin/network/user-new.php b/src/wp-admin/network/user-new.php
new file mode 100644
index 0000000000..316fffe58c
--- /dev/null
+++ b/src/wp-admin/network/user-new.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Add New User network administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.1.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can('create_users') )
+ wp_die(__('You do not have sufficient permissions to add users to this network.'));
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('Add User will set up a new user account on the network and send that person an email with username and password.') . '</p>' .
+ '<p>' . __('Users who are signed up to the network without a site are added as subscribers to the main or primary dashboard site, giving them profile pages to manage their accounts. These users will only see Dashboard and My Sites in the main navigation until a site is created for them.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Users_Screen" target="_blank">Documentation on Network Users</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( isset($_REQUEST['action']) && 'add-user' == $_REQUEST['action'] ) {
+ check_admin_referer( 'add-user', '_wpnonce_add-user' );
+ if ( ! current_user_can( 'manage_network_users' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+ if ( ! is_array( $_POST['user'] ) )
+ wp_die( __( 'Cannot create an empty user.' ) );
+
+ $user = $_POST['user'];
+
+ $user_details = wpmu_validate_user_signup( $user['username'], $user['email'] );
+ if ( is_wp_error( $user_details[ 'errors' ] ) && ! empty( $user_details[ 'errors' ]->errors ) ) {
+ $add_user_errors = $user_details[ 'errors' ];
+ } else {
+ $password = wp_generate_password( 12, false);
+ $user_id = wpmu_create_user( esc_html( strtolower( $user['username'] ) ), $password, esc_html( $user['email'] ) );
+
+ if ( ! $user_id ) {
+ $add_user_errors = new WP_Error( 'add_user_fail', __( 'Cannot add user.' ) );
+ } else {
+ wp_new_user_notification( $user_id, $password );
+ wp_redirect( add_query_arg( array('update' => 'added'), 'user-new.php' ) );
+ exit;
+ }
+ }
+}
+
+if ( isset($_GET['update']) ) {
+ $messages = array();
+ if ( 'added' == $_GET['update'] )
+ $messages[] = __('User added.');
+}
+
+$title = __('Add New User');
+$parent_file = 'users.php';
+
+require('../admin-header.php'); ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2 id="add-new-user"><?php _e('Add New User') ?></h2>
+<?php
+if ( ! empty( $messages ) ) {
+ foreach ( $messages as $msg )
+ echo '<div id="message" class="updated"><p>' . $msg . '</p></div>';
+}
+
+if ( isset( $add_user_errors ) && is_wp_error( $add_user_errors ) ) { ?>
+ <div class="error">
+ <?php
+ foreach ( $add_user_errors->get_error_messages() as $message )
+ echo "<p>$message</p>";
+ ?>
+ </div>
+<?php } ?>
+ <form action="<?php echo network_admin_url('user-new.php?action=add-user'); ?>" id="adduser" method="post">
+ <table class="form-table">
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Username' ) ?></th>
+ <td><input type="text" class="regular-text" name="user[username]" /></td>
+ </tr>
+ <tr class="form-field form-required">
+ <th scope="row"><?php _e( 'Email' ) ?></th>
+ <td><input type="text" class="regular-text" name="user[email]" /></td>
+ </tr>
+ <tr class="form-field">
+ <td colspan="2"><?php _e( 'Username and password will be mailed to the above email address.' ) ?></td>
+ </tr>
+ </table>
+ <?php wp_nonce_field( 'add-user', '_wpnonce_add-user' ) ?>
+ <?php submit_button( __('Add User'), 'primary', 'add-user' ); ?>
+ </form>
+</div>
+<?php
+require('../admin-footer.php');
diff --git a/src/wp-admin/network/users.php b/src/wp-admin/network/users.php
new file mode 100644
index 0000000000..1318355448
--- /dev/null
+++ b/src/wp-admin/network/users.php
@@ -0,0 +1,299 @@
+<?php
+/**
+ * Multisite users administration panel.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! is_multisite() )
+ wp_die( __( 'Multisite support is not enabled.' ) );
+
+if ( ! current_user_can( 'manage_network_users' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+function confirm_delete_users( $users ) {
+ $current_user = wp_get_current_user();
+ if ( !is_array( $users ) )
+ return false;
+
+ screen_icon();
+ ?>
+ <h2><?php esc_html_e( 'Users' ); ?></h2>
+ <p><?php _e( 'Transfer or delete posts before deleting users.' ); ?></p>
+ <form action="users.php?action=dodelete" method="post">
+ <input type="hidden" name="dodelete" />
+ <?php
+ wp_nonce_field( 'ms-users-delete' );
+ $site_admins = get_super_admins();
+ $admin_out = "<option value='$current_user->ID'>$current_user->user_login</option>";
+
+ foreach ( ( $allusers = (array) $_POST['allusers'] ) as $key => $val ) {
+ if ( $val != '' && $val != '0' ) {
+ $delete_user = get_userdata( $val );
+
+ if ( ! current_user_can( 'delete_user', $delete_user->ID ) )
+ wp_die( sprintf( __( 'Warning! User %s cannot be deleted.' ), $delete_user->user_login ) );
+
+ if ( in_array( $delete_user->user_login, $site_admins ) )
+ wp_die( sprintf( __( 'Warning! User cannot be deleted. The user %s is a network administrator.' ), $delete_user->user_login ) );
+
+ echo "<input type='hidden' name='user[]' value='{$val}'/>\n";
+ $blogs = get_blogs_of_user( $val, true );
+
+ if ( !empty( $blogs ) ) {
+ ?>
+ <br /><fieldset><p><legend><?php printf( __( "What should be done with posts owned by <em>%s</em>?" ), $delete_user->user_login ); ?></legend></p>
+ <?php
+ foreach ( (array) $blogs as $key => $details ) {
+ $blog_users = get_users( array( 'blog_id' => $details->userblog_id ) );
+ if ( is_array( $blog_users ) && !empty( $blog_users ) ) {
+ $user_site = "<a href='" . esc_url( get_home_url( $details->userblog_id ) ) . "'>{$details->blogname}</a>";
+ $user_dropdown = "<select name='blog[$val][{$key}]'>";
+ $user_list = '';
+ foreach ( $blog_users as $user ) {
+ if ( ! in_array( $user->ID, $allusers ) )
+ $user_list .= "<option value='{$user->ID}'>{$user->user_login}</option>";
+ }
+ if ( '' == $user_list )
+ $user_list = $admin_out;
+ $user_dropdown .= $user_list;
+ $user_dropdown .= "</select>\n";
+ ?>
+ <ul style="list-style:none;">
+ <li><?php printf( __( 'Site: %s' ), $user_site ); ?></li>
+ <li><label><input type="radio" id="delete_option0" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID ?>]" value="delete" checked="checked" />
+ <?php _e( 'Delete all posts.' ); ?></label></li>
+ <li><label><input type="radio" id="delete_option1" name="delete[<?php echo $details->userblog_id . '][' . $delete_user->ID ?>]" value="reassign" />
+ <?php echo __( 'Attribute all posts to:' ) . '</label>' . $user_dropdown; ?></li>
+ </ul>
+ <?php
+ }
+ }
+ echo "</fieldset>";
+ }
+ }
+ }
+
+ submit_button( __('Confirm Deletion'), 'delete' );
+ ?>
+ </form>
+ <?php
+ return true;
+}
+
+if ( isset( $_GET['action'] ) ) {
+ do_action( 'wpmuadminedit' , '' );
+
+ switch ( $_GET['action'] ) {
+ case 'deleteuser':
+ if ( ! current_user_can( 'manage_network_users' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+ check_admin_referer( 'deleteuser' );
+
+ $id = intval( $_GET['id'] );
+ if ( $id != '0' && $id != '1' ) {
+ $_POST['allusers'] = array( $id ); // confirm_delete_users() can only handle with arrays
+ $title = __( 'Users' );
+ $parent_file = 'users.php';
+ require_once( '../admin-header.php' );
+ echo '<div class="wrap">';
+ confirm_delete_users( $_POST['allusers'] );
+ echo '</div>';
+ require_once( '../admin-footer.php' );
+ } else {
+ wp_redirect( network_admin_url( 'users.php' ) );
+ }
+ exit();
+ break;
+
+ case 'allusers':
+ if ( !current_user_can( 'manage_network_users' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+ if ( ( isset( $_POST['action']) || isset($_POST['action2'] ) ) && isset( $_POST['allusers'] ) ) {
+ check_admin_referer( 'bulk-users-network' );
+
+ $doaction = $_POST['action'] != -1 ? $_POST['action'] : $_POST['action2'];
+ $userfunction = '';
+
+ foreach ( (array) $_POST['allusers'] as $key => $val ) {
+ if ( !empty( $val ) ) {
+ switch ( $doaction ) {
+ case 'delete':
+ if ( ! current_user_can( 'delete_users' ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+ $title = __( 'Users' );
+ $parent_file = 'users.php';
+ require_once( '../admin-header.php' );
+ echo '<div class="wrap">';
+ confirm_delete_users( $_POST['allusers'] );
+ echo '</div>';
+ require_once( '../admin-footer.php' );
+ exit();
+ break;
+
+ case 'spam':
+ $user = get_userdata( $val );
+ if ( is_super_admin( $user->ID ) )
+ wp_die( sprintf( __( 'Warning! User cannot be modified. The user %s is a network administrator.' ), esc_html( $user->user_login ) ) );
+
+ $userfunction = 'all_spam';
+ $blogs = get_blogs_of_user( $val, true );
+ foreach ( (array) $blogs as $key => $details ) {
+ if ( $details->userblog_id != $current_site->blog_id ) // main blog not a spam !
+ update_blog_status( $details->userblog_id, 'spam', '1' );
+ }
+ update_user_status( $val, 'spam', '1' );
+ break;
+
+ case 'notspam':
+ $userfunction = 'all_notspam';
+ $blogs = get_blogs_of_user( $val, true );
+ foreach ( (array) $blogs as $key => $details )
+ update_blog_status( $details->userblog_id, 'spam', '0' );
+
+ update_user_status( $val, 'spam', '0' );
+ break;
+ }
+ }
+ }
+
+ wp_safe_redirect( add_query_arg( array( 'updated' => 'true', 'action' => $userfunction ), wp_get_referer() ) );
+ } else {
+ $location = network_admin_url( 'users.php' );
+
+ if ( ! empty( $_REQUEST['paged'] ) )
+ $location = add_query_arg( 'paged', (int) $_REQUEST['paged'], $location );
+ wp_redirect( $location );
+ }
+ exit();
+ break;
+
+ case 'dodelete':
+ check_admin_referer( 'ms-users-delete' );
+ if ( ! ( current_user_can( 'manage_network_users' ) && current_user_can( 'delete_users' ) ) )
+ wp_die( __( 'You do not have permission to access this page.' ) );
+
+ if ( ! empty( $_POST['blog'] ) && is_array( $_POST['blog'] ) ) {
+ foreach ( $_POST['blog'] as $id => $users ) {
+ foreach ( $users as $blogid => $user_id ) {
+ if ( ! current_user_can( 'delete_user', $id ) )
+ continue;
+
+ if ( ! empty( $_POST['delete'] ) && 'reassign' == $_POST['delete'][$blogid][$id] )
+ remove_user_from_blog( $id, $blogid, $user_id );
+ else
+ remove_user_from_blog( $id, $blogid );
+ }
+ }
+ }
+ $i = 0;
+ if ( is_array( $_POST['user'] ) && ! empty( $_POST['user'] ) )
+ foreach( $_POST['user'] as $id ) {
+ if ( ! current_user_can( 'delete_user', $id ) )
+ continue;
+ wpmu_delete_user( $id );
+ $i++;
+ }
+
+ if ( $i == 1 )
+ $deletefunction = 'delete';
+ else
+ $deletefunction = 'all_delete';
+
+ wp_redirect( add_query_arg( array( 'updated' => 'true', 'action' => $deletefunction ), network_admin_url( 'users.php' ) ) );
+ exit();
+ break;
+ }
+}
+
+$wp_list_table = _get_list_table('WP_MS_Users_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+$wp_list_table->prepare_items();
+$total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
+
+if ( $pagenum > $total_pages && $total_pages > 0 ) {
+ wp_redirect( add_query_arg( 'paged', $total_pages ) );
+ exit;
+}
+$title = __( 'Users' );
+$parent_file = 'users.php';
+
+add_screen_option( 'per_page', array('label' => _x( 'Users', 'users per page (screen options)' )) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('This table shows all users across the network and the sites to which they are assigned.') . '</p>' .
+ '<p>' . __('Hover over any user on the list to make the edit links appear. The Edit link on the left will take you to his or her Edit User profile page; the Edit link on the right by any site name goes to an Edit Site screen for that site.') . '</p>' .
+ '<p>' . __('You can also go to the user&#8217;s profile page by clicking on the individual username.') . '</p>' .
+ '<p>' . __('You can sort the table by clicking on any of the bold headings and switch between list and excerpt views by using the icons in the upper right.') . '</p>' .
+ '<p>' . __('The bulk action will permanently delete selected users, or mark/unmark those selected as spam. Spam users will have posts removed and will be unable to sign up again with the same email addresses.') . '</p>' .
+ '<p>' . __('You can make an existing user an additional super admin by going to the Edit User profile page and checking the box to grant that privilege.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Network_Admin_Users_Screen" target="_blank">Documentation on Network Users</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/forum/multisite/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+require_once( '../admin-header.php' );
+
+if ( isset( $_REQUEST['updated'] ) && $_REQUEST['updated'] == 'true' && ! empty( $_REQUEST['action'] ) ) {
+ ?>
+ <div id="message" class="updated"><p>
+ <?php
+ switch ( $_REQUEST['action'] ) {
+ case 'delete':
+ _e( 'User deleted.' );
+ break;
+ case 'all_spam':
+ _e( 'Users marked as spam.' );
+ break;
+ case 'all_notspam':
+ _e( 'Users removed from spam.' );
+ break;
+ case 'all_delete':
+ _e( 'Users deleted.' );
+ break;
+ case 'add':
+ _e( 'User added.' );
+ break;
+ }
+ ?>
+ </p></div>
+ <?php
+}
+ ?>
+<div class="wrap">
+ <?php screen_icon(); ?>
+ <h2><?php esc_html_e( 'Users' );
+ if ( current_user_can( 'create_users') ) : ?>
+ <a href="<?php echo network_admin_url('user-new.php'); ?>" class="add-new-h2"><?php echo esc_html_x( 'Add New', 'user' ); ?></a><?php
+ endif;
+
+ if ( !empty( $usersearch ) )
+ printf( '<span class="subtitle">' . __( 'Search results for &#8220;%s&#8221;' ) . '</span>', esc_html( $usersearch ) );
+ ?>
+ </h2>
+
+ <?php $wp_list_table->views(); ?>
+
+ <form action="" method="get" class="search-form">
+ <?php $wp_list_table->search_box( __( 'Search Users' ), 'all-user' ); ?>
+ </form>
+
+ <form id="form-user-list" action='users.php?action=allusers' method='post'>
+ <?php $wp_list_table->display(); ?>
+ </form>
+</div>
+
+<?php require_once( '../admin-footer.php' ); ?>
diff --git a/src/wp-admin/options-discussion.php b/src/wp-admin/options-discussion.php
new file mode 100644
index 0000000000..6e8d79f3c9
--- /dev/null
+++ b/src/wp-admin/options-discussion.php
@@ -0,0 +1,252 @@
+<?php
+/**
+ * Discussion settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+$title = __('Discussion Settings');
+$parent_file = 'options-general.php';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('This screen provides many options for controlling the management and display of comments and links to your posts/pages. So many, in fact, they won&#8217;t all fit here! :) Use the documentation links to get information on what each discussion setting does.') . '</p>' .
+ '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>',
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Settings_Discussion_Screen" target="_blank">Documentation on Discussion Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include('./admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<form method="post" action="options.php">
+<?php settings_fields('discussion'); ?>
+
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><?php _e('Default article settings'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Default article settings'); ?></span></legend>
+<label for="default_pingback_flag">
+<input name="default_pingback_flag" type="checkbox" id="default_pingback_flag" value="1" <?php checked('1', get_option('default_pingback_flag')); ?> />
+<?php _e('Attempt to notify any blogs linked to from the article'); ?></label>
+<br />
+<label for="default_ping_status">
+<input name="default_ping_status" type="checkbox" id="default_ping_status" value="open" <?php checked('open', get_option('default_ping_status')); ?> />
+<?php _e('Allow link notifications from other blogs (pingbacks and trackbacks)'); ?></label>
+<br />
+<label for="default_comment_status">
+<input name="default_comment_status" type="checkbox" id="default_comment_status" value="open" <?php checked('open', get_option('default_comment_status')); ?> />
+<?php _e('Allow people to post comments on new articles'); ?></label>
+<br />
+<small><em><?php echo '(' . __('These settings may be overridden for individual articles.') . ')'; ?></em></small>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Other comment settings'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Other comment settings'); ?></span></legend>
+<label for="require_name_email"><input type="checkbox" name="require_name_email" id="require_name_email" value="1" <?php checked('1', get_option('require_name_email')); ?> /> <?php _e('Comment author must fill out name and e-mail'); ?></label>
+<br />
+<label for="comment_registration">
+<input name="comment_registration" type="checkbox" id="comment_registration" value="1" <?php checked('1', get_option('comment_registration')); ?> />
+<?php _e('Users must be registered and logged in to comment'); ?>
+<?php if ( !get_option( 'users_can_register' ) && is_multisite() ) echo ' ' . __( '(Signup has been disabled. Only members of this site can comment.)' ); ?>
+</label>
+<br />
+
+<label for="close_comments_for_old_posts">
+<input name="close_comments_for_old_posts" type="checkbox" id="close_comments_for_old_posts" value="1" <?php checked('1', get_option('close_comments_for_old_posts')); ?> />
+<?php printf( __('Automatically close comments on articles older than %s days'), '</label><label for="close_comments_days_old"><input name="close_comments_days_old" type="number" min="0" step="1" id="close_comments_days_old" value="' . esc_attr(get_option('close_comments_days_old')) . '" class="small-text" />'); ?>
+</label>
+<br />
+<label for="thread_comments">
+<input name="thread_comments" type="checkbox" id="thread_comments" value="1" <?php checked('1', get_option('thread_comments')); ?> />
+<?php
+
+$maxdeep = (int) apply_filters( 'thread_comments_depth_max', 10 );
+
+$thread_comments_depth = '</label><label for="thread_comments_depth"><select name="thread_comments_depth" id="thread_comments_depth">';
+for ( $i = 2; $i <= $maxdeep; $i++ ) {
+ $thread_comments_depth .= "<option value='" . esc_attr($i) . "'";
+ if ( get_option('thread_comments_depth') == $i ) $thread_comments_depth .= " selected='selected'";
+ $thread_comments_depth .= ">$i</option>";
+}
+$thread_comments_depth .= '</select>';
+
+printf( __('Enable threaded (nested) comments %s levels deep'), $thread_comments_depth );
+
+?></label>
+<br />
+<label for="page_comments">
+<input name="page_comments" type="checkbox" id="page_comments" value="1" <?php checked('1', get_option('page_comments')); ?> />
+<?php
+
+$default_comments_page = '</label><label for="default_comments_page"><select name="default_comments_page" id="default_comments_page"><option value="newest"';
+if ( 'newest' == get_option('default_comments_page') ) $default_comments_page .= ' selected="selected"';
+$default_comments_page .= '>' . __('last') . '</option><option value="oldest"';
+if ( 'oldest' == get_option('default_comments_page') ) $default_comments_page .= ' selected="selected"';
+$default_comments_page .= '>' . __('first') . '</option></select>';
+
+printf( __('Break comments into pages with %1$s top level comments per page and the %2$s page displayed by default'), '</label><label for="comments_per_page"><input name="comments_per_page" type="number" step="1" min="0" id="comments_per_page" value="' . esc_attr(get_option('comments_per_page')) . '" class="small-text" />', $default_comments_page );
+
+?></label>
+<br />
+<label for="comment_order"><?php
+
+$comment_order = '<select name="comment_order" id="comment_order"><option value="asc"';
+if ( 'asc' == get_option('comment_order') ) $comment_order .= ' selected="selected"';
+$comment_order .= '>' . __('older') . '</option><option value="desc"';
+if ( 'desc' == get_option('comment_order') ) $comment_order .= ' selected="selected"';
+$comment_order .= '>' . __('newer') . '</option></select>';
+
+printf( __('Comments should be displayed with the %s comments at the top of each page'), $comment_order );
+
+?></label>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('E-mail me whenever'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('E-mail me whenever'); ?></span></legend>
+<label for="comments_notify">
+<input name="comments_notify" type="checkbox" id="comments_notify" value="1" <?php checked('1', get_option('comments_notify')); ?> />
+<?php _e('Anyone posts a comment'); ?> </label>
+<br />
+<label for="moderation_notify">
+<input name="moderation_notify" type="checkbox" id="moderation_notify" value="1" <?php checked('1', get_option('moderation_notify')); ?> />
+<?php _e('A comment is held for moderation'); ?> </label>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Before a comment appears'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Before a comment appears'); ?></span></legend>
+<label for="comment_moderation">
+<input name="comment_moderation" type="checkbox" id="comment_moderation" value="1" <?php checked('1', get_option('comment_moderation')); ?> />
+<?php _e('An administrator must always approve the comment'); ?> </label>
+<br />
+<label for="comment_whitelist"><input type="checkbox" name="comment_whitelist" id="comment_whitelist" value="1" <?php checked('1', get_option('comment_whitelist')); ?> /> <?php _e('Comment author must have a previously approved comment'); ?></label>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Comment Moderation'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Comment Moderation'); ?></span></legend>
+<p><label for="comment_max_links"><?php printf(__('Hold a comment in the queue if it contains %s or more links. (A common characteristic of comment spam is a large number of hyperlinks.)'), '<input name="comment_max_links" type="number" step="1" min="0" id="comment_max_links" value="' . esc_attr(get_option('comment_max_links')) . '" class="small-text" />' ); ?></label></p>
+
+<p><label for="moderation_keys"><?php _e('When a comment contains any of these words in its content, name, URL, e-mail, or IP, it will be held in the <a href="edit-comments.php?comment_status=moderated">moderation queue</a>. One word or IP per line. It will match inside words, so &#8220;press&#8221; will match &#8220;WordPress&#8221;.'); ?></label></p>
+<p>
+<textarea name="moderation_keys" rows="10" cols="50" id="moderation_keys" class="large-text code"><?php echo esc_textarea( get_option( 'moderation_keys' ) ); ?></textarea>
+</p>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Comment Blacklist'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Comment Blacklist'); ?></span></legend>
+<p><label for="blacklist_keys"><?php _e('When a comment contains any of these words in its content, name, URL, e-mail, or IP, it will be marked as spam. One word or IP per line. It will match inside words, so &#8220;press&#8221; will match &#8220;WordPress&#8221;.'); ?></label></p>
+<p>
+<textarea name="blacklist_keys" rows="10" cols="50" id="blacklist_keys" class="large-text code"><?php echo esc_textarea( get_option( 'blacklist_keys' ) ); ?></textarea>
+</p>
+</fieldset></td>
+</tr>
+<?php do_settings_fields('discussion', 'default'); ?>
+</table>
+
+<h3 class="title"><?php _e('Avatars'); ?></h3>
+
+<p><?php _e('An avatar is an image that follows you from weblog to weblog appearing beside your name when you comment on avatar enabled sites. Here you can enable the display of avatars for people who comment on your site.'); ?></p>
+
+<?php // the above would be a good place to link to codex documentation on the gravatar functions, for putting it in themes. anything like that? ?>
+
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><?php _e('Avatar Display'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Avatar Display'); ?></span></legend>
+ <label for="show_avatars">
+ <input type="checkbox" id="show_avatars" name="show_avatars" value="1" <?php checked( get_option('show_avatars'), 1 ); ?> />
+ <?php _e( 'Show Avatars' ); ?>
+ </label>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Maximum Rating'); ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Maximum Rating'); ?></span></legend>
+
+<?php
+$ratings = array(
+ /* translators: Content suitability rating: http://bit.ly/89QxZA */
+ 'G' => __('G &#8212; Suitable for all audiences'),
+ /* translators: Content suitability rating: http://bit.ly/89QxZA */
+ 'PG' => __('PG &#8212; Possibly offensive, usually for audiences 13 and above'),
+ /* translators: Content suitability rating: http://bit.ly/89QxZA */
+ 'R' => __('R &#8212; Intended for adult audiences above 17'),
+ /* translators: Content suitability rating: http://bit.ly/89QxZA */
+ 'X' => __('X &#8212; Even more mature than above')
+);
+foreach ($ratings as $key => $rating) :
+ $selected = (get_option('avatar_rating') == $key) ? 'checked="checked"' : '';
+ echo "\n\t<label><input type='radio' name='avatar_rating' value='" . esc_attr($key) . "' $selected/> $rating</label><br />";
+endforeach;
+?>
+
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Default Avatar'); ?></th>
+<td class="defaultavatarpicker"><fieldset><legend class="screen-reader-text"><span><?php _e('Default Avatar'); ?></span></legend>
+
+<?php _e('For users without a custom avatar of their own, you can either display a generic logo or a generated one based on their e-mail address.'); ?><br />
+
+<?php
+$avatar_defaults = array(
+ 'mystery' => __('Mystery Man'),
+ 'blank' => __('Blank'),
+ 'gravatar_default' => __('Gravatar Logo'),
+ 'identicon' => __('Identicon (Generated)'),
+ 'wavatar' => __('Wavatar (Generated)'),
+ 'monsterid' => __('MonsterID (Generated)'),
+ 'retro' => __('Retro (Generated)')
+);
+$avatar_defaults = apply_filters('avatar_defaults', $avatar_defaults);
+$default = get_option('avatar_default');
+if ( empty($default) )
+ $default = 'mystery';
+$size = 32;
+$avatar_list = '';
+foreach ( $avatar_defaults as $default_key => $default_name ) {
+ $selected = ($default == $default_key) ? 'checked="checked" ' : '';
+ $avatar_list .= "\n\t<label><input type='radio' name='avatar_default' id='avatar_{$default_key}' value='" . esc_attr($default_key) . "' {$selected}/> ";
+
+ $avatar = get_avatar( $user_email, $size, $default_key );
+ $avatar_list .= preg_replace("/src='(.+?)'/", "src='\$1&amp;forcedefault=1'", $avatar);
+
+ $avatar_list .= ' ' . $default_name . '</label>';
+ $avatar_list .= '<br />';
+}
+echo apply_filters('default_avatar_select', $avatar_list);
+?>
+
+</fieldset></td>
+</tr>
+<?php do_settings_fields('discussion', 'avatars'); ?>
+</table>
+
+<?php do_settings_sections('discussion'); ?>
+
+<?php submit_button(); ?>
+</form>
+</div>
+
+<?php include('./admin-footer.php'); ?>
diff --git a/src/wp-admin/options-general.php b/src/wp-admin/options-general.php
new file mode 100644
index 0000000000..fdae33a60b
--- /dev/null
+++ b/src/wp-admin/options-general.php
@@ -0,0 +1,327 @@
+<?php
+/**
+ * General settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+$title = __('General Settings');
+$parent_file = 'options-general.php';
+/* translators: date and time format for exact current time, mainly about timezones, see http://php.net/date */
+$timezone_format = _x('Y-m-d G:i:s', 'timezone date format');
+
+/**
+ * Display JavaScript on the page.
+ *
+ * @since 3.5.0
+ */
+function options_general_add_js() {
+?>
+<script type="text/javascript">
+//<![CDATA[
+ jQuery(document).ready(function($){
+ $("input[name='date_format']").click(function(){
+ if ( "date_format_custom_radio" != $(this).attr("id") )
+ $("input[name='date_format_custom']").val( $(this).val() ).siblings('.example').text( $(this).siblings('span').text() );
+ });
+ $("input[name='date_format_custom']").focus(function(){
+ $("#date_format_custom_radio").attr("checked", "checked");
+ });
+
+ $("input[name='time_format']").click(function(){
+ if ( "time_format_custom_radio" != $(this).attr("id") )
+ $("input[name='time_format_custom']").val( $(this).val() ).siblings('.example').text( $(this).siblings('span').text() );
+ });
+ $("input[name='time_format_custom']").focus(function(){
+ $("#time_format_custom_radio").attr("checked", "checked");
+ });
+ $("input[name='date_format_custom'], input[name='time_format_custom']").change( function() {
+ var format = $(this);
+ format.siblings('.spinner').css('display', 'inline-block'); // show(); can't be used here
+ $.post(ajaxurl, {
+ action: 'date_format_custom' == format.attr('name') ? 'date_format' : 'time_format',
+ date : format.val()
+ }, function(d) { format.siblings('.spinner').hide(); format.siblings('.example').text(d); } );
+ });
+ });
+//]]>
+</script>
+<?php
+}
+add_action('admin_head', 'options_general_add_js');
+
+$options_help = '<p>' . __('The fields on this screen determine some of the basics of your site setup.') . '</p>' .
+ '<p>' . __('Most themes display the site title at the top of every page, in the title bar of the browser, and as the identifying name for syndicated feeds. The tagline is also displayed by many themes.') . '</p>';
+
+if ( ! is_multisite() ) {
+ $options_help .= '<p>' . __('The WordPress URL and the Site URL can be the same (example.com) or different; for example, having the WordPress core files (example.com/wordpress) in a subdirectory instead of the root directory.') . '</p>' .
+ '<p>' . __('If you want site visitors to be able to register themselves, as opposed to by the site administrator, check the membership box. A default user role can be set for all new users, whether self-registered or registered by the site admin.') . '</p>';
+}
+
+$options_help .= '<p>' . __('UTC means Coordinated Universal Time.') . '</p>' .
+ '<p>' . __( 'You must click the Save Changes button at the bottom of the screen for new settings to take effect.' ) . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $options_help,
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Settings_General_Screen" target="_blank">Documentation on General Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include('./admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<form method="post" action="options.php">
+<?php settings_fields('general'); ?>
+
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><label for="blogname"><?php _e('Site Title') ?></label></th>
+<td><input name="blogname" type="text" id="blogname" value="<?php form_option('blogname'); ?>" class="regular-text" /></td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="blogdescription"><?php _e('Tagline') ?></label></th>
+<td><input name="blogdescription" type="text" id="blogdescription" value="<?php form_option('blogdescription'); ?>" class="regular-text" />
+<p class="description"><?php _e('In a few words, explain what this site is about.') ?></p></td>
+</tr>
+<?php if ( !is_multisite() ) { ?>
+<tr valign="top">
+<th scope="row"><label for="siteurl"><?php _e('WordPress Address (URL)') ?></label></th>
+<td><input name="siteurl" type="text" id="siteurl" value="<?php form_option('siteurl'); ?>"<?php disabled( defined( 'WP_SITEURL' ) ); ?> class="regular-text code<?php if ( defined( 'WP_SITEURL' ) ) echo ' disabled' ?>" /></td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="home"><?php _e('Site Address (URL)') ?></label></th>
+<td><input name="home" type="text" id="home" value="<?php form_option('home'); ?>"<?php disabled( defined( 'WP_HOME' ) ); ?> class="regular-text code<?php if ( defined( 'WP_HOME' ) ) echo ' disabled' ?>" />
+<p class="description"><?php _e('Enter the address here if you want your site homepage <a href="http://codex.wordpress.org/Giving_WordPress_Its_Own_Directory">to be different from the directory</a> you installed WordPress.'); ?></p></td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="admin_email"><?php _e('E-mail Address') ?> </label></th>
+<td><input name="admin_email" type="text" id="admin_email" value="<?php form_option('admin_email'); ?>" class="regular-text ltr" />
+<p class="description"><?php _e('This address is used for admin purposes, like new user notification.') ?></p></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e('Membership') ?></th>
+<td> <fieldset><legend class="screen-reader-text"><span><?php _e('Membership') ?></span></legend><label for="users_can_register">
+<input name="users_can_register" type="checkbox" id="users_can_register" value="1" <?php checked('1', get_option('users_can_register')); ?> />
+<?php _e('Anyone can register') ?></label>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="default_role"><?php _e('New User Default Role') ?></label></th>
+<td>
+<select name="default_role" id="default_role"><?php wp_dropdown_roles( get_option('default_role') ); ?></select>
+</td>
+</tr>
+<?php } else { ?>
+<tr valign="top">
+<th scope="row"><label for="new_admin_email"><?php _e('E-mail Address') ?> </label></th>
+<td><input name="new_admin_email" type="text" id="new_admin_email" value="<?php form_option('admin_email'); ?>" class="regular-text ltr" />
+<p class="description"><?php _e('This address is used for admin purposes. If you change this we will send you an e-mail at your new address to confirm it. <strong>The new address will not become active until confirmed.</strong>') ?></p>
+<?php
+$new_admin_email = get_option( 'new_admin_email' );
+if ( $new_admin_email && $new_admin_email != get_option('admin_email') ) : ?>
+<div class="updated inline">
+<p><?php printf( __('There is a pending change of the admin e-mail to <code>%1$s</code>. <a href="%2$s">Cancel</a>'), esc_html( $new_admin_email ), esc_url( admin_url( 'options.php?dismiss=new_admin_email' ) ) ); ?></p>
+</div>
+<?php endif; ?>
+</td>
+</tr>
+<?php } ?>
+<tr>
+<?php
+$current_offset = get_option('gmt_offset');
+$tzstring = get_option('timezone_string');
+
+$check_zone_info = true;
+
+// Remove old Etc mappings. Fallback to gmt_offset.
+if ( false !== strpos($tzstring,'Etc/GMT') )
+ $tzstring = '';
+
+if ( empty($tzstring) ) { // Create a UTC+- zone if no timezone string exists
+ $check_zone_info = false;
+ if ( 0 == $current_offset )
+ $tzstring = 'UTC+0';
+ elseif ($current_offset < 0)
+ $tzstring = 'UTC' . $current_offset;
+ else
+ $tzstring = 'UTC+' . $current_offset;
+}
+
+?>
+<th scope="row"><label for="timezone_string"><?php _e('Timezone') ?></label></th>
+<td>
+
+<select id="timezone_string" name="timezone_string">
+<?php echo wp_timezone_choice($tzstring); ?>
+</select>
+
+ <span id="utc-time"><?php printf(__('<abbr title="Coordinated Universal Time">UTC</abbr> time is <code>%s</code>'), date_i18n($timezone_format, false, 'gmt')); ?></span>
+<?php if ( get_option('timezone_string') || !empty($current_offset) ) : ?>
+ <span id="local-time"><?php printf(__('Local time is <code>%1$s</code>'), date_i18n($timezone_format)); ?></span>
+<?php endif; ?>
+<p class="description"><?php _e('Choose a city in the same timezone as you.'); ?></p>
+<?php if ($check_zone_info && $tzstring) : ?>
+<br />
+<span>
+ <?php
+ // Set TZ so localtime works.
+ date_default_timezone_set($tzstring);
+ $now = localtime(time(), true);
+ if ( $now['tm_isdst'] )
+ _e('This timezone is currently in daylight saving time.');
+ else
+ _e('This timezone is currently in standard time.');
+ ?>
+ <br />
+ <?php
+ $allowed_zones = timezone_identifiers_list();
+
+ if ( in_array( $tzstring, $allowed_zones) ) {
+ $found = false;
+ $date_time_zone_selected = new DateTimeZone($tzstring);
+ $tz_offset = timezone_offset_get($date_time_zone_selected, date_create());
+ $right_now = time();
+ foreach ( timezone_transitions_get($date_time_zone_selected) as $tr) {
+ if ( $tr['ts'] > $right_now ) {
+ $found = true;
+ break;
+ }
+ }
+
+ if ( $found ) {
+ echo ' ';
+ $message = $tr['isdst'] ?
+ __('Daylight saving time begins on: <code>%s</code>.') :
+ __('Standard time begins on: <code>%s</code>.');
+ // Add the difference between the current offset and the new offset to ts to get the correct transition time from date_i18n().
+ printf( $message, date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $tr['ts'] + ($tz_offset - $tr['offset']) ) );
+ } else {
+ _e('This timezone does not observe daylight saving time.');
+ }
+ }
+ // Set back to UTC.
+ date_default_timezone_set('UTC');
+ ?>
+ </span>
+<?php endif; ?>
+</td>
+
+</tr>
+<tr>
+<th scope="row"><?php _e('Date Format') ?></th>
+<td>
+ <fieldset><legend class="screen-reader-text"><span><?php _e('Date Format') ?></span></legend>
+<?php
+
+ $date_formats = array_unique( apply_filters( 'date_formats', array(
+ __('F j, Y'),
+ 'Y/m/d',
+ 'm/d/Y',
+ 'd/m/Y',
+ ) ) );
+
+ $custom = true;
+
+ foreach ( $date_formats as $format ) {
+ echo "\t<label title='" . esc_attr($format) . "'><input type='radio' name='date_format' value='" . esc_attr($format) . "'";
+ if ( get_option('date_format') === $format ) { // checked() uses "==" rather than "==="
+ echo " checked='checked'";
+ $custom = false;
+ }
+ echo ' /> <span>' . date_i18n( $format ) . "</span></label><br />\n";
+ }
+
+ echo ' <label><input type="radio" name="date_format" id="date_format_custom_radio" value="\c\u\s\t\o\m"';
+ checked( $custom );
+ echo '/> ' . __('Custom:') . ' </label><input type="text" name="date_format_custom" value="' . esc_attr( get_option('date_format') ) . '" class="small-text" /> <span class="example"> ' . date_i18n( get_option('date_format') ) . "</span> <span class='spinner'></span>\n";
+
+ echo "\t<p>" . __('<a href="http://codex.wordpress.org/Formatting_Date_and_Time">Documentation on date and time formatting</a>.') . "</p>\n";
+?>
+ </fieldset>
+</td>
+</tr>
+<tr>
+<th scope="row"><?php _e('Time Format') ?></th>
+<td>
+ <fieldset><legend class="screen-reader-text"><span><?php _e('Time Format') ?></span></legend>
+<?php
+
+ $time_formats = array_unique( apply_filters( 'time_formats', array(
+ __('g:i a'),
+ 'g:i A',
+ 'H:i',
+ ) ) );
+
+ $custom = true;
+
+ foreach ( $time_formats as $format ) {
+ echo "\t<label title='" . esc_attr($format) . "'><input type='radio' name='time_format' value='" . esc_attr($format) . "'";
+ if ( get_option('time_format') === $format ) { // checked() uses "==" rather than "==="
+ echo " checked='checked'";
+ $custom = false;
+ }
+ echo ' /> <span>' . date_i18n( $format ) . "</span></label><br />\n";
+ }
+
+ echo ' <label><input type="radio" name="time_format" id="time_format_custom_radio" value="\c\u\s\t\o\m"';
+ checked( $custom );
+ echo '/> ' . __('Custom:') . ' </label><input type="text" name="time_format_custom" value="' . esc_attr( get_option('time_format') ) . '" class="small-text" /> <span class="example"> ' . date_i18n( get_option('time_format') ) . "</span> <span class='spinner'></span>\n";
+ ;
+?>
+ </fieldset>
+</td>
+</tr>
+<tr>
+<th scope="row"><label for="start_of_week"><?php _e('Week Starts On') ?></label></th>
+<td><select name="start_of_week" id="start_of_week">
+<?php
+for ($day_index = 0; $day_index <= 6; $day_index++) :
+ $selected = (get_option('start_of_week') == $day_index) ? 'selected="selected"' : '';
+ echo "\n\t<option value='" . esc_attr($day_index) . "' $selected>" . $wp_locale->get_weekday($day_index) . '</option>';
+endfor;
+?>
+</select></td>
+</tr>
+<?php do_settings_fields('general', 'default'); ?>
+<?php
+ $languages = get_available_languages();
+ if ( is_multisite() && !empty( $languages ) ):
+?>
+ <tr valign="top">
+ <th width="33%" scope="row"><?php _e('Site Language') ?></th>
+ <td>
+ <select name="WPLANG" id="WPLANG">
+ <?php mu_dropdown_languages( $languages, get_option('WPLANG') ); ?>
+ </select>
+ </td>
+ </tr>
+<?php
+ endif;
+?>
+</table>
+
+<?php do_settings_sections('general'); ?>
+
+<?php submit_button(); ?>
+</form>
+
+</div>
+
+<?php include('./admin-footer.php') ?>
diff --git a/src/wp-admin/options-head.php b/src/wp-admin/options-head.php
new file mode 100644
index 0000000000..1c706c87d7
--- /dev/null
+++ b/src/wp-admin/options-head.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * WordPress Options Header.
+ *
+ * Displays updated message, if updated variable is part of the URL query.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+wp_reset_vars( array( 'action' ) );
+
+if ( isset( $_GET['updated'] ) && isset( $_GET['page'] ) ) {
+ // For backwards compat with plugins that don't use the Settings API and just set updated=1 in the redirect
+ add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
+}
+
+settings_errors();
diff --git a/src/wp-admin/options-media.php b/src/wp-admin/options-media.php
new file mode 100644
index 0000000000..8ba2371f7f
--- /dev/null
+++ b/src/wp-admin/options-media.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * Media settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+$title = __('Media Settings');
+$parent_file = 'options-general.php';
+
+$media_options_help = '<p>' . __('You can set maximum sizes for images inserted into your written content; you can also insert an image as Full Size.') . '</p>';
+
+if ( ! is_multisite() && ( get_option('upload_url_path') || ( get_option('upload_path') != 'wp-content/uploads' && get_option('upload_path') ) ) ) {
+ $media_options_help .= '<p>' . __('Uploading Files allows you to choose the folder and path for storing your uploaded files.') . '</p>';
+}
+
+$media_options_help .= '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $media_options_help,
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Settings_Media_Screen" target="_blank">Documentation on Media Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include('./admin-header.php');
+
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<form action="options.php" method="post">
+<?php settings_fields('media'); ?>
+
+<h3 class="title"><?php _e('Image sizes') ?></h3>
+<p><?php _e('The sizes listed below determine the maximum dimensions in pixels to use when inserting an image into the body of a post.'); ?></p>
+
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><?php _e('Thumbnail size') ?></th>
+<td>
+<label for="thumbnail_size_w"><?php _e('Width'); ?></label>
+<input name="thumbnail_size_w" type="number" step="1" min="0" id="thumbnail_size_w" value="<?php form_option('thumbnail_size_w'); ?>" class="small-text" />
+<label for="thumbnail_size_h"><?php _e('Height'); ?></label>
+<input name="thumbnail_size_h" type="number" step="1" min="0" id="thumbnail_size_h" value="<?php form_option('thumbnail_size_h'); ?>" class="small-text" /><br />
+<input name="thumbnail_crop" type="checkbox" id="thumbnail_crop" value="1" <?php checked('1', get_option('thumbnail_crop')); ?>/>
+<label for="thumbnail_crop"><?php _e('Crop thumbnail to exact dimensions (normally thumbnails are proportional)'); ?></label>
+</td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><?php _e('Medium size') ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Medium size'); ?></span></legend>
+<label for="medium_size_w"><?php _e('Max Width'); ?></label>
+<input name="medium_size_w" type="number" step="1" min="0" id="medium_size_w" value="<?php form_option('medium_size_w'); ?>" class="small-text" />
+<label for="medium_size_h"><?php _e('Max Height'); ?></label>
+<input name="medium_size_h" type="number" step="1" min="0" id="medium_size_h" value="<?php form_option('medium_size_h'); ?>" class="small-text" />
+</fieldset></td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><?php _e('Large size') ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Large size'); ?></span></legend>
+<label for="large_size_w"><?php _e('Max Width'); ?></label>
+<input name="large_size_w" type="number" step="1" min="0" id="large_size_w" value="<?php form_option('large_size_w'); ?>" class="small-text" />
+<label for="large_size_h"><?php _e('Max Height'); ?></label>
+<input name="large_size_h" type="number" step="1" min="0" id="large_size_h" value="<?php form_option('large_size_h'); ?>" class="small-text" />
+</fieldset></td>
+</tr>
+
+<?php do_settings_fields('media', 'default'); ?>
+</table>
+
+<?php if ( isset( $GLOBALS['wp_settings']['media']['embeds'] ) ) : ?>
+<h3 class="title"><?php _e('Embeds') ?></h3>
+<table class="form-table">
+<?php do_settings_fields( 'media', 'embeds' ); ?>
+</table>
+<?php endif; ?>
+
+<?php if ( !is_multisite() ) : ?>
+<h3 class="title"><?php _e('Uploading Files'); ?></h3>
+<table class="form-table">
+<?php
+// If upload_url_path is not the default (empty), and upload_path is not the default ('wp-content/uploads' or empty)
+if ( get_option('upload_url_path') || ( get_option('upload_path') != 'wp-content/uploads' && get_option('upload_path') ) ) :
+?>
+<tr valign="top">
+<th scope="row"><label for="upload_path"><?php _e('Store uploads in this folder'); ?></label></th>
+<td><input name="upload_path" type="text" id="upload_path" value="<?php echo esc_attr(get_option('upload_path')); ?>" class="regular-text code" />
+<p class="description"><?php _e('Default is <code>wp-content/uploads</code>'); ?></p>
+</td>
+</tr>
+
+<tr valign="top">
+<th scope="row"><label for="upload_url_path"><?php _e('Full URL path to files'); ?></label></th>
+<td><input name="upload_url_path" type="text" id="upload_url_path" value="<?php echo esc_attr( get_option('upload_url_path')); ?>" class="regular-text code" />
+<p class="description"><?php _e('Configuring this is optional. By default, it should be blank.'); ?></p>
+</td>
+</tr>
+<?php endif; ?>
+<tr>
+<th scope="row" colspan="2" class="th-full">
+<label for="uploads_use_yearmonth_folders">
+<input name="uploads_use_yearmonth_folders" type="checkbox" id="uploads_use_yearmonth_folders" value="1"<?php checked('1', get_option('uploads_use_yearmonth_folders')); ?> />
+<?php _e('Organize my uploads into month- and year-based folders'); ?>
+</label>
+</th>
+</tr>
+
+<?php do_settings_fields('media', 'uploads'); ?>
+</table>
+<?php endif; ?>
+
+<?php do_settings_sections('media'); ?>
+
+<?php submit_button(); ?>
+
+</form>
+
+</div>
+
+<?php include('./admin-footer.php'); ?>
diff --git a/src/wp-admin/options-permalink.php b/src/wp-admin/options-permalink.php
new file mode 100644
index 0000000000..d086fdc6b1
--- /dev/null
+++ b/src/wp-admin/options-permalink.php
@@ -0,0 +1,285 @@
+<?php
+/**
+ * Permalink Settings Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+$title = __('Permalink Settings');
+$parent_file = 'options-general.php';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('Permalinks are the permanent URLs to your individual pages and blog posts, as well as your category and tag archives. A permalink is the web address used to link to your content. The URL to each post should be permanent, and never change &#8212; hence the name permalink.') . '</p>' .
+ '<p>' . __('This screen allows you to choose your default permalink structure. You can choose from common settings or create custom URL structures.') . '</p>' .
+ '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>',
+) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'common-settings',
+ 'title' => __('Common Settings'),
+ 'content' => '<p>' . __('Many people choose to use &#8220;pretty permalinks,&#8221; URLs that contain useful information such as the post title rather than generic post ID numbers. You can choose from any of the permalink formats under Common Settings, or can craft your own if you select Custom Structure.') . '</p>' .
+ '<p>' . __('If you pick an option other than Default, your general URL path with structure tags, terms surrounded by <code>%</code>, will also appear in the custom structure field and your path can be further modified there.') . '</p>' .
+ '<p>' . __('When you assign multiple categories or tags to a post, only one can show up in the permalink: the lowest numbered category. This applies if your custom structure includes <code>%category%</code> or <code>%tag%</code>.') . '</p>' .
+ '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>',
+) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'custom-structures',
+ 'title' => __('Custom Structures'),
+ 'content' => '<p>' . __('The Optional fields let you customize the &#8220;category&#8221; and &#8220;tag&#8221; base names that will appear in archive URLs. For example, the page listing all posts in the &#8220;Uncategorized&#8221; category could be <code>/topics/uncategorized</code> instead of <code>/category/uncategorized</code>.') . '</p>' .
+ '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>',
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Settings_Permalinks_Screen" target="_blank">Documentation on Permalinks Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Using_Permalinks" target="_blank">Documentation on Using Permalinks</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+/**
+ * Display JavaScript on the page.
+ *
+ * @since 3.5.0
+ */
+function options_permalink_add_js() {
+ ?>
+<script type="text/javascript">
+//<![CDATA[
+jQuery(document).ready(function() {
+ jQuery('.permalink-structure input:radio').change(function() {
+ if ( 'custom' == this.value )
+ return;
+ jQuery('#permalink_structure').val( this.value );
+ });
+ jQuery('#permalink_structure').focus(function() {
+ jQuery("#custom_selection").attr('checked', 'checked');
+ });
+});
+//]]>
+</script>
+<?php
+}
+add_filter('admin_head', 'options_permalink_add_js');
+
+$home_path = get_home_path();
+$iis7_permalinks = iis7_supports_permalinks();
+
+$prefix = $blog_prefix = '';
+if ( ! got_mod_rewrite() && ! $iis7_permalinks )
+ $prefix = '/index.php';
+if ( is_multisite() && !is_subdomain_install() && is_main_site() )
+ $blog_prefix = '/blog';
+
+if ( isset($_POST['permalink_structure']) || isset($_POST['category_base']) ) {
+ check_admin_referer('update-permalink');
+
+ if ( isset( $_POST['permalink_structure'] ) ) {
+ if ( isset( $_POST['selection'] ) && 'custom' != $_POST['selection'] )
+ $permalink_structure = $_POST['selection'];
+ else
+ $permalink_structure = $_POST['permalink_structure'];
+
+ if ( ! empty( $permalink_structure ) ) {
+ $permalink_structure = preg_replace( '#/+#', '/', '/' . str_replace( '#', '', $permalink_structure ) );
+ if ( $prefix && $blog_prefix )
+ $permalink_structure = $prefix . preg_replace( '#^/?index\.php#', '', $permalink_structure );
+ else
+ $permalink_structure = $blog_prefix . $permalink_structure;
+ }
+ $wp_rewrite->set_permalink_structure( $permalink_structure );
+ }
+
+ if ( isset( $_POST['category_base'] ) ) {
+ $category_base = $_POST['category_base'];
+ if ( ! empty( $category_base ) )
+ $category_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $category_base ) );
+ $wp_rewrite->set_category_base( $category_base );
+ }
+
+ if ( isset( $_POST['tag_base'] ) ) {
+ $tag_base = $_POST['tag_base'];
+ if ( ! empty( $tag_base ) )
+ $tag_base = $blog_prefix . preg_replace('#/+#', '/', '/' . str_replace( '#', '', $tag_base ) );
+ $wp_rewrite->set_tag_base( $tag_base );
+ }
+
+ wp_redirect( admin_url( 'options-permalink.php?settings-updated=true' ) );
+ exit;
+}
+
+$permalink_structure = get_option('permalink_structure');
+$category_base = get_option('category_base');
+$tag_base = get_option( 'tag_base' );
+
+if ( $iis7_permalinks ) {
+ if ( ( ! file_exists($home_path . 'web.config') && win_is_writable($home_path) ) || win_is_writable($home_path . 'web.config') )
+ $writable = true;
+ else
+ $writable = false;
+} else {
+ if ( ( ! file_exists($home_path . '.htaccess') && is_writable($home_path) ) || is_writable($home_path . '.htaccess') )
+ $writable = true;
+ else
+ $writable = false;
+}
+
+if ( $wp_rewrite->using_index_permalinks() )
+ $usingpi = true;
+else
+ $usingpi = false;
+
+flush_rewrite_rules();
+
+require( ABSPATH . 'wp-admin/admin-header.php' );
+
+if ( ! empty( $_GET['settings-updated'] ) ) : ?>
+<div id="message" class="updated"><p><?php
+if ( ! is_multisite() ) {
+ if ( $iis7_permalinks ) {
+ if ( $permalink_structure && ! $usingpi && ! $writable )
+ _e('You should update your web.config now.');
+ else if ( $permalink_structure && ! $usingpi && $writable )
+ _e('Permalink structure updated. Remove write access on web.config file now!');
+ else
+ _e('Permalink structure updated.');
+ } else {
+ if ( $permalink_structure && ! $usingpi && ! $writable )
+ _e('You should update your .htaccess now.');
+ else
+ _e('Permalink structure updated.');
+ }
+} else {
+ _e('Permalink structure updated.');
+}
+?>
+</p></div>
+<?php endif; ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<form name="form" action="options-permalink.php" method="post">
+<?php wp_nonce_field('update-permalink') ?>
+
+ <p><?php _e('By default WordPress uses web <abbr title="Universal Resource Locator">URL</abbr>s which have question marks and lots of numbers in them, however WordPress offers you the ability to create a custom URL structure for your permalinks and archives. This can improve the aesthetics, usability, and forward-compatibility of your links. A <a href="http://codex.wordpress.org/Using_Permalinks">number of tags are available</a>, and here are some examples to get you started.'); ?></p>
+
+<?php
+if ( is_multisite() && !is_subdomain_install() && is_main_site() ) {
+ $permalink_structure = preg_replace( '|^/?blog|', '', $permalink_structure );
+ $category_base = preg_replace( '|^/?blog|', '', $category_base );
+ $tag_base = preg_replace( '|^/?blog|', '', $tag_base );
+}
+
+$structures = array(
+ 0 => '',
+ 1 => $prefix . '/%year%/%monthnum%/%day%/%postname%/',
+ 2 => $prefix . '/%year%/%monthnum%/%postname%/',
+ 3 => $prefix . '/' . _x( 'archives', 'sample permalink base' ) . '/%post_id%',
+ 4 => $prefix . '/%postname%/',
+);
+?>
+<h3 class="title"><?php _e('Common Settings'); ?></h3>
+<table class="form-table permalink-structure">
+ <tr>
+ <th><label><input name="selection" type="radio" value="" <?php checked('', $permalink_structure); ?> /> <?php _e('Default'); ?></label></th>
+ <td><code><?php echo get_option('home'); ?>/?p=123</code></td>
+ </tr>
+ <tr>
+ <th><label><input name="selection" type="radio" value="<?php echo esc_attr($structures[1]); ?>" <?php checked($structures[1], $permalink_structure); ?> /> <?php _e('Day and name'); ?></label></th>
+ <td><code><?php echo get_option('home') . $blog_prefix . $prefix . '/' . date('Y') . '/' . date('m') . '/' . date('d') . '/' . _x( 'sample-post', 'sample permalink structure' ) . '/'; ?></code></td>
+ </tr>
+ <tr>
+ <th><label><input name="selection" type="radio" value="<?php echo esc_attr($structures[2]); ?>" <?php checked($structures[2], $permalink_structure); ?> /> <?php _e('Month and name'); ?></label></th>
+ <td><code><?php echo get_option('home') . $blog_prefix . $prefix . '/' . date('Y') . '/' . date('m') . '/' . _x( 'sample-post', 'sample permalink structure' ) . '/'; ?></code></td>
+ </tr>
+ <tr>
+ <th><label><input name="selection" type="radio" value="<?php echo esc_attr($structures[3]); ?>" <?php checked($structures[3], $permalink_structure); ?> /> <?php _e('Numeric'); ?></label></th>
+ <td><code><?php echo get_option('home') . $blog_prefix . $prefix . '/' . _x( 'archives', 'sample permalink base' ) . '/123'; ?></code></td>
+ </tr>
+ <tr>
+ <th><label><input name="selection" type="radio" value="<?php echo esc_attr($structures[4]); ?>" <?php checked($structures[4], $permalink_structure); ?> /> <?php _e('Post name'); ?></label></th>
+ <td><code><?php echo get_option('home') . $blog_prefix . $prefix . '/' . _x( 'sample-post', 'sample permalink structure' ) . '/'; ?></code></td>
+ </tr>
+ <tr>
+ <th>
+ <label><input name="selection" id="custom_selection" type="radio" value="custom" <?php checked( !in_array($permalink_structure, $structures) ); ?> />
+ <?php _e('Custom Structure'); ?>
+ </label>
+ </th>
+ <td>
+ <code><?php echo get_option('home') . $blog_prefix; ?></code>
+ <input name="permalink_structure" id="permalink_structure" type="text" value="<?php echo esc_attr($permalink_structure); ?>" class="regular-text code" />
+ </td>
+ </tr>
+</table>
+
+<h3 class="title"><?php _e('Optional'); ?></h3>
+<?php
+$suffix = '';
+if ( ! $is_apache && ! $iis7_permalinks )
+ $suffix = $wp_rewrite->index . '/';
+?>
+<p><?php
+/* translators: %s is a placeholder that must come at the start of the URL path. */
+printf( __('If you like, you may enter custom structures for your category and tag <abbr title="Universal Resource Locator">URL</abbr>s here. For example, using <code>topics</code> as your category base would make your category links like <code>http://example.org/%stopics/uncategorized/</code>. If you leave these blank the defaults will be used.'), $suffix ); ?></p>
+
+<table class="form-table">
+ <tr>
+ <th><label for="category_base"><?php /* translators: prefix for category permalinks */ _e('Category base'); ?></label></th>
+ <td><?php echo $blog_prefix; ?> <input name="category_base" id="category_base" type="text" value="<?php echo esc_attr( $category_base ); ?>" class="regular-text code" /></td>
+ </tr>
+ <tr>
+ <th><label for="tag_base"><?php _e('Tag base'); ?></label></th>
+ <td><?php echo $blog_prefix; ?> <input name="tag_base" id="tag_base" type="text" value="<?php echo esc_attr($tag_base); ?>" class="regular-text code" /></td>
+ </tr>
+ <?php do_settings_fields('permalink', 'optional'); ?>
+</table>
+
+<?php do_settings_sections('permalink'); ?>
+
+<?php submit_button(); ?>
+ </form>
+<?php if ( !is_multisite() ) { ?>
+<?php if ( $iis7_permalinks ) :
+ if ( isset($_POST['submit']) && $permalink_structure && ! $usingpi && ! $writable ) :
+ if ( file_exists($home_path . 'web.config') ) : ?>
+<p><?php _e('If your <code>web.config</code> file were <a href="http://codex.wordpress.org/Changing_File_Permissions">writable</a>, we could do this automatically, but it isn&#8217;t so this is the url rewrite rule you should have in your <code>web.config</code> file. Click in the field and press <kbd>CTRL + a</kbd> to select all. Then insert this rule inside of the <code>/&lt;configuration&gt;/&lt;system.webServer&gt;/&lt;rewrite&gt;/&lt;rules&gt;</code> element in <code>web.config</code> file.') ?></p>
+<form action="options-permalink.php" method="post">
+<?php wp_nonce_field('update-permalink') ?>
+ <p><textarea rows="9" class="large-text readonly" name="rules" id="rules" readonly="readonly"><?php echo esc_textarea( $wp_rewrite->iis7_url_rewrite_rules() ); ?></textarea></p>
+</form>
+<p><?php _e('If you temporarily make your <code>web.config</code> file writable for us to generate rewrite rules automatically, do not forget to revert the permissions after rule has been saved.') ?></p>
+ <?php else : ?>
+<p><?php _e('If the root directory of your site were <a href="http://codex.wordpress.org/Changing_File_Permissions">writable</a>, we could do this automatically, but it isn&#8217;t so this is the url rewrite rule you should have in your <code>web.config</code> file. Create a new file, called <code>web.config</code> in the root directory of your site. Click in the field and press <kbd>CTRL + a</kbd> to select all. Then insert this code into the <code>web.config</code> file.') ?></p>
+<form action="options-permalink.php" method="post">
+<?php wp_nonce_field('update-permalink') ?>
+ <p><textarea rows="18" class="large-text readonly" name="rules" id="rules" readonly="readonly"><?php echo esc_textarea( $wp_rewrite->iis7_url_rewrite_rules(true) ); ?></textarea></p>
+</form>
+<p><?php _e('If you temporarily make your site&#8217;s root directory writable for us to generate the <code>web.config</code> file automatically, do not forget to revert the permissions after the file has been created.') ?></p>
+ <?php endif; ?>
+ <?php endif; ?>
+<?php else :
+ if ( $permalink_structure && ! $usingpi && ! $writable ) : ?>
+<p><?php _e('If your <code>.htaccess</code> file were <a href="http://codex.wordpress.org/Changing_File_Permissions">writable</a>, we could do this automatically, but it isn&#8217;t so these are the mod_rewrite rules you should have in your <code>.htaccess</code> file. Click in the field and press <kbd>CTRL + a</kbd> to select all.') ?></p>
+<form action="options-permalink.php" method="post">
+<?php wp_nonce_field('update-permalink') ?>
+ <p><textarea rows="6" class="large-text readonly" name="rules" id="rules" readonly="readonly"><?php echo esc_textarea( $wp_rewrite->mod_rewrite_rules() ); ?></textarea></p>
+</form>
+ <?php endif; ?>
+<?php endif; ?>
+<?php } // multisite ?>
+
+</div>
+
+<?php require('./admin-footer.php'); ?>
diff --git a/src/wp-admin/options-reading.php b/src/wp-admin/options-reading.php
new file mode 100644
index 0000000000..3ca10df9bb
--- /dev/null
+++ b/src/wp-admin/options-reading.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * Reading settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+$title = __( 'Reading Settings' );
+$parent_file = 'options-general.php';
+
+/**
+ * Display JavaScript on the page.
+ *
+ * @since 3.5.0
+ */
+function options_reading_add_js() {
+?>
+<script type="text/javascript">
+//<![CDATA[
+ jQuery(document).ready(function($){
+ var section = $('#front-static-pages'),
+ staticPage = section.find('input:radio[value="page"]'),
+ selects = section.find('select'),
+ check_disabled = function(){
+ selects.prop( 'disabled', ! staticPage.prop('checked') );
+ };
+ check_disabled();
+ section.find('input:radio').change(check_disabled);
+ });
+//]]>
+</script>
+<?php
+}
+add_action('admin_head', 'options_reading_add_js');
+
+/**
+ * Render the blog charset setting.
+ *
+ * @since 3.5.0
+ */
+function options_reading_blog_charset() {
+ echo '<input name="blog_charset" type="text" id="blog_charset" value="' . esc_attr( get_option( 'blog_charset' ) ) . '" class="regular-text" />';
+ echo '<p class="description">' . __( 'The <a href="http://codex.wordpress.org/Glossary#Character_set">character encoding</a> of your site (UTF-8 is recommended)' ) . '</p>';
+}
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('This screen contains the settings that affect the display of your content.') . '</p>' .
+ '<p>' . sprintf(__('You can choose what&#8217;s displayed on the front page of your site. It can be posts in reverse chronological order (classic blog), or a fixed/static page. To set a static home page, you first need to create two <a href="%s">Pages</a>. One will become the front page, and the other will be where your posts are displayed.'), 'post-new.php?post_type=page') . '</p>' .
+ '<p>' . __('You can also control the display of your content in RSS feeds, including the maximum numbers of posts to display and whether to show full text or a summary.') . '</p>' .
+ '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>',
+) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'site-visibility',
+ 'title' => has_action( 'blog_privacy_selector' ) ? __( 'Site Visibility' ) : __( 'Search Engine Visibility' ),
+ 'content' => '<p>' . __( 'You can choose whether or not your site will be crawled by robots, ping services, and spiders. If you want those services to ignore your site, click the checkbox next to &#8220;Discourage search engines from indexing this site&#8221; and click the Save Changes button at the bottom of the screen. Note that your privacy is not complete; your site is still visible on the web.' ) . '</p>' .
+ '<p>' . __( 'When this setting is in effect, a reminder is shown in the Right Now box of the Dashboard that says, &#8220;Search Engines Discouraged,&#8221; to remind you that your site is not being crawled.' ) . '</p>',
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Settings_Reading_Screen" target="_blank">Documentation on Reading Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include( './admin-header.php' );
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<form method="post" action="options.php">
+<?php
+settings_fields( 'reading' );
+
+if ( ! in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) )
+ add_settings_field( 'blog_charset', __( 'Encoding for pages and feeds' ), 'options_reading_blog_charset', 'reading', 'default', array( 'label_for' => 'blog_charset' ) );
+?>
+
+<?php if ( ! get_pages() ) : ?>
+<input name="show_on_front" type="hidden" value="posts" />
+<table class="form-table">
+<?php
+ if ( 'posts' != get_option( 'show_on_front' ) ) :
+ update_option( 'show_on_front', 'posts' );
+ endif;
+
+else :
+ if ( 'page' == get_option( 'show_on_front' ) && ! get_option( 'page_on_front' ) && ! get_option( 'page_for_posts' ) )
+ update_option( 'show_on_front', 'posts' );
+?>
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><?php _e( 'Front page displays' ); ?></th>
+<td id="front-static-pages"><fieldset><legend class="screen-reader-text"><span><?php _e( 'Front page displays' ); ?></span></legend>
+ <p><label>
+ <input name="show_on_front" type="radio" value="posts" class="tog" <?php checked( 'posts', get_option( 'show_on_front' ) ); ?> />
+ <?php _e( 'Your latest posts' ); ?>
+ </label>
+ </p>
+ <p><label>
+ <input name="show_on_front" type="radio" value="page" class="tog" <?php checked( 'page', get_option( 'show_on_front' ) ); ?> />
+ <?php printf( __( 'A <a href="%s">static page</a> (select below)' ), 'edit.php?post_type=page' ); ?>
+ </label>
+ </p>
+<ul>
+ <li><label for="page_on_front"><?php printf( __( 'Front page: %s' ), wp_dropdown_pages( array( 'name' => 'page_on_front', 'echo' => 0, 'show_option_none' => __( '&mdash; Select &mdash;' ), 'option_none_value' => '0', 'selected' => get_option( 'page_on_front' ) ) ) ); ?></label></li>
+ <li><label for="page_for_posts"><?php printf( __( 'Posts page: %s' ), wp_dropdown_pages( array( 'name' => 'page_for_posts', 'echo' => 0, 'show_option_none' => __( '&mdash; Select &mdash;' ), 'option_none_value' => '0', 'selected' => get_option( 'page_for_posts' ) ) ) ); ?></label></li>
+</ul>
+<?php if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) == get_option( 'page_on_front' ) ) : ?>
+<div id="front-page-warning" class="error inline"><p><?php _e( '<strong>Warning:</strong> these pages should not be the same!' ); ?></p></div>
+<?php endif; ?>
+</fieldset></td>
+</tr>
+<?php endif; ?>
+<tr valign="top">
+<th scope="row"><label for="posts_per_page"><?php _e( 'Blog pages show at most' ); ?></label></th>
+<td>
+<input name="posts_per_page" type="number" step="1" min="1" id="posts_per_page" value="<?php form_option( 'posts_per_page' ); ?>" class="small-text" /> <?php _e( 'posts' ); ?>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="posts_per_rss"><?php _e( 'Syndication feeds show the most recent' ); ?></label></th>
+<td><input name="posts_per_rss" type="number" step="1" min="1" id="posts_per_rss" value="<?php form_option( 'posts_per_rss' ); ?>" class="small-text" /> <?php _e( 'items' ); ?></td>
+</tr>
+<tr valign="top">
+<th scope="row"><?php _e( 'For each article in a feed, show' ); ?> </th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e( 'For each article in a feed, show' ); ?> </span></legend>
+<p><label><input name="rss_use_excerpt" type="radio" value="0" <?php checked( 0, get_option( 'rss_use_excerpt' ) ); ?> /> <?php _e( 'Full text' ); ?></label><br />
+<label><input name="rss_use_excerpt" type="radio" value="1" <?php checked( 1, get_option( 'rss_use_excerpt' ) ); ?> /> <?php _e( 'Summary' ); ?></label></p>
+</fieldset></td>
+</tr>
+
+<tr valign="top" class="option-site-visibility">
+<th scope="row"><?php has_action( 'blog_privacy_selector' ) ? _e( 'Site Visibility' ) : _e( 'Search Engine Visibility' ); ?> </th>
+<td><fieldset><legend class="screen-reader-text"><span><?php has_action( 'blog_privacy_selector' ) ? _e( 'Site Visibility' ) : _e( 'Search Engine Visibility' ); ?> </span></legend>
+<?php if ( has_action( 'blog_privacy_selector' ) ) : ?>
+ <input id="blog-public" type="radio" name="blog_public" value="1" <?php checked('1', get_option('blog_public')); ?> />
+ <label for="blog-public"><?php _e( 'Allow search engines to index this site' );?></label><br/>
+ <input id="blog-norobots" type="radio" name="blog_public" value="0" <?php checked('0', get_option('blog_public')); ?> />
+ <label for="blog-norobots"><?php _e( 'Discourage search engines from indexing this site' ); ?></label>
+ <p class="description"><?php _e( 'Note: Neither of these options blocks access to your site &mdash; it is up to search engines to honor your request.' ); ?></p>
+ <?php do_action('blog_privacy_selector'); ?>
+<?php else : ?>
+ <label for="blog_public"><input name="blog_public" type="checkbox" id="blog_public" value="0" <?php checked( '0', get_option( 'blog_public' ) ); ?> />
+ <?php _e( 'Discourage search engines from indexing this site' ); ?></label>
+ <p class="description"><?php _e( 'It is up to search engines to honor this request.' ); ?></p>
+<?php endif; ?>
+</fieldset></td>
+</tr>
+
+<?php do_settings_fields( 'reading', 'default' ); ?>
+</table>
+
+<?php do_settings_sections( 'reading' ); ?>
+
+<?php submit_button(); ?>
+</form>
+</div>
+<?php include( './admin-footer.php' ); ?>
diff --git a/src/wp-admin/options-writing.php b/src/wp-admin/options-writing.php
new file mode 100644
index 0000000000..8015bae418
--- /dev/null
+++ b/src/wp-admin/options-writing.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * Writing settings administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can( 'manage_options' ) )
+ wp_die( __( 'You do not have sufficient permissions to manage options for this site.' ) );
+
+$title = __('Writing Settings');
+$parent_file = 'options-general.php';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('You can submit content in several different ways; this screen holds the settings for all of them. The top section controls the editor within the dashboard, while the rest control external publishing methods. For more information on any of these methods, use the documentation links.') . '</p>' .
+ '<p>' . __('You must click the Save Changes button at the bottom of the screen for new settings to take effect.') . '</p>',
+) );
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'options-press',
+ 'title' => __('Press This'),
+ 'content' => '<p>' . __('Press This is a bookmarklet that makes it easy to blog about something you come across on the web. You can use it to just grab a link, or to post an excerpt. Press This will even allow you to choose from images included on the page and use them in your post. Just drag the Press This link on this screen to your bookmarks bar in your browser, and you&#8217;ll be on your way to easier content creation. Clicking on it while on another website opens a popup window with all these options.') . '</p>',
+) );
+
+if ( apply_filters( 'enable_post_by_email_configuration', true ) ) {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'options-postemail',
+ 'title' => __( 'Post Via Email' ),
+ 'content' => '<p>' . __( 'Post via email settings allow you to send your WordPress install an email with the content of your post. You must set up a secret e-mail account with POP3 access to use this, and any mail received at this address will be posted, so it&#8217;s a good idea to keep this address very secret.' ) . '</p>',
+ ) );
+}
+
+if ( apply_filters( 'enable_update_services_configuration', true ) ) {
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'options-services',
+ 'title' => __( 'Update Services' ),
+ 'content' => '<p>' . __( 'If desired, WordPress will automatically alert various services of your new posts.' ) . '</p>',
+ ) );
+}
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Settings_Writing_Screen" target="_blank">Documentation on Writing Settings</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include('./admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<form method="post" action="options.php">
+<?php settings_fields('writing'); ?>
+
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><?php _e('Formatting') ?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Formatting') ?></span></legend>
+<label for="use_smilies">
+<input name="use_smilies" type="checkbox" id="use_smilies" value="1" <?php checked('1', get_option('use_smilies')); ?> />
+<?php _e('Convert emoticons like <code>:-)</code> and <code>:-P</code> to graphics on display') ?></label><br />
+<label for="use_balanceTags"><input name="use_balanceTags" type="checkbox" id="use_balanceTags" value="1" <?php checked('1', get_option('use_balanceTags')); ?> /> <?php _e('WordPress should correct invalidly nested XHTML automatically') ?></label>
+</fieldset></td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="default_category"><?php _e('Default Post Category') ?></label></th>
+<td>
+<?php
+wp_dropdown_categories(array('hide_empty' => 0, 'name' => 'default_category', 'orderby' => 'name', 'selected' => get_option('default_category'), 'hierarchical' => true));
+?>
+</td>
+</tr>
+<?php
+$post_formats = get_post_format_strings();
+unset( $post_formats['standard'] );
+?>
+<tr valign="top">
+<th scope="row"><label for="default_post_format"><?php _e('Default Post Format') ?></label></th>
+<td>
+ <select name="default_post_format" id="default_post_format">
+ <option value="0"><?php echo get_post_format_string( 'standard' ); ?></option>
+<?php foreach ( $post_formats as $format_slug => $format_name ): ?>
+ <option<?php selected( get_option( 'default_post_format' ), $format_slug ); ?> value="<?php echo esc_attr( $format_slug ); ?>"><?php echo esc_html( $format_name ); ?></option>
+<?php endforeach; ?>
+ </select>
+</td>
+</tr>
+<?php
+if ( get_option( 'link_manager_enabled' ) ) :
+?>
+<tr valign="top">
+<th scope="row"><label for="default_link_category"><?php _e('Default Link Category') ?></label></th>
+<td>
+<?php
+wp_dropdown_categories(array('hide_empty' => 0, 'name' => 'default_link_category', 'orderby' => 'name', 'selected' => get_option('default_link_category'), 'hierarchical' => true, 'taxonomy' => 'link_category'));
+?>
+</td>
+</tr>
+<?php endif; ?>
+
+<?php
+do_settings_fields('writing', 'default');
+do_settings_fields('writing', 'remote_publishing'); // A deprecated section.
+?>
+</table>
+
+<h3 class="title"><?php _e('Press This') ?></h3>
+<p><?php _e('Press This is a bookmarklet: a little app that runs in your browser and lets you grab bits of the web.');?></p>
+<p><?php _e('Use Press This to clip text, images and videos from any web page. Then edit and add more straight from Press This before you save or publish it in a post on your site.'); ?></p>
+<p><?php _e('Drag-and-drop the following link to your bookmarks bar or right click it and add it to your favorites for a posting shortcut.') ?></p>
+<p class="pressthis"><a onclick="return false;" oncontextmenu="if(window.navigator.userAgent.indexOf('WebKit')!=-1||window.navigator.userAgent.indexOf('MSIE')!=-1){jQuery('.pressthis-code').show().find('textarea').focus().select();return false;}" href="<?php echo htmlspecialchars( get_shortcut_link() ); ?>"><span><?php _e('Press This') ?></span></a></p>
+<div class="pressthis-code" style="display:none;">
+ <p class="description"><?php _e('If your bookmarks toolbar is hidden: copy the code below, open your Bookmarks manager, create new bookmark, type Press This into the name field and paste the code into the URL field.') ?></p>
+ <p><textarea rows="5" cols="120" readonly="readonly"><?php echo htmlspecialchars( get_shortcut_link() ); ?></textarea></p>
+</div>
+
+<?php if ( apply_filters( 'enable_post_by_email_configuration', true ) ) { ?>
+<h3 class="title"><?php _e('Post via e-mail') ?></h3>
+<p><?php printf(__('To post to WordPress by e-mail you must set up a secret e-mail account with POP3 access. Any mail received at this address will be posted, so it&#8217;s a good idea to keep this address very secret. Here are three random strings you could use: <kbd>%s</kbd>, <kbd>%s</kbd>, <kbd>%s</kbd>.'), wp_generate_password(8, false), wp_generate_password(8, false), wp_generate_password(8, false)) ?></p>
+
+<table class="form-table">
+<tr valign="top">
+<th scope="row"><label for="mailserver_url"><?php _e('Mail Server') ?></label></th>
+<td><input name="mailserver_url" type="text" id="mailserver_url" value="<?php form_option('mailserver_url'); ?>" class="regular-text code" />
+<label for="mailserver_port"><?php _e('Port') ?></label>
+<input name="mailserver_port" type="text" id="mailserver_port" value="<?php form_option('mailserver_port'); ?>" class="small-text" />
+</td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="mailserver_login"><?php _e('Login Name') ?></label></th>
+<td><input name="mailserver_login" type="text" id="mailserver_login" value="<?php form_option('mailserver_login'); ?>" class="regular-text ltr" /></td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="mailserver_pass"><?php _e('Password') ?></label></th>
+<td>
+<input name="mailserver_pass" type="text" id="mailserver_pass" value="<?php form_option('mailserver_pass'); ?>" class="regular-text ltr" />
+</td>
+</tr>
+<tr valign="top">
+<th scope="row"><label for="default_email_category"><?php _e('Default Mail Category') ?></label></th>
+<td>
+<?php
+wp_dropdown_categories(array('hide_empty' => 0, 'name' => 'default_email_category', 'orderby' => 'name', 'selected' => get_option('default_email_category'), 'hierarchical' => true));
+?>
+</td>
+</tr>
+<?php do_settings_fields('writing', 'post_via_email'); ?>
+</table>
+<?php } ?>
+
+<?php if ( apply_filters( 'enable_update_services_configuration', true ) ) { ?>
+<h3 class="title"><?php _e('Update Services') ?></h3>
+
+<?php if ( 1 == get_option('blog_public') ) : ?>
+
+<p><label for="ping_sites"><?php _e('When you publish a new post, WordPress automatically notifies the following site update services. For more about this, see <a href="http://codex.wordpress.org/Update_Services">Update Services</a> on the Codex. Separate multiple service <abbr title="Universal Resource Locator">URL</abbr>s with line breaks.') ?></label></p>
+
+<textarea name="ping_sites" id="ping_sites" class="large-text code" rows="3"><?php echo esc_textarea( get_option('ping_sites') ); ?></textarea>
+
+<?php else : ?>
+
+ <p><?php printf(__('WordPress is not notifying any <a href="http://codex.wordpress.org/Update_Services">Update Services</a> because of your site&#8217;s <a href="%s">visibility settings</a>.'), 'options-reading.php'); ?></p>
+
+<?php endif; ?>
+<?php } // multisite ?>
+
+<?php do_settings_sections('writing'); ?>
+
+<?php submit_button(); ?>
+</form>
+</div>
+
+<?php include('./admin-footer.php') ?>
diff --git a/src/wp-admin/options.php b/src/wp-admin/options.php
new file mode 100644
index 0000000000..80a07190df
--- /dev/null
+++ b/src/wp-admin/options.php
@@ -0,0 +1,231 @@
+<?php
+/**
+ * Options Management Administration Screen.
+ *
+ * If accessed directly in a browser this page shows a list of all saved options
+ * along with editable fields for their values. Serialized data is not supported
+ * and there is no way to remove options via this page. It is not linked to from
+ * anywhere else in the admin.
+ *
+ * This file is also the target of the forms in core and custom options pages
+ * that use the Settings API. In this case it saves the new option values
+ * and returns the user to their page of origin.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+$title = __('Settings');
+$this_file = 'options.php';
+$parent_file = 'options-general.php';
+
+wp_reset_vars(array('action', 'option_page'));
+
+$capability = 'manage_options';
+
+if ( empty($option_page) ) // This is for back compat and will eventually be removed.
+ $option_page = 'options';
+else
+ $capability = apply_filters( "option_page_capability_{$option_page}", $capability );
+
+if ( !current_user_can( $capability ) )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+// Handle admin email change requests
+if ( is_multisite() ) {
+ if ( ! empty($_GET[ 'adminhash' ] ) ) {
+ $new_admin_details = get_option( 'adminhash' );
+ $redirect = 'options-general.php?updated=false';
+ if ( is_array( $new_admin_details ) && $new_admin_details[ 'hash' ] == $_GET[ 'adminhash' ] && !empty($new_admin_details[ 'newemail' ]) ) {
+ update_option( 'admin_email', $new_admin_details[ 'newemail' ] );
+ delete_option( 'adminhash' );
+ delete_option( 'new_admin_email' );
+ $redirect = 'options-general.php?updated=true';
+ }
+ wp_redirect( admin_url( $redirect ) );
+ exit;
+ } elseif ( ! empty( $_GET['dismiss'] ) && 'new_admin_email' == $_GET['dismiss'] ) {
+ delete_option( 'adminhash' );
+ delete_option( 'new_admin_email' );
+ wp_redirect( admin_url( 'options-general.php?updated=true' ) );
+ exit;
+ }
+}
+
+if ( is_multisite() && !is_super_admin() && 'update' != $action )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+$whitelist_options = array(
+ 'general' => array( 'blogname', 'blogdescription', 'gmt_offset', 'date_format', 'time_format', 'start_of_week', 'timezone_string' ),
+ 'discussion' => array( 'default_pingback_flag', 'default_ping_status', 'default_comment_status', 'comments_notify', 'moderation_notify', 'comment_moderation', 'require_name_email', 'comment_whitelist', 'comment_max_links', 'moderation_keys', 'blacklist_keys', 'show_avatars', 'avatar_rating', 'avatar_default', 'close_comments_for_old_posts', 'close_comments_days_old', 'thread_comments', 'thread_comments_depth', 'page_comments', 'comments_per_page', 'default_comments_page', 'comment_order', 'comment_registration' ),
+ 'media' => array( 'thumbnail_size_w', 'thumbnail_size_h', 'thumbnail_crop', 'medium_size_w', 'medium_size_h', 'large_size_w', 'large_size_h', 'image_default_size', 'image_default_align', 'image_default_link_type' ),
+ 'reading' => array( 'posts_per_page', 'posts_per_rss', 'rss_use_excerpt', 'show_on_front', 'page_on_front', 'page_for_posts', 'blog_public' ),
+ 'writing' => array( 'use_smilies', 'default_category', 'default_email_category', 'use_balanceTags', 'default_link_category', 'default_post_format' )
+);
+$whitelist_options['misc'] = $whitelist_options['options'] = $whitelist_options['privacy'] = array();
+
+$mail_options = array('mailserver_url', 'mailserver_port', 'mailserver_login', 'mailserver_pass');
+
+if ( ! in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) )
+ $whitelist_options['reading'][] = 'blog_charset';
+
+if ( !is_multisite() ) {
+ if ( !defined( 'WP_SITEURL' ) )
+ $whitelist_options['general'][] = 'siteurl';
+ if ( !defined( 'WP_HOME' ) )
+ $whitelist_options['general'][] = 'home';
+
+ $whitelist_options['general'][] = 'admin_email';
+ $whitelist_options['general'][] = 'users_can_register';
+ $whitelist_options['general'][] = 'default_role';
+
+ $whitelist_options['writing'] = array_merge($whitelist_options['writing'], $mail_options);
+ $whitelist_options['writing'][] = 'ping_sites';
+
+ $whitelist_options['media'][] = 'uploads_use_yearmonth_folders';
+
+ // If upload_url_path and upload_path are both default values, they're locked.
+ if ( get_option( 'upload_url_path' ) || ( get_option('upload_path') != 'wp-content/uploads' && get_option('upload_path') ) ) {
+ $whitelist_options['media'][] = 'upload_path';
+ $whitelist_options['media'][] = 'upload_url_path';
+ }
+} else {
+ $whitelist_options['general'][] = 'new_admin_email';
+ $whitelist_options['general'][] = 'WPLANG';
+
+ if ( apply_filters( 'enable_post_by_email_configuration', true ) )
+ $whitelist_options['writing'] = array_merge($whitelist_options['writing'], $mail_options);
+}
+
+$whitelist_options = apply_filters( 'whitelist_options', $whitelist_options );
+
+/*
+ * If $_GET['action'] == 'update' we are saving settings sent from a settings page
+ */
+if ( 'update' == $action ) {
+ if ( 'options' == $option_page && !isset( $_POST['option_page'] ) ) { // This is for back compat and will eventually be removed.
+ $unregistered = true;
+ check_admin_referer( 'update-options' );
+ } else {
+ $unregistered = false;
+ check_admin_referer( $option_page . '-options' );
+ }
+
+ if ( !isset( $whitelist_options[ $option_page ] ) )
+ wp_die( __( '<strong>ERROR</strong>: options page not found.' ) );
+
+ if ( 'options' == $option_page ) {
+ if ( is_multisite() && ! is_super_admin() )
+ wp_die( __( 'You do not have sufficient permissions to modify unregistered settings for this site.' ) );
+ $options = explode( ',', wp_unslash( $_POST[ 'page_options' ] ) );
+ } else {
+ $options = $whitelist_options[ $option_page ];
+ }
+
+ // Handle custom date/time formats
+ if ( 'general' == $option_page ) {
+ if ( !empty($_POST['date_format']) && isset($_POST['date_format_custom']) && '\c\u\s\t\o\m' == wp_unslash( $_POST['date_format'] ) )
+ $_POST['date_format'] = $_POST['date_format_custom'];
+ if ( !empty($_POST['time_format']) && isset($_POST['time_format_custom']) && '\c\u\s\t\o\m' == wp_unslash( $_POST['time_format'] ) )
+ $_POST['time_format'] = $_POST['time_format_custom'];
+ // Map UTC+- timezones to gmt_offsets and set timezone_string to empty.
+ if ( !empty($_POST['timezone_string']) && preg_match('/^UTC[+-]/', $_POST['timezone_string']) ) {
+ $_POST['gmt_offset'] = $_POST['timezone_string'];
+ $_POST['gmt_offset'] = preg_replace('/UTC\+?/', '', $_POST['gmt_offset']);
+ $_POST['timezone_string'] = '';
+ }
+ }
+
+ if ( $options ) {
+ foreach ( $options as $option ) {
+ if ( $unregistered )
+ _deprecated_argument( 'options.php', '2.7', sprintf( __( 'The <code>%1$s</code> setting is unregistered. Unregistered settings are deprecated. See http://codex.wordpress.org/Settings_API' ), $option, $option_page ) );
+
+ $option = trim( $option );
+ $value = null;
+ if ( isset( $_POST[ $option ] ) ) {
+ $value = $_POST[ $option ];
+ if ( ! is_array( $value ) )
+ $value = trim( $value );
+ $value = wp_unslash( $value );
+ }
+ update_option( $option, $value );
+ }
+ }
+
+ /**
+ * Handle settings errors and return to options page
+ */
+ // If no settings errors were registered add a general 'updated' message.
+ if ( !count( get_settings_errors() ) )
+ add_settings_error('general', 'settings_updated', __('Settings saved.'), 'updated');
+ set_transient('settings_errors', get_settings_errors(), 30);
+
+ /**
+ * Redirect back to the settings page that was submitted
+ */
+ $goback = add_query_arg( 'settings-updated', 'true', wp_get_referer() );
+ wp_redirect( $goback );
+ exit;
+}
+
+include('./admin-header.php'); ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+ <h2><?php esc_html_e('All Settings'); ?></h2>
+ <form name="form" action="options.php" method="post" id="all-options">
+ <?php wp_nonce_field('options-options') ?>
+ <input type="hidden" name="action" value="update" />
+ <input type='hidden' name='option_page' value='options' />
+ <table class="form-table">
+<?php
+$options = $wpdb->get_results( "SELECT * FROM $wpdb->options ORDER BY option_name" );
+
+foreach ( (array) $options as $option ) :
+ $disabled = false;
+ if ( $option->option_name == '' )
+ continue;
+ if ( is_serialized( $option->option_value ) ) {
+ if ( is_serialized_string( $option->option_value ) ) {
+ // this is a serialized string, so we should display it
+ $value = maybe_unserialize( $option->option_value );
+ $options_to_update[] = $option->option_name;
+ $class = 'all-options';
+ } else {
+ $value = 'SERIALIZED DATA';
+ $disabled = true;
+ $class = 'all-options disabled';
+ }
+ } else {
+ $value = $option->option_value;
+ $options_to_update[] = $option->option_name;
+ $class = 'all-options';
+ }
+ $name = esc_attr( $option->option_name );
+ echo "
+<tr>
+ <th scope='row'><label for='$name'>" . esc_html( $option->option_name ) . "</label></th>
+<td>";
+ if ( strpos( $value, "\n" ) !== false )
+ echo "<textarea class='$class' name='$name' id='$name' cols='30' rows='5'>" . esc_textarea( $value ) . "</textarea>";
+ else
+ echo "<input class='regular-text $class' type='text' name='$name' id='$name' value='" . esc_attr( $value ) . "'" . disabled( $disabled, true, false ) . " />";
+ echo "</td>
+</tr>";
+endforeach;
+?>
+ </table>
+
+<input type="hidden" name="page_options" value="<?php echo esc_attr( implode( ',', $options_to_update ) ); ?>" />
+
+<?php submit_button( __( 'Save Changes' ), 'primary', 'Update' ); ?>
+
+ </form>
+</div>
+
+<?php
+include('./admin-footer.php');
diff --git a/src/wp-admin/plugin-editor.php b/src/wp-admin/plugin-editor.php
new file mode 100644
index 0000000000..2167c1ac74
--- /dev/null
+++ b/src/wp-admin/plugin-editor.php
@@ -0,0 +1,265 @@
+<?php
+/**
+ * Edit plugin editor administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( is_multisite() && ! is_network_admin() ) {
+ wp_redirect( network_admin_url( 'plugin-editor.php' ) );
+ exit();
+}
+
+if ( !current_user_can('edit_plugins') )
+ wp_die( __('You do not have sufficient permissions to edit plugins for this site.') );
+
+$title = __("Edit Plugins");
+$parent_file = 'plugins.php';
+
+wp_reset_vars( array( 'action', 'error', 'file', 'plugin' ) );
+
+$plugins = get_plugins();
+
+if ( empty($plugins) )
+ wp_die( __('There are no plugins installed on this site.') );
+
+if ( $file ) {
+ $plugin = $file;
+} elseif ( empty( $plugin ) ) {
+ $plugin = array_keys($plugins);
+ $plugin = $plugin[0];
+}
+
+$plugin_files = get_plugin_files($plugin);
+
+if ( empty($file) )
+ $file = $plugin_files[0];
+
+$file = validate_file_to_edit($file, $plugin_files);
+$real_file = WP_PLUGIN_DIR . '/' . $file;
+$scrollto = isset($_REQUEST['scrollto']) ? (int) $_REQUEST['scrollto'] : 0;
+
+switch ( $action ) {
+
+case 'update':
+
+ check_admin_referer('edit-plugin_' . $file);
+
+ $newcontent = wp_unslash( $_POST['newcontent'] );
+ if ( is_writeable($real_file) ) {
+ $f = fopen($real_file, 'w+');
+ fwrite($f, $newcontent);
+ fclose($f);
+
+ $network_wide = is_plugin_active_for_network( $file );
+
+ // Deactivate so we can test it.
+ if ( is_plugin_active($file) || isset($_POST['phperror']) ) {
+ if ( is_plugin_active($file) )
+ deactivate_plugins($file, true);
+
+ if ( ! is_network_admin() )
+ update_option( 'recently_activated', array( $file => time() ) + (array) get_option( 'recently_activated' ) );
+
+ wp_redirect(add_query_arg('_wpnonce', wp_create_nonce('edit-plugin-test_' . $file), "plugin-editor.php?file=$file&liveupdate=1&scrollto=$scrollto&networkwide=" . $network_wide));
+ exit;
+ }
+ wp_redirect( self_admin_url("plugin-editor.php?file=$file&a=te&scrollto=$scrollto") );
+ } else {
+ wp_redirect( self_admin_url("plugin-editor.php?file=$file&scrollto=$scrollto") );
+ }
+ exit;
+
+break;
+
+default:
+
+ if ( isset($_GET['liveupdate']) ) {
+ check_admin_referer('edit-plugin-test_' . $file);
+
+ $error = validate_plugin($file);
+ if ( is_wp_error($error) )
+ wp_die( $error );
+
+ if ( ( ! empty( $_GET['networkwide'] ) && ! is_plugin_active_for_network($file) ) || ! is_plugin_active($file) )
+ activate_plugin($file, "plugin-editor.php?file=$file&phperror=1", ! empty( $_GET['networkwide'] ) ); // we'll override this later if the plugin can be included without fatal error
+
+ wp_redirect( self_admin_url("plugin-editor.php?file=$file&a=te&scrollto=$scrollto") );
+ exit;
+ }
+
+ // List of allowable extensions
+ $editable_extensions = array('php', 'txt', 'text', 'js', 'css', 'html', 'htm', 'xml', 'inc', 'include');
+ $editable_extensions = (array) apply_filters('editable_extensions', $editable_extensions);
+
+ if ( ! is_file($real_file) ) {
+ wp_die(sprintf('<p>%s</p>', __('No such file exists! Double check the name and try again.')));
+ } else {
+ // Get the extension of the file
+ if ( preg_match('/\.([^.]+)$/', $real_file, $matches) ) {
+ $ext = strtolower($matches[1]);
+ // If extension is not in the acceptable list, skip it
+ if ( !in_array( $ext, $editable_extensions) )
+ wp_die(sprintf('<p>%s</p>', __('Files of this type are not editable.')));
+ }
+ }
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' =>
+ '<p>' . __('You can use the editor to make changes to any of your plugins&#8217; individual PHP files. Be aware that if you make changes, plugins updates will overwrite your customizations.') . '</p>' .
+ '<p>' . __('Choose a plugin to edit from the menu in the upper right and click the Select button. Click once on any file name to load it in the editor, and make your changes. Don&#8217;t forget to save your changes (Update File) when you&#8217;re finished.') . '</p>' .
+ '<p>' . __('The Documentation menu below the editor lists the PHP functions recognized in the plugin file. Clicking Look Up takes you to a web page about that particular function.') . '</p>' .
+ '<p id="newcontent-description">' . __('In the editing area the Tab key enters a tab character. To move below this area by pressing Tab, press the Esc key followed by the Tab key.') . '</p>' .
+ '<p>' . __('If you want to make changes but don&#8217;t want them to be overwritten when the plugin is updated, you may be ready to think about writing your own plugin. For information on how to edit plugins, write your own from scratch, or just better understand their anatomy, check out the links below.') . '</p>' .
+ ( is_network_admin() ? '<p>' . __('Any edits to files from this screen will be reflected on all sites in the network.') . '</p>' : '' )
+ ) );
+
+ get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Plugins_Editor_Screen" target="_blank">Documentation on Editing Plugins</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Writing_a_Plugin" target="_blank">Documentation on Writing Plugins</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+ );
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ update_recently_edited(WP_PLUGIN_DIR . '/' . $file);
+
+ $content = file_get_contents( $real_file );
+
+ if ( '.php' == substr( $real_file, strrpos( $real_file, '.' ) ) ) {
+ $functions = wp_doc_link_parse( $content );
+
+ if ( !empty($functions) ) {
+ $docs_select = '<select name="docs-list" id="docs-list">';
+ $docs_select .= '<option value="">' . __( 'Function Name&hellip;' ) . '</option>';
+ foreach ( $functions as $function) {
+ $docs_select .= '<option value="' . esc_attr( $function ) . '">' . esc_html( $function ) . '()</option>';
+ }
+ $docs_select .= '</select>';
+ }
+ }
+
+ $content = esc_textarea( $content );
+ ?>
+<?php if (isset($_GET['a'])) : ?>
+ <div id="message" class="updated"><p><?php _e('File edited successfully.') ?></p></div>
+<?php elseif (isset($_GET['phperror'])) : ?>
+ <div id="message" class="updated"><p><?php _e('This plugin has been deactivated because your changes resulted in a <strong>fatal error</strong>.') ?></p>
+ <?php
+ if ( wp_verify_nonce($_GET['_error_nonce'], 'plugin-activation-error_' . $file) ) { ?>
+ <iframe style="border:0" width="100%" height="70px" src="<?php bloginfo('wpurl'); ?>/wp-admin/plugins.php?action=error_scrape&amp;plugin=<?php echo esc_attr($file); ?>&amp;_wpnonce=<?php echo esc_attr($_GET['_error_nonce']); ?>"></iframe>
+ <?php } ?>
+</div>
+<?php endif; ?>
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<div class="fileedit-sub">
+<div class="alignleft">
+<big><?php
+ if ( is_plugin_active($plugin) ) {
+ if ( is_writeable($real_file) )
+ echo sprintf(__('Editing <strong>%s</strong> (active)'), $file);
+ else
+ echo sprintf(__('Browsing <strong>%s</strong> (active)'), $file);
+ } else {
+ if ( is_writeable($real_file) )
+ echo sprintf(__('Editing <strong>%s</strong> (inactive)'), $file);
+ else
+ echo sprintf(__('Browsing <strong>%s</strong> (inactive)'), $file);
+ }
+ ?></big>
+</div>
+<div class="alignright">
+ <form action="plugin-editor.php" method="post">
+ <strong><label for="plugin"><?php _e('Select plugin to edit:'); ?> </label></strong>
+ <select name="plugin" id="plugin">
+<?php
+ foreach ( $plugins as $plugin_key => $a_plugin ) {
+ $plugin_name = $a_plugin['Name'];
+ if ( $plugin_key == $plugin )
+ $selected = " selected='selected'";
+ else
+ $selected = '';
+ $plugin_name = esc_attr($plugin_name);
+ $plugin_key = esc_attr($plugin_key);
+ echo "\n\t<option value=\"$plugin_key\" $selected>$plugin_name</option>";
+ }
+?>
+ </select>
+ <?php submit_button( __( 'Select' ), 'button', 'Submit', false ); ?>
+ </form>
+</div>
+<br class="clear" />
+</div>
+
+<div id="templateside">
+ <h3><?php _e('Plugin Files'); ?></h3>
+
+ <ul>
+<?php
+foreach ( $plugin_files as $plugin_file ) :
+ // Get the extension of the file
+ if ( preg_match('/\.([^.]+)$/', $plugin_file, $matches) ) {
+ $ext = strtolower($matches[1]);
+ // If extension is not in the acceptable list, skip it
+ if ( !in_array( $ext, $editable_extensions ) )
+ continue;
+ } else {
+ // No extension found
+ continue;
+ }
+?>
+ <li<?php echo $file == $plugin_file ? ' class="highlight"' : ''; ?>><a href="plugin-editor.php?file=<?php echo urlencode( $plugin_file ) ?>&amp;plugin=<?php echo urlencode( $plugin ) ?>"><?php echo $plugin_file ?></a></li>
+<?php endforeach; ?>
+ </ul>
+</div>
+<form name="template" id="template" action="plugin-editor.php" method="post">
+ <?php wp_nonce_field('edit-plugin_' . $file) ?>
+ <div><textarea cols="70" rows="25" name="newcontent" id="newcontent" aria-describedby="newcontent-description"><?php echo $content; ?></textarea>
+ <input type="hidden" name="action" value="update" />
+ <input type="hidden" name="file" value="<?php echo esc_attr($file) ?>" />
+ <input type="hidden" name="plugin" value="<?php echo esc_attr($plugin) ?>" />
+ <input type="hidden" name="scrollto" id="scrollto" value="<?php echo $scrollto; ?>" />
+ </div>
+ <?php if ( !empty( $docs_select ) ) : ?>
+ <div id="documentation" class="hide-if-no-js"><label for="docs-list"><?php _e('Documentation:') ?></label> <?php echo $docs_select ?> <input type="button" class="button" value="<?php esc_attr_e( 'Look Up' ) ?> " onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'http://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&amp;locale=<?php echo urlencode( get_locale() ) ?>&amp;version=<?php echo urlencode( $wp_version ) ?>&amp;redirect=true'); }" /></div>
+ <?php endif; ?>
+<?php if ( is_writeable($real_file) ) : ?>
+ <?php if ( in_array( $file, (array) get_option( 'active_plugins', array() ) ) ) { ?>
+ <p><?php _e('<strong>Warning:</strong> Making changes to active plugins is not recommended. If your changes cause a fatal error, the plugin will be automatically deactivated.'); ?></p>
+ <?php } ?>
+ <p class="submit">
+ <?php
+ if ( isset($_GET['phperror']) ) {
+ echo "<input type='hidden' name='phperror' value='1' />";
+ submit_button( __( 'Update File and Attempt to Reactivate' ), 'primary', 'submit', false );
+ } else {
+ submit_button( __( 'Update File' ), 'primary', 'submit', false );
+ }
+ ?>
+ </p>
+<?php else : ?>
+ <p><em><?php _e('You need to make this file writable before you can save your changes. See <a href="http://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>
+<?php endif; ?>
+</form>
+<br class="clear" />
+</div>
+<script type="text/javascript">
+jQuery(document).ready(function($){
+ $('#template').submit(function(){ $('#scrollto').val( $('#newcontent').scrollTop() ); });
+ $('#newcontent').scrollTop( $('#scrollto').val() );
+});
+</script>
+<?php
+ break;
+}
+include(ABSPATH . "wp-admin/admin-footer.php");
diff --git a/src/wp-admin/plugin-install.php b/src/wp-admin/plugin-install.php
new file mode 100644
index 0000000000..25470d61a1
--- /dev/null
+++ b/src/wp-admin/plugin-install.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Install plugin administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+// TODO route this pages via a specific iframe handler instead of the do_action below
+if ( !defined( 'IFRAME_REQUEST' ) && isset( $_GET['tab'] ) && ( 'plugin-information' == $_GET['tab'] ) )
+ define( 'IFRAME_REQUEST', true );
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can('install_plugins') )
+ wp_die(__('You do not have sufficient permissions to install plugins on this site.'));
+
+if ( is_multisite() && ! is_network_admin() ) {
+ wp_redirect( network_admin_url( 'plugin-install.php' ) );
+ exit();
+}
+
+$wp_list_table = _get_list_table('WP_Plugin_Install_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+$wp_list_table->prepare_items();
+
+$title = __('Install Plugins');
+$parent_file = 'plugins.php';
+
+wp_enqueue_script( 'plugin-install' );
+if ( 'plugin-information' != $tab )
+ add_thickbox();
+
+$body_id = $tab;
+
+do_action('install_plugins_pre_' . $tab); //Used to override the general interface, Eg, install or plugin information.
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . sprintf(__('Plugins hook into WordPress to extend its functionality with custom features. Plugins are developed independently from the core WordPress application by thousands of developers all over the world. All plugins in the official <a href="%s" target="_blank">WordPress.org Plugin Directory</a> are compatible with the license WordPress uses. You can find new plugins to install by searching or browsing the Directory right here in your own Plugins section.'), 'http://wordpress.org/plugins/') . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'adding-plugins',
+'title' => __('Adding Plugins'),
+'content' =>
+ '<p>' . __('If you know what you&#8217;re looking for, Search is your best bet. The Search screen has options to search the WordPress.org Plugin Directory for a particular Term, Author, or Tag. You can also search the directory by selecting popular tags. Tags in larger type mean more plugins have been labeled with that tag.') . '</p>' .
+ '<p>' . __('If you just want to get an idea of what&#8217;s available, you can browse Featured, Popular, and Newest plugins by using the links in the upper left of the screen. These sections rotate regularly.') . '</p>' .
+ '<p>' . __('You can also browse a user&#8217;s favorite plugins, by using the Favorites link in the upper left of the screen and entering their WordPress.org username.') . '</p>' .
+ '<p>' . __('If you want to install a plugin that you&#8217;ve downloaded elsewhere, click the Upload link in the upper left. You will be prompted to upload the .zip package, and once uploaded, you can activate the new plugin.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Plugins_Add_New_Screen" target="_blank">Documentation on Installing Plugins</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include(ABSPATH . 'wp-admin/admin-header.php');
+?>
+<div class="wrap">
+<?php screen_icon( 'plugins' ); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<?php $wp_list_table->views(); ?>
+
+<br class="clear" />
+<?php do_action('install_plugins_' . $tab, $paged); ?>
+</div>
+<?php
+include(ABSPATH . 'wp-admin/admin-footer.php');
diff --git a/src/wp-admin/plugins.php b/src/wp-admin/plugins.php
new file mode 100644
index 0000000000..c371b6410f
--- /dev/null
+++ b/src/wp-admin/plugins.php
@@ -0,0 +1,437 @@
+<?php
+/**
+ * Plugins administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can('activate_plugins') )
+ wp_die( __( 'You do not have sufficient permissions to manage plugins for this site.' ) );
+
+$wp_list_table = _get_list_table('WP_Plugins_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+
+$action = $wp_list_table->current_action();
+
+$plugin = isset($_REQUEST['plugin']) ? $_REQUEST['plugin'] : '';
+$s = isset($_REQUEST['s']) ? urlencode($_REQUEST['s']) : '';
+
+// Clean up request URI from temporary args for screen options/paging uri's to work as expected.
+$_SERVER['REQUEST_URI'] = remove_query_arg(array('error', 'deleted', 'activate', 'activate-multi', 'deactivate', 'deactivate-multi', '_error_nonce'), $_SERVER['REQUEST_URI']);
+
+if ( $action ) {
+
+ switch ( $action ) {
+ case 'activate':
+ if ( ! current_user_can('activate_plugins') )
+ wp_die(__('You do not have sufficient permissions to activate plugins for this site.'));
+
+ if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) {
+ wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ }
+
+ check_admin_referer('activate-plugin_' . $plugin);
+
+ $result = activate_plugin($plugin, self_admin_url('plugins.php?error=true&plugin=' . $plugin), is_network_admin() );
+ if ( is_wp_error( $result ) ) {
+ if ( 'unexpected_output' == $result->get_error_code() ) {
+ $redirect = self_admin_url('plugins.php?error=true&charsout=' . strlen($result->get_error_data()) . '&plugin=' . $plugin . "&plugin_status=$status&paged=$page&s=$s");
+ wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect));
+ exit;
+ } else {
+ wp_die($result);
+ }
+ }
+
+ if ( ! is_network_admin() ) {
+ $recent = (array) get_option( 'recently_activated' );
+ unset( $recent[ $plugin ] );
+ update_option( 'recently_activated', $recent );
+ }
+
+ if ( isset($_GET['from']) && 'import' == $_GET['from'] ) {
+ wp_redirect( self_admin_url("import.php?import=" . str_replace('-importer', '', dirname($plugin))) ); // overrides the ?error=true one above and redirects to the Imports page, stripping the -importer suffix
+ } else {
+ wp_redirect( self_admin_url("plugins.php?activate=true&plugin_status=$status&paged=$page&s=$s") ); // overrides the ?error=true one above
+ }
+ exit;
+ break;
+ case 'activate-selected':
+ if ( ! current_user_can('activate_plugins') )
+ wp_die(__('You do not have sufficient permissions to activate plugins for this site.'));
+
+ check_admin_referer('bulk-plugins');
+
+ $plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+
+ // Only activate plugins which are not already active.
+ if ( is_network_admin() ) {
+ foreach ( $plugins as $i => $plugin ) {
+ if ( is_plugin_active_for_network( $plugin ) )
+ unset( $plugins[ $i ] );
+ }
+ } else {
+ foreach ( $plugins as $i => $plugin ) {
+ if ( is_plugin_active( $plugin ) || is_network_only_plugin( $plugin ) )
+ unset( $plugins[ $i ] );
+ }
+ }
+
+ if ( empty($plugins) ) {
+ wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ }
+
+ activate_plugins($plugins, self_admin_url('plugins.php?error=true'), is_network_admin() );
+
+ if ( ! is_network_admin() ) {
+ $recent = (array) get_option('recently_activated' );
+ foreach ( $plugins as $plugin )
+ unset( $recent[ $plugin ] );
+ update_option( 'recently_activated', $recent );
+ }
+
+ wp_redirect( self_admin_url("plugins.php?activate-multi=true&plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ break;
+ case 'update-selected' :
+
+ check_admin_referer( 'bulk-plugins' );
+
+ if ( isset( $_GET['plugins'] ) )
+ $plugins = explode( ',', $_GET['plugins'] );
+ elseif ( isset( $_POST['checked'] ) )
+ $plugins = (array) $_POST['checked'];
+ else
+ $plugins = array();
+
+ $title = __( 'Update Plugins' );
+ $parent_file = 'plugins.php';
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ echo '<div class="wrap">';
+ screen_icon();
+ echo '<h2>' . esc_html( $title ) . '</h2>';
+
+ $url = self_admin_url('update.php?action=update-selected&amp;plugins=' . urlencode( join(',', $plugins) ));
+ $url = wp_nonce_url($url, 'bulk-update-plugins');
+
+ echo "<iframe src='$url' style='width: 100%; height:100%; min-height:850px;'></iframe>";
+ echo '</div>';
+ require_once(ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ break;
+ case 'error_scrape':
+ if ( ! current_user_can('activate_plugins') )
+ wp_die(__('You do not have sufficient permissions to activate plugins for this site.'));
+
+ check_admin_referer('plugin-activation-error_' . $plugin);
+
+ $valid = validate_plugin($plugin);
+ if ( is_wp_error($valid) )
+ wp_die($valid);
+
+ if ( ! WP_DEBUG ) {
+ error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
+ }
+
+ @ini_set('display_errors', true); //Ensure that Fatal errors are displayed.
+ // Go back to "sandbox" scope so we get the same errors as before
+ function plugin_sandbox_scrape( $plugin ) {
+ include( WP_PLUGIN_DIR . '/' . $plugin );
+ }
+ plugin_sandbox_scrape( $plugin );
+ do_action('activate_' . $plugin);
+ exit;
+ break;
+ case 'deactivate':
+ if ( ! current_user_can('activate_plugins') )
+ wp_die(__('You do not have sufficient permissions to deactivate plugins for this site.'));
+
+ check_admin_referer('deactivate-plugin_' . $plugin);
+
+ if ( ! is_network_admin() && is_plugin_active_for_network( $plugin ) ) {
+ wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ }
+
+ deactivate_plugins( $plugin, false, is_network_admin() );
+ if ( ! is_network_admin() )
+ update_option( 'recently_activated', array( $plugin => time() ) + (array) get_option( 'recently_activated' ) );
+ if ( headers_sent() )
+ echo "<meta http-equiv='refresh' content='" . esc_attr( "0;url=plugins.php?deactivate=true&plugin_status=$status&paged=$page&s=$s" ) . "' />";
+ else
+ wp_redirect( self_admin_url("plugins.php?deactivate=true&plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ break;
+ case 'deactivate-selected':
+ if ( ! current_user_can('activate_plugins') )
+ wp_die(__('You do not have sufficient permissions to deactivate plugins for this site.'));
+
+ check_admin_referer('bulk-plugins');
+
+ $plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
+ // Do not deactivate plugins which are already deactivated.
+ if ( is_network_admin() ) {
+ $plugins = array_filter( $plugins, 'is_plugin_active_for_network' );
+ } else {
+ $plugins = array_filter( $plugins, 'is_plugin_active' );
+ $plugins = array_diff( $plugins, array_filter( $plugins, 'is_plugin_active_for_network' ) );
+ }
+ if ( empty($plugins) ) {
+ wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ }
+
+ deactivate_plugins( $plugins, false, is_network_admin() );
+
+ if ( ! is_network_admin() ) {
+ $deactivated = array();
+ foreach ( $plugins as $plugin )
+ $deactivated[ $plugin ] = time();
+ update_option( 'recently_activated', $deactivated + (array) get_option( 'recently_activated' ) );
+ }
+
+ wp_redirect( self_admin_url("plugins.php?deactivate-multi=true&plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ break;
+ case 'delete-selected':
+ if ( ! current_user_can('delete_plugins') )
+ wp_die(__('You do not have sufficient permissions to delete plugins for this site.'));
+
+ check_admin_referer('bulk-plugins');
+
+ //$_POST = from the plugin form; $_GET = from the FTP details screen.
+ $plugins = isset( $_REQUEST['checked'] ) ? (array) $_REQUEST['checked'] : array();
+ if ( empty( $plugins ) ) {
+ wp_redirect( self_admin_url("plugins.php?plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ }
+
+ $plugins = array_filter($plugins, 'is_plugin_inactive'); // Do not allow to delete Activated plugins.
+ if ( empty( $plugins ) ) {
+ wp_redirect( self_admin_url( "plugins.php?error=true&main=true&plugin_status=$status&paged=$page&s=$s" ) );
+ exit;
+ }
+
+ include(ABSPATH . 'wp-admin/update.php');
+
+ $parent_file = 'plugins.php';
+
+ if ( ! isset($_REQUEST['verify-delete']) ) {
+ wp_enqueue_script('jquery');
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+ ?>
+ <div class="wrap">
+ <?php
+ $files_to_delete = $plugin_info = array();
+ $have_non_network_plugins = false;
+ foreach ( (array) $plugins as $plugin ) {
+ if ( '.' == dirname($plugin) ) {
+ $files_to_delete[] = WP_PLUGIN_DIR . '/' . $plugin;
+ if( $data = get_plugin_data(WP_PLUGIN_DIR . '/' . $plugin) ) {
+ $plugin_info[ $plugin ] = $data;
+ $plugin_info[ $plugin ]['is_uninstallable'] = is_uninstallable_plugin( $plugin );
+ if ( ! $plugin_info[ $plugin ]['Network'] )
+ $have_non_network_plugins = true;
+ }
+ } else {
+ // Locate all the files in that folder
+ $files = list_files( WP_PLUGIN_DIR . '/' . dirname($plugin) );
+ if ( $files ) {
+ $files_to_delete = array_merge($files_to_delete, $files);
+ }
+ // Get plugins list from that folder
+ if ( $folder_plugins = get_plugins( '/' . dirname($plugin)) ) {
+ foreach( $folder_plugins as $plugin_file => $data ) {
+ $plugin_info[ $plugin_file ] = _get_plugin_data_markup_translate( $plugin_file, $data );
+ $plugin_info[ $plugin_file ]['is_uninstallable'] = is_uninstallable_plugin( $plugin );
+ if ( ! $plugin_info[ $plugin_file ]['Network'] )
+ $have_non_network_plugins = true;
+ }
+ }
+ }
+ }
+ screen_icon();
+ $plugins_to_delete = count( $plugin_info );
+ echo '<h2>' . _n( 'Delete Plugin', 'Delete Plugins', $plugins_to_delete ) . '</h2>';
+ ?>
+ <?php if ( $have_non_network_plugins && is_network_admin() ) : ?>
+ <div class="error"><p><strong><?php _e( 'Caution:' ); ?></strong> <?php echo _n( 'This plugin may be active on other sites in the network.', 'These plugins may be active on other sites in the network.', $plugins_to_delete ); ?></p></div>
+ <?php endif; ?>
+ <p><?php echo _n( 'You are about to remove the following plugin:', 'You are about to remove the following plugins:', $plugins_to_delete ); ?></p>
+ <ul class="ul-disc">
+ <?php
+ $data_to_delete = false;
+ foreach ( $plugin_info as $plugin ) {
+ if ( $plugin['is_uninstallable'] ) {
+ /* translators: 1: plugin name, 2: plugin author */
+ echo '<li>', sprintf( __( '<strong>%1$s</strong> by <em>%2$s</em> (will also <strong>delete its data</strong>)' ), esc_html($plugin['Name']), esc_html($plugin['AuthorName']) ), '</li>';
+ $data_to_delete = true;
+ } else {
+ /* translators: 1: plugin name, 2: plugin author */
+ echo '<li>', sprintf( __('<strong>%1$s</strong> by <em>%2$s</em>' ), esc_html($plugin['Name']), esc_html($plugin['AuthorName']) ), '</li>';
+ }
+ }
+ ?>
+ </ul>
+ <p><?php
+ if ( $data_to_delete )
+ _e('Are you sure you wish to delete these files and data?');
+ else
+ _e('Are you sure you wish to delete these files?');
+ ?></p>
+ <form method="post" action="<?php echo esc_url($_SERVER['REQUEST_URI']); ?>" style="display:inline;">
+ <input type="hidden" name="verify-delete" value="1" />
+ <input type="hidden" name="action" value="delete-selected" />
+ <?php
+ foreach ( (array) $plugins as $plugin )
+ echo '<input type="hidden" name="checked[]" value="' . esc_attr($plugin) . '" />';
+ ?>
+ <?php wp_nonce_field('bulk-plugins') ?>
+ <?php submit_button( $data_to_delete ? __( 'Yes, Delete these files and data' ) : __( 'Yes, Delete these files' ), 'button', 'submit', false ); ?>
+ </form>
+ <form method="post" action="<?php echo esc_url(wp_get_referer()); ?>" style="display:inline;">
+ <?php submit_button( __( 'No, Return me to the plugin list' ), 'button', 'submit', false ); ?>
+ </form>
+
+ <p><a href="#" onclick="jQuery('#files-list').toggle(); return false;"><?php _e('Click to view entire list of files which will be deleted'); ?></a></p>
+ <div id="files-list" style="display:none;">
+ <ul class="code">
+ <?php
+ foreach ( (array)$files_to_delete as $file )
+ echo '<li>' . esc_html(str_replace(WP_PLUGIN_DIR, '', $file)) . '</li>';
+ ?>
+ </ul>
+ </div>
+ </div>
+ <?php
+ require_once(ABSPATH . 'wp-admin/admin-footer.php');
+ exit;
+ } //Endif verify-delete
+ $delete_result = delete_plugins($plugins);
+
+ set_transient('plugins_delete_result_' . $user_ID, $delete_result); //Store the result in a cache rather than a URL param due to object type & length
+ wp_redirect( self_admin_url("plugins.php?deleted=true&plugin_status=$status&paged=$page&s=$s") );
+ exit;
+ break;
+ case 'clear-recent-list':
+ if ( ! is_network_admin() )
+ update_option( 'recently_activated', array() );
+ break;
+ }
+}
+
+$wp_list_table->prepare_items();
+
+wp_enqueue_script('plugin-install');
+add_thickbox();
+
+add_screen_option( 'per_page', array('label' => _x( 'Plugins', 'plugins per page (screen options)' ), 'default' => 999 ) );
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __('Plugins extend and expand the functionality of WordPress. Once a plugin is installed, you may activate it or deactivate it here.') . '</p>' .
+ '<p>' . sprintf(__('You can find additional plugins for your site by using the <a href="%1$s">Plugin Browser/Installer</a> functionality or by browsing the <a href="%2$s" target="_blank">WordPress Plugin Directory</a> directly and installing new plugins manually. To manually install a plugin you generally just need to upload the plugin file into your <code>/wp-content/plugins</code> directory. Once a plugin has been installed, you can activate it here.'), 'plugin-install.php', 'http://wordpress.org/plugins/') . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'compatibility-problems',
+'title' => __('Troubleshooting'),
+'content' =>
+ '<p>' . __('Most of the time, plugins play nicely with the core of WordPress and with other plugins. Sometimes, though, a plugin&#8217;s code will get in the way of another plugin, causing compatibility issues. If your site starts doing strange things, this may be the problem. Try deactivating all your plugins and re-activating them in various combinations until you isolate which one(s) caused the issue.') . '</p>' .
+ '<p>' . sprintf( __('If something goes wrong with a plugin and you can&#8217;t use WordPress, delete or rename that file in the <code>%s</code> directory and it will be automatically deactivated.'), WP_PLUGIN_DIR) . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Managing_Plugins#Plugin_Management" target="_blank">Documentation on Managing Plugins</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$title = __('Plugins');
+$parent_file = 'plugins.php';
+
+require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+$invalid = validate_active_plugins();
+if ( !empty($invalid) )
+ foreach ( $invalid as $plugin_file => $error )
+ echo '<div id="message" class="error"><p>' . sprintf(__('The plugin <code>%s</code> has been <strong>deactivated</strong> due to an error: %s'), esc_html($plugin_file), $error->get_error_message()) . '</p></div>';
+?>
+
+<?php if ( isset($_GET['error']) ) :
+
+ if ( isset( $_GET['main'] ) )
+ $errmsg = __( 'You cannot delete a plugin while it is active on the main site.' );
+ elseif ( isset($_GET['charsout']) )
+ $errmsg = sprintf(__('The plugin generated %d characters of <strong>unexpected output</strong> during activation. If you notice &#8220;headers already sent&#8221; messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.'), $_GET['charsout']);
+ else
+ $errmsg = __('Plugin could not be activated because it triggered a <strong>fatal error</strong>.');
+ ?>
+ <div id="message" class="updated"><p><?php echo $errmsg; ?></p>
+ <?php
+ if ( !isset( $_GET['main'] ) && !isset($_GET['charsout']) && wp_verify_nonce($_GET['_error_nonce'], 'plugin-activation-error_' . $plugin) ) { ?>
+ <iframe style="border:0" width="100%" height="70px" src="<?php echo 'plugins.php?action=error_scrape&amp;plugin=' . esc_attr($plugin) . '&amp;_wpnonce=' . esc_attr($_GET['_error_nonce']); ?>"></iframe>
+ <?php
+ }
+ ?>
+ </div>
+<?php elseif ( isset($_GET['deleted']) ) :
+ $delete_result = get_transient('plugins_delete_result_'.$user_ID);
+ delete_transient('plugins_delete_result'); //Delete it once we're done.
+
+ if ( is_wp_error($delete_result) ) : ?>
+ <div id="message" class="updated"><p><?php printf( __('Plugin could not be deleted due to an error: %s'), $delete_result->get_error_message() ); ?></p></div>
+ <?php else : ?>
+ <div id="message" class="updated"><p><?php _e('The selected plugins have been <strong>deleted</strong>.'); ?></p></div>
+ <?php endif; ?>
+<?php elseif ( isset($_GET['activate']) ) : ?>
+ <div id="message" class="updated"><p><?php _e('Plugin <strong>activated</strong>.') ?></p></div>
+<?php elseif (isset($_GET['activate-multi'])) : ?>
+ <div id="message" class="updated"><p><?php _e('Selected plugins <strong>activated</strong>.'); ?></p></div>
+<?php elseif ( isset($_GET['deactivate']) ) : ?>
+ <div id="message" class="updated"><p><?php _e('Plugin <strong>deactivated</strong>.') ?></p></div>
+<?php elseif (isset($_GET['deactivate-multi'])) : ?>
+ <div id="message" class="updated"><p><?php _e('Selected plugins <strong>deactivated</strong>.'); ?></p></div>
+<?php elseif ( 'update-selected' == $action ) : ?>
+ <div id="message" class="updated"><p><?php _e('No out of date plugins were selected.'); ?></p></div>
+<?php endif; ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title );
+if ( ( ! is_multisite() || is_network_admin() ) && current_user_can('install_plugins') ) { ?>
+ <a href="<?php echo self_admin_url( 'plugin-install.php' ); ?>" class="add-new-h2"><?php echo esc_html_x('Add New', 'plugin'); ?></a>
+<?php }
+if ( $s )
+ printf( '<span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', esc_html( $s ) ); ?>
+</h2>
+
+<?php do_action( 'pre_current_active_plugins', $plugins['all'] ) ?>
+
+<?php $wp_list_table->views(); ?>
+
+<form method="get" action="">
+<?php $wp_list_table->search_box( __( 'Search Installed Plugins' ), 'plugin' ); ?>
+</form>
+
+<form method="post" action="">
+
+<input type="hidden" name="plugin_status" value="<?php echo esc_attr($status) ?>" />
+<input type="hidden" name="paged" value="<?php echo esc_attr($page) ?>" />
+
+<?php $wp_list_table->display(); ?>
+</form>
+
+</div>
+
+<?php
+include(ABSPATH . 'wp-admin/admin-footer.php');
diff --git a/src/wp-admin/post-new.php b/src/wp-admin/post-new.php
new file mode 100644
index 0000000000..4d7df63c94
--- /dev/null
+++ b/src/wp-admin/post-new.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * New Post Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( !isset($_GET['post_type']) )
+ $post_type = 'post';
+elseif ( in_array( $_GET['post_type'], get_post_types( array('show_ui' => true ) ) ) )
+ $post_type = $_GET['post_type'];
+else
+ wp_die( __('Invalid post type') );
+
+$post_type_object = get_post_type_object( $post_type );
+
+if ( 'post' == $post_type ) {
+ $parent_file = 'edit.php';
+ $submenu_file = 'post-new.php';
+} elseif ( 'attachment' == $post_type ) {
+ wp_redirect( admin_url( 'media-new.php' ) );
+ exit;
+} else {
+ $submenu_file = "post-new.php?post_type=$post_type";
+ if ( isset( $post_type_object ) && $post_type_object->show_in_menu && $post_type_object->show_in_menu !== true ) {
+ $parent_file = $post_type_object->show_in_menu;
+ if ( ! isset( $_registered_pages[ get_plugin_page_hookname( "post-new.php?post_type=$post_type", $post_type_object->show_in_menu ) ] ) )
+ $submenu_file = $parent_file;
+ } else {
+ $parent_file = "edit.php?post_type=$post_type";
+ }
+}
+
+$title = $post_type_object->labels->add_new_item;
+
+$editing = true;
+
+if ( ! current_user_can( $post_type_object->cap->edit_posts ) || ! current_user_can( $post_type_object->cap->create_posts ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+// Schedule auto-draft cleanup
+if ( ! wp_next_scheduled( 'wp_scheduled_auto_draft_delete' ) )
+ wp_schedule_event( time(), 'daily', 'wp_scheduled_auto_draft_delete' );
+
+wp_enqueue_script( 'autosave' );
+
+if ( is_multisite() ) {
+ add_action( 'admin_footer', '_admin_notice_post_locked' );
+} else {
+ $check_users = get_users( array( 'fields' => 'ID', 'number' => 2 ) );
+
+ if ( count( $check_users ) > 1 )
+ add_action( 'admin_footer', '_admin_notice_post_locked' );
+
+ unset( $check_users );
+}
+
+// Show post form.
+$post = get_default_post_to_edit( $post_type, true );
+$post_ID = $post->ID;
+include('edit-form-advanced.php');
+include('./admin-footer.php');
diff --git a/src/wp-admin/post.php b/src/wp-admin/post.php
new file mode 100644
index 0000000000..eab89e6b09
--- /dev/null
+++ b/src/wp-admin/post.php
@@ -0,0 +1,312 @@
+<?php
+/**
+ * Edit post administration panel.
+ *
+ * Manage Post actions: post, edit, delete, etc.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+$parent_file = 'edit.php';
+$submenu_file = 'edit.php';
+
+wp_reset_vars( array( 'action' ) );
+
+if ( isset( $_GET['post'] ) )
+ $post_id = $post_ID = (int) $_GET['post'];
+elseif ( isset( $_POST['post_ID'] ) )
+ $post_id = $post_ID = (int) $_POST['post_ID'];
+else
+ $post_id = $post_ID = 0;
+
+$post = $post_type = $post_type_object = null;
+
+if ( $post_id )
+ $post = get_post( $post_id );
+
+if ( $post ) {
+ $post_type = $post->post_type;
+ $post_type_object = get_post_type_object( $post_type );
+}
+
+/**
+ * Redirect to previous page.
+ *
+ * @param int $post_id Optional. Post ID.
+ */
+function redirect_post($post_id = '') {
+ if ( isset($_POST['save']) || isset($_POST['publish']) ) {
+ $status = get_post_status( $post_id );
+
+ if ( isset( $_POST['publish'] ) ) {
+ switch ( $status ) {
+ case 'pending':
+ $message = 8;
+ break;
+ case 'future':
+ $message = 9;
+ break;
+ default:
+ $message = 6;
+ }
+ } else {
+ $message = 'draft' == $status ? 10 : 1;
+ }
+
+ $location = add_query_arg( 'message', $message, get_edit_post_link( $post_id, 'url' ) );
+ } elseif ( isset($_POST['addmeta']) && $_POST['addmeta'] ) {
+ $location = add_query_arg( 'message', 2, wp_get_referer() );
+ $location = explode('#', $location);
+ $location = $location[0] . '#postcustom';
+ } elseif ( isset($_POST['deletemeta']) && $_POST['deletemeta'] ) {
+ $location = add_query_arg( 'message', 3, wp_get_referer() );
+ $location = explode('#', $location);
+ $location = $location[0] . '#postcustom';
+ } elseif ( 'post-quickpress-save-cont' == $_POST['action'] ) {
+ $location = "post.php?action=edit&post=$post_id&message=7";
+ } else {
+ $location = add_query_arg( 'message', 4, get_edit_post_link( $post_id, 'url' ) );
+ }
+
+ wp_redirect( apply_filters( 'redirect_post_location', $location, $post_id ) );
+ exit;
+}
+
+if ( isset( $_POST['deletepost'] ) )
+ $action = 'delete';
+elseif ( isset($_POST['wp-preview']) && 'dopreview' == $_POST['wp-preview'] )
+ $action = 'preview';
+
+$sendback = wp_get_referer();
+if ( ! $sendback ||
+ strpos( $sendback, 'post.php' ) !== false ||
+ strpos( $sendback, 'post-new.php' ) !== false ) {
+ if ( 'attachment' == $post_type ) {
+ $sendback = admin_url( 'upload.php' );
+ } else {
+ $sendback = admin_url( 'edit.php' );
+ $sendback .= ( ! empty( $post_type ) ) ? '?post_type=' . $post_type : '';
+ }
+} else {
+ $sendback = remove_query_arg( array('trashed', 'untrashed', 'deleted', 'ids'), $sendback );
+}
+
+switch($action) {
+case 'postajaxpost':
+case 'post':
+case 'post-quickpress-publish':
+case 'post-quickpress-save':
+ check_admin_referer('add-' . $post_type);
+
+ if ( 'post-quickpress-publish' == $action )
+ $_POST['publish'] = 'publish'; // tell write_post() to publish
+
+ if ( 'post-quickpress-publish' == $action || 'post-quickpress-save' == $action ) {
+ $_POST['comment_status'] = get_option('default_comment_status');
+ $_POST['ping_status'] = get_option('default_ping_status');
+ $post_id = edit_post();
+ } else {
+ $post_id = 'postajaxpost' == $action ? edit_post() : write_post();
+ }
+
+ if ( 0 === strpos( $action, 'post-quickpress' ) ) {
+ $_POST['post_ID'] = $post_id;
+ // output the quickpress dashboard widget
+ require_once(ABSPATH . 'wp-admin/includes/dashboard.php');
+ wp_dashboard_quick_press();
+ exit;
+ }
+
+ redirect_post($post_id);
+ exit();
+ break;
+
+case 'edit':
+ $editing = true;
+
+ if ( empty( $post_id ) ) {
+ wp_redirect( admin_url('post.php') );
+ exit();
+ }
+
+ if ( ! $post )
+ wp_die( __( 'You attempted to edit an item that doesn&#8217;t exist. Perhaps it was deleted?' ) );
+
+ if ( ! $post_type_object )
+ wp_die( __( 'Unknown post type.' ) );
+
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ wp_die( __( 'You are not allowed to edit this item.' ) );
+
+ if ( 'trash' == $post->post_status )
+ wp_die( __( 'You can&#8217;t edit this item because it is in the Trash. Please restore it and try again.' ) );
+
+ if ( ! empty( $_GET['get-post-lock'] ) ) {
+ wp_set_post_lock( $post_id );
+ wp_redirect( get_edit_post_link( $post_id, 'url' ) );
+ exit();
+ }
+
+ $post_type = $post->post_type;
+ if ( 'post' == $post_type ) {
+ $parent_file = "edit.php";
+ $submenu_file = "edit.php";
+ $post_new_file = "post-new.php";
+ } elseif ( 'attachment' == $post_type ) {
+ $parent_file = 'upload.php';
+ $submenu_file = 'upload.php';
+ $post_new_file = 'media-new.php';
+ } else {
+ if ( isset( $post_type_object ) && $post_type_object->show_in_menu && $post_type_object->show_in_menu !== true )
+ $parent_file = $post_type_object->show_in_menu;
+ else
+ $parent_file = "edit.php?post_type=$post_type";
+ $submenu_file = "edit.php?post_type=$post_type";
+ $post_new_file = "post-new.php?post_type=$post_type";
+ }
+
+ if ( ! wp_check_post_lock( $post->ID ) ) {
+ $active_post_lock = wp_set_post_lock( $post->ID );
+
+ if ( 'attachment' !== $post_type )
+ wp_enqueue_script('autosave');
+ }
+
+ if ( is_multisite() ) {
+ add_action( 'admin_footer', '_admin_notice_post_locked' );
+ } else {
+ $check_users = get_users( array( 'fields' => 'ID', 'number' => 2 ) );
+
+ if ( count( $check_users ) > 1 )
+ add_action( 'admin_footer', '_admin_notice_post_locked' );
+
+ unset( $check_users );
+ }
+
+ $title = $post_type_object->labels->edit_item;
+ $post = get_post($post_id, OBJECT, 'edit');
+
+ if ( post_type_supports($post_type, 'comments') ) {
+ wp_enqueue_script('admin-comments');
+ enqueue_comment_hotkeys_js();
+ }
+
+ include('./edit-form-advanced.php');
+
+ break;
+
+case 'editattachment':
+ check_admin_referer('update-post_' . $post_id);
+
+ // Don't let these be changed
+ unset($_POST['guid']);
+ $_POST['post_type'] = 'attachment';
+
+ // Update the thumbnail filename
+ $newmeta = wp_get_attachment_metadata( $post_id, true );
+ $newmeta['thumb'] = $_POST['thumb'];
+
+ wp_update_attachment_metadata( $post_id, $newmeta );
+
+case 'editpost':
+ check_admin_referer('update-post_' . $post_id);
+
+ $post_id = edit_post();
+
+ // Session cookie flag that the post was saved
+ if ( isset( $_COOKIE['wp-saving-post-' . $post_id] ) )
+ setcookie( 'wp-saving-post-' . $post_id, 'saved' );
+
+ redirect_post($post_id); // Send user on their way while we keep working
+
+ exit();
+ break;
+
+case 'trash':
+ check_admin_referer('trash-post_' . $post_id);
+
+ if ( ! $post )
+ wp_die( __( 'The item you are trying to move to the Trash no longer exists.' ) );
+
+ if ( ! $post_type_object )
+ wp_die( __( 'Unknown post type.' ) );
+
+ if ( ! current_user_can( 'delete_post', $post_id ) )
+ wp_die( __( 'You are not allowed to move this item to the Trash.' ) );
+
+ if ( $user_id = wp_check_post_lock( $post_id ) ) {
+ $user = get_userdata( $user_id );
+ wp_die( sprintf( __( 'You cannot move this item to the Trash. %s is currently editing.' ), $user->display_name ) );
+ }
+
+ if ( ! wp_trash_post( $post_id ) )
+ wp_die( __( 'Error in moving to Trash.' ) );
+
+ wp_redirect( add_query_arg( array('trashed' => 1, 'ids' => $post_id), $sendback ) );
+ exit();
+ break;
+
+case 'untrash':
+ check_admin_referer('untrash-post_' . $post_id);
+
+ if ( ! $post )
+ wp_die( __( 'The item you are trying to restore from the Trash no longer exists.' ) );
+
+ if ( ! $post_type_object )
+ wp_die( __( 'Unknown post type.' ) );
+
+ if ( ! current_user_can( 'delete_post', $post_id ) )
+ wp_die( __( 'You are not allowed to move this item out of the Trash.' ) );
+
+ if ( ! wp_untrash_post( $post_id ) )
+ wp_die( __( 'Error in restoring from Trash.' ) );
+
+ wp_redirect( add_query_arg('untrashed', 1, $sendback) );
+ exit();
+ break;
+
+case 'delete':
+ check_admin_referer('delete-post_' . $post_id);
+
+ if ( ! $post )
+ wp_die( __( 'This item has already been deleted.' ) );
+
+ if ( ! $post_type_object )
+ wp_die( __( 'Unknown post type.' ) );
+
+ if ( ! current_user_can( 'delete_post', $post_id ) )
+ wp_die( __( 'You are not allowed to delete this item.' ) );
+
+ $force = ! EMPTY_TRASH_DAYS;
+ if ( $post->post_type == 'attachment' ) {
+ $force = ( $force || ! MEDIA_TRASH );
+ if ( ! wp_delete_attachment( $post_id, $force ) )
+ wp_die( __( 'Error in deleting.' ) );
+ } else {
+ if ( ! wp_delete_post( $post_id, $force ) )
+ wp_die( __( 'Error in deleting.' ) );
+ }
+
+ wp_redirect( add_query_arg('deleted', 1, $sendback) );
+ exit();
+ break;
+
+case 'preview':
+ check_admin_referer( 'autosave', 'autosavenonce' );
+
+ $url = post_preview();
+
+ wp_redirect($url);
+ exit();
+ break;
+
+default:
+ wp_redirect( admin_url('edit.php') );
+ exit();
+ break;
+} // end switch
+include('./admin-footer.php');
diff --git a/src/wp-admin/press-this.php b/src/wp-admin/press-this.php
new file mode 100644
index 0000000000..0f2be6c539
--- /dev/null
+++ b/src/wp-admin/press-this.php
@@ -0,0 +1,653 @@
+<?php
+/**
+ * Press This Display and Handler.
+ *
+ * @package WordPress
+ * @subpackage Press_This
+ */
+
+define('IFRAME_REQUEST' , true);
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
+
+if ( ! current_user_can( 'edit_posts' ) || ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+/**
+ * Press It form handler.
+ *
+ * @package WordPress
+ * @subpackage Press_This
+ * @since 2.6.0
+ *
+ * @return int Post ID
+ */
+function press_it() {
+
+ $post = get_default_post_to_edit();
+ $post = get_object_vars($post);
+ $post_ID = $post['ID'] = (int) $_POST['post_id'];
+
+ if ( !current_user_can('edit_post', $post_ID) )
+ wp_die(__('You are not allowed to edit this post.'));
+
+ $post['post_category'] = isset($_POST['post_category']) ? $_POST['post_category'] : '';
+ $post['tax_input'] = isset($_POST['tax_input']) ? $_POST['tax_input'] : '';
+ $post['post_title'] = isset($_POST['title']) ? $_POST['title'] : '';
+ $content = isset($_POST['content']) ? $_POST['content'] : '';
+
+ $upload = false;
+ if ( !empty($_POST['photo_src']) && current_user_can('upload_files') ) {
+ foreach( (array) $_POST['photo_src'] as $key => $image) {
+ // see if files exist in content - we don't want to upload non-used selected files.
+ if ( strpos($_POST['content'], htmlspecialchars($image)) !== false ) {
+ $desc = isset($_POST['photo_description'][$key]) ? $_POST['photo_description'][$key] : '';
+ $upload = media_sideload_image($image, $post_ID, $desc);
+
+ // Replace the POSTED content <img> with correct uploaded ones. Regex contains fix for Magic Quotes
+ if ( !is_wp_error($upload) )
+ $content = preg_replace('/<img ([^>]*)src=\\\?(\"|\')'.preg_quote(htmlspecialchars($image), '/').'\\\?(\2)([^>\/]*)\/*>/is', $upload, $content);
+ }
+ }
+ }
+ // set the post_content and status
+ $post['post_content'] = $content;
+ if ( isset( $_POST['publish'] ) && current_user_can( 'publish_posts' ) )
+ $post['post_status'] = 'publish';
+ elseif ( isset( $_POST['review'] ) )
+ $post['post_status'] = 'pending';
+ else
+ $post['post_status'] = 'draft';
+
+ // error handling for media_sideload
+ if ( is_wp_error($upload) ) {
+ wp_delete_post($post_ID);
+ wp_die($upload);
+ } else {
+ // Post formats
+ if ( isset( $_POST['post_format'] ) ) {
+ if ( current_theme_supports( 'post-formats', $_POST['post_format'] ) )
+ set_post_format( $post_ID, $_POST['post_format'] );
+ elseif ( '0' == $_POST['post_format'] )
+ set_post_format( $post_ID, false );
+ }
+
+ $post_ID = wp_update_post($post);
+ }
+
+ return $post_ID;
+}
+
+// For submitted posts.
+if ( isset($_REQUEST['action']) && 'post' == $_REQUEST['action'] ) {
+ check_admin_referer('press-this');
+ $posted = $post_ID = press_it();
+} else {
+ $post = get_default_post_to_edit('post', true);
+ $post_ID = $post->ID;
+}
+
+// Set Variables
+$title = isset( $_GET['t'] ) ? trim( strip_tags( html_entity_decode( wp_unslash( $_GET['t'] ) , ENT_QUOTES) ) ) : '';
+
+$selection = '';
+if ( !empty($_GET['s']) ) {
+ $selection = str_replace('&apos;', "'", wp_unslash($_GET['s']));
+ $selection = trim( htmlspecialchars( html_entity_decode($selection, ENT_QUOTES) ) );
+}
+
+if ( ! empty($selection) ) {
+ $selection = preg_replace('/(\r?\n|\r)/', '</p><p>', $selection);
+ $selection = '<p>' . str_replace('<p></p>', '', $selection) . '</p>';
+}
+
+$url = isset($_GET['u']) ? esc_url($_GET['u']) : '';
+$image = isset($_GET['i']) ? $_GET['i'] : '';
+
+if ( !empty($_REQUEST['ajax']) ) {
+ switch ($_REQUEST['ajax']) {
+ case 'video': ?>
+ <script type="text/javascript">
+ /* <![CDATA[ */
+ jQuery('.select').click(function() {
+ append_editor(jQuery('#embed-code').val());
+ jQuery('#extra-fields').hide();
+ jQuery('#extra-fields').html('');
+ });
+ jQuery('.close').click(function() {
+ jQuery('#extra-fields').hide();
+ jQuery('#extra-fields').html('');
+ });
+ /* ]]> */
+ </script>
+ <div class="postbox">
+ <h2><label for="embed-code"><?php _e('Embed Code') ?></label></h2>
+ <div class="inside">
+ <textarea name="embed-code" id="embed-code" rows="8" cols="40"><?php echo esc_textarea( $selection ); ?></textarea>
+ <p id="options"><a href="#" class="select button"><?php _e('Insert Video'); ?></a> <a href="#" class="close button"><?php _e('Cancel'); ?></a></p>
+ </div>
+ </div>
+ <?php break;
+
+ case 'photo_thickbox': ?>
+ <script type="text/javascript">
+ /* <![CDATA[ */
+ jQuery('.cancel').click(function() {
+ tb_remove();
+ });
+ jQuery('.select').click(function() {
+ image_selector(this);
+ });
+ /* ]]> */
+ </script>
+ <h3 class="tb"><label for="tb_this_photo_description"><?php _e('Description') ?></label></h3>
+ <div class="titlediv">
+ <div class="titlewrap">
+ <input id="tb_this_photo_description" name="photo_description" class="tb_this_photo_description tbtitle text" onkeypress="if(event.keyCode==13) image_selector(this);" value="<?php echo esc_attr($title);?>"/>
+ </div>
+ </div>
+
+ <p class="centered">
+ <input type="hidden" name="this_photo" value="<?php echo esc_attr($image); ?>" id="tb_this_photo" class="tb_this_photo" />
+ <a href="#" class="select">
+ <img src="<?php echo esc_url($image); ?>" alt="<?php echo esc_attr(__('Click to insert.')); ?>" title="<?php echo esc_attr(__('Click to insert.')); ?>" />
+ </a>
+ </p>
+
+ <p id="options"><a href="#" class="select button"><?php _e('Insert Image'); ?></a> <a href="#" class="cancel button"><?php _e('Cancel'); ?></a></p>
+ <?php break;
+ case 'photo_images':
+ /**
+ * Retrieve all image URLs from given URI.
+ *
+ * @package WordPress
+ * @subpackage Press_This
+ * @since 2.6.0
+ *
+ * @param string $uri
+ * @return string
+ */
+ function get_images_from_uri($uri) {
+ $uri = preg_replace('/\/#.+?$/','', $uri);
+ if ( preg_match( '/\.(jpe?g|jpe|gif|png)\b/i', $uri ) && !strpos( $uri, 'blogger.com' ) )
+ return "'" . esc_attr( html_entity_decode($uri) ) . "'";
+ $content = wp_remote_fopen($uri);
+ if ( false === $content )
+ return '';
+ $host = parse_url($uri);
+ $pattern = '/<img ([^>]*)src=(\"|\')([^<>\'\"]+)(\2)([^>]*)\/*>/i';
+ $content = str_replace(array("\n","\t","\r"), '', $content);
+ preg_match_all($pattern, $content, $matches);
+ if ( empty($matches[0]) )
+ return '';
+ $sources = array();
+ foreach ($matches[3] as $src) {
+ // if no http in url
+ if (strpos($src, 'http') === false)
+ // if it doesn't have a relative uri
+ if ( strpos($src, '../') === false && strpos($src, './') === false && strpos($src, '/') === 0)
+ $src = 'http://'.str_replace('//','/', $host['host'].'/'.$src);
+ else
+ $src = 'http://'.str_replace('//','/', $host['host'].'/'.dirname($host['path']).'/'.$src);
+ $sources[] = esc_url($src);
+ }
+ return "'" . implode("','", $sources) . "'";
+ }
+ $url = wp_kses(urldecode($url), null);
+ echo 'new Array('.get_images_from_uri($url).')';
+ break;
+
+ case 'photo_js': ?>
+ // gather images and load some default JS
+ var last = null
+ var img, img_tag, aspect, w, h, skip, i, strtoappend = "";
+ if(photostorage == false) {
+ var my_src = eval(
+ jQuery.ajax({
+ type: "GET",
+ url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
+ cache : false,
+ async : false,
+ data: "ajax=photo_images&u=<?php echo urlencode($url); ?>",
+ dataType : "script"
+ }).responseText
+ );
+ if(my_src.length == 0) {
+ var my_src = eval(
+ jQuery.ajax({
+ type: "GET",
+ url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
+ cache : false,
+ async : false,
+ data: "ajax=photo_images&u=<?php echo urlencode($url); ?>",
+ dataType : "script"
+ }).responseText
+ );
+ if(my_src.length == 0) {
+ strtoappend = '<?php _e('Unable to retrieve images or no images on page.'); ?>';
+ }
+ }
+ }
+ for (i = 0; i < my_src.length; i++) {
+ img = new Image();
+ img.src = my_src[i];
+ img_attr = 'id="img' + i + '"';
+ skip = false;
+
+ maybeappend = '<a href="?ajax=photo_thickbox&amp;i=' + encodeURIComponent(img.src) + '&amp;u=<?php echo urlencode($url); ?>&amp;height=400&amp;width=500" title="" class="thickbox"><img src="' + img.src + '" ' + img_attr + '/></a>';
+
+ if (img.width && img.height) {
+ if (img.width >= 30 && img.height >= 30) {
+ aspect = img.width / img.height;
+ scale = (aspect > 1) ? (71 / img.width) : (71 / img.height);
+
+ w = img.width;
+ h = img.height;
+
+ if (scale < 1) {
+ w = parseInt(img.width * scale);
+ h = parseInt(img.height * scale);
+ }
+ img_attr += ' style="width: ' + w + 'px; height: ' + h + 'px;"';
+ strtoappend += maybeappend;
+ }
+ } else {
+ strtoappend += maybeappend;
+ }
+ }
+
+ function pick(img, desc) {
+ if (img) {
+ if('object' == typeof jQuery('.photolist input') && jQuery('.photolist input').length != 0) length = jQuery('.photolist input').length;
+ if(length == 0) length = 1;
+ jQuery('.photolist').append('<input name="photo_src[' + length + ']" value="' + img +'" type="hidden"/>');
+ jQuery('.photolist').append('<input name="photo_description[' + length + ']" value="' + desc +'" type="hidden"/>');
+ insert_editor( "\n\n" + encodeURI('<p style="text-align: center;"><a href="<?php echo $url; ?>"><img src="' + img +'" alt="' + desc + '" /></a></p>'));
+ }
+ return false;
+ }
+
+ function image_selector(el) {
+ var desc, src, parent = jQuery(el).closest('#photo-add-url-div');
+
+ if ( parent.length ) {
+ desc = parent.find('input.tb_this_photo_description').val() || '';
+ src = parent.find('input.tb_this_photo').val() || ''
+ } else {
+ desc = jQuery('#tb_this_photo_description').val() || '';
+ src = jQuery('#tb_this_photo').val() || ''
+ }
+
+ tb_remove();
+ pick(src, desc);
+ jQuery('#extra-fields').hide();
+ jQuery('#extra-fields').html('');
+ return false;
+ }
+
+ jQuery('#extra-fields').html('<div class="postbox"><h2><?php _e( 'Add Photos' ); ?> <small id="photo_directions">(<?php _e("click images to select") ?>)</small></h2><ul class="actions"><li><a href="#" id="photo-add-url" class="button button-small"><?php _e("Add from URL") ?> +</a></li></ul><div class="inside"><div class="titlewrap"><div id="img_container"></div></div><p id="options"><a href="#" class="close button"><?php _e('Cancel'); ?></a><a href="#" class="refresh button"><?php _e('Refresh'); ?></a></p></div>');
+ jQuery('#img_container').html(strtoappend);
+ <?php break;
+}
+die;
+}
+
+ wp_enqueue_style( 'colors' );
+ wp_enqueue_script( 'post' );
+ _wp_admin_html_begin();
+?>
+<title><?php _e('Press This') ?></title>
+<script type="text/javascript">
+//<![CDATA[
+addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
+var ajaxurl = '<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>', pagenow = 'press-this', isRtl = <?php echo (int) is_rtl(); ?>;
+var photostorage = false;
+//]]>
+</script>
+
+<?php
+ do_action('admin_print_styles');
+ do_action('admin_print_scripts');
+ do_action('admin_head');
+?>
+ <script type="text/javascript">
+ var wpActiveEditor = 'content';
+
+ function insert_plain_editor(text) {
+ if ( typeof(QTags) != 'undefined' )
+ QTags.insertContent(text);
+ }
+ function set_editor(text) {
+ if ( '' == text || '<p></p>' == text )
+ text = '<p><br /></p>';
+
+ if ( tinyMCE.activeEditor )
+ tinyMCE.execCommand('mceSetContent', false, text);
+ }
+ function insert_editor(text) {
+ if ( '' != text && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden()) {
+ tinyMCE.execCommand('mceInsertContent', false, '<p>' + decodeURI(tinymce.DOM.decode(text)) + '</p>', {format : 'raw'});
+ } else {
+ insert_plain_editor(decodeURI(text));
+ }
+ }
+ function append_editor(text) {
+ if ( '' != text && tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden()) {
+ tinyMCE.execCommand('mceSetContent', false, tinyMCE.activeEditor.getContent({format : 'raw'}) + '<p>' + text + '</p>');
+ } else {
+ insert_plain_editor(text);
+ }
+ }
+
+ function show(tab_name) {
+ jQuery('#extra-fields').html('');
+ switch(tab_name) {
+ case 'video' :
+ jQuery('#extra-fields').load('<?php echo esc_url($_SERVER['PHP_SELF']); ?>', { ajax: 'video', s: '<?php echo esc_attr($selection); ?>'}, function() {
+ <?php
+ $content = '';
+ if ( preg_match("/youtube\.com\/watch/i", $url) ) {
+ list($domain, $video_id) = explode("v=", $url);
+ $video_id = esc_attr($video_id);
+ $content = '<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/' . $video_id . '"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/' . $video_id . '" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>';
+
+ } elseif ( preg_match("/vimeo\.com\/[0-9]+/i", $url) ) {
+ list($domain, $video_id) = explode(".com/", $url);
+ $video_id = esc_attr($video_id);
+ $content = '<object width="400" height="225"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=' . $video_id . '&amp;server=www.vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /> <embed src="http://www.vimeo.com/moogaloop.swf?clip_id=' . $video_id . '&amp;server=www.vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"></embed></object>';
+
+ if ( trim($selection) == '' )
+ $selection = '<p><a href="http://www.vimeo.com/' . $video_id . '?pg=embed&sec=' . $video_id . '">' . $title . '</a> on <a href="http://vimeo.com?pg=embed&sec=' . $video_id . '">Vimeo</a></p>';
+
+ } elseif ( strpos( $selection, '<object' ) !== false ) {
+ $content = $selection;
+ }
+ ?>
+ jQuery('#embed-code').prepend('<?php echo htmlentities($content); ?>');
+ });
+ jQuery('#extra-fields').show();
+ return false;
+ break;
+ case 'photo' :
+ function setup_photo_actions() {
+ jQuery('.close').click(function() {
+ jQuery('#extra-fields').hide();
+ jQuery('#extra-fields').html('');
+ });
+ jQuery('.refresh').click(function() {
+ photostorage = false;
+ show('photo');
+ });
+ jQuery('#photo-add-url').click(function(){
+ var form = jQuery('#photo-add-url-div').clone();
+ jQuery('#img_container').empty().append( form.show() );
+ });
+ jQuery('#waiting').hide();
+ jQuery('#extra-fields').show();
+ }
+
+ jQuery('#waiting').show();
+ if(photostorage == false) {
+ jQuery.ajax({
+ type: "GET",
+ cache : false,
+ url: "<?php echo esc_url($_SERVER['PHP_SELF']); ?>",
+ data: "ajax=photo_js&u=<?php echo urlencode($url)?>",
+ dataType : "script",
+ success : function(data) {
+ eval(data);
+ photostorage = jQuery('#extra-fields').html();
+ setup_photo_actions();
+ }
+ });
+ } else {
+ jQuery('#extra-fields').html(photostorage);
+ setup_photo_actions();
+ }
+ return false;
+ break;
+ }
+ }
+ jQuery(document).ready(function($) {
+ //resize screen
+ window.resizeTo(740,580);
+ // set button actions
+ jQuery('#photo_button').click(function() { show('photo'); return false; });
+ jQuery('#video_button').click(function() { show('video'); return false; });
+ // auto select
+ <?php if ( preg_match("/youtube\.com\/watch/i", $url) ) { ?>
+ show('video');
+ <?php } elseif ( preg_match("/vimeo\.com\/[0-9]+/i", $url) ) { ?>
+ show('video');
+ <?php } elseif ( preg_match("/flickr\.com/i", $url) ) { ?>
+ show('photo');
+ <?php } ?>
+ jQuery('#title').unbind();
+ jQuery('#publish, #save').click(function() { jQuery('.press-this #publishing-actions .spinner').css('display', 'inline-block'); });
+
+ $('#tagsdiv-post_tag, #categorydiv').children('h3, .handlediv').click(function(){
+ $(this).siblings('.inside').toggle();
+ });
+ });
+</script>
+</head>
+<?php
+$admin_body_class = ( is_rtl() ) ? 'rtl' : '';
+$admin_body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_locale() ) ) );
+?>
+<body class="press-this wp-admin wp-core-ui <?php echo $admin_body_class; ?>">
+<form action="press-this.php?action=post" method="post">
+<div id="poststuff" class="metabox-holder">
+ <div id="side-sortables" class="press-this-sidebar">
+ <div class="sleeve">
+ <?php wp_nonce_field('press-this') ?>
+ <input type="hidden" name="post_type" id="post_type" value="text"/>
+ <input type="hidden" name="autosave" id="autosave" />
+ <input type="hidden" id="original_post_status" name="original_post_status" value="draft" />
+ <input type="hidden" id="prev_status" name="prev_status" value="draft" />
+ <input type="hidden" id="post_id" name="post_id" value="<?php echo (int) $post_ID; ?>" />
+
+ <!-- This div holds the photo metadata -->
+ <div class="photolist"></div>
+
+ <div id="submitdiv" class="postbox">
+ <div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
+ <h3 class="hndle"><?php _e('Press This') ?></h3>
+ <div class="inside">
+ <p id="publishing-actions">
+ <?php
+ submit_button( __( 'Save Draft' ), 'button', 'draft', false, array( 'id' => 'save' ) );
+ if ( current_user_can('publish_posts') ) {
+ submit_button( __( 'Publish' ), 'primary', 'publish', false );
+ } else {
+ echo '<br /><br />';
+ submit_button( __( 'Submit for Review' ), 'primary', 'review', false );
+ } ?>
+ <span class="spinner" style="display: none;"></span>
+ </p>
+ <?php if ( current_theme_supports( 'post-formats' ) && post_type_supports( 'post', 'post-formats' ) ) :
+ $post_formats = get_theme_support( 'post-formats' );
+ if ( is_array( $post_formats[0] ) ) :
+ $default_format = get_option( 'default_post_format', '0' );
+ ?>
+ <p>
+ <label for="post_format"><?php _e( 'Post Format:' ); ?>
+ <select name="post_format" id="post_format">
+ <option value="0"><?php echo get_post_format_string( 'standard' ); ?></option>
+ <?php foreach ( $post_formats[0] as $format ): ?>
+ <option<?php selected( $default_format, $format ); ?> value="<?php echo esc_attr( $format ); ?>"> <?php echo esc_html( get_post_format_string( $format ) ); ?></option>
+ <?php endforeach; ?>
+ </select></label>
+ </p>
+ <?php endif; endif; ?>
+ </div>
+ </div>
+
+ <?php $tax = get_taxonomy( 'category' ); ?>
+ <div id="categorydiv" class="postbox">
+ <div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
+ <h3 class="hndle"><?php _e('Categories') ?></h3>
+ <div class="inside">
+ <div id="taxonomy-category" class="categorydiv">
+
+ <ul id="category-tabs" class="category-tabs">
+ <li class="tabs"><a href="#category-all"><?php echo $tax->labels->all_items; ?></a></li>
+ <li class="hide-if-no-js"><a href="#category-pop"><?php _e( 'Most Used' ); ?></a></li>
+ </ul>
+
+ <div id="category-pop" class="tabs-panel" style="display: none;">
+ <ul id="categorychecklist-pop" class="categorychecklist form-no-clear" >
+ <?php $popular_ids = wp_popular_terms_checklist( 'category' ); ?>
+ </ul>
+ </div>
+
+ <div id="category-all" class="tabs-panel">
+ <ul id="categorychecklist" data-wp-lists="list:category" class="categorychecklist form-no-clear">
+ <?php wp_terms_checklist($post_ID, array( 'taxonomy' => 'category', 'popular_cats' => $popular_ids ) ) ?>
+ </ul>
+ </div>
+
+ <?php if ( !current_user_can($tax->cap->assign_terms) ) : ?>
+ <p><em><?php _e('You cannot modify this Taxonomy.'); ?></em></p>
+ <?php endif; ?>
+ <?php if ( current_user_can($tax->cap->edit_terms) ) : ?>
+ <div id="category-adder" class="wp-hidden-children">
+ <h4>
+ <a id="category-add-toggle" href="#category-add" class="hide-if-no-js">
+ <?php printf( __( '+ %s' ), $tax->labels->add_new_item ); ?>
+ </a>
+ </h4>
+ <p id="category-add" class="category-add wp-hidden-child">
+ <label class="screen-reader-text" for="newcategory"><?php echo $tax->labels->add_new_item; ?></label>
+ <input type="text" name="newcategory" id="newcategory" class="form-required form-input-tip" value="<?php echo esc_attr( $tax->labels->new_item_name ); ?>" aria-required="true"/>
+ <label class="screen-reader-text" for="newcategory_parent">
+ <?php echo $tax->labels->parent_item_colon; ?>
+ </label>
+ <?php wp_dropdown_categories( array( 'taxonomy' => 'category', 'hide_empty' => 0, 'name' => 'newcategory_parent', 'orderby' => 'name', 'hierarchical' => 1, 'show_option_none' => '&mdash; ' . $tax->labels->parent_item . ' &mdash;' ) ); ?>
+ <input type="button" id="category-add-submit" data-wp-lists="add:categorychecklist:category-add" class="button category-add-submit" value="<?php echo esc_attr( $tax->labels->add_new_item ); ?>" />
+ <?php wp_nonce_field( 'add-category', '_ajax_nonce-add-category', false ); ?>
+ <span id="category-ajax-response"></span>
+ </p>
+ </div>
+ <?php endif; ?>
+ </div>
+ </div>
+ </div>
+
+ <div id="tagsdiv-post_tag" class="postbox">
+ <div class="handlediv" title="<?php esc_attr_e( 'Click to toggle' ); ?>"><br /></div>
+ <h3><span><?php _e('Tags'); ?></span></h3>
+ <div class="inside">
+ <div class="tagsdiv" id="post_tag">
+ <div class="jaxtag">
+ <label class="screen-reader-text" for="newtag"><?php _e('Tags'); ?></label>
+ <input type="hidden" name="tax_input[post_tag]" class="the-tags" id="tax-input[post_tag]" value="" />
+ <div class="ajaxtag">
+ <input type="text" name="newtag[post_tag]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
+ <input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" />
+ </div>
+ </div>
+ <div class="tagchecklist"></div>
+ </div>
+ <p class="tagcloud-link"><a href="#titlediv" class="tagcloud-link" id="link-post_tag"><?php _e('Choose from the most used tags'); ?></a></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="posting">
+
+ <div id="wphead">
+ <img id="header-logo" src="<?php echo esc_url( includes_url( 'images/blank.gif' ) ); ?>" alt="" width="16" height="16" />
+ <h1 id="site-heading">
+ <a href="<?php echo get_option('home'); ?>/" target="_blank">
+ <span id="site-title"><?php bloginfo('name'); ?></span>
+ </a>
+ </h1>
+ </div>
+
+ <?php
+ if ( isset($posted) && intval($posted) ) {
+ $post_ID = intval($posted); ?>
+ <div id="message" class="updated">
+ <p><strong><?php _e('Your post has been saved.'); ?></strong>
+ <a onclick="window.opener.location.replace(this.href); window.close();" href="<?php echo get_permalink($post_ID); ?>"><?php _e('View post'); ?></a>
+ | <a href="<?php echo get_edit_post_link( $post_ID ); ?>" onclick="window.opener.location.replace(this.href); window.close();"><?php _e('Edit Post'); ?></a>
+ | <a href="#" onclick="window.close();"><?php _e('Close Window'); ?></a></p>
+ </div>
+ <?php } ?>
+
+ <div id="titlediv">
+ <div class="titlewrap">
+ <input name="title" id="title" class="text" value="<?php echo esc_attr($title);?>"/>
+ </div>
+ </div>
+
+ <div id="waiting" style="display: none"><span class="spinner"></span> <span><?php esc_html_e( 'Loading&hellip;' ); ?></span></div>
+
+ <div id="extra-fields" style="display: none"></div>
+
+ <div class="postdivrich">
+ <?php
+
+ $editor_settings = array(
+ 'teeny' => true,
+ 'textarea_rows' => '15'
+ );
+
+ $content = '';
+ if ( $selection )
+ $content .= $selection;
+
+ if ( $url ) {
+ $content .= '<p>';
+
+ if ( $selection )
+ $content .= __('via ');
+
+ $content .= sprintf( "<a href='%s'>%s</a>.</p>", esc_url( $url ), esc_html( $title ) );
+ }
+
+ remove_action( 'media_buttons', 'media_buttons' );
+ add_action( 'media_buttons', 'press_this_media_buttons' );
+ function press_this_media_buttons() {
+ _e( 'Add:' );
+
+ if ( current_user_can('upload_files') ) {
+ ?>
+ <a id="photo_button" title="<?php esc_attr_e('Insert an Image'); ?>" href="#">
+ <img alt="<?php esc_attr_e('Insert an Image'); ?>" src="<?php echo esc_url( admin_url( 'images/media-button-image.gif?ver=20100531' ) ); ?>"/></a>
+ <?php
+ }
+ ?>
+ <a id="video_button" title="<?php esc_attr_e('Embed a Video'); ?>" href="#"><img alt="<?php esc_attr_e('Embed a Video'); ?>" src="<?php echo esc_url( admin_url( 'images/media-button-video.gif?ver=20100531' ) ); ?>"/></a>
+ <?php
+ }
+
+ wp_editor( $content, 'content', $editor_settings );
+
+ ?>
+ </div>
+ </div>
+</div>
+</form>
+<div id="photo-add-url-div" style="display:none;">
+ <table><tr>
+ <td><label for="this_photo"><?php _e('URL') ?></label></td>
+ <td><input type="text" id="this_photo" name="this_photo" class="tb_this_photo text" onkeypress="if(event.keyCode==13) image_selector(this);" /></td>
+ </tr><tr>
+ <td><label for="this_photo_description"><?php _e('Description') ?></label></td>
+ <td><input type="text" id="this_photo_description" name="photo_description" class="tb_this_photo_description text" onkeypress="if(event.keyCode==13) image_selector(this);" value="<?php echo esc_attr($title);?>"/></td>
+ </tr><tr>
+ <td><input type="button" class="button" onclick="image_selector(this)" value="<?php esc_attr_e('Insert Image'); ?>" /></td>
+ </tr></table>
+</div>
+<?php
+do_action('admin_footer');
+do_action('admin_print_footer_scripts');
+?>
+<script type="text/javascript">if(typeof wpOnload=='function')wpOnload();</script>
+</body>
+</html>
diff --git a/src/wp-admin/profile.php b/src/wp-admin/profile.php
new file mode 100644
index 0000000000..c5021f169e
--- /dev/null
+++ b/src/wp-admin/profile.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * User Profile Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * This is a profile page.
+ *
+ * @since 2.5.0
+ * @var bool
+ */
+define('IS_PROFILE_PAGE', true);
+
+/** Load User Editing Page */
+require_once('./user-edit.php');
diff --git a/src/wp-admin/revision.php b/src/wp-admin/revision.php
new file mode 100644
index 0000000000..b6b4ae821e
--- /dev/null
+++ b/src/wp-admin/revision.php
@@ -0,0 +1,210 @@
+<?php
+/**
+ * Revisions administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+require ABSPATH . 'wp-admin/includes/revision.php';
+
+wp_reset_vars( array( 'revision', 'action', 'from', 'to' ) );
+
+$revision_id = absint( $revision );
+
+$from = is_numeric( $from ) ? absint( $from ) : null;
+if ( ! $revision_id )
+ $revision_id = absint( $to );
+$redirect = 'edit.php';
+
+switch ( $action ) :
+case 'restore' :
+ if ( ! $revision = wp_get_post_revision( $revision_id ) )
+ break;
+
+ if ( ! current_user_can( 'edit_post', $revision->post_parent ) )
+ break;
+
+ if ( ! $post = get_post( $revision->post_parent ) )
+ break;
+
+ // Revisions disabled (previously checked autosaves && ! wp_is_post_autosave( $revision ))
+ if ( ! wp_revisions_enabled( $post ) ) {
+ $redirect = 'edit.php?post_type=' . $post->post_type;
+ break;
+ }
+
+ // Don't allow revision restore when post is locked
+ if ( wp_check_post_lock( $post->ID ) )
+ break;
+
+ check_admin_referer( "restore-post_{$revision->ID}" );
+
+ wp_restore_post_revision( $revision->ID );
+ $redirect = add_query_arg( array( 'message' => 5, 'revision' => $revision->ID ), get_edit_post_link( $post->ID, 'url' ) );
+ break;
+case 'view' :
+case 'edit' :
+default :
+ if ( ! $revision = wp_get_post_revision( $revision_id ) )
+ break;
+ if ( ! $post = get_post( $revision->post_parent ) )
+ break;
+
+ if ( ! current_user_can( 'read_post', $revision->ID ) || ! current_user_can( 'read_post', $post->ID ) )
+ break;
+
+ // Revisions disabled and we're not looking at an autosave
+ if ( ! wp_revisions_enabled( $post ) && ! wp_is_post_autosave( $revision ) ) {
+ $redirect = 'edit.php?post_type=' . $post->post_type;
+ break;
+ }
+
+ $post_title = '<a href="' . get_edit_post_link() . '">' . _draft_or_post_title() . '</a>';
+ $h2 = sprintf( __( 'Compare Revisions of &#8220;%1$s&#8221;' ), $post_title );
+ $title = __( 'Revisions' );
+
+ $redirect = false;
+ break;
+endswitch;
+
+// Empty post_type means either malformed object found, or no valid parent was found.
+if ( ! $redirect && empty( $post->post_type ) )
+ $redirect = 'edit.php';
+
+if ( ! empty( $redirect ) ) {
+ wp_redirect( $redirect );
+ exit;
+}
+
+// This is so that the correct "Edit" menu item is selected.
+if ( ! empty( $post->post_type ) && 'post' != $post->post_type )
+ $parent_file = $submenu_file = 'edit.php?post_type=' . $post->post_type;
+else
+ $parent_file = $submenu_file = 'edit.php';
+
+wp_enqueue_script( 'revisions' );
+wp_localize_script( 'revisions', '_wpRevisionsSettings', wp_prepare_revisions_for_js( $post, $revision_id, $from ) );
+
+/* Revisions Help Tab */
+
+$revisions_overview = '<p>' . __( 'This screen is used for managing your content revisions.' ) . '</p>';
+$revisions_overview .= '<p>' . __( 'Revisions are saved copies of your post or page, which are periodically created as you update your content. The red text on the left shows the content that was removed. The green text on the right shows the content that was added.' ) . '</p>';
+$revisions_overview .= '<p>' . __( 'From this screen you can review, compare, and restore revisions:' ) . '</p>';
+$revisions_overview .= '<ul><li>' . __( 'To navigate between revisions, <strong>drag the slider handle left or right</strong> or <strong>use the Previous or Next buttons</strong>.' ) . '</li>';
+$revisions_overview .= '<li>' . __( 'Compare two different revisions by <strong>selecting the &#8220;Compare any two revisions&#8221; box</strong> to the side.' ) . '</li>';
+$revisions_overview .= '<li>' . __( 'To restore a revision, <strong>click Restore This Revision</strong>.' ) . '</li></ul>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'revisions-overview',
+ 'title' => __( 'Overview' ),
+ 'content' => $revisions_overview
+) );
+
+$revisions_sidebar = '<p><strong>' . __( 'For more information:' ) . '</strong></p>';
+$revisions_sidebar .= '<p>' . __( '<a href="http://codex.wordpress.org/Revision_Management" target="_blank">Revisions Management</a>' ) . '</p>';
+$revisions_sidebar .= '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>';
+
+get_current_screen()->set_help_sidebar( $revisions_sidebar );
+
+require_once( './admin-header.php' );
+
+?>
+
+<div class="wrap">
+ <?php screen_icon(); ?>
+ <h2 class="long-header"><?php echo $h2; ?></h2>
+</div>
+
+<script id="tmpl-revisions-frame" type="text/html">
+ <div class="revisions-control-frame"></div>
+ <div class="revisions-diff-frame"></div>
+</script>
+
+<script id="tmpl-revisions-buttons" type="text/html">
+ <div class="revisions-previous">
+ <input class="button" type="button" value="<?php echo esc_attr_x( 'Previous', 'Button label for a previous revision' ); ?>" />
+ </div>
+
+ <div class="revisions-next">
+ <input class="button" type="button" value="<?php echo esc_attr_x( 'Next', 'Button label for a next revision' ); ?>" />
+ </div>
+</script>
+
+<script id="tmpl-revisions-checkbox" type="text/html">
+ <div class="revision-toggle-compare-mode">
+ <label>
+ <input type="checkbox" class="compare-two-revisions"
+ <#
+ if ( 'undefined' !== typeof data && data.model.attributes.compareTwoMode ) {
+ #> checked="checked"<#
+ }
+ #>
+ />
+ <?php esc_attr_e( 'Compare any two revisions' ); ?>
+ </label>
+ </div>
+</script>
+
+<script id="tmpl-revisions-meta" type="text/html">
+ <# if ( ! _.isUndefined( data.attributes ) ) { #>
+ <div class="diff-title">
+ <# if ( 'from' === data.type ) { #>
+ <strong><?php _ex( 'From:', 'Followed by post revision info' ); ?></strong>
+ <# } else if ( 'to' === data.type ) { #>
+ <strong><?php _ex( 'To:', 'Followed by post revision info' ); ?></strong>
+ <# } #>
+ <div class="author-card<# if ( data.attributes.autosave ) { #> autosave<# } #>">
+ {{{ data.attributes.author.avatar }}}
+ <div class="author-info">
+ <# if ( data.attributes.autosave ) { #>
+ <span class="byline"><?php printf( __( 'Autosave by %s' ),
+ '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
+ <# } else if ( data.attributes.current ) { #>
+ <span class="byline"><?php printf( __( 'Current Revision by %s' ),
+ '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
+ <# } else { #>
+ <span class="byline"><?php printf( __( 'Revision by %s' ),
+ '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
+ <# } #>
+ <span class="time-ago">{{ data.attributes.timeAgo }}</span>
+ <span class="date">({{ data.attributes.dateShort }})</span>
+ </div>
+ <# if ( 'to' === data.type && data.attributes.restoreUrl ) { #>
+ <input <?php if ( wp_check_post_lock( $post->ID ) ) { ?>
+ disabled="disabled"
+ <?php } else { ?>
+ <# if ( data.attributes.current ) { #>
+ disabled="disabled"
+ <# } #>
+ <?php } ?>
+ <# if ( data.attributes.autosave ) { #>
+ type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Autosave' ); ?>" />
+ <# } else { #>
+ type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Revision' ); ?>" />
+ <# } #>
+ <# } #>
+ </div>
+ <# if ( 'tooltip' === data.type ) { #>
+ <div class="revisions-tooltip-arrow"><span></span></div>
+ <# } #>
+<# } #>
+</script>
+
+<script id="tmpl-revisions-diff" type="text/html">
+ <div class="loading-indicator"><span class="spinner"></span></div>
+ <div class="diff-error"><?php _e( 'Sorry, something went wrong. The requested comparison could not be loaded.' ); ?></div>
+ <div class="diff">
+ <# _.each( data.fields, function( field ) { #>
+ <h3>{{ field.name }}</h3>
+ {{{ field.diff }}}
+ <# }); #>
+ </div>
+</script>
+
+
+<?php
+require_once( './admin-footer.php' );
diff --git a/src/wp-admin/setup-config.php b/src/wp-admin/setup-config.php
new file mode 100644
index 0000000000..82d06e99dc
--- /dev/null
+++ b/src/wp-admin/setup-config.php
@@ -0,0 +1,295 @@
+<?php
+/**
+ * Retrieves and creates the wp-config.php file.
+ *
+ * The permissions for the base directory must allow for writing files in order
+ * for the wp-config.php to be created using this page.
+ *
+ * @internal This file must be parsable by PHP4.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * We are installing.
+ *
+ * @package WordPress
+ */
+define('WP_INSTALLING', true);
+
+/**
+ * We are blissfully unaware of anything.
+ */
+define('WP_SETUP_CONFIG', true);
+
+/**
+ * Disable error reporting
+ *
+ * Set this to error_reporting( E_ALL ) or error_reporting( E_ALL | E_STRICT ) for debugging
+ */
+error_reporting(0);
+
+/**#@+
+ * These three defines are required to allow us to use require_wp_db() to load
+ * the database class while being wp-content/db.php aware.
+ * @ignore
+ */
+define('ABSPATH', dirname(dirname(__FILE__)).'/');
+define('WPINC', 'wp-includes');
+define('WP_CONTENT_DIR', ABSPATH . 'wp-content');
+define('WP_DEBUG', false);
+/**#@-*/
+
+require(ABSPATH . WPINC . '/load.php');
+require(ABSPATH . WPINC . '/version.php');
+
+// Check for the required PHP version and for the MySQL extension or a database drop-in.
+wp_check_php_mysql_versions();
+
+require_once(ABSPATH . WPINC . '/functions.php');
+
+// Also loads plugin.php, l10n.php, pomo/mo.php (all required by setup-config.php)
+wp_load_translations_early();
+
+// Turn register_globals off.
+wp_unregister_GLOBALS();
+
+require_once(ABSPATH . WPINC . '/compat.php');
+require_once(ABSPATH . WPINC . '/class-wp-error.php');
+require_once(ABSPATH . WPINC . '/formatting.php');
+
+// Add magic quotes and set up $_REQUEST ( $_GET + $_POST )
+wp_magic_quotes();
+
+if ( ! file_exists( ABSPATH . 'wp-config-sample.php' ) )
+ wp_die( __( 'Sorry, I need a wp-config-sample.php file to work from. Please re-upload this file from your WordPress installation.' ) );
+
+$config_file = file(ABSPATH . 'wp-config-sample.php');
+
+// Check if wp-config.php has been created
+if ( file_exists( ABSPATH . 'wp-config.php' ) )
+ wp_die( '<p>' . sprintf( __( "The file 'wp-config.php' already exists. If you need to reset any of the configuration items in this file, please delete it first. You may try <a href='%s'>installing now</a>." ), 'install.php' ) . '</p>' );
+
+// Check if wp-config.php exists above the root directory but is not part of another install
+if ( file_exists(ABSPATH . '../wp-config.php' ) && ! file_exists( ABSPATH . '../wp-settings.php' ) )
+ wp_die( '<p>' . sprintf( __( "The file 'wp-config.php' already exists one level above your WordPress installation. If you need to reset any of the configuration items in this file, please delete it first. You may try <a href='install.php'>installing now</a>."), 'install.php' ) . '</p>' );
+
+$step = isset( $_GET['step'] ) ? (int) $_GET['step'] : 0;
+
+/**
+ * Display setup wp-config.php file header.
+ *
+ * @ignore
+ * @since 2.3.0
+ * @package WordPress
+ * @subpackage Installer_WP_Config
+ */
+function setup_config_display_header() {
+ global $wp_version;
+
+ header( 'Content-Type: text/html; charset=utf-8' );
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php _e( 'WordPress &rsaquo; Setup Configuration File' ); ?></title>
+<link rel="stylesheet" href="css/install.css?ver=<?php echo preg_replace( '/[^0-9a-z\.-]/i', '', $wp_version ); ?>" type="text/css" />
+<link rel="stylesheet" href="../wp-includes/css/buttons.css?ver=<?php echo preg_replace( '/[^0-9a-z\.-]/i', '', $wp_version ); ?>" type="text/css" />
+
+</head>
+<body class="wp-core-ui<?php if ( is_rtl() ) echo ' rtl'; ?>">
+<h1 id="logo"><a href="<?php esc_attr_e( 'http://wordpress.org/' ); ?>"><?php _e( 'WordPress' ); ?></a></h1>
+<?php
+} // end function setup_config_display_header();
+
+switch($step) {
+ case 0:
+ setup_config_display_header();
+?>
+
+<p><?php _e( 'Welcome to WordPress. Before getting started, we need some information on the database. You will need to know the following items before proceeding.' ) ?></p>
+<ol>
+ <li><?php _e( 'Database name' ); ?></li>
+ <li><?php _e( 'Database username' ); ?></li>
+ <li><?php _e( 'Database password' ); ?></li>
+ <li><?php _e( 'Database host' ); ?></li>
+ <li><?php _e( 'Table prefix (if you want to run more than one WordPress in a single database)' ); ?></li>
+</ol>
+<p><strong><?php _e( "If for any reason this automatic file creation doesn&#8217;t work, don&#8217;t worry. All this does is fill in the database information to a configuration file. You may also simply open <code>wp-config-sample.php</code> in a text editor, fill in your information, and save it as <code>wp-config.php</code>." ); ?></strong></p>
+<p><?php _e( "In all likelihood, these items were supplied to you by your Web Host. If you do not have this information, then you will need to contact them before you can continue. If you&#8217;re all ready&hellip;" ); ?></p>
+
+<p class="step"><a href="setup-config.php?step=1<?php if ( isset( $_GET['noapi'] ) ) echo '&amp;noapi'; ?>" class="button button-large"><?php _e( 'Let&#8217;s go!' ); ?></a></p>
+<?php
+ break;
+
+ case 1:
+ setup_config_display_header();
+ ?>
+<form method="post" action="setup-config.php?step=2">
+ <p><?php _e( "Below you should enter your database connection details. If you&#8217;re not sure about these, contact your host." ); ?></p>
+ <table class="form-table">
+ <tr>
+ <th scope="row"><label for="dbname"><?php _e( 'Database Name' ); ?></label></th>
+ <td><input name="dbname" id="dbname" type="text" size="25" value="wordpress" /></td>
+ <td><?php _e( 'The name of the database you want to run WP in.' ); ?></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="uname"><?php _e( 'User Name' ); ?></label></th>
+ <td><input name="uname" id="uname" type="text" size="25" value="<?php echo htmlspecialchars( _x( 'username', 'example username' ), ENT_QUOTES ); ?>" /></td>
+ <td><?php _e( 'Your MySQL username' ); ?></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="pwd"><?php _e( 'Password' ); ?></label></th>
+ <td><input name="pwd" id="pwd" type="text" size="25" value="<?php echo htmlspecialchars( _x( 'password', 'example password' ), ENT_QUOTES ); ?>" /></td>
+ <td><?php _e( '&hellip;and your MySQL password.' ); ?></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="dbhost"><?php _e( 'Database Host' ); ?></label></th>
+ <td><input name="dbhost" id="dbhost" type="text" size="25" value="localhost" /></td>
+ <td><?php _e( 'You should be able to get this info from your web host, if <code>localhost</code> does not work.' ); ?></td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="prefix"><?php _e( 'Table Prefix' ); ?></label></th>
+ <td><input name="prefix" id="prefix" type="text" value="wp_" size="25" /></td>
+ <td><?php _e( 'If you want to run multiple WordPress installations in a single database, change this.' ); ?></td>
+ </tr>
+ </table>
+ <?php if ( isset( $_GET['noapi'] ) ) { ?><input name="noapi" type="hidden" value="1" /><?php } ?>
+ <p class="step"><input name="submit" type="submit" value="<?php echo htmlspecialchars( __( 'Submit' ), ENT_QUOTES ); ?>" class="button button-large" /></p>
+</form>
+<?php
+ break;
+
+ case 2:
+ foreach ( array( 'dbname', 'uname', 'pwd', 'dbhost', 'prefix' ) as $key )
+ $$key = trim( wp_unslash( $_POST[ $key ] ) );
+
+ $tryagain_link = '</p><p class="step"><a href="setup-config.php?step=1" onclick="javascript:history.go(-1);return false;" class="button button-large">' . __( 'Try again' ) . '</a>';
+
+ if ( empty( $prefix ) )
+ wp_die( __( '<strong>ERROR</strong>: "Table Prefix" must not be empty.' . $tryagain_link ) );
+
+ // Validate $prefix: it can only contain letters, numbers and underscores.
+ if ( preg_match( '|[^a-z0-9_]|i', $prefix ) )
+ wp_die( __( '<strong>ERROR</strong>: "Table Prefix" can only contain numbers, letters, and underscores.' . $tryagain_link ) );
+
+ // Test the db connection.
+ /**#@+
+ * @ignore
+ */
+ define('DB_NAME', $dbname);
+ define('DB_USER', $uname);
+ define('DB_PASSWORD', $pwd);
+ define('DB_HOST', $dbhost);
+ /**#@-*/
+
+ // We'll fail here if the values are no good.
+ require_wp_db();
+ if ( ! empty( $wpdb->error ) )
+ wp_die( $wpdb->error->get_error_message() . $tryagain_link );
+
+ // Fetch or generate keys and salts.
+ $no_api = isset( $_POST['noapi'] );
+ if ( ! $no_api ) {
+ require_once( ABSPATH . WPINC . '/class-http.php' );
+ require_once( ABSPATH . WPINC . '/http.php' );
+ wp_fix_server_vars();
+ /**#@+
+ * @ignore
+ */
+ function get_bloginfo() {
+ return ( ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . str_replace( $_SERVER['PHP_SELF'], '/wp-admin/setup-config.php', '' ) );
+ }
+ /**#@-*/
+ $secret_keys = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' );
+ }
+
+ if ( $no_api || is_wp_error( $secret_keys ) ) {
+ $secret_keys = array();
+ require_once( ABSPATH . WPINC . '/pluggable.php' );
+ for ( $i = 0; $i < 8; $i++ ) {
+ $secret_keys[] = wp_generate_password( 64, true, true );
+ }
+ } else {
+ $secret_keys = explode( "\n", wp_remote_retrieve_body( $secret_keys ) );
+ foreach ( $secret_keys as $k => $v ) {
+ $secret_keys[$k] = substr( $v, 28, 64 );
+ }
+ }
+
+ $key = 0;
+ // Not a PHP5-style by-reference foreach, as this file must be parseable by PHP4.
+ foreach ( $config_file as $line_num => $line ) {
+ if ( '$table_prefix =' == substr( $line, 0, 16 ) ) {
+ $config_file[ $line_num ] = '$table_prefix = \'' . addcslashes( $prefix, "\\'" ) . "';\r\n";
+ continue;
+ }
+
+ if ( ! preg_match( '/^define\(\'([A-Z_]+)\',([ ]+)/', $line, $match ) )
+ continue;
+
+ $constant = $match[1];
+ $padding = $match[2];
+
+ switch ( $constant ) {
+ case 'DB_NAME' :
+ case 'DB_USER' :
+ case 'DB_PASSWORD' :
+ case 'DB_HOST' :
+ $config_file[ $line_num ] = "define('" . $constant . "'," . $padding . "'" . addcslashes( constant( $constant ), "\\'" ) . "');\r\n";
+ break;
+ case 'AUTH_KEY' :
+ case 'SECURE_AUTH_KEY' :
+ case 'LOGGED_IN_KEY' :
+ case 'NONCE_KEY' :
+ case 'AUTH_SALT' :
+ case 'SECURE_AUTH_SALT' :
+ case 'LOGGED_IN_SALT' :
+ case 'NONCE_SALT' :
+ $config_file[ $line_num ] = "define('" . $constant . "'," . $padding . "'" . $secret_keys[$key++] . "');\r\n";
+ break;
+ }
+ }
+ unset( $line );
+
+ if ( ! is_writable(ABSPATH) ) :
+ setup_config_display_header();
+?>
+<p><?php _e( "Sorry, but I can&#8217;t write the <code>wp-config.php</code> file." ); ?></p>
+<p><?php _e( 'You can create the <code>wp-config.php</code> manually and paste the following text into it.' ); ?></p>
+<textarea id="wp-config" cols="98" rows="15" class="code" readonly="readonly"><?php
+ foreach( $config_file as $line ) {
+ echo htmlentities($line, ENT_COMPAT, 'UTF-8');
+ }
+?></textarea>
+<p><?php _e( 'After you&#8217;ve done that, click &#8220;Run the install.&#8221;' ); ?></p>
+<p class="step"><a href="install.php" class="button button-large"><?php _e( 'Run the install' ); ?></a></p>
+<script>
+(function(){
+var el=document.getElementById('wp-config');
+el.focus();
+el.select();
+})();
+</script>
+<?php
+ else :
+ $handle = fopen(ABSPATH . 'wp-config.php', 'w');
+ foreach( $config_file as $line ) {
+ fwrite($handle, $line);
+ }
+ fclose($handle);
+ chmod(ABSPATH . 'wp-config.php', 0666);
+ setup_config_display_header();
+?>
+<p><?php _e( "All right, sparky! You&#8217;ve made it through this part of the installation. WordPress can now communicate with your database. If you are ready, time now to&hellip;" ); ?></p>
+
+<p class="step"><a href="install.php" class="button button-large"><?php _e( 'Run the install' ); ?></a></p>
+<?php
+ endif;
+ break;
+}
+?>
+</body>
+</html>
diff --git a/src/wp-admin/theme-editor.php b/src/wp-admin/theme-editor.php
new file mode 100644
index 0000000000..8f95cab11f
--- /dev/null
+++ b/src/wp-admin/theme-editor.php
@@ -0,0 +1,246 @@
+<?php
+/**
+ * Theme editor administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( is_multisite() && ! is_network_admin() ) {
+ wp_redirect( network_admin_url( 'theme-editor.php' ) );
+ exit();
+}
+
+if ( !current_user_can('edit_themes') )
+ wp_die('<p>'.__('You do not have sufficient permissions to edit templates for this site.').'</p>');
+
+$title = __("Edit Themes");
+$parent_file = 'themes.php';
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __('You can use the Theme Editor to edit the individual CSS and PHP files which make up your theme.') . '</p>
+ <p>' . __('Begin by choosing a theme to edit from the dropdown menu and clicking Select. A list then appears of all the template files. Clicking once on any file name causes the file to appear in the large Editor box.') . '</p>
+ <p>' . __('For PHP files, you can use the Documentation dropdown to select from functions recognized in that file. Look Up takes you to a web page with reference material about that particular function.') . '</p>
+ <p id="newcontent-description">' . __('In the editing area the Tab key enters a tab character. To move below this area by pressing Tab, press the Esc key followed by the Tab key.') . '</p>
+ <p>' . __('After typing in your edits, click Update File.') . '</p>
+ <p>' . __('<strong>Advice:</strong> think very carefully about your site crashing if you are live-editing the theme currently in use.') . '</p>
+ <p>' . __('Upgrading to a newer version of the same theme will override changes made here. To avoid this, consider creating a <a href="http://codex.wordpress.org/Child_Themes" target="_blank">child theme</a> instead.') . '</p>' .
+ ( is_network_admin() ? '<p>' . __('Any edits to files from this screen will be reflected on all sites in the network.') . '</p>' : '' )
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Theme_Development" target="_blank">Documentation on Theme Development</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Using_Themes" target="_blank">Documentation on Using Themes</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Editing_Files" target="_blank">Documentation on Editing Files</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Template_Tags" target="_blank">Documentation on Template Tags</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+wp_reset_vars( array( 'action', 'error', 'file', 'theme' ) );
+
+if ( $theme )
+ $stylesheet = $theme;
+else
+ $stylesheet = get_stylesheet();
+
+$theme = wp_get_theme( $stylesheet );
+
+if ( ! $theme->exists() )
+ wp_die( __( 'The requested theme does not exist.' ) );
+
+if ( $theme->errors() && 'theme_no_stylesheet' == $theme->errors()->get_error_code() )
+ wp_die( __( 'The requested theme does not exist.' ) . ' ' . $theme->errors()->get_error_message() );
+
+$allowed_files = $theme->get_files( 'php', 1 );
+$has_templates = ! empty( $allowed_files );
+$style_files = $theme->get_files( 'css' );
+$allowed_files['style.css'] = $style_files['style.css'];
+$allowed_files += $style_files;
+
+if ( empty( $file ) ) {
+ $relative_file = 'style.css';
+ $file = $allowed_files['style.css'];
+} else {
+ $relative_file = $file;
+ $file = $theme->get_stylesheet_directory() . '/' . $relative_file;
+}
+
+validate_file_to_edit( $file, $allowed_files );
+$scrollto = isset( $_REQUEST['scrollto'] ) ? (int) $_REQUEST['scrollto'] : 0;
+
+switch( $action ) {
+case 'update':
+ check_admin_referer( 'edit-theme_' . $file . $stylesheet );
+ $newcontent = wp_unslash( $_POST['newcontent'] );
+ $location = 'theme-editor.php?file=' . urlencode( $relative_file ) . '&theme=' . urlencode( $stylesheet ) . '&scrollto=' . $scrollto;
+ if ( is_writeable( $file ) ) {
+ //is_writable() not always reliable, check return value. see comments @ http://uk.php.net/is_writable
+ $f = fopen( $file, 'w+' );
+ if ( $f !== false ) {
+ fwrite( $f, $newcontent );
+ fclose( $f );
+ $location .= '&updated=true';
+ $theme->cache_delete();
+ }
+ }
+ wp_redirect( $location );
+ exit;
+break;
+
+default:
+
+ require_once( ABSPATH . 'wp-admin/admin-header.php' );
+
+ update_recently_edited( $file );
+
+ if ( ! is_file( $file ) )
+ $error = true;
+
+ $content = '';
+ if ( ! $error && filesize( $file ) > 0 ) {
+ $f = fopen($file, 'r');
+ $content = fread($f, filesize($file));
+
+ if ( '.php' == substr( $file, strrpos( $file, '.' ) ) ) {
+ $functions = wp_doc_link_parse( $content );
+
+ $docs_select = '<select name="docs-list" id="docs-list">';
+ $docs_select .= '<option value="">' . esc_attr__( 'Function Name&hellip;' ) . '</option>';
+ foreach ( $functions as $function ) {
+ $docs_select .= '<option value="' . esc_attr( urlencode( $function ) ) . '">' . htmlspecialchars( $function ) . '()</option>';
+ }
+ $docs_select .= '</select>';
+ }
+
+ $content = esc_textarea( $content );
+ }
+
+ ?>
+<?php if ( isset( $_GET['updated'] ) ) : ?>
+ <div id="message" class="updated"><p><?php _e( 'File edited successfully.' ) ?></p></div>
+<?php endif;
+
+$description = get_file_description( $file );
+$file_show = array_search( $file, array_filter( $allowed_files ) );
+if ( $description != $file_show )
+ $description .= ' <span>(' . $file_show . ')</span>';
+?>
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<div class="fileedit-sub">
+<div class="alignleft">
+<h3><?php echo $theme->display('Name'); if ( $description ) echo ': ' . $description; ?></h3>
+</div>
+<div class="alignright">
+ <form action="theme-editor.php" method="post">
+ <strong><label for="theme"><?php _e('Select theme to edit:'); ?> </label></strong>
+ <select name="theme" id="theme">
+<?php
+foreach ( wp_get_themes( array( 'errors' => null ) ) as $a_stylesheet => $a_theme ) {
+ if ( $a_theme->errors() && 'theme_no_stylesheet' == $a_theme->errors()->get_error_code() )
+ continue;
+
+ $selected = $a_stylesheet == $stylesheet ? ' selected="selected"' : '';
+ echo "\n\t" . '<option value="' . esc_attr( $a_stylesheet ) . '"' . $selected . '>' . $a_theme->display('Name') . '</option>';
+}
+?>
+ </select>
+ <?php submit_button( __( 'Select' ), 'button', 'Submit', false ); ?>
+ </form>
+</div>
+<br class="clear" />
+</div>
+<?php
+if ( $theme->errors() )
+ echo '<div class="error"><p><strong>' . __( 'This theme is broken.' ) . '</strong> ' . $theme->errors()->get_error_message() . '</p></div>';
+?>
+ <div id="templateside">
+<?php
+if ( $allowed_files ) :
+ if ( $has_templates || $theme->parent() ) :
+?>
+ <h3><?php _e('Templates'); ?></h3>
+ <?php if ( $theme->parent() ) : ?>
+ <p class="howto"><?php printf( __( 'This child theme inherits templates from a parent theme, %s.' ), '<a href="' . self_admin_url('theme-editor.php?theme=' . urlencode( $theme->get_template() ) ) . '">' . $theme->parent()->display('Name') . '</a>' ); ?></p>
+ <?php endif; ?>
+ <ul>
+<?php
+ endif;
+
+ foreach ( $allowed_files as $filename => $absolute_filename ) :
+ if ( 'style.css' == $filename )
+ echo "\t</ul>\n\t<h3>" . _x( 'Styles', 'Theme stylesheets in theme editor' ) . "</h3>\n\t<ul>\n";
+
+ $file_description = get_file_description( $absolute_filename );
+ if ( $file_description != basename( $filename ) )
+ $file_description .= '<br /><span class="nonessential">(' . $filename . ')</span>';
+
+ if ( $absolute_filename == $file )
+ $file_description = '<span class="highlight">' . $file_description . '</span>';
+?>
+ <li><a href="theme-editor.php?file=<?php echo urlencode( $filename ) ?>&amp;theme=<?php echo urlencode( $stylesheet ) ?>"><?php echo $file_description; ?></a></li>
+<?php
+ endforeach;
+?>
+</ul>
+<?php endif; ?>
+</div>
+<?php if ( $error ) :
+ echo '<div class="error"><p>' . __('Oops, no such file exists! Double check the name and try again, merci.') . '</p></div>';
+else : ?>
+ <form name="template" id="template" action="theme-editor.php" method="post">
+ <?php wp_nonce_field( 'edit-theme_' . $file . $stylesheet ); ?>
+ <div><textarea cols="70" rows="30" name="newcontent" id="newcontent" aria-describedby="newcontent-description"><?php echo $content; ?></textarea>
+ <input type="hidden" name="action" value="update" />
+ <input type="hidden" name="file" value="<?php echo esc_attr( $relative_file ); ?>" />
+ <input type="hidden" name="theme" value="<?php echo esc_attr( $theme->get_stylesheet() ); ?>" />
+ <input type="hidden" name="scrollto" id="scrollto" value="<?php echo $scrollto; ?>" />
+ </div>
+ <?php if ( ! empty( $functions ) ) : ?>
+ <div id="documentation" class="hide-if-no-js">
+ <label for="docs-list"><?php _e('Documentation:') ?></label>
+ <?php echo $docs_select; ?>
+ <input type="button" class="button" value=" <?php esc_attr_e( 'Look Up' ); ?> " onclick="if ( '' != jQuery('#docs-list').val() ) { window.open( 'http://api.wordpress.org/core/handbook/1.0/?function=' + escape( jQuery( '#docs-list' ).val() ) + '&amp;locale=<?php echo urlencode( get_locale() ) ?>&amp;version=<?php echo urlencode( $wp_version ) ?>&amp;redirect=true'); }" />
+ </div>
+ <?php endif; ?>
+
+ <div>
+ <?php if ( is_child_theme() && $theme->get_stylesheet() == get_template() ) : ?>
+ <p><?php if ( is_writeable( $file ) ) { ?><strong><?php _e( 'Caution:' ); ?></strong><?php } ?>
+ <?php _e( 'This is a file in your current parent theme.' ); ?></p>
+ <?php endif; ?>
+<?php
+ if ( is_writeable( $file ) ) :
+ submit_button( __( 'Update File' ), 'primary', 'submit', true );
+ else : ?>
+<p><em><?php _e('You need to make this file writable before you can save your changes. See <a href="http://codex.wordpress.org/Changing_File_Permissions">the Codex</a> for more information.'); ?></em></p>
+<?php endif; ?>
+ </div>
+ </form>
+<?php
+endif; // $error
+?>
+<br class="clear" />
+</div>
+<script type="text/javascript">
+/* <![CDATA[ */
+jQuery(document).ready(function($){
+ $('#template').submit(function(){ $('#scrollto').val( $('#newcontent').scrollTop() ); });
+ $('#newcontent').scrollTop( $('#scrollto').val() );
+});
+/* ]]> */
+</script>
+<?php
+break;
+}
+
+include(ABSPATH . 'wp-admin/admin-footer.php' );
diff --git a/src/wp-admin/theme-install.php b/src/wp-admin/theme-install.php
new file mode 100644
index 0000000000..14d9f52e84
--- /dev/null
+++ b/src/wp-admin/theme-install.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Install theme administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+if ( !defined( 'IFRAME_REQUEST' ) && isset( $_GET['tab'] ) && ( 'theme-information' == $_GET['tab'] ) )
+ define( 'IFRAME_REQUEST', true );
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( ! current_user_can('install_themes') )
+ wp_die( __( 'You do not have sufficient permissions to install themes on this site.' ) );
+
+if ( is_multisite() && ! is_network_admin() ) {
+ wp_redirect( network_admin_url( 'theme-install.php' ) );
+ exit();
+}
+
+$wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+$wp_list_table->prepare_items();
+
+$title = __('Install Themes');
+$parent_file = 'themes.php';
+if ( !is_network_admin() )
+ $submenu_file = 'themes.php';
+
+wp_enqueue_script( 'theme-install' );
+wp_enqueue_script( 'theme' );
+
+$body_id = $tab;
+
+do_action('install_themes_pre_' . $tab); //Used to override the general interface, Eg, install or theme information.
+
+$help_overview =
+ '<p>' . sprintf(__('You can find additional themes for your site by using the Theme Browser/Installer on this screen, which will display themes from the <a href="%s" target="_blank">WordPress.org Theme Directory</a>. These themes are designed and developed by third parties, are available free of charge, and are compatible with the license WordPress uses.'), 'http://wordpress.org/themes/') . '</p>' .
+ '<p>' . __('You can Search for themes by keyword, author, or tag, or can get more specific and search by criteria listed in the feature filter. Alternately, you can browse the themes that are Featured, Newest, or Recently Updated. When you find a theme you like, you can preview it or install it.') . '</p>' .
+ '<p>' . __('You can Upload a theme manually if you have already downloaded its ZIP archive onto your computer (make sure it is from a trusted and original source). You can also do it the old-fashioned way and copy a downloaded theme&#8217;s folder via FTP into your <code>/wp-content/themes</code> directory.') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $help_overview
+) );
+
+$help_installing =
+ '<p>' . __('Once you have generated a list of themes, you can preview and install any of them. Click on the thumbnail of the theme you&#8217;re interested in previewing. It will open up in a full-screen Preview page to give you a better idea of how that theme will look.') . '</p>' .
+ '<p>' . __('To install the theme so you can preview it with your site&#8217;s content and customize its theme options, click the "Install" button at the top of the left-hand pane. The theme files will be downloaded to your website automatically. When this is complete, the theme is now available for activation, which you can do by clicking the "Activate" link, or by navigating to your Manage Themes screen and clicking the "Live Preview" link under any installed theme&#8217;s thumbnail image.') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'installing',
+ 'title' => __('Previewing and Installing'),
+ 'content' => $help_installing
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Using_Themes#Adding_New_Themes" target="_blank">Documentation on Adding New Themes</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+include(ABSPATH . 'wp-admin/admin-header.php');
+?>
+<div class="wrap">
+<?php
+screen_icon();
+
+if ( is_network_admin() ) : ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+<?php else : ?>
+<h2 class="nav-tab-wrapper"><a href="themes.php" class="nav-tab"><?php echo esc_html_x('Manage Themes', 'theme'); ?></a><a href="theme-install.php" class="nav-tab nav-tab-active"><?php echo esc_html( $title ); ?></a></h2>
+
+<?php
+endif;
+
+$wp_list_table->views(); ?>
+
+<br class="clear" />
+<?php do_action('install_themes_' . $tab, $paged); ?>
+</div>
+<?php
+include(ABSPATH . 'wp-admin/admin-footer.php');
diff --git a/src/wp-admin/themes.php b/src/wp-admin/themes.php
new file mode 100644
index 0000000000..14ed887da0
--- /dev/null
+++ b/src/wp-admin/themes.php
@@ -0,0 +1,311 @@
+<?php
+/**
+ * Themes administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( !current_user_can('switch_themes') && !current_user_can('edit_theme_options') )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+$wp_list_table = _get_list_table('WP_Themes_List_Table');
+
+if ( current_user_can( 'switch_themes' ) && isset($_GET['action'] ) ) {
+ if ( 'activate' == $_GET['action'] ) {
+ check_admin_referer('switch-theme_' . $_GET['stylesheet']);
+ $theme = wp_get_theme( $_GET['stylesheet'] );
+ if ( ! $theme->exists() || ! $theme->is_allowed() )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+ switch_theme( $theme->get_stylesheet() );
+ wp_redirect( admin_url('themes.php?activated=true') );
+ exit;
+ } elseif ( 'delete' == $_GET['action'] ) {
+ check_admin_referer('delete-theme_' . $_GET['stylesheet']);
+ $theme = wp_get_theme( $_GET['stylesheet'] );
+ if ( !current_user_can('delete_themes') || ! $theme->exists() )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+ delete_theme($_GET['stylesheet']);
+ wp_redirect( admin_url('themes.php?deleted=true') );
+ exit;
+ }
+}
+
+$wp_list_table->prepare_items();
+
+$title = __('Manage Themes');
+$parent_file = 'themes.php';
+
+if ( current_user_can( 'switch_themes' ) ) :
+
+$help_manage = '<p>' . __('Aside from the default theme included with your WordPress installation, themes are designed and developed by third parties.') . '</p>' .
+ '<p>' . __('You can see your active theme at the top of the screen. Below are the other themes you have installed that are not currently in use. You can see what your site would look like with one of these themes by clicking the Live Preview link (see "Previewing and Customizing" help tab). To change themes, click the Activate link.') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $help_manage
+) );
+
+if ( current_user_can( 'install_themes' ) ) {
+ if ( is_multisite() ) {
+ $help_install = '<p>' . __('Installing themes on Multisite can only be done from the Network Admin section.') . '</p>';
+ } else {
+ $help_install = '<p>' . sprintf( __('If you would like to see more themes to choose from, click on the &#8220;Install Themes&#8221; tab and you will be able to browse or search for additional themes from the <a href="%s" target="_blank">WordPress.org Theme Directory</a>. Themes in the WordPress.org Theme Directory are designed and developed by third parties, and are compatible with the license WordPress uses. Oh, and they&#8217;re free!'), 'http://wordpress.org/themes/' ) . '</p>';
+ }
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'adding-themes',
+ 'title' => __('Adding Themes'),
+ 'content' => $help_install
+ ) );
+}
+
+add_thickbox();
+
+endif; // switch_themes
+
+if ( current_user_can( 'edit_theme_options' ) ) {
+ $help_customize =
+ '<p>' . __('Click on the "Live Preview" link under any theme to preview that theme and change theme options in a separate, full-screen view. Any installed theme can be previewed and customized in this way.') . '</p>'.
+ '<p>' . __('The theme being previewed is fully interactive &mdash; navigate to different pages to see how the theme handles posts, archives, and other page templates.') . '</p>' .
+ '<p>' . __('In the left-hand pane you can edit the theme settings. The settings will differ, depending on what theme features the theme being previewed supports. To accept the new settings and activate the theme all in one step, click the "Save &amp; Activate" button at the top of the left-hand pane.') . '</p>' .
+ '<p>' . __('When previewing on smaller monitors, you can use the "Collapse" icon at the bottom of the left-hand pane. This will hide the pane, giving you more room to preview your site in the new theme. To bring the pane back, click on the Collapse icon again.') . '</p>';
+
+ get_current_screen()->add_help_tab( array(
+ 'id' => 'customize-preview-themes',
+ 'title' => __('Previewing and Customizing'),
+ 'content' => $help_customize
+ ) );
+}
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Using_Themes" target="_blank">Documentation on Using Themes</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+wp_enqueue_script( 'theme' );
+wp_enqueue_script( 'customize-loader' );
+
+require_once('./admin-header.php');
+?>
+
+<div class="wrap"><?php
+screen_icon();
+if ( ! is_multisite() && current_user_can( 'install_themes' ) ) : ?>
+<h2 class="nav-tab-wrapper">
+<a href="themes.php" class="nav-tab nav-tab-active"><?php echo esc_html( $title ); ?></a><a href="<?php echo admin_url( 'theme-install.php'); ?>" class="nav-tab"><?php echo esc_html_x('Install Themes', 'theme'); ?></a>
+<?php else : ?>
+<h2><?php echo esc_html( $title ); ?>
+<?php endif; ?>
+</h2>
+<?php
+if ( ! validate_current_theme() || isset( $_GET['broken'] ) ) : ?>
+<div id="message1" class="updated"><p><?php _e('The active theme is broken. Reverting to the default theme.'); ?></p></div>
+<?php elseif ( isset($_GET['activated']) ) :
+ if ( isset( $_GET['previewed'] ) ) { ?>
+ <div id="message2" class="updated"><p><?php printf( __( 'Settings saved and theme activated. <a href="%s">Visit site</a>' ), home_url( '/' ) ); ?></p></div>
+ <?php } else { ?>
+<div id="message2" class="updated"><p><?php printf( __( 'New theme activated. <a href="%s">Visit site</a>' ), home_url( '/' ) ); ?></p></div><?php
+ }
+ elseif ( isset($_GET['deleted']) ) : ?>
+<div id="message3" class="updated"><p><?php _e('Theme deleted.') ?></p></div>
+<?php
+endif;
+
+$ct = wp_get_theme();
+$screenshot = $ct->get_screenshot();
+$class = $screenshot ? 'has-screenshot' : '';
+
+$customize_title = sprintf( __( 'Customize &#8220;%s&#8221;' ), $ct->display('Name') );
+
+?>
+<div id="current-theme" class="<?php echo esc_attr( $class ); ?>">
+ <?php if ( $screenshot ) : ?>
+ <?php if ( current_user_can( 'edit_theme_options' ) ) : ?>
+ <a href="<?php echo wp_customize_url(); ?>" class="load-customize hide-if-no-customize" title="<?php echo esc_attr( $customize_title ); ?>">
+ <img src="<?php echo esc_url( $screenshot ); ?>" alt="<?php esc_attr_e( 'Current theme preview' ); ?>" />
+ </a>
+ <?php endif; ?>
+ <img class="hide-if-customize" src="<?php echo esc_url( $screenshot ); ?>" alt="<?php esc_attr_e( 'Current theme preview' ); ?>" />
+ <?php endif; ?>
+
+ <h3><?php _e('Current Theme'); ?></h3>
+ <h4>
+ <?php echo $ct->display('Name'); ?>
+ </h4>
+
+ <div>
+ <ul class="theme-info">
+ <li><?php printf( __('By %s'), $ct->display('Author') ); ?></li>
+ <li><?php printf( __('Version %s'), $ct->display('Version') ); ?></li>
+ </ul>
+ <p class="theme-description"><?php echo $ct->display('Description'); ?></p>
+ <?php if ( $ct->parent() ) {
+ printf( ' <p class="howto">' . __( 'This <a href="%1$s">child theme</a> requires its parent theme, %2$s.' ) . '</p>',
+ __( 'http://codex.wordpress.org/Child_Themes' ),
+ $ct->parent()->display( 'Name' ) );
+ } ?>
+ <?php theme_update_available( $ct ); ?>
+ </div>
+
+ <?php
+ // Pretend you didn't see this.
+ $options = array();
+ if ( is_array( $submenu ) && isset( $submenu['themes.php'] ) ) {
+ foreach ( (array) $submenu['themes.php'] as $item) {
+ $class = '';
+ if ( 'themes.php' == $item[2] || 'theme-editor.php' == $item[2] || 'customize.php' == $item[2] )
+ continue;
+ // 0 = name, 1 = capability, 2 = file
+ if ( ( strcmp($self, $item[2]) == 0 && empty($parent_file)) || ($parent_file && ($item[2] == $parent_file)) )
+ $class = ' class="current"';
+ if ( !empty($submenu[$item[2]]) ) {
+ $submenu[$item[2]] = array_values($submenu[$item[2]]); // Re-index.
+ $menu_hook = get_plugin_page_hook($submenu[$item[2]][0][2], $item[2]);
+ if ( file_exists(WP_PLUGIN_DIR . "/{$submenu[$item[2]][0][2]}") || !empty($menu_hook))
+ $options[] = "<a href='admin.php?page={$submenu[$item[2]][0][2]}'$class>{$item[0]}</a>";
+ else
+ $options[] = "<a href='{$submenu[$item[2]][0][2]}'$class>{$item[0]}</a>";
+ } else if ( current_user_can($item[1]) ) {
+ $menu_file = $item[2];
+ if ( false !== ( $pos = strpos( $menu_file, '?' ) ) )
+ $menu_file = substr( $menu_file, 0, $pos );
+ if ( file_exists( ABSPATH . "wp-admin/$menu_file" ) ) {
+ $options[] = "<a href='{$item[2]}'$class>{$item[0]}</a>";
+ } else {
+ $options[] = "<a href='themes.php?page={$item[2]}'$class>{$item[0]}</a>";
+ }
+ }
+ }
+ }
+
+ if ( $options || current_user_can( 'edit_theme_options' ) ) :
+ ?>
+ <div class="theme-options">
+ <?php if ( current_user_can( 'edit_theme_options' ) ) : ?>
+ <a id="customize-current-theme-link" href="<?php echo wp_customize_url(); ?>" class="load-customize hide-if-no-customize" title="<?php echo esc_attr( $customize_title ); ?>"><?php _e( 'Customize' ); ?></a>
+ <?php
+ endif; // edit_theme_options
+ if ( $options ) :
+ ?>
+ <span><?php _e( 'Options:' )?></span>
+ <ul>
+ <?php foreach ( $options as $option ) : ?>
+ <li><?php echo $option; ?></li>
+ <?php endforeach; ?>
+ </ul>
+ <?php
+ endif; // options
+ ?>
+ </div>
+ <?php
+ endif; // options || edit_theme_options
+ ?>
+
+</div>
+
+<br class="clear" />
+<?php
+if ( ! current_user_can( 'switch_themes' ) ) {
+ echo '</div>';
+ require( './admin-footer.php' );
+ exit;
+}
+?>
+
+<form class="search-form filter-form" action="" method="get">
+
+<h3 class="available-themes"><?php _e('Available Themes'); ?></h3>
+
+<?php if ( !empty( $_REQUEST['s'] ) || !empty( $_REQUEST['features'] ) || $wp_list_table->has_items() ) : ?>
+
+<p class="search-box">
+ <label class="screen-reader-text" for="theme-search-input"><?php _e('Search Installed Themes'); ?>:</label>
+ <input type="search" id="theme-search-input" name="s" value="<?php _admin_search_query(); ?>" />
+ <?php submit_button( __( 'Search Installed Themes' ), 'button', false, false, array( 'id' => 'search-submit' ) ); ?>
+ <a id="filter-click" href="?filter=1"><?php _e( 'Feature Filter' ); ?></a>
+</p>
+
+<div id="filter-box" style="<?php if ( empty($_REQUEST['filter']) ) echo 'display: none;'; ?>">
+<?php $feature_list = get_theme_feature_list(); ?>
+ <div class="feature-filter">
+ <p class="install-help"><?php _e('Theme filters') ?></p>
+ <?php if ( !empty( $_REQUEST['filter'] ) ) : ?>
+ <input type="hidden" name="filter" value="1" />
+ <?php endif; ?>
+ <?php foreach ( $feature_list as $feature_name => $features ) :
+ $feature_name = esc_html( $feature_name ); ?>
+
+ <div class="feature-container">
+ <div class="feature-name"><?php echo $feature_name ?></div>
+
+ <ol class="feature-group">
+ <?php foreach ( $features as $key => $feature ) :
+ $feature_name = $feature;
+ $feature_name = esc_html( $feature_name );
+ $feature = esc_attr( $feature );
+ ?>
+ <li>
+ <input type="checkbox" name="features[]" id="feature-id-<?php echo $key; ?>" value="<?php echo $key; ?>" <?php checked( in_array( $key, $wp_list_table->features ) ); ?>/>
+ <label for="feature-id-<?php echo $key; ?>"><?php echo $feature_name; ?></label>
+ </li>
+ <?php endforeach; ?>
+ </ol>
+ </div>
+ <?php endforeach; ?>
+
+ <div class="feature-container">
+ <?php submit_button( __( 'Apply Filters' ), 'button-secondary submitter', false, false, array( 'id' => 'filter-submit' ) ); ?>
+ &nbsp;
+ <a id="mini-filter-click" href="<?php echo esc_url( remove_query_arg( array('filter', 'features', 'submit') ) ); ?>"><?php _e( 'Close filters' )?></a>
+ </div>
+ <br/>
+ </div>
+ <br class="clear"/>
+</div>
+
+<?php endif; ?>
+
+<br class="clear" />
+
+<?php $wp_list_table->display(); ?>
+
+</form>
+<br class="clear" />
+
+<?php
+// List broken themes, if any.
+if ( ! is_multisite() && current_user_can('edit_themes') && $broken_themes = wp_get_themes( array( 'errors' => true ) ) ) {
+?>
+
+<h3><?php _e('Broken Themes'); ?></h3>
+<p><?php _e('The following themes are installed but incomplete. Themes must have a stylesheet and a template.'); ?></p>
+
+<table id="broken-themes">
+ <tr>
+ <th><?php _ex('Name', 'theme name'); ?></th>
+ <th><?php _e('Description'); ?></th>
+ </tr>
+<?php
+ $alt = '';
+ foreach ( $broken_themes as $broken_theme ) {
+ $alt = ('class="alternate"' == $alt) ? '' : 'class="alternate"';
+ echo "
+ <tr $alt>
+ <td>" . $broken_theme->get('Name') ."</td>
+ <td>" . $broken_theme->errors()->get_error_message() . "</td>
+ </tr>";
+ }
+?>
+</table>
+<?php
+}
+?>
+</div>
+
+<?php require('./admin-footer.php'); ?>
diff --git a/src/wp-admin/tools.php b/src/wp-admin/tools.php
new file mode 100644
index 0000000000..387be90356
--- /dev/null
+++ b/src/wp-admin/tools.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Tools Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+$title = __('Tools');
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'press-this',
+ 'title' => __('Press This'),
+ 'content' => '<p>' . __('Press This is a bookmarklet that makes it easy to blog about something you come across on the web. You can use it to just grab a link, or to post an excerpt. Press This will even allow you to choose from images included on the page and use them in your post. Just drag the Press This link on this screen to your bookmarks bar in your browser, and you&#8217;ll be on your way to easier content creation. Clicking on it while on another website opens a popup window with all these options.') . '</p>',
+) );
+get_current_screen()->add_help_tab( array(
+ 'id' => 'converter',
+ 'title' => __('Categories and Tags Converter'),
+ 'content' => '<p>' . __('Categories have hierarchy, meaning that you can nest sub-categories. Tags do not have hierarchy and cannot be nested. Sometimes people start out using one on their posts, then later realize that the other would work better for their content.' ) . '</p>' .
+ '<p>' . __( 'The Categories and Tags Converter link on this screen will take you to the Import screen, where that Converter is one of the plugins you can install. Once that plugin is installed, the Activate Plugin &amp; Run Importer link will take you to a screen where you can choose to convert tags into categories or vice versa.' ) . '</p>',
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Tools_Screen" target="_blank">Documentation on Tools</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+require_once('./admin-header.php');
+
+?>
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<?php if ( current_user_can('edit_posts') ) : ?>
+<div class="tool-box">
+ <h3 class="title"><?php _e('Press This') ?></h3>
+ <p><?php _e('Press This is a bookmarklet: a little app that runs in your browser and lets you grab bits of the web.');?></p>
+
+ <p><?php _e('Use Press This to clip text, images and videos from any web page. Then edit and add more straight from Press This before you save or publish it in a post on your site.'); ?></p>
+ <p class="description"><?php _e('Drag-and-drop the following link to your bookmarks bar or right click it and add it to your favorites for a posting shortcut.') ?></p>
+ <p class="pressthis"><a onclick="return false;" oncontextmenu="if(window.navigator.userAgent.indexOf('WebKit')!=-1||window.navigator.userAgent.indexOf('MSIE')!=-1){jQuery('.pressthis-code').show().find('textarea').focus().select();return false;}" href="<?php echo htmlspecialchars( get_shortcut_link() ); ?>"><span><?php _e('Press This') ?></span></a></p>
+ <div class="pressthis-code" style="display:none;">
+ <p class="description"><?php _e('If your bookmarks toolbar is hidden: copy the code below, open your Bookmarks manager, create new bookmark, type Press This into the name field and paste the code into the URL field.') ?></p>
+ <p><textarea rows="5" cols="120" readonly="readonly"><?php echo htmlspecialchars( get_shortcut_link() ); ?></textarea></p>
+ </div>
+</div>
+<?php
+endif;
+
+if ( current_user_can( 'import' ) ) :
+$cats = get_taxonomy('category');
+$tags = get_taxonomy('post_tag');
+if ( current_user_can($cats->cap->manage_terms) || current_user_can($tags->cap->manage_terms) ) : ?>
+<div class="tool-box">
+ <h3 class="title"><?php _e( 'Categories and Tags Converter' ) ?></h3>
+ <p><?php printf( __('If you want to convert your categories to tags (or vice versa), use the <a href="%s">Categories and Tags Converter</a> available from the Import screen.'), 'import.php' ); ?></p>
+</div>
+<?php
+endif;
+endif;
+
+do_action( 'tool_box' );
+?>
+</div>
+<?php
+include('./admin-footer.php');
diff --git a/src/wp-admin/update-core.php b/src/wp-admin/update-core.php
new file mode 100644
index 0000000000..c8f5877429
--- /dev/null
+++ b/src/wp-admin/update-core.php
@@ -0,0 +1,546 @@
+<?php
+/**
+ * Update Core administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+wp_enqueue_style( 'plugin-install' );
+wp_enqueue_script( 'plugin-install' );
+add_thickbox();
+
+if ( is_multisite() && ! is_network_admin() ) {
+ wp_redirect( network_admin_url( 'update-core.php' ) );
+ exit();
+}
+
+if ( ! current_user_can( 'update_core' ) && ! current_user_can( 'update_themes' ) && ! current_user_can( 'update_plugins' ) )
+ wp_die( __( 'You do not have sufficient permissions to update this site.' ) );
+
+function list_core_update( $update ) {
+ global $wp_local_package, $wpdb;
+ static $first_pass = true;
+
+ $version_string = ('en_US' == $update->locale && 'en_US' == get_locale() ) ?
+ $update->current : sprintf("%s&ndash;<strong>%s</strong>", $update->current, $update->locale);
+ $current = false;
+ if ( !isset($update->response) || 'latest' == $update->response )
+ $current = true;
+ $submit = __('Update Now');
+ $form_action = 'update-core.php?action=do-core-upgrade';
+ $php_version = phpversion();
+ $mysql_version = $wpdb->db_version();
+ $show_buttons = true;
+ if ( 'development' == $update->response ) {
+ $message = __('You are using a development version of WordPress. You can update to the latest nightly build automatically or download the nightly build and install it manually:');
+ $download = __('Download nightly build');
+ } else {
+ if ( $current ) {
+ $message = sprintf(__('You have the latest version of WordPress. You do not need to update. However, if you want to re-install version %s, you can do so automatically or download the package and re-install manually:'), $version_string);
+ $submit = __('Re-install Now');
+ $form_action = 'update-core.php?action=do-core-reinstall';
+ } else {
+ $php_compat = version_compare( $php_version, $update->php_version, '>=' );
+ if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
+ $mysql_compat = true;
+ else
+ $mysql_compat = version_compare( $mysql_version, $update->mysql_version, '>=' );
+
+ if ( !$mysql_compat && !$php_compat )
+ $message = sprintf( __('You cannot update because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.'), $update->current, $update->php_version, $update->mysql_version, $php_version, $mysql_version );
+ elseif ( !$php_compat )
+ $message = sprintf( __('You cannot update because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires PHP version %2$s or higher. You are running version %3$s.'), $update->current, $update->php_version, $php_version );
+ elseif ( !$mysql_compat )
+ $message = sprintf( __('You cannot update because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires MySQL version %2$s or higher. You are running version %3$s.'), $update->current, $update->mysql_version, $mysql_version );
+ else
+ $message = sprintf(__('You can update to <a href="http://codex.wordpress.org/Version_%1$s">WordPress %2$s</a> automatically or download the package and install it manually:'), $update->current, $version_string);
+ if ( !$mysql_compat || !$php_compat )
+ $show_buttons = false;
+ }
+ $download = sprintf(__('Download %s'), $version_string);
+ }
+
+ echo '<p>';
+ echo $message;
+ echo '</p>';
+ echo '<form method="post" action="' . $form_action . '" name="upgrade" class="upgrade">';
+ wp_nonce_field('upgrade-core');
+ echo '<p>';
+ echo '<input name="version" value="'. esc_attr($update->current) .'" type="hidden"/>';
+ echo '<input name="locale" value="'. esc_attr($update->locale) .'" type="hidden"/>';
+ if ( $show_buttons ) {
+ if ( $first_pass ) {
+ submit_button( $submit, $current ? 'button' : 'primary regular', 'upgrade', false );
+ $first_pass = false;
+ } else {
+ submit_button( $submit, 'button', 'upgrade', false );
+ }
+ echo '&nbsp;<a href="' . esc_url( $update->download ) . '" class="button">' . $download . '</a>&nbsp;';
+ }
+ if ( 'en_US' != $update->locale )
+ if ( !isset( $update->dismissed ) || !$update->dismissed )
+ submit_button( __('Hide this update'), 'button', 'dismiss', false );
+ else
+ submit_button( __('Bring back this update'), 'button', 'undismiss', false );
+ echo '</p>';
+ if ( 'en_US' != $update->locale && ( !isset($wp_local_package) || $wp_local_package != $update->locale ) )
+ echo '<p class="hint">'.__('This localized version contains both the translation and various other localization fixes. You can skip upgrading if you want to keep your current translation.').'</p>';
+ else if ( 'en_US' == $update->locale && get_locale() != 'en_US' ) {
+ echo '<p class="hint">'.sprintf( __('You are about to install WordPress %s <strong>in English (US).</strong> There is a chance this update will break your translation. You may prefer to wait for the localized version to be released.'), $update->response != 'development' ? $update->current : '' ).'</p>';
+ }
+ echo '</form>';
+
+}
+
+function dismissed_updates() {
+ $dismissed = get_core_updates( array( 'dismissed' => true, 'available' => false ) );
+ if ( $dismissed ) {
+
+ $show_text = esc_js(__('Show hidden updates'));
+ $hide_text = esc_js(__('Hide hidden updates'));
+ ?>
+ <script type="text/javascript">
+
+ jQuery(function($) {
+ $('dismissed-updates').show();
+ $('#show-dismissed').toggle(function(){$(this).text('<?php echo $hide_text; ?>');}, function() {$(this).text('<?php echo $show_text; ?>')});
+ $('#show-dismissed').click(function() { $('#dismissed-updates').toggle('slow');});
+ });
+ </script>
+ <?php
+ echo '<p class="hide-if-no-js"><a id="show-dismissed" href="#">'.__('Show hidden updates').'</a></p>';
+ echo '<ul id="dismissed-updates" class="core-updates dismissed">';
+ foreach( (array) $dismissed as $update) {
+ echo '<li>';
+ list_core_update( $update );
+ echo '</li>';
+ }
+ echo '</ul>';
+ }
+}
+
+/**
+ * Display upgrade WordPress for downloading latest or upgrading automatically form.
+ *
+ * @since 2.7
+ *
+ * @return null
+ */
+function core_upgrade_preamble() {
+ global $wp_version;
+
+ $updates = get_core_updates();
+
+ if ( !isset($updates[0]->response) || 'latest' == $updates[0]->response ) {
+ echo '<h3>';
+ _e('You have the latest version of WordPress.');
+ echo '</h3>';
+ } else {
+ echo '<div class="updated inline"><p>';
+ _e('<strong>Important:</strong> before updating, please <a href="http://codex.wordpress.org/WordPress_Backups">back up your database and files</a>. For help with updates, visit the <a href="http://codex.wordpress.org/Updating_WordPress">Updating WordPress</a> Codex page.');
+ echo '</p></div>';
+
+ echo '<h3 class="response">';
+ _e( 'An updated version of WordPress is available.' );
+ echo '</h3>';
+ }
+
+ echo '<ul class="core-updates">';
+ $alternate = true;
+ foreach( (array) $updates as $update ) {
+ echo '<li>';
+ list_core_update( $update );
+ echo '</li>';
+ }
+ echo '</ul>';
+ if ( $updates ) {
+ echo '<p>' . __( 'While your site is being updated, it will be in maintenance mode. As soon as your updates are complete, your site will return to normal.' ) . '</p>';
+ } else {
+ list( $normalized_version ) = explode( '-', $wp_version );
+ echo '<p>' . sprintf( __( '<a href="%s">Learn more about WordPress %s</a>.' ), esc_url( self_admin_url( 'about.php' ) ), $normalized_version ) . '</p>';
+ }
+ dismissed_updates();
+}
+
+function list_plugin_updates() {
+ global $wp_version;
+
+ $cur_wp_version = preg_replace('/-.*$/', '', $wp_version);
+
+ require_once(ABSPATH . 'wp-admin/includes/plugin-install.php');
+ $plugins = get_plugin_updates();
+ if ( empty( $plugins ) ) {
+ echo '<h3>' . __( 'Plugins' ) . '</h3>';
+ echo '<p>' . __( 'Your plugins are all up to date.' ) . '</p>';
+ return;
+ }
+ $form_action = 'update-core.php?action=do-plugin-upgrade';
+
+ $core_updates = get_core_updates();
+ if ( !isset($core_updates[0]->response) || 'latest' == $core_updates[0]->response || 'development' == $core_updates[0]->response || version_compare( $core_updates[0]->current, $cur_wp_version, '=') )
+ $core_update_version = false;
+ else
+ $core_update_version = $core_updates[0]->current;
+ ?>
+<h3><?php _e( 'Plugins' ); ?></h3>
+<p><?php _e( 'The following plugins have new versions available. Check the ones you want to update and then click &#8220;Update Plugins&#8221;.' ); ?></p>
+<form method="post" action="<?php echo esc_url( $form_action ); ?>" name="upgrade-plugins" class="upgrade">
+<?php wp_nonce_field('upgrade-core'); ?>
+<p><input id="upgrade-plugins" class="button" type="submit" value="<?php esc_attr_e('Update Plugins'); ?>" name="upgrade" /></p>
+<table class="widefat" cellspacing="0" id="update-plugins-table">
+ <thead>
+ <tr>
+ <th scope="col" class="manage-column check-column"><input type="checkbox" id="plugins-select-all" /></th>
+ <th scope="col" class="manage-column"><label for="plugins-select-all"><?php _e('Select All'); ?></label></th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr>
+ <th scope="col" class="manage-column check-column"><input type="checkbox" id="plugins-select-all-2" /></th>
+ <th scope="col" class="manage-column"><label for="plugins-select-all-2"><?php _e('Select All'); ?></label></th>
+ </tr>
+ </tfoot>
+ <tbody class="plugins">
+<?php
+ foreach ( (array) $plugins as $plugin_file => $plugin_data) {
+ $info = plugins_api('plugin_information', array('slug' => $plugin_data->update->slug ));
+ // Get plugin compat for running version of WordPress.
+ if ( isset($info->tested) && version_compare($info->tested, $cur_wp_version, '>=') ) {
+ $compat = '<br />' . sprintf(__('Compatibility with WordPress %1$s: 100%% (according to its author)'), $cur_wp_version);
+ } elseif ( isset($info->compatibility[$cur_wp_version][$plugin_data->update->new_version]) ) {
+ $compat = $info->compatibility[$cur_wp_version][$plugin_data->update->new_version];
+ $compat = '<br />' . sprintf(__('Compatibility with WordPress %1$s: %2$d%% (%3$d "works" votes out of %4$d total)'), $cur_wp_version, $compat[0], $compat[2], $compat[1]);
+ } else {
+ $compat = '<br />' . sprintf(__('Compatibility with WordPress %1$s: Unknown'), $cur_wp_version);
+ }
+ // Get plugin compat for updated version of WordPress.
+ if ( $core_update_version ) {
+ if ( isset($info->compatibility[$core_update_version][$plugin_data->update->new_version]) ) {
+ $update_compat = $info->compatibility[$core_update_version][$plugin_data->update->new_version];
+ $compat .= '<br />' . sprintf(__('Compatibility with WordPress %1$s: %2$d%% (%3$d "works" votes out of %4$d total)'), $core_update_version, $update_compat[0], $update_compat[2], $update_compat[1]);
+ } else {
+ $compat .= '<br />' . sprintf(__('Compatibility with WordPress %1$s: Unknown'), $core_update_version);
+ }
+ }
+ // Get the upgrade notice for the new plugin version.
+ if ( isset($plugin_data->update->upgrade_notice) ) {
+ $upgrade_notice = '<br />' . strip_tags($plugin_data->update->upgrade_notice);
+ } else {
+ $upgrade_notice = '';
+ }
+
+ $details_url = self_admin_url('plugin-install.php?tab=plugin-information&plugin=' . $plugin_data->update->slug . '&section=changelog&TB_iframe=true&width=640&height=662');
+ $details_text = sprintf(__('View version %1$s details'), $plugin_data->update->new_version);
+ $details = sprintf('<a href="%1$s" class="thickbox" title="%2$s">%3$s</a>.', esc_url($details_url), esc_attr($plugin_data->Name), $details_text);
+
+ echo "
+ <tr class='active'>
+ <th scope='row' class='check-column'><input type='checkbox' name='checked[]' value='" . esc_attr($plugin_file) . "' /></th>
+ <td><p><strong>{$plugin_data->Name}</strong><br />" . sprintf(__('You have version %1$s installed. Update to %2$s.'), $plugin_data->Version, $plugin_data->update->new_version) . ' ' . $details . $compat . $upgrade_notice . "</p></td>
+ </tr>";
+ }
+?>
+ </tbody>
+</table>
+<p><input id="upgrade-plugins-2" class="button" type="submit" value="<?php esc_attr_e('Update Plugins'); ?>" name="upgrade" /></p>
+</form>
+<?php
+}
+
+function list_theme_updates() {
+ $themes = get_theme_updates();
+ if ( empty( $themes ) ) {
+ echo '<h3>' . __( 'Themes' ) . '</h3>';
+ echo '<p>' . __( 'Your themes are all up to date.' ) . '</p>';
+ return;
+ }
+
+ $form_action = 'update-core.php?action=do-theme-upgrade';
+
+?>
+<h3><?php _e( 'Themes' ); ?></h3>
+<p><?php _e( 'The following themes have new versions available. Check the ones you want to update and then click &#8220;Update Themes&#8221;.' ); ?></p>
+<p><?php printf( __('<strong>Please Note:</strong> Any customizations you have made to theme files will be lost. Please consider using <a href="%s">child themes</a> for modifications.'), _x('http://codex.wordpress.org/Child_Themes', 'Link used in suggestion to use child themes in GUU') ); ?></p>
+<form method="post" action="<?php echo esc_url( $form_action ); ?>" name="upgrade-themes" class="upgrade">
+<?php wp_nonce_field('upgrade-core'); ?>
+<p><input id="upgrade-themes" class="button" type="submit" value="<?php esc_attr_e('Update Themes'); ?>" name="upgrade" /></p>
+<table class="widefat" cellspacing="0" id="update-themes-table">
+ <thead>
+ <tr>
+ <th scope="col" class="manage-column check-column"><input type="checkbox" id="themes-select-all" /></th>
+ <th scope="col" class="manage-column"><label for="themes-select-all"><?php _e('Select All'); ?></label></th>
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr>
+ <th scope="col" class="manage-column check-column"><input type="checkbox" id="themes-select-all-2" /></th>
+ <th scope="col" class="manage-column"><label for="themes-select-all-2"><?php _e('Select All'); ?></label></th>
+ </tr>
+ </tfoot>
+ <tbody class="plugins">
+<?php
+ foreach ( $themes as $stylesheet => $theme ) {
+ echo "
+ <tr class='active'>
+ <th scope='row' class='check-column'><input type='checkbox' name='checked[]' value='" . esc_attr( $stylesheet ) . "' /></th>
+ <td class='plugin-title'><img src='" . esc_url( $theme->get_screenshot() ) . "' width='85' height='64' style='float:left; padding: 0 5px 5px' /><strong>" . $theme->display('Name') . '</strong> ' . sprintf( __( 'You have version %1$s installed. Update to %2$s.' ), $theme->display('Version'), $theme->update['new_version'] ) . "</td>
+ </tr>";
+ }
+?>
+ </tbody>
+</table>
+<p><input id="upgrade-themes-2" class="button" type="submit" value="<?php esc_attr_e('Update Themes'); ?>" name="upgrade" /></p>
+</form>
+<?php
+}
+
+/**
+ * Upgrade WordPress core display.
+ *
+ * @since 2.7
+ *
+ * @return null
+ */
+function do_core_upgrade( $reinstall = false ) {
+ global $wp_filesystem;
+
+ if ( $reinstall )
+ $url = 'update-core.php?action=do-core-reinstall';
+ else
+ $url = 'update-core.php?action=do-core-upgrade';
+ $url = wp_nonce_url($url, 'upgrade-core');
+ if ( false === ($credentials = request_filesystem_credentials($url, '', false, ABSPATH)) )
+ return;
+
+ $version = isset( $_POST['version'] )? $_POST['version'] : false;
+ $locale = isset( $_POST['locale'] )? $_POST['locale'] : 'en_US';
+ $update = find_core_update( $version, $locale );
+ if ( !$update )
+ return;
+
+ if ( ! WP_Filesystem($credentials, ABSPATH) ) {
+ request_filesystem_credentials($url, '', true, ABSPATH); //Failed to connect, Error and request again
+ return;
+ }
+?>
+ <div class="wrap">
+ <?php screen_icon('tools'); ?>
+ <h2><?php _e('Update WordPress'); ?></h2>
+<?php
+ if ( $wp_filesystem->errors->get_error_code() ) {
+ foreach ( $wp_filesystem->errors->get_error_messages() as $message )
+ show_message($message);
+ echo '</div>';
+ return;
+ }
+
+ if ( $reinstall )
+ $update->response = 'reinstall';
+
+ $result = wp_update_core($update, 'show_message');
+
+ if ( is_wp_error($result) ) {
+ show_message($result);
+ if ('up_to_date' != $result->get_error_code() )
+ show_message( __('Installation Failed') );
+ echo '</div>';
+ return;
+ }
+
+ show_message( __('WordPress updated successfully') );
+ show_message( '<span class="hide-if-no-js">' . sprintf( __( 'Welcome to WordPress %1$s. You will be redirected to the About WordPress screen. If not, click <a href="%2$s">here</a>.' ), $result, esc_url( self_admin_url( 'about.php?updated' ) ) ) . '</span>' );
+ show_message( '<span class="hide-if-js">' . sprintf( __( 'Welcome to WordPress %1$s. <a href="%2$s">Learn more</a>.' ), $result, esc_url( self_admin_url( 'about.php?updated' ) ) ) . '</span>' );
+ ?>
+ </div>
+ <script type="text/javascript">
+ window.location = '<?php echo self_admin_url( 'about.php?updated' ); ?>';
+ </script>
+ <?php
+}
+
+function do_dismiss_core_update() {
+ $version = isset( $_POST['version'] )? $_POST['version'] : false;
+ $locale = isset( $_POST['locale'] )? $_POST['locale'] : 'en_US';
+ $update = find_core_update( $version, $locale );
+ if ( !$update )
+ return;
+ dismiss_core_update( $update );
+ wp_redirect( wp_nonce_url('update-core.php?action=upgrade-core', 'upgrade-core') );
+ exit;
+}
+
+function do_undismiss_core_update() {
+ $version = isset( $_POST['version'] )? $_POST['version'] : false;
+ $locale = isset( $_POST['locale'] )? $_POST['locale'] : 'en_US';
+ $update = find_core_update( $version, $locale );
+ if ( !$update )
+ return;
+ undismiss_core_update( $version, $locale );
+ wp_redirect( wp_nonce_url('update-core.php?action=upgrade-core', 'upgrade-core') );
+ exit;
+}
+
+function no_update_actions($actions) {
+ return '';
+}
+
+$action = isset($_GET['action']) ? $_GET['action'] : 'upgrade-core';
+
+$upgrade_error = false;
+if ( ( 'do-theme-upgrade' == $action || ( 'do-plugin-upgrade' == $action && ! isset( $_GET['plugins'] ) ) )
+ && ! isset( $_POST['checked'] ) ) {
+ $upgrade_error = $action == 'do-theme-upgrade' ? 'themes' : 'plugins';
+ $action = 'upgrade-core';
+}
+
+$title = __('WordPress Updates');
+$parent_file = 'tools.php';
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __('This screen lets you update to the latest version of WordPress as well as update your themes and plugins from the WordPress.org repository. When updates are available, the number of available updates will appear in a bubble on the left hand menu as a notification.') . '</p>' .
+ '<p>' . __('It is very important to keep your WordPress installation up to date for security reasons, so when you see a number appear, make sure you take the time to update, which is an easy process.') . '</p>'
+) );
+
+get_current_screen()->add_help_tab( array(
+'id' => 'how-to-update',
+'title' => __('How to Update'),
+'content' =>
+ '<p>' . __('Updating your WordPress installation is a simple one-click procedure; just click on the Update button when it says a new version is available.') . '</p>' .
+ '<p>' . __('To update themes or plugins from this screen, use the checkboxes to make your selection and click on the appropriate Update button. Check the box at the top of the Themes or Plugins section to select all and update them all at once.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Dashboard_Updates_Screen" target="_blank">Documentation on Updating WordPress</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( 'upgrade-core' == $action ) {
+
+ wp_version_check();
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+ ?>
+ <div class="wrap">
+ <?php screen_icon('tools'); ?>
+ <h2><?php _e('WordPress Updates'); ?></h2>
+ <?php
+ if ( $upgrade_error ) {
+ echo '<div class="error"><p>';
+ if ( $upgrade_error == 'themes' )
+ _e('Please select one or more themes to update.');
+ else
+ _e('Please select one or more plugins to update.');
+ echo '</p></div>';
+ }
+
+ echo '<p>';
+ /* translators: %1 date, %2 time. */
+ printf( __('Last checked on %1$s at %2$s.'), date_i18n( get_option( 'date_format' ) ), date_i18n( get_option( 'time_format' ) ) );
+ echo ' &nbsp; <a class="button" href="' . esc_url( self_admin_url('update-core.php') ) . '">' . __( 'Check Again' ) . '</a>';
+ echo '</p>';
+
+ if ( current_user_can( 'update_core' ) )
+ core_upgrade_preamble();
+ if ( current_user_can( 'update_plugins' ) )
+ list_plugin_updates();
+ if ( current_user_can( 'update_themes' ) )
+ list_theme_updates();
+ do_action('core_upgrade_preamble');
+ echo '</div>';
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+} elseif ( 'do-core-upgrade' == $action || 'do-core-reinstall' == $action ) {
+
+ if ( ! current_user_can( 'update_core' ) )
+ wp_die( __( 'You do not have sufficient permissions to update this site.' ) );
+
+ check_admin_referer('upgrade-core');
+
+ // do the (un)dismiss actions before headers,
+ // so that they can redirect
+ if ( isset( $_POST['dismiss'] ) )
+ do_dismiss_core_update();
+ elseif ( isset( $_POST['undismiss'] ) )
+ do_undismiss_core_update();
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+ if ( 'do-core-reinstall' == $action )
+ $reinstall = true;
+ else
+ $reinstall = false;
+
+ if ( isset( $_POST['upgrade'] ) )
+ do_core_upgrade($reinstall);
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+} elseif ( 'do-plugin-upgrade' == $action ) {
+
+ if ( ! current_user_can( 'update_plugins' ) )
+ wp_die( __( 'You do not have sufficient permissions to update this site.' ) );
+
+ check_admin_referer('upgrade-core');
+
+ if ( isset( $_GET['plugins'] ) ) {
+ $plugins = explode( ',', $_GET['plugins'] );
+ } elseif ( isset( $_POST['checked'] ) ) {
+ $plugins = (array) $_POST['checked'];
+ } else {
+ wp_redirect( admin_url('update-core.php') );
+ exit;
+ }
+
+ $url = 'update.php?action=update-selected&plugins=' . urlencode(implode(',', $plugins));
+ $url = wp_nonce_url($url, 'bulk-update-plugins');
+
+ $title = __('Update Plugins');
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+ echo '<div class="wrap">';
+ screen_icon('plugins');
+ echo '<h2>' . esc_html__('Update Plugins') . '</h2>';
+ echo "<iframe src='$url' style='width: 100%; height: 100%; min-height: 750px;' frameborder='0'></iframe>";
+ echo '</div>';
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+} elseif ( 'do-theme-upgrade' == $action ) {
+
+ if ( ! current_user_can( 'update_themes' ) )
+ wp_die( __( 'You do not have sufficient permissions to update this site.' ) );
+
+ check_admin_referer('upgrade-core');
+
+ if ( isset( $_GET['themes'] ) ) {
+ $themes = explode( ',', $_GET['themes'] );
+ } elseif ( isset( $_POST['checked'] ) ) {
+ $themes = (array) $_POST['checked'];
+ } else {
+ wp_redirect( admin_url('update-core.php') );
+ exit;
+ }
+
+ $url = 'update.php?action=update-selected-themes&themes=' . urlencode(implode(',', $themes));
+ $url = wp_nonce_url($url, 'bulk-update-themes');
+
+ $title = __('Update Themes');
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+ echo '<div class="wrap">';
+ screen_icon('themes');
+ echo '<h2>' . esc_html__('Update Themes') . '</h2>';
+ echo "<iframe src='$url' style='width: 100%; height: 100%; min-height: 750px;' frameborder='0'></iframe>";
+ echo '</div>';
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+} else {
+ do_action('update-core-custom_' . $action);
+} \ No newline at end of file
diff --git a/src/wp-admin/update.php b/src/wp-admin/update.php
new file mode 100644
index 0000000000..caed6e794d
--- /dev/null
+++ b/src/wp-admin/update.php
@@ -0,0 +1,257 @@
+<?php
+/**
+ * Update/Install Plugin/Theme administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+if ( ! defined( 'IFRAME_REQUEST' ) && isset( $_GET['action'] ) && in_array( $_GET['action'], array( 'update-selected', 'activate-plugin', 'update-selected-themes' ) ) )
+ define( 'IFRAME_REQUEST', true );
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+
+if ( isset($_GET['action']) ) {
+ $plugin = isset($_REQUEST['plugin']) ? trim($_REQUEST['plugin']) : '';
+ $theme = isset($_REQUEST['theme']) ? urldecode($_REQUEST['theme']) : '';
+ $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
+
+ if ( 'update-selected' == $action ) {
+ if ( ! current_user_can( 'update_plugins' ) )
+ wp_die( __( 'You do not have sufficient permissions to update plugins for this site.' ) );
+
+ check_admin_referer( 'bulk-update-plugins' );
+
+ if ( isset( $_GET['plugins'] ) )
+ $plugins = explode( ',', stripslashes($_GET['plugins']) );
+ elseif ( isset( $_POST['checked'] ) )
+ $plugins = (array) $_POST['checked'];
+ else
+ $plugins = array();
+
+ $plugins = array_map('urldecode', $plugins);
+
+ $url = 'update.php?action=update-selected&amp;plugins=' . urlencode(implode(',', $plugins));
+ $nonce = 'bulk-update-plugins';
+
+ wp_enqueue_script('jquery');
+ iframe_header();
+
+ $upgrader = new Plugin_Upgrader( new Bulk_Plugin_Upgrader_Skin( compact( 'nonce', 'url' ) ) );
+ $upgrader->bulk_upgrade( $plugins );
+
+ iframe_footer();
+
+ } elseif ( 'upgrade-plugin' == $action ) {
+ if ( ! current_user_can('update_plugins') )
+ wp_die(__('You do not have sufficient permissions to update plugins for this site.'));
+
+ check_admin_referer('upgrade-plugin_' . $plugin);
+
+ $title = __('Update Plugin');
+ $parent_file = 'plugins.php';
+ $submenu_file = 'plugins.php';
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ $nonce = 'upgrade-plugin_' . $plugin;
+ $url = 'update.php?action=upgrade-plugin&plugin=' . urlencode( $plugin );
+
+ $upgrader = new Plugin_Upgrader( new Plugin_Upgrader_Skin( compact('title', 'nonce', 'url', 'plugin') ) );
+ $upgrader->upgrade($plugin);
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ } elseif ('activate-plugin' == $action ) {
+ if ( ! current_user_can('update_plugins') )
+ wp_die(__('You do not have sufficient permissions to update plugins for this site.'));
+
+ check_admin_referer('activate-plugin_' . $plugin);
+ if ( ! isset($_GET['failure']) && ! isset($_GET['success']) ) {
+ wp_redirect( admin_url('update.php?action=activate-plugin&failure=true&plugin=' . urlencode( $plugin ) . '&_wpnonce=' . $_GET['_wpnonce']) );
+ activate_plugin( $plugin, '', ! empty( $_GET['networkwide'] ), true );
+ wp_redirect( admin_url('update.php?action=activate-plugin&success=true&plugin=' . urlencode( $plugin ) . '&_wpnonce=' . $_GET['_wpnonce']) );
+ die();
+ }
+ iframe_header( __('Plugin Reactivation'), true );
+ if ( isset($_GET['success']) )
+ echo '<p>' . __('Plugin reactivated successfully.') . '</p>';
+
+ if ( isset($_GET['failure']) ){
+ echo '<p>' . __('Plugin failed to reactivate due to a fatal error.') . '</p>';
+
+ error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
+ @ini_set('display_errors', true); //Ensure that Fatal errors are displayed.
+ include(WP_PLUGIN_DIR . '/' . $plugin);
+ }
+ iframe_footer();
+ } elseif ( 'install-plugin' == $action ) {
+
+ if ( ! current_user_can('install_plugins') )
+ wp_die( __( 'You do not have sufficient permissions to install plugins on this site.' ) );
+
+ include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; //for plugins_api..
+
+ check_admin_referer('install-plugin_' . $plugin);
+ $api = plugins_api('plugin_information', array('slug' => $plugin, 'fields' => array('sections' => false) ) ); //Save on a bit of bandwidth.
+
+ if ( is_wp_error($api) )
+ wp_die($api);
+
+ $title = __('Plugin Install');
+ $parent_file = 'plugins.php';
+ $submenu_file = 'plugin-install.php';
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ $title = sprintf( __('Installing Plugin: %s'), $api->name . ' ' . $api->version );
+ $nonce = 'install-plugin_' . $plugin;
+ $url = 'update.php?action=install-plugin&plugin=' . urlencode( $plugin );
+ if ( isset($_GET['from']) )
+ $url .= '&from=' . urlencode(stripslashes($_GET['from']));
+
+ $type = 'web'; //Install plugin type, From Web or an Upload.
+
+ $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( compact('title', 'url', 'nonce', 'plugin', 'api') ) );
+ $upgrader->install($api->download_link);
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ } elseif ( 'upload-plugin' == $action ) {
+
+ if ( ! current_user_can('install_plugins') )
+ wp_die( __( 'You do not have sufficient permissions to install plugins on this site.' ) );
+
+ check_admin_referer('plugin-upload');
+
+ $file_upload = new File_Upload_Upgrader('pluginzip', 'package');
+
+ $title = __('Upload Plugin');
+ $parent_file = 'plugins.php';
+ $submenu_file = 'plugin-install.php';
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ $title = sprintf( __('Installing Plugin from uploaded file: %s'), esc_html( basename( $file_upload->filename ) ) );
+ $nonce = 'plugin-upload';
+ $url = add_query_arg(array('package' => $file_upload->id), 'update.php?action=upload-plugin');
+ $type = 'upload'; //Install plugin type, From Web or an Upload.
+
+ $upgrader = new Plugin_Upgrader( new Plugin_Installer_Skin( compact('type', 'title', 'nonce', 'url') ) );
+ $result = $upgrader->install( $file_upload->package );
+
+ if ( $result || is_wp_error($result) )
+ $file_upload->cleanup();
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ } elseif ( 'upgrade-theme' == $action ) {
+
+ if ( ! current_user_can('update_themes') )
+ wp_die(__('You do not have sufficient permissions to update themes for this site.'));
+
+ check_admin_referer('upgrade-theme_' . $theme);
+
+ wp_enqueue_script( 'customize-loader' );
+
+ $title = __('Update Theme');
+ $parent_file = 'themes.php';
+ $submenu_file = 'themes.php';
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ $nonce = 'upgrade-theme_' . $theme;
+ $url = 'update.php?action=upgrade-theme&theme=' . urlencode( $theme );
+
+ $upgrader = new Theme_Upgrader( new Theme_Upgrader_Skin( compact('title', 'nonce', 'url', 'theme') ) );
+ $upgrader->upgrade($theme);
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+ } elseif ( 'update-selected-themes' == $action ) {
+ if ( ! current_user_can( 'update_themes' ) )
+ wp_die( __( 'You do not have sufficient permissions to update themes for this site.' ) );
+
+ check_admin_referer( 'bulk-update-themes' );
+
+ if ( isset( $_GET['themes'] ) )
+ $themes = explode( ',', stripslashes($_GET['themes']) );
+ elseif ( isset( $_POST['checked'] ) )
+ $themes = (array) $_POST['checked'];
+ else
+ $themes = array();
+
+ $themes = array_map('urldecode', $themes);
+
+ $url = 'update.php?action=update-selected-themes&amp;themes=' . urlencode(implode(',', $themes));
+ $nonce = 'bulk-update-themes';
+
+ wp_enqueue_script('jquery');
+ iframe_header();
+
+ $upgrader = new Theme_Upgrader( new Bulk_Theme_Upgrader_Skin( compact( 'nonce', 'url' ) ) );
+ $upgrader->bulk_upgrade( $themes );
+
+ iframe_footer();
+ } elseif ( 'install-theme' == $action ) {
+
+ if ( ! current_user_can('install_themes') )
+ wp_die( __( 'You do not have sufficient permissions to install themes on this site.' ) );
+
+ include_once ABSPATH . 'wp-admin/includes/theme-install.php'; //for themes_api..
+
+ check_admin_referer('install-theme_' . $theme);
+ $api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
+
+ if ( is_wp_error($api) )
+ wp_die($api);
+
+ wp_enqueue_script( 'customize-loader' );
+
+ $title = __('Install Themes');
+ $parent_file = 'themes.php';
+ $submenu_file = 'themes.php';
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ $title = sprintf( __('Installing Theme: %s'), $api->name . ' ' . $api->version );
+ $nonce = 'install-theme_' . $theme;
+ $url = 'update.php?action=install-theme&theme=' . urlencode( $theme );
+ $type = 'web'; //Install theme type, From Web or an Upload.
+
+ $upgrader = new Theme_Upgrader( new Theme_Installer_Skin( compact('title', 'url', 'nonce', 'plugin', 'api') ) );
+ $upgrader->install($api->download_link);
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ } elseif ( 'upload-theme' == $action ) {
+
+ if ( ! current_user_can('install_themes') )
+ wp_die( __( 'You do not have sufficient permissions to install themes on this site.' ) );
+
+ check_admin_referer('theme-upload');
+
+ $file_upload = new File_Upload_Upgrader('themezip', 'package');
+
+ wp_enqueue_script( 'customize-loader' );
+
+ $title = __('Upload Theme');
+ $parent_file = 'themes.php';
+ $submenu_file = 'theme-install.php';
+
+ require_once(ABSPATH . 'wp-admin/admin-header.php');
+
+ $title = sprintf( __('Installing Theme from uploaded file: %s'), esc_html( basename( $file_upload->filename ) ) );
+ $nonce = 'theme-upload';
+ $url = add_query_arg(array('package' => $file_upload->id), 'update.php?action=upload-theme');
+ $type = 'upload'; //Install plugin type, From Web or an Upload.
+
+ $upgrader = new Theme_Upgrader( new Theme_Installer_Skin( compact('type', 'title', 'nonce', 'url') ) );
+ $result = $upgrader->install( $file_upload->package );
+
+ if ( $result || is_wp_error($result) )
+ $file_upload->cleanup();
+
+ include(ABSPATH . 'wp-admin/admin-footer.php');
+
+ } else {
+ do_action('update-custom_' . $action);
+ }
+}
diff --git a/src/wp-admin/upgrade-functions.php b/src/wp-admin/upgrade-functions.php
new file mode 100644
index 0000000000..080d74d7c5
--- /dev/null
+++ b/src/wp-admin/upgrade-functions.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * WordPress Upgrade Functions. Old file, must not be used. Include
+ * wp-admin/includes/upgrade.php instead.
+ *
+ * @deprecated 2.5
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+_deprecated_file( basename(__FILE__), '2.5', 'wp-admin/includes/upgrade.php' );
+require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
diff --git a/src/wp-admin/upgrade.php b/src/wp-admin/upgrade.php
new file mode 100644
index 0000000000..b04287735d
--- /dev/null
+++ b/src/wp-admin/upgrade.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Upgrade WordPress Page.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/**
+ * We are upgrading WordPress.
+ *
+ * @since 1.5.1
+ * @var bool
+ */
+define( 'WP_INSTALLING', true );
+
+/** Load WordPress Bootstrap */
+require( '../wp-load.php' );
+
+nocache_headers();
+
+timer_start();
+require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
+
+delete_site_transient('update_core');
+
+if ( isset( $_GET['step'] ) )
+ $step = $_GET['step'];
+else
+ $step = 0;
+
+// Do it. No output.
+if ( 'upgrade_db' === $step ) {
+ wp_upgrade();
+ die( '0' );
+}
+
+$step = (int) $step;
+
+$php_version = phpversion();
+$mysql_version = $wpdb->db_version();
+$php_compat = version_compare( $php_version, $required_php_version, '>=' );
+if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) )
+ $mysql_compat = true;
+else
+ $mysql_compat = version_compare( $mysql_version, $required_mysql_version, '>=' );
+
+@header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+<head>
+ <meta http-equiv="Content-Type" content="<?php bloginfo( 'html_type' ); ?>; charset=<?php echo get_option( 'blog_charset' ); ?>" />
+ <title><?php _e( 'WordPress &rsaquo; Update' ); ?></title>
+ <?php
+ wp_admin_css( 'install', true );
+ wp_admin_css( 'ie', true );
+ ?>
+</head>
+<body class="wp-core-ui">
+<h1 id="logo"><a href="<?php echo esc_url( __( 'http://wordpress.org/' ) ); ?>"><?php _e( 'WordPress' ); ?></a></h1>
+
+<?php if ( get_option( 'db_version' ) == $wp_db_version || !is_blog_installed() ) : ?>
+
+<h2><?php _e( 'No Update Required' ); ?></h2>
+<p><?php _e( 'Your WordPress database is already up-to-date!' ); ?></p>
+<p class="step"><a class="button button-large" href="<?php echo get_option( 'home' ); ?>/"><?php _e( 'Continue' ); ?></a></p>
+
+<?php elseif ( !$php_compat || !$mysql_compat ) :
+ if ( !$mysql_compat && !$php_compat )
+ printf( __('You cannot update because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.'), $wp_version, $required_php_version, $required_mysql_version, $php_version, $mysql_version );
+ elseif ( !$php_compat )
+ printf( __('You cannot update because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires PHP version %2$s or higher. You are running version %3$s.'), $wp_version, $required_php_version, $php_version );
+ elseif ( !$mysql_compat )
+ printf( __('You cannot update because <a href="http://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> requires MySQL version %2$s or higher. You are running version %3$s.'), $wp_version, $required_mysql_version, $mysql_version );
+?>
+<?php else :
+switch ( $step ) :
+ case 0:
+ $goback = wp_get_referer();
+ $goback = esc_url_raw( $goback );
+ $goback = urlencode( $goback );
+?>
+<h2><?php _e( 'Database Update Required' ); ?></h2>
+<p><?php _e( 'WordPress has been updated! Before we send you on your way, we have to update your database to the newest version.' ); ?></p>
+<p><?php _e( 'The update process may take a little while, so please be patient.' ); ?></p>
+<p class="step"><a class="button button-large" href="upgrade.php?step=1&amp;backto=<?php echo $goback; ?>"><?php _e( 'Update WordPress Database' ); ?></a></p>
+<?php
+ break;
+ case 1:
+ wp_upgrade();
+
+ $backto = !empty($_GET['backto']) ? wp_unslash( urldecode( $_GET['backto'] ) ) : __get_option( 'home' ) . '/';
+ $backto = esc_url( $backto );
+ $backto = wp_validate_redirect($backto, __get_option( 'home' ) . '/');
+?>
+<h2><?php _e( 'Update Complete' ); ?></h2>
+ <p><?php _e( 'Your WordPress database has been successfully updated!' ); ?></p>
+ <p class="step"><a class="button button-large" href="<?php echo $backto; ?>"><?php _e( 'Continue' ); ?></a></p>
+
+<!--
+<pre>
+<?php printf( __( '%s queries' ), $wpdb->num_queries ); ?>
+
+<?php printf( __( '%s seconds' ), timer_stop( 0 ) ); ?>
+</pre>
+-->
+
+<?php
+ break;
+endswitch;
+endif;
+?>
+</body>
+</html>
diff --git a/src/wp-admin/upload.php b/src/wp-admin/upload.php
new file mode 100644
index 0000000000..8dec1302a1
--- /dev/null
+++ b/src/wp-admin/upload.php
@@ -0,0 +1,250 @@
+<?php
+/**
+ * Media Library administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( !current_user_can('upload_files') )
+ wp_die( __( 'You do not have permission to upload files.' ) );
+
+$wp_list_table = _get_list_table('WP_Media_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+
+// Handle bulk actions
+$doaction = $wp_list_table->current_action();
+
+if ( $doaction ) {
+ check_admin_referer('bulk-media');
+
+ if ( 'delete_all' == $doaction ) {
+ $post_ids = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type='attachment' AND post_status = 'trash'" );
+ $doaction = 'delete';
+ } elseif ( isset( $_REQUEST['media'] ) ) {
+ $post_ids = $_REQUEST['media'];
+ } elseif ( isset( $_REQUEST['ids'] ) ) {
+ $post_ids = explode( ',', $_REQUEST['ids'] );
+ }
+
+ $location = 'upload.php';
+ if ( $referer = wp_get_referer() ) {
+ if ( false !== strpos( $referer, 'upload.php' ) )
+ $location = remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'message', 'ids', 'posted' ), $referer );
+ }
+
+ switch ( $doaction ) {
+ case 'find_detached':
+ if ( !current_user_can('edit_posts') )
+ wp_die( __('You are not allowed to scan for lost attachments.') );
+
+ $lost = $wpdb->get_col( "
+ SELECT ID FROM $wpdb->posts
+ WHERE post_type = 'attachment' AND post_parent > '0'
+ AND post_parent NOT IN (
+ SELECT ID FROM $wpdb->posts
+ WHERE post_type NOT IN ( 'attachment', '" . join( "', '", get_post_types( array( 'public' => false ) ) ) . "' )
+ )
+ " );
+
+ $_REQUEST['detached'] = 1;
+ break;
+ case 'attach':
+ $parent_id = (int) $_REQUEST['found_post_id'];
+ if ( !$parent_id )
+ return;
+
+ $parent = get_post( $parent_id );
+ if ( !current_user_can( 'edit_post', $parent_id ) )
+ wp_die( __( 'You are not allowed to edit this post.' ) );
+
+ $attach = array();
+ foreach ( (array) $_REQUEST['media'] as $att_id ) {
+ $att_id = (int) $att_id;
+
+ if ( !current_user_can( 'edit_post', $att_id ) )
+ continue;
+
+ $attach[] = $att_id;
+ }
+
+ if ( ! empty( $attach ) ) {
+ $attach_string = implode( ',', $attach );
+ $attached = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $attach_string )", $parent_id ) );
+ foreach ( $attach as $att_id ) {
+ clean_attachment_cache( $att_id );
+ }
+ }
+
+ if ( isset( $attached ) ) {
+ $location = 'upload.php';
+ if ( $referer = wp_get_referer() ) {
+ if ( false !== strpos( $referer, 'upload.php' ) )
+ $location = $referer;
+ }
+
+ $location = add_query_arg( array( 'attached' => $attached ) , $location );
+ wp_redirect( $location );
+ exit;
+ }
+ break;
+ case 'trash':
+ if ( !isset( $post_ids ) )
+ break;
+ foreach ( (array) $post_ids as $post_id ) {
+ if ( !current_user_can( 'delete_post', $post_id ) )
+ wp_die( __( 'You are not allowed to move this post to the trash.' ) );
+
+ if ( !wp_trash_post( $post_id ) )
+ wp_die( __( 'Error in moving to trash.' ) );
+ }
+ $location = add_query_arg( array( 'trashed' => count( $post_ids ), 'ids' => join( ',', $post_ids ) ), $location );
+ break;
+ case 'untrash':
+ if ( !isset( $post_ids ) )
+ break;
+ foreach ( (array) $post_ids as $post_id ) {
+ if ( !current_user_can( 'delete_post', $post_id ) )
+ wp_die( __( 'You are not allowed to move this post out of the trash.' ) );
+
+ if ( !wp_untrash_post( $post_id ) )
+ wp_die( __( 'Error in restoring from trash.' ) );
+ }
+ $location = add_query_arg( 'untrashed', count( $post_ids ), $location );
+ break;
+ case 'delete':
+ if ( !isset( $post_ids ) )
+ break;
+ foreach ( (array) $post_ids as $post_id_del ) {
+ if ( !current_user_can( 'delete_post', $post_id_del ) )
+ wp_die( __( 'You are not allowed to delete this post.' ) );
+
+ if ( !wp_delete_attachment( $post_id_del ) )
+ wp_die( __( 'Error in deleting.' ) );
+ }
+ $location = add_query_arg( 'deleted', count( $post_ids ), $location );
+ break;
+ }
+
+ wp_redirect( $location );
+ exit;
+} elseif ( ! empty( $_GET['_wp_http_referer'] ) ) {
+ wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ exit;
+}
+
+$wp_list_table->prepare_items();
+
+$title = __('Media Library');
+$parent_file = 'upload.php';
+
+wp_enqueue_script( 'wp-ajax-response' );
+wp_enqueue_script( 'jquery-ui-draggable' );
+wp_enqueue_script( 'media' );
+
+add_screen_option( 'per_page', array('label' => _x( 'Media items', 'items per page (screen options)' )) );
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __( 'All the files you&#8217;ve uploaded are listed in the Media Library, with the most recent uploads listed first. You can use the Screen Options tab to customize the display of this screen.' ) . '</p>' .
+ '<p>' . __( 'You can narrow the list by file type/status using the text link filters at the top of the screen. You also can refine the list by date using the dropdown menu above the media table.' ) . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'actions-links',
+'title' => __('Available Actions'),
+'content' =>
+ '<p>' . __( 'Hovering over a row reveals action links: Edit, Delete Permanently, and View. Clicking Edit or on the media file&#8217;s name displays a simple screen to edit that individual file&#8217;s metadata. Clicking Delete Permanently will delete the file from the media library (as well as from any posts to which it is currently attached). View will take you to the display page for that file.' ) . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'attaching-files',
+'title' => __('Attaching Files'),
+'content' =>
+ '<p>' . __( 'If a media file has not been attached to any post, you will see that in the Attached To column, and can click on Attach File to launch a small popup that will allow you to search for a post and attach the file.' ) . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __( 'For more information:' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Media_Library_Screen" target="_blank">Documentation on Media Library</a>' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>' ) . '</p>'
+);
+
+require_once('./admin-header.php');
+?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2>
+<?php
+echo esc_html( $title );
+if ( current_user_can( 'upload_files' ) ) { ?>
+ <a href="media-new.php" class="add-new-h2"><?php echo esc_html_x('Add New', 'file'); ?></a><?php
+}
+if ( ! empty( $_REQUEST['s'] ) )
+ printf( '<span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', get_search_query() ); ?>
+</h2>
+
+<?php
+$message = '';
+if ( ! empty( $_GET['posted'] ) ) {
+ $message = __('Media attachment updated.');
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('posted'), $_SERVER['REQUEST_URI']);
+}
+
+if ( ! empty( $_GET['attached'] ) && $attached = absint( $_GET['attached'] ) ) {
+ $message = sprintf( _n('Reattached %d attachment.', 'Reattached %d attachments.', $attached), $attached );
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('attached'), $_SERVER['REQUEST_URI']);
+}
+
+if ( ! empty( $_GET['deleted'] ) && $deleted = absint( $_GET['deleted'] ) ) {
+ $message = sprintf( _n( 'Media attachment permanently deleted.', '%d media attachments permanently deleted.', $deleted ), number_format_i18n( $_GET['deleted'] ) );
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('deleted'), $_SERVER['REQUEST_URI']);
+}
+
+if ( ! empty( $_GET['trashed'] ) && $trashed = absint( $_GET['trashed'] ) ) {
+ $message = sprintf( _n( 'Media attachment moved to the trash.', '%d media attachments moved to the trash.', $trashed ), number_format_i18n( $_GET['trashed'] ) );
+ $message .= ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.(isset($_GET['ids']) ? $_GET['ids'] : ''), "bulk-media" ) ) . '">' . __('Undo') . '</a>';
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('trashed'), $_SERVER['REQUEST_URI']);
+}
+
+if ( ! empty( $_GET['untrashed'] ) && $untrashed = absint( $_GET['untrashed'] ) ) {
+ $message = sprintf( _n( 'Media attachment restored from the trash.', '%d media attachments restored from the trash.', $untrashed ), number_format_i18n( $_GET['untrashed'] ) );
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('untrashed'), $_SERVER['REQUEST_URI']);
+}
+
+$messages[1] = __('Media attachment updated.');
+$messages[2] = __('Media permanently deleted.');
+$messages[3] = __('Error saving media attachment.');
+$messages[4] = __('Media moved to the trash.') . ' <a href="' . esc_url( wp_nonce_url( 'upload.php?doaction=undo&action=untrash&ids='.(isset($_GET['ids']) ? $_GET['ids'] : ''), "bulk-media" ) ) . '">' . __('Undo') . '</a>';
+$messages[5] = __('Media restored from the trash.');
+
+if ( ! empty( $_GET['message'] ) && isset( $messages[ $_GET['message'] ] ) ) {
+ $message = $messages[ $_GET['message'] ];
+ $_SERVER['REQUEST_URI'] = remove_query_arg(array('message'), $_SERVER['REQUEST_URI']);
+}
+
+if ( !empty($message) ) { ?>
+<div id="message" class="updated"><p><?php echo $message; ?></p></div>
+<?php } ?>
+
+<?php $wp_list_table->views(); ?>
+
+<form id="posts-filter" action="" method="get">
+
+<?php $wp_list_table->search_box( __( 'Search Media' ), 'media' ); ?>
+
+<?php $wp_list_table->display(); ?>
+
+<div id="ajax-response"></div>
+<?php find_posts_div(); ?>
+<br class="clear" />
+
+</form>
+</div>
+
+<?php
+include('./admin-footer.php');
diff --git a/src/wp-admin/user-edit.php b/src/wp-admin/user-edit.php
new file mode 100644
index 0000000000..bb9119f221
--- /dev/null
+++ b/src/wp-admin/user-edit.php
@@ -0,0 +1,442 @@
+<?php
+/**
+ * Edit user administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+wp_reset_vars( array( 'action', 'user_id', 'wp_http_referer' ) );
+
+$user_id = (int) $user_id;
+$current_user = wp_get_current_user();
+if ( ! defined( 'IS_PROFILE_PAGE' ) )
+ define( 'IS_PROFILE_PAGE', ( $user_id == $current_user->ID ) );
+
+if ( ! $user_id && IS_PROFILE_PAGE )
+ $user_id = $current_user->ID;
+elseif ( ! $user_id && ! IS_PROFILE_PAGE )
+ wp_die(__( 'Invalid user ID.' ) );
+elseif ( ! get_userdata( $user_id ) )
+ wp_die( __('Invalid user ID.') );
+
+wp_enqueue_script('user-profile');
+
+$title = IS_PROFILE_PAGE ? __('Profile') : __('Edit User');
+if ( current_user_can('edit_users') && !IS_PROFILE_PAGE )
+ $submenu_file = 'users.php';
+else
+ $submenu_file = 'profile.php';
+
+if ( current_user_can('edit_users') && !is_user_admin() )
+ $parent_file = 'users.php';
+else
+ $parent_file = 'profile.php';
+
+$profile_help = '<p>' . __('Your profile contains information about you (your &#8220;account&#8221;) as well as some personal options related to using WordPress.') . '</p>' .
+ '<p>' . __('You can change your password, turn on keyboard shortcuts, change the color scheme of your WordPress administration screens, and turn off the WYSIWYG (Visual) editor, among other things. You can hide the Toolbar (formerly called the Admin Bar) from the front end of your site, however it cannot be disabled on the admin screens.') . '</p>' .
+ '<p>' . __('Your username cannot be changed, but you can use other fields to enter your real name or a nickname, and change which name to display on your posts.') . '</p>' .
+ '<p>' . __('Required fields are indicated; the rest are optional. Profile information will only be displayed if your theme is set up to do so.') . '</p>' .
+ '<p>' . __('Remember to click the Update Profile button when you are finished.') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $profile_help,
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Users_Your_Profile_Screen" target="_blank">Documentation on User Profiles</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+$wp_http_referer = remove_query_arg(array('update', 'delete_count'), $wp_http_referer );
+
+$user_can_edit = current_user_can( 'edit_posts' ) || current_user_can( 'edit_pages' );
+
+/**
+ * Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
+ *
+ * @since 2.7.0
+ *
+ * @param object $user User data object
+ */
+function use_ssl_preference($user) {
+?>
+ <tr>
+ <th scope="row"><?php _e('Use https')?></th>
+ <td><label for="use_ssl"><input name="use_ssl" type="checkbox" id="use_ssl" value="1" <?php checked('1', $user->use_ssl); ?> /> <?php _e('Always use https when visiting the admin'); ?></label></td>
+ </tr>
+<?php
+}
+
+// Only allow super admins on multisite to edit every user.
+if ( is_multisite() && ! current_user_can( 'manage_network_users' ) && $user_id != $current_user->ID && ! apply_filters( 'enable_edit_any_user_configuration', true ) )
+ wp_die( __( 'You do not have permission to edit this user.' ) );
+
+// Execute confirmed email change. See send_confirmation_on_profile_email().
+if ( is_multisite() && IS_PROFILE_PAGE && isset( $_GET[ 'newuseremail' ] ) && $current_user->ID ) {
+ $new_email = get_option( $current_user->ID . '_new_email' );
+ if ( $new_email[ 'hash' ] == $_GET[ 'newuseremail' ] ) {
+ $user = new stdClass;
+ $user->ID = $current_user->ID;
+ $user->user_email = esc_html( trim( $new_email[ 'newemail' ] ) );
+ if ( $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", $current_user->user_login ) ) )
+ $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $user->user_email, $current_user->user_login ) );
+ wp_update_user( $user );
+ delete_option( $current_user->ID . '_new_email' );
+ wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
+ die();
+ }
+} elseif ( is_multisite() && IS_PROFILE_PAGE && !empty( $_GET['dismiss'] ) && $current_user->ID . '_new_email' == $_GET['dismiss'] ) {
+ delete_option( $current_user->ID . '_new_email' );
+ wp_redirect( add_query_arg( array('updated' => 'true'), self_admin_url( 'profile.php' ) ) );
+ die();
+}
+
+switch ($action) {
+case 'update':
+
+check_admin_referer('update-user_' . $user_id);
+
+if ( !current_user_can('edit_user', $user_id) )
+ wp_die(__('You do not have permission to edit this user.'));
+
+if ( IS_PROFILE_PAGE )
+ do_action('personal_options_update', $user_id);
+else
+ do_action('edit_user_profile_update', $user_id);
+
+if ( !is_multisite() ) {
+ $errors = edit_user($user_id);
+} else {
+ $user = get_userdata( $user_id );
+
+ // Update the email address in signups, if present.
+ if ( $user->user_login && isset( $_POST[ 'email' ] ) && is_email( $_POST[ 'email' ] ) && $wpdb->get_var( $wpdb->prepare( "SELECT user_login FROM {$wpdb->signups} WHERE user_login = %s", $user->user_login ) ) )
+ $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->signups} SET user_email = %s WHERE user_login = %s", $_POST[ 'email' ], $user_login ) );
+
+ // WPMU must delete the user from the current blog if WP added him after editing.
+ $delete_role = false;
+ $blog_prefix = $wpdb->get_blog_prefix();
+ if ( $user_id != $current_user->ID ) {
+ $cap = $wpdb->get_var( "SELECT meta_value FROM {$wpdb->usermeta} WHERE user_id = '{$user_id}' AND meta_key = '{$blog_prefix}capabilities' AND meta_value = 'a:0:{}'" );
+ if ( !is_network_admin() && null == $cap && $_POST[ 'role' ] == '' ) {
+ $_POST[ 'role' ] = 'contributor';
+ $delete_role = true;
+ }
+ }
+ if ( !isset( $errors ) || ( isset( $errors ) && is_object( $errors ) && false == $errors->get_error_codes() ) )
+ $errors = edit_user($user_id);
+ if ( $delete_role ) // stops users being added to current blog when they are edited
+ delete_user_meta( $user_id, $blog_prefix . 'capabilities' );
+
+ if ( is_multisite() && is_network_admin() && !IS_PROFILE_PAGE && current_user_can( 'manage_network_options' ) && !isset($super_admins) && empty( $_POST['super_admin'] ) == is_super_admin( $user_id ) )
+ empty( $_POST['super_admin'] ) ? revoke_super_admin( $user_id ) : grant_super_admin( $user_id );
+}
+
+if ( !is_wp_error( $errors ) ) {
+ $redirect = add_query_arg( 'updated', true, get_edit_user_link( $user_id ) );
+ if ( $wp_http_referer )
+ $redirect = add_query_arg('wp_http_referer', urlencode($wp_http_referer), $redirect);
+ wp_redirect($redirect);
+ exit;
+}
+
+default:
+$profileuser = get_user_to_edit($user_id);
+
+if ( !current_user_can('edit_user', $user_id) )
+ wp_die(__('You do not have permission to edit this user.'));
+
+include (ABSPATH . 'wp-admin/admin-header.php');
+?>
+
+<?php if ( !IS_PROFILE_PAGE && is_super_admin( $profileuser->ID ) && current_user_can( 'manage_network_options' ) ) { ?>
+ <div class="updated"><p><strong><?php _e('Important:'); ?></strong> <?php _e('This user has super admin privileges.'); ?></p></div>
+<?php } ?>
+<?php if ( isset($_GET['updated']) ) : ?>
+<div id="message" class="updated">
+ <?php if ( IS_PROFILE_PAGE ) : ?>
+ <p><strong><?php _e('Profile updated.') ?></strong></p>
+ <?php else: ?>
+ <p><strong><?php _e('User updated.') ?></strong></p>
+ <?php endif; ?>
+ <?php if ( $wp_http_referer && !IS_PROFILE_PAGE ) : ?>
+ <p><a href="<?php echo esc_url( $wp_http_referer ); ?>"><?php _e('&larr; Back to Users'); ?></a></p>
+ <?php endif; ?>
+</div>
+<?php endif; ?>
+<?php if ( isset( $errors ) && is_wp_error( $errors ) ) : ?>
+<div class="error"><p><?php echo implode( "</p>\n<p>", $errors->get_error_messages() ); ?></p></div>
+<?php endif; ?>
+
+<div class="wrap" id="profile-page">
+<?php screen_icon(); ?>
+<h2>
+<?php
+echo esc_html( $title );
+if ( ! IS_PROFILE_PAGE ) {
+ if ( current_user_can( 'create_users' ) ) { ?>
+ <a href="user-new.php" class="add-new-h2"><?php echo esc_html_x( 'Add New', 'user' ); ?></a>
+ <?php } elseif ( is_multisite() && current_user_can( 'promote_users' ) ) { ?>
+ <a href="user-new.php" class="add-new-h2"><?php echo esc_html_x( 'Add Existing', 'user' ); ?></a>
+ <?php }
+} ?>
+</h2>
+
+<form id="your-profile" action="<?php echo esc_url( self_admin_url( IS_PROFILE_PAGE ? 'profile.php' : 'user-edit.php' ) ); ?>" method="post"<?php do_action('user_edit_form_tag'); ?>>
+<?php wp_nonce_field('update-user_' . $user_id) ?>
+<?php if ( $wp_http_referer ) : ?>
+ <input type="hidden" name="wp_http_referer" value="<?php echo esc_url($wp_http_referer); ?>" />
+<?php endif; ?>
+<p>
+<input type="hidden" name="from" value="profile" />
+<input type="hidden" name="checkuser_id" value="<?php echo $user_ID ?>" />
+</p>
+
+<h3><?php _e('Personal Options'); ?></h3>
+
+<table class="form-table">
+<?php if ( rich_edit_exists() && !( IS_PROFILE_PAGE && !$user_can_edit ) ) : // don't bother showing the option if the editor has been removed ?>
+ <tr>
+ <th scope="row"><?php _e('Visual Editor')?></th>
+ <td><label for="rich_editing"><input name="rich_editing" type="checkbox" id="rich_editing" value="false" <?php checked('false', $profileuser->rich_editing); ?> /> <?php _e('Disable the visual editor when writing'); ?></label></td>
+ </tr>
+<?php endif; ?>
+<?php if ( count($_wp_admin_css_colors) > 1 && has_action('admin_color_scheme_picker') ) : ?>
+<tr>
+<th scope="row"><?php _e('Admin Color Scheme')?></th>
+<td><?php do_action( 'admin_color_scheme_picker' ); ?></td>
+</tr>
+<?php
+endif; // $_wp_admin_css_colors
+if ( !( IS_PROFILE_PAGE && !$user_can_edit ) ) : ?>
+<tr>
+<th scope="row"><?php _e( 'Keyboard Shortcuts' ); ?></th>
+<td><label for="comment_shortcuts"><input type="checkbox" name="comment_shortcuts" id="comment_shortcuts" value="true" <?php if ( !empty($profileuser->comment_shortcuts) ) checked('true', $profileuser->comment_shortcuts); ?> /> <?php _e('Enable keyboard shortcuts for comment moderation.'); ?></label> <?php _e('<a href="http://codex.wordpress.org/Keyboard_Shortcuts" target="_blank">More information</a>'); ?></td>
+</tr>
+<?php endif; ?>
+<tr class="show-admin-bar">
+<th scope="row"><?php _e('Toolbar')?></th>
+<td><fieldset><legend class="screen-reader-text"><span><?php _e('Toolbar') ?></span></legend>
+<label for="admin_bar_front">
+<input name="admin_bar_front" type="checkbox" id="admin_bar_front" value="1"<?php checked( _get_admin_bar_pref( 'front', $profileuser->ID ) ); ?> />
+<?php _e( 'Show Toolbar when viewing site' ); ?></label><br />
+</fieldset>
+</td>
+</tr>
+<?php do_action('personal_options', $profileuser); ?>
+</table>
+<?php
+ if ( IS_PROFILE_PAGE )
+ do_action('profile_personal_options', $profileuser);
+?>
+
+<h3><?php _e('Name') ?></h3>
+
+<table class="form-table">
+ <tr>
+ <th><label for="user_login"><?php _e('Username'); ?></label></th>
+ <td><input type="text" name="user_login" id="user_login" value="<?php echo esc_attr($profileuser->user_login); ?>" disabled="disabled" class="regular-text" /> <span class="description"><?php _e('Usernames cannot be changed.'); ?></span></td>
+ </tr>
+
+<?php if ( !IS_PROFILE_PAGE && !is_network_admin() ) : ?>
+<tr><th><label for="role"><?php _e('Role') ?></label></th>
+<td><select name="role" id="role">
+<?php
+// Compare user role against currently editable roles
+$user_roles = array_intersect( array_values( $profileuser->roles ), array_keys( get_editable_roles() ) );
+$user_role = array_shift( $user_roles );
+
+// print the full list of roles with the primary one selected.
+wp_dropdown_roles($user_role);
+
+// print the 'no role' option. Make it selected if the user has no role yet.
+if ( $user_role )
+ echo '<option value="">' . __('&mdash; No role for this site &mdash;') . '</option>';
+else
+ echo '<option value="" selected="selected">' . __('&mdash; No role for this site &mdash;') . '</option>';
+?>
+</select></td></tr>
+<?php endif; //!IS_PROFILE_PAGE
+
+if ( is_multisite() && is_network_admin() && ! IS_PROFILE_PAGE && current_user_can( 'manage_network_options' ) && !isset($super_admins) ) { ?>
+<tr><th><?php _e('Super Admin'); ?></th>
+<td>
+<?php if ( $profileuser->user_email != get_site_option( 'admin_email' ) || ! is_super_admin( $profileuser->ID ) ) : ?>
+<p><label><input type="checkbox" id="super_admin" name="super_admin"<?php checked( is_super_admin( $profileuser->ID ) ); ?> /> <?php _e( 'Grant this user super admin privileges for the Network.' ); ?></label></p>
+<?php else : ?>
+<p><?php _e( 'Super admin privileges cannot be removed because this user has the network admin email.' ); ?></p>
+<?php endif; ?>
+</td></tr>
+<?php } ?>
+
+<tr>
+ <th><label for="first_name"><?php _e('First Name') ?></label></th>
+ <td><input type="text" name="first_name" id="first_name" value="<?php echo esc_attr($profileuser->first_name) ?>" class="regular-text" /></td>
+</tr>
+
+<tr>
+ <th><label for="last_name"><?php _e('Last Name') ?></label></th>
+ <td><input type="text" name="last_name" id="last_name" value="<?php echo esc_attr($profileuser->last_name) ?>" class="regular-text" /></td>
+</tr>
+
+<tr>
+ <th><label for="nickname"><?php _e('Nickname'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
+ <td><input type="text" name="nickname" id="nickname" value="<?php echo esc_attr($profileuser->nickname) ?>" class="regular-text" /></td>
+</tr>
+
+<tr>
+ <th><label for="display_name"><?php _e('Display name publicly as') ?></label></th>
+ <td>
+ <select name="display_name" id="display_name">
+ <?php
+ $public_display = array();
+ $public_display['display_nickname'] = $profileuser->nickname;
+ $public_display['display_username'] = $profileuser->user_login;
+
+ if ( !empty($profileuser->first_name) )
+ $public_display['display_firstname'] = $profileuser->first_name;
+
+ if ( !empty($profileuser->last_name) )
+ $public_display['display_lastname'] = $profileuser->last_name;
+
+ if ( !empty($profileuser->first_name) && !empty($profileuser->last_name) ) {
+ $public_display['display_firstlast'] = $profileuser->first_name . ' ' . $profileuser->last_name;
+ $public_display['display_lastfirst'] = $profileuser->last_name . ' ' . $profileuser->first_name;
+ }
+
+ if ( !in_array( $profileuser->display_name, $public_display ) ) // Only add this if it isn't duplicated elsewhere
+ $public_display = array( 'display_displayname' => $profileuser->display_name ) + $public_display;
+
+ $public_display = array_map( 'trim', $public_display );
+ $public_display = array_unique( $public_display );
+
+ foreach ( $public_display as $id => $item ) {
+ ?>
+ <option <?php selected( $profileuser->display_name, $item ); ?>><?php echo $item; ?></option>
+ <?php
+ }
+ ?>
+ </select>
+ </td>
+</tr>
+</table>
+
+<h3><?php _e('Contact Info') ?></h3>
+
+<table class="form-table">
+<tr>
+ <th><label for="email"><?php _e('E-mail'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
+ <td><input type="text" name="email" id="email" value="<?php echo esc_attr($profileuser->user_email) ?>" class="regular-text" />
+ <?php
+ $new_email = get_option( $current_user->ID . '_new_email' );
+ if ( $new_email && $new_email['newemail'] != $current_user->user_email && $profileuser->ID == $current_user->ID ) : ?>
+ <div class="updated inline">
+ <p><?php printf( __('There is a pending change of your e-mail to <code>%1$s</code>. <a href="%2$s">Cancel</a>'), $new_email['newemail'], esc_url( self_admin_url( 'profile.php?dismiss=' . $current_user->ID . '_new_email' ) ) ); ?></p>
+ </div>
+ <?php endif; ?>
+ </td>
+</tr>
+
+<tr>
+ <th><label for="url"><?php _e('Website') ?></label></th>
+ <td><input type="text" name="url" id="url" value="<?php echo esc_attr($profileuser->user_url) ?>" class="regular-text code" /></td>
+</tr>
+
+<?php
+ foreach (_wp_get_user_contactmethods( $profileuser ) as $name => $desc) {
+?>
+<tr>
+ <th><label for="<?php echo $name; ?>"><?php echo apply_filters('user_'.$name.'_label', $desc); ?></label></th>
+ <td><input type="text" name="<?php echo $name; ?>" id="<?php echo $name; ?>" value="<?php echo esc_attr($profileuser->$name) ?>" class="regular-text" /></td>
+</tr>
+<?php
+ }
+?>
+</table>
+
+<h3><?php IS_PROFILE_PAGE ? _e('About Yourself') : _e('About the user'); ?></h3>
+
+<table class="form-table">
+<tr>
+ <th><label for="description"><?php _e('Biographical Info'); ?></label></th>
+ <td><textarea name="description" id="description" rows="5" cols="30"><?php echo $profileuser->description; // textarea_escaped ?></textarea><br />
+ <span class="description"><?php _e('Share a little biographical information to fill out your profile. This may be shown publicly.'); ?></span></td>
+</tr>
+
+<?php
+$show_password_fields = apply_filters('show_password_fields', true, $profileuser);
+if ( $show_password_fields ) :
+?>
+<tr id="password">
+ <th><label for="pass1"><?php _e('New Password'); ?></label></th>
+ <td>
+ <input class="hidden" value=" " /><!-- #24364 workaround -->
+ <input type="password" name="pass1" id="pass1" size="16" value="" autocomplete="off" /> <span class="description"><?php _e("If you would like to change the password type a new one. Otherwise leave this blank."); ?></span>
+ </td>
+</tr>
+<tr>
+ <th scope="row"><label for="pass2"><?php _e('Repeat New Password'); ?></label></th>
+ <td>
+ <input name="pass2" type="password" id="pass2" size="16" value="" autocomplete="off" /> <span class="description" for="pass2"><?php _e("Type your new password again."); ?></span>
+ <br />
+ <div id="pass-strength-result"><?php _e('Strength indicator'); ?></div>
+ <p class="description indicator-hint"><?php _e('Hint: The password should be at least seven characters long. To make it stronger, use upper and lower case letters, numbers and symbols like ! " ? $ % ^ &amp; ).'); ?></p>
+ </td>
+</tr>
+<?php endif; ?>
+</table>
+
+<?php
+ if ( IS_PROFILE_PAGE )
+ do_action( 'show_user_profile', $profileuser );
+ else
+ do_action( 'edit_user_profile', $profileuser );
+?>
+
+<?php if ( count( $profileuser->caps ) > count( $profileuser->roles ) && apply_filters( 'additional_capabilities_display', true, $profileuser ) ) : ?>
+<h3><?php _e( 'Additional Capabilities' ); ?></h3>
+<table class="form-table">
+<tr>
+ <th scope="row"><?php _e( 'Capabilities' ); ?></th>
+ <td>
+<?php
+ $output = '';
+ foreach ( $profileuser->caps as $cap => $value ) {
+ if ( ! $wp_roles->is_role( $cap ) ) {
+ if ( '' != $output )
+ $output .= ', ';
+ $output .= $value ? $cap : sprintf( __( 'Denied: %s' ), $cap );
+ }
+ }
+ echo $output;
+?>
+ </td>
+</tr>
+</table>
+<?php endif; ?>
+
+<input type="hidden" name="action" value="update" />
+<input type="hidden" name="user_id" id="user_id" value="<?php echo esc_attr($user_id); ?>" />
+
+<?php submit_button( IS_PROFILE_PAGE ? __('Update Profile') : __('Update User') ); ?>
+
+</form>
+</div>
+<?php
+break;
+}
+?>
+<script type="text/javascript">
+ if (window.location.hash == '#password') {
+ document.getElementById('pass1').focus();
+ }
+</script>
+<?php
+include( ABSPATH . 'wp-admin/admin-footer.php');
diff --git a/src/wp-admin/user-new.php b/src/wp-admin/user-new.php
new file mode 100644
index 0000000000..ccae15ff26
--- /dev/null
+++ b/src/wp-admin/user-new.php
@@ -0,0 +1,389 @@
+<?php
+/**
+ * New User Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once('./admin.php');
+
+if ( is_multisite() ) {
+ if ( ! current_user_can( 'create_users' ) && ! current_user_can( 'promote_users' ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+} elseif ( ! current_user_can( 'create_users' ) ) {
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+}
+
+if ( is_multisite() ) {
+ function admin_created_user_email( $text ) {
+ $roles = get_editable_roles();
+ $role = $roles[ $_REQUEST['role'] ];
+ /* translators: 1: Site name, 2: site URL, 3: role */
+ return sprintf( __( 'Hi,
+You\'ve been invited to join \'%1$s\' at
+%2$s with the role of %3$s.
+If you do not want to join this site please ignore
+this email. This invitation will expire in a few days.
+
+Please click the following link to activate your user account:
+%%s' ), get_bloginfo( 'name' ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ) );
+ }
+ add_filter( 'wpmu_signup_user_notification_email', 'admin_created_user_email' );
+
+ function admin_created_user_subject( $text ) {
+ return sprintf( __( '[%s] Your site invite' ), get_bloginfo( 'name' ) );
+ }
+}
+
+if ( isset($_REQUEST['action']) && 'adduser' == $_REQUEST['action'] ) {
+ check_admin_referer( 'add-user', '_wpnonce_add-user' );
+
+ $user_details = null;
+ if ( false !== strpos($_REQUEST[ 'email' ], '@') ) {
+ $user_details = get_user_by('email', $_REQUEST[ 'email' ]);
+ } else {
+ if ( is_super_admin() ) {
+ $user_details = get_user_by('login', $_REQUEST[ 'email' ]);
+ } else {
+ wp_redirect( add_query_arg( array('update' => 'enter_email'), 'user-new.php' ) );
+ die();
+ }
+ }
+
+ if ( !$user_details ) {
+ wp_redirect( add_query_arg( array('update' => 'does_not_exist'), 'user-new.php' ) );
+ die();
+ }
+
+ if ( ! current_user_can('promote_user', $user_details->ID) )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+ // Adding an existing user to this blog
+ $new_user_email = $user_details->user_email;
+ $redirect = 'user-new.php';
+ $username = $user_details->user_login;
+ $user_id = $user_details->ID;
+ if ( ( $username != null && !is_super_admin( $user_id ) ) && ( array_key_exists($blog_id, get_blogs_of_user($user_id)) ) ) {
+ $redirect = add_query_arg( array('update' => 'addexisting'), 'user-new.php' );
+ } else {
+ if ( isset( $_POST[ 'noconfirmation' ] ) && is_super_admin() ) {
+ add_existing_user_to_blog( array( 'user_id' => $user_id, 'role' => $_REQUEST[ 'role' ] ) );
+ $redirect = add_query_arg( array('update' => 'addnoconfirmation'), 'user-new.php' );
+ } else {
+ $newuser_key = substr( md5( $user_id ), 0, 5 );
+ add_option( 'new_user_' . $newuser_key, array( 'user_id' => $user_id, 'email' => $user_details->user_email, 'role' => $_REQUEST[ 'role' ] ) );
+
+ $roles = get_editable_roles();
+ $role = $roles[ $_REQUEST['role'] ];
+ /* translators: 1: Site name, 2: site URL, 3: role, 4: activation URL */
+ $message = __( 'Hi,
+
+You\'ve been invited to join \'%1$s\' at
+%2$s with the role of %3$s.
+
+Please click the following link to confirm the invite:
+%4$s' );
+ wp_mail( $new_user_email, sprintf( __( '[%s] Joining confirmation' ), get_option( 'blogname' ) ), sprintf( $message, get_option( 'blogname' ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ), home_url( "/newbloguser/$newuser_key/" ) ) );
+ $redirect = add_query_arg( array('update' => 'add'), 'user-new.php' );
+ }
+ }
+ wp_redirect( $redirect );
+ die();
+} elseif ( isset($_REQUEST['action']) && 'createuser' == $_REQUEST['action'] ) {
+ check_admin_referer( 'create-user', '_wpnonce_create-user' );
+
+ if ( ! current_user_can('create_users') )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+ if ( ! is_multisite() ) {
+ $user_id = edit_user();
+
+ if ( is_wp_error( $user_id ) ) {
+ $add_user_errors = $user_id;
+ } else {
+ if ( current_user_can( 'list_users' ) )
+ $redirect = 'users.php?update=add&id=' . $user_id;
+ else
+ $redirect = add_query_arg( 'update', 'add', 'user-new.php' );
+ wp_redirect( $redirect );
+ die();
+ }
+ } else {
+ // Adding a new user to this blog
+ $user_details = wpmu_validate_user_signup( $_REQUEST[ 'user_login' ], $_REQUEST[ 'email' ] );
+ if ( is_wp_error( $user_details[ 'errors' ] ) && !empty( $user_details[ 'errors' ]->errors ) ) {
+ $add_user_errors = $user_details[ 'errors' ];
+ } else {
+ $new_user_login = apply_filters('pre_user_login', sanitize_user(wp_unslash($_REQUEST['user_login']), true));
+ if ( isset( $_POST[ 'noconfirmation' ] ) && is_super_admin() ) {
+ add_filter( 'wpmu_signup_user_notification', '__return_false' ); // Disable confirmation email
+ }
+ wpmu_signup_user( $new_user_login, $_REQUEST[ 'email' ], array( 'add_to_blog' => $wpdb->blogid, 'new_role' => $_REQUEST[ 'role' ] ) );
+ if ( isset( $_POST[ 'noconfirmation' ] ) && is_super_admin() ) {
+ $key = $wpdb->get_var( $wpdb->prepare( "SELECT activation_key FROM {$wpdb->signups} WHERE user_login = %s AND user_email = %s", $new_user_login, $_REQUEST[ 'email' ] ) );
+ wpmu_activate_signup( $key );
+ $redirect = add_query_arg( array('update' => 'addnoconfirmation'), 'user-new.php' );
+ } else {
+ $redirect = add_query_arg( array('update' => 'newuserconfirmation'), 'user-new.php' );
+ }
+ wp_redirect( $redirect );
+ die();
+ }
+ }
+}
+
+$title = __('Add New User');
+$parent_file = 'users.php';
+
+$do_both = false;
+if ( is_multisite() && current_user_can('promote_users') && current_user_can('create_users') )
+ $do_both = true;
+
+$help = '<p>' . __('To add a new user to your site, fill in the form on this screen and click the Add New User button at the bottom.') . '</p>';
+
+if ( is_multisite() ) {
+ $help .= '<p>' . __('Because this is a multisite installation, you may add accounts that already exist on the Network by specifying a username or email, and defining a role. For more options, such as specifying a password, you have to be a Network Administrator and use the hover link under an existing user&#8217;s name to Edit the user profile under Network Admin > All Users.') . '</p>' .
+ '<p>' . __('New users will receive an email letting them know they&#8217;ve been added as a user for your site. This email will also contain their password. Check the box if you don&#8217;t want the user to receive a welcome email.') . '</p>';
+} else {
+ $help .= '<p>' . __('You must assign a password to the new user, which they can change after logging in. The username, however, cannot be changed.') . '</p>' .
+ '<p>' . __('New users will receive an email letting them know they&#8217;ve been added as a user for your site. By default, this email will also contain their password. Uncheck the box if you don&#8217;t want the password to be included in the welcome email.') . '</p>';
+}
+
+$help .= '<p>' . __('Remember to click the Add New User button at the bottom of this screen when you are finished.') . '</p>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => $help,
+) );
+
+get_current_screen()->add_help_tab( array(
+'id' => 'user-roles',
+'title' => __('User Roles'),
+'content' => '<p>' . __('Here is a basic overview of the different user roles and the permissions associated with each one:') . '</p>' .
+ '<ul>' .
+ '<li>' . __('Administrators have access to all the administration features.') . '</li>' .
+ '<li>' . __('Editors can publish posts, manage posts as well as manage other people&#8217;s posts, etc.') . '</li>' .
+ '<li>' . __('Authors can publish and manage their own posts, and are able to upload files.') . '</li>' .
+ '<li>' . __('Contributors can write and manage their posts but not publish posts or upload media files.') . '</li>' .
+ '<li>' . __('Subscribers can read comments/comment/receive newsletters, etc. but cannot create regular site content.') . '</li>' .
+ '</ul>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Users_Add_New_Screen" target="_blank">Documentation on Adding New Users</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+wp_enqueue_script('wp-ajax-response');
+wp_enqueue_script('user-profile');
+
+if ( is_multisite() && current_user_can( 'promote_users' ) && ! wp_is_large_network( 'users' )
+ && ( is_super_admin() || apply_filters( 'autocomplete_users_for_site_admins', false ) )
+) {
+ wp_enqueue_script( 'user-suggest' );
+}
+
+require_once( 'admin-header.php' );
+
+if ( isset($_GET['update']) ) {
+ $messages = array();
+ if ( is_multisite() ) {
+ switch ( $_GET['update'] ) {
+ case "newuserconfirmation":
+ $messages[] = __('Invitation email sent to new user. A confirmation link must be clicked before their account is created.');
+ break;
+ case "add":
+ $messages[] = __('Invitation email sent to user. A confirmation link must be clicked for them to be added to your site.');
+ break;
+ case "addnoconfirmation":
+ $messages[] = __('User has been added to your site.');
+ break;
+ case "addexisting":
+ $messages[] = __('That user is already a member of this site.');
+ break;
+ case "does_not_exist":
+ $messages[] = __('The requested user does not exist.');
+ break;
+ case "enter_email":
+ $messages[] = __('Please enter a valid email address.');
+ break;
+ }
+ } else {
+ if ( 'add' == $_GET['update'] )
+ $messages[] = __('User added.');
+ }
+}
+?>
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2 id="add-new-user"> <?php
+if ( current_user_can( 'create_users' ) ) {
+ echo _x( 'Add New User', 'user' );
+} elseif ( current_user_can( 'promote_users' ) ) {
+ echo _x( 'Add Existing User', 'user' );
+} ?>
+</h2>
+
+<?php if ( isset($errors) && is_wp_error( $errors ) ) : ?>
+ <div class="error">
+ <ul>
+ <?php
+ foreach ( $errors->get_error_messages() as $err )
+ echo "<li>$err</li>\n";
+ ?>
+ </ul>
+ </div>
+<?php endif;
+
+if ( ! empty( $messages ) ) {
+ foreach ( $messages as $msg )
+ echo '<div id="message" class="updated"><p>' . $msg . '</p></div>';
+} ?>
+
+<?php if ( isset($add_user_errors) && is_wp_error( $add_user_errors ) ) : ?>
+ <div class="error">
+ <?php
+ foreach ( $add_user_errors->get_error_messages() as $message )
+ echo "<p>$message</p>";
+ ?>
+ </div>
+<?php endif; ?>
+<div id="ajax-response"></div>
+
+<?php
+if ( is_multisite() ) {
+ if ( $do_both )
+ echo '<h3 id="add-existing-user">' . __('Add Existing User') . '</h3>';
+ if ( !is_super_admin() ) {
+ _e( 'Enter the email address of an existing user on this network to invite them to this site. That person will be sent an email asking them to confirm the invite.' );
+ $label = __('E-mail');
+ } else {
+ _e( 'Enter the email address or username of an existing user on this network to invite them to this site. That person will be sent an email asking them to confirm the invite.' );
+ $label = __('E-mail or Username');
+ }
+?>
+<form action="" method="post" name="adduser" id="adduser" class="validate"<?php do_action('user_new_form_tag');?>>
+<input name="action" type="hidden" value="adduser" />
+<?php wp_nonce_field( 'add-user', '_wpnonce_add-user' ) ?>
+
+<table class="form-table">
+ <tr class="form-field form-required">
+ <th scope="row"><label for="adduser-email"><?php echo $label; ?></label></th>
+ <td><input name="email" type="text" id="adduser-email" class="wp-suggest-user" value="" /></td>
+ </tr>
+ <tr class="form-field">
+ <th scope="row"><label for="adduser-role"><?php _e('Role'); ?></label></th>
+ <td><select name="role" id="adduser-role">
+ <?php wp_dropdown_roles( get_option('default_role') ); ?>
+ </select>
+ </td>
+ </tr>
+<?php if ( is_super_admin() ) { ?>
+ <tr>
+ <th scope="row"><label for="adduser-noconfirmation"><?php _e('Skip Confirmation Email') ?></label></th>
+ <td><label for="adduser-noconfirmation"><input type="checkbox" name="noconfirmation" id="adduser-noconfirmation" value="1" /> <?php _e( 'Add the user without sending them a confirmation email.' ); ?></label></td>
+ </tr>
+<?php } ?>
+</table>
+<?php submit_button( __( 'Add Existing User '), 'primary', 'adduser', true, array( 'id' => 'addusersub' ) ); ?>
+</form>
+<?php
+} // is_multisite()
+
+if ( current_user_can( 'create_users') ) {
+ if ( $do_both )
+ echo '<h3 id="create-new-user">' . __( 'Add New User' ) . '</h3>';
+?>
+<p><?php _e('Create a brand new user and add them to this site.'); ?></p>
+<form action="" method="post" name="createuser" id="createuser" class="validate"<?php do_action('user_new_form_tag');?>>
+<input name="action" type="hidden" value="createuser" />
+<?php wp_nonce_field( 'create-user', '_wpnonce_create-user' ) ?>
+<?php
+// Load up the passed data, else set to a default.
+foreach ( array( 'user_login' => 'login', 'first_name' => 'firstname', 'last_name' => 'lastname',
+ 'email' => 'email', 'url' => 'uri', 'role' => 'role', 'send_password' => 'send_password', 'noconfirmation' => 'ignore_pass' ) as $post_field => $var ) {
+ $var = "new_user_$var";
+ if( isset( $_POST['createuser'] ) ) {
+ if ( ! isset($$var) )
+ $$var = isset( $_POST[$post_field] ) ? wp_unslash( $_POST[$post_field] ) : '';
+ } else {
+ $$var = false;
+ }
+}
+
+?>
+<table class="form-table">
+ <tr class="form-field form-required">
+ <th scope="row"><label for="user_login"><?php _e('Username'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
+ <td><input name="user_login" type="text" id="user_login" value="<?php echo esc_attr($new_user_login); ?>" aria-required="true" /></td>
+ </tr>
+ <tr class="form-field form-required">
+ <th scope="row"><label for="email"><?php _e('E-mail'); ?> <span class="description"><?php _e('(required)'); ?></span></label></th>
+ <td><input name="email" type="text" id="email" value="<?php echo esc_attr($new_user_email); ?>" /></td>
+ </tr>
+<?php if ( !is_multisite() ) { ?>
+ <tr class="form-field">
+ <th scope="row"><label for="first_name"><?php _e('First Name') ?> </label></th>
+ <td><input name="first_name" type="text" id="first_name" value="<?php echo esc_attr($new_user_firstname); ?>" /></td>
+ </tr>
+ <tr class="form-field">
+ <th scope="row"><label for="last_name"><?php _e('Last Name') ?> </label></th>
+ <td><input name="last_name" type="text" id="last_name" value="<?php echo esc_attr($new_user_lastname); ?>" /></td>
+ </tr>
+ <tr class="form-field">
+ <th scope="row"><label for="url"><?php _e('Website') ?></label></th>
+ <td><input name="url" type="text" id="url" class="code" value="<?php echo esc_attr($new_user_uri); ?>" /></td>
+ </tr>
+<?php if ( apply_filters('show_password_fields', true) ) : ?>
+ <tr class="form-field form-required">
+ <th scope="row"><label for="pass1"><?php _e('Password'); ?> <span class="description"><?php /* translators: password input field */_e('(required)'); ?></span></label></th>
+ <td>
+ <input class="hidden" value=" " /><!-- #24364 workaround -->
+ <input name="pass1" type="password" id="pass1" autocomplete="off" />
+ </td>
+ </tr>
+ <tr class="form-field form-required">
+ <th scope="row"><label for="pass2"><?php _e('Repeat Password'); ?> <span class="description"><?php /* translators: password input field */_e('(required)'); ?></span></label></th>
+ <td>
+ <input name="pass2" type="password" id="pass2" autocomplete="off" />
+ <br />
+ <div id="pass-strength-result"><?php _e('Strength indicator'); ?></div>
+ <p class="description indicator-hint"><?php _e('Hint: The password should be at least seven characters long. To make it stronger, use upper and lower case letters, numbers and symbols like ! " ? $ % ^ &amp; ).'); ?></p>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><label for="send_password"><?php _e('Send Password?') ?></label></th>
+ <td><label for="send_password"><input type="checkbox" name="send_password" id="send_password" <?php checked( $new_user_send_password ); ?> /> <?php _e('Send this password to the new user by email.'); ?></label></td>
+ </tr>
+<?php endif; ?>
+<?php } // !is_multisite ?>
+ <tr class="form-field">
+ <th scope="row"><label for="role"><?php _e('Role'); ?></label></th>
+ <td><select name="role" id="role">
+ <?php
+ if ( !$new_user_role )
+ $new_user_role = !empty($current_role) ? $current_role : get_option('default_role');
+ wp_dropdown_roles($new_user_role);
+ ?>
+ </select>
+ </td>
+ </tr>
+ <?php if ( is_multisite() && is_super_admin() ) { ?>
+ <tr>
+ <th scope="row"><label for="noconfirmation"><?php _e('Skip Confirmation Email') ?></label></th>
+ <td><label for="noconfirmation"><input type="checkbox" name="noconfirmation" id="noconfirmation" value="1" <?php checked( $new_user_ignore_pass ); ?> /> <?php _e( 'Add the user without sending them a confirmation email.' ); ?></label></td>
+ </tr>
+ <?php } ?>
+</table>
+
+<?php submit_button( __( 'Add New User '), 'primary', 'createuser', true, array( 'id' => 'createusersub' ) ); ?>
+
+</form>
+<?php } // current_user_can('create_users') ?>
+</div>
+<?php
+include('./admin-footer.php');
diff --git a/src/wp-admin/user/about.php b/src/wp-admin/user/about.php
new file mode 100644
index 0000000000..a5dbc9899f
--- /dev/null
+++ b/src/wp-admin/user/about.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * User Dashboard About administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.4.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+require( '../about.php' ); \ No newline at end of file
diff --git a/src/wp-admin/user/admin.php b/src/wp-admin/user/admin.php
new file mode 100644
index 0000000000..25691c866a
--- /dev/null
+++ b/src/wp-admin/user/admin.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * WordPress User Administration Bootstrap
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.1.0
+ */
+
+define('WP_USER_ADMIN', true);
+
+require_once( dirname(dirname(__FILE__)) . '/admin.php');
+
+if ( ! is_multisite() ) {
+ wp_redirect( admin_url() );
+ exit;
+}
+
+$redirect_user_admin_request = ( ( $current_blog->domain != $current_site->domain ) || ( $current_blog->path != $current_site->path ) );
+$redirect_user_admin_request = apply_filters( 'redirect_user_admin_request', $redirect_user_admin_request );
+if ( $redirect_user_admin_request ) {
+ wp_redirect( user_admin_url() );
+ exit;
+}
+unset( $redirect_user_admin_request );
diff --git a/src/wp-admin/user/credits.php b/src/wp-admin/user/credits.php
new file mode 100644
index 0000000000..faba84d012
--- /dev/null
+++ b/src/wp-admin/user/credits.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * User Dashboard Credits administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.4.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+require( '../credits.php' ); \ No newline at end of file
diff --git a/src/wp-admin/user/freedoms.php b/src/wp-admin/user/freedoms.php
new file mode 100644
index 0000000000..3d04407ade
--- /dev/null
+++ b/src/wp-admin/user/freedoms.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * User Dashboard Freedoms administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.4.0
+ */
+
+/** Load WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+require( '../freedoms.php' ); \ No newline at end of file
diff --git a/src/wp-admin/user/index.php b/src/wp-admin/user/index.php
new file mode 100644
index 0000000000..fe0c27cffd
--- /dev/null
+++ b/src/wp-admin/user/index.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * User Dashboard Administration Screen
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.1.0
+ */
+
+require_once( './admin.php' );
+
+require( '../index.php' );
diff --git a/src/wp-admin/user/menu.php b/src/wp-admin/user/menu.php
new file mode 100644
index 0000000000..9f30076bd4
--- /dev/null
+++ b/src/wp-admin/user/menu.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Build User Administration Menu.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.1.0
+ */
+
+$menu[2] = array(__('Dashboard'), 'exist', 'index.php', '', 'menu-top menu-top-first menu-icon-dashboard', 'menu-dashboard', 'div');
+
+$menu[4] = array( '', 'exist', 'separator1', '', 'wp-menu-separator' );
+
+$menu[70] = array( __('Profile'), 'exist', 'profile.php', '', 'menu-top menu-icon-users', 'menu-users', 'div' );
+
+$menu[99] = array( '', 'exist', 'separator-last', '', 'wp-menu-separator-last' );
+
+$_wp_real_parent_file['users.php'] = 'profile.php';
+$compat = array();
+$submenu = array();
+
+require_once(ABSPATH . 'wp-admin/includes/menu.php');
diff --git a/src/wp-admin/user/profile.php b/src/wp-admin/user/profile.php
new file mode 100644
index 0000000000..b55ba1c3e8
--- /dev/null
+++ b/src/wp-admin/user/profile.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * User Profile Administration Screen.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.1.0
+ */
+
+require_once( './admin.php' );
+
+require( '../profile.php' ); \ No newline at end of file
diff --git a/src/wp-admin/user/user-edit.php b/src/wp-admin/user/user-edit.php
new file mode 100644
index 0000000000..31794ba0d2
--- /dev/null
+++ b/src/wp-admin/user/user-edit.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Edit user administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ * @since 3.1.0
+ */
+
+require_once( './admin.php' );
+
+require( '../user-edit.php' ); \ No newline at end of file
diff --git a/src/wp-admin/users.php b/src/wp-admin/users.php
new file mode 100644
index 0000000000..e807487a57
--- /dev/null
+++ b/src/wp-admin/users.php
@@ -0,0 +1,458 @@
+<?php
+/**
+ * Users administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+if ( ! current_user_can( 'list_users' ) )
+ wp_die( __( 'Cheatin&#8217; uh?' ) );
+
+$wp_list_table = _get_list_table('WP_Users_List_Table');
+$pagenum = $wp_list_table->get_pagenum();
+$title = __('Users');
+$parent_file = 'users.php';
+
+add_screen_option( 'per_page', array('label' => _x( 'Users', 'users per page (screen options)' )) );
+
+// contextual help - choose Help on the top right of admin panel to preview this.
+get_current_screen()->add_help_tab( array(
+ 'id' => 'overview',
+ 'title' => __('Overview'),
+ 'content' => '<p>' . __('This screen lists all the existing users for your site. Each user has one of five defined roles as set by the site admin: Site Administrator, Editor, Author, Contributor, or Subscriber. Users with roles other than Administrator will see fewer options in the dashboard navigation when they are logged in, based on their role.') . '</p>' .
+ '<p>' . __('To add a new user for your site, click the Add New button at the top of the screen or Add New in the Users menu section.') . '</p>'
+) ) ;
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'screen-display',
+ 'title' => __('Screen Display'),
+ 'content' => '<p>' . __('You can customize the display of this screen in a number of ways:') . '</p>' .
+ '<ul>' .
+ '<li>' . __('You can hide/display columns based on your needs and decide how many users to list per screen using the Screen Options tab.') . '</li>' .
+ '<li>' . __('You can filter the list of users by User Role using the text links in the upper left to show All, Administrator, Editor, Author, Contributor, or Subscriber. The default view is to show all users. Unused User Roles are not listed.') . '</li>' .
+ '<li>' . __('You can view all posts made by a user by clicking on the number under the Posts column.') . '</li>' .
+ '</ul>'
+) );
+
+$help = '<p>' . __('Hovering over a row in the users list will display action links that allow you to manage users. You can perform the following actions:') . '</p>' .
+ '<ul>' .
+ '<li>' . __('Edit takes you to the editable profile screen for that user. You can also reach that screen by clicking on the username.') . '</li>';
+
+if ( is_multisite() )
+ $help .= '<li>' . __( 'Remove allows you to remove a user from your site. It does not delete their posts. You can also remove multiple users at once by using Bulk Actions.' ) . '</li>';
+else
+ $help .= '<li>' . __( 'Delete brings you to the Delete Users screen for confirmation, where you can permanently remove a user from your site and delete their posts. You can also delete multiple users at once by using Bulk Actions.' ) . '</li>';
+
+$help .= '</ul>';
+
+get_current_screen()->add_help_tab( array(
+ 'id' => 'actions',
+ 'title' => __('Actions'),
+ 'content' => $help,
+) );
+unset( $help );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Users_Screen" target="_blank">Documentation on Managing Users</a>') . '</p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Roles_and_Capabilities" target="_blank">Descriptions of Roles and Capabilities</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( empty($_REQUEST) ) {
+ $referer = '<input type="hidden" name="wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
+} elseif ( isset($_REQUEST['wp_http_referer']) ) {
+ $redirect = remove_query_arg(array('wp_http_referer', 'updated', 'delete_count'), wp_unslash( $_REQUEST['wp_http_referer'] ) );
+ $referer = '<input type="hidden" name="wp_http_referer" value="' . esc_attr($redirect) . '" />';
+} else {
+ $redirect = 'users.php';
+ $referer = '';
+}
+
+$update = '';
+
+/**
+ * @since 3.5.0
+ * @access private
+ */
+function delete_users_add_js() { ?>
+<script>
+jQuery(document).ready( function($) {
+ var submit = $('#submit').prop('disabled', true);
+ $('input[name=delete_option]').one('change', function() {
+ submit.prop('disabled', false);
+ });
+ $('#reassign_user').focus( function() {
+ $('#delete_option1').prop('checked', true).trigger('change');
+ });
+});
+</script>
+<?php
+}
+
+switch ( $wp_list_table->current_action() ) {
+
+/* Bulk Dropdown menu Role changes */
+case 'promote':
+ check_admin_referer('bulk-users');
+
+ if ( ! current_user_can( 'promote_users' ) )
+ wp_die( __( 'You can&#8217;t edit that user.' ) );
+
+ if ( empty($_REQUEST['users']) ) {
+ wp_redirect($redirect);
+ exit();
+ }
+
+ $editable_roles = get_editable_roles();
+ if ( empty( $editable_roles[$_REQUEST['new_role']] ) )
+ wp_die(__('You can&#8217;t give users that role.'));
+
+ $userids = $_REQUEST['users'];
+ $update = 'promote';
+ foreach ( $userids as $id ) {
+ $id = (int) $id;
+
+ if ( ! current_user_can('promote_user', $id) )
+ wp_die(__('You can&#8217;t edit that user.'));
+ // The new role of the current user must also have the promote_users cap or be a multisite super admin
+ if ( $id == $current_user->ID && ! $wp_roles->role_objects[ $_REQUEST['new_role'] ]->has_cap('promote_users')
+ && ! ( is_multisite() && is_super_admin() ) ) {
+ $update = 'err_admin_role';
+ continue;
+ }
+
+ // If the user doesn't already belong to the blog, bail.
+ if ( is_multisite() && !is_user_member_of_blog( $id ) )
+ wp_die(__('Cheatin&#8217; uh?'));
+
+ $user = get_userdata( $id );
+ $user->set_role($_REQUEST['new_role']);
+ }
+
+ wp_redirect(add_query_arg('update', $update, $redirect));
+ exit();
+
+break;
+
+case 'dodelete':
+ if ( is_multisite() )
+ wp_die( __('User deletion is not allowed from this screen.') );
+
+ check_admin_referer('delete-users');
+
+ if ( empty($_REQUEST['users']) ) {
+ wp_redirect($redirect);
+ exit();
+ }
+
+ $userids = array_map( 'intval', (array) $_REQUEST['users'] );
+
+ if ( empty( $_REQUEST['delete_option'] ) ) {
+ $url = self_admin_url( 'users.php?action=delete&users[]=' . implode( '&users[]=', $userids ) . '&error=true' );
+ $url = str_replace( '&amp;', '&', wp_nonce_url( $url, 'bulk-users' ) );
+ wp_redirect( $url );
+ exit;
+ }
+
+ if ( ! current_user_can( 'delete_users' ) )
+ wp_die(__('You can&#8217;t delete users.'));
+
+ $update = 'del';
+ $delete_count = 0;
+
+ foreach ( $userids as $id ) {
+ if ( ! current_user_can( 'delete_user', $id ) )
+ wp_die(__( 'You can&#8217;t delete that user.' ) );
+
+ if ( $id == $current_user->ID ) {
+ $update = 'err_admin_del';
+ continue;
+ }
+ switch ( $_REQUEST['delete_option'] ) {
+ case 'delete':
+ wp_delete_user( $id );
+ break;
+ case 'reassign':
+ wp_delete_user( $id, $_REQUEST['reassign_user'] );
+ break;
+ }
+ ++$delete_count;
+ }
+
+ $redirect = add_query_arg( array('delete_count' => $delete_count, 'update' => $update), $redirect);
+ wp_redirect($redirect);
+ exit();
+
+break;
+
+case 'delete':
+ if ( is_multisite() )
+ wp_die( __('User deletion is not allowed from this screen.') );
+
+ check_admin_referer('bulk-users');
+
+ if ( empty($_REQUEST['users']) && empty($_REQUEST['user']) ) {
+ wp_redirect($redirect);
+ exit();
+ }
+
+ if ( ! current_user_can( 'delete_users' ) )
+ $errors = new WP_Error( 'edit_users', __( 'You can&#8217;t delete users.' ) );
+
+ if ( empty($_REQUEST['users']) )
+ $userids = array( intval( $_REQUEST['user'] ) );
+ else
+ $userids = array_map( 'intval', (array) $_REQUEST['users'] );
+
+ add_action( 'admin_head', 'delete_users_add_js' );
+
+ include ('admin-header.php');
+?>
+<form action="" method="post" name="updateusers" id="updateusers">
+<?php wp_nonce_field('delete-users') ?>
+<?php echo $referer; ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php _e('Delete Users'); ?></h2>
+<?php if ( isset( $_REQUEST['error'] ) ) : ?>
+<div class="error">
+ <p><strong><?php _e( 'ERROR:' ); ?></strong> <?php _e( 'Please select an option.' ); ?></p>
+</div>
+<?php endif; ?>
+<p><?php echo _n( 'You have specified this user for deletion:', 'You have specified these users for deletion:', count( $userids ) ); ?></p>
+<ul>
+<?php
+ $go_delete = 0;
+ foreach ( $userids as $id ) {
+ $user = get_userdata( $id );
+ if ( $id == $current_user->ID ) {
+ echo "<li>" . sprintf(__('ID #%1$s: %2$s <strong>The current user will not be deleted.</strong>'), $id, $user->user_login) . "</li>\n";
+ } else {
+ echo "<li><input type=\"hidden\" name=\"users[]\" value=\"" . esc_attr($id) . "\" />" . sprintf(__('ID #%1$s: %2$s'), $id, $user->user_login) . "</li>\n";
+ $go_delete++;
+ }
+ }
+ ?>
+ </ul>
+<?php if ( $go_delete ) : ?>
+ <fieldset><p><legend><?php echo _n( 'What should be done with posts owned by this user?', 'What should be done with posts owned by these users?', $go_delete ); ?></legend></p>
+ <ul style="list-style:none;">
+ <li><label><input type="radio" id="delete_option0" name="delete_option" value="delete" />
+ <?php _e('Delete all posts.'); ?></label></li>
+ <li><input type="radio" id="delete_option1" name="delete_option" value="reassign" />
+ <?php echo '<label for="delete_option1">' . __( 'Attribute all posts to:' ) . '</label> ';
+ wp_dropdown_users( array( 'name' => 'reassign_user', 'exclude' => array_diff( $userids, array($current_user->ID) ) ) ); ?></li>
+ </ul></fieldset>
+ <input type="hidden" name="action" value="dodelete" />
+ <?php submit_button( __('Confirm Deletion'), 'secondary' ); ?>
+<?php else : ?>
+ <p><?php _e('There are no valid users selected for deletion.'); ?></p>
+<?php endif; ?>
+</div>
+</form>
+<?php
+
+break;
+
+case 'doremove':
+ check_admin_referer('remove-users');
+
+ if ( ! is_multisite() )
+ wp_die( __( 'You can&#8217;t remove users.' ) );
+
+ if ( empty($_REQUEST['users']) ) {
+ wp_redirect($redirect);
+ exit;
+ }
+
+ if ( ! current_user_can( 'remove_users' ) )
+ wp_die( __( 'You can&#8217;t remove users.' ) );
+
+ $userids = $_REQUEST['users'];
+
+ $update = 'remove';
+ foreach ( $userids as $id ) {
+ $id = (int) $id;
+ if ( $id == $current_user->ID && !is_super_admin() ) {
+ $update = 'err_admin_remove';
+ continue;
+ }
+ if ( !current_user_can('remove_user', $id) ) {
+ $update = 'err_admin_remove';
+ continue;
+ }
+ remove_user_from_blog($id, $blog_id);
+ }
+
+ $redirect = add_query_arg( array('update' => $update), $redirect);
+ wp_redirect($redirect);
+ exit;
+
+break;
+
+case 'remove':
+
+ check_admin_referer('bulk-users');
+
+ if ( ! is_multisite() )
+ wp_die( __( 'You can&#8217;t remove users.' ) );
+
+ if ( empty($_REQUEST['users']) && empty($_REQUEST['user']) ) {
+ wp_redirect($redirect);
+ exit();
+ }
+
+ if ( !current_user_can('remove_users') )
+ $error = new WP_Error('edit_users', __('You can&#8217;t remove users.'));
+
+ if ( empty($_REQUEST['users']) )
+ $userids = array(intval($_REQUEST['user']));
+ else
+ $userids = $_REQUEST['users'];
+
+ include ('admin-header.php');
+?>
+<form action="" method="post" name="updateusers" id="updateusers">
+<?php wp_nonce_field('remove-users') ?>
+<?php echo $referer; ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php _e('Remove Users from Site'); ?></h2>
+<p><?php _e('You have specified these users for removal:'); ?></p>
+<ul>
+<?php
+ $go_remove = false;
+ foreach ( $userids as $id ) {
+ $id = (int) $id;
+ $user = get_userdata( $id );
+ if ( $id == $current_user->ID && !is_super_admin() ) {
+ echo "<li>" . sprintf(__('ID #%1$s: %2$s <strong>The current user will not be removed.</strong>'), $id, $user->user_login) . "</li>\n";
+ } elseif ( !current_user_can('remove_user', $id) ) {
+ echo "<li>" . sprintf(__('ID #%1$s: %2$s <strong>You don\'t have permission to remove this user.</strong>'), $id, $user->user_login) . "</li>\n";
+ } else {
+ echo "<li><input type=\"hidden\" name=\"users[]\" value=\"{$id}\" />" . sprintf(__('ID #%1$s: %2$s'), $id, $user->user_login) . "</li>\n";
+ $go_remove = true;
+ }
+ }
+ ?>
+<?php if ( $go_remove ) : ?>
+ <input type="hidden" name="action" value="doremove" />
+ <?php submit_button( __('Confirm Removal'), 'secondary' ); ?>
+<?php else : ?>
+ <p><?php _e('There are no valid users selected for removal.'); ?></p>
+<?php endif; ?>
+</div>
+</form>
+<?php
+
+break;
+
+default:
+
+ if ( !empty($_GET['_wp_http_referer']) ) {
+ wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce'), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ exit;
+ }
+
+ $wp_list_table->prepare_items();
+ $total_pages = $wp_list_table->get_pagination_arg( 'total_pages' );
+ if ( $pagenum > $total_pages && $total_pages > 0 ) {
+ wp_redirect( add_query_arg( 'paged', $total_pages ) );
+ exit;
+ }
+
+ include('./admin-header.php');
+
+ $messages = array();
+ if ( isset($_GET['update']) ) :
+ switch($_GET['update']) {
+ case 'del':
+ case 'del_many':
+ $delete_count = isset($_GET['delete_count']) ? (int) $_GET['delete_count'] : 0;
+ $messages[] = '<div id="message" class="updated"><p>' . sprintf( _n( 'User deleted.', '%s users deleted.', $delete_count ), number_format_i18n( $delete_count ) ) . '</p></div>';
+ break;
+ case 'add':
+ if ( isset( $_GET['id'] ) && ( $user_id = $_GET['id'] ) && current_user_can( 'edit_user', $user_id ) ) {
+ $messages[] = '<div id="message" class="updated"><p>' . sprintf( __( 'New user created. <a href="%s">Edit user</a>' ),
+ esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ),
+ self_admin_url( 'user-edit.php?user_id=' . $user_id ) ) ) ) . '</p></div>';
+ } else {
+ $messages[] = '<div id="message" class="updated"><p>' . __( 'New user created.' ) . '</p></div>';
+ }
+ break;
+ case 'promote':
+ $messages[] = '<div id="message" class="updated"><p>' . __('Changed roles.') . '</p></div>';
+ break;
+ case 'err_admin_role':
+ $messages[] = '<div id="message" class="error"><p>' . __('The current user&#8217;s role must have user editing capabilities.') . '</p></div>';
+ $messages[] = '<div id="message" class="updated"><p>' . __('Other user roles have been changed.') . '</p></div>';
+ break;
+ case 'err_admin_del':
+ $messages[] = '<div id="message" class="error"><p>' . __('You can&#8217;t delete the current user.') . '</p></div>';
+ $messages[] = '<div id="message" class="updated"><p>' . __('Other users have been deleted.') . '</p></div>';
+ break;
+ case 'remove':
+ $messages[] = '<div id="message" class="updated fade"><p>' . __('User removed from this site.') . '</p></div>';
+ break;
+ case 'err_admin_remove':
+ $messages[] = '<div id="message" class="error"><p>' . __("You can't remove the current user.") . '</p></div>';
+ $messages[] = '<div id="message" class="updated fade"><p>' . __('Other users have been removed.') . '</p></div>';
+ break;
+ }
+ endif; ?>
+
+<?php if ( isset($errors) && is_wp_error( $errors ) ) : ?>
+ <div class="error">
+ <ul>
+ <?php
+ foreach ( $errors->get_error_messages() as $err )
+ echo "<li>$err</li>\n";
+ ?>
+ </ul>
+ </div>
+<?php endif;
+
+if ( ! empty($messages) ) {
+ foreach ( $messages as $msg )
+ echo $msg;
+} ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2>
+<?php
+echo esc_html( $title );
+if ( current_user_can( 'create_users' ) ) { ?>
+ <a href="user-new.php" class="add-new-h2"><?php echo esc_html_x( 'Add New', 'user' ); ?></a>
+<?php } elseif ( is_multisite() && current_user_can( 'promote_users' ) ) { ?>
+ <a href="user-new.php" class="add-new-h2"><?php echo esc_html_x( 'Add Existing', 'user' ); ?></a>
+<?php }
+
+if ( $usersearch )
+ printf( '<span class="subtitle">' . __('Search results for &#8220;%s&#8221;') . '</span>', esc_html( $usersearch ) ); ?>
+</h2>
+
+<?php $wp_list_table->views(); ?>
+
+<form action="" method="get">
+
+<?php $wp_list_table->search_box( __( 'Search Users' ), 'user' ); ?>
+
+<?php $wp_list_table->display(); ?>
+</form>
+
+<br class="clear" />
+</div>
+<?php
+break;
+
+} // end of the $doaction switch
+
+include('./admin-footer.php');
diff --git a/src/wp-admin/widgets.php b/src/wp-admin/widgets.php
new file mode 100644
index 0000000000..3e0b14621d
--- /dev/null
+++ b/src/wp-admin/widgets.php
@@ -0,0 +1,399 @@
+<?php
+/**
+ * Widgets administration panel.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( './admin.php' );
+
+/** WordPress Administration Widgets API */
+require_once(ABSPATH . 'wp-admin/includes/widgets.php');
+
+if ( ! current_user_can('edit_theme_options') )
+ wp_die( __( 'Cheatin&#8217; uh?' ));
+
+$widgets_access = get_user_setting( 'widgets_access' );
+if ( isset($_GET['widgets-access']) ) {
+ $widgets_access = 'on' == $_GET['widgets-access'] ? 'on' : 'off';
+ set_user_setting( 'widgets_access', $widgets_access );
+}
+
+function wp_widgets_access_body_class($classes) {
+ return "$classes widgets_access ";
+}
+
+if ( 'on' == $widgets_access ) {
+ add_filter( 'admin_body_class', 'wp_widgets_access_body_class' );
+} else {
+ wp_enqueue_script('admin-widgets');
+
+ if ( wp_is_mobile() )
+ wp_enqueue_script( 'jquery-touch-punch' );
+}
+
+do_action( 'sidebar_admin_setup' );
+
+$title = __( 'Widgets' );
+$parent_file = 'themes.php';
+
+get_current_screen()->add_help_tab( array(
+'id' => 'overview',
+'title' => __('Overview'),
+'content' =>
+ '<p>' . __('Widgets are independent sections of content that can be placed into any widgetized area provided by your theme (commonly called sidebars). To populate your sidebars/widget areas with individual widgets, drag and drop the title bars into the desired area. By default, only the first widget area is expanded. To populate additional widget areas, click on their title bars to expand them.') . '</p>
+ <p>' . __('The Available Widgets section contains all the widgets you can choose from. Once you drag a widget into a sidebar, it will open to allow you to configure its settings. When you are happy with the widget settings, click the Save button and the widget will go live on your site. If you click Delete, it will remove the widget.') . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'removing-reusing',
+'title' => __('Removing and Reusing'),
+'content' =>
+ '<p>' . __('If you want to remove the widget but save its setting for possible future use, just drag it into the Inactive Widgets area. You can add them back anytime from there. This is especially helpful when you switch to a theme with fewer or different widget areas.') . '</p>
+ <p>' . __('Widgets may be used multiple times. You can give each widget a title, to display on your site, but it&#8217;s not required.') . '</p>
+ <p>' . __('Enabling Accessibility Mode, via Screen Options, allows you to use Add and Edit buttons instead of using drag and drop.') . '</p>'
+) );
+get_current_screen()->add_help_tab( array(
+'id' => 'missing-widgets',
+'title' => __('Missing Widgets'),
+'content' =>
+ '<p>' . __('Many themes show some sidebar widgets by default until you edit your sidebars, but they are not automatically displayed in your sidebar management tool. After you make your first widget change, you can re-add the default widgets by adding them from the Available Widgets area.') . '</p>' .
+ '<p>' . __('When changing themes, there is often some variation in the number and setup of widget areas/sidebars and sometimes these conflicts make the transition a bit less smooth. If you changed themes and seem to be missing widgets, scroll down on this screen to the Inactive Widgets area, where all of your widgets and their settings will have been saved.') . '</p>'
+) );
+
+get_current_screen()->set_help_sidebar(
+ '<p><strong>' . __('For more information:') . '</strong></p>' .
+ '<p>' . __('<a href="http://codex.wordpress.org/Appearance_Widgets_Screen" target="_blank">Documentation on Widgets</a>') . '</p>' .
+ '<p>' . __('<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>') . '</p>'
+);
+
+if ( ! current_theme_supports( 'widgets' ) ) {
+ wp_die( __( 'The theme you are currently using isn&#8217;t widget-aware, meaning that it has no sidebars that you are able to change. For information on making your theme widget-aware, please <a href="http://codex.wordpress.org/Widgetizing_Themes">follow these instructions</a>.' ) );
+}
+
+// These are the widgets grouped by sidebar
+$sidebars_widgets = wp_get_sidebars_widgets();
+
+if ( empty( $sidebars_widgets ) )
+ $sidebars_widgets = wp_get_widget_defaults();
+
+foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
+ if ( 'wp_inactive_widgets' == $sidebar_id )
+ continue;
+
+ if ( !isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
+ if ( ! empty( $widgets ) ) { // register the inactive_widgets area as sidebar
+ register_sidebar(array(
+ 'name' => __( 'Inactive Sidebar (not used)' ),
+ 'id' => $sidebar_id,
+ 'class' => 'inactive-sidebar orphan-sidebar',
+ 'description' => __( 'This sidebar is no longer available and does not show anywhere on your site. Remove each of the widgets below to fully remove this inactive sidebar.' ),
+ 'before_widget' => '',
+ 'after_widget' => '',
+ 'before_title' => '',
+ 'after_title' => '',
+ ));
+ } else {
+ unset( $sidebars_widgets[ $sidebar_id ] );
+ }
+ }
+}
+
+// register the inactive_widgets area as sidebar
+register_sidebar(array(
+ 'name' => __('Inactive Widgets'),
+ 'id' => 'wp_inactive_widgets',
+ 'class' => 'inactive-sidebar',
+ 'description' => __( 'Drag widgets here to remove them from the sidebar but keep their settings.' ),
+ 'before_widget' => '',
+ 'after_widget' => '',
+ 'before_title' => '',
+ 'after_title' => '',
+));
+
+retrieve_widgets();
+
+// We're saving a widget without js
+if ( isset($_POST['savewidget']) || isset($_POST['removewidget']) ) {
+ $widget_id = $_POST['widget-id'];
+ check_admin_referer("save-delete-widget-$widget_id");
+
+ $number = isset($_POST['multi_number']) ? (int) $_POST['multi_number'] : '';
+ if ( $number ) {
+ foreach ( $_POST as $key => $val ) {
+ if ( is_array($val) && preg_match('/__i__|%i%/', key($val)) ) {
+ $_POST[$key] = array( $number => array_shift($val) );
+ break;
+ }
+ }
+ }
+
+ $sidebar_id = $_POST['sidebar'];
+ $position = isset($_POST[$sidebar_id . '_position']) ? (int) $_POST[$sidebar_id . '_position'] - 1 : 0;
+
+ $id_base = $_POST['id_base'];
+ $sidebar = isset($sidebars_widgets[$sidebar_id]) ? $sidebars_widgets[$sidebar_id] : array();
+
+ // delete
+ if ( isset($_POST['removewidget']) && $_POST['removewidget'] ) {
+
+ if ( !in_array($widget_id, $sidebar, true) ) {
+ wp_redirect( admin_url('widgets.php?error=0') );
+ exit;
+ }
+
+ $sidebar = array_diff( $sidebar, array($widget_id) );
+ $_POST = array('sidebar' => $sidebar_id, 'widget-' . $id_base => array(), 'the-widget-id' => $widget_id, 'delete_widget' => '1');
+ }
+
+ $_POST['widget-id'] = $sidebar;
+
+ foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
+ if ( $name != $id_base || !is_callable($control['callback']) )
+ continue;
+
+ ob_start();
+ call_user_func_array( $control['callback'], $control['params'] );
+ ob_end_clean();
+
+ break;
+ }
+
+ $sidebars_widgets[$sidebar_id] = $sidebar;
+
+ // remove old position
+ if ( !isset($_POST['delete_widget']) ) {
+ foreach ( $sidebars_widgets as $key => $sb ) {
+ if ( is_array($sb) )
+ $sidebars_widgets[$key] = array_diff( $sb, array($widget_id) );
+ }
+ array_splice( $sidebars_widgets[$sidebar_id], $position, 0, $widget_id );
+ }
+
+ wp_set_sidebars_widgets($sidebars_widgets);
+ wp_redirect( admin_url('widgets.php?message=0') );
+ exit;
+}
+
+// Output the widget form without js
+if ( isset($_GET['editwidget']) && $_GET['editwidget'] ) {
+ $widget_id = $_GET['editwidget'];
+
+ if ( isset($_GET['addnew']) ) {
+ // Default to the first sidebar
+ $sidebar = array_shift( $keys = array_keys($wp_registered_sidebars) );
+
+ if ( isset($_GET['base']) && isset($_GET['num']) ) { // multi-widget
+ // Copy minimal info from an existing instance of this widget to a new instance
+ foreach ( $wp_registered_widget_controls as $control ) {
+ if ( $_GET['base'] === $control['id_base'] ) {
+ $control_callback = $control['callback'];
+ $multi_number = (int) $_GET['num'];
+ $control['params'][0]['number'] = -1;
+ $widget_id = $control['id'] = $control['id_base'] . '-' . $multi_number;
+ $wp_registered_widget_controls[$control['id']] = $control;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( isset($wp_registered_widget_controls[$widget_id]) && !isset($control) ) {
+ $control = $wp_registered_widget_controls[$widget_id];
+ $control_callback = $control['callback'];
+ } elseif ( !isset($wp_registered_widget_controls[$widget_id]) && isset($wp_registered_widgets[$widget_id]) ) {
+ $name = esc_html( strip_tags($wp_registered_widgets[$widget_id]['name']) );
+ }
+
+ if ( !isset($name) )
+ $name = esc_html( strip_tags($control['name']) );
+
+ if ( !isset($sidebar) )
+ $sidebar = isset($_GET['sidebar']) ? $_GET['sidebar'] : 'wp_inactive_widgets';
+
+ if ( !isset($multi_number) )
+ $multi_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : '';
+
+ $id_base = isset($control['id_base']) ? $control['id_base'] : $control['id'];
+
+ // show the widget form
+ $width = ' style="width:' . max($control['width'], 350) . 'px"';
+ $key = isset($_GET['key']) ? (int) $_GET['key'] : 0;
+
+ require_once( './admin-header.php' ); ?>
+ <div class="wrap">
+ <?php screen_icon(); ?>
+ <h2><?php echo esc_html( $title ); ?></h2>
+ <div class="editwidget"<?php echo $width; ?>>
+ <h3><?php printf( __( 'Widget %s' ), $name ); ?></h3>
+
+ <form action="widgets.php" method="post">
+ <div class="widget-inside">
+<?php
+ if ( is_callable( $control_callback ) )
+ call_user_func_array( $control_callback, $control['params'] );
+ else
+ echo '<p>' . __('There are no options for this widget.') . "</p>\n"; ?>
+ </div>
+
+ <p class="describe"><?php _e('Select both the sidebar for this widget and the position of the widget in that sidebar.'); ?></p>
+ <div class="widget-position">
+ <table class="widefat"><thead><tr><th><?php _e('Sidebar'); ?></th><th><?php _e('Position'); ?></th></tr></thead><tbody>
+<?php
+ foreach ( $wp_registered_sidebars as $sbname => $sbvalue ) {
+ echo "\t\t<tr><td><label><input type='radio' name='sidebar' value='" . esc_attr($sbname) . "'" . checked( $sbname, $sidebar, false ) . " /> $sbvalue[name]</label></td><td>";
+ if ( 'wp_inactive_widgets' == $sbname || 'orphaned_widgets' == substr( $sbname, 0, 16 ) ) {
+ echo '&nbsp;';
+ } else {
+ if ( !isset($sidebars_widgets[$sbname]) || !is_array($sidebars_widgets[$sbname]) ) {
+ $j = 1;
+ $sidebars_widgets[$sbname] = array();
+ } else {
+ $j = count($sidebars_widgets[$sbname]);
+ if ( isset($_GET['addnew']) || !in_array($widget_id, $sidebars_widgets[$sbname], true) )
+ $j++;
+ }
+ $selected = '';
+ echo "\t\t<select name='{$sbname}_position'>\n";
+ echo "\t\t<option value=''>" . __('&mdash; Select &mdash;') . "</option>\n";
+ for ( $i = 1; $i <= $j; $i++ ) {
+ if ( in_array($widget_id, $sidebars_widgets[$sbname], true) )
+ $selected = selected( $i, $key + 1, false );
+ echo "\t\t<option value='$i'$selected> $i </option>\n";
+ }
+ echo "\t\t</select>\n";
+ }
+ echo "</td></tr>\n";
+ } ?>
+ </tbody></table>
+ </div>
+
+ <div class="widget-control-actions">
+<?php
+ if ( isset($_GET['addnew']) ) { ?>
+ <a href="widgets.php" class="button alignleft"><?php _e('Cancel'); ?></a>
+<?php
+ } else {
+ submit_button( __( 'Delete' ), 'button alignleft', 'removewidget', false );
+ }
+ submit_button( __( 'Save Widget' ), 'button-primary alignright', 'savewidget', false ); ?>
+ <input type="hidden" name="widget-id" class="widget-id" value="<?php echo esc_attr($widget_id); ?>" />
+ <input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" />
+ <input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" />
+<?php wp_nonce_field("save-delete-widget-$widget_id"); ?>
+ <br class="clear" />
+ </div>
+ </form>
+ </div>
+ </div>
+<?php
+ require_once( './admin-footer.php' );
+ exit;
+}
+
+$messages = array(
+ __('Changes saved.')
+);
+
+$errors = array(
+ __('Error while saving.'),
+ __('Error in displaying the widget settings form.')
+);
+
+require_once( './admin-header.php' ); ?>
+
+<div class="wrap">
+<?php screen_icon(); ?>
+<h2><?php echo esc_html( $title ); ?></h2>
+
+<?php if ( isset($_GET['message']) && isset($messages[$_GET['message']]) ) { ?>
+<div id="message" class="updated"><p><?php echo $messages[$_GET['message']]; ?></p></div>
+<?php } ?>
+<?php if ( isset($_GET['error']) && isset($errors[$_GET['error']]) ) { ?>
+<div id="message" class="error"><p><?php echo $errors[$_GET['error']]; ?></p></div>
+<?php } ?>
+
+<?php do_action( 'widgets_admin_page' ); ?>
+
+<div class="widget-liquid-left">
+<div id="widgets-left">
+ <div id="available-widgets" class="widgets-holder-wrap">
+ <div class="sidebar-name">
+ <div class="sidebar-name-arrow"><br /></div>
+ <h3><?php _e('Available Widgets'); ?> <span id="removing-widget"><?php _ex('Deactivate', 'removing-widget'); ?> <span></span></span></h3></div>
+ <div class="widget-holder">
+ <p class="description"><?php _e('Drag widgets from here to a sidebar on the right to activate them. Drag widgets back here to deactivate them and delete their settings.'); ?></p>
+ <div id="widget-list">
+ <?php wp_list_widgets(); ?>
+ </div>
+ <br class='clear' />
+ </div>
+ <br class="clear" />
+ </div>
+
+<?php
+foreach ( $wp_registered_sidebars as $sidebar => $registered_sidebar ) {
+ if ( false !== strpos( $registered_sidebar['class'], 'inactive-sidebar' ) || 'orphaned_widgets' == substr( $sidebar, 0, 16 ) ) {
+ $wrap_class = 'widgets-holder-wrap';
+ if ( !empty( $registered_sidebar['class'] ) )
+ $wrap_class .= ' ' . $registered_sidebar['class'];
+
+?>
+
+ <div class="<?php echo esc_attr( $wrap_class ); ?>">
+ <div class="sidebar-name">
+ <div class="sidebar-name-arrow"><br /></div>
+ <h3><?php echo esc_html( $registered_sidebar['name'] ); ?>
+ <span class="spinner"></span>
+ </h3>
+ </div>
+ <div class="widget-holder inactive">
+ <?php wp_list_widget_controls( $registered_sidebar['id'] ); ?>
+ <div class="clear"></div>
+ </div>
+ </div>
+<?php
+ }
+}
+?>
+
+</div>
+</div>
+
+<div class="widget-liquid-right">
+<div id="widgets-right">
+<?php
+$i = 0;
+foreach ( $wp_registered_sidebars as $sidebar => $registered_sidebar ) {
+ if ( false !== strpos( $registered_sidebar['class'], 'inactive-sidebar' ) || 'orphaned_widgets' == substr( $sidebar, 0, 16 ) )
+ continue;
+
+ $wrap_class = 'widgets-holder-wrap';
+ if ( !empty( $registered_sidebar['class'] ) )
+ $wrap_class .= ' sidebar-' . $registered_sidebar['class'];
+
+ if ( $i )
+ $wrap_class .= ' closed'; ?>
+
+ <div class="<?php echo esc_attr( $wrap_class ); ?>">
+ <div class="sidebar-name">
+ <div class="sidebar-name-arrow"><br /></div>
+ <h3><?php echo esc_html( $registered_sidebar['name'] ); ?>
+ <span class="spinner"></span></h3></div>
+ <?php wp_list_widget_controls( $sidebar ); // Show the control forms for each of the widgets in this sidebar ?>
+ </div>
+<?php
+ $i++;
+} ?>
+</div>
+</div>
+<form action="" method="post">
+<?php wp_nonce_field( 'save-sidebar-widgets', '_wpnonce_widgets', false ); ?>
+</form>
+<br class="clear" />
+</div>
+
+<?php
+do_action( 'sidebar_admin_page' );
+require_once( './admin-footer.php' );
diff --git a/src/wp-blog-header.php b/src/wp-blog-header.php
new file mode 100644
index 0000000000..3e1b8ef560
--- /dev/null
+++ b/src/wp-blog-header.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Loads the WordPress environment and template.
+ *
+ * @package WordPress
+ */
+
+if ( !isset($wp_did_header) ) {
+
+ $wp_did_header = true;
+
+ require_once( dirname(__FILE__) . '/wp-load.php' );
+
+ wp();
+
+ require_once( ABSPATH . WPINC . '/template-loader.php' );
+
+}
diff --git a/src/wp-comments-post.php b/src/wp-comments-post.php
new file mode 100644
index 0000000000..7b4a5e9dc0
--- /dev/null
+++ b/src/wp-comments-post.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Handles Comment Post to WordPress and prevents duplicate comment posting.
+ *
+ * @package WordPress
+ */
+
+if ( 'POST' != $_SERVER['REQUEST_METHOD'] ) {
+ header('Allow: POST');
+ header('HTTP/1.1 405 Method Not Allowed');
+ header('Content-Type: text/plain');
+ exit;
+}
+
+/** Sets up the WordPress Environment. */
+require( dirname(__FILE__) . '/wp-load.php' );
+
+nocache_headers();
+
+$comment_post_ID = isset($_POST['comment_post_ID']) ? (int) $_POST['comment_post_ID'] : 0;
+
+$post = get_post($comment_post_ID);
+
+if ( empty($post->comment_status) ) {
+ do_action('comment_id_not_found', $comment_post_ID);
+ exit;
+}
+
+// get_post_status() will get the parent status for attachments.
+$status = get_post_status($post);
+
+$status_obj = get_post_status_object($status);
+
+if ( !comments_open($comment_post_ID) ) {
+ do_action('comment_closed', $comment_post_ID);
+ wp_die( __('Sorry, comments are closed for this item.') );
+} elseif ( 'trash' == $status ) {
+ do_action('comment_on_trash', $comment_post_ID);
+ exit;
+} elseif ( !$status_obj->public && !$status_obj->private ) {
+ do_action('comment_on_draft', $comment_post_ID);
+ exit;
+} elseif ( post_password_required($comment_post_ID) ) {
+ do_action('comment_on_password_protected', $comment_post_ID);
+ exit;
+} else {
+ do_action('pre_comment_on_post', $comment_post_ID);
+}
+
+$comment_author = ( isset($_POST['author']) ) ? trim(strip_tags($_POST['author'])) : null;
+$comment_author_email = ( isset($_POST['email']) ) ? trim($_POST['email']) : null;
+$comment_author_url = ( isset($_POST['url']) ) ? trim($_POST['url']) : null;
+$comment_content = ( isset($_POST['comment']) ) ? trim($_POST['comment']) : null;
+
+// If the user is logged in
+$user = wp_get_current_user();
+if ( $user->exists() ) {
+ if ( empty( $user->display_name ) )
+ $user->display_name=$user->user_login;
+ $comment_author = wp_slash( $user->display_name );
+ $comment_author_email = wp_slash( $user->user_email );
+ $comment_author_url = wp_slash( $user->user_url );
+ if ( current_user_can('unfiltered_html') ) {
+ if ( wp_create_nonce('unfiltered-html-comment_' . $comment_post_ID) != $_POST['_wp_unfiltered_html_comment'] ) {
+ kses_remove_filters(); // start with a clean slate
+ kses_init_filters(); // set up the filters
+ }
+ }
+} else {
+ if ( get_option('comment_registration') || 'private' == $status )
+ wp_die( __('Sorry, you must be logged in to post a comment.') );
+}
+
+$comment_type = '';
+
+if ( get_option('require_name_email') && !$user->exists() ) {
+ if ( 6 > strlen($comment_author_email) || '' == $comment_author )
+ wp_die( __('<strong>ERROR</strong>: please fill the required fields (name, email).') );
+ elseif ( !is_email($comment_author_email))
+ wp_die( __('<strong>ERROR</strong>: please enter a valid email address.') );
+}
+
+if ( '' == $comment_content )
+ wp_die( __('<strong>ERROR</strong>: please type a comment.') );
+
+$comment_parent = isset($_POST['comment_parent']) ? absint($_POST['comment_parent']) : 0;
+
+$commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type', 'comment_parent', 'user_ID');
+
+$comment_id = wp_new_comment( $commentdata );
+
+$comment = get_comment($comment_id);
+do_action('set_comment_cookies', $comment, $user);
+
+$location = empty($_POST['redirect_to']) ? get_comment_link($comment_id) : $_POST['redirect_to'] . '#comment-' . $comment_id;
+$location = apply_filters('comment_post_redirect', $location, $comment);
+
+wp_safe_redirect( $location );
+exit;
diff --git a/src/wp-config-sample.php b/src/wp-config-sample.php
new file mode 100644
index 0000000000..e47e1b5ac4
--- /dev/null
+++ b/src/wp-config-sample.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * The base configurations of the WordPress.
+ *
+ * This file has the following configurations: MySQL settings, Table Prefix,
+ * Secret Keys, WordPress Language, and ABSPATH. You can find more information
+ * by visiting {@link http://codex.wordpress.org/Editing_wp-config.php Editing
+ * wp-config.php} Codex page. You can get the MySQL settings from your web host.
+ *
+ * This file is used by the wp-config.php creation script during the
+ * installation. You don't have to use the web site, you can just copy this file
+ * to "wp-config.php" and fill in the values.
+ *
+ * @package WordPress
+ */
+
+// ** MySQL settings - You can get this info from your web host ** //
+/** The name of the database for WordPress */
+define('DB_NAME', 'database_name_here');
+
+/** MySQL database username */
+define('DB_USER', 'username_here');
+
+/** MySQL database password */
+define('DB_PASSWORD', 'password_here');
+
+/** MySQL hostname */
+define('DB_HOST', 'localhost');
+
+/** Database Charset to use in creating database tables. */
+define('DB_CHARSET', 'utf8');
+
+/** The Database Collate type. Don't change this if in doubt. */
+define('DB_COLLATE', '');
+
+/**#@+
+ * Authentication Unique Keys and Salts.
+ *
+ * Change these to different unique phrases!
+ * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
+ * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
+ *
+ * @since 2.6.0
+ */
+define('AUTH_KEY', 'put your unique phrase here');
+define('SECURE_AUTH_KEY', 'put your unique phrase here');
+define('LOGGED_IN_KEY', 'put your unique phrase here');
+define('NONCE_KEY', 'put your unique phrase here');
+define('AUTH_SALT', 'put your unique phrase here');
+define('SECURE_AUTH_SALT', 'put your unique phrase here');
+define('LOGGED_IN_SALT', 'put your unique phrase here');
+define('NONCE_SALT', 'put your unique phrase here');
+
+/**#@-*/
+
+/**
+ * WordPress Database Table prefix.
+ *
+ * You can have multiple installations in one database if you give each a unique
+ * prefix. Only numbers, letters, and underscores please!
+ */
+$table_prefix = 'wp_';
+
+/**
+ * WordPress Localized Language, defaults to English.
+ *
+ * Change this to localize WordPress. A corresponding MO file for the chosen
+ * language must be installed to wp-content/languages. For example, install
+ * de_DE.mo to wp-content/languages and set WPLANG to 'de_DE' to enable German
+ * language support.
+ */
+define('WPLANG', '');
+
+/**
+ * For developers: WordPress debugging mode.
+ *
+ * Change this to true to enable the display of notices during development.
+ * It is strongly recommended that plugin and theme developers use WP_DEBUG
+ * in their development environments.
+ */
+define('WP_DEBUG', false);
+
+/* That's all, stop editing! Happy blogging. */
+
+/** Absolute path to the WordPress directory. */
+if ( !defined('ABSPATH') )
+ define('ABSPATH', dirname(__FILE__) . '/');
+
+/** Sets up WordPress vars and included files. */
+require_once(ABSPATH . 'wp-settings.php');
diff --git a/src/wp-content/index.php b/src/wp-content/index.php
new file mode 100644
index 0000000000..62200328fd
--- /dev/null
+++ b/src/wp-content/index.php
@@ -0,0 +1,2 @@
+<?php
+// Silence is golden.
diff --git a/src/wp-content/plugins/hello.php b/src/wp-content/plugins/hello.php
new file mode 100644
index 0000000000..2b1e07b59e
--- /dev/null
+++ b/src/wp-content/plugins/hello.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @package Hello_Dolly
+ * @version 1.6
+ */
+/*
+Plugin Name: Hello Dolly
+Plugin URI: http://wordpress.org/plugins/hello-dolly/
+Description: This is not just a plugin, it symbolizes the hope and enthusiasm of an entire generation summed up in two words sung most famously by Louis Armstrong: Hello, Dolly. When activated you will randomly see a lyric from <cite>Hello, Dolly</cite> in the upper right of your admin screen on every page.
+Author: Matt Mullenweg
+Version: 1.6
+Author URI: http://ma.tt/
+*/
+
+function hello_dolly_get_lyric() {
+ /** These are the lyrics to Hello Dolly */
+ $lyrics = "Hello, Dolly
+Well, hello, Dolly
+It's so nice to have you back where you belong
+You're lookin' swell, Dolly
+I can tell, Dolly
+You're still glowin', you're still crowin'
+You're still goin' strong
+We feel the room swayin'
+While the band's playin'
+One of your old favourite songs from way back when
+So, take her wrap, fellas
+Find her an empty lap, fellas
+Dolly'll never go away again
+Hello, Dolly
+Well, hello, Dolly
+It's so nice to have you back where you belong
+You're lookin' swell, Dolly
+I can tell, Dolly
+You're still glowin', you're still crowin'
+You're still goin' strong
+We feel the room swayin'
+While the band's playin'
+One of your old favourite songs from way back when
+Golly, gee, fellas
+Find her a vacant knee, fellas
+Dolly'll never go away
+Dolly'll never go away
+Dolly'll never go away again";
+
+ // Here we split it into lines
+ $lyrics = explode( "\n", $lyrics );
+
+ // And then randomly choose a line
+ return wptexturize( $lyrics[ mt_rand( 0, count( $lyrics ) - 1 ) ] );
+}
+
+// This just echoes the chosen line, we'll position it later
+function hello_dolly() {
+ $chosen = hello_dolly_get_lyric();
+ echo "<p id='dolly'>$chosen</p>";
+}
+
+// Now we set that function up to execute when the admin_notices action is called
+add_action( 'admin_notices', 'hello_dolly' );
+
+// We need some CSS to position the paragraph
+function dolly_css() {
+ // This makes sure that the positioning is also good for right-to-left languages
+ $x = is_rtl() ? 'left' : 'right';
+
+ echo "
+ <style type='text/css'>
+ #dolly {
+ float: $x;
+ padding-$x: 15px;
+ padding-top: 5px;
+ margin: 0;
+ font-size: 11px;
+ }
+ </style>
+ ";
+}
+
+add_action( 'admin_head', 'dolly_css' );
+
+?>
diff --git a/src/wp-content/plugins/index.php b/src/wp-content/plugins/index.php
new file mode 100644
index 0000000000..4e6c07c7ee
--- /dev/null
+++ b/src/wp-content/plugins/index.php
@@ -0,0 +1,3 @@
+<?php
+// Silence is golden.
+?> \ No newline at end of file
diff --git a/src/wp-content/themes/index.php b/src/wp-content/themes/index.php
new file mode 100644
index 0000000000..4e6c07c7ee
--- /dev/null
+++ b/src/wp-content/themes/index.php
@@ -0,0 +1,3 @@
+<?php
+// Silence is golden.
+?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/404.php b/src/wp-content/themes/twentyeleven/404.php
new file mode 100644
index 0000000000..03e0651279
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/404.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * The template for displaying 404 pages (Not Found).
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary">
+ <div id="content" role="main">
+
+ <article id="post-0" class="post error404 not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'This is somewhat embarrassing, isn&rsquo;t it?', 'twentyeleven' ); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <p><?php _e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching, or one of the links below, can help.', 'twentyeleven' ); ?></p>
+
+ <?php get_search_form(); ?>
+
+ <?php the_widget( 'WP_Widget_Recent_Posts', array( 'number' => 10 ), array( 'widget_id' => '404' ) ); ?>
+
+ <div class="widget">
+ <h2 class="widgettitle"><?php _e( 'Most Used Categories', 'twentyeleven' ); ?></h2>
+ <ul>
+ <?php wp_list_categories( array( 'orderby' => 'count', 'order' => 'DESC', 'show_count' => 1, 'title_li' => '', 'number' => 10 ) ); ?>
+ </ul>
+ </div>
+
+ <?php
+ /* translators: %1$s: smilie */
+ $archive_content = '<p>' . sprintf( __( 'Try looking in the monthly archives. %1$s', 'twentyeleven' ), convert_smilies( ':)' ) ) . '</p>';
+ the_widget( 'WP_Widget_Archives', array('count' => 0 , 'dropdown' => 1 ), array( 'after_title' => '</h2>'.$archive_content ) );
+ ?>
+
+ <?php the_widget( 'WP_Widget_Tag_Cloud' ); ?>
+
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/archive.php b/src/wp-content/themes/twentyeleven/archive.php
new file mode 100644
index 0000000000..13390e2295
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/archive.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * The template for displaying Archive pages.
+ *
+ * Used to display archive-type pages if nothing more specific matches a query.
+ * For example, puts together date-based pages if no date.php file exists.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title">
+ <?php if ( is_day() ) : ?>
+ <?php printf( __( 'Daily Archives: %s', 'twentyeleven' ), '<span>' . get_the_date() . '</span>' ); ?>
+ <?php elseif ( is_month() ) : ?>
+ <?php printf( __( 'Monthly Archives: %s', 'twentyeleven' ), '<span>' . get_the_date( _x( 'F Y', 'monthly archives date format', 'twentyeleven' ) ) . '</span>' ); ?>
+ <?php elseif ( is_year() ) : ?>
+ <?php printf( __( 'Yearly Archives: %s', 'twentyeleven' ), '<span>' . get_the_date( _x( 'Y', 'yearly archives date format', 'twentyeleven' ) ) . '</span>' ); ?>
+ <?php else : ?>
+ <?php _e( 'Blog Archives', 'twentyeleven' ); ?>
+ <?php endif; ?>
+ </h1>
+ </header>
+
+ <?php twentyeleven_content_nav( 'nav-above' ); ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php
+ /* Include the Post-Format-specific template for the content.
+ * If you want to overload this in a child theme then include a file
+ * called content-___.php (where ___ is the Post Format name) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+ ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyeleven_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyeleven' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/author.php b/src/wp-content/themes/twentyeleven/author.php
new file mode 100644
index 0000000000..472cb133d6
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/author.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * The template for displaying Author Archive pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <?php
+ /* Queue the first post, that way we know
+ * what author we're dealing with (if that is the case).
+ *
+ * We reset this later so we can run the loop
+ * properly with a call to rewind_posts().
+ */
+ the_post();
+ ?>
+
+ <header class="page-header">
+ <h1 class="page-title author"><?php printf( __( 'Author Archives: %s', 'twentyeleven' ), '<span class="vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( "ID" ) ) ) . '" title="' . esc_attr( get_the_author() ) . '" rel="me">' . get_the_author() . '</a></span>' ); ?></h1>
+ </header>
+
+ <?php
+ /* Since we called the_post() above, we need to
+ * rewind the loop back to the beginning that way
+ * we can run the loop properly, in full.
+ */
+ rewind_posts();
+ ?>
+
+ <?php twentyeleven_content_nav( 'nav-above' ); ?>
+
+ <?php
+ // If a user has filled out their description, show a bio on their entries.
+ if ( get_the_author_meta( 'description' ) ) : ?>
+ <div id="author-info">
+ <div id="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentyeleven_author_bio_avatar_size', 60 ) ); ?>
+ </div><!-- #author-avatar -->
+ <div id="author-description">
+ <h2><?php printf( __( 'About %s', 'twentyeleven' ), get_the_author() ); ?></h2>
+ <?php the_author_meta( 'description' ); ?>
+ </div><!-- #author-description -->
+ </div><!-- #author-info -->
+ <?php endif; ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php
+ /* Include the Post-Format-specific template for the content.
+ * If you want to overload this in a child theme then include a file
+ * called content-___.php (where ___ is the Post Format name) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+ ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyeleven_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyeleven' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/category.php b/src/wp-content/themes/twentyeleven/category.php
new file mode 100644
index 0000000000..539cbbdd36
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/category.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * The template for displaying Category Archive pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title"><?php
+ printf( __( 'Category Archives: %s', 'twentyeleven' ), '<span>' . single_cat_title( '', false ) . '</span>' );
+ ?></h1>
+
+ <?php
+ $category_description = category_description();
+ if ( ! empty( $category_description ) )
+ echo apply_filters( 'category_archive_meta', '<div class="category-archive-meta">' . $category_description . '</div>' );
+ ?>
+ </header>
+
+ <?php twentyeleven_content_nav( 'nav-above' ); ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php
+ /* Include the Post-Format-specific template for the content.
+ * If you want to overload this in a child theme then include a file
+ * called content-___.php (where ___ is the Post Format name) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+ ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyeleven_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyeleven' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyeleven/colors/dark.css b/src/wp-content/themes/twentyeleven/colors/dark.css
new file mode 100644
index 0000000000..63b809fd65
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/colors/dark.css
@@ -0,0 +1,623 @@
+/*
+ A dark color scheme for Twenty Eleven
+*/
+
+/* =Global
+----------------------------------------------- */
+
+body {
+ background: #1d1d1d;
+ color: #bbb;
+}
+#page {
+ background: #0f0f0f;
+}
+
+/* Headings */
+hr {
+ background-color: #333;
+}
+
+/* Text elements */
+blockquote cite {
+ color: #999;
+}
+pre {
+ background: #0b0b0b;
+}
+code, kbd {
+ font: 13px Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
+}
+abbr, acronym, dfn {
+ border-bottom: 1px dotted #999;
+}
+ins {
+ background: #00063f;
+}
+input[type=text],
+input[type=password],
+input[type=email],
+input[type=url],
+input[type=number],
+textarea {
+ border: 1px solid #222;
+}
+input#s {
+ background-color: #ddd;
+}
+
+/* Links */
+a {
+}
+
+
+/* =Header
+----------------------------------------------- */
+
+#branding {
+ border-top: 2px solid #0a0a0a;
+}
+#site-title a {
+ color: #eee;
+}
+#site-title a:hover,
+#site-title a:focus,
+#site-title a:active {
+}
+#site-description {
+ color: #858585;
+}
+#branding #s {
+ background-color: #ddd;
+}
+
+
+/* =Menu
+----------------------------------------------- */
+
+#access {
+ background: #333; /* Show a solid color for older browsers */
+ background: -moz-linear-gradient(#383838, #272727);
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#383838), to(#272727)); /* older webkit syntax */
+ background: -webkit-linear-gradient(#383838, #272727);
+ border-bottom: 1px solid #222;
+}
+
+/* =Content
+----------------------------------------------- */
+
+.page-title {
+ color: #ccc;
+}
+.hentry {
+ border-color: #222;
+}
+.entry-title {
+ color: #ddd;
+}
+.entry-title,
+.entry-title a {
+ color: #ddd;
+}
+.entry-title a:hover,
+.entry-title a:focus,
+.entry-title a:active {
+}
+.entry-meta {
+ color: #999;
+}
+.entry-content h1,
+.entry-content h2,
+.comment-content h1,
+.comment-content h2 {
+ color: #fff;
+}
+.entry-content table,
+.comment-content table {
+ border-color: #222;
+}
+.entry-content th,
+.comment-content th {
+ color: #999;
+}
+.entry-content td,
+.comment-content td {
+ border-color: #222;
+}
+.page-link {
+}
+.page-link a {
+ background: #242424;
+ color: #bbb;
+}
+.page-link a:hover {
+ background: #999;
+ color: #000;
+}
+.entry-meta .edit-link a {
+ background: #242424;
+ color: #bbb;
+}
+.entry-meta .edit-link a:hover,
+.entry-meta .edit-link a:focus,
+.entry-meta .edit-link a:active {
+ background: #999;
+ color: #000;
+}
+
+/* Images */
+.wp-caption {
+ background: #2c2c2c;
+}
+.wp-caption .wp-caption-text {
+ color: #999;
+}
+.wp-caption .wp-caption-text:before {
+ color: #999;
+}
+
+/* Image borders */
+img[class*="wp-image-"],
+#content .gallery .gallery-icon img {
+ border-color: #2c2c2c;
+}
+.wp-caption img {
+ border-color: #2c2c2c;
+}
+a:focus img[class*="wp-image-"],
+a:hover img[class*="wp-image-"],
+a:active img[class*="wp-image-"] {
+ background: #2c2c2c;
+ border-color: #444;
+}
+.wp-caption a:focus img,
+.wp-caption a:active img,
+.wp-caption a:hover img {
+ background: #0f0f0f;
+ border-color: #2c2c2c;
+}
+
+/* Password Protected Posts */
+.post-password-required input[type=password] {
+ background: #ddd;
+}
+.post-password-required input[type=password]:focus {
+ background: #fff;
+}
+
+/* Author Info */
+.singular #author-info {
+ background: #060606;
+ border-color: #222;
+}
+.archive #author-info {
+ border-color: #222;
+}
+#author-avatar img {
+ background: #000;
+ -webkit-box-shadow: 0 1px 2px #444;
+ -moz-box-shadow: 0 1px 2px #444;
+ box-shadow: 0 1px 2px #444;
+}
+#author-description h2 {
+ color: #fff;
+}
+
+/* Comments link */
+.entry-header .comments-link a {
+ background: #282828 url(../images/comment-bubble-dark.png) no-repeat;
+ border-color: #222;
+ color: #888;
+}
+
+.rtl .entry-header .comments-link a {
+ background-image: url(../images/comment-bubble-dark-rtl.png);
+}
+/* Singular content styles for Posts and Pages */
+.singular .entry-title {
+ color: #fff;
+}
+
+
+/* =Status
+----------------------------------------------- */
+
+.format-status img.avatar {
+ -webkit-box-shadow: 0 1px 2px #333;
+ -moz-box-shadow: 0 1px 2px #333;
+ box-shadow: 0 1px 2px #333;
+}
+
+
+/* =Quote
+----------------------------------------------- */
+
+.format-quote blockquote {
+ color: #aaa;
+}
+
+
+/* =Image
+----------------------------------------------- */
+
+.indexed.format-image .wp-caption {
+ background: #242424;
+}
+.indexed.format-image .entry-meta .edit-link a {
+ color: #ddd;
+}
+.indexed.format-image .entry-meta .edit-link a:hover {
+ color: #fff;
+}
+
+
+/* =error404
+----------------------------------------------- */
+.error404 #main #searchform {
+ background: #060606;
+ border-color: #222;
+}
+
+
+/* =Showcase
+----------------------------------------------- */
+
+h1.showcase-heading {
+ color: #ccc;
+}
+
+/* Intro */
+article.intro {
+ background: #060606;
+}
+article.intro .entry-content {
+ color: #eee;
+}
+article.intro .edit-link a {
+ background: #555;
+ color: #000;
+}
+article.intro .edit-link a:hover {
+ background: #888;
+}
+
+/* Featured post */
+section.featured-post .hentry {
+ color: #999;
+}
+
+/* Small featured post */
+section.featured-post .attachment-small-feature {
+ border-color: #444;
+}
+section.featured-post .attachment-small-feature:hover {
+ border-color: #777;
+}
+article.feature-image.small .entry-summary {
+ color: #aaa;
+}
+article.feature-image.small .entry-summary p a {
+ background: #ddd;
+ color: #111;
+}
+article.feature-image.small .entry-summary p a:hover {
+ color: #40220c;
+}
+
+/* Large featured post */
+article.feature-image.large .entry-title a {
+ background: #ddd;
+ background: rgba(0,0,0,0.8);
+ color: #fff;
+}
+section.feature-image.large:hover .entry-title a,
+section.feature-image.large .entry-title:hover a {
+ background: #111;
+ background: rgba(255,255,255,0.8);
+ color: #000;
+}
+section.feature-image.large img {
+ border-bottom: 1px solid #222;
+}
+
+/* Featured Slider */
+.featured-posts {
+ border-color: #222;
+}
+.featured-posts section.featured-post {
+ background: #000;
+}
+.featured-post .feature-text:after,
+.featured-post .feature-image.small:after {
+ background: -moz-linear-gradient(top, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(0,0,0,0)), color-stop(100%,rgba(0,0,0,1))); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00000000', endColorstr='#000000',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, rgba(0,0,0,0) 0%,rgba(0,0,0,1) 100%); /* W3C */
+}
+.feature-slider a {
+ background: #c3c3c3;
+ background: rgba(60,60,60,0.9);
+ -webkit-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.5), inset 0 0 2px rgba(255,255,255,0.5);
+ -moz-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.5), inset 0 0 2px rgba(255,255,255,0.5);
+ box-shadow: inset 1px 1px 5px rgba(0,0,0,0.5), inset 0 0 2px rgba(255,255,255,0.5);
+}
+.feature-slider a.active {
+ background: #000;
+ background: rgba(255,255,255,0.8);
+ -webkit-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.4), inset 0 0 2px rgba(255,255,255,0.8);
+ -moz-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.4), inset 0 0 2px rgba(255,255,255,0.8);
+ box-shadow: inset 1px 1px 5px rgba(0,0,0,0.4), inset 0 0 2px rgba(255,255,255,0.8);
+}
+
+/* Recent Posts */
+section.recent-posts .other-recent-posts {
+ border-color: #222;
+}
+section.recent-posts .other-recent-posts .entry-title {
+ border-color: #222;
+}
+section.recent-posts .other-recent-posts a[rel="bookmark"] {
+ color: #ccc;
+}
+section.recent-posts .other-recent-posts a[rel="bookmark"]:hover {
+}
+section.recent-posts .other-recent-posts .comments-link a,
+section.recent-posts .other-recent-posts .comments-link > span {
+ border-color: #959595;
+ color: #bbb;
+}
+section.recent-posts .other-recent-posts .comments-link > span {
+ border-color: #444;
+ color: #777;
+}
+section.recent-posts .other-recent-posts .comments-link a:hover {
+}
+
+
+/* =Attachments
+----------------------------------------------- */
+
+.image-attachment div.attachment {
+ background: #060606;
+ border-color: #222;
+}
+.image-attachment div.attachment a img {
+ border-color: #060606;
+}
+.image-attachment div.attachment a:focus img,
+.image-attachment div.attachment a:hover img,
+.image-attachment div.attachment a:active img {
+ border-color: #2c2c2c;
+ background: #0f0f0f;
+}
+
+
+/* =Widgets
+----------------------------------------------- */
+
+.widget-title {
+ color: #ccc;
+}
+.widget ul li {
+ color: #888;
+}
+
+/* Search Widget */
+.widget_search #searchsubmit {
+ background: #222;
+ border-color: #333;
+ -webkit-box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.09);
+ -moz-box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.09);
+ box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.09);
+ color: #777;
+}
+.widget_search #searchsubmit:active {
+ -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.1);
+ color: #40220c;
+}
+
+/* Calendar Widget */
+.widget_calendar #wp-calendar {
+ color: #aaa;
+}
+.widget_calendar #wp-calendar th {
+ background: #0b0b0b;
+ border-color: #333;
+}
+.widget_calendar #wp-calendar tfoot td {
+ background: #0b0b0b;
+ border-color: #333;
+}
+
+
+/* =Comments
+----------------------------------------------- */
+
+#comments-title {
+ color: #bbb;
+}
+.nocomments {
+ color: #555;
+}
+.commentlist > li.comment {
+ background: #090909;
+ border-color: #222;
+}
+.commentlist .children li.comment {
+ background: #000;
+ border-color: #222;
+}
+.rtl .commentlist .children li.comment {
+ border-color: #222;
+}
+.comment-meta {
+ color: #999;
+}
+.commentlist .avatar {
+ -webkit-box-shadow: 0 1px 2px #222;
+ -moz-box-shadow: 0 1px 2px #222;
+ box-shadow: 0 1px 2px #222;
+}
+a.comment-reply-link {
+ background: #242424;
+ color: #bbb;
+}
+li.bypostauthor a.comment-reply-link {
+ background: #111;
+}
+a.comment-reply-link:hover,
+a.comment-reply-link:focus,
+a.comment-reply-link:active,
+li.bypostauthor a.comment-reply-link:hover,
+li.bypostauthor a.comment-reply-link:focus,
+li.bypostauthor a.comment-reply-link:active {
+ background: #999;
+ color: #000;
+}
+.commentlist > li:before {
+ content: url(../images/comment-arrow-dark.png);
+}
+.rtl .commentlist > li:before {
+ content: url(../images/comment-arrow-dark-rtl.png);
+}
+
+/* Post author highlighting */
+.commentlist > li.bypostauthor {
+ background: #222;
+ border-color: #2c2c2c;
+}
+.commentlist > li.bypostauthor:before {
+ content: url(../images/comment-arrow-bypostauthor-dark.png);
+}
+.rtl .commentlist > li.bypostauthor:before {
+ content: url(../images/comment-arrow-bypostauthor-dark-rtl.png);
+}
+
+/* Post Author threaded comments */
+.commentlist .children > li.bypostauthor {
+ background: #222;
+ border-color: #2c2c2c;
+}
+.commentlist > li.bypostauthor .comment-meta {
+ color: #a8a8a8;
+}
+
+/* Comment Form */
+#respond {
+ background: #222;
+ border-color: #2c2c2c;
+}
+#respond input[type="text"],
+#respond textarea {
+ background: #000;
+ border: 4px solid #111;
+ -webkit-box-shadow: inset 0 1px 3px rgba(51,51,51,0.95);
+ -moz-box-shadow: inset 0 1px 3px rgba(51,51,51,0.95);
+ box-shadow: inset 0 1px 3px rgba(51,51,51,0.95);
+ color: #bbb;
+}
+#respond .comment-form-author label,
+#respond .comment-form-email label,
+#respond .comment-form-url label,
+#respond .comment-form-comment label {
+ background: #111;
+ -webkit-box-shadow: 1px 2px 2px rgba(51,51,51,0.8);
+ -moz-box-shadow: 1px 2px 2px rgba(51,51,51,0.8);
+ box-shadow: 1px 1px 2px rgba(51,51,51,0.8);
+ color: #aaa;
+}
+.rtl #respond .comment-form-author label,
+.rtl #respond .comment-form-email label,
+.rtl #respond .comment-form-url label,
+.rtl #respond .comment-form-comment label {
+ -webkit-box-shadow: -1px 2px 2px rgba(51,51,51,0.8);
+ -moz-box-shadow: -1px 2px 2px rgba(51,51,51,0.8);
+ box-shadow: -1px 1px 2px rgba(51,51,51,0.8);
+}
+#respond .comment-form-author .required,
+#respond .comment-form-email .required {
+ color: #42caff;
+}
+#respond input#submit {
+ background: #ddd;
+ -webkit-box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
+ -moz-box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
+ box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
+ color: #111;
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
+}
+#respond input#submit:active {
+ color: #40220c;
+}
+#respond #cancel-comment-reply-link {
+ color: #999;
+}
+#reply-title {
+ color: #ccc;
+}
+#cancel-comment-reply-link {
+ color: #777;
+}
+#cancel-comment-reply-link:focus,
+#cancel-comment-reply-link:active,
+#cancel-comment-reply-link:hover {
+ color: #00b4cc;
+}
+
+
+/* =Footer
+----------------------------------------------- */
+
+#supplementary {
+ border-color: #222;
+}
+
+/* Site Generator Line */
+#site-generator {
+ background: #060606;
+ border-color: #000;
+}
+
+
+/* =Print
+----------------------------------------------- */
+
+@media print {
+ body {
+ color: #333;
+ background: none !important;
+ }
+ #page {
+ background: none !important;
+ }
+
+ /* Comments */
+ .commentlist > li.comment {
+ }
+
+ /* Post author highlighting */
+ .commentlist > li.bypostauthor {
+ color: #333;
+ }
+ .commentlist > li.bypostauthor .comment-meta {
+ color: #959595;
+ }
+ .commentlist > li:before {
+ content: none !important;
+ }
+
+ /* Post Author threaded comments */
+ .commentlist .children > li.bypostauthor {
+ background: #fff;
+ border-color: #ddd;
+ }
+ .commentlist .children > li.bypostauthor > article,
+ .commentlist .children > li.bypostauthor > article .comment-meta {
+ color: #959595;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/comments.php b/src/wp-content/themes/twentyeleven/comments.php
new file mode 100644
index 0000000000..6b77feeacc
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/comments.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * The template for displaying Comments.
+ *
+ * The area of the page that contains both current comments
+ * and the comment form. The actual display of comments is
+ * handled by a callback to twentyeleven_comment() which is
+ * located in the functions.php file.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+ <div id="comments">
+ <?php if ( post_password_required() ) : ?>
+ <p class="nopassword"><?php _e( 'This post is password protected. Enter the password to view any comments.', 'twentyeleven' ); ?></p>
+ </div><!-- #comments -->
+ <?php
+ /* Stop the rest of comments.php from being processed,
+ * but don't kill the script entirely -- we still have
+ * to fully load the template.
+ */
+ return;
+ endif;
+ ?>
+
+ <?php // You can start editing here -- including this comment! ?>
+
+ <?php if ( have_comments() ) : ?>
+ <h2 id="comments-title">
+ <?php
+ printf( _n( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'twentyeleven' ),
+ number_format_i18n( get_comments_number() ), '<span>' . get_the_title() . '</span>' );
+ ?>
+ </h2>
+
+ <?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?>
+ <nav id="comment-nav-above">
+ <h1 class="assistive-text"><?php _e( 'Comment navigation', 'twentyeleven' ); ?></h1>
+ <div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'twentyeleven' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'twentyeleven' ) ); ?></div>
+ </nav>
+ <?php endif; // check for comment navigation ?>
+
+ <ol class="commentlist">
+ <?php
+ /* Loop through and list the comments. Tell wp_list_comments()
+ * to use twentyeleven_comment() to format the comments.
+ * If you want to overload this in a child theme then you can
+ * define twentyeleven_comment() and that will be used instead.
+ * See twentyeleven_comment() in twentyeleven/functions.php for more.
+ */
+ wp_list_comments( array( 'callback' => 'twentyeleven_comment' ) );
+ ?>
+ </ol>
+
+ <?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?>
+ <nav id="comment-nav-below">
+ <h1 class="assistive-text"><?php _e( 'Comment navigation', 'twentyeleven' ); ?></h1>
+ <div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'twentyeleven' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'twentyeleven' ) ); ?></div>
+ </nav>
+ <?php endif; // check for comment navigation ?>
+
+ <?php
+ /* If there are no comments and comments are closed, let's leave a little note, shall we?
+ * But we only want the note on posts and pages that had comments in the first place.
+ */
+ if ( ! comments_open() && get_comments_number() ) : ?>
+ <p class="nocomments"><?php _e( 'Comments are closed.' , 'twentyeleven' ); ?></p>
+ <?php endif; ?>
+
+ <?php endif; // have_comments() ?>
+
+ <?php comment_form(); ?>
+
+</div><!-- #comments -->
diff --git a/src/wp-content/themes/twentyeleven/content-aside.php b/src/wp-content/themes/twentyeleven/content-aside.php
new file mode 100644
index 0000000000..66f06037e1
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-aside.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * The template for displaying posts in the Aside Post Format on index and archive pages
+ *
+ * Learn more: http://codex.wordpress.org/Post_Formats
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Aside', 'twentyeleven' ); ?></h3>
+ </hgroup>
+
+ <?php if ( comments_open() && ! post_password_required() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'twentyeleven' ) . '</span>', _x( '1', 'comments number', 'twentyeleven' ), _x( '%', 'comments number', 'twentyeleven' ) ); ?>
+ </div>
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ <?php if ( comments_open() ) : ?>
+ <span class="sep"> | </span>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; ?>
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-featured.php b/src/wp-content/themes/twentyeleven/content-featured.php
new file mode 100644
index 0000000000..e1a0bf0b85
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-featured.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * The template for displaying content featured in the showcase.php page template
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+global $feature_class;
+?>
+<article id="post-<?php the_ID(); ?>" <?php post_class( $feature_class ); ?>>
+ <header class="entry-header">
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+
+ <div class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $tag_list = get_the_tag_list( '', __( ', ', 'twentyeleven' ) );
+ if ( '' != $tag_list ) {
+ $utility_text = __( 'This entry was posted in %1$s and tagged %2$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyeleven' );
+ } else {
+ $utility_text = __( 'This entry was posted in %1$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyeleven' );
+ }
+ printf(
+ $utility_text,
+ /* translators: used between list items, there is a space after the comma */
+ get_the_category_list( __( ', ', 'twentyeleven' ) ),
+ $tag_list,
+ esc_url( get_permalink() ),
+ the_title_attribute( 'echo=0' )
+ );
+ ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-gallery.php b/src/wp-content/themes/twentyeleven/content-gallery.php
new file mode 100644
index 0000000000..fb7b1058b1
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-gallery.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * The template for displaying posts in the Gallery Post Format on index and archive pages
+ *
+ * Learn more: http://codex.wordpress.org/Post_Formats
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Gallery', 'twentyeleven' ); ?></h3>
+ </hgroup>
+
+ <div class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for search pages ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php if ( post_password_required() ) : ?>
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php else :
+ $images = twentyeleven_get_gallery_images();
+ if ( $images ) :
+ $total_images = count( $images );
+ $image = array_shift( $images );
+ ?>
+ <figure class="gallery-thumb">
+ <a href="<?php the_permalink(); ?>"><?php echo wp_get_attachment_image( $image, 'thumbnail' ); ?></a>
+ </figure><!-- .gallery-thumb -->
+
+ <p><em><?php printf( _n( 'This gallery contains <a %1$s>%2$s photo</a>.', 'This gallery contains <a %1$s>%2$s photos</a>.', $total_images, 'twentyeleven' ),
+ 'href="' . esc_url( get_permalink() ) . '" title="' . esc_attr( sprintf( __( 'Permalink to %s', 'twentyeleven' ), the_title_attribute( 'echo=0' ) ) ) . '" rel="bookmark"',
+ number_format_i18n( $total_images )
+ ); ?></em></p>
+ <?php endif; // end twentyeleven_get_gallery_images() check ?>
+ <?php the_excerpt(); ?>
+ <?php endif; ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php $show_sep = false; ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyeleven' ) );
+ if ( $categories_list ):
+ ?>
+ <span class="cat-links">
+ <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list );
+ $show_sep = true; ?>
+ </span>
+ <?php endif; // End if categories ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $tags_list = get_the_tag_list( '', __( ', ', 'twentyeleven' ) );
+ if ( $tags_list ):
+ if ( $show_sep ) : ?>
+ <span class="sep"> | </span>
+ <?php endif; // End if $show_sep ?>
+ <span class="tag-links">
+ <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list );
+ $show_sep = true; ?>
+ </span>
+ <?php endif; // End if $tags_list ?>
+
+ <?php if ( comments_open() ) : ?>
+ <?php if ( $show_sep ) : ?>
+ <span class="sep"> | </span>
+ <?php endif; // End if $show_sep ?>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; // End if comments_open() ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-image.php b/src/wp-content/themes/twentyeleven/content-image.php
new file mode 100644
index 0000000000..4d2cbaf0c5
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-image.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * The template for displaying posts in the Image Post Format on index and archive pages
+ *
+ * Learn more: http://codex.wordpress.org/Post_Formats
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+ <article id="post-<?php the_ID(); ?>" <?php post_class( 'indexed' ); ?>>
+ <header class="entry-header">
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Image', 'twentyeleven' ); ?></h3>
+ </hgroup>
+
+ <?php if ( comments_open() && ! post_password_required() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( "Reply", 'twentyeleven' ) . '</span>', _x( '1', 'comments number', 'twentyeleven' ), _x( '%', 'comments number', 'twentyeleven' ) ); ?>
+ </div>
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <div class="entry-meta">
+ <?php
+ printf( __( '<a href="%1$s" rel="bookmark"><time class="entry-date" datetime="%2$s">%3$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%4$s" title="%5$s" rel="author">%6$s</a></span></span>', 'twentyeleven' ),
+ esc_url( get_permalink() ),
+ get_the_date( 'c' ),
+ get_the_date(),
+ esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentyeleven' ), get_the_author() ) ),
+ get_the_author()
+ );
+ ?>
+ </div><!-- .entry-meta -->
+ <div class="entry-meta">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyeleven' ) );
+ if ( $categories_list ):
+ ?>
+ <span class="cat-links">
+ <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list ); ?>
+ </span>
+ <?php endif; // End if categories ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $tags_list = get_the_tag_list( '', __( ', ', 'twentyeleven' ) );
+ if ( $tags_list ): ?>
+ <span class="tag-links">
+ <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list ); ?>
+ </span>
+ <?php endif; // End if $tags_list ?>
+
+ <?php if ( comments_open() ) : ?>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; // End if comments_open() ?>
+ </div><!-- .entry-meta -->
+
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-intro.php b/src/wp-content/themes/twentyeleven/content-intro.php
new file mode 100644
index 0000000000..573112d55b
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-intro.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * The template for displaying page content in the showcase.php page template
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class( 'intro' ); ?>>
+ <header class="entry-header">
+ <h2 class="entry-title"><?php the_title(); ?></h2>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-content -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-link.php b/src/wp-content/themes/twentyeleven/content-link.php
new file mode 100644
index 0000000000..f03099e52c
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-link.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * The template for displaying posts in the Link Post Format on index and archive pages
+ *
+ * Learn more: http://codex.wordpress.org/Post_Formats
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Link', 'twentyeleven' ); ?></h3>
+ </hgroup>
+
+ <?php if ( comments_open() && ! post_password_required() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'twentyeleven' ) . '</span>', _x( '1', 'comments number', 'twentyeleven' ), _x( '%', 'comments number', 'twentyeleven' ) ); ?>
+ </div>
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ <?php if ( comments_open() ) : ?>
+ <span class="sep"> | </span>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; ?>
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-page.php b/src/wp-content/themes/twentyeleven/content-page.php
new file mode 100644
index 0000000000..c4998429d0
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-page.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * The template used for displaying page content in page.php
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <footer class="entry-meta">
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-quote.php b/src/wp-content/themes/twentyeleven/content-quote.php
new file mode 100644
index 0000000000..c74e006932
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-quote.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * The default template for displaying content
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Quote', 'twentyeleven' ); ?></h3>
+ </hgroup>
+
+ <div class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ </div><!-- .entry-meta -->
+
+ <?php if ( comments_open() && ! post_password_required() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'twentyeleven' ) . '</span>', _x( '1', 'comments number', 'twentyeleven' ), _x( '%', 'comments number', 'twentyeleven' ) ); ?>
+ </div>
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php $show_sep = false; ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyeleven' ) );
+ if ( $categories_list ):
+ ?>
+ <span class="cat-links">
+ <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list );
+ $show_sep = true; ?>
+ </span>
+ <?php endif; // End if categories ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $tags_list = get_the_tag_list( '', __( ', ', 'twentyeleven' ) );
+ if ( $tags_list ):
+ if ( $show_sep ) : ?>
+ <span class="sep"> | </span>
+ <?php endif; // End if $show_sep ?>
+ <span class="tag-links">
+ <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list );
+ $show_sep = true; ?>
+ </span>
+ <?php endif; // End if $tags_list ?>
+
+ <?php if ( comments_open() ) : ?>
+ <?php if ( $show_sep ) : ?>
+ <span class="sep"> | </span>
+ <?php endif; // End if $show_sep ?>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; // End if comments_open() ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-single.php b/src/wp-content/themes/twentyeleven/content-single.php
new file mode 100644
index 0000000000..8c28371590
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-single.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * The template for displaying content in the single.php template
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+
+ <?php if ( 'post' == get_post_type() ) : ?>
+ <div class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ </div><!-- .entry-meta -->
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyeleven' ) );
+
+ /* translators: used between list items, there is a space after the comma */
+ $tag_list = get_the_tag_list( '', __( ', ', 'twentyeleven' ) );
+ if ( '' != $tag_list ) {
+ $utility_text = __( 'This entry was posted in %1$s and tagged %2$s by <a href="%6$s">%5$s</a>. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyeleven' );
+ } elseif ( '' != $categories_list ) {
+ $utility_text = __( 'This entry was posted in %1$s by <a href="%6$s">%5$s</a>. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyeleven' );
+ } else {
+ $utility_text = __( 'This entry was posted by <a href="%6$s">%5$s</a>. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyeleven' );
+ }
+
+ printf(
+ $utility_text,
+ $categories_list,
+ $tag_list,
+ esc_url( get_permalink() ),
+ the_title_attribute( 'echo=0' ),
+ get_the_author(),
+ esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) )
+ );
+ ?>
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( get_the_author_meta( 'description' ) && ( ! function_exists( 'is_multi_author' ) || is_multi_author() ) ) : // If a user has filled out their description and this is a multi-author blog, show a bio on their entries ?>
+ <div id="author-info">
+ <div id="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentyeleven_author_bio_avatar_size', 68 ) ); ?>
+ </div><!-- #author-avatar -->
+ <div id="author-description">
+ <h2><?php printf( __( 'About %s', 'twentyeleven' ), get_the_author() ); ?></h2>
+ <?php the_author_meta( 'description' ); ?>
+ <div id="author-link">
+ <a href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>" rel="author">
+ <?php printf( __( 'View all posts by %s <span class="meta-nav">&rarr;</span>', 'twentyeleven' ), get_the_author() ); ?>
+ </a>
+ </div><!-- #author-link -->
+ </div><!-- #author-description -->
+ </div><!-- #author-info -->
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content-status.php b/src/wp-content/themes/twentyeleven/content-status.php
new file mode 100644
index 0000000000..144d12262d
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content-status.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * The template for displaying posts in the Status Post Format on index and archive pages
+ *
+ * Learn more: http://codex.wordpress.org/Post_Formats
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Status', 'twentyeleven' ); ?></h3>
+ </hgroup>
+
+ <?php if ( comments_open() && ! post_password_required() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'twentyeleven' ) . '</span>', _x( '1', 'comments number', 'twentyeleven' ), _x( '%', 'comments number', 'twentyeleven' ) ); ?>
+ </div>
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <div class="avatar"><?php echo get_avatar( get_the_author_meta( 'ID' ), apply_filters( 'twentyeleven_status_avatar', '65' ) ); ?></div>
+
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ <?php if ( comments_open() ) : ?>
+ <span class="sep"> | </span>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; ?>
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/content.php b/src/wp-content/themes/twentyeleven/content.php
new file mode 100644
index 0000000000..cc8532c998
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/content.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * The default template for displaying content
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( is_sticky() ) : ?>
+ <hgroup>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+ <h3 class="entry-format"><?php _e( 'Featured', 'twentyeleven' ); ?></h3>
+ </hgroup>
+ <?php else : ?>
+ <h1 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
+ <?php endif; ?>
+
+ <?php if ( 'post' == get_post_type() ) : ?>
+ <div class="entry-meta">
+ <?php twentyeleven_posted_on(); ?>
+ </div><!-- .entry-meta -->
+ <?php endif; ?>
+
+ <?php if ( comments_open() && ! post_password_required() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'twentyeleven' ) . '</span>', _x( '1', 'comments number', 'twentyeleven' ), _x( '%', 'comments number', 'twentyeleven' ) ); ?>
+ </div>
+ <?php endif; ?>
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php $show_sep = false; ?>
+ <?php if ( is_object_in_taxonomy( get_post_type(), 'category' ) ) : // Hide category text when not supported ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyeleven' ) );
+ if ( $categories_list ):
+ ?>
+ <span class="cat-links">
+ <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list );
+ $show_sep = true; ?>
+ </span>
+ <?php endif; // End if categories ?>
+ <?php endif; // End if is_object_in_taxonomy( get_post_type(), 'category' ) ?>
+ <?php if ( is_object_in_taxonomy( get_post_type(), 'post_tag' ) ) : // Hide tag text when not supported ?>
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $tags_list = get_the_tag_list( '', __( ', ', 'twentyeleven' ) );
+ if ( $tags_list ):
+ if ( $show_sep ) : ?>
+ <span class="sep"> | </span>
+ <?php endif; // End if $show_sep ?>
+ <span class="tag-links">
+ <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'twentyeleven' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list );
+ $show_sep = true; ?>
+ </span>
+ <?php endif; // End if $tags_list ?>
+ <?php endif; // End if is_object_in_taxonomy( get_post_type(), 'post_tag' ) ?>
+
+ <?php if ( comments_open() ) : ?>
+ <?php if ( $show_sep ) : ?>
+ <span class="sep"> | </span>
+ <?php endif; // End if $show_sep ?>
+ <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?></span>
+ <?php endif; // End if comments_open() ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyeleven/editor-style-rtl.css b/src/wp-content/themes/twentyeleven/editor-style-rtl.css
new file mode 100644
index 0000000000..2146645add
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/editor-style-rtl.css
@@ -0,0 +1,24 @@
+/*
+Theme Name: Twenty Eleven
+*/
+/*
+Used to style the TinyMCE editor.
+*/
+html .mceContentBody {
+ direction: rtl;
+ unicode-bidi: embed;
+ float: right;
+ width: 584px;
+}
+* {
+ font-family: Arial, Tahoma, sans-serif;
+}
+ul, ol {
+ margin: 0 2.5em 1.625em 0;
+}
+blockquote {
+ font-style: normal;
+}
+table {
+ text-align: right;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/editor-style.css b/src/wp-content/themes/twentyeleven/editor-style.css
new file mode 100644
index 0000000000..234bb9c216
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/editor-style.css
@@ -0,0 +1,312 @@
+/*
+Theme Name: Twenty Eleven
+Description: Used to style the TinyMCE editor.
+*/
+
+html .mceContentBody {
+ max-width: 584px;
+}
+* {
+ color: inherit;
+ font: 15px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-style: inherit;
+ font-weight: inherit;
+ line-height: 1.625;
+}
+body {
+ color: #333;
+ font: 15px "Helvetica Neue", Helvetica, Arial, "Nimbus Sans L", sans-serif;
+ font-weight: 300;
+ line-height: 1.625;
+}
+
+/* Headings */
+h1,h2,h3,h4,h5,h6 {
+ clear: both;
+}
+h1,
+h2 {
+ color: #000;
+ font-size: 15px;
+ font-weight: bold;
+ margin: 0 0 .8125em;
+}
+h3 {
+ font-size: 10px;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+h4, h5, h6 {
+ font-size: 14px;
+ margin: 0;
+}
+hr {
+ background-color: #ccc;
+ border: 0;
+ height: 1px;
+ margin-bottom: 1.625em;
+}
+
+/* Text elements */
+p, ul, ol, dl {
+ font-weight: 300;
+}
+p {
+ margin-bottom: 1.625em;
+}
+ul, ol {
+ margin: 0 0 1.625em 2.5em;
+ padding: 0;
+}
+ul {
+ list-style: square;
+}
+ol {
+ list-style-type: decimal;
+}
+ol ol {
+ list-style: upper-alpha;
+}
+ol ol ol {
+ list-style: lower-roman;
+}
+ol ol ol ol {
+ list-style: lower-alpha;
+}
+ul ul, ol ol, ul ol, ol ul {
+ margin-bottom: 0;
+}
+dl {
+ margin: 0 1.625em;
+}
+dt {
+ font-size: 15px;
+ font-weight: bold;
+}
+dd {
+ margin: 0 0 1.625em;
+}
+strong {
+ font-weight: bold;
+}
+cite, em, i {
+ font-style: italic;
+}
+cite {
+ border: none;
+}
+big {
+ font-size: 131.25%;
+}
+.mceContentBody blockquote,
+.mceContentBody blockquote p {
+ font-family: Georgia, "Bitstream Charter", serif !important;
+ font-style: italic !important;
+ font-weight: normal;
+ margin: 0 3em;
+}
+.mceContentBody blockquote em,
+.mceContentBody blockquote i,
+.mceContentBody blockquote cite {
+ font-style: normal;
+}
+.mceContentBody blockquote cite {
+ color: #666;
+ font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-weight: 300;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+}
+pre {
+ background: #f4f4f4;
+ font: 13px "Courier 10 Pitch", Courier, monospace;
+ line-height: 1.5;
+ margin-bottom: 1.625em;
+ padding: 0.75em 1.625em;
+}
+code, kbd, samp, var {
+ font: 13px Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
+}
+abbr, acronym, dfn {
+ border-bottom: 1px dotted #666;
+ cursor: help;
+}
+address {
+ display: block;
+ margin: 0 0 1.625em;
+}
+del {
+ color: #333;
+}
+ins {
+ background: #fff9c0;
+ border: none;
+ color: #333;
+ text-decoration: none;
+}
+sup,
+sub {
+ font-size: 10px;
+ height: 0;
+ line-height: 1;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ bottom: 1ex;
+}
+sub {
+ top: .5ex;
+}
+input[type=text],
+textarea {
+ background: #fafafa;
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ border: 1px solid #ddd;
+ color: #888;
+}
+input[type=text]:focus,
+textarea:focus {
+ color: #333;
+}
+textarea {
+ padding-left: 3px;
+ width: 98%;
+}
+input[type=text] {
+ padding: 3px;
+}
+
+/* Links */
+a,
+a em,
+a strong {
+ color: #1b8be0;
+ text-decoration: none;
+}
+a:focus,
+a:active,
+a:hover {
+ text-decoration: underline;
+}
+
+/* Alignment */
+.alignleft {
+ display: inline;
+ float: left;
+ margin-right: 1.625em;
+}
+.alignright {
+ display: inline;
+ float: right;
+ margin-left: 1.625em;
+}
+.aligncenter {
+ clear: both;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+/* Tables */
+table {
+ border: none !important;
+ border-bottom: 1px solid #ddd !important;
+ border-collapse: collapse;
+ border-spacing: 0;
+ text-align: left;
+ margin: 0 0 1.625em;
+ width: 100%;
+}
+tr th {
+ border: none !important;
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+td {
+ border: none !important;
+ border-top: 1px solid #ddd !important;
+ padding: 6px 10px 6px 0;
+}
+
+/* Images */
+img[class*="wp-image-"] {
+ height: auto;
+ max-width: 97.5%;
+}
+img.size-full {
+ width: auto; /* Prevent stretching of full-size images in IE8 */
+}
+img.wp-smiley {
+ border: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+p img,
+.wp-caption {
+ margin-top: 0.4em;
+}
+img,
+.editor-attachment {
+ border: 1px solid #ddd;
+ padding: 6px;
+}
+img.alignleft,
+img.alignright,
+img.aligncenter {
+ margin-bottom: 1.625em;
+}
+.wp-caption {
+ background: #eee;
+ border: none;
+ margin-bottom: 1.625em;
+ max-width: 96%;
+ padding: 9px;
+}
+.wp-caption img {
+ display: block;
+ margin: 5px auto 0 !important;
+ max-width: 98%;
+ border-color: #eee;
+}
+.wp-caption .wp-caption-text,
+.wp-caption-dd {
+ color: #666;
+ font-family: Georgia, serif !important;
+ font-size: 12px;
+ margin: 0 0 0.6em 0 !important;
+ padding: 0 0 5px 40px;
+ position: relative;
+ text-align: left;
+}
+.wp-caption .wp-caption-text:before {
+ color: #666;
+ content: '\2014';
+ font-size: 14px;
+ font-style: normal;
+ font-weight: bold;
+ margin-right: 5px;
+ position: absolute;
+ left: 10px;
+ top: 7px;
+}
+a:focus img[class*="wp-image-"],
+a:hover img[class*="wp-image-"],
+a:active img[class*="wp-image-"] {
+ background: #eee;
+ border-color: #bbb;
+}
+.wp-caption a:focus img,
+.wp-caption a:active img,
+.wp-caption a:hover img {
+ background: #fff;
+ border-color: #ddd;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/footer.php b/src/wp-content/themes/twentyeleven/footer.php
new file mode 100644
index 0000000000..9cb702caf8
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/footer.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * The template for displaying the footer.
+ *
+ * Contains the closing of the id=main div and all content after
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+ </div><!-- #main -->
+
+ <footer id="colophon" role="contentinfo">
+
+ <?php
+ /* A sidebar in the footer? Yep. You can can customize
+ * your footer with three columns of widgets.
+ */
+ if ( ! is_404() )
+ get_sidebar( 'footer' );
+ ?>
+
+ <div id="site-generator">
+ <?php do_action( 'twentyeleven_credits' ); ?>
+ <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'twentyeleven' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'twentyeleven' ); ?>"><?php printf( __( 'Proudly powered by %s', 'twentyeleven' ), 'WordPress' ); ?></a>
+ </div>
+ </footer><!-- #colophon -->
+</div><!-- #page -->
+
+<?php wp_footer(); ?>
+
+</body>
+</html> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/functions.php b/src/wp-content/themes/twentyeleven/functions.php
new file mode 100644
index 0000000000..3d269676c9
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/functions.php
@@ -0,0 +1,671 @@
+<?php
+/**
+ * Twenty Eleven functions and definitions
+ *
+ * Sets up the theme and provides some helper functions. Some helper functions
+ * are used in the theme as custom template tags. Others are attached to action and
+ * filter hooks in WordPress to change core functionality.
+ *
+ * The first function, twentyeleven_setup(), sets up the theme by registering support
+ * for various features in WordPress, such as post thumbnails, navigation menus, and the like.
+ *
+ * When using a child theme (see http://codex.wordpress.org/Theme_Development and
+ * http://codex.wordpress.org/Child_Themes), you can override certain functions
+ * (those wrapped in a function_exists() call) by defining them first in your child theme's
+ * functions.php file. The child theme's functions.php file is included before the parent
+ * theme's file, so the child theme functions would be used.
+ *
+ * Functions that are not pluggable (not wrapped in function_exists()) are instead attached
+ * to a filter or action hook. The hook can be removed by using remove_action() or
+ * remove_filter() and you can attach your own function to the hook.
+ *
+ * We can remove the parent theme's hook only after it is attached, which means we need to
+ * wait until setting up the child theme:
+ *
+ * <code>
+ * add_action( 'after_setup_theme', 'my_child_theme_setup' );
+ * function my_child_theme_setup() {
+ * // We are providing our own filter for excerpt_length (or using the unfiltered value)
+ * remove_filter( 'excerpt_length', 'twentyeleven_excerpt_length' );
+ * ...
+ * }
+ * </code>
+ *
+ * For more information on hooks, actions, and filters, see http://codex.wordpress.org/Plugin_API.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+/**
+ * Set the content width based on the theme's design and stylesheet.
+ */
+if ( ! isset( $content_width ) )
+ $content_width = 584;
+
+/**
+ * Tell WordPress to run twentyeleven_setup() when the 'after_setup_theme' hook is run.
+ */
+add_action( 'after_setup_theme', 'twentyeleven_setup' );
+
+if ( ! function_exists( 'twentyeleven_setup' ) ):
+/**
+ * Sets up theme defaults and registers support for various WordPress features.
+ *
+ * Note that this function is hooked into the after_setup_theme hook, which runs
+ * before the init hook. The init hook is too late for some features, such as indicating
+ * support post thumbnails.
+ *
+ * To override twentyeleven_setup() in a child theme, add your own twentyeleven_setup to your child theme's
+ * functions.php file.
+ *
+ * @uses load_theme_textdomain() For translation/localization support.
+ * @uses add_editor_style() To style the visual editor.
+ * @uses add_theme_support() To add support for post thumbnails, automatic feed links, custom headers
+ * and backgrounds, and post formats.
+ * @uses register_nav_menus() To add support for navigation menus.
+ * @uses register_default_headers() To register the default custom header images provided with the theme.
+ * @uses set_post_thumbnail_size() To set a custom post thumbnail size.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_setup() {
+
+ /* Make Twenty Eleven available for translation.
+ * Translations can be added to the /languages/ directory.
+ * If you're building a theme based on Twenty Eleven, use a find and replace
+ * to change 'twentyeleven' to the name of your theme in all the template files.
+ */
+ load_theme_textdomain( 'twentyeleven', get_template_directory() . '/languages' );
+
+ // This theme styles the visual editor with editor-style.css to match the theme style.
+ add_editor_style();
+
+ // Load up our theme options page and related code.
+ require( get_template_directory() . '/inc/theme-options.php' );
+
+ // Grab Twenty Eleven's Ephemera widget.
+ require( get_template_directory() . '/inc/widgets.php' );
+
+ // Add default posts and comments RSS feed links to <head>.
+ add_theme_support( 'automatic-feed-links' );
+
+ // This theme uses wp_nav_menu() in one location.
+ register_nav_menu( 'primary', __( 'Primary Menu', 'twentyeleven' ) );
+
+ // Add support for a variety of post formats
+ add_theme_support( 'post-formats', array( 'aside', 'link', 'gallery', 'status', 'quote', 'image' ) );
+
+ $theme_options = twentyeleven_get_theme_options();
+ if ( 'dark' == $theme_options['color_scheme'] )
+ $default_background_color = '1d1d1d';
+ else
+ $default_background_color = 'e2e2e2';
+
+ // Add support for custom backgrounds.
+ add_theme_support( 'custom-background', array(
+ // Let WordPress know what our default background color is.
+ // This is dependent on our current color scheme.
+ 'default-color' => $default_background_color,
+ ) );
+
+ // This theme uses Featured Images (also known as post thumbnails) for per-post/per-page Custom Header images
+ add_theme_support( 'post-thumbnails' );
+
+ // Add support for custom headers.
+ $custom_header_support = array(
+ // The default header text color.
+ 'default-text-color' => '000',
+ // The height and width of our custom header.
+ 'width' => apply_filters( 'twentyeleven_header_image_width', 1000 ),
+ 'height' => apply_filters( 'twentyeleven_header_image_height', 288 ),
+ // Support flexible heights.
+ 'flex-height' => true,
+ // Random image rotation by default.
+ 'random-default' => true,
+ // Callback for styling the header.
+ 'wp-head-callback' => 'twentyeleven_header_style',
+ // Callback for styling the header preview in the admin.
+ 'admin-head-callback' => 'twentyeleven_admin_header_style',
+ // Callback used to display the header preview in the admin.
+ 'admin-preview-callback' => 'twentyeleven_admin_header_image',
+ );
+
+ add_theme_support( 'custom-header', $custom_header_support );
+
+ if ( ! function_exists( 'get_custom_header' ) ) {
+ // This is all for compatibility with versions of WordPress prior to 3.4.
+ define( 'HEADER_TEXTCOLOR', $custom_header_support['default-text-color'] );
+ define( 'HEADER_IMAGE', '' );
+ define( 'HEADER_IMAGE_WIDTH', $custom_header_support['width'] );
+ define( 'HEADER_IMAGE_HEIGHT', $custom_header_support['height'] );
+ add_custom_image_header( $custom_header_support['wp-head-callback'], $custom_header_support['admin-head-callback'], $custom_header_support['admin-preview-callback'] );
+ add_custom_background();
+ }
+
+ // We'll be using post thumbnails for custom header images on posts and pages.
+ // We want them to be the size of the header image that we just defined
+ // Larger images will be auto-cropped to fit, smaller ones will be ignored. See header.php.
+ set_post_thumbnail_size( $custom_header_support['width'], $custom_header_support['height'], true );
+
+ // Add Twenty Eleven's custom image sizes.
+ // Used for large feature (header) images.
+ add_image_size( 'large-feature', $custom_header_support['width'], $custom_header_support['height'], true );
+ // Used for featured posts if a large-feature doesn't exist.
+ add_image_size( 'small-feature', 500, 300 );
+
+ // Default custom headers packaged with the theme. %s is a placeholder for the theme template directory URI.
+ register_default_headers( array(
+ 'wheel' => array(
+ 'url' => '%s/images/headers/wheel.jpg',
+ 'thumbnail_url' => '%s/images/headers/wheel-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Wheel', 'twentyeleven' )
+ ),
+ 'shore' => array(
+ 'url' => '%s/images/headers/shore.jpg',
+ 'thumbnail_url' => '%s/images/headers/shore-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Shore', 'twentyeleven' )
+ ),
+ 'trolley' => array(
+ 'url' => '%s/images/headers/trolley.jpg',
+ 'thumbnail_url' => '%s/images/headers/trolley-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Trolley', 'twentyeleven' )
+ ),
+ 'pine-cone' => array(
+ 'url' => '%s/images/headers/pine-cone.jpg',
+ 'thumbnail_url' => '%s/images/headers/pine-cone-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Pine Cone', 'twentyeleven' )
+ ),
+ 'chessboard' => array(
+ 'url' => '%s/images/headers/chessboard.jpg',
+ 'thumbnail_url' => '%s/images/headers/chessboard-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Chessboard', 'twentyeleven' )
+ ),
+ 'lanterns' => array(
+ 'url' => '%s/images/headers/lanterns.jpg',
+ 'thumbnail_url' => '%s/images/headers/lanterns-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Lanterns', 'twentyeleven' )
+ ),
+ 'willow' => array(
+ 'url' => '%s/images/headers/willow.jpg',
+ 'thumbnail_url' => '%s/images/headers/willow-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Willow', 'twentyeleven' )
+ ),
+ 'hanoi' => array(
+ 'url' => '%s/images/headers/hanoi.jpg',
+ 'thumbnail_url' => '%s/images/headers/hanoi-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Hanoi Plant', 'twentyeleven' )
+ )
+ ) );
+}
+endif; // twentyeleven_setup
+
+if ( ! function_exists( 'twentyeleven_header_style' ) ) :
+/**
+ * Styles the header image and text displayed on the blog
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_header_style() {
+ $text_color = get_header_textcolor();
+
+ // If no custom options for text are set, let's bail.
+ if ( $text_color == HEADER_TEXTCOLOR )
+ return;
+
+ // If we get this far, we have custom styles. Let's do this.
+ ?>
+ <style type="text/css" id="twentyeleven-header-css">
+ <?php
+ // Has the text been hidden?
+ if ( 'blank' == $text_color ) :
+ ?>
+ #site-title,
+ #site-description {
+ position: absolute !important;
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ <?php
+ // If the user has set a custom color for the text use that
+ else :
+ ?>
+ #site-title a,
+ #site-description {
+ color: #<?php echo $text_color; ?> !important;
+ }
+ <?php endif; ?>
+ </style>
+ <?php
+}
+endif; // twentyeleven_header_style
+
+if ( ! function_exists( 'twentyeleven_admin_header_style' ) ) :
+/**
+ * Styles the header image displayed on the Appearance > Header admin panel.
+ *
+ * Referenced via add_theme_support('custom-header') in twentyeleven_setup().
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_admin_header_style() {
+?>
+ <style type="text/css" id="twentyeleven-admin-header-css">
+ .appearance_page_custom-header #headimg {
+ border: none;
+ }
+ #headimg h1,
+ #desc {
+ font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif;
+ }
+ #headimg h1 {
+ margin: 0;
+ }
+ #headimg h1 a {
+ font-size: 32px;
+ line-height: 36px;
+ text-decoration: none;
+ }
+ #desc {
+ font-size: 14px;
+ line-height: 23px;
+ padding: 0 0 3em;
+ }
+ <?php
+ // If the user has set a custom color for the text use that
+ if ( get_header_textcolor() != HEADER_TEXTCOLOR ) :
+ ?>
+ #site-title a,
+ #site-description {
+ color: #<?php echo get_header_textcolor(); ?>;
+ }
+ <?php endif; ?>
+ #headimg img {
+ max-width: 1000px;
+ height: auto;
+ width: 100%;
+ }
+ </style>
+<?php
+}
+endif; // twentyeleven_admin_header_style
+
+if ( ! function_exists( 'twentyeleven_admin_header_image' ) ) :
+/**
+ * Custom header image markup displayed on the Appearance > Header admin panel.
+ *
+ * Referenced via add_theme_support('custom-header') in twentyeleven_setup().
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_admin_header_image() { ?>
+ <div id="headimg">
+ <?php
+ $color = get_header_textcolor();
+ $image = get_header_image();
+ if ( $color && $color != 'blank' )
+ $style = ' style="color:#' . $color . '"';
+ else
+ $style = ' style="display:none"';
+ ?>
+ <h1 class="displaying-header-text"><a id="name"<?php echo $style; ?> onclick="return false;" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
+ <div id="desc" class="displaying-header-text"<?php echo $style; ?>><?php bloginfo( 'description' ); ?></div>
+ <?php if ( $image ) : ?>
+ <img src="<?php echo esc_url( $image ); ?>" alt="" />
+ <?php endif; ?>
+ </div>
+<?php }
+endif; // twentyeleven_admin_header_image
+
+/**
+ * Sets the post excerpt length to 40 words.
+ *
+ * To override this length in a child theme, remove the filter and add your own
+ * function tied to the excerpt_length filter hook.
+ */
+function twentyeleven_excerpt_length( $length ) {
+ return 40;
+}
+add_filter( 'excerpt_length', 'twentyeleven_excerpt_length' );
+
+if ( ! function_exists( 'twentyeleven_continue_reading_link' ) ) :
+/**
+ * Returns a "Continue Reading" link for excerpts
+ */
+function twentyeleven_continue_reading_link() {
+ return ' <a href="'. esc_url( get_permalink() ) . '">' . __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) . '</a>';
+}
+endif; // twentyeleven_continue_reading_link
+
+/**
+ * Replaces "[...]" (appended to automatically generated excerpts) with an ellipsis and twentyeleven_continue_reading_link().
+ *
+ * To override this in a child theme, remove the filter and add your own
+ * function tied to the excerpt_more filter hook.
+ */
+function twentyeleven_auto_excerpt_more( $more ) {
+ return ' &hellip;' . twentyeleven_continue_reading_link();
+}
+add_filter( 'excerpt_more', 'twentyeleven_auto_excerpt_more' );
+
+/**
+ * Adds a pretty "Continue Reading" link to custom post excerpts.
+ *
+ * To override this link in a child theme, remove the filter and add your own
+ * function tied to the get_the_excerpt filter hook.
+ */
+function twentyeleven_custom_excerpt_more( $output ) {
+ if ( has_excerpt() && ! is_attachment() ) {
+ $output .= twentyeleven_continue_reading_link();
+ }
+ return $output;
+}
+add_filter( 'get_the_excerpt', 'twentyeleven_custom_excerpt_more' );
+
+/**
+ * Get our wp_nav_menu() fallback, wp_page_menu(), to show a home link.
+ */
+function twentyeleven_page_menu_args( $args ) {
+ if ( ! isset( $args['show_home'] ) )
+ $args['show_home'] = true;
+ return $args;
+}
+add_filter( 'wp_page_menu_args', 'twentyeleven_page_menu_args' );
+
+/**
+ * Register our sidebars and widgetized areas. Also register the default Epherma widget.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_widgets_init() {
+
+ register_widget( 'Twenty_Eleven_Ephemera_Widget' );
+
+ register_sidebar( array(
+ 'name' => __( 'Main Sidebar', 'twentyeleven' ),
+ 'id' => 'sidebar-1',
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => "</aside>",
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'Showcase Sidebar', 'twentyeleven' ),
+ 'id' => 'sidebar-2',
+ 'description' => __( 'The sidebar for the optional Showcase Template', 'twentyeleven' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => "</aside>",
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'Footer Area One', 'twentyeleven' ),
+ 'id' => 'sidebar-3',
+ 'description' => __( 'An optional widget area for your site footer', 'twentyeleven' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => "</aside>",
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'Footer Area Two', 'twentyeleven' ),
+ 'id' => 'sidebar-4',
+ 'description' => __( 'An optional widget area for your site footer', 'twentyeleven' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => "</aside>",
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'Footer Area Three', 'twentyeleven' ),
+ 'id' => 'sidebar-5',
+ 'description' => __( 'An optional widget area for your site footer', 'twentyeleven' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => "</aside>",
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+}
+add_action( 'widgets_init', 'twentyeleven_widgets_init' );
+
+if ( ! function_exists( 'twentyeleven_content_nav' ) ) :
+/**
+ * Display navigation to next/previous pages when applicable
+ */
+function twentyeleven_content_nav( $html_id ) {
+ global $wp_query;
+
+ if ( $wp_query->max_num_pages > 1 ) : ?>
+ <nav id="<?php echo esc_attr( $html_id ); ?>">
+ <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentyeleven' ); ?></h3>
+ <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentyeleven' ) ); ?></div>
+ <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?></div>
+ </nav><!-- #nav-above -->
+ <?php endif;
+}
+endif; // twentyeleven_content_nav
+
+/**
+ * Return the first link from the post content. If none found, the
+ * post permalink is used as a fallback.
+ *
+ * @uses get_url_in_content() to get the first URL from the post content.
+ *
+ * @return string
+ */
+function twentyeleven_get_first_url() {
+ $content = get_the_content();
+ $has_url = function_exists( 'get_url_in_content' ) ? get_url_in_content( $content ) : false;
+
+ if ( ! $has_url )
+ $has_url = twentyeleven_url_grabber();
+
+ return ( $has_url ) ? $has_url : apply_filters( 'the_permalink', get_permalink() );
+}
+
+/**
+ * Return the URL for the first link found in the post content.
+ *
+ * @since Twenty Eleven 1.0
+ * @return string|bool URL or false when no link is present.
+ */
+function twentyeleven_url_grabber() {
+ if ( ! preg_match( '/<a\s[^>]*?href=[\'"](.+?)[\'"]/is', get_the_content(), $matches ) )
+ return false;
+
+ return esc_url_raw( $matches[1] );
+}
+
+/**
+ * Count the number of footer sidebars to enable dynamic classes for the footer
+ */
+function twentyeleven_footer_sidebar_class() {
+ $count = 0;
+
+ if ( is_active_sidebar( 'sidebar-3' ) )
+ $count++;
+
+ if ( is_active_sidebar( 'sidebar-4' ) )
+ $count++;
+
+ if ( is_active_sidebar( 'sidebar-5' ) )
+ $count++;
+
+ $class = '';
+
+ switch ( $count ) {
+ case '1':
+ $class = 'one';
+ break;
+ case '2':
+ $class = 'two';
+ break;
+ case '3':
+ $class = 'three';
+ break;
+ }
+
+ if ( $class )
+ echo 'class="' . $class . '"';
+}
+
+if ( ! function_exists( 'twentyeleven_comment' ) ) :
+/**
+ * Template for comments and pingbacks.
+ *
+ * To override this walker in a child theme without modifying the comments template
+ * simply create your own twentyeleven_comment(), and that function will be used instead.
+ *
+ * Used as a callback by wp_list_comments() for displaying the comments.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_comment( $comment, $args, $depth ) {
+ $GLOBALS['comment'] = $comment;
+ switch ( $comment->comment_type ) :
+ case 'pingback' :
+ case 'trackback' :
+ ?>
+ <li class="post pingback">
+ <p><?php _e( 'Pingback:', 'twentyeleven' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?></p>
+ <?php
+ break;
+ default :
+ ?>
+ <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
+ <article id="comment-<?php comment_ID(); ?>" class="comment">
+ <footer class="comment-meta">
+ <div class="comment-author vcard">
+ <?php
+ $avatar_size = 68;
+ if ( '0' != $comment->comment_parent )
+ $avatar_size = 39;
+
+ echo get_avatar( $comment, $avatar_size );
+
+ /* translators: 1: comment author, 2: date and time */
+ printf( __( '%1$s on %2$s <span class="says">said:</span>', 'twentyeleven' ),
+ sprintf( '<span class="fn">%s</span>', get_comment_author_link() ),
+ sprintf( '<a href="%1$s"><time datetime="%2$s">%3$s</time></a>',
+ esc_url( get_comment_link( $comment->comment_ID ) ),
+ get_comment_time( 'c' ),
+ /* translators: 1: date, 2: time */
+ sprintf( __( '%1$s at %2$s', 'twentyeleven' ), get_comment_date(), get_comment_time() )
+ )
+ );
+ ?>
+
+ <?php edit_comment_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .comment-author .vcard -->
+
+ <?php if ( $comment->comment_approved == '0' ) : ?>
+ <em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'twentyeleven' ); ?></em>
+ <br />
+ <?php endif; ?>
+
+ </footer>
+
+ <div class="comment-content"><?php comment_text(); ?></div>
+
+ <div class="reply">
+ <?php comment_reply_link( array_merge( $args, array( 'reply_text' => __( 'Reply <span>&darr;</span>', 'twentyeleven' ), 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
+ </div><!-- .reply -->
+ </article><!-- #comment-## -->
+
+ <?php
+ break;
+ endswitch;
+}
+endif; // ends check for twentyeleven_comment()
+
+if ( ! function_exists( 'twentyeleven_posted_on' ) ) :
+/**
+ * Prints HTML with meta information for the current post-date/time and author.
+ * Create your own twentyeleven_posted_on to override in a child theme
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_posted_on() {
+ printf( __( '<span class="sep">Posted on </span><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s">%4$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'twentyeleven' ),
+ esc_url( get_permalink() ),
+ esc_attr( get_the_time() ),
+ esc_attr( get_the_date( 'c' ) ),
+ esc_html( get_the_date() ),
+ esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentyeleven' ), get_the_author() ) ),
+ get_the_author()
+ );
+}
+endif;
+
+/**
+ * Adds two classes to the array of body classes.
+ * The first is if the site has only had one author with published posts.
+ * The second is if a singular post being displayed
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_body_classes( $classes ) {
+
+ if ( function_exists( 'is_multi_author' ) && ! is_multi_author() )
+ $classes[] = 'single-author';
+
+ if ( is_singular() && ! is_home() && ! is_page_template( 'showcase.php' ) && ! is_page_template( 'sidebar-page.php' ) )
+ $classes[] = 'singular';
+
+ return $classes;
+}
+add_filter( 'body_class', 'twentyeleven_body_classes' );
+
+/**
+ * Retrieves the IDs for images in a gallery.
+ *
+ * @uses get_post_galleries() first, if available. Falls back to shortcode parsing,
+ * then as last option uses a get_posts() call.
+ *
+ * @since Twenty Eleven 1.6.
+ *
+ * @return array List of image IDs from the post gallery.
+ */
+function twentyeleven_get_gallery_images() {
+ $images = array();
+
+ if ( function_exists( 'get_post_galleries' ) ) {
+ $galleries = get_post_galleries( get_the_ID(), false );
+ if ( isset( $galleries[0]['ids'] ) )
+ $images = explode( ',', $galleries[0]['ids'] );
+ } else {
+ $pattern = get_shortcode_regex();
+ preg_match( "/$pattern/s", get_the_content(), $match );
+ $atts = shortcode_parse_atts( $match[3] );
+ if ( isset( $atts['ids'] ) )
+ $images = explode( ',', $atts['ids'] );
+ }
+
+ if ( ! $images ) {
+ $images = get_posts( array(
+ 'fields' => 'ids',
+ 'numberposts' => 999,
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order',
+ 'post_mime_type' => 'image',
+ 'post_parent' => get_the_ID(),
+ 'post_type' => 'attachment',
+ ) );
+ }
+
+ return $images;
+}
diff --git a/src/wp-content/themes/twentyeleven/header.php b/src/wp-content/themes/twentyeleven/header.php
new file mode 100644
index 0000000000..59b6d3b140
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/header.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * The Header for our theme.
+ *
+ * Displays all of the <head> section and everything up till <div id="main">
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?><!DOCTYPE html>
+<!--[if IE 6]>
+<html id="ie6" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if IE 7]>
+<html id="ie7" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if IE 8]>
+<html id="ie8" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if !(IE 6) | !(IE 7) | !(IE 8) ]><!-->
+<html <?php language_attributes(); ?>>
+<!--<![endif]-->
+<head>
+<meta charset="<?php bloginfo( 'charset' ); ?>" />
+<meta name="viewport" content="width=device-width" />
+<title><?php
+ /*
+ * Print the <title> tag based on what is being viewed.
+ */
+ global $page, $paged;
+
+ wp_title( '|', true, 'right' );
+
+ // Add the blog name.
+ bloginfo( 'name' );
+
+ // Add the blog description for the home/front page.
+ $site_description = get_bloginfo( 'description', 'display' );
+ if ( $site_description && ( is_home() || is_front_page() ) )
+ echo " | $site_description";
+
+ // Add a page number if necessary:
+ if ( $paged >= 2 || $page >= 2 )
+ echo ' | ' . sprintf( __( 'Page %s', 'twentyeleven' ), max( $paged, $page ) );
+
+ ?></title>
+<link rel="profile" href="http://gmpg.org/xfn/11" />
+<link rel="stylesheet" type="text/css" media="all" href="<?php bloginfo( 'stylesheet_url' ); ?>" />
+<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
+<!--[if lt IE 9]>
+<script src="<?php echo get_template_directory_uri(); ?>/js/html5.js" type="text/javascript"></script>
+<![endif]-->
+<?php
+ /* We add some JavaScript to pages with the comment form
+ * to support sites with threaded comments (when in use).
+ */
+ if ( is_singular() && get_option( 'thread_comments' ) )
+ wp_enqueue_script( 'comment-reply' );
+
+ /* Always have wp_head() just before the closing </head>
+ * tag of your theme, or you will break many plugins, which
+ * generally use this hook to add elements to <head> such
+ * as styles, scripts, and meta tags.
+ */
+ wp_head();
+?>
+</head>
+
+<body <?php body_class(); ?>>
+<div id="page" class="hfeed">
+ <header id="branding" role="banner">
+ <hgroup>
+ <h1 id="site-title"><span><a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></span></h1>
+ <h2 id="site-description"><?php bloginfo( 'description' ); ?></h2>
+ </hgroup>
+
+ <?php
+ // Check to see if the header image has been removed
+ $header_image = get_header_image();
+ if ( $header_image ) :
+ // Compatibility with versions of WordPress prior to 3.4.
+ if ( function_exists( 'get_custom_header' ) ) {
+ // We need to figure out what the minimum width should be for our featured image.
+ // This result would be the suggested width if the theme were to implement flexible widths.
+ $header_image_width = get_theme_support( 'custom-header', 'width' );
+ } else {
+ $header_image_width = HEADER_IMAGE_WIDTH;
+ }
+ ?>
+ <a href="<?php echo esc_url( home_url( '/' ) ); ?>">
+ <?php
+ // The header image
+ // Check if this is a post or page, if it has a thumbnail, and if it's a big one
+ if ( is_singular() && has_post_thumbnail( $post->ID ) &&
+ ( /* $src, $width, $height */ $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), array( $header_image_width, $header_image_width ) ) ) &&
+ $image[1] >= $header_image_width ) :
+ // Houston, we have a new header image!
+ echo get_the_post_thumbnail( $post->ID, 'post-thumbnail' );
+ else :
+ // Compatibility with versions of WordPress prior to 3.4.
+ if ( function_exists( 'get_custom_header' ) ) {
+ $header_image_width = get_custom_header()->width;
+ $header_image_height = get_custom_header()->height;
+ } else {
+ $header_image_width = HEADER_IMAGE_WIDTH;
+ $header_image_height = HEADER_IMAGE_HEIGHT;
+ }
+ ?>
+ <img src="<?php header_image(); ?>" width="<?php echo $header_image_width; ?>" height="<?php echo $header_image_height; ?>" alt="" />
+ <?php endif; // end check for featured image or standard header ?>
+ </a>
+ <?php endif; // end check for removed header image ?>
+
+ <?php
+ // Has the text been hidden?
+ if ( 'blank' == get_header_textcolor() ) :
+ ?>
+ <div class="only-search<?php if ( $header_image ) : ?> with-image<?php endif; ?>">
+ <?php get_search_form(); ?>
+ </div>
+ <?php
+ else :
+ ?>
+ <?php get_search_form(); ?>
+ <?php endif; ?>
+
+ <nav id="access" role="navigation">
+ <h3 class="assistive-text"><?php _e( 'Main menu', 'twentyeleven' ); ?></h3>
+ <?php /* Allow screen readers / text browsers to skip the navigation menu and get right to the good stuff. */ ?>
+ <div class="skip-link"><a class="assistive-text" href="#content" title="<?php esc_attr_e( 'Skip to primary content', 'twentyeleven' ); ?>"><?php _e( 'Skip to primary content', 'twentyeleven' ); ?></a></div>
+ <div class="skip-link"><a class="assistive-text" href="#secondary" title="<?php esc_attr_e( 'Skip to secondary content', 'twentyeleven' ); ?>"><?php _e( 'Skip to secondary content', 'twentyeleven' ); ?></a></div>
+ <?php /* Our navigation menu. If one isn't filled out, wp_nav_menu falls back to wp_page_menu. The menu assigned to the primary location is the one used. If one isn't assigned, the menu with the lowest ID is used. */ ?>
+ <?php wp_nav_menu( array( 'theme_location' => 'primary' ) ); ?>
+ </nav><!-- #access -->
+ </header><!-- #branding -->
+
+
+ <div id="main">
diff --git a/src/wp-content/themes/twentyeleven/image.php b/src/wp-content/themes/twentyeleven/image.php
new file mode 100644
index 0000000000..3db208ef36
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/image.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * The template for displaying image attachments.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="image-attachment">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <nav id="nav-single">
+ <h3 class="assistive-text"><?php _e( 'Image navigation', 'twentyeleven' ); ?></h3>
+ <span class="nav-previous"><?php previous_image_link( false, __( '&larr; Previous' , 'twentyeleven' ) ); ?></span>
+ <span class="nav-next"><?php next_image_link( false, __( 'Next &rarr;' , 'twentyeleven' ) ); ?></span>
+ </nav><!-- #nav-single -->
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+
+ <div class="entry-meta">
+ <?php
+ $metadata = wp_get_attachment_metadata();
+ printf( __( '<span class="meta-prep meta-prep-entry-date">Published </span> <span class="entry-date"><abbr class="published" title="%1$s">%2$s</abbr></span> at <a href="%3$s" title="Link to full-size image">%4$s &times; %5$s</a> in <a href="%6$s" title="Return to %7$s" rel="gallery">%8$s</a>', 'twentyeleven' ),
+ esc_attr( get_the_time() ),
+ get_the_date(),
+ esc_url( wp_get_attachment_url() ),
+ $metadata['width'],
+ $metadata['height'],
+ esc_url( get_permalink( $post->post_parent ) ),
+ esc_attr( strip_tags( get_the_title( $post->post_parent ) ) ),
+ get_the_title( $post->post_parent )
+ );
+ ?>
+ <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+
+ <div class="entry-attachment">
+ <div class="attachment">
+<?php
+ /**
+ * Grab the IDs of all the image attachments in a gallery so we can get the URL of the next adjacent image in a gallery,
+ * or the first image (if we're looking at the last image in a gallery), or, in a gallery of one, just the link to that image file
+ */
+ $attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) );
+ foreach ( $attachments as $k => $attachment ) {
+ if ( $attachment->ID == $post->ID )
+ break;
+ }
+ $k++;
+ // If there is more than 1 attachment in a gallery
+ if ( count( $attachments ) > 1 ) {
+ if ( isset( $attachments[ $k ] ) )
+ // get the URL of the next image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ $k ]->ID );
+ else
+ // or get the URL of the first image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ 0 ]->ID );
+ } else {
+ // or, if there's only 1 image, get the URL of the image
+ $next_attachment_url = wp_get_attachment_url();
+ }
+?>
+ <a href="<?php echo esc_url( $next_attachment_url ); ?>" title="<?php the_title_attribute(); ?>" rel="attachment"><?php
+ $attachment_size = apply_filters( 'twentyeleven_attachment_size', 848 );
+ echo wp_get_attachment_image( $post->ID, array( $attachment_size, 1024 ) ); // filterable image width with 1024px limit for image height.
+ ?></a>
+
+ <?php if ( ! empty( $post->post_excerpt ) ) : ?>
+ <div class="entry-caption">
+ <?php the_excerpt(); ?>
+ </div>
+ <?php endif; ?>
+ </div><!-- .attachment -->
+
+ </div><!-- .entry-attachment -->
+
+ <div class="entry-description">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'twentyeleven' ) . '</span>', 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-description -->
+
+ </div><!-- .entry-content -->
+
+ </article><!-- #post-<?php the_ID(); ?> -->
+
+ <?php comments_template(); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark-rtl.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark-rtl.png
new file mode 100644
index 0000000000..46dac85bb9
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark-rtl.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark.png
new file mode 100644
index 0000000000..e32e285a61
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-dark.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-rtl.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-rtl.png
new file mode 100644
index 0000000000..9ae83f08de
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor-rtl.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor.png
new file mode 100644
index 0000000000..bf9d3d92d6
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-bypostauthor.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-dark-rtl.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-dark-rtl.png
new file mode 100644
index 0000000000..3644fdde2b
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-dark-rtl.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-dark.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-dark.png
new file mode 100644
index 0000000000..f9b624be92
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-dark.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow-rtl.png b/src/wp-content/themes/twentyeleven/images/comment-arrow-rtl.png
new file mode 100644
index 0000000000..e3fb1fddb2
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow-rtl.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-arrow.png b/src/wp-content/themes/twentyeleven/images/comment-arrow.png
new file mode 100644
index 0000000000..60a6d5d96f
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-arrow.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-bubble-dark-rtl.png b/src/wp-content/themes/twentyeleven/images/comment-bubble-dark-rtl.png
new file mode 100644
index 0000000000..f8c5061eb8
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-bubble-dark-rtl.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-bubble-dark.png b/src/wp-content/themes/twentyeleven/images/comment-bubble-dark.png
new file mode 100644
index 0000000000..2d1ca1a269
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-bubble-dark.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-bubble-rtl.png b/src/wp-content/themes/twentyeleven/images/comment-bubble-rtl.png
new file mode 100644
index 0000000000..55ff63fbbe
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-bubble-rtl.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/comment-bubble.png b/src/wp-content/themes/twentyeleven/images/comment-bubble.png
new file mode 100644
index 0000000000..1798846a5a
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/comment-bubble.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg
new file mode 100644
index 0000000000..e8c84d3f4d
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg b/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg
new file mode 100644
index 0000000000..831961fff5
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg
new file mode 100644
index 0000000000..9fc963f59b
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg b/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg
new file mode 100644
index 0000000000..5b0fa3fb87
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg
new file mode 100644
index 0000000000..3790f96caa
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg b/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg
new file mode 100644
index 0000000000..f71ce8f8cd
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg
new file mode 100644
index 0000000000..248fe00a14
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg b/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg
new file mode 100644
index 0000000000..e55ce97f1d
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg
new file mode 100644
index 0000000000..5e5e740e9b
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/shore.jpg b/src/wp-content/themes/twentyeleven/images/headers/shore.jpg
new file mode 100644
index 0000000000..71a8c54fed
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/shore.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg
new file mode 100644
index 0000000000..d2ee200088
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg b/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg
new file mode 100644
index 0000000000..110a764e5b
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg
new file mode 100644
index 0000000000..d7fa971358
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg b/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg
new file mode 100644
index 0000000000..c5b98789a8
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg
new file mode 100644
index 0000000000..240fff8a16
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/willow.jpg b/src/wp-content/themes/twentyeleven/images/headers/willow.jpg
new file mode 100644
index 0000000000..e867cc43df
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/headers/willow.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/search.png b/src/wp-content/themes/twentyeleven/images/search.png
new file mode 100644
index 0000000000..5036704b95
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/search.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/images/wordpress.png b/src/wp-content/themes/twentyeleven/images/wordpress.png
new file mode 100644
index 0000000000..4a15056adb
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/images/wordpress.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/inc/images/content-sidebar.png b/src/wp-content/themes/twentyeleven/inc/images/content-sidebar.png
new file mode 100644
index 0000000000..25ca6cb2ec
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/images/content-sidebar.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/inc/images/content.png b/src/wp-content/themes/twentyeleven/inc/images/content.png
new file mode 100644
index 0000000000..301a2946b3
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/images/content.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/inc/images/dark.png b/src/wp-content/themes/twentyeleven/inc/images/dark.png
new file mode 100644
index 0000000000..76b8dad493
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/images/dark.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/inc/images/light.png b/src/wp-content/themes/twentyeleven/inc/images/light.png
new file mode 100644
index 0000000000..42d8925a34
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/images/light.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/inc/images/sidebar-content.png b/src/wp-content/themes/twentyeleven/inc/images/sidebar-content.png
new file mode 100644
index 0000000000..579b9fdbcd
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/images/sidebar-content.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/inc/theme-customizer.js b/src/wp-content/themes/twentyeleven/inc/theme-customizer.js
new file mode 100644
index 0000000000..ea19f49932
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/theme-customizer.js
@@ -0,0 +1,12 @@
+( function( $ ){
+ wp.customize( 'blogname', function( value ) {
+ value.bind( function( to ) {
+ $( '#site-title a' ).text( to );
+ } );
+ } );
+ wp.customize( 'blogdescription', function( value ) {
+ value.bind( function( to ) {
+ $( '#site-description' ).text( to );
+ } );
+ } );
+} )( jQuery ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/inc/theme-options.css b/src/wp-content/themes/twentyeleven/inc/theme-options.css
new file mode 100644
index 0000000000..464ab8c465
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/theme-options.css
@@ -0,0 +1,35 @@
+#wpcontent select option {
+ padding-right: 5px;
+}
+.image-radio-option td {
+ padding-top: 15px;
+}
+.image-radio-option label {
+ display: block;
+ float: left;
+ margin: 0 30px 20px 2px;
+ position: relative;
+}
+.image-radio-option input {
+ margin: 0 0 10px;
+}
+.image-radio-option span {
+ display: block;
+ width: 136px;
+}
+.image-radio-option img {
+ margin: 0 0 0 -2px;
+}
+#link-color-example {
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ border: 1px solid #dfdfdf;
+ margin: 0 7px 0 3px;
+ padding: 4px 14px;
+}
+
+body.rtl .image-radio-option label {
+ float: right;
+ margin: 0 2px 20px 30px;
+}
diff --git a/src/wp-content/themes/twentyeleven/inc/theme-options.js b/src/wp-content/themes/twentyeleven/inc/theme-options.js
new file mode 100644
index 0000000000..4cfaec1512
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/theme-options.js
@@ -0,0 +1,52 @@
+var farbtastic;
+
+(function($){
+ var pickColor = function(a) {
+ farbtastic.setColor(a);
+ $('#link-color').val(a);
+ $('#link-color-example').css('background-color', a);
+ };
+
+ $(document).ready( function() {
+ $('#default-color').wrapInner('<a href="#" />');
+
+ farbtastic = $.farbtastic('#colorPickerDiv', pickColor);
+
+ pickColor( $('#link-color').val() );
+
+ $('.pickcolor').click( function(e) {
+ $('#colorPickerDiv').show();
+ e.preventDefault();
+ });
+
+ $('#link-color').keyup( function() {
+ var a = $('#link-color').val(),
+ b = a;
+
+ a = a.replace(/[^a-fA-F0-9]/, '');
+ if ( '#' + a !== b )
+ $('#link-color').val(a);
+ if ( a.length === 3 || a.length === 6 )
+ pickColor( '#' + a );
+ });
+
+ $(document).mousedown( function() {
+ $('#colorPickerDiv').hide();
+ });
+
+ $('#default-color a').click( function(e) {
+ pickColor( '#' + this.innerHTML.replace(/[^a-fA-F0-9]/, '') );
+ e.preventDefault();
+ });
+
+ $('.image-radio-option.color-scheme input:radio').change( function() {
+ var currentDefault = $('#default-color a'),
+ newDefault = $(this).next().val();
+
+ if ( $('#link-color').val() == currentDefault.text() )
+ pickColor( newDefault );
+
+ currentDefault.text( newDefault );
+ });
+ });
+})(jQuery); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/inc/theme-options.php b/src/wp-content/themes/twentyeleven/inc/theme-options.php
new file mode 100644
index 0000000000..698f2a0b5e
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/theme-options.php
@@ -0,0 +1,531 @@
+<?php
+/**
+ * Twenty Eleven Theme Options
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+/**
+ * Properly enqueue styles and scripts for our theme options page.
+ *
+ * This function is attached to the admin_enqueue_scripts action hook.
+ *
+ * @since Twenty Eleven 1.0
+ *
+ */
+function twentyeleven_admin_enqueue_scripts( $hook_suffix ) {
+ wp_enqueue_style( 'twentyeleven-theme-options', get_template_directory_uri() . '/inc/theme-options.css', false, '2011-04-28' );
+ wp_enqueue_script( 'twentyeleven-theme-options', get_template_directory_uri() . '/inc/theme-options.js', array( 'farbtastic' ), '2011-06-10' );
+ wp_enqueue_style( 'farbtastic' );
+}
+add_action( 'admin_print_styles-appearance_page_theme_options', 'twentyeleven_admin_enqueue_scripts' );
+
+/**
+ * Register the form setting for our twentyeleven_options array.
+ *
+ * This function is attached to the admin_init action hook.
+ *
+ * This call to register_setting() registers a validation callback, twentyeleven_theme_options_validate(),
+ * which is used when the option is saved, to ensure that our option values are complete, properly
+ * formatted, and safe.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_theme_options_init() {
+
+ register_setting(
+ 'twentyeleven_options', // Options group, see settings_fields() call in twentyeleven_theme_options_render_page()
+ 'twentyeleven_theme_options', // Database option, see twentyeleven_get_theme_options()
+ 'twentyeleven_theme_options_validate' // The sanitization callback, see twentyeleven_theme_options_validate()
+ );
+
+ // Register our settings field group
+ add_settings_section(
+ 'general', // Unique identifier for the settings section
+ '', // Section title (we don't want one)
+ '__return_false', // Section callback (we don't want anything)
+ 'theme_options' // Menu slug, used to uniquely identify the page; see twentyeleven_theme_options_add_page()
+ );
+
+ // Register our individual settings fields
+ add_settings_field(
+ 'color_scheme', // Unique identifier for the field for this section
+ __( 'Color Scheme', 'twentyeleven' ), // Setting field label
+ 'twentyeleven_settings_field_color_scheme', // Function that renders the settings field
+ 'theme_options', // Menu slug, used to uniquely identify the page; see twentyeleven_theme_options_add_page()
+ 'general' // Settings section. Same as the first argument in the add_settings_section() above
+ );
+
+ add_settings_field( 'link_color', __( 'Link Color', 'twentyeleven' ), 'twentyeleven_settings_field_link_color', 'theme_options', 'general' );
+ add_settings_field( 'layout', __( 'Default Layout', 'twentyeleven' ), 'twentyeleven_settings_field_layout', 'theme_options', 'general' );
+}
+add_action( 'admin_init', 'twentyeleven_theme_options_init' );
+
+/**
+ * Change the capability required to save the 'twentyeleven_options' options group.
+ *
+ * @see twentyeleven_theme_options_init() First parameter to register_setting() is the name of the options group.
+ * @see twentyeleven_theme_options_add_page() The edit_theme_options capability is used for viewing the page.
+ *
+ * By default, the options groups for all registered settings require the manage_options capability.
+ * This filter is required to change our theme options page to edit_theme_options instead.
+ * By default, only administrators have either of these capabilities, but the desire here is
+ * to allow for finer-grained control for roles and users.
+ *
+ * @param string $capability The capability used for the page, which is manage_options by default.
+ * @return string The capability to actually use.
+ */
+function twentyeleven_option_page_capability( $capability ) {
+ return 'edit_theme_options';
+}
+add_filter( 'option_page_capability_twentyeleven_options', 'twentyeleven_option_page_capability' );
+
+/**
+ * Add our theme options page to the admin menu, including some help documentation.
+ *
+ * This function is attached to the admin_menu action hook.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_theme_options_add_page() {
+ $theme_page = add_theme_page(
+ __( 'Theme Options', 'twentyeleven' ), // Name of page
+ __( 'Theme Options', 'twentyeleven' ), // Label in menu
+ 'edit_theme_options', // Capability required
+ 'theme_options', // Menu slug, used to uniquely identify the page
+ 'twentyeleven_theme_options_render_page' // Function that renders the options page
+ );
+
+ if ( ! $theme_page )
+ return;
+
+ add_action( "load-$theme_page", 'twentyeleven_theme_options_help' );
+}
+add_action( 'admin_menu', 'twentyeleven_theme_options_add_page' );
+
+function twentyeleven_theme_options_help() {
+
+ $help = '<p>' . __( 'Some themes provide customization options that are grouped together on a Theme Options screen. If you change themes, options may change or disappear, as they are theme-specific. Your current theme, Twenty Eleven, provides the following Theme Options:', 'twentyeleven' ) . '</p>' .
+ '<ol>' .
+ '<li>' . __( '<strong>Color Scheme</strong>: You can choose a color palette of "Light" (light background with dark text) or "Dark" (dark background with light text) for your site.', 'twentyeleven' ) . '</li>' .
+ '<li>' . __( '<strong>Link Color</strong>: You can choose the color used for text links on your site. You can enter the HTML color or hex code, or you can choose visually by clicking the "Select a Color" button to pick from a color wheel.', 'twentyeleven' ) . '</li>' .
+ '<li>' . __( '<strong>Default Layout</strong>: You can choose if you want your site&#8217;s default layout to have a sidebar on the left, the right, or not at all.', 'twentyeleven' ) . '</li>' .
+ '</ol>' .
+ '<p>' . __( 'Remember to click "Save Changes" to save any changes you have made to the theme options.', 'twentyeleven' ) . '</p>';
+
+ $sidebar = '<p><strong>' . __( 'For more information:', 'twentyeleven' ) . '</strong></p>' .
+ '<p>' . __( '<a href="http://codex.wordpress.org/Appearance_Theme_Options_Screen" target="_blank">Documentation on Theme Options</a>', 'twentyeleven' ) . '</p>' .
+ '<p>' . __( '<a href="http://wordpress.org/support/" target="_blank">Support Forums</a>', 'twentyeleven' ) . '</p>';
+
+ $screen = get_current_screen();
+
+ if ( method_exists( $screen, 'add_help_tab' ) ) {
+ // WordPress 3.3
+ $screen->add_help_tab( array(
+ 'title' => __( 'Overview', 'twentyeleven' ),
+ 'id' => 'theme-options-help',
+ 'content' => $help,
+ )
+ );
+
+ $screen->set_help_sidebar( $sidebar );
+ } else {
+ // WordPress 3.2
+ add_contextual_help( $screen, $help . $sidebar );
+ }
+}
+
+/**
+ * Returns an array of color schemes registered for Twenty Eleven.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_color_schemes() {
+ $color_scheme_options = array(
+ 'light' => array(
+ 'value' => 'light',
+ 'label' => __( 'Light', 'twentyeleven' ),
+ 'thumbnail' => get_template_directory_uri() . '/inc/images/light.png',
+ 'default_link_color' => '#1b8be0',
+ ),
+ 'dark' => array(
+ 'value' => 'dark',
+ 'label' => __( 'Dark', 'twentyeleven' ),
+ 'thumbnail' => get_template_directory_uri() . '/inc/images/dark.png',
+ 'default_link_color' => '#e4741f',
+ ),
+ );
+
+ return apply_filters( 'twentyeleven_color_schemes', $color_scheme_options );
+}
+
+/**
+ * Returns an array of layout options registered for Twenty Eleven.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_layouts() {
+ $layout_options = array(
+ 'content-sidebar' => array(
+ 'value' => 'content-sidebar',
+ 'label' => __( 'Content on left', 'twentyeleven' ),
+ 'thumbnail' => get_template_directory_uri() . '/inc/images/content-sidebar.png',
+ ),
+ 'sidebar-content' => array(
+ 'value' => 'sidebar-content',
+ 'label' => __( 'Content on right', 'twentyeleven' ),
+ 'thumbnail' => get_template_directory_uri() . '/inc/images/sidebar-content.png',
+ ),
+ 'content' => array(
+ 'value' => 'content',
+ 'label' => __( 'One-column, no sidebar', 'twentyeleven' ),
+ 'thumbnail' => get_template_directory_uri() . '/inc/images/content.png',
+ ),
+ );
+
+ return apply_filters( 'twentyeleven_layouts', $layout_options );
+}
+
+/**
+ * Returns the default options for Twenty Eleven.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_get_default_theme_options() {
+ $default_theme_options = array(
+ 'color_scheme' => 'light',
+ 'link_color' => twentyeleven_get_default_link_color( 'light' ),
+ 'theme_layout' => 'content-sidebar',
+ );
+
+ if ( is_rtl() )
+ $default_theme_options['theme_layout'] = 'sidebar-content';
+
+ return apply_filters( 'twentyeleven_default_theme_options', $default_theme_options );
+}
+
+/**
+ * Returns the default link color for Twenty Eleven, based on color scheme.
+ *
+ * @since Twenty Eleven 1.0
+ *
+ * @param $string $color_scheme Color scheme. Defaults to the active color scheme.
+ * @return $string Color.
+*/
+function twentyeleven_get_default_link_color( $color_scheme = null ) {
+ if ( null === $color_scheme ) {
+ $options = twentyeleven_get_theme_options();
+ $color_scheme = $options['color_scheme'];
+ }
+
+ $color_schemes = twentyeleven_color_schemes();
+ if ( ! isset( $color_schemes[ $color_scheme ] ) )
+ return false;
+
+ return $color_schemes[ $color_scheme ]['default_link_color'];
+}
+
+/**
+ * Returns the options array for Twenty Eleven.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_get_theme_options() {
+ return get_option( 'twentyeleven_theme_options', twentyeleven_get_default_theme_options() );
+}
+
+/**
+ * Renders the Color Scheme setting field.
+ *
+ * @since Twenty Eleven 1.3
+ */
+function twentyeleven_settings_field_color_scheme() {
+ $options = twentyeleven_get_theme_options();
+
+ foreach ( twentyeleven_color_schemes() as $scheme ) {
+ ?>
+ <div class="layout image-radio-option color-scheme">
+ <label class="description">
+ <input type="radio" name="twentyeleven_theme_options[color_scheme]" value="<?php echo esc_attr( $scheme['value'] ); ?>" <?php checked( $options['color_scheme'], $scheme['value'] ); ?> />
+ <input type="hidden" id="default-color-<?php echo esc_attr( $scheme['value'] ); ?>" value="<?php echo esc_attr( $scheme['default_link_color'] ); ?>" />
+ <span>
+ <img src="<?php echo esc_url( $scheme['thumbnail'] ); ?>" width="136" height="122" alt="" />
+ <?php echo $scheme['label']; ?>
+ </span>
+ </label>
+ </div>
+ <?php
+ }
+}
+
+/**
+ * Renders the Link Color setting field.
+ *
+ * @since Twenty Eleven 1.3
+ */
+function twentyeleven_settings_field_link_color() {
+ $options = twentyeleven_get_theme_options();
+ ?>
+ <input type="text" name="twentyeleven_theme_options[link_color]" id="link-color" value="<?php echo esc_attr( $options['link_color'] ); ?>" />
+ <a href="#" class="pickcolor hide-if-no-js" id="link-color-example"></a>
+ <input type="button" class="pickcolor button hide-if-no-js" value="<?php esc_attr_e( 'Select a Color', 'twentyeleven' ); ?>" />
+ <div id="colorPickerDiv" style="z-index: 100; background:#eee; border:1px solid #ccc; position:absolute; display:none;"></div>
+ <br />
+ <span><?php printf( __( 'Default color: %s', 'twentyeleven' ), '<span id="default-color">' . twentyeleven_get_default_link_color( $options['color_scheme'] ) . '</span>' ); ?></span>
+ <?php
+}
+
+/**
+ * Renders the Layout setting field.
+ *
+ * @since Twenty Eleven 1.3
+ */
+function twentyeleven_settings_field_layout() {
+ $options = twentyeleven_get_theme_options();
+ foreach ( twentyeleven_layouts() as $layout ) {
+ ?>
+ <div class="layout image-radio-option theme-layout">
+ <label class="description">
+ <input type="radio" name="twentyeleven_theme_options[theme_layout]" value="<?php echo esc_attr( $layout['value'] ); ?>" <?php checked( $options['theme_layout'], $layout['value'] ); ?> />
+ <span>
+ <img src="<?php echo esc_url( $layout['thumbnail'] ); ?>" width="136" height="122" alt="" />
+ <?php echo $layout['label']; ?>
+ </span>
+ </label>
+ </div>
+ <?php
+ }
+}
+
+/**
+ * Returns the options array for Twenty Eleven.
+ *
+ * @since Twenty Eleven 1.2
+ */
+function twentyeleven_theme_options_render_page() {
+ ?>
+ <div class="wrap">
+ <?php screen_icon(); ?>
+ <?php $theme_name = function_exists( 'wp_get_theme' ) ? wp_get_theme() : get_current_theme(); ?>
+ <h2><?php printf( __( '%s Theme Options', 'twentyeleven' ), $theme_name ); ?></h2>
+ <?php settings_errors(); ?>
+
+ <form method="post" action="options.php">
+ <?php
+ settings_fields( 'twentyeleven_options' );
+ do_settings_sections( 'theme_options' );
+ submit_button();
+ ?>
+ </form>
+ </div>
+ <?php
+}
+
+/**
+ * Sanitize and validate form input. Accepts an array, return a sanitized array.
+ *
+ * @see twentyeleven_theme_options_init()
+ * @todo set up Reset Options action
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_theme_options_validate( $input ) {
+ $output = $defaults = twentyeleven_get_default_theme_options();
+
+ // Color scheme must be in our array of color scheme options
+ if ( isset( $input['color_scheme'] ) && array_key_exists( $input['color_scheme'], twentyeleven_color_schemes() ) )
+ $output['color_scheme'] = $input['color_scheme'];
+
+ // Our defaults for the link color may have changed, based on the color scheme.
+ $output['link_color'] = $defaults['link_color'] = twentyeleven_get_default_link_color( $output['color_scheme'] );
+
+ // Link color must be 3 or 6 hexadecimal characters
+ if ( isset( $input['link_color'] ) && preg_match( '/^#?([a-f0-9]{3}){1,2}$/i', $input['link_color'] ) )
+ $output['link_color'] = '#' . strtolower( ltrim( $input['link_color'], '#' ) );
+
+ // Theme layout must be in our array of theme layout options
+ if ( isset( $input['theme_layout'] ) && array_key_exists( $input['theme_layout'], twentyeleven_layouts() ) )
+ $output['theme_layout'] = $input['theme_layout'];
+
+ return apply_filters( 'twentyeleven_theme_options_validate', $output, $input, $defaults );
+}
+
+/**
+ * Enqueue the styles for the current color scheme.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_enqueue_color_scheme() {
+ $options = twentyeleven_get_theme_options();
+ $color_scheme = $options['color_scheme'];
+
+ if ( 'dark' == $color_scheme )
+ wp_enqueue_style( 'dark', get_template_directory_uri() . '/colors/dark.css', array(), null );
+
+ do_action( 'twentyeleven_enqueue_color_scheme', $color_scheme );
+}
+add_action( 'wp_enqueue_scripts', 'twentyeleven_enqueue_color_scheme' );
+
+/**
+ * Add a style block to the theme for the current link color.
+ *
+ * This function is attached to the wp_head action hook.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_print_link_color_style() {
+ $options = twentyeleven_get_theme_options();
+ $link_color = $options['link_color'];
+
+ $default_options = twentyeleven_get_default_theme_options();
+
+ // Don't do anything if the current link color is the default.
+ if ( $default_options['link_color'] == $link_color )
+ return;
+?>
+ <style>
+ /* Link color */
+ a,
+ #site-title a:focus,
+ #site-title a:hover,
+ #site-title a:active,
+ .entry-title a:hover,
+ .entry-title a:focus,
+ .entry-title a:active,
+ .widget_twentyeleven_ephemera .comments-link a:hover,
+ section.recent-posts .other-recent-posts a[rel="bookmark"]:hover,
+ section.recent-posts .other-recent-posts .comments-link a:hover,
+ .format-image footer.entry-meta a:hover,
+ #site-generator a:hover {
+ color: <?php echo $link_color; ?>;
+ }
+ section.recent-posts .other-recent-posts .comments-link a:hover {
+ border-color: <?php echo $link_color; ?>;
+ }
+ article.feature-image.small .entry-summary p a:hover,
+ .entry-header .comments-link a:hover,
+ .entry-header .comments-link a:focus,
+ .entry-header .comments-link a:active,
+ .feature-slider a.active {
+ background-color: <?php echo $link_color; ?>;
+ }
+ </style>
+<?php
+}
+add_action( 'wp_head', 'twentyeleven_print_link_color_style' );
+
+/**
+ * Adds Twenty Eleven layout classes to the array of body classes.
+ *
+ * @since Twenty Eleven 1.0
+ */
+function twentyeleven_layout_classes( $existing_classes ) {
+ $options = twentyeleven_get_theme_options();
+ $current_layout = $options['theme_layout'];
+
+ if ( in_array( $current_layout, array( 'content-sidebar', 'sidebar-content' ) ) )
+ $classes = array( 'two-column' );
+ else
+ $classes = array( 'one-column' );
+
+ if ( 'content-sidebar' == $current_layout )
+ $classes[] = 'right-sidebar';
+ elseif ( 'sidebar-content' == $current_layout )
+ $classes[] = 'left-sidebar';
+ else
+ $classes[] = $current_layout;
+
+ $classes = apply_filters( 'twentyeleven_layout_classes', $classes, $current_layout );
+
+ return array_merge( $existing_classes, $classes );
+}
+add_filter( 'body_class', 'twentyeleven_layout_classes' );
+
+/**
+ * Implements Twenty Eleven theme options into Theme Customizer
+ *
+ * @param $wp_customize Theme Customizer object
+ * @return void
+ *
+ * @since Twenty Eleven 1.3
+ */
+function twentyeleven_customize_register( $wp_customize ) {
+ $wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
+ $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
+
+ $options = twentyeleven_get_theme_options();
+ $defaults = twentyeleven_get_default_theme_options();
+
+ $wp_customize->add_setting( 'twentyeleven_theme_options[color_scheme]', array(
+ 'default' => $defaults['color_scheme'],
+ 'type' => 'option',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $schemes = twentyeleven_color_schemes();
+ $choices = array();
+ foreach ( $schemes as $scheme ) {
+ $choices[ $scheme['value'] ] = $scheme['label'];
+ }
+
+ $wp_customize->add_control( 'twentyeleven_color_scheme', array(
+ 'label' => __( 'Color Scheme', 'twentyeleven' ),
+ 'section' => 'colors',
+ 'settings' => 'twentyeleven_theme_options[color_scheme]',
+ 'type' => 'radio',
+ 'choices' => $choices,
+ 'priority' => 5,
+ ) );
+
+ // Link Color (added to Color Scheme section in Theme Customizer)
+ $wp_customize->add_setting( 'twentyeleven_theme_options[link_color]', array(
+ 'default' => twentyeleven_get_default_link_color( $options['color_scheme'] ),
+ 'type' => 'option',
+ 'sanitize_callback' => 'sanitize_hex_color',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'link_color', array(
+ 'label' => __( 'Link Color', 'twentyeleven' ),
+ 'section' => 'colors',
+ 'settings' => 'twentyeleven_theme_options[link_color]',
+ ) ) );
+
+ // Default Layout
+ $wp_customize->add_section( 'twentyeleven_layout', array(
+ 'title' => __( 'Layout', 'twentyeleven' ),
+ 'priority' => 50,
+ ) );
+
+ $wp_customize->add_setting( 'twentyeleven_theme_options[theme_layout]', array(
+ 'type' => 'option',
+ 'default' => $defaults['theme_layout'],
+ 'sanitize_callback' => 'sanitize_key',
+ ) );
+
+ $layouts = twentyeleven_layouts();
+ $choices = array();
+ foreach ( $layouts as $layout ) {
+ $choices[$layout['value']] = $layout['label'];
+ }
+
+ $wp_customize->add_control( 'twentyeleven_theme_options[theme_layout]', array(
+ 'section' => 'twentyeleven_layout',
+ 'type' => 'radio',
+ 'choices' => $choices,
+ ) );
+}
+add_action( 'customize_register', 'twentyeleven_customize_register' );
+
+/**
+ * Bind JS handlers to make Theme Customizer preview reload changes asynchronously.
+ * Used with blogname and blogdescription.
+ *
+ * @since Twenty Eleven 1.3
+ */
+function twentyeleven_customize_preview_js() {
+ wp_enqueue_script( 'twentyeleven-customizer', get_template_directory_uri() . '/inc/theme-customizer.js', array( 'customize-preview' ), '20120523', true );
+}
+add_action( 'customize_preview_init', 'twentyeleven_customize_preview_js' ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/inc/widgets.php b/src/wp-content/themes/twentyeleven/inc/widgets.php
new file mode 100644
index 0000000000..2571274f6c
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/inc/widgets.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * Makes a custom Widget for displaying Aside, Link, Status, and Quote Posts available with Twenty Eleven
+ *
+ * Learn more: http://codex.wordpress.org/Widgets_API#Developing_Widgets
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+class Twenty_Eleven_Ephemera_Widget extends WP_Widget {
+
+ /**
+ * Constructor
+ *
+ * @return void
+ **/
+ function Twenty_Eleven_Ephemera_Widget() {
+ $widget_ops = array( 'classname' => 'widget_twentyeleven_ephemera', 'description' => __( 'Use this widget to list your recent Aside, Status, Quote, and Link posts', 'twentyeleven' ) );
+ $this->WP_Widget( 'widget_twentyeleven_ephemera', __( 'Twenty Eleven Ephemera', 'twentyeleven' ), $widget_ops );
+ $this->alt_option_name = 'widget_twentyeleven_ephemera';
+
+ add_action( 'save_post', array(&$this, 'flush_widget_cache' ) );
+ add_action( 'deleted_post', array(&$this, 'flush_widget_cache' ) );
+ add_action( 'switch_theme', array(&$this, 'flush_widget_cache' ) );
+ }
+
+ /**
+ * Outputs the HTML for this widget.
+ *
+ * @param array An array of standard parameters for widgets in this theme
+ * @param array An array of settings for this widget instance
+ * @return void Echoes its output
+ **/
+ function widget( $args, $instance ) {
+ $cache = wp_cache_get( 'widget_twentyeleven_ephemera', 'widget' );
+
+ if ( !is_array( $cache ) )
+ $cache = array();
+
+ if ( ! isset( $args['widget_id'] ) )
+ $args['widget_id'] = null;
+
+ if ( isset( $cache[$args['widget_id']] ) ) {
+ echo $cache[$args['widget_id']];
+ return;
+ }
+
+ ob_start();
+ extract( $args, EXTR_SKIP );
+
+ $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? __( 'Ephemera', 'twentyeleven' ) : $instance['title'], $instance, $this->id_base);
+
+ if ( ! isset( $instance['number'] ) )
+ $instance['number'] = '10';
+
+ if ( ! $number = absint( $instance['number'] ) )
+ $number = 10;
+
+ $ephemera_args = array(
+ 'order' => 'DESC',
+ 'posts_per_page' => $number,
+ 'no_found_rows' => true,
+ 'post_status' => 'publish',
+ 'post__not_in' => get_option( 'sticky_posts' ),
+ 'tax_query' => array(
+ array(
+ 'taxonomy' => 'post_format',
+ 'terms' => array( 'post-format-aside', 'post-format-link', 'post-format-status', 'post-format-quote' ),
+ 'field' => 'slug',
+ 'operator' => 'IN',
+ ),
+ ),
+ );
+ $ephemera = new WP_Query( $ephemera_args );
+
+ if ( $ephemera->have_posts() ) :
+ echo $before_widget;
+ echo $before_title;
+ echo $title; // Can set this with a widget option, or omit altogether
+ echo $after_title;
+ ?>
+ <ol>
+ <?php while ( $ephemera->have_posts() ) : $ephemera->the_post(); ?>
+
+ <?php if ( 'link' != get_post_format() ) : ?>
+
+ <li class="widget-entry-title">
+ <a href="<?php echo esc_url( get_permalink() ); ?>" rel="bookmark"><?php the_title(); ?></a>
+ <span class="comments-link">
+ <?php comments_popup_link( __( '0 <span class="reply">comments &rarr;</span>', 'twentyeleven' ), __( '1 <span class="reply">comment &rarr;</span>', 'twentyeleven' ), __( '% <span class="reply">comments &rarr;</span>', 'twentyeleven' ) ); ?>
+ </span>
+ </li>
+
+ <?php else : ?>
+
+ <li class="widget-entry-title">
+ <a href="<?php echo esc_url( twentyeleven_get_first_url() ); ?>" rel="bookmark"><?php the_title(); ?>&nbsp;<span>&rarr;</span></a>
+ <span class="comments-link">
+ <?php comments_popup_link( __( '0 <span class="reply">comments &rarr;</span>', 'twentyeleven' ), __( '1 <span class="reply">comment &rarr;</span>', 'twentyeleven' ), __( '% <span class="reply">comments &rarr;</span>', 'twentyeleven' ) ); ?>
+ </span>
+ </li>
+
+ <?php endif; ?>
+
+ <?php endwhile; ?>
+ </ol>
+ <?php
+
+ echo $after_widget;
+
+ // Reset the post globals as this query will have stomped on it
+ wp_reset_postdata();
+
+ // end check for ephemeral posts
+ endif;
+
+ $cache[$args['widget_id']] = ob_get_flush();
+ wp_cache_set( 'widget_twentyeleven_ephemera', $cache, 'widget' );
+ }
+
+ /**
+ * Deals with the settings when they are saved by the admin. Here is
+ * where any validation should be dealt with.
+ **/
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags( $new_instance['title'] );
+ $instance['number'] = (int) $new_instance['number'];
+ $this->flush_widget_cache();
+
+ $alloptions = wp_cache_get( 'alloptions', 'options' );
+ if ( isset( $alloptions['widget_twentyeleven_ephemera'] ) )
+ delete_option( 'widget_twentyeleven_ephemera' );
+
+ return $instance;
+ }
+
+ function flush_widget_cache() {
+ wp_cache_delete( 'widget_twentyeleven_ephemera', 'widget' );
+ }
+
+ /**
+ * Displays the form for this widget on the Widgets page of the WP Admin area.
+ **/
+ function form( $instance ) {
+ $title = isset( $instance['title']) ? esc_attr( $instance['title'] ) : '';
+ $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 10;
+?>
+ <p><label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php _e( 'Title:', 'twentyeleven' ); ?></label>
+ <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
+
+ <p><label for="<?php echo esc_attr( $this->get_field_id( 'number' ) ); ?>"><?php _e( 'Number of posts to show:', 'twentyeleven' ); ?></label>
+ <input id="<?php echo esc_attr( $this->get_field_id( 'number' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'number' ) ); ?>" type="text" value="<?php echo esc_attr( $number ); ?>" size="3" /></p>
+ <?php
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/index.php b/src/wp-content/themes/twentyeleven/index.php
new file mode 100644
index 0000000000..f955f34991
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/index.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * The main template file.
+ *
+ * This is the most generic template file in a WordPress theme
+ * and one of the two required files for a theme (the other being style.css).
+ * It is used to display a page when nothing more specific matches a query.
+ * E.g., it puts together the home page when no home.php file exists.
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ */
+
+get_header(); ?>
+
+ <div id="primary">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <?php twentyeleven_content_nav( 'nav-above' ); ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', get_post_format() ); ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyeleven_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyeleven' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/js/html5.js b/src/wp-content/themes/twentyeleven/js/html5.js
new file mode 100644
index 0000000000..fabcb85ec3
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/js/html5.js
@@ -0,0 +1,6 @@
+/*! HTML5 Shiv v3.6 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
+(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
+a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
+c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");
+var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,
+b){a||(a=f);if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/js/showcase.js b/src/wp-content/themes/twentyeleven/js/showcase.js
new file mode 100644
index 0000000000..d9fb2fedde
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/js/showcase.js
@@ -0,0 +1,17 @@
+(function($) {
+ $(document).ready( function() {
+ $('.feature-slider a').click(function(e) {
+ $('.featured-posts section.featured-post').css({
+ opacity: 0,
+ visibility: 'hidden'
+ });
+ $(this.hash).css({
+ opacity: 1,
+ visibility: 'visible'
+ });
+ $('.feature-slider a').removeClass('active');
+ $(this).addClass('active');
+ e.preventDefault();
+ });
+ });
+})(jQuery); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/languages/twentyeleven.pot b/src/wp-content/themes/twentyeleven/languages/twentyeleven.pot
new file mode 100644
index 0000000000..3ef69d7eb2
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/languages/twentyeleven.pot
@@ -0,0 +1,653 @@
+# Copyright (C) 2013 the WordPress team
+# This file is distributed under the GNU General Public License v2 or later.
+msgid ""
+msgstr ""
+"Project-Id-Version: Twenty Eleven 1.6\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tags/twentyeleven\n"
+"POT-Creation-Date: 2013-08-01 18:14:10+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: 404.php:17
+msgid "This is somewhat embarrassing, isn&rsquo;t it?"
+msgstr ""
+
+#: 404.php:21
+msgid ""
+"It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps "
+"searching, or one of the links below, can help."
+msgstr ""
+
+#: 404.php:28
+msgid "Most Used Categories"
+msgstr ""
+
+#. translators: %1$s: smilie
+#: 404.php:36
+msgid "Try looking in the monthly archives. %1$s"
+msgstr ""
+
+#: archive.php:25
+msgid "Daily Archives: %s"
+msgstr ""
+
+#: archive.php:27
+msgid "Monthly Archives: %s"
+msgstr ""
+
+#: archive.php:27
+msgctxt "monthly archives date format"
+msgid "F Y"
+msgstr ""
+
+#: archive.php:29
+msgid "Yearly Archives: %s"
+msgstr ""
+
+#: archive.php:29
+msgctxt "yearly archives date format"
+msgid "Y"
+msgstr ""
+
+#: archive.php:31
+msgid "Blog Archives"
+msgstr ""
+
+#: archive.php:57 author.php:74 category.php:50 index.php:37 search.php:42
+#: tag.php:50
+msgid "Nothing Found"
+msgstr ""
+
+#: archive.php:61 author.php:78 category.php:54 index.php:41 tag.php:54
+msgid ""
+"Apologies, but no results were found for the requested archive. Perhaps "
+"searching will help find a related post."
+msgstr ""
+
+#: author.php:28
+msgid "Author Archives: %s"
+msgstr ""
+
+#: author.php:49 content-single.php:60
+msgid "About %s"
+msgstr ""
+
+#: category.php:19
+msgid "Category Archives: %s"
+msgstr ""
+
+#: comments.php:17
+msgid ""
+"This post is password protected. Enter the password to view any comments."
+msgstr ""
+
+#: comments.php:33
+msgid "One thought on &ldquo;%2$s&rdquo;"
+msgid_plural "%1$s thoughts on &ldquo;%2$s&rdquo;"
+msgstr[0] ""
+msgstr[1] ""
+
+#: comments.php:40 comments.php:60
+msgid "Comment navigation"
+msgstr ""
+
+#: comments.php:41 comments.php:61
+msgid "&larr; Older Comments"
+msgstr ""
+
+#: comments.php:42 comments.php:62
+msgid "Newer Comments &rarr;"
+msgstr ""
+
+#: comments.php:71
+msgid "Comments are closed."
+msgstr ""
+
+#: content-aside.php:17
+msgid "Aside"
+msgstr ""
+
+#: content-aside.php:22 content-image.php:21 content-link.php:22
+#: content-quote.php:24 content-status.php:21 content.php:30
+msgid "Reply"
+msgstr ""
+
+#: content-aside.php:22 content-image.php:21 content-link.php:22
+#: content-quote.php:24 content-status.php:21 content.php:30
+msgctxt "comments number"
+msgid "1"
+msgstr ""
+
+#: content-aside.php:22 content-image.php:21 content-link.php:22
+#: content-quote.php:24 content-status.php:21 content.php:30
+msgctxt "comments number"
+msgid "%"
+msgstr ""
+
+#: content-aside.php:33 content-gallery.php:32 content-image.php:27
+#: content-link.php:33 content-quote.php:35 content-status.php:34
+#: content.php:41 functions.php:345
+msgid "Continue reading <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: content-aside.php:34 content-featured.php:23 content-gallery.php:50
+#: content-image.php:28 content-intro.php:18 content-link.php:34
+#: content-page.php:18 content-quote.php:36 content-single.php:24
+#: content-status.php:35 content.php:42 image.php:90
+msgid "Pages:"
+msgstr ""
+
+#: content-aside.php:42 content-gallery.php:83 content-image.php:64
+#: content-link.php:42 content-quote.php:69 content-status.php:43
+#: content.php:79 showcase.php:201
+msgid "Leave a reply"
+msgstr ""
+
+#: content-aside.php:42 content-gallery.php:83 content-image.php:64
+#: content-link.php:42 content-quote.php:69 content-status.php:43
+#: content.php:79 showcase.php:201
+msgid "<b>1</b> Reply"
+msgstr ""
+
+#: content-aside.php:42 content-gallery.php:83 content-image.php:64
+#: content-link.php:42 content-quote.php:69 content-status.php:43
+#: content.php:79 showcase.php:201
+msgid "<b>%</b> Replies"
+msgstr ""
+
+#: content-aside.php:44 content-featured.php:45 content-gallery.php:86
+#: content-image.php:68 content-intro.php:19 content-link.php:44
+#: content-page.php:21 content-quote.php:72 content-single.php:52
+#: content-status.php:45 content.php:82 functions.php:543 functions.php:571
+#: image.php:41
+msgid "Edit"
+msgstr ""
+
+#. translators: used between list items, there is a space after the comma
+#: content-featured.php:29 content-featured.php:38 content-gallery.php:58
+#: content-gallery.php:68 content-image.php:47 content-image.php:56
+#: content-quote.php:44 content-quote.php:54 content-single.php:30
+#: content-single.php:33 content.php:51 content.php:63
+msgid ", "
+msgstr ""
+
+#: content-featured.php:31
+msgid ""
+"This entry was posted in %1$s and tagged %2$s. Bookmark the <a href=\"%3$s\" "
+"title=\"Permalink to %4$s\" rel=\"bookmark\">permalink</a>."
+msgstr ""
+
+#: content-featured.php:33
+msgid ""
+"This entry was posted in %1$s. Bookmark the <a href=\"%3$s\" title="
+"\"Permalink to %4$s\" rel=\"bookmark\">permalink</a>."
+msgstr ""
+
+#: content-gallery.php:17
+msgid "Gallery"
+msgstr ""
+
+#: content-gallery.php:43
+msgid "This gallery contains <a %1$s>%2$s photo</a>."
+msgid_plural "This gallery contains <a %1$s>%2$s photos</a>."
+msgstr[0] ""
+msgstr[1] ""
+
+#: content-gallery.php:44 showcase.php:120
+msgid "Permalink to %s"
+msgstr ""
+
+#: content-gallery.php:62 content-image.php:51 content-quote.php:48
+#: content.php:55
+msgid "<span class=\"%1$s\">Posted in</span> %2$s"
+msgstr ""
+
+#: content-gallery.php:74 content-image.php:59 content-quote.php:60
+#: content.php:69
+msgid "<span class=\"%1$s\">Tagged</span> %2$s"
+msgstr ""
+
+#: content-image.php:16
+msgid "Image"
+msgstr ""
+
+#: content-image.php:34
+msgid ""
+"<a href=\"%1$s\" rel=\"bookmark\"><time class=\"entry-date\" datetime=\"%2$s"
+"\">%3$s</time></a><span class=\"by-author\"> <span class=\"sep\"> by </span> "
+"<span class=\"author vcard\"><a class=\"url fn n\" href=\"%4$s\" title=\"%5$s"
+"\" rel=\"author\">%6$s</a></span></span>"
+msgstr ""
+
+#: content-image.php:39 functions.php:608
+msgid "View all posts by %s"
+msgstr ""
+
+#: content-link.php:17
+msgid "Link"
+msgstr ""
+
+#: content-quote.php:15
+msgid "Quote"
+msgstr ""
+
+#: content-single.php:35
+msgid ""
+"This entry was posted in %1$s and tagged %2$s by <a href=\"%6$s\">%5$s</a>. "
+"Bookmark the <a href=\"%3$s\" title=\"Permalink to %4$s\" rel=\"bookmark"
+"\">permalink</a>."
+msgstr ""
+
+#: content-single.php:37
+msgid ""
+"This entry was posted in %1$s by <a href=\"%6$s\">%5$s</a>. Bookmark the <a "
+"href=\"%3$s\" title=\"Permalink to %4$s\" rel=\"bookmark\">permalink</a>."
+msgstr ""
+
+#: content-single.php:39
+msgid ""
+"This entry was posted by <a href=\"%6$s\">%5$s</a>. Bookmark the <a href="
+"\"%3$s\" title=\"Permalink to %4$s\" rel=\"bookmark\">permalink</a>."
+msgstr ""
+
+#: content-single.php:64
+msgid "View all posts by %s <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: content-status.php:16
+msgid "Status"
+msgstr ""
+
+#: content.php:16
+msgid "Featured"
+msgstr ""
+
+#. #-#-#-#-# twentyeleven.pot (Twenty Eleven 1.6) #-#-#-#-#
+#. Author URI of the plugin/theme
+#: footer.php:27
+msgid "http://wordpress.org/"
+msgstr ""
+
+#: footer.php:27
+msgid "Semantic Personal Publishing Platform"
+msgstr ""
+
+#: footer.php:27
+msgid "Proudly powered by %s"
+msgstr ""
+
+#: functions.php:95
+msgid "Primary Menu"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:164
+msgid "Wheel"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:170
+msgid "Shore"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:176
+msgid "Trolley"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:182
+msgid "Pine Cone"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:188
+msgid "Chessboard"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:194
+msgid "Lanterns"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:200
+msgid "Willow"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:206
+msgid "Hanoi Plant"
+msgstr ""
+
+#: functions.php:394
+msgid "Main Sidebar"
+msgstr ""
+
+#: functions.php:403
+msgid "Showcase Sidebar"
+msgstr ""
+
+#: functions.php:405
+msgid "The sidebar for the optional Showcase Template"
+msgstr ""
+
+#: functions.php:413
+msgid "Footer Area One"
+msgstr ""
+
+#: functions.php:415 functions.php:425 functions.php:435
+msgid "An optional widget area for your site footer"
+msgstr ""
+
+#: functions.php:423
+msgid "Footer Area Two"
+msgstr ""
+
+#: functions.php:433
+msgid "Footer Area Three"
+msgstr ""
+
+#: functions.php:453 single.php:18
+msgid "Post navigation"
+msgstr ""
+
+#: functions.php:454
+msgid "<span class=\"meta-nav\">&larr;</span> Older posts"
+msgstr ""
+
+#: functions.php:455
+msgid "Newer posts <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: functions.php:543
+msgid "Pingback:"
+msgstr ""
+
+#. translators: 1: comment author, 2: date and time
+#: functions.php:560
+msgid "%1$s on %2$s <span class=\"says\">said:</span>"
+msgstr ""
+
+#. translators: 1: date, 2: time
+#: functions.php:566
+msgid "%1$s at %2$s"
+msgstr ""
+
+#: functions.php:575
+msgid "Your comment is awaiting moderation."
+msgstr ""
+
+#: functions.php:584
+msgid "Reply <span>&darr;</span>"
+msgstr ""
+
+#: functions.php:602
+msgid ""
+"<span class=\"sep\">Posted on </span><a href=\"%1$s\" title=\"%2$s\" rel="
+"\"bookmark\"><time class=\"entry-date\" datetime=\"%3$s\">%4$s</time></"
+"a><span class=\"by-author\"> <span class=\"sep\"> by </span> <span class="
+"\"author vcard\"><a class=\"url fn n\" href=\"%5$s\" title=\"%6$s\" rel="
+"\"author\">%7$s</a></span></span>"
+msgstr ""
+
+#: header.php:45
+msgid "Page %s"
+msgstr ""
+
+#: header.php:129
+msgid "Main menu"
+msgstr ""
+
+#: header.php:131
+msgid "Skip to primary content"
+msgstr ""
+
+#: header.php:132
+msgid "Skip to secondary content"
+msgstr ""
+
+#: image.php:18
+msgid "Image navigation"
+msgstr ""
+
+#: image.php:19
+msgid "&larr; Previous"
+msgstr ""
+
+#: image.php:20
+msgid "Next &rarr;"
+msgstr ""
+
+#: image.php:30
+msgid ""
+"<span class=\"meta-prep meta-prep-entry-date\">Published </span> <span class="
+"\"entry-date\"><abbr class=\"published\" title=\"%1$s\">%2$s</abbr></span> "
+"at <a href=\"%3$s\" title=\"Link to full-size image\">%4$s &times; %5$s</a> "
+"in <a href=\"%6$s\" title=\"Return to %7$s\" rel=\"gallery\">%8$s</a>"
+msgstr ""
+
+#: inc/theme-options.php:55 inc/theme-options.php:474
+msgid "Color Scheme"
+msgstr ""
+
+#: inc/theme-options.php:61 inc/theme-options.php:491
+msgid "Link Color"
+msgstr ""
+
+#: inc/theme-options.php:62
+msgid "Default Layout"
+msgstr ""
+
+#: inc/theme-options.php:94 inc/theme-options.php:95
+msgid "Theme Options"
+msgstr ""
+
+#: inc/theme-options.php:110
+msgid ""
+"Some themes provide customization options that are grouped together on a "
+"Theme Options screen. If you change themes, options may change or disappear, "
+"as they are theme-specific. Your current theme, Twenty Eleven, provides the "
+"following Theme Options:"
+msgstr ""
+
+#: inc/theme-options.php:112
+msgid ""
+"<strong>Color Scheme</strong>: You can choose a color palette of \"Light"
+"\" (light background with dark text) or \"Dark\" (dark background with light "
+"text) for your site."
+msgstr ""
+
+#: inc/theme-options.php:113
+msgid ""
+"<strong>Link Color</strong>: You can choose the color used for text links on "
+"your site. You can enter the HTML color or hex code, or you can choose "
+"visually by clicking the \"Select a Color\" button to pick from a color "
+"wheel."
+msgstr ""
+
+#: inc/theme-options.php:114
+msgid ""
+"<strong>Default Layout</strong>: You can choose if you want your site&#8217;"
+"s default layout to have a sidebar on the left, the right, or not at all."
+msgstr ""
+
+#: inc/theme-options.php:116
+msgid ""
+"Remember to click \"Save Changes\" to save any changes you have made to the "
+"theme options."
+msgstr ""
+
+#: inc/theme-options.php:118
+msgid "For more information:"
+msgstr ""
+
+#: inc/theme-options.php:119
+msgid ""
+"<a href=\"http://codex.wordpress.org/Appearance_Theme_Options_Screen\" "
+"target=\"_blank\">Documentation on Theme Options</a>"
+msgstr ""
+
+#: inc/theme-options.php:120
+msgid ""
+"<a href=\"http://wordpress.org/support/\" target=\"_blank\">Support Forums</"
+"a>"
+msgstr ""
+
+#: inc/theme-options.php:127
+msgid "Overview"
+msgstr ""
+
+#: inc/theme-options.php:149
+msgid "Light"
+msgstr ""
+
+#: inc/theme-options.php:155
+msgid "Dark"
+msgstr ""
+
+#: inc/theme-options.php:173
+msgid "Content on left"
+msgstr ""
+
+#: inc/theme-options.php:178
+msgid "Content on right"
+msgstr ""
+
+#: inc/theme-options.php:183
+msgid "One-column, no sidebar"
+msgstr ""
+
+#: inc/theme-options.php:273
+msgid "Select a Color"
+msgstr ""
+
+#: inc/theme-options.php:276
+msgid "Default color: %s"
+msgstr ""
+
+#: inc/theme-options.php:312
+msgid "%s Theme Options"
+msgstr ""
+
+#: inc/theme-options.php:498
+msgid "Layout"
+msgstr ""
+
+#: inc/widgets.php:19
+msgid ""
+"Use this widget to list your recent Aside, Status, Quote, and Link posts"
+msgstr ""
+
+#: inc/widgets.php:20
+msgid "Twenty Eleven Ephemera"
+msgstr ""
+
+#: inc/widgets.php:52
+msgid "Ephemera"
+msgstr ""
+
+#: inc/widgets.php:91 inc/widgets.php:100
+msgid "0 <span class=\"reply\">comments &rarr;</span>"
+msgstr ""
+
+#: inc/widgets.php:91 inc/widgets.php:100
+msgid "1 <span class=\"reply\">comment &rarr;</span>"
+msgstr ""
+
+#: inc/widgets.php:91 inc/widgets.php:100
+msgid "% <span class=\"reply\">comments &rarr;</span>"
+msgstr ""
+
+#: inc/widgets.php:150
+msgid "Title:"
+msgstr ""
+
+#: inc/widgets.php:153
+msgid "Number of posts to show:"
+msgstr ""
+
+#: search.php:18
+msgid "Search Results for: %s"
+msgstr ""
+
+#: search.php:46
+msgid ""
+"Sorry, but nothing matched your search criteria. Please try again with some "
+"different keywords."
+msgstr ""
+
+#: searchform.php:11 searchform.php:12 searchform.php:13
+msgid "Search"
+msgstr ""
+
+#: showcase.php:77
+msgid "Featured Post"
+msgstr ""
+
+#: showcase.php:150
+msgid "Featuring: %s"
+msgstr ""
+
+#: showcase.php:160
+msgid "Recent Posts"
+msgstr ""
+
+#: sidebar.php:19
+msgid "Archives"
+msgstr ""
+
+#: sidebar.php:26
+msgid "Meta"
+msgstr ""
+
+#: single.php:19
+msgid "<span class=\"meta-nav\">&larr;</span> Previous"
+msgstr ""
+
+#: single.php:20
+msgid "Next <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: tag.php:19
+msgid "Tag Archives: %s"
+msgstr ""
+
+#. Theme Name of the plugin/theme
+msgid "Twenty Eleven"
+msgstr ""
+
+#. Theme URI of the plugin/theme
+msgid "http://wordpress.org/themes/twentyeleven"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"The 2011 theme for WordPress is sophisticated, lightweight, and adaptable. "
+"Make it yours with a custom menu, header image, and background -- then go "
+"further with available theme options for light or dark color scheme, custom "
+"link colors, and three layout choices. Twenty Eleven comes equipped with a "
+"Showcase page template that transforms your front page into a showcase to "
+"show off your best content, widget support galore (sidebar, three footer "
+"areas, and a Showcase page widget area), and a custom \"Ephemera\" widget to "
+"display your Aside, Link, Quote, or Status posts. Included are styles for "
+"print and for the admin editor, support for featured images (as custom "
+"header images on posts and pages and as large images on featured \"sticky\" "
+"posts), and special styles for six different post formats."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "the WordPress team"
+msgstr ""
+
+#. Template Name of the plugin/theme
+msgid "Showcase Template"
+msgstr ""
+
+#. Template Name of the plugin/theme
+msgid "Sidebar Template"
+msgstr ""
diff --git a/src/wp-content/themes/twentyeleven/license.txt b/src/wp-content/themes/twentyeleven/license.txt
new file mode 100644
index 0000000000..5fbe4a70aa
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/license.txt
@@ -0,0 +1,281 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/src/wp-content/themes/twentyeleven/page.php b/src/wp-content/themes/twentyeleven/page.php
new file mode 100644
index 0000000000..5dda4d164f
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/page.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * The template for displaying all pages.
+ *
+ * This is the template that displays all pages by default.
+ * Please note that this is the WordPress construct of pages
+ * and that other 'pages' on your WordPress site will use a
+ * different template.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', 'page' ); ?>
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/readme.txt b/src/wp-content/themes/twentyeleven/readme.txt
new file mode 100644
index 0000000000..e803014843
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/readme.txt
@@ -0,0 +1,5 @@
+= TWENTY ELEVEN =
+
+* by the WordPress team, http://wordpress.org/
+
+== ABOUT TWENTY ELEVEN == \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/rtl.css b/src/wp-content/themes/twentyeleven/rtl.css
new file mode 100644
index 0000000000..376e5437ed
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/rtl.css
@@ -0,0 +1,582 @@
+/*
+Theme Name: Twenty Eleven
+
+Adding support for language written in a Right To Left (RTL) direction is easy -
+it's just a matter of overwriting all the horizontal positioning attributes
+of your CSS stylesheet in a separate stylesheet file named rtl.css.
+
+http://codex.wordpress.org/Right_to_Left_Language_Support
+
+*/
+
+/* =Reset reset
+----------------------------------------------- */
+
+caption, th, td {
+ text-align: right;
+}
+
+/* =Structure
+----------------------------------------------- */
+
+body {
+ direction:rtl;
+ unicode-bidi:embed;
+}
+
+/* Showcase */
+.page-template-showcase-php section.recent-posts {
+ float: left;
+ margin: 0 31% 0 0;
+}
+.page-template-showcase-php #main .widget-area {
+ float: right;
+ margin: 0 0 0 -22.15%;
+}
+
+/* One column */
+
+.one-column article.feature-image.small .entry-summary a {
+ left: auto;
+ right: -9%;
+}
+
+/* Simplify the pullquotes and pull styles */
+.one-column.singular .entry-meta .edit-link a {
+ right: 0px;
+ left: auto;
+}
+/* Make sure we have room for our comment avatars */
+.one-column .commentlist > li.comment {
+ margin-left: 0;
+ margin-right: 102px;
+}
+/* Make sure the logo and search form don't collide */
+.one-column #branding #searchform {
+ right: auto;
+ left: 40px;
+}
+/* Talking avatars take up too much room at this size */
+.one-column .commentlist > li.comment {
+ margin-right: 0;
+}
+.one-column .commentlist > li.comment .comment-meta,
+.one-column .commentlist > li.comment .comment-content {
+ margin-right: 0;
+ margin-left: 85px;
+}
+.one-column .commentlist .avatar {
+ right: auto;
+ left: 1.625em;
+}
+.one-column .commentlist .children .avatar {
+ left: auto;
+ right: 2.2em;
+}
+
+/* =Global
+----------------------------------------------- */
+
+/* Text elements */
+p {
+ margin-bottom: 1.625em;
+}
+ul, ol {
+ margin: 0 2.5em 1.625em 0;
+}
+.ltr ul, .ltr ol {
+ margin: 0 0 1.625em 2.5em;
+}
+blockquote {
+ font-family: Arial, sans-serif;
+}
+blockquote em, blockquote i, blockquote cite {
+ font-style: normal;
+}
+
+/* Forms */
+textarea {
+ padding-left: 0;
+ padding-right: 3px;
+}
+input#s {
+ background-position: 97% 6px;
+ padding: 4px 28px 4px 10px;
+}
+
+/* Assistive text */
+#access a.assistive-text:focus {
+ left: auto;
+ right: 7.6%;
+}
+
+/* =Header
+----------------------------------------------- */
+
+#site-title {
+ margin-right: 0;
+ margin-left: 270px;
+}
+
+#site-description {
+ margin: 0 0 3.65625em 270px;
+}
+
+/* =Menu
+-------------------------------------------------------------- */
+
+#access {
+ float: right;
+}
+#access ul {
+ margin: 0 -0.8125em 0 0;
+ padding-right: 0;
+}
+#access li {
+ float: right;
+}
+#access ul ul {
+ float: right;
+ left: auto;
+ right: 0;
+}
+#access ul ul ul {
+ left: auto;
+ right: 100%;
+}
+
+/* Search Form */
+#branding #searchform {
+ right: auto;
+ left: 7.6%;
+ text-align: left;
+}
+#branding #s {
+ float: left;
+}
+#branding .only-search + #access div {
+ padding-right: 0;
+ padding-left: 205px;
+}
+
+
+/* =Content
+----------------------------------------------- */
+.entry-title,
+.entry-header .entry-meta {
+ padding-right: 0;
+ padding-left: 76px;
+}
+.entry-content td,
+.comment-content td {
+ padding: 6px 0 6px 10px;
+}
+.page-link span {
+ margin-right: 0;
+ margin-left: 6px;
+}
+.entry-meta .edit-link a {
+ float: left;
+}
+/* Images */
+
+.wp-caption .wp-caption-text,
+.gallery-caption {
+ font-family: Arial, sans-serif;
+}
+.wp-caption .wp-caption-text {
+ padding: 10px 40px 5px 0px;
+}
+.wp-caption .wp-caption-text:before {
+ margin-right: 0;
+ margin-left: 5px;
+ left: auto;
+ right: 10px;
+}
+#content .gallery-columns-4 .gallery-item {
+ padding-right:0;
+ padding-left:2%;
+}
+
+/* Author Info */
+.singular #author-info {
+ margin: 2.2em -35.4% 0 -35.6%;
+}
+#author-avatar {
+ float: right;
+ margin-right: 0;
+ margin-left: -78px;
+}
+#author-description {
+ float: right;
+ margin-left: 0;
+ margin-right: 108px;
+}
+/* Comments link */
+.entry-header .comments-link a {
+ background-image: url(images/comment-bubble-rtl.png);
+ right: auto;
+ left: 0;
+}
+
+/*
+ Post Formats Headings
+*/
+.singular .entry-title,
+.singular .entry-header .entry-meta {
+ padding-left: 0;
+}
+.singular .entry-header .entry-meta {
+ left: auto;
+ right: 0;
+}
+.singular .entry-meta .edit-link a {
+ left: auto;
+ right: 50px;
+}
+
+
+/* =Gallery
+----------------------------------------------- */
+
+.format-gallery .gallery-thumb {
+ float: right;
+ margin: .375em 0 0 1.625em;
+}
+
+
+/* =Status
+----------------------------------------------- */
+
+.format-status img.avatar {
+ float: right;
+ margin: 4px 0 2px 10px;
+}
+
+
+/* =Image
+----------------------------------------------- */
+
+.indexed.format-image div.entry-meta {
+ float: right;
+}
+/* =error404
+----------------------
+------------------------- */
+.error404 #main .widget {
+ float: right;
+ margin-right: auto;
+ margin-left: 3.7%;
+}
+.error404 #main .widget_archive {
+ margin-left: 0;
+}
+.error404 #main .widget_tag_cloud {
+ margin-left: 0;
+}
+
+/* =Showcase
+----------------------------------------------- */
+
+article.intro .edit-link a {
+ right: auto;
+ left: 20px;
+}
+
+/* Featured post */
+section.featured-post {
+ float: right;
+}
+
+/* Small featured post */
+section.featured-post .attachment-small-feature {
+ float: left;
+ margin: 0 0 1.625em -8.9%;
+ right: auto;
+ left: -15px;
+}
+article.feature-image.small {
+ float: right;
+}
+article.feature-image.small .entry-summary p a {
+ left:auto;
+ right: -23.8%;
+ padding: 9px 85px 9px 26px;
+}
+
+/* Large featured post */
+section.feature-image.large .hentry {
+ left:auto;
+ right: 9%;
+ margin: 1.625em 0 0 9%;
+}
+/* Featured Slider */
+.featured-posts .showcase-heading {
+ padding-left: 0;
+ padding-right: 8.9%;
+}
+.featured-posts section.featured-post {
+ left: auto;
+ right: 0;
+}
+#content .feature-slider {
+ right: auto;
+ left: 8.9%;
+}
+.feature-slider li {
+ float: right;
+}
+/* Recent Posts */
+section.recent-posts .other-recent-posts a[rel="bookmark"] {
+ float: right;
+}
+section.recent-posts .other-recent-posts .comments-link a,
+section.recent-posts .other-recent-posts .comments-link > span {
+ padding: 0.3125em 1em 0.3125em 0;
+ right: auto;
+ left: 0;
+ text-align: left;
+}
+
+/* =Attachments
+----------------------------------------------- */
+
+/* =Navigation
+-------------------------------------------------------------- */
+
+.nav-previous {
+ float: right;
+}
+.nav-next {
+ float: left;
+ text-align: left;
+}
+
+/* Singular navigation */
+#nav-single {
+ float: left;
+ text-align: left;
+}
+#nav-single .nav-next {
+ padding-left: 0;
+ padding-right: .5em;
+}
+
+
+/* =Widgets
+----------------------------------------------- */
+
+.widget ul ul {
+ margin-left: 0;
+ margin-right: 1.5em;
+}
+
+/* Twitter */
+.widget_twitter .timesince {
+ margin-right: 0;
+ margin-left: -10px;
+ text-align: left;
+}
+
+/* =Comments
+----------------------------------------------- */
+
+.commentlist .children li.comment {
+ border-left: none;
+ border-right: 1px solid #ddd;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+.commentlist .children li.comment .comment-meta {
+ margin-left: 0;
+ margin-right: 50px;
+}
+.commentlist .avatar {
+ left: auto;
+ right: -102px;
+}
+.commentlist > li:before {
+ content: url(images/comment-arrow-rtl.png);
+ left:auto;
+ right: -21px;
+}
+.commentlist > li.pingback:before {
+ content: '';
+}
+.commentlist .children .avatar {
+ left: auto;
+ right: 2.2em;
+}
+
+/* Post author highlighting */
+.commentlist > li.bypostauthor:before {
+ content: url(images/comment-arrow-bypostauthor-rtl.png);
+}
+
+/* sidebar-page.php comments */
+/* Make sure we have room for our comment avatars */
+.page-template-sidebar-page-php .commentlist > li.comment,
+.page-template-sidebar-page-php.commentlist .pingback {
+ margin-left: 0;
+ margin-right: 102px;
+}
+
+/* Comment Form */
+#respond .comment-form-author label,
+#respond .comment-form-email label,
+#respond .comment-form-url label,
+#respond .comment-form-comment label {
+ left: auto;
+ right: 4px;
+}
+#respond .comment-form-author label,
+#respond .comment-form-email label,
+#respond .comment-form-url label,
+#respond .comment-form-comment label {
+ -webkit-box-shadow: -1px 2px 2px rgba(204,204,204,0.8);
+ -moz-box-shadow: -1px 2px 2px rgba(204,204,204,0.8);
+ box-shadow: -1px 2px 2px rgba(204,204,204,0.8);
+}
+#respond .comment-form-author .required,
+#respond .comment-form-email .required {
+ left: auto;
+ right: 75%;
+}
+#respond .form-submit {
+ float: left;
+}
+#respond input#submit {
+ left: auto;
+ right: 30px;
+ padding: 5px 22px 5px 42px;
+}
+#respond #cancel-comment-reply-link {
+ margin-left: 0;
+ margin-right: 10px;
+}
+#cancel-comment-reply-link {
+ right: auto;
+ left: 1.625em;
+}
+
+/* =Footer
+----------------------------------------------- */
+
+/* Two Footer Widget Areas */
+#supplementary.two .widget-area {
+ float: right;
+ margin-right: 0;
+ margin-left: 3.7%;
+}
+#supplementary.two .widget-area + .widget-area {
+ margin-left: 0;
+}
+
+/* Three Footer Widget Areas */
+#supplementary.three .widget-area {
+ float: right;
+ margin-right: 0;
+ margin-left: 3.7%;
+}
+#supplementary.three .widget-area + .widget-area + .widget-area {
+ margin-left: 0;
+}
+
+/* Site Generator Line */
+#site-generator .sep {
+ background-position: right center;
+}
+
+
+/* =Responsive Structure
+----------------------------------------------- */
+
+@media (max-width: 800px) {
+ /* Simplify the showcase template when small feature */
+ section.featured-post .attachment-small-feature,
+ .one-column section.featured-post .attachment-small-feature {
+ float: right;
+ }
+ article.feature-image.small {
+ float: left;
+ }
+ article.feature-image.small .entry-summary p a {
+ right: 0;
+ }
+ .singular .entry-meta .edit-link a {
+ left: auto;
+ right: 0px;
+ }
+ /* Make sure we have room for our comment avatars */
+ .commentlist > li.comment,
+ .commentlist .pingback {
+ margin-left: 0;
+ margin-right: 102px;
+ }
+ /* No need to float footer widgets at this size */
+ #colophon #supplementary .widget-area {
+ margin-left: 0;
+ }
+ /* No need to float 404 widgets at this size */
+ .error404 #main .widget {
+ margin-left: 0;
+ }
+}
+@media (max-width: 650px) {
+ /* @media (max-width: 650px) Reduce font-sizes for better readability on smaller devices */
+ #site-title,
+ #site-description {
+ margin-left: 0;
+ }
+ /* Talking avatars take up too much room at this size */
+ .commentlist > li.comment,
+ .commentlist > li.pingback {
+ margin-right: 0 !important;
+ }
+ .commentlist .children .avatar {
+ left: auto;
+ right: 2.2em;
+ }
+ /* Use the available space in the smaller comment form */
+ #respond .comment-form-author .required,
+ #respond .comment-form-email .required {
+ left: auto;
+ right: 95%;
+ }
+ #content .gallery-columns-3 .gallery-item {
+ padding-right: 0;
+ padding-left:2%;
+ }
+}
+@media (max-width: 450px) {
+ #content .gallery-columns-2 .gallery-item {
+ padding-right:0;
+ padding-left:4%;
+ }
+}
+
+/* =Print
+----------------------------------------------- */
+
+@media print {
+ #primary {
+ float: right;
+ }
+ /* Comments */
+ .commentlist .avatar {
+ left: auto;
+ right: 2.2em;
+ }
+ .commentlist li.comment .comment-meta {
+ margin-left: 0;
+ margin-right: 50px;
+ }
+}
+
+/* =IE7
+----------------------------------------------- */
+
+#ie7 section.recent-posts {
+ margin-right: 0;
+ margin-left: 7.6%;
+}
diff --git a/src/wp-content/themes/twentyeleven/screenshot.png b/src/wp-content/themes/twentyeleven/screenshot.png
new file mode 100644
index 0000000000..8f120d8d5b
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/screenshot.png
Binary files differ
diff --git a/src/wp-content/themes/twentyeleven/search.php b/src/wp-content/themes/twentyeleven/search.php
new file mode 100644
index 0000000000..bf45c2feeb
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/search.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * The template for displaying Search Results pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentyeleven' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
+ </header>
+
+ <?php twentyeleven_content_nav( 'nav-above' ); ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php
+ /* Include the Post-Format-specific template for the content.
+ * If you want to overload this in a child theme then include a file
+ * called content-___.php (where ___ is the Post Format name) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+ ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyeleven_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'Sorry, but nothing matched your search criteria. Please try again with some different keywords.', 'twentyeleven' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/searchform.php b/src/wp-content/themes/twentyeleven/searchform.php
new file mode 100644
index 0000000000..b83ec1e67f
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/searchform.php
@@ -0,0 +1,14 @@
+<?php
+/**
+ * The template for displaying search forms in Twenty Eleven
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+ <form method="get" id="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>">
+ <label for="s" class="assistive-text"><?php _e( 'Search', 'twentyeleven' ); ?></label>
+ <input type="text" class="field" name="s" id="s" placeholder="<?php esc_attr_e( 'Search', 'twentyeleven' ); ?>" />
+ <input type="submit" class="submit" name="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'twentyeleven' ); ?>" />
+ </form>
diff --git a/src/wp-content/themes/twentyeleven/showcase.php b/src/wp-content/themes/twentyeleven/showcase.php
new file mode 100644
index 0000000000..e514231898
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/showcase.php
@@ -0,0 +1,227 @@
+<?php
+/**
+ * Template Name: Showcase Template
+ * Description: A Page Template that showcases Sticky Posts, Asides, and Blog Posts
+ *
+ * The showcase template in Twenty Eleven consists of a featured posts section using sticky posts,
+ * another recent posts area (with the latest post shown in full and the rest as a list)
+ * and a left sidebar holding aside posts.
+ *
+ * We are creating two queries to fetch the proper posts and a custom widget for the sidebar.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+// Enqueue showcase script for the slider
+wp_enqueue_script( 'twentyeleven-showcase', get_template_directory_uri() . '/js/showcase.js', array( 'jquery' ), '2011-04-28' );
+
+get_header(); ?>
+
+ <div id="primary" class="showcase">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php
+ /**
+ * We are using a heading by rendering the_content
+ * If we have content for this page, let's display it.
+ */
+ if ( '' != get_the_content() )
+ get_template_part( 'content', 'intro' );
+ ?>
+
+ <?php endwhile; ?>
+
+ <?php
+ /**
+ * Begin the featured posts section.
+ *
+ * See if we have any sticky posts and use them to create our featured posts.
+ * We limit the featured posts at ten.
+ */
+ $sticky = get_option( 'sticky_posts' );
+
+ // Proceed only if sticky posts exist.
+ if ( ! empty( $sticky ) ) :
+
+ $featured_args = array(
+ 'post__in' => $sticky,
+ 'post_status' => 'publish',
+ 'posts_per_page' => 10,
+ 'no_found_rows' => true,
+ );
+
+ // The Featured Posts query.
+ $featured = new WP_Query( $featured_args );
+
+ // Proceed only if published posts exist
+ if ( $featured->have_posts() ) :
+
+ /**
+ * We will need to count featured posts starting from zero
+ * to create the slider navigation.
+ */
+ $counter_slider = 0;
+
+ // Compatibility with versions of WordPress prior to 3.4.
+ if ( function_exists( 'get_custom_header' ) )
+ $header_image_width = get_theme_support( 'custom-header', 'width' );
+ else
+ $header_image_width = HEADER_IMAGE_WIDTH;
+ ?>
+
+ <div class="featured-posts">
+ <h1 class="showcase-heading"><?php _e( 'Featured Post', 'twentyeleven' ); ?></h1>
+
+ <?php
+ // Let's roll.
+ while ( $featured->have_posts() ) : $featured->the_post();
+
+ // Increase the counter.
+ $counter_slider++;
+
+ /**
+ * We're going to add a class to our featured post for featured images
+ * by default it'll have the feature-text class.
+ */
+ $feature_class = 'feature-text';
+
+ if ( has_post_thumbnail() ) {
+ // ... but if it has a featured image let's add some class
+ $feature_class = 'feature-image small';
+
+ // Hang on. Let's check this here image out.
+ $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), array( $header_image_width, $header_image_width ) );
+
+ // Is it bigger than or equal to our header?
+ if ( $image[1] >= $header_image_width ) {
+ // If bigger, let's add a BIGGER class. It's EXTRA classy now.
+ $feature_class = 'feature-image large';
+ }
+ }
+ ?>
+
+ <section class="featured-post <?php echo $feature_class; ?>" id="featured-post-<?php echo $counter_slider; ?>">
+
+ <?php
+ /**
+ * If the thumbnail is as big as the header image
+ * make it a large featured post, otherwise render it small
+ */
+ if ( has_post_thumbnail() ) {
+ if ( $image[1] >= $header_image_width )
+ $thumbnail_size = 'large-feature';
+ else
+ $thumbnail_size = 'small-feature';
+ ?>
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentyeleven' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php the_post_thumbnail( $thumbnail_size ); ?></a>
+ <?php
+ }
+ ?>
+ <?php get_template_part( 'content', 'featured' ); ?>
+ </section>
+ <?php endwhile; ?>
+
+ <?php
+ // Show slider only if we have more than one featured post.
+ if ( $featured->post_count > 1 ) :
+ ?>
+ <nav class="feature-slider">
+ <ul>
+ <?php
+
+ // Reset the counter so that we end up with matching elements
+ $counter_slider = 0;
+
+ // Begin from zero
+ rewind_posts();
+
+ // Let's roll again.
+ while ( $featured->have_posts() ) : $featured->the_post();
+ $counter_slider++;
+ if ( 1 == $counter_slider )
+ $class = 'class="active"';
+ else
+ $class = '';
+ ?>
+ <li><a href="#featured-post-<?php echo $counter_slider; ?>" title="<?php echo esc_attr( sprintf( __( 'Featuring: %s', 'twentyeleven' ), the_title_attribute( 'echo=0' ) ) ); ?>" <?php echo $class; ?>></a></li>
+ <?php endwhile; ?>
+ </ul>
+ </nav>
+ <?php endif; // End check for more than one sticky post. ?>
+ </div><!-- .featured-posts -->
+ <?php endif; // End check for published posts. ?>
+ <?php endif; // End check for sticky posts. ?>
+
+ <section class="recent-posts">
+ <h1 class="showcase-heading"><?php _e( 'Recent Posts', 'twentyeleven' ); ?></h1>
+
+ <?php
+
+ // Display our recent posts, showing full content for the very latest, ignoring Aside posts.
+ $recent_args = array(
+ 'order' => 'DESC',
+ 'post__not_in' => get_option( 'sticky_posts' ),
+ 'tax_query' => array(
+ array(
+ 'taxonomy' => 'post_format',
+ 'terms' => array( 'post-format-aside', 'post-format-link', 'post-format-quote', 'post-format-status' ),
+ 'field' => 'slug',
+ 'operator' => 'NOT IN',
+ ),
+ ),
+ 'no_found_rows' => true,
+ );
+
+ // Our new query for the Recent Posts section.
+ $recent = new WP_Query( $recent_args );
+
+ // The first Recent post is displayed normally
+ if ( $recent->have_posts() ) : $recent->the_post();
+
+ // Set $more to 0 in order to only get the first part of the post.
+ global $more;
+ $more = 0;
+
+ get_template_part( 'content', get_post_format() );
+
+ echo '<ol class="other-recent-posts">';
+
+ endif;
+
+ // For all other recent posts, just display the title and comment status.
+ while ( $recent->have_posts() ) : $recent->the_post(); ?>
+
+ <li class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ <span class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentyeleven' ) . '</span>', __( '<b>1</b> Reply', 'twentyeleven' ), __( '<b>%</b> Replies', 'twentyeleven' ) ); ?>
+ </span>
+ </li>
+
+ <?php
+ endwhile;
+
+ // If we had some posts, close the <ol>
+ if ( $recent->post_count > 0 )
+ echo '</ol>';
+ ?>
+ </section><!-- .recent-posts -->
+
+ <div class="widget-area" role="complementary">
+ <?php if ( ! dynamic_sidebar( 'sidebar-2' ) ) : ?>
+
+ <?php
+ the_widget( 'Twenty_Eleven_Ephemera_Widget', '', array( 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>' ) );
+ ?>
+
+ <?php endif; // end sidebar widget area ?>
+ </div><!-- .widget-area -->
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/sidebar-footer.php b/src/wp-content/themes/twentyeleven/sidebar-footer.php
new file mode 100644
index 0000000000..cbcb49b5de
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/sidebar-footer.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * The Footer widget areas.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+?>
+
+<?php
+ /* The footer widget area is triggered if any of the areas
+ * have widgets. So let's check that first.
+ *
+ * If none of the sidebars have widgets, then let's bail early.
+ */
+ if ( ! is_active_sidebar( 'sidebar-3' )
+ && ! is_active_sidebar( 'sidebar-4' )
+ && ! is_active_sidebar( 'sidebar-5' )
+ )
+ return;
+ // If we get this far, we have widgets. Let do this.
+?>
+<div id="supplementary" <?php twentyeleven_footer_sidebar_class(); ?>>
+ <?php if ( is_active_sidebar( 'sidebar-3' ) ) : ?>
+ <div id="first" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-3' ); ?>
+ </div><!-- #first .widget-area -->
+ <?php endif; ?>
+
+ <?php if ( is_active_sidebar( 'sidebar-4' ) ) : ?>
+ <div id="second" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-4' ); ?>
+ </div><!-- #second .widget-area -->
+ <?php endif; ?>
+
+ <?php if ( is_active_sidebar( 'sidebar-5' ) ) : ?>
+ <div id="third" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-5' ); ?>
+ </div><!-- #third .widget-area -->
+ <?php endif; ?>
+</div><!-- #supplementary --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/sidebar-page.php b/src/wp-content/themes/twentyeleven/sidebar-page.php
new file mode 100644
index 0000000000..c10d628586
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/sidebar-page.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Template Name: Sidebar Template
+ * Description: A Page Template that adds a sidebar to pages
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', 'page' ); ?>
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/sidebar.php b/src/wp-content/themes/twentyeleven/sidebar.php
new file mode 100644
index 0000000000..0f0857181f
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/sidebar.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * The Sidebar containing the main widget area.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+$options = twentyeleven_get_theme_options();
+$current_layout = $options['theme_layout'];
+
+if ( 'content' != $current_layout ) :
+?>
+ <div id="secondary" class="widget-area" role="complementary">
+ <?php if ( ! dynamic_sidebar( 'sidebar-1' ) ) : ?>
+
+ <aside id="archives" class="widget">
+ <h3 class="widget-title"><?php _e( 'Archives', 'twentyeleven' ); ?></h3>
+ <ul>
+ <?php wp_get_archives( array( 'type' => 'monthly' ) ); ?>
+ </ul>
+ </aside>
+
+ <aside id="meta" class="widget">
+ <h3 class="widget-title"><?php _e( 'Meta', 'twentyeleven' ); ?></h3>
+ <ul>
+ <?php wp_register(); ?>
+ <li><?php wp_loginout(); ?></li>
+ <?php wp_meta(); ?>
+ </ul>
+ </aside>
+
+ <?php endif; // end sidebar widget area ?>
+ </div><!-- #secondary .widget-area -->
+<?php endif; ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/single.php b/src/wp-content/themes/twentyeleven/single.php
new file mode 100644
index 0000000000..92a533eb9c
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/single.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * The Template for displaying all single posts.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <nav id="nav-single">
+ <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentyeleven' ); ?></h3>
+ <span class="nav-previous"><?php previous_post_link( '%link', __( '<span class="meta-nav">&larr;</span> Previous', 'twentyeleven' ) ); ?></span>
+ <span class="nav-next"><?php next_post_link( '%link', __( 'Next <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?></span>
+ </nav><!-- #nav-single -->
+
+ <?php get_template_part( 'content-single', get_post_format() ); ?>
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/style.css b/src/wp-content/themes/twentyeleven/style.css
new file mode 100644
index 0000000000..9eee8c5e91
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/style.css
@@ -0,0 +1,2721 @@
+/*
+Theme Name: Twenty Eleven
+Theme URI: http://wordpress.org/themes/twentyeleven
+Author: the WordPress team
+Author URI: http://wordpress.org/
+Description: The 2011 theme for WordPress is sophisticated, lightweight, and adaptable. Make it yours with a custom menu, header image, and background -- then go further with available theme options for light or dark color scheme, custom link colors, and three layout choices. Twenty Eleven comes equipped with a Showcase page template that transforms your front page into a showcase to show off your best content, widget support galore (sidebar, three footer areas, and a Showcase page widget area), and a custom "Ephemera" widget to display your Aside, Link, Quote, or Status posts. Included are styles for print and for the admin editor, support for featured images (as custom header images on posts and pages and as large images on featured "sticky" posts), and special styles for six different post formats.
+Version: 1.6
+License: GNU General Public License v2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+Tags: dark, light, white, black, gray, one-column, two-columns, left-sidebar, right-sidebar, fixed-width, flexible-width, custom-background, custom-colors, custom-header, custom-menu, editor-style, featured-image-header, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready
+Text Domain: twentyeleven
+*/
+
+/* =Reset default browser CSS. Based on work by Eric Meyer: http://meyerweb.com/eric/tools/css/reset/index.html
+-------------------------------------------------------------- */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ border: 0;
+ font-family: inherit;
+ font-size: 100%;
+ font-style: inherit;
+ font-weight: inherit;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+ vertical-align: baseline;
+}
+:focus {/* remember to define focus styles! */
+ outline: 0;
+}
+body {
+ background: #fff;
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+table {/* tables still need 'cellspacing="0"' in the markup */
+ border-collapse: separate;
+ border-spacing: 0;
+}
+caption, th, td {
+ font-weight: normal;
+ text-align: left;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: "";
+}
+blockquote, q {
+ quotes: "" "";
+}
+a img {
+ border: 0;
+}
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+
+
+/* =Structure
+----------------------------------------------- */
+
+body {
+ padding: 0 2em;
+}
+#page {
+ margin: 2em auto;
+ max-width: 1000px;
+}
+#branding hgroup {
+ margin: 0 7.6%;
+}
+#access div {
+ margin: 0 7.6%;
+}
+#primary {
+ float: left;
+ margin: 0 -26.4% 0 0;
+ width: 100%;
+}
+#content {
+ margin: 0 34% 0 7.6%;
+ width: 58.4%;
+}
+#secondary {
+ float: right;
+ margin-right: 7.6%;
+ width: 18.8%;
+}
+
+/* Singular */
+.singular #primary {
+ margin: 0;
+}
+.singular #content,
+.left-sidebar.singular #content {
+ margin: 0 7.6%;
+ position: relative;
+ width: auto;
+}
+.singular .entry-header,
+.singular .entry-content,
+.singular footer.entry-meta,
+.singular #comments-title {
+ margin: 0 auto;
+ width: 68.9%;
+}
+
+/* Attachments */
+.singular .image-attachment .entry-content {
+ margin: 0 auto;
+ width: auto;
+}
+.singular .image-attachment .entry-description {
+ margin: 0 auto;
+ width: 68.9%;
+}
+
+/* Showcase */
+.page-template-showcase-php #primary,
+.left-sidebar.page-template-showcase-php #primary {
+ margin: 0;
+}
+.page-template-showcase-php #content,
+.left-sidebar.page-template-showcase-php #content {
+ margin: 0 7.6%;
+ width: auto;
+}
+.page-template-showcase-php section.recent-posts {
+ float: right;
+ margin: 0 0 0 31%;
+ width: 69%;
+}
+.page-template-showcase-php #main .widget-area {
+ float: left;
+ margin: 0 -22.15% 0 0;
+ width: 22.15%;
+}
+
+/* error404 */
+.error404 #primary {
+ float: none;
+ margin: 0;
+}
+.error404 #primary #content {
+ margin: 0 7.6%;
+ width: auto;
+}
+
+/* Alignment */
+.alignleft {
+ display: inline;
+ float: left;
+ margin-right: 1.625em;
+}
+.alignright {
+ display: inline;
+ float: right;
+ margin-left: 1.625em;
+}
+.aligncenter {
+ clear: both;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+/* Right Content */
+.left-sidebar #primary {
+ float: right;
+ margin: 0 0 0 -26.4%;
+ width: 100%;
+}
+.left-sidebar #content {
+ margin: 0 7.6% 0 34%;
+ width: 58.4%;
+}
+.left-sidebar #secondary {
+ float: left;
+ margin-left: 7.6%;
+ margin-right: 0;
+ width: 18.8%;
+}
+
+/* One column */
+.one-column #page {
+ max-width: 690px;
+}
+.one-column #content {
+ margin: 0 7.6%;
+ width: auto;
+}
+.one-column #nav-below {
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 1.625em;
+}
+.one-column #secondary {
+ float: none;
+ margin: 0 7.6%;
+ width: auto;
+}
+/* Simplify the showcase template */
+.one-column .page-template-showcase-php section.recent-posts {
+ float: none;
+ margin: 0;
+ width: 100%;
+}
+.one-column .page-template-showcase-php #main .widget-area {
+ float: none;
+ margin: 0;
+ width: auto;
+}
+.one-column .page-template-showcase-php .other-recent-posts {
+ border-bottom: 1px solid #ddd;
+}
+/* Simplify the showcase template when small feature */
+.one-column section.featured-post .attachment-small-feature {
+ border: none;
+ display: block;
+ height: auto;
+ max-width: 60%;
+ position: static;
+}
+.one-column article.feature-image.small {
+ margin: 0 0 1.625em;
+ padding: 0;
+}
+.one-column article.feature-image.small .entry-title {
+ font-size: 20px;
+ line-height: 1.3em;
+}
+.one-column article.feature-image.small .entry-summary {
+ height: 150px;
+ overflow: hidden;
+ padding: 0;
+ text-overflow: ellipsis;
+}
+.one-column article.feature-image.small .entry-summary a {
+ left: -9%;
+}
+/* Remove the margin on singular articles */
+.one-column.singular .entry-header,
+.one-column.singular .entry-content,
+.one-column.singular footer.entry-meta,
+.one-column.singular #comments-title {
+ width: 100%;
+}
+/* Simplify the pullquotes and pull styles */
+.one-column.singular blockquote.pull {
+ margin: 0 0 1.625em;
+}
+.one-column.singular .pull.alignleft {
+ margin: 0 1.625em 0 0;
+}
+.one-column.singular .pull.alignright {
+ margin: 0 0 0 1.625em;
+}
+.one-column.singular .entry-meta .edit-link a {
+ position: absolute;
+ left: 0;
+ top: 40px;
+}
+.one-column.singular #author-info {
+ margin: 2.2em -8.8% 0;
+ padding: 20px 8.8%;
+}
+/* Make sure we have room for our comment avatars */
+.one-column .commentlist > li.comment {
+ margin-left: 102px;
+ width: auto;
+}
+/* Make sure the logo and search form don't collide */
+.one-column #branding #searchform {
+ right: 40px;
+ top: 4em;
+}
+/* Talking avatars take up too much room at this size */
+.one-column .commentlist > li.comment {
+ margin-left: 0;
+}
+.one-column .commentlist > li.comment .comment-meta,
+.one-column .commentlist > li.comment .comment-content {
+ margin-right: 85px;
+}
+.one-column .commentlist .avatar {
+ background: transparent;
+ display: block;
+ padding: 0;
+ top: 1.625em;
+ left: auto;
+ right: 1.625em;
+}
+.one-column .commentlist .children .avatar {
+ background: none;
+ padding: 0;
+ position: absolute;
+ top: 2.2em;
+ left: 2.2em;
+}
+.one-column #respond {
+ width: auto;
+}
+
+
+/* =Global
+----------------------------------------------- */
+
+body, input, textarea {
+ color: #373737;
+ font: 15px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-weight: 300;
+ line-height: 1.625;
+}
+body {
+ background: #e2e2e2;
+}
+#page {
+ background: #fff;
+}
+
+/* Headings */
+h1,h2,h3,h4,h5,h6 {
+ clear: both;
+}
+hr {
+ background-color: #ccc;
+ border: 0;
+ height: 1px;
+ margin-bottom: 1.625em;
+}
+
+/* Text elements */
+p {
+ margin-bottom: 1.625em;
+}
+ul, ol {
+ margin: 0 0 1.625em 2.5em;
+}
+ul {
+ list-style: square;
+}
+ol {
+ list-style-type: decimal;
+}
+ol ol {
+ list-style: upper-alpha;
+}
+ol ol ol {
+ list-style: lower-roman;
+}
+ol ol ol ol {
+ list-style: lower-alpha;
+}
+ul ul, ol ol, ul ol, ol ul {
+ margin-bottom: 0;
+}
+dl {
+ margin: 0 1.625em;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-bottom: 1.625em;
+}
+strong {
+ font-weight: bold;
+}
+cite, em, i {
+ font-style: italic;
+}
+blockquote {
+ font-family: Georgia, "Bitstream Charter", serif;
+ font-style: italic;
+ font-weight: normal;
+ margin: 0 3em;
+}
+blockquote em, blockquote i, blockquote cite {
+ font-style: normal;
+}
+blockquote cite {
+ color: #666;
+ font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-weight: 300;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+}
+pre {
+ background: #f4f4f4;
+ font: 13px "Courier 10 Pitch", Courier, monospace;
+ line-height: 1.5;
+ margin-bottom: 1.625em;
+ overflow: auto;
+ padding: 0.75em 1.625em;
+}
+code, kbd, samp, var {
+ font: 13px Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
+}
+abbr, acronym, dfn {
+ border-bottom: 1px dotted #666;
+ cursor: help;
+}
+address {
+ display: block;
+ margin: 0 0 1.625em;
+}
+ins {
+ background: #fff9c0;
+ text-decoration: none;
+}
+sup,
+sub {
+ font-size: 10px;
+ height: 0;
+ line-height: 1;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ bottom: 1ex;
+}
+sub {
+ top: .5ex;
+}
+small {
+ font-size: smaller;
+}
+
+/* Forms */
+input[type=text],
+input[type=password],
+input[type=email],
+input[type=url],
+input[type=number],
+textarea {
+ background: #fafafa;
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,0.1);
+ border: 1px solid #ddd;
+ color: #888;
+}
+input[type=text]:focus,
+input[type=password]:focus,
+input[type=email]:focus,
+input[type=url]:focus,
+input[type=number]:focus,
+textarea:focus {
+ color: #373737;
+}
+textarea {
+ padding-left: 3px;
+ width: 98%;
+}
+input[type=text],
+input[type=password],
+input[type=email],
+input[type=url],
+input[type=number] {
+ padding: 3px;
+}
+input#s {
+ background: url(images/search.png) no-repeat 5px 6px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ font-size: 14px;
+ height: 22px;
+ line-height: 1.2em;
+ padding: 4px 10px 4px 28px;
+}
+input#searchsubmit {
+ display: none;
+}
+
+/* Links */
+a {
+ color: #1982d1;
+ text-decoration: none;
+}
+a:focus,
+a:active,
+a:hover {
+ text-decoration: underline;
+}
+
+/* Assistive text */
+.assistive-text {
+ position: absolute !important;
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+}
+#access a.assistive-text:focus {
+ background: #eee;
+ border-bottom: 1px solid #ddd;
+ color: #1982d1;
+ clip: auto !important;
+ font-size: 12px;
+ position: absolute;
+ text-decoration: underline;
+ top: 0;
+ left: 7.6%;
+}
+
+
+/* =Header
+----------------------------------------------- */
+
+#branding {
+ border-top: 2px solid #bbb;
+ padding-bottom: 10px;
+ position: relative;
+ z-index: 9999;
+}
+#site-title {
+ margin-right: 270px;
+ padding: 3.65625em 0 0;
+}
+#site-title a {
+ color: #111;
+ font-size: 30px;
+ font-weight: bold;
+ line-height: 36px;
+ text-decoration: none;
+}
+#site-title a:hover,
+#site-title a:focus,
+#site-title a:active {
+ color: #1982d1;
+}
+#site-description {
+ color: #7a7a7a;
+ font-size: 14px;
+ margin: 0 270px 3.65625em 0;
+}
+#branding img {
+ height: auto;
+ display: block;
+ width: 100%;
+}
+
+
+/* =Menu
+-------------------------------------------------------------- */
+
+#access {
+ background: #222; /* Show a solid color for older browsers */
+ background: -moz-linear-gradient(#252525, #0a0a0a);
+ background: -o-linear-gradient(#252525, #0a0a0a);
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#252525), to(#0a0a0a)); /* older webkit syntax */
+ background: -webkit-linear-gradient(#252525, #0a0a0a);
+ -webkit-box-shadow: rgba(0, 0, 0, 0.4) 0px 1px 2px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.4) 0px 1px 2px;
+ box-shadow: rgba(0, 0, 0, 0.4) 0px 1px 2px;
+ clear: both;
+ display: block;
+ float: left;
+ margin: 0 auto 6px;
+ width: 100%;
+}
+#access ul {
+ font-size: 13px;
+ list-style: none;
+ margin: 0 0 0 -0.8125em;
+ padding-left: 0;
+}
+#access li {
+ float: left;
+ position: relative;
+}
+#access a {
+ color: #eee;
+ display: block;
+ line-height: 3.333em;
+ padding: 0 1.2125em;
+ text-decoration: none;
+}
+#access ul ul {
+ -moz-box-shadow: 0 3px 3px rgba(0,0,0,0.2);
+ -webkit-box-shadow: 0 3px 3px rgba(0,0,0,0.2);
+ box-shadow: 0 3px 3px rgba(0,0,0,0.2);
+ display: none;
+ float: left;
+ margin: 0;
+ position: absolute;
+ top: 3.333em;
+ left: 0;
+ width: 188px;
+ z-index: 99999;
+}
+#access ul ul ul {
+ left: 100%;
+ top: 0;
+}
+#access ul ul a {
+ background: #f9f9f9;
+ border-bottom: 1px dotted #ddd;
+ color: #444;
+ font-size: 13px;
+ font-weight: normal;
+ height: auto;
+ line-height: 1.4em;
+ padding: 10px 10px;
+ width: 168px;
+}
+#access li:hover > a,
+#access ul ul :hover > a,
+#access a:focus {
+ background: #efefef;
+}
+#access li:hover > a,
+#access a:focus {
+ background: #f9f9f9; /* Show a solid color for older browsers */
+ background: -moz-linear-gradient(#f9f9f9, #e5e5e5);
+ background: -o-linear-gradient(#f9f9f9, #e5e5e5);
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
+ background: -webkit-linear-gradient(#f9f9f9, #e5e5e5);
+ color: #373737;
+}
+#access ul li:hover > ul {
+ display: block;
+}
+#access .current-menu-item > a,
+#access .current-menu-ancestor > a,
+#access .current_page_item > a,
+#access .current_page_ancestor > a {
+ font-weight: bold;
+}
+
+/* Search Form */
+#branding #searchform {
+ position: absolute;
+ top: 3.8em;
+ right: 7.6%;
+ text-align: right;
+}
+#branding #searchform div {
+ margin: 0;
+}
+#branding #s {
+ float: right;
+ -webkit-transition-duration: 400ms;
+ -webkit-transition-property: width, background;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-duration: 400ms;
+ -moz-transition-property: width, background;
+ -moz-transition-timing-function: ease;
+ -o-transition-duration: 400ms;
+ -o-transition-property: width, background;
+ -o-transition-timing-function: ease;
+ width: 72px;
+}
+#branding #s:focus {
+ background-color: #f9f9f9;
+ width: 196px;
+}
+#branding #searchsubmit {
+ display: none;
+}
+#branding .only-search #searchform {
+ top: 5px;
+ z-index: 1;
+}
+#branding .only-search #s {
+ background-color: #666;
+ border-color: #000;
+ color: #222;
+}
+#branding .only-search #s,
+#branding .only-search #s:focus {
+ width: 85%;
+}
+#branding .only-search #s:focus {
+ background-color: #bbb;
+}
+#branding .with-image #searchform {
+ top: auto;
+ bottom: -27px;
+ max-width: 195px;
+}
+#branding .only-search + #access div {
+ padding-right: 205px;
+}
+
+
+/* =Content
+----------------------------------------------- */
+
+#main {
+ clear: both;
+ padding: 1.625em 0 0;
+}
+.page-title {
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ margin: 0 0 2.6em;
+ text-transform: uppercase;
+}
+.page-title a {
+ font-size: 12px;
+ font-weight: bold;
+ letter-spacing: 0;
+ text-transform: none;
+}
+.hentry,
+.no-results {
+ border-bottom: 1px solid #ddd;
+ margin: 0 0 1.625em;
+ padding: 0 0 1.625em;
+ position: relative;
+}
+.hentry:last-child,
+.no-results {
+ border-bottom: none;
+}
+.blog .sticky .entry-header .entry-meta {
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ position: absolute !important;
+}
+.entry-title,
+.entry-header .entry-meta {
+ padding-right: 76px;
+}
+.entry-title {
+ clear: both;
+ color: #222;
+ font-size: 26px;
+ font-weight: bold;
+ line-height: 1.5em;
+ padding-bottom: .3em;
+ padding-top: 15px;
+}
+.entry-title,
+.entry-title a {
+ color: #222;
+ text-decoration: none;
+}
+.entry-title a:hover,
+.entry-title a:focus,
+.entry-title a:active {
+ color: #1982d1;
+}
+.entry-meta {
+ color: #666;
+ clear: both;
+ font-size: 12px;
+ line-height: 18px;
+}
+.entry-meta a {
+ font-weight: bold;
+}
+.single-author .entry-meta .by-author {
+ display: none;
+}
+.entry-content,
+.entry-summary {
+ padding: 1.625em 0 0;
+}
+.entry-content h1,
+.entry-content h2,
+.comment-content h1,
+.comment-content h2 {
+ color: #000;
+ font-weight: bold;
+ margin: 0 0 .8125em;
+}
+.entry-content h3,
+.comment-content h3 {
+ font-size: 10px;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+.entry-content table,
+.comment-content table {
+ border-bottom: 1px solid #ddd;
+ margin: 0 0 1.625em;
+ width: 100%;
+}
+.entry-content th,
+.comment-content th {
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+.entry-content td,
+.comment-content td {
+ border-top: 1px solid #ddd;
+ padding: 6px 10px 6px 0;
+}
+.entry-content #s {
+ width: 75%;
+}
+.comment-content ul,
+.comment-content ol {
+ margin-bottom: 1.625em;
+}
+.comment-content ul ul,
+.comment-content ol ol,
+.comment-content ul ol,
+.comment-content ol ul {
+ margin-bottom: 0;
+}
+dl.gallery-item {
+ margin: 0;
+}
+.page-link {
+ clear: both;
+ display: block;
+ margin: 0 0 1.625em;
+}
+.page-link a {
+ background: #eee;
+ color: #373737;
+ margin: 0;
+ padding: 2px 3px;
+ text-decoration: none;
+}
+.page-link a:hover {
+ background: #888;
+ color: #fff;
+ font-weight: bold;
+}
+.page-link span {
+ margin-right: 6px;
+}
+.entry-meta .edit-link a,
+.commentlist .edit-link a {
+ background: #eee;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ color: #666;
+ float: right;
+ font-size: 12px;
+ line-height: 1.5em;
+ font-weight: 300;
+ text-decoration: none;
+ padding: 0 8px;
+}
+.entry-meta .edit-link a:hover,
+.commentlist .edit-link a:hover {
+ background: #888;
+ color: #fff;
+}
+.entry-content .edit-link {
+ clear: both;
+ display: block;
+}
+
+/* Images */
+.entry-content img,
+.comment-content img,
+.widget img {
+ max-width: 100%; /* Fluid images for posts, comments, and widgets */
+}
+img[class*="align"],
+img[class*="wp-image-"],
+img[class*="attachment-"] {
+ height: auto; /* Make sure images with WordPress-added height and width attributes are scaled correctly */
+}
+img.size-full,
+img.size-large {
+ max-width: 97.5%;
+ width: auto; /* Prevent stretching of full-size and large-size images with height and width attributes in IE8 */
+ height: auto; /* Make sure images with WordPress-added height and width attributes are scaled correctly */
+}
+.entry-content img.wp-smiley {
+ border: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+img.alignleft,
+img.alignright,
+img.aligncenter {
+ margin-bottom: 1.625em;
+}
+p img,
+.wp-caption {
+ margin-top: 0.4em;
+}
+.wp-caption {
+ background: #eee;
+ margin-bottom: 1.625em;
+ max-width: 96%;
+ padding: 9px;
+}
+.wp-caption img {
+ display: block;
+ margin: -2px 0 0 -2px;
+ max-width: 98%;
+}
+.wp-caption .wp-caption-text,
+.gallery-caption {
+ color: #666;
+ font-family: Georgia, serif;
+ font-size: 12px;
+}
+.wp-caption .wp-caption-text {
+ margin-bottom: 0.6em;
+ padding: 10px 0 5px 40px;
+ position: relative;
+}
+.wp-caption .wp-caption-text:before {
+ color: #666;
+ content: '\2014';
+ font-size: 14px;
+ font-style: normal;
+ font-weight: bold;
+ margin-right: 5px;
+ position: absolute;
+ left: 10px;
+ top: 7px;
+}
+#content .gallery {
+ margin: 0 auto 1.625em;
+}
+#content .gallery a img {
+ border: none;
+}
+img#wpstats {
+ display: block;
+ margin: 0 auto 1.625em;
+}
+#content .gallery-columns-4 .gallery-item {
+ width: 23%;
+ padding-right: 2%;
+}
+#content .gallery-columns-4 .gallery-item img {
+ width: 100%;
+ height: auto;
+}
+
+/* Image borders */
+img[class*="align"],
+img[class*="wp-image-"],
+#content .gallery .gallery-icon img {/* Add fancy borders to all WordPress-added images but not things like badges and icons and the like */
+ border: 1px solid #ddd;
+ padding: 6px;
+ max-width: 97.5%;
+}
+.wp-caption img {
+ border-color: #eee;
+}
+a:focus img[class*="align"],
+a:hover img[class*="align"],
+a:active img[class*="align"],
+a:focus img[class*="wp-image-"],
+a:hover img[class*="wp-image-"],
+a:active img[class*="wp-image-"],
+#content .gallery .gallery-icon a:focus img,
+#content .gallery .gallery-icon a:hover img,
+#content .gallery .gallery-icon a:active img {/* Add some useful style to those fancy borders for linked images ... */
+ background: #eee;
+ border-color: #bbb;
+}
+.wp-caption a:focus img,
+.wp-caption a:active img,
+.wp-caption a:hover img {/* ... including captioned images! */
+ background: #fff;
+ border-color: #ddd;
+}
+
+/* Make sure videos and embeds fit their containers */
+embed,
+iframe,
+object {
+ max-width: 100%;
+}
+.entry-content .twitter-tweet-rendered {
+ max-width: 100% !important; /* Override the Twitter embed fixed width */
+}
+
+/* Password Protected Posts */
+.post-password-required .entry-header .comments-link {
+ margin: 1.625em 0 0;
+}
+.post-password-required input[type=password] {
+ margin: 0.8125em 0;
+}
+.post-password-required input[type=password]:focus {
+ background: #f7f7f7;
+}
+
+/* Author Info */
+#author-info {
+ font-size: 12px;
+ overflow: hidden;
+}
+.singular #author-info {
+ background: #f9f9f9;
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 2.2em -35.6% 0 -35.4%;
+ padding: 20px 35.4%;
+}
+.archive #author-info {
+ border-bottom: 1px solid #ddd;
+ margin: 0 0 2.2em;
+ padding: 0 0 2.2em;
+}
+#author-avatar {
+ float: left;
+ margin-right: -78px;
+}
+#author-avatar img {
+ background: #fff;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0 1px 2px #bbb;
+ -moz-box-shadow: 0 1px 2px #bbb;
+ box-shadow: 0 1px 2px #bbb;
+ padding: 3px;
+}
+#author-description {
+ float: left;
+ margin-left: 108px;
+}
+#author-description h2 {
+ color: #000;
+ font-size: 15px;
+ font-weight: bold;
+ margin: 5px 0 10px;
+}
+
+/* Comments link */
+.entry-header .comments-link a {
+ background: #eee url(images/comment-bubble.png) no-repeat;
+ color: #666;
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 35px;
+ overflow: hidden;
+ padding: 0 0 0;
+ position: absolute;
+ top: 1.5em;
+ right: 0;
+ text-align: center;
+ text-decoration: none;
+ width: 43px;
+ height: 36px;
+}
+.entry-header .comments-link a:hover,
+.entry-header .comments-link a:focus,
+.entry-header .comments-link a:active {
+ background-color: #1982d1;
+ color: #fff;
+ color: rgba(255,255,255,0.8);
+}
+.entry-header .comments-link .leave-reply {
+ visibility: hidden;
+}
+
+/*
+Post Formats Headings
+To hide the headings, display: none the ".entry-header .entry-format" selector,
+and remove the padding rules below.
+*/
+.entry-header .entry-format {
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ position: absolute;
+ text-transform: uppercase;
+ top: -5px;
+}
+.entry-header hgroup .entry-title {
+ padding-top: 15px;
+}
+article.format-aside .entry-content,
+article.format-link .entry-content,
+article.format-status .entry-content {
+ padding: 20px 0 0;
+}
+article.format-status .entry-content {
+ min-height: 65px;
+}
+.recent-posts .entry-header .entry-format {
+ display: none;
+}
+.recent-posts .entry-header hgroup .entry-title {
+ padding-top: 0;
+}
+
+/* Singular content styles for Posts and Pages */
+.singular .hentry {
+ border-bottom: none;
+ padding: 4.875em 0 0;
+ position: relative;
+}
+.singular.page .hentry {
+ padding: 3.5em 0 0;
+}
+.singular .entry-title {
+ color: #000;
+ font-size: 36px;
+ font-weight: bold;
+ line-height: 48px;
+}
+.singular .entry-title,
+.singular .entry-header .entry-meta {
+ padding-right: 0;
+}
+.singular .entry-header .entry-meta {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+blockquote.pull {
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1.6125em;
+ margin: 0 0 1.625em;
+ text-align: center;
+}
+.singular blockquote.pull {
+ margin: 0 -22.25% 1.625em;
+}
+.pull.alignleft {
+ margin: 0 1.625em 0 0;
+ text-align: right;
+}
+.singular .pull.alignleft {
+ margin: 0 1.625em 0 -22.25%;
+}
+.pull.alignright {
+ margin: 0 0 0 1.625em;
+ text-align: left;
+}
+blockquote.pull.alignleft,
+blockquote.pull.alignright {
+ width: 33%;
+}
+.singular .pull.alignright {
+ margin: 0 -22.25% 0 1.625em;
+}
+.singular blockquote.pull.alignleft,
+.singular blockquote.pull.alignright {
+ width: 33%;
+}
+.singular .entry-meta .edit-link a {
+ bottom: auto;
+ left: 50px;
+ position: absolute;
+ right: auto;
+ top: 80px;
+}
+
+
+/* =Aside
+----------------------------------------------- */
+
+.format-aside .entry-title,
+.format-aside .entry-header .comments-link {
+ display: none;
+}
+.singular .format-aside .entry-title {
+ display: block;
+}
+.format-aside .entry-content {
+ padding: 0;
+}
+.singular .format-aside .entry-content {
+ padding: 1.625em 0 0;
+}
+
+
+/* =Link
+----------------------------------------------- */
+
+.format-link .entry-title,
+.format-link .entry-header .comments-link {
+ display: none;
+}
+.singular .format-link .entry-title {
+ display: block;
+}
+.format-link .entry-content {
+ padding: 0;
+}
+.singular .format-link .entry-content {
+ padding: 1.625em 0 0;
+}
+
+
+/* =Gallery
+----------------------------------------------- */
+
+.format-gallery .gallery-thumb {
+ float: left;
+ display: block;
+ margin: .375em 1.625em 0 0;
+ max-width: 100%;
+}
+
+
+/* =Status
+----------------------------------------------- */
+
+.format-status .entry-title,
+.format-status .entry-header .comments-link {
+ display: none;
+}
+.singular .format-status .entry-title {
+ display: block;
+}
+.format-status .entry-content {
+ padding: 0;
+}
+.singular .format-status .entry-content {
+ padding: 1.625em 0 0;
+}
+.format-status img.avatar {
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0 1px 2px #ccc;
+ -moz-box-shadow: 0 1px 2px #ccc;
+ box-shadow: 0 1px 2px #ccc;
+ float: left;
+ margin: 4px 10px 2px 0;
+ padding: 0;
+}
+
+
+/* =Quote
+----------------------------------------------- */
+
+.format-quote blockquote {
+ color: #555;
+ font-size: 17px;
+ margin: 0;
+}
+
+
+/* =Image
+----------------------------------------------- */
+
+.indexed.format-image .entry-header {
+ min-height: 61px; /* Prevent the comment icon from colliding with the image when there is no title */
+}
+.indexed.format-image .entry-content {
+ padding-top: 0.5em;
+}
+.indexed.format-image .entry-content p {
+ margin: 1em 0;
+}
+.indexed.format-image .entry-content p:first-child,
+.indexed.format-image .entry-content p:first-child a,
+.indexed.format-image .entry-content p:first-child img {
+ display: block;
+ margin: 0;
+}
+.indexed.format-image .entry-content .wp-caption .wp-caption-text {
+ margin: 0;
+ padding-bottom: 1em;
+}
+.indexed.format-image footer.entry-meta {
+ background: #ddd;
+ overflow: hidden;
+ padding: 4%;
+ max-width: 96%;
+}
+.indexed.format-image div.entry-meta {
+ display: inline-block;
+ float: left;
+ width: 35%;
+}
+.indexed.format-image div.entry-meta + div.entry-meta {
+ float: none;
+ width: 65%;
+}
+.indexed.format-image .entry-meta span.cat-links,
+.indexed.format-image .entry-meta span.tag-links,
+.indexed.format-image .entry-meta span.comments-link {
+ display: block;
+}
+.indexed.format-image footer.entry-meta a {
+ color: #444;
+}
+.indexed.format-image footer.entry-meta a:hover {
+ color: #fff;
+}
+#content .indexed.format-image img {
+ border: none;
+ max-width: 100%;
+ padding: 0;
+}
+.indexed.format-image .wp-caption {
+ background: #111;
+ margin-bottom: 0;
+ max-width: 96%;
+ padding: 2% 2% 0;
+}
+.indexed.format-image .wp-caption .wp-caption-text {
+ color: #ddd;
+}
+.indexed.format-image .wp-caption .wp-caption-text:before {
+ color: #444;
+}
+.indexed.format-image a:hover img {
+ opacity: 0.8;
+}
+
+
+/* =error404
+----------------------------------------------- */
+
+.error404 #main #searchform {
+ background: #f9f9f9;
+ border: 1px solid #ddd;
+ border-width: 1px 0;
+ margin: 0 -8.9% 1.625em;
+ overflow: hidden;
+ padding: 1.625em 8.9%;
+}
+.error404 #main #s {
+ width: 95%;
+}
+.error404 #main .widget {
+ clear: none;
+ float: left;
+ margin-right: 3.7%;
+ width: 30.85%;
+}
+.error404 #main .widget_archive {
+ margin-right: 0;
+}
+.error404 #main .widget_tag_cloud {
+ float: none;
+ margin-right: 0;
+ width: 100%;
+}
+.error404 .widgettitle {
+ font-size: 10px;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+
+
+/* =Showcase
+----------------------------------------------- */
+
+h1.showcase-heading {
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+
+/* Intro */
+article.intro {
+ background: #f9f9f9;
+ border-bottom: none;
+ margin: -1.855em -8.9% 1.625em;
+ padding: 0 8.9%;
+}
+article.intro .entry-title {
+ display: none;
+}
+article.intro .entry-content {
+ color: #111;
+ font-size: 16px;
+ padding: 1.625em 0 0.625em;
+}
+article.intro .edit-link a {
+ background: #aaa;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ color: #fff;
+ font-size: 12px;
+ padding: 0 8px;
+ position: absolute;
+ top: 30px;
+ right: 20px;
+ text-decoration: none;
+}
+article.intro .edit-link a:hover,
+article.intro .edit-link a:focus,
+article.intro .edit-link a:active {
+ background: #777;
+}
+
+/* Featured post */
+section.featured-post {
+ float: left;
+ margin: -1.625em -8.9% 1.625em;
+ padding: 1.625em 8.9% 0;
+ position: relative;
+ width: 100%;
+}
+section.featured-post .hentry {
+ border: none;
+ color: #666;
+ margin: 0;
+}
+section.featured-post .entry-meta {
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ position: absolute !important;
+}
+
+/* Small featured post */
+section.featured-post .attachment-small-feature {
+ float: right;
+ height: auto;
+ margin: 0 -8.9% 1.625em 0;
+ max-width: 59%;
+ position: relative;
+ right: -15px;
+}
+section.featured-post.small {
+ padding-top: 0;
+}
+section.featured-post .attachment-small-feature:hover,
+section.featured-post .attachment-small-feature:focus,
+section.featured-post .attachment-small-feature:active {
+ opacity: .8;
+}
+article.feature-image.small {
+ float: left;
+ margin: 0 0 1.625em;
+ width: 45%;
+}
+article.feature-image.small .entry-title {
+ line-height: 1.2em;
+}
+article.feature-image.small .entry-summary {
+ color: #555;
+ font-size: 13px;
+}
+article.feature-image.small .entry-summary p a {
+ background: #222;
+ color: #eee;
+ display: block;
+ left: -23.8%;
+ padding: 9px 26px 9px 85px;
+ position: relative;
+ text-decoration: none;
+ top: 20px;
+ width: 180px;
+ z-index: 1;
+}
+article.feature-image.small .entry-summary p a:hover {
+ background: #1982d1;
+ color: #eee;
+ color: rgba(255,255,255,0.8);
+}
+
+/* Large featured post */
+section.feature-image.large {
+ border: none;
+ max-height: 288px;
+ padding: 0;
+ width: 100%;
+}
+section.feature-image.large .showcase-heading {
+ display: none;
+}
+section.feature-image.large .hentry {
+ border-bottom: none;
+ left: 9%;
+ margin: 1.625em 9% 0 0;
+ position: absolute;
+ top: 0;
+}
+article.feature-image.large .entry-title a {
+ background: #222;
+ background: rgba(0,0,0,0.8);
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ color: #fff;
+ display: inline-block;
+ font-weight: 300;
+ padding: .2em 20px;
+}
+section.feature-image.large:hover .entry-title a,
+section.feature-image.large .entry-title:hover a {
+ background: #eee;
+ background: rgba(255,255,255,0.8);
+ color: #222;
+}
+article.feature-image.large .entry-summary {
+ display: none;
+}
+section.feature-image.large img {
+ display: block;
+ height: auto;
+ max-width: 117.9%;
+ padding: 0 0 6px;
+}
+
+/* Featured Slider */
+.featured-posts {
+ border-bottom: 1px solid #ddd;
+ display: block;
+ height: 328px;
+ margin: 1.625em -8.9% 20px;
+ max-width: 1000px;
+ padding: 0;
+ position: relative;
+ overflow: hidden;
+}
+.featured-posts .showcase-heading {
+ padding-left: 8.9%;
+}
+.featured-posts section.featured-post {
+ background: #fff;
+ height: 288px;
+ left: 0;
+ margin: 0;
+ position: absolute;
+ top: 30px;
+ width: auto;
+}
+.featured-posts section.featured-post.large {
+ max-width: 100%;
+ overflow: hidden;
+}
+.featured-posts section.featured-post {
+ -webkit-transition-duration: 200ms;
+ -webkit-transition-property: opacity, visibility;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-duration: 200ms;
+ -moz-transition-property: opacity, visibility;
+ -moz-transition-timing-function: ease;
+}
+.featured-posts section.featured-post {
+ opacity: 0;
+ visibility: hidden;
+}
+.featured-posts #featured-post-1 {
+ opacity: 1;
+ visibility: visible;
+}
+.featured-post .feature-text:after,
+.featured-post .feature-image.small:after {
+ content: ' ';
+ background: -moz-linear-gradient(top, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0)), color-stop(100%,rgba(255,255,255,1))); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 100%); /* W3C */
+ width: 100%;
+ height: 45px;
+ position: absolute;
+ top: 230px;
+}
+.featured-post .feature-image.small:after {
+ top: 253px;
+}
+#content .feature-slider {
+ top: 5px;
+ right: 8.9%;
+ overflow: visible;
+ position: absolute;
+}
+.feature-slider ul {
+ list-style-type: none;
+ margin: 0;
+}
+.feature-slider li {
+ float: left;
+ margin: 0 6px;
+}
+.feature-slider a {
+ background: #3c3c3c;
+ background: rgba(60,60,60,0.9);
+ -moz-border-radius: 12px;
+ border-radius: 12px;
+ -webkit-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.5), inset 0 0 2px rgba(255,255,255,0.5);
+ -moz-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.5), inset 0 0 2px rgba(255,255,255,0.5);
+ box-shadow: inset 1px 1px 5px rgba(0,0,0,0.5), inset 0 0 2px rgba(255,255,255,0.5);
+ display: block;
+ width: 14px;
+ height: 14px;
+}
+.feature-slider a.active {
+ background: #1982d1;
+ -webkit-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.4), inset 0 0 2px rgba(255,255,255,0.8);
+ -moz-box-shadow: inset 1px 1px 5px rgba(0,0,0,0.4), inset 0 0 2px rgba(255,255,255,0.8);
+ box-shadow: inset 1px 1px 5px rgba(0,0,0,0.4), inset 0 0 2px rgba(255,255,255,0.8);
+ cursor: default;
+ opacity: 0.5;
+}
+
+/* Recent Posts */
+section.recent-posts {
+ padding: 0 0 1.625em;
+}
+section.recent-posts .hentry {
+ border: none;
+ margin: 0;
+}
+section.recent-posts .other-recent-posts {
+ border-bottom: 1px solid #ddd;
+ list-style: none;
+ margin: 0;
+}
+section.recent-posts .other-recent-posts li {
+ padding: 0.3125em 0;
+ position: relative;
+}
+section.recent-posts .other-recent-posts .entry-title {
+ border-top: 1px solid #ddd;
+ font-size: 17px;
+}
+section.recent-posts .other-recent-posts a[rel="bookmark"] {
+ color: #373737;
+ float: left;
+ max-width: 84%;
+}
+section.recent-posts .other-recent-posts a[rel="bookmark"]:after {
+ content: '-';
+ color: transparent;
+ font-size: 11px;
+}
+section.recent-posts .other-recent-posts a[rel="bookmark"]:hover {
+}
+section.recent-posts .other-recent-posts .comments-link a,
+section.recent-posts .other-recent-posts .comments-link > span {
+ border-bottom: 2px solid #999;
+ bottom: -2px;
+ color: #444;
+ display: block;
+ font-size: 10px;
+ font-weight: 500;
+ line-height: 2.76333em;
+ padding: 0.3125em 0 0.3125em 1em;
+ position: absolute;
+ right: 0;
+ text-align: right;
+ text-transform: uppercase;
+ z-index: 1;
+}
+section.recent-posts .other-recent-posts .comments-link > span {
+ border-color: #bbb;
+ color: #888;
+}
+section.recent-posts .other-recent-posts .comments-link a:hover {
+ color: #1982d1;
+ border-color: #1982d1;
+}
+section.recent-posts .other-recent-posts li:after {
+ clear: both;
+ content: '.';
+ display: block;
+ height: 0;
+ visibility: hidden;
+}
+
+
+/* =Attachments
+----------------------------------------------- */
+
+.image-attachment div.attachment {
+ background: #f9f9f9;
+ border: 1px solid #ddd;
+ border-width: 1px 0;
+ margin: 0 -8.9% 1.625em;
+ overflow: hidden;
+ padding: 1.625em 1.625em 0;
+ text-align: center;
+}
+.image-attachment div.attachment img {
+ display: block;
+ height: auto;
+ margin: 0 auto 1.625em;
+ max-width: 100%;
+}
+.image-attachment div.attachment a img {
+ border-color: #f9f9f9;
+}
+.image-attachment div.attachment a:focus img,
+.image-attachment div.attachment a:hover img,
+.image-attachment div.attachment a:active img {
+ border-color: #ddd;
+ background: #fff;
+}
+.image-attachment .entry-caption p {
+ font-size: 10px;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ margin: 0 0 2.6em;
+ text-transform: uppercase;
+}
+
+
+/* =Navigation
+-------------------------------------------------------------- */
+
+#content nav {
+ clear: both;
+ overflow: hidden;
+ padding: 0 0 1.625em;
+}
+#content nav a {
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 2.2em;
+}
+#nav-above {
+ padding: 0 0 1.625em;
+}
+#nav-above {
+ display: none;
+}
+.paged #nav-above {
+ display: block;
+}
+.nav-previous {
+ float: left;
+ width: 50%;
+}
+.nav-next {
+ float: right;
+ text-align: right;
+ width: 50%;
+}
+#content nav .meta-nav {
+ font-weight: normal;
+}
+
+/* Singular navigation */
+#nav-single {
+ float: right;
+ position: relative;
+ top: -0.3em;
+ text-align: right;
+ z-index: 1;
+}
+#nav-single .nav-previous,
+#nav-single .nav-next {
+ width: auto;
+}
+#nav-single .nav-next {
+ padding-left: .5em;
+}
+#nav-single .nav-previous {
+ padding-right: .5em;
+}
+
+
+/* =Widgets
+----------------------------------------------- */
+
+.widget-area {
+ font-size: 12px;
+}
+.widget {
+ word-wrap: break-word;
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ hyphens: auto;
+ clear: both;
+ margin: 0 0 2.2em;
+}
+.widget-title {
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ letter-spacing: 0.1em;
+ line-height: 2.6em;
+ text-transform: uppercase;
+}
+.widget ul {
+ font-size: 15px;
+ margin: 0;
+}
+.widget ul ul {
+ margin-left: 1.5em;
+}
+.widget ul li {
+ color: #777;
+ font-size: 13px;
+}
+.widget a {
+ font-weight: bold;
+ text-decoration: none;
+}
+.widget a:hover,
+.widget a:focus,
+.widget a:active {
+ text-decoration: underline;
+}
+
+/* Search Widget */
+.widget_search form {
+ margin: 0 0 1.625em;
+}
+.widget_search #s {
+ width: 77%;
+}
+.widget_search #searchsubmit {
+ background: #ddd;
+ border: 1px solid #ccc;
+ -webkit-box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.09);
+ -moz-box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.09);
+ box-shadow: inset 0px -1px 1px rgba(0, 0, 0, 0.09);
+ color: #888;
+ font-size: 13px;
+ line-height: 25px;
+ position: relative;
+ top: -2px;
+}
+.widget_search #searchsubmit:active {
+ background: #1982d1;
+ border-color: #0861a5;
+ -webkit-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0px 1px 1px rgba(0, 0, 0, 0.1);
+ color: #bfddf3;
+}
+
+/* Ephemera Widget */
+section.ephemera ol,
+.widget_twentyeleven_ephemera ol {
+ list-style: square;
+ margin: 5px 0 0;
+}
+.widget_twentyeleven_ephemera .widget-entry-title {
+ font-size: 15px;
+ font-weight: bold;
+ padding: 0;
+}
+.widget_twentyeleven_ephemera .comments-link a,
+.widget_twentyeleven_ephemera .comments-link > span {
+ color: #666;
+ display: block;
+ font-size: 10px;
+ font-weight: 500;
+ line-height: 2.76333em;
+ text-transform: uppercase;
+}
+section.ephemera .entry-title .comments-link a:hover,
+.widget_twentyeleven_ephemera .entry-title .comments-link a:hover {
+}
+section.ephemera .entry-title a span {
+ color: #29628d;
+}
+
+/* Twitter */
+.widget_twitter li {
+ list-style-type: none;
+ margin-bottom: 14px;
+}
+.widget_twitter .timesince {
+ display: block;
+ font-size: 11px;
+ margin-right: -10px;
+ text-align: right;
+}
+
+/* Widget Image */
+.widget_image img {
+ border: 0;
+ padding: 0;
+ height: auto;
+ max-width: 100%;
+}
+
+/* Calendar Widget */
+
+.widget_calendar #wp-calendar {
+ color: #555;
+ width: 95%;
+ text-align: center;
+}
+.widget_calendar #wp-calendar caption,
+.widget_calendar #wp-calendar td,
+.widget_calendar #wp-calendar th {
+ text-align: center;
+}
+.widget_calendar #wp-calendar caption {
+ font-size: 11px;
+ font-weight: 500;
+ padding: 5px 0 3px 0;
+ text-transform: uppercase;
+}
+.widget_calendar #wp-calendar th {
+ background: #f4f4f4;
+ border-top: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ font-weight: bold;
+}
+.widget_calendar #wp-calendar tfoot td {
+ background: #f4f4f4;
+ border-top: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+}
+
+
+/* =Comments
+----------------------------------------------- */
+
+#comments-title {
+ color: #666;
+ font-size: 10px;
+ font-weight: 500;
+ line-height: 2.6em;
+ padding: 0 0 2.6em;
+ text-transform: uppercase;
+}
+.nopassword,
+.nocomments {
+ color: #aaa;
+ font-size: 24px;
+ font-weight: 100;
+ margin: 26px 0;
+ text-align: center;
+}
+.commentlist {
+ list-style: none;
+ margin: 0 auto;
+ width: 68.9%;
+}
+.content .commentlist,
+.page-template-sidebar-page-php .commentlist {
+ width: 100%; /* reset the width for the one-column and sidebar page layout */
+}
+.commentlist > li.comment {
+ background: #f6f6f6;
+ border: 1px solid #ddd;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ margin: 0 0 1.625em;
+ padding: 1.625em;
+ position: relative;
+}
+.commentlist .pingback {
+ margin: 0 0 1.625em;
+ padding: 0 1.625em;
+}
+.commentlist .children {
+ list-style: none;
+ margin: 0;
+}
+.commentlist .children li.comment {
+ background: #fff;
+ border-left: 1px solid #ddd;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+ margin: 1.625em 0 0;
+ padding: 1.625em;
+ position: relative;
+}
+.commentlist .children li.comment .fn {
+ display: block;
+}
+.comment-meta .fn {
+ font-style: normal;
+}
+.comment-meta {
+ color: #666;
+ font-size: 12px;
+ line-height: 2.2em;
+}
+.commentlist .children li.comment .comment-meta {
+ line-height: 1.625em;
+ margin-left: 50px;
+}
+.commentlist .children li.comment .comment-content {
+ margin: 1.625em 0 0;
+ word-wrap: break-word;
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ hyphens: auto;
+}
+.comment-meta a {
+ font-weight: bold;
+}
+.comment-meta a:focus,
+.comment-meta a:active,
+.comment-meta a:hover {
+}
+.commentlist .avatar {
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0 1px 2px #ccc;
+ -moz-box-shadow: 0 1px 2px #ccc;
+ box-shadow: 0 1px 2px #ccc;
+ left: -102px;
+ padding: 0;
+ position: absolute;
+ top: 0;
+}
+.commentlist > li:before {
+ content: url(images/comment-arrow.png);
+ left: -21px;
+ position: absolute;
+}
+.commentlist > li.pingback:before {
+ content: '';
+}
+.commentlist .children .avatar {
+ background: none;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ left: 2.2em;
+ padding: 0;
+ top: 2.2em;
+}
+a.comment-reply-link {
+ background: #eee;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ color: #666;
+ display: inline-block;
+ font-size: 12px;
+ padding: 0 8px;
+ text-decoration: none;
+}
+a.comment-reply-link:hover,
+a.comment-reply-link:focus,
+a.comment-reply-link:active {
+ background: #888;
+ color: #fff;
+}
+a.comment-reply-link > span {
+ display: inline-block;
+ position: relative;
+ top: -1px;
+}
+
+/* Post author highlighting */
+.commentlist > li.bypostauthor {
+ background: #ddd;
+ border-color: #d3d3d3;
+}
+.commentlist > li.bypostauthor .comment-meta {
+ color: #575757;
+}
+.commentlist > li.bypostauthor .comment-meta a:focus,
+.commentlist > li.bypostauthor .comment-meta a:active,
+.commentlist > li.bypostauthor .comment-meta a:hover {
+}
+.commentlist > li.bypostauthor:before {
+ content: url(images/comment-arrow-bypostauthor.png);
+}
+
+/* Post Author threaded comments */
+.commentlist .children > li.bypostauthor {
+ background: #ddd;
+ border-color: #d3d3d3;
+}
+
+/* sidebar-page.php comments */
+/* Make sure we have room for our comment avatars */
+.page-template-sidebar-page-php .commentlist > li.comment,
+.page-template-sidebar-page-php.commentlist .pingback {
+ margin-left: 102px;
+ width: auto;
+}
+/* And a full-width comment form */
+.page-template-sidebar-page-php #respond {
+ width: auto;
+}
+
+/* Comment Form */
+#respond {
+ background: #ddd;
+ border: 1px solid #d3d3d3;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ margin: 0 auto 1.625em;
+ padding: 1.625em;
+ position: relative;
+ width: 68.9%;
+}
+#respond input[type="text"],
+#respond textarea {
+ background: #fff;
+ border: 4px solid #eee;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ -webkit-box-shadow: inset 0 1px 3px rgba(204,204,204,0.95);
+ -moz-box-shadow: inset 0 1px 3px rgba(204,204,204,0.95);
+ box-shadow: inset 0 1px 3px rgba(204,204,204,0.95);
+ position: relative;
+ padding: 10px;
+ text-indent: 80px;
+}
+#respond .comment-form-author,
+#respond .comment-form-email,
+#respond .comment-form-url,
+#respond .comment-form-comment {
+ position: relative;
+}
+#respond .comment-form-author label,
+#respond .comment-form-email label,
+#respond .comment-form-url label,
+#respond .comment-form-comment label {
+ background: #eee;
+ -webkit-box-shadow: 1px 2px 2px rgba(204,204,204,0.8);
+ -moz-box-shadow: 1px 2px 2px rgba(204,204,204,0.8);
+ box-shadow: 1px 2px 2px rgba(204,204,204,0.8);
+ color: #555;
+ display: inline-block;
+ font-size: 13px;
+ left: 4px;
+ min-width: 60px;
+ padding: 4px 10px;
+ position: relative;
+ top: 40px;
+ z-index: 1;
+}
+#respond input[type="text"]:focus,
+#respond textarea:focus {
+ text-indent: 0;
+ z-index: 1;
+}
+#respond textarea {
+ resize: vertical;
+ width: 95%;
+}
+#respond .comment-form-author .required,
+#respond .comment-form-email .required {
+ color: #bd3500;
+ font-size: 22px;
+ font-weight: bold;
+ left: 75%;
+ position: absolute;
+ z-index: 1;
+}
+#respond .comment-notes,
+#respond .logged-in-as {
+ font-size: 13px;
+}
+#respond p {
+ margin: 10px 0;
+}
+#respond .form-submit {
+ float: right;
+ margin: -20px 0 10px;
+}
+#respond input#submit {
+ background: #222;
+ border: none;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
+ -moz-box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
+ box-shadow: 0px 1px 2px rgba(0,0,0,0.3);
+ color: #eee;
+ cursor: pointer;
+ font-size: 15px;
+ margin: 20px 0;
+ padding: 5px 42px 5px 22px;
+ position: relative;
+ left: 30px;
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
+}
+#respond input#submit:active {
+ background: #1982d1;
+ color: #bfddf3;
+}
+#respond #cancel-comment-reply-link {
+ color: #666;
+ margin-left: 10px;
+ text-decoration: none;
+}
+#respond .logged-in-as a:hover,
+#respond #cancel-comment-reply-link:hover {
+ text-decoration: underline;
+}
+.commentlist #respond {
+ margin: 1.625em 0 0;
+ width: auto;
+}
+#reply-title {
+ color: #373737;
+ font-size: 24px;
+ font-weight: bold;
+ line-height: 30px;
+}
+#cancel-comment-reply-link {
+ color: #888;
+ display: block;
+ font-size: 10px;
+ font-weight: normal;
+ line-height: 2.2em;
+ letter-spacing: 0.05em;
+ position: absolute;
+ right: 1.625em;
+ text-decoration: none;
+ text-transform: uppercase;
+ top: 1.1em;
+}
+#cancel-comment-reply-link:focus,
+#cancel-comment-reply-link:active,
+#cancel-comment-reply-link:hover {
+ color: #ff4b33;
+}
+#respond label {
+ line-height: 2.2em;
+}
+#respond input[type=text] {
+ display: block;
+ height: 24px;
+ width: 75%;
+}
+#respond p {
+ font-size: 12px;
+}
+p.comment-form-comment {
+ margin: 0;
+}
+.form-allowed-tags {
+ display: none;
+}
+
+
+/* =Footer
+----------------------------------------------- */
+
+#colophon {
+ clear: both;
+}
+#supplementary {
+ border-top: 1px solid #ddd;
+ padding: 1.625em 7.6%;
+ overflow: hidden;
+}
+
+/* Two Footer Widget Areas */
+#supplementary.two .widget-area {
+ float: left;
+ margin-right: 3.7%;
+ width: 48.1%;
+}
+#supplementary.two .widget-area + .widget-area {
+ margin-right: 0;
+}
+
+/* Three Footer Widget Areas */
+#supplementary.three .widget-area {
+ float: left;
+ margin-right: 3.7%;
+ width: 30.85%;
+}
+#supplementary.three .widget-area + .widget-area + .widget-area {
+ margin-right: 0;
+}
+
+/* Site Generator Line */
+#site-generator {
+ background: #f9f9f9;
+ border-top: 1px solid #ddd;
+ color: #666;
+ font-size: 12px;
+ line-height: 2.2em;
+ padding: 2.2em 0.5em;
+ text-align: center;
+}
+#site-generator a {
+ color: #555;
+ font-weight: bold;
+}
+
+
+/* =Responsive Structure
+----------------------------------------------- */
+
+@media (max-width: 800px) {
+ /* Simplify the basic layout */
+ #main #content {
+ margin: 0 7.6%;
+ width: auto;
+ }
+ #nav-below {
+ border-bottom: 1px solid #ddd;
+ margin-bottom: 1.625em;
+ }
+ #main #secondary {
+ float: none;
+ margin: 0 7.6%;
+ width: auto;
+ }
+ /* Simplify the showcase template */
+ .page-template-showcase-php .featured-posts {
+ min-height: 280px;
+ }
+ .featured-posts section.featured-post {
+ height: auto;
+ }
+ .page-template-showcase-php section.recent-posts {
+ float: none;
+ margin: 0;
+ width: 100%;
+ }
+ .page-template-showcase-php #main .widget-area {
+ float: none;
+ margin: 0;
+ width: auto;
+ }
+ .page-template-showcase-php .other-recent-posts {
+ border-bottom: 1px solid #ddd;
+ }
+ /* Simplify the showcase template when small feature */
+ section.featured-post .attachment-small-feature,
+ .one-column section.featured-post .attachment-small-feature {
+ border: none;
+ display: block;
+ float: left;
+ height: auto;
+ margin: 0.625em auto 1.025em;
+ max-width: 30%;
+ position: static;
+ }
+ article.feature-image.small {
+ float: right;
+ margin: 0 0 1.625em;
+ width: 64%;
+ }
+ .one-column article.feature-image.small .entry-summary {
+ height: auto;
+ }
+ article.feature-image.small .entry-summary p a {
+ left: 0;
+ padding-left: 20px;
+ padding-right: 20px;
+ width: auto;
+ }
+ /* Remove the margin on singular articles */
+ .singular .entry-header,
+ .singular .entry-content,
+ .singular footer.entry-meta,
+ .singular #comments-title {
+ width: 100%;
+ }
+ /* Simplify the pullquotes and pull styles */
+ .singular blockquote.pull {
+ margin: 0 0 1.625em;
+ }
+ .singular .pull.alignleft {
+ margin: 0 1.625em 0 0;
+ }
+ .singular .pull.alignright {
+ margin: 0 0 0 1.625em;
+ }
+ .singular .entry-meta .edit-link a {
+ left: 0;
+ position: absolute;
+ top: 40px;
+ }
+ .singular #author-info {
+ margin: 2.2em -8.8% 0;
+ padding: 20px 8.8%;
+ }
+ /* Make sure we have room for our comment avatars */
+ .commentlist {
+ width: 100%;
+ }
+ .commentlist > li.comment,
+ .commentlist .pingback {
+ margin-left: 102px;
+ width: auto;
+ }
+ /* And a full-width comment form */
+ #respond {
+ width: auto;
+ }
+ /* No need to float footer widgets at this size */
+ #colophon #supplementary .widget-area {
+ float: none;
+ margin-right: 0;
+ width: auto;
+ }
+ /* No need to float 404 widgets at this size */
+ .error404 #main .widget {
+ float: none;
+ margin-right: 0;
+ width: auto;
+ }
+}
+@media (max-width: 650px) {
+ /* @media (max-width: 650px) Reduce font-sizes for better readability on smaller devices */
+ body, input, textarea {
+ font-size: 13px;
+ }
+ #site-title a {
+ font-size: 24px;
+ }
+ #site-description {
+ font-size: 12px;
+ }
+ #access ul {
+ font-size: 12px;
+ }
+ article.intro .entry-content {
+ font-size: 12px;
+ }
+ .entry-title {
+ font-size: 21px;
+ }
+ .featured-post .entry-title {
+ font-size: 14px;
+ }
+ .singular .entry-title {
+ font-size: 28px;
+ }
+ .entry-meta {
+ font-size: 12px;
+ }
+ blockquote {
+ margin: 0;
+ }
+ blockquote.pull {
+ font-size: 17px;
+ }
+ /* Reposition the site title and description slightly */
+ #site-title {
+ padding: 5.30625em 0 0;
+ }
+ #site-title,
+ #site-description {
+ margin-right: 0;
+ }
+ /* Make sure the logo and search form don't collide */
+ #branding #searchform {
+ top: 1.625em !important;
+ }
+ /* Floated content doesn't work well at this size */
+ .alignleft,
+ .alignright {
+ display: block;
+ float: none;
+ margin-left: 0;
+ margin-right: 0;
+ }
+ /* Make sure the post-post navigation doesn't collide with anything */
+ #nav-single {
+ display: block;
+ position: static;
+ }
+ .singular .hentry {
+ padding: 1.625em 0 0;
+ }
+ .singular.page .hentry {
+ padding: 1.625em 0 0;
+ }
+ /* Talking avatars take up too much room at this size */
+ .commentlist > li.comment,
+ .commentlist > li.pingback {
+ margin-left: 0 !important;
+ }
+ .commentlist .avatar {
+ background: transparent;
+ display: block;
+ padding: 0;
+ position: static;
+ }
+ .commentlist .children .avatar {
+ background: none;
+ left: 2.2em;
+ padding: 0;
+ position: absolute;
+ top: 2.2em;
+ }
+ /* Use the available space in the smaller comment form */
+ #respond input[type="text"] {
+ width: 95%;
+ }
+ #respond .comment-form-author .required,
+ #respond .comment-form-email .required {
+ left: 95%;
+ }
+ #content .gallery-columns-3 .gallery-item {
+ width: 31%;
+ padding-right: 2%;
+ }
+ #content .gallery-columns-3 .gallery-item img {
+ width: 100%;
+ height: auto;
+ }
+}
+@media (max-width: 450px) {
+ #content .gallery-columns-2 .gallery-item {
+ width: 45%;
+ padding-right: 4%;
+ }
+ #content .gallery-columns-2 .gallery-item img {
+ width: 100%;
+ height: auto;
+ }
+}
+@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
+ body {
+ padding: 0;
+ }
+ #page {
+ margin-top: 0;
+ }
+ #branding {
+ border-top: none;
+ }
+}
+
+
+/* =Print
+----------------------------------------------- */
+
+@media print {
+ body {
+ background: none !important;
+ font-size: 10pt;
+ }
+ footer.entry-meta a[rel=bookmark]:link:after,
+ footer.entry-meta a[rel=bookmark]:visited:after {
+ content: " [" attr(href) "] "; /* Show URLs */
+ }
+ #page {
+ clear: both !important;
+ display: block !important;
+ float: none !important;
+ max-width: 100%;
+ position: relative !important;
+ }
+ #branding {
+ border-top: none !important;
+ padding: 0;
+ }
+ #branding hgroup {
+ margin: 0;
+ }
+ #site-title a {
+ font-size: 21pt;
+ }
+ #site-description {
+ font-size: 10pt;
+ }
+ #branding #searchform {
+ display: none;
+ }
+ #branding img {
+ display: none;
+ }
+ #access {
+ display: none;
+ }
+ #main {
+ border-top: none;
+ box-shadow: none;
+ }
+ #primary {
+ float: left;
+ margin: 0;
+ width: 100%;
+ }
+ #content {
+ margin: 0;
+ width: auto;
+ }
+ .singular #content {
+ margin: 0;
+ width: 100%;
+ }
+ .singular .entry-header .entry-meta {
+ position: static;
+ }
+ .entry-meta .edit-link a {
+ display: none;
+ }
+ #content nav {
+ display: none;
+ }
+ .singular .entry-header,
+ .singular .entry-content,
+ .singular footer.entry-meta,
+ .singular #comments-title {
+ margin: 0;
+ width: 100%;
+ }
+ .singular .hentry {
+ padding: 0;
+ }
+ .entry-title,
+ .singular .entry-title {
+ font-size: 21pt;
+ }
+ .entry-meta {
+ font-size: 10pt;
+ }
+ .entry-header .comments-link {
+ display: none;
+ }
+ .page-link {
+ display: none;
+ }
+ .singular #author-info {
+ background: none;
+ border-bottom: none;
+ border-top: none;
+ margin: 2.2em 0 0;
+ padding: 0;
+ }
+ #respond {
+ display: none;
+ }
+ .widget-area {
+ display: none;
+ }
+ #colophon {
+ display: none;
+ }
+
+ /* Comments */
+ .commentlist > li.comment {
+ background: none;
+ border: 1px solid #ddd;
+ -moz-border-radius: 3px 3px 3px 3px;
+ border-radius: 3px 3px 3px 3px;
+ margin: 0 auto 1.625em;
+ padding: 1.625em;
+ position: relative;
+ width: auto;
+ }
+ .commentlist .avatar {
+ height: 39px;
+ left: 2.2em;
+ top: 2.2em;
+ width: 39px;
+ }
+ .commentlist li.comment .comment-meta {
+ line-height: 1.625em;
+ margin-left: 50px;
+ }
+ .commentlist li.comment .fn {
+ display: block;
+ }
+ .commentlist li.comment .comment-content {
+ margin: 1.625em 0 0;
+ }
+ .commentlist .comment-edit-link {
+ display: none;
+ }
+ .commentlist > li::before,
+ .commentlist > li.bypostauthor::before {
+ content: '';
+ }
+ .commentlist .reply {
+ display: none;
+ }
+
+ /* Post author highlighting */
+ .commentlist > li.bypostauthor {
+ color: #444;
+ }
+ .commentlist > li.bypostauthor .comment-meta {
+ color: #666;
+ }
+ .commentlist > li.bypostauthor:before {
+ content: none;
+ }
+
+ /* Post Author threaded comments */
+ .commentlist .children > li.bypostauthor {
+ background: #fff;
+ border-color: #ddd;
+ }
+ .commentlist .children > li.bypostauthor > article,
+ .commentlist .children > li.bypostauthor > article .comment-meta {
+ color: #666;
+ }
+}
+
+
+/* =IE7
+----------------------------------------------- */
+
+#ie7 article.intro {
+ margin-left: -7.6%;
+ margin-right: -7.6%;
+ padding-left: -7.6%;
+ padding-right: -7.6%;
+ max-width: 1000px;
+}
+#ie7 .featured-posts {
+ margin: 0 -7.6%;
+}
+#ie7 .featured-post {
+ margin-left: 0;
+ margin-right: 0;
+ max-width: 100%;
+}
+#ie7 section.recent-posts {
+ margin-right: 7.6%;
+}
+
+
+/* =IE8
+----------------------------------------------- */
+
+#ie8 section.feature-image.large img {
+ width: auto;
+}
+#ie8 section.featured-post .attachment-small-feature {
+ max-width: none;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyeleven/tag.php b/src/wp-content/themes/twentyeleven/tag.php
new file mode 100644
index 0000000000..8180a8cf49
--- /dev/null
+++ b/src/wp-content/themes/twentyeleven/tag.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * The template used to display Tag Archive pages
+ *
+ * @package WordPress
+ * @subpackage Twenty_Eleven
+ * @since Twenty Eleven 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title"><?php
+ printf( __( 'Tag Archives: %s', 'twentyeleven' ), '<span>' . single_tag_title( '', false ) . '</span>' );
+ ?></h1>
+
+ <?php
+ $tag_description = tag_description();
+ if ( ! empty( $tag_description ) )
+ echo apply_filters( 'tag_archive_meta', '<div class="tag-archive-meta">' . $tag_description . '</div>' );
+ ?>
+ </header>
+
+ <?php twentyeleven_content_nav( 'nav-above' ); ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php
+ /* Include the Post-Format-specific template for the content.
+ * If you want to overload this in a child theme then include a file
+ * called content-___.php (where ___ is the Post Format name) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+ ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyeleven_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyeleven' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyfourteen/404.php b/src/wp-content/themes/twentyfourteen/404.php
new file mode 100644
index 0000000000..0de18a3c98
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/404.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * The template for displaying 404 pages (Not Found).
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <article id="post-0" class="post error404 not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Oops! That page can&rsquo;t be found.', 'twentyfourteen' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <p><?php _e( 'It looks like nothing was found at this location. Maybe try one of the links below or a search?', 'twentyfourteen' ); ?></p>
+
+ <?php get_search_form(); ?>
+
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 .post .error404 .not-found -->
+
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+<?php get_sidebar( 'content' ); ?>
+
+<?php get_sidebar(); ?>
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/archive.php b/src/wp-content/themes/twentyfourteen/archive.php
new file mode 100644
index 0000000000..089c5d78fa
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/archive.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * The template for displaying Archive pages.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+<section id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title">
+ <?php
+ if ( is_category() ) {
+ printf( __( 'Category Archives: %s', 'twentyfourteen' ), '<span>' . single_cat_title( '', false ) . '</span>' );
+
+ } elseif ( is_tag() ) {
+ printf( __( 'Tag Archives: %s', 'twentyfourteen' ), '<span>' . single_tag_title( '', false ) . '</span>' );
+
+ } elseif ( is_author() ) {
+ /* Queue the first post, that way we know
+ * what author we're dealing with (if that is the case).
+ */
+ the_post();
+ printf( __( 'Author Archives: %s', 'twentyfourteen' ), '<span class="vcard"><a class="url fn n" href="' . get_author_posts_url( get_the_author_meta( 'ID' ) ) . '" title="' . esc_attr( get_the_author() ) . '" rel="me">' . get_the_author() . '</a></span>' );
+ /* Since we called the_post() above, we need to
+ * rewind the loop back to the beginning that way
+ * we can run the loop properly, in full.
+ */
+ rewind_posts();
+
+ } elseif ( is_day() ) {
+ printf( __( 'Daily Archives: %s', 'twentyfourteen' ), '<span>' . get_the_date() . '</span>' );
+
+ } elseif ( is_month() ) {
+ printf( __( 'Monthly Archives: %s', 'twentyfourteen' ), '<span>' . get_the_date( 'F Y' ) . '</span>' );
+
+ } elseif ( is_year() ) {
+ printf( __( 'Yearly Archives: %s', 'twentyfourteen' ), '<span>' . get_the_date( 'Y' ) . '</span>' );
+
+ } else {
+ _e( 'Archives', 'twentyfourteen' );
+
+ }
+ ?>
+ </h1>
+ <?php
+ if ( is_category() ) {
+ // show an optional category description
+ $category_description = category_description();
+ if ( ! empty( $category_description ) )
+ echo apply_filters( 'category_archive_meta', '<div class="taxonomy-description">' . $category_description . '</div>' );
+
+ } elseif ( is_tag() ) {
+ // show an optional tag description
+ $tag_description = tag_description();
+ if ( ! empty( $tag_description ) )
+ echo apply_filters( 'tag_archive_meta', '<div class="taxonomy-description">' . $tag_description . '</div>' );
+ }
+ ?>
+ </header><!-- .page-header -->
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php twentyfourteen_get_template_part(); ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyfourteen_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <?php get_template_part( 'no-results', 'archive' ); ?>
+
+ <?php endif; ?>
+
+ </div><!-- #content .site-content -->
+</section><!-- #primary .content-area -->
+
+<?php get_sidebar( 'content' ); ?>
+
+<?php get_sidebar(); ?>
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/comments.php b/src/wp-content/themes/twentyfourteen/comments.php
new file mode 100644
index 0000000000..d47ac25b0c
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/comments.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * The template for displaying Comments.
+ *
+ * The area of the page that contains both current comments
+ * and the comment form. The actual display of comments is
+ * handled by a callback to twentyfourteen_comment() which is
+ * located in the functions.php file.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+
+<?php
+ /*
+ * If the current post is protected by a password and
+ * the visitor has not yet entered the password we will
+ * return early without loading the comments.
+ */
+ if ( post_password_required() )
+ return;
+?>
+
+ <div id="comments" class="comments-area">
+
+ <?php // You can start editing here -- including this comment! ?>
+
+ <?php if ( have_comments() ) : ?>
+ <h2 class="comments-title">
+ <?php
+ printf( _n( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'twentyfourteen' ),
+ number_format_i18n( get_comments_number() ), '<span>' . get_the_title() . '</span>' );
+ ?>
+ </h2>
+
+ <?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?>
+ <nav role="navigation" id="comment-nav-above" class="site-navigation comment-navigation clearfix">
+ <h1 class="assistive-text"><?php _e( 'Comment navigation', 'twentyfourteen' ); ?></h1>
+ <div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'twentyfourteen' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'twentyfourteen' ) ); ?></div>
+ </nav><!-- #comment-nav-above .site-navigation .comment-navigation -->
+ <?php endif; // check for comment navigation ?>
+
+ <ol class="commentlist">
+ <?php
+ /* Loop through and list the comments. Tell wp_list_comments()
+ * to use twentyfourteen_comment() to format the comments.
+ * If you want to overload this in a child theme then you can
+ * define twentyfourteen_comment() and that will be used instead.
+ * See twentyfourteen_comment() in inc/template-tags.php for more.
+ */
+ wp_list_comments( array( 'callback' => 'twentyfourteen_comment' ) );
+ ?>
+ </ol><!-- .commentlist -->
+
+ <?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?>
+ <nav role="navigation" id="comment-nav-below" class="site-navigation comment-navigation clearfix">
+ <h1 class="assistive-text"><?php _e( 'Comment navigation', 'twentyfourteen' ); ?></h1>
+ <div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'twentyfourteen' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'twentyfourteen' ) ); ?></div>
+ </nav><!-- #comment-nav-below .site-navigation .comment-navigation -->
+ <?php endif; // check for comment navigation ?>
+
+ <?php endif; // have_comments() ?>
+
+ <?php
+ // If comments are closed and there are comments, let's leave a little note, shall we?
+ if ( ! comments_open() && '0' != get_comments_number() && post_type_supports( get_post_type(), 'comments' ) ) :
+ ?>
+ <p class="nocomments"><?php _e( 'Comments are closed.', 'twentyfourteen' ); ?></p>
+ <?php endif; ?>
+
+ <?php comment_form(); ?>
+
+</div><!-- #comments .comments-area -->
diff --git a/src/wp-content/themes/twentyfourteen/content-featured-post.php b/src/wp-content/themes/twentyfourteen/content-featured-post.php
new file mode 100644
index 0000000000..63cd36a458
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/content-featured-post.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class( 'clearfix' ); ?>>
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentyfourteen' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="<?php the_ID(); ?>" class="attachment-featured-featured">
+ <?php
+ $images = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'menu_order', 'order' => 'ASC', 'numberposts' => 1 ) );
+
+ if ( '' != get_the_post_thumbnail() ) :
+ the_post_thumbnail( 'featured-thumbnail-featured' );
+ elseif ( $images ) :
+ $image = array_shift( $images );
+ echo wp_get_attachment_image( $image->ID, 'featured-thumbnail-featured' );
+ else : ?>
+ <img src="<?php echo get_template_directory_uri(); ?>/images/placeholder.png" alt="" class="featured-thumbnail-featured" /><?php
+ endif;
+ ?>
+ </a>
+
+ <div class="entry-wrap">
+ <header class="entry-header">
+ <div class="entry-meta">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyfourteen' ) );
+ if ( $categories_list && twentyfourteen_categorized_blog() ) :
+ ?>
+ <span class="cat-links">
+ <?php echo $categories_list; ?>
+ </span>
+ <?php endif; // End if categories ?>
+ </div><!-- .entry-meta -->
+ <h1 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-summary clearfix">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ </div>
+
+</article><!-- #post-<?php the_ID(); ?> --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/content-page.php b/src/wp-content/themes/twentyfourteen/content-page.php
new file mode 100644
index 0000000000..d5c7f0bc9e
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/content-page.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * The template used for displaying page content in page.php
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content clearfix">
+ <?php the_content(); ?>
+ <?php
+ wp_link_pages( array(
+ 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
+ 'after' => '</div>',
+ 'link_before' => '<span>',
+ 'link_after' => '</span>'
+ ) );
+ ?>
+ <?php edit_post_link( __( 'Edit', 'twentyfourteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-content -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyfourteen/content-post-format.php b/src/wp-content/themes/twentyfourteen/content-post-format.php
new file mode 100644
index 0000000000..6c693ea7fe
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/content-post-format.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+$format = get_post_format();
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class( 'clearfix' ); ?>>
+ <?php
+ if ( 'gallery' == $format ) :
+ $images = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'menu_order', 'order' => 'ASC' ) );
+ if ( $images ) :
+ $image = array_shift( $images ); ?>
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentyfourteen' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="<?php the_ID(); ?>" class="attachment-featured-thumbnail">
+ <?php echo wp_get_attachment_image( $image->ID, 'featured-thumbnail-large' ); ?>
+ </a><?php
+ endif;
+ endif;
+ ?>
+
+ <header class="entry-header">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyfourteen' ) );
+ if ( $categories_list && twentyfourteen_categorized_blog() && 'post' == get_post_type() ) :
+ ?>
+ <div class="entry-meta">
+ <span class="cat-links"><?php echo $categories_list; ?></span>
+ </div>
+ <?php endif; ?>
+
+ <?php
+ /* Show title only if it exists */
+ the_title( '<h1 class="entry-title"><a href="' . get_permalink() . '" rel="bookmark">', '</a></h1>' );
+ ?>
+
+ <div class="entry-meta">
+ <span class="post-format">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( get_post_format() ) ); ?>" title="<?php echo esc_attr( sprintf( __( 'All %s posts', 'twentyfourteen' ), get_post_format_string( get_post_format() ) ) ); ?>"><?php echo get_post_format_string( get_post_format() ); ?></a>
+ </span>
+
+ <?php
+ if ( 'post' == get_post_type() )
+ twentyfourteen_posted_on();
+ ?>
+
+ <?php if ( ! post_password_required() && ( comments_open() || '0' != get_comments_number() ) ) : ?>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyfourteen' ), __( '1 Comment', 'twentyfourteen' ), __( '% Comments', 'twentyfourteen' ) ); ?></span>
+ <?php endif; ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyfourteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content clearfix">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ) ); ?>
+ <?php
+ wp_link_pages( array(
+ 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
+ 'after' => '</div>',
+ 'link_before' => '<span>',
+ 'link_after' => '</span>'
+ ) );
+ ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php if ( ( 'quote' == $format ) || ( 'aside' == $format ) ) : ?>
+ <div class="entry-meta">
+ <?php the_title( '<h1 class="entry-title"><a href="' . get_permalink() . '" rel="bookmark">', '</a></h1>' ); ?>
+ </div>
+ <?php endif; ?>
+
+ <?php
+ $tag_list = get_the_tag_list();
+ if ( '' != $tag_list && 'post' == get_post_type() ) :
+ ?>
+ <span class="tag-links"><?php echo $tag_list; ?></span>
+ <?php endif; // End if $tag_list ?>
+ </footer><!-- .entry-meta -->
+
+</article><!-- #post-<?php the_ID(); ?> --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/content-recent-formatted-post.php b/src/wp-content/themes/twentyfourteen/content-recent-formatted-post.php
new file mode 100644
index 0000000000..48bb7db9d2
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/content-recent-formatted-post.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+if ( isset( $GLOBALS['content_width'] ) )
+ $GLOBALS['content_width'] = 306;
+
+$format = get_post_format();
+if ( false === $format )
+ $format = 'standard';
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class( 'clearfix' ); ?>>
+ <div class="entry-content clearfix">
+ <?php
+ if ( 'gallery' == $format ) :
+ $featured_image = get_the_post_thumbnail( get_the_ID(), 'featured-thumbnail-formatted' );
+ $images = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'menu_order', 'order' => 'ASC' ) );
+ if ( $images ) :
+ $total_images = count( $images );
+ if ( empty( $featured_image ) ) {
+ $image = array_shift( $images );
+ $featured_image = wp_get_attachment_image( $image->ID, 'featured-thumbnail-formatted' );
+ }
+ ?>
+ <a href="<?php the_permalink(); ?>"><?php echo $featured_image; ?></a>
+ <p class="wp-caption-text"><?php printf( _n( 'This gallery contains <a %1$s>%2$s photo</a>.', 'This gallery contains <a %1$s>%2$s photos</a>.', $total_images, 'twentyfourteen' ),
+ 'href="' . get_permalink() . '" title="' . esc_attr( sprintf( __( 'Permalink to %s', 'twentyfourteen' ), the_title_attribute( 'echo=0' ) ) ) . '" rel="bookmark"',
+ number_format_i18n( $total_images )
+ ); ?></p><?php
+ else :
+ the_excerpt();
+ endif;
+ else :
+ the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ) );
+ endif;
+ ?>
+ </div><!-- .entry-content -->
+
+ <header class="entry-header">
+ <div class="entry-meta">
+ <?php
+ if ( 'link' != $format ) :
+ the_title( '<h1 class="entry-title"><a href="' . get_permalink() . '" title="' . esc_attr( sprintf( __( 'Permalink to %s', 'twentyfourteen' ), the_title_attribute( 'echo=0' ) ) ) . '" rel="bookmark">', '</a></h1>' );
+ endif;
+ ?>
+ <?php twentyfourteen_posted_on(); ?>
+ <?php if ( ! post_password_required() && ( comments_open() || '0' != get_comments_number() ) ) : ?>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyfourteen' ), __( '1 Comment', 'twentyfourteen' ), __( '% Comments', 'twentyfourteen' ) ); ?></span>
+ <?php endif; ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+</article> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/content-single.php b/src/wp-content/themes/twentyfourteen/content-single.php
new file mode 100644
index 0000000000..6be2984c8f
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/content-single.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+$format = get_post_format();
+if ( false === $format )
+ $format = 'standard';
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <?php if ( ( 'video' != $format ) && ( 'image' != $format ) && ( 'aside' != $format ) && ( 'link' != $format ) && ( 'quote' != $format ) ) : ?>
+ <div class="attachment-featured-thumbnail">
+ <?php
+ if ( '' != get_the_post_thumbnail() )
+ the_post_thumbnail( 'featured-thumbnail-large' );
+ ?>
+ </div>
+ <?php endif; ?>
+
+ <header class="entry-header">
+ <div class="entry-meta">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyfourteen' ) );
+ if ( $categories_list && twentyfourteen_categorized_blog() ) :
+ ?>
+ <span class="cat-links">
+ <?php echo $categories_list; ?>
+ </span>
+ <?php endif; // End if categories ?>
+ </div><!-- .entry-meta -->
+
+ <?php if ( ( 'standard' == $format ) || ( 'video' == $format ) || ( 'image' == $format ) || ( 'gallery' == $format ) ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php endif; ?>
+
+ <div class="entry-meta">
+ <?php if ( 'standard' != $format ) : ?>
+ <span class="post-format">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( get_post_format() ) ); ?>" title="<?php echo esc_attr( sprintf( __( 'All %s posts', 'twentyfourteen' ), get_post_format_string( get_post_format() ) ) ); ?>"><?php echo get_post_format_string( get_post_format() ); ?></a>
+ </span>
+ <?php endif; ?>
+
+ <?php twentyfourteen_posted_on(); ?>
+
+ <?php if ( ! post_password_required() && ( comments_open() || '0' != get_comments_number() ) ) : ?>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyfourteen' ), __( '1 Comment', 'twentyfourteen' ), __( '% Comments', 'twentyfourteen' ) ); ?></span>
+ <?php endif; ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyfourteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content clearfix">
+ <?php the_content(); ?>
+ <?php
+ wp_link_pages( array(
+ 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
+ 'after' => '</div>',
+ 'link_before' => '<span>',
+ 'link_after' => '</span>'
+ ) );
+ ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php if ( ( 'quote' == $format ) || ( 'aside' == $format ) ) : ?>
+ <div class="entry-meta">
+ <?php the_title( '<h1 class="entry-title"><a href="' . get_permalink() . '" rel="bookmark">', '</a></h1>' ); ?>
+ </div><!-- .entry-meta -->
+ <?php endif; ?>
+
+ <?php
+ $tag_list = get_the_tag_list();
+ if ( '' != $tag_list ) :
+ ?>
+ <span class="tag-links">
+ <?php echo $tag_list; ?>
+ </span>
+ <?php endif; // End if $tag_list ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post-<?php the_ID(); ?> -->
diff --git a/src/wp-content/themes/twentyfourteen/content.php b/src/wp-content/themes/twentyfourteen/content.php
new file mode 100644
index 0000000000..02e214bfd9
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/content.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+$format = get_post_format();
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class( 'clearfix' ); ?>>
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentyfourteen' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="<?php the_ID(); ?>" class="attachment-featured-thumbnail">
+ <?php
+ if ( '' != get_the_post_thumbnail() )
+ the_post_thumbnail( 'featured-thumbnail-large' );
+ ?>
+ </a>
+
+ <header class="entry-header">
+ <?php
+ /* translators: used between list items, there is a space after the comma */
+ $categories_list = get_the_category_list( __( ', ', 'twentyfourteen' ) );
+ if ( $categories_list && twentyfourteen_categorized_blog() && 'post' == get_post_type() ) :
+ ?>
+ <div class="entry-meta">
+ <span class="cat-links"><?php echo $categories_list; ?></span>
+ </div>
+ <?php endif; ?>
+
+ <h1 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
+
+ <div class="entry-meta">
+ <?php if ( 'gallery' == $format ) : ?>
+ <span class="post-format">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( get_post_format() ) ); ?>" title="<?php echo esc_attr( sprintf( __( 'All %s posts', 'twentyfourteen' ), get_post_format_string( get_post_format() ) ) ); ?>"><?php echo get_post_format_string( get_post_format() ); ?></a>
+ </span>
+ <?php endif; ?>
+
+ <?php
+ if ( 'post' == get_post_type() )
+ twentyfourteen_posted_on();
+ ?>
+
+ <?php if ( ! post_password_required() && ( comments_open() || '0' != get_comments_number() ) ) : ?>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyfourteen' ), __( '1 Comment', 'twentyfourteen' ), __( '% Comments', 'twentyfourteen' ) ); ?></span>
+ <?php endif; ?>
+
+ <?php edit_post_link( __( 'Edit', 'twentyfourteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : ?>
+ <div class="entry-summary clearfix">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content clearfix">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ) ); ?>
+ <?php
+ wp_link_pages( array(
+ 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
+ 'after' => '</div>',
+ 'link_before' => '<span>',
+ 'link_after' => '</span>'
+ ) );
+ ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <?php
+ $tag_list = get_the_tag_list();
+ if ( '' != $tag_list && 'post' == get_post_type() ) :
+ ?>
+ <footer class="entry-meta">
+ <span class="tag-links"><?php echo $tag_list; ?></span>
+ </footer><!-- .entry-meta -->
+ <?php endif; // End if $tag_list ?>
+</article><!-- #post-<?php the_ID(); ?> --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/featured-content.php b/src/wp-content/themes/twentyfourteen/featured-content.php
new file mode 100644
index 0000000000..79bb599f40
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/featured-content.php
@@ -0,0 +1,19 @@
+<div class="featured-content-wrapper">
+ <div id="featured-content" class="featured-content clearfix">
+
+ <?php
+ do_action( 'twentyfourteen_featured_posts_before' );
+
+ $featured_posts = twentyfourteen_get_featured_posts();
+ foreach ( (array) $featured_posts as $order => $post ) :
+ setup_postdata( $post );
+ get_template_part( 'content', 'featured-post' );
+ endforeach;
+
+ do_action( 'twentyfourteen_featured_posts_after' );
+
+ wp_reset_postdata();
+ ?>
+
+ </div><!-- .featured-content -->
+</div><!-- .featured-content-wrapper -->
diff --git a/src/wp-content/themes/twentyfourteen/fonts/copying.txt b/src/wp-content/themes/twentyfourteen/fonts/copying.txt
new file mode 100644
index 0000000000..3f00a7a63f
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/fonts/copying.txt
@@ -0,0 +1,7 @@
+Genericons is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+The fonts are distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.eot b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.eot
new file mode 100644
index 0000000000..5144ec58eb
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.eot
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.svg b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.svg
new file mode 100644
index 0000000000..3e1d112dd8
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="genericonsregular" horiz-adv-x="2048" >
+<font-face units-per-em="2048" ascent="1638" descent="-410" />
+<missing-glyph horiz-adv-x="500" />
+<glyph unicode="&#xe000;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf100;" d="M512 1280v128h1024v-128h-1024zM512 1152h640v-128h-640v128zM1536 1024h-256v128h256v-128zM512 896h256v-128h-256v128zM1536 768h-640v128h640v-128zM1280 512h-768v128h768v-128z" />
+<glyph unicode="&#xf101;" d="M1024 1792q209 0 385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5t103 385.5t279.5 279.5t385.5 103zM1024 768q106 0 181 75t75 181t-75 181t-181 75t-181 -75t-75 -181t75 -181t181 -75z" />
+<glyph unicode="&#xf102;" d="M1280 1664l128 -256h512v-1024h-1792v896l512 128l128 256h512zM256 1600h256v-96l-256 -64v160zM1024 512q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1024 1280q133 0 226.5 -93.5t93.5 -226.5 t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5t93.5 226.5t226.5 93.5z" />
+<glyph unicode="&#xf103;" d="M1024 1024h-896v384h896v-384zM1152 512v896h896v-896h-896zM512 512h-384v384h384v-384zM1024 512h-384v384h384v-384z" />
+<glyph unicode="&#xf104;" d="M512 384v1280l1152 -640z" />
+<glyph unicode="&#xf105;" d="M896 384v664q-113 40 -184.5 138t-71.5 222q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5q0 -124 -71.5 -222t-184.5 -138v-536z" />
+<glyph unicode="&#xf106;" d="M768 640h-384l128 768h512zM1152 640l128 768h512l-256 -768h-384z" />
+<glyph unicode="&#xf107;" d="M870 1450l135 136q75 75 181 75t181 -75l91 -91q75 -75 75 -181t-75 -181l-136 -136l-90 91l135 136q38 37 38 90t-38 91l-90 90q-38 38 -91 38t-90 -38l-136 -135zM1186 1224l-362 -362l-90 90l362 362zM553 771l90 -90q38 -38 91 -38t90 38l136 135l91 -90l-136 -136 q-75 -75 -181 -75t-181 75l-91 91q-75 75 -75 181t75 181l136 135l91 -90l-136 -136q-38 -37 -38 -90t38 -91z" />
+<glyph unicode="&#xf108;" d="M256 1792h1024q96 0 176 -80t80 -176v-384q0 -96 -80 -176t-176 -80h-448l-448 -448v448h-128q-96 0 -176 80t-80 176v384q0 96 80 176t176 80zM1664 1152v384q96 0 176 -80t80 -176v-384q0 -96 -80 -176t-176 -80h-128v-448l-448 448h-320l128 128h384q168 0 276 108 t108 276z" />
+<glyph unicode="&#xf109;" d="M256 768v512h384l384 384v-1280l-384 384h-384zM1386 1386l91 91q88 -89 137.5 -206t49.5 -247q0 -87 -23 -170t-64.5 -153.5t-99.5 -129.5l-91 91q71 71 110.5 164.5t39.5 197.5t-39.5 197.5t-110.5 164.5zM1205 1205l91 91q53 -54 82.5 -124t29.5 -148t-29.5 -148 t-82.5 -124l-91 91q75 75 75 181t-75 181z" />
+<glyph unicode="&#xf200;" d="M1024 2048q212 0 402 -79.5t326.5 -216t216 -326.5t79.5 -402t-79.5 -402t-216 -326.5t-326.5 -216t-402 -79.5t-402 79.5t-326.5 216t-216 326.5t-79.5 402t79.5 402t216 326.5t326.5 216t402 79.5zM1280 384v-224q293 98 466.5 327.5t173.5 536.5q0 176 -73 341.5 t-194.5 287t-287 194.5t-341.5 73t-341.5 -73t-287 -194.5t-194.5 -287t-73 -341.5q0 -307 173.5 -536.5t466.5 -327.5v224q0 224 128 224q-125 0 -213.5 16t-146.5 47t-91.5 83t-47 115.5t-13.5 154.5q0 100 25 187t71 133q-28 71 -28 143t14 109l14 36q7 0 18 -1t44 -7.5 t63 -18.5t67 -38.5t64 -62.5q144 24 300 24t276 -24q27 36 60 62.5t60.5 38.5t51.5 18.5t38 7.5l14 1q4 -5 10 -14.5t19 -40.5t20 -63t4 -78.5t-21 -91.5q96 -144 96 -320q0 -113 -21 -187.5t-75 -128t-147.5 -77t-236.5 -23.5q49 -25 72.5 -77.5t23.5 -146.5z" />
+<glyph unicode="&#xf201;" d="M1024 2048q206 0 395.5 -82t327 -219.5t219.5 -327t82 -395.5t-82 -395.5t-219.5 -327t-327 -219.5t-395.5 -82t-395.5 82t-327 219.5t-219.5 327t-82 395.5t82 395.5t219.5 327t327 219.5t395.5 82zM1024 1920q-32 0 -96 -8t-96 -8q102 -166 304 -512q6 2 86 31 t118.5 45t108 47t122 64t93.5 69q-126 126 -290.5 199t-349.5 73zM672 1856q-194 -85 -329.5 -247.5t-182.5 -376.5q194 -22 444 14t388 82q-141 282 -320 528zM1760 1536q-71 -57 -162 -104.5t-214.5 -100.5t-183.5 -83q22 -29 36.5 -54.5t34 -67.5t25.5 -54q170 33 336 30 t288 -30q-26 285 -160 464zM128 1088v-64q0 -167 58 -319.5t166 -272.5q125 205 339 360t445 232q-16 48 -80 176q-282 -86 -481.5 -111t-446.5 -1zM1536 288q156 108 258 278t126 362q-276 46 -576 0q14 -27 43 -103t74.5 -231t74.5 -306zM1024 128q181 0 368 80 q-33 300 -208 688q-222 -74 -410 -225.5t-294 -350.5q216 -192 544 -192z" />
+<glyph unicode="&#xf202;" d="M2048 1659q-84 -127 -210 -217q2 -36 2 -55q0 -168 -49 -337t-150 -323.5t-241 -273.5t-336 -190t-420 -71q-351 0 -644 189q50 -6 100 -6q293 0 522 180q-137 2 -244.5 83t-147.5 208q44 -7 79 -7q57 0 110 15q-145 29 -241 144.5t-96 267.5v5q86 -48 191 -53 q-86 58 -136.5 150t-50.5 200q0 113 57 211q158 -194 383 -310t483 -129q-11 49 -11 96q0 174 123 297t297 123q89 0 168.5 -35t138.5 -97q142 27 266 102q-47 -150 -184 -233q124 15 241 66z" />
+<glyph unicode="&#xf203;" d="M117 0h1814q48 0 82.5 34.5t34.5 82.5v1814q0 48 -34.5 82.5t-82.5 34.5h-1814q-48 0 -82.5 -34.5t-34.5 -82.5v-1814q0 -48 34.5 -82.5t82.5 -34.5zM1442 1479v-207h329l-14 -303h-315v-841h-320v841h-222v303h222v258q0 78 26 147t77 124t136.5 87t194.5 32 q55 0 108 -3t79 -6l26 -3l-7 -282h-193q-76 0 -101.5 -32t-25.5 -101v-3v-2v-9z" />
+<glyph unicode="&#xf204;" d="M1182 1479v-207h329l-14 -303h-315v-841h-320v841h-222v303h222v258q0 78 26 147t77 124t136.5 87t194.5 32q55 0 108 -3t79 -6l26 -3l-7 -282h-193q-76 0 -101.5 -32t-25.5 -101v-3v-2v-9z" />
+<glyph unicode="&#xf205;" d="M1024 2048q208 0 398 -81t327 -218.5t218 -327t81 -397.5q0 -209 -81 -398.5t-218 -326.5t-326.5 -218t-398.5 -81q-208 0 -397.5 81t-327 218t-218.5 327t-81 398t81 397.5t218.5 327t327 218.5t397.5 81zM1456 537l90 301q69 177 69 293q0 51 -14 107q-18 45 -40 81 q-2 3 -15 24t-15.5 25t-13 22t-13 24.5t-10 22t-10 24.5t-6.5 22t-5 25t-1 24q0 63 42 110.5t106 49.5q-121 108 -274.5 168t-321.5 60q-226 0 -421 -105t-318 -285q4 0 13.5 -0.5t15.5 -0.5q70 0 127.5 2.5t80.5 4.5l22 3q29 2 46.5 -16t19.5 -40.5t-13 -43t-44 -24.5 q-27 -4 -70 -8l295 -877l198 591l-104 283l-90 11q-38 2 -51.5 34t4.5 62t56 28q54 -10 201 -10q70 0 127.5 2.5t80.5 4.5l22 3q38 2 56.5 -27t5 -60.5t-51.5 -36.5q-27 -4 -69 -8zM1756 1041l-271 -785q199 120 317 324t118 444q0 216 -99 409q4 -44 4 -68q0 -153 -69 -324 zM623 223l-421 1156q-74 -168 -74 -355q0 -259 135.5 -473.5t359.5 -327.5zM1040 945l-268 -780q123 -37 252 -37q152 0 296 51q0 1 -1 1l-1 2z" />
+<glyph unicode="&#xf206;" d="M1920 1696v-160h-256v256h-128v-256h-256v-128h256v-256h128v256h256v-1056q0 -96 -64 -160t-160 -64h-544v64q0 128 -43.5 215t-180.5 201q-60 30 -126 89.5t-66 102.5q0 46 26.5 78t101.5 82q48 48 72.5 75t57.5 70.5t47.5 86t14.5 88.5q0 122 -48.5 213.5 t-143.5 138.5h160l160 160h-608q-133 0 -249.5 -55t-198.5 -137v96q0 96 64 160t160 64h1344q96 0 160 -64t64 -160zM576 928q-122 0 -225 109.5t-127 274.5q-23 164 54.5 274t201.5 110q121 -24 208.5 -136.5t111.5 -279.5q24 -165 -38.5 -258.5t-185.5 -93.5zM128 480v480 q52 -52 140.5 -90t179.5 -38h64q0 -16 -16 -48t-16 -48q0 -50 25 -93.5t71 -66.5h-128q-176 0 -320 -96zM960 128h-608q-73 0 -136.5 44.5t-87.5 115.5q49 98 162 161t254 63q32 0 80 -16t80 -16q11 -8 41 -30.5l40 -30t34.5 -26.5t34 -28t28 -25.5t27 -28t20.5 -27t19 -30 t12 -30.5v-64v-32z" />
+<glyph unicode="&#xf207;" d="M530 1285h1q67 0 108.5 39.5t41.5 97.5q-2 60 -42 98.5t-106 38.5q-67 0 -108 -39t-41 -98q0 -58 40.5 -97.5t105.5 -39.5zM1350 384h264v455q0 175 -83.5 266t-220.5 91q-50 0 -90.5 -12t-68.5 -34t-45 -41t-33 -44v112h-264v-793h264v443q0 45 8 64q16 40 50.5 68 t85.5 28q133 0 133 -179v-424zM400 384h263v793h-263v-793z" />
+<glyph unicode="&#xf208;" d="M384 1920h1280q106 0 181 -75t75 -181v-1280q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181v1280q0 106 75 181t181 75zM530 1285h1q67 0 108.5 39.5t41.5 97.5q-2 60 -42 98.5t-106 38.5q-67 0 -108 -39t-41 -98q0 -58 40.5 -97.5t105.5 -39.5zM1350 384h264 v455q0 175 -83.5 266t-220.5 91q-50 0 -90.5 -12t-68.5 -34t-45 -41t-33 -44v112h-264v-793h264v443q0 45 8 64q16 40 50.5 68t85.5 28q133 0 133 -179v-424zM400 384h263v793h-263v-793z" />
+<glyph unicode="&#xf209;" d="M667 0l-149 54q-7 167 22 290l162 688q-40 81 -40 200q0 139 70.5 232.5t172.5 93.5q83 0 127 -53.5t44 -135.5q0 -51 -18.5 -124t-49 -170t-44.5 -154q-23 -99 37.5 -171t161.5 -72q117 0 209.5 92t142 244.5t49.5 334.5q0 214 -139 349t-387 135q-139 0 -257.5 -49.5 t-197 -133t-122.5 -193t-44 -229.5q0 -147 83 -247q18 -21 21.5 -34t-3.5 -37q-16 -61 -25 -101q-7 -24 -24.5 -32t-39.5 1q-127 51 -192.5 181.5t-65.5 300.5q0 109 35.5 219t110 213t179 182t254 126.5t323.5 47.5q176 0 327.5 -60.5t253.5 -161t160 -231t58 -270.5 q0 -246 -85 -443t-241 -309.5t-355 -112.5q-99 0 -186.5 46.5t-121.5 110.5q-73 -290 -89 -347q-34 -123 -127 -270z" />
+<glyph unicode="&#xf210;" d="M1024 2048q209 0 398.5 -81t326.5 -218t218 -326.5t81 -398.5t-81 -398.5t-218 -326.5t-326.5 -218t-398.5 -81q-147 0 -290 42q74 116 103 219l72 282q28 -53 99 -90.5t151 -37.5q162 0 288.5 91.5t195.5 251t69 359.5q0 114 -47 220t-130 187.5t-206.5 130.5t-265.5 49 q-141 0 -262 -38.5t-205.5 -103t-145.5 -147.5t-89.5 -172.5t-28.5 -178.5q0 -138 53 -243.5t156 -147.5q18 -8 32.5 -1t18.5 26q2 9 10 41t11 41q5 19 2.5 30t-16.5 28q-68 78 -68 200q0 97 35.5 186t99.5 156.5t160 108t209 40.5q201 0 313.5 -109.5t112.5 -283.5 q0 -148 -40 -271.5t-115 -198t-169 -74.5q-82 0 -131.5 58.5t-30.5 138.5q11 46 35.5 125t39.5 138t15 101q0 66 -35.5 109.5t-102.5 43.5q-82 0 -139.5 -76t-57.5 -189q0 -43 8 -83.5t16 -59.5l9 -19q-113 -475 -132 -558q-24 -97 -18 -235q-275 120 -444 374t-169 564 q0 208 81 398t218.5 327t327 218t397.5 81z" />
+<glyph unicode="&#xf211;" d="M992 1024q0 172 -122 294t-294 122t-294 -122t-122 -294t122 -294t294 -122t294 122t122 294zM1888 1024q0 172 -122 294t-294 122t-294 -122t-122 -294t122 -294t294 -122t294 122t122 294z" />
+<glyph unicode="&#xf212;" d="M128 1379l84 -108q121 84 141 84q92 0 173 -287q24 -87 72 -262.5t72 -262.5q108 -287 265 -287q253 0 619 471q353 451 365 710q16 347 -260 355q-373 12 -505 -417q69 29 133 29q136 0 120 -152q-8 -92 -120 -268q-113 -176 -169 -176q-73 0 -133 271q-20 78 -72 407 q-49 303 -258 284q-89 -8 -265 -160q-126 -113 -262 -231z" />
+<glyph unicode="&#xf213;" d="M512 1664h1024q104 0 192.5 -51.5t140 -140t51.5 -192.5v-512q0 -104 -51.5 -192.5t-140 -140t-192.5 -51.5h-1024q-104 0 -192.5 51.5t-140 140t-51.5 192.5v512q0 104 51.5 192.5t140 140t192.5 51.5zM768 1408v-768l640 384z" />
+<glyph unicode="&#xf300;" d="M512 1536h1024q106 0 181 -75t75 -181v-384q0 -106 -75 -181t-181 -75h-448l-448 -448v448h-128q-106 0 -181 75t-75 181v384q0 106 75 181t181 75z" />
+<glyph unicode="&#xf301;" d="M640 1024l64 128h960l-256 -640h-1024v1024h384l64 -128h448v-128h-640l-128 -256h128z" />
+<glyph unicode="&#xf302;" d="M256 768l768 768h512v-512l-768 -768zM1280 1152q53 0 90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5z" />
+<glyph unicode="&#xf303;" d="M960 1792q143 0 273.5 -55.5t225 -150t150 -225t55.5 -273.5t-55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5t55.5 273.5t150 225t225 150t273.5 55.5zM960 512q117 0 223.5 45.5t184 123t123 184t45.5 223.5t-45.5 223.5 t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5t45.5 -223.5t123 -184t184 -123t223.5 -45.5zM896 1536h128v-421l298 -298l-90 -91l-336 336v474z" />
+<glyph unicode="&#xf304;" d="M1024 1152q-106 0 -181 75t-75 181t75 181t181 75t181 -75t75 -181t-75 -181t-181 -75zM896 1024h256q159 0 271.5 -112.5t112.5 -271.5v-256h-1024v256q0 159 112.5 271.5t271.5 112.5z" />
+<glyph unicode="&#xf305;" d="M1408 1792v-128h256v-1280h-1408v1280h256v128h128v-128h640v128h128zM512 512h896q53 0 90.5 37.5t37.5 90.5v640q0 53 -37.5 90.5t-90.5 37.5h-896q-53 0 -90.5 -37.5t-37.5 -90.5v-640q0 -53 37.5 -90.5t90.5 -37.5zM832 1280h128q26 0 45 -19t19 -45v-512 q0 -26 -19 -45t-45 -19t-45 19t-19 45v448h-64q-26 0 -45 19t-19 45t19 45t45 19z" />
+<glyph unicode="&#xf306;" d="M1408 1792v-128h256v-1280h-1408v1280h256v128h128v-128h640v128h128zM512 512h896q53 0 90.5 37.5t37.5 90.5v640q0 53 -37.5 90.5t-90.5 37.5h-896q-53 0 -90.5 -37.5t-37.5 -90.5v-640q0 -53 37.5 -90.5t90.5 -37.5zM832 1280h256h2h1h3q22 -2 38.5 -18t19.5 -39v-2 v-2v-1v-2q0 -5 -2 -15l-128 -512q-6 -26 -28.5 -40t-48.5 -7q-26 6 -40 28.5t-7 48.5l108 433h-174q-26 0 -45 19t-19 45t19 45t45 19z" />
+<glyph unicode="&#xf307;" d="M1408 1792v-128h256v-1280h-1408v1280h256v128h128v-128h640v128h128zM512 512h896q53 0 90.5 37.5t37.5 90.5v640q0 53 -37.5 90.5t-90.5 37.5h-896q-53 0 -90.5 -37.5t-37.5 -90.5v-640q0 -53 37.5 -90.5t90.5 -37.5zM896 1152h-128v128h128v-128zM1152 1152h-128v128 h128v-128zM1408 1152h-128v128h128v-128zM640 896h-128v128h128v-128zM896 896h-128v128h128v-128zM1152 896h-128v128h128v-128zM1408 896h-128v128h128v-128zM640 640h-128v128h128v-128zM896 640h-128v128h128v-128zM1152 640h-128v128h128v-128z" />
+<glyph unicode="&#xf308;" d="M1280 1920h128l512 -512v-128h-256l-320 -320v-384h-128l-640 640v128h384l320 320v256zM256 384l512 512l128 -128l-512 -512z" />
+<glyph unicode="&#xf400;" d="M1664 256l-495 495q-153 -111 -337 -111q-117 0 -223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5q0 -184 -111 -337l495 -495zM832 768q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5 q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5z" />
+<glyph unicode="&#xf401;" d="M1664 256l-495 495q-153 -111 -337 -111q-117 0 -223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5q0 -184 -111 -337l495 -495zM832 768q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5 q-185 0 -316.5 -131.5t-131.5 -316.5t131.5 -316.5t316.5 -131.5zM1152 1152h-640v128h640v-128z" />
+<glyph unicode="&#xf402;" d="M1297 879l495 -495l-128 -128l-495 495q-153 -111 -337 -111q-117 0 -223.5 45.5t-184 123t-123 184t-45.5 223.5t45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5q0 -184 -111 -337zM384 1216q0 -185 131.5 -316.5t316.5 -131.5 q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5q-185 0 -316.5 -131.5t-131.5 -316.5zM896 1280h256v-128h-256v-256h-128v256h-256v128h256v256h128v-256z" />
+<glyph unicode="&#xf403;" d="M0 1024l506 506q101 103 234.5 160.5t283.5 57.5t283.5 -57.5t233.5 -159.5l507 -507l-506 -507q-101 -103 -234.5 -160t-283.5 -57t-283.5 57.5t-233.5 160.5zM272 1024l370 -371q77 -78 175.5 -119.5t206.5 -41.5t206 41.5t174 118.5l373 372l-371 371 q-158 161 -382 161q-108 0 -206.5 -41t-173.5 -119zM1024 1408q159 0 271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5t112.5 271.5t271.5 112.5zM1152 1024q53 0 90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5 t37.5 -90.5t90.5 -37.5z" />
+<glyph unicode="&#xf404;" d="M1382 1653l-143 -143q-103 46 -215 46q-108 0 -206.5 -41t-173.5 -119l-372 -372l240 -240l-136 -136l-376 376l506 506q101 103 234.5 160.5t283.5 57.5q193 0 358 -95zM339 429l90 -90l1280 1280l-90 90zM1122 1394l-468 -468q-14 54 -14 98q0 159 112.5 271.5 t271.5 112.5q44 0 98 -14zM1536 1265l136 135l376 -376l-506 -507q-101 -103 -234.5 -160t-283.5 -57q-193 0 -358 95l143 143q103 -46 215 -46q108 0 206 41.5t174 118.5l373 372zM926 654l468 468q14 -54 14 -98q0 -159 -112.5 -271.5t-271.5 -112.5q-44 0 -98 14z" />
+<glyph unicode="&#xf405;" d="M1408 1536l128 -128l-320 -320l320 -320l-128 -128l-320 320l-320 -320l-128 128l320 320l-320 320l128 128l320 -320z" />
+<glyph unicode="&#xf406;" d="M1920 2048l128 -128l-832 -832l832 -832l-128 -128l-832 832l-832 -832l-128 128l832 832l-832 832l128 128l832 -832z" />
+<glyph unicode="&#xf407;" d="M1140 1536h140q106 0 181 -75t75 -181h-128v-768q0 -53 -37.5 -90.5t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5v768h-128q0 106 75 181t181 75h140q20 56 69.5 92t110.5 36q62 0 111 -35.5t69 -92.5zM640 1216v-640q0 -26 19 -45t45 -19t45 19t19 45v640 q0 26 -19 45t-45 19t-45 -19t-19 -45zM896 1216v-640q0 -26 19 -45t45 -19t45 19t19 45v640q0 26 -19 45t-45 19t-45 -19t-19 -45zM1280 576v640q0 26 -19 45t-45 19t-45 -19t-19 -45v-640q0 -26 19 -45t45 -19t45 19t19 45z" />
+<glyph unicode="&#xf408;" d="M1205 1150l-181 535l-180 -534h-588l476 -330l-183 -535l475 332l475 -332l-183 535l476 329h-587z" />
+<glyph unicode="&#xf409;" d="M384 1024l640 640l640 -640l-128 -128l-512 512l-512 -512zM640 512v384l384 384l384 -384v-384h-256v384h-256v-384h-256z" />
+<glyph unicode="&#xf410;" d="M0 1792h2048l-1024 -1024zM0 512v1152l576 -576zM2048 1664v-1152l-576 576zM640 1024l384 -384l384 384l640 -640h-2048z" />
+<glyph unicode="&#xf411;" d="M384 832l896 896l448 -448l-896 -896h-448v448zM1376 1440l-96 96l-595 -595l96 -96zM941 685l595 595l-96 96l-595 -595zM512 768l256 -256l128 128l-256 256z" />
+<glyph unicode="&#xf412;" d="M1280 1472l640 -640l-640 -640v448h-1024v704l384 384v-704h640v448z" />
+<glyph unicode="&#xf413;" d="M1920 128h-345q0 197 -52 385.5t-145.5 348t-227 294t-292 228t-346 146t-383.5 52.5v345q243 0 475 -64.5t428.5 -181t362 -282.5t281 -363.5t180 -430.5t64.5 -477zM1311 128h-345q0 170 -63.5 324t-181.5 273q-119 119 -272 182.5t-321 63.5v345q240 0 459 -94 t377.5 -253.5t252.5 -379.5t94 -461zM384 640q106 0 181 -75t75 -181t-75 -181t-181 -75t-181 75t-75 181t75 181t181 75z" />
+<glyph unicode="&#xf414;" d="M1237 1711l759 -1237q88 -142 31 -244t-224 -102h-1557q-168 0 -225 102t31 244l760 1237q57 93 134.5 126.5t155 0t135.5 -126.5zM896 1280v-384q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5zM1024 384 q53 0 90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5z" />
+<glyph unicode="&#xf415;" d="M128 1280v-256h400q45 0 79.5 27.5t44.5 69.5q33 125 136.5 206t235.5 81q154 0 270 -114q38 -38 90.5 -38t90.5 38q37 38 37 91t-37 90q-88 89 -204.5 139t-246.5 50q-194 0 -353 -106t-234 -278h-309zM1280 1024q0 106 -75 181t-181 75t-181 -75t-75 -181t75 -181 t181 -75t181 75t75 181zM1611 768h309v256h-400q-45 0 -79.5 -27.5t-44.5 -69.5q-33 -125 -136.5 -206t-235.5 -81q-156 0 -269 115q-38 37 -91 37t-91 -38q-37 -38 -37 -91t37 -90q89 -89 205 -139t246 -50q194 0 353 106t234 278z" />
+<glyph unicode="&#xf416;" d="M768 960v512q0 133 93.5 226.5t226.5 93.5t226.5 -93.5t93.5 -226.5v-640q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5v320h128v-320q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5v640q0 80 -56 136t-136 56t-136 -56t-56 -136v-512 q0 -26 19 -45t45 -19t45 19t19 45v452h128v-452q0 -80 -56 -136t-136 -56t-136 56t-56 136z" />
+<glyph unicode="&#xf417;" d="M960 402l-407 406q-80 80 -124.5 185.5t-44.5 222.5t45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5t-44.5 -222.5t-124.5 -185.5zM960 896q133 0 226.5 93.5t93.5 226.5t-93.5 226.5t-226.5 93.5t-226.5 -93.5t-93.5 -226.5 t93.5 -226.5t226.5 -93.5z" />
+<glyph unicode="&#xf418;" d="M960 992l448 512l128 -96l-512 -768h-128l-288 416l128 128z" />
+<glyph unicode="&#xf419;" d="M0 1536v256h2048v-256h-2048zM2048 896h-2048v256h2048v-256zM2048 256h-2048v256h2048v-256z" />
+<glyph unicode="&#xf420;" d="M384 1280v128h1280v-128h-1280zM1664 512h-1280l640 640z" />
+<glyph unicode="&#xf421;" d="M384 896v256h1152v-256h-1152z" />
+<glyph unicode="&#xf422;" d="M384 512v1024h1152v-1024h-1152zM512 640h896v640h-896v-640z" />
+<glyph unicode="&#xf423;" d="M456 1503l112 -62l-267 -481h403v-384h-128v256h-493zM1912 1441l-267 -481h403v-384h-128v256h-493l373 671zM1088 1344q87 0 160.5 -43t116.5 -116.5t43 -160.5t-43 -160.5t-116.5 -116.5t-160.5 -43t-160.5 43t-116.5 116.5t-43 160.5t43 160.5t116.5 116.5t160.5 43z M1088 832q79 0 135.5 56.5t56.5 135.5t-56.5 135.5t-135.5 56.5t-135.5 -56.5t-56.5 -135.5t56.5 -135.5t135.5 -56.5z" />
+<glyph unicode="&#xf500;" d="M1088 960l960 -960h-1920z" />
+<glyph unicode="&#xf501;" d="M960 1088l-960 960v-1920z" />
+<glyph unicode="&#xf502;" d="M1088 1088l960 960h-1920z" />
+<glyph unicode="&#xf503;" d="M1088 1088l960 960v-1920z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.ttf b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.ttf
new file mode 100644
index 0000000000..57874a45d1
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.ttf
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.woff b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.woff
new file mode 100644
index 0000000000..1d3dda08df
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/fonts/genericons-regular-webfont.woff
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/footer.php b/src/wp-content/themes/twentyfourteen/footer.php
new file mode 100644
index 0000000000..4d7a05b184
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/footer.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * The template for displaying the footer.
+ *
+ * Contains the closing of the id=main div and all content after
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+
+ </div><!-- #main .site-main -->
+
+ <?php get_sidebar( 'footer' ); ?>
+
+ <footer id="colophon" class="site-footer" role="contentinfo">
+ <div class="site-info">
+ <?php do_action( 'twentyfourteen_credits' ); ?>
+ <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'twentythirteen' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'twentythirteen' ); ?>"><?php printf( __( 'Proudly powered by %s', 'twentythirteen' ), 'WordPress' ); ?></a>
+ </div><!-- .site-info -->
+ </footer><!-- #colophon .site-footer -->
+</div><!-- #page .hfeed .site -->
+
+<?php wp_footer(); ?>
+
+</body>
+</html> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/full-width-page.php b/src/wp-content/themes/twentyfourteen/full-width-page.php
new file mode 100644
index 0000000000..55e64fb1f2
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/full-width-page.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Template Name: Full Width Page
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+<?php if ( is_front_page() ) : ?>
+
+ <div class="front-page-content-wrapper">
+ <div class="front-page-content-main">
+
+ <?php if ( twentyfourteen_has_featured_posts() ) : ?>
+ <?php get_template_part( 'featured-content' ); ?>
+ <?php endif; ?>
+
+ <div class="front-page-content-area clearfix">
+
+ <div id="primary" class="content-area no-sidebar">
+ <div id="content" class="site-content full-width" role="main">
+ <?php
+ if ( have_posts() ) :
+ while ( have_posts() ) :
+ the_post();
+ get_template_part( 'content', 'page' );
+ comments_template( '', true );
+ endwhile;
+
+ twentyfourteen_content_nav( 'nav-below' );
+ else :
+ get_template_part( 'no-results', 'index' );
+ endif;
+ ?>
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+ </div><!-- .front-page-content-area -->
+
+ </div><!-- .front-page-content-main -->
+ </div><!-- .front-page-content-wrapper -->
+
+<?php else : ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content full-width" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', 'page' ); ?>
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endwhile; ?>
+
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+<?php endif; // is_front_page() check ?>
+
+<?php get_sidebar(); ?>
+
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyfourteen/functions.php b/src/wp-content/themes/twentyfourteen/functions.php
new file mode 100644
index 0000000000..2c38e1d929
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/functions.php
@@ -0,0 +1,446 @@
+<?php
+/**
+ * Twenty Fourteen functions and definitions
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+/**
+ * Set the content width based on the theme's design and stylesheet.
+ *
+ */
+if ( ! isset( $content_width ) )
+ $content_width = 474; /* pixels */
+
+function twentyfourteen_set_content_width() {
+ global $content_width;
+ if ( is_page_template( 'full-width-page.php' ) || is_attachment() )
+ $content_width = 895;
+}
+add_action( 'template_redirect', 'twentyfourteen_set_content_width' );
+
+if ( ! function_exists( 'twentyfourteen_setup' ) ) :
+/**
+ * Sets up theme defaults and registers support for various WordPress features.
+ *
+ * Note that this function is hooked into the after_setup_theme hook, which runs
+ * before the init hook. The init hook is too late for some features, such as indicating
+ * support post thumbnails.
+ *
+ */
+function twentyfourteen_setup() {
+ /**
+ * Custom template tags for this theme.
+ */
+ require( get_template_directory() . '/inc/template-tags.php' );
+
+ /**
+ * Customizer additions
+ */
+ require( get_template_directory() . '/inc/customizer.php' );
+
+ /**
+ * Make theme available for translation
+ * Translations can be filed in the /languages/ directory
+ * If you're building a theme based on Twenty Fourteen, use a find and replace
+ * to change 'twentyfourteen' to the name of your theme in all the template files
+ */
+ load_theme_textdomain( 'twentyfourteen', get_template_directory() . '/languages' );
+
+ /**
+ * Add default posts and comments RSS feed links to head
+ */
+ add_theme_support( 'automatic-feed-links' );
+
+ /**
+ * Enable support for Post Thumbnails
+ */
+ add_theme_support( 'post-thumbnails', array( 'post' ) );
+
+ /**
+ * Adding several sizes for Post Thumbnails
+ */
+ add_image_size( 'featured-thumbnail-large', 672, 0 );
+ add_image_size( 'featured-thumbnail-featured', 672, 336, true );
+ add_image_size( 'featured-thumbnail-formatted', 306, 0 );
+
+ /**
+ * This theme uses wp_nav_menu() in one location.
+ */
+ register_nav_menus( array(
+ 'primary' => __( 'Top primary menu', 'twentyfourteen' ),
+ 'secondary' => __( 'Secondary menu in left sidebar', 'twentyfourteen' )
+ ) );
+
+ /**
+ * Enable support for Post Formats
+ */
+ add_theme_support( 'post-formats', array( 'aside', 'image', 'video', 'quote', 'link', 'gallery' ) );
+
+ /**
+ * This theme allows users to set a custom background.
+ */
+ $args = apply_filters( 'twentyfourteen_custom_background_args', array( 'default-color' => 'f5f5f5' ) );
+
+ if ( function_exists( 'wp_get_theme' ) ) {
+ add_theme_support( 'custom-background', $args );
+ } else {
+ // Compat: Versions of WordPress prior to 3.4.
+ define( 'BACKGROUND_COLOR', $args['default-color'] );
+ add_custom_background();
+ }
+}
+endif; // twentyfourteen_setup
+add_action( 'after_setup_theme', 'twentyfourteen_setup' );
+
+/**
+ * Getter function for Featured Content Plugin.
+ *
+ */
+function twentyfourteen_get_featured_posts() {
+ return apply_filters( 'twentyfourteen_get_featured_posts', false );
+}
+
+/**
+ * A helper conditional function that returns a boolean value
+ * So that we can use a condition like
+ * if ( twentyfourteen_has_featured_posts( 1 ) )
+ *
+ */
+function twentyfourteen_has_featured_posts( $minimum = 1 ) {
+ if ( is_paged() )
+ return false;
+
+ $minimum = absint( $minimum );
+ $featured_posts = apply_filters( 'twentyfourteen_get_featured_posts', array() );
+
+ if ( ! is_array( $featured_posts ) )
+ return false;
+
+ if ( $minimum > count( $featured_posts ) )
+ return false;
+
+ return true;
+}
+
+/**
+ * Register widgetized area and update sidebar with default widgets
+ *
+ */
+function twentyfourteen_widgets_init() {
+ register_sidebar( array(
+ 'name' => __( 'Primary Sidebar', 'twentyfourteen' ),
+ 'id' => 'sidebar-1',
+ 'description' => __( 'Main sidebar that appears on the left.', 'twentyfourteen' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+ register_sidebar( array(
+ 'name' => __( 'Content Sidebar', 'twentyfourteen' ),
+ 'id' => 'sidebar-2',
+ 'description' => __( 'Additional sidebar that appears on the right, on single posts and pages.', 'twentyfourteen' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+ register_sidebar( array(
+ 'name' => __( 'Footer Widget Area One', 'twentyfourteen' ),
+ 'id' => 'sidebar-3',
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+ register_sidebar( array(
+ 'name' => __( 'Footer Widget Area Two', 'twentyfourteen' ),
+ 'id' => 'sidebar-4',
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+ register_sidebar( array(
+ 'name' => __( 'Footer Widget Area Three', 'twentyfourteen' ),
+ 'id' => 'sidebar-5',
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+ register_sidebar( array(
+ 'name' => __( 'Footer Widget Area Four', 'twentyfourteen' ),
+ 'id' => 'sidebar-6',
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+ register_sidebar( array(
+ 'name' => __( 'Footer Widget Area Five', 'twentyfourteen' ),
+ 'id' => 'sidebar-7',
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h1 class="widget-title">',
+ 'after_title' => '</h1>',
+ ) );
+}
+add_action( 'widgets_init', 'twentyfourteen_widgets_init' );
+
+/**
+ * Register Google fonts for Twenty Fourteen
+ *
+ */
+function twentyfourteen_fonts() {
+ /* translators: If there are characters in your language that are not supported
+ by Lato, translate this to 'off'. Do not translate into your own language. */
+ if ( 'off' !== _x( 'on', 'Lato font: on or off', 'twentyfourteen' ) ) {
+
+ $protocol = is_ssl() ? 'https' : 'http';
+
+ wp_register_style( 'twentyfourteen-lato', "$protocol://fonts.googleapis.com/css?family=Lato:100,300,400,700,900,100italic,300italic,400italic,700italic,900italic", array(), null );
+ }
+}
+add_action( 'init', 'twentyfourteen_fonts' );
+
+/**
+ * Enqueue scripts and styles
+ *
+ */
+function twentyfourteen_scripts() {
+ wp_enqueue_style( 'twentyfourteen-style', get_stylesheet_uri() );
+
+ wp_enqueue_style( 'twentyfourteen-lato' );
+
+ if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
+ wp_enqueue_script( 'comment-reply' );
+ }
+
+ if ( is_singular() && wp_attachment_is_image() ) {
+ wp_enqueue_script( 'twentyfourteen-keyboard-image-navigation', get_template_directory_uri() . '/js/keyboard-image-navigation.js', array( 'jquery' ), '20130402' );
+ }
+
+ wp_enqueue_script( 'twentyfourteen-theme', get_template_directory_uri() . '/js/theme.js', array( 'jquery' ), '20130402', true );
+}
+add_action( 'wp_enqueue_scripts', 'twentyfourteen_scripts' );
+
+/**
+ * Enqueue Google fonts style to admin screen for custom header display.
+ *
+ */
+function twentyfourteen_admin_fonts( $hook_suffix ) {
+ if ( 'appearance_page_custom-header' != $hook_suffix )
+ return;
+
+ wp_enqueue_style( 'twentyfourteen-lato' );
+}
+add_action( 'admin_enqueue_scripts', 'twentyfourteen_admin_fonts' );
+
+/**
+ * Implement the Custom Header feature
+ *
+ */
+require( get_template_directory() . '/inc/custom-header.php' );
+
+/**
+ * Sets the post excerpt length to 40 words.
+ *
+ */
+function twentyfourteen_excerpt_length( $length ) {
+ return 20;
+}
+add_filter( 'excerpt_length', 'twentyfourteen_excerpt_length' );
+
+/**
+ * Returns a "Continue Reading" link for excerpts
+ *
+ */
+function twentyfourteen_continue_reading_link() {
+ return ' <a href="'. esc_url( get_permalink() ) . '" class="more-link">' . __( 'Read More <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ) . '</a>';
+}
+
+/**
+ * Replaces "[...]" (appended to automatically generated excerpts) with an ellipsis and twentyeleven_continue_reading_link().
+ */
+function twentyfourteen_auto_excerpt_more( $more ) {
+ return ' &hellip;' . twentyfourteen_continue_reading_link();
+}
+add_filter( 'excerpt_more', 'twentyfourteen_auto_excerpt_more' );
+
+/**
+ * Adds a pretty "Continue Reading" link to custom post excerpts.
+ *
+ * To override this link in a child theme, remove the filter and add your own
+ * function tied to the get_the_excerpt filter hook.
+ *
+ */
+function twentyfourteen_custom_excerpt_more( $output ) {
+ if ( has_excerpt() && ! is_attachment() ) {
+ $output .= twentyfourteen_continue_reading_link();
+ }
+ return $output;
+}
+add_filter( 'get_the_excerpt', 'twentyfourteen_custom_excerpt_more' );
+
+/**
+ * Count the number of footer sidebars to enable dynamic classes for the footer
+ *
+ */
+function twentyfourteen_footer_sidebar_class() {
+ $count = 0;
+
+ if ( is_active_sidebar( 'sidebar-3' ) )
+ $count++;
+
+ if ( is_active_sidebar( 'sidebar-4' ) )
+ $count++;
+
+ if ( is_active_sidebar( 'sidebar-5' ) )
+ $count++;
+
+ if ( is_active_sidebar( 'sidebar-6' ) )
+ $count++;
+
+ if ( is_active_sidebar( 'sidebar-7' ) )
+ $count++;
+
+ $class = '';
+
+ switch ( $count ) {
+ case '1':
+ $class = 'one';
+ break;
+ case '2':
+ $class = 'two';
+ break;
+ case '3':
+ $class = 'three';
+ break;
+ case '4':
+ $class = 'four';
+ break;
+ case '5':
+ $class = 'five';
+ break;
+ }
+
+ if ( $class )
+ echo 'class="clearfix ' . $class . '"';
+}
+
+/**
+ * Gets recent formatted posts that are not featured in FC plugin.
+ *
+ */
+function twentyfourteen_get_recent( $post_format ) {
+ $args = array(
+ 'order' => 'DESC',
+ 'ignore_sticky_posts' => 1,
+ 'posts_per_page' => 2,
+ 'tax_query' => array(
+ array(
+ 'taxonomy' => 'post_format',
+ 'terms' => array( $post_format ),
+ 'field' => 'slug',
+ 'operator' => 'IN',
+ ),
+ ),
+ 'no_found_rows' => true,
+ );
+
+ $featured_posts = twentyfourteen_get_featured_posts();
+
+ if ( is_array( $featured_posts ) && ! empty( $featured_posts ) )
+ $args['post__not_in'] = wp_list_pluck( $featured_posts, 'ID' );
+
+ return new WP_Query( $args );
+}
+
+/**
+ * Filter the home page posts, and remove formatted posts visible in the sidebar from it
+ *
+ */
+function twentyfourteen_pre_get_posts( $query ) {
+ // Bail if not home, not a query, not main query.
+ if ( ! $query->is_main_query() || is_admin() )
+ return;
+
+ // Only on the home page
+ if ( $query->is_home() ) {
+ $exclude_ids = array();
+
+ $videos = twentyfourteen_get_recent( 'post-format-video' );
+ $images = twentyfourteen_get_recent( 'post-format-image' );
+ $galleries = twentyfourteen_get_recent( 'post-format-gallery' );
+ $asides = twentyfourteen_get_recent( 'post-format-aside' );
+ $links = twentyfourteen_get_recent( 'post-format-link' );
+ $quotes = twentyfourteen_get_recent( 'post-format-quote' );
+
+ foreach ( $videos->posts as $post )
+ $exclude_ids[] = $post->ID;
+
+ foreach ( $images->posts as $post )
+ $exclude_ids[] = $post->ID;
+
+ foreach ( $galleries->posts as $post )
+ $exclude_ids[] = $post->ID;
+
+ foreach ( $asides->posts as $post )
+ $exclude_ids[] = $post->ID;
+
+ foreach ( $links->posts as $post )
+ $exclude_ids[] = $post->ID;
+
+ foreach ( $quotes->posts as $post )
+ $exclude_ids[] = $post->ID;
+
+ $query->set( 'post__not_in', $exclude_ids );
+ }
+}
+add_action( 'pre_get_posts', 'twentyfourteen_pre_get_posts' );
+
+/**
+ * Adds custom classes to the array of body classes.
+ *
+ */
+function twentyfourteen_body_classes( $classes ) {
+ // Adds a class of group-blog to blogs with more than 1 published author
+ if ( is_multi_author() ) {
+ $classes[] = 'group-blog';
+ }
+ if ( is_archive() || is_search() || is_home() ) {
+ $classes[] = 'list-view';
+ }
+
+ return $classes;
+}
+add_filter( 'body_class', 'twentyfourteen_body_classes' );
+
+/**
+ * Filters wp_title to print a neat <title> tag based on what is being viewed.
+ *
+ */
+function twentyfourteen_wp_title( $title, $sep ) {
+ global $page, $paged;
+
+ if ( is_feed() )
+ return $title;
+
+ // Add the blog name
+ $title .= get_bloginfo( 'name' );
+
+ // Add the blog description for the home/front page.
+ $site_description = get_bloginfo( 'description', 'display' );
+ if ( $site_description && ( is_home() || is_front_page() ) )
+ $title .= " $sep $site_description";
+
+ // Add a page number if necessary:
+ if ( $paged >= 2 || $page >= 2 )
+ $title .= " $sep " . sprintf( __( 'Page %s', 'twentyfourteen' ), max( $paged, $page ) );
+
+ return $title;
+}
+add_filter( 'wp_title', 'twentyfourteen_wp_title', 10, 2 ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/header.php b/src/wp-content/themes/twentyfourteen/header.php
new file mode 100644
index 0000000000..1d11f89c50
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/header.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * The Header for our theme.
+ *
+ * Displays all of the <head> section and everything up till <div id="main">
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?><!DOCTYPE html>
+<html <?php language_attributes(); ?> class="no-js">
+<head>
+<script>
+/**
+ * Replaces class "no-js" with "js" in the <html>-tag when JavaScript is being used.
+ * Allows easy styling for browsers [not] supporting/running JavaScript.
+ */
+document.documentElement.className = document.documentElement.className.replace(/(\s|^)no-js(\s|$)/, '$1js$2');
+</script>
+<meta charset="<?php bloginfo( 'charset' ); ?>" />
+<meta name="viewport" content="width=device-width" />
+<title><?php wp_title( '|', true, 'right' ); ?></title>
+<link rel="profile" href="http://gmpg.org/xfn/11" />
+<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
+<!--[if lt IE 9]>
+<script src="<?php echo get_template_directory_uri(); ?>/js/html5.js" type="text/javascript"></script>
+<![endif]-->
+
+<?php wp_head(); ?>
+</head>
+
+<body <?php body_class(); ?>>
+<?php
+ $email_link = get_theme_mod( 'email_link' );
+ $twitter_link = get_theme_mod( 'twitter_link' );
+ $facebook_link = get_theme_mod( 'facebook_link' );
+ $pinterest_link = get_theme_mod( 'pinterest_link' );
+ $google_plus_link = get_theme_mod( 'google_plus_link' );
+ $linkedin_link = get_theme_mod( 'linkedin_link' );
+ $flickr_link = get_theme_mod( 'flickr_link' );
+ $github_link = get_theme_mod( 'github_link' );
+ $dribbble_link = get_theme_mod( 'dribbble_link' );
+ $vimeo_link = get_theme_mod( 'vimeo_link' );
+ $youtube_link = get_theme_mod( 'youtube_link' );
+ $social_links = ( '' != $email_link
+ || '' != $twitter_link
+ || '' != $facebook_link
+ || '' != $pinterest_link
+ || '' != $google_plus_link
+ || '' != $linkedin_link
+ || '' != $flickr_link
+ || '' != $github_link
+ || '' != $dribbble_link
+ || '' != $vimeo_link
+ || '' != $youtube_link
+ ) ? true : false;
+?>
+<div id="page" class="hfeed site">
+ <?php do_action( 'before' ); ?>
+
+ <?php $header_image = get_header_image();
+ if ( ! empty( $header_image ) ) { ?>
+ <div id="site-header">
+ <a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home">
+ <img src="<?php header_image(); ?>" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="" />
+ </a>
+ </div>
+ <?php } ?>
+
+ <header id="masthead" class="site-header clearfix" role="banner">
+ <div class="header-main clearfix">
+ <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
+
+ <div class="header-extra">
+ <?php if ( $social_links ) : ?>
+ <div class="social-links-toggle">
+ <span class="genericon"><?php _e( 'Connect', 'twentyfourteen' ); ?></span>
+ </div>
+ <?php endif; ?>
+
+ <div class="search-toggle">
+ <span class="genericon"><?php _e( 'Search', 'twentyfourteen' ); ?></span>
+ </div>
+ </div>
+
+ <nav role="navigation" class="site-navigation primary-navigation">
+ <h1 class="assistive-text"><?php _e( 'Primary Menu', 'twentyfourteen' ); ?></h1>
+ <div class="assistive-text skip-link"><a href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentyfourteen' ); ?>"><?php _e( 'Skip to content', 'twentyfourteen' ); ?></a></div>
+ <?php wp_nav_menu( array( 'theme_location' => 'primary' ) ); ?>
+ </nav>
+
+ </div>
+
+ <div id="mobile-navigations" class="hide"></div>
+
+ <?php if ( $social_links ) : ?>
+ <div class="social-links-wrapper hide">
+ <ul class="social-links clearfix">
+ <?php if ( is_email( $email_link ) ) : ?>
+ <li class="email-link">
+ <a href="mailto:<?php echo antispambot( sanitize_email( $email_link ) ); ?>" class="genericon" title="<?php esc_attr_e( 'Email', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Email', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $twitter_link ) : ?>
+ <li class="twitter-link">
+ <a href="<?php echo esc_url( $twitter_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Twitter', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Twitter', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $facebook_link ) : ?>
+ <li class="facebook-link">
+ <a href="<?php echo esc_url( $facebook_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Facebook', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Facebook', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $pinterest_link ) : ?>
+ <li class="pinterest-link">
+ <a href="<?php echo esc_url( $pinterest_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Pinterest', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Pinterest', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $google_plus_link ) : ?>
+ <li class="google-link">
+ <a href="<?php echo esc_url( $google_plus_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Google Plus', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Google Plus', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $linkedin_link ) : ?>
+ <li class="linkedin-link">
+ <a href="<?php echo esc_url( $linkedin_link ); ?>" class="genericon" title="<?php esc_attr_e( 'LinkedIn', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'LinkedIn', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $flickr_link ) : ?>
+ <li class="flickr-link">
+ <a href="<?php echo esc_url( $flickr_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Flickr', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Flickr', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $github_link ) : ?>
+ <li class="github-link">
+ <a href="<?php echo esc_url( $github_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Github', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Github', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $dribbble_link ) : ?>
+ <li class="dribbble-link">
+ <a href="<?php echo esc_url( $dribbble_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Dribbble', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Dribbble', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $vimeo_link ) : ?>
+ <li class="vimeo-link">
+ <a href="<?php echo esc_url( $vimeo_link ); ?>" class="genericon" title="<?php esc_attr_e( 'Vimeo', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'Vimeo', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+
+ <?php if ( '' != $youtube_link ) : ?>
+ <li class="youtube-link">
+ <a href="<?php echo esc_url( $youtube_link ); ?>" class="genericon" title="<?php esc_attr_e( 'YouTube', 'twentyfourteen' ); ?>" target="_blank">
+ <?php _e( 'YouTube', 'twentyfourteen' ); ?>
+ </a>
+ </li>
+ <?php endif; ?>
+ </ul>
+ </div>
+ <?php endif; ?>
+
+ <div class="search-box-wrapper hide">
+ <div class="search-box clearfix">
+ <?php get_search_form(); ?>
+ </div>
+ </div>
+ </header><!-- #masthead .site-header -->
+
+ <div id="main" class="site-main clearfix"> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/image.php b/src/wp-content/themes/twentyfourteen/image.php
new file mode 100644
index 0000000000..6cce17832e
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/image.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * The template for displaying image attachments.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header();
+?>
+
+<div id="primary" class="content-area image-attachment">
+ <div id="content" class="site-content full-width" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+
+ <div class="entry-meta">
+ <?php $metadata = wp_get_attachment_metadata(); ?>
+
+ <span class="entry-date"><time class="entry-date" datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>"><?php echo esc_html( get_the_date() ); ?></time></span>
+
+ <span class="full-size-link"><a href="<?php echo wp_get_attachment_url(); ?>" title="Link to full-size image"><?php echo $metadata['width']; ?> &times; <?php echo $metadata['height']; ?></a></span>
+
+ <span class="parent-post-link"><a href="<?php echo get_permalink( $post->post_parent ); ?>" title="Return to <?php echo esc_attr( get_the_title( $post->post_parent ) ); ?>" rel="gallery"><?php echo get_the_title( $post->post_parent ); ?></a></span>
+ <?php edit_post_link( __( 'Edit', 'twentyfourteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+
+ <div class="entry-attachment">
+ <div class="attachment">
+ <?php
+ /**
+ * Grab the IDs of all the image attachments in a gallery so we can get the URL of the next adjacent image in a gallery,
+ * or the first image (if we're looking at the last image in a gallery), or, in a gallery of one, just the link to that image file
+ */
+ $attachments = array_values( get_children( array(
+ 'post_parent' => $post->post_parent,
+ 'post_status' => 'inherit',
+ 'post_type' => 'attachment',
+ 'post_mime_type' => 'image',
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order ID'
+ ) ) );
+ foreach ( $attachments as $k => $attachment ) {
+ if ( $attachment->ID == $post->ID )
+ break;
+ }
+ $k++;
+ // If there is more than 1 attachment in a gallery
+ if ( count( $attachments ) > 1 ) {
+ if ( isset( $attachments[ $k ] ) )
+ // get the URL of the next image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ $k ]->ID );
+ else
+ // or get the URL of the first image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ 0 ]->ID );
+ } else {
+ // or, if there's only 1 image, get the URL of the image
+ $next_attachment_url = wp_get_attachment_url();
+ }
+ ?>
+
+ <a href="<?php echo $next_attachment_url; ?>" title="<?php echo esc_attr( get_the_title() ); ?>" rel="attachment"><?php
+ $attachment_size = apply_filters( 'twentyfourteen_attachment_size', array( 1200, 1200 ) ); // Filterable image size.
+ echo wp_get_attachment_image( $post->ID, $attachment_size );
+ ?></a>
+ </div><!-- .attachment -->
+
+ <?php if ( ! empty( $post->post_excerpt ) ) : ?>
+ <div class="entry-caption">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-caption -->
+ <?php endif; ?>
+ </div><!-- .entry-attachment -->
+
+ <?php the_content(); ?>
+ <?php
+ wp_link_pages( array(
+ 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentyfourteen' ) . '</span>',
+ 'after' => '</div>',
+ 'link_before' => '<span>',
+ 'link_after' => '</span>'
+ ) );
+ ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php if ( comments_open() && pings_open() ) : // Comments and trackbacks open ?>
+ <?php printf( __( '<a class="comment-link" href="#respond" title="Post a comment">Post a comment</a> or leave a trackback: <a class="trackback-link" href="%s" title="Trackback URL for your post" rel="trackback">Trackback URL</a>.', 'twentyfourteen' ), get_trackback_url() ); ?>
+ <?php elseif ( ! comments_open() && pings_open() ) : // Only trackbacks open ?>
+ <?php printf( __( 'Comments are closed, but you can leave a trackback: <a class="trackback-link" href="%s" title="Trackback URL for your post" rel="trackback">Trackback URL</a>.', 'twentyfourteen' ), get_trackback_url() ); ?>
+ <?php elseif ( comments_open() && ! pings_open() ) : // Only comments open ?>
+ <?php _e( 'Trackbacks are closed, but you can <a class="comment-link" href="#respond" title="Post a comment">post a comment</a>.', 'twentyfourteen' ); ?>
+ <?php elseif ( ! comments_open() && ! pings_open() ) : // Comments and trackbacks closed ?>
+ <?php _e( 'Both comments and trackbacks are currently closed.', 'twentyfourteen' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post-<?php the_ID(); ?> -->
+
+ <nav id="image-navigation" class="site-navigation">
+ <?php previous_image_link( false, __( '<div class="previous-image">Previous Image</div>', 'twentyfourteen' ) ); ?>
+ <?php next_image_link( false, __( '<div class="next-image">Next Image</div>', 'twentyfourteen' ) ); ?>
+ </nav><!-- #image-navigation -->
+
+ <?php comments_template(); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content .site-content -->
+</div><!-- #primary .content-area .image-attachment -->
+
+<?php get_sidebar(); ?>
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/images/pattern-dark.png b/src/wp-content/themes/twentyfourteen/images/pattern-dark.png
new file mode 100644
index 0000000000..1a6efe8287
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/images/pattern-dark.png
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/images/pattern.png b/src/wp-content/themes/twentyfourteen/images/pattern.png
new file mode 100644
index 0000000000..d7de376463
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/images/pattern.png
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/images/placeholder.png b/src/wp-content/themes/twentyfourteen/images/placeholder.png
new file mode 100644
index 0000000000..37377c352a
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/images/placeholder.png
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/inc/custom-header.php b/src/wp-content/themes/twentyfourteen/inc/custom-header.php
new file mode 100644
index 0000000000..c911e1385e
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/inc/custom-header.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+/**
+ * Setup the WordPress core custom header feature.
+ *
+ * Use add_theme_support to register support for WordPress 3.4+
+ * as well as provide backward compatibility for previous versions.
+ * Use feature detection of wp_get_theme() which was introduced
+ * in WordPress 3.4.
+ *
+ * @todo Rework this function to remove WordPress 3.4 support when WordPress 3.6 is released.
+ *
+ * @uses twentyfourteen_header_style()
+ * @uses twentyfourteen_admin_header_style()
+ * @uses twentyfourteen_admin_header_image()
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+function twentyfourteen_custom_header_setup() {
+ $args = array(
+ 'default-image' => '',
+ 'default-text-color' => 'fff',
+ 'width' => 1260,
+ 'height' => 240,
+ 'flex-height' => true,
+ 'wp-head-callback' => 'twentyfourteen_header_style',
+ 'admin-head-callback' => 'twentyfourteen_admin_header_style',
+ 'admin-preview-callback' => 'twentyfourteen_admin_header_image',
+ );
+
+ $args = apply_filters( 'twentyfourteen_custom_header_args', $args );
+
+ if ( function_exists( 'wp_get_theme' ) ) {
+ add_theme_support( 'custom-header', $args );
+ } else {
+ // Compat: Versions of WordPress prior to 3.4.
+ define( 'HEADER_TEXTCOLOR', $args['default-text-color'] );
+ define( 'HEADER_IMAGE', $args['default-image'] );
+ define( 'HEADER_IMAGE_WIDTH', $args['width'] );
+ define( 'HEADER_IMAGE_HEIGHT', $args['height'] );
+ add_custom_image_header( $args['wp-head-callback'], $args['admin-head-callback'], $args['admin-preview-callback'] );
+ }
+}
+add_action( 'after_setup_theme', 'twentyfourteen_custom_header_setup' );
+
+/**
+ * Shiv for get_custom_header().
+ *
+ * get_custom_header() was introduced to WordPress
+ * in version 3.4. To provide backward compatibility
+ * with previous versions, we will define our own version
+ * of this function.
+ *
+ * @todo Remove this function when WordPress 3.6 is released.
+ * @return stdClass All properties represent attributes of the curent header image.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+if ( ! function_exists( 'get_custom_header' ) ) {
+ function get_custom_header() {
+ return (object) array(
+ 'url' => get_header_image(),
+ 'thumbnail_url' => get_header_image(),
+ 'width' => HEADER_IMAGE_WIDTH,
+ 'height' => HEADER_IMAGE_HEIGHT,
+ );
+ }
+}
+
+if ( ! function_exists( 'twentyfourteen_header_style' ) ) :
+/**
+ * Styles the header image and text displayed on the blog
+ *
+ * @see twentyfourteen_custom_header_setup().
+ *
+ */
+function twentyfourteen_header_style() {
+
+ // If no custom options for text are set, let's bail
+ // get_header_textcolor() options: HEADER_TEXTCOLOR is default, hide text (returns 'blank') or any hex value
+ if ( HEADER_TEXTCOLOR == get_header_textcolor() )
+ return;
+ // If we get this far, we have custom styles. Let's do this.
+ ?>
+ <style type="text/css">
+ <?php
+ // Has the text been hidden?
+ if ( 'blank' == get_header_textcolor() ) :
+ ?>
+ .site-title {
+ position: absolute !important;
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ <?php
+ // If the user has set a custom color for the text use that
+ else :
+ ?>
+ .site-title a {
+ color: #<?php echo get_header_textcolor(); ?> !important;
+ }
+ <?php endif; ?>
+ </style>
+ <?php
+}
+endif; // twentyfourteen_header_style
+
+if ( ! function_exists( 'twentyfourteen_admin_header_style' ) ) :
+/**
+ * Styles the header image displayed on the Appearance > Header admin panel.
+ *
+ * @see twentyfourteen_custom_header_setup().
+ *
+ */
+function twentyfourteen_admin_header_style() {
+?>
+ <style type="text/css">
+ .appearance_page_custom-header #headimg {
+ background-color: #000;
+ border: none;
+ max-width: 1230px;
+ min-height: 48px;
+ }
+ #headimg h1 {
+ font-family: lato, sans-serif;
+ font-size: 18px;
+ line-height: 1.3333333333;
+ margin: 12px 0 12px 27px;
+ }
+ #headimg h1 a {
+ color: #fff;
+ text-decoration: none;
+ }
+ #headimg img {
+ vertical-align: middle;
+ }
+ </style>
+<?php
+}
+endif; // twentyfourteen_admin_header_style
+
+if ( ! function_exists( 'twentyfourteen_admin_header_image' ) ) :
+/**
+ * Custom header image markup displayed on the Appearance > Header admin panel.
+ *
+ * @see twentyfourteen_custom_header_setup().
+ *
+ */
+function twentyfourteen_admin_header_image() { ?>
+ <div id="headimg">
+ <?php
+ if ( 'blank' == get_header_textcolor() || '' == get_header_textcolor() )
+ $style = ' style="display:none;"';
+ else
+ $style = ' style="color:#' . get_header_textcolor() . ';"';
+ ?>
+ <?php $header_image = get_header_image();
+ if ( ! empty( $header_image ) ) : ?>
+ <img src="<?php echo esc_url( $header_image ); ?>" alt="" />
+ <?php endif; ?>
+ <h1><a id="name"<?php echo $style; ?> onclick="return false;" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
+ </div>
+<?php }
+endif; // twentyfourteen_admin_header_image \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/inc/customizer.php b/src/wp-content/themes/twentyfourteen/inc/customizer.php
new file mode 100644
index 0000000000..a3505192bf
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/inc/customizer.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * Twenty Fourteen Theme Customizer
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+/**
+ * Add postMessage support for site title and description for the Theme Customizer.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ *
+ */
+function twentyfourteen_customize_register( $wp_customize ) {
+ $wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
+ $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
+
+ $wp_customize->add_section( 'twentyfourteen_theme_options', array(
+ 'title' => __( 'Theme Options', 'twentyfourteen' ),
+ 'priority' => 35,
+ ) );
+
+ $wp_customize->add_setting( 'email_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'email_link', array(
+ 'label' => __( 'Email Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'email_link',
+ 'type' => 'text',
+ 'priority' => 1,
+ ) );
+
+ $wp_customize->add_setting( 'twitter_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'twitter_link', array(
+ 'label' => __( 'Twitter Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'twitter_link',
+ 'type' => 'text',
+ 'priority' => 2,
+ ) );
+
+ $wp_customize->add_setting( 'facebook_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'facebook_link', array(
+ 'label' => __( 'Facebook Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'facebook_link',
+ 'type' => 'text',
+ 'priority' => 3,
+ ) );
+
+ $wp_customize->add_setting( 'pinterest_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'pinterest_link', array(
+ 'label' => __( 'Pinterest Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'pinterest_link',
+ 'type' => 'text',
+ 'priority' => 4,
+ ) );
+
+ $wp_customize->add_setting( 'google_plus_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'google_plus_link', array(
+ 'label' => __( 'Google+ Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'google_plus_link',
+ 'type' => 'text',
+ 'priority' => 5,
+ ) );
+
+ $wp_customize->add_setting( 'linkedin_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'linkedin_link', array(
+ 'label' => __( 'LinkedIn Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'linkedin_link',
+ 'type' => 'text',
+ 'priority' => 6,
+ ) );
+
+ $wp_customize->add_setting( 'flickr_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'flickr_link', array(
+ 'label' => __( 'Flickr Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'flickr_link',
+ 'type' => 'text',
+ 'priority' => 7,
+ ) );
+
+ $wp_customize->add_setting( 'github_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'github_link', array(
+ 'label' => __( 'Github Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'github_link',
+ 'type' => 'text',
+ 'priority' => 8,
+ ) );
+
+ $wp_customize->add_setting( 'dribbble_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'dribbble_link', array(
+ 'label' => __( 'Dribbble Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'dribbble_link',
+ 'type' => 'text',
+ 'priority' => 9,
+ ) );
+
+ $wp_customize->add_setting( 'vimeo_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'vimeo_link', array(
+ 'label' => __( 'Vimeo Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'vimeo_link',
+ 'type' => 'text',
+ 'priority' => 10,
+ ) );
+
+ $wp_customize->add_setting( 'youtube_link', array(
+ 'default' => '',
+ 'type' => 'theme_mod',
+ 'capability' => 'edit_theme_options',
+ ) );
+
+ $wp_customize->add_control( 'youtube_link', array(
+ 'label' => __( 'YouTube Link', 'twentyfourteen' ),
+ 'section' => 'twentyfourteen_theme_options',
+ 'settings' => 'youtube_link',
+ 'type' => 'text',
+ 'priority' => 11,
+ ) );
+}
+add_action( 'customize_register', 'twentyfourteen_customize_register' );
+
+/**
+ * Binds JS handlers to make Theme Customizer preview reload changes asynchronously.
+ *
+ */
+function twentyfourteen_customize_preview_js() {
+ wp_enqueue_script( 'twentyfourteen_customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), '20120827', true );
+}
+add_action( 'customize_preview_init', 'twentyfourteen_customize_preview_js' ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/inc/template-tags.php b/src/wp-content/themes/twentyfourteen/inc/template-tags.php
new file mode 100644
index 0000000000..17b9086615
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/inc/template-tags.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * Custom template tags for this theme.
+ *
+ * Eventually, some of the functionality here could be replaced by core features
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+if ( ! function_exists( 'twentyfourteen_content_nav' ) ) :
+/**
+ * Display navigation to next/previous pages when applicable
+ *
+ */
+function twentyfourteen_content_nav( $nav_id ) {
+ global $wp_query, $post;
+
+ // Don't print empty markup on single pages if there's nowhere to navigate.
+ if ( is_single() ) {
+ $previous = ( is_attachment() ) ? get_post( $post->post_parent ) : get_adjacent_post( false, '', true );
+ $next = get_adjacent_post( false, '', false );
+
+ if ( ! $next && ! $previous )
+ return;
+ }
+
+ // Don't print empty markup in archives if there's only one page.
+ if ( $wp_query->max_num_pages < 2 && ( is_home() || is_archive() || is_search() ) )
+ return;
+
+ $nav_class = 'site-navigation paging-navigation';
+ if ( is_single() )
+ $nav_class = 'site-navigation post-navigation';
+
+ ?>
+ <nav role="navigation" id="<?php echo $nav_id; ?>" class="<?php echo $nav_class; ?>">
+ <h1 class="assistive-text"><?php _e( 'Post navigation', 'twentyfourteen' ); ?></h1>
+
+ <?php if ( is_single() ) : // navigation links for single posts ?>
+
+ <?php previous_post_link( '%link', __( '<div class="nav-previous"><span class="meta-nav">Previous Post</span>%title</div>', 'twentyfourteen' ) ); ?>
+ <?php next_post_link( '%link', __( '<div class="nav-next"><span class="meta-nav">Next Post</span>%title</div>', 'twentyfourteen' ) ); ?>
+
+ <?php elseif ( $wp_query->max_num_pages > 1 && ( is_home() || is_archive() || is_search() ) ) : // navigation links for home, archive, and search pages ?>
+
+ <div class="pagination loop-pagination">
+ <?php
+ /* Get the current page. */
+ $current = ( get_query_var( 'paged' ) ? absint( get_query_var( 'paged' ) ) : 1 );
+
+ /* Get the max number of pages. */
+ $max_num_pages = intval( $wp_query->max_num_pages );
+
+ /* Set up arguments for the paginate_links() function. */
+ $args = array(
+ 'base' => add_query_arg( 'paged', '%#%' ),
+ 'format' => '',
+ 'total' => $max_num_pages,
+ 'current' => $current,
+ 'prev_text' => __( '&larr; Previous', 'twentyfourteen' ),
+ 'next_text' => __( 'Next &rarr;', 'twentyfourteen' ),
+ 'mid_size' => 1
+ );
+
+ echo paginate_links( $args )
+ ?>
+ </div>
+ <?php endif; ?>
+
+ </nav><!-- #<?php echo $nav_id; ?> -->
+ <?php
+}
+endif; // twentyfourteen_content_nav
+
+if ( ! function_exists( 'twentyfourteen_comment' ) ) :
+/**
+ * Template for comments and pingbacks.
+ *
+ * Used as a callback by wp_list_comments() for displaying the comments.
+ *
+ */
+function twentyfourteen_comment( $comment, $args, $depth ) {
+ $GLOBALS['comment'] = $comment;
+ switch ( $comment->comment_type ) :
+ case 'pingback' :
+ case 'trackback' :
+ ?>
+ <li class="post pingback">
+ <p><?php _e( 'Pingback:', 'twentyfourteen' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( 'Edit', 'twentyfourteen' ), ' ' ); ?></p>
+ <?php
+ break;
+ default :
+ ?>
+ <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
+ <article id="comment-<?php comment_ID(); ?>" class="comment">
+ <footer>
+ <div class="comment-author vcard">
+ <span class="comment-author-avatar"><?php echo get_avatar( $comment, 32 ); ?></span>
+ <?php printf( __( '%s', 'twentyfourteen' ), sprintf( '<cite class="fn">%s</cite> says:', get_comment_author_link() ) ); ?>
+ </div><!-- .comment-author .vcard -->
+ </footer>
+
+ <div class="comment-content">
+ <?php comment_text(); ?>
+ <?php if ( $comment->comment_approved == '0' ) : ?>
+ <p><em><?php _e( 'Your comment is awaiting moderation.', 'twentyfourteen' ); ?></em></p>
+ <?php endif; ?>
+ </div>
+
+ <div class="comment-meta commentmetadata">
+ <a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>"><time pubdate datetime="<?php comment_time( 'c' ); ?>">
+ <?php
+ /* translators: 1: date, 2: time */
+ printf( __( '%1$s at %2$s', 'twentyfourteen' ), get_comment_date(), get_comment_time() ); ?>
+ </time></a>
+ <?php comment_reply_link( array_merge( $args, array( 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
+ <?php edit_comment_link( __( 'Edit', 'twentyfourteen' ), ' ' );
+ ?>
+ </div><!-- .comment-meta .commentmetadata -->
+ </article><!-- #comment-## -->
+
+ <?php
+ break;
+ endswitch;
+}
+endif; // ends check for twentyfourteen_comment()
+
+if ( ! function_exists( 'twentyfourteen_posted_on' ) ) :
+/**
+ * Prints HTML with meta information for the current post-date/time and author.
+ *
+ */
+function twentyfourteen_posted_on() {
+ if ( is_sticky() && is_home() && ! is_paged() )
+ echo '<span class="featured-post">' . __( 'Sticky', 'twentyfourteen' ) . '</span>';
+
+ printf( __( '<span class="entry-date"><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s">%4$s</time></a></span> <span class="byline"><span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'twentyfourteen' ),
+ esc_url( get_permalink() ),
+ esc_attr( get_the_time() ),
+ esc_attr( get_the_date( 'c' ) ),
+ esc_html( get_the_date() ),
+ esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentyfourteen' ), get_the_author() ) ),
+ get_the_author()
+ );
+}
+endif;
+
+/**
+ * Returns true if a blog has more than 1 category
+ *
+ */
+function twentyfourteen_categorized_blog() {
+ if ( false === ( $all_the_cool_cats = get_transient( 'all_the_cool_cats' ) ) ) {
+ // Create an array of all the categories that are attached to posts
+ $all_the_cool_cats = get_categories( array(
+ 'hide_empty' => 1,
+ ) );
+
+ // Count the number of categories that are attached to the posts
+ $all_the_cool_cats = count( $all_the_cool_cats );
+
+ set_transient( 'all_the_cool_cats', $all_the_cool_cats );
+ }
+
+ if ( '1' != $all_the_cool_cats ) {
+ // This blog has more than 1 category so twentyfourteen_categorized_blog should return true
+ return true;
+ } else {
+ // This blog has only 1 category so twentyfourteen_categorized_blog should return false
+ return false;
+ }
+}
+
+/**
+ * Flush out the transients used in twentyfourteen_categorized_blog
+ *
+ */
+function twentyfourteen_category_transient_flusher() {
+ // Like, beat it. Dig?
+ delete_transient( 'all_the_cool_cats' );
+}
+add_action( 'edit_category', 'twentyfourteen_category_transient_flusher' );
+add_action( 'save_post', 'twentyfourteen_category_transient_flusher' );
+
+/**
+ * Include the Post-Format-specific template for the content.
+ * This is called in index.php and single.php
+ */
+function twentyfourteen_get_template_part() {
+
+ $format = get_post_format();
+
+ switch( $format ) {
+ case 'aside':
+ case 'quote':
+ case 'link':
+ case 'video':
+ case 'image':
+ get_template_part( 'content', 'post-format' );
+ break;
+ default:
+ get_template_part( 'content', get_post_format() );
+ break;
+ }
+
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/index.php b/src/wp-content/themes/twentyfourteen/index.php
new file mode 100644
index 0000000000..e89b272f25
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/index.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * The main template file.
+ *
+ * This is the most generic template file in a WordPress theme
+ * and one of the two required files for a theme (the other being style.css).
+ * It is used to display a page when nothing more specific matches a query.
+ * E.g., it puts together the home page when no home.php file exists.
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+<?php if ( is_front_page() ) : ?>
+
+ <div class="front-page-content-wrapper">
+ <div class="front-page-content-main">
+
+ <?php if ( twentyfourteen_has_featured_posts() ) : ?>
+ <?php get_template_part( 'featured-content' ); ?>
+ <?php endif; ?>
+
+ <div class="front-page-content-area clearfix">
+
+ <div id="primary" class="content-area no-sidebar">
+ <div id="content" class="site-content" role="main">
+ <?php
+ if ( have_posts() ) :
+ while ( have_posts() ) :
+ the_post();
+ twentyfourteen_get_template_part();
+ endwhile;
+
+ twentyfourteen_content_nav( 'nav-below' );
+ else :
+ get_template_part( 'no-results', 'index' );
+ endif;
+ ?>
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+ <?php get_template_part( 'recent-formatted-posts' ); ?>
+
+ </div><!-- .front-page-content-area -->
+
+ </div><!-- .front-page-content-main -->
+ </div><!-- .front-page-content-wrapper -->
+
+ <?php get_sidebar(); ?>
+
+<?php else : ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php twentyfourteen_get_template_part(); ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyfourteen_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <?php get_template_part( 'no-results', 'index' ); ?>
+
+ <?php endif; ?>
+
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+ <?php get_sidebar( 'content' ); ?>
+
+ <?php get_sidebar(); ?>
+
+<?php endif; // is_front_page() check ?>
+
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyfourteen/js/customizer.js b/src/wp-content/themes/twentyfourteen/js/customizer.js
new file mode 100644
index 0000000000..df2a8f7853
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/js/customizer.js
@@ -0,0 +1,19 @@
+/**
+ * Theme Customizer enhancements for a better user experience.
+ *
+ * Contains handlers to make Theme Customizer preview reload changes asynchronously.
+ */
+
+( function( $ ) {
+ // Site title and description.
+ wp.customize( 'blogname', function( value ) {
+ value.bind( function( to ) {
+ $( '.site-title a' ).text( to );
+ } );
+ } );
+ wp.customize( 'blogdescription', function( value ) {
+ value.bind( function( to ) {
+ $( '.site-description' ).text( to );
+ } );
+ } );
+} )( jQuery ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/js/html5.js b/src/wp-content/themes/twentyfourteen/js/html5.js
new file mode 100644
index 0000000000..a7889168fb
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/js/html5.js
@@ -0,0 +1,7 @@
+/*! HTML5 Shiv v3.6 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
+/* Source: https://github.com/aFarkas/html5shiv */
+(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
+a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
+c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");
+var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,
+b){a||(a=f);if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/js/keyboard-image-navigation.js b/src/wp-content/themes/twentyfourteen/js/keyboard-image-navigation.js
new file mode 100644
index 0000000000..323af7fb4c
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/js/keyboard-image-navigation.js
@@ -0,0 +1,14 @@
+jQuery( document ).ready( function( $ ) {
+ $( document ).keydown( function( e ) {
+ var url = false;
+ if ( e.which == 37 ) { // Left arrow key code
+ url = $( '.previous-image a' ).attr( 'href' );
+ }
+ else if ( e.which == 39 ) { // Right arrow key code
+ url = $( '.entry-attachment a' ).attr( 'href' );
+ }
+ if ( url && ( !$( 'textarea, input' ).is( ':focus' ) ) ) {
+ window.location = url;
+ }
+ } );
+} ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/js/theme.js b/src/wp-content/themes/twentyfourteen/js/theme.js
new file mode 100644
index 0000000000..b295b8cdba
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/js/theme.js
@@ -0,0 +1,128 @@
+( function( $ ) {
+
+ $( document ).ready( function() {
+
+ var $primaryNaviClone,
+ $secondaryNaviClone,
+ $masthead = $( 'header#masthead' ),
+ $secondaryTop = $( 'div#secondary-top' ),
+ $mobileNavigations = $( 'div#mobile-navigations'),
+ $socialLinksWrapper = $( 'div.social-links-wrapper' ),
+ $searchBoxWrapper = $( 'div.search-box-wrapper' ),
+ $searchToggle = $( 'div.search-toggle' ),
+ $socialLinksToggle = $( 'div.social-links-toggle' ),
+ timeout = false;
+
+ // Toggle function.
+ function menuToggle() {
+ $( 'span#nav-toggle' ).toggleClass( 'active' );
+ $masthead.find( 'div#mobile-navigations' ).toggleClass( 'hide' );
+ }
+
+ // Click event for toggle the social links
+ $socialLinksToggle.click( function() {
+ $( this ).toggleClass( 'active' );
+ $socialLinksWrapper.toggleClass( 'hide' );
+ // if .search-box-wrapper is visible hide it
+ if ( ! $searchBoxWrapper.hasClass( 'hide' ) ) {
+ $searchBoxWrapper.addClass( 'hide' );
+ }
+ if ( $searchToggle.hasClass( 'active' ) ) {
+ $searchToggle.removeClass( 'active' );
+ }
+ } );
+
+ // Click event for toggle the search
+ $searchToggle.click( function() {
+ $( this ).toggleClass( 'active' );
+ $searchBoxWrapper.toggleClass( 'hide' );
+ // if .social-links-wrapper is visible hide it
+ if ( ! $socialLinksWrapper.hasClass( 'hide' ) ) {
+ $socialLinksWrapper.addClass( 'hide' );
+ }
+ if ( $socialLinksToggle.hasClass( 'active' ) ) {
+ $socialLinksToggle.removeClass( 'active' );
+ }
+ } );
+
+ // DOM manupilations for mobile header
+ function mobileHeader() {
+ // Check if the toggler exists. If not add it.
+ if ( ! $( 'span#nav-toggle' ).length )
+ $( '<span id="nav-toggle" class="genericon" />' ).appendTo( $masthead );
+
+ // Clone and detach the primary navigation for use later
+ $primaryNaviClone = $masthead.find( 'nav.primary-navigation' ).detach();
+
+ // Clone and detach the secondary navigation for use later
+ $secondaryNaviClone = $secondaryTop.find( 'nav.secondary-navigation' ).detach();
+
+ // Prepend the primary navigation clone to #mobile-navigations and remove the class and add an id
+ $primaryNaviClone.prependTo( $mobileNavigations ).removeClass( 'primary-navigation' ).addClass( 'mobile-navigation' ).attr( 'id', 'primary-mobile-navigation' );
+
+ // Append the secondary navigation clone to #mobile-navigations and remove the class and add an id
+ $secondaryNaviClone.appendTo( $mobileNavigations ).removeClass( 'secondary-navigation' ).addClass( 'mobile-navigation' ).attr( 'id', 'secondary-mobile-navigation' );
+
+ // Remove the click event first and bind it after to make sure it's invoked once.
+ $( 'span#nav-toggle' ).off( 'click', menuToggle ).click( menuToggle );
+ };
+
+ // DOM manupilations for desktop header
+ function normalHeader() {
+ // Check if the toggler exists. If it does remove it.
+ if ( $( 'span#nav-toggle').length )
+ $( 'span#nav-toggle' ).remove();
+
+ // Clone and detach the primary mobile navigation for use later
+ $primaryNaviClone = $mobileNavigations.find( '#primary-mobile-navigation' ).detach();
+
+ // Clone and detach the secondary mobile navigation for use later
+ $secondaryNaviClone = $mobileNavigations.find( '#secondary-mobile-navigation' ).detach();
+
+ // Append the secondary navigation clone to #mobile-navigations and remove the class and add an id
+ $primaryNaviClone.appendTo( '.header-main' ).removeClass( 'mobile-navigation' ).removeAttr( 'id' ).addClass( 'primary-navigation' );
+
+ // Append the secondary navigation clone to #mobile-navigations and remove the class and add an id
+ $secondaryNaviClone.appendTo( $secondaryTop ).removeClass( 'mobile-navigation' ).removeAttr( 'id' ).addClass( 'secondary-navigation' );
+ };
+
+ // Check viewport width when user resizes the browser window.
+ $( window ).resize( function() {
+ if ( false !== timeout )
+ clearTimeout( timeout );
+
+ timeout = setTimeout( function() {
+ if ( $( window ).width() < 770 ) {
+ mobileHeader();
+ } else {
+ normalHeader();
+ }
+ }, 100 );
+
+ } ).resize();
+
+ // Sticky header.
+ var $mastheadOffset = -1,
+ $toolbarOffset = $( 'body' ).is( '.admin-bar' ) ? 32 : 0,
+ $maindiv = $( 'div#main' );
+
+ $( window ).on( 'scroll', false, function() {
+ if ( $mastheadOffset < 0 )
+ $mastheadOffset = $masthead.offset().top - $toolbarOffset;
+
+ if ( ( window.scrollY >= $mastheadOffset ) && ( $( window ).width() > 769 ) ) {
+ $masthead.addClass( 'masthead-fixed' );
+ $maindiv.css( {
+ marginTop: $masthead.height()
+ } );
+ } else {
+ $masthead.removeClass( 'masthead-fixed' );
+ $maindiv.css( {
+ marginTop: 0
+ } );
+ }
+ } );
+
+ } );
+
+} )( jQuery ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/languages/twentyfourteen.pot b/src/wp-content/themes/twentyfourteen/languages/twentyfourteen.pot
new file mode 100644
index 0000000000..10bf8a9f9c
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/languages/twentyfourteen.pot
@@ -0,0 +1,539 @@
+# Copyright (C) 2013 the WordPress team
+# This file is distributed under the GNU General Public License v2 or later.
+msgid ""
+msgstr ""
+"Project-Id-Version: Twenty Fourteen 0.1\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tags/twentyfourteen\n"
+"POT-Creation-Date: 2013-07-28 22:14:19+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: 404.php:16
+msgid "Oops! That page can&rsquo;t be found."
+msgstr ""
+
+#: 404.php:20
+msgid "It looks like nothing was found at this location. Maybe try one of the links below or a search?"
+msgstr ""
+
+#: archive.php:22
+msgid "Category Archives: %s"
+msgstr ""
+
+#: archive.php:25
+msgid "Tag Archives: %s"
+msgstr ""
+
+#: archive.php:32
+msgid "Author Archives: %s"
+msgstr ""
+
+#: archive.php:40
+msgid "Daily Archives: %s"
+msgstr ""
+
+#: archive.php:43
+msgid "Monthly Archives: %s"
+msgstr ""
+
+#: archive.php:46
+msgid "Yearly Archives: %s"
+msgstr ""
+
+#: archive.php:49 sidebar.php:36
+msgid "Archives"
+msgstr ""
+
+#: comments.php:32
+msgid "One thought on &ldquo;%2$s&rdquo;"
+msgid_plural "%1$s thoughts on &ldquo;%2$s&rdquo;"
+msgstr[0] ""
+msgstr[1] ""
+
+#: comments.php:39 comments.php:59
+msgid "Comment navigation"
+msgstr ""
+
+#: comments.php:40 comments.php:60
+msgid "&larr; Older Comments"
+msgstr ""
+
+#: comments.php:41 comments.php:61
+msgid "Newer Comments &rarr;"
+msgstr ""
+
+#: comments.php:71
+msgid "Comments are closed."
+msgstr ""
+
+#: content-featured-post.php:9 content-post-format.php:15
+#: content-recent-formatted-post.php:29 content-recent-formatted-post.php:45
+#: content.php:10
+msgid "Permalink to %s"
+msgstr ""
+
+#. translators: used between list items, there is a space after the comma
+
+#: content-featured-post.php:29 content-post-format.php:25
+#: content-single.php:25 content.php:20
+msgid ", "
+msgstr ""
+
+#: content-page.php:19 content-post-format.php:60 content-single.php:59
+#: content.php:59 image.php:85
+msgid "Pages:"
+msgstr ""
+
+#: content-page.php:25 content-post-format.php:52 content-single.php:51
+#: content.php:46 image.php:29 inc/template-tags.php:90
+#: inc/template-tags.php:118
+msgid "Edit"
+msgstr ""
+
+#: content-post-format.php:40 content-single.php:41 content.php:33
+msgid "All %s posts"
+msgstr ""
+
+#: content-post-format.php:49 content-recent-formatted-post.php:50
+#: content-single.php:48 content.php:43
+msgid "Leave a comment"
+msgstr ""
+
+#: content-post-format.php:49 content-recent-formatted-post.php:50
+#: content-single.php:48 content.php:43
+msgid "1 Comment"
+msgstr ""
+
+#: content-post-format.php:49 content-recent-formatted-post.php:50
+#: content-single.php:48 content.php:43
+msgid "% Comments"
+msgstr ""
+
+#: content-post-format.php:57 content-recent-formatted-post.php:36
+#: content.php:56
+msgid "Continue reading <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: content-recent-formatted-post.php:28
+msgid "This gallery contains <a %1$s>%2$s photo</a>."
+msgid_plural "This gallery contains <a %1$s>%2$s photos</a>."
+msgstr[0] ""
+msgstr[1] ""
+
+#: footer.php:19
+msgid "http://wordpress.org/"
+msgstr ""
+
+#: footer.php:19
+msgid "Semantic Personal Publishing Platform"
+msgstr ""
+
+#: footer.php:19
+msgid "Proudly powered by %s"
+msgstr ""
+
+#: functions.php:72
+msgid "Top primary menu"
+msgstr ""
+
+#: functions.php:73
+msgid "Secondary menu in left sidebar"
+msgstr ""
+
+#: functions.php:133
+msgid "Primary Sidebar"
+msgstr ""
+
+#: functions.php:135
+msgid "Main sidebar that appears on the left."
+msgstr ""
+
+#: functions.php:142
+msgid "Content Sidebar"
+msgstr ""
+
+#: functions.php:144
+msgid "Additional sidebar that appears on the right, on single posts and pages."
+msgstr ""
+
+#: functions.php:151
+msgid "Footer Widget Area One"
+msgstr ""
+
+#: functions.php:159
+msgid "Footer Widget Area Two"
+msgstr ""
+
+#: functions.php:167
+msgid "Footer Widget Area Three"
+msgstr ""
+
+#: functions.php:175
+msgid "Footer Widget Area Four"
+msgstr ""
+
+#: functions.php:183
+msgid "Footer Widget Area Five"
+msgstr ""
+
+#. translators: If there are characters in your language that are not supported
+#. by Lato, translate this to 'off'. Do not translate into your own
+#. language.
+
+#: functions.php:200
+msgctxt "Lato font: on or off"
+msgid "on"
+msgstr ""
+
+#: functions.php:262
+msgid "Read More <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: functions.php:442
+msgid "Page %s"
+msgstr ""
+
+#: header.php:77
+msgid "Connect"
+msgstr ""
+
+#: header.php:82 searchform.php:10 searchform.php:12
+msgid "Search"
+msgstr ""
+
+#: header.php:87
+msgid "Primary Menu"
+msgstr ""
+
+#: header.php:88
+msgid "Skip to content"
+msgstr ""
+
+#: header.php:101 header.php:102
+msgid "Email"
+msgstr ""
+
+#: header.php:109 header.php:110
+msgid "Twitter"
+msgstr ""
+
+#: header.php:117 header.php:118
+msgid "Facebook"
+msgstr ""
+
+#: header.php:125 header.php:126
+msgid "Pinterest"
+msgstr ""
+
+#: header.php:133 header.php:134
+msgid "Google Plus"
+msgstr ""
+
+#: header.php:141 header.php:142
+msgid "LinkedIn"
+msgstr ""
+
+#: header.php:149 header.php:150
+msgid "Flickr"
+msgstr ""
+
+#: header.php:157 header.php:158
+msgid "Github"
+msgstr ""
+
+#: header.php:165 header.php:166
+msgid "Dribbble"
+msgstr ""
+
+#: header.php:173 header.php:174
+msgid "Vimeo"
+msgstr ""
+
+#: header.php:181 header.php:182
+msgid "YouTube"
+msgstr ""
+
+#: image.php:95
+msgid "<a class=\"comment-link\" href=\"#respond\" title=\"Post a comment\">Post a comment</a> or leave a trackback: <a class=\"trackback-link\" href=\"%s\" title=\"Trackback URL for your post\" rel=\"trackback\">Trackback URL</a>."
+msgstr ""
+
+#: image.php:97
+msgid "Comments are closed, but you can leave a trackback: <a class=\"trackback-link\" href=\"%s\" title=\"Trackback URL for your post\" rel=\"trackback\">Trackback URL</a>."
+msgstr ""
+
+#: image.php:99
+msgid "Trackbacks are closed, but you can <a class=\"comment-link\" href=\"#respond\" title=\"Post a comment\">post a comment</a>."
+msgstr ""
+
+#: image.php:101
+msgid "Both comments and trackbacks are currently closed."
+msgstr ""
+
+#: image.php:107
+msgid "<div class=\"previous-image\">Previous Image</div>"
+msgstr ""
+
+#: image.php:108
+msgid "<div class=\"next-image\">Next Image</div>"
+msgstr ""
+
+#: inc/customizer.php:20
+msgid "Theme Options"
+msgstr ""
+
+#: inc/customizer.php:31
+msgid "Email Link"
+msgstr ""
+
+#: inc/customizer.php:45
+msgid "Twitter Link"
+msgstr ""
+
+#: inc/customizer.php:59
+msgid "Facebook Link"
+msgstr ""
+
+#: inc/customizer.php:73
+msgid "Pinterest Link"
+msgstr ""
+
+#: inc/customizer.php:87
+msgid "Google+ Link"
+msgstr ""
+
+#: inc/customizer.php:101
+msgid "LinkedIn Link"
+msgstr ""
+
+#: inc/customizer.php:115
+msgid "Flickr Link"
+msgstr ""
+
+#: inc/customizer.php:129
+msgid "Github Link"
+msgstr ""
+
+#: inc/customizer.php:143
+msgid "Dribbble Link"
+msgstr ""
+
+#: inc/customizer.php:157
+msgid "Vimeo Link"
+msgstr ""
+
+#: inc/customizer.php:171
+msgid "YouTube Link"
+msgstr ""
+
+#: inc/template-tags.php:38
+msgid "Post navigation"
+msgstr ""
+
+#: inc/template-tags.php:42
+msgid "<div class=\"nav-previous\"><span class=\"meta-nav\">Previous Post</span>%title</div>"
+msgstr ""
+
+#: inc/template-tags.php:43
+msgid "<div class=\"nav-next\"><span class=\"meta-nav\">Next Post</span>%title</div>"
+msgstr ""
+
+#: inc/template-tags.php:61
+msgid "&larr; Previous"
+msgstr ""
+
+#: inc/template-tags.php:62
+msgid "Next &rarr;"
+msgstr ""
+
+#: inc/template-tags.php:90
+msgid "Pingback:"
+msgstr ""
+
+#: inc/template-tags.php:100
+msgid "%s"
+msgstr ""
+
+#: inc/template-tags.php:107
+msgid "Your comment is awaiting moderation."
+msgstr ""
+
+#. translators: 1: date, 2: time
+
+#: inc/template-tags.php:115
+msgid "%1$s at %2$s"
+msgstr ""
+
+#: inc/template-tags.php:136
+msgid "Sticky"
+msgstr ""
+
+#: inc/template-tags.php:138
+msgid "<span class=\"entry-date\"><a href=\"%1$s\" title=\"%2$s\" rel=\"bookmark\"><time class=\"entry-date\" datetime=\"%3$s\">%4$s</time></a></span> <span class=\"byline\"><span class=\"author vcard\"><a class=\"url fn n\" href=\"%5$s\" title=\"%6$s\" rel=\"author\">%7$s</a></span></span>"
+msgstr ""
+
+#: inc/template-tags.php:144
+msgid "View all posts by %s"
+msgstr ""
+
+#: no-results.php:14
+msgid "Nothing Found"
+msgstr ""
+
+#: no-results.php:20
+msgid "Ready to publish your first post? <a href=\"%1$s\">Get started here</a>."
+msgstr ""
+
+#: no-results.php:24
+msgid "Sorry, but nothing matched your search terms. Please try again with some different keywords."
+msgstr ""
+
+#: no-results.php:29
+msgid "It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help."
+msgstr ""
+
+#: recent-formatted-posts.php:19
+msgid "All Video Posts"
+msgstr ""
+
+#: recent-formatted-posts.php:19
+msgid "Videos"
+msgstr ""
+
+#: recent-formatted-posts.php:26
+msgid "More Videos"
+msgstr ""
+
+#: recent-formatted-posts.php:26
+msgid "More Videos <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: recent-formatted-posts.php:36
+msgid "All Image Posts"
+msgstr ""
+
+#: recent-formatted-posts.php:36
+msgid "Images"
+msgstr ""
+
+#: recent-formatted-posts.php:43
+msgid "More images"
+msgstr ""
+
+#: recent-formatted-posts.php:43
+msgid "More images <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: recent-formatted-posts.php:53
+msgid "All Gallery Posts"
+msgstr ""
+
+#: recent-formatted-posts.php:53
+msgid "Galleries"
+msgstr ""
+
+#: recent-formatted-posts.php:60
+msgid "More Galleries"
+msgstr ""
+
+#: recent-formatted-posts.php:60
+msgid "More galleries <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: recent-formatted-posts.php:70
+msgid "All Aside Posts"
+msgstr ""
+
+#: recent-formatted-posts.php:70
+msgid "Asides"
+msgstr ""
+
+#: recent-formatted-posts.php:77
+msgid "More Asides"
+msgstr ""
+
+#: recent-formatted-posts.php:77
+msgid "More asides <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: recent-formatted-posts.php:87
+msgid "All Link Posts"
+msgstr ""
+
+#: recent-formatted-posts.php:87
+msgid "Links"
+msgstr ""
+
+#: recent-formatted-posts.php:94
+msgid "More Links"
+msgstr ""
+
+#: recent-formatted-posts.php:94
+msgid "More links <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: recent-formatted-posts.php:104
+msgid "All Quote Posts"
+msgstr ""
+
+#: recent-formatted-posts.php:104
+msgid "Quotes"
+msgstr ""
+
+#: recent-formatted-posts.php:111
+msgid "More Quotes"
+msgstr ""
+
+#: recent-formatted-posts.php:111
+msgid "More quotes <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: search.php:17
+msgid "Search Results for: %s"
+msgstr ""
+
+#: searchform.php:11
+msgid "Search &hellip;"
+msgstr ""
+
+#: sidebar-content.php:18
+msgid "Blogroll"
+msgstr ""
+
+#: sidebar-content.php:25
+msgid "Meta"
+msgstr ""
+
+#: sidebar.php:29
+msgid "Categories"
+msgstr ""
+#. Theme Name of the plugin/theme
+msgid "Twenty Fourteen"
+msgstr ""
+
+#. Theme URI of the plugin/theme
+msgid "http://wordpress.org/themes/"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid "The default theme for 2014 is a magazine theme with a sleek, modern, and beautifully crafted responsive design. As a magazine theme it highlights featured content prominently on the home page."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "the WordPress team"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://wordpress.org/"
+msgstr ""
+
+#. Tags of the plugin/theme
+msgid "black, green, white, light, dark, two-columns, three-columns, fixed-width, responsive-width, custom-background, custom-header, custom-menu, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready"
+msgstr ""
+
+#. Template Name of the plugin/theme
+msgid "Full Width Page"
+msgstr ""
diff --git a/src/wp-content/themes/twentyfourteen/no-results.php b/src/wp-content/themes/twentyfourteen/no-results.php
new file mode 100644
index 0000000000..342a2dc8cc
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/no-results.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * The template part for displaying a message that posts cannot be found.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+
+<article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyfourteen' ); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php if ( is_home() && current_user_can( 'publish_posts' ) ) : ?>
+
+ <p><?php printf( __( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'twentyfourteen' ), admin_url( 'post-new.php' ) ); ?></p>
+
+ <?php elseif ( is_search() ) : ?>
+
+ <p><?php _e( 'Sorry, but nothing matched your search terms. Please try again with some different keywords.', 'twentyfourteen' ); ?></p>
+ <?php get_search_form(); ?>
+
+ <?php else : ?>
+
+ <p><?php _e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'twentyfourteen' ); ?></p>
+ <?php get_search_form(); ?>
+
+ <?php endif; ?>
+ </div><!-- .entry-content -->
+</article><!-- #post-0 .post .no-results .not-found -->
diff --git a/src/wp-content/themes/twentyfourteen/page.php b/src/wp-content/themes/twentyfourteen/page.php
new file mode 100644
index 0000000000..15dc518048
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/page.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * The template for displaying all pages.
+ *
+ * This is the template that displays all pages by default.
+ * Please note that this is the WordPress construct of pages
+ * and that other 'pages' on your WordPress site will use a
+ * different template.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+<?php if ( is_front_page() ) : ?>
+
+ <div class="front-page-content-wrapper">
+ <div class="front-page-content-main">
+
+ <?php if ( twentyfourteen_has_featured_posts() ) : ?>
+ <?php get_template_part( 'featured-content' ); ?>
+ <?php endif; ?>
+
+ <div class="front-page-content-area clearfix">
+
+ <div id="primary" class="content-area no-sidebar">
+ <div id="content" class="site-content" role="main">
+ <?php
+ if ( have_posts() ) :
+ while ( have_posts() ) :
+ the_post();
+ get_template_part( 'content', 'page' );
+ comments_template( '', true );
+ endwhile;
+
+ twentyfourteen_content_nav( 'nav-below' );
+ else :
+ get_template_part( 'no-results', 'index' );
+ endif;
+ ?>
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+ <?php get_template_part( 'recent-formatted-posts' ); ?>
+
+ </div><!-- .front-page-content-area -->
+
+ </div><!-- .front-page-content-main -->
+ </div><!-- .front-page-content-wrapper -->
+
+ <?php get_sidebar(); ?>
+
+<?php else : ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', 'page' ); ?>
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endwhile; ?>
+
+ </div><!-- #content .site-content -->
+ </div><!-- #primary .content-area -->
+
+ <?php get_sidebar( 'content' ); ?>
+
+ <?php get_sidebar(); ?>
+
+<?php endif; // is_front_page() check ?>
+
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyfourteen/recent-formatted-posts.php b/src/wp-content/themes/twentyfourteen/recent-formatted-posts.php
new file mode 100644
index 0000000000..4848e9587e
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/recent-formatted-posts.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * A template to display recent post formatted posts.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+
+<div class="post-formatted-posts">
+<?php
+ do_action( 'before_sidebar' );
+ do_action( 'twentyfourteen_formatted_posts_before' );
+ $recent_videos = twentyfourteen_get_recent( 'post-format-video' );
+ if ( $recent_videos->have_posts() ) :
+?>
+ <section id="recent-videos" class="recent-videos">
+ <h1 class="format-title genericon">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( 'video' ) ); ?>" title="<?php esc_attr_e( 'All Video Posts', 'twentyfourteen' ); ?>"><?php _e( 'Videos', 'twentyfourteen' ); ?></a>
+ </h1>
+ <?php
+ while ( $recent_videos->have_posts() ) : $recent_videos->the_post();
+ get_template_part( 'content', 'recent-formatted-post' );
+ endwhile;
+ ?>
+ <a class="more-formatted-posts-link" href="<?php echo esc_url( get_post_format_link( 'video' ) ); ?>" title="<?php esc_attr_e( 'More Videos', 'twentyfourteen' ); ?>"><?php _e( 'More Videos <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ); ?></a>
+ </section>
+<?php endif; ?>
+
+<?php
+ $recent_images = twentyfourteen_get_recent( 'post-format-image' );
+ if ( $recent_images->have_posts() ) :
+?>
+ <section id="recent-images" class="recent-images">
+ <h1 class="format-title genericon">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( 'image' ) ); ?>" title="<?php esc_attr_e( 'All Image Posts', 'twentyfourteen' ); ?>"><?php _e( 'Images', 'twentyfourteen' ); ?></a>
+ </h1>
+ <?php
+ while ( $recent_images->have_posts() ) : $recent_images->the_post();
+ get_template_part( 'content', 'recent-formatted-post' );
+ endwhile;
+ ?>
+ <a class="more-formatted-posts-link" href="<?php echo esc_url( get_post_format_link( 'image' ) ); ?>" title="<?php esc_attr_e( 'More images', 'twentyfourteen' ); ?>"><?php _e( 'More images <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ); ?></a>
+ </section>
+<?php endif; ?>
+
+<?php
+ $recent_galleries = twentyfourteen_get_recent( 'post-format-gallery' );
+ if ( $recent_galleries->have_posts() ) :
+?>
+ <section id="recent-galleries" class="recent-galleries">
+ <h1 class="format-title genericon">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( 'gallery' ) ); ?>" title="<?php esc_attr_e( 'All Gallery Posts', 'twentyfourteen' ); ?>"><?php _e( 'Galleries', 'twentyfourteen' ); ?></a>
+ </h1>
+ <?php
+ while ( $recent_galleries->have_posts() ) : $recent_galleries->the_post();
+ get_template_part( 'content', 'recent-formatted-post' );
+ endwhile;
+ ?>
+ <a class="more-formatted-posts-link" href="<?php echo esc_url( get_post_format_link( 'gallery' ) ); ?>" title="<?php esc_attr_e( 'More Galleries', 'twentyfourteen' ); ?>"><?php _e( 'More galleries <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ); ?></a>
+ </section>
+<?php endif; ?>
+
+<?php
+ $recent_asides = twentyfourteen_get_recent( 'post-format-aside' );
+ if ( $recent_asides->have_posts() ) :
+?>
+ <section id="recent-asides" class="recent-asides">
+ <h1 class="format-title genericon">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( 'aside' ) ); ?>" title="<?php esc_attr_e( 'All Aside Posts', 'twentyfourteen' ); ?>"><?php _e( 'Asides', 'twentyfourteen' ); ?></a>
+ </h1>
+ <?php
+ while ( $recent_asides->have_posts() ) : $recent_asides->the_post();
+ get_template_part( 'content', 'recent-formatted-post' );
+ endwhile;
+ ?>
+ <a class="more-formatted-posts-link" href="<?php echo esc_url( get_post_format_link( 'aside' ) ); ?>" title="<?php esc_attr_e( 'More Asides', 'twentyfourteen' ); ?>"><?php _e( 'More asides <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ); ?></a>
+ </section>
+<?php endif; ?>
+
+<?php
+ $recent_links = twentyfourteen_get_recent( 'post-format-link' );
+ if ( $recent_links->have_posts() ) :
+?>
+ <section id="recent-links" class="recent-links">
+ <h1 class="format-title genericon">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( 'link' ) ); ?>" title="<?php esc_attr_e( 'All Link Posts', 'twentyfourteen' ); ?>"><?php _e( 'Links', 'twentyfourteen' ); ?></a>
+ </h1>
+ <?php
+ while ( $recent_links->have_posts() ) : $recent_links->the_post();
+ get_template_part( 'content', 'recent-formatted-post' );
+ endwhile;
+ ?>
+ <a class="more-formatted-posts-link" href="<?php echo esc_url( get_post_format_link( 'link' ) ); ?>" title="<?php esc_attr_e( 'More Links', 'twentyfourteen' ); ?>"><?php _e( 'More links <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ); ?></a>
+ </section>
+<?php endif; ?>
+
+<?php
+ $recent_quotes = twentyfourteen_get_recent( 'post-format-quote' );
+ if ( $recent_quotes->have_posts() ) :
+?>
+ <section id="recent-quotes" class="recent-quotes">
+ <h1 class="format-title genericon">
+ <a class="entry-format" href="<?php echo esc_url( get_post_format_link( 'quote' ) ); ?>" title="<?php esc_attr_e( 'All Quote Posts', 'twentyfourteen' ); ?>"><?php _e( 'Quotes', 'twentyfourteen' ); ?></a>
+ </h1>
+ <?php
+ while ( $recent_quotes->have_posts() ) : $recent_quotes->the_post();
+ get_template_part( 'content', 'recent-formatted-post' );
+ endwhile;
+ ?>
+ <a class="more-formatted-posts-link" href="<?php echo esc_url( get_post_format_link( 'quote' ) ); ?>" title="<?php esc_attr_e( 'More Quotes', 'twentyfourteen' ); ?>"><?php _e( 'More quotes <span class="meta-nav">&rarr;</span>', 'twentyfourteen' ); ?></a>
+ </section>
+<?php endif; ?>
+
+<?php
+ wp_reset_postdata();
+ do_action( 'twentyfourteen_formatted_posts_after' );
+?>
+
+</div> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/rtl.css b/src/wp-content/themes/twentyfourteen/rtl.css
new file mode 100644
index 0000000000..a960997731
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/rtl.css
@@ -0,0 +1,859 @@
+/*
+Theme Name: Twenty Fourteen
+*/
+
+body {
+ direction: rtl;
+ unicode-bidi: embed;
+}
+
+/* =Reset
+----------------------------------------------- */
+
+caption, th, td {
+ text-align: right;
+}
+
+
+/* =Global
+----------------------------------------------- */
+
+/* Text elements */
+
+ul, ol {
+ margin: 0 22px 24px 0;
+ margin: 0 2.2rem 2.4rem 0;
+}
+
+ul ul, ol ol, ul ol, ol ul {
+ margin-right: 20px;
+ margin-right: 2.0rem;
+ margin-left: auto;
+}
+
+blockquote.pull.alignright {
+ margin: 7px 0 7px 24px;
+ margin: 0.7rem 0 0.7rem 2.4rem;
+}
+
+blockquote.pull.alignleft {
+ margin: 7px 24px 7px 0;
+ margin: 0.7rem 2.4rem 0.7rem 0;
+}
+
+/* Alignment */
+.alignright {
+ float: right;
+ margin-left: 24px;
+ margin-left: 2.4rem;
+ margin-right: auto;
+}
+
+.alignleft {
+ float: left;
+ margin-right: 24px;
+ margin-right: 2.4rem;
+ margin-left: auto;
+}
+
+/* =Header
+----------------------------------------------- */
+
+.header-main {
+ margin-left: 48px;
+ margin-left: 4.8rem;
+ padding-right: 10px;
+ padding-right: 1.0rem;
+ padding-left: 0;
+ margin-right: auto;
+}
+
+.header-extra {
+ float: left;
+}
+
+.site-title {
+ float: right;
+}
+
+#nav-toggle {
+ left: 0;
+ right: auto;
+}
+
+.social-links-toggle,
+.search-toggle {
+ float: right;
+}
+
+.social-links-toggle {
+ border-left: 1px solid rgba(255, 255, 255, 0.4);
+ border-right: none;
+}
+
+.social-links-toggle span:before,
+.search-toggle span:before {
+ margin-right: -8px;
+ margin-right: -0.8rem;
+ right: 50%;
+ left: auto;
+ margin-left: auto;
+}
+
+.social-links li {
+ float: left;
+ margin: 8px 0 8px 10px;
+ margin: 0.8rem 0 0.8rem 1.0rem;
+}
+
+.search-box #searchform input[type="text"] {
+ float: left;
+}
+
+
+/* =Menu
+----------------------------------------------- */
+
+/* Primary Navigation */
+.primary-navigation {
+ float: left;
+ margin: 0 -10px 0 10px;
+ margin: 0 -1.0rem 0 1.0rem;
+}
+
+.primary-navigation ul {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.primary-navigation ul ul {
+ float: right;
+ right: 0;
+ left: auto;
+}
+
+.primary-navigation ul ul ul {
+ right: 100%;
+ left: auto;
+}
+
+/* Secondary Navigation */
+.secondary-navigation ul ul {
+ margin: 0 20px 0 0;
+ margin: 0 2.0rem 0 0;
+}
+
+/* Mobile Navigations */
+.mobile-navigation ul ul li {
+ margin-right: 15px;
+ margin-right: 1.5rem;
+ margin-left: auto;
+}
+
+
+/* =Content
+----------------------------------------------- */
+
+.entry-content th,
+.comment-content th {
+ border-left: 1px solid rgba(0, 0, 0, 0.1);
+ border-right: none;
+}
+
+.entry-content td,
+.comment-content td {
+ border-left: 1px solid rgba(0, 0, 0, 0.1);
+ border-right: none;
+}
+
+.more-link .meta-nav,
+.more-formatted-posts-link .meta-nav {
+ right: 0;
+ left: auto;
+}
+
+.more-link:hover .meta-nav,
+.more-formatted-posts-link:hover .meta-nav {
+ right: 5px;
+ right: 0.5rem;
+ left: auto;
+}
+
+.page-links a,
+.page-links > span {
+ margin-left: 1px;
+ margin-left: 0.1rem;
+ margin-right: auto;
+}
+
+.page-links > span.page-links-title {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.tag-links a {
+ margin: 0 10px 4px 4px;
+ margin: 0 1.0rem 0.4rem 0.4rem;
+}
+
+.tag-links a:before {
+ border-left: 10px solid #8c8c8c;
+ right: -10px;
+ right: -1.0rem;
+ left: auto;
+ border-right: none;
+}
+
+.tag-links a:hover:before {
+ border-left-color: #2b2b2b;
+}
+
+.tag-links a:after {
+ right: -2px;
+ right: -0.2rem;
+ left: auto;
+}
+
+
+/* =Post Formatted posts column
+----------------------------------------------- */
+
+.format-title:before {
+ margin-left: 10px;
+ margin-left: 1.0rem;
+ margin-right: auto;
+}
+
+
+/* =Media
+----------------------------------------------- */
+
+img.alignright,
+.wp-caption.alignright {
+ margin: 7px 0 7px 24px;
+ margin: 0.7rem 0 0.7rem 2.4rem;
+}
+
+img.alignleft,
+.wp-caption.alignleft {
+ margin: 7px 24px 7px 0;
+ margin: 0.7rem 2.4rem 0.7rem 0;
+}
+
+.wp-caption-text {
+ padding: 0 0 0 10px;
+ padding: 0 0 0 1.0rem;
+ text-align: right;
+}
+
+
+/* =Navigation
+----------------------------------------------- */
+
+.paging-navigation .page-numbers {
+ margin-left: 5px;
+ margin-left: 0.5rem;
+ margin-right: auto;
+}
+
+.post-navigation .nav-previous,
+.post-navigation .nav-next,
+#image-navigation .previous-image,
+#image-navigation .next-image {
+ text-align: right;
+}
+
+.comment-navigation {
+ padding-right: 10px;
+ padding-right: 1.0rem;
+ padding-left: 0;
+}
+
+.comment-navigation .nav-previous a {
+ margin-left: 10px;
+ margin-right: auto;
+}
+
+
+/* =Comments
+----------------------------------------------- */
+
+.comment-author {
+ padding-right: 36px;
+ padding-right: 3.6rem;
+ padding-left: 0;
+}
+
+.comment-author .comment-author-avatar {
+ right: 0;
+ left: auto;
+}
+
+.comment-author .avatar {
+ right: 2px;
+ right: 0.2rem;
+ left: auto;
+}
+
+.comment-meta,
+.comment-content {
+ padding-right: 36px;
+ padding-right: 3.6rem;
+ padding-left: 0;
+}
+
+.comment-content ul,
+.comment-content ol {
+ margin: 0 22px 24px 0;
+ margin: 0 2.2rem 2.4rem 0;
+}
+
+.commentlist .children {
+ margin-right: 20px;
+ margin-right: 2.0rem;
+ margin-left: auto;
+}
+
+#comments li #respond {
+ margin-right: 47px;
+ margin-right: 4.7rem;
+ margin-left: auto;
+}
+
+
+/* =Widgets
+----------------------------------------------- */
+
+.widget ul ul,
+.widget ol ol,
+.widget ul ol,
+.widget ol ul {
+ margin: 0 10px 0 0;
+ margin: 0 1.0rem 0 0;
+}
+
+.widget select,
+.widget iframe {
+ margin-right: 1px;
+ margin-right: 0.1rem;
+ margin-left: auto;
+}
+
+/* Authors Widget */
+.widget_authors img {
+ margin: 0 0 9px 5px;
+ margin: 0 0 0.9rem 0.5rem;
+}
+
+/* Caledar widget*/
+.widget_calendar #wp-calendar caption {
+ text-align: right;
+}
+
+.widget_calendar #wp-calendar tfoot td#prev {
+ padding-right: 5px;
+ padding-right: 0.5rem;
+ padding-left: 0;
+}
+
+.widget_calendar #wp-calendar tfoot td#next {
+ border-left: 1px solid rgba(255, 255, 255, 0.2);
+ padding-left: 5px;
+ padding-left: 0.5rem;
+ text-align: left;
+ padding-right: 0;
+ border-right: none;
+}
+
+
+/* =Content Sidebar
+----------------------------------------------- */
+
+#content-sidebar .widget .children,
+#content-sidebar .widget .sub-menu {
+ margin:0 20px 0 0;
+ margin:0 2.0rem 0 0;
+}
+
+#content-sidebar .widget .widgets-multi-column-grid li {
+ padding: 0 0 6px 8px;
+ padding: 0 0 0.6rem 0.8rem;
+}
+
+
+/* =Media Queries
+----------------------------------------------- */
+
+/* Mobile list style */
+@media screen and (max-width: 400px) {
+ .list-view .attachment-featured-thumbnail img {
+ float: right;
+ margin: 0 0 3px 10px;
+ margin: 0 0 0.3rem 1.0rem;
+ }
+}
+
+@media screen and (min-width: 400px) {
+ #primary .featured-post:before,
+ #primary .post-format a:before,
+ #primary .post-format + span.entry-date a:before,
+ #primary span.entry-date a:before,
+ #primary .byline a:before,
+ #primary .comments-link a:before,
+ #primary .edit-link a:before,
+ .attachment span.entry-date:before,
+ #primary .full-size-link a:before,
+ #primary .parent-post-link a:before {
+ margin: 0 0 0 2px;
+ margin: 0 0 0 0.2rem;
+ }
+
+ #primary .entry-meta > span {
+ margin-left: 10px;
+ margin-left: 1.0rem;
+ margin-right: auto;
+ }
+
+ #primary .format-video .post-format a:before {
+ margin: -1px 0 0 2px;
+ margin: -0.1rem 0 0 0.2rem;
+ }
+
+ #primary .format-image .post-format a:before {
+ margin: -1px 0 0 2px;
+ margin: -0.1rem 0 0 0.2rem;
+ }
+
+ #primary .format-gallery .post-format a:before {
+ margin: -1px 0 0 4px;
+ margin: -0.1rem 0 0 0.4rem;
+ }
+
+ #primary .featured-post:before {
+ margin: -1px 0 0 3px;
+ margin: -0.1rem 0 0 0.3rem;
+ }
+
+ #primary .post-format + span.entry-date a:before,
+ #primary span.entry-date a:before,
+ .attachment span.entry-date:before {
+ margin: 0 0 0 1px;
+ margin: 0 0 0 0.1rem;
+ }
+
+ #primary .comments-link a:before {
+ margin: -1px 0 0 2px;
+ margin: -0.1rem 0 0 0.2rem;
+ }
+
+ #primary .edit-link a:before {
+ margin: -1px 0 0 2px;
+ margin: -0.1rem 0 0 0.2rem;
+ }
+
+ .page #primary .edit-link a:before {
+ margin: 5px 0 0 2px;
+ margin: 0.5rem 0 0 0.2rem;
+ }
+}
+
+@media screen and (min-width: 672px) {
+ #primary {
+ float: right;
+ }
+
+ .site-content {
+ margin: 0 0 0 33.33333333%;
+ }
+
+ #content-sidebar {
+ float: left;
+ margin: 0 -30.35714285% 0 0;
+ padding: 36px 0 24px 10px;
+ padding: 3.6rem 0 2.4rem 1.0rem;
+ }
+
+ .post-formatted-posts {
+ float: left;
+ margin: 0 -30.35714285% 0 0;
+ padding: 36px 0 0 10px;
+ padding: 3.6rem 0 0 1.0rem;
+ }
+
+ #featured-content .hentry {
+ float: right;
+ }
+}
+
+@media screen and (min-width: 740px) {
+ .comment-author {
+ padding-right: 60px;
+ padding-right: 6.0rem;
+ padding-left: 0;
+ }
+
+ .comment-meta,
+ .comment-content {
+ padding-right: 60px;
+ padding-right: 6.0rem;
+ padding-left: 0;
+ }
+
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-left: 9.12778904%;
+ padding-right: 9.12778904%;
+ }
+
+ .comment-navigation {
+ padding-right: 9.12778904%;
+ padding-left: 0;
+ }
+
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-left: 6.04307432%;
+ padding-right: 6.04307432%;
+ }
+}
+
+@media screen and (min-width: 770px) {
+ .header-main {
+ margin-left: 0;
+ margin-right: auto;
+ }
+}
+
+@media screen and (min-width: 870px) {
+ #primary .entry-header {
+ margin-left: 8.03571428%;
+ margin-right: 12.5%;
+ }
+
+ #primary .entry-content,
+ #primary .entry-summary {
+ margin-left: 8.03571428%;
+ margin-right: 12.5%;
+ }
+
+ #primary footer.entry-meta {
+ margin: 12px 12.5% 24px 8.03571428%;
+ margin: 1.2rem 12.5% 2.4rem 8.03571428%;
+ }
+
+ .page #primary .entry-header,
+ .error404 #primary .entry-header {
+ margin: 0 12.5% 0 8.03571428%;
+ }
+
+ .page-header {
+ margin: 0 12.5% 24px 8.03571428%;
+ margin: 0 12.5% 2.4rem 8.03571428%;
+ }
+
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-left: 12.39493534%;
+ padding-right: 17.06896551%;
+ }
+
+ #comments #respond {
+ padding-left: 13.8900862%;
+ }
+
+ .commentlist,
+ .full-width .commentlist {
+ margin-right: -70px;
+ margin-right: -7.0rem;
+ margin-left: auto;
+ }
+
+ .comment-navigation {
+ padding-right: 17.06896551%;
+ padding-left: 0;
+ }
+
+ #content-sidebar {
+ padding-top: 72px;
+ padding-top: 7.2rem;
+ }
+
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-left: 11.30926724%;
+ padding-right: 11.30926724%;
+ }
+
+ blockquote.pull.alignright {
+ margin-right: -20%;
+ margin-left: auto;
+ }
+
+ blockquote.pull.alignleft {
+ margin-left: -20%;
+ margin-right: auto;
+ }
+
+ #primary .no-results .entry-header {
+ margin-right: 12.5%;
+ margin-left: 8.03571428%;
+ }
+
+ #primary .no-results .entry-content {
+ margin-right: 12.5%;
+ margin-left: 8.03571428%;
+ }
+}
+
+@media screen and (min-width: 1008px) {
+ #page:before {
+ right: 0;
+ left: auto;
+ }
+
+ .header-main {
+ padding-right: 27px;
+ padding-right: 2.7rem;
+ padding-left: 0;
+ }
+
+ .social-links-wrapper,
+ .search-box-wrapper {
+ padding-right: 222px;
+ padding-right: 22.2rem;
+ padding-left: 0;
+ }
+
+ .site-content {
+ margin: 0 222px 0 27.31707317%;
+ margin: 0 22.2rem 0 27.31707317%;
+ }
+
+ #secondary {
+ float: right;
+ margin: 0 -100% 0 0;
+ }
+
+ .front-page-content-wrapper {
+ float: right;
+ }
+
+ .site-content {
+ margin: 0 222px 0 27.31707317%;
+ margin: 0 22.2rem 0 27.31707317%;
+ }
+
+ #content-sidebar,
+ .post-formatted-posts {
+ margin: 0 -27.31707317% 0 0;
+ }
+
+ #featured-content {
+ padding-right: 222px;
+ padding-right: 22.2rem;
+ padding-left: 0;
+ }
+
+ #colophon {
+ padding-right: 27px;
+ padding-right: 2.7rem;
+ padding-left: 0;
+ }
+
+ .secondary-navigation ul ul {
+ right: 168px;
+ right: 16.8rem;
+ left: auto;
+ }
+
+ .full-width.site-content {
+ margin-right: 222px;
+ margin-right: 22.2rem;
+ margin-left: auto;
+ }
+
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-left: 9.87001616%;
+ padding-right: 9.19765166%;
+ }
+
+ .commentlist,
+ .full-width .commentlist {
+ margin-right: 0;
+ margin-left: auto;
+ }
+
+ .comment-navigation {
+ padding-right: 9.19765166%;
+ padding-left: 0;
+ }
+
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-left: 5.882236%;
+ padding-right: 5.882236%;
+ }
+
+ blockquote.pull.alignright {
+ margin-right: 0;
+ margin-left: auto;
+ }
+
+ blockquote.pull.alignleft {
+ margin-left: 0;
+ margin-right: auto;
+ }
+
+ #supplementary {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ #supplementary .widget-area {
+ float: right;
+ }
+}
+
+@media screen and (min-width: 1150px) {
+ #primary .entry-header {
+ margin: -48px 12.5% 0 8.03571428%;
+ margin: -4.8rem 12.5% 0 8.03571428%;
+ }
+
+ #primary .entry-content,
+ #primary .entry-summary {
+ margin: 0 12.5% 0 8.03571428%;
+ }
+
+ #primary footer.entry-meta {
+ margin: 12px 12.5% 24px 8.03571428%;
+ margin: 1.2rem 12.5% 2.4rem 8.03571428%;
+ }
+
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-left: 12.44146986%;
+ padding-right: 16.77524429%;
+ }
+
+ #comments #respond {
+ padding-left: 13.73697916%;
+ }
+
+ .commentlist,
+ .full-width .commentlist {
+ margin-right: -70px;
+ margin-right: -7.0rem;
+ margin-left: auto;
+ }
+
+ .comment-navigation {
+ padding-right: 16.77524429%;
+ padding-left: 0;
+ }
+
+ .page-header {
+ margin: 0 12.5% 24px 8.03571428%;
+ margin: 0 12.5% 2.4rem 8.03571428%;
+ }
+
+ .page #primary .entry-header,
+ .error404 #primary .entry-header {
+ margin: 0 12.5% 0 8.03571428%;
+ }
+
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-left: 11.21868265%;
+ padding-right: 11.21868265%;
+ }
+
+ #primary .entry-content .wp-caption.alignright .wp-caption-text {
+ padding-right: 10px;
+ padding-right: 1.0rem;
+ padding-left: 0;
+ }
+
+ blockquote.pull.alignright {
+ margin-right: -20%;
+ margin-left: auto;
+ }
+
+ blockquote.pull.alignleft {
+ margin-left: -20%;
+ margin-right: auto;
+ }
+}
+
+@media screen and (min-width: 1230px) {
+ #content-sidebar,
+ .post-formatted-posts {
+ padding-left: 0;
+ }
+
+ #primary .full-width .entry-header,
+ #primary .full-width .entry-content,
+ #primary .full-width footer.entry-meta {
+ margin: 0 11.21868265% 0 0;
+ }
+
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-left: 0;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/screenshot.png b/src/wp-content/themes/twentyfourteen/screenshot.png
new file mode 100644
index 0000000000..184ecbba94
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/screenshot.png
Binary files differ
diff --git a/src/wp-content/themes/twentyfourteen/search.php b/src/wp-content/themes/twentyfourteen/search.php
new file mode 100644
index 0000000000..e65cfcaa4e
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/search.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * The template for displaying Search Results pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+<section id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentyfourteen' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
+ </header><!-- .page-header -->
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php twentyfourteen_get_template_part(); ?>
+
+ <?php endwhile; ?>
+
+ <?php twentyfourteen_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <?php get_template_part( 'no-results', 'search' ); ?>
+
+ <?php endif; ?>
+
+ </div><!-- #content .site-content -->
+</section><!-- #primary .content-area -->
+
+<?php get_sidebar( 'content' ); ?>
+
+<?php get_sidebar(); ?>
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/searchform.php b/src/wp-content/themes/twentyfourteen/searchform.php
new file mode 100644
index 0000000000..360d97f269
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/searchform.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * The template for displaying search forms in Twenty Fourteen
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+ <form method="get" id="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>" role="search">
+ <label for="s" class="assistive-text"><?php _e( 'Search', 'twentyfourteen' ); ?></label>
+ <input type="text" class="field" name="s" value="<?php echo esc_attr( get_search_query() ); ?>" id="s" placeholder="<?php esc_attr_e( 'Search &hellip;', 'twentyfourteen' ); ?>" />
+ <input type="submit" class="submit" name="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'twentyfourteen' ); ?>" />
+ </form>
diff --git a/src/wp-content/themes/twentyfourteen/sidebar-content.php b/src/wp-content/themes/twentyfourteen/sidebar-content.php
new file mode 100644
index 0000000000..963048a21d
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/sidebar-content.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * The Content Sidebar.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+<div id="content-sidebar" class="widget-area" role="complementary">
+ <?php do_action( 'before_sidebar' ); ?>
+
+ <?php if ( ! dynamic_sidebar( 'sidebar-2' ) ) : ?>
+ <aside id="search" class="widget widget_search">
+ <?php get_search_form(); ?>
+ </aside>
+
+ <aside id="link" class="widget widget_links">
+ <h1 class="widget-title"><?php _e( 'Blogroll', 'twentyfourteen' ); ?></h1>
+ <ul class="xoxo blogroll">
+ <?php wp_list_bookmarks( array( 'title_li' => '', 'categorize' => 0 ) ); ?>
+ </ul>
+ </aside>
+
+ <aside id="meta" class="widget">
+ <h1 class="widget-title"><?php _e( 'Meta', 'twentyfourteen' ); ?></h1>
+ <ul>
+ <?php wp_register(); ?>
+ <li><?php wp_loginout(); ?></li>
+ <?php wp_meta(); ?>
+ </ul>
+ </aside>
+ <?php endif; // end sidebar widget area ?>
+</div><!-- #content-sidebar .widget-area -->
diff --git a/src/wp-content/themes/twentyfourteen/sidebar-footer.php b/src/wp-content/themes/twentyfourteen/sidebar-footer.php
new file mode 100644
index 0000000000..e01e8b97f5
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/sidebar-footer.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * The Sidebar containing the main widget areas.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+<?php
+ if ( ! is_active_sidebar( 'sidebar-3' )
+ && ! is_active_sidebar( 'sidebar-4' )
+ && ! is_active_sidebar( 'sidebar-5' )
+ && ! is_active_sidebar( 'sidebar-6' )
+ && ! is_active_sidebar( 'sidebar-7' )
+ )
+ return;
+?>
+<div id="supplementary" <?php twentyfourteen_footer_sidebar_class(); ?>>
+ <?php if ( is_active_sidebar( 'sidebar-3' ) ) : ?>
+ <div id="footer-sidebar-one" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-3' ); ?>
+ </div><!-- #first .widget-area -->
+ <?php endif; ?>
+
+ <?php if ( is_active_sidebar( 'sidebar-4' ) ) : ?>
+ <div id="footer-sidebar-two" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-4' ); ?>
+ </div><!-- #second .widget-area -->
+ <?php endif; ?>
+
+ <?php if ( is_active_sidebar( 'sidebar-5' ) ) : ?>
+ <div id="footer-sidebar-three" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-5' ); ?>
+ </div><!-- #third .widget-area -->
+ <?php endif; ?>
+
+ <?php if ( is_active_sidebar( 'sidebar-6' ) ) : ?>
+ <div id="footer-sidebar-four" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-6' ); ?>
+ </div><!-- #fourth .widget-area -->
+ <?php endif; ?>
+ <?php if ( is_active_sidebar( 'sidebar-7' ) ) : ?>
+ <div id="footer-sidebar-five" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-7' ); ?>
+ </div><!-- #fourth .widget-area -->
+ <?php endif; ?>
+</div><!-- #supplementary -->
diff --git a/src/wp-content/themes/twentyfourteen/sidebar.php b/src/wp-content/themes/twentyfourteen/sidebar.php
new file mode 100644
index 0000000000..ada06bd22c
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/sidebar.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * The Sidebar containing the main widget areas.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+?>
+<div id="secondary">
+ <div id="secondary-top">
+ <?php
+ $description = get_bloginfo( 'description' );
+ if ( ! empty ( $description ) ) : ?>
+ <h2 class="site-description"><?php echo esc_html( $description ); ?></h2>
+ <?php endif; ?>
+
+ <?php if ( has_nav_menu( 'secondary' ) ) : ?>
+ <nav role="navigation" class="site-navigation secondary-navigation">
+ <?php wp_nav_menu( array( 'theme_location' => 'secondary' ) ); ?>
+ </nav>
+ <?php endif; ?>
+ </div>
+
+ <div id="secondary-bottom" class="widget-area" role="complementary">
+ <?php do_action( 'before_sidebar' ); ?>
+
+ <?php if ( ! dynamic_sidebar( 'sidebar-1' ) ) : ?>
+ <aside id="categories" class="widget widget_categories">
+ <h1 class="widget-title"><?php _e( 'Categories', 'twentyfourteen' ); ?></h1>
+ <ul>
+ <?php wp_list_categories( array( 'title_li' => '' ) ); ?>
+ </ul>
+ </aside>
+
+ <aside id="archives" class="widget widget_archive">
+ <h1 class="widget-title"><?php _e( 'Archives', 'twentyfourteen' ); ?></h1>
+ <ul>
+ <?php wp_get_archives( array( 'type' => 'monthly' ) ); ?>
+ </ul>
+ </aside>
+ <?php endif; // end sidebar widget area ?>
+ </div><!-- .widget-area -->
+</div><!-- #secondary -->
diff --git a/src/wp-content/themes/twentyfourteen/single.php b/src/wp-content/themes/twentyfourteen/single.php
new file mode 100644
index 0000000000..4abbb3fd9f
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/single.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * The Template for displaying all single posts.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Fourteen
+ */
+
+get_header(); ?>
+
+<div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', 'single' ); ?>
+
+ <?php twentyfourteen_content_nav( 'nav-below' ); ?>
+
+ <?php
+ // If comments are open or we have at least one comment, load up the comment template
+ if ( comments_open() || '0' != get_comments_number() )
+ comments_template( '', true );
+ ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content .site-content -->
+</div><!-- #primary .content-area -->
+
+<?php get_sidebar( 'content' ); ?>
+
+<?php get_sidebar(); ?>
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyfourteen/style.css b/src/wp-content/themes/twentyfourteen/style.css
new file mode 100644
index 0000000000..45425d76b2
--- /dev/null
+++ b/src/wp-content/themes/twentyfourteen/style.css
@@ -0,0 +1,3381 @@
+/*
+Theme Name: Twenty Fourteen
+Theme URI: http://wordpress.org/themes/
+Author: the WordPress team
+Author URI: http://wordpress.org/
+Description: The default theme for 2014 is a magazine theme with a sleek, modern, and beautifully crafted responsive design. As a magazine theme it highlights featured content prominently on the home page.
+Version: 0.1
+License: GNU General Public License v2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+Tags: black, green, white, light, dark, two-columns, three-columns, fixed-width, responsive-width, custom-background, custom-header, custom-menu, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready
+
+This theme, like WordPress, is licensed under the GPL.
+Use it to make something cool, have fun, and share what you've learned with others.
+*/
+
+
+/* =Reset
+----------------------------------------------- */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ border: 0;
+ font-family: inherit;
+ font-size: 100%;
+ font-style: inherit;
+ font-weight: inherit;
+ margin: 0;
+ outline: 0;
+ padding: 0;
+ vertical-align: baseline;
+}
+html {
+ font-size: 62.5%; /* Corrects text resizing oddly in IE6/7 when body font-size is set using em units http://clagnut.com/blog/348/#c790 */
+ overflow-y: scroll; /* Keeps page centred in all browsers regardless of content height */
+ -webkit-text-size-adjust: 100%; /* Prevents iOS text size adjust after orientation change, without disabling user zoom */
+ -ms-text-size-adjust: 100%; /* www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/ */
+}
+body {
+ background: #fff;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+ol, ul {
+ list-style: none;
+}
+table { /* tables still need 'cellspacing="0"' in the markup */
+ border-collapse: separate;
+ border-spacing: 0;
+}
+caption, th, td {
+ font-weight: normal;
+ text-align: left;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: "";
+}
+blockquote, q {
+ quotes: "" "";
+}
+a:focus {
+ outline: thin dotted;
+}
+a:hover,
+a:active { /* Improves readability when focused and also mouse hovered in all browsers people.opera.com/patrickl/experiments/keyboard/test */
+ outline: 0;
+}
+a img {
+ border: 0;
+}
+
+/* =Repeatable patterns
+----------------------------------------------- */
+
+/* Genericons */
+/*
+IE8 and below use EOT and allow cross-site embedding.
+IE9 uses WOFF which is base64 encoded to allow cross-site embedding.
+So unfortunately, IE9 will throw a console error, but it'll still work.
+*/
+@font-face {
+ font-family: 'Genericons';
+ src: url('fonts/genericons-regular-webfont.eot');
+ src: url('fonts/genericons-regular-webfont.eot?#iefix') format('embedded-opentype'),
+ url('fonts/genericons-regular-webfont.woff') format('woff'),
+ url('fonts/genericons-regular-webfont.ttf') format('truetype'),
+ url('fonts/genericons-regular-webfont.svg#genericonsregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+.genericon:before {
+ display: inline-block;
+ -webkit-font-smoothing: antialiased;
+ font: normal 16px/1 'Genericons';
+ font-size: 1.6rem;
+ vertical-align: top;
+}
+
+
+/* =Global
+----------------------------------------------- */
+
+body,
+button,
+input,
+select,
+textarea {
+ color: #2b2b2b;
+ font-family: lato, sans-serif;
+ font-size: 16px;
+ font-size: 1.6rem;
+ font-weight: 400;
+ line-height: 1.5;
+}
+
+/* Selection */
+::-moz-selection {
+ background: #41a62a;
+ color: #fff;
+ text-shadow: none;
+}
+::selection {
+ background: #41a62a;
+ color: #fff;
+ text-shadow: none;
+}
+
+/* Headings */
+h1,h2,h3,h4,h5,h6 {
+ clear: both;
+ font-weight: 700;
+ margin-bottom: 12px;
+ margin-bottom: 1.2rem;
+}
+h1 {
+ font-size: 33px;
+ font-size: 3.3rem;
+ line-height: 1.0909090909;
+}
+h2 {
+ font-size: 30px;
+ font-size: 3.0rem;
+ line-height: 1.2;
+}
+h3 {
+ font-size: 26px;
+ font-size: 2.6rem;
+ line-height: 1.3846153846;
+}
+h4 {
+ font-size: 22px;
+ font-size: 2.2rem;
+ line-height: 1.0909090909;
+}
+h5 {
+ font-size: 18px;
+ font-size: 1.8rem;
+ line-height: 1.3333333333;
+}
+h6 {
+ font-size: 16px;
+ font-size: 1.6rem;
+ line-height: 1.5;
+}
+h1 a,
+h2 a,
+h3 a,
+h4 a,
+h5 a,
+h6 a {
+ color: #2b2b2b;
+ text-decoration: none;
+}
+h1 a:hover,
+h2 a:hover,
+h3 a:hover,
+h4 a:hover,
+h5 a:hover,
+h6 a:hover {
+ color: #41a62a;
+ text-decoration: none;
+}
+hr {
+ background-color: rgba(0, 0, 0, 0.1);
+ border: 0;
+ height: 1px;
+ height: 0.1rem;
+ margin-bottom: 23px;
+ margin-bottom: 2.3rem;
+}
+
+/* Text elements */
+p {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+ul, ol {
+ margin: 0 0 24px 22px;
+ margin: 0 0 2.4rem 2.2rem;
+}
+ul {
+ list-style: disc;
+}
+ol {
+ list-style: decimal;
+}
+ul ul, ol ol, ul ol, ol ul {
+ margin-bottom: 0;
+ margin-left: 20px;
+ margin-left: 2.0rem;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin: 0 0 24px;
+ margin: 0 0 2.4rem;
+}
+b, strong {
+ font-weight: bold;
+}
+dfn, cite, em, i {
+ font-style: italic;
+}
+blockquote {
+ font-style: italic;
+ font-weight: 300;
+ margin: 0 0 24px;
+ margin: 0 0 2.4rem;
+}
+blockquote em, blockquote i, blockquote cite {
+ font-style: normal;
+}
+blockquote p {
+ color: #8c8c8c;
+ font-size: 19px;
+ font-size: 1.9rem;
+ line-height: 1.2631578947;
+}
+blockquote cite {
+ color: #2b2b2b;
+ font-size: 16px;
+ font-size: 1.6rem;
+ font-weight: 400;
+ line-height: 1.5;
+}
+blockquote.pull p {
+ margin-bottom: 17px;
+ margin-bottom: 1.7rem;
+}
+blockquote.pull.alignleft,
+blockquote.pull.alignright {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+ padding-top: 17px;
+ padding-top: 1.7rem;
+ width: 50%;
+}
+blockquote.pull.alignleft {
+ margin: 7px 24px 7px 0;
+ margin: 0.7rem 2.4rem 0.7rem 0;
+}
+blockquote.pull.alignright {
+ margin: 7px 0 7px 24px;
+ margin: 0.7rem 0 0.7rem 2.4rem;
+}
+address {
+ margin: 0 0 24px;
+ margin: 0 0 2.4rem;
+}
+pre {
+ background: #eee;
+ font-family: 'Courier 10 Pitch', Courier, monospace;
+ font-size: 15px;
+ font-size: 1.5rem;
+ line-height: 1.6;
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+ padding: 12px;
+ padding: 1.2rem;
+ overflow: auto;
+ max-width: 100%;
+}
+code, kbd, tt, var {
+ font: 15px/1.6 Monaco, Consolas, 'Andale Mono', 'DejaVu Sans Mono', monospace;
+ font-size: 1.5rem;
+}
+abbr, acronym {
+ border-bottom: 1px dotted rgba(0, 0, 0, 0.1);
+ cursor: help;
+}
+mark, ins {
+ background: #fff9c0;
+ text-decoration: none;
+}
+sup,
+sub {
+ font-size: 75%;
+ height: 0;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ bottom: 1ex;
+}
+sub {
+ top: .5ex;
+}
+small {
+ font-size: 75%;
+}
+big {
+ font-size: 125%;
+}
+figure {
+ margin: 0;
+}
+table {
+ margin: 0 0 24px;
+ margin: 0 0 2.4rem;
+ width: 100%;
+}
+th {
+ font-weight: bold;
+}
+button,
+input,
+select,
+textarea {
+ font-size: 100%; /* Corrects font size not being inherited in all browsers */
+ margin: 0; /* Addresses margins set differently in IE6/7, F3/4, S5, Chrome */
+}
+button,
+input {
+ line-height: normal; /* Addresses FF3/4 setting line-height using !important in the UA stylesheet */
+ *overflow: visible; /* Corrects inner spacing displayed oddly in IE6/7 */
+}
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ background-color: #000;
+ border: none;
+ border-radius: 2px;
+ color: #fff;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 700;
+ line-height: 1;
+ padding: 13px 33px 11px;
+ padding: 1.3rem 3.3rem 1.1rem;
+ text-transform: uppercase;
+ vertical-align: top;
+}
+button:hover,
+html input[type="button"]:hover,
+input[type="reset"]:hover,
+input[type="submit"]:hover,
+button:focus,
+html input[type="button"]:focus,
+input[type="reset"]:focus,
+input[type="submit"]:focus {
+ background-color: #41a62a;
+ cursor: pointer;
+}
+button:active,
+html input[type="button"]:active,
+input[type="reset"]:active,
+input[type="submit"]:active {
+ background-color: #5FF23D;
+ box-shadow: inset 0 0 8px 2px rgba(0, 0, 0, 0.2), 0 1px 0 0 rgba(0, 0, 0, 0.2);
+}
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* Addresses box sizing set to content-box in IE8/9 */
+ padding: 0; /* Addresses excess padding in IE8/9 */
+}
+input[type="search"] {
+ -webkit-appearance: textfield; /* Addresses appearance set to searchfield in S5, Chrome */
+ -moz-box-sizing: content-box;
+ -webkit-box-sizing: content-box; /* Addresses box sizing set to border-box in S5, Chrome (include -moz to future-proof) */
+ box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-decoration { /* Corrects inner padding displayed oddly in S5, Chrome on OSX */
+ -webkit-appearance: none;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner { /* Corrects inner padding and border displayed oddly in FF3/4 www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/ */
+ border: 0;
+ padding: 0;
+}
+input[type="text"],
+input[type="email"],
+input[type="password"],
+textarea {
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 2px;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ color: #2b2b2b;
+}
+input[type="text"]:focus,
+input[type="email"]:focus,
+textarea:focus {
+ color: #2b2b2b;
+}
+input[type="text"],
+input[type="email"],
+input[type="password"] {
+ padding: 8px 10px;
+ padding: 0.8rem 1.0rem;
+}
+textarea {
+ overflow: auto; /* Removes default vertical scrollbar in IE6/7/8/9 */
+ padding: 8px 10px;
+ padding: 0.8rem 1.0rem;
+ vertical-align: top; /* Improves readability and alignment in all browsers */
+ width: 100%;
+}
+#searchform input[type="text"] {
+ width: 100%;
+}
+
+/* Links */
+a {
+ color: #41a62a;
+ text-decoration: none;
+}
+a:hover,
+a:focus,
+a:active {
+ color: #5FF23D;
+}
+/* Animated elements */
+#page a,
+.more-link .meta-nav,
+.more-formatted-posts-link .meta-nav,
+.attachment-featured-featured img,
+.attachment-featured-thumbnail img,
+.social-links-toggle,
+.search-toggle,
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"],
+#infinite-handle span {
+ -webkit-transition: all 0.2s ease-out;
+ -moz-transition: all 0.2s ease-out;
+ -ms-transition: all 0.2s ease-out;
+ -o-transition: all 0.2s ease-out;
+ transition: all 0.2s ease-out;
+}
+
+/* Alignment */
+.alignleft {
+ display: inline;
+ float: left;
+ margin-right: 24px;
+ margin-right: 2.4rem;
+}
+.alignright {
+ display: inline;
+ float: right;
+ margin-left: 24px;
+ margin-left: 2.4rem;
+}
+.aligncenter {
+ clear: both;
+ display: block;
+ margin: 0 auto;
+}
+
+/* Text meant only for screen readers */
+.assistive-text {
+ clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ position: absolute !important;
+}
+
+/* Hidden */
+.hide {
+ display: none;
+}
+
+/* Clearing floats */
+.clearfix:after {
+ clear: both;
+}
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: "";
+}
+
+
+/* =Basic Structure
+----------------------------------------------- */
+
+body {
+ background-color: #f5f5f5;
+ text-rendering: optimizeLegibility;
+}
+#page {
+ background-color: #fff;
+ max-width: 1230px;
+ max-width: 123.0rem;
+ position: relative;
+}
+#main {
+ max-width: 1230px;
+ max-width: 123.0rem;
+}
+#primary {
+ padding-top:24px;
+ padding-top:2.4rem;
+}
+#secondary {
+ background-color: #000;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ clear: both;
+ color: rgba(255, 255, 255, 0.55);
+ padding: 48px 10px 0;
+ padding: 4.8rem 1.0rem 0;
+ position: relative;
+ z-index: 2;
+}
+#content-sidebar {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ padding: 36px 10px 0;
+ padding: 3.6rem 1.0rem 0;
+ position: relative;
+}
+#supplementary {
+ background-color: #000;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ color: #949a92;
+ padding: 48px 10px 0;
+ padding: 4.8rem 1.0rem 0;
+ position: relative;
+ z-index: 3;
+}
+#colophon {
+ background-color: #000;
+ color: rgba(255, 255, 255, 0.4);
+ font-size: 12px;
+ font-size: 1.2rem;
+ padding: 15px 10px;
+ padding: 1.5rem 1.0rem;
+ position: relative;
+ z-index: 3;
+}
+
+
+/* =Header
+----------------------------------------------- */
+
+#masthead {
+ background-color: #000;
+ max-width: 1230px;
+ max-width: 123.0rem;
+ position: relative;
+ width: 100%;
+ z-index: 3;
+}
+
+/* Fixed Header */
+#masthead.masthead-fixed {
+ box-shadow: 0 1px 8px rgba(0, 0, 0, 0.2);
+ position: fixed;
+ top: 0;
+}
+.admin-bar #masthead.masthead-fixed {
+ top: 32px;
+}
+
+#site-header {
+ position: relative;
+ z-index: 3;
+}
+.header-main {
+ margin-right: 48px;
+ margin-right: 4.8rem;
+ min-height: 48px;
+ min-height: 4.8rem;
+ padding-left: 10px;
+ padding-left: 1.0rem;
+}
+.header-extra {
+ background-color: #41a62a;
+ float: right;
+}
+.site-title {
+ display: inline-block;
+ float: left;
+ font-size: 18px;
+ font-size: 1.8rem;
+ font-weight: 700;
+ line-height: 48px;
+ margin: 0;
+}
+.site-title a {
+ color: #fff;
+}
+#nav-toggle {
+ background-color: #000;
+ padding: 16px;
+ padding: 1.6rem;
+ position: absolute;
+ top:0;
+ right: 0;
+ line-height: 1;
+}
+#nav-toggle:before {
+ content: '\F419';
+ color: #fff;
+}
+#nav-toggle:hover {
+ cursor: pointer;
+}
+.social-links-toggle,
+.search-toggle {
+ background-color: #41a62a;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ color: #fff;
+ display: block;
+ float: left;
+ font-size: 10px;
+ font-size: 1.0rem;
+ min-width: 70px;
+ min-width: 7.0rem;
+ min-height: 48px;
+ min-height: 4.8rem;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+ position: relative;
+ text-align: center;
+ text-transform: uppercase;
+}
+.social-links-toggle:hover,
+.search-toggle:hover,
+.social-links-toggle.active,
+.search-toggle.active {
+ background-color: #35921f;
+}
+.search-toggle {
+ display: none;
+}
+.social-links-toggle:hover,
+.search-toggle:hover {
+ cursor: pointer;
+}
+.social-links-toggle span,
+.search-toggle span {
+ display: inline-block;
+ padding: 25px 0 0 0;
+ padding: 2.5rem 0 0 0;
+}
+.social-links-toggle span:before,
+.search-toggle span:before {
+ color: #fff;
+ margin-left: -8px;
+ margin-left: -0.8rem;
+ position: absolute;
+ top: 9px;
+ top: 0.9rem;
+ left: 50%;
+}
+.social-links-toggle span:before {
+ content: '\F107';
+}
+.search-toggle span:before {
+ content: '\F400';
+}
+.social-links-wrapper,
+.search-box-wrapper {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ position: absolute;
+ width: 100%;
+ z-index: 2;
+}
+.social-links {
+ background-color: #35921f;
+ list-style: none;
+ margin: 0;
+ padding-top: 8px;
+ padding-top: 0.8rem;
+}
+.social-links li {
+ display: block;
+ float: right;
+ margin: 0 10px 8px 0;
+ margin: 0 1.0rem 0.8rem 0;
+ width: 32px;
+ width: 3.2rem;
+ height: 32px;
+ height: 3.2rem;
+}
+.social-links a {
+ background-color: rgba(255,255,255,0.2);
+ border-radius: 2px;
+ color: #fff;
+ display: inline-block;
+ overflow: hidden;
+ position: relative;
+ text-align: center;
+ text-decoration: none;
+ width: 32px;
+ width: 3.2rem;
+ height: 32px;
+ height: 3.2rem;
+}
+.social-links li a:hover {
+ background-color: rgba(0,0,0,0.2);
+}
+.social-links a:before {
+ line-height: 2;
+}
+.email-link a:before {
+ content: '\f410';
+}
+.facebook-link a:before {
+ content: '\f203';
+}
+.twitter-link a:before {
+ content: '\f202';
+}
+.google-link a:before {
+ content: '\f206';
+}
+.pinterest-link a:before {
+ content: '\f210';
+}
+.linkedin-link a:before {
+ content: '\f208';
+}
+.flickr-link a:before {
+ content: '\f211';
+}
+.github-link a:before {
+ content: '\f200';
+}
+.dribbble-link a:before {
+ content: '\f201';
+}
+.vimeo-link a:before {
+ content: '\f212';
+}
+.youtube-link a:before {
+ content: '\f213';
+}
+.search-box {
+ background-color: #35921f;
+}
+.search-box #searchform input[type="text"] {
+ background-color: #fff;
+ float: right;
+ font-size: 13px;
+ font-size: 1.3rem;
+ margin: 12px 10px;
+ margin: 1.2rem 1.0rem;
+ padding: 3px 6px;
+ padding: 0.3rem 0.6rem;
+ width: 326px;
+ width: 32.6rem;
+}
+
+
+/* =Menu
+----------------------------------------------- */
+
+/* Primary Navigation */
+.primary-navigation {
+ display: none;
+ float: right;
+ font-size: 11px;
+ font-size: 1.1rem;
+ font-weight: 700;
+ line-height: 1.6363636363;
+ margin: 0 10px 0 -10px;
+ margin: 0 1.0rem 0 -1.0rem;
+ text-transform: uppercase;
+}
+.primary-navigation ul {
+ list-style: none;
+ margin: 0;
+ padding-left: 0;
+}
+.primary-navigation li {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ display: inline-block;
+ height: 48px;
+ height: 4.8rem;
+ line-height: 48px;
+ line-height: 4.8rem;
+ position: relative;
+}
+.primary-navigation a {
+ color: #fff;
+ display: inline-block;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+ text-decoration: none;
+}
+.primary-navigation ul ul {
+ background-color: rgba(0, 0, 0, 0.9);
+ display: none;
+ float: left;
+ position: absolute;
+ top: 48px;
+ top: 4.8rem;
+ left: 0;
+ z-index: 99999;
+}
+.primary-navigation li li {
+ display: block;
+ height: auto;
+ line-height: 1.6363636363;
+}
+.primary-navigation ul ul ul {
+ left: 100%;
+ top: 0;
+}
+.primary-navigation ul ul a {
+ padding: 9px 12px;
+ padding: 0.9rem 1.2rem;
+ width: 148px;
+ width: 14.8rem;
+}
+.primary-navigation ul ul li {
+}
+.primary-navigation li:hover > a {
+ background-color: #2b2b2b;
+}
+.primary-navigation li li:hover > a {
+ background-color: #000;
+}
+.primary-navigation ul ul a:hover {
+ color: #41a62a;
+}
+.primary-navigation ul li:hover > ul {
+ display: block;
+}
+.primary-navigation li.current_page_item > a,
+.primary-navigation li.current-menu-item > a {
+ color: #5FF23D;
+}
+
+/* Secondary Navigation */
+.secondary-navigation {
+ border-bottom: 1px solid rgba(255, 255, 255, 0.4);
+ font-size: 14px;
+ font-size: 1.4rem;
+ margin-bottom: 48px;
+ margin-bottom: 4.8rem;
+}
+.secondary-navigation a {
+ display: block;
+ color: #fff;
+ font-weight: 700;
+ padding: 7px 0 7px;
+ padding: 0.7rem 0 0.7rem;
+ text-transform: uppercase;
+}
+.secondary-navigation a:hover {
+ color: #5FF23D;
+}
+.secondary-navigation ul {
+ list-style: none;
+ margin: 0;
+}
+.secondary-navigation ul ul {
+ margin: 0 0 0 20px;
+ margin: 0 0 0 2.0rem;
+}
+.secondary-navigation li {
+ border-top: 1px solid rgba(255, 255, 255, 0.4);
+}
+.secondary-navigation li li {
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
+}
+#secondary .current_page_item > a,
+#secondary .current-menu-item > a {
+ color: #5FF23D;
+}
+
+/* Mobile Navigations */
+#mobile-navigations {
+ margin-top: 1px;
+ margin-top: 0.1rem;
+}
+.mobile-navigation {
+ background-color: #000;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 700;
+ padding: 24px 10px 0;
+ padding: 2.4rem 1.0rem 0;
+ text-transform: uppercase;
+}
+.mobile-navigation ul {
+ list-style: none;
+ margin: 0;
+}
+.mobile-navigation li {
+ border-top: 1px solid rgba(255, 255, 255, 0.4);
+}
+.mobile-navigation li li {
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
+}
+.mobile-navigation ul ul li {
+ margin-left: 15px;
+ margin-left: 1.5rem;
+}
+.mobile-navigation a {
+ color: rgba(255, 255, 255, 1);
+ display: block;
+ padding: 7px 0 7px;
+ padding: 0.7rem 0 0.7rem;
+ text-decoration: none;
+}
+.mobile-navigation a:hover {
+ color: rgba(255, 255, 255, 0.7);
+}
+
+
+/* =Content
+----------------------------------------------- */
+
+.sticky .entry-date {
+ display: none;
+}
+.hentry {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+ max-width: 672px;
+ max-width: 67.2rem;
+}
+.attachment-featured-thumbnail {
+ background: #8c8c8c url(images/pattern.png) repeat 0 0;
+ background-size: 5px 5px;
+ display: block;
+ float: none;
+ margin: 0;
+ min-height: 180px;
+ min-height: 18.0rem;
+ position: relative;
+ width: 100%;
+ height: auto;
+ z-index: 0;
+}
+.entry-header {
+ position: relative;
+ z-index: 1;
+}
+.entry-title {
+ clear: none;
+ font-size: 15px;
+ font-size: 1.5rem;
+ font-weight: 900;
+ line-height: 18px;
+ line-height: 1.8rem;
+ margin: 0 0 6px 0;
+ margin: 0 0 0.6rem 0;
+}
+.entry-title a {
+ color: #2b2b2b;
+}
+.entry-title a:hover {
+ color: #41a62a;
+}
+.entry-meta {
+ clear: both;
+ color: #8c8c8c;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight:400;
+ line-height: 1.3333333333;
+}
+.entry-meta a {
+ color: #8c8c8c;
+}
+.entry-meta a:hover {
+ color: #2b2b2b;
+}
+.cat-links {
+ font-weight: 900;
+ text-transform: uppercase;
+}
+.cat-links a {
+ color: #2b2b2b;
+}
+.cat-links a:hover {
+ color: #41a62a;
+}
+.byline {
+ display: none;
+}
+.single .byline,
+.group-blog .byline {
+ display: inline;
+}
+.post-formatted-posts .entry-title:after,
+#primary span + span.entry-date:before,
+span + .byline:before,
+span + .comments-link:before,
+span + .edit-link:before,
+.full-size-link:before,
+.parent-post-link:before {
+ content: '\0020\007c\0020';
+}
+.entry-content,
+.entry-summary {
+ position: relative;
+ z-index: 2;
+}
+.entry-content a {
+ text-decoration: underline;
+}
+.entry-content table,
+.comment-content table {
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-width: 1px 0 1px 1px;
+ font-size: 14px;
+ font-size: 1.4rem;
+ line-height: 1.2857142857;
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+.entry-content th,
+.comment-content th {
+ border-right: 1px solid rgba(0, 0, 0, 0.1);
+ font-weight: 700;
+ padding: 8px;
+ padding: 0.8rem;
+ text-transform: uppercase;
+}
+.entry-content td,
+.comment-content td {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ border-right: 1px solid rgba(0, 0, 0, 0.1);
+ padding: 8px;
+ padding: 0.8rem;
+}
+.entry-content .video-player,
+.entry-content .PDS_Poll {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+footer.entry-meta {
+ margin-bottom: 36px;
+ margin-bottom: 3.6rem;
+}
+
+/* #primary specific styles */
+#primary .entry-header {
+ background-color: #fff;
+ padding: 24px 10px 12px;
+ padding: 2.4rem 1.0rem 1.2rem;
+}
+#primary .entry-title {
+ font-size: 33px;
+ font-size: 3.3rem;
+ font-weight: 300;
+ line-height: 1.0909090909;
+ margin-bottom: 12px;
+ margin-bottom: 1.2rem;
+ text-transform: uppercase;
+}
+#primary .entry-meta {
+ background-color: #fff;
+ margin-bottom: 8px;
+ margin-bottom: 0.8rem;
+ text-transform: uppercase;
+}
+#primary .entry-content,
+#primary .entry-summary {
+ background-color: #fff;
+ padding: 12px 10px 0;
+ padding: 1.2rem 1.0rem 0;
+}
+#primary footer.entry-meta {
+ margin-top: 12px;
+ margin-top: 1.2rem;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+}
+#primary footer.entry-meta .entry-meta {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+#primary footer.entry-meta .entry-title {
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 400;
+ line-height: 1.3333333333;
+ margin-bottom: 8px;
+ margin-bottom: 0.8rem;
+ text-transform: none;
+}
+#primary footer.entry-meta .entry-title a {
+ color: #8c8c8c;
+}
+#primary footer.entry-meta .entry-title a:hover {
+ color: #2b2b2b;
+}
+#primary .format-aside,
+#primary .format-quote,
+#primary .format-link,
+#primary .format-image,
+#primary .format-video {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+}
+#primary .format-aside .entry-header .entry-title,
+#primary .format-quote .entry-header .entry-title,
+#primary .format-link .entry-header .entry-title {
+ display: none;
+}
+#primary .format-aside .entry-content,
+#primary .format-aside .entry-summary,
+#primary .format-quote .entry-content,
+#primary .format-quote .entry-summary,
+#primary .format-link .entry-content,
+#primary .format-link.entry-summary {
+ padding-top: 0;
+}
+
+/* Single specific styles */
+.single #primary .format-aside .entry-header,
+.single #primary .format-quote .entry-header,
+.single #primary .format-link .entry-header,
+.single #primary .format-image .entry-header,
+.single #primary .format-video .entry-header {
+ padding-top: 0;
+}
+.single #primary .format-aside,
+.single #primary .format-quote,
+.single #primary .format-link,
+.single #primary .format-image,
+.single #primary .format-video {
+ border-top: none;
+}
+
+/* Page specific styles */
+.page #primary .entry-header,
+.error404 #primary .entry-header,
+.single-attachment #primary .entry-header,
+.page #primary .entry-content,
+.error404 #primary .entry-content,
+.single-attachment #primary .entry-content {
+ padding-top: 0;
+}
+.single-attachment #primary footer.entry-meta {
+ text-transform: none;
+}
+.more-link,
+.more-formatted-posts-link {
+ font-size: 14px;
+ font-size: 1.4rem;
+ text-transform: uppercase;
+ white-space: pre;
+}
+.more-link:hover,
+.more-formatted-posts-link:hover {
+ text-decoration: none;
+}
+.more-link .meta-nav,
+.more-formatted-posts-link .meta-nav {
+ position: relative;
+ left: 0;
+}
+.more-link:hover .meta-nav,
+.more-formatted-posts-link:hover .meta-nav {
+ left: 5px;
+ left: 0.5rem;
+}
+.page-links {
+ clear: both;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 900;
+ line-height: 2;
+ margin: 0 0 24px;
+ margin: 0 0 2.4rem;
+ text-transform: uppercase;
+}
+.page-links a,
+.page-links > span {
+ background: #fff;
+ border: 1px solid #fff;
+ border-radius: 2px;
+ display: inline-block;
+ margin: 0 1px 2px 0;
+ text-align: center;
+ width: 22px;
+ height: 22px;
+}
+.page-links a {
+ background: #000;
+ border: 1px solid #000;
+ color: #fff;
+ text-decoration: none;
+}
+.page-links a:hover {
+ background: #41a62a;
+ border: 1px solid #41a62a;
+}
+.page-links > span.page-links-title {
+ margin: 0;
+ padding-right: 9px;
+ width: auto;
+ height: auto;
+}
+#page .tag-links a {
+ -webkit-transition: all 0s ease-out;
+ -moz-transition: all 0s ease-out;
+ -ms-transition: all 0s ease-out;
+ -o-transition: all 0s ease-out;
+ transition: all 0s ease-out;
+}
+.tag-links a {
+ background-color: #8c8c8c;
+ border-radius: 0 2px 2px 0;
+ color: #fff;
+ display: inline-block;
+ font-size: 11px;
+ font-size: 1.1rem;
+ font-weight: 700;
+ line-height: 1.2727272727;
+ margin: 0 4px 4px 10px;
+ margin: 0 0.4rem 0.4rem 1.0rem;
+ padding: 3px 7px;
+ padding: 0.3rem 0.7rem;
+ position: relative;
+ text-transform: uppercase;
+}
+.tag-links a:hover {
+ background-color: #2b2b2b;
+ color: #fff;
+ text-decoration: none;
+}
+.tag-links a:before {
+ border-top: 10px solid transparent;
+ border-right: 8px solid #8c8c8c;
+ border-bottom: 10px solid transparent;
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -8px;
+ left: -0.8rem;
+ width: 0;
+ height: 0;
+}
+/* For Firefox to avoid jagged edge */
+@-moz-document url-prefix() {
+ .tag-links a:before {
+ border-right: 10px solid #8c8c8c;
+ left: -10px;
+ left: -1.0rem;
+ }
+}
+.tag-links a:hover:before {
+ border-right-color: #2b2b2b;
+}
+.tag-links a:after {
+ background-color: #fff;
+ border-radius: 50%;
+ content: '';
+ position: absolute;
+ top: 8px;
+ top: 0.8rem;
+ left: -2px;
+ left: -0.2rem;
+ width: 4px;
+ width: 0.4rem;
+ height: 4px;
+ height: 0.4rem;
+}
+.page-header {
+ margin: 0 0 24px;
+ margin: 0 0 2.4rem;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+}
+.page-title {
+ font-size: 16px;
+ font-size: 1.6rem;
+ font-weight: 900;
+ line-height: 1.5;
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+.taxonomy-description p {
+ color: #8c8c8c;
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1.5;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.taxonomy-description p:last-child {
+ margin: 0;
+}
+.entry-content .edit-link {
+ clear:both;
+ display: block;
+}
+
+
+/* =Front Page
+----------------------------------------------- */
+
+.front-page-content-wrapper {
+ width: 100%;
+}
+.front-page-content-area {
+ max-width: 1230px;
+ max-width: 123.0rem;
+}
+
+
+/* =Featured Content
+----------------------------------------------- */
+
+#featured-content {
+ background: #000 url(images/pattern-dark.png) repeat 0 0;
+ background-size: 5px 5px;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+}
+#featured-content .hentry {
+ color: #fff;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ width: 100%;
+}
+.attachment-featured-featured {
+ background-color: #2b2b2b;
+ display: block;
+ min-height: 168px;
+ min-height: 16.8rem;
+}
+.attachment-featured-featured:hover img {
+ opacity: 0.8;
+}
+#featured-content .entry-wrap {
+ background-color: #000;
+ overflow: hidden;
+ padding: 12px 10px;
+ padding: 1.2rem 1.0rem;
+}
+#featured-content .entry-meta a,
+#featured-content .entry-title a {
+ color: #fff;
+}
+#featured-content .entry-meta a:hover,
+#featured-content .entry-title a:hover {
+ color: #5FF23D;
+}
+#featured-content .entry-meta {
+ font-size: 11px;
+ font-size: 1.1rem;
+ font-weight: 700;
+ line-height: 1.0909090909;
+}
+#featured-content .cat-links {
+ font-weight: 700;
+}
+#featured-content .entry-title {
+ font-size: 18px;
+ font-size: 1.8rem;
+ font-weight: 300;
+ line-height: 1.3333333333;
+ margin-bottom: 0;
+ text-transform: uppercase;
+}
+#featured-content .entry-summary {
+ background-color: transparent;
+ color: rgba(255, 255, 255, 0.75);
+ padding-bottom: 12px;
+ padding-bottom: 1.2rem;
+}
+#featured-content .entry-summary p {
+ font-size: 11px;
+ font-size: 1.1rem;
+ line-height: 1.6363636363;
+ margin-top: 9px;
+ margin-top: 0.9rem;
+ margin-bottom: 0;
+}
+#featured-content .more-link {
+ color: #5FF23D;
+ font-size: 11px;
+ font-size: 1.1rem;
+}
+
+
+/* =Post Formatted posts column
+----------------------------------------------- */
+
+.post-formatted-posts {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ clear: both;
+ padding: 23px 10px 0;
+ padding: 2.3rem 1.0rem 0;
+}
+.post-formatted-posts .format-title {
+ border-top: 5px solid #000;
+ color: #2b2b2b;
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 900;
+ line-height: 1.2857142857;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+ padding-top: 1px;
+ text-transform: uppercase;
+}
+.post-formatted-posts .entry-content a {
+ word-wrap: break-word;
+}
+.format-title:before {
+ background-color: #000;
+ color: #fff;
+ margin-top: -1px;
+ margin-right: 10px;
+ margin-right: 1.0rem;
+ padding: 6px 0 9px;
+ padding: 0.6rem 0 0.9rem;
+ text-align: center;
+ vertical-align: middle;
+ width: 36px;
+ width: 3.6rem;
+}
+.recent-videos .format-title:before {
+ content: '\F104';
+}
+.recent-images .format-title:before {
+ content: '\F102';
+}
+.recent-galleries .format-title:before {
+ content: '\F103';
+}
+.recent-asides .format-title:before {
+ content: '\F101';
+}
+.recent-quotes .format-title:before {
+ content: '\F106';
+}
+.recent-links .format-title:before {
+ content: '\F107';
+}
+.post-formatted-posts .hentry {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.post-formatted-posts .hentry:last-of-type {
+ margin-bottom: 9px;
+ margin-bottom: 0.9rem;
+}
+.post-formatted-posts .entry-title {
+ display: inline;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 400;
+ line-height: 1.5;
+ margin: 0 0 6px 0;
+ margin: 0 0 0.6rem 0;
+}
+.post-formatted-posts .entry-meta {
+ color: rgba(0, 0, 0, 0.2);
+ line-height: 1.5;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.post-formatted-posts .entry-meta a {
+ color: #8c8c8c;
+}
+.post-formatted-posts .entry-meta a:hover {
+ color: #2b2b2b;
+}
+.post-formatted-posts .entry-content p:not(.wp-caption-text) {
+ font-size: 13px;
+ font-size: 1.3rem;
+ line-height: 1.3846153846;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.post-formatted-posts .entry-content blockquote p cite {
+ font-size: 13px;
+ font-size: 1.3rem;
+ line-height: 1.3846153846;
+}
+.post-formatted-posts .wp-caption {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.post-formatted-posts .wp-caption-text {
+ line-height: 1.5;
+ margin: 6px 0 0;
+ margin: 0.6rem 0 0;
+ padding: 0;
+}
+.post-formatted-posts .format-gallery .wp-caption-text {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.post-formatted-posts .more-link {
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1.5;
+}
+.post-formatted-posts .more-formatted-posts-link {
+ display: inline-block;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 900;
+ line-height: 1.5;
+ margin-bottom: 36px;
+ margin-bottom: 3.6rem;
+}
+
+
+/* =404 Page
+----------------------------------------------- */
+
+.error404 .entry-content #searchform {
+ margin-bottom: 36px;
+ margin-bottom: 3.6rem;
+}
+.error404 .entry-content .widget-title,
+.error404 .entry-content .widgettitle {
+ border-top: 5px solid #000;
+ color: #2b2b2b;
+ padding-top: 7px;
+ padding-top: 0.7rem;
+}
+
+
+/* =Media
+----------------------------------------------- */
+
+#site-header img,
+.attachment-featured-thumbnail-large,
+.entry-content img,
+.comment-content img,
+.widget img {
+ max-width: 100%;
+ vertical-align: middle;
+}
+#site-header img,
+.entry-content img,
+.attachment-featured-thumbnail-large,
+img[class*="align"],
+img[class*="wp-image-"],
+.widget img {
+ height: auto;
+}
+#site-header img,
+.entry-content img,
+img.size-full,
+img.size-large,
+img.wp-post-image {
+ max-width: 100%;
+ height: auto;
+}
+.attachment-featured-featured img,
+.attachment-featured-thumbnail img {
+ height: auto;
+ max-width: 100%;
+ vertical-align: middle;
+}
+img.alignleft,
+.wp-caption.alignleft {
+ margin: 7px 24px 7px 0;
+ margin: 0.7rem 2.4rem 0.7rem 0;
+}
+img.alignright,
+.wp-caption.alignright {
+ margin: 7px 0 7px 24px;
+ margin: 0.7rem 0 0.7rem 2.4rem;
+}
+img.aligncenter,
+.wp-caption.aligncenter {
+ margin-top: 7px;
+ margin-top: 0.7rem;
+ margin-bottom: 7px;
+ margin-bottom: 0.7rem;
+}
+.entry-content img.wp-smiley,
+.comment-content img.wp-smiley {
+ border: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+.wp-caption {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+ max-width: 100%;
+}
+.wp-caption img[class*="wp-image-"] {
+ display: block;
+ height: auto;
+ margin: 0;
+ max-width: 100%;
+}
+.wp-caption-text {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-style: italic;
+ line-height: 1.6666666666;
+ margin: 4px 0;
+ margin: 0.4em 0;
+ padding: 0 10px 0 0; /* Avoid the caption to overflow the width of the image because wp-caption has 10px wider width */
+ padding: 0 1.0rem 0 0;
+ text-align: left;
+}
+#content .gallery a img {
+ border: none;
+ height: auto;
+ vertical-align: middle; /* Remove a little margin bottom */
+}
+.site-content .gallery .gallery-icon {
+ line-height: 1; /* Remove a little margin bottom */
+}
+#content .gallery .gallery-item {
+ margin: 0 0 12px 0;
+ margin: 0 0 1.2rem 0;
+}
+#content .gallery {
+ margin-bottom: 12px;
+ margin-bottom: 1.2rem;
+}
+.site-content .gallery dd {
+ margin: 4px 0 0 0; /* Reset the margin and add a bit of margin-top to captions */
+ margin: 0.4rem 0 0 0;
+}
+.gallery-caption {
+ padding: 0;
+}
+.gallery-item .wp-caption-text {
+ text-align: center;
+}
+.hentry .tiled-gallery {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+.site-content .gallery-columns-1 a img {
+ max-width: 100%;
+}
+.site-content .gallery-columns-2 a img {
+ max-width: 96%;
+}
+.site-content .gallery-columns-3 a img {
+ max-width: 94%;
+}
+.site-content .gallery-columns-4 a img {
+ max-width: 92%;
+}
+.site-content .gallery-columns-5 a img {
+ max-width: 90%;
+}
+.site-content .gallery-columns-6 a img,
+.site-content .gallery-columns-7 a img,
+.site-content .gallery-columns-8 a img,
+.site-content .gallery-columns-9 a img {
+ max-width: 88%;
+}
+.entry-attachment .attachment {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+
+/* Make sure embeds and iframes fit their containers */
+embed,
+iframe,
+object,
+video {
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+ max-width: 100%;
+}
+p > embed,
+p > iframe,
+p > object,
+span > embed,
+span > iframe,
+span > object {
+ margin-bottom: 0;
+}
+
+
+/* =Navigation
+----------------------------------------------- */
+
+.paging-navigation {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ margin: 36px 0;
+ margin: 3.6rem 0;
+}
+.paging-navigation .loop-pagination {
+ margin-top: -1px;
+ margin-top: -0.1rem;
+ text-align: center;
+}
+.paging-navigation .page-numbers {
+ border-top: 1px solid transparent;
+ display: inline-block;
+ font-size: 12px;
+ font-size: 1.2rem;
+ font-weight: 900;
+ margin-right: 5px;
+ margin-right: 0.5rem;
+ padding: 9px 15px;
+ padding: 0.9rem 1.5rem;
+ text-transform: uppercase;
+}
+.paging-navigation .page-numbers.current {
+ border-top: 1px solid #41a62a;
+ color: #41a62a;
+}
+.paging-navigation a {
+ color: #2b2b2b;
+}
+.paging-navigation a:hover {
+ background-color: #f5f5f5;
+ border-top: 1px solid #000;
+}
+.post-navigation,
+#image-navigation {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ margin: 24px 0 0;
+ margin: 2.4rem 0 0;
+}
+.post-navigation .nav-previous,
+.post-navigation .nav-next,
+#image-navigation .previous-image,
+#image-navigation .next-image {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ float: none;
+ padding: 11px 10px;
+ padding: 1.1rem 1.0rem;
+ text-align: left;
+ width: 100%;
+}
+.post-navigation .nav-next {
+ margin: 0;
+}
+.post-navigation .meta-nav {
+ color: #8c8c8c;
+ display: block;
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 2;
+ font-weight: 900;
+ text-transform: uppercase;
+}
+.site-content .post-navigation a,
+.site-content #image-navigation a {
+ color: #2b2b2b;
+ display: block;
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 700;
+ line-height: 1.7142857142;
+ text-transform: none;
+}
+.site-content .post-navigation a:hover,
+.site-content #image-navigation a:hover {
+ background-color: rgba(0, 0, 0, 0.01);
+ color: #41a62a;
+}
+.comment-navigation {
+ color: rgba(0, 0, 0, 0.2);
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 2;
+ margin-bottom: 48px;
+ margin-bottom: 4.8rem;
+ padding-left: 10px;
+ padding-left: 1.0rem;
+ text-transform: uppercase;
+}
+.comment-navigation .nav-previous,
+.comment-navigation .nav-next {
+ display: inline-block;
+}
+.comment-navigation .nav-previous a {
+ margin-right: 10px;
+}
+#comment-nav-above {
+ margin-top: 36px;
+ margin-top: 3.6rem;
+ margin-bottom: 0;
+}
+
+
+/* =Comments
+----------------------------------------------- */
+
+#comments {
+ margin-top: 36px;
+ margin-top: 3.6rem;
+}
+.comments-title,
+#reply-title {
+ font-size: 16px;
+ font-size: 1.6rem;
+ font-weight: 900;
+ line-height: 1.5;
+ margin-bottom: 0;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+ text-transform: uppercase;
+}
+#respond #commentform {
+ background: #fff;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+}
+.commentlist {
+ list-style: none;
+ margin: 0 0 48px 0;
+ margin: 0 0 4.8rem 0;
+}
+.comment-meta,
+.comment-author {
+ font-size: 14px;
+ font-size: 1.4rem;
+ line-height: 1.7142857142;
+}
+.comment-author cite {
+ font-weight: 900;
+ text-transform: uppercase;
+}
+.comment-author a {
+ color: #2b2b2b;
+}
+.comment-meta a,
+.commentlist li.trackback a,
+.commentlist li.pingback a {
+ color: #8c8c8c;
+}
+.comment-author a:hover,
+.comment-meta a:hover,
+.commentlist li.trackback a:hover,
+.commentlist li.pingback a:hover {
+ color: #41a62a;
+ text-decoration: none;
+}
+.comment-edit-link:before,
+.comment-reply-link:before {
+ color: rgba(0, 0, 0, 0.2);
+ content: '\007c\0020';
+}
+.comments-area article,
+.commentlist li.trackback,
+.commentlist li.pingback {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+ padding: 24px 10px 0;
+ padding: 2.4rem 1.0rem 0;
+}
+.commentlist li:first-child article {
+ border: none;
+}
+.comments-area article {
+ background: none;
+ min-height: 48px;
+ min-height: 4.8rem;
+ position: relative;
+}
+.comment-author {
+ padding-left: 36px;
+ padding-left: 3.6rem;
+ position: relative;
+}
+.comment-author .comment-author-avatar {
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ padding: 2px;
+ padding: 0.2rem;
+ position: absolute;
+ top: 3px;
+ top: 0.3rem;
+ left: 0;
+ width: 22px;
+ width: 2.2rem;
+ height: 22px;
+ height: 2.2rem;
+}
+.bypostauthor > article .comment-author .comment-author-avatar {
+ background-color: #41a62a;
+}
+.comment-author cite {
+ font-style: normal;
+}
+.comment-author .avatar {
+ position: absolute;
+ top: 2px;
+ top: 0.2rem;
+ left: 2px;
+ left: 0.2rem;
+ width: 22px;
+ width: 2.2rem;
+ height: 22px;
+ height: 2.2rem;
+}
+.comment-meta,
+.comment-content {
+ padding-left: 36px;
+ padding-left: 3.6rem;
+}
+.comment-content a {
+ word-wrap: break-word;
+}
+.comment-content ul,
+.comment-content ol {
+ margin: 0 0 24px 22px;
+ margin: 0 0 2.4rem 2.2rem;
+}
+.comment-content ul ul,
+.comment-content ol ol,
+.comment-content ul ol,
+.comment-content ol ul {
+ margin-bottom: 0;
+}
+.commentlist .children {
+ list-style: none;
+ margin-left: 20px;
+ margin-left: 2.0rem;
+}
+.comments-area .children article {
+ border: none;
+}
+#comments #respond {
+ padding: 0;
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+#comments li #respond {
+ margin-left: 47px;
+ margin-left: 4.7rem;
+}
+#comments #respond h3 {
+ margin-top: 0;
+ margin-bottom: 24px;
+ margin-bottom: 2.4rem;
+}
+.nocomments {
+ color: #8c8c8c;
+ font-size: 16px;
+ font-size: 1.6rem;
+ font-weight: 900;
+ line-height: 1.5;
+ margin-top: 24px;
+ margin-top: 2.4rem;
+ padding: 0 10px;
+ padding: 0 1.0rem;
+ text-transform: uppercase;
+}
+#commentform {
+ padding: 0 10px;
+ padding: 0 1.0rem;
+}
+#commentform label {
+ display: block;
+}
+#commentform input[type=text] {
+ width: 100%;
+}
+.form-allowed-tags {
+ display: none;
+}
+#commentform p:last-child {
+ margin-bottom: 0;
+}
+
+/* =Primary Sidebar
+----------------------------------------------- */
+
+.site-description {
+ color: rgba(255, 255, 255, 0.4);
+ display: none;
+ font-size: 11px;
+ font-size: 1.1rem;
+ font-weight: 400;
+}
+
+
+/* =Colophon
+----------------------------------------------- */
+
+#colophon a {
+ color: rgba(255, 255, 255, 0.4);
+}
+#colophon a:hover {
+ color: #fff;
+}
+
+
+/* =Widgets
+----------------------------------------------- */
+
+.widget-area p {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.widget-area a {
+ color: rgba(255, 255, 255, 0.75);
+}
+.widget-area a:hover {
+ color: #5FF23D;
+}
+.widget-area .widget-title,
+.widget-area .widget-title a {
+ color: #fff;
+}
+.widget {
+ margin: 0 0 48px;
+ margin: 0 0 4.8rem;
+ overflow: hidden;
+}
+.widget ul,
+.widget ol {
+ list-style: none;
+ margin: 0;
+}
+.widget ul ul,
+.widget ol ol,
+.widget ul ol,
+.widget ol ul {
+ margin: 0 0 0 10px;
+ margin: 0 0 0 1.0rem;
+}
+.widget-title,
+.widgettitle {
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 900;
+ line-height: 1.7142857142;
+ margin: 0 0 2.4rem 0;
+ margin: 0 0 24px 0;
+ text-transform: uppercase;
+}
+.widget-area button,
+.widget-area html input[type="button"],
+.widget-area input[type="reset"],
+.widget-area input[type="submit"] {
+ background-color: #41a62a;
+ font-size: 11px;
+ font-size: 1.1rem;
+ padding: 6px 24px;
+ padding: 0.6rem 2.4rem;
+}
+.widget-area button:hover,
+.widget-area html input[type="button"]:hover,
+.widget-area input[type="reset"]:hover,
+.widget-area input[type="submit"]:hover,
+.widget-area button:focus,
+.widget-area html input[type="button"]:focus,
+.widget-area input[type="reset"]:focus,
+.widget-area input[type="submit"]:focus {
+ background-color: #35921f;
+}
+.widget-area button:active,
+.widget-area html input[type="button"]:active,
+.widget-area input[type="reset"]:active,
+.widget-area input[type="submit"]:active {
+ background-color: #35921f;
+}
+.widget-area input[type="text"],
+.widget-area input[type="email"],
+.widget-area input[type="password"],
+.widget-area textarea {
+ background-color: #2b2b2b;
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ color: #fff;
+ max-width: 100%;
+ padding: 4px;
+ padding: 0.4rem;
+}
+.widget select,
+.widget iframe {
+ max-width: 99%;
+ margin-left: 1px;
+ margin-left: 0.1rem;
+}
+.widget div:last-child,
+.widget table:last-child,
+.widget iframe:last-child,
+.widget p:last-child,
+#secondary .widget p:last-child,
+#content-sidebar .widget p:last-child {
+ margin-bottom: 0;
+}
+
+/* Authors Widget */
+.widget_authors > ul > li {
+ list-style: none;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.widget_authors > ul > li:last-child {
+ margin-bottom: 0;
+}
+.widget_authors img {
+ border-radius: 2;
+ margin: 0 5px 9px 0;
+ margin: 0 0.5rem 0.9rem 0;
+ vertical-align: middle;
+}
+.widget_authors ul ul {
+ margin: 0;
+}
+
+/* Author Grid Widget */
+.widget_author_grid .avatar {
+ max-width: none;
+}
+
+/* Blog Subscription */
+.widget_blog_subscription input[type="text"] {
+ padding: 4px !important;
+ padding: 0.4rem !important;
+}
+
+/* Caledar widget*/
+.widget_calendar #wp-calendar a {
+ display: block;
+}
+.widget_calendar #wp-calendar tbody a {
+ background-color: #41a62a;
+ color: #fff;
+ display: block;
+}
+.widget_calendar #wp-calendar tbody a:hover {
+ background-color: #35921f;
+}
+.widget_calendar #wp-calendar {
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-width: 1px 0 1px 1px;
+ line-height: 2;
+ margin: 0;
+}
+.widget_calendar #wp-calendar caption {
+ color: #fff;
+ font-weight: 700;
+ line-height: 1.7142857142;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+ text-align: left;
+ text-transform: uppercase;
+}
+.widget_calendar #wp-calendar thead th,
+.widget_calendar #wp-calendar tbody td {
+ border: 1px solid rgba(255, 255, 255, 0.2);
+ border-width: 0 1px 1px 0;
+ text-align: center;
+}
+.widget_calendar #wp-calendar tfoot td#prev {
+ padding-left: 5px;
+ padding-left: 0.5rem;
+}
+.widget_calendar #wp-calendar tfoot td#next {
+ border-right: 1px solid rgba(255, 255, 255, 0.2);
+ padding-right: 5px;
+ padding-right: 0.5rem;
+ text-align: right;
+}
+
+/* Cloud Widgets */
+.wp_widget_tag_cloud div,
+.widget_tag_cloud div {
+ word-wrap: break-word;
+}
+
+/* Contact Info Widget */
+.widget_contact_info #contact-map {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.widget_contact_info #contact-info-map-canvas {
+ height: 168px;
+ height: 16.8rem;
+}
+
+/* Flickr Widget (WP.com) */
+.widget_flickr #flickr_badge_uber_wrapper {
+ margin-top: 4px;
+ margin-top: 0.4rem;
+}
+.widget_flickr #flickr_badge_uber_wrapper a:link,
+.widget_flickr #flickr_badge_uber_wrapper a:active,
+.widget_flickr #flickr_badge_uber_wrapper a:visited {
+ color: #fff;
+}
+.widget_flickr #flickr_badge_uber_wrapper a:hover {
+ color: #5FF23D;
+}
+.widget_flickr #flickr_badge_wrapper {
+ background-color: transparent;
+ border: none;
+}
+
+/* Gravatar Profile widget */
+.widget-area .widget-grofile h4 {
+ color: rgba(255, 255, 255, 0.75);
+ font-size: 11px;
+ font-size: 1.1rem;
+ line-height: 1.6363636363;
+ margin: 18px 0 0;
+ margin: 1.8rem 0 0;
+ text-transform: uppercase;
+}
+.widget-grofile .grofile-accounts {
+ margin-top: 4px;
+ margin-top: 0.4rem;
+}
+
+/* Milestone Widget */
+.widget-area .milestone-widget .milestone-content {
+ max-width: 100%;
+}
+.widget-area .milestone-countdown,
+.widget-area .milestone-message {
+ border-color: rgba(255, 255, 255, 0.1);
+ border-top: 0;
+}
+.widget-area .milestone-header,
+.widget-area .milestone-countdown,
+.widget-area .milestone-message {
+ background-color: rgba(255, 255, 255, 0.1);
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ color: rgba(255, 255, 255, 0.75);
+}
+.widget-area .milestone-countdown {
+ background-color: rgba(255, 255, 255, 0.1);
+}
+.widget-area .milestone-widget {
+ margin-bottom: 48px;
+ margin-bottom: 4.8rem;
+}
+.widget-area .milestone-content {
+ margin-top: 0;
+}
+
+/* RSS Widget */
+.widget_rss li {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.widget_rss li:last-child {
+ margin-bottom: 0;
+}
+
+/* Recent Comments Widget */
+.widget_recent_comments table {
+ margin-bottom: 0;
+}
+.widget_recent_comments .avatar {
+ max-width: none;
+}
+.widget_recent_comments tr {
+}
+.widget_recent_comments td.recentcommentsavatartop,
+.widget_recent_comments td.recentcommentsavatarend {
+ padding: 8px 8px 8px 0;
+ padding: 0.8rem 0.8rem 0.8rem 0;
+}
+.widget_recent_comments td.recentcommentstexttop,
+.widget_recent_comments td.recentcommentstextend {
+ line-height: 1.2857142857;
+ padding: 8px 0 8px 8px;
+ padding: 0.8rem 0 0.8rem 0.8rem;
+ vertical-align: top;
+}
+
+/* Recent Posts Widget */
+.widget_recent_entries .post-date {
+ display: block;
+}
+
+/* Search widget */
+#searchsubmit {
+ display: none;
+}
+
+/* Twitter Widget */
+.widget_twitter li {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+.widget_twitter li:last-child {
+ margin-bottom: 0;
+}
+.widget_twitter li a {
+ word-wrap: break-word;
+}
+.widget_twitter iframe {
+ margin: 18px 0 0;
+ margin: 1.8rem 0 0;
+}
+
+
+/* =Content Sidebar
+----------------------------------------------- */
+
+#content-sidebar {
+ color: #8c8c8c;
+ font-size: 14px;
+ font-size: 1.4rem;
+ line-height: 1.2857142857;
+}
+#content-sidebar p {
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+}
+#content-sidebar a {
+ color: #2b2b2b;
+}
+#content-sidebar a:hover {
+ color: #41a62a;
+}
+#content-sidebar button,
+#content-sidebar html input[type="button"],
+#content-sidebar input[type="reset"],
+#content-sidebar input[type="submit"] {
+ background-color: #000;
+ font-size: 12px;
+ font-size: 1.2rem;
+ padding: 6px 24px;
+ padding: 0.6rem 2.4rem;
+}
+#content-sidebar button:hover,
+#content-sidebar html input[type="button"]:hover,
+#content-sidebar input[type="reset"]:hover,
+#content-sidebar input[type="submit"]:hover,
+#content-sidebar button:focus,
+#content-sidebar html input[type="button"]:focus,
+#content-sidebar input[type="reset"]:focus,
+#content-sidebar input[type="submit"]:focus {
+ background-color: #41a62a;
+}
+#content-sidebar button:active,
+#content-sidebar html input[type="button"]:active,
+#content-sidebar input[type="reset"]:active,
+#content-sidebar input[type="submit"]:active {
+ background-color: #5FF23D;
+}
+#content-sidebar input[type="text"],
+#content-sidebar input[type="email"],
+#content-sidebar input[type="password"],
+#content-sidebar textarea {
+ background-color: #fff;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ color: #2b2b2b;
+ padding: 4px;
+ padding: 0.4rem;
+}
+#content-sidebar .widget-title {
+ border-top: 5px solid #000;
+ color: #2b2b2b;
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 900;
+ margin: 0 0 18px 0;
+ margin: 0 0 1.8rem 0;
+ padding-top: 7px;
+ padding-top: 0.7rem;
+ text-transform: uppercase;
+}
+#content-sidebar .widget li {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ padding: 8px 0 9px;
+ padding: 0.8rem 0 0.9rem;
+}
+#content-sidebar .widget li:first-child {
+ border-top: none;
+}
+#content-sidebar .widget .children,
+#content-sidebar .widget .sub-menu {
+ margin:0 0 0 20px;
+ margin:0 0 0 2.0rem;
+}
+#content-sidebar .widget li li {
+ border-top: none;
+ padding-bottom: 0;
+}
+#content-sidebar .widget_calendar #wp-calendar,
+#content-sidebar .widget_calendar #wp-calendar thead th,
+#content-sidebar .widget_calendar #wp-calendar tbody td,
+#content-sidebar .widget_calendar #wp-calendar tfoot td#next {
+ border-color: rgba(0, 0, 0, 0.1);
+}
+#content-sidebar .widget_calendar #wp-calendar caption {
+ color: #2b2b2b;
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 900;
+}
+#content-sidebar .widget_calendar #wp-calendar thead th {
+ background-color: rgba(0, 0, 0, 0.02);
+}
+#content-sidebar .widget_flickr #flickr_badge_uber_wrapper a:link,
+#content-sidebar .widget_flickr #flickr_badge_uber_wrapper a:active,
+#content-sidebar .widget_flickr #flickr_badge_uber_wrapper a:visited {
+ color: #2b2b2b;
+}
+#content-sidebar .widget_flickr #flickr_badge_uber_wrapper a:hover {
+ color: #41a62a;
+}
+#content-sidebar .widget-grofile h4 {
+ color: #2b2b2b;
+ font-size: 14px;
+ font-size: 1.4rem;
+ font-weight: 900;
+ line-height: 1.2857142857;
+}
+#content-sidebar .milestone-countdown,
+#content-sidebar .milestone-message {
+ border-color: rgba(255, 255, 255, 0.1);
+ border-top: 0;
+}
+#content-sidebar .milestone-header,
+#content-sidebar .milestone-countdown,
+#content-sidebar .milestone-message {
+ background-color: #000;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ color: #fff;
+}
+#content-sidebar .milestone-countdown {
+ background-color: #fff;
+ color: #2b2b2b;
+}
+#content-sidebar .widget_rss li,
+#content-sidebar .widget_twitter li {
+ margin-bottom: 0;
+}
+#content-sidebar .widget .widgets-multi-column-grid li {
+ border-top: none;
+ padding: 0 8px 6px 0;
+ padding: 0 0.8rem 0.6rem 0;
+}
+
+
+/* =Footer Sidebar
+----------------------------------------------- */
+
+#supplementary .widget-area {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+
+/* =Jetpack
+----------------------------------------------- */
+
+/* Infinite Scroll */
+
+/* Hide elements when IS is in use */
+.infinite-scroll #nav-below,
+.infinite-scroll.neverending #colophon {
+ display: none;
+}
+.infinite-scroll #content {
+ margin-bottom: 48px;
+ margin-bottom: 4.8rem;
+}
+#infinite-handle {
+ margin-top: 48px;
+ margin-top: 4.8rem;
+ text-align: center;
+}
+#infinite-handle span {
+ background-color: #000;
+ border: 0;
+ border-radius: 2px;
+ color: #fff;
+ font-weight: 700;
+ font-size: 12px;
+ font-size: 1.2rem;
+ line-height: 1;
+ padding: 11px 35px 10px;
+ padding: 1.1rem 3.5rem 1.0rem;
+ text-transform: uppercase;
+}
+#infinite-handle span:before {
+ color: #fff;
+}
+#infinite-handle span:hover {
+ background-color: #41a62a;
+}
+.infinite-loader {
+ margin: 48px auto;
+ margin: 4.8rem auto;
+ width: 25px;
+ width: 2.5rem;
+ height: 24px;
+ height: 2.4rem;
+}
+#infinite-footer {
+ z-index: 10;
+}
+#infinite-footer .container {
+ border-width: 1px 1px 0 0;
+ margin: 0;
+}
+/* Reset when IS is finished */
+.infinite-scroll.infinity-end #content {
+ margin-bottom: 0;
+}
+.infinite-end.neverending #colophon {
+ display: block;
+}
+
+
+/* Sharing */
+#main div.sharedaddy div.sd-block {
+ border-top: 1px dotted rgba(0, 0, 0, 0.1);
+}
+#main div.sharedaddy h3.sd-title {
+ font-size: 11px;
+ font-size: 1.1rem;
+ font-family: lato, sans-serif;
+ text-transform: uppercase;
+}
+#main div.sharedaddy .sd-like h3.sd-title {
+ width: 17.875%;
+}
+.entry-content > .pd-rating .rating-msg {
+ font-size: 12px;
+ font-size: 1.2rem;
+}
+
+/* Stats image */
+img#wpstats {
+ margin-top: -5px;
+ margin-top: -0.5rem;
+ position: absolute;
+}
+
+/* Subscription */
+.jetpack_subscription_widget input[type="text"] {
+ padding: 4px !important;
+ width: 100% !important;
+}
+.comment-subscription-form {
+ margin-bottom: 0;
+}
+
+
+/* =WP.com
+----------------------------------------------- */
+
+/* Prevent stats images to break the layout */
+img[src^="http://botd"] {
+ position: absolute;
+}
+
+/* Corrects line number misalignemnt in GitHub Gist embeds */
+.gist .gist-file .gist-data .line-numbers span {
+ line-height: 1.7142857142;
+}
+.entry-content .gist table {
+ margin-bottom: 0;
+}
+
+
+/* =Media Queries
+----------------------------------------------- */
+
+/* Mobile list style */
+@media screen and (max-width: 400px) {
+ .list-view #primary {
+ padding: 12px 10px;
+ padding: 1.2rem 1.0rem;
+ }
+ .list-view #primary .hentry {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
+ margin-bottom: 12px;
+ margin-bottom: 1.2rem;
+ min-height: 60px;
+ min-height: 6.0rem;
+ padding-bottom: 9px;
+ padding-bottom: 0.9rem;
+ }
+ .list-view #primary .cat-links,
+ .list-view #primary .entry-content,
+ .list-view #primary .entry-summary,
+ .list-view #primary footer.entry-meta {
+ display: none;
+ }
+ .list-view .attachment-featured-thumbnail {
+ background: none;
+ min-height: 0;
+ width: auto;
+ z-index: 2;
+ }
+ .list-view .attachment-featured-thumbnail img {
+ float: left;
+ margin: 0 10px 3px 0;
+ margin: 0 1.0rem 0.3rem 0;
+ width: 84px;
+ width: 8.4rem;
+ }
+ .list-view #primary .entry-header {
+ background-color: transparent;
+ padding: 0;
+ }
+ .list-view #primary .entry-title {
+ font-size: 15px;
+ font-size: 1.5rem;
+ font-weight: 900;
+ line-height: 1.2;
+ margin-bottom: 6px;
+ margin-bottom: 0.6rem;
+ text-transform: none;
+ }
+ .list-view #primary .entry-meta {
+ background-color: transparent;
+ clear: none;
+ margin: 0;
+ text-transform: none;
+ }
+ .list-view #primary .format-aside,
+ .list-view #primary .format-quote,
+ .list-view #primary .format-link,
+ .list-view #primary .format-image,
+ .list-view #primary .format-video {
+ border-top: 0;
+ }
+ .list-view #primary .format-aside .entry-header .entry-title,
+ .list-view #primary .format-quote .entry-header .entry-title,
+ .list-view #primary .format-link .entry-header .entry-title {
+ display: block;
+ }
+}
+
+/* Enable Genricons */
+@media screen and (min-width: 400px) {
+ a.attachment-featured-thumbnail:hover img {
+ opacity: 0.8;
+ }
+ #primary span + span.entry-date:before,
+ #primary span + .byline:before,
+ #primary span + .comments-link:before,
+ #primary span + .edit-link:before,
+ .full-size-link:before,
+ .parent-post-link:before {
+ content: '';
+ }
+ #primary .featured-post:before,
+ #primary .post-format a:before,
+ #primary .post-format + span.entry-date a:before,
+ #primary span.entry-date a:before,
+ #primary .byline a:before,
+ #primary .comments-link a:before,
+ #primary .edit-link a:before,
+ .attachment span.entry-date:before,
+ #primary .full-size-link a:before,
+ #primary .parent-post-link a:before {
+ display: inline-block;
+ -webkit-font-smoothing: antialiased;
+ font: normal 16px/1 'Genericons';
+ font-size:1.6rem;
+ margin: 0 2px 0 0;
+ margin: 0 0.2rem 0 0;
+ text-transform: none;
+ vertical-align: top;
+ }
+ #primary .entry-meta > span {
+ margin-right: 10px;
+ margin-right: 1.0rem;
+ }
+ #primary .format-video .post-format a:before {
+ content: '\F104';
+ margin: -1px 2px 0 0;
+ margin: -0.1rem 0.2rem 0 0;
+ }
+ #primary .format-image .post-format a:before {
+ content: '\F102';
+ margin: -1px 2px 0 0;
+ margin: -0.1rem 0.2rem 0 0;
+ }
+ #primary .format-quote .post-format a:before {
+ content: '\F106';
+ }
+ #primary .format-gallery .post-format a:before {
+ content: '\F103';
+ margin: -1px 4px 0 0;
+ margin: -0.1rem 0.4rem 0 0;
+ }
+ #primary .format-aside .post-format a:before {
+ content: '\F101';
+ }
+ #primary .format-link .post-format a:before {
+ content: '\F107';
+ }
+ #primary .featured-post:before {
+ content: '\F308';
+ margin: -1px 3px 0 0;
+ margin: -0.1rem 0.3rem 0 0;
+ }
+ #primary .post-format + span.entry-date a:before,
+ #primary span.entry-date a:before,
+ .attachment span.entry-date:before {
+ content: '\F303';
+ margin: 0 1px 0 0;
+ margin: 0 0.1rem 0 0;
+ }
+ #primary .byline a:before {
+ content: '\F304';
+ margin: -1px 0 0 0;
+ margin: -0.1rem 0 0 0;
+ }
+ #primary .comments-link a:before {
+ content: '\F300';
+ margin: -1px 2px 0 0;
+ margin: -0.1rem 0.2rem 0 0;
+ }
+ #primary .edit-link a:before {
+ content: '\F411';
+ margin: -1px 2px 0 0;
+ margin: -0.1rem 0.2rem 0 0;
+ }
+ #primary .full-size-link a:before {
+ content: '\F402';
+ }
+ #primary .parent-post-link a:before {
+ content: '\F301';
+ }
+ .page #primary .edit-link a:before {
+ margin: 5px 2px 0 0;
+ margin: 0.5rem 0.2rem 0 0;
+ }
+ #infinite-handle {
+ margin: 48px 10px 0;
+ margin: 4.8rem 1.0rem 0;
+ }
+}
+
+/* Post formatted posts and post list start to appear on the right */
+@media screen and (min-width: 672px) {
+ .search-toggle {
+ display: block;
+ }
+ .social-links-toggle {
+ border-right: 1px solid rgba(255, 255, 255, 0.4);
+ }
+ .social-links-wrapper {
+ margin: 0;
+ }
+ #primary {
+ float: left;
+ padding: 36px 0;
+ padding: 3.6rem 0;
+ width: 100%;
+ }
+ .site-content {
+ margin: 0 33.33333333% 0 0;
+ }
+ #content-sidebar {
+ float: right;
+ margin: 0 0 0 -30.35714285%;
+ padding: 36px 10px 24px 0;
+ padding: 3.6rem 1.0rem 2.4rem 0;
+ width: 30.35714285%;
+ }
+ .post-formatted-posts {
+ border: none;
+ clear: none;
+ float: right;
+ margin: 0 0 0 -30.35714285%;
+ padding: 36px 10px 0 0;
+ padding: 3.6rem 1.0rem 0 0;
+ width: 30.35714285%;
+ }
+ #featured-content .hentry {
+ float: left;
+ width: 50%;
+ }
+ #featured-content .hentry:nth-child( 2n+1 ) {
+ clear: both;
+ }
+ #featured-content .entry-wrap {
+ height: 96px;
+ height: 9.6rem;
+ }
+ .full-width.site-content {
+ margin: 0;
+ }
+ .full-width.site-content .hentry {
+ max-width: 100%;
+ }
+}
+
+@media screen and (min-width: 740px) {
+ #primary .entry-header {
+ margin: -48px 4.59183673% 0;
+ margin: -4.8rem 4.59183673% 0;
+ padding: 24px 4.46428571% 12px;
+ padding: 2.4rem 4.46428571% 1.2rem;
+ }
+ #primary .entry-content,
+ #primary .entry-summary {
+ margin: 0 4.59183673%;
+ padding: 12px 4.46428571% 0;
+ padding: 1.2rem 4.46428571% 0;
+ }
+ #primary footer.entry-meta {
+ margin: 12px 4.59183673% 24px;
+ margin: 1.2rem 4.59183673% 2.4rem;
+ padding: 0 4.46428571%;
+ }
+ .page-header {
+ margin: 0 4.59183673% 24px;
+ margin: 0 4.59183673% 2.4rem;
+ padding: 0 4.46428571%;
+ }
+ .page #primary .entry-header,
+ .error404 #primary .entry-header {
+ margin: 0 4.59183673%;
+ padding: 0 4.46428571% 12px;
+ padding: 0 4.46428571% 1.2rem;
+ }
+ #primary .full-width .entry-header {
+ margin: 0 6.04307432%;
+ padding: 0 0 12px;
+ padding: 0 0 1.2rem;
+ }
+ #primary .full-width .entry-content {
+ margin: 0 6.04307432%;
+ padding: 0;
+ }
+ #primary .full-width footer.entry-meta {
+ margin: 0 6.04307432%;
+ padding: 0;
+ }
+ #primary .format-aside .entry-header,
+ #primary .format-quote .entry-header,
+ #primary .format-link .entry-header,
+ #primary .format-video .entry-header,
+ #primary .format-image .entry-header {
+ margin-top: 12px;
+ margin-top: 1.2rem;
+ }
+ .single #primary .format-aside .entry-header,
+ .single #primary .format-quote .entry-header,
+ .single #primary .format-link .entry-header,
+ .single #primary .format-image .entry-header,
+ .single #primary .format-video .entry-header {
+ margin-top: 0;
+ }
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback {
+ margin-bottom: 36px;
+ margin-bottom: 3.6rem;
+ padding-top: 36px;
+ padding-top: 3.6rem;
+ }
+ .comment-author {
+ padding-left: 60px;
+ padding-left: 6.0rem;
+ }
+ .comment-author .comment-author-avatar,
+ .comment-author .avatar {
+ width: 32px;
+ width: 3.2rem;
+ height: 32px;
+ height: 3.2rem;
+ }
+ .comment-meta,
+ .comment-content {
+ padding-left: 60px;
+ padding-left: 6.0rem;
+ }
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-right: 9.12778904%;
+ padding-left: 9.12778904%;
+ }
+ #reply-title,
+ #respond #commentform {
+ padding: 0;
+ }
+ .comment-navigation {
+ padding-left: 9.12778904%;
+ }
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-right: 6.04307432%;
+ padding-left: 6.04307432%;
+ }
+ .full-width #reply-title,
+ .full-width #commentform {
+ padding: 0;
+ }
+ #infinite-handle {
+ margin: 48px 0 0;
+ margin: 4.8rem 0 0;
+ }
+ #infinite-handle span {
+ display: inline;
+ }
+ #primary .no-results .entry-header {
+ margin: 0 4.59183673%;
+ padding: 0 4.46428571%;
+ }
+}
+
+@media screen and (min-width: 770px) {
+ .header-main {
+ margin-right: 0;
+ }
+ .primary-navigation {
+ display: block;
+ }
+}
+
+@media screen and (min-width: 870px) {
+ #primary {
+ padding-top: 72px;
+ padding-top: 7.2rem;
+ }
+ .home #primary {
+ padding-top: 36px;
+ padding-top: 3.6rem;
+ }
+ #primary .entry-header {
+ margin-right: 8.03571428%;
+ margin-left: 12.5%;
+ }
+ #primary .entry-content,
+ #primary .entry-summary {
+ margin-right: 8.03571428%;
+ margin-left: 12.5%;
+ }
+ #primary footer.entry-meta {
+ margin: 12px 8.03571428% 24px 12.5%;
+ margin: 1.2rem 8.03571428% 2.4rem 12.5%;
+ }
+ .page #primary .entry-header,
+ .error404 #primary .entry-header {
+ margin: 0 8.03571428% 0 12.5%;
+ }
+ #primary .full-width .entry-header,
+ #primary .full-width .entry-content,
+ #primary .full-width footer.entry-meta {
+ margin: 0 11.30926724%;
+ }
+ .page-header {
+ margin: 0 8.03571428% 24px 12.5%;
+ margin: 0 8.03571428% 2.4rem 12.5%;
+ }
+ #content-sidebar {
+ padding-top: 72px;
+ padding-top: 7.2rem;
+ }
+ #featured-content .hentry {
+ width: 33.3333333%;
+ }
+ #featured-content .hentry:nth-child( 2n+1 ) {
+ clear: none;
+ }
+ #featured-content .hentry:nth-child( 3n+1 ) {
+ clear: both;
+ }
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-right: 12.39493534%;
+ padding-left: 17.06896551%;
+ }
+ #comments #respond {
+ padding-right: 13.8900862%;
+ }
+ .commentlist,
+ .full-width .commentlist {
+ margin-left: -70px;
+ margin-left: -7.0rem;
+ }
+ .comment-navigation {
+ padding-left: 17.06896551%;
+ }
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-right: 11.30926724%;
+ padding-left: 11.30926724%;
+ }
+ blockquote.pull.alignleft {
+ margin-left: -20%;
+ }
+ blockquote.pull.alignright {
+ margin-right: -20%;
+ }
+ #primary .no-results .entry-header {
+ margin-right: 8.03571428%;
+ margin-left: 12.5%;
+ }
+ #primary .no-results .entry-content {
+ margin-right: 8.03571428%;
+ margin-left: 12.5%;
+ }
+}
+
+/* Secondary starts appear on the left */
+@media screen and (min-width: 1008px) {
+ #page:before {
+ background-color: #000;
+ content: '';
+ height: 100%;
+ min-height: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 222px;
+ width: 22.2rem;
+ z-index: 2;
+ }
+ .header-main {
+ padding-left: 27px;
+ padding-left: 2.7rem;
+ }
+ .social-links-wrapper,
+ .search-box-wrapper {
+ padding-left: 222px;
+ padding-left: 22.2rem;
+ }
+ .site-content {
+ margin: 0 27.31707317% 0 222px;
+ margin: 0 27.31707317% 0 22.2rem;
+ }
+ #secondary {
+ background-color: transparent;
+ border-bottom: 0;
+ clear: none;
+ font-size: 1.1rem;
+ float: left;
+ line-height: 1.6363636363;
+ margin: 0 0 0 -100%;
+ padding: 0 27px;
+ padding: 0 2.7rem;
+ width: 168px;
+ width: 16.8rem;
+ }
+ .site-description {
+ display: block;
+ line-height: 1.6363636363;
+ margin: -3px 0 21px;
+ margin: -0.3rem 0 2.1rem;
+ }
+ .front-page-content-wrapper {
+ float: left;
+ }
+ .site-content {
+ margin: 0 27.31707317% 0 222px;
+ margin: 0 27.31707317% 0 22.2rem;
+ }
+ #content-sidebar,
+ .post-formatted-posts {
+ margin: 0 0 0 -27.31707317%;
+ width: 24.87804878%;
+ }
+ #primary .entry-header {
+ margin: -48px 4.59183673% 0;
+ margin: -4.8rem 4.59183673% 0;
+ padding: 24px 4.46428571% 12px;
+ padding: 2.4rem 4.46428571% 1.2rem;
+ }
+ #primary .entry-content,
+ #primary .entry-summary {
+ margin: 0 4.59183673%;
+ padding: 12px 4.46428571% 0;
+ padding: 1.2rem 4.46428571% 0;
+ }
+ #primary footer.entry-meta {
+ margin: 12px 4.59183673% 24px;
+ margin: 1.2rem 4.59183673% 2.4rem;
+ padding: 0 4.46428571%;
+ }
+ .page-header {
+ margin: 0 4.59183673% 24px;
+ margin: 0 4.59183673% 2.4rem;
+ }
+ #featured-content {
+ padding-left: 222px;
+ padding-left: 22.2rem;
+ }
+ #colophon {
+ padding-left: 27px;
+ padding-left: 2.7rem;
+ }
+ .secondary-navigation {
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ font-size: 11px;
+ font-size: 1.1rem;
+ }
+ .secondary-navigation ul,
+ .secondary-navigation ul ul {
+ list-style: none;
+ margin: 0;
+ }
+ .secondary-navigation li {
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
+ position: relative;
+ }
+ .secondary-navigation a {
+ padding: 8px 0 9px;
+ padding: 0.8rem 0 0.9rem;
+ }
+ .secondary-navigation ul ul {
+ background: rgba(0, 0, 0, 0.9);
+ display: none;
+ position: absolute;
+ top: -1px;
+ top: -0.1rem;
+ left: 168px;
+ left: 16.8rem;
+ width: 168px;
+ width: 16.8rem;
+ z-index: 9999;
+ }
+ .secondary-navigation ul li:hover {
+ background: #000;
+ }
+ .secondary-navigation ul li:hover > ul {
+ display: block;
+ }
+ .page #primary .entry-header,
+ .error404 #primary .entry-header {
+ margin: 0 4.59183673%;
+ padding: 0 4.46428571% 12px;
+ padding: 0 4.46428571% 1.2rem;
+ }
+ .full-width.site-content {
+ margin-left: 222px;
+ margin-left: 22.2rem;
+ }
+ #primary .full-width .entry-header {
+ padding: 0 0 12px;
+ padding: 0 0 1.2rem;
+ }
+ #primary .full-width .entry-header,
+ #primary .full-width .entry-content,
+ #primary .full-width footer.entry-meta {
+ margin: 0 5.882236%;
+ }
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-right: 9.87001616%;
+ padding-left: 9.19765166%;
+ }
+ .commentlist,
+ .full-width .commentlist {
+ margin-left: 0;
+ }
+ .comment-navigation {
+ padding-left: 9.19765166%;
+ }
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-right: 5.882236%;
+ padding-left: 5.882236%;
+ }
+ blockquote.pull.alignleft {
+ margin-left: 0;
+ }
+ blockquote.pull.alignright {
+ margin-right: 0;
+ }
+ #secondary .widget,
+ #supplementary .widget {
+ margin-bottom: 48px;
+ margin-bottom: 4.8rem;
+ }
+ #secondary .widget-title,
+ #supplementary .widget-title {
+ font-size: 11px;
+ font-size: 1.1rem;
+ font-weight: 700;
+ line-height: 1.6363636363;
+ margin-bottom: 18px;
+ margin-bottom: 1.8rem;
+ }
+ #supplementary {
+ font-size: 11px;
+ font-size: 1.1rem;
+ line-height: 1.6363636363;
+ padding-right: 0;
+ padding-left: 0;
+ }
+ #supplementary .widget-area {
+ float: left;
+ padding: 0 27px;
+ padding: 0 2.7rem;
+ }
+ #supplementary.one .widget-area {
+ width: 100%;
+ }
+ #supplementary.two .widget-area {
+ width: 50%;
+ }
+ #supplementary.three .widget-area {
+ width: 33.33333333%;
+ }
+ #supplementary.four .widget-area {
+ width: 25%;
+ }
+ #supplementary.five .widget-area {
+ width: 20%;
+ }
+}
+
+@media screen and (min-width: 1150px) {
+ #primary .entry-header {
+ margin: -48px 8.03571428% 0 12.5%;
+ margin: -4.8rem 8.03571428% 0 12.5%;
+ }
+ #primary .entry-content,
+ #primary .entry-summary {
+ margin: 0 8.03571428% 0 12.5%;
+ }
+ #primary footer.entry-meta {
+ margin: 12px 8.03571428% 24px 12.5%;
+ margin: 1.2rem 8.03571428% 2.4rem 12.5%;
+ }
+ .comments-title,
+ .nocomments,
+ #comments #respond,
+ .comments-area article,
+ .commentlist li.trackback,
+ .commentlist li.pingback,
+ .post-navigation .nav-previous,
+ .post-navigation .nav-next {
+ padding-right: 12.44146986%;
+ padding-left: 16.77524429%;
+ }
+ #comments #respond {
+ padding-right: 13.73697916%;
+ }
+ .commentlist,
+ .full-width .commentlist {
+ margin-left: -70px;
+ margin-left: -7.0rem;
+ }
+ .comment-navigation {
+ padding-left: 16.77524429%;
+ }
+ .page-header {
+ margin: 0 8.03571428% 24px 12.5%;
+ margin: 0 8.03571428% 2.4rem 12.5%;
+ }
+ .page #primary .entry-header,
+ .error404 #primary .entry-header {
+ margin: 0 8.03571428% 0 12.5%;
+ }
+ #primary .full-width .entry-header,
+ #primary .full-width .entry-content,
+ #primary .full-width footer.entry-meta {
+ margin: 0 11.21868265%;
+ }
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-right: 11.21868265%;
+ padding-left: 11.21868265%;
+ }
+ #primary .entry-content .wp-caption.alignleft .wp-caption-text {
+ padding-left: 10px;
+ padding-left: 1.0rem;
+ }
+ blockquote.pull.alignleft {
+ margin-left: -20%;
+ }
+ blockquote.pull.alignright {
+ margin-right: -20%;
+ }
+}
+
+@media screen and (min-width: 1230px) {
+ #page,
+ #masthead,
+ .home #main {
+ max-width: 1260px;
+ max-width: 126.0rem;
+ }
+ #content-sidebar,
+ .post-formatted-posts {
+ padding-right: 0;
+ }
+ #primary .full-width .entry-header,
+ #primary .full-width .entry-content,
+ #primary .full-width footer.entry-meta {
+ margin: 0 0 0 11.21868265%;
+ }
+ #image-navigation .previous-image,
+ #image-navigation .next-image,
+ .full-width .comment-navigation,
+ .full-width .comments-title,
+ .full-width #comments #respond,
+ .full-width .comments-area article,
+ .full-width .commentlist li.trackback,
+ .full-width .commentlist li.pingback {
+ padding-right: 0;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyten/404.php b/src/wp-content/themes/twentyten/404.php
new file mode 100644
index 0000000000..3baea8126c
--- /dev/null
+++ b/src/wp-content/themes/twentyten/404.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * The template for displaying 404 pages (Not Found).
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+ <div id="post-0" class="post error404 not-found">
+ <h1 class="entry-title"><?php _e( 'Not Found', 'twentyten' ); ?></h1>
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but the page you requested could not be found. Perhaps searching will help.', 'twentyten' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </div><!-- #post-0 -->
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+ <script type="text/javascript">
+ // focus on search field after it has loaded
+ document.getElementById('s') && document.getElementById('s').focus();
+ </script>
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentyten/archive.php b/src/wp-content/themes/twentyten/archive.php
new file mode 100644
index 0000000000..3899f0ecde
--- /dev/null
+++ b/src/wp-content/themes/twentyten/archive.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * The template for displaying Archive pages.
+ *
+ * Used to display archive-type pages if nothing more specific matches a query.
+ * For example, puts together date-based pages if no date.php file exists.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+<?php
+ /* Queue the first post, that way we know
+ * what date we're dealing with (if that is the case).
+ *
+ * We reset this later so we can run the loop
+ * properly with a call to rewind_posts().
+ */
+ if ( have_posts() )
+ the_post();
+?>
+
+ <h1 class="page-title">
+<?php if ( is_day() ) : ?>
+ <?php printf( __( 'Daily Archives: <span>%s</span>', 'twentyten' ), get_the_date() ); ?>
+<?php elseif ( is_month() ) : ?>
+ <?php printf( __( 'Monthly Archives: <span>%s</span>', 'twentyten' ), get_the_date( _x( 'F Y', 'monthly archives date format', 'twentyten' ) ) ); ?>
+<?php elseif ( is_year() ) : ?>
+ <?php printf( __( 'Yearly Archives: <span>%s</span>', 'twentyten' ), get_the_date( _x( 'Y', 'yearly archives date format', 'twentyten' ) ) ); ?>
+<?php else : ?>
+ <?php _e( 'Blog Archives', 'twentyten' ); ?>
+<?php endif; ?>
+ </h1>
+
+<?php
+ /* Since we called the_post() above, we need to
+ * rewind the loop back to the beginning that way
+ * we can run the loop properly, in full.
+ */
+ rewind_posts();
+
+ /* Run the loop for the archives page to output the posts.
+ * If you want to overload this in a child theme then include a file
+ * called loop-archive.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'archive' );
+?>
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/attachment.php b/src/wp-content/themes/twentyten/attachment.php
new file mode 100644
index 0000000000..5b35936e90
--- /dev/null
+++ b/src/wp-content/themes/twentyten/attachment.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * The template for displaying attachments.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container" class="single-attachment">
+ <div id="content" role="main">
+
+ <?php
+ /* Run the loop to output the attachment.
+ * If you want to overload this in a child theme then include a file
+ * called loop-attachment.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'attachment' );
+ ?>
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/author.php b/src/wp-content/themes/twentyten/author.php
new file mode 100644
index 0000000000..2bd48c8472
--- /dev/null
+++ b/src/wp-content/themes/twentyten/author.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * The template for displaying Author Archive pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+<?php
+ /* Queue the first post, that way we know who
+ * the author is when we try to get their name,
+ * URL, description, avatar, etc.
+ *
+ * We reset this later so we can run the loop
+ * properly with a call to rewind_posts().
+ */
+ if ( have_posts() )
+ the_post();
+?>
+
+ <h1 class="page-title author"><?php printf( __( 'Author Archives: %s', 'twentyten' ), "<span class='vcard'><a class='url fn n' href='" . get_author_posts_url( get_the_author_meta( 'ID' ) ) . "' title='" . esc_attr( get_the_author() ) . "' rel='me'>" . get_the_author() . "</a></span>" ); ?></h1>
+
+<?php
+// If a user has filled out their description, show a bio on their entries.
+if ( get_the_author_meta( 'description' ) ) : ?>
+ <div id="entry-author-info">
+ <div id="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentyten_author_bio_avatar_size', 60 ) ); ?>
+ </div><!-- #author-avatar -->
+ <div id="author-description">
+ <h2><?php printf( __( 'About %s', 'twentyten' ), get_the_author() ); ?></h2>
+ <?php the_author_meta( 'description' ); ?>
+ </div><!-- #author-description -->
+ </div><!-- #entry-author-info -->
+<?php endif; ?>
+
+<?php
+ /* Since we called the_post() above, we need to
+ * rewind the loop back to the beginning that way
+ * we can run the loop properly, in full.
+ */
+ rewind_posts();
+
+ /* Run the loop for the author archive page to output the authors posts
+ * If you want to overload this in a child theme then include a file
+ * called loop-author.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'author' );
+?>
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/category.php b/src/wp-content/themes/twentyten/category.php
new file mode 100644
index 0000000000..0792e1fef5
--- /dev/null
+++ b/src/wp-content/themes/twentyten/category.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * The template for displaying Category Archive pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+ <h1 class="page-title"><?php
+ printf( __( 'Category Archives: %s', 'twentyten' ), '<span>' . single_cat_title( '', false ) . '</span>' );
+ ?></h1>
+ <?php
+ $category_description = category_description();
+ if ( ! empty( $category_description ) )
+ echo '<div class="archive-meta">' . $category_description . '</div>';
+
+ /* Run the loop for the category page to output the posts.
+ * If you want to overload this in a child theme then include a file
+ * called loop-category.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'category' );
+ ?>
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/comments.php b/src/wp-content/themes/twentyten/comments.php
new file mode 100644
index 0000000000..62527288f4
--- /dev/null
+++ b/src/wp-content/themes/twentyten/comments.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * The template for displaying Comments.
+ *
+ * The area of the page that contains both current comments
+ * and the comment form. The actual display of comments is
+ * handled by a callback to twentyten_comment which is
+ * located in the functions.php file.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+?>
+
+ <div id="comments">
+<?php if ( post_password_required() ) : ?>
+ <p class="nopassword"><?php _e( 'This post is password protected. Enter the password to view any comments.', 'twentyten' ); ?></p>
+ </div><!-- #comments -->
+<?php
+ /* Stop the rest of comments.php from being processed,
+ * but don't kill the script entirely -- we still have
+ * to fully load the template.
+ */
+ return;
+ endif;
+?>
+
+<?php
+ // You can start editing here -- including this comment!
+?>
+
+<?php if ( have_comments() ) : ?>
+ <h3 id="comments-title"><?php
+ printf( _n( 'One Response to %2$s', '%1$s Responses to %2$s', get_comments_number(), 'twentyten' ),
+ number_format_i18n( get_comments_number() ), '<em>' . get_the_title() . '</em>' );
+ ?></h3>
+
+<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // Are there comments to navigate through? ?>
+ <div class="navigation">
+ <div class="nav-previous"><?php previous_comments_link( __( '<span class="meta-nav">&larr;</span> Older Comments', 'twentyten' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>
+ </div> <!-- .navigation -->
+<?php endif; // check for comment navigation ?>
+
+ <ol class="commentlist">
+ <?php
+ /* Loop through and list the comments. Tell wp_list_comments()
+ * to use twentyten_comment() to format the comments.
+ * If you want to overload this in a child theme then you can
+ * define twentyten_comment() and that will be used instead.
+ * See twentyten_comment() in twentyten/functions.php for more.
+ */
+ wp_list_comments( array( 'callback' => 'twentyten_comment' ) );
+ ?>
+ </ol>
+
+<?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // Are there comments to navigate through? ?>
+ <div class="navigation">
+ <div class="nav-previous"><?php previous_comments_link( __( '<span class="meta-nav">&larr;</span> Older Comments', 'twentyten' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>
+ </div><!-- .navigation -->
+<?php endif; // check for comment navigation ?>
+
+ <?php
+ /* If there are no comments and comments are closed, let's leave a little note, shall we?
+ * But we only want the note on posts and pages that had comments in the first place.
+ */
+ if ( ! comments_open() && get_comments_number() ) : ?>
+ <p class="nocomments"><?php _e( 'Comments are closed.' , 'twentyten' ); ?></p>
+ <?php endif; ?>
+
+<?php endif; // end have_comments() ?>
+
+<?php comment_form(); ?>
+
+</div><!-- #comments -->
diff --git a/src/wp-content/themes/twentyten/editor-style-rtl.css b/src/wp-content/themes/twentyten/editor-style-rtl.css
new file mode 100644
index 0000000000..5868d3c18f
--- /dev/null
+++ b/src/wp-content/themes/twentyten/editor-style-rtl.css
@@ -0,0 +1,29 @@
+/*
+Theme Name: Twenty Ten
+*/
+/*
+Used to style the TinyMCE editor.
+*/
+html .mceContentBody{
+ direction: rtl;
+ unicode-bidi: embed;
+ float: right;
+ width: 640px;
+}
+* {
+ font-family: Arial, Tahoma, sans-serif;
+}
+/* Text elements */
+ul, ol {
+ margin: 0 -18px 18px 0;
+}
+dd {
+ margin-right: 0;
+}
+blockquote {
+ font-style: normal;
+}
+table {
+ text-align: right;
+ margin: 0 0 24px -1px;
+}
diff --git a/src/wp-content/themes/twentyten/editor-style.css b/src/wp-content/themes/twentyten/editor-style.css
new file mode 100644
index 0000000000..c397b116c2
--- /dev/null
+++ b/src/wp-content/themes/twentyten/editor-style.css
@@ -0,0 +1,297 @@
+/*
+Theme Name: Twenty Ten
+Description: Used to style the TinyMCE editor.
+*/
+html .mceContentBody {
+ max-width: 640px;
+}
+* {
+ color: #444;
+ font-family: Georgia, "Bitstream Charter", serif;
+ line-height: 1.5;
+}
+p,
+dl,
+td,
+th,
+ul,
+ol,
+blockquote {
+ font-size: 16px;
+}
+tr th,
+thead th,
+label,
+tr th,
+thead th {
+ font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif;
+}
+pre {
+ font-family: "Courier 10 Pitch", Courier, monospace;
+}
+code, code var {
+ font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
+}
+body, input, textarea {
+ font-size: 12px;
+ line-height: 18px;
+}
+hr {
+ background-color: #e7e7e7;
+ border: 0;
+ clear: both;
+ height: 1px;
+ margin-bottom: 18px;
+}
+/* Text elements */
+p {
+ margin-bottom: 18px;
+}
+
+ul,
+ol {
+ margin: 0 0 18px 1.5em;
+ padding: 0;
+}
+
+ul {
+ list-style: square;
+}
+ol {
+ list-style: decimal;
+}
+ol ol {
+ list-style: upper-alpha;
+}
+ol ol ol {
+ list-style: lower-roman;
+}
+ol ol ol ol {
+ list-style: lower-alpha;
+}
+ul ul,
+ol ol,
+ul ol,
+ol ul {
+ margin-bottom: 0;
+}
+dl {
+ margin: 0 0 24px 0;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-bottom: 18px;
+}
+strong {
+ color: #000;
+ font-weight: bold;
+}
+cite,
+em,
+i {
+ border: none;
+ font-style: italic;
+}
+big {
+ font-size: 131.25%;
+}
+ins {
+ background: #ffc;
+ border: none;
+ color: #333;
+}
+del {
+ text-decoration: line-through;
+ color: #555;
+}
+blockquote {
+ font-style: italic;
+ padding: 0 3em;
+}
+blockquote cite,
+blockquote em,
+blockquote i {
+ font-style: normal;
+}
+pre {
+ background: #f7f7f7;
+ color: #222;
+ line-height: 18px;
+ margin-bottom: 18px;
+ padding: 1.5em;
+}
+abbr,
+acronym {
+ border-bottom: 1px dotted #666;
+ cursor: help;
+}
+ins {
+ text-decoration: none;
+}
+sup,
+sub {
+ font-size: 10px;
+ height: 0;
+ line-height: 1;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ bottom: 1ex;
+}
+sub {
+ top: .5ex;
+}
+a:link {
+ color: #06c;
+}
+a:visited {
+ color: #743399;
+}
+a:active,
+a:hover {
+ color: #ff4b33;
+}
+p,
+ul,
+ol,
+dd,
+pre,
+hr {
+ margin-bottom: 24px;
+}
+ul ul,
+ol ol,
+ul ol,
+ol ul {
+ margin-bottom: 0;
+}
+pre,
+kbd,
+tt,
+var {
+ font-size: 15px;
+ line-height: 21px;
+}
+code {
+ font-size: 13px;
+}
+strong,
+b,
+dt,
+th {
+ color: #000;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ color: #000;
+ font-weight: normal;
+ line-height: 1.5em;
+ margin: 0 0 20px 0;
+}
+h1 {
+ font-size: 2.4em;
+}
+h2 {
+ font-size: 1.8em;
+}
+h3 {
+ font-size: 1.4em;
+}
+h4 {
+ font-size: 1.2em;
+}
+h5 {
+ font-size: 1em;
+}
+h6 {
+ font-size: 0.9em;
+}
+table {
+ border: 1px solid #e7e7e7 !important;
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 0 -1px 24px 0;
+ text-align: left;
+ width: 100%;
+}
+tr th,
+thead th {
+ border: none !important;
+ color: #888;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 18px;
+ padding: 9px 24px;
+}
+tr td {
+ border: none !important;
+ border-top: 1px solid #e7e7e7 !important;
+ padding: 6px 24px;
+}
+img {
+ margin: 0;
+}
+img.size-auto,
+img.size-large,
+img.size-full,
+img.size-medium {
+ max-width: 100%;
+ height: auto;
+}
+.alignleft,
+img.alignleft {
+ display: inline;
+ float: left;
+ margin-right: 24px;
+ margin-top: 4px;
+}
+.alignright,
+img.alignright {
+ display: inline;
+ float: right;
+ margin-left: 24px;
+ margin-top: 4px;
+}
+.aligncenter,
+img.aligncenter {
+ clear: both;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+img.alignleft,
+img.alignright,
+img.aligncenter {
+ margin-bottom: 12px;
+}
+.wp-caption {
+ background: #f1f1f1;
+ border: none;
+ -khtml-border-radius: 0;
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+ color: #888;
+ font-size: 12px;
+ line-height: 18px;
+ margin-bottom: 20px;
+ max-width: 632px !important; /* prevent too-wide images from breaking layout */
+ padding: 4px;
+ text-align: center;
+}
+.wp-caption img {
+ margin: 5px;
+}
+.wp-caption p.wp-caption-text {
+ margin: 0 0 4px;
+}
+.wp-smiley {
+ margin: 0;
+}
diff --git a/src/wp-content/themes/twentyten/footer.php b/src/wp-content/themes/twentyten/footer.php
new file mode 100644
index 0000000000..6dcfec0ca8
--- /dev/null
+++ b/src/wp-content/themes/twentyten/footer.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * The template for displaying the footer.
+ *
+ * Contains the closing of the id=main div and all content
+ * after. Calls sidebar-footer.php for bottom widgets.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+?>
+ </div><!-- #main -->
+
+ <div id="footer" role="contentinfo">
+ <div id="colophon">
+
+<?php
+ /* A sidebar in the footer? Yep. You can can customize
+ * your footer with four columns of widgets.
+ */
+ get_sidebar( 'footer' );
+?>
+
+ <div id="site-info">
+ <a href="<?php echo home_url( '/' ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home">
+ <?php bloginfo( 'name' ); ?>
+ </a>
+ </div><!-- #site-info -->
+
+ <div id="site-generator">
+ <?php do_action( 'twentyten_credits' ); ?>
+ <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'twentyten' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'twentyten' ); ?>"><?php printf( __( 'Proudly powered by %s.', 'twentyten' ), 'WordPress' ); ?></a>
+ </div><!-- #site-generator -->
+
+ </div><!-- #colophon -->
+ </div><!-- #footer -->
+
+</div><!-- #wrapper -->
+
+<?php
+ /* Always have wp_footer() just before the closing </body>
+ * tag of your theme, or you will break many plugins, which
+ * generally use this hook to reference JavaScript files.
+ */
+
+ wp_footer();
+?>
+</body>
+</html>
diff --git a/src/wp-content/themes/twentyten/functions.php b/src/wp-content/themes/twentyten/functions.php
new file mode 100644
index 0000000000..adc7e7a97d
--- /dev/null
+++ b/src/wp-content/themes/twentyten/functions.php
@@ -0,0 +1,556 @@
+<?php
+/**
+ * TwentyTen functions and definitions
+ *
+ * Sets up the theme and provides some helper functions. Some helper functions
+ * are used in the theme as custom template tags. Others are attached to action and
+ * filter hooks in WordPress to change core functionality.
+ *
+ * The first function, twentyten_setup(), sets up the theme by registering support
+ * for various features in WordPress, such as post thumbnails, navigation menus, and the like.
+ *
+ * When using a child theme (see http://codex.wordpress.org/Theme_Development and
+ * http://codex.wordpress.org/Child_Themes), you can override certain functions
+ * (those wrapped in a function_exists() call) by defining them first in your child theme's
+ * functions.php file. The child theme's functions.php file is included before the parent
+ * theme's file, so the child theme functions would be used.
+ *
+ * Functions that are not pluggable (not wrapped in function_exists()) are instead attached
+ * to a filter or action hook. The hook can be removed by using remove_action() or
+ * remove_filter() and you can attach your own function to the hook.
+ *
+ * We can remove the parent theme's hook only after it is attached, which means we need to
+ * wait until setting up the child theme:
+ *
+ * <code>
+ * add_action( 'after_setup_theme', 'my_child_theme_setup' );
+ * function my_child_theme_setup() {
+ * // We are providing our own filter for excerpt_length (or using the unfiltered value)
+ * remove_filter( 'excerpt_length', 'twentyten_excerpt_length' );
+ * ...
+ * }
+ * </code>
+ *
+ * For more information on hooks, actions, and filters, see http://codex.wordpress.org/Plugin_API.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+/**
+ * Set the content width based on the theme's design and stylesheet.
+ *
+ * Used to set the width of images and content. Should be equal to the width the theme
+ * is designed for, generally via the style.css stylesheet.
+ */
+if ( ! isset( $content_width ) )
+ $content_width = 640;
+
+/** Tell WordPress to run twentyten_setup() when the 'after_setup_theme' hook is run. */
+add_action( 'after_setup_theme', 'twentyten_setup' );
+
+if ( ! function_exists( 'twentyten_setup' ) ):
+/**
+ * Sets up theme defaults and registers support for various WordPress features.
+ *
+ * Note that this function is hooked into the after_setup_theme hook, which runs
+ * before the init hook. The init hook is too late for some features, such as indicating
+ * support post thumbnails.
+ *
+ * To override twentyten_setup() in a child theme, add your own twentyten_setup to your child theme's
+ * functions.php file.
+ *
+ * @uses add_theme_support() To add support for post thumbnails, custom headers and backgrounds, and automatic feed links.
+ * @uses register_nav_menus() To add support for navigation menus.
+ * @uses add_editor_style() To style the visual editor.
+ * @uses load_theme_textdomain() For translation/localization support.
+ * @uses register_default_headers() To register the default custom header images provided with the theme.
+ * @uses set_post_thumbnail_size() To set a custom post thumbnail size.
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_setup() {
+
+ // This theme styles the visual editor with editor-style.css to match the theme style.
+ add_editor_style();
+
+ // Post Format support. You can also use the legacy "gallery" or "asides" (note the plural) categories.
+ add_theme_support( 'post-formats', array( 'aside', 'gallery' ) );
+
+ // This theme uses post thumbnails
+ add_theme_support( 'post-thumbnails' );
+
+ // Add default posts and comments RSS feed links to head
+ add_theme_support( 'automatic-feed-links' );
+
+ // Make theme available for translation
+ // Translations can be filed in the /languages/ directory
+ load_theme_textdomain( 'twentyten', get_template_directory() . '/languages' );
+
+ // This theme uses wp_nav_menu() in one location.
+ register_nav_menus( array(
+ 'primary' => __( 'Primary Navigation', 'twentyten' ),
+ ) );
+
+ // This theme allows users to set a custom background.
+ add_theme_support( 'custom-background', array(
+ // Let WordPress know what our default background color is.
+ 'default-color' => 'f1f1f1',
+ ) );
+
+ // The custom header business starts here.
+
+ $custom_header_support = array(
+ // The default image to use.
+ // The %s is a placeholder for the theme template directory URI.
+ 'default-image' => '%s/images/headers/path.jpg',
+ // The height and width of our custom header.
+ 'width' => apply_filters( 'twentyten_header_image_width', 940 ),
+ 'height' => apply_filters( 'twentyten_header_image_height', 198 ),
+ // Support flexible heights.
+ 'flex-height' => true,
+ // Don't support text inside the header image.
+ 'header-text' => false,
+ // Callback for styling the header preview in the admin.
+ 'admin-head-callback' => 'twentyten_admin_header_style',
+ );
+
+ add_theme_support( 'custom-header', $custom_header_support );
+
+ if ( ! function_exists( 'get_custom_header' ) ) {
+ // This is all for compatibility with versions of WordPress prior to 3.4.
+ define( 'HEADER_TEXTCOLOR', '' );
+ define( 'NO_HEADER_TEXT', true );
+ define( 'HEADER_IMAGE', $custom_header_support['default-image'] );
+ define( 'HEADER_IMAGE_WIDTH', $custom_header_support['width'] );
+ define( 'HEADER_IMAGE_HEIGHT', $custom_header_support['height'] );
+ add_custom_image_header( '', $custom_header_support['admin-head-callback'] );
+ add_custom_background();
+ }
+
+ // We'll be using post thumbnails for custom header images on posts and pages.
+ // We want them to be 940 pixels wide by 198 pixels tall.
+ // Larger images will be auto-cropped to fit, smaller ones will be ignored. See header.php.
+ set_post_thumbnail_size( $custom_header_support['width'], $custom_header_support['height'], true );
+
+ // ... and thus ends the custom header business.
+
+ // Default custom headers packaged with the theme. %s is a placeholder for the theme template directory URI.
+ register_default_headers( array(
+ 'berries' => array(
+ 'url' => '%s/images/headers/berries.jpg',
+ 'thumbnail_url' => '%s/images/headers/berries-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Berries', 'twentyten' )
+ ),
+ 'cherryblossom' => array(
+ 'url' => '%s/images/headers/cherryblossoms.jpg',
+ 'thumbnail_url' => '%s/images/headers/cherryblossoms-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Cherry Blossoms', 'twentyten' )
+ ),
+ 'concave' => array(
+ 'url' => '%s/images/headers/concave.jpg',
+ 'thumbnail_url' => '%s/images/headers/concave-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Concave', 'twentyten' )
+ ),
+ 'fern' => array(
+ 'url' => '%s/images/headers/fern.jpg',
+ 'thumbnail_url' => '%s/images/headers/fern-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Fern', 'twentyten' )
+ ),
+ 'forestfloor' => array(
+ 'url' => '%s/images/headers/forestfloor.jpg',
+ 'thumbnail_url' => '%s/images/headers/forestfloor-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Forest Floor', 'twentyten' )
+ ),
+ 'inkwell' => array(
+ 'url' => '%s/images/headers/inkwell.jpg',
+ 'thumbnail_url' => '%s/images/headers/inkwell-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Inkwell', 'twentyten' )
+ ),
+ 'path' => array(
+ 'url' => '%s/images/headers/path.jpg',
+ 'thumbnail_url' => '%s/images/headers/path-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Path', 'twentyten' )
+ ),
+ 'sunset' => array(
+ 'url' => '%s/images/headers/sunset.jpg',
+ 'thumbnail_url' => '%s/images/headers/sunset-thumbnail.jpg',
+ /* translators: header image description */
+ 'description' => __( 'Sunset', 'twentyten' )
+ )
+ ) );
+}
+endif;
+
+if ( ! function_exists( 'twentyten_admin_header_style' ) ) :
+/**
+ * Styles the header image displayed on the Appearance > Header admin panel.
+ *
+ * Referenced via add_custom_image_header() in twentyten_setup().
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_admin_header_style() {
+?>
+<style type="text/css" id="twentyten-admin-header-css">
+/* Shows the same border as on front end */
+#headimg {
+ border-bottom: 1px solid #000;
+ border-top: 4px solid #000;
+}
+/* If header-text was supported, you would style the text with these selectors:
+ #headimg #name { }
+ #headimg #desc { }
+*/
+</style>
+<?php
+}
+endif;
+
+/**
+ * Get our wp_nav_menu() fallback, wp_page_menu(), to show a home link.
+ *
+ * To override this in a child theme, remove the filter and optionally add
+ * your own function tied to the wp_page_menu_args filter hook.
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_page_menu_args( $args ) {
+ if ( ! isset( $args['show_home'] ) )
+ $args['show_home'] = true;
+ return $args;
+}
+add_filter( 'wp_page_menu_args', 'twentyten_page_menu_args' );
+
+/**
+ * Sets the post excerpt length to 40 characters.
+ *
+ * To override this length in a child theme, remove the filter and add your own
+ * function tied to the excerpt_length filter hook.
+ *
+ * @since Twenty Ten 1.0
+ * @return int
+ */
+function twentyten_excerpt_length( $length ) {
+ return 40;
+}
+add_filter( 'excerpt_length', 'twentyten_excerpt_length' );
+
+if ( ! function_exists( 'twentyten_continue_reading_link' ) ) :
+/**
+ * Returns a "Continue Reading" link for excerpts
+ *
+ * @since Twenty Ten 1.0
+ * @return string "Continue Reading" link
+ */
+function twentyten_continue_reading_link() {
+ return ' <a href="'. get_permalink() . '">' . __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyten' ) . '</a>';
+}
+endif;
+
+/**
+ * Replaces "[...]" (appended to automatically generated excerpts) with an ellipsis and twentyten_continue_reading_link().
+ *
+ * To override this in a child theme, remove the filter and add your own
+ * function tied to the excerpt_more filter hook.
+ *
+ * @since Twenty Ten 1.0
+ * @return string An ellipsis
+ */
+function twentyten_auto_excerpt_more( $more ) {
+ return ' &hellip;' . twentyten_continue_reading_link();
+}
+add_filter( 'excerpt_more', 'twentyten_auto_excerpt_more' );
+
+/**
+ * Adds a pretty "Continue Reading" link to custom post excerpts.
+ *
+ * To override this link in a child theme, remove the filter and add your own
+ * function tied to the get_the_excerpt filter hook.
+ *
+ * @since Twenty Ten 1.0
+ * @return string Excerpt with a pretty "Continue Reading" link
+ */
+function twentyten_custom_excerpt_more( $output ) {
+ if ( has_excerpt() && ! is_attachment() ) {
+ $output .= twentyten_continue_reading_link();
+ }
+ return $output;
+}
+add_filter( 'get_the_excerpt', 'twentyten_custom_excerpt_more' );
+
+/**
+ * Remove inline styles printed when the gallery shortcode is used.
+ *
+ * Galleries are styled by the theme in Twenty Ten's style.css. This is just
+ * a simple filter call that tells WordPress to not use the default styles.
+ *
+ * @since Twenty Ten 1.2
+ */
+add_filter( 'use_default_gallery_style', '__return_false' );
+
+/**
+ * Deprecated way to remove inline styles printed when the gallery shortcode is used.
+ *
+ * This function is no longer needed or used. Use the use_default_gallery_style
+ * filter instead, as seen above.
+ *
+ * @since Twenty Ten 1.0
+ * @deprecated Deprecated in Twenty Ten 1.2 for WordPress 3.1
+ *
+ * @return string The gallery style filter, with the styles themselves removed.
+ */
+function twentyten_remove_gallery_css( $css ) {
+ return preg_replace( "#<style type='text/css'>(.*?)</style>#s", '', $css );
+}
+// Backwards compatibility with WordPress 3.0.
+if ( version_compare( $GLOBALS['wp_version'], '3.1', '<' ) )
+ add_filter( 'gallery_style', 'twentyten_remove_gallery_css' );
+
+if ( ! function_exists( 'twentyten_comment' ) ) :
+/**
+ * Template for comments and pingbacks.
+ *
+ * To override this walker in a child theme without modifying the comments template
+ * simply create your own twentyten_comment(), and that function will be used instead.
+ *
+ * Used as a callback by wp_list_comments() for displaying the comments.
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_comment( $comment, $args, $depth ) {
+ $GLOBALS['comment'] = $comment;
+ switch ( $comment->comment_type ) :
+ case '' :
+ ?>
+ <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
+ <div id="comment-<?php comment_ID(); ?>">
+ <div class="comment-author vcard">
+ <?php echo get_avatar( $comment, 40 ); ?>
+ <?php printf( __( '%s <span class="says">says:</span>', 'twentyten' ), sprintf( '<cite class="fn">%s</cite>', get_comment_author_link() ) ); ?>
+ </div><!-- .comment-author .vcard -->
+ <?php if ( $comment->comment_approved == '0' ) : ?>
+ <em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'twentyten' ); ?></em>
+ <br />
+ <?php endif; ?>
+
+ <div class="comment-meta commentmetadata"><a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
+ <?php
+ /* translators: 1: date, 2: time */
+ printf( __( '%1$s at %2$s', 'twentyten' ), get_comment_date(), get_comment_time() ); ?></a><?php edit_comment_link( __( '(Edit)', 'twentyten' ), ' ' );
+ ?>
+ </div><!-- .comment-meta .commentmetadata -->
+
+ <div class="comment-body"><?php comment_text(); ?></div>
+
+ <div class="reply">
+ <?php comment_reply_link( array_merge( $args, array( 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
+ </div><!-- .reply -->
+ </div><!-- #comment-## -->
+
+ <?php
+ break;
+ case 'pingback' :
+ case 'trackback' :
+ ?>
+ <li class="post pingback">
+ <p><?php _e( 'Pingback:', 'twentyten' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( '(Edit)', 'twentyten' ), ' ' ); ?></p>
+ <?php
+ break;
+ endswitch;
+}
+endif;
+
+/**
+ * Register widgetized areas, including two sidebars and four widget-ready columns in the footer.
+ *
+ * To override twentyten_widgets_init() in a child theme, remove the action hook and add your own
+ * function tied to the init hook.
+ *
+ * @since Twenty Ten 1.0
+ * @uses register_sidebar
+ */
+function twentyten_widgets_init() {
+ // Area 1, located at the top of the sidebar.
+ register_sidebar( array(
+ 'name' => __( 'Primary Widget Area', 'twentyten' ),
+ 'id' => 'primary-widget-area',
+ 'description' => __( 'Add widgets here to appear in your sidebar.', 'twentyten' ),
+ 'before_widget' => '<li id="%1$s" class="widget-container %2$s">',
+ 'after_widget' => '</li>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ // Area 2, located below the Primary Widget Area in the sidebar. Empty by default.
+ register_sidebar( array(
+ 'name' => __( 'Secondary Widget Area', 'twentyten' ),
+ 'id' => 'secondary-widget-area',
+ 'description' => __( 'An optional secondary widget area, displays below the primary widget area in your sidebar.', 'twentyten' ),
+ 'before_widget' => '<li id="%1$s" class="widget-container %2$s">',
+ 'after_widget' => '</li>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ // Area 3, located in the footer. Empty by default.
+ register_sidebar( array(
+ 'name' => __( 'First Footer Widget Area', 'twentyten' ),
+ 'id' => 'first-footer-widget-area',
+ 'description' => __( 'An optional widget area for your site footer.', 'twentyten' ),
+ 'before_widget' => '<li id="%1$s" class="widget-container %2$s">',
+ 'after_widget' => '</li>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ // Area 4, located in the footer. Empty by default.
+ register_sidebar( array(
+ 'name' => __( 'Second Footer Widget Area', 'twentyten' ),
+ 'id' => 'second-footer-widget-area',
+ 'description' => __( 'An optional widget area for your site footer.', 'twentyten' ),
+ 'before_widget' => '<li id="%1$s" class="widget-container %2$s">',
+ 'after_widget' => '</li>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ // Area 5, located in the footer. Empty by default.
+ register_sidebar( array(
+ 'name' => __( 'Third Footer Widget Area', 'twentyten' ),
+ 'id' => 'third-footer-widget-area',
+ 'description' => __( 'An optional widget area for your site footer.', 'twentyten' ),
+ 'before_widget' => '<li id="%1$s" class="widget-container %2$s">',
+ 'after_widget' => '</li>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ // Area 6, located in the footer. Empty by default.
+ register_sidebar( array(
+ 'name' => __( 'Fourth Footer Widget Area', 'twentyten' ),
+ 'id' => 'fourth-footer-widget-area',
+ 'description' => __( 'An optional widget area for your site footer.', 'twentyten' ),
+ 'before_widget' => '<li id="%1$s" class="widget-container %2$s">',
+ 'after_widget' => '</li>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+}
+/** Register sidebars by running twentyten_widgets_init() on the widgets_init hook. */
+add_action( 'widgets_init', 'twentyten_widgets_init' );
+
+/**
+ * Removes the default styles that are packaged with the Recent Comments widget.
+ *
+ * To override this in a child theme, remove the filter and optionally add your own
+ * function tied to the widgets_init action hook.
+ *
+ * This function uses a filter (show_recent_comments_widget_style) new in WordPress 3.1
+ * to remove the default style. Using Twenty Ten 1.2 in WordPress 3.0 will show the styles,
+ * but they won't have any effect on the widget in default Twenty Ten styling.
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_remove_recent_comments_style() {
+ add_filter( 'show_recent_comments_widget_style', '__return_false' );
+}
+add_action( 'widgets_init', 'twentyten_remove_recent_comments_style' );
+
+if ( ! function_exists( 'twentyten_posted_on' ) ) :
+/**
+ * Prints HTML with meta information for the current post-date/time and author.
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_posted_on() {
+ printf( __( '<span class="%1$s">Posted on</span> %2$s <span class="meta-sep">by</span> %3$s', 'twentyten' ),
+ 'meta-prep meta-prep-author',
+ sprintf( '<a href="%1$s" title="%2$s" rel="bookmark"><span class="entry-date">%3$s</span></a>',
+ get_permalink(),
+ esc_attr( get_the_time() ),
+ get_the_date()
+ ),
+ sprintf( '<span class="author vcard"><a class="url fn n" href="%1$s" title="%2$s">%3$s</a></span>',
+ get_author_posts_url( get_the_author_meta( 'ID' ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentyten' ), get_the_author() ) ),
+ get_the_author()
+ )
+ );
+}
+endif;
+
+if ( ! function_exists( 'twentyten_posted_in' ) ) :
+/**
+ * Prints HTML with meta information for the current post (category, tags and permalink).
+ *
+ * @since Twenty Ten 1.0
+ */
+function twentyten_posted_in() {
+ // Retrieves tag list of current post, separated by commas.
+ $tag_list = get_the_tag_list( '', ', ' );
+ if ( $tag_list ) {
+ $posted_in = __( 'This entry was posted in %1$s and tagged %2$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyten' );
+ } elseif ( is_object_in_taxonomy( get_post_type(), 'category' ) ) {
+ $posted_in = __( 'This entry was posted in %1$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyten' );
+ } else {
+ $posted_in = __( 'Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'twentyten' );
+ }
+ // Prints the string, replacing the placeholders.
+ printf(
+ $posted_in,
+ get_the_category_list( ', ' ),
+ $tag_list,
+ get_permalink(),
+ the_title_attribute( 'echo=0' )
+ );
+}
+endif;
+
+/**
+ * Retrieves the IDs for images in a gallery.
+ *
+ * @uses get_post_galleries() first, if available. Falls back to shortcode parsing,
+ * then as last option uses a get_posts() call.
+ *
+ * @since Twenty Ten 1.6.
+ *
+ * @return array List of image IDs from the post gallery.
+ */
+function twentyten_get_gallery_images() {
+ $images = array();
+
+ if ( function_exists( 'get_post_galleries' ) ) {
+ $galleries = get_post_galleries( get_the_ID(), false );
+ if ( isset( $galleries[0]['ids'] ) )
+ $images = explode( ',', $galleries[0]['ids'] );
+ } else {
+ $pattern = get_shortcode_regex();
+ preg_match( "/$pattern/s", get_the_content(), $match );
+ $atts = shortcode_parse_atts( $match[3] );
+ if ( isset( $atts['ids'] ) )
+ $images = explode( ',', $atts['ids'] );
+ }
+
+ if ( ! $images ) {
+ $images = get_posts( array(
+ 'fields' => 'ids',
+ 'numberposts' => 999,
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order',
+ 'post_mime_type' => 'image',
+ 'post_parent' => get_the_ID(),
+ 'post_type' => 'attachment',
+ ) );
+ }
+
+ return $images;
+}
diff --git a/src/wp-content/themes/twentyten/header.php b/src/wp-content/themes/twentyten/header.php
new file mode 100644
index 0000000000..50cb37589d
--- /dev/null
+++ b/src/wp-content/themes/twentyten/header.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * The Header for our theme.
+ *
+ * Displays all of the <head> section and everything up till <div id="main">
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+?><!DOCTYPE html>
+<html <?php language_attributes(); ?>>
+<head>
+<meta charset="<?php bloginfo( 'charset' ); ?>" />
+<title><?php
+ /*
+ * Print the <title> tag based on what is being viewed.
+ */
+ global $page, $paged;
+
+ wp_title( '|', true, 'right' );
+
+ // Add the blog name.
+ bloginfo( 'name' );
+
+ // Add the blog description for the home/front page.
+ $site_description = get_bloginfo( 'description', 'display' );
+ if ( $site_description && ( is_home() || is_front_page() ) )
+ echo " | $site_description";
+
+ // Add a page number if necessary:
+ if ( $paged >= 2 || $page >= 2 )
+ echo ' | ' . sprintf( __( 'Page %s', 'twentyten' ), max( $paged, $page ) );
+
+ ?></title>
+<link rel="profile" href="http://gmpg.org/xfn/11" />
+<link rel="stylesheet" type="text/css" media="all" href="<?php bloginfo( 'stylesheet_url' ); ?>" />
+<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
+<?php
+ /* We add some JavaScript to pages with the comment form
+ * to support sites with threaded comments (when in use).
+ */
+ if ( is_singular() && get_option( 'thread_comments' ) )
+ wp_enqueue_script( 'comment-reply' );
+
+ /* Always have wp_head() just before the closing </head>
+ * tag of your theme, or you will break many plugins, which
+ * generally use this hook to add elements to <head> such
+ * as styles, scripts, and meta tags.
+ */
+ wp_head();
+?>
+</head>
+
+<body <?php body_class(); ?>>
+<div id="wrapper" class="hfeed">
+ <div id="header">
+ <div id="masthead">
+ <div id="branding" role="banner">
+ <?php $heading_tag = ( is_home() || is_front_page() ) ? 'h1' : 'div'; ?>
+ <<?php echo $heading_tag; ?> id="site-title">
+ <span>
+ <a href="<?php echo home_url( '/' ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a>
+ </span>
+ </<?php echo $heading_tag; ?>>
+ <div id="site-description"><?php bloginfo( 'description' ); ?></div>
+
+ <?php
+ // Compatibility with versions of WordPress prior to 3.4.
+ if ( function_exists( 'get_custom_header' ) ) {
+ // We need to figure out what the minimum width should be for our featured image.
+ // This result would be the suggested width if the theme were to implement flexible widths.
+ $header_image_width = get_theme_support( 'custom-header', 'width' );
+ } else {
+ $header_image_width = HEADER_IMAGE_WIDTH;
+ }
+
+ // Check if this is a post or page, if it has a thumbnail, and if it's a big one
+ if ( is_singular() && current_theme_supports( 'post-thumbnails' ) &&
+ has_post_thumbnail( $post->ID ) &&
+ ( /* $src, $width, $height */ $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'post-thumbnail' ) ) &&
+ $image[1] >= $header_image_width ) :
+ // Houston, we have a new header image!
+ echo get_the_post_thumbnail( $post->ID );
+ elseif ( get_header_image() ) :
+ // Compatibility with versions of WordPress prior to 3.4.
+ if ( function_exists( 'get_custom_header' ) ) {
+ $header_image_width = get_custom_header()->width;
+ $header_image_height = get_custom_header()->height;
+ } else {
+ $header_image_width = HEADER_IMAGE_WIDTH;
+ $header_image_height = HEADER_IMAGE_HEIGHT;
+ }
+ ?>
+ <img src="<?php header_image(); ?>" width="<?php echo $header_image_width; ?>" height="<?php echo $header_image_height; ?>" alt="" />
+ <?php endif; ?>
+ </div><!-- #branding -->
+
+ <div id="access" role="navigation">
+ <?php /* Allow screen readers / text browsers to skip the navigation menu and get right to the good stuff */ ?>
+ <div class="skip-link screen-reader-text"><a href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentyten' ); ?>"><?php _e( 'Skip to content', 'twentyten' ); ?></a></div>
+ <?php /* Our navigation menu. If one isn't filled out, wp_nav_menu falls back to wp_page_menu. The menu assiged to the primary position is the one used. If none is assigned, the menu with the lowest ID is used. */ ?>
+ <?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary' ) ); ?>
+ </div><!-- #access -->
+ </div><!-- #masthead -->
+ </div><!-- #header -->
+
+ <div id="main">
diff --git a/src/wp-content/themes/twentyten/images/headers/berries-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/berries-thumbnail.jpg
new file mode 100644
index 0000000000..9588d31b70
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/berries-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/berries.jpg b/src/wp-content/themes/twentyten/images/headers/berries.jpg
new file mode 100644
index 0000000000..b221abc4f6
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/berries.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/cherryblossoms-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/cherryblossoms-thumbnail.jpg
new file mode 100644
index 0000000000..c74744a862
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/cherryblossoms-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/cherryblossoms.jpg b/src/wp-content/themes/twentyten/images/headers/cherryblossoms.jpg
new file mode 100644
index 0000000000..c9fffea3ed
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/cherryblossoms.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/concave-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/concave-thumbnail.jpg
new file mode 100644
index 0000000000..ed24a365cd
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/concave-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/concave.jpg b/src/wp-content/themes/twentyten/images/headers/concave.jpg
new file mode 100644
index 0000000000..0f29e4c550
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/concave.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/fern-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/fern-thumbnail.jpg
new file mode 100644
index 0000000000..1f78bd8a94
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/fern-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/fern.jpg b/src/wp-content/themes/twentyten/images/headers/fern.jpg
new file mode 100644
index 0000000000..bbefc6516f
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/fern.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/forestfloor-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/forestfloor-thumbnail.jpg
new file mode 100644
index 0000000000..2c9eb7e01f
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/forestfloor-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/forestfloor.jpg b/src/wp-content/themes/twentyten/images/headers/forestfloor.jpg
new file mode 100644
index 0000000000..9cf3e60b91
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/forestfloor.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/inkwell-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/inkwell-thumbnail.jpg
new file mode 100644
index 0000000000..3693f0a001
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/inkwell-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/inkwell.jpg b/src/wp-content/themes/twentyten/images/headers/inkwell.jpg
new file mode 100644
index 0000000000..8bd9147122
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/inkwell.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/path-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/path-thumbnail.jpg
new file mode 100644
index 0000000000..c19bba8739
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/path-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/path.jpg b/src/wp-content/themes/twentyten/images/headers/path.jpg
new file mode 100644
index 0000000000..5ebc76a92b
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/path.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/sunset-thumbnail.jpg b/src/wp-content/themes/twentyten/images/headers/sunset-thumbnail.jpg
new file mode 100644
index 0000000000..34e0730c54
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/sunset-thumbnail.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/headers/sunset.jpg b/src/wp-content/themes/twentyten/images/headers/sunset.jpg
new file mode 100644
index 0000000000..98cb24544c
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/headers/sunset.jpg
Binary files differ
diff --git a/src/wp-content/themes/twentyten/images/wordpress.png b/src/wp-content/themes/twentyten/images/wordpress.png
new file mode 100644
index 0000000000..ac9d227805
--- /dev/null
+++ b/src/wp-content/themes/twentyten/images/wordpress.png
Binary files differ
diff --git a/src/wp-content/themes/twentyten/index.php b/src/wp-content/themes/twentyten/index.php
new file mode 100644
index 0000000000..7bc3fd4671
--- /dev/null
+++ b/src/wp-content/themes/twentyten/index.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * The main template file.
+ *
+ * This is the most generic template file in a WordPress theme
+ * and one of the two required files for a theme (the other being style.css).
+ * It is used to display a page when nothing more specific matches a query.
+ * E.g., it puts together the home page when no home.php file exists.
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+ <?php
+ /* Run the loop to output the posts.
+ * If you want to overload this in a child theme then include a file
+ * called loop-index.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'index' );
+ ?>
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/languages/twentyten.pot b/src/wp-content/themes/twentyten/languages/twentyten.pot
new file mode 100644
index 0000000000..1c56f5fbee
--- /dev/null
+++ b/src/wp-content/themes/twentyten/languages/twentyten.pot
@@ -0,0 +1,409 @@
+# Copyright (C) 2013 the WordPress team
+# This file is distributed under the GNU General Public License v2 or later.
+msgid ""
+msgstr ""
+"Project-Id-Version: Twenty Ten 1.6\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tags/twentyten\n"
+"POT-Creation-Date: 2013-08-01 18:14:06+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: 404.php:16 loop.php:33
+msgid "Not Found"
+msgstr ""
+
+#: 404.php:18
+msgid ""
+"Apologies, but the page you requested could not be found. Perhaps searching "
+"will help."
+msgstr ""
+
+#: archive.php:33
+msgid "Daily Archives: <span>%s</span>"
+msgstr ""
+
+#: archive.php:35
+msgid "Monthly Archives: <span>%s</span>"
+msgstr ""
+
+#: archive.php:35
+msgctxt "monthly archives date format"
+msgid "F Y"
+msgstr ""
+
+#: archive.php:37
+msgid "Yearly Archives: <span>%s</span>"
+msgstr ""
+
+#: archive.php:37
+msgctxt "yearly archives date format"
+msgid "Y"
+msgstr ""
+
+#: archive.php:39
+msgid "Blog Archives"
+msgstr ""
+
+#: author.php:27
+msgid "Author Archives: %s"
+msgstr ""
+
+#: author.php:37 loop-single.php:43
+msgid "About %s"
+msgstr ""
+
+#: category.php:16
+msgid "Category Archives: %s"
+msgstr ""
+
+#: comments.php:18
+msgid ""
+"This post is password protected. Enter the password to view any comments."
+msgstr ""
+
+#: comments.php:35
+msgid "One Response to %2$s"
+msgid_plural "%1$s Responses to %2$s"
+msgstr[0] ""
+msgstr[1] ""
+
+#: comments.php:41 comments.php:60
+msgid "<span class=\"meta-nav\">&larr;</span> Older Comments"
+msgstr ""
+
+#: comments.php:42 comments.php:61
+msgid "Newer Comments <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: comments.php:70
+msgid "Comments are closed."
+msgstr ""
+
+#. #-#-#-#-# twentyten.pot (Twenty Ten 1.6) #-#-#-#-#
+#. Author URI of the plugin/theme
+#: footer.php:33
+msgid "http://wordpress.org/"
+msgstr ""
+
+#: footer.php:33
+msgid "Semantic Personal Publishing Platform"
+msgstr ""
+
+#: footer.php:33
+msgid "Proudly powered by %s."
+msgstr ""
+
+#: functions.php:93
+msgid "Primary Navigation"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:145
+msgid "Berries"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:151
+msgid "Cherry Blossoms"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:157
+msgid "Concave"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:163
+msgid "Fern"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:169
+msgid "Forest Floor"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:175
+msgid "Inkwell"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:181
+msgid "Path"
+msgstr ""
+
+#. translators: header image description
+#: functions.php:187
+msgid "Sunset"
+msgstr ""
+
+#: functions.php:255 loop-attachment.php:104 loop.php:114 loop.php:142
+msgid "Continue reading <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: functions.php:338
+msgid "%s <span class=\"says\">says:</span>"
+msgstr ""
+
+#: functions.php:341
+msgid "Your comment is awaiting moderation."
+msgstr ""
+
+#. translators: 1: date, 2: time
+#: functions.php:348
+msgid "%1$s at %2$s"
+msgstr ""
+
+#: functions.php:348 functions.php:365
+msgid "(Edit)"
+msgstr ""
+
+#: functions.php:365
+msgid "Pingback:"
+msgstr ""
+
+#: functions.php:384
+msgid "Primary Widget Area"
+msgstr ""
+
+#: functions.php:386
+msgid "Add widgets here to appear in your sidebar."
+msgstr ""
+
+#: functions.php:395
+msgid "Secondary Widget Area"
+msgstr ""
+
+#: functions.php:397
+msgid ""
+"An optional secondary widget area, displays below the primary widget area in "
+"your sidebar."
+msgstr ""
+
+#: functions.php:406
+msgid "First Footer Widget Area"
+msgstr ""
+
+#: functions.php:408 functions.php:419 functions.php:430 functions.php:441
+msgid "An optional widget area for your site footer."
+msgstr ""
+
+#: functions.php:417
+msgid "Second Footer Widget Area"
+msgstr ""
+
+#: functions.php:428
+msgid "Third Footer Widget Area"
+msgstr ""
+
+#: functions.php:439
+msgid "Fourth Footer Widget Area"
+msgstr ""
+
+#: functions.php:475
+msgid ""
+"<span class=\"%1$s\">Posted on</span> %2$s <span class=\"meta-sep\">by</"
+"span> %3$s"
+msgstr ""
+
+#: functions.php:484 loop-attachment.php:36
+msgid "View all posts by %s"
+msgstr ""
+
+#: functions.php:501
+msgid ""
+"This entry was posted in %1$s and tagged %2$s. Bookmark the <a href=\"%3$s\" "
+"title=\"Permalink to %4$s\" rel=\"bookmark\">permalink</a>."
+msgstr ""
+
+#: functions.php:503
+msgid ""
+"This entry was posted in %1$s. Bookmark the <a href=\"%3$s\" title="
+"\"Permalink to %4$s\" rel=\"bookmark\">permalink</a>."
+msgstr ""
+
+#: functions.php:505
+msgid ""
+"Bookmark the <a href=\"%3$s\" title=\"Permalink to %4$s\" rel=\"bookmark"
+"\">permalink</a>."
+msgstr ""
+
+#: header.php:33
+msgid "Page %s"
+msgstr ""
+
+#: header.php:101
+msgid "Skip to content"
+msgstr ""
+
+#: loop-attachment.php:21
+msgid "Return to %s"
+msgstr ""
+
+#. translators: %s - title of parent post
+#: loop-attachment.php:23
+msgid "<span class=\"meta-nav\">&larr;</span> %s"
+msgstr ""
+
+#: loop-attachment.php:32
+msgid "<span class=\"%1$s\">By</span> %2$s"
+msgstr ""
+
+#: loop-attachment.php:43
+msgid "<span class=\"%1$s\">Published</span> %2$s"
+msgstr ""
+
+#: loop-attachment.php:53
+msgid "Full size is %s pixels"
+msgstr ""
+
+#: loop-attachment.php:56
+msgid "Link to full-size image"
+msgstr ""
+
+#: loop-attachment.php:63 loop-attachment.php:111 loop-page.php:30
+#: loop-single.php:56 loop.php:99 loop.php:122 loop.php:164
+msgid "Edit"
+msgstr ""
+
+#: loop-attachment.php:105 loop-page.php:29 loop-single.php:34 loop.php:143
+msgid "Pages:"
+msgstr ""
+
+#: loop-single.php:21 loop-single.php:61
+msgctxt "Previous post link"
+msgid "&larr;"
+msgstr ""
+
+#: loop-single.php:22 loop-single.php:62
+msgctxt "Next post link"
+msgid "&rarr;"
+msgstr ""
+
+#: loop-single.php:47
+msgid "View all posts by %s <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: loop.php:25 loop.php:177
+msgid "<span class=\"meta-nav\">&larr;</span> Older posts"
+msgstr ""
+
+#: loop.php:26 loop.php:178
+msgid "Newer posts <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: loop.php:35
+msgid ""
+"Apologies, but no results were found for the requested archive. Perhaps "
+"searching will help find a related post."
+msgstr ""
+
+#: loop.php:60 loop.php:94
+msgctxt "gallery category slug"
+msgid "gallery"
+msgstr ""
+
+#: loop.php:81
+msgid "This gallery contains <a %1$s>%2$s photo</a>."
+msgid_plural "This gallery contains <a %1$s>%2$s photos</a>."
+msgstr[0] ""
+msgstr[1] ""
+
+#: loop.php:82
+msgid "Permalink to %s"
+msgstr ""
+
+#: loop.php:92
+msgid "View Galleries"
+msgstr ""
+
+#: loop.php:92 loop.php:95
+msgid "More Galleries"
+msgstr ""
+
+#: loop.php:95
+msgid "View posts in the Gallery category"
+msgstr ""
+
+#: loop.php:98 loop.php:121 loop.php:163
+msgid "Leave a comment"
+msgstr ""
+
+#: loop.php:98 loop.php:121 loop.php:163
+msgid "1 Comment"
+msgstr ""
+
+#: loop.php:98 loop.php:121 loop.php:163
+msgid "% Comments"
+msgstr ""
+
+#: loop.php:105
+msgctxt "asides category slug"
+msgid "asides"
+msgstr ""
+
+#: loop.php:150
+msgid "<span class=\"%1$s\">Posted in</span> %2$s"
+msgstr ""
+
+#: loop.php:159
+msgid "<span class=\"%1$s\">Tagged</span> %2$s"
+msgstr ""
+
+#: search.php:16
+msgid "Search Results for: %s"
+msgstr ""
+
+#: search.php:26
+msgid "Nothing Found"
+msgstr ""
+
+#: search.php:28
+msgid ""
+"Sorry, but nothing matched your search criteria. Please try again with some "
+"different keywords."
+msgstr ""
+
+#: sidebar.php:27
+msgid "Archives"
+msgstr ""
+
+#: sidebar.php:34
+msgid "Meta"
+msgstr ""
+
+#: tag.php:16
+msgid "Tag Archives: %s"
+msgstr ""
+
+#. Theme Name of the plugin/theme
+msgid "Twenty Ten"
+msgstr ""
+
+#. Theme URI of the plugin/theme
+msgid "http://wordpress.org/themes/twentyten"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"The 2010 theme for WordPress is stylish, customizable, simple, and readable "
+"-- make it yours with a custom menu, header image, and background. Twenty "
+"Ten supports six widgetized areas (two in the sidebar, four in the footer) "
+"and featured images (thumbnails for gallery posts and custom header images "
+"for posts and pages). It includes stylesheets for print and the admin Visual "
+"Editor, special styles for posts in the \"Asides\" and \"Gallery\" "
+"categories, and has an optional one-column page template that removes the "
+"sidebar."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "the WordPress team"
+msgstr ""
+
+#. Template Name of the plugin/theme
+msgid "One column, no sidebar"
+msgstr ""
diff --git a/src/wp-content/themes/twentyten/license.txt b/src/wp-content/themes/twentyten/license.txt
new file mode 100644
index 0000000000..5fbe4a70aa
--- /dev/null
+++ b/src/wp-content/themes/twentyten/license.txt
@@ -0,0 +1,281 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/src/wp-content/themes/twentyten/loop-attachment.php b/src/wp-content/themes/twentyten/loop-attachment.php
new file mode 100644
index 0000000000..e775869730
--- /dev/null
+++ b/src/wp-content/themes/twentyten/loop-attachment.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * The loop that displays an attachment.
+ *
+ * The loop displays the posts and the post content. See
+ * http://codex.wordpress.org/The_Loop to understand it and
+ * http://codex.wordpress.org/Template_Tags to understand
+ * the tags used in it.
+ *
+ * This can be overridden in child themes with loop-attachment.php.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.2
+ */
+?>
+
+<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
+
+ <?php if ( ! empty( $post->post_parent ) ) : ?>
+ <p class="page-title"><a href="<?php echo get_permalink( $post->post_parent ); ?>" title="<?php echo esc_attr( sprintf( __( 'Return to %s', 'twentyten' ), strip_tags( get_the_title( $post->post_parent ) ) ) ); ?>" rel="gallery"><?php
+ /* translators: %s - title of parent post */
+ printf( __( '<span class="meta-nav">&larr;</span> %s', 'twentyten' ), get_the_title( $post->post_parent ) );
+ ?></a></p>
+ <?php endif; ?>
+
+ <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <h2 class="entry-title"><?php the_title(); ?></h2>
+
+ <div class="entry-meta">
+ <?php
+ printf( __( '<span class="%1$s">By</span> %2$s', 'twentyten' ),
+ 'meta-prep meta-prep-author',
+ sprintf( '<span class="author vcard"><a class="url fn n" href="%1$s" title="%2$s" rel="author">%3$s</a></span>',
+ get_author_posts_url( get_the_author_meta( 'ID' ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentyten' ), get_the_author() ) ),
+ get_the_author()
+ )
+ );
+ ?>
+ <span class="meta-sep">|</span>
+ <?php
+ printf( __( '<span class="%1$s">Published</span> %2$s', 'twentyten' ),
+ 'meta-prep meta-prep-entry-date',
+ sprintf( '<span class="entry-date"><abbr class="published" title="%1$s">%2$s</abbr></span>',
+ esc_attr( get_the_time() ),
+ get_the_date()
+ )
+ );
+ if ( wp_attachment_is_image() ) {
+ echo ' <span class="meta-sep">|</span> ';
+ $metadata = wp_get_attachment_metadata();
+ printf( __( 'Full size is %s pixels', 'twentyten' ),
+ sprintf( '<a href="%1$s" title="%2$s">%3$s &times; %4$s</a>',
+ wp_get_attachment_url(),
+ esc_attr( __( 'Link to full-size image', 'twentyten' ) ),
+ $metadata['width'],
+ $metadata['height']
+ )
+ );
+ }
+ ?>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), '<span class="meta-sep">|</span> <span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+
+ <div class="entry-content">
+ <div class="entry-attachment">
+<?php if ( wp_attachment_is_image() ) :
+ $attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) );
+ foreach ( $attachments as $k => $attachment ) {
+ if ( $attachment->ID == $post->ID )
+ break;
+ }
+ $k++;
+ // If there is more than 1 image attachment in a gallery
+ if ( count( $attachments ) > 1 ) {
+ if ( isset( $attachments[ $k ] ) )
+ // get the URL of the next image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ $k ]->ID );
+ else
+ // or get the URL of the first image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ 0 ]->ID );
+ } else {
+ // or, if there's only 1 image attachment, get the URL of the image
+ $next_attachment_url = wp_get_attachment_url();
+ }
+?>
+ <p class="attachment"><a href="<?php echo $next_attachment_url; ?>" title="<?php the_title_attribute(); ?>" rel="attachment"><?php
+ $attachment_width = apply_filters( 'twentyten_attachment_size', 900 );
+ $attachment_height = apply_filters( 'twentyten_attachment_height', 900 );
+ echo wp_get_attachment_image( $post->ID, array( $attachment_width, $attachment_height ) ); // filterable image width with, essentially, no limit for image height.
+ ?></a></p>
+
+ <div id="nav-below" class="navigation">
+ <div class="nav-previous"><?php previous_image_link( false ); ?></div>
+ <div class="nav-next"><?php next_image_link( false ); ?></div>
+ </div><!-- #nav-below -->
+<?php else : ?>
+ <a href="<?php echo wp_get_attachment_url(); ?>" title="<?php the_title_attribute(); ?>" rel="attachment"><?php echo basename( get_permalink() ); ?></a>
+<?php endif; ?>
+ </div><!-- .entry-attachment -->
+ <div class="entry-caption"><?php if ( !empty( $post->post_excerpt ) ) the_excerpt(); ?></div>
+
+<?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?>
+<?php wp_link_pages( array( 'before' => '<div class="page-link">' . __( 'Pages:', 'twentyten' ), 'after' => '</div>' ) ); ?>
+
+ </div><!-- .entry-content -->
+
+ <div class="entry-utility">
+ <?php twentyten_posted_in(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), ' <span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-utility -->
+ </div><!-- #post-## -->
+
+<?php comments_template(); ?>
+
+<?php endwhile; // end of the loop. ?>
diff --git a/src/wp-content/themes/twentyten/loop-page.php b/src/wp-content/themes/twentyten/loop-page.php
new file mode 100644
index 0000000000..88c5d74549
--- /dev/null
+++ b/src/wp-content/themes/twentyten/loop-page.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * The loop that displays a page.
+ *
+ * The loop displays the posts and the post content. See
+ * http://codex.wordpress.org/The_Loop to understand it and
+ * http://codex.wordpress.org/Template_Tags to understand
+ * the tags used in it.
+ *
+ * This can be overridden in child themes with loop-page.php.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.2
+ */
+?>
+
+<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
+
+ <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <?php if ( is_front_page() ) { ?>
+ <h2 class="entry-title"><?php the_title(); ?></h2>
+ <?php } else { ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php } ?>
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link">' . __( 'Pages:', 'twentyten' ), 'after' => '</div>' ) ); ?>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-content -->
+ </div><!-- #post-## -->
+
+ <?php comments_template( '', true ); ?>
+
+<?php endwhile; // end of the loop. ?>
diff --git a/src/wp-content/themes/twentyten/loop-single.php b/src/wp-content/themes/twentyten/loop-single.php
new file mode 100644
index 0000000000..1dde4aa3ef
--- /dev/null
+++ b/src/wp-content/themes/twentyten/loop-single.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * The loop that displays a single post.
+ *
+ * The loop displays the posts and the post content. See
+ * http://codex.wordpress.org/The_Loop to understand it and
+ * http://codex.wordpress.org/Template_Tags to understand
+ * the tags used in it.
+ *
+ * This can be overridden in child themes with loop-single.php.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.2
+ */
+?>
+
+<?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
+
+ <div id="nav-above" class="navigation">
+ <div class="nav-previous"><?php previous_post_link( '%link', '<span class="meta-nav">' . _x( '&larr;', 'Previous post link', 'twentyten' ) . '</span> %title' ); ?></div>
+ <div class="nav-next"><?php next_post_link( '%link', '%title <span class="meta-nav">' . _x( '&rarr;', 'Next post link', 'twentyten' ) . '</span>' ); ?></div>
+ </div><!-- #nav-above -->
+
+ <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+
+ <div class="entry-meta">
+ <?php twentyten_posted_on(); ?>
+ </div><!-- .entry-meta -->
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link">' . __( 'Pages:', 'twentyten' ), 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+
+<?php if ( get_the_author_meta( 'description' ) ) : // If a user has filled out their description, show a bio on their entries ?>
+ <div id="entry-author-info">
+ <div id="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentyten_author_bio_avatar_size', 60 ) ); ?>
+ </div><!-- #author-avatar -->
+ <div id="author-description">
+ <h2><?php printf( __( 'About %s', 'twentyten' ), get_the_author() ); ?></h2>
+ <?php the_author_meta( 'description' ); ?>
+ <div id="author-link">
+ <a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) ); ?>" rel="author">
+ <?php printf( __( 'View all posts by %s <span class="meta-nav">&rarr;</span>', 'twentyten' ), get_the_author() ); ?>
+ </a>
+ </div><!-- #author-link -->
+ </div><!-- #author-description -->
+ </div><!-- #entry-author-info -->
+<?php endif; ?>
+
+ <div class="entry-utility">
+ <?php twentyten_posted_in(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-utility -->
+ </div><!-- #post-## -->
+
+ <div id="nav-below" class="navigation">
+ <div class="nav-previous"><?php previous_post_link( '%link', '<span class="meta-nav">' . _x( '&larr;', 'Previous post link', 'twentyten' ) . '</span> %title' ); ?></div>
+ <div class="nav-next"><?php next_post_link( '%link', '%title <span class="meta-nav">' . _x( '&rarr;', 'Next post link', 'twentyten' ) . '</span>' ); ?></div>
+ </div><!-- #nav-below -->
+
+ <?php comments_template( '', true ); ?>
+
+<?php endwhile; // end of the loop. ?>
diff --git a/src/wp-content/themes/twentyten/loop.php b/src/wp-content/themes/twentyten/loop.php
new file mode 100644
index 0000000000..a2d7f2ed13
--- /dev/null
+++ b/src/wp-content/themes/twentyten/loop.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * The loop that displays posts.
+ *
+ * The loop displays the posts and the post content. See
+ * http://codex.wordpress.org/The_Loop to understand it and
+ * http://codex.wordpress.org/Template_Tags to understand
+ * the tags used in it.
+ *
+ * This can be overridden in child themes with loop.php or
+ * loop-template.php, where 'template' is the loop context
+ * requested by a template. For example, loop-index.php would
+ * be used if it exists and we ask for the loop with:
+ * <code>get_template_part( 'loop', 'index' );</code>
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+?>
+
+<?php /* Display navigation to next/previous pages when applicable */ ?>
+<?php if ( $wp_query->max_num_pages > 1 ) : ?>
+ <div id="nav-above" class="navigation">
+ <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentyten' ) ); ?></div>
+ <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>
+ </div><!-- #nav-above -->
+<?php endif; ?>
+
+<?php /* If there are no posts to display, such as an empty archive page */ ?>
+<?php if ( ! have_posts() ) : ?>
+ <div id="post-0" class="post error404 not-found">
+ <h1 class="entry-title"><?php _e( 'Not Found', 'twentyten' ); ?></h1>
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyten' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </div><!-- #post-0 -->
+<?php endif; ?>
+
+<?php
+ /* Start the Loop.
+ *
+ * In Twenty Ten we use the same loop in multiple contexts.
+ * It is broken into three main parts: when we're displaying
+ * posts that are in the gallery category, when we're displaying
+ * posts in the asides category, and finally all other posts.
+ *
+ * Additionally, we sometimes check for whether we are on an
+ * archive page, a search page, etc., allowing for small differences
+ * in the loop on each template without actually duplicating
+ * the rest of the loop that is shared.
+ *
+ * Without further ado, the loop:
+ */ ?>
+<?php while ( have_posts() ) : the_post(); ?>
+
+<?php /* How to display posts of the Gallery format. The gallery category is the old way. */ ?>
+
+ <?php if ( ( function_exists( 'get_post_format' ) && 'gallery' == get_post_format( $post->ID ) ) || in_category( _x( 'gallery', 'gallery category slug', 'twentyten' ) ) ) : ?>
+ <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+
+ <div class="entry-meta">
+ <?php twentyten_posted_on(); ?>
+ </div><!-- .entry-meta -->
+
+ <div class="entry-content">
+<?php if ( post_password_required() ) : ?>
+ <?php the_content(); ?>
+<?php else : ?>
+ <?php
+ $images = twentyten_get_gallery_images();
+ if ( $images ) :
+ $total_images = count( $images );
+ $image = array_shift( $images );
+ ?>
+ <div class="gallery-thumb">
+ <a class="size-thumbnail" href="<?php the_permalink(); ?>"><?php echo wp_get_attachment_image( $image, 'thumbnail' ); ?></a>
+ </div><!-- .gallery-thumb -->
+ <p><em><?php printf( _n( 'This gallery contains <a %1$s>%2$s photo</a>.', 'This gallery contains <a %1$s>%2$s photos</a>.', $total_images, 'twentyten' ),
+ 'href="' . get_permalink() . '" title="' . esc_attr( sprintf( __( 'Permalink to %s', 'twentyten' ), the_title_attribute( 'echo=0' ) ) ) . '" rel="bookmark"',
+ number_format_i18n( $total_images )
+ ); ?></em></p>
+ <?php endif; // end twentyten_get_gallery_images() check ?>
+ <?php the_excerpt(); ?>
+<?php endif; ?>
+ </div><!-- .entry-content -->
+
+ <div class="entry-utility">
+ <?php if ( function_exists( 'get_post_format' ) && 'gallery' == get_post_format( $post->ID ) ) : ?>
+ <a href="<?php echo get_post_format_link( 'gallery' ); ?>" title="<?php esc_attr_e( 'View Galleries', 'twentyten' ); ?>"><?php _e( 'More Galleries', 'twentyten' ); ?></a>
+ <span class="meta-sep">|</span>
+ <?php elseif ( $gallery = get_term_by( 'slug', _x( 'gallery', 'gallery category slug', 'twentyten' ), 'category' ) && in_category( $gallery->term_id ) ) : ?>
+ <a href="<?php echo get_category_link( $gallery ); ?>" title="<?php esc_attr_e( 'View posts in the Gallery category', 'twentyten' ); ?>"><?php _e( 'More Galleries', 'twentyten' ); ?></a>
+ <span class="meta-sep">|</span>
+ <?php endif; ?>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyten' ), __( '1 Comment', 'twentyten' ), __( '% Comments', 'twentyten' ) ); ?></span>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), '<span class="meta-sep">|</span> <span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-utility -->
+ </div><!-- #post-## -->
+
+<?php /* How to display posts of the Aside format. The asides category is the old way. */ ?>
+
+ <?php elseif ( ( function_exists( 'get_post_format' ) && 'aside' == get_post_format( $post->ID ) ) || in_category( _x( 'asides', 'asides category slug', 'twentyten' ) ) ) : ?>
+ <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+
+ <?php if ( is_archive() || is_search() ) : // Display excerpts for archives and search. ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <div class="entry-utility">
+ <?php twentyten_posted_on(); ?>
+ <span class="meta-sep">|</span>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyten' ), __( '1 Comment', 'twentyten' ), __( '% Comments', 'twentyten' ) ); ?></span>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), '<span class="meta-sep">|</span> <span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-utility -->
+ </div><!-- #post-## -->
+
+<?php /* How to display all other posts. */ ?>
+
+ <?php else : ?>
+ <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <h2 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
+
+ <div class="entry-meta">
+ <?php twentyten_posted_on(); ?>
+ </div><!-- .entry-meta -->
+
+ <?php if ( is_archive() || is_search() ) : // Only display excerpts for archives and search. ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-link">' . __( 'Pages:', 'twentyten' ), 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <div class="entry-utility">
+ <?php if ( count( get_the_category() ) ) : ?>
+ <span class="cat-links">
+ <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'twentyten' ), 'entry-utility-prep entry-utility-prep-cat-links', get_the_category_list( ', ' ) ); ?>
+ </span>
+ <span class="meta-sep">|</span>
+ <?php endif; ?>
+ <?php
+ $tags_list = get_the_tag_list( '', ', ' );
+ if ( $tags_list ):
+ ?>
+ <span class="tag-links">
+ <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'twentyten' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list ); ?>
+ </span>
+ <span class="meta-sep">|</span>
+ <?php endif; ?>
+ <span class="comments-link"><?php comments_popup_link( __( 'Leave a comment', 'twentyten' ), __( '1 Comment', 'twentyten' ), __( '% Comments', 'twentyten' ) ); ?></span>
+ <?php edit_post_link( __( 'Edit', 'twentyten' ), '<span class="meta-sep">|</span> <span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-utility -->
+ </div><!-- #post-## -->
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endif; // This was the if statement that broke the loop into three parts based on categories. ?>
+
+<?php endwhile; // End the loop. Whew. ?>
+
+<?php /* Display navigation to next/previous pages when applicable */ ?>
+<?php if ( $wp_query->max_num_pages > 1 ) : ?>
+ <div id="nav-below" class="navigation">
+ <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentyten' ) ); ?></div>
+ <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentyten' ) ); ?></div>
+ </div><!-- #nav-below -->
+<?php endif; ?>
diff --git a/src/wp-content/themes/twentyten/onecolumn-page.php b/src/wp-content/themes/twentyten/onecolumn-page.php
new file mode 100644
index 0000000000..1a8d5b7e27
--- /dev/null
+++ b/src/wp-content/themes/twentyten/onecolumn-page.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Template Name: One column, no sidebar
+ *
+ * A custom page template without sidebar.
+ *
+ * The "Template Name:" bit above allows this to be selectable
+ * from a dropdown menu on the edit page screen.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container" class="one-column">
+ <div id="content" role="main">
+
+ <?php
+ /* Run the loop to output the page.
+ * If you want to overload this in a child theme then include a file
+ * called loop-page.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'page' );
+ ?>
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/page.php b/src/wp-content/themes/twentyten/page.php
new file mode 100644
index 0000000000..1a5504236f
--- /dev/null
+++ b/src/wp-content/themes/twentyten/page.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * The template for displaying all pages.
+ *
+ * This is the template that displays all pages by default.
+ * Please note that this is the WordPress construct of pages
+ * and that other 'pages' on your WordPress site will use a
+ * different template.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+ <?php
+ /* Run the loop to output the page.
+ * If you want to overload this in a child theme then include a file
+ * called loop-page.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'page' );
+ ?>
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/rtl.css b/src/wp-content/themes/twentyten/rtl.css
new file mode 100644
index 0000000000..93a7605017
--- /dev/null
+++ b/src/wp-content/themes/twentyten/rtl.css
@@ -0,0 +1,285 @@
+/*
+Theme Name: Twenty Ten
+*/
+
+
+/*
+RTL Basics
+*/
+
+
+body {
+ direction:rtl;
+ unicode-bidi:embed;
+}
+
+
+/*
+LAYOUT: Two-Column (Right)
+DESCRIPTION: Two-column fixed layout with one sidebar right of content
+*/
+
+#container {
+ float: right;
+ margin: 0 0 0 -240px;
+}
+#content {
+ margin: 0 20px 36px 280px;
+}
+#primary,
+#secondary {
+ float: left;
+}
+#secondary {
+ clear: left;
+}
+
+
+/* =Fonts
+-------------------------------------------------------------- */
+body,
+input,
+textarea,
+.page-title span,
+.pingback a.url,
+h3#comments-title,
+h3#reply-title,
+#access .menu,
+#access div.menu ul,
+#cancel-comment-reply-link,
+.form-allowed-tags,
+#site-info,
+#site-title,
+#wp-calendar,
+.comment-meta,
+.comment-body tr th,
+.comment-body thead th,
+.entry-content label,
+.entry-content tr th,
+.entry-content thead th,
+.entry-meta,
+.entry-title,
+.entry-utility,
+#respond label,
+.navigation,
+.page-title,
+.pingback p,
+.reply,
+.widget-title,
+input[type="submit"] {
+ font-family: Arial, Tahoma, sans-serif;
+}
+
+/* =Structure
+-------------------------------------------------------------- */
+
+/* The main theme structure */
+#footer-widget-area .widget-area {
+ float: right;
+ margin-left: 20px;
+ margin-right: 0;
+}
+#footer-widget-area #fourth {
+ margin-left: 0;
+}
+#site-info {
+ float: right;
+}
+#site-generator {
+ float: left;
+}
+
+
+/* =Global Elements
+-------------------------------------------------------------- */
+
+/* Text elements */
+ul, ol {
+ margin: 0 1.5em 18px 0;
+}
+blockquote {
+ font-style: normal;
+}
+
+/* Text meant only for screen readers */
+.screen-reader-text {
+ left: auto;
+ text-indent:-9000px;
+ overflow:hidden;
+}
+
+
+/* =Header
+-------------------------------------------------------------- */
+
+#site-title {
+ float: right;
+}
+#site-description {
+ clear: left;
+ float: left;
+ font-style: normal;
+}
+#branding img {
+ float: right;
+}
+
+/* =Menu
+-------------------------------------------------------------- */
+
+#access {
+ float:right;
+}
+
+#access .menu-header,
+div.menu {
+ margin-right: 12px;
+ margin-left: 0;
+}
+
+#access .menu-header li,
+div.menu li{
+ float:right;
+}
+
+#access ul ul {
+ left:auto;
+ right:0;
+ float:right;
+}
+#access ul ul ul {
+ left:auto;
+ right:100%;
+}
+
+/* =Content
+-------------------------------------------------------------- */
+
+#content table {
+ text-align: right;
+ margin: 0 0 24px -1px;
+}
+.page-title span {
+ font-style:normal;
+}
+.entry-title,
+.entry-meta {
+ clear: right;
+ float: right;
+ margin-left: 68px;
+ margin-right: 0;
+}
+
+.entry-content input.file,
+.entry-content input.button {
+ margin-left: 24px;
+ margin-right:0;
+}
+.entry-content blockquote.left {
+ float: right;
+ margin-right: 0;
+ margin-left: 24px;
+ text-align: left;
+}
+.entry-content blockquote.right {
+ float: left;
+ margin-right: 24px;
+ margin-left: 0;
+ text-align: right;
+}
+#entry-author-info #author-avatar {
+ float: right;
+ margin: 0 0 0 -104px;
+}
+#entry-author-info #author-description {
+ float: right;
+ margin: 0 104px 0 0;
+}
+
+/* Gallery listing
+-------------------------------------------------------------- */
+
+.category-gallery .gallery-thumb {
+ float: right;
+ margin-left:20px;
+ margin-right:0;
+}
+
+
+/* Images
+-------------------------------------------------------------- */
+
+#content .gallery .gallery-caption {
+ margin-right: 0;
+}
+
+#content .gallery .gallery-item {
+ float: right;
+}
+
+/* =Navigation
+-------------------------------------------------------------- */
+.nav-previous {
+ float: right;
+}
+.nav-next {
+ float: left;
+ text-align:left;
+}
+
+/* =Comments
+-------------------------------------------------------------- */
+
+.commentlist li.comment {
+ padding: 0 56px 0 0;
+}
+.commentlist .avatar {
+ right: 0;
+ left: auto;
+}
+.comment-author .says, #comments .pingback .url {
+ font-style: normal;
+}
+
+/* Comments form */
+.children #respond {
+ margin: 0 0 0 48px;
+}
+
+/* =Widget Areas
+-------------------------------------------------------------- */
+
+.widget-area ul {
+ margin-right: 0;
+}
+.widget-area ul ul {
+ margin-right: 1.3em;
+ margin-left: 0;
+}
+#wp-calendar caption {
+ text-align: right;
+}
+#wp-calendar tfoot #next {
+ text-align: left;
+}
+
+/* Main sidebars */
+#main .widget-area ul {
+ margin-right: 0;
+ padding: 0 0 0 20px;
+}
+#main .widget-area ul ul {
+ margin-right: 1.3em;
+ margin-left: 0;
+}
+
+/* =Footer
+-------------------------------------------------------------- */
+#site-generator {
+ font-style:normal;
+}
+#site-generator a {
+ background-position: right center;
+ padding-right: 20px;
+ padding-left: 0;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyten/screenshot.png b/src/wp-content/themes/twentyten/screenshot.png
new file mode 100644
index 0000000000..6f01d9451a
--- /dev/null
+++ b/src/wp-content/themes/twentyten/screenshot.png
Binary files differ
diff --git a/src/wp-content/themes/twentyten/search.php b/src/wp-content/themes/twentyten/search.php
new file mode 100644
index 0000000000..3b198bb203
--- /dev/null
+++ b/src/wp-content/themes/twentyten/search.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * The template for displaying Search Results pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+<?php if ( have_posts() ) : ?>
+ <h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentyten' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
+ <?php
+ /* Run the loop for the search to output the results.
+ * If you want to overload this in a child theme then include a file
+ * called loop-search.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'search' );
+ ?>
+<?php else : ?>
+ <div id="post-0" class="post no-results not-found">
+ <h2 class="entry-title"><?php _e( 'Nothing Found', 'twentyten' ); ?></h2>
+ <div class="entry-content">
+ <p><?php _e( 'Sorry, but nothing matched your search criteria. Please try again with some different keywords.', 'twentyten' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </div><!-- #post-0 -->
+<?php endif; ?>
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/sidebar-footer.php b/src/wp-content/themes/twentyten/sidebar-footer.php
new file mode 100644
index 0000000000..0e9f702357
--- /dev/null
+++ b/src/wp-content/themes/twentyten/sidebar-footer.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * The Footer widget areas.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+?>
+
+<?php
+ /* The footer widget area is triggered if any of the areas
+ * have widgets. So let's check that first.
+ *
+ * If none of the sidebars have widgets, then let's bail early.
+ */
+ if ( ! is_active_sidebar( 'first-footer-widget-area' )
+ && ! is_active_sidebar( 'second-footer-widget-area' )
+ && ! is_active_sidebar( 'third-footer-widget-area' )
+ && ! is_active_sidebar( 'fourth-footer-widget-area' )
+ )
+ return;
+ // If we get this far, we have widgets. Let do this.
+?>
+
+ <div id="footer-widget-area" role="complementary">
+
+<?php if ( is_active_sidebar( 'first-footer-widget-area' ) ) : ?>
+ <div id="first" class="widget-area">
+ <ul class="xoxo">
+ <?php dynamic_sidebar( 'first-footer-widget-area' ); ?>
+ </ul>
+ </div><!-- #first .widget-area -->
+<?php endif; ?>
+
+<?php if ( is_active_sidebar( 'second-footer-widget-area' ) ) : ?>
+ <div id="second" class="widget-area">
+ <ul class="xoxo">
+ <?php dynamic_sidebar( 'second-footer-widget-area' ); ?>
+ </ul>
+ </div><!-- #second .widget-area -->
+<?php endif; ?>
+
+<?php if ( is_active_sidebar( 'third-footer-widget-area' ) ) : ?>
+ <div id="third" class="widget-area">
+ <ul class="xoxo">
+ <?php dynamic_sidebar( 'third-footer-widget-area' ); ?>
+ </ul>
+ </div><!-- #third .widget-area -->
+<?php endif; ?>
+
+<?php if ( is_active_sidebar( 'fourth-footer-widget-area' ) ) : ?>
+ <div id="fourth" class="widget-area">
+ <ul class="xoxo">
+ <?php dynamic_sidebar( 'fourth-footer-widget-area' ); ?>
+ </ul>
+ </div><!-- #fourth .widget-area -->
+<?php endif; ?>
+
+ </div><!-- #footer-widget-area -->
diff --git a/src/wp-content/themes/twentyten/sidebar.php b/src/wp-content/themes/twentyten/sidebar.php
new file mode 100644
index 0000000000..8a1664f329
--- /dev/null
+++ b/src/wp-content/themes/twentyten/sidebar.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * The Sidebar containing the primary and secondary widget areas.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+?>
+
+ <div id="primary" class="widget-area" role="complementary">
+ <ul class="xoxo">
+
+<?php
+ /* When we call the dynamic_sidebar() function, it'll spit out
+ * the widgets for that widget area. If it instead returns false,
+ * then the sidebar simply doesn't exist, so we'll hard-code in
+ * some default sidebar stuff just in case.
+ */
+ if ( ! dynamic_sidebar( 'primary-widget-area' ) ) : ?>
+
+ <li id="search" class="widget-container widget_search">
+ <?php get_search_form(); ?>
+ </li>
+
+ <li id="archives" class="widget-container">
+ <h3 class="widget-title"><?php _e( 'Archives', 'twentyten' ); ?></h3>
+ <ul>
+ <?php wp_get_archives( 'type=monthly' ); ?>
+ </ul>
+ </li>
+
+ <li id="meta" class="widget-container">
+ <h3 class="widget-title"><?php _e( 'Meta', 'twentyten' ); ?></h3>
+ <ul>
+ <?php wp_register(); ?>
+ <li><?php wp_loginout(); ?></li>
+ <?php wp_meta(); ?>
+ </ul>
+ </li>
+
+ <?php endif; // end primary widget area ?>
+ </ul>
+ </div><!-- #primary .widget-area -->
+
+<?php
+ // A second sidebar for widgets, just because.
+ if ( is_active_sidebar( 'secondary-widget-area' ) ) : ?>
+
+ <div id="secondary" class="widget-area" role="complementary">
+ <ul class="xoxo">
+ <?php dynamic_sidebar( 'secondary-widget-area' ); ?>
+ </ul>
+ </div><!-- #secondary .widget-area -->
+
+<?php endif; ?>
diff --git a/src/wp-content/themes/twentyten/single.php b/src/wp-content/themes/twentyten/single.php
new file mode 100644
index 0000000000..a0dea11fb1
--- /dev/null
+++ b/src/wp-content/themes/twentyten/single.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * The Template for displaying all single posts.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+ <?php
+ /* Run the loop to output the post.
+ * If you want to overload this in a child theme then include a file
+ * called loop-single.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'single' );
+ ?>
+
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentyten/style.css b/src/wp-content/themes/twentyten/style.css
new file mode 100644
index 0000000000..5016922d9a
--- /dev/null
+++ b/src/wp-content/themes/twentyten/style.css
@@ -0,0 +1,1378 @@
+/*
+Theme Name: Twenty Ten
+Theme URI: http://wordpress.org/themes/twentyten
+Description: The 2010 theme for WordPress is stylish, customizable, simple, and readable -- make it yours with a custom menu, header image, and background. Twenty Ten supports six widgetized areas (two in the sidebar, four in the footer) and featured images (thumbnails for gallery posts and custom header images for posts and pages). It includes stylesheets for print and the admin Visual Editor, special styles for posts in the "Asides" and "Gallery" categories, and has an optional one-column page template that removes the sidebar.
+Author: the WordPress team
+Author URI: http://wordpress.org/
+Version: 1.6
+License: GNU General Public License v2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+Tags: black, blue, white, two-columns, fixed-width, custom-header, custom-background, threaded-comments, sticky-post, translation-ready, microformats, rtl-language-support, editor-style, custom-menu, flexible-header
+Text Domain: twentyten
+*/
+
+
+/* =Reset default browser CSS. Based on work by Eric Meyer: http://meyerweb.com/eric/tools/css/reset/index.html
+-------------------------------------------------------------- */
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, font, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td {
+ background: transparent;
+ border: 0;
+ margin: 0;
+ padding: 0;
+ vertical-align: baseline;
+}
+body {
+ line-height: 1;
+}
+h1, h2, h3, h4, h5, h6 {
+ clear: both;
+ font-weight: normal;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote {
+ quotes: none;
+}
+blockquote:before, blockquote:after {
+ content: '';
+ content: none;
+}
+del {
+ text-decoration: line-through;
+}
+/* tables still need 'cellspacing="0"' in the markup */
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+a img {
+ border: none;
+}
+
+/* =Layout
+-------------------------------------------------------------- */
+
+/*
+LAYOUT: Two columns
+DESCRIPTION: Two-column fixed layout with one sidebar right of content
+*/
+
+#container {
+ float: left;
+ margin: 0 -240px 0 0;
+ width: 100%;
+}
+#content {
+ margin: 0 280px 0 20px;
+}
+#primary,
+#secondary {
+ float: right;
+ overflow: hidden;
+ width: 220px;
+}
+#secondary {
+ clear: right;
+}
+#footer {
+ clear: both;
+ width: 100%;
+}
+
+/*
+LAYOUT: One column, no sidebar
+DESCRIPTION: One centered column with no sidebar
+*/
+
+.one-column #content {
+ margin: 0 auto;
+ width: 640px;
+}
+
+/*
+LAYOUT: Full width, no sidebar
+DESCRIPTION: Full width content with no sidebar; used for attachment pages
+*/
+
+.single-attachment #content {
+ margin: 0 auto;
+ width: 900px;
+}
+
+
+/* =Fonts
+-------------------------------------------------------------- */
+body,
+input,
+textarea,
+.page-title span,
+.pingback a.url {
+ font-family: Georgia, "Bitstream Charter", serif;
+}
+h3#comments-title,
+h3#reply-title,
+#access .menu,
+#access div.menu ul,
+#cancel-comment-reply-link,
+.form-allowed-tags,
+#site-info,
+#site-title,
+#wp-calendar,
+.comment-meta,
+.comment-body tr th,
+.comment-body thead th,
+.entry-content label,
+.entry-content tr th,
+.entry-content thead th,
+.entry-meta,
+.entry-title,
+.entry-utility,
+#respond label,
+.navigation,
+.page-title,
+.pingback p,
+.reply,
+.widget-title,
+.wp-caption-text {
+ font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif;
+}
+input[type="submit"] {
+ font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif;
+}
+pre {
+ font-family: "Courier 10 Pitch", Courier, monospace;
+}
+code {
+ font-family: Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace;
+}
+
+
+/* =Structure
+-------------------------------------------------------------- */
+
+/* The main theme structure */
+#access .menu-header,
+div.menu,
+#colophon,
+#branding,
+#main,
+#wrapper {
+ margin: 0 auto;
+ width: 940px;
+}
+#wrapper {
+ background: #fff;
+ margin-top: 20px;
+ padding: 0 20px;
+}
+
+/* Structure the footer area */
+#footer-widget-area {
+ overflow: hidden;
+}
+#footer-widget-area .widget-area {
+ float: left;
+ margin-right: 20px;
+ width: 220px;
+}
+#footer-widget-area #fourth {
+ margin-right: 0;
+}
+#site-info {
+ float: left;
+ font-size: 14px;
+ font-weight: bold;
+ width: 700px;
+}
+#site-generator {
+ float: right;
+ width: 220px;
+}
+
+
+/* =Global Elements
+-------------------------------------------------------------- */
+
+/* Main global 'theme' and typographic styles */
+body {
+ background: #f1f1f1;
+}
+body,
+input,
+textarea {
+ color: #666;
+ font-size: 12px;
+ line-height: 18px;
+}
+hr {
+ background-color: #e7e7e7;
+ border: 0;
+ clear: both;
+ height: 1px;
+ margin-bottom: 18px;
+}
+
+/* Text elements */
+p {
+ margin-bottom: 18px;
+}
+ul {
+ list-style: square;
+ margin: 0 0 18px 1.5em;
+}
+ol {
+ list-style: decimal;
+ margin: 0 0 18px 1.5em;
+}
+ol ol {
+ list-style: upper-alpha;
+}
+ol ol ol {
+ list-style: lower-roman;
+}
+ol ol ol ol {
+ list-style: lower-alpha;
+}
+ul ul,
+ol ol,
+ul ol,
+ol ul {
+ margin-bottom: 0;
+}
+dl {
+ margin: 0 0 24px 0;
+}
+dt {
+ font-weight: bold;
+}
+dd {
+ margin-bottom: 18px;
+}
+strong {
+ font-weight: bold;
+}
+cite,
+em,
+i {
+ font-style: italic;
+}
+big {
+ font-size: 131.25%;
+}
+ins {
+ background: #ffc;
+ text-decoration: none;
+}
+blockquote {
+ font-style: italic;
+ padding: 0 3em;
+}
+blockquote cite,
+blockquote em,
+blockquote i {
+ font-style: normal;
+}
+pre {
+ background: #f7f7f7;
+ color: #222;
+ line-height: 18px;
+ margin-bottom: 18px;
+ overflow: auto;
+ padding: 1.5em;
+}
+abbr,
+acronym {
+ border-bottom: 1px dotted #666;
+ cursor: help;
+}
+sup,
+sub {
+ height: 0;
+ line-height: 1;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ bottom: 1ex;
+}
+sub {
+ top: .5ex;
+}
+small {
+ font-size: smaller;
+}
+input[type="text"],
+input[type="password"],
+input[type="email"],
+input[type="url"],
+input[type="number"],
+textarea {
+ background: #f9f9f9;
+ border: 1px solid #ccc;
+ box-shadow: inset 1px 1px 1px rgba(0,0,0,0.1);
+ -moz-box-shadow: inset 1px 1px 1px rgba(0,0,0,0.1);
+ -webkit-box-shadow: inset 1px 1px 1px rgba(0,0,0,0.1);
+ padding: 2px;
+}
+a:link {
+ color: #0066cc;
+}
+a:visited {
+ color: #743399;
+}
+a:active,
+a:hover {
+ color: #ff4b33;
+}
+
+/* Text meant only for screen readers */
+.screen-reader-text {
+ position: absolute;
+ left: -9000px;
+}
+
+
+/* =Header
+-------------------------------------------------------------- */
+
+#header {
+ padding: 30px 0 0 0;
+}
+#site-title {
+ float: left;
+ font-size: 30px;
+ line-height: 36px;
+ margin: 0 0 18px 0;
+ width: 700px;
+}
+#site-title a {
+ color: #000;
+ font-weight: bold;
+ text-decoration: none;
+}
+#site-description {
+ clear: right;
+ float: right;
+ font-style: italic;
+ margin: 15px 0 18px 0;
+ width: 220px;
+}
+
+/* This is the custom header image */
+#branding img {
+ border-top: 4px solid #000;
+ border-bottom: 1px solid #000;
+ display: block;
+ float: left;
+}
+
+
+/* =Menu
+-------------------------------------------------------------- */
+
+#access {
+ background: #000;
+ display: block;
+ float: left;
+ margin: 0 auto;
+ width: 940px;
+}
+#access .menu-header,
+div.menu {
+ font-size: 13px;
+ margin-left: 12px;
+ width: 928px;
+}
+#access .menu-header ul,
+div.menu ul {
+ list-style: none;
+ margin: 0;
+}
+#access .menu-header li,
+div.menu li {
+ float: left;
+ position: relative;
+}
+#access a {
+ color: #aaa;
+ display: block;
+ line-height: 38px;
+ padding: 0 10px;
+ text-decoration: none;
+}
+#access ul ul {
+ box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
+ -moz-box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
+ -webkit-box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
+ display: none;
+ position: absolute;
+ top: 38px;
+ left: 0;
+ float: left;
+ width: 180px;
+ z-index: 99999;
+}
+#access ul ul li {
+ min-width: 180px;
+}
+#access ul ul ul {
+ left: 100%;
+ top: 0;
+}
+#access ul ul a {
+ background: #333;
+ line-height: 1em;
+ padding: 10px;
+ width: 160px;
+ height: auto;
+}
+#access li:hover > a,
+#access ul ul :hover > a {
+ background: #333;
+ color: #fff;
+}
+#access ul li:hover > ul {
+ display: block;
+}
+#access ul li.current_page_item > a,
+#access ul li.current_page_ancestor > a,
+#access ul li.current-menu-ancestor > a,
+#access ul li.current-menu-item > a,
+#access ul li.current-menu-parent > a {
+ color: #fff;
+}
+* html #access ul li.current_page_item a,
+* html #access ul li.current_page_ancestor a,
+* html #access ul li.current-menu-ancestor a,
+* html #access ul li.current-menu-item a,
+* html #access ul li.current-menu-parent a,
+* html #access ul li a:hover {
+ color: #fff;
+}
+
+
+/* =Content
+-------------------------------------------------------------- */
+
+#main {
+ clear: both;
+ overflow: hidden;
+ padding: 40px 0 0 0;
+}
+#content {
+ margin-bottom: 36px;
+}
+#content,
+#content input,
+#content textarea {
+ color: #333;
+ font-size: 16px;
+ line-height: 24px;
+}
+#content p,
+#content ul,
+#content ol,
+#content dd,
+#content pre,
+#content hr {
+ margin-bottom: 24px;
+}
+#content ul ul,
+#content ol ol,
+#content ul ol,
+#content ol ul {
+ margin-bottom: 0;
+}
+#content pre,
+#content kbd,
+#content tt,
+#content var {
+ font-size: 15px;
+ line-height: 21px;
+}
+#content code {
+ font-size: 13px;
+}
+#content dt,
+#content th {
+ color: #000;
+}
+#content h1,
+#content h2,
+#content h3,
+#content h4,
+#content h5,
+#content h6 {
+ color: #000;
+ line-height: 1.5em;
+ margin: 0 0 20px 0;
+}
+#content table {
+ border: 1px solid #e7e7e7;
+ margin: 0 -1px 24px 0;
+ text-align: left;
+ width: 100%;
+}
+#content tr th,
+#content thead th {
+ color: #777;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 18px;
+ padding: 9px 24px;
+}
+#content tr td {
+ border-top: 1px solid #e7e7e7;
+ padding: 6px 24px;
+}
+#content tr.odd td {
+ background: #f2f7fc;
+}
+.hentry {
+ margin: 0 0 48px 0;
+}
+.home .sticky {
+ background: #f2f7fc;
+ border-top: 4px solid #000;
+ margin-left: -20px;
+ margin-right: -20px;
+ padding: 18px 20px;
+}
+.single .hentry {
+ margin: 0 0 36px 0;
+}
+.page-title {
+ color: #000;
+ font-size: 14px;
+ font-weight: bold;
+ margin: 0 0 36px 0;
+}
+.page-title span {
+ color: #333;
+ font-size: 16px;
+ font-style: italic;
+ font-weight: normal;
+}
+.page-title a:link,
+.page-title a:visited {
+ color: #777;
+ text-decoration: none;
+}
+.page-title a:active,
+.page-title a:hover {
+ color: #ff4b33;
+}
+#content .entry-title {
+ color: #000;
+ font-size: 21px;
+ font-weight: bold;
+ line-height: 1.3em;
+ margin-bottom: 0;
+}
+.entry-title a:link,
+.entry-title a:visited {
+ color: #000;
+ text-decoration: none;
+}
+.entry-title a:active,
+.entry-title a:hover {
+ color: #ff4b33;
+}
+.entry-meta {
+ color: #777;
+ font-size: 12px;
+}
+.entry-meta abbr,
+.entry-utility abbr {
+ border: none;
+}
+.entry-meta abbr:hover,
+.entry-utility abbr:hover {
+ border-bottom: 1px dotted #666;
+}
+.entry-content,
+.entry-summary {
+ clear: both;
+ padding: 12px 0 0 0;
+}
+#content .entry-summary p:last-child {
+ margin-bottom: 12px;
+}
+.entry-content fieldset {
+ border: 1px solid #e7e7e7;
+ margin: 0 0 24px 0;
+ padding: 24px;
+}
+.entry-content fieldset legend {
+ background: #fff;
+ color: #000;
+ font-weight: bold;
+ padding: 0 24px;
+}
+.entry-content input {
+ margin: 0 0 24px 0;
+}
+.entry-content input.file,
+.entry-content input.button {
+ margin-right: 24px;
+}
+.entry-content label {
+ color: #777;
+ font-size: 12px;
+}
+.entry-content select {
+ margin: 0 0 24px 0;
+}
+.entry-content sup,
+.entry-content sub {
+ font-size: 10px;
+}
+.entry-content blockquote.left {
+ float: left;
+ margin-left: 0;
+ margin-right: 24px;
+ text-align: right;
+ width: 33%;
+}
+.entry-content blockquote.right {
+ float: right;
+ margin-left: 24px;
+ margin-right: 0;
+ text-align: left;
+ width: 33%;
+}
+.page-link {
+ clear: both;
+ color: #000;
+ font-weight: bold;
+ line-height: 48px;
+ word-spacing: 0.5em;
+}
+.page-link a:link,
+.page-link a:visited {
+ background: #f1f1f1;
+ color: #333;
+ font-weight: normal;
+ padding: 0.5em 0.75em;
+ text-decoration: none;
+}
+.home .sticky .page-link a {
+ background: #d9e8f7;
+}
+.page-link a:active,
+.page-link a:hover {
+ color: #ff4b33;
+}
+body.page .edit-link {
+ clear: both;
+ display: block;
+}
+#entry-author-info {
+ background: #f2f7fc;
+ border-top: 4px solid #000;
+ clear: both;
+ font-size: 14px;
+ line-height: 20px;
+ margin: 24px 0;
+ overflow: hidden;
+ padding: 18px 20px;
+}
+#entry-author-info #author-avatar {
+ background: #fff;
+ border: 1px solid #e7e7e7;
+ float: left;
+ height: 60px;
+ margin: 0 -104px 0 0;
+ padding: 11px;
+}
+#entry-author-info #author-description {
+ float: left;
+ margin: 0 0 0 104px;
+}
+#entry-author-info h2 {
+ color: #000;
+ font-size: 100%;
+ font-weight: bold;
+ margin-bottom: 0;
+}
+.entry-utility {
+ clear: both;
+ color: #777;
+ font-size: 12px;
+ line-height: 18px;
+}
+.entry-meta a,
+.entry-utility a {
+ color: #777;
+}
+.entry-meta a:hover,
+.entry-utility a:hover {
+ color: #ff4b33;
+}
+#content .video-player {
+ padding: 0;
+}
+
+
+/* =Asides
+-------------------------------------------------------------- */
+
+.home #content .format-aside p,
+.home #content .category-asides p {
+ font-size: 14px;
+ line-height: 20px;
+ margin-bottom: 10px;
+ margin-top: 0;
+}
+.home .hentry.format-aside,
+.home .hentry.category-asides {
+ padding: 0;
+}
+.home #content .format-aside .entry-content,
+.home #content .category-asides .entry-content {
+ padding-top: 0;
+}
+
+
+/* =Gallery listing
+-------------------------------------------------------------- */
+
+.format-gallery .size-thumbnail img,
+.category-gallery .size-thumbnail img {
+ border: 10px solid #f1f1f1;
+ margin-bottom: 0;
+}
+.format-gallery .gallery-thumb,
+.category-gallery .gallery-thumb {
+ float: left;
+ margin-right: 20px;
+ margin-top: -4px;
+}
+.home #content .format-gallery .entry-utility,
+.home #content .category-gallery .entry-utility {
+ padding-top: 4px;
+}
+
+
+/* =Attachment pages
+-------------------------------------------------------------- */
+
+.attachment .entry-content .entry-caption {
+ font-size: 140%;
+ margin-top: 24px;
+}
+.attachment .entry-content .nav-previous a:before {
+ content: '\2190\00a0';
+}
+.attachment .entry-content .nav-next a:after {
+ content: '\00a0\2192';
+}
+
+
+/* =Images
+-------------------------------------------------------------- */
+
+/*
+Resize images to fit the main content area.
+- Applies only to images uploaded via WordPress by targeting size-* classes.
+- Other images will be left alone. Use "size-auto" class to apply to other images.
+*/
+img.size-auto,
+img.size-full,
+img.size-large,
+img.size-medium,
+.attachment img,
+.widget-container img {
+ max-width: 100%; /* When images are too wide for containing element, force them to fit. */
+ height: auto; /* Override height to match resized width for correct aspect ratio. */
+}
+.alignleft,
+img.alignleft {
+ display: inline;
+ float: left;
+ margin-right: 24px;
+ margin-top: 4px;
+}
+.alignright,
+img.alignright {
+ display: inline;
+ float: right;
+ margin-left: 24px;
+ margin-top: 4px;
+}
+.aligncenter,
+img.aligncenter {
+ clear: both;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+img.alignleft,
+img.alignright,
+img.aligncenter {
+ margin-bottom: 12px;
+}
+.wp-caption {
+ background: #f1f1f1;
+ line-height: 18px;
+ margin-bottom: 20px;
+ max-width: 632px !important; /* prevent too-wide images from breaking layout */
+ padding: 4px;
+ text-align: center;
+}
+.wp-caption img {
+ margin: 5px 5px 0;
+ max-width: 622px; /* caption width - 10px */
+}
+.wp-caption p.wp-caption-text {
+ color: #777;
+ font-size: 12px;
+ margin: 5px;
+}
+.wp-smiley {
+ margin: 0;
+}
+.gallery {
+ margin: 0 auto 18px;
+}
+.gallery .gallery-item {
+ float: left;
+ margin-top: 0;
+ text-align: center;
+ width: 33%;
+}
+.gallery-columns-2 .gallery-item {
+ width: 50%;
+}
+.gallery-columns-4 .gallery-item {
+ width: 25%;
+}
+.gallery img {
+ border: 2px solid #cfcfcf;
+}
+.gallery-columns-2 .attachment-medium {
+ max-width: 92%;
+ height: auto;
+}
+.gallery-columns-4 .attachment-thumbnail {
+ max-width: 84%;
+ height: auto;
+}
+.gallery .gallery-caption {
+ color: #777;
+ font-size: 12px;
+ margin: 0 0 12px;
+}
+.gallery dl {
+ margin: 0;
+}
+.gallery img {
+ border: 10px solid #f1f1f1;
+}
+.gallery br+br {
+ display: none;
+}
+#content .attachment img {/* single attachment images should be centered */
+ display: block;
+ margin: 0 auto;
+}
+
+
+/* =Navigation
+-------------------------------------------------------------- */
+
+.navigation {
+ color: #777;
+ font-size: 12px;
+ line-height: 18px;
+ overflow: hidden;
+}
+.navigation a:link,
+.navigation a:visited {
+ color: #777;
+ text-decoration: none;
+}
+.navigation a:active,
+.navigation a:hover {
+ color: #ff4b33;
+}
+.nav-previous {
+ float: left;
+ width: 50%;
+}
+.nav-next {
+ float: right;
+ text-align: right;
+ width: 50%;
+}
+#nav-above {
+ margin: 0 0 18px 0;
+}
+#nav-above {
+ display: none;
+}
+.paged #nav-above,
+.single #nav-above {
+ display: block;
+}
+#nav-below {
+ margin: -18px 0 0 0;
+}
+
+
+/* =Comments
+-------------------------------------------------------------- */
+#comments {
+ clear: both;
+}
+#comments .navigation {
+ padding: 0 0 18px 0;
+}
+h3#comments-title,
+h3#reply-title {
+ color: #000;
+ font-size: 20px;
+ font-weight: bold;
+ margin-bottom: 0;
+}
+h3#comments-title {
+ padding: 24px 0;
+}
+.commentlist {
+ list-style: none;
+ margin: 0;
+}
+.commentlist li.comment {
+ border-bottom: 1px solid #e7e7e7;
+ line-height: 24px;
+ margin: 0 0 24px 0;
+ padding: 0 0 0 56px;
+ position: relative;
+}
+.commentlist li:last-child {
+ border-bottom: none;
+ margin-bottom: 0;
+}
+#comments .comment-body ul,
+#comments .comment-body ol {
+ margin-bottom: 18px;
+}
+#comments .comment-body p:last-child {
+ margin-bottom: 6px;
+}
+#comments .comment-body blockquote p:last-child {
+ margin-bottom: 24px;
+}
+.commentlist ol {
+ list-style: decimal;
+}
+.commentlist .avatar {
+ position: absolute;
+ top: 4px;
+ left: 0;
+}
+.comment-author {
+}
+.comment-author cite {
+ color: #000;
+ font-style: normal;
+ font-weight: bold;
+}
+.comment-author .says {
+ font-style: italic;
+}
+.comment-meta {
+ font-size: 12px;
+ margin: 0 0 18px 0;
+}
+.comment-meta a:link,
+.comment-meta a:visited {
+ color: #777;
+ text-decoration: none;
+}
+.comment-meta a:active,
+.comment-meta a:hover {
+ color: #ff4b33;
+}
+.commentlist .even {
+}
+.commentlist .bypostauthor {
+}
+.reply {
+ font-size: 12px;
+ padding: 0 0 24px 0;
+}
+.reply a,
+a.comment-edit-link {
+ color: #777;
+}
+.reply a:hover,
+a.comment-edit-link:hover {
+ color: #ff4b33;
+}
+.commentlist .children {
+ list-style: none;
+ margin: 0;
+}
+.commentlist .children li {
+ border: none;
+ margin: 0;
+}
+.nopassword,
+.nocomments {
+ display: none;
+}
+#comments .pingback {
+ border-bottom: 1px solid #e7e7e7;
+ margin-bottom: 18px;
+ padding-bottom: 18px;
+}
+.commentlist li.comment+li.pingback {
+ margin-top: -6px;
+}
+#comments .pingback p {
+ color: #777;
+ display: block;
+ font-size: 12px;
+ line-height: 18px;
+ margin: 0;
+}
+#comments .pingback .url {
+ font-size: 13px;
+ font-style: italic;
+}
+
+/* Comments form */
+input[type="submit"] {
+ color: #333;
+}
+#respond {
+ border-top: 1px solid #e7e7e7;
+ margin: 24px 0;
+ overflow: hidden;
+ position: relative;
+}
+#respond p {
+ margin: 0;
+}
+#respond .comment-notes {
+ margin-bottom: 1em;
+}
+.form-allowed-tags {
+ line-height: 1em;
+}
+.children #respond {
+ margin: 0 48px 0 0;
+}
+h3#reply-title {
+ margin: 18px 0;
+}
+#comments-list #respond {
+ margin: 0 0 18px 0;
+}
+#comments-list ul #respond {
+ margin: 0;
+}
+#cancel-comment-reply-link {
+ font-size: 12px;
+ font-weight: normal;
+ line-height: 18px;
+}
+#respond .required {
+ color: #ff4b33;
+ font-weight: bold;
+}
+#respond label {
+ color: #777;
+ font-size: 12px;
+}
+#respond input {
+ margin: 0 0 9px;
+ width: 98%;
+}
+#respond textarea {
+ width: 98%;
+}
+#respond .form-allowed-tags {
+ color: #777;
+ font-size: 12px;
+ line-height: 18px;
+}
+#respond .form-allowed-tags code {
+ font-size: 11px;
+}
+#respond .form-submit {
+ margin: 12px 0;
+}
+#respond .form-submit input {
+ font-size: 14px;
+ width: auto;
+}
+
+
+/* =Widget Areas
+-------------------------------------------------------------- */
+
+.widget-area ul {
+ list-style: none;
+ margin-left: 0;
+}
+.widget-area ul ul {
+ list-style: square;
+ margin-left: 1.3em;
+}
+.widget-area select {
+ max-width: 100%;
+}
+.widget_search #s {/* This keeps the search inputs in line */
+ width: 60%;
+}
+.widget_search label {
+ display: none;
+}
+.widget-container {
+ word-wrap: break-word;
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ hyphens: auto;
+ margin: 0 0 18px 0;
+}
+.widget-container .wp-caption img {
+ margin: auto;
+}
+.widget-title {
+ color: #222;
+ font-weight: bold;
+}
+.widget-area a:link,
+.widget-area a:visited {
+ text-decoration: none;
+}
+.widget-area a:active,
+.widget-area a:hover {
+ text-decoration: underline;
+}
+.widget-area .entry-meta {
+ font-size: 11px;
+}
+#wp_tag_cloud div {
+ line-height: 1.6em;
+}
+#wp-calendar {
+ width: 100%;
+}
+#wp-calendar caption {
+ color: #222;
+ font-size: 14px;
+ font-weight: bold;
+ padding-bottom: 4px;
+ text-align: left;
+}
+#wp-calendar thead {
+ font-size: 11px;
+}
+#wp-calendar thead th {
+}
+#wp-calendar tbody {
+ color: #aaa;
+}
+#wp-calendar tbody td {
+ background: #f5f5f5;
+ border: 1px solid #fff;
+ padding: 3px 0 2px;
+ text-align: center;
+}
+#wp-calendar tbody .pad {
+ background: none;
+}
+#wp-calendar tfoot #next {
+ text-align: right;
+}
+.widget_rss a.rsswidget {
+ color: #000;
+}
+.widget_rss a.rsswidget:hover {
+ color: #ff4b33;
+}
+.widget_rss .widget-title img {
+ width: 11px;
+ height: 11px;
+}
+
+/* Main sidebars */
+#main .widget-area ul {
+ margin-left: 0;
+ padding: 0 20px 0 0;
+}
+#main .widget-area ul ul {
+ border: none;
+ margin-left: 1.3em;
+ padding: 0;
+}
+#primary {
+}
+#secondary {
+}
+
+/* Footer widget areas */
+#footer-widget-area {
+}
+
+
+/* =Footer
+-------------------------------------------------------------- */
+
+#footer {
+ margin-bottom: 20px;
+}
+#colophon {
+ border-top: 4px solid #000;
+ margin-top: -4px;
+ overflow: hidden;
+ padding: 18px 0;
+}
+#site-info {
+ font-weight: bold;
+}
+#site-info a {
+ color: #000;
+ text-decoration: none;
+}
+#site-generator {
+ font-style: italic;
+ position: relative;
+}
+#site-generator a {
+ background: url(images/wordpress.png) center left no-repeat;
+ color: #666;
+ display: inline-block;
+ line-height: 16px;
+ padding-left: 20px;
+ text-decoration: none;
+}
+#site-generator a:hover {
+ text-decoration: underline;
+}
+img#wpstats {
+ display: block;
+ margin: 0 auto 10px;
+}
+
+
+/* =Mobile Safari ( iPad, iPhone and iPod Touch )
+-------------------------------------------------------------- */
+
+pre {
+ -webkit-text-size-adjust: 140%;
+}
+code {
+ -webkit-text-size-adjust: 160%;
+}
+#access,
+.entry-meta,
+.entry-utility,
+.navigation,
+.widget-area {
+ -webkit-text-size-adjust: 120%;
+}
+#site-description {
+ -webkit-text-size-adjust: none;
+}
+
+
+/* =Print Style
+-------------------------------------------------------------- */
+
+@media print {
+ body {
+ background: none !important;
+ }
+ #wrapper {
+ clear: both !important;
+ display: block !important;
+ float: none !important;
+ position: relative !important;
+ }
+ #header {
+ border-bottom: 2pt solid #000;
+ padding-bottom: 18pt;
+ }
+ #colophon {
+ border-top: 2pt solid #000;
+ }
+ #site-title,
+ #site-description {
+ float: none;
+ line-height: 1.4em;
+ margin: 0;
+ padding: 0;
+ }
+ #site-title {
+ font-size: 13pt;
+ }
+ .entry-content {
+ font-size: 14pt;
+ line-height: 1.6em;
+ }
+ .entry-title {
+ font-size: 21pt;
+ }
+ #access,
+ #branding img,
+ #respond,
+ .comment-edit-link,
+ .edit-link,
+ .navigation,
+ .page-link,
+ .widget-area {
+ display: none !important;
+ }
+ #container,
+ #header,
+ #footer {
+ margin: 0;
+ width: 100%;
+ }
+ #content,
+ .one-column #content {
+ margin: 24pt 0 0;
+ width: 100%;
+ }
+ .wp-caption p {
+ font-size: 11pt;
+ }
+ #site-info,
+ #site-generator {
+ float: none;
+ width: auto;
+ }
+ #colophon {
+ width: auto;
+ }
+ img#wpstats {
+ display: none;
+ }
+ #site-generator a {
+ margin: 0;
+ padding: 0;
+ }
+ #entry-author-info {
+ border: 1px solid #e7e7e7;
+ }
+ #main {
+ display: inline;
+ }
+ .home .sticky {
+ border: none;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentyten/tag.php b/src/wp-content/themes/twentyten/tag.php
new file mode 100644
index 0000000000..2c0cb874dd
--- /dev/null
+++ b/src/wp-content/themes/twentyten/tag.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * The template for displaying Tag Archive pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Ten
+ * @since Twenty Ten 1.0
+ */
+
+get_header(); ?>
+
+ <div id="container">
+ <div id="content" role="main">
+
+ <h1 class="page-title"><?php
+ printf( __( 'Tag Archives: %s', 'twentyten' ), '<span>' . single_tag_title( '', false ) . '</span>' );
+ ?></h1>
+
+<?php
+/* Run the loop for the tag archive to output the posts
+ * If you want to overload this in a child theme then include a file
+ * called loop-tag.php and that will be used instead.
+ */
+ get_template_part( 'loop', 'tag' );
+?>
+ </div><!-- #content -->
+ </div><!-- #container -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?>
diff --git a/src/wp-content/themes/twentythirteen/404.php b/src/wp-content/themes/twentythirteen/404.php
new file mode 100644
index 0000000000..76ef0822e6
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/404.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * The template for displaying 404 pages (Not Found).
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <header class="page-header">
+ <h1 class="page-title"><?php _e( 'Nothing Found', 'twentythirteen' ); ?></h1>
+ </header>
+
+ <div class="page-wrapper">
+ <div class="page-content">
+ <h2><?php _e( 'This is somewhat embarrassing, isn&rsquo;t it?', 'twentythirteen' ); ?></h2>
+ <p><?php _e( 'It looks like nothing was found at this location. Maybe try a search?', 'twentythirteen' ); ?></p>
+
+ <?php get_search_form(); ?>
+ </div><!-- .page-content -->
+ </div><!-- .page-wrapper -->
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/archive.php b/src/wp-content/themes/twentythirteen/archive.php
new file mode 100644
index 0000000000..af6c0ca597
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/archive.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * The template for displaying Archive pages.
+ *
+ * Used to display archive-type pages if nothing more specific matches a query.
+ * For example, puts together date-based pages if no date.php file exists.
+ *
+ * If you'd like to further customize these archive views, you may create a
+ * new template file for each specific one. For example, Twenty Thirteen
+ * already has tag.php for Tag archives, category.php for Category archives,
+ * and author.php for Author archives.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php
+ if ( is_day() ) :
+ printf( __( 'Daily Archives: %s', 'twentythirteen' ), get_the_date() );
+ elseif ( is_month() ) :
+ printf( __( 'Monthly Archives: %s', 'twentythirteen' ), get_the_date( _x( 'F Y', 'monthly archives date format', 'twentythirteen' ) ) );
+ elseif ( is_year() ) :
+ printf( __( 'Yearly Archives: %s', 'twentythirteen' ), get_the_date( _x( 'Y', 'yearly archives date format', 'twentythirteen' ) ) );
+ else :
+ _e( 'Archives', 'twentythirteen' );
+ endif;
+ ?></h1>
+ </header><!-- .archive-header -->
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/author-bio.php b/src/wp-content/themes/twentythirteen/author-bio.php
new file mode 100644
index 0000000000..46ce866783
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/author-bio.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * The template for displaying Author bios.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<div class="author-info">
+ <div class="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentythirteen_author_bio_avatar_size', 74 ) ); ?>
+ </div><!-- .author-avatar -->
+ <div class="author-description">
+ <h2 class="author-title"><?php printf( __( 'About %s', 'twentythirteen' ), get_the_author() ); ?></h2>
+ <p class="author-bio">
+ <?php the_author_meta( 'description' ); ?>
+ <a class="author-link" href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>" rel="author">
+ <?php printf( __( 'View all posts by %s <span class="meta-nav">&rarr;</span>', 'twentythirteen' ), get_the_author() ); ?>
+ </a>
+ </p>
+ </div><!-- .author-description -->
+</div><!-- .author-info --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/author.php b/src/wp-content/themes/twentythirteen/author.php
new file mode 100644
index 0000000000..dd27b07aef
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/author.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * The template for displaying Author archive pages.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <?php
+ /* Queue the first post, that way we know
+ * what author we're dealing with (if that is the case).
+ *
+ * We reset this later so we can run the loop
+ * properly with a call to rewind_posts().
+ */
+ the_post();
+ ?>
+
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( 'All posts by %s', 'twentythirteen' ), '<span class="vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '" title="' . esc_attr( get_the_author() ) . '" rel="me">' . get_the_author() . '</a></span>' ); ?></h1>
+ </header><!-- .archive-header -->
+
+ <?php
+ /* Since we called the_post() above, we need to
+ * rewind the loop back to the beginning that way
+ * we can run the loop properly, in full.
+ */
+ rewind_posts();
+ ?>
+
+ <?php if ( get_the_author_meta( 'description' ) ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/category.php b/src/wp-content/themes/twentythirteen/category.php
new file mode 100644
index 0000000000..7971177a8d
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/category.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * The template for displaying Category pages.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( 'Category Archives: %s', 'twentythirteen' ), single_cat_title( '', false ) ); ?></h1>
+
+ <?php if ( category_description() ) : // Show an optional category description ?>
+ <div class="archive-meta"><?php echo category_description(); ?></div>
+ <?php endif; ?>
+ </header><!-- .archive-header -->
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/comments.php b/src/wp-content/themes/twentythirteen/comments.php
new file mode 100644
index 0000000000..22818ac4f6
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/comments.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * The template for displaying Comments.
+ *
+ * The area of the page that contains comments and the comment form.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+/*
+ * If the current post is protected by a password and the visitor has not yet
+ * entered the password we will return early without loading the comments.
+ */
+if ( post_password_required() )
+ return;
+?>
+
+<div id="comments" class="comments-area">
+
+ <?php if ( have_comments() ) : ?>
+ <h2 class="comments-title">
+ <?php
+ printf( _nx( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'comments title', 'twentythirteen' ),
+ number_format_i18n( get_comments_number() ), '<span>' . get_the_title() . '</span>' );
+ ?>
+ </h2>
+
+ <ol class="comment-list">
+ <?php
+ wp_list_comments( array(
+ 'style' => 'ol',
+ 'short_ping' => true,
+ 'avatar_size' => 74,
+ ) );
+ ?>
+ </ol><!-- .comment-list -->
+
+ <?php
+ // Are there comments to navigate through?
+ if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) :
+ ?>
+ <nav class="navigation comment-navigation" role="navigation">
+ <h1 class="screen-reader-text section-heading"><?php _e( 'Comment navigation', 'twentythirteen' ); ?></h1>
+ <div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'twentythirteen' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'twentythirteen' ) ); ?></div>
+ </nav><!-- .comment-navigation -->
+ <?php endif; // Check for comment navigation ?>
+
+ <?php if ( ! comments_open() && get_comments_number() ) : ?>
+ <p class="no-comments"><?php _e( 'Comments are closed.' , 'twentythirteen' ); ?></p>
+ <?php endif; ?>
+
+ <?php endif; // have_comments() ?>
+
+ <?php comment_form(); ?>
+
+</div><!-- #comments --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/content-aside.php b/src/wp-content/themes/twentythirteen/content-aside.php
new file mode 100644
index 0000000000..9949fdd882
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-aside.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * The template for displaying posts in the Aside post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php if ( is_single() ) : ?>
+ <?php twentythirteen_entry_meta(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+
+ <?php else : ?>
+ <?php twentythirteen_entry_date(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+ <?php endif; // is_single() ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-audio.php b/src/wp-content/themes/twentythirteen/content-audio.php
new file mode 100644
index 0000000000..23abeaf175
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-audio.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * The template for displaying posts in the Audio post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <div class="audio-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .audio-content -->
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( is_single() && get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-chat.php b/src/wp-content/themes/twentythirteen/content-chat.php
new file mode 100644
index 0000000000..eb2fe69bce
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-chat.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * The template for displaying posts in the Chat post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-gallery.php b/src/wp-content/themes/twentythirteen/content-gallery.php
new file mode 100644
index 0000000000..b9537e8554
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-gallery.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * The template for displaying posts in the Gallery post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php if ( is_single() || ! get_post_gallery() ) : ?>
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ <?php else : ?>
+ <?php echo get_post_gallery(); ?>
+ <?php endif; // is_single() ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+
+ <?php if ( comments_open() && ! is_single() ) : ?>
+ <span class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a comment', 'twentythirteen' ) . '</span>', __( 'One comment so far', 'twentythirteen' ), __( 'View all % comments', 'twentythirteen' ) ); ?>
+ </span><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( is_single() && get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-image.php b/src/wp-content/themes/twentythirteen/content-image.php
new file mode 100644
index 0000000000..34f5144181
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-image.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * The template for displaying posts in the Image post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+
+ <?php if ( comments_open() && ! is_single() ) : ?>
+ <span class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a comment', 'twentythirteen' ) . '</span>', __( 'One comment so far', 'twentythirteen' ), __( 'View all % comments', 'twentythirteen' ) ); ?>
+ </span><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( is_single() && get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-link.php b/src/wp-content/themes/twentythirteen/content-link.php
new file mode 100644
index 0000000000..e9082cbeed
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-link.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * The template for displaying posts in the Link post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title">
+ <a href="<?php echo esc_url( twentythirteen_get_link_url() ); ?>"><?php the_title(); ?></a>
+ </h1>
+
+ <div class="entry-meta">
+ <?php twentythirteen_entry_date(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <?php if ( is_single() ) : ?>
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+ <?php if ( get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+ <?php endif; // is_single() ?>
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-none.php b/src/wp-content/themes/twentythirteen/content-none.php
new file mode 100644
index 0000000000..d3d27ec926
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-none.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * The template for displaying a "No posts found" message.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<header class="page-header">
+ <h1 class="page-title"><?php _e( 'Nothing Found', 'twentythirteen' ); ?></h1>
+</header>
+
+<div class="page-content">
+ <?php if ( is_home() && current_user_can( 'publish_posts' ) ) : ?>
+
+ <p><?php printf( __( 'Ready to publish your first post? <a href="%1$s">Get started here</a>.', 'twentythirteen' ), admin_url( 'post-new.php' ) ); ?></p>
+
+ <?php elseif ( is_search() ) : ?>
+
+ <p><?php _e( 'Sorry, but nothing matched your search terms. Please try again with different keywords.', 'twentythirteen' ); ?></p>
+ <?php get_search_form(); ?>
+
+ <?php else : ?>
+
+ <p><?php _e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'twentythirteen' ); ?></p>
+ <?php get_search_form(); ?>
+
+ <?php endif; ?>
+</div><!-- .page-content -->
diff --git a/src/wp-content/themes/twentythirteen/content-quote.php b/src/wp-content/themes/twentythirteen/content-quote.php
new file mode 100644
index 0000000000..4c3422be52
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-quote.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * The template for displaying posts in the Quote post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+
+ <?php if ( comments_open() && ! is_single() ) : ?>
+ <span class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a comment', 'twentythirteen' ) . '</span>', __( 'One comment so far', 'twentythirteen' ), __( 'View all % comments', 'twentythirteen' ) ); ?>
+ </span><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-status.php b/src/wp-content/themes/twentythirteen/content-status.php
new file mode 100644
index 0000000000..281becf00a
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-status.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * The template for displaying posts in the Status post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( is_single() && get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content-video.php b/src/wp-content/themes/twentythirteen/content-video.php
new file mode 100644
index 0000000000..af2ff71cd2
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content-video.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * The template for displaying posts in the Video post format.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+
+ <?php if ( comments_open() && ! is_single() ) : ?>
+ <span class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a comment', 'twentythirteen' ) . '</span>', __( 'One comment so far', 'twentythirteen' ), __( 'View all % comments', 'twentythirteen' ) ); ?>
+ </span><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+
+ <?php if ( is_single() && get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/content.php b/src/wp-content/themes/twentythirteen/content.php
new file mode 100644
index 0000000000..4f61b22066
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/content.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * The default template for displaying content. Used for both single and index/archive/search.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( has_post_thumbnail() && ! post_password_required() ) : ?>
+ <div class="entry-thumbnail">
+ <?php the_post_thumbnail(); ?>
+ </div>
+ <?php endif; ?>
+
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+
+ <div class="entry-meta">
+ <?php twentythirteen_entry_meta(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php if ( comments_open() && ! is_single() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a comment', 'twentythirteen' ) . '</span>', __( 'One comment so far', 'twentythirteen' ), __( 'View all % comments', 'twentythirteen' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+
+ <?php if ( is_single() && get_the_author_meta( 'description' ) && is_multi_author() ) : ?>
+ <?php get_template_part( 'author-bio' ); ?>
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+</article><!-- #post -->
diff --git a/src/wp-content/themes/twentythirteen/css/editor-style.css b/src/wp-content/themes/twentythirteen/css/editor-style.css
new file mode 100644
index 0000000000..f7665a8793
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/css/editor-style.css
@@ -0,0 +1,578 @@
+/*
+Theme Name: Twenty Thirteen
+Description: Used to style the TinyMCE editor.
+*/
+
+
+/**
+ * Table of Contents:
+ *
+ * 1.0 - Body
+ * 2.0 - Headings
+ * 3.0 - Text Elements
+ * 4.0 - Links
+ * 5.0 - Alignment
+ * 6.0 - Tables
+ * 7.0 - Images
+ * 8.0 - Post Formats
+ * 9.0 - RTL
+ * ----------------------------------------------------------------------------
+ */
+
+
+/**
+ * 1.0 Body
+ * ----------------------------------------------------------------------------
+ */
+
+html .mceContentBody {
+ font-size: 100%;
+ max-width: 604px;
+}
+
+body {
+ color: #141412;
+ font-family: "Source Sans Pro", Helvetica, sans-serif;
+ line-height: 1.5;
+ text-rendering: optimizeLegibility;
+ vertical-align: baseline;
+}
+
+
+/**
+ * 2.0 Headings
+ * ----------------------------------------------------------------------------
+ */
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ clear: both;
+ font-family: Bitter, Georgia, serif;
+ line-height: 1.3;
+}
+
+h1 {
+ font-size: 48px;
+ margin: 33px 0;
+}
+
+h2 {
+ font-size: 30px;
+ margin: 25px 0;
+}
+
+h3 {
+ font-size: 22px;
+ margin: 22px 0;
+}
+
+h4 {
+ font-size: 20px;
+ margin: 25px 0;
+}
+
+h5 {
+ font-size: 18px;
+ margin: 30px 0;
+}
+
+h6 {
+ font-size: 16px;
+ margin: 36px 0;
+}
+
+hr {
+ background: url(../images/dotted-line.png) repeat center top;
+ background-size: 4px 4px;
+ border: 0;
+ height: 1px;
+ margin: 0 0 24px;
+}
+
+
+/**
+ * 3.0 Text Elements
+ * ----------------------------------------------------------------------------
+ */
+
+p {
+ margin: 0 0 24px;
+}
+
+ol,
+ul {
+ margin: 16px 0;
+ padding: 0 0 0 40px;
+}
+
+ul {
+ list-style-type: square;
+}
+
+ol {
+ list-style: decimal outside;
+}
+
+li > ul,
+li > ol {
+ margin: 0;
+}
+
+dl {
+ margin: 0 20px;
+}
+
+dt {
+ font-weight: bold;
+}
+
+dd {
+ margin: 0 0 20px;
+}
+
+strong {
+ font-weight: bold;
+}
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 14px;
+}
+
+pre {
+ background: #f5f5f5;
+ color: #666;
+ font-family: monospace;
+ font-size: 14px;
+ margin: 20px 0;
+ overflow: auto;
+ padding: 20px;
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+blockquote,
+q {
+ quotes: none;
+}
+
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+ content: "";
+ content: none;
+}
+
+blockquote {
+ font-size: 24px;
+ font-style: italic;
+ font-weight: 300;
+ margin: 24px 40px;
+}
+
+blockquote blockquote {
+ margin-right: 0;
+}
+
+blockquote cite,
+blockquote small {
+ font-size: 14px;
+ font-weight: normal;
+ text-transform: uppercase;
+}
+
+cite {
+ border-bottom: 0;
+}
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+address {
+ font-style: italic;
+ margin: 0 0 24px;
+}
+
+del {
+ color: #333;
+}
+
+ins {
+ background: #fff9c0;
+ border: none;
+ color: #333;
+ text-decoration: none;
+}
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+
+/**
+ * 4.0 Links
+ * ----------------------------------------------------------------------------
+ */
+
+a {
+ color: #ca3c08;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #ac0404;
+}
+
+a:focus {
+ outline: thin dotted;
+}
+
+a:active,
+a:hover {
+ color: #ea9629;
+ outline: 0;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+
+/**
+ * 5.0 Alignment
+ * ----------------------------------------------------------------------------
+ */
+
+.alignleft {
+ float: left;
+ margin: 5px 20px 5px 0;
+}
+
+.alignright {
+ float: right;
+ margin: 5px 0 5px 20px;
+}
+
+.aligncenter {
+ display: block;
+ margin: 5px auto;
+}
+
+img.alignnone {
+ margin: 5px 0;
+}
+
+
+/**
+ * 6.0 Tables
+ * ----------------------------------------------------------------------------
+ */
+
+table {
+ border-bottom: 1px solid #ededed;
+ border-collapse: collapse;
+ border-spacing: 0;
+ font-size: 14px;
+ line-height: 2;
+ margin: 0 0 20px;
+ width: 100%;
+}
+
+caption,
+th,
+td {
+ font-weight: normal;
+ text-align: left;
+}
+
+caption {
+ font-size: 16px;
+ margin: 20px 0;
+}
+
+th {
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+td {
+ border-top: 1px solid #ededed;
+ padding: 6px 10px 6px 0;
+}
+
+
+/**
+ * 7.0 Images
+ * ----------------------------------------------------------------------------
+ */
+
+img {
+ height: auto;
+ max-width: 100%;
+ vertical-align: middle;
+}
+
+.wp-caption {
+ background: transparent;
+ border: none;
+ margin: 0;
+ padding: 0;
+ text-align: left;
+}
+
+.wp-caption.alignleft {
+ margin: 5px 10px 5px 0;
+}
+
+.wp-caption.alignright {
+ margin: 5px 0 5px 10px;
+}
+
+.wp-caption-dt {
+ margin: 0;
+}
+
+.wp-caption .wp-caption-text,
+.wp-caption-dd {
+ color: #220e10;
+ font-size: 18px;
+ font-style: italic;
+ font-weight: 300;
+ line-height: 1.5;
+ margin-bottom: 24px;
+ padding: 0;
+}
+
+.mceTemp + ul,
+.mceTemp + ol {
+ list-style-position: inside;
+}
+
+
+/**
+ * 8.0 Post Formats
+ * ----------------------------------------------------------------------------
+ */
+
+/* Aside */
+.post-format-aside {
+ background-color: #f7f5e7;
+}
+
+.post-format-aside blockquote {
+ font-size: 100%;
+ font-weight: normal;
+}
+
+.post-format-aside cite {
+ font-size: 100%;
+ text-transform: none;
+}
+
+.post-format-aside cite:before {
+ content: "\2014";
+ margin-right: 5px;
+}
+
+/* Audio */
+.post-format-audio {
+ background-color: #db572f;
+}
+
+.post-format-audio a {
+ color: #fbfaf3;
+}
+
+.post-format-audio:before {
+ background: url(../images/dotted-line.png) repeat-y 85px 0;
+ background-size: 4px 4px;
+ content: "\f109";
+ display: block;
+ float: left;
+ font-family: Genericons;
+ font-size: 64px;
+ -webkit-font-smoothing: antialiased;
+ height: 100%;
+ line-height: 1;
+ width: 120px;
+}
+
+/* Chat */
+.post-format-chat {
+ background-color: #eadaa6;
+}
+
+.post-format-chat a {
+ color: #722d19;
+}
+
+/* Gallery */
+.post-format-gallery {
+ background-color: #fbca3c;
+}
+
+.post-format-gallery a {
+ color: #722d19;
+}
+
+/* Image: same as Standard/Defaults */
+
+/* Link */
+.post-format-link {
+ background-color: #f7f5e7;
+}
+
+/* Quote */
+.post-format-quote {
+ background-color: #210d10;
+ color: #f7f5e7;
+}
+
+.post-format-quote a {
+ color: #e63f2a;
+}
+
+.post-format-quote blockquote {
+ font-size: 28px;
+ font-style: italic;
+ font-weight: 300;
+ margin: 0;
+ padding-left: 75px;
+ position: relative;
+}
+
+.post-format-quote blockquote:before {
+ content: '\201C';
+ font-size: 140px;
+ font-weight: 400;
+ line-height: .8;
+ padding-right: 25px;
+ position: absolute;
+ left: -15px;
+ top: -3px;
+}
+
+.post-format-quote blockquote small,
+.post-format-quote blockquote cite {
+ display: block;
+ font-size: 16px;
+}
+
+.format-quote .entry-content cite a {
+ border-bottom: 1px dotted #fff;
+ color: #fff;
+}
+
+.format-quote .entry-content cite a:hover {
+ text-decoration: none;
+}
+
+
+/* Status */
+.post-format-status {
+ background-color: #722d19;
+ color: #f7f5e7;
+ font-style: italic;
+ font-weight: 300;
+ padding: 0;
+ padding-left: 35px;
+}
+
+.post-format-status.mceContentBody {
+ font-size: 24px;
+}
+
+.post-format-status:before {
+ background: url(../images/dotted-line.png) repeat-y left bottom;
+ background-size: 4px 4px;
+ content: "";
+ display: block;
+ float: left;
+ height: 100%;
+ position: relative;
+ left: -30px;
+ width: 1px;
+}
+
+.post-format-status > p:first-child:before {
+ background-color: rgba(0, 0, 0, 0.65);
+ content: "";
+ height: 3px;
+ width: 13px;
+ margin-top: 13px;
+ position: absolute;
+ left: 9px;
+}
+
+.post-format-status a {
+ color: #eadaa6;
+}
+
+/* Video */
+.post-format-video {
+ background-color: #db572f;
+}
+
+.post-format-video a {
+ color: #fbfaf3;
+}
+
+
+/**
+ * 9.0 RTL
+ * ----------------------------------------------------------------------------
+ */
+
+html .mceContentBody.rtl {
+ direction: rtl;
+ unicode-bidi: embed;
+}
+
+.rtl ol,
+.rtl ul {
+ padding: 0 40px 0 0;
+}
+
+.rtl .wp-caption,
+.rtl tr th {
+ text-align: right;
+}
+
+.rtl td {
+ padding: 6px 0 6px 10px;
+ text-align: right;
+}
+
+.rtl blockquote blockquote {
+ margin-left: 0;
+ margin-right: 24px;
+}
+
+.rtl.post-format-audio:before,
+.rtl.post-format-status:before,
+.rtl.post-format-status > p:first-child:before {
+ background: none;
+ content: none;
+}
diff --git a/src/wp-content/themes/twentythirteen/css/ie.css b/src/wp-content/themes/twentythirteen/css/ie.css
new file mode 100644
index 0000000000..c815a14a65
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/css/ie.css
@@ -0,0 +1,284 @@
+/*
+Styles for older IE versions (previous to IE9).
+*/
+
+.site {
+ min-width: 1040px;
+}
+
+.genericon:before:hover,
+.menu-toggle:after:hover,
+.date a:before:hover,
+.entry-meta .author a:before:hover,
+.format-audio .entry-content:before:hover,
+.comments-link a:before:hover,
+.tags-links a:first-child:before:hover,
+.categories-links a:first-child:before:hover,
+.edit-link > a:before:hover,
+.attachment-meta:before:hover,
+.attachment-meta a:before:hover,
+.comment-awaiting-moderation:before:hover,
+.comment-reply-link:before:hover,
+.comment-reply-title small a:before:hover,
+.bypostauthor > .comment-body .fn:before:hover {
+ text-decoration: none;
+}
+
+.nav-menu .sub-menu ul,
+.nav-menu .children ul {
+ left: 100%;
+}
+
+.site-header .home-link {
+ max-width: 1040px;
+}
+
+.site-header .search-form [type="search"],
+.site-header .search-form [type="text"] {
+ padding-top: 6px;
+}
+
+img.alignright {
+ margin-right: 0;
+}
+
+img.alignleft {
+ margin-left: 0;
+}
+
+.site-main .sidebar-inner {
+ width: 1040px;
+}
+
+.site-main .widget-area {
+ margin-right: 60px;
+}
+
+.format-image .entry-content .size-full {
+ margin: 0;
+ max-width: 604px;
+}
+
+.gallery-columns-1 .gallery-item,
+.gallery-columns-2 .gallery-item,
+.gallery-columns-3 .gallery-item {
+ max-width: none;
+}
+
+.gallery img {
+ width: auto;
+}
+
+.gallery-caption {
+ background: #000;
+ filter: alpha(opacity=0);
+}
+
+.gallery-item:hover .gallery-caption {
+ filter: alpha(opacity=70);
+}
+
+.comment {
+ clear: both;
+}
+
+.comment-meta,
+.comment-content,
+.comment-list .reply {
+ width: 480px;
+}
+
+.depth-2 .comment-meta,
+.depth-2 .comment-content,
+.comment-list .depth-2 .reply {
+ width: 460px;
+}
+
+.depth-3 .comment-meta,
+.depth-3 .comment-content,
+.comment-list .depth-3 .reply {
+ width: 440px;
+}
+
+.depth-4 .comment-meta,
+.depth-4 .comment-content,
+.comment-list .depth-4 .reply {
+ width: 420px;
+}
+
+.depth-5 .comment-meta,
+.depth-5 .comment-content,
+.comment-list .depth-5 .reply {
+ width: 400px;
+}
+
+.comment-meta {
+ margin-bottom: 0;
+}
+
+.widget {
+ background: #f7f5e7;
+}
+
+.site-footer .widget {
+ background: none;
+}
+
+/* Internet Explorer 8 */
+.ie8 .site {
+ border: 0;
+}
+
+.ie8 img.size-full,
+.ie8 img.size-large {
+ height: auto;
+ width: auto;
+}
+
+.ie8 .sidebar .entry-header,
+.ie8 .sidebar .entry-content,
+.ie8 .sidebar .entry-summary,
+.ie8 .sidebar .entry-meta {
+ max-width: 724px;
+}
+
+.ie8 .author-info {
+ margin-left: 0;
+}
+
+.ie8 .paging-navigation .nav-previous .meta-nav {
+ padding: 5px 0 8px;
+ width: 40px;
+}
+
+.ie8 .paging-navigation .nav-next {
+ line-height: 1;
+}
+
+.ie8 .format-status .entry-content:before,
+.ie8 .format-status .entry-meta:before {
+ content: none;
+}
+
+.ie8 .site-main .widget-area {
+ margin-right: 0;
+}
+
+/* Internet Explorer 7 */
+.ie7 audio,
+.ie7 canvas,
+.ie7 video {
+ display: inline;
+ zoom: 1;
+}
+
+.ie7 legend {
+ margin-left: -7px;
+}
+
+.ie7 button,
+.ie7 input,
+.ie7 select,
+.ie7 textarea {
+ vertical-align: middle;
+}
+
+.ie7 button,
+.ie7 input[type="button"],
+.ie7 input[type="reset"],
+.ie7 input[type="submit"] {
+ overflow: visible;
+}
+
+.ie7 input[type="checkbox"],
+.ie7 input[type="radio"] {
+ height: 13px;
+ width: 13px;
+}
+
+.ie7 .screen-reader-text {
+ clip: rect(1px 1px 1px 1px); /* IE7 */
+}
+
+.ie7 .site-header {
+ position: relative;
+ z-index: 1;
+}
+
+.ie7 .main-navigation {
+ max-width: 930px;
+ padding-right: 150px;
+}
+
+.ie7 .nav-menu li a,
+.ie7 .nav-menu li {
+ display: block;
+ float: left;
+}
+
+.ie7 .nav-menu ul {
+ top: 40px;
+}
+
+.ie7 .nav-menu li ul ul {
+ left: 100%;
+ top: 0;
+}
+
+.ie7 .site-header .search-form [type="search"],
+.ie7 .site-header .search-form [type="text"] {
+ background-color: #fff;
+ border: 2px solid #c3c0ab;
+ cursor: text;
+ height: 28px;
+ outline: 0;
+ width: 150px;
+}
+
+.ie7 .entry-header,
+.ie7 .entry-content,
+.ie7 .entry-summary,
+.ie7 .entry-meta {
+ width: 604px;
+}
+
+.ie7 .format-status .entry-content,
+.ie7 .format-status .entry-meta {
+ padding-left: 60px;
+}
+
+.ie7 .sidebar .format-status .entry-content,
+.ie7 .sidebar .format-status .entry-meta {
+ padding-left: 60px;
+}
+
+.ie7 .sidebar .post-navigation .nav-links,
+.ie7 .sidebar .paging-navigation .nav-links {
+ width: 604px;
+}
+
+.ie7 .paging-navigation .meta-nav {
+ padding: 0 0 10px;
+ vertical-align: middle;
+ width: 40px;
+}
+
+.ie7 .comments-title,
+.ie7 .comment-list,
+.ie7 .comment-reply-title,
+.ie7 .comment-respond .comment-form {
+ width: 604px;
+}
+
+.ie7 .site-footer .widget-area {
+ max-width: none;
+ left: auto;
+}
+
+/* RTL for Internet Explorer 7 & 8 */
+.rtl .format-audio .entry-content:before,
+.rtl .comment-reply-link:before,
+.rtl .comment-reply-login:before {
+ -ms-filter: "FlipH";
+ filter: FlipH;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/fonts/COPYING.txt b/src/wp-content/themes/twentythirteen/fonts/COPYING.txt
new file mode 100644
index 0000000000..aece214b7c
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/COPYING.txt
@@ -0,0 +1,9 @@
+Genericons is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+The fonts are distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+As a special exception, if you create a document which uses this font, and embed this font or unaltered portions of this font into the document, this font does not by itself cause the resulting document to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the document might be covered by the GNU General Public License. If you modify this font, you may extend this exception to your version of the font, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.
+
+This license does not convey any intellectual property rights to third party trademarks that may be included in the icon font; such marks remain subject to all rights and guidelines of use of their owner. \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/fonts/LICENSE.txt b/src/wp-content/themes/twentythirteen/fonts/LICENSE.txt
new file mode 100644
index 0000000000..d159169d10
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/LICENSE.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.eot b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.eot
new file mode 100644
index 0000000000..defbbe5170
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.eot
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.svg b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.svg
new file mode 100644
index 0000000000..32ff53b007
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.svg
@@ -0,0 +1,105 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="genericonsregular" horiz-adv-x="2048" >
+<font-face units-per-em="2048" ascent="1638" descent="-410" />
+<missing-glyph horiz-adv-x="500" />
+<glyph unicode="&#xe000;" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="&#xf100;" d="M512 512v128h768v-128h-768zM512 768v128h256v-128h-256zM512 1024v128h640v-128h-640zM512 1280v128h1024v-128h-1024zM896 768v128h640v-128h-640zM1280 1024v128h256v-128h-256z" />
+<glyph unicode="&#xf101;" d="M256 1024q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5zM768 1024q0 -106 75 -181t181 -75t181 75t75 181t-75 181t-181 75t-181 -75t-75 -181z" />
+<glyph unicode="&#xf102;" d="M128 384v896l512 128l128 256h512l128 -256h512v-1024h-1792zM256 1440v160h256v-96zM576 960q0 -185 131.5 -316.5t316.5 -131.5q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5q-185 0 -316.5 -131.5t-131.5 -316.5zM704 960q0 133 93.5 226.5t226.5 93.5 t226.5 -93.5t93.5 -226.5t-93.5 -226.5t-226.5 -93.5t-226.5 93.5t-93.5 226.5z" />
+<glyph unicode="&#xf103;" d="M128 512v384h384v-384h-384zM128 1024v384h896v-384h-896zM640 512v384h384v-384h-384zM1152 512v896h896v-896h-896z" />
+<glyph unicode="&#xf104;" d="M512 384v1280l1152 -640z" />
+<glyph unicode="&#xf105;" d="M640 1408q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5q0 -124 -71.5 -222t-184.5 -138v-536l-256 -128v664q-113 40 -184.5 138t-71.5 222z" />
+<glyph unicode="&#xf106;" d="M384 640l128 768h512l-256 -768h-384zM1152 640l128 768h512l-256 -768h-384z" />
+<glyph unicode="&#xf107;" d="M387 862q0 106 75 181l136 135l91 -90l-136 -136q-38 -37 -38 -90t38 -91l90 -90q38 -38 91 -38t90 38l136 135l91 -90l-136 -136q-75 -75 -181 -75t-181 75l-91 91q-75 75 -75 181zM734 952l362 362l90 -90l-362 -362zM870 1450l135 136q75 75 181 75t181 -75l91 -91 q75 -75 75 -181t-75 -181l-136 -136l-90 91l135 136q38 37 38 90t-38 91l-90 90q-38 38 -91 38t-90 -38l-136 -135z" />
+<glyph unicode="&#xf108;" d="M0 1152v384q0 96 80 176t176 80h1024q96 0 176 -80t80 -176v-384q0 -96 -80 -176t-176 -80h-448l-448 -448v448h-128q-96 0 -176 80t-80 176zM768 640l128 128h384q168 0 276 108t108 276v384q96 0 176 -80t80 -176v-384q0 -96 -80 -176t-176 -80h-128v-448l-448 448 h-320z" />
+<glyph unicode="&#xf109;" d="M256 768v512h384l384 384v-1280l-384 384h-384zM1205 843q75 75 75 181t-75 181l91 91q53 -54 82.5 -124t29.5 -148t-29.5 -148t-82.5 -124zM1386 662q71 71 110.5 164.5t39.5 197.5t-39.5 197.5t-110.5 164.5l91 91q88 -89 137.5 -206t49.5 -247q0 -87 -23 -170 t-64.5 -153.5t-99.5 -129.5z" />
+<glyph unicode="&#xf200;" d="M0 1024q0 208 81 398t218.5 327t327 218t397.5 81q209 0 398.5 -81t326.5 -218t218 -326.5t81 -398.5q0 -335 -195.5 -601.5t-504.5 -369.5q-36 -7 -53 8.5t-17 40.5q0 4 0.5 102t0.5 179q0 130 -69 189q77 9 137.5 24.5t124.5 51.5t107 89t70.5 140t27.5 201 q0 161 -105 274q6 15 11 35t9 56t-3.5 83.5t-26.5 96.5q-4 1 -10.5 2t-32 -1t-55.5 -11t-79.5 -33.5t-104.5 -61.5q-118 33 -256 35q-138 -2 -256 -35q-55 37 -104 61.5t-80 33t-54.5 11.5t-33.5 1l-10 -2q-58 -146 -10 -271q-105 -115 -105 -274q0 -114 27.5 -201 t70.5 -140t107 -89t124.5 -52t136.5 -24q-53 -47 -65 -137q-28 -13 -59.5 -20t-75.5 -6.5t-87.5 28.5t-75.5 83q-2 4 -6.5 10.5t-19 24t-31.5 31t-44 25.5t-56 14h-10t-18.5 -3.5t-17 -9t4 -18.5t34.5 -31q3 -1 7.5 -4t19 -14.5t27.5 -27t30 -43.5t30 -61q1 -3 2.5 -7t8 -17 t15.5 -25.5t24.5 -28t33.5 -28t45 -23.5t57.5 -16t71.5 -3.5t87 11.5q0 -50 0.5 -110t0.5 -64q0 -24 -17 -40t-53 -10q-309 103 -504.5 370t-195.5 602z" />
+<glyph unicode="&#xf201;" d="M0 1024q0 206 82 395.5t219.5 327t327 219.5t395.5 82t395.5 -82t327 -219.5t219.5 -327t82 -395.5t-82 -395.5t-219.5 -327t-327 -219.5t-395.5 -82t-395.5 82t-327 219.5t-219.5 327t-82 395.5zM128 1024q0 -167 58 -319.5t166 -272.5q125 205 339 360t445 232 q-16 48 -80 176q-282 -86 -481.5 -111t-446.5 -1v-64zM160 1232q194 -22 444 14t388 82q-141 282 -320 528q-194 -85 -329.5 -247.5t-182.5 -376.5zM480 320q216 -192 544 -192q181 0 368 80q-33 300 -208 688q-222 -74 -410 -225.5t-294 -350.5zM832 1904 q102 -166 304 -512q6 2 86 31t118.5 45t108 47t122 64t93.5 69q-126 126 -290.5 199t-349.5 73q-32 0 -96 -8t-96 -8zM1200 1248q22 -29 36.5 -54.5t34 -67.5t25.5 -54q170 33 336 30t288 -30q-26 285 -160 464q-71 -57 -162 -104.5t-214.5 -100.5t-183.5 -83zM1344 928 q14 -27 43 -103t74.5 -231t74.5 -306q156 108 258 278t126 362q-276 46 -576 0z" />
+<glyph unicode="&#xf202;" d="M0 381q50 -6 100 -6q293 0 522 180q-137 2 -244.5 83t-147.5 208q44 -7 79 -7q57 0 110 15q-145 29 -241 144.5t-96 267.5v5q86 -48 191 -53q-86 58 -136.5 150t-50.5 200q0 113 57 211q158 -194 383 -310t483 -129q-11 49 -11 96q0 174 123 297t297 123q89 0 168.5 -35 t138.5 -97q142 27 266 102q-47 -150 -184 -233q124 15 241 66q-84 -127 -210 -217q2 -36 2 -55q0 -168 -49 -337t-150 -323.5t-241 -273.5t-336 -190t-420 -71q-351 0 -644 189z" />
+<glyph unicode="&#xf203;" d="M128 384v1280q0 106 75 181t181 75h1280q106 0 181 -75t75 -181v-1280q0 -106 -75 -181t-181 -75h-282v711h270l12 260h-282v192v12q0 60 21.5 87.5t87.5 27.5l166 -1l6 242q-78 10 -183 10q-94 0 -167 -27.5t-117 -74.5t-66 -105.5t-22 -126.5v-236h-254v-260h254v-711 h-724q-106 0 -181 75t-75 181z" />
+<glyph unicode="&#xf204;" d="M640 969v303h222v258q0 78 26 147t77 124t136.5 87t194.5 32q55 0 108 -3t79 -6l26 -3l-7 -282h-193q-76 0 -101.5 -32t-25.5 -101v-3v-2v-9v-207h329l-14 -303h-315v-841h-320v841h-222z" />
+<glyph unicode="&#xf205;" d="M128 1024q0 182 71 348t191 286t286 191t348 71t348 -71t286 -191t191 -286t71 -348t-71 -348t-191 -286t-286 -191t-348 -71t-348 71t-286 191t-191 286t-71 348zM218 1024q0 -236 125 -430.5t329 -294.5l-384 1053q-70 -156 -70 -328zM351 1466h52q37 0 91 2.5t89 4.5 l34 3q21 1 30.5 -14.5t2.5 -32.5t-27 -20q-44 -5 -93 -7l294 -873l176 529l-125 344l-85 7q-20 2 -27.5 19t2.5 33t30 15q133 -10 212 -10q38 0 91.5 2.5t88.5 4.5l35 3q16 1 25.5 -8.5t10 -22t-7 -23.5t-23.5 -13q-43 -5 -92 -7l291 -866l80 268q25 79 33.5 107.5 t18.5 74.5t10 79q0 46 -11.5 90.5t-23.5 71t-32 60.5q-2 4 -11.5 19t-12 20t-10.5 18.5t-11 19t-9 17.5t-8.5 19t-6.5 18t-5.5 19.5t-3 18.5t-1.5 20q0 57 39 100t96 43q3 0 11 -1q-110 101 -249.5 156.5t-294.5 55.5q-208 0 -385.5 -98t-287.5 -266zM796 251 q112 -33 228 -33q138 0 267 46q-3 6 -5 11l-248 679zM1429 328q183 106 291.5 291.5t108.5 404.5q0 207 -98 386q5 -40 5 -82q0 -135 -61 -289z" />
+<glyph unicode="&#xf206;" d="M128 486v485q125 -127 330 -127q30 0 59 3q-32 -61 -32 -118q0 -33 13 -63t28.5 -48.5t45.5 -47.5q-18 0 -54.5 -0.5t-55.5 -0.5q-183 0 -334 -83zM128 1599v65q0 106 75 181t181 75h1280q106 0 181 -75t75 -181v-128h-256v256h-128v-256h-256v-128h256v-256h128v256h256 v-1024q0 -106 -75 -181t-181 -75h-507q5 28 5 50q0 143 -46.5 230t-189.5 194q-3 2 -20.5 15t-25 19t-25.5 20t-27.5 22.5t-24 22t-23 23.5t-17 22t-12.5 22.5t-4 20.5q0 52 23 87t99 94q180 141 180 324q0 113 -45 204.5t-128 139.5h160l135 142h-607q-127 0 -241.5 -49 t-194.5 -132zM139 309q57 85 166 137.5t237 51.5q84 -1 158 -26q19 -13 62 -42.5t61 -42t48 -37t44.5 -41.5t29 -41.5t21.5 -49.5q7 -29 7 -66q0 -16 -1 -24h-588q-85 0 -153 50.5t-92 130.5zM228 1307q-21 161 50.5 269.5t194.5 104.5q121 -4 215.5 -118.5t116.5 -277.5 q21 -160 -43 -256t-187 -92q-125 4 -225.5 108t-121.5 262z" />
+<glyph unicode="&#xf207;" d="M384 1422q0 -58 40.5 -97.5t105.5 -39.5h1q67 0 108.5 39.5t41.5 97.5q-2 60 -42 98.5t-106 38.5q-67 0 -108 -39t-41 -98zM400 384h263v793h-263v-793zM809 384h264v443q0 45 8 64q16 40 50.5 68t85.5 28q133 0 133 -179v-424h264v455q0 175 -83.5 266t-220.5 91 q-50 0 -90.5 -12t-68.5 -34t-45 -41t-33 -44v112h-264v-793z" />
+<glyph unicode="&#xf208;" d="M128 384v1280q0 106 75 181t181 75h1280q106 0 181 -75t75 -181v-1280q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM384 1422q0 -58 40.5 -97.5t105.5 -39.5h1q67 0 108.5 39.5t41.5 97.5q-2 60 -42 98.5t-106 38.5q-67 0 -108 -39t-41 -98zM400 384h263 v793h-263v-793zM809 384h264v443q0 45 8 64q16 40 50.5 68t85.5 28q133 0 133 -179v-424h264v455q0 175 -83.5 266t-220.5 91q-50 0 -90.5 -12t-68.5 -34t-45 -41t-33 -44v112h-264v-793z" />
+<glyph unicode="&#xf209;" d="M171 1260q0 109 35.5 219t110 213t179 182t254 126.5t323.5 47.5q176 0 327.5 -60.5t253.5 -161t160 -231t58 -270.5q0 -246 -85 -443t-241 -309.5t-355 -112.5q-99 0 -186.5 46.5t-121.5 110.5q-73 -290 -89 -347q-34 -123 -127 -270l-149 54q-7 167 22 290l162 688 q-40 81 -40 200q0 139 70.5 232.5t172.5 93.5q83 0 127 -53.5t44 -135.5q0 -51 -18.5 -124t-49 -170t-44.5 -154q-23 -99 37.5 -171t161.5 -72q117 0 209.5 92t142 244.5t49.5 334.5q0 214 -139 349t-387 135q-139 0 -257.5 -49.5t-197 -133t-122.5 -193t-44 -229.5 q0 -147 83 -247q18 -21 21.5 -34t-3.5 -37q-16 -61 -25 -101q-7 -24 -24.5 -32t-39.5 1q-127 51 -192.5 181.5t-65.5 300.5z" />
+<glyph unicode="&#xf210;" d="M0 1024q0 208 81 398t218.5 327t327 218t397.5 81q209 0 398.5 -81t326.5 -218t218 -326.5t81 -398.5t-81 -398.5t-218 -326.5t-326.5 -218t-398.5 -81q-147 0 -290 42q74 116 103 219l72 282q28 -53 99 -90.5t151 -37.5q162 0 288.5 91.5t195.5 251t69 359.5 q0 114 -47 220t-130 187.5t-206.5 130.5t-265.5 49q-141 0 -262 -38.5t-205.5 -103t-145.5 -147.5t-89.5 -172.5t-28.5 -178.5q0 -138 53 -243.5t156 -147.5q18 -8 32.5 -1t18.5 26q2 9 10 41t11 41q5 19 2.5 30t-16.5 28q-68 78 -68 200q0 97 35.5 186t99.5 156.5t160 108 t209 40.5q201 0 313.5 -109.5t112.5 -283.5q0 -148 -40 -271.5t-115 -198t-169 -74.5q-82 0 -131.5 58.5t-30.5 138.5q11 46 35.5 125t39.5 138t15 101q0 66 -35.5 109.5t-102.5 43.5q-82 0 -139.5 -76t-57.5 -189q0 -43 8 -83.5t16 -59.5l9 -19q-113 -475 -132 -558 q-24 -97 -18 -235q-275 120 -444 374t-169 564z" />
+<glyph unicode="&#xf211;" d="M160 1024q0 -172 122 -294t294 -122t294 122t122 294t-122 294t-294 122t-294 -122t-122 -294zM1056 1024q0 -172 122 -294t294 -122t294 122t122 294t-122 294t-294 122t-294 -122t-122 -294z" />
+<glyph unicode="&#xf212;" d="M128 1379l84 -108q121 84 141 84q92 0 173 -287q20 -73 46 -167.5t52 -190t46 -167.5q108 -287 265 -287q253 0 619 471q353 451 365 710q16 347 -260 355q-373 12 -505 -417q69 29 133 29q136 0 120 -152q-8 -92 -120 -268q-113 -176 -169 -176q-73 0 -133 271 q-20 78 -72 407q-49 303 -258 284q-89 -8 -265 -160q-126 -113 -262 -231z" />
+<glyph unicode="&#xf213;" d="M128 768v512q0 159 112.5 271.5t271.5 112.5h1024q159 0 271.5 -112.5t112.5 -271.5v-512q0 -104 -51.5 -192.5t-140 -140t-192.5 -51.5h-1024q-104 0 -192.5 51.5t-140 140t-51.5 192.5zM768 640l640 384l-640 384v-768z" />
+<glyph unicode="&#xf214;" d="M472 1186h198v-629q0 -121 26 -187q26 -65 92 -122t161 -89q93 -31 218 -31q110 0 201 22q88 20 208 76v282q-134 -88 -271 -88q-76 0 -136 36q-44 25 -61 70q-17 46 -17 200v460h426v281h-426v453h-255q-17 -139 -62 -228q-48 -93 -121 -154q-74 -64 -181 -99v-253z" />
+<glyph unicode="&#xf215;" d="M128 384v1280q0 106 75 181t181 75h1280q106 0 181 -75t75 -181v-1280q0 -106 -75 -181t-181 -75h-1280q-106 0 -181 75t-75 181zM256 384q0 -53 37.5 -90.5t90.5 -37.5h1280q53 0 90.5 37.5t37.5 90.5v768h-272q16 -66 16 -128q0 -212 -150 -362t-362 -150t-362 150 t-150 362q0 62 16 128h-272v-768zM640 1024q0 -159 112.5 -271.5t271.5 -112.5t271.5 112.5t112.5 271.5t-112.5 271.5t-271.5 112.5t-271.5 -112.5t-112.5 -271.5zM1408 1536q0 -53 37.5 -90.5t90.5 -37.5h128q53 0 90.5 37.5t37.5 90.5v128q0 53 -37.5 90.5t-90.5 37.5 h-128q-53 0 -90.5 -37.5t-37.5 -90.5v-128z" />
+<glyph unicode="&#xf216;" d="M256 790v467q0 31 29 55l702 467q17 11 37 11t37 -11l702 -467q29 -24 29 -55v-467q0 -32 -29 -54l-702 -468q-17 -11 -37 -11q-18 0 -37 11l-702 468q-29 22 -29 54zM388 914l165 110l-165 110v-220zM441 790l517 -344v308l-286 191zM441 1257l231 -154l286 191v307z M791 1024l233 -156l234 156l-234 156zM1090 446l517 344l-231 155l-286 -191v-308zM1090 1294l286 -191l231 154l-517 344v-307zM1495 1024l165 -110v220z" />
+<glyph unicode="&#xf300;" d="M256 896v384q0 106 75 181t181 75h1024q106 0 181 -75t75 -181v-384q0 -106 -75 -181t-181 -75h-448l-448 -448v448h-128q-106 0 -181 75t-75 181z" />
+<glyph unicode="&#xf301;" d="M384 512v1024h384l64 -128h448v-128h-640l-128 -256h128l64 128h960l-256 -640h-1024z" />
+<glyph unicode="&#xf302;" d="M256 768l768 768h512v-512l-768 -768zM1152 1280q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5z" />
+<glyph unicode="&#xf303;" d="M256 1088q0 143 55.5 273.5t150 225t225 150t273.5 55.5t273.5 -55.5t225 -150t150 -225t55.5 -273.5t-55.5 -273.5t-150 -225t-225 -150t-273.5 -55.5t-273.5 55.5t-225 150t-150 225t-55.5 273.5zM384 1088q0 -117 45.5 -223.5t123 -184t184 -123t223.5 -45.5 t223.5 45.5t184 123t123 184t45.5 223.5t-45.5 223.5t-123 184t-184 123t-223.5 45.5t-223.5 -45.5t-184 -123t-123 -184t-45.5 -223.5zM896 1062v474h128v-421l298 -298l-90 -91z" />
+<glyph unicode="&#xf304;" d="M512 384v256q0 159 112.5 271.5t271.5 112.5h256q159 0 271.5 -112.5t112.5 -271.5v-256h-1024zM768 1408q0 106 75 181t181 75t181 -75t75 -181t-75 -181t-181 -75t-181 75t-75 181z" />
+<glyph unicode="&#xf305;" d="M256 384v1280h256v128h128v-128h640v128h128v-128h256v-1280h-1408zM384 640q0 -53 37.5 -90.5t90.5 -37.5h896q53 0 90.5 37.5t37.5 90.5v640q0 53 -37.5 90.5t-90.5 37.5h-896q-53 0 -90.5 -37.5t-37.5 -90.5v-640zM768 1216q0 26 19 45t45 19h128q26 0 45 -19t19 -45 v-512q0 -26 -19 -45t-45 -19t-45 19t-19 45v448h-64q-26 0 -45 19t-19 45z" />
+<glyph unicode="&#xf306;" d="M256 384v1280h256v128h128v-128h640v128h128v-128h256v-1280h-1408zM384 640q0 -53 37.5 -90.5t90.5 -37.5h896q53 0 90.5 37.5t37.5 90.5v640q0 53 -37.5 90.5t-90.5 37.5h-896q-53 0 -90.5 -37.5t-37.5 -90.5v-640zM768 1216q0 26 19 45t45 19h256h2h1h3 q22 -2 38.5 -18t19.5 -39v-2v-2v-1v-2q0 -5 -2 -15l-128 -512q-6 -26 -28.5 -40t-48.5 -7q-26 6 -40 28.5t-7 48.5l108 433h-174q-26 0 -45 19t-19 45z" />
+<glyph unicode="&#xf307;" d="M256 384v1280h256v128h128v-128h640v128h128v-128h256v-1280h-1408zM384 640q0 -53 37.5 -90.5t90.5 -37.5h896q53 0 90.5 37.5t37.5 90.5v640q0 53 -37.5 90.5t-90.5 37.5h-896q-53 0 -90.5 -37.5t-37.5 -90.5v-640zM512 640v128h128v-128h-128zM512 896v128h128v-128 h-128zM768 640v128h128v-128h-128zM768 896v128h128v-128h-128zM768 1152v128h128v-128h-128zM1024 640v128h128v-128h-128zM1024 896v128h128v-128h-128zM1024 1152v128h128v-128h-128zM1280 896v128h128v-128h-128zM1280 1152v128h128v-128h-128z" />
+<glyph unicode="&#xf308;" d="M256 384l512 512l128 -128l-512 -512zM576 1216v128h384l320 320v256h128l512 -512v-128h-256l-320 -320v-384h-128z" />
+<glyph unicode="&#xf400;" d="M256 1216q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5q0 -184 -111 -337l495 -495l-128 -128l-495 495q-153 -111 -337 -111q-117 0 -223.5 45.5t-184 123t-123 184t-45.5 223.5zM384 1216q0 -185 131.5 -316.5 t316.5 -131.5q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5q-185 0 -316.5 -131.5t-131.5 -316.5z" />
+<glyph unicode="&#xf401;" d="M256 1216q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5q0 -184 -111 -337l495 -495l-128 -128l-495 495q-153 -111 -337 -111q-117 0 -223.5 45.5t-184 123t-123 184t-45.5 223.5zM384 1216q0 -185 131.5 -316.5 t316.5 -131.5q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5q-185 0 -316.5 -131.5t-131.5 -316.5zM512 1152v128h640v-128h-640z" />
+<glyph unicode="&#xf402;" d="M256 1216q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5q0 -184 -111 -337l495 -495l-128 -128l-495 495q-153 -111 -337 -111q-117 0 -223.5 45.5t-184 123t-123 184t-45.5 223.5zM384 1216q0 -185 131.5 -316.5 t316.5 -131.5q186 0 317 131.5t131 316.5t-131 316.5t-317 131.5q-185 0 -316.5 -131.5t-131.5 -316.5zM512 1152v128h256v256h128v-256h256v-128h-256v-256h-128v256h-256z" />
+<glyph unicode="&#xf403;" d="M0 1024l506 506q101 103 234.5 160.5t283.5 57.5t283.5 -57.5t233.5 -159.5l507 -507l-506 -507q-101 -103 -234.5 -160t-283.5 -57t-283.5 57.5t-233.5 160.5zM272 1024l370 -371q77 -78 175.5 -119.5t206.5 -41.5t206 41.5t174 118.5l373 372l-371 371 q-158 161 -382 161q-108 0 -206.5 -41t-173.5 -119zM640 1024q0 159 112.5 271.5t271.5 112.5t271.5 -112.5t112.5 -271.5t-112.5 -271.5t-271.5 -112.5t-271.5 112.5t-112.5 271.5zM1024 1152q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5z" />
+<glyph unicode="&#xf404;" d="M0 1024l506 506q101 103 234.5 160.5t283.5 57.5q193 0 358 -95l-143 -143q-103 46 -215 46q-108 0 -206.5 -41t-173.5 -119l-372 -372l240 -240l-136 -136zM339 429l90 -90l1280 1280l-90 90zM640 1024q0 159 112.5 271.5t271.5 112.5q44 0 98 -14l-468 -468 q-14 54 -14 98zM666 395l143 143q103 -46 215 -46q108 0 206 41.5t174 118.5l373 372l-241 241l136 135l376 -376l-506 -507q-101 -103 -234.5 -160t-283.5 -57q-193 0 -358 95zM926 654l468 468q14 -54 14 -98q0 -159 -112.5 -271.5t-271.5 -112.5q-44 0 -98 14z" />
+<glyph unicode="&#xf405;" d="M640 768l320 320l-320 320l128 128l320 -320l320 320l128 -128l-320 -320l320 -320l-128 -128l-320 320l-320 -320z" />
+<glyph unicode="&#xf406;" d="M128 256l832 832l-832 832l128 128l832 -832l832 832l128 -128l-832 -832l832 -832l-128 -128l-832 832l-832 -832z" />
+<glyph unicode="&#xf407;" d="M384 1280v128l256 128q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5l256 -128v-128h-1152zM512 512v704h128v-704h128v704h128v-704h128v704h128v-704h128v704h128v-704q0 -53 -37.5 -90.5t-90.5 -37.5h-640q-53 0 -90.5 37.5t-37.5 90.5zM768 1472 q0 -26 19 -45t45 -19h256q26 0 45 19t19 45t-19 45t-45 19h-256q-26 0 -45 -19t-19 -45z" />
+<glyph unicode="&#xf408;" d="M256 1151l476 -330l-183 -535l475 332l475 -332l-183 535l476 329h-587l-181 535l-180 -534h-588z" />
+<glyph unicode="&#xf409;" d="M384 1024l640 640l640 -640l-128 -128l-512 512l-512 -512zM640 512v384l384 384l384 -384v-384h-256v384h-256v-384h-256z" />
+<glyph unicode="&#xf410;" d="M256 512v51l576 384l192 -128l192 128l576 -384v-51h-1536zM256 717v614l461 -307zM256 1485v51h1536v-51l-768 -512zM1331 1024l461 307v-614z" />
+<glyph unicode="&#xf411;" d="M384 384v448l896 896l448 -448l-896 -896h-448zM512 768l256 -256l128 128l-256 256zM685 941l96 -96l595 595l-96 96zM845 781l96 -96l595 595l-96 96z" />
+<glyph unicode="&#xf412;" d="M256 640v704l384 384v-704h640v448l640 -640l-640 -640v448h-1024z" />
+<glyph unicode="&#xf413;" d="M128 384q0 106 75 181t181 75t181 -75t75 -181t-75 -181t-181 -75t-181 75t-75 181zM128 971v345q240 0 459 -94t377.5 -253.5t252.5 -379.5t94 -461h-345q0 170 -63.5 324t-181.5 273q-119 119 -272 182.5t-321 63.5zM129 1582v345q243 0 475 -64.5t428.5 -181 t362 -282.5t281 -363.5t180 -430.5t64.5 -477h-345q0 197 -52 385.5t-145.5 348t-227 294t-292 228t-346 146t-383.5 52.5z" />
+<glyph unicode="&#xf414;" d="M21 230q-57 102 31 244l760 1237q57 93 134.5 126.5t155 0t135.5 -126.5l759 -1237q88 -142 31 -244t-224 -102h-1557q-168 0 -225 102zM896 512q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5zM896 896 q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v384q0 53 -37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5v-384z" />
+<glyph unicode="&#xf415;" d="M128 1024h400q45 0 79.5 27.5t44.5 69.5q33 125 136.5 206t235.5 81q154 0 270 -114q38 -38 90.5 -38t90.5 38q37 38 37 91t-37 90q-88 89 -204.5 139t-246.5 50q-194 0 -353 -106t-234 -278h-309v-256zM536 663q0 -53 37 -90q89 -89 205 -139t246 -50q194 0 353 106 t234 278h309v256h-400q-45 0 -79.5 -27.5t-44.5 -69.5q-33 -125 -136.5 -206t-235.5 -81q-156 0 -269 115q-38 37 -91 37t-91 -38q-37 -38 -37 -91zM768 1024q0 -106 75 -181t181 -75t181 75t75 181t-75 181t-181 75t-181 -75t-75 -181z" />
+<glyph unicode="&#xf416;" d="M512 832v320h128v-320q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5v640q0 80 -56 136t-136 56t-136 -56t-56 -136v-512q0 -26 19 -45t45 -19t45 19t19 45v452h128v-452q0 -80 -56 -136t-136 -56t-136 56t-56 136v512q0 133 93.5 226.5t226.5 93.5t226.5 -93.5 t93.5 -226.5v-640q0 -185 -131.5 -316.5t-316.5 -131.5t-316.5 131.5t-131.5 316.5z" />
+<glyph unicode="&#xf417;" d="M384 1216q0 117 45.5 223.5t123 184t184 123t223.5 45.5t223.5 -45.5t184 -123t123 -184t45.5 -223.5t-44.5 -222.5t-124.5 -185.5l-407 -406l-407 406q-80 80 -124.5 185.5t-44.5 222.5zM640 1216q0 -133 93.5 -226.5t226.5 -93.5t226.5 93.5t93.5 226.5t-93.5 226.5 t-226.5 93.5t-226.5 -93.5t-93.5 -226.5z" />
+<glyph unicode="&#xf418;" d="M608 1056l128 128l224 -192l448 512l128 -96l-512 -768h-128z" />
+<glyph unicode="&#xf419;" d="M0 256v256h2048v-256h-2048zM0 896v256h2048v-256h-2048zM0 1536v256h2048v-256h-2048z" />
+<glyph unicode="&#xf421;" d="M384 896v256h1152v-256h-1152z" />
+<glyph unicode="&#xf422;" d="M384 512v1024h1152v-1024h-1152zM512 640h896v640h-896v-640z" />
+<glyph unicode="&#xf423;" d="M83 832l373 671l112 -62l-267 -481h403v-384h-128v256h-493zM768 1024q0 87 43 160.5t116.5 116.5t160.5 43t160.5 -43t116.5 -116.5t43 -160.5t-43 -160.5t-116.5 -116.5t-160.5 -43t-160.5 43t-116.5 116.5t-43 160.5zM896 1024q0 -79 56.5 -135.5t135.5 -56.5 t135.5 56.5t56.5 135.5t-56.5 135.5t-135.5 56.5t-135.5 -56.5t-56.5 -135.5zM1427 832l373 671l112 -62l-267 -481h403v-384h-128v256h-493z" />
+<glyph unicode="&#xf424;" d="M256 640v768l384 384h768l384 -384v-768l-384 -384h-768zM896 640q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5zM896 1024q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5v384q0 53 -37.5 90.5t-90.5 37.5 t-90.5 -37.5t-37.5 -90.5v-384z" />
+<glyph unicode="&#xf425;" d="M384 384v1280h256q0 53 37.5 90.5t90.5 37.5h384q53 0 90.5 -37.5t37.5 -90.5h256v-1280h-1152zM512 512h896v1024h-128v-128h-640v128h-128v-1024zM640 704q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM640 960q0 26 19 45t45 19t45 -19t19 -45 t-19 -45t-45 -19t-45 19t-19 45zM640 1216q0 26 19 45t45 19t45 -19t19 -45t-19 -45t-45 -19t-45 19t-19 45zM768 1600q0 -26 19 -45t45 -19h256q26 0 45 19t19 45t-19 45t-45 19h-256q-26 0 -45 -19t-19 -45zM896 640v128h384v-128h-384zM896 896v128h384v-128h-384z M896 1152v128h384v-128h-384z" />
+<glyph unicode="&#xf426;" d="M128 768q0 106 75 181t181 75h7q-7 29 -7 64q0 133 93.5 226.5t226.5 93.5q134 0 228 -96q47 101 140.5 162.5t207.5 61.5q159 0 271.5 -112.5t112.5 -271.5q0 -62 -23 -128h23q106 0 181 -75t75 -181t-75 -181t-181 -75h-1280q-106 0 -181 75t-75 181z" />
+<glyph unicode="&#xf427;" d="M384 384v288l455 455l-1 1q-74 74 -74 180t74 181l233 233q75 74 181 74t180 -74l286 -286q74 -75 74 -180.5t-74 -180.5l-233 -233q-74 -73 -178.5 -74t-179.5 71l-455 -455h-288zM1088 1360l256 -256l160 160l-256 256z" />
+<glyph unicode="&#xf428;" d="M768 1024q0 106 75 181t181 75t181 -75t75 -181t-75 -181t-181 -75t-181 75t-75 181z" />
+<glyph unicode="&#xf429;" d="M384 896v128h896l-343 343l87 86l493 -493l-493 -493l-87 86l343 343h-896z" />
+<glyph unicode="&#xf430;" d="M531 960l493 -493l87 86l-343 343h896v128h-896l343 343l-87 86z" />
+<glyph unicode="&#xf431;" d="M384 1152l128 128l448 -448l448 448l128 -128l-576 -576z" />
+<glyph unicode="&#xf432;" d="M384 768l576 576l576 -576l-128 -128l-448 448l-448 -448z" />
+<glyph unicode="&#xf433;" d="M0 0v896l896 -896h-896z" />
+<glyph unicode="&#xf434;" d="M1152 0l896 896v-896h-896z" />
+<glyph unicode="&#xf435;" d="M384 512l640 640l640 -640h-1280zM384 1280v128h1280v-128h-1280z" />
+<glyph unicode="&#xf436;" d="M512 640v128h128v-128h-128zM512 896v128h128v-128h-128zM512 1152v128h128v-128h-128zM512 1408v128h128v-128h-128zM768 640v128h128v-128h-128zM768 896v128h128v-128h-128zM768 1152v128h128v-128h-128zM768 1408v128h128v-128h-128zM1024 640v128h128v-128h-128z M1024 896v128h128v-128h-128zM1024 1152v128h128v-128h-128zM1024 1408v128h128v-128h-128zM1280 640v128h128v-128h-128zM1280 896v128h128v-128h-128zM1280 1152v128h128v-128h-128zM1280 1408v128h128v-128h-128z" />
+<glyph unicode="&#xf437;" d="M512 512v1024q0 106 75 181t181 75h512q106 0 181 -75t75 -181v-1024q0 -106 -75 -181t-181 -75h-512q-106 0 -181 75t-75 181zM640 768h768v768h-768v-768zM896 512q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5z " />
+<glyph unicode="&#xf438;" d="M256 1024v256h512v128l384 -256l-384 -256v128h-512zM512 512v384h128v-128h768v768h-768v-128h-128v128q0 106 75 181t181 75h512q106 0 181 -75t75 -181v-1024q0 -106 -75 -181t-181 -75h-512q-106 0 -181 75t-75 181zM896 512q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5 t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5z" />
+<glyph unicode="&#xf439;" d="M384 1152h1280q0 -231 -145.5 -406.5t-366.5 -220.5v-269h-256v269q-221 45 -366.5 220.5t-145.5 406.5zM640 1280v384q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5v-384h-256zM1152 1280v384q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5v-384h-256z" />
+<glyph unicode="&#xf440;" d="M128 768q0 106 75 181t181 75h6q-6 32 -6 64q0 133 93.5 226.5t226.5 93.5q134 0 228 -96q47 101 140.5 162.5t207.5 61.5q159 0 271.5 -112.5t112.5 -271.5q0 -62 -23 -128h23q106 0 181 -75t75 -181t-75 -181t-181 -75h-384v256h-512v-256h-384q-106 0 -181 75t-75 181 zM640 384h256v256h256v-256h256l-384 -384z" />
+<glyph unicode="&#xf441;" d="M128 768q0 106 75 181t181 75h6q-6 32 -6 64q0 133 93.5 226.5t226.5 93.5q134 0 228 -96q47 101 140.5 162.5t207.5 61.5q159 0 271.5 -112.5t112.5 -271.5q0 -62 -23 -128h23q106 0 181 -75t75 -181t-75 -181t-181 -75h-512v256h256l-384 384l-384 -384h256v-256h-512 q-106 0 -181 75t-75 181z" />
+<glyph unicode="&#xf442;" d="M512 512v896h512l-128 -128h-256v-640h640v256l128 128v-512h-896zM896 987l550 549h-422v128h640v-640h-128v422l-550 -550z" />
+<glyph unicode="&#xf443;" d="M512 384v1280h640l384 -384v-896h-1024zM640 512h768v640h-384v384h-384v-1024zM1152 1280h203l-203 203v-203z" />
+<glyph unicode="&#xf444;" d="M384 512v1024q0 106 75 181t181 75h1024v-1152h-64q-53 0 -90.5 -37.5t-37.5 -90.5t37.5 -90.5t90.5 -37.5h64v-128h-1024q-106 0 -181 75t-75 181zM512 512q0 -53 37.5 -90.5t90.5 -37.5h818q-50 55 -50 128t50 128h-818q-53 0 -90.5 -37.5t-37.5 -90.5z" />
+<glyph unicode="&#xf445;" d="M160 747l232 201q-8 67 -8 76q0 8 8 75l-232 201l58 139l305 -21q47 60 107 107l-21 305l139 58l201 -232q67 8 75 8t75 -8l201 232l140 -58l-22 -305q56 -44 107 -107l305 22l58 -139l-232 -201q8 -67 8 -76q0 -8 -8 -75l232 -201l-58 -140l-305 22q-44 -56 -107 -107 l22 -305l-139 -58l-201 232q-67 -8 -76 -8q-8 0 -75 8l-201 -232l-139 58l21 305q-56 44 -107 107l-305 -22zM768 1024q0 -106 75 -181t181 -75t181 75t75 181t-75 181t-181 75t-181 -75t-75 -181z" />
+<glyph unicode="&#xf446;" d="M256 1024q0 209 103 385.5t279.5 279.5t385.5 103t385.5 -103t279.5 -279.5t103 -385.5t-103 -385.5t-279.5 -279.5t-385.5 -103t-385.5 103t-279.5 279.5t-103 385.5zM512 1024q0 -212 150 -362t362 -150q135 0 259 72l-699 699q-72 -126 -72 -259zM765 1464l699 -699 q72 123 72 259q0 212 -150 362t-362 150q-136 0 -259 -72z" />
+<glyph unicode="&#xf447;" d="M256 1664v128h384v-256h1152l-256 -640h-896v-128h896v-128h-1024v1024h-256zM512 384q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5t-37.5 -90.5t-90.5 -37.5t-90.5 37.5t-37.5 90.5zM1280 384q0 53 37.5 90.5t90.5 37.5t90.5 -37.5t37.5 -90.5t-37.5 -90.5 t-90.5 -37.5t-90.5 37.5t-37.5 90.5z" />
+<glyph unicode="&#xf448;" d="M512 384v1280h384v-1280h-384zM1152 384v1280h384v-1280h-384z" />
+<glyph unicode="&#xf449;" d="M512 512v1024h1024v-1024h-1024z" />
+<glyph unicode="&#xf450;" d="M256 384v1280h384v-1280h-384zM768 1024l1024 640v-1280z" />
+<glyph unicode="&#xf451;" d="M256 384v1280l1024 -640zM1408 384v1280h384v-1280h-384z" />
+<glyph unicode="&#xf452;" d="M512 384v1280l1024 -640z" />
+<glyph unicode="&#xf453;" d="M256 256v1536q0 106 75 181t181 75h1024q106 0 181 -75t75 -181v-1536q0 -106 -75 -181t-181 -75h-1024q-106 0 -181 75t-75 181zM512 512h1024v1280h-1024v-1280zM896 256q0 -53 37.5 -90.5t90.5 -37.5t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5 t-37.5 -90.5z" />
+<glyph unicode="&#xf454;" d="M128 1024v256h512v128l384 -256l-384 -256v128h-512zM256 256v640h256v-384h1024v1280h-1024v-384h-256v384q0 106 75 181t181 75h1024q106 0 181 -75t75 -181v-1536q0 -106 -75 -181t-181 -75h-1024q-106 0 -181 75t-75 181zM896 256q0 -53 37.5 -90.5t90.5 -37.5 t90.5 37.5t37.5 90.5t-37.5 90.5t-90.5 37.5t-90.5 -37.5t-37.5 -90.5z" />
+<glyph unicode="&#xf500;" d="M128 0l960 960l960 -960h-1920z" />
+<glyph unicode="&#xf501;" d="M0 128l960 960l-960 960v-1920z" />
+<glyph unicode="&#xf502;" d="M128 2048l960 -960l960 960h-1920z" />
+<glyph unicode="&#xf503;" d="M1088 1088l960 960v-1920z" />
+</font>
+</defs></svg> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.ttf b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.ttf
new file mode 100644
index 0000000000..a21dcb6476
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.ttf
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.woff b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.woff
new file mode 100644
index 0000000000..b57e62c0f6
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/genericons-regular-webfont.woff
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/fonts/genericons.css b/src/wp-content/themes/twentythirteen/fonts/genericons.css
new file mode 100644
index 0000000000..2fde3990ca
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/fonts/genericons.css
@@ -0,0 +1,157 @@
+/**
+
+ Genericons Helper CSS
+
+*/
+
+
+/**
+ * The font was graciously generated by Font Squirrel (http://www.fontsquirrel.com). We love those guys.
+ */
+@font-face {
+ font-family: 'Genericons';
+ src: url('genericons-regular-webfont.eot');
+}
+
+@font-face {
+ font-family: 'Genericons';
+ src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAC98ABEAAAAATZgAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABgAAAABwAAAAcaBk2X0dERUYAAAGcAAAAHQAAACAAjwAET1MvMgAAAbwAAABCAAAAYFFfaIFjbWFwAAACAAAAAIcAAAGayK6UdGN2dCAAAAKIAAAABgAAAAYAfwEJZnBnbQAAApAAAAGxAAACZVO0L6dnYXNwAAAERAAAAAgAAAAI//8AA2dseWYAAARMAAAmfwAAPpi5AaxsaGVhZAAAKswAAAArAAAANgMOxuZoaGVhAAAq+AAAABwAAAAkEAMH3WhtdHgAACsUAAAAcAAAAM5JOTFAbG9jYQAAK4QAAADGAAAAxk3HPlxtYXhwAAAsTAAAACAAAAAgAYoBJW5hbWUAACxsAAABZgAAAwhJCWWYcG9zdAAALdQAAAFwAAAD3pfLCKFwcmVwAAAvRAAAAC4AAAAusPIrFHdlYmYAAC90AAAABgAAAAYLT1HIAAAAAQAAAADMPaLPAAAAAM3t18IAAAAAze27zXjaY2BkYGDgA2IJBhBgYmAEwkQgZgHzGAAIdQCUAAAAeNpjYGZ/zziBgZWBhdWY5QwDA8NMCM10hsEIzAdKYQeh3uF+DA4PGL4ys6X9S2Ng4GBg0AAKMyIpUWBgBACF8guRAAB42mNgYGBmgGAZBkYGEJgC5DGC+SwMFUBaikEAKML1gOEj5yfOT2KfOb5wfpH8ovnF8ovnl5CvzP//MzAA5Rg+MXwS+MzwheGLwBfFLwZfHL4EfGX4/1+BmZ+Fj4+Pg1eeR4NHiUeaR5SHn4eTOw5qFw7AyMYAV8DIBCSY0BUwDHsAAB/OIGwAAAABCQB/AAB42l1Ru05bQRDdDQ8DgcTYIDnaFLOZkMZ7oQUJxNWNYmQ7heUIaTdykYtxAR9AgUQN2q8ZoKGkSJsGIRdIfEI+IRIza4iiNDs7s3POmTNLypGqd+lrz1PnJJDC3QbNNv1OSLWzAPek6+uNjLSDB1psZvTKdfv+Cwab0ZQ7agDlPW8pDxlNO4FatKf+0fwKhvv8H/M7GLQ00/TUOgnpIQTmm3FLg+8ZzbrLD/qC1eFiMDCkmKbiLj+mUv63NOdqy7C1kdG8gzMR+ck0QFNrbQSa/tQh1fNxFEuQy6axNpiYsv4kE8GFyXRVU7XM+NrBXbKz6GCDKs2BB9jDVnkMHg4PJhTStyTKLA0R9mKrxAgRkxwKOeXcyf6kQPlIEsa8SUo744a1BsaR18CgNk+z/zybTW1vHcL4WRzBd78ZSzr4yIbaGBFiO2IpgAlEQkZV+YYaz70sBuRS+89AlIDl8Y9/nQi07thEPJe1dQ4xVgh6ftvc8suKu1a5zotCd2+qaqjSKc37Xs6+xwOeHgvDQWPBm8/7/kqB+jwsrjRoDgRDejd6/6K16oirvBc+sifTv7FaAAAAAAAAAf//AAJ42q17CXgb5bX2d2ak0WJbmtFqy5YsyVqc2LESrXYWRyQsSRxCICFrgRCWNC4FwlYopUxZmrCFXrhNKaQkpC3Q5aczckLa5nJxKf17KYjlwc3llrZ/0+dpWVp66b2UQmJN/nO+kRyFpKX3ea5tzfLNaPyd853lPcswYE0/sxiTBCYwiVlVJjIba2Fu5mVB9kmmsYwGVc2S0eScZq1qSlazZzRfTnNUNX9Wa81obVXQ2jOa5WCF2Vuz2axmq1ZsFmffWNkmOmjb4ujTbLLugz4tWNVdnmy24gvSdZ/s6NM7oI/NnAWFmP9kHwGnU2PAjjJBrakWVlMF9SieC0xVoelj1PdMALxqw1+kwcsWMM2Z0dxVzYsTxHn6kJiDOGOtTdYVnI+tqvuhT1faFM+YxeEUE8EhpnvdeAaSjeHZzFlM9iSiFo8sWKIJ5gtki/lUHNiLcCHsgQtffNHYZZxv7ILsjokdOybETPPgiy8KO2l0B7HYwlRQbaqkcu76WZjdxHmLcwtntI4qTU2sjjlFn71Pa6lqdpxtpGm2QZxtZ1XrlHUPHklVvRvn3QaKR7c7h4a0oKIJQ1onUiH63DhvzaNoVqSlI6x49rYieUCDPqUiWKWhISTLqyS9MW9MISZ7ZJbLMpn1xAW5GA3IUlRF/vK/D5GrZbD94IcgGYd/+IOtB8B54IDxPqgi8fsom2SW6O4NxleN7caHYIOrwFar33KA0ywwe7NMLSSadXtrLkdC5ciSXKFQtWVBkzMaO6hZssgFTZR1O3A2SFmtRdZb8cRdpRVjNHOcdf2Tww/y1cDpGLjHncDo1NwazLw0qTIGNCQR/wU8UfDUgl+wokDRNTpUUWbaWJ6B5uJTwXlZq2MOK8MFcVZJjhxV3Y1cdzLFg9zWrQ7ci0MkvXlkm98n2RSrMoBPOwTDh+7dcpRtudeq7jp0aNfnnu2tvakKD/Q+i/KJEmxr8ISBNwa4DIBzF5Cd9Z2gktTTh4lwqyBaa9JNXB/72HKmKRnizLQMygNo/VxGbFXSsCSyqbuqz8A5Jm2Kp+wULS7FF2jvjMW5YE9roUEmtrn8wfZIrM+U7/x8CNokXzcEsvwongEHBMFbKmZxzOeGdKmYz0Aq7ga4dWTb+m2p1LrUaBIPRiZG1oMMo+uMHQNb6WRkZNu6rfXLwnsTI1vXbUuO4mkKD0bwXje/V1hKJ3g/PqJ+mdGqsHEbrYGH9bB+psUymjen+askGK05rr2JjNZ+UAtXiVCmW2RkfwdS0IHsz8WyAb/ik3pioPTEU1CKZYsFxRzrw+XevcHCNuxGSS0bZXXDbpG08fHXaEQ1yiQJ/CJujTKM7zY2qK89DuqxEVqHhvxYUY7D7Iy6ZeRaam9oqRdXoKOum3a0Ik637CfF8yp6IDyESwAoO09KjtY2j7eDsx+lGKeXLObTpQigBAWHIZ+iY7/PhQqF/5TLcwE5Vpgzp7DujLPOOmP9mosGVswWGYn0EfyMEO+Ld++8u7jujAMvHzhj/dq3b1n96D1zyO6Qnc/bUQvZJvYppl2S0c6vatNJ60D7JJfzYlUrynonkJTrm3HmRZxjZeTM5WgntE7lSavsn3vquRu5BJ1/CRoceSNemK6UW5zeMOvtz5cXr7qAiLR69sYTyZlZTpeS97BELmthHr/MrFKqkC8W8ulhC22EVHoAXIItlZZsA6IbpKDk90XEoGRzwQCkByzp6eCCQDBiCUZsxZKPVCudYHvACze+/ArcCJ49xg3G84k4nHbmDeqq0mbJaXd7LW25uReVrrvzzutKG4czTufsmZtLq9QblhZau+avWR0VHOF4MWxp7XAoIdERDsXbQGzzdCeK884ZgHjCeN64wcJehs/hw/cYfzJuf8XQa3/YZOvusDx79i1zHN2LRp+46pEt7t5FF8wCweKZlYwJQiw5S5EE4b6brt511ROji6L2zLo2FwyWLG09ne2CrSXkQdq6B2OiPdTR3RFwis7s9Zb2qLRJCNDa2GjD18bNOrnUz0a5Ws6uYZU2xvq0VJUca3dVGzTX62yu6zKqhKyfheu1IEsm6RxcsrNQF8pt1tY2S6CrO9E7ozBnEV+v9hRpvIN5pw/PLy9YvpSWqVvZa4eu8Bw6HvRUYplTuUNoB1ywKK6XjKYRXZ3o8wSLrJRKt6IBCCRKQlpiEIhlS4IoMW/AO2wppRI9cQkiQrBoCQppl+CNAH7HU0p8g1YKduLH+41vGO8YtxsX4+edxDWX3QTffUMuG783tvw1+gy8d+c9Y88YfwblNVi070Dse782tr1/6c+k3WfetXna5439P4iqsDwQTkvfhqWfDX3xjCf/utI1e3145wvtxh/F7InP/wb+X2HxY8ZL11eheOZMdVW2/UuBRQMQev9c48CRB8eXQz/ctsR4xbr5UeNRYXZ0eEHi8/fJtSvDuZWtMakTwmNDF4waezofMH72lctg5fhAXX/G7cxWZlnGlEAuWkIJDeSyuJuHIjoAhXwpYLGSfOeygWCxJNnogyLrhFboiWazkPzdHf/e298zVPin8VWbV10y9DA8A0LL+0+s3TVn++cyd3zu2pWfFzb+zHjTuP43xiNwk7RX2HOzzR1+4wHrTOvs71+2ZeMzb7bNyjzx/unDnSM7VrhzN69LeB83njCe/9N2mp/KEFfYVJZmpzIykWgs41XNlSU/Ec1pgaoWMsWnF7HaQQJwCN0cMmIxLYj4I6dPQwEKIkTQQkPcvTZbUwWd0zyyr8FSqifuEsLQQ043nlJ3jFrZ6I4do8bvwdVq/L5vwaPSss3n37em3zBq/aM7yLfS5SO4FX4KlvHWuSX4L2fp/GtP/aMxWRsiUISekqnWN3DunWwZt6dBjgv82QoDAoisA6EjemN7VWtFiNCV0UIHNSFLcEnJVjpCdE9H0NFXCXXQYYghngybeBJnmR8WcEm6QUQpDVtiIhKjCOqv85d+59Ol0VDI9qOlOVjsMn5ijIvPQQaEZXdeXpZE0fh9+TRRcLxkvDK5X1xMKmqd4rEbkdsqdj7i4u1Ma8toa6taNKOnCohnuqr69Ayi35Umszc36eo81NWzs9ql1cq8S2me85YiWZfK+kYcRwUeRf7PIwV2kAJ7A6vXX8CVN7qWlBrsDubz9gwuOv+CjZeSznYpewP9i5deTMcrPfq0WaS9HtlTRO0NoPZKqL0p0l6QvNlctjgfigHJJtnAK6LZLQYD5lgEzMFhoZAno+vgEhwknbYACXgqLULRg/YaZdmmbn8XlsJlsPTd7dvfNfYa/2zsfTd/+AVDPf32cDB5WU/c73X5+mdBSrvpXJ/b57v9rNSnenpkL7jlvlnQs7xD8QXbfYLXKkutVrsoLhsS7Zcbbz30svE1OOvKa+78gih8AFv3/8dG6zxxyUf+Dx4Jwh+NGy+2hHeCyyqI0B0XrcLkVwQF1tiEeBScNOjtCAg4+jC0njX0idjA2kLcEnF2trS7AorPObQKLrni2cNfjQ1IVuGx2vZRuPr1l8Z6p2990MTmU+t7GlvLLmE7mbY6o/XmtMVVkj+EpAsRbuU0X7Wy0EdLuDCCS9iBMnmpuc7ZOgSL45KGsloCLXe2Ek/QrfFBlMpNuMY2ROtjouv09bRycaXstLZEpvUtGFm56kK+3otXo99lfaejOdZFFx7bBgbJBy9U9oMc60nM+cRG7lq9Ci0PuUwIxqWeuFgwNTYMMaVHiflNWEzaiy4XXa0dr5f4Ya4Ui0viMATRt1qDtK6oyd5UMYhPCkgoHepN1Ug4GuqOeBZ793/FVPGjjEdcCPdR2a3W8+4Ve9wJb1hR7ANL965bsXtr7ZGbf3fa0C/UlUu8qxJzw2GbDWp7z912iv/eG294KuBXb7zpOfg9/O5mcd5QbG4yDBbpFLIMPH7gj57E/9IVuPeJTwmh1i6l09fud+ZPn3PP/i37Z27fePjr524G6Gib0zErPqsjnJTtl1iKj/yHxfK7r+8et1heZoTNECRJy6Qga8UoJs3OZeQ3oxhHZBDTcMPHGhiZoj5PVUtmNY8JelBvyQDaEPTobS5kfacHTWGU9K8dYyfZnUylTaTmC8wBRJUDgPYEIycE7kq+NAy5rB/Znefm0VaIgXr2KbBwhbB8wcJzZLBhWPRVsNvl03K3g/2xO7JnD8Zl4wPr9tlnnTV77pnLjuwXOybfgAMzvL2DY8Ya+On3nmzvT3VceZxMdrEoK1G8iBYH0W+sD83MTB44RaMHFa2Y07wYq8haCGkd5LSGq2R6wrIeQQpjVS1mSmZfVeuT9X7T7Awh1ZEwN/taTNHbgyhqcY9WGNL6FH1mkdBqFC/rvQUzXmx2C4iw/zFuTLkJ8gPA/gHWNDuOHZbrP45PwL6DQGo5YqhT2HdZJUC4yZ3RplWJQxIyZAFnSKGqFWS9CylH3xiXKUbCIEpfiLti6IfDLe8uYf4+p0vrQC6O6z74UEuNj3l8KW9fBbfRO6N39kiokkNsr8fXEUoN0A80HWvlEOhdBVTa4NA8Utq4UpECM+lohkd3TyNuzpyG+t/CuodNLUb3RAA54PH7BAvGLGkB7XE6VfLWsQQPACSy1miEGfHT70NFtRFKTqeE75zx5Veg7wkNMi9c823j33560ffii+X4eV+2hff03nPpijXJea7gDZdc+4OLjLc/uOudr61Z4bHZZIetJ3DzrZY/fvqXLz58wQ3PGUfuft+47tB5ZePXQzfeX3zsRkE7+zN3HfjUObn7nhm66Evfh1lPHgTXRY+9fv39F/tD7fN622VHDqyNuMLErqvY7aziIr4j1Fic0QarWrfpA1dz1idR22Q9h5xeWtWWyvrpeDSnqs2R9ZAZc6xBQVyaQ970ZVasJNt4urLfZfV2D54iL6fTOR49MJ8YGHBR9LESeboYow+Hk3lDyWm5OfOXfyTiIATbE08XSwhITfYNCMg/0e8LBANFFNJSMZVGLnN8QGxG7pfID6LUollFyIBLETw+4DBjgvvvXRJe1LV9+Z7anec/+tft9/zXtz47NLrJE7YIsmi1uk49Qx3f8tyh5TvOP+cib8usyBkLz7latju2eNslRKlPHBdfGOfj5097pl+zCUKFkf0w/9+umvj6xjO/8OjY2jtfnW53eR1lhzegLPvshZWtZ7/+xD//9cvXLh94+LrpC1Y/sKXvbK/XSK648M7rYZJR7Lxb2GDbYN2NEYWb9TJu93Jk8FxmYgXMbIasO5DjbY1EikcORItyKmqp73e/B2vee894XLi7fmD5rvH4e/VjvufrjnbbdjOGLglWYFoLZSE0f0ZTcL2TCIUoMu9sQatiG9L8SoVJXtIBXFy5O9pjCn4QpduLUYMnlwXm9SQTIg6gWJMrS4mkBZK68gbfJ8725fO+y75Wg8vhwlbZ+KNx122nlbfJ9iu3DC6e68vPemWt9nnrRZetNA4tfurpRcYh+Hf4MYiw3t5qrAg/8AlNA/cyWAwZr/2BLZQwrOffFOZjHgY0aZROT1UP1NNKUwYOBSIWHwCrA9RDuyxs16FN+icn2Sf1TYJKWUgKvCmrY9DQJr2dvA8DeI2pUi/a6zhGcpojgwYYtJ6M1nWQOBTI6glijUw5ozbyJjnFx90uuvJiSUHa0ySTCoHUHkJmiM1e+7+h0G0XnHfT5evXXP/FO5bO7VcU+Lax6qgyY+biJZ+y7KnddcOCU66Kdgd8gxBak+iYMfAgvAAd8JO71p43r9xznA/pYX1sDruF+xD0FpGMlq5qHRktntMy6BUoPapZZFRe0OZyxpjQNYoCYyrwtKkEJKUiczz0nEeZpihSFB/SpiljkXA/jyo7KS/D9I40LntnNNlLYxlFT0w7mSPB8D7HkzUxVEV0dBhPxRJ1iUyaTgYDkFQfoGoe503UkYKVFUaMd2VjwlhjTMjGu8Azb4eMZ4TukYJaGOGb4xzKKA2KbMHwhDEB/RPDC7qNZw7Rlxp3jxTQrAEup41JBkpKEGOTbuReGvk3gLE5aBnOHj9KvUzJay3C4V4vbqfcykzkS4cfqQ+0d0WJ+oSyV7IShguSPxiLJ6f3E+SjOCVfgmI2CMQPG5AYQGo+pL2gJMVgUhGDJTxOWxVryQHBArCw8K9KryL8azhcW6D4PN7agvBt3/xmQbAav33jDYg89tbbby8QrG8Yv4XIG7Uj8OVvigF4tbsdXm1pMWa0dxszogGjv6UFJgI7L7/ceNx4HPJPw+CDT0Ou9vTOnTtrcVjz0NNC19MPwpra05f/EhlBeTkmUV7Oz5qScd4MZfRNEk5IvyFUtJjRIeXbRneIqCL8FLeUT9uBz1UFJqkS5el7eOyHUanEobaAT2/N6G2kLw7GTQnPkwUR2ooIYYEUDh9SU1W1LI4fRXVESUckibpp5v8lmq8F0WA7owoFZelQ7J0H8em6i0/agXAFjqXzSaVrlEkbHRkZFfHUwFNLgc5GpnJ/NsrTdLMkO49rkZ9n7snPpbiFVTAoNRWmp6r1mLKBOpJGWYgqKAttFl8YF13v6FE8+1r91q5EksP+MArKPoryYslGweG4UM7jiwjZYQF9WNwFFNdSWvCKp8AKEbA+dcUVTxlHjN8aR55S1j/087d//tB6cwffVGH6OlH/yE14JDiO3YU7Yyf8wlhvHFyPfoTnyHFVGLKdRfiqoFlQzBqPJ6O1HKQ0vPcjy87yxWzAJ8UFdmgXoGWsMV4MwVXiZvIoE3eYZZBjfGxBrepnn25UQPooy1Xp66ZwqS+NkRXCd6GqWx1ZXg6woRebwbWutaq1yrqAnDX9GRmlRLUyjQItNi2M30QllDjjNYeZjkV1HKhPOFbI+flHgYbRQZePIZHfki+ioeEiHEcj3BMnKUJjjyQcYWgwuGGY5MYkFVJDqVQ+hYAPDQuKIKVgGV0X+F3r8qlUyGB4T6gpb1ynuci+0qC5kNHyOUrunUhr6aS0nkDWYB28drx7K4FXLT/g0nLjer/woTZjnFX6Z+QIpI7hPj8FUSUrCltXKt07bToXvoIb9Ssz9LHcycXmCOitwqLPJiL8HICS9+8zCVATxUBMFFRpRijUZbvsib/NLyEaFAQQrE5kW5cN7wedtR7Ht4YFzrAcRkJz2Hy2kO1vcLIroydm5nK8MDALuRjNVHrzc3M4EkPRKMyjmmR/Rh8s48gMjHtOwfMTmX5qE9MxTtCFKF7rruqWOO1lct96bz8ep6v69AHay9zO5wfxOFfVi7NpL+tzcUwq4/H8qm5fQPupBTvtY+XQi6Mifhr7v3X8tzivnuTn5Gwn4wmm1TyhiNo8TjDfrKkSjhDRAjJeHcJAV8mBn+w9r8YabBwVvszLV8a4StYdx0Q8KgNaU9UYN5qeRalvLwtT1g89SpDWkFtSs+Jp+taQaT+plhIiX2q1uGTynw5Fa0HJDVL5x0XpsDFgLY56LWtYyEYwTrIB96UDcKy0Caxu8q6A/1QN5avfv/bnDyWPVTYtI3WreO33v2ooKvznFesfEsRjZU3GTF0+NvcYu7Qx+wjP0tdpiJ9IQ0+dhn1EQyR6Eioiyhjzt3Tw/LxHcxBZFQj5eGb+71ElUp3871O2VVA/jjjDXOjj6ZvGxproS3Jb1ZOtRLiVjvQ6+irdETrsjqHZrdM+vYn2XqQ9SuqixbOVdC/dmk7it3rTdNhLCbT0FIf6SLuQQ5plSEsrlWCXTGFDyKNbXUP/m8yi1Jif0mQfxzQe56AS/AOsm8pjmXV+Bv12Jk2wNl7T6SMpwSjJU6VgIF33dbxhwqzehg82AexYvXobRllpUcT2CEeM05S9Toun2yzipgk+2Fz+rhj1J1CuJhwlwhUg1BB0AIGGtIh+P1tEzEghra1R1vc0AM/hS6AF+qHlYjhiSJcYf0EE/ZeL/wBXnfmT155dCtca9zz8m8t+MmKpo+ldHBZZGBzedPXVlxpWw7rpqqs3wWHjnmUrVpwJ18DVj5yzrPaOefMhoQGbmHWKF9RN0om8yLEyIyFBDjhMDuQzeoGAXvd0xVORu5QhvtxlJ7O5g6FwMjWDyomaxVORPN6hBp25bNDGCYOgG41RGnjqGlLeEqVLSpAuERt64l6g0mGPSe+OH33z3k1XIlnG3e9uS66zsnWTMw7t6i8a/a4QXSDC/7wNrucM2fGjC2DChZdNqi+4d+CcZfS91+l7tRW7DrmM/mJt/70DRP+ftxrbiCewESaK/bsOMbO2Iagch7agxRQIvTvA5qBWg7LBrWIZbSLfGOMiO/6c31Ov7fAcCz7D64Cph6hieXIcN2JZnRznm8lxBLHHnfN7GrlRwnQtaLFmsNsYZWcIxQWz2YqbK7PbhWqp+DvIUfKitu5Mcp/JdXoAIT/hPs0t6zLKKEaP3kY3jxaUMf6lwFDPoNzKiCYqQryHMthBH+UOMeTT2hXUUab3U7OK4KA1hEKyDh6tfkK0zb9mVMhMx8jdIgHJkQIQsGCTrO7VyIPRACENwlpHWYjcHI/i1BoTxmvl5g+OW9x5wm20NmjnIhjTfBlxLnozEf8g1kKjv9wPr8Pr++GXtX379lpuNp6svQVLjb1CEBYLwdrb3H+ZcQv1AbhYL8aD7owmHdRcVc0l6y1mRgvZpLdQBt9iB+QFxRsCLptXcQAP8KkHRCB/S9YDf4+iBbHwDid8OI6qZtXf4Fu0KeRheQwm4YxdiM0ZFCBYAn8Sn0geIAlo0ITy+LhQPsygauQkCmdyUBVYDpBbhpqrCpcaVajmcgYO5Wq87sFlY1wax39u57lzBorDUoIS6RR9VAzcxidJMMnCzdggrNhgnElb/Oa4qBrlST57XCB+rdZG23rMiE/Gp0Y5ShNRjhzcN2AE5iR9FymwkzjwJJ44iACTLdTiJSCYqPEQr6YSikY5rucytiIjfCxBnV22jO4KI6ZDAGfn4aM/owV4Ggr/kW73owibyNmNq2KuD6XDESamzPxXPW4RFd6mEMsL6VQCTxB6hhDZ5J3A+kE1Y5d34UmY9y/GYzdf9xnjxcf+G16GO2DkjS8Yj33yAFrPHxt3QIDfJ47A2n8xfmQs+vO3If+Zz9wsXARrv/CWsde41hh47ydwA8yHtgObOT1+pOcPtgHkO6U9zEhV5n1g7UhELEMZe5xlMVWCYQgEIYCK0YhYRdoTakTMuOyqNcIHQw89NFv465qrHvvwD8Kd3FzX/9QXtlt+ft7Checd6dv+AuzjYyYOhHq2g/O2nhsLoIUosBFG/rwXcTH5LdCKGS1zkDBuCeU6l0Es5unqtXFv1NuFy9g+pNnIZDvb/MHuWN/MPG9AI1c9c5YXtZiXBYKBbKmYT1O9wGJDQoKUm02UUB3ilNGm/Ffc1nBQKnxpxmnO2Eu3PXhNanMqmVzz1i3PGM+MGM/DA8m1b97yDAyPQMG40rxn55bUaOrHfJ0srDT9pj1XpVKp0eTaiye+W3vB3AMfvzqZguvrHXm8H4z3fKWpspKiYgEVyj3ViofXlT1+BCitVEZqFJDMxrQu3otGxvCYCbTzoJ/XkdzIkIo1lCI/5lP01m5qzkPv1ZGkEbuit0Qpld3qIWMI3BiS0QtEG8upmEubq4eivLNMIQlBQE2tdVfuvhKtmIo7OjM+JCgilslh3H7gwO2CuvzKK5fXw89njbl0JjC6UlN/QJjFxOAq3CcRznPhig8wLWBa+mBTzdpn4jI07rpPJpIsraYlqwMsn4QGLdVIIYNaR1Nrlxubjc3LH6s3AU6hp7dfXW6Mwo7laJveP0AXTR+5gXyk9Tdk2sjoBKFH2KD+BsYpFLFE1XGBbaAeOHKFdpqv2UcYaepKtdaVfyplRP1gxxoE7ewDZn6g3kV6bEs5KBH/v0Xl2lh/JiWLLBnd2ojV0FhbyAzSF6bsP02Y5tLbyJHYzCyT3WxipFQqPYGsnWPqQUmqkuHDJhm1JFLSapKCOMKMK4SynVn/Hz7Ry1HjLYzSLShc+PQubuG6MVCVSUZjWa0TPbLZDic1J/aPpSRN+YybgDLZSEa2Kp4WSkDFyUt3RbppPXUxiFfsbn87T9wqYw6Xz2xM8+JqEFAu5ochGwGfC+Kphno66tdWwLVXGn+B+9XxVfc/cf8q2kzf8vCWLQ/DnsYVsSzsGja60ZWxzfVbVq2CIbppi6FOXWuKPWy8G+oTZN+pz9HN89UdGZ4W7Gqkpu1ZElI/UthKVp66PnSZSriCDbGHFcnVRYnoc7fgoZXhYIcXjyx1lQPqujupOSU3JPLGUeo7bjalwtQ4zvhkltRhYq1677GJ/hvZige4pLTyXq5QThuikgBl2uM5bV6VcsjljDY9p51S1VK8cyfDe5ZdOSSb+mSLpoY2JymQ+DFB6UokgtQQU4lScgKPZMoL6XMpAzGnOuZwDy+gG+bIpBz1JIQ+ZxBZkc0NmRnoWB2LcQnt8ccKPQ3PKHxk72lCZd7mTu3jEJqoEpBRUxxuNf2ta8Jq66COboDnJ4h/R1DlEcFNPspvh9Rxu1/w3WRTgsKsRSEuohxyJ8swst6oKN5sReQGXHRQ97mI2JbLDVo2MtbVeoOQhzJ+ZqU1SO6JmiFyRCSSpu4YtdkO3P7F8zMHrtp1KBisVw8EdBzhntsPbLjkxkO7hheYjd1kS9GL2Cy8P5c6i9Op/Hwzpe9zgwvSCP4pY/1TWLLkrZGJJRDB/ZJXRowh2A1sN/X8QpSuToy8tWSJ8duRV0feWiwsMobEl4+y3TyoBMpIWymcspHts3E6RdPc1Et7DTvTyMWKZg62kXnltg5etb5j/T9oCkNTvauOjInGqC1Vs3JkHqMwI81No/Gt1fCO4V0Nq6nbe/Uqw2t4V8FqtNteeFVS+bNQ6EsQw2+lcfCd1ca3yLbB6tXiOL+XvsZz/WWJ5k8RIUUx1O8M42jna+MWRKdlfsTvI39Qpvs4YqYvChgTlY2yiPi2hpHRuFGeqj+LOEn0iwqr4Akus5hBBSc2YJQomo3fgNYdp/k37kMrQMbdbBFvYHuryl+F8PA6KsWoCDTtZtWAp1s4Sj2CcxSYWQ4kYZTpxKpK7Lj3J06Wufw+cb8iR2fmeBd8RYnNIsW1ZCq+RJ7GrNWKP1mgMXum0t47SGOOaqVj2hCNtWYqXf08u9lWrYRnUHYTyHiwgxht8PcvxGpFcrr4EY/YKr72LjrzViuBUIQf8TpFJWGajJ5qJUUZzSxVLWbieH5wbpYnNSvF2cN4pJ9Sf0fjWCLyo4nJf+RcYOrf/xHU41/qqLH/2TkXCYHXf3ithmzwfF6rQc3v5Oi6/h5IV1OJU2nk1amtsCPDXUkHZZp8QydUt+IpanVpuA2B7RgVzDIX1SPNN1W4ryDnTuPU2bQDRkU22VxLMucnoS6n2K0ca8erhECd1YozRabLaUfsacIRXq6ttHlpuM1NtizN+83dWXopoS1LbU5OM/Bsr2rtMtUiExlKvulRJ/WbWSXBrEBqFnSHzMkVXQM61dro/QUzI41xJAJR9AExf0/heJITU2Uy87UKjPeIVLWZ+HrpzMJ4oHiU8XcvuGpMsWFXIy3EcxKM5/apztTBFvG3dDw5CtL8KM0hXqsz62lSC9U/KlaJGGAFR19FstIhRsJ9BHw8LbzjvtOU0JiP2RBppRgtG1EQq+/JyRi/+tVR9ivjV3yN+MaivmE8MsP4b2ibARfAJtOPk08y9xzvYdxp+phuXK2VrJKiTpdIRuvINbxN5KPeBlcodhAXgq9CIoa+tiVFWCSSQuAVjSUoEhCVSidPlPxdV0TZgriV7zASHZWkj3glesfFUEdhFDi+RUCF1j4abfZRPDtJG5OeYz4zTv3CUU5IBNUjW4lEeWaXExJBQrSobJJIfQxm+0IkisQEGZ+/DoGPnT2VWbk/PXHmfLoE/QzTs3501qakUU2ynm9xoEW+jnsuK0f+qBz87bNKaxvNu1Um1nunXt1pLpjJHBNXZDfdKLc6+ii84bWwiuD0ULaK92VQjtlCg3ZzsBVwUDEVxEaLUFIc5OsofUzTUimSwBUQUsY6PKj9QjCxD3Dxf11I0vGjtV807JKZh7MwJ2tDSapTYuco12n6Y1fT9OtvQLWYhFjMd49a7PzdI01StFacLT8VhzSnYjaV0MskSVNccmnySICeTeSMFtjzz3MtwBFV4Gmb5+v4xdRFBa3l6Yzwtp/arUkLpVyTtcTYQ+IWx1sdc0r0VlQ7z2M7TfTtbEfRCHQMHTOaSk9cogYOP9qQIiHHVL5E2TzqDaCEXKE8abZxiOhjJl8smEbzCFkSlaxF6b4S721iu20bbBswTi3S+qOdzFYJD7urvFIqHtRmVrWZsp6n1lteFdVnilRSt9pbp80g25dXxuREG29DCXn2Kf72ru4enr3IokLuC7NYopfehdKKyhhY27vo0O3ZJznbZG/QjIVKKOCldMlaLImlIGK7UlAMBJNBavO3BW1Jyea1pal3w5b2ptLWhn/Y/abd/uZsmJWZ67/ruYXywufuDgzmYNZsPmy81D8/gMMO+8Ln7vIP5oyXhBRHa8IfGoNzMye7mR5ivDS7/mwcF5x1kCce9+4jX03z7cfQlNeDRvQQNN9+pJULYmC4j95+VHycKyE3cU+yMY//hDcgvT6Wy5ZA8kKRNyWe8CZkFvontn6udtqimnBgkTExse2EdyKzE8bEIuHA5yFXO+3GbRPQf8K8L2ekxxgluXmUhDTYGr0hddzaxT1EK++6FrIVp417TXIJTpkch82MDTsoUOQ02tDv6S4vtaIputtD4aCfe0Lz3VNqX/VTYUiu4+dEfU92yIKqMkkYse7b9/GdRDVSinMs7PDzTVEia+6jICzYxRp5ATOBZDE5fywvwN9LoDCAmcEQQcsjZn6ETeUaIsfnJxqPqzYlKkh/zKxCvc6KWs3nIPF+N1v9S3UsS9/wmllXJMH8vyawbfqucOy7IlmAqe8CfwvTfKvVfI2yxp9Qf8+SNb9nyRrvWYrAX3qyN7DZKfX3nP730Bk0obNjTUiTvPeYGFOHKYTA6MJhE55Z2eGpmpXI/T3N0cRnN7FKF83xf4jQbE0I7W/AswSK5F7BKlm6udadFJl5G8gsVv89OTJrvO+qmlQePY5y4aPQrIbrbHBPYDZlHW5GZ1Rzonhp/KTxUo5qT+P0O1k2YzA8tfO3N3GeNMovmzjDUua1K4HXrvi4nU2W8SpYyvW6lkDxo2LBQfp8oLL/D/oHFeoAeNpjYGRgYGBi8vVdNXdGPL/NVwZ5DgYQOPt29zlkmoOBA0IxgSgAVvoK5QB42mNgZGDgYPh/A0QyMPz/DySBIiiAFQBj/AP1eNpNTrENgDAMc0IHdsQ//MADnGKJRzrDQxzCxEScFolUtWIncYIHGX4AdgMjHAYQdDiNtkO8BZ2qmPAMXpNd8aPHEjX9f+mdM72D6T7L3+gbpBCrKuoapE6poQR6c2S/SFlte9qm71pdV5YXStwa2gAAAAAAAAAAAAgAbAC4ATIBeAGGAbwB1AJIApgC9APCBJQE5AVCBZYGhgdmB9AIZAkgCeYKHAp4CqgK8guODBQMQAxsDJYNCg06DbQOUA8WDzwPmhAKEKwRMhGwEdIR9BJ+EpwS1hMCEy4TWBPAFAYUgBT+FUIVVhWCFZwVxhZIFqoXYhekF9YX+BgeGDYYShhgGHQYihioGWwZvBo+GpQa/BtUG7gcBBxUHOodRh2uHdId8B4OHiweOh6MHwwfIh8wHz4fTAAAAAEAAABiAGkAEAAAAAAAAgABAAIAFgAAAQAAuAAAAAB42o1Ru04CQRQ9s6AJMbEwxMJqEym0YFnUNbpWFGiCSohG6UzALIuRfQgr4C/4ZfoDln6EpZVnZodIWAoymZlzzz33NQNgA+/IQeQLAL65UyxQpJViA5v40TgHV8w0eZSEq/EapuJB43XyXxoXsCN+Nd5CyShq/IFt40TjT9hGExdo4QomxvAwxAhPiBDSPuCOyJjo0H7jPSBKlCqrnhAl6BP1FJMQeZjikWdMa6bboybhiuGiwjVRy4JP7ytvWdEnP2CEjA1Zw+OukI3Jlpm/gxcqZZ6AzC7OdcV6pt4+p5M5ZK8yX6Ty3dD2WU3OM+ScFmyuU5zhDpdoo0m0LK68ELlMYy5o7jOv+l+thVsy0ppn+1QmOt+Y/qryWXBwTG/ArM/MKTU9svKdujre4l3FIU9npf4b5D3VVY3egPxIvXa40mRtWt253077vNZzNqhL5z1SMzr8b5u9udTZirdlr3+3BnfZAAB42m3Rx1JVQRSF4fNfA+Ys5ixGxNO7d3PBhAmMmCPGcubEma/pKxm4P4zsqlNrdL5aq3Y36Jbf719ddP973/5+dAMGrGEt61jPGBvYyCY2s4WtbGM7O9jJLnazh72Ms4/9HOAghzjMEY5yjOOc4CSnOM0EZzjLOc5zgYtMcokpLtNTCCpJY5ohM8xyhatc4zo3mOMmt7jNHe4yzwL3uM8DHvKIxyzyhKc84zkveMkrXvOGt7zjPUt84COf+MwXvo79/PF9vu/7f7lQVrOYYVYzzWZOm0NzxpxdztALvdALvdALvdALvdCLFa/oFb2iV/SKXtErI6/ao9qj2qPao9qj2qP2K/8NzVGP1Emd1Emd1Emd1EmdXHVGe9I96Z50T7on3ZPuSfdk0St6RS90Qid0Qid0Qid0Qid0qr2qXtWrelWv6lW9qlf1ql7qpV7qpV7qpV7qpV7qpV7Ta3pNr+m1kde8V/NezXu1vv4BRRflZLgB/4WwAY0AS7AIUFixAQGOWbFGBitYIbAQWUuwFFJYIbCAWR2wBitcWFmwFCsAAAABUcgLTgAA) format('woff'),
+ url('genericons-regular-webfont.ttf') format('truetype'),
+ url('genericons-regular-webfont.svg#genericonsregular') format('svg');
+ font-weight: normal;
+ font-style: normal;
+}
+
+
+/**
+ * All Genericons.
+ */
+[class*="genericon"] {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ -webkit-font-smoothing: antialiased;
+ font-size: 16px;
+ line-height: 1;
+ font-family: 'Genericons';
+ text-decoration: inherit;
+ font-weight: normal;
+ font-style: normal;
+ vertical-align: top;
+}
+
+/* IE7 */
+[class*="genericon"] {
+ *overflow: auto;
+ *zoom: 1;
+ *display: inline;
+}
+
+/**
+ * Individual icons.
+ */
+
+/* Post formats */
+.genericon-standard:before { content: '\f100'; }
+.genericon-aside:before { content: '\f101'; }
+.genericon-image:before { content: '\f102'; }
+.genericon-gallery:before { content: '\f103'; }
+.genericon-video:before { content: '\f104'; }
+.genericon-status:before { content: '\f105'; }
+.genericon-quote:before { content: '\f106'; }
+.genericon-link:before { content: '\f107'; }
+.genericon-chat:before { content: '\f108'; }
+.genericon-audio:before { content: '\f109'; }
+
+/* Social icons */
+.genericon-github:before { content: '\f200'; }
+.genericon-dribbble:before { content: '\f201'; }
+.genericon-twitter:before { content: '\f202'; }
+.genericon-facebook:before { content: '\f203'; }
+.genericon-facebook-alt:before { content: '\f204'; }
+.genericon-wordpress:before { content: '\f205'; }
+.genericon-googleplus:before { content: '\f206'; }
+.genericon-linkedin:before { content: '\f207'; }
+.genericon-linkedin-alt:before { content: '\f208'; }
+.genericon-pinterest:before { content: '\f209'; }
+.genericon-pinterest-alt:before { content: '\f210'; }
+.genericon-flickr:before { content: '\f211'; }
+.genericon-vimeo:before { content: '\f212'; }
+.genericon-youtube:before { content: '\f213'; }
+.genericon-tumblr:before { content: '\f214'; }
+.genericon-instagram:before { content: '\f215'; }
+.genericon-codepen:before { content: '\f216'; }
+
+/* Meta icons */
+.genericon-comment:before { content: '\f300'; }
+.genericon-category:before { content: '\f301'; }
+.genericon-tag:before { content: '\f302'; }
+.genericon-time:before { content: '\f303'; }
+.genericon-user:before { content: '\f304'; }
+.genericon-day:before { content: '\f305'; }
+.genericon-week:before { content: '\f306'; }
+.genericon-month:before { content: '\f307'; }
+.genericon-pinned:before { content: '\f308'; }
+
+/* Other icons */
+.genericon-search:before { content: '\f400'; }
+.genericon-unzoom:before { content: '\f401'; }
+.genericon-zoom:before { content: '\f402'; }
+.genericon-show:before { content: '\f403'; }
+.genericon-hide:before { content: '\f404'; }
+.genericon-close:before { content: '\f405'; }
+.genericon-close-alt:before { content: '\f406'; }
+.genericon-trash:before { content: '\f407'; }
+.genericon-star:before { content: '\f408'; }
+.genericon-home:before { content: '\f409'; }
+.genericon-mail:before { content: '\f410'; }
+.genericon-edit:before { content: '\f411'; }
+.genericon-reply:before { content: '\f412'; }
+.genericon-feed:before { content: '\f413'; }
+.genericon-warning:before { content: '\f414'; }
+.genericon-share:before { content: '\f415'; }
+.genericon-attachment:before { content: '\f416'; }
+.genericon-location:before { content: '\f417'; }
+.genericon-checkmark:before { content: '\f418'; }
+.genericon-menu:before { content: '\f419'; }
+.genericon-top:before { content: '\f420'; }
+.genericon-minimize:before { content: '\f421'; }
+.genericon-maximize:before { content: '\f422'; }
+.genericon-404:before { content: '\f423'; }
+.genericon-spam:before { content: '\f424'; }
+.genericon-summary:before { content: '\f425'; }
+.genericon-cloud:before { content: '\f426'; }
+.genericon-key:before { content: '\f427'; }
+.genericon-dot:before { content: '\f428'; }
+.genericon-next:before { content: '\f429'; }
+.genericon-previous:before { content: '\f430'; }
+.genericon-expand:before { content: '\f431'; }
+.genericon-collapse:before { content: '\f432'; }
+.genericon-dropdown:before { content: '\f433'; }
+.genericon-dropdown-left:before { content: '\f434'; }
+.genericon-top:before { content: '\f435'; }
+.genericon-draggable:before { content: '\f436'; }
+.genericon-phone:before { content: '\f437'; }
+.genericon-send-to-phone:before { content: '\f438'; }
+.genericon-plugin:before { content: '\f439'; }
+.genericon-cloud-download:before { content: '\f440'; }
+.genericon-cloud-upload:before { content: '\f441'; }
+.genericon-external:before { content: '\f442'; }
+.genericon-document:before { content: '\f443'; }
+.genericon-book:before { content: '\f444'; }
+.genericon-cog:before { content: '\f445'; }
+.genericon-unapprove:before { content: '\f446'; }
+.genericon-cart:before { content: '\f447'; }
+.genericon-pause:before { content: '\f448'; }
+.genericon-stop:before { content: '\f449'; }
+.genericon-skip-back:before { content: '\f450'; }
+.genericon-skip-ahead:before { content: '\f451'; }
+.genericon-play:before { content: '\f452'; }
+.genericon-tablet:before { content: '\f453'; }
+.genericon-send-to-tablet:before { content: '\f454'; }
+
+/* Generic shapes */
+.genericon-uparrow:before { content: '\f500'; }
+.genericon-rightarrow:before { content: '\f501'; }
+.genericon-downarrow:before { content: '\f502'; }
+.genericon-leftarrow:before { content: '\f503'; }
diff --git a/src/wp-content/themes/twentythirteen/footer.php b/src/wp-content/themes/twentythirteen/footer.php
new file mode 100644
index 0000000000..99b6bbb26c
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/footer.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * The template for displaying the footer.
+ *
+ * Contains footer content and the closing of the
+ * #main and #page div elements.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?>
+
+ </div><!-- #main -->
+ <footer id="colophon" class="site-footer" role="contentinfo">
+ <?php get_sidebar( 'main' ); ?>
+
+ <div class="site-info">
+ <?php do_action( 'twentythirteen_credits' ); ?>
+ <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'twentythirteen' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'twentythirteen' ); ?>"><?php printf( __( 'Proudly powered by %s', 'twentythirteen' ), 'WordPress' ); ?></a>
+ </div><!-- .site-info -->
+ </footer><!-- #colophon -->
+ </div><!-- #page -->
+
+ <?php wp_footer(); ?>
+</body>
+</html> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/functions.php b/src/wp-content/themes/twentythirteen/functions.php
new file mode 100644
index 0000000000..b4234bf1e7
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/functions.php
@@ -0,0 +1,526 @@
+<?php
+/**
+ * Twenty Thirteen functions and definitions.
+ *
+ * Sets up the theme and provides some helper functions, which are used in the
+ * theme as custom template tags. Others are attached to action and filter
+ * hooks in WordPress to change core functionality.
+ *
+ * When using a child theme (see http://codex.wordpress.org/Theme_Development
+ * and http://codex.wordpress.org/Child_Themes), you can override certain
+ * functions (those wrapped in a function_exists() call) by defining them first
+ * in your child theme's functions.php file. The child theme's functions.php
+ * file is included before the parent theme's file, so the child theme
+ * functions would be used.
+ *
+ * Functions that are not pluggable (not wrapped in function_exists()) are
+ * instead attached to a filter or action hook.
+ *
+ * For more information on hooks, actions, and filters,
+ * see http://codex.wordpress.org/Plugin_API
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+/**
+ * Sets up the content width value based on the theme's design.
+ * @see twentythirteen_content_width() for template-specific adjustments.
+ */
+if ( ! isset( $content_width ) )
+ $content_width = 604;
+
+/**
+ * Adds support for a custom header image.
+ */
+require get_template_directory() . '/inc/custom-header.php';
+
+/**
+ * Twenty Thirteen only works in WordPress 3.6 or later.
+ */
+if ( version_compare( $GLOBALS['wp_version'], '3.6-alpha', '<' ) )
+ require get_template_directory() . '/inc/back-compat.php';
+
+/**
+ * Sets up theme defaults and registers the various WordPress features that
+ * Twenty Thirteen supports.
+ *
+ * @uses load_theme_textdomain() For translation/localization support.
+ * @uses add_editor_style() To add Visual Editor stylesheets.
+ * @uses add_theme_support() To add support for automatic feed links, post
+ * formats, and post thumbnails.
+ * @uses register_nav_menu() To add support for a navigation menu.
+ * @uses set_post_thumbnail_size() To set a custom post thumbnail size.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_setup() {
+ /*
+ * Makes Twenty Thirteen available for translation.
+ *
+ * Translations can be added to the /languages/ directory.
+ * If you're building a theme based on Twenty Thirteen, use a find and
+ * replace to change 'twentythirteen' to the name of your theme in all
+ * template files.
+ */
+ load_theme_textdomain( 'twentythirteen', get_template_directory() . '/languages' );
+
+ /*
+ * This theme styles the visual editor to resemble the theme style,
+ * specifically font, colors, icons, and column width.
+ */
+ add_editor_style( array( 'css/editor-style.css', 'fonts/genericons.css', twentythirteen_fonts_url() ) );
+
+ // Adds RSS feed links to <head> for posts and comments.
+ add_theme_support( 'automatic-feed-links' );
+
+ // Switches default core markup for search form, comment form, and comments
+ // to output valid HTML5.
+ add_theme_support( 'html5', array( 'search-form', 'comment-form', 'comment-list' ) );
+
+ /*
+ * This theme supports all available post formats by default.
+ * See http://codex.wordpress.org/Post_Formats
+ */
+ add_theme_support( 'post-formats', array(
+ 'aside', 'audio', 'chat', 'gallery', 'image', 'link', 'quote', 'status', 'video'
+ ) );
+
+ // This theme uses wp_nav_menu() in one location.
+ register_nav_menu( 'primary', __( 'Navigation Menu', 'twentythirteen' ) );
+
+ /*
+ * This theme uses a custom image size for featured images, displayed on
+ * "standard" posts and pages.
+ */
+ add_theme_support( 'post-thumbnails' );
+ set_post_thumbnail_size( 604, 270, true );
+
+ // This theme uses its own gallery styles.
+ add_filter( 'use_default_gallery_style', '__return_false' );
+}
+add_action( 'after_setup_theme', 'twentythirteen_setup' );
+
+/**
+ * Returns the Google font stylesheet URL, if available.
+ *
+ * The use of Source Sans Pro and Bitter by default is localized. For languages
+ * that use characters not supported by the font, the font can be disabled.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return string Font stylesheet or empty string if disabled.
+ */
+function twentythirteen_fonts_url() {
+ $fonts_url = '';
+
+ /* Translators: If there are characters in your language that are not
+ * supported by Source Sans Pro, translate this to 'off'. Do not translate
+ * into your own language.
+ */
+ $source_sans_pro = _x( 'on', 'Source Sans Pro font: on or off', 'twentythirteen' );
+
+ /* Translators: If there are characters in your language that are not
+ * supported by Bitter, translate this to 'off'. Do not translate into your
+ * own language.
+ */
+ $bitter = _x( 'on', 'Bitter font: on or off', 'twentythirteen' );
+
+ if ( 'off' !== $source_sans_pro || 'off' !== $bitter ) {
+ $font_families = array();
+
+ if ( 'off' !== $source_sans_pro )
+ $font_families[] = 'Source Sans Pro:300,400,700,300italic,400italic,700italic';
+
+ if ( 'off' !== $bitter )
+ $font_families[] = 'Bitter:400,700';
+
+ $query_args = array(
+ 'family' => urlencode( implode( '|', $font_families ) ),
+ 'subset' => urlencode( 'latin,latin-ext' ),
+ );
+ $fonts_url = add_query_arg( $query_args, "//fonts.googleapis.com/css" );
+ }
+
+ return $fonts_url;
+}
+
+/**
+ * Enqueues scripts and styles for front end.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_scripts_styles() {
+ // Adds JavaScript to pages with the comment form to support sites with
+ // threaded comments (when in use).
+ if ( is_singular() && comments_open() && get_option( 'thread_comments' ) )
+ wp_enqueue_script( 'comment-reply' );
+
+ // Adds Masonry to handle vertical alignment of footer widgets.
+ if ( is_active_sidebar( 'sidebar-1' ) )
+ wp_enqueue_script( 'jquery-masonry' );
+
+ // Loads JavaScript file with functionality specific to Twenty Thirteen.
+ wp_enqueue_script( 'twentythirteen-script', get_template_directory_uri() . '/js/functions.js', array( 'jquery' ), '2013-07-18', true );
+
+ // Add Open Sans and Bitter fonts, used in the main stylesheet.
+ wp_enqueue_style( 'twentythirteen-fonts', twentythirteen_fonts_url(), array(), null );
+
+ // Add Genericons font, used in the main stylesheet.
+ wp_enqueue_style( 'genericons', get_template_directory_uri() . '/fonts/genericons.css', array(), '2.09' );
+
+ // Loads our main stylesheet.
+ wp_enqueue_style( 'twentythirteen-style', get_stylesheet_uri(), array(), '2013-07-18' );
+
+ // Loads the Internet Explorer specific stylesheet.
+ wp_enqueue_style( 'twentythirteen-ie', get_template_directory_uri() . '/css/ie.css', array( 'twentythirteen-style' ), '2013-07-18' );
+ wp_style_add_data( 'twentythirteen-ie', 'conditional', 'lt IE 9' );
+}
+add_action( 'wp_enqueue_scripts', 'twentythirteen_scripts_styles' );
+
+/**
+ * Creates a nicely formatted and more specific title element text for output
+ * in head of document, based on current view.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @param string $title Default title text for current view.
+ * @param string $sep Optional separator.
+ * @return string The filtered title.
+ */
+function twentythirteen_wp_title( $title, $sep ) {
+ global $paged, $page;
+
+ if ( is_feed() )
+ return $title;
+
+ // Add the site name.
+ $title .= get_bloginfo( 'name' );
+
+ // Add the site description for the home/front page.
+ $site_description = get_bloginfo( 'description', 'display' );
+ if ( $site_description && ( is_home() || is_front_page() ) )
+ $title = "$title $sep $site_description";
+
+ // Add a page number if necessary.
+ if ( $paged >= 2 || $page >= 2 )
+ $title = "$title $sep " . sprintf( __( 'Page %s', 'twentythirteen' ), max( $paged, $page ) );
+
+ return $title;
+}
+add_filter( 'wp_title', 'twentythirteen_wp_title', 10, 2 );
+
+/**
+ * Registers two widget areas.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_widgets_init() {
+ register_sidebar( array(
+ 'name' => __( 'Main Widget Area', 'twentythirteen' ),
+ 'id' => 'sidebar-1',
+ 'description' => __( 'Appears in the footer section of the site.', 'twentythirteen' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'Secondary Widget Area', 'twentythirteen' ),
+ 'id' => 'sidebar-2',
+ 'description' => __( 'Appears on posts and pages in the sidebar.', 'twentythirteen' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+}
+add_action( 'widgets_init', 'twentythirteen_widgets_init' );
+
+if ( ! function_exists( 'twentythirteen_paging_nav' ) ) :
+/**
+ * Displays navigation to next/previous set of posts when applicable.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_paging_nav() {
+ global $wp_query;
+
+ // Don't print empty markup if there's only one page.
+ if ( $wp_query->max_num_pages < 2 )
+ return;
+ ?>
+ <nav class="navigation paging-navigation" role="navigation">
+ <h1 class="screen-reader-text"><?php _e( 'Posts navigation', 'twentythirteen' ); ?></h1>
+ <div class="nav-links">
+
+ <?php if ( get_next_posts_link() ) : ?>
+ <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentythirteen' ) ); ?></div>
+ <?php endif; ?>
+
+ <?php if ( get_previous_posts_link() ) : ?>
+ <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?></div>
+ <?php endif; ?>
+
+ </div><!-- .nav-links -->
+ </nav><!-- .navigation -->
+ <?php
+}
+endif;
+
+if ( ! function_exists( 'twentythirteen_post_nav' ) ) :
+/**
+ * Displays navigation to next/previous post when applicable.
+*
+* @since Twenty Thirteen 1.0
+*
+* @return void
+*/
+function twentythirteen_post_nav() {
+ global $post;
+
+ // Don't print empty markup if there's nowhere to navigate.
+ $previous = ( is_attachment() ) ? get_post( $post->post_parent ) : get_adjacent_post( false, '', true );
+ $next = get_adjacent_post( false, '', false );
+
+ if ( ! $next && ! $previous )
+ return;
+ ?>
+ <nav class="navigation post-navigation" role="navigation">
+ <h1 class="screen-reader-text"><?php _e( 'Post navigation', 'twentythirteen' ); ?></h1>
+ <div class="nav-links">
+
+ <?php previous_post_link( '%link', _x( '<span class="meta-nav">&larr;</span> %title', 'Previous post link', 'twentythirteen' ) ); ?>
+ <?php next_post_link( '%link', _x( '%title <span class="meta-nav">&rarr;</span>', 'Next post link', 'twentythirteen' ) ); ?>
+
+ </div><!-- .nav-links -->
+ </nav><!-- .navigation -->
+ <?php
+}
+endif;
+
+if ( ! function_exists( 'twentythirteen_entry_meta' ) ) :
+/**
+ * Prints HTML with meta information for current post: categories, tags, permalink, author, and date.
+ *
+ * Create your own twentythirteen_entry_meta() to override in a child theme.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_entry_meta() {
+ if ( is_sticky() && is_home() && ! is_paged() )
+ echo '<span class="featured-post">' . __( 'Sticky', 'twentythirteen' ) . '</span>';
+
+ if ( ! has_post_format( 'link' ) && 'post' == get_post_type() )
+ twentythirteen_entry_date();
+
+ // Translators: used between list items, there is a space after the comma.
+ $categories_list = get_the_category_list( __( ', ', 'twentythirteen' ) );
+ if ( $categories_list ) {
+ echo '<span class="categories-links">' . $categories_list . '</span>';
+ }
+
+ // Translators: used between list items, there is a space after the comma.
+ $tag_list = get_the_tag_list( '', __( ', ', 'twentythirteen' ) );
+ if ( $tag_list ) {
+ echo '<span class="tags-links">' . $tag_list . '</span>';
+ }
+
+ // Post author
+ if ( 'post' == get_post_type() ) {
+ printf( '<span class="author vcard"><a class="url fn n" href="%1$s" title="%2$s" rel="author">%3$s</a></span>',
+ esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentythirteen' ), get_the_author() ) ),
+ get_the_author()
+ );
+ }
+}
+endif;
+
+if ( ! function_exists( 'twentythirteen_entry_date' ) ) :
+/**
+ * Prints HTML with date information for current post.
+ *
+ * Create your own twentythirteen_entry_date() to override in a child theme.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @param boolean $echo Whether to echo the date. Default true.
+ * @return string The HTML-formatted post date.
+ */
+function twentythirteen_entry_date( $echo = true ) {
+ if ( has_post_format( array( 'chat', 'status' ) ) )
+ $format_prefix = _x( '%1$s on %2$s', '1: post format name. 2: date', 'twentythirteen' );
+ else
+ $format_prefix = '%2$s';
+
+ $date = sprintf( '<span class="date"><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s">%4$s</time></a></span>',
+ esc_url( get_permalink() ),
+ esc_attr( sprintf( __( 'Permalink to %s', 'twentythirteen' ), the_title_attribute( 'echo=0' ) ) ),
+ esc_attr( get_the_date( 'c' ) ),
+ esc_html( sprintf( $format_prefix, get_post_format_string( get_post_format() ), get_the_date() ) )
+ );
+
+ if ( $echo )
+ echo $date;
+
+ return $date;
+}
+endif;
+
+if ( ! function_exists( 'twentythirteen_the_attached_image' ) ) :
+/**
+ * Prints the attached image with a link to the next attached image.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_the_attached_image() {
+ $post = get_post();
+ $attachment_size = apply_filters( 'twentythirteen_attachment_size', array( 724, 724 ) );
+ $next_attachment_url = wp_get_attachment_url();
+
+ /**
+ * Grab the IDs of all the image attachments in a gallery so we can get the URL
+ * of the next adjacent image in a gallery, or the first image (if we're
+ * looking at the last image in a gallery), or, in a gallery of one, just the
+ * link to that image file.
+ */
+ $attachment_ids = get_posts( array(
+ 'post_parent' => $post->post_parent,
+ 'fields' => 'ids',
+ 'numberposts' => -1,
+ 'post_status' => 'inherit',
+ 'post_type' => 'attachment',
+ 'post_mime_type' => 'image',
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order ID'
+ ) );
+
+ // If there is more than 1 attachment in a gallery...
+ if ( count( $attachment_ids ) > 1 ) {
+ foreach ( $attachment_ids as $attachment_id ) {
+ if ( $attachment_id == $post->ID ) {
+ $next_id = current( $attachment_ids );
+ break;
+ }
+ }
+
+ // get the URL of the next image attachment...
+ if ( $next_id )
+ $next_attachment_url = get_attachment_link( $next_id );
+
+ // or get the URL of the first image attachment.
+ else
+ $next_attachment_url = get_attachment_link( array_shift( $attachment_ids ) );
+ }
+
+ printf( '<a href="%1$s" title="%2$s" rel="attachment">%3$s</a>',
+ esc_url( $next_attachment_url ),
+ the_title_attribute( array( 'echo' => false ) ),
+ wp_get_attachment_image( $post->ID, $attachment_size )
+ );
+}
+endif;
+
+/**
+ * Returns the URL from the post.
+ *
+ * @uses get_url_in_content() to get the URL in the post meta (if it exists) or
+ * the first link found in the post content.
+ *
+ * Falls back to the post permalink if no URL is found in the post.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return string The Link format URL.
+ */
+function twentythirteen_get_link_url() {
+ $content = get_the_content();
+ $has_url = get_url_in_content( $content );
+
+ return ( $has_url ) ? $has_url : apply_filters( 'the_permalink', get_permalink() );
+}
+
+/**
+ * Extends the default WordPress body classes.
+ *
+ * Adds body classes to denote:
+ * 1. Single or multiple authors.
+ * 2. Active widgets in the sidebar to change the layout and spacing.
+ * 3. When avatars are disabled in discussion settings.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @param array $classes A list of existing body class values.
+ * @return array The filtered body class list.
+ */
+function twentythirteen_body_class( $classes ) {
+ if ( ! is_multi_author() )
+ $classes[] = 'single-author';
+
+ if ( is_active_sidebar( 'sidebar-2' ) && ! is_attachment() && ! is_404() )
+ $classes[] = 'sidebar';
+
+ if ( ! get_option( 'show_avatars' ) )
+ $classes[] = 'no-avatars';
+
+ return $classes;
+}
+add_filter( 'body_class', 'twentythirteen_body_class' );
+
+/**
+ * Adjusts content_width value for video post formats and attachment templates.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_content_width() {
+ global $content_width;
+
+ if ( is_attachment() )
+ $content_width = 724;
+ elseif ( has_post_format( 'audio' ) )
+ $content_width = 484;
+}
+add_action( 'template_redirect', 'twentythirteen_content_width' );
+
+/**
+ * Add postMessage support for site title and description for the Customizer.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @param WP_Customize_Manager $wp_customize Customizer object.
+ * @return void
+ */
+function twentythirteen_customize_register( $wp_customize ) {
+ $wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
+ $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
+ $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';
+}
+add_action( 'customize_register', 'twentythirteen_customize_register' );
+
+/**
+ * Binds JavaScript handlers to make Customizer preview reload changes
+ * asynchronously.
+ *
+ * @since Twenty Thirteen 1.0
+ */
+function twentythirteen_customize_preview_js() {
+ wp_enqueue_script( 'twentythirteen-customizer', get_template_directory_uri() . '/js/theme-customizer.js', array( 'customize-preview' ), '20130226', true );
+}
+add_action( 'customize_preview_init', 'twentythirteen_customize_preview_js' );
diff --git a/src/wp-content/themes/twentythirteen/header.php b/src/wp-content/themes/twentythirteen/header.php
new file mode 100644
index 0000000000..52fce701eb
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/header.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * The Header for our theme.
+ *
+ * Displays all of the <head> section and everything up till <div id="main">
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+?><!DOCTYPE html>
+<!--[if IE 7]>
+<html class="ie ie7" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if IE 8]>
+<html class="ie ie8" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if !(IE 7) | !(IE 8) ]><!-->
+<html <?php language_attributes(); ?>>
+<!--<![endif]-->
+<head>
+ <meta charset="<?php bloginfo( 'charset' ); ?>">
+ <meta name="viewport" content="width=device-width">
+ <title><?php wp_title( '|', true, 'right' ); ?></title>
+ <link rel="profile" href="http://gmpg.org/xfn/11">
+ <link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>">
+ <!--[if lt IE 9]>
+ <script src="<?php echo get_template_directory_uri(); ?>/js/html5.js"></script>
+ <![endif]-->
+ <?php wp_head(); ?>
+</head>
+
+<body <?php body_class(); ?>>
+ <div id="page" class="hfeed site">
+ <header id="masthead" class="site-header" role="banner">
+ <a class="home-link" href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home">
+ <h1 class="site-title"><?php bloginfo( 'name' ); ?></h1>
+ <h2 class="site-description"><?php bloginfo( 'description' ); ?></h2>
+ </a>
+
+ <div id="navbar" class="navbar">
+ <nav id="site-navigation" class="navigation main-navigation" role="navigation">
+ <h3 class="menu-toggle"><?php _e( 'Menu', 'twentythirteen' ); ?></h3>
+ <a class="screen-reader-text skip-link" href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentythirteen' ); ?>"><?php _e( 'Skip to content', 'twentythirteen' ); ?></a>
+ <?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_class' => 'nav-menu' ) ); ?>
+ <?php get_search_form(); ?>
+ </nav><!-- #site-navigation -->
+ </div><!-- #navbar -->
+ </header><!-- #masthead -->
+
+ <div id="main" class="site-main">
diff --git a/src/wp-content/themes/twentythirteen/image.php b/src/wp-content/themes/twentythirteen/image.php
new file mode 100644
index 0000000000..4ef31c4bc2
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/image.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * The template for displaying image attachments.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+ <article id="post-<?php the_ID(); ?>" <?php post_class( 'image-attachment' ); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+
+ <div class="entry-meta">
+ <?php
+ $published_text = __( '<span class="attachment-meta">Published on <time class="entry-date" datetime="%1$s">%2$s</time> in <a href="%3$s" title="Return to %4$s" rel="gallery">%5$s</a></span>', 'twentythirteen' );
+ $post_title = get_the_title( $post->post_parent );
+ if ( empty( $post_title ) || 0 == $post->post_parent )
+ $published_text = '<span class="attachment-meta"><time class="entry-date" datetime="%1$s">%2$s</time></span>';
+
+ printf( $published_text,
+ esc_attr( get_the_date( 'c' ) ),
+ esc_html( get_the_date() ),
+ esc_url( get_permalink( $post->post_parent ) ),
+ esc_attr( strip_tags( $post_title ) ),
+ $post_title
+ );
+
+ $metadata = wp_get_attachment_metadata();
+ printf( '<span class="attachment-meta full-size-link"><a href="%1$s" title="%2$s">%3$s (%4$s &times; %5$s)</a></span>',
+ esc_url( wp_get_attachment_url() ),
+ esc_attr__( 'Link to full-size image', 'twentythirteen' ),
+ __( 'Full resolution', 'twentythirteen' ),
+ $metadata['width'],
+ $metadata['height']
+ );
+
+ edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' );
+ ?>
+ </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <nav id="image-navigation" class="navigation image-navigation" role="navigation">
+ <span class="nav-previous"><?php previous_image_link( false, __( '<span class="meta-nav">&larr;</span> Previous', 'twentythirteen' ) ); ?></span>
+ <span class="nav-next"><?php next_image_link( false, __( 'Next <span class="meta-nav">&rarr;</span>', 'twentythirteen' ) ); ?></span>
+ </nav><!-- #image-navigation -->
+
+ <div class="entry-attachment">
+ <div class="attachment">
+ <?php twentythirteen_the_attached_image(); ?>
+
+ <?php if ( has_excerpt() ) : ?>
+ <div class="entry-caption">
+ <?php the_excerpt(); ?>
+ </div>
+ <?php endif; ?>
+ </div><!-- .attachment -->
+ </div><!-- .entry-attachment -->
+
+ <?php if ( ! empty( $post->post_content ) ) : ?>
+ <div class="entry-description">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links">' . __( 'Pages:', 'twentythirteen' ), 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-description -->
+ <?php endif; ?>
+
+ </div><!-- .entry-content -->
+ </article><!-- #post -->
+
+ <?php comments_template(); ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/images/dotted-line-2x.png b/src/wp-content/themes/twentythirteen/images/dotted-line-2x.png
new file mode 100644
index 0000000000..07f6c93f29
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/dotted-line-2x.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/dotted-line-light-2x.png b/src/wp-content/themes/twentythirteen/images/dotted-line-light-2x.png
new file mode 100644
index 0000000000..059d4ec051
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/dotted-line-light-2x.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/dotted-line-light.png b/src/wp-content/themes/twentythirteen/images/dotted-line-light.png
new file mode 100644
index 0000000000..b7f82cdbfd
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/dotted-line-light.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/dotted-line.png b/src/wp-content/themes/twentythirteen/images/dotted-line.png
new file mode 100644
index 0000000000..115b583f7f
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/dotted-line.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/headers/circle-thumbnail.png b/src/wp-content/themes/twentythirteen/images/headers/circle-thumbnail.png
new file mode 100644
index 0000000000..2f9344c519
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/headers/circle-thumbnail.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/headers/circle.png b/src/wp-content/themes/twentythirteen/images/headers/circle.png
new file mode 100644
index 0000000000..0bd940197e
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/headers/circle.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/headers/diamond-thumbnail.png b/src/wp-content/themes/twentythirteen/images/headers/diamond-thumbnail.png
new file mode 100644
index 0000000000..82777a04cb
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/headers/diamond-thumbnail.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/headers/diamond.png b/src/wp-content/themes/twentythirteen/images/headers/diamond.png
new file mode 100644
index 0000000000..a14de61469
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/headers/diamond.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/headers/star-thumbnail.png b/src/wp-content/themes/twentythirteen/images/headers/star-thumbnail.png
new file mode 100644
index 0000000000..693bb7618b
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/headers/star-thumbnail.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/headers/star.png b/src/wp-content/themes/twentythirteen/images/headers/star.png
new file mode 100644
index 0000000000..24ca62686d
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/headers/star.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/search-icon-2x.png b/src/wp-content/themes/twentythirteen/images/search-icon-2x.png
new file mode 100644
index 0000000000..02b63b8027
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/search-icon-2x.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/images/search-icon.png b/src/wp-content/themes/twentythirteen/images/search-icon.png
new file mode 100644
index 0000000000..11d8dc8e50
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/images/search-icon.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/inc/back-compat.php b/src/wp-content/themes/twentythirteen/inc/back-compat.php
new file mode 100644
index 0000000000..8638adfa49
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/inc/back-compat.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Twenty Thirteen back compat functionality.
+ *
+ * Prevents Twenty Thirteen from running on WordPress versions prior to 3.6,
+ * since this theme is not meant to be backwards compatible and relies on
+ * many new functions and markup changes introduced in 3.6.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+/**
+ * Prevent switching to Twenty Thirteen on old versions of WordPress. Switches
+ * to the default theme.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_switch_theme() {
+ switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
+ unset( $_GET['activated'] );
+ add_action( 'admin_notices', 'twentythirteen_upgrade_notice' );
+}
+add_action( 'after_switch_theme', 'twentythirteen_switch_theme' );
+
+/**
+ * Prints an update nag after an unsuccessful attempt to switch to
+ * Twenty Thirteen on WordPress versions prior to 3.6.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_upgrade_notice() {
+ $message = sprintf( __( 'Twenty Thirteen requires at least WordPress version 3.6. You are running version %s. Please upgrade and try again.', 'twentythirteen' ), $GLOBALS['wp_version'] );
+ printf( '<div class="error"><p>%s</p></div>', $message );
+}
+
+/**
+ * Prevents the Customizer from being loaded on WordPress versions prior to 3.6.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_customize() {
+ wp_die( sprintf( __( 'Twenty Thirteen requires at least WordPress version 3.6. You are running version %s. Please upgrade and try again.', 'twentythirteen' ), $GLOBALS['wp_version'] ), '', array(
+ 'back_link' => true,
+ ) );
+}
+add_action( 'load-customize.php', 'twentythirteen_customize' );
+
+/**
+ * Prevents the Theme Preview from being loaded on WordPress versions prior to 3.4.
+ *
+ * @since Twenty Thirteen 1.0
+ *
+ * @return void
+ */
+function twentythirteen_preview() {
+ if ( isset( $_GET['preview'] ) ) {
+ wp_die( sprintf( __( 'Twenty Thirteen requires at least WordPress version 3.6. You are running version %s. Please upgrade and try again.', 'twentythirteen' ), $GLOBALS['wp_version'] ) );
+ }
+}
+add_action( 'template_redirect', 'twentythirteen_preview' ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/inc/custom-header.php b/src/wp-content/themes/twentythirteen/inc/custom-header.php
new file mode 100644
index 0000000000..a835061f79
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/inc/custom-header.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Implements a custom header for Twenty Thirteen.
+ * See http://codex.wordpress.org/Custom_Headers
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+/**
+ * Sets up the WordPress core custom header arguments and settings.
+ *
+ * @uses add_theme_support() to register support for 3.4 and up.
+ * @uses twentythirteen_header_style() to style front-end.
+ * @uses twentythirteen_admin_header_style() to style wp-admin form.
+ * @uses twentythirteen_admin_header_image() to add custom markup to wp-admin form.
+ * @uses register_default_headers() to set up the bundled header images.
+ *
+ * @since Twenty Thirteen 1.0
+ */
+function twentythirteen_custom_header_setup() {
+ $args = array(
+ // Text color and image (empty to use none).
+ 'default-text-color' => '220e10',
+ 'default-image' => '%s/images/headers/circle.png',
+
+ // Set height and width, with a maximum value for the width.
+ 'height' => 230,
+ 'width' => 1600,
+
+ // Callbacks for styling the header and the admin preview.
+ 'wp-head-callback' => 'twentythirteen_header_style',
+ 'admin-head-callback' => 'twentythirteen_admin_header_style',
+ 'admin-preview-callback' => 'twentythirteen_admin_header_image',
+ );
+
+ add_theme_support( 'custom-header', $args );
+
+ /*
+ * Default custom headers packaged with the theme.
+ * %s is a placeholder for the theme template directory URI.
+ */
+ register_default_headers( array(
+ 'circle' => array(
+ 'url' => '%s/images/headers/circle.png',
+ 'thumbnail_url' => '%s/images/headers/circle-thumbnail.png',
+ 'description' => _x( 'Circle', 'header image description', 'twentythirteen' )
+ ),
+ 'diamond' => array(
+ 'url' => '%s/images/headers/diamond.png',
+ 'thumbnail_url' => '%s/images/headers/diamond-thumbnail.png',
+ 'description' => _x( 'Diamond', 'header image description', 'twentythirteen' )
+ ),
+ 'star' => array(
+ 'url' => '%s/images/headers/star.png',
+ 'thumbnail_url' => '%s/images/headers/star-thumbnail.png',
+ 'description' => _x( 'Star', 'header image description', 'twentythirteen' )
+ ),
+ ) );
+}
+add_action( 'after_setup_theme', 'twentythirteen_custom_header_setup' );
+
+/**
+ * Loads our special font CSS files.
+ *
+ * @since Twenty Thirteen 1.0
+ */
+function twentythirteen_custom_header_fonts() {
+ // Add Open Sans and Bitter fonts.
+ wp_enqueue_style( 'twentythirteen-fonts', twentythirteen_fonts_url(), array(), null );
+
+ // Add Genericons font.
+ wp_enqueue_style( 'genericons', get_template_directory_uri() . '/fonts/genericons.css', array(), '2.09' );
+}
+add_action( 'admin_print_styles-appearance_page_custom-header', 'twentythirteen_custom_header_fonts' );
+
+/**
+ * Styles the header text displayed on the blog.
+ *
+ * get_header_textcolor() options: Hide text (returns 'blank'), or any hex value.
+ *
+ * @since Twenty Thirteen 1.0
+ */
+function twentythirteen_header_style() {
+ $header_image = get_header_image();
+ $text_color = get_header_textcolor();
+
+ // If no custom options for text are set, let's bail.
+ if ( empty( $header_image ) && $text_color == get_theme_support( 'custom-header', 'default-text-color' ) )
+ return;
+
+ // If we get this far, we have custom styles.
+ ?>
+ <style type="text/css" id="twentythirteen-header-css">
+ <?php
+ if ( ! empty( $header_image ) ) :
+ ?>
+ .site-header {
+ background: url(<?php header_image(); ?>) no-repeat scroll top;
+ background-size: 1600px auto;
+ }
+ <?php
+ endif;
+
+ // Has the text been hidden?
+ if ( ! display_header_text() ) :
+ ?>
+ .site-title,
+ .site-description {
+ position: absolute;
+ clip: rect(1px 1px 1px 1px); /* IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ <?php
+ if ( empty( $header_image ) ) :
+ ?>
+ .site-header .home-link {
+ min-height: 0;
+ }
+ <?php
+ endif;
+
+ // If the user has set a custom color for the text, use that.
+ elseif ( $text_color != get_theme_support( 'custom-header', 'default-text-color' ) ) :
+ ?>
+ .site-title,
+ .site-description {
+ color: #<?php echo esc_attr( $text_color ); ?>;
+ }
+ <?php endif; ?>
+ </style>
+ <?php
+}
+
+/**
+ * Styles the header image displayed on the Appearance > Header admin panel.
+ *
+ * @since Twenty Thirteen 1.0
+ */
+function twentythirteen_admin_header_style() {
+ $header_image = get_header_image();
+?>
+ <style type="text/css" id="twentythirteen-admin-header-css">
+ .appearance_page_custom-header #headimg {
+ border: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ <?php
+ if ( ! empty( $header_image ) ) {
+ echo 'background: url(' . esc_url( $header_image ) . ') no-repeat scroll top; background-size: 1600px auto;';
+ } ?>
+ padding: 0 20px;
+ }
+ #headimg .home-link {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ margin: 0 auto;
+ max-width: 1040px;
+ <?php
+ if ( ! empty( $header_image ) || display_header_text() ) {
+ echo 'min-height: 230px;';
+ } ?>
+ width: 100%;
+ }
+ <?php if ( ! display_header_text() ) : ?>
+ #headimg h1,
+ #headimg h2 {
+ position: absolute !important;
+ clip: rect(1px 1px 1px 1px); /* IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ <?php endif; ?>
+ #headimg h1 {
+ font: bold 60px/1 Bitter, Georgia, serif;
+ margin: 0;
+ padding: 58px 0 10px;
+ }
+ #headimg h1 a {
+ text-decoration: none;
+ }
+ #headimg h1 a:hover {
+ text-decoration: underline;
+ }
+ #headimg h2 {
+ font: 200 italic 24px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0;
+ text-shadow: none;
+ }
+ .default-header img {
+ max-width: 230px;
+ width: auto;
+ }
+ </style>
+<?php
+}
+
+/**
+ * Outputs markup to be displayed on the Appearance > Header admin panel.
+ * This callback overrides the default markup displayed there.
+ *
+ * @since Twenty Thirteen 1.0
+ */
+function twentythirteen_admin_header_image() {
+ ?>
+ <div id="headimg" style="background: url(<?php header_image(); ?>) no-repeat scroll top; background-size: 1600px auto;">
+ <?php $style = ' style="color:#' . get_header_textcolor() . ';"'; ?>
+ <div class="home-link">
+ <h1 class="displaying-header-text"><a id="name"<?php echo $style; ?> onclick="return false;" href="#"><?php bloginfo( 'name' ); ?></a></h1>
+ <h2 id="desc" class="displaying-header-text"<?php echo $style; ?>><?php bloginfo( 'description' ); ?></h2>
+ </div>
+ </div>
+<?php }
diff --git a/src/wp-content/themes/twentythirteen/index.php b/src/wp-content/themes/twentythirteen/index.php
new file mode 100644
index 0000000000..67faeafb2c
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/index.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * The main template file.
+ *
+ * This is the most generic template file in a WordPress theme and one of the
+ * two required files for a theme (the other being style.css).
+ * It is used to display a page when nothing more specific matches a query.
+ * For example, it puts together the home page when no home.php file exists.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+ <?php if ( have_posts() ) : ?>
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/js/functions.js b/src/wp-content/themes/twentythirteen/js/functions.js
new file mode 100644
index 0000000000..777a5cf468
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/js/functions.js
@@ -0,0 +1,81 @@
+/**
+ * Functionality specific to Twenty Thirteen.
+ *
+ * Provides helper functions to enhance the theme experience.
+ */
+
+( function( $ ) {
+ var body = $( 'body' ),
+ _window = $( window );
+
+ /**
+ * Adds a top margin to the footer if the sidebar widget area is higher
+ * than the rest of the page, to help the footer always visually clear
+ * the sidebar.
+ */
+ $( function() {
+ if ( body.is( '.sidebar' ) ) {
+ var sidebar = $( '#secondary .widget-area' ),
+ secondary = ( 0 == sidebar.length ) ? -40 : sidebar.height(),
+ margin = $( '#tertiary .widget-area' ).height() - $( '#content' ).height() - secondary;
+
+ if ( margin > 0 && _window.innerWidth() > 999 )
+ $( '#colophon' ).css( 'margin-top', margin + 'px' );
+ }
+ } );
+
+ /**
+ * Enables menu toggle for small screens.
+ */
+ ( function() {
+ var nav = $( '#site-navigation' ), button, menu;
+ if ( ! nav )
+ return;
+
+ button = nav.find( '.menu-toggle' );
+ if ( ! button )
+ return;
+
+ // Hide button if menu is missing or empty.
+ menu = nav.find( '.nav-menu' );
+ if ( ! menu || ! menu.children().length ) {
+ button.hide();
+ return;
+ }
+
+ $( '.menu-toggle' ).on( 'click.twentythirteen', function() {
+ nav.toggleClass( 'toggled-on' );
+ } );
+ } )();
+
+ /**
+ * Makes "skip to content" link work correctly in IE9 and Chrome for better
+ * accessibility.
+ *
+ * @link http://www.nczonline.net/blog/2013/01/15/fixing-skip-to-content-links/
+ */
+ _window.on( 'hashchange.twentythirteen', function() {
+ var element = document.getElementById( location.hash.substring( 1 ) );
+
+ if ( element ) {
+ if ( ! /^(?:a|select|input|button|textarea)$/i.test( element.tagName ) )
+ element.tabIndex = -1;
+
+ element.focus();
+ }
+ } );
+
+ /**
+ * Arranges footer widgets vertically.
+ */
+ if ( $.isFunction( $.fn.masonry ) ) {
+ var columnWidth = body.is( '.sidebar' ) ? 228 : 245;
+
+ $( '#secondary .widget-area' ).masonry( {
+ itemSelector: '.widget',
+ columnWidth: columnWidth,
+ gutterWidth: 20,
+ isRTL: body.is( '.rtl' )
+ } );
+ }
+} )( jQuery ); \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/js/html5.js b/src/wp-content/themes/twentythirteen/js/html5.js
new file mode 100644
index 0000000000..a7889168fb
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/js/html5.js
@@ -0,0 +1,7 @@
+/*! HTML5 Shiv v3.6 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
+/* Source: https://github.com/aFarkas/html5shiv */
+(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
+a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
+c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");
+var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,
+b){a||(a=f);if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document); \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/js/theme-customizer.js b/src/wp-content/themes/twentythirteen/js/theme-customizer.js
new file mode 100644
index 0000000000..640db0fa24
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/js/theme-customizer.js
@@ -0,0 +1,40 @@
+/**
+ * Theme Customizer enhancements for a better user experience.
+ *
+ * Contains handlers to make Theme Customizer preview reload changes asynchronously.
+ * Things like site title and description changes.
+ */
+
+( function( $ ) {
+ // Site title and description.
+ wp.customize( 'blogname', function( value ) {
+ value.bind( function( to ) {
+ $( '.site-title' ).text( to );
+ } );
+ } );
+ wp.customize( 'blogdescription', function( value ) {
+ value.bind( function( to ) {
+ $( '.site-description' ).text( to );
+ } );
+ } );
+ // Header text color.
+ wp.customize( 'header_textcolor', function( value ) {
+ value.bind( function( to ) {
+ if ( 'blank' == to ) {
+ if ( 'remove-header' == _wpCustomizeSettings.values.header_image )
+ $( '.home-link' ).css( 'min-height', '0' );
+ $( '.site-title, .site-description' ).css( {
+ 'clip': 'rect(1px, 1px, 1px, 1px)',
+ 'position': 'absolute'
+ } );
+ } else {
+ $( '.home-link' ).css( 'min-height', '230px' );
+ $( '.site-title, .site-description' ).css( {
+ 'clip': 'auto',
+ 'color': to,
+ 'position': 'relative'
+ } );
+ }
+ } );
+ } );
+} )( jQuery );
diff --git a/src/wp-content/themes/twentythirteen/languages/twentythirteen.pot b/src/wp-content/themes/twentythirteen/languages/twentythirteen.pot
new file mode 100644
index 0000000000..9212259466
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/languages/twentythirteen.pot
@@ -0,0 +1,329 @@
+# Copyright (C) 2013 the WordPress team
+# This file is distributed under the GNU General Public License v2 or later.
+msgid ""
+msgstr ""
+"Project-Id-Version: Twenty Thirteen 1.0\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tags/twentythirteen\n"
+"POT-Creation-Date: 2013-08-01 18:14:17+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: 404.php:16 content-none.php:12
+msgid "Nothing Found"
+msgstr ""
+
+#: 404.php:21
+msgid "This is somewhat embarrassing, isn&rsquo;t it?"
+msgstr ""
+
+#: 404.php:22
+msgid "It looks like nothing was found at this location. Maybe try a search?"
+msgstr ""
+
+#: archive.php:29
+msgid "Daily Archives: %s"
+msgstr ""
+
+#: archive.php:31
+msgid "Monthly Archives: %s"
+msgstr ""
+
+#: archive.php:31
+msgctxt "monthly archives date format"
+msgid "F Y"
+msgstr ""
+
+#: archive.php:33
+msgid "Yearly Archives: %s"
+msgstr ""
+
+#: archive.php:33
+msgctxt "yearly archives date format"
+msgid "Y"
+msgstr ""
+
+#: archive.php:35
+msgid "Archives"
+msgstr ""
+
+#: author-bio.php:16
+msgid "About %s"
+msgstr ""
+
+#: author-bio.php:20
+msgid "View all posts by %s <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: author.php:30
+msgid "All posts by %s"
+msgstr ""
+
+#: category.php:19
+msgid "Category Archives: %s"
+msgstr ""
+
+#: comments.php:25
+msgctxt "comments title"
+msgid "One thought on &ldquo;%2$s&rdquo;"
+msgid_plural "%1$s thoughts on &ldquo;%2$s&rdquo;"
+msgstr[0] ""
+msgstr[1] ""
+
+#: comments.php:45
+msgid "Comment navigation"
+msgstr ""
+
+#: comments.php:46
+msgid "&larr; Older Comments"
+msgstr ""
+
+#: comments.php:47
+msgid "Newer Comments &rarr;"
+msgstr ""
+
+#: comments.php:52
+msgid "Comments are closed."
+msgstr ""
+
+#: content-aside.php:13 content-audio.php:24 content-gallery.php:24
+#: content-image.php:23 content-link.php:24 content-quote.php:13
+#: content-status.php:13 content-video.php:23 content.php:39
+msgid "Continue reading <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: content-aside.php:14 content-audio.php:25 content-chat.php:24
+#: content-gallery.php:25 content-image.php:24 content-link.php:25
+#: content-quote.php:14 content-status.php:14 content-video.php:24
+#: content.php:40 image.php:70 page.php:35
+msgid "Pages:"
+msgstr ""
+
+#: content-aside.php:20 content-aside.php:28 content-audio.php:31
+#: content-chat.php:29 content-gallery.php:39 content-image.php:35
+#: content-link.php:19 content-quote.php:25 content-status.php:19
+#: content-video.php:35 content.php:29 image.php:44 page.php:39
+msgid "Edit"
+msgstr ""
+
+#: content-gallery.php:36 content-image.php:32 content-quote.php:22
+#: content-video.php:32 content.php:47
+msgid "Leave a comment"
+msgstr ""
+
+#: content-gallery.php:36 content-image.php:32 content-quote.php:22
+#: content-video.php:32 content.php:47
+msgid "One comment so far"
+msgstr ""
+
+#: content-gallery.php:36 content-image.php:32 content-quote.php:22
+#: content-video.php:32 content.php:47
+msgid "View all % comments"
+msgstr ""
+
+#: content-none.php:18
+msgid ""
+"Ready to publish your first post? <a href=\"%1$s\">Get started here</a>."
+msgstr ""
+
+#: content-none.php:22
+msgid ""
+"Sorry, but nothing matched your search terms. Please try again with "
+"different keywords."
+msgstr ""
+
+#: content-none.php:27
+msgid ""
+"It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps "
+"searching can help."
+msgstr ""
+
+#. #-#-#-#-# twentythirteen.pot (Twenty Thirteen 1.0) #-#-#-#-#
+#. Author URI of the plugin/theme
+#: footer.php:20
+msgid "http://wordpress.org/"
+msgstr ""
+
+#: footer.php:20
+msgid "Semantic Personal Publishing Platform"
+msgstr ""
+
+#: footer.php:20
+msgid "Proudly powered by %s"
+msgstr ""
+
+#: functions.php:93
+msgid "Navigation Menu"
+msgstr ""
+
+#. Translators: If there are characters in your language that are not
+#. * supported by Source Sans Pro, translate this to 'off'. Do not translate
+#. * into your own language.
+#: functions.php:124
+msgctxt "Source Sans Pro font: on or off"
+msgid "on"
+msgstr ""
+
+#. Translators: If there are characters in your language that are not
+#. * supported by Bitter, translate this to 'off'. Do not translate into your
+#. * own language.
+#: functions.php:130
+msgctxt "Bitter font: on or off"
+msgid "on"
+msgstr ""
+
+#: functions.php:212
+msgid "Page %s"
+msgstr ""
+
+#: functions.php:227
+msgid "Main Widget Area"
+msgstr ""
+
+#: functions.php:229
+msgid "Appears in the footer section of the site."
+msgstr ""
+
+#: functions.php:237
+msgid "Secondary Widget Area"
+msgstr ""
+
+#: functions.php:239
+msgid "Appears on posts and pages in the sidebar."
+msgstr ""
+
+#: functions.php:264
+msgid "Posts navigation"
+msgstr ""
+
+#: functions.php:268
+msgid "<span class=\"meta-nav\">&larr;</span> Older posts"
+msgstr ""
+
+#: functions.php:272
+msgid "Newer posts <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: functions.php:300
+msgid "Post navigation"
+msgstr ""
+
+#: functions.php:303
+msgctxt "Previous post link"
+msgid "<span class=\"meta-nav\">&larr;</span> %title"
+msgstr ""
+
+#: functions.php:304
+msgctxt "Next post link"
+msgid "%title <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: functions.php:324
+msgid "Sticky"
+msgstr ""
+
+#. Translators: used between list items, there is a space after the comma.
+#: functions.php:330 functions.php:336
+msgid ", "
+msgstr ""
+
+#: functions.php:345
+msgid "View all posts by %s"
+msgstr ""
+
+#: functions.php:365
+msgctxt "1: post format name. 2: date"
+msgid "%1$s on %2$s"
+msgstr ""
+
+#: functions.php:371
+msgid "Permalink to %s"
+msgstr ""
+
+#: header.php:43
+msgid "Menu"
+msgstr ""
+
+#: header.php:44
+msgid "Skip to content"
+msgstr ""
+
+#: image.php:22
+msgid ""
+"<span class=\"attachment-meta\">Published on <time class=\"entry-date\" "
+"datetime=\"%1$s\">%2$s</time> in <a href=\"%3$s\" title=\"Return to %4$s\" "
+"rel=\"gallery\">%5$s</a></span>"
+msgstr ""
+
+#: image.php:38
+msgid "Link to full-size image"
+msgstr ""
+
+#: image.php:39
+msgid "Full resolution"
+msgstr ""
+
+#: image.php:51
+msgid "<span class=\"meta-nav\">&larr;</span> Previous"
+msgstr ""
+
+#: image.php:52
+msgid "Next <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: inc/back-compat.php:38 inc/back-compat.php:50 inc/back-compat.php:65
+msgid ""
+"Twenty Thirteen requires at least WordPress version 3.6. You are running "
+"version %s. Please upgrade and try again."
+msgstr ""
+
+#: inc/custom-header.php:48
+msgctxt "header image description"
+msgid "Circle"
+msgstr ""
+
+#: inc/custom-header.php:53
+msgctxt "header image description"
+msgid "Diamond"
+msgstr ""
+
+#: inc/custom-header.php:58
+msgctxt "header image description"
+msgid "Star"
+msgstr ""
+
+#: search.php:18
+msgid "Search Results for: %s"
+msgstr ""
+
+#: tag.php:21
+msgid "Tag Archives: %s"
+msgstr ""
+
+#: taxonomy-post_format.php:23
+msgid "%s Archives"
+msgstr ""
+
+#. Theme Name of the plugin/theme
+msgid "Twenty Thirteen"
+msgstr ""
+
+#. Theme URI of the plugin/theme
+msgid "http://wordpress.org/themes/twentythirteen"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"The 2013 theme for WordPress takes us back to the blog, featuring a full "
+"range of post formats, each displayed beautifully in their own unique way. "
+"Design details abound, starting with a vibrant color scheme and matching "
+"header images, beautiful typography and icons, and a flexible layout that "
+"looks great on any device, big or small."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "the WordPress team"
+msgstr ""
diff --git a/src/wp-content/themes/twentythirteen/page.php b/src/wp-content/themes/twentythirteen/page.php
new file mode 100644
index 0000000000..06e38e7548
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/page.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * The template for displaying all pages.
+ *
+ * This is the template that displays all pages by default.
+ * Please note that this is the WordPress construct of pages and that other
+ * 'pages' on your WordPress site will use a different template.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( has_post_thumbnail() && ! post_password_required() ) : ?>
+ <div class="entry-thumbnail">
+ <?php the_post_thumbnail(); ?>
+ </div>
+ <?php endif; ?>
+
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'twentythirteen' ) . '</span>', 'after' => '</div>', 'link_before' => '<span>', 'link_after' => '</span>' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php edit_post_link( __( 'Edit', 'twentythirteen' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
+
+ <?php comments_template(); ?>
+ <?php endwhile; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/rtl.css b/src/wp-content/themes/twentythirteen/rtl.css
new file mode 100644
index 0000000000..5428630251
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/rtl.css
@@ -0,0 +1,766 @@
+/*
+Theme Name: Twenty Thirteen
+Description: Adds support for languages written in a Right To Left (RTL) direction.
+It's easy, just a matter of overwriting all the horizontal positioning attributes
+of your CSS stylesheet in a separate stylesheet file named rtl.css.
+
+See http://codex.wordpress.org/Right_to_Left_Language_Support
+*/
+
+/**
+ * Table of Contents:
+ *
+ * 1.0 - Reset
+ * 4.0 - Header
+ * 4.1 - Site Header
+ * 4.2 - Navigation
+ * 5.0 - Content
+ * 5.2 - Entry Meta
+ * 5.4 - Galleries
+ * 5.5 - Post Formats
+ * 5.6 - Attachments
+ * 5.7 - Post/Paging Navigation
+ * 5.8 - Author Bio
+ * 5.9 - Archives
+ * 5.10 - Search Results/No posts
+ * 5.12 - Comments
+ * 6.0 - Sidebar
+ * 6.1 - Widgets
+ * 7.0 - Footer
+ * 8.0 - Media Queries
+ * 9.0 - Print
+ * ----------------------------------------------------------------------------
+ */
+
+
+/**
+ * 1.0 Reset
+ * ----------------------------------------------------------------------------
+ */
+
+body {
+ direction: rtl;
+ unicode-bidi: embed;
+}
+
+a {
+ display: inline-block;
+}
+
+blockquote blockquote {
+ margin-left: 0;
+ margin-right: 24px;
+}
+
+menu,
+ol,
+ul {
+ padding: 0 40px 0 0;
+}
+
+caption,
+th,
+td {
+ text-align: right;
+}
+
+td {
+ padding-left: 10px;
+ padding-right: 0;
+}
+
+.assistive-text:focus {
+ left: auto;
+ right: 5px;
+}
+
+
+/**
+ * 4.0 Header
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ * 4.1 Site Header
+ * ----------------------------------------------------------------------------
+ */
+
+.site-header > a:first-child {
+ display: inherit;
+}
+
+.site-description {
+ font-style: normal;
+}
+
+
+/**
+ * 4.2 Navigation
+ * ----------------------------------------------------------------------------
+ */
+
+/* Navbar */
+ul.nav-menu,
+div.nav-menu > ul {
+ margin: 0 -20px 0 0;
+ padding: 0 0 0 40px;
+}
+
+.nav-menu .sub-menu,
+.nav-menu .children {
+ float: right;
+ left: auto;
+ right: -2px;
+}
+
+.nav-menu .sub-menu ul,
+.nav-menu .children ul {
+ border-left: 2px solid #f7f5e7;
+ border-right: 0;
+ left: auto;
+ right: 100%;
+}
+
+.main-navigation .search-form {
+ left: 0;
+ right: auto;
+}
+
+.site-header .search-field {
+ background-position: 98% center;
+ padding: 0 34px 0 0;
+}
+
+.nav-menu .current_page_item > a,
+.nav-menu .current_page_ancestor > a,
+.nav-menu .current-menu-item > a,
+.nav-menu .current-menu-ancestor > a {
+ font-style: normal;
+}
+
+.menu-toggle {
+ padding-left: 0;
+ padding-right: 20px;
+}
+
+
+/**
+ * 5.0 Content
+ * ----------------------------------------------------------------------------
+ */
+
+.sidebar .entry-header,
+.sidebar .entry-content,
+.sidebar .entry-summary,
+.sidebar .entry-meta {
+ padding-left: 376px;
+ padding-right: 60px;
+}
+
+
+/**
+ * 5.2 Entry Meta
+ * ----------------------------------------------------------------------------
+ */
+
+.entry-meta > span {
+ margin-left: 20px;
+ margin-right: auto;
+}
+
+.entry-meta > span:last-child {
+ margin-left: 0;
+ margin-right: auto;
+}
+
+.featured-post:before {
+ margin-left: 2px;
+ margin-right: auto;
+}
+
+.entry-meta .date a:before {
+ margin-left: 2px;
+}
+
+.comments-link a:before {
+ margin-left: 2px;
+ margin-right: auto;
+}
+
+.tags-links a:first-child:before {
+ margin-left: 2px;
+}
+
+.edit-link a:before {
+ margin-left: 2px;
+}
+
+.page-links .page-links-title {
+ margin-left: 20px;
+ margin-right: auto;
+}
+
+/**
+ * 5.4 Galleries
+ * ----------------------------------------------------------------------------
+ */
+
+.gallery {
+ margin-left: auto;
+ margin-right: -4px;
+}
+
+.gallery-item {
+ float: right;
+ margin: 0 0 4px 4px;
+}
+
+.gallery-item a {
+ display: inline;
+}
+
+
+/**
+ * 5.5 Post Formats
+ * ----------------------------------------------------------------------------
+ */
+
+.entry-content a {
+ display: inline;
+}
+
+.format-aside cite:before {
+ content: normal;
+ margin-right: auto;
+}
+
+.format-aside cite:after {
+ content: "\2014";
+ margin-left: 5px;
+}
+
+.format-audio .entry-content:before {
+ float: right;
+ -webkit-transform: scaleX(-1);
+ -moz-transform: scaleX(-1);
+ -ms-transform: scaleX(-1);
+ -o-transform: scaleX(-1);
+ transform: scaleX(-1);
+}
+
+.format-audio .audio-content {
+ background-position: right top;
+ float: left;
+ padding-left: 0;
+ padding-right: 35px;
+}
+
+.format-chat .entry-meta .date a:before {
+ margin-left: 4px;
+ margin-right: auto;
+}
+
+.format-image .wp-caption-text {
+ text-align: right;
+}
+
+.format-link .entry-title {
+ margin-left: 20px;
+ margin-right: auto;
+}
+
+.format-status .entry-content,
+.format-status .entry-meta {
+ padding-left: 0;
+ padding-right: 35px;
+}
+
+.sidebar .format-status .entry-content,
+.sidebar .format-status .entry-meta {
+ padding-left: 376px;
+ padding-right: 95px;
+}
+
+.format-status .entry-content:before,
+.format-status .entry-meta:before {
+ left: auto;
+ right: 10px;
+}
+
+.sidebar .format-status .entry-content:before,
+.sidebar .format-status .entry-meta:before {
+ left: auto;
+ right: 70px;
+}
+
+.format-status .entry-content p:first-child:before {
+ left: auto;
+ right: 4px;
+}
+
+.sidebar .format-status .entry-content p:first-child:before {
+ left: auto;
+ right: 64px;
+}
+
+.format-quote blockquote {
+ padding-left: 0;
+ padding-right: 75px;
+}
+
+.format-quote blockquote:before {
+ content: '\201D';
+ padding-left: 25px;
+ padding-right: 0;
+ left: auto;
+ right: -15px;
+}
+
+
+/**
+ * 5.6 Attachments
+ * ----------------------------------------------------------------------------
+ */
+
+.attachment .entry-title {
+ float: right;
+}
+
+.attachment .entry-title:before {
+ margin-left: 10px;
+ margin-right: auto;
+}
+
+.attachment .entry-meta {
+ float: left;
+}
+
+.image-navigation .nav-previous {
+ left: auto;
+ right: 0;
+}
+
+.image-navigation .nav-next {
+ left: 0;
+ right: auto;
+}
+
+.attachment .entry-caption {
+ text-align: right;
+}
+
+
+/**
+ * 5.7 Post/Paging Navigation
+ * ----------------------------------------------------------------------------
+ */
+
+.navigation .nav-previous {
+ float: right;
+}
+
+.navigation .nav-next {
+ float: left;
+}
+
+.sidebar .paging-navigation .nav-links,
+.sidebar .post-navigation .nav-links {
+ padding-left: 376px;
+ padding-right: 60px;
+}
+
+.paging-navigation .nav-previous .meta-nav {
+ margin-left: 10px;
+ margin-right: auto;
+}
+
+.paging-navigation .nav-next .meta-nav {
+ margin-left: auto;
+ margin-right: 10px;
+}
+
+.post-navigation a[rel="next"] {
+ float: left;
+ text-align: left;
+}
+
+
+/**
+ * 5.8 Author Bio
+ * ----------------------------------------------------------------------------
+ */
+
+.author-info {
+ text-align: right; /* gallery & video post formats */
+}
+
+.author.sidebar .author-info {
+ padding-left: 376px;
+ padding-right: 60px;
+}
+
+.author-avatar .avatar {
+ float: right;
+ margin: 0 0 30px 30px;
+}
+
+.author-link {
+ margin-left: auto;
+ margin-right: 2px;
+}
+
+
+/**
+ * 5.9 Archives
+ * ----------------------------------------------------------------------------
+ */
+
+.sidebar .archive-meta {
+ padding-left: 316px;
+ padding-right: 0;
+}
+
+
+/**
+ * 5.10 Search Results/No posts
+ * ----------------------------------------------------------------------------
+ */
+
+.sidebar .page-content {
+ padding-left: 376px;
+ padding-right: 60px;
+}
+
+/**
+ * 5.12 Comments
+ * ----------------------------------------------------------------------------
+ */
+
+.sidebar .comments-title,
+.sidebar .comment-list,
+.sidebar .comment-reply-title,
+.sidebar .comment-navigation,
+.sidebar .comment-respond .comment-form {
+ padding-left: 376px;
+ padding-right: 60px;
+}
+
+.comment-list .children {
+ margin-left: auto;
+ margin-right: 20px;
+}
+
+.comment-author {
+ float: right;
+ margin-left: 50px;
+ margin-right: auto;
+}
+
+.comment-list .edit-link {
+ margin-left: auto;
+ margin-right: 20px;
+}
+
+.comment-metadata,
+.comment-content,
+.comment-list .reply,
+.comment-awaiting-moderation {
+ float: left;
+}
+
+.comment-awaiting-moderation:before {
+ margin-left: 5px;
+ margin-right: auto;
+}
+
+.comment-reply-link:before,
+.comment-reply-login:before {
+ margin-left: 3px;
+ margin-right: auto;
+ -webkit-transform: scaleX(-1);
+ -moz-transform: scaleX(-1);
+ -ms-transform: scaleX(-1);
+ -o-transform: scaleX(-1);
+ transform: scaleX(-1);
+}
+
+.comment-reply-title small a {
+ float: left;
+}
+
+.comment-form [for="author"],
+.comment-form [for="email"],
+.comment-form [for="url"],
+.comment-form [for="comment"] {
+ float: right;
+}
+
+.form-allowed-tags code {
+ margin-left: auto;
+ margin-right: 3px;
+}
+
+.sidebar .no-comments {
+ padding-left: 376px;
+ padding-right: 60px;
+}
+
+
+/**
+ * 6.0 Sidebar
+ * ----------------------------------------------------------------------------
+ */
+
+.site-main .widget-area {
+ float: left;
+}
+
+.widget-area a {
+ max-width: 100%;
+}
+
+
+/**
+ * 6.1 Widgets
+ * ----------------------------------------------------------------------------
+ */
+
+.widget .widget-title {
+ font-style: normal;
+}
+
+.widget li > ul,
+.widget li > ol {
+ margin-left: auto;
+ margin-right: 20px;
+}
+
+/**
+ * 7.0 Footer
+ * ----------------------------------------------------------------------------
+ */
+
+.site-footer .widget-area,
+.sidebar .site-footer {
+ text-align: right;
+}
+.sidebar .site-footer .widget-area {
+ left: auto;
+ right: -158px;
+}
+
+.site-footer .widget {
+ float: right;
+ margin-left: 20px;
+ margin-right: auto;
+}
+
+.sidebar .site-footer .widget:nth-of-type(4),
+.sidebar .site-footer .widget:nth-of-type(3) {
+ margin-left: 0;
+ margin-right: auto;
+}
+
+
+/**
+ * 8.0 Media Queries
+ * ----------------------------------------------------------------------------
+ */
+
+@media (max-width: 1069px) {
+ ul.nav-menu,
+ div.nav-menu > ul {
+ margin-left: auto;
+ margin-right: 0;
+ }
+
+ .error404 .page-header,
+ .sidebar .format-image .entry-content img.size-full,
+ .sidebar .format-image .wp-caption:first-child .wp-caption-text {
+ margin-right: auto;
+ }
+
+ .main-navigation .search-form {
+ left: 20px;
+ right: auto;
+ }
+
+ .site-main .widget-area {
+ margin-left: 60px;
+ margin-right: auto;
+ }
+}
+
+@media (max-width: 999px) {
+ .sidebar .entry-header,
+ .sidebar .entry-content,
+ .sidebar .entry-summary,
+ .sidebar .entry-meta,
+ .sidebar .comment-list,
+ .sidebar .comment-reply-title,
+ .sidebar .comment-navigation,
+ .sidebar .comment-respond .comment-form,
+ .sidebar .featured-gallery,
+ .sidebar .post-navigation .nav-links,
+ .author.sidebar .author-info,
+ .sidebar .format-image .entry-content {
+ max-width: 604px;
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .site-main .widget-area {
+ float: none;
+ margin-left: auto;
+ }
+
+ .attachment .entry-meta {
+ float: right;
+ text-align: right;
+ }
+
+ .sidebar .format-status .entry-content,
+ .sidebar .format-status .entry-meta {
+ padding-left: 0;
+ padding-right: 35px;
+ }
+
+ .sidebar .format-status .entry-content:before,
+ .sidebar .format-status .entry-meta:before {
+ left: auto;
+ right: 10px;
+ }
+
+ .sidebar .format-status .entry-content p:first-child:before {
+ left: auto;
+ right: 4px;
+ }
+
+ .sidebar .site-footer .widget-area {
+ left: auto;
+ right: 0;
+ }
+
+ .sidebar .paging-navigation .nav-links {
+ padding: 0 60px;
+ }
+}
+
+@media (max-width: 767px) {
+ .format-image .entry-content img:first-of-type,
+ .format-image .wp-caption:first-child .wp-caption-text {
+ margin-right: auto;
+ }
+}
+
+@media (max-width: 643px) {
+ .sidebar .entry-header,
+ .sidebar .entry-content,
+ .sidebar .entry-summary,
+ .sidebar .entry-meta,
+ .sidebar .comment-list,
+ .sidebar .comment-navigation,
+ .sidebar .featured-gallery,
+ .sidebar .post-navigation .nav-links,
+ .sidebar .format-image .entry-content {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+
+ #content .format-status .entry-content,
+ #content .format-status .entry-met {
+ padding-left: 0;
+ padding-right: 35px;
+ }
+
+ .menu-toggle:after {
+ padding-left: 0;
+ padding-right: 8px;
+ }
+
+ .toggled-on .nav-menu,
+ .toggled-on .nav-menu > ul {
+ margin-left: auto;
+ margin-right: 0;
+ }
+
+ .toggled-on .nav-menu li > ul {
+ margin-left: auto;
+ margin-right: 20px;
+ right: auto;
+ }
+
+ #content .featured-gallery {
+ padding-left: 0;
+ padding-right: 24px;
+ }
+
+ .gallery-columns-1 .gallery-item {
+ margin-left: 0;
+ margin-right: auto;
+ }
+
+ .comment-author {
+ margin-left: 30px;
+ margin-right: auto;
+ }
+
+ .format-audio .audio-content {
+ background: none;
+ float: none;
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .gallery-columns-3 .gallery-item:nth-of-type(3n) {
+ margin-left: 4px;
+ margin-right: auto;
+ }
+}
+
+@media (max-width: 359px) {
+ .gallery {
+ margin-left: auto;
+ margin-right: 0;
+ }
+
+ .gallery .gallery-item:nth-of-type(even) {
+ margin-left: 0;
+ margin-right: auto;
+ }
+
+ .gallery .gallery-item,
+ .gallery.gallery-columns-3 .gallery-item:nth-of-type(even),
+ .gallery-columns-3 .gallery-item:nth-of-type(3n),
+ .gallery-columns-5 .gallery-item:nth-of-type(5n),
+ .gallery-columns-7 .gallery-item:nth-of-type(7n),
+ .gallery-columns-9 .gallery-item:nth-of-type(9n) {
+ margin-left: 4px;
+ margin-right: auto;
+ }
+
+ .comment-author .avatar {
+ margin-left: 5px;
+ margin-right: auto;
+ }
+}
+
+
+/**
+ * 9.0 Print
+ * ----------------------------------------------------------------------------
+ */
+
+@media print {
+ .entry-content img.alignleft,
+ .entry-content .wp-caption.alignleft {
+ margin-left: auto;
+ margin-right: 0;
+ }
+
+ .entry-content img.alignright,
+ .entry-content .wp-caption.alignright {
+ margin-left: 0;
+ margin-right: auto;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/screenshot.png b/src/wp-content/themes/twentythirteen/screenshot.png
new file mode 100644
index 0000000000..199c8d5368
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/screenshot.png
Binary files differ
diff --git a/src/wp-content/themes/twentythirteen/search.php b/src/wp-content/themes/twentythirteen/search.php
new file mode 100644
index 0000000000..7839defaef
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/search.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * The template for displaying Search Results pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentythirteen' ), get_search_query() ); ?></h1>
+ </header>
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/sidebar-main.php b/src/wp-content/themes/twentythirteen/sidebar-main.php
new file mode 100644
index 0000000000..bb6034c2a6
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/sidebar-main.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * The sidebar containing the footer widget area.
+ *
+ * If no active widgets in this sidebar, it will be hidden completely.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+if ( is_active_sidebar( 'sidebar-1' ) ) : ?>
+ <div id="secondary" class="sidebar-container" role="complementary">
+ <div class="widget-area">
+ <?php dynamic_sidebar( 'sidebar-1' ); ?>
+ </div><!-- .widget-area -->
+ </div><!-- #secondary -->
+<?php endif; ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/sidebar.php b/src/wp-content/themes/twentythirteen/sidebar.php
new file mode 100644
index 0000000000..750945ccca
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/sidebar.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * The sidebar containing the secondary widget area, displays on posts and pages.
+ *
+ * If no active widgets in this sidebar, it will be hidden completely.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+if ( is_active_sidebar( 'sidebar-2' ) ) : ?>
+ <div id="tertiary" class="sidebar-container" role="complementary">
+ <div class="sidebar-inner">
+ <div class="widget-area">
+ <?php dynamic_sidebar( 'sidebar-2' ); ?>
+ </div><!-- .widget-area -->
+ </div><!-- .sidebar-inner -->
+ </div><!-- #tertiary -->
+<?php endif; ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/single.php b/src/wp-content/themes/twentythirteen/single.php
new file mode 100644
index 0000000000..6901828c36
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/single.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * The Template for displaying all single posts.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php twentythirteen_post_nav(); ?>
+ <?php comments_template(); ?>
+
+ <?php endwhile; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/style.css b/src/wp-content/themes/twentythirteen/style.css
new file mode 100644
index 0000000000..60d0416d66
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/style.css
@@ -0,0 +1,3121 @@
+/*
+Theme Name: Twenty Thirteen
+Theme URI: http://wordpress.org/themes/twentythirteen
+Author: the WordPress team
+Author URI: http://wordpress.org/
+Description: The 2013 theme for WordPress takes us back to the blog, featuring a full range of post formats, each displayed beautifully in their own unique way. Design details abound, starting with a vibrant color scheme and matching header images, beautiful typography and icons, and a flexible layout that looks great on any device, big or small.
+Version: 1.0
+License: GNU General Public License v2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+Tags: black, brown, orange, tan, white, yellow, light, one-column, two-columns, right-sidebar, flexible-width, custom-header, custom-menu, editor-style, featured-images, microformats, post-formats, rtl-language-support, sticky-post, translation-ready
+Text Domain: twentythirteen
+
+This theme, like WordPress, is licensed under the GPL.
+Use it to make something cool, have fun, and share what you've learned with others.
+*/
+
+
+/**
+ * Table of Contents:
+ *
+ * 1.0 - Reset
+ * 2.0 - Repeatable Patterns
+ * 3.0 - Basic Structure
+ * 4.0 - Header
+ * 4.1 - Site Header
+ * 4.2 - Navigation
+ * 5.0 - Content
+ * 5.1 - Entry Header
+ * 5.2 - Entry Meta
+ * 5.3 - Entry Content
+ * 5.4 - Galleries
+ * 5.5 - Post Formats
+ * 5.6 - Attachments
+ * 5.7 - Post/Paging Navigation
+ * 5.8 - Author Bio
+ * 5.9 - Archives
+ * 5.10 - Search Results/No posts
+ * 5.11 - 404
+ * 5.12 - Comments
+ * 5.13 - Multisite
+ * 6.0 - Sidebar
+ * 6.1 - Widgets
+ * 7.0 - Footer
+ * 8.0 - Media Queries
+ * 9.0 - Print
+ * ----------------------------------------------------------------------------
+ */
+
+
+/**
+ * 1.0 Reset
+ *
+ * Modified from Normalize.css to provide cross-browser consistency and a smart
+ * default styling of HTML elements.
+ *
+ * @see http://git.io/normalize
+ * ----------------------------------------------------------------------------
+ */
+
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+nav,
+section,
+summary {
+ display: block;
+}
+
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+[hidden] {
+ display: none;
+}
+
+html {
+ font-size: 100%;
+ overflow-y: scroll;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+
+html,
+button,
+input,
+select,
+textarea {
+ font-family: "Source Sans Pro", Helvetica, sans-serif;
+}
+
+body {
+ color: #141412;
+ line-height: 1.5;
+ margin: 0;
+}
+
+a {
+ color: #ca3c08;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #ac0404;
+}
+
+a:focus {
+ outline: thin dotted;
+}
+
+a:active,
+a:hover {
+ color: #ea9629;
+ outline: 0;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ clear: both;
+ font-family: Bitter, Georgia, serif;
+ line-height: 1.3;
+}
+
+h1 {
+ font-size: 48px;
+ margin: 33px 0;
+}
+
+h2 {
+ font-size: 30px;
+ margin: 25px 0;
+}
+
+h3 {
+ font-size: 22px;
+ margin: 22px 0;
+}
+
+h4 {
+ font-size: 20px;
+ margin: 25px 0;
+}
+
+h5 {
+ font-size: 18px;
+ margin: 30px 0;
+}
+
+h6 {
+ font-size: 16px;
+ margin: 36px 0;
+}
+
+address {
+ font-style: italic;
+ margin: 0 0 24px;
+}
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+b,
+strong {
+ font-weight: bold;
+}
+
+dfn {
+ font-style: italic;
+}
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+p {
+ margin: 0 0 24px;
+}
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, serif;
+ font-size: 14px;
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+pre {
+ background: #f5f5f5;
+ color: #666;
+ font-family: monospace;
+ font-size: 14px;
+ margin: 20px 0;
+ overflow: auto;
+ padding: 20px;
+ white-space: pre;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+blockquote,
+q {
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+ quotes: none;
+}
+
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+ content: "";
+ content: none;
+}
+
+blockquote {
+ font-size: 18px;
+ font-style: italic;
+ font-weight: 300;
+ margin: 24px 40px;
+}
+
+blockquote blockquote {
+ margin-right: 0;
+}
+
+blockquote cite,
+blockquote small {
+ font-size: 14px;
+ font-weight: normal;
+ text-transform: uppercase;
+}
+
+blockquote em,
+blockquote i {
+ font-style: normal;
+ font-weight: 300;
+}
+
+blockquote strong,
+blockquote b {
+ font-weight: 400;
+}
+
+small {
+ font-size: smaller;
+}
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+dl {
+ margin: 0 20px;
+}
+
+dt {
+ font-weight: bold;
+}
+
+dd {
+ margin: 0 0 20px;
+}
+
+menu,
+ol,
+ul {
+ margin: 16px 0;
+ padding: 0 0 0 40px;
+}
+
+ul {
+ list-style-type: square;
+}
+
+nav ul,
+nav ol {
+ list-style: none;
+ list-style-image: none;
+}
+
+li > ul,
+li > ol {
+ margin: 0;
+}
+
+img {
+ -ms-interpolation-mode: bicubic;
+ border: 0;
+ vertical-align: middle;
+}
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+figure {
+ margin: 0;
+}
+
+form {
+ margin: 0;
+}
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+legend {
+ border: 0;
+ padding: 0;
+ white-space: normal;
+}
+
+button,
+input,
+select,
+textarea {
+ font-size: 100%;
+ margin: 0;
+ max-width: 100%;
+ vertical-align: baseline;
+}
+
+button,
+input {
+ line-height: normal;
+}
+
+button,
+html input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ -webkit-appearance: button;
+ cursor: pointer;
+}
+
+button[disabled],
+input[disabled] {
+ cursor: default;
+}
+
+input[type="checkbox"],
+input[type="radio"] {
+ padding: 0;
+}
+
+input[type="search"] {
+ -webkit-appearance: textfield;
+ padding-right: 2px; /* Don't cut off the webkit search cancel button */
+ width: 270px;
+}
+
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+textarea {
+ overflow: auto;
+ vertical-align: top;
+}
+
+table {
+ border-bottom: 1px solid #ededed;
+ border-collapse: collapse;
+ border-spacing: 0;
+ font-size: 14px;
+ line-height: 2;
+ margin: 0 0 20px;
+ width: 100%;
+}
+
+caption,
+th,
+td {
+ font-weight: normal;
+ text-align: left;
+}
+
+caption {
+ font-size: 16px;
+ margin: 20px 0;
+}
+
+th {
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+td {
+ border-top: 1px solid #ededed;
+ padding: 6px 10px 6px 0;
+}
+
+del {
+ color: #333;
+}
+
+ins {
+ background: #fff9c0;
+ text-decoration: none;
+}
+
+hr {
+ background: url(images/dotted-line.png) repeat center top;
+ background-size: 4px 4px;
+ border: 0;
+ height: 1px;
+ margin: 0 0 24px;
+}
+
+
+/**
+ * 2.0 Repeatable Patterns
+ * ----------------------------------------------------------------------------
+ */
+
+.genericon:before,
+.menu-toggle:after,
+.featured-post:before,
+.date a:before,
+.entry-meta .author a:before,
+.format-audio .entry-content:before,
+.comments-link a:before,
+.tags-links a:first-child:before,
+.categories-links a:first-child:before,
+.edit-link a:before,
+.attachment .entry-title:before,
+.attachment-meta:before,
+.attachment-meta a:before,
+.comment-awaiting-moderation:before,
+.comment-reply-link:before,
+.comment-reply-login:before,
+.comment-reply-title small a:before,
+.bypostauthor > .comment-body .fn:before,
+.error404 .page-title:before {
+ -webkit-font-smoothing: antialiased;
+ display: inline-block;
+ font: normal 16px/1 Genericons;
+ vertical-align: text-bottom;
+}
+
+/* Clearing floats */
+.clear:after,
+.attachment .entry-header:after,
+.site-footer .widget-area:after,
+.entry-content:after,
+.page-content:after,
+.navigation:after,
+.nav-links:after,
+.gallery:after,
+.comment-form-author:after,
+.comment-form-email:after,
+.comment-form-url:after,
+.comment-body:after {
+ clear: both;
+}
+
+.clear:before,
+.clear:after,
+.attachment .entry-header:before,
+.attachment .entry-header:after,
+.site-footer .widget-area:before,
+.site-footer .widget-area:after,
+.entry-content:before,
+.entry-content:after,
+.page-content:before,
+.page-content:after,
+.navigation:before,
+.navigation:after,
+.nav-links:before,
+.nav-links:after,
+.gallery:before,
+.gallery:after,
+.comment-form-author:before,
+.comment-form-author:after,
+.comment-form-email:before,
+.comment-form-email:after,
+.comment-form-url:before,
+.comment-form-url:after,
+.comment-body:before,
+.comment-body:after {
+ content: "";
+ display: table;
+}
+
+/* Assistive text */
+.screen-reader-text {
+ clip: rect(1px, 1px, 1px, 1px);
+ position: absolute !important;
+}
+
+.screen-reader-text:focus {
+ background-color: #f1f1f1;
+ border-radius: 3px;
+ box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
+ clip: auto !important;
+ color: #21759b;
+ display: block;
+ font-size: 14px;
+ font-weight: bold;
+ height: auto;
+ line-height: normal;
+ padding: 15px 23px 14px;
+ position: absolute;
+ left: 5px;
+ top: 5px;
+ text-decoration: none;
+ width: auto;
+ z-index: 100000; /* Above WP toolbar */
+}
+
+/* Form fields, general styles first. */
+button,
+input,
+textarea {
+ border: 2px solid #d4d0ba;
+ font-family: inherit;
+ padding: 5px;
+}
+
+input,
+textarea {
+ color: #141412;
+}
+
+input:focus,
+textarea:focus {
+ border: 2px solid #c3c0ab;
+ outline: 0;
+}
+
+/* Buttons */
+button,
+input[type="submit"],
+input[type="button"],
+input[type="reset"] {
+ background: #e05d22; /* Old browsers */
+ background: -webkit-linear-gradient(top, #e05d22 0%, #d94412 100%); /* Chrome 10+, Safari 5.1+ */
+ background: linear-gradient(to bottom, #e05d22 0%, #d94412 100%); /* W3C */
+ border: none;
+ border-bottom: 3px solid #b93207;
+ border-radius: 2px;
+ color: #fff;
+ display: inline-block;
+ padding: 11px 24px 10px;
+ text-decoration: none;
+}
+
+button:hover,
+button:focus,
+input[type="submit"]:hover,
+input[type="button"]:hover,
+input[type="reset"]:hover,
+input[type="submit"]:focus,
+input[type="button"]:focus,
+input[type="reset"]:focus {
+ background: #ed6a31; /* Old browsers */
+ background: -webkit-linear-gradient(top, #ed6a31 0%, #e55627 100%); /* Chrome 10+, Safari 5.1+ */
+ background: linear-gradient(to bottom, #ed6a31 0%, #e55627 100%); /* W3C */
+ outline: none;
+}
+
+button:active,
+input[type="submit"]:active,
+input[type="button"]:active,
+input[type="reset"]:active {
+ background: #d94412; /* Old browsers */
+ background: -webkit-linear-gradient(top, #d94412 0%, #e05d22 100%); /* Chrome 10+, Safari 5.1+ */
+ background: linear-gradient(to bottom, #d94412 0%, #e05d22 100%); /* W3C */
+ border: none;
+ border-top: 3px solid #b93207;
+ padding: 10px 24px 11px;
+}
+
+.post-password-required input[type="submit"] {
+ padding: 7px 24px 4px;
+ vertical-align: bottom;
+}
+
+.post-password-required input[type="submit"]:active {
+ padding: 5px 24px 6px;
+}
+
+/* Placeholder text color -- selectors need to be separate to work. */
+::-webkit-input-placeholder {
+ color: #7d7b6d;
+}
+
+:-moz-placeholder {
+ color: #7d7b6d;
+}
+
+::-moz-placeholder {
+ color: #7d7b6d;
+}
+
+:-ms-input-placeholder {
+ color: #7d7b6d;
+}
+
+/*
+ * Responsive images
+ *
+ * Fluid images for posts, comments, and widgets
+ */
+.entry-content img,
+.entry-summary img,
+.comment-content img,
+.widget img,
+.wp-caption {
+ max-width: 100%;
+}
+
+/* Make sure images with WordPress-added height and width attributes are scaled correctly. */
+.entry-content img,
+.entry-summary img,
+.comment-content img[height],
+img[class*="align"],
+img[class*="wp-image-"],
+img[class*="attachment-"] {
+ height: auto;
+}
+
+img.size-full,
+img.size-large,
+img.wp-post-image {
+ height: auto;
+ max-width: 100%;
+}
+
+/* Make sure videos and embeds fit their containers. */
+embed,
+iframe,
+object,
+video {
+ max-width: 100%;
+}
+
+/* Override the Twitter embed fixed width. */
+.entry-content .twitter-tweet-rendered {
+ max-width: 100% !important;
+}
+
+/* Images */
+.alignleft {
+ float: left;
+}
+
+.alignright {
+ float: right;
+}
+
+.aligncenter {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+img.alignleft {
+ margin: 5px 20px 5px 0;
+}
+
+.wp-caption.alignleft {
+ margin: 5px 10px 5px 0;
+}
+
+img.alignright {
+ margin: 5px 0 5px 20px;
+}
+
+.wp-caption.alignright {
+ margin: 5px 0 5px 10px;
+}
+
+img.aligncenter {
+ margin: 5px auto;
+}
+
+img.alignnone {
+ margin: 5px 0;
+}
+
+.wp-caption .wp-caption-text,
+.entry-caption,
+.gallery-caption {
+ color: #220e10;
+ font-size: 18px;
+ font-style: italic;
+ font-weight: 300;
+}
+
+img.wp-smiley,
+.rsswidget img {
+ border: 0;
+ border-radius: 0;
+ box-shadow: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+
+.wp-caption.alignleft + ul,
+.wp-caption.alignleft + ol {
+ list-style-position: inside;
+}
+
+
+/**
+ * 3.0 Basic Structure
+ * ----------------------------------------------------------------------------
+ */
+
+.site {
+ background-color: #fff;
+ border-left: 1px solid #f2f2f2;
+ border-right: 1px solid #f2f2f2;
+ margin: 0 auto;
+ max-width: 1600px;
+ width: 100%;
+}
+
+.site-main {
+ position: relative;
+}
+
+.site-main .sidebar-container {
+ height: 0;
+ position: absolute;
+ top: 40px;
+ width: 100%;
+ z-index: 1;
+}
+
+.site-main .sidebar-inner {
+ margin: 0 auto;
+ max-width: 1040px;
+}
+
+
+/**
+ * 4.0 Header
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ * 4.1 Site Header
+ * ----------------------------------------------------------------------------
+ */
+
+.site-header {
+ position: relative;
+}
+
+.site-header .home-link {
+ color: #141412;
+ display: block;
+ margin: 0 auto;
+ max-width: 1080px;
+ min-height: 230px;
+ padding: 0 20px;
+ text-decoration: none;
+ width: 100%;
+}
+
+.site-header .site-title:hover {
+ text-decoration: underline;
+}
+
+.site-title {
+ font-size: 60px;
+ font-weight: bold;
+ line-height: 1;
+ margin: 0;
+ padding: 58px 0 10px;
+}
+
+.site-description {
+ font: 300 italic 24px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0;
+}
+
+
+/**
+ * 4.2 Navigation
+ * ----------------------------------------------------------------------------
+ */
+
+.main-navigation {
+ clear: both;
+ margin: 0 auto;
+ max-width: 1080px;
+ min-height: 45px;
+ position: relative;
+}
+
+ul.nav-menu,
+div.nav-menu > ul {
+ margin: 0;
+ padding: 0 40px 0 0;
+}
+
+.nav-menu li {
+ display: inline-block;
+ position: relative;
+}
+
+.nav-menu li a {
+ color: #141412;
+ display: block;
+ font-size: 15px;
+ line-height: 1;
+ padding: 15px 20px;
+ text-decoration: none;
+}
+
+.nav-menu li:hover > a,
+.nav-menu li a:hover {
+ background-color: #220e10;
+ color: #fff;
+}
+
+.nav-menu .sub-menu,
+.nav-menu .children {
+ background-color: #220e10;
+ border: 2px solid #f7f5e7;
+ border-top: 0;
+ display: none;
+ padding: 0;
+ position: absolute;
+ left: -2px;
+ z-index: 99999;
+}
+
+.nav-menu .sub-menu ul,
+.nav-menu .children ul {
+ border-left: 0;
+ left: 100%;
+ top: 0;
+}
+
+ul.nav-menu ul a,
+.nav-menu ul ul a {
+ color: #fff;
+ margin: 0;
+ width: 200px;
+}
+
+ul.nav-menu ul a:hover,
+.nav-menu ul ul a:hover {
+ background-color: #db572f;
+}
+
+ul.nav-menu li:hover > ul,
+.nav-menu ul li:hover > ul {
+ display: block;
+}
+
+.nav-menu .current_page_item > a,
+.nav-menu .current_page_ancestor > a,
+.nav-menu .current-menu-item > a,
+.nav-menu .current-menu-ancestor > a {
+ color: #bc360a;
+ font-style: italic;
+}
+
+.menu-toggle {
+ display: none;
+}
+
+/* Navbar */
+.navbar {
+ background-color: #f7f5e7;
+ margin: 0 auto;
+ max-width: 1600px;
+ width: 100%;
+}
+
+.site-header .search-form {
+ position: absolute;
+ right: 20px;
+ top: 1px;
+}
+
+.site-header .search-field {
+ background-color: transparent;
+ background-image: url(images/search-icon.png);
+ background-position: 5px center;
+ background-repeat: no-repeat;
+ background-size: 24px 24px;
+ border: none;
+ cursor: pointer;
+ height: 37px;
+ margin: 3px 0;
+ padding: 0 0 0 34px;
+ position: relative;
+ -webkit-transition: width 400ms ease, background 400ms ease;
+ transition: width 400ms ease, background 400ms ease;
+ width: 0;
+}
+
+.site-header .search-field:focus {
+ background-color: #fff;
+ border: 2px solid #c3c0ab;
+ cursor: text;
+ outline: 0;
+ width: 230px;
+}
+
+
+/**
+ * 5.0 Content
+ * ----------------------------------------------------------------------------
+ */
+
+.hentry {
+ padding: 40px 0;
+}
+
+.entry-header,
+.entry-content,
+.entry-summary,
+.entry-meta {
+ margin: 0 auto;
+ max-width: 604px;
+ width: 100%;
+}
+
+.sidebar .entry-header,
+.sidebar .entry-content,
+.sidebar .entry-summary,
+.sidebar .entry-meta {
+ max-width: 1040px;
+ padding: 0 376px 0 60px;
+}
+
+
+/**
+ * 5.1 Entry Header
+ * ----------------------------------------------------------------------------
+ */
+
+.sidebar .entry-header .entry-meta {
+ padding: 0;
+}
+
+.entry-thumbnail img {
+ display: block;
+ margin: 0 auto 10px;
+}
+
+.entry-header {
+ margin-bottom: 30px;
+}
+
+.entry-title {
+ font-weight: normal;
+ margin: 0 0 5px;
+}
+
+.entry-title a {
+ color: #141412;
+}
+
+.entry-title a:hover {
+ color: #ea9629;
+}
+
+
+/**
+ * 5.2 Entry Meta
+ * ----------------------------------------------------------------------------
+ */
+
+.entry-meta {
+ clear: both;
+ font-size: 14px;
+}
+
+.entry-meta a {
+ color: #bc360a;
+}
+
+.entry-meta a:hover {
+ color: #bc360a;
+}
+
+.entry-meta > span {
+ margin-right: 20px;
+}
+
+.entry-meta > span:last-child {
+ margin-right: 0;
+}
+
+.featured-post:before {
+ content: "\f308";
+ margin-right: 2px;
+}
+
+.entry-meta .date a:before {
+ content: "\f303";
+}
+
+.comments-link a:before {
+ content: "\f300";
+ margin-right: 2px;
+ position: relative;
+ top: -1px;
+}
+
+.entry-meta .author a:before {
+ content: "\f304";
+ position: relative;
+ top: -1px;
+}
+
+.categories-links a:first-child:before {
+ content: "\f301";
+}
+
+.tags-links a:first-child:before {
+ content: "\f302";
+ position: relative;
+ top: -1px;
+}
+
+.edit-link a:before {
+ content: "\f411";
+ position: relative;
+ top: -1px;
+}
+
+.single-author .entry-meta .author,
+.sticky.format-standard .entry-meta .date,
+.sticky.format-audio .entry-meta .date,
+.sticky.format-chat .entry-meta .date,
+.sticky.format-image .entry-meta .date,
+.sticky.format-gallery .entry-meta .date {
+ display: none;
+}
+
+
+/**
+ * 5.3 Entry Content
+ * ----------------------------------------------------------------------------
+ */
+
+.entry-content {
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ hyphens: auto;
+ word-wrap: break-word;
+}
+
+.entry-content a,
+.comment-content a {
+ color: #bc360a;
+}
+
+.entry-content a:hover,
+.comment-content a:hover {
+ color: #ea9629;
+}
+
+.entry-content blockquote {
+ font-size: 24px;
+}
+
+.entry-content blockquote cite,
+.entry-content blockquote small {
+ font-size: 16px;
+}
+
+.entry-content img.alignleft,
+.entry-content .wp-caption.alignleft {
+ margin-left: -60px;
+}
+
+.entry-content img.alignright,
+.entry-content .wp-caption.alignright {
+ margin-right: -60px;
+}
+
+footer.entry-meta {
+ margin-top: 24px;
+}
+
+.format-standard footer.entry-meta {
+ margin-top: 0;
+}
+
+/* Page links */
+.page-links {
+ clear: both;
+ font-size: 16px;
+ font-style: italic;
+ font-weight: normal;
+ line-height: 2.2;
+ margin: 20px 0;
+ text-transform: uppercase;
+}
+
+.page-links a,
+.page-links > span {
+ background: #fff;
+ border: 1px solid #fff;
+ padding: 5px 10px;
+ text-decoration: none;
+}
+
+.format-status .entry-content .page-links a,
+.format-gallery .entry-content .page-links a,
+.format-chat .entry-content .page-links a,
+.format-quote .entry-content .page-links a,
+.page-links a {
+ background: #e63f2a;
+ border: 1px solid #e63f2a;
+ color: #fff;
+}
+
+.format-gallery .entry-content .page-links a:hover,
+.format-audio .entry-content .page-links a:hover,
+.format-status .entry-content .page-links a:hover,
+.format-video .entry-content .page-links a:hover,
+.format-chat .entry-content .page-links a:hover,
+.format-quote .entry-content .page-links a:hover,
+.page-links a:hover {
+ background: #fff;
+ color: #e63f2a;
+}
+
+.format-status .entry-content .page-links > span,
+.format-quote .entry-content .page-links > span {
+ background: none;
+}
+
+.page-links .page-links-title {
+ background: transparent;
+ border: none;
+ margin-right: 20px;
+ padding: 0;
+}
+
+/* Mediaelements */
+.hentry .mejs-mediaelement,
+.hentry .mejs-container .mejs-controls {
+ background: #220e10;
+}
+
+.hentry .mejs-controls .mejs-time-rail .mejs-time-loaded,
+.hentry .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current {
+ background: #fff;
+}
+
+.hentry .mejs-controls .mejs-time-rail .mejs-time-current {
+ background: #ea9629;
+}
+
+.hentry .mejs-controls .mejs-time-rail .mejs-time-total,
+.hentry .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total {
+ background: #595959;
+}
+
+.hentry .mejs-controls .mejs-time-rail span,
+.hentry .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total,
+.hentry .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current {
+ border-radius: 0;
+}
+
+
+/**
+ * 5.4 Galleries
+ * ----------------------------------------------------------------------------
+ */
+
+.gallery {
+ margin-bottom: 20px;
+ margin-left: -4px;
+}
+
+.gallery-item {
+ float: left;
+ margin: 0 4px 4px 0;
+ overflow: hidden;
+ position: relative;
+}
+
+.gallery-columns-1.gallery-size-medium,
+.gallery-columns-1.gallery-size-thumbnail,
+.gallery-columns-2.gallery-size-thumbnail,
+.gallery-columns-3.gallery-size-thumbnail {
+ display: table;
+ margin: 0 auto 20px;
+}
+
+.gallery-columns-1 .gallery-item,
+.gallery-columns-2 .gallery-item,
+.gallery-columns-3 .gallery-item {
+ text-align: center;
+}
+
+.gallery-columns-4 .gallery-item {
+ max-width: 23%;
+ max-width: -webkit-calc(25% - 4px);
+ max-width: calc(25% - 4px);
+}
+
+.gallery-columns-5 .gallery-item {
+ max-width: 19%;
+ max-width: -webkit-calc(20% - 4px);
+ max-width: calc(20% - 4px);
+}
+
+.gallery-columns-6 .gallery-item {
+ max-width: 15%;
+ max-width: -webkit-calc(16.7% - 4px);
+ max-width: calc(16.7% - 4px);
+}
+
+.gallery-columns-7 .gallery-item {
+ max-width: 13%;
+ max-width: -webkit-calc(14.28% - 4px);
+ max-width: calc(14.28% - 4px);
+}
+
+.gallery-columns-8 .gallery-item {
+ max-width: 11%;
+ max-width: -webkit-calc(12.5% - 4px);
+ max-width: calc(12.5% - 4px);
+}
+
+.gallery-columns-9 .gallery-item {
+ max-width: 9%;
+ max-width: -webkit-calc(11.1% - 4px);
+ max-width: calc(11.1% - 4px);
+}
+
+.gallery-columns-1 .gallery-item:nth-of-type(1n),
+.gallery-columns-2 .gallery-item:nth-of-type(2n),
+.gallery-columns-3 .gallery-item:nth-of-type(3n),
+.gallery-columns-4 .gallery-item:nth-of-type(4n),
+.gallery-columns-5 .gallery-item:nth-of-type(5n),
+.gallery-columns-6 .gallery-item:nth-of-type(6n),
+.gallery-columns-7 .gallery-item:nth-of-type(7n),
+.gallery-columns-8 .gallery-item:nth-of-type(8n),
+.gallery-columns-9 .gallery-item:nth-of-type(9n) {
+ margin-right: 0;
+}
+
+.gallery-caption {
+ background-color: rgba(0, 0, 0, 0.7);
+ box-sizing: border-box;
+ color: #fff;
+ font-size: 14px;
+ line-height: 1.3;
+ margin: 0;
+ max-height: 50%;
+ opacity: 0;
+ padding: 2px 8px;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ text-align: left;
+ -webkit-transition: opacity 400ms ease;
+ transition: opacity 400ms ease;
+ width: 100%;
+}
+
+.gallery-caption:before {
+ box-shadow: 0 -10px 15px #000 inset;
+ content: "";
+ height: 100%;
+ min-height: 49px;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+}
+
+.gallery-item:hover .gallery-caption {
+ opacity: 1;
+}
+
+.gallery-columns-7 .gallery-caption,
+.gallery-columns-8 .gallery-caption,
+.gallery-columns-9 .gallery-caption {
+ display: none;
+}
+
+
+/**
+ * 5.5 Post Formats
+ * ----------------------------------------------------------------------------
+ */
+
+/* Aside */
+.format-aside {
+ background-color: #f7f5e7;
+}
+
+.blog .format-aside:first-of-type,
+.single .format-aside:first-of-type,
+.format-aside + .format-aside,
+.format-aside + .format-link,
+.format-link + .format-aside {
+ box-shadow: inset 0 2px 2px rgba(173, 165, 105, 0.2);
+}
+
+.format-aside .entry-meta {
+ margin-top: 0;
+}
+
+.format-aside blockquote {
+ font-size: 100%;
+ font-weight: normal;
+}
+
+.format-aside cite {
+ font-size: 100%;
+ text-transform: none;
+}
+
+.format-aside cite:before {
+ content: "\2014";
+ margin-right: 5px;
+}
+
+/* Audio */
+.format-audio {
+ background-color: #db572f;
+}
+
+.format-audio .entry-title {
+ font-size: 28px;
+ font-weight: bold;
+}
+
+.format-audio .entry-content:before {
+ content: "\f109";
+ float: left;
+ font-size: 64px;
+ position: relative;
+ top: 4px;
+}
+
+.format-audio .entry-content a,
+.format-audio .entry-meta a,
+.format-audio .entry-content a:hover,
+.format-audio .entry-meta a:hover {
+ color: #fbfaf3;
+}
+
+.format-audio .audio-content {
+ background: url(images/dotted-line.png) repeat-y left top;
+ background-size: 4px 4px;
+ float: right;
+ padding-left: 35px;
+ width: 80%;
+ width: -webkit-calc(100% - 85px);
+ width: calc(100% - 85px);
+}
+
+.format-audio .wp-audio-shortcode {
+ height: 30px !important; /* Override mediaelement.js style */
+ margin: 20px 0;
+ max-width: 400px !important; /* Override mediaelement.js style */
+}
+
+.format-audio audio {
+ max-width: 100% !important; /* Avoid player width overflow. */
+}
+
+/* Chat */
+.format-chat {
+ background-color: #eadaa6;
+}
+
+.format-chat .entry-title {
+ font-size: 28px;
+ font-weight: bold;
+}
+
+.format-chat .entry-meta a,
+.format-chat .entry-content a {
+ color: #722d19;
+}
+
+.format-chat .entry-meta .date a:before {
+ content: "\f108";
+ margin-right: 2px;
+}
+
+.format-chat .entry-meta .author {
+ display: none;
+}
+
+.format-chat .chat {
+ margin: 0;
+}
+
+.format-chat .chat .chat-timestamp {
+ color: #722d19;
+ float: right;
+ font-size: 12px;
+ font-weight: normal;
+ margin: 5px 10px 0;
+}
+
+.format-chat .chat .fn {
+ font-style: normal;
+}
+
+/* Gallery */
+.format-gallery {
+ background-color: #fbca3c;
+}
+
+.format-gallery .entry-header {
+ margin-bottom: 15px;
+}
+
+.format-gallery .entry-title {
+ font-size: 50px;
+ font-weight: 400;
+ margin: 0;
+}
+
+.format-gallery .entry-meta a,
+.format-gallery .entry-content a {
+ color: #722d19;
+}
+
+/* Image */
+.format-image .entry-title {
+ font-size: 28px;
+ font-weight: bold;
+}
+
+.format-image .categories-links,
+.format-image .tags-links {
+ display: none;
+}
+
+/* Link */
+.format-link {
+ background-color: #f7f5e7;
+}
+
+.blog .format-link:first-of-type,
+.single .format-link:first-of-type {
+ box-shadow: inset 0 2px 2px rgba(173, 165, 105, 0.2);
+}
+
+.format-link .entry-header,
+.format-link .entry-content p:last-child {
+ margin-bottom: 0;
+}
+
+.format-link .entry-title {
+ color: #ca3c08;
+ display: inline;
+ font: 300 italic 20px "Source Sans Pro", Helvetica, sans-serif;
+ margin-right: 20px;
+}
+
+.format-link .entry-title a {
+ color: #bc360a;
+}
+
+.format-link div.entry-meta {
+ display: inline;
+}
+
+/* Quote */
+.format-quote {
+ background-color: #210d10;
+}
+
+.format-quote .entry-content,
+.format-quote .entry-meta {
+ color: #f7f5e7;
+}
+
+.format-quote .entry-content blockquote {
+ font-size: 28px;
+ margin: 0;
+}
+
+.format-quote .entry-content a,
+.format-quote .entry-meta a,
+.format-quote .linked {
+ color: #e63f2a;
+}
+
+.format-quote .entry-content cite a {
+ border-bottom: 1px dotted #fff;
+ color: #fff;
+}
+
+.format-quote .entry-content cite a:hover {
+ text-decoration: none;
+}
+
+.format-quote blockquote small,
+.format-quote blockquote cite {
+ display: block;
+ font-size: 16px;
+}
+
+.format-quote blockquote {
+ font-style: italic;
+ font-weight: 300;
+ padding-left: 75px;
+ position: relative;
+}
+
+.format-quote blockquote:before {
+ content: '\201C';
+ font-size: 140px;
+ font-weight: 400;
+ line-height: .8;
+ padding-right: 25px;
+ position: absolute;
+ left: -15px;
+ top: -3px;
+}
+
+.format-quote .entry-meta .author {
+ display: none;
+}
+
+/* Status */
+.format-status {
+ background-color: #722d19;
+ padding: 0;
+}
+
+.format-status .entry-content,
+.format-status .entry-meta {
+ padding-left: 35px;
+ position: relative;
+}
+
+.format-status .entry-content a {
+ color: #eadaa6;
+}
+
+.format-status .entry-meta a {
+ color: #f7f5e7;
+}
+
+.sidebar .format-status .entry-content,
+.sidebar .format-status .entry-meta {
+ padding-left: 95px;
+}
+
+.format-status .entry-content:before,
+.format-status .entry-meta:before {
+ background: url(images/dotted-line.png) repeat-y left bottom;
+ background-size: 4px 4px;
+ content: "";
+ display: block;
+ height: 100%;
+ position: absolute;
+ left: 10px;
+ top: 0;
+ width: 1px;
+}
+
+.sidebar .format-status .entry-content:before,
+.sidebar .format-status .entry-meta:before {
+ left: 70px;
+}
+
+.format-status .categories-links,
+.format-status .tags-links {
+ display: none;
+}
+
+/* Ensures the dots in the dot background are in lockstep. */
+.format-status .entry-meta:before {
+ background-position: left top;
+}
+
+.format-status .entry-content {
+ color: #f7f5e7;
+ font-size: 24px;
+ font-style: italic;
+ font-weight: 300;
+ padding-bottom: 30px;
+ padding-top: 40px;
+ position: relative;
+}
+
+.format-status .entry-content p:first-child:before {
+ background-color: rgba(0, 0, 0, 0.65);
+ content: "";
+ height: 3px;
+ margin-top: 13px;
+ position: absolute;
+ left: 4px;
+ width: 13px;
+}
+
+.sidebar .format-status .entry-content > p:first-child:before {
+ left: 64px;
+}
+
+.format-status .entry-content p:last-child {
+ margin-bottom: 0;
+}
+
+.format-status .entry-meta {
+ margin-top: 0;
+ padding-bottom: 40px;
+}
+
+.format-status .entry-meta .date a:before {
+ content: "\f105";
+}
+
+/* Video */
+.format-video {
+ background-color: #db572f;
+}
+
+.format-video .entry-content a,
+.format-video .entry-meta a,
+.format-video .entry-content a:hover,
+.format-video .entry-meta a:hover {
+ color: #fbfaf3;
+}
+
+.format-video .entry-title {
+ font-size: 50px;
+ font-weight: 400;
+}
+
+.format-video .entry-meta {
+ color: #220e10;
+}
+
+
+/**
+ * 5.6 Attachments
+ * ----------------------------------------------------------------------------
+ */
+
+.attachment .hentry {
+ background-color: #e8e5ce;
+ margin: 0;
+ padding: 0;
+}
+
+.attachment .entry-header {
+ margin-bottom: 0;
+ max-width: 1040px;
+ padding: 30px 0;
+}
+
+.attachment .entry-title {
+ display: inline-block;
+ float: left;
+ font: 300 italic 30px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0;
+}
+
+.attachment .entry-title:before {
+ content: "\f416";
+ font-size: 32px;
+ margin-right: 10px;
+}
+
+.attachment .entry-meta {
+ clear: none;
+ color: inherit;
+ float: right;
+ max-width: 604px;
+ padding: 9px 0 0;
+ text-align: right;
+}
+
+.hentry.attachment:not(.image-attachment) .entry-meta {
+ max-width: 104px;
+}
+
+.attachment footer.entry-meta,
+.single-attachment .site-main .sidebar-container {
+ display: none;
+}
+
+.attachment-meta:before {
+ content: "\f307";
+}
+
+.full-size-link a:before {
+ content: "\f402";
+}
+
+.full-size-link:before {
+ content: none;
+}
+
+.attachment .entry-meta a,
+.attachment .entry-meta .edit-link:before,
+.attachment .full-size-link:before {
+ color: #ca3c08;
+}
+
+.attachment .entry-content {
+ background-color: #fff;
+ max-width: 100%;
+ padding: 40px 0;
+}
+
+.image-navigation {
+ margin: 0 auto;
+ max-width: 1040px;
+ position: relative;
+}
+
+.image-navigation a:hover {
+ text-decoration: none;
+}
+
+.image-navigation .nav-previous,
+.image-navigation .nav-next {
+ position: absolute;
+ top: 50px;
+}
+
+.image-navigation .nav-previous {
+ left: 0;
+}
+
+.image-navigation .nav-next {
+ right: 0;
+}
+
+.image-navigation .meta-nav {
+ font-size: 32px;
+ font-weight: 300;
+ vertical-align: -4px;
+}
+
+.attachment .entry-attachment,
+.attachment p.attachment {
+ margin: 0 auto;
+ max-width: 724px;
+ text-align: center;
+}
+
+.attachment .entry-attachment .attachment {
+ display: inline-block;
+}
+
+.attachment .entry-caption {
+ text-align: left;
+}
+
+.attachment .entry-description {
+ margin: 20px auto 0;
+ max-width: 604px;
+}
+
+.attachment .entry-caption p:last-child,
+.attachment .entry-description p:last-child {
+ margin: 0;
+}
+
+
+/**
+ * 5.7 Post/Paging Navigation
+ * ----------------------------------------------------------------------------
+ */
+
+.navigation .nav-previous {
+ float: left;
+}
+
+.navigation .nav-next {
+ float: right;
+}
+
+.navigation a {
+ color: #bc360a;
+}
+
+.navigation a:hover {
+ color: #ea9629;
+ text-decoration: none;
+}
+
+.paging-navigation {
+ background-color: #e8e5ce;
+ padding: 40px 0;
+}
+
+.paging-navigation .nav-links {
+ margin: 0 auto;
+ max-width: 604px;
+ width: 100%;
+}
+
+.sidebar .paging-navigation .nav-links {
+ max-width: 1040px;
+ padding: 0 376px 0 60px;
+}
+
+.paging-navigation .nav-next {
+ padding: 13px 0;
+}
+
+.paging-navigation a {
+ font-size: 22px;
+ font-style: italic;
+ font-weight: 300;
+}
+
+.paging-navigation .meta-nav {
+ background-color: #e63f2a;
+ border-radius: 50%;
+ color: #fff;
+ display: inline-block;
+ font-size: 26px;
+ padding: 3px 0 8px;
+ text-align: center;
+ width: 50px;
+}
+
+.paging-navigation .nav-previous .meta-nav {
+ margin-right: 10px;
+ padding: 17px 0 23px;
+ width: 80px;
+}
+
+.paging-navigation .nav-next .meta-nav {
+ margin-left: 10px;
+}
+
+.paging-navigation a:hover .meta-nav {
+ background-color: #ea9629;
+ text-decoration: none;
+}
+
+.post-navigation {
+ background-color: #fff;
+ color: #ca3c08;
+ font-size: 20px;
+ font-style: italic;
+ font-weight: 300;
+ padding: 20px 0;
+}
+
+.post-navigation .nav-links {
+ margin: 0 auto;
+ max-width: 1040px;
+}
+
+.sidebar .post-navigation .nav-links {
+ padding: 0 376px 0 60px;
+}
+
+.post-navigation a[rel="next"] {
+ float: right;
+ text-align: right;
+}
+
+
+/**
+ * 5.8 Author Bio
+ * ----------------------------------------------------------------------------
+ */
+
+.author-info {
+ margin: 0 auto;
+ max-width: 604px;
+ padding: 30px 0 10px;
+ text-align: left; /* gallery & video post formats */
+ width: 100%;
+}
+
+.author.sidebar .author-info {
+ max-width: 1040px;
+ padding: 30px 376px 10px 60px;
+}
+
+.single .author-info {
+ padding: 50px 0 0;
+}
+
+.author-avatar .avatar {
+ float: left;
+ margin: 0 30px 30px 0;
+}
+
+.single-format-status .author-description {
+ color: #f7f5e7;
+}
+
+.author-description .author-title {
+ clear: none;
+ font: 300 italic 20px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0 0 8px;
+}
+
+.author-link {
+ color: #ca3c08;
+ margin-left: 2px;
+}
+
+.author.archive .author-link {
+ display: none;
+}
+
+
+/**
+ * 5.9 Archives
+ * ----------------------------------------------------------------------------
+ */
+
+.archive-header {
+ background-color: #e8e5ce;
+}
+
+.archive-title,
+.archive-meta {
+ font: 300 italic 30px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0 auto;
+ max-width: 1040px;
+ padding: 30px 0;
+ width: 100%;
+}
+
+.archive-meta {
+ font-size: 16px;
+ font-style: normal;
+ font-weight: normal;
+ margin-top: -15px;
+ padding: 0 0 11px;
+}
+
+.sidebar .archive-meta {
+ padding-right: 316px;
+}
+
+
+/**
+ * 5.10 Search Results/No posts
+ * ----------------------------------------------------------------------------
+ */
+
+.page-header {
+ background-color: #e8e5ce;
+}
+
+.page-title {
+ font: 300 italic 30px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0 auto;
+ max-width: 1040px;
+ padding: 30px 0;
+ width: 100%;
+}
+
+.page-content {
+ margin: 0 auto;
+ max-width: 604px;
+ padding: 40px 0;
+ width: 100%;
+}
+
+.sidebar .page-content {
+ margin: 0 auto;
+ max-width: 1040px;
+ padding: 40px 376px 40px 60px;
+}
+
+
+/**
+ * 5.11 404
+ * ----------------------------------------------------------------------------
+ */
+
+.error404 .page-header {
+ background-color: #fff;
+}
+
+.error404 .page-title {
+ line-height: 0.6;
+ margin: 0;
+ padding: 300px;
+ position: relative;
+ text-align: center;
+ width: auto;
+}
+
+.error404 .page-title:before {
+ color: #e8e5ce;
+ content: "\f423";
+ font-size: 964px;
+ line-height: 0.6;
+ overflow: hidden;
+ position: absolute;
+ left: 7px;
+ top: 28px;
+}
+
+.error404 .page-wrapper {
+ background-color: #e8e5ce;
+}
+
+.error404 .page-header,
+.error404 .page-content {
+ margin: 0 auto;
+ max-width: 1040px;
+ padding-bottom: 40px;
+ width: 100%;
+}
+
+
+/**
+ * 5.12 Comments
+ * ----------------------------------------------------------------------------
+ */
+
+.comments-title,
+.comment-list,
+.comment-reply-title,
+.must-log-in,
+.comment-respond .comment-form,
+.comment-respond iframe {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 604px;
+ width: 100%;
+}
+
+.sidebar .comments-title,
+.sidebar .comment-list,
+.sidebar .must-log-in,
+.sidebar .comment-reply-title,
+.sidebar .comment-navigation,
+.sidebar .comment-respond .comment-form {
+ max-width: 1040px;
+ padding-left: 60px;
+ padding-right: 376px;
+}
+
+.comments-title {
+ font: 300 italic 28px "Source Sans Pro", Helvetica, sans-serif;
+}
+
+.comment-list,
+.comment-list .children {
+ list-style-type: none;
+ padding: 0;
+}
+
+.comment-list .children {
+ margin-left: 20px;
+}
+
+.comment-list > li:after,
+.comment-list .children > li:before {
+ background: url(images/dotted-line.png) repeat left top;
+ background-size: 4px 4px;
+ content: "";
+ display: block;
+ height: 1px;
+ width: 100%;
+}
+
+.comment-list > li:last-child:after {
+ display: none;
+}
+
+.comment-body {
+ padding: 24px 0;
+ position: relative;
+}
+
+.comment-author {
+ float: left;
+ max-width: 74px;
+}
+
+.comment-author .avatar {
+ display: block;
+ margin-bottom: 10px;
+}
+
+.comment-author .fn {
+ word-wrap: break-word;
+}
+
+.comment-author .fn,
+.comment-author .url,
+.comment-reply-link,
+.comment-reply-login {
+ color: #bc360a;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: normal;
+}
+
+.says {
+ display: none;
+}
+
+.no-avatars .comment-author {
+ margin: 0 0 5px;
+ max-width: 100%;
+ position: relative;
+}
+
+.no-avatars .comment-metadata,
+.no-avatars .comment-content,
+.no-avatars .comment-list .reply {
+ width: 100%;
+}
+
+.bypostauthor > .comment-body .fn:before {
+ content: "\f408";
+ vertical-align: text-top;
+}
+
+.comment-list .edit-link {
+ margin-left: 20px;
+}
+
+.comment-metadata,
+.comment-awaiting-moderation,
+.comment-content,
+.comment-list .reply {
+ float: right;
+ width: 79%;
+ width: -webkit-calc(100% - 124px);
+ width: calc(100% - 124px);
+}
+
+.comment-meta,
+.comment-meta a {
+ color: #a2a2a2;
+ font-size: 13px;
+}
+
+.comment-meta a:hover {
+ color: #ea9629;
+}
+
+.comment-metadata {
+ margin-bottom: 20px;
+}
+
+.ping-meta {
+ color: #a2a2a2;
+ font-size: 13px;
+ line-height: 2;
+}
+
+.comment-awaiting-moderation {
+ color: #a2a2a2;
+}
+
+.comment-awaiting-moderation:before {
+ content: "\f414";
+ margin-right: 5px;
+ position: relative;
+ top: -2px;
+}
+
+.comment-reply-link:before,
+.comment-reply-login:before {
+ content: "\f412";
+ margin-right: 3px;
+}
+
+/* Comment form */
+.comment-respond {
+ background-color: #f7f5e7;
+ padding: 30px 0;
+}
+
+.comment .comment-respond {
+ margin-bottom: 20px;
+ padding: 20px;
+}
+
+.comment-reply-title {
+ font: 300 italic 28px "Source Sans Pro", Helvetica, sans-serif;
+}
+
+.comment-reply-title small a {
+ color: #131310;
+ display: inline-block;
+ float: right;
+ height: 16px;
+ overflow: hidden;
+ width: 16px;
+}
+
+.comment-reply-title small a:hover {
+ color: #ed331c;
+ text-decoration: none;
+}
+
+.comment-reply-title small a:before {
+ content: "\f406";
+ vertical-align: top;
+}
+
+.sidebar .comment-list .comment-reply-title,
+.sidebar .comment-list .comment-respond .comment-form {
+ padding: 0;
+}
+
+.comment-form .comment-notes {
+ margin-bottom: 15px;
+}
+
+.comment-form .comment-form-author,
+.comment-form .comment-form-email,
+.comment-form .comment-form-url {
+ margin-bottom: 8px;
+}
+
+.comment-form [for="author"],
+.comment-form [for="email"],
+.comment-form [for="url"],
+.comment-form [for="comment"] {
+ float: left;
+ padding: 5px 0;
+ width: 120px;
+}
+
+.comment-form .required {
+ color: #ed331c;
+}
+
+.comment-form input[type="text"],
+.comment-form input[type="email"],
+.comment-form input[type="url"] {
+ max-width: 270px;
+ width: 60%;
+}
+
+.comment-form textarea {
+ width: 100%;
+}
+
+.form-allowed-tags,
+.form-allowed-tags code {
+ color: #686758;
+ font-size: 12px;
+}
+
+.form-allowed-tags code {
+ font-size: 10px;
+ margin-left: 3px;
+}
+
+.comment-list .pingback,
+.comment-list .trackback {
+ padding-top: 24px;
+}
+
+.comment-navigation {
+ font-size: 20px;
+ font-style: italic;
+ font-weight: 300;
+ margin: 0 auto;
+ max-width: 604px;
+ padding: 20px 0 30px;
+ width: 100%;
+}
+
+.no-comments {
+ background-color: #f7f5e7;
+ font-size: 20px;
+ font-style: italic;
+ font-weight: 300;
+ margin: 0;
+ padding: 40px 0;
+ text-align: center;
+}
+
+.sidebar .no-comments {
+ padding-left: 60px;
+ padding-right: 376px;
+}
+
+
+/**
+ * 5.13 Multisite
+ * ----------------------------------------------------------------------------
+ */
+
+.site-main .mu_register {
+ margin: 0 auto;
+ max-width: 604px;
+ width: 100%;
+}
+
+.mu_alert {
+ margin-top: 25px;
+}
+
+.site-main .mu_register input[type="submit"],
+.site-main .mu_register #blog_title,
+.site-main .mu_register #user_email,
+.site-main .mu_register #blogname,
+.site-main .mu_register #user_name {
+ font-size: inherit;
+ width: 270px;
+}
+
+.site-main .mu_register input[type="submit"] {
+ width: auto;
+}
+
+
+/**
+ * 6.0 Sidebar
+ * ----------------------------------------------------------------------------
+ */
+
+.site-main .widget-area {
+ float: right;
+ width: 300px;
+}
+
+
+/**
+ * 6.1 Widgets
+ * ----------------------------------------------------------------------------
+ */
+
+.widget {
+ background-color: rgba(247, 245, 231, 0.7);
+ font-size: 14px;
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ hyphens: auto;
+ margin: 0 0 24px;
+ padding: 20px;
+ word-wrap: break-word;
+}
+
+.widget .widget-title {
+ font: 300 italic 20px "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0 0 10px;
+}
+
+.widget ul,
+.widget ol {
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+
+.widget li {
+ padding: 5px 0;
+}
+
+.widget .children li:last-child {
+ padding-bottom: 0;
+}
+
+.widget li > ul,
+.widget li > ol {
+ margin-left: 20px;
+}
+
+.widget a {
+ color: #bc360a;
+}
+
+.widget a:hover {
+ color: #ea9629;
+}
+
+/* Search widget */
+.search-form .search-submit {
+ display: none;
+}
+
+/* RSS Widget */
+.widget_rss .rss-date {
+ display: block;
+}
+
+.widget_rss .rss-date,
+.widget_rss li > cite {
+ color: #a2a2a2;
+}
+
+/* Calendar Widget */
+.widget_calendar table,
+.widget_calendar td {
+ border: 0;
+ border-collapse: separate;
+ border-spacing: 1px;
+}
+
+.widget_calendar caption {
+ font-size: 14px;
+ margin: 0;
+}
+
+.widget_calendar th,
+.widget_calendar td {
+ padding: 0;
+ text-align: center;
+}
+
+.widget_calendar a {
+ display: block;
+}
+
+.widget_calendar a:hover {
+ background-color: rgba(0, 0, 0, 0.15);
+}
+
+.widget_calendar tbody td {
+ background-color: rgba(255, 255, 255, 0.5);
+}
+
+.site-footer .widget_calendar tbody td {
+ background-color: rgba(255, 255, 255, 0.05);
+}
+
+.widget_calendar tbody .pad, .site-footer .widget_calendar tbody .pad {
+ background-color: transparent;
+}
+
+
+/**
+ * 7.0 Footer
+ * ----------------------------------------------------------------------------
+ */
+
+.site-footer {
+ background-color: #e8e5ce;
+ color: #686758;
+ font-size: 14px;
+ text-align: center;
+}
+
+.site-footer .widget-area,
+.sidebar .site-footer {
+ text-align: left;
+}
+
+.site-footer a {
+ color: #686758;
+}
+
+.site-footer .sidebar-container {
+ background-color: #220e10;
+ padding: 20px 0;
+}
+
+.site-footer .widget-area {
+ margin: 0 auto;
+ max-width: 1040px;
+ width: 100%;
+}
+
+.sidebar .site-footer .widget-area {
+ max-width: 724px;
+ position: relative;
+ left: -158px;
+}
+
+.site-footer .widget {
+ background: transparent;
+ color: #fff;
+ float: left;
+ margin-right: 20px;
+ width: 245px;
+}
+
+.sidebar .site-footer .widget {
+ width: 228px;
+}
+
+.sidebar .site-footer .widget:nth-of-type(4),
+.sidebar .site-footer .widget:nth-of-type(3) {
+ margin-right: 0;
+}
+
+.site-footer .widget a {
+ color: #e6402a;
+}
+
+.site-footer .widget-title,
+.site-footer .widget-title a,
+.site-footer .wp-caption-text {
+ color: #fff;
+}
+
+.site-info {
+ margin: 0 auto;
+ max-width: 1040px;
+ padding: 30px 0;
+ width: 100%;
+}
+
+#wpstats {
+ display: block;
+ margin: -10px auto 0;
+}
+
+
+/**
+ * 8.0 Media Queries
+ * ----------------------------------------------------------------------------
+ */
+
+@media (max-width: 1599px) {
+ .site {
+ border: 0;
+ }
+}
+
+@media (max-width: 1069px) {
+ .sidebar img.alignleft,
+ .sidebar .wp-caption.alignleft {
+ margin-left: 0;
+ }
+
+ .sidebar img.alignright,
+ .sidebar .wp-caption.alignright {
+ margin-right: 0;
+ }
+
+ .error404 .page-header {
+ margin-left: auto;
+ max-width: 604px;
+ width: 100%;
+ }
+
+ .archive-header,
+ .search .page-header,
+ .archive .page-header,
+ .blog .page-header,
+ .error404 .page-content,
+ .search .page-content,
+ .archive .page-content,
+ .attachment .entry-header,
+ .attachment .entry-content,
+ .post-navigation .nav-links,
+ .sidebar .site-info,
+ .site-footer .widget-area {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+
+ .error404 .page-title {
+ font-size: 24px;
+ padding: 180px;
+ }
+
+ .error404 .page-title:before {
+ font-size: 554px;
+ }
+
+ .attachment .image-navigation {
+ max-width: 724px;
+ }
+
+ .image-navigation .nav-previous,
+ .image-navigation .nav-next {
+ position: static;
+ }
+
+ .site-main .widget-area {
+ margin-right: 60px;
+ }
+}
+
+@media (max-width: 999px) {
+ .sidebar .entry-header,
+ .sidebar .entry-content,
+ .sidebar .entry-summary,
+ .sidebar .entry-meta,
+ .sidebar .comment-list,
+ .sidebar .comment-reply-title,
+ .sidebar .comment-navigation,
+ .sidebar .comment-respond .comment-form,
+ .sidebar .featured-gallery,
+ .sidebar .post-navigation .nav-links,
+ .author.sidebar .author-info {
+ max-width: 604px;
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .sidebar .site-info,
+ .search.sidebar .page-content,
+ .blog.sidebar .page-content,
+ .attachment .entry-header,
+ .sidebar .comments-title {
+ max-width: 604px;
+ }
+
+ .sidebar .archive-meta,
+ .attachment .entry-header,
+ .search.sidebar .page-content,
+ .blog.sidebar .page-content,
+ .sidebar .site-info,
+ .sidebar .comments-title,
+ .sidebar .no-comments {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .attachment .entry-meta {
+ float: left;
+ text-align: left;
+ width: 100%;
+ }
+
+ .attachment .entry-content {
+ max-width: 100%;
+ padding: 40px 0;
+ }
+
+ .format-status .entry-content {
+ padding-top: 40px;
+ }
+
+ .format-status .entry-meta {
+ padding-bottom: 40px;
+ }
+
+ .sidebar .format-status .entry-content,
+ .sidebar .format-status .entry-meta {
+ padding-left: 35px;
+ }
+
+ .sidebar .format-status .entry-content:before,
+ .sidebar .format-status .entry-meta:before {
+ left: 10px;
+ }
+
+ .sidebar .format-status .entry-content p:first-child:before {
+ left: 4px;
+ }
+
+ .sidebar .paging-navigation .nav-links {
+ padding: 0 60px;
+ }
+
+ .site-main .sidebar-container {
+ height: auto;
+ margin: 0 auto;
+ max-width: 604px;
+ position: relative;
+ top: 20px;
+ }
+
+ .site-main .widget-area {
+ float: none;
+ margin: 0;
+ width: 100%;
+ }
+
+ .sidebar .site-footer .widget-area {
+ max-width: 100%;
+ left: 0;
+ }
+}
+
+/* Collapse oversized image and pulled images after iPad breakpoint. */
+@media (max-width: 767px) {
+ .entry-content img.alignleft,
+ .entry-content .wp-caption.alignleft {
+ margin-left: 0;
+ }
+
+ .entry-content img.alignright,
+ .entry-content .wp-caption.alignright {
+ margin-right: 0;
+ }
+
+ .attachment .image-navigation,
+ .attachment .entry-attachment .attachment {
+ max-width: 604px;
+ padding: 0;
+ width: 100%;
+ }
+
+ .gallery-caption {
+ display: none;
+ }
+}
+
+@media (max-width: 643px) {
+ .site-title {
+ font-size: 30px;
+ }
+
+ #content .entry-header,
+ #content .entry-content,
+ #content .entry-summary,
+ #content footer.entry-meta,
+ #content .featured-gallery,
+ .search.sidebar .page-content,
+ .blog.sidebar .page-content,
+ .sidebar .post-navigation .nav-links,
+ .paging-navigation .nav-links,
+ #content .author-info,
+ .comments-area .comments-title,
+ .comments-area .comment-list,
+ .comments-area .comment-navigation,
+ .comment-respond,
+ .sidebar .site-info,
+ .sidebar .paging-navigation .nav-links {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+
+ #content .format-status .entry-content,
+ #content .format-status .entry-met {
+ padding-left: 35px;
+ }
+
+ /* Small menu */
+ .menu-toggle {
+ cursor: pointer;
+ display: inline-block;
+ font: bold 16px/1.3 "Source Sans Pro", Helvetica, sans-serif;
+ margin: 0;
+ padding: 12px 0 12px 20px;
+ }
+
+ .menu-toggle:after {
+ content: "\f502";
+ font-size: 12px;
+ padding-left: 8px;
+ vertical-align: -4px;
+ }
+
+ .toggled-on .menu-toggle:after {
+ content: "\f500";
+ vertical-align: 2px;
+ }
+
+ .toggled-on .nav-menu,
+ .toggled-on .nav-menu > ul {
+ display: block;
+ margin-left: 0;
+ padding: 0;
+ width: 100%;
+ }
+
+ .toggled-on li,
+ .toggled-on .children {
+ display: block;
+ }
+
+ .toggled-on .nav-menu li > ul {
+ background-color: transparent;
+ display: block;
+ float: none;
+ margin-left: 20px;
+ position: relative;
+ left: auto;
+ top: auto;
+ }
+
+ .toggled-on .nav-menu li > ul a {
+ color: #141412;
+ width: auto;
+ }
+
+ .toggled-on .nav-menu li:hover > a,
+ .toggled-on .nav-menu .children a {
+ background-color: transparent;
+ color: #141412;
+ }
+
+ .toggled-on .nav-menu li a:hover,
+ .toggled-on .nav-menu ul a:hover {
+ background-color: #db572f;
+ color: #fff;
+ }
+
+ ul.nav-menu,
+ div.nav-menu > ul {
+ display: none;
+ }
+
+ #content .featured-gallery {
+ padding-left: 24px;
+ }
+
+ .gallery-columns-1 .gallery-item {
+ margin-right: 0;
+ width: 100%;
+ }
+
+ .entry-title,
+ .format-chat .entry-title,
+ .format-image .entry-title,
+ .format-gallery .entry-title,
+ .format-video .entry-title {
+ font-size: 22px;
+ font-weight: bold;
+ }
+
+ .format-quote blockquote,
+ .format-status .entry-content {
+ font-size: 18px;
+ }
+
+ .format-quote blockquote small,
+ .format-quote blockquote cite {
+ font-size: 13px;
+ }
+
+ .error404 .page-title {
+ padding: 40px 0 0;
+ }
+
+ .error404 .page-title:before {
+ content: normal;
+ }
+
+ .comment-author {
+ margin-right: 30px;
+ }
+
+ .comment-author .avatar {
+ height: auto;
+ max-width: 100%;
+ }
+
+ .comment-metadata,
+ .comment-content,
+ .comment-list .reply {
+ width: 70%;
+ width: -webkit-calc(100% - 104px);
+ width: calc(100% - 104px);
+ }
+
+ .comment-form input[type="text"],
+ .comment-form input[type="email"],
+ .comment-form input[type="url"] {
+ width: -webkit-calc(100% - 120px);
+ width: calc(100% - 120px);
+ }
+
+ .comment-form textarea {
+ height: 80px; /* Smaller field for mobile. */
+ }
+
+ /* Audio */
+ .format-audio .entry-content:before {
+ display: none;
+ }
+
+ .format-audio .audio-content {
+ background-image: none;
+ float: none;
+ padding-left: 0;
+ width: auto;
+ }
+}
+
+/* Mobile devices */
+@media (max-width: 359px) {
+ .gallery {
+ margin-left: 0;
+ }
+
+ .gallery .gallery-item,
+ .gallery-columns-2.gallery-size-thumbnail .gallery-item {
+ max-width: none;
+ width: 49%;
+ width: -webkit-calc(50% - 4px);
+ width: calc(50% - 4px);
+ }
+
+ .gallery-columns-1.gallery-size-medium,
+ .gallery-columns-1.gallery-size-thumbnail,
+ .gallery-columns-2.gallery-size-thumbnail,
+ .gallery-columns-3.gallery-size-thumbnail {
+ display: block;
+ }
+
+ .gallery-columns-1 .gallery-item,
+ .gallery-columns-1.gallery-size-medium .gallery-item,
+ .gallery-columns-1.gallery-size-thumbnail .gallery-item {
+ text-align: center;
+ width: 98%;
+ width: -webkit-calc(100% - 4px);
+ width: calc(100% - 4px);
+ }
+
+ .gallery-columns-3 .gallery-item:nth-of-type(3n),
+ .gallery-columns-5 .gallery-item:nth-of-type(5n),
+ .gallery-columns-7 .gallery-item:nth-of-type(7n),
+ .gallery-columns-9 .gallery-item:nth-of-type(9n) {
+ margin-right: 4px;
+ }
+
+ .gallery br {
+ display: none;
+ }
+
+ .gallery .gallery-item:nth-of-type(even) {
+ margin-right: 0;
+ }
+
+ /* Comments */
+ .comment-author {
+ margin: 0 0 5px;
+ max-width: 100%;
+ }
+
+ .comment-author .avatar {
+ display: inline;
+ margin: 0 5px 0 0;
+ max-width: 20px;
+ }
+
+ .comment-metadata,
+ .comment-content,
+ .comment-list .reply {
+ width: 100%;
+ }
+}
+
+
+/**
+ * 9.0 Print
+ * ----------------------------------------------------------------------------
+ */
+
+/* Retina-specific styles. */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+
+ .site-header .search-field {
+ background-image: url(images/search-icon-2x.png);
+ }
+
+ .format-audio .audio-content,
+ .format-status .entry-content:before,
+ .format-status .entry-meta:before,
+ .comment-list > li:after,
+ .comment-list .children > li:before {
+ background-image: url(images/dotted-line-2x.png);
+ }
+}
+
+@media print {
+ body {
+ background: none !important;
+ color: #000;
+ font-size: 10pt;
+ }
+
+ footer a[rel="bookmark"]:link:after,
+ footer a[rel="bookmark"]:visited:after {
+ content: " [" attr(href) "] "; /* Show URLs */
+ }
+
+ .site {
+ max-width: 98%;
+ }
+
+ .site-header {
+ background-image: none !important;
+ }
+
+ .site-header .home-link {
+ max-width: none;
+ min-height: 0;
+ }
+
+ .site-title {
+ color: #000;
+ font-size: 21pt;
+ }
+
+ .site-description {
+ font-size: 10pt;
+ }
+
+ .author-avatar,
+ .site-footer,
+ .comment-respond,
+ .comments-area .comment-edit-link,
+ .comments-area .reply,
+ .comments-link,
+ .entry-meta .edit-link,
+ .page-links,
+ .site-content nav,
+ .widget-area,
+ .main-navigation,
+ .navbar,
+ .more-link {
+ display: none;
+ }
+
+ .entry-header,
+ .entry-content,
+ .entry-summary,
+ .entry-meta {
+ margin: 0;
+ width: 100%;
+ }
+
+ .page-title,
+ .entry-title {
+ font-size: 21pt;
+ }
+
+ .entry-meta,
+ .entry-meta a {
+ color: #444;
+ font-size: 10pt;
+ }
+
+ .entry-content img.alignleft,
+ .entry-content .wp-caption.alignleft {
+ margin-left: 0;
+ }
+
+ .entry-content img.alignright,
+ .entry-content .wp-caption.alignright {
+ margin-right: 0;
+ }
+
+ .format-image .entry-content .size-full {
+ margin: 0;
+ }
+
+ /* Remove colors from post formats */
+ .hentry {
+ background-color: #fff;
+ }
+
+ /* Comments */
+ .comments-area > li.comment {
+ background: none;
+ position: relative;
+ width: auto;
+ }
+
+ .comment-metadata {
+ float: none;
+ }
+
+ .comment-author .fn,
+ .comment-reply-link,
+ .comment-reply-login {
+ color: #333;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/tag.php b/src/wp-content/themes/twentythirteen/tag.php
new file mode 100644
index 0000000000..5454005490
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/tag.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * The template for displaying Tag pages.
+ *
+ * Used to display archive-type pages for posts in a tag.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( 'Tag Archives: %s', 'twentythirteen' ), single_tag_title( '', false ) ); ?></h1>
+
+ <?php if ( tag_description() ) : // Show an optional tag description ?>
+ <div class="archive-meta"><?php echo tag_description(); ?></div>
+ <?php endif; ?>
+ </header><!-- .archive-header -->
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentythirteen/taxonomy-post_format.php b/src/wp-content/themes/twentythirteen/taxonomy-post_format.php
new file mode 100644
index 0000000000..0deb97cce2
--- /dev/null
+++ b/src/wp-content/themes/twentythirteen/taxonomy-post_format.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * The template for displaying Post Format pages.
+ *
+ * Used to display archive-type pages for posts with a post format.
+ * If you'd like to further customize these Post Format views, you may create a
+ * new template file for each specific one.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Thirteen
+ * @since Twenty Thirteen 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="content-area">
+ <div id="content" class="site-content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( '%s Archives', 'twentythirteen' ), '<span>' . get_post_format_string( get_post_format() ) . '</span>' ); ?></h1>
+ </header><!-- .archive-header -->
+
+ <?php /* The loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentythirteen_paging_nav(); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/404.php b/src/wp-content/themes/twentytwelve/404.php
new file mode 100644
index 0000000000..e7270b4f40
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/404.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * The template for displaying 404 pages (Not Found).
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <article id="post-0" class="post error404 no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'This is somewhat embarrassing, isn&rsquo;t it?', 'twentytwelve' ); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <p><?php _e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'twentytwelve' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/archive.php b/src/wp-content/themes/twentytwelve/archive.php
new file mode 100644
index 0000000000..8bfb01c903
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/archive.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * The template for displaying Archive pages.
+ *
+ * Used to display archive-type pages if nothing more specific matches a query.
+ * For example, puts together date-based pages if no date.php file exists.
+ *
+ * If you'd like to further customize these archive views, you may create a
+ * new template file for each specific one. For example, Twenty Twelve already
+ * has tag.php for Tag archives, category.php for Category archives, and
+ * author.php for Author archives.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php
+ if ( is_day() ) :
+ printf( __( 'Daily Archives: %s', 'twentytwelve' ), '<span>' . get_the_date() . '</span>' );
+ elseif ( is_month() ) :
+ printf( __( 'Monthly Archives: %s', 'twentytwelve' ), '<span>' . get_the_date( _x( 'F Y', 'monthly archives date format', 'twentytwelve' ) ) . '</span>' );
+ elseif ( is_year() ) :
+ printf( __( 'Yearly Archives: %s', 'twentytwelve' ), '<span>' . get_the_date( _x( 'Y', 'yearly archives date format', 'twentytwelve' ) ) . '</span>' );
+ else :
+ _e( 'Archives', 'twentytwelve' );
+ endif;
+ ?></h1>
+ </header><!-- .archive-header -->
+
+ <?php
+ /* Start the Loop */
+ while ( have_posts() ) : the_post();
+
+ /* Include the post format-specific template for the content. If you want to
+ * this in a child theme then include a file called called content-___.php
+ * (where ___ is the post format) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+
+ endwhile;
+
+ twentytwelve_content_nav( 'nav-below' );
+ ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/author.php b/src/wp-content/themes/twentytwelve/author.php
new file mode 100644
index 0000000000..0fa2e6bfeb
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/author.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * The template for displaying Author Archive pages.
+ *
+ * Used to display archive-type pages for posts by an author.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <?php
+ /* Queue the first post, that way we know
+ * what author we're dealing with (if that is the case).
+ *
+ * We reset this later so we can run the loop
+ * properly with a call to rewind_posts().
+ */
+ the_post();
+ ?>
+
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( 'Author Archives: %s', 'twentytwelve' ), '<span class="vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( "ID" ) ) ) . '" title="' . esc_attr( get_the_author() ) . '" rel="me">' . get_the_author() . '</a></span>' ); ?></h1>
+ </header><!-- .archive-header -->
+
+ <?php
+ /* Since we called the_post() above, we need to
+ * rewind the loop back to the beginning that way
+ * we can run the loop properly, in full.
+ */
+ rewind_posts();
+ ?>
+
+ <?php twentytwelve_content_nav( 'nav-above' ); ?>
+
+ <?php
+ // If a user has filled out their description, show a bio on their entries.
+ if ( get_the_author_meta( 'description' ) ) : ?>
+ <div class="author-info">
+ <div class="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentytwelve_author_bio_avatar_size', 60 ) ); ?>
+ </div><!-- .author-avatar -->
+ <div class="author-description">
+ <h2><?php printf( __( 'About %s', 'twentytwelve' ), get_the_author() ); ?></h2>
+ <p><?php the_author_meta( 'description' ); ?></p>
+ </div><!-- .author-description -->
+ </div><!-- .author-info -->
+ <?php endif; ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentytwelve_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/category.php b/src/wp-content/themes/twentytwelve/category.php
new file mode 100644
index 0000000000..fc500867d5
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/category.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * The template for displaying Category pages.
+ *
+ * Used to display archive-type pages for posts in a category.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( 'Category Archives: %s', 'twentytwelve' ), '<span>' . single_cat_title( '', false ) . '</span>' ); ?></h1>
+
+ <?php if ( category_description() ) : // Show an optional category description ?>
+ <div class="archive-meta"><?php echo category_description(); ?></div>
+ <?php endif; ?>
+ </header><!-- .archive-header -->
+
+ <?php
+ /* Start the Loop */
+ while ( have_posts() ) : the_post();
+
+ /* Include the post format-specific template for the content. If you want to
+ * this in a child theme then include a file called called content-___.php
+ * (where ___ is the post format) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+
+ endwhile;
+
+ twentytwelve_content_nav( 'nav-below' );
+ ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/comments.php b/src/wp-content/themes/twentytwelve/comments.php
new file mode 100644
index 0000000000..457b9e4640
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/comments.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * The template for displaying Comments.
+ *
+ * The area of the page that contains both current comments
+ * and the comment form. The actual display of comments is
+ * handled by a callback to twentytwelve_comment() which is
+ * located in the functions.php file.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+/*
+ * If the current post is protected by a password and
+ * the visitor has not yet entered the password we will
+ * return early without loading the comments.
+ */
+if ( post_password_required() )
+ return;
+?>
+
+<div id="comments" class="comments-area">
+
+ <?php // You can start editing here -- including this comment! ?>
+
+ <?php if ( have_comments() ) : ?>
+ <h2 class="comments-title">
+ <?php
+ printf( _n( 'One thought on &ldquo;%2$s&rdquo;', '%1$s thoughts on &ldquo;%2$s&rdquo;', get_comments_number(), 'twentytwelve' ),
+ number_format_i18n( get_comments_number() ), '<span>' . get_the_title() . '</span>' );
+ ?>
+ </h2>
+
+ <ol class="commentlist">
+ <?php wp_list_comments( array( 'callback' => 'twentytwelve_comment', 'style' => 'ol' ) ); ?>
+ </ol><!-- .commentlist -->
+
+ <?php if ( get_comment_pages_count() > 1 && get_option( 'page_comments' ) ) : // are there comments to navigate through ?>
+ <nav id="comment-nav-below" class="navigation" role="navigation">
+ <h1 class="assistive-text section-heading"><?php _e( 'Comment navigation', 'twentytwelve' ); ?></h1>
+ <div class="nav-previous"><?php previous_comments_link( __( '&larr; Older Comments', 'twentytwelve' ) ); ?></div>
+ <div class="nav-next"><?php next_comments_link( __( 'Newer Comments &rarr;', 'twentytwelve' ) ); ?></div>
+ </nav>
+ <?php endif; // check for comment navigation ?>
+
+ <?php
+ /* If there are no comments and comments are closed, let's leave a note.
+ * But we only want the note on posts and pages that had comments in the first place.
+ */
+ if ( ! comments_open() && get_comments_number() ) : ?>
+ <p class="nocomments"><?php _e( 'Comments are closed.' , 'twentytwelve' ); ?></p>
+ <?php endif; ?>
+
+ <?php endif; // have_comments() ?>
+
+ <?php comment_form(); ?>
+
+</div><!-- #comments .comments-area --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/content-aside.php b/src/wp-content/themes/twentytwelve/content-aside.php
new file mode 100644
index 0000000000..4a84ae76d0
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-aside.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * The template for displaying posts in the Aside post format
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="aside">
+ <h1 class="entry-title"><a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a></h1>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?>
+ </div><!-- .entry-content -->
+ </div><!-- .aside -->
+
+ <footer class="entry-meta">
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentytwelve' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php echo get_the_date(); ?></a>
+ <?php if ( comments_open() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentytwelve' ) . '</span>', __( '1 Reply', 'twentytwelve' ), __( '% Replies', 'twentytwelve' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/content-image.php b/src/wp-content/themes/twentytwelve/content-image.php
new file mode 100644
index 0000000000..a683b83cfc
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-image.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * The template for displaying posts in the Image post format
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <a href="<?php the_permalink(); ?>" rel="bookmark">
+ <h1><?php the_title(); ?></h1>
+ <h2><time class="entry-date" datetime="<?php echo esc_attr( get_the_date( 'c' ) ); ?>"><?php echo get_the_date(); ?></time></h2>
+ </a>
+ <?php if ( comments_open() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentytwelve' ) . '</span>', __( '1 Reply', 'twentytwelve' ), __( '% Replies', 'twentytwelve' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/content-link.php b/src/wp-content/themes/twentytwelve/content-link.php
new file mode 100644
index 0000000000..31e4ec958a
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-link.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * The template for displaying posts in the Link post format
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header><?php _e( 'Link', 'twentytwelve' ); ?></header>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentytwelve' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php echo get_the_date(); ?></a>
+ <?php if ( comments_open() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentytwelve' ) . '</span>', __( '1 Reply', 'twentytwelve' ), __( '% Replies', 'twentytwelve' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/content-none.php b/src/wp-content/themes/twentytwelve/content-none.php
new file mode 100644
index 0000000000..42bff09450
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-none.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * The template for displaying a "No posts found" message.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentytwelve' ); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found. Perhaps searching will help find a related post.', 'twentytwelve' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
diff --git a/src/wp-content/themes/twentytwelve/content-page.php b/src/wp-content/themes/twentytwelve/content-page.php
new file mode 100644
index 0000000000..0abcbf7911
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-page.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * The template used for displaying page content in page.php
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <header class="entry-header">
+ <?php if ( ! is_page_template( 'page-templates/front-page.php' ) ) : ?>
+ <?php the_post_thumbnail(); ?>
+ <?php endif; ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links">' . __( 'Pages:', 'twentytwelve' ), 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <footer class="entry-meta">
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/content-quote.php b/src/wp-content/themes/twentytwelve/content-quote.php
new file mode 100644
index 0000000000..0a98a96de3
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-quote.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * The template for displaying posts in the Quote post format
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentytwelve' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php echo get_the_date(); ?></a>
+ <?php if ( comments_open() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentytwelve' ) . '</span>', __( '1 Reply', 'twentytwelve' ), __( '% Replies', 'twentytwelve' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/content-status.php b/src/wp-content/themes/twentytwelve/content-status.php
new file mode 100644
index 0000000000..55ffcaee24
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content-status.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * The template for displaying posts in the Status post format
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <div class="entry-header">
+ <header>
+ <h1><?php the_author(); ?></h1>
+ <h2><a href="<?php the_permalink(); ?>" title="<?php echo esc_attr( sprintf( __( 'Permalink to %s', 'twentytwelve' ), the_title_attribute( 'echo=0' ) ) ); ?>" rel="bookmark"><?php echo get_the_date(); ?></a></h2>
+ </header>
+ <?php echo get_avatar( get_the_author_meta( 'ID' ), apply_filters( 'twentytwelve_status_avatar', '48' ) ); ?>
+ </div><!-- .entry-header -->
+
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ <?php if ( comments_open() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentytwelve' ) . '</span>', __( '1 Reply', 'twentytwelve' ), __( '% Replies', 'twentytwelve' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/content.php b/src/wp-content/themes/twentytwelve/content.php
new file mode 100644
index 0000000000..bf2936ca21
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/content.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * The default template for displaying content. Used for both single and index/archive/search.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
+ <?php if ( is_sticky() && is_home() && ! is_paged() ) : ?>
+ <div class="featured-post">
+ <?php _e( 'Featured post', 'twentytwelve' ); ?>
+ </div>
+ <?php endif; ?>
+ <header class="entry-header">
+ <?php the_post_thumbnail(); ?>
+ <?php if ( is_single() ) : ?>
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+ <?php else : ?>
+ <h1 class="entry-title">
+ <a href="<?php the_permalink(); ?>" rel="bookmark"><?php the_title(); ?></a>
+ </h1>
+ <?php endif; // is_single() ?>
+ <?php if ( comments_open() ) : ?>
+ <div class="comments-link">
+ <?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'twentytwelve' ) . '</span>', __( '1 Reply', 'twentytwelve' ), __( '% Replies', 'twentytwelve' ) ); ?>
+ </div><!-- .comments-link -->
+ <?php endif; // comments_open() ?>
+ </header><!-- .entry-header -->
+
+ <?php if ( is_search() ) : // Only display Excerpts for Search ?>
+ <div class="entry-summary">
+ <?php the_excerpt(); ?>
+ </div><!-- .entry-summary -->
+ <?php else : ?>
+ <div class="entry-content">
+ <?php the_content( __( 'Continue reading <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links">' . __( 'Pages:', 'twentytwelve' ), 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-content -->
+ <?php endif; ?>
+
+ <footer class="entry-meta">
+ <?php twentytwelve_entry_meta(); ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ <?php if ( is_singular() && get_the_author_meta( 'description' ) && is_multi_author() ) : // If a user has filled out their description and this is a multi-author blog, show a bio on their entries. ?>
+ <div class="author-info">
+ <div class="author-avatar">
+ <?php echo get_avatar( get_the_author_meta( 'user_email' ), apply_filters( 'twentytwelve_author_bio_avatar_size', 68 ) ); ?>
+ </div><!-- .author-avatar -->
+ <div class="author-description">
+ <h2><?php printf( __( 'About %s', 'twentytwelve' ), get_the_author() ); ?></h2>
+ <p><?php the_author_meta( 'description' ); ?></p>
+ <div class="author-link">
+ <a href="<?php echo esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ); ?>" rel="author">
+ <?php printf( __( 'View all posts by %s <span class="meta-nav">&rarr;</span>', 'twentytwelve' ), get_the_author() ); ?>
+ </a>
+ </div><!-- .author-link -->
+ </div><!-- .author-description -->
+ </div><!-- .author-info -->
+ <?php endif; ?>
+ </footer><!-- .entry-meta -->
+ </article><!-- #post -->
diff --git a/src/wp-content/themes/twentytwelve/css/ie.css b/src/wp-content/themes/twentytwelve/css/ie.css
new file mode 100644
index 0000000000..7acef64df6
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/css/ie.css
@@ -0,0 +1,243 @@
+/*
+Styles for older IE versions (previous to IE9).
+*/
+
+body {
+ background-color: #e6e6e6;
+}
+body.custom-background-empty {
+ background-color: #fff;
+}
+body.custom-background-empty .site,
+body.custom-background-white .site {
+ box-shadow: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+.assistive-text,
+.site .screen-reader-text {
+ clip: rect(1px 1px 1px 1px); /* IE7 */
+}
+.full-width .site-content {
+ float: none;
+ width: 100%;
+}
+img.size-full,
+img.size-large,
+img.header-image,
+img.wp-post-image,
+img[class*="align"],
+img[class*="wp-image-"],
+img[class*="attachment-"] {
+ width: auto; /* Prevent stretching of full-size and large-size images with height and width attributes in IE8 */
+}
+.author-avatar {
+ float: left;
+ margin-top: 8px;
+ margin-top: 0.571428571rem;
+}
+.author-description {
+ float: right;
+ width: 80%;
+}
+.site {
+ box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3);
+ margin: 48px auto;
+ max-width: 960px;
+ overflow: hidden;
+ padding: 0 40px;
+}
+.site-content {
+ float: left;
+ width: 65.104166667%;
+}
+body.template-front-page .site-content,
+body.single-attachment .site-content,
+body.full-width .site-content {
+ width: 100%;
+}
+.widget-area {
+ float: right;
+ width: 26.041666667%;
+}
+.site-header h1,
+.site-header h2 {
+ text-align: left;
+}
+.site-header h1 {
+ font-size: 26px;
+ line-height: 1.846153846;
+}
+.main-navigation ul.nav-menu,
+.main-navigation div.nav-menu > ul {
+ border-bottom: 1px solid #ededed;
+ border-top: 1px solid #ededed;
+ display: inline-block !important;
+ text-align: left;
+ width: 100%;
+}
+.main-navigation ul {
+ margin: 0;
+ text-indent: 0;
+}
+.main-navigation li a,
+.main-navigation li {
+ display: inline-block;
+ text-decoration: none;
+}
+.ie7 .main-navigation li a,
+.ie7 .main-navigation li {
+ display: inline;
+}
+.main-navigation li a {
+ border-bottom: 0;
+ color: #6a6a6a;
+ line-height: 3.692307692;
+ text-transform: uppercase;
+}
+.main-navigation li a:hover {
+ color: #000;
+}
+.main-navigation li {
+ margin: 0 40px 0 0;
+ position: relative;
+}
+.main-navigation li ul {
+ display: none;
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ top: 100%;
+ z-index: 1;
+}
+.ie7 .main-navigation li ul {
+ left: 0;
+}
+.main-navigation li ul ul,
+.ie7 .main-navigation li ul ul {
+ top: 0;
+ left: 100%;
+}
+.main-navigation ul li:hover > ul {
+ border-left: 0;
+ display: block;
+}
+.main-navigation li ul li a {
+ background: #efefef;
+ border-bottom: 1px solid #ededed;
+ display: block;
+ font-size: 11px;
+ line-height: 2.181818182;
+ padding: 8px 10px;
+ width: 180px;
+}
+.main-navigation li ul li a:hover {
+ background: #e3e3e3;
+ color: #444;
+}
+.main-navigation .current-menu-item > a,
+.main-navigation .current-menu-ancestor > a,
+.main-navigation .current_page_item > a,
+.main-navigation .current_page_ancestor > a {
+ color: #636363;
+ font-weight: bold;
+}
+.menu-toggle {
+ display: none;
+}
+.entry-header .entry-title {
+ font-size: 22px;
+}
+#respond form input[type="text"] {
+ width: 46.333333333%;
+}
+#respond form textarea.blog-textarea {
+ width: 79.666666667%;
+}
+.template-front-page .site-content,
+.template-front-page article {
+ overflow: hidden;
+}
+.template-front-page.has-post-thumbnail article {
+ float: left;
+ width: 47.916666667%;
+}
+.entry-page-image {
+ float: right;
+ margin-bottom: 0;
+ width: 47.916666667%;
+}
+.template-front-page .widget-area .widget,
+.template-front-page.two-sidebars .widget-area .front-widgets {
+ float: left;
+ margin-bottom: 24px;
+ width: 51.875%;
+}
+.template-front-page .widget-area .widget:nth-child(odd) {
+ clear: right;
+}
+.template-front-page .widget-area .widget:nth-child(even),
+.template-front-page.two-sidebars .widget-area .front-widgets + .front-widgets {
+ float: right;
+ margin: 0 0 24px;
+ width: 39.0625%;
+}
+.template-front-page.two-sidebars .widget,
+.template-front-page.two-sidebars .widget:nth-child(even) {
+ float: none;
+ width: auto;
+}
+
+/* =RTL overrides for IE7 and IE8
+-------------------------------------------------------------- */
+.rtl .site-header h1,
+.rtl .site-header h2 {
+ text-align: right;
+}
+.rtl .widget-area,
+.rtl .author-description {
+ float: left;
+}
+.rtl .author-avatar,
+.rtl .site-content {
+ float: right;
+}
+.rtl .main-navigation ul.nav-menu,
+.rtl .main-navigation div.nav-menu > ul {
+ text-align: right;
+}
+.rtl .main-navigation ul li ul li,
+.rtl .main-navigation ul li ul li ul li {
+ margin-left: 40px;
+ margin-right: auto;
+}
+.rtl .main-navigation li ul ul {
+ position: absolute;
+ bottom: 0;
+ right: 100%;
+ z-index: 1;
+}
+.ie7 .rtl .main-navigation li ul ul {
+ position: absolute;
+ bottom: 0;
+ right: 100%;
+ z-index: 1;
+}
+.ie7 .rtl .main-navigation ul li {
+ z-index: 99;
+}
+.ie7 .rtl .main-navigation li ul {
+ position: absolute;
+ bottom: 100%;
+ right: 0;
+ z-index: 1;
+}
+.ie7 .rtl .main-navigation li {
+ margin-right: auto;
+ margin-left: 40px;
+}
+.ie7 .rtl .main-navigation li ul ul ul {
+ position: relative;
+ z-index: 1;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/editor-style-rtl.css b/src/wp-content/themes/twentytwelve/editor-style-rtl.css
new file mode 100644
index 0000000000..5fd832c6ff
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/editor-style-rtl.css
@@ -0,0 +1,28 @@
+/*
+Theme Name: Twenty Twelve
+Description: Used to style the TinyMCE editor for RTL languages.
+See also rtl.css file.
+*/
+
+html .mceContentBody {
+ direction: rtl;
+ unicode-bidi: embed;
+}
+li {
+ margin: 0 24px 0 0;
+ margin: 0 1.714285714rem 0 0;
+}
+dl {
+ margin: 0 24px;
+ margin: 0 1.714285714rem;
+}
+tr th {
+ text-align: right;
+}
+td {
+ padding: 6px 0 6px 10px;
+ text-align: right;
+}
+.wp-caption {
+ text-align: right;
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/editor-style.css b/src/wp-content/themes/twentytwelve/editor-style.css
new file mode 100644
index 0000000000..24e9b24f63
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/editor-style.css
@@ -0,0 +1,342 @@
+/*
+Theme Name: Twenty Twelve
+Description: Used to style the TinyMCE editor.
+*/
+
+html {
+ font-size: 87.5%;
+}
+html .mceContentBody {
+ max-width: 625px;
+}
+body {
+ color: #444;
+ font-family: "Open Sans", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ font-size: 1rem;
+ line-height: 1;
+ text-rendering: optimizeLegibility;
+ vertical-align: baseline;
+}
+
+
+/* =Headings
+-------------------------------------------------------------- */
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ clear: both;
+ line-height: 1.846153846;
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+}
+h1 {
+ font-size: 21px;
+ font-size: 1.5rem;
+ line-height: 1.5;
+}
+h2 {
+ font-size: 18px;
+ font-size: 1.285714286rem;
+ line-height: 1.6;
+}
+h3 {
+ font-size: 16px;
+ font-size: 1.142857143rem;
+}
+h4 {
+ font-size: 14px;
+ font-size: 1rem;
+}
+h5 {
+ font-size: 13px;
+ font-size: 0.928571429rem;
+}
+h6 {
+ font-size: 12px;
+ font-size: 0.857142857rem;
+}
+hr {
+ background-color: #ccc;
+ border: 0;
+ height: 1px;
+ margin: 24px;
+ margin-bottom: 1.714285714rem;
+}
+
+
+/* =Text elements
+-------------------------------------------------------------- */
+
+p {
+ line-height: 1.714285714;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+}
+ul,
+ol {
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+ line-height: 1.714285714;
+ padding: 0;
+}
+ul {
+ list-style: disc outside;
+}
+ol {
+ list-style: decimal outside;
+}
+ul ul,
+ol ol,
+ul ol,
+ol ul {
+ margin-bottom: 0;
+}
+li {
+ margin: 0 0 0 24px;
+ margin: 0 0 0 1.714285714rem;
+}
+dl {
+ margin: 0 24px;
+ margin: 0 1.714285714rem;
+}
+dt {
+ font-weight: bold;
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+dd {
+ line-height: 1.714285714;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+}
+strong {
+ font-weight: bold;
+}
+cite,
+em,
+i {
+ font-style: italic;
+}
+cite {
+ border: none;
+}
+big {
+ font-size: 128.571429%;
+}
+.mceContentBody blockquote {
+ font-style: italic !important;
+ font-weight: normal;
+ margin: 0;
+ padding: 24px;
+ padding: 1.714285714rem;
+}
+pre {
+ border: 1px solid #ededed;
+ color: #666;
+ font-family: Consolas, Monaco, Lucida Console, monospace;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 1.714285714;
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+ overflow: auto;
+ padding: 24px;
+ padding: 1.714285714rem;
+}
+code,
+kbd,
+samp,
+var {
+ font-family: Consolas, Monaco, Lucida Console, monospace;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+}
+abbr,
+acronym,
+dfn {
+ border-bottom: 1px dotted #666;
+ cursor: help;
+}
+address {
+ display: block;
+ line-height: 1.714285714;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+}
+del {
+ color: #333;
+}
+ins {
+ background: #fff9c0;
+ border: none;
+ color: #333;
+ text-decoration: none;
+}
+sup,
+sub {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+input[type="text"] {
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ font-family: inherit;
+ padding: 6px;
+ padding: 0.428571429rem;
+}
+textarea {
+ border: 1px solid #d5d2ca;
+ border-radius: 3px;
+ font-family: inherit;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 1.714285714;
+ padding: 10px;
+ padding: 0.714285714rem;
+ width: 96%;
+}
+
+
+/* =Links
+-------------------------------------------------------------- */
+
+a,
+a em,
+a strong {
+ color: #21759b;
+ outline: none;
+}
+a:focus,
+a:active,
+a:hover {
+ color: #0f3647;
+}
+
+
+/* =Alignment
+-------------------------------------------------------------- */
+
+.alignleft {
+ display: inline;
+ float: left;
+ margin: 12px 24px 12px 0;
+ margin: 0.857142857rem 1.714285714rem 0.857142857rem 0;
+}
+.alignright {
+ display: inline;
+ float: right;
+ margin: 12px 0 12px 24px;
+ margin: 0.857142857rem 0 0.857142857rem 1.714285714rem;
+}
+.aligncenter {
+ clear: both;
+ display: block;
+ margin-top: 12px;
+ margin-top: 0.857142857rem;
+ margin-bottom: 12px;
+ margin-bottom: 0.857142857rem;
+}
+
+
+/* =Tables
+-------------------------------------------------------------- */
+
+table {
+ border-bottom: 1px solid #ededed;
+ border-collapse: collapse;
+ border-spacing: 0;
+ color: #757575;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+ width: 100%;
+}
+tr th {
+ color: #636363;
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ font-weight: bold;
+ line-height: 2.181818182;
+ text-align: left;
+ text-transform: uppercase;
+}
+td {
+ border-top: 1px solid #ededed !important;
+ color: #757575;
+ font-size: inherit;
+ font-weight: normal;
+ padding: 6px 10px 6px 0;
+ text-align: left;
+}
+
+
+/* =Images
+-------------------------------------------------------------- */
+
+img,
+.editor-attachment {
+ border: 0;
+ border-radius: 3px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
+ max-width: 100%;
+}
+img.size-full {
+ width: auto/9; /* Prevent stretching of full-size images in IE8 */
+}
+img[class*="wp-image-"] {
+ height: auto;
+ max-width: 100%;
+}
+img[class*="align"],
+img[class*="wp-image-"],
+img[class*="attachment-"] {
+ height: auto; /* Make sure images with WordPress-added height and width attributes are scaled correctly */
+}
+img.mce-wp-nextpage {
+ border-radius: 0;
+ box-shadow: none;
+}
+img.wp-smiley {
+ border: 0;
+ border-radius: 0;
+ box-shadow: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+.wp-caption {
+ background: transparent;
+ border: none;
+ margin: 0;
+ padding: 4px;
+ text-align: left;
+}
+.wp-caption-dt {
+ margin: 0;
+}
+.wp-caption .wp-caption-text,
+.wp-caption-dd {
+ color: #757575;
+ font-style: italic;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ margin: 0 0 24px;
+ margin: 0 0 1.71429rem;
+}
diff --git a/src/wp-content/themes/twentytwelve/footer.php b/src/wp-content/themes/twentytwelve/footer.php
new file mode 100644
index 0000000000..91ca7927f5
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/footer.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * The template for displaying the footer.
+ *
+ * Contains footer content and the closing of the
+ * #main and #page div elements.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+ </div><!-- #main .wrapper -->
+ <footer id="colophon" role="contentinfo">
+ <div class="site-info">
+ <?php do_action( 'twentytwelve_credits' ); ?>
+ <a href="<?php echo esc_url( __( 'http://wordpress.org/', 'twentytwelve' ) ); ?>" title="<?php esc_attr_e( 'Semantic Personal Publishing Platform', 'twentytwelve' ); ?>"><?php printf( __( 'Proudly powered by %s', 'twentytwelve' ), 'WordPress' ); ?></a>
+ </div><!-- .site-info -->
+ </footer><!-- #colophon -->
+</div><!-- #page -->
+
+<?php wp_footer(); ?>
+</body>
+</html> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/functions.php b/src/wp-content/themes/twentytwelve/functions.php
new file mode 100644
index 0000000000..04981390d3
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/functions.php
@@ -0,0 +1,486 @@
+<?php
+/**
+ * Twenty Twelve functions and definitions.
+ *
+ * Sets up the theme and provides some helper functions, which are used
+ * in the theme as custom template tags. Others are attached to action and
+ * filter hooks in WordPress to change core functionality.
+ *
+ * When using a child theme (see http://codex.wordpress.org/Theme_Development and
+ * http://codex.wordpress.org/Child_Themes), you can override certain functions
+ * (those wrapped in a function_exists() call) by defining them first in your child theme's
+ * functions.php file. The child theme's functions.php file is included before the parent
+ * theme's file, so the child theme functions would be used.
+ *
+ * Functions that are not pluggable (not wrapped in function_exists()) are instead attached
+ * to a filter or action hook.
+ *
+ * For more information on hooks, actions, and filters, see http://codex.wordpress.org/Plugin_API.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+/**
+ * Sets up the content width value based on the theme's design and stylesheet.
+ */
+if ( ! isset( $content_width ) )
+ $content_width = 625;
+
+/**
+ * Sets up theme defaults and registers the various WordPress features that
+ * Twenty Twelve supports.
+ *
+ * @uses load_theme_textdomain() For translation/localization support.
+ * @uses add_editor_style() To add a Visual Editor stylesheet.
+ * @uses add_theme_support() To add support for post thumbnails, automatic feed links,
+ * custom background, and post formats.
+ * @uses register_nav_menu() To add support for navigation menus.
+ * @uses set_post_thumbnail_size() To set a custom post thumbnail size.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_setup() {
+ /*
+ * Makes Twenty Twelve available for translation.
+ *
+ * Translations can be added to the /languages/ directory.
+ * If you're building a theme based on Twenty Twelve, use a find and replace
+ * to change 'twentytwelve' to the name of your theme in all the template files.
+ */
+ load_theme_textdomain( 'twentytwelve', get_template_directory() . '/languages' );
+
+ // This theme styles the visual editor with editor-style.css to match the theme style.
+ add_editor_style();
+
+ // Adds RSS feed links to <head> for posts and comments.
+ add_theme_support( 'automatic-feed-links' );
+
+ // This theme supports a variety of post formats.
+ add_theme_support( 'post-formats', array( 'aside', 'image', 'link', 'quote', 'status' ) );
+
+ // This theme uses wp_nav_menu() in one location.
+ register_nav_menu( 'primary', __( 'Primary Menu', 'twentytwelve' ) );
+
+ /*
+ * This theme supports custom background color and image, and here
+ * we also set up the default background color.
+ */
+ add_theme_support( 'custom-background', array(
+ 'default-color' => 'e6e6e6',
+ ) );
+
+ // This theme uses a custom image size for featured images, displayed on "standard" posts.
+ add_theme_support( 'post-thumbnails' );
+ set_post_thumbnail_size( 624, 9999 ); // Unlimited height, soft crop
+}
+add_action( 'after_setup_theme', 'twentytwelve_setup' );
+
+/**
+ * Adds support for a custom header image.
+ */
+require( get_template_directory() . '/inc/custom-header.php' );
+
+/**
+ * Returns the Google font stylesheet URL if available.
+ *
+ * The use of Open Sans by default is localized. For languages that use
+ * characters not supported by the font, the font can be disabled.
+ *
+ * @since Twenty Twelve 1.2
+ *
+ * @return string Font stylesheet or empty string if disabled.
+ */
+function twentytwelve_get_font_url() {
+ $font_url = '';
+
+ /* translators: If there are characters in your language that are not supported
+ by Open Sans, translate this to 'off'. Do not translate into your own language. */
+ if ( 'off' !== _x( 'on', 'Open Sans font: on or off', 'twentytwelve' ) ) {
+ $subsets = 'latin,latin-ext';
+
+ /* translators: To add an additional Open Sans character subset specific to your language, translate
+ this to 'greek', 'cyrillic' or 'vietnamese'. Do not translate into your own language. */
+ $subset = _x( 'no-subset', 'Open Sans font: add new subset (greek, cyrillic, vietnamese)', 'twentytwelve' );
+
+ if ( 'cyrillic' == $subset )
+ $subsets .= ',cyrillic,cyrillic-ext';
+ elseif ( 'greek' == $subset )
+ $subsets .= ',greek,greek-ext';
+ elseif ( 'vietnamese' == $subset )
+ $subsets .= ',vietnamese';
+
+ $protocol = is_ssl() ? 'https' : 'http';
+ $query_args = array(
+ 'family' => 'Open+Sans:400italic,700italic,400,700',
+ 'subset' => $subsets,
+ );
+ $font_url = add_query_arg( $query_args, "$protocol://fonts.googleapis.com/css" );
+ }
+
+ return $font_url;
+}
+
+/**
+ * Enqueues scripts and styles for front-end.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_scripts_styles() {
+ global $wp_styles;
+
+ /*
+ * Adds JavaScript to pages with the comment form to support
+ * sites with threaded comments (when in use).
+ */
+ if ( is_singular() && comments_open() && get_option( 'thread_comments' ) )
+ wp_enqueue_script( 'comment-reply' );
+
+ /*
+ * Adds JavaScript for handling the navigation menu hide-and-show behavior.
+ */
+ wp_enqueue_script( 'twentytwelve-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '1.0', true );
+
+ $font_url = twentytwelve_get_font_url();
+ if ( ! empty( $font_url ) )
+ wp_enqueue_style( 'twentytwelve-fonts', esc_url_raw( $font_url ), array(), null );
+
+ /*
+ * Loads our main stylesheet.
+ */
+ wp_enqueue_style( 'twentytwelve-style', get_stylesheet_uri() );
+
+ /*
+ * Loads the Internet Explorer specific stylesheet.
+ */
+ wp_enqueue_style( 'twentytwelve-ie', get_template_directory_uri() . '/css/ie.css', array( 'twentytwelve-style' ), '20121010' );
+ $wp_styles->add_data( 'twentytwelve-ie', 'conditional', 'lt IE 9' );
+}
+add_action( 'wp_enqueue_scripts', 'twentytwelve_scripts_styles' );
+
+/**
+ * Adds additional stylesheets to the TinyMCE editor if needed.
+ *
+ * @uses twentytwelve_get_font_url() To get the Google Font stylesheet URL.
+ *
+ * @since Twenty Twelve 1.2
+ *
+ * @param string $mce_css CSS path to load in TinyMCE.
+ * @return string
+ */
+function twentytwelve_mce_css( $mce_css ) {
+ $font_url = twentytwelve_get_font_url();
+
+ if ( empty( $font_url ) )
+ return $mce_css;
+
+ if ( ! empty( $mce_css ) )
+ $mce_css .= ',';
+
+ $mce_css .= esc_url_raw( str_replace( ',', '%2C', $font_url ) );
+
+ return $mce_css;
+}
+add_filter( 'mce_css', 'twentytwelve_mce_css' );
+
+/**
+ * Creates a nicely formatted and more specific title element text
+ * for output in head of document, based on current view.
+ *
+ * @since Twenty Twelve 1.0
+ *
+ * @param string $title Default title text for current view.
+ * @param string $sep Optional separator.
+ * @return string Filtered title.
+ */
+function twentytwelve_wp_title( $title, $sep ) {
+ global $paged, $page;
+
+ if ( is_feed() )
+ return $title;
+
+ // Add the site name.
+ $title .= get_bloginfo( 'name' );
+
+ // Add the site description for the home/front page.
+ $site_description = get_bloginfo( 'description', 'display' );
+ if ( $site_description && ( is_home() || is_front_page() ) )
+ $title = "$title $sep $site_description";
+
+ // Add a page number if necessary.
+ if ( $paged >= 2 || $page >= 2 )
+ $title = "$title $sep " . sprintf( __( 'Page %s', 'twentytwelve' ), max( $paged, $page ) );
+
+ return $title;
+}
+add_filter( 'wp_title', 'twentytwelve_wp_title', 10, 2 );
+
+/**
+ * Makes our wp_nav_menu() fallback -- wp_page_menu() -- show a home link.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_page_menu_args( $args ) {
+ if ( ! isset( $args['show_home'] ) )
+ $args['show_home'] = true;
+ return $args;
+}
+add_filter( 'wp_page_menu_args', 'twentytwelve_page_menu_args' );
+
+/**
+ * Registers our main widget area and the front page widget areas.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_widgets_init() {
+ register_sidebar( array(
+ 'name' => __( 'Main Sidebar', 'twentytwelve' ),
+ 'id' => 'sidebar-1',
+ 'description' => __( 'Appears on posts and pages except the optional Front Page template, which has its own widgets', 'twentytwelve' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'First Front Page Widget Area', 'twentytwelve' ),
+ 'id' => 'sidebar-2',
+ 'description' => __( 'Appears when using the optional Front Page template with a page set as Static Front Page', 'twentytwelve' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+
+ register_sidebar( array(
+ 'name' => __( 'Second Front Page Widget Area', 'twentytwelve' ),
+ 'id' => 'sidebar-3',
+ 'description' => __( 'Appears when using the optional Front Page template with a page set as Static Front Page', 'twentytwelve' ),
+ 'before_widget' => '<aside id="%1$s" class="widget %2$s">',
+ 'after_widget' => '</aside>',
+ 'before_title' => '<h3 class="widget-title">',
+ 'after_title' => '</h3>',
+ ) );
+}
+add_action( 'widgets_init', 'twentytwelve_widgets_init' );
+
+if ( ! function_exists( 'twentytwelve_content_nav' ) ) :
+/**
+ * Displays navigation to next/previous pages when applicable.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_content_nav( $html_id ) {
+ global $wp_query;
+
+ $html_id = esc_attr( $html_id );
+
+ if ( $wp_query->max_num_pages > 1 ) : ?>
+ <nav id="<?php echo $html_id; ?>" class="navigation" role="navigation">
+ <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentytwelve' ); ?></h3>
+ <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">&larr;</span> Older posts', 'twentytwelve' ) ); ?></div>
+ <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">&rarr;</span>', 'twentytwelve' ) ); ?></div>
+ </nav><!-- #<?php echo $html_id; ?> .navigation -->
+ <?php endif;
+}
+endif;
+
+if ( ! function_exists( 'twentytwelve_comment' ) ) :
+/**
+ * Template for comments and pingbacks.
+ *
+ * To override this walker in a child theme without modifying the comments template
+ * simply create your own twentytwelve_comment(), and that function will be used instead.
+ *
+ * Used as a callback by wp_list_comments() for displaying the comments.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_comment( $comment, $args, $depth ) {
+ $GLOBALS['comment'] = $comment;
+ switch ( $comment->comment_type ) :
+ case 'pingback' :
+ case 'trackback' :
+ // Display trackbacks differently than normal comments.
+ ?>
+ <li <?php comment_class(); ?> id="comment-<?php comment_ID(); ?>">
+ <p><?php _e( 'Pingback:', 'twentytwelve' ); ?> <?php comment_author_link(); ?> <?php edit_comment_link( __( '(Edit)', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?></p>
+ <?php
+ break;
+ default :
+ // Proceed with normal comments.
+ global $post;
+ ?>
+ <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
+ <article id="comment-<?php comment_ID(); ?>" class="comment">
+ <header class="comment-meta comment-author vcard">
+ <?php
+ echo get_avatar( $comment, 44 );
+ printf( '<cite><b class="fn">%1$s</b> %2$s</cite>',
+ get_comment_author_link(),
+ // If current post author is also comment author, make it known visually.
+ ( $comment->user_id === $post->post_author ) ? '<span>' . __( 'Post author', 'twentytwelve' ) . '</span>' : ''
+ );
+ printf( '<a href="%1$s"><time datetime="%2$s">%3$s</time></a>',
+ esc_url( get_comment_link( $comment->comment_ID ) ),
+ get_comment_time( 'c' ),
+ /* translators: 1: date, 2: time */
+ sprintf( __( '%1$s at %2$s', 'twentytwelve' ), get_comment_date(), get_comment_time() )
+ );
+ ?>
+ </header><!-- .comment-meta -->
+
+ <?php if ( '0' == $comment->comment_approved ) : ?>
+ <p class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'twentytwelve' ); ?></p>
+ <?php endif; ?>
+
+ <section class="comment-content comment">
+ <?php comment_text(); ?>
+ <?php edit_comment_link( __( 'Edit', 'twentytwelve' ), '<p class="edit-link">', '</p>' ); ?>
+ </section><!-- .comment-content -->
+
+ <div class="reply">
+ <?php comment_reply_link( array_merge( $args, array( 'reply_text' => __( 'Reply', 'twentytwelve' ), 'after' => ' <span>&darr;</span>', 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
+ </div><!-- .reply -->
+ </article><!-- #comment-## -->
+ <?php
+ break;
+ endswitch; // end comment_type check
+}
+endif;
+
+if ( ! function_exists( 'twentytwelve_entry_meta' ) ) :
+/**
+ * Prints HTML with meta information for current post: categories, tags, permalink, author, and date.
+ *
+ * Create your own twentytwelve_entry_meta() to override in a child theme.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_entry_meta() {
+ // Translators: used between list items, there is a space after the comma.
+ $categories_list = get_the_category_list( __( ', ', 'twentytwelve' ) );
+
+ // Translators: used between list items, there is a space after the comma.
+ $tag_list = get_the_tag_list( '', __( ', ', 'twentytwelve' ) );
+
+ $date = sprintf( '<a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s">%4$s</time></a>',
+ esc_url( get_permalink() ),
+ esc_attr( get_the_time() ),
+ esc_attr( get_the_date( 'c' ) ),
+ esc_html( get_the_date() )
+ );
+
+ $author = sprintf( '<span class="author vcard"><a class="url fn n" href="%1$s" title="%2$s" rel="author">%3$s</a></span>',
+ esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ),
+ esc_attr( sprintf( __( 'View all posts by %s', 'twentytwelve' ), get_the_author() ) ),
+ get_the_author()
+ );
+
+ // Translators: 1 is category, 2 is tag, 3 is the date and 4 is the author's name.
+ if ( $tag_list ) {
+ $utility_text = __( 'This entry was posted in %1$s and tagged %2$s on %3$s<span class="by-author"> by %4$s</span>.', 'twentytwelve' );
+ } elseif ( $categories_list ) {
+ $utility_text = __( 'This entry was posted in %1$s on %3$s<span class="by-author"> by %4$s</span>.', 'twentytwelve' );
+ } else {
+ $utility_text = __( 'This entry was posted on %3$s<span class="by-author"> by %4$s</span>.', 'twentytwelve' );
+ }
+
+ printf(
+ $utility_text,
+ $categories_list,
+ $tag_list,
+ $date,
+ $author
+ );
+}
+endif;
+
+/**
+ * Extends the default WordPress body class to denote:
+ * 1. Using a full-width layout, when no active widgets in the sidebar
+ * or full-width template.
+ * 2. Front Page template: thumbnail in use and number of sidebars for
+ * widget areas.
+ * 3. White or empty background color to change the layout and spacing.
+ * 4. Custom fonts enabled.
+ * 5. Single or multiple authors.
+ *
+ * @since Twenty Twelve 1.0
+ *
+ * @param array Existing class values.
+ * @return array Filtered class values.
+ */
+function twentytwelve_body_class( $classes ) {
+ $background_color = get_background_color();
+ $background_image = get_background_image();
+
+ if ( ! is_active_sidebar( 'sidebar-1' ) || is_page_template( 'page-templates/full-width.php' ) )
+ $classes[] = 'full-width';
+
+ if ( is_page_template( 'page-templates/front-page.php' ) ) {
+ $classes[] = 'template-front-page';
+ if ( has_post_thumbnail() )
+ $classes[] = 'has-post-thumbnail';
+ if ( is_active_sidebar( 'sidebar-2' ) && is_active_sidebar( 'sidebar-3' ) )
+ $classes[] = 'two-sidebars';
+ }
+
+ if ( empty( $background_image ) ) {
+ if ( empty( $background_color ) )
+ $classes[] = 'custom-background-empty';
+ elseif ( in_array( $background_color, array( 'fff', 'ffffff' ) ) )
+ $classes[] = 'custom-background-white';
+ }
+
+ // Enable custom font class only if the font CSS is queued to load.
+ if ( wp_style_is( 'twentytwelve-fonts', 'queue' ) )
+ $classes[] = 'custom-font-enabled';
+
+ if ( ! is_multi_author() )
+ $classes[] = 'single-author';
+
+ return $classes;
+}
+add_filter( 'body_class', 'twentytwelve_body_class' );
+
+/**
+ * Adjusts content_width value for full-width and single image attachment
+ * templates, and when there are no active widgets in the sidebar.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_content_width() {
+ if ( is_page_template( 'page-templates/full-width.php' ) || is_attachment() || ! is_active_sidebar( 'sidebar-1' ) ) {
+ global $content_width;
+ $content_width = 960;
+ }
+}
+add_action( 'template_redirect', 'twentytwelve_content_width' );
+
+/**
+ * Add postMessage support for site title and description for the Theme Customizer.
+ *
+ * @since Twenty Twelve 1.0
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ * @return void
+ */
+function twentytwelve_customize_register( $wp_customize ) {
+ $wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
+ $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
+ $wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';
+}
+add_action( 'customize_register', 'twentytwelve_customize_register' );
+
+/**
+ * Binds JS handlers to make Theme Customizer preview reload changes asynchronously.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_customize_preview_js() {
+ wp_enqueue_script( 'twentytwelve-customizer', get_template_directory_uri() . '/js/theme-customizer.js', array( 'customize-preview' ), '20130301', true );
+}
+add_action( 'customize_preview_init', 'twentytwelve_customize_preview_js' );
diff --git a/src/wp-content/themes/twentytwelve/header.php b/src/wp-content/themes/twentytwelve/header.php
new file mode 100644
index 0000000000..2d3dfa630f
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/header.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * The Header for our theme.
+ *
+ * Displays all of the <head> section and everything up till <div id="main">
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?><!DOCTYPE html>
+<!--[if IE 7]>
+<html class="ie ie7" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if IE 8]>
+<html class="ie ie8" <?php language_attributes(); ?>>
+<![endif]-->
+<!--[if !(IE 7) | !(IE 8) ]><!-->
+<html <?php language_attributes(); ?>>
+<!--<![endif]-->
+<head>
+<meta charset="<?php bloginfo( 'charset' ); ?>" />
+<meta name="viewport" content="width=device-width" />
+<title><?php wp_title( '|', true, 'right' ); ?></title>
+<link rel="profile" href="http://gmpg.org/xfn/11" />
+<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
+<?php // Loads HTML5 JavaScript file to add support for HTML5 elements in older IE versions. ?>
+<!--[if lt IE 9]>
+<script src="<?php echo get_template_directory_uri(); ?>/js/html5.js" type="text/javascript"></script>
+<![endif]-->
+<?php wp_head(); ?>
+</head>
+
+<body <?php body_class(); ?>>
+<div id="page" class="hfeed site">
+ <header id="masthead" class="site-header" role="banner">
+ <hgroup>
+ <h1 class="site-title"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php echo esc_attr( get_bloginfo( 'name', 'display' ) ); ?>" rel="home"><?php bloginfo( 'name' ); ?></a></h1>
+ <h2 class="site-description"><?php bloginfo( 'description' ); ?></h2>
+ </hgroup>
+
+ <nav id="site-navigation" class="main-navigation" role="navigation">
+ <h3 class="menu-toggle"><?php _e( 'Menu', 'twentytwelve' ); ?></h3>
+ <a class="assistive-text" href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentytwelve' ); ?>"><?php _e( 'Skip to content', 'twentytwelve' ); ?></a>
+ <?php wp_nav_menu( array( 'theme_location' => 'primary', 'menu_class' => 'nav-menu' ) ); ?>
+ </nav><!-- #site-navigation -->
+
+ <?php $header_image = get_header_image();
+ if ( ! empty( $header_image ) ) : ?>
+ <a href="<?php echo esc_url( home_url( '/' ) ); ?>"><img src="<?php echo esc_url( $header_image ); ?>" class="header-image" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="" /></a>
+ <?php endif; ?>
+ </header><!-- #masthead -->
+
+ <div id="main" class="wrapper"> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/image.php b/src/wp-content/themes/twentytwelve/image.php
new file mode 100644
index 0000000000..b2fcb428ac
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/image.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * The template for displaying image attachments.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <article id="post-<?php the_ID(); ?>" <?php post_class( 'image-attachment' ); ?>>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php the_title(); ?></h1>
+
+ <footer class="entry-meta">
+ <?php
+ $metadata = wp_get_attachment_metadata();
+ printf( __( '<span class="meta-prep meta-prep-entry-date">Published </span> <span class="entry-date"><time class="entry-date" datetime="%1$s">%2$s</time></span> at <a href="%3$s" title="Link to full-size image">%4$s &times; %5$s</a> in <a href="%6$s" title="Return to %7$s" rel="gallery">%8$s</a>.', 'twentytwelve' ),
+ esc_attr( get_the_date( 'c' ) ),
+ esc_html( get_the_date() ),
+ esc_url( wp_get_attachment_url() ),
+ $metadata['width'],
+ $metadata['height'],
+ esc_url( get_permalink( $post->post_parent ) ),
+ esc_attr( strip_tags( get_the_title( $post->post_parent ) ) ),
+ get_the_title( $post->post_parent )
+ );
+ ?>
+ <?php edit_post_link( __( 'Edit', 'twentytwelve' ), '<span class="edit-link">', '</span>' ); ?>
+ </footer><!-- .entry-meta -->
+
+ <nav id="image-navigation" class="navigation" role="navigation">
+ <span class="previous-image"><?php previous_image_link( false, __( '&larr; Previous', 'twentytwelve' ) ); ?></span>
+ <span class="next-image"><?php next_image_link( false, __( 'Next &rarr;', 'twentytwelve' ) ); ?></span>
+ </nav><!-- #image-navigation -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+
+ <div class="entry-attachment">
+ <div class="attachment">
+<?php
+/**
+ * Grab the IDs of all the image attachments in a gallery so we can get the URL of the next adjacent image in a gallery,
+ * or the first image (if we're looking at the last image in a gallery), or, in a gallery of one, just the link to that image file
+ */
+$attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) );
+foreach ( $attachments as $k => $attachment ) :
+ if ( $attachment->ID == $post->ID )
+ break;
+endforeach;
+
+$k++;
+// If there is more than 1 attachment in a gallery
+if ( count( $attachments ) > 1 ) :
+ if ( isset( $attachments[ $k ] ) ) :
+ // get the URL of the next image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ $k ]->ID );
+ else :
+ // or get the URL of the first image attachment
+ $next_attachment_url = get_attachment_link( $attachments[ 0 ]->ID );
+ endif;
+else :
+ // or, if there's only 1 image, get the URL of the image
+ $next_attachment_url = wp_get_attachment_url();
+endif;
+?>
+ <a href="<?php echo esc_url( $next_attachment_url ); ?>" title="<?php the_title_attribute(); ?>" rel="attachment"><?php
+ $attachment_size = apply_filters( 'twentytwelve_attachment_size', array( 960, 960 ) );
+ echo wp_get_attachment_image( $post->ID, $attachment_size );
+ ?></a>
+
+ <?php if ( ! empty( $post->post_excerpt ) ) : ?>
+ <div class="entry-caption">
+ <?php the_excerpt(); ?>
+ </div>
+ <?php endif; ?>
+ </div><!-- .attachment -->
+
+ </div><!-- .entry-attachment -->
+
+ <div class="entry-description">
+ <?php the_content(); ?>
+ <?php wp_link_pages( array( 'before' => '<div class="page-links">' . __( 'Pages:', 'twentytwelve' ), 'after' => '</div>' ) ); ?>
+ </div><!-- .entry-description -->
+
+ </div><!-- .entry-content -->
+
+ </article><!-- #post -->
+
+ <?php comments_template(); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/inc/custom-header.php b/src/wp-content/themes/twentytwelve/inc/custom-header.php
new file mode 100644
index 0000000000..595bf98f5a
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/inc/custom-header.php
@@ -0,0 +1,165 @@
+<?php
+/**
+ * Implements an optional custom header for Twenty Twelve.
+ * See http://codex.wordpress.org/Custom_Headers
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+/**
+ * Sets up the WordPress core custom header arguments and settings.
+ *
+ * @uses add_theme_support() to register support for 3.4 and up.
+ * @uses twentytwelve_header_style() to style front-end.
+ * @uses twentytwelve_admin_header_style() to style wp-admin form.
+ * @uses twentytwelve_admin_header_image() to add custom markup to wp-admin form.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_custom_header_setup() {
+ $args = array(
+ // Text color and image (empty to use none).
+ 'default-text-color' => '515151',
+ 'default-image' => '',
+
+ // Set height and width, with a maximum value for the width.
+ 'height' => 250,
+ 'width' => 960,
+ 'max-width' => 2000,
+
+ // Support flexible height and width.
+ 'flex-height' => true,
+ 'flex-width' => true,
+
+ // Random image rotation off by default.
+ 'random-default' => false,
+
+ // Callbacks for styling the header and the admin preview.
+ 'wp-head-callback' => 'twentytwelve_header_style',
+ 'admin-head-callback' => 'twentytwelve_admin_header_style',
+ 'admin-preview-callback' => 'twentytwelve_admin_header_image',
+ );
+
+ add_theme_support( 'custom-header', $args );
+}
+add_action( 'after_setup_theme', 'twentytwelve_custom_header_setup' );
+
+/**
+ * Loads our special font CSS file.
+ *
+ * @since Twenty Twelve 1.2
+ *
+ * @return void
+ */
+function twentytwelve_custom_header_fonts() {
+ $font_url = twentytwelve_get_font_url();
+ if ( ! empty( $font_url ) )
+ wp_enqueue_style( 'twentytwelve-fonts', esc_url_raw( $font_url ), array(), null );
+}
+add_action( 'admin_print_styles-appearance_page_custom-header', 'twentytwelve_custom_header_fonts' );
+
+/**
+ * Styles the header text displayed on the blog.
+ *
+ * get_header_textcolor() options: 515151 is default, hide text (returns 'blank'), or any hex value.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_header_style() {
+ $text_color = get_header_textcolor();
+
+ // If no custom options for text are set, let's bail
+ if ( $text_color == get_theme_support( 'custom-header', 'default-text-color' ) )
+ return;
+
+ // If we get this far, we have custom styles.
+ ?>
+ <style type="text/css" id="twentytwelve-header-css">
+ <?php
+ // Has the text been hidden?
+ if ( ! display_header_text() ) :
+ ?>
+ .site-title,
+ .site-description {
+ position: absolute;
+ clip: rect(1px 1px 1px 1px); /* IE7 */
+ clip: rect(1px, 1px, 1px, 1px);
+ }
+ <?php
+ // If the user has set a custom color for the text, use that.
+ else :
+ ?>
+ .site-header h1 a,
+ .site-header h2 {
+ color: #<?php echo $text_color; ?>;
+ }
+ <?php endif; ?>
+ </style>
+ <?php
+}
+
+/**
+ * Styles the header image displayed on the Appearance > Header admin panel.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_admin_header_style() {
+?>
+ <style type="text/css" id="twentytwelve-admin-header-css">
+ .appearance_page_custom-header #headimg {
+ border: none;
+ font-family: "Open Sans", Helvetica, Arial, sans-serif;
+ }
+ #headimg h1,
+ #headimg h2 {
+ line-height: 1.84615;
+ margin: 0;
+ padding: 0;
+ }
+ #headimg h1 {
+ font-size: 26px;
+ }
+ #headimg h1 a {
+ color: #515151;
+ text-decoration: none;
+ }
+ #headimg h1 a:hover {
+ color: #21759b !important; /* Has to override custom inline style. */
+ }
+ #headimg h2 {
+ color: #757575;
+ font-size: 13px;
+ margin-bottom: 24px;
+ }
+ #headimg img {
+ max-width: <?php echo get_theme_support( 'custom-header', 'max-width' ); ?>px;
+ }
+ </style>
+<?php
+}
+
+/**
+ * Outputs markup to be displayed on the Appearance > Header admin panel.
+ * This callback overrides the default markup displayed there.
+ *
+ * @since Twenty Twelve 1.0
+ */
+function twentytwelve_admin_header_image() {
+ ?>
+ <div id="headimg">
+ <?php
+ if ( ! display_header_text() )
+ $style = ' style="display:none;"';
+ else
+ $style = ' style="color:#' . get_header_textcolor() . ';"';
+ ?>
+ <h1 class="displaying-header-text"><a id="name"<?php echo $style; ?> onclick="return false;" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
+ <h2 id="desc" class="displaying-header-text"<?php echo $style; ?>><?php bloginfo( 'description' ); ?></h2>
+ <?php $header_image = get_header_image();
+ if ( ! empty( $header_image ) ) : ?>
+ <img src="<?php echo esc_url( $header_image ); ?>" class="header-image" width="<?php echo get_custom_header()->width; ?>" height="<?php echo get_custom_header()->height; ?>" alt="" />
+ <?php endif; ?>
+ </div>
+<?php } \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/index.php b/src/wp-content/themes/twentytwelve/index.php
new file mode 100644
index 0000000000..91201b447f
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/index.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * The main template file.
+ *
+ * This is the most generic template file in a WordPress theme
+ * and one of the two required files for a theme (the other being style.css).
+ * It is used to display a page when nothing more specific matches a query.
+ * For example, it puts together the home page when no home.php file exists.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+ <?php if ( have_posts() ) : ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentytwelve_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+
+ <?php if ( current_user_can( 'edit_posts' ) ) :
+ // Show a different message to a logged-in user who can add posts.
+ ?>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'No posts to display', 'twentytwelve' ); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <p><?php printf( __( 'Ready to publish your first post? <a href="%s">Get started here</a>.', 'twentytwelve' ), admin_url( 'post-new.php' ) ); ?></p>
+ </div><!-- .entry-content -->
+
+ <?php else :
+ // Show the default message to everyone else.
+ ?>
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentytwelve' ); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <p><?php _e( 'Apologies, but no results were found. Perhaps searching will help find a related post.', 'twentytwelve' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ <?php endif; // end current_user_can() check ?>
+
+ </article><!-- #post-0 -->
+
+ <?php endif; // end have_posts() check ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/js/html5.js b/src/wp-content/themes/twentytwelve/js/html5.js
new file mode 100644
index 0000000000..a7889168fb
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/js/html5.js
@@ -0,0 +1,7 @@
+/*! HTML5 Shiv v3.6 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
+/* Source: https://github.com/aFarkas/html5shiv */
+(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
+a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
+c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^<|^(?:a|b|button|code|div|fieldset|form|h1|h2|h3|h4|h5|h6|i|iframe|img|input|label|li|link|ol|option|p|param|q|script|select|span|strong|style|table|tbody|td|textarea|tfoot|th|thead|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");
+var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,
+b){a||(a=f);if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document); \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/js/navigation.js b/src/wp-content/themes/twentytwelve/js/navigation.js
new file mode 100644
index 0000000000..915e25a91d
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/js/navigation.js
@@ -0,0 +1,33 @@
+/**
+ * navigation.js
+ *
+ * Handles toggling the navigation menu for small screens.
+ */
+( function() {
+ var nav = document.getElementById( 'site-navigation' ), button, menu;
+ if ( ! nav )
+ return;
+ button = nav.getElementsByTagName( 'h3' )[0];
+ menu = nav.getElementsByTagName( 'ul' )[0];
+ if ( ! button )
+ return;
+
+ // Hide button if menu is missing or empty.
+ if ( ! menu || ! menu.childNodes.length ) {
+ button.style.display = 'none';
+ return;
+ }
+
+ button.onclick = function() {
+ if ( -1 == menu.className.indexOf( 'nav-menu' ) )
+ menu.className = 'nav-menu';
+
+ if ( -1 != button.className.indexOf( 'toggled-on' ) ) {
+ button.className = button.className.replace( ' toggled-on', '' );
+ menu.className = menu.className.replace( ' toggled-on', '' );
+ } else {
+ button.className += ' toggled-on';
+ menu.className += ' toggled-on';
+ }
+ };
+} )(); \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/js/theme-customizer.js b/src/wp-content/themes/twentytwelve/js/theme-customizer.js
new file mode 100644
index 0000000000..bde05d9c51
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/js/theme-customizer.js
@@ -0,0 +1,64 @@
+/**
+ * Theme Customizer enhancements for a better user experience.
+ *
+ * Contains handlers to make Theme Customizer preview reload changes asynchronously.
+ * Things like site title, description, and background color changes.
+ */
+
+( function( $ ) {
+ // Site title and description.
+ wp.customize( 'blogname', function( value ) {
+ value.bind( function( to ) {
+ $( '.site-title a' ).text( to );
+ } );
+ } );
+ wp.customize( 'blogdescription', function( value ) {
+ value.bind( function( to ) {
+ $( '.site-description' ).text( to );
+ } );
+ } );
+
+ // Header text color
+ wp.customize( 'header_textcolor', function( value ) {
+ value.bind( function( to ) {
+ if ( 'blank' === to ) {
+ $( '.site-title, .site-title a, .site-description' ).css( {
+ 'clip': 'rect(1px, 1px, 1px, 1px)',
+ 'position': 'absolute'
+ } );
+ } else {
+ $( '.site-title, .site-title a, .site-description' ).css( {
+ 'clip': 'auto',
+ 'color': to,
+ 'position': 'relative'
+ } );
+ }
+ } );
+ } );
+
+ // Hook into background color/image change and adjust body class value as needed.
+ wp.customize( 'background_color', function( value ) {
+ value.bind( function( to ) {
+ var body = $( 'body' );
+
+ if ( ( '#ffffff' == to || '#fff' == to ) && 'none' == body.css( 'background-image' ) )
+ body.addClass( 'custom-background-white' );
+ else if ( '' == to && 'none' == body.css( 'background-image' ) )
+ body.addClass( 'custom-background-empty' );
+ else
+ body.removeClass( 'custom-background-empty custom-background-white' );
+ } );
+ } );
+ wp.customize( 'background_image', function( value ) {
+ value.bind( function( to ) {
+ var body = $( 'body' );
+
+ if ( '' != to )
+ body.removeClass( 'custom-background-empty custom-background-white' );
+ else if ( 'rgb(255, 255, 255)' == body.css( 'background-color' ) )
+ body.addClass( 'custom-background-white' );
+ else if ( 'rgb(230, 230, 230)' == body.css( 'background-color' ) && '' == _wpCustomizeSettings.values.background_color )
+ body.addClass( 'custom-background-empty' );
+ } );
+ } );
+} )( jQuery );
diff --git a/src/wp-content/themes/twentytwelve/languages/twentytwelve.pot b/src/wp-content/themes/twentytwelve/languages/twentytwelve.pot
new file mode 100644
index 0000000000..2c1fed3995
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/languages/twentytwelve.pot
@@ -0,0 +1,353 @@
+# Copyright (C) 2013 the WordPress team
+# This file is distributed under the GNU General Public License v2 or later.
+msgid ""
+msgstr ""
+"Project-Id-Version: Twenty Twelve 1.2\n"
+"Report-Msgid-Bugs-To: http://wordpress.org/tags/twentytwelve\n"
+"POT-Creation-Date: 2013-08-01 18:14:14+00:00\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"PO-Revision-Date: 2013-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+
+#: 404.php:17
+msgid "This is somewhat embarrassing, isn&rsquo;t it?"
+msgstr ""
+
+#: 404.php:21
+msgid ""
+"It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps "
+"searching can help."
+msgstr ""
+
+#: archive.php:29
+msgid "Daily Archives: %s"
+msgstr ""
+
+#: archive.php:31
+msgid "Monthly Archives: %s"
+msgstr ""
+
+#: archive.php:31
+msgctxt "monthly archives date format"
+msgid "F Y"
+msgstr ""
+
+#: archive.php:33
+msgid "Yearly Archives: %s"
+msgstr ""
+
+#: archive.php:33
+msgctxt "yearly archives date format"
+msgid "Y"
+msgstr ""
+
+#: archive.php:35
+msgid "Archives"
+msgstr ""
+
+#: author.php:32
+msgid "Author Archives: %s"
+msgstr ""
+
+#: author.php:53 content.php:53
+msgid "About %s"
+msgstr ""
+
+#: category.php:21
+msgid "Category Archives: %s"
+msgstr ""
+
+#: comments.php:31
+msgid "One thought on &ldquo;%2$s&rdquo;"
+msgid_plural "%1$s thoughts on &ldquo;%2$s&rdquo;"
+msgstr[0] ""
+msgstr[1] ""
+
+#: comments.php:42
+msgid "Comment navigation"
+msgstr ""
+
+#: comments.php:43
+msgid "&larr; Older Comments"
+msgstr ""
+
+#: comments.php:44
+msgid "Newer Comments &rarr;"
+msgstr ""
+
+#: comments.php:53
+msgid "Comments are closed."
+msgstr ""
+
+#: content-aside.php:15 content-image.php:13 content-link.php:14
+#: content-quote.php:13 content-status.php:21 content.php:39
+msgid "Continue reading <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: content-aside.php:20 content-link.php:18 content-quote.php:17
+#: content-status.php:15
+msgid "Permalink to %s"
+msgstr ""
+
+#: content-aside.php:23 content-image.php:23 content-link.php:21
+#: content-quote.php:20 content-status.php:27 content.php:28
+msgid "Leave a reply"
+msgstr ""
+
+#: content-aside.php:23 content-image.php:23 content-link.php:21
+#: content-quote.php:20 content-status.php:27 content.php:28
+msgid "1 Reply"
+msgstr ""
+
+#: content-aside.php:23 content-image.php:23 content-link.php:21
+#: content-quote.php:20 content-status.php:27 content.php:28
+msgid "% Replies"
+msgstr ""
+
+#: content-aside.php:26 content-image.php:26 content-link.php:24
+#: content-page.php:24 content-quote.php:23 content-status.php:30
+#: content.php:46 functions.php:341 image.php:37
+msgid "Edit"
+msgstr ""
+
+#: content-link.php:12
+msgid "Link"
+msgstr ""
+
+#: content-none.php:13 index.php:49 search.php:34
+msgid "Nothing Found"
+msgstr ""
+
+#: content-none.php:17 index.php:53
+msgid ""
+"Apologies, but no results were found. Perhaps searching will help find a "
+"related post."
+msgstr ""
+
+#: content-page.php:21 content.php:40 image.php:92
+msgid "Pages:"
+msgstr ""
+
+#: content.php:14
+msgid "Featured post"
+msgstr ""
+
+#: content.php:57
+msgid "View all posts by %s <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#. #-#-#-#-# twentytwelve.pot (Twenty Twelve 1.2) #-#-#-#-#
+#. Author URI of the plugin/theme
+#: footer.php:17
+msgid "http://wordpress.org/"
+msgstr ""
+
+#: footer.php:17
+msgid "Semantic Personal Publishing Platform"
+msgstr ""
+
+#: footer.php:17
+msgid "Proudly powered by %s"
+msgstr ""
+
+#: functions.php:64
+msgid "Primary Menu"
+msgstr ""
+
+#. translators: If there are characters in your language that are not supported
+#. by Open Sans, translate this to 'off'. Do not translate into your own
+#. language.
+#: functions.php:100
+msgctxt "Open Sans font: on or off"
+msgid "on"
+msgstr ""
+
+#. translators: To add an additional Open Sans character subset specific to
+#. your language, translate
+#. this to 'greek', 'cyrillic' or 'vietnamese'. Do not translate into your
+#. own language.
+#: functions.php:105
+msgctxt "Open Sans font: add new subset (greek, cyrillic, vietnamese)"
+msgid "no-subset"
+msgstr ""
+
+#: functions.php:213
+msgid "Page %s"
+msgstr ""
+
+#: functions.php:238
+msgid "Main Sidebar"
+msgstr ""
+
+#: functions.php:240
+msgid ""
+"Appears on posts and pages except the optional Front Page template, which "
+"has its own widgets"
+msgstr ""
+
+#: functions.php:248
+msgid "First Front Page Widget Area"
+msgstr ""
+
+#: functions.php:250 functions.php:260
+msgid ""
+"Appears when using the optional Front Page template with a page set as "
+"Static Front Page"
+msgstr ""
+
+#: functions.php:258
+msgid "Second Front Page Widget Area"
+msgstr ""
+
+#: functions.php:282 single.php:20
+msgid "Post navigation"
+msgstr ""
+
+#: functions.php:283
+msgid "<span class=\"meta-nav\">&larr;</span> Older posts"
+msgstr ""
+
+#: functions.php:284
+msgid "Newer posts <span class=\"meta-nav\">&rarr;</span>"
+msgstr ""
+
+#: functions.php:309
+msgid "Pingback:"
+msgstr ""
+
+#: functions.php:309
+msgid "(Edit)"
+msgstr ""
+
+#: functions.php:324
+msgid "Post author"
+msgstr ""
+
+#. translators: 1: date, 2: time
+#: functions.php:330
+msgid "%1$s at %2$s"
+msgstr ""
+
+#: functions.php:336
+msgid "Your comment is awaiting moderation."
+msgstr ""
+
+#: functions.php:345
+msgid "Reply"
+msgstr ""
+
+#. Translators: used between list items, there is a space after the comma.
+#: functions.php:364 functions.php:367
+msgid ", "
+msgstr ""
+
+#: functions.php:378
+msgid "View all posts by %s"
+msgstr ""
+
+#. Translators: 1 is category, 2 is tag, 3 is the date and 4 is the author's
+#. name.
+#: functions.php:384
+msgid ""
+"This entry was posted in %1$s and tagged %2$s on %3$s<span class=\"by-author"
+"\"> by %4$s</span>."
+msgstr ""
+
+#: functions.php:386
+msgid ""
+"This entry was posted in %1$s on %3$s<span class=\"by-author\"> by %4$s</"
+"span>."
+msgstr ""
+
+#: functions.php:388
+msgid "This entry was posted on %3$s<span class=\"by-author\"> by %4$s</span>."
+msgstr ""
+
+#: header.php:43
+msgid "Menu"
+msgstr ""
+
+#: header.php:44
+msgid "Skip to content"
+msgstr ""
+
+#: image.php:26
+msgid ""
+"<span class=\"meta-prep meta-prep-entry-date\">Published </span> <span class="
+"\"entry-date\"><time class=\"entry-date\" datetime=\"%1$s\">%2$s</time></"
+"span> at <a href=\"%3$s\" title=\"Link to full-size image\">%4$s &times; "
+"%5$s</a> in <a href=\"%6$s\" title=\"Return to %7$s\" rel=\"gallery\">%8$s</"
+"a>."
+msgstr ""
+
+#: image.php:41
+msgid "&larr; Previous"
+msgstr ""
+
+#: image.php:42
+msgid "Next &rarr;"
+msgstr ""
+
+#: index.php:38
+msgid "No posts to display"
+msgstr ""
+
+#: index.php:42
+msgid "Ready to publish your first post? <a href=\"%s\">Get started here</a>."
+msgstr ""
+
+#: search.php:18
+msgid "Search Results for: %s"
+msgstr ""
+
+#: search.php:38
+msgid ""
+"Sorry, but nothing matched your search criteria. Please try again with some "
+"different keywords."
+msgstr ""
+
+#: single.php:21
+msgctxt "Previous post link"
+msgid "&larr;"
+msgstr ""
+
+#: single.php:22
+msgctxt "Next post link"
+msgid "&rarr;"
+msgstr ""
+
+#: tag.php:21
+msgid "Tag Archives: %s"
+msgstr ""
+
+#. Theme Name of the plugin/theme
+msgid "Twenty Twelve"
+msgstr ""
+
+#. Theme URI of the plugin/theme
+msgid "http://wordpress.org/themes/twentytwelve"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"The 2012 theme for WordPress is a fully responsive theme that looks great on "
+"any device. Features include a front page template with its own widgets, an "
+"optional display font, styling for post formats on both index and single "
+"views, and an optional no-sidebar page template. Make it yours with a custom "
+"menu, header image, and background."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "the WordPress team"
+msgstr ""
+
+#. Template Name of the plugin/theme
+msgid "Front Page Template"
+msgstr ""
+
+#. Template Name of the plugin/theme
+msgid "Full-width Page Template, No Sidebar"
+msgstr ""
diff --git a/src/wp-content/themes/twentytwelve/page-templates/front-page.php b/src/wp-content/themes/twentytwelve/page-templates/front-page.php
new file mode 100644
index 0000000000..9ae4f27dde
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/page-templates/front-page.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Template Name: Front Page Template
+ *
+ * Description: A page template that provides a key component of WordPress as a CMS
+ * by meeting the need for a carefully crafted introductory page. The front page template
+ * in Twenty Twelve consists of a page content area for adding text, images, video --
+ * anything you'd like -- followed by front-page-only widgets in one or two columns.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php if ( has_post_thumbnail() ) : ?>
+ <div class="entry-page-image">
+ <?php the_post_thumbnail(); ?>
+ </div><!-- .entry-page-image -->
+ <?php endif; ?>
+
+ <?php get_template_part( 'content', 'page' ); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar( 'front' ); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/page-templates/full-width.php b/src/wp-content/themes/twentytwelve/page-templates/full-width.php
new file mode 100644
index 0000000000..b0ce333c2d
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/page-templates/full-width.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Template Name: Full-width Page Template, No Sidebar
+ *
+ * Description: Twenty Twelve loves the no-sidebar look as much as
+ * you do. Use this page template to remove the sidebar from any page.
+ *
+ * Tip: to remove the sidebar from all posts and pages simply remove
+ * any active widgets from the Main Sidebar area, and the sidebar will
+ * disappear everywhere.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', 'page' ); ?>
+ <?php comments_template( '', true ); ?>
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/page.php b/src/wp-content/themes/twentytwelve/page.php
new file mode 100644
index 0000000000..dcda990c2c
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/page.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * The template for displaying all pages.
+ *
+ * This is the template that displays all pages by default.
+ * Please note that this is the WordPress construct of pages
+ * and that other 'pages' on your WordPress site will use a
+ * different template.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', 'page' ); ?>
+ <?php comments_template( '', true ); ?>
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/rtl.css b/src/wp-content/themes/twentytwelve/rtl.css
new file mode 100644
index 0000000000..1055f9cca9
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/rtl.css
@@ -0,0 +1,237 @@
+/*
+Theme Name: Twenty Twelve
+Description: Adds support for languages written in a Right To Left (RTL) direction.
+It's easy, just a matter of overwriting all the horizontal positioning attributes
+of your CSS stylesheet in a separate stylesheet file named rtl.css.
+
+See http://codex.wordpress.org/Right_to_Left_Language_Support
+*/
+
+
+body {
+ direction: rtl;
+ unicode-bidi: embed;
+}
+caption,
+th,
+td {
+ text-align: right;
+}
+
+/* =Repeatable patterns
+-------------------------------------------------------------- */
+
+/* Images */
+.site-content .gallery-columns-4 .gallery-item {
+ padding-left: 2%;
+ padding-right: 0;
+}
+.site-content .gallery-columns-5 .gallery-item {
+ padding-left: 2%;
+ padding-right: 0;
+}
+
+/* Navigation */
+.nav-previous,
+.previous-image {
+ float: right;
+}
+.nav-next,
+.next-image {
+ float: left;
+ text-align: left;
+}
+
+/* Author profiles */
+.author-avatar {
+ float: right;
+}
+.author-description {
+ float: right;
+ margin-right: 15px;
+ margin-right: 1.071428571rem;
+ margin-left: auto;
+}
+
+
+/* =Main Content
+----------------------------------------------- */
+
+.comment-content ol,
+.comment-content ul {
+ margin: 0 24px 0 0;
+ margin: 0 1.714285714rem 0 0;
+}
+
+
+/* =Basic post styling
+-------------------------------------------------------------- */
+
+.entry-content li,
+.comment-content li {
+ margin: 0 24px 0 0;
+ margin: 0 1.714285714rem 0 0;
+}
+.entry-content td,
+.comment-content td {
+ padding: 6px 0 6px 10px;
+}
+
+
+/* Aside posts */
+article.format-aside .aside {
+ border-right: 22px solid #a8bfe8;
+ border-left: none;
+}
+
+/* Link posts */
+article.format-link header {
+ float: left;
+}
+article.format-link .entry-content {
+ float: right;
+}
+
+/* Status posts */
+.format-status .entry-header img {
+ float: right;
+ margin-left: 21px;
+ margin-left: 1.5rem;
+ margin-right: 0;
+}
+
+
+/* =Comment styling
+-------------------------------------------------------------- */
+
+.comments-area article header img {
+ float: right;
+}
+.comments-area article header cite,
+.comments-area article header time {
+ margin-right: 85px;
+ margin-right: 6.071428571rem;
+ margin-left: auto;
+}
+.comments-area article header h4 {
+ left: 0;
+ right: auto;
+}
+.comments-area .bypostauthor cite span {
+ margin-right: 5px;
+ margin-right: 0.357142857rem;
+ margin-left: auto;
+}
+
+/* Comment form */
+#respond h3#reply-title #cancel-comment-reply-link {
+ margin-right: 10px;
+ margin-right: 0.714285714rem;
+ margin-left: auto;
+}
+label ~ span.required {
+ float: right;
+ margin: -18px -16px 0 0;
+ margin: -1.285714286rem -1.142857143rem 0 0;
+}
+
+
+/* =Front page template styling
+-------------------------------------------------------------- */
+
+.template-front-page .widget-area .widget_text img {
+ float: right;
+ margin: 8px 0 8px 24px;
+ margin: 0.571428571rem 0 0.571428571rem 1.714285714rem;
+}
+
+
+/* =Widget styling
+-------------------------------------------------------------- */
+
+.widget-area .widget ul ul {
+ margin-right: 12px;
+ margin-right: 0.857142857rem;
+ margin-left: auto;
+}
+.widget-area .textwidget li {
+ margin-left: auto;
+ margin-right: 36px;
+ margin-right: 2.571428571rem;
+}
+.widget_recent_entries .post-date,
+.widget_rss .rss-date {
+ margin-right: 12px;
+ margin-right: 0.857142857rem;
+ margin-left: auto;
+}
+#wp-calendar th,
+#wp-calendar td,
+#wp-calendar caption {
+ text-align: right;
+}
+#wp-calendar #next {
+ padding-left: 24px;
+ padding-left: 1.714285714rem;
+ text-align: left;
+ padding-right: 0;
+}
+
+/* =Media queries
+-------------------------------------------------------------- */
+
+/* Minimum width of 600 pixels. */
+@media screen and (min-width: 600px) {
+ .site-content,
+ .template-front-page.has-post-thumbnail article {
+ float: right;
+ }
+ .widget-area,
+ .entry-page-image {
+ float: left;
+ }
+ .site-header h1,
+ .site-header h2 {
+ text-align: right;
+ }
+ .template-front-page .widget-area .widget_text img {
+ float: right;
+ margin: 8px 0 8px 24px;
+ }
+ .template-front-page .widget-area .widget,
+ .template-front-page.two-sidebars .widget-area .front-widgets {
+ float: right;
+ }
+ .template-front-page .widget-area .widget:nth-child(odd) {
+ clear: left;
+ }
+ .template-front-page .widget-area .widget:nth-child(even),
+ .template-front-page.two-sidebars .widget-area .front-widgets + .front-widgets {
+ float: left;
+ margin: 0 24px 0;
+ margin: 0 1.714285714rem 0;
+ }
+ .main-navigation ul.nav-menu,
+ .main-navigation div.nav-menu > ul {
+ text-align: right;
+ }
+ .main-navigation li {
+ margin-left: 40px;
+ margin-left: 2.857142857rem;
+ margin-right: auto;
+ }
+ .main-navigation li ul ul {
+ margin-right: 0;
+ right: 100%;
+ left: auto;
+ }
+ .main-navigation ul li:hover > ul {
+ border-right: 0;
+ border-left: none;
+ }
+ .commentlist .children {
+ margin-right: 48px;
+ margin-right: 3.428571429rem;
+ margin-left: auto;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/screenshot.png b/src/wp-content/themes/twentytwelve/screenshot.png
new file mode 100644
index 0000000000..ee328b9553
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/screenshot.png
Binary files differ
diff --git a/src/wp-content/themes/twentytwelve/search.php b/src/wp-content/themes/twentytwelve/search.php
new file mode 100644
index 0000000000..4eea82c234
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/search.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * The template for displaying Search Results pages.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+
+ <header class="page-header">
+ <h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentytwelve' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
+ </header>
+
+ <?php twentytwelve_content_nav( 'nav-above' ); ?>
+
+ <?php /* Start the Loop */ ?>
+ <?php while ( have_posts() ) : the_post(); ?>
+ <?php get_template_part( 'content', get_post_format() ); ?>
+ <?php endwhile; ?>
+
+ <?php twentytwelve_content_nav( 'nav-below' ); ?>
+
+ <?php else : ?>
+
+ <article id="post-0" class="post no-results not-found">
+ <header class="entry-header">
+ <h1 class="entry-title"><?php _e( 'Nothing Found', 'twentytwelve' ); ?></h1>
+ </header>
+
+ <div class="entry-content">
+ <p><?php _e( 'Sorry, but nothing matched your search criteria. Please try again with some different keywords.', 'twentytwelve' ); ?></p>
+ <?php get_search_form(); ?>
+ </div><!-- .entry-content -->
+ </article><!-- #post-0 -->
+
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/sidebar-front.php b/src/wp-content/themes/twentytwelve/sidebar-front.php
new file mode 100644
index 0000000000..4dfa140372
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/sidebar-front.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * The sidebar containing the front page widget areas.
+ *
+ * If no active widgets in either sidebar, they will be hidden completely.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+/*
+ * The front page widget area is triggered if any of the areas
+ * have widgets. So let's check that first.
+ *
+ * If none of the sidebars have widgets, then let's bail early.
+ */
+if ( ! is_active_sidebar( 'sidebar-2' ) && ! is_active_sidebar( 'sidebar-3' ) )
+ return;
+
+// If we get this far, we have widgets. Let do this.
+?>
+<div id="secondary" class="widget-area" role="complementary">
+ <?php if ( is_active_sidebar( 'sidebar-2' ) ) : ?>
+ <div class="first front-widgets">
+ <?php dynamic_sidebar( 'sidebar-2' ); ?>
+ </div><!-- .first -->
+ <?php endif; ?>
+
+ <?php if ( is_active_sidebar( 'sidebar-3' ) ) : ?>
+ <div class="second front-widgets">
+ <?php dynamic_sidebar( 'sidebar-3' ); ?>
+ </div><!-- .second -->
+ <?php endif; ?>
+</div><!-- #secondary --> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/sidebar.php b/src/wp-content/themes/twentytwelve/sidebar.php
new file mode 100644
index 0000000000..2bc4969ae8
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/sidebar.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * The sidebar containing the main widget area.
+ *
+ * If no active widgets in sidebar, let's hide it completely.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+?>
+
+ <?php if ( is_active_sidebar( 'sidebar-1' ) ) : ?>
+ <div id="secondary" class="widget-area" role="complementary">
+ <?php dynamic_sidebar( 'sidebar-1' ); ?>
+ </div><!-- #secondary -->
+ <?php endif; ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/single.php b/src/wp-content/themes/twentytwelve/single.php
new file mode 100644
index 0000000000..38a813bc04
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/single.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * The Template for displaying all single posts.
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <div id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php while ( have_posts() ) : the_post(); ?>
+
+ <?php get_template_part( 'content', get_post_format() ); ?>
+
+ <nav class="nav-single">
+ <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentytwelve' ); ?></h3>
+ <span class="nav-previous"><?php previous_post_link( '%link', '<span class="meta-nav">' . _x( '&larr;', 'Previous post link', 'twentytwelve' ) . '</span> %title' ); ?></span>
+ <span class="nav-next"><?php next_post_link( '%link', '%title <span class="meta-nav">' . _x( '&rarr;', 'Next post link', 'twentytwelve' ) . '</span>' ); ?></span>
+ </nav><!-- .nav-single -->
+
+ <?php comments_template( '', true ); ?>
+
+ <?php endwhile; // end of the loop. ?>
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/style.css b/src/wp-content/themes/twentytwelve/style.css
new file mode 100644
index 0000000000..95892b71a4
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/style.css
@@ -0,0 +1,1742 @@
+/*
+Theme Name: Twenty Twelve
+Theme URI: http://wordpress.org/themes/twentytwelve
+Author: the WordPress team
+Author URI: http://wordpress.org/
+Description: The 2012 theme for WordPress is a fully responsive theme that looks great on any device. Features include a front page template with its own widgets, an optional display font, styling for post formats on both index and single views, and an optional no-sidebar page template. Make it yours with a custom menu, header image, and background.
+Version: 1.2
+License: GNU General Public License v2 or later
+License URI: http://www.gnu.org/licenses/gpl-2.0.html
+Tags: light, gray, white, one-column, two-columns, right-sidebar, flexible-width, custom-background, custom-header, custom-menu, editor-style, featured-images, flexible-header, full-width-template, microformats, post-formats, rtl-language-support, sticky-post, theme-options, translation-ready
+Text Domain: twentytwelve
+
+This theme, like WordPress, is licensed under the GPL.
+Use it to make something cool, have fun, and share what you've learned with others.
+*/
+
+/* =Notes
+--------------------------------------------------------------
+This stylesheet uses rem values with a pixel fallback. The rem
+values (and line heights) are calculated using two variables:
+
+$rembase: 14;
+$line-height: 24;
+
+---------- Examples
+
+* Use a pixel value with a rem fallback for font-size, padding, margins, etc.
+ padding: 5px 0;
+ padding: 0.357142857rem 0; (5 / $rembase)
+
+* Set a font-size and then set a line-height based on the font-size
+ font-size: 16px
+ font-size: 1.142857143rem; (16 / $rembase)
+ line-height: 1.5; ($line-height / 16)
+
+---------- Vertical spacing
+
+Vertical spacing between most elements should use 24px or 48px
+to maintain vertical rhythm:
+
+.my-new-div {
+ margin: 24px 0;
+ margin: 1.714285714rem 0; ( 24 / $rembase )
+}
+
+---------- Further reading
+
+http://snook.ca/archives/html_and_css/font-size-with-rem
+http://blog.typekit.com/2011/11/09/type-study-sizing-the-legible-letter/
+
+
+/* =Reset
+-------------------------------------------------------------- */
+
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ vertical-align: baseline;
+}
+body {
+ line-height: 1;
+}
+ol,
+ul {
+ list-style: none;
+}
+blockquote,
+q {
+ quotes: none;
+}
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+caption,
+th,
+td {
+ font-weight: normal;
+ text-align: left;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ clear: both;
+}
+html {
+ overflow-y: scroll;
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+a:focus {
+ outline: thin dotted;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+audio,
+canvas,
+video {
+ display: inline-block;
+}
+audio:not([controls]) {
+ display: none;
+}
+del {
+ color: #333;
+}
+ins {
+ background: #fff9c0;
+ text-decoration: none;
+}
+hr {
+ background-color: #ccc;
+ border: 0;
+ height: 1px;
+ margin: 24px;
+ margin-bottom: 1.714285714rem;
+}
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+small {
+ font-size: smaller;
+}
+img {
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+
+/* Clearing floats */
+.clear:after,
+.wrapper:after,
+.format-status .entry-header:after {
+ clear: both;
+}
+.clear:before,
+.clear:after,
+.wrapper:before,
+.wrapper:after,
+.format-status .entry-header:before,
+.format-status .entry-header:after {
+ display: table;
+ content: "";
+}
+
+
+/* =Repeatable patterns
+-------------------------------------------------------------- */
+
+/* Small headers */
+.archive-title,
+.page-title,
+.widget-title,
+.entry-content th,
+.comment-content th {
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ line-height: 2.181818182;
+ font-weight: bold;
+ text-transform: uppercase;
+ color: #636363;
+}
+
+/* Shared Post Format styling */
+article.format-quote footer.entry-meta,
+article.format-link footer.entry-meta,
+article.format-status footer.entry-meta {
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ line-height: 2.181818182;
+}
+
+/* Form fields, general styles first */
+button,
+input,
+textarea {
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ font-family: inherit;
+ padding: 6px;
+ padding: 0.428571429rem;
+}
+button,
+input {
+ line-height: normal;
+}
+textarea {
+ font-size: 100%;
+ overflow: auto;
+ vertical-align: top;
+}
+
+/* Reset non-text input types */
+input[type="checkbox"],
+input[type="radio"],
+input[type="file"],
+input[type="hidden"],
+input[type="image"],
+input[type="color"] {
+ border: 0;
+ border-radius: 0;
+ padding: 0;
+}
+
+/* Buttons */
+.menu-toggle,
+input[type="submit"],
+input[type="button"],
+input[type="reset"],
+article.post-password-required input[type=submit],
+.bypostauthor cite span {
+ padding: 6px 10px;
+ padding: 0.428571429rem 0.714285714rem;
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ line-height: 1.428571429;
+ font-weight: normal;
+ color: #7c7c7c;
+ background-color: #e6e6e6;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient(top, #f4f4f4, #e6e6e6);
+ background-image: -ms-linear-gradient(top, #f4f4f4, #e6e6e6);
+ background-image: -webkit-linear-gradient(top, #f4f4f4, #e6e6e6);
+ background-image: -o-linear-gradient(top, #f4f4f4, #e6e6e6);
+ background-image: linear-gradient(top, #f4f4f4, #e6e6e6);
+ border: 1px solid #d2d2d2;
+ border-radius: 3px;
+ box-shadow: 0 1px 2px rgba(64, 64, 64, 0.1);
+}
+.menu-toggle,
+button,
+input[type="submit"],
+input[type="button"],
+input[type="reset"] {
+ cursor: pointer;
+}
+button[disabled],
+input[disabled] {
+ cursor: default;
+}
+.menu-toggle:hover,
+button:hover,
+input[type="submit"]:hover,
+input[type="button"]:hover,
+input[type="reset"]:hover,
+article.post-password-required input[type=submit]:hover {
+ color: #5e5e5e;
+ background-color: #ebebeb;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient(top, #f9f9f9, #ebebeb);
+ background-image: -ms-linear-gradient(top, #f9f9f9, #ebebeb);
+ background-image: -webkit-linear-gradient(top, #f9f9f9, #ebebeb);
+ background-image: -o-linear-gradient(top, #f9f9f9, #ebebeb);
+ background-image: linear-gradient(top, #f9f9f9, #ebebeb);
+}
+.menu-toggle:active,
+.menu-toggle.toggled-on,
+button:active,
+input[type="submit"]:active,
+input[type="button"]:active,
+input[type="reset"]:active {
+ color: #757575;
+ background-color: #e1e1e1;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: -ms-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: -webkit-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: -o-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: linear-gradient(top, #ebebeb, #e1e1e1);
+ box-shadow: inset 0 0 8px 2px #c6c6c6, 0 1px 0 0 #f4f4f4;
+ border-color: transparent;
+}
+.bypostauthor cite span {
+ color: #fff;
+ background-color: #21759b;
+ background-image: none;
+ border: 1px solid #1f6f93;
+ border-radius: 2px;
+ box-shadow: none;
+ padding: 0;
+}
+
+/* Responsive images */
+.entry-content img,
+.comment-content img,
+.widget img {
+ max-width: 100%; /* Fluid images for posts, comments, and widgets */
+}
+img[class*="align"],
+img[class*="wp-image-"],
+img[class*="attachment-"] {
+ height: auto; /* Make sure images with WordPress-added height and width attributes are scaled correctly */
+}
+img.size-full,
+img.size-large,
+img.header-image,
+img.wp-post-image {
+ max-width: 100%;
+ height: auto; /* Make sure images with WordPress-added height and width attributes are scaled correctly */
+}
+
+/* Make sure videos and embeds fit their containers */
+embed,
+iframe,
+object,
+video {
+ max-width: 100%;
+}
+.entry-content .twitter-tweet-rendered {
+ max-width: 100% !important; /* Override the Twitter embed fixed width */
+}
+
+/* Images */
+.alignleft {
+ float: left;
+}
+.alignright {
+ float: right;
+}
+.aligncenter {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+.entry-content img,
+.comment-content img,
+.widget img,
+img.header-image,
+.author-avatar img,
+img.wp-post-image {
+ /* Add fancy borders to all WordPress-added images but not things like badges and icons and the like */
+ border-radius: 3px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
+}
+.wp-caption {
+ max-width: 100%; /* Keep wide captions from overflowing their container. */
+ padding: 4px;
+}
+.wp-caption .wp-caption-text,
+.gallery-caption,
+.entry-caption {
+ font-style: italic;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ color: #757575;
+}
+img.wp-smiley,
+.rsswidget img {
+ border: 0;
+ border-radius: 0;
+ box-shadow: none;
+ margin-bottom: 0;
+ margin-top: 0;
+ padding: 0;
+}
+.entry-content dl.gallery-item {
+ margin: 0;
+}
+.gallery-item a,
+.gallery-caption {
+ width: 90%;
+}
+.gallery-item a {
+ display: block;
+}
+.gallery-caption a {
+ display: inline;
+}
+.gallery-columns-1 .gallery-item a {
+ max-width: 100%;
+ width: auto;
+}
+.gallery .gallery-icon img {
+ height: auto;
+ max-width: 90%;
+ padding: 5%;
+}
+.gallery-columns-1 .gallery-icon img {
+ padding: 3%;
+}
+
+/* Navigation */
+.site-content nav {
+ clear: both;
+ line-height: 2;
+ overflow: hidden;
+}
+#nav-above {
+ padding: 24px 0;
+ padding: 1.714285714rem 0;
+}
+#nav-above {
+ display: none;
+}
+.paged #nav-above {
+ display: block;
+}
+.nav-previous,
+.previous-image {
+ float: left;
+ width: 50%;
+}
+.nav-next,
+.next-image {
+ float: right;
+ text-align: right;
+ width: 50%;
+}
+.nav-single + .comments-area,
+#comment-nav-above {
+ margin: 48px 0;
+ margin: 3.428571429rem 0;
+}
+
+/* Author profiles */
+.author .archive-header {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.author-info {
+ border-top: 1px solid #ededed;
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+ padding-top: 24px;
+ padding-top: 1.714285714rem;
+ overflow: hidden;
+}
+.author-description p {
+ color: #757575;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+}
+.author.archive .author-info {
+ border-top: 0;
+ margin: 0 0 48px;
+ margin: 0 0 3.428571429rem;
+}
+.author.archive .author-avatar {
+ margin-top: 0;
+}
+
+
+/* =Basic structure
+-------------------------------------------------------------- */
+
+/* Body, links, basics */
+html {
+ font-size: 87.5%;
+}
+body {
+ font-size: 14px;
+ font-size: 1rem;
+ font-family: Helvetica, Arial, sans-serif;
+ text-rendering: optimizeLegibility;
+ color: #444;
+}
+body.custom-font-enabled {
+ font-family: "Open Sans", Helvetica, Arial, sans-serif;
+}
+a {
+ outline: none;
+ color: #21759b;
+}
+a:hover {
+ color: #0f3647;
+}
+
+/* Assistive text */
+.assistive-text,
+.site .screen-reader-text {
+ position: absolute !important;
+ clip: rect(1px, 1px, 1px, 1px);
+}
+.main-navigation .assistive-text:focus {
+ background: #fff;
+ border: 2px solid #333;
+ border-radius: 3px;
+ clip: auto !important;
+ color: #000;
+ display: block;
+ font-size: 12px;
+ padding: 12px;
+ position: absolute;
+ top: 5px;
+ left: 5px;
+ z-index: 100000; /* Above WP toolbar */
+}
+
+/* Page structure */
+.site {
+ padding: 0 24px;
+ padding: 0 1.714285714rem;
+ background-color: #fff;
+}
+.site-content {
+ margin: 24px 0 0;
+ margin: 1.714285714rem 0 0;
+}
+.widget-area {
+ margin: 24px 0 0;
+ margin: 1.714285714rem 0 0;
+}
+
+/* Header */
+.site-header {
+ padding: 24px 0;
+ padding: 1.714285714rem 0;
+}
+.site-header h1,
+.site-header h2 {
+ text-align: center;
+}
+.site-header h1 a,
+.site-header h2 a {
+ color: #515151;
+ display: inline-block;
+ text-decoration: none;
+}
+.site-header h1 a:hover,
+.site-header h2 a:hover {
+ color: #21759b;
+}
+.site-header h1 {
+ font-size: 24px;
+ font-size: 1.714285714rem;
+ line-height: 1.285714286;
+ margin-bottom: 14px;
+ margin-bottom: 1rem;
+}
+.site-header h2 {
+ font-weight: normal;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+ color: #757575;
+}
+.header-image {
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+}
+
+/* Navigation Menu */
+.main-navigation {
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+ text-align: center;
+}
+.main-navigation li {
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 1.42857143;
+}
+.main-navigation a {
+ color: #5e5e5e;
+}
+.main-navigation a:hover {
+ color: #21759b;
+}
+.main-navigation ul.nav-menu,
+.main-navigation div.nav-menu > ul {
+ display: none;
+}
+.main-navigation ul.nav-menu.toggled-on,
+.menu-toggle {
+ display: inline-block;
+}
+
+/* Banner */
+section[role="banner"] {
+ margin-bottom: 48px;
+ margin-bottom: 3.428571429rem;
+}
+
+/* Sidebar */
+.widget-area .widget {
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ hyphens: auto;
+ margin-bottom: 48px;
+ margin-bottom: 3.428571429rem;
+ word-wrap: break-word;
+}
+.widget-area .widget h3 {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.widget-area .widget p,
+.widget-area .widget li,
+.widget-area .widget .textwidget {
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+}
+.widget-area .widget p {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.widget-area .textwidget ul {
+ list-style: disc outside;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+}
+.widget-area .textwidget li {
+ margin-left: 36px;
+ margin-left: 2.571428571rem;
+}
+.widget-area .widget a {
+ color: #757575;
+}
+.widget-area .widget a:hover {
+ color: #21759b;
+}
+.widget-area .widget a:visited {
+ color: #9f9f9f;
+}
+.widget-area #s {
+ width: 53.66666666666%; /* define a width to avoid dropping a wider submit button */
+}
+
+/* Footer */
+footer[role="contentinfo"] {
+ border-top: 1px solid #ededed;
+ clear: both;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ max-width: 960px;
+ max-width: 68.571428571rem;
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+ margin-left: auto;
+ margin-right: auto;
+ padding: 24px 0;
+ padding: 1.714285714rem 0;
+}
+footer[role="contentinfo"] a {
+ color: #686868;
+}
+footer[role="contentinfo"] a:hover {
+ color: #21759b;
+}
+
+
+/* =Main content and comment content
+-------------------------------------------------------------- */
+
+.entry-meta {
+ clear: both;
+}
+.entry-header {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.entry-header img.wp-post-image {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.entry-header .entry-title {
+ font-size: 20px;
+ font-size: 1.428571429rem;
+ line-height: 1.2;
+ font-weight: normal;
+}
+.entry-header .entry-title a {
+ text-decoration: none;
+}
+.entry-header .entry-format {
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+ font-weight: normal;
+}
+.entry-header .comments-link {
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+ color: #757575;
+}
+.comments-link a,
+.entry-meta a {
+ color: #757575;
+}
+.comments-link a:hover,
+.entry-meta a:hover {
+ color: #21759b;
+}
+article.sticky .featured-post {
+ border-top: 4px double #ededed;
+ border-bottom: 4px double #ededed;
+ color: #757575;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 3.692307692;
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+ text-align: center;
+}
+.entry-content,
+.entry-summary,
+.mu_register {
+ line-height: 1.714285714;
+}
+.entry-content h1,
+.comment-content h1,
+.entry-content h2,
+.comment-content h2,
+.entry-content h3,
+.comment-content h3,
+.entry-content h4,
+.comment-content h4,
+.entry-content h5,
+.comment-content h5,
+.entry-content h6,
+.comment-content h6 {
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+ line-height: 1.714285714;
+}
+.entry-content h1,
+.comment-content h1 {
+ font-size: 21px;
+ font-size: 1.5rem;
+ line-height: 1.5;
+}
+.entry-content h2,
+.comment-content h2,
+.mu_register h2 {
+ font-size: 18px;
+ font-size: 1.285714286rem;
+ line-height: 1.6;
+}
+.entry-content h3,
+.comment-content h3 {
+ font-size: 16px;
+ font-size: 1.142857143rem;
+ line-height: 1.846153846;
+}
+.entry-content h4,
+.comment-content h4 {
+ font-size: 14px;
+ font-size: 1rem;
+ line-height: 1.846153846;
+}
+.entry-content h5,
+.comment-content h5 {
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+}
+.entry-content h6,
+.comment-content h6 {
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 1.846153846;
+}
+.entry-content p,
+.entry-summary p,
+.comment-content p,
+.mu_register p {
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+ line-height: 1.714285714;
+}
+.entry-content a:visited,
+.comment-content a:visited {
+ color: #9f9f9f;
+}
+.entry-content ol,
+.comment-content ol,
+.entry-content ul,
+.comment-content ul,
+.mu_register ul {
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+ line-height: 1.714285714;
+}
+.entry-content ul ul,
+.comment-content ul ul,
+.entry-content ol ol,
+.comment-content ol ol,
+.entry-content ul ol,
+.comment-content ul ol,
+.entry-content ol ul,
+.comment-content ol ul {
+ margin-bottom: 0;
+}
+.entry-content ul,
+.comment-content ul,
+.mu_register ul {
+ list-style: disc outside;
+}
+.entry-content ol,
+.comment-content ol {
+ list-style: decimal outside;
+}
+.entry-content li,
+.comment-content li,
+.mu_register li {
+ margin: 0 0 0 36px;
+ margin: 0 0 0 2.571428571rem;
+}
+.entry-content blockquote,
+.comment-content blockquote {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+ padding: 24px;
+ padding: 1.714285714rem;
+ font-style: italic;
+}
+.entry-content blockquote p:last-child,
+.comment-content blockquote p:last-child {
+ margin-bottom: 0;
+}
+.entry-content code,
+.comment-content code {
+ font-family: Consolas, Monaco, Lucida Console, monospace;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+}
+.entry-content pre,
+.comment-content pre {
+ border: 1px solid #ededed;
+ color: #666;
+ font-family: Consolas, Monaco, Lucida Console, monospace;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 1.714285714;
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+ overflow: auto;
+ padding: 24px;
+ padding: 1.714285714rem;
+}
+.entry-content pre code,
+.comment-content pre code {
+ display: block;
+}
+.entry-content abbr,
+.comment-content abbr,
+.entry-content dfn,
+.comment-content dfn,
+.entry-content acronym,
+.comment-content acronym {
+ border-bottom: 1px dotted #666;
+ cursor: help;
+}
+.entry-content address,
+.comment-content address {
+ display: block;
+ line-height: 1.714285714;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+}
+img.alignleft,
+.wp-caption.alignleft {
+ margin: 12px 24px 12px 0;
+ margin: 0.857142857rem 1.714285714rem 0.857142857rem 0;
+}
+img.alignright,
+.wp-caption.alignright {
+ margin: 12px 0 12px 24px;
+ margin: 0.857142857rem 0 0.857142857rem 1.714285714rem;
+}
+img.aligncenter,
+.wp-caption.aligncenter {
+ clear: both;
+ margin-top: 12px;
+ margin-top: 0.857142857rem;
+ margin-bottom: 12px;
+ margin-bottom: 0.857142857rem;
+}
+.entry-content embed,
+.entry-content iframe,
+.entry-content object,
+.entry-content video {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.entry-content dl,
+.comment-content dl {
+ margin: 0 24px;
+ margin: 0 1.714285714rem;
+}
+.entry-content dt,
+.comment-content dt {
+ font-weight: bold;
+ line-height: 1.714285714;
+}
+.entry-content dd,
+.comment-content dd {
+ line-height: 1.714285714;
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.entry-content table,
+.comment-content table {
+ border-bottom: 1px solid #ededed;
+ color: #757575;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+ width: 100%;
+}
+.entry-content table caption,
+.comment-content table caption {
+ font-size: 16px;
+ font-size: 1.142857143rem;
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+}
+.entry-content td,
+.comment-content td {
+ border-top: 1px solid #ededed;
+ padding: 6px 10px 6px 0;
+}
+.site-content article {
+ border-bottom: 4px double #ededed;
+ margin-bottom: 72px;
+ margin-bottom: 5.142857143rem;
+ padding-bottom: 24px;
+ padding-bottom: 1.714285714rem;
+ word-wrap: break-word;
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ hyphens: auto;
+}
+.page-links {
+ clear: both;
+ line-height: 1.714285714;
+}
+footer.entry-meta {
+ margin-top: 24px;
+ margin-top: 1.714285714rem;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+ color: #757575;
+}
+.single-author .entry-meta .by-author {
+ display: none;
+}
+.mu_register h2 {
+ color: #757575;
+ font-weight: normal;
+}
+
+
+/* =Archives
+-------------------------------------------------------------- */
+
+.archive-header,
+.page-header {
+ margin-bottom: 48px;
+ margin-bottom: 3.428571429rem;
+ padding-bottom: 22px;
+ padding-bottom: 1.571428571rem;
+ border-bottom: 1px solid #ededed;
+}
+.archive-meta {
+ color: #757575;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ margin-top: 22px;
+ margin-top: 1.571428571rem;
+}
+
+
+/* =Single image attachment view
+-------------------------------------------------------------- */
+
+.article.attachment {
+ overflow: hidden;
+}
+.image-attachment div.attachment {
+ text-align: center;
+}
+.image-attachment div.attachment p {
+ text-align: center;
+}
+.image-attachment div.attachment img {
+ display: block;
+ height: auto;
+ margin: 0 auto;
+ max-width: 100%;
+}
+.image-attachment .entry-caption {
+ margin-top: 8px;
+ margin-top: 0.571428571rem;
+}
+
+
+/* =Aside post format
+-------------------------------------------------------------- */
+
+article.format-aside h1 {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+article.format-aside h1 a {
+ text-decoration: none;
+ color: #4d525a;
+}
+article.format-aside h1 a:hover {
+ color: #2e3542;
+}
+article.format-aside .aside {
+ padding: 24px 24px 0;
+ padding: 1.714285714rem;
+ background: #d2e0f9;
+ border-left: 22px solid #a8bfe8;
+}
+article.format-aside p {
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+ color: #4a5466;
+}
+article.format-aside blockquote:last-child,
+article.format-aside p:last-child {
+ margin-bottom: 0;
+}
+
+
+/* =Post formats
+-------------------------------------------------------------- */
+
+/* Image posts */
+article.format-image footer h1 {
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+ font-weight: normal;
+}
+article.format-image footer h2 {
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ line-height: 2.181818182;
+}
+article.format-image footer a h2 {
+ font-weight: normal;
+}
+
+/* Link posts */
+article.format-link header {
+ padding: 0 10px;
+ padding: 0 0.714285714rem;
+ float: right;
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ line-height: 2.181818182;
+ font-weight: bold;
+ font-style: italic;
+ text-transform: uppercase;
+ color: #848484;
+ background-color: #ebebeb;
+ border-radius: 3px;
+}
+article.format-link .entry-content {
+ max-width: 80%;
+ float: left;
+}
+article.format-link .entry-content a {
+ font-size: 22px;
+ font-size: 1.571428571rem;
+ line-height: 1.090909091;
+ text-decoration: none;
+}
+
+/* Quote posts */
+article.format-quote .entry-content p {
+ margin: 0;
+ padding-bottom: 24px;
+ padding-bottom: 1.714285714rem;
+}
+article.format-quote .entry-content blockquote {
+ display: block;
+ padding: 24px 24px 0;
+ padding: 1.714285714rem 1.714285714rem 0;
+ font-size: 15px;
+ font-size: 1.071428571rem;
+ line-height: 1.6;
+ font-style: normal;
+ color: #6a6a6a;
+ background: #efefef;
+}
+
+/* Status posts */
+.format-status .entry-header {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+.format-status .entry-header header {
+ display: inline-block;
+}
+.format-status .entry-header h1 {
+ font-size: 15px;
+ font-size: 1.071428571rem;
+ font-weight: normal;
+ line-height: 1.6;
+ margin: 0;
+}
+.format-status .entry-header h2 {
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ font-weight: normal;
+ line-height: 2;
+ margin: 0;
+}
+.format-status .entry-header header a {
+ color: #757575;
+}
+.format-status .entry-header header a:hover {
+ color: #21759b;
+}
+.format-status .entry-header img {
+ float: left;
+ margin-right: 21px;
+ margin-right: 1.5rem;
+}
+
+
+/* =Comments
+-------------------------------------------------------------- */
+
+.comments-title {
+ margin-bottom: 48px;
+ margin-bottom: 3.428571429rem;
+ font-size: 16px;
+ font-size: 1.142857143rem;
+ line-height: 1.5;
+ font-weight: normal;
+}
+.comments-area article {
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+}
+.comments-area article header {
+ margin: 0 0 48px;
+ margin: 0 0 3.428571429rem;
+ overflow: hidden;
+ position: relative;
+}
+.comments-area article header img {
+ float: left;
+ padding: 0;
+ line-height: 0;
+}
+.comments-area article header cite,
+.comments-area article header time {
+ display: block;
+ margin-left: 85px;
+ margin-left: 6.071428571rem;
+}
+.comments-area article header cite {
+ font-style: normal;
+ font-size: 15px;
+ font-size: 1.071428571rem;
+ line-height: 1.42857143;
+}
+.comments-area cite b {
+ font-weight: normal;
+}
+.comments-area article header time {
+ line-height: 1.714285714;
+ text-decoration: none;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ color: #5e5e5e;
+}
+.comments-area article header a {
+ text-decoration: none;
+ color: #5e5e5e;
+}
+.comments-area article header a:hover {
+ color: #21759b;
+}
+.comments-area article header cite a {
+ color: #444;
+}
+.comments-area article header cite a:hover {
+ text-decoration: underline;
+}
+.comments-area article header h4 {
+ position: absolute;
+ top: 0;
+ right: 0;
+ padding: 6px 12px;
+ padding: 0.428571429rem 0.857142857rem;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ font-weight: normal;
+ color: #fff;
+ background-color: #0088d0;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient(top, #009cee, #0088d0);
+ background-image: -ms-linear-gradient(top, #009cee, #0088d0);
+ background-image: -webkit-linear-gradient(top, #009cee, #0088d0);
+ background-image: -o-linear-gradient(top, #009cee, #0088d0);
+ background-image: linear-gradient(top, #009cee, #0088d0);
+ border-radius: 3px;
+ border: 1px solid #007cbd;
+}
+.comments-area .bypostauthor cite span {
+ position: absolute;
+ margin-left: 5px;
+ margin-left: 0.357142857rem;
+ padding: 2px 5px;
+ padding: 0.142857143rem 0.357142857rem;
+ font-size: 10px;
+ font-size: 0.714285714rem;
+}
+.comments-area .bypostauthor cite b {
+ font-weight: bold;
+}
+a.comment-reply-link,
+a.comment-edit-link {
+ color: #686868;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+}
+a.comment-reply-link:hover,
+a.comment-edit-link:hover {
+ color: #21759b;
+}
+.commentlist .pingback {
+ line-height: 1.714285714;
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+
+/* Comment form */
+#respond {
+ margin-top: 48px;
+ margin-top: 3.428571429rem;
+}
+#respond h3#reply-title {
+ font-size: 16px;
+ font-size: 1.142857143rem;
+ line-height: 1.5;
+}
+#respond h3#reply-title #cancel-comment-reply-link {
+ margin-left: 10px;
+ margin-left: 0.714285714rem;
+ font-weight: normal;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+}
+#respond form {
+ margin: 24px 0;
+ margin: 1.714285714rem 0;
+}
+#respond form p {
+ margin: 11px 0;
+ margin: 0.785714286rem 0;
+}
+#respond form p.logged-in-as {
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+}
+#respond form label {
+ display: block;
+ line-height: 1.714285714;
+}
+#respond form input[type="text"],
+#respond form textarea {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 1.714285714;
+ padding: 10px;
+ padding: 0.714285714rem;
+ width: 100%;
+}
+#respond form p.form-allowed-tags {
+ margin: 0;
+ font-size: 12px;
+ font-size: 0.857142857rem;
+ line-height: 2;
+ color: #5e5e5e;
+}
+.required {
+ color: red;
+}
+
+
+/* =Front page template
+-------------------------------------------------------------- */
+
+.entry-page-image {
+ margin-bottom: 14px;
+ margin-bottom: 1rem;
+}
+.template-front-page .site-content article {
+ border: 0;
+ margin-bottom: 0;
+}
+.template-front-page .widget-area {
+ clear: both;
+ float: none;
+ width: auto;
+ padding-top: 24px;
+ padding-top: 1.714285714rem;
+ border-top: 1px solid #ededed;
+}
+.template-front-page .widget-area .widget li {
+ margin: 8px 0 0;
+ margin: 0.571428571rem 0 0;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.714285714;
+ list-style-type: square;
+ list-style-position: inside;
+}
+.template-front-page .widget-area .widget li a {
+ color: #757575;
+}
+.template-front-page .widget-area .widget li a:hover {
+ color: #21759b;
+}
+.template-front-page .widget-area .widget_text img {
+ float: left;
+ margin: 8px 24px 8px 0;
+ margin: 0.571428571rem 1.714285714rem 0.571428571rem 0;
+}
+
+
+/* =Widgets
+-------------------------------------------------------------- */
+
+.widget-area .widget ul ul {
+ margin-left: 12px;
+ margin-left: 0.857142857rem;
+}
+.widget_rss li {
+ margin: 12px 0;
+ margin: 0.857142857rem 0;
+}
+.widget_recent_entries .post-date,
+.widget_rss .rss-date {
+ color: #aaa;
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ margin-left: 12px;
+ margin-left: 0.857142857rem;
+}
+#wp-calendar {
+ margin: 0;
+ width: 100%;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+ color: #686868;
+}
+#wp-calendar th,
+#wp-calendar td,
+#wp-calendar caption {
+ text-align: left;
+}
+#wp-calendar #next {
+ padding-right: 24px;
+ padding-right: 1.714285714rem;
+ text-align: right;
+}
+.widget_search label {
+ display: block;
+ font-size: 13px;
+ font-size: 0.928571429rem;
+ line-height: 1.846153846;
+}
+.widget_twitter li {
+ list-style-type: none;
+}
+.widget_twitter .timesince {
+ display: block;
+ text-align: right;
+}
+
+
+/* =Plugins
+----------------------------------------------- */
+
+img#wpstats {
+ display: block;
+ margin: 0 auto 24px;
+ margin: 0 auto 1.714285714rem;
+}
+
+
+/* =Media queries
+-------------------------------------------------------------- */
+
+/* Minimum width of 600 pixels. */
+@media screen and (min-width: 600px) {
+ .author-avatar {
+ float: left;
+ margin-top: 8px;
+ margin-top: 0.571428571rem;
+ }
+ .author-description {
+ float: right;
+ width: 80%;
+ }
+ .site {
+ margin: 0 auto;
+ max-width: 960px;
+ max-width: 68.571428571rem;
+ overflow: hidden;
+ }
+ .site-content {
+ float: left;
+ width: 65.104166667%;
+ }
+ body.template-front-page .site-content,
+ body.single-attachment .site-content,
+ body.full-width .site-content {
+ width: 100%;
+ }
+ .widget-area {
+ float: right;
+ width: 26.041666667%;
+ }
+ .site-header h1,
+ .site-header h2 {
+ text-align: left;
+ }
+ .site-header h1 {
+ font-size: 26px;
+ font-size: 1.857142857rem;
+ line-height: 1.846153846;
+ margin-bottom: 0;
+ }
+ .main-navigation ul.nav-menu,
+ .main-navigation div.nav-menu > ul {
+ border-bottom: 1px solid #ededed;
+ border-top: 1px solid #ededed;
+ display: inline-block !important;
+ text-align: left;
+ width: 100%;
+ }
+ .main-navigation ul {
+ margin: 0;
+ text-indent: 0;
+ }
+ .main-navigation li a,
+ .main-navigation li {
+ display: inline-block;
+ text-decoration: none;
+ }
+ .main-navigation li a {
+ border-bottom: 0;
+ color: #6a6a6a;
+ line-height: 3.692307692;
+ text-transform: uppercase;
+ white-space: nowrap;
+ }
+ .main-navigation li a:hover {
+ color: #000;
+ }
+ .main-navigation li {
+ margin: 0 40px 0 0;
+ margin: 0 2.857142857rem 0 0;
+ position: relative;
+ }
+ .main-navigation li ul {
+ display: none;
+ margin: 0;
+ padding: 0;
+ position: absolute;
+ top: 100%;
+ z-index: 1;
+ }
+ .main-navigation li ul ul {
+ top: 0;
+ left: 100%;
+ }
+ .main-navigation ul li:hover > ul {
+ border-left: 0;
+ display: block;
+ }
+ .main-navigation li ul li a {
+ background: #efefef;
+ border-bottom: 1px solid #ededed;
+ display: block;
+ font-size: 11px;
+ font-size: 0.785714286rem;
+ line-height: 2.181818182;
+ padding: 8px 10px;
+ padding: 0.571428571rem 0.714285714rem;
+ width: 180px;
+ width: 12.85714286rem;
+ white-space: normal;
+ }
+ .main-navigation li ul li a:hover {
+ background: #e3e3e3;
+ color: #444;
+ }
+ .main-navigation .current-menu-item > a,
+ .main-navigation .current-menu-ancestor > a,
+ .main-navigation .current_page_item > a,
+ .main-navigation .current_page_ancestor > a {
+ color: #636363;
+ font-weight: bold;
+ }
+ .menu-toggle {
+ display: none;
+ }
+ .entry-header .entry-title {
+ font-size: 22px;
+ font-size: 1.571428571rem;
+ }
+ #respond form input[type="text"] {
+ width: 46.333333333%;
+ }
+ #respond form textarea.blog-textarea {
+ width: 79.666666667%;
+ }
+ .template-front-page .site-content,
+ .template-front-page article {
+ overflow: hidden;
+ }
+ .template-front-page.has-post-thumbnail article {
+ float: left;
+ width: 47.916666667%;
+ }
+ .entry-page-image {
+ float: right;
+ margin-bottom: 0;
+ width: 47.916666667%;
+ }
+ .template-front-page .widget-area .widget,
+ .template-front-page.two-sidebars .widget-area .front-widgets {
+ float: left;
+ width: 51.875%;
+ margin-bottom: 24px;
+ margin-bottom: 1.714285714rem;
+ }
+ .template-front-page .widget-area .widget:nth-child(odd) {
+ clear: right;
+ }
+ .template-front-page .widget-area .widget:nth-child(even),
+ .template-front-page.two-sidebars .widget-area .front-widgets + .front-widgets {
+ float: right;
+ width: 39.0625%;
+ margin: 0 0 24px;
+ margin: 0 0 1.714285714rem;
+ }
+ .template-front-page.two-sidebars .widget,
+ .template-front-page.two-sidebars .widget:nth-child(even) {
+ float: none;
+ width: auto;
+ }
+ .commentlist .children {
+ margin-left: 48px;
+ margin-left: 3.428571429rem;
+ }
+}
+
+/* Minimum width of 960 pixels. */
+@media screen and (min-width: 960px) {
+ body {
+ background-color: #e6e6e6;
+ }
+ body .site {
+ padding: 0 40px;
+ padding: 0 2.857142857rem;
+ margin-top: 48px;
+ margin-top: 3.428571429rem;
+ margin-bottom: 48px;
+ margin-bottom: 3.428571429rem;
+ box-shadow: 0 2px 6px rgba(100, 100, 100, 0.3);
+ }
+ body.custom-background-empty {
+ background-color: #fff;
+ }
+ body.custom-background-empty .site,
+ body.custom-background-white .site {
+ padding: 0;
+ margin-top: 0;
+ margin-bottom: 0;
+ box-shadow: none;
+ }
+}
+
+
+/* =Print
+----------------------------------------------- */
+
+@media print {
+ body {
+ background: none !important;
+ color: #000;
+ font-size: 10pt;
+ }
+ footer a[rel=bookmark]:link:after,
+ footer a[rel=bookmark]:visited:after {
+ content: " [" attr(href) "] "; /* Show URLs */
+ }
+ a {
+ text-decoration: none;
+ }
+ .entry-content img,
+ .comment-content img,
+ .author-avatar img,
+ img.wp-post-image {
+ border-radius: 0;
+ box-shadow: none;
+ }
+ .site {
+ clear: both !important;
+ display: block !important;
+ float: none !important;
+ max-width: 100%;
+ position: relative !important;
+ }
+ .site-header {
+ margin-bottom: 72px;
+ margin-bottom: 5.142857143rem;
+ text-align: left;
+ }
+ .site-header h1 {
+ font-size: 21pt;
+ line-height: 1;
+ text-align: left;
+ }
+ .site-header h2 {
+ color: #000;
+ font-size: 10pt;
+ text-align: left;
+ }
+ .site-header h1 a,
+ .site-header h2 a {
+ color: #000;
+ }
+ .author-avatar,
+ #colophon,
+ #respond,
+ .commentlist .comment-edit-link,
+ .commentlist .reply,
+ .entry-header .comments-link,
+ .entry-meta .edit-link a,
+ .page-link,
+ .site-content nav,
+ .widget-area,
+ img.header-image,
+ .main-navigation {
+ display: none;
+ }
+ .wrapper {
+ border-top: none;
+ box-shadow: none;
+ }
+ .site-content {
+ margin: 0;
+ width: auto;
+ }
+ .singular .entry-header .entry-meta {
+ position: static;
+ }
+ .singular .site-content,
+ .singular .entry-header,
+ .singular .entry-content,
+ .singular footer.entry-meta,
+ .singular .comments-title {
+ margin: 0;
+ width: 100%;
+ }
+ .entry-header .entry-title,
+ .entry-title,
+ .singular .entry-title {
+ font-size: 21pt;
+ }
+ footer.entry-meta,
+ footer.entry-meta a {
+ color: #444;
+ font-size: 10pt;
+ }
+ .author-description {
+ float: none;
+ width: auto;
+ }
+
+ /* Comments */
+ .commentlist > li.comment {
+ background: none;
+ position: relative;
+ width: auto;
+ }
+ .commentlist .avatar {
+ height: 39px;
+ left: 2.2em;
+ top: 2.2em;
+ width: 39px;
+ }
+ .comments-area article header cite,
+ .comments-area article header time {
+ margin-left: 50px;
+ margin-left: 3.57142857rem;
+ }
+} \ No newline at end of file
diff --git a/src/wp-content/themes/twentytwelve/tag.php b/src/wp-content/themes/twentytwelve/tag.php
new file mode 100644
index 0000000000..9bf77e0a7e
--- /dev/null
+++ b/src/wp-content/themes/twentytwelve/tag.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * The template for displaying Tag pages.
+ *
+ * Used to display archive-type pages for posts in a tag.
+ *
+ * Learn more: http://codex.wordpress.org/Template_Hierarchy
+ *
+ * @package WordPress
+ * @subpackage Twenty_Twelve
+ * @since Twenty Twelve 1.0
+ */
+
+get_header(); ?>
+
+ <section id="primary" class="site-content">
+ <div id="content" role="main">
+
+ <?php if ( have_posts() ) : ?>
+ <header class="archive-header">
+ <h1 class="archive-title"><?php printf( __( 'Tag Archives: %s', 'twentytwelve' ), '<span>' . single_tag_title( '', false ) . '</span>' ); ?></h1>
+
+ <?php if ( tag_description() ) : // Show an optional tag description ?>
+ <div class="archive-meta"><?php echo tag_description(); ?></div>
+ <?php endif; ?>
+ </header><!-- .archive-header -->
+
+ <?php
+ /* Start the Loop */
+ while ( have_posts() ) : the_post();
+
+ /* Include the post format-specific template for the content. If you want to
+ * this in a child theme then include a file called called content-___.php
+ * (where ___ is the post format) and that will be used instead.
+ */
+ get_template_part( 'content', get_post_format() );
+
+ endwhile;
+
+ twentytwelve_content_nav( 'nav-below' );
+ ?>
+
+ <?php else : ?>
+ <?php get_template_part( 'content', 'none' ); ?>
+ <?php endif; ?>
+
+ </div><!-- #content -->
+ </section><!-- #primary -->
+
+<?php get_sidebar(); ?>
+<?php get_footer(); ?> \ No newline at end of file
diff --git a/src/wp-cron.php b/src/wp-cron.php
new file mode 100644
index 0000000000..04953c8d73
--- /dev/null
+++ b/src/wp-cron.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * WordPress Cron Implementation for hosts, which do not offer CRON or for which
+ * the user has not set up a CRON job pointing to this file.
+ *
+ * The HTTP request to this file will not slow down the visitor who happens to
+ * visit when the cron job is needed to run.
+ *
+ * @package WordPress
+ */
+
+ignore_user_abort(true);
+
+if ( !empty($_POST) || defined('DOING_AJAX') || defined('DOING_CRON') )
+ die();
+
+/**
+ * Tell WordPress we are doing the CRON task.
+ *
+ * @var bool
+ */
+define('DOING_CRON', true);
+
+if ( !defined('ABSPATH') ) {
+ /** Set up WordPress environment */
+ require_once('./wp-load.php');
+}
+
+// Uncached doing_cron transient fetch
+function _get_cron_lock() {
+ global $_wp_using_ext_object_cache, $wpdb;
+
+ $value = 0;
+ if ( $_wp_using_ext_object_cache ) {
+ // Skip local cache and force refetch of doing_cron transient in case
+ // another processs updated the cache
+ $value = wp_cache_get( 'doing_cron', 'transient', true );
+ } else {
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", '_transient_doing_cron' ) );
+ if ( is_object( $row ) )
+ $value = $row->option_value;
+ }
+
+ return $value;
+}
+
+if ( false === $crons = _get_cron_array() )
+ die();
+
+$keys = array_keys( $crons );
+$gmt_time = microtime( true );
+
+if ( isset($keys[0]) && $keys[0] > $gmt_time )
+ die();
+
+$doing_cron_transient = get_transient( 'doing_cron');
+
+// Use global $doing_wp_cron lock otherwise use the GET lock. If no lock, trying grabbing a new lock.
+if ( empty( $doing_wp_cron ) ) {
+ if ( empty( $_GET[ 'doing_wp_cron' ] ) ) {
+ // Called from external script/job. Try setting a lock.
+ if ( $doing_cron_transient && ( $doing_cron_transient + WP_CRON_LOCK_TIMEOUT > $gmt_time ) )
+ return;
+ $doing_cron_transient = $doing_wp_cron = sprintf( '%.22F', microtime( true ) );
+ set_transient( 'doing_cron', $doing_wp_cron );
+ } else {
+ $doing_wp_cron = $_GET[ 'doing_wp_cron' ];
+ }
+}
+
+// Check lock
+if ( $doing_cron_transient != $doing_wp_cron )
+ return;
+
+foreach ( $crons as $timestamp => $cronhooks ) {
+ if ( $timestamp > $gmt_time )
+ break;
+
+ foreach ( $cronhooks as $hook => $keys ) {
+
+ foreach ( $keys as $k => $v ) {
+
+ $schedule = $v['schedule'];
+
+ if ( $schedule != false ) {
+ $new_args = array($timestamp, $schedule, $hook, $v['args']);
+ call_user_func_array('wp_reschedule_event', $new_args);
+ }
+
+ wp_unschedule_event( $timestamp, $hook, $v['args'] );
+
+ do_action_ref_array( $hook, $v['args'] );
+
+ // If the hook ran too long and another cron process stole the lock, quit.
+ if ( _get_cron_lock() != $doing_wp_cron )
+ return;
+ }
+ }
+}
+
+if ( _get_cron_lock() == $doing_wp_cron )
+ delete_transient( 'doing_cron' );
+
+die();
diff --git a/src/wp-includes/ID3/getid3.lib.php b/src/wp-includes/ID3/getid3.lib.php
new file mode 100644
index 0000000000..f8df233486
--- /dev/null
+++ b/src/wp-includes/ID3/getid3.lib.php
@@ -0,0 +1,1341 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// getid3.lib.php - part of getID3() //
+// See readme.txt for more details //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_lib
+{
+
+ public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
+ $returnstring = '';
+ for ($i = 0; $i < strlen($string); $i++) {
+ if ($hex) {
+ $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
+ } else {
+ $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤');
+ }
+ if ($spaces) {
+ $returnstring .= ' ';
+ }
+ }
+ if (!empty($htmlencoding)) {
+ if ($htmlencoding === true) {
+ $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean
+ }
+ $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
+ }
+ return $returnstring;
+ }
+
+ public static function trunc($floatnumber) {
+ // truncates a floating-point number at the decimal point
+ // returns int (if possible, otherwise float)
+ if ($floatnumber >= 1) {
+ $truncatednumber = floor($floatnumber);
+ } elseif ($floatnumber <= -1) {
+ $truncatednumber = ceil($floatnumber);
+ } else {
+ $truncatednumber = 0;
+ }
+ if (self::intValueSupported($truncatednumber)) {
+ $truncatednumber = (int) $truncatednumber;
+ }
+ return $truncatednumber;
+ }
+
+
+ public static function safe_inc(&$variable, $increment=1) {
+ if (isset($variable)) {
+ $variable += $increment;
+ } else {
+ $variable = $increment;
+ }
+ return true;
+ }
+
+ public static function CastAsInt($floatnum) {
+ // convert to float if not already
+ $floatnum = (float) $floatnum;
+
+ // convert a float to type int, only if possible
+ if (self::trunc($floatnum) == $floatnum) {
+ // it's not floating point
+ if (self::intValueSupported($floatnum)) {
+ // it's within int range
+ $floatnum = (int) $floatnum;
+ }
+ }
+ return $floatnum;
+ }
+
+ public static function intValueSupported($num) {
+ // check if integers are 64-bit
+ static $hasINT64 = null;
+ if ($hasINT64 === null) { // 10x faster than is_null()
+ $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
+ if (!$hasINT64 && !defined('PHP_INT_MIN')) {
+ define('PHP_INT_MIN', ~PHP_INT_MAX);
+ }
+ }
+ // if integers are 64-bit - no other check required
+ if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
+ return true;
+ }
+ return false;
+ }
+
+ public static function DecimalizeFraction($fraction) {
+ list($numerator, $denominator) = explode('/', $fraction);
+ return $numerator / ($denominator ? $denominator : 1);
+ }
+
+
+ public static function DecimalBinary2Float($binarynumerator) {
+ $numerator = self::Bin2Dec($binarynumerator);
+ $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
+ return ($numerator / $denominator);
+ }
+
+
+ public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
+ if (strpos($binarypointnumber, '.') === false) {
+ $binarypointnumber = '0.'.$binarypointnumber;
+ } elseif ($binarypointnumber{0} == '.') {
+ $binarypointnumber = '0'.$binarypointnumber;
+ }
+ $exponent = 0;
+ while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
+ if (substr($binarypointnumber, 1, 1) == '.') {
+ $exponent--;
+ $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
+ } else {
+ $pointpos = strpos($binarypointnumber, '.');
+ $exponent += ($pointpos - 1);
+ $binarypointnumber = str_replace('.', '', $binarypointnumber);
+ $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
+ }
+ }
+ $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
+ return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
+ }
+
+
+ public static function Float2BinaryDecimal($floatvalue) {
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
+ $maxbits = 128; // to how many bits of precision should the calculations be taken?
+ $intpart = self::trunc($floatvalue);
+ $floatpart = abs($floatvalue - $intpart);
+ $pointbitstring = '';
+ while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
+ $floatpart *= 2;
+ $pointbitstring .= (string) self::trunc($floatpart);
+ $floatpart -= self::trunc($floatpart);
+ }
+ $binarypointnumber = decbin($intpart).'.'.$pointbitstring;
+ return $binarypointnumber;
+ }
+
+
+ public static function Float2String($floatvalue, $bits) {
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
+ switch ($bits) {
+ case 32:
+ $exponentbits = 8;
+ $fractionbits = 23;
+ break;
+
+ case 64:
+ $exponentbits = 11;
+ $fractionbits = 52;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ if ($floatvalue >= 0) {
+ $signbit = '0';
+ } else {
+ $signbit = '1';
+ }
+ $normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits);
+ $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
+ $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
+ $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
+
+ return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
+ }
+
+
+ public static function LittleEndian2Float($byteword) {
+ return self::BigEndian2Float(strrev($byteword));
+ }
+
+
+ public static function BigEndian2Float($byteword) {
+ // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
+ // http://www.psc.edu/general/software/packages/ieee/ieee.html
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
+
+ $bitword = self::BigEndian2Bin($byteword);
+ if (!$bitword) {
+ return 0;
+ }
+ $signbit = $bitword{0};
+
+ switch (strlen($byteword) * 8) {
+ case 32:
+ $exponentbits = 8;
+ $fractionbits = 23;
+ break;
+
+ case 64:
+ $exponentbits = 11;
+ $fractionbits = 52;
+ break;
+
+ case 80:
+ // 80-bit Apple SANE format
+ // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
+ $exponentstring = substr($bitword, 1, 15);
+ $isnormalized = intval($bitword{16});
+ $fractionstring = substr($bitword, 17, 63);
+ $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
+ $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
+ $floatvalue = $exponent * $fraction;
+ if ($signbit == '1') {
+ $floatvalue *= -1;
+ }
+ return $floatvalue;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ $exponentstring = substr($bitword, 1, $exponentbits);
+ $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
+ $exponent = self::Bin2Dec($exponentstring);
+ $fraction = self::Bin2Dec($fractionstring);
+
+ if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
+ // Not a Number
+ $floatvalue = false;
+ } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
+ if ($signbit == '1') {
+ $floatvalue = '-infinity';
+ } else {
+ $floatvalue = '+infinity';
+ }
+ } elseif (($exponent == 0) && ($fraction == 0)) {
+ if ($signbit == '1') {
+ $floatvalue = -0;
+ } else {
+ $floatvalue = 0;
+ }
+ $floatvalue = ($signbit ? 0 : -0);
+ } elseif (($exponent == 0) && ($fraction != 0)) {
+ // These are 'unnormalized' values
+ $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring);
+ if ($signbit == '1') {
+ $floatvalue *= -1;
+ }
+ } elseif ($exponent != 0) {
+ $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring));
+ if ($signbit == '1') {
+ $floatvalue *= -1;
+ }
+ }
+ return (float) $floatvalue;
+ }
+
+
+ public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
+ $intvalue = 0;
+ $bytewordlen = strlen($byteword);
+ if ($bytewordlen == 0) {
+ return false;
+ }
+ for ($i = 0; $i < $bytewordlen; $i++) {
+ if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
+ //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
+ $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
+ } else {
+ $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
+ }
+ }
+ if ($signed && !$synchsafe) {
+ // synchsafe ints are not allowed to be signed
+ if ($bytewordlen <= PHP_INT_SIZE) {
+ $signMaskBit = 0x80 << (8 * ($bytewordlen - 1));
+ if ($intvalue & $signMaskBit) {
+ $intvalue = 0 - ($intvalue & ($signMaskBit - 1));
+ }
+ } else {
+ throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()');
+ break;
+ }
+ }
+ return self::CastAsInt($intvalue);
+ }
+
+
+ public static function LittleEndian2Int($byteword, $signed=false) {
+ return self::BigEndian2Int(strrev($byteword), false, $signed);
+ }
+
+
+ public static function BigEndian2Bin($byteword) {
+ $binvalue = '';
+ $bytewordlen = strlen($byteword);
+ for ($i = 0; $i < $bytewordlen; $i++) {
+ $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
+ }
+ return $binvalue;
+ }
+
+
+ public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
+ if ($number < 0) {
+ throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
+ }
+ $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
+ $intstring = '';
+ if ($signed) {
+ if ($minbytes > PHP_INT_SIZE) {
+ throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()');
+ }
+ $number = $number & (0x80 << (8 * ($minbytes - 1)));
+ }
+ while ($number != 0) {
+ $quotient = ($number / ($maskbyte + 1));
+ $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring;
+ $number = floor($quotient);
+ }
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
+ }
+
+
+ public static function Dec2Bin($number) {
+ while ($number >= 256) {
+ $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
+ $number = floor($number / 256);
+ }
+ $bytes[] = $number;
+ $binstring = '';
+ for ($i = 0; $i < count($bytes); $i++) {
+ $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
+ }
+ return $binstring;
+ }
+
+
+ public static function Bin2Dec($binstring, $signed=false) {
+ $signmult = 1;
+ if ($signed) {
+ if ($binstring{0} == '1') {
+ $signmult = -1;
+ }
+ $binstring = substr($binstring, 1);
+ }
+ $decvalue = 0;
+ for ($i = 0; $i < strlen($binstring); $i++) {
+ $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
+ }
+ return self::CastAsInt($decvalue * $signmult);
+ }
+
+
+ public static function Bin2String($binstring) {
+ // return 'hi' for input of '0110100001101001'
+ $string = '';
+ $binstringreversed = strrev($binstring);
+ for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
+ $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
+ }
+ return $string;
+ }
+
+
+ public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
+ $intstring = '';
+ while ($number > 0) {
+ if ($synchsafe) {
+ $intstring = $intstring.chr($number & 127);
+ $number >>= 7;
+ } else {
+ $intstring = $intstring.chr($number & 255);
+ $number >>= 8;
+ }
+ }
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
+ }
+
+
+ public static function array_merge_clobber($array1, $array2) {
+ // written by kcØhireability*com
+ // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
+ if (!is_array($array1) || !is_array($array2)) {
+ return false;
+ }
+ $newarray = $array1;
+ foreach ($array2 as $key => $val) {
+ if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
+ $newarray[$key] = self::array_merge_clobber($newarray[$key], $val);
+ } else {
+ $newarray[$key] = $val;
+ }
+ }
+ return $newarray;
+ }
+
+
+ public static function array_merge_noclobber($array1, $array2) {
+ if (!is_array($array1) || !is_array($array2)) {
+ return false;
+ }
+ $newarray = $array1;
+ foreach ($array2 as $key => $val) {
+ if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
+ $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val);
+ } elseif (!isset($newarray[$key])) {
+ $newarray[$key] = $val;
+ }
+ }
+ return $newarray;
+ }
+
+
+ public static function ksort_recursive(&$theArray) {
+ ksort($theArray);
+ foreach ($theArray as $key => $value) {
+ if (is_array($value)) {
+ self::ksort_recursive($theArray[$key]);
+ }
+ }
+ return true;
+ }
+
+ public static function fileextension($filename, $numextensions=1) {
+ if (strstr($filename, '.')) {
+ $reversedfilename = strrev($filename);
+ $offset = 0;
+ for ($i = 0; $i < $numextensions; $i++) {
+ $offset = strpos($reversedfilename, '.', $offset + 1);
+ if ($offset === false) {
+ return '';
+ }
+ }
+ return strrev(substr($reversedfilename, 0, $offset));
+ }
+ return '';
+ }
+
+
+ public static function PlaytimeString($seconds) {
+ $sign = (($seconds < 0) ? '-' : '');
+ $seconds = round(abs($seconds));
+ $H = (int) floor( $seconds / 3600);
+ $M = (int) floor(($seconds - (3600 * $H) ) / 60);
+ $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
+ return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
+ }
+
+
+ public static function DateMac2Unix($macdate) {
+ // Macintosh timestamp: seconds since 00:00h January 1, 1904
+ // UNIX timestamp: seconds since 00:00h January 1, 1970
+ return self::CastAsInt($macdate - 2082844800);
+ }
+
+
+ public static function FixedPoint8_8($rawdata) {
+ return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
+ }
+
+
+ public static function FixedPoint16_16($rawdata) {
+ return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
+ }
+
+
+ public static function FixedPoint2_30($rawdata) {
+ $binarystring = self::BigEndian2Bin($rawdata);
+ return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
+ }
+
+
+ public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
+ // assigns $Value to a nested array path:
+ // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
+ // is the same as:
+ // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
+ // or
+ // $foo['path']['to']['my'] = 'file.txt';
+ $ArrayPath = ltrim($ArrayPath, $Separator);
+ if (($pos = strpos($ArrayPath, $Separator)) !== false) {
+ $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
+ } else {
+ $ReturnedArray[$ArrayPath] = $Value;
+ }
+ return $ReturnedArray;
+ }
+
+ public static function array_max($arraydata, $returnkey=false) {
+ $maxvalue = false;
+ $maxkey = false;
+ foreach ($arraydata as $key => $value) {
+ if (!is_array($value)) {
+ if ($value > $maxvalue) {
+ $maxvalue = $value;
+ $maxkey = $key;
+ }
+ }
+ }
+ return ($returnkey ? $maxkey : $maxvalue);
+ }
+
+ public static function array_min($arraydata, $returnkey=false) {
+ $minvalue = false;
+ $minkey = false;
+ foreach ($arraydata as $key => $value) {
+ if (!is_array($value)) {
+ if ($value > $minvalue) {
+ $minvalue = $value;
+ $minkey = $key;
+ }
+ }
+ }
+ return ($returnkey ? $minkey : $minvalue);
+ }
+
+ public static function XML2array($XMLstring) {
+ if (function_exists('simplexml_load_string')) {
+ if (function_exists('get_object_vars')) {
+ $XMLobject = simplexml_load_string($XMLstring);
+ return self::SimpleXMLelement2array($XMLobject);
+ }
+ }
+ return false;
+ }
+
+ public static function SimpleXMLelement2array($XMLobject) {
+ if (!is_object($XMLobject) && !is_array($XMLobject)) {
+ return $XMLobject;
+ }
+ $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
+ foreach ($XMLarray as $key => $value) {
+ $XMLarray[$key] = self::SimpleXMLelement2array($value);
+ }
+ return $XMLarray;
+ }
+
+
+ // Allan Hansen <ahØartemis*dk>
+ // self::md5_data() - returns md5sum for a file from startuing position to absolute end position
+ public static function hash_data($file, $offset, $end, $algorithm) {
+ static $tempdir = '';
+ if (!self::intValueSupported($end)) {
+ return false;
+ }
+ switch ($algorithm) {
+ case 'md5':
+ $hash_function = 'md5_file';
+ $unix_call = 'md5sum';
+ $windows_call = 'md5sum.exe';
+ $hash_length = 32;
+ break;
+
+ case 'sha1':
+ $hash_function = 'sha1_file';
+ $unix_call = 'sha1sum';
+ $windows_call = 'sha1sum.exe';
+ $hash_length = 40;
+ break;
+
+ default:
+ throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
+ break;
+ }
+ $size = $end - $offset;
+ while (true) {
+ if (GETID3_OS_ISWINDOWS) {
+
+ // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
+ // Fall back to create-temp-file method:
+ if ($algorithm == 'sha1') {
+ break;
+ }
+
+ $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
+ foreach ($RequiredFiles as $required_file) {
+ if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
+ // helper apps not available - fall back to old method
+ break 2;
+ }
+ }
+ $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
+ $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
+ $commandline .= GETID3_HELPERAPPSDIR.$windows_call;
+
+ } else {
+
+ $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
+ $commandline .= 'tail -c'.$size.' | ';
+ $commandline .= $unix_call;
+
+ }
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
+ //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
+ break;
+ }
+ return substr(`$commandline`, 0, $hash_length);
+ }
+
+ if (empty($tempdir)) {
+ // yes this is ugly, feel free to suggest a better way
+ require_once(dirname(__FILE__).'/getid3.php');
+ $getid3_temp = new getID3();
+ $tempdir = $getid3_temp->tempdir;
+ unset($getid3_temp);
+ }
+ // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
+ if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
+ // can't find anywhere to create a temp file, just fail
+ return false;
+ }
+
+ // Init
+ $result = false;
+
+ // copy parts of file
+ try {
+ self::CopyFileParts($file, $data_filename, $offset, $end - $offset);
+ $result = $hash_function($data_filename);
+ } catch (Exception $e) {
+ throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
+ }
+ unlink($data_filename);
+ return $result;
+ }
+
+ public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
+ if (!self::intValueSupported($offset + $length)) {
+ throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
+ }
+ if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
+ if (($fp_dest = fopen($filename_dest, 'wb'))) {
+ if (fseek($fp_src, $offset, SEEK_SET) == 0) {
+ $byteslefttowrite = $length;
+ while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
+ $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
+ $byteslefttowrite -= $byteswritten;
+ }
+ return true;
+ } else {
+ throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
+ }
+ fclose($fp_dest);
+ } else {
+ throw new Exception('failed to create file for writing '.$filename_dest);
+ }
+ fclose($fp_src);
+ } else {
+ throw new Exception('failed to open file for reading '.$filename_source);
+ }
+ return false;
+ }
+
+ public static function iconv_fallback_int_utf8($charval) {
+ if ($charval < 128) {
+ // 0bbbbbbb
+ $newcharstring = chr($charval);
+ } elseif ($charval < 2048) {
+ // 110bbbbb 10bbbbbb
+ $newcharstring = chr(($charval >> 6) | 0xC0);
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
+ } elseif ($charval < 65536) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $newcharstring = chr(($charval >> 12) | 0xE0);
+ $newcharstring .= chr(($charval >> 6) | 0xC0);
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
+ } else {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $newcharstring = chr(($charval >> 18) | 0xF0);
+ $newcharstring .= chr(($charval >> 12) | 0xC0);
+ $newcharstring .= chr(($charval >> 6) | 0xC0);
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-8
+ public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
+ if (function_exists('utf8_encode')) {
+ return utf8_encode($string);
+ }
+ // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xEF\xBB\xBF";
+ }
+ for ($i = 0; $i < strlen($string); $i++) {
+ $charval = ord($string{$i});
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-16BE
+ public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFE\xFF";
+ }
+ for ($i = 0; $i < strlen($string); $i++) {
+ $newcharstring .= "\x00".$string{$i};
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-16LE
+ public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFF\xFE";
+ }
+ for ($i = 0; $i < strlen($string); $i++) {
+ $newcharstring .= $string{$i}."\x00";
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-16LE (BOM)
+ public static function iconv_fallback_iso88591_utf16($string) {
+ return self::iconv_fallback_iso88591_utf16le($string, true);
+ }
+
+ // UTF-8 => ISO-8859-1
+ public static function iconv_fallback_utf8_iso88591($string) {
+ if (function_exists('utf8_decode')) {
+ return utf8_decode($string);
+ }
+ // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
+ $newcharstring = '';
+ $offset = 0;
+ $stringlength = strlen($string);
+ while ($offset < $stringlength) {
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
+ (ord($string{($offset + 3)}) & 0x3F);
+ $offset += 4;
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
+ (ord($string{($offset + 2)}) & 0x3F);
+ $offset += 3;
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ // 110bbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
+ (ord($string{($offset + 1)}) & 0x3F);
+ $offset += 2;
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ // 0bbbbbbb
+ $charval = ord($string{$offset});
+ $offset += 1;
+ } else {
+ // error? throw some kind of warning here?
+ $charval = false;
+ $offset += 1;
+ }
+ if ($charval !== false) {
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
+ }
+ }
+ return $newcharstring;
+ }
+
+ // UTF-8 => UTF-16BE
+ public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFE\xFF";
+ }
+ $offset = 0;
+ $stringlength = strlen($string);
+ while ($offset < $stringlength) {
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
+ (ord($string{($offset + 3)}) & 0x3F);
+ $offset += 4;
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
+ (ord($string{($offset + 2)}) & 0x3F);
+ $offset += 3;
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ // 110bbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
+ (ord($string{($offset + 1)}) & 0x3F);
+ $offset += 2;
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ // 0bbbbbbb
+ $charval = ord($string{$offset});
+ $offset += 1;
+ } else {
+ // error? throw some kind of warning here?
+ $charval = false;
+ $offset += 1;
+ }
+ if ($charval !== false) {
+ $newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?');
+ }
+ }
+ return $newcharstring;
+ }
+
+ // UTF-8 => UTF-16LE
+ public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFF\xFE";
+ }
+ $offset = 0;
+ $stringlength = strlen($string);
+ while ($offset < $stringlength) {
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
+ (ord($string{($offset + 3)}) & 0x3F);
+ $offset += 4;
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
+ (ord($string{($offset + 2)}) & 0x3F);
+ $offset += 3;
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ // 110bbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
+ (ord($string{($offset + 1)}) & 0x3F);
+ $offset += 2;
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ // 0bbbbbbb
+ $charval = ord($string{$offset});
+ $offset += 1;
+ } else {
+ // error? maybe throw some warning here?
+ $charval = false;
+ $offset += 1;
+ }
+ if ($charval !== false) {
+ $newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00");
+ }
+ }
+ return $newcharstring;
+ }
+
+ // UTF-8 => UTF-16LE (BOM)
+ public static function iconv_fallback_utf8_utf16($string) {
+ return self::iconv_fallback_utf8_utf16le($string, true);
+ }
+
+ // UTF-16BE => UTF-8
+ public static function iconv_fallback_utf16be_utf8($string) {
+ if (substr($string, 0, 2) == "\xFE\xFF") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::BigEndian2Int(substr($string, $i, 2));
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16LE => UTF-8
+ public static function iconv_fallback_utf16le_utf8($string) {
+ if (substr($string, 0, 2) == "\xFF\xFE") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::LittleEndian2Int(substr($string, $i, 2));
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16BE => ISO-8859-1
+ public static function iconv_fallback_utf16be_iso88591($string) {
+ if (substr($string, 0, 2) == "\xFE\xFF") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::BigEndian2Int(substr($string, $i, 2));
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16LE => ISO-8859-1
+ public static function iconv_fallback_utf16le_iso88591($string) {
+ if (substr($string, 0, 2) == "\xFF\xFE") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::LittleEndian2Int(substr($string, $i, 2));
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16 (BOM) => ISO-8859-1
+ public static function iconv_fallback_utf16_iso88591($string) {
+ $bom = substr($string, 0, 2);
+ if ($bom == "\xFE\xFF") {
+ return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
+ } elseif ($bom == "\xFF\xFE") {
+ return self::iconv_fallback_utf16le_iso88591(substr($string, 2));
+ }
+ return $string;
+ }
+
+ // UTF-16 (BOM) => UTF-8
+ public static function iconv_fallback_utf16_utf8($string) {
+ $bom = substr($string, 0, 2);
+ if ($bom == "\xFE\xFF") {
+ return self::iconv_fallback_utf16be_utf8(substr($string, 2));
+ } elseif ($bom == "\xFF\xFE") {
+ return self::iconv_fallback_utf16le_utf8(substr($string, 2));
+ }
+ return $string;
+ }
+
+ public static function iconv_fallback($in_charset, $out_charset, $string) {
+
+ if ($in_charset == $out_charset) {
+ return $string;
+ }
+
+ // iconv() availble
+ if (function_exists('iconv')) {
+ if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
+ switch ($out_charset) {
+ case 'ISO-8859-1':
+ $converted_string = rtrim($converted_string, "\x00");
+ break;
+ }
+ return $converted_string;
+ }
+
+ // iconv() may sometimes fail with "illegal character in input string" error message
+ // and return an empty string, but returning the unconverted string is more useful
+ return $string;
+ }
+
+
+ // iconv() not available
+ static $ConversionFunctionList = array();
+ if (empty($ConversionFunctionList)) {
+ $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8';
+ $ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16';
+ $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be';
+ $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le';
+ $ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591';
+ $ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16';
+ $ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be';
+ $ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le';
+ $ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591';
+ $ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8';
+ $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591';
+ $ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8';
+ $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591';
+ $ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8';
+ }
+ if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) {
+ $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
+ return self::$ConversionFunction($string);
+ }
+ throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
+ }
+
+
+ public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
+ $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
+ $HTMLstring = '';
+
+ switch ($charset) {
+ case '1251':
+ case '1252':
+ case '866':
+ case '932':
+ case '936':
+ case '950':
+ case 'BIG5':
+ case 'BIG5-HKSCS':
+ case 'cp1251':
+ case 'cp1252':
+ case 'cp866':
+ case 'EUC-JP':
+ case 'EUCJP':
+ case 'GB2312':
+ case 'ibm866':
+ case 'ISO-8859-1':
+ case 'ISO-8859-15':
+ case 'ISO8859-1':
+ case 'ISO8859-15':
+ case 'KOI8-R':
+ case 'koi8-ru':
+ case 'koi8r':
+ case 'Shift_JIS':
+ case 'SJIS':
+ case 'win-1251':
+ case 'Windows-1251':
+ case 'Windows-1252':
+ $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
+ break;
+
+ case 'UTF-8':
+ $strlen = strlen($string);
+ for ($i = 0; $i < $strlen; $i++) {
+ $char_ord_val = ord($string{$i});
+ $charval = 0;
+ if ($char_ord_val < 0x80) {
+ $charval = $char_ord_val;
+ } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) {
+ $charval = (($char_ord_val & 0x07) << 18);
+ $charval += ((ord($string{++$i}) & 0x3F) << 12);
+ $charval += ((ord($string{++$i}) & 0x3F) << 6);
+ $charval += (ord($string{++$i}) & 0x3F);
+ } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) {
+ $charval = (($char_ord_val & 0x0F) << 12);
+ $charval += ((ord($string{++$i}) & 0x3F) << 6);
+ $charval += (ord($string{++$i}) & 0x3F);
+ } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) {
+ $charval = (($char_ord_val & 0x1F) << 6);
+ $charval += (ord($string{++$i}) & 0x3F);
+ }
+ if (($charval >= 32) && ($charval <= 127)) {
+ $HTMLstring .= htmlentities(chr($charval));
+ } else {
+ $HTMLstring .= '&#'.$charval.';';
+ }
+ }
+ break;
+
+ case 'UTF-16LE':
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::LittleEndian2Int(substr($string, $i, 2));
+ if (($charval >= 32) && ($charval <= 127)) {
+ $HTMLstring .= chr($charval);
+ } else {
+ $HTMLstring .= '&#'.$charval.';';
+ }
+ }
+ break;
+
+ case 'UTF-16BE':
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::BigEndian2Int(substr($string, $i, 2));
+ if (($charval >= 32) && ($charval <= 127)) {
+ $HTMLstring .= chr($charval);
+ } else {
+ $HTMLstring .= '&#'.$charval.';';
+ }
+ }
+ break;
+
+ default:
+ $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()';
+ break;
+ }
+ return $HTMLstring;
+ }
+
+
+
+ public static function RGADnameLookup($namecode) {
+ static $RGADname = array();
+ if (empty($RGADname)) {
+ $RGADname[0] = 'not set';
+ $RGADname[1] = 'Track Gain Adjustment';
+ $RGADname[2] = 'Album Gain Adjustment';
+ }
+
+ return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
+ }
+
+
+ public static function RGADoriginatorLookup($originatorcode) {
+ static $RGADoriginator = array();
+ if (empty($RGADoriginator)) {
+ $RGADoriginator[0] = 'unspecified';
+ $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
+ $RGADoriginator[2] = 'set by user';
+ $RGADoriginator[3] = 'determined automatically';
+ }
+
+ return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
+ }
+
+
+ public static function RGADadjustmentLookup($rawadjustment, $signbit) {
+ $adjustment = $rawadjustment / 10;
+ if ($signbit == 1) {
+ $adjustment *= -1;
+ }
+ return (float) $adjustment;
+ }
+
+
+ public static function RGADgainString($namecode, $originatorcode, $replaygain) {
+ if ($replaygain < 0) {
+ $signbit = '1';
+ } else {
+ $signbit = '0';
+ }
+ $storedreplaygain = intval(round($replaygain * 10));
+ $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT);
+ $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT);
+ $gainstring .= $signbit;
+ $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT);
+
+ return $gainstring;
+ }
+
+ public static function RGADamplitude2dB($amplitude) {
+ return 20 * log10($amplitude);
+ }
+
+
+ public static function GetDataImageSize($imgData, &$imageinfo=array()) {
+ static $tempdir = '';
+ if (empty($tempdir)) {
+ // yes this is ugly, feel free to suggest a better way
+ require_once(dirname(__FILE__).'/getid3.php');
+ $getid3_temp = new getID3();
+ $tempdir = $getid3_temp->tempdir;
+ unset($getid3_temp);
+ }
+ $GetDataImageSize = false;
+ if ($tempfilename = tempnam($tempdir, 'gI3')) {
+ if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
+ fwrite($tmp, $imgData);
+ fclose($tmp);
+ $GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
+ }
+ unlink($tempfilename);
+ }
+ return $GetDataImageSize;
+ }
+
+ public static function ImageExtFromMime($mime_type) {
+ // temporary way, works OK for now, but should be reworked in the future
+ return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
+ }
+
+ public static function ImageTypesLookup($imagetypeid) {
+ static $ImageTypesLookup = array();
+ if (empty($ImageTypesLookup)) {
+ $ImageTypesLookup[1] = 'gif';
+ $ImageTypesLookup[2] = 'jpeg';
+ $ImageTypesLookup[3] = 'png';
+ $ImageTypesLookup[4] = 'swf';
+ $ImageTypesLookup[5] = 'psd';
+ $ImageTypesLookup[6] = 'bmp';
+ $ImageTypesLookup[7] = 'tiff (little-endian)';
+ $ImageTypesLookup[8] = 'tiff (big-endian)';
+ $ImageTypesLookup[9] = 'jpc';
+ $ImageTypesLookup[10] = 'jp2';
+ $ImageTypesLookup[11] = 'jpx';
+ $ImageTypesLookup[12] = 'jb2';
+ $ImageTypesLookup[13] = 'swc';
+ $ImageTypesLookup[14] = 'iff';
+ }
+ return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : '');
+ }
+
+ public static function CopyTagsToComments(&$ThisFileInfo) {
+
+ // Copy all entries from ['tags'] into common ['comments']
+ if (!empty($ThisFileInfo['tags'])) {
+ foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
+ foreach ($tagarray as $tagname => $tagdata) {
+ foreach ($tagdata as $key => $value) {
+ if (!empty($value)) {
+ if (empty($ThisFileInfo['comments'][$tagname])) {
+
+ // fall through and append value
+
+ } elseif ($tagtype == 'id3v1') {
+
+ $newvaluelength = strlen(trim($value));
+ foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
+ $oldvaluelength = strlen(trim($existingvalue));
+ if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) {
+ // new value is identical but shorter-than (or equal-length to) one already in comments - skip
+ break 2;
+ }
+ }
+
+ } elseif (!is_array($value)) {
+
+ $newvaluelength = strlen(trim($value));
+ foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
+ $oldvaluelength = strlen(trim($existingvalue));
+ if (($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
+ $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
+ break 2;
+ }
+ }
+
+ }
+ if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
+ $value = (is_string($value) ? trim($value) : $value);
+ $ThisFileInfo['comments'][$tagname][] = $value;
+ }
+ }
+ }
+ }
+ }
+
+ // Copy to ['comments_html']
+ foreach ($ThisFileInfo['comments'] as $field => $values) {
+ if ($field == 'picture') {
+ // pictures can take up a lot of space, and we don't need multiple copies of them
+ // let there be a single copy in [comments][picture], and not elsewhere
+ continue;
+ }
+ foreach ($values as $index => $value) {
+ if (is_array($value)) {
+ $ThisFileInfo['comments_html'][$field][$index] = $value;
+ } else {
+ $ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+
+ public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
+
+ // Cached
+ static $cache;
+ if (isset($cache[$file][$name])) {
+ return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
+ }
+
+ // Init
+ $keylength = strlen($key);
+ $line_count = $end - $begin - 7;
+
+ // Open php file
+ $fp = fopen($file, 'r');
+
+ // Discard $begin lines
+ for ($i = 0; $i < ($begin + 3); $i++) {
+ fgets($fp, 1024);
+ }
+
+ // Loop thru line
+ while (0 < $line_count--) {
+
+ // Read line
+ $line = ltrim(fgets($fp, 1024), "\t ");
+
+ // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key
+ //$keycheck = substr($line, 0, $keylength);
+ //if ($key == $keycheck) {
+ // $cache[$file][$name][$keycheck] = substr($line, $keylength + 1);
+ // break;
+ //}
+
+ // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key
+ //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1));
+ $explodedLine = explode("\t", $line, 2);
+ $ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : '');
+ $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : '');
+ $cache[$file][$name][$ThisKey] = trim($ThisValue);
+ }
+
+ // Close and return
+ fclose($fp);
+ return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
+ }
+
+ public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
+ global $GETID3_ERRORARRAY;
+
+ if (file_exists($filename)) {
+ if (include_once($filename)) {
+ return true;
+ } else {
+ $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors';
+ }
+ } else {
+ $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing';
+ }
+ if ($DieOnFailure) {
+ throw new Exception($diemessage);
+ } else {
+ $GETID3_ERRORARRAY[] = $diemessage;
+ }
+ return false;
+ }
+
+ public static function trimNullByte($string) {
+ return trim($string, "\x00");
+ }
+
+ public static function getFileSizeSyscall($path) {
+ $filesize = false;
+
+ if (GETID3_OS_ISWINDOWS) {
+ if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini:
+ $filesystem = new COM('Scripting.FileSystemObject');
+ $file = $filesystem->GetFile($path);
+ $filesize = $file->Size();
+ unset($filesystem, $file);
+ } else {
+ $commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI';
+ }
+ } else {
+ $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\'';
+ }
+ if (isset($commandline)) {
+ $output = trim(`$commandline`);
+ if (ctype_digit($output)) {
+ $filesize = (float) $output;
+ }
+ }
+ return $filesize;
+ }
+} \ No newline at end of file
diff --git a/src/wp-includes/ID3/getid3.php b/src/wp-includes/ID3/getid3.php
new file mode 100644
index 0000000000..84b9cce6ef
--- /dev/null
+++ b/src/wp-includes/ID3/getid3.php
@@ -0,0 +1,1776 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// Please see readme.txt for more information //
+// ///
+/////////////////////////////////////////////////////////////////
+
+// define a constant rather than looking up every time it is needed
+if (!defined('GETID3_OS_ISWINDOWS')) {
+ define('GETID3_OS_ISWINDOWS', (stripos(PHP_OS, 'WIN') === 0));
+}
+// Get base path of getID3() - ONCE
+if (!defined('GETID3_INCLUDEPATH')) {
+ define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
+}
+
+// attempt to define temp dir as something flexible but reliable
+$temp_dir = ini_get('upload_tmp_dir');
+if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
+ $temp_dir = '';
+}
+if (!$temp_dir && function_exists('sys_get_temp_dir')) {
+ // PHP v5.2.1+
+ // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
+ $temp_dir = sys_get_temp_dir();
+}
+$temp_dir = realpath($temp_dir);
+$open_basedir = ini_get('open_basedir');
+if ($open_basedir) {
+ // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/"
+ $temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir);
+ $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir);
+ if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) {
+ $temp_dir .= DIRECTORY_SEPARATOR;
+ }
+ $found_valid_tempdir = false;
+ $open_basedirs = explode(PATH_SEPARATOR, $open_basedir);
+ foreach ($open_basedirs as $basedir) {
+ if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
+ $basedir .= DIRECTORY_SEPARATOR;
+ }
+ if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
+ $found_valid_tempdir = true;
+ break;
+ }
+ }
+ if (!$found_valid_tempdir) {
+ $temp_dir = '';
+ }
+ unset($open_basedirs, $found_valid_tempdir, $basedir);
+}
+if (!$temp_dir) {
+ $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir
+}
+// $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system
+define('GETID3_TEMP_DIR', $temp_dir);
+unset($open_basedir, $temp_dir);
+
+// End: Defines
+
+
+class getID3
+{
+ // public: Settings
+ public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
+ public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
+
+ // public: Optional tag checks - disable for speed.
+ public $option_tag_id3v1 = true; // Read and process ID3v1 tags
+ public $option_tag_id3v2 = true; // Read and process ID3v2 tags
+ public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
+ public $option_tag_apetag = true; // Read and process APE tags
+ public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
+ public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
+
+ // public: Optional tag/comment calucations
+ public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
+
+ // public: Optional handling of embedded attachments (e.g. images)
+ public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
+
+ // public: Optional calculations
+ public $option_md5_data = false; // Get MD5 sum of data part - slow
+ public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
+ public $option_sha1_data = false; // Get SHA1 sum of data part - slow
+ public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
+
+ // public: Read buffer size in bytes
+ public $option_fread_buffer_size = 32768;
+
+ // Public variables
+ public $filename; // Filename of file being analysed.
+ public $fp; // Filepointer to file being analysed.
+ public $info; // Result array.
+ public $tempdir = GETID3_TEMP_DIR;
+
+ // Protected variables
+ protected $startup_error = '';
+ protected $startup_warning = '';
+ protected $memory_limit = 0;
+
+ const VERSION = '1.9.7-20130705';
+ const FREAD_BUFFER_SIZE = 32768;
+
+ const ATTACHMENTS_NONE = false;
+ const ATTACHMENTS_INLINE = true;
+
+ // public: constructor
+ public function __construct() {
+
+ // Check for PHP version
+ $required_php_version = '5.0.5';
+ if (version_compare(PHP_VERSION, $required_php_version, '<')) {
+ $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION;
+ return false;
+ }
+
+ // Check memory
+ $this->memory_limit = ini_get('memory_limit');
+ if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
+ // could be stored as "16M" rather than 16777216 for example
+ $this->memory_limit = $matches[1] * 1048576;
+ } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
+ // could be stored as "2G" rather than 2147483648 for example
+ $this->memory_limit = $matches[1] * 1073741824;
+ }
+ if ($this->memory_limit <= 0) {
+ // memory limits probably disabled
+ } elseif ($this->memory_limit <= 4194304) {
+ $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
+ } elseif ($this->memory_limit <= 12582912) {
+ $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
+ }
+
+ // Check safe_mode off
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
+ $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
+ }
+
+ if (intval(ini_get('mbstring.func_overload')) > 0) {
+ $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
+ }
+
+ // Check for magic_quotes_runtime
+ if (function_exists('get_magic_quotes_runtime')) {
+ if (get_magic_quotes_runtime()) {
+ return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
+ }
+ }
+
+ // Check for magic_quotes_gpc
+ if (function_exists('magic_quotes_gpc')) {
+ if (get_magic_quotes_gpc()) {
+ return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
+ }
+ }
+
+ // Load support library
+ if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
+ $this->startup_error .= 'getid3.lib.php is missing or corrupt';
+ }
+
+ if ($this->option_max_2gb_check === null) {
+ $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
+ }
+
+
+ // Needed for Windows only:
+ // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
+ // as well as other helper functions such as head, tail, md5sum, etc
+ // This path cannot contain spaces, but the below code will attempt to get the
+ // 8.3-equivalent path automatically
+ // IMPORTANT: This path must include the trailing slash
+ if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
+
+ $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
+
+ if (!is_dir($helperappsdir)) {
+ $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
+ } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
+ $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
+ $path_so_far = array();
+ foreach ($DirPieces as $key => $value) {
+ if (strpos($value, ' ') !== false) {
+ if (!empty($path_so_far)) {
+ $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
+ $dir_listing = `$commandline`;
+ $lines = explode("\n", $dir_listing);
+ foreach ($lines as $line) {
+ $line = trim($line);
+ if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
+ list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
+ if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
+ $value = $shortname;
+ }
+ }
+ }
+ } else {
+ $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
+ }
+ }
+ $path_so_far[] = $value;
+ }
+ $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
+ }
+ define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
+ }
+
+ return true;
+ }
+
+ public function version() {
+ return self::VERSION;
+ }
+
+ public function fread_buffer_size() {
+ return $this->option_fread_buffer_size;
+ }
+
+
+ // public: setOption
+ public function setOption($optArray) {
+ if (!is_array($optArray) || empty($optArray)) {
+ return false;
+ }
+ foreach ($optArray as $opt => $val) {
+ if (isset($this->$opt) === false) {
+ continue;
+ }
+ $this->$opt = $val;
+ }
+ return true;
+ }
+
+
+ public function openfile($filename) {
+ try {
+ if (!empty($this->startup_error)) {
+ throw new getid3_exception($this->startup_error);
+ }
+ if (!empty($this->startup_warning)) {
+ $this->warning($this->startup_warning);
+ }
+
+ // init result array and set parameters
+ $this->filename = $filename;
+ $this->info = array();
+ $this->info['GETID3_VERSION'] = $this->version();
+ $this->info['php_memory_limit'] = $this->memory_limit;
+
+ // remote files not supported
+ if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
+ throw new getid3_exception('Remote files are not supported - please copy the file locally first');
+ }
+
+ $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
+ $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
+
+ // open local file
+ if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
+ // great
+ } else {
+ throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)');
+ }
+
+ $this->info['filesize'] = filesize($filename);
+ // set redundant parameters - might be needed in some include file
+ $this->info['filename'] = basename($filename);
+ $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
+ $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
+
+
+ // option_max_2gb_check
+ if ($this->option_max_2gb_check) {
+ // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
+ // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
+ // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
+ $fseek = fseek($this->fp, 0, SEEK_END);
+ if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
+ ($this->info['filesize'] < 0) ||
+ (ftell($this->fp) < 0)) {
+ $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']);
+
+ if ($real_filesize === false) {
+ unset($this->info['filesize']);
+ fclose($this->fp);
+ throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
+ } elseif (getid3_lib::intValueSupported($real_filesize)) {
+ unset($this->info['filesize']);
+ fclose($this->fp);
+ throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
+ }
+ $this->info['filesize'] = $real_filesize;
+ $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
+ }
+ }
+
+ // set more parameters
+ $this->info['avdataoffset'] = 0;
+ $this->info['avdataend'] = $this->info['filesize'];
+ $this->info['fileformat'] = ''; // filled in later
+ $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used
+ $this->info['video']['dataformat'] = ''; // filled in later, unset if not used
+ $this->info['tags'] = array(); // filled in later, unset if not used
+ $this->info['error'] = array(); // filled in later, unset if not used
+ $this->info['warning'] = array(); // filled in later, unset if not used
+ $this->info['comments'] = array(); // filled in later, unset if not used
+ $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired
+
+ return true;
+
+ } catch (Exception $e) {
+ $this->error($e->getMessage());
+ }
+ return false;
+ }
+
+ // public: analyze file
+ public function analyze($filename) {
+ try {
+ if (!$this->openfile($filename)) {
+ return $this->info;
+ }
+
+ // Handle tags
+ foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
+ $option_tag = 'option_tag_'.$tag_name;
+ if ($this->$option_tag) {
+ $this->include_module('tag.'.$tag_name);
+ try {
+ $tag_class = 'getid3_'.$tag_name;
+ $tag = new $tag_class($this);
+ $tag->Analyze();
+ }
+ catch (getid3_exception $e) {
+ throw $e;
+ }
+ }
+ }
+ if (isset($this->info['id3v2']['tag_offset_start'])) {
+ $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']);
+ }
+ foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
+ if (isset($this->info[$tag_key]['tag_offset_start'])) {
+ $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']);
+ }
+ }
+
+ // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
+ if (!$this->option_tag_id3v2) {
+ fseek($this->fp, 0, SEEK_SET);
+ $header = fread($this->fp, 10);
+ if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
+ $this->info['id3v2']['header'] = true;
+ $this->info['id3v2']['majorversion'] = ord($header{3});
+ $this->info['id3v2']['minorversion'] = ord($header{4});
+ $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
+ }
+ }
+
+ // read 32 kb file data
+ fseek($this->fp, $this->info['avdataoffset'], SEEK_SET);
+ $formattest = fread($this->fp, 32774);
+
+ // determine format
+ $determined_format = $this->GetFileFormat($formattest, $filename);
+
+ // unable to determine file format
+ if (!$determined_format) {
+ fclose($this->fp);
+ return $this->error('unable to determine file format');
+ }
+
+ // check for illegal ID3 tags
+ if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
+ if ($determined_format['fail_id3'] === 'ERROR') {
+ fclose($this->fp);
+ return $this->error('ID3 tags not allowed on this file type.');
+ } elseif ($determined_format['fail_id3'] === 'WARNING') {
+ $this->warning('ID3 tags not allowed on this file type.');
+ }
+ }
+
+ // check for illegal APE tags
+ if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
+ if ($determined_format['fail_ape'] === 'ERROR') {
+ fclose($this->fp);
+ return $this->error('APE tags not allowed on this file type.');
+ } elseif ($determined_format['fail_ape'] === 'WARNING') {
+ $this->warning('APE tags not allowed on this file type.');
+ }
+ }
+
+ // set mime type
+ $this->info['mime_type'] = $determined_format['mime_type'];
+
+ // supported format signature pattern detected, but module deleted
+ if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
+ fclose($this->fp);
+ return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
+ }
+
+ // module requires iconv support
+ // Check encoding/iconv support
+ if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
+ $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
+ if (GETID3_OS_ISWINDOWS) {
+ $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
+ } else {
+ $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
+ }
+ return $this->error($errormessage);
+ }
+
+ // include module
+ include_once(GETID3_INCLUDEPATH.$determined_format['include']);
+
+ // instantiate module class
+ $class_name = 'getid3_'.$determined_format['module'];
+ if (!class_exists($class_name)) {
+ return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
+ }
+ $class = new $class_name($this);
+ $class->Analyze();
+ unset($class);
+
+ // close file
+ fclose($this->fp);
+
+ // process all tags - copy to 'tags' and convert charsets
+ if ($this->option_tags_process) {
+ $this->HandleAllTags();
+ }
+
+ // perform more calculations
+ if ($this->option_extra_info) {
+ $this->ChannelsBitratePlaytimeCalculations();
+ $this->CalculateCompressionRatioVideo();
+ $this->CalculateCompressionRatioAudio();
+ $this->CalculateReplayGain();
+ $this->ProcessAudioStreams();
+ }
+
+ // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
+ if ($this->option_md5_data) {
+ // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
+ if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
+ $this->getHashdata('md5');
+ }
+ }
+
+ // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
+ if ($this->option_sha1_data) {
+ $this->getHashdata('sha1');
+ }
+
+ // remove undesired keys
+ $this->CleanUp();
+
+ } catch (Exception $e) {
+ $this->error('Caught exception: '.$e->getMessage());
+ }
+
+ // return info array
+ return $this->info;
+ }
+
+
+ // private: error handling
+ public function error($message) {
+ $this->CleanUp();
+ if (!isset($this->info['error'])) {
+ $this->info['error'] = array();
+ }
+ $this->info['error'][] = $message;
+ return $this->info;
+ }
+
+
+ // private: warning handling
+ public function warning($message) {
+ $this->info['warning'][] = $message;
+ return true;
+ }
+
+
+ // private: CleanUp
+ private function CleanUp() {
+
+ // remove possible empty keys
+ $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
+ foreach ($AVpossibleEmptyKeys as $dummy => $key) {
+ if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
+ unset($this->info['audio'][$key]);
+ }
+ if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) {
+ unset($this->info['video'][$key]);
+ }
+ }
+
+ // remove empty root keys
+ if (!empty($this->info)) {
+ foreach ($this->info as $key => $value) {
+ if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) {
+ unset($this->info[$key]);
+ }
+ }
+ }
+
+ // remove meaningless entries from unknown-format files
+ if (empty($this->info['fileformat'])) {
+ if (isset($this->info['avdataoffset'])) {
+ unset($this->info['avdataoffset']);
+ }
+ if (isset($this->info['avdataend'])) {
+ unset($this->info['avdataend']);
+ }
+ }
+
+ // remove possible duplicated identical entries
+ if (!empty($this->info['error'])) {
+ $this->info['error'] = array_values(array_unique($this->info['error']));
+ }
+ if (!empty($this->info['warning'])) {
+ $this->info['warning'] = array_values(array_unique($this->info['warning']));
+ }
+
+ // remove "global variable" type keys
+ unset($this->info['php_memory_limit']);
+
+ return true;
+ }
+
+
+ // return array containing information about all supported formats
+ public function GetFileFormatArray() {
+ static $format_info = array();
+ if (empty($format_info)) {
+ $format_info = array(
+
+ // Audio formats
+
+ // AC-3 - audio - Dolby AC-3 / Dolby Digital
+ 'ac3' => array(
+ 'pattern' => '^\x0B\x77',
+ 'group' => 'audio',
+ 'module' => 'ac3',
+ 'mime_type' => 'audio/ac3',
+ ),
+
+ // AAC - audio - Advanced Audio Coding (AAC) - ADIF format
+ 'adif' => array(
+ 'pattern' => '^ADIF',
+ 'group' => 'audio',
+ 'module' => 'aac',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_ape' => 'WARNING',
+ ),
+
+/*
+ // AA - audio - Audible Audiobook
+ 'aa' => array(
+ 'pattern' => '^.{4}\x57\x90\x75\x36',
+ 'group' => 'audio',
+ 'module' => 'aa',
+ 'mime_type' => 'audio/audible',
+ ),
+*/
+ // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
+ 'adts' => array(
+ 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]',
+ 'group' => 'audio',
+ 'module' => 'aac',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_ape' => 'WARNING',
+ ),
+
+
+ // AU - audio - NeXT/Sun AUdio (AU)
+ 'au' => array(
+ 'pattern' => '^\.snd',
+ 'group' => 'audio',
+ 'module' => 'au',
+ 'mime_type' => 'audio/basic',
+ ),
+
+ // AVR - audio - Audio Visual Research
+ 'avr' => array(
+ 'pattern' => '^2BIT',
+ 'group' => 'audio',
+ 'module' => 'avr',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // BONK - audio - Bonk v0.9+
+ 'bonk' => array(
+ 'pattern' => '^\x00(BONK|INFO|META| ID3)',
+ 'group' => 'audio',
+ 'module' => 'bonk',
+ 'mime_type' => 'audio/xmms-bonk',
+ ),
+
+ // DSS - audio - Digital Speech Standard
+ 'dss' => array(
+ 'pattern' => '^[\x02-\x03]ds[s2]',
+ 'group' => 'audio',
+ 'module' => 'dss',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // DTS - audio - Dolby Theatre System
+ 'dts' => array(
+ 'pattern' => '^\x7F\xFE\x80\x01',
+ 'group' => 'audio',
+ 'module' => 'dts',
+ 'mime_type' => 'audio/dts',
+ ),
+
+ // FLAC - audio - Free Lossless Audio Codec
+ 'flac' => array(
+ 'pattern' => '^fLaC',
+ 'group' => 'audio',
+ 'module' => 'flac',
+ 'mime_type' => 'audio/x-flac',
+ ),
+
+ // LA - audio - Lossless Audio (LA)
+ 'la' => array(
+ 'pattern' => '^LA0[2-4]',
+ 'group' => 'audio',
+ 'module' => 'la',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // LPAC - audio - Lossless Predictive Audio Compression (LPAC)
+ 'lpac' => array(
+ 'pattern' => '^LPAC',
+ 'group' => 'audio',
+ 'module' => 'lpac',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // MIDI - audio - MIDI (Musical Instrument Digital Interface)
+ 'midi' => array(
+ 'pattern' => '^MThd',
+ 'group' => 'audio',
+ 'module' => 'midi',
+ 'mime_type' => 'audio/midi',
+ ),
+
+ // MAC - audio - Monkey's Audio Compressor
+ 'mac' => array(
+ 'pattern' => '^MAC ',
+ 'group' => 'audio',
+ 'module' => 'monkey',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
+// // MOD - audio - MODule (assorted sub-formats)
+// 'mod' => array(
+// 'pattern' => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)',
+// 'group' => 'audio',
+// 'module' => 'mod',
+// 'option' => 'mod',
+// 'mime_type' => 'audio/mod',
+// ),
+
+ // MOD - audio - MODule (Impulse Tracker)
+ 'it' => array(
+ 'pattern' => '^IMPM',
+ 'group' => 'audio',
+ 'module' => 'mod',
+ //'option' => 'it',
+ 'mime_type' => 'audio/it',
+ ),
+
+ // MOD - audio - MODule (eXtended Module, various sub-formats)
+ 'xm' => array(
+ 'pattern' => '^Extended Module',
+ 'group' => 'audio',
+ 'module' => 'mod',
+ //'option' => 'xm',
+ 'mime_type' => 'audio/xm',
+ ),
+
+ // MOD - audio - MODule (ScreamTracker)
+ 's3m' => array(
+ 'pattern' => '^.{44}SCRM',
+ 'group' => 'audio',
+ 'module' => 'mod',
+ //'option' => 's3m',
+ 'mime_type' => 'audio/s3m',
+ ),
+
+ // MPC - audio - Musepack / MPEGplus
+ 'mpc' => array(
+ 'pattern' => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
+ 'group' => 'audio',
+ 'module' => 'mpc',
+ 'mime_type' => 'audio/x-musepack',
+ ),
+
+ // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
+ 'mp3' => array(
+ 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
+ 'group' => 'audio',
+ 'module' => 'mp3',
+ 'mime_type' => 'audio/mpeg',
+ ),
+
+ // OFR - audio - OptimFROG
+ 'ofr' => array(
+ 'pattern' => '^(\*RIFF|OFR)',
+ 'group' => 'audio',
+ 'module' => 'optimfrog',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // RKAU - audio - RKive AUdio compressor
+ 'rkau' => array(
+ 'pattern' => '^RKA',
+ 'group' => 'audio',
+ 'module' => 'rkau',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // SHN - audio - Shorten
+ 'shn' => array(
+ 'pattern' => '^ajkg',
+ 'group' => 'audio',
+ 'module' => 'shorten',
+ 'mime_type' => 'audio/xmms-shn',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
+ 'tta' => array(
+ 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)'
+ 'group' => 'audio',
+ 'module' => 'tta',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // VOC - audio - Creative Voice (VOC)
+ 'voc' => array(
+ 'pattern' => '^Creative Voice File',
+ 'group' => 'audio',
+ 'module' => 'voc',
+ 'mime_type' => 'audio/voc',
+ ),
+
+ // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
+ 'vqf' => array(
+ 'pattern' => '^TWIN',
+ 'group' => 'audio',
+ 'module' => 'vqf',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // WV - audio - WavPack (v4.0+)
+ 'wv' => array(
+ 'pattern' => '^wvpk',
+ 'group' => 'audio',
+ 'module' => 'wavpack',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+
+ // Audio-Video formats
+
+ // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
+ 'asf' => array(
+ 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
+ 'group' => 'audio-video',
+ 'module' => 'asf',
+ 'mime_type' => 'video/x-ms-asf',
+ 'iconv_req' => false,
+ ),
+
+ // BINK - audio/video - Bink / Smacker
+ 'bink' => array(
+ 'pattern' => '^(BIK|SMK)',
+ 'group' => 'audio-video',
+ 'module' => 'bink',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // FLV - audio/video - FLash Video
+ 'flv' => array(
+ 'pattern' => '^FLV\x01',
+ 'group' => 'audio-video',
+ 'module' => 'flv',
+ 'mime_type' => 'video/x-flv',
+ ),
+
+ // MKAV - audio/video - Mastroka
+ 'matroska' => array(
+ 'pattern' => '^\x1A\x45\xDF\xA3',
+ 'group' => 'audio-video',
+ 'module' => 'matroska',
+ 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
+ ),
+
+ // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
+ 'mpeg' => array(
+ 'pattern' => '^\x00\x00\x01(\xBA|\xB3)',
+ 'group' => 'audio-video',
+ 'module' => 'mpeg',
+ 'mime_type' => 'video/mpeg',
+ ),
+
+ // NSV - audio/video - Nullsoft Streaming Video (NSV)
+ 'nsv' => array(
+ 'pattern' => '^NSV[sf]',
+ 'group' => 'audio-video',
+ 'module' => 'nsv',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
+ 'ogg' => array(
+ 'pattern' => '^OggS',
+ 'group' => 'audio',
+ 'module' => 'ogg',
+ 'mime_type' => 'application/ogg',
+ 'fail_id3' => 'WARNING',
+ 'fail_ape' => 'WARNING',
+ ),
+
+ // QT - audio/video - Quicktime
+ 'quicktime' => array(
+ 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
+ 'group' => 'audio-video',
+ 'module' => 'quicktime',
+ 'mime_type' => 'video/quicktime',
+ ),
+
+ // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
+ 'riff' => array(
+ 'pattern' => '^(RIFF|SDSS|FORM)',
+ 'group' => 'audio-video',
+ 'module' => 'riff',
+ 'mime_type' => 'audio/x-wave',
+ 'fail_ape' => 'WARNING',
+ ),
+
+ // Real - audio/video - RealAudio, RealVideo
+ 'real' => array(
+ 'pattern' => '^(\\.RMF|\\.ra)',
+ 'group' => 'audio-video',
+ 'module' => 'real',
+ 'mime_type' => 'audio/x-realaudio',
+ ),
+
+ // SWF - audio/video - ShockWave Flash
+ 'swf' => array(
+ 'pattern' => '^(F|C)WS',
+ 'group' => 'audio-video',
+ 'module' => 'swf',
+ 'mime_type' => 'application/x-shockwave-flash',
+ ),
+
+ // TS - audio/video - MPEG-2 Transport Stream
+ 'ts' => array(
+ 'pattern' => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern
+ 'group' => 'audio-video',
+ 'module' => 'ts',
+ 'mime_type' => 'video/MP2T',
+ ),
+
+
+ // Still-Image formats
+
+ // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
+ 'bmp' => array(
+ 'pattern' => '^BM',
+ 'group' => 'graphic',
+ 'module' => 'bmp',
+ 'mime_type' => 'image/bmp',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // GIF - still image - Graphics Interchange Format
+ 'gif' => array(
+ 'pattern' => '^GIF',
+ 'group' => 'graphic',
+ 'module' => 'gif',
+ 'mime_type' => 'image/gif',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // JPEG - still image - Joint Photographic Experts Group (JPEG)
+ 'jpg' => array(
+ 'pattern' => '^\xFF\xD8\xFF',
+ 'group' => 'graphic',
+ 'module' => 'jpg',
+ 'mime_type' => 'image/jpeg',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // PCD - still image - Kodak Photo CD
+ 'pcd' => array(
+ 'pattern' => '^.{2048}PCD_IPI\x00',
+ 'group' => 'graphic',
+ 'module' => 'pcd',
+ 'mime_type' => 'image/x-photo-cd',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // PNG - still image - Portable Network Graphics (PNG)
+ 'png' => array(
+ 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
+ 'group' => 'graphic',
+ 'module' => 'png',
+ 'mime_type' => 'image/png',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // SVG - still image - Scalable Vector Graphics (SVG)
+ 'svg' => array(
+ 'pattern' => '(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
+ 'group' => 'graphic',
+ 'module' => 'svg',
+ 'mime_type' => 'image/svg+xml',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // TIFF - still image - Tagged Information File Format (TIFF)
+ 'tiff' => array(
+ 'pattern' => '^(II\x2A\x00|MM\x00\x2A)',
+ 'group' => 'graphic',
+ 'module' => 'tiff',
+ 'mime_type' => 'image/tiff',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // EFAX - still image - eFax (TIFF derivative)
+ 'efax' => array(
+ 'pattern' => '^\xDC\xFE',
+ 'group' => 'graphic',
+ 'module' => 'efax',
+ 'mime_type' => 'image/efax',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // Data formats
+
+ // ISO - data - International Standards Organization (ISO) CD-ROM Image
+ 'iso' => array(
+ 'pattern' => '^.{32769}CD001',
+ 'group' => 'misc',
+ 'module' => 'iso',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ 'iconv_req' => false,
+ ),
+
+ // RAR - data - RAR compressed data
+ 'rar' => array(
+ 'pattern' => '^Rar\!',
+ 'group' => 'archive',
+ 'module' => 'rar',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // SZIP - audio/data - SZIP compressed data
+ 'szip' => array(
+ 'pattern' => '^SZ\x0A\x04',
+ 'group' => 'archive',
+ 'module' => 'szip',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // TAR - data - TAR compressed data
+ 'tar' => array(
+ 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
+ 'group' => 'archive',
+ 'module' => 'tar',
+ 'mime_type' => 'application/x-tar',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // GZIP - data - GZIP compressed data
+ 'gz' => array(
+ 'pattern' => '^\x1F\x8B\x08',
+ 'group' => 'archive',
+ 'module' => 'gzip',
+ 'mime_type' => 'application/x-gzip',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // ZIP - data - ZIP compressed data
+ 'zip' => array(
+ 'pattern' => '^PK\x03\x04',
+ 'group' => 'archive',
+ 'module' => 'zip',
+ 'mime_type' => 'application/zip',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // Misc other formats
+
+ // PAR2 - data - Parity Volume Set Specification 2.0
+ 'par2' => array (
+ 'pattern' => '^PAR2\x00PKT',
+ 'group' => 'misc',
+ 'module' => 'par2',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // PDF - data - Portable Document Format
+ 'pdf' => array(
+ 'pattern' => '^\x25PDF',
+ 'group' => 'misc',
+ 'module' => 'pdf',
+ 'mime_type' => 'application/pdf',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // MSOFFICE - data - ZIP compressed data
+ 'msoffice' => array(
+ 'pattern' => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
+ 'group' => 'misc',
+ 'module' => 'msoffice',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // CUE - data - CUEsheet (index to single-file disc images)
+ 'cue' => array(
+ 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
+ 'group' => 'misc',
+ 'module' => 'cue',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ );
+ }
+
+ return $format_info;
+ }
+
+
+
+ public function GetFileFormat(&$filedata, $filename='') {
+ // this function will determine the format of a file based on usually
+ // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
+ // and in the case of ISO CD image, 6 bytes offset 32kb from the start
+ // of the file).
+
+ // Identify file format - loop through $format_info and detect with reg expr
+ foreach ($this->GetFileFormatArray() as $format_name => $info) {
+ // The /s switch on preg_match() forces preg_match() NOT to treat
+ // newline (0x0A) characters as special chars but do a binary match
+ if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) {
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+ return $info;
+ }
+ }
+
+
+ if (preg_match('#\.mp[123a]$#i', $filename)) {
+ // Too many mp3 encoders on the market put gabage in front of mpeg files
+ // use assume format on these if format detection failed
+ $GetFileFormatArray = $this->GetFileFormatArray();
+ $info = $GetFileFormatArray['mp3'];
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+ return $info;
+ } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
+ // there's not really a useful consistent "magic" at the beginning of .cue files to identify them
+ // so until I think of something better, just go by filename if all other format checks fail
+ // and verify there's at least one instance of "TRACK xx AUDIO" in the file
+ $GetFileFormatArray = $this->GetFileFormatArray();
+ $info = $GetFileFormatArray['cue'];
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+ return $info;
+ }
+
+ return false;
+ }
+
+
+ // converts array to $encoding charset from $this->encoding
+ public function CharConvert(&$array, $encoding) {
+
+ // identical encoding - end here
+ if ($encoding == $this->encoding) {
+ return;
+ }
+
+ // loop thru array
+ foreach ($array as $key => $value) {
+
+ // go recursive
+ if (is_array($value)) {
+ $this->CharConvert($array[$key], $encoding);
+ }
+
+ // convert string
+ elseif (is_string($value)) {
+ $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
+ }
+ }
+ }
+
+
+ public function HandleAllTags() {
+
+ // key name => array (tag name, character encoding)
+ static $tags;
+ if (empty($tags)) {
+ $tags = array(
+ 'asf' => array('asf' , 'UTF-16LE'),
+ 'midi' => array('midi' , 'ISO-8859-1'),
+ 'nsv' => array('nsv' , 'ISO-8859-1'),
+ 'ogg' => array('vorbiscomment' , 'UTF-8'),
+ 'png' => array('png' , 'UTF-8'),
+ 'tiff' => array('tiff' , 'ISO-8859-1'),
+ 'quicktime' => array('quicktime' , 'UTF-8'),
+ 'real' => array('real' , 'ISO-8859-1'),
+ 'vqf' => array('vqf' , 'ISO-8859-1'),
+ 'zip' => array('zip' , 'ISO-8859-1'),
+ 'riff' => array('riff' , 'ISO-8859-1'),
+ 'lyrics3' => array('lyrics3' , 'ISO-8859-1'),
+ 'id3v1' => array('id3v1' , $this->encoding_id3v1),
+ 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8
+ 'ape' => array('ape' , 'UTF-8'),
+ 'cue' => array('cue' , 'ISO-8859-1'),
+ 'matroska' => array('matroska' , 'UTF-8'),
+ 'flac' => array('vorbiscomment' , 'UTF-8'),
+ 'divxtag' => array('divx' , 'ISO-8859-1'),
+ );
+ }
+
+ // loop through comments array
+ foreach ($tags as $comment_name => $tagname_encoding_array) {
+ list($tag_name, $encoding) = $tagname_encoding_array;
+
+ // fill in default encoding type if not already present
+ if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) {
+ $this->info[$comment_name]['encoding'] = $encoding;
+ }
+
+ // copy comments if key name set
+ if (!empty($this->info[$comment_name]['comments'])) {
+ foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
+ foreach ($valuearray as $key => $value) {
+ if (is_string($value)) {
+ $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
+ }
+ if ($value) {
+ $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
+ }
+ }
+ if ($tag_key == 'picture') {
+ unset($this->info[$comment_name]['comments'][$tag_key]);
+ }
+ }
+
+ if (!isset($this->info['tags'][$tag_name])) {
+ // comments are set but contain nothing but empty strings, so skip
+ continue;
+ }
+
+ if ($this->option_tags_html) {
+ foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
+ foreach ($valuearray as $key => $value) {
+ if (is_string($value)) {
+ //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding);
+ $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('&#0;', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding)));
+ } else {
+ $this->info['tags_html'][$tag_name][$tag_key][$key] = $value;
+ }
+ }
+ }
+ }
+
+ $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!
+ }
+
+ }
+
+ // pictures can take up a lot of space, and we don't need multiple copies of them
+ // let there be a single copy in [comments][picture], and not elsewhere
+ if (!empty($this->info['tags'])) {
+ $unset_keys = array('tags', 'tags_html');
+ foreach ($this->info['tags'] as $tagtype => $tagarray) {
+ foreach ($tagarray as $tagname => $tagdata) {
+ if ($tagname == 'picture') {
+ foreach ($tagdata as $key => $tagarray) {
+ $this->info['comments']['picture'][] = $tagarray;
+ if (isset($tagarray['data']) && isset($tagarray['image_mime'])) {
+ if (isset($this->info['tags'][$tagtype][$tagname][$key])) {
+ unset($this->info['tags'][$tagtype][$tagname][$key]);
+ }
+ if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) {
+ unset($this->info['tags_html'][$tagtype][$tagname][$key]);
+ }
+ }
+ }
+ }
+ }
+ foreach ($unset_keys as $unset_key) {
+ // remove possible empty keys from (e.g. [tags][id3v2][picture])
+ if (empty($this->info[$unset_key][$tagtype]['picture'])) {
+ unset($this->info[$unset_key][$tagtype]['picture']);
+ }
+ if (empty($this->info[$unset_key][$tagtype])) {
+ unset($this->info[$unset_key][$tagtype]);
+ }
+ if (empty($this->info[$unset_key])) {
+ unset($this->info[$unset_key]);
+ }
+ }
+ // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture])
+ if (isset($this->info[$tagtype]['comments']['picture'])) {
+ unset($this->info[$tagtype]['comments']['picture']);
+ }
+ if (empty($this->info[$tagtype]['comments'])) {
+ unset($this->info[$tagtype]['comments']);
+ }
+ if (empty($this->info[$tagtype])) {
+ unset($this->info[$tagtype]);
+ }
+ }
+ }
+ return true;
+ }
+
+
+ public function getHashdata($algorithm) {
+ switch ($algorithm) {
+ case 'md5':
+ case 'sha1':
+ break;
+
+ default:
+ return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
+ break;
+ }
+
+ if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
+
+ // We cannot get an identical md5_data value for Ogg files where the comments
+ // span more than 1 Ogg page (compared to the same audio data with smaller
+ // comments) using the normal getID3() method of MD5'ing the data between the
+ // end of the comments and the end of the file (minus any trailing tags),
+ // because the page sequence numbers of the pages that the audio data is on
+ // do not match. Under normal circumstances, where comments are smaller than
+ // the nominal 4-8kB page size, then this is not a problem, but if there are
+ // very large comments, the only way around it is to strip off the comment
+ // tags with vorbiscomment and MD5 that file.
+ // This procedure must be applied to ALL Ogg files, not just the ones with
+ // comments larger than 1 page, because the below method simply MD5's the
+ // whole file with the comments stripped, not just the portion after the
+ // comments block (which is the standard getID3() method.
+
+ // The above-mentioned problem of comments spanning multiple pages and changing
+ // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
+ // currently vorbiscomment only works on OggVorbis files.
+
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
+
+ $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
+ $this->info[$algorithm.'_data'] = false;
+
+ } else {
+
+ // Prevent user from aborting script
+ $old_abort = ignore_user_abort(true);
+
+ // Create empty file
+ $empty = tempnam(GETID3_TEMP_DIR, 'getID3');
+ touch($empty);
+
+ // Use vorbiscomment to make temp file without comments
+ $temp = tempnam(GETID3_TEMP_DIR, 'getID3');
+ $file = $this->info['filenamepath'];
+
+ if (GETID3_OS_ISWINDOWS) {
+
+ if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
+
+ $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"';
+ $VorbisCommentError = `$commandline`;
+
+ } else {
+
+ $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
+
+ }
+
+ } else {
+
+ $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
+ $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
+ $VorbisCommentError = `$commandline`;
+
+ }
+
+ if (!empty($VorbisCommentError)) {
+
+ $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;
+ $this->info[$algorithm.'_data'] = false;
+
+ } else {
+
+ // Get hash of newly created file
+ switch ($algorithm) {
+ case 'md5':
+ $this->info[$algorithm.'_data'] = md5_file($temp);
+ break;
+
+ case 'sha1':
+ $this->info[$algorithm.'_data'] = sha1_file($temp);
+ break;
+ }
+ }
+
+ // Clean up
+ unlink($empty);
+ unlink($temp);
+
+ // Reset abort setting
+ ignore_user_abort($old_abort);
+
+ }
+
+ } else {
+
+ if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) {
+
+ // get hash from part of file
+ $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
+
+ } else {
+
+ // get hash from whole file
+ switch ($algorithm) {
+ case 'md5':
+ $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']);
+ break;
+
+ case 'sha1':
+ $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']);
+ break;
+ }
+ }
+
+ }
+ return true;
+ }
+
+
+ public function ChannelsBitratePlaytimeCalculations() {
+
+ // set channelmode on audio
+ if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
+ // ignore
+ } elseif ($this->info['audio']['channels'] == 1) {
+ $this->info['audio']['channelmode'] = 'mono';
+ } elseif ($this->info['audio']['channels'] == 2) {
+ $this->info['audio']['channelmode'] = 'stereo';
+ }
+
+ // Calculate combined bitrate - audio + video
+ $CombinedBitrate = 0;
+ $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
+ $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
+ if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) {
+ $this->info['bitrate'] = $CombinedBitrate;
+ }
+ //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
+ // // for example, VBR MPEG video files cannot determine video bitrate:
+ // // should not set overall bitrate and playtime from audio bitrate only
+ // unset($this->info['bitrate']);
+ //}
+
+ // video bitrate undetermined, but calculable
+ if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) {
+ // if video bitrate not set
+ if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) {
+ // AND if audio bitrate is set to same as overall bitrate
+ if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) {
+ // AND if playtime is set
+ if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) {
+ // AND if AV data offset start/end is known
+ // THEN we can calculate the video bitrate
+ $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']);
+ $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate'];
+ }
+ }
+ }
+ }
+
+ if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
+ $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
+ }
+
+ if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
+ $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
+ }
+ if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
+ if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
+ // audio only
+ $this->info['audio']['bitrate'] = $this->info['bitrate'];
+ } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
+ // video only
+ $this->info['video']['bitrate'] = $this->info['bitrate'];
+ }
+ }
+
+ // Set playtime string
+ if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
+ $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
+ }
+ }
+
+
+ public function CalculateCompressionRatioVideo() {
+ if (empty($this->info['video'])) {
+ return false;
+ }
+ if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
+ return false;
+ }
+ if (empty($this->info['video']['bits_per_sample'])) {
+ return false;
+ }
+
+ switch ($this->info['video']['dataformat']) {
+ case 'bmp':
+ case 'gif':
+ case 'jpeg':
+ case 'jpg':
+ case 'png':
+ case 'tiff':
+ $FrameRate = 1;
+ $PlaytimeSeconds = 1;
+ $BitrateCompressed = $this->info['filesize'] * 8;
+ break;
+
+ default:
+ if (!empty($this->info['video']['frame_rate'])) {
+ $FrameRate = $this->info['video']['frame_rate'];
+ } else {
+ return false;
+ }
+ if (!empty($this->info['playtime_seconds'])) {
+ $PlaytimeSeconds = $this->info['playtime_seconds'];
+ } else {
+ return false;
+ }
+ if (!empty($this->info['video']['bitrate'])) {
+ $BitrateCompressed = $this->info['video']['bitrate'];
+ } else {
+ return false;
+ }
+ break;
+ }
+ $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;
+
+ $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
+ return true;
+ }
+
+
+ public function CalculateCompressionRatioAudio() {
+ if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
+ return false;
+ }
+ $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
+
+ if (!empty($this->info['audio']['streams'])) {
+ foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
+ if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
+ $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
+ }
+ }
+ }
+ return true;
+ }
+
+
+ public function CalculateReplayGain() {
+ if (isset($this->info['replay_gain'])) {
+ if (!isset($this->info['replay_gain']['reference_volume'])) {
+ $this->info['replay_gain']['reference_volume'] = (double) 89.0;
+ }
+ if (isset($this->info['replay_gain']['track']['adjustment'])) {
+ $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
+ }
+ if (isset($this->info['replay_gain']['album']['adjustment'])) {
+ $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
+ }
+
+ if (isset($this->info['replay_gain']['track']['peak'])) {
+ $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
+ }
+ if (isset($this->info['replay_gain']['album']['peak'])) {
+ $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
+ }
+ }
+ return true;
+ }
+
+ public function ProcessAudioStreams() {
+ if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
+ if (!isset($this->info['audio']['streams'])) {
+ foreach ($this->info['audio'] as $key => $value) {
+ if ($key != 'streams') {
+ $this->info['audio']['streams'][0][$key] = $value;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public function getid3_tempnam() {
+ return tempnam($this->tempdir, 'gI3');
+ }
+
+ public function include_module($name) {
+ //if (!file_exists($this->include_path.'module.'.$name.'.php')) {
+ if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
+ throw new getid3_exception('Required module.'.$name.'.php is missing.');
+ }
+ include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
+ return true;
+ }
+
+}
+
+
+abstract class getid3_handler
+{
+ protected $getid3; // pointer
+
+ protected $data_string_flag = false; // analyzing filepointer or string
+ protected $data_string = ''; // string to analyze
+ protected $data_string_position = 0; // seek position in string
+ protected $data_string_length = 0; // string length
+
+ private $dependency_to = null;
+
+
+ public function __construct(getID3 $getid3, $call_module=null) {
+ $this->getid3 = $getid3;
+
+ if ($call_module) {
+ $this->dependency_to = str_replace('getid3_', '', $call_module);
+ }
+ }
+
+
+ // Analyze from file pointer
+ abstract public function Analyze();
+
+
+ // Analyze from string instead
+ public function AnalyzeString($string) {
+ // Enter string mode
+ $this->setStringMode($string);
+
+ // Save info
+ $saved_avdataoffset = $this->getid3->info['avdataoffset'];
+ $saved_avdataend = $this->getid3->info['avdataend'];
+ $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call
+
+ // Reset some info
+ $this->getid3->info['avdataoffset'] = 0;
+ $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length;
+
+ // Analyze
+ $this->Analyze();
+
+ // Restore some info
+ $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
+ $this->getid3->info['avdataend'] = $saved_avdataend;
+ $this->getid3->info['filesize'] = $saved_filesize;
+
+ // Exit string mode
+ $this->data_string_flag = false;
+ }
+
+ public function setStringMode($string) {
+ $this->data_string_flag = true;
+ $this->data_string = $string;
+ $this->data_string_length = strlen($string);
+ }
+
+ protected function ftell() {
+ if ($this->data_string_flag) {
+ return $this->data_string_position;
+ }
+ return ftell($this->getid3->fp);
+ }
+
+ protected function fread($bytes) {
+ if ($this->data_string_flag) {
+ $this->data_string_position += $bytes;
+ return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
+ }
+ $pos = $this->ftell() + $bytes;
+ if (!getid3_lib::intValueSupported($pos)) {
+ throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
+ }
+ return fread($this->getid3->fp, $bytes);
+ }
+
+ protected function fseek($bytes, $whence=SEEK_SET) {
+ if ($this->data_string_flag) {
+ switch ($whence) {
+ case SEEK_SET:
+ $this->data_string_position = $bytes;
+ break;
+
+ case SEEK_CUR:
+ $this->data_string_position += $bytes;
+ break;
+
+ case SEEK_END:
+ $this->data_string_position = $this->data_string_length + $bytes;
+ break;
+ }
+ return 0;
+ } else {
+ $pos = $bytes;
+ if ($whence == SEEK_CUR) {
+ $pos = $this->ftell() + $bytes;
+ } elseif ($whence == SEEK_END) {
+ $pos = $this->info['filesize'] + $bytes;
+ }
+ if (!getid3_lib::intValueSupported($pos)) {
+ throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
+ }
+ }
+ return fseek($this->getid3->fp, $bytes, $whence);
+ }
+
+ protected function feof() {
+ if ($this->data_string_flag) {
+ return $this->data_string_position >= $this->data_string_length;
+ }
+ return feof($this->getid3->fp);
+ }
+
+ final protected function isDependencyFor($module) {
+ return $this->dependency_to == $module;
+ }
+
+ protected function error($text)
+ {
+ $this->getid3->info['error'][] = $text;
+
+ return false;
+ }
+
+ protected function warning($text)
+ {
+ return $this->getid3->warning($text);
+ }
+
+ protected function notice($text)
+ {
+ // does nothing for now
+ }
+
+ public function saveAttachment($name, $offset, $length, $image_mime=null) {
+ try {
+
+ // do not extract at all
+ if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
+
+ $attachment = null; // do not set any
+
+ // extract to return array
+ } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
+
+ $this->fseek($offset);
+ $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory
+ if ($attachment === false || strlen($attachment) != $length) {
+ throw new Exception('failed to read attachment data');
+ }
+
+ // assume directory path is given
+ } else {
+
+ // set up destination path
+ $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
+ if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory
+ throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
+ }
+ $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
+
+ // create dest file
+ if (($fp_dest = fopen($dest, 'wb')) == false) {
+ throw new Exception('failed to create file '.$dest);
+ }
+
+ // copy data
+ $this->fseek($offset);
+ $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
+ $bytesleft = $length;
+ while ($bytesleft > 0) {
+ if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) {
+ throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
+ }
+ $bytesleft -= $byteswritten;
+ }
+
+ fclose($fp_dest);
+ $attachment = $dest;
+
+ }
+
+ } catch (Exception $e) {
+
+ // close and remove dest file if created
+ if (isset($fp_dest) && is_resource($fp_dest)) {
+ fclose($fp_dest);
+ unlink($dest);
+ }
+
+ // do not set any is case of error
+ $attachment = null;
+ $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage());
+
+ }
+
+ // seek to the end of attachment
+ $this->fseek($offset + $length);
+
+ return $attachment;
+ }
+
+}
+
+
+class getid3_exception extends Exception
+{
+ public $message;
+} \ No newline at end of file
diff --git a/src/wp-includes/ID3/license.commercial.txt b/src/wp-includes/ID3/license.commercial.txt
new file mode 100644
index 0000000000..416e5a1469
--- /dev/null
+++ b/src/wp-includes/ID3/license.commercial.txt
@@ -0,0 +1,27 @@
+ getID3() Commercial License
+ ===========================
+
+getID3() is licensed under the "GNU Public License" (GPL) and/or the
+"getID3() Commercial License" (gCL). This document describes the gCL.
+
+---------------------------------------------------------------------
+
+The license is non-exclusively granted to a single person or company,
+per payment of the license fee, for the lifetime of that person or
+company. The license is non-transferrable.
+
+The gCL grants the licensee the right to use getID3() in commercial
+closed-source projects. Modifications may be made to getID3() with no
+obligation to release the modified source code. getID3() (or pieces
+thereof) may be included in any number of projects authored (in whole
+or in part) by the licensee.
+
+The licensee may use any version of getID3(), past, present or future,
+as is most convenient. This license does not entitle the licensee to
+receive any technical support, updates or bugfixes, except as such are
+made publicly available to all getID3() users.
+
+The licensee may not sub-license getID3() itself, meaning that any
+commercially released product containing all or parts of getID3() must
+have added functionality beyond what is available in getID3();
+getID3() itself may not be re-licensed by the licensee.
diff --git a/src/wp-includes/ID3/license.txt b/src/wp-includes/ID3/license.txt
new file mode 100644
index 0000000000..85f4356e81
--- /dev/null
+++ b/src/wp-includes/ID3/license.txt
@@ -0,0 +1,28 @@
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+
+*****************************************************************
+*****************************************************************
+
+ getID3() is released under multiple licenses. You may choose
+ from the following licenses, and use getID3 according to the
+ terms of the license most suitable to your project.
+
+GNU GPL: https://gnu.org/licenses/gpl.html (v3)
+ https://gnu.org/licenses/old-licenses/gpl-2.0.html (v2)
+ https://gnu.org/licenses/old-licenses/gpl-1.0.html (v1)
+
+GNU LGPL: https://gnu.org/licenses/lgpl.html (v3)
+
+Mozilla MPL: http://www.mozilla.org/MPL/2.0/ (v2)
+
+getID3 Commercial License: http://getid3.org/#gCL (payment required)
+
+*****************************************************************
+*****************************************************************
+
+Copies of each of the above licenses are included in the 'licenses'
+directory of the getID3 distribution.
diff --git a/src/wp-includes/ID3/module.audio-video.asf.php b/src/wp-includes/ID3/module.audio-video.asf.php
new file mode 100644
index 0000000000..cfc60a7803
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio-video.asf.php
@@ -0,0 +1,2019 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.asf.php //
+// module for analyzing ASF, WMA and WMV files //
+// dependencies: module.audio-video.riff.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true);
+
+class getid3_asf extends getid3_handler
+{
+
+ public function __construct(getID3 $getid3) {
+ parent::__construct($getid3); // extends getid3_handler::__construct()
+
+ // initialize all GUID constants
+ $GUIDarray = $this->KnownGUIDs();
+ foreach ($GUIDarray as $GUIDname => $hexstringvalue) {
+ if (!defined($GUIDname)) {
+ define($GUIDname, $this->GUIDtoBytestring($hexstringvalue));
+ }
+ }
+ }
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ // Shortcuts
+ $thisfile_audio = &$info['audio'];
+ $thisfile_video = &$info['video'];
+ $info['asf'] = array();
+ $thisfile_asf = &$info['asf'];
+ $thisfile_asf['comments'] = array();
+ $thisfile_asf_comments = &$thisfile_asf['comments'];
+ $thisfile_asf['header_object'] = array();
+ $thisfile_asf_headerobject = &$thisfile_asf['header_object'];
+
+
+ // ASF structure:
+ // * Header Object [required]
+ // * File Properties Object [required] (global file attributes)
+ // * Stream Properties Object [required] (defines media stream & characteristics)
+ // * Header Extension Object [required] (additional functionality)
+ // * Content Description Object (bibliographic information)
+ // * Script Command Object (commands for during playback)
+ // * Marker Object (named jumped points within the file)
+ // * Data Object [required]
+ // * Data Packets
+ // * Index Object
+
+ // Header Object: (mandatory, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for header object - GETID3_ASF_Header_Object
+ // Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header
+ // Number of Header Objects DWORD 32 // number of objects in header object
+ // Reserved1 BYTE 8 // hardcoded: 0x01
+ // Reserved2 BYTE 8 // hardcoded: 0x02
+
+ $info['fileformat'] = 'asf';
+
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+ $HeaderObjectData = fread($this->getid3->fp, 30);
+
+ $thisfile_asf_headerobject['objectid'] = substr($HeaderObjectData, 0, 16);
+ $thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']);
+ if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) {
+ $info['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}';
+ unset($info['fileformat']);
+ unset($info['asf']);
+ return false;
+ break;
+ }
+ $thisfile_asf_headerobject['objectsize'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8));
+ $thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4));
+ $thisfile_asf_headerobject['reserved1'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1));
+ $thisfile_asf_headerobject['reserved2'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1));
+
+ $NextObjectOffset = ftell($this->getid3->fp);
+ $ASFHeaderData = fread($this->getid3->fp, $thisfile_asf_headerobject['objectsize'] - 30);
+ $offset = 0;
+
+ for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) {
+ $NextObjectGUID = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
+ $NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ switch ($NextObjectGUID) {
+
+ case GETID3_ASF_File_Properties_Object:
+ // File Properties Object: (mandatory, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for file properties object - GETID3_ASF_File_Properties_Object
+ // Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header
+ // File ID GUID 128 // unique ID - identical to File ID in Data Object
+ // File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1
+ // Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1
+ // Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1
+ // Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1
+ // Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1
+ // Preroll QWORD 64 // time to buffer data before starting to play file, in 1-millisecond units. If <> 0, PlayDuration and PresentationTime have been offset by this amount
+ // Flags DWORD 32 //
+ // * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid
+ // * Seekable Flag bits 1 (0x02) // is file seekable
+ // * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero
+ // Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1
+ // Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1
+ // Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead
+
+ // shortcut
+ $thisfile_asf['file_properties_object'] = array();
+ $thisfile_asf_filepropertiesobject = &$thisfile_asf['file_properties_object'];
+
+ $thisfile_asf_filepropertiesobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_filepropertiesobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_filepropertiesobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_filepropertiesobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_filepropertiesobject['fileid'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_filepropertiesobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_filepropertiesobject['fileid']);
+ $thisfile_asf_filepropertiesobject['filesize'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_filepropertiesobject['creation_date'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $thisfile_asf_filepropertiesobject['creation_date_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_filepropertiesobject['creation_date']);
+ $offset += 8;
+ $thisfile_asf_filepropertiesobject['data_packets'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_filepropertiesobject['play_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_filepropertiesobject['send_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_filepropertiesobject['preroll'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_filepropertiesobject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_filepropertiesobject['flags']['broadcast'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0001);
+ $thisfile_asf_filepropertiesobject['flags']['seekable'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0002);
+
+ $thisfile_asf_filepropertiesobject['min_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_filepropertiesobject['max_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_filepropertiesobject['max_bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+
+ if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) {
+
+ // broadcast flag is set, some values invalid
+ unset($thisfile_asf_filepropertiesobject['filesize']);
+ unset($thisfile_asf_filepropertiesobject['data_packets']);
+ unset($thisfile_asf_filepropertiesobject['play_duration']);
+ unset($thisfile_asf_filepropertiesobject['send_duration']);
+ unset($thisfile_asf_filepropertiesobject['min_packet_size']);
+ unset($thisfile_asf_filepropertiesobject['max_packet_size']);
+
+ } else {
+
+ // broadcast flag NOT set, perform calculations
+ $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000);
+
+ //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate'];
+ $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds'];
+ }
+ break;
+
+ case GETID3_ASF_Stream_Properties_Object:
+ // Stream Properties Object: (mandatory, one per media stream)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for stream properties object - GETID3_ASF_Stream_Properties_Object
+ // Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header
+ // Stream Type GUID 128 // GETID3_ASF_Audio_Media, GETID3_ASF_Video_Media or GETID3_ASF_Command_Media
+ // Error Correction Type GUID 128 // GETID3_ASF_Audio_Spread for audio-only streams, GETID3_ASF_No_Error_Correction for other stream types
+ // Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream
+ // Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field
+ // Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field
+ // Flags WORD 16 //
+ // * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127
+ // * Reserved bits 8 (0x7F80) // reserved - set to zero
+ // * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set
+ // Reserved DWORD 32 // reserved - set to zero
+ // Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type
+ // Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type
+
+ // There is one GETID3_ASF_Stream_Properties_Object for each stream (audio, video) but the
+ // stream number isn't known until halfway through decoding the structure, hence it
+ // it is decoded to a temporary variable and then stuck in the appropriate index later
+
+ $StreamPropertiesObjectData['offset'] = $NextObjectOffset + $offset;
+ $StreamPropertiesObjectData['objectid'] = $NextObjectGUID;
+ $StreamPropertiesObjectData['objectid_guid'] = $NextObjectGUIDtext;
+ $StreamPropertiesObjectData['objectsize'] = $NextObjectSize;
+ $StreamPropertiesObjectData['stream_type'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $StreamPropertiesObjectData['stream_type_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['stream_type']);
+ $StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $StreamPropertiesObjectData['error_correct_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['error_correct_type']);
+ $StreamPropertiesObjectData['time_offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $StreamPropertiesObjectData['type_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $StreamPropertiesObjectData['error_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $StreamPropertiesObjectData['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $StreamPropertiesObjectStreamNumber = $StreamPropertiesObjectData['flags_raw'] & 0x007F;
+ $StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000);
+
+ $offset += 4; // reserved - DWORD
+ $StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']);
+ $offset += $StreamPropertiesObjectData['type_data_length'];
+ $StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']);
+ $offset += $StreamPropertiesObjectData['error_data_length'];
+
+ switch ($StreamPropertiesObjectData['stream_type']) {
+
+ case GETID3_ASF_Audio_Media:
+ $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf');
+ $thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr');
+
+ $audiodata = getid3_riff::parseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16));
+ unset($audiodata['raw']);
+ $thisfile_audio = getid3_lib::array_merge_noclobber($audiodata, $thisfile_audio);
+ break;
+
+ case GETID3_ASF_Video_Media:
+ $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf');
+ $thisfile_video['bitrate_mode'] = (!empty($thisfile_video['bitrate_mode']) ? $thisfile_video['bitrate_mode'] : 'cbr');
+ break;
+
+ case GETID3_ASF_Command_Media:
+ default:
+ // do nothing
+ break;
+
+ }
+
+ $thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData;
+ unset($StreamPropertiesObjectData); // clear for next stream, if any
+ break;
+
+ case GETID3_ASF_Header_Extension_Object:
+ // Header Extension Object: (mandatory, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Header Extension object - GETID3_ASF_Header_Extension_Object
+ // Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header
+ // Reserved Field 1 GUID 128 // hardcoded: GETID3_ASF_Reserved_1
+ // Reserved Field 2 WORD 16 // hardcoded: 0x00000006
+ // Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46
+ // Header Extension Data BYTESTREAM variable // array of zero or more extended header objects
+
+ // shortcut
+ $thisfile_asf['header_extension_object'] = array();
+ $thisfile_asf_headerextensionobject = &$thisfile_asf['header_extension_object'];
+
+ $thisfile_asf_headerextensionobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_headerextensionobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_headerextensionobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_headerextensionobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_headerextensionobject['reserved_1'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']);
+ if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) {
+ $info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')';
+ //return false;
+ break;
+ }
+ $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) {
+ $info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"';
+ //return false;
+ break;
+ }
+ $thisfile_asf_headerextensionobject['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_headerextensionobject['extension_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']);
+ $unhandled_sections = 0;
+ $thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->ASF_HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections);
+ if ($unhandled_sections === 0) {
+ unset($thisfile_asf_headerextensionobject['extension_data']);
+ }
+ $offset += $thisfile_asf_headerextensionobject['extension_data_size'];
+ break;
+
+ case GETID3_ASF_Codec_List_Object:
+ // Codec List Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Codec List object - GETID3_ASF_Codec_List_Object
+ // Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header
+ // Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6
+ // Codec Entries Count DWORD 32 // number of entries in Codec Entries array
+ // Codec Entries array of: variable //
+ // * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec
+ // * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field
+ // * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content
+ // * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field
+ // * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content
+ // * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field
+ // * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content
+
+ // shortcut
+ $thisfile_asf['codec_list_object'] = array();
+ $thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object'];
+
+ $thisfile_asf_codeclistobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_codeclistobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_codeclistobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_codeclistobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_codeclistobject['reserved'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']);
+ if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) {
+ $info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}';
+ //return false;
+ break;
+ }
+ $thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) {
+ // shortcut
+ $thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array();
+ $thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter];
+
+ $thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_codeclistobject_codecentries_current['type'] = $this->ASFCodecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']);
+
+ $CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
+ $offset += 2;
+ $thisfile_asf_codeclistobject_codecentries_current['name'] = substr($ASFHeaderData, $offset, $CodecNameLength);
+ $offset += $CodecNameLength;
+
+ $CodecDescriptionLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
+ $offset += 2;
+ $thisfile_asf_codeclistobject_codecentries_current['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength);
+ $offset += $CodecDescriptionLength;
+
+ $CodecInformationLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_codeclistobject_codecentries_current['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength);
+ $offset += $CodecInformationLength;
+
+ if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec
+
+ if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) {
+ $info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"';
+ } else {
+
+ list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']));
+ $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']);
+
+ if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) {
+ $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000);
+ }
+ //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) {
+ if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) {
+ //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate'];
+ $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate'];
+ }
+
+ $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency));
+ switch ($AudioCodecFrequency) {
+ case 8:
+ case 8000:
+ $thisfile_audio['sample_rate'] = 8000;
+ break;
+
+ case 11:
+ case 11025:
+ $thisfile_audio['sample_rate'] = 11025;
+ break;
+
+ case 12:
+ case 12000:
+ $thisfile_audio['sample_rate'] = 12000;
+ break;
+
+ case 16:
+ case 16000:
+ $thisfile_audio['sample_rate'] = 16000;
+ break;
+
+ case 22:
+ case 22050:
+ $thisfile_audio['sample_rate'] = 22050;
+ break;
+
+ case 24:
+ case 24000:
+ $thisfile_audio['sample_rate'] = 24000;
+ break;
+
+ case 32:
+ case 32000:
+ $thisfile_audio['sample_rate'] = 32000;
+ break;
+
+ case 44:
+ case 441000:
+ $thisfile_audio['sample_rate'] = 44100;
+ break;
+
+ case 48:
+ case 48000:
+ $thisfile_audio['sample_rate'] = 48000;
+ break;
+
+ default:
+ $info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')';
+ break;
+ }
+
+ if (!isset($thisfile_audio['channels'])) {
+ if (strstr($AudioCodecChannels, 'stereo')) {
+ $thisfile_audio['channels'] = 2;
+ } elseif (strstr($AudioCodecChannels, 'mono')) {
+ $thisfile_audio['channels'] = 1;
+ }
+ }
+
+ }
+ }
+ }
+ break;
+
+ case GETID3_ASF_Script_Command_Object:
+ // Script Command Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Script Command object - GETID3_ASF_Script_Command_Object
+ // Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header
+ // Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6
+ // Commands Count WORD 16 // number of Commands structures in the Script Commands Objects
+ // Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects
+ // Command Types array of: variable //
+ // * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name
+ // * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command
+ // Commands array of: variable //
+ // * Presentation Time DWORD 32 // presentation time of that command, in milliseconds
+ // * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object
+ // * Command Name Length WORD 16 // number of Unicode characters for Command Name
+ // * Command Name WCHAR variable // array of Unicode characters - name of this command
+
+ // shortcut
+ $thisfile_asf['script_command_object'] = array();
+ $thisfile_asf_scriptcommandobject = &$thisfile_asf['script_command_object'];
+
+ $thisfile_asf_scriptcommandobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_scriptcommandobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_scriptcommandobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_scriptcommandobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_scriptcommandobject['reserved'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']);
+ if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) {
+ $info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}';
+ //return false;
+ break;
+ }
+ $thisfile_asf_scriptcommandobject['commands_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_scriptcommandobject['command_types_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) {
+ $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
+ $offset += 2;
+ $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
+ $offset += $CommandTypeNameLength;
+ }
+ for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) {
+ $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+
+ $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character
+ $offset += 2;
+ $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength);
+ $offset += $CommandTypeNameLength;
+ }
+ break;
+
+ case GETID3_ASF_Marker_Object:
+ // Marker Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Marker object - GETID3_ASF_Marker_Object
+ // Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header
+ // Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB
+ // Markers Count DWORD 32 // number of Marker structures in Marker Object
+ // Reserved WORD 16 // hardcoded: 0x0000
+ // Name Length WORD 16 // number of bytes in the Name field
+ // Name WCHAR variable // name of the Marker Object
+ // Markers array of: variable //
+ // * Offset QWORD 64 // byte offset into Data Object
+ // * Presentation Time QWORD 64 // in 100-nanosecond units
+ // * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding)
+ // * Send Time DWORD 32 // in milliseconds
+ // * Flags DWORD 32 // hardcoded: 0x00000000
+ // * Marker Description Length DWORD 32 // number of bytes in Marker Description field
+ // * Marker Description WCHAR variable // array of Unicode characters - description of marker entry
+ // * Padding BYTESTREAM variable // optional padding bytes
+
+ // shortcut
+ $thisfile_asf['marker_object'] = array();
+ $thisfile_asf_markerobject = &$thisfile_asf['marker_object'];
+
+ $thisfile_asf_markerobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_markerobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_markerobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_markerobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_markerobject['reserved'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']);
+ if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) {
+ $info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}';
+ break;
+ }
+ $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ if ($thisfile_asf_markerobject['reserved_2'] != 0) {
+ $info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"';
+ break;
+ }
+ $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']);
+ $offset += $thisfile_asf_markerobject['name_length'];
+ for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) {
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['send_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['flags'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']);
+ $offset += $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'];
+ $PaddingLength = $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] - 4 - 4 - 4 - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'];
+ if ($PaddingLength > 0) {
+ $thisfile_asf_markerobject['markers'][$MarkersCounter]['padding'] = substr($ASFHeaderData, $offset, $PaddingLength);
+ $offset += $PaddingLength;
+ }
+ }
+ break;
+
+ case GETID3_ASF_Bitrate_Mutual_Exclusion_Object:
+ // Bitrate Mutual Exclusion Object: (optional)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - GETID3_ASF_Bitrate_Mutual_Exclusion_Object
+ // Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header
+ // Exlusion Type GUID 128 // nature of mutual exclusion relationship. one of: (GETID3_ASF_Mutex_Bitrate, GETID3_ASF_Mutex_Unknown)
+ // Stream Numbers Count WORD 16 // number of video streams
+ // Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127
+
+ // shortcut
+ $thisfile_asf['bitrate_mutual_exclusion_object'] = array();
+ $thisfile_asf_bitratemutualexclusionobject = &$thisfile_asf['bitrate_mutual_exclusion_object'];
+
+ $thisfile_asf_bitratemutualexclusionobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_bitratemutualexclusionobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_bitratemutualexclusionobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_bitratemutualexclusionobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_bitratemutualexclusionobject['reserved'] = substr($ASFHeaderData, $offset, 16);
+ $thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']);
+ $offset += 16;
+ if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) {
+ $info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}';
+ //return false;
+ break;
+ }
+ $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) {
+ $thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ }
+ break;
+
+ case GETID3_ASF_Error_Correction_Object:
+ // Error Correction Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Error Correction object - GETID3_ASF_Error_Correction_Object
+ // Object Size QWORD 64 // size of Error Correction object, including 44 bytes of Error Correction Object header
+ // Error Correction Type GUID 128 // type of error correction. one of: (GETID3_ASF_No_Error_Correction, GETID3_ASF_Audio_Spread)
+ // Error Correction Data Length DWORD 32 // number of bytes in Error Correction Data field
+ // Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field
+
+ // shortcut
+ $thisfile_asf['error_correction_object'] = array();
+ $thisfile_asf_errorcorrectionobject = &$thisfile_asf['error_correction_object'];
+
+ $thisfile_asf_errorcorrectionobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_errorcorrectionobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_errorcorrectionobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_errorcorrectionobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_errorcorrectionobject['error_correction_type'] = substr($ASFHeaderData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_errorcorrectionobject['error_correction_guid'] = $this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']);
+ $thisfile_asf_errorcorrectionobject['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ switch ($thisfile_asf_errorcorrectionobject['error_correction_type']) {
+ case GETID3_ASF_No_Error_Correction:
+ // should be no data, but just in case there is, skip to the end of the field
+ $offset += $thisfile_asf_errorcorrectionobject['error_correction_data_length'];
+ break;
+
+ case GETID3_ASF_Audio_Spread:
+ // Field Name Field Type Size (bits)
+ // Span BYTE 8 // number of packets over which audio will be spread.
+ // Virtual Packet Length WORD 16 // size of largest audio payload found in audio stream
+ // Virtual Chunk Length WORD 16 // size of largest audio payload found in audio stream
+ // Silence Data Length WORD 16 // number of bytes in Silence Data field
+ // Silence Data BYTESTREAM variable // hardcoded: 0x00 * (Silence Data Length) bytes
+
+ $thisfile_asf_errorcorrectionobject['span'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 1));
+ $offset += 1;
+ $thisfile_asf_errorcorrectionobject['virtual_packet_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_errorcorrectionobject['virtual_chunk_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_errorcorrectionobject['silence_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_errorcorrectionobject['silence_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_errorcorrectionobject['silence_data_length']);
+ $offset += $thisfile_asf_errorcorrectionobject['silence_data_length'];
+ break;
+
+ default:
+ $info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}';
+ //return false;
+ break;
+ }
+
+ break;
+
+ case GETID3_ASF_Content_Description_Object:
+ // Content Description Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Content Description object - GETID3_ASF_Content_Description_Object
+ // Object Size QWORD 64 // size of Content Description object, including 34 bytes of Content Description Object header
+ // Title Length WORD 16 // number of bytes in Title field
+ // Author Length WORD 16 // number of bytes in Author field
+ // Copyright Length WORD 16 // number of bytes in Copyright field
+ // Description Length WORD 16 // number of bytes in Description field
+ // Rating Length WORD 16 // number of bytes in Rating field
+ // Title WCHAR 16 // array of Unicode characters - Title
+ // Author WCHAR 16 // array of Unicode characters - Author
+ // Copyright WCHAR 16 // array of Unicode characters - Copyright
+ // Description WCHAR 16 // array of Unicode characters - Description
+ // Rating WCHAR 16 // array of Unicode characters - Rating
+
+ // shortcut
+ $thisfile_asf['content_description_object'] = array();
+ $thisfile_asf_contentdescriptionobject = &$thisfile_asf['content_description_object'];
+
+ $thisfile_asf_contentdescriptionobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_contentdescriptionobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_contentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_contentdescriptionobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_contentdescriptionobject['title_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_contentdescriptionobject['author_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_contentdescriptionobject['copyright_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_contentdescriptionobject['description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_contentdescriptionobject['rating_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_contentdescriptionobject['title'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['title_length']);
+ $offset += $thisfile_asf_contentdescriptionobject['title_length'];
+ $thisfile_asf_contentdescriptionobject['author'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['author_length']);
+ $offset += $thisfile_asf_contentdescriptionobject['author_length'];
+ $thisfile_asf_contentdescriptionobject['copyright'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['copyright_length']);
+ $offset += $thisfile_asf_contentdescriptionobject['copyright_length'];
+ $thisfile_asf_contentdescriptionobject['description'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['description_length']);
+ $offset += $thisfile_asf_contentdescriptionobject['description_length'];
+ $thisfile_asf_contentdescriptionobject['rating'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']);
+ $offset += $thisfile_asf_contentdescriptionobject['rating_length'];
+
+ $ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating');
+ foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) {
+ if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) {
+ $thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]);
+ }
+ }
+ break;
+
+ case GETID3_ASF_Extended_Content_Description_Object:
+ // Extended Content Description Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Extended Content Description object - GETID3_ASF_Extended_Content_Description_Object
+ // Object Size QWORD 64 // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header
+ // Content Descriptors Count WORD 16 // number of entries in Content Descriptors list
+ // Content Descriptors array of: variable //
+ // * Descriptor Name Length WORD 16 // size in bytes of Descriptor Name field
+ // * Descriptor Name WCHAR variable // array of Unicode characters - Descriptor Name
+ // * Descriptor Value Data Type WORD 16 // Lookup array:
+ // 0x0000 = Unicode String (variable length)
+ // 0x0001 = BYTE array (variable length)
+ // 0x0002 = BOOL (DWORD, 32 bits)
+ // 0x0003 = DWORD (DWORD, 32 bits)
+ // 0x0004 = QWORD (QWORD, 64 bits)
+ // 0x0005 = WORD (WORD, 16 bits)
+ // * Descriptor Value Length WORD 16 // number of bytes stored in Descriptor Value field
+ // * Descriptor Value variable variable // value for Content Descriptor
+
+ // shortcut
+ $thisfile_asf['extended_content_description_object'] = array();
+ $thisfile_asf_extendedcontentdescriptionobject = &$thisfile_asf['extended_content_description_object'];
+
+ $thisfile_asf_extendedcontentdescriptionobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_extendedcontentdescriptionobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_extendedcontentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_extendedcontentdescriptionobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) {
+ // shortcut
+ $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array();
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter];
+
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset'] = $offset + 30;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']);
+ $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'];
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']);
+ $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'];
+ switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
+ case 0x0000: // Unicode string
+ break;
+
+ case 0x0001: // BYTE array
+ // do nothing
+ break;
+
+ case 0x0002: // BOOL
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = (bool) getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
+ break;
+
+ case 0x0003: // DWORD
+ case 0x0004: // QWORD
+ case 0x0005: // WORD
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
+ break;
+
+ default:
+ $info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')';
+ //return false;
+ break;
+ }
+ switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) {
+
+ case 'wm/albumartist':
+ case 'artist':
+ // Note: not 'artist', that comes from 'author' tag
+ $thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
+ case 'wm/albumtitle':
+ case 'album':
+ $thisfile_asf_comments['album'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
+ case 'wm/genre':
+ case 'genre':
+ $thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
+ case 'wm/partofset':
+ $thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
+ case 'wm/tracknumber':
+ case 'tracknumber':
+ // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character)
+ $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ foreach ($thisfile_asf_comments['track'] as $key => $value) {
+ if (preg_match('/^[0-9\x00]+$/', $value)) {
+ $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value));
+ }
+ }
+ break;
+
+ case 'wm/track':
+ if (empty($thisfile_asf_comments['track'])) {
+ $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ }
+ break;
+
+ case 'wm/year':
+ case 'year':
+ case 'date':
+ $thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
+ case 'wm/lyrics':
+ case 'lyrics':
+ $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ break;
+
+ case 'isvbr':
+ if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) {
+ $thisfile_audio['bitrate_mode'] = 'vbr';
+ $thisfile_video['bitrate_mode'] = 'vbr';
+ }
+ break;
+
+ case 'id3':
+ // id3v2 module might not be loaded
+ if (class_exists('getid3_id3v2')) {
+ $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
+ $tempfilehandle = fopen($tempfile, 'wb');
+ $tempThisfileInfo = array('encoding'=>$info['encoding']);
+ fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
+ fclose($tempfilehandle);
+
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($tempfile);
+ $getid3_id3v2 = new getid3_id3v2($getid3_temp);
+ $getid3_id3v2->Analyze();
+ $info['id3v2'] = $getid3_temp->info['id3v2'];
+ unset($getid3_temp, $getid3_id3v2);
+
+ unlink($tempfile);
+ }
+ break;
+
+ case 'wm/encodingtime':
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
+ $thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']);
+ break;
+
+ case 'wm/picture':
+ $WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
+ foreach ($WMpicture as $key => $value) {
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value;
+ }
+ unset($WMpicture);
+/*
+ $wm_picture_offset = 0;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1));
+ $wm_picture_offset += 1;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type'] = $this->WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']);
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4));
+ $wm_picture_offset += 4;
+
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
+ do {
+ $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2);
+ $wm_picture_offset += 2;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] .= $next_byte_pair;
+ } while ($next_byte_pair !== "\x00\x00");
+
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] = '';
+ do {
+ $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2);
+ $wm_picture_offset += 2;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] .= $next_byte_pair;
+ } while ($next_byte_pair !== "\x00\x00");
+
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['dataoffset'] = $wm_picture_offset;
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'] = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset);
+ unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']);
+
+ $imageinfo = array();
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = '';
+ $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo);
+ unset($imageinfo);
+ if (!empty($imagechunkcheck)) {
+ $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
+ }
+ if (!isset($thisfile_asf_comments['picture'])) {
+ $thisfile_asf_comments['picture'] = array();
+ }
+ $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']);
+*/
+ break;
+
+ default:
+ switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) {
+ case 0: // Unicode string
+ if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') {
+ $thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']));
+ }
+ break;
+
+ case 1:
+ break;
+ }
+ break;
+ }
+
+ }
+ break;
+
+ case GETID3_ASF_Stream_Bitrate_Properties_Object:
+ // Stream Bitrate Properties Object: (optional, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Stream Bitrate Properties object - GETID3_ASF_Stream_Bitrate_Properties_Object
+ // Object Size QWORD 64 // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header
+ // Bitrate Records Count WORD 16 // number of records in Bitrate Records
+ // Bitrate Records array of: variable //
+ // * Flags WORD 16 //
+ // * * Stream Number bits 7 (0x007F) // number of this stream
+ // * * Reserved bits 9 (0xFF80) // hardcoded: 0
+ // * Average Bitrate DWORD 32 // in bits per second
+
+ // shortcut
+ $thisfile_asf['stream_bitrate_properties_object'] = array();
+ $thisfile_asf_streambitratepropertiesobject = &$thisfile_asf['stream_bitrate_properties_object'];
+
+ $thisfile_asf_streambitratepropertiesobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_streambitratepropertiesobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_streambitratepropertiesobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) {
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F;
+ $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4));
+ $offset += 4;
+ }
+ break;
+
+ case GETID3_ASF_Padding_Object:
+ // Padding Object: (optional)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Padding object - GETID3_ASF_Padding_Object
+ // Object Size QWORD 64 // size of Padding object, including 24 bytes of ASF Padding Object header
+ // Padding Data BYTESTREAM variable // ignore
+
+ // shortcut
+ $thisfile_asf['padding_object'] = array();
+ $thisfile_asf_paddingobject = &$thisfile_asf['padding_object'];
+
+ $thisfile_asf_paddingobject['offset'] = $NextObjectOffset + $offset;
+ $thisfile_asf_paddingobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_paddingobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_paddingobject['objectsize'] = $NextObjectSize;
+ $thisfile_asf_paddingobject['padding_length'] = $thisfile_asf_paddingobject['objectsize'] - 16 - 8;
+ $thisfile_asf_paddingobject['padding'] = substr($ASFHeaderData, $offset, $thisfile_asf_paddingobject['padding_length']);
+ $offset += ($NextObjectSize - 16 - 8);
+ break;
+
+ case GETID3_ASF_Extended_Content_Encryption_Object:
+ case GETID3_ASF_Content_Encryption_Object:
+ // WMA DRM - just ignore
+ $offset += ($NextObjectSize - 16 - 8);
+ break;
+
+ default:
+ // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
+ if ($this->GUIDname($NextObjectGUIDtext)) {
+ $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
+ } else {
+ $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8);
+ }
+ $offset += ($NextObjectSize - 16 - 8);
+ break;
+ }
+ }
+ if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) {
+ $ASFbitrateAudio = 0;
+ $ASFbitrateVideo = 0;
+ for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) {
+ if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) {
+ switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) {
+ case 1:
+ $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
+ break;
+
+ case 2:
+ $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate'];
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+ if ($ASFbitrateAudio > 0) {
+ $thisfile_audio['bitrate'] = $ASFbitrateAudio;
+ }
+ if ($ASFbitrateVideo > 0) {
+ $thisfile_video['bitrate'] = $ASFbitrateVideo;
+ }
+ }
+ if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) {
+
+ $thisfile_audio['bitrate'] = 0;
+ $thisfile_video['bitrate'] = 0;
+
+ foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) {
+
+ switch ($streamdata['stream_type']) {
+ case GETID3_ASF_Audio_Media:
+ // Field Name Field Type Size (bits)
+ // Codec ID / Format Tag WORD 16 // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure
+ // Number of Channels WORD 16 // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure
+ // Samples Per Second DWORD 32 // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure
+ // Average number of Bytes/sec DWORD 32 // bytes/sec of audio stream - defined as nAvgBytesPerSec field of WAVEFORMATEX structure
+ // Block Alignment WORD 16 // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure
+ // Bits per sample WORD 16 // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure
+ // Codec Specific Data Size WORD 16 // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure
+ // Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes
+
+ // shortcut
+ $thisfile_asf['audio_media'][$streamnumber] = array();
+ $thisfile_asf_audiomedia_currentstream = &$thisfile_asf['audio_media'][$streamnumber];
+
+ $audiomediaoffset = 0;
+
+ $thisfile_asf_audiomedia_currentstream = getid3_riff::parseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16));
+ $audiomediaoffset += 16;
+
+ $thisfile_audio['lossless'] = false;
+ switch ($thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']) {
+ case 0x0001: // PCM
+ case 0x0163: // WMA9 Lossless
+ $thisfile_audio['lossless'] = true;
+ break;
+ }
+
+ if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
+ foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
+ if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) {
+ $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate'];
+ $thisfile_audio['bitrate'] += $dataarray['bitrate'];
+ break;
+ }
+ }
+ } else {
+ if (!empty($thisfile_asf_audiomedia_currentstream['bytes_sec'])) {
+ $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8;
+ } elseif (!empty($thisfile_asf_audiomedia_currentstream['bitrate'])) {
+ $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate'];
+ }
+ }
+ $thisfile_audio['streams'][$streamnumber] = $thisfile_asf_audiomedia_currentstream;
+ $thisfile_audio['streams'][$streamnumber]['wformattag'] = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag'];
+ $thisfile_audio['streams'][$streamnumber]['lossless'] = $thisfile_audio['lossless'];
+ $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
+ $thisfile_audio['streams'][$streamnumber]['dataformat'] = 'wma';
+ unset($thisfile_audio['streams'][$streamnumber]['raw']);
+
+ $thisfile_asf_audiomedia_currentstream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2));
+ $audiomediaoffset += 2;
+ $thisfile_asf_audiomedia_currentstream['codec_data'] = substr($streamdata['type_specific_data'], $audiomediaoffset, $thisfile_asf_audiomedia_currentstream['codec_data_size']);
+ $audiomediaoffset += $thisfile_asf_audiomedia_currentstream['codec_data_size'];
+
+ break;
+
+ case GETID3_ASF_Video_Media:
+ // Field Name Field Type Size (bits)
+ // Encoded Image Width DWORD 32 // width of image in pixels
+ // Encoded Image Height DWORD 32 // height of image in pixels
+ // Reserved Flags BYTE 8 // hardcoded: 0x02
+ // Format Data Size WORD 16 // size of Format Data field in bytes
+ // Format Data array of: variable //
+ // * Format Data Size DWORD 32 // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure
+ // * Image Width LONG 32 // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure
+ // * Image Height LONG 32 // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure
+ // * Reserved WORD 16 // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure
+ // * Bits Per Pixel Count WORD 16 // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure
+ // * Compression ID FOURCC 32 // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure
+ // * Image Size DWORD 32 // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure
+ // * Horizontal Pixels / Meter DWORD 32 // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure
+ // * Vertical Pixels / Meter DWORD 32 // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure
+ // * Colors Used Count DWORD 32 // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure
+ // * Important Colors Count DWORD 32 // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure
+ // * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes
+
+ // shortcut
+ $thisfile_asf['video_media'][$streamnumber] = array();
+ $thisfile_asf_videomedia_currentstream = &$thisfile_asf['video_media'][$streamnumber];
+
+ $videomediaoffset = 0;
+ $thisfile_asf_videomedia_currentstream['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['flags'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1));
+ $videomediaoffset += 1;
+ $thisfile_asf_videomedia_currentstream['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
+ $videomediaoffset += 2;
+ $thisfile_asf_videomedia_currentstream['format_data']['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['reserved'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
+ $videomediaoffset += 2;
+ $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2));
+ $videomediaoffset += 2;
+ $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'] = substr($streamdata['type_specific_data'], $videomediaoffset, 4);
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['image_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['horizontal_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['vertical_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['colors_used'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['colors_important'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4));
+ $videomediaoffset += 4;
+ $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset);
+
+ if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) {
+ foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) {
+ if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) {
+ $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate'];
+ $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate'];
+ $thisfile_video['bitrate'] += $dataarray['bitrate'];
+ break;
+ }
+ }
+ }
+
+ $thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::fourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']);
+
+ $thisfile_video['streams'][$streamnumber]['fourcc'] = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'];
+ $thisfile_video['streams'][$streamnumber]['codec'] = $thisfile_asf_videomedia_currentstream['format_data']['codec'];
+ $thisfile_video['streams'][$streamnumber]['resolution_x'] = $thisfile_asf_videomedia_currentstream['image_width'];
+ $thisfile_video['streams'][$streamnumber]['resolution_y'] = $thisfile_asf_videomedia_currentstream['image_height'];
+ $thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'];
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ while (ftell($this->getid3->fp) < $info['avdataend']) {
+ $NextObjectDataHeader = fread($this->getid3->fp, 24);
+ $offset = 0;
+ $NextObjectGUID = substr($NextObjectDataHeader, 0, 16);
+ $offset += 16;
+ $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID);
+ $NextObjectSize = getid3_lib::LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8));
+ $offset += 8;
+
+ switch ($NextObjectGUID) {
+ case GETID3_ASF_Data_Object:
+ // Data Object: (mandatory, one only)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Data object - GETID3_ASF_Data_Object
+ // Object Size QWORD 64 // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1
+ // File ID GUID 128 // unique identifier. identical to File ID field in Header Object
+ // Total Data Packets QWORD 64 // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1
+ // Reserved WORD 16 // hardcoded: 0x0101
+
+ // shortcut
+ $thisfile_asf['data_object'] = array();
+ $thisfile_asf_dataobject = &$thisfile_asf['data_object'];
+
+ $DataObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 50 - 24);
+ $offset = 24;
+
+ $thisfile_asf_dataobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_dataobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_dataobject['objectsize'] = $NextObjectSize;
+
+ $thisfile_asf_dataobject['fileid'] = substr($DataObjectData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_dataobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_dataobject['fileid']);
+ $thisfile_asf_dataobject['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2));
+ $offset += 2;
+ if ($thisfile_asf_dataobject['reserved'] != 0x0101) {
+ $info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"';
+ //return false;
+ break;
+ }
+
+ // Data Packets array of: variable //
+ // * Error Correction Flags BYTE 8 //
+ // * * Error Correction Data Length bits 4 // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000
+ // * * Opaque Data Present bits 1 //
+ // * * Error Correction Length Type bits 2 // number of bits for size of the error correction data. hardcoded: 00
+ // * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure
+ // * Error Correction Data
+
+ $info['avdataoffset'] = ftell($this->getid3->fp);
+ fseek($this->getid3->fp, ($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data
+ $info['avdataend'] = ftell($this->getid3->fp);
+ break;
+
+ case GETID3_ASF_Simple_Index_Object:
+ // Simple Index Object: (optional, recommended, one per video stream)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for Simple Index object - GETID3_ASF_Data_Object
+ // Object Size QWORD 64 // size of Simple Index object, including 56 bytes of Simple Index Object header
+ // File ID GUID 128 // unique identifier. may be zero or identical to File ID field in Data Object and Header Object
+ // Index Entry Time Interval QWORD 64 // interval between index entries in 100-nanosecond units
+ // Maximum Packet Count DWORD 32 // maximum packet count for all index entries
+ // Index Entries Count DWORD 32 // number of Index Entries structures
+ // Index Entries array of: variable //
+ // * Packet Number DWORD 32 // number of the Data Packet associated with this index entry
+ // * Packet Count WORD 16 // number of Data Packets to sent at this index entry
+
+ // shortcut
+ $thisfile_asf['simple_index_object'] = array();
+ $thisfile_asf_simpleindexobject = &$thisfile_asf['simple_index_object'];
+
+ $SimpleIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 56 - 24);
+ $offset = 24;
+
+ $thisfile_asf_simpleindexobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_simpleindexobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_simpleindexobject['objectsize'] = $NextObjectSize;
+
+ $thisfile_asf_simpleindexobject['fileid'] = substr($SimpleIndexObjectData, $offset, 16);
+ $offset += 16;
+ $thisfile_asf_simpleindexobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_simpleindexobject['fileid']);
+ $thisfile_asf_simpleindexobject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8));
+ $offset += 8;
+ $thisfile_asf_simpleindexobject['maximum_packet_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_simpleindexobject['index_entries_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4));
+ $offset += 4;
+
+ $IndexEntriesData = $SimpleIndexObjectData.fread($this->getid3->fp, 6 * $thisfile_asf_simpleindexobject['index_entries_count']);
+ for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) {
+ $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4));
+ $offset += 2;
+ }
+
+ break;
+
+ case GETID3_ASF_Index_Object:
+ // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1)
+ // Field Name Field Type Size (bits)
+ // Object ID GUID 128 // GUID for the Index Object - GETID3_ASF_Index_Object
+ // Object Size QWORD 64 // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header
+ // Index Entry Time Interval DWORD 32 // Specifies the time interval between each index entry in ms.
+ // Index Specifiers Count WORD 16 // Specifies the number of Index Specifiers structures in this Index Object.
+ // Index Blocks Count DWORD 32 // Specifies the number of Index Blocks structures in this Index Object.
+
+ // Index Entry Time Interval DWORD 32 // Specifies the time interval between index entries in milliseconds. This value cannot be 0.
+ // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater.
+ // Index Specifiers array of: varies //
+ // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127.
+ // * Index Type WORD 16 // Specifies Index Type values as follows:
+ // 1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time.
+ // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object.
+ // 3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set.
+ // Nearest Past Cleanpoint is the most common type of index.
+ // Index Entry Count DWORD 32 // Specifies the number of Index Entries in the block.
+ // * Block Positions QWORD varies // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed.
+ // * Index Entries array of: varies //
+ // * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value
+
+ // shortcut
+ $thisfile_asf['asf_index_object'] = array();
+ $thisfile_asf_asfindexobject = &$thisfile_asf['asf_index_object'];
+
+ $ASFIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 34 - 24);
+ $offset = 24;
+
+ $thisfile_asf_asfindexobject['objectid'] = $NextObjectGUID;
+ $thisfile_asf_asfindexobject['objectid_guid'] = $NextObjectGUIDtext;
+ $thisfile_asf_asfindexobject['objectsize'] = $NextObjectSize;
+
+ $thisfile_asf_asfindexobject['entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
+ $offset += 4;
+ $thisfile_asf_asfindexobject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_asfindexobject['index_blocks_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
+ $offset += 4;
+
+ $ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count']);
+ for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
+ $IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber;
+ $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2));
+ $offset += 2;
+ $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']);
+ }
+
+ $ASFIndexObjectData .= fread($this->getid3->fp, 4);
+ $thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
+ $offset += 4;
+
+ $ASFIndexObjectData .= fread($this->getid3->fp, 8 * $thisfile_asf_asfindexobject['index_specifiers_count']);
+ for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
+ $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8));
+ $offset += 8;
+ }
+
+ $ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']);
+ for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) {
+ for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) {
+ $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4));
+ $offset += 4;
+ }
+ }
+ break;
+
+
+ default:
+ // Implementations shall ignore any standard or non-standard object that they do not know how to handle.
+ if ($this->GUIDname($NextObjectGUIDtext)) {
+ $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8);
+ } else {
+ $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.(ftell($this->getid3->fp) - 16 - 8);
+ }
+ fseek($this->getid3->fp, ($NextObjectSize - 16 - 8), SEEK_CUR);
+ break;
+ }
+ }
+
+ if (isset($thisfile_asf_codeclistobject['codec_entries']) && is_array($thisfile_asf_codeclistobject['codec_entries'])) {
+ foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
+ switch ($streamdata['information']) {
+ case 'WMV1':
+ case 'WMV2':
+ case 'WMV3':
+ case 'MSS1':
+ case 'MSS2':
+ case 'WMVA':
+ case 'WVC1':
+ case 'WMVP':
+ case 'WVP2':
+ $thisfile_video['dataformat'] = 'wmv';
+ $info['mime_type'] = 'video/x-ms-wmv';
+ break;
+
+ case 'MP42':
+ case 'MP43':
+ case 'MP4S':
+ case 'mp4s':
+ $thisfile_video['dataformat'] = 'asf';
+ $info['mime_type'] = 'video/x-ms-asf';
+ break;
+
+ default:
+ switch ($streamdata['type_raw']) {
+ case 1:
+ if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) {
+ $thisfile_video['dataformat'] = 'wmv';
+ if ($info['mime_type'] == 'video/x-ms-asf') {
+ $info['mime_type'] = 'video/x-ms-wmv';
+ }
+ }
+ break;
+
+ case 2:
+ if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) {
+ $thisfile_audio['dataformat'] = 'wma';
+ if ($info['mime_type'] == 'video/x-ms-asf') {
+ $info['mime_type'] = 'audio/x-ms-wma';
+ }
+ }
+ break;
+
+ }
+ break;
+ }
+ }
+ }
+
+ switch (isset($thisfile_audio['codec']) ? $thisfile_audio['codec'] : '') {
+ case 'MPEG Layer-3':
+ $thisfile_audio['dataformat'] = 'mp3';
+ break;
+
+ default:
+ break;
+ }
+
+ if (isset($thisfile_asf_codeclistobject['codec_entries'])) {
+ foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) {
+ switch ($streamdata['type_raw']) {
+
+ case 1: // video
+ $thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
+ break;
+
+ case 2: // audio
+ $thisfile_audio['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']);
+
+ // AH 2003-10-01
+ $thisfile_audio['encoder_options'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][0]['description']);
+
+ $thisfile_audio['codec'] = $thisfile_audio['encoder'];
+ break;
+
+ default:
+ $info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw'];
+ break;
+
+ }
+ }
+ }
+
+ if (isset($info['audio'])) {
+ $thisfile_audio['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false);
+ $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf');
+ }
+ if (!empty($thisfile_video['dataformat'])) {
+ $thisfile_video['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false);
+ $thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1);
+ $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf');
+ }
+ if (!empty($thisfile_video['streams'])) {
+ $thisfile_video['streams']['resolution_x'] = 0;
+ $thisfile_video['streams']['resolution_y'] = 0;
+ foreach ($thisfile_video['streams'] as $key => $valuearray) {
+ if (($valuearray['resolution_x'] > $thisfile_video['streams']['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['streams']['resolution_y'])) {
+ $thisfile_video['resolution_x'] = $valuearray['resolution_x'];
+ $thisfile_video['resolution_y'] = $valuearray['resolution_y'];
+ }
+ }
+ }
+ $info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0);
+
+ if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) {
+ $info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8);
+ }
+
+ return true;
+ }
+
+ public static function ASFCodecListObjectTypeLookup($CodecListType) {
+ static $ASFCodecListObjectTypeLookup = array();
+ if (empty($ASFCodecListObjectTypeLookup)) {
+ $ASFCodecListObjectTypeLookup[0x0001] = 'Video Codec';
+ $ASFCodecListObjectTypeLookup[0x0002] = 'Audio Codec';
+ $ASFCodecListObjectTypeLookup[0xFFFF] = 'Unknown Codec';
+ }
+
+ return (isset($ASFCodecListObjectTypeLookup[$CodecListType]) ? $ASFCodecListObjectTypeLookup[$CodecListType] : 'Invalid Codec Type');
+ }
+
+ public static function KnownGUIDs() {
+ static $GUIDarray = array(
+ 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A',
+ 'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8',
+ 'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8',
+ 'GETID3_ASF_Script_Command_Object' => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6',
+ 'GETID3_ASF_No_Error_Correction' => '20FB5700-5B55-11CF-A8FD-00805F5C442B',
+ 'GETID3_ASF_Content_Branding_Object' => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E',
+ 'GETID3_ASF_Content_Encryption_Object' => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E',
+ 'GETID3_ASF_Digital_Signature_Object' => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E',
+ 'GETID3_ASF_Extended_Content_Encryption_Object' => '298AE614-2622-4C17-B935-DAE07EE9289C',
+ 'GETID3_ASF_Simple_Index_Object' => '33000890-E5B1-11CF-89F4-00A0C90349CB',
+ 'GETID3_ASF_Degradable_JPEG_Media' => '35907DE0-E415-11CF-A917-00805F5C442B',
+ 'GETID3_ASF_Payload_Extension_System_Timecode' => '399595EC-8667-4E2D-8FDB-98814CE76C1E',
+ 'GETID3_ASF_Binary_Media' => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343',
+ 'GETID3_ASF_Timecode_Index_Object' => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C',
+ 'GETID3_ASF_Metadata_Library_Object' => '44231C94-9498-49D1-A141-1D134E457054',
+ 'GETID3_ASF_Reserved_3' => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6',
+ 'GETID3_ASF_Reserved_4' => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB',
+ 'GETID3_ASF_Command_Media' => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6',
+ 'GETID3_ASF_Header_Extension_Object' => '5FBF03B5-A92E-11CF-8EE3-00C00C205365',
+ 'GETID3_ASF_Media_Object_Index_Parameters_Obj' => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7',
+ 'GETID3_ASF_Header_Object' => '75B22630-668E-11CF-A6D9-00AA0062CE6C',
+ 'GETID3_ASF_Content_Description_Object' => '75B22633-668E-11CF-A6D9-00AA0062CE6C',
+ 'GETID3_ASF_Error_Correction_Object' => '75B22635-668E-11CF-A6D9-00AA0062CE6C',
+ 'GETID3_ASF_Data_Object' => '75B22636-668E-11CF-A6D9-00AA0062CE6C',
+ 'GETID3_ASF_Web_Stream_Media_Subtype' => '776257D4-C627-41CB-8F81-7AC7FF1C40CC',
+ 'GETID3_ASF_Stream_Bitrate_Properties_Object' => '7BF875CE-468D-11D1-8D82-006097C9A2B2',
+ 'GETID3_ASF_Language_List_Object' => '7C4346A9-EFE0-4BFC-B229-393EDE415C85',
+ 'GETID3_ASF_Codec_List_Object' => '86D15240-311D-11D0-A3A4-00A0C90348F6',
+ 'GETID3_ASF_Reserved_2' => '86D15241-311D-11D0-A3A4-00A0C90348F6',
+ 'GETID3_ASF_File_Properties_Object' => '8CABDCA1-A947-11CF-8EE4-00C00C205365',
+ 'GETID3_ASF_File_Transfer_Media' => '91BD222C-F21C-497A-8B6D-5AA86BFC0185',
+ 'GETID3_ASF_Old_RTP_Extension_Data' => '96800C63-4C94-11D1-837B-0080C7A37F95',
+ 'GETID3_ASF_Advanced_Mutual_Exclusion_Object' => 'A08649CF-4775-4670-8A16-6E35357566CD',
+ 'GETID3_ASF_Bandwidth_Sharing_Object' => 'A69609E6-517B-11D2-B6AF-00C04FD908E9',
+ 'GETID3_ASF_Reserved_1' => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365',
+ 'GETID3_ASF_Bandwidth_Sharing_Exclusive' => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9',
+ 'GETID3_ASF_Bandwidth_Sharing_Partial' => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9',
+ 'GETID3_ASF_JFIF_Media' => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B',
+ 'GETID3_ASF_Stream_Properties_Object' => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365',
+ 'GETID3_ASF_Video_Media' => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B',
+ 'GETID3_ASF_Audio_Spread' => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220',
+ 'GETID3_ASF_Metadata_Object' => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA',
+ 'GETID3_ASF_Payload_Ext_Syst_Sample_Duration' => 'C6BD9450-867F-4907-83A3-C77921B733AD',
+ 'GETID3_ASF_Group_Mutual_Exclusion_Object' => 'D1465A40-5A79-4338-B71B-E36B8FD6C249',
+ 'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850',
+ 'GETID3_ASF_Stream_Prioritization_Object' => 'D4FED15B-88D3-454F-81F0-ED5C45999E24',
+ 'GETID3_ASF_Payload_Ext_System_Content_Type' => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC',
+ 'GETID3_ASF_Old_File_Properties_Object' => 'D6E229D0-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_ASF_Header_Object' => 'D6E229D1-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_ASF_Data_Object' => 'D6E229D2-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Index_Object' => 'D6E229D3-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Stream_Properties_Object' => 'D6E229D4-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Content_Description_Object' => 'D6E229D5-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Script_Command_Object' => 'D6E229D6-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Marker_Object' => 'D6E229D7-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Component_Download_Object' => 'D6E229D8-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Stream_Group_Object' => 'D6E229D9-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Scalable_Object' => 'D6E229DA-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Prioritization_Object' => 'D6E229DB-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Bitrate_Mutual_Exclusion_Object' => 'D6E229DC-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Inter_Media_Dependency_Object' => 'D6E229DD-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Rating_Object' => 'D6E229DE-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Index_Parameters_Object' => 'D6E229DF-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Color_Table_Object' => 'D6E229E0-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Language_List_Object' => 'D6E229E1-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Audio_Media' => 'D6E229E2-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Video_Media' => 'D6E229E3-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Image_Media' => 'D6E229E4-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Timecode_Media' => 'D6E229E5-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Text_Media' => 'D6E229E6-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_MIDI_Media' => 'D6E229E7-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Command_Media' => 'D6E229E8-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_No_Error_Concealment' => 'D6E229EA-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Scrambled_Audio' => 'D6E229EB-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_No_Color_Table' => 'D6E229EC-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_SMPTE_Time' => 'D6E229ED-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_ASCII_Text' => 'D6E229EE-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Unicode_Text' => 'D6E229EF-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_HTML_Text' => 'D6E229F0-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_URL_Command' => 'D6E229F1-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Filename_Command' => 'D6E229F2-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_ACM_Codec' => 'D6E229F3-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_VCM_Codec' => 'D6E229F4-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_QuickTime_Codec' => 'D6E229F5-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_DirectShow_Transform_Filter' => 'D6E229F6-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_DirectShow_Rendering_Filter' => 'D6E229F7-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_No_Enhancement' => 'D6E229F8-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Unknown_Enhancement_Type' => 'D6E229F9-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Temporal_Enhancement' => 'D6E229FA-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Spatial_Enhancement' => 'D6E229FB-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Quality_Enhancement' => 'D6E229FC-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Number_of_Channels_Enhancement' => 'D6E229FD-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Frequency_Response_Enhancement' => 'D6E229FE-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Media_Object' => 'D6E229FF-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Mutex_Language' => 'D6E22A00-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Mutex_Bitrate' => 'D6E22A01-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Mutex_Unknown' => 'D6E22A02-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_ASF_Placeholder_Object' => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Old_Data_Unit_Extension_Object' => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE',
+ 'GETID3_ASF_Web_Stream_Format' => 'DA1E6B13-8359-4050-B398-388E965BF00C',
+ 'GETID3_ASF_Payload_Ext_System_File_Name' => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B',
+ 'GETID3_ASF_Marker_Object' => 'F487CD01-A951-11CF-8EE6-00C00C205365',
+ 'GETID3_ASF_Timecode_Index_Parameters_Object' => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24',
+ 'GETID3_ASF_Audio_Media' => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B',
+ 'GETID3_ASF_Media_Object_Index_Object' => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C',
+ 'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE',
+ 'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
+ 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html
+ );
+ return $GUIDarray;
+ }
+
+ public static function GUIDname($GUIDstring) {
+ static $GUIDarray = array();
+ if (empty($GUIDarray)) {
+ $GUIDarray = self::KnownGUIDs();
+ }
+ return array_search($GUIDstring, $GUIDarray);
+ }
+
+ public static function ASFIndexObjectIndexTypeLookup($id) {
+ static $ASFIndexObjectIndexTypeLookup = array();
+ if (empty($ASFIndexObjectIndexTypeLookup)) {
+ $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet';
+ $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object';
+ $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint';
+ }
+ return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid');
+ }
+
+ public static function GUIDtoBytestring($GUIDstring) {
+ // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
+ // first 4 bytes are in little-endian order
+ // next 2 bytes are appended in little-endian order
+ // next 2 bytes are appended in little-endian order
+ // next 2 bytes are appended in big-endian order
+ // next 6 bytes are appended in big-endian order
+
+ // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string:
+ // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp
+
+ $hexbytecharstring = chr(hexdec(substr($GUIDstring, 6, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 4, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 2, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 0, 2)));
+
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 9, 2)));
+
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2)));
+
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2)));
+
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2)));
+ $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2)));
+
+ return $hexbytecharstring;
+ }
+
+ public static function BytestringToGUID($Bytestring) {
+ $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= '-';
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= '-';
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= '-';
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= '-';
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
+ $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
+
+ return strtoupper($GUIDstring);
+ }
+
+ public static function FILETIMEtoUNIXtime($FILETIME, $round=true) {
+ // FILETIME is a 64-bit unsigned integer representing
+ // the number of 100-nanosecond intervals since January 1, 1601
+ // UNIX timestamp is number of seconds since January 1, 1970
+ // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days
+ if ($round) {
+ return intval(round(($FILETIME - 116444736000000000) / 10000000));
+ }
+ return ($FILETIME - 116444736000000000) / 10000000;
+ }
+
+ public static function WMpictureTypeLookup($WMpictureType) {
+ static $WMpictureTypeLookup = array();
+ if (empty($WMpictureTypeLookup)) {
+ $WMpictureTypeLookup[0x03] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Front Cover');
+ $WMpictureTypeLookup[0x04] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Back Cover');
+ $WMpictureTypeLookup[0x00] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'User Defined');
+ $WMpictureTypeLookup[0x05] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Leaflet Page');
+ $WMpictureTypeLookup[0x06] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Media Label');
+ $WMpictureTypeLookup[0x07] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lead Artist');
+ $WMpictureTypeLookup[0x08] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Artist');
+ $WMpictureTypeLookup[0x09] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Conductor');
+ $WMpictureTypeLookup[0x0A] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band');
+ $WMpictureTypeLookup[0x0B] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Composer');
+ $WMpictureTypeLookup[0x0C] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lyricist');
+ $WMpictureTypeLookup[0x0D] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Recording Location');
+ $WMpictureTypeLookup[0x0E] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Recording');
+ $WMpictureTypeLookup[0x0F] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Performance');
+ $WMpictureTypeLookup[0x10] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Video Screen Capture');
+ $WMpictureTypeLookup[0x12] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Illustration');
+ $WMpictureTypeLookup[0x13] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band Logotype');
+ $WMpictureTypeLookup[0x14] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Publisher Logotype');
+ }
+ return (isset($WMpictureTypeLookup[$WMpictureType]) ? $WMpictureTypeLookup[$WMpictureType] : '');
+ }
+
+ public function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) {
+ // http://msdn.microsoft.com/en-us/library/bb643323.aspx
+
+ $offset = 0;
+ $objectOffset = 0;
+ $HeaderExtensionObjectParsed = array();
+ while ($objectOffset < strlen($asf_header_extension_object_data)) {
+ $offset = $objectOffset;
+ $thisObject = array();
+
+ $thisObject['guid'] = substr($asf_header_extension_object_data, $offset, 16);
+ $offset += 16;
+ $thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']);
+ $thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']);
+
+ $thisObject['size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8));
+ $offset += 8;
+ if ($thisObject['size'] <= 0) {
+ break;
+ }
+
+ switch ($thisObject['guid']) {
+ case GETID3_ASF_Extended_Stream_Properties_Object:
+ $thisObject['start_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8));
+ $offset += 8;
+ $thisObject['start_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['start_time']);
+
+ $thisObject['end_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8));
+ $offset += 8;
+ $thisObject['end_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['end_time']);
+
+ $thisObject['data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['alternate_data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['alternate_buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['maximum_object_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+ $thisObject['flags']['reliable'] = (bool) $thisObject['flags_raw'] & 0x00000001;
+ $thisObject['flags']['seekable'] = (bool) $thisObject['flags_raw'] & 0x00000002;
+ $thisObject['flags']['no_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000004;
+ $thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008;
+
+ $thisObject['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $thisObject['stream_language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $thisObject['average_time_per_frame'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $thisObject['stream_name_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $thisObject['payload_extension_system_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ for ($i = 0; $i < $thisObject['stream_name_count']; $i++) {
+ $streamName = array();
+
+ $streamName['language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $streamName['stream_name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $streamName['stream_name'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $streamName['stream_name_length']));
+ $offset += $streamName['stream_name_length'];
+
+ $thisObject['stream_names'][$i] = $streamName;
+ }
+
+ for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) {
+ $payloadExtensionSystem = array();
+
+ $payloadExtensionSystem['extension_system_id'] = substr($asf_header_extension_object_data, $offset, 16);
+ $offset += 16;
+ $payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']);
+
+ $payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+ if ($payloadExtensionSystem['extension_system_size'] <= 0) {
+ break 2;
+ }
+
+ $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $payloadExtensionSystem['extension_system_info_length']));
+ $offset += $payloadExtensionSystem['extension_system_info_length'];
+
+ $thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem;
+ }
+
+ break;
+
+ case GETID3_ASF_Padding_Object:
+ // padding, skip it
+ break;
+
+ case GETID3_ASF_Metadata_Object:
+ $thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ for ($i = 0; $i < $thisObject['description_record_counts']; $i++) {
+ $descriptionRecord = array();
+
+ $descriptionRecord['reserved_1'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); // must be zero
+ $offset += 2;
+
+ $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+ $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
+
+ $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']);
+ $offset += $descriptionRecord['name_length'];
+
+ $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']);
+ $offset += $descriptionRecord['data_length'];
+ switch ($descriptionRecord['data_type']) {
+ case 0x0000: // Unicode string
+ break;
+
+ case 0x0001: // BYTE array
+ // do nothing
+ break;
+
+ case 0x0002: // BOOL
+ $descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']);
+ break;
+
+ case 0x0003: // DWORD
+ case 0x0004: // QWORD
+ case 0x0005: // WORD
+ $descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']);
+ break;
+
+ case 0x0006: // GUID
+ $descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']);
+ break;
+ }
+
+ $thisObject['description_record'][$i] = $descriptionRecord;
+ }
+ break;
+
+ case GETID3_ASF_Language_List_Object:
+ $thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) {
+ $languageIDrecord = array();
+
+ $languageIDrecord['language_id_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1));
+ $offset += 1;
+
+ $languageIDrecord['language_id'] = substr($asf_header_extension_object_data, $offset, $languageIDrecord['language_id_length']);
+ $offset += $languageIDrecord['language_id_length'];
+
+ $thisObject['language_id_record'][$i] = $languageIDrecord;
+ }
+ break;
+
+ case GETID3_ASF_Metadata_Library_Object:
+ $thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ for ($i = 0; $i < $thisObject['description_records_count']; $i++) {
+ $descriptionRecord = array();
+
+ $descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+
+ $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2));
+ $offset += 2;
+ $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']);
+
+ $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4));
+ $offset += 4;
+
+ $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']);
+ $offset += $descriptionRecord['name_length'];
+
+ $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']);
+ $offset += $descriptionRecord['data_length'];
+
+ if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) {
+ $WMpicture = $this->ASF_WMpicture($descriptionRecord['data']);
+ foreach ($WMpicture as $key => $value) {
+ $descriptionRecord['data'] = $WMpicture;
+ }
+ unset($WMpicture);
+ }
+
+ $thisObject['description_record'][$i] = $descriptionRecord;
+ }
+ break;
+
+ default:
+ $unhandled_sections++;
+ if ($this->GUIDname($thisObject['guid_text'])) {
+ $this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8);
+ } else {
+ $this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8);
+ }
+ break;
+ }
+ $HeaderExtensionObjectParsed[] = $thisObject;
+
+ $objectOffset += $thisObject['size'];
+ }
+ return $HeaderExtensionObjectParsed;
+ }
+
+
+ public static function ASFmetadataLibraryObjectDataTypeLookup($id) {
+ static $ASFmetadataLibraryObjectDataTypeLookup = array(
+ 0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters
+ 0x0001 => 'BYTE array', // The type of the data is implementation-specific
+ 0x0002 => 'BOOL', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values
+ 0x0003 => 'DWORD', // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer
+ 0x0004 => 'QWORD', // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer
+ 0x0005 => 'WORD', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer
+ 0x0006 => 'GUID', // The data is 16 bytes long and should be interpreted as a 128-bit GUID
+ );
+ return (isset($ASFmetadataLibraryObjectDataTypeLookup[$id]) ? $ASFmetadataLibraryObjectDataTypeLookup[$id] : 'invalid');
+ }
+
+ public function ASF_WMpicture(&$data) {
+ //typedef struct _WMPicture{
+ // LPWSTR pwszMIMEType;
+ // BYTE bPictureType;
+ // LPWSTR pwszDescription;
+ // DWORD dwDataLen;
+ // BYTE* pbData;
+ //} WM_PICTURE;
+
+ $WMpicture = array();
+
+ $offset = 0;
+ $WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1));
+ $offset += 1;
+ $WMpicture['image_type'] = $this->WMpictureTypeLookup($WMpicture['image_type_id']);
+ $WMpicture['image_size'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 4));
+ $offset += 4;
+
+ $WMpicture['image_mime'] = '';
+ do {
+ $next_byte_pair = substr($data, $offset, 2);
+ $offset += 2;
+ $WMpicture['image_mime'] .= $next_byte_pair;
+ } while ($next_byte_pair !== "\x00\x00");
+
+ $WMpicture['image_description'] = '';
+ do {
+ $next_byte_pair = substr($data, $offset, 2);
+ $offset += 2;
+ $WMpicture['image_description'] .= $next_byte_pair;
+ } while ($next_byte_pair !== "\x00\x00");
+
+ $WMpicture['dataoffset'] = $offset;
+ $WMpicture['data'] = substr($data, $offset);
+
+ $imageinfo = array();
+ $WMpicture['image_mime'] = '';
+ $imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo);
+ unset($imageinfo);
+ if (!empty($imagechunkcheck)) {
+ $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
+ }
+ if (!isset($this->getid3->info['asf']['comments']['picture'])) {
+ $this->getid3->info['asf']['comments']['picture'] = array();
+ }
+ $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']);
+
+ return $WMpicture;
+ }
+
+
+ // Remove terminator 00 00 and convert UTF-16LE to Latin-1
+ public static function TrimConvert($string) {
+ return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' ');
+ }
+
+
+ // Remove terminator 00 00
+ public static function TrimTerm($string) {
+ // remove terminator, only if present (it should be, but...)
+ if (substr($string, -2) === "\x00\x00") {
+ $string = substr($string, 0, -2);
+ }
+ return $string;
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio-video.flv.php b/src/wp-includes/ID3/module.audio-video.flv.php
new file mode 100644
index 0000000000..f9c4cf3ea0
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio-video.flv.php
@@ -0,0 +1,729 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+// //
+// FLV module by Seth Kaufman <sethØwhirl-i-gig*com> //
+// //
+// * version 0.1 (26 June 2005) //
+// //
+// //
+// * version 0.1.1 (15 July 2005) //
+// minor modifications by James Heinrich <info@getid3.org> //
+// //
+// * version 0.2 (22 February 2006) //
+// Support for On2 VP6 codec and meta information //
+// by Steve Webster <steve.websterØfeaturecreep*com> //
+// //
+// * version 0.3 (15 June 2006) //
+// Modified to not read entire file into memory //
+// by James Heinrich <info@getid3.org> //
+// //
+// * version 0.4 (07 December 2007) //
+// Bugfixes for incorrectly parsed FLV dimensions //
+// and incorrect parsing of onMetaTag //
+// by Evgeny Moysevich <moysevichØgmail*com> //
+// //
+// * version 0.5 (21 May 2009) //
+// Fixed parsing of audio tags and added additional codec //
+// details. The duration is now read from onMetaTag (if //
+// exists), rather than parsing whole file //
+// by Nigel Barnes <ngbarnesØhotmail*com> //
+// //
+// * version 0.6 (24 May 2009) //
+// Better parsing of files with h264 video //
+// by Evgeny Moysevich <moysevichØgmail*com> //
+// //
+// * version 0.6.1 (30 May 2011) //
+// prevent infinite loops in expGolombUe() //
+// //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.flv.php //
+// module for analyzing Shockwave Flash Video files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+define('GETID3_FLV_TAG_AUDIO', 8);
+define('GETID3_FLV_TAG_VIDEO', 9);
+define('GETID3_FLV_TAG_META', 18);
+
+define('GETID3_FLV_VIDEO_H263', 2);
+define('GETID3_FLV_VIDEO_SCREEN', 3);
+define('GETID3_FLV_VIDEO_VP6FLV', 4);
+define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5);
+define('GETID3_FLV_VIDEO_SCREENV2', 6);
+define('GETID3_FLV_VIDEO_H264', 7);
+
+define('H264_AVC_SEQUENCE_HEADER', 0);
+define('H264_PROFILE_BASELINE', 66);
+define('H264_PROFILE_MAIN', 77);
+define('H264_PROFILE_EXTENDED', 88);
+define('H264_PROFILE_HIGH', 100);
+define('H264_PROFILE_HIGH10', 110);
+define('H264_PROFILE_HIGH422', 122);
+define('H264_PROFILE_HIGH444', 144);
+define('H264_PROFILE_HIGH444_PREDICTIVE', 244);
+
+class getid3_flv extends getid3_handler
+{
+ public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ $FLVdataLength = $info['avdataend'] - $info['avdataoffset'];
+ $FLVheader = fread($this->getid3->fp, 5);
+
+ $info['fileformat'] = 'flv';
+ $info['flv']['header']['signature'] = substr($FLVheader, 0, 3);
+ $info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1));
+ $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1));
+
+ $magic = 'FLV';
+ if ($info['flv']['header']['signature'] != $magic) {
+ $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"';
+ unset($info['flv']);
+ unset($info['fileformat']);
+ return false;
+ }
+
+ $info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04);
+ $info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01);
+
+ $FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4));
+ $FLVheaderFrameLength = 9;
+ if ($FrameSizeDataLength > $FLVheaderFrameLength) {
+ fseek($this->getid3->fp, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR);
+ }
+ $Duration = 0;
+ $found_video = false;
+ $found_audio = false;
+ $found_meta = false;
+ $found_valid_meta_playtime = false;
+ $tagParseCount = 0;
+ $info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0);
+ $flv_framecount = &$info['flv']['framecount'];
+ while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) {
+ $ThisTagHeader = fread($this->getid3->fp, 16);
+
+ $PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4));
+ $TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1));
+ $DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3));
+ $Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3));
+ $LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1));
+ $NextOffset = ftell($this->getid3->fp) - 1 + $DataLength;
+ if ($Timestamp > $Duration) {
+ $Duration = $Timestamp;
+ }
+
+ $flv_framecount['total']++;
+ switch ($TagType) {
+ case GETID3_FLV_TAG_AUDIO:
+ $flv_framecount['audio']++;
+ if (!$found_audio) {
+ $found_audio = true;
+ $info['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F;
+ $info['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03;
+ $info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01;
+ $info['flv']['audio']['audioType'] = $LastHeaderByte & 0x01;
+ }
+ break;
+
+ case GETID3_FLV_TAG_VIDEO:
+ $flv_framecount['video']++;
+ if (!$found_video) {
+ $found_video = true;
+ $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07;
+
+ $FLVvideoHeader = fread($this->getid3->fp, 11);
+
+ if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) {
+ // this code block contributed by: moysevichØgmail*com
+
+ $AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1));
+ if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) {
+ // read AVCDecoderConfigurationRecord
+ $configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1));
+ $AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1));
+ $profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1));
+ $lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1));
+ $numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1));
+
+ if (($numOfSequenceParameterSets & 0x1F) != 0) {
+ // there is at least one SequenceParameterSet
+ // read size of the first SequenceParameterSet
+ //$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2));
+ $spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2));
+ // read the first SequenceParameterSet
+ $sps = fread($this->getid3->fp, $spsSize);
+ if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red
+ $spsReader = new AVCSequenceParameterSetReader($sps);
+ $spsReader->readData();
+ $info['video']['resolution_x'] = $spsReader->getWidth();
+ $info['video']['resolution_y'] = $spsReader->getHeight();
+ }
+ }
+ }
+ // end: moysevichØgmail*com
+
+ } elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) {
+
+ $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7;
+ $PictureSizeType = $PictureSizeType & 0x0007;
+ $info['flv']['header']['videoSizeType'] = $PictureSizeType;
+ switch ($PictureSizeType) {
+ case 0:
+ //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
+ //$PictureSizeEnc <<= 1;
+ //$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8;
+ //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2));
+ //$PictureSizeEnc <<= 1;
+ //$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8;
+
+ $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2));
+ $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2));
+ $PictureSizeEnc['x'] >>= 7;
+ $PictureSizeEnc['y'] >>= 7;
+ $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF;
+ $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF;
+ break;
+
+ case 1:
+ $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3));
+ $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3));
+ $PictureSizeEnc['x'] >>= 7;
+ $PictureSizeEnc['y'] >>= 7;
+ $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF;
+ $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF;
+ break;
+
+ case 2:
+ $info['video']['resolution_x'] = 352;
+ $info['video']['resolution_y'] = 288;
+ break;
+
+ case 3:
+ $info['video']['resolution_x'] = 176;
+ $info['video']['resolution_y'] = 144;
+ break;
+
+ case 4:
+ $info['video']['resolution_x'] = 128;
+ $info['video']['resolution_y'] = 96;
+ break;
+
+ case 5:
+ $info['video']['resolution_x'] = 320;
+ $info['video']['resolution_y'] = 240;
+ break;
+
+ case 6:
+ $info['video']['resolution_x'] = 160;
+ $info['video']['resolution_y'] = 120;
+ break;
+
+ default:
+ $info['video']['resolution_x'] = 0;
+ $info['video']['resolution_y'] = 0;
+ break;
+
+ }
+ }
+ $info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y'];
+ }
+ break;
+
+ // Meta tag
+ case GETID3_FLV_TAG_META:
+ if (!$found_meta) {
+ $found_meta = true;
+ fseek($this->getid3->fp, -1, SEEK_CUR);
+ $datachunk = fread($this->getid3->fp, $DataLength);
+ $AMFstream = new AMFStream($datachunk);
+ $reader = new AMFReader($AMFstream);
+ $eventName = $reader->readData();
+ $info['flv']['meta'][$eventName] = $reader->readData();
+ unset($reader);
+
+ $copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate');
+ foreach ($copykeys as $sourcekey => $destkey) {
+ if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) {
+ switch ($sourcekey) {
+ case 'width':
+ case 'height':
+ $info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey]));
+ break;
+ case 'audiodatarate':
+ $info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000));
+ break;
+ case 'videodatarate':
+ case 'frame_rate':
+ default:
+ $info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey];
+ break;
+ }
+ }
+ }
+ if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
+ $found_valid_meta_playtime = true;
+ }
+ }
+ break;
+
+ default:
+ // noop
+ break;
+ }
+ fseek($this->getid3->fp, $NextOffset, SEEK_SET);
+ }
+
+ $info['playtime_seconds'] = $Duration / 1000;
+ if ($info['playtime_seconds'] > 0) {
+ $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+ }
+
+ if ($info['flv']['header']['hasAudio']) {
+ $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['audio']['audioFormat']);
+ $info['audio']['sample_rate'] = $this->FLVaudioRate($info['flv']['audio']['audioRate']);
+ $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']);
+
+ $info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo
+ $info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed
+ $info['audio']['dataformat'] = 'flv';
+ }
+ if (!empty($info['flv']['header']['hasVideo'])) {
+ $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['video']['videoCodec']);
+ $info['video']['dataformat'] = 'flv';
+ $info['video']['lossless'] = false;
+ }
+
+ // Set information from meta
+ if (!empty($info['flv']['meta']['onMetaData']['duration'])) {
+ $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration'];
+ $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+ }
+ if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) {
+ $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']);
+ }
+ if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) {
+ $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['meta']['onMetaData']['videocodecid']);
+ }
+ return true;
+ }
+
+
+ public function FLVaudioFormat($id) {
+ $FLVaudioFormat = array(
+ 0 => 'Linear PCM, platform endian',
+ 1 => 'ADPCM',
+ 2 => 'mp3',
+ 3 => 'Linear PCM, little endian',
+ 4 => 'Nellymoser 16kHz mono',
+ 5 => 'Nellymoser 8kHz mono',
+ 6 => 'Nellymoser',
+ 7 => 'G.711A-law logarithmic PCM',
+ 8 => 'G.711 mu-law logarithmic PCM',
+ 9 => 'reserved',
+ 10 => 'AAC',
+ 11 => false, // unknown?
+ 12 => false, // unknown?
+ 13 => false, // unknown?
+ 14 => 'mp3 8kHz',
+ 15 => 'Device-specific sound',
+ );
+ return (isset($FLVaudioFormat[$id]) ? $FLVaudioFormat[$id] : false);
+ }
+
+ public function FLVaudioRate($id) {
+ $FLVaudioRate = array(
+ 0 => 5500,
+ 1 => 11025,
+ 2 => 22050,
+ 3 => 44100,
+ );
+ return (isset($FLVaudioRate[$id]) ? $FLVaudioRate[$id] : false);
+ }
+
+ public function FLVaudioBitDepth($id) {
+ $FLVaudioBitDepth = array(
+ 0 => 8,
+ 1 => 16,
+ );
+ return (isset($FLVaudioBitDepth[$id]) ? $FLVaudioBitDepth[$id] : false);
+ }
+
+ public function FLVvideoCodec($id) {
+ $FLVvideoCodec = array(
+ GETID3_FLV_VIDEO_H263 => 'Sorenson H.263',
+ GETID3_FLV_VIDEO_SCREEN => 'Screen video',
+ GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6',
+ GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel',
+ GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2',
+ GETID3_FLV_VIDEO_H264 => 'Sorenson H.264',
+ );
+ return (isset($FLVvideoCodec[$id]) ? $FLVvideoCodec[$id] : false);
+ }
+}
+
+class AMFStream {
+ public $bytes;
+ public $pos;
+
+ public function AMFStream(&$bytes) {
+ $this->bytes =& $bytes;
+ $this->pos = 0;
+ }
+
+ public function readByte() {
+ return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1));
+ }
+
+ public function readInt() {
+ return ($this->readByte() << 8) + $this->readByte();
+ }
+
+ public function readLong() {
+ return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte();
+ }
+
+ public function readDouble() {
+ return getid3_lib::BigEndian2Float($this->read(8));
+ }
+
+ public function readUTF() {
+ $length = $this->readInt();
+ return $this->read($length);
+ }
+
+ public function readLongUTF() {
+ $length = $this->readLong();
+ return $this->read($length);
+ }
+
+ public function read($length) {
+ $val = substr($this->bytes, $this->pos, $length);
+ $this->pos += $length;
+ return $val;
+ }
+
+ public function peekByte() {
+ $pos = $this->pos;
+ $val = $this->readByte();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ public function peekInt() {
+ $pos = $this->pos;
+ $val = $this->readInt();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ public function peekLong() {
+ $pos = $this->pos;
+ $val = $this->readLong();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ public function peekDouble() {
+ $pos = $this->pos;
+ $val = $this->readDouble();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ public function peekUTF() {
+ $pos = $this->pos;
+ $val = $this->readUTF();
+ $this->pos = $pos;
+ return $val;
+ }
+
+ public function peekLongUTF() {
+ $pos = $this->pos;
+ $val = $this->readLongUTF();
+ $this->pos = $pos;
+ return $val;
+ }
+}
+
+class AMFReader {
+ public $stream;
+
+ public function AMFReader(&$stream) {
+ $this->stream =& $stream;
+ }
+
+ public function readData() {
+ $value = null;
+
+ $type = $this->stream->readByte();
+ switch ($type) {
+
+ // Double
+ case 0:
+ $value = $this->readDouble();
+ break;
+
+ // Boolean
+ case 1:
+ $value = $this->readBoolean();
+ break;
+
+ // String
+ case 2:
+ $value = $this->readString();
+ break;
+
+ // Object
+ case 3:
+ $value = $this->readObject();
+ break;
+
+ // null
+ case 6:
+ return null;
+ break;
+
+ // Mixed array
+ case 8:
+ $value = $this->readMixedArray();
+ break;
+
+ // Array
+ case 10:
+ $value = $this->readArray();
+ break;
+
+ // Date
+ case 11:
+ $value = $this->readDate();
+ break;
+
+ // Long string
+ case 13:
+ $value = $this->readLongString();
+ break;
+
+ // XML (handled as string)
+ case 15:
+ $value = $this->readXML();
+ break;
+
+ // Typed object (handled as object)
+ case 16:
+ $value = $this->readTypedObject();
+ break;
+
+ // Long string
+ default:
+ $value = '(unknown or unsupported data type)';
+ break;
+ }
+
+ return $value;
+ }
+
+ public function readDouble() {
+ return $this->stream->readDouble();
+ }
+
+ public function readBoolean() {
+ return $this->stream->readByte() == 1;
+ }
+
+ public function readString() {
+ return $this->stream->readUTF();
+ }
+
+ public function readObject() {
+ // Get highest numerical index - ignored
+// $highestIndex = $this->stream->readLong();
+
+ $data = array();
+
+ while ($key = $this->stream->readUTF()) {
+ $data[$key] = $this->readData();
+ }
+ // Mixed array record ends with empty string (0x00 0x00) and 0x09
+ if (($key == '') && ($this->stream->peekByte() == 0x09)) {
+ // Consume byte
+ $this->stream->readByte();
+ }
+ return $data;
+ }
+
+ public function readMixedArray() {
+ // Get highest numerical index - ignored
+ $highestIndex = $this->stream->readLong();
+
+ $data = array();
+
+ while ($key = $this->stream->readUTF()) {
+ if (is_numeric($key)) {
+ $key = (float) $key;
+ }
+ $data[$key] = $this->readData();
+ }
+ // Mixed array record ends with empty string (0x00 0x00) and 0x09
+ if (($key == '') && ($this->stream->peekByte() == 0x09)) {
+ // Consume byte
+ $this->stream->readByte();
+ }
+
+ return $data;
+ }
+
+ public function readArray() {
+ $length = $this->stream->readLong();
+ $data = array();
+
+ for ($i = 0; $i < $length; $i++) {
+ $data[] = $this->readData();
+ }
+ return $data;
+ }
+
+ public function readDate() {
+ $timestamp = $this->stream->readDouble();
+ $timezone = $this->stream->readInt();
+ return $timestamp;
+ }
+
+ public function readLongString() {
+ return $this->stream->readLongUTF();
+ }
+
+ public function readXML() {
+ return $this->stream->readLongUTF();
+ }
+
+ public function readTypedObject() {
+ $className = $this->stream->readUTF();
+ return $this->readObject();
+ }
+}
+
+class AVCSequenceParameterSetReader {
+ public $sps;
+ public $start = 0;
+ public $currentBytes = 0;
+ public $currentBits = 0;
+ public $width;
+ public $height;
+
+ public function AVCSequenceParameterSetReader($sps) {
+ $this->sps = $sps;
+ }
+
+ public function readData() {
+ $this->skipBits(8);
+ $this->skipBits(8);
+ $profile = $this->getBits(8); // read profile
+ $this->skipBits(16);
+ $this->expGolombUe(); // read sps id
+ if (in_array($profile, array(H264_PROFILE_HIGH, H264_PROFILE_HIGH10, H264_PROFILE_HIGH422, H264_PROFILE_HIGH444, H264_PROFILE_HIGH444_PREDICTIVE))) {
+ if ($this->expGolombUe() == 3) {
+ $this->skipBits(1);
+ }
+ $this->expGolombUe();
+ $this->expGolombUe();
+ $this->skipBits(1);
+ if ($this->getBit()) {
+ for ($i = 0; $i < 8; $i++) {
+ if ($this->getBit()) {
+ $size = $i < 6 ? 16 : 64;
+ $lastScale = 8;
+ $nextScale = 8;
+ for ($j = 0; $j < $size; $j++) {
+ if ($nextScale != 0) {
+ $deltaScale = $this->expGolombUe();
+ $nextScale = ($lastScale + $deltaScale + 256) % 256;
+ }
+ if ($nextScale != 0) {
+ $lastScale = $nextScale;
+ }
+ }
+ }
+ }
+ }
+ }
+ $this->expGolombUe();
+ $pocType = $this->expGolombUe();
+ if ($pocType == 0) {
+ $this->expGolombUe();
+ } elseif ($pocType == 1) {
+ $this->skipBits(1);
+ $this->expGolombSe();
+ $this->expGolombSe();
+ $pocCycleLength = $this->expGolombUe();
+ for ($i = 0; $i < $pocCycleLength; $i++) {
+ $this->expGolombSe();
+ }
+ }
+ $this->expGolombUe();
+ $this->skipBits(1);
+ $this->width = ($this->expGolombUe() + 1) * 16;
+ $heightMap = $this->expGolombUe() + 1;
+ $this->height = (2 - $this->getBit()) * $heightMap * 16;
+ }
+
+ public function skipBits($bits) {
+ $newBits = $this->currentBits + $bits;
+ $this->currentBytes += (int)floor($newBits / 8);
+ $this->currentBits = $newBits % 8;
+ }
+
+ public function getBit() {
+ $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01;
+ $this->skipBits(1);
+ return $result;
+ }
+
+ public function getBits($bits) {
+ $result = 0;
+ for ($i = 0; $i < $bits; $i++) {
+ $result = ($result << 1) + $this->getBit();
+ }
+ return $result;
+ }
+
+ public function expGolombUe() {
+ $significantBits = 0;
+ $bit = $this->getBit();
+ while ($bit == 0) {
+ $significantBits++;
+ $bit = $this->getBit();
+
+ if ($significantBits > 31) {
+ // something is broken, this is an emergency escape to prevent infinite loops
+ return 0;
+ }
+ }
+ return (1 << $significantBits) + $this->getBits($significantBits) - 1;
+ }
+
+ public function expGolombSe() {
+ $result = $this->expGolombUe();
+ if (($result & 0x01) == 0) {
+ return -($result >> 1);
+ } else {
+ return ($result + 1) >> 1;
+ }
+ }
+
+ public function getWidth() {
+ return $this->width;
+ }
+
+ public function getHeight() {
+ return $this->height;
+ }
+}
diff --git a/src/wp-includes/ID3/module.audio-video.matroska.php b/src/wp-includes/ID3/module.audio-video.matroska.php
new file mode 100644
index 0000000000..fb0af7221e
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio-video.matroska.php
@@ -0,0 +1,1765 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.matriska.php //
+// module for analyzing Matroska containers //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+define('EBML_ID_CHAPTERS', 0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation.
+define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements.
+define('EBML_ID_TAGS', 0x0254C367); // [12][54][C3][67] -- Element containing elements specific to Tracks/Chapters. A list of valid tags can be found <http://www.matroska.org/technical/specs/tagging/index.html>.
+define('EBML_ID_INFO', 0x0549A966); // [15][49][A9][66] -- Contains miscellaneous general information and statistics on the file.
+define('EBML_ID_TRACKS', 0x0654AE6B); // [16][54][AE][6B] -- A top-level block of information with many tracks described.
+define('EBML_ID_SEGMENT', 0x08538067); // [18][53][80][67] -- This element contains all other top-level (level 1) elements. Typically a Matroska file is composed of 1 segment.
+define('EBML_ID_ATTACHMENTS', 0x0941A469); // [19][41][A4][69] -- Contain attached files.
+define('EBML_ID_EBML', 0x0A45DFA3); // [1A][45][DF][A3] -- Set the EBML characteristics of the data to follow. Each EBML document has to start with this.
+define('EBML_ID_CUES', 0x0C53BB6B); // [1C][53][BB][6B] -- A top-level element to speed seeking access. All entries are local to the segment.
+define('EBML_ID_CLUSTER', 0x0F43B675); // [1F][43][B6][75] -- The lower level element containing the (monolithic) Block structure.
+define('EBML_ID_LANGUAGE', 0x02B59C); // [22][B5][9C] -- Specifies the language of the track in the Matroska languages form.
+define('EBML_ID_TRACKTIMECODESCALE', 0x03314F); // [23][31][4F] -- The scale to apply on this track to work at normal speed in relation with other tracks (mostly used to adjust video speed when the audio length differs).
+define('EBML_ID_DEFAULTDURATION', 0x03E383); // [23][E3][83] -- Number of nanoseconds (i.e. not scaled) per frame.
+define('EBML_ID_CODECNAME', 0x058688); // [25][86][88] -- A human-readable string specifying the codec.
+define('EBML_ID_CODECDOWNLOADURL', 0x06B240); // [26][B2][40] -- A URL to download about the codec used.
+define('EBML_ID_TIMECODESCALE', 0x0AD7B1); // [2A][D7][B1] -- Timecode scale in nanoseconds (1.000.000 means all timecodes in the segment are expressed in milliseconds).
+define('EBML_ID_COLOURSPACE', 0x0EB524); // [2E][B5][24] -- Same value as in AVI (32 bits).
+define('EBML_ID_GAMMAVALUE', 0x0FB523); // [2F][B5][23] -- Gamma Value.
+define('EBML_ID_CODECSETTINGS', 0x1A9697); // [3A][96][97] -- A string describing the encoding setting used.
+define('EBML_ID_CODECINFOURL', 0x1B4040); // [3B][40][40] -- A URL to find information about the codec used.
+define('EBML_ID_PREVFILENAME', 0x1C83AB); // [3C][83][AB] -- An escaped filename corresponding to the previous segment.
+define('EBML_ID_PREVUID', 0x1CB923); // [3C][B9][23] -- A unique ID to identify the previous chained segment (128 bits).
+define('EBML_ID_NEXTFILENAME', 0x1E83BB); // [3E][83][BB] -- An escaped filename corresponding to the next segment.
+define('EBML_ID_NEXTUID', 0x1EB923); // [3E][B9][23] -- A unique ID to identify the next chained segment (128 bits).
+define('EBML_ID_CONTENTCOMPALGO', 0x0254); // [42][54] -- The compression algorithm used. Algorithms that have been specified so far are:
+define('EBML_ID_CONTENTCOMPSETTINGS', 0x0255); // [42][55] -- Settings that might be needed by the decompressor. For Header Stripping (ContentCompAlgo=3), the bytes that were removed from the beggining of each frames of the track.
+define('EBML_ID_DOCTYPE', 0x0282); // [42][82] -- A string that describes the type of document that follows this EBML header ('matroska' in our case).
+define('EBML_ID_DOCTYPEREADVERSION', 0x0285); // [42][85] -- The minimum DocType version an interpreter has to support to read this file.
+define('EBML_ID_EBMLVERSION', 0x0286); // [42][86] -- The version of EBML parser used to create the file.
+define('EBML_ID_DOCTYPEVERSION', 0x0287); // [42][87] -- The version of DocType interpreter used to create the file.
+define('EBML_ID_EBMLMAXIDLENGTH', 0x02F2); // [42][F2] -- The maximum length of the IDs you'll find in this file (4 or less in Matroska).
+define('EBML_ID_EBMLMAXSIZELENGTH', 0x02F3); // [42][F3] -- The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not override the element size indicated at the beginning of an element. Elements that have an indicated size which is larger than what is allowed by EBMLMaxSizeLength shall be considered invalid.
+define('EBML_ID_EBMLREADVERSION', 0x02F7); // [42][F7] -- The minimum EBML version a parser has to support to read this file.
+define('EBML_ID_CHAPLANGUAGE', 0x037C); // [43][7C] -- The languages corresponding to the string, in the bibliographic ISO-639-2 form.
+define('EBML_ID_CHAPCOUNTRY', 0x037E); // [43][7E] -- The countries corresponding to the string, same 2 octets as in Internet domains.
+define('EBML_ID_SEGMENTFAMILY', 0x0444); // [44][44] -- A randomly generated unique ID that all segments related to each other must use (128 bits).
+define('EBML_ID_DATEUTC', 0x0461); // [44][61] -- Date of the origin of timecode (value 0), i.e. production date.
+define('EBML_ID_TAGLANGUAGE', 0x047A); // [44][7A] -- Specifies the language of the tag specified, in the Matroska languages form.
+define('EBML_ID_TAGDEFAULT', 0x0484); // [44][84] -- Indication to know if this is the default/original language to use for the given tag.
+define('EBML_ID_TAGBINARY', 0x0485); // [44][85] -- The values of the Tag if it is binary. Note that this cannot be used in the same SimpleTag as TagString.
+define('EBML_ID_TAGSTRING', 0x0487); // [44][87] -- The value of the Tag.
+define('EBML_ID_DURATION', 0x0489); // [44][89] -- Duration of the segment (based on TimecodeScale).
+define('EBML_ID_CHAPPROCESSPRIVATE', 0x050D); // [45][0D] -- Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it is the "DVD level" equivalent.
+define('EBML_ID_CHAPTERFLAGENABLED', 0x0598); // [45][98] -- Specify wether the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the movie should skip all the content between the TimeStart and TimeEnd of this chapter.
+define('EBML_ID_TAGNAME', 0x05A3); // [45][A3] -- The name of the Tag that is going to be stored.
+define('EBML_ID_EDITIONENTRY', 0x05B9); // [45][B9] -- Contains all information about a segment edition.
+define('EBML_ID_EDITIONUID', 0x05BC); // [45][BC] -- A unique ID to identify the edition. It's useful for tagging an edition.
+define('EBML_ID_EDITIONFLAGHIDDEN', 0x05BD); // [45][BD] -- If an edition is hidden (1), it should not be available to the user interface (but still to Control Tracks).
+define('EBML_ID_EDITIONFLAGDEFAULT', 0x05DB); // [45][DB] -- If a flag is set (1) the edition should be used as the default one.
+define('EBML_ID_EDITIONFLAGORDERED', 0x05DD); // [45][DD] -- Specify if the chapters can be defined multiple times and the order to play them is enforced.
+define('EBML_ID_FILEDATA', 0x065C); // [46][5C] -- The data of the file.
+define('EBML_ID_FILEMIMETYPE', 0x0660); // [46][60] -- MIME type of the file.
+define('EBML_ID_FILENAME', 0x066E); // [46][6E] -- Filename of the attached file.
+define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] -- A binary value that a track/codec can refer to when the attachment is needed.
+define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
+define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
+define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
+define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
+define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
+define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
+define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
+define('EBML_ID_CONTENTSIGHASHALGO', 0x07E6); // [47][E6] -- The hash algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
+define('EBML_ID_MUXINGAPP', 0x0D80); // [4D][80] -- Muxing application or library ("libmatroska-0.4.3").
+define('EBML_ID_SEEK', 0x0DBB); // [4D][BB] -- Contains a single seek entry to an EBML element.
+define('EBML_ID_CONTENTENCODINGORDER', 0x1031); // [50][31] -- Tells when this modification was used during encoding/muxing starting with 0 and counting upwards. The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to be unique over all ContentEncodingOrder elements in the segment.
+define('EBML_ID_CONTENTENCODINGSCOPE', 0x1032); // [50][32] -- A bit field that describes which elements have been modified in this way. Values (big endian) can be OR'ed. Possible values:
+define('EBML_ID_CONTENTENCODINGTYPE', 0x1033); // [50][33] -- A value describing what kind of transformation has been done. Possible values:
+define('EBML_ID_CONTENTCOMPRESSION', 0x1034); // [50][34] -- Settings describing the compression used. Must be present if the value of ContentEncodingType is 0 and absent otherwise. Each block must be decompressable even if no previous block is available in order not to prevent seeking.
+define('EBML_ID_CONTENTENCRYPTION', 0x1035); // [50][35] -- Settings describing the encryption used. Must be present if the value of ContentEncodingType is 1 and absent otherwise.
+define('EBML_ID_CUEREFNUMBER', 0x135F); // [53][5F] -- Number of the referenced Block of Track X in the specified Cluster.
+define('EBML_ID_NAME', 0x136E); // [53][6E] -- A human-readable track name.
+define('EBML_ID_CUEBLOCKNUMBER', 0x1378); // [53][78] -- Number of the Block in the specified Cluster.
+define('EBML_ID_TRACKOFFSET', 0x137F); // [53][7F] -- A value to add to the Block's Timecode. This can be used to adjust the playback offset of a track.
+define('EBML_ID_SEEKID', 0x13AB); // [53][AB] -- The binary ID corresponding to the element name.
+define('EBML_ID_SEEKPOSITION', 0x13AC); // [53][AC] -- The position of the element in the segment in octets (0 = first level 1 element).
+define('EBML_ID_STEREOMODE', 0x13B8); // [53][B8] -- Stereo-3D video mode.
+define('EBML_ID_OLDSTEREOMODE', 0x13B9); // [53][B9] -- Bogus StereoMode value used in old versions of libmatroska. DO NOT USE. (0: mono, 1: right eye, 2: left eye, 3: both eyes).
+define('EBML_ID_PIXELCROPBOTTOM', 0x14AA); // [54][AA] -- The number of video pixels to remove at the bottom of the image (for HDTV content).
+define('EBML_ID_DISPLAYWIDTH', 0x14B0); // [54][B0] -- Width of the video frames to display.
+define('EBML_ID_DISPLAYUNIT', 0x14B2); // [54][B2] -- Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches).
+define('EBML_ID_ASPECTRATIOTYPE', 0x14B3); // [54][B3] -- Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed).
+define('EBML_ID_DISPLAYHEIGHT', 0x14BA); // [54][BA] -- Height of the video frames to display.
+define('EBML_ID_PIXELCROPTOP', 0x14BB); // [54][BB] -- The number of video pixels to remove at the top of the image.
+define('EBML_ID_PIXELCROPLEFT', 0x14CC); // [54][CC] -- The number of video pixels to remove on the left of the image.
+define('EBML_ID_PIXELCROPRIGHT', 0x14DD); // [54][DD] -- The number of video pixels to remove on the right of the image.
+define('EBML_ID_FLAGFORCED', 0x15AA); // [55][AA] -- Set if that track MUST be used during playback. There can be many forced track for a kind (audio, video or subs), the player should select the one which language matches the user preference or the default + forced track. Overlay MAY happen between a forced and non-forced track of the same kind.
+define('EBML_ID_MAXBLOCKADDITIONID', 0x15EE); // [55][EE] -- The maximum value of BlockAddID. A value 0 means there is no BlockAdditions for this track.
+define('EBML_ID_WRITINGAPP', 0x1741); // [57][41] -- Writing application ("mkvmerge-0.3.3").
+define('EBML_ID_CLUSTERSILENTTRACKS', 0x1854); // [58][54] -- The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks on seeking. Then you should decide what track to use.
+define('EBML_ID_CLUSTERSILENTTRACKNUMBER', 0x18D7); // [58][D7] -- One of the track number that are not used from now on in the stream. It could change later if not specified as silent in a further Cluster.
+define('EBML_ID_ATTACHEDFILE', 0x21A7); // [61][A7] -- An attached file.
+define('EBML_ID_CONTENTENCODING', 0x2240); // [62][40] -- Settings for one content encoding like compression or encryption.
+define('EBML_ID_BITDEPTH', 0x2264); // [62][64] -- Bits per sample, mostly used for PCM.
+define('EBML_ID_CODECPRIVATE', 0x23A2); // [63][A2] -- Private data only known to the codec.
+define('EBML_ID_TARGETS', 0x23C0); // [63][C0] -- Contain all UIDs where the specified meta data apply. It is void to describe everything in the segment.
+define('EBML_ID_CHAPTERPHYSICALEQUIV', 0x23C3); // [63][C3] -- Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50), see complete list of values.
+define('EBML_ID_TAGCHAPTERUID', 0x23C4); // [63][C4] -- A unique ID to identify the Chapter(s) the tags belong to. If the value is 0 at this level, the tags apply to all chapters in the Segment.
+define('EBML_ID_TAGTRACKUID', 0x23C5); // [63][C5] -- A unique ID to identify the Track(s) the tags belong to. If the value is 0 at this level, the tags apply to all tracks in the Segment.
+define('EBML_ID_TAGATTACHMENTUID', 0x23C6); // [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment.
+define('EBML_ID_TAGEDITIONUID', 0x23C9); // [63][C9] -- A unique ID to identify the EditionEntry(s) the tags belong to. If the value is 0 at this level, the tags apply to all editions in the Segment.
+define('EBML_ID_TARGETTYPE', 0x23CA); // [63][CA] -- An informational string that can be used to display the logical level of the target like "ALBUM", "TRACK", "MOVIE", "CHAPTER", etc (see TargetType).
+define('EBML_ID_TRACKTRANSLATE', 0x2624); // [66][24] -- The track identification for the given Chapter Codec.
+define('EBML_ID_TRACKTRANSLATETRACKID', 0x26A5); // [66][A5] -- The binary value used to represent this track in the chapter codec data. The format depends on the ChapProcessCodecID used.
+define('EBML_ID_TRACKTRANSLATECODEC', 0x26BF); // [66][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
+define('EBML_ID_TRACKTRANSLATEEDITIONUID', 0x26FC); // [66][FC] -- Specify an edition UID on which this translation applies. When not specified, it means for all editions found in the segment.
+define('EBML_ID_SIMPLETAG', 0x27C8); // [67][C8] -- Contains general information about the target.
+define('EBML_ID_TARGETTYPEVALUE', 0x28CA); // [68][CA] -- A number to indicate the logical level of the target (see TargetType).
+define('EBML_ID_CHAPPROCESSCOMMAND', 0x2911); // [69][11] -- Contains all the commands associated to the Atom.
+define('EBML_ID_CHAPPROCESSTIME', 0x2922); // [69][22] -- Defines when the process command should be handled (0: during the whole chapter, 1: before starting playback, 2: after playback of the chapter).
+define('EBML_ID_CHAPTERTRANSLATE', 0x2924); // [69][24] -- A tuple of corresponding ID used by chapter codecs to represent this segment.
+define('EBML_ID_CHAPPROCESSDATA', 0x2933); // [69][33] -- Contains the command information. The data should be interpreted depending on the ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post commands.
+define('EBML_ID_CHAPPROCESS', 0x2944); // [69][44] -- Contains all the commands associated to the Atom.
+define('EBML_ID_CHAPPROCESSCODECID', 0x2955); // [69][55] -- Contains the type of the codec used for the processing. A value of 0 means native Matroska processing (to be defined), a value of 1 means the DVD command set is used. More codec IDs can be added later.
+define('EBML_ID_CHAPTERTRANSLATEID', 0x29A5); // [69][A5] -- The binary value used to represent this segment in the chapter codec data. The format depends on the ChapProcessCodecID used.
+define('EBML_ID_CHAPTERTRANSLATECODEC', 0x29BF); // [69][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
+define('EBML_ID_CHAPTERTRANSLATEEDITIONUID', 0x29FC); // [69][FC] -- Specify an edition UID on which this correspondance applies. When not specified, it means for all editions found in the segment.
+define('EBML_ID_CONTENTENCODINGS', 0x2D80); // [6D][80] -- Settings for several content encoding mechanisms like compression or encryption.
+define('EBML_ID_MINCACHE', 0x2DE7); // [6D][E7] -- The minimum number of frames a player should be able to cache during playback. If set to 0, the reference pseudo-cache system is not used.
+define('EBML_ID_MAXCACHE', 0x2DF8); // [6D][F8] -- The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed.
+define('EBML_ID_CHAPTERSEGMENTUID', 0x2E67); // [6E][67] -- A segment to play in place of this chapter. Edition ChapterSegmentEditionUID should be used for this segment, otherwise no edition is used.
+define('EBML_ID_CHAPTERSEGMENTEDITIONUID', 0x2EBC); // [6E][BC] -- The edition to play from the segment linked in ChapterSegmentUID.
+define('EBML_ID_TRACKOVERLAY', 0x2FAB); // [6F][AB] -- Specify that this track is an overlay track for the Track specified (in the u-integer). That means when this track has a gap (see SilentTracks) the overlay track should be used instead. The order of multiple TrackOverlay matters, the first one is the one that should be used. If not found it should be the second, etc.
+define('EBML_ID_TAG', 0x3373); // [73][73] -- Element containing elements specific to Tracks/Chapters.
+define('EBML_ID_SEGMENTFILENAME', 0x3384); // [73][84] -- A filename corresponding to this segment.
+define('EBML_ID_SEGMENTUID', 0x33A4); // [73][A4] -- A randomly generated unique ID to identify the current segment between many others (128 bits).
+define('EBML_ID_CHAPTERUID', 0x33C4); // [73][C4] -- A unique ID to identify the Chapter.
+define('EBML_ID_TRACKUID', 0x33C5); // [73][C5] -- A unique ID to identify the Track. This should be kept the same when making a direct stream copy of the Track to another file.
+define('EBML_ID_ATTACHMENTLINK', 0x3446); // [74][46] -- The UID of an attachment that is used by this codec.
+define('EBML_ID_CLUSTERBLOCKADDITIONS', 0x35A1); // [75][A1] -- Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block structure could still see and use/skip these data.
+define('EBML_ID_CHANNELPOSITIONS', 0x347B); // [7D][7B] -- Table of horizontal angles for each successive channel, see appendix.
+define('EBML_ID_OUTPUTSAMPLINGFREQUENCY', 0x38B5); // [78][B5] -- Real output sampling frequency in Hz (used for SBR techniques).
+define('EBML_ID_TITLE', 0x3BA9); // [7B][A9] -- General name of the segment.
+define('EBML_ID_CHAPTERDISPLAY', 0x00); // [80] -- Contains all possible strings to use for the chapter display.
+define('EBML_ID_TRACKTYPE', 0x03); // [83] -- A set of track types coded on 8 bits (1: video, 2: audio, 3: complex, 0x10: logo, 0x11: subtitle, 0x12: buttons, 0x20: control).
+define('EBML_ID_CHAPSTRING', 0x05); // [85] -- Contains the string to use as the chapter atom.
+define('EBML_ID_CODECID', 0x06); // [86] -- An ID corresponding to the codec, see the codec page for more info.
+define('EBML_ID_FLAGDEFAULT', 0x08); // [88] -- Set if that track (audio, video or subs) SHOULD be used if no language found matches the user preference.
+define('EBML_ID_CHAPTERTRACKNUMBER', 0x09); // [89] -- UID of the Track to apply this chapter too. In the absense of a control track, choosing this chapter will select the listed Tracks and deselect unlisted tracks. Absense of this element indicates that the Chapter should be applied to any currently used Tracks.
+define('EBML_ID_CLUSTERSLICES', 0x0E); // [8E] -- Contains slices description.
+define('EBML_ID_CHAPTERTRACK', 0x0F); // [8F] -- List of tracks on which the chapter applies. If this element is not present, all tracks apply
+define('EBML_ID_CHAPTERTIMESTART', 0x11); // [91] -- Timecode of the start of Chapter (not scaled).
+define('EBML_ID_CHAPTERTIMEEND', 0x12); // [92] -- Timecode of the end of Chapter (timecode excluded, not scaled).
+define('EBML_ID_CUEREFTIME', 0x16); // [96] -- Timecode of the referenced Block.
+define('EBML_ID_CUEREFCLUSTER', 0x17); // [97] -- Position of the Cluster containing the referenced Block.
+define('EBML_ID_CHAPTERFLAGHIDDEN', 0x18); // [98] -- If a chapter is hidden (1), it should not be available to the user interface (but still to Control Tracks).
+define('EBML_ID_FLAGINTERLACED', 0x1A); // [9A] -- Set if the video is interlaced.
+define('EBML_ID_CLUSTERBLOCKDURATION', 0x1B); // [9B] -- The duration of the Block (based on TimecodeScale). This element is mandatory when DefaultDuration is set for the track. When not written and with no DefaultDuration, the value is assumed to be the difference between the timecode of this Block and the timecode of the next Block in "display" order (not coding order). This element can be useful at the end of a Track (as there is not other Block available), or when there is a break in a track like for subtitle tracks.
+define('EBML_ID_FLAGLACING', 0x1C); // [9C] -- Set if the track may contain blocks using lacing.
+define('EBML_ID_CHANNELS', 0x1F); // [9F] -- Numbers of channels in the track.
+define('EBML_ID_CLUSTERBLOCKGROUP', 0x20); // [A0] -- Basic container of information containing a single Block or BlockVirtual, and information specific to that Block/VirtualBlock.
+define('EBML_ID_CLUSTERBLOCK', 0x21); // [A1] -- Block containing the actual data to be rendered and a timecode relative to the Cluster Timecode.
+define('EBML_ID_CLUSTERBLOCKVIRTUAL', 0x22); // [A2] -- A Block with no data. It must be stored in the stream at the place the real Block should be in display order.
+define('EBML_ID_CLUSTERSIMPLEBLOCK', 0x23); // [A3] -- Similar to Block but without all the extra information, mostly used to reduced overhead when no extra feature is needed.
+define('EBML_ID_CLUSTERCODECSTATE', 0x24); // [A4] -- The new codec state to use. Data interpretation is private to the codec. This information should always be referenced by a seek entry.
+define('EBML_ID_CLUSTERBLOCKADDITIONAL', 0x25); // [A5] -- Interpreted by the codec as it wishes (using the BlockAddID).
+define('EBML_ID_CLUSTERBLOCKMORE', 0x26); // [A6] -- Contain the BlockAdditional and some parameters.
+define('EBML_ID_CLUSTERPOSITION', 0x27); // [A7] -- Position of the Cluster in the segment (0 in live broadcast streams). It might help to resynchronise offset on damaged streams.
+define('EBML_ID_CODECDECODEALL', 0x2A); // [AA] -- The codec can decode potentially damaged data.
+define('EBML_ID_CLUSTERPREVSIZE', 0x2B); // [AB] -- Size of the previous Cluster, in octets. Can be useful for backward playing.
+define('EBML_ID_TRACKENTRY', 0x2E); // [AE] -- Describes a track with all elements.
+define('EBML_ID_CLUSTERENCRYPTEDBLOCK', 0x2F); // [AF] -- Similar to SimpleBlock but the data inside the Block are Transformed (encrypt and/or signed).
+define('EBML_ID_PIXELWIDTH', 0x30); // [B0] -- Width of the encoded video frames in pixels.
+define('EBML_ID_CUETIME', 0x33); // [B3] -- Absolute timecode according to the segment time base.
+define('EBML_ID_SAMPLINGFREQUENCY', 0x35); // [B5] -- Sampling frequency in Hz.
+define('EBML_ID_CHAPTERATOM', 0x36); // [B6] -- Contains the atom information to use as the chapter atom (apply to all tracks).
+define('EBML_ID_CUETRACKPOSITIONS', 0x37); // [B7] -- Contain positions for different tracks corresponding to the timecode.
+define('EBML_ID_FLAGENABLED', 0x39); // [B9] -- Set if the track is used.
+define('EBML_ID_PIXELHEIGHT', 0x3A); // [BA] -- Height of the encoded video frames in pixels.
+define('EBML_ID_CUEPOINT', 0x3B); // [BB] -- Contains all information relative to a seek point in the segment.
+define('EBML_ID_CRC32', 0x3F); // [BF] -- The CRC is computed on all the data of the Master element it's in, regardless of its position. It's recommended to put the CRC value at the beggining of the Master element for easier reading. All level 1 elements should include a CRC-32.
+define('EBML_ID_CLUSTERBLOCKADDITIONID', 0x4B); // [CB] -- The ID of the BlockAdditional element (0 is the main Block).
+define('EBML_ID_CLUSTERLACENUMBER', 0x4C); // [CC] -- The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback.
+define('EBML_ID_CLUSTERFRAMENUMBER', 0x4D); // [CD] -- The number of the frame to generate from this lace with this delay (allow you to generate many frames from the same Block/Frame).
+define('EBML_ID_CLUSTERDELAY', 0x4E); // [CE] -- The (scaled) delay to apply to the element.
+define('EBML_ID_CLUSTERDURATION', 0x4F); // [CF] -- The (scaled) duration to apply to the element.
+define('EBML_ID_TRACKNUMBER', 0x57); // [D7] -- The track number as used in the Block Header (using more than 127 tracks is not encouraged, though the design allows an unlimited number).
+define('EBML_ID_CUEREFERENCE', 0x5B); // [DB] -- The Clusters containing the required referenced Blocks.
+define('EBML_ID_VIDEO', 0x60); // [E0] -- Video settings.
+define('EBML_ID_AUDIO', 0x61); // [E1] -- Audio settings.
+define('EBML_ID_CLUSTERTIMESLICE', 0x68); // [E8] -- Contains extra time information about the data contained in the Block. While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback.
+define('EBML_ID_CUECODECSTATE', 0x6A); // [EA] -- The position of the Codec State corresponding to this Cue element. 0 means that the data is taken from the initial Track Entry.
+define('EBML_ID_CUEREFCODECSTATE', 0x6B); // [EB] -- The position of the Codec State corresponding to this referenced element. 0 means that the data is taken from the initial Track Entry.
+define('EBML_ID_VOID', 0x6C); // [EC] -- Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is discarded. Also used to reserve space in a sub-element for later use.
+define('EBML_ID_CLUSTERTIMECODE', 0x67); // [E7] -- Absolute timecode of the cluster (based on TimecodeScale).
+define('EBML_ID_CLUSTERBLOCKADDID', 0x6E); // [EE] -- An ID to identify the BlockAdditional level.
+define('EBML_ID_CUECLUSTERPOSITION', 0x71); // [F1] -- The position of the Cluster containing the required Block.
+define('EBML_ID_CUETRACK', 0x77); // [F7] -- The track for which a position is given.
+define('EBML_ID_CLUSTERREFERENCEPRIORITY', 0x7A); // [FA] -- This frame is referenced and has the specified cache priority. In cache only a frame of the same or higher priority can replace this frame. A value of 0 means the frame is not referenced.
+define('EBML_ID_CLUSTERREFERENCEBLOCK', 0x7B); // [FB] -- Timecode of another frame used as a reference (ie: B or P frame). The timecode is relative to the block it's attached to.
+define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] -- Relative position of the data that should be in position of the virtual block.
+
+
+/**
+* @tutorial http://www.matroska.org/technical/specs/index.html
+*
+* @todo Rewrite EBML parser to reduce it's size and honor default element values
+* @todo After rewrite implement stream size calculation, that will provide additional useful info and enable AAC/FLAC audio bitrate detection
+*/
+class getid3_matroska extends getid3_handler
+{
+ // public options
+ public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
+ public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE]
+
+ // private parser settings/placeholders
+ private $EBMLbuffer = '';
+ private $EBMLbuffer_offset = 0;
+ private $EBMLbuffer_length = 0;
+ private $current_offset = 0;
+ private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
+
+ public function Analyze()
+ {
+ $info = &$this->getid3->info;
+
+ // parse container
+ try {
+ $this->parseEBML($info);
+ } catch (Exception $e) {
+ $info['error'][] = 'EBML parser: '.$e->getMessage();
+ }
+
+ // calculate playtime
+ if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
+ foreach ($info['matroska']['info'] as $key => $infoarray) {
+ if (isset($infoarray['Duration'])) {
+ // TimecodeScale is how many nanoseconds each Duration unit is
+ $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
+ break;
+ }
+ }
+ }
+
+ // extract tags
+ if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
+ foreach ($info['matroska']['tags'] as $key => $infoarray) {
+ $this->ExtractCommentsSimpleTag($infoarray);
+ }
+ }
+
+ // process tracks
+ if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
+ foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
+
+ $track_info = array();
+ $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']);
+ $track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true);
+ if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; }
+
+ switch ($trackarray['TrackType']) {
+
+ case 1: // Video
+ $track_info['resolution_x'] = $trackarray['PixelWidth'];
+ $track_info['resolution_y'] = $trackarray['PixelHeight'];
+ $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0);
+ $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']);
+ $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']);
+
+ if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; }
+ if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; }
+ if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; }
+ if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; }
+ if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); }
+ if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
+
+ switch ($trackarray['CodecID']) {
+ case 'V_MS/VFW/FOURCC':
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
+ $this->warning('Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
+ break;
+ }
+ $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
+ $track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']);
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
+ break;
+
+ /*case 'V_MPEG4/ISO/AVC':
+ $h264['profile'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1));
+ $h264['level'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1));
+ $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1));
+ $h264['NALUlength'] = ($rn & 3) + 1;
+ $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1));
+ $nsps = ($rn & 31);
+ $offset = 6;
+ for ($i = 0; $i < $nsps; $i ++) {
+ $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
+ $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
+ $offset += 2 + $length;
+ }
+ $npps = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1));
+ $offset += 1;
+ for ($i = 0; $i < $npps; $i ++) {
+ $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
+ $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
+ $offset += 2 + $length;
+ }
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264;
+ break;*/
+ }
+
+ $info['video']['streams'][] = $track_info;
+ break;
+
+ case 2: // Audio
+ $track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0);
+ $track_info['channels'] = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1);
+ $track_info['language'] = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng');
+ if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; }
+ if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
+
+ switch ($trackarray['CodecID']) {
+ case 'A_PCM/INT/LIT':
+ case 'A_PCM/INT/BIG':
+ $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
+ break;
+
+ case 'A_AC3':
+ case 'A_DTS':
+ case 'A_MPEG/L3':
+ case 'A_MPEG/L2':
+ case 'A_FLAC':
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, false)) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.'.$track_info['dataformat'].'.php"');
+ break;
+ }
+
+ if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
+ break;
+ }
+
+ // create temp instance
+ $getid3_temp = new getID3();
+ if ($track_info['dataformat'] != 'flac') {
+ $getid3_temp->openfile($this->getid3->filename);
+ }
+ $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
+ if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
+ $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
+ }
+
+ // analyze
+ $class = 'getid3_'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);
+ $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
+ $getid3_audio = new $class($getid3_temp, __CLASS__);
+ if ($track_info['dataformat'] == 'flac') {
+ $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
+ }
+ else {
+ $getid3_audio->Analyze();
+ }
+ if (!empty($getid3_temp->info[$header_data_key])) {
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
+ if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
+ foreach ($getid3_temp->info['audio'] as $key => $value) {
+ $track_info[$key] = $value;
+ }
+ }
+ }
+ else {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']);
+ }
+
+ // copy errors and warnings
+ if (!empty($getid3_temp->info['error'])) {
+ foreach ($getid3_temp->info['error'] as $newerror) {
+ $this->warning($class.'() says: ['.$newerror.']');
+ }
+ }
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) {
+ // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning
+ continue;
+ }
+ $this->warning($class.'() says: ['.$newerror.']');
+ }
+ }
+ unset($getid3_temp, $getid3_audio);
+ break;
+
+ case 'A_AAC':
+ case 'A_AAC/MPEG2/LC':
+ case 'A_AAC/MPEG2/LC/SBR':
+ case 'A_AAC/MPEG4/LC':
+ case 'A_AAC/MPEG4/LC/SBR':
+ $this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated');
+ break;
+
+ case 'A_VORBIS':
+ if (!isset($trackarray['CodecPrivate'])) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data not set');
+ break;
+ }
+ $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
+ if ($vorbis_offset === false) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data does not contain "vorbis" keyword');
+ break;
+ }
+ $vorbis_offset -= 1;
+
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"');
+ break;
+ }
+
+ // create temp instance
+ $getid3_temp = new getID3();
+
+ // analyze
+ $getid3_ogg = new getid3_ogg($getid3_temp);
+ $oggpageinfo['page_seqno'] = 0;
+ $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
+ if (!empty($getid3_temp->info['ogg'])) {
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
+ if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
+ foreach ($getid3_temp->info['audio'] as $key => $value) {
+ $track_info[$key] = $value;
+ }
+ }
+ }
+
+ // copy errors and warnings
+ if (!empty($getid3_temp->info['error'])) {
+ foreach ($getid3_temp->info['error'] as $newerror) {
+ $this->warning('getid3_ogg() says: ['.$newerror.']');
+ }
+ }
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ $this->warning('getid3_ogg() says: ['.$newerror.']');
+ }
+ }
+
+ if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
+ $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
+ }
+ unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
+ break;
+
+ case 'A_MS/ACM':
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
+ break;
+ }
+
+ $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
+ foreach ($parsed as $key => $value) {
+ if ($key != 'raw') {
+ $track_info[$key] = $value;
+ }
+ }
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
+ break;
+
+ default:
+ $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"');
+ }
+
+ $info['audio']['streams'][] = $track_info;
+ break;
+ }
+ }
+
+ if (!empty($info['video']['streams'])) {
+ $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
+ }
+ if (!empty($info['audio']['streams'])) {
+ $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
+ }
+ }
+
+ // process attachments
+ if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) {
+ foreach ($info['matroska']['attachments'] as $i => $entry) {
+ if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) {
+ $info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']);
+ }
+ }
+ }
+
+ // determine mime type
+ if (!empty($info['video']['streams'])) {
+ $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska');
+ } elseif (!empty($info['audio']['streams'])) {
+ $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska');
+ } elseif (isset($info['mime_type'])) {
+ unset($info['mime_type']);
+ }
+
+ return true;
+ }
+
+ private function parseEBML(&$info) {
+ // http://www.matroska.org/technical/specs/index.html#EBMLBasics
+ $this->current_offset = $info['avdataoffset'];
+
+ while ($this->getEBMLelement($top_element, $info['avdataend'])) {
+ switch ($top_element['id']) {
+
+ case EBML_ID_EBML:
+ $info['fileformat'] = 'matroska';
+ $info['matroska']['header']['offset'] = $top_element['offset'];
+ $info['matroska']['header']['length'] = $top_element['length'];
+
+ while ($this->getEBMLelement($element_data, $top_element['end'], true)) {
+ switch ($element_data['id']) {
+
+ case EBML_ID_EBMLVERSION:
+ case EBML_ID_EBMLREADVERSION:
+ case EBML_ID_EBMLMAXIDLENGTH:
+ case EBML_ID_EBMLMAXSIZELENGTH:
+ case EBML_ID_DOCTYPEVERSION:
+ case EBML_ID_DOCTYPEREADVERSION:
+ $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']);
+ break;
+
+ case EBML_ID_DOCTYPE:
+ $element_data['data'] = getid3_lib::trimNullByte($element_data['data']);
+ $info['matroska']['doctype'] = $element_data['data'];
+ break;
+
+ default:
+ $this->unhandledElement('header', __LINE__, $element_data);
+ }
+
+ unset($element_data['offset'], $element_data['end']);
+ $info['matroska']['header']['elements'][] = $element_data;
+ }
+ break;
+
+ case EBML_ID_SEGMENT:
+ $info['matroska']['segment'][0]['offset'] = $top_element['offset'];
+ $info['matroska']['segment'][0]['length'] = $top_element['length'];
+
+ while ($this->getEBMLelement($element_data, $top_element['end'])) {
+ if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
+ $info['matroska']['segments'][] = $element_data;
+ }
+ switch ($element_data['id']) {
+
+ case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements.
+
+ while ($this->getEBMLelement($seek_entry, $element_data['end'])) {
+ switch ($seek_entry['id']) {
+
+ case EBML_ID_SEEK: // Contains a single seek entry to an EBML element
+ while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) {
+
+ switch ($sub_seek_entry['id']) {
+
+ case EBML_ID_SEEKID:
+ $seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']);
+ $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']);
+ break;
+
+ case EBML_ID_SEEKPOSITION:
+ $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']);
+ break;
+
+ default:
+ $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
+ }
+
+ if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
+ $info['matroska']['seek'][] = $seek_entry;
+ }
+ break;
+
+ default:
+ $this->unhandledElement('seekhead', __LINE__, $seek_entry);
+ }
+ }
+ break;
+
+ case EBML_ID_TRACKS: // A top-level block of information with many tracks described.
+ $info['matroska']['tracks'] = $element_data;
+
+ while ($this->getEBMLelement($track_entry, $element_data['end'])) {
+ switch ($track_entry['id']) {
+
+ case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements.
+
+ while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_TRACKNUMBER:
+ case EBML_ID_TRACKUID:
+ case EBML_ID_TRACKTYPE:
+ case EBML_ID_MINCACHE:
+ case EBML_ID_MAXCACHE:
+ case EBML_ID_MAXBLOCKADDITIONID:
+ case EBML_ID_DEFAULTDURATION: // nanoseconds per frame
+ $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_TRACKTIMECODESCALE:
+ $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
+ break;
+
+ case EBML_ID_CODECID:
+ case EBML_ID_LANGUAGE:
+ case EBML_ID_NAME:
+ case EBML_ID_CODECNAME:
+ $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
+ break;
+
+ case EBML_ID_CODECPRIVATE:
+ $track_entry[$subelement['id_name']] = $this->readEBMLelementData($subelement['length'], true);
+ break;
+
+ case EBML_ID_FLAGENABLED:
+ case EBML_ID_FLAGDEFAULT:
+ case EBML_ID_FLAGFORCED:
+ case EBML_ID_FLAGLACING:
+ case EBML_ID_CODECDECODEALL:
+ $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_VIDEO:
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_PIXELWIDTH:
+ case EBML_ID_PIXELHEIGHT:
+ case EBML_ID_PIXELCROPBOTTOM:
+ case EBML_ID_PIXELCROPTOP:
+ case EBML_ID_PIXELCROPLEFT:
+ case EBML_ID_PIXELCROPRIGHT:
+ case EBML_ID_DISPLAYWIDTH:
+ case EBML_ID_DISPLAYHEIGHT:
+ case EBML_ID_DISPLAYUNIT:
+ case EBML_ID_ASPECTRATIOTYPE:
+ case EBML_ID_STEREOMODE:
+ case EBML_ID_OLDSTEREOMODE:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_FLAGINTERLACED:
+ $track_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_GAMMAVALUE:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
+ break;
+
+ case EBML_ID_COLOURSPACE:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('track.video', __LINE__, $sub_subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_AUDIO:
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CHANNELS:
+ case EBML_ID_BITDEPTH:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_SAMPLINGFREQUENCY:
+ case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHANNELPOSITIONS:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('track.audio', __LINE__, $sub_subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CONTENTENCODINGS:
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'])) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CONTENTENCODING:
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_CONTENTENCODINGORDER:
+ case EBML_ID_CONTENTENCODINGSCOPE:
+ case EBML_ID_CONTENTENCODINGTYPE:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CONTENTCOMPRESSION:
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CONTENTCOMPALGO:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CONTENTCOMPSETTINGS:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CONTENTENCRYPTION:
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CONTENTENCALGO:
+ case EBML_ID_CONTENTSIGALGO:
+ case EBML_ID_CONTENTSIGHASHALGO:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CONTENTENCKEYID:
+ case EBML_ID_CONTENTSIGNATURE:
+ case EBML_ID_CONTENTSIGKEYID:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('track', __LINE__, $subelement);
+ }
+ }
+
+ $info['matroska']['tracks']['tracks'][] = $track_entry;
+ break;
+
+ default:
+ $this->unhandledElement('tracks', __LINE__, $track_entry);
+ }
+ }
+ break;
+
+ case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file.
+ $info_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'], true)) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_TIMECODESCALE:
+ $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_DURATION:
+ $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
+ break;
+
+ case EBML_ID_DATEUTC:
+ $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ $info_entry[$subelement['id_name'].'_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]);
+ break;
+
+ case EBML_ID_SEGMENTUID:
+ case EBML_ID_PREVUID:
+ case EBML_ID_NEXTUID:
+ $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
+ break;
+
+ case EBML_ID_SEGMENTFAMILY:
+ $info_entry[$subelement['id_name']][] = getid3_lib::trimNullByte($subelement['data']);
+ break;
+
+ case EBML_ID_SEGMENTFILENAME:
+ case EBML_ID_PREVFILENAME:
+ case EBML_ID_NEXTFILENAME:
+ case EBML_ID_TITLE:
+ case EBML_ID_MUXINGAPP:
+ case EBML_ID_WRITINGAPP:
+ $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
+ $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']];
+ break;
+
+ case EBML_ID_CHAPTERTRANSLATE:
+ $chaptertranslate_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
+ $chaptertranslate_entry[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERTRANSLATECODEC:
+ $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERTRANSLATEID:
+ $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement);
+ }
+ }
+ $info_entry[$subelement['id_name']] = $chaptertranslate_entry;
+ break;
+
+ default:
+ $this->unhandledElement('info', __LINE__, $subelement);
+ }
+ }
+ $info['matroska']['info'][] = $info_entry;
+ break;
+
+ case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams.
+ if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
+ $this->current_offset = $element_data['end'];
+ break;
+ }
+ $cues_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'])) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_CUEPOINT:
+ $cuepoint_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CUETRACKPOSITIONS:
+ $cuetrackpositions_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_CUETRACK:
+ case EBML_ID_CUECLUSTERPOSITION:
+ case EBML_ID_CUEBLOCKNUMBER:
+ case EBML_ID_CUECODECSTATE:
+ $cuetrackpositions_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
+ }
+ }
+ $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry;
+ break;
+
+ case EBML_ID_CUETIME:
+ $cuepoint_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
+ }
+ }
+ $cues_entry[] = $cuepoint_entry;
+ break;
+
+ default:
+ $this->unhandledElement('cues', __LINE__, $subelement);
+ }
+ }
+ $info['matroska']['cues'] = $cues_entry;
+ break;
+
+ case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters.
+ $tags_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'], false)) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_TAG:
+ $tag_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_TARGETS:
+ $targets_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_TARGETTYPEVALUE:
+ $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ $targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::TargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]);
+ break;
+
+ case EBML_ID_TARGETTYPE:
+ $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
+ break;
+
+ case EBML_ID_TAGTRACKUID:
+ case EBML_ID_TAGEDITIONUID:
+ case EBML_ID_TAGCHAPTERUID:
+ case EBML_ID_TAGATTACHMENTUID:
+ $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
+ }
+ }
+ $tag_entry[$sub_subelement['id_name']] = $targets_entry;
+ break;
+
+ case EBML_ID_SIMPLETAG:
+ $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']);
+ break;
+
+ default:
+ $this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
+ }
+ }
+ $tags_entry[] = $tag_entry;
+ break;
+
+ default:
+ $this->unhandledElement('tags', __LINE__, $subelement);
+ }
+ }
+ $info['matroska']['tags'] = $tags_entry;
+ break;
+
+ case EBML_ID_ATTACHMENTS: // Contain attached files.
+
+ while ($this->getEBMLelement($subelement, $element_data['end'])) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_ATTACHEDFILE:
+ $attachedfile_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_FILEDESCRIPTION:
+ case EBML_ID_FILENAME:
+ case EBML_ID_FILEMIMETYPE:
+ $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data'];
+ break;
+
+ case EBML_ID_FILEDATA:
+ $attachedfile_entry['data_offset'] = $this->current_offset;
+ $attachedfile_entry['data_length'] = $sub_subelement['length'];
+
+ $attachedfile_entry[$sub_subelement['id_name']] = $this->saveAttachment(
+ $attachedfile_entry['FileName'],
+ $attachedfile_entry['data_offset'],
+ $attachedfile_entry['data_length']);
+
+ $this->current_offset = $sub_subelement['end'];
+ break;
+
+ case EBML_ID_FILEUID:
+ $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
+ }
+ }
+ $info['matroska']['attachments'][] = $attachedfile_entry;
+ break;
+
+ default:
+ $this->unhandledElement('attachments', __LINE__, $subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CHAPTERS:
+
+ while ($this->getEBMLelement($subelement, $element_data['end'])) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_EDITIONENTRY:
+ $editionentry_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_EDITIONUID:
+ $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_EDITIONFLAGHIDDEN:
+ case EBML_ID_EDITIONFLAGDEFAULT:
+ case EBML_ID_EDITIONFLAGORDERED:
+ $editionentry_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERATOM:
+ $chapteratom_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_CHAPTERSEGMENTUID:
+ case EBML_ID_CHAPTERSEGMENTEDITIONUID:
+ $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
+ break;
+
+ case EBML_ID_CHAPTERFLAGENABLED:
+ case EBML_ID_CHAPTERFLAGHIDDEN:
+ $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERUID:
+ case EBML_ID_CHAPTERTIMESTART:
+ case EBML_ID_CHAPTERTIMEEND:
+ $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERTRACK:
+ $chaptertrack_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CHAPTERTRACKNUMBER:
+ $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
+ break;
+
+ case EBML_ID_CHAPTERDISPLAY:
+ $chapterdisplay_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CHAPSTRING:
+ case EBML_ID_CHAPLANGUAGE:
+ case EBML_ID_CHAPCOUNTRY:
+ $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
+ }
+ }
+ $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
+ }
+ }
+ $info['matroska']['chapters'][] = $editionentry_entry;
+ break;
+
+ default:
+ $this->unhandledElement('chapters', __LINE__, $subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure.
+ $cluster_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_CLUSTERTIMECODE:
+ case EBML_ID_CLUSTERPOSITION:
+ case EBML_ID_CLUSTERPREVSIZE:
+ $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_CLUSTERSILENTTRACKS:
+ $cluster_silent_tracks = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CLUSTERSILENTTRACKNUMBER:
+ $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
+ }
+ }
+ $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
+ break;
+
+ case EBML_ID_CLUSTERBLOCKGROUP:
+ $cluster_block_group = array('offset' => $this->current_offset);
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CLUSTERBLOCK:
+ $cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info);
+ break;
+
+ case EBML_ID_CLUSTERREFERENCEPRIORITY: // unsigned-int
+ case EBML_ID_CLUSTERBLOCKDURATION: // unsigned-int
+ $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CLUSTERREFERENCEBLOCK: // signed-int
+ $cluster_block_group[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data'], false, true);
+ break;
+
+ case EBML_ID_CLUSTERCODECSTATE:
+ $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement);
+ }
+ }
+ $cluster_entry[$subelement['id_name']][] = $cluster_block_group;
+ break;
+
+ case EBML_ID_CLUSTERSIMPLEBLOCK:
+ $cluster_entry[$subelement['id_name']][] = $this->HandleEMBLClusterBlock($subelement, EBML_ID_CLUSTERSIMPLEBLOCK, $info);
+ break;
+
+ default:
+ $this->unhandledElement('cluster', __LINE__, $subelement);
+ }
+ $this->current_offset = $subelement['end'];
+ }
+ if (!self::$hide_clusters) {
+ $info['matroska']['cluster'][] = $cluster_entry;
+ }
+
+ // check to see if all the data we need exists already, if so, break out of the loop
+ if (!self::$parse_whole_file) {
+ if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
+ if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
+ if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) {
+ return;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('segment', __LINE__, $element_data);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('root', __LINE__, $top_element);
+ }
+ }
+ }
+
+ private function EnsureBufferHasEnoughData($min_data=1024) {
+ if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
+ $read_bytes = max($min_data, $this->getid3->fread_buffer_size());
+
+ try {
+ $this->fseek($this->current_offset);
+ $this->EBMLbuffer_offset = $this->current_offset;
+ $this->EBMLbuffer = $this->fread($read_bytes);
+ $this->EBMLbuffer_length = strlen($this->EBMLbuffer);
+ } catch (getid3_exception $e) {
+ $this->warning('EBML parser: '.$e->getMessage());
+ return false;
+ }
+
+ if ($this->EBMLbuffer_length == 0 && $this->feof()) {
+ return $this->error('EBML parser: ran out of file at offset '.$this->current_offset);
+ }
+ }
+ return true;
+ }
+
+ private function readEBMLint() {
+ $actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
+
+ // get length of integer
+ $first_byte_int = ord($this->EBMLbuffer[$actual_offset]);
+ if (0x80 & $first_byte_int) {
+ $length = 1;
+ } elseif (0x40 & $first_byte_int) {
+ $length = 2;
+ } elseif (0x20 & $first_byte_int) {
+ $length = 3;
+ } elseif (0x10 & $first_byte_int) {
+ $length = 4;
+ } elseif (0x08 & $first_byte_int) {
+ $length = 5;
+ } elseif (0x04 & $first_byte_int) {
+ $length = 6;
+ } elseif (0x02 & $first_byte_int) {
+ $length = 7;
+ } elseif (0x01 & $first_byte_int) {
+ $length = 8;
+ } else {
+ throw new Exception('invalid EBML integer (leading 0x00) at '.$this->current_offset);
+ }
+
+ // read
+ $int_value = self::EBML2Int(substr($this->EBMLbuffer, $actual_offset, $length));
+ $this->current_offset += $length;
+
+ return $int_value;
+ }
+
+ private function readEBMLelementData($length, $check_buffer=false) {
+ if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
+ return false;
+ }
+ $data = substr($this->EBMLbuffer, $this->current_offset - $this->EBMLbuffer_offset, $length);
+ $this->current_offset += $length;
+ return $data;
+ }
+
+ private function getEBMLelement(&$element, $parent_end, $get_data=false) {
+ if ($this->current_offset >= $parent_end) {
+ return false;
+ }
+
+ if (!$this->EnsureBufferHasEnoughData()) {
+ $this->current_offset = PHP_INT_MAX; // do not exit parser right now, allow to finish current loop to gather maximum information
+ return false;
+ }
+
+ $element = array();
+
+ // set offset
+ $element['offset'] = $this->current_offset;
+
+ // get ID
+ $element['id'] = $this->readEBMLint();
+
+ // get name
+ $element['id_name'] = self::EBMLidName($element['id']);
+
+ // get length
+ $element['length'] = $this->readEBMLint();
+
+ // get end offset
+ $element['end'] = $this->current_offset + $element['length'];
+
+ // get raw data
+ $dont_parse = (in_array($element['id'], $this->unuseful_elements) || $element['id_name'] == dechex($element['id']));
+ if (($get_data === true || (is_array($get_data) && !in_array($element['id'], $get_data))) && !$dont_parse) {
+ $element['data'] = $this->readEBMLelementData($element['length'], $element);
+ }
+
+ return true;
+ }
+
+ private function unhandledElement($type, $line, $element) {
+ // warn only about unknown and missed elements, not about unuseful
+ if (!in_array($element['id'], $this->unuseful_elements)) {
+ $this->warning('Unhandled '.$type.' element ['.basename(__FILE__).':'.$line.'] ('.$element['id'].'::'.$element['id_name'].' ['.$element['length'].' bytes]) at '.$element['offset']);
+ }
+
+ // increase offset for unparsed elements
+ if (!isset($element['data'])) {
+ $this->current_offset = $element['end'];
+ }
+ }
+
+ private function ExtractCommentsSimpleTag($SimpleTagArray) {
+ if (!empty($SimpleTagArray['SimpleTag'])) {
+ foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
+ if (!empty($SimpleTagData['TagName']) && !empty($SimpleTagData['TagString'])) {
+ $this->getid3->info['matroska']['comments'][strtolower($SimpleTagData['TagName'])][] = $SimpleTagData['TagString'];
+ }
+ if (!empty($SimpleTagData['SimpleTag'])) {
+ $this->ExtractCommentsSimpleTag($SimpleTagData);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private function HandleEMBLSimpleTag($parent_end) {
+ $simpletag_entry = array();
+
+ while ($this->getEBMLelement($element, $parent_end, array(EBML_ID_SIMPLETAG))) {
+ switch ($element['id']) {
+
+ case EBML_ID_TAGNAME:
+ case EBML_ID_TAGLANGUAGE:
+ case EBML_ID_TAGSTRING:
+ case EBML_ID_TAGBINARY:
+ $simpletag_entry[$element['id_name']] = $element['data'];
+ break;
+
+ case EBML_ID_SIMPLETAG:
+ $simpletag_entry[$element['id_name']][] = $this->HandleEMBLSimpleTag($element['end']);
+ break;
+
+ case EBML_ID_TAGDEFAULT:
+ $simpletag_entry[$element['id_name']] = (bool)getid3_lib::BigEndian2Int($element['data']);
+ break;
+
+ default:
+ $this->unhandledElement('tag.simpletag', __LINE__, $element);
+ }
+ }
+
+ return $simpletag_entry;
+ }
+
+ private function HandleEMBLClusterBlock($element, $block_type, &$info) {
+ // http://www.matroska.org/technical/specs/index.html#block_structure
+ // http://www.matroska.org/technical/specs/index.html#simpleblock_structure
+
+ $block_data = array();
+ $block_data['tracknumber'] = $this->readEBMLint();
+ $block_data['timecode'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(2), false, true);
+ $block_data['flags_raw'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
+
+ if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
+ $block_data['flags']['keyframe'] = (($block_data['flags_raw'] & 0x80) >> 7);
+ //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0x70) >> 4);
+ }
+ else {
+ //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0xF0) >> 4);
+ }
+ $block_data['flags']['invisible'] = (bool)(($block_data['flags_raw'] & 0x08) >> 3);
+ $block_data['flags']['lacing'] = (($block_data['flags_raw'] & 0x06) >> 1); // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing
+ if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
+ $block_data['flags']['discardable'] = (($block_data['flags_raw'] & 0x01));
+ }
+ else {
+ //$block_data['flags']['reserved2'] = (($block_data['flags_raw'] & 0x01) >> 0);
+ }
+ $block_data['flags']['lacing_type'] = self::BlockLacingType($block_data['flags']['lacing']);
+
+ // Lace (when lacing bit is set)
+ if ($block_data['flags']['lacing'] > 0) {
+ $block_data['lace_frames'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)) + 1; // Number of frames in the lace-1 (uint8)
+ if ($block_data['flags']['lacing'] != 0x02) {
+ for ($i = 1; $i < $block_data['lace_frames']; $i ++) { // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
+ if ($block_data['flags']['lacing'] == 0x03) { // EBML lacing
+ $block_data['lace_frames_size'][$i] = $this->readEBMLint(); // TODO: read size correctly, calc size for the last frame. For now offsets are deteminded OK with readEBMLint() and that's the most important thing.
+ }
+ else { // Xiph lacing
+ $block_data['lace_frames_size'][$i] = 0;
+ do {
+ $size = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
+ $block_data['lace_frames_size'][$i] += $size;
+ }
+ while ($size == 255);
+ }
+ }
+ if ($block_data['flags']['lacing'] == 0x01) { // calc size of the last frame only for Xiph lacing, till EBML sizes are now anyway determined incorrectly
+ $block_data['lace_frames_size'][] = $element['end'] - $this->current_offset - array_sum($block_data['lace_frames_size']);
+ }
+ }
+ }
+
+ if (!isset($info['matroska']['track_data_offsets'][$block_data['tracknumber']])) {
+ $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['offset'] = $this->current_offset;
+ $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'] = $element['end'] - $this->current_offset;
+ //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] = 0;
+ }
+ //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] += $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'];
+ //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['duration'] = $block_data['timecode'] * ((isset($info['matroska']['info'][0]['TimecodeScale']) ? $info['matroska']['info'][0]['TimecodeScale'] : 1000000) / 1000000000);
+
+ // set offset manually
+ $this->current_offset = $element['end'];
+
+ return $block_data;
+ }
+
+ private static function EBML2Int($EBMLstring) {
+ // http://matroska.org/specs/
+
+ // Element ID coded with an UTF-8 like system:
+ // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X)
+ // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX)
+ // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX)
+ // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX)
+ // Values with all x at 0 and 1 are reserved (hence the -2).
+
+ // Data size, in octets, is also coded with an UTF-8 like system :
+ // 1xxx xxxx - value 0 to 2^7-2
+ // 01xx xxxx xxxx xxxx - value 0 to 2^14-2
+ // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2
+ // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2
+ // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2
+ // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2
+ // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2
+ // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2
+
+ $first_byte_int = ord($EBMLstring[0]);
+ if (0x80 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x7F);
+ } elseif (0x40 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x3F);
+ } elseif (0x20 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x1F);
+ } elseif (0x10 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x0F);
+ } elseif (0x08 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x07);
+ } elseif (0x04 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x03);
+ } elseif (0x02 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x01);
+ } elseif (0x01 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x00);
+ }
+
+ return getid3_lib::BigEndian2Int($EBMLstring);
+ }
+
+ private static function EBMLdate2unix($EBMLdatestamp) {
+ // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
+ // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
+ return round(($EBMLdatestamp / 1000000000) + 978307200);
+ }
+
+ public static function TargetTypeValue($target_type) {
+ // http://www.matroska.org/technical/specs/tagging/index.html
+ static $TargetTypeValue = array();
+ if (empty($TargetTypeValue)) {
+ $TargetTypeValue[10] = 'A: ~ V:shot'; // the lowest hierarchy found in music or movies
+ $TargetTypeValue[20] = 'A:subtrack/part/movement ~ V:scene'; // corresponds to parts of a track for audio (like a movement)
+ $TargetTypeValue[30] = 'A:track/song ~ V:chapter'; // the common parts of an album or a movie
+ $TargetTypeValue[40] = 'A:part/session ~ V:part/session'; // when an album or episode has different logical parts
+ $TargetTypeValue[50] = 'A:album/opera/concert ~ V:movie/episode/concert'; // the most common grouping level of music and video (equals to an episode for TV series)
+ $TargetTypeValue[60] = 'A:edition/issue/volume/opus ~ V:season/sequel/volume'; // a list of lower levels grouped together
+ $TargetTypeValue[70] = 'A:collection ~ V:collection'; // the high hierarchy consisting of many different lower items
+ }
+ return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
+ }
+
+ public static function BlockLacingType($lacingtype) {
+ // http://matroska.org/technical/specs/index.html#block_structure
+ static $BlockLacingType = array();
+ if (empty($BlockLacingType)) {
+ $BlockLacingType[0x00] = 'no lacing';
+ $BlockLacingType[0x01] = 'Xiph lacing';
+ $BlockLacingType[0x02] = 'fixed-size lacing';
+ $BlockLacingType[0x03] = 'EBML lacing';
+ }
+ return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
+ }
+
+ public static function CodecIDtoCommonName($codecid) {
+ // http://www.matroska.org/technical/specs/codecid/index.html
+ static $CodecIDlist = array();
+ if (empty($CodecIDlist)) {
+ $CodecIDlist['A_AAC'] = 'aac';
+ $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac';
+ $CodecIDlist['A_AC3'] = 'ac3';
+ $CodecIDlist['A_DTS'] = 'dts';
+ $CodecIDlist['A_FLAC'] = 'flac';
+ $CodecIDlist['A_MPEG/L1'] = 'mp1';
+ $CodecIDlist['A_MPEG/L2'] = 'mp2';
+ $CodecIDlist['A_MPEG/L3'] = 'mp3';
+ $CodecIDlist['A_PCM/INT/LIT'] = 'pcm'; // PCM Integer Little Endian
+ $CodecIDlist['A_PCM/INT/BIG'] = 'pcm'; // PCM Integer Big Endian
+ $CodecIDlist['A_QUICKTIME/QDMC'] = 'quicktime'; // Quicktime: QDesign Music
+ $CodecIDlist['A_QUICKTIME/QDM2'] = 'quicktime'; // Quicktime: QDesign Music v2
+ $CodecIDlist['A_VORBIS'] = 'vorbis';
+ $CodecIDlist['V_MPEG1'] = 'mpeg';
+ $CodecIDlist['V_THEORA'] = 'theora';
+ $CodecIDlist['V_REAL/RV40'] = 'real';
+ $CodecIDlist['V_REAL/RV10'] = 'real';
+ $CodecIDlist['V_REAL/RV20'] = 'real';
+ $CodecIDlist['V_REAL/RV30'] = 'real';
+ $CodecIDlist['V_QUICKTIME'] = 'quicktime'; // Quicktime
+ $CodecIDlist['V_MPEG4/ISO/AP'] = 'mpeg4';
+ $CodecIDlist['V_MPEG4/ISO/ASP'] = 'mpeg4';
+ $CodecIDlist['V_MPEG4/ISO/AVC'] = 'h264';
+ $CodecIDlist['V_MPEG4/ISO/SP'] = 'mpeg4';
+ $CodecIDlist['V_VP8'] = 'vp8';
+ $CodecIDlist['V_MS/VFW/FOURCC'] = 'riff';
+ $CodecIDlist['A_MS/ACM'] = 'riff';
+ }
+ return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
+ }
+
+ private static function EBMLidName($value) {
+ static $EBMLidList = array();
+ if (empty($EBMLidList)) {
+ $EBMLidList[EBML_ID_ASPECTRATIOTYPE] = 'AspectRatioType';
+ $EBMLidList[EBML_ID_ATTACHEDFILE] = 'AttachedFile';
+ $EBMLidList[EBML_ID_ATTACHMENTLINK] = 'AttachmentLink';
+ $EBMLidList[EBML_ID_ATTACHMENTS] = 'Attachments';
+ $EBMLidList[EBML_ID_AUDIO] = 'Audio';
+ $EBMLidList[EBML_ID_BITDEPTH] = 'BitDepth';
+ $EBMLidList[EBML_ID_CHANNELPOSITIONS] = 'ChannelPositions';
+ $EBMLidList[EBML_ID_CHANNELS] = 'Channels';
+ $EBMLidList[EBML_ID_CHAPCOUNTRY] = 'ChapCountry';
+ $EBMLidList[EBML_ID_CHAPLANGUAGE] = 'ChapLanguage';
+ $EBMLidList[EBML_ID_CHAPPROCESS] = 'ChapProcess';
+ $EBMLidList[EBML_ID_CHAPPROCESSCODECID] = 'ChapProcessCodecID';
+ $EBMLidList[EBML_ID_CHAPPROCESSCOMMAND] = 'ChapProcessCommand';
+ $EBMLidList[EBML_ID_CHAPPROCESSDATA] = 'ChapProcessData';
+ $EBMLidList[EBML_ID_CHAPPROCESSPRIVATE] = 'ChapProcessPrivate';
+ $EBMLidList[EBML_ID_CHAPPROCESSTIME] = 'ChapProcessTime';
+ $EBMLidList[EBML_ID_CHAPSTRING] = 'ChapString';
+ $EBMLidList[EBML_ID_CHAPTERATOM] = 'ChapterAtom';
+ $EBMLidList[EBML_ID_CHAPTERDISPLAY] = 'ChapterDisplay';
+ $EBMLidList[EBML_ID_CHAPTERFLAGENABLED] = 'ChapterFlagEnabled';
+ $EBMLidList[EBML_ID_CHAPTERFLAGHIDDEN] = 'ChapterFlagHidden';
+ $EBMLidList[EBML_ID_CHAPTERPHYSICALEQUIV] = 'ChapterPhysicalEquiv';
+ $EBMLidList[EBML_ID_CHAPTERS] = 'Chapters';
+ $EBMLidList[EBML_ID_CHAPTERSEGMENTEDITIONUID] = 'ChapterSegmentEditionUID';
+ $EBMLidList[EBML_ID_CHAPTERSEGMENTUID] = 'ChapterSegmentUID';
+ $EBMLidList[EBML_ID_CHAPTERTIMEEND] = 'ChapterTimeEnd';
+ $EBMLidList[EBML_ID_CHAPTERTIMESTART] = 'ChapterTimeStart';
+ $EBMLidList[EBML_ID_CHAPTERTRACK] = 'ChapterTrack';
+ $EBMLidList[EBML_ID_CHAPTERTRACKNUMBER] = 'ChapterTrackNumber';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATE] = 'ChapterTranslate';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATECODEC] = 'ChapterTranslateCodec';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATEEDITIONUID] = 'ChapterTranslateEditionUID';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATEID] = 'ChapterTranslateID';
+ $EBMLidList[EBML_ID_CHAPTERUID] = 'ChapterUID';
+ $EBMLidList[EBML_ID_CLUSTER] = 'Cluster';
+ $EBMLidList[EBML_ID_CLUSTERBLOCK] = 'ClusterBlock';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDID] = 'ClusterBlockAddID';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONAL] = 'ClusterBlockAdditional';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONID] = 'ClusterBlockAdditionID';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONS] = 'ClusterBlockAdditions';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKDURATION] = 'ClusterBlockDuration';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKGROUP] = 'ClusterBlockGroup';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKMORE] = 'ClusterBlockMore';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKVIRTUAL] = 'ClusterBlockVirtual';
+ $EBMLidList[EBML_ID_CLUSTERCODECSTATE] = 'ClusterCodecState';
+ $EBMLidList[EBML_ID_CLUSTERDELAY] = 'ClusterDelay';
+ $EBMLidList[EBML_ID_CLUSTERDURATION] = 'ClusterDuration';
+ $EBMLidList[EBML_ID_CLUSTERENCRYPTEDBLOCK] = 'ClusterEncryptedBlock';
+ $EBMLidList[EBML_ID_CLUSTERFRAMENUMBER] = 'ClusterFrameNumber';
+ $EBMLidList[EBML_ID_CLUSTERLACENUMBER] = 'ClusterLaceNumber';
+ $EBMLidList[EBML_ID_CLUSTERPOSITION] = 'ClusterPosition';
+ $EBMLidList[EBML_ID_CLUSTERPREVSIZE] = 'ClusterPrevSize';
+ $EBMLidList[EBML_ID_CLUSTERREFERENCEBLOCK] = 'ClusterReferenceBlock';
+ $EBMLidList[EBML_ID_CLUSTERREFERENCEPRIORITY] = 'ClusterReferencePriority';
+ $EBMLidList[EBML_ID_CLUSTERREFERENCEVIRTUAL] = 'ClusterReferenceVirtual';
+ $EBMLidList[EBML_ID_CLUSTERSILENTTRACKNUMBER] = 'ClusterSilentTrackNumber';
+ $EBMLidList[EBML_ID_CLUSTERSILENTTRACKS] = 'ClusterSilentTracks';
+ $EBMLidList[EBML_ID_CLUSTERSIMPLEBLOCK] = 'ClusterSimpleBlock';
+ $EBMLidList[EBML_ID_CLUSTERTIMECODE] = 'ClusterTimecode';
+ $EBMLidList[EBML_ID_CLUSTERTIMESLICE] = 'ClusterTimeSlice';
+ $EBMLidList[EBML_ID_CODECDECODEALL] = 'CodecDecodeAll';
+ $EBMLidList[EBML_ID_CODECDOWNLOADURL] = 'CodecDownloadURL';
+ $EBMLidList[EBML_ID_CODECID] = 'CodecID';
+ $EBMLidList[EBML_ID_CODECINFOURL] = 'CodecInfoURL';
+ $EBMLidList[EBML_ID_CODECNAME] = 'CodecName';
+ $EBMLidList[EBML_ID_CODECPRIVATE] = 'CodecPrivate';
+ $EBMLidList[EBML_ID_CODECSETTINGS] = 'CodecSettings';
+ $EBMLidList[EBML_ID_COLOURSPACE] = 'ColourSpace';
+ $EBMLidList[EBML_ID_CONTENTCOMPALGO] = 'ContentCompAlgo';
+ $EBMLidList[EBML_ID_CONTENTCOMPRESSION] = 'ContentCompression';
+ $EBMLidList[EBML_ID_CONTENTCOMPSETTINGS] = 'ContentCompSettings';
+ $EBMLidList[EBML_ID_CONTENTENCALGO] = 'ContentEncAlgo';
+ $EBMLidList[EBML_ID_CONTENTENCKEYID] = 'ContentEncKeyID';
+ $EBMLidList[EBML_ID_CONTENTENCODING] = 'ContentEncoding';
+ $EBMLidList[EBML_ID_CONTENTENCODINGORDER] = 'ContentEncodingOrder';
+ $EBMLidList[EBML_ID_CONTENTENCODINGS] = 'ContentEncodings';
+ $EBMLidList[EBML_ID_CONTENTENCODINGSCOPE] = 'ContentEncodingScope';
+ $EBMLidList[EBML_ID_CONTENTENCODINGTYPE] = 'ContentEncodingType';
+ $EBMLidList[EBML_ID_CONTENTENCRYPTION] = 'ContentEncryption';
+ $EBMLidList[EBML_ID_CONTENTSIGALGO] = 'ContentSigAlgo';
+ $EBMLidList[EBML_ID_CONTENTSIGHASHALGO] = 'ContentSigHashAlgo';
+ $EBMLidList[EBML_ID_CONTENTSIGKEYID] = 'ContentSigKeyID';
+ $EBMLidList[EBML_ID_CONTENTSIGNATURE] = 'ContentSignature';
+ $EBMLidList[EBML_ID_CRC32] = 'CRC32';
+ $EBMLidList[EBML_ID_CUEBLOCKNUMBER] = 'CueBlockNumber';
+ $EBMLidList[EBML_ID_CUECLUSTERPOSITION] = 'CueClusterPosition';
+ $EBMLidList[EBML_ID_CUECODECSTATE] = 'CueCodecState';
+ $EBMLidList[EBML_ID_CUEPOINT] = 'CuePoint';
+ $EBMLidList[EBML_ID_CUEREFCLUSTER] = 'CueRefCluster';
+ $EBMLidList[EBML_ID_CUEREFCODECSTATE] = 'CueRefCodecState';
+ $EBMLidList[EBML_ID_CUEREFERENCE] = 'CueReference';
+ $EBMLidList[EBML_ID_CUEREFNUMBER] = 'CueRefNumber';
+ $EBMLidList[EBML_ID_CUEREFTIME] = 'CueRefTime';
+ $EBMLidList[EBML_ID_CUES] = 'Cues';
+ $EBMLidList[EBML_ID_CUETIME] = 'CueTime';
+ $EBMLidList[EBML_ID_CUETRACK] = 'CueTrack';
+ $EBMLidList[EBML_ID_CUETRACKPOSITIONS] = 'CueTrackPositions';
+ $EBMLidList[EBML_ID_DATEUTC] = 'DateUTC';
+ $EBMLidList[EBML_ID_DEFAULTDURATION] = 'DefaultDuration';
+ $EBMLidList[EBML_ID_DISPLAYHEIGHT] = 'DisplayHeight';
+ $EBMLidList[EBML_ID_DISPLAYUNIT] = 'DisplayUnit';
+ $EBMLidList[EBML_ID_DISPLAYWIDTH] = 'DisplayWidth';
+ $EBMLidList[EBML_ID_DOCTYPE] = 'DocType';
+ $EBMLidList[EBML_ID_DOCTYPEREADVERSION] = 'DocTypeReadVersion';
+ $EBMLidList[EBML_ID_DOCTYPEVERSION] = 'DocTypeVersion';
+ $EBMLidList[EBML_ID_DURATION] = 'Duration';
+ $EBMLidList[EBML_ID_EBML] = 'EBML';
+ $EBMLidList[EBML_ID_EBMLMAXIDLENGTH] = 'EBMLMaxIDLength';
+ $EBMLidList[EBML_ID_EBMLMAXSIZELENGTH] = 'EBMLMaxSizeLength';
+ $EBMLidList[EBML_ID_EBMLREADVERSION] = 'EBMLReadVersion';
+ $EBMLidList[EBML_ID_EBMLVERSION] = 'EBMLVersion';
+ $EBMLidList[EBML_ID_EDITIONENTRY] = 'EditionEntry';
+ $EBMLidList[EBML_ID_EDITIONFLAGDEFAULT] = 'EditionFlagDefault';
+ $EBMLidList[EBML_ID_EDITIONFLAGHIDDEN] = 'EditionFlagHidden';
+ $EBMLidList[EBML_ID_EDITIONFLAGORDERED] = 'EditionFlagOrdered';
+ $EBMLidList[EBML_ID_EDITIONUID] = 'EditionUID';
+ $EBMLidList[EBML_ID_FILEDATA] = 'FileData';
+ $EBMLidList[EBML_ID_FILEDESCRIPTION] = 'FileDescription';
+ $EBMLidList[EBML_ID_FILEMIMETYPE] = 'FileMimeType';
+ $EBMLidList[EBML_ID_FILENAME] = 'FileName';
+ $EBMLidList[EBML_ID_FILEREFERRAL] = 'FileReferral';
+ $EBMLidList[EBML_ID_FILEUID] = 'FileUID';
+ $EBMLidList[EBML_ID_FLAGDEFAULT] = 'FlagDefault';
+ $EBMLidList[EBML_ID_FLAGENABLED] = 'FlagEnabled';
+ $EBMLidList[EBML_ID_FLAGFORCED] = 'FlagForced';
+ $EBMLidList[EBML_ID_FLAGINTERLACED] = 'FlagInterlaced';
+ $EBMLidList[EBML_ID_FLAGLACING] = 'FlagLacing';
+ $EBMLidList[EBML_ID_GAMMAVALUE] = 'GammaValue';
+ $EBMLidList[EBML_ID_INFO] = 'Info';
+ $EBMLidList[EBML_ID_LANGUAGE] = 'Language';
+ $EBMLidList[EBML_ID_MAXBLOCKADDITIONID] = 'MaxBlockAdditionID';
+ $EBMLidList[EBML_ID_MAXCACHE] = 'MaxCache';
+ $EBMLidList[EBML_ID_MINCACHE] = 'MinCache';
+ $EBMLidList[EBML_ID_MUXINGAPP] = 'MuxingApp';
+ $EBMLidList[EBML_ID_NAME] = 'Name';
+ $EBMLidList[EBML_ID_NEXTFILENAME] = 'NextFilename';
+ $EBMLidList[EBML_ID_NEXTUID] = 'NextUID';
+ $EBMLidList[EBML_ID_OUTPUTSAMPLINGFREQUENCY] = 'OutputSamplingFrequency';
+ $EBMLidList[EBML_ID_PIXELCROPBOTTOM] = 'PixelCropBottom';
+ $EBMLidList[EBML_ID_PIXELCROPLEFT] = 'PixelCropLeft';
+ $EBMLidList[EBML_ID_PIXELCROPRIGHT] = 'PixelCropRight';
+ $EBMLidList[EBML_ID_PIXELCROPTOP] = 'PixelCropTop';
+ $EBMLidList[EBML_ID_PIXELHEIGHT] = 'PixelHeight';
+ $EBMLidList[EBML_ID_PIXELWIDTH] = 'PixelWidth';
+ $EBMLidList[EBML_ID_PREVFILENAME] = 'PrevFilename';
+ $EBMLidList[EBML_ID_PREVUID] = 'PrevUID';
+ $EBMLidList[EBML_ID_SAMPLINGFREQUENCY] = 'SamplingFrequency';
+ $EBMLidList[EBML_ID_SEEK] = 'Seek';
+ $EBMLidList[EBML_ID_SEEKHEAD] = 'SeekHead';
+ $EBMLidList[EBML_ID_SEEKID] = 'SeekID';
+ $EBMLidList[EBML_ID_SEEKPOSITION] = 'SeekPosition';
+ $EBMLidList[EBML_ID_SEGMENT] = 'Segment';
+ $EBMLidList[EBML_ID_SEGMENTFAMILY] = 'SegmentFamily';
+ $EBMLidList[EBML_ID_SEGMENTFILENAME] = 'SegmentFilename';
+ $EBMLidList[EBML_ID_SEGMENTUID] = 'SegmentUID';
+ $EBMLidList[EBML_ID_SIMPLETAG] = 'SimpleTag';
+ $EBMLidList[EBML_ID_CLUSTERSLICES] = 'ClusterSlices';
+ $EBMLidList[EBML_ID_STEREOMODE] = 'StereoMode';
+ $EBMLidList[EBML_ID_OLDSTEREOMODE] = 'OldStereoMode';
+ $EBMLidList[EBML_ID_TAG] = 'Tag';
+ $EBMLidList[EBML_ID_TAGATTACHMENTUID] = 'TagAttachmentUID';
+ $EBMLidList[EBML_ID_TAGBINARY] = 'TagBinary';
+ $EBMLidList[EBML_ID_TAGCHAPTERUID] = 'TagChapterUID';
+ $EBMLidList[EBML_ID_TAGDEFAULT] = 'TagDefault';
+ $EBMLidList[EBML_ID_TAGEDITIONUID] = 'TagEditionUID';
+ $EBMLidList[EBML_ID_TAGLANGUAGE] = 'TagLanguage';
+ $EBMLidList[EBML_ID_TAGNAME] = 'TagName';
+ $EBMLidList[EBML_ID_TAGTRACKUID] = 'TagTrackUID';
+ $EBMLidList[EBML_ID_TAGS] = 'Tags';
+ $EBMLidList[EBML_ID_TAGSTRING] = 'TagString';
+ $EBMLidList[EBML_ID_TARGETS] = 'Targets';
+ $EBMLidList[EBML_ID_TARGETTYPE] = 'TargetType';
+ $EBMLidList[EBML_ID_TARGETTYPEVALUE] = 'TargetTypeValue';
+ $EBMLidList[EBML_ID_TIMECODESCALE] = 'TimecodeScale';
+ $EBMLidList[EBML_ID_TITLE] = 'Title';
+ $EBMLidList[EBML_ID_TRACKENTRY] = 'TrackEntry';
+ $EBMLidList[EBML_ID_TRACKNUMBER] = 'TrackNumber';
+ $EBMLidList[EBML_ID_TRACKOFFSET] = 'TrackOffset';
+ $EBMLidList[EBML_ID_TRACKOVERLAY] = 'TrackOverlay';
+ $EBMLidList[EBML_ID_TRACKS] = 'Tracks';
+ $EBMLidList[EBML_ID_TRACKTIMECODESCALE] = 'TrackTimecodeScale';
+ $EBMLidList[EBML_ID_TRACKTRANSLATE] = 'TrackTranslate';
+ $EBMLidList[EBML_ID_TRACKTRANSLATECODEC] = 'TrackTranslateCodec';
+ $EBMLidList[EBML_ID_TRACKTRANSLATEEDITIONUID] = 'TrackTranslateEditionUID';
+ $EBMLidList[EBML_ID_TRACKTRANSLATETRACKID] = 'TrackTranslateTrackID';
+ $EBMLidList[EBML_ID_TRACKTYPE] = 'TrackType';
+ $EBMLidList[EBML_ID_TRACKUID] = 'TrackUID';
+ $EBMLidList[EBML_ID_VIDEO] = 'Video';
+ $EBMLidList[EBML_ID_VOID] = 'Void';
+ $EBMLidList[EBML_ID_WRITINGAPP] = 'WritingApp';
+ }
+
+ return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
+ }
+
+ public static function displayUnit($value) {
+ // http://www.matroska.org/technical/specs/index.html#DisplayUnit
+ static $units = array(
+ 0 => 'pixels',
+ 1 => 'centimeters',
+ 2 => 'inches',
+ 3 => 'Display Aspect Ratio');
+
+ return (isset($units[$value]) ? $units[$value] : 'unknown');
+ }
+
+ private static function getDefaultStreamInfo($streams)
+ {
+ foreach (array_reverse($streams) as $stream) {
+ if ($stream['default']) {
+ break;
+ }
+ }
+
+ $unset = array('default', 'name');
+ foreach ($unset as $u) {
+ if (isset($stream[$u])) {
+ unset($stream[$u]);
+ }
+ }
+
+ $info = $stream;
+ $info['streams'] = $streams;
+
+ return $info;
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio-video.quicktime.php b/src/wp-includes/ID3/module.audio-video.quicktime.php
new file mode 100644
index 0000000000..1b5ad5f042
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio-video.quicktime.php
@@ -0,0 +1,2221 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.quicktime.php //
+// module for analyzing Quicktime and MP3-in-MP4 files //
+// dependencies: module.audio.mp3.php //
+// dependencies: module.tag.id3v2.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup
+
+class getid3_quicktime extends getid3_handler
+{
+
+ public $ReturnAtomData = true;
+ public $ParseAllPossibleAtoms = false;
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'quicktime';
+ $info['quicktime']['hinting'] = false;
+ $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
+
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ $offset = 0;
+ $atomcounter = 0;
+
+ while ($offset < $info['avdataend']) {
+ if (!getid3_lib::intValueSupported($offset)) {
+ $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
+ break;
+ }
+ fseek($this->getid3->fp, $offset, SEEK_SET);
+ $AtomHeader = fread($this->getid3->fp, 8);
+
+ $atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
+ $atomname = substr($AtomHeader, 4, 4);
+
+ // 64-bit MOV patch by jlegateØktnc*com
+ if ($atomsize == 1) {
+ $atomsize = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 8));
+ }
+
+ $info['quicktime'][$atomname]['name'] = $atomname;
+ $info['quicktime'][$atomname]['size'] = $atomsize;
+ $info['quicktime'][$atomname]['offset'] = $offset;
+
+ if (($offset + $atomsize) > $info['avdataend']) {
+ $info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';
+ return false;
+ }
+
+ if ($atomsize == 0) {
+ // Furthermore, for historical reasons the list of atoms is optionally
+ // terminated by a 32-bit integer set to 0. If you are writing a program
+ // to read user data atoms, you should allow for the terminating 0.
+ break;
+ }
+ switch ($atomname) {
+ case 'mdat': // Media DATa atom
+ // 'mdat' contains the actual data for the audio/video
+ if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
+
+ $info['avdataoffset'] = $info['quicktime'][$atomname]['offset'] + 8;
+ $OldAVDataEnd = $info['avdataend'];
+ $info['avdataend'] = $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
+
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode(fread($this->getid3->fp, 4)))) {
+ $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $value) {
+ $info['warning'][] = $value;
+ }
+ }
+ if (!empty($getid3_temp->info['mpeg'])) {
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
+ if (isset($info['mpeg']['audio'])) {
+ $info['audio']['dataformat'] = 'mp3';
+ $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ $info['bitrate'] = $info['audio']['bitrate'];
+ }
+ }
+ }
+ unset($getid3_mp3, $getid3_temp);
+ $info['avdataend'] = $OldAVDataEnd;
+ unset($OldAVDataEnd);
+
+ }
+ break;
+
+ case 'free': // FREE space atom
+ case 'skip': // SKIP atom
+ case 'wide': // 64-bit expansion placeholder atom
+ // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
+ break;
+
+ default:
+ $atomHierarchy = array();
+ $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, fread($this->getid3->fp, $atomsize), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
+ break;
+ }
+
+ $offset += $atomsize;
+ $atomcounter++;
+ }
+
+ if (!empty($info['avdataend_tmp'])) {
+ // this value is assigned to a temp value and then erased because
+ // otherwise any atoms beyond the 'mdat' atom would not get parsed
+ $info['avdataend'] = $info['avdataend_tmp'];
+ unset($info['avdataend_tmp']);
+ }
+
+ if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
+ $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+ }
+ if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
+ $info['audio']['bitrate'] = $info['bitrate'];
+ }
+ if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
+ foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
+ $samples_per_second = $samples_count / $info['playtime_seconds'];
+ if ($samples_per_second > 240) {
+ // has to be audio samples
+ } else {
+ $info['video']['frame_rate'] = $samples_per_second;
+ break;
+ }
+ }
+ }
+ if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {
+ $info['fileformat'] = 'mp4';
+ $info['mime_type'] = 'audio/mp4';
+ unset($info['video']['dataformat']);
+ }
+
+ if (!$this->ReturnAtomData) {
+ unset($info['quicktime']['moov']);
+ }
+
+ if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) {
+ $info['audio']['dataformat'] = 'quicktime';
+ }
+ if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
+ $info['video']['dataformat'] = 'quicktime';
+ }
+
+ return true;
+ }
+
+ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
+ // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
+
+ $info = &$this->getid3->info;
+
+ //$atom_parent = array_pop($atomHierarchy);
+ $atom_parent = end($atomHierarchy); // http://www.getid3.org/phpBB3/viewtopic.php?t=1717
+ array_push($atomHierarchy, $atomname);
+ $atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
+ $atom_structure['name'] = $atomname;
+ $atom_structure['size'] = $atomsize;
+ $atom_structure['offset'] = $baseoffset;
+//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
+//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
+ switch ($atomname) {
+ case 'moov': // MOVie container atom
+ case 'trak': // TRAcK container atom
+ case 'clip': // CLIPping container atom
+ case 'matt': // track MATTe container atom
+ case 'edts': // EDiTS container atom
+ case 'tref': // Track REFerence container atom
+ case 'mdia': // MeDIA container atom
+ case 'minf': // Media INFormation container atom
+ case 'dinf': // Data INFormation container atom
+ case 'udta': // User DaTA container atom
+ case 'cmov': // Compressed MOVie container atom
+ case 'rmra': // Reference Movie Record Atom
+ case 'rmda': // Reference Movie Descriptor Atom
+ case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+
+ case 'ilst': // Item LiST container atom
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+
+ // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
+ $allnumericnames = true;
+ foreach ($atom_structure['subatoms'] as $subatomarray) {
+ if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
+ $allnumericnames = false;
+ break;
+ }
+ }
+ if ($allnumericnames) {
+ $newData = array();
+ foreach ($atom_structure['subatoms'] as $subatomarray) {
+ foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
+ unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
+ $newData[$subatomarray['name']] = $newData_subatomarray;
+ break;
+ }
+ }
+ $atom_structure['data'] = $newData;
+ unset($atom_structure['subatoms']);
+ }
+ break;
+
+ case "\x00\x00\x00\x01":
+ case "\x00\x00\x00\x02":
+ case "\x00\x00\x00\x03":
+ case "\x00\x00\x00\x04":
+ case "\x00\x00\x00\x05":
+ $atomname = getid3_lib::BigEndian2Int($atomname);
+ $atom_structure['name'] = $atomname;
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+
+ case 'stbl': // Sample TaBLe container atom
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ $isVideo = false;
+ $framerate = 0;
+ $framecount = 0;
+ foreach ($atom_structure['subatoms'] as $key => $value_array) {
+ if (isset($value_array['sample_description_table'])) {
+ foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
+ if (isset($value_array2['data_format'])) {
+ switch ($value_array2['data_format']) {
+ case 'avc1':
+ case 'mp4v':
+ // video data
+ $isVideo = true;
+ break;
+ case 'mp4a':
+ // audio data
+ break;
+ }
+ }
+ }
+ } elseif (isset($value_array['time_to_sample_table'])) {
+ foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
+ if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
+ $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
+ $framecount = $value_array2['sample_count'];
+ }
+ }
+ }
+ }
+ if ($isVideo && $framerate) {
+ $info['quicktime']['video']['frame_rate'] = $framerate;
+ $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
+ }
+ if ($isVideo && $framecount) {
+ $info['quicktime']['video']['frame_count'] = $framecount;
+ }
+ break;
+
+
+ case 'aART': // Album ARTist
+ case 'catg': // CaTeGory
+ case 'covr': // COVeR artwork
+ case 'cpil': // ComPILation
+ case 'cprt': // CoPyRighT
+ case 'desc': // DESCription
+ case 'disk': // DISK number
+ case 'egid': // Episode Global ID
+ case 'gnre': // GeNRE
+ case 'keyw': // KEYWord
+ case 'ldes':
+ case 'pcst': // PodCaST
+ case 'pgap': // GAPless Playback
+ case 'purd': // PURchase Date
+ case 'purl': // Podcast URL
+ case 'rati':
+ case 'rndu':
+ case 'rpdu':
+ case 'rtng': // RaTiNG
+ case 'stik':
+ case 'tmpo': // TeMPO (BPM)
+ case 'trkn': // TRacK Number
+ case 'tves': // TV EpiSode
+ case 'tvnn': // TV Network Name
+ case 'tvsh': // TV SHow Name
+ case 'tvsn': // TV SeasoN
+ case 'akID': // iTunes store account type
+ case 'apID':
+ case 'atID':
+ case 'cmID':
+ case 'cnID':
+ case 'geID':
+ case 'plID':
+ case 'sfID': // iTunes store country
+ case '©alb': // ALBum
+ case '©art': // ARTist
+ case '©ART':
+ case '©aut':
+ case '©cmt': // CoMmenT
+ case '©com': // COMposer
+ case '©cpy':
+ case '©day': // content created year
+ case '©dir':
+ case '©ed1':
+ case '©ed2':
+ case '©ed3':
+ case '©ed4':
+ case '©ed5':
+ case '©ed6':
+ case '©ed7':
+ case '©ed8':
+ case '©ed9':
+ case '©enc':
+ case '©fmt':
+ case '©gen': // GENre
+ case '©grp': // GRouPing
+ case '©hst':
+ case '©inf':
+ case '©lyr': // LYRics
+ case '©mak':
+ case '©mod':
+ case '©nam': // full NAMe
+ case '©ope':
+ case '©PRD':
+ case '©prd':
+ case '©prf':
+ case '©req':
+ case '©src':
+ case '©swr':
+ case '©too': // encoder
+ case '©trk': // TRacK
+ case '©url':
+ case '©wrn':
+ case '©wrt': // WRiTer
+ case '----': // itunes specific
+ if ($atom_parent == 'udta') {
+ // User data atom handler
+ $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
+ $atom_structure['data'] = substr($atom_data, 4);
+
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
+ $info['comments']['language'][] = $atom_structure['language'];
+ }
+ } else {
+ // Apple item list box atom handler
+ $atomoffset = 0;
+ if (substr($atom_data, 2, 2) == "\x10\xB5") {
+ // not sure what it means, but observed on iPhone4 data.
+ // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
+ while ($atomoffset < strlen($atom_data)) {
+ $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2));
+ $boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
+ $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
+ if ($boxsmallsize <= 1) {
+ $info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset);
+ $atom_structure['data'] = null;
+ $atomoffset = strlen($atom_data);
+ break;
+ }
+ switch ($boxsmalltype) {
+ case "\x10\xB5":
+ $atom_structure['data'] = $boxsmalldata;
+ break;
+ default:
+ $info['warning'][] = 'Unknown QuickTime smallbox type: "'.getid3_lib::PrintHexBytes($boxsmalltype).'" at offset '.$baseoffset;
+ $atom_structure['data'] = $atom_data;
+ break;
+ }
+ $atomoffset += (4 + $boxsmallsize);
+ }
+ } else {
+ while ($atomoffset < strlen($atom_data)) {
+ $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
+ $boxtype = substr($atom_data, $atomoffset + 4, 4);
+ $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
+ if ($boxsize <= 1) {
+ $info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset);
+ $atom_structure['data'] = null;
+ $atomoffset = strlen($atom_data);
+ break;
+ }
+ $atomoffset += $boxsize;
+
+ switch ($boxtype) {
+ case 'mean':
+ case 'name':
+ $atom_structure[$boxtype] = substr($boxdata, 4);
+ break;
+
+ case 'data':
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3));
+ switch ($atom_structure['flags_raw']) {
+ case 0: // data flag
+ case 21: // tmpo/cpil flag
+ switch ($atomname) {
+ case 'cpil':
+ case 'pcst':
+ case 'pgap':
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
+ break;
+
+ case 'tmpo':
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
+ break;
+
+ case 'disk':
+ case 'trkn':
+ $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
+ $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
+ $atom_structure['data'] = empty($num) ? '' : $num;
+ $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
+ break;
+
+ case 'gnre':
+ $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
+ $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
+ break;
+
+ case 'rtng':
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
+ $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
+ break;
+
+ case 'stik':
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
+ $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
+ break;
+
+ case 'sfID':
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
+ $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
+ break;
+
+ case 'egid':
+ case 'purl':
+ $atom_structure['data'] = substr($boxdata, 8);
+ break;
+
+ default:
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
+ }
+ break;
+
+ case 1: // text flag
+ case 13: // image flag
+ default:
+ $atom_structure['data'] = substr($boxdata, 8);
+ break;
+
+ }
+ break;
+
+ default:
+ $info['warning'][] = 'Unknown QuickTime box type: "'.getid3_lib::PrintHexBytes($boxtype).'" at offset '.$baseoffset;
+ $atom_structure['data'] = $atom_data;
+
+ }
+ }
+ }
+ }
+ $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
+ break;
+
+
+ case 'play': // auto-PLAY atom
+ $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+
+ $info['quicktime']['autoplay'] = $atom_structure['autoplay'];
+ break;
+
+
+ case 'WLOC': // Window LOCation atom
+ $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
+ $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
+ break;
+
+
+ case 'LOOP': // LOOPing atom
+ case 'SelO': // play SELection Only atom
+ case 'AllF': // play ALL Frames atom
+ $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
+ break;
+
+
+ case 'name': //
+ case 'MCPS': // Media Cleaner PRo
+ case '@PRM': // adobe PReMiere version
+ case '@PRQ': // adobe PRemiere Quicktime version
+ $atom_structure['data'] = $atom_data;
+ break;
+
+
+ case 'cmvd': // Compressed MooV Data atom
+ // Code by ubergeekØubergeek*tv based on information from
+ // http://developer.apple.com/quicktime/icefloe/dispatch012.html
+ $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+
+ $CompressedFileData = substr($atom_data, 4);
+ if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
+ } else {
+ $info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];
+ }
+ break;
+
+
+ case 'dcom': // Data COMpression atom
+ $atom_structure['compression_id'] = $atom_data;
+ $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
+ break;
+
+
+ case 'rdrf': // Reference movie Data ReFerence atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
+
+ $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);
+ $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ switch ($atom_structure['reference_type_name']) {
+ case 'url ':
+ $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));
+ break;
+
+ case 'alis':
+ $atom_structure['file_alias'] = substr($atom_data, 12);
+ break;
+
+ case 'rsrc':
+ $atom_structure['resource_alias'] = substr($atom_data, 12);
+ break;
+
+ default:
+ $atom_structure['data'] = substr($atom_data, 12);
+ break;
+ }
+ break;
+
+
+ case 'rmqu': // Reference Movie QUality atom
+ $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
+ break;
+
+
+ case 'rmcs': // Reference Movie Cpu Speed atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ break;
+
+
+ case 'rmvc': // Reference Movie Version Check atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);
+ $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
+ break;
+
+
+ case 'rmcd': // Reference Movie Component check atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['component_type'] = substr($atom_data, 4, 4);
+ $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
+ $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
+ $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
+ $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
+ break;
+
+
+ case 'rmdr': // Reference Movie Data Rate atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+
+ $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
+ break;
+
+
+ case 'rmla': // Reference Movie Language Atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
+ $info['comments']['language'][] = $atom_structure['language'];
+ }
+ break;
+
+
+ case 'rmla': // Reference Movie Language Atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ break;
+
+
+ case 'ptv ': // Print To Video - defines a movie's full screen mode
+ // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
+ $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
+ $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
+ $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
+ $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
+ $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
+
+ $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
+ $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
+
+ $ptv_lookup[0] = 'normal';
+ $ptv_lookup[1] = 'double';
+ $ptv_lookup[2] = 'half';
+ $ptv_lookup[3] = 'full';
+ $ptv_lookup[4] = 'current';
+ if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
+ $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
+ } else {
+ $info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';
+ }
+ break;
+
+
+ case 'stsd': // Sample Table Sample Description atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stsdEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
+ $stsdEntriesDataOffset += 4;
+ $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4);
+ $stsdEntriesDataOffset += 4;
+ $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
+ $stsdEntriesDataOffset += 6;
+ $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
+ $stsdEntriesDataOffset += 2;
+ $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
+ $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
+
+ $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
+ $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
+ $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
+
+ switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
+
+ case "\x00\x00\x00\x00":
+ // audio tracks
+ $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
+ $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2));
+ $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2));
+ $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2));
+ $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4));
+
+ // video tracks
+ // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
+ $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
+ $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
+ $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
+ $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
+ $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
+ $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
+ $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4));
+ $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2));
+ $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4);
+ $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2));
+ $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2));
+
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
+ case '2vuY':
+ case 'avc1':
+ case 'cvid':
+ case 'dvc ':
+ case 'dvcp':
+ case 'gif ':
+ case 'h263':
+ case 'jpeg':
+ case 'kpcd':
+ case 'mjpa':
+ case 'mjpb':
+ case 'mp4v':
+ case 'png ':
+ case 'raw ':
+ case 'rle ':
+ case 'rpza':
+ case 'smc ':
+ case 'SVQ1':
+ case 'SVQ3':
+ case 'tiff':
+ case 'v210':
+ case 'v216':
+ case 'v308':
+ case 'v408':
+ case 'v410':
+ case 'yuv2':
+ $info['fileformat'] = 'mp4';
+ $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
+// http://www.getid3.org/phpBB3/viewtopic.php?t=1550
+//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
+if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
+ // assume that values stored here are more important than values stored in [tkhd] atom
+ $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
+ $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
+ $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
+ $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
+}
+ break;
+
+ case 'qtvr':
+ $info['video']['dataformat'] = 'quicktimevr';
+ break;
+
+ case 'mp4a':
+ default:
+ $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
+ $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
+ $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels'];
+ $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
+ $info['audio']['codec'] = $info['quicktime']['audio']['codec'];
+ $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate'];
+ $info['audio']['channels'] = $info['quicktime']['audio']['channels'];
+ $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth'];
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
+ case 'raw ': // PCM
+ case 'alac': // Apple Lossless Audio Codec
+ $info['audio']['lossless'] = true;
+ break;
+ default:
+ $info['audio']['lossless'] = false;
+ break;
+ }
+ break;
+ }
+ break;
+
+ default:
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
+ case 'mp4s':
+ $info['fileformat'] = 'mp4';
+ break;
+
+ default:
+ // video atom
+ $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
+ $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
+ $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
+ $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
+ $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4));
+ $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
+ $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
+ $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2));
+ $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1));
+ $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']);
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
+ $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
+
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
+
+ if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
+ $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
+ $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
+ $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
+ $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
+ $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
+
+ $info['video']['codec'] = $info['quicktime']['video']['codec'];
+ $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
+ }
+ $info['video']['lossless'] = false;
+ $info['video']['pixel_aspect_ratio'] = (float) 1;
+ break;
+ }
+ break;
+ }
+ switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
+ case 'mp4a':
+ $info['audio']['dataformat'] = 'mp4';
+ $info['quicktime']['audio']['codec'] = 'mp4';
+ break;
+
+ case '3ivx':
+ case '3iv1':
+ case '3iv2':
+ $info['video']['dataformat'] = '3ivx';
+ break;
+
+ case 'xvid':
+ $info['video']['dataformat'] = 'xvid';
+ break;
+
+ case 'mp4v':
+ $info['video']['dataformat'] = 'mpeg4';
+ break;
+
+ case 'divx':
+ case 'div1':
+ case 'div2':
+ case 'div3':
+ case 'div4':
+ case 'div5':
+ case 'div6':
+ $info['video']['dataformat'] = 'divx';
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+ unset($atom_structure['sample_description_table'][$i]['data']);
+ }
+ break;
+
+
+ case 'stts': // Sample Table Time-to-Sample atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $sttsEntriesDataOffset = 8;
+ //$FrameRateCalculatorArray = array();
+ $frames_count = 0;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
+ $sttsEntriesDataOffset += 4;
+ $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
+ $sttsEntriesDataOffset += 4;
+
+ $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
+
+ // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
+ //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
+ // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
+ // if ($stts_new_framerate <= 60) {
+ // // some atoms have durations of "1" giving a very large framerate, which probably is not right
+ // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
+ // }
+ //}
+ //
+ //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
+ }
+ $info['quicktime']['stts_framecount'][] = $frames_count;
+ //$sttsFramesTotal = 0;
+ //$sttsSecondsTotal = 0;
+ //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
+ // if (($frames_per_second > 60) || ($frames_per_second < 1)) {
+ // // not video FPS information, probably audio information
+ // $sttsFramesTotal = 0;
+ // $sttsSecondsTotal = 0;
+ // break;
+ // }
+ // $sttsFramesTotal += $frame_count;
+ // $sttsSecondsTotal += $frame_count / $frames_per_second;
+ //}
+ //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
+ // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
+ // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
+ // }
+ //}
+ break;
+
+
+ case 'stss': // Sample Table Sync Sample (key frames) atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stssEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
+ $stssEntriesDataOffset += 4;
+ }
+ }
+ break;
+
+
+ case 'stsc': // Sample Table Sample-to-Chunk atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stscEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
+ $stscEntriesDataOffset += 4;
+ $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
+ $stscEntriesDataOffset += 4;
+ $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
+ $stscEntriesDataOffset += 4;
+ }
+ }
+ break;
+
+
+ case 'stsz': // Sample Table SiZe atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $stszEntriesDataOffset = 12;
+ if ($atom_structure['sample_size'] == 0) {
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
+ $stszEntriesDataOffset += 4;
+ }
+ }
+ }
+ break;
+
+
+ case 'stco': // Sample Table Chunk Offset atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stcoEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
+ $stcoEntriesDataOffset += 4;
+ }
+ }
+ break;
+
+
+ case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stcoEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
+ $stcoEntriesDataOffset += 8;
+ }
+ }
+ break;
+
+
+ case 'dref': // Data REFerence atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $drefDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
+ $drefDataOffset += 4;
+ $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
+ $drefDataOffset += 4;
+ $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
+ $drefDataOffset += 1;
+ $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000
+ $drefDataOffset += 3;
+ $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
+ $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
+
+ $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
+ }
+ break;
+
+
+ case 'gmin': // base Media INformation atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
+ $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
+ $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
+ $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
+ $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
+ break;
+
+
+ case 'smhd': // Sound Media information HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
+ break;
+
+
+ case 'vmhd': // Video Media information HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
+ $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
+ $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
+
+ $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
+ break;
+
+
+ case 'hdlr': // HanDLeR reference atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['component_type'] = substr($atom_data, 4, 4);
+ $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
+ $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
+ $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
+ $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
+
+ if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
+ $info['video']['dataformat'] = 'quicktimevr';
+ }
+ break;
+
+
+ case 'mdhd': // MeDia HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
+ $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
+
+ if ($atom_structure['time_scale'] == 0) {
+ $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
+ return false;
+ }
+ $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
+
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+ $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
+ $info['comments']['language'][] = $atom_structure['language'];
+ }
+ break;
+
+
+ case 'pnot': // Preview atom
+ $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"
+ $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00
+ $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
+ $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
+
+ $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
+ break;
+
+
+ case 'crgn': // Clipping ReGioN atom
+ $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box,
+ $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields
+ $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
+ break;
+
+
+ case 'load': // track LOAD settings atom
+ $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+ $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+
+ $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
+ $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
+ break;
+
+
+ case 'tmcd': // TiMe CoDe atom
+ case 'chap': // CHAPter list atom
+ case 'sync': // SYNChronization atom
+ case 'scpt': // tranSCriPT atom
+ case 'ssrc': // non-primary SouRCe atom
+ for ($i = 0; $i < (strlen($atom_data) % 4); $i++) {
+ $atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4));
+ }
+ break;
+
+
+ case 'elst': // Edit LiST atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
+ $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
+ $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
+ $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
+ }
+ break;
+
+
+ case 'kmat': // compressed MATte atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['matte_data_raw'] = substr($atom_data, 4);
+ break;
+
+
+ case 'ctab': // Color TABle atom
+ $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000
+ $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000
+ $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1;
+ for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
+ $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
+ $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
+ $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
+ $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
+ }
+ break;
+
+
+ case 'mvhd': // MoVie HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
+ $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
+ $atom_structure['reserved'] = substr($atom_data, 26, 10);
+ $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
+ $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
+ $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
+ $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
+ $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
+ $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
+ $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
+ $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
+ $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
+ $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
+ $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
+ $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
+ $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
+ $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
+ $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
+ $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
+
+ if ($atom_structure['time_scale'] == 0) {
+ $info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
+ return false;
+ }
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+ $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
+ $info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
+ $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
+ break;
+
+
+ case 'tkhd': // TracK HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
+ $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
+ $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
+ $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
+ $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
+ $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
+// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
+// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
+ $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
+ $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
+ $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
+ $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
+ $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
+ $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
+ $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
+ $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
+ $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
+ $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
+ $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
+ $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001);
+ $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002);
+ $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
+ $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008);
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+
+ if ($atom_structure['flags']['enabled'] == 1) {
+ if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
+ $info['video']['resolution_x'] = $atom_structure['width'];
+ $info['video']['resolution_y'] = $atom_structure['height'];
+ }
+ $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
+ $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
+ $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
+ $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
+ } else {
+ // see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295
+ //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
+ //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
+ //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); }
+ }
+ break;
+
+
+ case 'iods': // Initial Object DeScriptor atom
+ // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
+ // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
+ $offset = 0;
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
+ $offset += 3;
+ $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
+ //$offset already adjusted by quicktime_read_mp4_descr_length()
+ $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
+ $offset += 2;
+ $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+
+ $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
+ for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) {
+ $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
+ //$offset already adjusted by quicktime_read_mp4_descr_length()
+ $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
+ $offset += 4;
+ }
+
+ $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
+ $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
+ break;
+
+ case 'ftyp': // FileTYPe (?) atom (for MP4 it seems)
+ $atom_structure['signature'] = substr($atom_data, 0, 4);
+ $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['fourcc'] = substr($atom_data, 8, 4);
+ break;
+
+ case 'mdat': // Media DATa atom
+ case 'free': // FREE space atom
+ case 'skip': // SKIP atom
+ case 'wide': // 64-bit expansion placeholder atom
+ // 'mdat' data is too big to deal with, contains no useful metadata
+ // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
+
+ // When writing QuickTime files, it is sometimes necessary to update an atom's size.
+ // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
+ // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
+ // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
+ // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
+ // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
+ // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
+ break;
+
+
+ case 'nsav': // NoSAVe atom
+ // http://developer.apple.com/technotes/tn/tn2038.html
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+ break;
+
+ case 'ctyp': // Controller TYPe atom (seen on QTVR)
+ // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
+ // some controller names are:
+ // 0x00 + 'std' for linear movie
+ // 'none' for no controls
+ $atom_structure['ctyp'] = substr($atom_data, 0, 4);
+ $info['quicktime']['controller'] = $atom_structure['ctyp'];
+ switch ($atom_structure['ctyp']) {
+ case 'qtvr':
+ $info['video']['dataformat'] = 'quicktimevr';
+ break;
+ }
+ break;
+
+ case 'pano': // PANOrama track (seen on QTVR)
+ $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+ break;
+
+ case 'hint': // HINT track
+ case 'hinf': //
+ case 'hinv': //
+ case 'hnti': //
+ $info['quicktime']['hinting'] = true;
+ break;
+
+ case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
+ for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
+ $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
+ }
+ break;
+
+
+ // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
+ case 'FXTC': // Something to do with Adobe After Effects (?)
+ case 'PrmA':
+ case 'code':
+ case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
+ case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
+ // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
+ // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
+ // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
+ case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ //$atom_structure['data'] = $atom_data;
+ break;
+
+ case '©xyz': // GPS latitude+longitude+altitude
+ $atom_structure['data'] = $atom_data;
+ if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
+ @list($all, $latitude, $longitude, $altitude) = $matches;
+ $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude);
+ $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
+ if (!empty($altitude)) {
+ $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
+ }
+ } else {
+ $info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.';
+ }
+ break;
+
+ case 'NCDT':
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+ case 'NCTH': // Nikon Camera THumbnail image
+ case 'NCVW': // Nikon Camera preVieW image
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
+ $atom_structure['data'] = $atom_data;
+ $atom_structure['image_mime'] = 'image/jpeg';
+ $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
+ $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
+ }
+ break;
+ case 'NCHD': // MakerNoteVersion
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ $atom_structure['data'] = $atom_data;
+ break;
+ case 'NCTG': // NikonTags
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
+ $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
+ break;
+ case 'NCDB': // NikonTags
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ $atom_structure['data'] = $atom_data;
+ break;
+
+ case "\x00\x00\x00\x00":
+ case 'meta': // METAdata atom
+ // some kind of metacontainer, may contain a big data dump such as:
+ // mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
+
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+
+ case 'data': // metaDATA atom
+ // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
+ $atom_structure['language'] = substr($atom_data, 4 + 0, 2);
+ $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
+ $atom_structure['data'] = substr($atom_data, 4 + 4);
+ break;
+
+ default:
+ $info['warning'][] = 'Unknown QuickTime atom type: "'.$atomname.'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
+ $atom_structure['data'] = $atom_data;
+ break;
+ }
+ array_pop($atomHierarchy);
+ return $atom_structure;
+ }
+
+ public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
+//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
+ $atom_structure = false;
+ $subatomoffset = 0;
+ $subatomcounter = 0;
+ if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
+ return false;
+ }
+ while ($subatomoffset < strlen($atom_data)) {
+ $subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4));
+ $subatomname = substr($atom_data, $subatomoffset + 4, 4);
+ $subatomdata = substr($atom_data, $subatomoffset + 8, $subatomsize - 8);
+ if ($subatomsize == 0) {
+ // Furthermore, for historical reasons the list of atoms is optionally
+ // terminated by a 32-bit integer set to 0. If you are writing a program
+ // to read user data atoms, you should allow for the terminating 0.
+ return $atom_structure;
+ }
+
+ $atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
+
+ $subatomoffset += $subatomsize;
+ $subatomcounter++;
+ }
+ return $atom_structure;
+ }
+
+
+ public function quicktime_read_mp4_descr_length($data, &$offset) {
+ // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
+ $num_bytes = 0;
+ $length = 0;
+ do {
+ $b = ord(substr($data, $offset++, 1));
+ $length = ($length << 7) | ($b & 0x7F);
+ } while (($b & 0x80) && ($num_bytes++ < 4));
+ return $length;
+ }
+
+
+ public function QuicktimeLanguageLookup($languageid) {
+ // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353
+ static $QuicktimeLanguageLookup = array();
+ if (empty($QuicktimeLanguageLookup)) {
+ $QuicktimeLanguageLookup[0] = 'English';
+ $QuicktimeLanguageLookup[1] = 'French';
+ $QuicktimeLanguageLookup[2] = 'German';
+ $QuicktimeLanguageLookup[3] = 'Italian';
+ $QuicktimeLanguageLookup[4] = 'Dutch';
+ $QuicktimeLanguageLookup[5] = 'Swedish';
+ $QuicktimeLanguageLookup[6] = 'Spanish';
+ $QuicktimeLanguageLookup[7] = 'Danish';
+ $QuicktimeLanguageLookup[8] = 'Portuguese';
+ $QuicktimeLanguageLookup[9] = 'Norwegian';
+ $QuicktimeLanguageLookup[10] = 'Hebrew';
+ $QuicktimeLanguageLookup[11] = 'Japanese';
+ $QuicktimeLanguageLookup[12] = 'Arabic';
+ $QuicktimeLanguageLookup[13] = 'Finnish';
+ $QuicktimeLanguageLookup[14] = 'Greek';
+ $QuicktimeLanguageLookup[15] = 'Icelandic';
+ $QuicktimeLanguageLookup[16] = 'Maltese';
+ $QuicktimeLanguageLookup[17] = 'Turkish';
+ $QuicktimeLanguageLookup[18] = 'Croatian';
+ $QuicktimeLanguageLookup[19] = 'Chinese (Traditional)';
+ $QuicktimeLanguageLookup[20] = 'Urdu';
+ $QuicktimeLanguageLookup[21] = 'Hindi';
+ $QuicktimeLanguageLookup[22] = 'Thai';
+ $QuicktimeLanguageLookup[23] = 'Korean';
+ $QuicktimeLanguageLookup[24] = 'Lithuanian';
+ $QuicktimeLanguageLookup[25] = 'Polish';
+ $QuicktimeLanguageLookup[26] = 'Hungarian';
+ $QuicktimeLanguageLookup[27] = 'Estonian';
+ $QuicktimeLanguageLookup[28] = 'Lettish';
+ $QuicktimeLanguageLookup[28] = 'Latvian';
+ $QuicktimeLanguageLookup[29] = 'Saamisk';
+ $QuicktimeLanguageLookup[29] = 'Lappish';
+ $QuicktimeLanguageLookup[30] = 'Faeroese';
+ $QuicktimeLanguageLookup[31] = 'Farsi';
+ $QuicktimeLanguageLookup[31] = 'Persian';
+ $QuicktimeLanguageLookup[32] = 'Russian';
+ $QuicktimeLanguageLookup[33] = 'Chinese (Simplified)';
+ $QuicktimeLanguageLookup[34] = 'Flemish';
+ $QuicktimeLanguageLookup[35] = 'Irish';
+ $QuicktimeLanguageLookup[36] = 'Albanian';
+ $QuicktimeLanguageLookup[37] = 'Romanian';
+ $QuicktimeLanguageLookup[38] = 'Czech';
+ $QuicktimeLanguageLookup[39] = 'Slovak';
+ $QuicktimeLanguageLookup[40] = 'Slovenian';
+ $QuicktimeLanguageLookup[41] = 'Yiddish';
+ $QuicktimeLanguageLookup[42] = 'Serbian';
+ $QuicktimeLanguageLookup[43] = 'Macedonian';
+ $QuicktimeLanguageLookup[44] = 'Bulgarian';
+ $QuicktimeLanguageLookup[45] = 'Ukrainian';
+ $QuicktimeLanguageLookup[46] = 'Byelorussian';
+ $QuicktimeLanguageLookup[47] = 'Uzbek';
+ $QuicktimeLanguageLookup[48] = 'Kazakh';
+ $QuicktimeLanguageLookup[49] = 'Azerbaijani';
+ $QuicktimeLanguageLookup[50] = 'AzerbaijanAr';
+ $QuicktimeLanguageLookup[51] = 'Armenian';
+ $QuicktimeLanguageLookup[52] = 'Georgian';
+ $QuicktimeLanguageLookup[53] = 'Moldavian';
+ $QuicktimeLanguageLookup[54] = 'Kirghiz';
+ $QuicktimeLanguageLookup[55] = 'Tajiki';
+ $QuicktimeLanguageLookup[56] = 'Turkmen';
+ $QuicktimeLanguageLookup[57] = 'Mongolian';
+ $QuicktimeLanguageLookup[58] = 'MongolianCyr';
+ $QuicktimeLanguageLookup[59] = 'Pashto';
+ $QuicktimeLanguageLookup[60] = 'Kurdish';
+ $QuicktimeLanguageLookup[61] = 'Kashmiri';
+ $QuicktimeLanguageLookup[62] = 'Sindhi';
+ $QuicktimeLanguageLookup[63] = 'Tibetan';
+ $QuicktimeLanguageLookup[64] = 'Nepali';
+ $QuicktimeLanguageLookup[65] = 'Sanskrit';
+ $QuicktimeLanguageLookup[66] = 'Marathi';
+ $QuicktimeLanguageLookup[67] = 'Bengali';
+ $QuicktimeLanguageLookup[68] = 'Assamese';
+ $QuicktimeLanguageLookup[69] = 'Gujarati';
+ $QuicktimeLanguageLookup[70] = 'Punjabi';
+ $QuicktimeLanguageLookup[71] = 'Oriya';
+ $QuicktimeLanguageLookup[72] = 'Malayalam';
+ $QuicktimeLanguageLookup[73] = 'Kannada';
+ $QuicktimeLanguageLookup[74] = 'Tamil';
+ $QuicktimeLanguageLookup[75] = 'Telugu';
+ $QuicktimeLanguageLookup[76] = 'Sinhalese';
+ $QuicktimeLanguageLookup[77] = 'Burmese';
+ $QuicktimeLanguageLookup[78] = 'Khmer';
+ $QuicktimeLanguageLookup[79] = 'Lao';
+ $QuicktimeLanguageLookup[80] = 'Vietnamese';
+ $QuicktimeLanguageLookup[81] = 'Indonesian';
+ $QuicktimeLanguageLookup[82] = 'Tagalog';
+ $QuicktimeLanguageLookup[83] = 'MalayRoman';
+ $QuicktimeLanguageLookup[84] = 'MalayArabic';
+ $QuicktimeLanguageLookup[85] = 'Amharic';
+ $QuicktimeLanguageLookup[86] = 'Tigrinya';
+ $QuicktimeLanguageLookup[87] = 'Galla';
+ $QuicktimeLanguageLookup[87] = 'Oromo';
+ $QuicktimeLanguageLookup[88] = 'Somali';
+ $QuicktimeLanguageLookup[89] = 'Swahili';
+ $QuicktimeLanguageLookup[90] = 'Ruanda';
+ $QuicktimeLanguageLookup[91] = 'Rundi';
+ $QuicktimeLanguageLookup[92] = 'Chewa';
+ $QuicktimeLanguageLookup[93] = 'Malagasy';
+ $QuicktimeLanguageLookup[94] = 'Esperanto';
+ $QuicktimeLanguageLookup[128] = 'Welsh';
+ $QuicktimeLanguageLookup[129] = 'Basque';
+ $QuicktimeLanguageLookup[130] = 'Catalan';
+ $QuicktimeLanguageLookup[131] = 'Latin';
+ $QuicktimeLanguageLookup[132] = 'Quechua';
+ $QuicktimeLanguageLookup[133] = 'Guarani';
+ $QuicktimeLanguageLookup[134] = 'Aymara';
+ $QuicktimeLanguageLookup[135] = 'Tatar';
+ $QuicktimeLanguageLookup[136] = 'Uighur';
+ $QuicktimeLanguageLookup[137] = 'Dzongkha';
+ $QuicktimeLanguageLookup[138] = 'JavaneseRom';
+ $QuicktimeLanguageLookup[32767] = 'Unspecified';
+ }
+ if (($languageid > 138) && ($languageid < 32767)) {
+ /*
+ ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php
+ Because the language codes specified by ISO 639-2/T are three characters long, they must be packed to fit into a 16-bit field.
+ The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate
+ these integers into the least significant 15 bits of a 16-bit integer, leaving the 16-bit integer's most significant bit set to zero.
+
+ One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character
+ and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character,
+ and add the three 16-bit values. This will result in a single 16-bit value with the three codes correctly packed into the 15 least
+ significant bits and the most significant bit set to zero.
+ */
+ $iso_language_id = '';
+ $iso_language_id .= chr((($languageid & 0x7C00) >> 10) + 0x60);
+ $iso_language_id .= chr((($languageid & 0x03E0) >> 5) + 0x60);
+ $iso_language_id .= chr((($languageid & 0x001F) >> 0) + 0x60);
+ $QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id);
+ }
+ return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
+ }
+
+ public function QuicktimeVideoCodecLookup($codecid) {
+ static $QuicktimeVideoCodecLookup = array();
+ if (empty($QuicktimeVideoCodecLookup)) {
+ $QuicktimeVideoCodecLookup['.SGI'] = 'SGI';
+ $QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1';
+ $QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2';
+ $QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4';
+ $QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB';
+ $QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC';
+ $QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG';
+ $QuicktimeVideoCodecLookup['b16g'] = '16Gray';
+ $QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray';
+ $QuicktimeVideoCodecLookup['b48r'] = '48RGB';
+ $QuicktimeVideoCodecLookup['b64a'] = '64ARGB';
+ $QuicktimeVideoCodecLookup['base'] = 'Base';
+ $QuicktimeVideoCodecLookup['clou'] = 'Cloud';
+ $QuicktimeVideoCodecLookup['cmyk'] = 'CMYK';
+ $QuicktimeVideoCodecLookup['cvid'] = 'Cinepak';
+ $QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG';
+ $QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC';
+ $QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL';
+ $QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC';
+ $QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL';
+ $QuicktimeVideoCodecLookup['fire'] = 'Fire';
+ $QuicktimeVideoCodecLookup['flic'] = 'FLC';
+ $QuicktimeVideoCodecLookup['gif '] = 'GIF';
+ $QuicktimeVideoCodecLookup['h261'] = 'H261';
+ $QuicktimeVideoCodecLookup['h263'] = 'H263';
+ $QuicktimeVideoCodecLookup['IV41'] = 'Indeo4';
+ $QuicktimeVideoCodecLookup['jpeg'] = 'JPEG';
+ $QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD';
+ $QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A';
+ $QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B';
+ $QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1';
+ $QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420';
+ $QuicktimeVideoCodecLookup['path'] = 'Vector';
+ $QuicktimeVideoCodecLookup['png '] = 'PNG';
+ $QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint';
+ $QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX';
+ $QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw';
+ $QuicktimeVideoCodecLookup['raw '] = 'RAW';
+ $QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple';
+ $QuicktimeVideoCodecLookup['rpza'] = 'Video';
+ $QuicktimeVideoCodecLookup['smc '] = 'Graphics';
+ $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1';
+ $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3';
+ $QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9';
+ $QuicktimeVideoCodecLookup['tga '] = 'Targa';
+ $QuicktimeVideoCodecLookup['tiff'] = 'TIFF';
+ $QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW';
+ $QuicktimeVideoCodecLookup['WRLE'] = 'BMP';
+ $QuicktimeVideoCodecLookup['y420'] = 'YUV420';
+ $QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo';
+ $QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned';
+ $QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned';
+ }
+ return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
+ }
+
+ public function QuicktimeAudioCodecLookup($codecid) {
+ static $QuicktimeAudioCodecLookup = array();
+ if (empty($QuicktimeAudioCodecLookup)) {
+ $QuicktimeAudioCodecLookup['.mp3'] = 'Fraunhofer MPEG Layer-III alias';
+ $QuicktimeAudioCodecLookup['aac '] = 'ISO/IEC 14496-3 AAC';
+ $QuicktimeAudioCodecLookup['agsm'] = 'Apple GSM 10:1';
+ $QuicktimeAudioCodecLookup['alac'] = 'Apple Lossless Audio Codec';
+ $QuicktimeAudioCodecLookup['alaw'] = 'A-law 2:1';
+ $QuicktimeAudioCodecLookup['conv'] = 'Sample Format';
+ $QuicktimeAudioCodecLookup['dvca'] = 'DV';
+ $QuicktimeAudioCodecLookup['dvi '] = 'DV 4:1';
+ $QuicktimeAudioCodecLookup['eqal'] = 'Frequency Equalizer';
+ $QuicktimeAudioCodecLookup['fl32'] = '32-bit Floating Point';
+ $QuicktimeAudioCodecLookup['fl64'] = '64-bit Floating Point';
+ $QuicktimeAudioCodecLookup['ima4'] = 'Interactive Multimedia Association 4:1';
+ $QuicktimeAudioCodecLookup['in24'] = '24-bit Integer';
+ $QuicktimeAudioCodecLookup['in32'] = '32-bit Integer';
+ $QuicktimeAudioCodecLookup['lpc '] = 'LPC 23:1';
+ $QuicktimeAudioCodecLookup['MAC3'] = 'Macintosh Audio Compression/Expansion (MACE) 3:1';
+ $QuicktimeAudioCodecLookup['MAC6'] = 'Macintosh Audio Compression/Expansion (MACE) 6:1';
+ $QuicktimeAudioCodecLookup['mixb'] = '8-bit Mixer';
+ $QuicktimeAudioCodecLookup['mixw'] = '16-bit Mixer';
+ $QuicktimeAudioCodecLookup['mp4a'] = 'ISO/IEC 14496-3 AAC';
+ $QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM';
+ $QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA';
+ $QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III';
+ $QuicktimeAudioCodecLookup['NONE'] = 'No Encoding';
+ $QuicktimeAudioCodecLookup['Qclp'] = 'Qualcomm PureVoice';
+ $QuicktimeAudioCodecLookup['QDM2'] = 'QDesign Music 2';
+ $QuicktimeAudioCodecLookup['QDMC'] = 'QDesign Music 1';
+ $QuicktimeAudioCodecLookup['ratb'] = '8-bit Rate';
+ $QuicktimeAudioCodecLookup['ratw'] = '16-bit Rate';
+ $QuicktimeAudioCodecLookup['raw '] = 'raw PCM';
+ $QuicktimeAudioCodecLookup['sour'] = 'Sound Source';
+ $QuicktimeAudioCodecLookup['sowt'] = 'signed/two\'s complement (Little Endian)';
+ $QuicktimeAudioCodecLookup['str1'] = 'Iomega MPEG layer II';
+ $QuicktimeAudioCodecLookup['str2'] = 'Iomega MPEG *layer II';
+ $QuicktimeAudioCodecLookup['str3'] = 'Iomega MPEG **layer II';
+ $QuicktimeAudioCodecLookup['str4'] = 'Iomega MPEG ***layer II';
+ $QuicktimeAudioCodecLookup['twos'] = 'signed/two\'s complement (Big Endian)';
+ $QuicktimeAudioCodecLookup['ulaw'] = 'mu-law 2:1';
+ }
+ return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
+ }
+
+ public function QuicktimeDCOMLookup($compressionid) {
+ static $QuicktimeDCOMLookup = array();
+ if (empty($QuicktimeDCOMLookup)) {
+ $QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate';
+ $QuicktimeDCOMLookup['adec'] = 'Apple Compression';
+ }
+ return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
+ }
+
+ public function QuicktimeColorNameLookup($colordepthid) {
+ static $QuicktimeColorNameLookup = array();
+ if (empty($QuicktimeColorNameLookup)) {
+ $QuicktimeColorNameLookup[1] = '2-color (monochrome)';
+ $QuicktimeColorNameLookup[2] = '4-color';
+ $QuicktimeColorNameLookup[4] = '16-color';
+ $QuicktimeColorNameLookup[8] = '256-color';
+ $QuicktimeColorNameLookup[16] = 'thousands (16-bit color)';
+ $QuicktimeColorNameLookup[24] = 'millions (24-bit color)';
+ $QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)';
+ $QuicktimeColorNameLookup[33] = 'black & white';
+ $QuicktimeColorNameLookup[34] = '4-gray';
+ $QuicktimeColorNameLookup[36] = '16-gray';
+ $QuicktimeColorNameLookup[40] = '256-gray';
+ }
+ return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
+ }
+
+ public function QuicktimeSTIKLookup($stik) {
+ static $QuicktimeSTIKLookup = array();
+ if (empty($QuicktimeSTIKLookup)) {
+ $QuicktimeSTIKLookup[0] = 'Movie';
+ $QuicktimeSTIKLookup[1] = 'Normal';
+ $QuicktimeSTIKLookup[2] = 'Audiobook';
+ $QuicktimeSTIKLookup[5] = 'Whacked Bookmark';
+ $QuicktimeSTIKLookup[6] = 'Music Video';
+ $QuicktimeSTIKLookup[9] = 'Short Film';
+ $QuicktimeSTIKLookup[10] = 'TV Show';
+ $QuicktimeSTIKLookup[11] = 'Booklet';
+ $QuicktimeSTIKLookup[14] = 'Ringtone';
+ $QuicktimeSTIKLookup[21] = 'Podcast';
+ }
+ return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
+ }
+
+ public function QuicktimeIODSaudioProfileName($audio_profile_id) {
+ static $QuicktimeIODSaudioProfileNameLookup = array();
+ if (empty($QuicktimeIODSaudioProfileNameLookup)) {
+ $QuicktimeIODSaudioProfileNameLookup = array(
+ 0x00 => 'ISO Reserved (0x00)',
+ 0x01 => 'Main Audio Profile @ Level 1',
+ 0x02 => 'Main Audio Profile @ Level 2',
+ 0x03 => 'Main Audio Profile @ Level 3',
+ 0x04 => 'Main Audio Profile @ Level 4',
+ 0x05 => 'Scalable Audio Profile @ Level 1',
+ 0x06 => 'Scalable Audio Profile @ Level 2',
+ 0x07 => 'Scalable Audio Profile @ Level 3',
+ 0x08 => 'Scalable Audio Profile @ Level 4',
+ 0x09 => 'Speech Audio Profile @ Level 1',
+ 0x0A => 'Speech Audio Profile @ Level 2',
+ 0x0B => 'Synthetic Audio Profile @ Level 1',
+ 0x0C => 'Synthetic Audio Profile @ Level 2',
+ 0x0D => 'Synthetic Audio Profile @ Level 3',
+ 0x0E => 'High Quality Audio Profile @ Level 1',
+ 0x0F => 'High Quality Audio Profile @ Level 2',
+ 0x10 => 'High Quality Audio Profile @ Level 3',
+ 0x11 => 'High Quality Audio Profile @ Level 4',
+ 0x12 => 'High Quality Audio Profile @ Level 5',
+ 0x13 => 'High Quality Audio Profile @ Level 6',
+ 0x14 => 'High Quality Audio Profile @ Level 7',
+ 0x15 => 'High Quality Audio Profile @ Level 8',
+ 0x16 => 'Low Delay Audio Profile @ Level 1',
+ 0x17 => 'Low Delay Audio Profile @ Level 2',
+ 0x18 => 'Low Delay Audio Profile @ Level 3',
+ 0x19 => 'Low Delay Audio Profile @ Level 4',
+ 0x1A => 'Low Delay Audio Profile @ Level 5',
+ 0x1B => 'Low Delay Audio Profile @ Level 6',
+ 0x1C => 'Low Delay Audio Profile @ Level 7',
+ 0x1D => 'Low Delay Audio Profile @ Level 8',
+ 0x1E => 'Natural Audio Profile @ Level 1',
+ 0x1F => 'Natural Audio Profile @ Level 2',
+ 0x20 => 'Natural Audio Profile @ Level 3',
+ 0x21 => 'Natural Audio Profile @ Level 4',
+ 0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
+ 0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
+ 0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
+ 0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
+ 0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
+ 0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
+ 0x28 => 'AAC Profile @ Level 1',
+ 0x29 => 'AAC Profile @ Level 2',
+ 0x2A => 'AAC Profile @ Level 4',
+ 0x2B => 'AAC Profile @ Level 5',
+ 0x2C => 'High Efficiency AAC Profile @ Level 2',
+ 0x2D => 'High Efficiency AAC Profile @ Level 3',
+ 0x2E => 'High Efficiency AAC Profile @ Level 4',
+ 0x2F => 'High Efficiency AAC Profile @ Level 5',
+ 0xFE => 'Not part of MPEG-4 audio profiles',
+ 0xFF => 'No audio capability required',
+ );
+ }
+ return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
+ }
+
+
+ public function QuicktimeIODSvideoProfileName($video_profile_id) {
+ static $QuicktimeIODSvideoProfileNameLookup = array();
+ if (empty($QuicktimeIODSvideoProfileNameLookup)) {
+ $QuicktimeIODSvideoProfileNameLookup = array(
+ 0x00 => 'Reserved (0x00) Profile',
+ 0x01 => 'Simple Profile @ Level 1',
+ 0x02 => 'Simple Profile @ Level 2',
+ 0x03 => 'Simple Profile @ Level 3',
+ 0x08 => 'Simple Profile @ Level 0',
+ 0x10 => 'Simple Scalable Profile @ Level 0',
+ 0x11 => 'Simple Scalable Profile @ Level 1',
+ 0x12 => 'Simple Scalable Profile @ Level 2',
+ 0x15 => 'AVC/H264 Profile',
+ 0x21 => 'Core Profile @ Level 1',
+ 0x22 => 'Core Profile @ Level 2',
+ 0x32 => 'Main Profile @ Level 2',
+ 0x33 => 'Main Profile @ Level 3',
+ 0x34 => 'Main Profile @ Level 4',
+ 0x42 => 'N-bit Profile @ Level 2',
+ 0x51 => 'Scalable Texture Profile @ Level 1',
+ 0x61 => 'Simple Face Animation Profile @ Level 1',
+ 0x62 => 'Simple Face Animation Profile @ Level 2',
+ 0x63 => 'Simple FBA Profile @ Level 1',
+ 0x64 => 'Simple FBA Profile @ Level 2',
+ 0x71 => 'Basic Animated Texture Profile @ Level 1',
+ 0x72 => 'Basic Animated Texture Profile @ Level 2',
+ 0x81 => 'Hybrid Profile @ Level 1',
+ 0x82 => 'Hybrid Profile @ Level 2',
+ 0x91 => 'Advanced Real Time Simple Profile @ Level 1',
+ 0x92 => 'Advanced Real Time Simple Profile @ Level 2',
+ 0x93 => 'Advanced Real Time Simple Profile @ Level 3',
+ 0x94 => 'Advanced Real Time Simple Profile @ Level 4',
+ 0xA1 => 'Core Scalable Profile @ Level1',
+ 0xA2 => 'Core Scalable Profile @ Level2',
+ 0xA3 => 'Core Scalable Profile @ Level3',
+ 0xB1 => 'Advanced Coding Efficiency Profile @ Level 1',
+ 0xB2 => 'Advanced Coding Efficiency Profile @ Level 2',
+ 0xB3 => 'Advanced Coding Efficiency Profile @ Level 3',
+ 0xB4 => 'Advanced Coding Efficiency Profile @ Level 4',
+ 0xC1 => 'Advanced Core Profile @ Level 1',
+ 0xC2 => 'Advanced Core Profile @ Level 2',
+ 0xD1 => 'Advanced Scalable Texture @ Level1',
+ 0xD2 => 'Advanced Scalable Texture @ Level2',
+ 0xE1 => 'Simple Studio Profile @ Level 1',
+ 0xE2 => 'Simple Studio Profile @ Level 2',
+ 0xE3 => 'Simple Studio Profile @ Level 3',
+ 0xE4 => 'Simple Studio Profile @ Level 4',
+ 0xE5 => 'Core Studio Profile @ Level 1',
+ 0xE6 => 'Core Studio Profile @ Level 2',
+ 0xE7 => 'Core Studio Profile @ Level 3',
+ 0xE8 => 'Core Studio Profile @ Level 4',
+ 0xF0 => 'Advanced Simple Profile @ Level 0',
+ 0xF1 => 'Advanced Simple Profile @ Level 1',
+ 0xF2 => 'Advanced Simple Profile @ Level 2',
+ 0xF3 => 'Advanced Simple Profile @ Level 3',
+ 0xF4 => 'Advanced Simple Profile @ Level 4',
+ 0xF5 => 'Advanced Simple Profile @ Level 5',
+ 0xF7 => 'Advanced Simple Profile @ Level 3b',
+ 0xF8 => 'Fine Granularity Scalable Profile @ Level 0',
+ 0xF9 => 'Fine Granularity Scalable Profile @ Level 1',
+ 0xFA => 'Fine Granularity Scalable Profile @ Level 2',
+ 0xFB => 'Fine Granularity Scalable Profile @ Level 3',
+ 0xFC => 'Fine Granularity Scalable Profile @ Level 4',
+ 0xFD => 'Fine Granularity Scalable Profile @ Level 5',
+ 0xFE => 'Not part of MPEG-4 Visual profiles',
+ 0xFF => 'No visual capability required',
+ );
+ }
+ return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
+ }
+
+
+ public function QuicktimeContentRatingLookup($rtng) {
+ static $QuicktimeContentRatingLookup = array();
+ if (empty($QuicktimeContentRatingLookup)) {
+ $QuicktimeContentRatingLookup[0] = 'None';
+ $QuicktimeContentRatingLookup[2] = 'Clean';
+ $QuicktimeContentRatingLookup[4] = 'Explicit';
+ }
+ return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
+ }
+
+ public function QuicktimeStoreAccountTypeLookup($akid) {
+ static $QuicktimeStoreAccountTypeLookup = array();
+ if (empty($QuicktimeStoreAccountTypeLookup)) {
+ $QuicktimeStoreAccountTypeLookup[0] = 'iTunes';
+ $QuicktimeStoreAccountTypeLookup[1] = 'AOL';
+ }
+ return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
+ }
+
+ public function QuicktimeStoreFrontCodeLookup($sfid) {
+ static $QuicktimeStoreFrontCodeLookup = array();
+ if (empty($QuicktimeStoreFrontCodeLookup)) {
+ $QuicktimeStoreFrontCodeLookup[143460] = 'Australia';
+ $QuicktimeStoreFrontCodeLookup[143445] = 'Austria';
+ $QuicktimeStoreFrontCodeLookup[143446] = 'Belgium';
+ $QuicktimeStoreFrontCodeLookup[143455] = 'Canada';
+ $QuicktimeStoreFrontCodeLookup[143458] = 'Denmark';
+ $QuicktimeStoreFrontCodeLookup[143447] = 'Finland';
+ $QuicktimeStoreFrontCodeLookup[143442] = 'France';
+ $QuicktimeStoreFrontCodeLookup[143443] = 'Germany';
+ $QuicktimeStoreFrontCodeLookup[143448] = 'Greece';
+ $QuicktimeStoreFrontCodeLookup[143449] = 'Ireland';
+ $QuicktimeStoreFrontCodeLookup[143450] = 'Italy';
+ $QuicktimeStoreFrontCodeLookup[143462] = 'Japan';
+ $QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg';
+ $QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands';
+ $QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand';
+ $QuicktimeStoreFrontCodeLookup[143457] = 'Norway';
+ $QuicktimeStoreFrontCodeLookup[143453] = 'Portugal';
+ $QuicktimeStoreFrontCodeLookup[143454] = 'Spain';
+ $QuicktimeStoreFrontCodeLookup[143456] = 'Sweden';
+ $QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland';
+ $QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom';
+ $QuicktimeStoreFrontCodeLookup[143441] = 'United States';
+ }
+ return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
+ }
+
+ public function QuicktimeParseNikonNCTG($atom_data) {
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
+ // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
+ // Data is stored as records of:
+ // * 4 bytes record type
+ // * 2 bytes size of data field type:
+ // 0x0001 = flag (size field *= 1-byte)
+ // 0x0002 = char (size field *= 1-byte)
+ // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
+ // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
+ // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
+ // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
+ // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
+ // * 2 bytes data size field
+ // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
+ // all integers are stored BigEndian
+
+ $NCTGtagName = array(
+ 0x00000001 => 'Make',
+ 0x00000002 => 'Model',
+ 0x00000003 => 'Software',
+ 0x00000011 => 'CreateDate',
+ 0x00000012 => 'DateTimeOriginal',
+ 0x00000013 => 'FrameCount',
+ 0x00000016 => 'FrameRate',
+ 0x00000022 => 'FrameWidth',
+ 0x00000023 => 'FrameHeight',
+ 0x00000032 => 'AudioChannels',
+ 0x00000033 => 'AudioBitsPerSample',
+ 0x00000034 => 'AudioSampleRate',
+ 0x02000001 => 'MakerNoteVersion',
+ 0x02000005 => 'WhiteBalance',
+ 0x0200000b => 'WhiteBalanceFineTune',
+ 0x0200001e => 'ColorSpace',
+ 0x02000023 => 'PictureControlData',
+ 0x02000024 => 'WorldTime',
+ 0x02000032 => 'UnknownInfo',
+ 0x02000083 => 'LensType',
+ 0x02000084 => 'Lens',
+ );
+
+ $offset = 0;
+ $datalength = strlen($atom_data);
+ $parsed = array();
+ while ($offset < $datalength) {
+//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
+ $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;
+ $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
+ $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
+ switch ($data_size_type) {
+ case 0x0001: // 0x0001 = flag (size field *= 1-byte)
+ $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
+ $offset += ($data_size * 1);
+ break;
+ case 0x0002: // 0x0002 = char (size field *= 1-byte)
+ $data = substr($atom_data, $offset, $data_size * 1);
+ $offset += ($data_size * 1);
+ $data = rtrim($data, "\x00");
+ break;
+ case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
+ $data = '';
+ for ($i = $data_size - 1; $i >= 0; $i--) {
+ $data .= substr($atom_data, $offset + ($i * 2), 2);
+ }
+ $data = getid3_lib::BigEndian2Int($data);
+ $offset += ($data_size * 2);
+ break;
+ case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
+ $data = '';
+ for ($i = $data_size - 1; $i >= 0; $i--) {
+ $data .= substr($atom_data, $offset + ($i * 4), 4);
+ }
+ $data = getid3_lib::BigEndian2Int($data);
+ $offset += ($data_size * 4);
+ break;
+ case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
+ $data = array();
+ for ($i = 0; $i < $data_size; $i++) {
+ $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
+ $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
+ if ($denomninator == 0) {
+ $data[$i] = false;
+ } else {
+ $data[$i] = (double) $numerator / $denomninator;
+ }
+ }
+ $offset += (8 * $data_size);
+ if (count($data) == 1) {
+ $data = $data[0];
+ }
+ break;
+ case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
+ $data = substr($atom_data, $offset, $data_size * 1);
+ $offset += ($data_size * 1);
+ break;
+ case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
+ $data = substr($atom_data, $offset, $data_size * 2);
+ $offset += ($data_size * 2);
+ break;
+ default:
+echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
+ break 2;
+ }
+
+ switch ($record_type) {
+ case 0x00000011: // CreateDate
+ case 0x00000012: // DateTimeOriginal
+ $data = strtotime($data);
+ break;
+ case 0x0200001e: // ColorSpace
+ switch ($data) {
+ case 1:
+ $data = 'sRGB';
+ break;
+ case 2:
+ $data = 'Adobe RGB';
+ break;
+ }
+ break;
+ case 0x02000023: // PictureControlData
+ $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
+ $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a');
+ $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
+ $data = array(
+ 'PictureControlVersion' => substr($data, 0, 4),
+ 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"),
+ 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"),
+ //'?' => substr($data, 44, 4),
+ 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))],
+ 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)),
+ 'Sharpness' => ord(substr($data, 50, 1)),
+ 'Contrast' => ord(substr($data, 51, 1)),
+ 'Brightness' => ord(substr($data, 52, 1)),
+ 'Saturation' => ord(substr($data, 53, 1)),
+ 'HueAdjustment' => ord(substr($data, 54, 1)),
+ 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))],
+ 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))],
+ 'ToningSaturation' => ord(substr($data, 57, 1)),
+ );
+ break;
+ case 0x02000024: // WorldTime
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
+ // timezone is stored as offset from GMT in minutes
+ $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
+ if ($timezone & 0x8000) {
+ $timezone = 0 - (0x10000 - $timezone);
+ }
+ $timezone /= 60;
+
+ $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
+ switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
+ case 2:
+ $datedisplayformat = 'D/M/Y'; break;
+ case 1:
+ $datedisplayformat = 'M/D/Y'; break;
+ case 0:
+ default:
+ $datedisplayformat = 'Y/M/D'; break;
+ }
+
+ $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
+ break;
+ case 0x02000083: // LensType
+ $data = array(
+ //'_' => $data,
+ 'mf' => (bool) ($data & 0x01),
+ 'd' => (bool) ($data & 0x02),
+ 'g' => (bool) ($data & 0x04),
+ 'vr' => (bool) ($data & 0x08),
+ );
+ break;
+ }
+ $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
+ $parsed[$tag_name] = $data;
+ }
+ return $parsed;
+ }
+
+
+ public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
+ static $handyatomtranslatorarray = array();
+ if (empty($handyatomtranslatorarray)) {
+ $handyatomtranslatorarray['©cpy'] = 'copyright';
+ $handyatomtranslatorarray['©day'] = 'creation_date'; // iTunes 4.0
+ $handyatomtranslatorarray['©dir'] = 'director';
+ $handyatomtranslatorarray['©ed1'] = 'edit1';
+ $handyatomtranslatorarray['©ed2'] = 'edit2';
+ $handyatomtranslatorarray['©ed3'] = 'edit3';
+ $handyatomtranslatorarray['©ed4'] = 'edit4';
+ $handyatomtranslatorarray['©ed5'] = 'edit5';
+ $handyatomtranslatorarray['©ed6'] = 'edit6';
+ $handyatomtranslatorarray['©ed7'] = 'edit7';
+ $handyatomtranslatorarray['©ed8'] = 'edit8';
+ $handyatomtranslatorarray['©ed9'] = 'edit9';
+ $handyatomtranslatorarray['©fmt'] = 'format';
+ $handyatomtranslatorarray['©inf'] = 'information';
+ $handyatomtranslatorarray['©prd'] = 'producer';
+ $handyatomtranslatorarray['©prf'] = 'performers';
+ $handyatomtranslatorarray['©req'] = 'system_requirements';
+ $handyatomtranslatorarray['©src'] = 'source_credit';
+ $handyatomtranslatorarray['©wrt'] = 'writer';
+
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
+ $handyatomtranslatorarray['©nam'] = 'title'; // iTunes 4.0
+ $handyatomtranslatorarray['©cmt'] = 'comment'; // iTunes 4.0
+ $handyatomtranslatorarray['©wrn'] = 'warning';
+ $handyatomtranslatorarray['©hst'] = 'host_computer';
+ $handyatomtranslatorarray['©mak'] = 'make';
+ $handyatomtranslatorarray['©mod'] = 'model';
+ $handyatomtranslatorarray['©PRD'] = 'product';
+ $handyatomtranslatorarray['©swr'] = 'software';
+ $handyatomtranslatorarray['©aut'] = 'author';
+ $handyatomtranslatorarray['©ART'] = 'artist';
+ $handyatomtranslatorarray['©trk'] = 'track';
+ $handyatomtranslatorarray['©alb'] = 'album'; // iTunes 4.0
+ $handyatomtranslatorarray['©com'] = 'comment';
+ $handyatomtranslatorarray['©gen'] = 'genre'; // iTunes 4.0
+ $handyatomtranslatorarray['©ope'] = 'composer';
+ $handyatomtranslatorarray['©url'] = 'url';
+ $handyatomtranslatorarray['©enc'] = 'encoder';
+
+ // http://atomicparsley.sourceforge.net/mpeg-4files.html
+ $handyatomtranslatorarray['©art'] = 'artist'; // iTunes 4.0
+ $handyatomtranslatorarray['aART'] = 'album_artist';
+ $handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0
+ $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
+ $handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
+ $handyatomtranslatorarray['©too'] = 'encoder'; // iTunes 4.0
+ $handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
+ $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
+ $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
+ $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
+ $handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
+ $handyatomtranslatorarray['©grp'] = 'grouping'; // iTunes 4.2
+ $handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
+ $handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
+ $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9
+ $handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9
+ $handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9
+ $handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9
+ $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0
+ $handyatomtranslatorarray['©lyr'] = 'lyrics'; // iTunes 5.0
+ $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0
+ $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0
+ $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0
+ $handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0
+ $handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2
+ $handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
+
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
+
+
+
+ // boxnames:
+ /*
+ $handyatomtranslatorarray['iTunSMPB'] = 'iTunSMPB';
+ $handyatomtranslatorarray['iTunNORM'] = 'iTunNORM';
+ $handyatomtranslatorarray['Encoding Params'] = 'Encoding Params';
+ $handyatomtranslatorarray['replaygain_track_gain'] = 'replaygain_track_gain';
+ $handyatomtranslatorarray['replaygain_track_peak'] = 'replaygain_track_peak';
+ $handyatomtranslatorarray['replaygain_track_minmax'] = 'replaygain_track_minmax';
+ $handyatomtranslatorarray['MusicIP PUID'] = 'MusicIP PUID';
+ $handyatomtranslatorarray['MusicBrainz Artist Id'] = 'MusicBrainz Artist Id';
+ $handyatomtranslatorarray['MusicBrainz Album Id'] = 'MusicBrainz Album Id';
+ $handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id';
+ $handyatomtranslatorarray['MusicBrainz Track Id'] = 'MusicBrainz Track Id';
+ $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id';
+
+ // http://age.hobba.nl/audio/tag_frame_reference.html
+ $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
+ $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
+ */
+ }
+ $info = &$this->getid3->info;
+ $comment_key = '';
+ if ($boxname && ($boxname != $keyname)) {
+ $comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname);
+ } elseif (isset($handyatomtranslatorarray[$keyname])) {
+ $comment_key = $handyatomtranslatorarray[$keyname];
+ }
+ if ($comment_key) {
+ if ($comment_key == 'picture') {
+ if (!is_array($data)) {
+ $image_mime = '';
+ if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) {
+ $image_mime = 'image/png';
+ } elseif (preg_match('#^\xFF\xD8\xFF#', $data)) {
+ $image_mime = 'image/jpeg';
+ } elseif (preg_match('#^GIF#', $data)) {
+ $image_mime = 'image/gif';
+ } elseif (preg_match('#^BM#', $data)) {
+ $image_mime = 'image/bmp';
+ }
+ $data = array('data'=>$data, 'image_mime'=>$image_mime);
+ }
+ }
+ $info['quicktime']['comments'][$comment_key][] = $data;
+ }
+ return true;
+ }
+
+ public function NoNullString($nullterminatedstring) {
+ // remove the single null terminator on null terminated strings
+ if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
+ return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
+ }
+ return $nullterminatedstring;
+ }
+
+ public function Pascal2String($pascalstring) {
+ // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
+ return substr($pascalstring, 1);
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio-video.riff.php b/src/wp-includes/ID3/module.audio-video.riff.php
new file mode 100644
index 0000000000..8f431009c3
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio-video.riff.php
@@ -0,0 +1,2435 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.riff.php //
+// module for analyzing RIFF files //
+// multiple formats supported by this module: //
+// Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX //
+// dependencies: module.audio.mp3.php //
+// module.audio.ac3.php //
+// module.audio.dts.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+/**
+* @todo Parse AC-3/DTS audio inside WAVE correctly
+* @todo Rewrite RIFF parser totally
+*/
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
+
+class getid3_riff extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ // initialize these values to an empty array, otherwise they default to NULL
+ // and you can't append array values to a NULL value
+ $info['riff'] = array('raw'=>array());
+
+ // Shortcuts
+ $thisfile_riff = &$info['riff'];
+ $thisfile_riff_raw = &$thisfile_riff['raw'];
+ $thisfile_audio = &$info['audio'];
+ $thisfile_video = &$info['video'];
+ $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
+ $thisfile_riff_audio = &$thisfile_riff['audio'];
+ $thisfile_riff_video = &$thisfile_riff['video'];
+
+ $Original['avdataoffset'] = $info['avdataoffset'];
+ $Original['avdataend'] = $info['avdataend'];
+
+ $this->fseek($info['avdataoffset']);
+ $RIFFheader = $this->fread(12);
+ $offset = $this->ftell();
+ $RIFFtype = substr($RIFFheader, 0, 4);
+ $RIFFsize = substr($RIFFheader, 4, 4);
+ $RIFFsubtype = substr($RIFFheader, 8, 4);
+
+ switch ($RIFFtype) {
+
+ case 'FORM': // AIFF, AIFC
+ $info['fileformat'] = 'aiff';
+ $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
+ $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
+ break;
+
+ case 'RIFF': // AVI, WAV, etc
+ case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
+ case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
+ $info['fileformat'] = 'riff';
+ $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
+ if ($RIFFsubtype == 'RMP3') {
+ // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
+ $RIFFsubtype = 'WAVE';
+ }
+ $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
+ if (($info['avdataend'] - $info['filesize']) == 1) {
+ // LiteWave appears to incorrectly *not* pad actual output file
+ // to nearest WORD boundary so may appear to be short by one
+ // byte, in which case - skip warning
+ $info['avdataend'] = $info['filesize'];
+ }
+
+ $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
+ while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
+ try {
+ $this->fseek($nextRIFFoffset);
+ } catch (getid3_exception $e) {
+ if ($e->getCode() == 10) {
+ //$this->warning('RIFF parser: '.$e->getMessage());
+ $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong');
+ $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present');
+ break;
+ } else {
+ throw $e;
+ }
+ }
+ $nextRIFFheader = $this->fread(12);
+ if ($nextRIFFoffset == ($info['avdataend'] - 1)) {
+ if (substr($nextRIFFheader, 0, 1) == "\x00") {
+ // RIFF padded to WORD boundary, we're actually already at the end
+ break;
+ }
+ }
+ $nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
+ $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
+ $nextRIFFtype = substr($nextRIFFheader, 8, 4);
+ $chunkdata = array();
+ $chunkdata['offset'] = $nextRIFFoffset + 8;
+ $chunkdata['size'] = $nextRIFFsize;
+ $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
+
+ switch ($nextRIFFheaderID) {
+
+ case 'RIFF':
+ $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
+
+ if (!isset($thisfile_riff[$nextRIFFtype])) {
+ $thisfile_riff[$nextRIFFtype] = array();
+ }
+ $thisfile_riff[$nextRIFFtype][] = $chunkdata;
+ break;
+
+ case 'JUNK':
+ // ignore
+ $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
+ break;
+
+ case 'IDVX':
+ $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size']));
+ break;
+
+ default:
+ if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) {
+ $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12);
+ if (substr($DIVXTAG, -7) == 'DIVXTAG') {
+ // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file
+ $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway');
+ $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG);
+ break 2;
+ }
+ }
+ $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
+ break 2;
+
+ }
+
+ }
+ if ($RIFFsubtype == 'WAVE') {
+ $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
+ }
+ break;
+
+ default:
+ $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
+ unset($info['fileformat']);
+ return false;
+ }
+
+ $streamindex = 0;
+ switch ($RIFFsubtype) {
+ case 'WAVE':
+ if (empty($thisfile_audio['bitrate_mode'])) {
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ }
+ if (empty($thisfile_audio_dataformat)) {
+ $thisfile_audio_dataformat = 'wav';
+ }
+
+ if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
+ $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
+ }
+ if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
+
+ $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
+ $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
+ if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
+ $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
+ return false;
+ }
+ $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
+ unset($thisfile_riff_audio[$streamindex]['raw']);
+ $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
+
+ $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
+ if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
+ $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];
+ }
+ $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
+
+ if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
+ $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
+ }
+
+ $thisfile_audio['lossless'] = false;
+ if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
+ switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
+
+ case 0x0001: // PCM
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case 0x2000: // AC-3
+ $thisfile_audio_dataformat = 'ac3';
+ break;
+
+ default:
+ // do nothing
+ break;
+
+ }
+ }
+ $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
+ $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
+ $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
+ $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
+ }
+
+ if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
+
+ // shortcuts
+ $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
+ $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array());
+ $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad'];
+ $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
+ $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
+
+ $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
+ $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2));
+ $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2));
+
+ $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
+ $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
+ $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
+ $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
+ $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
+ $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
+ $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
+ $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
+ $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
+ $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
+
+ $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
+ if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
+ $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
+ $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
+ $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
+ }
+ if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
+ $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
+ $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
+ $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
+ }
+ }
+
+ if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
+ $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
+
+ // This should be a good way of calculating exact playtime,
+ // but some sample files have had incorrect number of samples,
+ // so cannot use this method
+
+ // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
+ // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
+ // }
+ }
+ if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
+ $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
+ }
+
+ if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
+ // shortcut
+ $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
+
+ $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
+ $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
+ $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
+ $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
+ $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
+ $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
+ $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
+ $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
+ $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
+ if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
+ if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
+ list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
+ list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
+ $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
+ } else {
+ $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
+ }
+ } else {
+ $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
+ }
+ $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
+ $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
+ }
+
+ if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
+ // shortcut
+ $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
+
+ $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
+ $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
+ if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
+ $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true;
+ $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
+ $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
+
+ $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
+ }
+ $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
+ $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
+ $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
+ $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
+ $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
+ }
+
+ if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
+ // shortcut
+ $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
+
+ $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
+ $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
+ $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
+ $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
+ $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
+ $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
+ $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
+ $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
+ $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
+ $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
+ $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
+ $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
+ $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
+ $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
+ $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
+ $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
+ for ($i = 0; $i < 8; $i++) {
+ $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4);
+ $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4));
+ }
+ $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
+ $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
+
+ $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
+ $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
+ }
+
+ if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
+ // SoundMiner metadata
+
+ // shortcuts
+ $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0];
+ $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data'];
+ $SNDM_startoffset = 0;
+ $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size'];
+
+ while ($SNDM_startoffset < $SNDM_endoffset) {
+ $SNDM_thisTagOffset = 0;
+ $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
+ $SNDM_thisTagOffset += 4;
+ $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
+ $SNDM_thisTagOffset += 4;
+ $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
+ $SNDM_thisTagOffset += 2;
+ $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
+ $SNDM_thisTagOffset += 2;
+ $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
+ $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
+
+ if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
+ $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
+ break;
+ } elseif ($SNDM_thisTagSize <= 0) {
+ $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
+ break;
+ }
+ $SNDM_startoffset += $SNDM_thisTagSize;
+
+ $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
+ if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
+ $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
+ } else {
+ $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
+ }
+ }
+
+ $tagmapping = array(
+ 'tracktitle'=>'title',
+ 'category' =>'genre',
+ 'cdtitle' =>'album',
+ 'tracktitle'=>'title',
+ );
+ foreach ($tagmapping as $fromkey => $tokey) {
+ if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
+ $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
+ }
+ }
+ }
+
+ if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
+ // requires functions simplexml_load_string and get_object_vars
+ if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
+ $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
+ if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
+ @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
+ $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
+ }
+ if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
+ @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
+ $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
+ }
+ if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
+ $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
+ $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
+ $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
+ $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
+ $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
+ $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
+ $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
+ $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
+ }
+ unset($parsedXML);
+ }
+ }
+
+
+
+ if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
+ $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
+ $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
+ }
+
+ if (!empty($info['wavpack'])) {
+ $thisfile_audio_dataformat = 'wavpack';
+ $thisfile_audio['bitrate_mode'] = 'vbr';
+ $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version'];
+
+ // Reset to the way it was - RIFF parsing will have messed this up
+ $info['avdataend'] = $Original['avdataend'];
+ $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+
+ $this->fseek($info['avdataoffset'] - 44);
+ $RIFFdata = $this->fread(44);
+ $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
+ $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
+
+ if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
+ $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
+ $this->fseek($info['avdataend']);
+ $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
+ }
+
+ // move the data chunk after all other chunks (if any)
+ // so that the RIFF parser doesn't see EOF when trying
+ // to skip over the data chunk
+ $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
+ $getid3_riff = new getid3_riff($this->getid3);
+ $getid3_riff->ParseRIFFdata($RIFFdata);
+ unset($getid3_riff);
+ }
+
+ if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
+ switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
+ case 0x0001: // PCM
+ if (!empty($info['ac3'])) {
+ // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
+ $thisfile_audio['wformattag'] = 0x2000;
+ $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']);
+ $thisfile_audio['lossless'] = false;
+ $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
+ $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
+ }
+ if (!empty($info['dts'])) {
+ // Dolby DTS files masquerade as PCM-WAV, but they're not
+ $thisfile_audio['wformattag'] = 0x2001;
+ $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']);
+ $thisfile_audio['lossless'] = false;
+ $thisfile_audio['bitrate'] = $info['dts']['bitrate'];
+ $thisfile_audio['sample_rate'] = $info['dts']['sample_rate'];
+ }
+ break;
+ case 0x08AE: // ClearJump LiteWave
+ $thisfile_audio['bitrate_mode'] = 'vbr';
+ $thisfile_audio_dataformat = 'litewave';
+
+ //typedef struct tagSLwFormat {
+ // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
+ // DWORD m_dwScale; // scale factor for lossy compression
+ // DWORD m_dwBlockSize; // number of samples in encoded blocks
+ // WORD m_wQuality; // alias for the scale factor
+ // WORD m_wMarkDistance; // distance between marks in bytes
+ // WORD m_wReserved;
+ //
+ // //following paramters are ignored if CF_FILESRC is not set
+ // DWORD m_dwOrgSize; // original file size in bytes
+ // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
+ // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
+ //
+ // PCMWAVEFORMAT m_OrgWf; // original wave format
+ // }SLwFormat, *PSLwFormat;
+
+ // shortcut
+ $thisfile_riff['litewave']['raw'] = array();
+ $riff_litewave = &$thisfile_riff['litewave'];
+ $riff_litewave_raw = &$riff_litewave['raw'];
+
+ $flags = array(
+ 'compression_method' => 1,
+ 'compression_flags' => 1,
+ 'm_dwScale' => 4,
+ 'm_dwBlockSize' => 4,
+ 'm_wQuality' => 2,
+ 'm_wMarkDistance' => 2,
+ 'm_wReserved' => 2,
+ 'm_dwOrgSize' => 4,
+ 'm_bFactExists' => 2,
+ 'm_dwRiffChunkSize' => 4,
+ );
+ $litewave_offset = 18;
+ foreach ($flags as $flag => $length) {
+ $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
+ $litewave_offset += $length;
+ }
+
+ //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
+ $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
+
+ $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
+ $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
+ $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04);
+
+ $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false);
+ $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
+ break;
+
+ default:
+ break;
+ }
+ }
+ if ($info['avdataend'] > $info['filesize']) {
+ switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
+ case 'wavpack': // WavPack
+ case 'lpac': // LPAC
+ case 'ofr': // OptimFROG
+ case 'ofs': // OptimFROG DualStream
+ // lossless compressed audio formats that keep original RIFF headers - skip warning
+ break;
+
+ case 'litewave':
+ if (($info['avdataend'] - $info['filesize']) == 1) {
+ // LiteWave appears to incorrectly *not* pad actual output file
+ // to nearest WORD boundary so may appear to be short by one
+ // byte, in which case - skip warning
+ } else {
+ // Short by more than one byte, throw warning
+ $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ }
+ break;
+
+ default:
+ if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
+ // output file appears to be incorrectly *not* padded to nearest WORD boundary
+ // Output less severe warning
+ $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ } else {
+ // Short by more than one byte, throw warning
+ $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ }
+ break;
+ }
+ }
+ if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
+ if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
+ $info['avdataend']--;
+ $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
+ }
+ }
+ if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
+ unset($thisfile_audio['bits_per_sample']);
+ if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
+ $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
+ }
+ }
+ break;
+
+ case 'AVI ':
+ $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
+ $thisfile_video['dataformat'] = 'avi';
+ $info['mime_type'] = 'video/avi';
+
+ if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
+ if (isset($thisfile_riff['AVIX'])) {
+ $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
+ } else {
+ $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
+ }
+ if ($info['avdataend'] > $info['filesize']) {
+ $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ }
+ }
+
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
+ //$bIndexType = array(
+ // 0x00 => 'AVI_INDEX_OF_INDEXES',
+ // 0x01 => 'AVI_INDEX_OF_CHUNKS',
+ // 0x80 => 'AVI_INDEX_IS_DATA',
+ //);
+ //$bIndexSubtype = array(
+ // 0x01 => array(
+ // 0x01 => 'AVI_INDEX_2FIELD',
+ // ),
+ //);
+ foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
+ $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
+
+ $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2));
+ $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1));
+ $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1));
+ $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4));
+ $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4);
+ $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4));
+
+ //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
+ //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
+
+ unset($ahsisd);
+ }
+ }
+ if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
+ $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
+
+ // shortcut
+ $thisfile_riff_raw['avih'] = array();
+ $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
+
+ $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
+ if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
+ $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
+ return false;
+ }
+
+ $flags = array(
+ 'dwMaxBytesPerSec', // max. transfer rate
+ 'dwPaddingGranularity', // pad to multiples of this size; normally 2K.
+ 'dwFlags', // the ever-present flags
+ 'dwTotalFrames', // # frames in file
+ 'dwInitialFrames', //
+ 'dwStreams', //
+ 'dwSuggestedBufferSize', //
+ 'dwWidth', //
+ 'dwHeight', //
+ 'dwScale', //
+ 'dwRate', //
+ 'dwStart', //
+ 'dwLength', //
+ );
+ $avih_offset = 4;
+ foreach ($flags as $flag) {
+ $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
+ $avih_offset += 4;
+ }
+
+ $flags = array(
+ 'hasindex' => 0x00000010,
+ 'mustuseindex' => 0x00000020,
+ 'interleaved' => 0x00000100,
+ 'trustcktype' => 0x00000800,
+ 'capturedfile' => 0x00010000,
+ 'copyrighted' => 0x00020010,
+ );
+ foreach ($flags as $flag => $value) {
+ $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
+ }
+
+ // shortcut
+ $thisfile_riff_video[$streamindex] = array();
+ $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
+
+ if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
+ $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
+ $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
+ }
+ if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
+ $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
+ $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
+ }
+ if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
+ $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
+ $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
+ }
+
+ $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
+ $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
+ }
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
+ if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
+ for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
+ $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
+ $strhfccType = substr($strhData, 0, 4);
+
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
+ $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
+
+ // shortcut
+ $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
+
+ switch ($strhfccType) {
+ case 'auds':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = 'wav';
+ if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
+ $streamindex = count($thisfile_riff_audio);
+ }
+
+ $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData);
+ $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
+
+ // shortcut
+ $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
+ $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
+
+ if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
+ unset($thisfile_audio_streams_currentstream['bits_per_sample']);
+ }
+ $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
+ unset($thisfile_audio_streams_currentstream['raw']);
+
+ // shortcut
+ $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
+
+ unset($thisfile_riff_audio[$streamindex]['raw']);
+ $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
+
+ $thisfile_audio['lossless'] = false;
+ switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
+ case 0x0001: // PCM
+ $thisfile_audio_dataformat = 'wav';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case 0x0050: // MPEG Layer 2 or Layer 1
+ $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
+ break;
+
+ case 0x0055: // MPEG Layer 3
+ $thisfile_audio_dataformat = 'mp3';
+ break;
+
+ case 0x00FF: // AAC
+ $thisfile_audio_dataformat = 'aac';
+ break;
+
+ case 0x0161: // Windows Media v7 / v8 / v9
+ case 0x0162: // Windows Media Professional v9
+ case 0x0163: // Windows Media Lossess v9
+ $thisfile_audio_dataformat = 'wma';
+ break;
+
+ case 0x2000: // AC-3
+ $thisfile_audio_dataformat = 'ac3';
+ break;
+
+ case 0x2001: // DTS
+ $thisfile_audio_dataformat = 'dts';
+ break;
+
+ default:
+ $thisfile_audio_dataformat = 'wav';
+ break;
+ }
+ $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
+ $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
+ $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
+ break;
+
+
+ case 'iavs':
+ case 'vids':
+ // shortcut
+ $thisfile_riff_raw['strh'][$i] = array();
+ $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
+
+ $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType;
+ $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
+ $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags
+ $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2));
+ $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2));
+ $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4));
+ $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4));
+ $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4));
+ $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4));
+ $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4));
+ $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
+ $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4));
+ $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4));
+ $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4));
+
+ $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
+ $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
+ if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
+ $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
+ $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
+ }
+ $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
+ $thisfile_video['pixel_aspect_ratio'] = (float) 1;
+ switch ($thisfile_riff_raw_strh_current['fccHandler']) {
+ case 'HFYU': // Huffman Lossless Codec
+ case 'IRAW': // Intel YUV Uncompressed
+ case 'YUY2': // Uncompressed YUV 4:2:2
+ $thisfile_video['lossless'] = true;
+ break;
+
+ default:
+ $thisfile_video['lossless'] = false;
+ break;
+ }
+
+ switch ($strhfccType) {
+ case 'vids':
+ $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($info['fileformat'] == 'riff'));
+ $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
+
+ if ($thisfile_riff_video_current['codec'] == 'DV') {
+ $thisfile_riff_video_current['dv_type'] = 2;
+ }
+ break;
+
+ case 'iavs':
+ $thisfile_riff_video_current['dv_type'] = 1;
+ break;
+ }
+ break;
+
+ default:
+ $info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';
+ break;
+
+ }
+ }
+ }
+
+ if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
+
+ $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
+ if (self::fourccLookup($thisfile_video['fourcc'])) {
+ $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']);
+ $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
+ }
+
+ switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
+ case 'HFYU': // Huffman Lossless Codec
+ case 'IRAW': // Intel YUV Uncompressed
+ case 'YUY2': // Uncompressed YUV 4:2:2
+ $thisfile_video['lossless'] = true;
+ //$thisfile_video['bits_per_sample'] = 24;
+ break;
+
+ default:
+ $thisfile_video['lossless'] = false;
+ //$thisfile_video['bits_per_sample'] = 24;
+ break;
+ }
+
+ }
+ }
+ }
+ }
+ break;
+
+ case 'CDDA':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = 'cda';
+ $thisfile_audio['lossless'] = true;
+ unset($info['mime_type']);
+
+ $info['avdataoffset'] = 44;
+
+ if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
+ // shortcut
+ $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
+
+ $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
+ $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
+ $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
+ $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
+ $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
+ $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
+ $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
+
+ $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
+ $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
+ $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
+ $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
+
+ // hardcoded data for CD-audio
+ $thisfile_audio['sample_rate'] = 44100;
+ $thisfile_audio['channels'] = 2;
+ $thisfile_audio['bits_per_sample'] = 16;
+ $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ }
+ break;
+
+
+ case 'AIFF':
+ case 'AIFC':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = 'aiff';
+ $thisfile_audio['lossless'] = true;
+ $info['mime_type'] = 'audio/x-aiff';
+
+ if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
+ $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
+ if ($info['avdataend'] > $info['filesize']) {
+ if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) {
+ // structures rounded to 2-byte boundary, but dumb encoders
+ // forget to pad end of file to make this actually work
+ } else {
+ $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
+ }
+ $info['avdataend'] = $info['filesize'];
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
+
+ // shortcut
+ $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
+
+ $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
+ $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
+ $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
+ $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
+
+ if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
+ $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
+ $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
+ $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
+ switch ($thisfile_riff_audio['codec_name']) {
+ case 'NONE':
+ $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case '':
+ switch ($thisfile_riff_audio['codec_fourcc']) {
+ // http://developer.apple.com/qa/snd/snd07.html
+ case 'sowt':
+ $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case 'twos':
+ $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
+ $thisfile_audio['lossless'] = false;
+ break;
+ }
+ }
+
+ $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
+ if ($thisfile_riff_audio['bits_per_sample'] > 0) {
+ $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
+ }
+ $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
+ if ($thisfile_audio['sample_rate'] == 0) {
+ $info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
+ return false;
+ }
+ $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
+ $offset = 0;
+ $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
+ $offset += 2;
+ for ($i = 0; $i < $CommentCount; $i++) {
+ $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
+ $offset += 4;
+ $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
+ $offset += 2;
+ $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
+ $offset += 2;
+ $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
+ $offset += $CommentLength;
+
+ $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
+ $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
+ }
+ }
+
+ $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
+ foreach ($CommentsChunkNames as $key => $value) {
+ if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
+ $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
+ }
+ }
+/*
+ if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_id3v2 = new getid3_id3v2($getid3_temp);
+ $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
+ if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
+ $info['id3v2'] = $getid3_temp->info['id3v2'];
+ }
+ unset($getid3_temp, $getid3_id3v2);
+ }
+*/
+ break;
+
+ case '8SVX':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = '8svx';
+ $thisfile_audio['bits_per_sample'] = 8;
+ $thisfile_audio['channels'] = 1; // overridden below, if need be
+ $info['mime_type'] = 'audio/x-aiff';
+
+ if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
+ $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
+ if ($info['avdataend'] > $info['filesize']) {
+ $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
+ // shortcut
+ $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
+
+ $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
+ $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
+ $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
+ $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
+ $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
+ $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
+ $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
+
+ $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
+
+ switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
+ case 0:
+ $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
+ $thisfile_audio['lossless'] = true;
+ $ActualBitsPerSample = 8;
+ break;
+
+ case 1:
+ $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
+ $thisfile_audio['lossless'] = false;
+ $ActualBitsPerSample = 4;
+ break;
+
+ default:
+ $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';
+ break;
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
+ $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
+ switch ($ChannelsIndex) {
+ case 6: // Stereo
+ $thisfile_audio['channels'] = 2;
+ break;
+
+ case 2: // Left channel only
+ case 4: // Right channel only
+ $thisfile_audio['channels'] = 1;
+ break;
+
+ default:
+ $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';
+ break;
+ }
+
+ }
+
+ $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
+ foreach ($CommentsChunkNames as $key => $value) {
+ if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
+ $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
+ }
+ }
+
+ $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
+ if (!empty($thisfile_audio['bitrate'])) {
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
+ }
+ break;
+
+
+ case 'CDXA':
+ $info['mime_type'] = 'video/mpeg';
+ if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
+ if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_mpeg = new getid3_mpeg($getid3_temp);
+ $getid3_mpeg->Analyze();
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['video'] = $getid3_temp->info['video'];
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
+ $info['warning'] = $getid3_temp->info['warning'];
+ }
+ unset($getid3_temp, $getid3_mpeg);
+ }
+ }
+ break;
+
+
+ default:
+ $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
+ unset($info['fileformat']);
+ break;
+ }
+
+ switch ($RIFFsubtype) {
+ case 'WAVE':
+ case 'AIFF':
+ case 'AIFC':
+ $ID3v2_key_good = 'id3 ';
+ $ID3v2_keys_bad = array('ID3 ', 'tag ');
+ foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
+ if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
+ $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
+ $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"';
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_id3v2 = new getid3_id3v2($getid3_temp);
+ $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
+ if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
+ $info['id3v2'] = $getid3_temp->info['id3v2'];
+ }
+ unset($getid3_temp, $getid3_id3v2);
+ }
+ break;
+ }
+
+ if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
+ $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
+ }
+ if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
+ self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
+ }
+ if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
+ self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
+ }
+
+ if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
+ $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
+ }
+
+ if (!isset($info['playtime_seconds'])) {
+ $info['playtime_seconds'] = 0;
+ }
+ if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
+ // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
+ $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
+ } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
+ $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
+ }
+
+ if ($info['playtime_seconds'] > 0) {
+ if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
+
+ if (!isset($info['bitrate'])) {
+ $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ }
+
+ } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
+
+ if (!isset($thisfile_audio['bitrate'])) {
+ $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ }
+
+ } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
+
+ if (!isset($thisfile_video['bitrate'])) {
+ $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ }
+
+ }
+ }
+
+
+ if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
+
+ $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ $thisfile_audio['bitrate'] = 0;
+ $thisfile_video['bitrate'] = $info['bitrate'];
+ foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
+ $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
+ $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
+ }
+ if ($thisfile_video['bitrate'] <= 0) {
+ unset($thisfile_video['bitrate']);
+ }
+ if ($thisfile_audio['bitrate'] <= 0) {
+ unset($thisfile_audio['bitrate']);
+ }
+ }
+
+ if (isset($info['mpeg']['audio'])) {
+ $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer'];
+ $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $thisfile_audio['channels'] = $info['mpeg']['audio']['channels'];
+ $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ if (!empty($info['mpeg']['audio']['codec'])) {
+ $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
+ }
+ if (!empty($thisfile_audio['streams'])) {
+ foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
+ if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
+ $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
+ $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
+ $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
+ $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
+ $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
+ }
+ }
+ }
+ $getid3_mp3 = new getid3_mp3($this->getid3);
+ $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
+ unset($getid3_mp3);
+ }
+
+
+ if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
+ switch ($thisfile_audio_dataformat) {
+ case 'ac3':
+ // ignore bits_per_sample
+ break;
+
+ default:
+ $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
+ break;
+ }
+ }
+
+
+ if (empty($thisfile_riff_raw)) {
+ unset($thisfile_riff['raw']);
+ }
+ if (empty($thisfile_riff_audio)) {
+ unset($thisfile_riff['audio']);
+ }
+ if (empty($thisfile_riff_video)) {
+ unset($thisfile_riff['video']);
+ }
+
+ return true;
+ }
+
+ public function ParseRIFF($startoffset, $maxoffset) {
+ $info = &$this->getid3->info;
+
+ $RIFFchunk = false;
+ $FoundAllChunksWeNeed = false;
+
+ try {
+ $this->fseek($startoffset);
+ $maxoffset = min($maxoffset, $info['avdataend']);
+ while ($this->ftell() < $maxoffset) {
+ $chunknamesize = $this->fread(8);
+ //$chunkname = substr($chunknamesize, 0, 4);
+ $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult
+ $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
+ //if (strlen(trim($chunkname, "\x00")) < 4) {
+ if (strlen($chunkname) < 4) {
+ $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
+ break;
+ }
+ if (($chunksize == 0) && ($chunkname != 'JUNK')) {
+ $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
+ break;
+ }
+ if (($chunksize % 2) != 0) {
+ // all structures are packed on word boundaries
+ $chunksize++;
+ }
+
+ switch ($chunkname) {
+ case 'LIST':
+ $listname = $this->fread(4);
+ if (preg_match('#^(movi|rec )$#i', $listname)) {
+ $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
+ $RIFFchunk[$listname]['size'] = $chunksize;
+
+ if (!$FoundAllChunksWeNeed) {
+ $WhereWeWere = $this->ftell();
+ $AudioChunkHeader = $this->fread(12);
+ $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
+ $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
+ $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
+
+ if ($AudioChunkStreamType == 'wb') {
+ $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
+ if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
+ // MP3
+ if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
+ $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
+ if (isset($getid3_temp->info['mpeg']['audio'])) {
+ $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio'];
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ //$info['bitrate'] = $info['audio']['bitrate'];
+ }
+ unset($getid3_temp, $getid3_mp3);
+ }
+
+ } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
+
+ // AC3
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
+ $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
+ $getid3_ac3 = new getid3_ac3($getid3_temp);
+ $getid3_ac3->Analyze();
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['ac3'] = $getid3_temp->info['ac3'];
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $key => $value) {
+ $info['warning'][] = $value;
+ }
+ }
+ }
+ unset($getid3_temp, $getid3_ac3);
+ }
+ }
+ $FoundAllChunksWeNeed = true;
+ $this->fseek($WhereWeWere);
+ }
+ $this->fseek($chunksize - 4, SEEK_CUR);
+
+ } else {
+
+ if (!isset($RIFFchunk[$listname])) {
+ $RIFFchunk[$listname] = array();
+ }
+ $LISTchunkParent = $listname;
+ $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
+ if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
+ $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
+ }
+
+ }
+ break;
+
+ default:
+ if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
+ $this->fseek($chunksize, SEEK_CUR);
+ break;
+ }
+ $thisindex = 0;
+ if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
+ $thisindex = count($RIFFchunk[$chunkname]);
+ }
+ $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
+ $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
+ switch ($chunkname) {
+ case 'data':
+ $info['avdataoffset'] = $this->ftell();
+ $info['avdataend'] = $info['avdataoffset'] + $chunksize;
+
+ $testData = $this->fread(36);
+ if ($testData === '') {
+ break;
+ }
+ if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
+
+ // Probably is MP3 data
+ if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
+ }
+ unset($getid3_temp, $getid3_mp3);
+ }
+
+ } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
+
+ // This is probably AC-3 data
+ $getid3_temp = new getID3();
+ if ($isRegularAC3) {
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
+ }
+ $getid3_ac3 = new getid3_ac3($getid3_temp);
+ if ($isRegularAC3) {
+ $getid3_ac3->Analyze();
+ } else {
+ // Dolby Digital WAV
+ // AC-3 content, but not encoded in same format as normal AC-3 file
+ // For one thing, byte order is swapped
+ $ac3_data = '';
+ for ($i = 0; $i < 28; $i += 2) {
+ $ac3_data .= substr($testData, 8 + $i + 1, 1);
+ $ac3_data .= substr($testData, 8 + $i + 0, 1);
+ }
+ $getid3_ac3->AnalyzeString($ac3_data);
+ }
+
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['ac3'] = $getid3_temp->info['ac3'];
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ $this->warning('getid3_ac3() says: ['.$newerror.']');
+ }
+ }
+ }
+ unset($getid3_temp, $getid3_ac3);
+
+ } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
+
+ // This is probably DTS data
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_dts = new getid3_dts($getid3_temp);
+ $getid3_dts->Analyze();
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['dts'] = $getid3_temp->info['dts'];
+ $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ $this->warning('getid3_dts() says: ['.$newerror.']');
+ }
+ }
+ }
+
+ unset($getid3_temp, $getid3_dts);
+
+ } elseif (substr($testData, 0, 4) == 'wvpk') {
+
+ // This is WavPack data
+ $info['wavpack']['offset'] = $info['avdataoffset'];
+ $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
+ $this->parseWavPackHeader(substr($testData, 8, 28));
+
+ } else {
+ // This is some other kind of data (quite possibly just PCM)
+ // do nothing special, just skip it
+ }
+ $nextoffset = $info['avdataend'];
+ $this->fseek($nextoffset);
+ break;
+
+ case 'iXML':
+ case 'bext':
+ case 'cart':
+ case 'fmt ':
+ case 'strh':
+ case 'strf':
+ case 'indx':
+ case 'MEXT':
+ case 'DISP':
+ // always read data in
+ case 'JUNK':
+ // should be: never read data in
+ // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
+ if ($chunksize < 1048576) {
+ if ($chunksize > 0) {
+ $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ if ($chunkname == 'JUNK') {
+ if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
+ // only keep text characters [chr(32)-chr(127)]
+ $info['riff']['comments']['junk'][] = trim($matches[1]);
+ }
+ // but if nothing there, ignore
+ // remove the key in either case
+ unset($RIFFchunk[$chunkname][$thisindex]['data']);
+ }
+ }
+ } else {
+ $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
+ $this->fseek($chunksize, SEEK_CUR);
+ }
+ break;
+
+ //case 'IDVX':
+ // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
+ // break;
+
+ default:
+ if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
+ $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
+ $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
+ unset($RIFFchunk[$chunkname][$thisindex]['offset']);
+ unset($RIFFchunk[$chunkname][$thisindex]['size']);
+ if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
+ unset($RIFFchunk[$chunkname][$thisindex]);
+ }
+ if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
+ unset($RIFFchunk[$chunkname]);
+ }
+ $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ } elseif ($chunksize < 2048) {
+ // only read data in if smaller than 2kB
+ $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ } else {
+ $this->fseek($chunksize, SEEK_CUR);
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ } catch (getid3_exception $e) {
+ if ($e->getCode() == 10) {
+ $this->warning('RIFF parser: '.$e->getMessage());
+ } else {
+ throw $e;
+ }
+ }
+
+ return $RIFFchunk;
+ }
+
+ public function ParseRIFFdata(&$RIFFdata) {
+ $info = &$this->getid3->info;
+ if ($RIFFdata) {
+ $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
+ $fp_temp = fopen($tempfile, 'wb');
+ $RIFFdataLength = strlen($RIFFdata);
+ $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
+ for ($i = 0; $i < 4; $i++) {
+ $RIFFdata[($i + 4)] = $NewLengthString[$i];
+ }
+ fwrite($fp_temp, $RIFFdata);
+ fclose($fp_temp);
+
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($tempfile);
+ $getid3_temp->info['filesize'] = $RIFFdataLength;
+ $getid3_temp->info['filenamepath'] = $info['filenamepath'];
+ $getid3_temp->info['tags'] = $info['tags'];
+ $getid3_temp->info['warning'] = $info['warning'];
+ $getid3_temp->info['error'] = $info['error'];
+ $getid3_temp->info['comments'] = $info['comments'];
+ $getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array());
+ $getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array());
+ $getid3_riff = new getid3_riff($getid3_temp);
+ $getid3_riff->Analyze();
+
+ $info['riff'] = $getid3_temp->info['riff'];
+ $info['warning'] = $getid3_temp->info['warning'];
+ $info['error'] = $getid3_temp->info['error'];
+ $info['tags'] = $getid3_temp->info['tags'];
+ $info['comments'] = $getid3_temp->info['comments'];
+ unset($getid3_riff, $getid3_temp);
+ unlink($tempfile);
+ }
+ return false;
+ }
+
+ public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
+ $RIFFinfoKeyLookup = array(
+ 'IARL'=>'archivallocation',
+ 'IART'=>'artist',
+ 'ICDS'=>'costumedesigner',
+ 'ICMS'=>'commissionedby',
+ 'ICMT'=>'comment',
+ 'ICNT'=>'country',
+ 'ICOP'=>'copyright',
+ 'ICRD'=>'creationdate',
+ 'IDIM'=>'dimensions',
+ 'IDIT'=>'digitizationdate',
+ 'IDPI'=>'resolution',
+ 'IDST'=>'distributor',
+ 'IEDT'=>'editor',
+ 'IENG'=>'engineers',
+ 'IFRM'=>'accountofparts',
+ 'IGNR'=>'genre',
+ 'IKEY'=>'keywords',
+ 'ILGT'=>'lightness',
+ 'ILNG'=>'language',
+ 'IMED'=>'orignalmedium',
+ 'IMUS'=>'composer',
+ 'INAM'=>'title',
+ 'IPDS'=>'productiondesigner',
+ 'IPLT'=>'palette',
+ 'IPRD'=>'product',
+ 'IPRO'=>'producer',
+ 'IPRT'=>'part',
+ 'IRTD'=>'rating',
+ 'ISBJ'=>'subject',
+ 'ISFT'=>'software',
+ 'ISGN'=>'secondarygenre',
+ 'ISHP'=>'sharpness',
+ 'ISRC'=>'sourcesupplier',
+ 'ISRF'=>'digitizationsource',
+ 'ISTD'=>'productionstudio',
+ 'ISTR'=>'starring',
+ 'ITCH'=>'encoded_by',
+ 'IWEB'=>'url',
+ 'IWRI'=>'writer',
+ '____'=>'comment',
+ );
+ foreach ($RIFFinfoKeyLookup as $key => $value) {
+ if (isset($RIFFinfoArray[$key])) {
+ foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
+ if (trim($commentdata['data']) != '') {
+ if (isset($CommentsTargetArray[$value])) {
+ $CommentsTargetArray[$value][] = trim($commentdata['data']);
+ } else {
+ $CommentsTargetArray[$value] = array(trim($commentdata['data']));
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public static function parseWAVEFORMATex($WaveFormatExData) {
+ // shortcut
+ $WaveFormatEx['raw'] = array();
+ $WaveFormatEx_raw = &$WaveFormatEx['raw'];
+
+ $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2);
+ $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2);
+ $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4);
+ $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4);
+ $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2);
+ $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2);
+ if (strlen($WaveFormatExData) > 16) {
+ $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2);
+ }
+ $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
+
+ $WaveFormatEx['codec'] = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
+ $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels'];
+ $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec'];
+ $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
+ $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
+
+ return $WaveFormatEx;
+ }
+
+ public function parseWavPackHeader($WavPackChunkData) {
+ // typedef struct {
+ // char ckID [4];
+ // long ckSize;
+ // short version;
+ // short bits; // added for version 2.00
+ // short flags, shift; // added for version 3.00
+ // long total_samples, crc, crc2;
+ // char extension [4], extra_bc, extras [3];
+ // } WavpackHeader;
+
+ // shortcut
+ $info = &$this->getid3->info;
+ $info['wavpack'] = array();
+ $thisfile_wavpack = &$info['wavpack'];
+
+ $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2));
+ if ($thisfile_wavpack['version'] >= 2) {
+ $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2));
+ }
+ if ($thisfile_wavpack['version'] >= 3) {
+ $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2));
+ $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2));
+ $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4));
+ $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
+ $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
+ $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4);
+ $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
+ for ($i = 0; $i <= 2; $i++) {
+ $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1));
+ }
+
+ // shortcut
+ $thisfile_wavpack['flags'] = array();
+ $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
+
+ $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
+ $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
+ $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
+ $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
+ $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
+ $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
+ $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
+ $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
+ $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
+ $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
+ $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
+ $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
+ $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
+ $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
+ $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
+ $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
+ $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
+ $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
+ $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
+ $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
+ }
+
+ return true;
+ }
+
+ public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
+
+ $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
+ $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
+ $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
+ $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1
+ $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels
+ $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
+ $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device
+ $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device
+ $parsed['biClrUsed'] = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
+ $parsed['biClrImportant'] = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
+ $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed);
+
+ $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier
+
+ return $parsed;
+ }
+
+ public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
+ // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
+ // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
+ // 'Byte Layout: '1111111111111111
+ // '32 for Movie - 1 '1111111111111111
+ // '28 for Author - 6 '6666666666666666
+ // '4 for year - 2 '6666666666662222
+ // '3 for genre - 3 '7777777777777777
+ // '48 for Comments - 7 '7777777777777777
+ // '1 for Rating - 4 '7777777777777777
+ // '5 for Future Additions - 0 '333400000DIVXTAG
+ // '128 bytes total
+
+ static $DIVXTAGgenre = array(
+ 0 => 'Action',
+ 1 => 'Action/Adventure',
+ 2 => 'Adventure',
+ 3 => 'Adult',
+ 4 => 'Anime',
+ 5 => 'Cartoon',
+ 6 => 'Claymation',
+ 7 => 'Comedy',
+ 8 => 'Commercial',
+ 9 => 'Documentary',
+ 10 => 'Drama',
+ 11 => 'Home Video',
+ 12 => 'Horror',
+ 13 => 'Infomercial',
+ 14 => 'Interactive',
+ 15 => 'Mystery',
+ 16 => 'Music Video',
+ 17 => 'Other',
+ 18 => 'Religion',
+ 19 => 'Sci Fi',
+ 20 => 'Thriller',
+ 21 => 'Western',
+ ),
+ $DIVXTAGrating = array(
+ 0 => 'Unrated',
+ 1 => 'G',
+ 2 => 'PG',
+ 3 => 'PG-13',
+ 4 => 'R',
+ 5 => 'NC-17',
+ );
+
+ $parsed['title'] = trim(substr($DIVXTAG, 0, 32));
+ $parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
+ $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
+ $parsed['comment'] = trim(substr($DIVXTAG, 64, 48));
+ $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3)));
+ $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1));
+ //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null
+ //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG"
+
+ $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ? $DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']);
+ $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']);
+
+ if (!$raw) {
+ unset($parsed['genre_id'], $parsed['rating_id']);
+ foreach ($parsed as $key => $value) {
+ if (!$value === '') {
+ unset($parsed['key']);
+ }
+ }
+ }
+
+ foreach ($parsed as $tag => $value) {
+ $parsed[$tag] = array($value);
+ }
+
+ return $parsed;
+ }
+
+ public static function waveSNDMtagLookup($tagshortname) {
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ ©kwd keywords
+ ©BPM bpm
+ ©trt tracktitle
+ ©des description
+ ©gen category
+ ©fin featuredinstrument
+ ©LID longid
+ ©bex bwdescription
+ ©pub publisher
+ ©cdt cdtitle
+ ©alb library
+ ©com composer
+
+ */
+
+ return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
+ }
+
+ public static function wFormatTagLookup($wFormatTag) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ 0x0000 Microsoft Unknown Wave Format
+ 0x0001 Pulse Code Modulation (PCM)
+ 0x0002 Microsoft ADPCM
+ 0x0003 IEEE Float
+ 0x0004 Compaq Computer VSELP
+ 0x0005 IBM CVSD
+ 0x0006 Microsoft A-Law
+ 0x0007 Microsoft mu-Law
+ 0x0008 Microsoft DTS
+ 0x0010 OKI ADPCM
+ 0x0011 Intel DVI/IMA ADPCM
+ 0x0012 Videologic MediaSpace ADPCM
+ 0x0013 Sierra Semiconductor ADPCM
+ 0x0014 Antex Electronics G.723 ADPCM
+ 0x0015 DSP Solutions DigiSTD
+ 0x0016 DSP Solutions DigiFIX
+ 0x0017 Dialogic OKI ADPCM
+ 0x0018 MediaVision ADPCM
+ 0x0019 Hewlett-Packard CU
+ 0x0020 Yamaha ADPCM
+ 0x0021 Speech Compression Sonarc
+ 0x0022 DSP Group TrueSpeech
+ 0x0023 Echo Speech EchoSC1
+ 0x0024 Audiofile AF36
+ 0x0025 Audio Processing Technology APTX
+ 0x0026 AudioFile AF10
+ 0x0027 Prosody 1612
+ 0x0028 LRC
+ 0x0030 Dolby AC2
+ 0x0031 Microsoft GSM 6.10
+ 0x0032 MSNAudio
+ 0x0033 Antex Electronics ADPCME
+ 0x0034 Control Resources VQLPC
+ 0x0035 DSP Solutions DigiREAL
+ 0x0036 DSP Solutions DigiADPCM
+ 0x0037 Control Resources CR10
+ 0x0038 Natural MicroSystems VBXADPCM
+ 0x0039 Crystal Semiconductor IMA ADPCM
+ 0x003A EchoSC3
+ 0x003B Rockwell ADPCM
+ 0x003C Rockwell Digit LK
+ 0x003D Xebec
+ 0x0040 Antex Electronics G.721 ADPCM
+ 0x0041 G.728 CELP
+ 0x0042 MSG723
+ 0x0050 MPEG Layer-2 or Layer-1
+ 0x0052 RT24
+ 0x0053 PAC
+ 0x0055 MPEG Layer-3
+ 0x0059 Lucent G.723
+ 0x0060 Cirrus
+ 0x0061 ESPCM
+ 0x0062 Voxware
+ 0x0063 Canopus Atrac
+ 0x0064 G.726 ADPCM
+ 0x0065 G.722 ADPCM
+ 0x0066 DSAT
+ 0x0067 DSAT Display
+ 0x0069 Voxware Byte Aligned
+ 0x0070 Voxware AC8
+ 0x0071 Voxware AC10
+ 0x0072 Voxware AC16
+ 0x0073 Voxware AC20
+ 0x0074 Voxware MetaVoice
+ 0x0075 Voxware MetaSound
+ 0x0076 Voxware RT29HW
+ 0x0077 Voxware VR12
+ 0x0078 Voxware VR18
+ 0x0079 Voxware TQ40
+ 0x0080 Softsound
+ 0x0081 Voxware TQ60
+ 0x0082 MSRT24
+ 0x0083 G.729A
+ 0x0084 MVI MV12
+ 0x0085 DF G.726
+ 0x0086 DF GSM610
+ 0x0088 ISIAudio
+ 0x0089 Onlive
+ 0x0091 SBC24
+ 0x0092 Dolby AC3 SPDIF
+ 0x0093 MediaSonic G.723
+ 0x0094 Aculab PLC Prosody 8kbps
+ 0x0097 ZyXEL ADPCM
+ 0x0098 Philips LPCBB
+ 0x0099 Packed
+ 0x00FF AAC
+ 0x0100 Rhetorex ADPCM
+ 0x0101 IBM mu-law
+ 0x0102 IBM A-law
+ 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
+ 0x0111 Vivo G.723
+ 0x0112 Vivo Siren
+ 0x0123 Digital G.723
+ 0x0125 Sanyo LD ADPCM
+ 0x0130 Sipro Lab Telecom ACELP NET
+ 0x0131 Sipro Lab Telecom ACELP 4800
+ 0x0132 Sipro Lab Telecom ACELP 8V3
+ 0x0133 Sipro Lab Telecom G.729
+ 0x0134 Sipro Lab Telecom G.729A
+ 0x0135 Sipro Lab Telecom Kelvin
+ 0x0140 Windows Media Video V8
+ 0x0150 Qualcomm PureVoice
+ 0x0151 Qualcomm HalfRate
+ 0x0155 Ring Zero Systems TUB GSM
+ 0x0160 Microsoft Audio 1
+ 0x0161 Windows Media Audio V7 / V8 / V9
+ 0x0162 Windows Media Audio Professional V9
+ 0x0163 Windows Media Audio Lossless V9
+ 0x0200 Creative Labs ADPCM
+ 0x0202 Creative Labs Fastspeech8
+ 0x0203 Creative Labs Fastspeech10
+ 0x0210 UHER Informatic GmbH ADPCM
+ 0x0220 Quarterdeck
+ 0x0230 I-link Worldwide VC
+ 0x0240 Aureal RAW Sport
+ 0x0250 Interactive Products HSX
+ 0x0251 Interactive Products RPELP
+ 0x0260 Consistent Software CS2
+ 0x0270 Sony SCX
+ 0x0300 Fujitsu FM Towns Snd
+ 0x0400 BTV Digital
+ 0x0401 Intel Music Coder
+ 0x0450 QDesign Music
+ 0x0680 VME VMPCM
+ 0x0681 AT&T Labs TPC
+ 0x08AE ClearJump LiteWave
+ 0x1000 Olivetti GSM
+ 0x1001 Olivetti ADPCM
+ 0x1002 Olivetti CELP
+ 0x1003 Olivetti SBC
+ 0x1004 Olivetti OPR
+ 0x1100 Lernout & Hauspie Codec (0x1100)
+ 0x1101 Lernout & Hauspie CELP Codec (0x1101)
+ 0x1102 Lernout & Hauspie SBC Codec (0x1102)
+ 0x1103 Lernout & Hauspie SBC Codec (0x1103)
+ 0x1104 Lernout & Hauspie SBC Codec (0x1104)
+ 0x1400 Norris
+ 0x1401 AT&T ISIAudio
+ 0x1500 Soundspace Music Compression
+ 0x181C VoxWare RT24 Speech
+ 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com)
+ 0x2000 Dolby AC3
+ 0x2001 Dolby DTS
+ 0x2002 WAVE_FORMAT_14_4
+ 0x2003 WAVE_FORMAT_28_8
+ 0x2004 WAVE_FORMAT_COOK
+ 0x2005 WAVE_FORMAT_DNET
+ 0x674F Ogg Vorbis 1
+ 0x6750 Ogg Vorbis 2
+ 0x6751 Ogg Vorbis 3
+ 0x676F Ogg Vorbis 1+
+ 0x6770 Ogg Vorbis 2+
+ 0x6771 Ogg Vorbis 3+
+ 0x7A21 GSM-AMR (CBR, no SID)
+ 0x7A22 GSM-AMR (VBR, including SID)
+ 0xFFFE WAVE_FORMAT_EXTENSIBLE
+ 0xFFFF WAVE_FORMAT_DEVELOPMENT
+
+ */
+
+ return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
+ }
+
+ public static function fourccLookup($fourcc) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ swot http://developer.apple.com/qa/snd/snd07.html
+ ____ No Codec (____)
+ _BIT BI_BITFIELDS (Raw RGB)
+ _JPG JPEG compressed
+ _PNG PNG compressed W3C/ISO/IEC (RFC-2083)
+ _RAW Full Frames (Uncompressed)
+ _RGB Raw RGB Bitmap
+ _RL4 RLE 4bpp RGB
+ _RL8 RLE 8bpp RGB
+ 3IV1 3ivx MPEG-4 v1
+ 3IV2 3ivx MPEG-4 v2
+ 3IVX 3ivx MPEG-4
+ AASC Autodesk Animator
+ ABYR Kensington ?ABYR?
+ AEMI Array Microsystems VideoONE MPEG1-I Capture
+ AFLC Autodesk Animator FLC
+ AFLI Autodesk Animator FLI
+ AMPG Array Microsystems VideoONE MPEG
+ ANIM Intel RDX (ANIM)
+ AP41 AngelPotion Definitive
+ ASV1 Asus Video v1
+ ASV2 Asus Video v2
+ ASVX Asus Video 2.0 (audio)
+ AUR2 AuraVision Aura 2 Codec - YUV 4:2:2
+ AURA AuraVision Aura 1 Codec - YUV 4:1:1
+ AVDJ Independent JPEG Group\'s codec (AVDJ)
+ AVRN Independent JPEG Group\'s codec (AVRN)
+ AYUV 4:4:4 YUV (AYUV)
+ AZPR Quicktime Apple Video (AZPR)
+ BGR Raw RGB32
+ BLZ0 Blizzard DivX MPEG-4
+ BTVC Conexant Composite Video
+ BINK RAD Game Tools Bink Video
+ BT20 Conexant Prosumer Video
+ BTCV Conexant Composite Video Codec
+ BW10 Data Translation Broadway MPEG Capture
+ CC12 Intel YUV12
+ CDVC Canopus DV
+ CFCC Digital Processing Systems DPS Perception
+ CGDI Microsoft Office 97 Camcorder Video
+ CHAM Winnov Caviara Champagne
+ CJPG Creative WebCam JPEG
+ CLJR Cirrus Logic YUV 4:1:1
+ CMYK Common Data Format in Printing (Colorgraph)
+ CPLA Weitek 4:2:0 YUV Planar
+ CRAM Microsoft Video 1 (CRAM)
+ cvid Radius Cinepak
+ CVID Radius Cinepak
+ CWLT Microsoft Color WLT DIB
+ CYUV Creative Labs YUV
+ CYUY ATI YUV
+ D261 H.261
+ D263 H.263
+ DIB Device Independent Bitmap
+ DIV1 FFmpeg OpenDivX
+ DIV2 Microsoft MPEG-4 v1/v2
+ DIV3 DivX ;-) MPEG-4 v3.x Low-Motion
+ DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion
+ DIV5 DivX MPEG-4 v5.x
+ DIV6 DivX ;-) (MS MPEG-4 v3.x)
+ DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo)
+ divx DivX MPEG-4
+ DMB1 Matrox Rainbow Runner hardware MJPEG
+ DMB2 Paradigm MJPEG
+ DSVD ?DSVD?
+ DUCK Duck TrueMotion 1.0
+ DPS0 DPS/Leitch Reality Motion JPEG
+ DPSC DPS/Leitch PAR Motion JPEG
+ DV25 Matrox DVCPRO codec
+ DV50 Matrox DVCPRO50 codec
+ DVC IEC 61834 and SMPTE 314M (DVC/DV Video)
+ DVCP IEC 61834 and SMPTE 314M (DVC/DV Video)
+ DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps
+ DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)
+ DVSL IEC Standard DV compressed in SD (SDL)
+ DVAN ?DVAN?
+ DVE2 InSoft DVE-2 Videoconferencing
+ dvsd IEC 61834 and SMPTE 314M DVC/DV Video
+ DVSD IEC 61834 and SMPTE 314M DVC/DV Video
+ DVX1 Lucent DVX1000SP Video Decoder
+ DVX2 Lucent DVX2000S Video Decoder
+ DVX3 Lucent DVX3000S Video Decoder
+ DX50 DivX v5
+ DXT1 Microsoft DirectX Compressed Texture (DXT1)
+ DXT2 Microsoft DirectX Compressed Texture (DXT2)
+ DXT3 Microsoft DirectX Compressed Texture (DXT3)
+ DXT4 Microsoft DirectX Compressed Texture (DXT4)
+ DXT5 Microsoft DirectX Compressed Texture (DXT5)
+ DXTC Microsoft DirectX Compressed Texture (DXTC)
+ DXTn Microsoft DirectX Compressed Texture (DXTn)
+ EM2V Etymonix MPEG-2 I-frame (www.etymonix.com)
+ EKQ0 Elsa ?EKQ0?
+ ELK0 Elsa ?ELK0?
+ ESCP Eidos Escape
+ ETV1 eTreppid Video ETV1
+ ETV2 eTreppid Video ETV2
+ ETVC eTreppid Video ETVC
+ FLIC Autodesk FLI/FLC Animation
+ FLV1 Sorenson Spark
+ FLV4 On2 TrueMotion VP6
+ FRWT Darim Vision Forward Motion JPEG (www.darvision.com)
+ FRWU Darim Vision Forward Uncompressed (www.darvision.com)
+ FLJP D-Vision Field Encoded Motion JPEG
+ FPS1 FRAPS v1
+ FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel
+ FRWD SoftLab-Nsk Forward Motion JPEG
+ FVF1 Iterated Systems Fractal Video Frame
+ GLZW Motion LZW (gabest@freemail.hu)
+ GPEG Motion JPEG (gabest@freemail.hu)
+ GWLT Microsoft Greyscale WLT DIB
+ H260 Intel ITU H.260 Videoconferencing
+ H261 Intel ITU H.261 Videoconferencing
+ H262 Intel ITU H.262 Videoconferencing
+ H263 Intel ITU H.263 Videoconferencing
+ H264 Intel ITU H.264 Videoconferencing
+ H265 Intel ITU H.265 Videoconferencing
+ H266 Intel ITU H.266 Videoconferencing
+ H267 Intel ITU H.267 Videoconferencing
+ H268 Intel ITU H.268 Videoconferencing
+ H269 Intel ITU H.269 Videoconferencing
+ HFYU Huffman Lossless Codec
+ HMCR Rendition Motion Compensation Format (HMCR)
+ HMRR Rendition Motion Compensation Format (HMRR)
+ I263 FFmpeg I263 decoder
+ IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")
+ IUYV Interlaced version of UYVY (www.leadtools.com)
+ IY41 Interlaced version of Y41P (www.leadtools.com)
+ IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
+ IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
+ IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes)
+ i263 Intel ITU H.263 Videoconferencing (i263)
+ I420 Intel Indeo 4
+ IAN Intel Indeo 4 (RDX)
+ ICLB InSoft CellB Videoconferencing
+ IGOR Power DVD
+ IJPG Intergraph JPEG
+ ILVC Intel Layered Video
+ ILVR ITU-T H.263+
+ IPDV I-O Data Device Giga AVI DV Codec
+ IR21 Intel Indeo 2.1
+ IRAW Intel YUV Uncompressed
+ IV30 Intel Indeo 3.0
+ IV31 Intel Indeo 3.1
+ IV32 Ligos Indeo 3.2
+ IV33 Ligos Indeo 3.3
+ IV34 Ligos Indeo 3.4
+ IV35 Ligos Indeo 3.5
+ IV36 Ligos Indeo 3.6
+ IV37 Ligos Indeo 3.7
+ IV38 Ligos Indeo 3.8
+ IV39 Ligos Indeo 3.9
+ IV40 Ligos Indeo Interactive 4.0
+ IV41 Ligos Indeo Interactive 4.1
+ IV42 Ligos Indeo Interactive 4.2
+ IV43 Ligos Indeo Interactive 4.3
+ IV44 Ligos Indeo Interactive 4.4
+ IV45 Ligos Indeo Interactive 4.5
+ IV46 Ligos Indeo Interactive 4.6
+ IV47 Ligos Indeo Interactive 4.7
+ IV48 Ligos Indeo Interactive 4.8
+ IV49 Ligos Indeo Interactive 4.9
+ IV50 Ligos Indeo Interactive 5.0
+ JBYR Kensington ?JBYR?
+ JPEG Still Image JPEG DIB
+ JPGL Pegasus Lossless Motion JPEG
+ KMVC Team17 Software Karl Morton\'s Video Codec
+ LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)
+ LEAD LEAD Video Codec
+ Ljpg LEAD MJPEG Codec
+ MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)
+ MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)
+ MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)
+ MMES Matrox MPEG-2 I-frame
+ MP2v Microsoft S-Mpeg 4 version 1 (MP2v)
+ MP42 Microsoft S-Mpeg 4 version 2 (MP42)
+ MP43 Microsoft S-Mpeg 4 version 3 (MP43)
+ MP4S Microsoft S-Mpeg 4 version 3 (MP4S)
+ MP4V FFmpeg MPEG-4
+ MPG1 FFmpeg MPEG 1/2
+ MPG2 FFmpeg MPEG 1/2
+ MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3)
+ MPG4 Microsoft MPEG-4
+ MPGI Sigma Designs MPEG
+ MPNG PNG images decoder
+ MSS1 Microsoft Windows Screen Video
+ MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
+ M261 Microsoft H.261
+ M263 Microsoft H.263
+ M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)
+ m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)
+ MC12 ATI Motion Compensation Format (MC12)
+ MCAM ATI Motion Compensation Format (MCAM)
+ MJ2C Morgan Multimedia Motion JPEG2000
+ mJPG IBM Motion JPEG w/ Huffman Tables
+ MJPG Microsoft Motion JPEG DIB
+ MP42 Microsoft MPEG-4 (low-motion)
+ MP43 Microsoft MPEG-4 (fast-motion)
+ MP4S Microsoft MPEG-4 (MP4S)
+ mp4s Microsoft MPEG-4 (mp4s)
+ MPEG Chromatic Research MPEG-1 Video I-Frame
+ MPG4 Microsoft MPEG-4 Video High Speed Compressor
+ MPGI Sigma Designs MPEG
+ MRCA FAST Multimedia Martin Regen Codec
+ MRLE Microsoft Run Length Encoding
+ MSVC Microsoft Video 1
+ MTX1 Matrox ?MTX1?
+ MTX2 Matrox ?MTX2?
+ MTX3 Matrox ?MTX3?
+ MTX4 Matrox ?MTX4?
+ MTX5 Matrox ?MTX5?
+ MTX6 Matrox ?MTX6?
+ MTX7 Matrox ?MTX7?
+ MTX8 Matrox ?MTX8?
+ MTX9 Matrox ?MTX9?
+ MV12 Motion Pixels Codec (old)
+ MWV1 Aware Motion Wavelets
+ nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)
+ NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)
+ NUV1 NuppelVideo
+ NTN1 Nogatech Video Compression 1
+ NVS0 nVidia GeForce Texture (NVS0)
+ NVS1 nVidia GeForce Texture (NVS1)
+ NVS2 nVidia GeForce Texture (NVS2)
+ NVS3 nVidia GeForce Texture (NVS3)
+ NVS4 nVidia GeForce Texture (NVS4)
+ NVS5 nVidia GeForce Texture (NVS5)
+ NVT0 nVidia GeForce Texture (NVT0)
+ NVT1 nVidia GeForce Texture (NVT1)
+ NVT2 nVidia GeForce Texture (NVT2)
+ NVT3 nVidia GeForce Texture (NVT3)
+ NVT4 nVidia GeForce Texture (NVT4)
+ NVT5 nVidia GeForce Texture (NVT5)
+ PIXL MiroXL, Pinnacle PCTV
+ PDVC I-O Data Device Digital Video Capture DV codec
+ PGVV Radius Video Vision
+ PHMO IBM Photomotion
+ PIM1 MPEG Realtime (Pinnacle Cards)
+ PIM2 Pegasus Imaging ?PIM2?
+ PIMJ Pegasus Imaging Lossless JPEG
+ PVEZ Horizons Technology PowerEZ
+ PVMM PacketVideo Corporation MPEG-4
+ PVW2 Pegasus Imaging Wavelet Compression
+ Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de)
+ Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de)
+ QPEG Q-Team QPEG 1.0
+ qpeq Q-Team QPEG 1.1
+ RGB Raw BGR32
+ RGBA Raw RGB w/ Alpha
+ RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)
+ ROQV Id RoQ File Video Decoder
+ RPZA Quicktime Apple Video (RPZA)
+ RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/)
+ RV10 RealVideo 1.0 (aka RealVideo 5.0)
+ RV13 RealVideo 1.0 (RV13)
+ RV20 RealVideo G2
+ RV30 RealVideo 8
+ RV40 RealVideo 9
+ RGBT Raw RGB w/ Transparency
+ RLE Microsoft Run Length Encoder
+ RLE4 Run Length Encoded (4bpp, 16-color)
+ RLE8 Run Length Encoded (8bpp, 256-color)
+ RT21 Intel Indeo RealTime Video 2.1
+ rv20 RealVideo G2
+ rv30 RealVideo 8
+ RVX Intel RDX (RVX )
+ SMC Apple Graphics (SMC )
+ SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
+ SPIG Radius Spigot
+ SVQ3 Sorenson Video 3 (Apple Quicktime 5)
+ s422 Tekram VideoCap C210 YUV 4:2:2
+ SDCC Sun Communication Digital Camera Codec
+ SFMC CrystalNet Surface Fitting Method
+ SMSC Radius SMSC
+ SMSD Radius SMSD
+ smsv WorldConnect Wavelet Video
+ SPIG Radius Spigot
+ SPLC Splash Studios ACM Audio Codec (www.splashstudios.net)
+ SQZ2 Microsoft VXTreme Video Codec V2
+ STVA ST Microelectronics CMOS Imager Data (Bayer)
+ STVB ST Microelectronics CMOS Imager Data (Nudged Bayer)
+ STVC ST Microelectronics CMOS Imager Data (Bunched)
+ STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)
+ STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)
+ SV10 Sorenson Video R1
+ SVQ1 Sorenson Video
+ T420 Toshiba YUV 4:2:0
+ TM2A Duck TrueMotion Archiver 2.0 (www.duck.com)
+ TVJP Pinnacle/Truevision Targa 2000 board (TVJP)
+ TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ)
+ TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com)
+ TY2C Trident Decompression Driver
+ TLMS TeraLogic Motion Intraframe Codec (TLMS)
+ TLST TeraLogic Motion Intraframe Codec (TLST)
+ TM20 Duck TrueMotion 2.0
+ TM2X Duck TrueMotion 2X
+ TMIC TeraLogic Motion Intraframe Codec (TMIC)
+ TMOT Horizons Technology TrueMotion S
+ tmot Horizons TrueMotion Video Compression
+ TR20 Duck TrueMotion RealTime 2.0
+ TSCC TechSmith Screen Capture Codec
+ TV10 Tecomac Low-Bit Rate Codec
+ TY2N Trident ?TY2N?
+ U263 UB Video H.263/H.263+/H.263++ Decoder
+ UMP4 UB Video MPEG 4 (www.ubvideo.com)
+ UYNV Nvidia UYVY packed 4:2:2
+ UYVP Evans & Sutherland YCbCr 4:2:2 extended precision
+ UCOD eMajix.com ClearVideo
+ ULTI IBM Ultimotion
+ UYVY UYVY packed 4:2:2
+ V261 Lucent VX2000S
+ VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/)
+ VIV1 FFmpeg H263+ decoder
+ VIV2 Vivo H.263
+ VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
+ VTLP Alaris VideoGramPiX
+ VYU9 ATI YUV (VYU9)
+ VYUY ATI YUV (VYUY)
+ V261 Lucent VX2000S
+ V422 Vitec Multimedia 24-bit YUV 4:2:2 Format
+ V655 Vitec Multimedia 16-bit YUV 4:2:2 Format
+ VCR1 ATI Video Codec 1
+ VCR2 ATI Video Codec 2
+ VCR3 ATI VCR 3.0
+ VCR4 ATI VCR 4.0
+ VCR5 ATI VCR 5.0
+ VCR6 ATI VCR 6.0
+ VCR7 ATI VCR 7.0
+ VCR8 ATI VCR 8.0
+ VCR9 ATI VCR 9.0
+ VDCT Vitec Multimedia Video Maker Pro DIB
+ VDOM VDOnet VDOWave
+ VDOW VDOnet VDOLive (H.263)
+ VDTZ Darim Vison VideoTizer YUV
+ VGPX Alaris VideoGramPiX
+ VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422
+ VIVO Vivo H.263 v2.00
+ vivo Vivo H.263
+ VIXL Miro/Pinnacle Video XL
+ VLV1 VideoLogic/PURE Digital Videologic Capture
+ VP30 On2 VP3.0
+ VP31 On2 VP3.1
+ VP6F On2 TrueMotion VP6
+ VX1K Lucent VX1000S Video Codec
+ VX2K Lucent VX2000S Video Codec
+ VXSP Lucent VX1000SP Video Codec
+ WBVC Winbond W9960
+ WHAM Microsoft Video 1 (WHAM)
+ WINX Winnov Software Compression
+ WJPG AverMedia Winbond JPEG
+ WMV1 Windows Media Video V7
+ WMV2 Windows Media Video V8
+ WMV3 Windows Media Video V9
+ WNV1 Winnov Hardware Compression
+ XYZP Extended PAL format XYZ palette (www.riff.org)
+ x263 Xirlink H.263
+ XLV0 NetXL Video Decoder
+ XMPG Xing MPEG (I-Frame only)
+ XVID XviD MPEG-4 (www.xvid.org)
+ XXAN ?XXAN?
+ YU92 Intel YUV (YU92)
+ YUNV Nvidia Uncompressed YUV 4:2:2
+ YUVP Extended PAL format YUV palette (www.riff.org)
+ Y211 YUV 2:1:1 Packed
+ Y411 YUV 4:1:1 Packed
+ Y41B Weitek YUV 4:1:1 Planar
+ Y41P Brooktree PC1 YUV 4:1:1 Packed
+ Y41T Brooktree PC1 YUV 4:1:1 with transparency
+ Y42B Weitek YUV 4:2:2 Planar
+ Y42T Brooktree UYUV 4:2:2 with transparency
+ Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
+ Y800 Simple, single Y plane for monochrome images
+ Y8 Grayscale video
+ YC12 Intel YUV 12 codec
+ YUV8 Winnov Caviar YUV8
+ YUV9 Intel YUV9
+ YUY2 Uncompressed YUV 4:2:2
+ YUYV Canopus YUV
+ YV12 YVU12 Planar
+ YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)
+ YVYU YVYU 4:2:2 Packed
+ ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
+ ZPEG Metheus Video Zipper
+
+ */
+
+ return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
+ }
+
+ private function EitherEndian2Int($byteword, $signed=false) {
+ if ($this->getid3->info['fileformat'] == 'riff') {
+ return getid3_lib::LittleEndian2Int($byteword, $signed);
+ }
+ return getid3_lib::BigEndian2Int($byteword, false, $signed);
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio.ac3.php b/src/wp-includes/ID3/module.audio.ac3.php
new file mode 100644
index 0000000000..9834feb5b2
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio.ac3.php
@@ -0,0 +1,473 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.ac3.php //
+// module for analyzing AC-3 (aka Dolby Digital) audio files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_ac3 extends getid3_handler
+{
+ private $AC3header = array();
+ private $BSIoffset = 0;
+
+ const syncword = "\x0B\x77";
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ ///AH
+ $info['ac3']['raw']['bsi'] = array();
+ $thisfile_ac3 = &$info['ac3'];
+ $thisfile_ac3_raw = &$thisfile_ac3['raw'];
+ $thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi'];
+
+
+ // http://www.atsc.org/standards/a_52a.pdf
+
+ $info['fileformat'] = 'ac3';
+
+ // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
+ // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
+ // new audio samples per channel. A synchronization information (SI) header at the beginning
+ // of each frame contains information needed to acquire and maintain synchronization. A
+ // bit stream information (BSI) header follows SI, and contains parameters describing the coded
+ // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
+ // end of each frame is an error check field that includes a CRC word for error detection. An
+ // additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
+ //
+ // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
+
+ // syncinfo() {
+ // syncword 16
+ // crc1 16
+ // fscod 2
+ // frmsizecod 6
+ // } /* end of syncinfo */
+
+ $this->fseek($info['avdataoffset']);
+ $this->AC3header['syncinfo'] = $this->fread(5);
+
+ if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) {
+ $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword;
+ $offset = 2;
+ } else {
+ if (!$this->isDependencyFor('matroska')) {
+ unset($info['fileformat'], $info['ac3']);
+ return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"');
+ }
+ $offset = 0;
+ $this->fseek(-2, SEEK_CUR);
+ }
+
+ $info['audio']['dataformat'] = 'ac3';
+ $info['audio']['bitrate_mode'] = 'cbr';
+ $info['audio']['lossless'] = false;
+
+ $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2));
+ $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1));
+ $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
+ $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
+
+ $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
+ if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
+ $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
+ }
+
+ $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
+ $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
+ $info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
+
+ $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15));
+ $ac3_bsi_offset = 0;
+
+ $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5);
+ if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
+ // Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
+ // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
+ // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
+ $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8');
+ unset($info['ac3']);
+ return false;
+ }
+
+ $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
+ $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
+
+ $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
+ $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
+ foreach($ac3_coding_mode as $key => $value) {
+ $thisfile_ac3[$key] = $value;
+ }
+ switch ($thisfile_ac3_raw_bsi['acmod']) {
+ case 0:
+ case 1:
+ $info['audio']['channelmode'] = 'mono';
+ break;
+ case 3:
+ case 4:
+ $info['audio']['channelmode'] = 'stereo';
+ break;
+ default:
+ $info['audio']['channelmode'] = 'surround';
+ break;
+ }
+ $info['audio']['channels'] = $thisfile_ac3['num_channels'];
+
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
+ // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
+ $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
+ $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
+ }
+
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
+ // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
+ $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
+ $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
+ }
+
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
+ // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
+ $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
+ $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
+ }
+
+ $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
+ $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
+ if ($thisfile_ac3_raw_bsi['lfeon']) {
+ //$info['audio']['channels']++;
+ $info['audio']['channels'] .= '.1';
+ }
+
+ $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
+
+ // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
+ // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
+ $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
+ $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
+
+ $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['compre_flag']) {
+ $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
+ $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
+ }
+
+ $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['langcode_flag']) {
+ $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);
+ }
+
+ $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['audprodie']) {
+ $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
+ $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
+
+ $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
+ $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
+ }
+
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {
+ // If acmod is 0, then two completely independent program channels (dual mono)
+ // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
+ // a number of additional items are present in BSI or audblk to fully describe Ch2.
+
+ // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
+ // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
+ $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
+ $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
+
+ $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['compre_flag2']) {
+ $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
+ $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
+ }
+
+ $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
+ $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);
+ }
+
+ $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['audprodie2']) {
+ $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
+ $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
+
+ $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
+ $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
+ }
+
+ }
+
+ $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1);
+
+ $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1);
+
+ $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
+ $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);
+ }
+
+ $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
+ $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);
+ }
+
+ $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
+ $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);
+
+ $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
+
+ $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
+ $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
+ }
+
+ return true;
+ }
+
+ private function readHeaderBSI($length) {
+ $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
+ $this->BSIoffset += $length;
+
+ return bindec($data);
+ }
+
+ public static function sampleRateCodeLookup($fscod) {
+ static $sampleRateCodeLookup = array(
+ 0 => 48000,
+ 1 => 44100,
+ 2 => 32000,
+ 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
+ );
+ return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
+ }
+
+ public static function serviceTypeLookup($bsmod, $acmod) {
+ static $serviceTypeLookup = array();
+ if (empty($serviceTypeLookup)) {
+ for ($i = 0; $i <= 7; $i++) {
+ $serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
+ $serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)';
+ $serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)';
+ $serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)';
+ $serviceTypeLookup[4][$i] = 'associated service: dialogue (D)';
+ $serviceTypeLookup[5][$i] = 'associated service: commentary (C)';
+ $serviceTypeLookup[6][$i] = 'associated service: emergency (E)';
+ }
+
+ $serviceTypeLookup[7][1] = 'associated service: voice over (VO)';
+ for ($i = 2; $i <= 7; $i++) {
+ $serviceTypeLookup[7][$i] = 'main audio service: karaoke';
+ }
+ }
+ return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
+ }
+
+ public static function audioCodingModeLookup($acmod) {
+ // array(channel configuration, # channels (not incl LFE), channel order)
+ static $audioCodingModeLookup = array (
+ 0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
+ 1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
+ 2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
+ 3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
+ 4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
+ 5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
+ 6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
+ 7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'),
+ );
+ return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
+ }
+
+ public static function centerMixLevelLookup($cmixlev) {
+ static $centerMixLevelLookup;
+ if (empty($centerMixLevelLookup)) {
+ $centerMixLevelLookup = array(
+ 0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB)
+ 1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB)
+ 2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB)
+ 3 => 'reserved'
+ );
+ }
+ return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
+ }
+
+ public static function surroundMixLevelLookup($surmixlev) {
+ static $surroundMixLevelLookup;
+ if (empty($surroundMixLevelLookup)) {
+ $surroundMixLevelLookup = array(
+ 0 => pow(2, -3.0 / 6),
+ 1 => pow(2, -6.0 / 6),
+ 2 => 0,
+ 3 => 'reserved'
+ );
+ }
+ return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
+ }
+
+ public static function dolbySurroundModeLookup($dsurmod) {
+ static $dolbySurroundModeLookup = array(
+ 0 => 'not indicated',
+ 1 => 'Not Dolby Surround encoded',
+ 2 => 'Dolby Surround encoded',
+ 3 => 'reserved'
+ );
+ return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
+ }
+
+ public static function channelsEnabledLookup($acmod, $lfeon) {
+ $lookup = array(
+ 'ch1'=>(bool) ($acmod == 0),
+ 'ch2'=>(bool) ($acmod == 0),
+ 'left'=>(bool) ($acmod > 1),
+ 'right'=>(bool) ($acmod > 1),
+ 'center'=>(bool) ($acmod & 0x01),
+ 'surround_mono'=>false,
+ 'surround_left'=>false,
+ 'surround_right'=>false,
+ 'lfe'=>$lfeon);
+ switch ($acmod) {
+ case 4:
+ case 5:
+ $lookup['surround_mono'] = true;
+ break;
+ case 6:
+ case 7:
+ $lookup['surround_left'] = true;
+ $lookup['surround_right'] = true;
+ break;
+ }
+ return $lookup;
+ }
+
+ public static function heavyCompression($compre) {
+ // The first four bits indicate gain changes in 6.02dB increments which can be
+ // implemented with an arithmetic shift operation. The following four bits
+ // indicate linear gain changes, and require a 5-bit multiply.
+ // We will represent the two 4-bit fields of compr as follows:
+ // X0 X1 X2 X3 . Y4 Y5 Y6 Y7
+ // The meaning of the X values is most simply described by considering X to represent a 4-bit
+ // signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The
+ // following table shows this in detail.
+
+ // Meaning of 4 msb of compr
+ // 7 +48.16 dB
+ // 6 +42.14 dB
+ // 5 +36.12 dB
+ // 4 +30.10 dB
+ // 3 +24.08 dB
+ // 2 +18.06 dB
+ // 1 +12.04 dB
+ // 0 +6.02 dB
+ // -1 0 dB
+ // -2 -6.02 dB
+ // -3 -12.04 dB
+ // -4 -18.06 dB
+ // -5 -24.08 dB
+ // -6 -30.10 dB
+ // -7 -36.12 dB
+ // -8 -42.14 dB
+
+ $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
+ if ($fourbit{0} == '1') {
+ $log_gain = -8 + bindec(substr($fourbit, 1));
+ } else {
+ $log_gain = bindec(substr($fourbit, 1));
+ }
+ $log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2);
+
+ // The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to
+ // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can
+ // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain
+ // changes from -0.28 dB to -6.02 dB.
+
+ $lin_gain = (16 + ($compre & 0x0F)) / 32;
+
+ // The combination of X and Y values allows compr to indicate gain changes from
+ // 48.16 - 0.28 = +47.89 dB, to
+ // -42.14 - 6.02 = -48.16 dB.
+
+ return $log_gain - $lin_gain;
+ }
+
+ public static function roomTypeLookup($roomtyp) {
+ static $roomTypeLookup = array(
+ 0 => 'not indicated',
+ 1 => 'large room, X curve monitor',
+ 2 => 'small room, flat monitor',
+ 3 => 'reserved'
+ );
+ return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
+ }
+
+ public static function frameSizeLookup($frmsizecod, $fscod) {
+ $padding = (bool) ($frmsizecod % 2);
+ $framesizeid = floor($frmsizecod / 2);
+
+ static $frameSizeLookup = array();
+ if (empty($frameSizeLookup)) {
+ $frameSizeLookup = array (
+ 0 => array(128, 138, 192),
+ 1 => array(40, 160, 174, 240),
+ 2 => array(48, 192, 208, 288),
+ 3 => array(56, 224, 242, 336),
+ 4 => array(64, 256, 278, 384),
+ 5 => array(80, 320, 348, 480),
+ 6 => array(96, 384, 416, 576),
+ 7 => array(112, 448, 486, 672),
+ 8 => array(128, 512, 556, 768),
+ 9 => array(160, 640, 696, 960),
+ 10 => array(192, 768, 834, 1152),
+ 11 => array(224, 896, 974, 1344),
+ 12 => array(256, 1024, 1114, 1536),
+ 13 => array(320, 1280, 1392, 1920),
+ 14 => array(384, 1536, 1670, 2304),
+ 15 => array(448, 1792, 1950, 2688),
+ 16 => array(512, 2048, 2228, 3072),
+ 17 => array(576, 2304, 2506, 3456),
+ 18 => array(640, 2560, 2786, 3840)
+ );
+ }
+ if (($fscod == 1) && $padding) {
+ // frame lengths are padded by 1 word (16 bits) at 44100
+ $frameSizeLookup[$frmsizecod] += 2;
+ }
+ return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
+ }
+
+ public static function bitrateLookup($frmsizecod) {
+ $framesizeid = floor($frmsizecod / 2);
+
+ static $bitrateLookup = array(
+ 0 => 32000,
+ 1 => 40000,
+ 2 => 48000,
+ 3 => 56000,
+ 4 => 64000,
+ 5 => 80000,
+ 6 => 96000,
+ 7 => 112000,
+ 8 => 128000,
+ 9 => 160000,
+ 10 => 192000,
+ 11 => 224000,
+ 12 => 256000,
+ 13 => 320000,
+ 14 => 384000,
+ 15 => 448000,
+ 16 => 512000,
+ 17 => 576000,
+ 18 => 640000
+ );
+ return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
+ }
+
+
+}
diff --git a/src/wp-includes/ID3/module.audio.dts.php b/src/wp-includes/ID3/module.audio.dts.php
new file mode 100644
index 0000000000..79982cccfb
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio.dts.php
@@ -0,0 +1,290 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.dts.php //
+// module for analyzing DTS Audio files //
+// dependencies: NONE //
+// //
+/////////////////////////////////////////////////////////////////
+
+
+/**
+* @tutorial http://wiki.multimedia.cx/index.php?title=DTS
+*/
+class getid3_dts extends getid3_handler
+{
+ /**
+ * Default DTS syncword used in native .cpt or .dts formats
+ */
+ const syncword = "\x7F\xFE\x80\x01";
+
+ private $readBinDataOffset = 0;
+
+ /**
+ * Possible syncwords indicating bitstream encoding
+ */
+ public static $syncwords = array(
+ 0 => "\x7F\xFE\x80\x01", // raw big-endian
+ 1 => "\xFE\x7F\x01\x80", // raw little-endian
+ 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian
+ 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+ $info['fileformat'] = 'dts';
+
+ $this->fseek($info['avdataoffset']);
+ $DTSheader = $this->fread(20); // we only need 2 words magic + 6 words frame header, but these words may be normal 16-bit words OR 14-bit words with 2 highest bits set to zero, so 8 words can be either 8*16/8 = 16 bytes OR 8*16*(16/14)/8 = 18.3 bytes
+
+ // check syncword
+ $sync = substr($DTSheader, 0, 4);
+ if (($encoding = array_search($sync, self::$syncwords)) !== false) {
+
+ $info['dts']['raw']['magic'] = $sync;
+ $this->readBinDataOffset = 32;
+
+ } elseif ($this->isDependencyFor('matroska')) {
+
+ // Matroska contains DTS without syncword encoded as raw big-endian format
+ $encoding = 0;
+ $this->readBinDataOffset = 0;
+
+ } else {
+
+ unset($info['fileformat']);
+ return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
+
+ }
+
+ // decode header
+ $fhBS = '';
+ for ($word_offset = 0; $word_offset <= strlen($DTSheader); $word_offset += 2) {
+ switch ($encoding) {
+ case 0: // raw big-endian
+ $fhBS .= getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) );
+ break;
+ case 1: // raw little-endian
+ $fhBS .= getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2)));
+ break;
+ case 2: // 14-bit big-endian
+ $fhBS .= substr(getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) ), 2, 14);
+ break;
+ case 3: // 14-bit little-endian
+ $fhBS .= substr(getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))), 2, 14);
+ break;
+ }
+ }
+
+ $info['dts']['raw']['frame_type'] = $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['deficit_samples'] = $this->readBinData($fhBS, 5);
+ $info['dts']['flags']['crc_present'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['pcm_sample_blocks'] = $this->readBinData($fhBS, 7);
+ $info['dts']['raw']['frame_byte_size'] = $this->readBinData($fhBS, 14);
+ $info['dts']['raw']['channel_arrangement'] = $this->readBinData($fhBS, 6);
+ $info['dts']['raw']['sample_frequency'] = $this->readBinData($fhBS, 4);
+ $info['dts']['raw']['bitrate'] = $this->readBinData($fhBS, 5);
+ $info['dts']['flags']['embedded_downmix'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['dynamicrange'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['timestamp'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['auxdata'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['hdcd'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['extension_audio'] = $this->readBinData($fhBS, 3);
+ $info['dts']['flags']['extended_coding'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['audio_sync_insertion'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['lfe_effects'] = $this->readBinData($fhBS, 2);
+ $info['dts']['flags']['predictor_history'] = (bool) $this->readBinData($fhBS, 1);
+ if ($info['dts']['flags']['crc_present']) {
+ $info['dts']['raw']['crc16'] = $this->readBinData($fhBS, 16);
+ }
+ $info['dts']['flags']['mri_perfect_reconst'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['encoder_soft_version'] = $this->readBinData($fhBS, 4);
+ $info['dts']['raw']['copy_history'] = $this->readBinData($fhBS, 2);
+ $info['dts']['raw']['bits_per_sample'] = $this->readBinData($fhBS, 2);
+ $info['dts']['flags']['surround_es'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['front_sum_diff'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['surround_sum_diff'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['dialog_normalization'] = $this->readBinData($fhBS, 4);
+
+
+ $info['dts']['bitrate'] = self::bitrateLookup($info['dts']['raw']['bitrate']);
+ $info['dts']['bits_per_sample'] = self::bitPerSampleLookup($info['dts']['raw']['bits_per_sample']);
+ $info['dts']['sample_rate'] = self::sampleRateLookup($info['dts']['raw']['sample_frequency']);
+ $info['dts']['dialog_normalization'] = self::dialogNormalization($info['dts']['raw']['dialog_normalization'], $info['dts']['raw']['encoder_soft_version']);
+ $info['dts']['flags']['lossless'] = (($info['dts']['raw']['bitrate'] == 31) ? true : false);
+ $info['dts']['bitrate_mode'] = (($info['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr');
+ $info['dts']['channels'] = self::numChannelsLookup($info['dts']['raw']['channel_arrangement']);
+ $info['dts']['channel_arrangement'] = self::channelArrangementLookup($info['dts']['raw']['channel_arrangement']);
+
+ $info['audio']['dataformat'] = 'dts';
+ $info['audio']['lossless'] = $info['dts']['flags']['lossless'];
+ $info['audio']['bitrate_mode'] = $info['dts']['bitrate_mode'];
+ $info['audio']['bits_per_sample'] = $info['dts']['bits_per_sample'];
+ $info['audio']['sample_rate'] = $info['dts']['sample_rate'];
+ $info['audio']['channels'] = $info['dts']['channels'];
+ $info['audio']['bitrate'] = $info['dts']['bitrate'];
+ if (isset($info['avdataend']) && !empty($info['dts']['bitrate']) && is_numeric($info['dts']['bitrate'])) {
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($info['dts']['bitrate'] / 8);
+ if (($encoding == 2) || ($encoding == 3)) {
+ // 14-bit data packed into 16-bit words, so the playtime is wrong because only (14/16) of the bytes in the data portion of the file are used at the specified bitrate
+ $info['playtime_seconds'] *= (14 / 16);
+ }
+ }
+ return true;
+ }
+
+ private function readBinData($bin, $length) {
+ $data = substr($bin, $this->readBinDataOffset, $length);
+ $this->readBinDataOffset += $length;
+
+ return bindec($data);
+ }
+
+ public static function bitrateLookup($index) {
+ static $lookup = array(
+ 0 => 32000,
+ 1 => 56000,
+ 2 => 64000,
+ 3 => 96000,
+ 4 => 112000,
+ 5 => 128000,
+ 6 => 192000,
+ 7 => 224000,
+ 8 => 256000,
+ 9 => 320000,
+ 10 => 384000,
+ 11 => 448000,
+ 12 => 512000,
+ 13 => 576000,
+ 14 => 640000,
+ 15 => 768000,
+ 16 => 960000,
+ 17 => 1024000,
+ 18 => 1152000,
+ 19 => 1280000,
+ 20 => 1344000,
+ 21 => 1408000,
+ 22 => 1411200,
+ 23 => 1472000,
+ 24 => 1536000,
+ 25 => 1920000,
+ 26 => 2048000,
+ 27 => 3072000,
+ 28 => 3840000,
+ 29 => 'open',
+ 30 => 'variable',
+ 31 => 'lossless',
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : false);
+ }
+
+ public static function sampleRateLookup($index) {
+ static $lookup = array(
+ 0 => 'invalid',
+ 1 => 8000,
+ 2 => 16000,
+ 3 => 32000,
+ 4 => 'invalid',
+ 5 => 'invalid',
+ 6 => 11025,
+ 7 => 22050,
+ 8 => 44100,
+ 9 => 'invalid',
+ 10 => 'invalid',
+ 11 => 12000,
+ 12 => 24000,
+ 13 => 48000,
+ 14 => 'invalid',
+ 15 => 'invalid',
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : false);
+ }
+
+ public static function bitPerSampleLookup($index) {
+ static $lookup = array(
+ 0 => 16,
+ 1 => 20,
+ 2 => 24,
+ 3 => 24,
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : false);
+ }
+
+ public static function numChannelsLookup($index) {
+ switch ($index) {
+ case 0:
+ return 1;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return 2;
+ break;
+ case 5:
+ case 6:
+ return 3;
+ break;
+ case 7:
+ case 8:
+ return 4;
+ break;
+ case 9:
+ return 5;
+ break;
+ case 10:
+ case 11:
+ case 12:
+ return 6;
+ break;
+ case 13:
+ return 7;
+ break;
+ case 14:
+ case 15:
+ return 8;
+ break;
+ }
+ return false;
+ }
+
+ public static function channelArrangementLookup($index) {
+ static $lookup = array(
+ 0 => 'A',
+ 1 => 'A + B (dual mono)',
+ 2 => 'L + R (stereo)',
+ 3 => '(L+R) + (L-R) (sum-difference)',
+ 4 => 'LT + RT (left and right total)',
+ 5 => 'C + L + R',
+ 6 => 'L + R + S',
+ 7 => 'C + L + R + S',
+ 8 => 'L + R + SL + SR',
+ 9 => 'C + L + R + SL + SR',
+ 10 => 'CL + CR + L + R + SL + SR',
+ 11 => 'C + L + R+ LR + RR + OV',
+ 12 => 'CF + CR + LF + RF + LR + RR',
+ 13 => 'CL + C + CR + L + R + SL + SR',
+ 14 => 'CL + CR + L + R + SL1 + SL2 + SR1 + SR2',
+ 15 => 'CL + C+ CR + L + R + SL + S + SR',
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined');
+ }
+
+ public static function dialogNormalization($index, $version) {
+ switch ($version) {
+ case 7:
+ return 0 - $index;
+ break;
+ case 6:
+ return 0 - 16 - $index;
+ break;
+ }
+ return false;
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio.flac.php b/src/wp-includes/ID3/module.audio.flac.php
new file mode 100644
index 0000000000..6b9598c741
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio.flac.php
@@ -0,0 +1,442 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.flac.php //
+// module for analyzing FLAC and OggFLAC audio files //
+// dependencies: module.audio.ogg.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
+
+/**
+* @tutorial http://flac.sourceforge.net/format.html
+*/
+class getid3_flac extends getid3_handler
+{
+ const syncword = 'fLaC';
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $this->fseek($info['avdataoffset']);
+ $StreamMarker = $this->fread(4);
+ if ($StreamMarker != self::syncword) {
+ return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($StreamMarker).'"');
+ }
+ $info['fileformat'] = 'flac';
+ $info['audio']['dataformat'] = 'flac';
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['lossless'] = true;
+
+ // parse flac container
+ return $this->parseMETAdata();
+ }
+
+ public function parseMETAdata() {
+ $info = &$this->getid3->info;
+ do {
+ $BlockOffset = $this->ftell();
+ $BlockHeader = $this->fread(4);
+ $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));
+ $LastBlockFlag = (bool) ($LBFBT & 0x80);
+ $BlockType = ($LBFBT & 0x7F);
+ $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
+ $BlockTypeText = self::metaBlockTypeLookup($BlockType);
+
+ if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
+ $this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
+ break;
+ }
+ if ($BlockLength < 1) {
+ $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
+ break;
+ }
+
+ $info['flac'][$BlockTypeText]['raw'] = array();
+ $BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw'];
+
+ $BlockTypeText_raw['offset'] = $BlockOffset;
+ $BlockTypeText_raw['last_meta_block'] = $LastBlockFlag;
+ $BlockTypeText_raw['block_type'] = $BlockType;
+ $BlockTypeText_raw['block_type_text'] = $BlockTypeText;
+ $BlockTypeText_raw['block_length'] = $BlockLength;
+ if ($BlockTypeText_raw['block_type'] != 0x06) { // do not read attachment data automatically
+ $BlockTypeText_raw['block_data'] = $this->fread($BlockLength);
+ }
+
+ switch ($BlockTypeText) {
+ case 'STREAMINFO': // 0x00
+ if (!$this->parseSTREAMINFO($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'PADDING': // 0x01
+ unset($info['flac']['PADDING']); // ignore
+ break;
+
+ case 'APPLICATION': // 0x02
+ if (!$this->parseAPPLICATION($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'SEEKTABLE': // 0x03
+ if (!$this->parseSEEKTABLE($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'VORBIS_COMMENT': // 0x04
+ if (!$this->parseVORBIS_COMMENT($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'CUESHEET': // 0x05
+ if (!$this->parseCUESHEET($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'PICTURE': // 0x06
+ if (!$this->parsePICTURE()) {
+ return false;
+ }
+ break;
+
+ default:
+ $this->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.') at offset '.$BlockOffset);
+ }
+
+ unset($info['flac'][$BlockTypeText]['raw']);
+ $info['avdataoffset'] = $this->ftell();
+ }
+ while ($LastBlockFlag === false);
+
+ // handle tags
+ if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) {
+ $info['flac']['comments'] = $info['flac']['VORBIS_COMMENT']['comments'];
+ }
+ if (!empty($info['flac']['VORBIS_COMMENT']['vendor'])) {
+ $info['audio']['encoder'] = str_replace('reference ', '', $info['flac']['VORBIS_COMMENT']['vendor']);
+ }
+
+ // copy attachments to 'comments' array if nesesary
+ if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) {
+ foreach ($info['flac']['PICTURE'] as $entry) {
+ if (!empty($entry['data'])) {
+ $info['flac']['comments']['picture'][] = array('image_mime'=>$entry['image_mime'], 'data'=>$entry['data']);
+ }
+ }
+ }
+
+ if (isset($info['flac']['STREAMINFO'])) {
+ if (!$this->isDependencyFor('matroska')) {
+ $info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset'];
+ }
+ $info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8);
+ if ($info['flac']['uncompressed_audio_bytes'] == 0) {
+ return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero');
+ }
+ if (!empty($info['flac']['compressed_audio_bytes'])) {
+ $info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes'];
+ }
+ }
+
+ // set md5_data_source - built into flac 0.5+
+ if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
+
+ if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
+ $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
+ }
+ else {
+ $info['md5_data_source'] = '';
+ $md5 = $info['flac']['STREAMINFO']['audio_signature'];
+ for ($i = 0; $i < strlen($md5); $i++) {
+ $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
+ }
+ if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
+ unset($info['md5_data_source']);
+ }
+ }
+ }
+
+ if (isset($info['flac']['STREAMINFO']['bits_per_sample'])) {
+ $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
+ if ($info['audio']['bits_per_sample'] == 8) {
+ // special case
+ // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value
+ // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed
+ $this->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file');
+ }
+ }
+
+ return true;
+ }
+
+ private function parseSTREAMINFO($BlockData) {
+ $info = &$this->getid3->info;
+
+ $info['flac']['STREAMINFO'] = array();
+ $streaminfo = &$info['flac']['STREAMINFO'];
+
+ $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
+ $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
+ $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
+ $streaminfo['max_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3));
+
+ $SRCSBSS = getid3_lib::BigEndian2Bin(substr($BlockData, 10, 8));
+ $streaminfo['sample_rate'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 0, 20));
+ $streaminfo['channels'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 20, 3)) + 1;
+ $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1;
+ $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
+
+ $streaminfo['audio_signature'] = substr($BlockData, 18, 16);
+
+ if (!empty($streaminfo['sample_rate'])) {
+
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['sample_rate'] = $streaminfo['sample_rate'];
+ $info['audio']['channels'] = $streaminfo['channels'];
+ $info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample'];
+ $info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate'];
+ if ($info['playtime_seconds'] > 0) {
+ if (!$this->isDependencyFor('matroska')) {
+ $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+ }
+ else {
+ $this->warning('Cannot determine audio bitrate because total stream size is unknown');
+ }
+ }
+
+ } else {
+ return $this->error('Corrupt METAdata block: STREAMINFO');
+ }
+
+ return true;
+ }
+
+ private function parseAPPLICATION($BlockData) {
+ $info = &$this->getid3->info;
+
+ $ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4));
+ $info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID);
+ $info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4);
+
+ return true;
+ }
+
+ private function parseSEEKTABLE($BlockData) {
+ $info = &$this->getid3->info;
+
+ $offset = 0;
+ $BlockLength = strlen($BlockData);
+ $placeholderpattern = str_repeat("\xFF", 8);
+ while ($offset < $BlockLength) {
+ $SampleNumberString = substr($BlockData, $offset, 8);
+ $offset += 8;
+ if ($SampleNumberString == $placeholderpattern) {
+
+ // placeholder point
+ getid3_lib::safe_inc($info['flac']['SEEKTABLE']['placeholders'], 1);
+ $offset += 10;
+
+ } else {
+
+ $SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString);
+ $info['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 2));
+ $offset += 2;
+
+ }
+ }
+
+ return true;
+ }
+
+ private function parseVORBIS_COMMENT($BlockData) {
+ $info = &$this->getid3->info;
+
+ $getid3_ogg = new getid3_ogg($this->getid3);
+ if ($this->isDependencyFor('matroska')) {
+ $getid3_ogg->setStringMode($this->data_string);
+ }
+ $getid3_ogg->ParseVorbisComments();
+ if (isset($info['ogg'])) {
+ unset($info['ogg']['comments_raw']);
+ $info['flac']['VORBIS_COMMENT'] = $info['ogg'];
+ unset($info['ogg']);
+ }
+
+ unset($getid3_ogg);
+
+ return true;
+ }
+
+ private function parseCUESHEET($BlockData) {
+ $info = &$this->getid3->info;
+ $offset = 0;
+ $info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($BlockData, $offset, 128), "\0");
+ $offset += 128;
+ $info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $info['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)) & 0x80);
+ $offset += 1;
+
+ $offset += 258; // reserved
+
+ $info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ for ($track = 0; $track < $info['flac']['CUESHEET']['number_tracks']; $track++) {
+ $TrackSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $TrackNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset;
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($BlockData, $offset, 12);
+ $offset += 12;
+
+ $TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
+
+ $offset += 13; // reserved
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ for ($index = 0; $index < $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) {
+ $IndexSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $IndexNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ $offset += 3; // reserved
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
+ * External usage: audio.ogg
+ */
+ public function parsePICTURE() {
+ $info = &$this->getid3->info;
+
+ $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['type'] = self::pictureTypeLookup($picture['typeid']);
+ $picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
+ $descr_length = getid3_lib::BigEndian2Int($this->fread(4));
+ if ($descr_length) {
+ $picture['description'] = $this->fread($descr_length);
+ }
+ $picture['width'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['height'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $data_length = getid3_lib::BigEndian2Int($this->fread(4));
+
+ if ($picture['image_mime'] == '-->') {
+ $picture['data'] = $this->fread($data_length);
+ } else {
+ $picture['data'] = $this->saveAttachment(
+ str_replace('/', '_', $picture['type']).'_'.$this->ftell(),
+ $this->ftell(),
+ $data_length,
+ $picture['image_mime']);
+ }
+
+ $info['flac']['PICTURE'][] = $picture;
+
+ return true;
+ }
+
+ public static function metaBlockTypeLookup($blocktype) {
+ static $lookup = array(
+ 0 => 'STREAMINFO',
+ 1 => 'PADDING',
+ 2 => 'APPLICATION',
+ 3 => 'SEEKTABLE',
+ 4 => 'VORBIS_COMMENT',
+ 5 => 'CUESHEET',
+ 6 => 'PICTURE',
+ );
+ return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
+ }
+
+ public static function applicationIDLookup($applicationid) {
+ // http://flac.sourceforge.net/id.html
+ static $lookup = array(
+ 0x41544348 => 'FlacFile', // "ATCH"
+ 0x42534F4C => 'beSolo', // "BSOL"
+ 0x42554753 => 'Bugs Player', // "BUGS"
+ 0x43756573 => 'GoldWave cue points (specification)', // "Cues"
+ 0x46696361 => 'CUE Splitter', // "Fica"
+ 0x46746F6C => 'flac-tools', // "Ftol"
+ 0x4D4F5442 => 'MOTB MetaCzar', // "MOTB"
+ 0x4D505345 => 'MP3 Stream Editor', // "MPSE"
+ 0x4D754D4C => 'MusicML: Music Metadata Language', // "MuML"
+ 0x52494646 => 'Sound Devices RIFF chunk storage', // "RIFF"
+ 0x5346464C => 'Sound Font FLAC', // "SFFL"
+ 0x534F4E59 => 'Sony Creative Software', // "SONY"
+ 0x5351455A => 'flacsqueeze', // "SQEZ"
+ 0x54745776 => 'TwistedWave', // "TtWv"
+ 0x55495453 => 'UITS Embedding tools', // "UITS"
+ 0x61696666 => 'FLAC AIFF chunk storage', // "aiff"
+ 0x696D6167 => 'flac-image application for storing arbitrary files in APPLICATION metadata blocks', // "imag"
+ 0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // "peem"
+ 0x71667374 => 'QFLAC Studio', // "qfst"
+ 0x72696666 => 'FLAC RIFF chunk storage', // "riff"
+ 0x74756E65 => 'TagTuner', // "tune"
+ 0x78626174 => 'XBAT', // "xbat"
+ 0x786D6364 => 'xmcd', // "xmcd"
+ );
+ return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
+ }
+
+ public static function pictureTypeLookup($type_id) {
+ static $lookup = array (
+ 0 => 'Other',
+ 1 => '32x32 pixels \'file icon\' (PNG only)',
+ 2 => 'Other file icon',
+ 3 => 'Cover (front)',
+ 4 => 'Cover (back)',
+ 5 => 'Leaflet page',
+ 6 => 'Media (e.g. label side of CD)',
+ 7 => 'Lead artist/lead performer/soloist',
+ 8 => 'Artist/performer',
+ 9 => 'Conductor',
+ 10 => 'Band/Orchestra',
+ 11 => 'Composer',
+ 12 => 'Lyricist/text writer',
+ 13 => 'Recording Location',
+ 14 => 'During recording',
+ 15 => 'During performance',
+ 16 => 'Movie/video screen capture',
+ 17 => 'A bright coloured fish',
+ 18 => 'Illustration',
+ 19 => 'Band/artist logotype',
+ 20 => 'Publisher/Studio logotype',
+ );
+ return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio.mp3.php b/src/wp-includes/ID3/module.audio.mp3.php
new file mode 100644
index 0000000000..e6ffea947b
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio.mp3.php
@@ -0,0 +1,2009 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.mp3.php //
+// module for analyzing MP3 files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+// number of frames to scan to determine if MPEG-audio sequence is valid
+// Lower this number to 5-20 for faster scanning
+// Increase this number to 50+ for most accurate detection of valid VBR/CBR
+// mpeg-audio streams
+define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
+
+
+class getid3_mp3 extends getid3_handler
+{
+
+ public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $initialOffset = $info['avdataoffset'];
+
+ if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
+ if ($this->allow_bruteforce) {
+ $info['error'][] = 'Rescanning file in BruteForce mode';
+ $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info);
+ }
+ }
+
+
+ if (isset($info['mpeg']['audio']['bitrate_mode'])) {
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ }
+
+ if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
+
+ $synchoffsetwarning = 'Unknown data before synch ';
+ if (isset($info['id3v2']['headerlength'])) {
+ $synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
+ } elseif ($initialOffset > 0) {
+ $synchoffsetwarning .= '(should be at '.$initialOffset.', ';
+ } else {
+ $synchoffsetwarning .= '(should be at beginning of file, ';
+ }
+ $synchoffsetwarning .= 'synch detected at '.$info['avdataoffset'].')';
+ if (isset($info['audio']['bitrate_mode']) && ($info['audio']['bitrate_mode'] == 'cbr')) {
+
+ if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) {
+
+ $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.';
+ $info['audio']['codec'] = 'LAME';
+ $CurrentDataLAMEversionString = 'LAME3.';
+
+ } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) {
+
+ $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.';
+ $info['audio']['codec'] = 'LAME';
+ $CurrentDataLAMEversionString = 'LAME3.';
+
+ }
+
+ }
+ $info['warning'][] = $synchoffsetwarning;
+
+ }
+
+ if (isset($info['mpeg']['audio']['LAME'])) {
+ $info['audio']['codec'] = 'LAME';
+ if (!empty($info['mpeg']['audio']['LAME']['long_version'])) {
+ $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00");
+ } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) {
+ $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00");
+ }
+ }
+
+ $CurrentDataLAMEversionString = (!empty($CurrentDataLAMEversionString) ? $CurrentDataLAMEversionString : (isset($info['audio']['encoder']) ? $info['audio']['encoder'] : ''));
+ if (!empty($CurrentDataLAMEversionString) && (substr($CurrentDataLAMEversionString, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($CurrentDataLAMEversionString, -1))) {
+ // a version number of LAME that does not end with a number like "LAME3.92"
+ // or with a closing parenthesis like "LAME3.88 (alpha)"
+ // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92)
+
+ // not sure what the actual last frame length will be, but will be less than or equal to 1441
+ $PossiblyLongerLAMEversion_FrameLength = 1441;
+
+ // Not sure what version of LAME this is - look in padding of last frame for longer version string
+ $PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
+ fseek($this->getid3->fp, $PossibleLAMEversionStringOffset);
+ $PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength);
+ switch (substr($CurrentDataLAMEversionString, -1)) {
+ case 'a':
+ case 'b':
+ // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
+ // need to trim off "a" to match longer string
+ $CurrentDataLAMEversionString = substr($CurrentDataLAMEversionString, 0, -1);
+ break;
+ }
+ if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) {
+ if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
+ $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
+ if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
+ $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
+ }
+ }
+ }
+ }
+ if (!empty($info['audio']['encoder'])) {
+ $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 ");
+ }
+
+ switch (isset($info['mpeg']['audio']['layer']) ? $info['mpeg']['audio']['layer'] : '') {
+ case 1:
+ case 2:
+ $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
+ break;
+ }
+ if (isset($info['fileformat']) && ($info['fileformat'] == 'mp3')) {
+ switch ($info['audio']['dataformat']) {
+ case 'mp1':
+ case 'mp2':
+ case 'mp3':
+ $info['fileformat'] = $info['audio']['dataformat'];
+ break;
+
+ default:
+ $info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"';
+ break;
+ }
+ }
+
+ if (empty($info['fileformat'])) {
+ unset($info['fileformat']);
+ unset($info['audio']['bitrate_mode']);
+ unset($info['avdataoffset']);
+ unset($info['avdataend']);
+ return false;
+ }
+
+ $info['mime_type'] = 'audio/mpeg';
+ $info['audio']['lossless'] = false;
+
+ // Calculate playtime
+ if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
+ }
+
+ $info['audio']['encoder_options'] = $this->GuessEncoderOptions();
+
+ return true;
+ }
+
+
+ public function GuessEncoderOptions() {
+ // shortcuts
+ $info = &$this->getid3->info;
+ if (!empty($info['mpeg']['audio'])) {
+ $thisfile_mpeg_audio = &$info['mpeg']['audio'];
+ if (!empty($thisfile_mpeg_audio['LAME'])) {
+ $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
+ }
+ }
+
+ $encoder_options = '';
+ static $NamedPresetBitrates = array(16, 24, 40, 56, 112, 128, 160, 192, 256);
+
+ if (isset($thisfile_mpeg_audio['VBR_method']) && ($thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) {
+
+ $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
+
+ } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
+
+ $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
+
+ } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) {
+
+ static $KnownEncoderValues = array();
+ if (empty($KnownEncoderValues)) {
+
+ //$KnownEncoderValues[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name';
+ $KnownEncoderValues[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91
+ $KnownEncoderValues[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95
+ $KnownEncoderValues['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91
+ $KnownEncoderValues['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3
+ $KnownEncoderValues['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91
+ $KnownEncoderValues['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3
+ $KnownEncoderValues['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3
+ $KnownEncoderValues['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91
+ $KnownEncoderValues['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95
+ $KnownEncoderValues['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3
+ $KnownEncoderValues['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3
+
+ $KnownEncoderValues[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93
+ $KnownEncoderValues[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95
+ $KnownEncoderValues[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93
+ $KnownEncoderValues[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95
+ $KnownEncoderValues[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95
+ $KnownEncoderValues[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95
+ $KnownEncoderValues[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95
+ $KnownEncoderValues[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14
+ $KnownEncoderValues[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91
+ $KnownEncoderValues[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95
+ $KnownEncoderValues[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14
+ $KnownEncoderValues[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15
+ $KnownEncoderValues[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93
+ $KnownEncoderValues[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95
+ $KnownEncoderValues[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14
+ $KnownEncoderValues[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15
+ $KnownEncoderValues[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93
+ $KnownEncoderValues[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95
+ }
+
+ if (isset($KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
+
+ $encoder_options = $KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
+
+ } elseif (isset($KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
+
+ $encoder_options = $KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
+
+ } elseif ($info['audio']['bitrate_mode'] == 'vbr') {
+
+ // http://gabriel.mp3-tech.org/mp3infotag.html
+ // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h
+
+
+ $LAME_V_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10);
+ $LAME_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10);
+ $encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value;
+
+ } elseif ($info['audio']['bitrate_mode'] == 'cbr') {
+
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
+
+ } else {
+
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']);
+
+ }
+
+ } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) {
+
+ $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
+
+ } elseif (!empty($info['audio']['bitrate'])) {
+
+ if ($info['audio']['bitrate_mode'] == 'cbr') {
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
+ } else {
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']);
+ }
+
+ }
+ if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) {
+ $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min'];
+ }
+
+ if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) {
+ $encoder_options .= ' --nogap';
+ }
+
+ if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) {
+ $ExplodedOptions = explode(' ', $encoder_options, 4);
+ if ($ExplodedOptions[0] == '--r3mix') {
+ $ExplodedOptions[1] = 'r3mix';
+ }
+ switch ($ExplodedOptions[0]) {
+ case '--preset':
+ case '--alt-preset':
+ case '--r3mix':
+ if ($ExplodedOptions[1] == 'fast') {
+ $ExplodedOptions[1] .= ' '.$ExplodedOptions[2];
+ }
+ switch ($ExplodedOptions[1]) {
+ case 'portable':
+ case 'medium':
+ case 'standard':
+ case 'extreme':
+ case 'insane':
+ case 'fast portable':
+ case 'fast medium':
+ case 'fast standard':
+ case 'fast extreme':
+ case 'fast insane':
+ case 'r3mix':
+ static $ExpectedLowpass = array(
+ 'insane|20500' => 20500,
+ 'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91
+ 'medium|18000' => 18000,
+ 'fast medium|18000' => 18000,
+ 'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
+ 'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
+ 'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
+ 'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
+ 'standard|19000' => 19000,
+ 'fast standard|19000' => 19000,
+ 'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92
+ 'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91
+ 'r3mix|18000' => 18000, // 3.94, 3.95
+ );
+ if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) {
+ $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) {
+ if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) {
+ $encoder_options .= ' --resample 44100';
+ } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) {
+ $encoder_options .= ' --resample 48000';
+ } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) {
+ switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) {
+ case 0: // <= 32000
+ // may or may not be same as source frequency - ignore
+ break;
+ case 1: // 44100
+ case 2: // 48000
+ case 3: // 48000+
+ $ExplodedOptions = explode(' ', $encoder_options, 4);
+ switch ($ExplodedOptions[0]) {
+ case '--preset':
+ case '--alt-preset':
+ switch ($ExplodedOptions[1]) {
+ case 'fast':
+ case 'portable':
+ case 'medium':
+ case 'standard':
+ case 'extreme':
+ case 'insane':
+ $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
+ break;
+
+ default:
+ static $ExpectedResampledRate = array(
+ 'phon+/lw/mw-eu/sw|16000' => 16000,
+ 'mw-us|24000' => 24000, // 3.95
+ 'mw-us|32000' => 32000, // 3.93
+ 'mw-us|16000' => 16000, // 3.92
+ 'phone|16000' => 16000,
+ 'phone|11025' => 11025, // 3.94a15
+ 'radio|32000' => 32000, // 3.94a15
+ 'fm/radio|32000' => 32000, // 3.92
+ 'fm|32000' => 32000, // 3.90
+ 'voice|32000' => 32000);
+ if (!isset($ExpectedResampledRate[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio['sample_rate']])) {
+ $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
+ }
+ break;
+ }
+ break;
+
+ case '--r3mix':
+ default:
+ $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
+ break;
+ }
+ break;
+ }
+ }
+ }
+ if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) {
+ //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']);
+ }
+
+ return $encoder_options;
+ }
+
+
+ public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
+ static $MPEGaudioVersionLookup;
+ static $MPEGaudioLayerLookup;
+ static $MPEGaudioBitrateLookup;
+ static $MPEGaudioFrequencyLookup;
+ static $MPEGaudioChannelModeLookup;
+ static $MPEGaudioModeExtensionLookup;
+ static $MPEGaudioEmphasisLookup;
+ if (empty($MPEGaudioVersionLookup)) {
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+ $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
+ $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
+ $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
+ $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
+ }
+
+ if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) {
+ $info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
+ return false;
+ }
+ //$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
+ $headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
+
+ // MP3 audio frame structure:
+ // $aa $aa $aa $aa [$bb $bb] $cc...
+ // where $aa..$aa is the four-byte mpeg-audio header (below)
+ // $bb $bb is the optional 2-byte CRC
+ // and $cc... is the audio data
+
+ $head4 = substr($headerstring, 0, 4);
+
+ static $MPEGaudioHeaderDecodeCache = array();
+ if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
+ $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
+ } else {
+ $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4);
+ $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
+ }
+
+ static $MPEGaudioHeaderValidCache = array();
+ if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache
+ //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)
+ $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);
+ }
+
+ // shortcut
+ if (!isset($info['mpeg']['audio'])) {
+ $info['mpeg']['audio'] = array();
+ }
+ $thisfile_mpeg_audio = &$info['mpeg']['audio'];
+
+
+ if ($MPEGaudioHeaderValidCache[$head4]) {
+ $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
+ } else {
+ $info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset;
+ return false;
+ }
+
+ if (!$FastMPEGheaderScan) {
+ $thisfile_mpeg_audio['version'] = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']];
+ $thisfile_mpeg_audio['layer'] = $MPEGaudioLayerLookup[$thisfile_mpeg_audio['raw']['layer']];
+
+ $thisfile_mpeg_audio['channelmode'] = $MPEGaudioChannelModeLookup[$thisfile_mpeg_audio['raw']['channelmode']];
+ $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2);
+ $thisfile_mpeg_audio['sample_rate'] = $MPEGaudioFrequencyLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']];
+ $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection'];
+ $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private'];
+ $thisfile_mpeg_audio['modeextension'] = $MPEGaudioModeExtensionLookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']];
+ $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright'];
+ $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original'];
+ $thisfile_mpeg_audio['emphasis'] = $MPEGaudioEmphasisLookup[$thisfile_mpeg_audio['raw']['emphasis']];
+
+ $info['audio']['channels'] = $thisfile_mpeg_audio['channels'];
+ $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate'];
+
+ if ($thisfile_mpeg_audio['protection']) {
+ $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($headerstring, 4, 2));
+ }
+ }
+
+ if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
+ // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
+ $info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
+ $thisfile_mpeg_audio['raw']['bitrate'] = 0;
+ }
+ $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
+ $thisfile_mpeg_audio['bitrate'] = $MPEGaudioBitrateLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']];
+
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) {
+ // only skip multiple frame check if free-format bitstream found at beginning of file
+ // otherwise is quite possibly simply corrupted data
+ $recursivesearch = false;
+ }
+
+ // For Layer 2 there are some combinations of bitrate and mode which are not allowed.
+ if (!$FastMPEGheaderScan && ($thisfile_mpeg_audio['layer'] == '2')) {
+
+ $info['audio']['dataformat'] = 'mp2';
+ switch ($thisfile_mpeg_audio['channelmode']) {
+
+ case 'mono':
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
+ // these are ok
+ } else {
+ $info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
+ return false;
+ }
+ break;
+
+ case 'stereo':
+ case 'joint stereo':
+ case 'dual channel':
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
+ // these are ok
+ } else {
+ $info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
+ return false;
+ }
+ break;
+
+ }
+
+ }
+
+
+ if ($info['audio']['sample_rate'] > 0) {
+ $thisfile_mpeg_audio['framelength'] = self::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']);
+ }
+
+ $nextframetestoffset = $offset + 1;
+ if ($thisfile_mpeg_audio['bitrate'] != 'free') {
+
+ $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
+
+ if (isset($thisfile_mpeg_audio['framelength'])) {
+ $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength'];
+ } else {
+ $info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.';
+ return false;
+ }
+
+ }
+
+ $ExpectedNumberOfAudioBytes = 0;
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Variable-bitrate headers
+
+ if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
+ // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
+ // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
+
+ $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
+ $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer';
+ $info['audio']['codec'] = 'Fraunhofer';
+
+ $SideInfoData = substr($headerstring, 4 + 2, 32);
+
+ $FraunhoferVBROffset = 36;
+
+ $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2)); // VbriVersion
+ $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2)); // VbriDelay
+ $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2)); // VbriQuality
+ $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4)); // VbriStreamBytes
+ $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4)); // VbriStreamFrames
+ $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2)); // VbriTableSize
+ $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 2)); // VbriTableScale
+ $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 22, 2)); // VbriEntryBytes
+ $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2)); // VbriEntryFrames
+
+ $ExpectedNumberOfAudioBytes = $thisfile_mpeg_audio['VBR_bytes'];
+
+ $previousbyteoffset = $offset;
+ for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) {
+ $Fraunhofer_OffsetN = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, $thisfile_mpeg_audio['VBR_entry_bytes']));
+ $FraunhoferVBROffset += $thisfile_mpeg_audio['VBR_entry_bytes'];
+ $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']);
+ $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']) + $previousbyteoffset;
+ $previousbyteoffset += $Fraunhofer_OffsetN;
+ }
+
+
+ } else {
+
+ // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
+ // depending on MPEG layer and number of channels
+
+ $VBRidOffset = self::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']);
+ $SideInfoData = substr($headerstring, 4 + 2, $VBRidOffset - 4);
+
+ if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info')) {
+ // 'Xing' is traditional Xing VBR frame
+ // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
+ // 'Info' *can* legally be used to specify a VBR file as well, however.
+
+ // http://www.multiweb.cz/twoinches/MP3inside.htm
+ //00..03 = "Xing" or "Info"
+ //04..07 = Flags:
+ // 0x01 Frames Flag set if value for number of frames in file is stored
+ // 0x02 Bytes Flag set if value for filesize in bytes is stored
+ // 0x04 TOC Flag set if values for TOC are stored
+ // 0x08 VBR Scale Flag set if values for VBR scale is stored
+ //08..11 Frames: Number of frames in file (including the first Xing/Info one)
+ //12..15 Bytes: File length in Bytes
+ //16..115 TOC (Table of Contents):
+ // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
+ // Each Byte has a value according this formula:
+ // (TOC[i] / 256) * fileLenInBytes
+ // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use:
+ // TOC[(60/240)*100] = TOC[25]
+ // and corresponding Byte in file is then approximately at:
+ // (TOC[25]/256) * 5000000
+ //116..119 VBR Scale
+
+
+ // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME
+// if (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Xing') {
+ $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
+ $thisfile_mpeg_audio['VBR_method'] = 'Xing';
+// } else {
+// $ScanAsCBR = true;
+// $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+// }
+
+ $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4));
+
+ $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001);
+ $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002);
+ $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004);
+ $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008);
+
+ if ($thisfile_mpeg_audio['xing_flags']['frames']) {
+ $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4));
+ //$thisfile_mpeg_audio['VBR_frames']--; // don't count header Xing/Info frame
+ }
+ if ($thisfile_mpeg_audio['xing_flags']['bytes']) {
+ $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4));
+ }
+
+ //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
+ if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
+
+ $framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames'];
+
+ if ($thisfile_mpeg_audio['layer'] == '1') {
+ // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
+ //$info['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
+ $info['audio']['bitrate'] = ($framelengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12;
+ } else {
+ // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
+ //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
+ $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144;
+ }
+ $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat);
+ }
+
+ if ($thisfile_mpeg_audio['xing_flags']['toc']) {
+ $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
+ for ($i = 0; $i < 100; $i++) {
+ $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i});
+ }
+ }
+ if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
+ $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4));
+ }
+
+
+ // http://gabriel.mp3-tech.org/mp3infotag.html
+ if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') {
+
+ // shortcut
+ $thisfile_mpeg_audio['LAME'] = array();
+ $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
+
+
+ $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
+ $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
+
+ if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
+
+ // extra 11 chars are not part of version string when LAMEtag present
+ unset($thisfile_mpeg_audio_lame['long_version']);
+
+ // It the LAME tag was only introduced in LAME v3.90
+ // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
+
+ // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
+ // are assuming a 'Xing' identifier offset of 0x24, which is the case for
+ // MPEG-1 non-mono, but not for other combinations
+ $LAMEtagOffsetContant = $VBRidOffset - 0x24;
+
+ // shortcuts
+ $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array());
+ $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD'];
+ $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
+ $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
+ $thisfile_mpeg_audio_lame['raw'] = array();
+ $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw'];
+
+ // byte $9B VBR Quality
+ // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
+ // Actually overwrites original Xing bytes
+ unset($thisfile_mpeg_audio['VBR_scale']);
+ $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
+
+ // bytes $9C-$A4 Encoder short VersionString
+ $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
+
+ // byte $A5 Info Tag revision + VBR method
+ $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
+
+ $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
+ $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F;
+ $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
+ $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
+
+ // byte $A6 Lowpass filter value
+ $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
+
+ // bytes $A7-$AE Replay Gain
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
+ // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
+ if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
+ // LAME 3.94a16 and later - 9.23 fixed point
+ // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
+ $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
+ } else {
+ // LAME 3.94a15 and earlier - 32-bit floating point
+ // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
+ $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
+ }
+ if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
+ unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
+ } else {
+ $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
+ }
+
+ $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
+ $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
+
+
+ if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
+
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
+ $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
+ $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
+ $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
+
+ if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
+ $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
+ }
+ $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
+ $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
+ } else {
+ unset($thisfile_mpeg_audio_lame_RGAD['track']);
+ }
+ if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
+
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
+ $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
+ $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
+ $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
+
+ if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
+ $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
+ }
+ $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
+ $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
+ } else {
+ unset($thisfile_mpeg_audio_lame_RGAD['album']);
+ }
+ if (empty($thisfile_mpeg_audio_lame_RGAD)) {
+ unset($thisfile_mpeg_audio_lame['RGAD']);
+ }
+
+
+ // byte $AF Encoding flags + ATH Type
+ $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
+ $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
+ $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
+ $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
+ $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
+ $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F;
+
+ // byte $B0 if ABR {specified bitrate} else {minimal bitrate}
+ $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
+ if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
+ $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
+ } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
+ // ignore
+ } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
+ $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
+ }
+
+ // bytes $B1-$B3 Encoder delays
+ $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
+ $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
+ $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF;
+
+ // byte $B4 Misc
+ $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
+ $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03);
+ $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2;
+ $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
+ $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6;
+ $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
+ $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
+ $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
+ $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
+
+ // byte $B5 MP3 Gain
+ $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
+ $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
+ $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
+
+ // bytes $B6-$B7 Preset and surround info
+ $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
+ // Reserved = ($PresetSurroundBytes & 0xC000);
+ $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
+ $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
+ $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
+ $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
+ if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
+ $info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org';
+ }
+ if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
+ // this may change if 3.90.4 ever comes out
+ $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
+ }
+
+ // bytes $B8-$BB MusicLength
+ $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
+ $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
+
+ // bytes $BC-$BD MusicCRC
+ $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
+
+ // bytes $BE-$BF CRC-16 of Info Tag
+ $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
+
+
+ // LAME CBR
+ if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
+
+ $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+ $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
+ $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
+ //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
+ // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
+ //}
+
+ }
+
+ }
+ }
+
+ } else {
+
+ // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
+ $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+ if ($recursivesearch) {
+ $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
+ if ($this->RecursiveFrameScanning($offset, $nextframetestoffset, true)) {
+ $recursivesearch = false;
+ $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+ }
+ if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
+ $info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
+ }
+ }
+
+ }
+
+ }
+
+ if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
+ if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
+ if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) {
+ // ignore, audio data is broken into chunks so will always be data "missing"
+ } elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
+ $info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
+ } else {
+ $info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)';
+ }
+ } else {
+ if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
+ // $prenullbytefileoffset = ftell($this->getid3->fp);
+ // fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
+ // $PossibleNullByte = fread($this->getid3->fp, 1);
+ // fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET);
+ // if ($PossibleNullByte === "\x00") {
+ $info['avdataend']--;
+ // $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
+ // } else {
+ // $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
+ // }
+ } else {
+ $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
+ }
+ }
+ }
+
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) {
+ if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) {
+ $framebytelength = $this->FreeFormatFrameLength($offset, true);
+ if ($framebytelength > 0) {
+ $thisfile_mpeg_audio['framelength'] = $framebytelength;
+ if ($thisfile_mpeg_audio['layer'] == '1') {
+ // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
+ $info['audio']['bitrate'] = ((($framebytelength / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
+ } else {
+ // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
+ $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
+ }
+ } else {
+ $info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header';
+ }
+ }
+ }
+
+ if (isset($thisfile_mpeg_audio['VBR_frames']) ? $thisfile_mpeg_audio['VBR_frames'] : '') {
+ switch ($thisfile_mpeg_audio['bitrate_mode']) {
+ case 'vbr':
+ case 'abr':
+ $bytes_per_frame = 1152;
+ if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) {
+ $bytes_per_frame = 384;
+ } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) {
+ $bytes_per_frame = 576;
+ }
+ $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0);
+ if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) {
+ $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];
+ $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion
+ }
+ break;
+ }
+ }
+
+ // End variable-bitrate headers
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ if ($recursivesearch) {
+
+ if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
+ return false;
+ }
+
+ }
+
+
+ //if (false) {
+ // // experimental side info parsing section - not returning anything useful yet
+ //
+ // $SideInfoBitstream = getid3_lib::BigEndian2Bin($SideInfoData);
+ // $SideInfoOffset = 0;
+ //
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
+ // // MPEG-1 (mono)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // $SideInfoOffset += 5;
+ // } else {
+ // // MPEG-1 (stereo, joint-stereo, dual-channel)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // $SideInfoOffset += 3;
+ // }
+ // } else { // 2 or 2.5
+ // if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
+ // // MPEG-2, MPEG-2.5 (mono)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
+ // $SideInfoOffset += 8;
+ // $SideInfoOffset += 1;
+ // } else {
+ // // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
+ // $SideInfoOffset += 8;
+ // $SideInfoOffset += 2;
+ // }
+ // }
+ //
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
+ // for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
+ // $thisfile_mpeg_audio['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 2;
+ // }
+ // }
+ // }
+ // for ($granule = 0; $granule < (($thisfile_mpeg_audio['version'] == '1') ? 2 : 1); $granule++) {
+ // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
+ // $thisfile_mpeg_audio['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
+ // $SideInfoOffset += 12;
+ // $thisfile_mpeg_audio['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // $thisfile_mpeg_audio['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
+ // $SideInfoOffset += 8;
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
+ // $SideInfoOffset += 4;
+ // } else {
+ // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // }
+ // $thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ //
+ // if ($thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] == '1') {
+ //
+ // $thisfile_mpeg_audio['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
+ // $SideInfoOffset += 2;
+ // $thisfile_mpeg_audio['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ //
+ // for ($region = 0; $region < 2; $region++) {
+ // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
+ // $SideInfoOffset += 5;
+ // }
+ // $thisfile_mpeg_audio['table_select'][$granule][$channel][2] = 0;
+ //
+ // for ($window = 0; $window < 3; $window++) {
+ // $thisfile_mpeg_audio['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
+ // $SideInfoOffset += 3;
+ // }
+ //
+ // } else {
+ //
+ // for ($region = 0; $region < 3; $region++) {
+ // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
+ // $SideInfoOffset += 5;
+ // }
+ //
+ // $thisfile_mpeg_audio['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
+ // $SideInfoOffset += 4;
+ // $thisfile_mpeg_audio['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
+ // $SideInfoOffset += 3;
+ // $thisfile_mpeg_audio['block_type'][$granule][$channel] = 0;
+ // }
+ //
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // $thisfile_mpeg_audio['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ // }
+ // $thisfile_mpeg_audio['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ // $thisfile_mpeg_audio['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ // }
+ // }
+ //}
+
+ return true;
+ }
+
+ public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
+ $info = &$this->getid3->info;
+ $firstframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
+ $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
+
+ for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
+ // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
+ if (($nextframetestoffset + 4) >= $info['avdataend']) {
+ // end of file
+ return true;
+ }
+
+ $nextframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
+ if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
+ if ($ScanAsCBR) {
+ // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
+ if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
+ return false;
+ }
+ }
+
+
+ // next frame is OK, get ready to check the one after that
+ if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) {
+ $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
+ } else {
+ $info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.';
+ return false;
+ }
+
+ } elseif (!empty($firstframetestarray['mpeg']['audio']['framelength']) && (($nextframetestoffset + $firstframetestarray['mpeg']['audio']['framelength']) > $info['avdataend'])) {
+
+ // it's not the end of the file, but there's not enough data left for another frame, so assume it's garbage/padding and return OK
+ return true;
+
+ } else {
+
+ // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
+ $info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.';
+
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public function FreeFormatFrameLength($offset, $deepscan=false) {
+ $info = &$this->getid3->info;
+
+ fseek($this->getid3->fp, $offset, SEEK_SET);
+ $MPEGaudioData = fread($this->getid3->fp, 32768);
+
+ $SyncPattern1 = substr($MPEGaudioData, 0, 4);
+ // may be different pattern due to padding
+ $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
+ if ($SyncPattern2 === $SyncPattern1) {
+ $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};
+ }
+
+ $framelength = false;
+ $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4);
+ $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4);
+ if ($framelength1 > 4) {
+ $framelength = $framelength1;
+ }
+ if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
+ $framelength = $framelength2;
+ }
+ if (!$framelength) {
+
+ // LAME 3.88 has a different value for modeextension on the first frame vs the rest
+ $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4);
+ $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4);
+
+ if ($framelength1 > 4) {
+ $framelength = $framelength1;
+ }
+ if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
+ $framelength = $framelength2;
+ }
+ if (!$framelength) {
+ $info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset;
+ return false;
+ } else {
+ $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';
+ $info['audio']['codec'] = 'LAME';
+ $info['audio']['encoder'] = 'LAME3.88';
+ $SyncPattern1 = substr($SyncPattern1, 0, 3);
+ $SyncPattern2 = substr($SyncPattern2, 0, 3);
+ }
+ }
+
+ if ($deepscan) {
+
+ $ActualFrameLengthValues = array();
+ $nextoffset = $offset + $framelength;
+ while ($nextoffset < ($info['avdataend'] - 6)) {
+ fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET);
+ $NextSyncPattern = fread($this->getid3->fp, 6);
+ if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
+ // good - found where expected
+ $ActualFrameLengthValues[] = $framelength;
+ } elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) {
+ // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
+ $ActualFrameLengthValues[] = ($framelength - 1);
+ $nextoffset--;
+ } elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2)) {
+ // ok - found one byte later than expected (last frame was padded, first frame wasn't)
+ $ActualFrameLengthValues[] = ($framelength + 1);
+ $nextoffset++;
+ } else {
+ $info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset;
+ return false;
+ }
+ $nextoffset += $framelength;
+ }
+ if (count($ActualFrameLengthValues) > 0) {
+ $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues)));
+ }
+ }
+ return $framelength;
+ }
+
+ public function getOnlyMPEGaudioInfoBruteForce() {
+ $MPEGaudioHeaderDecodeCache = array();
+ $MPEGaudioHeaderValidCache = array();
+ $MPEGaudioHeaderLengthCache = array();
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+ $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
+ $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
+ $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
+ $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
+ $LongMPEGversionLookup = array();
+ $LongMPEGlayerLookup = array();
+ $LongMPEGbitrateLookup = array();
+ $LongMPEGpaddingLookup = array();
+ $LongMPEGfrequencyLookup = array();
+ $Distribution['bitrate'] = array();
+ $Distribution['frequency'] = array();
+ $Distribution['layer'] = array();
+ $Distribution['version'] = array();
+ $Distribution['padding'] = array();
+
+ $info = &$this->getid3->info;
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ $max_frames_scan = 5000;
+ $frames_scanned = 0;
+
+ $previousvalidframe = $info['avdataoffset'];
+ while (ftell($this->getid3->fp) < $info['avdataend']) {
+ set_time_limit(30);
+ $head4 = fread($this->getid3->fp, 4);
+ if (strlen($head4) < 4) {
+ break;
+ }
+ if ($head4{0} != "\xFF") {
+ for ($i = 1; $i < 4; $i++) {
+ if ($head4{$i} == "\xFF") {
+ fseek($this->getid3->fp, $i - 4, SEEK_CUR);
+ continue 2;
+ }
+ }
+ continue;
+ }
+ if (!isset($MPEGaudioHeaderDecodeCache[$head4])) {
+ $MPEGaudioHeaderDecodeCache[$head4] = self::MPEGaudioHeaderDecode($head4);
+ }
+ if (!isset($MPEGaudioHeaderValidCache[$head4])) {
+ $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false);
+ }
+ if ($MPEGaudioHeaderValidCache[$head4]) {
+
+ if (!isset($MPEGaudioHeaderLengthCache[$head4])) {
+ $LongMPEGversionLookup[$head4] = $MPEGaudioVersionLookup[$MPEGaudioHeaderDecodeCache[$head4]['version']];
+ $LongMPEGlayerLookup[$head4] = $MPEGaudioLayerLookup[$MPEGaudioHeaderDecodeCache[$head4]['layer']];
+ $LongMPEGbitrateLookup[$head4] = $MPEGaudioBitrateLookup[$LongMPEGversionLookup[$head4]][$LongMPEGlayerLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['bitrate']];
+ $LongMPEGpaddingLookup[$head4] = (bool) $MPEGaudioHeaderDecodeCache[$head4]['padding'];
+ $LongMPEGfrequencyLookup[$head4] = $MPEGaudioFrequencyLookup[$LongMPEGversionLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['sample_rate']];
+ $MPEGaudioHeaderLengthCache[$head4] = self::MPEGaudioFrameLength(
+ $LongMPEGbitrateLookup[$head4],
+ $LongMPEGversionLookup[$head4],
+ $LongMPEGlayerLookup[$head4],
+ $LongMPEGpaddingLookup[$head4],
+ $LongMPEGfrequencyLookup[$head4]);
+ }
+ if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
+ $WhereWeWere = ftell($this->getid3->fp);
+ fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
+ $next4 = fread($this->getid3->fp, 4);
+ if ($next4{0} == "\xFF") {
+ if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
+ $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
+ }
+ if (!isset($MPEGaudioHeaderValidCache[$next4])) {
+ $MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
+ }
+ if ($MPEGaudioHeaderValidCache[$next4]) {
+ fseek($this->getid3->fp, -4, SEEK_CUR);
+
+ getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
+ getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
+ if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
+ $pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
+ $info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
+ foreach ($Distribution as $key1 => $value1) {
+ foreach ($value1 as $key2 => $value2) {
+ $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
+ }
+ }
+ break;
+ }
+ continue;
+ }
+ }
+ unset($next4);
+ fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET);
+ }
+
+ }
+ }
+ foreach ($Distribution as $key => $value) {
+ ksort($Distribution[$key], SORT_NUMERIC);
+ }
+ ksort($Distribution['version'], SORT_STRING);
+ $info['mpeg']['audio']['bitrate_distribution'] = $Distribution['bitrate'];
+ $info['mpeg']['audio']['frequency_distribution'] = $Distribution['frequency'];
+ $info['mpeg']['audio']['layer_distribution'] = $Distribution['layer'];
+ $info['mpeg']['audio']['version_distribution'] = $Distribution['version'];
+ $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding'];
+ if (count($Distribution['version']) > 1) {
+ $info['error'][] = 'Corrupt file - more than one MPEG version detected';
+ }
+ if (count($Distribution['layer']) > 1) {
+ $info['error'][] = 'Corrupt file - more than one MPEG layer detected';
+ }
+ if (count($Distribution['frequency']) > 1) {
+ $info['error'][] = 'Corrupt file - more than one MPEG sample rate detected';
+ }
+
+
+ $bittotal = 0;
+ foreach ($Distribution['bitrate'] as $bitratevalue => $bitratecount) {
+ if ($bitratevalue != 'free') {
+ $bittotal += ($bitratevalue * $bitratecount);
+ }
+ }
+ $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']);
+ if ($info['mpeg']['audio']['frame_count'] == 0) {
+ $info['error'][] = 'no MPEG audio frames found';
+ return false;
+ }
+ $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']);
+ $info['mpeg']['audio']['bitrate_mode'] = ((count($Distribution['bitrate']) > 0) ? 'vbr' : 'cbr');
+ $info['mpeg']['audio']['sample_rate'] = getid3_lib::array_max($Distribution['frequency'], true);
+
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $info['audio']['dataformat'] = 'mp'.getid3_lib::array_max($Distribution['layer'], true);
+ $info['fileformat'] = $info['audio']['dataformat'];
+
+ return true;
+ }
+
+
+ public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) {
+ // looks for synch, decodes MPEG audio header
+
+ $info = &$this->getid3->info;
+
+ static $MPEGaudioVersionLookup;
+ static $MPEGaudioLayerLookup;
+ static $MPEGaudioBitrateLookup;
+ if (empty($MPEGaudioVersionLookup)) {
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+
+ }
+
+ fseek($this->getid3->fp, $avdataoffset, SEEK_SET);
+ $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
+ if ($sync_seek_buffer_size <= 0) {
+ $info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
+ return false;
+ }
+ $header = fread($this->getid3->fp, $sync_seek_buffer_size);
+ $sync_seek_buffer_size = strlen($header);
+ $SynchSeekOffset = 0;
+ while ($SynchSeekOffset < $sync_seek_buffer_size) {
+ if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) {
+
+ if ($SynchSeekOffset > $sync_seek_buffer_size) {
+ // if a synch's not found within the first 128k bytes, then give up
+ $info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB';
+ if (isset($info['audio']['bitrate'])) {
+ unset($info['audio']['bitrate']);
+ }
+ if (isset($info['mpeg']['audio'])) {
+ unset($info['mpeg']['audio']);
+ }
+ if (empty($info['mpeg'])) {
+ unset($info['mpeg']);
+ }
+ return false;
+
+ } elseif (feof($this->getid3->fp)) {
+
+ $info['error'][] = 'Could not find valid MPEG audio synch before end of file';
+ if (isset($info['audio']['bitrate'])) {
+ unset($info['audio']['bitrate']);
+ }
+ if (isset($info['mpeg']['audio'])) {
+ unset($info['mpeg']['audio']);
+ }
+ if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) {
+ unset($info['mpeg']);
+ }
+ return false;
+ }
+ }
+
+ if (($SynchSeekOffset + 1) >= strlen($header)) {
+ $info['error'][] = 'Could not find valid MPEG synch before end of file';
+ return false;
+ }
+
+ if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
+ if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
+ $FirstFrameThisfileInfo = $info;
+ $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
+ if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) {
+ // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
+ // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
+ unset($FirstFrameThisfileInfo);
+ }
+ }
+
+ $dummy = $info; // only overwrite real data if valid header found
+ if ($this->decodeMPEGaudioHeader($avdataoffset + $SynchSeekOffset, $dummy, true)) {
+ $info = $dummy;
+ $info['avdataoffset'] = $avdataoffset + $SynchSeekOffset;
+ switch (isset($info['fileformat']) ? $info['fileformat'] : '') {
+ case '':
+ case 'id3':
+ case 'ape':
+ case 'mp3':
+ $info['fileformat'] = 'mp3';
+ $info['audio']['dataformat'] = 'mp3';
+ break;
+ }
+ if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
+ if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
+ // If there is garbage data between a valid VBR header frame and a sequence
+ // of valid MPEG-audio frames the VBR data is no longer discarded.
+ $info = $FirstFrameThisfileInfo;
+ $info['avdataoffset'] = $FirstFrameAVDataOffset;
+ $info['fileformat'] = 'mp3';
+ $info['audio']['dataformat'] = 'mp3';
+ $dummy = $info;
+ unset($dummy['mpeg']['audio']);
+ $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
+ $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset;
+ if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
+ $info = $dummy;
+ $info['avdataoffset'] = $GarbageOffsetEnd;
+ $info['warning'][] = 'apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd;
+ } else {
+ $info['warning'][] = 'using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')';
+ }
+ }
+ }
+ if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
+ // VBR file with no VBR header
+ $BitrateHistogram = true;
+ }
+
+ if ($BitrateHistogram) {
+
+ $info['mpeg']['audio']['stereo_distribution'] = array('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0);
+ $info['mpeg']['audio']['version_distribution'] = array('1'=>0, '2'=>0, '2.5'=>0);
+
+ if ($info['mpeg']['audio']['version'] == '1') {
+ if ($info['mpeg']['audio']['layer'] == 3) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0);
+ } elseif ($info['mpeg']['audio']['layer'] == 2) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0);
+ } elseif ($info['mpeg']['audio']['layer'] == 1) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0);
+ }
+ } elseif ($info['mpeg']['audio']['layer'] == 1) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0);
+ } else {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0);
+ }
+
+ $dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
+ $synchstartoffset = $info['avdataoffset'];
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ // you can play with these numbers:
+ $max_frames_scan = 50000;
+ $max_scan_segments = 10;
+
+ // don't play with these numbers:
+ $FastMode = false;
+ $SynchErrorsFound = 0;
+ $frames_scanned = 0;
+ $this_scan_segment = 0;
+ $frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
+ $pct_data_scanned = 0;
+ for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
+ $frames_scanned_this_segment = 0;
+ if (ftell($this->getid3->fp) >= $info['avdataend']) {
+ break;
+ }
+ $scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
+ if ($current_segment > 0) {
+ fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET);
+ $buffer_4k = fread($this->getid3->fp, 4096);
+ for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
+ if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
+ if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
+ $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
+ if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
+ $scan_start_offset[$current_segment] += $j;
+ break;
+ }
+ }
+ }
+ }
+ }
+ $synchstartoffset = $scan_start_offset[$current_segment];
+ while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
+ $FastMode = true;
+ $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
+
+ if (empty($dummy['mpeg']['audio']['framelength'])) {
+ $SynchErrorsFound++;
+ $synchstartoffset++;
+ } else {
+ getid3_lib::safe_inc($info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]);
+ getid3_lib::safe_inc($info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]);
+ getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]);
+ $synchstartoffset += $dummy['mpeg']['audio']['framelength'];
+ }
+ $frames_scanned++;
+ if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
+ $this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
+ if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
+ // file likely contains < $max_frames_scan, just scan as one segment
+ $max_scan_segments = 1;
+ $frames_scan_per_segment = $max_frames_scan;
+ } else {
+ $pct_data_scanned += $this_pct_scanned;
+ break;
+ }
+ }
+ }
+ }
+ if ($pct_data_scanned > 0) {
+ $info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
+ foreach ($info['mpeg']['audio'] as $key1 => $value1) {
+ if (!preg_match('#_distribution$#i', $key1)) {
+ continue;
+ }
+ foreach ($value1 as $key2 => $value2) {
+ $info['mpeg']['audio'][$key1][$key2] = round($value2 / $pct_data_scanned);
+ }
+ }
+ }
+
+ if ($SynchErrorsFound > 0) {
+ $info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis';
+ //return false;
+ }
+
+ $bittotal = 0;
+ $framecounter = 0;
+ foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) {
+ $framecounter += $bitratecount;
+ if ($bitratevalue != 'free') {
+ $bittotal += ($bitratevalue * $bitratecount);
+ }
+ }
+ if ($framecounter == 0) {
+ $info['error'][] = 'Corrupt MP3 file: framecounter == zero';
+ return false;
+ }
+ $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter);
+ $info['mpeg']['audio']['bitrate'] = ($bittotal / $framecounter);
+
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+
+
+ // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
+ $distinct_bitrates = 0;
+ foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) {
+ if ($bitrate_count > 0) {
+ $distinct_bitrates++;
+ }
+ }
+ if ($distinct_bitrates > 1) {
+ $info['mpeg']['audio']['bitrate_mode'] = 'vbr';
+ } else {
+ $info['mpeg']['audio']['bitrate_mode'] = 'cbr';
+ }
+ $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
+
+ }
+
+ break; // exit while()
+ }
+ }
+
+ $SynchSeekOffset++;
+ if (($avdataoffset + $SynchSeekOffset) >= $info['avdataend']) {
+ // end of file/data
+
+ if (empty($info['mpeg']['audio'])) {
+
+ $info['error'][] = 'could not find valid MPEG synch before end of file';
+ if (isset($info['audio']['bitrate'])) {
+ unset($info['audio']['bitrate']);
+ }
+ if (isset($info['mpeg']['audio'])) {
+ unset($info['mpeg']['audio']);
+ }
+ if (isset($info['mpeg']) && (!is_array($info['mpeg']) || empty($info['mpeg']))) {
+ unset($info['mpeg']);
+ }
+ return false;
+
+ }
+ break;
+ }
+
+ }
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
+ $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode'];
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ return true;
+ }
+
+
+ public static function MPEGaudioVersionArray() {
+ static $MPEGaudioVersion = array('2.5', false, '2', '1');
+ return $MPEGaudioVersion;
+ }
+
+ public static function MPEGaudioLayerArray() {
+ static $MPEGaudioLayer = array(false, 3, 2, 1);
+ return $MPEGaudioLayer;
+ }
+
+ public static function MPEGaudioBitrateArray() {
+ static $MPEGaudioBitrate;
+ if (empty($MPEGaudioBitrate)) {
+ $MPEGaudioBitrate = array (
+ '1' => array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000),
+ 2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000),
+ 3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)
+ ),
+
+ '2' => array (1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000),
+ 2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000),
+ )
+ );
+ $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2];
+ $MPEGaudioBitrate['2.5'] = $MPEGaudioBitrate['2'];
+ }
+ return $MPEGaudioBitrate;
+ }
+
+ public static function MPEGaudioFrequencyArray() {
+ static $MPEGaudioFrequency;
+ if (empty($MPEGaudioFrequency)) {
+ $MPEGaudioFrequency = array (
+ '1' => array(44100, 48000, 32000),
+ '2' => array(22050, 24000, 16000),
+ '2.5' => array(11025, 12000, 8000)
+ );
+ }
+ return $MPEGaudioFrequency;
+ }
+
+ public static function MPEGaudioChannelModeArray() {
+ static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
+ return $MPEGaudioChannelMode;
+ }
+
+ public static function MPEGaudioModeExtensionArray() {
+ static $MPEGaudioModeExtension;
+ if (empty($MPEGaudioModeExtension)) {
+ $MPEGaudioModeExtension = array (
+ 1 => array('4-31', '8-31', '12-31', '16-31'),
+ 2 => array('4-31', '8-31', '12-31', '16-31'),
+ 3 => array('', 'IS', 'MS', 'IS+MS')
+ );
+ }
+ return $MPEGaudioModeExtension;
+ }
+
+ public static function MPEGaudioEmphasisArray() {
+ static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
+ return $MPEGaudioEmphasis;
+ }
+
+ public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) {
+ return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
+ }
+
+ public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
+ if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
+ return false;
+ }
+
+ static $MPEGaudioVersionLookup;
+ static $MPEGaudioLayerLookup;
+ static $MPEGaudioBitrateLookup;
+ static $MPEGaudioFrequencyLookup;
+ static $MPEGaudioChannelModeLookup;
+ static $MPEGaudioModeExtensionLookup;
+ static $MPEGaudioEmphasisLookup;
+ if (empty($MPEGaudioVersionLookup)) {
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+ $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
+ $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
+ $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
+ $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
+ }
+
+ if (isset($MPEGaudioVersionLookup[$rawarray['version']])) {
+ $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
+ } else {
+ echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : '');
+ return false;
+ }
+ if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) {
+ $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
+ } else {
+ echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) {
+ echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : '');
+ if ($rawarray['bitrate'] == 15) {
+ // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
+ // let it go through here otherwise file will not be identified
+ if (!$allowBitrate15) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) {
+ echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) {
+ echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) {
+ echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) {
+ echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : '');
+ return false;
+ }
+ // These are just either set or not set, you can't mess that up :)
+ // $rawarray['protection'];
+ // $rawarray['padding'];
+ // $rawarray['private'];
+ // $rawarray['copyright'];
+ // $rawarray['original'];
+
+ return true;
+ }
+
+ public static function MPEGaudioHeaderDecode($Header4Bytes) {
+ // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
+ // A - Frame sync (all bits set)
+ // B - MPEG Audio version ID
+ // C - Layer description
+ // D - Protection bit
+ // E - Bitrate index
+ // F - Sampling rate frequency index
+ // G - Padding bit
+ // H - Private bit
+ // I - Channel Mode
+ // J - Mode extension (Only if Joint stereo)
+ // K - Copyright
+ // L - Original
+ // M - Emphasis
+
+ if (strlen($Header4Bytes) != 4) {
+ return false;
+ }
+
+ $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
+ $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB
+ $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC
+ $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D
+ $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
+ $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF
+ $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G
+ $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H
+ $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
+ $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ
+ $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K
+ $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L
+ $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM
+
+ return $MPEGrawHeader;
+ }
+
+ public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) {
+ static $AudioFrameLengthCache = array();
+
+ if (!isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate])) {
+ $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false;
+ if ($bitrate != 'free') {
+
+ if ($version == '1') {
+
+ if ($layer == '1') {
+
+ // For Layer I slot is 32 bits long
+ $FrameLengthCoefficient = 48;
+ $SlotLength = 4;
+
+ } else { // Layer 2 / 3
+
+ // for Layer 2 and Layer 3 slot is 8 bits long.
+ $FrameLengthCoefficient = 144;
+ $SlotLength = 1;
+
+ }
+
+ } else { // MPEG-2 / MPEG-2.5
+
+ if ($layer == '1') {
+
+ // For Layer I slot is 32 bits long
+ $FrameLengthCoefficient = 24;
+ $SlotLength = 4;
+
+ } elseif ($layer == '2') {
+
+ // for Layer 2 and Layer 3 slot is 8 bits long.
+ $FrameLengthCoefficient = 144;
+ $SlotLength = 1;
+
+ } else { // layer 3
+
+ // for Layer 2 and Layer 3 slot is 8 bits long.
+ $FrameLengthCoefficient = 72;
+ $SlotLength = 1;
+
+ }
+
+ }
+
+ // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
+ if ($samplerate > 0) {
+ $NewFramelength = ($FrameLengthCoefficient * $bitrate) / $samplerate;
+ $NewFramelength = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I)
+ if ($padding) {
+ $NewFramelength += $SlotLength;
+ }
+ $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength;
+ }
+ }
+ }
+ return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
+ }
+
+ public static function ClosestStandardMP3Bitrate($bit_rate) {
+ static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
+ static $bit_rate_table = array (0=>'-');
+ $round_bit_rate = intval(round($bit_rate, -3));
+ if (!isset($bit_rate_table[$round_bit_rate])) {
+ if ($round_bit_rate > max($standard_bit_rates)) {
+ $bit_rate_table[$round_bit_rate] = round($bit_rate, 2 - strlen($bit_rate));
+ } else {
+ $bit_rate_table[$round_bit_rate] = max($standard_bit_rates);
+ foreach ($standard_bit_rates as $standard_bit_rate) {
+ if ($round_bit_rate >= $standard_bit_rate + (($bit_rate_table[$round_bit_rate] - $standard_bit_rate) / 2)) {
+ break;
+ }
+ $bit_rate_table[$round_bit_rate] = $standard_bit_rate;
+ }
+ }
+ }
+ return $bit_rate_table[$round_bit_rate];
+ }
+
+ public static function XingVBRidOffset($version, $channelmode) {
+ static $XingVBRidOffsetCache = array();
+ if (empty($XingVBRidOffset)) {
+ $XingVBRidOffset = array (
+ '1' => array ('mono' => 0x15, // 4 + 17 = 21
+ 'stereo' => 0x24, // 4 + 32 = 36
+ 'joint stereo' => 0x24,
+ 'dual channel' => 0x24
+ ),
+
+ '2' => array ('mono' => 0x0D, // 4 + 9 = 13
+ 'stereo' => 0x15, // 4 + 17 = 21
+ 'joint stereo' => 0x15,
+ 'dual channel' => 0x15
+ ),
+
+ '2.5' => array ('mono' => 0x15,
+ 'stereo' => 0x15,
+ 'joint stereo' => 0x15,
+ 'dual channel' => 0x15
+ )
+ );
+ }
+ return $XingVBRidOffset[$version][$channelmode];
+ }
+
+ public static function LAMEvbrMethodLookup($VBRmethodID) {
+ static $LAMEvbrMethodLookup = array(
+ 0x00 => 'unknown',
+ 0x01 => 'cbr',
+ 0x02 => 'abr',
+ 0x03 => 'vbr-old / vbr-rh',
+ 0x04 => 'vbr-new / vbr-mtrh',
+ 0x05 => 'vbr-mt',
+ 0x06 => 'vbr (full vbr method 4)',
+ 0x08 => 'cbr (constant bitrate 2 pass)',
+ 0x09 => 'abr (2 pass)',
+ 0x0F => 'reserved'
+ );
+ return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
+ }
+
+ public static function LAMEmiscStereoModeLookup($StereoModeID) {
+ static $LAMEmiscStereoModeLookup = array(
+ 0 => 'mono',
+ 1 => 'stereo',
+ 2 => 'dual mono',
+ 3 => 'joint stereo',
+ 4 => 'forced stereo',
+ 5 => 'auto',
+ 6 => 'intensity stereo',
+ 7 => 'other'
+ );
+ return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
+ }
+
+ public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) {
+ static $LAMEmiscSourceSampleFrequencyLookup = array(
+ 0 => '<= 32 kHz',
+ 1 => '44.1 kHz',
+ 2 => '48 kHz',
+ 3 => '> 48kHz'
+ );
+ return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
+ }
+
+ public static function LAMEsurroundInfoLookup($SurroundInfoID) {
+ static $LAMEsurroundInfoLookup = array(
+ 0 => 'no surround info',
+ 1 => 'DPL encoding',
+ 2 => 'DPL2 encoding',
+ 3 => 'Ambisonic encoding'
+ );
+ return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
+ }
+
+ public static function LAMEpresetUsedLookup($LAMEtag) {
+
+ if ($LAMEtag['preset_used_id'] == 0) {
+ // no preset used (LAME >=3.93)
+ // no preset recorded (LAME <3.93)
+ return '';
+ }
+ $LAMEpresetUsedLookup = array();
+
+ ///// THIS PART CANNOT BE STATIC .
+ for ($i = 8; $i <= 320; $i++) {
+ switch ($LAMEtag['vbr_method']) {
+ case 'cbr':
+ $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i;
+ break;
+ case 'abr':
+ default: // other VBR modes shouldn't be here(?)
+ $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i;
+ break;
+ }
+ }
+
+ // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
+
+ // named alt-presets
+ $LAMEpresetUsedLookup[1000] = '--r3mix';
+ $LAMEpresetUsedLookup[1001] = '--alt-preset standard';
+ $LAMEpresetUsedLookup[1002] = '--alt-preset extreme';
+ $LAMEpresetUsedLookup[1003] = '--alt-preset insane';
+ $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard';
+ $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme';
+ $LAMEpresetUsedLookup[1006] = '--alt-preset medium';
+ $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium';
+
+ // LAME 3.94 additions/changes
+ $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003
+ $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003
+
+ $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[410] = '-V9';
+ $LAMEpresetUsedLookup[420] = '-V8';
+ $LAMEpresetUsedLookup[440] = '-V6';
+ $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003
+ $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[490] = '-V1';
+ $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003
+
+ return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org');
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.audio.ogg.php b/src/wp-includes/ID3/module.audio.ogg.php
new file mode 100644
index 0000000000..a2a35aadf7
--- /dev/null
+++ b/src/wp-includes/ID3/module.audio.ogg.php
@@ -0,0 +1,671 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.ogg.php //
+// module for analyzing Ogg Vorbis, OggFLAC and Speex files //
+// dependencies: module.audio.flac.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
+
+class getid3_ogg extends getid3_handler
+{
+ // http://xiph.org/vorbis/doc/Vorbis_I_spec.html
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'ogg';
+
+ // Warn about illegal tags - only vorbiscomments are allowed
+ if (isset($info['id3v2'])) {
+ $info['warning'][] = 'Illegal ID3v2 tag present.';
+ }
+ if (isset($info['id3v1'])) {
+ $info['warning'][] = 'Illegal ID3v1 tag present.';
+ }
+ if (isset($info['ape'])) {
+ $info['warning'][] = 'Illegal APE tag present.';
+ }
+
+
+ // Page 1 - Stream Header
+
+ $this->fseek($info['avdataoffset']);
+
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
+ $info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';
+ unset($info['fileformat']);
+ unset($info['ogg']);
+ return false;
+ }
+
+ $filedata = $this->fread($oggpageinfo['page_length']);
+ $filedataoffset = 0;
+
+ if (substr($filedata, 0, 4) == 'fLaC') {
+
+ $info['audio']['dataformat'] = 'flac';
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['lossless'] = true;
+
+ } elseif (substr($filedata, 1, 6) == 'vorbis') {
+
+ $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
+
+ } elseif (substr($filedata, 0, 8) == 'Speex ') {
+
+ // http://www.speex.org/manual/node10.html
+
+ $info['audio']['dataformat'] = 'speex';
+ $info['mime_type'] = 'audio/speex';
+ $info['audio']['bitrate_mode'] = 'abr';
+ $info['audio']['lossless'] = false;
+
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex '
+ $filedataoffset += 8;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20);
+ $filedataoffset += 20;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+
+ $info['speex']['speex_version'] = trim($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
+ $info['speex']['sample_rate'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
+ $info['speex']['channels'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
+ $info['speex']['vbr'] = (bool) $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
+ $info['speex']['band_type'] = $this->SpeexBandModeLookup($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
+
+ $info['audio']['sample_rate'] = $info['speex']['sample_rate'];
+ $info['audio']['channels'] = $info['speex']['channels'];
+ if ($info['speex']['vbr']) {
+ $info['audio']['bitrate_mode'] = 'vbr';
+ }
+
+
+ } elseif (substr($filedata, 0, 8) == "fishead\x00") {
+
+ // Ogg Skeleton version 3.0 Format Specification
+ // http://xiph.org/ogg/doc/skeleton.html
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['version_major'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
+ $filedataoffset += 2;
+ $info['ogg']['skeleton']['fishead']['raw']['version_minor'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
+ $filedataoffset += 2;
+ $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['utc'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 20));
+ $filedataoffset += 20;
+
+ $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor'];
+ $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'];
+ $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'];
+ $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc'];
+
+
+ $counter = 0;
+ do {
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno'].'.'.$counter++] = $oggpageinfo;
+ $filedata = $this->fread($oggpageinfo['page_length']);
+ $this->fseek($oggpageinfo['page_end_offset']);
+
+ if (substr($filedata, 0, 8) == "fisbone\x00") {
+
+ $filedataoffset = 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['message_header_offset'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['serial_number'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['number_header_packets'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['granulerate_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['granulerate_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['basegranule'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['preroll'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['granuleshift'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3);
+ $filedataoffset += 3;
+
+ } elseif (substr($filedata, 1, 6) == 'theora') {
+
+ $info['video']['dataformat'] = 'theora';
+ $info['error'][] = 'Ogg Theora not correctly handled in this version of getID3 ['.$this->getid3->version().']';
+ //break;
+
+ } elseif (substr($filedata, 1, 6) == 'vorbis') {
+
+ $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
+
+ } else {
+ $info['error'][] = 'unexpected';
+ //break;
+ }
+ //} while ($oggpageinfo['page_seqno'] == 0);
+ } while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
+
+ $this->fseek($oggpageinfo['page_start_offset']);
+
+ $info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
+ //return false;
+
+ } else {
+
+ $info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
+ unset($info['ogg']);
+ unset($info['mime_type']);
+ return false;
+
+ }
+
+ // Page 2 - Comment Header
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ switch ($info['audio']['dataformat']) {
+ case 'vorbis':
+ $filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis'
+
+ $this->ParseVorbisComments();
+ break;
+
+ case 'flac':
+ $flac = new getid3_flac($this->getid3);
+ if (!$flac->parseMETAdata()) {
+ $info['error'][] = 'Failed to parse FLAC headers';
+ return false;
+ }
+ unset($flac);
+ break;
+
+ case 'speex':
+ $this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
+ $this->ParseVorbisComments();
+ break;
+ }
+
+
+ // Last Page - Number of Samples
+ if (!getid3_lib::intValueSupported($info['avdataend'])) {
+
+ $info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
+
+ } else {
+
+ $this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0));
+ $LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size()));
+ if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
+ $this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO')));
+ $info['avdataend'] = $this->ftell();
+ $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
+ $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
+ if ($info['ogg']['samples'] == 0) {
+ $info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
+ return false;
+ }
+ if (!empty($info['audio']['sample_rate'])) {
+ $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']);
+ }
+ }
+
+ }
+
+ if (!empty($info['ogg']['bitrate_average'])) {
+ $info['audio']['bitrate'] = $info['ogg']['bitrate_average'];
+ } elseif (!empty($info['ogg']['bitrate_nominal'])) {
+ $info['audio']['bitrate'] = $info['ogg']['bitrate_nominal'];
+ } elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) {
+ $info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2;
+ }
+ if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
+ if ($info['audio']['bitrate'] == 0) {
+ $info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
+ return false;
+ }
+ $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
+ }
+
+ if (isset($info['ogg']['vendor'])) {
+ $info['audio']['encoder'] = preg_replace('/^Encoded with /', '', $info['ogg']['vendor']);
+
+ // Vorbis only
+ if ($info['audio']['dataformat'] == 'vorbis') {
+
+ // Vorbis 1.0 starts with Xiph.Org
+ if (preg_match('/^Xiph.Org/', $info['audio']['encoder'])) {
+
+ if ($info['audio']['bitrate_mode'] == 'abr') {
+
+ // Set -b 128 on abr files
+ $info['audio']['encoder_options'] = '-b '.round($info['ogg']['bitrate_nominal'] / 1000);
+
+ } elseif (($info['audio']['bitrate_mode'] == 'vbr') && ($info['audio']['channels'] == 2) && ($info['audio']['sample_rate'] >= 44100) && ($info['audio']['sample_rate'] <= 48000)) {
+ // Set -q N on vbr files
+ $info['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($info['ogg']['bitrate_nominal']);
+
+ }
+ }
+
+ if (empty($info['audio']['encoder_options']) && !empty($info['ogg']['bitrate_nominal'])) {
+ $info['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($info['ogg']['bitrate_nominal'] / 1000)).'kbps';
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
+ $info = &$this->getid3->info;
+ $info['audio']['dataformat'] = 'vorbis';
+ $info['audio']['lossless'] = false;
+
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
+ $filedataoffset += 6;
+ $info['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $info['audio']['channels'] = $info['ogg']['numberofchannels'];
+ $info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ if ($info['ogg']['samplerate'] == 0) {
+ $info['error'][] = 'Corrupt Ogg file: sample rate == zero';
+ return false;
+ }
+ $info['audio']['sample_rate'] = $info['ogg']['samplerate'];
+ $info['ogg']['samples'] = 0; // filled in later
+ $info['ogg']['bitrate_average'] = 0; // filled in later
+ $info['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
+ $info['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
+ $info['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
+
+ $info['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
+ if ($info['ogg']['bitrate_max'] == 0xFFFFFFFF) {
+ unset($info['ogg']['bitrate_max']);
+ $info['audio']['bitrate_mode'] = 'abr';
+ }
+ if ($info['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
+ unset($info['ogg']['bitrate_nominal']);
+ }
+ if ($info['ogg']['bitrate_min'] == 0xFFFFFFFF) {
+ unset($info['ogg']['bitrate_min']);
+ $info['audio']['bitrate_mode'] = 'abr';
+ }
+ return true;
+ }
+
+ public function ParseOggPageHeader() {
+ // http://xiph.org/ogg/vorbis/doc/framing.html
+ $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
+
+ $filedata = $this->fread($this->getid3->fread_buffer_size());
+ $filedataoffset = 0;
+ while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
+ if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) {
+ // should be found before here
+ return false;
+ }
+ if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
+ if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) {
+ // get some more data, unless eof, in which case fail
+ return false;
+ }
+ }
+ }
+ $filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS'
+
+ $oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet
+ $oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos)
+ $oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos)
+
+ $oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['page_length'] = 0;
+ for ($i = 0; $i < $oggheader['page_segments']; $i++) {
+ $oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['page_length'] += $oggheader['segment_table'][$i];
+ }
+ $oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset;
+ $oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length'];
+ $this->fseek($oggheader['header_end_offset']);
+
+ return $oggheader;
+ }
+
+ // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
+ public function ParseVorbisComments() {
+ $info = &$this->getid3->info;
+
+ $OriginalOffset = $this->ftell();
+ $commentdataoffset = 0;
+ $VorbisCommentPage = 1;
+
+ switch ($info['audio']['dataformat']) {
+ case 'vorbis':
+ case 'speex':
+ $CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
+ $this->fseek($CommentStartOffset);
+ $commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
+ $commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
+
+ if ($info['audio']['dataformat'] == 'vorbis') {
+ $commentdataoffset += (strlen('vorbis') + 1);
+ }
+ break;
+
+ case 'flac':
+ $CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
+ $this->fseek($CommentStartOffset);
+ $commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']);
+ break;
+
+ default:
+ return false;
+ }
+
+ $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
+ $commentdataoffset += 4;
+
+ $info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
+ $commentdataoffset += $VendorSize;
+
+ $CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
+ $commentdataoffset += 4;
+ $info['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
+
+ $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
+ $ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
+ for ($i = 0; $i < $CommentsCount; $i++) {
+
+ $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
+
+ if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
+ if ($oggpageinfo = $this->ParseOggPageHeader()) {
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ $VorbisCommentPage++;
+
+ // First, save what we haven't read yet
+ $AsYetUnusedData = substr($commentdata, $commentdataoffset);
+
+ // Then take that data off the end
+ $commentdata = substr($commentdata, 0, $commentdataoffset);
+
+ // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
+ $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+ $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+
+ // Finally, stick the unused data back on the end
+ $commentdata .= $AsYetUnusedData;
+
+ //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
+ $commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1));
+ }
+
+ }
+ $ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
+
+ // replace avdataoffset with position just after the last vorbiscomment
+ $info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
+
+ $commentdataoffset += 4;
+ while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
+ if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
+ $info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';
+ break 2;
+ }
+
+ $VorbisCommentPage++;
+
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ // First, save what we haven't read yet
+ $AsYetUnusedData = substr($commentdata, $commentdataoffset);
+
+ // Then take that data off the end
+ $commentdata = substr($commentdata, 0, $commentdataoffset);
+
+ // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
+ $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+ $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+
+ // Finally, stick the unused data back on the end
+ $commentdata .= $AsYetUnusedData;
+
+ //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
+ if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
+ $info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
+ break;
+ }
+ $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
+ if ($readlength <= 0) {
+ $info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
+ break;
+ }
+ $commentdata .= $this->fread($readlength);
+
+ //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
+ }
+ $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
+ $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
+ $commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
+
+ if (!$commentstring) {
+
+ // no comment?
+ $info['warning'][] = 'Blank Ogg comment ['.$i.']';
+
+ } elseif (strstr($commentstring, '=')) {
+
+ $commentexploded = explode('=', $commentstring, 2);
+ $ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]);
+ $ThisFileInfo_ogg_comments_raw[$i]['value'] = (isset($commentexploded[1]) ? $commentexploded[1] : '');
+
+ if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') {
+
+ // http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
+ // The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard.
+ // http://flac.sourceforge.net/format.html#metadata_block_picture
+ $flac = new getid3_flac($this->getid3);
+ $flac->setStringMode(base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']));
+ $flac->parsePICTURE();
+ $info['ogg']['comments']['picture'][] = $flac->getid3->info['flac']['PICTURE'][0];
+ unset($flac);
+
+ } elseif ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'COVERART') {
+
+ $data = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']);
+ $this->notice('Found deprecated COVERART tag, it should be replaced in honor of METADATA_BLOCK_PICTURE structure');
+ /** @todo use 'coverartmime' where available */
+ $imageinfo = getid3_lib::GetDataImageSize($data);
+ if ($imageinfo === false || !isset($imageinfo['mime'])) {
+ $this->warning('COVERART vorbiscomment tag contains invalid image');
+ continue;
+ }
+
+ $ogg = new self($this->getid3);
+ $ogg->setStringMode($data);
+ $info['ogg']['comments']['picture'][] = array(
+ 'image_mime' => $imageinfo['mime'],
+ 'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
+ );
+ unset($ogg);
+
+ } else {
+
+ $info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
+
+ }
+
+ } else {
+
+ $info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
+
+ }
+ unset($ThisFileInfo_ogg_comments_raw[$i]);
+ }
+ unset($ThisFileInfo_ogg_comments_raw);
+
+
+ // Replay Gain Adjustment
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/
+ if (isset($info['ogg']['comments']) && is_array($info['ogg']['comments'])) {
+ foreach ($info['ogg']['comments'] as $index => $commentvalue) {
+ switch ($index) {
+ case 'rg_audiophile':
+ case 'replaygain_album_gain':
+ $info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'rg_radio':
+ case 'replaygain_track_gain':
+ $info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'replaygain_album_peak':
+ $info['replay_gain']['album']['peak'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'rg_peak':
+ case 'replaygain_track_peak':
+ $info['replay_gain']['track']['peak'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'replaygain_reference_loudness':
+ $info['replay_gain']['reference_volume'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ $this->fseek($OriginalOffset);
+
+ return true;
+ }
+
+ public static function SpeexBandModeLookup($mode) {
+ static $SpeexBandModeLookup = array();
+ if (empty($SpeexBandModeLookup)) {
+ $SpeexBandModeLookup[0] = 'narrow';
+ $SpeexBandModeLookup[1] = 'wide';
+ $SpeexBandModeLookup[2] = 'ultra-wide';
+ }
+ return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
+ }
+
+
+ public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
+ for ($i = 0; $i < $SegmentNumber; $i++) {
+ $segmentlength = 0;
+ foreach ($OggInfoArray['segment_table'] as $key => $value) {
+ $segmentlength += $value;
+ if ($value < 255) {
+ break;
+ }
+ }
+ }
+ return $segmentlength;
+ }
+
+
+ public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
+
+ // decrease precision
+ $nominal_bitrate = $nominal_bitrate / 1000;
+
+ if ($nominal_bitrate < 128) {
+ // q-1 to q4
+ $qval = ($nominal_bitrate - 64) / 16;
+ } elseif ($nominal_bitrate < 256) {
+ // q4 to q8
+ $qval = $nominal_bitrate / 32;
+ } elseif ($nominal_bitrate < 320) {
+ // q8 to q9
+ $qval = ($nominal_bitrate + 256) / 64;
+ } else {
+ // q9 to q10
+ $qval = ($nominal_bitrate + 1300) / 180;
+ }
+ //return $qval; // 5.031324
+ //return intval($qval); // 5
+ return round($qval, 1); // 5 or 4.9
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.tag.apetag.php b/src/wp-includes/ID3/module.tag.apetag.php
new file mode 100644
index 0000000000..afeede769c
--- /dev/null
+++ b/src/wp-includes/ID3/module.tag.apetag.php
@@ -0,0 +1,370 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.tag.apetag.php //
+// module for analyzing APE tags //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+class getid3_apetag extends getid3_handler
+{
+ public $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory
+ public $overrideendoffset = 0;
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ if (!getid3_lib::intValueSupported($info['filesize'])) {
+ $info['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
+ return false;
+ }
+
+ $id3v1tagsize = 128;
+ $apetagheadersize = 32;
+ $lyrics3tagsize = 10;
+
+ if ($this->overrideendoffset == 0) {
+
+ fseek($this->getid3->fp, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END);
+ $APEfooterID3v1 = fread($this->getid3->fp, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize);
+
+ //if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) {
+ if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') {
+
+ // APE tag found before ID3v1
+ $info['ape']['tag_offset_end'] = $info['filesize'] - $id3v1tagsize;
+
+ //} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) {
+ } elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') {
+
+ // APE tag found, no ID3v1
+ $info['ape']['tag_offset_end'] = $info['filesize'];
+
+ }
+
+ } else {
+
+ fseek($this->getid3->fp, $this->overrideendoffset - $apetagheadersize, SEEK_SET);
+ if (fread($this->getid3->fp, 8) == 'APETAGEX') {
+ $info['ape']['tag_offset_end'] = $this->overrideendoffset;
+ }
+
+ }
+ if (!isset($info['ape']['tag_offset_end'])) {
+
+ // APE tag not found
+ unset($info['ape']);
+ return false;
+
+ }
+
+ // shortcut
+ $thisfile_ape = &$info['ape'];
+
+ fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET);
+ $APEfooterData = fread($this->getid3->fp, 32);
+ if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) {
+ $info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end'];
+ return false;
+ }
+
+ if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
+ fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET);
+ $thisfile_ape['tag_offset_start'] = ftell($this->getid3->fp);
+ $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize);
+ } else {
+ $thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'];
+ fseek($this->getid3->fp, $thisfile_ape['tag_offset_start'], SEEK_SET);
+ $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize']);
+ }
+ $info['avdataend'] = $thisfile_ape['tag_offset_start'];
+
+ if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) {
+ $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data';
+ unset($info['id3v1']);
+ foreach ($info['warning'] as $key => $value) {
+ if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
+ unset($info['warning'][$key]);
+ sort($info['warning']);
+ break;
+ }
+ }
+ }
+
+ $offset = 0;
+ if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) {
+ if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) {
+ $offset += $apetagheadersize;
+ } else {
+ $info['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start'];
+ return false;
+ }
+ }
+
+ // shortcut
+ $info['replay_gain'] = array();
+ $thisfile_replaygain = &$info['replay_gain'];
+
+ for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) {
+ $value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
+ $offset += 4;
+ $item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4));
+ $offset += 4;
+ if (strstr(substr($APEtagData, $offset), "\x00") === false) {
+ $info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset);
+ return false;
+ }
+ $ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset;
+ $item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength));
+
+ // shortcut
+ $thisfile_ape['items'][$item_key] = array();
+ $thisfile_ape_items_current = &$thisfile_ape['items'][$item_key];
+
+ $thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset;
+
+ $offset += ($ItemKeyLength + 1); // skip 0x00 terminator
+ $thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size);
+ $offset += $value_size;
+
+ $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags);
+ switch ($thisfile_ape_items_current['flags']['item_contents_raw']) {
+ case 0: // UTF-8
+ case 3: // Locator (URL, filename, etc), UTF-8 encoded
+ $thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data']));
+ break;
+
+ default: // binary data
+ break;
+ }
+
+ switch (strtolower($item_key)) {
+ case 'replaygain_track_gain':
+ $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ $thisfile_replaygain['track']['originator'] = 'unspecified';
+ break;
+
+ case 'replaygain_track_peak':
+ $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ $thisfile_replaygain['track']['originator'] = 'unspecified';
+ if ($thisfile_replaygain['track']['peak'] <= 0) {
+ $info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
+ }
+ break;
+
+ case 'replaygain_album_gain':
+ $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ $thisfile_replaygain['album']['originator'] = 'unspecified';
+ break;
+
+ case 'replaygain_album_peak':
+ $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero!
+ $thisfile_replaygain['album']['originator'] = 'unspecified';
+ if ($thisfile_replaygain['album']['peak'] <= 0) {
+ $info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")';
+ }
+ break;
+
+ case 'mp3gain_undo':
+ list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]);
+ $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left);
+ $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right);
+ $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false);
+ break;
+
+ case 'mp3gain_minmax':
+ list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]);
+ $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min);
+ $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max);
+ break;
+
+ case 'mp3gain_album_minmax':
+ list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]);
+ $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min);
+ $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max);
+ break;
+
+ case 'tracknumber':
+ if (is_array($thisfile_ape_items_current['data'])) {
+ foreach ($thisfile_ape_items_current['data'] as $comment) {
+ $thisfile_ape['comments']['track'][] = $comment;
+ }
+ }
+ break;
+
+ case 'cover art (artist)':
+ case 'cover art (back)':
+ case 'cover art (band logo)':
+ case 'cover art (band)':
+ case 'cover art (colored fish)':
+ case 'cover art (composer)':
+ case 'cover art (conductor)':
+ case 'cover art (front)':
+ case 'cover art (icon)':
+ case 'cover art (illustration)':
+ case 'cover art (lead)':
+ case 'cover art (leaflet)':
+ case 'cover art (lyricist)':
+ case 'cover art (media)':
+ case 'cover art (movie scene)':
+ case 'cover art (other icon)':
+ case 'cover art (other)':
+ case 'cover art (performance)':
+ case 'cover art (publisher logo)':
+ case 'cover art (recording)':
+ case 'cover art (studio)':
+ // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html
+ list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2);
+ $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00");
+ $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']);
+
+ $thisfile_ape_items_current['image_mime'] = '';
+ $imageinfo = array();
+ $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo);
+ $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]);
+
+ do {
+ if ($this->inline_attachments === false) {
+ // skip entirely
+ unset($thisfile_ape_items_current['data']);
+ break;
+ }
+ if ($this->inline_attachments === true) {
+ // great
+ } elseif (is_int($this->inline_attachments)) {
+ if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) {
+ // too big, skip
+ $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)';
+ unset($thisfile_ape_items_current['data']);
+ break;
+ }
+ } elseif (is_string($this->inline_attachments)) {
+ $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR);
+ if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) {
+ // cannot write, skip
+ $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)';
+ unset($thisfile_ape_items_current['data']);
+ break;
+ }
+ }
+ // if we get this far, must be OK
+ if (is_string($this->inline_attachments)) {
+ $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset'];
+ if (!file_exists($destination_filename) || is_writable($destination_filename)) {
+ file_put_contents($destination_filename, $thisfile_ape_items_current['data']);
+ } else {
+ $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)';
+ }
+ $thisfile_ape_items_current['data_filename'] = $destination_filename;
+ unset($thisfile_ape_items_current['data']);
+ } else {
+ if (!isset($info['ape']['comments']['picture'])) {
+ $info['ape']['comments']['picture'] = array();
+ }
+ $info['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']);
+ }
+ } while (false);
+ break;
+
+ default:
+ if (is_array($thisfile_ape_items_current['data'])) {
+ foreach ($thisfile_ape_items_current['data'] as $comment) {
+ $thisfile_ape['comments'][strtolower($item_key)][] = $comment;
+ }
+ }
+ break;
+ }
+
+ }
+ if (empty($thisfile_replaygain)) {
+ unset($info['replay_gain']);
+ }
+ return true;
+ }
+
+ public function parseAPEheaderFooter($APEheaderFooterData) {
+ // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html
+
+ // shortcut
+ $headerfooterinfo['raw'] = array();
+ $headerfooterinfo_raw = &$headerfooterinfo['raw'];
+
+ $headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8);
+ if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') {
+ return false;
+ }
+ $headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4));
+ $headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4));
+ $headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4));
+ $headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4));
+ $headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8);
+
+ $headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000;
+ if ($headerfooterinfo['tag_version'] >= 2) {
+ $headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']);
+ }
+ return $headerfooterinfo;
+ }
+
+ public function parseAPEtagFlags($rawflagint) {
+ // "Note: APE Tags 1.0 do not use any of the APE Tag flags.
+ // All are set to zero on creation and ignored on reading."
+ // http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html
+ $flags['header'] = (bool) ($rawflagint & 0x80000000);
+ $flags['footer'] = (bool) ($rawflagint & 0x40000000);
+ $flags['this_is_header'] = (bool) ($rawflagint & 0x20000000);
+ $flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1;
+ $flags['read_only'] = (bool) ($rawflagint & 0x00000001);
+
+ $flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']);
+
+ return $flags;
+ }
+
+ public function APEcontentTypeFlagLookup($contenttypeid) {
+ static $APEcontentTypeFlagLookup = array(
+ 0 => 'utf-8',
+ 1 => 'binary',
+ 2 => 'external',
+ 3 => 'reserved'
+ );
+ return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid');
+ }
+
+ public function APEtagItemIsUTF8Lookup($itemkey) {
+ static $APEtagItemIsUTF8Lookup = array(
+ 'title',
+ 'subtitle',
+ 'artist',
+ 'album',
+ 'debut album',
+ 'publisher',
+ 'conductor',
+ 'track',
+ 'composer',
+ 'comment',
+ 'copyright',
+ 'publicationright',
+ 'file',
+ 'year',
+ 'record date',
+ 'record location',
+ 'genre',
+ 'media',
+ 'related',
+ 'isrc',
+ 'abstract',
+ 'language',
+ 'bibliography'
+ );
+ return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup);
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.tag.id3v1.php b/src/wp-includes/ID3/module.tag.id3v1.php
new file mode 100644
index 0000000000..fd9069e04a
--- /dev/null
+++ b/src/wp-includes/ID3/module.tag.id3v1.php
@@ -0,0 +1,359 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.tag.id3v1.php //
+// module for analyzing ID3v1 tags //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_id3v1 extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ if (!getid3_lib::intValueSupported($info['filesize'])) {
+ $info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
+ return false;
+ }
+
+ fseek($this->getid3->fp, -256, SEEK_END);
+ $preid3v1 = fread($this->getid3->fp, 128);
+ $id3v1tag = fread($this->getid3->fp, 128);
+
+ if (substr($id3v1tag, 0, 3) == 'TAG') {
+
+ $info['avdataend'] = $info['filesize'] - 128;
+
+ $ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
+ $ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30));
+ $ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30));
+ $ParsedID3v1['year'] = $this->cutfield(substr($id3v1tag, 93, 4));
+ $ParsedID3v1['comment'] = substr($id3v1tag, 97, 30); // can't remove nulls yet, track detection depends on them
+ $ParsedID3v1['genreid'] = ord(substr($id3v1tag, 127, 1));
+
+ // If second-last byte of comment field is null and last byte of comment field is non-null
+ // then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number
+ if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) {
+ $ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1));
+ $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
+ }
+ $ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']);
+
+ $ParsedID3v1['genre'] = $this->LookupGenreName($ParsedID3v1['genreid']);
+ if (!empty($ParsedID3v1['genre'])) {
+ unset($ParsedID3v1['genreid']);
+ }
+ if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) {
+ unset($ParsedID3v1['genre']);
+ }
+
+ foreach ($ParsedID3v1 as $key => $value) {
+ $ParsedID3v1['comments'][$key][0] = $value;
+ }
+
+ // ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces
+ $GoodFormatID3v1tag = $this->GenerateID3v1Tag(
+ $ParsedID3v1['title'],
+ $ParsedID3v1['artist'],
+ $ParsedID3v1['album'],
+ $ParsedID3v1['year'],
+ (isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
+ $ParsedID3v1['comment'],
+ (!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : ''));
+ $ParsedID3v1['padding_valid'] = true;
+ if ($id3v1tag !== $GoodFormatID3v1tag) {
+ $ParsedID3v1['padding_valid'] = false;
+ $info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding';
+ }
+
+ $ParsedID3v1['tag_offset_end'] = $info['filesize'];
+ $ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128;
+
+ $info['id3v1'] = $ParsedID3v1;
+ }
+
+ if (substr($preid3v1, 0, 3) == 'TAG') {
+ // The way iTunes handles tags is, well, brain-damaged.
+ // It completely ignores v1 if ID3v2 is present.
+ // This goes as far as adding a new v1 tag *even if there already is one*
+
+ // A suspected double-ID3v1 tag has been detected, but it could be that
+ // the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag
+ if (substr($preid3v1, 96, 8) == 'APETAGEX') {
+ // an APE tag footer was found before the last ID3v1, assume false "TAG" synch
+ } elseif (substr($preid3v1, 119, 6) == 'LYRICS') {
+ // a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch
+ } else {
+ // APE and Lyrics3 footers not found - assume double ID3v1
+ $info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes';
+ $info['avdataend'] -= 128;
+ }
+ }
+
+ return true;
+ }
+
+ public static function cutfield($str) {
+ return trim(substr($str, 0, strcspn($str, "\x00")));
+ }
+
+ public static function ArrayOfGenres($allowSCMPXextended=false) {
+ static $GenreLookup = array(
+ 0 => 'Blues',
+ 1 => 'Classic Rock',
+ 2 => 'Country',
+ 3 => 'Dance',
+ 4 => 'Disco',
+ 5 => 'Funk',
+ 6 => 'Grunge',
+ 7 => 'Hip-Hop',
+ 8 => 'Jazz',
+ 9 => 'Metal',
+ 10 => 'New Age',
+ 11 => 'Oldies',
+ 12 => 'Other',
+ 13 => 'Pop',
+ 14 => 'R&B',
+ 15 => 'Rap',
+ 16 => 'Reggae',
+ 17 => 'Rock',
+ 18 => 'Techno',
+ 19 => 'Industrial',
+ 20 => 'Alternative',
+ 21 => 'Ska',
+ 22 => 'Death Metal',
+ 23 => 'Pranks',
+ 24 => 'Soundtrack',
+ 25 => 'Euro-Techno',
+ 26 => 'Ambient',
+ 27 => 'Trip-Hop',
+ 28 => 'Vocal',
+ 29 => 'Jazz+Funk',
+ 30 => 'Fusion',
+ 31 => 'Trance',
+ 32 => 'Classical',
+ 33 => 'Instrumental',
+ 34 => 'Acid',
+ 35 => 'House',
+ 36 => 'Game',
+ 37 => 'Sound Clip',
+ 38 => 'Gospel',
+ 39 => 'Noise',
+ 40 => 'Alt. Rock',
+ 41 => 'Bass',
+ 42 => 'Soul',
+ 43 => 'Punk',
+ 44 => 'Space',
+ 45 => 'Meditative',
+ 46 => 'Instrumental Pop',
+ 47 => 'Instrumental Rock',
+ 48 => 'Ethnic',
+ 49 => 'Gothic',
+ 50 => 'Darkwave',
+ 51 => 'Techno-Industrial',
+ 52 => 'Electronic',
+ 53 => 'Pop-Folk',
+ 54 => 'Eurodance',
+ 55 => 'Dream',
+ 56 => 'Southern Rock',
+ 57 => 'Comedy',
+ 58 => 'Cult',
+ 59 => 'Gangsta Rap',
+ 60 => 'Top 40',
+ 61 => 'Christian Rap',
+ 62 => 'Pop/Funk',
+ 63 => 'Jungle',
+ 64 => 'Native American',
+ 65 => 'Cabaret',
+ 66 => 'New Wave',
+ 67 => 'Psychedelic',
+ 68 => 'Rave',
+ 69 => 'Showtunes',
+ 70 => 'Trailer',
+ 71 => 'Lo-Fi',
+ 72 => 'Tribal',
+ 73 => 'Acid Punk',
+ 74 => 'Acid Jazz',
+ 75 => 'Polka',
+ 76 => 'Retro',
+ 77 => 'Musical',
+ 78 => 'Rock & Roll',
+ 79 => 'Hard Rock',
+ 80 => 'Folk',
+ 81 => 'Folk/Rock',
+ 82 => 'National Folk',
+ 83 => 'Swing',
+ 84 => 'Fast-Fusion',
+ 85 => 'Bebob',
+ 86 => 'Latin',
+ 87 => 'Revival',
+ 88 => 'Celtic',
+ 89 => 'Bluegrass',
+ 90 => 'Avantgarde',
+ 91 => 'Gothic Rock',
+ 92 => 'Progressive Rock',
+ 93 => 'Psychedelic Rock',
+ 94 => 'Symphonic Rock',
+ 95 => 'Slow Rock',
+ 96 => 'Big Band',
+ 97 => 'Chorus',
+ 98 => 'Easy Listening',
+ 99 => 'Acoustic',
+ 100 => 'Humour',
+ 101 => 'Speech',
+ 102 => 'Chanson',
+ 103 => 'Opera',
+ 104 => 'Chamber Music',
+ 105 => 'Sonata',
+ 106 => 'Symphony',
+ 107 => 'Booty Bass',
+ 108 => 'Primus',
+ 109 => 'Porn Groove',
+ 110 => 'Satire',
+ 111 => 'Slow Jam',
+ 112 => 'Club',
+ 113 => 'Tango',
+ 114 => 'Samba',
+ 115 => 'Folklore',
+ 116 => 'Ballad',
+ 117 => 'Power Ballad',
+ 118 => 'Rhythmic Soul',
+ 119 => 'Freestyle',
+ 120 => 'Duet',
+ 121 => 'Punk Rock',
+ 122 => 'Drum Solo',
+ 123 => 'A Cappella',
+ 124 => 'Euro-House',
+ 125 => 'Dance Hall',
+ 126 => 'Goa',
+ 127 => 'Drum & Bass',
+ 128 => 'Club-House',
+ 129 => 'Hardcore',
+ 130 => 'Terror',
+ 131 => 'Indie',
+ 132 => 'BritPop',
+ 133 => 'Negerpunk',
+ 134 => 'Polsk Punk',
+ 135 => 'Beat',
+ 136 => 'Christian Gangsta Rap',
+ 137 => 'Heavy Metal',
+ 138 => 'Black Metal',
+ 139 => 'Crossover',
+ 140 => 'Contemporary Christian',
+ 141 => 'Christian Rock',
+ 142 => 'Merengue',
+ 143 => 'Salsa',
+ 144 => 'Thrash Metal',
+ 145 => 'Anime',
+ 146 => 'JPop',
+ 147 => 'Synthpop',
+
+ 255 => 'Unknown',
+
+ 'CR' => 'Cover',
+ 'RX' => 'Remix'
+ );
+
+ static $GenreLookupSCMPX = array();
+ if ($allowSCMPXextended && empty($GenreLookupSCMPX)) {
+ $GenreLookupSCMPX = $GenreLookup;
+ // http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
+ // Extended ID3v1 genres invented by SCMPX
+ // Note that 255 "Japanese Anime" conflicts with standard "Unknown"
+ $GenreLookupSCMPX[240] = 'Sacred';
+ $GenreLookupSCMPX[241] = 'Northern Europe';
+ $GenreLookupSCMPX[242] = 'Irish & Scottish';
+ $GenreLookupSCMPX[243] = 'Scotland';
+ $GenreLookupSCMPX[244] = 'Ethnic Europe';
+ $GenreLookupSCMPX[245] = 'Enka';
+ $GenreLookupSCMPX[246] = 'Children\'s Song';
+ $GenreLookupSCMPX[247] = 'Japanese Sky';
+ $GenreLookupSCMPX[248] = 'Japanese Heavy Rock';
+ $GenreLookupSCMPX[249] = 'Japanese Doom Rock';
+ $GenreLookupSCMPX[250] = 'Japanese J-POP';
+ $GenreLookupSCMPX[251] = 'Japanese Seiyu';
+ $GenreLookupSCMPX[252] = 'Japanese Ambient Techno';
+ $GenreLookupSCMPX[253] = 'Japanese Moemoe';
+ $GenreLookupSCMPX[254] = 'Japanese Tokusatsu';
+ //$GenreLookupSCMPX[255] = 'Japanese Anime';
+ }
+
+ return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup);
+ }
+
+ public static function LookupGenreName($genreid, $allowSCMPXextended=true) {
+ switch ($genreid) {
+ case 'RX':
+ case 'CR':
+ break;
+ default:
+ if (!is_numeric($genreid)) {
+ return false;
+ }
+ $genreid = intval($genreid); // to handle 3 or '3' or '03'
+ break;
+ }
+ $GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
+ return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
+ }
+
+ public static function LookupGenreID($genre, $allowSCMPXextended=false) {
+ $GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
+ $LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre));
+ foreach ($GenreLookup as $key => $value) {
+ if (strtolower(str_replace(' ', '', $value)) == $LowerCaseNoSpaceSearchTerm) {
+ return $key;
+ }
+ }
+ return false;
+ }
+
+ public static function StandardiseID3v1GenreName($OriginalGenre) {
+ if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) {
+ return self::LookupGenreName($GenreID);
+ }
+ return $OriginalGenre;
+ }
+
+ public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') {
+ $ID3v1Tag = 'TAG';
+ $ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT);
+ if (!empty($track) && ($track > 0) && ($track <= 255)) {
+ $ID3v1Tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= "\x00";
+ if (gettype($track) == 'string') {
+ $track = (int) $track;
+ }
+ $ID3v1Tag .= chr($track);
+ } else {
+ $ID3v1Tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ }
+ if (($genreid < 0) || ($genreid > 147)) {
+ $genreid = 255; // 'unknown' genre
+ }
+ switch (gettype($genreid)) {
+ case 'string':
+ case 'integer':
+ $ID3v1Tag .= chr(intval($genreid));
+ break;
+ default:
+ $ID3v1Tag .= chr(255); // 'unknown' genre
+ break;
+ }
+
+ return $ID3v1Tag;
+ }
+
+}
diff --git a/src/wp-includes/ID3/module.tag.id3v2.php b/src/wp-includes/ID3/module.tag.id3v2.php
new file mode 100644
index 0000000000..b08f9f9a3b
--- /dev/null
+++ b/src/wp-includes/ID3/module.tag.id3v2.php
@@ -0,0 +1,3414 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+/// //
+// module.tag.id3v2.php //
+// module for analyzing ID3v2 tags //
+// dependencies: module.tag.id3v1.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
+
+class getid3_id3v2 extends getid3_handler
+{
+ public $StartingOffset = 0;
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ // Overall tag structure:
+ // +-----------------------------+
+ // | Header (10 bytes) |
+ // +-----------------------------+
+ // | Extended Header |
+ // | (variable length, OPTIONAL) |
+ // +-----------------------------+
+ // | Frames (variable length) |
+ // +-----------------------------+
+ // | Padding |
+ // | (variable length, OPTIONAL) |
+ // +-----------------------------+
+ // | Footer (10 bytes, OPTIONAL) |
+ // +-----------------------------+
+
+ // Header
+ // ID3v2/file identifier "ID3"
+ // ID3v2 version $04 00
+ // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
+ // ID3v2 size 4 * %0xxxxxxx
+
+
+ // shortcuts
+ $info['id3v2']['header'] = true;
+ $thisfile_id3v2 = &$info['id3v2'];
+ $thisfile_id3v2['flags'] = array();
+ $thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
+
+
+ fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET);
+ $header = fread($this->getid3->fp, 10);
+ if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
+
+ $thisfile_id3v2['majorversion'] = ord($header{3});
+ $thisfile_id3v2['minorversion'] = ord($header{4});
+
+ // shortcut
+ $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
+
+ } else {
+
+ unset($info['id3v2']);
+ return false;
+
+ }
+
+ if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
+
+ $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
+ return false;
+
+ }
+
+ $id3_flags = ord($header{5});
+ switch ($id3v2_majorversion) {
+ case 2:
+ // %ab000000 in v2.2
+ $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
+ $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
+ break;
+
+ case 3:
+ // %abc00000 in v2.3
+ $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
+ $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
+ $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
+ break;
+
+ case 4:
+ // %abcd0000 in v2.4
+ $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
+ $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
+ $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
+ $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present
+ break;
+ }
+
+ $thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
+
+ $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
+ $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
+
+
+
+ // create 'encoding' key - used by getid3::HandleAllTags()
+ // in ID3v2 every field can have it's own encoding type
+ // so force everything to UTF-8 so it can be handled consistantly
+ $thisfile_id3v2['encoding'] = 'UTF-8';
+
+
+ // Frames
+
+ // All ID3v2 frames consists of one frame header followed by one or more
+ // fields containing the actual information. The header is always 10
+ // bytes and laid out as follows:
+ //
+ // Frame ID $xx xx xx xx (four characters)
+ // Size 4 * %0xxxxxxx
+ // Flags $xx xx
+
+ $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
+ if (!empty($thisfile_id3v2['exthead']['length'])) {
+ $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
+ }
+ if (!empty($thisfile_id3v2_flags['isfooter'])) {
+ $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
+ }
+ if ($sizeofframes > 0) {
+
+ $framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable
+
+ // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
+ if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
+ $framedata = $this->DeUnsynchronise($framedata);
+ }
+ // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
+ // of on tag level, making it easier to skip frames, increasing the streamability
+ // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
+ // there exists an unsynchronised frame, while the new unsynchronisation flag in
+ // the frame header [S:4.1.2] indicates unsynchronisation.
+
+
+ //$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present)
+ $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
+
+
+ // Extended Header
+ if (!empty($thisfile_id3v2_flags['exthead'])) {
+ $extended_header_offset = 0;
+
+ if ($id3v2_majorversion == 3) {
+
+ // v2.3 definition:
+ //Extended header size $xx xx xx xx // 32-bit integer
+ //Extended Flags $xx xx
+ // %x0000000 %00000000 // v2.3
+ // x - CRC data present
+ //Size of padding $xx xx xx xx
+
+ $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
+ $extended_header_offset += 4;
+
+ $thisfile_id3v2['exthead']['flag_bytes'] = 2;
+ $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
+ $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
+
+ $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
+
+ $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
+ $extended_header_offset += 4;
+
+ if ($thisfile_id3v2['exthead']['flags']['crc']) {
+ $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
+ $extended_header_offset += 4;
+ }
+ $extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
+
+ } elseif ($id3v2_majorversion == 4) {
+
+ // v2.4 definition:
+ //Extended header size 4 * %0xxxxxxx // 28-bit synchsafe integer
+ //Number of flag bytes $01
+ //Extended Flags $xx
+ // %0bcd0000 // v2.4
+ // b - Tag is an update
+ // Flag data length $00
+ // c - CRC data present
+ // Flag data length $05
+ // Total frame CRC 5 * %0xxxxxxx
+ // d - Tag restrictions
+ // Flag data length $01
+
+ $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
+ $extended_header_offset += 4;
+
+ $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1
+ $extended_header_offset += 1;
+
+ $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
+ $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
+
+ $thisfile_id3v2['exthead']['flags']['update'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
+ $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
+ $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
+
+ if ($thisfile_id3v2['exthead']['flags']['update']) {
+ $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0
+ $extended_header_offset += 1;
+ }
+
+ if ($thisfile_id3v2['exthead']['flags']['crc']) {
+ $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5
+ $extended_header_offset += 1;
+ $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
+ $extended_header_offset += $ext_header_chunk_length;
+ }
+
+ if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
+ $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1
+ $extended_header_offset += 1;
+
+ // %ppqrrstt
+ $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
+ $extended_header_offset += 1;
+ $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions
+
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize'] = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc'] = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc'] = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize'] = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
+ }
+
+ if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
+ $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';
+ }
+ }
+
+ $framedataoffset += $extended_header_offset;
+ $framedata = substr($framedata, $extended_header_offset);
+ } // end extended header
+
+
+ while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
+ if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
+ // insufficient room left in ID3v2 header for actual data - must be padding
+ $thisfile_id3v2['padding']['start'] = $framedataoffset;
+ $thisfile_id3v2['padding']['length'] = strlen($framedata);
+ $thisfile_id3v2['padding']['valid'] = true;
+ for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
+ if ($framedata{$i} != "\x00") {
+ $thisfile_id3v2['padding']['valid'] = false;
+ $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
+ $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
+ break;
+ }
+ }
+ break; // skip rest of ID3v2 header
+ }
+ if ($id3v2_majorversion == 2) {
+ // Frame ID $xx xx xx (three characters)
+ // Size $xx xx xx (24-bit integer)
+ // Flags $xx xx
+
+ $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
+ $framedata = substr($framedata, 6); // and leave the rest in $framedata
+ $frame_name = substr($frame_header, 0, 3);
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
+ $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
+
+ } elseif ($id3v2_majorversion > 2) {
+
+ // Frame ID $xx xx xx xx (four characters)
+ // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
+ // Flags $xx xx
+
+ $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
+ $framedata = substr($framedata, 10); // and leave the rest in $framedata
+
+ $frame_name = substr($frame_header, 0, 4);
+ if ($id3v2_majorversion == 3) {
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
+ } else { // ID3v2.4+
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
+ }
+
+ if ($frame_size < (strlen($framedata) + 4)) {
+ $nextFrameID = substr($framedata, $frame_size, 4);
+ if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
+ // next frame is OK
+ } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
+ // MP3ext known broken frames - "ok" for the purposes of this test
+ } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
+ $info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3';
+ $id3v2_majorversion = 3;
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
+ }
+ }
+
+
+ $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
+ }
+
+ if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
+ // padding encountered
+
+ $thisfile_id3v2['padding']['start'] = $framedataoffset;
+ $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
+ $thisfile_id3v2['padding']['valid'] = true;
+
+ $len = strlen($framedata);
+ for ($i = 0; $i < $len; $i++) {
+ if ($framedata{$i} != "\x00") {
+ $thisfile_id3v2['padding']['valid'] = false;
+ $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
+ $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
+ break;
+ }
+ }
+ break; // skip rest of ID3v2 header
+ }
+
+ if ($frame_name == 'COM ') {
+ $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
+ $frame_name = 'COMM';
+ }
+ if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
+
+ unset($parsedFrame);
+ $parsedFrame['frame_name'] = $frame_name;
+ $parsedFrame['frame_flags_raw'] = $frame_flags;
+ $parsedFrame['data'] = substr($framedata, 0, $frame_size);
+ $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size);
+ $parsedFrame['dataoffset'] = $framedataoffset;
+
+ $this->ParseID3v2Frame($parsedFrame);
+ $thisfile_id3v2[$frame_name][] = $parsedFrame;
+
+ $framedata = substr($framedata, $frame_size);
+
+ } else { // invalid frame length or FrameID
+
+ if ($frame_size <= strlen($framedata)) {
+
+ if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
+
+ // next frame is valid, just skip the current frame
+ $framedata = substr($framedata, $frame_size);
+ $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
+
+ } else {
+
+ // next frame is invalid too, abort processing
+ //unset($framedata);
+ $framedata = null;
+ $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
+
+ }
+
+ } elseif ($frame_size == strlen($framedata)) {
+
+ // this is the last frame, just skip
+ $info['warning'][] = 'This was the last ID3v2 frame.';
+
+ } else {
+
+ // next frame is invalid too, abort processing
+ //unset($framedata);
+ $framedata = null;
+ $info['warning'][] = 'Invalid ID3v2 frame size, aborting.';
+
+ }
+ if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
+
+ switch ($frame_name) {
+ case "\x00\x00".'MP':
+ case "\x00".'MP3':
+ case ' MP3':
+ case 'MP3e':
+ case "\x00".'MP':
+ case ' MP':
+ case 'MP3':
+ $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
+ break;
+
+ default:
+ $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
+ break;
+ }
+
+ } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
+
+ $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).';
+
+ } else {
+
+ $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
+
+ }
+
+ }
+ $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
+
+ }
+
+ }
+
+
+ // Footer
+
+ // The footer is a copy of the header, but with a different identifier.
+ // ID3v2 identifier "3DI"
+ // ID3v2 version $04 00
+ // ID3v2 flags %abcd0000
+ // ID3v2 size 4 * %0xxxxxxx
+
+ if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
+ $footer = fread($this->getid3->fp, 10);
+ if (substr($footer, 0, 3) == '3DI') {
+ $thisfile_id3v2['footer'] = true;
+ $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
+ $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
+ }
+ if ($thisfile_id3v2['majorversion_footer'] <= 4) {
+ $id3_flags = ord(substr($footer{5}));
+ $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
+ $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
+ $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
+ $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
+
+ $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
+ }
+ } // end footer
+
+ if (isset($thisfile_id3v2['comments']['genre'])) {
+ foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
+ unset($thisfile_id3v2['comments']['genre'][$key]);
+ $thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value)));
+ }
+ }
+
+ if (isset($thisfile_id3v2['comments']['track'])) {
+ foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
+ if (strstr($value, '/')) {
+ list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
+ }
+ }
+ }
+
+ if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
+ $thisfile_id3v2['comments']['year'] = array($matches[1]);
+ }
+
+
+ if (!empty($thisfile_id3v2['TXXX'])) {
+ // MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames
+ foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
+ switch ($txxx_array['description']) {
+ case 'replaygain_track_gain':
+ if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
+ $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
+ }
+ break;
+ case 'replaygain_track_peak':
+ if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
+ $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
+ }
+ break;
+ case 'replaygain_album_gain':
+ if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
+ $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
+ }
+ break;
+ }
+ }
+ }
+
+
+ // Set avdataoffset
+ $info['avdataoffset'] = $thisfile_id3v2['headerlength'];
+ if (isset($thisfile_id3v2['footer'])) {
+ $info['avdataoffset'] += 10;
+ }
+
+ return true;
+ }
+
+
+ public function ParseID3v2GenreString($genrestring) {
+ // Parse genres into arrays of genreName and genreID
+ // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
+ // ID3v2.4.x: '21' $00 'Eurodisco' $00
+ $clean_genres = array();
+ if (strpos($genrestring, "\x00") === false) {
+ $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
+ }
+ $genre_elements = explode("\x00", $genrestring);
+ foreach ($genre_elements as $element) {
+ $element = trim($element);
+ if ($element) {
+ if (preg_match('#^[0-9]{1,3}#', $element)) {
+ $clean_genres[] = getid3_id3v1::LookupGenreName($element);
+ } else {
+ $clean_genres[] = str_replace('((', '(', $element);
+ }
+ }
+ }
+ return $clean_genres;
+ }
+
+
+ public function ParseID3v2Frame(&$parsedFrame) {
+
+ // shortcuts
+ $info = &$this->getid3->info;
+ $id3v2_majorversion = $info['id3v2']['majorversion'];
+
+ $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']);
+ if (empty($parsedFrame['framenamelong'])) {
+ unset($parsedFrame['framenamelong']);
+ }
+ $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
+ if (empty($parsedFrame['framenameshort'])) {
+ unset($parsedFrame['framenameshort']);
+ }
+
+ if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
+ if ($id3v2_majorversion == 3) {
+ // Frame Header Flags
+ // %abc00000 %ijk00000
+ $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
+ $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
+ $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
+ $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
+ $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
+ $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
+
+ } elseif ($id3v2_majorversion == 4) {
+ // Frame Header Flags
+ // %0abc0000 %0h00kmnp
+ $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
+ $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
+ $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
+ $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
+ $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
+ $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
+ $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
+ $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
+
+ // Frame-level de-unsynchronisation - ID3v2.4
+ if ($parsedFrame['flags']['Unsynchronisation']) {
+ $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
+ }
+
+ if ($parsedFrame['flags']['DataLengthIndicator']) {
+ $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
+ $parsedFrame['data'] = substr($parsedFrame['data'], 4);
+ }
+ }
+
+ // Frame-level de-compression
+ if ($parsedFrame['flags']['compression']) {
+ $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
+ if (!function_exists('gzuncompress')) {
+ $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
+ } else {
+ if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
+ //if ($decompresseddata = @gzuncompress($parsedFrame['data'])) {
+ $parsedFrame['data'] = $decompresseddata;
+ unset($decompresseddata);
+ } else {
+ $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
+ }
+ }
+ }
+ }
+
+ if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
+ if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
+ $info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data';
+ }
+ }
+
+ if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
+
+ $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
+ switch ($parsedFrame['frame_name']) {
+ case 'WCOM':
+ $warning .= ' (this is known to happen with files tagged by RioPort)';
+ break;
+
+ default:
+ break;
+ }
+ $info['warning'][] = $warning;
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier
+ // There may be more than one 'UFID' frame in a tag,
+ // but only one with the same 'Owner identifier'.
+ // <Header for 'Unique file identifier', ID: 'UFID'>
+ // Owner identifier <text string> $00
+ // Identifier <up to 64 bytes binary data>
+ $exploded = explode("\x00", $parsedFrame['data'], 2);
+ $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
+ $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : '');
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame
+ // There may be more than one 'TXXX' frame in each tag,
+ // but only one with the same description.
+ // <Header for 'User defined text information frame', ID: 'TXXX'>
+ // Text encoding $xx
+ // Description <text string according to encoding> $00 (00)
+ // Value <text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
+ }
+ //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
+
+
+ } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
+ // There may only be one text information frame of its kind in an tag.
+ // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
+ // excluding 'TXXX' described in 4.2.6.>
+ // Text encoding $xx
+ // Information <text string(s) according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
+ // This of course breaks when an artist name contains slash character, e.g. "AC/DC"
+ // MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense
+ // getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user
+ switch ($parsedFrame['encoding']) {
+ case 'UTF-16':
+ case 'UTF-16BE':
+ case 'UTF-16LE':
+ $wordsize = 2;
+ break;
+ case 'ISO-8859-1':
+ case 'UTF-8':
+ default:
+ $wordsize = 1;
+ break;
+ }
+ $Txxx_elements = array();
+ $Txxx_elements_start_offset = 0;
+ for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
+ if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
+ $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
+ $Txxx_elements_start_offset = $i + $wordsize;
+ }
+ }
+ $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
+ foreach ($Txxx_elements as $Txxx_element) {
+ $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
+ if (!empty($string)) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
+ }
+ }
+ unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
+ }
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame
+ // There may be more than one 'WXXX' frame in each tag,
+ // but only one with the same description
+ // <Header for 'User defined URL link frame', ID: 'WXXX'>
+ // Text encoding $xx
+ // Description <text string according to encoding> $00 (00)
+ // URL <text string>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ if ($frame_terminatorpos) {
+ // there are null bytes after the data - this is not according to spec
+ // only use data up to first null byte
+ $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
+ } else {
+ // no null bytes following data, just use all data
+ $frame_urldata = (string) $parsedFrame['data'];
+ }
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['url'] = $frame_urldata;
+ $parsedFrame['description'] = $frame_description;
+ if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
+ // There may only be one URL link frame of its kind in a tag,
+ // except when stated otherwise in the frame description
+ // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
+ // described in 4.3.2.>
+ // URL <text string>
+
+ $parsedFrame['url'] = trim($parsedFrame['data']);
+ if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only)
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only)
+ // http://id3.org/id3v2.3.0#sec4.4
+ // There may only be one 'IPL' frame in each tag
+ // <Header for 'User defined URL link frame', ID: 'IPL'>
+ // Text encoding $xx
+ // People list strings <textstrings>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
+ $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+ // http://www.getid3.org/phpBB3/viewtopic.php?t=1369
+ // "this tag typically contains null terminated strings, which are associated in pairs"
+ // "there are users that use the tag incorrectly"
+ $IPLS_parts = array();
+ if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
+ $IPLS_parts_unsorted = array();
+ if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
+ // UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding
+ $thisILPS = '';
+ for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
+ $twobytes = substr($parsedFrame['data_raw'], $i, 2);
+ if ($twobytes === "\x00\x00") {
+ $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
+ $thisILPS = '';
+ } else {
+ $thisILPS .= $twobytes;
+ }
+ }
+ if (strlen($thisILPS) > 2) { // 2-byte BOM
+ $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
+ }
+ } else {
+ // ISO-8859-1 or UTF-8 or other single-byte-null character set
+ $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
+ }
+ if (count($IPLS_parts_unsorted) == 1) {
+ // just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson"
+ foreach ($IPLS_parts_unsorted as $key => $value) {
+ $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
+ $position = '';
+ foreach ($IPLS_parts_sorted as $person) {
+ $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
+ }
+ }
+ } elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
+ $position = '';
+ $person = '';
+ foreach ($IPLS_parts_unsorted as $key => $value) {
+ if (($key % 2) == 0) {
+ $position = $value;
+ } else {
+ $person = $value;
+ $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
+ $position = '';
+ $person = '';
+ }
+ }
+ } else {
+ foreach ($IPLS_parts_unsorted as $key => $value) {
+ $IPLS_parts[] = array($value);
+ }
+ }
+
+ } else {
+ $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
+ }
+ $parsedFrame['data'] = $IPLS_parts;
+
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
+ }
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier
+ // There may only be one 'MCDI' frame in each tag
+ // <Header for 'Music CD identifier', ID: 'MCDI'>
+ // CD TOC <binary data>
+
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
+ }
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes
+ // There may only be one 'ETCO' frame in each tag
+ // <Header for 'Event timing codes', ID: 'ETCO'>
+ // Time stamp format $xx
+ // Where time stamp format is:
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ // Followed by a list of key events in the following format:
+ // Type of event $xx
+ // Time stamp $xx (xx ...)
+ // The 'Time stamp' is set to zero if directly at the beginning of the sound
+ // or after the previous event. All events MUST be sorted in chronological order.
+
+ $frame_offset = 0;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ while ($frame_offset < strlen($parsedFrame['data'])) {
+ $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1);
+ $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']);
+ $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table
+ // There may only be one 'MLLT' frame in each tag
+ // <Header for 'Location lookup table', ID: 'MLLT'>
+ // MPEG frames between reference $xx xx
+ // Bytes between reference $xx xx xx
+ // Milliseconds between reference $xx xx xx
+ // Bits for bytes deviation $xx
+ // Bits for milliseconds dev. $xx
+ // Then for every reference the following data is included;
+ // Deviation in bytes %xxx....
+ // Deviation in milliseconds %xxx....
+
+ $frame_offset = 0;
+ $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
+ $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
+ $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
+ $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
+ $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
+ $parsedFrame['data'] = substr($parsedFrame['data'], 10);
+ while ($frame_offset < strlen($parsedFrame['data'])) {
+ $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
+ }
+ $reference_counter = 0;
+ while (strlen($deviationbitstream) > 0) {
+ $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
+ $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
+ $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
+ $reference_counter++;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes
+ // There may only be one 'SYTC' frame in each tag
+ // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
+ // Time stamp format $xx
+ // Tempo data <binary data>
+ // Where time stamp format is:
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+
+ $frame_offset = 0;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $timestamp_counter = 0;
+ while ($frame_offset < strlen($parsedFrame['data'])) {
+ $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
+ $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ }
+ $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $timestamp_counter++;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription
+ // There may be more than one 'Unsynchronised lyrics/text transcription' frame
+ // in each tag, but only one with the same language and content descriptor.
+ // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Content descriptor <text string according to encoding> $00 (00)
+ // Lyrics/text <full text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['data'] = $parsedFrame['data'];
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+ $parsedFrame['description'] = $frame_description;
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text
+ // There may be more than one 'SYLT' frame in each tag,
+ // but only one with the same language and content descriptor.
+ // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Time stamp format $xx
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ // Content type $xx
+ // Content descriptor <text string according to encoding> $00 (00)
+ // Terminated text to be synced (typically a syllable)
+ // Sync identifier (terminator to above string) $00 (00)
+ // Time stamp $xx (xx ...)
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+
+ $timestampindex = 0;
+ $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
+ while (strlen($frame_remainingdata)) {
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding));
+ if ($frame_terminatorpos === false) {
+ $frame_remainingdata = '';
+ } else {
+ if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
+
+ $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
+ // timestamp probably omitted for first data item
+ } else {
+ $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
+ $frame_remainingdata = substr($frame_remainingdata, 4);
+ }
+ $timestampindex++;
+ }
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) { // 4.11 COM Comments
+ // There may be more than one comment frame in each tag,
+ // but only one with the same language and content descriptor.
+ // <Header for 'Comment', ID: 'COMM'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Short content descrip. <text string according to encoding> $00 (00)
+ // The actual text <full text string according to encoding>
+
+ if (strlen($parsedFrame['data']) < 5) {
+
+ $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
+
+ } else {
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['data'] = $frame_text;
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
+
+ }
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
+ // There may be more than one 'RVA2' frame in each tag,
+ // but only one with the same identification string
+ // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
+ // Identification <text string> $00
+ // The 'identification' string is used to identify the situation and/or
+ // device where this adjustment should apply. The following is then
+ // repeated for every channel:
+ // Type of channel $xx
+ // Volume adjustment $xx xx
+ // Bits representing peak $xx
+ // Peak volume $xx (xx ...)
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
+ $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
+ if (ord($frame_idstring) === 0) {
+ $frame_idstring = '';
+ }
+ $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
+ $parsedFrame['description'] = $frame_idstring;
+ $RVA2channelcounter = 0;
+ while (strlen($frame_remainingdata) >= 5) {
+ $frame_offset = 0;
+ $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
+ $parsedFrame[$RVA2channelcounter]['channeltypeid'] = $frame_channeltypeid;
+ $parsedFrame[$RVA2channelcounter]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
+ $parsedFrame[$RVA2channelcounter]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
+ $frame_offset += 2;
+ $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
+ if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
+ $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';
+ break;
+ }
+ $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
+ $parsedFrame[$RVA2channelcounter]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
+ $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
+ $RVA2channelcounter++;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only)
+ // There may only be one 'RVA' frame in each tag
+ // <Header for 'Relative volume adjustment', ID: 'RVA'>
+ // ID3v2.2 => Increment/decrement %000000ba
+ // ID3v2.3 => Increment/decrement %00fedcba
+ // Bits used for volume descr. $xx
+ // Relative volume change, right $xx xx (xx ...) // a
+ // Relative volume change, left $xx xx (xx ...) // b
+ // Peak volume right $xx xx (xx ...)
+ // Peak volume left $xx xx (xx ...)
+ // ID3v2.3 only, optional (not present in ID3v2.2):
+ // Relative volume change, right back $xx xx (xx ...) // c
+ // Relative volume change, left back $xx xx (xx ...) // d
+ // Peak volume right back $xx xx (xx ...)
+ // Peak volume left back $xx xx (xx ...)
+ // ID3v2.3 only, optional (not present in ID3v2.2):
+ // Relative volume change, center $xx xx (xx ...) // e
+ // Peak volume center $xx xx (xx ...)
+ // ID3v2.3 only, optional (not present in ID3v2.2):
+ // Relative volume change, bass $xx xx (xx ...) // f
+ // Peak volume bass $xx xx (xx ...)
+
+ $frame_offset = 0;
+ $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
+ $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
+ $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
+ $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['right'] === false) {
+ $parsedFrame['volumechange']['right'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['left'] === false) {
+ $parsedFrame['volumechange']['left'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ if ($id3v2_majorversion == 3) {
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
+ if (strlen($parsedFrame['data']) > 0) {
+ $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
+ $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
+ $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['rightrear'] === false) {
+ $parsedFrame['volumechange']['rightrear'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['leftrear'] === false) {
+ $parsedFrame['volumechange']['leftrear'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
+ if (strlen($parsedFrame['data']) > 0) {
+ $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
+ $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['center'] === false) {
+ $parsedFrame['volumechange']['center'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
+ if (strlen($parsedFrame['data']) > 0) {
+ $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
+ $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['bass'] === false) {
+ $parsedFrame['volumechange']['bass'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ }
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
+ // There may be more than one 'EQU2' frame in each tag,
+ // but only one with the same identification string
+ // <Header of 'Equalisation (2)', ID: 'EQU2'>
+ // Interpolation method $xx
+ // $00 Band
+ // $01 Linear
+ // Identification <text string> $00
+ // The following is then repeated for every adjustment point
+ // Frequency $xx xx
+ // Volume adjustment $xx xx
+
+ $frame_offset = 0;
+ $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_idstring) === 0) {
+ $frame_idstring = '';
+ }
+ $parsedFrame['description'] = $frame_idstring;
+ $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
+ while (strlen($frame_remainingdata)) {
+ $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
+ $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
+ $frame_remainingdata = substr($frame_remainingdata, 4);
+ }
+ $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only)
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only)
+ // There may only be one 'EQUA' frame in each tag
+ // <Header for 'Relative volume adjustment', ID: 'EQU'>
+ // Adjustment bits $xx
+ // This is followed by 2 bytes + ('adjustment bits' rounded up to the
+ // nearest byte) for every equalisation band in the following format,
+ // giving a frequency range of 0 - 32767Hz:
+ // Increment/decrement %x (MSB of the Frequency)
+ // Frequency (lower 15 bits)
+ // Adjustment $xx (xx ...)
+
+ $frame_offset = 0;
+ $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
+ $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
+
+ $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
+ while (strlen($frame_remainingdata) > 0) {
+ $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
+ $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
+ $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
+ $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
+ $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
+ if ($parsedFrame[$frame_frequency]['incdec'] === false) {
+ $parsedFrame[$frame_frequency]['adjustment'] *= -1;
+ }
+ $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) { // 4.14 REV Reverb
+ // There may only be one 'RVRB' frame in each tag.
+ // <Header for 'Reverb', ID: 'RVRB'>
+ // Reverb left (ms) $xx xx
+ // Reverb right (ms) $xx xx
+ // Reverb bounces, left $xx
+ // Reverb bounces, right $xx
+ // Reverb feedback, left to left $xx
+ // Reverb feedback, left to right $xx
+ // Reverb feedback, right to right $xx
+ // Reverb feedback, right to left $xx
+ // Premix left to right $xx
+ // Premix right to left $xx
+
+ $frame_offset = 0;
+ $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture
+ // There may be several pictures attached to one file,
+ // each in their individual 'APIC' frame, but only one
+ // with the same content descriptor
+ // <Header for 'Attached picture', ID: 'APIC'>
+ // Text encoding $xx
+ // ID3v2.3+ => MIME type <text string> $00
+ // ID3v2.2 => Image format $xx xx xx
+ // Picture type $xx
+ // Description <text string according to encoding> $00 (00)
+ // Picture data <binary data>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+
+ if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
+ $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
+ if (strtolower($frame_imagetype) == 'ima') {
+ // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
+ // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net)
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_mimetype) === 0) {
+ $frame_mimetype = '';
+ }
+ $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
+ if ($frame_imagetype == 'JPEG') {
+ $frame_imagetype = 'JPG';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ } else {
+ $frame_offset += 3;
+ }
+ }
+ if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_mimetype) === 0) {
+ $frame_mimetype = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ }
+
+ $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ if ($frame_offset >= $parsedFrame['datalength']) {
+ $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
+ } else {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ if ($id3v2_majorversion == 2) {
+ $parsedFrame['imagetype'] = $frame_imagetype;
+ } else {
+ $parsedFrame['mime'] = $frame_mimetype;
+ }
+ $parsedFrame['picturetypeid'] = $frame_picturetype;
+ $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ $parsedFrame['datalength'] = strlen($parsedFrame['data']);
+
+ $parsedFrame['image_mime'] = '';
+ $imageinfo = array();
+ $imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo);
+ if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
+ $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
+ if ($imagechunkcheck[0]) {
+ $parsedFrame['image_width'] = $imagechunkcheck[0];
+ }
+ if ($imagechunkcheck[1]) {
+ $parsedFrame['image_height'] = $imagechunkcheck[1];
+ }
+ }
+
+ do {
+ if ($this->getid3->option_save_attachments === false) {
+ // skip entirely
+ unset($parsedFrame['data']);
+ break;
+ }
+ if ($this->getid3->option_save_attachments === true) {
+ // great
+/*
+ } elseif (is_int($this->getid3->option_save_attachments)) {
+ if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) {
+ // too big, skip
+ $info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)';
+ unset($parsedFrame['data']);
+ break;
+ }
+*/
+ } elseif (is_string($this->getid3->option_save_attachments)) {
+ $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
+ if (!is_dir($dir) || !is_writable($dir)) {
+ // cannot write, skip
+ $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';
+ unset($parsedFrame['data']);
+ break;
+ }
+ }
+ // if we get this far, must be OK
+ if (is_string($this->getid3->option_save_attachments)) {
+ $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
+ if (!file_exists($destination_filename) || is_writable($destination_filename)) {
+ file_put_contents($destination_filename, $parsedFrame['data']);
+ } else {
+ $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
+ }
+ $parsedFrame['data_filename'] = $destination_filename;
+ unset($parsedFrame['data']);
+ } else {
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ if (!isset($info['id3v2']['comments']['picture'])) {
+ $info['id3v2']['comments']['picture'] = array();
+ }
+ $info['id3v2']['comments']['picture'][] = array('data'=>$parsedFrame['data'], 'image_mime'=>$parsedFrame['image_mime']);
+ }
+ }
+ } while (false);
+ }
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object
+ // There may be more than one 'GEOB' frame in each tag,
+ // but only one with the same content descriptor
+ // <Header for 'General encapsulated object', ID: 'GEOB'>
+ // Text encoding $xx
+ // MIME type <text string> $00
+ // Filename <text string according to encoding> $00 (00)
+ // Content description <text string according to encoding> $00 (00)
+ // Encapsulated object <binary data>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_mimetype) === 0) {
+ $frame_mimetype = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_filename) === 0) {
+ $frame_filename = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['mime'] = $frame_mimetype;
+ $parsedFrame['filename'] = $frame_filename;
+ $parsedFrame['description'] = $frame_description;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter
+ // There may only be one 'PCNT' frame in each tag.
+ // When the counter reaches all one's, one byte is inserted in
+ // front of the counter thus making the counter eight bits bigger
+ // <Header for 'Play counter', ID: 'PCNT'>
+ // Counter $xx xx xx xx (xx ...)
+
+ $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter
+ // There may be more than one 'POPM' frame in each tag,
+ // but only one with the same email address
+ // <Header for 'Popularimeter', ID: 'POPM'>
+ // Email to user <text string> $00
+ // Rating $xx
+ // Counter $xx xx xx xx (xx ...)
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_emailaddress) === 0) {
+ $frame_emailaddress = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
+ $parsedFrame['email'] = $frame_emailaddress;
+ $parsedFrame['rating'] = $frame_rating;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size
+ // There may only be one 'RBUF' frame in each tag
+ // <Header for 'Recommended buffer size', ID: 'RBUF'>
+ // Buffer size $xx xx xx
+ // Embedded info flag %0000000x
+ // Offset to next tag $xx xx xx xx
+
+ $frame_offset = 0;
+ $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
+ $frame_offset += 3;
+
+ $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
+ $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only)
+ // There may be more than one 'CRM' frame in a tag,
+ // but only one with the same 'owner identifier'
+ // <Header for 'Encrypted meta frame', ID: 'CRM'>
+ // Owner identifier <textstring> $00 (00)
+ // Content/explanation <textstring> $00 (00)
+ // Encrypted datablock <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['description'] = $frame_description;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption
+ // There may be more than one 'AENC' frames in a tag,
+ // but only one with the same 'Owner identifier'
+ // <Header for 'Audio encryption', ID: 'AENC'>
+ // Owner identifier <text string> $00
+ // Preview start $xx xx
+ // Preview length $xx xx
+ // Encryption info <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid == '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information
+ // There may be more than one 'LINK' frame in a tag,
+ // but only one with the same contents
+ // <Header for 'Linked information', ID: 'LINK'>
+ // ID3v2.3+ => Frame identifier $xx xx xx xx
+ // ID3v2.2 => Frame identifier $xx xx xx
+ // URL <text string> $00
+ // ID and additional data <text string(s)>
+
+ $frame_offset = 0;
+ if ($id3v2_majorversion == 2) {
+ $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ } else {
+ $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
+ $frame_offset += 4;
+ }
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_url) === 0) {
+ $frame_url = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $parsedFrame['url'] = $frame_url;
+
+ $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
+ if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = utf8_encode($parsedFrame['url']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only)
+ // There may only be one 'POSS' frame in each tag
+ // <Head for 'Position synchronisation', ID: 'POSS'>
+ // Time stamp format $xx
+ // Position $xx (xx ...)
+
+ $frame_offset = 0;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only)
+ // There may be more than one 'Terms of use' frame in a tag,
+ // but only one with the same 'Language'
+ // <Header for 'Terms of use frame', ID: 'USER'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // The actual text <text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only)
+ // There may only be one 'OWNE' frame in a tag
+ // <Header for 'Ownership frame', ID: 'OWNE'>
+ // Text encoding $xx
+ // Price paid <text string> $00
+ // Date of purch. <text string>
+ // Seller <text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
+ $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
+ $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3);
+
+ $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
+ if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
+ $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
+ }
+ $frame_offset += 8;
+
+ $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only)
+ // There may be more than one 'commercial frame' in a tag,
+ // but no two may be identical
+ // <Header for 'Commercial frame', ID: 'COMR'>
+ // Text encoding $xx
+ // Price string <text string> $00
+ // Valid until <text string>
+ // Contact URL <text string> $00
+ // Received as $xx
+ // Name of seller <text string according to encoding> $00 (00)
+ // Description <text string according to encoding> $00 (00)
+ // Picture MIME type <string> $00
+ // Seller logo <binary data>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $frame_rawpricearray = explode('/', $frame_pricestring);
+ foreach ($frame_rawpricearray as $key => $val) {
+ $frame_currencyid = substr($val, 0, 3);
+ $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
+ $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3);
+ }
+
+ $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
+ $frame_offset += 8;
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_sellername) === 0) {
+ $frame_sellername = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['pricevaliduntil'] = $frame_datestring;
+ $parsedFrame['contacturl'] = $frame_contacturl;
+ $parsedFrame['receivedasid'] = $frame_receivedasid;
+ $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
+ $parsedFrame['sellername'] = $frame_sellername;
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['mime'] = $frame_mimetype;
+ $parsedFrame['logo'] = $frame_sellerlogo;
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only)
+ // There may be several 'ENCR' frames in a tag,
+ // but only one containing the same symbol
+ // and only one containing the same owner identifier
+ // <Header for 'Encryption method registration', ID: 'ENCR'>
+ // Owner identifier <text string> $00
+ // Method symbol $xx
+ // Encryption data <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only)
+
+ // There may be several 'GRID' frames in a tag,
+ // but only one containing the same symbol
+ // and only one containing the same owner identifier
+ // <Header for 'Group ID registration', ID: 'GRID'>
+ // Owner identifier <text string> $00
+ // Group symbol $xx
+ // Group dependent data <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only)
+ // The tag may contain more than one 'PRIV' frame
+ // but only with different contents
+ // <Header for 'Private frame', ID: 'PRIV'>
+ // Owner identifier <text string> $00
+ // The private data <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only)
+ // There may be more than one 'signature frame' in a tag,
+ // but no two may be identical
+ // <Header for 'Signature frame', ID: 'SIGN'>
+ // Group symbol $xx
+ // Signature <binary data>
+
+ $frame_offset = 0;
+ $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only)
+ // There may only be one 'seek frame' in a tag
+ // <Header for 'Seek frame', ID: 'SEEK'>
+ // Minimum offset to next tag $xx xx xx xx
+
+ $frame_offset = 0;
+ $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only)
+ // There may only be one 'audio seek point index' frame in a tag
+ // <Header for 'Seek Point Index', ID: 'ASPI'>
+ // Indexed data start (S) $xx xx xx xx
+ // Indexed data length (L) $xx xx xx xx
+ // Number of index points (N) $xx xx
+ // Bits per index point (b) $xx
+ // Then for every index point the following data is included:
+ // Fraction at index (Fi) $xx (xx)
+
+ $frame_offset = 0;
+ $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
+ for ($i = 0; $i < $frame_indexpoints; $i++) {
+ $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
+ $frame_offset += $frame_bytesperpoint;
+ }
+ unset($parsedFrame['data']);
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
+ // There may only be one 'RGAD' frame in a tag
+ // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
+ // Peak Amplitude $xx $xx $xx $xx
+ // Radio Replay Gain Adjustment %aaabbbcd %dddddddd
+ // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd
+ // a - name code
+ // b - originator code
+ // c - sign bit
+ // d - replay gain adjustment
+
+ $frame_offset = 0;
+ $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
+ $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
+ $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
+ $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
+ $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
+ $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
+ $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
+ $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
+ $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
+ $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
+ $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
+ $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
+ $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
+ $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
+
+ $info['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude'];
+ $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
+ $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
+ $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
+ $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
+
+ unset($parsedFrame['data']);
+
+ }
+
+ return true;
+ }
+
+
+ public function DeUnsynchronise($data) {
+ return str_replace("\xFF\x00", "\xFF", $data);
+ }
+
+ public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
+ static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
+ 0x00 => 'No more than 128 frames and 1 MB total tag size',
+ 0x01 => 'No more than 64 frames and 128 KB total tag size',
+ 0x02 => 'No more than 32 frames and 40 KB total tag size',
+ 0x03 => 'No more than 32 frames and 4 KB total tag size',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
+ static $LookupExtendedHeaderRestrictionsTextEncodings = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
+ static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'No string is longer than 1024 characters',
+ 0x02 => 'No string is longer than 128 characters',
+ 0x03 => 'No string is longer than 30 characters',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
+ static $LookupExtendedHeaderRestrictionsImageEncoding = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'Images are encoded only with PNG or JPEG',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
+ static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'All images are 256x256 pixels or smaller',
+ 0x02 => 'All images are 64x64 pixels or smaller',
+ 0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
+ }
+
+ public function LookupCurrencyUnits($currencyid) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+
+ AED Dirhams
+ AFA Afghanis
+ ALL Leke
+ AMD Drams
+ ANG Guilders
+ AOA Kwanza
+ ARS Pesos
+ ATS Schillings
+ AUD Dollars
+ AWG Guilders
+ AZM Manats
+ BAM Convertible Marka
+ BBD Dollars
+ BDT Taka
+ BEF Francs
+ BGL Leva
+ BHD Dinars
+ BIF Francs
+ BMD Dollars
+ BND Dollars
+ BOB Bolivianos
+ BRL Brazil Real
+ BSD Dollars
+ BTN Ngultrum
+ BWP Pulas
+ BYR Rubles
+ BZD Dollars
+ CAD Dollars
+ CDF Congolese Francs
+ CHF Francs
+ CLP Pesos
+ CNY Yuan Renminbi
+ COP Pesos
+ CRC Colones
+ CUP Pesos
+ CVE Escudos
+ CYP Pounds
+ CZK Koruny
+ DEM Deutsche Marks
+ DJF Francs
+ DKK Kroner
+ DOP Pesos
+ DZD Algeria Dinars
+ EEK Krooni
+ EGP Pounds
+ ERN Nakfa
+ ESP Pesetas
+ ETB Birr
+ EUR Euro
+ FIM Markkaa
+ FJD Dollars
+ FKP Pounds
+ FRF Francs
+ GBP Pounds
+ GEL Lari
+ GGP Pounds
+ GHC Cedis
+ GIP Pounds
+ GMD Dalasi
+ GNF Francs
+ GRD Drachmae
+ GTQ Quetzales
+ GYD Dollars
+ HKD Dollars
+ HNL Lempiras
+ HRK Kuna
+ HTG Gourdes
+ HUF Forints
+ IDR Rupiahs
+ IEP Pounds
+ ILS New Shekels
+ IMP Pounds
+ INR Rupees
+ IQD Dinars
+ IRR Rials
+ ISK Kronur
+ ITL Lire
+ JEP Pounds
+ JMD Dollars
+ JOD Dinars
+ JPY Yen
+ KES Shillings
+ KGS Soms
+ KHR Riels
+ KMF Francs
+ KPW Won
+ KWD Dinars
+ KYD Dollars
+ KZT Tenge
+ LAK Kips
+ LBP Pounds
+ LKR Rupees
+ LRD Dollars
+ LSL Maloti
+ LTL Litai
+ LUF Francs
+ LVL Lati
+ LYD Dinars
+ MAD Dirhams
+ MDL Lei
+ MGF Malagasy Francs
+ MKD Denars
+ MMK Kyats
+ MNT Tugriks
+ MOP Patacas
+ MRO Ouguiyas
+ MTL Liri
+ MUR Rupees
+ MVR Rufiyaa
+ MWK Kwachas
+ MXN Pesos
+ MYR Ringgits
+ MZM Meticais
+ NAD Dollars
+ NGN Nairas
+ NIO Gold Cordobas
+ NLG Guilders
+ NOK Krone
+ NPR Nepal Rupees
+ NZD Dollars
+ OMR Rials
+ PAB Balboa
+ PEN Nuevos Soles
+ PGK Kina
+ PHP Pesos
+ PKR Rupees
+ PLN Zlotych
+ PTE Escudos
+ PYG Guarani
+ QAR Rials
+ ROL Lei
+ RUR Rubles
+ RWF Rwanda Francs
+ SAR Riyals
+ SBD Dollars
+ SCR Rupees
+ SDD Dinars
+ SEK Kronor
+ SGD Dollars
+ SHP Pounds
+ SIT Tolars
+ SKK Koruny
+ SLL Leones
+ SOS Shillings
+ SPL Luigini
+ SRG Guilders
+ STD Dobras
+ SVC Colones
+ SYP Pounds
+ SZL Emalangeni
+ THB Baht
+ TJR Rubles
+ TMM Manats
+ TND Dinars
+ TOP Pa'anga
+ TRL Liras
+ TTD Dollars
+ TVD Tuvalu Dollars
+ TWD New Dollars
+ TZS Shillings
+ UAH Hryvnia
+ UGX Shillings
+ USD Dollars
+ UYU Pesos
+ UZS Sums
+ VAL Lire
+ VEB Bolivares
+ VND Dong
+ VUV Vatu
+ WST Tala
+ XAF Francs
+ XAG Ounces
+ XAU Ounces
+ XCD Dollars
+ XDR Special Drawing Rights
+ XPD Ounces
+ XPF Francs
+ XPT Ounces
+ YER Rials
+ YUM New Dinars
+ ZAR Rand
+ ZMK Kwacha
+ ZWD Zimbabwe Dollars
+
+ */
+
+ return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
+ }
+
+
+ public function LookupCurrencyCountry($currencyid) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ AED United Arab Emirates
+ AFA Afghanistan
+ ALL Albania
+ AMD Armenia
+ ANG Netherlands Antilles
+ AOA Angola
+ ARS Argentina
+ ATS Austria
+ AUD Australia
+ AWG Aruba
+ AZM Azerbaijan
+ BAM Bosnia and Herzegovina
+ BBD Barbados
+ BDT Bangladesh
+ BEF Belgium
+ BGL Bulgaria
+ BHD Bahrain
+ BIF Burundi
+ BMD Bermuda
+ BND Brunei Darussalam
+ BOB Bolivia
+ BRL Brazil
+ BSD Bahamas
+ BTN Bhutan
+ BWP Botswana
+ BYR Belarus
+ BZD Belize
+ CAD Canada
+ CDF Congo/Kinshasa
+ CHF Switzerland
+ CLP Chile
+ CNY China
+ COP Colombia
+ CRC Costa Rica
+ CUP Cuba
+ CVE Cape Verde
+ CYP Cyprus
+ CZK Czech Republic
+ DEM Germany
+ DJF Djibouti
+ DKK Denmark
+ DOP Dominican Republic
+ DZD Algeria
+ EEK Estonia
+ EGP Egypt
+ ERN Eritrea
+ ESP Spain
+ ETB Ethiopia
+ EUR Euro Member Countries
+ FIM Finland
+ FJD Fiji
+ FKP Falkland Islands (Malvinas)
+ FRF France
+ GBP United Kingdom
+ GEL Georgia
+ GGP Guernsey
+ GHC Ghana
+ GIP Gibraltar
+ GMD Gambia
+ GNF Guinea
+ GRD Greece
+ GTQ Guatemala
+ GYD Guyana
+ HKD Hong Kong
+ HNL Honduras
+ HRK Croatia
+ HTG Haiti
+ HUF Hungary
+ IDR Indonesia
+ IEP Ireland (Eire)
+ ILS Israel
+ IMP Isle of Man
+ INR India
+ IQD Iraq
+ IRR Iran
+ ISK Iceland
+ ITL Italy
+ JEP Jersey
+ JMD Jamaica
+ JOD Jordan
+ JPY Japan
+ KES Kenya
+ KGS Kyrgyzstan
+ KHR Cambodia
+ KMF Comoros
+ KPW Korea
+ KWD Kuwait
+ KYD Cayman Islands
+ KZT Kazakstan
+ LAK Laos
+ LBP Lebanon
+ LKR Sri Lanka
+ LRD Liberia
+ LSL Lesotho
+ LTL Lithuania
+ LUF Luxembourg
+ LVL Latvia
+ LYD Libya
+ MAD Morocco
+ MDL Moldova
+ MGF Madagascar
+ MKD Macedonia
+ MMK Myanmar (Burma)
+ MNT Mongolia
+ MOP Macau
+ MRO Mauritania
+ MTL Malta
+ MUR Mauritius
+ MVR Maldives (Maldive Islands)
+ MWK Malawi
+ MXN Mexico
+ MYR Malaysia
+ MZM Mozambique
+ NAD Namibia
+ NGN Nigeria
+ NIO Nicaragua
+ NLG Netherlands (Holland)
+ NOK Norway
+ NPR Nepal
+ NZD New Zealand
+ OMR Oman
+ PAB Panama
+ PEN Peru
+ PGK Papua New Guinea
+ PHP Philippines
+ PKR Pakistan
+ PLN Poland
+ PTE Portugal
+ PYG Paraguay
+ QAR Qatar
+ ROL Romania
+ RUR Russia
+ RWF Rwanda
+ SAR Saudi Arabia
+ SBD Solomon Islands
+ SCR Seychelles
+ SDD Sudan
+ SEK Sweden
+ SGD Singapore
+ SHP Saint Helena
+ SIT Slovenia
+ SKK Slovakia
+ SLL Sierra Leone
+ SOS Somalia
+ SPL Seborga
+ SRG Suriname
+ STD São Tome and Principe
+ SVC El Salvador
+ SYP Syria
+ SZL Swaziland
+ THB Thailand
+ TJR Tajikistan
+ TMM Turkmenistan
+ TND Tunisia
+ TOP Tonga
+ TRL Turkey
+ TTD Trinidad and Tobago
+ TVD Tuvalu
+ TWD Taiwan
+ TZS Tanzania
+ UAH Ukraine
+ UGX Uganda
+ USD United States of America
+ UYU Uruguay
+ UZS Uzbekistan
+ VAL Vatican City
+ VEB Venezuela
+ VND Viet Nam
+ VUV Vanuatu
+ WST Samoa
+ XAF Communauté Financière Africaine
+ XAG Silver
+ XAU Gold
+ XCD East Caribbean
+ XDR International Monetary Fund
+ XPD Palladium
+ XPF Comptoirs Français du Pacifique
+ XPT Platinum
+ YER Yemen
+ YUM Yugoslavia
+ ZAR South Africa
+ ZMK Zambia
+ ZWD Zimbabwe
+
+ */
+
+ return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
+ }
+
+
+
+ public static function LanguageLookup($languagecode, $casesensitive=false) {
+
+ if (!$casesensitive) {
+ $languagecode = strtolower($languagecode);
+ }
+
+ // http://www.id3.org/id3v2.4.0-structure.txt
+ // [4. ID3v2 frame overview]
+ // The three byte language field, present in several frames, is used to
+ // describe the language of the frame's content, according to ISO-639-2
+ // [ISO-639-2]. The language should be represented in lower case. If the
+ // language is not known the string "XXX" should be used.
+
+
+ // ISO 639-2 - http://www.id3.org/iso639-2.html
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ XXX unknown
+ xxx unknown
+ aar Afar
+ abk Abkhazian
+ ace Achinese
+ ach Acoli
+ ada Adangme
+ afa Afro-Asiatic (Other)
+ afh Afrihili
+ afr Afrikaans
+ aka Akan
+ akk Akkadian
+ alb Albanian
+ ale Aleut
+ alg Algonquian Languages
+ amh Amharic
+ ang English, Old (ca. 450-1100)
+ apa Apache Languages
+ ara Arabic
+ arc Aramaic
+ arm Armenian
+ arn Araucanian
+ arp Arapaho
+ art Artificial (Other)
+ arw Arawak
+ asm Assamese
+ ath Athapascan Languages
+ ava Avaric
+ ave Avestan
+ awa Awadhi
+ aym Aymara
+ aze Azerbaijani
+ bad Banda
+ bai Bamileke Languages
+ bak Bashkir
+ bal Baluchi
+ bam Bambara
+ ban Balinese
+ baq Basque
+ bas Basa
+ bat Baltic (Other)
+ bej Beja
+ bel Byelorussian
+ bem Bemba
+ ben Bengali
+ ber Berber (Other)
+ bho Bhojpuri
+ bih Bihari
+ bik Bikol
+ bin Bini
+ bis Bislama
+ bla Siksika
+ bnt Bantu (Other)
+ bod Tibetan
+ bra Braj
+ bre Breton
+ bua Buriat
+ bug Buginese
+ bul Bulgarian
+ bur Burmese
+ cad Caddo
+ cai Central American Indian (Other)
+ car Carib
+ cat Catalan
+ cau Caucasian (Other)
+ ceb Cebuano
+ cel Celtic (Other)
+ ces Czech
+ cha Chamorro
+ chb Chibcha
+ che Chechen
+ chg Chagatai
+ chi Chinese
+ chm Mari
+ chn Chinook jargon
+ cho Choctaw
+ chr Cherokee
+ chu Church Slavic
+ chv Chuvash
+ chy Cheyenne
+ cop Coptic
+ cor Cornish
+ cos Corsican
+ cpe Creoles and Pidgins, English-based (Other)
+ cpf Creoles and Pidgins, French-based (Other)
+ cpp Creoles and Pidgins, Portuguese-based (Other)
+ cre Cree
+ crp Creoles and Pidgins (Other)
+ cus Cushitic (Other)
+ cym Welsh
+ cze Czech
+ dak Dakota
+ dan Danish
+ del Delaware
+ deu German
+ din Dinka
+ div Divehi
+ doi Dogri
+ dra Dravidian (Other)
+ dua Duala
+ dum Dutch, Middle (ca. 1050-1350)
+ dut Dutch
+ dyu Dyula
+ dzo Dzongkha
+ efi Efik
+ egy Egyptian (Ancient)
+ eka Ekajuk
+ ell Greek, Modern (1453-)
+ elx Elamite
+ eng English
+ enm English, Middle (ca. 1100-1500)
+ epo Esperanto
+ esk Eskimo (Other)
+ esl Spanish
+ est Estonian
+ eus Basque
+ ewe Ewe
+ ewo Ewondo
+ fan Fang
+ fao Faroese
+ fas Persian
+ fat Fanti
+ fij Fijian
+ fin Finnish
+ fiu Finno-Ugrian (Other)
+ fon Fon
+ fra French
+ fre French
+ frm French, Middle (ca. 1400-1600)
+ fro French, Old (842- ca. 1400)
+ fry Frisian
+ ful Fulah
+ gaa Ga
+ gae Gaelic (Scots)
+ gai Irish
+ gay Gayo
+ gdh Gaelic (Scots)
+ gem Germanic (Other)
+ geo Georgian
+ ger German
+ gez Geez
+ gil Gilbertese
+ glg Gallegan
+ gmh German, Middle High (ca. 1050-1500)
+ goh German, Old High (ca. 750-1050)
+ gon Gondi
+ got Gothic
+ grb Grebo
+ grc Greek, Ancient (to 1453)
+ gre Greek, Modern (1453-)
+ grn Guarani
+ guj Gujarati
+ hai Haida
+ hau Hausa
+ haw Hawaiian
+ heb Hebrew
+ her Herero
+ hil Hiligaynon
+ him Himachali
+ hin Hindi
+ hmo Hiri Motu
+ hun Hungarian
+ hup Hupa
+ hye Armenian
+ iba Iban
+ ibo Igbo
+ ice Icelandic
+ ijo Ijo
+ iku Inuktitut
+ ilo Iloko
+ ina Interlingua (International Auxiliary language Association)
+ inc Indic (Other)
+ ind Indonesian
+ ine Indo-European (Other)
+ ine Interlingue
+ ipk Inupiak
+ ira Iranian (Other)
+ iri Irish
+ iro Iroquoian uages
+ isl Icelandic
+ ita Italian
+ jav Javanese
+ jaw Javanese
+ jpn Japanese
+ jpr Judeo-Persian
+ jrb Judeo-Arabic
+ kaa Kara-Kalpak
+ kab Kabyle
+ kac Kachin
+ kal Greenlandic
+ kam Kamba
+ kan Kannada
+ kar Karen
+ kas Kashmiri
+ kat Georgian
+ kau Kanuri
+ kaw Kawi
+ kaz Kazakh
+ kha Khasi
+ khi Khoisan (Other)
+ khm Khmer
+ kho Khotanese
+ kik Kikuyu
+ kin Kinyarwanda
+ kir Kirghiz
+ kok Konkani
+ kom Komi
+ kon Kongo
+ kor Korean
+ kpe Kpelle
+ kro Kru
+ kru Kurukh
+ kua Kuanyama
+ kum Kumyk
+ kur Kurdish
+ kus Kusaie
+ kut Kutenai
+ lad Ladino
+ lah Lahnda
+ lam Lamba
+ lao Lao
+ lat Latin
+ lav Latvian
+ lez Lezghian
+ lin Lingala
+ lit Lithuanian
+ lol Mongo
+ loz Lozi
+ ltz Letzeburgesch
+ lub Luba-Katanga
+ lug Ganda
+ lui Luiseno
+ lun Lunda
+ luo Luo (Kenya and Tanzania)
+ mac Macedonian
+ mad Madurese
+ mag Magahi
+ mah Marshall
+ mai Maithili
+ mak Macedonian
+ mak Makasar
+ mal Malayalam
+ man Mandingo
+ mao Maori
+ map Austronesian (Other)
+ mar Marathi
+ mas Masai
+ max Manx
+ may Malay
+ men Mende
+ mga Irish, Middle (900 - 1200)
+ mic Micmac
+ min Minangkabau
+ mis Miscellaneous (Other)
+ mkh Mon-Kmer (Other)
+ mlg Malagasy
+ mlt Maltese
+ mni Manipuri
+ mno Manobo Languages
+ moh Mohawk
+ mol Moldavian
+ mon Mongolian
+ mos Mossi
+ mri Maori
+ msa Malay
+ mul Multiple Languages
+ mun Munda Languages
+ mus Creek
+ mwr Marwari
+ mya Burmese
+ myn Mayan Languages
+ nah Aztec
+ nai North American Indian (Other)
+ nau Nauru
+ nav Navajo
+ nbl Ndebele, South
+ nde Ndebele, North
+ ndo Ndongo
+ nep Nepali
+ new Newari
+ nic Niger-Kordofanian (Other)
+ niu Niuean
+ nla Dutch
+ nno Norwegian (Nynorsk)
+ non Norse, Old
+ nor Norwegian
+ nso Sotho, Northern
+ nub Nubian Languages
+ nya Nyanja
+ nym Nyamwezi
+ nyn Nyankole
+ nyo Nyoro
+ nzi Nzima
+ oci Langue d'Oc (post 1500)
+ oji Ojibwa
+ ori Oriya
+ orm Oromo
+ osa Osage
+ oss Ossetic
+ ota Turkish, Ottoman (1500 - 1928)
+ oto Otomian Languages
+ paa Papuan-Australian (Other)
+ pag Pangasinan
+ pal Pahlavi
+ pam Pampanga
+ pan Panjabi
+ pap Papiamento
+ pau Palauan
+ peo Persian, Old (ca 600 - 400 B.C.)
+ per Persian
+ phn Phoenician
+ pli Pali
+ pol Polish
+ pon Ponape
+ por Portuguese
+ pra Prakrit uages
+ pro Provencal, Old (to 1500)
+ pus Pushto
+ que Quechua
+ raj Rajasthani
+ rar Rarotongan
+ roa Romance (Other)
+ roh Rhaeto-Romance
+ rom Romany
+ ron Romanian
+ rum Romanian
+ run Rundi
+ rus Russian
+ sad Sandawe
+ sag Sango
+ sah Yakut
+ sai South American Indian (Other)
+ sal Salishan Languages
+ sam Samaritan Aramaic
+ san Sanskrit
+ sco Scots
+ scr Serbo-Croatian
+ sel Selkup
+ sem Semitic (Other)
+ sga Irish, Old (to 900)
+ shn Shan
+ sid Sidamo
+ sin Singhalese
+ sio Siouan Languages
+ sit Sino-Tibetan (Other)
+ sla Slavic (Other)
+ slk Slovak
+ slo Slovak
+ slv Slovenian
+ smi Sami Languages
+ smo Samoan
+ sna Shona
+ snd Sindhi
+ sog Sogdian
+ som Somali
+ son Songhai
+ sot Sotho, Southern
+ spa Spanish
+ sqi Albanian
+ srd Sardinian
+ srr Serer
+ ssa Nilo-Saharan (Other)
+ ssw Siswant
+ ssw Swazi
+ suk Sukuma
+ sun Sudanese
+ sus Susu
+ sux Sumerian
+ sve Swedish
+ swa Swahili
+ swe Swedish
+ syr Syriac
+ tah Tahitian
+ tam Tamil
+ tat Tatar
+ tel Telugu
+ tem Timne
+ ter Tereno
+ tgk Tajik
+ tgl Tagalog
+ tha Thai
+ tib Tibetan
+ tig Tigre
+ tir Tigrinya
+ tiv Tivi
+ tli Tlingit
+ tmh Tamashek
+ tog Tonga (Nyasa)
+ ton Tonga (Tonga Islands)
+ tru Truk
+ tsi Tsimshian
+ tsn Tswana
+ tso Tsonga
+ tuk Turkmen
+ tum Tumbuka
+ tur Turkish
+ tut Altaic (Other)
+ twi Twi
+ tyv Tuvinian
+ uga Ugaritic
+ uig Uighur
+ ukr Ukrainian
+ umb Umbundu
+ und Undetermined
+ urd Urdu
+ uzb Uzbek
+ vai Vai
+ ven Venda
+ vie Vietnamese
+ vol Volapük
+ vot Votic
+ wak Wakashan Languages
+ wal Walamo
+ war Waray
+ was Washo
+ wel Welsh
+ wen Sorbian Languages
+ wol Wolof
+ xho Xhosa
+ yao Yao
+ yap Yap
+ yid Yiddish
+ yor Yoruba
+ zap Zapotec
+ zen Zenaga
+ zha Zhuang
+ zho Chinese
+ zul Zulu
+ zun Zuni
+
+ */
+
+ return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
+ }
+
+
+ public static function ETCOEventLookup($index) {
+ if (($index >= 0x17) && ($index <= 0xDF)) {
+ return 'reserved for future use';
+ }
+ if (($index >= 0xE0) && ($index <= 0xEF)) {
+ return 'not predefined synch 0-F';
+ }
+ if (($index >= 0xF0) && ($index <= 0xFC)) {
+ return 'reserved for future use';
+ }
+
+ static $EventLookup = array(
+ 0x00 => 'padding (has no meaning)',
+ 0x01 => 'end of initial silence',
+ 0x02 => 'intro start',
+ 0x03 => 'main part start',
+ 0x04 => 'outro start',
+ 0x05 => 'outro end',
+ 0x06 => 'verse start',
+ 0x07 => 'refrain start',
+ 0x08 => 'interlude start',
+ 0x09 => 'theme start',
+ 0x0A => 'variation start',
+ 0x0B => 'key change',
+ 0x0C => 'time change',
+ 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
+ 0x0E => 'sustained noise',
+ 0x0F => 'sustained noise end',
+ 0x10 => 'intro end',
+ 0x11 => 'main part end',
+ 0x12 => 'verse end',
+ 0x13 => 'refrain end',
+ 0x14 => 'theme end',
+ 0x15 => 'profanity',
+ 0x16 => 'profanity end',
+ 0xFD => 'audio end (start of silence)',
+ 0xFE => 'audio file ends',
+ 0xFF => 'one more byte of events follows'
+ );
+
+ return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
+ }
+
+ public static function SYTLContentTypeLookup($index) {
+ static $SYTLContentTypeLookup = array(
+ 0x00 => 'other',
+ 0x01 => 'lyrics',
+ 0x02 => 'text transcription',
+ 0x03 => 'movement/part name', // (e.g. 'Adagio')
+ 0x04 => 'events', // (e.g. 'Don Quijote enters the stage')
+ 0x05 => 'chord', // (e.g. 'Bb F Fsus')
+ 0x06 => 'trivia/\'pop up\' information',
+ 0x07 => 'URLs to webpages',
+ 0x08 => 'URLs to images'
+ );
+
+ return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
+ }
+
+ public static function APICPictureTypeLookup($index, $returnarray=false) {
+ static $APICPictureTypeLookup = array(
+ 0x00 => 'Other',
+ 0x01 => '32x32 pixels \'file icon\' (PNG only)',
+ 0x02 => 'Other file icon',
+ 0x03 => 'Cover (front)',
+ 0x04 => 'Cover (back)',
+ 0x05 => 'Leaflet page',
+ 0x06 => 'Media (e.g. label side of CD)',
+ 0x07 => 'Lead artist/lead performer/soloist',
+ 0x08 => 'Artist/performer',
+ 0x09 => 'Conductor',
+ 0x0A => 'Band/Orchestra',
+ 0x0B => 'Composer',
+ 0x0C => 'Lyricist/text writer',
+ 0x0D => 'Recording Location',
+ 0x0E => 'During recording',
+ 0x0F => 'During performance',
+ 0x10 => 'Movie/video screen capture',
+ 0x11 => 'A bright coloured fish',
+ 0x12 => 'Illustration',
+ 0x13 => 'Band/artist logotype',
+ 0x14 => 'Publisher/Studio logotype'
+ );
+ if ($returnarray) {
+ return $APICPictureTypeLookup;
+ }
+ return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
+ }
+
+ public static function COMRReceivedAsLookup($index) {
+ static $COMRReceivedAsLookup = array(
+ 0x00 => 'Other',
+ 0x01 => 'Standard CD album with other songs',
+ 0x02 => 'Compressed audio on CD',
+ 0x03 => 'File over the Internet',
+ 0x04 => 'Stream over the Internet',
+ 0x05 => 'As note sheets',
+ 0x06 => 'As note sheets in a book with other sheets',
+ 0x07 => 'Music on other media',
+ 0x08 => 'Non-musical merchandise'
+ );
+
+ return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
+ }
+
+ public static function RVA2ChannelTypeLookup($index) {
+ static $RVA2ChannelTypeLookup = array(
+ 0x00 => 'Other',
+ 0x01 => 'Master volume',
+ 0x02 => 'Front right',
+ 0x03 => 'Front left',
+ 0x04 => 'Back right',
+ 0x05 => 'Back left',
+ 0x06 => 'Front centre',
+ 0x07 => 'Back centre',
+ 0x08 => 'Subwoofer'
+ );
+
+ return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
+ }
+
+ public static function FrameNameLongLookup($framename) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ AENC Audio encryption
+ APIC Attached picture
+ ASPI Audio seek point index
+ BUF Recommended buffer size
+ CNT Play counter
+ COM Comments
+ COMM Comments
+ COMR Commercial frame
+ CRA Audio encryption
+ CRM Encrypted meta frame
+ ENCR Encryption method registration
+ EQU Equalisation
+ EQU2 Equalisation (2)
+ EQUA Equalisation
+ ETC Event timing codes
+ ETCO Event timing codes
+ GEO General encapsulated object
+ GEOB General encapsulated object
+ GRID Group identification registration
+ IPL Involved people list
+ IPLS Involved people list
+ LINK Linked information
+ LNK Linked information
+ MCDI Music CD identifier
+ MCI Music CD Identifier
+ MLL MPEG location lookup table
+ MLLT MPEG location lookup table
+ OWNE Ownership frame
+ PCNT Play counter
+ PIC Attached picture
+ POP Popularimeter
+ POPM Popularimeter
+ POSS Position synchronisation frame
+ PRIV Private frame
+ RBUF Recommended buffer size
+ REV Reverb
+ RVA Relative volume adjustment
+ RVA2 Relative volume adjustment (2)
+ RVAD Relative volume adjustment
+ RVRB Reverb
+ SEEK Seek frame
+ SIGN Signature frame
+ SLT Synchronised lyric/text
+ STC Synced tempo codes
+ SYLT Synchronised lyric/text
+ SYTC Synchronised tempo codes
+ TAL Album/Movie/Show title
+ TALB Album/Movie/Show title
+ TBP BPM (Beats Per Minute)
+ TBPM BPM (beats per minute)
+ TCM Composer
+ TCMP Part of a compilation
+ TCO Content type
+ TCOM Composer
+ TCON Content type
+ TCOP Copyright message
+ TCP Part of a compilation
+ TCR Copyright message
+ TDA Date
+ TDAT Date
+ TDEN Encoding time
+ TDLY Playlist delay
+ TDOR Original release time
+ TDRC Recording time
+ TDRL Release time
+ TDTG Tagging time
+ TDY Playlist delay
+ TEN Encoded by
+ TENC Encoded by
+ TEXT Lyricist/Text writer
+ TFLT File type
+ TFT File type
+ TIM Time
+ TIME Time
+ TIPL Involved people list
+ TIT1 Content group description
+ TIT2 Title/songname/content description
+ TIT3 Subtitle/Description refinement
+ TKE Initial key
+ TKEY Initial key
+ TLA Language(s)
+ TLAN Language(s)
+ TLE Length
+ TLEN Length
+ TMCL Musician credits list
+ TMED Media type
+ TMOO Mood
+ TMT Media type
+ TOA Original artist(s)/performer(s)
+ TOAL Original album/movie/show title
+ TOF Original filename
+ TOFN Original filename
+ TOL Original Lyricist(s)/text writer(s)
+ TOLY Original lyricist(s)/text writer(s)
+ TOPE Original artist(s)/performer(s)
+ TOR Original release year
+ TORY Original release year
+ TOT Original album/Movie/Show title
+ TOWN File owner/licensee
+ TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
+ TP2 Band/Orchestra/Accompaniment
+ TP3 Conductor/Performer refinement
+ TP4 Interpreted, remixed, or otherwise modified by
+ TPA Part of a set
+ TPB Publisher
+ TPE1 Lead performer(s)/Soloist(s)
+ TPE2 Band/orchestra/accompaniment
+ TPE3 Conductor/performer refinement
+ TPE4 Interpreted, remixed, or otherwise modified by
+ TPOS Part of a set
+ TPRO Produced notice
+ TPUB Publisher
+ TRC ISRC (International Standard Recording Code)
+ TRCK Track number/Position in set
+ TRD Recording dates
+ TRDA Recording dates
+ TRK Track number/Position in set
+ TRSN Internet radio station name
+ TRSO Internet radio station owner
+ TS2 Album-Artist sort order
+ TSA Album sort order
+ TSC Composer sort order
+ TSI Size
+ TSIZ Size
+ TSO2 Album-Artist sort order
+ TSOA Album sort order
+ TSOC Composer sort order
+ TSOP Performer sort order
+ TSOT Title sort order
+ TSP Performer sort order
+ TSRC ISRC (international standard recording code)
+ TSS Software/hardware and settings used for encoding
+ TSSE Software/Hardware and settings used for encoding
+ TSST Set subtitle
+ TST Title sort order
+ TT1 Content group description
+ TT2 Title/Songname/Content description
+ TT3 Subtitle/Description refinement
+ TXT Lyricist/text writer
+ TXX User defined text information frame
+ TXXX User defined text information frame
+ TYE Year
+ TYER Year
+ UFI Unique file identifier
+ UFID Unique file identifier
+ ULT Unsychronised lyric/text transcription
+ USER Terms of use
+ USLT Unsynchronised lyric/text transcription
+ WAF Official audio file webpage
+ WAR Official artist/performer webpage
+ WAS Official audio source webpage
+ WCM Commercial information
+ WCOM Commercial information
+ WCOP Copyright/Legal information
+ WCP Copyright/Legal information
+ WOAF Official audio file webpage
+ WOAR Official artist/performer webpage
+ WOAS Official audio source webpage
+ WORS Official Internet radio station homepage
+ WPAY Payment
+ WPB Publishers official webpage
+ WPUB Publishers official webpage
+ WXX User defined URL link frame
+ WXXX User defined URL link frame
+ TFEA Featured Artist
+ TSTU Recording Studio
+ rgad Replay Gain Adjustment
+
+ */
+
+ return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
+
+ // Last three:
+ // from Helium2 [www.helium2.com]
+ // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
+ }
+
+
+ public static function FrameNameShortLookup($framename) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ AENC audio_encryption
+ APIC attached_picture
+ ASPI audio_seek_point_index
+ BUF recommended_buffer_size
+ CNT play_counter
+ COM comment
+ COMM comment
+ COMR commercial_frame
+ CRA audio_encryption
+ CRM encrypted_meta_frame
+ ENCR encryption_method_registration
+ EQU equalisation
+ EQU2 equalisation
+ EQUA equalisation
+ ETC event_timing_codes
+ ETCO event_timing_codes
+ GEO general_encapsulated_object
+ GEOB general_encapsulated_object
+ GRID group_identification_registration
+ IPL involved_people_list
+ IPLS involved_people_list
+ LINK linked_information
+ LNK linked_information
+ MCDI music_cd_identifier
+ MCI music_cd_identifier
+ MLL mpeg_location_lookup_table
+ MLLT mpeg_location_lookup_table
+ OWNE ownership_frame
+ PCNT play_counter
+ PIC attached_picture
+ POP popularimeter
+ POPM popularimeter
+ POSS position_synchronisation_frame
+ PRIV private_frame
+ RBUF recommended_buffer_size
+ REV reverb
+ RVA relative_volume_adjustment
+ RVA2 relative_volume_adjustment
+ RVAD relative_volume_adjustment
+ RVRB reverb
+ SEEK seek_frame
+ SIGN signature_frame
+ SLT synchronised_lyric
+ STC synced_tempo_codes
+ SYLT synchronised_lyric
+ SYTC synchronised_tempo_codes
+ TAL album
+ TALB album
+ TBP bpm
+ TBPM bpm
+ TCM composer
+ TCMP part_of_a_compilation
+ TCO genre
+ TCOM composer
+ TCON genre
+ TCOP copyright_message
+ TCP part_of_a_compilation
+ TCR copyright_message
+ TDA date
+ TDAT date
+ TDEN encoding_time
+ TDLY playlist_delay
+ TDOR original_release_time
+ TDRC recording_time
+ TDRL release_time
+ TDTG tagging_time
+ TDY playlist_delay
+ TEN encoded_by
+ TENC encoded_by
+ TEXT lyricist
+ TFLT file_type
+ TFT file_type
+ TIM time
+ TIME time
+ TIPL involved_people_list
+ TIT1 content_group_description
+ TIT2 title
+ TIT3 subtitle
+ TKE initial_key
+ TKEY initial_key
+ TLA language
+ TLAN language
+ TLE length
+ TLEN length
+ TMCL musician_credits_list
+ TMED media_type
+ TMOO mood
+ TMT media_type
+ TOA original_artist
+ TOAL original_album
+ TOF original_filename
+ TOFN original_filename
+ TOL original_lyricist
+ TOLY original_lyricist
+ TOPE original_artist
+ TOR original_year
+ TORY original_year
+ TOT original_album
+ TOWN file_owner
+ TP1 artist
+ TP2 band
+ TP3 conductor
+ TP4 remixer
+ TPA part_of_a_set
+ TPB publisher
+ TPE1 artist
+ TPE2 band
+ TPE3 conductor
+ TPE4 remixer
+ TPOS part_of_a_set
+ TPRO produced_notice
+ TPUB publisher
+ TRC isrc
+ TRCK track_number
+ TRD recording_dates
+ TRDA recording_dates
+ TRK track_number
+ TRSN internet_radio_station_name
+ TRSO internet_radio_station_owner
+ TS2 album_artist_sort_order
+ TSA album_sort_order
+ TSC composer_sort_order
+ TSI size
+ TSIZ size
+ TSO2 album_artist_sort_order
+ TSOA album_sort_order
+ TSOC composer_sort_order
+ TSOP performer_sort_order
+ TSOT title_sort_order
+ TSP performer_sort_order
+ TSRC isrc
+ TSS encoder_settings
+ TSSE encoder_settings
+ TSST set_subtitle
+ TST title_sort_order
+ TT1 content_group_description
+ TT2 title
+ TT3 subtitle
+ TXT lyricist
+ TXX text
+ TXXX text
+ TYE year
+ TYER year
+ UFI unique_file_identifier
+ UFID unique_file_identifier
+ ULT unsychronised_lyric
+ USER terms_of_use
+ USLT unsynchronised_lyric
+ WAF url_file
+ WAR url_artist
+ WAS url_source
+ WCM commercial_information
+ WCOM commercial_information
+ WCOP copyright
+ WCP copyright
+ WOAF url_file
+ WOAR url_artist
+ WOAS url_source
+ WORS url_station
+ WPAY url_payment
+ WPB url_publisher
+ WPUB url_publisher
+ WXX url_user
+ WXXX url_user
+ TFEA featured_artist
+ TSTU recording_studio
+ rgad replay_gain_adjustment
+
+ */
+
+ return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
+ }
+
+ public static function TextEncodingTerminatorLookup($encoding) {
+ // http://www.id3.org/id3v2.4.0-structure.txt
+ // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
+ static $TextEncodingTerminatorLookup = array(
+ 0 => "\x00", // $00 ISO-8859-1. Terminated with $00.
+ 1 => "\x00\x00", // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
+ 2 => "\x00\x00", // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
+ 3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00.
+ 255 => "\x00\x00"
+ );
+ return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : '');
+ }
+
+ public static function TextEncodingNameLookup($encoding) {
+ // http://www.id3.org/id3v2.4.0-structure.txt
+ // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
+ static $TextEncodingNameLookup = array(
+ 0 => 'ISO-8859-1', // $00 ISO-8859-1. Terminated with $00.
+ 1 => 'UTF-16', // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
+ 2 => 'UTF-16BE', // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
+ 3 => 'UTF-8', // $03 UTF-8 encoded Unicode. Terminated with $00.
+ 255 => 'UTF-16BE'
+ );
+ return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
+ }
+
+ public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
+ switch ($id3v2majorversion) {
+ case 2:
+ return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
+ break;
+
+ case 3:
+ case 4:
+ return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
+ break;
+ }
+ return false;
+ }
+
+ public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
+ for ($i = 0; $i < strlen($numberstring); $i++) {
+ if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
+ if (($numberstring{$i} == '.') && $allowdecimal) {
+ // allowed
+ } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
+ // allowed
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static function IsValidDateStampString($datestamp) {
+ if (strlen($datestamp) != 8) {
+ return false;
+ }
+ if (!self::IsANumber($datestamp, false)) {
+ return false;
+ }
+ $year = substr($datestamp, 0, 4);
+ $month = substr($datestamp, 4, 2);
+ $day = substr($datestamp, 6, 2);
+ if (($year == 0) || ($month == 0) || ($day == 0)) {
+ return false;
+ }
+ if ($month > 12) {
+ return false;
+ }
+ if ($day > 31) {
+ return false;
+ }
+ if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
+ return false;
+ }
+ if (($day > 29) && ($month == 2)) {
+ return false;
+ }
+ return true;
+ }
+
+ public static function ID3v2HeaderLength($majorversion) {
+ return (($majorversion == 2) ? 6 : 10);
+ }
+
+}
+
diff --git a/src/wp-includes/ID3/module.tag.lyrics3.php b/src/wp-includes/ID3/module.tag.lyrics3.php
new file mode 100644
index 0000000000..108d7aeeab
--- /dev/null
+++ b/src/wp-includes/ID3/module.tag.lyrics3.php
@@ -0,0 +1,294 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+/// //
+// module.tag.lyrics3.php //
+// module for analyzing Lyrics3 tags //
+// dependencies: module.tag.apetag.php (optional) //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_lyrics3 extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ // http://www.volweb.cz/str/tags.htm
+
+ if (!getid3_lib::intValueSupported($info['filesize'])) {
+ $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
+ return false;
+ }
+
+ fseek($this->getid3->fp, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size]
+ $lyrics3_id3v1 = fread($this->getid3->fp, 128 + 9 + 6);
+ $lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size
+ $lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200
+ $id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1
+
+ if ($lyrics3end == 'LYRICSEND') {
+ // Lyrics3v1, ID3v1, no APE
+
+ $lyrics3size = 5100;
+ $lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
+ $lyrics3version = 1;
+
+ } elseif ($lyrics3end == 'LYRICS200') {
+ // Lyrics3v2, ID3v1, no APE
+
+ // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
+ $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200');
+ $lyrics3offset = $info['filesize'] - 128 - $lyrics3size;
+ $lyrics3version = 2;
+
+ } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) {
+ // Lyrics3v1, no ID3v1, no APE
+
+ $lyrics3size = 5100;
+ $lyrics3offset = $info['filesize'] - $lyrics3size;
+ $lyrics3version = 1;
+ $lyrics3offset = $info['filesize'] - $lyrics3size;
+
+ } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) {
+
+ // Lyrics3v2, no ID3v1, no APE
+
+ $lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
+ $lyrics3offset = $info['filesize'] - $lyrics3size;
+ $lyrics3version = 2;
+
+ } else {
+
+ if (isset($info['ape']['tag_offset_start']) && ($info['ape']['tag_offset_start'] > 15)) {
+
+ fseek($this->getid3->fp, $info['ape']['tag_offset_start'] - 15, SEEK_SET);
+ $lyrics3lsz = fread($this->getid3->fp, 6);
+ $lyrics3end = fread($this->getid3->fp, 9);
+
+ if ($lyrics3end == 'LYRICSEND') {
+ // Lyrics3v1, APE, maybe ID3v1
+
+ $lyrics3size = 5100;
+ $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
+ $info['avdataend'] = $lyrics3offset;
+ $lyrics3version = 1;
+ $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
+
+ } elseif ($lyrics3end == 'LYRICS200') {
+ // Lyrics3v2, APE, maybe ID3v1
+
+ $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200'
+ $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size;
+ $lyrics3version = 2;
+ $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability';
+
+ }
+
+ }
+
+ }
+
+ if (isset($lyrics3offset)) {
+ $info['avdataend'] = $lyrics3offset;
+ $this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size);
+
+ if (!isset($info['ape'])) {
+ $GETID3_ERRORARRAY = &$info['warning'];
+ if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, false)) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_apetag = new getid3_apetag($getid3_temp);
+ $getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start'];
+ $getid3_apetag->Analyze();
+ if (!empty($getid3_temp->info['ape'])) {
+ $info['ape'] = $getid3_temp->info['ape'];
+ }
+ if (!empty($getid3_temp->info['replay_gain'])) {
+ $info['replay_gain'] = $getid3_temp->info['replay_gain'];
+ }
+ unset($getid3_temp, $getid3_apetag);
+ }
+ }
+
+ }
+
+ return true;
+ }
+
+ public function getLyrics3Data($endoffset, $version, $length) {
+ // http://www.volweb.cz/str/tags.htm
+
+ $info = &$this->getid3->info;
+
+ if (!getid3_lib::intValueSupported($endoffset)) {
+ $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
+ return false;
+ }
+
+ fseek($this->getid3->fp, $endoffset, SEEK_SET);
+ if ($length <= 0) {
+ return false;
+ }
+ $rawdata = fread($this->getid3->fp, $length);
+
+ $ParsedLyrics3['raw']['lyrics3version'] = $version;
+ $ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
+ $ParsedLyrics3['tag_offset_start'] = $endoffset;
+ $ParsedLyrics3['tag_offset_end'] = $endoffset + $length - 1;
+
+ if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') {
+ if (strpos($rawdata, 'LYRICSBEGIN') !== false) {
+
+ $info['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version;
+ $info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN');
+ $rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN'));
+ $length = strlen($rawdata);
+ $ParsedLyrics3['tag_offset_start'] = $info['avdataend'];
+ $ParsedLyrics3['raw']['lyrics3tagsize'] = $length;
+
+ } else {
+
+ $info['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead';
+ return false;
+
+ }
+
+ }
+
+ switch ($version) {
+
+ case 1:
+ if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') {
+ $ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9));
+ $this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
+ } else {
+ $info['error'][] = '"LYRICSEND" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
+ return false;
+ }
+ break;
+
+ case 2:
+ if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') {
+ $ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ
+ $rawdata = $ParsedLyrics3['raw']['unparsed'];
+ while (strlen($rawdata) > 0) {
+ $fieldname = substr($rawdata, 0, 3);
+ $fieldsize = (int) substr($rawdata, 3, 5);
+ $ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize);
+ $rawdata = substr($rawdata, 3 + 5 + $fieldsize);
+ }
+
+ if (isset($ParsedLyrics3['raw']['IND'])) {
+ $i = 0;
+ $flagnames = array('lyrics', 'timestamps', 'inhibitrandom');
+ foreach ($flagnames as $flagname) {
+ if (strlen($ParsedLyrics3['raw']['IND']) > $i++) {
+ $ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1));
+ }
+ }
+ }
+
+ $fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author');
+ foreach ($fieldnametranslation as $key => $value) {
+ if (isset($ParsedLyrics3['raw'][$key])) {
+ $ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]);
+ }
+ }
+
+ if (isset($ParsedLyrics3['raw']['IMG'])) {
+ $imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']);
+ foreach ($imagestrings as $key => $imagestring) {
+ if (strpos($imagestring, '||') !== false) {
+ $imagearray = explode('||', $imagestring);
+ $ParsedLyrics3['images'][$key]['filename'] = (isset($imagearray[0]) ? $imagearray[0] : '');
+ $ParsedLyrics3['images'][$key]['description'] = (isset($imagearray[1]) ? $imagearray[1] : '');
+ $ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(isset($imagearray[2]) ? $imagearray[2] : '');
+ }
+ }
+ }
+ if (isset($ParsedLyrics3['raw']['LYR'])) {
+ $this->Lyrics3LyricsTimestampParse($ParsedLyrics3);
+ }
+ } else {
+ $info['error'][] = '"LYRICS200" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead';
+ return false;
+ }
+ break;
+
+ default:
+ $info['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)';
+ return false;
+ break;
+ }
+
+
+ if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end'])) {
+ $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data';
+ unset($info['id3v1']);
+ foreach ($info['warning'] as $key => $value) {
+ if ($value == 'Some ID3v1 fields do not use NULL characters for padding') {
+ unset($info['warning'][$key]);
+ sort($info['warning']);
+ break;
+ }
+ }
+ }
+
+ $info['lyrics3'] = $ParsedLyrics3;
+
+ return true;
+ }
+
+ public function Lyrics3Timestamp2Seconds($rawtimestamp) {
+ if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) {
+ return (int) (($regs[1] * 60) + $regs[2]);
+ }
+ return false;
+ }
+
+ public function Lyrics3LyricsTimestampParse(&$Lyrics3data) {
+ $lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']);
+ foreach ($lyricsarray as $key => $lyricline) {
+ $regs = array();
+ unset($thislinetimestamps);
+ while (preg_match('#^(\\[[0-9]{2}:[0-9]{2}\\])#', $lyricline, $regs)) {
+ $thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]);
+ $lyricline = str_replace($regs[0], '', $lyricline);
+ }
+ $notimestamplyricsarray[$key] = $lyricline;
+ if (isset($thislinetimestamps) && is_array($thislinetimestamps)) {
+ sort($thislinetimestamps);
+ foreach ($thislinetimestamps as $timestampkey => $timestamp) {
+ if (isset($Lyrics3data['synchedlyrics'][$timestamp])) {
+ // timestamps only have a 1-second resolution, it's possible that multiple lines
+ // could have the same timestamp, if so, append
+ $Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline;
+ } else {
+ $Lyrics3data['synchedlyrics'][$timestamp] = $lyricline;
+ }
+ }
+ }
+ }
+ $Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray);
+ if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) {
+ ksort($Lyrics3data['synchedlyrics']);
+ }
+ return true;
+ }
+
+ public function IntString2Bool($char) {
+ if ($char == '1') {
+ return true;
+ } elseif ($char == '0') {
+ return false;
+ }
+ return null;
+ }
+}
diff --git a/src/wp-includes/ID3/readme.txt b/src/wp-includes/ID3/readme.txt
new file mode 100644
index 0000000000..337e84f35e
--- /dev/null
+++ b/src/wp-includes/ID3/readme.txt
@@ -0,0 +1,603 @@
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+
+*****************************************************************
+*****************************************************************
+
+ getID3() is released under multiple licenses. You may choose
+ from the following licenses, and use getID3 according to the
+ terms of the license most suitable to your project.
+
+GNU GPL: https://gnu.org/licenses/gpl.html (v3)
+ https://gnu.org/licenses/old-licenses/gpl-2.0.html (v2)
+ https://gnu.org/licenses/old-licenses/gpl-1.0.html (v1)
+
+GNU LGPL: https://gnu.org/licenses/lgpl.html (v3)
+
+Mozilla MPL: http://www.mozilla.org/MPL/2.0/ (v2)
+
+getID3 Commercial License: http://getid3.org/#gCL (payment required)
+
+*****************************************************************
+*****************************************************************
+Copies of each of the above licenses are included in the 'licenses'
+directory of the getID3 distribution.
+
+
+ +---------------------------------------------+
+ | If you want to donate, there is a link on |
+ | http://www.getid3.org for PayPal donations. |
+ +---------------------------------------------+
+
+
+Quick Start
+===========================================================================
+
+Q: How can I check that getID3() works on my server/files?
+A: Unzip getID3() to a directory, then access /demos/demo.browse.php
+
+
+
+Support
+===========================================================================
+
+Q: I have a question, or I found a bug. What do I do?
+A: The preferred method of support requests and/or bug reports is the
+ forum at http://support.getid3.org/
+
+
+
+Sourceforge Notification
+===========================================================================
+
+It's highly recommended that you sign up for notification from
+Sourceforge for when new versions are released. Please visit:
+http://sourceforge.net/project/showfiles.php?group_id=55859
+and click the little "monitor package" icon/link. If you're
+previously signed up for the mailing list, be aware that it has
+been discontinued, only the automated Sourceforge notification
+will be used from now on.
+
+
+
+What does getID3() do?
+===========================================================================
+
+Reads & parses (to varying degrees):
+# tags:
+ * APE (v1 and v2)
+ * ID3v1 (& ID3v1.1)
+ * ID3v2 (v2.4, v2.3, v2.2)
+ * Lyrics3 (v1 & v2)
+
+# audio-lossy:
+ * MP3/MP2/MP1
+ * MPC / Musepack
+ * Ogg (Vorbis, OggFLAC, Speex)
+ * AAC / MP4
+ * AC3
+ * DTS
+ * RealAudio
+ * Speex
+ * DSS
+ * VQF
+
+# audio-lossless:
+ * AIFF
+ * AU
+ * Bonk
+ * CD-audio (*.cda)
+ * FLAC
+ * LA (Lossless Audio)
+ * LiteWave
+ * LPAC
+ * MIDI
+ * Monkey's Audio
+ * OptimFROG
+ * RKAU
+ * Shorten
+ * TTA
+ * VOC
+ * WAV (RIFF)
+ * WavPack
+
+# audio-video:
+ * ASF: ASF, Windows Media Audio (WMA), Windows Media Video (WMV)
+ * AVI (RIFF)
+ * Flash
+ * Matroska (MKV)
+ * MPEG-1 / MPEG-2
+ * NSV (Nullsoft Streaming Video)
+ * Quicktime (including MP4)
+ * RealVideo
+
+# still image:
+ * BMP
+ * GIF
+ * JPEG
+ * PNG
+ * TIFF
+ * SWF (Flash)
+ * PhotoCD
+
+# data:
+ * ISO-9660 CD-ROM image (directory structure)
+ * SZIP (limited support)
+ * ZIP (directory structure)
+ * TAR
+ * CUE
+
+
+Writes:
+ * ID3v1 (& ID3v1.1)
+ * ID3v2 (v2.3 & v2.4)
+ * VorbisComment on OggVorbis
+ * VorbisComment on FLAC (not OggFLAC)
+ * APE v2
+ * Lyrics3 (delete only)
+
+
+
+Requirements
+===========================================================================
+
+* PHP 4.2.0 up to 5.2.x for getID3() 1.7.x (and earlier)
+* PHP 5.0.5 (or higher) for getID3() 1.8.x (and up)
+* PHP 5.0.5 (or higher) for getID3() 2.0.x (and up)
+* at least 4MB memory for PHP. 8MB or more is highly recommended.
+ 12MB is required with all modules loaded.
+
+
+
+Usage
+===========================================================================
+
+See /demos/demo.basic.php for a very basic use of getID3() with no
+fancy output, just scanning one file.
+
+See structure.txt for the returned data structure.
+
+*> For an example of a complete directory-browsing, <*
+*> file-scanning implementation of getID3(), please run <*
+*> /demos/demo.browse.php <*
+
+See /demos/demo.mysql.php for a sample recursive scanning code that
+scans every file in a given directory, and all sub-directories, stores
+the results in a database and allows various analysis / maintenance
+operations
+
+To analyze remote files over HTTP or FTP you need to copy the file
+locally first before running getID3(). Your code would look something
+like this:
+
+// Copy remote file locally to scan with getID3()
+$remotefilename = 'http://www.example.com/filename.mp3';
+if ($fp_remote = fopen($remotefilename, 'rb')) {
+ $localtempfilename = tempnam('/tmp', 'getID3');
+ if ($fp_local = fopen($localtempfilename, 'wb')) {
+ while ($buffer = fread($fp_remote, 8192)) {
+ fwrite($fp_local, $buffer);
+ }
+ fclose($fp_local);
+
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+
+ $ThisFileInfo = $getID3->analyze($filename);
+
+ // Delete temporary file
+ unlink($localtempfilename);
+ }
+ fclose($fp_remote);
+}
+
+
+See /demos/demo.write.php for how to write tags.
+
+
+
+What does the returned data structure look like?
+===========================================================================
+
+See structure.txt
+
+It is recommended that you look at the output of
+/demos/demo.browse.php scanning the file(s) you're interested in to
+confirm what data is actually returned for any particular filetype in
+general, and your files in particular, as the actual data returned
+may vary considerably depending on what information is available in
+the file itself.
+
+
+
+Notes
+===========================================================================
+
+getID3() 1.x:
+If the format parser encounters a critical problem, it will return
+something in $fileinfo['error'], describing the encountered error. If
+a less critical error or notice is generated it will appear in
+$fileinfo['warning']. Both keys may contain more than one warning or
+error. If something is returned in ['error'] then the file was not
+correctly parsed and returned data may or may not be correct and/or
+complete. If something is returned in ['warning'] (and not ['error'])
+then the data that is returned is OK - usually getID3() is reporting
+errors in the file that have been worked around due to known bugs in
+other programs. Some warnings may indicate that the data that is
+returned is OK but that some data could not be extracted due to
+errors in the file.
+
+getID3() 2.x:
+See above except errors are thrown (so you will only get one error).
+
+
+
+Disclaimer
+===========================================================================
+
+getID3() has been tested on many systems, on many types of files,
+under many operating systems, and is generally believe to be stable
+and safe. That being said, there is still the chance there is an
+undiscovered and/or unfixed bug that may potentially corrupt your
+file, especially within the writing functions. By using getID3() you
+agree that it's not my fault if any of your files are corrupted.
+In fact, I'm not liable for anything :)
+
+
+
+License
+===========================================================================
+
+GNU General Public License - see license.txt
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to:
+Free Software Foundation, Inc.
+59 Temple Place - Suite 330
+Boston, MA 02111-1307, USA.
+
+FAQ:
+Q: Can I use getID3() in my program? Do I need a commercial license?
+A: You're generally free to use getID3 however you see fit. The only
+ case in which you would require a commercial license is if you're
+ selling your closed-source program that integrates getID3. If you
+ sell your program including a copy of getID3, that's fine as long
+ as you include a copy of the sourcecode when you sell it. Or you
+ can distribute your code without getID3 and say "download it from
+ getid3.sourceforge.net"
+
+
+
+Why is it called "getID3()" if it does so much more than just that?
+===========================================================================
+
+v0.1 did in fact just do that. I don't have a copy of code that old, but I
+could essentially write it today with a one-line function:
+ function getID3($filename) { return unpack('a3TAG/a30title/a30artist/a30album/a4year/a28comment/c1track/c1genreid', substr(file_get_contents($filename), -128)); }
+
+
+Future Plans
+===========================================================================
+http://www.getid3.org/phpBB3/viewforum.php?f=7
+
+* Better support for MP4 container format
+* Scan for appended ID3v2 tag at end of file per ID3v2.4 specs (Section 5.0)
+* Support for JPEG-2000 (http://www.morgan-multimedia.com/jpeg2000_overview.htm)
+* Support for MOD (mod/stm/s3m/it/xm/mtm/ult/669)
+* Support for ACE (thanks Vince)
+* Support for Ogg other than Vorbis, Speex and OggFlac (ie. Ogg+Xvid)
+* Ability to create Xing/LAME VBR header for VBR MP3s that are missing VBR header
+* Ability to "clean" ID3v2 padding (replace invalid padding with valid padding)
+* Warn if MP3s change version mid-stream (in full-scan mode)
+* check for corrupt/broken mid-file MP3 streams in histogram scan
+* Support for lossless-compression formats
+ (http://www.firstpr.com.au/audiocomp/lossless/#Links)
+ (http://compression.ca/act-sound.html)
+ (http://web.inter.nl.net/users/hvdh/lossless/lossless.htm)
+* Support for RIFF-INFO chunks
+ * http://lotto.st-andrews.ac.uk/~njh/tag_interchange.html
+ (thanks Nick Humfrey <njh@surgeradio*co*uk>)
+ * http://abcavi.narod.ru/sof/abcavi/infotags.htm
+ (thanks Kibi)
+* Better support for Bink video
+* http://www.hr/josip/DSP/AudioFile2.html
+* http://www.pcisys.net/~melanson/codecs/
+* Detect mp3PRO
+* Support for PSD
+* Support for JPC
+* Support for JP2
+* Support for JPX
+* Support for JB2
+* Support for IFF
+* Support for ICO
+* Support for ANI
+* Support for EXE (comments, author, etc) (thanks p*quaedackers@planet*nl)
+* Support for DVD-IFO (region, subtitles, aspect ratio, etc)
+ (thanks p*quaedackers@planet*nl)
+* More complete support for SWF - parsing encapsulated MP3 and/or JPEG content
+ (thanks n8n8@yahoo*com)
+* Support for a2b
+* Optional scan-through-frames for AVI verification
+ (thanks rockcohen@massive-interactive*nl)
+* Support for TTF (thanks info@butterflyx*com)
+* Support for DSS (http://www.getid3.org/phpBB3/viewtopic.php?t=171)
+* Support for SMAF (http://smaf-yamaha.com/what/demo.html)
+ http://www.getid3.org/phpBB3/viewtopic.php?t=182
+* Support for AMR (http://www.getid3.org/phpBB3/viewtopic.php?t=195)
+* Support for 3gpp (http://www.getid3.org/phpBB3/viewtopic.php?t=195)
+* Support for ID4 (http://www.wackysoft.cjb.net grizlyY2K@hotmail*com)
+* Parse XML data returned in Ogg comments
+* Parse XML data from Quicktime SMIL metafiles (klausrath@mac*com)
+* ID3v2 genre string creator function
+* More complete parsing of JPG
+* Support for all old-style ASF packets
+* ASF/WMA/WMV tag writing
+* Parse declared T??? ID3v2 text information frames, where appropriate
+ (thanks Christian Fritz for the idea)
+* Recognize encoder:
+ http://www.guerillasoft.com/EncSpot2/index.html
+ http://ff123.net/identify.html
+ http://www.hydrogenaudio.org/?act=ST&f=16&t=9414
+ http://www.hydrogenaudio.org/?showtopic=11785
+* Support for other OS/2 bitmap structures: Bitmap Array('BA'),
+ Color Icon('CI'), Color Pointer('CP'), Icon('IC'), Pointer ('PT')
+ http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
+* Support for WavPack RAW mode
+* ASF/WMA/WMV data packet parsing
+* ID3v2FrameFlagsLookupTagAlter()
+* ID3v2FrameFlagsLookupFileAlter()
+* obey ID3v2 tag alter/preserve/discard rules
+* http://www.geocities.com/SiliconValley/Sector/9654/Softdoc/Illyrium/Aolyr.htm
+* proper checking for LINK/LNK frame validity in ID3v2 writing
+* proper checking for ASPI-TLEN frame validity in ID3v2 writing
+* proper checking for COMR frame validity in ID3v2 writing
+* http://www.geocities.co.jp/SiliconValley-Oakland/3664/index.html
+* decode GEOB ID3v2 structure as encoded by RealJukebox,
+ decode NCON ID3v2 structure as encoded by MusicMatch
+ (probably won't happen - the formats are proprietary)
+
+
+
+Known Bugs/Issues in getID3() that may be fixed eventually
+===========================================================================
+http://www.getid3.org/phpBB3/viewtopic.php?t=25
+
+* Cannot determine bitrate for MPEG video with VBR video data
+ (need documentation)
+* Interlace/progressive cannot be determined for MPEG video
+ (need documentation)
+* MIDI playtime is sometimes inaccurate
+* AAC-RAW mode files cannot be identified
+* WavPack-RAW mode files cannot be identified
+* mp4 files report lots of "Unknown QuickTime atom type"
+ (need documentation)
+* Encrypted ASF/WMA/WMV files warn about "unhandled GUID
+ ASF_Content_Encryption_Object"
+* Bitrate split between audio and video cannot be calculated for
+ NSV, only the total bitrate. (need documentation)
+* All Ogg formats (Vorbis, OggFLAC, Speex) are affected by the
+ problem of large VorbisComments spanning multiple Ogg pages, but
+ but only OggVorbis files can be processed with vorbiscomment.
+* The version of "head" supplied with Mac OS 10.2.8 (maybe other
+ versions too) does only understands a single option (-n) and
+ therefore fails. getID3 ignores this and returns wrong md5_data.
+
+
+
+Known Bugs/Issues in getID3() that cannot be fixed
+--------------------------------------------------
+http://www.getid3.org/phpBB3/viewtopic.php?t=25
+
+* 32-bit PHP installations only:
+ Files larger than 2GB cannot always be parsed fully by getID3()
+ due to limitations in the 32-bit PHP filesystem functions.
+ NOTE: Since v1.7.8b3 there is partial support for larger-than-
+ 2GB files, most of which will parse OK, as long as no critical
+ data is located beyond the 2GB offset.
+ Known will-work:
+ * all file formats on 64-bit PHP
+ * ZIP (format doesn't support files >2GB)
+ * FLAC (current encoders don't support files >2GB)
+ Known will-not-work:
+ * ID3v1 tags (always located at end-of-file)
+ * Lyrics3 tags (always located at end-of-file)
+ * APE tags (always located at end-of-file)
+ Maybe-will-work:
+ * Quicktime (will work if needed metadata is before 2GB offset,
+ that is if the file has been hinted/optimized for streaming)
+ * RIFF.WAV (should work fine, but gives warnings about not being
+ able to parse all chunks)
+ * RIFF.AVI (playtime will probably be wrong, is only based on
+ "movi" chunk that fits in the first 2GB, should issue error
+ to show that playtime is incorrect. Other data should be mostly
+ correct, assuming that data is constant throughout the file)
+
+
+
+Known Bugs/Issues in other programs
+-----------------------------------
+http://www.getid3.org/phpBB3/viewtopic.php?t=25
+
+* Windows Media Player (up to v11) and iTunes (up to v10+) do
+ not correctly handle ID3v2.3 tags with UTF-16BE+BOM
+ encoding (they assume the data is UTF-16LE+BOM and either
+ crash (WMP) or output Asian character set (iTunes)
+* Winamp (up to v2.80 at least) does not support ID3v2.4 tags,
+ only ID3v2.3
+ see: http://forums.winamp.com/showthread.php?postid=387524
+* Some versions of Helium2 (www.helium2.com) do not write
+ ID3v2.4-compliant Frame Sizes, even though the tag is marked
+ as ID3v2.4) (detected by getID3())
+* MP3ext V3.3.17 places a non-compliant padding string at the end
+ of the ID3v2 header. This is supposedly fixed in v3.4b21 but
+ only if you manually add a registry key. This fix is not yet
+ confirmed. (detected by getID3())
+* CDex v1.40 (fixed by v1.50b7) writes non-compliant Ogg comment
+ strings, supposed to be in the format "NAME=value" but actually
+ written just "value" (detected by getID3())
+* Oggenc 0.9-rc3 flags the encoded file as ABR whether it's
+ actually ABR or VBR.
+* iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably
+ other versions are too) writes ID3v2.3 comment tags using a
+ frame name 'COM ' which is not valid for ID3v2.3+ (it's an
+ ID3v2.2-style frame name) (detected by getID3())
+* MP2enc does not encode mono CBR MP2 files properly (half speed
+ sound and double playtime)
+* MP2enc does not encode mono VBR MP2 files properly (actually
+ encoded as stereo)
+* tooLAME does not encode mono VBR MP2 files properly (actually
+ encoded as stereo)
+* AACenc encodes files in VBR mode (actually ABR) even if CBR is
+ specified
+* AAC/ADIF - bitrate_mode = cbr for vbr files
+* LAME 3.90-3.92 prepends one frame of null data (space for the
+ LAME/VBR header, but it never gets written) when encoding in CBR
+ mode with the DLL
+* Ahead Nero encodes TwinVQF with a DSIZ value (which is supposed
+ to be the filesize in bytes) of "0" for TwinVQF v1.0 and "1" for
+ TwinVQF v2.0 (detected by getID3())
+* Ahead Nero encodes TwinVQF files 1 second shorter than they
+ should be
+* AAC-ADTS files are always actually encoded VBR, even if CBR mode
+ is specified (the CBR-mode switches on the encoder enable ABR
+ mode, not CBR as such, but it's not possible to tell the
+ difference between such ABR files and true VBR)
+* STREAMINFO.audio_signature in OggFLAC is always null. "The reason
+ it's like that is because there is no seeking support in
+ libOggFLAC yet, so it has no way to go back and write the
+ computed sum after encoding. Seeking support in Ogg FLAC is the
+ #1 item for the next release." - Josh Coalson (FLAC developer)
+ NOTE: getID3() will calculate md5_data in a method similar to
+ other file formats, but that value cannot be compared to the
+ md5_data value from FLAC data in a FLAC file format.
+* STREAMINFO.audio_signature is not calculated in FLAC v0.3.0 &
+ v0.4.0 - getID3() will calculate md5_data in a method similar to
+ other file formats, but that value cannot be compared to the
+ md5_data value from FLAC v0.5.0+
+* RioPort (various versions including 2.0 and 3.11) tags ID3v2 with
+ a WCOM frame that has no data portion
+* Earlier versions of Coolplayer adds illegal ID3 tags to Ogg Vorbis
+ files, thus making them corrupt.
+* Meracl ID3 Tag Writer v1.3.4 (and older) incorrectly truncates the
+ last byte of data from an MP3 file when appending a new ID3v1 tag.
+ (detected by getID3())
+* Lossless-Audio files encoded with and without the -noseek switch
+ do actually differ internally and therefore cannot match md5_data
+* iTunes has been known to append a new ID3v1 tag on the end of an
+ existing ID3v1 tag when ID3v2 tag is also present
+ (detected by getID3())
+* MediaMonkey may write a blank RGAD ID3v2 frame but put actual
+ replay gain adjustments in a series of user-defined TXXX frames
+ (detected and handled by getID3() since v1.9.2)
+
+
+
+
+Reference material:
+===========================================================================
+
+[www.id3.org material now mirrored at http://id3lib.sourceforge.net/id3/]
+* http://www.id3.org/id3v2.4.0-structure.txt
+* http://www.id3.org/id3v2.4.0-frames.txt
+* http://www.id3.org/id3v2.4.0-changes.txt
+* http://www.id3.org/id3v2.3.0.txt
+* http://www.id3.org/id3v2-00.txt
+* http://www.id3.org/mp3frame.html
+* http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html <mathewhendry@hotmail.com>
+* http://www.dv.co.yu/mpgscript/mpeghdr.htm
+* http://www.mp3-tech.org/programmer/frame_header.html
+* http://users.belgacom.net/gc247244/extra/tag.html
+* http://gabriel.mp3-tech.org/mp3infotag.html
+* http://www.id3.org/iso4217.html
+* http://www.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT
+* http://www.xiph.org/ogg/vorbis/doc/framing.html
+* http://www.xiph.org/ogg/vorbis/doc/v-comment.html
+* http://leknor.com/code/php/class.ogg.php.txt
+* http://www.id3.org/iso639-2.html
+* http://www.id3.org/lyrics3.html
+* http://www.id3.org/lyrics3200.html
+* http://www.psc.edu/general/software/packages/ieee/ieee.html
+* http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
+* http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
+* http://www.jmcgowan.com/avi.html
+* http://www.wotsit.org/
+* http://www.herdsoft.com/ti/davincie/davp3xo2.htm
+* http://www.mathdogs.com/vorbis-illuminated/bitstream-appendix.html
+* "Standard MIDI File Format" by Dustin Caldwell (from www.wotsit.org)
+* http://midistudio.com/Help/GMSpecs_Patches.htm
+* http://www.xiph.org/archives/vorbis/200109/0459.html
+* http://www.replaygain.org/
+* http://www.lossless-audio.com/
+* http://download.microsoft.com/download/winmediatech40/Doc/1.0/WIN98MeXP/EN-US/ASF_Specification_v.1.0.exe
+* http://mediaxw.sourceforge.net/files/doc/Active%20Streaming%20Format%20(ASF)%201.0%20Specification.pdf
+* http://www.uni-jena.de/~pfk/mpp/sv8/ (archived at http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/sv8/)
+* http://jfaul.de/atl/
+* http://www.uni-jena.de/~pfk/mpp/ (archived at http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/)
+* http://www.libpng.org/pub/png/spec/png-1.2-pdg.html
+* http://www.real.com/devzone/library/creating/rmsdk/doc/rmff.htm
+* http://www.fastgraph.com/help/bmp_os2_header_format.html
+* http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
+* http://flac.sourceforge.net/format.html
+* http://www.research.att.com/projects/mpegaudio/mpeg2.html
+* http://www.audiocoding.com/wiki/index.php?page=AAC
+* http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
+* http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
+* http://developer.apple.com/techpubs/quicktime/qtdevdocs/RM/frameset.htm
+* http://www.nullsoft.com/nsv/
+* http://www.wotsit.org/download.asp?f=iso9660
+* http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
+* http://www.cdroller.com/htm/readdata.html
+* http://www.speex.org/manual/node10.html
+* http://www.harmony-central.com/Computer/Programming/aiff-file-format.doc
+* http://www.faqs.org/rfcs/rfc2361.html
+* http://ghido.shelter.ro/
+* http://www.ebu.ch/tech_t3285.pdf
+* http://www.sr.se/utveckling/tu/bwf
+* http://ftp.aessc.org/pub/aes46-2002.pdf
+* http://cartchunk.org:8080/
+* http://www.broadcastpapers.com/radio/cartchunk01.htm
+* http://www.hr/josip/DSP/AudioFile2.html
+* http://home.attbi.com/~chris.bagwell/AudioFormats-11.html
+* http://www.pure-mac.com/extkey.html
+* http://cesnet.dl.sourceforge.net/sourceforge/bonkenc/bonk-binary-format-0.9.txt
+* http://www.headbands.com/gspot/
+* http://www.openswf.org/spec/SWFfileformat.html
+* http://j-faul.virtualave.net/
+* http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
+* http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
+* http://sswf.sourceforge.net/SWFalexref.html
+* http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
+* http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
+* http://developer.apple.com/quicktime/icefloe/dispatch012.html
+* http://www.csdn.net/Dev/Format/graphics/PCD.htm
+* http://tta.iszf.irk.ru/
+* http://www.atsc.org/standards/a_52a.pdf
+* http://www.alanwood.net/unicode/
+* http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
+* http://www.its.msstate.edu/net/real/reports/config/tags.stats
+* http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
+* http://brennan.young.net/Comp/LiveStage/things.html
+* http://www.multiweb.cz/twoinches/MP3inside.htm
+* http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
+* http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
+* http://www.unicode.org/unicode/faq/utf_bom.html
+* http://tta.corecodec.org/?menu=format
+* http://www.scvi.net/nsvformat.htm
+* http://pda.etsi.org/pda/queryform.asp
+* http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
+* http://trac.musepack.net/trac/wiki/SV8Specification
+* http://wyday.com/cuesharp/specification.php
+* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
diff --git a/src/wp-includes/SimplePie/Author.php b/src/wp-includes/SimplePie/Author.php
new file mode 100644
index 0000000000..bbf3812ff8
--- /dev/null
+++ b/src/wp-includes/SimplePie/Author.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Manages all author-related data
+ *
+ * Used by {@see SimplePie_Item::get_author()} and {@see SimplePie::get_authors()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_author_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Author
+{
+ /**
+ * Author's name
+ *
+ * @var string
+ * @see get_name()
+ */
+ var $name;
+
+ /**
+ * Author's link
+ *
+ * @var string
+ * @see get_link()
+ */
+ var $link;
+
+ /**
+ * Author's email address
+ *
+ * @var string
+ * @see get_email()
+ */
+ var $email;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * @param string $name
+ * @param string $link
+ * @param string $email
+ */
+ public function __construct($name = null, $link = null, $email = null)
+ {
+ $this->name = $name;
+ $this->link = $link;
+ $this->email = $email;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Author's name
+ *
+ * @return string|null
+ */
+ public function get_name()
+ {
+ if ($this->name !== null)
+ {
+ return $this->name;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Author's link
+ *
+ * @return string|null
+ */
+ public function get_link()
+ {
+ if ($this->link !== null)
+ {
+ return $this->link;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Author's email address
+ *
+ * @return string|null
+ */
+ public function get_email()
+ {
+ if ($this->email !== null)
+ {
+ return $this->email;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Cache.php b/src/wp-includes/SimplePie/Cache.php
new file mode 100644
index 0000000000..75586d7497
--- /dev/null
+++ b/src/wp-includes/SimplePie/Cache.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Used to create cache objects
+ *
+ * This class can be overloaded with {@see SimplePie::set_cache_class()},
+ * although the preferred way is to create your own handler
+ * via {@see register()}
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+class SimplePie_Cache
+{
+ /**
+ * Cache handler classes
+ *
+ * These receive 3 parameters to their constructor, as documented in
+ * {@see register()}
+ * @var array
+ */
+ protected static $handlers = array(
+ 'mysql' => 'SimplePie_Cache_MySQL',
+ 'memcache' => 'SimplePie_Cache_Memcache',
+ );
+
+ /**
+ * Don't call the constructor. Please.
+ */
+ private function __construct() { }
+
+ /**
+ * Create a new SimplePie_Cache object
+ *
+ * @param string $location URL location (scheme is used to determine handler)
+ * @param string $filename Unique identifier for cache object
+ * @param string $extension 'spi' or 'spc'
+ * @return SimplePie_Cache_Base Type of object depends on scheme of `$location`
+ */
+ public static function get_handler($location, $filename, $extension)
+ {
+ $type = explode(':', $location, 2);
+ $type = $type[0];
+ if (!empty(self::$handlers[$type]))
+ {
+ $class = self::$handlers[$type];
+ return new $class($location, $filename, $extension);
+ }
+
+ return new SimplePie_Cache_File($location, $filename, $extension);
+ }
+
+ /**
+ * Create a new SimplePie_Cache object
+ *
+ * @deprecated Use {@see get_handler} instead
+ */
+ public function create($location, $filename, $extension)
+ {
+ trigger_error('Cache::create() has been replaced with Cache::get_handler(). Switch to the registry system to use this.', E_USER_DEPRECATED);
+ return self::get_handler($location, $filename, $extension);
+ }
+
+ /**
+ * Register a handler
+ *
+ * @param string $type DSN type to register for
+ * @param string $class Name of handler class. Must implement SimplePie_Cache_Base
+ */
+ public static function register($type, $class)
+ {
+ self::$handlers[$type] = $class;
+ }
+
+ /**
+ * Parse a URL into an array
+ *
+ * @param string $url
+ * @return array
+ */
+ public static function parse_URL($url)
+ {
+ $params = parse_url($url);
+ $params['extras'] = array();
+ if (isset($params['query']))
+ {
+ parse_str($params['query'], $params['extras']);
+ }
+ return $params;
+ }
+}
diff --git a/src/wp-includes/SimplePie/Cache/Base.php b/src/wp-includes/SimplePie/Cache/Base.php
new file mode 100644
index 0000000000..937e346317
--- /dev/null
+++ b/src/wp-includes/SimplePie/Cache/Base.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Base for cache objects
+ *
+ * Classes to be used with {@see SimplePie_Cache::register()} are expected
+ * to implement this interface.
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+interface SimplePie_Cache_Base
+{
+ /**
+ * Feed cache type
+ *
+ * @var string
+ */
+ const TYPE_FEED = 'spc';
+
+ /**
+ * Image cache type
+ *
+ * @var string
+ */
+ const TYPE_IMAGE = 'spi';
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type);
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data);
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load();
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime();
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch();
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink();
+}
diff --git a/src/wp-includes/SimplePie/Cache/DB.php b/src/wp-includes/SimplePie/Cache/DB.php
new file mode 100644
index 0000000000..ac509ae087
--- /dev/null
+++ b/src/wp-includes/SimplePie/Cache/DB.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Base class for database-based caches
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+abstract class SimplePie_Cache_DB implements SimplePie_Cache_Base
+{
+ /**
+ * Helper for database conversion
+ *
+ * Converts a given {@see SimplePie} object into data to be stored
+ *
+ * @param SimplePie $data
+ * @return array First item is the serialized data for storage, second item is the unique ID for this item
+ */
+ protected static function prepare_simplepie_object_for_cache($data)
+ {
+ $items = $data->get_items();
+ $items_by_id = array();
+
+ if (!empty($items))
+ {
+ foreach ($items as $item)
+ {
+ $items_by_id[$item->get_id()] = $item;
+ }
+
+ if (count($items_by_id) !== count($items))
+ {
+ $items_by_id = array();
+ foreach ($items as $item)
+ {
+ $items_by_id[$item->get_id(true)] = $item;
+ }
+ }
+
+ if (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
+ }
+ elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
+ }
+ elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
+ }
+ elseif (isset($data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0]))
+ {
+ $channel =& $data->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['channel'][0];
+ }
+ else
+ {
+ $channel = null;
+ }
+
+ if ($channel !== null)
+ {
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['entry']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item']);
+ }
+ if (isset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']))
+ {
+ unset($channel['child'][SIMPLEPIE_NAMESPACE_RSS_20]['item']);
+ }
+ }
+ if (isset($data->data['items']))
+ {
+ unset($data->data['items']);
+ }
+ if (isset($data->data['ordered_items']))
+ {
+ unset($data->data['ordered_items']);
+ }
+ }
+ return array(serialize($data->data), $items_by_id);
+ }
+}
diff --git a/src/wp-includes/SimplePie/Cache/File.php b/src/wp-includes/SimplePie/Cache/File.php
new file mode 100644
index 0000000000..5797b3aede
--- /dev/null
+++ b/src/wp-includes/SimplePie/Cache/File.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Caches data to the filesystem
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+class SimplePie_Cache_File implements SimplePie_Cache_Base
+{
+ /**
+ * Location string
+ *
+ * @see SimplePie::$cache_location
+ * @var string
+ */
+ protected $location;
+
+ /**
+ * Filename
+ *
+ * @var string
+ */
+ protected $filename;
+
+ /**
+ * File extension
+ *
+ * @var string
+ */
+ protected $extension;
+
+ /**
+ * File path
+ *
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type)
+ {
+ $this->location = $location;
+ $this->filename = $name;
+ $this->extension = $type;
+ $this->name = "$this->location/$this->filename.$this->extension";
+ }
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data)
+ {
+ if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
+ {
+ if ($data instanceof SimplePie)
+ {
+ $data = $data->data;
+ }
+
+ $data = serialize($data);
+ return (bool) file_put_contents($this->name, $data);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load()
+ {
+ if (file_exists($this->name) && is_readable($this->name))
+ {
+ return unserialize(file_get_contents($this->name));
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime()
+ {
+ if (file_exists($this->name))
+ {
+ return filemtime($this->name);
+ }
+ return false;
+ }
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch()
+ {
+ if (file_exists($this->name))
+ {
+ return touch($this->name);
+ }
+ return false;
+ }
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink()
+ {
+ if (file_exists($this->name))
+ {
+ return unlink($this->name);
+ }
+ return false;
+ }
+}
diff --git a/src/wp-includes/SimplePie/Cache/Memcache.php b/src/wp-includes/SimplePie/Cache/Memcache.php
new file mode 100644
index 0000000000..fd44780609
--- /dev/null
+++ b/src/wp-includes/SimplePie/Cache/Memcache.php
@@ -0,0 +1,183 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Caches data to memcache
+ *
+ * Registered for URLs with the "memcache" protocol
+ *
+ * For example, `memcache://localhost:11211/?timeout=3600&prefix=sp_` will
+ * connect to memcache on `localhost` on port 11211. All tables will be
+ * prefixed with `sp_` and data will expire after 3600 seconds
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ * @uses Memcache
+ */
+class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
+{
+ /**
+ * Memcache instance
+ *
+ * @var Memcache
+ */
+ protected $cache;
+
+ /**
+ * Options
+ *
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * Cache name
+ *
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type)
+ {
+ $this->options = array(
+ 'host' => '127.0.0.1',
+ 'port' => 11211,
+ 'extras' => array(
+ 'timeout' => 3600, // one hour
+ 'prefix' => 'simplepie_',
+ ),
+ );
+ $parsed = SimplePie_Cache::parse_URL($location);
+ $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
+ $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
+ $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
+ $this->name = $this->options['extras']['prefix'] . md5("$name:$type");
+
+ $this->cache = new Memcache();
+ $this->cache->addServer($this->options['host'], (int) $this->options['port']);
+ }
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data)
+ {
+ if ($data instanceof SimplePie)
+ {
+ $data = $data->data;
+ }
+ return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
+ }
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load()
+ {
+ $data = $this->cache->get($this->name);
+
+ if ($data !== false)
+ {
+ return unserialize($data);
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime()
+ {
+ $data = $this->cache->get($this->name);
+
+ if ($data !== false)
+ {
+ // essentially ignore the mtime because Memcache expires on it's own
+ return time();
+ }
+
+ return false;
+ }
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch()
+ {
+ $data = $this->cache->get($this->name);
+
+ if ($data !== false)
+ {
+ return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
+ }
+
+ return false;
+ }
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink()
+ {
+ return $this->cache->delete($this->name, 0);
+ }
+}
diff --git a/src/wp-includes/SimplePie/Cache/MySQL.php b/src/wp-includes/SimplePie/Cache/MySQL.php
new file mode 100644
index 0000000000..d53ebc1174
--- /dev/null
+++ b/src/wp-includes/SimplePie/Cache/MySQL.php
@@ -0,0 +1,438 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Caches data to a MySQL database
+ *
+ * Registered for URLs with the "mysql" protocol
+ *
+ * For example, `mysql://root:password@localhost:3306/mydb?prefix=sp_` will
+ * connect to the `mydb` database on `localhost` on port 3306, with the user
+ * `root` and the password `password`. All tables will be prefixed with `sp_`
+ *
+ * @package SimplePie
+ * @subpackage Caching
+ */
+class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
+{
+ /**
+ * PDO instance
+ *
+ * @var PDO
+ */
+ protected $mysql;
+
+ /**
+ * Options
+ *
+ * @var array
+ */
+ protected $options;
+
+ /**
+ * Cache ID
+ *
+ * @var string
+ */
+ protected $id;
+
+ /**
+ * Create a new cache object
+ *
+ * @param string $location Location string (from SimplePie::$cache_location)
+ * @param string $name Unique ID for the cache
+ * @param string $type Either TYPE_FEED for SimplePie data, or TYPE_IMAGE for image data
+ */
+ public function __construct($location, $name, $type)
+ {
+ $this->options = array(
+ 'user' => null,
+ 'pass' => null,
+ 'host' => '127.0.0.1',
+ 'port' => '3306',
+ 'path' => '',
+ 'extras' => array(
+ 'prefix' => '',
+ ),
+ );
+ $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+
+ // Path is prefixed with a "/"
+ $this->options['dbname'] = substr($this->options['path'], 1);
+
+ try
+ {
+ $this->mysql = new PDO("mysql:dbname={$this->options['dbname']};host={$this->options['host']};port={$this->options['port']}", $this->options['user'], $this->options['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
+ }
+ catch (PDOException $e)
+ {
+ $this->mysql = null;
+ return;
+ }
+
+ $this->id = $name . $type;
+
+ if (!$query = $this->mysql->query('SHOW TABLES'))
+ {
+ $this->mysql = null;
+ return;
+ }
+
+ $db = array();
+ while ($row = $query->fetchColumn())
+ {
+ $db[] = $row;
+ }
+
+ if (!in_array($this->options['extras']['prefix'] . 'cache_data', $db))
+ {
+ $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'cache_data` (`id` TEXT CHARACTER SET utf8 NOT NULL, `items` SMALLINT NOT NULL DEFAULT 0, `data` BLOB NOT NULL, `mtime` INT UNSIGNED NOT NULL, UNIQUE (`id`(125)))');
+ if ($query === false)
+ {
+ $this->mysql = null;
+ }
+ }
+
+ if (!in_array($this->options['extras']['prefix'] . 'items', $db))
+ {
+ $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
+ if ($query === false)
+ {
+ $this->mysql = null;
+ }
+ }
+ }
+
+ /**
+ * Save data to the cache
+ *
+ * @param array|SimplePie $data Data to store in the cache. If passed a SimplePie object, only cache the $data property
+ * @return bool Successfulness
+ */
+ public function save($data)
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ if ($data instanceof SimplePie)
+ {
+ $data = clone $data;
+
+ $prepared = self::prepare_simplepie_object_for_cache($data);
+
+ $query = $this->mysql->prepare('SELECT COUNT(*) FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
+ $query->bindValue(':feed', $this->id);
+ if ($query->execute())
+ {
+ if ($query->fetchColumn() > 0)
+ {
+ $items = count($prepared[1]);
+ if ($items)
+ {
+ $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = :items, `data` = :data, `mtime` = :time WHERE `id` = :feed';
+ $query = $this->mysql->prepare($sql);
+ $query->bindValue(':items', $items);
+ }
+ else
+ {
+ $sql = 'UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `data` = :data, `mtime` = :time WHERE `id` = :feed';
+ $query = $this->mysql->prepare($sql);
+ }
+
+ $query->bindValue(':data', $prepared[0]);
+ $query->bindValue(':time', time());
+ $query->bindValue(':feed', $this->id);
+ if (!$query->execute())
+ {
+ return false;
+ }
+ }
+ else
+ {
+ $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:feed, :count, :data, :time)');
+ $query->bindValue(':feed', $this->id);
+ $query->bindValue(':count', count($prepared[1]));
+ $query->bindValue(':data', $prepared[0]);
+ $query->bindValue(':time', time());
+ if (!$query->execute())
+ {
+ return false;
+ }
+ }
+
+ $ids = array_keys($prepared[1]);
+ if (!empty($ids))
+ {
+ foreach ($ids as $id)
+ {
+ $database_ids[] = $this->mysql->quote($id);
+ }
+
+ $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `id` = ' . implode(' OR `id` = ', $database_ids) . ' AND `feed_id` = :feed');
+ $query->bindValue(':feed', $this->id);
+
+ if ($query->execute())
+ {
+ $existing_ids = array();
+ while ($row = $query->fetchColumn())
+ {
+ $existing_ids[] = $row;
+ }
+
+ $new_ids = array_diff($ids, $existing_ids);
+
+ foreach ($new_ids as $new_id)
+ {
+ if (!($date = $prepared[1][$new_id]->get_date('U')))
+ {
+ $date = time();
+ }
+
+ $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'items` (`feed_id`, `id`, `data`, `posted`) VALUES(:feed, :id, :data, :date)');
+ $query->bindValue(':feed', $this->id);
+ $query->bindValue(':id', $new_id);
+ $query->bindValue(':data', serialize($prepared[1][$new_id]->data));
+ $query->bindValue(':date', $date);
+ if (!$query->execute())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ $query = $this->mysql->prepare('SELECT `id` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :feed');
+ $query->bindValue(':feed', $this->id);
+ if ($query->execute())
+ {
+ if ($query->rowCount() > 0)
+ {
+ $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `items` = 0, `data` = :data, `mtime` = :time WHERE `id` = :feed');
+ $query->bindValue(':data', serialize($data));
+ $query->bindValue(':time', time());
+ $query->bindValue(':feed', $this->id);
+ if ($this->execute())
+ {
+ return true;
+ }
+ }
+ else
+ {
+ $query = $this->mysql->prepare('INSERT INTO `' . $this->options['extras']['prefix'] . 'cache_data` (`id`, `items`, `data`, `mtime`) VALUES(:id, 0, :data, :time)');
+ $query->bindValue(':id', $this->id);
+ $query->bindValue(':data', serialize($data));
+ $query->bindValue(':time', time());
+ if ($query->execute())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the data saved to the cache
+ *
+ * @return array Data for SimplePie::$data
+ */
+ public function load()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('SELECT `items`, `data` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
+ $query->bindValue(':id', $this->id);
+ if ($query->execute() && ($row = $query->fetch()))
+ {
+ $data = unserialize($row[1]);
+
+ if (isset($this->options['items'][0]))
+ {
+ $items = (int) $this->options['items'][0];
+ }
+ else
+ {
+ $items = (int) $row[0];
+ }
+
+ if ($items !== 0)
+ {
+ if (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0];
+ }
+ elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0];
+ }
+ elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0];
+ }
+ elseif (isset($data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]))
+ {
+ $feed =& $data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0];
+ }
+ else
+ {
+ $feed = null;
+ }
+
+ if ($feed !== null)
+ {
+ $sql = 'SELECT `data` FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :feed ORDER BY `posted` DESC';
+ if ($items > 0)
+ {
+ $sql .= ' LIMIT ' . $items;
+ }
+
+ $query = $this->mysql->prepare($sql);
+ $query->bindValue(':feed', $this->id);
+ if ($query->execute())
+ {
+ while ($row = $query->fetchColumn())
+ {
+ $feed['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['entry'][] = unserialize($row);
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ return $data;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve the last modified time for the cache
+ *
+ * @return int Timestamp
+ */
+ public function mtime()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('SELECT `mtime` FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
+ $query->bindValue(':id', $this->id);
+ if ($query->execute() && ($time = $query->fetchColumn()))
+ {
+ return $time;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Set the last modified time to the current time
+ *
+ * @return bool Success status
+ */
+ public function touch()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('UPDATE `' . $this->options['extras']['prefix'] . 'cache_data` SET `mtime` = :time WHERE `id` = :id');
+ $query->bindValue(':time', time());
+ $query->bindValue(':id', $this->id);
+ if ($query->execute() && $query->rowCount() > 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Remove the cache
+ *
+ * @return bool Success status
+ */
+ public function unlink()
+ {
+ if ($this->mysql === null)
+ {
+ return false;
+ }
+
+ $query = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'cache_data` WHERE `id` = :id');
+ $query->bindValue(':id', $this->id);
+ $query2 = $this->mysql->prepare('DELETE FROM `' . $this->options['extras']['prefix'] . 'items` WHERE `feed_id` = :id');
+ $query2->bindValue(':id', $this->id);
+ if ($query->execute() && $query2->execute())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/Caption.php b/src/wp-includes/SimplePie/Caption.php
new file mode 100644
index 0000000000..52922c5d95
--- /dev/null
+++ b/src/wp-includes/SimplePie/Caption.php
@@ -0,0 +1,210 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Handles `<media:text>` captions as defined in Media RSS.
+ *
+ * Used by {@see SimplePie_Enclosure::get_caption()} and {@see SimplePie_Enclosure::get_captions()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_caption_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Caption
+{
+ /**
+ * Content type
+ *
+ * @var string
+ * @see get_type()
+ */
+ var $type;
+
+ /**
+ * Language
+ *
+ * @var string
+ * @see get_language()
+ */
+ var $lang;
+
+ /**
+ * Start time
+ *
+ * @var string
+ * @see get_starttime()
+ */
+ var $startTime;
+
+ /**
+ * End time
+ *
+ * @var string
+ * @see get_endtime()
+ */
+ var $endTime;
+
+ /**
+ * Caption text
+ *
+ * @var string
+ * @see get_text()
+ */
+ var $text;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
+ {
+ $this->type = $type;
+ $this->lang = $lang;
+ $this->startTime = $startTime;
+ $this->endTime = $endTime;
+ $this->text = $text;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the end time
+ *
+ * @return string|null Time in the format 'hh:mm:ss.SSS'
+ */
+ public function get_endtime()
+ {
+ if ($this->endTime !== null)
+ {
+ return $this->endTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the language
+ *
+ * @link http://tools.ietf.org/html/rfc3066
+ * @return string|null Language code as per RFC 3066
+ */
+ public function get_language()
+ {
+ if ($this->lang !== null)
+ {
+ return $this->lang;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the start time
+ *
+ * @return string|null Time in the format 'hh:mm:ss.SSS'
+ */
+ public function get_starttime()
+ {
+ if ($this->startTime !== null)
+ {
+ return $this->startTime;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the text of the caption
+ *
+ * @return string|null
+ */
+ public function get_text()
+ {
+ if ($this->text !== null)
+ {
+ return $this->text;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the content type (not MIME type)
+ *
+ * @return string|null Either 'text' or 'html'
+ */
+ public function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Category.php b/src/wp-includes/SimplePie/Category.php
new file mode 100644
index 0000000000..ad0407b4e2
--- /dev/null
+++ b/src/wp-includes/SimplePie/Category.php
@@ -0,0 +1,157 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Manages all category-related data
+ *
+ * Used by {@see SimplePie_Item::get_category()} and {@see SimplePie_Item::get_categories()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_category_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Category
+{
+ /**
+ * Category identifier
+ *
+ * @var string
+ * @see get_term
+ */
+ var $term;
+
+ /**
+ * Categorization scheme identifier
+ *
+ * @var string
+ * @see get_scheme()
+ */
+ var $scheme;
+
+ /**
+ * Human readable label
+ *
+ * @var string
+ * @see get_label()
+ */
+ var $label;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * @param string $term
+ * @param string $scheme
+ * @param string $label
+ */
+ public function __construct($term = null, $scheme = null, $label = null)
+ {
+ $this->term = $term;
+ $this->scheme = $scheme;
+ $this->label = $label;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the category identifier
+ *
+ * @return string|null
+ */
+ public function get_term()
+ {
+ if ($this->term !== null)
+ {
+ return $this->term;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the categorization scheme identifier
+ *
+ * @return string|null
+ */
+ public function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the human readable label
+ *
+ * @return string|null
+ */
+ public function get_label()
+ {
+ if ($this->label !== null)
+ {
+ return $this->label;
+ }
+ else
+ {
+ return $this->get_term();
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Content/Type/Sniffer.php b/src/wp-includes/SimplePie/Content/Type/Sniffer.php
new file mode 100644
index 0000000000..20d053dca4
--- /dev/null
+++ b/src/wp-includes/SimplePie/Content/Type/Sniffer.php
@@ -0,0 +1,332 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Content-type sniffing
+ *
+ * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06
+ *
+ * This is used since we can't always trust Content-Type headers, and is based
+ * upon the HTML5 parsing rules.
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()}
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ */
+class SimplePie_Content_Type_Sniffer
+{
+ /**
+ * File object
+ *
+ * @var SimplePie_File
+ */
+ var $file;
+
+ /**
+ * Create an instance of the class with the input file
+ *
+ * @param SimplePie_Content_Type_Sniffer $file Input file
+ */
+ public function __construct($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Get the Content-Type of the specified file
+ *
+ * @return string Actual Content-Type
+ */
+ public function get_type()
+ {
+ if (isset($this->file->headers['content-type']))
+ {
+ if (!isset($this->file->headers['content-encoding'])
+ && ($this->file->headers['content-type'] === 'text/plain'
+ || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
+ || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'
+ || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8'))
+ {
+ return $this->text_or_binary();
+ }
+
+ if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
+ {
+ $official = substr($this->file->headers['content-type'], 0, $pos);
+ }
+ else
+ {
+ $official = $this->file->headers['content-type'];
+ }
+ $official = trim(strtolower($official));
+
+ if ($official === 'unknown/unknown'
+ || $official === 'application/unknown')
+ {
+ return $this->unknown();
+ }
+ elseif (substr($official, -4) === '+xml'
+ || $official === 'text/xml'
+ || $official === 'application/xml')
+ {
+ return $official;
+ }
+ elseif (substr($official, 0, 6) === 'image/')
+ {
+ if ($return = $this->image())
+ {
+ return $return;
+ }
+ else
+ {
+ return $official;
+ }
+ }
+ elseif ($official === 'text/html')
+ {
+ return $this->feed_or_html();
+ }
+ else
+ {
+ return $official;
+ }
+ }
+ else
+ {
+ return $this->unknown();
+ }
+ }
+
+ /**
+ * Sniff text or binary
+ *
+ * @return string Actual Content-Type
+ */
+ public function text_or_binary()
+ {
+ if (substr($this->file->body, 0, 2) === "\xFE\xFF"
+ || substr($this->file->body, 0, 2) === "\xFF\xFE"
+ || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
+ || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
+ {
+ return 'text/plain';
+ }
+ elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
+ {
+ return 'application/octect-stream';
+ }
+ else
+ {
+ return 'text/plain';
+ }
+ }
+
+ /**
+ * Sniff unknown
+ *
+ * @return string Actual Content-Type
+ */
+ public function unknown()
+ {
+ $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
+ if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
+ || strtolower(substr($this->file->body, $ws, 5)) === '<html'
+ || strtolower(substr($this->file->body, $ws, 7)) === '<script')
+ {
+ return 'text/html';
+ }
+ elseif (substr($this->file->body, 0, 5) === '%PDF-')
+ {
+ return 'application/pdf';
+ }
+ elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
+ {
+ return 'application/postscript';
+ }
+ elseif (substr($this->file->body, 0, 6) === 'GIF87a'
+ || substr($this->file->body, 0, 6) === 'GIF89a')
+ {
+ return 'image/gif';
+ }
+ elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+ {
+ return 'image/png';
+ }
+ elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+ {
+ return 'image/jpeg';
+ }
+ elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+ {
+ return 'image/bmp';
+ }
+ elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
+ {
+ return 'image/vnd.microsoft.icon';
+ }
+ else
+ {
+ return $this->text_or_binary();
+ }
+ }
+
+ /**
+ * Sniff images
+ *
+ * @return string Actual Content-Type
+ */
+ public function image()
+ {
+ if (substr($this->file->body, 0, 6) === 'GIF87a'
+ || substr($this->file->body, 0, 6) === 'GIF89a')
+ {
+ return 'image/gif';
+ }
+ elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+ {
+ return 'image/png';
+ }
+ elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+ {
+ return 'image/jpeg';
+ }
+ elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+ {
+ return 'image/bmp';
+ }
+ elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00")
+ {
+ return 'image/vnd.microsoft.icon';
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Sniff HTML
+ *
+ * @return string Actual Content-Type
+ */
+ public function feed_or_html()
+ {
+ $len = strlen($this->file->body);
+ $pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
+
+ while ($pos < $len)
+ {
+ switch ($this->file->body[$pos])
+ {
+ case "\x09":
+ case "\x0A":
+ case "\x0D":
+ case "\x20":
+ $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
+ continue 2;
+
+ case '<':
+ $pos++;
+ break;
+
+ default:
+ return 'text/html';
+ }
+
+ if (substr($this->file->body, $pos, 3) === '!--')
+ {
+ $pos += 3;
+ if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
+ {
+ $pos += 3;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 1) === '!')
+ {
+ if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
+ {
+ $pos++;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 1) === '?')
+ {
+ if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
+ {
+ $pos += 2;
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+ elseif (substr($this->file->body, $pos, 3) === 'rss'
+ || substr($this->file->body, $pos, 7) === 'rdf:RDF')
+ {
+ return 'application/rss+xml';
+ }
+ elseif (substr($this->file->body, $pos, 4) === 'feed')
+ {
+ return 'application/atom+xml';
+ }
+ else
+ {
+ return 'text/html';
+ }
+ }
+
+ return 'text/html';
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Copyright.php b/src/wp-includes/SimplePie/Copyright.php
new file mode 100644
index 0000000000..57c535a64a
--- /dev/null
+++ b/src/wp-includes/SimplePie/Copyright.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Manages `<media:copyright>` copyright tags as defined in Media RSS
+ *
+ * Used by {@see SimplePie_Enclosure::get_copyright()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_copyright_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Copyright
+{
+ /**
+ * Copyright URL
+ *
+ * @var string
+ * @see get_url()
+ */
+ var $url;
+
+ /**
+ * Attribution
+ *
+ * @var string
+ * @see get_attribution()
+ */
+ var $label;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($url = null, $label = null)
+ {
+ $this->url = $url;
+ $this->label = $label;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the copyright URL
+ *
+ * @return string|null URL to copyright information
+ */
+ public function get_url()
+ {
+ if ($this->url !== null)
+ {
+ return $this->url;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the attribution text
+ *
+ * @return string|null
+ */
+ public function get_attribution()
+ {
+ if ($this->label !== null)
+ {
+ return $this->label;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Core.php b/src/wp-includes/SimplePie/Core.php
new file mode 100644
index 0000000000..46d996628e
--- /dev/null
+++ b/src/wp-includes/SimplePie/Core.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * SimplePie class.
+ *
+ * Class for backward compatibility.
+ *
+ * @deprecated Use {@see SimplePie} directly
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Core extends SimplePie
+{
+
+} \ No newline at end of file
diff --git a/src/wp-includes/SimplePie/Credit.php b/src/wp-includes/SimplePie/Credit.php
new file mode 100644
index 0000000000..d3a3442ad9
--- /dev/null
+++ b/src/wp-includes/SimplePie/Credit.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Handles `<media:credit>` as defined in Media RSS
+ *
+ * Used by {@see SimplePie_Enclosure::get_credit()} and {@see SimplePie_Enclosure::get_credits()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_credit_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Credit
+{
+ /**
+ * Credited role
+ *
+ * @var string
+ * @see get_role()
+ */
+ var $role;
+
+ /**
+ * Organizational scheme
+ *
+ * @var string
+ * @see get_scheme()
+ */
+ var $scheme;
+
+ /**
+ * Credited name
+ *
+ * @var string
+ * @see get_name()
+ */
+ var $name;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($role = null, $scheme = null, $name = null)
+ {
+ $this->role = $role;
+ $this->scheme = $scheme;
+ $this->name = $name;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the role of the person receiving credit
+ *
+ * @return string|null
+ */
+ public function get_role()
+ {
+ if ($this->role !== null)
+ {
+ return $this->role;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the organizational scheme
+ *
+ * @return string|null
+ */
+ public function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the credited person/entity's name
+ *
+ * @return string|null
+ */
+ public function get_name()
+ {
+ if ($this->name !== null)
+ {
+ return $this->name;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Decode/HTML/Entities.php b/src/wp-includes/SimplePie/Decode/HTML/Entities.php
new file mode 100644
index 0000000000..069e8d8e56
--- /dev/null
+++ b/src/wp-includes/SimplePie/Decode/HTML/Entities.php
@@ -0,0 +1,617 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Decode HTML Entities
+ *
+ * This implements HTML5 as of revision 967 (2007-06-28)
+ *
+ * @deprecated Use DOMDocument instead!
+ * @package SimplePie
+ */
+class SimplePie_Decode_HTML_Entities
+{
+ /**
+ * Data to be parsed
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Currently consumed bytes
+ *
+ * @access private
+ * @var string
+ */
+ var $consumed = '';
+
+ /**
+ * Position of the current byte being parsed
+ *
+ * @access private
+ * @var int
+ */
+ var $position = 0;
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return string Output data
+ */
+ public function parse()
+ {
+ while (($this->position = strpos($this->data, '&', $this->position)) !== false)
+ {
+ $this->consume();
+ $this->entity();
+ $this->consumed = '';
+ }
+ return $this->data;
+ }
+
+ /**
+ * Consume the next byte
+ *
+ * @access private
+ * @return mixed The next byte, or false, if there is no more data
+ */
+ public function consume()
+ {
+ if (isset($this->data[$this->position]))
+ {
+ $this->consumed .= $this->data[$this->position];
+ return $this->data[$this->position++];
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Consume a range of characters
+ *
+ * @access private
+ * @param string $chars Characters to consume
+ * @return mixed A series of characters that match the range, or false
+ */
+ public function consume_range($chars)
+ {
+ if ($len = strspn($this->data, $chars, $this->position))
+ {
+ $data = substr($this->data, $this->position, $len);
+ $this->consumed .= $data;
+ $this->position += $len;
+ return $data;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Unconsume one byte
+ *
+ * @access private
+ */
+ public function unconsume()
+ {
+ $this->consumed = substr($this->consumed, 0, -1);
+ $this->position--;
+ }
+
+ /**
+ * Decode an entity
+ *
+ * @access private
+ */
+ public function entity()
+ {
+ switch ($this->consume())
+ {
+ case "\x09":
+ case "\x0A":
+ case "\x0B":
+ case "\x0B":
+ case "\x0C":
+ case "\x20":
+ case "\x3C":
+ case "\x26":
+ case false:
+ break;
+
+ case "\x23":
+ switch ($this->consume())
+ {
+ case "\x78":
+ case "\x58":
+ $range = '0123456789ABCDEFabcdef';
+ $hex = true;
+ break;
+
+ default:
+ $range = '0123456789';
+ $hex = false;
+ $this->unconsume();
+ break;
+ }
+
+ if ($codepoint = $this->consume_range($range))
+ {
+ static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
+
+ if ($hex)
+ {
+ $codepoint = hexdec($codepoint);
+ }
+ else
+ {
+ $codepoint = intval($codepoint);
+ }
+
+ if (isset($windows_1252_specials[$codepoint]))
+ {
+ $replacement = $windows_1252_specials[$codepoint];
+ }
+ else
+ {
+ $replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
+ }
+
+ if (!in_array($this->consume(), array(';', false), true))
+ {
+ $this->unconsume();
+ }
+
+ $consumed_length = strlen($this->consumed);
+ $this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
+ $this->position += strlen($replacement) - $consumed_length;
+ }
+ break;
+
+ default:
+ static $entities = array(
+ 'Aacute' => "\xC3\x81",
+ 'aacute' => "\xC3\xA1",
+ 'Aacute;' => "\xC3\x81",
+ 'aacute;' => "\xC3\xA1",
+ 'Acirc' => "\xC3\x82",
+ 'acirc' => "\xC3\xA2",
+ 'Acirc;' => "\xC3\x82",
+ 'acirc;' => "\xC3\xA2",
+ 'acute' => "\xC2\xB4",
+ 'acute;' => "\xC2\xB4",
+ 'AElig' => "\xC3\x86",
+ 'aelig' => "\xC3\xA6",
+ 'AElig;' => "\xC3\x86",
+ 'aelig;' => "\xC3\xA6",
+ 'Agrave' => "\xC3\x80",
+ 'agrave' => "\xC3\xA0",
+ 'Agrave;' => "\xC3\x80",
+ 'agrave;' => "\xC3\xA0",
+ 'alefsym;' => "\xE2\x84\xB5",
+ 'Alpha;' => "\xCE\x91",
+ 'alpha;' => "\xCE\xB1",
+ 'AMP' => "\x26",
+ 'amp' => "\x26",
+ 'AMP;' => "\x26",
+ 'amp;' => "\x26",
+ 'and;' => "\xE2\x88\xA7",
+ 'ang;' => "\xE2\x88\xA0",
+ 'apos;' => "\x27",
+ 'Aring' => "\xC3\x85",
+ 'aring' => "\xC3\xA5",
+ 'Aring;' => "\xC3\x85",
+ 'aring;' => "\xC3\xA5",
+ 'asymp;' => "\xE2\x89\x88",
+ 'Atilde' => "\xC3\x83",
+ 'atilde' => "\xC3\xA3",
+ 'Atilde;' => "\xC3\x83",
+ 'atilde;' => "\xC3\xA3",
+ 'Auml' => "\xC3\x84",
+ 'auml' => "\xC3\xA4",
+ 'Auml;' => "\xC3\x84",
+ 'auml;' => "\xC3\xA4",
+ 'bdquo;' => "\xE2\x80\x9E",
+ 'Beta;' => "\xCE\x92",
+ 'beta;' => "\xCE\xB2",
+ 'brvbar' => "\xC2\xA6",
+ 'brvbar;' => "\xC2\xA6",
+ 'bull;' => "\xE2\x80\xA2",
+ 'cap;' => "\xE2\x88\xA9",
+ 'Ccedil' => "\xC3\x87",
+ 'ccedil' => "\xC3\xA7",
+ 'Ccedil;' => "\xC3\x87",
+ 'ccedil;' => "\xC3\xA7",
+ 'cedil' => "\xC2\xB8",
+ 'cedil;' => "\xC2\xB8",
+ 'cent' => "\xC2\xA2",
+ 'cent;' => "\xC2\xA2",
+ 'Chi;' => "\xCE\xA7",
+ 'chi;' => "\xCF\x87",
+ 'circ;' => "\xCB\x86",
+ 'clubs;' => "\xE2\x99\xA3",
+ 'cong;' => "\xE2\x89\x85",
+ 'COPY' => "\xC2\xA9",
+ 'copy' => "\xC2\xA9",
+ 'COPY;' => "\xC2\xA9",
+ 'copy;' => "\xC2\xA9",
+ 'crarr;' => "\xE2\x86\xB5",
+ 'cup;' => "\xE2\x88\xAA",
+ 'curren' => "\xC2\xA4",
+ 'curren;' => "\xC2\xA4",
+ 'Dagger;' => "\xE2\x80\xA1",
+ 'dagger;' => "\xE2\x80\xA0",
+ 'dArr;' => "\xE2\x87\x93",
+ 'darr;' => "\xE2\x86\x93",
+ 'deg' => "\xC2\xB0",
+ 'deg;' => "\xC2\xB0",
+ 'Delta;' => "\xCE\x94",
+ 'delta;' => "\xCE\xB4",
+ 'diams;' => "\xE2\x99\xA6",
+ 'divide' => "\xC3\xB7",
+ 'divide;' => "\xC3\xB7",
+ 'Eacute' => "\xC3\x89",
+ 'eacute' => "\xC3\xA9",
+ 'Eacute;' => "\xC3\x89",
+ 'eacute;' => "\xC3\xA9",
+ 'Ecirc' => "\xC3\x8A",
+ 'ecirc' => "\xC3\xAA",
+ 'Ecirc;' => "\xC3\x8A",
+ 'ecirc;' => "\xC3\xAA",
+ 'Egrave' => "\xC3\x88",
+ 'egrave' => "\xC3\xA8",
+ 'Egrave;' => "\xC3\x88",
+ 'egrave;' => "\xC3\xA8",
+ 'empty;' => "\xE2\x88\x85",
+ 'emsp;' => "\xE2\x80\x83",
+ 'ensp;' => "\xE2\x80\x82",
+ 'Epsilon;' => "\xCE\x95",
+ 'epsilon;' => "\xCE\xB5",
+ 'equiv;' => "\xE2\x89\xA1",
+ 'Eta;' => "\xCE\x97",
+ 'eta;' => "\xCE\xB7",
+ 'ETH' => "\xC3\x90",
+ 'eth' => "\xC3\xB0",
+ 'ETH;' => "\xC3\x90",
+ 'eth;' => "\xC3\xB0",
+ 'Euml' => "\xC3\x8B",
+ 'euml' => "\xC3\xAB",
+ 'Euml;' => "\xC3\x8B",
+ 'euml;' => "\xC3\xAB",
+ 'euro;' => "\xE2\x82\xAC",
+ 'exist;' => "\xE2\x88\x83",
+ 'fnof;' => "\xC6\x92",
+ 'forall;' => "\xE2\x88\x80",
+ 'frac12' => "\xC2\xBD",
+ 'frac12;' => "\xC2\xBD",
+ 'frac14' => "\xC2\xBC",
+ 'frac14;' => "\xC2\xBC",
+ 'frac34' => "\xC2\xBE",
+ 'frac34;' => "\xC2\xBE",
+ 'frasl;' => "\xE2\x81\x84",
+ 'Gamma;' => "\xCE\x93",
+ 'gamma;' => "\xCE\xB3",
+ 'ge;' => "\xE2\x89\xA5",
+ 'GT' => "\x3E",
+ 'gt' => "\x3E",
+ 'GT;' => "\x3E",
+ 'gt;' => "\x3E",
+ 'hArr;' => "\xE2\x87\x94",
+ 'harr;' => "\xE2\x86\x94",
+ 'hearts;' => "\xE2\x99\xA5",
+ 'hellip;' => "\xE2\x80\xA6",
+ 'Iacute' => "\xC3\x8D",
+ 'iacute' => "\xC3\xAD",
+ 'Iacute;' => "\xC3\x8D",
+ 'iacute;' => "\xC3\xAD",
+ 'Icirc' => "\xC3\x8E",
+ 'icirc' => "\xC3\xAE",
+ 'Icirc;' => "\xC3\x8E",
+ 'icirc;' => "\xC3\xAE",
+ 'iexcl' => "\xC2\xA1",
+ 'iexcl;' => "\xC2\xA1",
+ 'Igrave' => "\xC3\x8C",
+ 'igrave' => "\xC3\xAC",
+ 'Igrave;' => "\xC3\x8C",
+ 'igrave;' => "\xC3\xAC",
+ 'image;' => "\xE2\x84\x91",
+ 'infin;' => "\xE2\x88\x9E",
+ 'int;' => "\xE2\x88\xAB",
+ 'Iota;' => "\xCE\x99",
+ 'iota;' => "\xCE\xB9",
+ 'iquest' => "\xC2\xBF",
+ 'iquest;' => "\xC2\xBF",
+ 'isin;' => "\xE2\x88\x88",
+ 'Iuml' => "\xC3\x8F",
+ 'iuml' => "\xC3\xAF",
+ 'Iuml;' => "\xC3\x8F",
+ 'iuml;' => "\xC3\xAF",
+ 'Kappa;' => "\xCE\x9A",
+ 'kappa;' => "\xCE\xBA",
+ 'Lambda;' => "\xCE\x9B",
+ 'lambda;' => "\xCE\xBB",
+ 'lang;' => "\xE3\x80\x88",
+ 'laquo' => "\xC2\xAB",
+ 'laquo;' => "\xC2\xAB",
+ 'lArr;' => "\xE2\x87\x90",
+ 'larr;' => "\xE2\x86\x90",
+ 'lceil;' => "\xE2\x8C\x88",
+ 'ldquo;' => "\xE2\x80\x9C",
+ 'le;' => "\xE2\x89\xA4",
+ 'lfloor;' => "\xE2\x8C\x8A",
+ 'lowast;' => "\xE2\x88\x97",
+ 'loz;' => "\xE2\x97\x8A",
+ 'lrm;' => "\xE2\x80\x8E",
+ 'lsaquo;' => "\xE2\x80\xB9",
+ 'lsquo;' => "\xE2\x80\x98",
+ 'LT' => "\x3C",
+ 'lt' => "\x3C",
+ 'LT;' => "\x3C",
+ 'lt;' => "\x3C",
+ 'macr' => "\xC2\xAF",
+ 'macr;' => "\xC2\xAF",
+ 'mdash;' => "\xE2\x80\x94",
+ 'micro' => "\xC2\xB5",
+ 'micro;' => "\xC2\xB5",
+ 'middot' => "\xC2\xB7",
+ 'middot;' => "\xC2\xB7",
+ 'minus;' => "\xE2\x88\x92",
+ 'Mu;' => "\xCE\x9C",
+ 'mu;' => "\xCE\xBC",
+ 'nabla;' => "\xE2\x88\x87",
+ 'nbsp' => "\xC2\xA0",
+ 'nbsp;' => "\xC2\xA0",
+ 'ndash;' => "\xE2\x80\x93",
+ 'ne;' => "\xE2\x89\xA0",
+ 'ni;' => "\xE2\x88\x8B",
+ 'not' => "\xC2\xAC",
+ 'not;' => "\xC2\xAC",
+ 'notin;' => "\xE2\x88\x89",
+ 'nsub;' => "\xE2\x8A\x84",
+ 'Ntilde' => "\xC3\x91",
+ 'ntilde' => "\xC3\xB1",
+ 'Ntilde;' => "\xC3\x91",
+ 'ntilde;' => "\xC3\xB1",
+ 'Nu;' => "\xCE\x9D",
+ 'nu;' => "\xCE\xBD",
+ 'Oacute' => "\xC3\x93",
+ 'oacute' => "\xC3\xB3",
+ 'Oacute;' => "\xC3\x93",
+ 'oacute;' => "\xC3\xB3",
+ 'Ocirc' => "\xC3\x94",
+ 'ocirc' => "\xC3\xB4",
+ 'Ocirc;' => "\xC3\x94",
+ 'ocirc;' => "\xC3\xB4",
+ 'OElig;' => "\xC5\x92",
+ 'oelig;' => "\xC5\x93",
+ 'Ograve' => "\xC3\x92",
+ 'ograve' => "\xC3\xB2",
+ 'Ograve;' => "\xC3\x92",
+ 'ograve;' => "\xC3\xB2",
+ 'oline;' => "\xE2\x80\xBE",
+ 'Omega;' => "\xCE\xA9",
+ 'omega;' => "\xCF\x89",
+ 'Omicron;' => "\xCE\x9F",
+ 'omicron;' => "\xCE\xBF",
+ 'oplus;' => "\xE2\x8A\x95",
+ 'or;' => "\xE2\x88\xA8",
+ 'ordf' => "\xC2\xAA",
+ 'ordf;' => "\xC2\xAA",
+ 'ordm' => "\xC2\xBA",
+ 'ordm;' => "\xC2\xBA",
+ 'Oslash' => "\xC3\x98",
+ 'oslash' => "\xC3\xB8",
+ 'Oslash;' => "\xC3\x98",
+ 'oslash;' => "\xC3\xB8",
+ 'Otilde' => "\xC3\x95",
+ 'otilde' => "\xC3\xB5",
+ 'Otilde;' => "\xC3\x95",
+ 'otilde;' => "\xC3\xB5",
+ 'otimes;' => "\xE2\x8A\x97",
+ 'Ouml' => "\xC3\x96",
+ 'ouml' => "\xC3\xB6",
+ 'Ouml;' => "\xC3\x96",
+ 'ouml;' => "\xC3\xB6",
+ 'para' => "\xC2\xB6",
+ 'para;' => "\xC2\xB6",
+ 'part;' => "\xE2\x88\x82",
+ 'permil;' => "\xE2\x80\xB0",
+ 'perp;' => "\xE2\x8A\xA5",
+ 'Phi;' => "\xCE\xA6",
+ 'phi;' => "\xCF\x86",
+ 'Pi;' => "\xCE\xA0",
+ 'pi;' => "\xCF\x80",
+ 'piv;' => "\xCF\x96",
+ 'plusmn' => "\xC2\xB1",
+ 'plusmn;' => "\xC2\xB1",
+ 'pound' => "\xC2\xA3",
+ 'pound;' => "\xC2\xA3",
+ 'Prime;' => "\xE2\x80\xB3",
+ 'prime;' => "\xE2\x80\xB2",
+ 'prod;' => "\xE2\x88\x8F",
+ 'prop;' => "\xE2\x88\x9D",
+ 'Psi;' => "\xCE\xA8",
+ 'psi;' => "\xCF\x88",
+ 'QUOT' => "\x22",
+ 'quot' => "\x22",
+ 'QUOT;' => "\x22",
+ 'quot;' => "\x22",
+ 'radic;' => "\xE2\x88\x9A",
+ 'rang;' => "\xE3\x80\x89",
+ 'raquo' => "\xC2\xBB",
+ 'raquo;' => "\xC2\xBB",
+ 'rArr;' => "\xE2\x87\x92",
+ 'rarr;' => "\xE2\x86\x92",
+ 'rceil;' => "\xE2\x8C\x89",
+ 'rdquo;' => "\xE2\x80\x9D",
+ 'real;' => "\xE2\x84\x9C",
+ 'REG' => "\xC2\xAE",
+ 'reg' => "\xC2\xAE",
+ 'REG;' => "\xC2\xAE",
+ 'reg;' => "\xC2\xAE",
+ 'rfloor;' => "\xE2\x8C\x8B",
+ 'Rho;' => "\xCE\xA1",
+ 'rho;' => "\xCF\x81",
+ 'rlm;' => "\xE2\x80\x8F",
+ 'rsaquo;' => "\xE2\x80\xBA",
+ 'rsquo;' => "\xE2\x80\x99",
+ 'sbquo;' => "\xE2\x80\x9A",
+ 'Scaron;' => "\xC5\xA0",
+ 'scaron;' => "\xC5\xA1",
+ 'sdot;' => "\xE2\x8B\x85",
+ 'sect' => "\xC2\xA7",
+ 'sect;' => "\xC2\xA7",
+ 'shy' => "\xC2\xAD",
+ 'shy;' => "\xC2\xAD",
+ 'Sigma;' => "\xCE\xA3",
+ 'sigma;' => "\xCF\x83",
+ 'sigmaf;' => "\xCF\x82",
+ 'sim;' => "\xE2\x88\xBC",
+ 'spades;' => "\xE2\x99\xA0",
+ 'sub;' => "\xE2\x8A\x82",
+ 'sube;' => "\xE2\x8A\x86",
+ 'sum;' => "\xE2\x88\x91",
+ 'sup;' => "\xE2\x8A\x83",
+ 'sup1' => "\xC2\xB9",
+ 'sup1;' => "\xC2\xB9",
+ 'sup2' => "\xC2\xB2",
+ 'sup2;' => "\xC2\xB2",
+ 'sup3' => "\xC2\xB3",
+ 'sup3;' => "\xC2\xB3",
+ 'supe;' => "\xE2\x8A\x87",
+ 'szlig' => "\xC3\x9F",
+ 'szlig;' => "\xC3\x9F",
+ 'Tau;' => "\xCE\xA4",
+ 'tau;' => "\xCF\x84",
+ 'there4;' => "\xE2\x88\xB4",
+ 'Theta;' => "\xCE\x98",
+ 'theta;' => "\xCE\xB8",
+ 'thetasym;' => "\xCF\x91",
+ 'thinsp;' => "\xE2\x80\x89",
+ 'THORN' => "\xC3\x9E",
+ 'thorn' => "\xC3\xBE",
+ 'THORN;' => "\xC3\x9E",
+ 'thorn;' => "\xC3\xBE",
+ 'tilde;' => "\xCB\x9C",
+ 'times' => "\xC3\x97",
+ 'times;' => "\xC3\x97",
+ 'TRADE;' => "\xE2\x84\xA2",
+ 'trade;' => "\xE2\x84\xA2",
+ 'Uacute' => "\xC3\x9A",
+ 'uacute' => "\xC3\xBA",
+ 'Uacute;' => "\xC3\x9A",
+ 'uacute;' => "\xC3\xBA",
+ 'uArr;' => "\xE2\x87\x91",
+ 'uarr;' => "\xE2\x86\x91",
+ 'Ucirc' => "\xC3\x9B",
+ 'ucirc' => "\xC3\xBB",
+ 'Ucirc;' => "\xC3\x9B",
+ 'ucirc;' => "\xC3\xBB",
+ 'Ugrave' => "\xC3\x99",
+ 'ugrave' => "\xC3\xB9",
+ 'Ugrave;' => "\xC3\x99",
+ 'ugrave;' => "\xC3\xB9",
+ 'uml' => "\xC2\xA8",
+ 'uml;' => "\xC2\xA8",
+ 'upsih;' => "\xCF\x92",
+ 'Upsilon;' => "\xCE\xA5",
+ 'upsilon;' => "\xCF\x85",
+ 'Uuml' => "\xC3\x9C",
+ 'uuml' => "\xC3\xBC",
+ 'Uuml;' => "\xC3\x9C",
+ 'uuml;' => "\xC3\xBC",
+ 'weierp;' => "\xE2\x84\x98",
+ 'Xi;' => "\xCE\x9E",
+ 'xi;' => "\xCE\xBE",
+ 'Yacute' => "\xC3\x9D",
+ 'yacute' => "\xC3\xBD",
+ 'Yacute;' => "\xC3\x9D",
+ 'yacute;' => "\xC3\xBD",
+ 'yen' => "\xC2\xA5",
+ 'yen;' => "\xC2\xA5",
+ 'yuml' => "\xC3\xBF",
+ 'Yuml;' => "\xC5\xB8",
+ 'yuml;' => "\xC3\xBF",
+ 'Zeta;' => "\xCE\x96",
+ 'zeta;' => "\xCE\xB6",
+ 'zwj;' => "\xE2\x80\x8D",
+ 'zwnj;' => "\xE2\x80\x8C"
+ );
+
+ for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
+ {
+ $consumed = substr($this->consumed, 1);
+ if (isset($entities[$consumed]))
+ {
+ $match = $consumed;
+ }
+ }
+
+ if ($match !== null)
+ {
+ $this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
+ $this->position += strlen($entities[$match]) - strlen($consumed) - 1;
+ }
+ break;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Enclosure.php b/src/wp-includes/SimplePie/Enclosure.php
new file mode 100644
index 0000000000..55674379c2
--- /dev/null
+++ b/src/wp-includes/SimplePie/Enclosure.php
@@ -0,0 +1,1380 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Handles everything related to enclosures (including Media RSS and iTunes RSS)
+ *
+ * Used by {@see SimplePie_Item::get_enclosure()} and {@see SimplePie_Item::get_enclosures()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_enclosure_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Enclosure
+{
+ /**
+ * @var string
+ * @see get_bitrate()
+ */
+ var $bitrate;
+
+ /**
+ * @var array
+ * @see get_captions()
+ */
+ var $captions;
+
+ /**
+ * @var array
+ * @see get_categories()
+ */
+ var $categories;
+
+ /**
+ * @var int
+ * @see get_channels()
+ */
+ var $channels;
+
+ /**
+ * @var SimplePie_Copyright
+ * @see get_copyright()
+ */
+ var $copyright;
+
+ /**
+ * @var array
+ * @see get_credits()
+ */
+ var $credits;
+
+ /**
+ * @var string
+ * @see get_description()
+ */
+ var $description;
+
+ /**
+ * @var int
+ * @see get_duration()
+ */
+ var $duration;
+
+ /**
+ * @var string
+ * @see get_expression()
+ */
+ var $expression;
+
+ /**
+ * @var string
+ * @see get_framerate()
+ */
+ var $framerate;
+
+ /**
+ * @var string
+ * @see get_handler()
+ */
+ var $handler;
+
+ /**
+ * @var array
+ * @see get_hashes()
+ */
+ var $hashes;
+
+ /**
+ * @var string
+ * @see get_height()
+ */
+ var $height;
+
+ /**
+ * @deprecated
+ * @var null
+ */
+ var $javascript;
+
+ /**
+ * @var array
+ * @see get_keywords()
+ */
+ var $keywords;
+
+ /**
+ * @var string
+ * @see get_language()
+ */
+ var $lang;
+
+ /**
+ * @var string
+ * @see get_length()
+ */
+ var $length;
+
+ /**
+ * @var string
+ * @see get_link()
+ */
+ var $link;
+
+ /**
+ * @var string
+ * @see get_medium()
+ */
+ var $medium;
+
+ /**
+ * @var string
+ * @see get_player()
+ */
+ var $player;
+
+ /**
+ * @var array
+ * @see get_ratings()
+ */
+ var $ratings;
+
+ /**
+ * @var array
+ * @see get_restrictions()
+ */
+ var $restrictions;
+
+ /**
+ * @var string
+ * @see get_sampling_rate()
+ */
+ var $samplingrate;
+
+ /**
+ * @var array
+ * @see get_thumbnails()
+ */
+ var $thumbnails;
+
+ /**
+ * @var string
+ * @see get_title()
+ */
+ var $title;
+
+ /**
+ * @var string
+ * @see get_type()
+ */
+ var $type;
+
+ /**
+ * @var string
+ * @see get_width()
+ */
+ var $width;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ *
+ * @uses idna_convert If available, this will convert an IDN
+ */
+ public function __construct($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
+ {
+ $this->bitrate = $bitrate;
+ $this->captions = $captions;
+ $this->categories = $categories;
+ $this->channels = $channels;
+ $this->copyright = $copyright;
+ $this->credits = $credits;
+ $this->description = $description;
+ $this->duration = $duration;
+ $this->expression = $expression;
+ $this->framerate = $framerate;
+ $this->hashes = $hashes;
+ $this->height = $height;
+ $this->keywords = $keywords;
+ $this->lang = $lang;
+ $this->length = $length;
+ $this->link = $link;
+ $this->medium = $medium;
+ $this->player = $player;
+ $this->ratings = $ratings;
+ $this->restrictions = $restrictions;
+ $this->samplingrate = $samplingrate;
+ $this->thumbnails = $thumbnails;
+ $this->title = $title;
+ $this->type = $type;
+ $this->width = $width;
+
+ if (class_exists('idna_convert'))
+ {
+ $idn = new idna_convert();
+ $parsed = SimplePie_Misc::parse_url($link);
+ $this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+ }
+ $this->handler = $this->get_handler(); // Needs to load last
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the bitrate
+ *
+ * @return string|null
+ */
+ public function get_bitrate()
+ {
+ if ($this->bitrate !== null)
+ {
+ return $this->bitrate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single caption
+ *
+ * @param int $key
+ * @return SimplePie_Caption|null
+ */
+ public function get_caption($key = 0)
+ {
+ $captions = $this->get_captions();
+ if (isset($captions[$key]))
+ {
+ return $captions[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all captions
+ *
+ * @return array|null Array of {@see SimplePie_Caption} objects
+ */
+ public function get_captions()
+ {
+ if ($this->captions !== null)
+ {
+ return $this->captions;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single category
+ *
+ * @param int $key
+ * @return SimplePie_Category|null
+ */
+ public function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all categories
+ *
+ * @return array|null Array of {@see SimplePie_Category} objects
+ */
+ public function get_categories()
+ {
+ if ($this->categories !== null)
+ {
+ return $this->categories;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the number of audio channels
+ *
+ * @return int|null
+ */
+ public function get_channels()
+ {
+ if ($this->channels !== null)
+ {
+ return $this->channels;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the copyright information
+ *
+ * @return SimplePie_Copyright|null
+ */
+ public function get_copyright()
+ {
+ if ($this->copyright !== null)
+ {
+ return $this->copyright;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single credit
+ *
+ * @param int $key
+ * @return SimplePie_Credit|null
+ */
+ public function get_credit($key = 0)
+ {
+ $credits = $this->get_credits();
+ if (isset($credits[$key]))
+ {
+ return $credits[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all credits
+ *
+ * @return array|null Array of {@see SimplePie_Credit} objects
+ */
+ public function get_credits()
+ {
+ if ($this->credits !== null)
+ {
+ return $this->credits;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the description of the enclosure
+ *
+ * @return string|null
+ */
+ public function get_description()
+ {
+ if ($this->description !== null)
+ {
+ return $this->description;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the duration of the enclosure
+ *
+ * @param string $convert Convert seconds into hh:mm:ss
+ * @return string|int|null 'hh:mm:ss' string if `$convert` was specified, otherwise integer (or null if none found)
+ */
+ public function get_duration($convert = false)
+ {
+ if ($this->duration !== null)
+ {
+ if ($convert)
+ {
+ $time = SimplePie_Misc::time_hms($this->duration);
+ return $time;
+ }
+ else
+ {
+ return $this->duration;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the expression
+ *
+ * @return string Probably one of 'sample', 'full', 'nonstop', 'clip'. Defaults to 'full'
+ */
+ public function get_expression()
+ {
+ if ($this->expression !== null)
+ {
+ return $this->expression;
+ }
+ else
+ {
+ return 'full';
+ }
+ }
+
+ /**
+ * Get the file extension
+ *
+ * @return string|null
+ */
+ public function get_extension()
+ {
+ if ($this->link !== null)
+ {
+ $url = SimplePie_Misc::parse_url($this->link);
+ if ($url['path'] !== '')
+ {
+ return pathinfo($url['path'], PATHINFO_EXTENSION);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the framerate (in frames-per-second)
+ *
+ * @return string|null
+ */
+ public function get_framerate()
+ {
+ if ($this->framerate !== null)
+ {
+ return $this->framerate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the preferred handler
+ *
+ * @return string|null One of 'flash', 'fmedia', 'quicktime', 'wmedia', 'mp3'
+ */
+ public function get_handler()
+ {
+ return $this->get_real_type(true);
+ }
+
+ /**
+ * Get a single hash
+ *
+ * @link http://www.rssboard.org/media-rss#media-hash
+ * @param int $key
+ * @return string|null Hash as per `media:hash`, prefixed with "$algo:"
+ */
+ public function get_hash($key = 0)
+ {
+ $hashes = $this->get_hashes();
+ if (isset($hashes[$key]))
+ {
+ return $hashes[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all credits
+ *
+ * @return array|null Array of strings, see {@see get_hash()}
+ */
+ public function get_hashes()
+ {
+ if ($this->hashes !== null)
+ {
+ return $this->hashes;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the height
+ *
+ * @return string|null
+ */
+ public function get_height()
+ {
+ if ($this->height !== null)
+ {
+ return $this->height;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the language
+ *
+ * @link http://tools.ietf.org/html/rfc3066
+ * @return string|null Language code as per RFC 3066
+ */
+ public function get_language()
+ {
+ if ($this->lang !== null)
+ {
+ return $this->lang;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single keyword
+ *
+ * @param int $key
+ * @return string|null
+ */
+ public function get_keyword($key = 0)
+ {
+ $keywords = $this->get_keywords();
+ if (isset($keywords[$key]))
+ {
+ return $keywords[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all keywords
+ *
+ * @return array|null Array of strings
+ */
+ public function get_keywords()
+ {
+ if ($this->keywords !== null)
+ {
+ return $this->keywords;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get length
+ *
+ * @return float Length in bytes
+ */
+ public function get_length()
+ {
+ if ($this->length !== null)
+ {
+ return $this->length;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the URL
+ *
+ * @return string|null
+ */
+ public function get_link()
+ {
+ if ($this->link !== null)
+ {
+ return urldecode($this->link);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the medium
+ *
+ * @link http://www.rssboard.org/media-rss#media-content
+ * @return string|null Should be one of 'image', 'audio', 'video', 'document', 'executable'
+ */
+ public function get_medium()
+ {
+ if ($this->medium !== null)
+ {
+ return $this->medium;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the player URL
+ *
+ * Typically the same as {@see get_permalink()}
+ * @return string|null Player URL
+ */
+ public function get_player()
+ {
+ if ($this->player !== null)
+ {
+ return $this->player;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single rating
+ *
+ * @param int $key
+ * @return SimplePie_Rating|null
+ */
+ public function get_rating($key = 0)
+ {
+ $ratings = $this->get_ratings();
+ if (isset($ratings[$key]))
+ {
+ return $ratings[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all ratings
+ *
+ * @return array|null Array of {@see SimplePie_Rating} objects
+ */
+ public function get_ratings()
+ {
+ if ($this->ratings !== null)
+ {
+ return $this->ratings;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single restriction
+ *
+ * @param int $key
+ * @return SimplePie_Restriction|null
+ */
+ public function get_restriction($key = 0)
+ {
+ $restrictions = $this->get_restrictions();
+ if (isset($restrictions[$key]))
+ {
+ return $restrictions[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all restrictions
+ *
+ * @return array|null Array of {@see SimplePie_Restriction} objects
+ */
+ public function get_restrictions()
+ {
+ if ($this->restrictions !== null)
+ {
+ return $this->restrictions;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the sampling rate (in kHz)
+ *
+ * @return string|null
+ */
+ public function get_sampling_rate()
+ {
+ if ($this->samplingrate !== null)
+ {
+ return $this->samplingrate;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the file size (in MiB)
+ *
+ * @return float|null File size in mebibytes (1048 bytes)
+ */
+ public function get_size()
+ {
+ $length = $this->get_length();
+ if ($length !== null)
+ {
+ return round($length/1048576, 2);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single thumbnail
+ *
+ * @param int $key
+ * @return string|null Thumbnail URL
+ */
+ public function get_thumbnail($key = 0)
+ {
+ $thumbnails = $this->get_thumbnails();
+ if (isset($thumbnails[$key]))
+ {
+ return $thumbnails[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all thumbnails
+ *
+ * @return array|null Array of thumbnail URLs
+ */
+ public function get_thumbnails()
+ {
+ if ($this->thumbnails !== null)
+ {
+ return $this->thumbnails;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the title
+ *
+ * @return string|null
+ */
+ public function get_title()
+ {
+ if ($this->title !== null)
+ {
+ return $this->title;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get mimetype of the enclosure
+ *
+ * @see get_real_type()
+ * @return string|null MIME type
+ */
+ public function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the width
+ *
+ * @return string|null
+ */
+ public function get_width()
+ {
+ if ($this->width !== null)
+ {
+ return $this->width;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Embed the enclosure using `<embed>`
+ *
+ * @deprecated Use the second parameter to {@see embed} instead
+ *
+ * @param array|string $options See first paramter to {@see embed}
+ * @return string HTML string to output
+ */
+ public function native_embed($options='')
+ {
+ return $this->embed($options, true);
+ }
+
+ /**
+ * Embed the enclosure using Javascript
+ *
+ * `$options` is an array or comma-separated key:value string, with the
+ * following properties:
+ *
+ * - `alt` (string): Alternate content for when an end-user does not have
+ * the appropriate handler installed or when a file type is
+ * unsupported. Can be any text or HTML. Defaults to blank.
+ * - `altclass` (string): If a file type is unsupported, the end-user will
+ * see the alt text (above) linked directly to the content. That link
+ * will have this value as its class name. Defaults to blank.
+ * - `audio` (string): This is an image that should be used as a
+ * placeholder for audio files before they're loaded (QuickTime-only).
+ * Can be any relative or absolute URL. Defaults to blank.
+ * - `bgcolor` (string): The background color for the media, if not
+ * already transparent. Defaults to `#ffffff`.
+ * - `height` (integer): The height of the embedded media. Accepts any
+ * numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
+ * and it is recommended that you use this default.
+ * - `loop` (boolean): Do you want the media to loop when its done?
+ * Defaults to `false`.
+ * - `mediaplayer` (string): The location of the included
+ * `mediaplayer.swf` file. This allows for the playback of Flash Video
+ * (`.flv`) files, and is the default handler for non-Odeo MP3's.
+ * Defaults to blank.
+ * - `video` (string): This is an image that should be used as a
+ * placeholder for video files before they're loaded (QuickTime-only).
+ * Can be any relative or absolute URL. Defaults to blank.
+ * - `width` (integer): The width of the embedded media. Accepts any
+ * numeric pixel value (such as `480`) or `auto`. Defaults to `auto`,
+ * and it is recommended that you use this default.
+ * - `widescreen` (boolean): Is the enclosure widescreen or standard?
+ * This applies only to video enclosures, and will automatically resize
+ * the content appropriately. Defaults to `false`, implying 4:3 mode.
+ *
+ * Note: Non-widescreen (4:3) mode with `width` and `height` set to `auto`
+ * will default to 480x360 video resolution. Widescreen (16:9) mode with
+ * `width` and `height` set to `auto` will default to 480x270 video resolution.
+ *
+ * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
+ * @param array|string $options Comma-separated key:value list, or array
+ * @param bool $native Use `<embed>`
+ * @return string HTML string to output
+ */
+ public function embed($options = '', $native = false)
+ {
+ // Set up defaults
+ $audio = '';
+ $video = '';
+ $alt = '';
+ $altclass = '';
+ $loop = 'false';
+ $width = 'auto';
+ $height = 'auto';
+ $bgcolor = '#ffffff';
+ $mediaplayer = '';
+ $widescreen = false;
+ $handler = $this->get_handler();
+ $type = $this->get_real_type();
+
+ // Process options and reassign values as necessary
+ if (is_array($options))
+ {
+ extract($options);
+ }
+ else
+ {
+ $options = explode(',', $options);
+ foreach($options as $option)
+ {
+ $opt = explode(':', $option, 2);
+ if (isset($opt[0], $opt[1]))
+ {
+ $opt[0] = trim($opt[0]);
+ $opt[1] = trim($opt[1]);
+ switch ($opt[0])
+ {
+ case 'audio':
+ $audio = $opt[1];
+ break;
+
+ case 'video':
+ $video = $opt[1];
+ break;
+
+ case 'alt':
+ $alt = $opt[1];
+ break;
+
+ case 'altclass':
+ $altclass = $opt[1];
+ break;
+
+ case 'loop':
+ $loop = $opt[1];
+ break;
+
+ case 'width':
+ $width = $opt[1];
+ break;
+
+ case 'height':
+ $height = $opt[1];
+ break;
+
+ case 'bgcolor':
+ $bgcolor = $opt[1];
+ break;
+
+ case 'mediaplayer':
+ $mediaplayer = $opt[1];
+ break;
+
+ case 'widescreen':
+ $widescreen = $opt[1];
+ break;
+ }
+ }
+ }
+ }
+
+ $mime = explode('/', $type, 2);
+ $mime = $mime[0];
+
+ // Process values for 'auto'
+ if ($width === 'auto')
+ {
+ if ($mime === 'video')
+ {
+ if ($height === 'auto')
+ {
+ $width = 480;
+ }
+ elseif ($widescreen)
+ {
+ $width = round((intval($height)/9)*16);
+ }
+ else
+ {
+ $width = round((intval($height)/3)*4);
+ }
+ }
+ else
+ {
+ $width = '100%';
+ }
+ }
+
+ if ($height === 'auto')
+ {
+ if ($mime === 'audio')
+ {
+ $height = 0;
+ }
+ elseif ($mime === 'video')
+ {
+ if ($width === 'auto')
+ {
+ if ($widescreen)
+ {
+ $height = 270;
+ }
+ else
+ {
+ $height = 360;
+ }
+ }
+ elseif ($widescreen)
+ {
+ $height = round((intval($width)/16)*9);
+ }
+ else
+ {
+ $height = round((intval($width)/4)*3);
+ }
+ }
+ else
+ {
+ $height = 376;
+ }
+ }
+ elseif ($mime === 'audio')
+ {
+ $height = 0;
+ }
+
+ // Set proper placeholder value
+ if ($mime === 'audio')
+ {
+ $placeholder = $audio;
+ }
+ elseif ($mime === 'video')
+ {
+ $placeholder = $video;
+ }
+
+ $embed = '';
+
+ // Flash
+ if ($handler === 'flash')
+ {
+ if ($native)
+ {
+ $embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
+ }
+ }
+
+ // Flash Media Player file types.
+ // Preferred handler for MP3 file types.
+ elseif ($handler === 'fmedia' || ($handler === 'mp3' && $mediaplayer !== ''))
+ {
+ $height += 20;
+ if ($native)
+ {
+ $embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
+ }
+ }
+
+ // QuickTime 7 file types. Need to test with QuickTime 6.
+ // Only handle MP3's if the Flash Media Player is not present.
+ elseif ($handler === 'quicktime' || ($handler === 'mp3' && $mediaplayer === ''))
+ {
+ $height += 16;
+ if ($native)
+ {
+ if ($placeholder !== '')
+ {
+ $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+ }
+ else
+ {
+ $embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+ }
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
+ }
+ }
+
+ // Windows Media
+ elseif ($handler === 'wmedia')
+ {
+ $height += 45;
+ if ($native)
+ {
+ $embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
+ }
+ else
+ {
+ $embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
+ }
+ }
+
+ // Everything else
+ else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
+
+ return $embed;
+ }
+
+ /**
+ * Get the real media type
+ *
+ * Often, feeds lie to us, necessitating a bit of deeper inspection. This
+ * converts types to their canonical representations based on the file
+ * extension
+ *
+ * @see get_type()
+ * @param bool $find_handler Internal use only, use {@see get_handler()} instead
+ * @return string MIME type
+ */
+ public function get_real_type($find_handler = false)
+ {
+ // Mime-types by handler.
+ $types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
+ $types_fmedia = array('video/flv', 'video/x-flv','flv-application/octet-stream'); // Flash Media Player
+ $types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
+ $types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
+ $types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
+
+ if ($this->get_type() !== null)
+ {
+ $type = strtolower($this->type);
+ }
+ else
+ {
+ $type = null;
+ }
+
+ // If we encounter an unsupported mime-type, check the file extension and guess intelligently.
+ if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
+ {
+ switch (strtolower($this->get_extension()))
+ {
+ // Audio mime-types
+ case 'aac':
+ case 'adts':
+ $type = 'audio/acc';
+ break;
+
+ case 'aif':
+ case 'aifc':
+ case 'aiff':
+ case 'cdda':
+ $type = 'audio/aiff';
+ break;
+
+ case 'bwf':
+ $type = 'audio/wav';
+ break;
+
+ case 'kar':
+ case 'mid':
+ case 'midi':
+ case 'smf':
+ $type = 'audio/midi';
+ break;
+
+ case 'm4a':
+ $type = 'audio/x-m4a';
+ break;
+
+ case 'mp3':
+ case 'swa':
+ $type = 'audio/mp3';
+ break;
+
+ case 'wav':
+ $type = 'audio/wav';
+ break;
+
+ case 'wax':
+ $type = 'audio/x-ms-wax';
+ break;
+
+ case 'wma':
+ $type = 'audio/x-ms-wma';
+ break;
+
+ // Video mime-types
+ case '3gp':
+ case '3gpp':
+ $type = 'video/3gpp';
+ break;
+
+ case '3g2':
+ case '3gp2':
+ $type = 'video/3gpp2';
+ break;
+
+ case 'asf':
+ $type = 'video/x-ms-asf';
+ break;
+
+ case 'flv':
+ $type = 'video/x-flv';
+ break;
+
+ case 'm1a':
+ case 'm1s':
+ case 'm1v':
+ case 'm15':
+ case 'm75':
+ case 'mp2':
+ case 'mpa':
+ case 'mpeg':
+ case 'mpg':
+ case 'mpm':
+ case 'mpv':
+ $type = 'video/mpeg';
+ break;
+
+ case 'm4v':
+ $type = 'video/x-m4v';
+ break;
+
+ case 'mov':
+ case 'qt':
+ $type = 'video/quicktime';
+ break;
+
+ case 'mp4':
+ case 'mpg4':
+ $type = 'video/mp4';
+ break;
+
+ case 'sdv':
+ $type = 'video/sd-video';
+ break;
+
+ case 'wm':
+ $type = 'video/x-ms-wm';
+ break;
+
+ case 'wmv':
+ $type = 'video/x-ms-wmv';
+ break;
+
+ case 'wvx':
+ $type = 'video/x-ms-wvx';
+ break;
+
+ // Flash mime-types
+ case 'spl':
+ $type = 'application/futuresplash';
+ break;
+
+ case 'swf':
+ $type = 'application/x-shockwave-flash';
+ break;
+ }
+ }
+
+ if ($find_handler)
+ {
+ if (in_array($type, $types_flash))
+ {
+ return 'flash';
+ }
+ elseif (in_array($type, $types_fmedia))
+ {
+ return 'fmedia';
+ }
+ elseif (in_array($type, $types_quicktime))
+ {
+ return 'quicktime';
+ }
+ elseif (in_array($type, $types_wmedia))
+ {
+ return 'wmedia';
+ }
+ elseif (in_array($type, $types_mp3))
+ {
+ return 'mp3';
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return $type;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Exception.php b/src/wp-includes/SimplePie/Exception.php
new file mode 100644
index 0000000000..73e104d697
--- /dev/null
+++ b/src/wp-includes/SimplePie/Exception.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.4-dev
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * General SimplePie exception class
+ *
+ * @package SimplePie
+ */
+class SimplePie_Exception extends Exception
+{
+} \ No newline at end of file
diff --git a/src/wp-includes/SimplePie/File.php b/src/wp-includes/SimplePie/File.php
new file mode 100644
index 0000000000..b7d1a2ac9b
--- /dev/null
+++ b/src/wp-includes/SimplePie/File.php
@@ -0,0 +1,292 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Used for fetching remote files and reading local files
+ *
+ * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
+ *
+ * This class can be overloaded with {@see SimplePie::set_file_class()}
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @todo Move to properly supporting RFC2616 (HTTP/1.1)
+ */
+class SimplePie_File
+{
+ var $url;
+ var $useragent;
+ var $success = true;
+ var $headers = array();
+ var $body;
+ var $status_code;
+ var $redirects = 0;
+ var $error;
+ var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+
+ public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
+ {
+ if (class_exists('idna_convert'))
+ {
+ $idn = new idna_convert();
+ $parsed = SimplePie_Misc::parse_url($url);
+ $url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+ }
+ $this->url = $url;
+ $this->useragent = $useragent;
+ if (preg_match('/^http(s)?:\/\//i', $url))
+ {
+ if ($useragent === null)
+ {
+ $useragent = ini_get('user_agent');
+ $this->useragent = $useragent;
+ }
+ if (!is_array($headers))
+ {
+ $headers = array();
+ }
+ if (!$force_fsockopen && function_exists('curl_exec'))
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
+ $fp = curl_init();
+ $headers2 = array();
+ foreach ($headers as $key => $value)
+ {
+ $headers2[] = "$key: $value";
+ }
+ if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
+ {
+ curl_setopt($fp, CURLOPT_ENCODING, '');
+ }
+ curl_setopt($fp, CURLOPT_URL, $url);
+ curl_setopt($fp, CURLOPT_HEADER, 1);
+ curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
+ curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
+ curl_setopt($fp, CURLOPT_REFERER, $url);
+ curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
+ curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
+ if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
+ {
+ curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
+ curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
+ }
+
+ $this->headers = curl_exec($fp);
+ if (curl_errno($fp) === 23 || curl_errno($fp) === 61)
+ {
+ curl_setopt($fp, CURLOPT_ENCODING, 'none');
+ $this->headers = curl_exec($fp);
+ }
+ if (curl_errno($fp))
+ {
+ $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
+ $this->success = false;
+ }
+ else
+ {
+ $info = curl_getinfo($fp);
+ curl_close($fp);
+ $this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
+ $this->headers = array_pop($this->headers);
+ $parser = new SimplePie_HTTP_Parser($this->headers);
+ if ($parser->parse())
+ {
+ $this->headers = $parser->headers;
+ $this->body = $parser->body;
+ $this->status_code = $parser->status_code;
+ if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+ {
+ $this->redirects++;
+ $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+ return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
+ $url_parts = parse_url($url);
+ $socket_host = $url_parts['host'];
+ if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https')
+ {
+ $socket_host = "ssl://$url_parts[host]";
+ $url_parts['port'] = 443;
+ }
+ if (!isset($url_parts['port']))
+ {
+ $url_parts['port'] = 80;
+ }
+ $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
+ if (!$fp)
+ {
+ $this->error = 'fsockopen error: ' . $errstr;
+ $this->success = false;
+ }
+ else
+ {
+ stream_set_timeout($fp, $timeout);
+ if (isset($url_parts['path']))
+ {
+ if (isset($url_parts['query']))
+ {
+ $get = "$url_parts[path]?$url_parts[query]";
+ }
+ else
+ {
+ $get = $url_parts['path'];
+ }
+ }
+ else
+ {
+ $get = '/';
+ }
+ $out = "GET $get HTTP/1.1\r\n";
+ $out .= "Host: $url_parts[host]\r\n";
+ $out .= "User-Agent: $useragent\r\n";
+ if (extension_loaded('zlib'))
+ {
+ $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
+ }
+
+ if (isset($url_parts['user']) && isset($url_parts['pass']))
+ {
+ $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
+ }
+ foreach ($headers as $key => $value)
+ {
+ $out .= "$key: $value\r\n";
+ }
+ $out .= "Connection: Close\r\n\r\n";
+ fwrite($fp, $out);
+
+ $info = stream_get_meta_data($fp);
+
+ $this->headers = '';
+ while (!$info['eof'] && !$info['timed_out'])
+ {
+ $this->headers .= fread($fp, 1160);
+ $info = stream_get_meta_data($fp);
+ }
+ if (!$info['timed_out'])
+ {
+ $parser = new SimplePie_HTTP_Parser($this->headers);
+ if ($parser->parse())
+ {
+ $this->headers = $parser->headers;
+ $this->body = $parser->body;
+ $this->status_code = $parser->status_code;
+ if ((in_array($this->status_code, array(300, 301, 302, 303, 307)) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+ {
+ $this->redirects++;
+ $location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+ return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ }
+ if (isset($this->headers['content-encoding']))
+ {
+ // Hey, we act dumb elsewhere, so let's do that here too
+ switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20")))
+ {
+ case 'gzip':
+ case 'x-gzip':
+ $decoder = new SimplePie_gzdecode($this->body);
+ if (!$decoder->parse())
+ {
+ $this->error = 'Unable to decode HTTP "gzip" stream';
+ $this->success = false;
+ }
+ else
+ {
+ $this->body = $decoder->data;
+ }
+ break;
+
+ case 'deflate':
+ if (($decompressed = gzinflate($this->body)) !== false)
+ {
+ $this->body = $decompressed;
+ }
+ else if (($decompressed = gzuncompress($this->body)) !== false)
+ {
+ $this->body = $decompressed;
+ }
+ else if (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false)
+ {
+ $this->body = $decompressed;
+ }
+ else
+ {
+ $this->error = 'Unable to decode HTTP "deflate" stream';
+ $this->success = false;
+ }
+ break;
+
+ default:
+ $this->error = 'Unknown content coding';
+ $this->success = false;
+ }
+ }
+ }
+ }
+ else
+ {
+ $this->error = 'fsocket timed out';
+ $this->success = false;
+ }
+ fclose($fp);
+ }
+ }
+ }
+ else
+ {
+ $this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
+ if (!$this->body = file_get_contents($url))
+ {
+ $this->error = 'file_get_contents could not read the file';
+ $this->success = false;
+ }
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/HTTP/Parser.php b/src/wp-includes/SimplePie/HTTP/Parser.php
new file mode 100644
index 0000000000..bff2222b2c
--- /dev/null
+++ b/src/wp-includes/SimplePie/HTTP/Parser.php
@@ -0,0 +1,500 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * HTTP Response Parser
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ */
+class SimplePie_HTTP_Parser
+{
+ /**
+ * HTTP Version
+ *
+ * @var float
+ */
+ public $http_version = 0.0;
+
+ /**
+ * Status code
+ *
+ * @var int
+ */
+ public $status_code = 0;
+
+ /**
+ * Reason phrase
+ *
+ * @var string
+ */
+ public $reason = '';
+
+ /**
+ * Key/value pairs of the headers
+ *
+ * @var array
+ */
+ public $headers = array();
+
+ /**
+ * Body of the response
+ *
+ * @var string
+ */
+ public $body = '';
+
+ /**
+ * Current state of the state machine
+ *
+ * @var string
+ */
+ protected $state = 'http_version';
+
+ /**
+ * Input data
+ *
+ * @var string
+ */
+ protected $data = '';
+
+ /**
+ * Input data length (to avoid calling strlen() everytime this is needed)
+ *
+ * @var int
+ */
+ protected $data_length = 0;
+
+ /**
+ * Current position of the pointer
+ *
+ * @var int
+ */
+ protected $position = 0;
+
+ /**
+ * Name of the hedaer currently being parsed
+ *
+ * @var string
+ */
+ protected $name = '';
+
+ /**
+ * Value of the hedaer currently being parsed
+ *
+ * @var string
+ */
+ protected $value = '';
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @param string $data Input data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ $this->data_length = strlen($this->data);
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @return bool true on success, false on failure
+ */
+ public function parse()
+ {
+ while ($this->state && $this->state !== 'emit' && $this->has_data())
+ {
+ $state = $this->state;
+ $this->$state();
+ }
+ $this->data = '';
+ if ($this->state === 'emit' || $this->state === 'body')
+ {
+ return true;
+ }
+ else
+ {
+ $this->http_version = '';
+ $this->status_code = '';
+ $this->reason = '';
+ $this->headers = array();
+ $this->body = '';
+ return false;
+ }
+ }
+
+ /**
+ * Check whether there is data beyond the pointer
+ *
+ * @return bool true if there is further data, false if not
+ */
+ protected function has_data()
+ {
+ return (bool) ($this->position < $this->data_length);
+ }
+
+ /**
+ * See if the next character is LWS
+ *
+ * @return bool true if the next character is LWS, false if not
+ */
+ protected function is_linear_whitespace()
+ {
+ return (bool) ($this->data[$this->position] === "\x09"
+ || $this->data[$this->position] === "\x20"
+ || ($this->data[$this->position] === "\x0A"
+ && isset($this->data[$this->position + 1])
+ && ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
+ }
+
+ /**
+ * Parse the HTTP version
+ */
+ protected function http_version()
+ {
+ if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
+ {
+ $len = strspn($this->data, '0123456789.', 5);
+ $this->http_version = substr($this->data, 5, $len);
+ $this->position += 5 + $len;
+ if (substr_count($this->http_version, '.') <= 1)
+ {
+ $this->http_version = (float) $this->http_version;
+ $this->position += strspn($this->data, "\x09\x20", $this->position);
+ $this->state = 'status';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse the status code
+ */
+ protected function status()
+ {
+ if ($len = strspn($this->data, '0123456789', $this->position))
+ {
+ $this->status_code = (int) substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'reason';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse the reason phrase
+ */
+ protected function reason()
+ {
+ $len = strcspn($this->data, "\x0A", $this->position);
+ $this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
+ $this->position += $len + 1;
+ $this->state = 'new_line';
+ }
+
+ /**
+ * Deal with a new line, shifting data around as needed
+ */
+ protected function new_line()
+ {
+ $this->value = trim($this->value, "\x0D\x20");
+ if ($this->name !== '' && $this->value !== '')
+ {
+ $this->name = strtolower($this->name);
+ // We should only use the last Content-Type header. c.f. issue #1
+ if (isset($this->headers[$this->name]) && $this->name !== 'content-type')
+ {
+ $this->headers[$this->name] .= ', ' . $this->value;
+ }
+ else
+ {
+ $this->headers[$this->name] = $this->value;
+ }
+ }
+ $this->name = '';
+ $this->value = '';
+ if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
+ {
+ $this->position += 2;
+ $this->state = 'body';
+ }
+ elseif ($this->data[$this->position] === "\x0A")
+ {
+ $this->position++;
+ $this->state = 'body';
+ }
+ else
+ {
+ $this->state = 'name';
+ }
+ }
+
+ /**
+ * Parse a header name
+ */
+ protected function name()
+ {
+ $len = strcspn($this->data, "\x0A:", $this->position);
+ if (isset($this->data[$this->position + $len]))
+ {
+ if ($this->data[$this->position + $len] === "\x0A")
+ {
+ $this->position += $len;
+ $this->state = 'new_line';
+ }
+ else
+ {
+ $this->name = substr($this->data, $this->position, $len);
+ $this->position += $len + 1;
+ $this->state = 'value';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ /**
+ * Parse LWS, replacing consecutive LWS characters with a single space
+ */
+ protected function linear_whitespace()
+ {
+ do
+ {
+ if (substr($this->data, $this->position, 2) === "\x0D\x0A")
+ {
+ $this->position += 2;
+ }
+ elseif ($this->data[$this->position] === "\x0A")
+ {
+ $this->position++;
+ }
+ $this->position += strspn($this->data, "\x09\x20", $this->position);
+ } while ($this->has_data() && $this->is_linear_whitespace());
+ $this->value .= "\x20";
+ }
+
+ /**
+ * See what state to move to while within non-quoted header values
+ */
+ protected function value()
+ {
+ if ($this->is_linear_whitespace())
+ {
+ $this->linear_whitespace();
+ }
+ else
+ {
+ switch ($this->data[$this->position])
+ {
+ case '"':
+ // Workaround for ETags: we have to include the quotes as
+ // part of the tag.
+ if (strtolower($this->name) === 'etag')
+ {
+ $this->value .= '"';
+ $this->position++;
+ $this->state = 'value_char';
+ break;
+ }
+ $this->position++;
+ $this->state = 'quote';
+ break;
+
+ case "\x0A":
+ $this->position++;
+ $this->state = 'new_line';
+ break;
+
+ default:
+ $this->state = 'value_char';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a header value while outside quotes
+ */
+ protected function value_char()
+ {
+ $len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
+ $this->value .= substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'value';
+ }
+
+ /**
+ * See what state to move to while within quoted header values
+ */
+ protected function quote()
+ {
+ if ($this->is_linear_whitespace())
+ {
+ $this->linear_whitespace();
+ }
+ else
+ {
+ switch ($this->data[$this->position])
+ {
+ case '"':
+ $this->position++;
+ $this->state = 'value';
+ break;
+
+ case "\x0A":
+ $this->position++;
+ $this->state = 'new_line';
+ break;
+
+ case '\\':
+ $this->position++;
+ $this->state = 'quote_escaped';
+ break;
+
+ default:
+ $this->state = 'quote_char';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Parse a header value while within quotes
+ */
+ protected function quote_char()
+ {
+ $len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
+ $this->value .= substr($this->data, $this->position, $len);
+ $this->position += $len;
+ $this->state = 'value';
+ }
+
+ /**
+ * Parse an escaped character within quotes
+ */
+ protected function quote_escaped()
+ {
+ $this->value .= $this->data[$this->position];
+ $this->position++;
+ $this->state = 'quote';
+ }
+
+ /**
+ * Parse the body
+ */
+ protected function body()
+ {
+ $this->body = substr($this->data, $this->position);
+ if (!empty($this->headers['transfer-encoding']))
+ {
+ unset($this->headers['transfer-encoding']);
+ $this->state = 'chunked';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+
+ /**
+ * Parsed a "Transfer-Encoding: chunked" body
+ */
+ protected function chunked()
+ {
+ if (!preg_match('/^([0-9a-f]+)[^\r\n]*\r\n/i', trim($this->body)))
+ {
+ $this->state = 'emit';
+ return;
+ }
+
+ $decoded = '';
+ $encoded = $this->body;
+
+ while (true)
+ {
+ $is_chunked = (bool) preg_match( '/^([0-9a-f]+)[^\r\n]*\r\n/i', $encoded, $matches );
+ if (!$is_chunked)
+ {
+ // Looks like it's not chunked after all
+ $this->state = 'emit';
+ return;
+ }
+
+ $length = hexdec(trim($matches[1]));
+ if ($length === 0)
+ {
+ // Ignore trailer headers
+ $this->state = 'emit';
+ $this->body = $decoded;
+ return;
+ }
+
+ $chunk_length = strlen($matches[0]);
+ $decoded .= $part = substr($encoded, $chunk_length, $length);
+ $encoded = substr($encoded, $chunk_length + $length + 2);
+
+ if (trim($encoded) === '0' || empty($encoded))
+ {
+ $this->state = 'emit';
+ $this->body = $decoded;
+ return;
+ }
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/IRI.php b/src/wp-includes/SimplePie/IRI.php
new file mode 100644
index 0000000000..d3198c04ff
--- /dev/null
+++ b/src/wp-includes/SimplePie/IRI.php
@@ -0,0 +1,1238 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * IRI parser/serialiser/normaliser
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @author Geoffrey Sneddon
+ * @author Steve Minutillo
+ * @author Ryan McCue
+ * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ */
+class SimplePie_IRI
+{
+ /**
+ * Scheme
+ *
+ * @var string
+ */
+ protected $scheme = null;
+
+ /**
+ * User Information
+ *
+ * @var string
+ */
+ protected $iuserinfo = null;
+
+ /**
+ * ihost
+ *
+ * @var string
+ */
+ protected $ihost = null;
+
+ /**
+ * Port
+ *
+ * @var string
+ */
+ protected $port = null;
+
+ /**
+ * ipath
+ *
+ * @var string
+ */
+ protected $ipath = '';
+
+ /**
+ * iquery
+ *
+ * @var string
+ */
+ protected $iquery = null;
+
+ /**
+ * ifragment
+ *
+ * @var string
+ */
+ protected $ifragment = null;
+
+ /**
+ * Normalization database
+ *
+ * Each key is the scheme, each value is an array with each key as the IRI
+ * part and value as the default value for that part.
+ */
+ protected $normalization = array(
+ 'acap' => array(
+ 'port' => 674
+ ),
+ 'dict' => array(
+ 'port' => 2628
+ ),
+ 'file' => array(
+ 'ihost' => 'localhost'
+ ),
+ 'http' => array(
+ 'port' => 80,
+ 'ipath' => '/'
+ ),
+ 'https' => array(
+ 'port' => 443,
+ 'ipath' => '/'
+ ),
+ );
+
+ /**
+ * Return the entire IRI when you try and read the object as a string
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->get_iri();
+ }
+
+ /**
+ * Overload __set() to provide access via properties
+ *
+ * @param string $name Property name
+ * @param mixed $value Property value
+ */
+ public function __set($name, $value)
+ {
+ if (method_exists($this, 'set_' . $name))
+ {
+ call_user_func(array($this, 'set_' . $name), $value);
+ }
+ elseif (
+ $name === 'iauthority'
+ || $name === 'iuserinfo'
+ || $name === 'ihost'
+ || $name === 'ipath'
+ || $name === 'iquery'
+ || $name === 'ifragment'
+ )
+ {
+ call_user_func(array($this, 'set_' . substr($name, 1)), $value);
+ }
+ }
+
+ /**
+ * Overload __get() to provide access via properties
+ *
+ * @param string $name Property name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ // isset() returns false for null, we don't want to do that
+ // Also why we use array_key_exists below instead of isset()
+ $props = get_object_vars($this);
+
+ if (
+ $name === 'iri' ||
+ $name === 'uri' ||
+ $name === 'iauthority' ||
+ $name === 'authority'
+ )
+ {
+ $return = $this->{"get_$name"}();
+ }
+ elseif (array_key_exists($name, $props))
+ {
+ $return = $this->$name;
+ }
+ // host -> ihost
+ elseif (($prop = 'i' . $name) && array_key_exists($prop, $props))
+ {
+ $name = $prop;
+ $return = $this->$prop;
+ }
+ // ischeme -> scheme
+ elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props))
+ {
+ $name = $prop;
+ $return = $this->$prop;
+ }
+ else
+ {
+ trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE);
+ $return = null;
+ }
+
+ if ($return === null && isset($this->normalization[$this->scheme][$name]))
+ {
+ return $this->normalization[$this->scheme][$name];
+ }
+ else
+ {
+ return $return;
+ }
+ }
+
+ /**
+ * Overload __isset() to provide access via properties
+ *
+ * @param string $name Property name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ if (method_exists($this, 'get_' . $name) || isset($this->$name))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Overload __unset() to provide access via properties
+ *
+ * @param string $name Property name
+ */
+ public function __unset($name)
+ {
+ if (method_exists($this, 'set_' . $name))
+ {
+ call_user_func(array($this, 'set_' . $name), '');
+ }
+ }
+
+ /**
+ * Create a new IRI object, from a specified string
+ *
+ * @param string $iri
+ */
+ public function __construct($iri = null)
+ {
+ $this->set_iri($iri);
+ }
+
+ /**
+ * Create a new IRI object by resolving a relative IRI
+ *
+ * Returns false if $base is not absolute, otherwise an IRI.
+ *
+ * @param IRI|string $base (Absolute) Base IRI
+ * @param IRI|string $relative Relative IRI
+ * @return IRI|false
+ */
+ public static function absolutize($base, $relative)
+ {
+ if (!($relative instanceof SimplePie_IRI))
+ {
+ $relative = new SimplePie_IRI($relative);
+ }
+ if (!$relative->is_valid())
+ {
+ return false;
+ }
+ elseif ($relative->scheme !== null)
+ {
+ return clone $relative;
+ }
+ else
+ {
+ if (!($base instanceof SimplePie_IRI))
+ {
+ $base = new SimplePie_IRI($base);
+ }
+ if ($base->scheme !== null && $base->is_valid())
+ {
+ if ($relative->get_iri() !== '')
+ {
+ if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null)
+ {
+ $target = clone $relative;
+ $target->scheme = $base->scheme;
+ }
+ else
+ {
+ $target = new SimplePie_IRI;
+ $target->scheme = $base->scheme;
+ $target->iuserinfo = $base->iuserinfo;
+ $target->ihost = $base->ihost;
+ $target->port = $base->port;
+ if ($relative->ipath !== '')
+ {
+ if ($relative->ipath[0] === '/')
+ {
+ $target->ipath = $relative->ipath;
+ }
+ elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '')
+ {
+ $target->ipath = '/' . $relative->ipath;
+ }
+ elseif (($last_segment = strrpos($base->ipath, '/')) !== false)
+ {
+ $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath;
+ }
+ else
+ {
+ $target->ipath = $relative->ipath;
+ }
+ $target->ipath = $target->remove_dot_segments($target->ipath);
+ $target->iquery = $relative->iquery;
+ }
+ else
+ {
+ $target->ipath = $base->ipath;
+ if ($relative->iquery !== null)
+ {
+ $target->iquery = $relative->iquery;
+ }
+ elseif ($base->iquery !== null)
+ {
+ $target->iquery = $base->iquery;
+ }
+ }
+ $target->ifragment = $relative->ifragment;
+ }
+ }
+ else
+ {
+ $target = clone $base;
+ $target->ifragment = null;
+ }
+ $target->scheme_normalization();
+ return $target;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Parse an IRI into scheme/authority/path/query/fragment segments
+ *
+ * @param string $iri
+ * @return array
+ */
+ protected function parse_iri($iri)
+ {
+ $iri = trim($iri, "\x20\x09\x0A\x0C\x0D");
+ if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match))
+ {
+ if ($match[1] === '')
+ {
+ $match['scheme'] = null;
+ }
+ if (!isset($match[3]) || $match[3] === '')
+ {
+ $match['authority'] = null;
+ }
+ if (!isset($match[5]))
+ {
+ $match['path'] = '';
+ }
+ if (!isset($match[6]) || $match[6] === '')
+ {
+ $match['query'] = null;
+ }
+ if (!isset($match[8]) || $match[8] === '')
+ {
+ $match['fragment'] = null;
+ }
+ return $match;
+ }
+ else
+ {
+ // This can occur when a paragraph is accidentally parsed as a URI
+ return false;
+ }
+ }
+
+ /**
+ * Remove dot segments from a path
+ *
+ * @param string $input
+ * @return string
+ */
+ protected function remove_dot_segments($input)
+ {
+ $output = '';
+ while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
+ {
+ // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
+ if (strpos($input, '../') === 0)
+ {
+ $input = substr($input, 3);
+ }
+ elseif (strpos($input, './') === 0)
+ {
+ $input = substr($input, 2);
+ }
+ // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
+ elseif (strpos($input, '/./') === 0)
+ {
+ $input = substr($input, 2);
+ }
+ elseif ($input === '/.')
+ {
+ $input = '/';
+ }
+ // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
+ elseif (strpos($input, '/../') === 0)
+ {
+ $input = substr($input, 3);
+ $output = substr_replace($output, '', strrpos($output, '/'));
+ }
+ elseif ($input === '/..')
+ {
+ $input = '/';
+ $output = substr_replace($output, '', strrpos($output, '/'));
+ }
+ // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
+ elseif ($input === '.' || $input === '..')
+ {
+ $input = '';
+ }
+ // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
+ elseif (($pos = strpos($input, '/', 1)) !== false)
+ {
+ $output .= substr($input, 0, $pos);
+ $input = substr_replace($input, '', 0, $pos);
+ }
+ else
+ {
+ $output .= $input;
+ $input = '';
+ }
+ }
+ return $output . $input;
+ }
+
+ /**
+ * Replace invalid character with percent encoding
+ *
+ * @param string $string Input string
+ * @param string $extra_chars Valid characters not in iunreserved or
+ * iprivate (this is ASCII-only)
+ * @param bool $iprivate Allow iprivate
+ * @return string
+ */
+ protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false)
+ {
+ // Normalize as many pct-encoded sections as possible
+ $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string);
+
+ // Replace invalid percent characters
+ $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
+
+ // Add unreserved and % to $extra_chars (the latter is safe because all
+ // pct-encoded sections are now valid).
+ $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
+
+ // Now replace any bytes that aren't allowed with their pct-encoded versions
+ $position = 0;
+ $strlen = strlen($string);
+ while (($position += strspn($string, $extra_chars, $position)) < $strlen)
+ {
+ $value = ord($string[$position]);
+
+ // Start position
+ $start = $position;
+
+ // By default we are valid
+ $valid = true;
+
+ // No one byte sequences are valid due to the while.
+ // Two byte sequence:
+ if (($value & 0xE0) === 0xC0)
+ {
+ $character = ($value & 0x1F) << 6;
+ $length = 2;
+ $remaining = 1;
+ }
+ // Three byte sequence:
+ elseif (($value & 0xF0) === 0xE0)
+ {
+ $character = ($value & 0x0F) << 12;
+ $length = 3;
+ $remaining = 2;
+ }
+ // Four byte sequence:
+ elseif (($value & 0xF8) === 0xF0)
+ {
+ $character = ($value & 0x07) << 18;
+ $length = 4;
+ $remaining = 3;
+ }
+ // Invalid byte:
+ else
+ {
+ $valid = false;
+ $length = 1;
+ $remaining = 0;
+ }
+
+ if ($remaining)
+ {
+ if ($position + $length <= $strlen)
+ {
+ for ($position++; $remaining; $position++)
+ {
+ $value = ord($string[$position]);
+
+ // Check that the byte is valid, then add it to the character:
+ if (($value & 0xC0) === 0x80)
+ {
+ $character |= ($value & 0x3F) << (--$remaining * 6);
+ }
+ // If it is invalid, count the sequence as invalid and reprocess the current byte:
+ else
+ {
+ $valid = false;
+ $position--;
+ break;
+ }
+ }
+ }
+ else
+ {
+ $position = $strlen - 1;
+ $valid = false;
+ }
+ }
+
+ // Percent encode anything invalid or not in ucschar
+ if (
+ // Invalid sequences
+ !$valid
+ // Non-shortest form sequences are invalid
+ || $length > 1 && $character <= 0x7F
+ || $length > 2 && $character <= 0x7FF
+ || $length > 3 && $character <= 0xFFFF
+ // Outside of range of ucschar codepoints
+ // Noncharacters
+ || ($character & 0xFFFE) === 0xFFFE
+ || $character >= 0xFDD0 && $character <= 0xFDEF
+ || (
+ // Everything else not in ucschar
+ $character > 0xD7FF && $character < 0xF900
+ || $character < 0xA0
+ || $character > 0xEFFFD
+ )
+ && (
+ // Everything not in iprivate, if it applies
+ !$iprivate
+ || $character < 0xE000
+ || $character > 0x10FFFD
+ )
+ )
+ {
+ // If we were a character, pretend we weren't, but rather an error.
+ if ($valid)
+ $position--;
+
+ for ($j = $start; $j <= $position; $j++)
+ {
+ $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
+ $j += 2;
+ $position += 2;
+ $strlen += 2;
+ }
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Callback function for preg_replace_callback.
+ *
+ * Removes sequences of percent encoded bytes that represent UTF-8
+ * encoded characters in iunreserved
+ *
+ * @param array $match PCRE match
+ * @return string Replacement
+ */
+ protected function remove_iunreserved_percent_encoded($match)
+ {
+ // As we just have valid percent encoded sequences we can just explode
+ // and ignore the first member of the returned array (an empty string).
+ $bytes = explode('%', $match[0]);
+
+ // Initialize the new string (this is what will be returned) and that
+ // there are no bytes remaining in the current sequence (unsurprising
+ // at the first byte!).
+ $string = '';
+ $remaining = 0;
+
+ // Loop over each and every byte, and set $value to its value
+ for ($i = 1, $len = count($bytes); $i < $len; $i++)
+ {
+ $value = hexdec($bytes[$i]);
+
+ // If we're the first byte of sequence:
+ if (!$remaining)
+ {
+ // Start position
+ $start = $i;
+
+ // By default we are valid
+ $valid = true;
+
+ // One byte sequence:
+ if ($value <= 0x7F)
+ {
+ $character = $value;
+ $length = 1;
+ }
+ // Two byte sequence:
+ elseif (($value & 0xE0) === 0xC0)
+ {
+ $character = ($value & 0x1F) << 6;
+ $length = 2;
+ $remaining = 1;
+ }
+ // Three byte sequence:
+ elseif (($value & 0xF0) === 0xE0)
+ {
+ $character = ($value & 0x0F) << 12;
+ $length = 3;
+ $remaining = 2;
+ }
+ // Four byte sequence:
+ elseif (($value & 0xF8) === 0xF0)
+ {
+ $character = ($value & 0x07) << 18;
+ $length = 4;
+ $remaining = 3;
+ }
+ // Invalid byte:
+ else
+ {
+ $valid = false;
+ $remaining = 0;
+ }
+ }
+ // Continuation byte:
+ else
+ {
+ // Check that the byte is valid, then add it to the character:
+ if (($value & 0xC0) === 0x80)
+ {
+ $remaining--;
+ $character |= ($value & 0x3F) << ($remaining * 6);
+ }
+ // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
+ else
+ {
+ $valid = false;
+ $remaining = 0;
+ $i--;
+ }
+ }
+
+ // If we've reached the end of the current byte sequence, append it to Unicode::$data
+ if (!$remaining)
+ {
+ // Percent encode anything invalid or not in iunreserved
+ if (
+ // Invalid sequences
+ !$valid
+ // Non-shortest form sequences are invalid
+ || $length > 1 && $character <= 0x7F
+ || $length > 2 && $character <= 0x7FF
+ || $length > 3 && $character <= 0xFFFF
+ // Outside of range of iunreserved codepoints
+ || $character < 0x2D
+ || $character > 0xEFFFD
+ // Noncharacters
+ || ($character & 0xFFFE) === 0xFFFE
+ || $character >= 0xFDD0 && $character <= 0xFDEF
+ // Everything else not in iunreserved (this is all BMP)
+ || $character === 0x2F
+ || $character > 0x39 && $character < 0x41
+ || $character > 0x5A && $character < 0x61
+ || $character > 0x7A && $character < 0x7E
+ || $character > 0x7E && $character < 0xA0
+ || $character > 0xD7FF && $character < 0xF900
+ )
+ {
+ for ($j = $start; $j <= $i; $j++)
+ {
+ $string .= '%' . strtoupper($bytes[$j]);
+ }
+ }
+ else
+ {
+ for ($j = $start; $j <= $i; $j++)
+ {
+ $string .= chr(hexdec($bytes[$j]));
+ }
+ }
+ }
+ }
+
+ // If we have any bytes left over they are invalid (i.e., we are
+ // mid-way through a multi-byte sequence)
+ if ($remaining)
+ {
+ for ($j = $start; $j < $len; $j++)
+ {
+ $string .= '%' . strtoupper($bytes[$j]);
+ }
+ }
+
+ return $string;
+ }
+
+ protected function scheme_normalization()
+ {
+ if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo'])
+ {
+ $this->iuserinfo = null;
+ }
+ if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost'])
+ {
+ $this->ihost = null;
+ }
+ if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port'])
+ {
+ $this->port = null;
+ }
+ if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath'])
+ {
+ $this->ipath = '';
+ }
+ if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery'])
+ {
+ $this->iquery = null;
+ }
+ if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment'])
+ {
+ $this->ifragment = null;
+ }
+ }
+
+ /**
+ * Check if the object represents a valid IRI. This needs to be done on each
+ * call as some things change depending on another part of the IRI.
+ *
+ * @return bool
+ */
+ public function is_valid()
+ {
+ $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null;
+ if ($this->ipath !== '' &&
+ (
+ $isauthority && (
+ $this->ipath[0] !== '/' ||
+ substr($this->ipath, 0, 2) === '//'
+ ) ||
+ (
+ $this->scheme === null &&
+ !$isauthority &&
+ strpos($this->ipath, ':') !== false &&
+ (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/'))
+ )
+ )
+ )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Set the entire IRI. Returns true on success, false on failure (if there
+ * are any invalid characters).
+ *
+ * @param string $iri
+ * @return bool
+ */
+ public function set_iri($iri)
+ {
+ static $cache;
+ if (!$cache)
+ {
+ $cache = array();
+ }
+
+ if ($iri === null)
+ {
+ return true;
+ }
+ elseif (isset($cache[$iri]))
+ {
+ list($this->scheme,
+ $this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $this->ipath,
+ $this->iquery,
+ $this->ifragment,
+ $return) = $cache[$iri];
+ return $return;
+ }
+ else
+ {
+ $parsed = $this->parse_iri((string) $iri);
+ if (!$parsed)
+ {
+ return false;
+ }
+
+ $return = $this->set_scheme($parsed['scheme'])
+ && $this->set_authority($parsed['authority'])
+ && $this->set_path($parsed['path'])
+ && $this->set_query($parsed['query'])
+ && $this->set_fragment($parsed['fragment']);
+
+ $cache[$iri] = array($this->scheme,
+ $this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $this->ipath,
+ $this->iquery,
+ $this->ifragment,
+ $return);
+ return $return;
+ }
+ }
+
+ /**
+ * Set the scheme. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $scheme
+ * @return bool
+ */
+ public function set_scheme($scheme)
+ {
+ if ($scheme === null)
+ {
+ $this->scheme = null;
+ }
+ elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme))
+ {
+ $this->scheme = null;
+ return false;
+ }
+ else
+ {
+ $this->scheme = strtolower($scheme);
+ }
+ return true;
+ }
+
+ /**
+ * Set the authority. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $authority
+ * @return bool
+ */
+ public function set_authority($authority)
+ {
+ static $cache;
+ if (!$cache)
+ $cache = array();
+
+ if ($authority === null)
+ {
+ $this->iuserinfo = null;
+ $this->ihost = null;
+ $this->port = null;
+ return true;
+ }
+ elseif (isset($cache[$authority]))
+ {
+ list($this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $return) = $cache[$authority];
+
+ return $return;
+ }
+ else
+ {
+ $remaining = $authority;
+ if (($iuserinfo_end = strrpos($remaining, '@')) !== false)
+ {
+ $iuserinfo = substr($remaining, 0, $iuserinfo_end);
+ $remaining = substr($remaining, $iuserinfo_end + 1);
+ }
+ else
+ {
+ $iuserinfo = null;
+ }
+ if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false)
+ {
+ if (($port = substr($remaining, $port_start + 1)) === false)
+ {
+ $port = null;
+ }
+ $remaining = substr($remaining, 0, $port_start);
+ }
+ else
+ {
+ $port = null;
+ }
+
+ $return = $this->set_userinfo($iuserinfo) &&
+ $this->set_host($remaining) &&
+ $this->set_port($port);
+
+ $cache[$authority] = array($this->iuserinfo,
+ $this->ihost,
+ $this->port,
+ $return);
+
+ return $return;
+ }
+ }
+
+ /**
+ * Set the iuserinfo.
+ *
+ * @param string $iuserinfo
+ * @return bool
+ */
+ public function set_userinfo($iuserinfo)
+ {
+ if ($iuserinfo === null)
+ {
+ $this->iuserinfo = null;
+ }
+ else
+ {
+ $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:');
+ $this->scheme_normalization();
+ }
+
+ return true;
+ }
+
+ /**
+ * Set the ihost. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $ihost
+ * @return bool
+ */
+ public function set_host($ihost)
+ {
+ if ($ihost === null)
+ {
+ $this->ihost = null;
+ return true;
+ }
+ elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']')
+ {
+ if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1)))
+ {
+ $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']';
+ }
+ else
+ {
+ $this->ihost = null;
+ return false;
+ }
+ }
+ else
+ {
+ $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;=');
+
+ // Lowercase, but ignore pct-encoded sections (as they should
+ // remain uppercase). This must be done after the previous step
+ // as that can add unescaped characters.
+ $position = 0;
+ $strlen = strlen($ihost);
+ while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen)
+ {
+ if ($ihost[$position] === '%')
+ {
+ $position += 3;
+ }
+ else
+ {
+ $ihost[$position] = strtolower($ihost[$position]);
+ $position++;
+ }
+ }
+
+ $this->ihost = $ihost;
+ }
+
+ $this->scheme_normalization();
+
+ return true;
+ }
+
+ /**
+ * Set the port. Returns true on success, false on failure (if there are
+ * any invalid characters).
+ *
+ * @param string $port
+ * @return bool
+ */
+ public function set_port($port)
+ {
+ if ($port === null)
+ {
+ $this->port = null;
+ return true;
+ }
+ elseif (strspn($port, '0123456789') === strlen($port))
+ {
+ $this->port = (int) $port;
+ $this->scheme_normalization();
+ return true;
+ }
+ else
+ {
+ $this->port = null;
+ return false;
+ }
+ }
+
+ /**
+ * Set the ipath.
+ *
+ * @param string $ipath
+ * @return bool
+ */
+ public function set_path($ipath)
+ {
+ static $cache;
+ if (!$cache)
+ {
+ $cache = array();
+ }
+
+ $ipath = (string) $ipath;
+
+ if (isset($cache[$ipath]))
+ {
+ $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)];
+ }
+ else
+ {
+ $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/');
+ $removed = $this->remove_dot_segments($valid);
+
+ $cache[$ipath] = array($valid, $removed);
+ $this->ipath = ($this->scheme !== null) ? $removed : $valid;
+ }
+
+ $this->scheme_normalization();
+ return true;
+ }
+
+ /**
+ * Set the iquery.
+ *
+ * @param string $iquery
+ * @return bool
+ */
+ public function set_query($iquery)
+ {
+ if ($iquery === null)
+ {
+ $this->iquery = null;
+ }
+ else
+ {
+ $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true);
+ $this->scheme_normalization();
+ }
+ return true;
+ }
+
+ /**
+ * Set the ifragment.
+ *
+ * @param string $ifragment
+ * @return bool
+ */
+ public function set_fragment($ifragment)
+ {
+ if ($ifragment === null)
+ {
+ $this->ifragment = null;
+ }
+ else
+ {
+ $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?');
+ $this->scheme_normalization();
+ }
+ return true;
+ }
+
+ /**
+ * Convert an IRI to a URI (or parts thereof)
+ *
+ * @return string
+ */
+ public function to_uri($string)
+ {
+ static $non_ascii;
+ if (!$non_ascii)
+ {
+ $non_ascii = implode('', range("\x80", "\xFF"));
+ }
+
+ $position = 0;
+ $strlen = strlen($string);
+ while (($position += strcspn($string, $non_ascii, $position)) < $strlen)
+ {
+ $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1);
+ $position += 3;
+ $strlen += 2;
+ }
+
+ return $string;
+ }
+
+ /**
+ * Get the complete IRI
+ *
+ * @return string
+ */
+ public function get_iri()
+ {
+ if (!$this->is_valid())
+ {
+ return false;
+ }
+
+ $iri = '';
+ if ($this->scheme !== null)
+ {
+ $iri .= $this->scheme . ':';
+ }
+ if (($iauthority = $this->get_iauthority()) !== null)
+ {
+ $iri .= '//' . $iauthority;
+ }
+ if ($this->ipath !== '')
+ {
+ $iri .= $this->ipath;
+ }
+ elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '')
+ {
+ $iri .= $this->normalization[$this->scheme]['ipath'];
+ }
+ if ($this->iquery !== null)
+ {
+ $iri .= '?' . $this->iquery;
+ }
+ if ($this->ifragment !== null)
+ {
+ $iri .= '#' . $this->ifragment;
+ }
+
+ return $iri;
+ }
+
+ /**
+ * Get the complete URI
+ *
+ * @return string
+ */
+ public function get_uri()
+ {
+ return $this->to_uri($this->get_iri());
+ }
+
+ /**
+ * Get the complete iauthority
+ *
+ * @return string
+ */
+ protected function get_iauthority()
+ {
+ if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null)
+ {
+ $iauthority = '';
+ if ($this->iuserinfo !== null)
+ {
+ $iauthority .= $this->iuserinfo . '@';
+ }
+ if ($this->ihost !== null)
+ {
+ $iauthority .= $this->ihost;
+ }
+ if ($this->port !== null)
+ {
+ $iauthority .= ':' . $this->port;
+ }
+ return $iauthority;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the complete authority
+ *
+ * @return string
+ */
+ protected function get_authority()
+ {
+ $iauthority = $this->get_iauthority();
+ if (is_string($iauthority))
+ return $this->to_uri($iauthority);
+ else
+ return $iauthority;
+ }
+}
diff --git a/src/wp-includes/SimplePie/Item.php b/src/wp-includes/SimplePie/Item.php
new file mode 100644
index 0000000000..a77574b37e
--- /dev/null
+++ b/src/wp-includes/SimplePie/Item.php
@@ -0,0 +1,2964 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Manages all item-related data
+ *
+ * Used by {@see SimplePie::get_item()} and {@see SimplePie::get_items()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_item_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Item
+{
+ /**
+ * Parent feed
+ *
+ * @access private
+ * @var SimplePie
+ */
+ var $feed;
+
+ /**
+ * Raw data
+ *
+ * @access private
+ * @var array
+ */
+ var $data = array();
+
+ /**
+ * Registry object
+ *
+ * @see set_registry
+ * @var SimplePie_Registry
+ */
+ protected $registry;
+
+ /**
+ * Create a new item object
+ *
+ * This is usually used by {@see SimplePie::get_items} and
+ * {@see SimplePie::get_item}. Avoid creating this manually.
+ *
+ * @param SimplePie $feed Parent feed
+ * @param array $data Raw data
+ */
+ public function __construct($feed, $data)
+ {
+ $this->feed = $feed;
+ $this->data = $data;
+ }
+
+ /**
+ * Set the registry handler
+ *
+ * This is usually used by {@see SimplePie_Registry::create}
+ *
+ * @since 1.3
+ * @param SimplePie_Registry $registry
+ */
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ /**
+ * Get a string representation of the item
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ /**
+ * Remove items that link back to this before destroying this object
+ */
+ public function __destruct()
+ {
+ if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
+ {
+ unset($this->feed);
+ }
+ }
+
+ /**
+ * Get data for an item-level element
+ *
+ * This method allows you to get access to ANY element/attribute that is a
+ * sub-element of the item/entry tag.
+ *
+ * See {@see SimplePie::get_feed_tags()} for a description of the return value
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_item_tags($namespace, $tag)
+ {
+ if (isset($this->data['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][$namespace][$tag];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the base URL value from the parent feed
+ *
+ * Uses `<xml:base>`
+ *
+ * @param array $element
+ * @return string
+ */
+ public function get_base($element = array())
+ {
+ return $this->feed->get_base($element);
+ }
+
+ /**
+ * Sanitize feed data
+ *
+ * @access private
+ * @see SimplePie::sanitize()
+ * @param string $data Data to sanitize
+ * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
+ * @param string $base Base URL to resolve URLs against
+ * @return string Sanitized data
+ */
+ public function sanitize($data, $type, $base = '')
+ {
+ return $this->feed->sanitize($data, $type, $base);
+ }
+
+ /**
+ * Get the parent feed
+ *
+ * Note: this may not work as you think for multifeeds!
+ *
+ * @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
+ * @since 1.0
+ * @return SimplePie
+ */
+ public function get_feed()
+ {
+ return $this->feed;
+ }
+
+ /**
+ * Get the unique identifier for the item
+ *
+ * This is usually used when writing code to check for new items in a feed.
+ *
+ * Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
+ * for RDF. If none of these are supplied (or `$hash` is true), creates an
+ * MD5 hash based on the permalink and title. If either of those are not
+ * supplied, creates a hash based on the full feed data.
+ *
+ * @since Beta 2
+ * @param boolean $hash Should we force using a hash instead of the supplied ID?
+ * @return string
+ */
+ public function get_id($hash = false)
+ {
+ if (!$hash)
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about']))
+ {
+ return $this->sanitize($this->data['attribs'][SIMPLEPIE_NAMESPACE_RDF]['about'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (($return = $this->get_permalink()) !== null)
+ {
+ return $return;
+ }
+ elseif (($return = $this->get_title()) !== null)
+ {
+ return $return;
+ }
+ }
+ if ($this->get_permalink() !== null || $this->get_title() !== null)
+ {
+ return md5($this->get_permalink() . $this->get_title());
+ }
+ else
+ {
+ return md5(serialize($this->data));
+ }
+ }
+
+ /**
+ * Get the title of the item
+ *
+ * Uses `<atom:title>`, `<title>` or `<dc:title>`
+ *
+ * @since Beta 2 (previously called `get_item_title` since 0.8)
+ * @return string|null
+ */
+ public function get_title()
+ {
+ if (!isset($this->data['title']))
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ $this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $this->data['title'] = null;
+ }
+ }
+ return $this->data['title'];
+ }
+
+ /**
+ * Get the content for the item
+ *
+ * Prefers summaries over full content , but will return full content if a
+ * summary does not exist.
+ *
+ * To prefer full content instead, use {@see get_content}
+ *
+ * Uses `<atom:summary>`, `<description>`, `<dc:description>` or
+ * `<itunes:subtitle>`
+ *
+ * @since 0.8
+ * @param boolean $description_only Should we avoid falling back to the content?
+ * @return string|null
+ */
+ public function get_description($description_only = false)
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML);
+ }
+
+ elseif (!$description_only)
+ {
+ return $this->get_content(true);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the content for the item
+ *
+ * Prefers full content over summaries, but will return a summary if full
+ * content does not exist.
+ *
+ * To prefer summaries instead, use {@see get_description}
+ *
+ * Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
+ *
+ * @since 1.0
+ * @param boolean $content_only Should we avoid falling back to the description?
+ * @return string|null
+ */
+ public function get_content($content_only = false)
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_content_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif (!$content_only)
+ {
+ return $this->get_description(true);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a category for the item
+ *
+ * @since Beta 3 (previously called `get_categories()` since Beta 2)
+ * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Category|null
+ */
+ public function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all categories for the item
+ *
+ * Uses `<atom:category>`, `<category>` or `<dc:subject>`
+ *
+ * @since Beta 3
+ * @return array|null List of {@see SimplePie_Category} objects
+ */
+ public function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
+ {
+ // This is really the label, but keep this as the term also for BC.
+ // Label will also work on retrieving because that falls back to term.
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ if (isset($category['attribs']['']['domain']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = null;
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, null));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($categories))
+ {
+ return array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get an author for the item
+ *
+ * @since Beta 2
+ * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a contributor for the item
+ *
+ * @since 1.1
+ * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all contributors for the item
+ *
+ * Uses `<atom:contributor>`
+ *
+ * @since 1.1
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all authors for the item
+ *
+ * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
+ *
+ * @since Beta 2
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+ if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'author'))
+ {
+ $authors[] = $this->registry->create('Author', array(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT)));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($authors))
+ {
+ return array_unique($authors);
+ }
+ elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
+ {
+ return $authors;
+ }
+ elseif ($authors = $this->feed->get_authors())
+ {
+ return $authors;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the copyright info for the item
+ *
+ * Uses `<atom:rights>` or `<dc:rights>`
+ *
+ * @since 1.1
+ * @return string
+ */
+ public function get_copyright()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the posting date/time for the item
+ *
+ * Uses `<atom:published>`, `<atom:updated>`, `<atom:issued>`,
+ * `<atom:modified>`, `<pubDate>` or `<dc:date>`
+ *
+ * Note: obeys PHP's timezone setting. To get a UTC date/time, use
+ * {@see get_gmdate}
+ *
+ * @since Beta 2 (previously called `get_item_date` since 0.8)
+ *
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
+ * @return int|string|null
+ */
+ public function get_date($date_format = 'j F Y, g:i a')
+ {
+ if (!isset($this->data['date']))
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'pubDate'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
+ {
+ $this->data['date']['raw'] = $return[0]['data'];
+ }
+
+ if (!empty($this->data['date']['raw']))
+ {
+ $parser = $this->registry->call('Parse_Date', 'get');
+ $this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
+ }
+ else
+ {
+ $this->data['date'] = null;
+ }
+ }
+ if ($this->data['date'])
+ {
+ $date_format = (string) $date_format;
+ switch ($date_format)
+ {
+ case '':
+ return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
+
+ case 'U':
+ return $this->data['date']['parsed'];
+
+ default:
+ return date($date_format, $this->data['date']['parsed']);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the update date/time for the item
+ *
+ * Uses `<atom:updated>`
+ *
+ * Note: obeys PHP's timezone setting. To get a UTC date/time, use
+ * {@see get_gmdate}
+ *
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date} (empty for the raw data)
+ * @return int|string|null
+ */
+ public function get_updated_date($date_format = 'j F Y, g:i a')
+ {
+ if (!isset($this->data['updated']))
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
+ {
+ $this->data['updated']['raw'] = $return[0]['data'];
+ }
+
+ if (!empty($this->data['updated']['raw']))
+ {
+ $parser = $this->registry->call('Parse_Date', 'get');
+ $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
+ }
+ else
+ {
+ $this->data['updated'] = null;
+ }
+ }
+ if ($this->data['updated'])
+ {
+ $date_format = (string) $date_format;
+ switch ($date_format)
+ {
+ case '':
+ return $this->sanitize($this->data['updated']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
+
+ case 'U':
+ return $this->data['updated']['parsed'];
+
+ default:
+ return date($date_format, $this->data['updated']['parsed']);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the localized posting date/time for the item
+ *
+ * Returns the date formatted in the localized language. To display in
+ * languages other than the server's default, you need to change the locale
+ * with {@link http://php.net/setlocale setlocale()}. The available
+ * localizations depend on which ones are installed on your web server.
+ *
+ * @since 1.0
+ *
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/strftime} (empty for the raw data)
+ * @return int|string|null
+ */
+ public function get_local_date($date_format = '%c')
+ {
+ if (!$date_format)
+ {
+ return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (($date = $this->get_date('U')) !== null && $date !== false)
+ {
+ return strftime($date_format, $date);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the posting date/time for the item (UTC time)
+ *
+ * @see get_date
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
+ * @return int|string|null
+ */
+ public function get_gmdate($date_format = 'j F Y, g:i a')
+ {
+ $date = $this->get_date('U');
+ if ($date === null)
+ {
+ return null;
+ }
+
+ return gmdate($date_format, $date);
+ }
+
+ /**
+ * Get the update date/time for the item (UTC time)
+ *
+ * @see get_updated_date
+ * @param string $date_format Supports any PHP date format from {@see http://php.net/date}
+ * @return int|string|null
+ */
+ public function get_updated_gmdate($date_format = 'j F Y, g:i a')
+ {
+ $date = $this->get_updated_date('U');
+ if ($date === null)
+ {
+ return null;
+ }
+
+ return gmdate($date_format, $date);
+ }
+
+ /**
+ * Get the permalink for the item
+ *
+ * Returns the first link available with a relationship of "alternate".
+ * Identical to {@see get_link()} with key 0
+ *
+ * @see get_link
+ * @since 0.8
+ * @return string|null Permalink URL
+ */
+ public function get_permalink()
+ {
+ $link = $this->get_link();
+ $enclosure = $this->get_enclosure(0);
+ if ($link !== null)
+ {
+ return $link;
+ }
+ elseif ($enclosure !== null)
+ {
+ return $enclosure->get_link();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single link for the item
+ *
+ * @since Beta 3
+ * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
+ * @param string $rel The relationship of the link to return
+ * @return string|null Link URL
+ */
+ public function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if ($links[$key] !== null)
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all links for the item
+ *
+ * Uses `<atom:link>`, `<link>` or `<guid>`
+ *
+ * @since Beta 2
+ * @param string $rel The relationship of links to return
+ * @return array|null Links found for the item (strings)
+ */
+ public function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'guid'))
+ {
+ if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) === 'true')
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get an enclosure from the item
+ *
+ * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
+ *
+ * @since Beta 2
+ * @todo Add ability to prefer one type of content over another (in a media group).
+ * @param int $key The enclosure that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Enclosure|null
+ */
+ public function get_enclosure($key = 0, $prefer = null)
+ {
+ $enclosures = $this->get_enclosures();
+ if (isset($enclosures[$key]))
+ {
+ return $enclosures[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all available enclosures (podcasts, etc.)
+ *
+ * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
+ *
+ * At this point, we're pretty much assuming that all enclosures for an item
+ * are the same content. Anything else is too complicated to
+ * properly support.
+ *
+ * @since Beta 2
+ * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
+ * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
+ * @return array|null List of SimplePie_Enclosure items
+ */
+ public function get_enclosures()
+ {
+ if (!isset($this->data['enclosures']))
+ {
+ $this->data['enclosures'] = array();
+
+ // Elements
+ $captions_parent = null;
+ $categories_parent = null;
+ $copyrights_parent = null;
+ $credits_parent = null;
+ $description_parent = null;
+ $duration_parent = null;
+ $hashes_parent = null;
+ $keywords_parent = null;
+ $player_parent = null;
+ $ratings_parent = null;
+ $restrictions_parent = null;
+ $thumbnails_parent = null;
+ $title_parent = null;
+
+ // Let's do the channel and item-level ones first, and just re-use them if we need to.
+ $parent = $this->get_feed();
+
+ // CAPTIONS
+ if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
+ {
+ foreach ($captions as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
+ }
+ }
+ elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
+ {
+ foreach ($captions as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions_parent[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
+ }
+ }
+ if (is_array($captions_parent))
+ {
+ $captions_parent = array_values(array_unique($captions_parent));
+ }
+
+ // CATEGORIES
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
+ {
+ $term = null;
+ $scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
+ $label = null;
+ if (isset($category['attribs']['']['text']))
+ {
+ $label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
+
+ if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
+ {
+ foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
+ {
+ if (isset($subcategory['attribs']['']['text']))
+ {
+ $label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories_parent[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ }
+ }
+ if (is_array($categories_parent))
+ {
+ $categories_parent = array_values(array_unique($categories_parent));
+ }
+
+ // COPYRIGHT
+ if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($copyright[0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($copyright[0]['data']))
+ {
+ $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
+ }
+ elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($copyright[0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($copyright[0]['data']))
+ {
+ $copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights_parent = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
+ }
+
+ // CREDITS
+ if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
+ {
+ foreach ($credits as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
+ }
+ }
+ elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
+ {
+ foreach ($credits as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits_parent[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
+ }
+ }
+ if (is_array($credits_parent))
+ {
+ $credits_parent = array_values(array_unique($credits_parent));
+ }
+
+ // DESCRIPTION
+ if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
+ {
+ if (isset($description_parent[0]['data']))
+ {
+ $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+ elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
+ {
+ if (isset($description_parent[0]['data']))
+ {
+ $description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+
+ // DURATION
+ if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
+ {
+ $seconds = null;
+ $minutes = null;
+ $hours = null;
+ if (isset($duration_parent[0]['data']))
+ {
+ $temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ if (sizeof($temp) > 0)
+ {
+ $seconds = (int) array_pop($temp);
+ }
+ if (sizeof($temp) > 0)
+ {
+ $minutes = (int) array_pop($temp);
+ $seconds += $minutes * 60;
+ }
+ if (sizeof($temp) > 0)
+ {
+ $hours = (int) array_pop($temp);
+ $seconds += $hours * 3600;
+ }
+ unset($temp);
+ $duration_parent = $seconds;
+ }
+ }
+
+ // HASHES
+ if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
+ {
+ foreach ($hashes_iterator as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes_parent[] = $algo.':'.$value;
+ }
+ }
+ elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
+ {
+ foreach ($hashes_iterator as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes_parent[] = $algo.':'.$value;
+ }
+ }
+ if (is_array($hashes_parent))
+ {
+ $hashes_parent = array_values(array_unique($hashes_parent));
+ }
+
+ // KEYWORDS
+ if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
+ {
+ if (isset($keywords[0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords_parent[] = trim($word);
+ }
+ }
+ unset($temp);
+ }
+ if (is_array($keywords_parent))
+ {
+ $keywords_parent = array_values(array_unique($keywords_parent));
+ }
+
+ // PLAYER
+ if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
+ {
+ if (isset($player_parent[0]['attribs']['']['url']))
+ {
+ $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
+ {
+ if (isset($player_parent[0]['attribs']['']['url']))
+ {
+ $player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+
+ // RATINGS
+ if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ }
+ elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = 'urn:itunes';
+ $rating_value = null;
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ }
+ elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ }
+ elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
+ {
+ foreach ($ratings as $rating)
+ {
+ $rating_scheme = 'urn:itunes';
+ $rating_value = null;
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings_parent[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ }
+ if (is_array($ratings_parent))
+ {
+ $ratings_parent = array_values(array_unique($ratings_parent));
+ }
+
+ // RESTRICTIONS
+ if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ }
+ elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = 'allow';
+ $restriction_type = null;
+ $restriction_value = 'itunes';
+ if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
+ {
+ $restriction_relationship = 'deny';
+ }
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ }
+ elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ }
+ elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
+ {
+ foreach ($restrictions as $restriction)
+ {
+ $restriction_relationship = 'allow';
+ $restriction_type = null;
+ $restriction_value = 'itunes';
+ if (isset($restriction['data']) && strtolower($restriction['data']) === 'yes')
+ {
+ $restriction_relationship = 'deny';
+ }
+ $restrictions_parent[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ }
+ if (is_array($restrictions_parent))
+ {
+ $restrictions_parent = array_values(array_unique($restrictions_parent));
+ }
+ else
+ {
+ $restrictions_parent = array(new SimplePie_Restriction('allow', null, 'default'));
+ }
+
+ // THUMBNAILS
+ if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+ {
+ foreach ($thumbnails as $thumbnail)
+ {
+ if (isset($thumbnail['attribs']['']['url']))
+ {
+ $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ }
+ elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+ {
+ foreach ($thumbnails as $thumbnail)
+ {
+ if (isset($thumbnail['attribs']['']['url']))
+ {
+ $thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ }
+ }
+
+ // TITLES
+ if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
+ {
+ if (isset($title_parent[0]['data']))
+ {
+ $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+ elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
+ {
+ if (isset($title_parent[0]['data']))
+ {
+ $title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ }
+
+ // Clear the memory
+ unset($parent);
+
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ // Elements
+ $captions = null;
+ $categories = null;
+ $copyrights = null;
+ $credits = null;
+ $description = null;
+ $hashes = null;
+ $keywords = null;
+ $player = null;
+ $ratings = null;
+ $restrictions = null;
+ $thumbnails = null;
+ $title = null;
+
+ // If we have media:group tags, loop through them.
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
+ {
+ if(isset($group['child']) && isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
+ {
+ // If we have media:content tags, loop through them.
+ foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
+ {
+ if (isset($content['attribs']['']['url']))
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ // Elements
+ $captions = null;
+ $categories = null;
+ $copyrights = null;
+ $credits = null;
+ $description = null;
+ $hashes = null;
+ $keywords = null;
+ $player = null;
+ $ratings = null;
+ $restrictions = null;
+ $thumbnails = null;
+ $title = null;
+
+ // Start checking the attributes of media:content
+ if (isset($content['attribs']['']['bitrate']))
+ {
+ $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['channels']))
+ {
+ $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['duration']))
+ {
+ $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $duration = $duration_parent;
+ }
+ if (isset($content['attribs']['']['expression']))
+ {
+ $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['framerate']))
+ {
+ $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['height']))
+ {
+ $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['lang']))
+ {
+ $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['fileSize']))
+ {
+ $length = ceil($content['attribs']['']['fileSize']);
+ }
+ if (isset($content['attribs']['']['medium']))
+ {
+ $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['samplingrate']))
+ {
+ $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['type']))
+ {
+ $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['width']))
+ {
+ $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+
+ // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
+
+ // CAPTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
+ }
+ if (is_array($captions))
+ {
+ $captions = array_values(array_unique($captions));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
+ }
+ if (is_array($captions))
+ {
+ $captions = array_values(array_unique($captions));
+ }
+ }
+ else
+ {
+ $captions = $captions_parent;
+ }
+
+ // CATEGORIES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+ {
+ foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ }
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+ {
+ foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ }
+ if (is_array($categories) && is_array($categories_parent))
+ {
+ $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
+ }
+ elseif (is_array($categories))
+ {
+ $categories = array_values(array_unique($categories));
+ }
+ elseif (is_array($categories_parent))
+ {
+ $categories = array_values(array_unique($categories_parent));
+ }
+
+ // COPYRIGHTS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+ {
+ $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+ {
+ $copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
+ }
+ else
+ {
+ $copyrights = $copyrights_parent;
+ }
+
+ // CREDITS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
+ }
+ if (is_array($credits))
+ {
+ $credits = array_values(array_unique($credits));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
+ }
+ if (is_array($credits))
+ {
+ $credits = array_values(array_unique($credits));
+ }
+ }
+ else
+ {
+ $credits = $credits_parent;
+ }
+
+ // DESCRIPTION
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+ {
+ $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+ {
+ $description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $description = $description_parent;
+ }
+
+ // HASHES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes[] = $algo.':'.$value;
+ }
+ if (is_array($hashes))
+ {
+ $hashes = array_values(array_unique($hashes));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes[] = $algo.':'.$value;
+ }
+ if (is_array($hashes))
+ {
+ $hashes = array_values(array_unique($hashes));
+ }
+ }
+ else
+ {
+ $hashes = $hashes_parent;
+ }
+
+ // KEYWORDS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+ {
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords[] = trim($word);
+ }
+ unset($temp);
+ }
+ if (is_array($keywords))
+ {
+ $keywords = array_values(array_unique($keywords));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+ {
+ if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords[] = trim($word);
+ }
+ unset($temp);
+ }
+ if (is_array($keywords))
+ {
+ $keywords = array_values(array_unique($keywords));
+ }
+ }
+ else
+ {
+ $keywords = $keywords_parent;
+ }
+
+ // PLAYER
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ $player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ $player = $player_parent;
+ }
+
+ // RATINGS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ if (is_array($ratings))
+ {
+ $ratings = array_values(array_unique($ratings));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ if (is_array($ratings))
+ {
+ $ratings = array_values(array_unique($ratings));
+ }
+ }
+ else
+ {
+ $ratings = $ratings_parent;
+ }
+
+ // RESTRICTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ if (is_array($restrictions))
+ {
+ $restrictions = array_values(array_unique($restrictions));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ if (is_array($restrictions))
+ {
+ $restrictions = array_values(array_unique($restrictions));
+ }
+ }
+ else
+ {
+ $restrictions = $restrictions_parent;
+ }
+
+ // THUMBNAILS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+ {
+ $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ if (is_array($thumbnails))
+ {
+ $thumbnails = array_values(array_unique($thumbnails));
+ }
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+ {
+ foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+ {
+ $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ if (is_array($thumbnails))
+ {
+ $thumbnails = array_values(array_unique($thumbnails));
+ }
+ }
+ else
+ {
+ $thumbnails = $thumbnails_parent;
+ }
+
+ // TITLES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+ {
+ $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+ {
+ $title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $title = $title_parent;
+ }
+
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
+ }
+ }
+ }
+ }
+
+ // If we have standalone media:content tags, loop through them.
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
+ {
+ foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
+ {
+ if (isset($content['attribs']['']['url']) || isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ // Elements
+ $captions = null;
+ $categories = null;
+ $copyrights = null;
+ $credits = null;
+ $description = null;
+ $hashes = null;
+ $keywords = null;
+ $player = null;
+ $ratings = null;
+ $restrictions = null;
+ $thumbnails = null;
+ $title = null;
+
+ // Start checking the attributes of media:content
+ if (isset($content['attribs']['']['bitrate']))
+ {
+ $bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['channels']))
+ {
+ $channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['duration']))
+ {
+ $duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $duration = $duration_parent;
+ }
+ if (isset($content['attribs']['']['expression']))
+ {
+ $expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['framerate']))
+ {
+ $framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['height']))
+ {
+ $height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['lang']))
+ {
+ $lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['fileSize']))
+ {
+ $length = ceil($content['attribs']['']['fileSize']);
+ }
+ if (isset($content['attribs']['']['medium']))
+ {
+ $medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['samplingrate']))
+ {
+ $samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['type']))
+ {
+ $type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['width']))
+ {
+ $width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['attribs']['']['url']))
+ {
+ $url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ // Checking the other optional media: elements. Priority: media:content, media:group, item, channel
+
+ // CAPTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+ {
+ $caption_type = null;
+ $caption_lang = null;
+ $caption_startTime = null;
+ $caption_endTime = null;
+ $caption_text = null;
+ if (isset($caption['attribs']['']['type']))
+ {
+ $caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['lang']))
+ {
+ $caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['start']))
+ {
+ $caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['attribs']['']['end']))
+ {
+ $caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($caption['data']))
+ {
+ $caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $captions[] = $this->registry->create('Caption', array($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text));
+ }
+ if (is_array($captions))
+ {
+ $captions = array_values(array_unique($captions));
+ }
+ }
+ else
+ {
+ $captions = $captions_parent;
+ }
+
+ // CATEGORIES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+ {
+ foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['data']))
+ {
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = 'http://search.yahoo.com/mrss/category_schema';
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ }
+ if (is_array($categories) && is_array($categories_parent))
+ {
+ $categories = array_values(array_unique(array_merge($categories, $categories_parent)));
+ }
+ elseif (is_array($categories))
+ {
+ $categories = array_values(array_unique($categories));
+ }
+ elseif (is_array($categories_parent))
+ {
+ $categories = array_values(array_unique($categories_parent));
+ }
+ else
+ {
+ $categories = null;
+ }
+
+ // COPYRIGHTS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+ {
+ $copyright_url = null;
+ $copyright_label = null;
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+ {
+ $copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+ {
+ $copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $copyrights = $this->registry->create('Copyright', array($copyright_url, $copyright_label));
+ }
+ else
+ {
+ $copyrights = $copyrights_parent;
+ }
+
+ // CREDITS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+ {
+ $credit_role = null;
+ $credit_scheme = null;
+ $credit_name = null;
+ if (isset($credit['attribs']['']['role']))
+ {
+ $credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($credit['attribs']['']['scheme']))
+ {
+ $credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $credit_scheme = 'urn:ebu';
+ }
+ if (isset($credit['data']))
+ {
+ $credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $credits[] = $this->registry->create('Credit', array($credit_role, $credit_scheme, $credit_name));
+ }
+ if (is_array($credits))
+ {
+ $credits = array_values(array_unique($credits));
+ }
+ }
+ else
+ {
+ $credits = $credits_parent;
+ }
+
+ // DESCRIPTION
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+ {
+ $description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $description = $description_parent;
+ }
+
+ // HASHES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+ {
+ $value = null;
+ $algo = null;
+ if (isset($hash['data']))
+ {
+ $value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($hash['attribs']['']['algo']))
+ {
+ $algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $algo = 'md5';
+ }
+ $hashes[] = $algo.':'.$value;
+ }
+ if (is_array($hashes))
+ {
+ $hashes = array_values(array_unique($hashes));
+ }
+ }
+ else
+ {
+ $hashes = $hashes_parent;
+ }
+
+ // KEYWORDS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+ {
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+ {
+ $temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+ foreach ($temp as $word)
+ {
+ $keywords[] = trim($word);
+ }
+ unset($temp);
+ }
+ if (is_array($keywords))
+ {
+ $keywords = array_values(array_unique($keywords));
+ }
+ }
+ else
+ {
+ $keywords = $keywords_parent;
+ }
+
+ // PLAYER
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+ {
+ $player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ $player = $player_parent;
+ }
+
+ // RATINGS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+ {
+ $rating_scheme = null;
+ $rating_value = null;
+ if (isset($rating['attribs']['']['scheme']))
+ {
+ $rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $rating_scheme = 'urn:simple';
+ }
+ if (isset($rating['data']))
+ {
+ $rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $ratings[] = $this->registry->create('Rating', array($rating_scheme, $rating_value));
+ }
+ if (is_array($ratings))
+ {
+ $ratings = array_values(array_unique($ratings));
+ }
+ }
+ else
+ {
+ $ratings = $ratings_parent;
+ }
+
+ // RESTRICTIONS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+ {
+ $restriction_relationship = null;
+ $restriction_type = null;
+ $restriction_value = null;
+ if (isset($restriction['attribs']['']['relationship']))
+ {
+ $restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['attribs']['']['type']))
+ {
+ $restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($restriction['data']))
+ {
+ $restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $restrictions[] = $this->registry->create('Restriction', array($restriction_relationship, $restriction_type, $restriction_value));
+ }
+ if (is_array($restrictions))
+ {
+ $restrictions = array_values(array_unique($restrictions));
+ }
+ }
+ else
+ {
+ $restrictions = $restrictions_parent;
+ }
+
+ // THUMBNAILS
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+ {
+ foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+ {
+ $thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ if (is_array($thumbnails))
+ {
+ $thumbnails = array_values(array_unique($thumbnails));
+ }
+ }
+ else
+ {
+ $thumbnails = $thumbnails_parent;
+ }
+
+ // TITLES
+ if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+ {
+ $title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $title = $title_parent;
+ }
+
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width));
+ }
+ }
+ }
+
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ if (isset($link['attribs']['']['type']))
+ {
+ $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($link['attribs']['']['length']))
+ {
+ $length = ceil($link['attribs']['']['length']);
+ }
+
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
+ }
+ }
+
+ foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
+ {
+ if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] === 'enclosure')
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ $url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ if (isset($link['attribs']['']['type']))
+ {
+ $type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($link['attribs']['']['length']))
+ {
+ $length = ceil($link['attribs']['']['length']);
+ }
+
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
+ }
+ }
+
+ if ($enclosure = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'enclosure'))
+ {
+ if (isset($enclosure[0]['attribs']['']['url']))
+ {
+ // Attributes
+ $bitrate = null;
+ $channels = null;
+ $duration = null;
+ $expression = null;
+ $framerate = null;
+ $height = null;
+ $javascript = null;
+ $lang = null;
+ $length = null;
+ $medium = null;
+ $samplingrate = null;
+ $type = null;
+ $url = null;
+ $width = null;
+
+ $url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
+ if (isset($enclosure[0]['attribs']['']['type']))
+ {
+ $type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($enclosure[0]['attribs']['']['length']))
+ {
+ $length = ceil($enclosure[0]['attribs']['']['length']);
+ }
+
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
+ }
+ }
+
+ if (sizeof($this->data['enclosures']) === 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
+ {
+ // Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+ $this->data['enclosures'][] = $this->registry->create('Enclosure', array($url, $type, $length, null, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width));
+ }
+
+ $this->data['enclosures'] = array_values(array_unique($this->data['enclosures']));
+ }
+ if (!empty($this->data['enclosures']))
+ {
+ return $this->data['enclosures'];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the latitude coordinates for the item
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:lat>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_latitude()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the longitude coordinates for the item
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_longitude()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the `<atom:source>` for the item
+ *
+ * @since 1.1
+ * @return SimplePie_Source|null
+ */
+ public function get_source()
+ {
+ if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
+ {
+ return $this->registry->create('Source', array($this, $return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Locator.php b/src/wp-includes/SimplePie/Locator.php
new file mode 100644
index 0000000000..da89514685
--- /dev/null
+++ b/src/wp-includes/SimplePie/Locator.php
@@ -0,0 +1,372 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Used for feed auto-discovery
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_locator_class()}
+ *
+ * @package SimplePie
+ */
+class SimplePie_Locator
+{
+ var $useragent;
+ var $timeout;
+ var $file;
+ var $local = array();
+ var $elsewhere = array();
+ var $cached_entities = array();
+ var $http_base;
+ var $base;
+ var $base_location = 0;
+ var $checked_feeds = 0;
+ var $max_checked_feeds = 10;
+ protected $registry;
+
+ public function __construct(SimplePie_File $file, $timeout = 10, $useragent = null, $max_checked_feeds = 10)
+ {
+ $this->file = $file;
+ $this->useragent = $useragent;
+ $this->timeout = $timeout;
+ $this->max_checked_feeds = $max_checked_feeds;
+
+ if (class_exists('DOMDocument'))
+ {
+ $this->dom = new DOMDocument();
+
+ set_error_handler(array('SimplePie_Misc', 'silence_errors'));
+ $this->dom->loadHTML($this->file->body);
+ restore_error_handler();
+ }
+ else
+ {
+ $this->dom = null;
+ }
+ }
+
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ public function find($type = SIMPLEPIE_LOCATOR_ALL, &$working)
+ {
+ if ($this->is_feed($this->file))
+ {
+ return $this->file;
+ }
+
+ if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
+ {
+ $sniffer = $this->registry->create('Content_Type_Sniffer', array($this->file));
+ if ($sniffer->get_type() !== 'text/html')
+ {
+ return null;
+ }
+ }
+
+ if ($type & ~SIMPLEPIE_LOCATOR_NONE)
+ {
+ $this->get_base();
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
+ {
+ return $working[0];
+ }
+
+ if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
+ {
+ if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
+ {
+ return $working;
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
+ {
+ return $working;
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
+ {
+ return $working;
+ }
+
+ if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
+ {
+ return $working;
+ }
+ }
+ return null;
+ }
+
+ public function is_feed($file)
+ {
+ if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
+ {
+ $sniffer = $this->registry->create('Content_Type_Sniffer', array($file));
+ $sniffed = $sniffer->get_type();
+ if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml')))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function get_base()
+ {
+ if ($this->dom === null)
+ {
+ throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
+ }
+ $this->http_base = $this->file->url;
+ $this->base = $this->http_base;
+ $elements = $this->dom->getElementsByTagName('base');
+ foreach ($elements as $element)
+ {
+ if ($element->hasAttribute('href'))
+ {
+ $base = $this->registry->call('Misc', 'absolutize_url', array(trim($element->getAttribute('href')), $this->http_base));
+ if ($base === false)
+ {
+ continue;
+ }
+ $this->base = $base;
+ $this->base_location = method_exists($element, 'getLineNo') ? $element->getLineNo() : 0;
+ break;
+ }
+ }
+ }
+
+ public function autodiscovery()
+ {
+ $done = array();
+ $feeds = array();
+ $feeds = array_merge($feeds, $this->search_elements_by_tag('link', $done, $feeds));
+ $feeds = array_merge($feeds, $this->search_elements_by_tag('a', $done, $feeds));
+ $feeds = array_merge($feeds, $this->search_elements_by_tag('area', $done, $feeds));
+
+ if (!empty($feeds))
+ {
+ return array_values($feeds);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ protected function search_elements_by_tag($name, &$done, $feeds)
+ {
+ if ($this->dom === null)
+ {
+ throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
+ }
+
+ $links = $this->dom->getElementsByTagName($name);
+ foreach ($links as $link)
+ {
+ if ($this->checked_feeds === $this->max_checked_feeds)
+ {
+ break;
+ }
+ if ($link->hasAttribute('href') && $link->hasAttribute('rel'))
+ {
+ $rel = array_unique($this->registry->call('Misc', 'space_seperated_tokens', array(strtolower($link->getAttribute('rel')))));
+ $line = method_exists($link, 'getLineNo') ? $link->getLineNo() : 1;
+
+ if ($this->base_location < $line)
+ {
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
+ }
+ else
+ {
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
+ }
+ if ($href === false)
+ {
+ continue;
+ }
+
+ if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !in_array('stylesheet', $rel) && $link->hasAttribute('type') && in_array(strtolower($this->registry->call('Misc', 'parse_mime', array($link->getAttribute('type')))), array('application/rss+xml', 'application/atom+xml'))) && !isset($feeds[$href]))
+ {
+ $this->checked_feeds++;
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $feed = $this->registry->create('File', array($href, $this->timeout, 5, $headers, $this->useragent));
+ if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
+ {
+ $feeds[$href] = $feed;
+ }
+ }
+ $done[] = $href;
+ }
+ }
+
+ return $feeds;
+ }
+
+ public function get_links()
+ {
+ if ($this->dom === null)
+ {
+ throw new SimplePie_Exception('DOMDocument not found, unable to use locator');
+ }
+
+ $links = $this->dom->getElementsByTagName('a');
+ foreach ($links as $link)
+ {
+ if ($link->hasAttribute('href'))
+ {
+ $href = trim($link->getAttribute('href'));
+ $parsed = $this->registry->call('Misc', 'parse_url', array($href));
+ if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
+ {
+ if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo())
+ {
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
+ }
+ else
+ {
+ $href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->http_base));
+ }
+ if ($href === false)
+ {
+ continue;
+ }
+
+ $current = $this->registry->call('Misc', 'parse_url', array($this->file->url));
+
+ if ($parsed['authority'] === '' || $parsed['authority'] === $current['authority'])
+ {
+ $this->local[] = $href;
+ }
+ else
+ {
+ $this->elsewhere[] = $href;
+ }
+ }
+ }
+ }
+ $this->local = array_unique($this->local);
+ $this->elsewhere = array_unique($this->elsewhere);
+ if (!empty($this->local) || !empty($this->elsewhere))
+ {
+ return true;
+ }
+ return null;
+ }
+
+ public function extension(&$array)
+ {
+ foreach ($array as $key => $value)
+ {
+ if ($this->checked_feeds === $this->max_checked_feeds)
+ {
+ break;
+ }
+ if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
+ {
+ $this->checked_feeds++;
+
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $feed = $this->registry->create('File', array($value, $this->timeout, 5, $headers, $this->useragent));
+ if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
+ {
+ return $feed;
+ }
+ else
+ {
+ unset($array[$key]);
+ }
+ }
+ }
+ return null;
+ }
+
+ public function body(&$array)
+ {
+ foreach ($array as $key => $value)
+ {
+ if ($this->checked_feeds === $this->max_checked_feeds)
+ {
+ break;
+ }
+ if (preg_match('/(rss|rdf|atom|xml)/i', $value))
+ {
+ $this->checked_feeds++;
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $feed = $this->registry->create('File', array($value, $this->timeout, 5, null, $this->useragent));
+ if ($feed->success && ($feed->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($feed->status_code === 200 || $feed->status_code > 206 && $feed->status_code < 300)) && $this->is_feed($feed))
+ {
+ return $feed;
+ }
+ else
+ {
+ unset($array[$key]);
+ }
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Misc.php b/src/wp-includes/SimplePie/Misc.php
new file mode 100644
index 0000000000..1c1b618414
--- /dev/null
+++ b/src/wp-includes/SimplePie/Misc.php
@@ -0,0 +1,2247 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Miscellanous utilities
+ *
+ * @package SimplePie
+ */
+class SimplePie_Misc
+{
+ public static function time_hms($seconds)
+ {
+ $time = '';
+
+ $hours = floor($seconds / 3600);
+ $remainder = $seconds % 3600;
+ if ($hours > 0)
+ {
+ $time .= $hours.':';
+ }
+
+ $minutes = floor($remainder / 60);
+ $seconds = $remainder % 60;
+ if ($minutes < 10 && $hours > 0)
+ {
+ $minutes = '0' . $minutes;
+ }
+ if ($seconds < 10)
+ {
+ $seconds = '0' . $seconds;
+ }
+
+ $time .= $minutes.':';
+ $time .= $seconds;
+
+ return $time;
+ }
+
+ public static function absolutize_url($relative, $base)
+ {
+ $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative);
+ if ($iri === false)
+ {
+ return false;
+ }
+ return $iri->get_uri();
+ }
+
+ /**
+ * Get a HTML/XML element from a HTML string
+ *
+ * @deprecated Use DOMDocument instead (parsing HTML with regex is bad!)
+ * @param string $realname Element name (including namespace prefix if applicable)
+ * @param string $string HTML document
+ * @return array
+ */
+ public static function get_element($realname, $string)
+ {
+ $return = array();
+ $name = preg_quote($realname, '/');
+ if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
+ {
+ for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
+ {
+ $return[$i]['tag'] = $realname;
+ $return[$i]['full'] = $matches[$i][0][0];
+ $return[$i]['offset'] = $matches[$i][0][1];
+ if (strlen($matches[$i][3][0]) <= 2)
+ {
+ $return[$i]['self_closing'] = true;
+ }
+ else
+ {
+ $return[$i]['self_closing'] = false;
+ $return[$i]['content'] = $matches[$i][4][0];
+ }
+ $return[$i]['attribs'] = array();
+ if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
+ {
+ for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
+ {
+ if (count($attribs[$j]) === 2)
+ {
+ $attribs[$j][2] = $attribs[$j][1];
+ }
+ $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]));
+ }
+ }
+ }
+ }
+ return $return;
+ }
+
+ public static function element_implode($element)
+ {
+ $full = "<$element[tag]";
+ foreach ($element['attribs'] as $key => $value)
+ {
+ $key = strtolower($key);
+ $full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
+ }
+ if ($element['self_closing'])
+ {
+ $full .= ' />';
+ }
+ else
+ {
+ $full .= ">$element[content]</$element[tag]>";
+ }
+ return $full;
+ }
+
+ public static function error($message, $level, $file, $line)
+ {
+ if ((ini_get('error_reporting') & $level) > 0)
+ {
+ switch ($level)
+ {
+ case E_USER_ERROR:
+ $note = 'PHP Error';
+ break;
+ case E_USER_WARNING:
+ $note = 'PHP Warning';
+ break;
+ case E_USER_NOTICE:
+ $note = 'PHP Notice';
+ break;
+ default:
+ $note = 'Unknown Error';
+ break;
+ }
+
+ $log_error = true;
+ if (!function_exists('error_log'))
+ {
+ $log_error = false;
+ }
+
+ $log_file = @ini_get('error_log');
+ if (!empty($log_file) && ('syslog' !== $log_file) && !@is_writable($log_file))
+ {
+ $log_error = false;
+ }
+
+ if ($log_error)
+ {
+ @error_log("$note: $message in $file on line $line", 0);
+ }
+ }
+
+ return $message;
+ }
+
+ public static function fix_protocol($url, $http = 1)
+ {
+ $url = SimplePie_Misc::normalize_url($url);
+ $parsed = SimplePie_Misc::parse_url($url);
+ if ($parsed['scheme'] !== '' && $parsed['scheme'] !== 'http' && $parsed['scheme'] !== 'https')
+ {
+ return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
+ }
+
+ if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
+ {
+ return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
+ }
+
+ if ($http === 2 && $parsed['scheme'] !== '')
+ {
+ return "feed:$url";
+ }
+ elseif ($http === 3 && strtolower($parsed['scheme']) === 'http')
+ {
+ return substr_replace($url, 'podcast', 0, 4);
+ }
+ elseif ($http === 4 && strtolower($parsed['scheme']) === 'http')
+ {
+ return substr_replace($url, 'itpc', 0, 4);
+ }
+ else
+ {
+ return $url;
+ }
+ }
+
+ public static function parse_url($url)
+ {
+ $iri = new SimplePie_IRI($url);
+ return array(
+ 'scheme' => (string) $iri->scheme,
+ 'authority' => (string) $iri->authority,
+ 'path' => (string) $iri->path,
+ 'query' => (string) $iri->query,
+ 'fragment' => (string) $iri->fragment
+ );
+ }
+
+ public static function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
+ {
+ $iri = new SimplePie_IRI('');
+ $iri->scheme = $scheme;
+ $iri->authority = $authority;
+ $iri->path = $path;
+ $iri->query = $query;
+ $iri->fragment = $fragment;
+ return $iri->get_uri();
+ }
+
+ public static function normalize_url($url)
+ {
+ $iri = new SimplePie_IRI($url);
+ return $iri->get_uri();
+ }
+
+ public static function percent_encoding_normalization($match)
+ {
+ $integer = hexdec($match[1]);
+ if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer === 0x2D || $integer === 0x2E || $integer === 0x5F || $integer === 0x7E)
+ {
+ return chr($integer);
+ }
+ else
+ {
+ return strtoupper($match[0]);
+ }
+ }
+
+ /**
+ * Converts a Windows-1252 encoded string to a UTF-8 encoded string
+ *
+ * @static
+ * @param string $string Windows-1252 encoded string
+ * @return string UTF-8 encoded string
+ */
+ public static function windows_1252_to_utf8($string)
+ {
+ static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
+
+ return strtr($string, $convert_table);
+ }
+
+ /**
+ * Change a string from one encoding to another
+ *
+ * @param string $data Raw data in $input encoding
+ * @param string $input Encoding of $data
+ * @param string $output Encoding you want
+ * @return string|boolean False if we can't convert it
+ */
+ public static function change_encoding($data, $input, $output)
+ {
+ $input = SimplePie_Misc::encoding($input);
+ $output = SimplePie_Misc::encoding($output);
+
+ // We fail to fail on non US-ASCII bytes
+ if ($input === 'US-ASCII')
+ {
+ static $non_ascii_octects = '';
+ if (!$non_ascii_octects)
+ {
+ for ($i = 0x80; $i <= 0xFF; $i++)
+ {
+ $non_ascii_octects .= chr($i);
+ }
+ }
+ $data = substr($data, 0, strcspn($data, $non_ascii_octects));
+ }
+
+ // This is first, as behaviour of this is completely predictable
+ if ($input === 'windows-1252' && $output === 'UTF-8')
+ {
+ return SimplePie_Misc::windows_1252_to_utf8($data);
+ }
+ // This is second, as behaviour of this varies only with PHP version (the middle part of this expression checks the encoding is supported).
+ elseif (function_exists('mb_convert_encoding') && ($return = SimplePie_Misc::change_encoding_mbstring($data, $input, $output)))
+ {
+ return $return;
+ }
+ // This is last, as behaviour of this varies with OS userland and PHP version
+ elseif (function_exists('iconv') && ($return = SimplePie_Misc::change_encoding_iconv($data, $input, $output)))
+ {
+ return $return;
+ }
+ // If we can't do anything, just fail
+ else
+ {
+ return false;
+ }
+ }
+
+ protected static function change_encoding_mbstring($data, $input, $output)
+ {
+ if ($input === 'windows-949')
+ {
+ $input = 'EUC-KR';
+ }
+ if ($output === 'windows-949')
+ {
+ $output = 'EUC-KR';
+ }
+ if ($input === 'Windows-31J')
+ {
+ $input = 'SJIS';
+ }
+ if ($output === 'Windows-31J')
+ {
+ $output = 'SJIS';
+ }
+
+ // Check that the encoding is supported
+ if (@mb_convert_encoding("\x80", 'UTF-16BE', $input) === "\x00\x80")
+ {
+ return false;
+ }
+ if (!in_array($input, mb_list_encodings()))
+ {
+ return false;
+ }
+
+ // Let's do some conversion
+ if ($return = @mb_convert_encoding($data, $output, $input))
+ {
+ return $return;
+ }
+
+ return false;
+ }
+
+ protected static function change_encoding_iconv($data, $input, $output)
+ {
+ return @iconv($input, $output, $data);
+ }
+
+ /**
+ * Normalize an encoding name
+ *
+ * This is automatically generated by create.php
+ *
+ * To generate it, run `php create.php` on the command line, and copy the
+ * output to replace this function.
+ *
+ * @param string $charset Character set to standardise
+ * @return string Standardised name
+ */
+ public static function encoding($charset)
+ {
+ // Normalization from UTS #22
+ switch (strtolower(preg_replace('/(?:[^a-zA-Z0-9]+|([^0-9])0+)/', '\1', $charset)))
+ {
+ case 'adobestandardencoding':
+ case 'csadobestandardencoding':
+ return 'Adobe-Standard-Encoding';
+
+ case 'adobesymbolencoding':
+ case 'cshppsmath':
+ return 'Adobe-Symbol-Encoding';
+
+ case 'ami1251':
+ case 'amiga1251':
+ return 'Amiga-1251';
+
+ case 'ansix31101983':
+ case 'csat5001983':
+ case 'csiso99naplps':
+ case 'isoir99':
+ case 'naplps':
+ return 'ANSI_X3.110-1983';
+
+ case 'arabic7':
+ case 'asmo449':
+ case 'csiso89asmo449':
+ case 'iso9036':
+ case 'isoir89':
+ return 'ASMO_449';
+
+ case 'big5':
+ case 'csbig5':
+ return 'Big5';
+
+ case 'big5hkscs':
+ return 'Big5-HKSCS';
+
+ case 'bocu1':
+ case 'csbocu1':
+ return 'BOCU-1';
+
+ case 'brf':
+ case 'csbrf':
+ return 'BRF';
+
+ case 'bs4730':
+ case 'csiso4unitedkingdom':
+ case 'gb':
+ case 'iso646gb':
+ case 'isoir4':
+ case 'uk':
+ return 'BS_4730';
+
+ case 'bsviewdata':
+ case 'csiso47bsviewdata':
+ case 'isoir47':
+ return 'BS_viewdata';
+
+ case 'cesu8':
+ case 'cscesu8':
+ return 'CESU-8';
+
+ case 'ca':
+ case 'csa71':
+ case 'csaz243419851':
+ case 'csiso121canadian1':
+ case 'iso646ca':
+ case 'isoir121':
+ return 'CSA_Z243.4-1985-1';
+
+ case 'csa72':
+ case 'csaz243419852':
+ case 'csiso122canadian2':
+ case 'iso646ca2':
+ case 'isoir122':
+ return 'CSA_Z243.4-1985-2';
+
+ case 'csaz24341985gr':
+ case 'csiso123csaz24341985gr':
+ case 'isoir123':
+ return 'CSA_Z243.4-1985-gr';
+
+ case 'csiso139csn369103':
+ case 'csn369103':
+ case 'isoir139':
+ return 'CSN_369103';
+
+ case 'csdecmcs':
+ case 'dec':
+ case 'decmcs':
+ return 'DEC-MCS';
+
+ case 'csiso21german':
+ case 'de':
+ case 'din66003':
+ case 'iso646de':
+ case 'isoir21':
+ return 'DIN_66003';
+
+ case 'csdkus':
+ case 'dkus':
+ return 'dk-us';
+
+ case 'csiso646danish':
+ case 'dk':
+ case 'ds2089':
+ case 'iso646dk':
+ return 'DS_2089';
+
+ case 'csibmebcdicatde':
+ case 'ebcdicatde':
+ return 'EBCDIC-AT-DE';
+
+ case 'csebcdicatdea':
+ case 'ebcdicatdea':
+ return 'EBCDIC-AT-DE-A';
+
+ case 'csebcdiccafr':
+ case 'ebcdiccafr':
+ return 'EBCDIC-CA-FR';
+
+ case 'csebcdicdkno':
+ case 'ebcdicdkno':
+ return 'EBCDIC-DK-NO';
+
+ case 'csebcdicdknoa':
+ case 'ebcdicdknoa':
+ return 'EBCDIC-DK-NO-A';
+
+ case 'csebcdices':
+ case 'ebcdices':
+ return 'EBCDIC-ES';
+
+ case 'csebcdicesa':
+ case 'ebcdicesa':
+ return 'EBCDIC-ES-A';
+
+ case 'csebcdicess':
+ case 'ebcdicess':
+ return 'EBCDIC-ES-S';
+
+ case 'csebcdicfise':
+ case 'ebcdicfise':
+ return 'EBCDIC-FI-SE';
+
+ case 'csebcdicfisea':
+ case 'ebcdicfisea':
+ return 'EBCDIC-FI-SE-A';
+
+ case 'csebcdicfr':
+ case 'ebcdicfr':
+ return 'EBCDIC-FR';
+
+ case 'csebcdicit':
+ case 'ebcdicit':
+ return 'EBCDIC-IT';
+
+ case 'csebcdicpt':
+ case 'ebcdicpt':
+ return 'EBCDIC-PT';
+
+ case 'csebcdicuk':
+ case 'ebcdicuk':
+ return 'EBCDIC-UK';
+
+ case 'csebcdicus':
+ case 'ebcdicus':
+ return 'EBCDIC-US';
+
+ case 'csiso111ecmacyrillic':
+ case 'ecmacyrillic':
+ case 'isoir111':
+ case 'koi8e':
+ return 'ECMA-cyrillic';
+
+ case 'csiso17spanish':
+ case 'es':
+ case 'iso646es':
+ case 'isoir17':
+ return 'ES';
+
+ case 'csiso85spanish2':
+ case 'es2':
+ case 'iso646es2':
+ case 'isoir85':
+ return 'ES2';
+
+ case 'cseucpkdfmtjapanese':
+ case 'eucjp':
+ case 'extendedunixcodepackedformatforjapanese':
+ return 'EUC-JP';
+
+ case 'cseucfixwidjapanese':
+ case 'extendedunixcodefixedwidthforjapanese':
+ return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
+
+ case 'gb18030':
+ return 'GB18030';
+
+ case 'chinese':
+ case 'cp936':
+ case 'csgb2312':
+ case 'csiso58gb231280':
+ case 'gb2312':
+ case 'gb231280':
+ case 'gbk':
+ case 'isoir58':
+ case 'ms936':
+ case 'windows936':
+ return 'GBK';
+
+ case 'cn':
+ case 'csiso57gb1988':
+ case 'gb198880':
+ case 'iso646cn':
+ case 'isoir57':
+ return 'GB_1988-80';
+
+ case 'csiso153gost1976874':
+ case 'gost1976874':
+ case 'isoir153':
+ case 'stsev35888':
+ return 'GOST_19768-74';
+
+ case 'csiso150':
+ case 'csiso150greekccitt':
+ case 'greekccitt':
+ case 'isoir150':
+ return 'greek-ccitt';
+
+ case 'csiso88greek7':
+ case 'greek7':
+ case 'isoir88':
+ return 'greek7';
+
+ case 'csiso18greek7old':
+ case 'greek7old':
+ case 'isoir18':
+ return 'greek7-old';
+
+ case 'cshpdesktop':
+ case 'hpdesktop':
+ return 'HP-DeskTop';
+
+ case 'cshplegal':
+ case 'hplegal':
+ return 'HP-Legal';
+
+ case 'cshpmath8':
+ case 'hpmath8':
+ return 'HP-Math8';
+
+ case 'cshppifont':
+ case 'hppifont':
+ return 'HP-Pi-font';
+
+ case 'cshproman8':
+ case 'hproman8':
+ case 'r8':
+ case 'roman8':
+ return 'hp-roman8';
+
+ case 'hzgb2312':
+ return 'HZ-GB-2312';
+
+ case 'csibmsymbols':
+ case 'ibmsymbols':
+ return 'IBM-Symbols';
+
+ case 'csibmthai':
+ case 'ibmthai':
+ return 'IBM-Thai';
+
+ case 'cp37':
+ case 'csibm37':
+ case 'ebcdiccpca':
+ case 'ebcdiccpnl':
+ case 'ebcdiccpus':
+ case 'ebcdiccpwt':
+ case 'ibm37':
+ return 'IBM037';
+
+ case 'cp38':
+ case 'csibm38':
+ case 'ebcdicint':
+ case 'ibm38':
+ return 'IBM038';
+
+ case 'cp273':
+ case 'csibm273':
+ case 'ibm273':
+ return 'IBM273';
+
+ case 'cp274':
+ case 'csibm274':
+ case 'ebcdicbe':
+ case 'ibm274':
+ return 'IBM274';
+
+ case 'cp275':
+ case 'csibm275':
+ case 'ebcdicbr':
+ case 'ibm275':
+ return 'IBM275';
+
+ case 'csibm277':
+ case 'ebcdiccpdk':
+ case 'ebcdiccpno':
+ case 'ibm277':
+ return 'IBM277';
+
+ case 'cp278':
+ case 'csibm278':
+ case 'ebcdiccpfi':
+ case 'ebcdiccpse':
+ case 'ibm278':
+ return 'IBM278';
+
+ case 'cp280':
+ case 'csibm280':
+ case 'ebcdiccpit':
+ case 'ibm280':
+ return 'IBM280';
+
+ case 'cp281':
+ case 'csibm281':
+ case 'ebcdicjpe':
+ case 'ibm281':
+ return 'IBM281';
+
+ case 'cp284':
+ case 'csibm284':
+ case 'ebcdiccpes':
+ case 'ibm284':
+ return 'IBM284';
+
+ case 'cp285':
+ case 'csibm285':
+ case 'ebcdiccpgb':
+ case 'ibm285':
+ return 'IBM285';
+
+ case 'cp290':
+ case 'csibm290':
+ case 'ebcdicjpkana':
+ case 'ibm290':
+ return 'IBM290';
+
+ case 'cp297':
+ case 'csibm297':
+ case 'ebcdiccpfr':
+ case 'ibm297':
+ return 'IBM297';
+
+ case 'cp420':
+ case 'csibm420':
+ case 'ebcdiccpar1':
+ case 'ibm420':
+ return 'IBM420';
+
+ case 'cp423':
+ case 'csibm423':
+ case 'ebcdiccpgr':
+ case 'ibm423':
+ return 'IBM423';
+
+ case 'cp424':
+ case 'csibm424':
+ case 'ebcdiccphe':
+ case 'ibm424':
+ return 'IBM424';
+
+ case '437':
+ case 'cp437':
+ case 'cspc8codepage437':
+ case 'ibm437':
+ return 'IBM437';
+
+ case 'cp500':
+ case 'csibm500':
+ case 'ebcdiccpbe':
+ case 'ebcdiccpch':
+ case 'ibm500':
+ return 'IBM500';
+
+ case 'cp775':
+ case 'cspc775baltic':
+ case 'ibm775':
+ return 'IBM775';
+
+ case '850':
+ case 'cp850':
+ case 'cspc850multilingual':
+ case 'ibm850':
+ return 'IBM850';
+
+ case '851':
+ case 'cp851':
+ case 'csibm851':
+ case 'ibm851':
+ return 'IBM851';
+
+ case '852':
+ case 'cp852':
+ case 'cspcp852':
+ case 'ibm852':
+ return 'IBM852';
+
+ case '855':
+ case 'cp855':
+ case 'csibm855':
+ case 'ibm855':
+ return 'IBM855';
+
+ case '857':
+ case 'cp857':
+ case 'csibm857':
+ case 'ibm857':
+ return 'IBM857';
+
+ case 'ccsid858':
+ case 'cp858':
+ case 'ibm858':
+ case 'pcmultilingual850euro':
+ return 'IBM00858';
+
+ case '860':
+ case 'cp860':
+ case 'csibm860':
+ case 'ibm860':
+ return 'IBM860';
+
+ case '861':
+ case 'cp861':
+ case 'cpis':
+ case 'csibm861':
+ case 'ibm861':
+ return 'IBM861';
+
+ case '862':
+ case 'cp862':
+ case 'cspc862latinhebrew':
+ case 'ibm862':
+ return 'IBM862';
+
+ case '863':
+ case 'cp863':
+ case 'csibm863':
+ case 'ibm863':
+ return 'IBM863';
+
+ case 'cp864':
+ case 'csibm864':
+ case 'ibm864':
+ return 'IBM864';
+
+ case '865':
+ case 'cp865':
+ case 'csibm865':
+ case 'ibm865':
+ return 'IBM865';
+
+ case '866':
+ case 'cp866':
+ case 'csibm866':
+ case 'ibm866':
+ return 'IBM866';
+
+ case 'cp868':
+ case 'cpar':
+ case 'csibm868':
+ case 'ibm868':
+ return 'IBM868';
+
+ case '869':
+ case 'cp869':
+ case 'cpgr':
+ case 'csibm869':
+ case 'ibm869':
+ return 'IBM869';
+
+ case 'cp870':
+ case 'csibm870':
+ case 'ebcdiccproece':
+ case 'ebcdiccpyu':
+ case 'ibm870':
+ return 'IBM870';
+
+ case 'cp871':
+ case 'csibm871':
+ case 'ebcdiccpis':
+ case 'ibm871':
+ return 'IBM871';
+
+ case 'cp880':
+ case 'csibm880':
+ case 'ebcdiccyrillic':
+ case 'ibm880':
+ return 'IBM880';
+
+ case 'cp891':
+ case 'csibm891':
+ case 'ibm891':
+ return 'IBM891';
+
+ case 'cp903':
+ case 'csibm903':
+ case 'ibm903':
+ return 'IBM903';
+
+ case '904':
+ case 'cp904':
+ case 'csibbm904':
+ case 'ibm904':
+ return 'IBM904';
+
+ case 'cp905':
+ case 'csibm905':
+ case 'ebcdiccptr':
+ case 'ibm905':
+ return 'IBM905';
+
+ case 'cp918':
+ case 'csibm918':
+ case 'ebcdiccpar2':
+ case 'ibm918':
+ return 'IBM918';
+
+ case 'ccsid924':
+ case 'cp924':
+ case 'ebcdiclatin9euro':
+ case 'ibm924':
+ return 'IBM00924';
+
+ case 'cp1026':
+ case 'csibm1026':
+ case 'ibm1026':
+ return 'IBM1026';
+
+ case 'ibm1047':
+ return 'IBM1047';
+
+ case 'ccsid1140':
+ case 'cp1140':
+ case 'ebcdicus37euro':
+ case 'ibm1140':
+ return 'IBM01140';
+
+ case 'ccsid1141':
+ case 'cp1141':
+ case 'ebcdicde273euro':
+ case 'ibm1141':
+ return 'IBM01141';
+
+ case 'ccsid1142':
+ case 'cp1142':
+ case 'ebcdicdk277euro':
+ case 'ebcdicno277euro':
+ case 'ibm1142':
+ return 'IBM01142';
+
+ case 'ccsid1143':
+ case 'cp1143':
+ case 'ebcdicfi278euro':
+ case 'ebcdicse278euro':
+ case 'ibm1143':
+ return 'IBM01143';
+
+ case 'ccsid1144':
+ case 'cp1144':
+ case 'ebcdicit280euro':
+ case 'ibm1144':
+ return 'IBM01144';
+
+ case 'ccsid1145':
+ case 'cp1145':
+ case 'ebcdices284euro':
+ case 'ibm1145':
+ return 'IBM01145';
+
+ case 'ccsid1146':
+ case 'cp1146':
+ case 'ebcdicgb285euro':
+ case 'ibm1146':
+ return 'IBM01146';
+
+ case 'ccsid1147':
+ case 'cp1147':
+ case 'ebcdicfr297euro':
+ case 'ibm1147':
+ return 'IBM01147';
+
+ case 'ccsid1148':
+ case 'cp1148':
+ case 'ebcdicinternational500euro':
+ case 'ibm1148':
+ return 'IBM01148';
+
+ case 'ccsid1149':
+ case 'cp1149':
+ case 'ebcdicis871euro':
+ case 'ibm1149':
+ return 'IBM01149';
+
+ case 'csiso143iecp271':
+ case 'iecp271':
+ case 'isoir143':
+ return 'IEC_P27-1';
+
+ case 'csiso49inis':
+ case 'inis':
+ case 'isoir49':
+ return 'INIS';
+
+ case 'csiso50inis8':
+ case 'inis8':
+ case 'isoir50':
+ return 'INIS-8';
+
+ case 'csiso51iniscyrillic':
+ case 'iniscyrillic':
+ case 'isoir51':
+ return 'INIS-cyrillic';
+
+ case 'csinvariant':
+ case 'invariant':
+ return 'INVARIANT';
+
+ case 'iso2022cn':
+ return 'ISO-2022-CN';
+
+ case 'iso2022cnext':
+ return 'ISO-2022-CN-EXT';
+
+ case 'csiso2022jp':
+ case 'iso2022jp':
+ return 'ISO-2022-JP';
+
+ case 'csiso2022jp2':
+ case 'iso2022jp2':
+ return 'ISO-2022-JP-2';
+
+ case 'csiso2022kr':
+ case 'iso2022kr':
+ return 'ISO-2022-KR';
+
+ case 'cswindows30latin1':
+ case 'iso88591windows30latin1':
+ return 'ISO-8859-1-Windows-3.0-Latin-1';
+
+ case 'cswindows31latin1':
+ case 'iso88591windows31latin1':
+ return 'ISO-8859-1-Windows-3.1-Latin-1';
+
+ case 'csisolatin2':
+ case 'iso88592':
+ case 'iso885921987':
+ case 'isoir101':
+ case 'l2':
+ case 'latin2':
+ return 'ISO-8859-2';
+
+ case 'cswindows31latin2':
+ case 'iso88592windowslatin2':
+ return 'ISO-8859-2-Windows-Latin-2';
+
+ case 'csisolatin3':
+ case 'iso88593':
+ case 'iso885931988':
+ case 'isoir109':
+ case 'l3':
+ case 'latin3':
+ return 'ISO-8859-3';
+
+ case 'csisolatin4':
+ case 'iso88594':
+ case 'iso885941988':
+ case 'isoir110':
+ case 'l4':
+ case 'latin4':
+ return 'ISO-8859-4';
+
+ case 'csisolatincyrillic':
+ case 'cyrillic':
+ case 'iso88595':
+ case 'iso885951988':
+ case 'isoir144':
+ return 'ISO-8859-5';
+
+ case 'arabic':
+ case 'asmo708':
+ case 'csisolatinarabic':
+ case 'ecma114':
+ case 'iso88596':
+ case 'iso885961987':
+ case 'isoir127':
+ return 'ISO-8859-6';
+
+ case 'csiso88596e':
+ case 'iso88596e':
+ return 'ISO-8859-6-E';
+
+ case 'csiso88596i':
+ case 'iso88596i':
+ return 'ISO-8859-6-I';
+
+ case 'csisolatingreek':
+ case 'ecma118':
+ case 'elot928':
+ case 'greek':
+ case 'greek8':
+ case 'iso88597':
+ case 'iso885971987':
+ case 'isoir126':
+ return 'ISO-8859-7';
+
+ case 'csisolatinhebrew':
+ case 'hebrew':
+ case 'iso88598':
+ case 'iso885981988':
+ case 'isoir138':
+ return 'ISO-8859-8';
+
+ case 'csiso88598e':
+ case 'iso88598e':
+ return 'ISO-8859-8-E';
+
+ case 'csiso88598i':
+ case 'iso88598i':
+ return 'ISO-8859-8-I';
+
+ case 'cswindows31latin5':
+ case 'iso88599windowslatin5':
+ return 'ISO-8859-9-Windows-Latin-5';
+
+ case 'csisolatin6':
+ case 'iso885910':
+ case 'iso8859101992':
+ case 'isoir157':
+ case 'l6':
+ case 'latin6':
+ return 'ISO-8859-10';
+
+ case 'iso885913':
+ return 'ISO-8859-13';
+
+ case 'iso885914':
+ case 'iso8859141998':
+ case 'isoceltic':
+ case 'isoir199':
+ case 'l8':
+ case 'latin8':
+ return 'ISO-8859-14';
+
+ case 'iso885915':
+ case 'latin9':
+ return 'ISO-8859-15';
+
+ case 'iso885916':
+ case 'iso8859162001':
+ case 'isoir226':
+ case 'l10':
+ case 'latin10':
+ return 'ISO-8859-16';
+
+ case 'iso10646j1':
+ return 'ISO-10646-J-1';
+
+ case 'csunicode':
+ case 'iso10646ucs2':
+ return 'ISO-10646-UCS-2';
+
+ case 'csucs4':
+ case 'iso10646ucs4':
+ return 'ISO-10646-UCS-4';
+
+ case 'csunicodeascii':
+ case 'iso10646ucsbasic':
+ return 'ISO-10646-UCS-Basic';
+
+ case 'csunicodelatin1':
+ case 'iso10646':
+ case 'iso10646unicodelatin1':
+ return 'ISO-10646-Unicode-Latin1';
+
+ case 'csiso10646utf1':
+ case 'iso10646utf1':
+ return 'ISO-10646-UTF-1';
+
+ case 'csiso115481':
+ case 'iso115481':
+ case 'isotr115481':
+ return 'ISO-11548-1';
+
+ case 'csiso90':
+ case 'isoir90':
+ return 'iso-ir-90';
+
+ case 'csunicodeibm1261':
+ case 'isounicodeibm1261':
+ return 'ISO-Unicode-IBM-1261';
+
+ case 'csunicodeibm1264':
+ case 'isounicodeibm1264':
+ return 'ISO-Unicode-IBM-1264';
+
+ case 'csunicodeibm1265':
+ case 'isounicodeibm1265':
+ return 'ISO-Unicode-IBM-1265';
+
+ case 'csunicodeibm1268':
+ case 'isounicodeibm1268':
+ return 'ISO-Unicode-IBM-1268';
+
+ case 'csunicodeibm1276':
+ case 'isounicodeibm1276':
+ return 'ISO-Unicode-IBM-1276';
+
+ case 'csiso646basic1983':
+ case 'iso646basic1983':
+ case 'ref':
+ return 'ISO_646.basic:1983';
+
+ case 'csiso2intlrefversion':
+ case 'irv':
+ case 'iso646irv1983':
+ case 'isoir2':
+ return 'ISO_646.irv:1983';
+
+ case 'csiso2033':
+ case 'e13b':
+ case 'iso20331983':
+ case 'isoir98':
+ return 'ISO_2033-1983';
+
+ case 'csiso5427cyrillic':
+ case 'iso5427':
+ case 'isoir37':
+ return 'ISO_5427';
+
+ case 'iso5427cyrillic1981':
+ case 'iso54271981':
+ case 'isoir54':
+ return 'ISO_5427:1981';
+
+ case 'csiso5428greek':
+ case 'iso54281980':
+ case 'isoir55':
+ return 'ISO_5428:1980';
+
+ case 'csiso6937add':
+ case 'iso6937225':
+ case 'isoir152':
+ return 'ISO_6937-2-25';
+
+ case 'csisotextcomm':
+ case 'iso69372add':
+ case 'isoir142':
+ return 'ISO_6937-2-add';
+
+ case 'csiso8859supp':
+ case 'iso8859supp':
+ case 'isoir154':
+ case 'latin125':
+ return 'ISO_8859-supp';
+
+ case 'csiso10367box':
+ case 'iso10367box':
+ case 'isoir155':
+ return 'ISO_10367-box';
+
+ case 'csiso15italian':
+ case 'iso646it':
+ case 'isoir15':
+ case 'it':
+ return 'IT';
+
+ case 'csiso13jisc6220jp':
+ case 'isoir13':
+ case 'jisc62201969':
+ case 'jisc62201969jp':
+ case 'katakana':
+ case 'x2017':
+ return 'JIS_C6220-1969-jp';
+
+ case 'csiso14jisc6220ro':
+ case 'iso646jp':
+ case 'isoir14':
+ case 'jisc62201969ro':
+ case 'jp':
+ return 'JIS_C6220-1969-ro';
+
+ case 'csiso42jisc62261978':
+ case 'isoir42':
+ case 'jisc62261978':
+ return 'JIS_C6226-1978';
+
+ case 'csiso87jisx208':
+ case 'isoir87':
+ case 'jisc62261983':
+ case 'jisx2081983':
+ case 'x208':
+ return 'JIS_C6226-1983';
+
+ case 'csiso91jisc62291984a':
+ case 'isoir91':
+ case 'jisc62291984a':
+ case 'jpocra':
+ return 'JIS_C6229-1984-a';
+
+ case 'csiso92jisc62991984b':
+ case 'iso646jpocrb':
+ case 'isoir92':
+ case 'jisc62291984b':
+ case 'jpocrb':
+ return 'JIS_C6229-1984-b';
+
+ case 'csiso93jis62291984badd':
+ case 'isoir93':
+ case 'jisc62291984badd':
+ case 'jpocrbadd':
+ return 'JIS_C6229-1984-b-add';
+
+ case 'csiso94jis62291984hand':
+ case 'isoir94':
+ case 'jisc62291984hand':
+ case 'jpocrhand':
+ return 'JIS_C6229-1984-hand';
+
+ case 'csiso95jis62291984handadd':
+ case 'isoir95':
+ case 'jisc62291984handadd':
+ case 'jpocrhandadd':
+ return 'JIS_C6229-1984-hand-add';
+
+ case 'csiso96jisc62291984kana':
+ case 'isoir96':
+ case 'jisc62291984kana':
+ return 'JIS_C6229-1984-kana';
+
+ case 'csjisencoding':
+ case 'jisencoding':
+ return 'JIS_Encoding';
+
+ case 'cshalfwidthkatakana':
+ case 'jisx201':
+ case 'x201':
+ return 'JIS_X0201';
+
+ case 'csiso159jisx2121990':
+ case 'isoir159':
+ case 'jisx2121990':
+ case 'x212':
+ return 'JIS_X0212-1990';
+
+ case 'csiso141jusib1002':
+ case 'iso646yu':
+ case 'isoir141':
+ case 'js':
+ case 'jusib1002':
+ case 'yu':
+ return 'JUS_I.B1.002';
+
+ case 'csiso147macedonian':
+ case 'isoir147':
+ case 'jusib1003mac':
+ case 'macedonian':
+ return 'JUS_I.B1.003-mac';
+
+ case 'csiso146serbian':
+ case 'isoir146':
+ case 'jusib1003serb':
+ case 'serbian':
+ return 'JUS_I.B1.003-serb';
+
+ case 'koi7switched':
+ return 'KOI7-switched';
+
+ case 'cskoi8r':
+ case 'koi8r':
+ return 'KOI8-R';
+
+ case 'koi8u':
+ return 'KOI8-U';
+
+ case 'csksc5636':
+ case 'iso646kr':
+ case 'ksc5636':
+ return 'KSC5636';
+
+ case 'cskz1048':
+ case 'kz1048':
+ case 'rk1048':
+ case 'strk10482002':
+ return 'KZ-1048';
+
+ case 'csiso19latingreek':
+ case 'isoir19':
+ case 'latingreek':
+ return 'latin-greek';
+
+ case 'csiso27latingreek1':
+ case 'isoir27':
+ case 'latingreek1':
+ return 'Latin-greek-1';
+
+ case 'csiso158lap':
+ case 'isoir158':
+ case 'lap':
+ case 'latinlap':
+ return 'latin-lap';
+
+ case 'csmacintosh':
+ case 'mac':
+ case 'macintosh':
+ return 'macintosh';
+
+ case 'csmicrosoftpublishing':
+ case 'microsoftpublishing':
+ return 'Microsoft-Publishing';
+
+ case 'csmnem':
+ case 'mnem':
+ return 'MNEM';
+
+ case 'csmnemonic':
+ case 'mnemonic':
+ return 'MNEMONIC';
+
+ case 'csiso86hungarian':
+ case 'hu':
+ case 'iso646hu':
+ case 'isoir86':
+ case 'msz77953':
+ return 'MSZ_7795.3';
+
+ case 'csnatsdano':
+ case 'isoir91':
+ case 'natsdano':
+ return 'NATS-DANO';
+
+ case 'csnatsdanoadd':
+ case 'isoir92':
+ case 'natsdanoadd':
+ return 'NATS-DANO-ADD';
+
+ case 'csnatssefi':
+ case 'isoir81':
+ case 'natssefi':
+ return 'NATS-SEFI';
+
+ case 'csnatssefiadd':
+ case 'isoir82':
+ case 'natssefiadd':
+ return 'NATS-SEFI-ADD';
+
+ case 'csiso151cuba':
+ case 'cuba':
+ case 'iso646cu':
+ case 'isoir151':
+ case 'ncnc1081':
+ return 'NC_NC00-10:81';
+
+ case 'csiso69french':
+ case 'fr':
+ case 'iso646fr':
+ case 'isoir69':
+ case 'nfz62010':
+ return 'NF_Z_62-010';
+
+ case 'csiso25french':
+ case 'iso646fr1':
+ case 'isoir25':
+ case 'nfz620101973':
+ return 'NF_Z_62-010_(1973)';
+
+ case 'csiso60danishnorwegian':
+ case 'csiso60norwegian1':
+ case 'iso646no':
+ case 'isoir60':
+ case 'no':
+ case 'ns45511':
+ return 'NS_4551-1';
+
+ case 'csiso61norwegian2':
+ case 'iso646no2':
+ case 'isoir61':
+ case 'no2':
+ case 'ns45512':
+ return 'NS_4551-2';
+
+ case 'osdebcdicdf3irv':
+ return 'OSD_EBCDIC_DF03_IRV';
+
+ case 'osdebcdicdf41':
+ return 'OSD_EBCDIC_DF04_1';
+
+ case 'osdebcdicdf415':
+ return 'OSD_EBCDIC_DF04_15';
+
+ case 'cspc8danishnorwegian':
+ case 'pc8danishnorwegian':
+ return 'PC8-Danish-Norwegian';
+
+ case 'cspc8turkish':
+ case 'pc8turkish':
+ return 'PC8-Turkish';
+
+ case 'csiso16portuguese':
+ case 'iso646pt':
+ case 'isoir16':
+ case 'pt':
+ return 'PT';
+
+ case 'csiso84portuguese2':
+ case 'iso646pt2':
+ case 'isoir84':
+ case 'pt2':
+ return 'PT2';
+
+ case 'cp154':
+ case 'csptcp154':
+ case 'cyrillicasian':
+ case 'pt154':
+ case 'ptcp154':
+ return 'PTCP154';
+
+ case 'scsu':
+ return 'SCSU';
+
+ case 'csiso10swedish':
+ case 'fi':
+ case 'iso646fi':
+ case 'iso646se':
+ case 'isoir10':
+ case 'se':
+ case 'sen850200b':
+ return 'SEN_850200_B';
+
+ case 'csiso11swedishfornames':
+ case 'iso646se2':
+ case 'isoir11':
+ case 'se2':
+ case 'sen850200c':
+ return 'SEN_850200_C';
+
+ case 'csiso102t617bit':
+ case 'isoir102':
+ case 't617bit':
+ return 'T.61-7bit';
+
+ case 'csiso103t618bit':
+ case 'isoir103':
+ case 't61':
+ case 't618bit':
+ return 'T.61-8bit';
+
+ case 'csiso128t101g2':
+ case 'isoir128':
+ case 't101g2':
+ return 'T.101-G2';
+
+ case 'cstscii':
+ case 'tscii':
+ return 'TSCII';
+
+ case 'csunicode11':
+ case 'unicode11':
+ return 'UNICODE-1-1';
+
+ case 'csunicode11utf7':
+ case 'unicode11utf7':
+ return 'UNICODE-1-1-UTF-7';
+
+ case 'csunknown8bit':
+ case 'unknown8bit':
+ return 'UNKNOWN-8BIT';
+
+ case 'ansix341968':
+ case 'ansix341986':
+ case 'ascii':
+ case 'cp367':
+ case 'csascii':
+ case 'ibm367':
+ case 'iso646irv1991':
+ case 'iso646us':
+ case 'isoir6':
+ case 'us':
+ case 'usascii':
+ return 'US-ASCII';
+
+ case 'csusdk':
+ case 'usdk':
+ return 'us-dk';
+
+ case 'utf7':
+ return 'UTF-7';
+
+ case 'utf8':
+ return 'UTF-8';
+
+ case 'utf16':
+ return 'UTF-16';
+
+ case 'utf16be':
+ return 'UTF-16BE';
+
+ case 'utf16le':
+ return 'UTF-16LE';
+
+ case 'utf32':
+ return 'UTF-32';
+
+ case 'utf32be':
+ return 'UTF-32BE';
+
+ case 'utf32le':
+ return 'UTF-32LE';
+
+ case 'csventurainternational':
+ case 'venturainternational':
+ return 'Ventura-International';
+
+ case 'csventuramath':
+ case 'venturamath':
+ return 'Ventura-Math';
+
+ case 'csventuraus':
+ case 'venturaus':
+ return 'Ventura-US';
+
+ case 'csiso70videotexsupp1':
+ case 'isoir70':
+ case 'videotexsuppl':
+ return 'videotex-suppl';
+
+ case 'csviqr':
+ case 'viqr':
+ return 'VIQR';
+
+ case 'csviscii':
+ case 'viscii':
+ return 'VISCII';
+
+ case 'csshiftjis':
+ case 'cswindows31j':
+ case 'mskanji':
+ case 'shiftjis':
+ case 'windows31j':
+ return 'Windows-31J';
+
+ case 'iso885911':
+ case 'tis620':
+ return 'windows-874';
+
+ case 'cseuckr':
+ case 'csksc56011987':
+ case 'euckr':
+ case 'isoir149':
+ case 'korean':
+ case 'ksc5601':
+ case 'ksc56011987':
+ case 'ksc56011989':
+ case 'windows949':
+ return 'windows-949';
+
+ case 'windows1250':
+ return 'windows-1250';
+
+ case 'windows1251':
+ return 'windows-1251';
+
+ case 'cp819':
+ case 'csisolatin1':
+ case 'ibm819':
+ case 'iso88591':
+ case 'iso885911987':
+ case 'isoir100':
+ case 'l1':
+ case 'latin1':
+ case 'windows1252':
+ return 'windows-1252';
+
+ case 'windows1253':
+ return 'windows-1253';
+
+ case 'csisolatin5':
+ case 'iso88599':
+ case 'iso885991989':
+ case 'isoir148':
+ case 'l5':
+ case 'latin5':
+ case 'windows1254':
+ return 'windows-1254';
+
+ case 'windows1255':
+ return 'windows-1255';
+
+ case 'windows1256':
+ return 'windows-1256';
+
+ case 'windows1257':
+ return 'windows-1257';
+
+ case 'windows1258':
+ return 'windows-1258';
+
+ default:
+ return $charset;
+ }
+ }
+
+ public static function get_curl_version()
+ {
+ if (is_array($curl = curl_version()))
+ {
+ $curl = $curl['version'];
+ }
+ elseif (substr($curl, 0, 5) === 'curl/')
+ {
+ $curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
+ }
+ elseif (substr($curl, 0, 8) === 'libcurl/')
+ {
+ $curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
+ }
+ else
+ {
+ $curl = 0;
+ }
+ return $curl;
+ }
+
+ /**
+ * Strip HTML comments
+ *
+ * @param string $data Data to strip comments from
+ * @return string Comment stripped string
+ */
+ public static function strip_comments($data)
+ {
+ $output = '';
+ while (($start = strpos($data, '<!--')) !== false)
+ {
+ $output .= substr($data, 0, $start);
+ if (($end = strpos($data, '-->', $start)) !== false)
+ {
+ $data = substr_replace($data, '', 0, $end + 3);
+ }
+ else
+ {
+ $data = '';
+ }
+ }
+ return $output . $data;
+ }
+
+ public static function parse_date($dt)
+ {
+ $parser = SimplePie_Parse_Date::get();
+ return $parser->parse($dt);
+ }
+
+ /**
+ * Decode HTML entities
+ *
+ * @deprecated Use DOMDocument instead
+ * @param string $data Input data
+ * @return string Output data
+ */
+ public static function entities_decode($data)
+ {
+ $decoder = new SimplePie_Decode_HTML_Entities($data);
+ return $decoder->parse();
+ }
+
+ /**
+ * Remove RFC822 comments
+ *
+ * @param string $data Data to strip comments from
+ * @return string Comment stripped string
+ */
+ public static function uncomment_rfc822($string)
+ {
+ $string = (string) $string;
+ $position = 0;
+ $length = strlen($string);
+ $depth = 0;
+
+ $output = '';
+
+ while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
+ {
+ $output .= substr($string, $position, $pos - $position);
+ $position = $pos + 1;
+ if ($string[$pos - 1] !== '\\')
+ {
+ $depth++;
+ while ($depth && $position < $length)
+ {
+ $position += strcspn($string, '()', $position);
+ if ($string[$position - 1] === '\\')
+ {
+ $position++;
+ continue;
+ }
+ elseif (isset($string[$position]))
+ {
+ switch ($string[$position])
+ {
+ case '(':
+ $depth++;
+ break;
+
+ case ')':
+ $depth--;
+ break;
+ }
+ $position++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ $output .= '(';
+ }
+ }
+ $output .= substr($string, $position);
+
+ return $output;
+ }
+
+ public static function parse_mime($mime)
+ {
+ if (($pos = strpos($mime, ';')) === false)
+ {
+ return trim($mime);
+ }
+ else
+ {
+ return trim(substr($mime, 0, $pos));
+ }
+ }
+
+ public static function atom_03_construct_type($attribs)
+ {
+ if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) === 'base64'))
+ {
+ $mode = SIMPLEPIE_CONSTRUCT_BASE64;
+ }
+ else
+ {
+ $mode = SIMPLEPIE_CONSTRUCT_NONE;
+ }
+ if (isset($attribs['']['type']))
+ {
+ switch (strtolower(trim($attribs['']['type'])))
+ {
+ case 'text':
+ case 'text/plain':
+ return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
+
+ case 'html':
+ case 'text/html':
+ return SIMPLEPIE_CONSTRUCT_HTML | $mode;
+
+ case 'xhtml':
+ case 'application/xhtml+xml':
+ return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
+
+ default:
+ return SIMPLEPIE_CONSTRUCT_NONE | $mode;
+ }
+ }
+ else
+ {
+ return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
+ }
+ }
+
+ public static function atom_10_construct_type($attribs)
+ {
+ if (isset($attribs['']['type']))
+ {
+ switch (strtolower(trim($attribs['']['type'])))
+ {
+ case 'text':
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+
+ case 'html':
+ return SIMPLEPIE_CONSTRUCT_HTML;
+
+ case 'xhtml':
+ return SIMPLEPIE_CONSTRUCT_XHTML;
+
+ default:
+ return SIMPLEPIE_CONSTRUCT_NONE;
+ }
+ }
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+
+ public static function atom_10_content_construct_type($attribs)
+ {
+ if (isset($attribs['']['type']))
+ {
+ $type = strtolower(trim($attribs['']['type']));
+ switch ($type)
+ {
+ case 'text':
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+
+ case 'html':
+ return SIMPLEPIE_CONSTRUCT_HTML;
+
+ case 'xhtml':
+ return SIMPLEPIE_CONSTRUCT_XHTML;
+ }
+ if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) === 'text/')
+ {
+ return SIMPLEPIE_CONSTRUCT_NONE;
+ }
+ else
+ {
+ return SIMPLEPIE_CONSTRUCT_BASE64;
+ }
+ }
+ else
+ {
+ return SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+ }
+
+ public static function is_isegment_nz_nc($string)
+ {
+ return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
+ }
+
+ public static function space_seperated_tokens($string)
+ {
+ $space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
+ $string_length = strlen($string);
+
+ $position = strspn($string, $space_characters);
+ $tokens = array();
+
+ while ($position < $string_length)
+ {
+ $len = strcspn($string, $space_characters, $position);
+ $tokens[] = substr($string, $position, $len);
+ $position += $len;
+ $position += strspn($string, $space_characters, $position);
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Converts a unicode codepoint to a UTF-8 character
+ *
+ * @static
+ * @param int $codepoint Unicode codepoint
+ * @return string UTF-8 character
+ */
+ public static function codepoint_to_utf8($codepoint)
+ {
+ $codepoint = (int) $codepoint;
+ if ($codepoint < 0)
+ {
+ return false;
+ }
+ else if ($codepoint <= 0x7f)
+ {
+ return chr($codepoint);
+ }
+ else if ($codepoint <= 0x7ff)
+ {
+ return chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
+ }
+ else if ($codepoint <= 0xffff)
+ {
+ return chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
+ }
+ else if ($codepoint <= 0x10ffff)
+ {
+ return chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
+ }
+ else
+ {
+ // U+FFFD REPLACEMENT CHARACTER
+ return "\xEF\xBF\xBD";
+ }
+ }
+
+ /**
+ * Similar to parse_str()
+ *
+ * Returns an associative array of name/value pairs, where the value is an
+ * array of values that have used the same name
+ *
+ * @static
+ * @param string $str The input string.
+ * @return array
+ */
+ public static function parse_str($str)
+ {
+ $return = array();
+ $str = explode('&', $str);
+
+ foreach ($str as $section)
+ {
+ if (strpos($section, '=') !== false)
+ {
+ list($name, $value) = explode('=', $section, 2);
+ $return[urldecode($name)][] = urldecode($value);
+ }
+ else
+ {
+ $return[urldecode($section)][] = null;
+ }
+ }
+
+ return $return;
+ }
+
+ /**
+ * Detect XML encoding, as per XML 1.0 Appendix F.1
+ *
+ * @todo Add support for EBCDIC
+ * @param string $data XML data
+ * @param SimplePie_Registry $registry Class registry
+ * @return array Possible encodings
+ */
+ public static function xml_encoding($data, $registry)
+ {
+ // UTF-32 Big Endian BOM
+ if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+ {
+ $encoding[] = 'UTF-32BE';
+ }
+ // UTF-32 Little Endian BOM
+ elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+ {
+ $encoding[] = 'UTF-32LE';
+ }
+ // UTF-16 Big Endian BOM
+ elseif (substr($data, 0, 2) === "\xFE\xFF")
+ {
+ $encoding[] = 'UTF-16BE';
+ }
+ // UTF-16 Little Endian BOM
+ elseif (substr($data, 0, 2) === "\xFF\xFE")
+ {
+ $encoding[] = 'UTF-16LE';
+ }
+ // UTF-8 BOM
+ elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+ {
+ $encoding[] = 'UTF-8';
+ }
+ // UTF-32 Big Endian Without BOM
+ elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
+ {
+ if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
+ {
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8')));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-32BE';
+ }
+ // UTF-32 Little Endian Without BOM
+ elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
+ {
+ if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
+ {
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8')));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-32LE';
+ }
+ // UTF-16 Big Endian Without BOM
+ elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
+ {
+ if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
+ {
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8')));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-16BE';
+ }
+ // UTF-16 Little Endian Without BOM
+ elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
+ {
+ if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
+ {
+ $parser = $registry->create('XML_Declaration_Parser', array(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8')));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-16LE';
+ }
+ // US-ASCII (or superset)
+ elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
+ {
+ if ($pos = strpos($data, "\x3F\x3E"))
+ {
+ $parser = $registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
+ if ($parser->parse())
+ {
+ $encoding[] = $parser->encoding;
+ }
+ }
+ $encoding[] = 'UTF-8';
+ }
+ // Fallback to UTF-8
+ else
+ {
+ $encoding[] = 'UTF-8';
+ }
+ return $encoding;
+ }
+
+ public static function output_javascript()
+ {
+ if (function_exists('ob_gzhandler'))
+ {
+ ob_start('ob_gzhandler');
+ }
+ header('Content-type: text/javascript; charset: UTF-8');
+ header('Cache-Control: must-revalidate');
+ header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
+ ?>
+function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
+ if (placeholder != '') {
+ document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
+ }
+ else {
+ document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
+ }
+}
+
+function embed_flash(bgcolor, width, height, link, loop, type) {
+ document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
+}
+
+function embed_flv(width, height, link, placeholder, loop, player) {
+ document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
+}
+
+function embed_wmedia(width, height, link) {
+ document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
+}
+ <?php
+ }
+
+ /**
+ * Get the SimplePie build timestamp
+ *
+ * Uses the git index if it exists, otherwise uses the modification time
+ * of the newest file.
+ */
+ public static function get_build()
+ {
+ $root = dirname(dirname(__FILE__));
+ if (file_exists($root . '/.git/index'))
+ {
+ return filemtime($root . '/.git/index');
+ }
+ elseif (file_exists($root . '/SimplePie'))
+ {
+ $time = 0;
+ foreach (glob($root . '/SimplePie/*.php') as $file)
+ {
+ if (($mtime = filemtime($file)) > $time)
+ {
+ $time = $mtime;
+ }
+ }
+ return $time;
+ }
+ elseif (file_exists(dirname(__FILE__) . '/Core.php'))
+ {
+ return filemtime(dirname(__FILE__) . '/Core.php');
+ }
+ else
+ {
+ return filemtime(__FILE__);
+ }
+ }
+
+ /**
+ * Format debugging information
+ */
+ public static function debug(&$sp)
+ {
+ $info = 'SimplePie ' . SIMPLEPIE_VERSION . ' Build ' . SIMPLEPIE_BUILD . "\n";
+ $info .= 'PHP ' . PHP_VERSION . "\n";
+ if ($sp->error() !== null)
+ {
+ $info .= 'Error occurred: ' . $sp->error() . "\n";
+ }
+ else
+ {
+ $info .= "No error found.\n";
+ }
+ $info .= "Extensions:\n";
+ $extensions = array('pcre', 'curl', 'zlib', 'mbstring', 'iconv', 'xmlreader', 'xml');
+ foreach ($extensions as $ext)
+ {
+ if (extension_loaded($ext))
+ {
+ $info .= " $ext loaded\n";
+ switch ($ext)
+ {
+ case 'pcre':
+ $info .= ' Version ' . PCRE_VERSION . "\n";
+ break;
+ case 'curl':
+ $version = curl_version();
+ $info .= ' Version ' . $version['version'] . "\n";
+ break;
+ case 'mbstring':
+ $info .= ' Overloading: ' . mb_get_info('func_overload') . "\n";
+ break;
+ case 'iconv':
+ $info .= ' Version ' . ICONV_VERSION . "\n";
+ break;
+ case 'xml':
+ $info .= ' Version ' . LIBXML_DOTTED_VERSION . "\n";
+ break;
+ }
+ }
+ else
+ {
+ $info .= " $ext not loaded\n";
+ }
+ }
+ return $info;
+ }
+
+ public static function silence_errors($num, $str)
+ {
+ // No-op
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Net/IPv6.php b/src/wp-includes/SimplePie/Net/IPv6.php
new file mode 100644
index 0000000000..da80d8acac
--- /dev/null
+++ b/src/wp-includes/SimplePie/Net/IPv6.php
@@ -0,0 +1,276 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Class to validate and to work with IPv6 addresses.
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @copyright 2003-2005 The PHP Group
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @link http://pear.php.net/package/Net_IPv6
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @author elfrink at introweb dot nl
+ * @author Josh Peck <jmp at joshpeck dot org>
+ * @author Geoffrey Sneddon <geoffers@gmail.com>
+ */
+class SimplePie_Net_IPv6
+{
+ /**
+ * Uncompresses an IPv6 address
+ *
+ * RFC 4291 allows you to compress concecutive zero pieces in an address to
+ * '::'. This method expects a valid IPv6 address and expands the '::' to
+ * the required number of zero pieces.
+ *
+ * Example: FF01::101 -> FF01:0:0:0:0:0:0:101
+ * ::1 -> 0:0:0:0:0:0:0:1
+ *
+ * @author Alexander Merz <alexander.merz@web.de>
+ * @author elfrink at introweb dot nl
+ * @author Josh Peck <jmp at joshpeck dot org>
+ * @copyright 2003-2005 The PHP Group
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @param string $ip An IPv6 address
+ * @return string The uncompressed IPv6 address
+ */
+ public static function uncompress($ip)
+ {
+ $c1 = -1;
+ $c2 = -1;
+ if (substr_count($ip, '::') === 1)
+ {
+ list($ip1, $ip2) = explode('::', $ip);
+ if ($ip1 === '')
+ {
+ $c1 = -1;
+ }
+ else
+ {
+ $c1 = substr_count($ip1, ':');
+ }
+ if ($ip2 === '')
+ {
+ $c2 = -1;
+ }
+ else
+ {
+ $c2 = substr_count($ip2, ':');
+ }
+ if (strpos($ip2, '.') !== false)
+ {
+ $c2++;
+ }
+ // ::
+ if ($c1 === -1 && $c2 === -1)
+ {
+ $ip = '0:0:0:0:0:0:0:0';
+ }
+ // ::xxx
+ else if ($c1 === -1)
+ {
+ $fill = str_repeat('0:', 7 - $c2);
+ $ip = str_replace('::', $fill, $ip);
+ }
+ // xxx::
+ else if ($c2 === -1)
+ {
+ $fill = str_repeat(':0', 7 - $c1);
+ $ip = str_replace('::', $fill, $ip);
+ }
+ // xxx::xxx
+ else
+ {
+ $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
+ $ip = str_replace('::', $fill, $ip);
+ }
+ }
+ return $ip;
+ }
+
+ /**
+ * Compresses an IPv6 address
+ *
+ * RFC 4291 allows you to compress concecutive zero pieces in an address to
+ * '::'. This method expects a valid IPv6 address and compresses consecutive
+ * zero pieces to '::'.
+ *
+ * Example: FF01:0:0:0:0:0:0:101 -> FF01::101
+ * 0:0:0:0:0:0:0:1 -> ::1
+ *
+ * @see uncompress()
+ * @param string $ip An IPv6 address
+ * @return string The compressed IPv6 address
+ */
+ public static function compress($ip)
+ {
+ // Prepare the IP to be compressed
+ $ip = self::uncompress($ip);
+ $ip_parts = self::split_v6_v4($ip);
+
+ // Replace all leading zeros
+ $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
+
+ // Find bunches of zeros
+ if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE))
+ {
+ $max = 0;
+ $pos = null;
+ foreach ($matches[0] as $match)
+ {
+ if (strlen($match[0]) > $max)
+ {
+ $max = strlen($match[0]);
+ $pos = $match[1];
+ }
+ }
+
+ $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
+ }
+
+ if ($ip_parts[1] !== '')
+ {
+ return implode(':', $ip_parts);
+ }
+ else
+ {
+ return $ip_parts[0];
+ }
+ }
+
+ /**
+ * Splits an IPv6 address into the IPv6 and IPv4 representation parts
+ *
+ * RFC 4291 allows you to represent the last two parts of an IPv6 address
+ * using the standard IPv4 representation
+ *
+ * Example: 0:0:0:0:0:0:13.1.68.3
+ * 0:0:0:0:0:FFFF:129.144.52.38
+ *
+ * @param string $ip An IPv6 address
+ * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
+ */
+ private static function split_v6_v4($ip)
+ {
+ if (strpos($ip, '.') !== false)
+ {
+ $pos = strrpos($ip, ':');
+ $ipv6_part = substr($ip, 0, $pos);
+ $ipv4_part = substr($ip, $pos + 1);
+ return array($ipv6_part, $ipv4_part);
+ }
+ else
+ {
+ return array($ip, '');
+ }
+ }
+
+ /**
+ * Checks an IPv6 address
+ *
+ * Checks if the given IP is a valid IPv6 address
+ *
+ * @param string $ip An IPv6 address
+ * @return bool true if $ip is a valid IPv6 address
+ */
+ public static function check_ipv6($ip)
+ {
+ $ip = self::uncompress($ip);
+ list($ipv6, $ipv4) = self::split_v6_v4($ip);
+ $ipv6 = explode(':', $ipv6);
+ $ipv4 = explode('.', $ipv4);
+ if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
+ {
+ foreach ($ipv6 as $ipv6_part)
+ {
+ // The section can't be empty
+ if ($ipv6_part === '')
+ return false;
+
+ // Nor can it be over four characters
+ if (strlen($ipv6_part) > 4)
+ return false;
+
+ // Remove leading zeros (this is safe because of the above)
+ $ipv6_part = ltrim($ipv6_part, '0');
+ if ($ipv6_part === '')
+ $ipv6_part = '0';
+
+ // Check the value is valid
+ $value = hexdec($ipv6_part);
+ if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
+ return false;
+ }
+ if (count($ipv4) === 4)
+ {
+ foreach ($ipv4 as $ipv4_part)
+ {
+ $value = (int) $ipv4_part;
+ if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
+ return false;
+ }
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given IP is a valid IPv6 address
+ *
+ * @codeCoverageIgnore
+ * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
+ * @see check_ipv6
+ * @param string $ip An IPv6 address
+ * @return bool true if $ip is a valid IPv6 address
+ */
+ public static function checkIPv6($ip)
+ {
+ return self::check_ipv6($ip);
+ }
+}
diff --git a/src/wp-includes/SimplePie/Parse/Date.php b/src/wp-includes/SimplePie/Parse/Date.php
new file mode 100644
index 0000000000..d51f500d3f
--- /dev/null
+++ b/src/wp-includes/SimplePie/Parse/Date.php
@@ -0,0 +1,983 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Date Parser
+ *
+ * @package SimplePie
+ * @subpackage Parsing
+ */
+class SimplePie_Parse_Date
+{
+ /**
+ * Input data
+ *
+ * @access protected
+ * @var string
+ */
+ var $date;
+
+ /**
+ * List of days, calendar day name => ordinal day number in the week
+ *
+ * @access protected
+ * @var array
+ */
+ var $day = array(
+ // English
+ 'mon' => 1,
+ 'monday' => 1,
+ 'tue' => 2,
+ 'tuesday' => 2,
+ 'wed' => 3,
+ 'wednesday' => 3,
+ 'thu' => 4,
+ 'thursday' => 4,
+ 'fri' => 5,
+ 'friday' => 5,
+ 'sat' => 6,
+ 'saturday' => 6,
+ 'sun' => 7,
+ 'sunday' => 7,
+ // Dutch
+ 'maandag' => 1,
+ 'dinsdag' => 2,
+ 'woensdag' => 3,
+ 'donderdag' => 4,
+ 'vrijdag' => 5,
+ 'zaterdag' => 6,
+ 'zondag' => 7,
+ // French
+ 'lundi' => 1,
+ 'mardi' => 2,
+ 'mercredi' => 3,
+ 'jeudi' => 4,
+ 'vendredi' => 5,
+ 'samedi' => 6,
+ 'dimanche' => 7,
+ // German
+ 'montag' => 1,
+ 'dienstag' => 2,
+ 'mittwoch' => 3,
+ 'donnerstag' => 4,
+ 'freitag' => 5,
+ 'samstag' => 6,
+ 'sonnabend' => 6,
+ 'sonntag' => 7,
+ // Italian
+ 'lunedì' => 1,
+ 'martedì' => 2,
+ 'mercoledì' => 3,
+ 'giovedì' => 4,
+ 'venerdì' => 5,
+ 'sabato' => 6,
+ 'domenica' => 7,
+ // Spanish
+ 'lunes' => 1,
+ 'martes' => 2,
+ 'miércoles' => 3,
+ 'jueves' => 4,
+ 'viernes' => 5,
+ 'sábado' => 6,
+ 'domingo' => 7,
+ // Finnish
+ 'maanantai' => 1,
+ 'tiistai' => 2,
+ 'keskiviikko' => 3,
+ 'torstai' => 4,
+ 'perjantai' => 5,
+ 'lauantai' => 6,
+ 'sunnuntai' => 7,
+ // Hungarian
+ 'hétfő' => 1,
+ 'kedd' => 2,
+ 'szerda' => 3,
+ 'csütörtok' => 4,
+ 'péntek' => 5,
+ 'szombat' => 6,
+ 'vasárnap' => 7,
+ // Greek
+ 'Δευ' => 1,
+ 'ΤÏι' => 2,
+ 'Τετ' => 3,
+ 'Πεμ' => 4,
+ 'ΠαÏ' => 5,
+ 'Σαβ' => 6,
+ 'ΚυÏ' => 7,
+ );
+
+ /**
+ * List of months, calendar month name => calendar month number
+ *
+ * @access protected
+ * @var array
+ */
+ var $month = array(
+ // English
+ 'jan' => 1,
+ 'january' => 1,
+ 'feb' => 2,
+ 'february' => 2,
+ 'mar' => 3,
+ 'march' => 3,
+ 'apr' => 4,
+ 'april' => 4,
+ 'may' => 5,
+ // No long form of May
+ 'jun' => 6,
+ 'june' => 6,
+ 'jul' => 7,
+ 'july' => 7,
+ 'aug' => 8,
+ 'august' => 8,
+ 'sep' => 9,
+ 'september' => 8,
+ 'oct' => 10,
+ 'october' => 10,
+ 'nov' => 11,
+ 'november' => 11,
+ 'dec' => 12,
+ 'december' => 12,
+ // Dutch
+ 'januari' => 1,
+ 'februari' => 2,
+ 'maart' => 3,
+ 'april' => 4,
+ 'mei' => 5,
+ 'juni' => 6,
+ 'juli' => 7,
+ 'augustus' => 8,
+ 'september' => 9,
+ 'oktober' => 10,
+ 'november' => 11,
+ 'december' => 12,
+ // French
+ 'janvier' => 1,
+ 'février' => 2,
+ 'mars' => 3,
+ 'avril' => 4,
+ 'mai' => 5,
+ 'juin' => 6,
+ 'juillet' => 7,
+ 'août' => 8,
+ 'septembre' => 9,
+ 'octobre' => 10,
+ 'novembre' => 11,
+ 'décembre' => 12,
+ // German
+ 'januar' => 1,
+ 'februar' => 2,
+ 'märz' => 3,
+ 'april' => 4,
+ 'mai' => 5,
+ 'juni' => 6,
+ 'juli' => 7,
+ 'august' => 8,
+ 'september' => 9,
+ 'oktober' => 10,
+ 'november' => 11,
+ 'dezember' => 12,
+ // Italian
+ 'gennaio' => 1,
+ 'febbraio' => 2,
+ 'marzo' => 3,
+ 'aprile' => 4,
+ 'maggio' => 5,
+ 'giugno' => 6,
+ 'luglio' => 7,
+ 'agosto' => 8,
+ 'settembre' => 9,
+ 'ottobre' => 10,
+ 'novembre' => 11,
+ 'dicembre' => 12,
+ // Spanish
+ 'enero' => 1,
+ 'febrero' => 2,
+ 'marzo' => 3,
+ 'abril' => 4,
+ 'mayo' => 5,
+ 'junio' => 6,
+ 'julio' => 7,
+ 'agosto' => 8,
+ 'septiembre' => 9,
+ 'setiembre' => 9,
+ 'octubre' => 10,
+ 'noviembre' => 11,
+ 'diciembre' => 12,
+ // Finnish
+ 'tammikuu' => 1,
+ 'helmikuu' => 2,
+ 'maaliskuu' => 3,
+ 'huhtikuu' => 4,
+ 'toukokuu' => 5,
+ 'kesäkuu' => 6,
+ 'heinäkuu' => 7,
+ 'elokuu' => 8,
+ 'suuskuu' => 9,
+ 'lokakuu' => 10,
+ 'marras' => 11,
+ 'joulukuu' => 12,
+ // Hungarian
+ 'január' => 1,
+ 'február' => 2,
+ 'március' => 3,
+ 'április' => 4,
+ 'május' => 5,
+ 'június' => 6,
+ 'július' => 7,
+ 'augusztus' => 8,
+ 'szeptember' => 9,
+ 'október' => 10,
+ 'november' => 11,
+ 'december' => 12,
+ // Greek
+ 'Ιαν' => 1,
+ 'Φεβ' => 2,
+ 'Μάώ' => 3,
+ 'Μαώ' => 3,
+ 'ΑπÏ' => 4,
+ 'Μάι' => 5,
+ 'Μαϊ' => 5,
+ 'Μαι' => 5,
+ 'ΙοÏν' => 6,
+ 'Ιον' => 6,
+ 'ΙοÏλ' => 7,
+ 'Ιολ' => 7,
+ 'ΑÏγ' => 8,
+ 'Αυγ' => 8,
+ 'Σεπ' => 9,
+ 'Οκτ' => 10,
+ 'Îοέ' => 11,
+ 'Δεκ' => 12,
+ );
+
+ /**
+ * List of timezones, abbreviation => offset from UTC
+ *
+ * @access protected
+ * @var array
+ */
+ var $timezone = array(
+ 'ACDT' => 37800,
+ 'ACIT' => 28800,
+ 'ACST' => 34200,
+ 'ACT' => -18000,
+ 'ACWDT' => 35100,
+ 'ACWST' => 31500,
+ 'AEDT' => 39600,
+ 'AEST' => 36000,
+ 'AFT' => 16200,
+ 'AKDT' => -28800,
+ 'AKST' => -32400,
+ 'AMDT' => 18000,
+ 'AMT' => -14400,
+ 'ANAST' => 46800,
+ 'ANAT' => 43200,
+ 'ART' => -10800,
+ 'AZOST' => -3600,
+ 'AZST' => 18000,
+ 'AZT' => 14400,
+ 'BIOT' => 21600,
+ 'BIT' => -43200,
+ 'BOT' => -14400,
+ 'BRST' => -7200,
+ 'BRT' => -10800,
+ 'BST' => 3600,
+ 'BTT' => 21600,
+ 'CAST' => 18000,
+ 'CAT' => 7200,
+ 'CCT' => 23400,
+ 'CDT' => -18000,
+ 'CEDT' => 7200,
+ 'CET' => 3600,
+ 'CGST' => -7200,
+ 'CGT' => -10800,
+ 'CHADT' => 49500,
+ 'CHAST' => 45900,
+ 'CIST' => -28800,
+ 'CKT' => -36000,
+ 'CLDT' => -10800,
+ 'CLST' => -14400,
+ 'COT' => -18000,
+ 'CST' => -21600,
+ 'CVT' => -3600,
+ 'CXT' => 25200,
+ 'DAVT' => 25200,
+ 'DTAT' => 36000,
+ 'EADT' => -18000,
+ 'EAST' => -21600,
+ 'EAT' => 10800,
+ 'ECT' => -18000,
+ 'EDT' => -14400,
+ 'EEST' => 10800,
+ 'EET' => 7200,
+ 'EGT' => -3600,
+ 'EKST' => 21600,
+ 'EST' => -18000,
+ 'FJT' => 43200,
+ 'FKDT' => -10800,
+ 'FKST' => -14400,
+ 'FNT' => -7200,
+ 'GALT' => -21600,
+ 'GEDT' => 14400,
+ 'GEST' => 10800,
+ 'GFT' => -10800,
+ 'GILT' => 43200,
+ 'GIT' => -32400,
+ 'GST' => 14400,
+ 'GST' => -7200,
+ 'GYT' => -14400,
+ 'HAA' => -10800,
+ 'HAC' => -18000,
+ 'HADT' => -32400,
+ 'HAE' => -14400,
+ 'HAP' => -25200,
+ 'HAR' => -21600,
+ 'HAST' => -36000,
+ 'HAT' => -9000,
+ 'HAY' => -28800,
+ 'HKST' => 28800,
+ 'HMT' => 18000,
+ 'HNA' => -14400,
+ 'HNC' => -21600,
+ 'HNE' => -18000,
+ 'HNP' => -28800,
+ 'HNR' => -25200,
+ 'HNT' => -12600,
+ 'HNY' => -32400,
+ 'IRDT' => 16200,
+ 'IRKST' => 32400,
+ 'IRKT' => 28800,
+ 'IRST' => 12600,
+ 'JFDT' => -10800,
+ 'JFST' => -14400,
+ 'JST' => 32400,
+ 'KGST' => 21600,
+ 'KGT' => 18000,
+ 'KOST' => 39600,
+ 'KOVST' => 28800,
+ 'KOVT' => 25200,
+ 'KRAST' => 28800,
+ 'KRAT' => 25200,
+ 'KST' => 32400,
+ 'LHDT' => 39600,
+ 'LHST' => 37800,
+ 'LINT' => 50400,
+ 'LKT' => 21600,
+ 'MAGST' => 43200,
+ 'MAGT' => 39600,
+ 'MAWT' => 21600,
+ 'MDT' => -21600,
+ 'MESZ' => 7200,
+ 'MEZ' => 3600,
+ 'MHT' => 43200,
+ 'MIT' => -34200,
+ 'MNST' => 32400,
+ 'MSDT' => 14400,
+ 'MSST' => 10800,
+ 'MST' => -25200,
+ 'MUT' => 14400,
+ 'MVT' => 18000,
+ 'MYT' => 28800,
+ 'NCT' => 39600,
+ 'NDT' => -9000,
+ 'NFT' => 41400,
+ 'NMIT' => 36000,
+ 'NOVST' => 25200,
+ 'NOVT' => 21600,
+ 'NPT' => 20700,
+ 'NRT' => 43200,
+ 'NST' => -12600,
+ 'NUT' => -39600,
+ 'NZDT' => 46800,
+ 'NZST' => 43200,
+ 'OMSST' => 25200,
+ 'OMST' => 21600,
+ 'PDT' => -25200,
+ 'PET' => -18000,
+ 'PETST' => 46800,
+ 'PETT' => 43200,
+ 'PGT' => 36000,
+ 'PHOT' => 46800,
+ 'PHT' => 28800,
+ 'PKT' => 18000,
+ 'PMDT' => -7200,
+ 'PMST' => -10800,
+ 'PONT' => 39600,
+ 'PST' => -28800,
+ 'PWT' => 32400,
+ 'PYST' => -10800,
+ 'PYT' => -14400,
+ 'RET' => 14400,
+ 'ROTT' => -10800,
+ 'SAMST' => 18000,
+ 'SAMT' => 14400,
+ 'SAST' => 7200,
+ 'SBT' => 39600,
+ 'SCDT' => 46800,
+ 'SCST' => 43200,
+ 'SCT' => 14400,
+ 'SEST' => 3600,
+ 'SGT' => 28800,
+ 'SIT' => 28800,
+ 'SRT' => -10800,
+ 'SST' => -39600,
+ 'SYST' => 10800,
+ 'SYT' => 7200,
+ 'TFT' => 18000,
+ 'THAT' => -36000,
+ 'TJT' => 18000,
+ 'TKT' => -36000,
+ 'TMT' => 18000,
+ 'TOT' => 46800,
+ 'TPT' => 32400,
+ 'TRUT' => 36000,
+ 'TVT' => 43200,
+ 'TWT' => 28800,
+ 'UYST' => -7200,
+ 'UYT' => -10800,
+ 'UZT' => 18000,
+ 'VET' => -14400,
+ 'VLAST' => 39600,
+ 'VLAT' => 36000,
+ 'VOST' => 21600,
+ 'VUT' => 39600,
+ 'WAST' => 7200,
+ 'WAT' => 3600,
+ 'WDT' => 32400,
+ 'WEST' => 3600,
+ 'WFT' => 43200,
+ 'WIB' => 25200,
+ 'WIT' => 32400,
+ 'WITA' => 28800,
+ 'WKST' => 18000,
+ 'WST' => 28800,
+ 'YAKST' => 36000,
+ 'YAKT' => 32400,
+ 'YAPT' => 36000,
+ 'YEKST' => 21600,
+ 'YEKT' => 18000,
+ );
+
+ /**
+ * Cached PCRE for SimplePie_Parse_Date::$day
+ *
+ * @access protected
+ * @var string
+ */
+ var $day_pcre;
+
+ /**
+ * Cached PCRE for SimplePie_Parse_Date::$month
+ *
+ * @access protected
+ * @var string
+ */
+ var $month_pcre;
+
+ /**
+ * Array of user-added callback methods
+ *
+ * @access private
+ * @var array
+ */
+ var $built_in = array();
+
+ /**
+ * Array of user-added callback methods
+ *
+ * @access private
+ * @var array
+ */
+ var $user = array();
+
+ /**
+ * Create new SimplePie_Parse_Date object, and set self::day_pcre,
+ * self::month_pcre, and self::built_in
+ *
+ * @access private
+ */
+ public function __construct()
+ {
+ $this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
+ $this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
+
+ static $cache;
+ if (!isset($cache[get_class($this)]))
+ {
+ $all_methods = get_class_methods($this);
+
+ foreach ($all_methods as $method)
+ {
+ if (strtolower(substr($method, 0, 5)) === 'date_')
+ {
+ $cache[get_class($this)][] = $method;
+ }
+ }
+ }
+
+ foreach ($cache[get_class($this)] as $method)
+ {
+ $this->built_in[] = $method;
+ }
+ }
+
+ /**
+ * Get the object
+ *
+ * @access public
+ */
+ public static function get()
+ {
+ static $object;
+ if (!$object)
+ {
+ $object = new SimplePie_Parse_Date;
+ }
+ return $object;
+ }
+
+ /**
+ * Parse a date
+ *
+ * @final
+ * @access public
+ * @param string $date Date to parse
+ * @return int Timestamp corresponding to date string, or false on failure
+ */
+ public function parse($date)
+ {
+ foreach ($this->user as $method)
+ {
+ if (($returned = call_user_func($method, $date)) !== false)
+ {
+ return $returned;
+ }
+ }
+
+ foreach ($this->built_in as $method)
+ {
+ if (($returned = call_user_func(array($this, $method), $date)) !== false)
+ {
+ return $returned;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Add a callback method to parse a date
+ *
+ * @final
+ * @access public
+ * @param callback $callback
+ */
+ public function add_callback($callback)
+ {
+ if (is_callable($callback))
+ {
+ $this->user[] = $callback;
+ }
+ else
+ {
+ trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
+ }
+ }
+
+ /**
+ * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
+ * well as allowing any of upper or lower case "T", horizontal tabs, or
+ * spaces to be used as the time seperator (including more than one))
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ public function date_w3cdtf($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $year = '([0-9]{4})';
+ $month = $day = $hour = $minute = $second = '([0-9]{2})';
+ $decimal = '([0-9]*)';
+ $zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
+ $pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
+ }
+ if (preg_match($pcre, $date, $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Year
+ 2: Month
+ 3: Day
+ 4: Hour
+ 5: Minute
+ 6: Second
+ 7: Decimal fraction of a second
+ 8: Zulu
+ 9: Timezone ±
+ 10: Timezone hours
+ 11: Timezone minutes
+ */
+
+ // Fill in empty matches
+ for ($i = count($match); $i <= 3; $i++)
+ {
+ $match[$i] = '1';
+ }
+
+ for ($i = count($match); $i <= 7; $i++)
+ {
+ $match[$i] = '0';
+ }
+
+ // Numeric timezone
+ if (isset($match[9]) && $match[9] !== '')
+ {
+ $timezone = $match[10] * 3600;
+ $timezone += $match[11] * 60;
+ if ($match[9] === '-')
+ {
+ $timezone = 0 - $timezone;
+ }
+ }
+ else
+ {
+ $timezone = 0;
+ }
+
+ // Convert the number of seconds to an integer, taking decimals into account
+ $second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
+
+ return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Remove RFC822 comments
+ *
+ * @access protected
+ * @param string $data Data to strip comments from
+ * @return string Comment stripped string
+ */
+ public function remove_rfc2822_comments($string)
+ {
+ $string = (string) $string;
+ $position = 0;
+ $length = strlen($string);
+ $depth = 0;
+
+ $output = '';
+
+ while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
+ {
+ $output .= substr($string, $position, $pos - $position);
+ $position = $pos + 1;
+ if ($string[$pos - 1] !== '\\')
+ {
+ $depth++;
+ while ($depth && $position < $length)
+ {
+ $position += strcspn($string, '()', $position);
+ if ($string[$position - 1] === '\\')
+ {
+ $position++;
+ continue;
+ }
+ elseif (isset($string[$position]))
+ {
+ switch ($string[$position])
+ {
+ case '(':
+ $depth++;
+ break;
+
+ case ')':
+ $depth--;
+ break;
+ }
+ $position++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ $output .= '(';
+ }
+ }
+ $output .= substr($string, $position);
+
+ return $output;
+ }
+
+ /**
+ * Parse RFC2822's date format
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ public function date_rfc2822($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $wsp = '[\x09\x20]';
+ $fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
+ $optional_fws = $fws . '?';
+ $day_name = $this->day_pcre;
+ $month = $this->month_pcre;
+ $day = '([0-9]{1,2})';
+ $hour = $minute = $second = '([0-9]{2})';
+ $year = '([0-9]{2,4})';
+ $num_zone = '([+\-])([0-9]{2})([0-9]{2})';
+ $character_zone = '([A-Z]{1,5})';
+ $zone = '(?:' . $num_zone . '|' . $character_zone . ')';
+ $pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
+ }
+ if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Day name
+ 2: Day
+ 3: Month
+ 4: Year
+ 5: Hour
+ 6: Minute
+ 7: Second
+ 8: Timezone ±
+ 9: Timezone hours
+ 10: Timezone minutes
+ 11: Alphabetic timezone
+ */
+
+ // Find the month number
+ $month = $this->month[strtolower($match[3])];
+
+ // Numeric timezone
+ if ($match[8] !== '')
+ {
+ $timezone = $match[9] * 3600;
+ $timezone += $match[10] * 60;
+ if ($match[8] === '-')
+ {
+ $timezone = 0 - $timezone;
+ }
+ }
+ // Character timezone
+ elseif (isset($this->timezone[strtoupper($match[11])]))
+ {
+ $timezone = $this->timezone[strtoupper($match[11])];
+ }
+ // Assume everything else to be -0000
+ else
+ {
+ $timezone = 0;
+ }
+
+ // Deal with 2/3 digit years
+ if ($match[4] < 50)
+ {
+ $match[4] += 2000;
+ }
+ elseif ($match[4] < 1000)
+ {
+ $match[4] += 1900;
+ }
+
+ // Second is optional, if it is empty set it to zero
+ if ($match[7] !== '')
+ {
+ $second = $match[7];
+ }
+ else
+ {
+ $second = 0;
+ }
+
+ return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Parse RFC850's date format
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ public function date_rfc850($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $space = '[\x09\x20]+';
+ $day_name = $this->day_pcre;
+ $month = $this->month_pcre;
+ $day = '([0-9]{1,2})';
+ $year = $hour = $minute = $second = '([0-9]{2})';
+ $zone = '([A-Z]{1,5})';
+ $pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
+ }
+ if (preg_match($pcre, $date, $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Day name
+ 2: Day
+ 3: Month
+ 4: Year
+ 5: Hour
+ 6: Minute
+ 7: Second
+ 8: Timezone
+ */
+
+ // Month
+ $month = $this->month[strtolower($match[3])];
+
+ // Character timezone
+ if (isset($this->timezone[strtoupper($match[8])]))
+ {
+ $timezone = $this->timezone[strtoupper($match[8])];
+ }
+ // Assume everything else to be -0000
+ else
+ {
+ $timezone = 0;
+ }
+
+ // Deal with 2 digit year
+ if ($match[4] < 50)
+ {
+ $match[4] += 2000;
+ }
+ else
+ {
+ $match[4] += 1900;
+ }
+
+ return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Parse C99's asctime()'s date format
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ public function date_asctime($date)
+ {
+ static $pcre;
+ if (!$pcre)
+ {
+ $space = '[\x09\x20]+';
+ $wday_name = $this->day_pcre;
+ $mon_name = $this->month_pcre;
+ $day = '([0-9]{1,2})';
+ $hour = $sec = $min = '([0-9]{2})';
+ $year = '([0-9]{4})';
+ $terminator = '\x0A?\x00?';
+ $pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
+ }
+ if (preg_match($pcre, $date, $match))
+ {
+ /*
+ Capturing subpatterns:
+ 1: Day name
+ 2: Month
+ 3: Day
+ 4: Hour
+ 5: Minute
+ 6: Second
+ 7: Year
+ */
+
+ $month = $this->month[strtolower($match[2])];
+ return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Parse dates using strtotime()
+ *
+ * @access protected
+ * @return int Timestamp
+ */
+ public function date_strtotime($date)
+ {
+ $strtotime = strtotime($date);
+ if ($strtotime === -1 || $strtotime === false)
+ {
+ return false;
+ }
+ else
+ {
+ return $strtotime;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/Parser.php b/src/wp-includes/SimplePie/Parser.php
new file mode 100644
index 0000000000..d698552ca7
--- /dev/null
+++ b/src/wp-includes/SimplePie/Parser.php
@@ -0,0 +1,407 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Parses XML into something sane
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_parser_class()}
+ *
+ * @package SimplePie
+ * @subpackage Parsing
+ */
+class SimplePie_Parser
+{
+ var $error_code;
+ var $error_string;
+ var $current_line;
+ var $current_column;
+ var $current_byte;
+ var $separator = ' ';
+ var $namespace = array('');
+ var $element = array('');
+ var $xml_base = array('');
+ var $xml_base_explicit = array(false);
+ var $xml_lang = array('');
+ var $data = array();
+ var $datas = array(array());
+ var $current_xhtml_construct = -1;
+ var $encoding;
+ protected $registry;
+
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ public function parse(&$data, $encoding)
+ {
+ // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
+ if (strtoupper($encoding) === 'US-ASCII')
+ {
+ $this->encoding = 'UTF-8';
+ }
+ else
+ {
+ $this->encoding = $encoding;
+ }
+
+ // Strip BOM:
+ // UTF-32 Big Endian BOM
+ if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+ {
+ $data = substr($data, 4);
+ }
+ // UTF-32 Little Endian BOM
+ elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+ {
+ $data = substr($data, 4);
+ }
+ // UTF-16 Big Endian BOM
+ elseif (substr($data, 0, 2) === "\xFE\xFF")
+ {
+ $data = substr($data, 2);
+ }
+ // UTF-16 Little Endian BOM
+ elseif (substr($data, 0, 2) === "\xFF\xFE")
+ {
+ $data = substr($data, 2);
+ }
+ // UTF-8 BOM
+ elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+ {
+ $data = substr($data, 3);
+ }
+
+ if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
+ {
+ $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
+ if ($declaration->parse())
+ {
+ $data = substr($data, $pos + 2);
+ $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
+ }
+ else
+ {
+ $this->error_string = 'SimplePie bug! Please report this!';
+ return false;
+ }
+ }
+
+ $return = true;
+
+ static $xml_is_sane = null;
+ if ($xml_is_sane === null)
+ {
+ $parser_check = xml_parser_create();
+ xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
+ xml_parser_free($parser_check);
+ $xml_is_sane = isset($values[0]['value']);
+ }
+
+ // Create the parser
+ if ($xml_is_sane)
+ {
+ $xml = xml_parser_create_ns($this->encoding, $this->separator);
+ xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
+ xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
+ xml_set_object($xml, $this);
+ xml_set_character_data_handler($xml, 'cdata');
+ xml_set_element_handler($xml, 'tag_open', 'tag_close');
+
+ // Parse!
+ if (!xml_parse($xml, $data, true))
+ {
+ $this->error_code = xml_get_error_code($xml);
+ $this->error_string = xml_error_string($this->error_code);
+ $return = false;
+ }
+ $this->current_line = xml_get_current_line_number($xml);
+ $this->current_column = xml_get_current_column_number($xml);
+ $this->current_byte = xml_get_current_byte_index($xml);
+ xml_parser_free($xml);
+ return $return;
+ }
+ else
+ {
+ libxml_clear_errors();
+ $xml = new XMLReader();
+ $xml->xml($data);
+ while (@$xml->read())
+ {
+ switch ($xml->nodeType)
+ {
+
+ case constant('XMLReader::END_ELEMENT'):
+ if ($xml->namespaceURI !== '')
+ {
+ $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
+ }
+ else
+ {
+ $tagName = $xml->localName;
+ }
+ $this->tag_close(null, $tagName);
+ break;
+ case constant('XMLReader::ELEMENT'):
+ $empty = $xml->isEmptyElement;
+ if ($xml->namespaceURI !== '')
+ {
+ $tagName = $xml->namespaceURI . $this->separator . $xml->localName;
+ }
+ else
+ {
+ $tagName = $xml->localName;
+ }
+ $attributes = array();
+ while ($xml->moveToNextAttribute())
+ {
+ if ($xml->namespaceURI !== '')
+ {
+ $attrName = $xml->namespaceURI . $this->separator . $xml->localName;
+ }
+ else
+ {
+ $attrName = $xml->localName;
+ }
+ $attributes[$attrName] = $xml->value;
+ }
+ $this->tag_open(null, $tagName, $attributes);
+ if ($empty)
+ {
+ $this->tag_close(null, $tagName);
+ }
+ break;
+ case constant('XMLReader::TEXT'):
+
+ case constant('XMLReader::CDATA'):
+ $this->cdata(null, $xml->value);
+ break;
+ }
+ }
+ if ($error = libxml_get_last_error())
+ {
+ $this->error_code = $error->code;
+ $this->error_string = $error->message;
+ $this->current_line = $error->line;
+ $this->current_column = $error->column;
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+
+ public function get_error_code()
+ {
+ return $this->error_code;
+ }
+
+ public function get_error_string()
+ {
+ return $this->error_string;
+ }
+
+ public function get_current_line()
+ {
+ return $this->current_line;
+ }
+
+ public function get_current_column()
+ {
+ return $this->current_column;
+ }
+
+ public function get_current_byte()
+ {
+ return $this->current_byte;
+ }
+
+ public function get_data()
+ {
+ return $this->data;
+ }
+
+ public function tag_open($parser, $tag, $attributes)
+ {
+ list($this->namespace[], $this->element[]) = $this->split_ns($tag);
+
+ $attribs = array();
+ foreach ($attributes as $name => $value)
+ {
+ list($attrib_namespace, $attribute) = $this->split_ns($name);
+ $attribs[$attrib_namespace][$attribute] = $value;
+ }
+
+ if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
+ {
+ $base = $this->registry->call('Misc', 'absolutize_url', array($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base)));
+ if ($base !== false)
+ {
+ $this->xml_base[] = $base;
+ $this->xml_base_explicit[] = true;
+ }
+ }
+ else
+ {
+ $this->xml_base[] = end($this->xml_base);
+ $this->xml_base_explicit[] = end($this->xml_base_explicit);
+ }
+
+ if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
+ {
+ $this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
+ }
+ else
+ {
+ $this->xml_lang[] = end($this->xml_lang);
+ }
+
+ if ($this->current_xhtml_construct >= 0)
+ {
+ $this->current_xhtml_construct++;
+ if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML)
+ {
+ $this->data['data'] .= '<' . end($this->element);
+ if (isset($attribs['']))
+ {
+ foreach ($attribs[''] as $name => $value)
+ {
+ $this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
+ }
+ }
+ $this->data['data'] .= '>';
+ }
+ }
+ else
+ {
+ $this->datas[] =& $this->data;
+ $this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
+ $this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
+ if ((end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] === 'xml')
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] === 'xhtml')
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_20 && in_array(end($this->element), array('title')))
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_090 && in_array(end($this->element), array('title')))
+ || (end($this->namespace) === SIMPLEPIE_NAMESPACE_RSS_10 && in_array(end($this->element), array('title'))))
+ {
+ $this->current_xhtml_construct = 0;
+ }
+ }
+ }
+
+ public function cdata($parser, $cdata)
+ {
+ if ($this->current_xhtml_construct >= 0)
+ {
+ $this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
+ }
+ else
+ {
+ $this->data['data'] .= $cdata;
+ }
+ }
+
+ public function tag_close($parser, $tag)
+ {
+ if ($this->current_xhtml_construct >= 0)
+ {
+ $this->current_xhtml_construct--;
+ if (end($this->namespace) === SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
+ {
+ $this->data['data'] .= '</' . end($this->element) . '>';
+ }
+ }
+ if ($this->current_xhtml_construct === -1)
+ {
+ $this->data =& $this->datas[count($this->datas) - 1];
+ array_pop($this->datas);
+ }
+
+ array_pop($this->element);
+ array_pop($this->namespace);
+ array_pop($this->xml_base);
+ array_pop($this->xml_base_explicit);
+ array_pop($this->xml_lang);
+ }
+
+ public function split_ns($string)
+ {
+ static $cache = array();
+ if (!isset($cache[$string]))
+ {
+ if ($pos = strpos($string, $this->separator))
+ {
+ static $separator_length;
+ if (!$separator_length)
+ {
+ $separator_length = strlen($this->separator);
+ }
+ $namespace = substr($string, 0, $pos);
+ $local_name = substr($string, $pos + $separator_length);
+ if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
+ {
+ $namespace = SIMPLEPIE_NAMESPACE_ITUNES;
+ }
+
+ // Normalize the Media RSS namespaces
+ if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2 ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3 ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4 ||
+ $namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5 )
+ {
+ $namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
+ }
+ $cache[$string] = array($namespace, $local_name);
+ }
+ else
+ {
+ $cache[$string] = array('', $string);
+ }
+ }
+ return $cache[$string];
+ }
+}
diff --git a/src/wp-includes/SimplePie/Rating.php b/src/wp-includes/SimplePie/Rating.php
new file mode 100644
index 0000000000..8689e5dfbd
--- /dev/null
+++ b/src/wp-includes/SimplePie/Rating.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Handles `<media:rating>` or `<itunes:explicit>` tags as defined in Media RSS and iTunes RSS respectively
+ *
+ * Used by {@see SimplePie_Enclosure::get_rating()} and {@see SimplePie_Enclosure::get_ratings()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_rating_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Rating
+{
+ /**
+ * Rating scheme
+ *
+ * @var string
+ * @see get_scheme()
+ */
+ var $scheme;
+
+ /**
+ * Rating value
+ *
+ * @var string
+ * @see get_value()
+ */
+ var $value;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($scheme = null, $value = null)
+ {
+ $this->scheme = $scheme;
+ $this->value = $value;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the organizational scheme for the rating
+ *
+ * @return string|null
+ */
+ public function get_scheme()
+ {
+ if ($this->scheme !== null)
+ {
+ return $this->scheme;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the value of the rating
+ *
+ * @return string|null
+ */
+ public function get_value()
+ {
+ if ($this->value !== null)
+ {
+ return $this->value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/Registry.php b/src/wp-includes/SimplePie/Registry.php
new file mode 100644
index 0000000000..1072cdebb5
--- /dev/null
+++ b/src/wp-includes/SimplePie/Registry.php
@@ -0,0 +1,225 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Handles creating objects and calling methods
+ *
+ * Access this via {@see SimplePie::get_registry()}
+ *
+ * @package SimplePie
+ */
+class SimplePie_Registry
+{
+ /**
+ * Default class mapping
+ *
+ * Overriding classes *must* subclass these.
+ *
+ * @var array
+ */
+ protected $default = array(
+ 'Cache' => 'SimplePie_Cache',
+ 'Locator' => 'SimplePie_Locator',
+ 'Parser' => 'SimplePie_Parser',
+ 'File' => 'SimplePie_File',
+ 'Sanitize' => 'SimplePie_Sanitize',
+ 'Item' => 'SimplePie_Item',
+ 'Author' => 'SimplePie_Author',
+ 'Category' => 'SimplePie_Category',
+ 'Enclosure' => 'SimplePie_Enclosure',
+ 'Caption' => 'SimplePie_Caption',
+ 'Copyright' => 'SimplePie_Copyright',
+ 'Credit' => 'SimplePie_Credit',
+ 'Rating' => 'SimplePie_Rating',
+ 'Restriction' => 'SimplePie_Restriction',
+ 'Content_Type_Sniffer' => 'SimplePie_Content_Type_Sniffer',
+ 'Source' => 'SimplePie_Source',
+ 'Misc' => 'SimplePie_Misc',
+ 'XML_Declaration_Parser' => 'SimplePie_XML_Declaration_Parser',
+ 'Parse_Date' => 'SimplePie_Parse_Date',
+ );
+
+ /**
+ * Class mapping
+ *
+ * @see register()
+ * @var array
+ */
+ protected $classes = array();
+
+ /**
+ * Legacy classes
+ *
+ * @see register()
+ * @var array
+ */
+ protected $legacy = array();
+
+ /**
+ * Constructor
+ *
+ * No-op
+ */
+ public function __construct() { }
+
+ /**
+ * Register a class
+ *
+ * @param string $type See {@see $default} for names
+ * @param string $class Class name, must subclass the corresponding default
+ * @param bool $legacy Whether to enable legacy support for this class
+ * @return bool Successfulness
+ */
+ public function register($type, $class, $legacy = false)
+ {
+ if (!is_subclass_of($class, $this->default[$type]))
+ {
+ return false;
+ }
+
+ $this->classes[$type] = $class;
+
+ if ($legacy)
+ {
+ $this->legacy[] = $class;
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the class registered for a type
+ *
+ * Where possible, use {@see create()} or {@see call()} instead
+ *
+ * @param string $type
+ * @return string|null
+ */
+ public function get_class($type)
+ {
+ if (!empty($this->classes[$type]))
+ {
+ return $this->classes[$type];
+ }
+ if (!empty($this->default[$type]))
+ {
+ return $this->default[$type];
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a new instance of a given type
+ *
+ * @param string $type
+ * @param array $parameters Parameters to pass to the constructor
+ * @return object Instance of class
+ */
+ public function &create($type, $parameters = array())
+ {
+ $class = $this->get_class($type);
+
+ if (in_array($class, $this->legacy))
+ {
+ switch ($type)
+ {
+ case 'locator':
+ // Legacy: file, timeout, useragent, file_class, max_checked_feeds, content_type_sniffer_class
+ // Specified: file, timeout, useragent, max_checked_feeds
+ $replacement = array($this->get_class('file'), $parameters[3], $this->get_class('content_type_sniffer'));
+ array_splice($parameters, 3, 1, $replacement);
+ break;
+ }
+ }
+
+ if (!method_exists($class, '__construct'))
+ {
+ $instance = new $class;
+ }
+ else
+ {
+ $reflector = new ReflectionClass($class);
+ $instance = $reflector->newInstanceArgs($parameters);
+ }
+
+ if (method_exists($instance, 'set_registry'))
+ {
+ $instance->set_registry($this);
+ }
+ return $instance;
+ }
+
+ /**
+ * Call a static method for a type
+ *
+ * @param string $type
+ * @param string $method
+ * @param array $parameters
+ * @return mixed
+ */
+ public function &call($type, $method, $parameters = array())
+ {
+ $class = $this->get_class($type);
+
+ if (in_array($class, $this->legacy))
+ {
+ switch ($type)
+ {
+ case 'Cache':
+ // For backwards compatibility with old non-static
+ // Cache::create() methods
+ if ($method === 'get_handler')
+ {
+ $result = @call_user_func_array(array($class, 'create'), $parameters);
+ return $result;
+ }
+ break;
+ }
+ }
+
+ $result = call_user_func_array(array($class, $method), $parameters);
+ return $result;
+ }
+} \ No newline at end of file
diff --git a/src/wp-includes/SimplePie/Restriction.php b/src/wp-includes/SimplePie/Restriction.php
new file mode 100644
index 0000000000..4ba371bfbc
--- /dev/null
+++ b/src/wp-includes/SimplePie/Restriction.php
@@ -0,0 +1,155 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Handles `<media:restriction>` as defined in Media RSS
+ *
+ * Used by {@see SimplePie_Enclosure::get_restriction()} and {@see SimplePie_Enclosure::get_restrictions()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_restriction_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Restriction
+{
+ /**
+ * Relationship ('allow'/'deny')
+ *
+ * @var string
+ * @see get_relationship()
+ */
+ var $relationship;
+
+ /**
+ * Type of restriction
+ *
+ * @var string
+ * @see get_type()
+ */
+ var $type;
+
+ /**
+ * Restricted values
+ *
+ * @var string
+ * @see get_value()
+ */
+ var $value;
+
+ /**
+ * Constructor, used to input the data
+ *
+ * For documentation on all the parameters, see the corresponding
+ * properties and their accessors
+ */
+ public function __construct($relationship = null, $type = null, $value = null)
+ {
+ $this->relationship = $relationship;
+ $this->type = $type;
+ $this->value = $value;
+ }
+
+ /**
+ * String-ified version
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ // There is no $this->data here
+ return md5(serialize($this));
+ }
+
+ /**
+ * Get the relationship
+ *
+ * @return string|null Either 'allow' or 'deny'
+ */
+ public function get_relationship()
+ {
+ if ($this->relationship !== null)
+ {
+ return $this->relationship;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the type
+ *
+ * @return string|null
+ */
+ public function get_type()
+ {
+ if ($this->type !== null)
+ {
+ return $this->type;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the list of restricted things
+ *
+ * @return string|null
+ */
+ public function get_value()
+ {
+ if ($this->value !== null)
+ {
+ return $this->value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/Sanitize.php b/src/wp-includes/SimplePie/Sanitize.php
new file mode 100644
index 0000000000..442e8e219c
--- /dev/null
+++ b/src/wp-includes/SimplePie/Sanitize.php
@@ -0,0 +1,554 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Used for data cleanup and post-processing
+ *
+ *
+ * This class can be overloaded with {@see SimplePie::set_sanitize_class()}
+ *
+ * @package SimplePie
+ * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
+ */
+class SimplePie_Sanitize
+{
+ // Private vars
+ var $base;
+
+ // Options
+ var $remove_div = true;
+ var $image_handler = '';
+ var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+ var $encode_instead_of_strip = false;
+ var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+ var $strip_comments = false;
+ var $output_encoding = 'UTF-8';
+ var $enable_cache = true;
+ var $cache_location = './cache';
+ var $cache_name_function = 'md5';
+ var $timeout = 10;
+ var $useragent = '';
+ var $force_fsockopen = false;
+ var $replace_url_attributes = null;
+
+ public function __construct()
+ {
+ // Set defaults
+ $this->set_url_replacements(null);
+ }
+
+ public function remove_div($enable = true)
+ {
+ $this->remove_div = (bool) $enable;
+ }
+
+ public function set_image_handler($page = false)
+ {
+ if ($page)
+ {
+ $this->image_handler = (string) $page;
+ }
+ else
+ {
+ $this->image_handler = false;
+ }
+ }
+
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ public function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
+ {
+ if (isset($enable_cache))
+ {
+ $this->enable_cache = (bool) $enable_cache;
+ }
+
+ if ($cache_location)
+ {
+ $this->cache_location = (string) $cache_location;
+ }
+
+ if ($cache_name_function)
+ {
+ $this->cache_name_function = (string) $cache_name_function;
+ }
+ }
+
+ public function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
+ {
+ if ($timeout)
+ {
+ $this->timeout = (string) $timeout;
+ }
+
+ if ($useragent)
+ {
+ $this->useragent = (string) $useragent;
+ }
+
+ if ($force_fsockopen)
+ {
+ $this->force_fsockopen = (string) $force_fsockopen;
+ }
+ }
+
+ public function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
+ {
+ if ($tags)
+ {
+ if (is_array($tags))
+ {
+ $this->strip_htmltags = $tags;
+ }
+ else
+ {
+ $this->strip_htmltags = explode(',', $tags);
+ }
+ }
+ else
+ {
+ $this->strip_htmltags = false;
+ }
+ }
+
+ public function encode_instead_of_strip($encode = false)
+ {
+ $this->encode_instead_of_strip = (bool) $encode;
+ }
+
+ public function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
+ {
+ if ($attribs)
+ {
+ if (is_array($attribs))
+ {
+ $this->strip_attributes = $attribs;
+ }
+ else
+ {
+ $this->strip_attributes = explode(',', $attribs);
+ }
+ }
+ else
+ {
+ $this->strip_attributes = false;
+ }
+ }
+
+ public function strip_comments($strip = false)
+ {
+ $this->strip_comments = (bool) $strip;
+ }
+
+ public function set_output_encoding($encoding = 'UTF-8')
+ {
+ $this->output_encoding = (string) $encoding;
+ }
+
+ /**
+ * Set element/attribute key/value pairs of HTML attributes
+ * containing URLs that need to be resolved relative to the feed
+ *
+ * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
+ * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
+ * |q|@cite
+ *
+ * @since 1.0
+ * @param array|null $element_attribute Element/attribute key/value pairs, null for default
+ */
+ public function set_url_replacements($element_attribute = null)
+ {
+ if ($element_attribute === null)
+ {
+ $element_attribute = array(
+ 'a' => 'href',
+ 'area' => 'href',
+ 'blockquote' => 'cite',
+ 'del' => 'cite',
+ 'form' => 'action',
+ 'img' => array(
+ 'longdesc',
+ 'src'
+ ),
+ 'input' => 'src',
+ 'ins' => 'cite',
+ 'q' => 'cite'
+ );
+ }
+ $this->replace_url_attributes = (array) $element_attribute;
+ }
+
+ public function sanitize($data, $type, $base = '')
+ {
+ $data = trim($data);
+ if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
+ {
+ if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
+ {
+ if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
+ {
+ $type |= SIMPLEPIE_CONSTRUCT_HTML;
+ }
+ else
+ {
+ $type |= SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+ }
+
+ if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
+ {
+ $data = base64_decode($data);
+ }
+
+ if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
+ {
+
+ if (!class_exists('DOMDocument'))
+ {
+ $this->registry->call('Misc', 'error', array('DOMDocument not found, unable to use sanitizer', E_USER_WARNING, __FILE__, __LINE__));
+ return '';
+ }
+ $document = new DOMDocument();
+ $document->encoding = 'UTF-8';
+ $data = $this->preprocess($data, $type);
+
+ set_error_handler(array('SimplePie_Misc', 'silence_errors'));
+ $document->loadHTML($data);
+ restore_error_handler();
+
+ // Strip comments
+ if ($this->strip_comments)
+ {
+ $xpath = new DOMXPath($document);
+ $comments = $xpath->query('//comment()');
+
+ foreach ($comments as $comment)
+ {
+ $comment->parentNode->removeChild($comment);
+ }
+ }
+
+ // Strip out HTML tags and attributes that might cause various security problems.
+ // Based on recommendations by Mark Pilgrim at:
+ // http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
+ if ($this->strip_htmltags)
+ {
+ foreach ($this->strip_htmltags as $tag)
+ {
+ $this->strip_tag($tag, $document, $type);
+ }
+ }
+
+ if ($this->strip_attributes)
+ {
+ foreach ($this->strip_attributes as $attrib)
+ {
+ $this->strip_attr($attrib, $document);
+ }
+ }
+
+ // Replace relative URLs
+ $this->base = $base;
+ foreach ($this->replace_url_attributes as $element => $attributes)
+ {
+ $this->replace_urls($document, $element, $attributes);
+ }
+
+ // If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
+ if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
+ {
+ $images = $document->getElementsByTagName('img');
+ foreach ($images as $img)
+ {
+ if ($img->hasAttribute('src'))
+ {
+ $image_url = call_user_func($this->cache_name_function, $img->getAttribute('src'));
+ $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, $image_url, 'spi'));
+
+ if ($cache->load())
+ {
+ $img->setAttribute('src', $this->image_handler . $image_url);
+ }
+ else
+ {
+ $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
+ $headers = $file->headers;
+
+ if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
+ {
+ if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
+ {
+ $img->setAttribute('src', $this->image_handler . $image_url);
+ }
+ else
+ {
+ trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Remove the DOCTYPE
+ // Seems to cause segfaulting if we don't do this
+ if ($document->firstChild instanceof DOMDocumentType)
+ {
+ $document->removeChild($document->firstChild);
+ }
+
+ // Move everything from the body to the root
+ $real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
+ $document->replaceChild($real_body, $document->firstChild);
+
+ // Finally, convert to a HTML string
+ $data = trim($document->saveHTML());
+
+ if ($this->remove_div)
+ {
+ $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
+ $data = preg_replace('/<\/div>$/', '', $data);
+ }
+ else
+ {
+ $data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
+ }
+ }
+
+ if ($type & SIMPLEPIE_CONSTRUCT_IRI)
+ {
+ $absolute = $this->registry->call('Misc', 'absolutize_url', array($data, $base));
+ if ($absolute !== false)
+ {
+ $data = $absolute;
+ }
+ }
+
+ if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
+ {
+ $data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
+ }
+
+ if ($this->output_encoding !== 'UTF-8')
+ {
+ $data = $this->registry->call('Misc', 'change_encoding', array($data, 'UTF-8', $this->output_encoding));
+ }
+ }
+ return $data;
+ }
+
+ protected function preprocess($html, $type)
+ {
+ $ret = '';
+ if ($type & ~SIMPLEPIE_CONSTRUCT_XHTML)
+ {
+ // Atom XHTML constructs are wrapped with a div by default
+ // Note: No protection if $html contains a stray </div>!
+ $html = '<div>' . $html . '</div>';
+ $ret .= '<!DOCTYPE html>';
+ $content_type = 'text/html';
+ }
+ else
+ {
+ $ret .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
+ $content_type = 'application/xhtml+xml';
+ }
+
+ $ret .= '<html><head>';
+ $ret .= '<meta http-equiv="Content-Type" content="' . $content_type . '; charset=utf-8" />';
+ $ret .= '</head><body>' . $html . '</body></html>';
+ return $ret;
+ }
+
+ public function replace_urls($document, $tag, $attributes)
+ {
+ if (!is_array($attributes))
+ {
+ $attributes = array($attributes);
+ }
+
+ if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
+ {
+ $elements = $document->getElementsByTagName($tag);
+ foreach ($elements as $element)
+ {
+ foreach ($attributes as $attribute)
+ {
+ if ($element->hasAttribute($attribute))
+ {
+ $value = $this->registry->call('Misc', 'absolutize_url', array($element->getAttribute($attribute), $this->base));
+ if ($value !== false)
+ {
+ $element->setAttribute($attribute, $value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public function do_strip_htmltags($match)
+ {
+ if ($this->encode_instead_of_strip)
+ {
+ if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
+ {
+ $match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
+ $match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
+ return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
+ }
+ else
+ {
+ return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
+ }
+ }
+ elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
+ {
+ return $match[4];
+ }
+ else
+ {
+ return '';
+ }
+ }
+
+ protected function strip_tag($tag, $document, $type)
+ {
+ $xpath = new DOMXPath($document);
+ $elements = $xpath->query('body//' . $tag);
+ if ($this->encode_instead_of_strip)
+ {
+ foreach ($elements as $element)
+ {
+ $fragment = $document->createDocumentFragment();
+
+ // For elements which aren't script or style, include the tag itself
+ if (!in_array($tag, array('script', 'style')))
+ {
+ $text = '<' . $tag;
+ if ($element->hasAttributes())
+ {
+ $attrs = array();
+ foreach ($element->attributes as $name => $attr)
+ {
+ $value = $attr->value;
+
+ // In XHTML, empty values should never exist, so we repeat the value
+ if (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_XHTML))
+ {
+ $value = $name;
+ }
+ // For HTML, empty is fine
+ elseif (empty($value) && ($type & SIMPLEPIE_CONSTRUCT_HTML))
+ {
+ $attrs[] = $name;
+ continue;
+ }
+
+ // Standard attribute text
+ $attrs[] = $name . '="' . $attr->value . '"';
+ }
+ $text .= ' ' . implode(' ', $attrs);
+ }
+ $text .= '>';
+ $fragment->appendChild(new DOMText($text));
+ }
+
+ $number = $element->childNodes->length;
+ for ($i = $number; $i > 0; $i--)
+ {
+ $child = $element->childNodes->item(0);
+ $fragment->appendChild($child);
+ }
+
+ if (!in_array($tag, array('script', 'style')))
+ {
+ $fragment->appendChild(new DOMText('</' . $tag . '>'));
+ }
+
+ $element->parentNode->replaceChild($fragment, $element);
+ }
+
+ return;
+ }
+ elseif (in_array($tag, array('script', 'style')))
+ {
+ foreach ($elements as $element)
+ {
+ $element->parentNode->removeChild($element);
+ }
+
+ return;
+ }
+ else
+ {
+ foreach ($elements as $element)
+ {
+ $fragment = $document->createDocumentFragment();
+ $number = $element->childNodes->length;
+ for ($i = $number; $i > 0; $i--)
+ {
+ $child = $element->childNodes->item(0);
+ $fragment->appendChild($child);
+ }
+
+ $element->parentNode->replaceChild($fragment, $element);
+ }
+ }
+ }
+
+ protected function strip_attr($attrib, $document)
+ {
+ $xpath = new DOMXPath($document);
+ $elements = $xpath->query('//*[@' . $attrib . ']');
+
+ foreach ($elements as $element)
+ {
+ $element->removeAttribute($attrib);
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/Source.php b/src/wp-includes/SimplePie/Source.php
new file mode 100644
index 0000000000..51d8e6c256
--- /dev/null
+++ b/src/wp-includes/SimplePie/Source.php
@@ -0,0 +1,611 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * Handles `<atom:source>`
+ *
+ * Used by {@see SimplePie_Item::get_source()}
+ *
+ * This class can be overloaded with {@see SimplePie::set_source_class()}
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie_Source
+{
+ var $item;
+ var $data = array();
+ protected $registry;
+
+ public function __construct($item, $data)
+ {
+ $this->item = $item;
+ $this->data = $data;
+ }
+
+ public function set_registry(SimplePie_Registry $registry)
+ {
+ $this->registry = $registry;
+ }
+
+ public function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ public function get_source_tags($namespace, $tag)
+ {
+ if (isset($this->data['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][$namespace][$tag];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_base($element = array())
+ {
+ return $this->item->get_base($element);
+ }
+
+ public function sanitize($data, $type, $base = '')
+ {
+ return $this->item->sanitize($data, $type, $base);
+ }
+
+ public function get_item()
+ {
+ return $this->item;
+ }
+
+ public function get_title()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
+ {
+ // This is really the label, but keep this as the term also for BC.
+ // Label will also work on retrieving because that falls back to term.
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ if (isset($category['attribs']['']['domain']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = null;
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($categories))
+ {
+ return array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($authors))
+ {
+ return array_unique($authors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if (isset($links[$key]))
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Added for parity between the parent-level and the item/entry-level.
+ */
+ public function get_permalink()
+ {
+ return $this->get_link(0);
+ }
+
+ public function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_description()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_copyright()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_language()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['xml_lang']))
+ {
+ return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_latitude()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_longitude()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_image_url()
+ {
+ if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+ {
+ return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+}
+
diff --git a/src/wp-includes/SimplePie/XML/Declaration/Parser.php b/src/wp-includes/SimplePie/XML/Declaration/Parser.php
new file mode 100644
index 0000000000..aec19f10ad
--- /dev/null
+++ b/src/wp-includes/SimplePie/XML/Declaration/Parser.php
@@ -0,0 +1,362 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Parses the XML Declaration
+ *
+ * @package SimplePie
+ * @subpackage Parsing
+ */
+class SimplePie_XML_Declaration_Parser
+{
+ /**
+ * XML Version
+ *
+ * @access public
+ * @var string
+ */
+ var $version = '1.0';
+
+ /**
+ * Encoding
+ *
+ * @access public
+ * @var string
+ */
+ var $encoding = 'UTF-8';
+
+ /**
+ * Standalone
+ *
+ * @access public
+ * @var bool
+ */
+ var $standalone = false;
+
+ /**
+ * Current state of the state machine
+ *
+ * @access private
+ * @var string
+ */
+ var $state = 'before_version_name';
+
+ /**
+ * Input data
+ *
+ * @access private
+ * @var string
+ */
+ var $data = '';
+
+ /**
+ * Input data length (to avoid calling strlen() everytime this is needed)
+ *
+ * @access private
+ * @var int
+ */
+ var $data_length = 0;
+
+ /**
+ * Current position of the pointer
+ *
+ * @var int
+ * @access private
+ */
+ var $position = 0;
+
+ /**
+ * Create an instance of the class with the input data
+ *
+ * @access public
+ * @param string $data Input data
+ */
+ public function __construct($data)
+ {
+ $this->data = $data;
+ $this->data_length = strlen($this->data);
+ }
+
+ /**
+ * Parse the input data
+ *
+ * @access public
+ * @return bool true on success, false on failure
+ */
+ public function parse()
+ {
+ while ($this->state && $this->state !== 'emit' && $this->has_data())
+ {
+ $state = $this->state;
+ $this->$state();
+ }
+ $this->data = '';
+ if ($this->state === 'emit')
+ {
+ return true;
+ }
+ else
+ {
+ $this->version = '';
+ $this->encoding = '';
+ $this->standalone = '';
+ return false;
+ }
+ }
+
+ /**
+ * Check whether there is data beyond the pointer
+ *
+ * @access private
+ * @return bool true if there is further data, false if not
+ */
+ public function has_data()
+ {
+ return (bool) ($this->position < $this->data_length);
+ }
+
+ /**
+ * Advance past any whitespace
+ *
+ * @return int Number of whitespace characters passed
+ */
+ public function skip_whitespace()
+ {
+ $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
+ $this->position += $whitespace;
+ return $whitespace;
+ }
+
+ /**
+ * Read value
+ */
+ public function get_value()
+ {
+ $quote = substr($this->data, $this->position, 1);
+ if ($quote === '"' || $quote === "'")
+ {
+ $this->position++;
+ $len = strcspn($this->data, $quote, $this->position);
+ if ($this->has_data())
+ {
+ $value = substr($this->data, $this->position, $len);
+ $this->position += $len + 1;
+ return $value;
+ }
+ }
+ return false;
+ }
+
+ public function before_version_name()
+ {
+ if ($this->skip_whitespace())
+ {
+ $this->state = 'version_name';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function version_name()
+ {
+ if (substr($this->data, $this->position, 7) === 'version')
+ {
+ $this->position += 7;
+ $this->skip_whitespace();
+ $this->state = 'version_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function version_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'version_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function version_value()
+ {
+ if ($this->version = $this->get_value())
+ {
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = 'encoding_name';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function encoding_name()
+ {
+ if (substr($this->data, $this->position, 8) === 'encoding')
+ {
+ $this->position += 8;
+ $this->skip_whitespace();
+ $this->state = 'encoding_equals';
+ }
+ else
+ {
+ $this->state = 'standalone_name';
+ }
+ }
+
+ public function encoding_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'encoding_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function encoding_value()
+ {
+ if ($this->encoding = $this->get_value())
+ {
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = 'standalone_name';
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function standalone_name()
+ {
+ if (substr($this->data, $this->position, 10) === 'standalone')
+ {
+ $this->position += 10;
+ $this->skip_whitespace();
+ $this->state = 'standalone_equals';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function standalone_equals()
+ {
+ if (substr($this->data, $this->position, 1) === '=')
+ {
+ $this->position++;
+ $this->skip_whitespace();
+ $this->state = 'standalone_value';
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+
+ public function standalone_value()
+ {
+ if ($standalone = $this->get_value())
+ {
+ switch ($standalone)
+ {
+ case 'yes':
+ $this->standalone = true;
+ break;
+
+ case 'no':
+ $this->standalone = false;
+ break;
+
+ default:
+ $this->state = false;
+ return;
+ }
+
+ $this->skip_whitespace();
+ if ($this->has_data())
+ {
+ $this->state = false;
+ }
+ else
+ {
+ $this->state = 'emit';
+ }
+ }
+ else
+ {
+ $this->state = false;
+ }
+ }
+}
diff --git a/src/wp-includes/SimplePie/gzdecode.php b/src/wp-includes/SimplePie/gzdecode.php
new file mode 100644
index 0000000000..52e024ea98
--- /dev/null
+++ b/src/wp-includes/SimplePie/gzdecode.php
@@ -0,0 +1,371 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+
+/**
+ * Decode 'gzip' encoded HTTP data
+ *
+ * @package SimplePie
+ * @subpackage HTTP
+ * @link http://www.gzip.org/format.txt
+ */
+class SimplePie_gzdecode
+{
+ /**
+ * Compressed data
+ *
+ * @access private
+ * @var string
+ * @see gzdecode::$data
+ */
+ var $compressed_data;
+
+ /**
+ * Size of compressed data
+ *
+ * @access private
+ * @var int
+ */
+ var $compressed_size;
+
+ /**
+ * Minimum size of a valid gzip string
+ *
+ * @access private
+ * @var int
+ */
+ var $min_compressed_size = 18;
+
+ /**
+ * Current position of pointer
+ *
+ * @access private
+ * @var int
+ */
+ var $position = 0;
+
+ /**
+ * Flags (FLG)
+ *
+ * @access private
+ * @var int
+ */
+ var $flags;
+
+ /**
+ * Uncompressed data
+ *
+ * @access public
+ * @see gzdecode::$compressed_data
+ * @var string
+ */
+ var $data;
+
+ /**
+ * Modified time
+ *
+ * @access public
+ * @var int
+ */
+ var $MTIME;
+
+ /**
+ * Extra Flags
+ *
+ * @access public
+ * @var int
+ */
+ var $XFL;
+
+ /**
+ * Operating System
+ *
+ * @access public
+ * @var int
+ */
+ var $OS;
+
+ /**
+ * Subfield ID 1
+ *
+ * @access public
+ * @see gzdecode::$extra_field
+ * @see gzdecode::$SI2
+ * @var string
+ */
+ var $SI1;
+
+ /**
+ * Subfield ID 2
+ *
+ * @access public
+ * @see gzdecode::$extra_field
+ * @see gzdecode::$SI1
+ * @var string
+ */
+ var $SI2;
+
+ /**
+ * Extra field content
+ *
+ * @access public
+ * @see gzdecode::$SI1
+ * @see gzdecode::$SI2
+ * @var string
+ */
+ var $extra_field;
+
+ /**
+ * Original filename
+ *
+ * @access public
+ * @var string
+ */
+ var $filename;
+
+ /**
+ * Human readable comment
+ *
+ * @access public
+ * @var string
+ */
+ var $comment;
+
+ /**
+ * Don't allow anything to be set
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ public function __set($name, $value)
+ {
+ trigger_error("Cannot write property $name", E_USER_ERROR);
+ }
+
+ /**
+ * Set the compressed string and related properties
+ *
+ * @param string $data
+ */
+ public function __construct($data)
+ {
+ $this->compressed_data = $data;
+ $this->compressed_size = strlen($data);
+ }
+
+ /**
+ * Decode the GZIP stream
+ *
+ * @return bool Successfulness
+ */
+ public function parse()
+ {
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Check ID1, ID2, and CM
+ if (substr($this->compressed_data, 0, 3) !== "\x1F\x8B\x08")
+ {
+ return false;
+ }
+
+ // Get the FLG (FLaGs)
+ $this->flags = ord($this->compressed_data[3]);
+
+ // FLG bits above (1 << 4) are reserved
+ if ($this->flags > 0x1F)
+ {
+ return false;
+ }
+
+ // Advance the pointer after the above
+ $this->position += 4;
+
+ // MTIME
+ $mtime = substr($this->compressed_data, $this->position, 4);
+ // Reverse the string if we're on a big-endian arch because l is the only signed long and is machine endianness
+ if (current(unpack('S', "\x00\x01")) === 1)
+ {
+ $mtime = strrev($mtime);
+ }
+ $this->MTIME = current(unpack('l', $mtime));
+ $this->position += 4;
+
+ // Get the XFL (eXtra FLags)
+ $this->XFL = ord($this->compressed_data[$this->position++]);
+
+ // Get the OS (Operating System)
+ $this->OS = ord($this->compressed_data[$this->position++]);
+
+ // Parse the FEXTRA
+ if ($this->flags & 4)
+ {
+ // Read subfield IDs
+ $this->SI1 = $this->compressed_data[$this->position++];
+ $this->SI2 = $this->compressed_data[$this->position++];
+
+ // SI2 set to zero is reserved for future use
+ if ($this->SI2 === "\x00")
+ {
+ return false;
+ }
+
+ // Get the length of the extra field
+ $len = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
+ $this->position += 2;
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 4;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the extra field to the given data
+ $this->extra_field = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FNAME
+ if ($this->flags & 8)
+ {
+ // Get the length of the filename
+ $len = strcspn($this->compressed_data, "\x00", $this->position);
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 1;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the original filename to the given string
+ $this->filename = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len + 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FCOMMENT
+ if ($this->flags & 16)
+ {
+ // Get the length of the comment
+ $len = strcspn($this->compressed_data, "\x00", $this->position);
+
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 1;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Set the original comment to the given string
+ $this->comment = substr($this->compressed_data, $this->position, $len);
+ $this->position += $len + 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Parse the FHCRC
+ if ($this->flags & 2)
+ {
+ // Check the length of the string is still valid
+ $this->min_compressed_size += $len + 2;
+ if ($this->compressed_size >= $this->min_compressed_size)
+ {
+ // Read the CRC
+ $crc = current(unpack('v', substr($this->compressed_data, $this->position, 2)));
+
+ // Check the CRC matches
+ if ((crc32(substr($this->compressed_data, 0, $this->position)) & 0xFFFF) === $crc)
+ {
+ $this->position += 2;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Decompress the actual data
+ if (($this->data = gzinflate(substr($this->compressed_data, $this->position, -8))) === false)
+ {
+ return false;
+ }
+ else
+ {
+ $this->position = $this->compressed_size - 8;
+ }
+
+ // Check CRC of data
+ $crc = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
+ $this->position += 4;
+ /*if (extension_loaded('hash') && sprintf('%u', current(unpack('V', hash('crc32b', $this->data)))) !== sprintf('%u', $crc))
+ {
+ return false;
+ }*/
+
+ // Check ISIZE of data
+ $isize = current(unpack('V', substr($this->compressed_data, $this->position, 4)));
+ $this->position += 4;
+ if (sprintf('%u', strlen($this->data) & 0xFFFFFFFF) !== sprintf('%u', $isize))
+ {
+ return false;
+ }
+
+ // Wow, against all odds, we've actually got a valid gzip string
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
diff --git a/src/wp-includes/Text/Diff.php b/src/wp-includes/Text/Diff.php
new file mode 100644
index 0000000000..dc24b67f71
--- /dev/null
+++ b/src/wp-includes/Text/Diff.php
@@ -0,0 +1,450 @@
+<?php
+/**
+ * General API for generating and formatting diffs - the differences between
+ * two sequences of strings.
+ *
+ * The original PHP version of this code was written by Geoffrey T. Dairiki
+ * <dairiki@dairiki.org>, and is used/adapted with his permission.
+ *
+ * Copyright 2004 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ */
+class Text_Diff {
+
+ /**
+ * Array of changes.
+ *
+ * @var array
+ */
+ var $_edits;
+
+ /**
+ * Computes diffs between sequences of strings.
+ *
+ * @param string $engine Name of the diffing engine to use. 'auto'
+ * will automatically select the best.
+ * @param array $params Parameters to pass to the diffing engine.
+ * Normally an array of two arrays, each
+ * containing the lines from a file.
+ */
+ function Text_Diff($engine, $params)
+ {
+ // Backward compatibility workaround.
+ if (!is_string($engine)) {
+ $params = array($engine, $params);
+ $engine = 'auto';
+ }
+
+ if ($engine == 'auto') {
+ $engine = extension_loaded('xdiff') ? 'xdiff' : 'native';
+ } else {
+ $engine = basename($engine);
+ }
+
+ // WP #7391
+ require_once dirname(__FILE__).'/Diff/Engine/' . $engine . '.php';
+ $class = 'Text_Diff_Engine_' . $engine;
+ $diff_engine = new $class();
+
+ $this->_edits = call_user_func_array(array($diff_engine, 'diff'), $params);
+ }
+
+ /**
+ * Returns the array of differences.
+ */
+ function getDiff()
+ {
+ return $this->_edits;
+ }
+
+ /**
+ * returns the number of new (added) lines in a given diff.
+ *
+ * @since Text_Diff 1.1.0
+ *
+ * @return integer The number of new lines
+ */
+ function countAddedLines()
+ {
+ $count = 0;
+ foreach ($this->_edits as $edit) {
+ if (is_a($edit, 'Text_Diff_Op_add') ||
+ is_a($edit, 'Text_Diff_Op_change')) {
+ $count += $edit->nfinal();
+ }
+ }
+ return $count;
+ }
+
+ /**
+ * Returns the number of deleted (removed) lines in a given diff.
+ *
+ * @since Text_Diff 1.1.0
+ *
+ * @return integer The number of deleted lines
+ */
+ function countDeletedLines()
+ {
+ $count = 0;
+ foreach ($this->_edits as $edit) {
+ if (is_a($edit, 'Text_Diff_Op_delete') ||
+ is_a($edit, 'Text_Diff_Op_change')) {
+ $count += $edit->norig();
+ }
+ }
+ return $count;
+ }
+
+ /**
+ * Computes a reversed diff.
+ *
+ * Example:
+ * <code>
+ * $diff = new Text_Diff($lines1, $lines2);
+ * $rev = $diff->reverse();
+ * </code>
+ *
+ * @return Text_Diff A Diff object representing the inverse of the
+ * original diff. Note that we purposely don't return a
+ * reference here, since this essentially is a clone()
+ * method.
+ */
+ function reverse()
+ {
+ if (version_compare(zend_version(), '2', '>')) {
+ $rev = clone($this);
+ } else {
+ $rev = $this;
+ }
+ $rev->_edits = array();
+ foreach ($this->_edits as $edit) {
+ $rev->_edits[] = $edit->reverse();
+ }
+ return $rev;
+ }
+
+ /**
+ * Checks for an empty diff.
+ *
+ * @return boolean True if two sequences were identical.
+ */
+ function isEmpty()
+ {
+ foreach ($this->_edits as $edit) {
+ if (!is_a($edit, 'Text_Diff_Op_copy')) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Computes the length of the Longest Common Subsequence (LCS).
+ *
+ * This is mostly for diagnostic purposes.
+ *
+ * @return integer The length of the LCS.
+ */
+ function lcs()
+ {
+ $lcs = 0;
+ foreach ($this->_edits as $edit) {
+ if (is_a($edit, 'Text_Diff_Op_copy')) {
+ $lcs += count($edit->orig);
+ }
+ }
+ return $lcs;
+ }
+
+ /**
+ * Gets the original set of lines.
+ *
+ * This reconstructs the $from_lines parameter passed to the constructor.
+ *
+ * @return array The original sequence of strings.
+ */
+ function getOriginal()
+ {
+ $lines = array();
+ foreach ($this->_edits as $edit) {
+ if ($edit->orig) {
+ array_splice($lines, count($lines), 0, $edit->orig);
+ }
+ }
+ return $lines;
+ }
+
+ /**
+ * Gets the final set of lines.
+ *
+ * This reconstructs the $to_lines parameter passed to the constructor.
+ *
+ * @return array The sequence of strings.
+ */
+ function getFinal()
+ {
+ $lines = array();
+ foreach ($this->_edits as $edit) {
+ if ($edit->final) {
+ array_splice($lines, count($lines), 0, $edit->final);
+ }
+ }
+ return $lines;
+ }
+
+ /**
+ * Removes trailing newlines from a line of text. This is meant to be used
+ * with array_walk().
+ *
+ * @param string $line The line to trim.
+ * @param integer $key The index of the line in the array. Not used.
+ */
+ static function trimNewlines(&$line, $key)
+ {
+ $line = str_replace(array("\n", "\r"), '', $line);
+ }
+
+ /**
+ * Determines the location of the system temporary directory.
+ *
+ * @static
+ *
+ * @access protected
+ *
+ * @return string A directory name which can be used for temp files.
+ * Returns false if one could not be found.
+ */
+ function _getTempDir()
+ {
+ $tmp_locations = array('/tmp', '/var/tmp', 'c:\WUTemp', 'c:\temp',
+ 'c:\windows\temp', 'c:\winnt\temp');
+
+ /* Try PHP's upload_tmp_dir directive. */
+ $tmp = ini_get('upload_tmp_dir');
+
+ /* Otherwise, try to determine the TMPDIR environment variable. */
+ if (!strlen($tmp)) {
+ $tmp = getenv('TMPDIR');
+ }
+
+ /* If we still cannot determine a value, then cycle through a list of
+ * preset possibilities. */
+ while (!strlen($tmp) && count($tmp_locations)) {
+ $tmp_check = array_shift($tmp_locations);
+ if (@is_dir($tmp_check)) {
+ $tmp = $tmp_check;
+ }
+ }
+
+ /* If it is still empty, we have failed, so return false; otherwise
+ * return the directory determined. */
+ return strlen($tmp) ? $tmp : false;
+ }
+
+ /**
+ * Checks a diff for validity.
+ *
+ * This is here only for debugging purposes.
+ */
+ function _check($from_lines, $to_lines)
+ {
+ if (serialize($from_lines) != serialize($this->getOriginal())) {
+ trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
+ }
+ if (serialize($to_lines) != serialize($this->getFinal())) {
+ trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
+ }
+
+ $rev = $this->reverse();
+ if (serialize($to_lines) != serialize($rev->getOriginal())) {
+ trigger_error("Reversed original doesn't match", E_USER_ERROR);
+ }
+ if (serialize($from_lines) != serialize($rev->getFinal())) {
+ trigger_error("Reversed final doesn't match", E_USER_ERROR);
+ }
+
+ $prevtype = null;
+ foreach ($this->_edits as $edit) {
+ if ($prevtype == get_class($edit)) {
+ trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
+ }
+ $prevtype = get_class($edit);
+ }
+
+ return true;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ */
+class Text_MappedDiff extends Text_Diff {
+
+ /**
+ * Computes a diff between sequences of strings.
+ *
+ * This can be used to compute things like case-insensitve diffs, or diffs
+ * which ignore changes in white-space.
+ *
+ * @param array $from_lines An array of strings.
+ * @param array $to_lines An array of strings.
+ * @param array $mapped_from_lines This array should have the same size
+ * number of elements as $from_lines. The
+ * elements in $mapped_from_lines and
+ * $mapped_to_lines are what is actually
+ * compared when computing the diff.
+ * @param array $mapped_to_lines This array should have the same number
+ * of elements as $to_lines.
+ */
+ function Text_MappedDiff($from_lines, $to_lines,
+ $mapped_from_lines, $mapped_to_lines)
+ {
+ assert(count($from_lines) == count($mapped_from_lines));
+ assert(count($to_lines) == count($mapped_to_lines));
+
+ parent::Text_Diff($mapped_from_lines, $mapped_to_lines);
+
+ $xi = $yi = 0;
+ for ($i = 0; $i < count($this->_edits); $i++) {
+ $orig = &$this->_edits[$i]->orig;
+ if (is_array($orig)) {
+ $orig = array_slice($from_lines, $xi, count($orig));
+ $xi += count($orig);
+ }
+
+ $final = &$this->_edits[$i]->final;
+ if (is_array($final)) {
+ $final = array_slice($to_lines, $yi, count($final));
+ $yi += count($final);
+ }
+ }
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ *
+ * @access private
+ */
+class Text_Diff_Op {
+
+ var $orig;
+ var $final;
+
+ function &reverse()
+ {
+ trigger_error('Abstract method', E_USER_ERROR);
+ }
+
+ function norig()
+ {
+ return $this->orig ? count($this->orig) : 0;
+ }
+
+ function nfinal()
+ {
+ return $this->final ? count($this->final) : 0;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ *
+ * @access private
+ */
+class Text_Diff_Op_copy extends Text_Diff_Op {
+
+ function Text_Diff_Op_copy($orig, $final = false)
+ {
+ if (!is_array($final)) {
+ $final = $orig;
+ }
+ $this->orig = $orig;
+ $this->final = $final;
+ }
+
+ function &reverse()
+ {
+ $reverse = new Text_Diff_Op_copy($this->final, $this->orig);
+ return $reverse;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ *
+ * @access private
+ */
+class Text_Diff_Op_delete extends Text_Diff_Op {
+
+ function Text_Diff_Op_delete($lines)
+ {
+ $this->orig = $lines;
+ $this->final = false;
+ }
+
+ function &reverse()
+ {
+ $reverse = new Text_Diff_Op_add($this->orig);
+ return $reverse;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ *
+ * @access private
+ */
+class Text_Diff_Op_add extends Text_Diff_Op {
+
+ function Text_Diff_Op_add($lines)
+ {
+ $this->final = $lines;
+ $this->orig = false;
+ }
+
+ function &reverse()
+ {
+ $reverse = new Text_Diff_Op_delete($this->final);
+ return $reverse;
+ }
+
+}
+
+/**
+ * @package Text_Diff
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ *
+ * @access private
+ */
+class Text_Diff_Op_change extends Text_Diff_Op {
+
+ function Text_Diff_Op_change($orig, $final)
+ {
+ $this->orig = $orig;
+ $this->final = $final;
+ }
+
+ function &reverse()
+ {
+ $reverse = new Text_Diff_Op_change($this->final, $this->orig);
+ return $reverse;
+ }
+
+}
diff --git a/src/wp-includes/Text/Diff/Engine/native.php b/src/wp-includes/Text/Diff/Engine/native.php
new file mode 100644
index 0000000000..e908cfecca
--- /dev/null
+++ b/src/wp-includes/Text/Diff/Engine/native.php
@@ -0,0 +1,436 @@
+<?php
+/**
+ * Class used internally by Text_Diff to actually compute the diffs.
+ *
+ * This class is implemented using native PHP code.
+ *
+ * The algorithm used here is mostly lifted from the perl module
+ * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
+ * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
+ *
+ * More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html
+ *
+ * Some ideas (and a bit of code) are taken from analyze.c, of GNU
+ * diffutils-2.7, which can be found at:
+ * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
+ *
+ * Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
+ * Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this
+ * code was written by him, and is used/adapted with his permission.
+ *
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * @package Text_Diff
+ */
+class Text_Diff_Engine_native {
+
+ function diff($from_lines, $to_lines)
+ {
+ array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+ array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+ $n_from = count($from_lines);
+ $n_to = count($to_lines);
+
+ $this->xchanged = $this->ychanged = array();
+ $this->xv = $this->yv = array();
+ $this->xind = $this->yind = array();
+ unset($this->seq);
+ unset($this->in_seq);
+ unset($this->lcs);
+
+ // Skip leading common lines.
+ for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
+ if ($from_lines[$skip] !== $to_lines[$skip]) {
+ break;
+ }
+ $this->xchanged[$skip] = $this->ychanged[$skip] = false;
+ }
+
+ // Skip trailing common lines.
+ $xi = $n_from; $yi = $n_to;
+ for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
+ if ($from_lines[$xi] !== $to_lines[$yi]) {
+ break;
+ }
+ $this->xchanged[$xi] = $this->ychanged[$yi] = false;
+ }
+
+ // Ignore lines which do not exist in both files.
+ for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+ $xhash[$from_lines[$xi]] = 1;
+ }
+ for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
+ $line = $to_lines[$yi];
+ if (($this->ychanged[$yi] = empty($xhash[$line]))) {
+ continue;
+ }
+ $yhash[$line] = 1;
+ $this->yv[] = $line;
+ $this->yind[] = $yi;
+ }
+ for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
+ $line = $from_lines[$xi];
+ if (($this->xchanged[$xi] = empty($yhash[$line]))) {
+ continue;
+ }
+ $this->xv[] = $line;
+ $this->xind[] = $xi;
+ }
+
+ // Find the LCS.
+ $this->_compareseq(0, count($this->xv), 0, count($this->yv));
+
+ // Merge edits when possible.
+ $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
+ $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
+
+ // Compute the edit operations.
+ $edits = array();
+ $xi = $yi = 0;
+ while ($xi < $n_from || $yi < $n_to) {
+ assert($yi < $n_to || $this->xchanged[$xi]);
+ assert($xi < $n_from || $this->ychanged[$yi]);
+
+ // Skip matching "snake".
+ $copy = array();
+ while ($xi < $n_from && $yi < $n_to
+ && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
+ $copy[] = $from_lines[$xi++];
+ ++$yi;
+ }
+ if ($copy) {
+ $edits[] = new Text_Diff_Op_copy($copy);
+ }
+
+ // Find deletes & adds.
+ $delete = array();
+ while ($xi < $n_from && $this->xchanged[$xi]) {
+ $delete[] = $from_lines[$xi++];
+ }
+
+ $add = array();
+ while ($yi < $n_to && $this->ychanged[$yi]) {
+ $add[] = $to_lines[$yi++];
+ }
+
+ if ($delete && $add) {
+ $edits[] = new Text_Diff_Op_change($delete, $add);
+ } elseif ($delete) {
+ $edits[] = new Text_Diff_Op_delete($delete);
+ } elseif ($add) {
+ $edits[] = new Text_Diff_Op_add($add);
+ }
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
+ * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
+ * segments.
+ *
+ * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of
+ * NCHUNKS+1 (X, Y) indexes giving the diving points between sub
+ * sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1),
+ * the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) ==
+ * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
+ *
+ * This function assumes that the first lines of the specified portions of
+ * the two files do not match, and likewise that the last lines do not
+ * match. The caller must trim matching lines from the beginning and end
+ * of the portions it is going to specify.
+ */
+ function _diag ($xoff, $xlim, $yoff, $ylim, $nchunks)
+ {
+ $flip = false;
+
+ if ($xlim - $xoff > $ylim - $yoff) {
+ /* Things seems faster (I'm not sure I understand why) when the
+ * shortest sequence is in X. */
+ $flip = true;
+ list ($xoff, $xlim, $yoff, $ylim)
+ = array($yoff, $ylim, $xoff, $xlim);
+ }
+
+ if ($flip) {
+ for ($i = $ylim - 1; $i >= $yoff; $i--) {
+ $ymatches[$this->xv[$i]][] = $i;
+ }
+ } else {
+ for ($i = $ylim - 1; $i >= $yoff; $i--) {
+ $ymatches[$this->yv[$i]][] = $i;
+ }
+ }
+
+ $this->lcs = 0;
+ $this->seq[0]= $yoff - 1;
+ $this->in_seq = array();
+ $ymids[0] = array();
+
+ $numer = $xlim - $xoff + $nchunks - 1;
+ $x = $xoff;
+ for ($chunk = 0; $chunk < $nchunks; $chunk++) {
+ if ($chunk > 0) {
+ for ($i = 0; $i <= $this->lcs; $i++) {
+ $ymids[$i][$chunk - 1] = $this->seq[$i];
+ }
+ }
+
+ $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
+ for (; $x < $x1; $x++) {
+ $line = $flip ? $this->yv[$x] : $this->xv[$x];
+ if (empty($ymatches[$line])) {
+ continue;
+ }
+ $matches = $ymatches[$line];
+ reset($matches);
+ while (list(, $y) = each($matches)) {
+ if (empty($this->in_seq[$y])) {
+ $k = $this->_lcsPos($y);
+ assert($k > 0);
+ $ymids[$k] = $ymids[$k - 1];
+ break;
+ }
+ }
+ while (list(, $y) = each($matches)) {
+ if ($y > $this->seq[$k - 1]) {
+ assert($y <= $this->seq[$k]);
+ /* Optimization: this is a common case: next match is
+ * just replacing previous match. */
+ $this->in_seq[$this->seq[$k]] = false;
+ $this->seq[$k] = $y;
+ $this->in_seq[$y] = 1;
+ } elseif (empty($this->in_seq[$y])) {
+ $k = $this->_lcsPos($y);
+ assert($k > 0);
+ $ymids[$k] = $ymids[$k - 1];
+ }
+ }
+ }
+ }
+
+ $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
+ $ymid = $ymids[$this->lcs];
+ for ($n = 0; $n < $nchunks - 1; $n++) {
+ $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
+ $y1 = $ymid[$n] + 1;
+ $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
+ }
+ $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
+
+ return array($this->lcs, $seps);
+ }
+
+ function _lcsPos($ypos)
+ {
+ $end = $this->lcs;
+ if ($end == 0 || $ypos > $this->seq[$end]) {
+ $this->seq[++$this->lcs] = $ypos;
+ $this->in_seq[$ypos] = 1;
+ return $this->lcs;
+ }
+
+ $beg = 1;
+ while ($beg < $end) {
+ $mid = (int)(($beg + $end) / 2);
+ if ($ypos > $this->seq[$mid]) {
+ $beg = $mid + 1;
+ } else {
+ $end = $mid;
+ }
+ }
+
+ assert($ypos != $this->seq[$end]);
+
+ $this->in_seq[$this->seq[$end]] = false;
+ $this->seq[$end] = $ypos;
+ $this->in_seq[$ypos] = 1;
+ return $end;
+ }
+
+ /**
+ * Finds LCS of two sequences.
+ *
+ * The results are recorded in the vectors $this->{x,y}changed[], by
+ * storing a 1 in the element for each line that is an insertion or
+ * deletion (ie. is not in the LCS).
+ *
+ * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
+ *
+ * Note that XLIM, YLIM are exclusive bounds. All line numbers are
+ * origin-0 and discarded lines are not counted.
+ */
+ function _compareseq ($xoff, $xlim, $yoff, $ylim)
+ {
+ /* Slide down the bottom initial diagonal. */
+ while ($xoff < $xlim && $yoff < $ylim
+ && $this->xv[$xoff] == $this->yv[$yoff]) {
+ ++$xoff;
+ ++$yoff;
+ }
+
+ /* Slide up the top initial diagonal. */
+ while ($xlim > $xoff && $ylim > $yoff
+ && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
+ --$xlim;
+ --$ylim;
+ }
+
+ if ($xoff == $xlim || $yoff == $ylim) {
+ $lcs = 0;
+ } else {
+ /* This is ad hoc but seems to work well. $nchunks =
+ * sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
+ * max(2,min(8,(int)$nchunks)); */
+ $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
+ list($lcs, $seps)
+ = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
+ }
+
+ if ($lcs == 0) {
+ /* X and Y sequences have no common subsequence: mark all
+ * changed. */
+ while ($yoff < $ylim) {
+ $this->ychanged[$this->yind[$yoff++]] = 1;
+ }
+ while ($xoff < $xlim) {
+ $this->xchanged[$this->xind[$xoff++]] = 1;
+ }
+ } else {
+ /* Use the partitions to split this problem into subproblems. */
+ reset($seps);
+ $pt1 = $seps[0];
+ while ($pt2 = next($seps)) {
+ $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
+ $pt1 = $pt2;
+ }
+ }
+ }
+
+ /**
+ * Adjusts inserts/deletes of identical lines to join changes as much as
+ * possible.
+ *
+ * We do something when a run of changed lines include a line at one end
+ * and has an excluded, identical line at the other. We are free to
+ * choose which identical line is included. `compareseq' usually chooses
+ * the one at the beginning, but usually it is cleaner to consider the
+ * following identical line to be the "change".
+ *
+ * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
+ */
+ function _shiftBoundaries($lines, &$changed, $other_changed)
+ {
+ $i = 0;
+ $j = 0;
+
+ assert('count($lines) == count($changed)');
+ $len = count($lines);
+ $other_len = count($other_changed);
+
+ while (1) {
+ /* Scan forward to find the beginning of another run of
+ * changes. Also keep track of the corresponding point in the
+ * other file.
+ *
+ * Throughout this code, $i and $j are adjusted together so that
+ * the first $i elements of $changed and the first $j elements of
+ * $other_changed both contain the same number of zeros (unchanged
+ * lines).
+ *
+ * Furthermore, $j is always kept so that $j == $other_len or
+ * $other_changed[$j] == false. */
+ while ($j < $other_len && $other_changed[$j]) {
+ $j++;
+ }
+
+ while ($i < $len && ! $changed[$i]) {
+ assert('$j < $other_len && ! $other_changed[$j]');
+ $i++; $j++;
+ while ($j < $other_len && $other_changed[$j]) {
+ $j++;
+ }
+ }
+
+ if ($i == $len) {
+ break;
+ }
+
+ $start = $i;
+
+ /* Find the end of this run of changes. */
+ while (++$i < $len && $changed[$i]) {
+ continue;
+ }
+
+ do {
+ /* Record the length of this run of changes, so that we can
+ * later determine whether the run has grown. */
+ $runlength = $i - $start;
+
+ /* Move the changed region back, so long as the previous
+ * unchanged line matches the last changed one. This merges
+ * with previous changed regions. */
+ while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
+ $changed[--$start] = 1;
+ $changed[--$i] = false;
+ while ($start > 0 && $changed[$start - 1]) {
+ $start--;
+ }
+ assert('$j > 0');
+ while ($other_changed[--$j]) {
+ continue;
+ }
+ assert('$j >= 0 && !$other_changed[$j]');
+ }
+
+ /* Set CORRESPONDING to the end of the changed run, at the
+ * last point where it corresponds to a changed run in the
+ * other file. CORRESPONDING == LEN means no such point has
+ * been found. */
+ $corresponding = $j < $other_len ? $i : $len;
+
+ /* Move the changed region forward, so long as the first
+ * changed line matches the following unchanged one. This
+ * merges with following changed regions. Do this second, so
+ * that if there are no merges, the changed region is moved
+ * forward as far as possible. */
+ while ($i < $len && $lines[$start] == $lines[$i]) {
+ $changed[$start++] = false;
+ $changed[$i++] = 1;
+ while ($i < $len && $changed[$i]) {
+ $i++;
+ }
+
+ assert('$j < $other_len && ! $other_changed[$j]');
+ $j++;
+ if ($j < $other_len && $other_changed[$j]) {
+ $corresponding = $i;
+ while ($j < $other_len && $other_changed[$j]) {
+ $j++;
+ }
+ }
+ }
+ } while ($runlength != $i - $start);
+
+ /* If possible, move the fully-merged run of changes back to a
+ * corresponding run in the other file. */
+ while ($corresponding < $i) {
+ $changed[--$start] = 1;
+ $changed[--$i] = 0;
+ assert('$j > 0');
+ while ($other_changed[--$j]) {
+ continue;
+ }
+ assert('$j >= 0 && !$other_changed[$j]');
+ }
+ }
+ }
+
+}
diff --git a/src/wp-includes/Text/Diff/Engine/shell.php b/src/wp-includes/Text/Diff/Engine/shell.php
new file mode 100644
index 0000000000..faf387032d
--- /dev/null
+++ b/src/wp-includes/Text/Diff/Engine/shell.php
@@ -0,0 +1,162 @@
+<?php
+/**
+ * Class used internally by Diff to actually compute the diffs.
+ *
+ * This class uses the Unix `diff` program via shell_exec to compute the
+ * differences between the two input arrays.
+ *
+ * Copyright 2007-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Milian Wolff <mail@milianw.de>
+ * @package Text_Diff
+ * @since 0.3.0
+ */
+class Text_Diff_Engine_shell {
+
+ /**
+ * Path to the diff executable
+ *
+ * @var string
+ */
+ var $_diffCommand = 'diff';
+
+ /**
+ * Returns the array of differences.
+ *
+ * @param array $from_lines lines of text from old file
+ * @param array $to_lines lines of text from new file
+ *
+ * @return array all changes made (array with Text_Diff_Op_* objects)
+ */
+ function diff($from_lines, $to_lines)
+ {
+ array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+ array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+ $temp_dir = Text_Diff::_getTempDir();
+
+ // Execute gnu diff or similar to get a standard diff file.
+ $from_file = tempnam($temp_dir, 'Text_Diff');
+ $to_file = tempnam($temp_dir, 'Text_Diff');
+ $fp = fopen($from_file, 'w');
+ fwrite($fp, implode("\n", $from_lines));
+ fclose($fp);
+ $fp = fopen($to_file, 'w');
+ fwrite($fp, implode("\n", $to_lines));
+ fclose($fp);
+ $diff = shell_exec($this->_diffCommand . ' ' . $from_file . ' ' . $to_file);
+ unlink($from_file);
+ unlink($to_file);
+
+ if (is_null($diff)) {
+ // No changes were made
+ return array(new Text_Diff_Op_copy($from_lines));
+ }
+
+ $from_line_no = 1;
+ $to_line_no = 1;
+ $edits = array();
+
+ // Get changed lines by parsing something like:
+ // 0a1,2
+ // 1,2c4,6
+ // 1,5d6
+ preg_match_all('#^(\d+)(?:,(\d+))?([adc])(\d+)(?:,(\d+))?$#m', $diff,
+ $matches, PREG_SET_ORDER);
+
+ foreach ($matches as $match) {
+ if (!isset($match[5])) {
+ // This paren is not set every time (see regex).
+ $match[5] = false;
+ }
+
+ if ($match[3] == 'a') {
+ $from_line_no--;
+ }
+
+ if ($match[3] == 'd') {
+ $to_line_no--;
+ }
+
+ if ($from_line_no < $match[1] || $to_line_no < $match[4]) {
+ // copied lines
+ assert('$match[1] - $from_line_no == $match[4] - $to_line_no');
+ array_push($edits,
+ new Text_Diff_Op_copy(
+ $this->_getLines($from_lines, $from_line_no, $match[1] - 1),
+ $this->_getLines($to_lines, $to_line_no, $match[4] - 1)));
+ }
+
+ switch ($match[3]) {
+ case 'd':
+ // deleted lines
+ array_push($edits,
+ new Text_Diff_Op_delete(
+ $this->_getLines($from_lines, $from_line_no, $match[2])));
+ $to_line_no++;
+ break;
+
+ case 'c':
+ // changed lines
+ array_push($edits,
+ new Text_Diff_Op_change(
+ $this->_getLines($from_lines, $from_line_no, $match[2]),
+ $this->_getLines($to_lines, $to_line_no, $match[5])));
+ break;
+
+ case 'a':
+ // added lines
+ array_push($edits,
+ new Text_Diff_Op_add(
+ $this->_getLines($to_lines, $to_line_no, $match[5])));
+ $from_line_no++;
+ break;
+ }
+ }
+
+ if (!empty($from_lines)) {
+ // Some lines might still be pending. Add them as copied
+ array_push($edits,
+ new Text_Diff_Op_copy(
+ $this->_getLines($from_lines, $from_line_no,
+ $from_line_no + count($from_lines) - 1),
+ $this->_getLines($to_lines, $to_line_no,
+ $to_line_no + count($to_lines) - 1)));
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Get lines from either the old or new text
+ *
+ * @access private
+ *
+ * @param array &$text_lines Either $from_lines or $to_lines
+ * @param int &$line_no Current line number
+ * @param int $end Optional end line, when we want to chop more
+ * than one line.
+ *
+ * @return array The chopped lines
+ */
+ function _getLines(&$text_lines, &$line_no, $end = false)
+ {
+ if (!empty($end)) {
+ $lines = array();
+ // We can shift even more
+ while ($line_no <= $end) {
+ array_push($lines, array_shift($text_lines));
+ $line_no++;
+ }
+ } else {
+ $lines = array(array_shift($text_lines));
+ $line_no++;
+ }
+
+ return $lines;
+ }
+
+}
diff --git a/src/wp-includes/Text/Diff/Engine/string.php b/src/wp-includes/Text/Diff/Engine/string.php
new file mode 100644
index 0000000000..0f3b3745a5
--- /dev/null
+++ b/src/wp-includes/Text/Diff/Engine/string.php
@@ -0,0 +1,248 @@
+<?php
+/**
+ * Parses unified or context diffs output from eg. the diff utility.
+ *
+ * Example:
+ * <code>
+ * $patch = file_get_contents('example.patch');
+ * $diff = new Text_Diff('string', array($patch));
+ * $renderer = new Text_Diff_Renderer_inline();
+ * echo $renderer->render($diff);
+ * </code>
+ *
+ * Copyright 2005 Örjan Persson <o@42mm.org>
+ * Copyright 2005-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Örjan Persson <o@42mm.org>
+ * @package Text_Diff
+ * @since 0.2.0
+ */
+class Text_Diff_Engine_string {
+
+ /**
+ * Parses a unified or context diff.
+ *
+ * First param contains the whole diff and the second can be used to force
+ * a specific diff type. If the second parameter is 'autodetect', the
+ * diff will be examined to find out which type of diff this is.
+ *
+ * @param string $diff The diff content.
+ * @param string $mode The diff mode of the content in $diff. One of
+ * 'context', 'unified', or 'autodetect'.
+ *
+ * @return array List of all diff operations.
+ */
+ function diff($diff, $mode = 'autodetect')
+ {
+ // Detect line breaks.
+ $lnbr = "\n";
+ if (strpos($diff, "\r\n") !== false) {
+ $lnbr = "\r\n";
+ } elseif (strpos($diff, "\r") !== false) {
+ $lnbr = "\r";
+ }
+
+ // Make sure we have a line break at the EOF.
+ if (substr($diff, -strlen($lnbr)) != $lnbr) {
+ $diff .= $lnbr;
+ }
+
+ if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') {
+ return PEAR::raiseError('Type of diff is unsupported');
+ }
+
+ if ($mode == 'autodetect') {
+ $context = strpos($diff, '***');
+ $unified = strpos($diff, '---');
+ if ($context === $unified) {
+ return PEAR::raiseError('Type of diff could not be detected');
+ } elseif ($context === false || $unified === false) {
+ $mode = $context !== false ? 'context' : 'unified';
+ } else {
+ $mode = $context < $unified ? 'context' : 'unified';
+ }
+ }
+
+ // Split by new line and remove the diff header, if there is one.
+ $diff = explode($lnbr, $diff);
+ if (($mode == 'context' && strpos($diff[0], '***') === 0) ||
+ ($mode == 'unified' && strpos($diff[0], '---') === 0)) {
+ array_shift($diff);
+ array_shift($diff);
+ }
+
+ if ($mode == 'context') {
+ return $this->parseContextDiff($diff);
+ } else {
+ return $this->parseUnifiedDiff($diff);
+ }
+ }
+
+ /**
+ * Parses an array containing the unified diff.
+ *
+ * @param array $diff Array of lines.
+ *
+ * @return array List of all diff operations.
+ */
+ function parseUnifiedDiff($diff)
+ {
+ $edits = array();
+ $end = count($diff) - 1;
+ for ($i = 0; $i < $end;) {
+ $diff1 = array();
+ switch (substr($diff[$i], 0, 1)) {
+ case ' ':
+ do {
+ $diff1[] = substr($diff[$i], 1);
+ } while (++$i < $end && substr($diff[$i], 0, 1) == ' ');
+ $edits[] = new Text_Diff_Op_copy($diff1);
+ break;
+
+ case '+':
+ // get all new lines
+ do {
+ $diff1[] = substr($diff[$i], 1);
+ } while (++$i < $end && substr($diff[$i], 0, 1) == '+');
+ $edits[] = new Text_Diff_Op_add($diff1);
+ break;
+
+ case '-':
+ // get changed or removed lines
+ $diff2 = array();
+ do {
+ $diff1[] = substr($diff[$i], 1);
+ } while (++$i < $end && substr($diff[$i], 0, 1) == '-');
+
+ while ($i < $end && substr($diff[$i], 0, 1) == '+') {
+ $diff2[] = substr($diff[$i++], 1);
+ }
+ if (count($diff2) == 0) {
+ $edits[] = new Text_Diff_Op_delete($diff1);
+ } else {
+ $edits[] = new Text_Diff_Op_change($diff1, $diff2);
+ }
+ break;
+
+ default:
+ $i++;
+ break;
+ }
+ }
+
+ return $edits;
+ }
+
+ /**
+ * Parses an array containing the context diff.
+ *
+ * @param array $diff Array of lines.
+ *
+ * @return array List of all diff operations.
+ */
+ function parseContextDiff(&$diff)
+ {
+ $edits = array();
+ $i = $max_i = $j = $max_j = 0;
+ $end = count($diff) - 1;
+ while ($i < $end && $j < $end) {
+ while ($i >= $max_i && $j >= $max_j) {
+ // Find the boundaries of the diff output of the two files
+ for ($i = $j;
+ $i < $end && substr($diff[$i], 0, 3) == '***';
+ $i++);
+ for ($max_i = $i;
+ $max_i < $end && substr($diff[$max_i], 0, 3) != '---';
+ $max_i++);
+ for ($j = $max_i;
+ $j < $end && substr($diff[$j], 0, 3) == '---';
+ $j++);
+ for ($max_j = $j;
+ $max_j < $end && substr($diff[$max_j], 0, 3) != '***';
+ $max_j++);
+ }
+
+ // find what hasn't been changed
+ $array = array();
+ while ($i < $max_i &&
+ $j < $max_j &&
+ strcmp($diff[$i], $diff[$j]) == 0) {
+ $array[] = substr($diff[$i], 2);
+ $i++;
+ $j++;
+ }
+
+ while ($i < $max_i && ($max_j-$j) <= 1) {
+ if ($diff[$i] != '' && substr($diff[$i], 0, 1) != ' ') {
+ break;
+ }
+ $array[] = substr($diff[$i++], 2);
+ }
+
+ while ($j < $max_j && ($max_i-$i) <= 1) {
+ if ($diff[$j] != '' && substr($diff[$j], 0, 1) != ' ') {
+ break;
+ }
+ $array[] = substr($diff[$j++], 2);
+ }
+ if (count($array) > 0) {
+ $edits[] = new Text_Diff_Op_copy($array);
+ }
+
+ if ($i < $max_i) {
+ $diff1 = array();
+ switch (substr($diff[$i], 0, 1)) {
+ case '!':
+ $diff2 = array();
+ do {
+ $diff1[] = substr($diff[$i], 2);
+ if ($j < $max_j && substr($diff[$j], 0, 1) == '!') {
+ $diff2[] = substr($diff[$j++], 2);
+ }
+ } while (++$i < $max_i && substr($diff[$i], 0, 1) == '!');
+ $edits[] = new Text_Diff_Op_change($diff1, $diff2);
+ break;
+
+ case '+':
+ do {
+ $diff1[] = substr($diff[$i], 2);
+ } while (++$i < $max_i && substr($diff[$i], 0, 1) == '+');
+ $edits[] = new Text_Diff_Op_add($diff1);
+ break;
+
+ case '-':
+ do {
+ $diff1[] = substr($diff[$i], 2);
+ } while (++$i < $max_i && substr($diff[$i], 0, 1) == '-');
+ $edits[] = new Text_Diff_Op_delete($diff1);
+ break;
+ }
+ }
+
+ if ($j < $max_j) {
+ $diff2 = array();
+ switch (substr($diff[$j], 0, 1)) {
+ case '+':
+ do {
+ $diff2[] = substr($diff[$j++], 2);
+ } while ($j < $max_j && substr($diff[$j], 0, 1) == '+');
+ $edits[] = new Text_Diff_Op_add($diff2);
+ break;
+
+ case '-':
+ do {
+ $diff2[] = substr($diff[$j++], 2);
+ } while ($j < $max_j && substr($diff[$j], 0, 1) == '-');
+ $edits[] = new Text_Diff_Op_delete($diff2);
+ break;
+ }
+ }
+ }
+
+ return $edits;
+ }
+
+}
diff --git a/src/wp-includes/Text/Diff/Engine/xdiff.php b/src/wp-includes/Text/Diff/Engine/xdiff.php
new file mode 100644
index 0000000000..02ce848078
--- /dev/null
+++ b/src/wp-includes/Text/Diff/Engine/xdiff.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Class used internally by Diff to actually compute the diffs.
+ *
+ * This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff)
+ * to compute the differences between the two input arrays.
+ *
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Jon Parise <jon@horde.org>
+ * @package Text_Diff
+ */
+class Text_Diff_Engine_xdiff {
+
+ /**
+ */
+ function diff($from_lines, $to_lines)
+ {
+ array_walk($from_lines, array('Text_Diff', 'trimNewlines'));
+ array_walk($to_lines, array('Text_Diff', 'trimNewlines'));
+
+ /* Convert the two input arrays into strings for xdiff processing. */
+ $from_string = implode("\n", $from_lines);
+ $to_string = implode("\n", $to_lines);
+
+ /* Diff the two strings and convert the result to an array. */
+ $diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
+ $diff = explode("\n", $diff);
+
+ /* Walk through the diff one line at a time. We build the $edits
+ * array of diff operations by reading the first character of the
+ * xdiff output (which is in the "unified diff" format).
+ *
+ * Note that we don't have enough information to detect "changed"
+ * lines using this approach, so we can't add Text_Diff_Op_changed
+ * instances to the $edits array. The result is still perfectly
+ * valid, albeit a little less descriptive and efficient. */
+ $edits = array();
+ foreach ($diff as $line) {
+ if (!strlen($line)) {
+ continue;
+ }
+ switch ($line[0]) {
+ case ' ':
+ $edits[] = new Text_Diff_Op_copy(array(substr($line, 1)));
+ break;
+
+ case '+':
+ $edits[] = new Text_Diff_Op_add(array(substr($line, 1)));
+ break;
+
+ case '-':
+ $edits[] = new Text_Diff_Op_delete(array(substr($line, 1)));
+ break;
+ }
+ }
+
+ return $edits;
+ }
+
+}
diff --git a/src/wp-includes/Text/Diff/Renderer.php b/src/wp-includes/Text/Diff/Renderer.php
new file mode 100644
index 0000000000..95c6db4b89
--- /dev/null
+++ b/src/wp-includes/Text/Diff/Renderer.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * A class to render Diffs in different formats.
+ *
+ * This class renders the diff in classic diff format. It is intended that
+ * this class be customized via inheritance, to obtain fancier outputs.
+ *
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @package Text_Diff
+ */
+class Text_Diff_Renderer {
+
+ /**
+ * Number of leading context "lines" to preserve.
+ *
+ * This should be left at zero for this class, but subclasses may want to
+ * set this to other values.
+ */
+ var $_leading_context_lines = 0;
+
+ /**
+ * Number of trailing context "lines" to preserve.
+ *
+ * This should be left at zero for this class, but subclasses may want to
+ * set this to other values.
+ */
+ var $_trailing_context_lines = 0;
+
+ /**
+ * Constructor.
+ */
+ function Text_Diff_Renderer($params = array())
+ {
+ foreach ($params as $param => $value) {
+ $v = '_' . $param;
+ if (isset($this->$v)) {
+ $this->$v = $value;
+ }
+ }
+ }
+
+ /**
+ * Get any renderer parameters.
+ *
+ * @return array All parameters of this renderer object.
+ */
+ function getParams()
+ {
+ $params = array();
+ foreach (get_object_vars($this) as $k => $v) {
+ if ($k[0] == '_') {
+ $params[substr($k, 1)] = $v;
+ }
+ }
+
+ return $params;
+ }
+
+ /**
+ * Renders a diff.
+ *
+ * @param Text_Diff $diff A Text_Diff object.
+ *
+ * @return string The formatted output.
+ */
+ function render($diff)
+ {
+ $xi = $yi = 1;
+ $block = false;
+ $context = array();
+
+ $nlead = $this->_leading_context_lines;
+ $ntrail = $this->_trailing_context_lines;
+
+ $output = $this->_startDiff();
+
+ $diffs = $diff->getDiff();
+ foreach ($diffs as $i => $edit) {
+ /* If these are unchanged (copied) lines, and we want to keep
+ * leading or trailing context lines, extract them from the copy
+ * block. */
+ if (is_a($edit, 'Text_Diff_Op_copy')) {
+ /* Do we have any diff blocks yet? */
+ if (is_array($block)) {
+ /* How many lines to keep as context from the copy
+ * block. */
+ $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
+ if (count($edit->orig) <= $keep) {
+ /* We have less lines in the block than we want for
+ * context => keep the whole block. */
+ $block[] = $edit;
+ } else {
+ if ($ntrail) {
+ /* Create a new block with as many lines as we need
+ * for the trailing context. */
+ $context = array_slice($edit->orig, 0, $ntrail);
+ $block[] = new Text_Diff_Op_copy($context);
+ }
+ /* @todo */
+ $output .= $this->_block($x0, $ntrail + $xi - $x0,
+ $y0, $ntrail + $yi - $y0,
+ $block);
+ $block = false;
+ }
+ }
+ /* Keep the copy block as the context for the next block. */
+ $context = $edit->orig;
+ } else {
+ /* Don't we have any diff blocks yet? */
+ if (!is_array($block)) {
+ /* Extract context lines from the preceding copy block. */
+ $context = array_slice($context, count($context) - $nlead);
+ $x0 = $xi - count($context);
+ $y0 = $yi - count($context);
+ $block = array();
+ if ($context) {
+ $block[] = new Text_Diff_Op_copy($context);
+ }
+ }
+ $block[] = $edit;
+ }
+
+ if ($edit->orig) {
+ $xi += count($edit->orig);
+ }
+ if ($edit->final) {
+ $yi += count($edit->final);
+ }
+ }
+
+ if (is_array($block)) {
+ $output .= $this->_block($x0, $xi - $x0,
+ $y0, $yi - $y0,
+ $block);
+ }
+
+ return $output . $this->_endDiff();
+ }
+
+ function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
+ {
+ $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
+
+ foreach ($edits as $edit) {
+ switch (strtolower(get_class($edit))) {
+ case 'text_diff_op_copy':
+ $output .= $this->_context($edit->orig);
+ break;
+
+ case 'text_diff_op_add':
+ $output .= $this->_added($edit->final);
+ break;
+
+ case 'text_diff_op_delete':
+ $output .= $this->_deleted($edit->orig);
+ break;
+
+ case 'text_diff_op_change':
+ $output .= $this->_changed($edit->orig, $edit->final);
+ break;
+ }
+ }
+
+ return $output . $this->_endBlock();
+ }
+
+ function _startDiff()
+ {
+ return '';
+ }
+
+ function _endDiff()
+ {
+ return '';
+ }
+
+ function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+ {
+ if ($xlen > 1) {
+ $xbeg .= ',' . ($xbeg + $xlen - 1);
+ }
+ if ($ylen > 1) {
+ $ybeg .= ',' . ($ybeg + $ylen - 1);
+ }
+
+ // this matches the GNU Diff behaviour
+ if ($xlen && !$ylen) {
+ $ybeg--;
+ } elseif (!$xlen) {
+ $xbeg--;
+ }
+
+ return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
+ }
+
+ function _startBlock($header)
+ {
+ return $header . "\n";
+ }
+
+ function _endBlock()
+ {
+ return '';
+ }
+
+ function _lines($lines, $prefix = ' ')
+ {
+ return $prefix . implode("\n$prefix", $lines) . "\n";
+ }
+
+ function _context($lines)
+ {
+ return $this->_lines($lines, ' ');
+ }
+
+ function _added($lines)
+ {
+ return $this->_lines($lines, '> ');
+ }
+
+ function _deleted($lines)
+ {
+ return $this->_lines($lines, '< ');
+ }
+
+ function _changed($orig, $final)
+ {
+ return $this->_deleted($orig) . "---\n" . $this->_added($final);
+ }
+
+}
diff --git a/src/wp-includes/Text/Diff/Renderer/inline.php b/src/wp-includes/Text/Diff/Renderer/inline.php
new file mode 100644
index 0000000000..392bd57cff
--- /dev/null
+++ b/src/wp-includes/Text/Diff/Renderer/inline.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ * "Inline" diff renderer.
+ *
+ * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you did
+ * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
+ *
+ * @author Ciprian Popovici
+ * @package Text_Diff
+ */
+
+/** Text_Diff_Renderer */
+
+// WP #7391
+require_once dirname(dirname(__FILE__)) . '/Renderer.php';
+
+/**
+ * "Inline" diff renderer.
+ *
+ * This class renders diffs in the Wiki-style "inline" format.
+ *
+ * @author Ciprian Popovici
+ * @package Text_Diff
+ */
+class Text_Diff_Renderer_inline extends Text_Diff_Renderer {
+
+ /**
+ * Number of leading context "lines" to preserve.
+ *
+ * @var integer
+ */
+ var $_leading_context_lines = 10000;
+
+ /**
+ * Number of trailing context "lines" to preserve.
+ *
+ * @var integer
+ */
+ var $_trailing_context_lines = 10000;
+
+ /**
+ * Prefix for inserted text.
+ *
+ * @var string
+ */
+ var $_ins_prefix = '<ins>';
+
+ /**
+ * Suffix for inserted text.
+ *
+ * @var string
+ */
+ var $_ins_suffix = '</ins>';
+
+ /**
+ * Prefix for deleted text.
+ *
+ * @var string
+ */
+ var $_del_prefix = '<del>';
+
+ /**
+ * Suffix for deleted text.
+ *
+ * @var string
+ */
+ var $_del_suffix = '</del>';
+
+ /**
+ * Header for each change block.
+ *
+ * @var string
+ */
+ var $_block_header = '';
+
+ /**
+ * Whether to split down to character-level.
+ *
+ * @var boolean
+ */
+ var $_split_characters = false;
+
+ /**
+ * What are we currently splitting on? Used to recurse to show word-level
+ * or character-level changes.
+ *
+ * @var string
+ */
+ var $_split_level = 'lines';
+
+ function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
+ {
+ return $this->_block_header;
+ }
+
+ function _startBlock($header)
+ {
+ return $header;
+ }
+
+ function _lines($lines, $prefix = ' ', $encode = true)
+ {
+ if ($encode) {
+ array_walk($lines, array(&$this, '_encode'));
+ }
+
+ if ($this->_split_level == 'lines') {
+ return implode("\n", $lines) . "\n";
+ } else {
+ return implode('', $lines);
+ }
+ }
+
+ function _added($lines)
+ {
+ array_walk($lines, array(&$this, '_encode'));
+ $lines[0] = $this->_ins_prefix . $lines[0];
+ $lines[count($lines) - 1] .= $this->_ins_suffix;
+ return $this->_lines($lines, ' ', false);
+ }
+
+ function _deleted($lines, $words = false)
+ {
+ array_walk($lines, array(&$this, '_encode'));
+ $lines[0] = $this->_del_prefix . $lines[0];
+ $lines[count($lines) - 1] .= $this->_del_suffix;
+ return $this->_lines($lines, ' ', false);
+ }
+
+ function _changed($orig, $final)
+ {
+ /* If we've already split on characters, just display. */
+ if ($this->_split_level == 'characters') {
+ return $this->_deleted($orig)
+ . $this->_added($final);
+ }
+
+ /* If we've already split on words, just display. */
+ if ($this->_split_level == 'words') {
+ $prefix = '';
+ while ($orig[0] !== false && $final[0] !== false &&
+ substr($orig[0], 0, 1) == ' ' &&
+ substr($final[0], 0, 1) == ' ') {
+ $prefix .= substr($orig[0], 0, 1);
+ $orig[0] = substr($orig[0], 1);
+ $final[0] = substr($final[0], 1);
+ }
+ return $prefix . $this->_deleted($orig) . $this->_added($final);
+ }
+
+ $text1 = implode("\n", $orig);
+ $text2 = implode("\n", $final);
+
+ /* Non-printing newline marker. */
+ $nl = "\0";
+
+ if ($this->_split_characters) {
+ $diff = new Text_Diff('native',
+ array(preg_split('//', $text1),
+ preg_split('//', $text2)));
+ } else {
+ /* We want to split on word boundaries, but we need to preserve
+ * whitespace as well. Therefore we split on words, but include
+ * all blocks of whitespace in the wordlist. */
+ $diff = new Text_Diff('native',
+ array($this->_splitOnWords($text1, $nl),
+ $this->_splitOnWords($text2, $nl)));
+ }
+
+ /* Get the diff in inline format. */
+ $renderer = new Text_Diff_Renderer_inline
+ (array_merge($this->getParams(),
+ array('split_level' => $this->_split_characters ? 'characters' : 'words')));
+
+ /* Run the diff and get the output. */
+ return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
+ }
+
+ function _splitOnWords($string, $newlineEscape = "\n")
+ {
+ // Ignore \0; otherwise the while loop will never finish.
+ $string = str_replace("\0", '', $string);
+
+ $words = array();
+ $length = strlen($string);
+ $pos = 0;
+
+ while ($pos < $length) {
+ // Eat a word with any preceding whitespace.
+ $spaces = strspn(substr($string, $pos), " \n");
+ $nextpos = strcspn(substr($string, $pos + $spaces), " \n");
+ $words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
+ $pos += $spaces + $nextpos;
+ }
+
+ return $words;
+ }
+
+ function _encode(&$string)
+ {
+ $string = htmlspecialchars($string);
+ }
+
+}
diff --git a/src/wp-includes/admin-bar.php b/src/wp-includes/admin-bar.php
new file mode 100644
index 0000000000..d2664ca71e
--- /dev/null
+++ b/src/wp-includes/admin-bar.php
@@ -0,0 +1,792 @@
+<?php
+/**
+ * Admin Bar
+ *
+ * This code handles the building and rendering of the press bar.
+ */
+
+/**
+ * Instantiate the admin bar object and set it up as a global for access elsewhere.
+ *
+ * UNHOOKING THIS FUNCTION WILL NOT PROPERLY REMOVE THE ADMIN BAR.
+ * For that, use show_admin_bar(false) or the 'show_admin_bar' filter.
+ *
+ * @since 3.1.0
+ * @access private
+ * @return bool Whether the admin bar was successfully initialized.
+ */
+function _wp_admin_bar_init() {
+ global $wp_admin_bar;
+
+ if ( ! is_admin_bar_showing() )
+ return false;
+
+ /* Load the admin bar class code ready for instantiation */
+ require( ABSPATH . WPINC . '/class-wp-admin-bar.php' );
+
+ /* Instantiate the admin bar */
+ $admin_bar_class = apply_filters( 'wp_admin_bar_class', 'WP_Admin_Bar' );
+ if ( class_exists( $admin_bar_class ) )
+ $wp_admin_bar = new $admin_bar_class;
+ else
+ return false;
+
+ $wp_admin_bar->initialize();
+ $wp_admin_bar->add_menus();
+
+ return true;
+}
+// Don't remove. Wrong way to disable.
+add_action( 'template_redirect', '_wp_admin_bar_init', 0 );
+add_action( 'admin_init', '_wp_admin_bar_init' );
+
+/**
+ * Render the admin bar to the page based on the $wp_admin_bar->menu member var.
+ * This is called very late on the footer actions so that it will render after anything else being
+ * added to the footer.
+ *
+ * It includes the action "admin_bar_menu" which should be used to hook in and
+ * add new menus to the admin bar. That way you can be sure that you are adding at most optimal point,
+ * right before the admin bar is rendered. This also gives you access to the $post global, among others.
+ *
+ * @since 3.1.0
+ */
+function wp_admin_bar_render() {
+ global $wp_admin_bar;
+
+ if ( ! is_admin_bar_showing() || ! is_object( $wp_admin_bar ) )
+ return false;
+
+ do_action_ref_array( 'admin_bar_menu', array( &$wp_admin_bar ) );
+
+ do_action( 'wp_before_admin_bar_render' );
+
+ $wp_admin_bar->render();
+
+ do_action( 'wp_after_admin_bar_render' );
+}
+add_action( 'wp_footer', 'wp_admin_bar_render', 1000 );
+add_action( 'in_admin_header', 'wp_admin_bar_render', 0 );
+
+/**
+ * Add the WordPress logo menu.
+ *
+ * @since 3.3.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_wp_menu( $wp_admin_bar ) {
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'wp-logo',
+ 'title' => '<span class="ab-icon"></span>',
+ 'href' => self_admin_url( 'about.php' ),
+ 'meta' => array(
+ 'title' => __('About WordPress'),
+ ),
+ ) );
+
+ if ( is_user_logged_in() ) {
+ // Add "About WordPress" link
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'wp-logo',
+ 'id' => 'about',
+ 'title' => __('About WordPress'),
+ 'href' => self_admin_url( 'about.php' ),
+ ) );
+ }
+
+ // Add WordPress.org link
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'wp-logo-external',
+ 'id' => 'wporg',
+ 'title' => __('WordPress.org'),
+ 'href' => __('http://wordpress.org/'),
+ ) );
+
+ // Add codex link
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'wp-logo-external',
+ 'id' => 'documentation',
+ 'title' => __('Documentation'),
+ 'href' => __('http://codex.wordpress.org/'),
+ ) );
+
+ // Add forums link
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'wp-logo-external',
+ 'id' => 'support-forums',
+ 'title' => __('Support Forums'),
+ 'href' => __('http://wordpress.org/support/'),
+ ) );
+
+ // Add feedback link
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'wp-logo-external',
+ 'id' => 'feedback',
+ 'title' => __('Feedback'),
+ 'href' => __('http://wordpress.org/support/forum/requests-and-feedback'),
+ ) );
+}
+
+/**
+ * Add the "My Account" item.
+ *
+ * @since 3.3.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_my_account_item( $wp_admin_bar ) {
+ $user_id = get_current_user_id();
+ $current_user = wp_get_current_user();
+ $profile_url = get_edit_profile_url( $user_id );
+
+ if ( ! $user_id )
+ return;
+
+ $avatar = get_avatar( $user_id, 16 );
+ $howdy = sprintf( __('Howdy, %1$s'), $current_user->display_name );
+ $class = empty( $avatar ) ? '' : 'with-avatar';
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'my-account',
+ 'parent' => 'top-secondary',
+ 'title' => $howdy . $avatar,
+ 'href' => $profile_url,
+ 'meta' => array(
+ 'class' => $class,
+ 'title' => __('My Account'),
+ ),
+ ) );
+}
+
+/**
+ * Add the "My Account" submenu items.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_my_account_menu( $wp_admin_bar ) {
+ $user_id = get_current_user_id();
+ $current_user = wp_get_current_user();
+ $profile_url = get_edit_profile_url( $user_id );
+
+ if ( ! $user_id )
+ return;
+
+ $wp_admin_bar->add_group( array(
+ 'parent' => 'my-account',
+ 'id' => 'user-actions',
+ ) );
+
+ $user_info = get_avatar( $user_id, 64 );
+ $user_info .= "<span class='display-name'>{$current_user->display_name}</span>";
+
+ if ( $current_user->display_name !== $current_user->user_login )
+ $user_info .= "<span class='username'>{$current_user->user_login}</span>";
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'user-actions',
+ 'id' => 'user-info',
+ 'title' => $user_info,
+ 'href' => $profile_url,
+ 'meta' => array(
+ 'tabindex' => -1,
+ ),
+ ) );
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'user-actions',
+ 'id' => 'edit-profile',
+ 'title' => __( 'Edit My Profile' ),
+ 'href' => $profile_url,
+ ) );
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'user-actions',
+ 'id' => 'logout',
+ 'title' => __( 'Log Out' ),
+ 'href' => wp_logout_url(),
+ ) );
+}
+
+/**
+ * Add the "Site Name" menu.
+ *
+ * @since 3.3.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_site_menu( $wp_admin_bar ) {
+ global $current_site;
+
+ // Don't show for logged out users.
+ if ( ! is_user_logged_in() )
+ return;
+
+ // Show only when the user is a member of this site, or they're a super admin.
+ if ( ! is_user_member_of_blog() && ! is_super_admin() )
+ return;
+
+ $blogname = get_bloginfo('name');
+
+ if ( empty( $blogname ) )
+ $blogname = preg_replace( '#^(https?://)?(www.)?#', '', get_home_url() );
+
+ if ( is_network_admin() ) {
+ $blogname = sprintf( __('Network Admin: %s'), esc_html( $current_site->site_name ) );
+ } elseif ( is_user_admin() ) {
+ $blogname = sprintf( __('Global Dashboard: %s'), esc_html( $current_site->site_name ) );
+ }
+
+ $title = wp_html_excerpt( $blogname, 40, '&hellip;' );
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'site-name',
+ 'title' => $title,
+ 'href' => is_admin() ? home_url( '/' ) : admin_url(),
+ ) );
+
+ // Create submenu items.
+
+ if ( is_admin() ) {
+ // Add an option to visit the site.
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'site-name',
+ 'id' => 'view-site',
+ 'title' => __( 'Visit Site' ),
+ 'href' => home_url( '/' ),
+ ) );
+
+ if ( is_blog_admin() && is_multisite() && current_user_can( 'manage_sites' ) ) {
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'site-name',
+ 'id' => 'edit-site',
+ 'title' => __( 'Edit Site' ),
+ 'href' => network_admin_url( 'site-info.php?id=' . get_current_blog_id() ),
+ ) );
+ }
+
+ } else {
+ // We're on the front end, link to the Dashboard.
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'site-name',
+ 'id' => 'dashboard',
+ 'title' => __( 'Dashboard' ),
+ 'href' => admin_url(),
+ ) );
+
+ // Add the appearance submenu items.
+ wp_admin_bar_appearance_menu( $wp_admin_bar );
+ }
+}
+
+/**
+ * Add the "My Sites/[Site Name]" menu and all submenus.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_my_sites_menu( $wp_admin_bar ) {
+ // Don't show for logged out users or single site mode.
+ if ( ! is_user_logged_in() || ! is_multisite() )
+ return;
+
+ // Show only when the user has at least one site, or they're a super admin.
+ if ( count( $wp_admin_bar->user->blogs ) < 1 && ! is_super_admin() )
+ return;
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'my-sites',
+ 'title' => __( 'My Sites' ),
+ 'href' => admin_url( 'my-sites.php' ),
+ ) );
+
+ if ( is_super_admin() ) {
+ $wp_admin_bar->add_group( array(
+ 'parent' => 'my-sites',
+ 'id' => 'my-sites-super-admin',
+ ) );
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'my-sites-super-admin',
+ 'id' => 'network-admin',
+ 'title' => __('Network Admin'),
+ 'href' => network_admin_url(),
+ ) );
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'network-admin',
+ 'id' => 'network-admin-d',
+ 'title' => __( 'Dashboard' ),
+ 'href' => network_admin_url(),
+ ) );
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'network-admin',
+ 'id' => 'network-admin-s',
+ 'title' => __( 'Sites' ),
+ 'href' => network_admin_url( 'sites.php' ),
+ ) );
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'network-admin',
+ 'id' => 'network-admin-u',
+ 'title' => __( 'Users' ),
+ 'href' => network_admin_url( 'users.php' ),
+ ) );
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'network-admin',
+ 'id' => 'network-admin-v',
+ 'title' => __( 'Visit Network' ),
+ 'href' => network_home_url(),
+ ) );
+ }
+
+ // Add site links
+ $wp_admin_bar->add_group( array(
+ 'parent' => 'my-sites',
+ 'id' => 'my-sites-list',
+ 'meta' => array(
+ 'class' => is_super_admin() ? 'ab-sub-secondary' : '',
+ ),
+ ) );
+
+ foreach ( (array) $wp_admin_bar->user->blogs as $blog ) {
+ switch_to_blog( $blog->userblog_id );
+
+ $blavatar = '<div class="blavatar"></div>';
+
+ $blogname = empty( $blog->blogname ) ? $blog->domain : $blog->blogname;
+ $menu_id = 'blog-' . $blog->userblog_id;
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'my-sites-list',
+ 'id' => $menu_id,
+ 'title' => $blavatar . $blogname,
+ 'href' => admin_url(),
+ ) );
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => $menu_id,
+ 'id' => $menu_id . '-d',
+ 'title' => __( 'Dashboard' ),
+ 'href' => admin_url(),
+ ) );
+
+ if ( current_user_can( get_post_type_object( 'post' )->cap->create_posts ) ) {
+ $wp_admin_bar->add_menu( array(
+ 'parent' => $menu_id,
+ 'id' => $menu_id . '-n',
+ 'title' => __( 'New Post' ),
+ 'href' => admin_url( 'post-new.php' ),
+ ) );
+ }
+
+ if ( current_user_can( 'edit_posts' ) ) {
+ $wp_admin_bar->add_menu( array(
+ 'parent' => $menu_id,
+ 'id' => $menu_id . '-c',
+ 'title' => __( 'Manage Comments' ),
+ 'href' => admin_url( 'edit-comments.php' ),
+ ) );
+ }
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => $menu_id,
+ 'id' => $menu_id . '-v',
+ 'title' => __( 'Visit Site' ),
+ 'href' => home_url( '/' ),
+ ) );
+
+ restore_current_blog();
+ }
+}
+
+/**
+ * Provide a shortlink.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_shortlink_menu( $wp_admin_bar ) {
+ $short = wp_get_shortlink( 0, 'query' );
+ $id = 'get-shortlink';
+
+ if ( empty( $short ) )
+ return;
+
+ $html = '<input class="shortlink-input" type="text" readonly="readonly" value="' . esc_attr( $short ) . '" />';
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => $id,
+ 'title' => __( 'Shortlink' ),
+ 'href' => $short,
+ 'meta' => array( 'html' => $html ),
+ ) );
+}
+
+/**
+ * Provide an edit link for posts and terms.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_edit_menu( $wp_admin_bar ) {
+ global $tag, $wp_the_query;
+
+ if ( is_admin() ) {
+ $current_screen = get_current_screen();
+ $post = get_post();
+
+ if ( 'post' == $current_screen->base
+ && 'add' != $current_screen->action
+ && ( $post_type_object = get_post_type_object( $post->post_type ) )
+ && current_user_can( 'read_post', $post->ID )
+ && ( $post_type_object->public )
+ && ( $post_type_object->show_in_admin_bar ) )
+ {
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'view',
+ 'title' => $post_type_object->labels->view_item,
+ 'href' => get_permalink( $post->ID )
+ ) );
+ } elseif ( 'edit-tags' == $current_screen->base
+ && isset( $tag ) && is_object( $tag )
+ && ( $tax = get_taxonomy( $tag->taxonomy ) )
+ && $tax->public )
+ {
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'view',
+ 'title' => $tax->labels->view_item,
+ 'href' => get_term_link( $tag )
+ ) );
+ }
+ } else {
+ $current_object = $wp_the_query->get_queried_object();
+
+ if ( empty( $current_object ) )
+ return;
+
+ if ( ! empty( $current_object->post_type )
+ && ( $post_type_object = get_post_type_object( $current_object->post_type ) )
+ && current_user_can( 'edit_post', $current_object->ID )
+ && $post_type_object->show_ui && $post_type_object->show_in_admin_bar )
+ {
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'edit',
+ 'title' => $post_type_object->labels->edit_item,
+ 'href' => get_edit_post_link( $current_object->ID )
+ ) );
+ } elseif ( ! empty( $current_object->taxonomy )
+ && ( $tax = get_taxonomy( $current_object->taxonomy ) )
+ && current_user_can( $tax->cap->edit_terms )
+ && $tax->show_ui )
+ {
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'edit',
+ 'title' => $tax->labels->edit_item,
+ 'href' => get_edit_term_link( $current_object->term_id, $current_object->taxonomy )
+ ) );
+ }
+ }
+}
+
+/**
+ * Add "Add New" menu.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_new_content_menu( $wp_admin_bar ) {
+ $actions = array();
+
+ $cpts = (array) get_post_types( array( 'show_in_admin_bar' => true ), 'objects' );
+
+ if ( isset( $cpts['post'] ) && current_user_can( $cpts['post']->cap->create_posts ) )
+ $actions[ 'post-new.php' ] = array( $cpts['post']->labels->name_admin_bar, 'new-post' );
+
+ if ( isset( $cpts['attachment'] ) && current_user_can( 'upload_files' ) )
+ $actions[ 'media-new.php' ] = array( $cpts['attachment']->labels->name_admin_bar, 'new-media' );
+
+ if ( current_user_can( 'manage_links' ) )
+ $actions[ 'link-add.php' ] = array( _x( 'Link', 'add new from admin bar' ), 'new-link' );
+
+ if ( isset( $cpts['page'] ) && current_user_can( $cpts['page']->cap->create_posts ) )
+ $actions[ 'post-new.php?post_type=page' ] = array( $cpts['page']->labels->name_admin_bar, 'new-page' );
+
+ unset( $cpts['post'], $cpts['page'], $cpts['attachment'] );
+
+ // Add any additional custom post types.
+ foreach ( $cpts as $cpt ) {
+ if ( ! current_user_can( $cpt->cap->create_posts ) )
+ continue;
+
+ $key = 'post-new.php?post_type=' . $cpt->name;
+ $actions[ $key ] = array( $cpt->labels->name_admin_bar, 'new-' . $cpt->name );
+ }
+ // Avoid clash with parent node and a 'content' post type.
+ if ( isset( $actions['post-new.php?post_type=content'] ) )
+ $actions['post-new.php?post_type=content'][1] = 'add-new-content';
+
+ if ( current_user_can( 'create_users' ) || current_user_can( 'promote_users' ) )
+ $actions[ 'user-new.php' ] = array( _x( 'User', 'add new from admin bar' ), 'new-user' );
+
+ if ( ! $actions )
+ return;
+
+ $title = '<span class="ab-icon"></span><span class="ab-label">' . _x( 'New', 'admin bar menu group label' ) . '</span>';
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'new-content',
+ 'title' => $title,
+ 'href' => admin_url( current( array_keys( $actions ) ) ),
+ 'meta' => array(
+ 'title' => _x( 'Add New', 'admin bar menu group label' ),
+ ),
+ ) );
+
+ foreach ( $actions as $link => $action ) {
+ list( $title, $id ) = $action;
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'new-content',
+ 'id' => $id,
+ 'title' => $title,
+ 'href' => admin_url( $link )
+ ) );
+ }
+}
+
+/**
+ * Add edit comments link with awaiting moderation count bubble.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_comments_menu( $wp_admin_bar ) {
+ if ( !current_user_can('edit_posts') )
+ return;
+
+ $awaiting_mod = wp_count_comments();
+ $awaiting_mod = $awaiting_mod->moderated;
+ $awaiting_title = esc_attr( sprintf( _n( '%s comment awaiting moderation', '%s comments awaiting moderation', $awaiting_mod ), number_format_i18n( $awaiting_mod ) ) );
+
+ $icon = '<span class="ab-icon"></span>';
+ $title = '<span id="ab-awaiting-mod" class="ab-label awaiting-mod pending-count count-' . $awaiting_mod . '">' . number_format_i18n( $awaiting_mod ) . '</span>';
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'comments',
+ 'title' => $icon . $title,
+ 'href' => admin_url('edit-comments.php'),
+ 'meta' => array( 'title' => $awaiting_title ),
+ ) );
+}
+
+/**
+ * Add appearance submenu items to the "Site Name" menu.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_appearance_menu( $wp_admin_bar ) {
+ $wp_admin_bar->add_group( array( 'parent' => 'site-name', 'id' => 'appearance' ) );
+
+ if ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) )
+ $wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'themes', 'title' => __('Themes'), 'href' => admin_url('themes.php') ) );
+
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ return;
+
+ $current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'appearance',
+ 'id' => 'customize',
+ 'title' => __('Customize'),
+ 'href' => add_query_arg( 'url', urlencode( $current_url ), wp_customize_url() ),
+ 'meta' => array(
+ 'class' => 'hide-if-no-customize',
+ ),
+ ) );
+ add_action( 'wp_before_admin_bar_render', 'wp_customize_support_script' );
+
+ if ( current_theme_supports( 'widgets' ) )
+ $wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'widgets', 'title' => __('Widgets'), 'href' => admin_url('widgets.php') ) );
+
+ if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) )
+ $wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'menus', 'title' => __('Menus'), 'href' => admin_url('nav-menus.php') ) );
+
+ if ( current_theme_supports( 'custom-background' ) )
+ $wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'background', 'title' => __('Background'), 'href' => admin_url('themes.php?page=custom-background') ) );
+
+ if ( current_theme_supports( 'custom-header' ) )
+ $wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'header', 'title' => __('Header'), 'href' => admin_url('themes.php?page=custom-header') ) );
+}
+
+/**
+ * Provide an update link if theme/plugin/core updates are available.
+ *
+ * @since 3.1.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_updates_menu( $wp_admin_bar ) {
+
+ $update_data = wp_get_update_data();
+
+ if ( !$update_data['counts']['total'] )
+ return;
+
+ $title = '<span class="ab-icon"></span><span class="ab-label">' . number_format_i18n( $update_data['counts']['total'] ) . '</span>';
+ $title .= '<span class="screen-reader-text">' . $update_data['title'] . '</span>';
+
+ $wp_admin_bar->add_menu( array(
+ 'id' => 'updates',
+ 'title' => $title,
+ 'href' => network_admin_url( 'update-core.php' ),
+ 'meta' => array(
+ 'title' => $update_data['title'],
+ ),
+ ) );
+}
+
+/**
+ * Add search form.
+ *
+ * @since 3.3.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_search_menu( $wp_admin_bar ) {
+ if ( is_admin() )
+ return;
+
+ $form = '<form action="' . esc_url( home_url( '/' ) ) . '" method="get" id="adminbarsearch">';
+ $form .= '<input class="adminbar-input" name="s" id="adminbar-search" type="text" value="" maxlength="150" />';
+ $form .= '<input type="submit" class="adminbar-button" value="' . __('Search') . '"/>';
+ $form .= '</form>';
+
+ $wp_admin_bar->add_menu( array(
+ 'parent' => 'top-secondary',
+ 'id' => 'search',
+ 'title' => $form,
+ 'meta' => array(
+ 'class' => 'admin-bar-search',
+ 'tabindex' => -1,
+ )
+ ) );
+}
+
+/**
+ * Add secondary menus.
+ *
+ * @since 3.3.0
+ *
+ * @param WP_Admin_Bar $wp_admin_bar
+ */
+function wp_admin_bar_add_secondary_groups( $wp_admin_bar ) {
+ $wp_admin_bar->add_group( array(
+ 'id' => 'top-secondary',
+ 'meta' => array(
+ 'class' => 'ab-top-secondary',
+ ),
+ ) );
+
+ $wp_admin_bar->add_group( array(
+ 'parent' => 'wp-logo',
+ 'id' => 'wp-logo-external',
+ 'meta' => array(
+ 'class' => 'ab-sub-secondary',
+ ),
+ ) );
+}
+
+/**
+ * Style and scripts for the admin bar.
+ *
+ * @since 3.1.0
+ */
+function wp_admin_bar_header() { ?>
+<style type="text/css" media="print">#wpadminbar { display:none; }</style>
+<?php
+}
+
+/**
+ * Default admin bar callback.
+ *
+ * @since 3.1.0
+ */
+function _admin_bar_bump_cb() { ?>
+<style type="text/css" media="screen">
+ html { margin-top: 28px !important; }
+ * html body { margin-top: 28px !important; }
+</style>
+<?php
+}
+
+/**
+ * Set the display status of the admin bar.
+ *
+ * This can be called immediately upon plugin load. It does not need to be called from a function hooked to the init action.
+ *
+ * @since 3.1.0
+ *
+ * @param bool $show Whether to allow the admin bar to show.
+ * @return void
+ */
+function show_admin_bar( $show ) {
+ global $show_admin_bar;
+ $show_admin_bar = (bool) $show;
+}
+
+/**
+ * Determine whether the admin bar should be showing.
+ *
+ * @since 3.1.0
+ *
+ * @return bool Whether the admin bar should be showing.
+ */
+function is_admin_bar_showing() {
+ global $show_admin_bar, $pagenow;
+
+ // For all these types of requests, we never want an admin bar.
+ if ( defined('XMLRPC_REQUEST') || defined('DOING_AJAX') || defined('IFRAME_REQUEST') )
+ return false;
+
+ // Integrated into the admin.
+ if ( is_admin() )
+ return true;
+
+ if ( ! isset( $show_admin_bar ) ) {
+ if ( ! is_user_logged_in() || 'wp-login.php' == $pagenow ) {
+ $show_admin_bar = false;
+ } else {
+ $show_admin_bar = _get_admin_bar_pref();
+ }
+ }
+
+ $show_admin_bar = apply_filters( 'show_admin_bar', $show_admin_bar );
+
+ return $show_admin_bar;
+}
+
+/**
+ * Retrieve the admin bar display preference of a user.
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param string $context Context of this preference check. Defaults to 'front'. The 'admin'
+ * preference is no longer used.
+ * @param int $user Optional. ID of the user to check, defaults to 0 for current user.
+ * @return bool Whether the admin bar should be showing for this user.
+ */
+function _get_admin_bar_pref( $context = 'front', $user = 0 ) {
+ $pref = get_user_option( "show_admin_bar_{$context}", $user );
+ if ( false === $pref )
+ return true;
+
+ return 'true' === $pref;
+}
diff --git a/src/wp-includes/atomlib.php b/src/wp-includes/atomlib.php
new file mode 100644
index 0000000000..4dcddc99cb
--- /dev/null
+++ b/src/wp-includes/atomlib.php
@@ -0,0 +1,352 @@
+<?php
+/**
+ * Atom Syndication Format PHP Library
+ *
+ * @package AtomLib
+ * @link http://code.google.com/p/phpatomlib/
+ *
+ * @author Elias Torres <elias@torrez.us>
+ * @version 0.4
+ * @since 2.3
+ */
+
+/**
+ * Structure that store common Atom Feed Properties
+ *
+ * @package AtomLib
+ */
+class AtomFeed {
+ /**
+ * Stores Links
+ * @var array
+ * @access public
+ */
+ var $links = array();
+ /**
+ * Stores Categories
+ * @var array
+ * @access public
+ */
+ var $categories = array();
+ /**
+ * Stores Entries
+ *
+ * @var array
+ * @access public
+ */
+ var $entries = array();
+}
+
+/**
+ * Structure that store Atom Entry Properties
+ *
+ * @package AtomLib
+ */
+class AtomEntry {
+ /**
+ * Stores Links
+ * @var array
+ * @access public
+ */
+ var $links = array();
+ /**
+ * Stores Categories
+ * @var array
+ * @access public
+ */
+ var $categories = array();
+}
+
+/**
+ * AtomLib Atom Parser API
+ *
+ * @package AtomLib
+ */
+class AtomParser {
+
+ var $NS = 'http://www.w3.org/2005/Atom';
+ var $ATOM_CONTENT_ELEMENTS = array('content','summary','title','subtitle','rights');
+ var $ATOM_SIMPLE_ELEMENTS = array('id','updated','published','draft');
+
+ var $debug = false;
+
+ var $depth = 0;
+ var $indent = 2;
+ var $in_content;
+ var $ns_contexts = array();
+ var $ns_decls = array();
+ var $content_ns_decls = array();
+ var $content_ns_contexts = array();
+ var $is_xhtml = false;
+ var $is_html = false;
+ var $is_text = true;
+ var $skipped_div = false;
+
+ var $FILE = "php://input";
+
+ var $feed;
+ var $current;
+
+ function AtomParser() {
+
+ $this->feed = new AtomFeed();
+ $this->current = null;
+ $this->map_attrs_func = create_function('$k,$v', 'return "$k=\"$v\"";');
+ $this->map_xmlns_func = create_function('$p,$n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";');
+ }
+
+ function _p($msg) {
+ if($this->debug) {
+ print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n";
+ }
+ }
+
+ function error_handler($log_level, $log_text, $error_file, $error_line) {
+ $this->error = $log_text;
+ }
+
+ function parse() {
+
+ set_error_handler(array(&$this, 'error_handler'));
+
+ array_unshift($this->ns_contexts, array());
+
+ $parser = xml_parser_create_ns();
+ xml_set_object($parser, $this);
+ xml_set_element_handler($parser, "start_element", "end_element");
+ xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);
+ xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,0);
+ xml_set_character_data_handler($parser, "cdata");
+ xml_set_default_handler($parser, "_default");
+ xml_set_start_namespace_decl_handler($parser, "start_ns");
+ xml_set_end_namespace_decl_handler($parser, "end_ns");
+
+ $this->content = '';
+
+ $ret = true;
+
+ $fp = fopen($this->FILE, "r");
+ while ($data = fread($fp, 4096)) {
+ if($this->debug) $this->content .= $data;
+
+ if(!xml_parse($parser, $data, feof($fp))) {
+ trigger_error(sprintf(__('XML error: %s at line %d')."\n",
+ xml_error_string(xml_get_error_code($parser)),
+ xml_get_current_line_number($parser)));
+ $ret = false;
+ break;
+ }
+ }
+ fclose($fp);
+
+ xml_parser_free($parser);
+
+ restore_error_handler();
+
+ return $ret;
+ }
+
+ function start_element($parser, $name, $attrs) {
+
+ $tag = array_pop(split(":", $name));
+
+ switch($name) {
+ case $this->NS . ':feed':
+ $this->current = $this->feed;
+ break;
+ case $this->NS . ':entry':
+ $this->current = new AtomEntry();
+ break;
+ };
+
+ $this->_p("start_element('$name')");
+ #$this->_p(print_r($this->ns_contexts,true));
+ #$this->_p('current(' . $this->current . ')');
+
+ array_unshift($this->ns_contexts, $this->ns_decls);
+
+ $this->depth++;
+
+ if(!empty($this->in_content)) {
+
+ $this->content_ns_decls = array();
+
+ if($this->is_html || $this->is_text)
+ trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup.");
+
+ $attrs_prefix = array();
+
+ // resolve prefixes for attributes
+ foreach($attrs as $key => $value) {
+ $with_prefix = $this->ns_to_prefix($key, true);
+ $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value);
+ }
+
+ $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix)));
+ if(strlen($attrs_str) > 0) {
+ $attrs_str = " " . $attrs_str;
+ }
+
+ $with_prefix = $this->ns_to_prefix($name);
+
+ if(!$this->is_declared_content_ns($with_prefix[0])) {
+ array_push($this->content_ns_decls, $with_prefix[0]);
+ }
+
+ $xmlns_str = '';
+ if(count($this->content_ns_decls) > 0) {
+ array_unshift($this->content_ns_contexts, $this->content_ns_decls);
+ $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0])));
+ if(strlen($xmlns_str) > 0) {
+ $xmlns_str = " " . $xmlns_str;
+ }
+ }
+
+ array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">"));
+
+ } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) {
+ $this->in_content = array();
+ $this->is_xhtml = $attrs['type'] == 'xhtml';
+ $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html';
+ $this->is_text = !in_array('type',array_keys($attrs)) || $attrs['type'] == 'text';
+ $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type']));
+
+ if(in_array('src',array_keys($attrs))) {
+ $this->current->$tag = $attrs;
+ } else {
+ array_push($this->in_content, array($tag,$this->depth, $type));
+ }
+ } else if($tag == 'link') {
+ array_push($this->current->links, $attrs);
+ } else if($tag == 'category') {
+ array_push($this->current->categories, $attrs);
+ }
+
+ $this->ns_decls = array();
+ }
+
+ function end_element($parser, $name) {
+
+ $tag = array_pop(split(":", $name));
+
+ $ccount = count($this->in_content);
+
+ # if we are *in* content, then let's proceed to serialize it
+ if(!empty($this->in_content)) {
+ # if we are ending the original content element
+ # then let's finalize the content
+ if($this->in_content[0][0] == $tag &&
+ $this->in_content[0][1] == $this->depth) {
+ $origtype = $this->in_content[0][2];
+ array_shift($this->in_content);
+ $newcontent = array();
+ foreach($this->in_content as $c) {
+ if(count($c) == 3) {
+ array_push($newcontent, $c[2]);
+ } else {
+ if($this->is_xhtml || $this->is_text) {
+ array_push($newcontent, $this->xml_escape($c));
+ } else {
+ array_push($newcontent, $c);
+ }
+ }
+ }
+ if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) {
+ $this->current->$tag = array($origtype, join('',$newcontent));
+ } else {
+ $this->current->$tag = join('',$newcontent);
+ }
+ $this->in_content = array();
+ } else if($this->in_content[$ccount-1][0] == $tag &&
+ $this->in_content[$ccount-1][1] == $this->depth) {
+ $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2],0,-1) . "/>";
+ } else {
+ # else, just finalize the current element's content
+ $endtag = $this->ns_to_prefix($name);
+ array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>"));
+ }
+ }
+
+ array_shift($this->ns_contexts);
+
+ $this->depth--;
+
+ if($name == ($this->NS . ':entry')) {
+ array_push($this->feed->entries, $this->current);
+ $this->current = null;
+ }
+
+ $this->_p("end_element('$name')");
+ }
+
+ function start_ns($parser, $prefix, $uri) {
+ $this->_p("starting: " . $prefix . ":" . $uri);
+ array_push($this->ns_decls, array($prefix,$uri));
+ }
+
+ function end_ns($parser, $prefix) {
+ $this->_p("ending: #" . $prefix . "#");
+ }
+
+ function cdata($parser, $data) {
+ $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#");
+ if(!empty($this->in_content)) {
+ array_push($this->in_content, $data);
+ }
+ }
+
+ function _default($parser, $data) {
+ # when does this gets called?
+ }
+
+
+ function ns_to_prefix($qname, $attr=false) {
+ # split 'http://www.w3.org/1999/xhtml:div' into ('http','//www.w3.org/1999/xhtml','div')
+ $components = split(":", $qname);
+
+ # grab the last one (e.g 'div')
+ $name = array_pop($components);
+
+ if(!empty($components)) {
+ # re-join back the namespace component
+ $ns = join(":",$components);
+ foreach($this->ns_contexts as $context) {
+ foreach($context as $mapping) {
+ if($mapping[1] == $ns && strlen($mapping[0]) > 0) {
+ return array($mapping, "$mapping[0]:$name");
+ }
+ }
+ }
+ }
+
+ if($attr) {
+ return array(null, $name);
+ } else {
+ foreach($this->ns_contexts as $context) {
+ foreach($context as $mapping) {
+ if(strlen($mapping[0]) == 0) {
+ return array($mapping, $name);
+ }
+ }
+ }
+ }
+ }
+
+ function is_declared_content_ns($new_mapping) {
+ foreach($this->content_ns_contexts as $context) {
+ foreach($context as $mapping) {
+ if($new_mapping == $mapping) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ function xml_escape($string)
+ {
+ return str_replace(array('&','"',"'",'<','>'),
+ array('&amp;','&quot;','&apos;','&lt;','&gt;'),
+ $string );
+ }
+}
diff --git a/src/wp-includes/author-template.php b/src/wp-includes/author-template.php
new file mode 100644
index 0000000000..2a89498968
--- /dev/null
+++ b/src/wp-includes/author-template.php
@@ -0,0 +1,392 @@
+<?php
+/**
+ * Author Template functions for use in themes.
+ *
+ * These functions must be used within the WordPress Loop.
+ *
+ * @link http://codex.wordpress.org/Author_Templates
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Retrieve the author of the current post.
+ *
+ * @since 1.5
+ * @uses $authordata The current author's DB object.
+ * @uses apply_filters() Calls 'the_author' hook on the author display name.
+ *
+ * @param string $deprecated Deprecated.
+ * @return string The author's display name.
+ */
+function get_the_author($deprecated = '') {
+ global $authordata;
+
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.1' );
+
+ return apply_filters('the_author', is_object($authordata) ? $authordata->display_name : null);
+}
+
+/**
+ * Display the name of the author of the current post.
+ *
+ * The behavior of this function is based off of old functionality predating
+ * get_the_author(). This function is not deprecated, but is designed to echo
+ * the value from get_the_author() and as an result of any old theme that might
+ * still use the old behavior will also pass the value from get_the_author().
+ *
+ * The normal, expected behavior of this function is to echo the author and not
+ * return it. However, backwards compatibility has to be maintained.
+ *
+ * @since 0.71
+ * @see get_the_author()
+ * @link http://codex.wordpress.org/Template_Tags/the_author
+ *
+ * @param string $deprecated Deprecated.
+ * @param string $deprecated_echo Deprecated. Use get_the_author(). Echo the string or return it.
+ * @return string The author's display name, from get_the_author().
+ */
+function the_author( $deprecated = '', $deprecated_echo = true ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.1' );
+ if ( $deprecated_echo !== true )
+ _deprecated_argument( __FUNCTION__, '1.5', __('Use <code>get_the_author()</code> instead if you do not want the value echoed.') );
+ if ( $deprecated_echo )
+ echo get_the_author();
+ return get_the_author();
+}
+
+/**
+ * Retrieve the author who last edited the current post.
+ *
+ * @since 2.8
+ * @uses $post The current post's DB object.
+ * @uses get_post_meta() Retrieves the ID of the author who last edited the current post.
+ * @uses get_userdata() Retrieves the author's DB object.
+ * @uses apply_filters() Calls 'the_modified_author' hook on the author display name.
+ * @return string The author's display name.
+ */
+function get_the_modified_author() {
+ if ( $last_id = get_post_meta( get_post()->ID, '_edit_last', true) ) {
+ $last_user = get_userdata($last_id);
+ return apply_filters('the_modified_author', $last_user->display_name);
+ }
+}
+
+/**
+ * Display the name of the author who last edited the current post.
+ *
+ * @since 2.8
+ * @see get_the_author()
+ * @return string The author's display name, from get_the_modified_author().
+ */
+function the_modified_author() {
+ echo get_the_modified_author();
+}
+
+/**
+ * Retrieve the requested data of the author of the current post.
+ * @link http://codex.wordpress.org/Template_Tags/the_author_meta
+ * @since 2.8.0
+ * @uses $authordata The current author's DB object (if $user_id not specified).
+ * @param string $field selects the field of the users record.
+ * @param int $user_id Optional. User ID.
+ * @return string The author's field from the current author's DB object.
+ */
+function get_the_author_meta( $field = '', $user_id = false ) {
+ if ( ! $user_id ) {
+ global $authordata;
+ $user_id = isset( $authordata->ID ) ? $authordata->ID : 0;
+ } else {
+ $authordata = get_userdata( $user_id );
+ }
+
+ if ( in_array( $field, array( 'login', 'pass', 'nicename', 'email', 'url', 'registered', 'activation_key', 'status' ) ) )
+ $field = 'user_' . $field;
+
+ $value = isset( $authordata->$field ) ? $authordata->$field : '';
+
+ return apply_filters( 'get_the_author_' . $field, $value, $user_id );
+}
+
+/**
+ * Retrieve the requested data of the author of the current post.
+ * @link http://codex.wordpress.org/Template_Tags/the_author_meta
+ * @since 2.8.0
+ * @param string $field selects the field of the users record.
+ * @param int $user_id Optional. User ID.
+ * @echo string The author's field from the current author's DB object.
+ */
+function the_author_meta($field = '', $user_id = false) {
+ echo apply_filters('the_author_' . $field, get_the_author_meta($field, $user_id), $user_id);
+}
+
+/**
+ * Retrieve either author's link or author's name.
+ *
+ * If the author has a home page set, return an HTML link, otherwise just return the
+ * author's name.
+ *
+ * @uses get_the_author_meta()
+ * @uses get_the_author()
+ */
+function get_the_author_link() {
+ if ( get_the_author_meta('url') ) {
+ return '<a href="' . esc_url( get_the_author_meta('url') ) . '" title="' . esc_attr( sprintf(__("Visit %s&#8217;s website"), get_the_author()) ) . '" rel="author external">' . get_the_author() . '</a>';
+ } else {
+ return get_the_author();
+ }
+}
+
+/**
+ * Display either author's link or author's name.
+ *
+ * If the author has a home page set, echo an HTML link, otherwise just echo the
+ * author's name.
+ *
+ * @link http://codex.wordpress.org/Template_Tags/the_author_link
+ * @since 2.1
+ * @uses get_the_author_link()
+ */
+function the_author_link() {
+ echo get_the_author_link();
+}
+
+/**
+ * Retrieve the number of posts by the author of the current post.
+ *
+ * @since 1.5
+ * @uses $post The current post in the Loop's DB object.
+ * @uses count_user_posts()
+ * @return int The number of posts by the author.
+ */
+function get_the_author_posts() {
+ return count_user_posts( get_post()->post_author );
+}
+
+/**
+ * Display the number of posts by the author of the current post.
+ *
+ * @link http://codex.wordpress.org/Template_Tags/the_author_posts
+ * @since 0.71
+ * @uses get_the_author_posts() Echoes returned value from function.
+ */
+function the_author_posts() {
+ echo get_the_author_posts();
+}
+
+/**
+ * Display an HTML link to the author page of the author of the current post.
+ *
+ * Does just echo get_author_posts_url() function, like the others do. The
+ * reason for this, is that another function is used to help in printing the
+ * link to the author's posts.
+ *
+ * @link http://codex.wordpress.org/Template_Tags/the_author_posts_link
+ * @since 1.2.0
+ * @uses $authordata The current author's DB object.
+ * @uses get_author_posts_url()
+ * @uses get_the_author()
+ * @param string $deprecated Deprecated.
+ */
+function the_author_posts_link($deprecated = '') {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.1' );
+
+ global $authordata;
+ if ( !is_object( $authordata ) )
+ return false;
+ $link = sprintf(
+ '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
+ esc_url( get_author_posts_url( $authordata->ID, $authordata->user_nicename ) ),
+ esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
+ get_the_author()
+ );
+ echo apply_filters( 'the_author_posts_link', $link );
+}
+
+/**
+ * Retrieve the URL to the author page for the user with the ID provided.
+ *
+ * @since 2.1.0
+ * @uses $wp_rewrite WP_Rewrite
+ * @return string The URL to the author's page.
+ */
+function get_author_posts_url($author_id, $author_nicename = '') {
+ global $wp_rewrite;
+ $auth_ID = (int) $author_id;
+ $link = $wp_rewrite->get_author_permastruct();
+
+ if ( empty($link) ) {
+ $file = home_url( '/' );
+ $link = $file . '?author=' . $auth_ID;
+ } else {
+ if ( '' == $author_nicename ) {
+ $user = get_userdata($author_id);
+ if ( !empty($user->user_nicename) )
+ $author_nicename = $user->user_nicename;
+ }
+ $link = str_replace('%author%', $author_nicename, $link);
+ $link = home_url( user_trailingslashit( $link ) );
+ }
+
+ $link = apply_filters('author_link', $link, $author_id, $author_nicename);
+
+ return $link;
+}
+
+/**
+ * List all the authors of the blog, with several options available.
+ *
+ * <ul>
+ * <li>optioncount (boolean) (false): Show the count in parenthesis next to the
+ * author's name.</li>
+ * <li>exclude_admin (boolean) (true): Exclude the 'admin' user that is
+ * installed by default.</li>
+ * <li>show_fullname (boolean) (false): Show their full names.</li>
+ * <li>hide_empty (boolean) (true): Don't show authors without any posts.</li>
+ * <li>feed (string) (''): If isn't empty, show links to author's feeds.</li>
+ * <li>feed_image (string) (''): If isn't empty, use this image to link to
+ * feeds.</li>
+ * <li>echo (boolean) (true): Set to false to return the output, instead of
+ * echoing.</li>
+ * <li>style (string) ('list'): Whether to display list of authors in list form
+ * or as a string.</li>
+ * <li>html (bool) (true): Whether to list the items in html form or plaintext.
+ * </li>
+ * </ul>
+ *
+ * @link http://codex.wordpress.org/Template_Tags/wp_list_authors
+ * @since 1.2.0
+ * @param array $args The argument array.
+ * @return null|string The output, if echo is set to false.
+ */
+function wp_list_authors($args = '') {
+ global $wpdb;
+
+ $defaults = array(
+ 'orderby' => 'name', 'order' => 'ASC', 'number' => '',
+ 'optioncount' => false, 'exclude_admin' => true,
+ 'show_fullname' => false, 'hide_empty' => true,
+ 'feed' => '', 'feed_image' => '', 'feed_type' => '', 'echo' => true,
+ 'style' => 'list', 'html' => true
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+ extract( $args, EXTR_SKIP );
+
+ $return = '';
+
+ $query_args = wp_array_slice_assoc( $args, array( 'orderby', 'order', 'number' ) );
+ $query_args['fields'] = 'ids';
+ $authors = get_users( $query_args );
+
+ $author_count = array();
+ foreach ( (array) $wpdb->get_results("SELECT DISTINCT post_author, COUNT(ID) AS count FROM $wpdb->posts WHERE post_type = 'post' AND " . get_private_posts_cap_sql( 'post' ) . " GROUP BY post_author") as $row )
+ $author_count[$row->post_author] = $row->count;
+
+ foreach ( $authors as $author_id ) {
+ $author = get_userdata( $author_id );
+
+ if ( $exclude_admin && 'admin' == $author->display_name )
+ continue;
+
+ $posts = isset( $author_count[$author->ID] ) ? $author_count[$author->ID] : 0;
+
+ if ( !$posts && $hide_empty )
+ continue;
+
+ $link = '';
+
+ if ( $show_fullname && $author->first_name && $author->last_name )
+ $name = "$author->first_name $author->last_name";
+ else
+ $name = $author->display_name;
+
+ if ( !$html ) {
+ $return .= $name . ', ';
+
+ continue; // No need to go further to process HTML.
+ }
+
+ if ( 'list' == $style ) {
+ $return .= '<li>';
+ }
+
+ $link = '<a href="' . get_author_posts_url( $author->ID, $author->user_nicename ) . '" title="' . esc_attr( sprintf(__("Posts by %s"), $author->display_name) ) . '">' . $name . '</a>';
+
+ if ( !empty( $feed_image ) || !empty( $feed ) ) {
+ $link .= ' ';
+ if ( empty( $feed_image ) ) {
+ $link .= '(';
+ }
+
+ $link .= '<a href="' . get_author_feed_link( $author->ID ) . '"';
+
+ $alt = $title = '';
+ if ( !empty( $feed ) ) {
+ $title = ' title="' . esc_attr( $feed ) . '"';
+ $alt = ' alt="' . esc_attr( $feed ) . '"';
+ $name = $feed;
+ $link .= $title;
+ }
+
+ $link .= '>';
+
+ if ( !empty( $feed_image ) )
+ $link .= '<img src="' . esc_url( $feed_image ) . '" style="border: none;"' . $alt . $title . ' />';
+ else
+ $link .= $name;
+
+ $link .= '</a>';
+
+ if ( empty( $feed_image ) )
+ $link .= ')';
+ }
+
+ if ( $optioncount )
+ $link .= ' ('. $posts . ')';
+
+ $return .= $link;
+ $return .= ( 'list' == $style ) ? '</li>' : ', ';
+ }
+
+ $return = rtrim($return, ', ');
+
+ if ( !$echo )
+ return $return;
+
+ echo $return;
+}
+
+/**
+ * Does this site have more than one author
+ *
+ * Checks to see if more than one author has published posts.
+ *
+ * @since 3.2.0
+ * @return bool Whether or not we have more than one author
+ */
+function is_multi_author() {
+ global $wpdb;
+
+ if ( false === ( $is_multi_author = get_transient( 'is_multi_author' ) ) ) {
+ $rows = (array) $wpdb->get_col("SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' LIMIT 2");
+ $is_multi_author = 1 < count( $rows ) ? 1 : 0;
+ set_transient( 'is_multi_author', $is_multi_author );
+ }
+
+ return apply_filters( 'is_multi_author', (bool) $is_multi_author );
+}
+
+/**
+ * Helper function to clear the cache for number of authors.
+ *
+ * @private
+ */
+function __clear_multi_author_cache() {
+ delete_transient( 'is_multi_author' );
+}
+add_action('transition_post_status', '__clear_multi_author_cache');
diff --git a/src/wp-includes/bookmark-template.php b/src/wp-includes/bookmark-template.php
new file mode 100644
index 0000000000..cb30b896a9
--- /dev/null
+++ b/src/wp-includes/bookmark-template.php
@@ -0,0 +1,257 @@
+<?php
+/**
+ * Bookmark Template Functions for usage in Themes
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * The formatted output of a list of bookmarks.
+ *
+ * The $bookmarks array must contain bookmark objects and will be iterated over
+ * to retrieve the bookmark to be used in the output.
+ *
+ * The output is formatted as HTML with no way to change that format. However,
+ * what is between, before, and after can be changed. The link itself will be
+ * HTML.
+ *
+ * This function is used internally by wp_list_bookmarks() and should not be
+ * used by themes.
+ *
+ * The defaults for overwriting are:
+ * 'show_updated' - Default is 0 (integer). Will show the time of when the
+ * bookmark was last updated.
+ * 'show_description' - Default is 0 (integer). Whether to show the description
+ * of the bookmark.
+ * 'show_images' - Default is 1 (integer). Whether to show link image if
+ * available.
+ * 'show_name' - Default is 0 (integer). Whether to show link name if
+ * available.
+ * 'before' - Default is '<li>' (string). The html or text to prepend to each
+ * bookmarks.
+ * 'after' - Default is '</li>' (string). The html or text to append to each
+ * bookmarks.
+ * 'link_before' - Default is '' (string). The html or text to prepend to each
+ * bookmarks inside the <a> tag.
+ * 'link_after' - Default is '' (string). The html or text to append to each
+ * bookmarks inside the <a> tag.
+ * 'between' - Default is '\n' (string). The string for use in between the link,
+ * description, and image.
+ * 'show_rating' - Default is 0 (integer). Whether to show the link rating.
+ *
+ * @since 2.1.0
+ * @access private
+ *
+ * @param array $bookmarks List of bookmarks to traverse
+ * @param string|array $args Optional. Overwrite the defaults.
+ * @return string Formatted output in HTML
+ */
+function _walk_bookmarks($bookmarks, $args = '' ) {
+ $defaults = array(
+ 'show_updated' => 0, 'show_description' => 0,
+ 'show_images' => 1, 'show_name' => 0,
+ 'before' => '<li>', 'after' => '</li>', 'between' => "\n",
+ 'show_rating' => 0, 'link_before' => '', 'link_after' => ''
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $output = ''; // Blank string to start with.
+
+ foreach ( (array) $bookmarks as $bookmark ) {
+ if ( !isset($bookmark->recently_updated) )
+ $bookmark->recently_updated = false;
+ $output .= $before;
+ if ( $show_updated && $bookmark->recently_updated )
+ $output .= get_option('links_recently_updated_prepend');
+
+ $the_link = '#';
+ if ( !empty($bookmark->link_url) )
+ $the_link = esc_url($bookmark->link_url);
+
+ $desc = esc_attr(sanitize_bookmark_field('link_description', $bookmark->link_description, $bookmark->link_id, 'display'));
+ $name = esc_attr(sanitize_bookmark_field('link_name', $bookmark->link_name, $bookmark->link_id, 'display'));
+ $title = $desc;
+
+ if ( $show_updated )
+ if ( '00' != substr($bookmark->link_updated_f, 0, 2) ) {
+ $title .= ' (';
+ $title .= sprintf(__('Last updated: %s'), date(get_option('links_updated_date_format'), $bookmark->link_updated_f + (get_option('gmt_offset') * HOUR_IN_SECONDS)));
+ $title .= ')';
+ }
+
+ $alt = ' alt="' . $name . ( $show_description ? ' ' . $title : '' ) . '"';
+
+ if ( '' != $title )
+ $title = ' title="' . $title . '"';
+
+ $rel = $bookmark->link_rel;
+ if ( '' != $rel )
+ $rel = ' rel="' . esc_attr($rel) . '"';
+
+ $target = $bookmark->link_target;
+ if ( '' != $target )
+ $target = ' target="' . $target . '"';
+
+ $output .= '<a href="' . $the_link . '"' . $rel . $title . $target . '>';
+
+ $output .= $link_before;
+
+ if ( $bookmark->link_image != null && $show_images ) {
+ if ( strpos($bookmark->link_image, 'http') === 0 )
+ $output .= "<img src=\"$bookmark->link_image\" $alt $title />";
+ else // If it's a relative path
+ $output .= "<img src=\"" . get_option('siteurl') . "$bookmark->link_image\" $alt $title />";
+
+ if ( $show_name )
+ $output .= " $name";
+ } else {
+ $output .= $name;
+ }
+
+ $output .= $link_after;
+
+ $output .= '</a>';
+
+ if ( $show_updated && $bookmark->recently_updated )
+ $output .= get_option('links_recently_updated_append');
+
+ if ( $show_description && '' != $desc )
+ $output .= $between . $desc;
+
+ if ( $show_rating )
+ $output .= $between . sanitize_bookmark_field('link_rating', $bookmark->link_rating, $bookmark->link_id, 'display');
+
+ $output .= "$after\n";
+ } // end while
+
+ return $output;
+}
+
+/**
+ * Retrieve or echo all of the bookmarks.
+ *
+ * List of default arguments are as follows:
+ * 'orderby' - Default is 'name' (string). How to order the links by. String is
+ * based off of the bookmark scheme.
+ * 'order' - Default is 'ASC' (string). Either 'ASC' or 'DESC'. Orders in either
+ * ascending or descending order.
+ * 'limit' - Default is -1 (integer) or show all. The amount of bookmarks to
+ * display.
+ * 'category' - Default is empty string (string). Include the links in what
+ * category ID(s).
+ * 'category_name' - Default is empty string (string). Get links by category
+ * name.
+ * 'hide_invisible' - Default is 1 (integer). Whether to show (default) or hide
+ * links marked as 'invisible'.
+ * 'show_updated' - Default is 0 (integer). Will show the time of when the
+ * bookmark was last updated.
+ * 'echo' - Default is 1 (integer). Whether to echo (default) or return the
+ * formatted bookmarks.
+ * 'categorize' - Default is 1 (integer). Whether to show links listed by
+ * category (default) or show links in one column.
+ * 'show_description' - Default is 0 (integer). Whether to show the description
+ * of the bookmark.
+ *
+ * These options define how the Category name will appear before the category
+ * links are displayed, if 'categorize' is 1. If 'categorize' is 0, then it will
+ * display for only the 'title_li' string and only if 'title_li' is not empty.
+ * 'title_li' - Default is 'Bookmarks' (translatable string). What to show
+ * before the links appear.
+ * 'title_before' - Default is '<h2>' (string). The HTML or text to show before
+ * the 'title_li' string.
+ * 'title_after' - Default is '</h2>' (string). The HTML or text to show after
+ * the 'title_li' string.
+ * 'class' - Default is 'linkcat' (string). The CSS class to use for the
+ * 'title_li'.
+ *
+ * 'category_before' - Default is '<li id="%id" class="%class">'. String must
+ * contain '%id' and '%class' to get
+ * the id of the category and the 'class' argument. These are used for
+ * formatting in themes.
+ * Argument will be displayed before the 'title_before' argument.
+ * 'category_after' - Default is '</li>' (string). The HTML or text that will
+ * appear after the list of links.
+ *
+ * These are only used if 'categorize' is set to 1 or true.
+ * 'category_orderby' - Default is 'name'. How to order the bookmark category
+ * based on term scheme.
+ * 'category_order' - Default is 'ASC'. Set the order by either ASC (ascending)
+ * or DESC (descending).
+ *
+ * @see _walk_bookmarks() For other arguments that can be set in this function
+ * and passed to _walk_bookmarks().
+ * @see get_bookmarks() For other arguments that can be set in this function and
+ * passed to get_bookmarks().
+ * @link http://codex.wordpress.org/Template_Tags/wp_list_bookmarks
+ *
+ * @since 2.1.0
+ * @uses _walk_bookmarks() Used to iterate over all of the bookmarks and return
+ * the html
+ * @uses get_terms() Gets all of the categories that are for links.
+ *
+ * @param string|array $args Optional. Overwrite the defaults of the function
+ * @return string|null Will only return if echo option is set to not echo.
+ * Default is not return anything.
+ */
+function wp_list_bookmarks($args = '') {
+ $defaults = array(
+ 'orderby' => 'name', 'order' => 'ASC',
+ 'limit' => -1, 'category' => '', 'exclude_category' => '',
+ 'category_name' => '', 'hide_invisible' => 1,
+ 'show_updated' => 0, 'echo' => 1,
+ 'categorize' => 1, 'title_li' => __('Bookmarks'),
+ 'title_before' => '<h2>', 'title_after' => '</h2>',
+ 'category_orderby' => 'name', 'category_order' => 'ASC',
+ 'class' => 'linkcat', 'category_before' => '<li id="%id" class="%class">',
+ 'category_after' => '</li>'
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $output = '';
+
+ if ( $categorize ) {
+ $cats = get_terms( 'link_category', array( 'name__like' => $category_name, 'include' => $category, 'exclude' => $exclude_category, 'orderby' => $category_orderby, 'order' => $category_order, 'hierarchical' => 0 ) );
+ if ( empty( $cats ) )
+ $categorize = false;
+ }
+
+ if ( $categorize ) {
+ // Split the bookmarks into ul's for each category
+ foreach ( (array) $cats as $cat ) {
+ $params = array_merge($r, array('category'=>$cat->term_id));
+ $bookmarks = get_bookmarks($params);
+ if ( empty($bookmarks) )
+ continue;
+ $output .= str_replace(array('%id', '%class'), array("linkcat-$cat->term_id", $class), $category_before);
+ $catname = apply_filters( "link_category", $cat->name );
+ $output .= "$title_before$catname$title_after\n\t<ul class='xoxo blogroll'>\n";
+ $output .= _walk_bookmarks($bookmarks, $r);
+ $output .= "\n\t</ul>\n$category_after\n";
+ }
+ } else {
+ //output one single list using title_li for the title
+ $bookmarks = get_bookmarks($r);
+
+ if ( !empty($bookmarks) ) {
+ if ( !empty( $title_li ) ){
+ $output .= str_replace(array('%id', '%class'), array("linkcat-$category", $class), $category_before);
+ $output .= "$title_before$title_li$title_after\n\t<ul class='xoxo blogroll'>\n";
+ $output .= _walk_bookmarks($bookmarks, $r);
+ $output .= "\n\t</ul>\n$category_after\n";
+ } else {
+ $output .= _walk_bookmarks($bookmarks, $r);
+ }
+ }
+ }
+
+ $output = apply_filters( 'wp_list_bookmarks', $output );
+
+ if ( !$echo )
+ return $output;
+ echo $output;
+}
diff --git a/src/wp-includes/bookmark.php b/src/wp-includes/bookmark.php
new file mode 100644
index 0000000000..9a3ac6107c
--- /dev/null
+++ b/src/wp-includes/bookmark.php
@@ -0,0 +1,387 @@
+<?php
+/**
+ * Link/Bookmark API
+ *
+ * @package WordPress
+ * @subpackage Bookmark
+ */
+
+/**
+ * Retrieve Bookmark data
+ *
+ * @since 2.1.0
+ * @uses $wpdb Database Object
+ *
+ * @param mixed $bookmark
+ * @param string $output Optional. Either OBJECT, ARRAY_N, or ARRAY_A constant
+ * @param string $filter Optional, default is 'raw'.
+ * @return array|object Type returned depends on $output value.
+ */
+function get_bookmark($bookmark, $output = OBJECT, $filter = 'raw') {
+ global $wpdb;
+
+ if ( empty($bookmark) ) {
+ if ( isset($GLOBALS['link']) )
+ $_bookmark = & $GLOBALS['link'];
+ else
+ $_bookmark = null;
+ } elseif ( is_object($bookmark) ) {
+ wp_cache_add($bookmark->link_id, $bookmark, 'bookmark');
+ $_bookmark = $bookmark;
+ } else {
+ if ( isset($GLOBALS['link']) && ($GLOBALS['link']->link_id == $bookmark) ) {
+ $_bookmark = & $GLOBALS['link'];
+ } elseif ( ! $_bookmark = wp_cache_get($bookmark, 'bookmark') ) {
+ $_bookmark = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->links WHERE link_id = %d LIMIT 1", $bookmark));
+ if ( $_bookmark ) {
+ $_bookmark->link_category = array_unique( wp_get_object_terms( $_bookmark->link_id, 'link_category', array( 'fields' => 'ids' ) ) );
+ wp_cache_add( $_bookmark->link_id, $_bookmark, 'bookmark' );
+ }
+ }
+ }
+
+ if ( ! $_bookmark )
+ return $_bookmark;
+
+ $_bookmark = sanitize_bookmark($_bookmark, $filter);
+
+ if ( $output == OBJECT ) {
+ return $_bookmark;
+ } elseif ( $output == ARRAY_A ) {
+ return get_object_vars($_bookmark);
+ } elseif ( $output == ARRAY_N ) {
+ return array_values(get_object_vars($_bookmark));
+ } else {
+ return $_bookmark;
+ }
+}
+
+/**
+ * Retrieve single bookmark data item or field.
+ *
+ * @since 2.3.0
+ * @uses get_bookmark() Gets bookmark object using $bookmark as ID
+ * @uses sanitize_bookmark_field() Sanitizes Bookmark field based on $context.
+ *
+ * @param string $field The name of the data field to return
+ * @param int $bookmark The bookmark ID to get field
+ * @param string $context Optional. The context of how the field will be used.
+ * @return string
+ */
+function get_bookmark_field( $field, $bookmark, $context = 'display' ) {
+ $bookmark = (int) $bookmark;
+ $bookmark = get_bookmark( $bookmark );
+
+ if ( is_wp_error($bookmark) )
+ return $bookmark;
+
+ if ( !is_object($bookmark) )
+ return '';
+
+ if ( !isset($bookmark->$field) )
+ return '';
+
+ return sanitize_bookmark_field($field, $bookmark->$field, $bookmark->link_id, $context);
+}
+
+/**
+ * Retrieves the list of bookmarks
+ *
+ * Attempts to retrieve from the cache first based on MD5 hash of arguments. If
+ * that fails, then the query will be built from the arguments and executed. The
+ * results will be stored to the cache.
+ *
+ * List of default arguments are as follows:
+ * 'orderby' - Default is 'name' (string). How to order the links by. String is
+ * based off of the bookmark scheme.
+ * 'order' - Default is 'ASC' (string). Either 'ASC' or 'DESC'. Orders in either
+ * ascending or descending order.
+ * 'limit' - Default is -1 (integer) or show all. The amount of bookmarks to
+ * display.
+ * 'category' - Default is empty string (string). Include the links in what
+ * category ID(s).
+ * 'category_name' - Default is empty string (string). Get links by category
+ * name.
+ * 'hide_invisible' - Default is 1 (integer). Whether to show (default) or hide
+ * links marked as 'invisible'.
+ * 'show_updated' - Default is 0 (integer). Will show the time of when the
+ * bookmark was last updated.
+ * 'include' - Default is empty string (string). Include bookmark ID(s)
+ * separated by commas.
+ * 'exclude' - Default is empty string (string). Exclude bookmark ID(s)
+ * separated by commas.
+ *
+ * @since 2.1.0
+ * @uses $wpdb Database Object
+ * @link http://codex.wordpress.org/Template_Tags/get_bookmarks
+ *
+ * @param string|array $args List of arguments to overwrite the defaults
+ * @return array List of bookmark row objects
+ */
+function get_bookmarks($args = '') {
+ global $wpdb;
+
+ $defaults = array(
+ 'orderby' => 'name', 'order' => 'ASC',
+ 'limit' => -1, 'category' => '',
+ 'category_name' => '', 'hide_invisible' => 1,
+ 'show_updated' => 0, 'include' => '',
+ 'exclude' => '', 'search' => ''
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $cache = array();
+ $key = md5( serialize( $r ) );
+ if ( $cache = wp_cache_get( 'get_bookmarks', 'bookmark' ) ) {
+ if ( is_array($cache) && isset( $cache[ $key ] ) )
+ return apply_filters('get_bookmarks', $cache[ $key ], $r );
+ }
+
+ if ( !is_array($cache) )
+ $cache = array();
+
+ $inclusions = '';
+ if ( !empty($include) ) {
+ $exclude = ''; //ignore exclude, category, and category_name params if using include
+ $category = '';
+ $category_name = '';
+ $inclinks = preg_split('/[\s,]+/',$include);
+ if ( count($inclinks) ) {
+ foreach ( $inclinks as $inclink ) {
+ if (empty($inclusions))
+ $inclusions = ' AND ( link_id = ' . intval($inclink) . ' ';
+ else
+ $inclusions .= ' OR link_id = ' . intval($inclink) . ' ';
+ }
+ }
+ }
+ if (!empty($inclusions))
+ $inclusions .= ')';
+
+ $exclusions = '';
+ if ( !empty($exclude) ) {
+ $exlinks = preg_split('/[\s,]+/',$exclude);
+ if ( count($exlinks) ) {
+ foreach ( $exlinks as $exlink ) {
+ if (empty($exclusions))
+ $exclusions = ' AND ( link_id <> ' . intval($exlink) . ' ';
+ else
+ $exclusions .= ' AND link_id <> ' . intval($exlink) . ' ';
+ }
+ }
+ }
+ if (!empty($exclusions))
+ $exclusions .= ')';
+
+ if ( !empty($category_name) ) {
+ if ( $category = get_term_by('name', $category_name, 'link_category') ) {
+ $category = $category->term_id;
+ } else {
+ $cache[ $key ] = array();
+ wp_cache_set( 'get_bookmarks', $cache, 'bookmark' );
+ return apply_filters( 'get_bookmarks', array(), $r );
+ }
+ }
+
+ if ( ! empty($search) ) {
+ $search = esc_sql( like_escape( $search ) );
+ $search = " AND ( (link_url LIKE '%$search%') OR (link_name LIKE '%$search%') OR (link_description LIKE '%$search%') ) ";
+ }
+
+ $category_query = '';
+ $join = '';
+ if ( !empty($category) ) {
+ $incategories = preg_split('/[\s,]+/',$category);
+ if ( count($incategories) ) {
+ foreach ( $incategories as $incat ) {
+ if (empty($category_query))
+ $category_query = ' AND ( tt.term_id = ' . intval($incat) . ' ';
+ else
+ $category_query .= ' OR tt.term_id = ' . intval($incat) . ' ';
+ }
+ }
+ }
+ if (!empty($category_query)) {
+ $category_query .= ") AND taxonomy = 'link_category'";
+ $join = " INNER JOIN $wpdb->term_relationships AS tr ON ($wpdb->links.link_id = tr.object_id) INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_taxonomy_id = tr.term_taxonomy_id";
+ }
+
+ if ( $show_updated && get_option('links_recently_updated_time') ) {
+ $recently_updated_test = ", IF (DATE_ADD(link_updated, INTERVAL " . get_option('links_recently_updated_time') . " MINUTE) >= NOW(), 1,0) as recently_updated ";
+ } else {
+ $recently_updated_test = '';
+ }
+
+ $get_updated = ( $show_updated ) ? ', UNIX_TIMESTAMP(link_updated) AS link_updated_f ' : '';
+
+ $orderby = strtolower($orderby);
+ $length = '';
+ switch ( $orderby ) {
+ case 'length':
+ $length = ", CHAR_LENGTH(link_name) AS length";
+ break;
+ case 'rand':
+ $orderby = 'rand()';
+ break;
+ case 'link_id':
+ $orderby = "$wpdb->links.link_id";
+ break;
+ default:
+ $orderparams = array();
+ foreach ( explode(',', $orderby) as $ordparam ) {
+ $ordparam = trim($ordparam);
+ $keys = array( 'link_id', 'link_name', 'link_url', 'link_visible', 'link_rating', 'link_owner', 'link_updated', 'link_notes' );
+ if ( in_array( 'link_' . $ordparam, $keys ) )
+ $orderparams[] = 'link_' . $ordparam;
+ elseif ( in_array( $ordparam, $keys ) )
+ $orderparams[] = $ordparam;
+ }
+ $orderby = implode(',', $orderparams);
+ }
+
+ if ( empty( $orderby ) )
+ $orderby = 'link_name';
+
+ $order = strtoupper( $order );
+ if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) )
+ $order = 'ASC';
+
+ $visible = '';
+ if ( $hide_invisible )
+ $visible = "AND link_visible = 'Y'";
+
+ $query = "SELECT * $length $recently_updated_test $get_updated FROM $wpdb->links $join WHERE 1=1 $visible $category_query";
+ $query .= " $exclusions $inclusions $search";
+ $query .= " ORDER BY $orderby $order";
+ if ($limit != -1)
+ $query .= " LIMIT $limit";
+
+ $results = $wpdb->get_results($query);
+
+ $cache[ $key ] = $results;
+ wp_cache_set( 'get_bookmarks', $cache, 'bookmark' );
+
+ return apply_filters('get_bookmarks', $results, $r);
+}
+
+/**
+ * Sanitizes all bookmark fields
+ *
+ * @since 2.3.0
+ *
+ * @param object|array $bookmark Bookmark row
+ * @param string $context Optional, default is 'display'. How to filter the
+ * fields
+ * @return object|array Same type as $bookmark but with fields sanitized.
+ */
+function sanitize_bookmark($bookmark, $context = 'display') {
+ $fields = array('link_id', 'link_url', 'link_name', 'link_image', 'link_target', 'link_category',
+ 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_updated',
+ 'link_rel', 'link_notes', 'link_rss', );
+
+ if ( is_object($bookmark) ) {
+ $do_object = true;
+ $link_id = $bookmark->link_id;
+ } else {
+ $do_object = false;
+ $link_id = $bookmark['link_id'];
+ }
+
+ foreach ( $fields as $field ) {
+ if ( $do_object ) {
+ if ( isset($bookmark->$field) )
+ $bookmark->$field = sanitize_bookmark_field($field, $bookmark->$field, $link_id, $context);
+ } else {
+ if ( isset($bookmark[$field]) )
+ $bookmark[$field] = sanitize_bookmark_field($field, $bookmark[$field], $link_id, $context);
+ }
+ }
+
+ return $bookmark;
+}
+
+/**
+ * Sanitizes a bookmark field
+ *
+ * Sanitizes the bookmark fields based on what the field name is. If the field
+ * has a strict value set, then it will be tested for that, else a more generic
+ * filtering is applied. After the more strict filter is applied, if the
+ * $context is 'raw' then the value is immediately return.
+ *
+ * Hooks exist for the more generic cases. With the 'edit' context, the
+ * 'edit_$field' filter will be called and passed the $value and $bookmark_id
+ * respectively. With the 'db' context, the 'pre_$field' filter is called and
+ * passed the value. The 'display' context is the final context and has the
+ * $field has the filter name and is passed the $value, $bookmark_id, and
+ * $context respectively.
+ *
+ * @since 2.3.0
+ *
+ * @param string $field The bookmark field
+ * @param mixed $value The bookmark field value
+ * @param int $bookmark_id Bookmark ID
+ * @param string $context How to filter the field value. Either 'raw', 'edit',
+ * 'attribute', 'js', 'db', or 'display'
+ * @return mixed The filtered value
+ */
+function sanitize_bookmark_field($field, $value, $bookmark_id, $context) {
+ switch ( $field ) {
+ case 'link_id' : // ints
+ case 'link_rating' :
+ $value = (int) $value;
+ break;
+ case 'link_category' : // array( ints )
+ $value = array_map('absint', (array) $value);
+ // We return here so that the categories aren't filtered.
+ // The 'link_category' filter is for the name of a link category, not an array of a link's link categories
+ return $value;
+ break;
+ case 'link_visible' : // bool stored as Y|N
+ $value = preg_replace('/[^YNyn]/', '', $value);
+ break;
+ case 'link_target' : // "enum"
+ $targets = array('_top', '_blank');
+ if ( ! in_array($value, $targets) )
+ $value = '';
+ break;
+ }
+
+ if ( 'raw' == $context )
+ return $value;
+
+ if ( 'edit' == $context ) {
+ $value = apply_filters("edit_$field", $value, $bookmark_id);
+
+ if ( 'link_notes' == $field ) {
+ $value = esc_html( $value ); // textarea_escaped
+ } else {
+ $value = esc_attr($value);
+ }
+ } else if ( 'db' == $context ) {
+ $value = apply_filters("pre_$field", $value);
+ } else {
+ // Use display filters by default.
+ $value = apply_filters($field, $value, $bookmark_id, $context);
+
+ if ( 'attribute' == $context )
+ $value = esc_attr($value);
+ else if ( 'js' == $context )
+ $value = esc_js($value);
+ }
+
+ return $value;
+}
+
+/**
+ * Deletes bookmark cache
+ *
+ * @since 2.7.0
+ * @uses wp_cache_delete() Deletes the contents of 'get_bookmarks'
+ */
+function clean_bookmark_cache( $bookmark_id ) {
+ wp_cache_delete( $bookmark_id, 'bookmark' );
+ wp_cache_delete( 'get_bookmarks', 'bookmark' );
+ clean_object_term_cache( $bookmark_id, 'link');
+}
diff --git a/src/wp-includes/cache.php b/src/wp-includes/cache.php
new file mode 100644
index 0000000000..af1c2adac9
--- /dev/null
+++ b/src/wp-includes/cache.php
@@ -0,0 +1,653 @@
+<?php
+/**
+ * Object Cache API
+ *
+ * @link http://codex.wordpress.org/Function_Reference/WP_Cache
+ *
+ * @package WordPress
+ * @subpackage Cache
+ */
+
+/**
+ * Adds data to the cache, if the cache key doesn't already exist.
+ *
+ * @since 2.0.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::add()
+ *
+ * @param int|string $key The cache key to use for retrieval later
+ * @param mixed $data The data to add to the cache store
+ * @param string $group The group to add the cache to
+ * @param int $expire When the cache data should be expired
+ * @return bool False if cache key and group already exist, true on success
+ */
+function wp_cache_add($key, $data, $group = '', $expire = 0) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->add($key, $data, $group, $expire);
+}
+
+/**
+ * Closes the cache.
+ *
+ * This function has ceased to do anything since WordPress 2.5. The
+ * functionality was removed along with the rest of the persistent cache. This
+ * does not mean that plugins can't implement this function when they need to
+ * make sure that the cache is cleaned up after WordPress no longer needs it.
+ *
+ * @since 2.0.0
+ *
+ * @return bool Always returns True
+ */
+function wp_cache_close() {
+ return true;
+}
+
+/**
+ * Decrement numeric cache item's value
+ *
+ * @since 3.3.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::decr()
+ *
+ * @param int|string $key The cache key to increment
+ * @param int $offset The amount by which to decrement the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return false|int False on failure, the item's new value on success.
+ */
+function wp_cache_decr( $key, $offset = 1, $group = '' ) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->decr( $key, $offset, $group );
+}
+
+/**
+ * Removes the cache contents matching key and group.
+ *
+ * @since 2.0.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::delete()
+ *
+ * @param int|string $key What the contents in the cache are called
+ * @param string $group Where the cache contents are grouped
+ * @return bool True on successful removal, false on failure
+ */
+function wp_cache_delete($key, $group = '') {
+ global $wp_object_cache;
+
+ return $wp_object_cache->delete($key, $group);
+}
+
+/**
+ * Removes all cache items.
+ *
+ * @since 2.0.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::flush()
+ *
+ * @return bool False on failure, true on success
+ */
+function wp_cache_flush() {
+ global $wp_object_cache;
+
+ return $wp_object_cache->flush();
+}
+
+/**
+ * Retrieves the cache contents from the cache by key and group.
+ *
+ * @since 2.0.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::get()
+ *
+ * @param int|string $key What the contents in the cache are called
+ * @param string $group Where the cache contents are grouped
+ * @param bool $force Whether to force an update of the local cache from the persistent cache (default is false)
+ * @param &bool $found Whether key was found in the cache. Disambiguates a return of false, a storable value.
+ * @return bool|mixed False on failure to retrieve contents or the cache
+ * contents on success
+ */
+function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->get( $key, $group, $force, $found );
+}
+
+/**
+ * Increment numeric cache item's value
+ *
+ * @since 3.3.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::incr()
+ *
+ * @param int|string $key The cache key to increment
+ * @param int $offset The amount by which to increment the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return false|int False on failure, the item's new value on success.
+ */
+function wp_cache_incr( $key, $offset = 1, $group = '' ) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->incr( $key, $offset, $group );
+}
+
+/**
+ * Sets up Object Cache Global and assigns it.
+ *
+ * @since 2.0.0
+ * @global WP_Object_Cache $wp_object_cache WordPress Object Cache
+ */
+function wp_cache_init() {
+ $GLOBALS['wp_object_cache'] = new WP_Object_Cache();
+}
+
+/**
+ * Replaces the contents of the cache with new data.
+ *
+ * @since 2.0.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::replace()
+ *
+ * @param int|string $key What to call the contents in the cache
+ * @param mixed $data The contents to store in the cache
+ * @param string $group Where to group the cache contents
+ * @param int $expire When to expire the cache contents
+ * @return bool False if not exists, true if contents were replaced
+ */
+function wp_cache_replace($key, $data, $group = '', $expire = 0) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->replace($key, $data, $group, $expire);
+}
+
+/**
+ * Saves the data to the cache.
+ *
+ * @since 2.0
+ * @uses $wp_object_cache Object Cache Class
+ * @see WP_Object_Cache::set()
+ *
+ * @param int|string $key What to call the contents in the cache
+ * @param mixed $data The contents to store in the cache
+ * @param string $group Where to group the cache contents
+ * @param int $expire When to expire the cache contents
+ * @return bool False on failure, true on success
+ */
+function wp_cache_set($key, $data, $group = '', $expire = 0) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->set($key, $data, $group, $expire);
+}
+
+/**
+ * Switch the interal blog id.
+ *
+ * This changes the blog id used to create keys in blog specific groups.
+ *
+ * @since 3.5.0
+ *
+ * @param int $blog_id Blog ID
+ */
+function wp_cache_switch_to_blog( $blog_id ) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->switch_to_blog( $blog_id );
+}
+
+/**
+ * Adds a group or set of groups to the list of global groups.
+ *
+ * @since 2.6.0
+ *
+ * @param string|array $groups A group or an array of groups to add
+ */
+function wp_cache_add_global_groups( $groups ) {
+ global $wp_object_cache;
+
+ return $wp_object_cache->add_global_groups( $groups );
+}
+
+/**
+ * Adds a group or set of groups to the list of non-persistent groups.
+ *
+ * @since 2.6.0
+ *
+ * @param string|array $groups A group or an array of groups to add
+ */
+function wp_cache_add_non_persistent_groups( $groups ) {
+ // Default cache doesn't persist so nothing to do here.
+ return;
+}
+
+/**
+ * Reset internal cache keys and structures. If the cache backend uses global
+ * blog or site IDs as part of its cache keys, this function instructs the
+ * backend to reset those keys and perform any cleanup since blog or site IDs
+ * have changed since cache init.
+ *
+ * This function is deprecated. Use wp_cache_switch_to_blog() instead of this
+ * function when preparing the cache for a blog switch. For clearing the cache
+ * during unit tests, consider using wp_cache_init(). wp_cache_init() is not
+ * recommended outside of unit tests as the performance penality for using it is
+ * high.
+ *
+ * @since 2.6.0
+ * @deprecated 3.5.0
+ */
+function wp_cache_reset() {
+ _deprecated_function( __FUNCTION__, '3.5' );
+
+ global $wp_object_cache;
+
+ return $wp_object_cache->reset();
+}
+
+/**
+ * WordPress Object Cache
+ *
+ * The WordPress Object Cache is used to save on trips to the database. The
+ * Object Cache stores all of the cache data to memory and makes the cache
+ * contents available by using a key, which is used to name and later retrieve
+ * the cache contents.
+ *
+ * The Object Cache can be replaced by other caching mechanisms by placing files
+ * in the wp-content folder which is looked at in wp-settings. If that file
+ * exists, then this file will not be included.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 2.0
+ */
+class WP_Object_Cache {
+
+ /**
+ * Holds the cached objects
+ *
+ * @var array
+ * @access private
+ * @since 2.0.0
+ */
+ var $cache = array ();
+
+ /**
+ * The amount of times the cache data was already stored in the cache.
+ *
+ * @since 2.5.0
+ * @access private
+ * @var int
+ */
+ var $cache_hits = 0;
+
+ /**
+ * Amount of times the cache did not have the request in cache
+ *
+ * @var int
+ * @access public
+ * @since 2.0.0
+ */
+ var $cache_misses = 0;
+
+ /**
+ * List of global groups
+ *
+ * @var array
+ * @access protected
+ * @since 3.0.0
+ */
+ var $global_groups = array();
+
+ /**
+ * The blog prefix to prepend to keys in non-global groups.
+ *
+ * @var int
+ * @access private
+ * @since 3.5.0
+ */
+ var $blog_prefix;
+
+ /**
+ * Adds data to the cache if it doesn't already exist.
+ *
+ * @uses WP_Object_Cache::_exists Checks to see if the cache already has data.
+ * @uses WP_Object_Cache::set Sets the data after the checking the cache
+ * contents existence.
+ *
+ * @since 2.0.0
+ *
+ * @param int|string $key What to call the contents in the cache
+ * @param mixed $data The contents to store in the cache
+ * @param string $group Where to group the cache contents
+ * @param int $expire When to expire the cache contents
+ * @return bool False if cache key and group already exist, true on success
+ */
+ function add( $key, $data, $group = 'default', $expire = '' ) {
+ if ( wp_suspend_cache_addition() )
+ return false;
+
+ if ( empty( $group ) )
+ $group = 'default';
+
+ $id = $key;
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $id = $this->blog_prefix . $key;
+
+ if ( $this->_exists( $id, $group ) )
+ return false;
+
+ return $this->set($key, $data, $group, $expire);
+ }
+
+ /**
+ * Sets the list of global groups.
+ *
+ * @since 3.0.0
+ *
+ * @param array $groups List of groups that are global.
+ */
+ function add_global_groups( $groups ) {
+ $groups = (array) $groups;
+
+ $groups = array_fill_keys( $groups, true );
+ $this->global_groups = array_merge( $this->global_groups, $groups );
+ }
+
+ /**
+ * Decrement numeric cache item's value
+ *
+ * @since 3.3.0
+ *
+ * @param int|string $key The cache key to increment
+ * @param int $offset The amount by which to decrement the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return false|int False on failure, the item's new value on success.
+ */
+ function decr( $key, $offset = 1, $group = 'default' ) {
+ if ( empty( $group ) )
+ $group = 'default';
+
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $key = $this->blog_prefix . $key;
+
+ if ( ! $this->_exists( $key, $group ) )
+ return false;
+
+ if ( ! is_numeric( $this->cache[ $group ][ $key ] ) )
+ $this->cache[ $group ][ $key ] = 0;
+
+ $offset = (int) $offset;
+
+ $this->cache[ $group ][ $key ] -= $offset;
+
+ if ( $this->cache[ $group ][ $key ] < 0 )
+ $this->cache[ $group ][ $key ] = 0;
+
+ return $this->cache[ $group ][ $key ];
+ }
+
+ /**
+ * Remove the contents of the cache key in the group
+ *
+ * If the cache key does not exist in the group and $force parameter is set
+ * to false, then nothing will happen. The $force parameter is set to false
+ * by default.
+ *
+ * @since 2.0.0
+ *
+ * @param int|string $key What the contents in the cache are called
+ * @param string $group Where the cache contents are grouped
+ * @param bool $force Optional. Whether to force the unsetting of the cache
+ * key in the group
+ * @return bool False if the contents weren't deleted and true on success
+ */
+ function delete($key, $group = 'default', $force = false) {
+ if ( empty( $group ) )
+ $group = 'default';
+
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $key = $this->blog_prefix . $key;
+
+ if ( ! $force && ! $this->_exists( $key, $group ) )
+ return false;
+
+ unset( $this->cache[$group][$key] );
+ return true;
+ }
+
+ /**
+ * Clears the object cache of all data
+ *
+ * @since 2.0.0
+ *
+ * @return bool Always returns true
+ */
+ function flush() {
+ $this->cache = array ();
+
+ return true;
+ }
+
+ /**
+ * Retrieves the cache contents, if it exists
+ *
+ * The contents will be first attempted to be retrieved by searching by the
+ * key in the cache group. If the cache is hit (success) then the contents
+ * are returned.
+ *
+ * On failure, the number of cache misses will be incremented.
+ *
+ * @since 2.0.0
+ *
+ * @param int|string $key What the contents in the cache are called
+ * @param string $group Where the cache contents are grouped
+ * @param string $force Whether to force a refetch rather than relying on the local cache (default is false)
+ * @return bool|mixed False on failure to retrieve contents or the cache
+ * contents on success
+ */
+ function get( $key, $group = 'default', $force = false, &$found = null ) {
+ if ( empty( $group ) )
+ $group = 'default';
+
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $key = $this->blog_prefix . $key;
+
+ if ( $this->_exists( $key, $group ) ) {
+ $found = true;
+ $this->cache_hits += 1;
+ if ( is_object($this->cache[$group][$key]) )
+ return clone $this->cache[$group][$key];
+ else
+ return $this->cache[$group][$key];
+ }
+
+ $found = false;
+ $this->cache_misses += 1;
+ return false;
+ }
+
+ /**
+ * Increment numeric cache item's value
+ *
+ * @since 3.3.0
+ *
+ * @param int|string $key The cache key to increment
+ * @param int $offset The amount by which to increment the item's value. Default is 1.
+ * @param string $group The group the key is in.
+ * @return false|int False on failure, the item's new value on success.
+ */
+ function incr( $key, $offset = 1, $group = 'default' ) {
+ if ( empty( $group ) )
+ $group = 'default';
+
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $key = $this->blog_prefix . $key;
+
+ if ( ! $this->_exists( $key, $group ) )
+ return false;
+
+ if ( ! is_numeric( $this->cache[ $group ][ $key ] ) )
+ $this->cache[ $group ][ $key ] = 0;
+
+ $offset = (int) $offset;
+
+ $this->cache[ $group ][ $key ] += $offset;
+
+ if ( $this->cache[ $group ][ $key ] < 0 )
+ $this->cache[ $group ][ $key ] = 0;
+
+ return $this->cache[ $group ][ $key ];
+ }
+
+ /**
+ * Replace the contents in the cache, if contents already exist
+ *
+ * @since 2.0.0
+ * @see WP_Object_Cache::set()
+ *
+ * @param int|string $key What to call the contents in the cache
+ * @param mixed $data The contents to store in the cache
+ * @param string $group Where to group the cache contents
+ * @param int $expire When to expire the cache contents
+ * @return bool False if not exists, true if contents were replaced
+ */
+ function replace( $key, $data, $group = 'default', $expire = '' ) {
+ if ( empty( $group ) )
+ $group = 'default';
+
+ $id = $key;
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $id = $this->blog_prefix . $key;
+
+ if ( ! $this->_exists( $id, $group ) )
+ return false;
+
+ return $this->set( $key, $data, $group, $expire );
+ }
+
+ /**
+ * Reset keys
+ *
+ * @since 3.0.0
+ * @deprecated 3.5.0
+ */
+ function reset() {
+ _deprecated_function( __FUNCTION__, '3.5', 'switch_to_blog()' );
+
+ // Clear out non-global caches since the blog ID has changed.
+ foreach ( array_keys( $this->cache ) as $group ) {
+ if ( ! isset( $this->global_groups[ $group ] ) )
+ unset( $this->cache[ $group ] );
+ }
+ }
+
+ /**
+ * Sets the data contents into the cache
+ *
+ * The cache contents is grouped by the $group parameter followed by the
+ * $key. This allows for duplicate ids in unique groups. Therefore, naming of
+ * the group should be used with care and should follow normal function
+ * naming guidelines outside of core WordPress usage.
+ *
+ * The $expire parameter is not used, because the cache will automatically
+ * expire for each time a page is accessed and PHP finishes. The method is
+ * more for cache plugins which use files.
+ *
+ * @since 2.0.0
+ *
+ * @param int|string $key What to call the contents in the cache
+ * @param mixed $data The contents to store in the cache
+ * @param string $group Where to group the cache contents
+ * @param int $expire Not Used
+ * @return bool Always returns true
+ */
+ function set($key, $data, $group = 'default', $expire = '') {
+ if ( empty( $group ) )
+ $group = 'default';
+
+ if ( $this->multisite && ! isset( $this->global_groups[ $group ] ) )
+ $key = $this->blog_prefix . $key;
+
+ if ( is_object( $data ) )
+ $data = clone $data;
+
+ $this->cache[$group][$key] = $data;
+ return true;
+ }
+
+ /**
+ * Echoes the stats of the caching.
+ *
+ * Gives the cache hits, and cache misses. Also prints every cached group,
+ * key and the data.
+ *
+ * @since 2.0.0
+ */
+ function stats() {
+ echo "<p>";
+ echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
+ echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
+ echo "</p>";
+ echo '<ul>';
+ foreach ($this->cache as $group => $cache) {
+ echo "<li><strong>Group:</strong> $group - ( " . number_format( strlen( serialize( $cache ) ) / 1024, 2 ) . 'k )</li>';
+ }
+ echo '</ul>';
+ }
+
+ /**
+ * Switch the interal blog id.
+ *
+ * This changes the blog id used to create keys in blog specific groups.
+ *
+ * @since 3.5.0
+ *
+ * @param int $blog_id Blog ID
+ */
+ function switch_to_blog( $blog_id ) {
+ $blog_id = (int) $blog_id;
+ $this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
+ }
+
+ /**
+ * Utility function to determine whether a key exists in the cache.
+ *
+ * @since 3.4.0
+ *
+ * @access protected
+ */
+ protected function _exists( $key, $group ) {
+ return isset( $this->cache[ $group ] ) && ( isset( $this->cache[ $group ][ $key ] ) || array_key_exists( $key, $this->cache[ $group ] ) );
+ }
+
+ /**
+ * Sets up object properties; PHP 5 style constructor
+ *
+ * @since 2.0.8
+ * @return null|WP_Object_Cache If cache is disabled, returns null.
+ */
+ function __construct() {
+ global $blog_id;
+
+ $this->multisite = is_multisite();
+ $this->blog_prefix = $this->multisite ? $blog_id . ':' : '';
+
+
+ /**
+ * @todo This should be moved to the PHP4 style constructor, PHP5
+ * already calls __destruct()
+ */
+ register_shutdown_function( array( $this, '__destruct' ) );
+ }
+
+ /**
+ * Will save the object cache before object is completely destroyed.
+ *
+ * Called upon object destruction, which should be when PHP ends.
+ *
+ * @since 2.0.8
+ *
+ * @return bool True value. Won't be used by PHP
+ */
+ function __destruct() {
+ return true;
+ }
+}
diff --git a/src/wp-includes/canonical.php b/src/wp-includes/canonical.php
new file mode 100644
index 0000000000..423dcc6366
--- /dev/null
+++ b/src/wp-includes/canonical.php
@@ -0,0 +1,536 @@
+<?php
+/**
+ * Canonical API to handle WordPress Redirecting
+ *
+ * Based on "Permalink Redirect" from Scott Yang and "Enforce www. Preference"
+ * by Mark Jaquith
+ *
+ * @package WordPress
+ * @since 2.3.0
+ */
+
+/**
+ * Redirects incoming links to the proper URL based on the site url.
+ *
+ * Search engines consider www.somedomain.com and somedomain.com to be two
+ * different URLs when they both go to the same location. This SEO enhancement
+ * prevents penalty for duplicate content by redirecting all incoming links to
+ * one or the other.
+ *
+ * Prevents redirection for feeds, trackbacks, searches, comment popup, and
+ * admin URLs. Does not redirect on non-pretty-permalink-supporting IIS 7+,
+ * page/post previews, WP admin, Trackbacks, robots.txt, searches, or on POST
+ * requests.
+ *
+ * Will also attempt to find the correct link when a user enters a URL that does
+ * not exist based on exact WordPress query. Will instead try to parse the URL
+ * or query in an attempt to figure the correct page to go to.
+ *
+ * @since 2.3.0
+ * @uses $wp_rewrite
+ * @uses $is_IIS
+ *
+ * @param string $requested_url Optional. The URL that was requested, used to
+ * figure if redirect is needed.
+ * @param bool $do_redirect Optional. Redirect to the new URL.
+ * @return null|false|string Null, if redirect not needed. False, if redirect
+ * not needed or the string of the URL
+ */
+function redirect_canonical( $requested_url = null, $do_redirect = true ) {
+ global $wp_rewrite, $is_IIS, $wp_query, $wpdb;
+
+ if ( is_trackback() || is_search() || is_comments_popup() || is_admin() || !empty($_POST) || is_preview() || is_robots() || ( $is_IIS && !iis7_supports_permalinks() ) )
+ return;
+
+ if ( !$requested_url ) {
+ // build the URL in the address bar
+ $requested_url = is_ssl() ? 'https://' : 'http://';
+ $requested_url .= $_SERVER['HTTP_HOST'];
+ $requested_url .= $_SERVER['REQUEST_URI'];
+ }
+
+ $original = @parse_url($requested_url);
+ if ( false === $original )
+ return;
+
+ // Some PHP setups turn requests for / into /index.php in REQUEST_URI
+ // See: http://trac.wordpress.org/ticket/5017
+ // See: http://trac.wordpress.org/ticket/7173
+ // Disabled, for now:
+ // $original['path'] = preg_replace('|/index\.php$|', '/', $original['path']);
+
+ $redirect = $original;
+ $redirect_url = false;
+
+ // Notice fixing
+ if ( !isset($redirect['path']) )
+ $redirect['path'] = '';
+ if ( !isset($redirect['query']) )
+ $redirect['query'] = '';
+
+ if ( is_feed() && ( $id = get_query_var( 'p' ) ) ) {
+ if ( $redirect_url = get_post_comments_feed_link( $id, get_query_var( 'feed' ) ) ) {
+ $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type', 'feed'), $redirect_url );
+ $redirect['path'] = parse_url( $redirect_url, PHP_URL_PATH );
+ }
+ }
+
+ if ( is_singular() && 1 > $wp_query->post_count && ($id = get_query_var('p')) ) {
+
+ $vars = $wpdb->get_results( $wpdb->prepare("SELECT post_type, post_parent FROM $wpdb->posts WHERE ID = %d", $id) );
+
+ if ( isset($vars[0]) && $vars = $vars[0] ) {
+ if ( 'revision' == $vars->post_type && $vars->post_parent > 0 )
+ $id = $vars->post_parent;
+
+ if ( $redirect_url = get_permalink($id) )
+ $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
+ }
+ }
+
+ // These tests give us a WP-generated permalink
+ if ( is_404() ) {
+
+ // Redirect ?page_id, ?p=, ?attachment_id= to their respective url's
+ $id = max( get_query_var('p'), get_query_var('page_id'), get_query_var('attachment_id') );
+ if ( $id && $redirect_post = get_post($id) ) {
+ $post_type_obj = get_post_type_object($redirect_post->post_type);
+ if ( $post_type_obj->public ) {
+ $redirect_url = get_permalink($redirect_post);
+ $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
+ }
+ }
+
+ if ( ! $redirect_url ) {
+ if ( $redirect_url = redirect_guess_404_permalink() ) {
+ $redirect['query'] = _remove_qs_args_if_not_in_url( $redirect['query'], array( 'page', 'feed', 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ), $redirect_url );
+ }
+ }
+
+ } elseif ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
+ // rewriting of old ?p=X, ?m=2004, ?m=200401, ?m=20040101
+ if ( is_attachment() && !empty($_GET['attachment_id']) && ! $redirect_url ) {
+ if ( $redirect_url = get_attachment_link(get_query_var('attachment_id')) )
+ $redirect['query'] = remove_query_arg('attachment_id', $redirect['query']);
+ } elseif ( is_single() && !empty($_GET['p']) && ! $redirect_url ) {
+ if ( $redirect_url = get_permalink(get_query_var('p')) )
+ $redirect['query'] = remove_query_arg(array('p', 'post_type'), $redirect['query']);
+ } elseif ( is_single() && !empty($_GET['name']) && ! $redirect_url ) {
+ if ( $redirect_url = get_permalink( $wp_query->get_queried_object_id() ) )
+ $redirect['query'] = remove_query_arg('name', $redirect['query']);
+ } elseif ( is_page() && !empty($_GET['page_id']) && ! $redirect_url ) {
+ if ( $redirect_url = get_permalink(get_query_var('page_id')) )
+ $redirect['query'] = remove_query_arg('page_id', $redirect['query']);
+ } elseif ( is_page() && !is_feed() && isset($wp_query->queried_object) && 'page' == get_option('show_on_front') && $wp_query->queried_object->ID == get_option('page_on_front') && ! $redirect_url ) {
+ $redirect_url = home_url('/');
+ } elseif ( is_home() && !empty($_GET['page_id']) && 'page' == get_option('show_on_front') && get_query_var('page_id') == get_option('page_for_posts') && ! $redirect_url ) {
+ if ( $redirect_url = get_permalink(get_option('page_for_posts')) )
+ $redirect['query'] = remove_query_arg('page_id', $redirect['query']);
+ } elseif ( !empty($_GET['m']) && ( is_year() || is_month() || is_day() ) ) {
+ $m = get_query_var('m');
+ switch ( strlen($m) ) {
+ case 4: // Yearly
+ $redirect_url = get_year_link($m);
+ break;
+ case 6: // Monthly
+ $redirect_url = get_month_link( substr($m, 0, 4), substr($m, 4, 2) );
+ break;
+ case 8: // Daily
+ $redirect_url = get_day_link(substr($m, 0, 4), substr($m, 4, 2), substr($m, 6, 2));
+ break;
+ }
+ if ( $redirect_url )
+ $redirect['query'] = remove_query_arg('m', $redirect['query']);
+ // now moving on to non ?m=X year/month/day links
+ } elseif ( is_day() && get_query_var('year') && get_query_var('monthnum') && !empty($_GET['day']) ) {
+ if ( $redirect_url = get_day_link(get_query_var('year'), get_query_var('monthnum'), get_query_var('day')) )
+ $redirect['query'] = remove_query_arg(array('year', 'monthnum', 'day'), $redirect['query']);
+ } elseif ( is_month() && get_query_var('year') && !empty($_GET['monthnum']) ) {
+ if ( $redirect_url = get_month_link(get_query_var('year'), get_query_var('monthnum')) )
+ $redirect['query'] = remove_query_arg(array('year', 'monthnum'), $redirect['query']);
+ } elseif ( is_year() && !empty($_GET['year']) ) {
+ if ( $redirect_url = get_year_link(get_query_var('year')) )
+ $redirect['query'] = remove_query_arg('year', $redirect['query']);
+ } elseif ( is_author() && !empty($_GET['author']) && preg_match( '|^[0-9]+$|', $_GET['author'] ) ) {
+ $author = get_userdata(get_query_var('author'));
+ if ( ( false !== $author ) && $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) ) ) {
+ if ( $redirect_url = get_author_posts_url($author->ID, $author->user_nicename) )
+ $redirect['query'] = remove_query_arg('author', $redirect['query']);
+ }
+ } elseif ( is_category() || is_tag() || is_tax() ) { // Terms (Tags/categories)
+
+ $term_count = 0;
+ foreach ( $wp_query->tax_query->queries as $tax_query )
+ $term_count += count( $tax_query['terms'] );
+
+ $obj = $wp_query->get_queried_object();
+ if ( $term_count <= 1 && !empty($obj->term_id) && ( $tax_url = get_term_link((int)$obj->term_id, $obj->taxonomy) ) && !is_wp_error($tax_url) ) {
+ if ( !empty($redirect['query']) ) {
+ // Strip taxonomy query vars off the url.
+ $qv_remove = array( 'term', 'taxonomy');
+ if ( is_category() ) {
+ $qv_remove[] = 'category_name';
+ $qv_remove[] = 'cat';
+ } elseif ( is_tag() ) {
+ $qv_remove[] = 'tag';
+ $qv_remove[] = 'tag_id';
+ } else { // Custom taxonomies will have a custom query var, remove those too:
+ $tax_obj = get_taxonomy( $obj->taxonomy );
+ if ( false !== $tax_obj->query_var )
+ $qv_remove[] = $tax_obj->query_var;
+ }
+
+ $rewrite_vars = array_diff( array_keys($wp_query->query), array_keys($_GET) );
+
+ if ( !array_diff($rewrite_vars, array_keys($_GET)) ) { // Check to see if all the Query vars are coming from the rewrite, none are set via $_GET
+ $redirect['query'] = remove_query_arg($qv_remove, $redirect['query']); //Remove all of the per-tax qv's
+
+ // Create the destination url for this taxonomy
+ $tax_url = parse_url($tax_url);
+ if ( ! empty($tax_url['query']) ) { // Taxonomy accessible via ?taxonomy=..&term=.. or any custom qv..
+ parse_str($tax_url['query'], $query_vars);
+ $redirect['query'] = add_query_arg($query_vars, $redirect['query']);
+ } else { // Taxonomy is accessible via a "pretty-URL"
+ $redirect['path'] = $tax_url['path'];
+ }
+
+ } else { // Some query vars are set via $_GET. Unset those from $_GET that exist via the rewrite
+ foreach ( $qv_remove as $_qv ) {
+ if ( isset($rewrite_vars[$_qv]) )
+ $redirect['query'] = remove_query_arg($_qv, $redirect['query']);
+ }
+ }
+ }
+
+ }
+ } elseif ( is_single() && strpos($wp_rewrite->permalink_structure, '%category%') !== false && $cat = get_query_var( 'category_name' ) ) {
+ $category = get_category_by_path( $cat );
+ $post_terms = wp_get_object_terms($wp_query->get_queried_object_id(), 'category', array('fields' => 'tt_ids'));
+ if ( (!$category || is_wp_error($category)) || ( !is_wp_error($post_terms) && !empty($post_terms) && !in_array($category->term_taxonomy_id, $post_terms) ) )
+ $redirect_url = get_permalink($wp_query->get_queried_object_id());
+ }
+
+ // Post Paging
+ if ( is_singular() && ! is_front_page() && get_query_var('page') ) {
+ if ( !$redirect_url )
+ $redirect_url = get_permalink( get_queried_object_id() );
+ $redirect_url = trailingslashit( $redirect_url ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' );
+ $redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
+ }
+
+ // paging and feeds
+ if ( get_query_var('paged') || is_feed() || get_query_var('cpage') ) {
+ while ( preg_match( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", $redirect['path'] ) || preg_match( '#/(comments/?)?(feed|rss|rdf|atom|rss2)(/+)?$#', $redirect['path'] ) || preg_match( '#/comment-page-[0-9]+(/+)?$#', $redirect['path'] ) ) {
+ // Strip off paging and feed
+ $redirect['path'] = preg_replace("#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", '/', $redirect['path']); // strip off any existing paging
+ $redirect['path'] = preg_replace('#/(comments/?)?(feed|rss2?|rdf|atom)(/+|$)#', '/', $redirect['path']); // strip off feed endings
+ $redirect['path'] = preg_replace('#/comment-page-[0-9]+?(/+)?$#', '/', $redirect['path']); // strip off any existing comment paging
+ }
+
+ $addl_path = '';
+ if ( is_feed() && in_array( get_query_var('feed'), $wp_rewrite->feeds ) ) {
+ $addl_path = !empty( $addl_path ) ? trailingslashit($addl_path) : '';
+ if ( !is_singular() && get_query_var( 'withcomments' ) )
+ $addl_path .= 'comments/';
+ if ( ( 'rss' == get_default_feed() && 'feed' == get_query_var('feed') ) || 'rss' == get_query_var('feed') )
+ $addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == 'rss2' ) ? '' : 'rss2' ), 'feed' );
+ else
+ $addl_path .= user_trailingslashit( 'feed/' . ( ( get_default_feed() == get_query_var('feed') || 'feed' == get_query_var('feed') ) ? '' : get_query_var('feed') ), 'feed' );
+ $redirect['query'] = remove_query_arg( 'feed', $redirect['query'] );
+ } elseif ( is_feed() && 'old' == get_query_var('feed') ) {
+ $old_feed_files = array(
+ 'wp-atom.php' => 'atom',
+ 'wp-commentsrss2.php' => 'comments_rss2',
+ 'wp-feed.php' => get_default_feed(),
+ 'wp-rdf.php' => 'rdf',
+ 'wp-rss.php' => 'rss2',
+ 'wp-rss2.php' => 'rss2',
+ );
+ if ( isset( $old_feed_files[ basename( $redirect['path'] ) ] ) ) {
+ $redirect_url = get_feed_link( $old_feed_files[ basename( $redirect['path'] ) ] );
+ wp_redirect( $redirect_url, 301 );
+ die();
+ }
+ }
+
+ if ( get_query_var('paged') > 0 ) {
+ $paged = get_query_var('paged');
+ $redirect['query'] = remove_query_arg( 'paged', $redirect['query'] );
+ if ( !is_feed() ) {
+ if ( $paged > 1 && !is_single() ) {
+ $addl_path = ( !empty( $addl_path ) ? trailingslashit($addl_path) : '' ) . user_trailingslashit("$wp_rewrite->pagination_base/$paged", 'paged');
+ } elseif ( !is_single() ) {
+ $addl_path = !empty( $addl_path ) ? trailingslashit($addl_path) : '';
+ }
+ } elseif ( $paged > 1 ) {
+ $redirect['query'] = add_query_arg( 'paged', $paged, $redirect['query'] );
+ }
+ }
+
+ if ( get_option('page_comments') && ( ( 'newest' == get_option('default_comments_page') && get_query_var('cpage') > 0 ) || ( 'newest' != get_option('default_comments_page') && get_query_var('cpage') > 1 ) ) ) {
+ $addl_path = ( !empty( $addl_path ) ? trailingslashit($addl_path) : '' ) . user_trailingslashit( 'comment-page-' . get_query_var('cpage'), 'commentpaged' );
+ $redirect['query'] = remove_query_arg( 'cpage', $redirect['query'] );
+ }
+
+ $redirect['path'] = user_trailingslashit( preg_replace('|/' . preg_quote( $wp_rewrite->index, '|' ) . '/?$|', '/', $redirect['path']) ); // strip off trailing /index.php/
+ if ( !empty( $addl_path ) && $wp_rewrite->using_index_permalinks() && strpos($redirect['path'], '/' . $wp_rewrite->index . '/') === false )
+ $redirect['path'] = trailingslashit($redirect['path']) . $wp_rewrite->index . '/';
+ if ( !empty( $addl_path ) )
+ $redirect['path'] = trailingslashit($redirect['path']) . $addl_path;
+ $redirect_url = $redirect['scheme'] . '://' . $redirect['host'] . $redirect['path'];
+ }
+
+ if ( 'wp-register.php' == basename( $redirect['path'] ) ) {
+ if ( is_multisite() )
+ $redirect_url = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) );
+ else
+ $redirect_url = site_url( 'wp-login.php?action=register' );
+ wp_redirect( $redirect_url, 301 );
+ die();
+ }
+ }
+
+ // tack on any additional query vars
+ $redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
+ if ( $redirect_url && !empty($redirect['query']) ) {
+ parse_str( $redirect['query'], $_parsed_query );
+ $redirect = @parse_url($redirect_url);
+
+ if ( ! empty( $_parsed_query['name'] ) && ! empty( $redirect['query'] ) ) {
+ parse_str( $redirect['query'], $_parsed_redirect_query );
+
+ if ( empty( $_parsed_redirect_query['name'] ) )
+ unset( $_parsed_query['name'] );
+ }
+
+ $_parsed_query = rawurlencode_deep( $_parsed_query );
+ $redirect_url = add_query_arg( $_parsed_query, $redirect_url );
+ }
+
+ if ( $redirect_url )
+ $redirect = @parse_url($redirect_url);
+
+ // www.example.com vs example.com
+ $user_home = @parse_url(home_url());
+ if ( !empty($user_home['host']) )
+ $redirect['host'] = $user_home['host'];
+ if ( empty($user_home['path']) )
+ $user_home['path'] = '/';
+
+ // Handle ports
+ if ( !empty($user_home['port']) )
+ $redirect['port'] = $user_home['port'];
+ else
+ unset($redirect['port']);
+
+ // trailing /index.php
+ $redirect['path'] = preg_replace('|/' . preg_quote( $wp_rewrite->index, '|' ) . '/*?$|', '/', $redirect['path']);
+
+ // Remove trailing spaces from the path
+ $redirect['path'] = preg_replace( '#(%20| )+$#', '', $redirect['path'] );
+
+ if ( !empty( $redirect['query'] ) ) {
+ // Remove trailing spaces from certain terminating query string args
+ $redirect['query'] = preg_replace( '#((p|page_id|cat|tag)=[^&]*?)(%20| )+$#', '$1', $redirect['query'] );
+
+ // Clean up empty query strings
+ $redirect['query'] = trim(preg_replace( '#(^|&)(p|page_id|cat|tag)=?(&|$)#', '&', $redirect['query']), '&');
+
+ // Redirect obsolete feeds
+ $redirect['query'] = preg_replace( '#(^|&)feed=rss(&|$)#', '$1feed=rss2$2', $redirect['query'] );
+
+ // Remove redundant leading ampersands
+ $redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
+ }
+
+ // strip /index.php/ when we're not using PATHINFO permalinks
+ if ( !$wp_rewrite->using_index_permalinks() )
+ $redirect['path'] = str_replace( '/' . $wp_rewrite->index . '/', '/', $redirect['path'] );
+
+ // trailing slashes
+ if ( is_object($wp_rewrite) && $wp_rewrite->using_permalinks() && !is_404() && (!is_front_page() || ( is_front_page() && (get_query_var('paged') > 1) ) ) ) {
+ $user_ts_type = '';
+ if ( get_query_var('paged') > 0 ) {
+ $user_ts_type = 'paged';
+ } else {
+ foreach ( array('single', 'category', 'page', 'day', 'month', 'year', 'home') as $type ) {
+ $func = 'is_' . $type;
+ if ( call_user_func($func) ) {
+ $user_ts_type = $type;
+ break;
+ }
+ }
+ }
+ $redirect['path'] = user_trailingslashit($redirect['path'], $user_ts_type);
+ } elseif ( is_front_page() ) {
+ $redirect['path'] = trailingslashit($redirect['path']);
+ }
+
+ // Strip multiple slashes out of the URL
+ if ( strpos($redirect['path'], '//') > -1 )
+ $redirect['path'] = preg_replace('|/+|', '/', $redirect['path']);
+
+ // Always trailing slash the Front Page URL
+ if ( trailingslashit( $redirect['path'] ) == trailingslashit( $user_home['path'] ) )
+ $redirect['path'] = trailingslashit($redirect['path']);
+
+ // Ignore differences in host capitalization, as this can lead to infinite redirects
+ // Only redirect no-www <=> yes-www
+ if ( strtolower($original['host']) == strtolower($redirect['host']) ||
+ ( strtolower($original['host']) != 'www.' . strtolower($redirect['host']) && 'www.' . strtolower($original['host']) != strtolower($redirect['host']) ) )
+ $redirect['host'] = $original['host'];
+
+ $compare_original = array($original['host'], $original['path']);
+
+ if ( !empty( $original['port'] ) )
+ $compare_original[] = $original['port'];
+
+ if ( !empty( $original['query'] ) )
+ $compare_original[] = $original['query'];
+
+ $compare_redirect = array($redirect['host'], $redirect['path']);
+
+ if ( !empty( $redirect['port'] ) )
+ $compare_redirect[] = $redirect['port'];
+
+ if ( !empty( $redirect['query'] ) )
+ $compare_redirect[] = $redirect['query'];
+
+ if ( $compare_original !== $compare_redirect ) {
+ $redirect_url = $redirect['scheme'] . '://' . $redirect['host'];
+ if ( !empty($redirect['port']) )
+ $redirect_url .= ':' . $redirect['port'];
+ $redirect_url .= $redirect['path'];
+ if ( !empty($redirect['query']) )
+ $redirect_url .= '?' . $redirect['query'];
+ }
+
+ if ( !$redirect_url || $redirect_url == $requested_url )
+ return false;
+
+ // Hex encoded octets are case-insensitive.
+ if ( false !== strpos($requested_url, '%') ) {
+ if ( !function_exists('lowercase_octets') ) {
+ function lowercase_octets($matches) {
+ return strtolower( $matches[0] );
+ }
+ }
+ $requested_url = preg_replace_callback('|%[a-fA-F0-9][a-fA-F0-9]|', 'lowercase_octets', $requested_url);
+ }
+
+ // Note that you can use the "redirect_canonical" filter to cancel a canonical redirect for whatever reason by returning false
+ $redirect_url = apply_filters('redirect_canonical', $redirect_url, $requested_url);
+
+ if ( !$redirect_url || $redirect_url == $requested_url ) // yes, again -- in case the filter aborted the request
+ return false;
+
+ if ( $do_redirect ) {
+ // protect against chained redirects
+ if ( !redirect_canonical($redirect_url, false) ) {
+ wp_redirect($redirect_url, 301);
+ exit();
+ } else {
+ // Debug
+ // die("1: $redirect_url<br />2: " . redirect_canonical( $redirect_url, false ) );
+ return false;
+ }
+ } else {
+ return $redirect_url;
+ }
+}
+
+/**
+ * Removes arguments from a query string if they are not present in a URL
+ * DO NOT use this in plugin code.
+ *
+ * @since 3.4
+ * @access private
+ *
+ * @return string The altered query string
+ */
+function _remove_qs_args_if_not_in_url( $query_string, Array $args_to_check, $url ) {
+ $parsed_url = @parse_url( $url );
+ if ( ! empty( $parsed_url['query'] ) ) {
+ parse_str( $parsed_url['query'], $parsed_query );
+ foreach ( $args_to_check as $qv ) {
+ if ( !isset( $parsed_query[$qv] ) )
+ $query_string = remove_query_arg( $qv, $query_string );
+ }
+ } else {
+ $query_string = remove_query_arg( $args_to_check, $query_string );
+ }
+ return $query_string;
+}
+
+/**
+ * Attempts to guess the correct URL based on query vars
+ *
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @return bool|string The correct URL if one is found. False on failure.
+ */
+function redirect_guess_404_permalink() {
+ global $wpdb, $wp_rewrite;
+
+ if ( get_query_var('name') ) {
+ $where = $wpdb->prepare("post_name LIKE %s", like_escape( get_query_var('name') ) . '%');
+
+ // if any of post_type, year, monthnum, or day are set, use them to refine the query
+ if ( get_query_var('post_type') )
+ $where .= $wpdb->prepare(" AND post_type = %s", get_query_var('post_type'));
+ else
+ $where .= " AND post_type IN ('" . implode( "', '", get_post_types( array( 'public' => true ) ) ) . "')";
+
+ if ( get_query_var('year') )
+ $where .= $wpdb->prepare(" AND YEAR(post_date) = %d", get_query_var('year'));
+ if ( get_query_var('monthnum') )
+ $where .= $wpdb->prepare(" AND MONTH(post_date) = %d", get_query_var('monthnum'));
+ if ( get_query_var('day') )
+ $where .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", get_query_var('day'));
+
+ $post_id = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE $where AND post_status = 'publish'");
+ if ( ! $post_id )
+ return false;
+ if ( get_query_var( 'feed' ) )
+ return get_post_comments_feed_link( $post_id, get_query_var( 'feed' ) );
+ elseif ( get_query_var( 'page' ) )
+ return trailingslashit( get_permalink( $post_id ) ) . user_trailingslashit( get_query_var( 'page' ), 'single_paged' );
+ else
+ return get_permalink( $post_id );
+ }
+
+ return false;
+}
+
+add_action('template_redirect', 'redirect_canonical');
+
+function wp_redirect_admin_locations() {
+ global $wp_rewrite;
+ if ( ! ( is_404() && $wp_rewrite->using_permalinks() ) )
+ return;
+
+ $admins = array(
+ home_url( 'wp-admin', 'relative' ),
+ home_url( 'dashboard', 'relative' ),
+ home_url( 'admin', 'relative' ),
+ site_url( 'dashboard', 'relative' ),
+ site_url( 'admin', 'relative' ),
+ );
+ if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $admins ) ) {
+ wp_redirect( admin_url() );
+ exit;
+ }
+
+ $logins = array(
+ home_url( 'wp-login.php', 'relative' ),
+ home_url( 'login', 'relative' ),
+ site_url( 'login', 'relative' ),
+ );
+ if ( in_array( untrailingslashit( $_SERVER['REQUEST_URI'] ), $logins ) ) {
+ wp_redirect( site_url( 'wp-login.php', 'login' ) );
+ exit;
+ }
+}
+
+add_action( 'template_redirect', 'wp_redirect_admin_locations', 1000 );
diff --git a/src/wp-includes/capabilities.php b/src/wp-includes/capabilities.php
new file mode 100644
index 0000000000..c3bb58f627
--- /dev/null
+++ b/src/wp-includes/capabilities.php
@@ -0,0 +1,1468 @@
+<?php
+/**
+ * WordPress Roles and Capabilities.
+ *
+ * @package WordPress
+ * @subpackage User
+ */
+
+/**
+ * WordPress User Roles.
+ *
+ * The role option is simple, the structure is organized by role name that store
+ * the name in value of the 'name' key. The capabilities are stored as an array
+ * in the value of the 'capability' key.
+ *
+ * <code>
+ * array (
+ * 'rolename' => array (
+ * 'name' => 'rolename',
+ * 'capabilities' => array()
+ * )
+ * )
+ * </code>
+ *
+ * @since 2.0.0
+ * @package WordPress
+ * @subpackage User
+ */
+class WP_Roles {
+ /**
+ * List of roles and capabilities.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $roles;
+
+ /**
+ * List of the role objects.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $role_objects = array();
+
+ /**
+ * List of role names.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $role_names = array();
+
+ /**
+ * Option name for storing role list.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var string
+ */
+ var $role_key;
+
+ /**
+ * Whether to use the database for retrieval and storage.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $use_db = true;
+
+ /**
+ * Constructor
+ *
+ * @since 2.0.0
+ */
+ function __construct() {
+ $this->_init();
+ }
+
+ /**
+ * Set up the object properties.
+ *
+ * The role key is set to the current prefix for the $wpdb object with
+ * 'user_roles' appended. If the $wp_user_roles global is set, then it will
+ * be used and the role option will not be updated or used.
+ *
+ * @since 2.1.0
+ * @access protected
+ * @uses $wpdb Used to get the database prefix.
+ * @global array $wp_user_roles Used to set the 'roles' property value.
+ */
+ function _init () {
+ global $wpdb, $wp_user_roles;
+ $this->role_key = $wpdb->prefix . 'user_roles';
+ if ( ! empty( $wp_user_roles ) ) {
+ $this->roles = $wp_user_roles;
+ $this->use_db = false;
+ } else {
+ $this->roles = get_option( $this->role_key );
+ }
+
+ if ( empty( $this->roles ) )
+ return;
+
+ $this->role_objects = array();
+ $this->role_names = array();
+ foreach ( array_keys( $this->roles ) as $role ) {
+ $this->role_objects[$role] = new WP_Role( $role, $this->roles[$role]['capabilities'] );
+ $this->role_names[$role] = $this->roles[$role]['name'];
+ }
+ }
+
+ /**
+ * Reinitialize the object
+ *
+ * Recreates the role objects. This is typically called only by switch_to_blog()
+ * after switching wpdb to a new blog ID.
+ *
+ * @since 3.5.0
+ * @access public
+ */
+ function reinit() {
+ // There is no need to reinit if using the wp_user_roles global.
+ if ( ! $this->use_db )
+ return;
+
+ global $wpdb, $wp_user_roles;
+
+ // Duplicated from _init() to avoid an extra function call.
+ $this->role_key = $wpdb->prefix . 'user_roles';
+ $this->roles = get_option( $this->role_key );
+ if ( empty( $this->roles ) )
+ return;
+
+ $this->role_objects = array();
+ $this->role_names = array();
+ foreach ( array_keys( $this->roles ) as $role ) {
+ $this->role_objects[$role] = new WP_Role( $role, $this->roles[$role]['capabilities'] );
+ $this->role_names[$role] = $this->roles[$role]['name'];
+ }
+ }
+
+ /**
+ * Add role name with capabilities to list.
+ *
+ * Updates the list of roles, if the role doesn't already exist.
+ *
+ * The capabilities are defined in the following format `array( 'read' => true );`
+ * To explicitly deny a role a capability you set the value for that capability to false.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ * @param string $display_name Role display name.
+ * @param array $capabilities List of role capabilities in the above format.
+ * @return WP_Role|null WP_Role object if role is added, null if already exists.
+ */
+ function add_role( $role, $display_name, $capabilities = array() ) {
+ if ( isset( $this->roles[$role] ) )
+ return;
+
+ $this->roles[$role] = array(
+ 'name' => $display_name,
+ 'capabilities' => $capabilities
+ );
+ if ( $this->use_db )
+ update_option( $this->role_key, $this->roles );
+ $this->role_objects[$role] = new WP_Role( $role, $capabilities );
+ $this->role_names[$role] = $display_name;
+ return $this->role_objects[$role];
+ }
+
+ /**
+ * Remove role by name.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ */
+ function remove_role( $role ) {
+ if ( ! isset( $this->role_objects[$role] ) )
+ return;
+
+ unset( $this->role_objects[$role] );
+ unset( $this->role_names[$role] );
+ unset( $this->roles[$role] );
+
+ if ( $this->use_db )
+ update_option( $this->role_key, $this->roles );
+ }
+
+ /**
+ * Add capability to role.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ * @param string $cap Capability name.
+ * @param bool $grant Optional, default is true. Whether role is capable of performing capability.
+ */
+ function add_cap( $role, $cap, $grant = true ) {
+ if ( ! isset( $this->roles[$role] ) )
+ return;
+
+ $this->roles[$role]['capabilities'][$cap] = $grant;
+ if ( $this->use_db )
+ update_option( $this->role_key, $this->roles );
+ }
+
+ /**
+ * Remove capability from role.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ * @param string $cap Capability name.
+ */
+ function remove_cap( $role, $cap ) {
+ if ( ! isset( $this->roles[$role] ) )
+ return;
+
+ unset( $this->roles[$role]['capabilities'][$cap] );
+ if ( $this->use_db )
+ update_option( $this->role_key, $this->roles );
+ }
+
+ /**
+ * Retrieve role object by name.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ * @return WP_Role|null WP_Role object if found, null if the role does not exist.
+ */
+ function get_role( $role ) {
+ if ( isset( $this->role_objects[$role] ) )
+ return $this->role_objects[$role];
+ else
+ return null;
+ }
+
+ /**
+ * Retrieve list of role names.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @return array List of role names.
+ */
+ function get_names() {
+ return $this->role_names;
+ }
+
+ /**
+ * Whether role name is currently in the list of available roles.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name to look up.
+ * @return bool
+ */
+ function is_role( $role ) {
+ return isset( $this->role_names[$role] );
+ }
+}
+
+/**
+ * WordPress Role class.
+ *
+ * @since 2.0.0
+ * @package WordPress
+ * @subpackage User
+ */
+class WP_Role {
+ /**
+ * Role name.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var string
+ */
+ var $name;
+
+ /**
+ * List of capabilities the role contains.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $capabilities;
+
+ /**
+ * Constructor - Set up object properties.
+ *
+ * The list of capabilities, must have the key as the name of the capability
+ * and the value a boolean of whether it is granted to the role.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ * @param array $capabilities List of capabilities.
+ */
+ function __construct( $role, $capabilities ) {
+ $this->name = $role;
+ $this->capabilities = $capabilities;
+ }
+
+ /**
+ * Assign role a capability.
+ *
+ * @see WP_Roles::add_cap() Method uses implementation for role.
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $cap Capability name.
+ * @param bool $grant Whether role has capability privilege.
+ */
+ function add_cap( $cap, $grant = true ) {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ $this->capabilities[$cap] = $grant;
+ $wp_roles->add_cap( $this->name, $cap, $grant );
+ }
+
+ /**
+ * Remove capability from role.
+ *
+ * This is a container for {@link WP_Roles::remove_cap()} to remove the
+ * capability from the role. That is to say, that {@link
+ * WP_Roles::remove_cap()} implements the functionality, but it also makes
+ * sense to use this class, because you don't need to enter the role name.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $cap Capability name.
+ */
+ function remove_cap( $cap ) {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ unset( $this->capabilities[$cap] );
+ $wp_roles->remove_cap( $this->name, $cap );
+ }
+
+ /**
+ * Whether role has capability.
+ *
+ * The capabilities is passed through the 'role_has_cap' filter. The first
+ * parameter for the hook is the list of capabilities the class has
+ * assigned. The second parameter is the capability name to look for. The
+ * third and final parameter for the hook is the role name.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $cap Capability name.
+ * @return bool True, if user has capability. False, if doesn't have capability.
+ */
+ function has_cap( $cap ) {
+ $capabilities = apply_filters( 'role_has_cap', $this->capabilities, $cap, $this->name );
+ if ( !empty( $capabilities[$cap] ) )
+ return $capabilities[$cap];
+ else
+ return false;
+ }
+
+}
+
+/**
+ * WordPress User class.
+ *
+ * @since 2.0.0
+ * @package WordPress
+ * @subpackage User
+ */
+class WP_User {
+ /**
+ * User data container.
+ *
+ * @since 2.0.0
+ * @access private
+ * @var array
+ */
+ var $data;
+
+ /**
+ * The user's ID.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var int
+ */
+ var $ID = 0;
+
+ /**
+ * The individual capabilities the user has been given.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $caps = array();
+
+ /**
+ * User metadata option name.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var string
+ */
+ var $cap_key;
+
+ /**
+ * The roles the user is part of.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $roles = array();
+
+ /**
+ * All capabilities the user has, including individual and role based.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $allcaps = array();
+
+ /**
+ * The filter context applied to user data fields.
+ *
+ * @since 2.9.0
+ * @access private
+ * @var string
+ */
+ var $filter = null;
+
+ private static $back_compat_keys;
+
+ /**
+ * Constructor
+ *
+ * Retrieves the userdata and passes it to {@link WP_User::init()}.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param int|string|stdClass|WP_User $id User's ID, a WP_User object, or a user object from the DB.
+ * @param string $name Optional. User's username
+ * @param int $blog_id Optional Blog ID, defaults to current blog.
+ * @return WP_User
+ */
+ function __construct( $id = 0, $name = '', $blog_id = '' ) {
+ if ( ! isset( self::$back_compat_keys ) ) {
+ $prefix = $GLOBALS['wpdb']->prefix;
+ self::$back_compat_keys = array(
+ 'user_firstname' => 'first_name',
+ 'user_lastname' => 'last_name',
+ 'user_description' => 'description',
+ 'user_level' => $prefix . 'user_level',
+ $prefix . 'usersettings' => $prefix . 'user-settings',
+ $prefix . 'usersettingstime' => $prefix . 'user-settings-time',
+ );
+ }
+
+ if ( is_a( $id, 'WP_User' ) ) {
+ $this->init( $id->data, $blog_id );
+ return;
+ } elseif ( is_object( $id ) ) {
+ $this->init( $id, $blog_id );
+ return;
+ }
+
+ if ( ! empty( $id ) && ! is_numeric( $id ) ) {
+ $name = $id;
+ $id = 0;
+ }
+
+ if ( $id )
+ $data = self::get_data_by( 'id', $id );
+ else
+ $data = self::get_data_by( 'login', $name );
+
+ if ( $data )
+ $this->init( $data, $blog_id );
+ }
+
+ /**
+ * Sets up object properties, including capabilities.
+ *
+ * @param object $data User DB row object
+ * @param int $blog_id Optional. The blog id to initialize for
+ */
+ function init( $data, $blog_id = '' ) {
+ $this->data = $data;
+ $this->ID = (int) $data->ID;
+
+ $this->for_blog( $blog_id );
+ }
+
+ /**
+ * Return only the main user fields
+ *
+ * @since 3.3.0
+ *
+ * @param string $field The field to query against: 'id', 'slug', 'email' or 'login'
+ * @param string|int $value The field value
+ * @return object Raw user object
+ */
+ static function get_data_by( $field, $value ) {
+ global $wpdb;
+
+ if ( 'id' == $field ) {
+ // Make sure the value is numeric to avoid casting objects, for example,
+ // to int 1.
+ if ( ! is_numeric( $value ) )
+ return false;
+ $value = intval( $value );
+ if ( $value < 1 )
+ return false;
+ } else {
+ $value = trim( $value );
+ }
+
+ if ( !$value )
+ return false;
+
+ switch ( $field ) {
+ case 'id':
+ $user_id = $value;
+ $db_field = 'ID';
+ break;
+ case 'slug':
+ $user_id = wp_cache_get($value, 'userslugs');
+ $db_field = 'user_nicename';
+ break;
+ case 'email':
+ $user_id = wp_cache_get($value, 'useremail');
+ $db_field = 'user_email';
+ break;
+ case 'login':
+ $value = sanitize_user( $value );
+ $user_id = wp_cache_get($value, 'userlogins');
+ $db_field = 'user_login';
+ break;
+ default:
+ return false;
+ }
+
+ if ( false !== $user_id ) {
+ if ( $user = wp_cache_get( $user_id, 'users' ) )
+ return $user;
+ }
+
+ if ( !$user = $wpdb->get_row( $wpdb->prepare(
+ "SELECT * FROM $wpdb->users WHERE $db_field = %s", $value
+ ) ) )
+ return false;
+
+ update_user_caches( $user );
+
+ return $user;
+ }
+
+ /**
+ * Magic method for checking the existence of a certain custom field
+ *
+ * @since 3.3.0
+ */
+ function __isset( $key ) {
+ if ( 'id' == $key ) {
+ _deprecated_argument( 'WP_User->id', '2.1', __( 'Use <code>WP_User->ID</code> instead.' ) );
+ $key = 'ID';
+ }
+
+ if ( isset( $this->data->$key ) )
+ return true;
+
+ if ( isset( self::$back_compat_keys[ $key ] ) )
+ $key = self::$back_compat_keys[ $key ];
+
+ return metadata_exists( 'user', $this->ID, $key );
+ }
+
+ /**
+ * Magic method for accessing custom fields
+ *
+ * @since 3.3.0
+ */
+ function __get( $key ) {
+ if ( 'id' == $key ) {
+ _deprecated_argument( 'WP_User->id', '2.1', __( 'Use <code>WP_User->ID</code> instead.' ) );
+ return $this->ID;
+ }
+
+ if ( isset( $this->data->$key ) ) {
+ $value = $this->data->$key;
+ } else {
+ if ( isset( self::$back_compat_keys[ $key ] ) )
+ $key = self::$back_compat_keys[ $key ];
+ $value = get_user_meta( $this->ID, $key, true );
+ }
+
+ if ( $this->filter ) {
+ $value = sanitize_user_field( $key, $value, $this->ID, $this->filter );
+ }
+
+ return $value;
+ }
+
+ /**
+ * Magic method for setting custom fields
+ *
+ * @since 3.3.0
+ */
+ function __set( $key, $value ) {
+ if ( 'id' == $key ) {
+ _deprecated_argument( 'WP_User->id', '2.1', __( 'Use <code>WP_User->ID</code> instead.' ) );
+ $this->ID = $value;
+ return;
+ }
+
+ $this->data->$key = $value;
+ }
+
+ /**
+ * Determine whether the user exists in the database.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return bool True if user exists in the database, false if not.
+ */
+ function exists() {
+ return ! empty( $this->ID );
+ }
+
+ /**
+ * Retrieve the value of a property or meta key.
+ *
+ * Retrieves from the users and usermeta table.
+ *
+ * @since 3.3.0
+ *
+ * @param string $key Property
+ */
+ function get( $key ) {
+ return $this->__get( $key );
+ }
+
+ /**
+ * Determine whether a property or meta key is set
+ *
+ * Consults the users and usermeta tables.
+ *
+ * @since 3.3.0
+ *
+ * @param string $key Property
+ */
+ function has_prop( $key ) {
+ return $this->__isset( $key );
+ }
+
+ /*
+ * Return an array representation.
+ *
+ * @since 3.5.0
+ *
+ * @return array Array representation.
+ */
+ function to_array() {
+ return get_object_vars( $this->data );
+ }
+
+ /**
+ * Set up capability object properties.
+ *
+ * Will set the value for the 'cap_key' property to current database table
+ * prefix, followed by 'capabilities'. Will then check to see if the
+ * property matching the 'cap_key' exists and is an array. If so, it will be
+ * used.
+ *
+ * @access protected
+ * @since 2.1.0
+ *
+ * @param string $cap_key Optional capability key
+ */
+ function _init_caps( $cap_key = '' ) {
+ global $wpdb;
+
+ if ( empty($cap_key) )
+ $this->cap_key = $wpdb->prefix . 'capabilities';
+ else
+ $this->cap_key = $cap_key;
+
+ $this->caps = get_user_meta( $this->ID, $this->cap_key, true );
+
+ if ( ! is_array( $this->caps ) )
+ $this->caps = array();
+
+ $this->get_role_caps();
+ }
+
+ /**
+ * Retrieve all of the role capabilities and merge with individual capabilities.
+ *
+ * All of the capabilities of the roles the user belongs to are merged with
+ * the users individual roles. This also means that the user can be denied
+ * specific roles that their role might have, but the specific user isn't
+ * granted permission to.
+ *
+ * @since 2.0.0
+ * @uses $wp_roles
+ * @access public
+ */
+ function get_role_caps() {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ //Filter out caps that are not role names and assign to $this->roles
+ if ( is_array( $this->caps ) )
+ $this->roles = array_filter( array_keys( $this->caps ), array( $wp_roles, 'is_role' ) );
+
+ //Build $allcaps from role caps, overlay user's $caps
+ $this->allcaps = array();
+ foreach ( (array) $this->roles as $role ) {
+ $the_role = $wp_roles->get_role( $role );
+ $this->allcaps = array_merge( (array) $this->allcaps, (array) $the_role->capabilities );
+ }
+ $this->allcaps = array_merge( (array) $this->allcaps, (array) $this->caps );
+ }
+
+ /**
+ * Add role to user.
+ *
+ * Updates the user's meta data option with capabilities and roles.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ */
+ function add_role( $role ) {
+ $this->caps[$role] = true;
+ update_user_meta( $this->ID, $this->cap_key, $this->caps );
+ $this->get_role_caps();
+ $this->update_user_level_from_caps();
+ }
+
+ /**
+ * Remove role from user.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ */
+ function remove_role( $role ) {
+ if ( !in_array($role, $this->roles) )
+ return;
+ unset( $this->caps[$role] );
+ update_user_meta( $this->ID, $this->cap_key, $this->caps );
+ $this->get_role_caps();
+ $this->update_user_level_from_caps();
+ }
+
+ /**
+ * Set the role of the user.
+ *
+ * This will remove the previous roles of the user and assign the user the
+ * new one. You can set the role to an empty string and it will remove all
+ * of the roles from the user.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $role Role name.
+ */
+ function set_role( $role ) {
+ if ( 1 == count( $this->roles ) && $role == current( $this->roles ) )
+ return;
+
+ foreach ( (array) $this->roles as $oldrole )
+ unset( $this->caps[$oldrole] );
+
+ $old_roles = $this->roles;
+ if ( !empty( $role ) ) {
+ $this->caps[$role] = true;
+ $this->roles = array( $role => true );
+ } else {
+ $this->roles = false;
+ }
+ update_user_meta( $this->ID, $this->cap_key, $this->caps );
+ $this->get_role_caps();
+ $this->update_user_level_from_caps();
+ do_action( 'set_user_role', $this->ID, $role, $old_roles );
+ }
+
+ /**
+ * Choose the maximum level the user has.
+ *
+ * Will compare the level from the $item parameter against the $max
+ * parameter. If the item is incorrect, then just the $max parameter value
+ * will be returned.
+ *
+ * Used to get the max level based on the capabilities the user has. This
+ * is also based on roles, so if the user is assigned the Administrator role
+ * then the capability 'level_10' will exist and the user will get that
+ * value.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param int $max Max level of user.
+ * @param string $item Level capability name.
+ * @return int Max Level.
+ */
+ function level_reduction( $max, $item ) {
+ if ( preg_match( '/^level_(10|[0-9])$/i', $item, $matches ) ) {
+ $level = intval( $matches[1] );
+ return max( $max, $level );
+ } else {
+ return $max;
+ }
+ }
+
+ /**
+ * Update the maximum user level for the user.
+ *
+ * Updates the 'user_level' user metadata (includes prefix that is the
+ * database table prefix) with the maximum user level. Gets the value from
+ * the all of the capabilities that the user has.
+ *
+ * @since 2.0.0
+ * @access public
+ */
+ function update_user_level_from_caps() {
+ global $wpdb;
+ $this->user_level = array_reduce( array_keys( $this->allcaps ), array( $this, 'level_reduction' ), 0 );
+ update_user_meta( $this->ID, $wpdb->prefix . 'user_level', $this->user_level );
+ }
+
+ /**
+ * Add capability and grant or deny access to capability.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $cap Capability name.
+ * @param bool $grant Whether to grant capability to user.
+ */
+ function add_cap( $cap, $grant = true ) {
+ $this->caps[$cap] = $grant;
+ update_user_meta( $this->ID, $this->cap_key, $this->caps );
+ }
+
+ /**
+ * Remove capability from user.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string $cap Capability name.
+ */
+ function remove_cap( $cap ) {
+ if ( ! isset( $this->caps[$cap] ) )
+ return;
+ unset( $this->caps[$cap] );
+ update_user_meta( $this->ID, $this->cap_key, $this->caps );
+ }
+
+ /**
+ * Remove all of the capabilities of the user.
+ *
+ * @since 2.1.0
+ * @access public
+ */
+ function remove_all_caps() {
+ global $wpdb;
+ $this->caps = array();
+ delete_user_meta( $this->ID, $this->cap_key );
+ delete_user_meta( $this->ID, $wpdb->prefix . 'user_level' );
+ $this->get_role_caps();
+ }
+
+ /**
+ * Whether user has capability or role name.
+ *
+ * This is useful for looking up whether the user has a specific role
+ * assigned to the user. The second optional parameter can also be used to
+ * check for capabilities against a specific object, such as a post or user.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param string|int $cap Capability or role name to search.
+ * @return bool True, if user has capability; false, if user does not have capability.
+ */
+ function has_cap( $cap ) {
+ if ( is_numeric( $cap ) ) {
+ _deprecated_argument( __FUNCTION__, '2.0', __('Usage of user levels by plugins and themes is deprecated. Use roles and capabilities instead.') );
+ $cap = $this->translate_level_to_cap( $cap );
+ }
+
+ $args = array_slice( func_get_args(), 1 );
+ $args = array_merge( array( $cap, $this->ID ), $args );
+ $caps = call_user_func_array( 'map_meta_cap', $args );
+
+ // Multisite super admin has all caps by definition, Unless specifically denied.
+ if ( is_multisite() && is_super_admin( $this->ID ) ) {
+ if ( in_array('do_not_allow', $caps) )
+ return false;
+ return true;
+ }
+
+ // Must have ALL requested caps
+ $capabilities = apply_filters( 'user_has_cap', $this->allcaps, $caps, $args );
+ $capabilities['exist'] = true; // Everyone is allowed to exist
+ foreach ( (array) $caps as $cap ) {
+ if ( empty( $capabilities[ $cap ] ) )
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert numeric level to level capability name.
+ *
+ * Prepends 'level_' to level number.
+ *
+ * @since 2.0.0
+ * @access public
+ *
+ * @param int $level Level number, 1 to 10.
+ * @return string
+ */
+ function translate_level_to_cap( $level ) {
+ return 'level_' . $level;
+ }
+
+ /**
+ * Set the blog to operate on. Defaults to the current blog.
+ *
+ * @since 3.0.0
+ *
+ * @param int $blog_id Optional Blog ID, defaults to current blog.
+ */
+ function for_blog( $blog_id = '' ) {
+ global $wpdb;
+ if ( ! empty( $blog_id ) )
+ $cap_key = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
+ else
+ $cap_key = '';
+ $this->_init_caps( $cap_key );
+ }
+}
+
+/**
+ * Map meta capabilities to primitive capabilities.
+ *
+ * This does not actually compare whether the user ID has the actual capability,
+ * just what the capability or capabilities are. Meta capability list value can
+ * be 'delete_user', 'edit_user', 'remove_user', 'promote_user', 'delete_post',
+ * 'delete_page', 'edit_post', 'edit_page', 'read_post', or 'read_page'.
+ *
+ * @since 2.0.0
+ *
+ * @param string $cap Capability name.
+ * @param int $user_id User ID.
+ * @return array Actual capabilities for meta capability.
+ */
+function map_meta_cap( $cap, $user_id ) {
+ $args = array_slice( func_get_args(), 2 );
+ $caps = array();
+
+ switch ( $cap ) {
+ case 'remove_user':
+ $caps[] = 'remove_users';
+ break;
+ case 'promote_user':
+ $caps[] = 'promote_users';
+ break;
+ case 'edit_user':
+ case 'edit_users':
+ // Allow user to edit itself
+ if ( 'edit_user' == $cap && isset( $args[0] ) && $user_id == $args[0] )
+ break;
+
+ // If multisite these caps are allowed only for super admins.
+ if ( is_multisite() && !is_super_admin( $user_id ) )
+ $caps[] = 'do_not_allow';
+ else
+ $caps[] = 'edit_users'; // edit_user maps to edit_users.
+ break;
+ case 'delete_post':
+ case 'delete_page':
+ $post = get_post( $args[0] );
+
+ if ( 'revision' == $post->post_type ) {
+ $post = get_post( $post->post_parent );
+ }
+
+ $post_type = get_post_type_object( $post->post_type );
+
+ if ( ! $post_type->map_meta_cap ) {
+ $caps[] = $post_type->cap->$cap;
+ // Prior to 3.1 we would re-call map_meta_cap here.
+ if ( 'delete_post' == $cap )
+ $cap = $post_type->cap->$cap;
+ break;
+ }
+
+ $post_author_id = $post->post_author;
+
+ // If no author set yet, default to current user for cap checks.
+ if ( ! $post_author_id )
+ $post_author_id = $user_id;
+
+ $post_author_data = $post_author_id == get_current_user_id() ? wp_get_current_user() : get_userdata( $post_author_id );
+
+ // If the user is the author...
+ if ( is_object( $post_author_data ) && $user_id == $post_author_data->ID ) {
+ // If the post is published...
+ if ( 'publish' == $post->post_status ) {
+ $caps[] = $post_type->cap->delete_published_posts;
+ } elseif ( 'trash' == $post->post_status ) {
+ if ('publish' == get_post_meta($post->ID, '_wp_trash_meta_status', true) )
+ $caps[] = $post_type->cap->delete_published_posts;
+ } else {
+ // If the post is draft...
+ $caps[] = $post_type->cap->delete_posts;
+ }
+ } else {
+ // The user is trying to edit someone else's post.
+ $caps[] = $post_type->cap->delete_others_posts;
+ // The post is published, extra cap required.
+ if ( 'publish' == $post->post_status )
+ $caps[] = $post_type->cap->delete_published_posts;
+ elseif ( 'private' == $post->post_status )
+ $caps[] = $post_type->cap->delete_private_posts;
+ }
+ break;
+ // edit_post breaks down to edit_posts, edit_published_posts, or
+ // edit_others_posts
+ case 'edit_post':
+ case 'edit_page':
+ $post = get_post( $args[0] );
+
+ if ( 'revision' == $post->post_type ) {
+ $post = get_post( $post->post_parent );
+ }
+
+ $post_type = get_post_type_object( $post->post_type );
+
+ if ( ! $post_type->map_meta_cap ) {
+ $caps[] = $post_type->cap->$cap;
+ // Prior to 3.1 we would re-call map_meta_cap here.
+ if ( 'edit_post' == $cap )
+ $cap = $post_type->cap->$cap;
+ break;
+ }
+
+ $post_author_id = $post->post_author;
+
+ // If no author set yet, default to current user for cap checks.
+ if ( ! $post_author_id )
+ $post_author_id = $user_id;
+
+ $post_author_data = $post_author_id == get_current_user_id() ? wp_get_current_user() : get_userdata( $post_author_id );
+
+ // If the user is the author...
+ if ( is_object( $post_author_data ) && $user_id == $post_author_data->ID ) {
+ // If the post is published...
+ if ( 'publish' == $post->post_status ) {
+ $caps[] = $post_type->cap->edit_published_posts;
+ } elseif ( 'trash' == $post->post_status ) {
+ if ('publish' == get_post_meta($post->ID, '_wp_trash_meta_status', true) )
+ $caps[] = $post_type->cap->edit_published_posts;
+ } else {
+ // If the post is draft...
+ $caps[] = $post_type->cap->edit_posts;
+ }
+ } else {
+ // The user is trying to edit someone else's post.
+ $caps[] = $post_type->cap->edit_others_posts;
+ // The post is published, extra cap required.
+ if ( 'publish' == $post->post_status )
+ $caps[] = $post_type->cap->edit_published_posts;
+ elseif ( 'private' == $post->post_status )
+ $caps[] = $post_type->cap->edit_private_posts;
+ }
+ break;
+ case 'read_post':
+ case 'read_page':
+ $post = get_post( $args[0] );
+
+ if ( 'revision' == $post->post_type ) {
+ $post = get_post( $post->post_parent );
+ }
+
+ $post_type = get_post_type_object( $post->post_type );
+
+ if ( ! $post_type->map_meta_cap ) {
+ $caps[] = $post_type->cap->$cap;
+ // Prior to 3.1 we would re-call map_meta_cap here.
+ if ( 'read_post' == $cap )
+ $cap = $post_type->cap->$cap;
+ break;
+ }
+
+ $status_obj = get_post_status_object( $post->post_status );
+ if ( $status_obj->public ) {
+ $caps[] = $post_type->cap->read;
+ break;
+ }
+
+ $post_author_id = $post->post_author;
+
+ // If no author set yet, default to current user for cap checks.
+ if ( ! $post_author_id )
+ $post_author_id = $user_id;
+
+ $post_author_data = $post_author_id == get_current_user_id() ? wp_get_current_user() : get_userdata( $post_author_id );
+
+ if ( is_object( $post_author_data ) && $user_id == $post_author_data->ID )
+ $caps[] = $post_type->cap->read;
+ elseif ( $status_obj->private )
+ $caps[] = $post_type->cap->read_private_posts;
+ else
+ $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
+ break;
+ case 'publish_post':
+ $post = get_post( $args[0] );
+ $post_type = get_post_type_object( $post->post_type );
+
+ $caps[] = $post_type->cap->publish_posts;
+ break;
+ case 'edit_post_meta':
+ case 'delete_post_meta':
+ case 'add_post_meta':
+ $post = get_post( $args[0] );
+ $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
+
+ $meta_key = isset( $args[ 1 ] ) ? $args[ 1 ] : false;
+
+ if ( $meta_key && has_filter( "auth_post_meta_{$meta_key}" ) ) {
+ $allowed = apply_filters( "auth_post_meta_{$meta_key}", false, $meta_key, $post->ID, $user_id, $cap, $caps );
+ if ( ! $allowed )
+ $caps[] = $cap;
+ } elseif ( $meta_key && is_protected_meta( $meta_key, 'post' ) ) {
+ $caps[] = $cap;
+ }
+ break;
+ case 'edit_comment':
+ $comment = get_comment( $args[0] );
+ $post = get_post( $comment->comment_post_ID );
+ $caps = map_meta_cap( 'edit_post', $user_id, $post->ID );
+ break;
+ case 'unfiltered_upload':
+ if ( defined('ALLOW_UNFILTERED_UPLOADS') && ALLOW_UNFILTERED_UPLOADS && ( !is_multisite() || is_super_admin( $user_id ) ) )
+ $caps[] = $cap;
+ else
+ $caps[] = 'do_not_allow';
+ break;
+ case 'unfiltered_html' :
+ // Disallow unfiltered_html for all users, even admins and super admins.
+ if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML )
+ $caps[] = 'do_not_allow';
+ elseif ( is_multisite() && ! is_super_admin( $user_id ) )
+ $caps[] = 'do_not_allow';
+ else
+ $caps[] = $cap;
+ break;
+ case 'edit_files':
+ case 'edit_plugins':
+ case 'edit_themes':
+ // Disallow the file editors.
+ if ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT )
+ $caps[] = 'do_not_allow';
+ elseif ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
+ $caps[] = 'do_not_allow';
+ elseif ( is_multisite() && ! is_super_admin( $user_id ) )
+ $caps[] = 'do_not_allow';
+ else
+ $caps[] = $cap;
+ break;
+ case 'update_plugins':
+ case 'delete_plugins':
+ case 'install_plugins':
+ case 'update_themes':
+ case 'delete_themes':
+ case 'install_themes':
+ case 'update_core':
+ // Disallow anything that creates, deletes, or updates core, plugin, or theme files.
+ // Files in uploads are excepted.
+ if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS )
+ $caps[] = 'do_not_allow';
+ elseif ( is_multisite() && ! is_super_admin( $user_id ) )
+ $caps[] = 'do_not_allow';
+ else
+ $caps[] = $cap;
+ break;
+ case 'activate_plugins':
+ $caps[] = $cap;
+ if ( is_multisite() ) {
+ // update_, install_, and delete_ are handled above with is_super_admin().
+ $menu_perms = get_site_option( 'menu_items', array() );
+ if ( empty( $menu_perms['plugins'] ) )
+ $caps[] = 'manage_network_plugins';
+ }
+ break;
+ case 'delete_user':
+ case 'delete_users':
+ // If multisite only super admins can delete users.
+ if ( is_multisite() && ! is_super_admin( $user_id ) )
+ $caps[] = 'do_not_allow';
+ else
+ $caps[] = 'delete_users'; // delete_user maps to delete_users.
+ break;
+ case 'create_users':
+ if ( !is_multisite() )
+ $caps[] = $cap;
+ elseif ( is_super_admin() || get_site_option( 'add_new_users' ) )
+ $caps[] = $cap;
+ else
+ $caps[] = 'do_not_allow';
+ break;
+ case 'manage_links' :
+ if ( get_option( 'link_manager_enabled' ) )
+ $caps[] = $cap;
+ else
+ $caps[] = 'do_not_allow';
+ break;
+ default:
+ // Handle meta capabilities for custom post types.
+ $post_type_meta_caps = _post_type_meta_capabilities();
+ if ( isset( $post_type_meta_caps[ $cap ] ) ) {
+ $args = array_merge( array( $post_type_meta_caps[ $cap ], $user_id ), $args );
+ return call_user_func_array( 'map_meta_cap', $args );
+ }
+
+ // If no meta caps match, return the original cap.
+ $caps[] = $cap;
+ }
+
+ return apply_filters('map_meta_cap', $caps, $cap, $user_id, $args);
+}
+
+/**
+ * Whether current user has capability or role.
+ *
+ * @since 2.0.0
+ *
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function current_user_can( $capability ) {
+ $current_user = wp_get_current_user();
+
+ if ( empty( $current_user ) )
+ return false;
+
+ $args = array_slice( func_get_args(), 1 );
+ $args = array_merge( array( $capability ), $args );
+
+ return call_user_func_array( array( $current_user, 'has_cap' ), $args );
+}
+
+/**
+ * Whether current user has a capability or role for a given blog.
+ *
+ * @since 3.0.0
+ *
+ * @param int $blog_id Blog ID
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function current_user_can_for_blog( $blog_id, $capability ) {
+ if ( is_multisite() )
+ switch_to_blog( $blog_id );
+
+ $current_user = wp_get_current_user();
+
+ if ( empty( $current_user ) )
+ return false;
+
+ $args = array_slice( func_get_args(), 2 );
+ $args = array_merge( array( $capability ), $args );
+
+ $can = call_user_func_array( array( $current_user, 'has_cap' ), $args );
+
+ if ( is_multisite() )
+ restore_current_blog();
+
+ return $can;
+}
+
+/**
+ * Whether author of supplied post has capability or role.
+ *
+ * @since 2.9.0
+ *
+ * @param int|object $post Post ID or post object.
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function author_can( $post, $capability ) {
+ if ( !$post = get_post($post) )
+ return false;
+
+ $author = get_userdata( $post->post_author );
+
+ if ( ! $author )
+ return false;
+
+ $args = array_slice( func_get_args(), 2 );
+ $args = array_merge( array( $capability ), $args );
+
+ return call_user_func_array( array( $author, 'has_cap' ), $args );
+}
+
+/**
+ * Whether a particular user has capability or role.
+ *
+ * @since 3.1.0
+ *
+ * @param int|object $user User ID or object.
+ * @param string $capability Capability or role name.
+ * @return bool
+ */
+function user_can( $user, $capability ) {
+ if ( ! is_object( $user ) )
+ $user = get_userdata( $user );
+
+ if ( ! $user || ! $user->exists() )
+ return false;
+
+ $args = array_slice( func_get_args(), 2 );
+ $args = array_merge( array( $capability ), $args );
+
+ return call_user_func_array( array( $user, 'has_cap' ), $args );
+}
+
+/**
+ * Retrieve role object.
+ *
+ * @see WP_Roles::get_role() Uses method to retrieve role object.
+ * @since 2.0.0
+ *
+ * @param string $role Role name.
+ * @return WP_Role|null WP_Role object if found, null if the role does not exist.
+ */
+function get_role( $role ) {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ return $wp_roles->get_role( $role );
+}
+
+/**
+ * Add role, if it does not exist.
+ *
+ * @see WP_Roles::add_role() Uses method to add role.
+ * @since 2.0.0
+ *
+ * @param string $role Role name.
+ * @param string $display_name Display name for role.
+ * @param array $capabilities List of capabilities, e.g. array( 'edit_posts' => true, 'delete_posts' => false );
+ * @return WP_Role|null WP_Role object if role is added, null if already exists.
+ */
+function add_role( $role, $display_name, $capabilities = array() ) {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ return $wp_roles->add_role( $role, $display_name, $capabilities );
+}
+
+/**
+ * Remove role, if it exists.
+ *
+ * @see WP_Roles::remove_role() Uses method to remove role.
+ * @since 2.0.0
+ *
+ * @param string $role Role name.
+ * @return null
+ */
+function remove_role( $role ) {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ return $wp_roles->remove_role( $role );
+}
+
+/**
+ * Retrieve a list of super admins.
+ *
+ * @since 3.0.0
+ *
+ * @uses $super_admins Super admins global variable, if set.
+ *
+ * @return array List of super admin logins
+ */
+function get_super_admins() {
+ global $super_admins;
+
+ if ( isset($super_admins) )
+ return $super_admins;
+ else
+ return get_site_option( 'site_admins', array('admin') );
+}
+
+/**
+ * Determine if user is a site admin.
+ *
+ * @since 3.0.0
+ *
+ * @param int $user_id (Optional) The ID of a user. Defaults to the current user.
+ * @return bool True if the user is a site admin.
+ */
+function is_super_admin( $user_id = false ) {
+ if ( ! $user_id || $user_id == get_current_user_id() )
+ $user = wp_get_current_user();
+ else
+ $user = get_userdata( $user_id );
+
+ if ( ! $user || ! $user->exists() )
+ return false;
+
+ if ( is_multisite() ) {
+ $super_admins = get_super_admins();
+ if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins ) )
+ return true;
+ } else {
+ if ( $user->has_cap('delete_users') )
+ return true;
+ }
+
+ return false;
+}
diff --git a/src/wp-includes/category-template.php b/src/wp-includes/category-template.php
new file mode 100644
index 0000000000..96a61cf35e
--- /dev/null
+++ b/src/wp-includes/category-template.php
@@ -0,0 +1,1191 @@
+<?php
+/**
+ * Category Template Tags and API.
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Retrieve category link URL.
+ *
+ * @since 1.0.0
+ * @see get_term_link()
+ *
+ * @param int|object $category Category ID or object.
+ * @return string Link on success, empty string if category does not exist.
+ */
+function get_category_link( $category ) {
+ if ( ! is_object( $category ) )
+ $category = (int) $category;
+
+ $category = get_term_link( $category, 'category' );
+
+ if ( is_wp_error( $category ) )
+ return '';
+
+ return $category;
+}
+
+/**
+ * Retrieve category parents with separator.
+ *
+ * @since 1.2.0
+ *
+ * @param int $id Category ID.
+ * @param bool $link Optional, default is false. Whether to format with link.
+ * @param string $separator Optional, default is '/'. How to separate categories.
+ * @param bool $nicename Optional, default is false. Whether to use nice name for display.
+ * @param array $visited Optional. Already linked to categories to prevent duplicates.
+ * @return string|WP_Error A list of category parents on success, WP_Error on failure.
+ */
+function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
+ $chain = '';
+ $parent = get_category( $id );
+ if ( is_wp_error( $parent ) )
+ return $parent;
+
+ if ( $nicename )
+ $name = $parent->slug;
+ else
+ $name = $parent->name;
+
+ if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
+ $visited[] = $parent->parent;
+ $chain .= get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
+ }
+
+ if ( $link )
+ $chain .= '<a href="' . esc_url( get_category_link( $parent->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $parent->name ) ) . '">'.$name.'</a>' . $separator;
+ else
+ $chain .= $name.$separator;
+ return $chain;
+}
+
+/**
+ * Retrieve post categories.
+ *
+ * @since 0.71
+ * @uses $post
+ *
+ * @param int $id Optional, default to current post ID. The post ID.
+ * @return array
+ */
+function get_the_category( $id = false ) {
+ $categories = get_the_terms( $id, 'category' );
+ if ( ! $categories || is_wp_error( $categories ) )
+ $categories = array();
+
+ $categories = array_values( $categories );
+
+ foreach ( array_keys( $categories ) as $key ) {
+ _make_cat_compat( $categories[$key] );
+ }
+
+ // Filter name is plural because we return alot of categories (possibly more than #13237) not just one
+ return apply_filters( 'get_the_categories', $categories );
+}
+
+/**
+ * Sort categories by name.
+ *
+ * Used by usort() as a callback, should not be used directly. Can actually be
+ * used to sort any term object.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param object $a
+ * @param object $b
+ * @return int
+ */
+function _usort_terms_by_name( $a, $b ) {
+ return strcmp( $a->name, $b->name );
+}
+
+/**
+ * Sort categories by ID.
+ *
+ * Used by usort() as a callback, should not be used directly. Can actually be
+ * used to sort any term object.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param object $a
+ * @param object $b
+ * @return int
+ */
+function _usort_terms_by_ID( $a, $b ) {
+ if ( $a->term_id > $b->term_id )
+ return 1;
+ elseif ( $a->term_id < $b->term_id )
+ return -1;
+ else
+ return 0;
+}
+
+/**
+ * Retrieve category name based on category ID.
+ *
+ * @since 0.71
+ *
+ * @param int $cat_ID Category ID.
+ * @return string|WP_Error Category name on success, WP_Error on failure.
+ */
+function get_the_category_by_ID( $cat_ID ) {
+ $cat_ID = (int) $cat_ID;
+ $category = get_category( $cat_ID );
+ if ( is_wp_error( $category ) )
+ return $category;
+ return $category->name;
+}
+
+/**
+ * Retrieve category list in either HTML list or custom format.
+ *
+ * @since 1.5.1
+ *
+ * @param string $separator Optional, default is empty string. Separator for between the categories.
+ * @param string $parents Optional. How to display the parents.
+ * @param int $post_id Optional. Post ID to retrieve categories.
+ * @return string
+ */
+function get_the_category_list( $separator = '', $parents='', $post_id = false ) {
+ global $wp_rewrite;
+ if ( ! is_object_in_taxonomy( get_post_type( $post_id ), 'category' ) )
+ return apply_filters( 'the_category', '', $separator, $parents );
+
+ $categories = get_the_category( $post_id );
+ if ( empty( $categories ) )
+ return apply_filters( 'the_category', __( 'Uncategorized' ), $separator, $parents );
+
+ $rel = ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) ? 'rel="category tag"' : 'rel="category"';
+
+ $thelist = '';
+ if ( '' == $separator ) {
+ $thelist .= '<ul class="post-categories">';
+ foreach ( $categories as $category ) {
+ $thelist .= "\n\t<li>";
+ switch ( strtolower( $parents ) ) {
+ case 'multiple':
+ if ( $category->parent )
+ $thelist .= get_category_parents( $category->parent, true, $separator );
+ $thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
+ break;
+ case 'single':
+ $thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>';
+ if ( $category->parent )
+ $thelist .= get_category_parents( $category->parent, false, $separator );
+ $thelist .= $category->name.'</a></li>';
+ break;
+ case '':
+ default:
+ $thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
+ }
+ }
+ $thelist .= '</ul>';
+ } else {
+ $i = 0;
+ foreach ( $categories as $category ) {
+ if ( 0 < $i )
+ $thelist .= $separator;
+ switch ( strtolower( $parents ) ) {
+ case 'multiple':
+ if ( $category->parent )
+ $thelist .= get_category_parents( $category->parent, true, $separator );
+ $thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a>';
+ break;
+ case 'single':
+ $thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>';
+ if ( $category->parent )
+ $thelist .= get_category_parents( $category->parent, false, $separator );
+ $thelist .= "$category->name</a>";
+ break;
+ case '':
+ default:
+ $thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a>';
+ }
+ ++$i;
+ }
+ }
+ return apply_filters( 'the_category', $thelist, $separator, $parents );
+}
+
+/**
+ * Check if the current post in within any of the given categories.
+ *
+ * The given categories are checked against the post's categories' term_ids, names and slugs.
+ * Categories given as integers will only be checked against the post's categories' term_ids.
+ *
+ * Prior to v2.5 of WordPress, category names were not supported.
+ * Prior to v2.7, category slugs were not supported.
+ * Prior to v2.7, only one category could be compared: in_category( $single_category ).
+ * Prior to v2.7, this function could only be used in the WordPress Loop.
+ * As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
+ *
+ * @since 1.2.0
+ *
+ * @param int|string|array $category Category ID, name or slug, or array of said.
+ * @param int|object $post Optional. Post to check instead of the current post. (since 2.7.0)
+ * @return bool True if the current post is in any of the given categories.
+ */
+function in_category( $category, $post = null ) {
+ if ( empty( $category ) )
+ return false;
+
+ return has_term( $category, 'category', $post );
+}
+
+/**
+ * Display the category list for the post.
+ *
+ * @since 0.71
+ *
+ * @param string $separator Optional, default is empty string. Separator for between the categories.
+ * @param string $parents Optional. How to display the parents.
+ * @param int $post_id Optional. Post ID to retrieve categories.
+ */
+function the_category( $separator = '', $parents='', $post_id = false ) {
+ echo get_the_category_list( $separator, $parents, $post_id );
+}
+
+/**
+ * Retrieve category description.
+ *
+ * @since 1.0.0
+ *
+ * @param int $category Optional. Category ID. Will use global category ID by default.
+ * @return string Category description, available.
+ */
+function category_description( $category = 0 ) {
+ return term_description( $category, 'category' );
+}
+
+/**
+ * Display or retrieve the HTML dropdown list of categories.
+ *
+ * The list of arguments is below:
+ * 'show_option_all' (string) - Text to display for showing all categories.
+ * 'show_option_none' (string) - Text to display for showing no categories.
+ * 'orderby' (string) default is 'ID' - What column to use for ordering the
+ * categories.
+ * 'order' (string) default is 'ASC' - What direction to order categories.
+ * 'show_count' (bool|int) default is 0 - Whether to show how many posts are
+ * in the category.
+ * 'hide_empty' (bool|int) default is 1 - Whether to hide categories that
+ * don't have any posts attached to them.
+ * 'child_of' (int) default is 0 - See {@link get_categories()}.
+ * 'exclude' (string) - See {@link get_categories()}.
+ * 'echo' (bool|int) default is 1 - Whether to display or retrieve content.
+ * 'depth' (int) - The max depth.
+ * 'tab_index' (int) - Tab index for select element.
+ * 'name' (string) - The name attribute value for select element.
+ * 'id' (string) - The ID attribute value for select element. Defaults to name if omitted.
+ * 'class' (string) - The class attribute value for select element.
+ * 'selected' (int) - Which category ID is selected.
+ * 'taxonomy' (string) - The name of the taxonomy to retrieve. Defaults to category.
+ *
+ * The 'hierarchical' argument, which is disabled by default, will override the
+ * depth argument, unless it is true. When the argument is false, it will
+ * display all of the categories. When it is enabled it will use the value in
+ * the 'depth' argument.
+ *
+ * @since 2.1.0
+ *
+ * @param string|array $args Optional. Override default arguments.
+ * @return string HTML content only if 'echo' argument is 0.
+ */
+function wp_dropdown_categories( $args = '' ) {
+ $defaults = array(
+ 'show_option_all' => '', 'show_option_none' => '',
+ 'orderby' => 'id', 'order' => 'ASC',
+ 'show_count' => 0,
+ 'hide_empty' => 1, 'child_of' => 0,
+ 'exclude' => '', 'echo' => 1,
+ 'selected' => 0, 'hierarchical' => 0,
+ 'name' => 'cat', 'id' => '',
+ 'class' => 'postform', 'depth' => 0,
+ 'tab_index' => 0, 'taxonomy' => 'category',
+ 'hide_if_empty' => false
+ );
+
+ $defaults['selected'] = ( is_category() ) ? get_query_var( 'cat' ) : 0;
+
+ // Back compat.
+ if ( isset( $args['type'] ) && 'link' == $args['type'] ) {
+ _deprecated_argument( __FUNCTION__, '3.0', '' );
+ $args['taxonomy'] = 'link_category';
+ }
+
+ $r = wp_parse_args( $args, $defaults );
+
+ if ( !isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] ) {
+ $r['pad_counts'] = true;
+ }
+
+ extract( $r );
+
+ $tab_index_attribute = '';
+ if ( (int) $tab_index > 0 )
+ $tab_index_attribute = " tabindex=\"$tab_index\"";
+
+ $categories = get_terms( $taxonomy, $r );
+ $name = esc_attr( $name );
+ $class = esc_attr( $class );
+ $id = $id ? esc_attr( $id ) : $name;
+
+ if ( ! $r['hide_if_empty'] || ! empty($categories) )
+ $output = "<select name='$name' id='$id' class='$class' $tab_index_attribute>\n";
+ else
+ $output = '';
+
+ if ( empty($categories) && ! $r['hide_if_empty'] && !empty($show_option_none) ) {
+ $show_option_none = apply_filters( 'list_cats', $show_option_none );
+ $output .= "\t<option value='-1' selected='selected'>$show_option_none</option>\n";
+ }
+
+ if ( ! empty( $categories ) ) {
+
+ if ( $show_option_all ) {
+ $show_option_all = apply_filters( 'list_cats', $show_option_all );
+ $selected = ( '0' === strval($r['selected']) ) ? " selected='selected'" : '';
+ $output .= "\t<option value='0'$selected>$show_option_all</option>\n";
+ }
+
+ if ( $show_option_none ) {
+ $show_option_none = apply_filters( 'list_cats', $show_option_none );
+ $selected = ( '-1' === strval($r['selected']) ) ? " selected='selected'" : '';
+ $output .= "\t<option value='-1'$selected>$show_option_none</option>\n";
+ }
+
+ if ( $hierarchical )
+ $depth = $r['depth']; // Walk the full depth.
+ else
+ $depth = -1; // Flat.
+
+ $output .= walk_category_dropdown_tree( $categories, $depth, $r );
+ }
+
+ if ( ! $r['hide_if_empty'] || ! empty($categories) )
+ $output .= "</select>\n";
+
+ $output = apply_filters( 'wp_dropdown_cats', $output );
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+/**
+ * Display or retrieve the HTML list of categories.
+ *
+ * The list of arguments is below:
+ * 'show_option_all' (string) - Text to display for showing all categories.
+ * 'orderby' (string) default is 'ID' - What column to use for ordering the
+ * categories.
+ * 'order' (string) default is 'ASC' - What direction to order categories.
+ * 'show_count' (bool|int) default is 0 - Whether to show how many posts are
+ * in the category.
+ * 'hide_empty' (bool|int) default is 1 - Whether to hide categories that
+ * don't have any posts attached to them.
+ * 'use_desc_for_title' (bool|int) default is 1 - Whether to use the
+ * description instead of the category title.
+ * 'feed' - See {@link get_categories()}.
+ * 'feed_type' - See {@link get_categories()}.
+ * 'feed_image' - See {@link get_categories()}.
+ * 'child_of' (int) default is 0 - See {@link get_categories()}.
+ * 'exclude' (string) - See {@link get_categories()}.
+ * 'exclude_tree' (string) - See {@link get_categories()}.
+ * 'echo' (bool|int) default is 1 - Whether to display or retrieve content.
+ * 'current_category' (int) - See {@link get_categories()}.
+ * 'hierarchical' (bool) - See {@link get_categories()}.
+ * 'title_li' (string) - See {@link get_categories()}.
+ * 'depth' (int) - The max depth.
+ *
+ * @since 2.1.0
+ *
+ * @param string|array $args Optional. Override default arguments.
+ * @return string HTML content only if 'echo' argument is 0.
+ */
+function wp_list_categories( $args = '' ) {
+ $defaults = array(
+ 'show_option_all' => '', 'show_option_none' => __('No categories'),
+ 'orderby' => 'name', 'order' => 'ASC',
+ 'style' => 'list',
+ 'show_count' => 0, 'hide_empty' => 1,
+ 'use_desc_for_title' => 1, 'child_of' => 0,
+ 'feed' => '', 'feed_type' => '',
+ 'feed_image' => '', 'exclude' => '',
+ 'exclude_tree' => '', 'current_category' => 0,
+ 'hierarchical' => true, 'title_li' => __( 'Categories' ),
+ 'echo' => 1, 'depth' => 0,
+ 'taxonomy' => 'category'
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ if ( !isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] )
+ $r['pad_counts'] = true;
+
+ if ( true == $r['hierarchical'] ) {
+ $r['exclude_tree'] = $r['exclude'];
+ $r['exclude'] = '';
+ }
+
+ if ( !isset( $r['class'] ) )
+ $r['class'] = ( 'category' == $r['taxonomy'] ) ? 'categories' : $r['taxonomy'];
+
+ extract( $r );
+
+ if ( !taxonomy_exists($taxonomy) )
+ return false;
+
+ $categories = get_categories( $r );
+
+ $output = '';
+ if ( $title_li && 'list' == $style )
+ $output = '<li class="' . esc_attr( $class ) . '">' . $title_li . '<ul>';
+
+ if ( empty( $categories ) ) {
+ if ( ! empty( $show_option_none ) ) {
+ if ( 'list' == $style )
+ $output .= '<li>' . $show_option_none . '</li>';
+ else
+ $output .= $show_option_none;
+ }
+ } else {
+ if ( ! empty( $show_option_all ) ) {
+ $posts_page = ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) ) ? get_permalink( get_option( 'page_for_posts' ) ) : home_url( '/' );
+ $posts_page = esc_url( $posts_page );
+ if ( 'list' == $style )
+ $output .= "<li><a href='$posts_page'>$show_option_all</a></li>";
+ else
+ $output .= "<a href='$posts_page'>$show_option_all</a>";
+ }
+
+ if ( empty( $r['current_category'] ) && ( is_category() || is_tax() || is_tag() ) ) {
+ $current_term_object = get_queried_object();
+ if ( $r['taxonomy'] == $current_term_object->taxonomy )
+ $r['current_category'] = get_queried_object_id();
+ }
+
+ if ( $hierarchical )
+ $depth = $r['depth'];
+ else
+ $depth = -1; // Flat.
+
+ $output .= walk_category_tree( $categories, $depth, $r );
+ }
+
+ if ( $title_li && 'list' == $style )
+ $output .= '</ul></li>';
+
+ $output = apply_filters( 'wp_list_categories', $output, $args );
+
+ if ( $echo )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Display tag cloud.
+ *
+ * The text size is set by the 'smallest' and 'largest' arguments, which will
+ * use the 'unit' argument value for the CSS text size unit. The 'format'
+ * argument can be 'flat' (default), 'list', or 'array'. The flat value for the
+ * 'format' argument will separate tags with spaces. The list value for the
+ * 'format' argument will format the tags in a UL HTML list. The array value for
+ * the 'format' argument will return in PHP array type format.
+ *
+ * The 'orderby' argument will accept 'name' or 'count' and defaults to 'name'.
+ * The 'order' is the direction to sort, defaults to 'ASC' and can be 'DESC'.
+ *
+ * The 'number' argument is how many tags to return. By default, the limit will
+ * be to return the top 45 tags in the tag cloud list.
+ *
+ * The 'topic_count_text_callback' argument is a function, which, given the count
+ * of the posts with that tag, returns a text for the tooltip of the tag link.
+ *
+ * The 'exclude' and 'include' arguments are used for the {@link get_tags()}
+ * function. Only one should be used, because only one will be used and the
+ * other ignored, if they are both set.
+ *
+ * @since 2.3.0
+ *
+ * @param array|string $args Optional. Override default arguments.
+ * @return array Generated tag cloud, only if no failures and 'array' is set for the 'format' argument.
+ */
+function wp_tag_cloud( $args = '' ) {
+ $defaults = array(
+ 'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 45,
+ 'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
+ 'exclude' => '', 'include' => '', 'link' => 'view', 'taxonomy' => 'post_tag', 'echo' => true
+ );
+ $args = wp_parse_args( $args, $defaults );
+
+ $tags = get_terms( $args['taxonomy'], array_merge( $args, array( 'orderby' => 'count', 'order' => 'DESC' ) ) ); // Always query top tags
+
+ if ( empty( $tags ) || is_wp_error( $tags ) )
+ return;
+
+ foreach ( $tags as $key => $tag ) {
+ if ( 'edit' == $args['link'] )
+ $link = get_edit_tag_link( $tag->term_id, $tag->taxonomy );
+ else
+ $link = get_term_link( intval($tag->term_id), $tag->taxonomy );
+ if ( is_wp_error( $link ) )
+ return false;
+
+ $tags[ $key ]->link = $link;
+ $tags[ $key ]->id = $tag->term_id;
+ }
+
+ $return = wp_generate_tag_cloud( $tags, $args ); // Here's where those top tags get sorted according to $args
+
+ $return = apply_filters( 'wp_tag_cloud', $return, $args );
+
+ if ( 'array' == $args['format'] || empty($args['echo']) )
+ return $return;
+
+ echo $return;
+}
+
+/**
+ * Default text for tooltip for tag links
+ *
+ * @param integer $count number of posts with that tag
+ * @return string text for the tooltip of a tag link.
+ */
+function default_topic_count_text( $count ) {
+ return sprintf( _n('%s topic', '%s topics', $count), number_format_i18n( $count ) );
+}
+
+/**
+ * Default topic count scaling for tag links
+ *
+ * @param integer $count number of posts with that tag
+ * @return integer scaled count
+ */
+function default_topic_count_scale( $count ) {
+ return round(log10($count + 1) * 100);
+}
+
+/**
+ * Generates a tag cloud (heatmap) from provided data.
+ *
+ * The text size is set by the 'smallest' and 'largest' arguments, which will
+ * use the 'unit' argument value for the CSS text size unit. The 'format'
+ * argument can be 'flat' (default), 'list', or 'array'. The flat value for the
+ * 'format' argument will separate tags with spaces. The list value for the
+ * 'format' argument will format the tags in a UL HTML list. The array value for
+ * the 'format' argument will return in PHP array type format.
+ *
+ * The 'tag_cloud_sort' filter allows you to override the sorting.
+ * Passed to the filter: $tags array and $args array, has to return the $tags array
+ * after sorting it.
+ *
+ * The 'orderby' argument will accept 'name' or 'count' and defaults to 'name'.
+ * The 'order' is the direction to sort, defaults to 'ASC' and can be 'DESC' or
+ * 'RAND'.
+ *
+ * The 'number' argument is how many tags to return. By default, the limit will
+ * be to return the entire tag cloud list.
+ *
+ * The 'topic_count_text_callback' argument is a function, which given the count
+ * of the posts with that tag returns a text for the tooltip of the tag link.
+ *
+ * @todo Complete functionality.
+ * @since 2.3.0
+ *
+ * @param array $tags List of tags.
+ * @param string|array $args Optional, override default arguments.
+ * @return string
+ */
+function wp_generate_tag_cloud( $tags, $args = '' ) {
+ $defaults = array(
+ 'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 0,
+ 'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
+ 'topic_count_text_callback' => 'default_topic_count_text',
+ 'topic_count_scale_callback' => 'default_topic_count_scale', 'filter' => 1,
+ );
+
+ if ( !isset( $args['topic_count_text_callback'] ) && isset( $args['single_text'] ) && isset( $args['multiple_text'] ) ) {
+ $body = 'return sprintf (
+ _n(' . var_export($args['single_text'], true) . ', ' . var_export($args['multiple_text'], true) . ', $count),
+ number_format_i18n( $count ));';
+ $args['topic_count_text_callback'] = create_function('$count', $body);
+ }
+
+ $args = wp_parse_args( $args, $defaults );
+ extract( $args );
+
+ if ( empty( $tags ) )
+ return;
+
+ $tags_sorted = apply_filters( 'tag_cloud_sort', $tags, $args );
+ if ( $tags_sorted != $tags ) { // the tags have been sorted by a plugin
+ $tags = $tags_sorted;
+ unset($tags_sorted);
+ } else {
+ if ( 'RAND' == $order ) {
+ shuffle($tags);
+ } else {
+ // SQL cannot save you; this is a second (potentially different) sort on a subset of data.
+ if ( 'name' == $orderby )
+ uasort( $tags, '_wp_object_name_sort_cb' );
+ else
+ uasort( $tags, '_wp_object_count_sort_cb' );
+
+ if ( 'DESC' == $order )
+ $tags = array_reverse( $tags, true );
+ }
+ }
+
+ if ( $number > 0 )
+ $tags = array_slice($tags, 0, $number);
+
+ $counts = array();
+ $real_counts = array(); // For the alt tag
+ foreach ( (array) $tags as $key => $tag ) {
+ $real_counts[ $key ] = $tag->count;
+ $counts[ $key ] = $topic_count_scale_callback($tag->count);
+ }
+
+ $min_count = min( $counts );
+ $spread = max( $counts ) - $min_count;
+ if ( $spread <= 0 )
+ $spread = 1;
+ $font_spread = $largest - $smallest;
+ if ( $font_spread < 0 )
+ $font_spread = 1;
+ $font_step = $font_spread / $spread;
+
+ $a = array();
+
+ foreach ( $tags as $key => $tag ) {
+ $count = $counts[ $key ];
+ $real_count = $real_counts[ $key ];
+ $tag_link = '#' != $tag->link ? esc_url( $tag->link ) : '#';
+ $tag_id = isset($tags[ $key ]->id) ? $tags[ $key ]->id : $key;
+ $tag_name = $tags[ $key ]->name;
+ $a[] = "<a href='$tag_link' class='tag-link-$tag_id' title='" . esc_attr( call_user_func( $topic_count_text_callback, $real_count, $tag, $args ) ) . "' style='font-size: " .
+ str_replace( ',', '.', ( $smallest + ( ( $count - $min_count ) * $font_step ) ) )
+ . "$unit;'>$tag_name</a>";
+ }
+
+ switch ( $format ) :
+ case 'array' :
+ $return =& $a;
+ break;
+ case 'list' :
+ $return = "<ul class='wp-tag-cloud'>\n\t<li>";
+ $return .= join( "</li>\n\t<li>", $a );
+ $return .= "</li>\n</ul>\n";
+ break;
+ default :
+ $return = join( $separator, $a );
+ break;
+ endswitch;
+
+ if ( $filter )
+ return apply_filters( 'wp_generate_tag_cloud', $return, $tags, $args );
+ else
+ return $return;
+}
+
+/**
+ * Callback for comparing objects based on name
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _wp_object_name_sort_cb( $a, $b ) {
+ return strnatcasecmp( $a->name, $b->name );
+}
+
+/**
+ * Callback for comparing objects based on count
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _wp_object_count_sort_cb( $a, $b ) {
+ return ( $a->count > $b->count );
+}
+
+//
+// Helper functions
+//
+
+/**
+ * Retrieve HTML list content for category list.
+ *
+ * @uses Walker_Category to create HTML list content.
+ * @since 2.1.0
+ * @see Walker_Category::walk() for parameters and return description.
+ */
+function walk_category_tree() {
+ $args = func_get_args();
+ // the user's options are the third parameter
+ if ( empty($args[2]['walker']) || !is_a($args[2]['walker'], 'Walker') )
+ $walker = new Walker_Category;
+ else
+ $walker = $args[2]['walker'];
+
+ return call_user_func_array(array( &$walker, 'walk' ), $args );
+}
+
+/**
+ * Retrieve HTML dropdown (select) content for category list.
+ *
+ * @uses Walker_CategoryDropdown to create HTML dropdown content.
+ * @since 2.1.0
+ * @see Walker_CategoryDropdown::walk() for parameters and return description.
+ */
+function walk_category_dropdown_tree() {
+ $args = func_get_args();
+ // the user's options are the third parameter
+ if ( empty($args[2]['walker']) || !is_a($args[2]['walker'], 'Walker') )
+ $walker = new Walker_CategoryDropdown;
+ else
+ $walker = $args[2]['walker'];
+
+ return call_user_func_array(array( &$walker, 'walk' ), $args );
+}
+
+/**
+ * Create HTML list of categories.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_Category extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'category';
+
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
+
+ /**
+ * @see Walker::start_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of category. Used for tab indentation.
+ * @param array $args Will only append content if style argument value is 'list'.
+ */
+ function start_lvl( &$output, $depth = 0, $args = array() ) {
+ if ( 'list' != $args['style'] )
+ return;
+
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent<ul class='children'>\n";
+ }
+
+ /**
+ * @see Walker::end_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of category. Used for tab indentation.
+ * @param array $args Will only append content if style argument value is 'list'.
+ */
+ function end_lvl( &$output, $depth = 0, $args = array() ) {
+ if ( 'list' != $args['style'] )
+ return;
+
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent</ul>\n";
+ }
+
+ /**
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $category Category data object.
+ * @param int $depth Depth of category in reference to parents.
+ * @param array $args
+ */
+ function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
+ extract($args);
+
+ $cat_name = esc_attr( $category->name );
+ $cat_name = apply_filters( 'list_cats', $cat_name, $category );
+ $link = '<a href="' . esc_url( get_term_link($category) ) . '" ';
+ if ( $use_desc_for_title == 0 || empty($category->description) )
+ $link .= 'title="' . esc_attr( sprintf(__( 'View all posts filed under %s' ), $cat_name) ) . '"';
+ else
+ $link .= 'title="' . esc_attr( strip_tags( apply_filters( 'category_description', $category->description, $category ) ) ) . '"';
+ $link .= '>';
+ $link .= $cat_name . '</a>';
+
+ if ( !empty($feed_image) || !empty($feed) ) {
+ $link .= ' ';
+
+ if ( empty($feed_image) )
+ $link .= '(';
+
+ $link .= '<a href="' . esc_url( get_term_feed_link( $category->term_id, $category->taxonomy, $feed_type ) ) . '"';
+
+ if ( empty($feed) ) {
+ $alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
+ } else {
+ $title = ' title="' . $feed . '"';
+ $alt = ' alt="' . $feed . '"';
+ $name = $feed;
+ $link .= $title;
+ }
+
+ $link .= '>';
+
+ if ( empty($feed_image) )
+ $link .= $name;
+ else
+ $link .= "<img src='$feed_image'$alt$title" . ' />';
+
+ $link .= '</a>';
+
+ if ( empty($feed_image) )
+ $link .= ')';
+ }
+
+ if ( !empty($show_count) )
+ $link .= ' (' . intval($category->count) . ')';
+
+ if ( 'list' == $args['style'] ) {
+ $output .= "\t<li";
+ $class = 'cat-item cat-item-' . $category->term_id;
+ if ( !empty($current_category) ) {
+ $_current_category = get_term( $current_category, $category->taxonomy );
+ if ( $category->term_id == $current_category )
+ $class .= ' current-cat';
+ elseif ( $category->term_id == $_current_category->parent )
+ $class .= ' current-cat-parent';
+ }
+ $output .= ' class="' . $class . '"';
+ $output .= ">$link\n";
+ } else {
+ $output .= "\t$link<br />\n";
+ }
+ }
+
+ /**
+ * @see Walker::end_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Not used.
+ * @param int $depth Depth of category. Not used.
+ * @param array $args Only uses 'list' for whether should append to output.
+ */
+ function end_el( &$output, $page, $depth = 0, $args = array() ) {
+ if ( 'list' != $args['style'] )
+ return;
+
+ $output .= "</li>\n";
+ }
+
+}
+
+/**
+ * Create HTML dropdown list of Categories.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_CategoryDropdown extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'category';
+
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
+
+ /**
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $category Category data object.
+ * @param int $depth Depth of category. Used for padding.
+ * @param array $args Uses 'selected' and 'show_count' keys, if they exist.
+ */
+ function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
+ $pad = str_repeat('&nbsp;', $depth * 3);
+
+ $cat_name = apply_filters('list_cats', $category->name, $category);
+ $output .= "\t<option class=\"level-$depth\" value=\"".$category->term_id."\"";
+ if ( $category->term_id == $args['selected'] )
+ $output .= ' selected="selected"';
+ $output .= '>';
+ $output .= $pad.$cat_name;
+ if ( $args['show_count'] )
+ $output .= '&nbsp;&nbsp;('. $category->count .')';
+ $output .= "</option>\n";
+ }
+}
+
+//
+// Tags
+//
+
+/**
+ * Retrieve the link to the tag.
+ *
+ * @since 2.3.0
+ * @see get_term_link()
+ *
+ * @param int|object $tag Tag ID or object.
+ * @return string Link on success, empty string if tag does not exist.
+ */
+function get_tag_link( $tag ) {
+ if ( ! is_object( $tag ) )
+ $tag = (int) $tag;
+
+ $tag = get_term_link( $tag, 'post_tag' );
+
+ if ( is_wp_error( $tag ) )
+ return '';
+
+ return $tag;
+}
+
+/**
+ * Retrieve the tags for a post.
+ *
+ * @since 2.3.0
+ * @uses apply_filters() Calls 'get_the_tags' filter on the list of post tags.
+ *
+ * @param int $id Post ID.
+ * @return array|bool Array of tag objects on success, false on failure.
+ */
+function get_the_tags( $id = 0 ) {
+ return apply_filters( 'get_the_tags', get_the_terms( $id, 'post_tag' ) );
+}
+
+/**
+ * Retrieve the tags for a post formatted as a string.
+ *
+ * @since 2.3.0
+ * @uses apply_filters() Calls 'the_tags' filter on string list of tags.
+ *
+ * @param string $before Optional. Before tags.
+ * @param string $sep Optional. Between tags.
+ * @param string $after Optional. After tags.
+ * @param int $id Optional. Post ID. Defaults to the current post.
+ * @return string|bool|WP_Error A list of tags on success, false or WP_Error on failure.
+ */
+function get_the_tag_list( $before = '', $sep = '', $after = '', $id = 0 ) {
+ return apply_filters( 'the_tags', get_the_term_list( $id, 'post_tag', $before, $sep, $after ), $before, $sep, $after, $id );
+}
+
+/**
+ * Retrieve the tags for a post.
+ *
+ * @since 2.3.0
+ *
+ * @param string $before Optional. Before list.
+ * @param string $sep Optional. Separate items using this.
+ * @param string $after Optional. After list.
+ */
+function the_tags( $before = null, $sep = ', ', $after = '' ) {
+ if ( null === $before )
+ $before = __('Tags: ');
+ echo get_the_tag_list($before, $sep, $after);
+}
+
+/**
+ * Retrieve tag description.
+ *
+ * @since 2.8
+ *
+ * @param int $tag Optional. Tag ID. Will use global tag ID by default.
+ * @return string Tag description, available.
+ */
+function tag_description( $tag = 0 ) {
+ return term_description( $tag );
+}
+
+/**
+ * Retrieve term description.
+ *
+ * @since 2.8
+ *
+ * @param int $term Optional. Term ID. Will use global term ID by default.
+ * @param string $taxonomy Optional taxonomy name. Defaults to 'post_tag'.
+ * @return string Term description, available.
+ */
+function term_description( $term = 0, $taxonomy = 'post_tag' ) {
+ if ( !$term && ( is_tax() || is_tag() || is_category() ) ) {
+ $term = get_queried_object();
+ $taxonomy = $term->taxonomy;
+ $term = $term->term_id;
+ }
+ $description = get_term_field( 'description', $term, $taxonomy );
+ return is_wp_error( $description ) ? '' : $description;
+}
+
+/**
+ * Retrieve the terms of the taxonomy that are attached to the post.
+ *
+ * @since 2.5.0
+ *
+ * @param int|object $post Post ID or object.
+ * @param string $taxonomy Taxonomy name.
+ * @return array|bool|WP_Error Array of term objects on success, false or WP_Error on failure.
+ */
+function get_the_terms( $post, $taxonomy ) {
+ if ( ! $post = get_post( $post ) )
+ return false;
+
+ $terms = get_object_term_cache( $post->ID, $taxonomy );
+ if ( false === $terms ) {
+ $terms = wp_get_object_terms( $post->ID, $taxonomy );
+ wp_cache_add($post->ID, $terms, $taxonomy . '_relationships');
+ }
+
+ $terms = apply_filters( 'get_the_terms', $terms, $post->ID, $taxonomy );
+
+ if ( empty( $terms ) )
+ return false;
+
+ return $terms;
+}
+
+/**
+ * Retrieve a post's terms as a list with specified format.
+ *
+ * @since 2.5.0
+ *
+ * @param int $id Post ID.
+ * @param string $taxonomy Taxonomy name.
+ * @param string $before Optional. Before list.
+ * @param string $sep Optional. Separate items using this.
+ * @param string $after Optional. After list.
+ * @return string|bool|WP_Error A list of terms on success, false or WP_Error on failure.
+ */
+function get_the_term_list( $id, $taxonomy, $before = '', $sep = '', $after = '' ) {
+ $terms = get_the_terms( $id, $taxonomy );
+
+ if ( is_wp_error( $terms ) )
+ return $terms;
+
+ if ( empty( $terms ) )
+ return false;
+
+ foreach ( $terms as $term ) {
+ $link = get_term_link( $term, $taxonomy );
+ if ( is_wp_error( $link ) )
+ return $link;
+ $term_links[] = '<a href="' . esc_url( $link ) . '" rel="tag">' . $term->name . '</a>';
+ }
+
+ $term_links = apply_filters( "term_links-$taxonomy", $term_links );
+
+ return $before . join( $sep, $term_links ) . $after;
+}
+
+/**
+ * Display the terms in a list.
+ *
+ * @since 2.5.0
+ *
+ * @param int $id Post ID.
+ * @param string $taxonomy Taxonomy name.
+ * @param string $before Optional. Before list.
+ * @param string $sep Optional. Separate items using this.
+ * @param string $after Optional. After list.
+ * @return null|bool False on WordPress error. Returns null when displaying.
+ */
+function the_terms( $id, $taxonomy, $before = '', $sep = ', ', $after = '' ) {
+ $term_list = get_the_term_list( $id, $taxonomy, $before, $sep, $after );
+
+ if ( is_wp_error( $term_list ) )
+ return false;
+
+ echo apply_filters('the_terms', $term_list, $taxonomy, $before, $sep, $after);
+}
+
+/**
+ * Check if the current post has any of given category.
+ *
+ * @since 3.1.0
+ *
+ * @param string|int|array $category Optional. The category name/term_id/slug or array of them to check for.
+ * @param int|object $post Optional. Post to check instead of the current post.
+ * @return bool True if the current post has any of the given categories (or any category, if no category specified).
+ */
+function has_category( $category = '', $post = null ) {
+ return has_term( $category, 'category', $post );
+}
+
+/**
+ * Check if the current post has any of given tags.
+ *
+ * The given tags are checked against the post's tags' term_ids, names and slugs.
+ * Tags given as integers will only be checked against the post's tags' term_ids.
+ * If no tags are given, determines if post has any tags.
+ *
+ * Prior to v2.7 of WordPress, tags given as integers would also be checked against the post's tags' names and slugs (in addition to term_ids)
+ * Prior to v2.7, this function could only be used in the WordPress Loop.
+ * As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
+ *
+ * @since 2.6.0
+ *
+ * @param string|int|array $tag Optional. The tag name/term_id/slug or array of them to check for.
+ * @param int|object $post Optional. Post to check instead of the current post. (since 2.7.0)
+ * @return bool True if the current post has any of the given tags (or any tag, if no tag specified).
+ */
+function has_tag( $tag = '', $post = null ) {
+ return has_term( $tag, 'post_tag', $post );
+}
+
+/**
+ * Check if the current post has any of given terms.
+ *
+ * The given terms are checked against the post's terms' term_ids, names and slugs.
+ * Terms given as integers will only be checked against the post's terms' term_ids.
+ * If no terms are given, determines if post has any terms.
+ *
+ * @since 3.1.0
+ *
+ * @param string|int|array $term Optional. The term name/term_id/slug or array of them to check for.
+ * @param string $taxonomy Taxonomy name
+ * @param int|object $post Optional. Post to check instead of the current post.
+ * @return bool True if the current post has any of the given tags (or any tag, if no tag specified).
+ */
+function has_term( $term = '', $taxonomy = '', $post = null ) {
+ $post = get_post($post);
+
+ if ( !$post )
+ return false;
+
+ $r = is_object_in_term( $post->ID, $taxonomy, $term );
+ if ( is_wp_error( $r ) )
+ return false;
+
+ return $r;
+}
diff --git a/src/wp-includes/category.php b/src/wp-includes/category.php
new file mode 100644
index 0000000000..adac2475bf
--- /dev/null
+++ b/src/wp-includes/category.php
@@ -0,0 +1,336 @@
+<?php
+/**
+ * WordPress Category API
+ *
+ * @package WordPress
+ */
+
+/**
+ * Retrieves all category IDs.
+ *
+ * @since 2.0.0
+ * @link http://codex.wordpress.org/Function_Reference/get_all_category_ids
+ *
+ * @return object List of all of the category IDs.
+ */
+function get_all_category_ids() {
+ if ( ! $cat_ids = wp_cache_get( 'all_category_ids', 'category' ) ) {
+ $cat_ids = get_terms( 'category', array('fields' => 'ids', 'get' => 'all') );
+ wp_cache_add( 'all_category_ids', $cat_ids, 'category' );
+ }
+
+ return $cat_ids;
+}
+
+/**
+ * Retrieve list of category objects.
+ *
+ * If you change the type to 'link' in the arguments, then the link categories
+ * will be returned instead. Also all categories will be updated to be backwards
+ * compatible with pre-2.3 plugins and themes.
+ *
+ * @since 2.1.0
+ * @see get_terms() Type of arguments that can be changed.
+ * @link http://codex.wordpress.org/Function_Reference/get_categories
+ *
+ * @param string|array $args Optional. Change the defaults retrieving categories.
+ * @return array List of categories.
+ */
+function get_categories( $args = '' ) {
+ $defaults = array( 'taxonomy' => 'category' );
+ $args = wp_parse_args( $args, $defaults );
+
+ $taxonomy = apply_filters( 'get_categories_taxonomy', $args['taxonomy'], $args );
+
+ // Back compat
+ if ( isset($args['type']) && 'link' == $args['type'] ) {
+ _deprecated_argument( __FUNCTION__, '3.0', '' );
+ $taxonomy = $args['taxonomy'] = 'link_category';
+ }
+
+ $categories = (array) get_terms( $taxonomy, $args );
+
+ foreach ( array_keys( $categories ) as $k )
+ _make_cat_compat( $categories[$k] );
+
+ return $categories;
+}
+
+/**
+ * Retrieves category data given a category ID or category object.
+ *
+ * If you pass the $category parameter an object, which is assumed to be the
+ * category row object retrieved the database. It will cache the category data.
+ *
+ * If you pass $category an integer of the category ID, then that category will
+ * be retrieved from the database, if it isn't already cached, and pass it back.
+ *
+ * If you look at get_term(), then both types will be passed through several
+ * filters and finally sanitized based on the $filter parameter value.
+ *
+ * The category will converted to maintain backwards compatibility.
+ *
+ * @since 1.5.1
+ * @uses get_term() Used to get the category data from the taxonomy.
+ *
+ * @param int|object $category Category ID or Category row object
+ * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
+ * @return mixed Category data in type defined by $output parameter.
+ */
+function get_category( $category, $output = OBJECT, $filter = 'raw' ) {
+ $category = get_term( $category, 'category', $output, $filter );
+ if ( is_wp_error( $category ) )
+ return $category;
+
+ _make_cat_compat( $category );
+
+ return $category;
+}
+
+/**
+ * Retrieve category based on URL containing the category slug.
+ *
+ * Breaks the $category_path parameter up to get the category slug.
+ *
+ * Tries to find the child path and will return it. If it doesn't find a
+ * match, then it will return the first category matching slug, if $full_match,
+ * is set to false. If it does not, then it will return null.
+ *
+ * It is also possible that it will return a WP_Error object on failure. Check
+ * for it when using this function.
+ *
+ * @since 2.1.0
+ *
+ * @param string $category_path URL containing category slugs.
+ * @param bool $full_match Optional. Whether full path should be matched.
+ * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @return null|object|array Null on failure. Type is based on $output value.
+ */
+function get_category_by_path( $category_path, $full_match = true, $output = OBJECT ) {
+ $category_path = rawurlencode( urldecode( $category_path ) );
+ $category_path = str_replace( '%2F', '/', $category_path );
+ $category_path = str_replace( '%20', ' ', $category_path );
+ $category_paths = '/' . trim( $category_path, '/' );
+ $leaf_path = sanitize_title( basename( $category_paths ) );
+ $category_paths = explode( '/', $category_paths );
+ $full_path = '';
+ foreach ( (array) $category_paths as $pathdir )
+ $full_path .= ( $pathdir != '' ? '/' : '' ) . sanitize_title( $pathdir );
+
+ $categories = get_terms( 'category', array('get' => 'all', 'slug' => $leaf_path) );
+
+ if ( empty( $categories ) )
+ return null;
+
+ foreach ( $categories as $category ) {
+ $path = '/' . $leaf_path;
+ $curcategory = $category;
+ while ( ( $curcategory->parent != 0 ) && ( $curcategory->parent != $curcategory->term_id ) ) {
+ $curcategory = get_term( $curcategory->parent, 'category' );
+ if ( is_wp_error( $curcategory ) )
+ return $curcategory;
+ $path = '/' . $curcategory->slug . $path;
+ }
+
+ if ( $path == $full_path )
+ return get_category( $category->term_id, $output );
+ }
+
+ // If full matching is not required, return the first cat that matches the leaf.
+ if ( ! $full_match )
+ return get_category( $categories[0]->term_id, $output );
+
+ return null;
+}
+
+/**
+ * Retrieve category object by category slug.
+ *
+ * @since 2.3.0
+ *
+ * @param string $slug The category slug.
+ * @return object Category data object
+ */
+function get_category_by_slug( $slug ) {
+ $category = get_term_by( 'slug', $slug, 'category' );
+ if ( $category )
+ _make_cat_compat( $category );
+
+ return $category;
+}
+
+/**
+ * Retrieve the ID of a category from its name.
+ *
+ * @since 1.0.0
+ *
+ * @param string $cat_name Category name.
+ * @return int 0, if failure and ID of category on success.
+ */
+function get_cat_ID( $cat_name ) {
+ $cat = get_term_by( 'name', $cat_name, 'category' );
+ if ( $cat )
+ return $cat->term_id;
+ return 0;
+}
+
+/**
+ * Retrieve the name of a category from its ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $cat_id Category ID
+ * @return string Category name, or an empty string if category doesn't exist.
+ */
+function get_cat_name( $cat_id ) {
+ $cat_id = (int) $cat_id;
+ $category = get_category( $cat_id );
+ if ( ! $category || is_wp_error( $category ) )
+ return '';
+ return $category->name;
+}
+
+/**
+ * Check if a category is an ancestor of another category.
+ *
+ * You can use either an id or the category object for both parameters. If you
+ * use an integer the category will be retrieved.
+ *
+ * @since 2.1.0
+ *
+ * @param int|object $cat1 ID or object to check if this is the parent category.
+ * @param int|object $cat2 The child category.
+ * @return bool Whether $cat2 is child of $cat1
+ */
+function cat_is_ancestor_of( $cat1, $cat2 ) {
+ return term_is_ancestor_of( $cat1, $cat2, 'category' );
+}
+
+/**
+ * Sanitizes category data based on context.
+ *
+ * @since 2.3.0
+ * @uses sanitize_term() See this function for what context are supported.
+ *
+ * @param object|array $category Category data
+ * @param string $context Optional. Default is 'display'.
+ * @return object|array Same type as $category with sanitized data for safe use.
+ */
+function sanitize_category( $category, $context = 'display' ) {
+ return sanitize_term( $category, 'category', $context );
+}
+
+/**
+ * Sanitizes data in single category key field.
+ *
+ * @since 2.3.0
+ * @uses sanitize_term_field() See function for more details.
+ *
+ * @param string $field Category key to sanitize
+ * @param mixed $value Category value to sanitize
+ * @param int $cat_id Category ID
+ * @param string $context What filter to use, 'raw', 'display', etc.
+ * @return mixed Same type as $value after $value has been sanitized.
+ */
+function sanitize_category_field( $field, $value, $cat_id, $context ) {
+ return sanitize_term_field( $field, $value, $cat_id, 'category', $context );
+}
+
+/* Tags */
+
+/**
+ * Retrieves all post tags.
+ *
+ * @since 2.3.0
+ * @see get_terms() For list of arguments to pass.
+ * @uses apply_filters() Calls 'get_tags' hook on array of tags and with $args.
+ *
+ * @param string|array $args Tag arguments to use when retrieving tags.
+ * @return array List of tags.
+ */
+function get_tags( $args = '' ) {
+ $tags = get_terms( 'post_tag', $args );
+
+ if ( empty( $tags ) ) {
+ $return = array();
+ return $return;
+ }
+
+ $tags = apply_filters( 'get_tags', $tags, $args );
+ return $tags;
+}
+
+/**
+ * Retrieve post tag by tag ID or tag object.
+ *
+ * If you pass the $tag parameter an object, which is assumed to be the tag row
+ * object retrieved the database. It will cache the tag data.
+ *
+ * If you pass $tag an integer of the tag ID, then that tag will
+ * be retrieved from the database, if it isn't already cached, and pass it back.
+ *
+ * If you look at get_term(), then both types will be passed through several
+ * filters and finally sanitized based on the $filter parameter value.
+ *
+ * @since 2.3.0
+ *
+ * @param int|object $tag
+ * @param string $output Optional. Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional. Default is raw or no WordPress defined filter will applied.
+ * @return object|array Return type based on $output value.
+ */
+function get_tag( $tag, $output = OBJECT, $filter = 'raw' ) {
+ return get_term( $tag, 'post_tag', $output, $filter );
+}
+
+/* Cache */
+
+/**
+ * Remove the category cache data based on ID.
+ *
+ * @since 2.1.0
+ * @uses clean_term_cache() Clears the cache for the category based on ID
+ *
+ * @param int $id Category ID
+ */
+function clean_category_cache( $id ) {
+ clean_term_cache( $id, 'category' );
+}
+
+/**
+ * Update category structure to old pre 2.3 from new taxonomy structure.
+ *
+ * This function was added for the taxonomy support to update the new category
+ * structure with the old category one. This will maintain compatibility with
+ * plugins and themes which depend on the old key or property names.
+ *
+ * The parameter should only be passed a variable and not create the array or
+ * object inline to the parameter. The reason for this is that parameter is
+ * passed by reference and PHP will fail unless it has the variable.
+ *
+ * There is no return value, because everything is updated on the variable you
+ * pass to it. This is one of the features with using pass by reference in PHP.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param array|object $category Category Row object or array
+ */
+function _make_cat_compat( &$category ) {
+ if ( is_object( $category ) ) {
+ $category->cat_ID = &$category->term_id;
+ $category->category_count = &$category->count;
+ $category->category_description = &$category->description;
+ $category->cat_name = &$category->name;
+ $category->category_nicename = &$category->slug;
+ $category->category_parent = &$category->parent;
+ } elseif ( is_array( $category ) && isset( $category['term_id'] ) ) {
+ $category['cat_ID'] = &$category['term_id'];
+ $category['category_count'] = &$category['count'];
+ $category['category_description'] = &$category['description'];
+ $category['cat_name'] = &$category['name'];
+ $category['category_nicename'] = &$category['slug'];
+ $category['category_parent'] = &$category['parent'];
+ }
+}
diff --git a/src/wp-includes/class-IXR.php b/src/wp-includes/class-IXR.php
new file mode 100644
index 0000000000..f8fbc00b10
--- /dev/null
+++ b/src/wp-includes/class-IXR.php
@@ -0,0 +1,1070 @@
+<?php
+/**
+ * IXR - The Incutio XML-RPC Library
+ *
+ * Copyright (c) 2010, Incutio Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of Incutio Ltd. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package IXR
+ * @since 1.5
+ *
+ * @copyright Incutio Ltd 2010 (http://www.incutio.com)
+ * @version 1.7.4 7th September 2010
+ * @author Simon Willison
+ * @link http://scripts.incutio.com/xmlrpc/ Site/manual
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD
+ */
+
+/**
+ * IXR_Value
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Value {
+ var $data;
+ var $type;
+
+ function IXR_Value($data, $type = false)
+ {
+ $this->data = $data;
+ if (!$type) {
+ $type = $this->calculateType();
+ }
+ $this->type = $type;
+ if ($type == 'struct') {
+ // Turn all the values in the array in to new IXR_Value objects
+ foreach ($this->data as $key => $value) {
+ $this->data[$key] = new IXR_Value($value);
+ }
+ }
+ if ($type == 'array') {
+ for ($i = 0, $j = count($this->data); $i < $j; $i++) {
+ $this->data[$i] = new IXR_Value($this->data[$i]);
+ }
+ }
+ }
+
+ function calculateType()
+ {
+ if ($this->data === true || $this->data === false) {
+ return 'boolean';
+ }
+ if (is_integer($this->data)) {
+ return 'int';
+ }
+ if (is_double($this->data)) {
+ return 'double';
+ }
+
+ // Deal with IXR object types base64 and date
+ if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
+ return 'date';
+ }
+ if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
+ return 'base64';
+ }
+
+ // If it is a normal PHP object convert it in to a struct
+ if (is_object($this->data)) {
+ $this->data = get_object_vars($this->data);
+ return 'struct';
+ }
+ if (!is_array($this->data)) {
+ return 'string';
+ }
+
+ // We have an array - is it an array or a struct?
+ if ($this->isStruct($this->data)) {
+ return 'struct';
+ } else {
+ return 'array';
+ }
+ }
+
+ function getXml()
+ {
+ // Return XML for this value
+ switch ($this->type) {
+ case 'boolean':
+ return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
+ break;
+ case 'int':
+ return '<int>'.$this->data.'</int>';
+ break;
+ case 'double':
+ return '<double>'.$this->data.'</double>';
+ break;
+ case 'string':
+ return '<string>'.htmlspecialchars($this->data).'</string>';
+ break;
+ case 'array':
+ $return = '<array><data>'."\n";
+ foreach ($this->data as $item) {
+ $return .= ' <value>'.$item->getXml()."</value>\n";
+ }
+ $return .= '</data></array>';
+ return $return;
+ break;
+ case 'struct':
+ $return = '<struct>'."\n";
+ foreach ($this->data as $name => $value) {
+ $name = htmlspecialchars($name);
+ $return .= " <member><name>$name</name><value>";
+ $return .= $value->getXml()."</value></member>\n";
+ }
+ $return .= '</struct>';
+ return $return;
+ break;
+ case 'date':
+ case 'base64':
+ return $this->data->getXml();
+ break;
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether or not the supplied array is a struct or not
+ *
+ * @param unknown_type $array
+ * @return boolean
+ */
+ function isStruct($array)
+ {
+ $expected = 0;
+ foreach ($array as $key => $value) {
+ if ((string)$key != (string)$expected) {
+ return true;
+ }
+ $expected++;
+ }
+ return false;
+ }
+}
+
+/**
+ * IXR_MESSAGE
+ *
+ * @package IXR
+ * @since 1.5
+ *
+ */
+class IXR_Message
+{
+ var $message;
+ var $messageType; // methodCall / methodResponse / fault
+ var $faultCode;
+ var $faultString;
+ var $methodName;
+ var $params;
+
+ // Current variable stacks
+ var $_arraystructs = array(); // The stack used to keep track of the current array/struct
+ var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
+ var $_currentStructName = array(); // A stack as well
+ var $_param;
+ var $_value;
+ var $_currentTag;
+ var $_currentTagContents;
+ // The XML parser
+ var $_parser;
+
+ function IXR_Message($message)
+ {
+ $this->message =& $message;
+ }
+
+ function parse()
+ {
+ // first remove the XML declaration
+ // merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
+ $header = preg_replace( '/<\?xml.*?\?'.'>/', '', substr($this->message, 0, 100), 1);
+ $this->message = substr_replace($this->message, $header, 0, 100);
+ if (trim($this->message) == '') {
+ return false;
+ }
+ $this->_parser = xml_parser_create();
+ // Set XML parser to take the case of tags in to account
+ xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
+ // Set XML parser callback functions
+ xml_set_object($this->_parser, $this);
+ xml_set_element_handler($this->_parser, 'tag_open', 'tag_close');
+ xml_set_character_data_handler($this->_parser, 'cdata');
+ $chunk_size = 262144; // 256Kb, parse in chunks to avoid the RAM usage on very large messages
+ $final = false;
+ do {
+ if (strlen($this->message) <= $chunk_size) {
+ $final = true;
+ }
+ $part = substr($this->message, 0, $chunk_size);
+ $this->message = substr($this->message, $chunk_size);
+ if (!xml_parse($this->_parser, $part, $final)) {
+ return false;
+ }
+ if ($final) {
+ break;
+ }
+ } while (true);
+ xml_parser_free($this->_parser);
+
+ // Grab the error messages, if any
+ if ($this->messageType == 'fault') {
+ $this->faultCode = $this->params[0]['faultCode'];
+ $this->faultString = $this->params[0]['faultString'];
+ }
+ return true;
+ }
+
+ function tag_open($parser, $tag, $attr)
+ {
+ $this->_currentTagContents = '';
+ $this->currentTag = $tag;
+ switch($tag) {
+ case 'methodCall':
+ case 'methodResponse':
+ case 'fault':
+ $this->messageType = $tag;
+ break;
+ /* Deal with stacks of arrays and structs */
+ case 'data': // data is to all intents and puposes more interesting than array
+ $this->_arraystructstypes[] = 'array';
+ $this->_arraystructs[] = array();
+ break;
+ case 'struct':
+ $this->_arraystructstypes[] = 'struct';
+ $this->_arraystructs[] = array();
+ break;
+ }
+ }
+
+ function cdata($parser, $cdata)
+ {
+ $this->_currentTagContents .= $cdata;
+ }
+
+ function tag_close($parser, $tag)
+ {
+ $valueFlag = false;
+ switch($tag) {
+ case 'int':
+ case 'i4':
+ $value = (int)trim($this->_currentTagContents);
+ $valueFlag = true;
+ break;
+ case 'double':
+ $value = (double)trim($this->_currentTagContents);
+ $valueFlag = true;
+ break;
+ case 'string':
+ $value = (string)trim($this->_currentTagContents);
+ $valueFlag = true;
+ break;
+ case 'dateTime.iso8601':
+ $value = new IXR_Date(trim($this->_currentTagContents));
+ $valueFlag = true;
+ break;
+ case 'value':
+ // "If no type is indicated, the type is string."
+ if (trim($this->_currentTagContents) != '') {
+ $value = (string)$this->_currentTagContents;
+ $valueFlag = true;
+ }
+ break;
+ case 'boolean':
+ $value = (boolean)trim($this->_currentTagContents);
+ $valueFlag = true;
+ break;
+ case 'base64':
+ $value = base64_decode($this->_currentTagContents);
+ $valueFlag = true;
+ break;
+ /* Deal with stacks of arrays and structs */
+ case 'data':
+ case 'struct':
+ $value = array_pop($this->_arraystructs);
+ array_pop($this->_arraystructstypes);
+ $valueFlag = true;
+ break;
+ case 'member':
+ array_pop($this->_currentStructName);
+ break;
+ case 'name':
+ $this->_currentStructName[] = trim($this->_currentTagContents);
+ break;
+ case 'methodName':
+ $this->methodName = trim($this->_currentTagContents);
+ break;
+ }
+
+ if ($valueFlag) {
+ if (count($this->_arraystructs) > 0) {
+ // Add value to struct or array
+ if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
+ // Add to struct
+ $this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
+ } else {
+ // Add to array
+ $this->_arraystructs[count($this->_arraystructs)-1][] = $value;
+ }
+ } else {
+ // Just add as a paramater
+ $this->params[] = $value;
+ }
+ }
+ $this->_currentTagContents = '';
+ }
+}
+
+/**
+ * IXR_Server
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Server
+{
+ var $data;
+ var $callbacks = array();
+ var $message;
+ var $capabilities;
+
+ function IXR_Server($callbacks = false, $data = false, $wait = false)
+ {
+ $this->setCapabilities();
+ if ($callbacks) {
+ $this->callbacks = $callbacks;
+ }
+ $this->setCallbacks();
+ if (!$wait) {
+ $this->serve($data);
+ }
+ }
+
+ function serve($data = false)
+ {
+ if (!$data) {
+ if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
+ header('Content-Type: text/plain'); // merged from WP #9093
+ die('XML-RPC server accepts POST requests only.');
+ }
+
+ global $HTTP_RAW_POST_DATA;
+ if (empty($HTTP_RAW_POST_DATA)) {
+ // workaround for a bug in PHP 5.2.2 - http://bugs.php.net/bug.php?id=41293
+ $data = file_get_contents('php://input');
+ } else {
+ $data =& $HTTP_RAW_POST_DATA;
+ }
+ }
+ $this->message = new IXR_Message($data);
+ if (!$this->message->parse()) {
+ $this->error(-32700, 'parse error. not well formed');
+ }
+ if ($this->message->messageType != 'methodCall') {
+ $this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
+ }
+ $result = $this->call($this->message->methodName, $this->message->params);
+
+ // Is the result an error?
+ if (is_a($result, 'IXR_Error')) {
+ $this->error($result);
+ }
+
+ // Encode the result
+ $r = new IXR_Value($result);
+ $resultxml = $r->getXml();
+
+ // Create the XML
+ $xml = <<<EOD
+<methodResponse>
+ <params>
+ <param>
+ <value>
+ $resultxml
+ </value>
+ </param>
+ </params>
+</methodResponse>
+
+EOD;
+ // Send it
+ $this->output($xml);
+ }
+
+ function call($methodname, $args)
+ {
+ if (!$this->hasMethod($methodname)) {
+ return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
+ }
+ $method = $this->callbacks[$methodname];
+
+ // Perform the callback and send the response
+ if (count($args) == 1) {
+ // If only one paramater just send that instead of the whole array
+ $args = $args[0];
+ }
+
+ // Are we dealing with a function or a method?
+ if (is_string($method) && substr($method, 0, 5) == 'this:') {
+ // It's a class method - check it exists
+ $method = substr($method, 5);
+ if (!method_exists($this, $method)) {
+ return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
+ }
+
+ //Call the method
+ $result = $this->$method($args);
+ } else {
+ // It's a function - does it exist?
+ if (is_array($method)) {
+ if (!is_callable(array($method[0], $method[1]))) {
+ return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.');
+ }
+ } else if (!function_exists($method)) {
+ return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
+ }
+
+ // Call the function
+ $result = call_user_func($method, $args);
+ }
+ return $result;
+ }
+
+ function error($error, $message = false)
+ {
+ // Accepts either an error object or an error code and message
+ if ($message && !is_object($error)) {
+ $error = new IXR_Error($error, $message);
+ }
+ $this->output($error->getXml());
+ }
+
+ function output($xml)
+ {
+ $charset = function_exists('get_option') ? get_option('blog_charset') : '';
+ if ($charset)
+ $xml = '<?xml version="1.0" encoding="'.$charset.'"?>'."\n".$xml;
+ else
+ $xml = '<?xml version="1.0"?>'."\n".$xml;
+ $length = strlen($xml);
+ header('Connection: close');
+ header('Content-Length: '.$length);
+ if ($charset)
+ header('Content-Type: text/xml; charset='.$charset);
+ else
+ header('Content-Type: text/xml');
+ header('Date: '.date('r'));
+ echo $xml;
+ exit;
+ }
+
+ function hasMethod($method)
+ {
+ return in_array($method, array_keys($this->callbacks));
+ }
+
+ function setCapabilities()
+ {
+ // Initialises capabilities array
+ $this->capabilities = array(
+ 'xmlrpc' => array(
+ 'specUrl' => 'http://www.xmlrpc.com/spec',
+ 'specVersion' => 1
+ ),
+ 'faults_interop' => array(
+ 'specUrl' => 'http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
+ 'specVersion' => 20010516
+ ),
+ 'system.multicall' => array(
+ 'specUrl' => 'http://www.xmlrpc.com/discuss/msgReader$1208',
+ 'specVersion' => 1
+ ),
+ );
+ }
+
+ function getCapabilities($args)
+ {
+ return $this->capabilities;
+ }
+
+ function setCallbacks()
+ {
+ $this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
+ $this->callbacks['system.listMethods'] = 'this:listMethods';
+ $this->callbacks['system.multicall'] = 'this:multiCall';
+ }
+
+ function listMethods($args)
+ {
+ // Returns a list of methods - uses array_reverse to ensure user defined
+ // methods are listed before server defined methods
+ return array_reverse(array_keys($this->callbacks));
+ }
+
+ function multiCall($methodcalls)
+ {
+ // See http://www.xmlrpc.com/discuss/msgReader$1208
+ $return = array();
+ foreach ($methodcalls as $call) {
+ $method = $call['methodName'];
+ $params = $call['params'];
+ if ($method == 'system.multicall') {
+ $result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
+ } else {
+ $result = $this->call($method, $params);
+ }
+ if (is_a($result, 'IXR_Error')) {
+ $return[] = array(
+ 'faultCode' => $result->code,
+ 'faultString' => $result->message
+ );
+ } else {
+ $return[] = array($result);
+ }
+ }
+ return $return;
+ }
+}
+
+/**
+ * IXR_Request
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Request
+{
+ var $method;
+ var $args;
+ var $xml;
+
+ function IXR_Request($method, $args)
+ {
+ $this->method = $method;
+ $this->args = $args;
+ $this->xml = <<<EOD
+<?xml version="1.0"?>
+<methodCall>
+<methodName>{$this->method}</methodName>
+<params>
+
+EOD;
+ foreach ($this->args as $arg) {
+ $this->xml .= '<param><value>';
+ $v = new IXR_Value($arg);
+ $this->xml .= $v->getXml();
+ $this->xml .= "</value></param>\n";
+ }
+ $this->xml .= '</params></methodCall>';
+ }
+
+ function getLength()
+ {
+ return strlen($this->xml);
+ }
+
+ function getXml()
+ {
+ return $this->xml;
+ }
+}
+
+/**
+ * IXR_Client
+ *
+ * @package IXR
+ * @since 1.5
+ *
+ */
+class IXR_Client
+{
+ var $server;
+ var $port;
+ var $path;
+ var $useragent;
+ var $response;
+ var $message = false;
+ var $debug = false;
+ var $timeout;
+ var $headers = array();
+
+ // Storage place for an error message
+ var $error = false;
+
+ function IXR_Client($server, $path = false, $port = 80, $timeout = 15)
+ {
+ if (!$path) {
+ // Assume we have been given a URL instead
+ $bits = parse_url($server);
+ $this->server = $bits['host'];
+ $this->port = isset($bits['port']) ? $bits['port'] : 80;
+ $this->path = isset($bits['path']) ? $bits['path'] : '/';
+
+ // Make absolutely sure we have a path
+ if (!$this->path) {
+ $this->path = '/';
+ }
+ } else {
+ $this->server = $server;
+ $this->path = $path;
+ $this->port = $port;
+ }
+ $this->useragent = 'The Incutio XML-RPC PHP Library';
+ $this->timeout = $timeout;
+ }
+
+ function query()
+ {
+ $args = func_get_args();
+ $method = array_shift($args);
+ $request = new IXR_Request($method, $args);
+ $length = $request->getLength();
+ $xml = $request->getXml();
+ $r = "\r\n";
+ $request = "POST {$this->path} HTTP/1.0$r";
+
+ // Merged from WP #8145 - allow custom headers
+ $this->headers['Host'] = $this->server;
+ $this->headers['Content-Type'] = 'text/xml';
+ $this->headers['User-Agent'] = $this->useragent;
+ $this->headers['Content-Length']= $length;
+
+ foreach( $this->headers as $header => $value ) {
+ $request .= "{$header}: {$value}{$r}";
+ }
+ $request .= $r;
+
+ $request .= $xml;
+
+ // Now send the request
+ if ($this->debug) {
+ echo '<pre class="ixr_request">'.htmlspecialchars($request)."\n</pre>\n\n";
+ }
+
+ if ($this->timeout) {
+ $fp = @fsockopen($this->server, $this->port, $errno, $errstr, $this->timeout);
+ } else {
+ $fp = @fsockopen($this->server, $this->port, $errno, $errstr);
+ }
+ if (!$fp) {
+ $this->error = new IXR_Error(-32300, 'transport error - could not open socket');
+ return false;
+ }
+ fputs($fp, $request);
+ $contents = '';
+ $debugContents = '';
+ $gotFirstLine = false;
+ $gettingHeaders = true;
+ while (!feof($fp)) {
+ $line = fgets($fp, 4096);
+ if (!$gotFirstLine) {
+ // Check line for '200'
+ if (strstr($line, '200') === false) {
+ $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
+ return false;
+ }
+ $gotFirstLine = true;
+ }
+ if (trim($line) == '') {
+ $gettingHeaders = false;
+ }
+ if (!$gettingHeaders) {
+ // merged from WP #12559 - remove trim
+ $contents .= $line;
+ }
+ if ($this->debug) {
+ $debugContents .= $line;
+ }
+ }
+ if ($this->debug) {
+ echo '<pre class="ixr_response">'.htmlspecialchars($debugContents)."\n</pre>\n\n";
+ }
+
+ // Now parse what we've got back
+ $this->message = new IXR_Message($contents);
+ if (!$this->message->parse()) {
+ // XML error
+ $this->error = new IXR_Error(-32700, 'parse error. not well formed');
+ return false;
+ }
+
+ // Is the message a fault?
+ if ($this->message->messageType == 'fault') {
+ $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
+ return false;
+ }
+
+ // Message must be OK
+ return true;
+ }
+
+ function getResponse()
+ {
+ // methodResponses can only have one param - return that
+ return $this->message->params[0];
+ }
+
+ function isError()
+ {
+ return (is_object($this->error));
+ }
+
+ function getErrorCode()
+ {
+ return $this->error->code;
+ }
+
+ function getErrorMessage()
+ {
+ return $this->error->message;
+ }
+}
+
+
+/**
+ * IXR_Error
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Error
+{
+ var $code;
+ var $message;
+
+ function IXR_Error($code, $message)
+ {
+ $this->code = $code;
+ $this->message = htmlspecialchars($message);
+ }
+
+ function getXml()
+ {
+ $xml = <<<EOD
+<methodResponse>
+ <fault>
+ <value>
+ <struct>
+ <member>
+ <name>faultCode</name>
+ <value><int>{$this->code}</int></value>
+ </member>
+ <member>
+ <name>faultString</name>
+ <value><string>{$this->message}</string></value>
+ </member>
+ </struct>
+ </value>
+ </fault>
+</methodResponse>
+
+EOD;
+ return $xml;
+ }
+}
+
+/**
+ * IXR_Date
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Date {
+ var $year;
+ var $month;
+ var $day;
+ var $hour;
+ var $minute;
+ var $second;
+ var $timezone;
+
+ function IXR_Date($time)
+ {
+ // $time can be a PHP timestamp or an ISO one
+ if (is_numeric($time)) {
+ $this->parseTimestamp($time);
+ } else {
+ $this->parseIso($time);
+ }
+ }
+
+ function parseTimestamp($timestamp)
+ {
+ $this->year = date('Y', $timestamp);
+ $this->month = date('m', $timestamp);
+ $this->day = date('d', $timestamp);
+ $this->hour = date('H', $timestamp);
+ $this->minute = date('i', $timestamp);
+ $this->second = date('s', $timestamp);
+ $this->timezone = '';
+ }
+
+ function parseIso($iso)
+ {
+ $this->year = substr($iso, 0, 4);
+ $this->month = substr($iso, 4, 2);
+ $this->day = substr($iso, 6, 2);
+ $this->hour = substr($iso, 9, 2);
+ $this->minute = substr($iso, 12, 2);
+ $this->second = substr($iso, 15, 2);
+ $this->timezone = substr($iso, 17);
+ }
+
+ function getIso()
+ {
+ return $this->year.$this->month.$this->day.'T'.$this->hour.':'.$this->minute.':'.$this->second.$this->timezone;
+ }
+
+ function getXml()
+ {
+ return '<dateTime.iso8601>'.$this->getIso().'</dateTime.iso8601>';
+ }
+
+ function getTimestamp()
+ {
+ return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
+ }
+}
+
+/**
+ * IXR_Base64
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_Base64
+{
+ var $data;
+
+ function IXR_Base64($data)
+ {
+ $this->data = $data;
+ }
+
+ function getXml()
+ {
+ return '<base64>'.base64_encode($this->data).'</base64>';
+ }
+}
+
+/**
+ * IXR_IntrospectionServer
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_IntrospectionServer extends IXR_Server
+{
+ var $signatures;
+ var $help;
+
+ function IXR_IntrospectionServer()
+ {
+ $this->setCallbacks();
+ $this->setCapabilities();
+ $this->capabilities['introspection'] = array(
+ 'specUrl' => 'http://xmlrpc.usefulinc.com/doc/reserved.html',
+ 'specVersion' => 1
+ );
+ $this->addCallback(
+ 'system.methodSignature',
+ 'this:methodSignature',
+ array('array', 'string'),
+ 'Returns an array describing the return type and required parameters of a method'
+ );
+ $this->addCallback(
+ 'system.getCapabilities',
+ 'this:getCapabilities',
+ array('struct'),
+ 'Returns a struct describing the XML-RPC specifications supported by this server'
+ );
+ $this->addCallback(
+ 'system.listMethods',
+ 'this:listMethods',
+ array('array'),
+ 'Returns an array of available methods on this server'
+ );
+ $this->addCallback(
+ 'system.methodHelp',
+ 'this:methodHelp',
+ array('string', 'string'),
+ 'Returns a documentation string for the specified method'
+ );
+ }
+
+ function addCallback($method, $callback, $args, $help)
+ {
+ $this->callbacks[$method] = $callback;
+ $this->signatures[$method] = $args;
+ $this->help[$method] = $help;
+ }
+
+ function call($methodname, $args)
+ {
+ // Make sure it's in an array
+ if ($args && !is_array($args)) {
+ $args = array($args);
+ }
+
+ // Over-rides default call method, adds signature check
+ if (!$this->hasMethod($methodname)) {
+ return new IXR_Error(-32601, 'server error. requested method "'.$this->message->methodName.'" not specified.');
+ }
+ $method = $this->callbacks[$methodname];
+ $signature = $this->signatures[$methodname];
+ $returnType = array_shift($signature);
+
+ // Check the number of arguments
+ if (count($args) != count($signature)) {
+ return new IXR_Error(-32602, 'server error. wrong number of method parameters');
+ }
+
+ // Check the argument types
+ $ok = true;
+ $argsbackup = $args;
+ for ($i = 0, $j = count($args); $i < $j; $i++) {
+ $arg = array_shift($args);
+ $type = array_shift($signature);
+ switch ($type) {
+ case 'int':
+ case 'i4':
+ if (is_array($arg) || !is_int($arg)) {
+ $ok = false;
+ }
+ break;
+ case 'base64':
+ case 'string':
+ if (!is_string($arg)) {
+ $ok = false;
+ }
+ break;
+ case 'boolean':
+ if ($arg !== false && $arg !== true) {
+ $ok = false;
+ }
+ break;
+ case 'float':
+ case 'double':
+ if (!is_float($arg)) {
+ $ok = false;
+ }
+ break;
+ case 'date':
+ case 'dateTime.iso8601':
+ if (!is_a($arg, 'IXR_Date')) {
+ $ok = false;
+ }
+ break;
+ }
+ if (!$ok) {
+ return new IXR_Error(-32602, 'server error. invalid method parameters');
+ }
+ }
+ // It passed the test - run the "real" method call
+ return parent::call($methodname, $argsbackup);
+ }
+
+ function methodSignature($method)
+ {
+ if (!$this->hasMethod($method)) {
+ return new IXR_Error(-32601, 'server error. requested method "'.$method.'" not specified.');
+ }
+ // We should be returning an array of types
+ $types = $this->signatures[$method];
+ $return = array();
+ foreach ($types as $type) {
+ switch ($type) {
+ case 'string':
+ $return[] = 'string';
+ break;
+ case 'int':
+ case 'i4':
+ $return[] = 42;
+ break;
+ case 'double':
+ $return[] = 3.1415;
+ break;
+ case 'dateTime.iso8601':
+ $return[] = new IXR_Date(time());
+ break;
+ case 'boolean':
+ $return[] = true;
+ break;
+ case 'base64':
+ $return[] = new IXR_Base64('base64');
+ break;
+ case 'array':
+ $return[] = array('array');
+ break;
+ case 'struct':
+ $return[] = array('struct' => 'struct');
+ break;
+ }
+ }
+ return $return;
+ }
+
+ function methodHelp($method)
+ {
+ return $this->help[$method];
+ }
+}
+
+/**
+ * IXR_ClientMulticall
+ *
+ * @package IXR
+ * @since 1.5
+ */
+class IXR_ClientMulticall extends IXR_Client
+{
+ var $calls = array();
+
+ function IXR_ClientMulticall($server, $path = false, $port = 80)
+ {
+ parent::IXR_Client($server, $path, $port);
+ $this->useragent = 'The Incutio XML-RPC PHP Library (multicall client)';
+ }
+
+ function addCall()
+ {
+ $args = func_get_args();
+ $methodName = array_shift($args);
+ $struct = array(
+ 'methodName' => $methodName,
+ 'params' => $args
+ );
+ $this->calls[] = $struct;
+ }
+
+ function query()
+ {
+ // Prepare multicall, then call the parent::query() method
+ return parent::query('system.multicall', $this->calls);
+ }
+}
diff --git a/src/wp-includes/class-feed.php b/src/wp-includes/class-feed.php
new file mode 100644
index 0000000000..bdad84db6c
--- /dev/null
+++ b/src/wp-includes/class-feed.php
@@ -0,0 +1,130 @@
+<?php
+
+if ( !class_exists('SimplePie') )
+ require_once (ABSPATH . WPINC . '/class-simplepie.php');
+
+class WP_Feed_Cache extends SimplePie_Cache {
+ /**
+ * Create a new SimplePie_Cache object
+ *
+ * @static
+ * @access public
+ */
+ function create($location, $filename, $extension) {
+ return new WP_Feed_Cache_Transient($location, $filename, $extension);
+ }
+}
+
+class WP_Feed_Cache_Transient {
+ var $name;
+ var $mod_name;
+ var $lifetime = 43200; //Default lifetime in cache of 12 hours
+
+ function __construct($location, $filename, $extension) {
+ $this->name = 'feed_' . $filename;
+ $this->mod_name = 'feed_mod_' . $filename;
+ $this->lifetime = apply_filters('wp_feed_cache_transient_lifetime', $this->lifetime, $filename);
+ }
+
+ function save($data) {
+ if ( is_a($data, 'SimplePie') )
+ $data = $data->data;
+
+ set_transient($this->name, $data, $this->lifetime);
+ set_transient($this->mod_name, time(), $this->lifetime);
+ return true;
+ }
+
+ function load() {
+ return get_transient($this->name);
+ }
+
+ function mtime() {
+ return get_transient($this->mod_name);
+ }
+
+ function touch() {
+ return set_transient($this->mod_name, time(), $this->lifetime);
+ }
+
+ function unlink() {
+ delete_transient($this->name);
+ delete_transient($this->mod_name);
+ return true;
+ }
+}
+
+class WP_SimplePie_File extends SimplePie_File {
+
+ function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
+ $this->url = $url;
+ $this->timeout = $timeout;
+ $this->redirects = $redirects;
+ $this->headers = $headers;
+ $this->useragent = $useragent;
+
+ $this->method = SIMPLEPIE_FILE_SOURCE_REMOTE;
+
+ if ( preg_match('/^http(s)?:\/\//i', $url) ) {
+ $args = array(
+ 'timeout' => $this->timeout,
+ 'redirection' => $this->redirects,
+ );
+
+ if ( !empty($this->headers) )
+ $args['headers'] = $this->headers;
+
+ if ( SIMPLEPIE_USERAGENT != $this->useragent ) //Use default WP user agent unless custom has been specified
+ $args['user-agent'] = $this->useragent;
+
+ $res = wp_safe_remote_request($url, $args);
+
+ if ( is_wp_error($res) ) {
+ $this->error = 'WP HTTP Error: ' . $res->get_error_message();
+ $this->success = false;
+ } else {
+ $this->headers = wp_remote_retrieve_headers( $res );
+ $this->body = wp_remote_retrieve_body( $res );
+ $this->status_code = wp_remote_retrieve_response_code( $res );
+ }
+ } else {
+ $this->error = '';
+ $this->success = false;
+ }
+ }
+}
+
+/**
+ * WordPress SimplePie Sanitization Class
+ *
+ * Extension of the SimplePie_Sanitize class to use KSES, because
+ * we cannot universally count on DOMDocument being available
+ *
+ * @package WordPress
+ * @since 3.5.0
+ */
+class WP_SimplePie_Sanitize_KSES extends SimplePie_Sanitize {
+ public function sanitize( $data, $type, $base = '' ) {
+ $data = trim( $data );
+ if ( $type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML ) {
+ if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data)) {
+ $type |= SIMPLEPIE_CONSTRUCT_HTML;
+ }
+ else {
+ $type |= SIMPLEPIE_CONSTRUCT_TEXT;
+ }
+ }
+ if ( $type & SIMPLEPIE_CONSTRUCT_BASE64 ) {
+ $data = base64_decode( $data );
+ }
+ if ( $type & ( SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML ) ) {
+ $data = wp_kses_post( $data );
+ if ( $this->output_encoding !== 'UTF-8' ) {
+ $data = $this->registry->call( 'Misc', 'change_encoding', array( $data, 'UTF-8', $this->output_encoding ) );
+ }
+ return $data;
+ } else {
+ return parent::sanitize( $data, $type, $base );
+ }
+ }
+}
diff --git a/src/wp-includes/class-http.php b/src/wp-includes/class-http.php
new file mode 100644
index 0000000000..12e73bbb86
--- /dev/null
+++ b/src/wp-includes/class-http.php
@@ -0,0 +1,1977 @@
+<?php
+/**
+ * Simple and uniform HTTP request API.
+ *
+ * Standardizes the HTTP requests for WordPress. Handles cookies, gzip encoding and decoding, chunk
+ * decoding, if HTTP 1.1 and various other difficult HTTP protocol implementations.
+ *
+ * @link http://trac.wordpress.org/ticket/4779 HTTP API Proposal
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.7.0
+ */
+
+/**
+ * WordPress HTTP Class for managing HTTP Transports and making HTTP requests.
+ *
+ * This class is called for the functionality of making HTTP requests and replaces Snoopy
+ * functionality. There is no available functionality to add HTTP transport implementations, since
+ * most of the HTTP transports are added and available for use.
+ *
+ * There are no properties, because none are needed and for performance reasons. Some of the
+ * functions are static and while they do have some overhead over functions in PHP4, the purpose is
+ * maintainability. When PHP5 is finally the requirement, it will be easy to add the static keyword
+ * to the code. It is not as easy to convert a function to a method after enough code uses the old
+ * way.
+ *
+ * Debugging includes several actions, which pass different variables for debugging the HTTP API.
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.7.0
+ */
+class WP_Http {
+
+ /**
+ * Send a HTTP request to a URI.
+ *
+ * The body and headers are part of the arguments. The 'body' argument is for the body and will
+ * accept either a string or an array. The 'headers' argument should be an array, but a string
+ * is acceptable. If the 'body' argument is an array, then it will automatically be escaped
+ * using http_build_query().
+ *
+ * The only URI that are supported in the HTTP Transport implementation are the HTTP and HTTPS
+ * protocols. HTTP and HTTPS are assumed so the server might not know how to handle the send
+ * headers. Other protocols are unsupported and most likely will fail.
+ *
+ * The defaults are 'method', 'timeout', 'redirection', 'httpversion', 'blocking' and
+ * 'user-agent'.
+ *
+ * Accepted 'method' values are 'GET', 'POST', and 'HEAD', some transports technically allow
+ * others, but should not be assumed. The 'timeout' is used to sent how long the connection
+ * should stay open before failing when no response. 'redirection' is used to track how many
+ * redirects were taken and used to sent the amount for other transports, but not all transports
+ * accept setting that value.
+ *
+ * The 'httpversion' option is used to sent the HTTP version and accepted values are '1.0', and
+ * '1.1' and should be a string. Version 1.1 is not supported, because of chunk response. The
+ * 'user-agent' option is the user-agent and is used to replace the default user-agent, which is
+ * 'WordPress/WP_Version', where WP_Version is the value from $wp_version.
+ *
+ * 'blocking' is the default, which is used to tell the transport, whether it should halt PHP
+ * while it performs the request or continue regardless. Actually, that isn't entirely correct.
+ * Blocking mode really just means whether the fread should just pull what it can whenever it
+ * gets bytes or if it should wait until it has enough in the buffer to read or finishes reading
+ * the entire content. It doesn't actually always mean that PHP will continue going after making
+ * the request.
+ *
+ * @access public
+ * @since 2.7.0
+ * @todo Refactor this code. The code in this method extends the scope of its original purpose
+ * and should be refactored to allow for cleaner abstraction and reduce duplication of the
+ * code. One suggestion is to create a class specifically for the arguments, however
+ * preliminary refactoring to this affect has affect more than just the scope of the
+ * arguments. Something to ponder at least.
+ *
+ * @param string $url URI resource.
+ * @param str|array $args Optional. Override the defaults.
+ * @return array|object Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
+ */
+ function request( $url, $args = array() ) {
+ global $wp_version;
+
+ $defaults = array(
+ 'method' => 'GET',
+ 'timeout' => apply_filters( 'http_request_timeout', 5),
+ 'redirection' => apply_filters( 'http_request_redirection_count', 5),
+ 'httpversion' => apply_filters( 'http_request_version', '1.0'),
+ 'user-agent' => apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' ) ),
+ 'reject_unsafe_urls' => apply_filters( 'http_request_reject_unsafe_urls', false ),
+ 'blocking' => true,
+ 'headers' => array(),
+ 'cookies' => array(),
+ 'body' => null,
+ 'compress' => false,
+ 'decompress' => true,
+ 'sslverify' => true,
+ 'stream' => false,
+ 'filename' => null,
+ 'limit_response_size' => null,
+ );
+
+ // Pre-parse for the HEAD checks.
+ $args = wp_parse_args( $args );
+
+ // By default, Head requests do not cause redirections.
+ if ( isset($args['method']) && 'HEAD' == $args['method'] )
+ $defaults['redirection'] = 0;
+
+ $r = wp_parse_args( $args, $defaults );
+ $r = apply_filters( 'http_request_args', $r, $url );
+
+ // The transports decrement this, store a copy of the original value for loop purposes.
+ if ( ! isset( $r['_redirection'] ) )
+ $r['_redirection'] = $r['redirection'];
+
+ // Allow plugins to short-circuit the request
+ $pre = apply_filters( 'pre_http_request', false, $r, $url );
+ if ( false !== $pre )
+ return $pre;
+
+ if ( function_exists( 'wp_kses_bad_protocol' ) ) {
+ if ( $r['reject_unsafe_urls'] )
+ $url = wp_http_validate_url( $url );
+ $url = wp_kses_bad_protocol( $url, array( 'http', 'https', 'ssl' ) );
+ }
+
+ $arrURL = @parse_url( $url );
+
+ if ( empty( $url ) || empty( $arrURL['scheme'] ) )
+ return new WP_Error('http_request_failed', __('A valid URL was not provided.'));
+
+ if ( $this->block_request( $url ) )
+ return new WP_Error( 'http_request_failed', __( 'User has blocked requests through HTTP.' ) );
+
+ // Determine if this is a https call and pass that on to the transport functions
+ // so that we can blacklist the transports that do not support ssl verification
+ $r['ssl'] = $arrURL['scheme'] == 'https' || $arrURL['scheme'] == 'ssl';
+
+ // Determine if this request is to OUR install of WordPress
+ $homeURL = parse_url( get_bloginfo( 'url' ) );
+ $r['local'] = $homeURL['host'] == $arrURL['host'] || 'localhost' == $arrURL['host'];
+ unset( $homeURL );
+
+ // If we are streaming to a file but no filename was given drop it in the WP temp dir
+ // and pick its name using the basename of the $url
+ if ( $r['stream'] && empty( $r['filename'] ) )
+ $r['filename'] = get_temp_dir() . basename( $url );
+
+ // Force some settings if we are streaming to a file and check for existence and perms of destination directory
+ if ( $r['stream'] ) {
+ $r['blocking'] = true;
+ if ( ! wp_is_writable( dirname( $r['filename'] ) ) )
+ return new WP_Error( 'http_request_failed', __( 'Destination directory for file streaming does not exist or is not writable.' ) );
+ }
+
+ if ( is_null( $r['headers'] ) )
+ $r['headers'] = array();
+
+ if ( ! is_array( $r['headers'] ) ) {
+ $processedHeaders = WP_Http::processHeaders( $r['headers'] );
+ $r['headers'] = $processedHeaders['headers'];
+ }
+
+ if ( isset( $r['headers']['User-Agent'] ) ) {
+ $r['user-agent'] = $r['headers']['User-Agent'];
+ unset( $r['headers']['User-Agent'] );
+ }
+
+ if ( isset( $r['headers']['user-agent'] ) ) {
+ $r['user-agent'] = $r['headers']['user-agent'];
+ unset( $r['headers']['user-agent'] );
+ }
+
+ // Construct Cookie: header if any cookies are set
+ WP_Http::buildCookieHeader( $r );
+
+ if ( ! isset( $r['headers']['Accept-Encoding'] ) ) {
+ if ( $encoding = WP_Http_Encoding::accept_encoding( $url, $r ) )
+ $r['headers']['Accept-Encoding'] = $encoding;
+ }
+
+ if ( ( ! is_null( $r['body'] ) && '' != $r['body'] ) || 'POST' == $r['method'] || 'PUT' == $r['method'] ) {
+ if ( is_array( $r['body'] ) || is_object( $r['body'] ) ) {
+ $r['body'] = http_build_query( $r['body'], null, '&' );
+
+ if ( ! isset( $r['headers']['Content-Type'] ) )
+ $r['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' );
+ }
+
+ if ( '' === $r['body'] )
+ $r['body'] = null;
+
+ if ( ! isset( $r['headers']['Content-Length'] ) && ! isset( $r['headers']['content-length'] ) )
+ $r['headers']['Content-Length'] = strlen( $r['body'] );
+ }
+
+ return $this->_dispatch_request($url, $r);
+ }
+
+ /**
+ * Tests which transports are capable of supporting the request.
+ *
+ * @since 3.2.0
+ * @access private
+ *
+ * @param array $args Request arguments
+ * @param string $url URL to Request
+ *
+ * @return string|bool Class name for the first transport that claims to support the request. False if no transport claims to support the request.
+ */
+ public function _get_first_available_transport( $args, $url = null ) {
+ $request_order = array( 'curl', 'streams', 'fsockopen' );
+
+ // Loop over each transport on each HTTP request looking for one which will serve this request's needs
+ foreach ( $request_order as $transport ) {
+ $class = 'WP_HTTP_' . $transport;
+
+ // Check to see if this transport is a possibility, calls the transport statically
+ if ( !call_user_func( array( $class, 'test' ), $args, $url ) )
+ continue;
+
+ return $class;
+ }
+
+ return false;
+ }
+
+ /**
+ * Dispatches a HTTP request to a supporting transport.
+ *
+ * Tests each transport in order to find a transport which matches the request arguments.
+ * Also caches the transport instance to be used later.
+ *
+ * The order for blocking requests is cURL, Streams, and finally Fsockopen.
+ * The order for non-blocking requests is cURL, Streams and Fsockopen().
+ *
+ * There are currently issues with "localhost" not resolving correctly with DNS. This may cause
+ * an error "failed to open stream: A connection attempt failed because the connected party did
+ * not properly respond after a period of time, or established connection failed because [the]
+ * connected host has failed to respond."
+ *
+ * @since 3.2.0
+ * @access private
+ *
+ * @param string $url URL to Request
+ * @param array $args Request arguments
+ * @return array|object Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
+ */
+ private function _dispatch_request( $url, $args ) {
+ static $transports = array();
+
+ $class = $this->_get_first_available_transport( $args, $url );
+ if ( !$class )
+ return new WP_Error( 'http_failure', __( 'There are no HTTP transports available which can complete the requested request.' ) );
+
+ // Transport claims to support request, instantiate it and give it a whirl.
+ if ( empty( $transports[$class] ) )
+ $transports[$class] = new $class;
+
+ $response = $transports[$class]->request( $url, $args );
+
+ do_action( 'http_api_debug', $response, 'response', $class, $args, $url );
+
+ if ( is_wp_error( $response ) )
+ return $response;
+
+ return apply_filters( 'http_response', $response, $args, $url );
+ }
+
+ /**
+ * Uses the POST HTTP method.
+ *
+ * Used for sending data that is expected to be in the body.
+ *
+ * @access public
+ * @since 2.7.0
+ *
+ * @param string $url URI resource.
+ * @param str|array $args Optional. Override the defaults.
+ * @return array|object Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
+ */
+ function post($url, $args = array()) {
+ $defaults = array('method' => 'POST');
+ $r = wp_parse_args( $args, $defaults );
+ return $this->request($url, $r);
+ }
+
+ /**
+ * Uses the GET HTTP method.
+ *
+ * Used for sending data that is expected to be in the body.
+ *
+ * @access public
+ * @since 2.7.0
+ *
+ * @param string $url URI resource.
+ * @param str|array $args Optional. Override the defaults.
+ * @return array|object Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
+ */
+ function get($url, $args = array()) {
+ $defaults = array('method' => 'GET');
+ $r = wp_parse_args( $args, $defaults );
+ return $this->request($url, $r);
+ }
+
+ /**
+ * Uses the HEAD HTTP method.
+ *
+ * Used for sending data that is expected to be in the body.
+ *
+ * @access public
+ * @since 2.7.0
+ *
+ * @param string $url URI resource.
+ * @param str|array $args Optional. Override the defaults.
+ * @return array|object Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
+ */
+ function head($url, $args = array()) {
+ $defaults = array('method' => 'HEAD');
+ $r = wp_parse_args( $args, $defaults );
+ return $this->request($url, $r);
+ }
+
+ /**
+ * Parses the responses and splits the parts into headers and body.
+ *
+ * @access public
+ * @static
+ * @since 2.7.0
+ *
+ * @param string $strResponse The full response string
+ * @return array Array with 'headers' and 'body' keys.
+ */
+ public static function processResponse($strResponse) {
+ $res = explode("\r\n\r\n", $strResponse, 2);
+
+ return array('headers' => $res[0], 'body' => isset($res[1]) ? $res[1] : '');
+ }
+
+ /**
+ * Transform header string into an array.
+ *
+ * If an array is given then it is assumed to be raw header data with numeric keys with the
+ * headers as the values. No headers must be passed that were already processed.
+ *
+ * @access public
+ * @static
+ * @since 2.7.0
+ *
+ * @param string|array $headers
+ * @return array Processed string headers. If duplicate headers are encountered,
+ * Then a numbered array is returned as the value of that header-key.
+ */
+ public static function processHeaders($headers) {
+ // split headers, one per array element
+ if ( is_string($headers) ) {
+ // tolerate line terminator: CRLF = LF (RFC 2616 19.3)
+ $headers = str_replace("\r\n", "\n", $headers);
+ // unfold folded header fields. LWS = [CRLF] 1*( SP | HT ) <US-ASCII SP, space (32)>, <US-ASCII HT, horizontal-tab (9)> (RFC 2616 2.2)
+ $headers = preg_replace('/\n[ \t]/', ' ', $headers);
+ // create the headers array
+ $headers = explode("\n", $headers);
+ }
+
+ $response = array('code' => 0, 'message' => '');
+
+ // If a redirection has taken place, The headers for each page request may have been passed.
+ // In this case, determine the final HTTP header and parse from there.
+ for ( $i = count($headers)-1; $i >= 0; $i-- ) {
+ if ( !empty($headers[$i]) && false === strpos($headers[$i], ':') ) {
+ $headers = array_splice($headers, $i);
+ break;
+ }
+ }
+
+ $cookies = array();
+ $newheaders = array();
+ foreach ( (array) $headers as $tempheader ) {
+ if ( empty($tempheader) )
+ continue;
+
+ if ( false === strpos($tempheader, ':') ) {
+ $stack = explode(' ', $tempheader, 3);
+ $stack[] = '';
+ list( , $response['code'], $response['message']) = $stack;
+ continue;
+ }
+
+ list($key, $value) = explode(':', $tempheader, 2);
+
+ $key = strtolower( $key );
+ $value = trim( $value );
+
+ if ( isset( $newheaders[ $key ] ) ) {
+ if ( ! is_array( $newheaders[ $key ] ) )
+ $newheaders[$key] = array( $newheaders[ $key ] );
+ $newheaders[ $key ][] = $value;
+ } else {
+ $newheaders[ $key ] = $value;
+ }
+ if ( 'set-cookie' == $key )
+ $cookies[] = new WP_Http_Cookie( $value );
+ }
+
+ return array('response' => $response, 'headers' => $newheaders, 'cookies' => $cookies);
+ }
+
+ /**
+ * Takes the arguments for a ::request() and checks for the cookie array.
+ *
+ * If it's found, then it's assumed to contain WP_Http_Cookie objects, which are each parsed
+ * into strings and added to the Cookie: header (within the arguments array). Edits the array by
+ * reference.
+ *
+ * @access public
+ * @version 2.8.0
+ * @static
+ *
+ * @param array $r Full array of args passed into ::request()
+ */
+ public static function buildCookieHeader( &$r ) {
+ if ( ! empty($r['cookies']) ) {
+ $cookies_header = '';
+ foreach ( (array) $r['cookies'] as $cookie ) {
+ $cookies_header .= $cookie->getHeaderValue() . '; ';
+ }
+ $cookies_header = substr( $cookies_header, 0, -2 );
+ $r['headers']['cookie'] = $cookies_header;
+ }
+ }
+
+ /**
+ * Decodes chunk transfer-encoding, based off the HTTP 1.1 specification.
+ *
+ * Based off the HTTP http_encoding_dechunk function. Does not support UTF-8. Does not support
+ * returning footer headers. Shouldn't be too difficult to support it though.
+ *
+ * @link http://tools.ietf.org/html/rfc2616#section-19.4.6 Process for chunked decoding.
+ *
+ * @todo Add support for footer chunked headers.
+ * @access public
+ * @since 2.7.0
+ * @static
+ *
+ * @param string $body Body content
+ * @return string Chunked decoded body on success or raw body on failure.
+ */
+ function chunkTransferDecode($body) {
+ $body = str_replace(array("\r\n", "\r"), "\n", $body);
+ // The body is not chunked encoding or is malformed.
+ if ( ! preg_match( '/^[0-9a-f]+(\s|\n)+/mi', trim($body) ) )
+ return $body;
+
+ $parsedBody = '';
+ //$parsedHeaders = array(); Unsupported
+
+ while ( true ) {
+ $hasChunk = (bool) preg_match( '/^([0-9a-f]+)(\s|\n)+/mi', $body, $match );
+
+ if ( $hasChunk ) {
+ if ( empty( $match[1] ) )
+ return $body;
+
+ $length = hexdec( $match[1] );
+ $chunkLength = strlen( $match[0] );
+
+ $strBody = substr($body, $chunkLength, $length);
+ $parsedBody .= $strBody;
+
+ $body = ltrim(str_replace(array($match[0], $strBody), '', $body), "\n");
+
+ if ( "0" == trim($body) )
+ return $parsedBody; // Ignore footer headers.
+ } else {
+ return $body;
+ }
+ }
+ }
+
+ /**
+ * Block requests through the proxy.
+ *
+ * Those who are behind a proxy and want to prevent access to certain hosts may do so. This will
+ * prevent plugins from working and core functionality, if you don't include api.wordpress.org.
+ *
+ * You block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL as true in your wp-config.php
+ * file and this will only allow localhost and your blog to make requests. The constant
+ * WP_ACCESSIBLE_HOSTS will allow additional hosts to go through for requests. The format of the
+ * WP_ACCESSIBLE_HOSTS constant is a comma separated list of hostnames to allow, wildcard domains
+ * are supported, eg *.wordpress.org will allow for all subdomains of wordpress.org to be contacted.
+ *
+ * @since 2.8.0
+ * @link http://core.trac.wordpress.org/ticket/8927 Allow preventing external requests.
+ * @link http://core.trac.wordpress.org/ticket/14636 Allow wildcard domains in WP_ACCESSIBLE_HOSTS
+ *
+ * @param string $uri URI of url.
+ * @return bool True to block, false to allow.
+ */
+ function block_request($uri) {
+ // We don't need to block requests, because nothing is blocked.
+ if ( ! defined( 'WP_HTTP_BLOCK_EXTERNAL' ) || ! WP_HTTP_BLOCK_EXTERNAL )
+ return false;
+
+ // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure.
+ // This will be displayed on blogs, which is not reasonable.
+ $check = @parse_url($uri);
+
+ /* Malformed URL, can not process, but this could mean ssl, so let through anyway.
+ *
+ * This isn't very security sound. There are instances where a hacker might attempt
+ * to bypass the proxy and this check. However, the reason for this behavior is that
+ * WordPress does not do any checking currently for non-proxy requests, so it is keeps with
+ * the default unsecure nature of the HTTP request.
+ */
+ if ( $check === false )
+ return false;
+
+ $home = parse_url( get_option('siteurl') );
+
+ // Don't block requests back to ourselves by default
+ if ( $check['host'] == 'localhost' || $check['host'] == $home['host'] )
+ return apply_filters('block_local_requests', false);
+
+ if ( !defined('WP_ACCESSIBLE_HOSTS') )
+ return true;
+
+ static $accessible_hosts;
+ static $wildcard_regex = false;
+ if ( null == $accessible_hosts ) {
+ $accessible_hosts = preg_split('|,\s*|', WP_ACCESSIBLE_HOSTS);
+
+ if ( false !== strpos(WP_ACCESSIBLE_HOSTS, '*') ) {
+ $wildcard_regex = array();
+ foreach ( $accessible_hosts as $host )
+ $wildcard_regex[] = str_replace('\*', '[\w.]+?', preg_quote($host, '/'));
+ $wildcard_regex = '/^(' . implode('|', $wildcard_regex) . ')$/i';
+ }
+ }
+
+ if ( !empty($wildcard_regex) )
+ return !preg_match($wildcard_regex, $check['host']);
+ else
+ return !in_array( $check['host'], $accessible_hosts ); //Inverse logic, If it's in the array, then we can't access it.
+
+ }
+
+ static function make_absolute_url( $maybe_relative_path, $url ) {
+ if ( empty( $url ) )
+ return $maybe_relative_path;
+
+ // Check for a scheme
+ if ( false !== strpos( $maybe_relative_path, '://' ) )
+ return $maybe_relative_path;
+
+ if ( ! $url_parts = @parse_url( $url ) )
+ return $maybe_relative_path;
+
+ if ( ! $relative_url_parts = @parse_url( $maybe_relative_path ) )
+ return $maybe_relative_path;
+
+ $absolute_path = $url_parts['scheme'] . '://' . $url_parts['host'];
+ if ( isset( $url_parts['port'] ) )
+ $absolute_path .= ':' . $url_parts['port'];
+
+ // Start off with the Absolute URL path
+ $path = ! empty( $url_parts['path'] ) ? $url_parts['path'] : '/';
+
+ // If it's a root-relative path, then great
+ if ( ! empty( $relative_url_parts['path'] ) && '/' == $relative_url_parts['path'][0] ) {
+ $path = $relative_url_parts['path'];
+
+ // Else it's a relative path
+ } elseif ( ! empty( $relative_url_parts['path'] ) ) {
+ // Strip off any file components from the absolute path
+ $path = substr( $path, 0, strrpos( $path, '/' ) + 1 );
+
+ // Build the new path
+ $path .= $relative_url_parts['path'];
+
+ // Strip all /path/../ out of the path
+ while ( strpos( $path, '../' ) > 1 ) {
+ $path = preg_replace( '![^/]+/\.\./!', '', $path );
+ }
+
+ // Strip any final leading ../ from the path
+ $path = preg_replace( '!^/(\.\./)+!', '', $path );
+ }
+
+ // Add the Query string
+ if ( ! empty( $relative_url_parts['query'] ) )
+ $path .= '?' . $relative_url_parts['query'];
+
+ return $absolute_path . '/' . ltrim( $path, '/' );
+ }
+
+ /**
+ * Handles HTTP Redirects and follows them if appropriate.
+ *
+ * @since 3.7.0
+ *
+ * @param string $url The URL which was requested.
+ * @param array $args The Arguements which were used to make the request.
+ * @param array $response The Response of the HTTP request.
+ * @return false|object False if no redirect is present, a WP_HTTP or WP_Error result otherwise.
+ */
+ static function handle_redirects( $url, $args, $response ) {
+ // If no redirects are present, or, redirects were not requested, perform no action.
+ if ( ! isset( $response['headers']['location'] ) || 0 === $args['_redirection'] )
+ return false;
+
+ // Only perform redirections on redirection http codes
+ if ( $response['response']['code'] > 399 || $response['response']['code'] < 300 )
+ return false;
+
+ // Don't redirect if we've run out of redirects
+ if ( $args['redirection']-- <= 0 )
+ return new WP_Error( 'http_request_failed', __('Too many redirects.') );
+
+ $redirect_location = $response['headers']['location'];
+
+ // If there were multiple Location headers, use the last header specified
+ if ( is_array( $redirect_location ) )
+ $redirect_location = array_pop( $redirect_location );
+
+ $redirect_location = WP_HTTP::make_absolute_url( $redirect_location, $url );
+
+ // POST requests should not POST to a redirected location
+ if ( 'POST' == $args['method'] ) {
+ if ( in_array( $response['response']['code'], array( 302, 303 ) ) )
+ $args['method'] = 'GET';
+ }
+
+ return wp_remote_request( $redirect_location, $args );
+ }
+}
+
+/**
+ * HTTP request method uses fsockopen function to retrieve the url.
+ *
+ * This would be the preferred method, but the fsockopen implementation has the most overhead of all
+ * the HTTP transport implementations.
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.7.0
+ */
+class WP_Http_Fsockopen {
+ /**
+ * Send a HTTP request to a URI using fsockopen().
+ *
+ * Does not support non-blocking mode.
+ *
+ * @see WP_Http::request For default options descriptions.
+ *
+ * @since 2.7
+ * @access public
+ * @param string $url URI resource.
+ * @param str|array $args Optional. Override the defaults.
+ * @return array 'headers', 'body', 'response', 'cookies' and 'filename' keys.
+ */
+ function request($url, $args = array()) {
+ $defaults = array(
+ 'method' => 'GET', 'timeout' => 5,
+ 'redirection' => 5, 'httpversion' => '1.0',
+ 'blocking' => true,
+ 'headers' => array(), 'body' => null, 'cookies' => array()
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ if ( isset($r['headers']['User-Agent']) ) {
+ $r['user-agent'] = $r['headers']['User-Agent'];
+ unset($r['headers']['User-Agent']);
+ } else if ( isset($r['headers']['user-agent']) ) {
+ $r['user-agent'] = $r['headers']['user-agent'];
+ unset($r['headers']['user-agent']);
+ }
+
+ // Construct Cookie: header if any cookies are set
+ WP_Http::buildCookieHeader( $r );
+
+ $iError = null; // Store error number
+ $strError = null; // Store error string
+
+ $arrURL = parse_url($url);
+
+ $fsockopen_host = $arrURL['host'];
+
+ $secure_transport = false;
+
+ if ( ! isset( $arrURL['port'] ) ) {
+ if ( ( $arrURL['scheme'] == 'ssl' || $arrURL['scheme'] == 'https' ) && extension_loaded('openssl') ) {
+ $fsockopen_host = "ssl://$fsockopen_host";
+ $arrURL['port'] = 443;
+ $secure_transport = true;
+ } else {
+ $arrURL['port'] = 80;
+ }
+ }
+
+ if ( isset( $r['headers']['Host'] ) || isset( $r['headers']['host'] ) ) {
+ if ( isset( $r['headers']['Host'] ) )
+ $arrURL['host'] = $r['headers']['Host'];
+ else
+ $arrURL['host'] = $r['headers']['host'];
+ unset( $r['headers']['Host'], $r['headers']['host'] );
+ }
+
+ //fsockopen has issues with 'localhost' with IPv6 with certain versions of PHP, It attempts to connect to ::1,
+ // which fails when the server is not set up for it. For compatibility, always connect to the IPv4 address.
+ if ( 'localhost' == strtolower($fsockopen_host) )
+ $fsockopen_host = '127.0.0.1';
+
+ // There are issues with the HTTPS and SSL protocols that cause errors that can be safely
+ // ignored and should be ignored.
+ if ( true === $secure_transport )
+ $error_reporting = error_reporting(0);
+
+ $startDelay = time();
+
+ $proxy = new WP_HTTP_Proxy();
+
+ if ( !WP_DEBUG ) {
+ if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) )
+ $handle = @fsockopen( $proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] );
+ else
+ $handle = @fsockopen( $fsockopen_host, $arrURL['port'], $iError, $strError, $r['timeout'] );
+ } else {
+ if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) )
+ $handle = fsockopen( $proxy->host(), $proxy->port(), $iError, $strError, $r['timeout'] );
+ else
+ $handle = fsockopen( $fsockopen_host, $arrURL['port'], $iError, $strError, $r['timeout'] );
+ }
+
+ $endDelay = time();
+
+ // If the delay is greater than the timeout then fsockopen shouldn't be used, because it will
+ // cause a long delay.
+ $elapseDelay = ($endDelay-$startDelay) > $r['timeout'];
+ if ( true === $elapseDelay )
+ add_option( 'disable_fsockopen', $endDelay, null, true );
+
+ if ( false === $handle )
+ return new WP_Error('http_request_failed', $iError . ': ' . $strError);
+
+ $timeout = (int) floor( $r['timeout'] );
+ $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000;
+ stream_set_timeout( $handle, $timeout, $utimeout );
+
+ if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) //Some proxies require full URL in this field.
+ $requestPath = $url;
+ else
+ $requestPath = $arrURL['path'] . ( isset($arrURL['query']) ? '?' . $arrURL['query'] : '' );
+
+ if ( empty($requestPath) )
+ $requestPath .= '/';
+
+ $strHeaders = strtoupper($r['method']) . ' ' . $requestPath . ' HTTP/' . $r['httpversion'] . "\r\n";
+
+ if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) )
+ $strHeaders .= 'Host: ' . $arrURL['host'] . ':' . $arrURL['port'] . "\r\n";
+ else
+ $strHeaders .= 'Host: ' . $arrURL['host'] . "\r\n";
+
+ if ( isset($r['user-agent']) )
+ $strHeaders .= 'User-agent: ' . $r['user-agent'] . "\r\n";
+
+ if ( is_array($r['headers']) ) {
+ foreach ( (array) $r['headers'] as $header => $headerValue )
+ $strHeaders .= $header . ': ' . $headerValue . "\r\n";
+ } else {
+ $strHeaders .= $r['headers'];
+ }
+
+ if ( $proxy->use_authentication() )
+ $strHeaders .= $proxy->authentication_header() . "\r\n";
+
+ $strHeaders .= "\r\n";
+
+ if ( ! is_null($r['body']) )
+ $strHeaders .= $r['body'];
+
+ fwrite($handle, $strHeaders);
+
+ if ( ! $r['blocking'] ) {
+ fclose($handle);
+ return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
+ }
+
+ $strResponse = '';
+ $bodyStarted = false;
+ $keep_reading = true;
+ $block_size = 4096;
+ if ( isset( $r['limit_response_size'] ) )
+ $block_size = min( $block_size, $r['limit_response_size'] );
+
+ // If streaming to a file setup the file handle
+ if ( $r['stream'] ) {
+ if ( ! WP_DEBUG )
+ $stream_handle = @fopen( $r['filename'], 'w+' );
+ else
+ $stream_handle = fopen( $r['filename'], 'w+' );
+ if ( ! $stream_handle )
+ return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
+
+ $bytes_written = 0;
+ while ( ! feof($handle) && $keep_reading ) {
+ $block = fread( $handle, $block_size );
+ if ( ! $bodyStarted ) {
+ $strResponse .= $block;
+ if ( strpos( $strResponse, "\r\n\r\n" ) ) {
+ $process = WP_Http::processResponse( $strResponse );
+ $bodyStarted = true;
+ $block = $process['body'];
+ unset( $strResponse );
+ $process['body'] = '';
+ }
+ }
+
+ if ( isset( $r['limit_response_size'] ) && ( $bytes_written + strlen( $block ) ) > $r['limit_response_size'] )
+ $block = substr( $block, 0, ( $r['limit_response_size'] - $bytes_written ) );
+
+ $bytes_written += fwrite( $stream_handle, $block );
+
+ $keep_reading = !isset( $r['limit_response_size'] ) || $bytes_written < $r['limit_response_size'];
+ }
+
+ fclose( $stream_handle );
+
+ } else {
+ $header_length = 0;
+ while ( ! feof( $handle ) && $keep_reading ) {
+ $block = fread( $handle, $block_size );
+ $strResponse .= $block;
+ if ( ! $bodyStarted && strpos( $strResponse, "\r\n\r\n" ) ) {
+ $header_length = strpos( $strResponse, "\r\n\r\n" ) + 4;
+ $bodyStarted = true;
+ }
+ $keep_reading = ( ! $bodyStarted || !isset( $r['limit_response_size'] ) || strlen( $strResponse ) < ( $header_length + $r['limit_response_size'] ) );
+ }
+
+ $process = WP_Http::processResponse( $strResponse );
+ unset( $strResponse );
+
+ }
+
+ fclose( $handle );
+
+ if ( true === $secure_transport )
+ error_reporting($error_reporting);
+
+ $arrHeaders = WP_Http::processHeaders( $process['headers'] );
+
+ $response = array(
+ 'headers' => $arrHeaders['headers'],
+ 'body' => null, // Not yet processed
+ 'response' => $arrHeaders['response'],
+ 'cookies' => $arrHeaders['cookies'],
+ 'filename' => $r['filename']
+ );
+
+ // Handle redirects
+ if ( false !== ( $redirect_response = WP_HTTP::handle_redirects( $url, $r, $response ) ) )
+ return $redirect_response;
+
+ // If the body was chunk encoded, then decode it.
+ if ( ! empty( $process['body'] ) && isset( $arrHeaders['headers']['transfer-encoding'] ) && 'chunked' == $arrHeaders['headers']['transfer-encoding'] )
+ $process['body'] = WP_Http::chunkTransferDecode($process['body']);
+
+ if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($arrHeaders['headers']) )
+ $process['body'] = WP_Http_Encoding::decompress( $process['body'] );
+
+ if ( isset( $r['limit_response_size'] ) && strlen( $process['body'] ) > $r['limit_response_size'] )
+ $process['body'] = substr( $process['body'], 0, $r['limit_response_size'] );
+
+ $response['body'] = $process['body'];
+
+ return $response;
+ }
+
+ /**
+ * Whether this class can be used for retrieving an URL.
+ *
+ * @since 2.7.0
+ * @static
+ * @return boolean False means this class can not be used, true means it can.
+ */
+ public static function test( $args = array() ) {
+ if ( ! function_exists( 'fsockopen' ) )
+ return false;
+
+ if ( false !== ( $option = get_option( 'disable_fsockopen' ) ) && time() - $option < 12 * HOUR_IN_SECONDS )
+ return false;
+
+ $is_ssl = isset( $args['ssl'] ) && $args['ssl'];
+
+ if ( $is_ssl && ! extension_loaded( 'openssl' ) )
+ return false;
+
+ return apply_filters( 'use_fsockopen_transport', true, $args );
+ }
+}
+
+/**
+ * HTTP request method uses Streams to retrieve the url.
+ *
+ * Requires PHP 5.0+ and uses fopen with stream context. Requires that 'allow_url_fopen' PHP setting
+ * to be enabled.
+ *
+ * Second preferred method for getting the URL, for PHP 5.
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.7.0
+ */
+class WP_Http_Streams {
+ /**
+ * Send a HTTP request to a URI using streams with fopen().
+ *
+ * @access public
+ * @since 2.7.0
+ *
+ * @param string $url
+ * @param str|array $args Optional. Override the defaults.
+ * @return array 'headers', 'body', 'response', 'cookies' and 'filename' keys.
+ */
+ function request($url, $args = array()) {
+ $defaults = array(
+ 'method' => 'GET', 'timeout' => 5,
+ 'redirection' => 5, 'httpversion' => '1.0',
+ 'blocking' => true,
+ 'headers' => array(), 'body' => null, 'cookies' => array()
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ if ( isset($r['headers']['User-Agent']) ) {
+ $r['user-agent'] = $r['headers']['User-Agent'];
+ unset($r['headers']['User-Agent']);
+ } else if ( isset($r['headers']['user-agent']) ) {
+ $r['user-agent'] = $r['headers']['user-agent'];
+ unset($r['headers']['user-agent']);
+ }
+
+ // Construct Cookie: header if any cookies are set
+ WP_Http::buildCookieHeader( $r );
+
+ $arrURL = parse_url($url);
+
+ if ( false === $arrURL )
+ return new WP_Error('http_request_failed', sprintf(__('Malformed URL: %s'), $url));
+
+ if ( 'http' != $arrURL['scheme'] && 'https' != $arrURL['scheme'] )
+ $url = preg_replace('|^' . preg_quote($arrURL['scheme'], '|') . '|', 'http', $url);
+
+ // Convert Header array to string.
+ $strHeaders = '';
+ if ( is_array( $r['headers'] ) )
+ foreach ( $r['headers'] as $name => $value )
+ $strHeaders .= "{$name}: $value\r\n";
+ else if ( is_string( $r['headers'] ) )
+ $strHeaders = $r['headers'];
+
+ $is_local = isset($args['local']) && $args['local'];
+ $ssl_verify = isset($args['sslverify']) && $args['sslverify'];
+ if ( $is_local )
+ $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify);
+ elseif ( ! $is_local )
+ $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify);
+
+ $arrContext = array('http' =>
+ array(
+ 'method' => strtoupper($r['method']),
+ 'user_agent' => $r['user-agent'],
+ 'max_redirects' => 0, // Follow no redirects
+ 'follow_redirects' => false,
+ 'protocol_version' => (float) $r['httpversion'],
+ 'header' => $strHeaders,
+ 'ignore_errors' => true, // Return non-200 requests.
+ 'timeout' => $r['timeout'],
+ 'ssl' => array(
+ 'verify_peer' => $ssl_verify,
+ 'verify_host' => $ssl_verify
+ )
+ )
+ );
+
+ $proxy = new WP_HTTP_Proxy();
+
+ if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
+ $arrContext['http']['proxy'] = 'tcp://' . $proxy->host() . ':' . $proxy->port();
+ $arrContext['http']['request_fulluri'] = true;
+
+ // We only support Basic authentication so this will only work if that is what your proxy supports.
+ if ( $proxy->use_authentication() )
+ $arrContext['http']['header'] .= $proxy->authentication_header() . "\r\n";
+ }
+
+ if ( ! is_null( $r['body'] ) )
+ $arrContext['http']['content'] = $r['body'];
+
+ $context = stream_context_create($arrContext);
+
+ if ( !WP_DEBUG )
+ $handle = @fopen($url, 'r', false, $context);
+ else
+ $handle = fopen($url, 'r', false, $context);
+
+ if ( ! $handle )
+ return new WP_Error('http_request_failed', sprintf(__('Could not open handle for fopen() to %s'), $url));
+
+ $timeout = (int) floor( $r['timeout'] );
+ $utimeout = $timeout == $r['timeout'] ? 0 : 1000000 * $r['timeout'] % 1000000;
+ stream_set_timeout( $handle, $timeout, $utimeout );
+
+ if ( ! $r['blocking'] ) {
+ stream_set_blocking($handle, 0);
+ fclose($handle);
+ return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
+ }
+
+ $max_bytes = isset( $r['limit_response_size'] ) ? intval( $r['limit_response_size'] ) : -1;
+ if ( $r['stream'] ) {
+ if ( ! WP_DEBUG )
+ $stream_handle = @fopen( $r['filename'], 'w+' );
+ else
+ $stream_handle = fopen( $r['filename'], 'w+' );
+
+ if ( ! $stream_handle )
+ return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
+
+ stream_copy_to_stream( $handle, $stream_handle, $max_bytes );
+
+ fclose( $stream_handle );
+ $strResponse = '';
+ } else {
+ $strResponse = stream_get_contents( $handle, $max_bytes );
+ }
+
+ $meta = stream_get_meta_data( $handle );
+
+ fclose( $handle );
+
+ $processedHeaders = array();
+ if ( isset( $meta['wrapper_data']['headers'] ) )
+ $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']['headers']);
+ else
+ $processedHeaders = WP_Http::processHeaders($meta['wrapper_data']);
+
+ $response = array(
+ 'headers' => $processedHeaders['headers'],
+ 'body' => null,
+ 'response' => $processedHeaders['response'],
+ 'cookies' => $processedHeaders['cookies'],
+ 'filename' => $r['filename']
+ );
+
+ // Handle redirects
+ if ( false !== ( $redirect_response = WP_HTTP::handle_redirects( $url, $r, $response ) ) )
+ return $redirect_response;
+
+ if ( ! empty( $strResponse ) && isset( $processedHeaders['headers']['transfer-encoding'] ) && 'chunked' == $processedHeaders['headers']['transfer-encoding'] )
+ $strResponse = WP_Http::chunkTransferDecode($strResponse);
+
+ if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($processedHeaders['headers']) )
+ $strResponse = WP_Http_Encoding::decompress( $strResponse );
+
+ $response['body'] = $strResponse;
+
+ return $response;
+ }
+
+ /**
+ * Whether this class can be used for retrieving an URL.
+ *
+ * @static
+ * @access public
+ * @since 2.7.0
+ *
+ * @return boolean False means this class can not be used, true means it can.
+ */
+ public static function test( $args = array() ) {
+ if ( ! function_exists( 'fopen' ) )
+ return false;
+
+ if ( ! function_exists( 'ini_get' ) || true != ini_get( 'allow_url_fopen' ) )
+ return false;
+
+ $is_ssl = isset( $args['ssl'] ) && $args['ssl'];
+
+ if ( $is_ssl && ! extension_loaded( 'openssl' ) )
+ return false;
+
+ return apply_filters( 'use_streams_transport', true, $args );
+ }
+}
+
+/**
+ * HTTP request method uses Curl extension to retrieve the url.
+ *
+ * Requires the Curl extension to be installed.
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.7
+ */
+class WP_Http_Curl {
+
+ /**
+ * Temporary header storage for during requests.
+ *
+ * @since 3.2.0
+ * @access private
+ * @var string
+ */
+ private $headers = '';
+
+ /**
+ * Temporary body storage for during requests.
+ *
+ * @since 3.6.0
+ * @access private
+ * @var string
+ */
+ private $body = '';
+
+ /**
+ * The maximum amount of data to recieve from the remote server
+ *
+ * @since 3.6.0
+ * @access private
+ * @var int
+ */
+ private $max_body_length = false;
+
+ /**
+ * The file resource used for streaming to file.
+ *
+ * @since 3.6.0
+ * @access private
+ * @var resource
+ */
+ private $stream_handle = false;
+
+ /**
+ * Send a HTTP request to a URI using cURL extension.
+ *
+ * @access public
+ * @since 2.7.0
+ *
+ * @param string $url
+ * @param str|array $args Optional. Override the defaults.
+ * @return array 'headers', 'body', 'response', 'cookies' and 'filename' keys.
+ */
+ function request($url, $args = array()) {
+ $defaults = array(
+ 'method' => 'GET', 'timeout' => 5,
+ 'redirection' => 5, 'httpversion' => '1.0',
+ 'blocking' => true,
+ 'headers' => array(), 'body' => null, 'cookies' => array()
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ if ( isset($r['headers']['User-Agent']) ) {
+ $r['user-agent'] = $r['headers']['User-Agent'];
+ unset($r['headers']['User-Agent']);
+ } else if ( isset($r['headers']['user-agent']) ) {
+ $r['user-agent'] = $r['headers']['user-agent'];
+ unset($r['headers']['user-agent']);
+ }
+
+ // Construct Cookie: header if any cookies are set.
+ WP_Http::buildCookieHeader( $r );
+
+ $handle = curl_init();
+
+ // cURL offers really easy proxy support.
+ $proxy = new WP_HTTP_Proxy();
+
+ if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
+
+ curl_setopt( $handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
+ curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() );
+ curl_setopt( $handle, CURLOPT_PROXYPORT, $proxy->port() );
+
+ if ( $proxy->use_authentication() ) {
+ curl_setopt( $handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
+ curl_setopt( $handle, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
+ }
+ }
+
+ $is_local = isset($r['local']) && $r['local'];
+ $ssl_verify = isset($r['sslverify']) && $r['sslverify'];
+ if ( $is_local )
+ $ssl_verify = apply_filters('https_local_ssl_verify', $ssl_verify);
+ elseif ( ! $is_local )
+ $ssl_verify = apply_filters('https_ssl_verify', $ssl_verify);
+
+ // CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT expect integers. Have to use ceil since
+ // a value of 0 will allow an unlimited timeout.
+ $timeout = (int) ceil( $r['timeout'] );
+ curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, $timeout );
+ curl_setopt( $handle, CURLOPT_TIMEOUT, $timeout );
+
+ curl_setopt( $handle, CURLOPT_URL, $url);
+ curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true );
+ curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, ( $ssl_verify === true ) ? 2 : false );
+ curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify );
+ curl_setopt( $handle, CURLOPT_USERAGENT, $r['user-agent'] );
+ // The option doesn't work with safe mode or when open_basedir is set, and there's a
+ // bug #17490 with redirected POST requests, so handle redirections outside Curl.
+ curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, false );
+ if ( defined( 'CURLOPT_PROTOCOLS' ) ) // PHP 5.2.10 / cURL 7.19.4
+ curl_setopt( $handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS );
+
+ switch ( $r['method'] ) {
+ case 'HEAD':
+ curl_setopt( $handle, CURLOPT_NOBODY, true );
+ break;
+ case 'POST':
+ curl_setopt( $handle, CURLOPT_POST, true );
+ curl_setopt( $handle, CURLOPT_POSTFIELDS, $r['body'] );
+ break;
+ case 'PUT':
+ curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'PUT' );
+ curl_setopt( $handle, CURLOPT_POSTFIELDS, $r['body'] );
+ break;
+ default:
+ curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, $r['method'] );
+ if ( ! is_null( $r['body'] ) )
+ curl_setopt( $handle, CURLOPT_POSTFIELDS, $r['body'] );
+ break;
+ }
+
+ if ( true === $r['blocking'] ) {
+ curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( $this, 'stream_headers' ) );
+ curl_setopt( $handle, CURLOPT_WRITEFUNCTION, array( $this, 'stream_body' ) );
+ }
+
+ curl_setopt( $handle, CURLOPT_HEADER, false );
+
+ if ( isset( $r['limit_response_size'] ) )
+ $this->max_body_length = intval( $r['limit_response_size'] );
+ else
+ $this->max_body_length = false;
+
+ // If streaming to a file open a file handle, and setup our curl streaming handler
+ if ( $r['stream'] ) {
+ if ( ! WP_DEBUG )
+ $this->stream_handle = @fopen( $r['filename'], 'w+' );
+ else
+ $this->stream_handle = fopen( $r['filename'], 'w+' );
+ if ( ! $this->stream_handle )
+ return new WP_Error( 'http_request_failed', sprintf( __( 'Could not open handle for fopen() to %s' ), $r['filename'] ) );
+ } else {
+ $this->stream_handle = false;
+ }
+
+ if ( !empty( $r['headers'] ) ) {
+ // cURL expects full header strings in each element
+ $headers = array();
+ foreach ( $r['headers'] as $name => $value ) {
+ $headers[] = "{$name}: $value";
+ }
+ curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers );
+ }
+
+ if ( $r['httpversion'] == '1.0' )
+ curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
+ else
+ curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
+
+ // Cookies are not handled by the HTTP API currently. Allow for plugin authors to handle it
+ // themselves... Although, it is somewhat pointless without some reference.
+ do_action_ref_array( 'http_api_curl', array(&$handle) );
+
+ // We don't need to return the body, so don't. Just execute request and return.
+ if ( ! $r['blocking'] ) {
+ curl_exec( $handle );
+
+ if ( $curl_error = curl_error( $handle ) ) {
+ curl_close( $handle );
+ return new WP_Error( 'http_request_failed', $curl_error );
+ }
+ if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ) ) ) {
+ curl_close( $handle );
+ return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
+ }
+
+ curl_close( $handle );
+ return array( 'headers' => array(), 'body' => '', 'response' => array('code' => false, 'message' => false), 'cookies' => array() );
+ }
+
+ $theResponse = curl_exec( $handle );
+ $theHeaders = WP_Http::processHeaders( $this->headers );
+ $theBody = $this->body;
+
+ $this->headers = '';
+ $this->body = '';
+
+ // If no response
+ if ( 0 == strlen( $theBody ) && empty( $theHeaders['headers'] ) ) {
+ if ( $curl_error = curl_error( $handle ) ) {
+ curl_close( $handle );
+ return new WP_Error( 'http_request_failed', $curl_error );
+ }
+ if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ) ) ) {
+ curl_close( $handle );
+ return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
+ }
+ }
+
+ $response = array();
+ $response['code'] = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
+ $response['message'] = get_status_header_desc($response['code']);
+
+ curl_close( $handle );
+
+ if ( $r['stream'] )
+ fclose( $this->stream_handle );
+
+ $response = array(
+ 'headers' => $theHeaders['headers'],
+ 'body' => null,
+ 'response' => $response,
+ 'cookies' => $theHeaders['cookies'],
+ 'filename' => $r['filename']
+ );
+
+ // Handle redirects
+ if ( false !== ( $redirect_response = WP_HTTP::handle_redirects( $url, $r, $response ) ) )
+ return $redirect_response;
+
+ if ( true === $r['decompress'] && true === WP_Http_Encoding::should_decode($theHeaders['headers']) )
+ $theBody = WP_Http_Encoding::decompress( $theBody );
+
+ $response['body'] = $theBody;
+
+ return $response;
+ }
+
+ /**
+ * Grab the headers of the cURL request
+ *
+ * Each header is sent individually to this callback, so we append to the $header property for temporary storage
+ *
+ * @since 3.2.0
+ * @access private
+ * @return int
+ */
+ private function stream_headers( $handle, $headers ) {
+ $this->headers .= $headers;
+ return strlen( $headers );
+ }
+
+ /**
+ * Grab the body of the cURL request
+ *
+ * The contents of the document are passed in chunks, so we append to the $body property for temporary storage.
+ * Returning a length shorter than the length of $data passed in will cause cURL to abort the request as "completed"
+ *
+ * @since 3.6.0
+ * @access private
+ * @return int
+ */
+ private function stream_body( $handle, $data ) {
+ if ( $this->max_body_length && ( strlen( $this->body ) + strlen( $data ) ) > $this->max_body_length )
+ $data = substr( $data, 0, ( $this->max_body_length - strlen( $this->body ) ) );
+
+ if ( $this->stream_handle )
+ fwrite( $this->stream_handle, $data );
+ else
+ $this->body .= $data;
+
+ return strlen( $data );
+ }
+
+ /**
+ * Whether this class can be used for retrieving an URL.
+ *
+ * @static
+ * @since 2.7.0
+ *
+ * @return boolean False means this class can not be used, true means it can.
+ */
+ public static function test( $args = array() ) {
+ if ( ! function_exists( 'curl_init' ) || ! function_exists( 'curl_exec' ) )
+ return false;
+
+ $is_ssl = isset( $args['ssl'] ) && $args['ssl'];
+
+ if ( $is_ssl ) {
+ $curl_version = curl_version();
+ if ( ! (CURL_VERSION_SSL & $curl_version['features']) ) // Does this cURL version support SSL requests?
+ return false;
+ }
+
+ return apply_filters( 'use_curl_transport', true, $args );
+ }
+}
+
+/**
+ * Adds Proxy support to the WordPress HTTP API.
+ *
+ * There are caveats to proxy support. It requires that defines be made in the wp-config.php file to
+ * enable proxy support. There are also a few filters that plugins can hook into for some of the
+ * constants.
+ *
+ * Please note that only BASIC authentication is supported by most transports.
+ * cURL MAY support more methods (such as NTLM authentication) depending on your environment.
+ *
+ * The constants are as follows:
+ * <ol>
+ * <li>WP_PROXY_HOST - Enable proxy support and host for connecting.</li>
+ * <li>WP_PROXY_PORT - Proxy port for connection. No default, must be defined.</li>
+ * <li>WP_PROXY_USERNAME - Proxy username, if it requires authentication.</li>
+ * <li>WP_PROXY_PASSWORD - Proxy password, if it requires authentication.</li>
+ * <li>WP_PROXY_BYPASS_HOSTS - Will prevent the hosts in this list from going through the proxy.
+ * You do not need to have localhost and the blog host in this list, because they will not be passed
+ * through the proxy. The list should be presented in a comma separated list, wildcards using * are supported, eg. *.wordpress.org</li>
+ * </ol>
+ *
+ * An example can be as seen below.
+ * <code>
+ * define('WP_PROXY_HOST', '192.168.84.101');
+ * define('WP_PROXY_PORT', '8080');
+ * define('WP_PROXY_BYPASS_HOSTS', 'localhost, www.example.com, *.wordpress.org');
+ * </code>
+ *
+ * @link http://core.trac.wordpress.org/ticket/4011 Proxy support ticket in WordPress.
+ * @link http://core.trac.wordpress.org/ticket/14636 Allow wildcard domains in WP_PROXY_BYPASS_HOSTS
+ * @since 2.8
+ */
+class WP_HTTP_Proxy {
+
+ /**
+ * Whether proxy connection should be used.
+ *
+ * @since 2.8
+ * @use WP_PROXY_HOST
+ * @use WP_PROXY_PORT
+ *
+ * @return bool
+ */
+ function is_enabled() {
+ return defined('WP_PROXY_HOST') && defined('WP_PROXY_PORT');
+ }
+
+ /**
+ * Whether authentication should be used.
+ *
+ * @since 2.8
+ * @use WP_PROXY_USERNAME
+ * @use WP_PROXY_PASSWORD
+ *
+ * @return bool
+ */
+ function use_authentication() {
+ return defined('WP_PROXY_USERNAME') && defined('WP_PROXY_PASSWORD');
+ }
+
+ /**
+ * Retrieve the host for the proxy server.
+ *
+ * @since 2.8
+ *
+ * @return string
+ */
+ function host() {
+ if ( defined('WP_PROXY_HOST') )
+ return WP_PROXY_HOST;
+
+ return '';
+ }
+
+ /**
+ * Retrieve the port for the proxy server.
+ *
+ * @since 2.8
+ *
+ * @return string
+ */
+ function port() {
+ if ( defined('WP_PROXY_PORT') )
+ return WP_PROXY_PORT;
+
+ return '';
+ }
+
+ /**
+ * Retrieve the username for proxy authentication.
+ *
+ * @since 2.8
+ *
+ * @return string
+ */
+ function username() {
+ if ( defined('WP_PROXY_USERNAME') )
+ return WP_PROXY_USERNAME;
+
+ return '';
+ }
+
+ /**
+ * Retrieve the password for proxy authentication.
+ *
+ * @since 2.8
+ *
+ * @return string
+ */
+ function password() {
+ if ( defined('WP_PROXY_PASSWORD') )
+ return WP_PROXY_PASSWORD;
+
+ return '';
+ }
+
+ /**
+ * Retrieve authentication string for proxy authentication.
+ *
+ * @since 2.8
+ *
+ * @return string
+ */
+ function authentication() {
+ return $this->username() . ':' . $this->password();
+ }
+
+ /**
+ * Retrieve header string for proxy authentication.
+ *
+ * @since 2.8
+ *
+ * @return string
+ */
+ function authentication_header() {
+ return 'Proxy-Authorization: Basic ' . base64_encode( $this->authentication() );
+ }
+
+ /**
+ * Whether URL should be sent through the proxy server.
+ *
+ * We want to keep localhost and the blog URL from being sent through the proxy server, because
+ * some proxies can not handle this. We also have the constant available for defining other
+ * hosts that won't be sent through the proxy.
+ *
+ * @uses WP_PROXY_BYPASS_HOSTS
+ * @since 2.8.0
+ *
+ * @param string $uri URI to check.
+ * @return bool True, to send through the proxy and false if, the proxy should not be used.
+ */
+ function send_through_proxy( $uri ) {
+ // parse_url() only handles http, https type URLs, and will emit E_WARNING on failure.
+ // This will be displayed on blogs, which is not reasonable.
+ $check = @parse_url($uri);
+
+ // Malformed URL, can not process, but this could mean ssl, so let through anyway.
+ if ( $check === false )
+ return true;
+
+ $home = parse_url( get_option('siteurl') );
+
+ $result = apply_filters( 'pre_http_send_through_proxy', null, $uri, $check, $home );
+ if ( ! is_null( $result ) )
+ return $result;
+
+ if ( $check['host'] == 'localhost' || $check['host'] == $home['host'] )
+ return false;
+
+ if ( !defined('WP_PROXY_BYPASS_HOSTS') )
+ return true;
+
+ static $bypass_hosts;
+ static $wildcard_regex = false;
+ if ( null == $bypass_hosts ) {
+ $bypass_hosts = preg_split('|,\s*|', WP_PROXY_BYPASS_HOSTS);
+
+ if ( false !== strpos(WP_PROXY_BYPASS_HOSTS, '*') ) {
+ $wildcard_regex = array();
+ foreach ( $bypass_hosts as $host )
+ $wildcard_regex[] = str_replace('\*', '[\w.]+?', preg_quote($host, '/'));
+ $wildcard_regex = '/^(' . implode('|', $wildcard_regex) . ')$/i';
+ }
+ }
+
+ if ( !empty($wildcard_regex) )
+ return !preg_match($wildcard_regex, $check['host']);
+ else
+ return !in_array( $check['host'], $bypass_hosts );
+ }
+}
+/**
+ * Internal representation of a single cookie.
+ *
+ * Returned cookies are represented using this class, and when cookies are set, if they are not
+ * already a WP_Http_Cookie() object, then they are turned into one.
+ *
+ * @todo The WordPress convention is to use underscores instead of camelCase for function and method
+ * names. Need to switch to use underscores instead for the methods.
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.8.0
+ */
+class WP_Http_Cookie {
+
+ /**
+ * Cookie name.
+ *
+ * @since 2.8.0
+ * @var string
+ */
+ var $name;
+
+ /**
+ * Cookie value.
+ *
+ * @since 2.8.0
+ * @var string
+ */
+ var $value;
+
+ /**
+ * When the cookie expires.
+ *
+ * @since 2.8.0
+ * @var string
+ */
+ var $expires;
+
+ /**
+ * Cookie URL path.
+ *
+ * @since 2.8.0
+ * @var string
+ */
+ var $path;
+
+ /**
+ * Cookie Domain.
+ *
+ * @since 2.8.0
+ * @var string
+ */
+ var $domain;
+
+ /**
+ * Sets up this cookie object.
+ *
+ * The parameter $data should be either an associative array containing the indices names below
+ * or a header string detailing it.
+ *
+ * If it's an array, it should include the following elements:
+ * <ol>
+ * <li>Name</li>
+ * <li>Value - should NOT be urlencoded already.</li>
+ * <li>Expires - (optional) String or int (UNIX timestamp).</li>
+ * <li>Path (optional)</li>
+ * <li>Domain (optional)</li>
+ * </ol>
+ *
+ * @access public
+ * @since 2.8.0
+ *
+ * @param string|array $data Raw cookie data.
+ */
+ function __construct( $data ) {
+ if ( is_string( $data ) ) {
+ // Assume it's a header string direct from a previous request
+ $pairs = explode( ';', $data );
+
+ // Special handling for first pair; name=value. Also be careful of "=" in value
+ $name = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) );
+ $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 );
+ $this->name = $name;
+ $this->value = urldecode( $value );
+ array_shift( $pairs ); //Removes name=value from items.
+
+ // Set everything else as a property
+ foreach ( $pairs as $pair ) {
+ $pair = rtrim($pair);
+ if ( empty($pair) ) //Handles the cookie ending in ; which results in a empty final pair
+ continue;
+
+ list( $key, $val ) = strpos( $pair, '=' ) ? explode( '=', $pair ) : array( $pair, '' );
+ $key = strtolower( trim( $key ) );
+ if ( 'expires' == $key )
+ $val = strtotime( $val );
+ $this->$key = $val;
+ }
+ } else {
+ if ( !isset( $data['name'] ) )
+ return false;
+
+ // Set properties based directly on parameters
+ $this->name = $data['name'];
+ $this->value = isset( $data['value'] ) ? $data['value'] : '';
+ $this->path = isset( $data['path'] ) ? $data['path'] : '';
+ $this->domain = isset( $data['domain'] ) ? $data['domain'] : '';
+
+ if ( isset( $data['expires'] ) )
+ $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] );
+ else
+ $this->expires = null;
+ }
+ }
+
+ /**
+ * Confirms that it's OK to send this cookie to the URL checked against.
+ *
+ * Decision is based on RFC 2109/2965, so look there for details on validity.
+ *
+ * @access public
+ * @since 2.8.0
+ *
+ * @param string $url URL you intend to send this cookie to
+ * @return boolean true if allowed, false otherwise.
+ */
+ function test( $url ) {
+ // Expires - if expired then nothing else matters
+ if ( isset( $this->expires ) && time() > $this->expires )
+ return false;
+
+ // Get details on the URL we're thinking about sending to
+ $url = parse_url( $url );
+ $url['port'] = isset( $url['port'] ) ? $url['port'] : 80;
+ $url['path'] = isset( $url['path'] ) ? $url['path'] : '/';
+
+ // Values to use for comparison against the URL
+ $path = isset( $this->path ) ? $this->path : '/';
+ $port = isset( $this->port ) ? $this->port : 80;
+ $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] );
+ if ( false === stripos( $domain, '.' ) )
+ $domain .= '.local';
+
+ // Host - very basic check that the request URL ends with the domain restriction (minus leading dot)
+ $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain;
+ if ( substr( $url['host'], -strlen( $domain ) ) != $domain )
+ return false;
+
+ // Port - supports "port-lists" in the format: "80,8000,8080"
+ if ( !in_array( $url['port'], explode( ',', $port) ) )
+ return false;
+
+ // Path - request path must start with path restriction
+ if ( substr( $url['path'], 0, strlen( $path ) ) != $path )
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Convert cookie name and value back to header string.
+ *
+ * @access public
+ * @since 2.8.0
+ *
+ * @return string Header encoded cookie name and value.
+ */
+ function getHeaderValue() {
+ if ( ! isset( $this->name ) || ! isset( $this->value ) )
+ return '';
+
+ return $this->name . '=' . apply_filters( 'wp_http_cookie_value', $this->value, $this->name );
+ }
+
+ /**
+ * Retrieve cookie header for usage in the rest of the WordPress HTTP API.
+ *
+ * @access public
+ * @since 2.8.0
+ *
+ * @return string
+ */
+ function getFullHeader() {
+ return 'Cookie: ' . $this->getHeaderValue();
+ }
+}
+
+/**
+ * Implementation for deflate and gzip transfer encodings.
+ *
+ * Includes RFC 1950, RFC 1951, and RFC 1952.
+ *
+ * @since 2.8
+ * @package WordPress
+ * @subpackage HTTP
+ */
+class WP_Http_Encoding {
+
+ /**
+ * Compress raw string using the deflate format.
+ *
+ * Supports the RFC 1951 standard.
+ *
+ * @since 2.8
+ *
+ * @param string $raw String to compress.
+ * @param int $level Optional, default is 9. Compression level, 9 is highest.
+ * @param string $supports Optional, not used. When implemented it will choose the right compression based on what the server supports.
+ * @return string|bool False on failure.
+ */
+ public static function compress( $raw, $level = 9, $supports = null ) {
+ return gzdeflate( $raw, $level );
+ }
+
+ /**
+ * Decompression of deflated string.
+ *
+ * Will attempt to decompress using the RFC 1950 standard, and if that fails
+ * then the RFC 1951 standard deflate will be attempted. Finally, the RFC
+ * 1952 standard gzip decode will be attempted. If all fail, then the
+ * original compressed string will be returned.
+ *
+ * @since 2.8
+ *
+ * @param string $compressed String to decompress.
+ * @param int $length The optional length of the compressed data.
+ * @return string|bool False on failure.
+ */
+ public static function decompress( $compressed, $length = null ) {
+
+ if ( empty($compressed) )
+ return $compressed;
+
+ if ( false !== ( $decompressed = @gzinflate( $compressed ) ) )
+ return $decompressed;
+
+ if ( false !== ( $decompressed = WP_Http_Encoding::compatible_gzinflate( $compressed ) ) )
+ return $decompressed;
+
+ if ( false !== ( $decompressed = @gzuncompress( $compressed ) ) )
+ return $decompressed;
+
+ if ( function_exists('gzdecode') ) {
+ $decompressed = @gzdecode( $compressed );
+
+ if ( false !== $decompressed )
+ return $decompressed;
+ }
+
+ return $compressed;
+ }
+
+ /**
+ * Decompression of deflated string while staying compatible with the majority of servers.
+ *
+ * Certain Servers will return deflated data with headers which PHP's gzinflate()
+ * function cannot handle out of the box. The following function has been created from
+ * various snippets on the gzinflate() PHP documentation.
+ *
+ * Warning: Magic numbers within. Due to the potential different formats that the compressed
+ * data may be returned in, some "magic offsets" are needed to ensure proper decompression
+ * takes place. For a simple progmatic way to determine the magic offset in use, see:
+ * http://core.trac.wordpress.org/ticket/18273
+ *
+ * @since 2.8.1
+ * @link http://core.trac.wordpress.org/ticket/18273
+ * @link http://au2.php.net/manual/en/function.gzinflate.php#70875
+ * @link http://au2.php.net/manual/en/function.gzinflate.php#77336
+ *
+ * @param string $gzData String to decompress.
+ * @return string|bool False on failure.
+ */
+ public static function compatible_gzinflate($gzData) {
+
+ // Compressed data might contain a full header, if so strip it for gzinflate()
+ if ( substr($gzData, 0, 3) == "\x1f\x8b\x08" ) {
+ $i = 10;
+ $flg = ord( substr($gzData, 3, 1) );
+ if ( $flg > 0 ) {
+ if ( $flg & 4 ) {
+ list($xlen) = unpack('v', substr($gzData, $i, 2) );
+ $i = $i + 2 + $xlen;
+ }
+ if ( $flg & 8 )
+ $i = strpos($gzData, "\0", $i) + 1;
+ if ( $flg & 16 )
+ $i = strpos($gzData, "\0", $i) + 1;
+ if ( $flg & 2 )
+ $i = $i + 2;
+ }
+ $decompressed = @gzinflate( substr($gzData, $i, -8) );
+ if ( false !== $decompressed )
+ return $decompressed;
+ }
+
+ // Compressed data from java.util.zip.Deflater amongst others.
+ $decompressed = @gzinflate( substr($gzData, 2) );
+ if ( false !== $decompressed )
+ return $decompressed;
+
+ return false;
+ }
+
+ /**
+ * What encoding types to accept and their priority values.
+ *
+ * @since 2.8
+ *
+ * @return string Types of encoding to accept.
+ */
+ public static function accept_encoding( $url, $args ) {
+ $type = array();
+ $compression_enabled = WP_Http_Encoding::is_available();
+
+ if ( ! $args['decompress'] ) // decompression specifically disabled
+ $compression_enabled = false;
+ elseif ( $args['stream'] ) // disable when streaming to file
+ $compression_enabled = false;
+ elseif ( isset( $args['limit_response_size'] ) ) // If only partial content is being requested, we won't be able to decompress it
+ $compression_enabled = false;
+
+ if ( $compression_enabled ) {
+ if ( function_exists( 'gzinflate' ) )
+ $type[] = 'deflate;q=1.0';
+
+ if ( function_exists( 'gzuncompress' ) )
+ $type[] = 'compress;q=0.5';
+
+ if ( function_exists( 'gzdecode' ) )
+ $type[] = 'gzip;q=0.5';
+ }
+
+ $type = apply_filters( 'wp_http_accept_encoding', $type, $url, $args );
+
+ return implode(', ', $type);
+ }
+
+ /**
+ * What encoding the content used when it was compressed to send in the headers.
+ *
+ * @since 2.8
+ *
+ * @return string Content-Encoding string to send in the header.
+ */
+ public static function content_encoding() {
+ return 'deflate';
+ }
+
+ /**
+ * Whether the content be decoded based on the headers.
+ *
+ * @since 2.8
+ *
+ * @param array|string $headers All of the available headers.
+ * @return bool
+ */
+ public static function should_decode($headers) {
+ if ( is_array( $headers ) ) {
+ if ( array_key_exists('content-encoding', $headers) && ! empty( $headers['content-encoding'] ) )
+ return true;
+ } else if ( is_string( $headers ) ) {
+ return ( stripos($headers, 'content-encoding:') !== false );
+ }
+
+ return false;
+ }
+
+ /**
+ * Whether decompression and compression are supported by the PHP version.
+ *
+ * Each function is tested instead of checking for the zlib extension, to
+ * ensure that the functions all exist in the PHP version and aren't
+ * disabled.
+ *
+ * @since 2.8
+ *
+ * @return bool
+ */
+ public static function is_available() {
+ return ( function_exists('gzuncompress') || function_exists('gzdeflate') || function_exists('gzinflate') );
+ }
+}
diff --git a/src/wp-includes/class-json.php b/src/wp-includes/class-json.php
new file mode 100644
index 0000000000..417592fb88
--- /dev/null
+++ b/src/wp-includes/class-json.php
@@ -0,0 +1,936 @@
+<?php
+if ( ! class_exists( 'Services_JSON' ) ) :
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+/**
+ * Converts to and from JSON format.
+ *
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
+ * format. It is easy for humans to read and write. It is easy for machines
+ * to parse and generate. It is based on a subset of the JavaScript
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+ * This feature can also be found in Python. JSON is a text format that is
+ * completely language independent but uses conventions that are familiar
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
+ * ideal data-interchange language.
+ *
+ * This package provides a simple encoder and decoder for JSON notation. It
+ * is intended for use with client-side Javascript applications that make
+ * use of HTTPRequest to perform server communication functions - data can
+ * be encoded into JSON notation for use in a client-side javascript, or
+ * decoded from incoming Javascript requests. JSON format is native to
+ * Javascript, and can be directly eval()'ed with no further parsing
+ * overhead
+ *
+ * All strings should be in ASCII or UTF-8 format!
+ *
+ * LICENSE: Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met: Redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following
+ * disclaimer. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * @category
+ * @package Services_JSON
+ * @author Michal Migurski <mike-json@teczno.com>
+ * @author Matt Knapp <mdknapp[at]gmail[dot]com>
+ * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+ * @copyright 2005 Michal Migurski
+ * @version CVS: $Id: JSON.php 305040 2010-11-02 23:19:03Z alan_k $
+ * @license http://www.opensource.org/licenses/bsd-license.php
+ * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+ */
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_SLICE', 1);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_STR', 2);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_ARR', 3);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_OBJ', 4);
+
+/**
+ * Marker constant for Services_JSON::decode(), used to flag stack state
+ */
+define('SERVICES_JSON_IN_CMT', 5);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_LOOSE_TYPE', 16);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
+
+/**
+ * Behavior switch for Services_JSON::decode()
+ */
+define('SERVICES_JSON_USE_TO_JSON', 64);
+
+/**
+ * Converts to and from JSON format.
+ *
+ * Brief example of use:
+ *
+ * <code>
+ * // create a new instance of Services_JSON
+ * $json = new Services_JSON();
+ *
+ * // convert a complexe value to JSON notation, and send it to the browser
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
+ * $output = $json->encode($value);
+ *
+ * print($output);
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
+ *
+ * // accept incoming POST data, assumed to be in JSON notation
+ * $input = file_get_contents('php://input', 1000000);
+ * $value = $json->decode($input);
+ * </code>
+ */
+class Services_JSON
+{
+ /**
+ * constructs a new JSON instance
+ *
+ * @param int $use object behavior flags; combine with boolean-OR
+ *
+ * possible values:
+ * - SERVICES_JSON_LOOSE_TYPE: loose typing.
+ * "{...}" syntax creates associative arrays
+ * instead of objects in decode().
+ * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
+ * Values which can't be encoded (e.g. resources)
+ * appear as NULL instead of throwing errors.
+ * By default, a deeply-nested resource will
+ * bubble up with an error, so all return values
+ * from encode() should be checked with isError()
+ * - SERVICES_JSON_USE_TO_JSON: call toJSON when serializing objects
+ * It serializes the return value from the toJSON call rather
+ * than the object it'self, toJSON can return associative arrays,
+ * strings or numbers, if you return an object, make sure it does
+ * not have a toJSON method, otherwise an error will occur.
+ */
+ function Services_JSON($use = 0)
+ {
+ $this->use = $use;
+ $this->_mb_strlen = function_exists('mb_strlen');
+ $this->_mb_convert_encoding = function_exists('mb_convert_encoding');
+ $this->_mb_substr = function_exists('mb_substr');
+ }
+ // private - cache the mbstring lookup results..
+ var $_mb_strlen = false;
+ var $_mb_substr = false;
+ var $_mb_convert_encoding = false;
+
+ /**
+ * convert a string from one UTF-16 char to one UTF-8 char
+ *
+ * Normally should be handled by mb_convert_encoding, but
+ * provides a slower PHP-only method for installations
+ * that lack the multibye string extension.
+ *
+ * @param string $utf16 UTF-16 character
+ * @return string UTF-8 character
+ * @access private
+ */
+ function utf162utf8($utf16)
+ {
+ // oh please oh please oh please oh please oh please
+ if($this->_mb_convert_encoding) {
+ return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
+ }
+
+ $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
+
+ switch(true) {
+ case ((0x7F & $bytes) == $bytes):
+ // this case should never be reached, because we are in ASCII range
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0x7F & $bytes);
+
+ case (0x07FF & $bytes) == $bytes:
+ // return a 2-byte UTF-8 character
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0xC0 | (($bytes >> 6) & 0x1F))
+ . chr(0x80 | ($bytes & 0x3F));
+
+ case (0xFFFF & $bytes) == $bytes:
+ // return a 3-byte UTF-8 character
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0xE0 | (($bytes >> 12) & 0x0F))
+ . chr(0x80 | (($bytes >> 6) & 0x3F))
+ . chr(0x80 | ($bytes & 0x3F));
+ }
+
+ // ignoring UTF-32 for now, sorry
+ return '';
+ }
+
+ /**
+ * convert a string from one UTF-8 char to one UTF-16 char
+ *
+ * Normally should be handled by mb_convert_encoding, but
+ * provides a slower PHP-only method for installations
+ * that lack the multibye string extension.
+ *
+ * @param string $utf8 UTF-8 character
+ * @return string UTF-16 character
+ * @access private
+ */
+ function utf82utf16($utf8)
+ {
+ // oh please oh please oh please oh please oh please
+ if($this->_mb_convert_encoding) {
+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+ }
+
+ switch($this->strlen8($utf8)) {
+ case 1:
+ // this case should never be reached, because we are in ASCII range
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return $utf8;
+
+ case 2:
+ // return a UTF-16 character from a 2-byte UTF-8 char
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr(0x07 & (ord($utf8{0}) >> 2))
+ . chr((0xC0 & (ord($utf8{0}) << 6))
+ | (0x3F & ord($utf8{1})));
+
+ case 3:
+ // return a UTF-16 character from a 3-byte UTF-8 char
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ return chr((0xF0 & (ord($utf8{0}) << 4))
+ | (0x0F & (ord($utf8{1}) >> 2)))
+ . chr((0xC0 & (ord($utf8{1}) << 6))
+ | (0x7F & ord($utf8{2})));
+ }
+
+ // ignoring UTF-32 for now, sorry
+ return '';
+ }
+
+ /**
+ * encodes an arbitrary variable into JSON format (and sends JSON Header)
+ *
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
+ * if var is a strng, note that encode() always expects it
+ * to be in ASCII or UTF-8 format!
+ *
+ * @return mixed JSON string representation of input var or an error if a problem occurs
+ * @access public
+ */
+ function encode($var)
+ {
+ header('Content-type: application/json');
+ return $this->encodeUnsafe($var);
+ }
+ /**
+ * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!)
+ *
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
+ * if var is a strng, note that encode() always expects it
+ * to be in ASCII or UTF-8 format!
+ *
+ * @return mixed JSON string representation of input var or an error if a problem occurs
+ * @access public
+ */
+ function encodeUnsafe($var)
+ {
+ // see bug #16908 - regarding numeric locale printing
+ $lc = setlocale(LC_NUMERIC, 0);
+ setlocale(LC_NUMERIC, 'C');
+ $ret = $this->_encode($var);
+ setlocale(LC_NUMERIC, $lc);
+ return $ret;
+
+ }
+ /**
+ * PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format
+ *
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
+ * if var is a strng, note that encode() always expects it
+ * to be in ASCII or UTF-8 format!
+ *
+ * @return mixed JSON string representation of input var or an error if a problem occurs
+ * @access public
+ */
+ function _encode($var)
+ {
+
+ switch (gettype($var)) {
+ case 'boolean':
+ return $var ? 'true' : 'false';
+
+ case 'NULL':
+ return 'null';
+
+ case 'integer':
+ return (int) $var;
+
+ case 'double':
+ case 'float':
+ return (float) $var;
+
+ case 'string':
+ // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+ $ascii = '';
+ $strlen_var = $this->strlen8($var);
+
+ /*
+ * Iterate over every character in the string,
+ * escaping with a slash or encoding to UTF-8 where necessary
+ */
+ for ($c = 0; $c < $strlen_var; ++$c) {
+
+ $ord_var_c = ord($var{$c});
+
+ switch (true) {
+ case $ord_var_c == 0x08:
+ $ascii .= '\b';
+ break;
+ case $ord_var_c == 0x09:
+ $ascii .= '\t';
+ break;
+ case $ord_var_c == 0x0A:
+ $ascii .= '\n';
+ break;
+ case $ord_var_c == 0x0C:
+ $ascii .= '\f';
+ break;
+ case $ord_var_c == 0x0D:
+ $ascii .= '\r';
+ break;
+
+ case $ord_var_c == 0x22:
+ case $ord_var_c == 0x2F:
+ case $ord_var_c == 0x5C:
+ // double quote, slash, slosh
+ $ascii .= '\\'.$var{$c};
+ break;
+
+ case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+ // characters U-00000000 - U-0000007F (same as ASCII)
+ $ascii .= $var{$c};
+ break;
+
+ case (($ord_var_c & 0xE0) == 0xC0):
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ if ($c+1 >= $strlen_var) {
+ $c += 1;
+ $ascii .= '?';
+ break;
+ }
+
+ $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+ $c += 1;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xF0) == 0xE0):
+ if ($c+2 >= $strlen_var) {
+ $c += 2;
+ $ascii .= '?';
+ break;
+ }
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ @ord($var{$c + 1}),
+ @ord($var{$c + 2}));
+ $c += 2;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xF8) == 0xF0):
+ if ($c+3 >= $strlen_var) {
+ $c += 3;
+ $ascii .= '?';
+ break;
+ }
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}),
+ ord($var{$c + 3}));
+ $c += 3;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xFC) == 0xF8):
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ if ($c+4 >= $strlen_var) {
+ $c += 4;
+ $ascii .= '?';
+ break;
+ }
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}),
+ ord($var{$c + 3}),
+ ord($var{$c + 4}));
+ $c += 4;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+
+ case (($ord_var_c & 0xFE) == 0xFC):
+ if ($c+5 >= $strlen_var) {
+ $c += 5;
+ $ascii .= '?';
+ break;
+ }
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $char = pack('C*', $ord_var_c,
+ ord($var{$c + 1}),
+ ord($var{$c + 2}),
+ ord($var{$c + 3}),
+ ord($var{$c + 4}),
+ ord($var{$c + 5}));
+ $c += 5;
+ $utf16 = $this->utf82utf16($char);
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
+ break;
+ }
+ }
+ return '"'.$ascii.'"';
+
+ case 'array':
+ /*
+ * As per JSON spec if any array key is not an integer
+ * we must treat the the whole array as an object. We
+ * also try to catch a sparsely populated associative
+ * array with numeric keys here because some JS engines
+ * will create an array with empty indexes up to
+ * max_index which can cause memory issues and because
+ * the keys, which may be relevant, will be remapped
+ * otherwise.
+ *
+ * As per the ECMA and JSON specification an object may
+ * have any string as a property. Unfortunately due to
+ * a hole in the ECMA specification if the key is a
+ * ECMA reserved word or starts with a digit the
+ * parameter is only accessible using ECMAScript's
+ * bracket notation.
+ */
+
+ // treat as a JSON object
+ if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+ $properties = array_map(array($this, 'name_value'),
+ array_keys($var),
+ array_values($var));
+
+ foreach($properties as $property) {
+ if(Services_JSON::isError($property)) {
+ return $property;
+ }
+ }
+
+ return '{' . join(',', $properties) . '}';
+ }
+
+ // treat it like a regular array
+ $elements = array_map(array($this, '_encode'), $var);
+
+ foreach($elements as $element) {
+ if(Services_JSON::isError($element)) {
+ return $element;
+ }
+ }
+
+ return '[' . join(',', $elements) . ']';
+
+ case 'object':
+
+ // support toJSON methods.
+ if (($this->use & SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) {
+ // this may end up allowing unlimited recursion
+ // so we check the return value to make sure it's not got the same method.
+ $recode = $var->toJSON();
+
+ if (method_exists($recode, 'toJSON')) {
+
+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
+ ? 'null'
+ : new Services_JSON_Error(get_class($var).
+ " toJSON returned an object with a toJSON method.");
+
+ }
+
+ return $this->_encode( $recode );
+ }
+
+ $vars = get_object_vars($var);
+
+ $properties = array_map(array($this, 'name_value'),
+ array_keys($vars),
+ array_values($vars));
+
+ foreach($properties as $property) {
+ if(Services_JSON::isError($property)) {
+ return $property;
+ }
+ }
+
+ return '{' . join(',', $properties) . '}';
+
+ default:
+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
+ ? 'null'
+ : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
+ }
+ }
+
+ /**
+ * array-walking function for use in generating JSON-formatted name-value pairs
+ *
+ * @param string $name name of key to use
+ * @param mixed $value reference to an array element to be encoded
+ *
+ * @return string JSON-formatted name-value pair, like '"name":value'
+ * @access private
+ */
+ function name_value($name, $value)
+ {
+ $encoded_value = $this->_encode($value);
+
+ if(Services_JSON::isError($encoded_value)) {
+ return $encoded_value;
+ }
+
+ return $this->_encode(strval($name)) . ':' . $encoded_value;
+ }
+
+ /**
+ * reduce a string by removing leading and trailing comments and whitespace
+ *
+ * @param $str string string value to strip of comments and whitespace
+ *
+ * @return string string value stripped of comments and whitespace
+ * @access private
+ */
+ function reduce_string($str)
+ {
+ $str = preg_replace(array(
+
+ // eliminate single line comments in '// ...' form
+ '#^\s*//(.+)$#m',
+
+ // eliminate multi-line comments in '/* ... */' form, at start of string
+ '#^\s*/\*(.+)\*/#Us',
+
+ // eliminate multi-line comments in '/* ... */' form, at end of string
+ '#/\*(.+)\*/\s*$#Us'
+
+ ), '', $str);
+
+ // eliminate extraneous space
+ return trim($str);
+ }
+
+ /**
+ * decodes a JSON string into appropriate variable
+ *
+ * @param string $str JSON-formatted string
+ *
+ * @return mixed number, boolean, string, array, or object
+ * corresponding to given JSON input string.
+ * See argument 1 to Services_JSON() above for object-output behavior.
+ * Note that decode() always returns strings
+ * in ASCII or UTF-8 format!
+ * @access public
+ */
+ function decode($str)
+ {
+ $str = $this->reduce_string($str);
+
+ switch (strtolower($str)) {
+ case 'true':
+ return true;
+
+ case 'false':
+ return false;
+
+ case 'null':
+ return null;
+
+ default:
+ $m = array();
+
+ if (is_numeric($str)) {
+ // Lookie-loo, it's a number
+
+ // This would work on its own, but I'm trying to be
+ // good about returning integers where appropriate:
+ // return (float)$str;
+
+ // Return float or int, as appropriate
+ return ((float)$str == (integer)$str)
+ ? (integer)$str
+ : (float)$str;
+
+ } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
+ // STRINGS RETURNED IN UTF-8 FORMAT
+ $delim = $this->substr8($str, 0, 1);
+ $chrs = $this->substr8($str, 1, -1);
+ $utf8 = '';
+ $strlen_chrs = $this->strlen8($chrs);
+
+ for ($c = 0; $c < $strlen_chrs; ++$c) {
+
+ $substr_chrs_c_2 = $this->substr8($chrs, $c, 2);
+ $ord_chrs_c = ord($chrs{$c});
+
+ switch (true) {
+ case $substr_chrs_c_2 == '\b':
+ $utf8 .= chr(0x08);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\t':
+ $utf8 .= chr(0x09);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\n':
+ $utf8 .= chr(0x0A);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\f':
+ $utf8 .= chr(0x0C);
+ ++$c;
+ break;
+ case $substr_chrs_c_2 == '\r':
+ $utf8 .= chr(0x0D);
+ ++$c;
+ break;
+
+ case $substr_chrs_c_2 == '\\"':
+ case $substr_chrs_c_2 == '\\\'':
+ case $substr_chrs_c_2 == '\\\\':
+ case $substr_chrs_c_2 == '\\/':
+ if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
+ ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
+ $utf8 .= $chrs{++$c};
+ }
+ break;
+
+ case preg_match('/\\\u[0-9A-F]{4}/i', $this->substr8($chrs, $c, 6)):
+ // single, escaped unicode character
+ $utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2)))
+ . chr(hexdec($this->substr8($chrs, ($c + 4), 2)));
+ $utf8 .= $this->utf162utf8($utf16);
+ $c += 5;
+ break;
+
+ case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
+ $utf8 .= $chrs{$c};
+ break;
+
+ case ($ord_chrs_c & 0xE0) == 0xC0:
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
+ //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= $this->substr8($chrs, $c, 2);
+ ++$c;
+ break;
+
+ case ($ord_chrs_c & 0xF0) == 0xE0:
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= $this->substr8($chrs, $c, 3);
+ $c += 2;
+ break;
+
+ case ($ord_chrs_c & 0xF8) == 0xF0:
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= $this->substr8($chrs, $c, 4);
+ $c += 3;
+ break;
+
+ case ($ord_chrs_c & 0xFC) == 0xF8:
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= $this->substr8($chrs, $c, 5);
+ $c += 4;
+ break;
+
+ case ($ord_chrs_c & 0xFE) == 0xFC:
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ $utf8 .= $this->substr8($chrs, $c, 6);
+ $c += 5;
+ break;
+
+ }
+
+ }
+
+ return $utf8;
+
+ } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
+ // array, or object notation
+
+ if ($str{0} == '[') {
+ $stk = array(SERVICES_JSON_IN_ARR);
+ $arr = array();
+ } else {
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+ $stk = array(SERVICES_JSON_IN_OBJ);
+ $obj = array();
+ } else {
+ $stk = array(SERVICES_JSON_IN_OBJ);
+ $obj = new stdClass();
+ }
+ }
+
+ array_push($stk, array('what' => SERVICES_JSON_SLICE,
+ 'where' => 0,
+ 'delim' => false));
+
+ $chrs = $this->substr8($str, 1, -1);
+ $chrs = $this->reduce_string($chrs);
+
+ if ($chrs == '') {
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
+ return $arr;
+
+ } else {
+ return $obj;
+
+ }
+ }
+
+ //print("\nparsing {$chrs}\n");
+
+ $strlen_chrs = $this->strlen8($chrs);
+
+ for ($c = 0; $c <= $strlen_chrs; ++$c) {
+
+ $top = end($stk);
+ $substr_chrs_c_2 = $this->substr8($chrs, $c, 2);
+
+ if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
+ // found a comma that is not inside a string, array, etc.,
+ // OR we've reached the end of the character list
+ $slice = $this->substr8($chrs, $top['where'], ($c - $top['where']));
+ array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
+ //print("Found split at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
+ // we are in an array, so just push an element onto the stack
+ array_push($arr, $this->decode($slice));
+
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+ // we are in an object, so figure
+ // out the property name and set an
+ // element in an associative array,
+ // for now
+ $parts = array();
+
+ if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:/Uis', $slice, $parts)) {
+ // "name":value pair
+ $key = $this->decode($parts[1]);
+ $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B"));
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+ $obj[$key] = $val;
+ } else {
+ $obj->$key = $val;
+ }
+ } elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) {
+ // name:value pair, where name is unquoted
+ $key = $parts[1];
+ $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B"));
+
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
+ $obj[$key] = $val;
+ } else {
+ $obj->$key = $val;
+ }
+ }
+
+ }
+
+ } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
+ // found a quote, and we are not inside a string
+ array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
+ //print("Found start of string at {$c}\n");
+
+ } elseif (($chrs{$c} == $top['delim']) &&
+ ($top['what'] == SERVICES_JSON_IN_STR) &&
+ (($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($chrs, 0, $c), '\\'))) % 2 != 1)) {
+ // found a quote, we're in a string, and it's not escaped
+ // we know that it's not escaped becase there is _not_ an
+ // odd number of backslashes at the end of the string so far
+ array_pop($stk);
+ //print("Found end of string at {$c}: ".$this->substr8($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
+
+ } elseif (($chrs{$c} == '[') &&
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+ // found a left-bracket, and we are in an array, object, or slice
+ array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
+ //print("Found start of array at {$c}\n");
+
+ } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
+ // found a right-bracket, and we're in an array
+ array_pop($stk);
+ //print("Found end of array at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ } elseif (($chrs{$c} == '{') &&
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+ // found a left-brace, and we are in an array, object, or slice
+ array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
+ //print("Found start of object at {$c}\n");
+
+ } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
+ // found a right-brace, and we're in an object
+ array_pop($stk);
+ //print("Found end of object at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ } elseif (($substr_chrs_c_2 == '/*') &&
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
+ // found a comment start, and we are in an array, object, or slice
+ array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
+ $c++;
+ //print("Found start of comment at {$c}\n");
+
+ } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
+ // found a comment end, and we're in one now
+ array_pop($stk);
+ $c++;
+
+ for ($i = $top['where']; $i <= $c; ++$i)
+ $chrs = substr_replace($chrs, ' ', $i, 1);
+
+ //print("Found end of comment at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
+
+ }
+
+ }
+
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
+ return $arr;
+
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
+ return $obj;
+
+ }
+
+ }
+ }
+ }
+
+ /**
+ * @todo Ultimately, this should just call PEAR::isError()
+ */
+ function isError($data, $code = null)
+ {
+ if (class_exists('pear')) {
+ return PEAR::isError($data, $code);
+ } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
+ is_subclass_of($data, 'services_json_error'))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculates length of string in bytes
+ * @param string
+ * @return integer length
+ */
+ function strlen8( $str )
+ {
+ if ( $this->_mb_strlen ) {
+ return mb_strlen( $str, "8bit" );
+ }
+ return strlen( $str );
+ }
+
+ /**
+ * Returns part of a string, interpreting $start and $length as number of bytes.
+ * @param string
+ * @param integer start
+ * @param integer length
+ * @return integer length
+ */
+ function substr8( $string, $start, $length=false )
+ {
+ if ( $length === false ) {
+ $length = $this->strlen8( $string ) - $start;
+ }
+ if ( $this->_mb_substr ) {
+ return mb_substr( $string, $start, $length, "8bit" );
+ }
+ return substr( $string, $start, $length );
+ }
+
+}
+
+if (class_exists('PEAR_Error')) {
+
+ class Services_JSON_Error extends PEAR_Error
+ {
+ function Services_JSON_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+ parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
+ }
+ }
+
+} else {
+
+ /**
+ * @todo Ultimately, this class shall be descended from PEAR_Error
+ */
+ class Services_JSON_Error
+ {
+ function Services_JSON_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+
+ }
+ }
+
+}
+
+endif;
diff --git a/src/wp-includes/class-oembed.php b/src/wp-includes/class-oembed.php
new file mode 100644
index 0000000000..a880448db3
--- /dev/null
+++ b/src/wp-includes/class-oembed.php
@@ -0,0 +1,351 @@
+<?php
+/**
+ * API for fetching the HTML to embed remote content based on a provided URL.
+ * Used internally by the {@link WP_Embed} class, but is designed to be generic.
+ *
+ * @link http://codex.wordpress.org/oEmbed oEmbed Codex Article
+ * @link http://oembed.com/ oEmbed Homepage
+ *
+ * @package WordPress
+ * @subpackage oEmbed
+ */
+
+/**
+ * oEmbed class.
+ *
+ * @package WordPress
+ * @subpackage oEmbed
+ * @since 2.9.0
+ */
+class WP_oEmbed {
+ var $providers = array();
+
+ /**
+ * Constructor
+ *
+ * @uses apply_filters() Filters a list of pre-defined oEmbed providers.
+ */
+ function __construct() {
+ // List out some popular sites that support oEmbed.
+ // The WP_Embed class disables discovery for non-unfiltered_html users, so only providers in this array will be used for them.
+ // Add to this list using the wp_oembed_add_provider() function (see its PHPDoc for details).
+ $this->providers = apply_filters( 'oembed_providers', array(
+ '#https?://(www\.)?youtube\.com/watch.*#i' => array( 'http://www.youtube.com/oembed', true ),
+ 'http://youtu.be/*' => array( 'http://www.youtube.com/oembed', false ),
+ 'http://blip.tv/*' => array( 'http://blip.tv/oembed/', false ),
+ '#https?://(www\.)?vimeo\.com/.*#i' => array( 'http://vimeo.com/api/oembed.{format}', true ),
+ '#https?://(www\.)?dailymotion\.com/.*#i' => array( 'http://www.dailymotion.com/services/oembed', true ),
+ 'http://dai.ly/*' => array( 'http://www.dailymotion.com/services/oembed', false ),
+ '#https?://(www\.)?flickr\.com/.*#i' => array( 'http://www.flickr.com/services/oembed/', true ),
+ 'http://flic.kr/*' => array( 'http://www.flickr.com/services/oembed/', false ),
+ '#https?://(.+\.)?smugmug\.com/.*#i' => array( 'http://api.smugmug.com/services/oembed/', true ),
+ '#https?://(www\.)?hulu\.com/watch/.*#i' => array( 'http://www.hulu.com/api/oembed.{format}', true ),
+ '#https?://(www\.)?viddler\.com/.*#i' => array( 'http://lab.viddler.com/services/oembed/', true ),
+ 'http://qik.com/*' => array( 'http://qik.com/api/oembed.{format}', false ),
+ 'http://revision3.com/*' => array( 'http://revision3.com/api/oembed/', false ),
+ 'http://i*.photobucket.com/albums/*' => array( 'http://photobucket.com/oembed', false ),
+ 'http://gi*.photobucket.com/groups/*' => array( 'http://photobucket.com/oembed', false ),
+ '#https?://(www\.)?scribd\.com/.*#i' => array( 'http://www.scribd.com/services/oembed', true ),
+ 'http://wordpress.tv/*' => array( 'http://wordpress.tv/oembed/', false ),
+ '#https?://(.+\.)?polldaddy\.com/.*#i' => array( 'http://polldaddy.com/oembed/', true ),
+ '#https?://(www\.)?funnyordie\.com/videos/.*#i' => array( 'http://www.funnyordie.com/oembed', true ),
+ '#https?://(www\.)?twitter\.com/.+?/status(es)?/.*#i'=> array( 'http://api.twitter.com/1/statuses/oembed.{format}', true ),
+ '#https?://(www\.)?soundcloud\.com/.*#i' => array( 'http://soundcloud.com/oembed', true ),
+ '#https?://(www\.)?slideshare\.net/*#' => array( 'http://www.slideshare.net/api/oembed/2', true ),
+ '#http://instagr(\.am|am\.com)/p/.*#i' => array( 'http://api.instagram.com/oembed', true ),
+ '#https?://(www\.)?rdio\.com/.*#i' => array( 'http://www.rdio.com/api/oembed/', true ),
+ '#https?://rd\.io/x/.*#i' => array( 'http://www.rdio.com/api/oembed/', true ),
+ '#https?://(open|play)\.spotify\.com/.*#i' => array( 'https://embed.spotify.com/oembed/', true ),
+ ) );
+
+ // Fix any embeds that contain new lines in the middle of the HTML which breaks wpautop().
+ add_filter( 'oembed_dataparse', array($this, '_strip_newlines'), 10, 3 );
+ }
+
+ /**
+ * The do-it-all function that takes a URL and attempts to return the HTML.
+ *
+ * @see WP_oEmbed::discover()
+ * @see WP_oEmbed::fetch()
+ * @see WP_oEmbed::data2html()
+ *
+ * @param string $url The URL to the content that should be attempted to be embedded.
+ * @param array $args Optional arguments. Usually passed from a shortcode.
+ * @return bool|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed.
+ */
+ function get_html( $url, $args = '' ) {
+ $provider = false;
+
+ if ( !isset($args['discover']) )
+ $args['discover'] = true;
+
+ foreach ( $this->providers as $matchmask => $data ) {
+ list( $providerurl, $regex ) = $data;
+
+ // Turn the asterisk-type provider URLs into regex
+ if ( !$regex ) {
+ $matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i';
+ $matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask );
+ }
+
+ if ( preg_match( $matchmask, $url ) ) {
+ $provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML
+ break;
+ }
+ }
+
+ if ( !$provider && $args['discover'] )
+ $provider = $this->discover( $url );
+
+ if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) )
+ return false;
+
+ return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args );
+ }
+
+ /**
+ * Attempts to find oEmbed provider discovery <link> tags at the given URL.
+ *
+ * @param string $url The URL that should be inspected for discovery <link> tags.
+ * @return bool|string False on failure, otherwise the oEmbed provider URL.
+ */
+ function discover( $url ) {
+ $providers = array();
+
+ // Fetch URL content
+ if ( $html = wp_remote_retrieve_body( wp_safe_remote_get( $url ) ) ) {
+
+ // <link> types that contain oEmbed provider URLs
+ $linktypes = apply_filters( 'oembed_linktypes', array(
+ 'application/json+oembed' => 'json',
+ 'text/xml+oembed' => 'xml',
+ 'application/xml+oembed' => 'xml', // Incorrect, but used by at least Vimeo
+ ) );
+
+ // Strip <body>
+ $html = substr( $html, 0, stripos( $html, '</head>' ) );
+
+ // Do a quick check
+ $tagfound = false;
+ foreach ( $linktypes as $linktype => $format ) {
+ if ( stripos($html, $linktype) ) {
+ $tagfound = true;
+ break;
+ }
+ }
+
+ if ( $tagfound && preg_match_all( '/<link([^<>]+)>/i', $html, $links ) ) {
+ foreach ( $links[1] as $link ) {
+ $atts = shortcode_parse_atts( $link );
+
+ if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) {
+ $providers[$linktypes[$atts['type']]] = $atts['href'];
+
+ // Stop here if it's JSON (that's all we need)
+ if ( 'json' == $linktypes[$atts['type']] )
+ break;
+ }
+ }
+ }
+ }
+
+ // JSON is preferred to XML
+ if ( !empty($providers['json']) )
+ return $providers['json'];
+ elseif ( !empty($providers['xml']) )
+ return $providers['xml'];
+ else
+ return false;
+ }
+
+ /**
+ * Connects to a oEmbed provider and returns the result.
+ *
+ * @param string $provider The URL to the oEmbed provider.
+ * @param string $url The URL to the content that is desired to be embedded.
+ * @param array $args Optional arguments. Usually passed from a shortcode.
+ * @return bool|object False on failure, otherwise the result in the form of an object.
+ */
+ function fetch( $provider, $url, $args = '' ) {
+ $args = wp_parse_args( $args, wp_embed_defaults() );
+
+ $provider = add_query_arg( 'maxwidth', (int) $args['width'], $provider );
+ $provider = add_query_arg( 'maxheight', (int) $args['height'], $provider );
+ $provider = add_query_arg( 'url', urlencode($url), $provider );
+
+ $provider = apply_filters( 'oembed_fetch_url', $provider, $url, $args );
+
+ foreach( array( 'json', 'xml' ) as $format ) {
+ $result = $this->_fetch_with_format( $provider, $format );
+ if ( is_wp_error( $result ) && 'not-implemented' == $result->get_error_code() )
+ continue;
+ return ( $result && ! is_wp_error( $result ) ) ? $result : false;
+ }
+ return false;
+ }
+
+ /**
+ * Fetches result from an oEmbed provider for a specific format and complete provider URL
+ *
+ * @since 3.0.0
+ * @access private
+ * @param string $provider_url_with_args URL to the provider with full arguments list (url, maxheight, etc.)
+ * @param string $format Format to use
+ * @return bool|object False on failure, otherwise the result in the form of an object.
+ */
+ function _fetch_with_format( $provider_url_with_args, $format ) {
+ $provider_url_with_args = add_query_arg( 'format', $format, $provider_url_with_args );
+ $response = wp_safe_remote_get( $provider_url_with_args );
+ if ( 501 == wp_remote_retrieve_response_code( $response ) )
+ return new WP_Error( 'not-implemented' );
+ if ( ! $body = wp_remote_retrieve_body( $response ) )
+ return false;
+ $parse_method = "_parse_$format";
+ return $this->$parse_method( $body );
+ }
+
+ /**
+ * Parses a json response body.
+ *
+ * @since 3.0.0
+ * @access private
+ */
+ function _parse_json( $response_body ) {
+ return ( ( $data = json_decode( trim( $response_body ) ) ) && is_object( $data ) ) ? $data : false;
+ }
+
+ /**
+ * Parses an XML response body.
+ *
+ * @since 3.0.0
+ * @access private
+ */
+ function _parse_xml( $response_body ) {
+ if ( ! function_exists( 'libxml_disable_entity_loader' ) )
+ return false;
+
+ $loader = libxml_disable_entity_loader( true );
+ $errors = libxml_use_internal_errors( true );
+
+ $return = $this->_parse_xml_body( $response_body );
+
+ libxml_use_internal_errors( $errors );
+ libxml_disable_entity_loader( $loader );
+
+ return $return;
+ }
+
+ /**
+ * Helper function for parsing an XML response body.
+ *
+ * @since 3.6.0
+ * @access private
+ */
+ private function _parse_xml_body( $response_body ) {
+ if ( ! function_exists( 'simplexml_import_dom' ) || ! class_exists( 'DOMDocument' ) )
+ return false;
+
+ $dom = new DOMDocument;
+ $success = $dom->loadXML( $response_body );
+ if ( ! $success )
+ return false;
+
+ if ( isset( $dom->doctype ) )
+ return false;
+
+ foreach ( $dom->childNodes as $child ) {
+ if ( XML_DOCUMENT_TYPE_NODE === $child->nodeType )
+ return false;
+ }
+
+ $xml = simplexml_import_dom( $dom );
+ if ( ! $xml )
+ return false;
+
+ $return = new stdClass;
+ foreach ( $xml as $key => $value ) {
+ $return->$key = (string) $value;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Converts a data object from {@link WP_oEmbed::fetch()} and returns the HTML.
+ *
+ * @param object $data A data object result from an oEmbed provider.
+ * @param string $url The URL to the content that is desired to be embedded.
+ * @return bool|string False on error, otherwise the HTML needed to embed.
+ */
+ function data2html( $data, $url ) {
+ if ( ! is_object( $data ) || empty( $data->type ) )
+ return false;
+
+ $return = false;
+
+ switch ( $data->type ) {
+ case 'photo':
+ if ( empty( $data->url ) || empty( $data->width ) || empty( $data->height ) )
+ break;
+ if ( ! is_string( $data->url ) || ! is_numeric( $data->width ) || ! is_numeric( $data->height ) )
+ break;
+
+ $title = ! empty( $data->title ) && is_string( $data->title ) ? $data->title : '';
+ $return = '<a href="' . esc_url( $url ) . '"><img src="' . esc_url( $data->url ) . '" alt="' . esc_attr($title) . '" width="' . esc_attr($data->width) . '" height="' . esc_attr($data->height) . '" /></a>';
+ break;
+
+ case 'video':
+ case 'rich':
+ if ( ! empty( $data->html ) && is_string( $data->html ) )
+ $return = $data->html;
+ break;
+
+ case 'link':
+ if ( ! empty( $data->title ) && is_string( $data->title ) )
+ $return = '<a href="' . esc_url( $url ) . '">' . esc_html( $data->title ) . '</a>';
+ break;
+
+ default:
+ $return = false;
+ }
+
+ // You can use this filter to add support for custom data types or to filter the result
+ return apply_filters( 'oembed_dataparse', $return, $data, $url );
+ }
+
+ /**
+ * Strip any new lines from the HTML.
+ *
+ * @access private
+ * @param string $html Existing HTML.
+ * @param object $data Data object from WP_oEmbed::data2html()
+ * @param string $url The original URL passed to oEmbed.
+ * @return string Possibly modified $html
+ */
+ function _strip_newlines( $html, $data, $url ) {
+ if ( false !== strpos( $html, "\n" ) )
+ $html = str_replace( array( "\r\n", "\n" ), '', $html );
+
+ return $html;
+ }
+}
+
+/**
+ * Returns the initialized {@link WP_oEmbed} object
+ *
+ * @since 2.9.0
+ * @access private
+ *
+ * @see WP_oEmbed
+ * @uses WP_oEmbed
+ *
+ * @return WP_oEmbed object.
+ */
+function _wp_oembed_get_object() {
+ static $wp_oembed;
+
+ if ( is_null($wp_oembed) )
+ $wp_oembed = new WP_oEmbed();
+
+ return $wp_oembed;
+}
diff --git a/src/wp-includes/class-phpass.php b/src/wp-includes/class-phpass.php
new file mode 100644
index 0000000000..2fed5d7685
--- /dev/null
+++ b/src/wp-includes/class-phpass.php
@@ -0,0 +1,260 @@
+<?php
+/**
+ * Portable PHP password hashing framework.
+ * @package phpass
+ * @since 2.5
+ * @version 0.3 / WordPress
+ * @link http://www.openwall.com/phpass/
+ */
+
+#
+# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
+# the public domain. Revised in subsequent years, still public domain.
+#
+# There's absolutely no warranty.
+#
+# Please be sure to update the Version line if you edit this file in any way.
+# It is suggested that you leave the main version number intact, but indicate
+# your project name (after the slash) and add your own revision information.
+#
+# Please do not change the "private" password hashing method implemented in
+# here, thereby making your hashes incompatible. However, if you must, please
+# change the hash type identifier (the "$P$") to something different.
+#
+# Obviously, since this code is in the public domain, the above are not
+# requirements (there can be none), but merely suggestions.
+#
+
+/**
+ * Portable PHP password hashing framework.
+ *
+ * @package phpass
+ * @version 0.3 / WordPress
+ * @link http://www.openwall.com/phpass/
+ * @since 2.5
+ */
+class PasswordHash {
+ var $itoa64;
+ var $iteration_count_log2;
+ var $portable_hashes;
+ var $random_state;
+
+ function PasswordHash($iteration_count_log2, $portable_hashes)
+ {
+ $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+
+ if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
+ $iteration_count_log2 = 8;
+ $this->iteration_count_log2 = $iteration_count_log2;
+
+ $this->portable_hashes = $portable_hashes;
+
+ $this->random_state = microtime() . uniqid(rand(), TRUE); // removed getmypid() for compatibility reasons
+ }
+
+ function get_random_bytes($count)
+ {
+ $output = '';
+ if ( @is_readable('/dev/urandom') &&
+ ($fh = @fopen('/dev/urandom', 'rb'))) {
+ $output = fread($fh, $count);
+ fclose($fh);
+ }
+
+ if (strlen($output) < $count) {
+ $output = '';
+ for ($i = 0; $i < $count; $i += 16) {
+ $this->random_state =
+ md5(microtime() . $this->random_state);
+ $output .=
+ pack('H*', md5($this->random_state));
+ }
+ $output = substr($output, 0, $count);
+ }
+
+ return $output;
+ }
+
+ function encode64($input, $count)
+ {
+ $output = '';
+ $i = 0;
+ do {
+ $value = ord($input[$i++]);
+ $output .= $this->itoa64[$value & 0x3f];
+ if ($i < $count)
+ $value |= ord($input[$i]) << 8;
+ $output .= $this->itoa64[($value >> 6) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ if ($i < $count)
+ $value |= ord($input[$i]) << 16;
+ $output .= $this->itoa64[($value >> 12) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ $output .= $this->itoa64[($value >> 18) & 0x3f];
+ } while ($i < $count);
+
+ return $output;
+ }
+
+ function gensalt_private($input)
+ {
+ $output = '$P$';
+ $output .= $this->itoa64[min($this->iteration_count_log2 +
+ ((PHP_VERSION >= '5') ? 5 : 3), 30)];
+ $output .= $this->encode64($input, 6);
+
+ return $output;
+ }
+
+ function crypt_private($password, $setting)
+ {
+ $output = '*0';
+ if (substr($setting, 0, 2) == $output)
+ $output = '*1';
+
+ $id = substr($setting, 0, 3);
+ # We use "$P$", phpBB3 uses "$H$" for the same thing
+ if ($id != '$P$' && $id != '$H$')
+ return $output;
+
+ $count_log2 = strpos($this->itoa64, $setting[3]);
+ if ($count_log2 < 7 || $count_log2 > 30)
+ return $output;
+
+ $count = 1 << $count_log2;
+
+ $salt = substr($setting, 4, 8);
+ if (strlen($salt) != 8)
+ return $output;
+
+ # We're kind of forced to use MD5 here since it's the only
+ # cryptographic primitive available in all versions of PHP
+ # currently in use. To implement our own low-level crypto
+ # in PHP would result in much worse performance and
+ # consequently in lower iteration counts and hashes that are
+ # quicker to crack (by non-PHP code).
+ if (PHP_VERSION >= '5') {
+ $hash = md5($salt . $password, TRUE);
+ do {
+ $hash = md5($hash . $password, TRUE);
+ } while (--$count);
+ } else {
+ $hash = pack('H*', md5($salt . $password));
+ do {
+ $hash = pack('H*', md5($hash . $password));
+ } while (--$count);
+ }
+
+ $output = substr($setting, 0, 12);
+ $output .= $this->encode64($hash, 16);
+
+ return $output;
+ }
+
+ function gensalt_extended($input)
+ {
+ $count_log2 = min($this->iteration_count_log2 + 8, 24);
+ # This should be odd to not reveal weak DES keys, and the
+ # maximum valid value is (2**24 - 1) which is odd anyway.
+ $count = (1 << $count_log2) - 1;
+
+ $output = '_';
+ $output .= $this->itoa64[$count & 0x3f];
+ $output .= $this->itoa64[($count >> 6) & 0x3f];
+ $output .= $this->itoa64[($count >> 12) & 0x3f];
+ $output .= $this->itoa64[($count >> 18) & 0x3f];
+
+ $output .= $this->encode64($input, 3);
+
+ return $output;
+ }
+
+ function gensalt_blowfish($input)
+ {
+ # This one needs to use a different order of characters and a
+ # different encoding scheme from the one in encode64() above.
+ # We care because the last character in our encoded string will
+ # only represent 2 bits. While two known implementations of
+ # bcrypt will happily accept and correct a salt string which
+ # has the 4 unused bits set to non-zero, we do not want to take
+ # chances and we also do not want to waste an additional byte
+ # of entropy.
+ $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $output = '$2a$';
+ $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
+ $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
+ $output .= '$';
+
+ $i = 0;
+ do {
+ $c1 = ord($input[$i++]);
+ $output .= $itoa64[$c1 >> 2];
+ $c1 = ($c1 & 0x03) << 4;
+ if ($i >= 16) {
+ $output .= $itoa64[$c1];
+ break;
+ }
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 4;
+ $output .= $itoa64[$c1];
+ $c1 = ($c2 & 0x0f) << 2;
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 6;
+ $output .= $itoa64[$c1];
+ $output .= $itoa64[$c2 & 0x3f];
+ } while (1);
+
+ return $output;
+ }
+
+ function HashPassword($password)
+ {
+ $random = '';
+
+ if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
+ $random = $this->get_random_bytes(16);
+ $hash =
+ crypt($password, $this->gensalt_blowfish($random));
+ if (strlen($hash) == 60)
+ return $hash;
+ }
+
+ if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
+ if (strlen($random) < 3)
+ $random = $this->get_random_bytes(3);
+ $hash =
+ crypt($password, $this->gensalt_extended($random));
+ if (strlen($hash) == 20)
+ return $hash;
+ }
+
+ if (strlen($random) < 6)
+ $random = $this->get_random_bytes(6);
+ $hash =
+ $this->crypt_private($password,
+ $this->gensalt_private($random));
+ if (strlen($hash) == 34)
+ return $hash;
+
+ # Returning '*' on error is safe here, but would _not_ be safe
+ # in a crypt(3)-like function used _both_ for generating new
+ # hashes and for validating passwords against existing hashes.
+ return '*';
+ }
+
+ function CheckPassword($password, $stored_hash)
+ {
+ $hash = $this->crypt_private($password, $stored_hash);
+ if ($hash[0] == '*')
+ $hash = crypt($password, $stored_hash);
+
+ return $hash === $stored_hash;
+ }
+}
+
+?>
diff --git a/src/wp-includes/class-phpmailer.php b/src/wp-includes/class-phpmailer.php
new file mode 100644
index 0000000000..38ac37626a
--- /dev/null
+++ b/src/wp-includes/class-phpmailer.php
@@ -0,0 +1,2826 @@
+<?php
+/*~ class.phpmailer.php
+.---------------------------------------------------------------------------.
+| Software: PHPMailer - PHP email class |
+| Version: 5.2.4 |
+| Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
+| ------------------------------------------------------------------------- |
+| Admin: Jim Jagielski (project admininistrator) |
+| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
+| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
+| : Jim Jagielski (jimjag) jimjag@gmail.com |
+| Founder: Brent R. Matzelle (original founder) |
+| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
+| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
+| Copyright (c) 2001-2003, Brent R. Matzelle |
+| ------------------------------------------------------------------------- |
+| License: Distributed under the Lesser General Public License (LGPL) |
+| http://www.gnu.org/copyleft/lesser.html |
+| This program is distributed in the hope that it will be useful - WITHOUT |
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
+| FITNESS FOR A PARTICULAR PURPOSE. |
+'---------------------------------------------------------------------------'
+*/
+
+/**
+ * PHPMailer - PHP email creation and transport class
+ * NOTE: Requires PHP version 5 or later
+ * @package PHPMailer
+ * @author Andy Prevost
+ * @author Marcus Bointon
+ * @author Jim Jagielski
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
+ */
+
+if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
+
+/**
+ * PHP email creation and transport class
+ * @package PHPMailer
+ */
+class PHPMailer {
+
+ /////////////////////////////////////////////////
+ // PROPERTIES, PUBLIC
+ /////////////////////////////////////////////////
+
+ /**
+ * Email priority (1 = High, 3 = Normal, 5 = low).
+ * @var int
+ */
+ public $Priority = 3;
+
+ /**
+ * Sets the CharSet of the message.
+ * @var string
+ */
+ public $CharSet = 'iso-8859-1';
+
+ /**
+ * Sets the Content-type of the message.
+ * @var string
+ */
+ public $ContentType = 'text/plain';
+
+ /**
+ * Sets the Encoding of the message. Options for this are
+ * "8bit", "7bit", "binary", "base64", and "quoted-printable".
+ * @var string
+ */
+ public $Encoding = '8bit';
+
+ /**
+ * Holds the most recent mailer error message.
+ * @var string
+ */
+ public $ErrorInfo = '';
+
+ /**
+ * Sets the From email address for the message.
+ * @var string
+ */
+ public $From = 'root@localhost';
+
+ /**
+ * Sets the From name of the message.
+ * @var string
+ */
+ public $FromName = 'Root User';
+
+ /**
+ * Sets the Sender email (Return-Path) of the message. If not empty,
+ * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
+ * @var string
+ */
+ public $Sender = '';
+
+ /**
+ * Sets the Return-Path of the message. If empty, it will
+ * be set to either From or Sender.
+ * @var string
+ */
+ public $ReturnPath = '';
+
+ /**
+ * Sets the Subject of the message.
+ * @var string
+ */
+ public $Subject = '';
+
+ /**
+ * Sets the Body of the message. This can be either an HTML or text body.
+ * If HTML then run IsHTML(true).
+ * @var string
+ */
+ public $Body = '';
+
+ /**
+ * Sets the text-only body of the message. This automatically sets the
+ * email to multipart/alternative. This body can be read by mail
+ * clients that do not have HTML email capability such as mutt. Clients
+ * that can read HTML will view the normal Body.
+ * @var string
+ */
+ public $AltBody = '';
+
+ /**
+ * Stores the complete compiled MIME message body.
+ * @var string
+ * @access protected
+ */
+ protected $MIMEBody = '';
+
+ /**
+ * Stores the complete compiled MIME message headers.
+ * @var string
+ * @access protected
+ */
+ protected $MIMEHeader = '';
+
+ /**
+ * Stores the extra header list which CreateHeader() doesn't fold in
+ * @var string
+ * @access protected
+ */
+ protected $mailHeader = '';
+
+ /**
+ * Sets word wrapping on the body of the message to a given number of
+ * characters.
+ * @var int
+ */
+ public $WordWrap = 0;
+
+ /**
+ * Method to send mail: ("mail", "sendmail", or "smtp").
+ * @var string
+ */
+ public $Mailer = 'mail';
+
+ /**
+ * Sets the path of the sendmail program.
+ * @var string
+ */
+ public $Sendmail = '/usr/sbin/sendmail';
+
+ /**
+ * Determine if mail() uses a fully sendmail compatible MTA that
+ * supports sendmail's "-oi -f" options
+ * @var boolean
+ */
+ public $UseSendmailOptions = true;
+
+ /**
+ * Path to PHPMailer plugins. Useful if the SMTP class
+ * is in a different directory than the PHP include path.
+ * @var string
+ */
+ public $PluginDir = '';
+
+ /**
+ * Sets the email address that a reading confirmation will be sent.
+ * @var string
+ */
+ public $ConfirmReadingTo = '';
+
+ /**
+ * Sets the hostname to use in Message-Id and Received headers
+ * and as default HELO string. If empty, the value returned
+ * by SERVER_NAME is used or 'localhost.localdomain'.
+ * @var string
+ */
+ public $Hostname = '';
+
+ /**
+ * Sets the message ID to be used in the Message-Id header.
+ * If empty, a unique id will be generated.
+ * @var string
+ */
+ public $MessageID = '';
+
+ /**
+ * Sets the message Date to be used in the Date header.
+ * If empty, the current date will be added.
+ * @var string
+ */
+ public $MessageDate = '';
+
+ /////////////////////////////////////////////////
+ // PROPERTIES FOR SMTP
+ /////////////////////////////////////////////////
+
+ /**
+ * Sets the SMTP hosts.
+ *
+ * All hosts must be separated by a
+ * semicolon. You can also specify a different port
+ * for each host by using this format: [hostname:port]
+ * (e.g. "smtp1.example.com:25;smtp2.example.com").
+ * Hosts will be tried in order.
+ * @var string
+ */
+ public $Host = 'localhost';
+
+ /**
+ * Sets the default SMTP server port.
+ * @var int
+ */
+ public $Port = 25;
+
+ /**
+ * Sets the SMTP HELO of the message (Default is $Hostname).
+ * @var string
+ */
+ public $Helo = '';
+
+ /**
+ * Sets connection prefix. Options are "", "ssl" or "tls"
+ * @var string
+ */
+ public $SMTPSecure = '';
+
+ /**
+ * Sets SMTP authentication. Utilizes the Username and Password variables.
+ * @var bool
+ */
+ public $SMTPAuth = false;
+
+ /**
+ * Sets SMTP username.
+ * @var string
+ */
+ public $Username = '';
+
+ /**
+ * Sets SMTP password.
+ * @var string
+ */
+ public $Password = '';
+
+ /**
+ * Sets SMTP auth type. Options are LOGIN | PLAIN | NTLM (default LOGIN)
+ * @var string
+ */
+ public $AuthType = '';
+
+ /**
+ * Sets SMTP realm.
+ * @var string
+ */
+ public $Realm = '';
+
+ /**
+ * Sets SMTP workstation.
+ * @var string
+ */
+ public $Workstation = '';
+
+ /**
+ * Sets the SMTP server timeout in seconds.
+ * This function will not work with the win32 version.
+ * @var int
+ */
+ public $Timeout = 10;
+
+ /**
+ * Sets SMTP class debugging on or off.
+ * @var bool
+ */
+ public $SMTPDebug = false;
+
+ /**
+ * Sets the function/method to use for debugging output.
+ * Right now we only honor "echo" or "error_log"
+ * @var string
+ */
+ public $Debugoutput = "echo";
+
+ /**
+ * Prevents the SMTP connection from being closed after each mail
+ * sending. If this is set to true then to close the connection
+ * requires an explicit call to SmtpClose().
+ * @var bool
+ */
+ public $SMTPKeepAlive = false;
+
+ /**
+ * Provides the ability to have the TO field process individual
+ * emails, instead of sending to entire TO addresses
+ * @var bool
+ */
+ public $SingleTo = false;
+
+ /**
+ * If SingleTo is true, this provides the array to hold the email addresses
+ * @var bool
+ */
+ public $SingleToArray = array();
+
+ /**
+ * Provides the ability to change the generic line ending
+ * NOTE: The default remains '\n'. We force CRLF where we KNOW
+ * it must be used via self::CRLF
+ * @var string
+ */
+ public $LE = "\n";
+
+ /**
+ * Used with DKIM Signing
+ * required parameter if DKIM is enabled
+ *
+ * domain selector example domainkey
+ * @var string
+ */
+ public $DKIM_selector = '';
+
+ /**
+ * Used with DKIM Signing
+ * required if DKIM is enabled, in format of email address 'you@yourdomain.com' typically used as the source of the email
+ * @var string
+ */
+ public $DKIM_identity = '';
+
+ /**
+ * Used with DKIM Signing
+ * optional parameter if your private key requires a passphras
+ * @var string
+ */
+ public $DKIM_passphrase = '';
+
+ /**
+ * Used with DKIM Singing
+ * required if DKIM is enabled, in format of email address 'domain.com'
+ * @var string
+ */
+ public $DKIM_domain = '';
+
+ /**
+ * Used with DKIM Signing
+ * required if DKIM is enabled, path to private key file
+ * @var string
+ */
+ public $DKIM_private = '';
+
+ /**
+ * Callback Action function name.
+ * The function that handles the result of the send email action.
+ * It is called out by Send() for each email sent.
+ *
+ * Value can be:
+ * - 'function_name' for function names
+ * - 'Class::Method' for static method calls
+ * - array($object, 'Method') for calling methods on $object
+ * See http://php.net/is_callable manual page for more details.
+ *
+ * Parameters:
+ * bool $result result of the send action
+ * string $to email address of the recipient
+ * string $cc cc email addresses
+ * string $bcc bcc email addresses
+ * string $subject the subject
+ * string $body the email body
+ * string $from email address of sender
+ * @var string
+ */
+ public $action_function = ''; //'callbackAction';
+
+ /**
+ * Sets the PHPMailer Version number
+ * @var string
+ */
+ public $Version = '5.2.4';
+
+ /**
+ * What to use in the X-Mailer header
+ * @var string NULL for default, whitespace for None, or actual string to use
+ */
+ public $XMailer = '';
+
+ /////////////////////////////////////////////////
+ // PROPERTIES, PRIVATE AND PROTECTED
+ /////////////////////////////////////////////////
+
+ /**
+ * @var SMTP An instance of the SMTP sender class
+ * @access protected
+ */
+ protected $smtp = null;
+ /**
+ * @var array An array of 'to' addresses
+ * @access protected
+ */
+ protected $to = array();
+ /**
+ * @var array An array of 'cc' addresses
+ * @access protected
+ */
+ protected $cc = array();
+ /**
+ * @var array An array of 'bcc' addresses
+ * @access protected
+ */
+ protected $bcc = array();
+ /**
+ * @var array An array of reply-to name and address
+ * @access protected
+ */
+ protected $ReplyTo = array();
+ /**
+ * @var array An array of all kinds of addresses: to, cc, bcc, replyto
+ * @access protected
+ */
+ protected $all_recipients = array();
+ /**
+ * @var array An array of attachments
+ * @access protected
+ */
+ protected $attachment = array();
+ /**
+ * @var array An array of custom headers
+ * @access protected
+ */
+ protected $CustomHeader = array();
+ /**
+ * @var string The message's MIME type
+ * @access protected
+ */
+ protected $message_type = '';
+ /**
+ * @var array An array of MIME boundary strings
+ * @access protected
+ */
+ protected $boundary = array();
+ /**
+ * @var array An array of available languages
+ * @access protected
+ */
+ protected $language = array();
+ /**
+ * @var integer The number of errors encountered
+ * @access protected
+ */
+ protected $error_count = 0;
+ /**
+ * @var string The filename of a DKIM certificate file
+ * @access protected
+ */
+ protected $sign_cert_file = '';
+ /**
+ * @var string The filename of a DKIM key file
+ * @access protected
+ */
+ protected $sign_key_file = '';
+ /**
+ * @var string The password of a DKIM key
+ * @access protected
+ */
+ protected $sign_key_pass = '';
+ /**
+ * @var boolean Whether to throw exceptions for errors
+ * @access protected
+ */
+ protected $exceptions = false;
+
+ /////////////////////////////////////////////////
+ // CONSTANTS
+ /////////////////////////////////////////////////
+
+ const STOP_MESSAGE = 0; // message only, continue processing
+ const STOP_CONTINUE = 1; // message?, likely ok to continue processing
+ const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
+ const CRLF = "\r\n"; // SMTP RFC specified EOL
+
+ /////////////////////////////////////////////////
+ // METHODS, VARIABLES
+ /////////////////////////////////////////////////
+
+ /**
+ * Calls actual mail() function, but in a safe_mode aware fashion
+ * Also, unless sendmail_path points to sendmail (or something that
+ * claims to be sendmail), don't pass params (not a perfect fix,
+ * but it will do)
+ * @param string $to To
+ * @param string $subject Subject
+ * @param string $body Message Body
+ * @param string $header Additional Header(s)
+ * @param string $params Params
+ * @access private
+ * @return bool
+ */
+ private function mail_passthru($to, $subject, $body, $header, $params) {
+ if ( ini_get('safe_mode') || !($this->UseSendmailOptions) ) {
+ $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header);
+ } else {
+ $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header, $params);
+ }
+ return $rt;
+ }
+
+ /**
+ * Outputs debugging info via user-defined method
+ * @param string $str
+ */
+ private function edebug($str) {
+ if ($this->Debugoutput == "error_log") {
+ error_log($str);
+ } else {
+ echo $str;
+ }
+ }
+
+ /**
+ * Constructor
+ * @param boolean $exceptions Should we throw external exceptions?
+ */
+ public function __construct($exceptions = false) {
+ $this->exceptions = ($exceptions == true);
+ }
+
+ /**
+ * Sets message type to HTML.
+ * @param bool $ishtml
+ * @return void
+ */
+ public function IsHTML($ishtml = true) {
+ if ($ishtml) {
+ $this->ContentType = 'text/html';
+ } else {
+ $this->ContentType = 'text/plain';
+ }
+ }
+
+ /**
+ * Sets Mailer to send message using SMTP.
+ * @return void
+ */
+ public function IsSMTP() {
+ $this->Mailer = 'smtp';
+ }
+
+ /**
+ * Sets Mailer to send message using PHP mail() function.
+ * @return void
+ */
+ public function IsMail() {
+ $this->Mailer = 'mail';
+ }
+
+ /**
+ * Sets Mailer to send message using the $Sendmail program.
+ * @return void
+ */
+ public function IsSendmail() {
+ if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
+ $this->Sendmail = '/var/qmail/bin/sendmail';
+ }
+ $this->Mailer = 'sendmail';
+ }
+
+ /**
+ * Sets Mailer to send message using the qmail MTA.
+ * @return void
+ */
+ public function IsQmail() {
+ if (stristr(ini_get('sendmail_path'), 'qmail')) {
+ $this->Sendmail = '/var/qmail/bin/sendmail';
+ }
+ $this->Mailer = 'sendmail';
+ }
+
+ /////////////////////////////////////////////////
+ // METHODS, RECIPIENTS
+ /////////////////////////////////////////////////
+
+ /**
+ * Adds a "To" address.
+ * @param string $address
+ * @param string $name
+ * @return boolean true on success, false if address already used
+ */
+ public function AddAddress($address, $name = '') {
+ return $this->AddAnAddress('to', $address, $name);
+ }
+
+ /**
+ * Adds a "Cc" address.
+ * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
+ * @param string $address
+ * @param string $name
+ * @return boolean true on success, false if address already used
+ */
+ public function AddCC($address, $name = '') {
+ return $this->AddAnAddress('cc', $address, $name);
+ }
+
+ /**
+ * Adds a "Bcc" address.
+ * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
+ * @param string $address
+ * @param string $name
+ * @return boolean true on success, false if address already used
+ */
+ public function AddBCC($address, $name = '') {
+ return $this->AddAnAddress('bcc', $address, $name);
+ }
+
+ /**
+ * Adds a "Reply-to" address.
+ * @param string $address
+ * @param string $name
+ * @return boolean
+ */
+ public function AddReplyTo($address, $name = '') {
+ return $this->AddAnAddress('Reply-To', $address, $name);
+ }
+
+ /**
+ * Adds an address to one of the recipient arrays
+ * Addresses that have been added already return false, but do not throw exceptions
+ * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
+ * @param string $address The email address to send to
+ * @param string $name
+ * @throws phpmailerException
+ * @return boolean true on success, false if address already used or invalid in some way
+ * @access protected
+ */
+ protected function AddAnAddress($kind, $address, $name = '') {
+ if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
+ $this->SetError($this->Lang('Invalid recipient array').': '.$kind);
+ if ($this->exceptions) {
+ throw new phpmailerException('Invalid recipient array: ' . $kind);
+ }
+ if ($this->SMTPDebug) {
+ $this->edebug($this->Lang('Invalid recipient array').': '.$kind);
+ }
+ return false;
+ }
+ $address = trim($address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ if (!$this->ValidateAddress($address)) {
+ $this->SetError($this->Lang('invalid_address').': '. $address);
+ if ($this->exceptions) {
+ throw new phpmailerException($this->Lang('invalid_address').': '.$address);
+ }
+ if ($this->SMTPDebug) {
+ $this->edebug($this->Lang('invalid_address').': '.$address);
+ }
+ return false;
+ }
+ if ($kind != 'Reply-To') {
+ if (!isset($this->all_recipients[strtolower($address)])) {
+ array_push($this->$kind, array($address, $name));
+ $this->all_recipients[strtolower($address)] = true;
+ return true;
+ }
+ } else {
+ if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
+ $this->ReplyTo[strtolower($address)] = array($address, $name);
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Set the From and FromName properties
+ * @param string $address
+ * @param string $name
+ * @param int $auto Also set Reply-To and Sender
+ * @throws phpmailerException
+ * @return boolean
+ */
+ public function SetFrom($address, $name = '', $auto = 1) {
+ $address = trim($address);
+ $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+ if (!$this->ValidateAddress($address)) {
+ $this->SetError($this->Lang('invalid_address').': '. $address);
+ if ($this->exceptions) {
+ throw new phpmailerException($this->Lang('invalid_address').': '.$address);
+ }
+ if ($this->SMTPDebug) {
+ $this->edebug($this->Lang('invalid_address').': '.$address);
+ }
+ return false;
+ }
+ $this->From = $address;
+ $this->FromName = $name;
+ if ($auto) {
+ if (empty($this->ReplyTo)) {
+ $this->AddAnAddress('Reply-To', $address, $name);
+ }
+ if (empty($this->Sender)) {
+ $this->Sender = $address;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check that a string looks roughly like an email address should
+ * Static so it can be used without instantiation, public so people can overload
+ * Conforms to RFC5322: Uses *correct* regex on which FILTER_VALIDATE_EMAIL is
+ * based; So why not use FILTER_VALIDATE_EMAIL? Because it was broken to
+ * not allow a@b type valid addresses :(
+ * Some Versions of PHP break on the regex though, likely due to PCRE, so use
+ * the older validation method for those users. (http://php.net/manual/en/pcre.installation.php)
+ * @link http://squiloople.com/2009/12/20/email-address-validation/
+ * @copyright regex Copyright Michael Rushton 2009-10 | http://squiloople.com/ | Feel free to use and redistribute this code. But please keep this copyright notice.
+ * @param string $address The email address to check
+ * @return boolean
+ * @static
+ * @access public
+ */
+ public static function ValidateAddress($address) {
+ if ((defined('PCRE_VERSION')) && (version_compare(PCRE_VERSION, '8.0') >= 0)) {
+ return preg_match('/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[ ])+|(?>[ ]*\x0D\x0A)?[ ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){7,})((?6)(?>:(?6)){0,5})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){5,})(?8)?::(?>((?6)(?>:(?6)){0,3}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address);
+ } elseif (function_exists('filter_var')) { //Introduced in PHP 5.2
+ if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
+ }
+ }
+
+ /////////////////////////////////////////////////
+ // METHODS, MAIL SENDING
+ /////////////////////////////////////////////////
+
+ /**
+ * Creates message and assigns Mailer. If the message is
+ * not sent successfully then it returns false. Use the ErrorInfo
+ * variable to view description of the error.
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function Send() {
+ try {
+ if(!$this->PreSend()) return false;
+ return $this->PostSend();
+ } catch (phpmailerException $e) {
+ $this->mailHeader = '';
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Prep mail by constructing all message entities
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function PreSend() {
+ try {
+ $this->mailHeader = "";
+ if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
+ throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
+ }
+
+ // Set whether the message is multipart/alternative
+ if(!empty($this->AltBody)) {
+ $this->ContentType = 'multipart/alternative';
+ }
+
+ $this->error_count = 0; // reset errors
+ $this->SetMessageType();
+ //Refuse to send an empty message
+ if (empty($this->Body)) {
+ throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
+ }
+
+ $this->MIMEHeader = $this->CreateHeader();
+ $this->MIMEBody = $this->CreateBody();
+
+ // To capture the complete message when using mail(), create
+ // an extra header list which CreateHeader() doesn't fold in
+ if ($this->Mailer == 'mail') {
+ if (count($this->to) > 0) {
+ $this->mailHeader .= $this->AddrAppend("To", $this->to);
+ } else {
+ $this->mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;");
+ }
+ $this->mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject))));
+ // if(count($this->cc) > 0) {
+ // $this->mailHeader .= $this->AddrAppend("Cc", $this->cc);
+ // }
+ }
+
+ // digitally sign with DKIM if enabled
+ if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector) && !empty($this->DKIM_domain) && file_exists($this->DKIM_private)) {
+ $header_dkim = $this->DKIM_Add($this->MIMEHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
+ $this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader;
+ }
+
+ return true;
+
+ } catch (phpmailerException $e) {
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Actual Email transport function
+ * Send the email via the selected mechanism
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function PostSend() {
+ try {
+ // Choose the mailer and send through it
+ switch($this->Mailer) {
+ case 'sendmail':
+ return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody);
+ case 'smtp':
+ return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
+ case 'mail':
+ return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
+ default:
+ return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
+ }
+ } catch (phpmailerException $e) {
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ if ($this->SMTPDebug) {
+ $this->edebug($e->getMessage()."\n");
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sends mail using the $Sendmail program.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @throws phpmailerException
+ * @access protected
+ * @return bool
+ */
+ protected function SendmailSend($header, $body) {
+ if ($this->Sender != '') {
+ $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+ } else {
+ $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
+ }
+ if ($this->SingleTo === true) {
+ foreach ($this->SingleToArray as $val) {
+ if(!@$mail = popen($sendmail, 'w')) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fputs($mail, "To: " . $val . "\n");
+ fputs($mail, $header);
+ fputs($mail, $body);
+ $result = pclose($mail);
+ // implement call back function if it exists
+ $isSent = ($result == 0) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
+ if($result != 0) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ } else {
+ if(!@$mail = popen($sendmail, 'w')) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ fputs($mail, $header);
+ fputs($mail, $body);
+ $result = pclose($mail);
+ // implement call back function if it exists
+ $isSent = ($result == 0) ? 1 : 0;
+ $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
+ if($result != 0) {
+ throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Sends mail using the PHP mail() function.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @throws phpmailerException
+ * @access protected
+ * @return bool
+ */
+ protected function MailSend($header, $body) {
+ $toArr = array();
+ foreach($this->to as $t) {
+ $toArr[] = $this->AddrFormat($t);
+ }
+ $to = implode(', ', $toArr);
+
+ if (empty($this->Sender)) {
+ $params = "-oi ";
+ } else {
+ $params = sprintf("-oi -f%s", $this->Sender);
+ }
+ if ($this->Sender != '' and !ini_get('safe_mode')) {
+ $old_from = ini_get('sendmail_from');
+ ini_set('sendmail_from', $this->Sender);
+ }
+ $rt = false;
+ if ($this->SingleTo === true && count($toArr) > 1) {
+ foreach ($toArr as $val) {
+ $rt = $this->mail_passthru($val, $this->Subject, $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
+ }
+ } else {
+ $rt = $this->mail_passthru($to, $this->Subject, $body, $header, $params);
+ // implement call back function if it exists
+ $isSent = ($rt == 1) ? 1 : 0;
+ $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
+ }
+ if (isset($old_from)) {
+ ini_set('sendmail_from', $old_from);
+ }
+ if(!$rt) {
+ throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
+ }
+ return true;
+ }
+
+ /**
+ * Sends mail via SMTP using PhpSMTP
+ * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
+ * @param string $header The message headers
+ * @param string $body The message body
+ * @throws phpmailerException
+ * @uses SMTP
+ * @access protected
+ * @return bool
+ */
+ protected function SmtpSend($header, $body) {
+ require_once $this->PluginDir . 'class-smtp.php';
+ $bad_rcpt = array();
+
+ if(!$this->SmtpConnect()) {
+ throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
+ }
+ $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
+ if(!$this->smtp->Mail($smtp_from)) {
+ $this->SetError($this->Lang('from_failed') . $smtp_from . " : " . implode(",",$this->smtp->getError())) ;
+ throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
+ }
+
+ // Attempt to send attach all recipients
+ foreach($this->to as $to) {
+ if (!$this->smtp->Recipient($to[0])) {
+ $bad_rcpt[] = $to[0];
+ // implement call back function if it exists
+ $isSent = 0;
+ $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
+ } else {
+ // implement call back function if it exists
+ $isSent = 1;
+ $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
+ }
+ }
+ foreach($this->cc as $cc) {
+ if (!$this->smtp->Recipient($cc[0])) {
+ $bad_rcpt[] = $cc[0];
+ // implement call back function if it exists
+ $isSent = 0;
+ $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
+ } else {
+ // implement call back function if it exists
+ $isSent = 1;
+ $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
+ }
+ }
+ foreach($this->bcc as $bcc) {
+ if (!$this->smtp->Recipient($bcc[0])) {
+ $bad_rcpt[] = $bcc[0];
+ // implement call back function if it exists
+ $isSent = 0;
+ $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
+ } else {
+ // implement call back function if it exists
+ $isSent = 1;
+ $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
+ }
+ }
+
+
+ if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
+ $badaddresses = implode(', ', $bad_rcpt);
+ throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
+ }
+ if(!$this->smtp->Data($header . $body)) {
+ throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
+ }
+ if($this->SMTPKeepAlive == true) {
+ $this->smtp->Reset();
+ } else {
+ $this->smtp->Quit();
+ $this->smtp->Close();
+ }
+ return true;
+ }
+
+ /**
+ * Initiates a connection to an SMTP server.
+ * Returns false if the operation failed.
+ * @uses SMTP
+ * @access public
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function SmtpConnect() {
+ if(is_null($this->smtp)) {
+ $this->smtp = new SMTP;
+ }
+
+ $this->smtp->Timeout = $this->Timeout;
+ $this->smtp->do_debug = $this->SMTPDebug;
+ $hosts = explode(';', $this->Host);
+ $index = 0;
+ $connection = $this->smtp->Connected();
+
+ // Retry while there is no connection
+ try {
+ while($index < count($hosts) && !$connection) {
+ $hostinfo = array();
+ if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
+ $host = $hostinfo[1];
+ $port = $hostinfo[2];
+ } else {
+ $host = $hosts[$index];
+ $port = $this->Port;
+ }
+
+ $tls = ($this->SMTPSecure == 'tls');
+ $ssl = ($this->SMTPSecure == 'ssl');
+
+ if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
+
+ $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
+ $this->smtp->Hello($hello);
+
+ if ($tls) {
+ if (!$this->smtp->StartTLS()) {
+ throw new phpmailerException($this->Lang('connect_host'));
+ }
+
+ //We must resend HELO after tls negotiation
+ $this->smtp->Hello($hello);
+ }
+
+ $connection = true;
+ if ($this->SMTPAuth) {
+ if (!$this->smtp->Authenticate($this->Username, $this->Password, $this->AuthType,
+ $this->Realm, $this->Workstation)) {
+ throw new phpmailerException($this->Lang('authenticate'));
+ }
+ }
+ }
+ $index++;
+ if (!$connection) {
+ throw new phpmailerException($this->Lang('connect_host'));
+ }
+ }
+ } catch (phpmailerException $e) {
+ $this->smtp->Reset();
+ if ($this->exceptions) {
+ throw $e;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Closes the active SMTP session if one exists.
+ * @return void
+ */
+ public function SmtpClose() {
+ if ($this->smtp !== null) {
+ if($this->smtp->Connected()) {
+ $this->smtp->Quit();
+ $this->smtp->Close();
+ }
+ }
+ }
+
+ /**
+ * Sets the language for all class error messages.
+ * Returns false if it cannot load the language file. The default language is English.
+ * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
+ * @param string $lang_path Path to the language file directory
+ * @return bool
+ * @access public
+ */
+ function SetLanguage($langcode = 'en', $lang_path = 'language/') {
+ //Define full set of translatable strings
+ $PHPMAILER_LANG = array(
+ 'authenticate' => 'SMTP Error: Could not authenticate.',
+ 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
+ 'data_not_accepted' => 'SMTP Error: Data not accepted.',
+ 'empty_message' => 'Message body empty',
+ 'encoding' => 'Unknown encoding: ',
+ 'execute' => 'Could not execute: ',
+ 'file_access' => 'Could not access file: ',
+ 'file_open' => 'File Error: Could not open file: ',
+ 'from_failed' => 'The following From address failed: ',
+ 'instantiate' => 'Could not instantiate mail function.',
+ 'invalid_address' => 'Invalid address',
+ 'mailer_not_supported' => ' mailer is not supported.',
+ 'provide_address' => 'You must provide at least one recipient email address.',
+ 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
+ 'signing' => 'Signing Error: ',
+ 'smtp_connect_failed' => 'SMTP Connect() failed.',
+ 'smtp_error' => 'SMTP server error: ',
+ 'variable_set' => 'Cannot set or reset variable: '
+ );
+ //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
+ $l = true;
+ if ($langcode != 'en') { //There is no English translation file
+ $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
+ }
+ $this->language = $PHPMAILER_LANG;
+ return ($l == true); //Returns false if language not found
+ }
+
+ /**
+ * Return the current array of language strings
+ * @return array
+ */
+ public function GetTranslations() {
+ return $this->language;
+ }
+
+ /////////////////////////////////////////////////
+ // METHODS, MESSAGE CREATION
+ /////////////////////////////////////////////////
+
+ /**
+ * Creates recipient headers.
+ * @access public
+ * @param string $type
+ * @param array $addr
+ * @return string
+ */
+ public function AddrAppend($type, $addr) {
+ $addr_str = $type . ': ';
+ $addresses = array();
+ foreach ($addr as $a) {
+ $addresses[] = $this->AddrFormat($a);
+ }
+ $addr_str .= implode(', ', $addresses);
+ $addr_str .= $this->LE;
+
+ return $addr_str;
+ }
+
+ /**
+ * Formats an address correctly.
+ * @access public
+ * @param string $addr
+ * @return string
+ */
+ public function AddrFormat($addr) {
+ if (empty($addr[1])) {
+ return $this->SecureHeader($addr[0]);
+ } else {
+ return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
+ }
+ }
+
+ /**
+ * Wraps message for use with mailers that do not
+ * automatically perform wrapping and for quoted-printable.
+ * Original written by philippe.
+ * @param string $message The message to wrap
+ * @param integer $length The line length to wrap to
+ * @param boolean $qp_mode Whether to run in Quoted-Printable mode
+ * @access public
+ * @return string
+ */
+ public function WrapText($message, $length, $qp_mode = false) {
+ $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
+ // If utf-8 encoding is used, we will need to make sure we don't
+ // split multibyte characters when we wrap
+ $is_utf8 = (strtolower($this->CharSet) == "utf-8");
+ $lelen = strlen($this->LE);
+ $crlflen = strlen(self::CRLF);
+
+ $message = $this->FixEOL($message);
+ if (substr($message, -$lelen) == $this->LE) {
+ $message = substr($message, 0, -$lelen);
+ }
+
+ $line = explode($this->LE, $message); // Magic. We know FixEOL uses $LE
+ $message = '';
+ for ($i = 0 ;$i < count($line); $i++) {
+ $line_part = explode(' ', $line[$i]);
+ $buf = '';
+ for ($e = 0; $e<count($line_part); $e++) {
+ $word = $line_part[$e];
+ if ($qp_mode and (strlen($word) > $length)) {
+ $space_left = $length - strlen($buf) - $crlflen;
+ if ($e != 0) {
+ if ($space_left > 20) {
+ $len = $space_left;
+ if ($is_utf8) {
+ $len = $this->UTF8CharBoundary($word, $len);
+ } elseif (substr($word, $len - 1, 1) == "=") {
+ $len--;
+ } elseif (substr($word, $len - 2, 1) == "=") {
+ $len -= 2;
+ }
+ $part = substr($word, 0, $len);
+ $word = substr($word, $len);
+ $buf .= ' ' . $part;
+ $message .= $buf . sprintf("=%s", self::CRLF);
+ } else {
+ $message .= $buf . $soft_break;
+ }
+ $buf = '';
+ }
+ while (strlen($word) > 0) {
+ $len = $length;
+ if ($is_utf8) {
+ $len = $this->UTF8CharBoundary($word, $len);
+ } elseif (substr($word, $len - 1, 1) == "=") {
+ $len--;
+ } elseif (substr($word, $len - 2, 1) == "=") {
+ $len -= 2;
+ }
+ $part = substr($word, 0, $len);
+ $word = substr($word, $len);
+
+ if (strlen($word) > 0) {
+ $message .= $part . sprintf("=%s", self::CRLF);
+ } else {
+ $buf = $part;
+ }
+ }
+ } else {
+ $buf_o = $buf;
+ $buf .= ($e == 0) ? $word : (' ' . $word);
+
+ if (strlen($buf) > $length and $buf_o != '') {
+ $message .= $buf_o . $soft_break;
+ $buf = $word;
+ }
+ }
+ }
+ $message .= $buf . self::CRLF;
+ }
+
+ return $message;
+ }
+
+ /**
+ * Finds last character boundary prior to maxLength in a utf-8
+ * quoted (printable) encoded string.
+ * Original written by Colin Brown.
+ * @access public
+ * @param string $encodedText utf-8 QP text
+ * @param int $maxLength find last character boundary prior to this length
+ * @return int
+ */
+ public function UTF8CharBoundary($encodedText, $maxLength) {
+ $foundSplitPos = false;
+ $lookBack = 3;
+ while (!$foundSplitPos) {
+ $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
+ $encodedCharPos = strpos($lastChunk, "=");
+ if ($encodedCharPos !== false) {
+ // Found start of encoded character byte within $lookBack block.
+ // Check the encoded byte value (the 2 chars after the '=')
+ $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
+ $dec = hexdec($hex);
+ if ($dec < 128) { // Single byte character.
+ // If the encoded char was found at pos 0, it will fit
+ // otherwise reduce maxLength to start of the encoded char
+ $maxLength = ($encodedCharPos == 0) ? $maxLength :
+ $maxLength - ($lookBack - $encodedCharPos);
+ $foundSplitPos = true;
+ } elseif ($dec >= 192) { // First byte of a multi byte character
+ // Reduce maxLength to split at start of character
+ $maxLength = $maxLength - ($lookBack - $encodedCharPos);
+ $foundSplitPos = true;
+ } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
+ $lookBack += 3;
+ }
+ } else {
+ // No encoded character found
+ $foundSplitPos = true;
+ }
+ }
+ return $maxLength;
+ }
+
+
+ /**
+ * Set the body wrapping.
+ * @access public
+ * @return void
+ */
+ public function SetWordWrap() {
+ if($this->WordWrap < 1) {
+ return;
+ }
+
+ switch($this->message_type) {
+ case 'alt':
+ case 'alt_inline':
+ case 'alt_attach':
+ case 'alt_inline_attach':
+ $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
+ break;
+ default:
+ $this->Body = $this->WrapText($this->Body, $this->WordWrap);
+ break;
+ }
+ }
+
+ /**
+ * Assembles message header.
+ * @access public
+ * @return string The assembled header
+ */
+ public function CreateHeader() {
+ $result = '';
+
+ // Set the boundaries
+ $uniq_id = md5(uniqid(time()));
+ $this->boundary[1] = 'b1_' . $uniq_id;
+ $this->boundary[2] = 'b2_' . $uniq_id;
+ $this->boundary[3] = 'b3_' . $uniq_id;
+
+ if ($this->MessageDate == '') {
+ $result .= $this->HeaderLine('Date', self::RFCDate());
+ } else {
+ $result .= $this->HeaderLine('Date', $this->MessageDate);
+ }
+
+ if ($this->ReturnPath) {
+ $result .= $this->HeaderLine('Return-Path', trim($this->ReturnPath));
+ } elseif ($this->Sender == '') {
+ $result .= $this->HeaderLine('Return-Path', trim($this->From));
+ } else {
+ $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
+ }
+
+ // To be created automatically by mail()
+ if($this->Mailer != 'mail') {
+ if ($this->SingleTo === true) {
+ foreach($this->to as $t) {
+ $this->SingleToArray[] = $this->AddrFormat($t);
+ }
+ } else {
+ if(count($this->to) > 0) {
+ $result .= $this->AddrAppend('To', $this->to);
+ } elseif (count($this->cc) == 0) {
+ $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
+ }
+ }
+ }
+
+ $from = array();
+ $from[0][0] = trim($this->From);
+ $from[0][1] = $this->FromName;
+ $result .= $this->AddrAppend('From', $from);
+
+ // sendmail and mail() extract Cc from the header before sending
+ if(count($this->cc) > 0) {
+ $result .= $this->AddrAppend('Cc', $this->cc);
+ }
+
+ // sendmail and mail() extract Bcc from the header before sending
+ if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
+ $result .= $this->AddrAppend('Bcc', $this->bcc);
+ }
+
+ if(count($this->ReplyTo) > 0) {
+ $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
+ }
+
+ // mail() sets the subject itself
+ if($this->Mailer != 'mail') {
+ $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
+ }
+
+ if($this->MessageID != '') {
+ $result .= $this->HeaderLine('Message-ID', $this->MessageID);
+ } else {
+ $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
+ }
+ $result .= $this->HeaderLine('X-Priority', $this->Priority);
+ if ($this->XMailer == '') {
+ $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (http://code.google.com/a/apache-extras.org/p/phpmailer/)');
+ } else {
+ $myXmailer = trim($this->XMailer);
+ if ($myXmailer) {
+ $result .= $this->HeaderLine('X-Mailer', $myXmailer);
+ }
+ }
+
+ if($this->ConfirmReadingTo != '') {
+ $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
+ }
+
+ // Add custom headers
+ for($index = 0; $index < count($this->CustomHeader); $index++) {
+ $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
+ }
+ if (!$this->sign_key_file) {
+ $result .= $this->HeaderLine('MIME-Version', '1.0');
+ $result .= $this->GetMailMIME();
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the message MIME.
+ * @access public
+ * @return string
+ */
+ public function GetMailMIME() {
+ $result = '';
+ switch($this->message_type) {
+ case 'inline':
+ $result .= $this->HeaderLine('Content-Type', 'multipart/related;');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ case 'attach':
+ case 'inline_attach':
+ case 'alt_attach':
+ case 'alt_inline_attach':
+ $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ case 'alt':
+ case 'alt_inline':
+ $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
+ $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+ break;
+ default:
+ // Catches case 'plain': and case '':
+ $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
+ $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet);
+ break;
+ }
+
+ if($this->Mailer != 'mail') {
+ $result .= $this->LE;
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the MIME message (headers and body). Only really valid post PreSend().
+ * @access public
+ * @return string
+ */
+ public function GetSentMIMEMessage() {
+ return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
+ }
+
+
+ /**
+ * Assembles the message body. Returns an empty string on failure.
+ * @access public
+ * @throws phpmailerException
+ * @return string The assembled message body
+ */
+ public function CreateBody() {
+ $body = '';
+
+ if ($this->sign_key_file) {
+ $body .= $this->GetMailMIME().$this->LE;
+ }
+
+ $this->SetWordWrap();
+
+ switch($this->message_type) {
+ case 'inline':
+ $body .= $this->GetBoundary($this->boundary[1], '', '', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->AttachAll("inline", $this->boundary[1]);
+ break;
+ case 'attach':
+ $body .= $this->GetBoundary($this->boundary[1], '', '', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ break;
+ case 'inline_attach':
+ $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->GetBoundary($this->boundary[2], '', '', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->AttachAll("inline", $this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ break;
+ case 'alt':
+ $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
+ $body .= $this->EncodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->EndBoundary($this->boundary[1]);
+ break;
+ case 'alt_inline':
+ $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
+ $body .= $this->EncodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->AttachAll("inline", $this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->EndBoundary($this->boundary[1]);
+ break;
+ case 'alt_attach':
+ $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
+ $body .= $this->EncodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->EndBoundary($this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ break;
+ case 'alt_inline_attach':
+ $body .= $this->TextLine("--" . $this->boundary[1]);
+ $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
+ $body .= $this->LE;
+ $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
+ $body .= $this->EncodeString($this->AltBody, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->TextLine("--" . $this->boundary[2]);
+ $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
+ $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3] . '"');
+ $body .= $this->LE;
+ $body .= $this->GetBoundary($this->boundary[3], '', 'text/html', '');
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ $body .= $this->LE.$this->LE;
+ $body .= $this->AttachAll("inline", $this->boundary[3]);
+ $body .= $this->LE;
+ $body .= $this->EndBoundary($this->boundary[2]);
+ $body .= $this->LE;
+ $body .= $this->AttachAll("attachment", $this->boundary[1]);
+ break;
+ default:
+ // catch case 'plain' and case ''
+ $body .= $this->EncodeString($this->Body, $this->Encoding);
+ break;
+ }
+
+ if ($this->IsError()) {
+ $body = '';
+ } elseif ($this->sign_key_file) {
+ try {
+ $file = tempnam('', 'mail');
+ file_put_contents($file, $body); //TODO check this worked
+ $signed = tempnam("", "signed");
+ if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
+ @unlink($file);
+ $body = file_get_contents($signed);
+ @unlink($signed);
+ } else {
+ @unlink($file);
+ @unlink($signed);
+ throw new phpmailerException($this->Lang("signing").openssl_error_string());
+ }
+ } catch (phpmailerException $e) {
+ $body = '';
+ if ($this->exceptions) {
+ throw $e;
+ }
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Returns the start of a message boundary.
+ * @access protected
+ * @param string $boundary
+ * @param string $charSet
+ * @param string $contentType
+ * @param string $encoding
+ * @return string
+ */
+ protected function GetBoundary($boundary, $charSet, $contentType, $encoding) {
+ $result = '';
+ if($charSet == '') {
+ $charSet = $this->CharSet;
+ }
+ if($contentType == '') {
+ $contentType = $this->ContentType;
+ }
+ if($encoding == '') {
+ $encoding = $this->Encoding;
+ }
+ $result .= $this->TextLine('--' . $boundary);
+ $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet);
+ $result .= $this->LE;
+ $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
+ $result .= $this->LE;
+
+ return $result;
+ }
+
+ /**
+ * Returns the end of a message boundary.
+ * @access protected
+ * @param string $boundary
+ * @return string
+ */
+ protected function EndBoundary($boundary) {
+ return $this->LE . '--' . $boundary . '--' . $this->LE;
+ }
+
+ /**
+ * Sets the message type.
+ * @access protected
+ * @return void
+ */
+ protected function SetMessageType() {
+ $this->message_type = array();
+ if($this->AlternativeExists()) $this->message_type[] = "alt";
+ if($this->InlineImageExists()) $this->message_type[] = "inline";
+ if($this->AttachmentExists()) $this->message_type[] = "attach";
+ $this->message_type = implode("_", $this->message_type);
+ if($this->message_type == "") $this->message_type = "plain";
+ }
+
+ /**
+ * Returns a formatted header line.
+ * @access public
+ * @param string $name
+ * @param string $value
+ * @return string
+ */
+ public function HeaderLine($name, $value) {
+ return $name . ': ' . $value . $this->LE;
+ }
+
+ /**
+ * Returns a formatted mail line.
+ * @access public
+ * @param string $value
+ * @return string
+ */
+ public function TextLine($value) {
+ return $value . $this->LE;
+ }
+
+ /////////////////////////////////////////////////
+ // CLASS METHODS, ATTACHMENTS
+ /////////////////////////////////////////////////
+
+ /**
+ * Adds an attachment from a path on the filesystem.
+ * Returns false if the file could not be found
+ * or accessed.
+ * @param string $path Path to the attachment.
+ * @param string $name Overrides the attachment name.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File extension (MIME) type.
+ * @throws phpmailerException
+ * @return bool
+ */
+ public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
+ try {
+ if ( !@is_file($path) ) {
+ throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
+ }
+ $filename = basename($path);
+ if ( $name == '' ) {
+ $name = $filename;
+ }
+
+ $this->attachment[] = array(
+ 0 => $path,
+ 1 => $filename,
+ 2 => $name,
+ 3 => $encoding,
+ 4 => $type,
+ 5 => false, // isStringAttachment
+ 6 => 'attachment',
+ 7 => 0
+ );
+
+ } catch (phpmailerException $e) {
+ $this->SetError($e->getMessage());
+ if ($this->exceptions) {
+ throw $e;
+ }
+ if ($this->SMTPDebug) {
+ $this->edebug($e->getMessage()."\n");
+ }
+ if ( $e->getCode() == self::STOP_CRITICAL ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return the current array of attachments
+ * @return array
+ */
+ public function GetAttachments() {
+ return $this->attachment;
+ }
+
+ /**
+ * Attaches all fs, string, and binary attachments to the message.
+ * Returns an empty string on failure.
+ * @access protected
+ * @param string $disposition_type
+ * @param string $boundary
+ * @return string
+ */
+ protected function AttachAll($disposition_type, $boundary) {
+ // Return text of body
+ $mime = array();
+ $cidUniq = array();
+ $incl = array();
+
+ // Add all attachments
+ foreach ($this->attachment as $attachment) {
+ // CHECK IF IT IS A VALID DISPOSITION_FILTER
+ if($attachment[6] == $disposition_type) {
+ // Check for string attachment
+ $string = '';
+ $path = '';
+ $bString = $attachment[5];
+ if ($bString) {
+ $string = $attachment[0];
+ } else {
+ $path = $attachment[0];
+ }
+
+ $inclhash = md5(serialize($attachment));
+ if (in_array($inclhash, $incl)) { continue; }
+ $incl[] = $inclhash;
+ $filename = $attachment[1];
+ $name = $attachment[2];
+ $encoding = $attachment[3];
+ $type = $attachment[4];
+ $disposition = $attachment[6];
+ $cid = $attachment[7];
+ if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
+ $cidUniq[$cid] = true;
+
+ $mime[] = sprintf("--%s%s", $boundary, $this->LE);
+ $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
+ $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
+
+ if($disposition == 'inline') {
+ $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
+ }
+
+ $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
+
+ // Encode as string attachment
+ if($bString) {
+ $mime[] = $this->EncodeString($string, $encoding);
+ if($this->IsError()) {
+ return '';
+ }
+ $mime[] = $this->LE.$this->LE;
+ } else {
+ $mime[] = $this->EncodeFile($path, $encoding);
+ if($this->IsError()) {
+ return '';
+ }
+ $mime[] = $this->LE.$this->LE;
+ }
+ }
+ }
+
+ $mime[] = sprintf("--%s--%s", $boundary, $this->LE);
+
+ return implode("", $mime);
+ }
+
+ /**
+ * Encodes attachment in requested format.
+ * Returns an empty string on failure.
+ * @param string $path The full path to the file
+ * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+ * @throws phpmailerException
+ * @see EncodeFile()
+ * @access protected
+ * @return string
+ */
+ protected function EncodeFile($path, $encoding = 'base64') {
+ try {
+ if (!is_readable($path)) {
+ throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
+ }
+ // if (!function_exists('get_magic_quotes')) {
+ // function get_magic_quotes() {
+ // return false;
+ // }
+ // }
+ $magic_quotes = get_magic_quotes_runtime();
+ if ($magic_quotes) {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ set_magic_quotes_runtime(0);
+ } else {
+ ini_set('magic_quotes_runtime', 0);
+ }
+ }
+ $file_buffer = file_get_contents($path);
+ $file_buffer = $this->EncodeString($file_buffer, $encoding);
+ if ($magic_quotes) {
+ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
+ set_magic_quotes_runtime($magic_quotes);
+ } else {
+ ini_set('magic_quotes_runtime', $magic_quotes);
+ }
+ }
+ return $file_buffer;
+ } catch (Exception $e) {
+ $this->SetError($e->getMessage());
+ return '';
+ }
+ }
+
+ /**
+ * Encodes string to requested format.
+ * Returns an empty string on failure.
+ * @param string $str The text to encode
+ * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+ * @access public
+ * @return string
+ */
+ public function EncodeString($str, $encoding = 'base64') {
+ $encoded = '';
+ switch(strtolower($encoding)) {
+ case 'base64':
+ $encoded = chunk_split(base64_encode($str), 76, $this->LE);
+ break;
+ case '7bit':
+ case '8bit':
+ $encoded = $this->FixEOL($str);
+ //Make sure it ends with a line break
+ if (substr($encoded, -(strlen($this->LE))) != $this->LE)
+ $encoded .= $this->LE;
+ break;
+ case 'binary':
+ $encoded = $str;
+ break;
+ case 'quoted-printable':
+ $encoded = $this->EncodeQP($str);
+ break;
+ default:
+ $this->SetError($this->Lang('encoding') . $encoding);
+ break;
+ }
+ return $encoded;
+ }
+
+ /**
+ * Encode a header string to best (shortest) of Q, B, quoted or none.
+ * @access public
+ * @param string $str
+ * @param string $position
+ * @return string
+ */
+ public function EncodeHeader($str, $position = 'text') {
+ $x = 0;
+
+ switch (strtolower($position)) {
+ case 'phrase':
+ if (!preg_match('/[\200-\377]/', $str)) {
+ // Can't use addslashes as we don't know what value has magic_quotes_sybase
+ $encoded = addcslashes($str, "\0..\37\177\\\"");
+ if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
+ return ($encoded);
+ } else {
+ return ("\"$encoded\"");
+ }
+ }
+ $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
+ break;
+ case 'comment':
+ $x = preg_match_all('/[()"]/', $str, $matches);
+ // Fall-through
+ case 'text':
+ default:
+ $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
+ break;
+ }
+
+ if ($x == 0) {
+ return ($str);
+ }
+
+ $maxlen = 75 - 7 - strlen($this->CharSet);
+ // Try to select the encoding which should produce the shortest output
+ if (strlen($str)/3 < $x) {
+ $encoding = 'B';
+ if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
+ // Use a custom function which correctly encodes and wraps long
+ // multibyte strings without breaking lines within a character
+ $encoded = $this->Base64EncodeWrapMB($str, "\n");
+ } else {
+ $encoded = base64_encode($str);
+ $maxlen -= $maxlen % 4;
+ $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
+ }
+ } else {
+ $encoding = 'Q';
+ $encoded = $this->EncodeQ($str, $position);
+ $encoded = $this->WrapText($encoded, $maxlen, true);
+ $encoded = str_replace('='.self::CRLF, "\n", trim($encoded));
+ }
+
+ $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
+ $encoded = trim(str_replace("\n", $this->LE, $encoded));
+
+ return $encoded;
+ }
+
+ /**
+ * Checks if a string contains multibyte characters.
+ * @access public
+ * @param string $str multi-byte text to wrap encode
+ * @return bool
+ */
+ public function HasMultiBytes($str) {
+ if (function_exists('mb_strlen')) {
+ return (strlen($str) > mb_strlen($str, $this->CharSet));
+ } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
+ return false;
+ }
+ }
+
+ /**
+ * Correctly encodes and wraps long multibyte strings for mail headers
+ * without breaking lines within a character.
+ * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
+ * @access public
+ * @param string $str multi-byte text to wrap encode
+ * @param string $lf string to use as linefeed/end-of-line
+ * @return string
+ */
+ public function Base64EncodeWrapMB($str, $lf=null) {
+ $start = "=?".$this->CharSet."?B?";
+ $end = "?=";
+ $encoded = "";
+ if ($lf === null) {
+ $lf = $this->LE;
+ }
+
+ $mb_length = mb_strlen($str, $this->CharSet);
+ // Each line must have length <= 75, including $start and $end
+ $length = 75 - strlen($start) - strlen($end);
+ // Average multi-byte ratio
+ $ratio = $mb_length / strlen($str);
+ // Base64 has a 4:3 ratio
+ $offset = $avgLength = floor($length * $ratio * .75);
+
+ for ($i = 0; $i < $mb_length; $i += $offset) {
+ $lookBack = 0;
+
+ do {
+ $offset = $avgLength - $lookBack;
+ $chunk = mb_substr($str, $i, $offset, $this->CharSet);
+ $chunk = base64_encode($chunk);
+ $lookBack++;
+ }
+ while (strlen($chunk) > $length);
+
+ $encoded .= $chunk . $lf;
+ }
+
+ // Chomp the last linefeed
+ $encoded = substr($encoded, 0, -strlen($lf));
+ return $encoded;
+ }
+
+ /**
+ * Encode string to quoted-printable.
+ * Only uses standard PHP, slow, but will always work
+ * @access public
+ * @param string $input
+ * @param integer $line_max Number of chars allowed on a line before wrapping
+ * @param bool $space_conv
+ * @internal param string $string the text to encode
+ * @return string
+ */
+ public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
+ $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
+ $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
+ $eol = "\r\n";
+ $escape = '=';
+ $output = '';
+ while( list(, $line) = each($lines) ) {
+ $linlen = strlen($line);
+ $newline = '';
+ for($i = 0; $i < $linlen; $i++) {
+ $c = substr( $line, $i, 1 );
+ $dec = ord( $c );
+ if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
+ $c = '=2E';
+ }
+ if ( $dec == 32 ) {
+ if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
+ $c = '=20';
+ } else if ( $space_conv ) {
+ $c = '=20';
+ }
+ } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
+ $h2 = (integer)floor($dec/16);
+ $h1 = (integer)floor($dec%16);
+ $c = $escape.$hex[$h2].$hex[$h1];
+ }
+ if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
+ $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
+ $newline = '';
+ // check if newline first character will be point or not
+ if ( $dec == 46 ) {
+ $c = '=2E';
+ }
+ }
+ $newline .= $c;
+ } // end of for
+ $output .= $newline.$eol;
+ } // end of while
+ return $output;
+ }
+
+ /**
+ * Encode string to RFC2045 (6.7) quoted-printable format
+ * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
+ * Also results in same content as you started with after decoding
+ * @see EncodeQPphp()
+ * @access public
+ * @param string $string the text to encode
+ * @param integer $line_max Number of chars allowed on a line before wrapping
+ * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
+ * @return string
+ * @author Marcus Bointon
+ */
+ public function EncodeQP($string, $line_max = 76, $space_conv = false) {
+ if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
+ return quoted_printable_encode($string);
+ }
+ $filters = stream_get_filters();
+ if (!in_array('convert.*', $filters)) { //Got convert stream filter?
+ return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
+ }
+ $fp = fopen('php://temp/', 'r+');
+ $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
+ $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
+ $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
+ fputs($fp, $string);
+ rewind($fp);
+ $out = stream_get_contents($fp);
+ stream_filter_remove($s);
+ $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
+ fclose($fp);
+ return $out;
+ }
+
+ /**
+ * Encode string to q encoding.
+ * @link http://tools.ietf.org/html/rfc2047
+ * @param string $str the text to encode
+ * @param string $position Where the text is going to be used, see the RFC for what that means
+ * @access public
+ * @return string
+ */
+ public function EncodeQ($str, $position = 'text') {
+ //There should not be any EOL in the string
+ $pattern="";
+ $encoded = str_replace(array("\r", "\n"), '', $str);
+ switch (strtolower($position)) {
+ case 'phrase':
+ $pattern = '^A-Za-z0-9!*+\/ -';
+ break;
+
+ case 'comment':
+ $pattern = '\(\)"';
+ //note that we dont break here!
+ //for this reason we build the $pattern withoud including delimiters and []
+
+ case 'text':
+ default:
+ //Replace every high ascii, control =, ? and _ characters
+ //We put \075 (=) as first value to make sure it's the first one in being converted, preventing double encode
+ $pattern = '\075\000-\011\013\014\016-\037\077\137\177-\377' . $pattern;
+ break;
+ }
+
+ if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
+ foreach (array_unique($matches[0]) as $char) {
+ $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
+ }
+ }
+
+ //Replace every spaces to _ (more readable than =20)
+ return str_replace(' ', '_', $encoded);
+}
+
+
+ /**
+ * Adds a string or binary attachment (non-filesystem) to the list.
+ * This method can be used to attach ascii or binary data,
+ * such as a BLOB record from a database.
+ * @param string $string String attachment data.
+ * @param string $filename Name of the attachment.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File extension (MIME) type.
+ * @return void
+ */
+ public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
+ // Append to $attachment array
+ $this->attachment[] = array(
+ 0 => $string,
+ 1 => $filename,
+ 2 => basename($filename),
+ 3 => $encoding,
+ 4 => $type,
+ 5 => true, // isStringAttachment
+ 6 => 'attachment',
+ 7 => 0
+ );
+ }
+
+ /**
+ * Adds an embedded attachment. This can include images, sounds, and
+ * just about any other document. Make sure to set the $type to an
+ * image type. For JPEG images use "image/jpeg" and for GIF images
+ * use "image/gif".
+ * @param string $path Path to the attachment.
+ * @param string $cid Content ID of the attachment. Use this to identify
+ * the Id for accessing the image in an HTML form.
+ * @param string $name Overrides the attachment name.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File extension (MIME) type.
+ * @return bool
+ */
+ public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
+
+ if ( !@is_file($path) ) {
+ $this->SetError($this->Lang('file_access') . $path);
+ return false;
+ }
+
+ $filename = basename($path);
+ if ( $name == '' ) {
+ $name = $filename;
+ }
+
+ // Append to $attachment array
+ $this->attachment[] = array(
+ 0 => $path,
+ 1 => $filename,
+ 2 => $name,
+ 3 => $encoding,
+ 4 => $type,
+ 5 => false, // isStringAttachment
+ 6 => 'inline',
+ 7 => $cid
+ );
+
+ return true;
+ }
+
+ /**
+ * Adds an embedded stringified attachment. This can include images, sounds, and
+ * just about any other document. Make sure to set the $type to an
+ * image type. For JPEG images use "image/jpeg" and for GIF images
+ * use "image/gif".
+ * @param string $string The attachment.
+ * @param string $cid Content ID of the attachment. Use this to identify
+ * the Id for accessing the image in an HTML form.
+ * @param string $name Overrides the attachment name.
+ * @param string $encoding File encoding (see $Encoding).
+ * @param string $type File extension (MIME) type.
+ * @return bool
+ */
+ public function AddStringEmbeddedImage($string, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
+ // Append to $attachment array
+ $this->attachment[] = array(
+ 0 => $string,
+ 1 => $name,
+ 2 => $name,
+ 3 => $encoding,
+ 4 => $type,
+ 5 => true, // isStringAttachment
+ 6 => 'inline',
+ 7 => $cid
+ );
+ }
+
+ /**
+ * Returns true if an inline attachment is present.
+ * @access public
+ * @return bool
+ */
+ public function InlineImageExists() {
+ foreach($this->attachment as $attachment) {
+ if ($attachment[6] == 'inline') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if an attachment (non-inline) is present.
+ * @return bool
+ */
+ public function AttachmentExists() {
+ foreach($this->attachment as $attachment) {
+ if ($attachment[6] == 'attachment') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Does this message have an alternative body set?
+ * @return bool
+ */
+ public function AlternativeExists() {
+ return !empty($this->AltBody);
+ }
+
+ /////////////////////////////////////////////////
+ // CLASS METHODS, MESSAGE RESET
+ /////////////////////////////////////////////////
+
+ /**
+ * Clears all recipients assigned in the TO array. Returns void.
+ * @return void
+ */
+ public function ClearAddresses() {
+ foreach($this->to as $to) {
+ unset($this->all_recipients[strtolower($to[0])]);
+ }
+ $this->to = array();
+ }
+
+ /**
+ * Clears all recipients assigned in the CC array. Returns void.
+ * @return void
+ */
+ public function ClearCCs() {
+ foreach($this->cc as $cc) {
+ unset($this->all_recipients[strtolower($cc[0])]);
+ }
+ $this->cc = array();
+ }
+
+ /**
+ * Clears all recipients assigned in the BCC array. Returns void.
+ * @return void
+ */
+ public function ClearBCCs() {
+ foreach($this->bcc as $bcc) {
+ unset($this->all_recipients[strtolower($bcc[0])]);
+ }
+ $this->bcc = array();
+ }
+
+ /**
+ * Clears all recipients assigned in the ReplyTo array. Returns void.
+ * @return void
+ */
+ public function ClearReplyTos() {
+ $this->ReplyTo = array();
+ }
+
+ /**
+ * Clears all recipients assigned in the TO, CC and BCC
+ * array. Returns void.
+ * @return void
+ */
+ public function ClearAllRecipients() {
+ $this->to = array();
+ $this->cc = array();
+ $this->bcc = array();
+ $this->all_recipients = array();
+ }
+
+ /**
+ * Clears all previously set filesystem, string, and binary
+ * attachments. Returns void.
+ * @return void
+ */
+ public function ClearAttachments() {
+ $this->attachment = array();
+ }
+
+ /**
+ * Clears all custom headers. Returns void.
+ * @return void
+ */
+ public function ClearCustomHeaders() {
+ $this->CustomHeader = array();
+ }
+
+ /////////////////////////////////////////////////
+ // CLASS METHODS, MISCELLANEOUS
+ /////////////////////////////////////////////////
+
+ /**
+ * Adds the error message to the error container.
+ * @access protected
+ * @param string $msg
+ * @return void
+ */
+ protected function SetError($msg) {
+ $this->error_count++;
+ if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
+ $lasterror = $this->smtp->getError();
+ if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
+ $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
+ }
+ }
+ $this->ErrorInfo = $msg;
+ }
+
+ /**
+ * Returns the proper RFC 822 formatted date.
+ * @access public
+ * @return string
+ * @static
+ */
+ public static function RFCDate() {
+ $tz = date('Z');
+ $tzs = ($tz < 0) ? '-' : '+';
+ $tz = abs($tz);
+ $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
+ $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
+
+ return $result;
+ }
+
+ /**
+ * Returns the server hostname or 'localhost.localdomain' if unknown.
+ * @access protected
+ * @return string
+ */
+ protected function ServerHostname() {
+ if (!empty($this->Hostname)) {
+ $result = $this->Hostname;
+ } elseif (isset($_SERVER['SERVER_NAME'])) {
+ $result = $_SERVER['SERVER_NAME'];
+ } else {
+ $result = 'localhost.localdomain';
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns a message in the appropriate language.
+ * @access protected
+ * @param string $key
+ * @return string
+ */
+ protected function Lang($key) {
+ if(count($this->language) < 1) {
+ $this->SetLanguage('en'); // set the default language
+ }
+
+ if(isset($this->language[$key])) {
+ return $this->language[$key];
+ } else {
+ return 'Language string failed to load: ' . $key;
+ }
+ }
+
+ /**
+ * Returns true if an error occurred.
+ * @access public
+ * @return bool
+ */
+ public function IsError() {
+ return ($this->error_count > 0);
+ }
+
+ /**
+ * Changes every end of line from CRLF, CR or LF to $this->LE.
+ * @access public
+ * @param string $str String to FixEOL
+ * @return string
+ */
+ public function FixEOL($str) {
+ // condense down to \n
+ $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
+ // Now convert LE as needed
+ if ($this->LE !== "\n") {
+ $nstr = str_replace("\n", $this->LE, $nstr);
+ }
+ return $nstr;
+ }
+
+ /**
+ * Adds a custom header. $name value can be overloaded to contain
+ * both header name and value (name:value)
+ * @access public
+ * @param string $name custom header name
+ * @param string $value header value
+ * @return void
+ */
+ public function AddCustomHeader($name, $value=null) {
+ if ($value === null) {
+ // Value passed in as name:value
+ $this->CustomHeader[] = explode(':', $name, 2);
+ } else {
+ $this->CustomHeader[] = array($name, $value);
+ }
+ }
+
+ /**
+ * Evaluates the message and returns modifications for inline images and backgrounds
+ * @access public
+ * @param string $message Text to be HTML modified
+ * @param string $basedir baseline directory for path
+ * @return string $message
+ */
+ public function MsgHTML($message, $basedir = '') {
+ preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images);
+ if(isset($images[2])) {
+ foreach($images[2] as $i => $url) {
+ // do not change urls for absolute images (thanks to corvuscorax)
+ if (!preg_match('#^[A-z]+://#', $url)) {
+ $filename = basename($url);
+ $directory = dirname($url);
+ if ($directory == '.') {
+ $directory = '';
+ }
+ $cid = 'cid:' . md5($url);
+ $ext = pathinfo($filename, PATHINFO_EXTENSION);
+ $mimeType = self::_mime_types($ext);
+ if ( strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; }
+ if ( strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; }
+ if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($url), $filename, 'base64', $mimeType) ) {
+ $message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"".$cid."\"", $message);
+ }
+ }
+ }
+ }
+ $this->IsHTML(true);
+ $this->Body = $message;
+ if (empty($this->AltBody)) {
+ $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $message)));
+ if (!empty($textMsg)) {
+ $this->AltBody = html_entity_decode($textMsg, ENT_QUOTES, $this->CharSet);
+ }
+ }
+ if (empty($this->AltBody)) {
+ $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
+ }
+ return $message;
+ }
+
+ /**
+ * Gets the MIME type of the embedded or inline image
+ * @param string $ext File extension
+ * @access public
+ * @return string MIME type of ext
+ * @static
+ */
+ public static function _mime_types($ext = '') {
+ $mimes = array(
+ 'xl' => 'application/excel',
+ 'hqx' => 'application/mac-binhex40',
+ 'cpt' => 'application/mac-compactpro',
+ 'bin' => 'application/macbinary',
+ 'doc' => 'application/msword',
+ 'word' => 'application/msword',
+ 'class' => 'application/octet-stream',
+ 'dll' => 'application/octet-stream',
+ 'dms' => 'application/octet-stream',
+ 'exe' => 'application/octet-stream',
+ 'lha' => 'application/octet-stream',
+ 'lzh' => 'application/octet-stream',
+ 'psd' => 'application/octet-stream',
+ 'sea' => 'application/octet-stream',
+ 'so' => 'application/octet-stream',
+ 'oda' => 'application/oda',
+ 'pdf' => 'application/pdf',
+ 'ai' => 'application/postscript',
+ 'eps' => 'application/postscript',
+ 'ps' => 'application/postscript',
+ 'smi' => 'application/smil',
+ 'smil' => 'application/smil',
+ 'mif' => 'application/vnd.mif',
+ 'xls' => 'application/vnd.ms-excel',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'dcr' => 'application/x-director',
+ 'dir' => 'application/x-director',
+ 'dxr' => 'application/x-director',
+ 'dvi' => 'application/x-dvi',
+ 'gtar' => 'application/x-gtar',
+ 'php3' => 'application/x-httpd-php',
+ 'php4' => 'application/x-httpd-php',
+ 'php' => 'application/x-httpd-php',
+ 'phtml' => 'application/x-httpd-php',
+ 'phps' => 'application/x-httpd-php-source',
+ 'js' => 'application/x-javascript',
+ 'swf' => 'application/x-shockwave-flash',
+ 'sit' => 'application/x-stuffit',
+ 'tar' => 'application/x-tar',
+ 'tgz' => 'application/x-tar',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'zip' => 'application/zip',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mpga' => 'audio/mpeg',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rm' => 'audio/x-pn-realaudio',
+ 'rpm' => 'audio/x-pn-realaudio-plugin',
+ 'ra' => 'audio/x-realaudio',
+ 'wav' => 'audio/x-wav',
+ 'bmp' => 'image/bmp',
+ 'gif' => 'image/gif',
+ 'jpeg' => 'image/jpeg',
+ 'jpe' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'png' => 'image/png',
+ 'tiff' => 'image/tiff',
+ 'tif' => 'image/tiff',
+ 'eml' => 'message/rfc822',
+ 'css' => 'text/css',
+ 'html' => 'text/html',
+ 'htm' => 'text/html',
+ 'shtml' => 'text/html',
+ 'log' => 'text/plain',
+ 'text' => 'text/plain',
+ 'txt' => 'text/plain',
+ 'rtx' => 'text/richtext',
+ 'rtf' => 'text/rtf',
+ 'xml' => 'text/xml',
+ 'xsl' => 'text/xml',
+ 'mpeg' => 'video/mpeg',
+ 'mpe' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mov' => 'video/quicktime',
+ 'qt' => 'video/quicktime',
+ 'rv' => 'video/vnd.rn-realvideo',
+ 'avi' => 'video/x-msvideo',
+ 'movie' => 'video/x-sgi-movie'
+ );
+ return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
+ }
+
+ /**
+ * Set (or reset) Class Objects (variables)
+ *
+ * Usage Example:
+ * $page->set('X-Priority', '3');
+ *
+ * @access public
+ * @param string $name Parameter Name
+ * @param mixed $value Parameter Value
+ * NOTE: will not work with arrays, there are no arrays to set/reset
+ * @throws phpmailerException
+ * @return bool
+ * @todo Should this not be using __set() magic function?
+ */
+ public function set($name, $value = '') {
+ try {
+ if (isset($this->$name) ) {
+ $this->$name = $value;
+ } else {
+ throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
+ }
+ } catch (Exception $e) {
+ $this->SetError($e->getMessage());
+ if ($e->getCode() == self::STOP_CRITICAL) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Strips newlines to prevent header injection.
+ * @access public
+ * @param string $str String
+ * @return string
+ */
+ public function SecureHeader($str) {
+ return trim(str_replace(array("\r", "\n"), '', $str));
+ }
+
+ /**
+ * Set the private key file and password to sign the message.
+ *
+ * @access public
+ * @param $cert_filename
+ * @param string $key_filename Parameter File Name
+ * @param string $key_pass Password for private key
+ */
+ public function Sign($cert_filename, $key_filename, $key_pass) {
+ $this->sign_cert_file = $cert_filename;
+ $this->sign_key_file = $key_filename;
+ $this->sign_key_pass = $key_pass;
+ }
+
+ /**
+ * Set the private key file and password to sign the message.
+ *
+ * @access public
+ * @param string $txt
+ * @return string
+ */
+ public function DKIM_QP($txt) {
+ $line = '';
+ for ($i = 0; $i < strlen($txt); $i++) {
+ $ord = ord($txt[$i]);
+ if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
+ $line .= $txt[$i];
+ } else {
+ $line .= "=".sprintf("%02X", $ord);
+ }
+ }
+ return $line;
+ }
+
+ /**
+ * Generate DKIM signature
+ *
+ * @access public
+ * @param string $s Header
+ * @return string
+ */
+ public function DKIM_Sign($s) {
+ $privKeyStr = file_get_contents($this->DKIM_private);
+ if ($this->DKIM_passphrase != '') {
+ $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
+ } else {
+ $privKey = $privKeyStr;
+ }
+ if (openssl_sign($s, $signature, $privKey)) {
+ return base64_encode($signature);
+ }
+ return '';
+ }
+
+ /**
+ * Generate DKIM Canonicalization Header
+ *
+ * @access public
+ * @param string $s Header
+ * @return string
+ */
+ public function DKIM_HeaderC($s) {
+ $s = preg_replace("/\r\n\s+/", " ", $s);
+ $lines = explode("\r\n", $s);
+ foreach ($lines as $key => $line) {
+ list($heading, $value) = explode(":", $line, 2);
+ $heading = strtolower($heading);
+ $value = preg_replace("/\s+/", " ", $value) ; // Compress useless spaces
+ $lines[$key] = $heading.":".trim($value) ; // Don't forget to remove WSP around the value
+ }
+ $s = implode("\r\n", $lines);
+ return $s;
+ }
+
+ /**
+ * Generate DKIM Canonicalization Body
+ *
+ * @access public
+ * @param string $body Message Body
+ * @return string
+ */
+ public function DKIM_BodyC($body) {
+ if ($body == '') return "\r\n";
+ // stabilize line endings
+ $body = str_replace("\r\n", "\n", $body);
+ $body = str_replace("\n", "\r\n", $body);
+ // END stabilize line endings
+ while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
+ $body = substr($body, 0, strlen($body) - 2);
+ }
+ return $body;
+ }
+
+ /**
+ * Create the DKIM header, body, as new header
+ *
+ * @access public
+ * @param string $headers_line Header lines
+ * @param string $subject Subject
+ * @param string $body Body
+ * @return string
+ */
+ public function DKIM_Add($headers_line, $subject, $body) {
+ $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
+ $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
+ $DKIMquery = 'dns/txt'; // Query method
+ $DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
+ $subject_header = "Subject: $subject";
+ $headers = explode($this->LE, $headers_line);
+ $from_header = "";
+ $to_header = "";
+ foreach($headers as $header) {
+ if (strpos($header, 'From:') === 0) {
+ $from_header = $header;
+ } elseif (strpos($header, 'To:') === 0) {
+ $to_header = $header;
+ }
+ }
+ $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
+ $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
+ $subject = str_replace('|', '=7C', $this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
+ $body = $this->DKIM_BodyC($body);
+ $DKIMlen = strlen($body) ; // Length of body
+ $DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
+ $ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
+ $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
+ "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
+ "\th=From:To:Subject;\r\n".
+ "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
+ "\tz=$from\r\n".
+ "\t|$to\r\n".
+ "\t|$subject;\r\n".
+ "\tbh=" . $DKIMb64 . ";\r\n".
+ "\tb=";
+ $toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
+ $signed = $this->DKIM_Sign($toSign);
+ return "X-PHPMAILER-DKIM: code.google.com/a/apache-extras.org/p/phpmailer/\r\n".$dkimhdrs.$signed."\r\n";
+ }
+
+ /**
+ * Perform callback
+ * @param boolean $isSent
+ * @param string $to
+ * @param string $cc
+ * @param string $bcc
+ * @param string $subject
+ * @param string $body
+ * @param string $from
+ */
+ protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from=null) {
+ if (!empty($this->action_function) && is_callable($this->action_function)) {
+ $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
+ call_user_func_array($this->action_function, $params);
+ }
+ }
+}
+
+/**
+ * Exception handler for PHPMailer
+ * @package PHPMailer
+ */
+class phpmailerException extends Exception {
+ /**
+ * Prettify error message output
+ * @return string
+ */
+ public function errorMessage() {
+ $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
+ return $errorMsg;
+ }
+}
+?>
diff --git a/src/wp-includes/class-pop3.php b/src/wp-includes/class-pop3.php
new file mode 100644
index 0000000000..d0455d7ef6
--- /dev/null
+++ b/src/wp-includes/class-pop3.php
@@ -0,0 +1,652 @@
+<?php
+/**
+ * mail_fetch/setup.php
+ *
+ * Copyright (c) 1999-2011 CDI (cdi@thewebmasters.net) All Rights Reserved
+ * Modified by Philippe Mingo 2001-2009 mingo@rotedic.com
+ * An RFC 1939 compliant wrapper class for the POP3 protocol.
+ *
+ * Licensed under the GNU GPL. For full terms see the file COPYING.
+ *
+ * POP3 class
+ *
+ * @copyright 1999-2011 The SquirrelMail Project Team
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License
+ * @package plugins
+ * @subpackage mail_fetch
+ */
+
+class POP3 {
+ var $ERROR = ''; // Error string.
+
+ var $TIMEOUT = 60; // Default timeout before giving up on a
+ // network operation.
+
+ var $COUNT = -1; // Mailbox msg count
+
+ var $BUFFER = 512; // Socket buffer for socket fgets() calls.
+ // Per RFC 1939 the returned line a POP3
+ // server can send is 512 bytes.
+
+ var $FP = ''; // The connection to the server's
+ // file descriptor
+
+ var $MAILSERVER = ''; // Set this to hard code the server name
+
+ var $DEBUG = FALSE; // set to true to echo pop3
+ // commands and responses to error_log
+ // this WILL log passwords!
+
+ var $BANNER = ''; // Holds the banner returned by the
+ // pop server - used for apop()
+
+ var $ALLOWAPOP = FALSE; // Allow or disallow apop()
+ // This must be set to true
+ // manually
+
+ function POP3 ( $server = '', $timeout = '' ) {
+ settype($this->BUFFER,"integer");
+ if( !empty($server) ) {
+ // Do not allow programs to alter MAILSERVER
+ // if it is already specified. They can get around
+ // this if they -really- want to, so don't count on it.
+ if(empty($this->MAILSERVER))
+ $this->MAILSERVER = $server;
+ }
+ if(!empty($timeout)) {
+ settype($timeout,"integer");
+ $this->TIMEOUT = $timeout;
+ if (!ini_get('safe_mode'))
+ set_time_limit($timeout);
+ }
+ return true;
+ }
+
+ function update_timer () {
+ if (!ini_get('safe_mode'))
+ set_time_limit($this->TIMEOUT);
+ return true;
+ }
+
+ function connect ($server, $port = 110) {
+ // Opens a socket to the specified server. Unless overridden,
+ // port defaults to 110. Returns true on success, false on fail
+
+ // If MAILSERVER is set, override $server with it's value
+
+ if (!isset($port) || !$port) {$port = 110;}
+ if(!empty($this->MAILSERVER))
+ $server = $this->MAILSERVER;
+
+ if(empty($server)){
+ $this->ERROR = "POP3 connect: " . _("No server specified");
+ unset($this->FP);
+ return false;
+ }
+
+ $fp = @fsockopen("$server", $port, $errno, $errstr);
+
+ if(!$fp) {
+ $this->ERROR = "POP3 connect: " . _("Error ") . "[$errno] [$errstr]";
+ unset($this->FP);
+ return false;
+ }
+
+ socket_set_blocking($fp,-1);
+ $this->update_timer();
+ $reply = fgets($fp,$this->BUFFER);
+ $reply = $this->strip_clf($reply);
+ if($this->DEBUG)
+ error_log("POP3 SEND [connect: $server] GOT [$reply]",0);
+ if(!$this->is_ok($reply)) {
+ $this->ERROR = "POP3 connect: " . _("Error ") . "[$reply]";
+ unset($this->FP);
+ return false;
+ }
+ $this->FP = $fp;
+ $this->BANNER = $this->parse_banner($reply);
+ return true;
+ }
+
+ function user ($user = "") {
+ // Sends the USER command, returns true or false
+
+ if( empty($user) ) {
+ $this->ERROR = "POP3 user: " . _("no login ID submitted");
+ return false;
+ } elseif(!isset($this->FP)) {
+ $this->ERROR = "POP3 user: " . _("connection not established");
+ return false;
+ } else {
+ $reply = $this->send_cmd("USER $user");
+ if(!$this->is_ok($reply)) {
+ $this->ERROR = "POP3 user: " . _("Error ") . "[$reply]";
+ return false;
+ } else
+ return true;
+ }
+ }
+
+ function pass ($pass = "") {
+ // Sends the PASS command, returns # of msgs in mailbox,
+ // returns false (undef) on Auth failure
+
+ if(empty($pass)) {
+ $this->ERROR = "POP3 pass: " . _("No password submitted");
+ return false;
+ } elseif(!isset($this->FP)) {
+ $this->ERROR = "POP3 pass: " . _("connection not established");
+ return false;
+ } else {
+ $reply = $this->send_cmd("PASS $pass");
+ if(!$this->is_ok($reply)) {
+ $this->ERROR = "POP3 pass: " . _("Authentication failed") . " [$reply]";
+ $this->quit();
+ return false;
+ } else {
+ // Auth successful.
+ $count = $this->last("count");
+ $this->COUNT = $count;
+ return $count;
+ }
+ }
+ }
+
+ function apop ($login,$pass) {
+ // Attempts an APOP login. If this fails, it'll
+ // try a standard login. YOUR SERVER MUST SUPPORT
+ // THE USE OF THE APOP COMMAND!
+ // (apop is optional per rfc1939)
+
+ if(!isset($this->FP)) {
+ $this->ERROR = "POP3 apop: " . _("No connection to server");
+ return false;
+ } elseif(!$this->ALLOWAPOP) {
+ $retVal = $this->login($login,$pass);
+ return $retVal;
+ } elseif(empty($login)) {
+ $this->ERROR = "POP3 apop: " . _("No login ID submitted");
+ return false;
+ } elseif(empty($pass)) {
+ $this->ERROR = "POP3 apop: " . _("No password submitted");
+ return false;
+ } else {
+ $banner = $this->BANNER;
+ if( (!$banner) or (empty($banner)) ) {
+ $this->ERROR = "POP3 apop: " . _("No server banner") . ' - ' . _("abort");
+ $retVal = $this->login($login,$pass);
+ return $retVal;
+ } else {
+ $AuthString = $banner;
+ $AuthString .= $pass;
+ $APOPString = md5($AuthString);
+ $cmd = "APOP $login $APOPString";
+ $reply = $this->send_cmd($cmd);
+ if(!$this->is_ok($reply)) {
+ $this->ERROR = "POP3 apop: " . _("apop authentication failed") . ' - ' . _("abort");
+ $retVal = $this->login($login,$pass);
+ return $retVal;
+ } else {
+ // Auth successful.
+ $count = $this->last("count");
+ $this->COUNT = $count;
+ return $count;
+ }
+ }
+ }
+ }
+
+ function login ($login = "", $pass = "") {
+ // Sends both user and pass. Returns # of msgs in mailbox or
+ // false on failure (or -1, if the error occurs while getting
+ // the number of messages.)
+
+ if( !isset($this->FP) ) {
+ $this->ERROR = "POP3 login: " . _("No connection to server");
+ return false;
+ } else {
+ $fp = $this->FP;
+ if( !$this->user( $login ) ) {
+ // Preserve the error generated by user()
+ return false;
+ } else {
+ $count = $this->pass($pass);
+ if( (!$count) || ($count == -1) ) {
+ // Preserve the error generated by last() and pass()
+ return false;
+ } else
+ return $count;
+ }
+ }
+ }
+
+ function top ($msgNum, $numLines = "0") {
+ // Gets the header and first $numLines of the msg body
+ // returns data in an array with each returned line being
+ // an array element. If $numLines is empty, returns
+ // only the header information, and none of the body.
+
+ if(!isset($this->FP)) {
+ $this->ERROR = "POP3 top: " . _("No connection to server");
+ return false;
+ }
+ $this->update_timer();
+
+ $fp = $this->FP;
+ $buffer = $this->BUFFER;
+ $cmd = "TOP $msgNum $numLines";
+ fwrite($fp, "TOP $msgNum $numLines\r\n");
+ $reply = fgets($fp, $buffer);
+ $reply = $this->strip_clf($reply);
+ if($this->DEBUG) {
+ @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
+ }
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 top: " . _("Error ") . "[$reply]";
+ return false;
+ }
+
+ $count = 0;
+ $MsgArray = array();
+
+ $line = fgets($fp,$buffer);
+ while ( !preg_match('/^\.\r\n/',$line))
+ {
+ $MsgArray[$count] = $line;
+ $count++;
+ $line = fgets($fp,$buffer);
+ if(empty($line)) { break; }
+ }
+
+ return $MsgArray;
+ }
+
+ function pop_list ($msgNum = "") {
+ // If called with an argument, returns that msgs' size in octets
+ // No argument returns an associative array of undeleted
+ // msg numbers and their sizes in octets
+
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 pop_list: " . _("No connection to server");
+ return false;
+ }
+ $fp = $this->FP;
+ $Total = $this->COUNT;
+ if( (!$Total) or ($Total == -1) )
+ {
+ return false;
+ }
+ if($Total == 0)
+ {
+ return array("0","0");
+ // return -1; // mailbox empty
+ }
+
+ $this->update_timer();
+
+ if(!empty($msgNum))
+ {
+ $cmd = "LIST $msgNum";
+ fwrite($fp,"$cmd\r\n");
+ $reply = fgets($fp,$this->BUFFER);
+ $reply = $this->strip_clf($reply);
+ if($this->DEBUG) {
+ @error_log("POP3 SEND [$cmd] GOT [$reply]",0);
+ }
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
+ return false;
+ }
+ list($junk,$num,$size) = preg_split('/\s+/',$reply);
+ return $size;
+ }
+ $cmd = "LIST";
+ $reply = $this->send_cmd($cmd);
+ if(!$this->is_ok($reply))
+ {
+ $reply = $this->strip_clf($reply);
+ $this->ERROR = "POP3 pop_list: " . _("Error ") . "[$reply]";
+ return false;
+ }
+ $MsgArray = array();
+ $MsgArray[0] = $Total;
+ for($msgC=1;$msgC <= $Total; $msgC++)
+ {
+ if($msgC > $Total) { break; }
+ $line = fgets($fp,$this->BUFFER);
+ $line = $this->strip_clf($line);
+ if(strpos($line, '.') === 0)
+ {
+ $this->ERROR = "POP3 pop_list: " . _("Premature end of list");
+ return false;
+ }
+ list($thisMsg,$msgSize) = preg_split('/\s+/',$line);
+ settype($thisMsg,"integer");
+ if($thisMsg != $msgC)
+ {
+ $MsgArray[$msgC] = "deleted";
+ }
+ else
+ {
+ $MsgArray[$msgC] = $msgSize;
+ }
+ }
+ return $MsgArray;
+ }
+
+ function get ($msgNum) {
+ // Retrieve the specified msg number. Returns an array
+ // where each line of the msg is an array element.
+
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 get: " . _("No connection to server");
+ return false;
+ }
+
+ $this->update_timer();
+
+ $fp = $this->FP;
+ $buffer = $this->BUFFER;
+ $cmd = "RETR $msgNum";
+ $reply = $this->send_cmd($cmd);
+
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 get: " . _("Error ") . "[$reply]";
+ return false;
+ }
+
+ $count = 0;
+ $MsgArray = array();
+
+ $line = fgets($fp,$buffer);
+ while ( !preg_match('/^\.\r\n/',$line))
+ {
+ if ( $line{0} == '.' ) { $line = substr($line,1); }
+ $MsgArray[$count] = $line;
+ $count++;
+ $line = fgets($fp,$buffer);
+ if(empty($line)) { break; }
+ }
+ return $MsgArray;
+ }
+
+ function last ( $type = "count" ) {
+ // Returns the highest msg number in the mailbox.
+ // returns -1 on error, 0+ on success, if type != count
+ // results in a popstat() call (2 element array returned)
+
+ $last = -1;
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 last: " . _("No connection to server");
+ return $last;
+ }
+
+ $reply = $this->send_cmd("STAT");
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 last: " . _("Error ") . "[$reply]";
+ return $last;
+ }
+
+ $Vars = preg_split('/\s+/',$reply);
+ $count = $Vars[1];
+ $size = $Vars[2];
+ settype($count,"integer");
+ settype($size,"integer");
+ if($type != "count")
+ {
+ return array($count,$size);
+ }
+ return $count;
+ }
+
+ function reset () {
+ // Resets the status of the remote server. This includes
+ // resetting the status of ALL msgs to not be deleted.
+ // This method automatically closes the connection to the server.
+
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 reset: " . _("No connection to server");
+ return false;
+ }
+ $reply = $this->send_cmd("RSET");
+ if(!$this->is_ok($reply))
+ {
+ // The POP3 RSET command -never- gives a -ERR
+ // response - if it ever does, something truely
+ // wild is going on.
+
+ $this->ERROR = "POP3 reset: " . _("Error ") . "[$reply]";
+ @error_log("POP3 reset: ERROR [$reply]",0);
+ }
+ $this->quit();
+ return true;
+ }
+
+ function send_cmd ( $cmd = "" )
+ {
+ // Sends a user defined command string to the
+ // POP server and returns the results. Useful for
+ // non-compliant or custom POP servers.
+ // Do NOT includ the \r\n as part of your command
+ // string - it will be appended automatically.
+
+ // The return value is a standard fgets() call, which
+ // will read up to $this->BUFFER bytes of data, until it
+ // encounters a new line, or EOF, whichever happens first.
+
+ // This method works best if $cmd responds with only
+ // one line of data.
+
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 send_cmd: " . _("No connection to server");
+ return false;
+ }
+
+ if(empty($cmd))
+ {
+ $this->ERROR = "POP3 send_cmd: " . _("Empty command string");
+ return "";
+ }
+
+ $fp = $this->FP;
+ $buffer = $this->BUFFER;
+ $this->update_timer();
+ fwrite($fp,"$cmd\r\n");
+ $reply = fgets($fp,$buffer);
+ $reply = $this->strip_clf($reply);
+ if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
+ return $reply;
+ }
+
+ function quit() {
+ // Closes the connection to the POP3 server, deleting
+ // any msgs marked as deleted.
+
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 quit: " . _("connection does not exist");
+ return false;
+ }
+ $fp = $this->FP;
+ $cmd = "QUIT";
+ fwrite($fp,"$cmd\r\n");
+ $reply = fgets($fp,$this->BUFFER);
+ $reply = $this->strip_clf($reply);
+ if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
+ fclose($fp);
+ unset($this->FP);
+ return true;
+ }
+
+ function popstat () {
+ // Returns an array of 2 elements. The number of undeleted
+ // msgs in the mailbox, and the size of the mbox in octets.
+
+ $PopArray = $this->last("array");
+
+ if($PopArray == -1) { return false; }
+
+ if( (!$PopArray) or (empty($PopArray)) )
+ {
+ return false;
+ }
+ return $PopArray;
+ }
+
+ function uidl ($msgNum = "")
+ {
+ // Returns the UIDL of the msg specified. If called with
+ // no arguments, returns an associative array where each
+ // undeleted msg num is a key, and the msg's uidl is the element
+ // Array element 0 will contain the total number of msgs
+
+ if(!isset($this->FP)) {
+ $this->ERROR = "POP3 uidl: " . _("No connection to server");
+ return false;
+ }
+
+ $fp = $this->FP;
+ $buffer = $this->BUFFER;
+
+ if(!empty($msgNum)) {
+ $cmd = "UIDL $msgNum";
+ $reply = $this->send_cmd($cmd);
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
+ return false;
+ }
+ list ($ok,$num,$myUidl) = preg_split('/\s+/',$reply);
+ return $myUidl;
+ } else {
+ $this->update_timer();
+
+ $UIDLArray = array();
+ $Total = $this->COUNT;
+ $UIDLArray[0] = $Total;
+
+ if ($Total < 1)
+ {
+ return $UIDLArray;
+ }
+ $cmd = "UIDL";
+ fwrite($fp, "UIDL\r\n");
+ $reply = fgets($fp, $buffer);
+ $reply = $this->strip_clf($reply);
+ if($this->DEBUG) { @error_log("POP3 SEND [$cmd] GOT [$reply]",0); }
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 uidl: " . _("Error ") . "[$reply]";
+ return false;
+ }
+
+ $line = "";
+ $count = 1;
+ $line = fgets($fp,$buffer);
+ while ( !preg_match('/^\.\r\n/',$line)) {
+ list ($msg,$msgUidl) = preg_split('/\s+/',$line);
+ $msgUidl = $this->strip_clf($msgUidl);
+ if($count == $msg) {
+ $UIDLArray[$msg] = $msgUidl;
+ }
+ else
+ {
+ $UIDLArray[$count] = 'deleted';
+ }
+ $count++;
+ $line = fgets($fp,$buffer);
+ }
+ }
+ return $UIDLArray;
+ }
+
+ function delete ($msgNum = "") {
+ // Flags a specified msg as deleted. The msg will not
+ // be deleted until a quit() method is called.
+
+ if(!isset($this->FP))
+ {
+ $this->ERROR = "POP3 delete: " . _("No connection to server");
+ return false;
+ }
+ if(empty($msgNum))
+ {
+ $this->ERROR = "POP3 delete: " . _("No msg number submitted");
+ return false;
+ }
+ $reply = $this->send_cmd("DELE $msgNum");
+ if(!$this->is_ok($reply))
+ {
+ $this->ERROR = "POP3 delete: " . _("Command failed ") . "[$reply]";
+ return false;
+ }
+ return true;
+ }
+
+ // *********************************************************
+
+ // The following methods are internal to the class.
+
+ function is_ok ($cmd = "") {
+ // Return true or false on +OK or -ERR
+
+ if( empty($cmd) )
+ return false;
+ else
+ return( stripos($cmd, '+OK') !== false );
+ }
+
+ function strip_clf ($text = "") {
+ // Strips \r\n from server responses
+
+ if(empty($text))
+ return $text;
+ else {
+ $stripped = str_replace(array("\r","\n"),'',$text);
+ return $stripped;
+ }
+ }
+
+ function parse_banner ( $server_text ) {
+ $outside = true;
+ $banner = "";
+ $length = strlen($server_text);
+ for($count =0; $count < $length; $count++)
+ {
+ $digit = substr($server_text,$count,1);
+ if(!empty($digit)) {
+ if( (!$outside) && ($digit != '<') && ($digit != '>') )
+ {
+ $banner .= $digit;
+ }
+ if ($digit == '<')
+ {
+ $outside = false;
+ }
+ if($digit == '>')
+ {
+ $outside = true;
+ }
+ }
+ }
+ $banner = $this->strip_clf($banner); // Just in case
+ return "<$banner>";
+ }
+
+} // End class
+
+// For php4 compatibility
+if (!function_exists("stripos")) {
+ function stripos($haystack, $needle){
+ return strpos($haystack, stristr( $haystack, $needle ));
+ }
+}
diff --git a/src/wp-includes/class-simplepie.php b/src/wp-includes/class-simplepie.php
new file mode 100644
index 0000000000..ba6f28dba0
--- /dev/null
+++ b/src/wp-includes/class-simplepie.php
@@ -0,0 +1,3119 @@
+<?php
+if ( ! class_exists( 'SimplePie' ) ) :
+
+// Load classes we will need.
+require ABSPATH . WPINC . '/SimplePie/Misc.php';
+require ABSPATH . WPINC . '/SimplePie/Cache.php';
+require ABSPATH . WPINC . '/SimplePie/File.php';
+require ABSPATH . WPINC . '/SimplePie/Sanitize.php';
+require ABSPATH . WPINC . '/SimplePie/Registry.php';
+require ABSPATH . WPINC . '/SimplePie/IRI.php';
+require ABSPATH . WPINC . '/SimplePie/Locator.php';
+require ABSPATH . WPINC . '/SimplePie/Content/Type/Sniffer.php';
+require ABSPATH . WPINC . '/SimplePie/XML/Declaration/Parser.php';
+require ABSPATH . WPINC . '/SimplePie/Parser.php';
+require ABSPATH . WPINC . '/SimplePie/Item.php';
+require ABSPATH . WPINC . '/SimplePie/Parse/Date.php';
+require ABSPATH . WPINC . '/SimplePie/Author.php';
+
+/**
+ * WordPress autoloader for SimplePie.
+ *
+ * @since 3.5.0
+ */
+function wp_simplepie_autoload( $class ) {
+ if ( 0 !== strpos( $class, 'SimplePie_' ) )
+ return;
+
+ $file = ABSPATH . WPINC . '/' . str_replace( '_', '/', $class ) . '.php';
+ include $file;
+}
+
+if ( function_exists( 'spl_autoload_register' ) ) {
+ /**
+ * We autoload classes we may not need.
+ *
+ * If SPL is disabled, we load all of SimplePie manually.
+ *
+ * Core.php is not loaded manually, because SimplePie_Core (a deprecated class)
+ * was never included in WordPress core.
+ */
+ spl_autoload_register( 'wp_simplepie_autoload' );
+} else {
+ require ABSPATH . WPINC . '/SimplePie/Cache/Base.php';
+ require ABSPATH . WPINC . '/SimplePie/Cache/DB.php';
+ require ABSPATH . WPINC . '/SimplePie/Cache/File.php';
+ require ABSPATH . WPINC . '/SimplePie/Cache/Memcache.php';
+ require ABSPATH . WPINC . '/SimplePie/Cache/MySQL.php';
+ require ABSPATH . WPINC . '/SimplePie/Caption.php';
+ require ABSPATH . WPINC . '/SimplePie/Category.php';
+ require ABSPATH . WPINC . '/SimplePie/Copyright.php';
+ require ABSPATH . WPINC . '/SimplePie/Credit.php';
+ require ABSPATH . WPINC . '/SimplePie/Decode/HTML/Entities.php';
+ require ABSPATH . WPINC . '/SimplePie/Enclosure.php';
+ require ABSPATH . WPINC . '/SimplePie/gzdecode.php';
+ require ABSPATH . WPINC . '/SimplePie/HTTP/Parser.php';
+ require ABSPATH . WPINC . '/SimplePie/Net/IPv6.php';
+ require ABSPATH . WPINC . '/SimplePie/Rating.php';
+ require ABSPATH . WPINC . '/SimplePie/Restriction.php';
+ require ABSPATH . WPINC . '/SimplePie/Source.php';
+}
+
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2012, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * * Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.3.1
+ * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @author Ryan McCue
+ * @link http://simplepie.org/ SimplePie
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ */
+
+/**
+ * SimplePie Name
+ */
+define('SIMPLEPIE_NAME', 'SimplePie');
+
+/**
+ * SimplePie Version
+ */
+define('SIMPLEPIE_VERSION', '1.3.1');
+
+/**
+ * SimplePie Build
+ * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::get_build() only every load of simplepie.inc)
+ */
+define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::get_build()));
+
+/**
+ * SimplePie Website URL
+ */
+define('SIMPLEPIE_URL', 'http://simplepie.org');
+
+/**
+ * SimplePie Useragent
+ * @see SimplePie::set_useragent()
+ */
+define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
+
+/**
+ * SimplePie Linkback
+ */
+define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
+
+/**
+ * No Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_NONE', 0);
+
+/**
+ * Feed Link Element Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
+
+/**
+ * Local Feed Extension Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
+
+/**
+ * Local Feed Body Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
+
+/**
+ * Remote Feed Extension Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
+
+/**
+ * Remote Feed Body Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
+
+/**
+ * All Feed Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_ALL', 31);
+
+/**
+ * No known feed type
+ */
+define('SIMPLEPIE_TYPE_NONE', 0);
+
+/**
+ * RSS 0.90
+ */
+define('SIMPLEPIE_TYPE_RSS_090', 1);
+
+/**
+ * RSS 0.91 (Netscape)
+ */
+define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
+
+/**
+ * RSS 0.91 (Userland)
+ */
+define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
+
+/**
+ * RSS 0.91 (both Netscape and Userland)
+ */
+define('SIMPLEPIE_TYPE_RSS_091', 6);
+
+/**
+ * RSS 0.92
+ */
+define('SIMPLEPIE_TYPE_RSS_092', 8);
+
+/**
+ * RSS 0.93
+ */
+define('SIMPLEPIE_TYPE_RSS_093', 16);
+
+/**
+ * RSS 0.94
+ */
+define('SIMPLEPIE_TYPE_RSS_094', 32);
+
+/**
+ * RSS 1.0
+ */
+define('SIMPLEPIE_TYPE_RSS_10', 64);
+
+/**
+ * RSS 2.0
+ */
+define('SIMPLEPIE_TYPE_RSS_20', 128);
+
+/**
+ * RDF-based RSS
+ */
+define('SIMPLEPIE_TYPE_RSS_RDF', 65);
+
+/**
+ * Non-RDF-based RSS (truly intended as syndication format)
+ */
+define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
+
+/**
+ * All RSS
+ */
+define('SIMPLEPIE_TYPE_RSS_ALL', 255);
+
+/**
+ * Atom 0.3
+ */
+define('SIMPLEPIE_TYPE_ATOM_03', 256);
+
+/**
+ * Atom 1.0
+ */
+define('SIMPLEPIE_TYPE_ATOM_10', 512);
+
+/**
+ * All Atom
+ */
+define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
+
+/**
+ * All feed types
+ */
+define('SIMPLEPIE_TYPE_ALL', 1023);
+
+/**
+ * No construct
+ */
+define('SIMPLEPIE_CONSTRUCT_NONE', 0);
+
+/**
+ * Text construct
+ */
+define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
+
+/**
+ * HTML construct
+ */
+define('SIMPLEPIE_CONSTRUCT_HTML', 2);
+
+/**
+ * XHTML construct
+ */
+define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
+
+/**
+ * base64-encoded construct
+ */
+define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
+
+/**
+ * IRI construct
+ */
+define('SIMPLEPIE_CONSTRUCT_IRI', 16);
+
+/**
+ * A construct that might be HTML
+ */
+define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
+
+/**
+ * All constructs
+ */
+define('SIMPLEPIE_CONSTRUCT_ALL', 63);
+
+/**
+ * Don't change case
+ */
+define('SIMPLEPIE_SAME_CASE', 1);
+
+/**
+ * Change to lowercase
+ */
+define('SIMPLEPIE_LOWERCASE', 2);
+
+/**
+ * Change to uppercase
+ */
+define('SIMPLEPIE_UPPERCASE', 4);
+
+/**
+ * PCRE for HTML attributes
+ */
+define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
+
+/**
+ * PCRE for XML attributes
+ */
+define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
+
+/**
+ * XML Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
+
+/**
+ * Atom 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
+
+/**
+ * Atom 0.3 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
+
+/**
+ * RDF Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+
+/**
+ * RSS 0.90 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
+
+/**
+ * RSS 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
+
+/**
+ * RSS 1.0 Content Module Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
+
+/**
+ * RSS 2.0 Namespace
+ * (Stupid, I know, but I'm certain it will confuse people less with support.)
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_20', '');
+
+/**
+ * DC 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
+
+/**
+ * DC 1.1 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
+
+/**
+ * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
+
+/**
+ * GeoRSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
+
+/**
+ * Media RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
+
+/**
+ * Wrong Media RSS Namespace. Caused by a long-standing typo in the spec.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
+
+/**
+ * Wrong Media RSS Namespace #2. New namespace introduced in Media RSS 1.5.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG2', 'http://video.search.yahoo.com/mrss');
+
+/**
+ * Wrong Media RSS Namespace #3. A possible typo of the Media RSS 1.5 namespace.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG3', 'http://video.search.yahoo.com/mrss/');
+
+/**
+ * Wrong Media RSS Namespace #4. New spec location after the RSS Advisory Board takes it over, but not a valid namespace.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG4', 'http://www.rssboard.org/media-rss');
+
+/**
+ * Wrong Media RSS Namespace #5. A possible typo of the RSS Advisory Board URL.
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG5', 'http://www.rssboard.org/media-rss/');
+
+/**
+ * iTunes RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+
+/**
+ * XHTML Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
+
+/**
+ * IANA Link Relations Registry
+ */
+define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
+
+/**
+ * No file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
+
+/**
+ * Remote file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
+
+/**
+ * Local file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
+
+/**
+ * fsockopen() file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
+
+/**
+ * cURL file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
+
+/**
+ * file_get_contents() file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
+
+
+
+/**
+ * SimplePie
+ *
+ * @package SimplePie
+ * @subpackage API
+ */
+class SimplePie
+{
+ /**
+ * @var array Raw data
+ * @access private
+ */
+ public $data = array();
+
+ /**
+ * @var mixed Error string
+ * @access private
+ */
+ public $error;
+
+ /**
+ * @var object Instance of SimplePie_Sanitize (or other class)
+ * @see SimplePie::set_sanitize_class()
+ * @access private
+ */
+ public $sanitize;
+
+ /**
+ * @var string SimplePie Useragent
+ * @see SimplePie::set_useragent()
+ * @access private
+ */
+ public $useragent = SIMPLEPIE_USERAGENT;
+
+ /**
+ * @var string Feed URL
+ * @see SimplePie::set_feed_url()
+ * @access private
+ */
+ public $feed_url;
+
+ /**
+ * @var object Instance of SimplePie_File to use as a feed
+ * @see SimplePie::set_file()
+ * @access private
+ */
+ public $file;
+
+ /**
+ * @var string Raw feed data
+ * @see SimplePie::set_raw_data()
+ * @access private
+ */
+ public $raw_data;
+
+ /**
+ * @var int Timeout for fetching remote files
+ * @see SimplePie::set_timeout()
+ * @access private
+ */
+ public $timeout = 10;
+
+ /**
+ * @var bool Forces fsockopen() to be used for remote files instead
+ * of cURL, even if a new enough version is installed
+ * @see SimplePie::force_fsockopen()
+ * @access private
+ */
+ public $force_fsockopen = false;
+
+ /**
+ * @var bool Force the given data/URL to be treated as a feed no matter what
+ * it appears like
+ * @see SimplePie::force_feed()
+ * @access private
+ */
+ public $force_feed = false;
+
+ /**
+ * @var bool Enable/Disable Caching
+ * @see SimplePie::enable_cache()
+ * @access private
+ */
+ public $cache = true;
+
+ /**
+ * @var int Cache duration (in seconds)
+ * @see SimplePie::set_cache_duration()
+ * @access private
+ */
+ public $cache_duration = 3600;
+
+ /**
+ * @var int Auto-discovery cache duration (in seconds)
+ * @see SimplePie::set_autodiscovery_cache_duration()
+ * @access private
+ */
+ public $autodiscovery_cache_duration = 604800; // 7 Days.
+
+ /**
+ * @var string Cache location (relative to executing script)
+ * @see SimplePie::set_cache_location()
+ * @access private
+ */
+ public $cache_location = './cache';
+
+ /**
+ * @var string Function that creates the cache filename
+ * @see SimplePie::set_cache_name_function()
+ * @access private
+ */
+ public $cache_name_function = 'md5';
+
+ /**
+ * @var bool Reorder feed by date descending
+ * @see SimplePie::enable_order_by_date()
+ * @access private
+ */
+ public $order_by_date = true;
+
+ /**
+ * @var mixed Force input encoding to be set to the follow value
+ * (false, or anything type-cast to false, disables this feature)
+ * @see SimplePie::set_input_encoding()
+ * @access private
+ */
+ public $input_encoding = false;
+
+ /**
+ * @var int Feed Autodiscovery Level
+ * @see SimplePie::set_autodiscovery_level()
+ * @access private
+ */
+ public $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
+
+ /**
+ * Class registry object
+ *
+ * @var SimplePie_Registry
+ */
+ public $registry;
+
+ /**
+ * @var int Maximum number of feeds to check with autodiscovery
+ * @see SimplePie::set_max_checked_feeds()
+ * @access private
+ */
+ public $max_checked_feeds = 10;
+
+ /**
+ * @var array All the feeds found during the autodiscovery process
+ * @see SimplePie::get_all_discovered_feeds()
+ * @access private
+ */
+ public $all_discovered_feeds = array();
+
+ /**
+ * @var string Web-accessible path to the handler_image.php file.
+ * @see SimplePie::set_image_handler()
+ * @access private
+ */
+ public $image_handler = '';
+
+ /**
+ * @var array Stores the URLs when multiple feeds are being initialized.
+ * @see SimplePie::set_feed_url()
+ * @access private
+ */
+ public $multifeed_url = array();
+
+ /**
+ * @var array Stores SimplePie objects when multiple feeds initialized.
+ * @access private
+ */
+ public $multifeed_objects = array();
+
+ /**
+ * @var array Stores the get_object_vars() array for use with multifeeds.
+ * @see SimplePie::set_feed_url()
+ * @access private
+ */
+ public $config_settings = null;
+
+ /**
+ * @var integer Stores the number of items to return per-feed with multifeeds.
+ * @see SimplePie::set_item_limit()
+ * @access private
+ */
+ public $item_limit = 0;
+
+ /**
+ * @var array Stores the default attributes to be stripped by strip_attributes().
+ * @see SimplePie::strip_attributes()
+ * @access private
+ */
+ public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+
+ /**
+ * @var array Stores the default tags to be stripped by strip_htmltags().
+ * @see SimplePie::strip_htmltags()
+ * @access private
+ */
+ public $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+
+ /**
+ * The SimplePie class contains feed level data and options
+ *
+ * To use SimplePie, create the SimplePie object with no parameters. You can
+ * then set configuration options using the provided methods. After setting
+ * them, you must initialise the feed using $feed->init(). At that point the
+ * object's methods and properties will be available to you.
+ *
+ * Previously, it was possible to pass in the feed URL along with cache
+ * options directly into the constructor. This has been removed as of 1.3 as
+ * it caused a lot of confusion.
+ *
+ * @since 1.0 Preview Release
+ */
+ public function __construct()
+ {
+ if (version_compare(PHP_VERSION, '5.2', '<'))
+ {
+ trigger_error('PHP 4.x, 5.0 and 5.1 are no longer supported. Please upgrade to PHP 5.2 or newer.');
+ die();
+ }
+
+ // Other objects, instances created here so we can set options on them
+ $this->sanitize = new SimplePie_Sanitize();
+ $this->registry = new SimplePie_Registry();
+
+ if (func_num_args() > 0)
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
+
+ $args = func_get_args();
+ switch (count($args)) {
+ case 3:
+ $this->set_cache_duration($args[2]);
+ case 2:
+ $this->set_cache_location($args[1]);
+ case 1:
+ $this->set_feed_url($args[0]);
+ $this->init();
+ }
+ }
+ }
+
+ /**
+ * Used for converting object to a string
+ */
+ public function __toString()
+ {
+ return md5(serialize($this->data));
+ }
+
+ /**
+ * Remove items that link back to this before destroying this object
+ */
+ public function __destruct()
+ {
+ if ((version_compare(PHP_VERSION, '5.3', '<') || !gc_enabled()) && !ini_get('zend.ze1_compatibility_mode'))
+ {
+ if (!empty($this->data['items']))
+ {
+ foreach ($this->data['items'] as $item)
+ {
+ $item->__destruct();
+ }
+ unset($item, $this->data['items']);
+ }
+ if (!empty($this->data['ordered_items']))
+ {
+ foreach ($this->data['ordered_items'] as $item)
+ {
+ $item->__destruct();
+ }
+ unset($item, $this->data['ordered_items']);
+ }
+ }
+ }
+
+ /**
+ * Force the given data/URL to be treated as a feed
+ *
+ * This tells SimplePie to ignore the content-type provided by the server.
+ * Be careful when using this option, as it will also disable autodiscovery.
+ *
+ * @since 1.1
+ * @param bool $enable Force the given data/URL to be treated as a feed
+ */
+ public function force_feed($enable = false)
+ {
+ $this->force_feed = (bool) $enable;
+ }
+
+ /**
+ * Set the URL of the feed you want to parse
+ *
+ * This allows you to enter the URL of the feed you want to parse, or the
+ * website you want to try to use auto-discovery on. This takes priority
+ * over any set raw data.
+ *
+ * You can set multiple feeds to mash together by passing an array instead
+ * of a string for the $url. Remember that with each additional feed comes
+ * additional processing and resources.
+ *
+ * @since 1.0 Preview Release
+ * @see set_raw_data()
+ * @param string|array $url This is the URL (or array of URLs) that you want to parse.
+ */
+ public function set_feed_url($url)
+ {
+ $this->multifeed_url = array();
+ if (is_array($url))
+ {
+ foreach ($url as $value)
+ {
+ $this->multifeed_url[] = $this->registry->call('Misc', 'fix_protocol', array($value, 1));
+ }
+ }
+ else
+ {
+ $this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
+ }
+ }
+
+ /**
+ * Set an instance of {@see SimplePie_File} to use as a feed
+ *
+ * @param SimplePie_File &$file
+ * @return bool True on success, false on failure
+ */
+ public function set_file(&$file)
+ {
+ if ($file instanceof SimplePie_File)
+ {
+ $this->feed_url = $file->url;
+ $this->file =& $file;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Set the raw XML data to parse
+ *
+ * Allows you to use a string of RSS/Atom data instead of a remote feed.
+ *
+ * If you have a feed available as a string in PHP, you can tell SimplePie
+ * to parse that data string instead of a remote feed. Any set feed URL
+ * takes precedence.
+ *
+ * @since 1.0 Beta 3
+ * @param string $data RSS or Atom data as a string.
+ * @see set_feed_url()
+ */
+ public function set_raw_data($data)
+ {
+ $this->raw_data = $data;
+ }
+
+ /**
+ * Set the the default timeout for fetching remote feeds
+ *
+ * This allows you to change the maximum time the feed's server to respond
+ * and send the feed back.
+ *
+ * @since 1.0 Beta 3
+ * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
+ */
+ public function set_timeout($timeout = 10)
+ {
+ $this->timeout = (int) $timeout;
+ }
+
+ /**
+ * Force SimplePie to use fsockopen() instead of cURL
+ *
+ * @since 1.0 Beta 3
+ * @param bool $enable Force fsockopen() to be used
+ */
+ public function force_fsockopen($enable = false)
+ {
+ $this->force_fsockopen = (bool) $enable;
+ }
+
+ /**
+ * Enable/disable caching in SimplePie.
+ *
+ * This option allows you to disable caching all-together in SimplePie.
+ * However, disabling the cache can lead to longer load times.
+ *
+ * @since 1.0 Preview Release
+ * @param bool $enable Enable caching
+ */
+ public function enable_cache($enable = true)
+ {
+ $this->cache = (bool) $enable;
+ }
+
+ /**
+ * Set the length of time (in seconds) that the contents of a feed will be
+ * cached
+ *
+ * @param int $seconds The feed content cache duration
+ */
+ public function set_cache_duration($seconds = 3600)
+ {
+ $this->cache_duration = (int) $seconds;
+ }
+
+ /**
+ * Set the length of time (in seconds) that the autodiscovered feed URL will
+ * be cached
+ *
+ * @param int $seconds The autodiscovered feed URL cache duration.
+ */
+ public function set_autodiscovery_cache_duration($seconds = 604800)
+ {
+ $this->autodiscovery_cache_duration = (int) $seconds;
+ }
+
+ /**
+ * Set the file system location where the cached files should be stored
+ *
+ * @param string $location The file system location.
+ */
+ public function set_cache_location($location = './cache')
+ {
+ $this->cache_location = (string) $location;
+ }
+
+ /**
+ * Set whether feed items should be sorted into reverse chronological order
+ *
+ * @param bool $enable Sort as reverse chronological order.
+ */
+ public function enable_order_by_date($enable = true)
+ {
+ $this->order_by_date = (bool) $enable;
+ }
+
+ /**
+ * Set the character encoding used to parse the feed
+ *
+ * This overrides the encoding reported by the feed, however it will fall
+ * back to the normal encoding detection if the override fails
+ *
+ * @param string $encoding Character encoding
+ */
+ public function set_input_encoding($encoding = false)
+ {
+ if ($encoding)
+ {
+ $this->input_encoding = (string) $encoding;
+ }
+ else
+ {
+ $this->input_encoding = false;
+ }
+ }
+
+ /**
+ * Set how much feed autodiscovery to do
+ *
+ * @see SIMPLEPIE_LOCATOR_NONE
+ * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
+ * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
+ * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
+ * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
+ * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
+ * @see SIMPLEPIE_LOCATOR_ALL
+ * @param int $level Feed Autodiscovery Level (level can be a combination of the above constants, see bitwise OR operator)
+ */
+ public function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
+ {
+ $this->autodiscovery = (int) $level;
+ }
+
+ /**
+ * Get the class registry
+ *
+ * Use this to override SimplePie's default classes
+ * @see SimplePie_Registry
+ * @return SimplePie_Registry
+ */
+ public function &get_registry()
+ {
+ return $this->registry;
+ }
+
+ /**#@+
+ * Useful when you are overloading or extending SimplePie's default classes.
+ *
+ * @deprecated Use {@see get_registry()} instead
+ * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+ * @param string $class Name of custom class
+ * @return boolean True on success, false otherwise
+ */
+ /**
+ * Set which class SimplePie uses for caching
+ */
+ public function set_cache_class($class = 'SimplePie_Cache')
+ {
+ return $this->registry->register('Cache', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for auto-discovery
+ */
+ public function set_locator_class($class = 'SimplePie_Locator')
+ {
+ return $this->registry->register('Locator', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for XML parsing
+ */
+ public function set_parser_class($class = 'SimplePie_Parser')
+ {
+ return $this->registry->register('Parser', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for remote file fetching
+ */
+ public function set_file_class($class = 'SimplePie_File')
+ {
+ return $this->registry->register('File', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for data sanitization
+ */
+ public function set_sanitize_class($class = 'SimplePie_Sanitize')
+ {
+ return $this->registry->register('Sanitize', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for handling feed items
+ */
+ public function set_item_class($class = 'SimplePie_Item')
+ {
+ return $this->registry->register('Item', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for handling author data
+ */
+ public function set_author_class($class = 'SimplePie_Author')
+ {
+ return $this->registry->register('Author', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for handling category data
+ */
+ public function set_category_class($class = 'SimplePie_Category')
+ {
+ return $this->registry->register('Category', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for feed enclosures
+ */
+ public function set_enclosure_class($class = 'SimplePie_Enclosure')
+ {
+ return $this->registry->register('Enclosure', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for `<media:text>` captions
+ */
+ public function set_caption_class($class = 'SimplePie_Caption')
+ {
+ return $this->registry->register('Caption', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for `<media:copyright>`
+ */
+ public function set_copyright_class($class = 'SimplePie_Copyright')
+ {
+ return $this->registry->register('Copyright', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for `<media:credit>`
+ */
+ public function set_credit_class($class = 'SimplePie_Credit')
+ {
+ return $this->registry->register('Credit', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for `<media:rating>`
+ */
+ public function set_rating_class($class = 'SimplePie_Rating')
+ {
+ return $this->registry->register('Rating', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for `<media:restriction>`
+ */
+ public function set_restriction_class($class = 'SimplePie_Restriction')
+ {
+ return $this->registry->register('Restriction', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses for content-type sniffing
+ */
+ public function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
+ {
+ return $this->registry->register('Content_Type_Sniffer', $class, true);
+ }
+
+ /**
+ * Set which class SimplePie uses item sources
+ */
+ public function set_source_class($class = 'SimplePie_Source')
+ {
+ return $this->registry->register('Source', $class, true);
+ }
+ /**#@-*/
+
+ /**
+ * Set the user agent string
+ *
+ * @param string $ua New user agent string.
+ */
+ public function set_useragent($ua = SIMPLEPIE_USERAGENT)
+ {
+ $this->useragent = (string) $ua;
+ }
+
+ /**
+ * Set callback function to create cache filename with
+ *
+ * @param mixed $function Callback function
+ */
+ public function set_cache_name_function($function = 'md5')
+ {
+ if (is_callable($function))
+ {
+ $this->cache_name_function = $function;
+ }
+ }
+
+ /**
+ * Set options to make SP as fast as possible
+ *
+ * Forgoes a substantial amount of data sanitization in favor of speed. This
+ * turns SimplePie into a dumb parser of feeds.
+ *
+ * @param bool $set Whether to set them or not
+ */
+ public function set_stupidly_fast($set = false)
+ {
+ if ($set)
+ {
+ $this->enable_order_by_date(false);
+ $this->remove_div(false);
+ $this->strip_comments(false);
+ $this->strip_htmltags(false);
+ $this->strip_attributes(false);
+ $this->set_image_handler(false);
+ }
+ }
+
+ /**
+ * Set maximum number of feeds to check with autodiscovery
+ *
+ * @param int $max Maximum number of feeds to check
+ */
+ public function set_max_checked_feeds($max = 10)
+ {
+ $this->max_checked_feeds = (int) $max;
+ }
+
+ public function remove_div($enable = true)
+ {
+ $this->sanitize->remove_div($enable);
+ }
+
+ public function strip_htmltags($tags = '', $encode = null)
+ {
+ if ($tags === '')
+ {
+ $tags = $this->strip_htmltags;
+ }
+ $this->sanitize->strip_htmltags($tags);
+ if ($encode !== null)
+ {
+ $this->sanitize->encode_instead_of_strip($tags);
+ }
+ }
+
+ public function encode_instead_of_strip($enable = true)
+ {
+ $this->sanitize->encode_instead_of_strip($enable);
+ }
+
+ public function strip_attributes($attribs = '')
+ {
+ if ($attribs === '')
+ {
+ $attribs = $this->strip_attributes;
+ }
+ $this->sanitize->strip_attributes($attribs);
+ }
+
+ /**
+ * Set the output encoding
+ *
+ * Allows you to override SimplePie's output to match that of your webpage.
+ * This is useful for times when your webpages are not being served as
+ * UTF-8. This setting will be obeyed by {@see handle_content_type()}, and
+ * is similar to {@see set_input_encoding()}.
+ *
+ * It should be noted, however, that not all character encodings can support
+ * all characters. If your page is being served as ISO-8859-1 and you try
+ * to display a Japanese feed, you'll likely see garbled characters.
+ * Because of this, it is highly recommended to ensure that your webpages
+ * are served as UTF-8.
+ *
+ * The number of supported character encodings depends on whether your web
+ * host supports {@link http://php.net/mbstring mbstring},
+ * {@link http://php.net/iconv iconv}, or both. See
+ * {@link http://simplepie.org/wiki/faq/Supported_Character_Encodings} for
+ * more information.
+ *
+ * @param string $encoding
+ */
+ public function set_output_encoding($encoding = 'UTF-8')
+ {
+ $this->sanitize->set_output_encoding($encoding);
+ }
+
+ public function strip_comments($strip = false)
+ {
+ $this->sanitize->strip_comments($strip);
+ }
+
+ /**
+ * Set element/attribute key/value pairs of HTML attributes
+ * containing URLs that need to be resolved relative to the feed
+ *
+ * Defaults to |a|@href, |area|@href, |blockquote|@cite, |del|@cite,
+ * |form|@action, |img|@longdesc, |img|@src, |input|@src, |ins|@cite,
+ * |q|@cite
+ *
+ * @since 1.0
+ * @param array|null $element_attribute Element/attribute key/value pairs, null for default
+ */
+ public function set_url_replacements($element_attribute = null)
+ {
+ $this->sanitize->set_url_replacements($element_attribute);
+ }
+
+ /**
+ * Set the handler to enable the display of cached images.
+ *
+ * @param str $page Web-accessible path to the handler_image.php file.
+ * @param str $qs The query string that the value should be passed to.
+ */
+ public function set_image_handler($page = false, $qs = 'i')
+ {
+ if ($page !== false)
+ {
+ $this->sanitize->set_image_handler($page . '?' . $qs . '=');
+ }
+ else
+ {
+ $this->image_handler = '';
+ }
+ }
+
+ /**
+ * Set the limit for items returned per-feed with multifeeds
+ *
+ * @param integer $limit The maximum number of items to return.
+ */
+ public function set_item_limit($limit = 0)
+ {
+ $this->item_limit = (int) $limit;
+ }
+
+ /**
+ * Initialize the feed object
+ *
+ * This is what makes everything happen. Period. This is where all of the
+ * configuration options get processed, feeds are fetched, cached, and
+ * parsed, and all of that other good stuff.
+ *
+ * @return boolean True if successful, false otherwise
+ */
+ public function init()
+ {
+ // Check absolute bare minimum requirements.
+ if (!extension_loaded('xml') || !extension_loaded('pcre'))
+ {
+ return false;
+ }
+ // Then check the xml extension is sane (i.e., libxml 2.7.x issue on PHP < 5.2.9 and libxml 2.7.0 to 2.7.2 on any version) if we don't have xmlreader.
+ elseif (!extension_loaded('xmlreader'))
+ {
+ static $xml_is_sane = null;
+ if ($xml_is_sane === null)
+ {
+ $parser_check = xml_parser_create();
+ xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
+ xml_parser_free($parser_check);
+ $xml_is_sane = isset($values[0]['value']);
+ }
+ if (!$xml_is_sane)
+ {
+ return false;
+ }
+ }
+
+ if (method_exists($this->sanitize, 'set_registry'))
+ {
+ $this->sanitize->set_registry($this->registry);
+ }
+
+ // Pass whatever was set with config options over to the sanitizer.
+ // Pass the classes in for legacy support; new classes should use the registry instead
+ $this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->registry->get_class('Cache'));
+ $this->sanitize->pass_file_data($this->registry->get_class('File'), $this->timeout, $this->useragent, $this->force_fsockopen);
+
+ if (!empty($this->multifeed_url))
+ {
+ $i = 0;
+ $success = 0;
+ $this->multifeed_objects = array();
+ $this->error = array();
+ foreach ($this->multifeed_url as $url)
+ {
+ $this->multifeed_objects[$i] = clone $this;
+ $this->multifeed_objects[$i]->set_feed_url($url);
+ $single_success = $this->multifeed_objects[$i]->init();
+ $success |= $single_success;
+ if (!$single_success)
+ {
+ $this->error[$i] = $this->multifeed_objects[$i]->error();
+ }
+ $i++;
+ }
+ return (bool) $success;
+ }
+ elseif ($this->feed_url === null && $this->raw_data === null)
+ {
+ return false;
+ }
+
+ $this->error = null;
+ $this->data = array();
+ $this->multifeed_objects = array();
+ $cache = false;
+
+ if ($this->feed_url !== null)
+ {
+ $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));
+
+ // Decide whether to enable caching
+ if ($this->cache && $parsed_feed_url['scheme'] !== '')
+ {
+ $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc'));
+ }
+
+ // Fetch the data via SimplePie_File into $this->raw_data
+ if (($fetched = $this->fetch_data($cache)) === true)
+ {
+ return true;
+ }
+ elseif ($fetched === false) {
+ return false;
+ }
+
+ list($headers, $sniffed) = $fetched;
+ }
+
+ // Set up array of possible encodings
+ $encodings = array();
+
+ // First check to see if input has been overridden.
+ if ($this->input_encoding !== false)
+ {
+ $encodings[] = $this->input_encoding;
+ }
+
+ $application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
+ $text_types = array('text/xml', 'text/xml-external-parsed-entity');
+
+ // RFC 3023 (only applies to sniffed content)
+ if (isset($sniffed))
+ {
+ if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
+ {
+ if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ {
+ $encodings[] = strtoupper($charset[1]);
+ }
+ $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
+ $encodings[] = 'UTF-8';
+ }
+ elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
+ {
+ if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+ {
+ $encodings[] = $charset[1];
+ }
+ $encodings[] = 'US-ASCII';
+ }
+ // Text MIME-type default
+ elseif (substr($sniffed, 0, 5) === 'text/')
+ {
+ $encodings[] = 'US-ASCII';
+ }
+ }
+
+ // Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
+ $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
+ $encodings[] = 'UTF-8';
+ $encodings[] = 'ISO-8859-1';
+
+ // There's no point in trying an encoding twice
+ $encodings = array_unique($encodings);
+
+ // Loop through each possible encoding, till we return something, or run out of possibilities
+ foreach ($encodings as $encoding)
+ {
+ // Change the encoding to UTF-8 (as we always use UTF-8 internally)
+ if ($utf8_data = $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
+ {
+ // Create new parser
+ $parser = $this->registry->create('Parser');
+
+ // If it's parsed fine
+ if ($parser->parse($utf8_data, 'UTF-8'))
+ {
+ $this->data = $parser->get_data();
+ if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
+ {
+ $this->error = "A feed could not be found at $this->feed_url. This does not appear to be a valid RSS or Atom feed.";
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
+ return false;
+ }
+
+ if (isset($headers))
+ {
+ $this->data['headers'] = $headers;
+ }
+ $this->data['build'] = SIMPLEPIE_BUILD;
+
+ // Cache the file if caching is enabled
+ if ($cache && !$cache->save($this))
+ {
+ trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
+ }
+ return true;
+ }
+ }
+ }
+
+ if (isset($parser))
+ {
+ // We have an error, just set SimplePie_Misc::error to it and quit
+ $this->error = sprintf('This XML document is invalid, likely due to invalid characters. XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
+ }
+ else
+ {
+ $this->error = 'The data could not be converted to UTF-8. You MUST have either the iconv or mbstring extension installed. Upgrading to PHP 5.x (which includes iconv) is highly recommended.';
+ }
+
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
+
+ return false;
+ }
+
+ /**
+ * Fetch the data via SimplePie_File
+ *
+ * If the data is already cached, attempt to fetch it from there instead
+ * @param SimplePie_Cache|false $cache Cache handler, or false to not load from the cache
+ * @return array|true Returns true if the data was loaded from the cache, or an array of HTTP headers and sniffed type
+ */
+ protected function fetch_data(&$cache)
+ {
+ // If it's enabled, use the cache
+ if ($cache)
+ {
+ // Load the Cache
+ $this->data = $cache->load();
+ if (!empty($this->data))
+ {
+ // If the cache is for an outdated build of SimplePie
+ if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD)
+ {
+ $cache->unlink();
+ $this->data = array();
+ }
+ // If we've hit a collision just rerun it with caching disabled
+ elseif (isset($this->data['url']) && $this->data['url'] !== $this->feed_url)
+ {
+ $cache = false;
+ $this->data = array();
+ }
+ // If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
+ elseif (isset($this->data['feed_url']))
+ {
+ // If the autodiscovery cache is still valid use it.
+ if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
+ {
+ // Do not need to do feed autodiscovery yet.
+ if ($this->data['feed_url'] !== $this->data['url'])
+ {
+ $this->set_feed_url($this->data['feed_url']);
+ return $this->init();
+ }
+
+ $cache->unlink();
+ $this->data = array();
+ }
+ }
+ // Check if the cache has been updated
+ elseif ($cache->mtime() + $this->cache_duration < time())
+ {
+ // If we have last-modified and/or etag set
+ if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
+ {
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ if (isset($this->data['headers']['last-modified']))
+ {
+ $headers['if-modified-since'] = $this->data['headers']['last-modified'];
+ }
+ if (isset($this->data['headers']['etag']))
+ {
+ $headers['if-none-match'] = $this->data['headers']['etag'];
+ }
+
+ $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
+
+ if ($file->success)
+ {
+ if ($file->status_code === 304)
+ {
+ $cache->touch();
+ return true;
+ }
+ }
+ else
+ {
+ unset($file);
+ }
+ }
+ }
+ // If the cache is still valid, just return true
+ else
+ {
+ $this->raw_data = false;
+ return true;
+ }
+ }
+ // If the cache is empty, delete it
+ else
+ {
+ $cache->unlink();
+ $this->data = array();
+ }
+ }
+ // If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
+ if (!isset($file))
+ {
+ if ($this->file instanceof SimplePie_File && $this->file->url === $this->feed_url)
+ {
+ $file =& $this->file;
+ }
+ else
+ {
+ $headers = array(
+ 'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
+ );
+ $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen));
+ }
+ }
+ // If the file connection has an error, set SimplePie::error to that and quit
+ if (!$file->success && !($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
+ {
+ $this->error = $file->error;
+ return !empty($this->data);
+ }
+
+ if (!$this->force_feed)
+ {
+ // Check if the supplied URL is a feed, if it isn't, look for it.
+ $locate = $this->registry->create('Locator', array(&$file, $this->timeout, $this->useragent, $this->max_checked_feeds));
+
+ if (!$locate->is_feed($file))
+ {
+ // We need to unset this so that if SimplePie::set_file() has been called that object is untouched
+ unset($file);
+ try
+ {
+ if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds)))
+ {
+ $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed.";
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__));
+ return false;
+ }
+ }
+ catch (SimplePie_Exception $e)
+ {
+ // This is usually because DOMDocument doesn't exist
+ $this->error = $e->getMessage();
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, $e->getFile(), $e->getLine()));
+ return false;
+ }
+ if ($cache)
+ {
+ $this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
+ if (!$cache->save($this))
+ {
+ trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
+ }
+ $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc'));
+ }
+ $this->feed_url = $file->url;
+ }
+ $locate = null;
+ }
+
+ $this->raw_data = $file->body;
+
+ $headers = $file->headers;
+ $sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
+ $sniffed = $sniffer->get_type();
+
+ return array($headers, $sniffed);
+ }
+
+ /**
+ * Get the error message for the occured error
+ *
+ * @return string|array Error message, or array of messages for multifeeds
+ */
+ public function error()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Get the raw XML
+ *
+ * This is the same as the old `$feed->enable_xml_dump(true)`, but returns
+ * the data instead of printing it.
+ *
+ * @return string|boolean Raw XML data, false if the cache is used
+ */
+ public function get_raw_data()
+ {
+ return $this->raw_data;
+ }
+
+ /**
+ * Get the character encoding used for output
+ *
+ * @since Preview Release
+ * @return string
+ */
+ public function get_encoding()
+ {
+ return $this->sanitize->output_encoding;
+ }
+
+ /**
+ * Send the content-type header with correct encoding
+ *
+ * This method ensures that the SimplePie-enabled page is being served with
+ * the correct {@link http://www.iana.org/assignments/media-types/ mime-type}
+ * and character encoding HTTP headers (character encoding determined by the
+ * {@see set_output_encoding} config option).
+ *
+ * This won't work properly if any content or whitespace has already been
+ * sent to the browser, because it relies on PHP's
+ * {@link http://php.net/header header()} function, and these are the
+ * circumstances under which the function works.
+ *
+ * Because it's setting these settings for the entire page (as is the nature
+ * of HTTP headers), this should only be used once per page (again, at the
+ * top).
+ *
+ * @param string $mime MIME type to serve the page as
+ */
+ public function handle_content_type($mime = 'text/html')
+ {
+ if (!headers_sent())
+ {
+ $header = "Content-type: $mime;";
+ if ($this->get_encoding())
+ {
+ $header .= ' charset=' . $this->get_encoding();
+ }
+ else
+ {
+ $header .= ' charset=UTF-8';
+ }
+ header($header);
+ }
+ }
+
+ /**
+ * Get the type of the feed
+ *
+ * This returns a SIMPLEPIE_TYPE_* constant, which can be tested against
+ * using {@link http://php.net/language.operators.bitwise bitwise operators}
+ *
+ * @since 0.8 (usage changed to using constants in 1.0)
+ * @see SIMPLEPIE_TYPE_NONE Unknown.
+ * @see SIMPLEPIE_TYPE_RSS_090 RSS 0.90.
+ * @see SIMPLEPIE_TYPE_RSS_091_NETSCAPE RSS 0.91 (Netscape).
+ * @see SIMPLEPIE_TYPE_RSS_091_USERLAND RSS 0.91 (Userland).
+ * @see SIMPLEPIE_TYPE_RSS_091 RSS 0.91.
+ * @see SIMPLEPIE_TYPE_RSS_092 RSS 0.92.
+ * @see SIMPLEPIE_TYPE_RSS_093 RSS 0.93.
+ * @see SIMPLEPIE_TYPE_RSS_094 RSS 0.94.
+ * @see SIMPLEPIE_TYPE_RSS_10 RSS 1.0.
+ * @see SIMPLEPIE_TYPE_RSS_20 RSS 2.0.x.
+ * @see SIMPLEPIE_TYPE_RSS_RDF RDF-based RSS.
+ * @see SIMPLEPIE_TYPE_RSS_SYNDICATION Non-RDF-based RSS (truly intended as syndication format).
+ * @see SIMPLEPIE_TYPE_RSS_ALL Any version of RSS.
+ * @see SIMPLEPIE_TYPE_ATOM_03 Atom 0.3.
+ * @see SIMPLEPIE_TYPE_ATOM_10 Atom 1.0.
+ * @see SIMPLEPIE_TYPE_ATOM_ALL Any version of Atom.
+ * @see SIMPLEPIE_TYPE_ALL Any known/supported feed type.
+ * @return int SIMPLEPIE_TYPE_* constant
+ */
+ public function get_type()
+ {
+ if (!isset($this->data['type']))
+ {
+ $this->data['type'] = SIMPLEPIE_TYPE_ALL;
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
+ }
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
+ || isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
+ }
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss']))
+ {
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
+ {
+ switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['attribs']['']['version']))
+ {
+ case '0.91':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
+ {
+ switch (trim($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_20]['skiphours']['hour'][0]['data']))
+ {
+ case '0':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
+ break;
+
+ case '24':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
+ break;
+ }
+ }
+ break;
+
+ case '0.92':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
+ break;
+
+ case '0.93':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
+ break;
+
+ case '0.94':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
+ break;
+
+ case '2.0':
+ $this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
+ break;
+ }
+ }
+ }
+ else
+ {
+ $this->data['type'] = SIMPLEPIE_TYPE_NONE;
+ }
+ }
+ return $this->data['type'];
+ }
+
+ /**
+ * Get the URL for the feed
+ *
+ * May or may not be different from the URL passed to {@see set_feed_url()},
+ * depending on whether auto-discovery was used.
+ *
+ * @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
+ * @todo If we have a perm redirect we should return the new URL
+ * @todo When we make the above change, let's support <itunes:new-feed-url> as well
+ * @todo Also, |atom:link|@rel=self
+ * @return string|null
+ */
+ public function subscribe_url()
+ {
+ if ($this->feed_url !== null)
+ {
+ return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get data for an feed-level element
+ *
+ * This method allows you to get access to ANY element/attribute that is a
+ * sub-element of the opening feed tag.
+ *
+ * The return value is an indexed array of elements matching the given
+ * namespace and tag name. Each element has `attribs`, `data` and `child`
+ * subkeys. For `attribs` and `child`, these contain namespace subkeys.
+ * `attribs` then has one level of associative name => value data (where
+ * `value` is a string) after the namespace. `child` has tag-indexed keys
+ * after the namespace, each member of which is an indexed array matching
+ * this same format.
+ *
+ * For example:
+ * <pre>
+ * // This is probably a bad example because we already support
+ * // <media:content> natively, but it shows you how to parse through
+ * // the nodes.
+ * $group = $item->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group');
+ * $content = $group[0]['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'];
+ * $file = $content[0]['attribs']['']['url'];
+ * echo $file;
+ * </pre>
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_feed_tags($namespace, $tag)
+ {
+ $type = $this->get_type();
+ if ($type & SIMPLEPIE_TYPE_ATOM_10)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_ATOM_03)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_RDF)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+ {
+ if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag]))
+ {
+ return $this->data['child'][SIMPLEPIE_NAMESPACE_RSS_20]['rss'][0]['child'][$namespace][$tag];
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get data for an channel-level element
+ *
+ * This method allows you to get access to ANY element/attribute in the
+ * channel/header section of the feed.
+ *
+ * See {@see SimplePie::get_feed_tags()} for a description of the return value
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_channel_tags($namespace, $tag)
+ {
+ $type = $this->get_type();
+ if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
+ {
+ if ($return = $this->get_feed_tags($namespace, $tag))
+ {
+ return $return;
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_10)
+ {
+ if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
+ {
+ if (isset($channel[0]['child'][$namespace][$tag]))
+ {
+ return $channel[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_090)
+ {
+ if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
+ {
+ if (isset($channel[0]['child'][$namespace][$tag]))
+ {
+ return $channel[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+ {
+ if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'channel'))
+ {
+ if (isset($channel[0]['child'][$namespace][$tag]))
+ {
+ return $channel[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get data for an channel-level element
+ *
+ * This method allows you to get access to ANY element/attribute in the
+ * image/logo section of the feed.
+ *
+ * See {@see SimplePie::get_feed_tags()} for a description of the return value
+ *
+ * @since 1.0
+ * @see http://simplepie.org/wiki/faq/supported_xml_namespaces
+ * @param string $namespace The URL of the XML namespace of the elements you're trying to access
+ * @param string $tag Tag name
+ * @return array
+ */
+ public function get_image_tags($namespace, $tag)
+ {
+ $type = $this->get_type();
+ if ($type & SIMPLEPIE_TYPE_RSS_10)
+ {
+ if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
+ {
+ if (isset($image[0]['child'][$namespace][$tag]))
+ {
+ return $image[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_090)
+ {
+ if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
+ {
+ if (isset($image[0]['child'][$namespace][$tag]))
+ {
+ return $image[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+ {
+ if ($image = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'image'))
+ {
+ if (isset($image[0]['child'][$namespace][$tag]))
+ {
+ return $image[0]['child'][$namespace][$tag];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the base URL value from the feed
+ *
+ * Uses `<xml:base>` if available, otherwise uses the first link in the
+ * feed, or failing that, the URL of the feed itself.
+ *
+ * @see get_link
+ * @see subscribe_url
+ *
+ * @param array $element
+ * @return string
+ */
+ public function get_base($element = array())
+ {
+ if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
+ {
+ return $element['xml_base'];
+ }
+ elseif ($this->get_link() !== null)
+ {
+ return $this->get_link();
+ }
+ else
+ {
+ return $this->subscribe_url();
+ }
+ }
+
+ /**
+ * Sanitize feed data
+ *
+ * @access private
+ * @see SimplePie_Sanitize::sanitize()
+ * @param string $data Data to sanitize
+ * @param int $type One of the SIMPLEPIE_CONSTRUCT_* constants
+ * @param string $base Base URL to resolve URLs against
+ * @return string Sanitized data
+ */
+ public function sanitize($data, $type, $base = '')
+ {
+ return $this->sanitize->sanitize($data, $type, $base);
+ }
+
+ /**
+ * Get the title of the feed
+ *
+ * Uses `<atom:title>`, `<title>` or `<dc:title>`
+ *
+ * @since 1.0 (previously called `get_feed_title` since 0.8)
+ * @return string|null
+ */
+ public function get_title()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a category for the feed
+ *
+ * @since Unknown
+ * @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Category|null
+ */
+ public function get_category($key = 0)
+ {
+ $categories = $this->get_categories();
+ if (isset($categories[$key]))
+ {
+ return $categories[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all categories for the feed
+ *
+ * Uses `<atom:category>`, `<category>` or `<dc:subject>`
+ *
+ * @since Unknown
+ * @return array|null List of {@see SimplePie_Category} objects
+ */
+ public function get_categories()
+ {
+ $categories = array();
+
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+ {
+ $term = null;
+ $scheme = null;
+ $label = null;
+ if (isset($category['attribs']['']['term']))
+ {
+ $term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['scheme']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($category['attribs']['']['label']))
+ {
+ $label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, $label));
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'category') as $category)
+ {
+ // This is really the label, but keep this as the term also for BC.
+ // Label will also work on retrieving because that falls back to term.
+ $term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ if (isset($category['attribs']['']['domain']))
+ {
+ $scheme = $this->sanitize($category['attribs']['']['domain'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ $scheme = null;
+ }
+ $categories[] = $this->registry->create('Category', array($term, $scheme, null));
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+ {
+ $categories[] = $this->registry->create('Category', array($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($categories))
+ {
+ return array_unique($categories);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get an author for the feed
+ *
+ * @since 1.1
+ * @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_author($key = 0)
+ {
+ $authors = $this->get_authors();
+ if (isset($authors[$key]))
+ {
+ return $authors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all authors for the feed
+ *
+ * Uses `<atom:author>`, `<author>`, `<dc:creator>` or `<itunes:author>`
+ *
+ * @since 1.1
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_authors()
+ {
+ $authors = array();
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $authors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+ {
+ $authors[] = $this->registry->create('Author', array($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null));
+ }
+
+ if (!empty($authors))
+ {
+ return array_unique($authors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a contributor for the feed
+ *
+ * @since 1.1
+ * @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Author|null
+ */
+ public function get_contributor($key = 0)
+ {
+ $contributors = $this->get_contributors();
+ if (isset($contributors[$key]))
+ {
+ return $contributors[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all contributors for the feed
+ *
+ * Uses `<atom:contributor>`
+ *
+ * @since 1.1
+ * @return array|null List of {@see SimplePie_Author} objects
+ */
+ public function get_contributors()
+ {
+ $contributors = array();
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+ {
+ $name = null;
+ $uri = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+ {
+ $uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $uri !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $uri, $email));
+ }
+ }
+ foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+ {
+ $name = null;
+ $url = null;
+ $email = null;
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+ {
+ $name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+ {
+ $url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+ }
+ if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+ {
+ $email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ if ($name !== null || $email !== null || $url !== null)
+ {
+ $contributors[] = $this->registry->create('Author', array($name, $url, $email));
+ }
+ }
+
+ if (!empty($contributors))
+ {
+ return array_unique($contributors);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get a single link for the feed
+ *
+ * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
+ * @param int $key The link that you want to return. Remember that arrays begin with 0, not 1
+ * @param string $rel The relationship of the link to return
+ * @return string|null Link URL
+ */
+ public function get_link($key = 0, $rel = 'alternate')
+ {
+ $links = $this->get_links($rel);
+ if (isset($links[$key]))
+ {
+ return $links[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the permalink for the item
+ *
+ * Returns the first link available with a relationship of "alternate".
+ * Identical to {@see get_link()} with key 0
+ *
+ * @see get_link
+ * @since 1.0 (previously called `get_feed_link` since Preview Release, `get_feed_permalink()` since 0.8)
+ * @internal Added for parity between the parent-level and the item/entry-level.
+ * @return string|null Link URL
+ */
+ public function get_permalink()
+ {
+ return $this->get_link(0);
+ }
+
+ /**
+ * Get all links for the feed
+ *
+ * Uses `<atom:link>` or `<link>`
+ *
+ * @since Beta 2
+ * @param string $rel The relationship of links to return
+ * @return array|null Links found for the feed (strings)
+ */
+ public function get_links($rel = 'alternate')
+ {
+ if (!isset($this->data['links']))
+ {
+ $this->data['links'] = array();
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+ }
+ }
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+ {
+ foreach ($links as $link)
+ {
+ if (isset($link['attribs']['']['href']))
+ {
+ $link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+ $this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+ }
+ }
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+ if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
+ {
+ $this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+ }
+
+ $keys = array_keys($this->data['links']);
+ foreach ($keys as $key)
+ {
+ if ($this->registry->call('Misc', 'is_isegment_nz_nc', array($key)))
+ {
+ if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+ $this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+ }
+ else
+ {
+ $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+ }
+ }
+ elseif (substr($key, 0, 41) === SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+ {
+ $this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+ }
+ $this->data['links'][$key] = array_unique($this->data['links'][$key]);
+ }
+ }
+
+ if (isset($this->data['links'][$rel]))
+ {
+ return $this->data['links'][$rel];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public function get_all_discovered_feeds()
+ {
+ return $this->all_discovered_feeds;
+ }
+
+ /**
+ * Get the content for the item
+ *
+ * Uses `<atom:subtitle>`, `<atom:tagline>`, `<description>`,
+ * `<dc:description>`, `<itunes:summary>` or `<itunes:subtitle>`
+ *
+ * @since 1.0 (previously called `get_feed_description()` since 0.8)
+ * @return string|null
+ */
+ public function get_description()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the copyright info for the feed
+ *
+ * Uses `<atom:rights>`, `<atom:copyright>` or `<dc:rights>`
+ *
+ * @since 1.0 (previously called `get_feed_copyright()` since 0.8)
+ * @return string|null
+ */
+ public function get_copyright()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_10_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], $this->registry->call('Misc', 'atom_03_construct_type', array($return[0]['attribs'])), $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'copyright'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the language for the feed
+ *
+ * Uses `<language>`, `<dc:language>`, or @xml_lang
+ *
+ * @since 1.0 (previously called `get_feed_language()` since 0.8)
+ * @return string|null
+ */
+ public function get_language()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
+ {
+ return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
+ {
+ return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
+ {
+ return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif (isset($this->data['headers']['content-language']))
+ {
+ return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the latitude coordinates for the item
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:lat>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_latitude()
+ {
+
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[1];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the longitude coordinates for the feed
+ *
+ * Compatible with the W3C WGS84 Basic Geo and GeoRSS specifications
+ *
+ * Uses `<geo:long>`, `<geo:lon>` or `<georss:point>`
+ *
+ * @since 1.0
+ * @link http://www.w3.org/2003/01/geo/ W3C WGS84 Basic Geo
+ * @link http://www.georss.org/ GeoRSS
+ * @return string|null
+ */
+ public function get_longitude()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+ {
+ return (float) $return[0]['data'];
+ }
+ elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', trim($return[0]['data']), $match))
+ {
+ return (float) $match[2];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the feed logo's title
+ *
+ * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" title.
+ *
+ * Uses `<image><title>` or `<image><dc:title>`
+ *
+ * @return string|null
+ */
+ public function get_image_title()
+ {
+ if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the feed logo's URL
+ *
+ * RSS 0.9.0, 2.0, Atom 1.0, and feeds with iTunes RSS tags are allowed to
+ * have a "feed logo" URL. This points directly to the image itself.
+ *
+ * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
+ * `<image><title>` or `<image><dc:title>`
+ *
+ * @return string|null
+ */
+ public function get_image_url()
+ {
+ if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+ {
+ return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * Get the feed logo's link
+ *
+ * RSS 0.9.0, 1.0 and 2.0 feeds are allowed to have a "feed logo" link. This
+ * points to a human-readable page that the image should link to.
+ *
+ * Uses `<itunes:image>`, `<atom:logo>`, `<atom:icon>`,
+ * `<image><title>` or `<image><dc:title>`
+ *
+ * @return string|null
+ */
+ public function get_image_link()
+ {
+ if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'link'))
+ {
+ return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the feed logo's link
+ *
+ * RSS 2.0 feeds are allowed to have a "feed logo" width.
+ *
+ * Uses `<image><width>` or defaults to 88.0 if no width is specified and
+ * the feed is an RSS 2.0 feed.
+ *
+ * @return int|float|null
+ */
+ public function get_image_width()
+ {
+ if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'width'))
+ {
+ return round($return[0]['data']);
+ }
+ elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
+ {
+ return 88.0;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the feed logo's height
+ *
+ * RSS 2.0 feeds are allowed to have a "feed logo" height.
+ *
+ * Uses `<image><height>` or defaults to 31.0 if no height is specified and
+ * the feed is an RSS 2.0 feed.
+ *
+ * @return int|float|null
+ */
+ public function get_image_height()
+ {
+ if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'height'))
+ {
+ return round($return[0]['data']);
+ }
+ elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'url'))
+ {
+ return 31.0;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get the number of items in the feed
+ *
+ * This is well-suited for {@link http://php.net/for for()} loops with
+ * {@see get_item()}
+ *
+ * @param int $max Maximum value to return. 0 for no limit
+ * @return int Number of items in the feed
+ */
+ public function get_item_quantity($max = 0)
+ {
+ $max = (int) $max;
+ $qty = count($this->get_items());
+ if ($max === 0)
+ {
+ return $qty;
+ }
+ else
+ {
+ return ($qty > $max) ? $max : $qty;
+ }
+ }
+
+ /**
+ * Get a single item from the feed
+ *
+ * This is better suited for {@link http://php.net/for for()} loops, whereas
+ * {@see get_items()} is better suited for
+ * {@link http://php.net/foreach foreach()} loops.
+ *
+ * @see get_item_quantity()
+ * @since Beta 2
+ * @param int $key The item that you want to return. Remember that arrays begin with 0, not 1
+ * @return SimplePie_Item|null
+ */
+ public function get_item($key = 0)
+ {
+ $items = $this->get_items();
+ if (isset($items[$key]))
+ {
+ return $items[$key];
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Get all items from the feed
+ *
+ * This is better suited for {@link http://php.net/for for()} loops, whereas
+ * {@see get_items()} is better suited for
+ * {@link http://php.net/foreach foreach()} loops.
+ *
+ * @see get_item_quantity
+ * @since Beta 2
+ * @param int $start Index to start at
+ * @param int $end Number of items to return. 0 for all items after `$start`
+ * @return array|null List of {@see SimplePie_Item} objects
+ */
+ public function get_items($start = 0, $end = 0)
+ {
+ if (!isset($this->data['items']))
+ {
+ if (!empty($this->multifeed_objects))
+ {
+ $this->data['items'] = SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
+ }
+ else
+ {
+ $this->data['items'] = array();
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
+ }
+ }
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
+ }
+ }
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
+ }
+ }
+ if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
+ }
+ }
+ if ($items = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_20, 'item'))
+ {
+ $keys = array_keys($items);
+ foreach ($keys as $key)
+ {
+ $this->data['items'][] = $this->registry->create('Item', array($this, $items[$key]));
+ }
+ }
+ }
+ }
+
+ if (!empty($this->data['items']))
+ {
+ // If we want to order it by date, check if all items have a date, and then sort it
+ if ($this->order_by_date && empty($this->multifeed_objects))
+ {
+ if (!isset($this->data['ordered_items']))
+ {
+ $do_sort = true;
+ foreach ($this->data['items'] as $item)
+ {
+ if (!$item->get_date('U'))
+ {
+ $do_sort = false;
+ break;
+ }
+ }
+ $item = null;
+ $this->data['ordered_items'] = $this->data['items'];
+ if ($do_sort)
+ {
+ usort($this->data['ordered_items'], array(get_class($this), 'sort_items'));
+ }
+ }
+ $items = $this->data['ordered_items'];
+ }
+ else
+ {
+ $items = $this->data['items'];
+ }
+
+ // Slice the data as desired
+ if ($end === 0)
+ {
+ return array_slice($items, $start);
+ }
+ else
+ {
+ return array_slice($items, $start, $end);
+ }
+ }
+ else
+ {
+ return array();
+ }
+ }
+
+ /**
+ * Set the favicon handler
+ *
+ * @deprecated Use your own favicon handling instead
+ */
+ public function set_favicon_handler($page = false, $qs = 'i')
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('Favicon handling has been removed, please use your own handling', $level);
+ return false;
+ }
+
+ /**
+ * Get the favicon for the current feed
+ *
+ * @deprecated Use your own favicon handling instead
+ */
+ public function get_favicon()
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('Favicon handling has been removed, please use your own handling', $level);
+
+ if (($url = $this->get_link()) !== null)
+ {
+ return 'http://g.etfv.co/' . urlencode($url);
+ }
+
+ return false;
+ }
+
+ /**
+ * Magic method handler
+ *
+ * @param string $method Method name
+ * @param array $args Arguments to the method
+ * @return mixed
+ */
+ public function __call($method, $args)
+ {
+ if (strpos($method, 'subscribe_') === 0)
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('subscribe_*() has been deprecated, implement the callback yourself', $level);
+ return '';
+ }
+ if ($method === 'enable_xml_dump')
+ {
+ $level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
+ trigger_error('enable_xml_dump() has been deprecated, use get_raw_data() instead', $level);
+ return false;
+ }
+
+ $class = get_class($this);
+ $trace = debug_backtrace();
+ $file = $trace[0]['file'];
+ $line = $trace[0]['line'];
+ trigger_error("Call to undefined method $class::$method() in $file on line $line", E_USER_ERROR);
+ }
+
+ /**
+ * Sorting callback for items
+ *
+ * @access private
+ * @param SimplePie $a
+ * @param SimplePie $b
+ * @return boolean
+ */
+ public static function sort_items($a, $b)
+ {
+ return $a->get_date('U') <= $b->get_date('U');
+ }
+
+ /**
+ * Merge items from several feeds into one
+ *
+ * If you're merging multiple feeds together, they need to all have dates
+ * for the items or else SimplePie will refuse to sort them.
+ *
+ * @link http://simplepie.org/wiki/tutorial/sort_multiple_feeds_by_time_and_date#if_feeds_require_separate_per-feed_settings
+ * @param array $urls List of SimplePie feed objects to merge
+ * @param int $start Starting item
+ * @param int $end Number of items to return
+ * @param int $limit Maximum number of items per feed
+ * @return array
+ */
+ public static function merge_items($urls, $start = 0, $end = 0, $limit = 0)
+ {
+ if (is_array($urls) && sizeof($urls) > 0)
+ {
+ $items = array();
+ foreach ($urls as $arg)
+ {
+ if ($arg instanceof SimplePie)
+ {
+ $items = array_merge($items, $arg->get_items(0, $limit));
+ }
+ else
+ {
+ trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
+ }
+ }
+
+ $do_sort = true;
+ foreach ($items as $item)
+ {
+ if (!$item->get_date('U'))
+ {
+ $do_sort = false;
+ break;
+ }
+ }
+ $item = null;
+ if ($do_sort)
+ {
+ usort($items, array(get_class($urls[0]), 'sort_items'));
+ }
+
+ if ($end === 0)
+ {
+ return array_slice($items, $start);
+ }
+ else
+ {
+ return array_slice($items, $start, $end);
+ }
+ }
+ else
+ {
+ trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
+ return array();
+ }
+ }
+}
+endif; \ No newline at end of file
diff --git a/src/wp-includes/class-smtp.php b/src/wp-includes/class-smtp.php
new file mode 100644
index 0000000000..72361bbbbb
--- /dev/null
+++ b/src/wp-includes/class-smtp.php
@@ -0,0 +1,1003 @@
+<?php
+/*~ class.smtp.php
+.---------------------------------------------------------------------------.
+| Software: PHPMailer - PHP email class |
+| Version: 5.2.4 |
+| Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
+| ------------------------------------------------------------------------- |
+| Admin: Jim Jagielski (project admininistrator) |
+| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
+| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
+| : Jim Jagielski (jimjag) jimjag@gmail.com |
+| Founder: Brent R. Matzelle (original founder) |
+| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
+| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
+| Copyright (c) 2001-2003, Brent R. Matzelle |
+| ------------------------------------------------------------------------- |
+| License: Distributed under the Lesser General Public License (LGPL) |
+| http://www.gnu.org/copyleft/lesser.html |
+| This program is distributed in the hope that it will be useful - WITHOUT |
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
+| FITNESS FOR A PARTICULAR PURPOSE. |
+'---------------------------------------------------------------------------'
+*/
+
+/**
+ * PHPMailer - PHP SMTP email transport class
+ * NOTE: Designed for use with PHP version 5 and up
+ * @package PHPMailer
+ * @author Andy Prevost
+ * @author Marcus Bointon
+ * @copyright 2004 - 2008 Andy Prevost
+ * @author Jim Jagielski
+ * @copyright 2010 - 2012 Jim Jagielski
+ * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
+ */
+
+/**
+ * PHP RFC821 SMTP client
+ *
+ * Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
+ * SMTP also provides some utility methods for sending mail to an SMTP server.
+ * @author Chris Ryan
+ * @package PHPMailer
+ */
+
+class SMTP {
+ /**
+ * SMTP server port
+ * @var int
+ */
+ public $SMTP_PORT = 25;
+
+ /**
+ * SMTP reply line ending (don't change)
+ * @var string
+ */
+ public $CRLF = "\r\n";
+
+ /**
+ * Sets whether debugging is turned on
+ * @var bool
+ */
+ public $do_debug; // the level of debug to perform
+
+ /**
+ * Sets the function/method to use for debugging output.
+ * Right now we only honor "echo" or "error_log"
+ * @var string
+ */
+ public $Debugoutput = "echo";
+
+ /**
+ * Sets VERP use on/off (default is off)
+ * @var bool
+ */
+ public $do_verp = false;
+
+ /**
+ * Sets the SMTP timeout value for reads, in seconds
+ * @var int
+ */
+ public $Timeout = 15;
+
+ /**
+ * Sets the SMTP timelimit value for reads, in seconds
+ * @var int
+ */
+ public $Timelimit = 30;
+
+ /**
+ * Sets the SMTP PHPMailer Version number
+ * @var string
+ */
+ public $Version = '5.2.4';
+
+ /////////////////////////////////////////////////
+ // PROPERTIES, PRIVATE AND PROTECTED
+ /////////////////////////////////////////////////
+
+ /**
+ * @var resource The socket to the server
+ */
+ private $smtp_conn;
+ /**
+ * @var string Error message, if any, for the last call
+ */
+ private $error;
+ /**
+ * @var string The reply the server sent to us for HELO
+ */
+ private $helo_rply;
+
+ /**
+ * Outputs debugging info via user-defined method
+ * @param string $str
+ */
+ private function edebug($str) {
+ if ($this->Debugoutput == "error_log") {
+ error_log($str);
+ } else {
+ echo $str;
+ }
+ }
+
+ /**
+ * Initialize the class so that the data is in a known state.
+ * @access public
+ * @return SMTP
+ */
+ public function __construct() {
+ $this->smtp_conn = 0;
+ $this->error = null;
+ $this->helo_rply = null;
+
+ $this->do_debug = 0;
+ }
+
+ /////////////////////////////////////////////////
+ // CONNECTION FUNCTIONS
+ /////////////////////////////////////////////////
+
+ /**
+ * Connect to the server specified on the port specified.
+ * If the port is not specified use the default SMTP_PORT.
+ * If tval is specified then a connection will try and be
+ * established with the server for that number of seconds.
+ * If tval is not specified the default is 30 seconds to
+ * try on the connection.
+ *
+ * SMTP CODE SUCCESS: 220
+ * SMTP CODE FAILURE: 421
+ * @access public
+ * @param string $host
+ * @param int $port
+ * @param int $tval
+ * @return bool
+ */
+ public function Connect($host, $port = 0, $tval = 30) {
+ // set the error val to null so there is no confusion
+ $this->error = null;
+
+ // make sure we are __not__ connected
+ if($this->connected()) {
+ // already connected, generate error
+ $this->error = array("error" => "Already connected to a server");
+ return false;
+ }
+
+ if(empty($port)) {
+ $port = $this->SMTP_PORT;
+ }
+
+ // connect to the smtp server
+ $this->smtp_conn = @fsockopen($host, // the host of the server
+ $port, // the port to use
+ $errno, // error number if any
+ $errstr, // error message if any
+ $tval); // give up after ? secs
+ // verify we connected properly
+ if(empty($this->smtp_conn)) {
+ $this->error = array("error" => "Failed to connect to server",
+ "errno" => $errno,
+ "errstr" => $errstr);
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ // SMTP server can take longer to respond, give longer timeout for first read
+ // Windows does not have support for this timeout function
+ if(substr(PHP_OS, 0, 3) != "WIN") {
+ $max = ini_get('max_execution_time');
+ if ($max != 0 && $tval > $max) { // don't bother if unlimited
+ @set_time_limit($tval);
+ }
+ stream_set_timeout($this->smtp_conn, $tval, 0);
+ }
+
+ // get any announcement
+ $announce = $this->get_lines();
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />');
+ }
+
+ return true;
+ }
+
+ /**
+ * Initiate a TLS communication with the server.
+ *
+ * SMTP CODE 220 Ready to start TLS
+ * SMTP CODE 501 Syntax error (no parameters allowed)
+ * SMTP CODE 454 TLS not available due to temporary reason
+ * @access public
+ * @return bool success
+ */
+ public function StartTLS() {
+ $this->error = null; # to avoid confusion
+
+ if(!$this->connected()) {
+ $this->error = array("error" => "Called StartTLS() without being connected");
+ return false;
+ }
+
+ fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 220) {
+ $this->error =
+ array("error" => "STARTTLS not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ // Begin encrypted connection
+ if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Performs SMTP authentication. Must be run after running the
+ * Hello() method. Returns true if successfully authenticated.
+ * @access public
+ * @param string $username
+ * @param string $password
+ * @param string $authtype
+ * @param string $realm
+ * @param string $workstation
+ * @return bool
+ */
+ public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') {
+ if (empty($authtype)) {
+ $authtype = 'LOGIN';
+ }
+
+ switch ($authtype) {
+ case 'PLAIN':
+ // Start authentication
+ fputs($this->smtp_conn,"AUTH PLAIN" . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($code != 334) {
+ $this->error =
+ array("error" => "AUTH not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ // Send encoded username and password
+ fputs($this->smtp_conn, base64_encode("\0".$username."\0".$password) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($code != 235) {
+ $this->error =
+ array("error" => "Authentication not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ break;
+ case 'LOGIN':
+ // Start authentication
+ fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($code != 334) {
+ $this->error =
+ array("error" => "AUTH not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ // Send encoded username
+ fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($code != 334) {
+ $this->error =
+ array("error" => "Username not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ // Send encoded password
+ fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($code != 235) {
+ $this->error =
+ array("error" => "Password not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ break;
+ case 'NTLM':
+ /*
+ * ntlm_sasl_client.php
+ ** Bundled with Permission
+ **
+ ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
+ ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
+ */
+ require_once('ntlm_sasl_client.php');
+ $temp = new stdClass();
+ $ntlm_client = new ntlm_sasl_client_class;
+ if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
+ $this->error = array("error" => $temp->error);
+ if($this->do_debug >= 1) {
+ $this->edebug("You need to enable some modules in your php.ini file: " . $this->error["error"] . $this->CRLF);
+ }
+ return false;
+ }
+ $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
+
+ fputs($this->smtp_conn,"AUTH NTLM " . base64_encode($msg1) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+
+ if($code != 334) {
+ $this->error =
+ array("error" => "AUTH not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
+ }
+ return false;
+ }
+
+ $challange = substr($rply,3);//though 0 based, there is a white space after the 3 digit number....//msg2
+ $challange = base64_decode($challange);
+ $ntlm_res = $ntlm_client->NTLMResponse(substr($challange,24,8),$password);
+ $msg3 = $ntlm_client->TypeMsg3($ntlm_res,$username,$realm,$workstation);//msg3
+ // Send encoded username
+ fputs($this->smtp_conn, base64_encode($msg3) . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($code != 235) {
+ $this->error =
+ array("error" => "Could not authenticate",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
+ }
+ return false;
+ }
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if connected to a server otherwise false
+ * @access public
+ * @return bool
+ */
+ public function Connected() {
+ if(!empty($this->smtp_conn)) {
+ $sock_status = socket_get_status($this->smtp_conn);
+ if($sock_status["eof"]) {
+ // the socket is valid but we are not connected
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected");
+ }
+ $this->Close();
+ return false;
+ }
+ return true; // everything looks good
+ }
+ return false;
+ }
+
+ /**
+ * Closes the socket and cleans up the state of the class.
+ * It is not considered good to use this function without
+ * first trying to use QUIT.
+ * @access public
+ * @return void
+ */
+ public function Close() {
+ $this->error = null; // so there is no confusion
+ $this->helo_rply = null;
+ if(!empty($this->smtp_conn)) {
+ // close the connection and cleanup
+ fclose($this->smtp_conn);
+ $this->smtp_conn = 0;
+ }
+ }
+
+ /////////////////////////////////////////////////
+ // SMTP COMMANDS
+ /////////////////////////////////////////////////
+
+ /**
+ * Issues a data command and sends the msg_data to the server
+ * finializing the mail transaction. $msg_data is the message
+ * that is to be send with the headers. Each header needs to be
+ * on a single line followed by a <CRLF> with the message headers
+ * and the message body being seperated by and additional <CRLF>.
+ *
+ * Implements rfc 821: DATA <CRLF>
+ *
+ * SMTP CODE INTERMEDIATE: 354
+ * [data]
+ * <CRLF>.<CRLF>
+ * SMTP CODE SUCCESS: 250
+ * SMTP CODE FAILURE: 552,554,451,452
+ * SMTP CODE FAILURE: 451,554
+ * SMTP CODE ERROR : 500,501,503,421
+ * @access public
+ * @param string $msg_data
+ * @return bool
+ */
+ public function Data($msg_data) {
+ $this->error = null; // so no confusion is caused
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called Data() without being connected");
+ return false;
+ }
+
+ fputs($this->smtp_conn,"DATA" . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 354) {
+ $this->error =
+ array("error" => "DATA command not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ /* the server is ready to accept data!
+ * according to rfc 821 we should not send more than 1000
+ * including the CRLF
+ * characters on a single line so we will break the data up
+ * into lines by \r and/or \n then if needed we will break
+ * each of those into smaller lines to fit within the limit.
+ * in addition we will be looking for lines that start with
+ * a period '.' and append and additional period '.' to that
+ * line. NOTE: this does not count towards limit.
+ */
+
+ // normalize the line breaks so we know the explode works
+ $msg_data = str_replace("\r\n","\n",$msg_data);
+ $msg_data = str_replace("\r","\n",$msg_data);
+ $lines = explode("\n",$msg_data);
+
+ /* we need to find a good way to determine is headers are
+ * in the msg_data or if it is a straight msg body
+ * currently I am assuming rfc 822 definitions of msg headers
+ * and if the first field of the first line (':' sperated)
+ * does not contain a space then it _should_ be a header
+ * and we can process all lines before a blank "" line as
+ * headers.
+ */
+
+ $field = substr($lines[0],0,strpos($lines[0],":"));
+ $in_headers = false;
+ if(!empty($field) && !strstr($field," ")) {
+ $in_headers = true;
+ }
+
+ $max_line_length = 998; // used below; set here for ease in change
+
+ while(list(,$line) = @each($lines)) {
+ $lines_out = null;
+ if($line == "" && $in_headers) {
+ $in_headers = false;
+ }
+ // ok we need to break this line up into several smaller lines
+ while(strlen($line) > $max_line_length) {
+ $pos = strrpos(substr($line,0,$max_line_length)," ");
+
+ // Patch to fix DOS attack
+ if(!$pos) {
+ $pos = $max_line_length - 1;
+ $lines_out[] = substr($line,0,$pos);
+ $line = substr($line,$pos);
+ } else {
+ $lines_out[] = substr($line,0,$pos);
+ $line = substr($line,$pos + 1);
+ }
+
+ /* if processing headers add a LWSP-char to the front of new line
+ * rfc 822 on long msg headers
+ */
+ if($in_headers) {
+ $line = "\t" . $line;
+ }
+ }
+ $lines_out[] = $line;
+
+ // send the lines to the server
+ while(list(,$line_out) = @each($lines_out)) {
+ if(strlen($line_out) > 0)
+ {
+ if(substr($line_out, 0, 1) == ".") {
+ $line_out = "." . $line_out;
+ }
+ }
+ fputs($this->smtp_conn,$line_out . $this->CRLF);
+ }
+ }
+
+ // message data has been sent
+ fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 250) {
+ $this->error =
+ array("error" => "DATA not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sends the HELO command to the smtp server.
+ * This makes sure that we and the server are in
+ * the same known state.
+ *
+ * Implements from rfc 821: HELO <SP> <domain> <CRLF>
+ *
+ * SMTP CODE SUCCESS: 250
+ * SMTP CODE ERROR : 500, 501, 504, 421
+ * @access public
+ * @param string $host
+ * @return bool
+ */
+ public function Hello($host = '') {
+ $this->error = null; // so no confusion is caused
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called Hello() without being connected");
+ return false;
+ }
+
+ // if hostname for HELO was not specified send default
+ if(empty($host)) {
+ // determine appropriate default to send to server
+ $host = "localhost";
+ }
+
+ // Send extended hello first (RFC 2821)
+ if(!$this->SendHello("EHLO", $host)) {
+ if(!$this->SendHello("HELO", $host)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sends a HELO/EHLO command.
+ * @access private
+ * @param string $hello
+ * @param string $host
+ * @return bool
+ */
+ private function SendHello($hello, $host) {
+ fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 250) {
+ $this->error =
+ array("error" => $hello . " not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ $this->helo_rply = $rply;
+
+ return true;
+ }
+
+ /**
+ * Starts a mail transaction from the email address specified in
+ * $from. Returns true if successful or false otherwise. If True
+ * the mail transaction is started and then one or more Recipient
+ * commands may be called followed by a Data command.
+ *
+ * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
+ *
+ * SMTP CODE SUCCESS: 250
+ * SMTP CODE SUCCESS: 552,451,452
+ * SMTP CODE SUCCESS: 500,501,421
+ * @access public
+ * @param string $from
+ * @return bool
+ */
+ public function Mail($from) {
+ $this->error = null; // so no confusion is caused
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called Mail() without being connected");
+ return false;
+ }
+
+ $useVerp = ($this->do_verp ? " XVERP" : "");
+ fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 250) {
+ $this->error =
+ array("error" => "MAIL not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sends the quit command to the server and then closes the socket
+ * if there is no error or the $close_on_error argument is true.
+ *
+ * Implements from rfc 821: QUIT <CRLF>
+ *
+ * SMTP CODE SUCCESS: 221
+ * SMTP CODE ERROR : 500
+ * @access public
+ * @param bool $close_on_error
+ * @return bool
+ */
+ public function Quit($close_on_error = true) {
+ $this->error = null; // so there is no confusion
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called Quit() without being connected");
+ return false;
+ }
+
+ // send the quit command to the server
+ fputs($this->smtp_conn,"quit" . $this->CRLF);
+
+ // get any good-bye messages
+ $byemsg = $this->get_lines();
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />');
+ }
+
+ $rval = true;
+ $e = null;
+
+ $code = substr($byemsg,0,3);
+ if($code != 221) {
+ // use e as a tmp var cause Close will overwrite $this->error
+ $e = array("error" => "SMTP server rejected quit command",
+ "smtp_code" => $code,
+ "smtp_rply" => substr($byemsg,4));
+ $rval = false;
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />');
+ }
+ }
+
+ if(empty($e) || $close_on_error) {
+ $this->Close();
+ }
+
+ return $rval;
+ }
+
+ /**
+ * Sends the command RCPT to the SMTP server with the TO: argument of $to.
+ * Returns true if the recipient was accepted false if it was rejected.
+ *
+ * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
+ *
+ * SMTP CODE SUCCESS: 250,251
+ * SMTP CODE FAILURE: 550,551,552,553,450,451,452
+ * SMTP CODE ERROR : 500,501,503,421
+ * @access public
+ * @param string $to
+ * @return bool
+ */
+ public function Recipient($to) {
+ $this->error = null; // so no confusion is caused
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called Recipient() without being connected");
+ return false;
+ }
+
+ fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 250 && $code != 251) {
+ $this->error =
+ array("error" => "RCPT not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sends the RSET command to abort and transaction that is
+ * currently in progress. Returns true if successful false
+ * otherwise.
+ *
+ * Implements rfc 821: RSET <CRLF>
+ *
+ * SMTP CODE SUCCESS: 250
+ * SMTP CODE ERROR : 500,501,504,421
+ * @access public
+ * @return bool
+ */
+ public function Reset() {
+ $this->error = null; // so no confusion is caused
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called Reset() without being connected");
+ return false;
+ }
+
+ fputs($this->smtp_conn,"RSET" . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 250) {
+ $this->error =
+ array("error" => "RSET failed",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Starts a mail transaction from the email address specified in
+ * $from. Returns true if successful or false otherwise. If True
+ * the mail transaction is started and then one or more Recipient
+ * commands may be called followed by a Data command. This command
+ * will send the message to the users terminal if they are logged
+ * in and send them an email.
+ *
+ * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
+ *
+ * SMTP CODE SUCCESS: 250
+ * SMTP CODE SUCCESS: 552,451,452
+ * SMTP CODE SUCCESS: 500,501,502,421
+ * @access public
+ * @param string $from
+ * @return bool
+ */
+ public function SendAndMail($from) {
+ $this->error = null; // so no confusion is caused
+
+ if(!$this->connected()) {
+ $this->error = array(
+ "error" => "Called SendAndMail() without being connected");
+ return false;
+ }
+
+ fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
+
+ $rply = $this->get_lines();
+ $code = substr($rply,0,3);
+
+ if($this->do_debug >= 2) {
+ $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
+ }
+
+ if($code != 250) {
+ $this->error =
+ array("error" => "SAML not accepted from server",
+ "smtp_code" => $code,
+ "smtp_msg" => substr($rply,4));
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * This is an optional command for SMTP that this class does not
+ * support. This method is here to make the RFC821 Definition
+ * complete for this class and __may__ be implimented in the future
+ *
+ * Implements from rfc 821: TURN <CRLF>
+ *
+ * SMTP CODE SUCCESS: 250
+ * SMTP CODE FAILURE: 502
+ * SMTP CODE ERROR : 500, 503
+ * @access public
+ * @return bool
+ */
+ public function Turn() {
+ $this->error = array("error" => "This method, TURN, of the SMTP ".
+ "is not implemented");
+ if($this->do_debug >= 1) {
+ $this->edebug("SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />');
+ }
+ return false;
+ }
+
+ /**
+ * Get the current error
+ * @access public
+ * @return array
+ */
+ public function getError() {
+ return $this->error;
+ }
+
+ /////////////////////////////////////////////////
+ // INTERNAL FUNCTIONS
+ /////////////////////////////////////////////////
+
+ /**
+ * Read in as many lines as possible
+ * either before eof or socket timeout occurs on the operation.
+ * With SMTP we can tell if we have more lines to read if the
+ * 4th character is '-' symbol. If it is a space then we don't
+ * need to read anything else.
+ * @access private
+ * @return string
+ */
+ private function get_lines() {
+ $data = "";
+ $endtime = 0;
+ /* If for some reason the fp is bad, don't inf loop */
+ if (!is_resource($this->smtp_conn)) {
+ return $data;
+ }
+ stream_set_timeout($this->smtp_conn, $this->Timeout);
+ if ($this->Timelimit > 0) {
+ $endtime = time() + $this->Timelimit;
+ }
+ while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
+ $str = @fgets($this->smtp_conn,515);
+ if($this->do_debug >= 4) {
+ $this->edebug("SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />');
+ $this->edebug("SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />');
+ }
+ $data .= $str;
+ if($this->do_debug >= 4) {
+ $this->edebug("SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />');
+ }
+ // if 4th character is a space, we are done reading, break the loop
+ if(substr($str,3,1) == " ") { break; }
+ // Timed-out? Log and break
+ $info = stream_get_meta_data($this->smtp_conn);
+ if ($info['timed_out']) {
+ if($this->do_debug >= 4) {
+ $this->edebug("SMTP -> get_lines(): timed-out (" . $this->Timeout . " seconds) <br />");
+ }
+ break;
+ }
+ // Now check if reads took too long
+ if ($endtime) {
+ if (time() > $endtime) {
+ if($this->do_debug >= 4) {
+ $this->edebug("SMTP -> get_lines(): timelimit reached (" . $this->Timelimit . " seconds) <br />");
+ }
+ break;
+ }
+ }
+ }
+ return $data;
+ }
+
+}
+?>
diff --git a/src/wp-includes/class-snoopy.php b/src/wp-includes/class-snoopy.php
new file mode 100644
index 0000000000..2c59c48112
--- /dev/null
+++ b/src/wp-includes/class-snoopy.php
@@ -0,0 +1,1256 @@
+<?php
+
+/**
+ * Deprecated. Use WP_HTTP (http.php, class-http.php) instead.
+ */
+_deprecated_file( basename( __FILE__ ), '3.0', WPINC . '/http.php' );
+
+if ( !class_exists( 'Snoopy' ) ) :
+/*************************************************
+
+Snoopy - the PHP net client
+Author: Monte Ohrt <monte@ispi.net>
+Copyright (c): 1999-2008 New Digital Group, all rights reserved
+Version: 1.2.4
+
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+You may contact the author of Snoopy by e-mail at:
+monte@ohrt.com
+
+The latest version of Snoopy can be obtained from:
+http://snoopy.sourceforge.net/
+
+*************************************************/
+
+class Snoopy
+{
+ /**** Public variables ****/
+
+ /* user definable vars */
+
+ var $host = "www.php.net"; // host name we are connecting to
+ var $port = 80; // port we are connecting to
+ var $proxy_host = ""; // proxy host to use
+ var $proxy_port = ""; // proxy port to use
+ var $proxy_user = ""; // proxy user to use
+ var $proxy_pass = ""; // proxy password to use
+
+ var $agent = "Snoopy v1.2.4"; // agent we masquerade as
+ var $referer = ""; // referer info to pass
+ var $cookies = array(); // array of cookies to pass
+ // $cookies["username"]="joe";
+ var $rawheaders = array(); // array of raw headers to send
+ // $rawheaders["Content-type"]="text/html";
+
+ var $maxredirs = 5; // http redirection depth maximum. 0 = disallow
+ var $lastredirectaddr = ""; // contains address of last redirected address
+ var $offsiteok = true; // allows redirection off-site
+ var $maxframes = 0; // frame content depth maximum. 0 = disallow
+ var $expandlinks = true; // expand links to fully qualified URLs.
+ // this only applies to fetchlinks()
+ // submitlinks(), and submittext()
+ var $passcookies = true; // pass set cookies back through redirects
+ // NOTE: this currently does not respect
+ // dates, domains or paths.
+
+ var $user = ""; // user for http authentication
+ var $pass = ""; // password for http authentication
+
+ // http accept types
+ var $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
+
+ var $results = ""; // where the content is put
+
+ var $error = ""; // error messages sent here
+ var $response_code = ""; // response code returned from server
+ var $headers = array(); // headers returned from server sent here
+ var $maxlength = 500000; // max return data length (body)
+ var $read_timeout = 0; // timeout on read operations, in seconds
+ // supported only since PHP 4 Beta 4
+ // set to 0 to disallow timeouts
+ var $timed_out = false; // if a read operation timed out
+ var $status = 0; // http request status
+
+ var $temp_dir = "/tmp"; // temporary directory that the webserver
+ // has permission to write to.
+ // under Windows, this should be C:\temp
+
+ var $curl_path = "/usr/local/bin/curl";
+ // Snoopy will use cURL for fetching
+ // SSL content if a full system path to
+ // the cURL binary is supplied here.
+ // set to false if you do not have
+ // cURL installed. See http://curl.haxx.se
+ // for details on installing cURL.
+ // Snoopy does *not* use the cURL
+ // library functions built into php,
+ // as these functions are not stable
+ // as of this Snoopy release.
+
+ /**** Private variables ****/
+
+ var $_maxlinelen = 4096; // max line length (headers)
+
+ var $_httpmethod = "GET"; // default http request method
+ var $_httpversion = "HTTP/1.0"; // default http request version
+ var $_submit_method = "POST"; // default submit method
+ var $_submit_type = "application/x-www-form-urlencoded"; // default submit type
+ var $_mime_boundary = ""; // MIME boundary for multipart/form-data submit type
+ var $_redirectaddr = false; // will be set if page fetched is a redirect
+ var $_redirectdepth = 0; // increments on an http redirect
+ var $_frameurls = array(); // frame src urls
+ var $_framedepth = 0; // increments on frame depth
+
+ var $_isproxy = false; // set if using a proxy server
+ var $_fp_timeout = 30; // timeout for socket connection
+
+/*======================================================================*\
+ Function: fetch
+ Purpose: fetch the contents of a web page
+ (and possibly other protocols in the
+ future like ftp, nntp, gopher, etc.)
+ Input: $URI the location of the page to fetch
+ Output: $this->results the output text from the fetch
+\*======================================================================*/
+
+ function fetch($URI)
+ {
+
+ //preg_match("|^([^:]+)://([^:/]+)(:[\d]+)*(.*)|",$URI,$URI_PARTS);
+ $URI_PARTS = parse_url($URI);
+ if (!empty($URI_PARTS["user"]))
+ $this->user = $URI_PARTS["user"];
+ if (!empty($URI_PARTS["pass"]))
+ $this->pass = $URI_PARTS["pass"];
+ if (empty($URI_PARTS["query"]))
+ $URI_PARTS["query"] = '';
+ if (empty($URI_PARTS["path"]))
+ $URI_PARTS["path"] = '';
+
+ switch(strtolower($URI_PARTS["scheme"]))
+ {
+ case "http":
+ $this->host = $URI_PARTS["host"];
+ if(!empty($URI_PARTS["port"]))
+ $this->port = $URI_PARTS["port"];
+ if($this->_connect($fp))
+ {
+ if($this->_isproxy)
+ {
+ // using proxy, send entire URI
+ $this->_httprequest($URI,$fp,$URI,$this->_httpmethod);
+ }
+ else
+ {
+ $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
+ // no proxy, send only the path
+ $this->_httprequest($path, $fp, $URI, $this->_httpmethod);
+ }
+
+ $this->_disconnect($fp);
+
+ if($this->_redirectaddr)
+ {
+ /* url was redirected, check if we've hit the max depth */
+ if($this->maxredirs > $this->_redirectdepth)
+ {
+ // only follow redirect if it's on this site, or offsiteok is true
+ if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
+ {
+ /* follow the redirect */
+ $this->_redirectdepth++;
+ $this->lastredirectaddr=$this->_redirectaddr;
+ $this->fetch($this->_redirectaddr);
+ }
+ }
+ }
+
+ if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
+ {
+ $frameurls = $this->_frameurls;
+ $this->_frameurls = array();
+
+ while(list(,$frameurl) = each($frameurls))
+ {
+ if($this->_framedepth < $this->maxframes)
+ {
+ $this->fetch($frameurl);
+ $this->_framedepth++;
+ }
+ else
+ break;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ break;
+ case "https":
+ if(!$this->curl_path)
+ return false;
+ if(function_exists("is_executable"))
+ if (!is_executable($this->curl_path))
+ return false;
+ $this->host = $URI_PARTS["host"];
+ if(!empty($URI_PARTS["port"]))
+ $this->port = $URI_PARTS["port"];
+ if($this->_isproxy)
+ {
+ // using proxy, send entire URI
+ $this->_httpsrequest($URI,$URI,$this->_httpmethod);
+ }
+ else
+ {
+ $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
+ // no proxy, send only the path
+ $this->_httpsrequest($path, $URI, $this->_httpmethod);
+ }
+
+ if($this->_redirectaddr)
+ {
+ /* url was redirected, check if we've hit the max depth */
+ if($this->maxredirs > $this->_redirectdepth)
+ {
+ // only follow redirect if it's on this site, or offsiteok is true
+ if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
+ {
+ /* follow the redirect */
+ $this->_redirectdepth++;
+ $this->lastredirectaddr=$this->_redirectaddr;
+ $this->fetch($this->_redirectaddr);
+ }
+ }
+ }
+
+ if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
+ {
+ $frameurls = $this->_frameurls;
+ $this->_frameurls = array();
+
+ while(list(,$frameurl) = each($frameurls))
+ {
+ if($this->_framedepth < $this->maxframes)
+ {
+ $this->fetch($frameurl);
+ $this->_framedepth++;
+ }
+ else
+ break;
+ }
+ }
+ return true;
+ break;
+ default:
+ // not a valid protocol
+ $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
+ return false;
+ break;
+ }
+ return true;
+ }
+
+/*======================================================================*\
+ Function: submit
+ Purpose: submit an http form
+ Input: $URI the location to post the data
+ $formvars the formvars to use.
+ format: $formvars["var"] = "val";
+ $formfiles an array of files to submit
+ format: $formfiles["var"] = "/dir/filename.ext";
+ Output: $this->results the text output from the post
+\*======================================================================*/
+
+ function submit($URI, $formvars="", $formfiles="")
+ {
+ unset($postdata);
+
+ $postdata = $this->_prepare_post_body($formvars, $formfiles);
+
+ $URI_PARTS = parse_url($URI);
+ if (!empty($URI_PARTS["user"]))
+ $this->user = $URI_PARTS["user"];
+ if (!empty($URI_PARTS["pass"]))
+ $this->pass = $URI_PARTS["pass"];
+ if (empty($URI_PARTS["query"]))
+ $URI_PARTS["query"] = '';
+ if (empty($URI_PARTS["path"]))
+ $URI_PARTS["path"] = '';
+
+ switch(strtolower($URI_PARTS["scheme"]))
+ {
+ case "http":
+ $this->host = $URI_PARTS["host"];
+ if(!empty($URI_PARTS["port"]))
+ $this->port = $URI_PARTS["port"];
+ if($this->_connect($fp))
+ {
+ if($this->_isproxy)
+ {
+ // using proxy, send entire URI
+ $this->_httprequest($URI,$fp,$URI,$this->_submit_method,$this->_submit_type,$postdata);
+ }
+ else
+ {
+ $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
+ // no proxy, send only the path
+ $this->_httprequest($path, $fp, $URI, $this->_submit_method, $this->_submit_type, $postdata);
+ }
+
+ $this->_disconnect($fp);
+
+ if($this->_redirectaddr)
+ {
+ /* url was redirected, check if we've hit the max depth */
+ if($this->maxredirs > $this->_redirectdepth)
+ {
+ if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr))
+ $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]);
+
+ // only follow redirect if it's on this site, or offsiteok is true
+ if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
+ {
+ /* follow the redirect */
+ $this->_redirectdepth++;
+ $this->lastredirectaddr=$this->_redirectaddr;
+ if( strpos( $this->_redirectaddr, "?" ) > 0 )
+ $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get
+ else
+ $this->submit($this->_redirectaddr,$formvars, $formfiles);
+ }
+ }
+ }
+
+ if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
+ {
+ $frameurls = $this->_frameurls;
+ $this->_frameurls = array();
+
+ while(list(,$frameurl) = each($frameurls))
+ {
+ if($this->_framedepth < $this->maxframes)
+ {
+ $this->fetch($frameurl);
+ $this->_framedepth++;
+ }
+ else
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ break;
+ case "https":
+ if(!$this->curl_path)
+ return false;
+ if(function_exists("is_executable"))
+ if (!is_executable($this->curl_path))
+ return false;
+ $this->host = $URI_PARTS["host"];
+ if(!empty($URI_PARTS["port"]))
+ $this->port = $URI_PARTS["port"];
+ if($this->_isproxy)
+ {
+ // using proxy, send entire URI
+ $this->_httpsrequest($URI, $URI, $this->_submit_method, $this->_submit_type, $postdata);
+ }
+ else
+ {
+ $path = $URI_PARTS["path"].($URI_PARTS["query"] ? "?".$URI_PARTS["query"] : "");
+ // no proxy, send only the path
+ $this->_httpsrequest($path, $URI, $this->_submit_method, $this->_submit_type, $postdata);
+ }
+
+ if($this->_redirectaddr)
+ {
+ /* url was redirected, check if we've hit the max depth */
+ if($this->maxredirs > $this->_redirectdepth)
+ {
+ if(!preg_match("|^".$URI_PARTS["scheme"]."://|", $this->_redirectaddr))
+ $this->_redirectaddr = $this->_expandlinks($this->_redirectaddr,$URI_PARTS["scheme"]."://".$URI_PARTS["host"]);
+
+ // only follow redirect if it's on this site, or offsiteok is true
+ if(preg_match("|^http://".preg_quote($this->host)."|i",$this->_redirectaddr) || $this->offsiteok)
+ {
+ /* follow the redirect */
+ $this->_redirectdepth++;
+ $this->lastredirectaddr=$this->_redirectaddr;
+ if( strpos( $this->_redirectaddr, "?" ) > 0 )
+ $this->fetch($this->_redirectaddr); // the redirect has changed the request method from post to get
+ else
+ $this->submit($this->_redirectaddr,$formvars, $formfiles);
+ }
+ }
+ }
+
+ if($this->_framedepth < $this->maxframes && count($this->_frameurls) > 0)
+ {
+ $frameurls = $this->_frameurls;
+ $this->_frameurls = array();
+
+ while(list(,$frameurl) = each($frameurls))
+ {
+ if($this->_framedepth < $this->maxframes)
+ {
+ $this->fetch($frameurl);
+ $this->_framedepth++;
+ }
+ else
+ break;
+ }
+ }
+ return true;
+ break;
+
+ default:
+ // not a valid protocol
+ $this->error = 'Invalid protocol "'.$URI_PARTS["scheme"].'"\n';
+ return false;
+ break;
+ }
+ return true;
+ }
+
+/*======================================================================*\
+ Function: fetchlinks
+ Purpose: fetch the links from a web page
+ Input: $URI where you are fetching from
+ Output: $this->results an array of the URLs
+\*======================================================================*/
+
+ function fetchlinks($URI)
+ {
+ if ($this->fetch($URI))
+ {
+ if($this->lastredirectaddr)
+ $URI = $this->lastredirectaddr;
+ if(is_array($this->results))
+ {
+ for($x=0;$x<count($this->results);$x++)
+ $this->results[$x] = $this->_striplinks($this->results[$x]);
+ }
+ else
+ $this->results = $this->_striplinks($this->results);
+
+ if($this->expandlinks)
+ $this->results = $this->_expandlinks($this->results, $URI);
+ return true;
+ }
+ else
+ return false;
+ }
+
+/*======================================================================*\
+ Function: fetchform
+ Purpose: fetch the form elements from a web page
+ Input: $URI where you are fetching from
+ Output: $this->results the resulting html form
+\*======================================================================*/
+
+ function fetchform($URI)
+ {
+
+ if ($this->fetch($URI))
+ {
+
+ if(is_array($this->results))
+ {
+ for($x=0;$x<count($this->results);$x++)
+ $this->results[$x] = $this->_stripform($this->results[$x]);
+ }
+ else
+ $this->results = $this->_stripform($this->results);
+
+ return true;
+ }
+ else
+ return false;
+ }
+
+
+/*======================================================================*\
+ Function: fetchtext
+ Purpose: fetch the text from a web page, stripping the links
+ Input: $URI where you are fetching from
+ Output: $this->results the text from the web page
+\*======================================================================*/
+
+ function fetchtext($URI)
+ {
+ if($this->fetch($URI))
+ {
+ if(is_array($this->results))
+ {
+ for($x=0;$x<count($this->results);$x++)
+ $this->results[$x] = $this->_striptext($this->results[$x]);
+ }
+ else
+ $this->results = $this->_striptext($this->results);
+ return true;
+ }
+ else
+ return false;
+ }
+
+/*======================================================================*\
+ Function: submitlinks
+ Purpose: grab links from a form submission
+ Input: $URI where you are submitting from
+ Output: $this->results an array of the links from the post
+\*======================================================================*/
+
+ function submitlinks($URI, $formvars="", $formfiles="")
+ {
+ if($this->submit($URI,$formvars, $formfiles))
+ {
+ if($this->lastredirectaddr)
+ $URI = $this->lastredirectaddr;
+ if(is_array($this->results))
+ {
+ for($x=0;$x<count($this->results);$x++)
+ {
+ $this->results[$x] = $this->_striplinks($this->results[$x]);
+ if($this->expandlinks)
+ $this->results[$x] = $this->_expandlinks($this->results[$x],$URI);
+ }
+ }
+ else
+ {
+ $this->results = $this->_striplinks($this->results);
+ if($this->expandlinks)
+ $this->results = $this->_expandlinks($this->results,$URI);
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+
+/*======================================================================*\
+ Function: submittext
+ Purpose: grab text from a form submission
+ Input: $URI where you are submitting from
+ Output: $this->results the text from the web page
+\*======================================================================*/
+
+ function submittext($URI, $formvars = "", $formfiles = "")
+ {
+ if($this->submit($URI,$formvars, $formfiles))
+ {
+ if($this->lastredirectaddr)
+ $URI = $this->lastredirectaddr;
+ if(is_array($this->results))
+ {
+ for($x=0;$x<count($this->results);$x++)
+ {
+ $this->results[$x] = $this->_striptext($this->results[$x]);
+ if($this->expandlinks)
+ $this->results[$x] = $this->_expandlinks($this->results[$x],$URI);
+ }
+ }
+ else
+ {
+ $this->results = $this->_striptext($this->results);
+ if($this->expandlinks)
+ $this->results = $this->_expandlinks($this->results,$URI);
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+
+
+
+/*======================================================================*\
+ Function: set_submit_multipart
+ Purpose: Set the form submission content type to
+ multipart/form-data
+\*======================================================================*/
+ function set_submit_multipart()
+ {
+ $this->_submit_type = "multipart/form-data";
+ }
+
+
+/*======================================================================*\
+ Function: set_submit_normal
+ Purpose: Set the form submission content type to
+ application/x-www-form-urlencoded
+\*======================================================================*/
+ function set_submit_normal()
+ {
+ $this->_submit_type = "application/x-www-form-urlencoded";
+ }
+
+
+
+
+/*======================================================================*\
+ Private functions
+\*======================================================================*/
+
+
+/*======================================================================*\
+ Function: _striplinks
+ Purpose: strip the hyperlinks from an html document
+ Input: $document document to strip.
+ Output: $match an array of the links
+\*======================================================================*/
+
+ function _striplinks($document)
+ {
+ preg_match_all("'<\s*a\s.*?href\s*=\s* # find <a href=
+ ([\"\'])? # find single or double quote
+ (?(1) (.*?)\\1 | ([^\s\>]+)) # if quote found, match up to next matching
+ # quote, otherwise match up to next space
+ 'isx",$document,$links);
+
+
+ // catenate the non-empty matches from the conditional subpattern
+
+ while(list($key,$val) = each($links[2]))
+ {
+ if(!empty($val))
+ $match[] = $val;
+ }
+
+ while(list($key,$val) = each($links[3]))
+ {
+ if(!empty($val))
+ $match[] = $val;
+ }
+
+ // return the links
+ return $match;
+ }
+
+/*======================================================================*\
+ Function: _stripform
+ Purpose: strip the form elements from an html document
+ Input: $document document to strip.
+ Output: $match an array of the links
+\*======================================================================*/
+
+ function _stripform($document)
+ {
+ preg_match_all("'<\/?(FORM|INPUT|SELECT|TEXTAREA|(OPTION))[^<>]*>(?(2)(.*(?=<\/?(option|select)[^<>]*>[\r\n]*)|(?=[\r\n]*))|(?=[\r\n]*))'Usi",$document,$elements);
+
+ // catenate the matches
+ $match = implode("\r\n",$elements[0]);
+
+ // return the links
+ return $match;
+ }
+
+
+
+/*======================================================================*\
+ Function: _striptext
+ Purpose: strip the text from an html document
+ Input: $document document to strip.
+ Output: $text the resulting text
+\*======================================================================*/
+
+ function _striptext($document)
+ {
+
+ // I didn't use preg eval (//e) since that is only available in PHP 4.0.
+ // so, list your entities one by one here. I included some of the
+ // more common ones.
+
+ $search = array("'<script[^>]*?>.*?</script>'si", // strip out javascript
+ "'<[\/\!]*?[^<>]*?>'si", // strip out html tags
+ "'([\r\n])[\s]+'", // strip out white space
+ "'&(quot|#34|#034|#x22);'i", // replace html entities
+ "'&(amp|#38|#038|#x26);'i", // added hexadecimal values
+ "'&(lt|#60|#060|#x3c);'i",
+ "'&(gt|#62|#062|#x3e);'i",
+ "'&(nbsp|#160|#xa0);'i",
+ "'&(iexcl|#161);'i",
+ "'&(cent|#162);'i",
+ "'&(pound|#163);'i",
+ "'&(copy|#169);'i",
+ "'&(reg|#174);'i",
+ "'&(deg|#176);'i",
+ "'&(#39|#039|#x27);'",
+ "'&(euro|#8364);'i", // europe
+ "'&a(uml|UML);'", // german
+ "'&o(uml|UML);'",
+ "'&u(uml|UML);'",
+ "'&A(uml|UML);'",
+ "'&O(uml|UML);'",
+ "'&U(uml|UML);'",
+ "'&szlig;'i",
+ );
+ $replace = array( "",
+ "",
+ "\\1",
+ "\"",
+ "&",
+ "<",
+ ">",
+ " ",
+ chr(161),
+ chr(162),
+ chr(163),
+ chr(169),
+ chr(174),
+ chr(176),
+ chr(39),
+ chr(128),
+ chr(0xE4), // ANSI &auml;
+ chr(0xF6), // ANSI &ouml;
+ chr(0xFC), // ANSI &uuml;
+ chr(0xC4), // ANSI &Auml;
+ chr(0xD6), // ANSI &Ouml;
+ chr(0xDC), // ANSI &Uuml;
+ chr(0xDF), // ANSI &szlig;
+ );
+
+ $text = preg_replace($search,$replace,$document);
+
+ return $text;
+ }
+
+/*======================================================================*\
+ Function: _expandlinks
+ Purpose: expand each link into a fully qualified URL
+ Input: $links the links to qualify
+ $URI the full URI to get the base from
+ Output: $expandedLinks the expanded links
+\*======================================================================*/
+
+ function _expandlinks($links,$URI)
+ {
+
+ preg_match("/^[^\?]+/",$URI,$match);
+
+ $match = preg_replace("|/[^\/\.]+\.[^\/\.]+$|","",$match[0]);
+ $match = preg_replace("|/$|","",$match);
+ $match_part = parse_url($match);
+ $match_root =
+ $match_part["scheme"]."://".$match_part["host"];
+
+ $search = array( "|^http://".preg_quote($this->host)."|i",
+ "|^(\/)|i",
+ "|^(?!http://)(?!mailto:)|i",
+ "|/\./|",
+ "|/[^\/]+/\.\./|"
+ );
+
+ $replace = array( "",
+ $match_root."/",
+ $match."/",
+ "/",
+ "/"
+ );
+
+ $expandedLinks = preg_replace($search,$replace,$links);
+
+ return $expandedLinks;
+ }
+
+/*======================================================================*\
+ Function: _httprequest
+ Purpose: go get the http data from the server
+ Input: $url the url to fetch
+ $fp the current open file pointer
+ $URI the full URI
+ $body body contents to send if any (POST)
+ Output:
+\*======================================================================*/
+
+ function _httprequest($url,$fp,$URI,$http_method,$content_type="",$body="")
+ {
+ $cookie_headers = '';
+ if($this->passcookies && $this->_redirectaddr)
+ $this->setcookies();
+
+ $URI_PARTS = parse_url($URI);
+ if(empty($url))
+ $url = "/";
+ $headers = $http_method." ".$url." ".$this->_httpversion."\r\n";
+ if(!empty($this->agent))
+ $headers .= "User-Agent: ".$this->agent."\r\n";
+ if(!empty($this->host) && !isset($this->rawheaders['Host'])) {
+ $headers .= "Host: ".$this->host;
+ if(!empty($this->port) && $this->port != 80)
+ $headers .= ":".$this->port;
+ $headers .= "\r\n";
+ }
+ if(!empty($this->accept))
+ $headers .= "Accept: ".$this->accept."\r\n";
+ if(!empty($this->referer))
+ $headers .= "Referer: ".$this->referer."\r\n";
+ if(!empty($this->cookies))
+ {
+ if(!is_array($this->cookies))
+ $this->cookies = (array)$this->cookies;
+
+ reset($this->cookies);
+ if ( count($this->cookies) > 0 ) {
+ $cookie_headers .= 'Cookie: ';
+ foreach ( $this->cookies as $cookieKey => $cookieVal ) {
+ $cookie_headers .= $cookieKey."=".urlencode($cookieVal)."; ";
+ }
+ $headers .= substr($cookie_headers,0,-2) . "\r\n";
+ }
+ }
+ if(!empty($this->rawheaders))
+ {
+ if(!is_array($this->rawheaders))
+ $this->rawheaders = (array)$this->rawheaders;
+ while(list($headerKey,$headerVal) = each($this->rawheaders))
+ $headers .= $headerKey.": ".$headerVal."\r\n";
+ }
+ if(!empty($content_type)) {
+ $headers .= "Content-type: $content_type";
+ if ($content_type == "multipart/form-data")
+ $headers .= "; boundary=".$this->_mime_boundary;
+ $headers .= "\r\n";
+ }
+ if(!empty($body))
+ $headers .= "Content-length: ".strlen($body)."\r\n";
+ if(!empty($this->user) || !empty($this->pass))
+ $headers .= "Authorization: Basic ".base64_encode($this->user.":".$this->pass)."\r\n";
+
+ //add proxy auth headers
+ if(!empty($this->proxy_user))
+ $headers .= 'Proxy-Authorization: ' . 'Basic ' . base64_encode($this->proxy_user . ':' . $this->proxy_pass)."\r\n";
+
+
+ $headers .= "\r\n";
+
+ // set the read timeout if needed
+ if ($this->read_timeout > 0)
+ socket_set_timeout($fp, $this->read_timeout);
+ $this->timed_out = false;
+
+ fwrite($fp,$headers.$body,strlen($headers.$body));
+
+ $this->_redirectaddr = false;
+ unset($this->headers);
+
+ while($currentHeader = fgets($fp,$this->_maxlinelen))
+ {
+ if ($this->read_timeout > 0 && $this->_check_timeout($fp))
+ {
+ $this->status=-100;
+ return false;
+ }
+
+ if($currentHeader == "\r\n")
+ break;
+
+ // if a header begins with Location: or URI:, set the redirect
+ if(preg_match("/^(Location:|URI:)/i",$currentHeader))
+ {
+ // get URL portion of the redirect
+ preg_match("/^(Location:|URI:)[ ]+(.*)/i",chop($currentHeader),$matches);
+ // look for :// in the Location header to see if hostname is included
+ if(!preg_match("|\:\/\/|",$matches[2]))
+ {
+ // no host in the path, so prepend
+ $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port;
+ // eliminate double slash
+ if(!preg_match("|^/|",$matches[2]))
+ $this->_redirectaddr .= "/".$matches[2];
+ else
+ $this->_redirectaddr .= $matches[2];
+ }
+ else
+ $this->_redirectaddr = $matches[2];
+ }
+
+ if(preg_match("|^HTTP/|",$currentHeader))
+ {
+ if(preg_match("|^HTTP/[^\s]*\s(.*?)\s|",$currentHeader, $status))
+ {
+ $this->status= $status[1];
+ }
+ $this->response_code = $currentHeader;
+ }
+
+ $this->headers[] = $currentHeader;
+ }
+
+ $results = '';
+ do {
+ $_data = fread($fp, $this->maxlength);
+ if (strlen($_data) == 0) {
+ break;
+ }
+ $results .= $_data;
+ } while(true);
+
+ if ($this->read_timeout > 0 && $this->_check_timeout($fp))
+ {
+ $this->status=-100;
+ return false;
+ }
+
+ // check if there is a redirect meta tag
+
+ if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
+
+ {
+ $this->_redirectaddr = $this->_expandlinks($match[1],$URI);
+ }
+
+ // have we hit our frame depth and is there frame src to fetch?
+ if(($this->_framedepth < $this->maxframes) && preg_match_all("'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i",$results,$match))
+ {
+ $this->results[] = $results;
+ for($x=0; $x<count($match[1]); $x++)
+ $this->_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host);
+ }
+ // have we already fetched framed content?
+ elseif(is_array($this->results))
+ $this->results[] = $results;
+ // no framed content
+ else
+ $this->results = $results;
+
+ return true;
+ }
+
+/*======================================================================*\
+ Function: _httpsrequest
+ Purpose: go get the https data from the server using curl
+ Input: $url the url to fetch
+ $URI the full URI
+ $body body contents to send if any (POST)
+ Output:
+\*======================================================================*/
+
+ function _httpsrequest($url,$URI,$http_method,$content_type="",$body="")
+ {
+ if($this->passcookies && $this->_redirectaddr)
+ $this->setcookies();
+
+ $headers = array();
+
+ $URI_PARTS = parse_url($URI);
+ if(empty($url))
+ $url = "/";
+ // GET ... header not needed for curl
+ //$headers[] = $http_method." ".$url." ".$this->_httpversion;
+ if(!empty($this->agent))
+ $headers[] = "User-Agent: ".$this->agent;
+ if(!empty($this->host))
+ if(!empty($this->port))
+ $headers[] = "Host: ".$this->host.":".$this->port;
+ else
+ $headers[] = "Host: ".$this->host;
+ if(!empty($this->accept))
+ $headers[] = "Accept: ".$this->accept;
+ if(!empty($this->referer))
+ $headers[] = "Referer: ".$this->referer;
+ if(!empty($this->cookies))
+ {
+ if(!is_array($this->cookies))
+ $this->cookies = (array)$this->cookies;
+
+ reset($this->cookies);
+ if ( count($this->cookies) > 0 ) {
+ $cookie_str = 'Cookie: ';
+ foreach ( $this->cookies as $cookieKey => $cookieVal ) {
+ $cookie_str .= $cookieKey."=".urlencode($cookieVal)."; ";
+ }
+ $headers[] = substr($cookie_str,0,-2);
+ }
+ }
+ if(!empty($this->rawheaders))
+ {
+ if(!is_array($this->rawheaders))
+ $this->rawheaders = (array)$this->rawheaders;
+ while(list($headerKey,$headerVal) = each($this->rawheaders))
+ $headers[] = $headerKey.": ".$headerVal;
+ }
+ if(!empty($content_type)) {
+ if ($content_type == "multipart/form-data")
+ $headers[] = "Content-type: $content_type; boundary=".$this->_mime_boundary;
+ else
+ $headers[] = "Content-type: $content_type";
+ }
+ if(!empty($body))
+ $headers[] = "Content-length: ".strlen($body);
+ if(!empty($this->user) || !empty($this->pass))
+ $headers[] = "Authorization: BASIC ".base64_encode($this->user.":".$this->pass);
+
+ for($curr_header = 0; $curr_header < count($headers); $curr_header++) {
+ $safer_header = strtr( $headers[$curr_header], "\"", " " );
+ $cmdline_params .= " -H \"".$safer_header."\"";
+ }
+
+ if(!empty($body))
+ $cmdline_params .= " -d \"$body\"";
+
+ if($this->read_timeout > 0)
+ $cmdline_params .= " -m ".$this->read_timeout;
+
+ $headerfile = tempnam($this->temp_dir, "sno");
+
+ exec($this->curl_path." -k -D \"$headerfile\"".$cmdline_params." \"".escapeshellcmd($URI)."\"",$results,$return);
+
+ if($return)
+ {
+ $this->error = "Error: cURL could not retrieve the document, error $return.";
+ return false;
+ }
+
+
+ $results = implode("\r\n",$results);
+
+ $result_headers = file("$headerfile");
+
+ $this->_redirectaddr = false;
+ unset($this->headers);
+
+ for($currentHeader = 0; $currentHeader < count($result_headers); $currentHeader++)
+ {
+
+ // if a header begins with Location: or URI:, set the redirect
+ if(preg_match("/^(Location: |URI: )/i",$result_headers[$currentHeader]))
+ {
+ // get URL portion of the redirect
+ preg_match("/^(Location: |URI:)\s+(.*)/",chop($result_headers[$currentHeader]),$matches);
+ // look for :// in the Location header to see if hostname is included
+ if(!preg_match("|\:\/\/|",$matches[2]))
+ {
+ // no host in the path, so prepend
+ $this->_redirectaddr = $URI_PARTS["scheme"]."://".$this->host.":".$this->port;
+ // eliminate double slash
+ if(!preg_match("|^/|",$matches[2]))
+ $this->_redirectaddr .= "/".$matches[2];
+ else
+ $this->_redirectaddr .= $matches[2];
+ }
+ else
+ $this->_redirectaddr = $matches[2];
+ }
+
+ if(preg_match("|^HTTP/|",$result_headers[$currentHeader]))
+ $this->response_code = $result_headers[$currentHeader];
+
+ $this->headers[] = $result_headers[$currentHeader];
+ }
+
+ // check if there is a redirect meta tag
+
+ if(preg_match("'<meta[\s]*http-equiv[^>]*?content[\s]*=[\s]*[\"\']?\d+;[\s]*URL[\s]*=[\s]*([^\"\']*?)[\"\']?>'i",$results,$match))
+ {
+ $this->_redirectaddr = $this->_expandlinks($match[1],$URI);
+ }
+
+ // have we hit our frame depth and is there frame src to fetch?
+ if(($this->_framedepth < $this->maxframes) && preg_match_all("'<frame\s+.*src[\s]*=[\'\"]?([^\'\"\>]+)'i",$results,$match))
+ {
+ $this->results[] = $results;
+ for($x=0; $x<count($match[1]); $x++)
+ $this->_frameurls[] = $this->_expandlinks($match[1][$x],$URI_PARTS["scheme"]."://".$this->host);
+ }
+ // have we already fetched framed content?
+ elseif(is_array($this->results))
+ $this->results[] = $results;
+ // no framed content
+ else
+ $this->results = $results;
+
+ unlink("$headerfile");
+
+ return true;
+ }
+
+/*======================================================================*\
+ Function: setcookies()
+ Purpose: set cookies for a redirection
+\*======================================================================*/
+
+ function setcookies()
+ {
+ for($x=0; $x<count($this->headers); $x++)
+ {
+ if(preg_match('/^set-cookie:[\s]+([^=]+)=([^;]+)/i', $this->headers[$x],$match))
+ $this->cookies[$match[1]] = urldecode($match[2]);
+ }
+ }
+
+
+/*======================================================================*\
+ Function: _check_timeout
+ Purpose: checks whether timeout has occurred
+ Input: $fp file pointer
+\*======================================================================*/
+
+ function _check_timeout($fp)
+ {
+ if ($this->read_timeout > 0) {
+ $fp_status = socket_get_status($fp);
+ if ($fp_status["timed_out"]) {
+ $this->timed_out = true;
+ return true;
+ }
+ }
+ return false;
+ }
+
+/*======================================================================*\
+ Function: _connect
+ Purpose: make a socket connection
+ Input: $fp file pointer
+\*======================================================================*/
+
+ function _connect(&$fp)
+ {
+ if(!empty($this->proxy_host) && !empty($this->proxy_port))
+ {
+ $this->_isproxy = true;
+
+ $host = $this->proxy_host;
+ $port = $this->proxy_port;
+ }
+ else
+ {
+ $host = $this->host;
+ $port = $this->port;
+ }
+
+ $this->status = 0;
+
+ if($fp = fsockopen(
+ $host,
+ $port,
+ $errno,
+ $errstr,
+ $this->_fp_timeout
+ ))
+ {
+ // socket connection succeeded
+
+ return true;
+ }
+ else
+ {
+ // socket connection failed
+ $this->status = $errno;
+ switch($errno)
+ {
+ case -3:
+ $this->error="socket creation failed (-3)";
+ case -4:
+ $this->error="dns lookup failure (-4)";
+ case -5:
+ $this->error="connection refused or timed out (-5)";
+ default:
+ $this->error="connection failed (".$errno.")";
+ }
+ return false;
+ }
+ }
+/*======================================================================*\
+ Function: _disconnect
+ Purpose: disconnect a socket connection
+ Input: $fp file pointer
+\*======================================================================*/
+
+ function _disconnect($fp)
+ {
+ return(fclose($fp));
+ }
+
+
+/*======================================================================*\
+ Function: _prepare_post_body
+ Purpose: Prepare post body according to encoding type
+ Input: $formvars - form variables
+ $formfiles - form upload files
+ Output: post body
+\*======================================================================*/
+
+ function _prepare_post_body($formvars, $formfiles)
+ {
+ settype($formvars, "array");
+ settype($formfiles, "array");
+ $postdata = '';
+
+ if (count($formvars) == 0 && count($formfiles) == 0)
+ return;
+
+ switch ($this->_submit_type) {
+ case "application/x-www-form-urlencoded":
+ reset($formvars);
+ while(list($key,$val) = each($formvars)) {
+ if (is_array($val) || is_object($val)) {
+ while (list($cur_key, $cur_val) = each($val)) {
+ $postdata .= urlencode($key)."[]=".urlencode($cur_val)."&";
+ }
+ } else
+ $postdata .= urlencode($key)."=".urlencode($val)."&";
+ }
+ break;
+
+ case "multipart/form-data":
+ $this->_mime_boundary = "Snoopy".md5(uniqid(microtime()));
+
+ reset($formvars);
+ while(list($key,$val) = each($formvars)) {
+ if (is_array($val) || is_object($val)) {
+ while (list($cur_key, $cur_val) = each($val)) {
+ $postdata .= "--".$this->_mime_boundary."\r\n";
+ $postdata .= "Content-Disposition: form-data; name=\"$key\[\]\"\r\n\r\n";
+ $postdata .= "$cur_val\r\n";
+ }
+ } else {
+ $postdata .= "--".$this->_mime_boundary."\r\n";
+ $postdata .= "Content-Disposition: form-data; name=\"$key\"\r\n\r\n";
+ $postdata .= "$val\r\n";
+ }
+ }
+
+ reset($formfiles);
+ while (list($field_name, $file_names) = each($formfiles)) {
+ settype($file_names, "array");
+ while (list(, $file_name) = each($file_names)) {
+ if (!is_readable($file_name)) continue;
+
+ $fp = fopen($file_name, "r");
+ $file_content = fread($fp, filesize($file_name));
+ fclose($fp);
+ $base_name = basename($file_name);
+
+ $postdata .= "--".$this->_mime_boundary."\r\n";
+ $postdata .= "Content-Disposition: form-data; name=\"$field_name\"; filename=\"$base_name\"\r\n\r\n";
+ $postdata .= "$file_content\r\n";
+ }
+ }
+ $postdata .= "--".$this->_mime_boundary."--\r\n";
+ break;
+ }
+
+ return $postdata;
+ }
+}
+endif;
+?>
diff --git a/src/wp-includes/class-wp-admin-bar.php b/src/wp-includes/class-wp-admin-bar.php
new file mode 100644
index 0000000000..1483da2d99
--- /dev/null
+++ b/src/wp-includes/class-wp-admin-bar.php
@@ -0,0 +1,492 @@
+<?php
+/**
+ * The WordPress Toolbar
+ *
+ * @since 3.1.0
+ *
+ * @package WordPress
+ * @subpackage Toolbar
+ */
+class WP_Admin_Bar {
+ private $nodes = array();
+ private $bound = false;
+ public $user;
+
+ public function __get( $name ) {
+ switch ( $name ) {
+ case 'proto' :
+ return is_ssl() ? 'https://' : 'http://';
+ break;
+ case 'menu' :
+ _deprecated_argument( 'WP_Admin_Bar', '3.3', 'Modify admin bar nodes with WP_Admin_Bar::get_node(), WP_Admin_Bar::add_node(), and WP_Admin_Bar::remove_node(), not the <code>menu</code> property.' );
+ return array(); // Sorry, folks.
+ break;
+ }
+ }
+
+ public function initialize() {
+ $this->user = new stdClass;
+
+ if ( is_user_logged_in() ) {
+ /* Populate settings we need for the menu based on the current user. */
+ $this->user->blogs = get_blogs_of_user( get_current_user_id() );
+ if ( is_multisite() ) {
+ $this->user->active_blog = get_active_blog_for_user( get_current_user_id() );
+ $this->user->domain = empty( $this->user->active_blog ) ? user_admin_url() : trailingslashit( get_home_url( $this->user->active_blog->blog_id ) );
+ $this->user->account_domain = $this->user->domain;
+ } else {
+ $this->user->active_blog = $this->user->blogs[get_current_blog_id()];
+ $this->user->domain = trailingslashit( home_url() );
+ $this->user->account_domain = $this->user->domain;
+ }
+ }
+
+ add_action( 'wp_head', 'wp_admin_bar_header' );
+
+ add_action( 'admin_head', 'wp_admin_bar_header' );
+
+ if ( current_theme_supports( 'admin-bar' ) ) {
+ $admin_bar_args = get_theme_support( 'admin-bar' ); // add_theme_support( 'admin-bar', array( 'callback' => '__return_false') );
+ $header_callback = $admin_bar_args[0]['callback'];
+ }
+
+ if ( empty($header_callback) )
+ $header_callback = '_admin_bar_bump_cb';
+
+ add_action('wp_head', $header_callback);
+
+ wp_enqueue_script( 'admin-bar' );
+ wp_enqueue_style( 'admin-bar' );
+
+ do_action( 'admin_bar_init' );
+ }
+
+ public function add_menu( $node ) {
+ $this->add_node( $node );
+ }
+
+ public function remove_menu( $id ) {
+ $this->remove_node( $id );
+ }
+
+ /**
+ * Add a node to the menu.
+ *
+ * @param array $args - The arguments for each node.
+ * - id - string - The ID of the item.
+ * - title - string - The title of the node.
+ * - parent - string - The ID of the parent node. Optional.
+ * - href - string - The link for the item. Optional.
+ * - group - boolean - If the node is a group. Optional. Default false.
+ * - meta - array - Meta data including the following keys: html, class, onclick, target, title, tabindex.
+ */
+ public function add_node( $args ) {
+ // Shim for old method signature: add_node( $parent_id, $menu_obj, $args )
+ if ( func_num_args() >= 3 && is_string( func_get_arg(0) ) )
+ $args = array_merge( array( 'parent' => func_get_arg(0) ), func_get_arg(2) );
+
+ if ( is_object( $args ) )
+ $args = get_object_vars( $args );
+
+ // Ensure we have a valid title.
+ if ( empty( $args['id'] ) ) {
+ if ( empty( $args['title'] ) )
+ return;
+
+ _doing_it_wrong( __METHOD__, __( 'The menu ID should not be empty.' ), '3.3' );
+ // Deprecated: Generate an ID from the title.
+ $args['id'] = esc_attr( sanitize_title( trim( $args['title'] ) ) );
+ }
+
+ $defaults = array(
+ 'id' => false,
+ 'title' => false,
+ 'parent' => false,
+ 'href' => false,
+ 'group' => false,
+ 'meta' => array(),
+ );
+
+ // If the node already exists, keep any data that isn't provided.
+ if ( $maybe_defaults = $this->get_node( $args['id'] ) )
+ $defaults = get_object_vars( $maybe_defaults );
+
+ // Do the same for 'meta' items.
+ if ( ! empty( $defaults['meta'] ) && ! empty( $args['meta'] ) )
+ $args['meta'] = wp_parse_args( $args['meta'], $defaults['meta'] );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ $back_compat_parents = array(
+ 'my-account-with-avatar' => array( 'my-account', '3.3' ),
+ 'my-blogs' => array( 'my-sites', '3.3' ),
+ );
+
+ if ( isset( $back_compat_parents[ $args['parent'] ] ) ) {
+ list( $new_parent, $version ) = $back_compat_parents[ $args['parent'] ];
+ _deprecated_argument( __METHOD__, $version, sprintf( 'Use <code>%s</code> as the parent for the <code>%s</code> admin bar node instead of <code>%s</code>.', $new_parent, $args['id'], $args['parent'] ) );
+ $args['parent'] = $new_parent;
+ }
+
+ $this->_set_node( $args );
+ }
+
+ final protected function _set_node( $args ) {
+ $this->nodes[ $args['id'] ] = (object) $args;
+ }
+
+ /**
+ * Gets a node.
+ *
+ * @return object Node.
+ */
+ final public function get_node( $id ) {
+ if ( $node = $this->_get_node( $id ) )
+ return clone $node;
+ }
+
+ final protected function _get_node( $id ) {
+ if ( $this->bound )
+ return;
+
+ if ( empty( $id ) )
+ $id = 'root';
+
+ if ( isset( $this->nodes[ $id ] ) )
+ return $this->nodes[ $id ];
+ }
+
+ final public function get_nodes() {
+ if ( ! $nodes = $this->_get_nodes() )
+ return;
+
+ foreach ( $nodes as &$node ) {
+ $node = clone $node;
+ }
+ return $nodes;
+ }
+
+ final protected function _get_nodes() {
+ if ( $this->bound )
+ return;
+
+ return $this->nodes;
+ }
+
+ /**
+ * Add a group to a menu node.
+ *
+ * @since 3.3.0
+ *
+ * @param array $args - The arguments for each node.
+ * - id - string - The ID of the item.
+ * - parent - string - The ID of the parent node. Optional. Default root.
+ * - meta - array - Meta data including the following keys: class, onclick, target, title.
+ */
+ final public function add_group( $args ) {
+ $args['group'] = true;
+
+ $this->add_node( $args );
+ }
+
+ /**
+ * Remove a node.
+ *
+ * @param string The ID of the item.
+ */
+ public function remove_node( $id ) {
+ $this->_unset_node( $id );
+ }
+
+ final protected function _unset_node( $id ) {
+ unset( $this->nodes[ $id ] );
+ }
+
+ public function render() {
+ $root = $this->_bind();
+ if ( $root )
+ $this->_render( $root );
+ }
+
+ final protected function _bind() {
+ if ( $this->bound )
+ return;
+
+ // Add the root node.
+ // Clear it first, just in case. Don't mess with The Root.
+ $this->remove_node( 'root' );
+ $this->add_node( array(
+ 'id' => 'root',
+ 'group' => false,
+ ) );
+
+ // Normalize nodes: define internal 'children' and 'type' properties.
+ foreach ( $this->_get_nodes() as $node ) {
+ $node->children = array();
+ $node->type = ( $node->group ) ? 'group' : 'item';
+ unset( $node->group );
+
+ // The Root wants your orphans. No lonely items allowed.
+ if ( ! $node->parent )
+ $node->parent = 'root';
+ }
+
+ foreach ( $this->_get_nodes() as $node ) {
+ if ( 'root' == $node->id )
+ continue;
+
+ // Fetch the parent node. If it isn't registered, ignore the node.
+ if ( ! $parent = $this->_get_node( $node->parent ) ) {
+ continue;
+ }
+
+ // Generate the group class (we distinguish between top level and other level groups).
+ $group_class = ( $node->parent == 'root' ) ? 'ab-top-menu' : 'ab-submenu';
+
+ if ( $node->type == 'group' ) {
+ if ( empty( $node->meta['class'] ) )
+ $node->meta['class'] = $group_class;
+ else
+ $node->meta['class'] .= ' ' . $group_class;
+ }
+
+ // Items in items aren't allowed. Wrap nested items in 'default' groups.
+ if ( $parent->type == 'item' && $node->type == 'item' ) {
+ $default_id = $parent->id . '-default';
+ $default = $this->_get_node( $default_id );
+
+ // The default group is added here to allow groups that are
+ // added before standard menu items to render first.
+ if ( ! $default ) {
+ // Use _set_node because add_node can be overloaded.
+ // Make sure to specify default settings for all properties.
+ $this->_set_node( array(
+ 'id' => $default_id,
+ 'parent' => $parent->id,
+ 'type' => 'group',
+ 'children' => array(),
+ 'meta' => array(
+ 'class' => $group_class,
+ ),
+ 'title' => false,
+ 'href' => false,
+ ) );
+ $default = $this->_get_node( $default_id );
+ $parent->children[] = $default;
+ }
+ $parent = $default;
+
+ // Groups in groups aren't allowed. Add a special 'container' node.
+ // The container will invisibly wrap both groups.
+ } elseif ( $parent->type == 'group' && $node->type == 'group' ) {
+ $container_id = $parent->id . '-container';
+ $container = $this->_get_node( $container_id );
+
+ // We need to create a container for this group, life is sad.
+ if ( ! $container ) {
+ // Use _set_node because add_node can be overloaded.
+ // Make sure to specify default settings for all properties.
+ $this->_set_node( array(
+ 'id' => $container_id,
+ 'type' => 'container',
+ 'children' => array( $parent ),
+ 'parent' => false,
+ 'title' => false,
+ 'href' => false,
+ 'meta' => array(),
+ ) );
+
+ $container = $this->_get_node( $container_id );
+
+ // Link the container node if a grandparent node exists.
+ $grandparent = $this->_get_node( $parent->parent );
+
+ if ( $grandparent ) {
+ $container->parent = $grandparent->id;
+
+ $index = array_search( $parent, $grandparent->children, true );
+ if ( $index === false )
+ $grandparent->children[] = $container;
+ else
+ array_splice( $grandparent->children, $index, 1, array( $container ) );
+ }
+
+ $parent->parent = $container->id;
+ }
+
+ $parent = $container;
+ }
+
+ // Update the parent ID (it might have changed).
+ $node->parent = $parent->id;
+
+ // Add the node to the tree.
+ $parent->children[] = $node;
+ }
+
+ $root = $this->_get_node( 'root' );
+ $this->bound = true;
+ return $root;
+ }
+
+ final protected function _render( $root ) {
+ global $is_IE;
+
+ // Add browser classes.
+ // We have to do this here since admin bar shows on the front end.
+ $class = 'nojq nojs';
+ if ( $is_IE ) {
+ if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) )
+ $class .= ' ie7';
+ elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) )
+ $class .= ' ie8';
+ elseif ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 9' ) )
+ $class .= ' ie9';
+ } elseif ( wp_is_mobile() ) {
+ $class .= ' mobile';
+ }
+
+ ?>
+ <div id="wpadminbar" class="<?php echo $class; ?>" role="navigation">
+ <a class="screen-reader-shortcut" href="#wp-toolbar" tabindex="1"><?php _e('Skip to toolbar'); ?></a>
+ <div class="quicklinks" id="wp-toolbar" role="navigation" aria-label="<?php esc_attr_e('Top navigation toolbar.'); ?>" tabindex="0">
+ <?php foreach ( $root->children as $group ) {
+ $this->_render_group( $group );
+ } ?>
+ </div>
+ <?php if ( is_user_logged_in() ) : ?>
+ <a class="screen-reader-shortcut" href="<?php echo esc_url( wp_logout_url() ); ?>"><?php _e('Log Out'); ?></a>
+ <?php endif; ?>
+ </div>
+
+ <?php
+ }
+
+ final protected function _render_container( $node ) {
+ if ( $node->type != 'container' || empty( $node->children ) )
+ return;
+
+ ?><div id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>" class="ab-group-container"><?php
+ foreach ( $node->children as $group ) {
+ $this->_render_group( $group );
+ }
+ ?></div><?php
+ }
+
+ final protected function _render_group( $node ) {
+ if ( $node->type == 'container' )
+ return $this->_render_container( $node );
+
+ if ( $node->type != 'group' || empty( $node->children ) )
+ return;
+
+ if ( ! empty( $node->meta['class'] ) )
+ $class = ' class="' . esc_attr( trim( $node->meta['class'] ) ) . '"';
+ else
+ $class = '';
+
+ ?><ul id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $class; ?>><?php
+ foreach ( $node->children as $item ) {
+ $this->_render_item( $item );
+ }
+ ?></ul><?php
+ }
+
+ final protected function _render_item( $node ) {
+ if ( $node->type != 'item' )
+ return;
+
+ $is_parent = ! empty( $node->children );
+ $has_link = ! empty( $node->href );
+
+ $tabindex = isset( $node->meta['tabindex'] ) ? (int) $node->meta['tabindex'] : '';
+ $aria_attributes = $tabindex ? 'tabindex="' . $tabindex . '"' : '';
+
+ $menuclass = '';
+
+ if ( $is_parent ) {
+ $menuclass = 'menupop ';
+ $aria_attributes .= ' aria-haspopup="true"';
+ }
+
+ if ( ! empty( $node->meta['class'] ) )
+ $menuclass .= $node->meta['class'];
+
+ if ( $menuclass )
+ $menuclass = ' class="' . esc_attr( trim( $menuclass ) ) . '"';
+
+ ?>
+
+ <li id="<?php echo esc_attr( 'wp-admin-bar-' . $node->id ); ?>"<?php echo $menuclass; ?>><?php
+ if ( $has_link ):
+ ?><a class="ab-item" <?php echo $aria_attributes; ?> href="<?php echo esc_url( $node->href ) ?>"<?php
+ if ( ! empty( $node->meta['onclick'] ) ) :
+ ?> onclick="<?php echo esc_js( $node->meta['onclick'] ); ?>"<?php
+ endif;
+ if ( ! empty( $node->meta['target'] ) ) :
+ ?> target="<?php echo esc_attr( $node->meta['target'] ); ?>"<?php
+ endif;
+ if ( ! empty( $node->meta['title'] ) ) :
+ ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php
+ endif;
+ ?>><?php
+ else:
+ ?><div class="ab-item ab-empty-item" <?php echo $aria_attributes;
+ if ( ! empty( $node->meta['title'] ) ) :
+ ?> title="<?php echo esc_attr( $node->meta['title'] ); ?>"<?php
+ endif;
+ ?>><?php
+ endif;
+
+ echo $node->title;
+
+ if ( $has_link ) :
+ ?></a><?php
+ else:
+ ?></div><?php
+ endif;
+
+ if ( $is_parent ) :
+ ?><div class="ab-sub-wrapper"><?php
+ foreach ( $node->children as $group ) {
+ $this->_render_group( $group );
+ }
+ ?></div><?php
+ endif;
+
+ if ( ! empty( $node->meta['html'] ) )
+ echo $node->meta['html'];
+
+ ?>
+ </li><?php
+ }
+
+ public function recursive_render( $id, $node ) {
+ _deprecated_function( __METHOD__, '3.3', 'WP_Admin_bar::render(), WP_Admin_Bar::_render_item()' );
+ $this->_render_item( $node );
+ }
+
+ public function add_menus() {
+ // User related, aligned right.
+ add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_menu', 0 );
+ add_action( 'admin_bar_menu', 'wp_admin_bar_search_menu', 4 );
+ add_action( 'admin_bar_menu', 'wp_admin_bar_my_account_item', 7 );
+
+ // Site related.
+ add_action( 'admin_bar_menu', 'wp_admin_bar_wp_menu', 10 );
+ add_action( 'admin_bar_menu', 'wp_admin_bar_my_sites_menu', 20 );
+ add_action( 'admin_bar_menu', 'wp_admin_bar_site_menu', 30 );
+ add_action( 'admin_bar_menu', 'wp_admin_bar_updates_menu', 40 );
+
+ // Content related.
+ if ( ! is_network_admin() && ! is_user_admin() ) {
+ add_action( 'admin_bar_menu', 'wp_admin_bar_comments_menu', 60 );
+ add_action( 'admin_bar_menu', 'wp_admin_bar_new_content_menu', 70 );
+ }
+ add_action( 'admin_bar_menu', 'wp_admin_bar_edit_menu', 80 );
+
+ add_action( 'admin_bar_menu', 'wp_admin_bar_add_secondary_groups', 200 );
+
+ do_action( 'add_admin_bar_menus' );
+ }
+}
diff --git a/src/wp-includes/class-wp-ajax-response.php b/src/wp-includes/class-wp-ajax-response.php
new file mode 100644
index 0000000000..24eb687f12
--- /dev/null
+++ b/src/wp-includes/class-wp-ajax-response.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * Send XML response back to AJAX request.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ */
+class WP_Ajax_Response {
+ /**
+ * Store XML responses to send.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $responses = array();
+
+ /**
+ * Constructor - Passes args to {@link WP_Ajax_Response::add()}.
+ *
+ * @since 2.1.0
+ * @see WP_Ajax_Response::add()
+ *
+ * @param string|array $args Optional. Will be passed to add() method.
+ * @return WP_Ajax_Response
+ */
+ function __construct( $args = '' ) {
+ if ( !empty($args) )
+ $this->add($args);
+ }
+
+ /**
+ * Append to XML response based on given arguments.
+ *
+ * The arguments that can be passed in the $args parameter are below. It is
+ * also possible to pass a WP_Error object in either the 'id' or 'data'
+ * argument. The parameter isn't actually optional, content should be given
+ * in order to send the correct response.
+ *
+ * 'what' argument is a string that is the XMLRPC response type.
+ * 'action' argument is a boolean or string that acts like a nonce.
+ * 'id' argument can be WP_Error or an integer.
+ * 'old_id' argument is false by default or an integer of the previous ID.
+ * 'position' argument is an integer or a string with -1 = top, 1 = bottom,
+ * html ID = after, -html ID = before.
+ * 'data' argument is a string with the content or message.
+ * 'supplemental' argument is an array of strings that will be children of
+ * the supplemental element.
+ *
+ * @since 2.1.0
+ *
+ * @param string|array $args Override defaults.
+ * @return string XML response.
+ */
+ function add( $args = '' ) {
+ $defaults = array(
+ 'what' => 'object', 'action' => false,
+ 'id' => '0', 'old_id' => false,
+ 'position' => 1,
+ 'data' => '', 'supplemental' => array()
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+ $position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
+
+ if ( is_wp_error($id) ) {
+ $data = $id;
+ $id = 0;
+ }
+
+ $response = '';
+ if ( is_wp_error($data) ) {
+ foreach ( (array) $data->get_error_codes() as $code ) {
+ $response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
+ if ( !$error_data = $data->get_error_data($code) )
+ continue;
+ $class = '';
+ if ( is_object($error_data) ) {
+ $class = ' class="' . get_class($error_data) . '"';
+ $error_data = get_object_vars($error_data);
+ }
+
+ $response .= "<wp_error_data code='$code'$class>";
+
+ if ( is_scalar($error_data) ) {
+ $response .= "<![CDATA[$error_data]]>";
+ } elseif ( is_array($error_data) ) {
+ foreach ( $error_data as $k => $v )
+ $response .= "<$k><![CDATA[$v]]></$k>";
+ }
+
+ $response .= "</wp_error_data>";
+ }
+ } else {
+ $response = "<response_data><![CDATA[$data]]></response_data>";
+ }
+
+ $s = '';
+ if ( is_array($supplemental) ) {
+ foreach ( $supplemental as $k => $v )
+ $s .= "<$k><![CDATA[$v]]></$k>";
+ $s = "<supplemental>$s</supplemental>";
+ }
+
+ if ( false === $action )
+ $action = $_POST['action'];
+
+ $x = '';
+ $x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
+ $x .= "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
+ $x .= $response;
+ $x .= $s;
+ $x .= "</$what>";
+ $x .= "</response>";
+
+ $this->responses[] = $x;
+ return $x;
+ }
+
+ /**
+ * Display XML formatted responses.
+ *
+ * Sets the content type header to text/xml.
+ *
+ * @since 2.1.0
+ */
+ function send() {
+ header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ) );
+ echo "<?xml version='1.0' encoding='" . get_option( 'blog_charset' ) . "' standalone='yes'?><wp_ajax>";
+ foreach ( (array) $this->responses as $response )
+ echo $response;
+ echo '</wp_ajax>';
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
+ wp_die();
+ else
+ die();
+ }
+}
diff --git a/src/wp-includes/class-wp-customize-control.php b/src/wp-includes/class-wp-customize-control.php
new file mode 100644
index 0000000000..fde8561584
--- /dev/null
+++ b/src/wp-includes/class-wp-customize-control.php
@@ -0,0 +1,817 @@
+<?php
+/**
+ * Customize Control Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Control {
+ /**
+ * @access public
+ * @var WP_Customize_Manager
+ */
+ public $manager;
+
+ /**
+ * @access public
+ * @var string
+ */
+ public $id;
+
+ /**
+ * All settings tied to the control.
+ *
+ * @access public
+ * @var array
+ */
+ public $settings;
+
+ /**
+ * The primary setting for the control (if there is one).
+ *
+ * @access public
+ * @var string
+ */
+ public $setting = 'default';
+
+ /**
+ * @access public
+ * @var int
+ */
+ public $priority = 10;
+
+ /**
+ * @access public
+ * @var string
+ */
+ public $section = '';
+
+ /**
+ * @access public
+ * @var string
+ */
+ public $label = '';
+
+ /**
+ * @todo: Remove choices
+ *
+ * @access public
+ * @var array
+ */
+ public $choices = array();
+
+ /**
+ * @access public
+ * @var array
+ */
+ public $json = array();
+
+ /**
+ * @access public
+ * @var string
+ */
+ public $type = 'text';
+
+
+ /**
+ * Constructor.
+ *
+ * If $args['settings'] is not defined, use the $id as the setting ID.
+ *
+ * @since 3.4.0
+ *
+ * @param WP_Customize_Manager $manager
+ * @param string $id
+ * @param array $args
+ */
+ function __construct( $manager, $id, $args = array() ) {
+ $keys = array_keys( get_object_vars( $this ) );
+ foreach ( $keys as $key ) {
+ if ( isset( $args[ $key ] ) )
+ $this->$key = $args[ $key ];
+ }
+
+ $this->manager = $manager;
+ $this->id = $id;
+
+
+ // Process settings.
+ if ( empty( $this->settings ) )
+ $this->settings = $id;
+
+ $settings = array();
+ if ( is_array( $this->settings ) ) {
+ foreach ( $this->settings as $key => $setting ) {
+ $settings[ $key ] = $this->manager->get_setting( $setting );
+ }
+ } else {
+ $this->setting = $this->manager->get_setting( $this->settings );
+ $settings['default'] = $this->setting;
+ }
+ $this->settings = $settings;
+ }
+
+ /**
+ * Enqueue control related scripts/styles.
+ *
+ * @since 3.4.0
+ */
+ public function enqueue() {}
+
+
+ /**
+ * Fetch a setting's value.
+ * Grabs the main setting by default.
+ *
+ * @since 3.4.0
+ *
+ * @param string $setting_key
+ * @return mixed The requested setting's value, if the setting exists.
+ */
+ public final function value( $setting_key = 'default' ) {
+ if ( isset( $this->settings[ $setting_key ] ) )
+ return $this->settings[ $setting_key ]->value();
+ }
+
+ /**
+ * Refresh the parameters passed to the JavaScript via JSON.
+ *
+ * @since 3.4.0
+ */
+ public function to_json() {
+ $this->json['settings'] = array();
+ foreach ( $this->settings as $key => $setting ) {
+ $this->json['settings'][ $key ] = $setting->id;
+ }
+
+ $this->json['type'] = $this->type;
+ }
+
+ /**
+ * Check if the theme supports the control and check user capabilities.
+ *
+ * @since 3.4.0
+ *
+ * @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true.
+ */
+ public final function check_capabilities() {
+ foreach ( $this->settings as $setting ) {
+ if ( ! $setting->check_capabilities() )
+ return false;
+ }
+
+ $section = $this->manager->get_section( $this->section );
+ if ( isset( $section ) && ! $section->check_capabilities() )
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Check capabilities and render the control.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Control::render()
+ */
+ public final function maybe_render() {
+ if ( ! $this->check_capabilities() )
+ return;
+
+ do_action( 'customize_render_control', $this );
+ do_action( 'customize_render_control_' . $this->id, $this );
+
+ $this->render();
+ }
+
+ /**
+ * Render the control. Renders the control wrapper, then calls $this->render_content().
+ *
+ * @since 3.4.0
+ */
+ protected function render() {
+ $id = 'customize-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) );
+ $class = 'customize-control customize-control-' . $this->type;
+
+ ?><li id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $class ); ?>">
+ <?php $this->render_content(); ?>
+ </li><?php
+ }
+
+ /**
+ * Get the data link parameter for a setting.
+ *
+ * @since 3.4.0
+ *
+ * @param string $setting_key
+ * @return string Data link parameter, if $setting_key is a valid setting, empty string otherwise.
+ */
+ public function get_link( $setting_key = 'default' ) {
+ if ( ! isset( $this->settings[ $setting_key ] ) )
+ return '';
+
+ return 'data-customize-setting-link="' . esc_attr( $this->settings[ $setting_key ]->id ) . '"';
+ }
+
+ /**
+ * Render the data link parameter for a setting
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Control::get_link()
+ *
+ * @param string $setting_key
+ */
+ public function link( $setting_key = 'default' ) {
+ echo $this->get_link( $setting_key );
+ }
+
+ /**
+ * Render the control's content.
+ *
+ * Allows the content to be overriden without having to rewrite the wrapper.
+ *
+ * @since 3.4.0
+ */
+ protected function render_content() {
+ switch( $this->type ) {
+ case 'text':
+ ?>
+ <label>
+ <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
+ <input type="text" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); ?> />
+ </label>
+ <?php
+ break;
+ case 'checkbox':
+ ?>
+ <label>
+ <input type="checkbox" value="<?php echo esc_attr( $this->value() ); ?>" <?php $this->link(); checked( $this->value() ); ?> />
+ <?php echo esc_html( $this->label ); ?>
+ </label>
+ <?php
+ break;
+ case 'radio':
+ if ( empty( $this->choices ) )
+ return;
+
+ $name = '_customize-radio-' . $this->id;
+
+ ?>
+ <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
+ <?php
+ foreach ( $this->choices as $value => $label ) :
+ ?>
+ <label>
+ <input type="radio" value="<?php echo esc_attr( $value ); ?>" name="<?php echo esc_attr( $name ); ?>" <?php $this->link(); checked( $this->value(), $value ); ?> />
+ <?php echo esc_html( $label ); ?><br/>
+ </label>
+ <?php
+ endforeach;
+ break;
+ case 'select':
+ if ( empty( $this->choices ) )
+ return;
+
+ ?>
+ <label>
+ <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
+ <select <?php $this->link(); ?>>
+ <?php
+ foreach ( $this->choices as $value => $label )
+ echo '<option value="' . esc_attr( $value ) . '"' . selected( $this->value(), $value, false ) . '>' . $label . '</option>';
+ ?>
+ </select>
+ </label>
+ <?php
+ break;
+ case 'dropdown-pages':
+ $dropdown = wp_dropdown_pages(
+ array(
+ 'name' => '_customize-dropdown-pages-' . $this->id,
+ 'echo' => 0,
+ 'show_option_none' => __( '&mdash; Select &mdash;' ),
+ 'option_none_value' => '0',
+ 'selected' => $this->value(),
+ )
+ );
+
+ // Hackily add in the data link parameter.
+ $dropdown = str_replace( '<select', '<select ' . $this->get_link(), $dropdown );
+
+ printf(
+ '<label class="customize-control-select"><span class="customize-control-title">%s</span> %s</label>',
+ $this->label,
+ $dropdown
+ );
+ break;
+ }
+ }
+}
+
+/**
+ * Customize Color Control Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Color_Control extends WP_Customize_Control {
+ /**
+ * @access public
+ * @var string
+ */
+ public $type = 'color';
+
+ /**
+ * @access public
+ * @var array
+ */
+ public $statuses;
+
+ /**
+ * Constructor.
+ *
+ * If $args['settings'] is not defined, use the $id as the setting ID.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Control::__construct()
+ *
+ * @param WP_Customize_Manager $manager
+ * @param string $id
+ * @param array $args
+ */
+ public function __construct( $manager, $id, $args = array() ) {
+ $this->statuses = array( '' => __('Default') );
+ parent::__construct( $manager, $id, $args );
+ }
+
+ /**
+ * Enqueue control related scripts/styles.
+ *
+ * @since 3.4.0
+ */
+ public function enqueue() {
+ wp_enqueue_script( 'wp-color-picker' );
+ wp_enqueue_style( 'wp-color-picker' );
+ }
+
+ /**
+ * Refresh the parameters passed to the JavaScript via JSON.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Control::to_json()
+ */
+ public function to_json() {
+ parent::to_json();
+ $this->json['statuses'] = $this->statuses;
+ }
+
+ /**
+ * Render the control's content.
+ *
+ * @since 3.4.0
+ */
+ public function render_content() {
+ $this_default = $this->setting->default;
+ $default_attr = '';
+ if ( $this_default ) {
+ if ( false === strpos( $this_default, '#' ) )
+ $this_default = '#' . $this_default;
+ $default_attr = ' data-default-color="' . esc_attr( $this_default ) . '"';
+ }
+ // The input's value gets set by JS. Don't fill it.
+ ?>
+ <label>
+ <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
+ <div class="customize-control-content">
+ <input class="color-picker-hex" type="text" maxlength="7" placeholder="<?php esc_attr_e( 'Hex Value' ); ?>"<?php echo $default_attr; ?> />
+ </div>
+ </label>
+ <?php
+ }
+}
+
+/**
+ * Customize Upload Control Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Upload_Control extends WP_Customize_Control {
+ public $type = 'upload';
+ public $removed = '';
+ public $context;
+ public $extensions = array();
+
+ /**
+ * Enqueue control related scripts/styles.
+ *
+ * @since 3.4.0
+ */
+ public function enqueue() {
+ wp_enqueue_script( 'wp-plupload' );
+ }
+
+ /**
+ * Refresh the parameters passed to the JavaScript via JSON.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Control::to_json()
+ */
+ public function to_json() {
+ parent::to_json();
+
+ $this->json['removed'] = $this->removed;
+
+ if ( $this->context )
+ $this->json['context'] = $this->context;
+
+ if ( $this->extensions )
+ $this->json['extensions'] = implode( ',', $this->extensions );
+ }
+
+ /**
+ * Render the control's content.
+ *
+ * @since 3.4.0
+ */
+ public function render_content() {
+ ?>
+ <label>
+ <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
+ <div>
+ <a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a>
+ <a href="#" class="remove"><?php _e( 'Remove' ); ?></a>
+ </div>
+ </label>
+ <?php
+ }
+}
+
+/**
+ * Customize Image Control Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
+ public $type = 'image';
+ public $get_url;
+ public $statuses;
+ public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' );
+
+ protected $tabs = array();
+
+ /**
+ * Constructor.
+ *
+ * If $args['settings'] is not defined, use the $id as the setting ID.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Upload_Control::__construct()
+ *
+ * @param WP_Customize_Manager $manager
+ * @param string $id
+ * @param array $args
+ */
+ public function __construct( $manager, $id, $args ) {
+ $this->statuses = array( '' => __('No Image') );
+
+ parent::__construct( $manager, $id, $args );
+
+ $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) );
+ $this->add_tab( 'uploaded', __('Uploaded'), array( $this, 'tab_uploaded' ) );
+
+ // Early priority to occur before $this->manager->prepare_controls();
+ add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 );
+ }
+
+ /**
+ * Prepares the control.
+ *
+ * If no tabs exist, removes the control from the manager.
+ *
+ * @since 3.4.2
+ */
+ public function prepare_control() {
+ if ( ! $this->tabs )
+ $this->manager->remove_control( $this->id );
+ }
+
+ /**
+ * Refresh the parameters passed to the JavaScript via JSON.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Upload_Control::to_json()
+ */
+ public function to_json() {
+ parent::to_json();
+ $this->json['statuses'] = $this->statuses;
+ }
+
+ /**
+ * Render the control's content.
+ *
+ * @since 3.4.0
+ */
+ public function render_content() {
+ $src = $this->value();
+ if ( isset( $this->get_url ) )
+ $src = call_user_func( $this->get_url, $src );
+
+ ?>
+ <div class="customize-image-picker">
+ <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
+
+ <div class="customize-control-content">
+ <div class="dropdown preview-thumbnail" tabindex="0">
+ <div class="dropdown-content">
+ <?php if ( empty( $src ) ): ?>
+ <img style="display:none;" />
+ <?php else: ?>
+ <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />
+ <?php endif; ?>
+ <div class="dropdown-status"></div>
+ </div>
+ <div class="dropdown-arrow"></div>
+ </div>
+ </div>
+
+ <div class="library">
+ <ul>
+ <?php foreach ( $this->tabs as $id => $tab ): ?>
+ <li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>
+ <?php echo esc_html( $tab['label'] ); ?>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+ <?php foreach ( $this->tabs as $id => $tab ): ?>
+ <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>
+ <?php call_user_func( $tab['callback'] ); ?>
+ </div>
+ <?php endforeach; ?>
+ </div>
+
+ <div class="actions">
+ <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>
+ </div>
+ </div>
+ <?php
+ }
+
+ /**
+ * Add a tab to the control.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id
+ * @param string $label
+ * @param mixed $callback
+ */
+ public function add_tab( $id, $label, $callback ) {
+ $this->tabs[ $id ] = array(
+ 'label' => $label,
+ 'callback' => $callback,
+ );
+ }
+
+ /**
+ * Remove a tab from the control.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id
+ */
+ public function remove_tab( $id ) {
+ unset( $this->tabs[ $id ] );
+ }
+
+ /**
+ * @since 3.4.0
+ */
+ public function tab_upload_new() {
+ if ( ! _device_can_upload() ) {
+ echo '<p>' . sprintf( __('The web browser on your device cannot be used to upload files. You may be able to use the <a href="%s">native app for your device</a> instead.'), 'http://wordpress.org/mobile/' ) . '</p>';
+ } else {
+ ?>
+ <div class="upload-dropzone">
+ <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?>
+ </div>
+ <div class="upload-fallback">
+ <span class="button-secondary"><?php _e('Select File'); ?></span>
+ </div>
+ <?php
+ }
+ }
+
+ /**
+ * @since 3.4.0
+ */
+ public function tab_uploaded() {
+ ?>
+ <div class="uploaded-target"></div>
+ <?php
+ }
+
+ /**
+ * @since 3.4.0
+ *
+ * @param string $url
+ * @param string $thumbnail_url
+ */
+ public function print_tab_image( $url, $thumbnail_url = null ) {
+ $url = set_url_scheme( $url );
+ $thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url;
+ ?>
+ <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>">
+ <img src="<?php echo esc_url( $thumbnail_url ); ?>" />
+ </a>
+ <?php
+ }
+}
+
+/**
+ * Customize Background Image Control Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control {
+
+ /**
+ * Constructor.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Image_Control::__construct()
+ *
+ * @param WP_Customize_Manager $manager
+ */
+ public function __construct( $manager ) {
+ parent::__construct( $manager, 'background_image', array(
+ 'label' => __( 'Background Image' ),
+ 'section' => 'background_image',
+ 'context' => 'custom-background',
+ 'get_url' => 'get_background_image',
+ ) );
+
+ if ( $this->setting->default )
+ $this->add_tab( 'default', __('Default'), array( $this, 'tab_default_background' ) );
+ }
+
+ /**
+ * @since 3.4.0
+ */
+ public function tab_uploaded() {
+ $backgrounds = get_posts( array(
+ 'post_type' => 'attachment',
+ 'meta_key' => '_wp_attachment_is_custom_background',
+ 'meta_value' => $this->manager->get_stylesheet(),
+ 'orderby' => 'none',
+ 'nopaging' => true,
+ ) );
+
+ ?><div class="uploaded-target"></div><?php
+
+ if ( empty( $backgrounds ) )
+ return;
+
+ foreach ( (array) $backgrounds as $background )
+ $this->print_tab_image( esc_url_raw( $background->guid ) );
+ }
+
+ /**
+ * @since 3.4.0
+ * @uses WP_Customize_Image_Control::print_tab_image()
+ */
+ public function tab_default_background() {
+ $this->print_tab_image( $this->setting->default );
+ }
+}
+
+/**
+ * Customize Header Image Control Class
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
+ /**
+ * The processed default headers.
+ * @since 3.4.2
+ * @var array
+ */
+ protected $default_headers;
+
+ /**
+ * The uploaded headers.
+ * @since 3.4.2
+ * @var array
+ */
+ protected $uploaded_headers;
+
+ /**
+ * Constructor.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Image_Control::__construct()
+ * @uses WP_Customize_Image_Control::add_tab()
+ *
+ * @param WP_Customize_Manager $manager
+ */
+ public function __construct( $manager ) {
+ parent::__construct( $manager, 'header_image', array(
+ 'label' => __( 'Header Image' ),
+ 'settings' => array(
+ 'default' => 'header_image',
+ 'data' => 'header_image_data',
+ ),
+ 'section' => 'header_image',
+ 'context' => 'custom-header',
+ 'removed' => 'remove-header',
+ 'get_url' => 'get_header_image',
+ 'statuses' => array(
+ '' => __('Default'),
+ 'remove-header' => __('No Image'),
+ 'random-default-image' => __('Random Default Image'),
+ 'random-uploaded-image' => __('Random Uploaded Image'),
+ )
+ ) );
+
+ // Remove the upload tab.
+ $this->remove_tab( 'upload-new' );
+ }
+
+ /**
+ * Prepares the control.
+ *
+ * If no tabs exist, removes the control from the manager.
+ *
+ * @since 3.4.2
+ */
+ public function prepare_control() {
+ global $custom_image_header;
+ if ( empty( $custom_image_header ) )
+ return parent::prepare_control();
+
+ // Process default headers and uploaded headers.
+ $custom_image_header->process_default_headers();
+ $this->default_headers = $custom_image_header->default_headers;
+ $this->uploaded_headers = get_uploaded_header_images();
+
+ if ( $this->default_headers )
+ $this->add_tab( 'default', __('Default'), array( $this, 'tab_default_headers' ) );
+
+ if ( ! $this->uploaded_headers )
+ $this->remove_tab( 'uploaded' );
+
+ return parent::prepare_control();
+ }
+
+ /**
+ * @since 3.4.0
+ *
+ * @param mixed $choice Which header image to select. (@see Custom_Image_Header::get_header_image() )
+ * @param array $header
+ */
+ public function print_header_image( $choice, $header ) {
+ $header['url'] = set_url_scheme( $header['url'] );
+ $header['thumbnail_url'] = set_url_scheme( $header['thumbnail_url'] );
+
+ $header_image_data = array( 'choice' => $choice );
+ foreach ( array( 'attachment_id', 'width', 'height', 'url', 'thumbnail_url' ) as $key ) {
+ if ( isset( $header[ $key ] ) )
+ $header_image_data[ $key ] = $header[ $key ];
+ }
+
+
+ ?>
+ <a href="#" class="thumbnail"
+ data-customize-image-value="<?php echo esc_url( $header['url'] ); ?>"
+ data-customize-header-image-data="<?php echo esc_attr( json_encode( $header_image_data ) ); ?>">
+ <img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" />
+ </a>
+ <?php
+ }
+
+ /**
+ * @since 3.4.0
+ */
+ public function tab_uploaded() {
+ ?><div class="uploaded-target"></div><?php
+
+ foreach ( $this->uploaded_headers as $choice => $header )
+ $this->print_header_image( $choice, $header );
+ }
+
+ /**
+ * @since 3.4.0
+ */
+ public function tab_default_headers() {
+ foreach ( $this->default_headers as $choice => $header )
+ $this->print_header_image( $choice, $header );
+ }
+} \ No newline at end of file
diff --git a/src/wp-includes/class-wp-customize-manager.php b/src/wp-includes/class-wp-customize-manager.php
new file mode 100644
index 0000000000..cad9f1351c
--- /dev/null
+++ b/src/wp-includes/class-wp-customize-manager.php
@@ -0,0 +1,1059 @@
+<?php
+/**
+ * Customize Manager.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+final class WP_Customize_Manager {
+ protected $theme;
+ protected $original_stylesheet;
+
+ protected $previewing = false;
+
+ protected $settings = array();
+ protected $sections = array();
+ protected $controls = array();
+
+ protected $nonce_tick;
+
+ protected $customized;
+
+ private $_post_values;
+
+ /**
+ * Constructor.
+ *
+ * @since 3.4.0
+ */
+ public function __construct() {
+ require( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
+ require( ABSPATH . WPINC . '/class-wp-customize-section.php' );
+ require( ABSPATH . WPINC . '/class-wp-customize-control.php' );
+
+ add_filter( 'wp_die_handler', array( $this, 'wp_die_handler' ) );
+
+ add_action( 'setup_theme', array( $this, 'setup_theme' ) );
+ add_action( 'wp_loaded', array( $this, 'wp_loaded' ) );
+
+ // Run wp_redirect_status late to make sure we override the status last.
+ add_action( 'wp_redirect_status', array( $this, 'wp_redirect_status' ), 1000 );
+
+ // Do not spawn cron (especially the alternate cron) while running the customizer.
+ remove_action( 'init', 'wp_cron' );
+
+ // Do not run update checks when rendering the controls.
+ remove_action( 'admin_init', '_maybe_update_core' );
+ remove_action( 'admin_init', '_maybe_update_plugins' );
+ remove_action( 'admin_init', '_maybe_update_themes' );
+
+ add_action( 'wp_ajax_customize_save', array( $this, 'save' ) );
+
+ add_action( 'customize_register', array( $this, 'register_controls' ) );
+ add_action( 'customize_controls_init', array( $this, 'prepare_controls' ) );
+ add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_control_scripts' ) );
+ }
+
+ /**
+ * Return true if it's an AJAX request.
+ *
+ * @since 3.4.0
+ *
+ * @return bool
+ */
+ public function doing_ajax() {
+ return isset( $_POST['customized'] ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX );
+ }
+
+ /**
+ * Custom wp_die wrapper. Returns either the standard message for UI
+ * or the AJAX message.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $ajax_message AJAX return
+ * @param mixed $message UI message
+ */
+ protected function wp_die( $ajax_message, $message = null ) {
+ if ( $this->doing_ajax() )
+ wp_die( $ajax_message );
+
+ if ( ! $message )
+ $message = __( 'Cheatin&#8217; uh?' );
+
+ wp_die( $message );
+ }
+
+ /**
+ * Return the AJAX wp_die() handler if it's a customized request.
+ *
+ * @since 3.4.0
+ *
+ * @return string
+ */
+ public function wp_die_handler() {
+ if ( $this->doing_ajax() )
+ return '_ajax_wp_die_handler';
+
+ return '_default_wp_die_handler';
+ }
+
+ /**
+ * Start preview and customize theme.
+ *
+ * Check if customize query variable exist. Init filters to filter the current theme.
+ *
+ * @since 3.4.0
+ */
+ public function setup_theme() {
+ send_origin_headers();
+
+ if ( is_admin() && ! $this->doing_ajax() )
+ auth_redirect();
+ elseif ( $this->doing_ajax() && ! is_user_logged_in() )
+ $this->wp_die( 0 );
+
+ show_admin_bar( false );
+
+ if ( ! current_user_can( 'edit_theme_options' ) )
+ $this->wp_die( -1 );
+
+ $this->original_stylesheet = get_stylesheet();
+
+ $this->theme = wp_get_theme( isset( $_REQUEST['theme'] ) ? $_REQUEST['theme'] : null );
+
+ if ( $this->is_theme_active() ) {
+ // Once the theme is loaded, we'll validate it.
+ add_action( 'after_setup_theme', array( $this, 'after_setup_theme' ) );
+ } else {
+ if ( ! current_user_can( 'switch_themes' ) )
+ $this->wp_die( -1 );
+
+ // If the theme isn't active, you can't preview it if it is not allowed or has errors.
+ if ( $this->theme()->errors() )
+ $this->wp_die( -1 );
+
+ if ( ! $this->theme()->is_allowed() )
+ $this->wp_die( -1 );
+ }
+
+ $this->start_previewing_theme();
+ }
+
+ /**
+ * Callback to validate a theme once it is loaded
+ *
+ * @since 3.4.0
+ */
+ function after_setup_theme() {
+ if ( ! $this->doing_ajax() && ! validate_current_theme() ) {
+ wp_redirect( 'themes.php?broken=true' );
+ exit;
+ }
+ }
+
+ /**
+ * Start previewing the selected theme.
+ *
+ * Adds filters to change the current theme.
+ *
+ * @since 3.4.0
+ */
+ public function start_previewing_theme() {
+ // Bail if we're already previewing.
+ if ( $this->is_preview() )
+ return;
+
+ $this->previewing = true;
+
+ if ( ! $this->is_theme_active() ) {
+ add_filter( 'template', array( $this, 'get_template' ) );
+ add_filter( 'stylesheet', array( $this, 'get_stylesheet' ) );
+ add_filter( 'pre_option_current_theme', array( $this, 'current_theme' ) );
+
+ // @link: http://core.trac.wordpress.org/ticket/20027
+ add_filter( 'pre_option_stylesheet', array( $this, 'get_stylesheet' ) );
+ add_filter( 'pre_option_template', array( $this, 'get_template' ) );
+
+ // Handle custom theme roots.
+ add_filter( 'pre_option_stylesheet_root', array( $this, 'get_stylesheet_root' ) );
+ add_filter( 'pre_option_template_root', array( $this, 'get_template_root' ) );
+ }
+
+ do_action( 'start_previewing_theme', $this );
+ }
+
+ /**
+ * Stop previewing the selected theme.
+ *
+ * Removes filters to change the current theme.
+ *
+ * @since 3.4.0
+ */
+ public function stop_previewing_theme() {
+ if ( ! $this->is_preview() )
+ return;
+
+ $this->previewing = false;
+
+ if ( ! $this->is_theme_active() ) {
+ remove_filter( 'template', array( $this, 'get_template' ) );
+ remove_filter( 'stylesheet', array( $this, 'get_stylesheet' ) );
+ remove_filter( 'pre_option_current_theme', array( $this, 'current_theme' ) );
+
+ // @link: http://core.trac.wordpress.org/ticket/20027
+ remove_filter( 'pre_option_stylesheet', array( $this, 'get_stylesheet' ) );
+ remove_filter( 'pre_option_template', array( $this, 'get_template' ) );
+
+ // Handle custom theme roots.
+ remove_filter( 'pre_option_stylesheet_root', array( $this, 'get_stylesheet_root' ) );
+ remove_filter( 'pre_option_template_root', array( $this, 'get_template_root' ) );
+ }
+
+ do_action( 'stop_previewing_theme', $this );
+ }
+
+ /**
+ * Get the theme being customized.
+ *
+ * @since 3.4.0
+ *
+ * @return WP_Theme
+ */
+ public function theme() {
+ return $this->theme;
+ }
+
+ /**
+ * Get the registered settings.
+ *
+ * @since 3.4.0
+ *
+ * @return array
+ */
+ public function settings() {
+ return $this->settings;
+ }
+
+ /**
+ * Get the registered controls.
+ *
+ * @since 3.4.0
+ *
+ * @return array
+ */
+ public function controls() {
+ return $this->controls;
+ }
+
+ /**
+ * Get the registered sections.
+ *
+ * @since 3.4.0
+ *
+ * @return array
+ */
+ public function sections() {
+ return $this->sections;
+ }
+
+ /**
+ * Checks if the current theme is active.
+ *
+ * @since 3.4.0
+ *
+ * @return bool
+ */
+ public function is_theme_active() {
+ return $this->get_stylesheet() == $this->original_stylesheet;
+ }
+
+ /**
+ * Register styles/scripts and initialize the preview of each setting
+ *
+ * @since 3.4.0
+ */
+ public function wp_loaded() {
+ do_action( 'customize_register', $this );
+
+ if ( $this->is_preview() && ! is_admin() )
+ $this->customize_preview_init();
+ }
+
+ /**
+ * Prevents AJAX requests from following redirects when previewing a theme
+ * by issuing a 200 response instead of a 30x.
+ *
+ * Instead, the JS will sniff out the location header.
+ *
+ * @since 3.4.0
+ *
+ * @param $status
+ * @return int
+ */
+ public function wp_redirect_status( $status ) {
+ if ( $this->is_preview() && ! is_admin() )
+ return 200;
+
+ return $status;
+ }
+
+ /**
+ * Decode the $_POST attribute used to override the WP_Customize_Setting values.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $setting A WP_Customize_Setting derived object
+ * @return string Sanitized attribute
+ */
+ public function post_value( $setting ) {
+ if ( ! isset( $this->_post_values ) ) {
+ if ( isset( $_POST['customized'] ) )
+ $this->_post_values = json_decode( wp_unslash( $_POST['customized'] ), true );
+ else
+ $this->_post_values = false;
+ }
+
+ if ( isset( $this->_post_values[ $setting->id ] ) )
+ return $setting->sanitize( $this->_post_values[ $setting->id ] );
+ }
+
+ /**
+ * Print javascript settings.
+ *
+ * @since 3.4.0
+ */
+ public function customize_preview_init() {
+ $this->nonce_tick = check_ajax_referer( 'preview-customize_' . $this->get_stylesheet(), 'nonce' );
+
+ $this->prepare_controls();
+
+ wp_enqueue_script( 'customize-preview' );
+ add_action( 'wp_head', array( $this, 'customize_preview_base' ) );
+ add_action( 'wp_head', array( $this, 'customize_preview_html5' ) );
+ add_action( 'wp_footer', array( $this, 'customize_preview_settings' ), 20 );
+ add_action( 'shutdown', array( $this, 'customize_preview_signature' ), 1000 );
+ add_filter( 'wp_die_handler', array( $this, 'remove_preview_signature' ) );
+
+ foreach ( $this->settings as $setting ) {
+ $setting->preview();
+ }
+
+ do_action( 'customize_preview_init', $this );
+ }
+
+ /**
+ * Print base element for preview frame.
+ *
+ * @since 3.4.0
+ */
+ public function customize_preview_base() {
+ ?><base href="<?php echo home_url( '/' ); ?>" /><?php
+ }
+
+ /**
+ * Print a workaround to handle HTML5 tags in IE < 9
+ *
+ * @since 3.4.0
+ */
+ public function customize_preview_html5() { ?>
+ <!--[if lt IE 9]>
+ <script type="text/javascript">
+ var e = [ 'abbr', 'article', 'aside', 'audio', 'canvas', 'datalist', 'details',
+ 'figure', 'footer', 'header', 'hgroup', 'mark', 'menu', 'meter', 'nav',
+ 'output', 'progress', 'section', 'time', 'video' ];
+ for ( var i = 0; i < e.length; i++ ) {
+ document.createElement( e[i] );
+ }
+ </script>
+ <![endif]--><?php
+ }
+
+ /**
+ * Print javascript settings for preview frame.
+ *
+ * @since 3.4.0
+ */
+ public function customize_preview_settings() {
+ $settings = array(
+ 'values' => array(),
+ 'channel' => esc_js( $_POST['customize_messenger_channel'] ),
+ );
+
+ if ( 2 == $this->nonce_tick ) {
+ $settings['nonce'] = array(
+ 'save' => wp_create_nonce( 'save-customize_' . $this->get_stylesheet() ),
+ 'preview' => wp_create_nonce( 'preview-customize_' . $this->get_stylesheet() )
+ );
+ }
+
+ foreach ( $this->settings as $id => $setting ) {
+ $settings['values'][ $id ] = $setting->js_value();
+ }
+
+ ?>
+ <script type="text/javascript">
+ var _wpCustomizeSettings = <?php echo json_encode( $settings ); ?>;
+ </script>
+ <?php
+ }
+
+ /**
+ * Prints a signature so we can ensure the customizer was properly executed.
+ *
+ * @since 3.4.0
+ */
+ public function customize_preview_signature() {
+ echo 'WP_CUSTOMIZER_SIGNATURE';
+ }
+
+ /**
+ * Removes the signature in case we experience a case where the customizer was not properly executed.
+ *
+ * @since 3.4.0
+ */
+ public function remove_preview_signature( $return = null ) {
+ remove_action( 'shutdown', array( $this, 'customize_preview_signature' ), 1000 );
+
+ return $return;
+ }
+
+ /**
+ * Is it a theme preview?
+ *
+ * @since 3.4.0
+ *
+ * @return bool True if it's a preview, false if not.
+ */
+ public function is_preview() {
+ return (bool) $this->previewing;
+ }
+
+ /**
+ * Retrieve the template name of the previewed theme.
+ *
+ * @since 3.4.0
+ *
+ * @return string Template name.
+ */
+ public function get_template() {
+ return $this->theme()->get_template();
+ }
+
+ /**
+ * Retrieve the stylesheet name of the previewed theme.
+ *
+ * @since 3.4.0
+ *
+ * @return string Stylesheet name.
+ */
+ public function get_stylesheet() {
+ return $this->theme()->get_stylesheet();
+ }
+
+ /**
+ * Retrieve the template root of the previewed theme.
+ *
+ * @since 3.4.0
+ *
+ * @return string Theme root.
+ */
+ public function get_template_root() {
+ return get_raw_theme_root( $this->get_template(), true );
+ }
+
+ /**
+ * Retrieve the stylesheet root of the previewed theme.
+ *
+ * @since 3.4.0
+ *
+ * @return string Theme root.
+ */
+ public function get_stylesheet_root() {
+ return get_raw_theme_root( $this->get_stylesheet(), true );
+ }
+
+ /**
+ * Filter the current theme and return the name of the previewed theme.
+ *
+ * @since 3.4.0
+ *
+ * @param $current_theme {@internal Parameter is not used}
+ * @return string Theme name.
+ */
+ public function current_theme( $current_theme ) {
+ return $this->theme()->display('Name');
+ }
+
+ /**
+ * Switch the theme and trigger the save action of each setting.
+ *
+ * @since 3.4.0
+ */
+ public function save() {
+ if ( ! $this->is_preview() )
+ die;
+
+ check_ajax_referer( 'save-customize_' . $this->get_stylesheet(), 'nonce' );
+
+ // Do we have to switch themes?
+ if ( ! $this->is_theme_active() ) {
+ // Temporarily stop previewing the theme to allow switch_themes()
+ // to operate properly.
+ $this->stop_previewing_theme();
+ switch_theme( $this->get_stylesheet() );
+ $this->start_previewing_theme();
+ }
+
+ do_action( 'customize_save', $this );
+
+ foreach ( $this->settings as $setting ) {
+ $setting->save();
+ }
+
+ do_action( 'customize_save_after', $this );
+
+ die;
+ }
+
+ /**
+ * Add a customize setting.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the setting. Can be a
+ * theme mod or option name.
+ * @param array $args Setting arguments.
+ */
+ public function add_setting( $id, $args = array() ) {
+ if ( is_a( $id, 'WP_Customize_Setting' ) )
+ $setting = $id;
+ else
+ $setting = new WP_Customize_Setting( $this, $id, $args );
+
+ $this->settings[ $setting->id ] = $setting;
+ }
+
+ /**
+ * Retrieve a customize setting.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the setting.
+ * @return object The settings object.
+ */
+ public function get_setting( $id ) {
+ if ( isset( $this->settings[ $id ] ) )
+ return $this->settings[ $id ];
+ }
+
+ /**
+ * Remove a customize setting.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the setting.
+ */
+ public function remove_setting( $id ) {
+ unset( $this->settings[ $id ] );
+ }
+
+ /**
+ * Add a customize section.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the section.
+ * @param array $args Section arguments.
+ */
+ public function add_section( $id, $args = array() ) {
+ if ( is_a( $id, 'WP_Customize_Section' ) )
+ $section = $id;
+ else
+ $section = new WP_Customize_Section( $this, $id, $args );
+
+ $this->sections[ $section->id ] = $section;
+ }
+
+ /**
+ * Retrieve a customize section.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the section.
+ * @return object The section object.
+ */
+ public function get_section( $id ) {
+ if ( isset( $this->sections[ $id ] ) )
+ return $this->sections[ $id ];
+ }
+
+ /**
+ * Remove a customize section.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the section.
+ */
+ public function remove_section( $id ) {
+ unset( $this->sections[ $id ] );
+ }
+
+ /**
+ * Add a customize control.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the control.
+ * @param array $args Setting arguments.
+ */
+ public function add_control( $id, $args = array() ) {
+ if ( is_a( $id, 'WP_Customize_Control' ) )
+ $control = $id;
+ else
+ $control = new WP_Customize_Control( $this, $id, $args );
+
+ $this->controls[ $control->id ] = $control;
+ }
+
+ /**
+ * Retrieve a customize control.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the control.
+ * @return object The settings object.
+ */
+ public function get_control( $id ) {
+ if ( isset( $this->controls[ $id ] ) )
+ return $this->controls[ $id ];
+ }
+
+ /**
+ * Remove a customize setting.
+ *
+ * @since 3.4.0
+ *
+ * @param string $id A specific ID of the control.
+ */
+ public function remove_control( $id ) {
+ unset( $this->controls[ $id ] );
+ }
+
+ /**
+ * Helper function to compare two objects by priority.
+ *
+ * @since 3.4.0
+ *
+ * @param object $a Object A.
+ * @param object $b Object B.
+ * @return int
+ */
+ protected final function _cmp_priority( $a, $b ) {
+ $ap = $a->priority;
+ $bp = $b->priority;
+
+ if ( $ap == $bp )
+ return 0;
+ return ( $ap > $bp ) ? 1 : -1;
+ }
+
+ /**
+ * Prepare settings and sections.
+ *
+ * @since 3.4.0
+ */
+ public function prepare_controls() {
+ // Prepare controls
+ // Reversing makes uasort sort by time added when conflicts occur.
+
+ $this->controls = array_reverse( $this->controls );
+ $controls = array();
+
+ foreach ( $this->controls as $id => $control ) {
+ if ( ! isset( $this->sections[ $control->section ] ) || ! $control->check_capabilities() )
+ continue;
+
+ $this->sections[ $control->section ]->controls[] = $control;
+ $controls[ $id ] = $control;
+ }
+ $this->controls = $controls;
+
+ // Prepare sections
+ $this->sections = array_reverse( $this->sections );
+ uasort( $this->sections, array( $this, '_cmp_priority' ) );
+ $sections = array();
+
+ foreach ( $this->sections as $section ) {
+ if ( ! $section->check_capabilities() || ! $section->controls )
+ continue;
+
+ usort( $section->controls, array( $this, '_cmp_priority' ) );
+ $sections[] = $section;
+ }
+ $this->sections = $sections;
+ }
+
+ /**
+ * Enqueue scripts for customize controls.
+ *
+ * @since 3.4.0
+ */
+ public function enqueue_control_scripts() {
+ foreach ( $this->controls as $control ) {
+ $control->enqueue();
+ }
+ }
+
+ /**
+ * Register some default controls.
+ *
+ * @since 3.4.0
+ */
+ public function register_controls() {
+
+ /* Site Title & Tagline */
+
+ $this->add_section( 'title_tagline', array(
+ 'title' => __( 'Site Title & Tagline' ),
+ 'priority' => 20,
+ ) );
+
+ $this->add_setting( 'blogname', array(
+ 'default' => get_option( 'blogname' ),
+ 'type' => 'option',
+ 'capability' => 'manage_options',
+ ) );
+
+ $this->add_control( 'blogname', array(
+ 'label' => __( 'Site Title' ),
+ 'section' => 'title_tagline',
+ ) );
+
+ $this->add_setting( 'blogdescription', array(
+ 'default' => get_option( 'blogdescription' ),
+ 'type' => 'option',
+ 'capability' => 'manage_options',
+ ) );
+
+ $this->add_control( 'blogdescription', array(
+ 'label' => __( 'Tagline' ),
+ 'section' => 'title_tagline',
+ ) );
+
+ /* Colors */
+
+ $this->add_section( 'colors', array(
+ 'title' => __( 'Colors' ),
+ 'priority' => 40,
+ ) );
+
+ $this->add_setting( 'header_textcolor', array(
+ 'theme_supports' => array( 'custom-header', 'header-text' ),
+ 'default' => get_theme_support( 'custom-header', 'default-text-color' ),
+
+ 'sanitize_callback' => array( $this, '_sanitize_header_textcolor' ),
+ 'sanitize_js_callback' => 'maybe_hash_hex_color',
+ ) );
+
+ // Input type: checkbox
+ // With custom value
+ $this->add_control( 'display_header_text', array(
+ 'settings' => 'header_textcolor',
+ 'label' => __( 'Display Header Text' ),
+ 'section' => 'title_tagline',
+ 'type' => 'checkbox',
+ ) );
+
+ $this->add_control( new WP_Customize_Color_Control( $this, 'header_textcolor', array(
+ 'label' => __( 'Header Text Color' ),
+ 'section' => 'colors',
+ ) ) );
+
+ // Input type: Color
+ // With sanitize_callback
+ $this->add_setting( 'background_color', array(
+ 'default' => get_theme_support( 'custom-background', 'default-color' ),
+ 'theme_supports' => 'custom-background',
+
+ 'sanitize_callback' => 'sanitize_hex_color_no_hash',
+ 'sanitize_js_callback' => 'maybe_hash_hex_color',
+ ) );
+
+ $this->add_control( new WP_Customize_Color_Control( $this, 'background_color', array(
+ 'label' => __( 'Background Color' ),
+ 'section' => 'colors',
+ ) ) );
+
+
+ /* Custom Header */
+
+ $this->add_section( 'header_image', array(
+ 'title' => __( 'Header Image' ),
+ 'theme_supports' => 'custom-header',
+ 'priority' => 60,
+ ) );
+
+ $this->add_setting( new WP_Customize_Filter_Setting( $this, 'header_image', array(
+ 'default' => get_theme_support( 'custom-header', 'default-image' ),
+ 'theme_supports' => 'custom-header',
+ ) ) );
+
+ $this->add_setting( new WP_Customize_Header_Image_Setting( $this, 'header_image_data', array(
+ // 'default' => get_theme_support( 'custom-header', 'default-image' ),
+ 'theme_supports' => 'custom-header',
+ ) ) );
+
+ $this->add_control( new WP_Customize_Header_Image_Control( $this ) );
+
+ /* Custom Background */
+
+ $this->add_section( 'background_image', array(
+ 'title' => __( 'Background Image' ),
+ 'theme_supports' => 'custom-background',
+ 'priority' => 80,
+ ) );
+
+ $this->add_setting( 'background_image', array(
+ 'default' => get_theme_support( 'custom-background', 'default-image' ),
+ 'theme_supports' => 'custom-background',
+ ) );
+
+ $this->add_setting( new WP_Customize_Background_Image_Setting( $this, 'background_image_thumb', array(
+ 'theme_supports' => 'custom-background',
+ ) ) );
+
+ $this->add_control( new WP_Customize_Background_Image_Control( $this ) );
+
+ $this->add_setting( 'background_repeat', array(
+ 'default' => 'repeat',
+ 'theme_supports' => 'custom-background',
+ ) );
+
+ $this->add_control( 'background_repeat', array(
+ 'label' => __( 'Background Repeat' ),
+ 'section' => 'background_image',
+ 'type' => 'radio',
+ 'choices' => array(
+ 'no-repeat' => __('No Repeat'),
+ 'repeat' => __('Tile'),
+ 'repeat-x' => __('Tile Horizontally'),
+ 'repeat-y' => __('Tile Vertically'),
+ ),
+ ) );
+
+ $this->add_setting( 'background_position_x', array(
+ 'default' => 'left',
+ 'theme_supports' => 'custom-background',
+ ) );
+
+ $this->add_control( 'background_position_x', array(
+ 'label' => __( 'Background Position' ),
+ 'section' => 'background_image',
+ 'type' => 'radio',
+ 'choices' => array(
+ 'left' => __('Left'),
+ 'center' => __('Center'),
+ 'right' => __('Right'),
+ ),
+ ) );
+
+ $this->add_setting( 'background_attachment', array(
+ 'default' => 'fixed',
+ 'theme_supports' => 'custom-background',
+ ) );
+
+ $this->add_control( 'background_attachment', array(
+ 'label' => __( 'Background Attachment' ),
+ 'section' => 'background_image',
+ 'type' => 'radio',
+ 'choices' => array(
+ 'fixed' => __('Fixed'),
+ 'scroll' => __('Scroll'),
+ ),
+ ) );
+
+ // If the theme is using the default background callback, we can update
+ // the background CSS using postMessage.
+ if ( get_theme_support( 'custom-background', 'wp-head-callback' ) === '_custom_background_cb' ) {
+ foreach ( array( 'color', 'image', 'position_x', 'repeat', 'attachment' ) as $prop ) {
+ $this->get_setting( 'background_' . $prop )->transport = 'postMessage';
+ }
+ }
+
+ /* Nav Menus */
+
+ $locations = get_registered_nav_menus();
+ $menus = wp_get_nav_menus();
+ $menu_locations = get_nav_menu_locations();
+ $num_locations = count( array_keys( $locations ) );
+
+ $this->add_section( 'nav', array(
+ 'title' => __( 'Navigation' ),
+ 'theme_supports' => 'menus',
+ 'priority' => 100,
+ 'description' => sprintf( _n('Your theme supports %s menu. Select which menu you would like to use.', 'Your theme supports %s menus. Select which menu appears in each location.', $num_locations ), number_format_i18n( $num_locations ) ) . "\n\n" . __('You can edit your menu content on the Menus screen in the Appearance section.'),
+ ) );
+
+ if ( $menus ) {
+ $choices = array( 0 => __( '&mdash; Select &mdash;' ) );
+ foreach ( $menus as $menu ) {
+ $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '&hellip;' );
+ }
+
+ foreach ( $locations as $location => $description ) {
+ $menu_setting_id = "nav_menu_locations[{$location}]";
+
+ $this->add_setting( $menu_setting_id, array(
+ 'sanitize_callback' => 'absint',
+ 'theme_supports' => 'menus',
+ ) );
+
+ $this->add_control( $menu_setting_id, array(
+ 'label' => $description,
+ 'section' => 'nav',
+ 'type' => 'select',
+ 'choices' => $choices,
+ ) );
+ }
+ }
+
+ /* Static Front Page */
+ // #WP19627
+
+ $this->add_section( 'static_front_page', array(
+ 'title' => __( 'Static Front Page' ),
+ // 'theme_supports' => 'static-front-page',
+ 'priority' => 120,
+ 'description' => __( 'Your theme supports a static front page.' ),
+ ) );
+
+ $this->add_setting( 'show_on_front', array(
+ 'default' => get_option( 'show_on_front' ),
+ 'capability' => 'manage_options',
+ 'type' => 'option',
+ // 'theme_supports' => 'static-front-page',
+ ) );
+
+ $this->add_control( 'show_on_front', array(
+ 'label' => __( 'Front page displays' ),
+ 'section' => 'static_front_page',
+ 'type' => 'radio',
+ 'choices' => array(
+ 'posts' => __( 'Your latest posts' ),
+ 'page' => __( 'A static page' ),
+ ),
+ ) );
+
+ $this->add_setting( 'page_on_front', array(
+ 'type' => 'option',
+ 'capability' => 'manage_options',
+ // 'theme_supports' => 'static-front-page',
+ ) );
+
+ $this->add_control( 'page_on_front', array(
+ 'label' => __( 'Front page' ),
+ 'section' => 'static_front_page',
+ 'type' => 'dropdown-pages',
+ ) );
+
+ $this->add_setting( 'page_for_posts', array(
+ 'type' => 'option',
+ 'capability' => 'manage_options',
+ // 'theme_supports' => 'static-front-page',
+ ) );
+
+ $this->add_control( 'page_for_posts', array(
+ 'label' => __( 'Posts page' ),
+ 'section' => 'static_front_page',
+ 'type' => 'dropdown-pages',
+ ) );
+ }
+
+ /**
+ * Callback for validating the header_textcolor value.
+ *
+ * Accepts 'blank', and otherwise uses sanitize_hex_color_no_hash().
+ * Returns default text color if hex color is empty.
+ *
+ * @since 3.4.0
+ *
+ * @param string $color
+ * @return string
+ */
+ public function _sanitize_header_textcolor( $color ) {
+ if ( 'blank' === $color )
+ return 'blank';
+
+ $color = sanitize_hex_color_no_hash( $color );
+ if ( empty( $color ) )
+ $color = get_theme_support( 'custom-header', 'default-text-color' );
+
+ return $color;
+ }
+};
+
+/**
+ * Validates a hex color.
+ *
+ * Returns either '', a 3 or 6 digit hex color (with #), or null.
+ * For validating values without a #, see sanitize_hex_color_no_hash().
+ *
+ * @since 3.4.0
+ *
+ * @param string $color
+ * @return string|null
+ */
+function sanitize_hex_color( $color ) {
+ if ( '' === $color )
+ return '';
+
+ // 3 or 6 hex digits, or the empty string.
+ if ( preg_match('|^#([A-Fa-f0-9]{3}){1,2}$|', $color ) )
+ return $color;
+
+ return null;
+}
+
+/**
+ * Sanitizes a hex color without a hash. Use sanitize_hex_color() when possible.
+ *
+ * Saving hex colors without a hash puts the burden of adding the hash on the
+ * UI, which makes it difficult to use or upgrade to other color types such as
+ * rgba, hsl, rgb, and html color names.
+ *
+ * Returns either '', a 3 or 6 digit hex color (without a #), or null.
+ *
+ * @since 3.4.0
+ * @uses sanitize_hex_color()
+ *
+ * @param string $color
+ * @return string|null
+ */
+function sanitize_hex_color_no_hash( $color ) {
+ $color = ltrim( $color, '#' );
+
+ if ( '' === $color )
+ return '';
+
+ return sanitize_hex_color( '#' . $color ) ? $color : null;
+}
+
+/**
+ * Ensures that any hex color is properly hashed.
+ * Otherwise, returns value untouched.
+ *
+ * This method should only be necessary if using sanitize_hex_color_no_hash().
+ *
+ * @since 3.4.0
+ *
+ * @param string $color
+ * @return string
+ */
+function maybe_hash_hex_color( $color ) {
+ if ( $unhashed = sanitize_hex_color_no_hash( $color ) )
+ return '#' . $unhashed;
+
+ return $color;
+}
diff --git a/src/wp-includes/class-wp-customize-section.php b/src/wp-includes/class-wp-customize-section.php
new file mode 100644
index 0000000000..63051be619
--- /dev/null
+++ b/src/wp-includes/class-wp-customize-section.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Customize Section Class.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Section {
+ public $manager;
+ public $id;
+ public $priority = 10;
+ public $capability = 'edit_theme_options';
+ public $theme_supports = '';
+ public $title = '';
+ public $description = '';
+ public $controls;
+
+ /**
+ * Constructor.
+ *
+ * @since 3.4.0
+ *
+ * @param WP_Customize_Manager $manager
+ * @param string $id An specific ID of the section.
+ * @param array $args Section arguments.
+ */
+ function __construct( $manager, $id, $args = array() ) {
+ $keys = array_keys( get_class_vars( __CLASS__ ) );
+ foreach ( $keys as $key ) {
+ if ( isset( $args[ $key ] ) )
+ $this->$key = $args[ $key ];
+ }
+
+ $this->manager = $manager;
+ $this->id = $id;
+
+ $this->controls = array(); // Users cannot customize the $controls array.
+
+ return $this;
+ }
+
+ /**
+ * Check if the theme supports the section and check user capabilities.
+ *
+ * @since 3.4.0
+ *
+ * @return bool False if theme doesn't support the section or user doesn't have the capability.
+ */
+ public final function check_capabilities() {
+ if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
+ return false;
+
+ if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Check capabilities and render the section.
+ *
+ * @since 3.4.0
+ */
+ public final function maybe_render() {
+ if ( ! $this->check_capabilities() )
+ return;
+
+ do_action( 'customize_render_section', $this );
+ do_action( 'customize_render_section_' . $this->id );
+
+ $this->render();
+ }
+
+ /**
+ * Render the section.
+ *
+ * @since 3.4.0
+ */
+ protected function render() {
+ ?>
+ <li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="control-section accordion-section">
+ <h3 class="accordion-section-title" tabindex="0" title="<?php echo esc_attr( $this->description ); ?>"><?php echo esc_html( $this->title ); ?></h3>
+ <ul class="accordion-section-content">
+ <?php
+ foreach ( $this->controls as $control )
+ $control->maybe_render();
+ ?>
+ </ul>
+ </li>
+ <?php
+ }
+}
diff --git a/src/wp-includes/class-wp-customize-setting.php b/src/wp-includes/class-wp-customize-setting.php
new file mode 100644
index 0000000000..c8542efefa
--- /dev/null
+++ b/src/wp-includes/class-wp-customize-setting.php
@@ -0,0 +1,439 @@
+<?php
+/**
+ * Customize Setting Class.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Setting {
+ public $manager;
+ public $id;
+
+ public $type = 'theme_mod';
+ public $capability = 'edit_theme_options';
+ public $theme_supports = '';
+ public $default = '';
+ public $transport = 'refresh';
+
+ public $sanitize_callback = '';
+ public $sanitize_js_callback = '';
+
+ protected $id_data = array();
+ private $_post_value; // Cached, sanitized $_POST value.
+
+ /**
+ * Constructor.
+ *
+ * @since 3.4.0
+ *
+ * @param WP_Customize_Manager $manager
+ * @param string $id An specific ID of the setting. Can be a
+ * theme mod or option name.
+ * @param array $args Setting arguments.
+ * @return WP_Customize_Setting
+ */
+ function __construct( $manager, $id, $args = array() ) {
+ $keys = array_keys( get_class_vars( __CLASS__ ) );
+ foreach ( $keys as $key ) {
+ if ( isset( $args[ $key ] ) )
+ $this->$key = $args[ $key ];
+ }
+
+ $this->manager = $manager;
+ $this->id = $id;
+
+ // Parse the ID for array keys.
+ $this->id_data[ 'keys' ] = preg_split( '/\[/', str_replace( ']', '', $this->id ) );
+ $this->id_data[ 'base' ] = array_shift( $this->id_data[ 'keys' ] );
+
+ // Rebuild the ID.
+ $this->id = $this->id_data[ 'base' ];
+ if ( ! empty( $this->id_data[ 'keys' ] ) )
+ $this->id .= '[' . implode( '][', $this->id_data[ 'keys' ] ) . ']';
+
+ if ( $this->sanitize_callback )
+ add_filter( "customize_sanitize_{$this->id}", $this->sanitize_callback, 10, 2 );
+
+ if ( $this->sanitize_js_callback )
+ add_filter( "customize_sanitize_js_{$this->id}", $this->sanitize_js_callback, 10, 2 );
+
+ return $this;
+ }
+
+ /**
+ * Handle previewing the setting.
+ *
+ * @since 3.4.0
+ */
+ public function preview() {
+ switch( $this->type ) {
+ case 'theme_mod' :
+ add_filter( 'theme_mod_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+ break;
+ case 'option' :
+ if ( empty( $this->id_data[ 'keys' ] ) )
+ add_filter( 'pre_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+ else {
+ add_filter( 'option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+ add_filter( 'default_option_' . $this->id_data[ 'base' ], array( $this, '_preview_filter' ) );
+ }
+ break;
+ default :
+ do_action( 'customize_preview_' . $this->id );
+ }
+ }
+
+ /**
+ * Callback function to filter the theme mods and options.
+ *
+ * @since 3.4.0
+ * @uses WP_Customize_Setting::multidimensional_replace()
+ *
+ * @param mixed $original Old value.
+ * @return mixed New or old value.
+ */
+ public function _preview_filter( $original ) {
+ return $this->multidimensional_replace( $original, $this->id_data[ 'keys' ], $this->post_value() );
+ }
+
+ /**
+ * Set the value of the parameter for a specific theme.
+ *
+ * @since 3.4.0
+ *
+ * @return bool False if cap check fails or value isn't set.
+ */
+ public final function save() {
+ $value = $this->post_value();
+
+ if ( ! $this->check_capabilities() || ! isset( $value ) )
+ return false;
+
+ do_action( 'customize_save_' . $this->id_data[ 'base' ] );
+
+ $this->update( $value );
+ }
+
+ /**
+ * Fetches, validates, and sanitizes the $_POST value.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $default A default value which is used as a fallback. Default is null.
+ * @return mixed The default value on failure, otherwise the sanitized value.
+ */
+ public final function post_value( $default = null ) {
+ if ( isset( $this->_post_value ) )
+ return $this->_post_value;
+
+ $result = $this->manager->post_value( $this );
+
+ if ( isset( $result ) )
+ return $this->_post_value = $result;
+ else
+ return $default;
+ }
+
+ /**
+ * Sanitize an input.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $value The value to sanitize.
+ * @return mixed Null if an input isn't valid, otherwise the sanitized value.
+ */
+ public function sanitize( $value ) {
+ $value = wp_unslash( $value );
+ return apply_filters( "customize_sanitize_{$this->id}", $value, $this );
+ }
+
+ /**
+ * Set the value of the parameter for a specific theme.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $value The value to update.
+ * @return mixed The result of saving the value.
+ */
+ protected function update( $value ) {
+ switch( $this->type ) {
+ case 'theme_mod' :
+ return $this->_update_theme_mod( $value );
+ break;
+ case 'option' :
+ return $this->_update_option( $value );
+ break;
+ default :
+ return do_action( 'customize_update_' . $this->type, $value );
+ }
+ }
+
+ /**
+ * Update the theme mod from the value of the parameter.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $value The value to update.
+ * @return mixed The result of saving the value.
+ */
+ protected function _update_theme_mod( $value ) {
+ // Handle non-array theme mod.
+ if ( empty( $this->id_data[ 'keys' ] ) )
+ return set_theme_mod( $this->id_data[ 'base' ], $value );
+
+ // Handle array-based theme mod.
+ $mods = get_theme_mod( $this->id_data[ 'base' ] );
+ $mods = $this->multidimensional_replace( $mods, $this->id_data[ 'keys' ], $value );
+ if ( isset( $mods ) )
+ return set_theme_mod( $this->id_data[ 'base' ], $mods );
+ }
+
+ /**
+ * Update the theme mod from the value of the parameter.
+ *
+ * @since 3.4.0
+ *
+ * @param mixed $value The value to update.
+ * @return mixed The result of saving the value.
+ */
+ protected function _update_option( $value ) {
+ // Handle non-array option.
+ if ( empty( $this->id_data[ 'keys' ] ) )
+ return update_option( $this->id_data[ 'base' ], $value );
+
+ // Handle array-based options.
+ $options = get_option( $this->id_data[ 'base' ] );
+ $options = $this->multidimensional_replace( $options, $this->id_data[ 'keys' ], $value );
+ if ( isset( $options ) )
+ return update_option( $this->id_data[ 'base' ], $options );
+ }
+
+ /**
+ * Fetch the value of the parameter for a specific theme.
+ *
+ * @since 3.4.0
+ *
+ * @return mixed The requested value.
+ */
+ public function value() {
+ switch( $this->type ) {
+ case 'theme_mod' :
+ $function = 'get_theme_mod';
+ break;
+ case 'option' :
+ $function = 'get_option';
+ break;
+ default :
+ return apply_filters( 'customize_value_' . $this->id_data[ 'base' ], $this->default );
+ }
+
+ // Handle non-array value
+ if ( empty( $this->id_data[ 'keys' ] ) )
+ return $function( $this->id_data[ 'base' ], $this->default );
+
+ // Handle array-based value
+ $values = $function( $this->id_data[ 'base' ] );
+ return $this->multidimensional_get( $values, $this->id_data[ 'keys' ], $this->default );
+ }
+
+ /**
+ * Escape the parameter's value for use in JavaScript.
+ *
+ * @since 3.4.0
+ *
+ * @return mixed The requested escaped value.
+ */
+ public function js_value() {
+ $value = apply_filters( "customize_sanitize_js_{$this->id}", $this->value(), $this );
+
+ if ( is_string( $value ) )
+ return html_entity_decode( $value, ENT_QUOTES, 'UTF-8');
+
+ return $value;
+ }
+
+ /**
+ * Check if the theme supports the setting and check user capabilities.
+ *
+ * @since 3.4.0
+ *
+ * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true.
+ */
+ public final function check_capabilities() {
+ if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) )
+ return false;
+
+ if ( $this->theme_supports && ! call_user_func_array( 'current_theme_supports', (array) $this->theme_supports ) )
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Multidimensional helper function.
+ *
+ * @since 3.4.0
+ *
+ * @param $root
+ * @param $keys
+ * @param bool $create Default is false.
+ * @return null|array Keys are 'root', 'node', and 'key'.
+ */
+ final protected function multidimensional( &$root, $keys, $create = false ) {
+ if ( $create && empty( $root ) )
+ $root = array();
+
+ if ( ! isset( $root ) || empty( $keys ) )
+ return;
+
+ $last = array_pop( $keys );
+ $node = &$root;
+
+ foreach ( $keys as $key ) {
+ if ( $create && ! isset( $node[ $key ] ) )
+ $node[ $key ] = array();
+
+ if ( ! is_array( $node ) || ! isset( $node[ $key ] ) )
+ return;
+
+ $node = &$node[ $key ];
+ }
+
+ if ( $create && ! isset( $node[ $last ] ) )
+ $node[ $last ] = array();
+
+ if ( ! isset( $node[ $last ] ) )
+ return;
+
+ return array(
+ 'root' => &$root,
+ 'node' => &$node,
+ 'key' => $last,
+ );
+ }
+
+ /**
+ * Will attempt to replace a specific value in a multidimensional array.
+ *
+ * @since 3.4.0
+ *
+ * @param $root
+ * @param $keys
+ * @param mixed $value The value to update.
+ * @return
+ */
+ final protected function multidimensional_replace( $root, $keys, $value ) {
+ if ( ! isset( $value ) )
+ return $root;
+ elseif ( empty( $keys ) ) // If there are no keys, we're replacing the root.
+ return $value;
+
+ $result = $this->multidimensional( $root, $keys, true );
+
+ if ( isset( $result ) )
+ $result['node'][ $result['key'] ] = $value;
+
+ return $root;
+ }
+
+ /**
+ * Will attempt to fetch a specific value from a multidimensional array.
+ *
+ * @since 3.4.0
+ *
+ * @param $root
+ * @param $keys
+ * @param $default A default value which is used as a fallback. Default is null.
+ * @return mixed The requested value or the default value.
+ */
+ final protected function multidimensional_get( $root, $keys, $default = null ) {
+ if ( empty( $keys ) ) // If there are no keys, test the root.
+ return isset( $root ) ? $root : $default;
+
+ $result = $this->multidimensional( $root, $keys );
+ return isset( $result ) ? $result['node'][ $result['key'] ] : $default;
+ }
+
+ /**
+ * Will attempt to check if a specific value in a multidimensional array is set.
+ *
+ * @since 3.4.0
+ *
+ * @param $root
+ * @param $keys
+ * @return bool True if value is set, false if not.
+ */
+ final protected function multidimensional_isset( $root, $keys ) {
+ $result = $this->multidimensional_get( $root, $keys );
+ return isset( $result );
+ }
+}
+
+/**
+ * A setting that is used to filter a value, but will not save the results.
+ *
+ * Results should be properly handled using another setting or callback.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+class WP_Customize_Filter_Setting extends WP_Customize_Setting {
+
+ /**
+ * @since 3.4.0
+ */
+ public function update( $value ) {}
+}
+
+/**
+ * A setting that is used to filter a value, but will not save the results.
+ *
+ * Results should be properly handled using another setting or callback.
+ *
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+final class WP_Customize_Header_Image_Setting extends WP_Customize_Setting {
+ public $id = 'header_image_data';
+
+ /**
+ * @since 3.4.0
+ *
+ * @param $value
+ */
+ public function update( $value ) {
+ global $custom_image_header;
+
+ // If the value doesn't exist (removed or random),
+ // use the header_image value.
+ if ( ! $value )
+ $value = $this->manager->get_setting('header_image')->post_value();
+
+ if ( is_array( $value ) && isset( $value['choice'] ) )
+ $custom_image_header->set_header_image( $value['choice'] );
+ else
+ $custom_image_header->set_header_image( $value );
+ }
+}
+
+/**
+ * @package WordPress
+ * @subpackage Customize
+ * @since 3.4.0
+ */
+final class WP_Customize_Background_Image_Setting extends WP_Customize_Setting {
+ public $id = 'background_image_thumb';
+
+ /**
+ * @since 3.4.0
+ * @uses remove_theme_mod()
+ *
+ * @param $value
+ */
+ public function update( $value ) {
+ remove_theme_mod( 'background_image_thumb' );
+ }
+}
diff --git a/src/wp-includes/class-wp-editor.php b/src/wp-includes/class-wp-editor.php
new file mode 100644
index 0000000000..9ab3feb5c6
--- /dev/null
+++ b/src/wp-includes/class-wp-editor.php
@@ -0,0 +1,887 @@
+<?php
+/**
+ * Facilitates adding of the WordPress editor as used on the Write and Edit screens.
+ *
+ * @package WordPress
+ * @since 3.3.0
+ *
+ * Private, not included by default. See wp_editor() in wp-includes/general-template.php.
+ */
+
+final class _WP_Editors {
+ public static $mce_locale;
+
+ private static $mce_settings = array();
+ private static $qt_settings = array();
+ private static $plugins = array();
+ private static $qt_buttons = array();
+ private static $ext_plugins;
+ private static $baseurl;
+ private static $first_init;
+ private static $this_tinymce = false;
+ private static $this_quicktags = false;
+ private static $has_tinymce = false;
+ private static $has_quicktags = false;
+ private static $has_medialib = false;
+ private static $editor_buttons_css = true;
+
+ private function __construct() {}
+
+ public static function parse_settings($editor_id, $settings) {
+ $set = wp_parse_args( $settings, array(
+ 'wpautop' => true, // use wpautop?
+ 'media_buttons' => true, // show insert/upload button(s)
+ 'textarea_name' => $editor_id, // set the textarea name to something different, square brackets [] can be used here
+ 'textarea_rows' => 20,
+ 'tabindex' => '',
+ 'tabfocus_elements' => ':prev,:next', // the previous and next element ID to move the focus to when pressing the Tab key in TinyMCE
+ 'editor_css' => '', // intended for extra styles for both visual and Text editors buttons, needs to include the <style> tags, can use "scoped".
+ 'editor_class' => '', // add extra class(es) to the editor textarea
+ 'teeny' => false, // output the minimal editor config used in Press This
+ 'dfw' => false, // replace the default fullscreen with DFW (needs specific DOM elements and css)
+ 'tinymce' => true, // load TinyMCE, can be used to pass settings directly to TinyMCE using an array()
+ 'quicktags' => true // load Quicktags, can be used to pass settings directly to Quicktags using an array()
+ ) );
+
+ self::$this_tinymce = ( $set['tinymce'] && user_can_richedit() );
+ self::$this_quicktags = (bool) $set['quicktags'];
+
+ if ( self::$this_tinymce )
+ self::$has_tinymce = true;
+
+ if ( self::$this_quicktags )
+ self::$has_quicktags = true;
+
+ if ( empty( $set['editor_height'] ) )
+ return $set;
+
+ if ( 'content' === $editor_id ) {
+ // A cookie (set when a user resizes the editor) overrides the height.
+ $cookie = (int) get_user_setting( 'ed_size' );
+
+ // Upgrade an old TinyMCE cookie if it is still around, and the new one isn't.
+ if ( ! $cookie && isset( $_COOKIE['TinyMCE_content_size'] ) ) {
+ parse_str( $_COOKIE['TinyMCE_content_size'], $cookie );
+ $cookie = $cookie['ch'];
+ }
+
+ if ( $cookie )
+ $set['editor_height'] = $cookie;
+ }
+
+ if ( $set['editor_height'] < 50 )
+ $set['editor_height'] = 50;
+ elseif ( $set['editor_height'] > 5000 )
+ $set['editor_height'] = 5000;
+
+ return $set;
+ }
+
+ /**
+ * Outputs the HTML for a single instance of the editor.
+ *
+ * @param string $content The initial content of the editor.
+ * @param string $editor_id ID for the textarea and TinyMCE and Quicktags instances (can contain only ASCII letters and numbers).
+ * @param array $settings See the _parse_settings() method for description.
+ */
+ public static function editor( $content, $editor_id, $settings = array() ) {
+
+ $set = self::parse_settings($editor_id, $settings);
+ $editor_class = ' class="' . trim( $set['editor_class'] . ' wp-editor-area' ) . '"';
+ $tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
+ $switch_class = 'html-active';
+ $toolbar = $buttons = '';
+
+ if ( ! empty( $set['editor_height'] ) )
+ $height = ' style="height: ' . $set['editor_height'] . 'px"';
+ else
+ $height = ' rows="' . $set['textarea_rows'] . '"';
+
+ if ( !current_user_can( 'upload_files' ) )
+ $set['media_buttons'] = false;
+
+ if ( self::$this_quicktags && self::$this_tinymce ) {
+ $switch_class = 'html-active';
+
+ // 'html' and 'switch-html' are used for the "Text" editor tab.
+ if ( 'html' == wp_default_editor() ) {
+ add_filter('the_editor_content', 'wp_htmledit_pre');
+ } else {
+ add_filter('the_editor_content', 'wp_richedit_pre');
+ $switch_class = 'tmce-active';
+ }
+
+ $buttons .= '<a id="' . $editor_id . '-html" class="wp-switch-editor switch-html" onclick="switchEditors.switchto(this);">' . _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ) . "</a>\n";
+ $buttons .= '<a id="' . $editor_id . '-tmce" class="wp-switch-editor switch-tmce" onclick="switchEditors.switchto(this);">' . __('Visual') . "</a>\n";
+ }
+
+ echo '<div id="wp-' . $editor_id . '-wrap" class="wp-core-ui wp-editor-wrap ' . $switch_class . '">';
+
+ if ( self::$editor_buttons_css ) {
+ wp_print_styles('editor-buttons');
+ self::$editor_buttons_css = false;
+ }
+
+ if ( !empty($set['editor_css']) )
+ echo $set['editor_css'] . "\n";
+
+ if ( !empty($buttons) || $set['media_buttons'] ) {
+ echo '<div id="wp-' . $editor_id . '-editor-tools" class="wp-editor-tools hide-if-no-js">';
+ echo $buttons;
+
+ if ( $set['media_buttons'] ) {
+ self::$has_medialib = true;
+
+ if ( !function_exists('media_buttons') )
+ include(ABSPATH . 'wp-admin/includes/media.php');
+
+ echo '<div id="wp-' . $editor_id . '-media-buttons" class="wp-media-buttons">';
+ do_action('media_buttons', $editor_id);
+ echo "</div>\n";
+ }
+ echo "</div>\n";
+ }
+
+ $the_editor = apply_filters('the_editor', '<div id="wp-' . $editor_id . '-editor-container" class="wp-editor-container"><textarea' . $editor_class . $height . $tabindex . ' cols="40" name="' . $set['textarea_name'] . '" id="' . $editor_id . '">%s</textarea></div>');
+ $content = apply_filters('the_editor_content', $content);
+
+ printf($the_editor, $content);
+ echo "\n</div>\n\n";
+
+ self::editor_settings($editor_id, $set);
+ }
+
+ public static function editor_settings($editor_id, $set) {
+ $first_run = false;
+
+ if ( empty(self::$first_init) ) {
+ if ( is_admin() ) {
+ add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
+ add_action( 'admin_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
+ } else {
+ add_action( 'wp_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
+ add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
+ }
+ }
+
+ if ( self::$this_quicktags ) {
+
+ $qtInit = array(
+ 'id' => $editor_id,
+ 'buttons' => ''
+ );
+
+ if ( is_array($set['quicktags']) )
+ $qtInit = array_merge($qtInit, $set['quicktags']);
+
+ if ( empty($qtInit['buttons']) )
+ $qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close';
+
+ if ( $set['dfw'] )
+ $qtInit['buttons'] .= ',fullscreen';
+
+ $qtInit = apply_filters('quicktags_settings', $qtInit, $editor_id);
+ self::$qt_settings[$editor_id] = $qtInit;
+
+ self::$qt_buttons = array_merge( self::$qt_buttons, explode(',', $qtInit['buttons']) );
+ }
+
+ if ( self::$this_tinymce ) {
+
+ if ( empty(self::$first_init) ) {
+ self::$baseurl = includes_url('js/tinymce');
+ self::$mce_locale = $mce_locale = ( '' == get_locale() ) ? 'en' : strtolower( substr(get_locale(), 0, 2) ); // only ISO 639-1
+ $no_captions = (bool) apply_filters( 'disable_captions', '' );
+ $plugins = array( 'inlinepopups', 'tabfocus', 'paste', 'media', 'fullscreen', 'wordpress', 'wpeditimage', 'wpgallery', 'wplink', 'wpdialogs' );
+ $first_run = true;
+ $ext_plugins = '';
+
+ if ( $set['teeny'] ) {
+ self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array('inlinepopups', 'fullscreen', 'wordpress', 'wplink', 'wpdialogs' ), $editor_id );
+ } else {
+ /*
+ The following filter takes an associative array of external plugins for TinyMCE in the form 'plugin_name' => 'url'.
+ It adds the plugin's name to TinyMCE's plugins init and the call to PluginManager to load the plugin.
+ The url should be absolute and should include the js file name to be loaded. Example:
+ array( 'myplugin' => 'http://my-site.com/wp-content/plugins/myfolder/mce_plugin.js' )
+ If the plugin uses a button, it should be added with one of the "$mce_buttons" filters.
+ */
+ $mce_external_plugins = apply_filters('mce_external_plugins', array());
+
+ if ( ! empty($mce_external_plugins) ) {
+
+ /*
+ The following filter loads external language files for TinyMCE plugins.
+ It takes an associative array 'plugin_name' => 'path', where path is the
+ include path to the file. The language file should follow the same format as
+ /tinymce/langs/wp-langs.php and should define a variable $strings that
+ holds all translated strings.
+ When this filter is not used, the function will try to load {mce_locale}.js.
+ If that is not found, en.js will be tried next.
+ */
+ $mce_external_languages = apply_filters('mce_external_languages', array());
+
+ $loaded_langs = array();
+ $strings = '';
+
+ if ( ! empty($mce_external_languages) ) {
+ foreach ( $mce_external_languages as $name => $path ) {
+ if ( @is_file($path) && @is_readable($path) ) {
+ include_once($path);
+ $ext_plugins .= $strings . "\n";
+ $loaded_langs[] = $name;
+ }
+ }
+ }
+
+ foreach ( $mce_external_plugins as $name => $url ) {
+
+ $url = set_url_scheme( $url );
+
+ $plugins[] = '-' . $name;
+
+ $plugurl = dirname($url);
+ $strings = $str1 = $str2 = '';
+ if ( ! in_array($name, $loaded_langs) ) {
+ $path = str_replace( content_url(), '', $plugurl );
+ $path = WP_CONTENT_DIR . $path . '/langs/';
+
+ if ( function_exists('realpath') )
+ $path = trailingslashit( realpath($path) );
+
+ if ( @is_file($path . $mce_locale . '.js') )
+ $strings .= @file_get_contents($path . $mce_locale . '.js') . "\n";
+
+ if ( @is_file($path . $mce_locale . '_dlg.js') )
+ $strings .= @file_get_contents($path . $mce_locale . '_dlg.js') . "\n";
+
+ if ( 'en' != $mce_locale && empty($strings) ) {
+ if ( @is_file($path . 'en.js') ) {
+ $str1 = @file_get_contents($path . 'en.js');
+ $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
+ }
+
+ if ( @is_file($path . 'en_dlg.js') ) {
+ $str2 = @file_get_contents($path . 'en_dlg.js');
+ $strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
+ }
+ }
+
+ if ( ! empty($strings) )
+ $ext_plugins .= "\n" . $strings . "\n";
+ }
+
+ $ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
+ $ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
+ }
+ }
+
+ $plugins = array_unique( apply_filters('tiny_mce_plugins', $plugins) );
+ }
+
+ if ( $set['dfw'] )
+ $plugins[] = 'wpfullscreen';
+
+ self::$plugins = $plugins;
+ self::$ext_plugins = $ext_plugins;
+
+ if ( in_array( 'spellchecker', $plugins ) ) {
+ /*
+ translators: These languages show up in the spellchecker drop-down menu, in the order specified, and with the first
+ language listed being the default language. They must be comma-separated and take the format of name=code, where name
+ is the language name (which you may internationalize), and code is a valid ISO 639 language code. Please test the
+ spellchecker with your values.
+ */
+ $mce_spellchecker_languages = __( 'English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv' );
+
+ /*
+ The following filter allows localization scripts to change the languages displayed in the spellchecker's drop-down menu.
+ By default it uses Google's spellchecker API, but can be configured to use PSpell/ASpell if installed on the server.
+ The + sign marks the default language. More: http://www.tinymce.com/wiki.php/Plugin:spellchecker.
+ */
+ $mce_spellchecker_languages = apply_filters( 'mce_spellchecker_languages', '+' . $mce_spellchecker_languages );
+ }
+
+ self::$first_init = array(
+ 'mode' => 'exact',
+ 'width' => '100%',
+ 'theme' => 'advanced',
+ 'skin' => 'wp_theme',
+ 'language' => self::$mce_locale,
+ 'theme_advanced_toolbar_location' => 'top',
+ 'theme_advanced_toolbar_align' => 'left',
+ 'theme_advanced_statusbar_location' => 'bottom',
+ 'theme_advanced_resizing' => true,
+ 'theme_advanced_resize_horizontal' => false,
+ 'dialog_type' => 'modal',
+ 'formats' => "{
+ alignleft : [
+ {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}},
+ {selector : 'img,table', classes : 'alignleft'}
+ ],
+ aligncenter : [
+ {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}},
+ {selector : 'img,table', classes : 'aligncenter'}
+ ],
+ alignright : [
+ {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}},
+ {selector : 'img,table', classes : 'alignright'}
+ ],
+ strikethrough : {inline : 'del'}
+ }",
+ 'relative_urls' => false,
+ 'remove_script_host' => false,
+ 'convert_urls' => false,
+ 'remove_linebreaks' => true,
+ 'gecko_spellcheck' => true,
+ 'fix_list_elements' => true,
+ 'keep_styles' => false,
+ 'entities' => '38,amp,60,lt,62,gt',
+ 'accessibility_focus' => true,
+ 'media_strict' => false,
+ 'paste_remove_styles' => true,
+ 'paste_remove_spans' => true,
+ 'paste_strip_class_attributes' => 'all',
+ 'paste_text_use_dialog' => true,
+ 'webkit_fake_resize' => false,
+ 'preview_styles' => 'font-family font-weight text-decoration text-transform',
+ 'schema' => 'html5',
+ 'wpeditimage_disable_captions' => $no_captions,
+ 'wp_fullscreen_content_css' => self::$baseurl . '/plugins/wpfullscreen/css/wp-fullscreen.css',
+ 'plugins' => implode( ',', $plugins )
+ );
+
+ if ( in_array( 'spellchecker', $plugins ) ) {
+ self::$first_init['spellchecker_rpc_url'] = self::$baseurl . '/plugins/spellchecker/rpc.php';
+ self::$first_init['spellchecker_languages'] = $mce_spellchecker_languages;
+ }
+
+ // load editor_style.css if the current theme supports it
+ if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
+ $editor_styles = $GLOBALS['editor_styles'];
+
+ $mce_css = array();
+ $editor_styles = array_unique( array_filter( $editor_styles ) );
+ $style_uri = get_stylesheet_directory_uri();
+ $style_dir = get_stylesheet_directory();
+
+ // Support externally referenced styles (like, say, fonts).
+ foreach ( $editor_styles as $key => $file ) {
+ if ( preg_match( '~^(https?:)?//~', $file ) ) {
+ $mce_css[] = esc_url_raw( $file );
+ unset( $editor_styles[ $key ] );
+ }
+ }
+
+ // Look in a parent theme first, that way child theme CSS overrides.
+ if ( is_child_theme() ) {
+ $template_uri = get_template_directory_uri();
+ $template_dir = get_template_directory();
+
+ foreach ( $editor_styles as $key => $file ) {
+ if ( $file && file_exists( "$template_dir/$file" ) )
+ $mce_css[] = "$template_uri/$file";
+ }
+ }
+
+ foreach ( $editor_styles as $file ) {
+ if ( $file && file_exists( "$style_dir/$file" ) )
+ $mce_css[] = "$style_uri/$file";
+ }
+
+ $mce_css = implode( ',', $mce_css );
+ } else {
+ $mce_css = '';
+ }
+
+ $mce_css = trim( apply_filters( 'mce_css', $mce_css ), ' ,' );
+
+ if ( ! empty($mce_css) )
+ self::$first_init['content_css'] = $mce_css;
+ }
+
+ if ( $set['teeny'] ) {
+ $mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'undo', 'redo', 'link', 'unlink', 'fullscreen'), $editor_id );
+ $mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
+ } else {
+ $mce_buttons = apply_filters('mce_buttons', array('bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'justifyleft', 'justifycenter', 'justifyright', 'link', 'unlink', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' ), $editor_id);
+ $mce_buttons_2 = apply_filters('mce_buttons_2', array( 'formatselect', 'underline', 'justifyfull', 'forecolor', 'pastetext', 'pasteword', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' ), $editor_id);
+ $mce_buttons_3 = apply_filters('mce_buttons_3', array(), $editor_id);
+ $mce_buttons_4 = apply_filters('mce_buttons_4', array(), $editor_id);
+ }
+
+ $body_class = $editor_id;
+
+ if ( $post = get_post() ) {
+ $body_class .= ' post-type-' . sanitize_html_class( $post->post_type ) . ' post-status-' . sanitize_html_class( $post->post_status );
+ if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
+ $post_format = get_post_format( $post );
+ if ( $post_format && ! is_wp_error( $post_format ) )
+ $body_class .= ' post-format-' . sanitize_html_class( $post_format );
+ else
+ $body_class .= ' post-format-standard';
+ }
+ }
+
+ if ( !empty($set['tinymce']['body_class']) ) {
+ $body_class .= ' ' . $set['tinymce']['body_class'];
+ unset($set['tinymce']['body_class']);
+ }
+
+ if ( $set['dfw'] ) {
+ // replace the first 'fullscreen' with 'wp_fullscreen'
+ if ( ($key = array_search('fullscreen', $mce_buttons)) !== false )
+ $mce_buttons[$key] = 'wp_fullscreen';
+ elseif ( ($key = array_search('fullscreen', $mce_buttons_2)) !== false )
+ $mce_buttons_2[$key] = 'wp_fullscreen';
+ elseif ( ($key = array_search('fullscreen', $mce_buttons_3)) !== false )
+ $mce_buttons_3[$key] = 'wp_fullscreen';
+ elseif ( ($key = array_search('fullscreen', $mce_buttons_4)) !== false )
+ $mce_buttons_4[$key] = 'wp_fullscreen';
+ }
+
+ $mceInit = array (
+ 'elements' => $editor_id,
+ 'wpautop' => (bool) $set['wpautop'],
+ 'remove_linebreaks' => (bool) $set['wpautop'],
+ 'apply_source_formatting' => (bool) !$set['wpautop'],
+ 'theme_advanced_buttons1' => implode($mce_buttons, ','),
+ 'theme_advanced_buttons2' => implode($mce_buttons_2, ','),
+ 'theme_advanced_buttons3' => implode($mce_buttons_3, ','),
+ 'theme_advanced_buttons4' => implode($mce_buttons_4, ','),
+ 'tabfocus_elements' => $set['tabfocus_elements'],
+ 'body_class' => $body_class
+ );
+
+ // The main editor doesn't use the TinyMCE resizing cookie.
+ $mceInit['theme_advanced_resizing_use_cookie'] = 'content' !== $editor_id || empty( $set['editor_height'] );
+
+ if ( $first_run )
+ $mceInit = array_merge(self::$first_init, $mceInit);
+
+ if ( is_array($set['tinymce']) )
+ $mceInit = array_merge($mceInit, $set['tinymce']);
+
+ // For people who really REALLY know what they're doing with TinyMCE
+ // You can modify $mceInit to add, remove, change elements of the config before tinyMCE.init
+ // Setting "valid_elements", "invalid_elements" and "extended_valid_elements" can be done through this filter.
+ // Best is to use the default cleanup by not specifying valid_elements, as TinyMCE contains full set of XHTML 1.0.
+ if ( $set['teeny'] ) {
+ $mceInit = apply_filters('teeny_mce_before_init', $mceInit, $editor_id);
+ } else {
+ $mceInit = apply_filters('tiny_mce_before_init', $mceInit, $editor_id);
+ }
+
+ if ( empty($mceInit['theme_advanced_buttons3']) && !empty($mceInit['theme_advanced_buttons4']) ) {
+ $mceInit['theme_advanced_buttons3'] = $mceInit['theme_advanced_buttons4'];
+ $mceInit['theme_advanced_buttons4'] = '';
+ }
+
+ self::$mce_settings[$editor_id] = $mceInit;
+ } // end if self::$this_tinymce
+ }
+
+ private static function _parse_init($init) {
+ $options = '';
+
+ foreach ( $init as $k => $v ) {
+ if ( is_bool($v) ) {
+ $val = $v ? 'true' : 'false';
+ $options .= $k . ':' . $val . ',';
+ continue;
+ } elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
+ $options .= $k . ':' . $v . ',';
+ continue;
+ }
+ $options .= $k . ':"' . $v . '",';
+ }
+
+ return '{' . trim( $options, ' ,' ) . '}';
+ }
+
+ public static function enqueue_scripts() {
+ wp_enqueue_script('word-count');
+
+ if ( self::$has_tinymce )
+ wp_enqueue_script('editor');
+
+ if ( self::$has_quicktags )
+ wp_enqueue_script('quicktags');
+
+ if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
+ wp_enqueue_script('wplink');
+ wp_enqueue_script('wpdialogs-popup');
+ wp_enqueue_style('wp-jquery-ui-dialog');
+ }
+
+ if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
+ wp_enqueue_script('wp-fullscreen');
+
+ if ( self::$has_medialib ) {
+ add_thickbox();
+ wp_enqueue_script('media-upload');
+ }
+ }
+
+ public static function editor_js() {
+ global $tinymce_version, $concatenate_scripts, $compress_scripts;
+
+ /**
+ * Filter "tiny_mce_version" is deprecated
+ *
+ * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
+ * These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
+ * If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
+ */
+ $version = 'ver=' . $tinymce_version;
+ $tmce_on = !empty(self::$mce_settings);
+
+ if ( ! isset($concatenate_scripts) )
+ script_concat_settings();
+
+ $compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
+ && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
+
+ if ( $tmce_on && 'en' != self::$mce_locale )
+ include_once(ABSPATH . WPINC . '/js/tinymce/langs/wp-langs.php');
+
+ $mceInit = $qtInit = '';
+ if ( $tmce_on ) {
+ foreach ( self::$mce_settings as $editor_id => $init ) {
+ $options = self::_parse_init( $init );
+ $mceInit .= "'$editor_id':{$options},";
+ }
+ $mceInit = '{' . trim($mceInit, ',') . '}';
+ } else {
+ $mceInit = '{}';
+ }
+
+ if ( !empty(self::$qt_settings) ) {
+ foreach ( self::$qt_settings as $editor_id => $init ) {
+ $options = self::_parse_init( $init );
+ $qtInit .= "'$editor_id':{$options},";
+ }
+ $qtInit = '{' . trim($qtInit, ',') . '}';
+ } else {
+ $qtInit = '{}';
+ }
+
+ $ref = array(
+ 'plugins' => implode( ',', self::$plugins ),
+ 'theme' => 'advanced',
+ 'language' => self::$mce_locale
+ );
+
+ $suffix = ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? '_src' : '';
+
+ do_action('before_wp_tiny_mce', self::$mce_settings);
+?>
+
+ <script type="text/javascript">
+ tinyMCEPreInit = {
+ base : "<?php echo self::$baseurl; ?>",
+ suffix : "<?php echo $suffix; ?>",
+ query : "<?php echo $version; ?>",
+ mceInit : <?php echo $mceInit; ?>,
+ qtInit : <?php echo $qtInit; ?>,
+ ref : <?php echo self::_parse_init( $ref ); ?>,
+ load_ext : function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
+ };
+ </script>
+<?php
+
+ $baseurl = self::$baseurl;
+
+ if ( $tmce_on ) {
+ if ( $compressed ) {
+ echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
+ } else {
+ echo "<script type='text/javascript' src='{$baseurl}/tiny_mce.js?$version'></script>\n";
+ echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce-schema.js?$version'></script>\n";
+ }
+
+ if ( 'en' != self::$mce_locale && isset($lang) )
+ echo "<script type='text/javascript'>\n$lang\n</script>\n";
+ else
+ echo "<script type='text/javascript' src='{$baseurl}/langs/wp-langs-en.js?$version'></script>\n";
+ }
+
+ $mce = ( self::$has_tinymce && wp_default_editor() == 'tinymce' ) || ! self::$has_quicktags;
+?>
+
+ <script type="text/javascript">
+ var wpActiveEditor;
+
+ (function(){
+ var init, ed, qt, first_init, DOM, el, i, mce = <?php echo (int) $mce; ?>;
+
+ if ( typeof(tinymce) == 'object' ) {
+ DOM = tinymce.DOM;
+ // mark wp_theme/ui.css as loaded
+ DOM.files[tinymce.baseURI.getURI() + '/themes/advanced/skins/wp_theme/ui.css'] = true;
+
+ DOM.events.add( DOM.select('.wp-editor-wrap'), 'mousedown', function(e){
+ if ( this.id )
+ wpActiveEditor = this.id.slice(3, -5);
+ });
+
+ for ( ed in tinyMCEPreInit.mceInit ) {
+ if ( first_init ) {
+ init = tinyMCEPreInit.mceInit[ed] = tinymce.extend( {}, first_init, tinyMCEPreInit.mceInit[ed] );
+ } else {
+ init = first_init = tinyMCEPreInit.mceInit[ed];
+ }
+
+ if ( mce )
+ try { tinymce.init(init); } catch(e){}
+ }
+ } else {
+ if ( tinyMCEPreInit.qtInit ) {
+ for ( i in tinyMCEPreInit.qtInit ) {
+ el = tinyMCEPreInit.qtInit[i].id;
+ if ( el )
+ document.getElementById('wp-'+el+'-wrap').onmousedown = function(){ wpActiveEditor = this.id.slice(3, -5); }
+ }
+ }
+ }
+
+ if ( typeof(QTags) == 'function' ) {
+ for ( qt in tinyMCEPreInit.qtInit ) {
+ try { quicktags( tinyMCEPreInit.qtInit[qt] ); } catch(e){}
+ }
+ }
+ })();
+ <?php
+
+ if ( self::$ext_plugins )
+ echo self::$ext_plugins . "\n";
+
+ if ( ! $compressed && $tmce_on ) {
+ ?>
+ (function(){var t=tinyMCEPreInit,sl=tinymce.ScriptLoader,ln=t.ref.language,th=t.ref.theme,pl=t.ref.plugins;sl.markDone(t.base+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'.js');sl.markDone(t.base+'/themes/'+th+'/langs/'+ln+'_dlg.js');sl.markDone(t.base+'/themes/advanced/skins/wp_theme/ui.css');tinymce.each(pl.split(','),function(n){if(n&&n.charAt(0)!='-'){sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'.js');sl.markDone(t.base+'/plugins/'+n+'/langs/'+ln+'_dlg.js');}});})();
+ <?php
+ }
+
+ if ( !is_admin() )
+ echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';
+
+ ?>
+ </script>
+ <?php
+
+ if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) )
+ self::wp_link_dialog();
+
+ if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
+ self::wp_fullscreen_html();
+
+ do_action('after_wp_tiny_mce', self::$mce_settings);
+ }
+
+ public static function wp_fullscreen_html() {
+ global $content_width;
+ $post = get_post();
+
+ $width = isset($content_width) && 800 > $content_width ? $content_width : 800;
+ $width = $width + 22; // compensate for the padding and border
+ $dfw_width = get_user_setting( 'dfw_width', $width );
+ $save = isset($post->post_status) && $post->post_status == 'publish' ? __('Update') : __('Save');
+ ?>
+ <div id="wp-fullscreen-body"<?php if ( is_rtl() ) echo ' class="rtl"'; ?>>
+ <div id="fullscreen-topbar">
+ <div id="wp-fullscreen-toolbar">
+ <div id="wp-fullscreen-close"><a href="#" onclick="fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
+ <div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
+
+ <div id="wp-fullscreen-mode-bar"><div id="wp-fullscreen-modes">
+ <a href="#" onclick="fullscreen.switchmode('tinymce');return false;"><?php _e( 'Visual' ); ?></a>
+ <a href="#" onclick="fullscreen.switchmode('html');return false;"><?php _ex( 'Text', 'Name for the Text editor tab (formerly HTML)' ); ?></a>
+ </div></div>
+
+ <div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="wp_themeSkin">
+ <?php
+
+ $buttons = array(
+ // format: title, onclick, show in both editors
+ 'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'onclick' => 'fullscreen.b();', 'both' => false ),
+ 'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'onclick' => 'fullscreen.i();', 'both' => false ),
+ '0' => 'separator',
+ 'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'onclick' => 'fullscreen.ul();', 'both' => false ),
+ 'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'onclick' => 'fullscreen.ol();', 'both' => false ),
+ '1' => 'separator',
+ 'blockquote' => array( 'title' => __('Blockquote (Alt + Shift + Q)'), 'onclick' => 'fullscreen.blockquote();', 'both' => false ),
+ 'image' => array( 'title' => __('Insert/edit image (Alt + Shift + M)'), 'onclick' => "fullscreen.medialib();", 'both' => true ),
+ '2' => 'separator',
+ 'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'onclick' => 'fullscreen.link();', 'both' => true ),
+ 'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'onclick' => 'fullscreen.unlink();', 'both' => false ),
+ '3' => 'separator',
+ 'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'onclick' => 'fullscreen.help();', 'both' => false )
+ );
+
+ $buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
+
+ foreach ( $buttons as $button => $args ) {
+ if ( 'separator' == $args ) { ?>
+ <div><span aria-orientation="vertical" role="separator" class="mceSeparator"></span></div>
+ <?php continue;
+ } ?>
+
+ <div<?php if ( $args['both'] ) { ?> class="wp-fullscreen-both"<?php } ?>>
+ <a title="<?php echo $args['title']; ?>" onclick="<?php echo $args['onclick']; ?>return false;" class="mceButton mceButtonEnabled mce_<?php echo $button; ?>" href="#" id="wp_fs_<?php echo $button; ?>" role="button" aria-pressed="false">
+ <span class="mceIcon mce_<?php echo $button; ?>"></span>
+ </a>
+ </div>
+ <?php
+ } ?>
+
+ </div></div>
+
+ <div id="wp-fullscreen-save">
+ <input type="button" class="button-primary right" value="<?php echo $save; ?>" onclick="fullscreen.save();" />
+ <span class="spinner"></span>
+ <span class="fs-saved"><?php if ( $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
+ </div>
+
+ </div>
+ </div>
+ </div>
+
+ <div id="wp-fullscreen-wrap" style="width:<?php echo $dfw_width; ?>px;">
+ <?php if ( post_type_supports($post->post_type, 'title') ) { ?>
+ <label id="wp-fullscreen-title-prompt-text" for="wp-fullscreen-title"><?php echo apply_filters( 'enter_title_here', __( 'Enter title here' ), $post ); ?></label>
+ <input type="text" id="wp-fullscreen-title" value="" autocomplete="off" />
+ <?php } ?>
+
+ <div id="wp-fullscreen-container">
+ <textarea id="wp_mce_fullscreen"></textarea>
+ </div>
+
+ <div id="wp-fullscreen-status">
+ <div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
+ <div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
+ </div>
+ </div>
+ </div>
+
+ <div class="fullscreen-overlay" id="fullscreen-overlay"></div>
+ <div class="fullscreen-overlay fullscreen-fader fade-600" id="fullscreen-fader"></div>
+ <?php
+ }
+
+ /**
+ * Performs post queries for internal linking.
+ *
+ * @since 3.1.0
+ *
+ * @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
+ * @return array Results.
+ */
+ public static function wp_link_query( $args = array() ) {
+ $pts = get_post_types( array( 'public' => true ), 'objects' );
+ $pt_names = array_keys( $pts );
+
+ $query = array(
+ 'post_type' => $pt_names,
+ 'suppress_filters' => true,
+ 'update_post_term_cache' => false,
+ 'update_post_meta_cache' => false,
+ 'post_status' => 'publish',
+ 'order' => 'DESC',
+ 'orderby' => 'post_date',
+ 'posts_per_page' => 20,
+ );
+
+ $args['pagenum'] = isset( $args['pagenum'] ) ? absint( $args['pagenum'] ) : 1;
+
+ if ( isset( $args['s'] ) )
+ $query['s'] = $args['s'];
+
+ $query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
+
+ // Do main query.
+ $get_posts = new WP_Query;
+ $posts = $get_posts->query( $query );
+ // Check if any posts were found.
+ if ( ! $get_posts->post_count )
+ return false;
+
+ // Build results.
+ $results = array();
+ foreach ( $posts as $post ) {
+ if ( 'post' == $post->post_type )
+ $info = mysql2date( __( 'Y/m/d' ), $post->post_date );
+ else
+ $info = $pts[ $post->post_type ]->labels->singular_name;
+
+ $results[] = array(
+ 'ID' => $post->ID,
+ 'title' => trim( esc_html( strip_tags( get_the_title( $post ) ) ) ),
+ 'permalink' => get_permalink( $post->ID ),
+ 'info' => $info,
+ );
+ }
+
+ return $results;
+ }
+
+ /**
+ * Dialog for internal linking.
+ *
+ * @since 3.1.0
+ */
+ public static function wp_link_dialog() {
+ ?>
+ <div style="display:none;">
+ <form id="wp-link" tabindex="-1">
+ <?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
+ <div id="link-selector">
+ <div id="link-options">
+ <p class="howto"><?php _e( 'Enter the destination URL' ); ?></p>
+ <div>
+ <label><span><?php _e( 'URL' ); ?></span><input id="url-field" type="text" name="href" /></label>
+ </div>
+ <div>
+ <label><span><?php _e( 'Title' ); ?></span><input id="link-title-field" type="text" name="linktitle" /></label>
+ </div>
+ <div class="link-target">
+ <label><input type="checkbox" id="link-target-checkbox" /> <?php _e( 'Open link in a new window/tab' ); ?></label>
+ </div>
+ </div>
+ <?php $show_internal = '1' == get_user_setting( 'wplink', '0' ); ?>
+ <p class="howto toggle-arrow <?php if ( $show_internal ) echo 'toggle-arrow-active'; ?>" id="internal-toggle"><?php _e( 'Or link to existing content' ); ?></p>
+ <div id="search-panel"<?php if ( ! $show_internal ) echo ' style="display:none"'; ?>>
+ <div class="link-search-wrapper">
+ <label>
+ <span class="search-label"><?php _e( 'Search' ); ?></span>
+ <input type="search" id="search-field" class="link-search-field" autocomplete="off" />
+ <span class="spinner"></span>
+ </label>
+ </div>
+ <div id="search-results" class="query-results">
+ <ul></ul>
+ <div class="river-waiting">
+ <span class="spinner"></span>
+ </div>
+ </div>
+ <div id="most-recent-results" class="query-results">
+ <div class="query-notice"><em><?php _e( 'No search term specified. Showing recent items.' ); ?></em></div>
+ <ul></ul>
+ <div class="river-waiting">
+ <span class="spinner"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="submitbox">
+ <div id="wp-link-update">
+ <input type="submit" value="<?php esc_attr_e( 'Add Link' ); ?>" class="button-primary" id="wp-link-submit" name="wp-link-submit">
+ </div>
+ <div id="wp-link-cancel">
+ <a class="submitdelete deletion" href="#"><?php _e( 'Cancel' ); ?></a>
+ </div>
+ </div>
+ </form>
+ </div>
+ <?php
+ }
+}
diff --git a/src/wp-includes/class-wp-embed.php b/src/wp-includes/class-wp-embed.php
new file mode 100644
index 0000000000..c5381846f4
--- /dev/null
+++ b/src/wp-includes/class-wp-embed.php
@@ -0,0 +1,277 @@
+<?php
+/**
+ * API for easily embedding rich media such as videos and images into content.
+ *
+ * @package WordPress
+ * @subpackage Embed
+ * @since 2.9.0
+ */
+class WP_Embed {
+ var $handlers = array();
+ var $post_ID;
+ var $usecache = true;
+ var $linkifunknown = true;
+
+ /**
+ * Constructor
+ */
+ function __construct() {
+ // Hack to get the [embed] shortcode to run before wpautop()
+ add_filter( 'the_content', array( $this, 'run_shortcode' ), 8 );
+
+ // Shortcode placeholder for strip_shortcodes()
+ add_shortcode( 'embed', '__return_false' );
+
+ // Attempts to embed all URLs in a post
+ add_filter( 'the_content', array( $this, 'autoembed' ), 8 );
+
+ // When a post is saved, invalidate the oEmbed cache
+ add_action( 'pre_post_update', array( $this, 'delete_oembed_caches' ) );
+
+ // After a post is saved, cache oEmbed items via AJAX
+ add_action( 'edit_form_advanced', array( $this, 'maybe_run_ajax_cache' ) );
+ }
+
+ /**
+ * Process the [embed] shortcode.
+ *
+ * Since the [embed] shortcode needs to be run earlier than other shortcodes,
+ * this function removes all existing shortcodes, registers the [embed] shortcode,
+ * calls {@link do_shortcode()}, and then re-registers the old shortcodes.
+ *
+ * @uses $shortcode_tags
+ * @uses remove_all_shortcodes()
+ * @uses add_shortcode()
+ * @uses do_shortcode()
+ *
+ * @param string $content Content to parse
+ * @return string Content with shortcode parsed
+ */
+ function run_shortcode( $content ) {
+ global $shortcode_tags;
+
+ // Back up current registered shortcodes and clear them all out
+ $orig_shortcode_tags = $shortcode_tags;
+ remove_all_shortcodes();
+
+ add_shortcode( 'embed', array( $this, 'shortcode' ) );
+
+ // Do the shortcode (only the [embed] one is registered)
+ $content = do_shortcode( $content );
+
+ // Put the original shortcodes back
+ $shortcode_tags = $orig_shortcode_tags;
+
+ return $content;
+ }
+
+ /**
+ * If a post/page was saved, then output JavaScript to make
+ * an AJAX request that will call WP_Embed::cache_oembed().
+ */
+ function maybe_run_ajax_cache() {
+ $post = get_post();
+
+ if ( ! $post || empty($_GET['message']) || 1 != $_GET['message'] )
+ return;
+
+?>
+<script type="text/javascript">
+/* <![CDATA[ */
+ jQuery(document).ready(function($){
+ $.get("<?php echo admin_url( 'admin-ajax.php?action=oembed-cache&post=' . $post->ID, 'relative' ); ?>");
+ });
+/* ]]> */
+</script>
+<?php
+ }
+
+ /**
+ * Register an embed handler. Do not use this function directly, use {@link wp_embed_register_handler()} instead.
+ * This function should probably also only be used for sites that do not support oEmbed.
+ *
+ * @param string $id An internal ID/name for the handler. Needs to be unique.
+ * @param string $regex The regex that will be used to see if this handler should be used for a URL.
+ * @param callback $callback The callback function that will be called if the regex is matched.
+ * @param int $priority Optional. Used to specify the order in which the registered handlers will be tested (default: 10). Lower numbers correspond with earlier testing, and handlers with the same priority are tested in the order in which they were added to the action.
+ */
+ function register_handler( $id, $regex, $callback, $priority = 10 ) {
+ $this->handlers[$priority][$id] = array(
+ 'regex' => $regex,
+ 'callback' => $callback,
+ );
+ }
+
+ /**
+ * Unregister a previously registered embed handler. Do not use this function directly, use {@link wp_embed_unregister_handler()} instead.
+ *
+ * @param string $id The handler ID that should be removed.
+ * @param int $priority Optional. The priority of the handler to be removed (default: 10).
+ */
+ function unregister_handler( $id, $priority = 10 ) {
+ if ( isset($this->handlers[$priority][$id]) )
+ unset($this->handlers[$priority][$id]);
+ }
+
+ /**
+ * The {@link do_shortcode()} callback function.
+ *
+ * Attempts to convert a URL into embed HTML. Starts by checking the URL against the regex of the registered embed handlers.
+ * If none of the regex matches and it's enabled, then the URL will be given to the {@link WP_oEmbed} class.
+ *
+ * @uses wp_oembed_get()
+ * @uses wp_parse_args()
+ * @uses wp_embed_defaults()
+ * @uses WP_Embed::maybe_make_link()
+ * @uses get_option()
+ * @uses author_can()
+ * @uses wp_cache_get()
+ * @uses wp_cache_set()
+ * @uses get_post_meta()
+ * @uses update_post_meta()
+ *
+ * @param array $attr Shortcode attributes.
+ * @param string $url The URL attempting to be embedded.
+ * @return string The embed HTML on success, otherwise the original URL.
+ */
+ function shortcode( $attr, $url = '' ) {
+ $post = get_post();
+
+ if ( empty( $url ) )
+ return '';
+
+ $rawattr = $attr;
+ $attr = wp_parse_args( $attr, wp_embed_defaults() );
+
+ // kses converts & into &amp; and we need to undo this
+ // See http://core.trac.wordpress.org/ticket/11311
+ $url = str_replace( '&amp;', '&', $url );
+
+ // Look for known internal handlers
+ ksort( $this->handlers );
+ foreach ( $this->handlers as $priority => $handlers ) {
+ foreach ( $handlers as $id => $handler ) {
+ if ( preg_match( $handler['regex'], $url, $matches ) && is_callable( $handler['callback'] ) ) {
+ if ( false !== $return = call_user_func( $handler['callback'], $matches, $attr, $url, $rawattr ) )
+ return apply_filters( 'embed_handler_html', $return, $url, $attr );
+ }
+ }
+ }
+
+ $post_ID = ( ! empty( $post->ID ) ) ? $post->ID : null;
+ if ( ! empty( $this->post_ID ) ) // Potentially set by WP_Embed::cache_oembed()
+ $post_ID = $this->post_ID;
+
+ // Unknown URL format. Let oEmbed have a go.
+ if ( $post_ID ) {
+
+ // Check for a cached result (stored in the post meta)
+ $cachekey = '_oembed_' . md5( $url . serialize( $attr ) );
+ if ( $this->usecache ) {
+ $cache = get_post_meta( $post_ID, $cachekey, true );
+
+ // Failures are cached
+ if ( '{{unknown}}' === $cache )
+ return $this->maybe_make_link( $url );
+
+ if ( ! empty( $cache ) )
+ return apply_filters( 'embed_oembed_html', $cache, $url, $attr, $post_ID );
+ }
+
+ // Use oEmbed to get the HTML
+ $attr['discover'] = ( apply_filters('embed_oembed_discover', false) && author_can( $post_ID, 'unfiltered_html' ) );
+ $html = wp_oembed_get( $url, $attr );
+
+ // Cache the result
+ $cache = ( $html ) ? $html : '{{unknown}}';
+ update_post_meta( $post_ID, $cachekey, $cache );
+
+ // If there was a result, return it
+ if ( $html )
+ return apply_filters( 'embed_oembed_html', $html, $url, $attr, $post_ID );
+ }
+
+ // Still unknown
+ return $this->maybe_make_link( $url );
+ }
+
+ /**
+ * Delete all oEmbed caches.
+ *
+ * @param int $post_ID Post ID to delete the caches for.
+ */
+ function delete_oembed_caches( $post_ID ) {
+ $post_metas = get_post_custom_keys( $post_ID );
+ if ( empty($post_metas) )
+ return;
+
+ foreach( $post_metas as $post_meta_key ) {
+ if ( '_oembed_' == substr( $post_meta_key, 0, 8 ) )
+ delete_post_meta( $post_ID, $post_meta_key );
+ }
+ }
+
+ /**
+ * Triggers a caching of all oEmbed results.
+ *
+ * @param int $post_ID Post ID to do the caching for.
+ */
+ function cache_oembed( $post_ID ) {
+ $post = get_post( $post_ID );
+
+ if ( empty($post->ID) || !in_array( $post->post_type, apply_filters( 'embed_cache_oembed_types', array( 'post', 'page' ) ) ) )
+ return;
+
+ // Trigger a caching
+ if ( !empty($post->post_content) ) {
+ $this->post_ID = $post->ID;
+ $this->usecache = false;
+
+ $content = $this->run_shortcode( $post->post_content );
+ $this->autoembed( $content );
+
+ $this->usecache = true;
+ }
+ }
+
+ /**
+ * Passes any unlinked URLs that are on their own line to {@link WP_Embed::shortcode()} for potential embedding.
+ *
+ * @uses WP_Embed::autoembed_callback()
+ *
+ * @param string $content The content to be searched.
+ * @return string Potentially modified $content.
+ */
+ function autoembed( $content ) {
+ return preg_replace_callback( '|^\s*(https?://[^\s"]+)\s*$|im', array( $this, 'autoembed_callback' ), $content );
+ }
+
+ /**
+ * Callback function for {@link WP_Embed::autoembed()}.
+ *
+ * @uses WP_Embed::shortcode()
+ *
+ * @param array $match A regex match array.
+ * @return string The embed HTML on success, otherwise the original URL.
+ */
+ function autoembed_callback( $match ) {
+ $oldval = $this->linkifunknown;
+ $this->linkifunknown = false;
+ $return = $this->shortcode( array(), $match[1] );
+ $this->linkifunknown = $oldval;
+
+ return "\n$return\n";
+ }
+
+ /**
+ * Conditionally makes a hyperlink based on an internal class variable.
+ *
+ * @param string $url URL to potentially be linked.
+ * @return string Linked URL or the original URL.
+ */
+ function maybe_make_link( $url ) {
+ $output = ( $this->linkifunknown ) ? '<a href="' . esc_url($url) . '">' . esc_html($url) . '</a>' : $url;
+ return apply_filters( 'embed_maybe_make_link', $output, $url );
+ }
+}
+$GLOBALS['wp_embed'] = new WP_Embed();
diff --git a/src/wp-includes/class-wp-error.php b/src/wp-includes/class-wp-error.php
new file mode 100644
index 0000000000..bbfcebc444
--- /dev/null
+++ b/src/wp-includes/class-wp-error.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * WordPress Error API.
+ *
+ * Contains the WP_Error class and the is_wp_error() function.
+ *
+ * @package WordPress
+ */
+
+/**
+ * WordPress Error class.
+ *
+ * Container for checking for WordPress errors and error messages. Return
+ * WP_Error and use {@link is_wp_error()} to check if this class is returned.
+ * Many core WordPress functions pass this class in the event of an error and
+ * if not handled properly will result in code errors.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ */
+class WP_Error {
+ /**
+ * Stores the list of errors.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $errors = array();
+
+ /**
+ * Stores the list of data for error codes.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $error_data = array();
+
+ /**
+ * Constructor - Sets up error message.
+ *
+ * If code parameter is empty then nothing will be done. It is possible to
+ * add multiple messages to the same code, but with other methods in the
+ * class.
+ *
+ * All parameters are optional, but if the code parameter is set, then the
+ * data parameter is optional.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Error code
+ * @param string $message Error message
+ * @param mixed $data Optional. Error data.
+ * @return WP_Error
+ */
+ function __construct($code = '', $message = '', $data = '') {
+ if ( empty($code) )
+ return;
+
+ $this->errors[$code][] = $message;
+
+ if ( ! empty($data) )
+ $this->error_data[$code] = $data;
+ }
+
+ /**
+ * Retrieve all error codes.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return array List of error codes, if available.
+ */
+ function get_error_codes() {
+ if ( empty($this->errors) )
+ return array();
+
+ return array_keys($this->errors);
+ }
+
+ /**
+ * Retrieve first error code available.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @return string|int Empty string, if no error codes.
+ */
+ function get_error_code() {
+ $codes = $this->get_error_codes();
+
+ if ( empty($codes) )
+ return '';
+
+ return $codes[0];
+ }
+
+ /**
+ * Retrieve all error messages or error messages matching code.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Optional. Retrieve messages matching code, if exists.
+ * @return array Error strings on success, or empty array on failure (if using code parameter).
+ */
+ function get_error_messages($code = '') {
+ // Return all messages if no code specified.
+ if ( empty($code) ) {
+ $all_messages = array();
+ foreach ( (array) $this->errors as $code => $messages )
+ $all_messages = array_merge($all_messages, $messages);
+
+ return $all_messages;
+ }
+
+ if ( isset($this->errors[$code]) )
+ return $this->errors[$code];
+ else
+ return array();
+ }
+
+ /**
+ * Get single error message.
+ *
+ * This will get the first message available for the code. If no code is
+ * given then the first code available will be used.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Optional. Error code to retrieve message.
+ * @return string
+ */
+ function get_error_message($code = '') {
+ if ( empty($code) )
+ $code = $this->get_error_code();
+ $messages = $this->get_error_messages($code);
+ if ( empty($messages) )
+ return '';
+ return $messages[0];
+ }
+
+ /**
+ * Retrieve error data for error code.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $code Optional. Error code.
+ * @return mixed Null, if no errors.
+ */
+ function get_error_data($code = '') {
+ if ( empty($code) )
+ $code = $this->get_error_code();
+
+ if ( isset($this->error_data[$code]) )
+ return $this->error_data[$code];
+ return null;
+ }
+
+ /**
+ * Append more error messages to list of error messages.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string|int $code Error code.
+ * @param string $message Error message.
+ * @param mixed $data Optional. Error data.
+ */
+ function add($code, $message, $data = '') {
+ $this->errors[$code][] = $message;
+ if ( ! empty($data) )
+ $this->error_data[$code] = $data;
+ }
+
+ /**
+ * Add data for error code.
+ *
+ * The error code can only contain one error data.
+ *
+ * @since 2.1.0
+ *
+ * @param mixed $data Error data.
+ * @param string|int $code Error code.
+ */
+ function add_data($data, $code = '') {
+ if ( empty($code) )
+ $code = $this->get_error_code();
+
+ $this->error_data[$code] = $data;
+ }
+}
+
+/**
+ * Check whether variable is a WordPress Error.
+ *
+ * Returns true if $thing is an object of the WP_Error class.
+ *
+ * @since 2.1.0
+ *
+ * @param mixed $thing Check if unknown variable is a WP_Error object.
+ * @return bool True, if WP_Error. False, if not WP_Error.
+ */
+function is_wp_error($thing) {
+ if ( is_object($thing) && is_a($thing, 'WP_Error') )
+ return true;
+ return false;
+}
diff --git a/src/wp-includes/class-wp-http-ixr-client.php b/src/wp-includes/class-wp-http-ixr-client.php
new file mode 100644
index 0000000000..736fc5a223
--- /dev/null
+++ b/src/wp-includes/class-wp-http-ixr-client.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * WP_HTTP_IXR_Client
+ *
+ * @package WordPress
+ * @since 3.1.0
+ *
+ */
+class WP_HTTP_IXR_Client extends IXR_Client {
+
+ function __construct($server, $path = false, $port = false, $timeout = 15) {
+ if ( ! $path ) {
+ // Assume we have been given a URL instead
+ $bits = parse_url($server);
+ $this->scheme = $bits['scheme'];
+ $this->server = $bits['host'];
+ $this->port = isset($bits['port']) ? $bits['port'] : $port;
+ $this->path = !empty($bits['path']) ? $bits['path'] : '/';
+
+ // Make absolutely sure we have a path
+ if ( ! $this->path )
+ $this->path = '/';
+ } else {
+ $this->scheme = 'http';
+ $this->server = $server;
+ $this->path = $path;
+ $this->port = $port;
+ }
+ $this->useragent = 'The Incutio XML-RPC PHP Library';
+ $this->timeout = $timeout;
+ }
+
+ function query() {
+ $args = func_get_args();
+ $method = array_shift($args);
+ $request = new IXR_Request($method, $args);
+ $xml = $request->getXml();
+
+ $port = $this->port ? ":$this->port" : '';
+ $url = $this->scheme . '://' . $this->server . $port . $this->path;
+ $args = array(
+ 'headers' => array('Content-Type' => 'text/xml'),
+ 'user-agent' => $this->useragent,
+ 'body' => $xml,
+ );
+
+ // Merge Custom headers ala #8145
+ foreach ( $this->headers as $header => $value )
+ $args['headers'][$header] = $value;
+
+ if ( $this->timeout !== false )
+ $args['timeout'] = $this->timeout;
+
+ // Now send the request
+ if ( $this->debug )
+ echo '<pre class="ixr_request">' . htmlspecialchars($xml) . "\n</pre>\n\n";
+
+ $response = wp_remote_post($url, $args);
+
+ if ( is_wp_error($response) ) {
+ $errno = $response->get_error_code();
+ $errorstr = $response->get_error_message();
+ $this->error = new IXR_Error(-32300, "transport error: $errno $errorstr");
+ return false;
+ }
+
+ if ( 200 != wp_remote_retrieve_response_code( $response ) ) {
+ $this->error = new IXR_Error(-32301, 'transport error - HTTP status code was not 200 (' . wp_remote_retrieve_response_code( $response ) . ')');
+ return false;
+ }
+
+ if ( $this->debug )
+ echo '<pre class="ixr_response">' . htmlspecialchars( wp_remote_retrieve_body( $response ) ) . "\n</pre>\n\n";
+
+ // Now parse what we've got back
+ $this->message = new IXR_Message( wp_remote_retrieve_body( $response ) );
+ if ( ! $this->message->parse() ) {
+ // XML error
+ $this->error = new IXR_Error(-32700, 'parse error. not well formed');
+ return false;
+ }
+
+ // Is the message a fault?
+ if ( $this->message->messageType == 'fault' ) {
+ $this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
+ return false;
+ }
+
+ // Message must be OK
+ return true;
+ }
+}
diff --git a/src/wp-includes/class-wp-image-editor-gd.php b/src/wp-includes/class-wp-image-editor-gd.php
new file mode 100644
index 0000000000..12aaece1eb
--- /dev/null
+++ b/src/wp-includes/class-wp-image-editor-gd.php
@@ -0,0 +1,422 @@
+<?php
+/**
+ * WordPress GD Image Editor
+ *
+ * @package WordPress
+ * @subpackage Image_Editor
+ */
+
+/**
+ * WordPress Image Editor Class for Image Manipulation through GD
+ *
+ * @since 3.5.0
+ * @package WordPress
+ * @subpackage Image_Editor
+ * @uses WP_Image_Editor Extends class
+ */
+class WP_Image_Editor_GD extends WP_Image_Editor {
+
+ protected $image = false; // GD Resource
+
+ function __destruct() {
+ if ( $this->image ) {
+ // we don't need the original in memory anymore
+ imagedestroy( $this->image );
+ }
+ }
+
+ /**
+ * Checks to see if current environment supports GD.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @return boolean
+ */
+ public static function test( $args = array() ) {
+ if ( ! extension_loaded('gd') || ! function_exists('gd_info') )
+ return false;
+
+ // On some setups GD library does not provide imagerotate() - Ticket #11536
+ if ( isset( $args['methods'] ) &&
+ in_array( 'rotate', $args['methods'] ) &&
+ ! function_exists('imagerotate') ){
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks to see if editor supports the mime-type specified.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $mime_type
+ * @return boolean
+ */
+ public static function supports_mime_type( $mime_type ) {
+ $image_types = imagetypes();
+ switch( $mime_type ) {
+ case 'image/jpeg':
+ return ($image_types & IMG_JPG) != 0;
+ case 'image/png':
+ return ($image_types & IMG_PNG) != 0;
+ case 'image/gif':
+ return ($image_types & IMG_GIF) != 0;
+ }
+
+ return false;
+ }
+
+ /**
+ * Loads image from $this->file into new GD Resource.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @return boolean|\WP_Error
+ */
+ public function load() {
+ if ( $this->image )
+ return true;
+
+ if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) )
+ return new WP_Error( 'error_loading_image', __('File doesn&#8217;t exist?'), $this->file );
+
+ // Set artificially high because GD uses uncompressed images in memory
+ @ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+ $this->image = @imagecreatefromstring( file_get_contents( $this->file ) );
+
+ if ( ! is_resource( $this->image ) )
+ return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file );
+
+ $size = @getimagesize( $this->file );
+ if ( ! $size )
+ return new WP_Error( 'invalid_image', __('Could not read image size.'), $this->file );
+
+ if ( function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) {
+ imagealphablending( $this->image, false );
+ imagesavealpha( $this->image, true );
+ }
+
+ $this->update_size( $size[0], $size[1] );
+ $this->mime_type = $size['mime'];
+
+ return true;
+ }
+
+ /**
+ * Sets or updates current image size.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param int $width
+ * @param int $height
+ */
+ protected function update_size( $width = false, $height = false ) {
+ if ( ! $width )
+ $width = imagesx( $this->image );
+
+ if ( ! $height )
+ $height = imagesy( $this->image );
+
+ return parent::update_size( $width, $height );
+ }
+
+ /**
+ * Resizes current image.
+ * Wraps _resize, since _resize returns a GD Resource.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param int $max_w
+ * @param int $max_h
+ * @param boolean $crop
+ * @return boolean|WP_Error
+ */
+ public function resize( $max_w, $max_h, $crop = false ) {
+ if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) )
+ return true;
+
+ $resized = $this->_resize( $max_w, $max_h, $crop );
+
+ if ( is_resource( $resized ) ) {
+ imagedestroy( $this->image );
+ $this->image = $resized;
+ return true;
+
+ } elseif ( is_wp_error( $resized ) )
+ return $resized;
+
+ return new WP_Error( 'image_resize_error', __('Image resize failed.'), $this->file );
+ }
+
+ protected function _resize( $max_w, $max_h, $crop = false ) {
+ $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
+ if ( ! $dims ) {
+ return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions'), $this->file );
+ }
+ list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
+
+ $resized = wp_imagecreatetruecolor( $dst_w, $dst_h );
+ imagecopyresampled( $resized, $this->image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
+
+ if ( is_resource( $resized ) ) {
+ $this->update_size( $dst_w, $dst_h );
+ return $resized;
+ }
+
+ return new WP_Error( 'image_resize_error', __('Image resize failed.'), $this->file );
+ }
+
+ /**
+ * Processes current image and saves to disk
+ * multiple sizes from single source.
+ *
+ * 'width' and 'height' are required.
+ * 'crop' defaults to false when not provided.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param array $sizes { {'width'=>int, 'height'=>int, ['crop'=>bool]}, ... }
+ * @return array
+ */
+ public function multi_resize( $sizes ) {
+ $metadata = array();
+ $orig_size = $this->size;
+
+ foreach ( $sizes as $size => $size_data ) {
+ if ( ! ( isset( $size_data['width'] ) && isset( $size_data['height'] ) ) )
+ continue;
+
+ if ( ! isset( $size_data['crop'] ) )
+ $size_data['crop'] = false;
+
+ $image = $this->_resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
+
+ if( ! is_wp_error( $image ) ) {
+ $resized = $this->_save( $image );
+
+ imagedestroy( $image );
+
+ if ( ! is_wp_error( $resized ) && $resized ) {
+ unset( $resized['path'] );
+ $metadata[$size] = $resized;
+ }
+ }
+
+ $this->size = $orig_size;
+ }
+
+ return $metadata;
+ }
+
+ /**
+ * Crops Image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string|int $src The source file or Attachment ID.
+ * @param int $src_x The start x position to crop from.
+ * @param int $src_y The start y position to crop from.
+ * @param int $src_w The width to crop.
+ * @param int $src_h The height to crop.
+ * @param int $dst_w Optional. The destination width.
+ * @param int $dst_h Optional. The destination height.
+ * @param boolean $src_abs Optional. If the source crop points are absolute.
+ * @return boolean|WP_Error
+ */
+ public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
+ // If destination width/height isn't specified, use same as
+ // width/height from source.
+ if ( ! $dst_w )
+ $dst_w = $src_w;
+ if ( ! $dst_h )
+ $dst_h = $src_h;
+
+ $dst = wp_imagecreatetruecolor( $dst_w, $dst_h );
+
+ if ( $src_abs ) {
+ $src_w -= $src_x;
+ $src_h -= $src_y;
+ }
+
+ if ( function_exists( 'imageantialias' ) )
+ imageantialias( $dst, true );
+
+ imagecopyresampled( $dst, $this->image, 0, 0, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h );
+
+ if ( is_resource( $dst ) ) {
+ imagedestroy( $this->image );
+ $this->image = $dst;
+ $this->update_size();
+ return true;
+ }
+
+ return new WP_Error( 'image_crop_error', __('Image crop failed.'), $this->file );
+ }
+
+ /**
+ * Rotates current image counter-clockwise by $angle.
+ * Ported from image-edit.php
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param float $angle
+ * @return boolean|WP_Error
+ */
+ public function rotate( $angle ) {
+ if ( function_exists('imagerotate') ) {
+ $rotated = imagerotate( $this->image, $angle, 0 );
+
+ if ( is_resource( $rotated ) ) {
+ imagedestroy( $this->image );
+ $this->image = $rotated;
+ $this->update_size();
+ return true;
+ }
+ }
+ return new WP_Error( 'image_rotate_error', __('Image rotate failed.'), $this->file );
+ }
+
+ /**
+ * Flips current image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param boolean $horz Flip along Horizontal Axis
+ * @param boolean $vert Flip along Vertical Axis
+ * @returns boolean|WP_Error
+ */
+ public function flip( $horz, $vert ) {
+ $w = $this->size['width'];
+ $h = $this->size['height'];
+ $dst = wp_imagecreatetruecolor( $w, $h );
+
+ if ( is_resource( $dst ) ) {
+ $sx = $vert ? ($w - 1) : 0;
+ $sy = $horz ? ($h - 1) : 0;
+ $sw = $vert ? -$w : $w;
+ $sh = $horz ? -$h : $h;
+
+ if ( imagecopyresampled( $dst, $this->image, 0, 0, $sx, $sy, $w, $h, $sw, $sh ) ) {
+ imagedestroy( $this->image );
+ $this->image = $dst;
+ return true;
+ }
+ }
+ return new WP_Error( 'image_flip_error', __('Image flip failed.'), $this->file );
+ }
+
+ /**
+ * Saves current in-memory image to file.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $destfilename
+ * @param string $mime_type
+ * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
+ */
+ public function save( $filename = null, $mime_type = null ) {
+ $saved = $this->_save( $this->image, $filename, $mime_type );
+
+ if ( ! is_wp_error( $saved ) ) {
+ $this->file = $saved['path'];
+ $this->mime_type = $saved['mime-type'];
+ }
+
+ return $saved;
+ }
+
+ protected function _save( $image, $filename = null, $mime_type = null ) {
+ list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
+
+ if ( ! $filename )
+ $filename = $this->generate_filename( null, null, $extension );
+
+ if ( 'image/gif' == $mime_type ) {
+ if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) )
+ return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
+ }
+ elseif ( 'image/png' == $mime_type ) {
+ // convert from full colors to index colors, like original PNG.
+ if ( function_exists('imageistruecolor') && ! imageistruecolor( $image ) )
+ imagetruecolortopalette( $image, false, imagecolorstotal( $image ) );
+
+ if ( ! $this->make_image( $filename, 'imagepng', array( $image, $filename ) ) )
+ return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
+ }
+ elseif ( 'image/jpeg' == $mime_type ) {
+ if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, apply_filters( 'jpeg_quality', $this->quality, 'image_resize' ) ) ) )
+ return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
+ }
+ else {
+ return new WP_Error( 'image_save_error', __('Image Editor Save Failed') );
+ }
+
+ // Set correct file permissions
+ $stat = stat( dirname( $filename ) );
+ $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
+ @ chmod( $filename, $perms );
+
+ return array(
+ 'path' => $filename,
+ 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ),
+ 'width' => $this->size['width'],
+ 'height' => $this->size['height'],
+ 'mime-type'=> $mime_type,
+ );
+ }
+
+ /**
+ * Returns stream of current image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $mime_type
+ */
+ public function stream( $mime_type = null ) {
+ list( $filename, $extension, $mime_type ) = $this->get_output_format( null, $mime_type );
+
+ switch ( $mime_type ) {
+ case 'image/png':
+ header( 'Content-Type: image/png' );
+ return imagepng( $this->image );
+ case 'image/gif':
+ header( 'Content-Type: image/gif' );
+ return imagegif( $this->image );
+ default:
+ header( 'Content-Type: image/jpeg' );
+ return imagejpeg( $this->image, null, $this->quality );
+ }
+ }
+
+ /**
+ * Either calls editor's save function or handles file as a stream.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param string|stream $filename
+ * @param callable $function
+ * @param array $arguments
+ * @return boolean
+ */
+ protected function make_image( $filename, $function, $arguments ) {
+ if ( wp_is_stream( $filename ) )
+ $arguments[1] = null;
+
+ return parent::make_image( $filename, $function, $arguments );
+ }
+}
diff --git a/src/wp-includes/class-wp-image-editor-imagick.php b/src/wp-includes/class-wp-image-editor-imagick.php
new file mode 100644
index 0000000000..f803943a4b
--- /dev/null
+++ b/src/wp-includes/class-wp-image-editor-imagick.php
@@ -0,0 +1,477 @@
+<?php
+/**
+ * WordPress Imagick Image Editor
+ *
+ * @package WordPress
+ * @subpackage Image_Editor
+ */
+
+/**
+ * WordPress Image Editor Class for Image Manipulation through Imagick PHP Module
+ *
+ * @since 3.5.0
+ * @package WordPress
+ * @subpackage Image_Editor
+ * @uses WP_Image_Editor Extends class
+ */
+class WP_Image_Editor_Imagick extends WP_Image_Editor {
+
+ protected $image = null; // Imagick Object
+
+ function __destruct() {
+ if ( $this->image instanceof Imagick ) {
+ // we don't need the original in memory anymore
+ $this->image->clear();
+ $this->image->destroy();
+ }
+ }
+
+ /**
+ * Checks to see if current environment supports Imagick.
+ *
+ * We require Imagick 2.2.0 or greater, based on whether the queryFormats()
+ * method can be called statically.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @return boolean
+ */
+ public static function test( $args = array() ) {
+
+ // First, test Imagick's extension and classes.
+ if ( ! extension_loaded( 'imagick' ) || ! class_exists( 'Imagick' ) || ! class_exists( 'ImagickPixel' ) )
+ return false;
+
+ if ( version_compare( phpversion( 'imagick' ), '2.2.0', '<' ) )
+ return false;
+
+ $required_methods = array(
+ 'clear',
+ 'destroy',
+ 'valid',
+ 'getimage',
+ 'writeimage',
+ 'getimageblob',
+ 'getimagegeometry',
+ 'getimageformat',
+ 'setimageformat',
+ 'setimagecompression',
+ 'setimagecompressionquality',
+ 'setimagepage',
+ 'scaleimage',
+ 'cropimage',
+ 'rotateimage',
+ 'flipimage',
+ 'flopimage',
+ );
+
+ // Now, test for deep requirements within Imagick.
+ if ( ! defined( 'imagick::COMPRESSION_JPEG' ) )
+ return false;
+
+ if ( array_diff( $required_methods, get_class_methods( 'Imagick' ) ) )
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Checks to see if editor supports the mime-type specified.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $mime_type
+ * @return boolean
+ */
+ public static function supports_mime_type( $mime_type ) {
+ $imagick_extension = strtoupper( self::get_extension( $mime_type ) );
+
+ if ( ! $imagick_extension )
+ return false;
+
+ // setIteratorIndex is optional unless mime is an animated format.
+ // Here, we just say no if you are missing it and aren't loading a jpeg.
+ if ( ! method_exists( 'Imagick', 'setIteratorIndex' ) && $mime_type != 'image/jpeg' )
+ return false;
+
+ try {
+ return ( (bool) @Imagick::queryFormats( $imagick_extension ) );
+ }
+ catch ( Exception $e ) {
+ return false;
+ }
+ }
+
+ /**
+ * Loads image from $this->file into new Imagick Object.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @return boolean|WP_Error True if loaded; WP_Error on failure.
+ */
+ public function load() {
+ if ( $this->image instanceof Imagick )
+ return true;
+
+ if ( ! is_file( $this->file ) && ! preg_match( '|^https?://|', $this->file ) )
+ return new WP_Error( 'error_loading_image', __('File doesn&#8217;t exist?'), $this->file );
+
+ // Even though Imagick uses less PHP memory than GD, set higher limit for users that have low PHP.ini limits
+ @ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+
+ try {
+ $this->image = new Imagick( $this->file );
+
+ if( ! $this->image->valid() )
+ return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file);
+
+ // Select the first frame to handle animated images properly
+ if ( is_callable( array( $this->image, 'setIteratorIndex' ) ) )
+ $this->image->setIteratorIndex(0);
+
+ $this->mime_type = $this->get_mime_type( $this->image->getImageFormat() );
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'invalid_image', $e->getMessage(), $this->file );
+ }
+
+ $updated_size = $this->update_size();
+ if ( is_wp_error( $updated_size ) )
+ return $updated_size;
+
+ return $this->set_quality();
+ }
+
+ /**
+ * Sets Image Compression quality on a 1-100% scale.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param int $quality Compression Quality. Range: [1,100]
+ * @return boolean|WP_Error
+ */
+ public function set_quality( $quality = null ) {
+ if ( !$quality )
+ $quality = $this->quality;
+
+ try {
+ if( 'image/jpeg' == $this->mime_type ) {
+ $this->image->setImageCompressionQuality( apply_filters( 'jpeg_quality', $quality, 'image_resize' ) );
+ $this->image->setImageCompression( imagick::COMPRESSION_JPEG );
+ }
+ else {
+ $this->image->setImageCompressionQuality( $quality );
+ }
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_quality_error', $e->getMessage() );
+ }
+
+ return parent::set_quality( $quality );
+ }
+
+ /**
+ * Sets or updates current image size.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param int $width
+ * @param int $height
+ */
+ protected function update_size( $width = null, $height = null ) {
+ $size = null;
+ if ( !$width || !$height ) {
+ try {
+ $size = $this->image->getImageGeometry();
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'invalid_image', __('Could not read image size'), $this->file );
+ }
+ }
+
+ if ( ! $width )
+ $width = $size['width'];
+
+ if ( ! $height )
+ $height = $size['height'];
+
+ return parent::update_size( $width, $height );
+ }
+
+ /**
+ * Resizes current image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param int $max_w
+ * @param int $max_h
+ * @param boolean $crop
+ * @return boolean|WP_Error
+ */
+ public function resize( $max_w, $max_h, $crop = false ) {
+ if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) )
+ return true;
+
+ $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop );
+ if ( ! $dims )
+ return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') );
+ list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
+
+ if ( $crop ) {
+ return $this->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h );
+ }
+
+ try {
+ /**
+ * @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
+ * $this->image->thumbnailImage( $dst_w, $dst_h );
+ */
+ $this->image->scaleImage( $dst_w, $dst_h );
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_resize_error', $e->getMessage() );
+ }
+
+ return $this->update_size( $dst_w, $dst_h );
+ }
+
+ /**
+ * Processes current image and saves to disk
+ * multiple sizes from single source.
+ *
+ * 'width' and 'height' are required.
+ * 'crop' defaults to false when not provided.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param array $sizes { {'width'=>int, 'height'=>int, ['crop'=>bool]}, ... }
+ * @return array
+ */
+ public function multi_resize( $sizes ) {
+ $metadata = array();
+ $orig_size = $this->size;
+ $orig_image = $this->image->getImage();
+
+ foreach ( $sizes as $size => $size_data ) {
+ if ( ! $this->image )
+ $this->image = $orig_image->getImage();
+
+ if ( ! ( isset( $size_data['width'] ) && isset( $size_data['height'] ) ) )
+ continue;
+
+ if ( ! isset( $size_data['crop'] ) )
+ $size_data['crop'] = false;
+
+ $resize_result = $this->resize( $size_data['width'], $size_data['height'], $size_data['crop'] );
+
+ if( ! is_wp_error( $resize_result ) ) {
+ $resized = $this->_save( $this->image );
+
+ $this->image->clear();
+ $this->image->destroy();
+ $this->image = null;
+
+ if ( ! is_wp_error( $resized ) && $resized ) {
+ unset( $resized['path'] );
+ $metadata[$size] = $resized;
+ }
+ }
+
+ $this->size = $orig_size;
+ }
+
+ $this->image = $orig_image;
+
+ return $metadata;
+ }
+
+ /**
+ * Crops Image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string|int $src The source file or Attachment ID.
+ * @param int $src_x The start x position to crop from.
+ * @param int $src_y The start y position to crop from.
+ * @param int $src_w The width to crop.
+ * @param int $src_h The height to crop.
+ * @param int $dst_w Optional. The destination width.
+ * @param int $dst_h Optional. The destination height.
+ * @param boolean $src_abs Optional. If the source crop points are absolute.
+ * @return boolean|WP_Error
+ */
+ public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) {
+ if ( $src_abs ) {
+ $src_w -= $src_x;
+ $src_h -= $src_y;
+ }
+
+ try {
+ $this->image->cropImage( $src_w, $src_h, $src_x, $src_y );
+ $this->image->setImagePage( $src_w, $src_h, 0, 0);
+
+ if ( $dst_w || $dst_h ) {
+ // If destination width/height isn't specified, use same as
+ // width/height from source.
+ if ( ! $dst_w )
+ $dst_w = $src_w;
+ if ( ! $dst_h )
+ $dst_h = $src_h;
+
+ $this->image->scaleImage( $dst_w, $dst_h );
+ return $this->update_size();
+ }
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_crop_error', $e->getMessage() );
+ }
+ return $this->update_size();
+ }
+
+ /**
+ * Rotates current image counter-clockwise by $angle.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param float $angle
+ * @return boolean|WP_Error
+ */
+ public function rotate( $angle ) {
+ /**
+ * $angle is 360-$angle because Imagick rotates clockwise
+ * (GD rotates counter-clockwise)
+ */
+ try {
+ $this->image->rotateImage( new ImagickPixel('none'), 360-$angle );
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_rotate_error', $e->getMessage() );
+ }
+ return $this->update_size();
+ }
+
+ /**
+ * Flips current image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param boolean $horz Flip along Horizontal Axis
+ * @param boolean $vert Flip along Vertical Axis
+ * @returns boolean|WP_Error
+ */
+ public function flip( $horz, $vert ) {
+ try {
+ if ( $horz )
+ $this->image->flipImage();
+
+ if ( $vert )
+ $this->image->flopImage();
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_flip_error', $e->getMessage() );
+ }
+ return true;
+ }
+
+ /**
+ * Saves current image to file.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $destfilename
+ * @param string $mime_type
+ * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
+ */
+ public function save( $destfilename = null, $mime_type = null ) {
+ $saved = $this->_save( $this->image, $destfilename, $mime_type );
+
+ if ( ! is_wp_error( $saved ) ) {
+ $this->file = $saved['path'];
+ $this->mime_type = $saved['mime-type'];
+
+ try {
+ $this->image->setImageFormat( strtoupper( $this->get_extension( $this->mime_type ) ) );
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_save_error', $e->getMessage(), $this->file );
+ }
+ }
+
+ return $saved;
+ }
+
+ protected function _save( $image, $filename = null, $mime_type = null ) {
+ list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type );
+
+ if ( ! $filename )
+ $filename = $this->generate_filename( null, null, $extension );
+
+ try {
+ // Store initial Format
+ $orig_format = $this->image->getImageFormat();
+
+ $this->image->setImageFormat( strtoupper( $this->get_extension( $mime_type ) ) );
+ $this->make_image( $filename, array( $image, 'writeImage' ), array( $filename ) );
+
+ // Reset original Format
+ $this->image->setImageFormat( $orig_format );
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_save_error', $e->getMessage(), $filename );
+ }
+
+ // Set correct file permissions
+ $stat = stat( dirname( $filename ) );
+ $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
+ @ chmod( $filename, $perms );
+
+ return array(
+ 'path' => $filename,
+ 'file' => wp_basename( apply_filters( 'image_make_intermediate_size', $filename ) ),
+ 'width' => $this->size['width'],
+ 'height' => $this->size['height'],
+ 'mime-type' => $mime_type,
+ );
+ }
+
+ /**
+ * Streams current image to browser.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $mime_type
+ * @return boolean|WP_Error
+ */
+ public function stream( $mime_type = null ) {
+ list( $filename, $extension, $mime_type ) = $this->get_output_format( null, $mime_type );
+
+ try {
+ // Temporarily change format for stream
+ $this->image->setImageFormat( strtoupper( $extension ) );
+
+ // Output stream of image content
+ header( "Content-Type: $mime_type" );
+ print $this->image->getImageBlob();
+
+ // Reset Image to original Format
+ $this->image->setImageFormat( $this->get_extension( $this->mime_type ) );
+ }
+ catch ( Exception $e ) {
+ return new WP_Error( 'image_stream_error', $e->getMessage() );
+ }
+
+ return true;
+ }
+}
diff --git a/src/wp-includes/class-wp-image-editor.php b/src/wp-includes/class-wp-image-editor.php
new file mode 100644
index 0000000000..3c2e1b3d43
--- /dev/null
+++ b/src/wp-includes/class-wp-image-editor.php
@@ -0,0 +1,403 @@
+<?php
+/**
+ * Base WordPress Image Editor
+ *
+ * @package WordPress
+ * @subpackage Image_Editor
+ */
+
+/**
+ * Base image editor class from which implementations extend
+ *
+ * @since 3.5.0
+ */
+abstract class WP_Image_Editor {
+ protected $file = null;
+ protected $size = null;
+ protected $mime_type = null;
+ protected $default_mime_type = 'image/jpeg';
+ protected $quality = 90;
+
+ /**
+ * Each instance handles a single file.
+ */
+ public function __construct( $file ) {
+ $this->file = $file;
+ }
+
+ /**
+ * Checks to see if current environment supports the editor chosen.
+ * Must be overridden in a sub-class.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param array $args
+ * @return boolean
+ */
+ public static function test( $args = array() ) {
+ return false;
+ }
+
+ /**
+ * Checks to see if editor supports the mime-type specified.
+ * Must be overridden in a sub-class.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param string $mime_type
+ * @return boolean
+ */
+ public static function supports_mime_type( $mime_type ) {
+ return false;
+ }
+
+ /**
+ * Loads image from $this->file into editor.
+ *
+ * @since 3.5.0
+ * @access protected
+ * @abstract
+ *
+ * @return boolean|WP_Error True if loaded; WP_Error on failure.
+ */
+ abstract public function load();
+
+ /**
+ * Saves current image to file.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param string $destfilename
+ * @param string $mime_type
+ * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string}
+ */
+ abstract public function save( $destfilename = null, $mime_type = null );
+
+ /**
+ * Resizes current image.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param int $max_w
+ * @param int $max_h
+ * @param boolean $crop
+ * @return boolean|WP_Error
+ */
+ abstract public function resize( $max_w, $max_h, $crop = false );
+
+ /**
+ * Processes current image and saves to disk
+ * multiple sizes from single source.
+ *
+ * 'width' and 'height' are required.
+ * 'crop' defaults to false when not provided.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param array $sizes { {'width'=>int, 'height'=>int, ['crop'=>bool]}, ... }
+ * @return array
+ */
+ abstract public function multi_resize( $sizes );
+
+ /**
+ * Crops Image.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param string|int $src The source file or Attachment ID.
+ * @param int $src_x The start x position to crop from.
+ * @param int $src_y The start y position to crop from.
+ * @param int $src_w The width to crop.
+ * @param int $src_h The height to crop.
+ * @param int $dst_w Optional. The destination width.
+ * @param int $dst_h Optional. The destination height.
+ * @param boolean $src_abs Optional. If the source crop points are absolute.
+ * @return boolean|WP_Error
+ */
+ abstract public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false );
+
+ /**
+ * Rotates current image counter-clockwise by $angle.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param float $angle
+ * @return boolean|WP_Error
+ */
+ abstract public function rotate( $angle );
+
+ /**
+ * Flips current image.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param boolean $horz Flip along Horizontal Axis
+ * @param boolean $vert Flip along Vertical Axis
+ * @return boolean|WP_Error
+ */
+ abstract public function flip( $horz, $vert );
+
+ /**
+ * Streams current image to browser.
+ *
+ * @since 3.5.0
+ * @access public
+ * @abstract
+ *
+ * @param string $mime_type
+ * @return boolean|WP_Error
+ */
+ abstract public function stream( $mime_type = null );
+
+ /**
+ * Gets dimensions of image.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @return array {'width'=>int, 'height'=>int}
+ */
+ public function get_size() {
+ return $this->size;
+ }
+
+ /**
+ * Sets current image size.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param int $width
+ * @param int $height
+ */
+ protected function update_size( $width = null, $height = null ) {
+ $this->size = array(
+ 'width' => (int) $width,
+ 'height' => (int) $height
+ );
+ return true;
+ }
+
+ /**
+ * Sets Image Compression quality on a 1-100% scale.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param int $quality Compression Quality. Range: [1,100]
+ * @return boolean
+ */
+ public function set_quality( $quality ) {
+ $this->quality = apply_filters( 'wp_editor_set_quality', $quality );
+
+ return ( (bool) $this->quality );
+ }
+
+ /**
+ * Returns preferred mime-type and extension based on provided
+ * file's extension and mime, or current file's extension and mime.
+ *
+ * Will default to $this->default_mime_type if requested is not supported.
+ *
+ * Provides corrected filename only if filename is provided.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param string $filename
+ * @param string $mime_type
+ * @return array { filename|null, extension, mime-type }
+ */
+ protected function get_output_format( $filename = null, $mime_type = null ) {
+ $new_ext = $file_ext = null;
+ $file_mime = null;
+
+ // By default, assume specified type takes priority
+ if ( $mime_type ) {
+ $new_ext = $this->get_extension( $mime_type );
+ }
+
+ if ( $filename ) {
+ $file_ext = strtolower( pathinfo( $filename, PATHINFO_EXTENSION ) );
+ $file_mime = $this->get_mime_type( $file_ext );
+ }
+ else {
+ // If no file specified, grab editor's current extension and mime-type.
+ $file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) );
+ $file_mime = $this->mime_type;
+ }
+
+ // Check to see if specified mime-type is the same as type implied by
+ // file extension. If so, prefer extension from file.
+ if ( ! $mime_type || ( $file_mime == $mime_type ) ) {
+ $mime_type = $file_mime;
+ $new_ext = $file_ext;
+ }
+
+ // Double-check that the mime-type selected is supported by the editor.
+ // If not, choose a default instead.
+ if ( ! $this->supports_mime_type( $mime_type ) ) {
+ $mime_type = apply_filters( 'image_editor_default_mime_type', $this->default_mime_type );
+ $new_ext = $this->get_extension( $mime_type );
+ }
+
+ if ( $filename ) {
+ $ext = '';
+ $info = pathinfo( $filename );
+ $dir = $info['dirname'];
+
+ if( isset( $info['extension'] ) )
+ $ext = $info['extension'];
+
+ $filename = trailingslashit( $dir ) . wp_basename( $filename, ".$ext" ) . ".{$new_ext}";
+ }
+
+ return array( $filename, $new_ext, $mime_type );
+ }
+
+ /**
+ * Builds an output filename based on current file, and adding proper suffix
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $suffix
+ * @param string $dest_path
+ * @param string $extension
+ * @return string filename
+ */
+ public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) {
+ // $suffix will be appended to the destination filename, just before the extension
+ if ( ! $suffix )
+ $suffix = $this->get_suffix();
+
+ $info = pathinfo( $this->file );
+ $dir = $info['dirname'];
+ $ext = $info['extension'];
+
+ $name = wp_basename( $this->file, ".$ext" );
+ $new_ext = strtolower( $extension ? $extension : $ext );
+
+ if ( ! is_null( $dest_path ) && $_dest_path = realpath( $dest_path ) )
+ $dir = $_dest_path;
+
+ return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}";
+ }
+
+ /**
+ * Builds and returns proper suffix for file based on height and width.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @return string suffix
+ */
+ public function get_suffix() {
+ if ( ! $this->get_size() )
+ return false;
+
+ return "{$this->size['width']}x{$this->size['height']}";
+ }
+
+ /**
+ * Either calls editor's save function or handles file as a stream.
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param string|stream $filename
+ * @param callable $function
+ * @param array $arguments
+ * @return boolean
+ */
+ protected function make_image( $filename, $function, $arguments ) {
+ if ( $stream = wp_is_stream( $filename ) ) {
+ ob_start();
+ } else {
+ // The directory containing the original file may no longer exist when using a replication plugin.
+ wp_mkdir_p( dirname( $filename ) );
+ }
+
+ $result = call_user_func_array( $function, $arguments );
+
+ if ( $result && $stream ) {
+ $contents = ob_get_contents();
+
+ $fp = fopen( $filename, 'w' );
+
+ if ( ! $fp )
+ return false;
+
+ fwrite( $fp, $contents );
+ fclose( $fp );
+ }
+
+ if ( $stream ) {
+ ob_end_clean();
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns first matched mime-type from extension,
+ * as mapped from wp_get_mime_types()
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param string $extension
+ * @return string|boolean
+ */
+ protected static function get_mime_type( $extension = null ) {
+ if ( ! $extension )
+ return false;
+
+ $mime_types = wp_get_mime_types();
+ $extensions = array_keys( $mime_types );
+
+ foreach( $extensions as $_extension ) {
+ if ( preg_match( "/{$extension}/i", $_extension ) ) {
+ return $mime_types[$_extension];
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns first matched extension from Mime-type,
+ * as mapped from wp_get_mime_types()
+ *
+ * @since 3.5.0
+ * @access protected
+ *
+ * @param string $mime_type
+ * @return string|boolean
+ */
+ protected static function get_extension( $mime_type = null ) {
+ $extensions = explode( '|', array_search( $mime_type, wp_get_mime_types() ) );
+
+ if ( empty( $extensions[0] ) )
+ return false;
+
+ return $extensions[0];
+ }
+}
+
diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php
new file mode 100644
index 0000000000..0d47f025c1
--- /dev/null
+++ b/src/wp-includes/class-wp-theme.php
@@ -0,0 +1,1200 @@
+<?php
+/**
+ * WP_Theme Class
+ *
+ * @package WordPress
+ * @subpackage Theme
+ */
+
+final class WP_Theme implements ArrayAccess {
+
+ /**
+ * Headers for style.css files.
+ *
+ * @static
+ * @access private
+ * @var array
+ */
+ private static $file_headers = array(
+ 'Name' => 'Theme Name',
+ 'ThemeURI' => 'Theme URI',
+ 'Description' => 'Description',
+ 'Author' => 'Author',
+ 'AuthorURI' => 'Author URI',
+ 'Version' => 'Version',
+ 'Template' => 'Template',
+ 'Status' => 'Status',
+ 'Tags' => 'Tags',
+ 'TextDomain' => 'Text Domain',
+ 'DomainPath' => 'Domain Path',
+ );
+
+ /**
+ * Default themes.
+ *
+ * @static
+ * @access private
+ * @var array
+ */
+ private static $default_themes = array(
+ 'classic' => 'WordPress Classic',
+ 'default' => 'WordPress Default',
+ 'twentyten' => 'Twenty Ten',
+ 'twentyeleven' => 'Twenty Eleven',
+ 'twentytwelve' => 'Twenty Twelve',
+ 'twentythirteen' => 'Twenty Thirteen',
+ );
+
+ /**
+ * Absolute path to the theme root, usually wp-content/themes
+ *
+ * @access private
+ * @var string
+ */
+ private $theme_root;
+
+ /**
+ * Header data from the theme's style.css file.
+ *
+ * @access private
+ * @var array
+ */
+ private $headers = array();
+
+ /**
+ * Header data from the theme's style.css file after being sanitized.
+ *
+ * @access private
+ * @var array
+ */
+ private $headers_sanitized;
+
+ /**
+ * Header name from the theme's style.css after being translated.
+ *
+ * Cached due to sorting functions running over the translated name.
+ */
+ private $name_translated;
+
+ /**
+ * Errors encountered when initializing the theme.
+ *
+ * @access private
+ * @var WP_Error
+ */
+ private $errors;
+
+ /**
+ * The directory name of the theme's files, inside the theme root.
+ *
+ * In the case of a child theme, this is directory name of the child theme.
+ * Otherwise, 'stylesheet' is the same as 'template'.
+ *
+ * @access private
+ * @var string
+ */
+ private $stylesheet;
+
+ /**
+ * The directory name of the theme's files, inside the theme root.
+ *
+ * In the case of a child theme, this is the directory name of the parent theme.
+ * Otherwise, 'template' is the same as 'stylesheet'.
+ *
+ * @access private
+ * @var string
+ */
+ private $template;
+
+ /**
+ * A reference to the parent theme, in the case of a child theme.
+ *
+ * @access private
+ * @var WP_Theme
+ */
+ private $parent;
+
+ /**
+ * URL to the theme root, usually an absolute URL to wp-content/themes
+ *
+ * @access private
+ * var string
+ */
+ private $theme_root_uri;
+
+ /**
+ * Flag for whether the theme's textdomain is loaded.
+ *
+ * @access private
+ * @var bool
+ */
+ private $textdomain_loaded;
+
+ /**
+ * Stores an md5 hash of the theme root, to function as the cache key.
+ *
+ * @access private
+ * @var string
+ */
+ private $cache_hash;
+
+ /**
+ * Flag for whether the themes cache bucket should be persistently cached.
+ *
+ * Default is false. Can be set with the wp_cache_themes_persistently filter.
+ *
+ * @access private
+ * @var bool
+ */
+ private static $persistently_cache;
+
+ /**
+ * Expiration time for the themes cache bucket.
+ *
+ * By default the bucket is not cached, so this value is useless.
+ *
+ * @access private
+ * @var bool
+ */
+ private static $cache_expiration = 1800;
+
+ /**
+ * Constructor for WP_Theme.
+ *
+ * @param string $theme_dir Directory of the theme within the theme_root.
+ * @param string $theme_root Theme root.
+ * @param WP_Error|null $_child If this theme is a parent theme, the child may be passed for validation purposes.
+ */
+ public function __construct( $theme_dir, $theme_root, $_child = null ) {
+ global $wp_theme_directories;
+
+ // Initialize caching on first run.
+ if ( ! isset( self::$persistently_cache ) ) {
+ self::$persistently_cache = apply_filters( 'wp_cache_themes_persistently', false, 'WP_Theme' );
+ if ( self::$persistently_cache ) {
+ wp_cache_add_global_groups( 'themes' );
+ if ( is_int( self::$persistently_cache ) )
+ self::$cache_expiration = self::$persistently_cache;
+ } else {
+ wp_cache_add_non_persistent_groups( 'themes' );
+ }
+ }
+
+ $this->theme_root = $theme_root;
+ $this->stylesheet = $theme_dir;
+
+ // Correct a situation where the theme is 'some-directory/some-theme' but 'some-directory' was passed in as part of the theme root instead.
+ if ( ! in_array( $theme_root, (array) $wp_theme_directories ) && in_array( dirname( $theme_root ), (array) $wp_theme_directories ) ) {
+ $this->stylesheet = basename( $this->theme_root ) . '/' . $this->stylesheet;
+ $this->theme_root = dirname( $theme_root );
+ }
+
+ $this->cache_hash = md5( $this->theme_root . '/' . $this->stylesheet );
+ $theme_file = $this->stylesheet . '/style.css';
+
+ $cache = $this->cache_get( 'theme' );
+
+ if ( is_array( $cache ) ) {
+ foreach ( array( 'errors', 'headers', 'template' ) as $key ) {
+ if ( isset( $cache[ $key ] ) )
+ $this->$key = $cache[ $key ];
+ }
+ if ( $this->errors )
+ return;
+ if ( isset( $cache['theme_root_template'] ) )
+ $theme_root_template = $cache['theme_root_template'];
+ } elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) {
+ $this->headers['Name'] = $this->stylesheet;
+ if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) )
+ $this->errors = new WP_Error( 'theme_not_found', __( 'The theme directory does not exist.' ) );
+ else
+ $this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) );
+ $this->template = $this->stylesheet;
+ $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
+ if ( ! file_exists( $this->theme_root ) ) // Don't cache this one.
+ $this->errors->add( 'theme_root_missing', __( 'ERROR: The themes directory is either empty or doesn&#8217;t exist. Please check your installation.' ) );
+ return;
+ } elseif ( ! is_readable( $this->theme_root . '/' . $theme_file ) ) {
+ $this->headers['Name'] = $this->stylesheet;
+ $this->errors = new WP_Error( 'theme_stylesheet_not_readable', __( 'Stylesheet is not readable.' ) );
+ $this->template = $this->stylesheet;
+ $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
+ return;
+ } else {
+ $this->headers = get_file_data( $this->theme_root . '/' . $theme_file, self::$file_headers, 'theme' );
+ // Default themes always trump their pretenders.
+ // Properly identify default themes that are inside a directory within wp-content/themes.
+ if ( $default_theme_slug = array_search( $this->headers['Name'], self::$default_themes ) ) {
+ if ( basename( $this->stylesheet ) != $default_theme_slug )
+ $this->headers['Name'] .= '/' . $this->stylesheet;
+ }
+ }
+
+ // (If template is set from cache [and there are no errors], we know it's good.)
+ if ( ! $this->template && ! ( $this->template = $this->headers['Template'] ) ) {
+ $this->template = $this->stylesheet;
+ if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet . '/index.php' ) ) {
+ $this->errors = new WP_Error( 'theme_no_index', __( 'Template is missing.' ) );
+ $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
+ return;
+ }
+ }
+
+ // If we got our data from cache, we can assume that 'template' is pointing to the right place.
+ if ( ! is_array( $cache ) && $this->template != $this->stylesheet && ! file_exists( $this->theme_root . '/' . $this->template . '/index.php' ) ) {
+ // If we're in a directory of themes inside /themes, look for the parent nearby.
+ // wp-content/themes/directory-of-themes/*
+ $parent_dir = dirname( $this->stylesheet );
+ if ( '.' != $parent_dir && file_exists( $this->theme_root . '/' . $parent_dir . '/' . $this->template . '/index.php' ) ) {
+ $this->template = $parent_dir . '/' . $this->template;
+ } elseif ( ( $directories = search_theme_directories() ) && isset( $directories[ $this->template ] ) ) {
+ // Look for the template in the search_theme_directories() results, in case it is in another theme root.
+ // We don't look into directories of themes, just the theme root.
+ $theme_root_template = $directories[ $this->template ]['theme_root'];
+ } else {
+ // Parent theme is missing.
+ $this->errors = new WP_Error( 'theme_no_parent', sprintf( __( 'The parent theme is missing. Please install the "%s" parent theme.' ), $this->template ) );
+ $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
+ $this->parent = new WP_Theme( $this->template, $this->theme_root, $this );
+ return;
+ }
+ }
+
+ // Set the parent, if we're a child theme.
+ if ( $this->template != $this->stylesheet ) {
+ // If we are a parent, then there is a problem. Only two generations allowed! Cancel things out.
+ if ( is_a( $_child, 'WP_Theme' ) && $_child->template == $this->stylesheet ) {
+ $_child->parent = null;
+ $_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), $_child->template ) );
+ $_child->cache_add( 'theme', array( 'headers' => $_child->headers, 'errors' => $_child->errors, 'stylesheet' => $_child->stylesheet, 'template' => $_child->template ) );
+ // The two themes actually reference each other with the Template header.
+ if ( $_child->stylesheet == $this->template ) {
+ $this->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), $this->template ) );
+ $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) );
+ }
+ return;
+ }
+ // Set the parent. Pass the current instance so we can do the crazy checks above and assess errors.
+ $this->parent = new WP_Theme( $this->template, isset( $theme_root_template ) ? $theme_root_template : $this->theme_root, $this );
+ }
+
+ // We're good. If we didn't retrieve from cache, set it.
+ if ( ! is_array( $cache ) ) {
+ $cache = array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template );
+ // If the parent theme is in another root, we'll want to cache this. Avoids an entire branch of filesystem calls above.
+ if ( isset( $theme_root_template ) )
+ $cache['theme_root_template'] = $theme_root_template;
+ $this->cache_add( 'theme', $cache );
+ }
+ }
+
+ /**
+ * When converting the object to a string, the theme name is returned.
+ *
+ * @return string Theme name, ready for display (translated)
+ */
+ public function __toString() {
+ return (string) $this->display('Name');
+ }
+
+ /**
+ * __isset() magic method for properties formerly returned by current_theme_info()
+ */
+ public function __isset( $offset ) {
+ static $properties = array(
+ 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet',
+ 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri',
+ );
+
+ return in_array( $offset, $properties );
+ }
+
+ /**
+ * __get() magic method for properties formerly returned by current_theme_info()
+ */
+ public function __get( $offset ) {
+ switch ( $offset ) {
+ case 'name' :
+ case 'title' :
+ return $this->get('Name');
+ case 'version' :
+ return $this->get('Version');
+ case 'parent_theme' :
+ return $this->parent() ? $this->parent()->get('Name') : '';
+ case 'template_dir' :
+ return $this->get_template_directory();
+ case 'stylesheet_dir' :
+ return $this->get_stylesheet_directory();
+ case 'template' :
+ return $this->get_template();
+ case 'stylesheet' :
+ return $this->get_stylesheet();
+ case 'screenshot' :
+ return $this->get_screenshot( 'relative' );
+ // 'author' and 'description' did not previously return translated data.
+ case 'description' :
+ return $this->display('Description');
+ case 'author' :
+ return $this->display('Author');
+ case 'tags' :
+ return $this->get( 'Tags' );
+ case 'theme_root' :
+ return $this->get_theme_root();
+ case 'theme_root_uri' :
+ return $this->get_theme_root_uri();
+ // For cases where the array was converted to an object.
+ default :
+ return $this->offsetGet( $offset );
+ }
+ }
+
+ /**
+ * Method to implement ArrayAccess for keys formerly returned by get_themes()
+ */
+ public function offsetSet( $offset, $value ) {}
+
+ /**
+ * Method to implement ArrayAccess for keys formerly returned by get_themes()
+ */
+ public function offsetUnset( $offset ) {}
+
+ /**
+ * Method to implement ArrayAccess for keys formerly returned by get_themes()
+ */
+ public function offsetExists( $offset ) {
+ static $keys = array(
+ 'Name', 'Version', 'Status', 'Title', 'Author', 'Author Name', 'Author URI', 'Description',
+ 'Template', 'Stylesheet', 'Template Files', 'Stylesheet Files', 'Template Dir', 'Stylesheet Dir',
+ 'Screenshot', 'Tags', 'Theme Root', 'Theme Root URI', 'Parent Theme',
+ );
+
+ return in_array( $offset, $keys );
+ }
+
+ /**
+ * Method to implement ArrayAccess for keys formerly returned by get_themes().
+ *
+ * Author, Author Name, Author URI, and Description did not previously return
+ * translated data. We are doing so now as it is safe to do. However, as
+ * Name and Title could have been used as the key for get_themes(), both remain
+ * untranslated for back compatibility. This means that ['Name'] is not ideal,
+ * and care should be taken to use $theme->display('Name') to get a properly
+ * translated header.
+ */
+ public function offsetGet( $offset ) {
+ switch ( $offset ) {
+ case 'Name' :
+ case 'Title' :
+ // See note above about using translated data. get() is not ideal.
+ // It is only for backwards compatibility. Use display().
+ return $this->get('Name');
+ case 'Author' :
+ return $this->display( 'Author');
+ case 'Author Name' :
+ return $this->display( 'Author', false);
+ case 'Author URI' :
+ return $this->display('AuthorURI');
+ case 'Description' :
+ return $this->display( 'Description');
+ case 'Version' :
+ case 'Status' :
+ return $this->get( $offset );
+ case 'Template' :
+ return $this->get_template();
+ case 'Stylesheet' :
+ return $this->get_stylesheet();
+ case 'Template Files' :
+ return $this->get_files( 'php', 1, true );
+ case 'Stylesheet Files' :
+ return $this->get_files( 'css', 0, false );
+ case 'Template Dir' :
+ return $this->get_template_directory();
+ case 'Stylesheet Dir' :
+ return $this->get_stylesheet_directory();
+ case 'Screenshot' :
+ return $this->get_screenshot( 'relative' );
+ case 'Tags' :
+ return $this->get('Tags');
+ case 'Theme Root' :
+ return $this->get_theme_root();
+ case 'Theme Root URI' :
+ return $this->get_theme_root_uri();
+ case 'Parent Theme' :
+ return $this->parent() ? $this->parent()->get('Name') : '';
+ default :
+ return null;
+ }
+ }
+
+ /**
+ * Returns errors property.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return WP_Error|bool WP_Error if there are errors, or false.
+ */
+ public function errors() {
+ return is_wp_error( $this->errors ) ? $this->errors : false;
+ }
+
+ /**
+ * Whether the theme exists.
+ *
+ * A theme with errors exists. A theme with the error of 'theme_not_found',
+ * meaning that the theme's directory was not found, does not exist.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return bool Whether the theme exists.
+ */
+ public function exists() {
+ return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes() ) );
+ }
+
+ /**
+ * Returns reference to the parent theme.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return WP_Theme|bool Parent theme, or false if the current theme is not a child theme.
+ */
+ public function parent() {
+ return isset( $this->parent ) ? $this->parent : false;
+ }
+
+ /**
+ * Adds theme data to cache.
+ *
+ * Cache entries keyed by the theme and the type of data.
+ *
+ * @access private
+ * @since 3.4.0
+ *
+ * @param string $key Type of data to store (theme, screenshot, headers, page_templates)
+ * @param string $data Data to store
+ * @return bool Return value from wp_cache_add()
+ */
+ private function cache_add( $key, $data ) {
+ return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration );
+ }
+
+ /**
+ * Gets theme data from cache.
+ *
+ * Cache entries are keyed by the theme and the type of data.
+ *
+ * @access private
+ * @since 3.4.0
+ *
+ * @param string $key Type of data to retrieve (theme, screenshot, headers, page_templates)
+ * @return mixed Retrieved data
+ */
+ private function cache_get( $key ) {
+ return wp_cache_get( $key . '-' . $this->cache_hash, 'themes' );
+ }
+
+ /**
+ * Clears the cache for the theme.
+ *
+ * @access public
+ * @since 3.4.0
+ */
+ public function cache_delete() {
+ foreach ( array( 'theme', 'screenshot', 'headers', 'page_templates' ) as $key )
+ wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' );
+ $this->template = $this->textdomain_loaded = $this->theme_root_uri = $this->parent = $this->errors = $this->headers_sanitized = $this->name_translated = null;
+ $this->headers = array();
+ $this->__construct( $this->stylesheet, $this->theme_root );
+ }
+
+ /**
+ * Get a raw, unformatted theme header.
+ *
+ * The header is sanitized, but is not translated, and is not marked up for display.
+ * To get a theme header for display, use the display() method.
+ *
+ * Use the get_template() method, not the 'Template' header, for finding the template.
+ * The 'Template' header is only good for what was written in the style.css, while
+ * get_template() takes into account where WordPress actually located the theme and
+ * whether it is actually valid.
+ *
+ * @access public
+ * @since 3.4.0
+ *
+ * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
+ * @return string String on success, false on failure.
+ */
+ public function get( $header ) {
+ if ( ! isset( $this->headers[ $header ] ) )
+ return false;
+
+ if ( ! isset( $this->headers_sanitized ) ) {
+ $this->headers_sanitized = $this->cache_get( 'headers' );
+ if ( ! is_array( $this->headers_sanitized ) )
+ $this->headers_sanitized = array();
+ }
+
+ if ( isset( $this->headers_sanitized[ $header ] ) )
+ return $this->headers_sanitized[ $header ];
+
+ // If themes are a persistent group, sanitize everything and cache it. One cache add is better than many cache sets.
+ if ( self::$persistently_cache ) {
+ foreach ( array_keys( $this->headers ) as $_header )
+ $this->headers_sanitized[ $_header ] = $this->sanitize_header( $_header, $this->headers[ $_header ] );
+ $this->cache_add( 'headers', $this->headers_sanitized );
+ } else {
+ $this->headers_sanitized[ $header ] = $this->sanitize_header( $header, $this->headers[ $header ] );
+ }
+
+ return $this->headers_sanitized[ $header ];
+ }
+
+ /**
+ * Gets a theme header, formatted and translated for display.
+ *
+ * @access public
+ * @since 3.4.0
+ *
+ * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
+ * @param bool $markup Optional. Whether to mark up the header. Defaults to true.
+ * @param bool $translate Optional. Whether to translate the header. Defaults to true.
+ * @return string Processed header, false on failure.
+ */
+ public function display( $header, $markup = true, $translate = true ) {
+ $value = $this->get( $header );
+
+ if ( $translate && ( empty( $value ) || ! $this->load_textdomain() ) )
+ $translate = false;
+
+ if ( $translate )
+ $value = $this->translate_header( $header, $value );
+
+ if ( $markup )
+ $value = $this->markup_header( $header, $value, $translate );
+
+ return $value;
+ }
+
+ /**
+ * Sanitize a theme header.
+ *
+ * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
+ * @param string $value Value to sanitize.
+ */
+ private function sanitize_header( $header, $value ) {
+ switch ( $header ) {
+ case 'Status' :
+ if ( ! $value ) {
+ $value = 'publish';
+ break;
+ }
+ // Fall through otherwise.
+ case 'Name' :
+ static $header_tags = array(
+ 'abbr' => array( 'title' => true ),
+ 'acronym' => array( 'title' => true ),
+ 'code' => true,
+ 'em' => true,
+ 'strong' => true,
+ );
+ $value = wp_kses( $value, $header_tags );
+ break;
+ case 'Author' :
+ // There shouldn't be anchor tags in Author, but some themes like to be challenging.
+ case 'Description' :
+ static $header_tags_with_a = array(
+ 'a' => array( 'href' => true, 'title' => true ),
+ 'abbr' => array( 'title' => true ),
+ 'acronym' => array( 'title' => true ),
+ 'code' => true,
+ 'em' => true,
+ 'strong' => true,
+ );
+ $value = wp_kses( $value, $header_tags_with_a );
+ break;
+ case 'ThemeURI' :
+ case 'AuthorURI' :
+ $value = esc_url_raw( $value );
+ break;
+ case 'Tags' :
+ $value = array_filter( array_map( 'trim', explode( ',', strip_tags( $value ) ) ) );
+ break;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Mark up a theme header.
+ *
+ * @access private
+ * @since 3.4.0
+ *
+ * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
+ * @param string $value Value to mark up.
+ * @param string $translate Whether the header has been translated.
+ * @return string Value, marked up.
+ */
+ private function markup_header( $header, $value, $translate ) {
+ switch ( $header ) {
+ case 'Name' :
+ if ( empty( $value ) )
+ $value = $this->get_stylesheet();
+ break;
+ case 'Description' :
+ $value = wptexturize( $value );
+ break;
+ case 'Author' :
+ if ( $this->get('AuthorURI') ) {
+ static $attr = null;
+ if ( ! isset( $attr ) )
+ $attr = esc_attr__( 'Visit author homepage' );
+ $value = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $this->display( 'AuthorURI', true, $translate ), $attr, $value );
+ } elseif ( ! $value ) {
+ $value = __( 'Anonymous' );
+ }
+ break;
+ case 'Tags' :
+ static $comma = null;
+ if ( ! isset( $comma ) ) {
+ /* translators: used between list items, there is a space after the comma */
+ $comma = __( ', ' );
+ }
+ $value = implode( $comma, $value );
+ break;
+ case 'ThemeURI' :
+ case 'AuthorURI' :
+ $value = esc_url( $value );
+ break;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Translate a theme header.
+ *
+ * @access private
+ * @since 3.4.0
+ *
+ * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
+ * @param string $value Value to translate.
+ * @return string Translated value.
+ */
+ private function translate_header( $header, $value ) {
+ switch ( $header ) {
+ case 'Name' :
+ // Cached for sorting reasons.
+ if ( isset( $this->name_translated ) )
+ return $this->name_translated;
+ $this->name_translated = translate( $value, $this->get('TextDomain' ) );
+ return $this->name_translated;
+ case 'Tags' :
+ if ( empty( $value ) || ! function_exists( 'get_theme_feature_list' ) )
+ return $value;
+
+ static $tags_list;
+ if ( ! isset( $tags_list ) ) {
+ $tags_list = array();
+ $feature_list = get_theme_feature_list( false ); // No API
+ foreach ( $feature_list as $tags )
+ $tags_list += $tags;
+ }
+
+ foreach ( $value as &$tag ) {
+ if ( isset( $tags_list[ $tag ] ) )
+ $tag = $tags_list[ $tag ];
+ }
+
+ return $value;
+ break;
+ default :
+ $value = translate( $value, $this->get('TextDomain') );
+ }
+ return $value;
+ }
+
+ /**
+ * The directory name of the theme's "stylesheet" files, inside the theme root.
+ *
+ * In the case of a child theme, this is directory name of the child theme.
+ * Otherwise, get_stylesheet() is the same as get_template().
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string Stylesheet
+ */
+ public function get_stylesheet() {
+ return $this->stylesheet;
+ }
+
+ /**
+ * The directory name of the theme's "template" files, inside the theme root.
+ *
+ * In the case of a child theme, this is the directory name of the parent theme.
+ * Otherwise, the get_template() is the same as get_stylesheet().
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string Template
+ */
+ public function get_template() {
+ return $this->template;
+ }
+
+ /**
+ * Returns the absolute path to the directory of a theme's "stylesheet" files.
+ *
+ * In the case of a child theme, this is the absolute path to the directory
+ * of the child theme's files.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string Absolute path of the stylesheet directory.
+ */
+ public function get_stylesheet_directory() {
+ if ( $this->errors() && in_array( 'theme_root_missing', $this->errors()->get_error_codes() ) )
+ return '';
+
+ return $this->theme_root . '/' . $this->stylesheet;
+ }
+
+ /**
+ * Returns the absolute path to the directory of a theme's "template" files.
+ *
+ * In the case of a child theme, this is the absolute path to the directory
+ * of the parent theme's files.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string Absolute path of the template directory.
+ */
+ public function get_template_directory() {
+ if ( $this->parent() )
+ $theme_root = $this->parent()->theme_root;
+ else
+ $theme_root = $this->theme_root;
+
+ return $theme_root . '/' . $this->template;
+ }
+
+ /**
+ * Returns the URL to the directory of a theme's "stylesheet" files.
+ *
+ * In the case of a child theme, this is the URL to the directory of the
+ * child theme's files.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string URL to the stylesheet directory.
+ */
+ public function get_stylesheet_directory_uri() {
+ return $this->get_theme_root_uri() . '/' . str_replace( '%2F', '/', rawurlencode( $this->stylesheet ) );
+ }
+
+ /**
+ * Returns the URL to the directory of a theme's "template" files.
+ *
+ * In the case of a child theme, this is the URL to the directory of the
+ * parent theme's files.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string URL to the template directory.
+ */
+ public function get_template_directory_uri() {
+ if ( $this->parent() )
+ $theme_root_uri = $this->parent()->get_theme_root_uri();
+ else
+ $theme_root_uri = $this->get_theme_root_uri();
+
+ return $theme_root_uri . '/' . str_replace( '%2F', '/', rawurlencode( $this->template ) );
+ }
+
+ /**
+ * The absolute path to the directory of the theme root.
+ *
+ * This is typically the absolute path to wp-content/themes.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string Theme root.
+ */
+ public function get_theme_root() {
+ return $this->theme_root;
+ }
+
+ /**
+ * Returns the URL to the directory of the theme root.
+ *
+ * This is typically the absolute URL to wp-content/themes. This forms the basis
+ * for all other URLs returned by WP_Theme, so we pass it to the public function
+ * get_theme_root_uri() and allow it to run the theme_root_uri filter.
+ *
+ * @uses get_theme_root_uri()
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return string Theme root URI.
+ */
+ public function get_theme_root_uri() {
+ if ( ! isset( $this->theme_root_uri ) )
+ $this->theme_root_uri = get_theme_root_uri( $this->stylesheet, $this->theme_root );
+ return $this->theme_root_uri;
+ }
+
+ /**
+ * Returns the main screenshot file for the theme.
+ *
+ * The main screenshot is called screenshot.png. gif and jpg extensions are also allowed.
+ *
+ * Screenshots for a theme must be in the stylesheet directory. (In the case of child
+ * themes, parent theme screenshots are not inherited.)
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @param string $uri Type of URL to return, either 'relative' or an absolute URI. Defaults to absolute URI.
+ * @return mixed Screenshot file. False if the theme does not have a screenshot.
+ */
+ public function get_screenshot( $uri = 'uri' ) {
+ $screenshot = $this->cache_get( 'screenshot' );
+ if ( $screenshot ) {
+ if ( 'relative' == $uri )
+ return $screenshot;
+ return $this->get_stylesheet_directory_uri() . '/' . $screenshot;
+ } elseif ( 0 === $screenshot ) {
+ return false;
+ }
+
+ foreach ( array( 'png', 'gif', 'jpg', 'jpeg' ) as $ext ) {
+ if ( file_exists( $this->get_stylesheet_directory() . "/screenshot.$ext" ) ) {
+ $this->cache_add( 'screenshot', 'screenshot.' . $ext );
+ if ( 'relative' == $uri )
+ return 'screenshot.' . $ext;
+ return $this->get_stylesheet_directory_uri() . '/' . 'screenshot.' . $ext;
+ }
+ }
+
+ $this->cache_add( 'screenshot', 0 );
+ return false;
+ }
+
+ /**
+ * Return files in the theme's directory.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @param mixed $type Optional. Array of extensions to return. Defaults to all files (null).
+ * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). -1 depth is infinite.
+ * @param bool $search_parent Optional. Whether to return parent files. Defaults to false.
+ * @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values
+ * being absolute paths.
+ */
+ public function get_files( $type = null, $depth = 0, $search_parent = false ) {
+ $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth );
+
+ if ( $search_parent && $this->parent() )
+ $files += (array) self::scandir( $this->get_template_directory(), $type, $depth );
+
+ return $files;
+ }
+
+ /**
+ * Returns the theme's page templates.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return array Array of page templates, keyed by filename, with the value of the translated header name.
+ */
+ public function get_page_templates() {
+ // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide.
+ if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) )
+ return array();
+
+ $page_templates = $this->cache_get( 'page_templates' );
+
+ if ( ! is_array( $page_templates ) ) {
+ $page_templates = array();
+
+ $files = (array) $this->get_files( 'php', 1 );
+
+ foreach ( $files as $file => $full_path ) {
+ if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) )
+ continue;
+ $page_templates[ $file ] = _cleanup_header_comment( $header[1] );
+ }
+
+ $this->cache_add( 'page_templates', $page_templates );
+ }
+
+ if ( $this->load_textdomain() ) {
+ foreach ( $page_templates as &$page_template ) {
+ $page_template = $this->translate_header( 'Template Name', $page_template );
+ }
+ }
+
+ if ( $this->parent() )
+ $page_templates += $this->parent()->get_page_templates();
+
+ return $page_templates;
+ }
+
+ /**
+ * Scans a directory for files of a certain extension.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string $path Absolute path to search.
+ * @param mixed Array of extensions to find, string of a single extension, or null for all extensions.
+ * @param int $depth How deep to search for files. Optional, defaults to a flat scan (0 depth). -1 depth is infinite.
+ * @param string $relative_path The basename of the absolute path. Used to control the returned path
+ * for the found files, particularly when this function recurses to lower depths.
+ */
+ private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) {
+ if ( ! is_dir( $path ) )
+ return false;
+
+ if ( $extensions ) {
+ $extensions = (array) $extensions;
+ $_extensions = implode( '|', $extensions );
+ }
+
+ $relative_path = trailingslashit( $relative_path );
+ if ( '/' == $relative_path )
+ $relative_path = '';
+
+ $results = scandir( $path );
+ $files = array();
+
+ foreach ( $results as $result ) {
+ if ( '.' == $result[0] )
+ continue;
+ if ( is_dir( $path . '/' . $result ) ) {
+ if ( ! $depth || 'CVS' == $result )
+ continue;
+ $found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result );
+ $files = array_merge_recursive( $files, $found );
+ } elseif ( ! $extensions || preg_match( '~\.(' . $_extensions . ')$~', $result ) ) {
+ $files[ $relative_path . $result ] = $path . '/' . $result;
+ }
+ }
+
+ return $files;
+ }
+
+ /**
+ * Loads the theme's textdomain.
+ *
+ * Translation files are not inherited from the parent theme. Todo: if this fails for the
+ * child theme, it should probably try to load the parent theme's translations.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return True if the textdomain was successfully loaded or has already been loaded. False if
+ * no textdomain was specified in the file headers, or if the domain could not be loaded.
+ */
+ public function load_textdomain() {
+ if ( isset( $this->textdomain_loaded ) )
+ return $this->textdomain_loaded;
+
+ $textdomain = $this->get('TextDomain');
+ if ( ! $textdomain ) {
+ $this->textdomain_loaded = false;
+ return false;
+ }
+
+ if ( is_textdomain_loaded( $textdomain ) ) {
+ $this->textdomain_loaded = true;
+ return true;
+ }
+
+ $path = $this->get_stylesheet_directory();
+ if ( $domainpath = $this->get('DomainPath') )
+ $path .= $domainpath;
+ else
+ $path .= '/languages';
+
+ $this->textdomain_loaded = load_theme_textdomain( $textdomain, $path );
+ return $this->textdomain_loaded;
+ }
+
+ /**
+ * Whether the theme is allowed (multisite only).
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @param string $check Optional. Whether to check only the 'network'-wide settings, the 'site'
+ * settings, or 'both'. Defaults to 'both'.
+ * @param int $blog_id Optional. Ignored if only network-wide settings are checked. Defaults to current blog.
+ * @return bool Whether the theme is allowed for the network. Returns true in single-site.
+ */
+ public function is_allowed( $check = 'both', $blog_id = null ) {
+ if ( ! is_multisite() )
+ return true;
+
+ if ( 'both' == $check || 'network' == $check ) {
+ $allowed = self::get_allowed_on_network();
+ if ( ! empty( $allowed[ $this->get_stylesheet() ] ) )
+ return true;
+ }
+
+ if ( 'both' == $check || 'site' == $check ) {
+ $allowed = self::get_allowed_on_site( $blog_id );
+ if ( ! empty( $allowed[ $this->get_stylesheet() ] ) )
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns array of stylesheet names of themes allowed on the site or network.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @param int $blog_id Optional. Defaults to current blog.
+ * @return array Array of stylesheet names.
+ */
+ public static function get_allowed( $blog_id = null ) {
+ $network = (array) apply_filters( 'allowed_themes', self::get_allowed_on_network() );
+ return $network + self::get_allowed_on_site( $blog_id );
+ }
+
+ /**
+ * Returns array of stylesheet names of themes allowed on the network.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @return array Array of stylesheet names.
+ */
+ public static function get_allowed_on_network() {
+ static $allowed_themes;
+ if ( ! isset( $allowed_themes ) )
+ $allowed_themes = (array) get_site_option( 'allowedthemes' );
+ return $allowed_themes;
+ }
+
+ /**
+ * Returns array of stylesheet names of themes allowed on the site.
+ *
+ * @since 3.4.0
+ * @access public
+ *
+ * @param int $blog_id Optional. Defaults to current blog.
+ * @return array Array of stylesheet names.
+ */
+ public static function get_allowed_on_site( $blog_id = null ) {
+ static $allowed_themes = array();
+
+ if ( ! $blog_id || ! is_multisite() )
+ $blog_id = get_current_blog_id();
+
+ if ( isset( $allowed_themes[ $blog_id ] ) )
+ return $allowed_themes[ $blog_id ];
+
+ $current = $blog_id == get_current_blog_id();
+
+ if ( $current ) {
+ $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' );
+ } else {
+ switch_to_blog( $blog_id );
+ $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' );
+ restore_current_blog();
+ }
+
+ // This is all super old MU back compat joy.
+ // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name.
+ if ( false === $allowed_themes[ $blog_id ] ) {
+ if ( $current ) {
+ $allowed_themes[ $blog_id ] = get_option( 'allowed_themes' );
+ } else {
+ switch_to_blog( $blog_id );
+ $allowed_themes[ $blog_id ] = get_option( 'allowed_themes' );
+ restore_current_blog();
+ }
+
+ if ( ! is_array( $allowed_themes[ $blog_id ] ) || empty( $allowed_themes[ $blog_id ] ) ) {
+ $allowed_themes[ $blog_id ] = array();
+ } else {
+ $converted = array();
+ $themes = wp_get_themes();
+ foreach ( $themes as $stylesheet => $theme_data ) {
+ if ( isset( $allowed_themes[ $blog_id ][ $theme_data->get('Name') ] ) )
+ $converted[ $stylesheet ] = true;
+ }
+ $allowed_themes[ $blog_id ] = $converted;
+ }
+ // Set the option so we never have to go through this pain again.
+ if ( is_admin() && $allowed_themes[ $blog_id ] ) {
+ if ( $current ) {
+ update_option( 'allowedthemes', $allowed_themes[ $blog_id ] );
+ delete_option( 'allowed_themes' );
+ } else {
+ switch_to_blog( $blog_id );
+ update_option( 'allowedthemes', $allowed_themes[ $blog_id ] );
+ delete_option( 'allowed_themes' );
+ restore_current_blog();
+ }
+ }
+ }
+
+ return (array) $allowed_themes[ $blog_id ];
+ }
+
+ /**
+ * Sort themes by name.
+ *
+ * @since 3.4.0
+ * @access public
+ */
+ public static function sort_by_name( &$themes ) {
+ if ( 0 === strpos( get_locale(), 'en_' ) ) {
+ uasort( $themes, array( 'WP_Theme', '_name_sort' ) );
+ } else {
+ uasort( $themes, array( 'WP_Theme', '_name_sort_i18n' ) );
+ }
+ }
+
+ /**
+ * Callback function for usort() to naturally sort themes by name.
+ *
+ * Accesses the Name header directly from the class for maximum speed.
+ * Would choke on HTML but we don't care enough to slow it down with strip_tags().
+ *
+ * @since 3.4.0
+ * @access private
+ */
+ private static function _name_sort( $a, $b ) {
+ return strnatcasecmp( $a->headers['Name'], $b->headers['Name'] );
+ }
+
+ /**
+ * Name sort (with translation).
+ *
+ * @since 3.4.0
+ * @access private
+ */
+ private static function _name_sort_i18n( $a, $b ) {
+ // Don't mark up; Do translate.
+ return strnatcasecmp( $a->display( 'Name', false, true ), $b->display( 'Name', false, true ) );
+ }
+}
diff --git a/src/wp-includes/class-wp-walker.php b/src/wp-includes/class-wp-walker.php
new file mode 100644
index 0000000000..655e7f4671
--- /dev/null
+++ b/src/wp-includes/class-wp-walker.php
@@ -0,0 +1,397 @@
+<?php
+/**
+ * A class for displaying various tree-like structures.
+ *
+ * Extend the Walker class to use it, see examples at the below. Child classes
+ * do not need to implement all of the abstract methods in the class. The child
+ * only needs to implement the methods that are needed. Also, the methods are
+ * not strictly abstract in that the parameter definition needs to be followed.
+ * The child classes can have additional parameters.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @abstract
+ */
+class Walker {
+ /**
+ * What the class handles.
+ *
+ * @since 2.1.0
+ * @var string
+ * @access public
+ */
+ var $tree_type;
+
+ /**
+ * DB fields to use.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access protected
+ */
+ var $db_fields;
+
+ /**
+ * Max number of pages walked by the paged walker
+ *
+ * @since 2.7.0
+ * @var int
+ * @access protected
+ */
+ var $max_pages = 1;
+
+ /**
+ * Starts the list before the elements are added.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods. This
+ * method is called at the start of the output list.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function start_lvl( &$output, $depth = 0, $args = array() ) {}
+
+ /**
+ * Ends the list of after the elements are added.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods. This
+ * method finishes the list at the end of output of the elements.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function end_lvl( &$output, $depth = 0, $args = array() ) {}
+
+ /**
+ * Start the element output.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods. Includes
+ * the element output also.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {}
+
+ /**
+ * Ends the element output, if needed.
+ *
+ * Additional parameters are used in child classes. The args parameter holds
+ * additional values that may be used with the child class methods.
+ *
+ * @since 2.1.0
+ * @abstract
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ */
+ function end_el( &$output, $object, $depth = 0, $args = array() ) {}
+
+ /**
+ * Traverse elements to create list from elements.
+ *
+ * Display one element if the element doesn't have any children otherwise,
+ * display the element and its children. Will only traverse up to the max
+ * depth and no ignore elements under that depth. It is possible to set the
+ * max depth to include all depths, see walk() method.
+ *
+ * This method shouldn't be called directly, use the walk() method instead.
+ *
+ * @since 2.5.0
+ *
+ * @param object $element Data object
+ * @param array $children_elements List of elements to continue traversing.
+ * @param int $max_depth Max depth to traverse.
+ * @param int $depth Depth of current element.
+ * @param array $args
+ * @param string $output Passed by reference. Used to append additional content.
+ * @return null Null on failure with no changes to parameters.
+ */
+ function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
+
+ if ( !$element )
+ return;
+
+ $id_field = $this->db_fields['id'];
+
+ //display this element
+ if ( isset( $args[0] ) && is_array( $args[0] ) )
+ $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
+ $cb_args = array_merge( array(&$output, $element, $depth), $args);
+ call_user_func_array(array($this, 'start_el'), $cb_args);
+
+ $id = $element->$id_field;
+
+ // descend only when the depth is right and there are childrens for this element
+ if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
+
+ foreach( $children_elements[ $id ] as $child ){
+
+ if ( !isset($newlevel) ) {
+ $newlevel = true;
+ //start the child delimiter
+ $cb_args = array_merge( array(&$output, $depth), $args);
+ call_user_func_array(array($this, 'start_lvl'), $cb_args);
+ }
+ $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
+ }
+ unset( $children_elements[ $id ] );
+ }
+
+ if ( isset($newlevel) && $newlevel ){
+ //end the child delimiter
+ $cb_args = array_merge( array(&$output, $depth), $args);
+ call_user_func_array(array($this, 'end_lvl'), $cb_args);
+ }
+
+ //end this element
+ $cb_args = array_merge( array(&$output, $element, $depth), $args);
+ call_user_func_array(array($this, 'end_el'), $cb_args);
+ }
+
+ /**
+ * Display array of elements hierarchically.
+ *
+ * It is a generic function which does not assume any existing order of
+ * elements. max_depth = -1 means flatly display every element. max_depth =
+ * 0 means display all levels. max_depth > 0 specifies the number of
+ * display levels.
+ *
+ * @since 2.1.0
+ *
+ * @param array $elements
+ * @param int $max_depth
+ * @return string
+ */
+ function walk( $elements, $max_depth) {
+
+ $args = array_slice(func_get_args(), 2);
+ $output = '';
+
+ if ($max_depth < -1) //invalid parameter
+ return $output;
+
+ if (empty($elements)) //nothing to walk
+ return $output;
+
+ $id_field = $this->db_fields['id'];
+ $parent_field = $this->db_fields['parent'];
+
+ // flat display
+ if ( -1 == $max_depth ) {
+ $empty_array = array();
+ foreach ( $elements as $e )
+ $this->display_element( $e, $empty_array, 1, 0, $args, $output );
+ return $output;
+ }
+
+ /*
+ * need to display in hierarchical order
+ * separate elements into two buckets: top level and children elements
+ * children_elements is two dimensional array, eg.
+ * children_elements[10][] contains all sub-elements whose parent is 10.
+ */
+ $top_level_elements = array();
+ $children_elements = array();
+ foreach ( $elements as $e) {
+ if ( 0 == $e->$parent_field )
+ $top_level_elements[] = $e;
+ else
+ $children_elements[ $e->$parent_field ][] = $e;
+ }
+
+ /*
+ * when none of the elements is top level
+ * assume the first one must be root of the sub elements
+ */
+ if ( empty($top_level_elements) ) {
+
+ $first = array_slice( $elements, 0, 1 );
+ $root = $first[0];
+
+ $top_level_elements = array();
+ $children_elements = array();
+ foreach ( $elements as $e) {
+ if ( $root->$parent_field == $e->$parent_field )
+ $top_level_elements[] = $e;
+ else
+ $children_elements[ $e->$parent_field ][] = $e;
+ }
+ }
+
+ foreach ( $top_level_elements as $e )
+ $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
+
+ /*
+ * if we are displaying all levels, and remaining children_elements is not empty,
+ * then we got orphans, which should be displayed regardless
+ */
+ if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
+ $empty_array = array();
+ foreach ( $children_elements as $orphans )
+ foreach( $orphans as $op )
+ $this->display_element( $op, $empty_array, 1, 0, $args, $output );
+ }
+
+ return $output;
+ }
+
+ /**
+ * paged_walk() - produce a page of nested elements
+ *
+ * Given an array of hierarchical elements, the maximum depth, a specific page number,
+ * and number of elements per page, this function first determines all top level root elements
+ * belonging to that page, then lists them and all of their children in hierarchical order.
+ *
+ * @package WordPress
+ * @since 2.7
+ * @param int $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
+ * @param int $page_num the specific page number, beginning with 1.
+ * @return XHTML of the specified page of elements
+ */
+ function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
+
+ /* sanity check */
+ if ( empty($elements) || $max_depth < -1 )
+ return '';
+
+ $args = array_slice( func_get_args(), 4 );
+ $output = '';
+
+ $id_field = $this->db_fields['id'];
+ $parent_field = $this->db_fields['parent'];
+
+ $count = -1;
+ if ( -1 == $max_depth )
+ $total_top = count( $elements );
+ if ( $page_num < 1 || $per_page < 0 ) {
+ // No paging
+ $paging = false;
+ $start = 0;
+ if ( -1 == $max_depth )
+ $end = $total_top;
+ $this->max_pages = 1;
+ } else {
+ $paging = true;
+ $start = ( (int)$page_num - 1 ) * (int)$per_page;
+ $end = $start + $per_page;
+ if ( -1 == $max_depth )
+ $this->max_pages = ceil($total_top / $per_page);
+ }
+
+ // flat display
+ if ( -1 == $max_depth ) {
+ if ( !empty($args[0]['reverse_top_level']) ) {
+ $elements = array_reverse( $elements );
+ $oldstart = $start;
+ $start = $total_top - $end;
+ $end = $total_top - $oldstart;
+ }
+
+ $empty_array = array();
+ foreach ( $elements as $e ) {
+ $count++;
+ if ( $count < $start )
+ continue;
+ if ( $count >= $end )
+ break;
+ $this->display_element( $e, $empty_array, 1, 0, $args, $output );
+ }
+ return $output;
+ }
+
+ /*
+ * separate elements into two buckets: top level and children elements
+ * children_elements is two dimensional array, eg.
+ * children_elements[10][] contains all sub-elements whose parent is 10.
+ */
+ $top_level_elements = array();
+ $children_elements = array();
+ foreach ( $elements as $e) {
+ if ( 0 == $e->$parent_field )
+ $top_level_elements[] = $e;
+ else
+ $children_elements[ $e->$parent_field ][] = $e;
+ }
+
+ $total_top = count( $top_level_elements );
+ if ( $paging )
+ $this->max_pages = ceil($total_top / $per_page);
+ else
+ $end = $total_top;
+
+ if ( !empty($args[0]['reverse_top_level']) ) {
+ $top_level_elements = array_reverse( $top_level_elements );
+ $oldstart = $start;
+ $start = $total_top - $end;
+ $end = $total_top - $oldstart;
+ }
+ if ( !empty($args[0]['reverse_children']) ) {
+ foreach ( $children_elements as $parent => $children )
+ $children_elements[$parent] = array_reverse( $children );
+ }
+
+ foreach ( $top_level_elements as $e ) {
+ $count++;
+
+ //for the last page, need to unset earlier children in order to keep track of orphans
+ if ( $end >= $total_top && $count < $start )
+ $this->unset_children( $e, $children_elements );
+
+ if ( $count < $start )
+ continue;
+
+ if ( $count >= $end )
+ break;
+
+ $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
+ }
+
+ if ( $end >= $total_top && count( $children_elements ) > 0 ) {
+ $empty_array = array();
+ foreach ( $children_elements as $orphans )
+ foreach( $orphans as $op )
+ $this->display_element( $op, $empty_array, 1, 0, $args, $output );
+ }
+
+ return $output;
+ }
+
+ function get_number_of_root_elements( $elements ){
+
+ $num = 0;
+ $parent_field = $this->db_fields['parent'];
+
+ foreach ( $elements as $e) {
+ if ( 0 == $e->$parent_field )
+ $num++;
+ }
+ return $num;
+ }
+
+ // unset all the children for a given top level element
+ function unset_children( $e, &$children_elements ){
+
+ if ( !$e || !$children_elements )
+ return;
+
+ $id_field = $this->db_fields['id'];
+ $id = $e->$id_field;
+
+ if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
+ foreach ( (array) $children_elements[$id] as $child )
+ $this->unset_children( $child, $children_elements );
+
+ if ( isset($children_elements[$id]) )
+ unset( $children_elements[$id] );
+
+ }
+}
diff --git a/src/wp-includes/class-wp-xmlrpc-server.php b/src/wp-includes/class-wp-xmlrpc-server.php
new file mode 100644
index 0000000000..922e0284a4
--- /dev/null
+++ b/src/wp-includes/class-wp-xmlrpc-server.php
@@ -0,0 +1,5522 @@
+<?php
+/**
+ * XML-RPC protocol support for WordPress
+ *
+ * @package WordPress
+ */
+
+/**
+ * WordPress XMLRPC server implementation.
+ *
+ * Implements compatibility for Blogger API, MetaWeblog API, MovableType, and
+ * pingback. Additional WordPress API for managing comments, pages, posts,
+ * options, etc.
+ *
+ * As of WordPress 3.5.0, XML-RPC is enabled by default. It can be disabled
+ * via the xmlrpc_enabled filter found in wp_xmlrpc_server::login().
+ *
+ * @package WordPress
+ * @subpackage Publishing
+ * @since 1.5.0
+ */
+class wp_xmlrpc_server extends IXR_Server {
+
+ /**
+ * Register all of the XMLRPC methods that XMLRPC server understands.
+ *
+ * Sets up server and method property. Passes XMLRPC
+ * methods through the 'xmlrpc_methods' filter to allow plugins to extend
+ * or replace XMLRPC methods.
+ *
+ * @since 1.5.0
+ *
+ * @return wp_xmlrpc_server
+ */
+ function __construct() {
+ $this->methods = array(
+ // WordPress API
+ 'wp.getUsersBlogs' => 'this:wp_getUsersBlogs',
+ 'wp.newPost' => 'this:wp_newPost',
+ 'wp.editPost' => 'this:wp_editPost',
+ 'wp.deletePost' => 'this:wp_deletePost',
+ 'wp.getPost' => 'this:wp_getPost',
+ 'wp.getPosts' => 'this:wp_getPosts',
+ 'wp.newTerm' => 'this:wp_newTerm',
+ 'wp.editTerm' => 'this:wp_editTerm',
+ 'wp.deleteTerm' => 'this:wp_deleteTerm',
+ 'wp.getTerm' => 'this:wp_getTerm',
+ 'wp.getTerms' => 'this:wp_getTerms',
+ 'wp.getTaxonomy' => 'this:wp_getTaxonomy',
+ 'wp.getTaxonomies' => 'this:wp_getTaxonomies',
+ 'wp.getUser' => 'this:wp_getUser',
+ 'wp.getUsers' => 'this:wp_getUsers',
+ 'wp.getProfile' => 'this:wp_getProfile',
+ 'wp.editProfile' => 'this:wp_editProfile',
+ 'wp.getPage' => 'this:wp_getPage',
+ 'wp.getPages' => 'this:wp_getPages',
+ 'wp.newPage' => 'this:wp_newPage',
+ 'wp.deletePage' => 'this:wp_deletePage',
+ 'wp.editPage' => 'this:wp_editPage',
+ 'wp.getPageList' => 'this:wp_getPageList',
+ 'wp.getAuthors' => 'this:wp_getAuthors',
+ 'wp.getCategories' => 'this:mw_getCategories', // Alias
+ 'wp.getTags' => 'this:wp_getTags',
+ 'wp.newCategory' => 'this:wp_newCategory',
+ 'wp.deleteCategory' => 'this:wp_deleteCategory',
+ 'wp.suggestCategories' => 'this:wp_suggestCategories',
+ 'wp.uploadFile' => 'this:mw_newMediaObject', // Alias
+ 'wp.getCommentCount' => 'this:wp_getCommentCount',
+ 'wp.getPostStatusList' => 'this:wp_getPostStatusList',
+ 'wp.getPageStatusList' => 'this:wp_getPageStatusList',
+ 'wp.getPageTemplates' => 'this:wp_getPageTemplates',
+ 'wp.getOptions' => 'this:wp_getOptions',
+ 'wp.setOptions' => 'this:wp_setOptions',
+ 'wp.getComment' => 'this:wp_getComment',
+ 'wp.getComments' => 'this:wp_getComments',
+ 'wp.deleteComment' => 'this:wp_deleteComment',
+ 'wp.editComment' => 'this:wp_editComment',
+ 'wp.newComment' => 'this:wp_newComment',
+ 'wp.getCommentStatusList' => 'this:wp_getCommentStatusList',
+ 'wp.getMediaItem' => 'this:wp_getMediaItem',
+ 'wp.getMediaLibrary' => 'this:wp_getMediaLibrary',
+ 'wp.getPostFormats' => 'this:wp_getPostFormats',
+ 'wp.getPostType' => 'this:wp_getPostType',
+ 'wp.getPostTypes' => 'this:wp_getPostTypes',
+ 'wp.getRevisions' => 'this:wp_getRevisions',
+ 'wp.restoreRevision' => 'this:wp_restoreRevision',
+
+ // Blogger API
+ 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
+ 'blogger.getUserInfo' => 'this:blogger_getUserInfo',
+ 'blogger.getPost' => 'this:blogger_getPost',
+ 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
+ 'blogger.newPost' => 'this:blogger_newPost',
+ 'blogger.editPost' => 'this:blogger_editPost',
+ 'blogger.deletePost' => 'this:blogger_deletePost',
+
+ // MetaWeblog API (with MT extensions to structs)
+ 'metaWeblog.newPost' => 'this:mw_newPost',
+ 'metaWeblog.editPost' => 'this:mw_editPost',
+ 'metaWeblog.getPost' => 'this:mw_getPost',
+ 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
+ 'metaWeblog.getCategories' => 'this:mw_getCategories',
+ 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
+
+ // MetaWeblog API aliases for Blogger API
+ // see http://www.xmlrpc.com/stories/storyReader$2460
+ 'metaWeblog.deletePost' => 'this:blogger_deletePost',
+ 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
+
+ // MovableType API
+ 'mt.getCategoryList' => 'this:mt_getCategoryList',
+ 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
+ 'mt.getPostCategories' => 'this:mt_getPostCategories',
+ 'mt.setPostCategories' => 'this:mt_setPostCategories',
+ 'mt.supportedMethods' => 'this:mt_supportedMethods',
+ 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
+ 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
+ 'mt.publishPost' => 'this:mt_publishPost',
+
+ // PingBack
+ 'pingback.ping' => 'this:pingback_ping',
+ 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
+
+ 'demo.sayHello' => 'this:sayHello',
+ 'demo.addTwoNumbers' => 'this:addTwoNumbers'
+ );
+
+ $this->initialise_blog_option_info();
+ $this->methods = apply_filters('xmlrpc_methods', $this->methods);
+ }
+
+ function serve_request() {
+ $this->IXR_Server($this->methods);
+ }
+
+ /**
+ * Test XMLRPC API by saying, "Hello!" to client.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method Parameters.
+ * @return string
+ */
+ function sayHello($args) {
+ return 'Hello!';
+ }
+
+ /**
+ * Test XMLRPC API by adding two numbers for client.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method Parameters.
+ * @return int
+ */
+ function addTwoNumbers($args) {
+ $number1 = $args[0];
+ $number2 = $args[1];
+ return $number1 + $number2;
+ }
+
+ /**
+ * Log user in.
+ *
+ * @since 2.8.0
+ *
+ * @param string $username User's username.
+ * @param string $password User's password.
+ * @return mixed WP_User object if authentication passed, false otherwise
+ */
+ function login( $username, $password ) {
+ // Respect any old filters against get_option() for 'enable_xmlrpc'.
+ $enabled = apply_filters( 'pre_option_enable_xmlrpc', false ); // Deprecated
+ if ( false === $enabled )
+ $enabled = apply_filters( 'option_enable_xmlrpc', true ); // Deprecated
+
+ // Proper filter for turning off XML-RPC. It is on by default.
+ $enabled = apply_filters( 'xmlrpc_enabled', $enabled );
+
+ if ( ! $enabled ) {
+ $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.' ) ) );
+ return false;
+ }
+
+ $user = wp_authenticate($username, $password);
+
+ if (is_wp_error($user)) {
+ $this->error = new IXR_Error( 403, __( 'Incorrect username or password.' ) );
+ $this->error = apply_filters( 'xmlrpc_login_error', $this->error, $user );
+ return false;
+ }
+
+ wp_set_current_user( $user->ID );
+ return $user;
+ }
+
+ /**
+ * Check user's credentials. Deprecated.
+ *
+ * @since 1.5.0
+ * @deprecated 2.8.0
+ * @deprecated use wp_xmlrpc_server::login
+ * @see wp_xmlrpc_server::login
+ *
+ * @param string $username User's username.
+ * @param string $password User's password.
+ * @return bool Whether authentication passed.
+ */
+ function login_pass_ok( $username, $password ) {
+ return (bool) $this->login( $username, $password );
+ }
+
+ /**
+ * Escape string or array of strings for database.
+ *
+ * @since 1.5.2
+ *
+ * @param string|array $data Escape single string or array of strings.
+ * @return string|array Type matches $data and sanitized for the database.
+ */
+ function escape( &$data ) {
+ if ( ! is_array( $data ) )
+ return wp_slash( $data );
+
+ foreach ( $data as &$v ) {
+ if ( is_array( $v ) )
+ $this->escape( $v );
+ elseif ( ! is_object( $v ) )
+ $v = wp_slash( $v );
+ }
+ }
+
+ /**
+ * Retrieve custom fields for post.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Post ID.
+ * @return array Custom fields, if exist.
+ */
+ function get_custom_fields($post_id) {
+ $post_id = (int) $post_id;
+
+ $custom_fields = array();
+
+ foreach ( (array) has_meta($post_id) as $meta ) {
+ // Don't expose protected fields.
+ if ( ! current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) )
+ continue;
+
+ $custom_fields[] = array(
+ "id" => $meta['meta_id'],
+ "key" => $meta['meta_key'],
+ "value" => $meta['meta_value']
+ );
+ }
+
+ return $custom_fields;
+ }
+
+ /**
+ * Set custom fields for post.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Post ID.
+ * @param array $fields Custom fields.
+ */
+ function set_custom_fields($post_id, $fields) {
+ $post_id = (int) $post_id;
+
+ foreach ( (array) $fields as $meta ) {
+ if ( isset($meta['id']) ) {
+ $meta['id'] = (int) $meta['id'];
+ $pmeta = get_metadata_by_mid( 'post', $meta['id'] );
+ if ( isset($meta['key']) ) {
+ $meta['key'] = wp_unslash( $meta['key'] );
+ if ( $meta['key'] !== $pmeta->meta_key )
+ continue;
+ $meta['value'] = wp_unslash( $meta['value'] );
+ if ( current_user_can( 'edit_post_meta', $post_id, $meta['key'] ) )
+ update_metadata_by_mid( 'post', $meta['id'], $meta['value'] );
+ } elseif ( current_user_can( 'delete_post_meta', $post_id, $pmeta->meta_key ) ) {
+ delete_metadata_by_mid( 'post', $meta['id'] );
+ }
+ } elseif ( current_user_can( 'add_post_meta', $post_id, wp_unslash( $meta['key'] ) ) ) {
+ add_post_meta( $post_id, $meta['key'], $meta['value'] );
+ }
+ }
+ }
+
+ /**
+ * Set up blog options property.
+ *
+ * Passes property through 'xmlrpc_blog_options' filter.
+ *
+ * @since 2.6.0
+ */
+ function initialise_blog_option_info() {
+ global $wp_version;
+
+ $this->blog_options = array(
+ // Read only options
+ 'software_name' => array(
+ 'desc' => __( 'Software Name' ),
+ 'readonly' => true,
+ 'value' => 'WordPress'
+ ),
+ 'software_version' => array(
+ 'desc' => __( 'Software Version' ),
+ 'readonly' => true,
+ 'value' => $wp_version
+ ),
+ 'blog_url' => array(
+ 'desc' => __( 'WordPress Address (URL)' ),
+ 'readonly' => true,
+ 'option' => 'siteurl'
+ ),
+ 'home_url' => array(
+ 'desc' => __( 'Site Address (URL)' ),
+ 'readonly' => true,
+ 'option' => 'home'
+ ),
+ 'login_url' => array(
+ 'desc' => __( 'Login Address (URL)' ),
+ 'readonly' => true,
+ 'value' => wp_login_url( )
+ ),
+ 'admin_url' => array(
+ 'desc' => __( 'The URL to the admin area' ),
+ 'readonly' => true,
+ 'value' => get_admin_url( )
+ ),
+ 'image_default_link_type' => array(
+ 'desc' => __( 'Image default link type' ),
+ 'readonly' => true,
+ 'option' => 'image_default_link_type'
+ ),
+ 'image_default_size' => array(
+ 'desc' => __( 'Image default size' ),
+ 'readonly' => true,
+ 'option' => 'image_default_size'
+ ),
+ 'image_default_align' => array(
+ 'desc' => __( 'Image default align' ),
+ 'readonly' => true,
+ 'option' => 'image_default_align'
+ ),
+ 'template' => array(
+ 'desc' => __( 'Template' ),
+ 'readonly' => true,
+ 'option' => 'template'
+ ),
+ 'stylesheet' => array(
+ 'desc' => __( 'Stylesheet' ),
+ 'readonly' => true,
+ 'option' => 'stylesheet'
+ ),
+ 'post_thumbnail' => array(
+ 'desc' => __('Post Thumbnail'),
+ 'readonly' => true,
+ 'value' => current_theme_supports( 'post-thumbnails' )
+ ),
+
+ // Updatable options
+ 'time_zone' => array(
+ 'desc' => __( 'Time Zone' ),
+ 'readonly' => false,
+ 'option' => 'gmt_offset'
+ ),
+ 'blog_title' => array(
+ 'desc' => __( 'Site Title' ),
+ 'readonly' => false,
+ 'option' => 'blogname'
+ ),
+ 'blog_tagline' => array(
+ 'desc' => __( 'Site Tagline' ),
+ 'readonly' => false,
+ 'option' => 'blogdescription'
+ ),
+ 'date_format' => array(
+ 'desc' => __( 'Date Format' ),
+ 'readonly' => false,
+ 'option' => 'date_format'
+ ),
+ 'time_format' => array(
+ 'desc' => __( 'Time Format' ),
+ 'readonly' => false,
+ 'option' => 'time_format'
+ ),
+ 'users_can_register' => array(
+ 'desc' => __( 'Allow new users to sign up' ),
+ 'readonly' => false,
+ 'option' => 'users_can_register'
+ ),
+ 'thumbnail_size_w' => array(
+ 'desc' => __( 'Thumbnail Width' ),
+ 'readonly' => false,
+ 'option' => 'thumbnail_size_w'
+ ),
+ 'thumbnail_size_h' => array(
+ 'desc' => __( 'Thumbnail Height' ),
+ 'readonly' => false,
+ 'option' => 'thumbnail_size_h'
+ ),
+ 'thumbnail_crop' => array(
+ 'desc' => __( 'Crop thumbnail to exact dimensions' ),
+ 'readonly' => false,
+ 'option' => 'thumbnail_crop'
+ ),
+ 'medium_size_w' => array(
+ 'desc' => __( 'Medium size image width' ),
+ 'readonly' => false,
+ 'option' => 'medium_size_w'
+ ),
+ 'medium_size_h' => array(
+ 'desc' => __( 'Medium size image height' ),
+ 'readonly' => false,
+ 'option' => 'medium_size_h'
+ ),
+ 'large_size_w' => array(
+ 'desc' => __( 'Large size image width' ),
+ 'readonly' => false,
+ 'option' => 'large_size_w'
+ ),
+ 'large_size_h' => array(
+ 'desc' => __( 'Large size image height' ),
+ 'readonly' => false,
+ 'option' => 'large_size_h'
+ ),
+ 'default_comment_status' => array(
+ 'desc' => __( 'Allow people to post comments on new articles' ),
+ 'readonly' => false,
+ 'option' => 'default_comment_status'
+ ),
+ 'default_ping_status' => array(
+ 'desc' => __( 'Allow link notifications from other blogs (pingbacks and trackbacks)' ),
+ 'readonly' => false,
+ 'option' => 'default_ping_status'
+ )
+ );
+
+ $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
+ }
+
+ /**
+ * Retrieve the blogs of the user.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - username
+ * - password
+ * @return array. Contains:
+ * - 'isAdmin'
+ * - 'url'
+ * - 'blogid'
+ * - 'blogName'
+ * - 'xmlrpc' - url of xmlrpc endpoint
+ */
+ function wp_getUsersBlogs( $args ) {
+ global $current_site;
+ // If this isn't on WPMU then just use blogger_getUsersBlogs
+ if ( !is_multisite() ) {
+ array_unshift( $args, 1 );
+ return $this->blogger_getUsersBlogs( $args );
+ }
+
+ $this->escape( $args );
+
+ $username = $args[0];
+ $password = $args[1];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getUsersBlogs' );
+
+ $blogs = (array) get_blogs_of_user( $user->ID );
+ $struct = array();
+
+ foreach ( $blogs as $blog ) {
+ // Don't include blogs that aren't hosted at this site
+ if ( $blog->site_id != $current_site->id )
+ continue;
+
+ $blog_id = $blog->userblog_id;
+
+ switch_to_blog( $blog_id );
+
+ $is_admin = current_user_can( 'manage_options' );
+
+ $struct[] = array(
+ 'isAdmin' => $is_admin,
+ 'url' => home_url( '/' ),
+ 'blogid' => (string) $blog_id,
+ 'blogName' => get_option( 'blogname' ),
+ 'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ),
+ );
+
+ restore_current_blog();
+ }
+
+ return $struct;
+ }
+
+ /**
+ * Checks if the method received at least the minimum number of arguments.
+ *
+ * @since 3.4.0
+ *
+ * @param string|array $args Sanitize single string or array of strings.
+ * @param int $count Minimum number of arguments.
+ * @return boolean if $args contains at least $count arguments.
+ */
+ protected function minimum_args( $args, $count ) {
+ if ( count( $args ) < $count ) {
+ $this->error = new IXR_Error( 400, __( 'Insufficient arguments passed to this XML-RPC method.' ) );
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Prepares taxonomy data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param object $taxonomy The unprepared taxonomy data
+ * @param array $fields The subset of taxonomy fields to return
+ * @return array The prepared taxonomy data
+ */
+ protected function _prepare_taxonomy( $taxonomy, $fields ) {
+ $_taxonomy = array(
+ 'name' => $taxonomy->name,
+ 'label' => $taxonomy->label,
+ 'hierarchical' => (bool) $taxonomy->hierarchical,
+ 'public' => (bool) $taxonomy->public,
+ 'show_ui' => (bool) $taxonomy->show_ui,
+ '_builtin' => (bool) $taxonomy->_builtin,
+ );
+
+ if ( in_array( 'labels', $fields ) )
+ $_taxonomy['labels'] = (array) $taxonomy->labels;
+
+ if ( in_array( 'cap', $fields ) )
+ $_taxonomy['cap'] = (array) $taxonomy->cap;
+
+ if ( in_array( 'object_type', $fields ) )
+ $_taxonomy['object_type'] = array_unique( (array) $taxonomy->object_type );
+
+ return apply_filters( 'xmlrpc_prepare_taxonomy', $_taxonomy, $taxonomy, $fields );
+ }
+
+ /**
+ * Prepares term data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param array|object $term The unprepared term data
+ * @return array The prepared term data
+ */
+ protected function _prepare_term( $term ) {
+ $_term = $term;
+ if ( ! is_array( $_term) )
+ $_term = get_object_vars( $_term );
+
+ // For integers which may be larger than XML-RPC supports ensure we return strings.
+ $_term['term_id'] = strval( $_term['term_id'] );
+ $_term['term_group'] = strval( $_term['term_group'] );
+ $_term['term_taxonomy_id'] = strval( $_term['term_taxonomy_id'] );
+ $_term['parent'] = strval( $_term['parent'] );
+
+ // Count we are happy to return as an integer because people really shouldn't use terms that much.
+ $_term['count'] = intval( $_term['count'] );
+
+ return apply_filters( 'xmlrpc_prepare_term', $_term, $term );
+ }
+
+ /**
+ * Convert a WordPress date string to an IXR_Date object.
+ *
+ * @access protected
+ *
+ * @param string $date
+ * @return IXR_Date
+ */
+ protected function _convert_date( $date ) {
+ if ( $date === '0000-00-00 00:00:00' ) {
+ return new IXR_Date( '00000000T00:00:00Z' );
+ }
+ return new IXR_Date( mysql2date( 'Ymd\TH:i:s', $date, false ) );
+ }
+
+ /**
+ * Convert a WordPress GMT date string to an IXR_Date object.
+ *
+ * @access protected
+ *
+ * @param string $date_gmt
+ * @param string $date
+ * @return IXR_Date
+ */
+ protected function _convert_date_gmt( $date_gmt, $date ) {
+ if ( $date !== '0000-00-00 00:00:00' && $date_gmt === '0000-00-00 00:00:00' ) {
+ return new IXR_Date( get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $date, false ), 'Ymd\TH:i:s' ) );
+ }
+ return $this->_convert_date( $date_gmt );
+ }
+
+ /**
+ * Prepares post data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param array $post The unprepared post data
+ * @param array $fields The subset of post type fields to return
+ * @return array The prepared post data
+ */
+ protected function _prepare_post( $post, $fields ) {
+ // holds the data for this post. built up based on $fields
+ $_post = array( 'post_id' => strval( $post['ID'] ) );
+
+ // prepare common post fields
+ $post_fields = array(
+ 'post_title' => $post['post_title'],
+ 'post_date' => $this->_convert_date( $post['post_date'] ),
+ 'post_date_gmt' => $this->_convert_date_gmt( $post['post_date_gmt'], $post['post_date'] ),
+ 'post_modified' => $this->_convert_date( $post['post_modified'] ),
+ 'post_modified_gmt' => $this->_convert_date_gmt( $post['post_modified_gmt'], $post['post_modified'] ),
+ 'post_status' => $post['post_status'],
+ 'post_type' => $post['post_type'],
+ 'post_name' => $post['post_name'],
+ 'post_author' => $post['post_author'],
+ 'post_password' => $post['post_password'],
+ 'post_excerpt' => $post['post_excerpt'],
+ 'post_content' => $post['post_content'],
+ 'post_parent' => strval( $post['post_parent'] ),
+ 'post_mime_type' => $post['post_mime_type'],
+ 'link' => post_permalink( $post['ID'] ),
+ 'guid' => $post['guid'],
+ 'menu_order' => intval( $post['menu_order'] ),
+ 'comment_status' => $post['comment_status'],
+ 'ping_status' => $post['ping_status'],
+ 'sticky' => ( $post['post_type'] === 'post' && is_sticky( $post['ID'] ) ),
+ );
+
+ // Thumbnail
+ $post_fields['post_thumbnail'] = array();
+ $thumbnail_id = get_post_thumbnail_id( $post['ID'] );
+ if ( $thumbnail_id ) {
+ $thumbnail_size = current_theme_supports('post-thumbnail') ? 'post-thumbnail' : 'thumbnail';
+ $post_fields['post_thumbnail'] = $this->_prepare_media_item( get_post( $thumbnail_id ), $thumbnail_size );
+ }
+
+ // Consider future posts as published
+ if ( $post_fields['post_status'] === 'future' )
+ $post_fields['post_status'] = 'publish';
+
+ // Fill in blank post format
+ $post_fields['post_format'] = get_post_format( $post['ID'] );
+ if ( empty( $post_fields['post_format'] ) )
+ $post_fields['post_format'] = 'standard';
+
+ // Merge requested $post_fields fields into $_post
+ if ( in_array( 'post', $fields ) ) {
+ $_post = array_merge( $_post, $post_fields );
+ } else {
+ $requested_fields = array_intersect_key( $post_fields, array_flip( $fields ) );
+ $_post = array_merge( $_post, $requested_fields );
+ }
+
+ $all_taxonomy_fields = in_array( 'taxonomies', $fields );
+
+ if ( $all_taxonomy_fields || in_array( 'terms', $fields ) ) {
+ $post_type_taxonomies = get_object_taxonomies( $post['post_type'], 'names' );
+ $terms = wp_get_object_terms( $post['ID'], $post_type_taxonomies );
+ $_post['terms'] = array();
+ foreach ( $terms as $term ) {
+ $_post['terms'][] = $this->_prepare_term( $term );
+ }
+ }
+
+ if ( in_array( 'custom_fields', $fields ) )
+ $_post['custom_fields'] = $this->get_custom_fields( $post['ID'] );
+
+ if ( in_array( 'enclosure', $fields ) ) {
+ $_post['enclosure'] = array();
+ $enclosures = (array) get_post_meta( $post['ID'], 'enclosure' );
+ if ( ! empty( $enclosures ) ) {
+ $encdata = explode( "\n", $enclosures[0] );
+ $_post['enclosure']['url'] = trim( htmlspecialchars( $encdata[0] ) );
+ $_post['enclosure']['length'] = (int) trim( $encdata[1] );
+ $_post['enclosure']['type'] = trim( $encdata[2] );
+ }
+ }
+
+ return apply_filters( 'xmlrpc_prepare_post', $_post, $post, $fields );
+ }
+
+ /**
+ * Prepares post data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param object $post_type Post type object
+ * @param array $fields The subset of post fields to return
+ * @return array The prepared post type data
+ */
+ protected function _prepare_post_type( $post_type, $fields ) {
+ $_post_type = array(
+ 'name' => $post_type->name,
+ 'label' => $post_type->label,
+ 'hierarchical' => (bool) $post_type->hierarchical,
+ 'public' => (bool) $post_type->public,
+ 'show_ui' => (bool) $post_type->show_ui,
+ '_builtin' => (bool) $post_type->_builtin,
+ 'has_archive' => (bool) $post_type->has_archive,
+ 'supports' => get_all_post_type_supports( $post_type->name ),
+ );
+
+ if ( in_array( 'labels', $fields ) ) {
+ $_post_type['labels'] = (array) $post_type->labels;
+ }
+
+ if ( in_array( 'cap', $fields ) ) {
+ $_post_type['cap'] = (array) $post_type->cap;
+ $_post_type['map_meta_cap'] = (bool) $post_type->map_meta_cap;
+ }
+
+ if ( in_array( 'menu', $fields ) ) {
+ $_post_type['menu_position'] = (int) $post_type->menu_position;
+ $_post_type['menu_icon'] = $post_type->menu_icon;
+ $_post_type['show_in_menu'] = (bool) $post_type->show_in_menu;
+ }
+
+ if ( in_array( 'taxonomies', $fields ) )
+ $_post_type['taxonomies'] = get_object_taxonomies( $post_type->name, 'names' );
+
+ return apply_filters( 'xmlrpc_prepare_post_type', $_post_type, $post_type );
+ }
+
+ /**
+ * Prepares media item data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param object $media_item The unprepared media item data
+ * @param string $thumbnail_size The image size to use for the thumbnail URL
+ * @return array The prepared media item data
+ */
+ protected function _prepare_media_item( $media_item, $thumbnail_size = 'thumbnail' ) {
+ $_media_item = array(
+ 'attachment_id' => strval( $media_item->ID ),
+ 'date_created_gmt' => $this->_convert_date_gmt( $media_item->post_date_gmt, $media_item->post_date ),
+ 'parent' => $media_item->post_parent,
+ 'link' => wp_get_attachment_url( $media_item->ID ),
+ 'title' => $media_item->post_title,
+ 'caption' => $media_item->post_excerpt,
+ 'description' => $media_item->post_content,
+ 'metadata' => wp_get_attachment_metadata( $media_item->ID ),
+ );
+
+ $thumbnail_src = image_downsize( $media_item->ID, $thumbnail_size );
+ if ( $thumbnail_src )
+ $_media_item['thumbnail'] = $thumbnail_src[0];
+ else
+ $_media_item['thumbnail'] = $_media_item['link'];
+
+ return apply_filters( 'xmlrpc_prepare_media_item', $_media_item, $media_item, $thumbnail_size );
+ }
+
+ /**
+ * Prepares page data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param object $page The unprepared page data
+ * @return array The prepared page data
+ */
+ protected function _prepare_page( $page ) {
+ // Get all of the page content and link.
+ $full_page = get_extended( $page->post_content );
+ $link = post_permalink( $page->ID );
+
+ // Get info the page parent if there is one.
+ $parent_title = "";
+ if ( ! empty( $page->post_parent ) ) {
+ $parent = get_post( $page->post_parent );
+ $parent_title = $parent->post_title;
+ }
+
+ // Determine comment and ping settings.
+ $allow_comments = comments_open( $page->ID ) ? 1 : 0;
+ $allow_pings = pings_open( $page->ID ) ? 1 : 0;
+
+ // Format page date.
+ $page_date = $this->_convert_date( $page->post_date );
+ $page_date_gmt = $this->_convert_date_gmt( $page->post_date_gmt, $page->post_date );
+
+ // Pull the categories info together.
+ $categories = array();
+ foreach ( wp_get_post_categories( $page->ID ) as $cat_id ) {
+ $categories[] = get_cat_name( $cat_id );
+ }
+
+ // Get the author info.
+ $author = get_userdata( $page->post_author );
+
+ $page_template = get_page_template_slug( $page->ID );
+ if ( empty( $page_template ) )
+ $page_template = 'default';
+
+ $_page = array(
+ 'dateCreated' => $page_date,
+ 'userid' => $page->post_author,
+ 'page_id' => $page->ID,
+ 'page_status' => $page->post_status,
+ 'description' => $full_page['main'],
+ 'title' => $page->post_title,
+ 'link' => $link,
+ 'permaLink' => $link,
+ 'categories' => $categories,
+ 'excerpt' => $page->post_excerpt,
+ 'text_more' => $full_page['extended'],
+ 'mt_allow_comments' => $allow_comments,
+ 'mt_allow_pings' => $allow_pings,
+ 'wp_slug' => $page->post_name,
+ 'wp_password' => $page->post_password,
+ 'wp_author' => $author->display_name,
+ 'wp_page_parent_id' => $page->post_parent,
+ 'wp_page_parent_title' => $parent_title,
+ 'wp_page_order' => $page->menu_order,
+ 'wp_author_id' => (string) $author->ID,
+ 'wp_author_display_name' => $author->display_name,
+ 'date_created_gmt' => $page_date_gmt,
+ 'custom_fields' => $this->get_custom_fields( $page->ID ),
+ 'wp_page_template' => $page_template
+ );
+
+ return apply_filters( 'xmlrpc_prepare_page', $_page, $page );
+ }
+
+ /**
+ * Prepares comment data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param object $comment The unprepared comment data
+ * @return array The prepared comment data
+ */
+ protected function _prepare_comment( $comment ) {
+ // Format page date.
+ $comment_date = $this->_convert_date( $comment->comment_date );
+ $comment_date_gmt = $this->_convert_date_gmt( $comment->comment_date_gmt, $comment->comment_date );
+
+ if ( '0' == $comment->comment_approved )
+ $comment_status = 'hold';
+ else if ( 'spam' == $comment->comment_approved )
+ $comment_status = 'spam';
+ else if ( '1' == $comment->comment_approved )
+ $comment_status = 'approve';
+ else
+ $comment_status = $comment->comment_approved;
+
+ $_comment = array(
+ 'date_created_gmt' => $comment_date_gmt,
+ 'user_id' => $comment->user_id,
+ 'comment_id' => $comment->comment_ID,
+ 'parent' => $comment->comment_parent,
+ 'status' => $comment_status,
+ 'content' => $comment->comment_content,
+ 'link' => get_comment_link($comment),
+ 'post_id' => $comment->comment_post_ID,
+ 'post_title' => get_the_title($comment->comment_post_ID),
+ 'author' => $comment->comment_author,
+ 'author_url' => $comment->comment_author_url,
+ 'author_email' => $comment->comment_author_email,
+ 'author_ip' => $comment->comment_author_IP,
+ 'type' => $comment->comment_type,
+ );
+
+ return apply_filters( 'xmlrpc_prepare_comment', $_comment, $comment );
+ }
+
+ /**
+ * Prepares user data for return in an XML-RPC object.
+ *
+ * @access protected
+ *
+ * @param WP_User $user The unprepared user object
+ * @param array $fields The subset of user fields to return
+ * @return array The prepared user data
+ */
+ protected function _prepare_user( $user, $fields ) {
+ $_user = array( 'user_id' => strval( $user->ID ) );
+
+ $user_fields = array(
+ 'username' => $user->user_login,
+ 'first_name' => $user->user_firstname,
+ 'last_name' => $user->user_lastname,
+ 'registered' => $this->_convert_date( $user->user_registered ),
+ 'bio' => $user->user_description,
+ 'email' => $user->user_email,
+ 'nickname' => $user->nickname,
+ 'nicename' => $user->user_nicename,
+ 'url' => $user->user_url,
+ 'display_name' => $user->display_name,
+ 'roles' => $user->roles,
+ );
+
+ if ( in_array( 'all', $fields ) ) {
+ $_user = array_merge( $_user, $user_fields );
+ } else {
+ if ( in_array( 'basic', $fields ) ) {
+ $basic_fields = array( 'username', 'email', 'registered', 'display_name', 'nicename' );
+ $fields = array_merge( $fields, $basic_fields );
+ }
+ $requested_fields = array_intersect_key( $user_fields, array_flip( $fields ) );
+ $_user = array_merge( $_user, $requested_fields );
+ }
+
+ return apply_filters( 'xmlrpc_prepare_user', $_user, $user, $fields );
+ }
+
+ /**
+ * Create a new post for any registered post type.
+ *
+ * @since 3.4.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $content_struct
+ * $content_struct can contain:
+ * - post_type (default: 'post')
+ * - post_status (default: 'draft')
+ * - post_title
+ * - post_author
+ * - post_excerpt
+ * - post_content
+ * - post_date_gmt | post_date
+ * - post_format
+ * - post_password
+ * - comment_status - can be 'open' | 'closed'
+ * - ping_status - can be 'open' | 'closed'
+ * - sticky
+ * - post_thumbnail - ID of a media item to use as the post thumbnail/featured image
+ * - custom_fields - array, with each element containing 'key' and 'value'
+ * - terms - array, with taxonomy names as keys and arrays of term IDs as values
+ * - terms_names - array, with taxonomy names as keys and arrays of term names as values
+ * - enclosure
+ * - any other fields supported by wp_insert_post()
+ * @return string post_id
+ */
+ function wp_newPost( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $content_struct = $args[3];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.newPost' );
+
+ unset( $content_struct['ID'] );
+
+ return $this->_insert_post( $user, $content_struct );
+ }
+
+ /**
+ * Helper method for filtering out elements from an array.
+ *
+ * @since 3.4.0
+ *
+ * @param int $count Number to compare to one.
+ */
+ private function _is_greater_than_one( $count ) {
+ return $count > 1;
+ }
+
+ /**
+ * Helper method for wp_newPost and wp_editPost, containing shared logic.
+ *
+ * @since 3.4.0
+ * @uses wp_insert_post()
+ *
+ * @param WP_User $user The post author if post_author isn't set in $content_struct.
+ * @param array $content_struct Post data to insert.
+ */
+ protected function _insert_post( $user, $content_struct ) {
+ $defaults = array( 'post_status' => 'draft', 'post_type' => 'post', 'post_author' => 0,
+ 'post_password' => '', 'post_excerpt' => '', 'post_content' => '', 'post_title' => '' );
+
+ $post_data = wp_parse_args( $content_struct, $defaults );
+
+ $post_type = get_post_type_object( $post_data['post_type'] );
+ if ( ! $post_type )
+ return new IXR_Error( 403, __( 'Invalid post type' ) );
+
+ $update = ! empty( $post_data['ID'] );
+
+ if ( $update ) {
+ if ( ! get_post( $post_data['ID'] ) )
+ return new IXR_Error( 401, __( 'Invalid post ID.' ) );
+ if ( ! current_user_can( 'edit_post', $post_data['ID'] ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post.' ) );
+ if ( $post_data['post_type'] != get_post_type( $post_data['ID'] ) )
+ return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
+ } else {
+ if ( ! current_user_can( $post_type->cap->create_posts ) || ! current_user_can( $post_type->cap->edit_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to post on this site.' ) );
+ }
+
+ switch ( $post_data['post_status'] ) {
+ case 'draft':
+ case 'pending':
+ break;
+ case 'private':
+ if ( ! current_user_can( $post_type->cap->publish_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to create private posts in this post type' ) );
+ break;
+ case 'publish':
+ case 'future':
+ if ( ! current_user_can( $post_type->cap->publish_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts in this post type' ) );
+ break;
+ default:
+ if ( ! get_post_status_object( $post_data['post_status'] ) )
+ $post_data['post_status'] = 'draft';
+ break;
+ }
+
+ if ( ! empty( $post_data['post_password'] ) && ! current_user_can( $post_type->cap->publish_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to create password protected posts in this post type' ) );
+
+ $post_data['post_author'] = absint( $post_data['post_author'] );
+ if ( ! empty( $post_data['post_author'] ) && $post_data['post_author'] != $user->ID ) {
+ if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
+ return new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) );
+
+ $author = get_userdata( $post_data['post_author'] );
+
+ if ( ! $author )
+ return new IXR_Error( 404, __( 'Invalid author ID.' ) );
+ } else {
+ $post_data['post_author'] = $user->ID;
+ }
+
+ if ( isset( $post_data['comment_status'] ) && $post_data['comment_status'] != 'open' && $post_data['comment_status'] != 'closed' )
+ unset( $post_data['comment_status'] );
+
+ if ( isset( $post_data['ping_status'] ) && $post_data['ping_status'] != 'open' && $post_data['ping_status'] != 'closed' )
+ unset( $post_data['ping_status'] );
+
+ // Do some timestamp voodoo
+ if ( ! empty( $post_data['post_date_gmt'] ) ) {
+ // We know this is supposed to be GMT, so we're going to slap that Z on there by force
+ $dateCreated = rtrim( $post_data['post_date_gmt']->getIso(), 'Z' ) . 'Z';
+ } elseif ( ! empty( $post_data['post_date'] ) ) {
+ $dateCreated = $post_data['post_date']->getIso();
+ }
+
+ if ( ! empty( $dateCreated ) ) {
+ $post_data['post_date'] = get_date_from_gmt( iso8601_to_datetime( $dateCreated ) );
+ $post_data['post_date_gmt'] = iso8601_to_datetime( $dateCreated, 'GMT' );
+ }
+
+ if ( ! isset( $post_data['ID'] ) )
+ $post_data['ID'] = get_default_post_to_edit( $post_data['post_type'], true )->ID;
+ $post_ID = $post_data['ID'];
+
+ if ( $post_data['post_type'] == 'post' ) {
+ // Private and password-protected posts cannot be stickied.
+ if ( $post_data['post_status'] == 'private' || ! empty( $post_data['post_password'] ) ) {
+ // Error if the client tried to stick the post, otherwise, silently unstick.
+ if ( ! empty( $post_data['sticky'] ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) );
+ if ( $update )
+ unstick_post( $post_ID );
+ } elseif ( isset( $post_data['sticky'] ) ) {
+ if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to stick this post.' ) );
+ if ( $post_data['sticky'] )
+ stick_post( $post_ID );
+ else
+ unstick_post( $post_ID );
+ }
+ }
+
+ if ( isset( $post_data['post_thumbnail'] ) ) {
+ // empty value deletes, non-empty value adds/updates
+ if ( ! $post_data['post_thumbnail'] )
+ delete_post_thumbnail( $post_ID );
+ elseif ( ! get_post( absint( $post_data['post_thumbnail'] ) ) )
+ return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
+ set_post_thumbnail( $post_ID, $post_data['post_thumbnail'] );
+ unset( $content_struct['post_thumbnail'] );
+ }
+
+ if ( isset( $post_data['custom_fields'] ) )
+ $this->set_custom_fields( $post_ID, $post_data['custom_fields'] );
+
+ if ( isset( $post_data['terms'] ) || isset( $post_data['terms_names'] ) ) {
+ $post_type_taxonomies = get_object_taxonomies( $post_data['post_type'], 'objects' );
+
+ // accumulate term IDs from terms and terms_names
+ $terms = array();
+
+ // first validate the terms specified by ID
+ if ( isset( $post_data['terms'] ) && is_array( $post_data['terms'] ) ) {
+ $taxonomies = array_keys( $post_data['terms'] );
+
+ // validating term ids
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) )
+ return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
+
+ if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
+
+ $term_ids = $post_data['terms'][$taxonomy];
+ foreach ( $term_ids as $term_id ) {
+ $term = get_term_by( 'id', $term_id, $taxonomy );
+
+ if ( ! $term )
+ return new IXR_Error( 403, __( 'Invalid term ID' ) );
+
+ $terms[$taxonomy][] = (int) $term_id;
+ }
+ }
+ }
+
+ // now validate terms specified by name
+ if ( isset( $post_data['terms_names'] ) && is_array( $post_data['terms_names'] ) ) {
+ $taxonomies = array_keys( $post_data['terms_names'] );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) )
+ return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
+
+ if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
+
+ // for hierarchical taxonomies, we can't assign a term when multiple terms in the hierarchy share the same name
+ $ambiguous_terms = array();
+ if ( is_taxonomy_hierarchical( $taxonomy ) ) {
+ $tax_term_names = get_terms( $taxonomy, array( 'fields' => 'names', 'hide_empty' => false ) );
+
+ // count the number of terms with the same name
+ $tax_term_names_count = array_count_values( $tax_term_names );
+
+ // filter out non-ambiguous term names
+ $ambiguous_tax_term_counts = array_filter( $tax_term_names_count, array( $this, '_is_greater_than_one') );
+
+ $ambiguous_terms = array_keys( $ambiguous_tax_term_counts );
+ }
+
+ $term_names = $post_data['terms_names'][$taxonomy];
+ foreach ( $term_names as $term_name ) {
+ if ( in_array( $term_name, $ambiguous_terms ) )
+ return new IXR_Error( 401, __( 'Ambiguous term name used in a hierarchical taxonomy. Please use term ID instead.' ) );
+
+ $term = get_term_by( 'name', $term_name, $taxonomy );
+
+ if ( ! $term ) {
+ // term doesn't exist, so check that the user is allowed to create new terms
+ if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->edit_terms ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to add a term to one of the given taxonomies.' ) );
+
+ // create the new term
+ $term_info = wp_insert_term( $term_name, $taxonomy );
+ if ( is_wp_error( $term_info ) )
+ return new IXR_Error( 500, $term_info->get_error_message() );
+
+ $terms[$taxonomy][] = (int) $term_info['term_id'];
+ } else {
+ $terms[$taxonomy][] = (int) $term->term_id;
+ }
+ }
+ }
+ }
+
+ $post_data['tax_input'] = $terms;
+ unset( $post_data['terms'], $post_data['terms_names'] );
+ } else {
+ // do not allow direct submission of 'tax_input', clients must use 'terms' and/or 'terms_names'
+ unset( $post_data['tax_input'], $post_data['post_category'], $post_data['tags_input'] );
+ }
+
+ if ( isset( $post_data['post_format'] ) ) {
+ $format = set_post_format( $post_ID, $post_data['post_format'] );
+
+ if ( is_wp_error( $format ) )
+ return new IXR_Error( 500, $format->get_error_message() );
+
+ unset( $post_data['post_format'] );
+ }
+
+ // Handle enclosures
+ $enclosure = isset( $post_data['enclosure'] ) ? $post_data['enclosure'] : null;
+ $this->add_enclosure_if_new( $post_ID, $enclosure );
+
+ $this->attach_uploads( $post_ID, $post_data['post_content'] );
+
+ $post_data = apply_filters( 'xmlrpc_wp_insert_post_data', $post_data, $content_struct );
+
+ $post_ID = $update ? wp_update_post( $post_data, true ) : wp_insert_post( $post_data, true );
+ if ( is_wp_error( $post_ID ) )
+ return new IXR_Error( 500, $post_ID->get_error_message() );
+
+ if ( ! $post_ID )
+ return new IXR_Error( 401, __( 'Sorry, your entry could not be posted. Something wrong happened.' ) );
+
+ return strval( $post_ID );
+ }
+
+ /**
+ * Edit a post for any registered post type.
+ *
+ * The $content_struct parameter only needs to contain fields that
+ * should be changed. All other fields will retain their existing values.
+ *
+ * @since 3.4.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - int $post_id
+ * - array $content_struct
+ * @return true on success
+ */
+ function wp_editPost( $args ) {
+ if ( ! $this->minimum_args( $args, 5 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_id = (int) $args[3];
+ $content_struct = $args[4];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.editPost' );
+
+ $post = get_post( $post_id, ARRAY_A );
+
+ if ( empty( $post['ID'] ) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( isset( $content_struct['if_not_modified_since'] ) ) {
+ // If the post has been modified since the date provided, return an error.
+ if ( mysql2date( 'U', $post['post_modified_gmt'] ) > $content_struct['if_not_modified_since']->getTimestamp() ) {
+ return new IXR_Error( 409, __( 'There is a revision of this post that is more recent.' ) );
+ }
+ }
+
+ // convert the date field back to IXR form
+ $post['post_date'] = $this->_convert_date( $post['post_date'] );
+
+ // ignore the existing GMT date if it is empty or a non-GMT date was supplied in $content_struct,
+ // since _insert_post will ignore the non-GMT date if the GMT date is set
+ if ( $post['post_date_gmt'] == '0000-00-00 00:00:00' || isset( $content_struct['post_date'] ) )
+ unset( $post['post_date_gmt'] );
+ else
+ $post['post_date_gmt'] = $this->_convert_date( $post['post_date_gmt'] );
+
+ $this->escape( $post );
+ $merged_content_struct = array_merge( $post, $content_struct );
+
+ $retval = $this->_insert_post( $user, $merged_content_struct );
+ if ( $retval instanceof IXR_Error )
+ return $retval;
+
+ return true;
+ }
+
+ /**
+ * Delete a post for any registered post type.
+ *
+ * @since 3.4.0
+ *
+ * @uses wp_delete_post()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - int $post_id
+ * @return true on success
+ */
+ function wp_deletePost( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_id = (int) $args[3];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.deletePost' );
+
+ $post = get_post( $post_id, ARRAY_A );
+ if ( empty( $post['ID'] ) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( ! current_user_can( 'delete_post', $post_id ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this post.' ) );
+
+ $result = wp_delete_post( $post_id );
+
+ if ( ! $result )
+ return new IXR_Error( 500, __( 'The post cannot be deleted.' ) );
+
+ return true;
+ }
+
+ /**
+ * Retrieve a post.
+ *
+ * @since 3.4.0
+ *
+ * The optional $fields parameter specifies what fields will be included
+ * in the response array. This should be a list of field names. 'post_id' will
+ * always be included in the response regardless of the value of $fields.
+ *
+ * Instead of, or in addition to, individual field names, conceptual group
+ * names can be used to specify multiple fields. The available conceptual
+ * groups are 'post' (all basic fields), 'taxonomies', 'custom_fields',
+ * and 'enclosure'.
+ *
+ * @uses get_post()
+ * @param array $args Method parameters. Contains:
+ * - int $post_id
+ * - string $username
+ * - string $password
+ * - array $fields optional
+ * @return array contains (based on $fields parameter):
+ * - 'post_id'
+ * - 'post_title'
+ * - 'post_date'
+ * - 'post_date_gmt'
+ * - 'post_modified'
+ * - 'post_modified_gmt'
+ * - 'post_status'
+ * - 'post_type'
+ * - 'post_name'
+ * - 'post_author'
+ * - 'post_password'
+ * - 'post_excerpt'
+ * - 'post_content'
+ * - 'link'
+ * - 'comment_status'
+ * - 'ping_status'
+ * - 'sticky'
+ * - 'custom_fields'
+ * - 'terms'
+ * - 'categories'
+ * - 'tags'
+ * - 'enclosure'
+ */
+ function wp_getPost( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_id = (int) $args[3];
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPost' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getPost' );
+
+ $post = get_post( $post_id, ARRAY_A );
+
+ if ( empty( $post['ID'] ) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
+
+ return $this->_prepare_post( $post, $fields );
+ }
+
+ /**
+ * Retrieve posts.
+ *
+ * @since 3.4.0
+ *
+ * The optional $filter parameter modifies the query used to retrieve posts.
+ * Accepted keys are 'post_type', 'post_status', 'number', 'offset',
+ * 'orderby', and 'order'.
+ *
+ * The optional $fields parameter specifies what fields will be included
+ * in the response array.
+ *
+ * @uses wp_get_recent_posts()
+ * @see wp_getPost() for more on $fields
+ * @see get_posts() for more on $filter values
+ *
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $filter optional
+ * - array $fields optional
+ * @return array contains a collection of posts.
+ */
+ function wp_getPosts( $args ) {
+ if ( ! $this->minimum_args( $args, 3 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $filter = isset( $args[3] ) ? $args[3] : array();
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPosts' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getPosts' );
+
+ $query = array();
+
+ if ( isset( $filter['post_type'] ) ) {
+ $post_type = get_post_type_object( $filter['post_type'] );
+ if ( ! ( (bool) $post_type ) )
+ return new IXR_Error( 403, __( 'The post type specified is not valid' ) );
+ } else {
+ $post_type = get_post_type_object( 'post' );
+ }
+
+ if ( ! current_user_can( $post_type->cap->edit_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts in this post type' ));
+
+ $query['post_type'] = $post_type->name;
+
+ if ( isset( $filter['post_status'] ) )
+ $query['post_status'] = $filter['post_status'];
+
+ if ( isset( $filter['number'] ) )
+ $query['numberposts'] = absint( $filter['number'] );
+
+ if ( isset( $filter['offset'] ) )
+ $query['offset'] = absint( $filter['offset'] );
+
+ if ( isset( $filter['orderby'] ) ) {
+ $query['orderby'] = $filter['orderby'];
+
+ if ( isset( $filter['order'] ) )
+ $query['order'] = $filter['order'];
+ }
+
+ if ( isset( $filter['s'] ) ) {
+ $query['s'] = $filter['s'];
+ }
+
+ $posts_list = wp_get_recent_posts( $query );
+
+ if ( ! $posts_list )
+ return array();
+
+ // holds all the posts data
+ $struct = array();
+
+ foreach ( $posts_list as $post ) {
+ if ( ! current_user_can( 'edit_post', $post['ID'] ) )
+ continue;
+
+ $struct[] = $this->_prepare_post( $post, $fields );
+ }
+
+ return $struct;
+ }
+
+ /**
+ * Create a new term.
+ *
+ * @since 3.4.0
+ *
+ * @uses wp_insert_term()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $content_struct
+ * The $content_struct must contain:
+ * - 'name'
+ * - 'taxonomy'
+ * Also, it can optionally contain:
+ * - 'parent'
+ * - 'description'
+ * - 'slug'
+ * @return string term_id
+ */
+ function wp_newTerm( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $content_struct = $args[3];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.newTerm' );
+
+ if ( ! taxonomy_exists( $content_struct['taxonomy'] ) )
+ return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
+
+ $taxonomy = get_taxonomy( $content_struct['taxonomy'] );
+
+ if ( ! current_user_can( $taxonomy->cap->manage_terms ) )
+ return new IXR_Error( 401, __( 'You are not allowed to create terms in this taxonomy.' ) );
+
+ $taxonomy = (array) $taxonomy;
+
+ // hold the data of the term
+ $term_data = array();
+
+ $term_data['name'] = trim( $content_struct['name'] );
+ if ( empty( $term_data['name'] ) )
+ return new IXR_Error( 403, __( 'The term name cannot be empty.' ) );
+
+ if ( isset( $content_struct['parent'] ) ) {
+ if ( ! $taxonomy['hierarchical'] )
+ return new IXR_Error( 403, __( 'This taxonomy is not hierarchical.' ) );
+
+ $parent_term_id = (int) $content_struct['parent'];
+ $parent_term = get_term( $parent_term_id , $taxonomy['name'] );
+
+ if ( is_wp_error( $parent_term ) )
+ return new IXR_Error( 500, $parent_term->get_error_message() );
+
+ if ( ! $parent_term )
+ return new IXR_Error( 403, __( 'Parent term does not exist.' ) );
+
+ $term_data['parent'] = $content_struct['parent'];
+ }
+
+ if ( isset( $content_struct['description'] ) )
+ $term_data['description'] = $content_struct['description'];
+
+ if ( isset( $content_struct['slug'] ) )
+ $term_data['slug'] = $content_struct['slug'];
+
+ $term = wp_insert_term( $term_data['name'] , $taxonomy['name'] , $term_data );
+
+ if ( is_wp_error( $term ) )
+ return new IXR_Error( 500, $term->get_error_message() );
+
+ if ( ! $term )
+ return new IXR_Error( 500, __( 'Sorry, your term could not be created. Something wrong happened.' ) );
+
+ return strval( $term['term_id'] );
+ }
+
+ /**
+ * Edit a term.
+ *
+ * @since 3.4.0
+ *
+ * @uses wp_update_term()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - string $term_id
+ * - array $content_struct
+ * The $content_struct must contain:
+ * - 'taxonomy'
+ * Also, it can optionally contain:
+ * - 'name'
+ * - 'parent'
+ * - 'description'
+ * - 'slug'
+ * @return bool True, on success.
+ */
+ function wp_editTerm( $args ) {
+ if ( ! $this->minimum_args( $args, 5 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $term_id = (int) $args[3];
+ $content_struct = $args[4];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.editTerm' );
+
+ if ( ! taxonomy_exists( $content_struct['taxonomy'] ) )
+ return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
+
+ $taxonomy = get_taxonomy( $content_struct['taxonomy'] );
+
+ if ( ! current_user_can( $taxonomy->cap->edit_terms ) )
+ return new IXR_Error( 401, __( 'You are not allowed to edit terms in this taxonomy.' ) );
+
+ $taxonomy = (array) $taxonomy;
+
+ // hold the data of the term
+ $term_data = array();
+
+ $term = get_term( $term_id , $content_struct['taxonomy'] );
+
+ if ( is_wp_error( $term ) )
+ return new IXR_Error( 500, $term->get_error_message() );
+
+ if ( ! $term )
+ return new IXR_Error( 404, __( 'Invalid term ID' ) );
+
+ if ( isset( $content_struct['name'] ) ) {
+ $term_data['name'] = trim( $content_struct['name'] );
+
+ if ( empty( $term_data['name'] ) )
+ return new IXR_Error( 403, __( 'The term name cannot be empty.' ) );
+ }
+
+ if ( isset( $content_struct['parent'] ) ) {
+ if ( ! $taxonomy['hierarchical'] )
+ return new IXR_Error( 403, __( "This taxonomy is not hierarchical so you can't set a parent." ) );
+
+ $parent_term_id = (int) $content_struct['parent'];
+ $parent_term = get_term( $parent_term_id , $taxonomy['name'] );
+
+ if ( is_wp_error( $parent_term ) )
+ return new IXR_Error( 500, $parent_term->get_error_message() );
+
+ if ( ! $parent_term )
+ return new IXR_Error( 403, __( 'Parent term does not exist.' ) );
+
+ $term_data['parent'] = $content_struct['parent'];
+ }
+
+ if ( isset( $content_struct['description'] ) )
+ $term_data['description'] = $content_struct['description'];
+
+ if ( isset( $content_struct['slug'] ) )
+ $term_data['slug'] = $content_struct['slug'];
+
+ $term = wp_update_term( $term_id , $taxonomy['name'] , $term_data );
+
+ if ( is_wp_error( $term ) )
+ return new IXR_Error( 500, $term->get_error_message() );
+
+ if ( ! $term )
+ return new IXR_Error( 500, __( 'Sorry, editing the term failed.' ) );
+
+ return true;
+ }
+
+ /**
+ * Delete a term.
+ *
+ * @since 3.4.0
+ *
+ * @uses wp_delete_term()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - string $taxnomy_name
+ * - string $term_id
+ * @return boolean|IXR_Error If it suceeded true else a reason why not
+ */
+ function wp_deleteTerm( $args ) {
+ if ( ! $this->minimum_args( $args, 5 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $taxonomy = $args[3];
+ $term_id = (int) $args[4];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.deleteTerm' );
+
+ if ( ! taxonomy_exists( $taxonomy ) )
+ return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
+
+ $taxonomy = get_taxonomy( $taxonomy );
+
+ if ( ! current_user_can( $taxonomy->cap->delete_terms ) )
+ return new IXR_Error( 401, __( 'You are not allowed to delete terms in this taxonomy.' ) );
+
+ $term = get_term( $term_id, $taxonomy->name );
+
+ if ( is_wp_error( $term ) )
+ return new IXR_Error( 500, $term->get_error_message() );
+
+ if ( ! $term )
+ return new IXR_Error( 404, __( 'Invalid term ID' ) );
+
+ $result = wp_delete_term( $term_id, $taxonomy->name );
+
+ if ( is_wp_error( $result ) )
+ return new IXR_Error( 500, $term->get_error_message() );
+
+ if ( ! $result )
+ return new IXR_Error( 500, __( 'Sorry, deleting the term failed.' ) );
+
+ return $result;
+ }
+
+ /**
+ * Retrieve a term.
+ *
+ * @since 3.4.0
+ *
+ * @uses get_term()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - string $taxonomy
+ * - string $term_id
+ * @return array contains:
+ * - 'term_id'
+ * - 'name'
+ * - 'slug'
+ * - 'term_group'
+ * - 'term_taxonomy_id'
+ * - 'taxonomy'
+ * - 'description'
+ * - 'parent'
+ * - 'count'
+ */
+ function wp_getTerm( $args ) {
+ if ( ! $this->minimum_args( $args, 5 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $taxonomy = $args[3];
+ $term_id = (int) $args[4];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getTerm' );
+
+ if ( ! taxonomy_exists( $taxonomy ) )
+ return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
+
+ $taxonomy = get_taxonomy( $taxonomy );
+
+ if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
+ return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
+
+ $term = get_term( $term_id , $taxonomy->name, ARRAY_A );
+
+ if ( is_wp_error( $term ) )
+ return new IXR_Error( 500, $term->get_error_message() );
+
+ if ( ! $term )
+ return new IXR_Error( 404, __( 'Invalid term ID' ) );
+
+ return $this->_prepare_term( $term );
+ }
+
+ /**
+ * Retrieve all terms for a taxonomy.
+ *
+ * @since 3.4.0
+ *
+ * The optional $filter parameter modifies the query used to retrieve terms.
+ * Accepted keys are 'number', 'offset', 'orderby', 'order', 'hide_empty', and 'search'.
+ *
+ * @uses get_terms()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - string $taxonomy
+ * - array $filter optional
+ * @return array terms
+ */
+ function wp_getTerms( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $taxonomy = $args[3];
+ $filter = isset( $args[4] ) ? $args[4] : array();
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getTerms' );
+
+ if ( ! taxonomy_exists( $taxonomy ) )
+ return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
+
+ $taxonomy = get_taxonomy( $taxonomy );
+
+ if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
+ return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
+
+ $query = array();
+
+ if ( isset( $filter['number'] ) )
+ $query['number'] = absint( $filter['number'] );
+
+ if ( isset( $filter['offset'] ) )
+ $query['offset'] = absint( $filter['offset'] );
+
+ if ( isset( $filter['orderby'] ) ) {
+ $query['orderby'] = $filter['orderby'];
+
+ if ( isset( $filter['order'] ) )
+ $query['order'] = $filter['order'];
+ }
+
+ if ( isset( $filter['hide_empty'] ) )
+ $query['hide_empty'] = $filter['hide_empty'];
+ else
+ $query['get'] = 'all';
+
+ if ( isset( $filter['search'] ) )
+ $query['search'] = $filter['search'];
+
+ $terms = get_terms( $taxonomy->name, $query );
+
+ if ( is_wp_error( $terms ) )
+ return new IXR_Error( 500, $terms->get_error_message() );
+
+ $struct = array();
+
+ foreach ( $terms as $term ) {
+ $struct[] = $this->_prepare_term( $term );
+ }
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve a taxonomy.
+ *
+ * @since 3.4.0
+ *
+ * @uses get_taxonomy()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - string $taxonomy
+ * @return array (@see get_taxonomy())
+ */
+ function wp_getTaxonomy( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $taxonomy = $args[3];
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomy' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getTaxonomy' );
+
+ if ( ! taxonomy_exists( $taxonomy ) )
+ return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
+
+ $taxonomy = get_taxonomy( $taxonomy );
+
+ if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
+ return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
+
+ return $this->_prepare_taxonomy( $taxonomy, $fields );
+ }
+
+ /**
+ * Retrieve all taxonomies.
+ *
+ * @since 3.4.0
+ *
+ * @uses get_taxonomies()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * @return array taxonomies
+ */
+ function wp_getTaxonomies( $args ) {
+ if ( ! $this->minimum_args( $args, 3 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $filter = isset( $args[3] ) ? $args[3] : array( 'public' => true );
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomies' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getTaxonomies' );
+
+ $taxonomies = get_taxonomies( $filter, 'objects' );
+
+ // holds all the taxonomy data
+ $struct = array();
+
+ foreach ( $taxonomies as $taxonomy ) {
+ // capability check for post_types
+ if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
+ continue;
+
+ $struct[] = $this->_prepare_taxonomy( $taxonomy, $fields );
+ }
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve a user.
+ *
+ * The optional $fields parameter specifies what fields will be included
+ * in the response array. This should be a list of field names. 'user_id' will
+ * always be included in the response regardless of the value of $fields.
+ *
+ * Instead of, or in addition to, individual field names, conceptual group
+ * names can be used to specify multiple fields. The available conceptual
+ * groups are 'basic' and 'all'.
+ *
+ * @uses get_userdata()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - int $user_id
+ * - array $fields optional
+ * @return array contains (based on $fields parameter):
+ * - 'user_id'
+ * - 'username'
+ * - 'first_name'
+ * - 'last_name'
+ * - 'registered'
+ * - 'bio'
+ * - 'email'
+ * - 'nickname'
+ * - 'nicename'
+ * - 'url'
+ * - 'display_name'
+ * - 'roles'
+ */
+ function wp_getUser( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $user_id = (int) $args[3];
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getUser' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getUser' );
+
+ if ( ! current_user_can( 'edit_user', $user_id ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit users.' ) );
+
+ $user_data = get_userdata( $user_id );
+
+ if ( ! $user_data )
+ return new IXR_Error( 404, __( 'Invalid user ID' ) );
+
+ return $this->_prepare_user( $user_data, $fields );
+ }
+
+ /**
+ * Retrieve users.
+ *
+ * The optional $filter parameter modifies the query used to retrieve users.
+ * Accepted keys are 'number' (default: 50), 'offset' (default: 0), 'role',
+ * 'who', 'orderby', and 'order'.
+ *
+ * The optional $fields parameter specifies what fields will be included
+ * in the response array.
+ *
+ * @uses get_users()
+ * @see wp_getUser() for more on $fields and return values
+ *
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $filter optional
+ * - array $fields optional
+ * @return array users data
+ */
+ function wp_getUsers( $args ) {
+ if ( ! $this->minimum_args( $args, 3 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $filter = isset( $args[3] ) ? $args[3] : array();
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getUsers' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getUsers' );
+
+ if ( ! current_user_can( 'list_users' ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot list users.' ) );
+
+ $query = array( 'fields' => 'all_with_meta' );
+
+ $query['number'] = ( isset( $filter['number'] ) ) ? absint( $filter['number'] ) : 50;
+ $query['offset'] = ( isset( $filter['offset'] ) ) ? absint( $filter['offset'] ) : 0;
+
+ if ( isset( $filter['orderby'] ) ) {
+ $query['orderby'] = $filter['orderby'];
+
+ if ( isset( $filter['order'] ) )
+ $query['order'] = $filter['order'];
+ }
+
+ if ( isset( $filter['role'] ) ) {
+ if ( get_role( $filter['role'] ) === null )
+ return new IXR_Error( 403, __( 'The role specified is not valid' ) );
+
+ $query['role'] = $filter['role'];
+ }
+
+ if ( isset( $filter['who'] ) ) {
+ $query['who'] = $filter['who'];
+ }
+
+ $users = get_users( $query );
+
+ $_users = array();
+ foreach ( $users as $user_data ) {
+ if ( current_user_can( 'edit_user', $user_data->ID ) )
+ $_users[] = $this->_prepare_user( $user_data, $fields );
+ }
+ return $_users;
+ }
+
+ /**
+ * Retrieve information about the requesting user.
+ *
+ * @uses get_userdata()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $fields optional
+ * @return array (@see wp_getUser)
+ */
+ function wp_getProfile( $args ) {
+ if ( ! $this->minimum_args( $args, 3 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( isset( $args[3] ) )
+ $fields = $args[3];
+ else
+ $fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getProfile' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getProfile' );
+
+ if ( ! current_user_can( 'edit_user', $user->ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit your profile.' ) );
+
+ $user_data = get_userdata( $user->ID );
+
+ return $this->_prepare_user( $user_data, $fields );
+ }
+
+ /**
+ * Edit user's profile.
+ *
+ * @uses wp_update_user()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $content_struct
+ * It can optionally contain:
+ * - 'first_name'
+ * - 'last_name'
+ * - 'website'
+ * - 'display_name'
+ * - 'nickname'
+ * - 'nicename'
+ * - 'bio'
+ * @return bool True, on success.
+ */
+ function wp_editProfile( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $content_struct = $args[3];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.editProfile' );
+
+ if ( ! current_user_can( 'edit_user', $user->ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit your profile.' ) );
+
+ // holds data of the user
+ $user_data = array();
+ $user_data['ID'] = $user->ID;
+
+ // only set the user details if it was given
+ if ( isset( $content_struct['first_name'] ) )
+ $user_data['first_name'] = $content_struct['first_name'];
+
+ if ( isset( $content_struct['last_name'] ) )
+ $user_data['last_name'] = $content_struct['last_name'];
+
+ if ( isset( $content_struct['url'] ) )
+ $user_data['user_url'] = $content_struct['url'];
+
+ if ( isset( $content_struct['display_name'] ) )
+ $user_data['display_name'] = $content_struct['display_name'];
+
+ if ( isset( $content_struct['nickname'] ) )
+ $user_data['nickname'] = $content_struct['nickname'];
+
+ if ( isset( $content_struct['nicename'] ) )
+ $user_data['user_nicename'] = $content_struct['nicename'];
+
+ if ( isset( $content_struct['bio'] ) )
+ $user_data['description'] = $content_struct['bio'];
+
+ $result = wp_update_user( $user_data );
+
+ if ( is_wp_error( $result ) )
+ return new IXR_Error( 500, $result->get_error_message() );
+
+ if ( ! $result )
+ return new IXR_Error( 500, __( 'Sorry, the user cannot be updated.' ) );
+
+ return true;
+ }
+
+ /**
+ * Retrieve page.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - page_id
+ * - username
+ * - password
+ * @return array
+ */
+ function wp_getPage($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $page_id = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+
+ if ( !$user = $this->login($username, $password) ) {
+ return $this->error;
+ }
+
+ $page = get_post($page_id);
+ if ( ! $page )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( !current_user_can( 'edit_page', $page_id ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) );
+
+ do_action('xmlrpc_call', 'wp.getPage');
+
+ // If we found the page then format the data.
+ if ( $page->ID && ($page->post_type == 'page') ) {
+ return $this->_prepare_page( $page );
+ }
+ // If the page doesn't exist indicate that.
+ else {
+ return(new IXR_Error(404, __('Sorry, no such page.')));
+ }
+ }
+
+ /**
+ * Retrieve Pages.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * - num_pages
+ * @return array
+ */
+ function wp_getPages($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $num_pages = isset($args[3]) ? (int) $args[3] : 10;
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_pages' ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
+
+ do_action('xmlrpc_call', 'wp.getPages');
+
+ $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) );
+ $num_pages = count($pages);
+
+ // If we have pages, put together their info.
+ if ( $num_pages >= 1 ) {
+ $pages_struct = array();
+
+ foreach ($pages as $page) {
+ if ( current_user_can( 'edit_page', $page->ID ) )
+ $pages_struct[] = $this->_prepare_page( $page );
+ }
+
+ return($pages_struct);
+ }
+ // If no pages were found return an error.
+ else {
+ return(array());
+ }
+ }
+
+ /**
+ * Create new page.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters. See {@link wp_xmlrpc_server::mw_newPost()}
+ * @return unknown
+ */
+ function wp_newPage($args) {
+ // Items not escaped here will be escaped in newPost.
+ $username = $this->escape($args[1]);
+ $password = $this->escape($args[2]);
+ $page = $args[3];
+ $publish = $args[4];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'wp.newPage');
+
+ // Mark this as content for a page.
+ $args[3]["post_type"] = 'page';
+
+ // Let mw_newPost do all of the heavy lifting.
+ return($this->mw_newPost($args));
+ }
+
+ /**
+ * Delete page.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True, if success.
+ */
+ function wp_deletePage($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $page_id = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'wp.deletePage');
+
+ // Get the current page based on the page_id and
+ // make sure it is a page and not a post.
+ $actual_page = get_post($page_id, ARRAY_A);
+ if ( !$actual_page || ($actual_page['post_type'] != 'page') )
+ return(new IXR_Error(404, __('Sorry, no such page.')));
+
+ // Make sure the user can delete pages.
+ if ( !current_user_can('delete_page', $page_id) )
+ return(new IXR_Error(401, __('Sorry, you do not have the right to delete this page.')));
+
+ // Attempt to delete the page.
+ $result = wp_delete_post($page_id);
+ if ( !$result )
+ return(new IXR_Error(500, __('Failed to delete the page.')));
+
+ do_action( 'xmlrpc_call_success_wp_deletePage', $page_id, $args );
+
+ return(true);
+ }
+
+ /**
+ * Edit page.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters.
+ * @return unknown
+ */
+ function wp_editPage($args) {
+ // Items not escaped here will be escaped in editPost.
+ $blog_id = (int) $args[0];
+ $page_id = (int) $this->escape($args[1]);
+ $username = $this->escape($args[2]);
+ $password = $this->escape($args[3]);
+ $content = $args[4];
+ $publish = $args[5];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'wp.editPage');
+
+ // Get the page data and make sure it is a page.
+ $actual_page = get_post($page_id, ARRAY_A);
+ if ( !$actual_page || ($actual_page['post_type'] != 'page') )
+ return(new IXR_Error(404, __('Sorry, no such page.')));
+
+ // Make sure the user is allowed to edit pages.
+ if ( !current_user_can('edit_page', $page_id) )
+ return(new IXR_Error(401, __('Sorry, you do not have the right to edit this page.')));
+
+ // Mark this as content for a page.
+ $content['post_type'] = 'page';
+
+ // Arrange args in the way mw_editPost understands.
+ $args = array(
+ $page_id,
+ $username,
+ $password,
+ $content,
+ $publish
+ );
+
+ // Let mw_editPost do all of the heavy lifting.
+ return($this->mw_editPost($args));
+ }
+
+ /**
+ * Retrieve page list.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters.
+ * @return unknown
+ */
+ function wp_getPageList($args) {
+ global $wpdb;
+
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_pages' ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
+
+ do_action('xmlrpc_call', 'wp.getPageList');
+
+ // Get list of pages ids and titles
+ $page_list = $wpdb->get_results("
+ SELECT ID page_id,
+ post_title page_title,
+ post_parent page_parent_id,
+ post_date_gmt,
+ post_date,
+ post_status
+ FROM {$wpdb->posts}
+ WHERE post_type = 'page'
+ ORDER BY ID
+ ");
+
+ // The date needs to be formatted properly.
+ $num_pages = count($page_list);
+ for ( $i = 0; $i < $num_pages; $i++ ) {
+ $page_list[$i]->dateCreated = $this->_convert_date( $page_list[$i]->post_date );
+ $page_list[$i]->date_created_gmt = $this->_convert_date_gmt( $page_list[$i]->post_date_gmt, $page_list[$i]->post_date );
+
+ unset($page_list[$i]->post_date_gmt);
+ unset($page_list[$i]->post_date);
+ unset($page_list[$i]->post_status);
+ }
+
+ return($page_list);
+ }
+
+ /**
+ * Retrieve authors list.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getAuthors($args) {
+
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can('edit_posts') )
+ return(new IXR_Error(401, __('Sorry, you cannot edit posts on this site.')));
+
+ do_action('xmlrpc_call', 'wp.getAuthors');
+
+ $authors = array();
+ foreach ( get_users( array( 'fields' => array('ID','user_login','display_name') ) ) as $user ) {
+ $authors[] = array(
+ 'user_id' => $user->ID,
+ 'user_login' => $user->user_login,
+ 'display_name' => $user->display_name
+ );
+ }
+
+ return $authors;
+ }
+
+ /**
+ * Get list of all tags
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getTags( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) );
+
+ do_action( 'xmlrpc_call', 'wp.getKeywords' );
+
+ $tags = array();
+
+ if ( $all_tags = get_tags() ) {
+ foreach( (array) $all_tags as $tag ) {
+ $struct['tag_id'] = $tag->term_id;
+ $struct['name'] = $tag->name;
+ $struct['count'] = $tag->count;
+ $struct['slug'] = $tag->slug;
+ $struct['html_url'] = esc_html( get_tag_link( $tag->term_id ) );
+ $struct['rss_url'] = esc_html( get_tag_feed_link( $tag->term_id ) );
+
+ $tags[] = $struct;
+ }
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Create new category.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters.
+ * @return int Category ID.
+ */
+ function wp_newCategory($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $category = $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'wp.newCategory');
+
+ // Make sure the user is allowed to add a category.
+ if ( !current_user_can('manage_categories') )
+ return(new IXR_Error(401, __('Sorry, you do not have the right to add a category.')));
+
+ // If no slug was provided make it empty so that
+ // WordPress will generate one.
+ if ( empty($category['slug']) )
+ $category['slug'] = '';
+
+ // If no parent_id was provided make it empty
+ // so that it will be a top level page (no parent).
+ if ( !isset($category['parent_id']) )
+ $category['parent_id'] = '';
+
+ // If no description was provided make it empty.
+ if ( empty($category["description"]) )
+ $category["description"] = "";
+
+ $new_category = array(
+ 'cat_name' => $category['name'],
+ 'category_nicename' => $category['slug'],
+ 'category_parent' => $category['parent_id'],
+ 'category_description' => $category['description']
+ );
+
+ $cat_id = wp_insert_category($new_category, true);
+ if ( is_wp_error( $cat_id ) ) {
+ if ( 'term_exists' == $cat_id->get_error_code() )
+ return (int) $cat_id->get_error_data();
+ else
+ return(new IXR_Error(500, __('Sorry, the new category failed.')));
+ } elseif ( ! $cat_id ) {
+ return(new IXR_Error(500, __('Sorry, the new category failed.')));
+ }
+
+ do_action( 'xmlrpc_call_success_wp_newCategory', $cat_id, $args );
+
+ return $cat_id;
+ }
+
+ /**
+ * Remove category.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return mixed See {@link wp_delete_term()} for return info.
+ */
+ function wp_deleteCategory($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $category_id = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'wp.deleteCategory');
+
+ if ( !current_user_can('manage_categories') )
+ return new IXR_Error( 401, __( 'Sorry, you do not have the right to delete a category.' ) );
+
+ $status = wp_delete_term( $category_id, 'category' );
+
+ if( true == $status )
+ do_action( 'xmlrpc_call_success_wp_deleteCategory', $category_id, $args );
+
+ return $status;
+ }
+
+ /**
+ * Retrieve category list.
+ *
+ * @since 2.2.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_suggestCategories($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $category = $args[3];
+ $max_results = (int) $args[4];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) );
+
+ do_action('xmlrpc_call', 'wp.suggestCategories');
+
+ $category_suggestions = array();
+ $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
+ foreach ( (array) get_categories($args) as $cat ) {
+ $category_suggestions[] = array(
+ 'category_id' => $cat->term_id,
+ 'category_name' => $cat->name
+ );
+ }
+
+ return($category_suggestions);
+ }
+
+ /**
+ * Retrieve comment.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getComment($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $comment_id = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
+
+ do_action('xmlrpc_call', 'wp.getComment');
+
+ if ( ! $comment = get_comment($comment_id) )
+ return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
+
+ return $this->_prepare_comment( $comment );
+ }
+
+ /**
+ * Retrieve comments.
+ *
+ * Besides the common blog_id, username, and password arguments, it takes a filter
+ * array as last argument.
+ *
+ * Accepted 'filter' keys are 'status', 'post_id', 'offset', and 'number'.
+ *
+ * The defaults are as follows:
+ * - 'status' - Default is ''. Filter by status (e.g., 'approve', 'hold')
+ * - 'post_id' - Default is ''. The post where the comment is posted. Empty string shows all comments.
+ * - 'number' - Default is 10. Total number of media items to retrieve.
+ * - 'offset' - Default is 0. See {@link WP_Query::query()} for more.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return array. Contains a collection of comments. See {@link wp_xmlrpc_server::wp_getComment()} for a description of each item contents
+ */
+ function wp_getComments($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $struct = isset( $args[3] ) ? $args[3] : array();
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) );
+
+ do_action('xmlrpc_call', 'wp.getComments');
+
+ if ( isset($struct['status']) )
+ $status = $struct['status'];
+ else
+ $status = '';
+
+ $post_id = '';
+ if ( isset($struct['post_id']) )
+ $post_id = absint($struct['post_id']);
+
+ $offset = 0;
+ if ( isset($struct['offset']) )
+ $offset = absint($struct['offset']);
+
+ $number = 10;
+ if ( isset($struct['number']) )
+ $number = absint($struct['number']);
+
+ $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) );
+
+ $comments_struct = array();
+
+ foreach ( $comments as $comment ) {
+ $comments_struct[] = $this->_prepare_comment( $comment );
+ }
+
+ return $comments_struct;
+ }
+
+ /**
+ * Delete a comment.
+ *
+ * By default, the comment will be moved to the trash instead of deleted.
+ * See {@link wp_delete_comment()} for more information on
+ * this behavior.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * - comment_id
+ * @return mixed {@link wp_delete_comment()}
+ */
+ function wp_deleteComment($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $comment_ID = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
+
+ if ( ! get_comment($comment_ID) )
+ return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
+
+ if ( !current_user_can( 'edit_comment', $comment_ID ) )
+ return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
+
+ do_action('xmlrpc_call', 'wp.deleteComment');
+
+ $status = wp_delete_comment( $comment_ID );
+
+ if( true == $status )
+ do_action( 'xmlrpc_call_success_wp_deleteComment', $comment_ID, $args );
+
+ return $status;
+ }
+
+ /**
+ * Edit comment.
+ *
+ * Besides the common blog_id, username, and password arguments, it takes a
+ * comment_id integer and a content_struct array as last argument.
+ *
+ * The allowed keys in the content_struct array are:
+ * - 'author'
+ * - 'author_url'
+ * - 'author_email'
+ * - 'content'
+ * - 'date_created_gmt'
+ * - 'status'. Common statuses are 'approve', 'hold', 'spam'. See {@link get_comment_statuses()} for more details
+ *
+ * @since 2.7.0
+ *
+ * @param array $args. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * - comment_id
+ * - content_struct
+ * @return bool True, on success.
+ */
+ function wp_editComment($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $comment_ID = (int) $args[3];
+ $content_struct = $args[4];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
+
+ if ( ! get_comment($comment_ID) )
+ return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
+
+ if ( !current_user_can( 'edit_comment', $comment_ID ) )
+ return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
+
+ do_action('xmlrpc_call', 'wp.editComment');
+
+ if ( isset($content_struct['status']) ) {
+ $statuses = get_comment_statuses();
+ $statuses = array_keys($statuses);
+
+ if ( ! in_array($content_struct['status'], $statuses) )
+ return new IXR_Error( 401, __( 'Invalid comment status.' ) );
+ $comment_approved = $content_struct['status'];
+ }
+
+ // Do some timestamp voodoo
+ if ( !empty( $content_struct['date_created_gmt'] ) ) {
+ // We know this is supposed to be GMT, so we're going to slap that Z on there by force
+ $dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
+ $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
+ $comment_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
+ }
+
+ if ( isset($content_struct['content']) )
+ $comment_content = $content_struct['content'];
+
+ if ( isset($content_struct['author']) )
+ $comment_author = $content_struct['author'];
+
+ if ( isset($content_struct['author_url']) )
+ $comment_author_url = $content_struct['author_url'];
+
+ if ( isset($content_struct['author_email']) )
+ $comment_author_email = $content_struct['author_email'];
+
+ // We've got all the data -- post it:
+ $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url');
+
+ $result = wp_update_comment($comment);
+ if ( is_wp_error( $result ) )
+ return new IXR_Error(500, $result->get_error_message());
+
+ if ( !$result )
+ return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.'));
+
+ do_action( 'xmlrpc_call_success_wp_editComment', $comment_ID, $args );
+
+ return true;
+ }
+
+ /**
+ * Create new comment.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return mixed {@link wp_new_comment()}
+ */
+ function wp_newComment($args) {
+ global $wpdb;
+
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post = $args[3];
+ $content_struct = $args[4];
+
+ $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false);
+
+ $user = $this->login($username, $password);
+
+ if ( !$user ) {
+ $logged_in = false;
+ if ( $allow_anon && get_option('comment_registration') )
+ return new IXR_Error( 403, __( 'You must be registered to comment' ) );
+ else if ( !$allow_anon )
+ return $this->error;
+ } else {
+ $logged_in = true;
+ }
+
+ if ( is_numeric($post) )
+ $post_id = absint($post);
+ else
+ $post_id = url_to_postid($post);
+
+ if ( ! $post_id )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( ! get_post($post_id) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ $comment['comment_post_ID'] = $post_id;
+
+ if ( $logged_in ) {
+ $comment['comment_author'] = $this->escape( $user->display_name );
+ $comment['comment_author_email'] = $this->escape( $user->user_email );
+ $comment['comment_author_url'] = $this->escape( $user->user_url );
+ $comment['user_ID'] = $user->ID;
+ } else {
+ $comment['comment_author'] = '';
+ if ( isset($content_struct['author']) )
+ $comment['comment_author'] = $content_struct['author'];
+
+ $comment['comment_author_email'] = '';
+ if ( isset($content_struct['author_email']) )
+ $comment['comment_author_email'] = $content_struct['author_email'];
+
+ $comment['comment_author_url'] = '';
+ if ( isset($content_struct['author_url']) )
+ $comment['comment_author_url'] = $content_struct['author_url'];
+
+ $comment['user_ID'] = 0;
+
+ if ( get_option('require_name_email') ) {
+ if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] )
+ return new IXR_Error( 403, __( 'Comment author name and email are required' ) );
+ elseif ( !is_email($comment['comment_author_email']) )
+ return new IXR_Error( 403, __( 'A valid email address is required' ) );
+ }
+ }
+
+ $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0;
+
+ $comment['comment_content'] = isset($content_struct['content']) ? $content_struct['content'] : null;
+
+ do_action('xmlrpc_call', 'wp.newComment');
+
+ $comment_ID = wp_new_comment( $comment );
+
+ do_action( 'xmlrpc_call_success_wp_newComment', $comment_ID, $args );
+
+ return $comment_ID;
+ }
+
+ /**
+ * Retrieve all of the comment status.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getCommentStatusList($args) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'moderate_comments' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
+
+ do_action('xmlrpc_call', 'wp.getCommentStatusList');
+
+ return get_comment_statuses();
+ }
+
+ /**
+ * Retrieve comment count.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getCommentCount( $args ) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_id = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
+
+ do_action('xmlrpc_call', 'wp.getCommentCount');
+
+ $count = wp_count_comments( $post_id );
+ return array(
+ 'approved' => $count->approved,
+ 'awaiting_moderation' => $count->moderated,
+ 'spam' => $count->spam,
+ 'total_comments' => $count->total_comments
+ );
+ }
+
+ /**
+ * Retrieve post statuses.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getPostStatusList( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
+
+ do_action('xmlrpc_call', 'wp.getPostStatusList');
+
+ return get_post_statuses();
+ }
+
+ /**
+ * Retrieve page statuses.
+ *
+ * @since 2.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getPageStatusList( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_pages' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
+
+ do_action('xmlrpc_call', 'wp.getPageStatusList');
+
+ return get_page_statuses();
+ }
+
+ /**
+ * Retrieve page templates.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getPageTemplates( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_pages' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
+
+ $templates = get_page_templates();
+ $templates['Default'] = 'default';
+
+ return $templates;
+ }
+
+ /**
+ * Retrieve blog options.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function wp_getOptions( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $options = isset( $args[3] ) ? (array) $args[3] : array();
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ // If no specific options where asked for, return all of them
+ if ( count( $options ) == 0 )
+ $options = array_keys($this->blog_options);
+
+ return $this->_getOptions($options);
+ }
+
+ /**
+ * Retrieve blog options value from list.
+ *
+ * @since 2.6.0
+ *
+ * @param array $options Options to retrieve.
+ * @return array
+ */
+ function _getOptions($options) {
+ $data = array();
+ $can_manage = current_user_can( 'manage_options' );
+ foreach ( $options as $option ) {
+ if ( array_key_exists( $option, $this->blog_options ) ) {
+ $data[$option] = $this->blog_options[$option];
+ //Is the value static or dynamic?
+ if ( isset( $data[$option]['option'] ) ) {
+ $data[$option]['value'] = get_option( $data[$option]['option'] );
+ unset($data[$option]['option']);
+ }
+
+ if ( ! $can_manage )
+ $data[$option]['readonly'] = true;
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Update blog options.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args Method parameters.
+ * @return unknown
+ */
+ function wp_setOptions( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $options = (array) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'manage_options' ) )
+ return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
+
+ foreach ( $options as $o_name => $o_value ) {
+ $option_names[] = $o_name;
+ if ( !array_key_exists( $o_name, $this->blog_options ) )
+ continue;
+
+ if ( $this->blog_options[$o_name]['readonly'] == true )
+ continue;
+
+ update_option( $this->blog_options[$o_name]['option'], $o_value );
+ }
+
+ //Now return the updated values
+ return $this->_getOptions($option_names);
+ }
+
+ /**
+ * Retrieve a media item by ID
+ *
+ * @since 3.1.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * - attachment_id
+ * @return array. Associative array containing:
+ * - 'date_created_gmt'
+ * - 'parent'
+ * - 'link'
+ * - 'thumbnail'
+ * - 'title'
+ * - 'caption'
+ * - 'description'
+ * - 'metadata'
+ */
+ function wp_getMediaItem($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $attachment_id = (int) $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'upload_files' ) )
+ return new IXR_Error( 403, __( 'You do not have permission to upload files.' ) );
+
+ do_action('xmlrpc_call', 'wp.getMediaItem');
+
+ if ( ! $attachment = get_post($attachment_id) )
+ return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
+
+ return $this->_prepare_media_item( $attachment );
+ }
+
+ /**
+ * Retrieves a collection of media library items (or attachments)
+ *
+ * Besides the common blog_id, username, and password arguments, it takes a filter
+ * array as last argument.
+ *
+ * Accepted 'filter' keys are 'parent_id', 'mime_type', 'offset', and 'number'.
+ *
+ * The defaults are as follows:
+ * - 'number' - Default is 5. Total number of media items to retrieve.
+ * - 'offset' - Default is 0. See {@link WP_Query::query()} for more.
+ * - 'parent_id' - Default is ''. The post where the media item is attached. Empty string shows all media items. 0 shows unattached media items.
+ * - 'mime_type' - Default is ''. Filter by mime type (e.g., 'image/jpeg', 'application/pdf')
+ *
+ * @since 3.1.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * - filter
+ * @return array. Contains a collection of media items. See {@link wp_xmlrpc_server::wp_getMediaItem()} for a description of each item contents
+ */
+ function wp_getMediaLibrary($args) {
+ $this->escape($args);
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $struct = isset( $args[3] ) ? $args[3] : array() ;
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'upload_files' ) )
+ return new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
+
+ do_action('xmlrpc_call', 'wp.getMediaLibrary');
+
+ $parent_id = ( isset($struct['parent_id']) ) ? absint($struct['parent_id']) : '' ;
+ $mime_type = ( isset($struct['mime_type']) ) ? $struct['mime_type'] : '' ;
+ $offset = ( isset($struct['offset']) ) ? absint($struct['offset']) : 0 ;
+ $number = ( isset($struct['number']) ) ? absint($struct['number']) : -1 ;
+
+ $attachments = get_posts( array('post_type' => 'attachment', 'post_parent' => $parent_id, 'offset' => $offset, 'numberposts' => $number, 'post_mime_type' => $mime_type ) );
+
+ $attachments_struct = array();
+
+ foreach ($attachments as $attachment )
+ $attachments_struct[] = $this->_prepare_media_item( $attachment );
+
+ return $attachments_struct;
+ }
+
+ /**
+ * Retrieves a list of post formats used by the site
+ *
+ * @since 3.1
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * @return array
+ */
+ function wp_getPostFormats( $args ) {
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login( $username, $password ) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
+
+ do_action( 'xmlrpc_call', 'wp.getPostFormats' );
+
+ $formats = get_post_format_strings();
+
+ # find out if they want a list of currently supports formats
+ if ( isset( $args[3] ) && is_array( $args[3] ) ) {
+ if ( $args[3]['show-supported'] ) {
+ if ( current_theme_supports( 'post-formats' ) ) {
+ $supported = get_theme_support( 'post-formats' );
+
+ $data['all'] = $formats;
+ $data['supported'] = $supported[0];
+
+ $formats = $data;
+ }
+ }
+ }
+
+ return $formats;
+ }
+
+ /**
+ * Retrieves a post type
+ *
+ * @since 3.4.0
+ *
+ * @uses get_post_type_object()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - string $post_type_name
+ * - array $fields
+ * @return array contains:
+ * - 'labels'
+ * - 'description'
+ * - 'capability_type'
+ * - 'cap'
+ * - 'map_meta_cap'
+ * - 'hierarchical'
+ * - 'menu_position'
+ * - 'taxonomies'
+ * - 'supports'
+ */
+ function wp_getPostType( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_type_name = $args[3];
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostType' );
+
+ if ( !$user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getPostType' );
+
+ if( ! post_type_exists( $post_type_name ) )
+ return new IXR_Error( 403, __( 'Invalid post type' ) );
+
+ $post_type = get_post_type_object( $post_type_name );
+
+ if( ! current_user_can( $post_type->cap->edit_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post type.' ) );
+
+ return $this->_prepare_post_type( $post_type, $fields );
+ }
+
+ /**
+ * Retrieves a post types
+ *
+ * @since 3.4.0
+ *
+ * @uses get_post_types()
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - array $filter
+ * - array $fields
+ * @return array
+ */
+ function wp_getPostTypes( $args ) {
+ if ( ! $this->minimum_args( $args, 3 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $filter = isset( $args[3] ) ? $args[3] : array( 'public' => true );
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostTypes' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getPostTypes' );
+
+ $post_types = get_post_types( $filter, 'objects' );
+
+ $struct = array();
+
+ foreach( $post_types as $post_type ) {
+ if( ! current_user_can( $post_type->cap->edit_posts ) )
+ continue;
+
+ $struct[$post_type->name] = $this->_prepare_post_type( $post_type, $fields );
+ }
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve revisions for a specific post.
+ *
+ * @since 3.5.0
+ *
+ * The optional $fields parameter specifies what fields will be included
+ * in the response array.
+ *
+ * @uses wp_get_post_revisions()
+ * @see wp_getPost() for more on $fields
+ *
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - int $post_id
+ * - array $fields
+ * @return array contains a collection of posts.
+ */
+ function wp_getRevisions( $args ) {
+ if ( ! $this->minimum_args( $args, 4 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $post_id = (int) $args[3];
+
+ if ( isset( $args[4] ) )
+ $fields = $args[4];
+ else
+ $fields = apply_filters( 'xmlrpc_default_revision_fields', array( 'post_date', 'post_date_gmt' ), 'wp.getRevisions' );
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.getRevisions' );
+
+ if ( ! $post = get_post( $post_id ) )
+ return new IXR_Error( 404, __( 'Invalid post ID' ) );
+
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts.' ) );
+
+ // Check if revisions are enabled.
+ if ( ! wp_revisions_enabled( $post ) )
+ return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) );
+
+ $revisions = wp_get_post_revisions( $post_id );
+
+ if ( ! $revisions )
+ return array();
+
+ $struct = array();
+
+ foreach ( $revisions as $revision ) {
+ if ( ! current_user_can( 'read_post', $revision->ID ) )
+ continue;
+
+ // Skip autosaves
+ if ( wp_is_post_autosave( $revision ) )
+ continue;
+
+ $struct[] = $this->_prepare_post( get_object_vars( $revision ), $fields );
+ }
+
+ return $struct;
+ }
+
+ /**
+ * Restore a post revision
+ *
+ * @since 3.5.0
+ *
+ * @uses wp_restore_post_revision()
+ *
+ * @param array $args Method parameters. Contains:
+ * - int $blog_id
+ * - string $username
+ * - string $password
+ * - int $post_id
+ * @return bool false if there was an error restoring, true if success.
+ */
+ function wp_restoreRevision( $args ) {
+ if ( ! $this->minimum_args( $args, 3 ) )
+ return $this->error;
+
+ $this->escape( $args );
+
+ $blog_id = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $revision_id = (int) $args[3];
+
+ if ( ! $user = $this->login( $username, $password ) )
+ return $this->error;
+
+ do_action( 'xmlrpc_call', 'wp.restoreRevision' );
+
+ if ( ! $revision = wp_get_post_revision( $revision_id ) )
+ return new IXR_Error( 404, __( 'Invalid post ID' ) );
+
+ if ( wp_is_post_autosave( $revision ) )
+ return new IXR_Error( 404, __( 'Invalid post ID' ) );
+
+ if ( ! $post = get_post( $revision->post_parent ) )
+ return new IXR_Error( 404, __( 'Invalid post ID' ) );
+
+ if ( ! current_user_can( 'edit_post', $revision->post_parent ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
+
+ // Check if revisions are disabled.
+ if ( ! wp_revisions_enabled( $post ) )
+ return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) );
+
+ $post = wp_restore_post_revision( $revision_id );
+
+ return (bool) $post;
+ }
+
+ /* Blogger API functions.
+ * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
+ */
+
+ /**
+ * Retrieve blogs that user owns.
+ *
+ * Will make more sense once we support multiple blogs.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getUsersBlogs($args) {
+ if ( is_multisite() )
+ return $this->_multisite_getUsersBlogs($args);
+
+ $this->escape($args);
+
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'blogger.getUsersBlogs');
+
+ $is_admin = current_user_can('manage_options');
+
+ $struct = array(
+ 'isAdmin' => $is_admin,
+ 'url' => get_option('home') . '/',
+ 'blogid' => '1',
+ 'blogName' => get_option('blogname'),
+ 'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ),
+ );
+
+ return array($struct);
+ }
+
+ /**
+ * Private function for retrieving a users blogs for multisite setups
+ *
+ * @access protected
+ */
+ function _multisite_getUsersBlogs($args) {
+ $current_blog = get_blog_details();
+
+ $domain = $current_blog->domain;
+ $path = $current_blog->path . 'xmlrpc.php';
+
+ $rpc = new IXR_Client( set_url_scheme( "http://{$domain}{$path}" ) );
+ $rpc->query('wp.getUsersBlogs', $args[1], $args[2]);
+ $blogs = $rpc->getResponse();
+
+ if ( isset($blogs['faultCode']) )
+ return new IXR_Error($blogs['faultCode'], $blogs['faultString']);
+
+ if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) {
+ return $blogs;
+ } else {
+ foreach ( (array) $blogs as $blog ) {
+ if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) )
+ return array($blog);
+ }
+ return array();
+ }
+ }
+
+ /**
+ * Retrieve user's data.
+ *
+ * Gives your client some info about you, so you don't have to.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getUserInfo($args) {
+
+ $this->escape($args);
+
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) );
+
+ do_action('xmlrpc_call', 'blogger.getUserInfo');
+
+ $struct = array(
+ 'nickname' => $user->nickname,
+ 'userid' => $user->ID,
+ 'url' => $user->user_url,
+ 'lastname' => $user->last_name,
+ 'firstname' => $user->first_name
+ );
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ $post_data = get_post($post_ID, ARRAY_A);
+ if ( ! $post_data )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( !current_user_can( 'edit_post', $post_ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
+
+ do_action('xmlrpc_call', 'blogger.getPost');
+
+ $categories = implode(',', wp_get_post_categories($post_ID));
+
+ $content = '<title>'.wp_unslash($post_data['post_title']).'</title>';
+ $content .= '<category>'.$categories.'</category>';
+ $content .= wp_unslash($post_data['post_content']);
+
+ $struct = array(
+ 'userid' => $post_data['post_author'],
+ 'dateCreated' => $this->_convert_date( $post_data['post_date'] ),
+ 'content' => $content,
+ 'postid' => (string) $post_data['ID']
+ );
+
+ return $struct;
+ }
+
+ /**
+ * Retrieve list of recent posts.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function blogger_getRecentPosts($args) {
+
+ $this->escape($args);
+
+ // $args[0] = appkey - ignored
+ $blog_ID = (int) $args[1]; /* though we don't use it yet */
+ $username = $args[2];
+ $password = $args[3];
+ if ( isset( $args[4] ) )
+ $query = array( 'numberposts' => absint( $args[4] ) );
+ else
+ $query = array();
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( ! current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) );
+
+ do_action('xmlrpc_call', 'blogger.getRecentPosts');
+
+ $posts_list = wp_get_recent_posts( $query );
+
+ if ( !$posts_list ) {
+ $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
+ return $this->error;
+ }
+
+ foreach ($posts_list as $entry) {
+ if ( !current_user_can( 'edit_post', $entry['ID'] ) )
+ continue;
+
+ $post_date = $this->_convert_date( $entry['post_date'] );
+ $categories = implode(',', wp_get_post_categories($entry['ID']));
+
+ $content = '<title>'.wp_unslash($entry['post_title']).'</title>';
+ $content .= '<category>'.$categories.'</category>';
+ $content .= wp_unslash($entry['post_content']);
+
+ $struct[] = array(
+ 'userid' => $entry['post_author'],
+ 'dateCreated' => $post_date,
+ 'content' => $content,
+ 'postid' => (string) $entry['ID'],
+ );
+
+ }
+
+ $recent_posts = array();
+ for ( $j=0; $j<count($struct); $j++ ) {
+ array_push($recent_posts, $struct[$j]);
+ }
+
+ return $recent_posts;
+ }
+
+ /**
+ * Deprecated.
+ *
+ * @since 1.5.0
+ * @deprecated 3.5.0
+ */
+ function blogger_getTemplate($args) {
+ return new IXR_Error( 403, __('Sorry, that file cannot be edited.' ) );
+ }
+
+ /**
+ * Deprecated.
+ *
+ * @since 1.5.0
+ * @deprecated 3.5.0
+ */
+ function blogger_setTemplate($args) {
+ return new IXR_Error( 403, __('Sorry, that file cannot be edited.' ) );
+ }
+
+ /**
+ * Create new post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return int
+ */
+ function blogger_newPost($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[1]; /* though we don't use it yet */
+ $username = $args[2];
+ $password = $args[3];
+ $content = $args[4];
+ $publish = $args[5];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'blogger.newPost');
+
+ $cap = ($publish) ? 'publish_posts' : 'edit_posts';
+ if ( ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) || !current_user_can($cap) )
+ return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.'));
+
+ $post_status = ($publish) ? 'publish' : 'draft';
+
+ $post_author = $user->ID;
+
+ $post_title = xmlrpc_getposttitle($content);
+ $post_category = xmlrpc_getpostcategory($content);
+ $post_content = xmlrpc_removepostdata($content);
+
+ $post_date = current_time('mysql');
+ $post_date_gmt = current_time('mysql', 1);
+
+ $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
+
+ $post_ID = wp_insert_post($post_data);
+ if ( is_wp_error( $post_ID ) )
+ return new IXR_Error(500, $post_ID->get_error_message());
+
+ if ( !$post_ID )
+ return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
+
+ $this->attach_uploads( $post_ID, $post_content );
+
+ do_action( 'xmlrpc_call_success_blogger_newPost', $post_ID, $args );
+
+ return $post_ID;
+ }
+
+ /**
+ * Edit a post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool true when done.
+ */
+ function blogger_editPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+ $content = $args[4];
+ $publish = $args[5];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'blogger.editPost');
+
+ $actual_post = get_post($post_ID,ARRAY_A);
+
+ if ( !$actual_post || $actual_post['post_type'] != 'post' )
+ return new IXR_Error(404, __('Sorry, no such post.'));
+
+ $this->escape($actual_post);
+
+ if ( !current_user_can('edit_post', $post_ID) )
+ return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
+
+ extract($actual_post, EXTR_SKIP);
+
+ if ( ('publish' == $post_status) && !current_user_can('publish_posts') )
+ return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
+
+ $post_title = xmlrpc_getposttitle($content);
+ $post_category = xmlrpc_getpostcategory($content);
+ $post_content = xmlrpc_removepostdata($content);
+
+ $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
+
+ $result = wp_update_post($postdata);
+
+ if ( !$result )
+ return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
+
+ $this->attach_uploads( $ID, $post_content );
+
+ do_action( 'xmlrpc_call_success_blogger_editPost', $post_ID, $args );
+
+ return true;
+ }
+
+ /**
+ * Remove a post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True when post is deleted.
+ */
+ function blogger_deletePost($args) {
+ $this->escape($args);
+
+ $post_ID = (int) $args[1];
+ $username = $args[2];
+ $password = $args[3];
+ $publish = $args[4];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'blogger.deletePost');
+
+ $actual_post = get_post($post_ID,ARRAY_A);
+
+ if ( !$actual_post || $actual_post['post_type'] != 'post' )
+ return new IXR_Error(404, __('Sorry, no such post.'));
+
+ if ( !current_user_can('delete_post', $post_ID) )
+ return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
+
+ $result = wp_delete_post($post_ID);
+
+ if ( !$result )
+ return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
+
+ do_action( 'xmlrpc_call_success_blogger_deletePost', $post_ID, $args );
+
+ return true;
+ }
+
+ /* MetaWeblog API functions
+ * specs on wherever Dave Winer wants them to be
+ */
+
+ /**
+ * Create a new post.
+ *
+ * The 'content_struct' argument must contain:
+ * - title
+ * - description
+ * - mt_excerpt
+ * - mt_text_more
+ * - mt_keywords
+ * - mt_tb_ping_urls
+ * - categories
+ *
+ * Also, it can optionally contain:
+ * - wp_slug
+ * - wp_password
+ * - wp_page_parent_id
+ * - wp_page_order
+ * - wp_author_id
+ * - post_status | page_status - can be 'draft', 'private', 'publish', or 'pending'
+ * - mt_allow_comments - can be 'open' or 'closed'
+ * - mt_allow_pings - can be 'open' or 'closed'
+ * - date_created_gmt
+ * - dateCreated
+ * - wp_post_thumbnail
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters. Contains:
+ * - blog_id
+ * - username
+ * - password
+ * - content_struct
+ * - publish
+ * @return int
+ */
+ function mw_newPost($args) {
+ $this->escape($args);
+
+ $blog_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $content_struct = $args[3];
+ $publish = isset( $args[4] ) ? $args[4] : 0;
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'metaWeblog.newPost');
+
+ $page_template = '';
+ if ( !empty( $content_struct['post_type'] ) ) {
+ if ( $content_struct['post_type'] == 'page' ) {
+ if ( $publish )
+ $cap = 'publish_pages';
+ elseif ( isset( $content_struct['page_status'] ) && 'publish' == $content_struct['page_status'] )
+ $cap = 'publish_pages';
+ else
+ $cap = 'edit_pages';
+ $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
+ $post_type = 'page';
+ if ( !empty( $content_struct['wp_page_template'] ) )
+ $page_template = $content_struct['wp_page_template'];
+ } elseif ( $content_struct['post_type'] == 'post' ) {
+ if ( $publish )
+ $cap = 'publish_posts';
+ elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'] )
+ $cap = 'publish_posts';
+ else
+ $cap = 'edit_posts';
+ $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
+ $post_type = 'post';
+ } else {
+ // No other post_type values are allowed here
+ return new IXR_Error( 401, __( 'Invalid post type' ) );
+ }
+ } else {
+ if ( $publish )
+ $cap = 'publish_posts';
+ elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'])
+ $cap = 'publish_posts';
+ else
+ $cap = 'edit_posts';
+ $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
+ $post_type = 'post';
+ }
+
+ if ( ! current_user_can( get_post_type_object( $post_type )->cap->create_posts ) )
+ return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts on this site.' ) );
+ if ( !current_user_can( $cap ) )
+ return new IXR_Error( 401, $error_message );
+
+ // Check for a valid post format if one was given
+ if ( isset( $content_struct['wp_post_format'] ) ) {
+ $content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] );
+ if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) {
+ return new IXR_Error( 404, __( 'Invalid post format' ) );
+ }
+ }
+
+ // Let WordPress generate the post_name (slug) unless
+ // one has been provided.
+ $post_name = "";
+ if ( isset($content_struct['wp_slug']) )
+ $post_name = $content_struct['wp_slug'];
+
+ // Only use a password if one was given.
+ if ( isset($content_struct['wp_password']) )
+ $post_password = $content_struct['wp_password'];
+
+ // Only set a post parent if one was provided.
+ if ( isset($content_struct['wp_page_parent_id']) )
+ $post_parent = $content_struct['wp_page_parent_id'];
+
+ // Only set the menu_order if it was provided.
+ if ( isset($content_struct['wp_page_order']) )
+ $menu_order = $content_struct['wp_page_order'];
+
+ $post_author = $user->ID;
+
+ // If an author id was provided then use it instead.
+ if ( isset( $content_struct['wp_author_id'] ) && ( $user->ID != $content_struct['wp_author_id'] ) ) {
+ switch ( $post_type ) {
+ case "post":
+ if ( !current_user_can( 'edit_others_posts' ) )
+ return( new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) ) );
+ break;
+ case "page":
+ if ( !current_user_can( 'edit_others_pages' ) )
+ return( new IXR_Error( 401, __( 'You are not allowed to create pages as this user.' ) ) );
+ break;
+ default:
+ return( new IXR_Error( 401, __( 'Invalid post type' ) ) );
+ break;
+ }
+ $author = get_userdata( $content_struct['wp_author_id'] );
+ if ( ! $author )
+ return new IXR_Error( 404, __( 'Invalid author ID.' ) );
+ $post_author = $content_struct['wp_author_id'];
+ }
+
+ $post_title = isset( $content_struct['title'] ) ? $content_struct['title'] : null;
+ $post_content = isset( $content_struct['description'] ) ? $content_struct['description'] : null;
+
+ $post_status = $publish ? 'publish' : 'draft';
+
+ if ( isset( $content_struct["{$post_type}_status"] ) ) {
+ switch ( $content_struct["{$post_type}_status"] ) {
+ case 'draft':
+ case 'pending':
+ case 'private':
+ case 'publish':
+ $post_status = $content_struct["{$post_type}_status"];
+ break;
+ default:
+ $post_status = $publish ? 'publish' : 'draft';
+ break;
+ }
+ }
+
+ $post_excerpt = isset($content_struct['mt_excerpt']) ? $content_struct['mt_excerpt'] : null;
+ $post_more = isset($content_struct['mt_text_more']) ? $content_struct['mt_text_more'] : null;
+
+ $tags_input = isset($content_struct['mt_keywords']) ? $content_struct['mt_keywords'] : null;
+
+ if ( isset($content_struct['mt_allow_comments']) ) {
+ if ( !is_numeric($content_struct['mt_allow_comments']) ) {
+ switch ( $content_struct['mt_allow_comments'] ) {
+ case 'closed':
+ $comment_status = 'closed';
+ break;
+ case 'open':
+ $comment_status = 'open';
+ break;
+ default:
+ $comment_status = get_option('default_comment_status');
+ break;
+ }
+ } else {
+ switch ( (int) $content_struct['mt_allow_comments'] ) {
+ case 0:
+ case 2:
+ $comment_status = 'closed';
+ break;
+ case 1:
+ $comment_status = 'open';
+ break;
+ default:
+ $comment_status = get_option('default_comment_status');
+ break;
+ }
+ }
+ } else {
+ $comment_status = get_option('default_comment_status');
+ }
+
+ if ( isset($content_struct['mt_allow_pings']) ) {
+ if ( !is_numeric($content_struct['mt_allow_pings']) ) {
+ switch ( $content_struct['mt_allow_pings'] ) {
+ case 'closed':
+ $ping_status = 'closed';
+ break;
+ case 'open':
+ $ping_status = 'open';
+ break;
+ default:
+ $ping_status = get_option('default_ping_status');
+ break;
+ }
+ } else {
+ switch ( (int) $content_struct['mt_allow_pings'] ) {
+ case 0:
+ $ping_status = 'closed';
+ break;
+ case 1:
+ $ping_status = 'open';
+ break;
+ default:
+ $ping_status = get_option('default_ping_status');
+ break;
+ }
+ }
+ } else {
+ $ping_status = get_option('default_ping_status');
+ }
+
+ if ( $post_more )
+ $post_content = $post_content . '<!--more-->' . $post_more;
+
+ $to_ping = null;
+ if ( isset( $content_struct['mt_tb_ping_urls'] ) ) {
+ $to_ping = $content_struct['mt_tb_ping_urls'];
+ if ( is_array($to_ping) )
+ $to_ping = implode(' ', $to_ping);
+ }
+
+ // Do some timestamp voodoo
+ if ( !empty( $content_struct['date_created_gmt'] ) )
+ // We know this is supposed to be GMT, so we're going to slap that Z on there by force
+ $dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
+ elseif ( !empty( $content_struct['dateCreated']) )
+ $dateCreated = $content_struct['dateCreated']->getIso();
+
+ if ( !empty( $dateCreated ) ) {
+ $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
+ $post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
+ } else {
+ $post_date = current_time('mysql');
+ $post_date_gmt = current_time('mysql', 1);
+ }
+
+ $post_category = array();
+ if ( isset( $content_struct['categories'] ) ) {
+ $catnames = $content_struct['categories'];
+
+ if ( is_array($catnames) ) {
+ foreach ($catnames as $cat) {
+ $post_category[] = get_cat_ID($cat);
+ }
+ }
+ }
+
+ $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'to_ping', 'post_type', 'post_name', 'post_password', 'post_parent', 'menu_order', 'tags_input', 'page_template');
+
+ $post_ID = $postdata['ID'] = get_default_post_to_edit( $post_type, true )->ID;
+
+ // Only posts can be sticky
+ if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
+ if ( $content_struct['sticky'] == true )
+ stick_post( $post_ID );
+ elseif ( $content_struct['sticky'] == false )
+ unstick_post( $post_ID );
+ }
+
+ if ( isset($content_struct['custom_fields']) )
+ $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
+
+ if ( isset ( $content_struct['wp_post_thumbnail'] ) ) {
+ if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false )
+ return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
+
+ unset( $content_struct['wp_post_thumbnail'] );
+ }
+
+ // Handle enclosures
+ $thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null;
+ $this->add_enclosure_if_new($post_ID, $thisEnclosure);
+
+ $this->attach_uploads( $post_ID, $post_content );
+
+ // Handle post formats if assigned, value is validated earlier
+ // in this function
+ if ( isset( $content_struct['wp_post_format'] ) )
+ set_post_format( $post_ID, $content_struct['wp_post_format'] );
+
+ $post_ID = wp_insert_post( $postdata, true );
+ if ( is_wp_error( $post_ID ) )
+ return new IXR_Error(500, $post_ID->get_error_message());
+
+ if ( !$post_ID )
+ return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
+
+ do_action( 'xmlrpc_call_success_mw_newPost', $post_ID, $args );
+
+ return strval($post_ID);
+ }
+
+ function add_enclosure_if_new( $post_ID, $enclosure ) {
+ if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) {
+ $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'] . "\n";
+ $found = false;
+ if ( $enclosures = get_post_meta( $post_ID, 'enclosure' ) ) {
+ foreach ( $enclosures as $enc ) {
+ // This method used to omit the trailing new line. #23219
+ if ( rtrim( $enc, "\n" ) == rtrim( $encstring, "\n" ) ) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ if ( ! $found )
+ add_post_meta( $post_ID, 'enclosure', $encstring );
+ }
+ }
+
+ /**
+ * Attach upload to a post.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_ID Post ID.
+ * @param string $post_content Post Content for attachment.
+ */
+ function attach_uploads( $post_ID, $post_content ) {
+ global $wpdb;
+
+ // find any unattached files
+ $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" );
+ if ( is_array( $attachments ) ) {
+ foreach ( $attachments as $file ) {
+ if ( ! empty( $file->guid ) && strpos( $post_content, $file->guid ) !== false )
+ $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) );
+ }
+ }
+ }
+
+ /**
+ * Edit a post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True on success.
+ */
+ function mw_editPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $content_struct = $args[3];
+ $publish = isset( $args[4] ) ? $args[4] : 0;
+
+ if ( ! $user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'metaWeblog.editPost');
+
+ $postdata = get_post( $post_ID, ARRAY_A );
+
+ // If there is no post data for the give post id, stop
+ // now and return an error. Other wise a new post will be
+ // created (which was the old behavior).
+ if ( ! $postdata || empty( $postdata[ 'ID' ] ) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( ! current_user_can( 'edit_post', $post_ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you do not have the right to edit this post.' ) );
+
+ // Use wp.editPost to edit post types other than post and page.
+ if ( ! in_array( $postdata[ 'post_type' ], array( 'post', 'page' ) ) )
+ return new IXR_Error( 401, __( 'Invalid post type' ) );
+
+ // Thwart attempt to change the post type.
+ if ( ! empty( $content_struct[ 'post_type' ] ) && ( $content_struct['post_type'] != $postdata[ 'post_type' ] ) )
+ return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
+
+ // Check for a valid post format if one was given
+ if ( isset( $content_struct['wp_post_format'] ) ) {
+ $content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] );
+ if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) {
+ return new IXR_Error( 404, __( 'Invalid post format' ) );
+ }
+ }
+
+ $this->escape($postdata);
+ extract($postdata, EXTR_SKIP);
+
+ // Let WordPress manage slug if none was provided.
+ $post_name = "";
+ $post_name = $postdata['post_name'];
+ if ( isset($content_struct['wp_slug']) )
+ $post_name = $content_struct['wp_slug'];
+
+ // Only use a password if one was given.
+ if ( isset($content_struct['wp_password']) )
+ $post_password = $content_struct['wp_password'];
+
+ // Only set a post parent if one was given.
+ if ( isset($content_struct['wp_page_parent_id']) )
+ $post_parent = $content_struct['wp_page_parent_id'];
+
+ // Only set the menu_order if it was given.
+ if ( isset($content_struct['wp_page_order']) )
+ $menu_order = $content_struct['wp_page_order'];
+
+ if ( ! empty( $content_struct['wp_page_template'] ) && 'page' == $post_type )
+ $page_template = $content_struct['wp_page_template'];
+
+ $post_author = $postdata['post_author'];
+
+ // Only set the post_author if one is set.
+ if ( isset($content_struct['wp_author_id']) && ($user->ID != $content_struct['wp_author_id']) ) {
+ switch ( $post_type ) {
+ case 'post':
+ if ( !current_user_can('edit_others_posts') )
+ return(new IXR_Error(401, __('You are not allowed to change the post author as this user.')));
+ break;
+ case 'page':
+ if ( !current_user_can('edit_others_pages') )
+ return(new IXR_Error(401, __('You are not allowed to change the page author as this user.')));
+ break;
+ default:
+ return(new IXR_Error(401, __('Invalid post type')));
+ break;
+ }
+ $post_author = $content_struct['wp_author_id'];
+ }
+
+ if ( isset($content_struct['mt_allow_comments']) ) {
+ if ( !is_numeric($content_struct['mt_allow_comments']) ) {
+ switch ( $content_struct['mt_allow_comments'] ) {
+ case 'closed':
+ $comment_status = 'closed';
+ break;
+ case 'open':
+ $comment_status = 'open';
+ break;
+ default:
+ $comment_status = get_option('default_comment_status');
+ break;
+ }
+ } else {
+ switch ( (int) $content_struct['mt_allow_comments'] ) {
+ case 0:
+ case 2:
+ $comment_status = 'closed';
+ break;
+ case 1:
+ $comment_status = 'open';
+ break;
+ default:
+ $comment_status = get_option('default_comment_status');
+ break;
+ }
+ }
+ }
+
+ if ( isset($content_struct['mt_allow_pings']) ) {
+ if ( !is_numeric($content_struct['mt_allow_pings']) ) {
+ switch ( $content_struct['mt_allow_pings'] ) {
+ case 'closed':
+ $ping_status = 'closed';
+ break;
+ case 'open':
+ $ping_status = 'open';
+ break;
+ default:
+ $ping_status = get_option('default_ping_status');
+ break;
+ }
+ } else {
+ switch ( (int) $content_struct["mt_allow_pings"] ) {
+ case 0:
+ $ping_status = 'closed';
+ break;
+ case 1:
+ $ping_status = 'open';
+ break;
+ default:
+ $ping_status = get_option('default_ping_status');
+ break;
+ }
+ }
+ }
+
+ if ( isset( $content_struct['title'] ) )
+ $post_title = $content_struct['title'];
+
+ if ( isset( $content_struct['description'] ) )
+ $post_content = $content_struct['description'];
+
+ $post_category = array();
+ if ( isset( $content_struct['categories'] ) ) {
+ $catnames = $content_struct['categories'];
+ if ( is_array($catnames) ) {
+ foreach ($catnames as $cat) {
+ $post_category[] = get_cat_ID($cat);
+ }
+ }
+ }
+
+ if ( isset( $content_struct['mt_excerpt'] ) )
+ $post_excerpt = $content_struct['mt_excerpt'];
+
+ $post_more = isset( $content_struct['mt_text_more'] ) ? $content_struct['mt_text_more'] : null;
+
+ $post_status = $publish ? 'publish' : 'draft';
+ if ( isset( $content_struct["{$post_type}_status"] ) ) {
+ switch( $content_struct["{$post_type}_status"] ) {
+ case 'draft':
+ case 'pending':
+ case 'private':
+ case 'publish':
+ $post_status = $content_struct["{$post_type}_status"];
+ break;
+ default:
+ $post_status = $publish ? 'publish' : 'draft';
+ break;
+ }
+ }
+
+ $tags_input = isset( $content_struct['mt_keywords'] ) ? $content_struct['mt_keywords'] : null;
+
+ if ( ('publish' == $post_status) ) {
+ if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
+ return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
+ else if ( !current_user_can('publish_posts') )
+ return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
+ }
+
+ if ( $post_more )
+ $post_content = $post_content . "<!--more-->" . $post_more;
+
+ $to_ping = null;
+ if ( isset( $content_struct['mt_tb_ping_urls'] ) ) {
+ $to_ping = $content_struct['mt_tb_ping_urls'];
+ if ( is_array($to_ping) )
+ $to_ping = implode(' ', $to_ping);
+ }
+
+ // Do some timestamp voodoo
+ if ( !empty( $content_struct['date_created_gmt'] ) )
+ // We know this is supposed to be GMT, so we're going to slap that Z on there by force
+ $dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
+ elseif ( !empty( $content_struct['dateCreated']) )
+ $dateCreated = $content_struct['dateCreated']->getIso();
+
+ if ( !empty( $dateCreated ) ) {
+ $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
+ $post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
+ } else {
+ $post_date = $postdata['post_date'];
+ $post_date_gmt = $postdata['post_date_gmt'];
+ }
+
+ // We've got all the data -- post it:
+ $newpost = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'post_date', 'post_date_gmt', 'to_ping', 'post_name', 'post_password', 'post_parent', 'menu_order', 'post_author', 'tags_input', 'page_template');
+
+ $result = wp_update_post($newpost, true);
+ if ( is_wp_error( $result ) )
+ return new IXR_Error(500, $result->get_error_message());
+
+ if ( !$result )
+ return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.'));
+
+ // Only posts can be sticky
+ if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
+ if ( $content_struct['sticky'] == true )
+ stick_post( $post_ID );
+ elseif ( $content_struct['sticky'] == false )
+ unstick_post( $post_ID );
+ }
+
+ if ( isset($content_struct['custom_fields']) )
+ $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
+
+ if ( isset ( $content_struct['wp_post_thumbnail'] ) ) {
+ // empty value deletes, non-empty value adds/updates
+ if ( empty( $content_struct['wp_post_thumbnail'] ) ) {
+ delete_post_thumbnail( $post_ID );
+ } else {
+ if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false )
+ return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
+ }
+ unset( $content_struct['wp_post_thumbnail'] );
+ }
+
+ // Handle enclosures
+ $thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null;
+ $this->add_enclosure_if_new($post_ID, $thisEnclosure);
+
+ $this->attach_uploads( $ID, $post_content );
+
+ // Handle post formats if assigned, validation is handled
+ // earlier in this function
+ if ( isset( $content_struct['wp_post_format'] ) )
+ set_post_format( $post_ID, $content_struct['wp_post_format'] );
+
+ do_action( 'xmlrpc_call_success_mw_editPost', $post_ID, $args );
+
+ return true;
+ }
+
+ /**
+ * Retrieve post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mw_getPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ $postdata = get_post($post_ID, ARRAY_A);
+ if ( ! $postdata )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( !current_user_can( 'edit_post', $post_ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
+
+ do_action('xmlrpc_call', 'metaWeblog.getPost');
+
+ if ($postdata['post_date'] != '') {
+ $post_date = $this->_convert_date( $postdata['post_date'] );
+ $post_date_gmt = $this->_convert_date_gmt( $postdata['post_date_gmt'], $postdata['post_date'] );
+ $post_modified = $this->_convert_date( $postdata['post_modified'] );
+ $post_modified_gmt = $this->_convert_date_gmt( $postdata['post_modified_gmt'], $postdata['post_modified'] );
+
+ $categories = array();
+ $catids = wp_get_post_categories($post_ID);
+ foreach($catids as $catid)
+ $categories[] = get_cat_name($catid);
+
+ $tagnames = array();
+ $tags = wp_get_post_tags( $post_ID );
+ if ( !empty( $tags ) ) {
+ foreach ( $tags as $tag )
+ $tagnames[] = $tag->name;
+ $tagnames = implode( ', ', $tagnames );
+ } else {
+ $tagnames = '';
+ }
+
+ $post = get_extended($postdata['post_content']);
+ $link = post_permalink($postdata['ID']);
+
+ // Get the author info.
+ $author = get_userdata($postdata['post_author']);
+
+ $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
+ $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
+
+ // Consider future posts as published
+ if ( $postdata['post_status'] === 'future' )
+ $postdata['post_status'] = 'publish';
+
+ // Get post format
+ $post_format = get_post_format( $post_ID );
+ if ( empty( $post_format ) )
+ $post_format = 'standard';
+
+ $sticky = false;
+ if ( is_sticky( $post_ID ) )
+ $sticky = true;
+
+ $enclosure = array();
+ foreach ( (array) get_post_custom($post_ID) as $key => $val) {
+ if ($key == 'enclosure') {
+ foreach ( (array) $val as $enc ) {
+ $encdata = explode("\n", $enc);
+ $enclosure['url'] = trim(htmlspecialchars($encdata[0]));
+ $enclosure['length'] = (int) trim($encdata[1]);
+ $enclosure['type'] = trim($encdata[2]);
+ break 2;
+ }
+ }
+ }
+
+ $resp = array(
+ 'dateCreated' => $post_date,
+ 'userid' => $postdata['post_author'],
+ 'postid' => $postdata['ID'],
+ 'description' => $post['main'],
+ 'title' => $postdata['post_title'],
+ 'link' => $link,
+ 'permaLink' => $link,
+ // commented out because no other tool seems to use this
+ // 'content' => $entry['post_content'],
+ 'categories' => $categories,
+ 'mt_excerpt' => $postdata['post_excerpt'],
+ 'mt_text_more' => $post['extended'],
+ 'wp_more_text' => $post['more_text'],
+ 'mt_allow_comments' => $allow_comments,
+ 'mt_allow_pings' => $allow_pings,
+ 'mt_keywords' => $tagnames,
+ 'wp_slug' => $postdata['post_name'],
+ 'wp_password' => $postdata['post_password'],
+ 'wp_author_id' => (string) $author->ID,
+ 'wp_author_display_name' => $author->display_name,
+ 'date_created_gmt' => $post_date_gmt,
+ 'post_status' => $postdata['post_status'],
+ 'custom_fields' => $this->get_custom_fields($post_ID),
+ 'wp_post_format' => $post_format,
+ 'sticky' => $sticky,
+ 'date_modified' => $post_modified,
+ 'date_modified_gmt' => $post_modified_gmt
+ );
+
+ if ( !empty($enclosure) ) $resp['enclosure'] = $enclosure;
+
+ $resp['wp_post_thumbnail'] = get_post_thumbnail_id( $postdata['ID'] );
+
+ return $resp;
+ } else {
+ return new IXR_Error(404, __('Sorry, no such post.'));
+ }
+ }
+
+ /**
+ * Retrieve list of recent posts.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mw_getRecentPosts($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ if ( isset( $args[3] ) )
+ $query = array( 'numberposts' => absint( $args[3] ) );
+ else
+ $query = array();
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( ! current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) );
+
+ do_action('xmlrpc_call', 'metaWeblog.getRecentPosts');
+
+ $posts_list = wp_get_recent_posts( $query );
+
+ if ( !$posts_list )
+ return array();
+
+ $struct = array();
+ foreach ($posts_list as $entry) {
+ if ( !current_user_can( 'edit_post', $entry['ID'] ) )
+ continue;
+
+ $post_date = $this->_convert_date( $entry['post_date'] );
+ $post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] );
+ $post_modified = $this->_convert_date( $entry['post_modified'] );
+ $post_modified_gmt = $this->_convert_date_gmt( $entry['post_modified_gmt'], $entry['post_modified'] );
+
+ $categories = array();
+ $catids = wp_get_post_categories($entry['ID']);
+ foreach( $catids as $catid )
+ $categories[] = get_cat_name($catid);
+
+ $tagnames = array();
+ $tags = wp_get_post_tags( $entry['ID'] );
+ if ( !empty( $tags ) ) {
+ foreach ( $tags as $tag ) {
+ $tagnames[] = $tag->name;
+ }
+ $tagnames = implode( ', ', $tagnames );
+ } else {
+ $tagnames = '';
+ }
+
+ $post = get_extended($entry['post_content']);
+ $link = post_permalink($entry['ID']);
+
+ // Get the post author info.
+ $author = get_userdata($entry['post_author']);
+
+ $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
+ $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
+
+ // Consider future posts as published
+ if ( $entry['post_status'] === 'future' )
+ $entry['post_status'] = 'publish';
+
+ // Get post format
+ $post_format = get_post_format( $entry['ID'] );
+ if ( empty( $post_format ) )
+ $post_format = 'standard';
+
+ $struct[] = array(
+ 'dateCreated' => $post_date,
+ 'userid' => $entry['post_author'],
+ 'postid' => (string) $entry['ID'],
+ 'description' => $post['main'],
+ 'title' => $entry['post_title'],
+ 'link' => $link,
+ 'permaLink' => $link,
+ // commented out because no other tool seems to use this
+ // 'content' => $entry['post_content'],
+ 'categories' => $categories,
+ 'mt_excerpt' => $entry['post_excerpt'],
+ 'mt_text_more' => $post['extended'],
+ 'wp_more_text' => $post['more_text'],
+ 'mt_allow_comments' => $allow_comments,
+ 'mt_allow_pings' => $allow_pings,
+ 'mt_keywords' => $tagnames,
+ 'wp_slug' => $entry['post_name'],
+ 'wp_password' => $entry['post_password'],
+ 'wp_author_id' => (string) $author->ID,
+ 'wp_author_display_name' => $author->display_name,
+ 'date_created_gmt' => $post_date_gmt,
+ 'post_status' => $entry['post_status'],
+ 'custom_fields' => $this->get_custom_fields($entry['ID']),
+ 'wp_post_format' => $post_format,
+ 'date_modified' => $post_modified,
+ 'date_modified_gmt' => $post_modified_gmt
+ );
+
+ $entry_index = count( $struct ) - 1;
+ $struct[ $entry_index ][ 'wp_post_thumbnail' ] = get_post_thumbnail_id( $entry['ID'] );
+ }
+
+ $recent_posts = array();
+ for ( $j=0; $j<count($struct); $j++ ) {
+ array_push($recent_posts, $struct[$j]);
+ }
+
+ return $recent_posts;
+ }
+
+ /**
+ * Retrieve the list of categories on a given blog.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mw_getCategories($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
+
+ do_action('xmlrpc_call', 'metaWeblog.getCategories');
+
+ $categories_struct = array();
+
+ if ( $cats = get_categories(array('get' => 'all')) ) {
+ foreach ( $cats as $cat ) {
+ $struct['categoryId'] = $cat->term_id;
+ $struct['parentId'] = $cat->parent;
+ $struct['description'] = $cat->name;
+ $struct['categoryDescription'] = $cat->description;
+ $struct['categoryName'] = $cat->name;
+ $struct['htmlUrl'] = esc_html(get_category_link($cat->term_id));
+ $struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2'));
+
+ $categories_struct[] = $struct;
+ }
+ }
+
+ return $categories_struct;
+ }
+
+ /**
+ * Uploads a file, following your settings.
+ *
+ * Adapted from a patch by Johann Richard.
+ *
+ * @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mw_newMediaObject($args) {
+ global $wpdb;
+
+ $blog_ID = (int) $args[0];
+ $username = $this->escape($args[1]);
+ $password = $this->escape($args[2]);
+ $data = $args[3];
+
+ $name = sanitize_file_name( $data['name'] );
+ $type = $data['type'];
+ $bits = $data['bits'];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'metaWeblog.newMediaObject');
+
+ if ( !current_user_can('upload_files') ) {
+ $this->error = new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
+ return $this->error;
+ }
+
+ if ( $upload_err = apply_filters( 'pre_upload_error', false ) )
+ return new IXR_Error(500, $upload_err);
+
+ if ( !empty($data['overwrite']) && ($data['overwrite'] == true) ) {
+ // Get postmeta info on the object.
+ $old_file = $wpdb->get_row("
+ SELECT ID
+ FROM {$wpdb->posts}
+ WHERE post_title = '{$name}'
+ AND post_type = 'attachment'
+ ");
+
+ // Delete previous file.
+ wp_delete_attachment($old_file->ID);
+
+ // Make sure the new name is different by pre-pending the
+ // previous post id.
+ $filename = preg_replace('/^wpid\d+-/', '', $name);
+ $name = "wpid{$old_file->ID}-{$filename}";
+ }
+
+ $upload = wp_upload_bits($name, null, $bits);
+ if ( ! empty($upload['error']) ) {
+ $errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
+ return new IXR_Error(500, $errorString);
+ }
+ // Construct the attachment array
+ $post_id = 0;
+ if ( ! empty( $data['post_id'] ) ) {
+ $post_id = (int) $data['post_id'];
+
+ if ( ! current_user_can( 'edit_post', $post_id ) )
+ return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
+ }
+ $attachment = array(
+ 'post_title' => $name,
+ 'post_content' => '',
+ 'post_type' => 'attachment',
+ 'post_parent' => $post_id,
+ 'post_mime_type' => $type,
+ 'guid' => $upload[ 'url' ]
+ );
+
+ // Save the data
+ $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
+ wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
+
+ do_action( 'xmlrpc_call_success_mw_newMediaObject', $id, $args );
+
+ $struct = array(
+ 'id' => strval( $id ),
+ 'file' => $name,
+ 'url' => $upload[ 'url' ],
+ 'type' => $type
+ );
+ return apply_filters( 'wp_handle_upload', $struct, 'upload' );
+ }
+
+ /* MovableType API functions
+ * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
+ */
+
+ /**
+ * Retrieve the post titles of recent posts.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mt_getRecentPostTitles($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ if ( isset( $args[3] ) )
+ $query = array( 'numberposts' => absint( $args[3] ) );
+ else
+ $query = array();
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'mt.getRecentPostTitles');
+
+ $posts_list = wp_get_recent_posts( $query );
+
+ if ( !$posts_list ) {
+ $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
+ return $this->error;
+ }
+
+ $struct = array();
+
+ foreach ($posts_list as $entry) {
+ if ( !current_user_can( 'edit_post', $entry['ID'] ) )
+ continue;
+
+ $post_date = $this->_convert_date( $entry['post_date'] );
+ $post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] );
+
+ $struct[] = array(
+ 'dateCreated' => $post_date,
+ 'userid' => $entry['post_author'],
+ 'postid' => (string) $entry['ID'],
+ 'title' => $entry['post_title'],
+ 'post_status' => $entry['post_status'],
+ 'date_created_gmt' => $post_date_gmt
+ );
+
+ }
+
+ $recent_posts = array();
+ for ( $j=0; $j<count($struct); $j++ ) {
+ array_push($recent_posts, $struct[$j]);
+ }
+
+ return $recent_posts;
+ }
+
+ /**
+ * Retrieve list of all categories on blog.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mt_getCategoryList($args) {
+
+ $this->escape($args);
+
+ $blog_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( !current_user_can( 'edit_posts' ) )
+ return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
+
+ do_action('xmlrpc_call', 'mt.getCategoryList');
+
+ $categories_struct = array();
+
+ if ( $cats = get_categories(array('hide_empty' => 0, 'hierarchical' => 0)) ) {
+ foreach ( $cats as $cat ) {
+ $struct['categoryId'] = $cat->term_id;
+ $struct['categoryName'] = $cat->name;
+
+ $categories_struct[] = $struct;
+ }
+ }
+
+ return $categories_struct;
+ }
+
+ /**
+ * Retrieve post categories.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mt_getPostCategories($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ if ( ! get_post( $post_ID ) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( !current_user_can( 'edit_post', $post_ID ) )
+ return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
+
+ do_action('xmlrpc_call', 'mt.getPostCategories');
+
+ $categories = array();
+ $catids = wp_get_post_categories(intval($post_ID));
+ // first listed category will be the primary category
+ $isPrimary = true;
+ foreach ( $catids as $catid ) {
+ $categories[] = array(
+ 'categoryName' => get_cat_name($catid),
+ 'categoryId' => (string) $catid,
+ 'isPrimary' => $isPrimary
+ );
+ $isPrimary = false;
+ }
+
+ return $categories;
+ }
+
+ /**
+ * Sets categories for a post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return bool True on success.
+ */
+ function mt_setPostCategories($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+ $categories = $args[3];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'mt.setPostCategories');
+
+ if ( ! get_post( $post_ID ) )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( !current_user_can('edit_post', $post_ID) )
+ return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
+
+ $catids = array();
+ foreach ( $categories as $cat ) {
+ $catids[] = $cat['categoryId'];
+ }
+
+ wp_set_post_categories($post_ID, $catids);
+
+ return true;
+ }
+
+ /**
+ * Retrieve an array of methods supported by this server.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function mt_supportedMethods($args) {
+
+ do_action('xmlrpc_call', 'mt.supportedMethods');
+
+ $supported_methods = array();
+ foreach ( $this->methods as $key => $value ) {
+ $supported_methods[] = $key;
+ }
+
+ return $supported_methods;
+ }
+
+ /**
+ * Retrieve an empty array because we don't support per-post text filters.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ */
+ function mt_supportedTextFilters($args) {
+ do_action('xmlrpc_call', 'mt.supportedTextFilters');
+ return apply_filters('xmlrpc_text_filters', array());
+ }
+
+ /**
+ * Retrieve trackbacks sent to a given post.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return mixed
+ */
+ function mt_getTrackbackPings($args) {
+
+ global $wpdb;
+
+ $post_ID = intval($args);
+
+ do_action('xmlrpc_call', 'mt.getTrackbackPings');
+
+ $actual_post = get_post($post_ID, ARRAY_A);
+
+ if ( !$actual_post )
+ return new IXR_Error(404, __('Sorry, no such post.'));
+
+ $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
+
+ if ( !$comments )
+ return array();
+
+ $trackback_pings = array();
+ foreach ( $comments as $comment ) {
+ if ( 'trackback' == $comment->comment_type ) {
+ $content = $comment->comment_content;
+ $title = substr($content, 8, (strpos($content, '</strong>') - 8));
+ $trackback_pings[] = array(
+ 'pingTitle' => $title,
+ 'pingURL' => $comment->comment_author_url,
+ 'pingIP' => $comment->comment_author_IP
+ );
+ }
+ }
+
+ return $trackback_pings;
+ }
+
+ /**
+ * Sets a post's publish status to 'publish'.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return int
+ */
+ function mt_publishPost($args) {
+
+ $this->escape($args);
+
+ $post_ID = (int) $args[0];
+ $username = $args[1];
+ $password = $args[2];
+
+ if ( !$user = $this->login($username, $password) )
+ return $this->error;
+
+ do_action('xmlrpc_call', 'mt.publishPost');
+
+ $postdata = get_post($post_ID, ARRAY_A);
+ if ( ! $postdata )
+ return new IXR_Error( 404, __( 'Invalid post ID.' ) );
+
+ if ( !current_user_can('publish_posts') || !current_user_can('edit_post', $post_ID) )
+ return new IXR_Error(401, __('Sorry, you cannot publish this post.'));
+
+ $postdata['post_status'] = 'publish';
+
+ // retain old cats
+ $cats = wp_get_post_categories($post_ID);
+ $postdata['post_category'] = $cats;
+ $this->escape($postdata);
+
+ $result = wp_update_post($postdata);
+
+ return $result;
+ }
+
+ /* PingBack functions
+ * specs on www.hixie.ch/specs/pingback/pingback
+ */
+
+ /**
+ * Retrieves a pingback and registers it.
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function pingback_ping($args) {
+ global $wpdb;
+
+ do_action('xmlrpc_call', 'pingback.ping');
+
+ $this->escape($args);
+
+ $pagelinkedfrom = $args[0];
+ $pagelinkedto = $args[1];
+
+ $title = '';
+
+ $pagelinkedfrom = str_replace('&amp;', '&', $pagelinkedfrom);
+ $pagelinkedto = str_replace('&amp;', '&', $pagelinkedto);
+ $pagelinkedto = str_replace('&', '&amp;', $pagelinkedto);
+
+ $pagelinkedfrom = apply_filters( 'pingback_ping_source_uri', $pagelinkedfrom, $pagelinkedto );
+ if ( ! $pagelinkedfrom )
+ return $this->pingback_error( 0, __( 'A valid URL was not provided.' ) );
+
+ // Check if the page linked to is in our site
+ $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
+ if ( !$pos1 )
+ return $this->pingback_error( 0, __( 'Is there no link to us?' ) );
+
+ // let's find which post is linked to
+ // FIXME: does url_to_postid() cover all these cases already?
+ // if so, then let's use it and drop the old code.
+ $urltest = parse_url($pagelinkedto);
+ if ( $post_ID = url_to_postid($pagelinkedto) ) {
+ $way = 'url_to_postid()';
+ } elseif ( preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
+ // the path defines the post_ID (archives/p/XXXX)
+ $blah = explode('/', $match[0]);
+ $post_ID = (int) $blah[1];
+ $way = 'from the path';
+ } elseif ( isset( $urltest['query'] ) && preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
+ // the querystring defines the post_ID (?p=XXXX)
+ $blah = explode('=', $match[0]);
+ $post_ID = (int) $blah[1];
+ $way = 'from the querystring';
+ } elseif ( isset($urltest['fragment']) ) {
+ // an #anchor is there, it's either...
+ if ( intval($urltest['fragment']) ) {
+ // ...an integer #XXXX (simplest case)
+ $post_ID = (int) $urltest['fragment'];
+ $way = 'from the fragment (numeric)';
+ } elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
+ // ...a post id in the form 'post-###'
+ $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
+ $way = 'from the fragment (post-###)';
+ } elseif ( is_string($urltest['fragment']) ) {
+ // ...or a string #title, a little more complicated
+ $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
+ $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", like_escape( $title ) );
+ if (! ($post_ID = $wpdb->get_var($sql)) ) {
+ // returning unknown error '0' is better than die()ing
+ return $this->pingback_error( 0, '' );
+ }
+ $way = 'from the fragment (title)';
+ }
+ } else {
+ // TODO: Attempt to extract a post ID from the given URL
+ return $this->pingback_error( 33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.' ) );
+ }
+ $post_ID = (int) $post_ID;
+
+ $post = get_post($post_ID);
+
+ if ( !$post ) // Post_ID not found
+ return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.' ) );
+
+ if ( $post_ID == url_to_postid($pagelinkedfrom) )
+ return $this->pingback_error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) );
+
+ // Check if pings are on
+ if ( !pings_open($post) )
+ return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.' ) );
+
+ // Let's check that the remote site didn't already pingback this entry
+ if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
+ return $this->pingback_error( 48, __( 'The pingback has already been registered.' ) );
+
+ // very stupid, but gives time to the 'from' server to publish !
+ sleep(1);
+
+ // Let's check the remote site
+ $http_api_args = array(
+ 'timeout' => 10,
+ 'redirection' => 0,
+ 'limit_response_size' => 153600, // 150 KB
+ );
+ $linea = wp_remote_retrieve_body( wp_safe_remote_get( $pagelinkedfrom, $http_api_args ) );
+
+ if ( !$linea )
+ return $this->pingback_error( 16, __( 'The source URL does not exist.' ) );
+
+ $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto);
+
+ // Work around bug in strip_tags():
+ $linea = str_replace('<!DOC', '<DOC', $linea);
+ $linea = preg_replace( '/[\r\n\t ]+/', ' ', $linea ); // normalize spaces
+ $linea = preg_replace( "/<\/*(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
+
+ preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
+ $title = $matchtitle[1];
+ if ( empty( $title ) )
+ return $this->pingback_error( 32, __('We cannot find a title on that page.' ) );
+
+ $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
+
+ $p = explode( "\n\n", $linea );
+
+ $preg_target = preg_quote($pagelinkedto, '|');
+
+ foreach ( $p as $para ) {
+ if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
+ preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
+
+ // If the URL isn't in a link context, keep looking
+ if ( empty($context) )
+ continue;
+
+ // We're going to use this fake tag to mark the context in a bit
+ // the marker is needed in case the link text appears more than once in the paragraph
+ $excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
+
+ // prevent really long link text
+ if ( strlen($context[1]) > 100 )
+ $context[1] = substr($context[1], 0, 100) . '&#8230;';
+
+ $marker = '<wpcontext>'.$context[1].'</wpcontext>'; // set up our marker
+ $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
+ $excerpt = strip_tags($excerpt, '<wpcontext>'); // strip all tags but our context marker
+ $excerpt = trim($excerpt);
+ $preg_marker = preg_quote($marker, '|');
+ $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
+ $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
+ break;
+ }
+ }
+
+ if ( empty($context) ) // Link to target not found
+ return $this->pingback_error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) );
+
+ $pagelinkedfrom = str_replace('&', '&amp;', $pagelinkedfrom);
+
+ $context = '[&#8230;] ' . esc_html( $excerpt ) . ' [&#8230;]';
+ $pagelinkedfrom = $this->escape( $pagelinkedfrom );
+
+ $comment_post_ID = (int) $post_ID;
+ $comment_author = $title;
+ $comment_author_email = '';
+ $this->escape($comment_author);
+ $comment_author_url = $pagelinkedfrom;
+ $comment_content = $context;
+ $this->escape($comment_content);
+ $comment_type = 'pingback';
+
+ $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_author_email', 'comment_content', 'comment_type');
+
+ $comment_ID = wp_new_comment($commentdata);
+ do_action('pingback_post', $comment_ID);
+
+ return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto);
+ }
+
+ /**
+ * Retrieve array of URLs that pingbacked the given URL.
+ *
+ * Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html
+ *
+ * @since 1.5.0
+ *
+ * @param array $args Method parameters.
+ * @return array
+ */
+ function pingback_extensions_getPingbacks($args) {
+
+ global $wpdb;
+
+ do_action('xmlrpc_call', 'pingback.extensions.getPingbacks');
+
+ $this->escape($args);
+
+ $url = $args;
+
+ $post_ID = url_to_postid($url);
+ if ( !$post_ID ) {
+ // We aren't sure that the resource is available and/or pingback enabled
+ return $this->pingback_error( 33, __( 'The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.' ) );
+ }
+
+ $actual_post = get_post($post_ID, ARRAY_A);
+
+ if ( !$actual_post ) {
+ // No such post = resource not found
+ return $this->pingback_error( 32, __('The specified target URL does not exist.' ) );
+ }
+
+ $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
+
+ if ( !$comments )
+ return array();
+
+ $pingbacks = array();
+ foreach ( $comments as $comment ) {
+ if ( 'pingback' == $comment->comment_type )
+ $pingbacks[] = $comment->comment_author_url;
+ }
+
+ return $pingbacks;
+ }
+
+ protected function pingback_error( $code, $message ) {
+ return apply_filters( 'xmlrpc_pingback_error', new IXR_Error( $code, $message ) );
+ }
+}
diff --git a/src/wp-includes/class-wp.php b/src/wp-includes/class-wp.php
new file mode 100644
index 0000000000..dc77688650
--- /dev/null
+++ b/src/wp-includes/class-wp.php
@@ -0,0 +1,645 @@
+<?php
+/**
+ * WordPress environment setup class.
+ *
+ * @package WordPress
+ * @since 2.0.0
+ */
+class WP {
+ /**
+ * Public query variables.
+ *
+ * Long list of public query variables.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var array
+ */
+ var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type');
+
+ /**
+ * Private query variables.
+ *
+ * Long list of private query variables.
+ *
+ * @since 2.0.0
+ * @var array
+ */
+ var $private_query_vars = array( 'offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in', 'post_parent__in', 'post_parent__not_in' );
+
+ /**
+ * Extra query variables set by the user.
+ *
+ * @since 2.1.0
+ * @var array
+ */
+ var $extra_query_vars = array();
+
+ /**
+ * Query variables for setting up the WordPress Query Loop.
+ *
+ * @since 2.0.0
+ * @var array
+ */
+ var $query_vars;
+
+ /**
+ * String parsed to set the query variables.
+ *
+ * @since 2.0.0
+ * @var string
+ */
+ var $query_string;
+
+ /**
+ * Permalink or requested URI.
+ *
+ * @since 2.0.0
+ * @var string
+ */
+ var $request;
+
+ /**
+ * Rewrite rule the request matched.
+ *
+ * @since 2.0.0
+ * @var string
+ */
+ var $matched_rule;
+
+ /**
+ * Rewrite query the request matched.
+ *
+ * @since 2.0.0
+ * @var string
+ */
+ var $matched_query;
+
+ /**
+ * Whether already did the permalink.
+ *
+ * @since 2.0.0
+ * @var bool
+ */
+ var $did_permalink = false;
+
+ /**
+ * Add name to list of public query variables.
+ *
+ * @since 2.1.0
+ *
+ * @param string $qv Query variable name.
+ */
+ function add_query_var($qv) {
+ if ( !in_array($qv, $this->public_query_vars) )
+ $this->public_query_vars[] = $qv;
+ }
+
+ /**
+ * Set the value of a query variable.
+ *
+ * @since 2.3.0
+ *
+ * @param string $key Query variable name.
+ * @param mixed $value Query variable value.
+ */
+ function set_query_var($key, $value) {
+ $this->query_vars[$key] = $value;
+ }
+
+ /**
+ * Parse request to find correct WordPress query.
+ *
+ * Sets up the query variables based on the request. There are also many
+ * filters and actions that can be used to further manipulate the result.
+ *
+ * @since 2.0.0
+ *
+ * @param array|string $extra_query_vars Set the extra query variables.
+ */
+ function parse_request($extra_query_vars = '') {
+ global $wp_rewrite;
+
+ if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) )
+ return;
+
+ $this->query_vars = array();
+ $post_type_query_vars = array();
+
+ if ( is_array($extra_query_vars) )
+ $this->extra_query_vars = & $extra_query_vars;
+ else if (! empty($extra_query_vars))
+ parse_str($extra_query_vars, $this->extra_query_vars);
+
+ // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
+
+ // Fetch the rewrite rules.
+ $rewrite = $wp_rewrite->wp_rewrite_rules();
+
+ if ( ! empty($rewrite) ) {
+ // If we match a rewrite rule, this will be cleared.
+ $error = '404';
+ $this->did_permalink = true;
+
+ if ( isset($_SERVER['PATH_INFO']) )
+ $pathinfo = $_SERVER['PATH_INFO'];
+ else
+ $pathinfo = '';
+ $pathinfo_array = explode('?', $pathinfo);
+ $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
+ $req_uri = $_SERVER['REQUEST_URI'];
+ $req_uri_array = explode('?', $req_uri);
+ $req_uri = $req_uri_array[0];
+ $self = $_SERVER['PHP_SELF'];
+ $home_path = parse_url(home_url());
+ if ( isset($home_path['path']) )
+ $home_path = $home_path['path'];
+ else
+ $home_path = '';
+ $home_path = trim($home_path, '/');
+
+ // Trim path info from the end and the leading home path from the
+ // front. For path info requests, this leaves us with the requesting
+ // filename, if any. For 404 requests, this leaves us with the
+ // requested permalink.
+ $req_uri = str_replace($pathinfo, '', $req_uri);
+ $req_uri = trim($req_uri, '/');
+ $req_uri = preg_replace("|^$home_path|i", '', $req_uri);
+ $req_uri = trim($req_uri, '/');
+ $pathinfo = trim($pathinfo, '/');
+ $pathinfo = preg_replace("|^$home_path|i", '', $pathinfo);
+ $pathinfo = trim($pathinfo, '/');
+ $self = trim($self, '/');
+ $self = preg_replace("|^$home_path|i", '', $self);
+ $self = trim($self, '/');
+
+ // The requested permalink is in $pathinfo for path info requests and
+ // $req_uri for other requests.
+ if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
+ $request = $pathinfo;
+ } else {
+ // If the request uri is the index, blank it out so that we don't try to match it against a rule.
+ if ( $req_uri == $wp_rewrite->index )
+ $req_uri = '';
+ $request = $req_uri;
+ }
+
+ $this->request = $request;
+
+ // Look for matches.
+ $request_match = $request;
+ if ( empty( $request_match ) ) {
+ // An empty request could only match against ^$ regex
+ if ( isset( $rewrite['$'] ) ) {
+ $this->matched_rule = '$';
+ $query = $rewrite['$'];
+ $matches = array('');
+ }
+ } else {
+ foreach ( (array) $rewrite as $match => $query ) {
+ // If the requesting file is the anchor of the match, prepend it to the path info.
+ if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request )
+ $request_match = $req_uri . '/' . $request;
+
+ if ( preg_match("#^$match#", $request_match, $matches) ||
+ preg_match("#^$match#", urldecode($request_match), $matches) ) {
+
+ if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
+ // this is a verbose page match, lets check to be sure about it
+ if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
+ continue;
+ }
+
+ // Got a match.
+ $this->matched_rule = $match;
+ break;
+ }
+ }
+ }
+
+ if ( isset( $this->matched_rule ) ) {
+ // Trim the query of everything up to the '?'.
+ $query = preg_replace("!^.+\?!", '', $query);
+
+ // Substitute the substring matches into the query.
+ $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
+
+ $this->matched_query = $query;
+
+ // Parse the query.
+ parse_str($query, $perma_query_vars);
+
+ // If we're processing a 404 request, clear the error var since we found something.
+ if ( '404' == $error )
+ unset( $error, $_GET['error'] );
+ }
+
+ // If req_uri is empty or if it is a request for ourself, unset error.
+ if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
+ unset( $error, $_GET['error'] );
+
+ if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
+ unset( $perma_query_vars );
+
+ $this->did_permalink = false;
+ }
+ }
+
+ $this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
+
+ foreach ( $GLOBALS['wp_post_types'] as $post_type => $t )
+ if ( $t->query_var )
+ $post_type_query_vars[$t->query_var] = $post_type;
+
+ foreach ( $this->public_query_vars as $wpvar ) {
+ if ( isset( $this->extra_query_vars[$wpvar] ) )
+ $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
+ elseif ( isset( $_POST[$wpvar] ) )
+ $this->query_vars[$wpvar] = $_POST[$wpvar];
+ elseif ( isset( $_GET[$wpvar] ) )
+ $this->query_vars[$wpvar] = $_GET[$wpvar];
+ elseif ( isset( $perma_query_vars[$wpvar] ) )
+ $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
+
+ if ( !empty( $this->query_vars[$wpvar] ) ) {
+ if ( ! is_array( $this->query_vars[$wpvar] ) ) {
+ $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
+ } else {
+ foreach ( $this->query_vars[$wpvar] as $vkey => $v ) {
+ if ( !is_object( $v ) ) {
+ $this->query_vars[$wpvar][$vkey] = (string) $v;
+ }
+ }
+ }
+
+ if ( isset($post_type_query_vars[$wpvar] ) ) {
+ $this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
+ $this->query_vars['name'] = $this->query_vars[$wpvar];
+ }
+ }
+ }
+
+ // Convert urldecoded spaces back into +
+ foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
+ if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
+ $this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );
+
+ // Limit publicly queried post_types to those that are publicly_queryable
+ if ( isset( $this->query_vars['post_type']) ) {
+ $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
+ if ( ! is_array( $this->query_vars['post_type'] ) ) {
+ if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
+ unset( $this->query_vars['post_type'] );
+ } else {
+ $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
+ }
+ }
+
+ foreach ( (array) $this->private_query_vars as $var) {
+ if ( isset($this->extra_query_vars[$var]) )
+ $this->query_vars[$var] = $this->extra_query_vars[$var];
+ }
+
+ if ( isset($error) )
+ $this->query_vars['error'] = $error;
+
+ $this->query_vars = apply_filters('request', $this->query_vars);
+
+ do_action_ref_array('parse_request', array(&$this));
+ }
+
+ /**
+ * Send additional HTTP headers for caching, content type, etc.
+ *
+ * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
+ * a feed, it will also send last-modified, etag, and 304 status if needed.
+ *
+ * @since 2.0.0
+ */
+ function send_headers() {
+ $headers = array('X-Pingback' => get_bloginfo('pingback_url'));
+ $status = null;
+ $exit_required = false;
+
+ if ( is_user_logged_in() )
+ $headers = array_merge($headers, wp_get_nocache_headers());
+ if ( ! empty( $this->query_vars['error'] ) ) {
+ $status = (int) $this->query_vars['error'];
+ if ( 404 === $status ) {
+ if ( ! is_user_logged_in() )
+ $headers = array_merge($headers, wp_get_nocache_headers());
+ $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
+ } elseif ( in_array( $status, array( 403, 500, 502, 503 ) ) ) {
+ $exit_required = true;
+ }
+ } else if ( empty($this->query_vars['feed']) ) {
+ $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
+ } else {
+ // We're showing a feed, so WP is indeed the only thing that last changed
+ if ( !empty($this->query_vars['withcomments'])
+ || ( empty($this->query_vars['withoutcomments'])
+ && ( !empty($this->query_vars['p'])
+ || !empty($this->query_vars['name'])
+ || !empty($this->query_vars['page_id'])
+ || !empty($this->query_vars['pagename'])
+ || !empty($this->query_vars['attachment'])
+ || !empty($this->query_vars['attachment_id'])
+ )
+ )
+ )
+ $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
+ else
+ $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
+ $wp_etag = '"' . md5($wp_last_modified) . '"';
+ $headers['Last-Modified'] = $wp_last_modified;
+ $headers['ETag'] = $wp_etag;
+
+ // Support for Conditional GET
+ if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
+ $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
+ else $client_etag = false;
+
+ $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
+ // If string is empty, return 0. If not, attempt to parse into a timestamp
+ $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
+
+ // Make a timestamp for our most recent modification...
+ $wp_modified_timestamp = strtotime($wp_last_modified);
+
+ if ( ($client_last_modified && $client_etag) ?
+ (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
+ (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
+ $status = 304;
+ $exit_required = true;
+ }
+ }
+
+ $headers = apply_filters('wp_headers', $headers, $this);
+
+ if ( ! empty( $status ) )
+ status_header( $status );
+
+ // If Last-Modified is set to false, it should not be sent (no-cache situation).
+ if ( isset( $headers['Last-Modified'] ) && false === $headers['Last-Modified'] ) {
+ unset( $headers['Last-Modified'] );
+
+ // In PHP 5.3+, make sure we are not sending a Last-Modified header.
+ if ( function_exists( 'header_remove' ) ) {
+ @header_remove( 'Last-Modified' );
+ } else {
+ // In PHP 5.2, send an empty Last-Modified header, but only as a
+ // last resort to override a header already sent. #WP23021
+ foreach ( headers_list() as $header ) {
+ if ( 0 === stripos( $header, 'Last-Modified' ) ) {
+ $headers['Last-Modified'] = '';
+ break;
+ }
+ }
+ }
+ }
+
+ foreach( (array) $headers as $name => $field_value )
+ @header("{$name}: {$field_value}");
+
+ if ( $exit_required )
+ exit();
+
+ do_action_ref_array('send_headers', array(&$this));
+ }
+
+ /**
+ * Sets the query string property based off of the query variable property.
+ *
+ * The 'query_string' filter is deprecated, but still works. Plugins should
+ * use the 'request' filter instead.
+ *
+ * @since 2.0.0
+ */
+ function build_query_string() {
+ $this->query_string = '';
+ foreach ( (array) array_keys($this->query_vars) as $wpvar) {
+ if ( '' != $this->query_vars[$wpvar] ) {
+ $this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
+ if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
+ continue;
+ $this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
+ }
+ }
+
+ // query_string filter deprecated. Use request filter instead.
+ if ( has_filter('query_string') ) { // Don't bother filtering and parsing if no plugins are hooked in.
+ $this->query_string = apply_filters('query_string', $this->query_string);
+ parse_str($this->query_string, $this->query_vars);
+ }
+ }
+
+ /**
+ * Set up the WordPress Globals.
+ *
+ * The query_vars property will be extracted to the GLOBALS. So care should
+ * be taken when naming global variables that might interfere with the
+ * WordPress environment.
+ *
+ * @global string $query_string Query string for the loop.
+ * @global int $more Only set, if single page or post.
+ * @global int $single If single page or post. Only set, if single page or post.
+ *
+ * @since 2.0.0
+ */
+ function register_globals() {
+ global $wp_query;
+ // Extract updated query vars back into global namespace.
+ foreach ( (array) $wp_query->query_vars as $key => $value) {
+ $GLOBALS[$key] = $value;
+ }
+
+ $GLOBALS['query_string'] = $this->query_string;
+ $GLOBALS['posts'] = & $wp_query->posts;
+ $GLOBALS['post'] = (isset($wp_query->post)) ? $wp_query->post : null;
+ $GLOBALS['request'] = $wp_query->request;
+
+ if ( is_single() || is_page() ) {
+ $GLOBALS['more'] = 1;
+ $GLOBALS['single'] = 1;
+ }
+ }
+
+ /**
+ * Set up the current user.
+ *
+ * @since 2.0.0
+ */
+ function init() {
+ wp_get_current_user();
+ }
+
+ /**
+ * Set up the Loop based on the query variables.
+ *
+ * @uses WP::$query_vars
+ * @since 2.0.0
+ */
+ function query_posts() {
+ global $wp_the_query;
+ $this->build_query_string();
+ $wp_the_query->query($this->query_vars);
+ }
+
+ /**
+ * Set the Headers for 404, if nothing is found for requested URL.
+ *
+ * Issue a 404 if a request doesn't match any posts and doesn't match
+ * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
+ * issued, and if the request was not a search or the homepage.
+ *
+ * Otherwise, issue a 200.
+ *
+ * @since 2.0.0
+ */
+ function handle_404() {
+ global $wp_query;
+
+ // If we've already issued a 404, bail.
+ if ( is_404() )
+ return;
+
+ // Never 404 for the admin, robots, or if we found posts.
+ if ( is_admin() || is_robots() || $wp_query->posts ) {
+ status_header( 200 );
+ return;
+ }
+
+ // We will 404 for paged queries, as no posts were found.
+ if ( ! is_paged() ) {
+
+ // Don't 404 for these queries if they matched an object.
+ if ( ( is_tag() || is_category() || is_tax() || is_author() || is_post_type_archive() ) && $wp_query->get_queried_object() ) {
+ status_header( 200 );
+ return;
+ }
+
+ // Don't 404 for these queries either.
+ if ( is_home() || is_search() ) {
+ status_header( 200 );
+ return;
+ }
+ }
+
+ // Guess it's time to 404.
+ $wp_query->set_404();
+ status_header( 404 );
+ nocache_headers();
+ }
+
+ /**
+ * Sets up all of the variables required by the WordPress environment.
+ *
+ * The action 'wp' has one parameter that references the WP object. It
+ * allows for accessing the properties and methods to further manipulate the
+ * object.
+ *
+ * @since 2.0.0
+ *
+ * @param string|array $query_args Passed to {@link parse_request()}
+ */
+ function main($query_args = '') {
+ $this->init();
+ $this->parse_request($query_args);
+ $this->send_headers();
+ $this->query_posts();
+ $this->handle_404();
+ $this->register_globals();
+ do_action_ref_array('wp', array(&$this));
+ }
+
+}
+
+/**
+ * Helper class to remove the need to use eval to replace $matches[] in query strings.
+ *
+ * @since 2.9.0
+ */
+class WP_MatchesMapRegex {
+ /**
+ * store for matches
+ *
+ * @access private
+ * @var array
+ */
+ var $_matches;
+
+ /**
+ * store for mapping result
+ *
+ * @access public
+ * @var string
+ */
+ var $output;
+
+ /**
+ * subject to perform mapping on (query string containing $matches[] references
+ *
+ * @access private
+ * @var string
+ */
+ var $_subject;
+
+ /**
+ * regexp pattern to match $matches[] references
+ *
+ * @var string
+ */
+ var $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
+
+ /**
+ * constructor
+ *
+ * @param string $subject subject if regex
+ * @param array $matches data to use in map
+ * @return self
+ */
+ function WP_MatchesMapRegex($subject, $matches) {
+ $this->_subject = $subject;
+ $this->_matches = $matches;
+ $this->output = $this->_map();
+ }
+
+ /**
+ * Substitute substring matches in subject.
+ *
+ * static helper function to ease use
+ *
+ * @access public
+ * @param string $subject subject
+ * @param array $matches data used for substitution
+ * @return string
+ */
+ public static function apply($subject, $matches) {
+ $oSelf = new WP_MatchesMapRegex($subject, $matches);
+ return $oSelf->output;
+ }
+
+ /**
+ * do the actual mapping
+ *
+ * @access private
+ * @return string
+ */
+ function _map() {
+ $callback = array($this, 'callback');
+ return preg_replace_callback($this->_pattern, $callback, $this->_subject);
+ }
+
+ /**
+ * preg_replace_callback hook
+ *
+ * @access public
+ * @param array $matches preg_replace regexp matches
+ * @return string
+ */
+ function callback($matches) {
+ $index = intval(substr($matches[0], 9, -1));
+ return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
+ }
+
+}
diff --git a/src/wp-includes/class.wp-dependencies.php b/src/wp-includes/class.wp-dependencies.php
new file mode 100644
index 0000000000..eb075c8574
--- /dev/null
+++ b/src/wp-includes/class.wp-dependencies.php
@@ -0,0 +1,261 @@
+<?php
+/**
+ * BackPress Scripts enqueue.
+ *
+ * These classes were refactored from the WordPress WP_Scripts and WordPress
+ * script enqueue API.
+ *
+ * @package BackPress
+ * @since r74
+ */
+
+/**
+ * BackPress enqueued dependiences class.
+ *
+ * @package BackPress
+ * @uses _WP_Dependency
+ * @since r74
+ */
+class WP_Dependencies {
+ var $registered = array();
+ var $queue = array();
+ var $to_do = array();
+ var $done = array();
+ var $args = array();
+ var $groups = array();
+ var $group = 0;
+
+ /**
+ * Do the dependencies
+ *
+ * Process the items passed to it or the queue. Processes all dependencies.
+ *
+ * @param mixed $handles (optional) items to be processed. (void) processes queue, (string) process that item, (array of strings) process those items
+ * @return array Items that have been processed
+ */
+ function do_items( $handles = false, $group = false ) {
+ // Print the queue if nothing is passed. If a string is passed, print that script. If an array is passed, print those scripts.
+ $handles = false === $handles ? $this->queue : (array) $handles;
+ $this->all_deps( $handles );
+
+ foreach( $this->to_do as $key => $handle ) {
+ if ( !in_array($handle, $this->done, true) && isset($this->registered[$handle]) ) {
+
+ if ( ! $this->registered[$handle]->src ) { // Defines a group.
+ $this->done[] = $handle;
+ continue;
+ }
+
+ if ( $this->do_item( $handle, $group ) )
+ $this->done[] = $handle;
+
+ unset( $this->to_do[$key] );
+ }
+ }
+
+ return $this->done;
+ }
+
+ function do_item( $handle ) {
+ return isset($this->registered[$handle]);
+ }
+
+ /**
+ * Determines dependencies
+ *
+ * Recursively builds array of items to process taking dependencies into account. Does NOT catch infinite loops.
+ *
+ *
+ * @param mixed $handles Accepts (string) dep name or (array of strings) dep names
+ * @param bool $recursion Used internally when function calls itself
+ */
+ function all_deps( $handles, $recursion = false, $group = false ) {
+ if ( !$handles = (array) $handles )
+ return false;
+
+ foreach ( $handles as $handle ) {
+ $handle_parts = explode('?', $handle);
+ $handle = $handle_parts[0];
+ $queued = in_array($handle, $this->to_do, true);
+
+ if ( in_array($handle, $this->done, true) ) // Already done
+ continue;
+
+ $moved = $this->set_group( $handle, $recursion, $group );
+
+ if ( $queued && !$moved ) // already queued and in the right group
+ continue;
+
+ $keep_going = true;
+ if ( !isset($this->registered[$handle]) )
+ $keep_going = false; // Script doesn't exist
+ elseif ( $this->registered[$handle]->deps && array_diff($this->registered[$handle]->deps, array_keys($this->registered)) )
+ $keep_going = false; // Script requires deps which don't exist (not a necessary check. efficiency?)
+ elseif ( $this->registered[$handle]->deps && !$this->all_deps( $this->registered[$handle]->deps, true, $group ) )
+ $keep_going = false; // Script requires deps which don't exist
+
+ if ( !$keep_going ) { // Either script or its deps don't exist.
+ if ( $recursion )
+ return false; // Abort this branch.
+ else
+ continue; // We're at the top level. Move on to the next one.
+ }
+
+ if ( $queued ) // Already grobbed it and its deps
+ continue;
+
+ if ( isset($handle_parts[1]) )
+ $this->args[$handle] = $handle_parts[1];
+
+ $this->to_do[] = $handle;
+ }
+
+ return true;
+ }
+
+ /**
+ * Adds item
+ *
+ * Adds the item only if no item of that name already exists
+ *
+ * @param string $handle Script name
+ * @param string $src Script url
+ * @param array $deps (optional) Array of script names on which this script depends
+ * @param string $ver (optional) Script version (used for cache busting)
+ * @return array Hierarchical array of dependencies
+ */
+ function add( $handle, $src, $deps = array(), $ver = false, $args = null ) {
+ if ( isset($this->registered[$handle]) )
+ return false;
+ $this->registered[$handle] = new _WP_Dependency( $handle, $src, $deps, $ver, $args );
+ return true;
+ }
+
+ /**
+ * Adds extra data
+ *
+ * Adds data only if script has already been added.
+ *
+ * @param string $handle Script name
+ * @param string $key
+ * @param mixed $value
+ * @return bool success
+ */
+ function add_data( $handle, $key, $value ) {
+ if ( !isset( $this->registered[$handle] ) )
+ return false;
+
+ return $this->registered[$handle]->add_data( $key, $value );
+ }
+
+ /**
+ * Get extra data
+ *
+ * Gets data associated with a certain handle.
+ *
+ * @since WP 3.3
+ *
+ * @param string $handle Script name
+ * @param string $key
+ * @return mixed
+ */
+ function get_data( $handle, $key ) {
+ if ( !isset( $this->registered[$handle] ) )
+ return false;
+
+ if ( !isset( $this->registered[$handle]->extra[$key] ) )
+ return false;
+
+ return $this->registered[$handle]->extra[$key];
+ }
+
+ function remove( $handles ) {
+ foreach ( (array) $handles as $handle )
+ unset($this->registered[$handle]);
+ }
+
+ function enqueue( $handles ) {
+ foreach ( (array) $handles as $handle ) {
+ $handle = explode('?', $handle);
+ if ( !in_array($handle[0], $this->queue) && isset($this->registered[$handle[0]]) ) {
+ $this->queue[] = $handle[0];
+ if ( isset($handle[1]) )
+ $this->args[$handle[0]] = $handle[1];
+ }
+ }
+ }
+
+ function dequeue( $handles ) {
+ foreach ( (array) $handles as $handle ) {
+ $handle = explode('?', $handle);
+ $key = array_search($handle[0], $this->queue);
+ if ( false !== $key ) {
+ unset($this->queue[$key]);
+ unset($this->args[$handle[0]]);
+ }
+ }
+ }
+
+
+ function query( $handle, $list = 'registered' ) {
+ switch ( $list ) {
+ case 'registered' :
+ case 'scripts': // back compat
+ if ( isset( $this->registered[ $handle ] ) )
+ return $this->registered[ $handle ];
+ return false;
+
+ case 'enqueued' :
+ case 'queue' :
+ return in_array( $handle, $this->queue );
+
+ case 'to_do' :
+ case 'to_print': // back compat
+ return in_array( $handle, $this->to_do );
+
+ case 'done' :
+ case 'printed': // back compat
+ return in_array( $handle, $this->done );
+ }
+ return false;
+ }
+
+ function set_group( $handle, $recursion, $group ) {
+ $group = (int) $group;
+
+ if ( $recursion )
+ $group = min($this->group, $group);
+ else
+ $this->group = $group;
+
+ if ( isset($this->groups[$handle]) && $this->groups[$handle] <= $group )
+ return false;
+
+ $this->groups[$handle] = $group;
+ return true;
+ }
+
+}
+
+class _WP_Dependency {
+ var $handle;
+ var $src;
+ var $deps = array();
+ var $ver = false;
+ var $args = null;
+
+ var $extra = array();
+
+ function __construct() {
+ @list( $this->handle, $this->src, $this->deps, $this->ver, $this->args ) = func_get_args();
+ if ( ! is_array($this->deps) )
+ $this->deps = array();
+ }
+
+ function add_data( $name, $data ) {
+ if ( !is_scalar($name) )
+ return false;
+ $this->extra[$name] = $data;
+ return true;
+ }
+}
diff --git a/src/wp-includes/class.wp-scripts.php b/src/wp-includes/class.wp-scripts.php
new file mode 100644
index 0000000000..38f3f9fcf3
--- /dev/null
+++ b/src/wp-includes/class.wp-scripts.php
@@ -0,0 +1,217 @@
+<?php
+/**
+ * BackPress Scripts enqueue.
+ *
+ * These classes were refactored from the WordPress WP_Scripts and WordPress
+ * script enqueue API.
+ *
+ * @package BackPress
+ * @since r16
+ */
+
+/**
+ * BackPress Scripts enqueue class.
+ *
+ * @package BackPress
+ * @uses WP_Dependencies
+ * @since r16
+ */
+class WP_Scripts extends WP_Dependencies {
+ var $base_url; // Full URL with trailing slash
+ var $content_url;
+ var $default_version;
+ var $in_footer = array();
+ var $concat = '';
+ var $concat_version = '';
+ var $do_concat = false;
+ var $print_html = '';
+ var $print_code = '';
+ var $ext_handles = '';
+ var $ext_version = '';
+ var $default_dirs;
+
+ function __construct() {
+ $this->init();
+ add_action( 'init', array( $this, 'init' ), 0 );
+ }
+
+ function init() {
+ do_action_ref_array( 'wp_default_scripts', array(&$this) );
+ }
+
+ /**
+ * Prints scripts
+ *
+ * Prints the scripts passed to it or the print queue. Also prints all necessary dependencies.
+ *
+ * @param mixed $handles (optional) Scripts to be printed. (void) prints queue, (string) prints that script, (array of strings) prints those scripts.
+ * @param int $group (optional) If scripts were queued in groups prints this group number.
+ * @return array Scripts that have been printed
+ */
+ function print_scripts( $handles = false, $group = false ) {
+ return $this->do_items( $handles, $group );
+ }
+
+ // Deprecated since 3.3, see print_extra_script()
+ function print_scripts_l10n( $handle, $echo = true ) {
+ _deprecated_function( __FUNCTION__, '3.3', 'print_extra_script()' );
+ return $this->print_extra_script( $handle, $echo );
+ }
+
+ function print_extra_script( $handle, $echo = true ) {
+ if ( !$output = $this->get_data( $handle, 'data' ) )
+ return;
+
+ if ( !$echo )
+ return $output;
+
+ echo "<script type='text/javascript'>\n"; // CDATA and type='text/javascript' is not needed for HTML 5
+ echo "/* <![CDATA[ */\n";
+ echo "$output\n";
+ echo "/* ]]> */\n";
+ echo "</script>\n";
+
+ return true;
+ }
+
+ function do_item( $handle, $group = false ) {
+ if ( !parent::do_item($handle) )
+ return false;
+
+ if ( 0 === $group && $this->groups[$handle] > 0 ) {
+ $this->in_footer[] = $handle;
+ return false;
+ }
+
+ if ( false === $group && in_array($handle, $this->in_footer, true) )
+ $this->in_footer = array_diff( $this->in_footer, (array) $handle );
+
+ if ( null === $this->registered[$handle]->ver )
+ $ver = '';
+ else
+ $ver = $this->registered[$handle]->ver ? $this->registered[$handle]->ver : $this->default_version;
+
+ if ( isset($this->args[$handle]) )
+ $ver = $ver ? $ver . '&amp;' . $this->args[$handle] : $this->args[$handle];
+
+ $src = $this->registered[$handle]->src;
+
+ if ( $this->do_concat ) {
+ $srce = apply_filters( 'script_loader_src', $src, $handle );
+ if ( $this->in_default_dir($srce) ) {
+ $this->print_code .= $this->print_extra_script( $handle, false );
+ $this->concat .= "$handle,";
+ $this->concat_version .= "$handle$ver";
+ return true;
+ } else {
+ $this->ext_handles .= "$handle,";
+ $this->ext_version .= "$handle$ver";
+ }
+ }
+
+ $this->print_extra_script( $handle );
+ if ( !preg_match('|^(https?:)?//|', $src) && ! ( $this->content_url && 0 === strpos($src, $this->content_url) ) ) {
+ $src = $this->base_url . $src;
+ }
+
+ if ( !empty($ver) )
+ $src = add_query_arg('ver', $ver, $src);
+
+ $src = esc_url( apply_filters( 'script_loader_src', $src, $handle ) );
+
+ if ( $this->do_concat )
+ $this->print_html .= "<script type='text/javascript' src='$src'></script>\n";
+ else
+ echo "<script type='text/javascript' src='$src'></script>\n";
+
+ return true;
+ }
+
+ /**
+ * Localizes a script
+ *
+ * Localizes only if the script has already been added
+ */
+ function localize( $handle, $object_name, $l10n ) {
+ if ( $handle === 'jquery' )
+ $handle = 'jquery-core';
+
+ if ( is_array($l10n) && isset($l10n['l10n_print_after']) ) { // back compat, preserve the code in 'l10n_print_after' if present
+ $after = $l10n['l10n_print_after'];
+ unset($l10n['l10n_print_after']);
+ }
+
+ foreach ( (array) $l10n as $key => $value ) {
+ if ( !is_scalar($value) )
+ continue;
+
+ $l10n[$key] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8');
+ }
+
+ $script = "var $object_name = " . json_encode($l10n) . ';';
+
+ if ( !empty($after) )
+ $script .= "\n$after;";
+
+ $data = $this->get_data( $handle, 'data' );
+
+ if ( !empty( $data ) )
+ $script = "$data\n$script";
+
+ return $this->add_data( $handle, 'data', $script );
+ }
+
+ function set_group( $handle, $recursion, $group = false ) {
+
+ if ( $this->registered[$handle]->args === 1 )
+ $grp = 1;
+ else
+ $grp = (int) $this->get_data( $handle, 'group' );
+
+ if ( false !== $group && $grp > $group )
+ $grp = $group;
+
+ return parent::set_group( $handle, $recursion, $grp );
+ }
+
+ function all_deps( $handles, $recursion = false, $group = false ) {
+ $r = parent::all_deps( $handles, $recursion );
+ if ( !$recursion )
+ $this->to_do = apply_filters( 'print_scripts_array', $this->to_do );
+ return $r;
+ }
+
+ function do_head_items() {
+ $this->do_items(false, 0);
+ return $this->done;
+ }
+
+ function do_footer_items() {
+ $this->do_items(false, 1);
+ return $this->done;
+ }
+
+ function in_default_dir($src) {
+ if ( ! $this->default_dirs )
+ return true;
+
+ if ( 0 === strpos( $src, '/wp-includes/js/l10n' ) )
+ return false;
+
+ foreach ( (array) $this->default_dirs as $test ) {
+ if ( 0 === strpos($src, $test) )
+ return true;
+ }
+ return false;
+ }
+
+ function reset() {
+ $this->do_concat = false;
+ $this->print_code = '';
+ $this->concat = '';
+ $this->concat_version = '';
+ $this->print_html = '';
+ $this->ext_version = '';
+ $this->ext_handles = '';
+ }
+}
diff --git a/src/wp-includes/class.wp-styles.php b/src/wp-includes/class.wp-styles.php
new file mode 100644
index 0000000000..b1241b3046
--- /dev/null
+++ b/src/wp-includes/class.wp-styles.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * BackPress Styles enqueue.
+ *
+ * These classes were refactored from the WordPress WP_Scripts and WordPress
+ * script enqueue API.
+ *
+ * @package BackPress
+ * @since r74
+ */
+
+/**
+ * BackPress Styles enqueue class.
+ *
+ * @package BackPress
+ * @uses WP_Dependencies
+ * @since r74
+ */
+class WP_Styles extends WP_Dependencies {
+ var $base_url;
+ var $content_url;
+ var $default_version;
+ var $text_direction = 'ltr';
+ var $concat = '';
+ var $concat_version = '';
+ var $do_concat = false;
+ var $print_html = '';
+ var $print_code = '';
+ var $default_dirs;
+
+ function __construct() {
+ do_action_ref_array( 'wp_default_styles', array(&$this) );
+ }
+
+ function do_item( $handle ) {
+ if ( !parent::do_item($handle) )
+ return false;
+
+ $obj = $this->registered[$handle];
+ if ( null === $obj->ver )
+ $ver = '';
+ else
+ $ver = $obj->ver ? $obj->ver : $this->default_version;
+
+ if ( isset($this->args[$handle]) )
+ $ver = $ver ? $ver . '&amp;' . $this->args[$handle] : $this->args[$handle];
+
+ if ( $this->do_concat ) {
+ if ( $this->in_default_dir($obj->src) && !isset($obj->extra['conditional']) && !isset($obj->extra['alt']) ) {
+ $this->concat .= "$handle,";
+ $this->concat_version .= "$handle$ver";
+
+ $this->print_code .= $this->print_inline_style( $handle, false );
+
+ return true;
+ }
+ }
+
+ if ( isset($obj->args) )
+ $media = esc_attr( $obj->args );
+ else
+ $media = 'all';
+
+ $href = $this->_css_href( $obj->src, $ver, $handle );
+ $rel = isset($obj->extra['alt']) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
+ $title = isset($obj->extra['title']) ? "title='" . esc_attr( $obj->extra['title'] ) . "'" : '';
+
+ $end_cond = $tag = '';
+ if ( isset($obj->extra['conditional']) && $obj->extra['conditional'] ) {
+ $tag .= "<!--[if {$obj->extra['conditional']}]>\n";
+ $end_cond = "<![endif]-->\n";
+ }
+
+ $tag .= apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-css' $title href='$href' type='text/css' media='$media' />\n", $handle );
+ if ( 'rtl' === $this->text_direction && isset($obj->extra['rtl']) && $obj->extra['rtl'] ) {
+ if ( is_bool( $obj->extra['rtl'] ) ) {
+ $suffix = isset( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
+ $rtl_href = str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $this->_css_href( $obj->src , $ver, "$handle-rtl" ));
+ } else {
+ $rtl_href = $this->_css_href( $obj->extra['rtl'], $ver, "$handle-rtl" );
+ }
+
+ $tag .= apply_filters( 'style_loader_tag', "<link rel='$rel' id='$handle-rtl-css' $title href='$rtl_href' type='text/css' media='$media' />\n", $handle );
+ }
+
+ $tag .= $end_cond;
+
+ if ( $this->do_concat ) {
+ $this->print_html .= $tag;
+ $this->print_html .= $this->print_inline_style( $handle, false );
+ } else {
+ echo $tag;
+ $this->print_inline_style( $handle );
+ }
+
+ return true;
+ }
+
+ function add_inline_style( $handle, $code ) {
+ if ( !$code )
+ return false;
+
+ $after = $this->get_data( $handle, 'after' );
+ if ( !$after )
+ $after = array();
+
+ $after[] = $code;
+
+ return $this->add_data( $handle, 'after', $after );
+ }
+
+ function print_inline_style( $handle, $echo = true ) {
+ $output = $this->get_data( $handle, 'after' );
+
+ if ( empty( $output ) )
+ return false;
+
+ $output = implode( "\n", $output );
+
+ if ( !$echo )
+ return $output;
+
+ echo "<style type='text/css'>\n";
+ echo "$output\n";
+ echo "</style>\n";
+
+ return true;
+ }
+
+ function all_deps( $handles, $recursion = false, $group = false ) {
+ $r = parent::all_deps( $handles, $recursion );
+ if ( !$recursion )
+ $this->to_do = apply_filters( 'print_styles_array', $this->to_do );
+ return $r;
+ }
+
+ function _css_href( $src, $ver, $handle ) {
+ if ( !is_bool($src) && !preg_match('|^(https?:)?//|', $src) && ! ( $this->content_url && 0 === strpos($src, $this->content_url) ) ) {
+ $src = $this->base_url . $src;
+ }
+
+ if ( !empty($ver) )
+ $src = add_query_arg('ver', $ver, $src);
+ $src = apply_filters( 'style_loader_src', $src, $handle );
+ return esc_url( $src );
+ }
+
+ function in_default_dir($src) {
+ if ( ! $this->default_dirs )
+ return true;
+
+ foreach ( (array) $this->default_dirs as $test ) {
+ if ( 0 === strpos($src, $test) )
+ return true;
+ }
+ return false;
+ }
+
+ function do_footer_items() { // HTML 5 allows styles in the body, grab late enqueued items and output them in the footer.
+ $this->do_items(false, 1);
+ return $this->done;
+ }
+
+ function reset() {
+ $this->do_concat = false;
+ $this->concat = '';
+ $this->concat_version = '';
+ $this->print_html = '';
+ }
+}
diff --git a/src/wp-includes/comment-template.php b/src/wp-includes/comment-template.php
new file mode 100644
index 0000000000..9a09d28d54
--- /dev/null
+++ b/src/wp-includes/comment-template.php
@@ -0,0 +1,1682 @@
+<?php
+/**
+ * Comment template functions
+ *
+ * These functions are meant to live inside of the WordPress loop.
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Retrieve the author of the current comment.
+ *
+ * If the comment has an empty comment_author field, then 'Anonymous' person is
+ * assumed.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'get_comment_author' hook on the comment author
+ *
+ * @param int $comment_ID The ID of the comment for which to retrieve the author. Optional.
+ * @return string The comment author
+ */
+function get_comment_author( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ if ( empty($comment->comment_author) ) {
+ if (!empty($comment->user_id)){
+ $user=get_userdata($comment->user_id);
+ $author=$user->user_login;
+ } else {
+ $author = __('Anonymous');
+ }
+ } else {
+ $author = $comment->comment_author;
+ }
+ return apply_filters('get_comment_author', $author);
+}
+
+/**
+ * Displays the author of the current comment.
+ *
+ * @since 0.71
+ * @uses apply_filters() Calls 'comment_author' on comment author before displaying
+ *
+ * @param int $comment_ID The ID of the comment for which to print the author. Optional.
+ */
+function comment_author( $comment_ID = 0 ) {
+ $author = apply_filters('comment_author', get_comment_author( $comment_ID ) );
+ echo $author;
+}
+
+/**
+ * Retrieve the email of the author of the current comment.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls the 'get_comment_author_email' hook on the comment author email
+ * @uses $comment
+ *
+ * @param int $comment_ID The ID of the comment for which to get the author's email. Optional.
+ * @return string The current comment author's email
+ */
+function get_comment_author_email( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ return apply_filters('get_comment_author_email', $comment->comment_author_email);
+}
+
+/**
+ * Display the email of the author of the current global $comment.
+ *
+ * Care should be taken to protect the email address and assure that email
+ * harvesters do not capture your commentors' email address. Most assume that
+ * their email address will not appear in raw form on the blog. Doing so will
+ * enable anyone, including those that people don't want to get the email
+ * address and use it for their own means good and bad.
+ *
+ * @since 0.71
+ * @uses apply_filters() Calls 'author_email' hook on the author email
+ *
+ * @param int $comment_ID The ID of the comment for which to print the author's email. Optional.
+ */
+function comment_author_email( $comment_ID = 0 ) {
+ echo apply_filters('author_email', get_comment_author_email( $comment_ID ) );
+}
+
+/**
+ * Display the html email link to the author of the current comment.
+ *
+ * Care should be taken to protect the email address and assure that email
+ * harvesters do not capture your commentors' email address. Most assume that
+ * their email address will not appear in raw form on the blog. Doing so will
+ * enable anyone, including those that people don't want to get the email
+ * address and use it for their own means good and bad.
+ *
+ * @since 0.71
+ * @uses apply_filters() Calls 'comment_email' hook for the display of the comment author's email
+ * @uses get_comment_author_email_link() For generating the link
+ * @global object $comment The current Comment row object
+ *
+ * @param string $linktext The text to display instead of the comment author's email address
+ * @param string $before The text or HTML to display before the email link.
+ * @param string $after The text or HTML to display after the email link.
+ */
+function comment_author_email_link($linktext='', $before='', $after='') {
+ if ( $link = get_comment_author_email_link( $linktext, $before, $after ) )
+ echo $link;
+}
+
+/**
+ * Return the html email link to the author of the current comment.
+ *
+ * Care should be taken to protect the email address and assure that email
+ * harvesters do not capture your commentors' email address. Most assume that
+ * their email address will not appear in raw form on the blog. Doing so will
+ * enable anyone, including those that people don't want to get the email
+ * address and use it for their own means good and bad.
+ *
+ * @since 2.7
+ * @uses apply_filters() Calls 'comment_email' hook for the display of the comment author's email
+ * @global object $comment The current Comment row object
+ *
+ * @param string $linktext The text to display instead of the comment author's email address
+ * @param string $before The text or HTML to display before the email link.
+ * @param string $after The text or HTML to display after the email link.
+ */
+function get_comment_author_email_link($linktext='', $before='', $after='') {
+ global $comment;
+ $email = apply_filters('comment_email', $comment->comment_author_email);
+ if ((!empty($email)) && ($email != '@')) {
+ $display = ($linktext != '') ? $linktext : $email;
+ $return = $before;
+ $return .= "<a href='mailto:$email'>$display</a>";
+ $return .= $after;
+ return $return;
+ } else {
+ return '';
+ }
+}
+
+/**
+ * Retrieve the html link to the url of the author of the current comment.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'get_comment_author_link' hook on the complete link HTML or author
+ *
+ * @param int $comment_ID The ID of the comment for which to get the author's link. Optional.
+ * @return string Comment Author name or HTML link for author's URL
+ */
+function get_comment_author_link( $comment_ID = 0 ) {
+ /** @todo Only call these functions when they are needed. Include in if... else blocks */
+ $url = get_comment_author_url( $comment_ID );
+ $author = get_comment_author( $comment_ID );
+
+ if ( empty( $url ) || 'http://' == $url )
+ $return = $author;
+ else
+ $return = "<a href='$url' rel='external nofollow' class='url'>$author</a>";
+ return apply_filters('get_comment_author_link', $return);
+}
+
+/**
+ * Display the html link to the url of the author of the current comment.
+ *
+ * @since 0.71
+ * @see get_comment_author_link() Echoes result
+ *
+ * @param int $comment_ID The ID of the comment for which to print the author's link. Optional.
+ */
+function comment_author_link( $comment_ID = 0 ) {
+ echo get_comment_author_link( $comment_ID );
+}
+
+/**
+ * Retrieve the IP address of the author of the current comment.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ * @uses apply_filters()
+ *
+ * @param int $comment_ID The ID of the comment for which to get the author's IP address. Optional.
+ * @return string The comment author's IP address.
+ */
+function get_comment_author_IP( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ return apply_filters('get_comment_author_IP', $comment->comment_author_IP);
+}
+
+/**
+ * Display the IP address of the author of the current comment.
+ *
+ * @since 0.71
+ * @see get_comment_author_IP() Echoes Result
+ *
+ * @param int $comment_ID The ID of the comment for which to print the author's IP address. Optional.
+ */
+function comment_author_IP( $comment_ID = 0 ) {
+ echo get_comment_author_IP( $comment_ID );
+}
+
+/**
+ * Retrieve the url of the author of the current comment.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'get_comment_author_url' hook on the comment author's URL
+ *
+ * @param int $comment_ID The ID of the comment for which to get the author's URL. Optional.
+ * @return string
+ */
+function get_comment_author_url( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ $url = ('http://' == $comment->comment_author_url) ? '' : $comment->comment_author_url;
+ $url = esc_url( $url, array('http', 'https') );
+ return apply_filters('get_comment_author_url', $url);
+}
+
+/**
+ * Display the url of the author of the current comment.
+ *
+ * @since 0.71
+ * @uses apply_filters()
+ * @uses get_comment_author_url() Retrieves the comment author's URL
+ *
+ * @param int $comment_ID The ID of the comment for which to print the author's URL. Optional.
+ */
+function comment_author_url( $comment_ID = 0 ) {
+ echo apply_filters('comment_url', get_comment_author_url( $comment_ID ));
+}
+
+/**
+ * Retrieves the HTML link of the url of the author of the current comment.
+ *
+ * $linktext parameter is only used if the URL does not exist for the comment
+ * author. If the URL does exist then the URL will be used and the $linktext
+ * will be ignored.
+ *
+ * Encapsulate the HTML link between the $before and $after. So it will appear
+ * in the order of $before, link, and finally $after.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls the 'get_comment_author_url_link' on the complete HTML before returning.
+ *
+ * @param string $linktext The text to display instead of the comment author's email address
+ * @param string $before The text or HTML to display before the email link.
+ * @param string $after The text or HTML to display after the email link.
+ * @return string The HTML link between the $before and $after parameters
+ */
+function get_comment_author_url_link( $linktext = '', $before = '', $after = '' ) {
+ $url = get_comment_author_url();
+ $display = ($linktext != '') ? $linktext : $url;
+ $display = str_replace( 'http://www.', '', $display );
+ $display = str_replace( 'http://', '', $display );
+ if ( '/' == substr($display, -1) )
+ $display = substr($display, 0, -1);
+ $return = "$before<a href='$url' rel='external'>$display</a>$after";
+ return apply_filters('get_comment_author_url_link', $return);
+}
+
+/**
+ * Displays the HTML link of the url of the author of the current comment.
+ *
+ * @since 0.71
+ * @see get_comment_author_url_link() Echoes result
+ *
+ * @param string $linktext The text to display instead of the comment author's email address
+ * @param string $before The text or HTML to display before the email link.
+ * @param string $after The text or HTML to display after the email link.
+ */
+function comment_author_url_link( $linktext = '', $before = '', $after = '' ) {
+ echo get_comment_author_url_link( $linktext, $before, $after );
+}
+
+/**
+ * Generates semantic classes for each comment element
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $class One or more classes to add to the class list
+ * @param int $comment_id An optional comment ID
+ * @param int $post_id An optional post ID
+ * @param bool $echo Whether comment_class should echo or return
+ */
+function comment_class( $class = '', $comment_id = null, $post_id = null, $echo = true ) {
+ // Separates classes with a single space, collates classes for comment DIV
+ $class = 'class="' . join( ' ', get_comment_class( $class, $comment_id, $post_id ) ) . '"';
+ if ( $echo)
+ echo $class;
+ else
+ return $class;
+}
+
+/**
+ * Returns the classes for the comment div as an array
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $class One or more classes to add to the class list
+ * @param int $comment_id An optional comment ID
+ * @param int $post_id An optional post ID
+ * @return array Array of classes
+ */
+function get_comment_class( $class = '', $comment_id = null, $post_id = null ) {
+ global $comment_alt, $comment_depth, $comment_thread_alt;
+
+ $comment = get_comment($comment_id);
+
+ $classes = array();
+
+ // Get the comment type (comment, trackback),
+ $classes[] = ( empty( $comment->comment_type ) ) ? 'comment' : $comment->comment_type;
+
+ // If the comment author has an id (registered), then print the log in name
+ if ( $comment->user_id > 0 && $user = get_userdata($comment->user_id) ) {
+ // For all registered users, 'byuser'
+ $classes[] = 'byuser';
+ $classes[] = 'comment-author-' . sanitize_html_class($user->user_nicename, $comment->user_id);
+ // For comment authors who are the author of the post
+ if ( $post = get_post($post_id) ) {
+ if ( $comment->user_id === $post->post_author )
+ $classes[] = 'bypostauthor';
+ }
+ }
+
+ if ( empty($comment_alt) )
+ $comment_alt = 0;
+ if ( empty($comment_depth) )
+ $comment_depth = 1;
+ if ( empty($comment_thread_alt) )
+ $comment_thread_alt = 0;
+
+ if ( $comment_alt % 2 ) {
+ $classes[] = 'odd';
+ $classes[] = 'alt';
+ } else {
+ $classes[] = 'even';
+ }
+
+ $comment_alt++;
+
+ // Alt for top-level comments
+ if ( 1 == $comment_depth ) {
+ if ( $comment_thread_alt % 2 ) {
+ $classes[] = 'thread-odd';
+ $classes[] = 'thread-alt';
+ } else {
+ $classes[] = 'thread-even';
+ }
+ $comment_thread_alt++;
+ }
+
+ $classes[] = "depth-$comment_depth";
+
+ if ( !empty($class) ) {
+ if ( !is_array( $class ) )
+ $class = preg_split('#\s+#', $class);
+ $classes = array_merge($classes, $class);
+ }
+
+ $classes = array_map('esc_attr', $classes);
+
+ return apply_filters('comment_class', $classes, $class, $comment_id, $post_id);
+}
+
+/**
+ * Retrieve the comment date of the current comment.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'get_comment_date' hook with the formatted date and the $d parameter respectively
+ * @uses $comment
+ *
+ * @param string $d The format of the date (defaults to user's config)
+ * @param int $comment_ID The ID of the comment for which to get the date. Optional.
+ * @return string The comment's date
+ */
+function get_comment_date( $d = '', $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ if ( '' == $d )
+ $date = mysql2date(get_option('date_format'), $comment->comment_date);
+ else
+ $date = mysql2date($d, $comment->comment_date);
+ return apply_filters('get_comment_date', $date, $d);
+}
+
+/**
+ * Display the comment date of the current comment.
+ *
+ * @since 0.71
+ *
+ * @param string $d The format of the date (defaults to user's config)
+ * @param int $comment_ID The ID of the comment for which to print the date. Optional.
+ */
+function comment_date( $d = '', $comment_ID = 0 ) {
+ echo get_comment_date( $d, $comment_ID );
+}
+
+/**
+ * Retrieve the excerpt of the current comment.
+ *
+ * Will cut each word and only output the first 20 words with '&hellip;' at the end.
+ * If the word count is less than 20, then no truncating is done and no '&hellip;'
+ * will appear.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ * @uses apply_filters() Calls 'get_comment_excerpt' on truncated comment
+ *
+ * @param int $comment_ID The ID of the comment for which to get the excerpt. Optional.
+ * @return string The maybe truncated comment with 20 words or less
+ */
+function get_comment_excerpt( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ $comment_text = strip_tags($comment->comment_content);
+ $blah = explode(' ', $comment_text);
+ if (count($blah) > 20) {
+ $k = 20;
+ $use_dotdotdot = 1;
+ } else {
+ $k = count($blah);
+ $use_dotdotdot = 0;
+ }
+ $excerpt = '';
+ for ($i=0; $i<$k; $i++) {
+ $excerpt .= $blah[$i] . ' ';
+ }
+ $excerpt .= ($use_dotdotdot) ? '&hellip;' : '';
+ return apply_filters('get_comment_excerpt', $excerpt);
+}
+
+/**
+ * Display the excerpt of the current comment.
+ *
+ * @since 1.2.0
+ * @uses apply_filters() Calls 'comment_excerpt' hook before displaying excerpt
+ *
+ * @param int $comment_ID The ID of the comment for which to print the excerpt. Optional.
+ */
+function comment_excerpt( $comment_ID = 0 ) {
+ echo apply_filters('comment_excerpt', get_comment_excerpt($comment_ID) );
+}
+
+/**
+ * Retrieve the comment id of the current comment.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ * @uses apply_filters() Calls the 'get_comment_ID' hook for the comment ID
+ *
+ * @return int The comment ID
+ */
+function get_comment_ID() {
+ global $comment;
+ return apply_filters('get_comment_ID', $comment->comment_ID);
+}
+
+/**
+ * Displays the comment id of the current comment.
+ *
+ * @since 0.71
+ * @see get_comment_ID() Echoes Result
+ */
+function comment_ID() {
+ echo get_comment_ID();
+}
+
+/**
+ * Retrieve the link to a given comment.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ *
+ * @param object|string|int $comment Comment to retrieve.
+ * @param array $args Optional args.
+ * @return string The permalink to the given comment.
+ */
+function get_comment_link( $comment = null, $args = array() ) {
+ global $wp_rewrite, $in_comment_loop;
+
+ $comment = get_comment($comment);
+
+ // Backwards compat
+ if ( !is_array($args) ) {
+ $page = $args;
+ $args = array();
+ $args['page'] = $page;
+ }
+
+ $defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( '' === $args['per_page'] && get_option('page_comments') )
+ $args['per_page'] = get_option('comments_per_page');
+
+ if ( empty($args['per_page']) ) {
+ $args['per_page'] = 0;
+ $args['page'] = 0;
+ }
+
+ if ( $args['per_page'] ) {
+ if ( '' == $args['page'] )
+ $args['page'] = ( !empty($in_comment_loop) ) ? get_query_var('cpage') : get_page_of_comment( $comment->comment_ID, $args );
+
+ if ( $wp_rewrite->using_permalinks() )
+ $link = user_trailingslashit( trailingslashit( get_permalink( $comment->comment_post_ID ) ) . 'comment-page-' . $args['page'], 'comment' );
+ else
+ $link = add_query_arg( 'cpage', $args['page'], get_permalink( $comment->comment_post_ID ) );
+ } else {
+ $link = get_permalink( $comment->comment_post_ID );
+ }
+
+ return apply_filters( 'get_comment_link', $link . '#comment-' . $comment->comment_ID, $comment, $args );
+}
+
+/**
+ * Retrieves the link to the current post comments.
+ *
+ * @since 1.5.0
+ *
+ * @param int $post_id Optional post id
+ * @return string The link to the comments
+ */
+function get_comments_link($post_id = 0) {
+ return apply_filters( 'get_comments_link', get_permalink( $post_id ) . '#comments', $post_id );
+}
+
+/**
+ * Displays the link to the current post comments.
+ *
+ * @since 0.71
+ *
+ * @param string $deprecated Not Used
+ * @param bool $deprecated_2 Not Used
+ */
+function comments_link( $deprecated = '', $deprecated_2 = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '0.72' );
+ if ( !empty( $deprecated_2 ) )
+ _deprecated_argument( __FUNCTION__, '1.3' );
+ echo esc_url( get_comments_link() );
+}
+
+/**
+ * Retrieve the amount of comments a post has.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls the 'get_comments_number' hook on the number of comments
+ *
+ * @param int $post_id The Post ID
+ * @return int The number of comments a post has
+ */
+function get_comments_number( $post_id = 0 ) {
+ $post_id = absint( $post_id );
+
+ if ( !$post_id )
+ $post_id = get_the_ID();
+
+ $post = get_post($post_id);
+ if ( ! isset($post->comment_count) )
+ $count = 0;
+ else
+ $count = $post->comment_count;
+
+ return apply_filters('get_comments_number', $count, $post_id);
+}
+
+/**
+ * Display the language string for the number of comments the current post has.
+ *
+ * @since 0.71
+ * @uses apply_filters() Calls the 'comments_number' hook on the output and number of comments respectively.
+ *
+ * @param string $zero Text for no comments
+ * @param string $one Text for one comment
+ * @param string $more Text for more than one comment
+ * @param string $deprecated Not used.
+ */
+function comments_number( $zero = false, $one = false, $more = false, $deprecated = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '1.3' );
+
+ $number = get_comments_number();
+
+ if ( $number > 1 )
+ $output = str_replace('%', number_format_i18n($number), ( false === $more ) ? __('% Comments') : $more);
+ elseif ( $number == 0 )
+ $output = ( false === $zero ) ? __('No Comments') : $zero;
+ else // must be one
+ $output = ( false === $one ) ? __('1 Comment') : $one;
+
+ echo apply_filters('comments_number', $output, $number);
+}
+
+/**
+ * Retrieve the text of the current comment.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ *
+ * @param int $comment_ID The ID of the comment for which to get the text. Optional.
+ * @return string The comment content
+ */
+function get_comment_text( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ return apply_filters( 'get_comment_text', $comment->comment_content, $comment );
+}
+
+/**
+ * Displays the text of the current comment.
+ *
+ * @since 0.71
+ * @uses apply_filters() Passes the comment content through the 'comment_text' hook before display
+ * @uses get_comment_text() Gets the comment content
+ *
+ * @param int $comment_ID The ID of the comment for which to print the text. Optional.
+ */
+function comment_text( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ echo apply_filters( 'comment_text', get_comment_text( $comment_ID ), $comment );
+}
+
+/**
+ * Retrieve the comment time of the current comment.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ * @uses apply_filter() Calls 'get_comment_time' hook with the formatted time, the $d parameter, and $gmt parameter passed.
+ *
+ * @param string $d Optional. The format of the time (defaults to user's config)
+ * @param bool $gmt Whether to use the GMT date
+ * @param bool $translate Whether to translate the time (for use in feeds)
+ * @return string The formatted time
+ */
+function get_comment_time( $d = '', $gmt = false, $translate = true ) {
+ global $comment;
+ $comment_date = $gmt ? $comment->comment_date_gmt : $comment->comment_date;
+ if ( '' == $d )
+ $date = mysql2date(get_option('time_format'), $comment_date, $translate);
+ else
+ $date = mysql2date($d, $comment_date, $translate);
+ return apply_filters('get_comment_time', $date, $d, $gmt, $translate);
+}
+
+/**
+ * Display the comment time of the current comment.
+ *
+ * @since 0.71
+ *
+ * @param string $d Optional. The format of the time (defaults to user's config)
+ */
+function comment_time( $d = '' ) {
+ echo get_comment_time($d);
+}
+
+/**
+ * Retrieve the comment type of the current comment.
+ *
+ * @since 1.5.0
+ * @uses $comment
+ * @uses apply_filters() Calls the 'get_comment_type' hook on the comment type
+ *
+ * @param int $comment_ID The ID of the comment for which to get the type. Optional.
+ * @return string The comment type
+ */
+function get_comment_type( $comment_ID = 0 ) {
+ $comment = get_comment( $comment_ID );
+ if ( '' == $comment->comment_type )
+ $comment->comment_type = 'comment';
+
+ return apply_filters('get_comment_type', $comment->comment_type);
+}
+
+/**
+ * Display the comment type of the current comment.
+ *
+ * @since 0.71
+ *
+ * @param string $commenttxt The string to display for comment type
+ * @param string $trackbacktxt The string to display for trackback type
+ * @param string $pingbacktxt The string to display for pingback type
+ */
+function comment_type($commenttxt = false, $trackbacktxt = false, $pingbacktxt = false) {
+ if ( false === $commenttxt ) $commenttxt = _x( 'Comment', 'noun' );
+ if ( false === $trackbacktxt ) $trackbacktxt = __( 'Trackback' );
+ if ( false === $pingbacktxt ) $pingbacktxt = __( 'Pingback' );
+ $type = get_comment_type();
+ switch( $type ) {
+ case 'trackback' :
+ echo $trackbacktxt;
+ break;
+ case 'pingback' :
+ echo $pingbacktxt;
+ break;
+ default :
+ echo $commenttxt;
+ }
+}
+
+/**
+ * Retrieve The current post's trackback URL.
+ *
+ * There is a check to see if permalink's have been enabled and if so, will
+ * retrieve the pretty path. If permalinks weren't enabled, the ID of the
+ * current post is used and appended to the correct page to go to.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'trackback_url' on the resulting trackback URL
+ *
+ * @return string The trackback URL after being filtered
+ */
+function get_trackback_url() {
+ if ( '' != get_option('permalink_structure') ) {
+ $tb_url = trailingslashit(get_permalink()) . user_trailingslashit('trackback', 'single_trackback');
+ } else {
+ $tb_url = get_option('siteurl') . '/wp-trackback.php?p=' . get_the_ID();
+ }
+ return apply_filters('trackback_url', $tb_url);
+}
+
+/**
+ * Displays the current post's trackback URL.
+ *
+ * @since 0.71
+ * @uses get_trackback_url() Gets the trackback url for the current post
+ *
+ * @param bool $deprecated_echo Remove backwards compat in 2.5
+ * @return void|string Should only be used to echo the trackback URL, use get_trackback_url() for the result instead.
+ */
+function trackback_url( $deprecated_echo = true ) {
+ if ( $deprecated_echo !== true )
+ _deprecated_argument( __FUNCTION__, '2.5', __('Use <code>get_trackback_url()</code> instead if you do not want the value echoed.') );
+ if ( $deprecated_echo )
+ echo get_trackback_url();
+ else
+ return get_trackback_url();
+}
+
+/**
+ * Generates and displays the RDF for the trackback information of current post.
+ *
+ * Deprecated in 3.0.0, and restored in 3.0.1.
+ *
+ * @since 0.71
+ *
+ * @param int $deprecated Not used (Was $timezone = 0)
+ */
+function trackback_rdf( $deprecated = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.5' );
+
+ if ( false !== stripos($_SERVER['HTTP_USER_AGENT'], 'W3C_Validator') )
+ return;
+
+ echo '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
+ <rdf:Description rdf:about="';
+ the_permalink();
+ echo '"'."\n";
+ echo ' dc:identifier="';
+ the_permalink();
+ echo '"'."\n";
+ echo ' dc:title="'.str_replace('--', '&#x2d;&#x2d;', wptexturize(strip_tags(get_the_title()))).'"'."\n";
+ echo ' trackback:ping="'.get_trackback_url().'"'." />\n";
+ echo '</rdf:RDF>';
+}
+
+/**
+ * Whether the current post is open for comments.
+ *
+ * @since 1.5.0
+ * @uses $post
+ *
+ * @param int $post_id An optional post ID to check instead of the current post.
+ * @return bool True if the comments are open
+ */
+function comments_open( $post_id = null ) {
+
+ $_post = get_post($post_id);
+
+ $open = ( 'open' == $_post->comment_status );
+ return apply_filters( 'comments_open', $open, $post_id );
+}
+
+/**
+ * Whether the current post is open for pings.
+ *
+ * @since 1.5.0
+ * @uses $post
+ *
+ * @param int $post_id An optional post ID to check instead of the current post.
+ * @return bool True if pings are accepted
+ */
+function pings_open( $post_id = null ) {
+
+ $_post = get_post($post_id);
+
+ $open = ( 'open' == $_post->ping_status );
+ return apply_filters( 'pings_open', $open, $post_id );
+}
+
+/**
+ * Displays form token for unfiltered comments.
+ *
+ * Will only display nonce token if the current user has permissions for
+ * unfiltered html. Won't display the token for other users.
+ *
+ * The function was backported to 2.0.10 and was added to versions 2.1.3 and
+ * above. Does not exist in versions prior to 2.0.10 in the 2.0 branch and in
+ * the 2.1 branch, prior to 2.1.3. Technically added in 2.2.0.
+ *
+ * Backported to 2.0.10.
+ *
+ * @since 2.1.3
+ * @uses $post Gets the ID of the current post for the token
+ */
+function wp_comment_form_unfiltered_html_nonce() {
+ $post = get_post();
+ $post_id = $post ? $post->ID : 0;
+
+ if ( current_user_can( 'unfiltered_html' ) ) {
+ wp_nonce_field( 'unfiltered-html-comment_' . $post_id, '_wp_unfiltered_html_comment_disabled', false );
+ echo "<script>(function(){if(window===window.parent){document.getElementById('_wp_unfiltered_html_comment_disabled').name='_wp_unfiltered_html_comment';}})();</script>\n";
+ }
+}
+
+/**
+ * Loads the comment template specified in $file.
+ *
+ * Will not display the comments template if not on single post or page, or if
+ * the post does not have comments.
+ *
+ * Uses the WordPress database object to query for the comments. The comments
+ * are passed through the 'comments_array' filter hook with the list of comments
+ * and the post ID respectively.
+ *
+ * The $file path is passed through a filter hook called, 'comments_template'
+ * which includes the TEMPLATEPATH and $file combined. Tries the $filtered path
+ * first and if it fails it will require the default comment template from the
+ * default theme. If either does not exist, then the WordPress process will be
+ * halted. It is advised for that reason, that the default theme is not deleted.
+ *
+ * @since 1.5.0
+ * @global array $comment List of comment objects for the current post
+ * @uses $wpdb
+ * @uses $post
+ * @uses $withcomments Will not try to get the comments if the post has none.
+ *
+ * @param string $file Optional, default '/comments.php'. The file to load
+ * @param bool $separate_comments Optional, whether to separate the comments by comment type. Default is false.
+ * @return null Returns null if no comments appear
+ */
+function comments_template( $file = '/comments.php', $separate_comments = false ) {
+ global $wp_query, $withcomments, $post, $wpdb, $id, $comment, $user_login, $user_ID, $user_identity, $overridden_cpage;
+
+ if ( !(is_single() || is_page() || $withcomments) || empty($post) )
+ return;
+
+ if ( empty($file) )
+ $file = '/comments.php';
+
+ $req = get_option('require_name_email');
+
+ /**
+ * Comment author information fetched from the comment cookies.
+ *
+ * @uses wp_get_current_commenter()
+ */
+ $commenter = wp_get_current_commenter();
+
+ /**
+ * The name of the current comment author escaped for use in attributes.
+ */
+ $comment_author = $commenter['comment_author']; // Escaped by sanitize_comment_cookies()
+
+ /**
+ * The email address of the current comment author escaped for use in attributes.
+ */
+ $comment_author_email = $commenter['comment_author_email']; // Escaped by sanitize_comment_cookies()
+
+ /**
+ * The url of the current comment author escaped for use in attributes.
+ */
+ $comment_author_url = esc_url($commenter['comment_author_url']);
+
+ /** @todo Use API instead of SELECTs. */
+ if ( $user_ID) {
+ $comments = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND (comment_approved = '1' OR ( user_id = %d AND comment_approved = '0' ) ) ORDER BY comment_date_gmt", $post->ID, $user_ID));
+ } else if ( empty($comment_author) ) {
+ $comments = get_comments( array('post_id' => $post->ID, 'status' => 'approve', 'order' => 'ASC') );
+ } else {
+ $comments = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND ( comment_approved = '1' OR ( comment_author = %s AND comment_author_email = %s AND comment_approved = '0' ) ) ORDER BY comment_date_gmt", $post->ID, wp_specialchars_decode($comment_author,ENT_QUOTES), $comment_author_email));
+ }
+
+ // keep $comments for legacy's sake
+ $wp_query->comments = apply_filters( 'comments_array', $comments, $post->ID );
+ $comments = &$wp_query->comments;
+ $wp_query->comment_count = count($wp_query->comments);
+ update_comment_cache($wp_query->comments);
+
+ if ( $separate_comments ) {
+ $wp_query->comments_by_type = separate_comments($comments);
+ $comments_by_type = &$wp_query->comments_by_type;
+ }
+
+ $overridden_cpage = false;
+ if ( '' == get_query_var('cpage') && get_option('page_comments') ) {
+ set_query_var( 'cpage', 'newest' == get_option('default_comments_page') ? get_comment_pages_count() : 1 );
+ $overridden_cpage = true;
+ }
+
+ if ( !defined('COMMENTS_TEMPLATE') )
+ define('COMMENTS_TEMPLATE', true);
+
+ $include = apply_filters('comments_template', STYLESHEETPATH . $file );
+ if ( file_exists( $include ) )
+ require( $include );
+ elseif ( file_exists( TEMPLATEPATH . $file ) )
+ require( TEMPLATEPATH . $file );
+ else // Backward compat code will be removed in a future release
+ require( ABSPATH . WPINC . '/theme-compat/comments.php');
+}
+
+/**
+ * Displays the JS popup script to show a comment.
+ *
+ * If the $file parameter is empty, then the home page is assumed. The defaults
+ * for the window are 400px by 400px.
+ *
+ * For the comment link popup to work, this function has to be called or the
+ * normal comment link will be assumed.
+ *
+ * @since 0.71
+ * @global string $wpcommentspopupfile The URL to use for the popup window
+ * @global int $wpcommentsjavascript Whether to use JavaScript. Set when function is called
+ *
+ * @param int $width Optional. The width of the popup window
+ * @param int $height Optional. The height of the popup window
+ * @param string $file Optional. Sets the location of the popup window
+ */
+function comments_popup_script($width=400, $height=400, $file='') {
+ global $wpcommentspopupfile, $wpcommentsjavascript;
+
+ if (empty ($file)) {
+ $wpcommentspopupfile = ''; // Use the index.
+ } else {
+ $wpcommentspopupfile = $file;
+ }
+
+ $wpcommentsjavascript = 1;
+ $javascript = "<script type='text/javascript'>\nfunction wpopen (macagna) {\n window.open(macagna, '_blank', 'width=$width,height=$height,scrollbars=yes,status=yes');\n}\n</script>\n";
+ echo $javascript;
+}
+
+/**
+ * Displays the link to the comments popup window for the current post ID.
+ *
+ * Is not meant to be displayed on single posts and pages. Should be used on the
+ * lists of posts
+ *
+ * @since 0.71
+ * @uses $wpcommentspopupfile
+ * @uses $wpcommentsjavascript
+ * @uses $post
+ *
+ * @param string $zero The string to display when no comments
+ * @param string $one The string to display when only one comment is available
+ * @param string $more The string to display when there are more than one comment
+ * @param string $css_class The CSS class to use for comments
+ * @param string $none The string to display when comments have been turned off
+ * @return null Returns null on single posts and pages.
+ */
+function comments_popup_link( $zero = false, $one = false, $more = false, $css_class = '', $none = false ) {
+ global $wpcommentspopupfile, $wpcommentsjavascript;
+
+ $id = get_the_ID();
+
+ if ( false === $zero ) $zero = __( 'No Comments' );
+ if ( false === $one ) $one = __( '1 Comment' );
+ if ( false === $more ) $more = __( '% Comments' );
+ if ( false === $none ) $none = __( 'Comments Off' );
+
+ $number = get_comments_number( $id );
+
+ if ( 0 == $number && !comments_open() && !pings_open() ) {
+ echo '<span' . ((!empty($css_class)) ? ' class="' . esc_attr( $css_class ) . '"' : '') . '>' . $none . '</span>';
+ return;
+ }
+
+ if ( post_password_required() ) {
+ echo __('Enter your password to view comments.');
+ return;
+ }
+
+ echo '<a href="';
+ if ( $wpcommentsjavascript ) {
+ if ( empty( $wpcommentspopupfile ) )
+ $home = home_url();
+ else
+ $home = get_option('siteurl');
+ echo $home . '/' . $wpcommentspopupfile . '?comments_popup=' . $id;
+ echo '" onclick="wpopen(this.href); return false"';
+ } else { // if comments_popup_script() is not in the template, display simple comment link
+ if ( 0 == $number )
+ echo get_permalink() . '#respond';
+ else
+ comments_link();
+ echo '"';
+ }
+
+ if ( !empty( $css_class ) ) {
+ echo ' class="'.$css_class.'" ';
+ }
+ $title = the_title_attribute( array('echo' => 0 ) );
+
+ echo apply_filters( 'comments_popup_link_attributes', '' );
+
+ echo ' title="' . esc_attr( sprintf( __('Comment on %s'), $title ) ) . '">';
+ comments_number( $zero, $one, $more );
+ echo '</a>';
+}
+
+/**
+ * Retrieve HTML content for reply to comment link.
+ *
+ * The default arguments that can be override are 'add_below', 'respond_id',
+ * 'reply_text', 'login_text', and 'depth'. The 'login_text' argument will be
+ * used, if the user must log in or register first before posting a comment. The
+ * 'reply_text' will be used, if they can post a reply. The 'add_below' and
+ * 'respond_id' arguments are for the JavaScript moveAddCommentForm() function
+ * parameters.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Optional. Override default options.
+ * @param int $comment Optional. Comment being replied to.
+ * @param int $post Optional. Post that the comment is going to be displayed on.
+ * @return string|bool|null Link to show comment form, if successful. False, if comments are closed.
+ */
+function get_comment_reply_link($args = array(), $comment = null, $post = null) {
+ global $user_ID;
+
+ $defaults = array('add_below' => 'comment', 'respond_id' => 'respond', 'reply_text' => __('Reply'),
+ 'login_text' => __('Log in to Reply'), 'depth' => 0, 'before' => '', 'after' => '');
+
+ $args = wp_parse_args($args, $defaults);
+
+ if ( 0 == $args['depth'] || $args['max_depth'] <= $args['depth'] )
+ return;
+
+ extract($args, EXTR_SKIP);
+
+ $comment = get_comment($comment);
+ if ( empty($post) )
+ $post = $comment->comment_post_ID;
+ $post = get_post($post);
+
+ if ( !comments_open($post->ID) )
+ return false;
+
+ $link = '';
+
+ if ( get_option('comment_registration') && !$user_ID )
+ $link = '<a rel="nofollow" class="comment-reply-login" href="' . esc_url( wp_login_url( get_permalink() ) ) . '">' . $login_text . '</a>';
+ else
+ $link = "<a class='comment-reply-link' href='" . esc_url( add_query_arg( 'replytocom', $comment->comment_ID ) ) . "#" . $respond_id . "' onclick='return addComment.moveForm(\"$add_below-$comment->comment_ID\", \"$comment->comment_ID\", \"$respond_id\", \"$post->ID\")'>$reply_text</a>";
+ return apply_filters('comment_reply_link', $before . $link . $after, $args, $comment, $post);
+}
+
+/**
+ * Displays the HTML content for reply to comment link.
+ *
+ * @since 2.7.0
+ * @see get_comment_reply_link() Echoes result
+ *
+ * @param array $args Optional. Override default options.
+ * @param int $comment Optional. Comment being replied to.
+ * @param int $post Optional. Post that the comment is going to be displayed on.
+ * @return string|bool|null Link to show comment form, if successful. False, if comments are closed.
+ */
+function comment_reply_link($args = array(), $comment = null, $post = null) {
+ echo get_comment_reply_link($args, $comment, $post);
+}
+
+/**
+ * Retrieve HTML content for reply to post link.
+ *
+ * The default arguments that can be override are 'add_below', 'respond_id',
+ * 'reply_text', 'login_text', and 'depth'. The 'login_text' argument will be
+ * used, if the user must log in or register first before posting a comment. The
+ * 'reply_text' will be used, if they can post a reply. The 'add_below' and
+ * 'respond_id' arguments are for the JavaScript moveAddCommentForm() function
+ * parameters.
+ *
+ * @since 2.7.0
+ *
+ * @param array $args Optional. Override default options.
+ * @param int|object $post Optional. Post that the comment is going to be displayed on. Defaults to current post.
+ * @return string|bool|null Link to show comment form, if successful. False, if comments are closed.
+ */
+function get_post_reply_link($args = array(), $post = null) {
+ global $user_ID;
+
+ $defaults = array('add_below' => 'post', 'respond_id' => 'respond', 'reply_text' => __('Leave a Comment'),
+ 'login_text' => __('Log in to leave a Comment'), 'before' => '', 'after' => '');
+
+ $args = wp_parse_args($args, $defaults);
+ extract($args, EXTR_SKIP);
+ $post = get_post($post);
+
+ if ( !comments_open($post->ID) )
+ return false;
+
+ if ( get_option('comment_registration') && !$user_ID ) {
+ $link = '<a rel="nofollow" href="' . wp_login_url( get_permalink() ) . '">' . $login_text . '</a>';
+ } else {
+ $link = "<a rel='nofollow' class='comment-reply-link' href='" . get_permalink($post->ID) . "#$respond_id' onclick='return addComment.moveForm(\"$add_below-$post->ID\", \"0\", \"$respond_id\", \"$post->ID\")'>$reply_text</a>";
+ }
+ return apply_filters('post_comments_link', $before . $link . $after, $post);
+}
+
+/**
+ * Displays the HTML content for reply to post link.
+ * @since 2.7.0
+ * @see get_post_reply_link()
+ *
+ * @param array $args Optional. Override default options.
+ * @param int|object $post Optional. Post that the comment is going to be displayed on.
+ * @return string|bool|null Link to show comment form, if successful. False, if comments are closed.
+ */
+function post_reply_link($args = array(), $post = null) {
+ echo get_post_reply_link($args, $post);
+}
+
+/**
+ * Retrieve HTML content for cancel comment reply link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $text Optional. Text to display for cancel reply link.
+ */
+function get_cancel_comment_reply_link($text = '') {
+ if ( empty($text) )
+ $text = __('Click here to cancel reply.');
+
+ $style = isset($_GET['replytocom']) ? '' : ' style="display:none;"';
+ $link = esc_html( remove_query_arg('replytocom') ) . '#respond';
+ return apply_filters('cancel_comment_reply_link', '<a rel="nofollow" id="cancel-comment-reply-link" href="' . $link . '"' . $style . '>' . $text . '</a>', $link, $text);
+}
+
+/**
+ * Display HTML content for cancel comment reply link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $text Optional. Text to display for cancel reply link.
+ */
+function cancel_comment_reply_link($text = '') {
+ echo get_cancel_comment_reply_link($text);
+}
+
+/**
+ * Retrieve hidden input HTML for replying to comments.
+ *
+ * @since 3.0.0
+ *
+ * @return string Hidden input HTML for replying to comments
+ */
+function get_comment_id_fields( $id = 0 ) {
+ if ( empty( $id ) )
+ $id = get_the_ID();
+
+ $replytoid = isset($_GET['replytocom']) ? (int) $_GET['replytocom'] : 0;
+ $result = "<input type='hidden' name='comment_post_ID' value='$id' id='comment_post_ID' />\n";
+ $result .= "<input type='hidden' name='comment_parent' id='comment_parent' value='$replytoid' />\n";
+ return apply_filters('comment_id_fields', $result, $id, $replytoid);
+}
+
+/**
+ * Output hidden input HTML for replying to comments.
+ *
+ * @since 2.7.0
+ * @see get_comment_id_fields() Echoes result
+ */
+function comment_id_fields( $id = 0 ) {
+ echo get_comment_id_fields( $id );
+}
+
+/**
+ * Display text based on comment reply status. Only affects users with Javascript disabled.
+ *
+ * @since 2.7.0
+ *
+ * @param string $noreplytext Optional. Text to display when not replying to a comment.
+ * @param string $replytext Optional. Text to display when replying to a comment. Accepts "%s" for the author of the comment being replied to.
+ * @param string $linktoparent Optional. Boolean to control making the author's name a link to their comment.
+ */
+function comment_form_title( $noreplytext = false, $replytext = false, $linktoparent = true ) {
+ global $comment;
+
+ if ( false === $noreplytext ) $noreplytext = __( 'Leave a Reply' );
+ if ( false === $replytext ) $replytext = __( 'Leave a Reply to %s' );
+
+ $replytoid = isset($_GET['replytocom']) ? (int) $_GET['replytocom'] : 0;
+
+ if ( 0 == $replytoid )
+ echo $noreplytext;
+ else {
+ $comment = get_comment($replytoid);
+ $author = ( $linktoparent ) ? '<a href="#comment-' . get_comment_ID() . '">' . get_comment_author() . '</a>' : get_comment_author();
+ printf( $replytext, $author );
+ }
+}
+
+/**
+ * HTML comment list class.
+ *
+ * @package WordPress
+ * @uses Walker
+ * @since 2.7.0
+ */
+class Walker_Comment extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.7.0
+ * @var string
+ */
+ var $tree_type = 'comment';
+
+ /**
+ * @see Walker::$db_fields
+ * @since 2.7.0
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'comment_parent', 'id' => 'comment_ID');
+
+ /**
+ * @see Walker::start_lvl()
+ * @since 2.7.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of comment.
+ * @param array $args Uses 'style' argument for type of HTML list.
+ */
+ function start_lvl( &$output, $depth = 0, $args = array() ) {
+ $GLOBALS['comment_depth'] = $depth + 1;
+
+ switch ( $args['style'] ) {
+ case 'div':
+ break;
+ case 'ol':
+ echo '<ol class="children">' . "\n";
+ break;
+ default:
+ case 'ul':
+ echo '<ul class="children">' . "\n";
+ break;
+ }
+ }
+
+ /**
+ * @see Walker::end_lvl()
+ * @since 2.7.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of comment.
+ * @param array $args Will only append content if style argument value is 'ol' or 'ul'.
+ */
+ function end_lvl( &$output, $depth = 0, $args = array() ) {
+ $GLOBALS['comment_depth'] = $depth + 1;
+
+ switch ( $args['style'] ) {
+ case 'div':
+ break;
+ case 'ol':
+ echo "</ol><!-- .children -->\n";
+ break;
+ default:
+ case 'ul':
+ echo "</ul><!-- .children -->\n";
+ break;
+ }
+ }
+
+ /**
+ * This function is designed to enhance Walker::display_element() to
+ * display children of higher nesting levels than selected inline on
+ * the highest depth level displayed. This prevents them being orphaned
+ * at the end of the comment list.
+ *
+ * Example: max_depth = 2, with 5 levels of nested content.
+ * 1
+ * 1.1
+ * 1.1.1
+ * 1.1.1.1
+ * 1.1.1.1.1
+ * 1.1.2
+ * 1.1.2.1
+ * 2
+ * 2.2
+ *
+ */
+ function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
+
+ if ( !$element )
+ return;
+
+ $id_field = $this->db_fields['id'];
+ $id = $element->$id_field;
+
+ parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
+
+ // If we're at the max depth, and the current element still has children, loop over those and display them at this level
+ // This is to prevent them being orphaned to the end of the list.
+ if ( $max_depth <= $depth + 1 && isset( $children_elements[$id]) ) {
+ foreach ( $children_elements[ $id ] as $child )
+ $this->display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
+
+ unset( $children_elements[ $id ] );
+ }
+
+ }
+
+ /**
+ * @see Walker::start_el()
+ * @since 2.7.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $comment Comment data object.
+ * @param int $depth Depth of comment in reference to parents.
+ * @param array $args
+ */
+ function start_el( &$output, $comment, $depth = 0, $args = array(), $id = 0 ) {
+ $depth++;
+ $GLOBALS['comment_depth'] = $depth;
+ $GLOBALS['comment'] = $comment;
+
+ if ( !empty( $args['callback'] ) ) {
+ call_user_func( $args['callback'], $comment, $args, $depth );
+ return;
+ }
+
+ if ( ( 'pingback' == $comment->comment_type || 'trackback' == $comment->comment_type ) && $args['short_ping'] ) {
+ $this->ping( $comment, $depth, $args );
+ } elseif ( 'html5' === $args['format'] ) {
+ $this->html5_comment( $comment, $depth, $args );
+ } else {
+ $this->comment( $comment, $depth, $args );
+ }
+ }
+
+ /**
+ * @see Walker::end_el()
+ * @since 2.7.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $comment
+ * @param int $depth Depth of comment.
+ * @param array $args
+ */
+ function end_el( &$output, $comment, $depth = 0, $args = array() ) {
+ if ( !empty( $args['end-callback'] ) ) {
+ call_user_func( $args['end-callback'], $comment, $args, $depth );
+ return;
+ }
+ if ( 'div' == $args['style'] )
+ echo "</div><!-- #comment-## -->\n";
+ else
+ echo "</li><!-- #comment-## -->\n";
+ }
+
+ /**
+ * @since 3.6
+ * @access protected
+ *
+ * @param object $comment
+ * @param int $depth Depth of comment.
+ * @param array $args
+ */
+ protected function ping( $comment, $depth, $args ) {
+ $tag = ( 'div' == $args['style'] ) ? 'div' : 'li';
+?>
+ <<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class(); ?>>
+ <div class="comment-body">
+ <?php _e( 'Pingback:' ); ?> <?php comment_author_link(); ?> <?php edit_comment_link( __( 'Edit' ), '<span class="edit-link">', '</span>' ); ?>
+ </div>
+<?php
+ }
+
+ /**
+ * @since 3.6
+ * @access protected
+ *
+ * @param object $comment Comment to display.
+ * @param int $depth Depth of comment.
+ * @param array $args Optional args.
+ */
+ protected function comment( $comment, $depth, $args ) {
+ if ( 'div' == $args['style'] ) {
+ $tag = 'div';
+ $add_below = 'comment';
+ } else {
+ $tag = 'li';
+ $add_below = 'div-comment';
+ }
+?>
+ <<?php echo $tag; ?> <?php comment_class( empty( $args['has_children'] ) ? '' : 'parent' ); ?> id="comment-<?php comment_ID(); ?>">
+ <?php if ( 'div' != $args['style'] ) : ?>
+ <div id="div-comment-<?php comment_ID(); ?>" class="comment-body">
+ <?php endif; ?>
+ <div class="comment-author vcard">
+ <?php if ( 0 != $args['avatar_size'] ) echo get_avatar( $comment, $args['avatar_size'] ); ?>
+ <?php printf( __( '<cite class="fn">%s</cite> <span class="says">says:</span>' ), get_comment_author_link() ); ?>
+ </div>
+ <?php if ( '0' == $comment->comment_approved ) : ?>
+ <em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.' ) ?></em>
+ <br />
+ <?php endif; ?>
+
+ <div class="comment-meta commentmetadata"><a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
+ <?php
+ /* translators: 1: date, 2: time */
+ printf( __( '%1$s at %2$s' ), get_comment_date(), get_comment_time() ); ?></a><?php edit_comment_link( __( '(Edit)' ), '&nbsp;&nbsp;', '' );
+ ?>
+ </div>
+
+ <?php comment_text() ?>
+
+ <div class="reply">
+ <?php comment_reply_link( array_merge( $args, array( 'add_below' => $add_below, 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
+ </div>
+ <?php if ( 'div' != $args['style'] ) : ?>
+ </div>
+ <?php endif; ?>
+<?php
+ }
+
+ /**
+ * @since 3.6
+ * @access protected
+ *
+ * @param object $comment Comment to display.
+ * @param int $depth Depth of comment.
+ * @param array $args Optional args.
+ */
+ protected function html5_comment( $comment, $depth, $args ) {
+ $tag = ( 'div' === $args['style'] ) ? 'div' : 'li';
+?>
+ <<?php echo $tag; ?> id="comment-<?php comment_ID(); ?>" <?php comment_class( empty( $args['has_children'] ) ? '' : 'parent' ); ?>>
+ <article id="div-comment-<?php comment_ID(); ?>" class="comment-body">
+ <footer class="comment-meta">
+ <div class="comment-author vcard">
+ <?php if ( 0 != $args['avatar_size'] ) echo get_avatar( $comment, $args['avatar_size'] ); ?>
+ <?php printf( __( '%s <span class="says">says:</span>' ), sprintf( '<b class="fn">%s</b>', get_comment_author_link() ) ); ?>
+ </div><!-- .comment-author -->
+
+ <div class="comment-metadata">
+ <a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
+ <time datetime="<?php comment_time( 'c' ); ?>">
+ <?php printf( _x( '%1$s at %2$s', '1: date, 2: time' ), get_comment_date(), get_comment_time() ); ?>
+ </time>
+ </a>
+ <?php edit_comment_link( __( 'Edit' ), '<span class="edit-link">', '</span>' ); ?>
+ </div><!-- .comment-metadata -->
+
+ <?php if ( '0' == $comment->comment_approved ) : ?>
+ <p class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.' ); ?></p>
+ <?php endif; ?>
+ </footer><!-- .comment-meta -->
+
+ <div class="comment-content">
+ <?php comment_text(); ?>
+ </div><!-- .comment-content -->
+
+ <div class="reply">
+ <?php comment_reply_link( array_merge( $args, array( 'add_below' => 'div-comment', 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
+ </div><!-- .reply -->
+ </article><!-- .comment-body -->
+<?php
+ }
+}
+
+/**
+ * List comments
+ *
+ * Used in the comments.php template to list comments for a particular post
+ *
+ * @since 2.7.0
+ * @uses Walker_Comment
+ *
+ * @param string|array $args Formatting options
+ * @param array $comments Optional array of comment objects. Defaults to $wp_query->comments
+ */
+function wp_list_comments($args = array(), $comments = null ) {
+ global $wp_query, $comment_alt, $comment_depth, $comment_thread_alt, $overridden_cpage, $in_comment_loop;
+
+ $in_comment_loop = true;
+
+ $comment_alt = $comment_thread_alt = 0;
+ $comment_depth = 1;
+
+ $defaults = array(
+ 'walker' => null,
+ 'max_depth' => '',
+ 'style' => 'ul',
+ 'callback' => null,
+ 'end-callback' => null,
+ 'type' => 'all',
+ 'page' => '',
+ 'per_page' => '',
+ 'avatar_size' => 32,
+ 'reverse_top_level' => null,
+ 'reverse_children' => '',
+ 'format' => current_theme_supports( 'html5', 'comment-list' ) ? 'html5' : 'xhtml',
+ 'short_ping' => false,
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ // Figure out what comments we'll be looping through ($_comments)
+ if ( null !== $comments ) {
+ $comments = (array) $comments;
+ if ( empty($comments) )
+ return;
+ if ( 'all' != $r['type'] ) {
+ $comments_by_type = separate_comments($comments);
+ if ( empty($comments_by_type[$r['type']]) )
+ return;
+ $_comments = $comments_by_type[$r['type']];
+ } else {
+ $_comments = $comments;
+ }
+ } else {
+ if ( empty($wp_query->comments) )
+ return;
+ if ( 'all' != $r['type'] ) {
+ if ( empty($wp_query->comments_by_type) )
+ $wp_query->comments_by_type = separate_comments($wp_query->comments);
+ if ( empty($wp_query->comments_by_type[$r['type']]) )
+ return;
+ $_comments = $wp_query->comments_by_type[$r['type']];
+ } else {
+ $_comments = $wp_query->comments;
+ }
+ }
+
+ if ( '' === $r['per_page'] && get_option('page_comments') )
+ $r['per_page'] = get_query_var('comments_per_page');
+
+ if ( empty($r['per_page']) ) {
+ $r['per_page'] = 0;
+ $r['page'] = 0;
+ }
+
+ if ( '' === $r['max_depth'] ) {
+ if ( get_option('thread_comments') )
+ $r['max_depth'] = get_option('thread_comments_depth');
+ else
+ $r['max_depth'] = -1;
+ }
+
+ if ( '' === $r['page'] ) {
+ if ( empty($overridden_cpage) ) {
+ $r['page'] = get_query_var('cpage');
+ } else {
+ $threaded = ( -1 != $r['max_depth'] );
+ $r['page'] = ( 'newest' == get_option('default_comments_page') ) ? get_comment_pages_count($_comments, $r['per_page'], $threaded) : 1;
+ set_query_var( 'cpage', $r['page'] );
+ }
+ }
+ // Validation check
+ $r['page'] = intval($r['page']);
+ if ( 0 == $r['page'] && 0 != $r['per_page'] )
+ $r['page'] = 1;
+
+ if ( null === $r['reverse_top_level'] )
+ $r['reverse_top_level'] = ( 'desc' == get_option('comment_order') );
+
+ extract( $r, EXTR_SKIP );
+
+ if ( empty($walker) )
+ $walker = new Walker_Comment;
+
+ $walker->paged_walk($_comments, $max_depth, $page, $per_page, $r);
+ $wp_query->max_num_comment_pages = $walker->max_pages;
+
+ $in_comment_loop = false;
+}
+
+/**
+ * Outputs a complete commenting form for use within a template.
+ * Most strings and form fields may be controlled through the $args array passed
+ * into the function, while you may also choose to use the comment_form_default_fields
+ * filter to modify the array of default fields if you'd just like to add a new
+ * one or remove a single field. All fields are also individually passed through
+ * a filter of the form comment_form_field_$name where $name is the key used
+ * in the array of fields.
+ *
+ * @since 3.0.0
+ * @param array $args Options for strings, fields etc in the form
+ * @param mixed $post_id Post ID to generate the form for, uses the current post if null
+ * @return void
+ */
+function comment_form( $args = array(), $post_id = null ) {
+ if ( null === $post_id )
+ $post_id = get_the_ID();
+ else
+ $id = $post_id;
+
+ $commenter = wp_get_current_commenter();
+ $user = wp_get_current_user();
+ $user_identity = $user->exists() ? $user->display_name : '';
+
+ if ( ! isset( $args['format'] ) )
+ $args['format'] = current_theme_supports( 'html5', 'comment-form' ) ? 'html5' : 'xhtml';
+
+ $req = get_option( 'require_name_email' );
+ $aria_req = ( $req ? " aria-required='true'" : '' );
+ $html5 = 'html5' === $args['format'];
+ $fields = array(
+ 'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
+ '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' /></p>',
+ 'email' => '<p class="comment-form-email"><label for="email">' . __( 'Email' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label> ' .
+ '<input id="email" name="email" ' . ( $html5 ? 'type="email"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . ' /></p>',
+ 'url' => '<p class="comment-form-url"><label for="url">' . __( 'Website' ) . '</label> ' .
+ '<input id="url" name="url" ' . ( $html5 ? 'type="url"' : 'type="text"' ) . ' value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p>',
+ );
+
+ $required_text = sprintf( ' ' . __('Required fields are marked %s'), '<span class="required">*</span>' );
+ $defaults = array(
+ 'fields' => apply_filters( 'comment_form_default_fields', $fields ),
+ 'comment_field' => '<p class="comment-form-comment"><label for="comment">' . _x( 'Comment', 'noun' ) . '</label> <textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p>',
+ 'must_log_in' => '<p class="must-log-in">' . sprintf( __( 'You must be <a href="%s">logged in</a> to post a comment.' ), wp_login_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) ) ) . '</p>',
+ 'logged_in_as' => '<p class="logged-in-as">' . sprintf( __( 'Logged in as <a href="%1$s">%2$s</a>. <a href="%3$s" title="Log out of this account">Log out?</a>' ), get_edit_user_link(), $user_identity, wp_logout_url( apply_filters( 'the_permalink', get_permalink( $post_id ) ) ) ) . '</p>',
+ 'comment_notes_before' => '<p class="comment-notes">' . __( 'Your email address will not be published.' ) . ( $req ? $required_text : '' ) . '</p>',
+ 'comment_notes_after' => '<p class="form-allowed-tags">' . sprintf( __( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes: %s' ), ' <code>' . allowed_tags() . '</code>' ) . '</p>',
+ 'id_form' => 'commentform',
+ 'id_submit' => 'submit',
+ 'title_reply' => __( 'Leave a Reply' ),
+ 'title_reply_to' => __( 'Leave a Reply to %s' ),
+ 'cancel_reply_link' => __( 'Cancel reply' ),
+ 'label_submit' => __( 'Post Comment' ),
+ 'format' => 'xhtml',
+ );
+
+ $args = wp_parse_args( $args, apply_filters( 'comment_form_defaults', $defaults ) );
+
+ ?>
+ <?php if ( comments_open( $post_id ) ) : ?>
+ <?php do_action( 'comment_form_before' ); ?>
+ <div id="respond" class="comment-respond">
+ <h3 id="reply-title" class="comment-reply-title"><?php comment_form_title( $args['title_reply'], $args['title_reply_to'] ); ?> <small><?php cancel_comment_reply_link( $args['cancel_reply_link'] ); ?></small></h3>
+ <?php if ( get_option( 'comment_registration' ) && !is_user_logged_in() ) : ?>
+ <?php echo $args['must_log_in']; ?>
+ <?php do_action( 'comment_form_must_log_in_after' ); ?>
+ <?php else : ?>
+ <form action="<?php echo site_url( '/wp-comments-post.php' ); ?>" method="post" id="<?php echo esc_attr( $args['id_form'] ); ?>" class="comment-form"<?php echo $html5 ? ' novalidate' : ''; ?>>
+ <?php do_action( 'comment_form_top' ); ?>
+ <?php if ( is_user_logged_in() ) : ?>
+ <?php echo apply_filters( 'comment_form_logged_in', $args['logged_in_as'], $commenter, $user_identity ); ?>
+ <?php do_action( 'comment_form_logged_in_after', $commenter, $user_identity ); ?>
+ <?php else : ?>
+ <?php echo $args['comment_notes_before']; ?>
+ <?php
+ do_action( 'comment_form_before_fields' );
+ foreach ( (array) $args['fields'] as $name => $field ) {
+ echo apply_filters( "comment_form_field_{$name}", $field ) . "\n";
+ }
+ do_action( 'comment_form_after_fields' );
+ ?>
+ <?php endif; ?>
+ <?php echo apply_filters( 'comment_form_field_comment', $args['comment_field'] ); ?>
+ <?php echo $args['comment_notes_after']; ?>
+ <p class="form-submit">
+ <input name="submit" type="submit" id="<?php echo esc_attr( $args['id_submit'] ); ?>" value="<?php echo esc_attr( $args['label_submit'] ); ?>" />
+ <?php comment_id_fields( $post_id ); ?>
+ </p>
+ <?php do_action( 'comment_form', $post_id ); ?>
+ </form>
+ <?php endif; ?>
+ </div><!-- #respond -->
+ <?php do_action( 'comment_form_after' ); ?>
+ <?php else : ?>
+ <?php do_action( 'comment_form_comments_closed' ); ?>
+ <?php endif; ?>
+ <?php
+}
diff --git a/src/wp-includes/comment.php b/src/wp-includes/comment.php
new file mode 100644
index 0000000000..312f384a79
--- /dev/null
+++ b/src/wp-includes/comment.php
@@ -0,0 +1,2083 @@
+<?php
+/**
+ * Manages WordPress comments
+ *
+ * @package WordPress
+ * @subpackage Comment
+ */
+
+/**
+ * Checks whether a comment passes internal checks to be allowed to add.
+ *
+ * If comment moderation is set in the administration, then all comments,
+ * regardless of their type and whitelist will be set to false. If the number of
+ * links exceeds the amount in the administration, then the check fails. If any
+ * of the parameter contents match the blacklist of words, then the check fails.
+ *
+ * If the number of links exceeds the amount in the administration, then the
+ * check fails. If any of the parameter contents match the blacklist of words,
+ * then the check fails.
+ *
+ * If the comment author was approved before, then the comment is
+ * automatically whitelisted.
+ *
+ * If none of the checks fail, then the failback is to set the check to pass
+ * (return true).
+ *
+ * @since 1.2.0
+ * @uses $wpdb
+ *
+ * @param string $author Comment Author's name
+ * @param string $email Comment Author's email
+ * @param string $url Comment Author's URL
+ * @param string $comment Comment contents
+ * @param string $user_ip Comment Author's IP address
+ * @param string $user_agent Comment Author's User Agent
+ * @param string $comment_type Comment type, either user submitted comment,
+ * trackback, or pingback
+ * @return bool Whether the checks passed (true) and the comments should be
+ * displayed or set to moderated
+ */
+function check_comment($author, $email, $url, $comment, $user_ip, $user_agent, $comment_type) {
+ global $wpdb;
+
+ if ( 1 == get_option('comment_moderation') )
+ return false; // If moderation is set to manual
+
+ $comment = apply_filters( 'comment_text', $comment );
+
+ // Check # of external links
+ if ( $max_links = get_option( 'comment_max_links' ) ) {
+ $num_links = preg_match_all( '/<a [^>]*href/i', $comment, $out );
+ $num_links = apply_filters( 'comment_max_links_url', $num_links, $url ); // provide for counting of $url as a link
+ if ( $num_links >= $max_links )
+ return false;
+ }
+
+ $mod_keys = trim(get_option('moderation_keys'));
+ if ( !empty($mod_keys) ) {
+ $words = explode("\n", $mod_keys );
+
+ foreach ( (array) $words as $word) {
+ $word = trim($word);
+
+ // Skip empty lines
+ if ( empty($word) )
+ continue;
+
+ // Do some escaping magic so that '#' chars in the
+ // spam words don't break things:
+ $word = preg_quote($word, '#');
+
+ $pattern = "#$word#i";
+ if ( preg_match($pattern, $author) ) return false;
+ if ( preg_match($pattern, $email) ) return false;
+ if ( preg_match($pattern, $url) ) return false;
+ if ( preg_match($pattern, $comment) ) return false;
+ if ( preg_match($pattern, $user_ip) ) return false;
+ if ( preg_match($pattern, $user_agent) ) return false;
+ }
+ }
+
+ // Comment whitelisting:
+ if ( 1 == get_option('comment_whitelist')) {
+ if ( 'trackback' != $comment_type && 'pingback' != $comment_type && $author != '' && $email != '' ) {
+ // expected_slashed ($author, $email)
+ $ok_to_comment = $wpdb->get_var("SELECT comment_approved FROM $wpdb->comments WHERE comment_author = '$author' AND comment_author_email = '$email' and comment_approved = '1' LIMIT 1");
+ if ( ( 1 == $ok_to_comment ) &&
+ ( empty($mod_keys) || false === strpos( $email, $mod_keys) ) )
+ return true;
+ else
+ return false;
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Retrieve the approved comments for post $post_id.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @param int $post_id The ID of the post
+ * @return array $comments The approved comments
+ */
+function get_approved_comments($post_id) {
+ global $wpdb;
+ return $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1' ORDER BY comment_date", $post_id));
+}
+
+/**
+ * Retrieves comment data given a comment ID or comment object.
+ *
+ * If an object is passed then the comment data will be cached and then returned
+ * after being passed through a filter. If the comment is empty, then the global
+ * comment variable will be used, if it is set.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @param object|string|int $comment Comment to retrieve.
+ * @param string $output Optional. OBJECT or ARRAY_A or ARRAY_N constants.
+ * @return object|array|null Depends on $output value.
+ */
+function get_comment(&$comment, $output = OBJECT) {
+ global $wpdb;
+ $null = null;
+
+ if ( empty($comment) ) {
+ if ( isset($GLOBALS['comment']) )
+ $_comment = & $GLOBALS['comment'];
+ else
+ $_comment = null;
+ } elseif ( is_object($comment) ) {
+ wp_cache_add($comment->comment_ID, $comment, 'comment');
+ $_comment = $comment;
+ } else {
+ if ( isset($GLOBALS['comment']) && ($GLOBALS['comment']->comment_ID == $comment) ) {
+ $_comment = & $GLOBALS['comment'];
+ } elseif ( ! $_comment = wp_cache_get($comment, 'comment') ) {
+ $_comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_ID = %d LIMIT 1", $comment));
+ if ( ! $_comment )
+ return $null;
+ wp_cache_add($_comment->comment_ID, $_comment, 'comment');
+ }
+ }
+
+ $_comment = apply_filters('get_comment', $_comment);
+
+ if ( $output == OBJECT ) {
+ return $_comment;
+ } elseif ( $output == ARRAY_A ) {
+ $__comment = get_object_vars($_comment);
+ return $__comment;
+ } elseif ( $output == ARRAY_N ) {
+ $__comment = array_values(get_object_vars($_comment));
+ return $__comment;
+ } else {
+ return $_comment;
+ }
+}
+
+/**
+ * Retrieve a list of comments.
+ *
+ * The comment list can be for the blog as a whole or for an individual post.
+ *
+ * The list of comment arguments are 'status', 'orderby', 'comment_date_gmt',
+ * 'order', 'number', 'offset', and 'post_id'.
+ *
+ * @since 2.7.0
+ * @uses $wpdb
+ *
+ * @param mixed $args Optional. Array or string of options to override defaults.
+ * @return array List of comments.
+ */
+function get_comments( $args = '' ) {
+ $query = new WP_Comment_Query;
+ return $query->query( $args );
+}
+
+/**
+ * WordPress Comment Query class.
+ *
+ * @since 3.1.0
+ */
+class WP_Comment_Query {
+ /**
+ * Metadata query container
+ *
+ * @since 3.5.0
+ * @access public
+ * @var object WP_Meta_Query
+ */
+ var $meta_query = false;
+
+ /**
+ * Execute the query
+ *
+ * @since 3.1.0
+ *
+ * @param string|array $query_vars
+ * @return int|array
+ */
+ function query( $query_vars ) {
+ global $wpdb;
+
+ $defaults = array(
+ 'author_email' => '',
+ 'ID' => '',
+ 'karma' => '',
+ 'number' => '',
+ 'offset' => '',
+ 'orderby' => '',
+ 'order' => 'DESC',
+ 'parent' => '',
+ 'post_ID' => '',
+ 'post_id' => 0,
+ 'post_author' => '',
+ 'post_name' => '',
+ 'post_parent' => '',
+ 'post_status' => '',
+ 'post_type' => '',
+ 'status' => '',
+ 'type' => '',
+ 'user_id' => '',
+ 'search' => '',
+ 'count' => false,
+ 'meta_key' => '',
+ 'meta_value' => '',
+ 'meta_query' => '',
+ );
+
+ $groupby = '';
+
+ $this->query_vars = wp_parse_args( $query_vars, $defaults );
+
+ // Parse meta query
+ $this->meta_query = new WP_Meta_Query();
+ $this->meta_query->parse_query_vars( $this->query_vars );
+
+ do_action_ref_array( 'pre_get_comments', array( &$this ) );
+ extract( $this->query_vars, EXTR_SKIP );
+
+ // $args can be whatever, only use the args defined in defaults to compute the key
+ $key = md5( serialize( compact(array_keys($defaults)) ) );
+ $last_changed = wp_cache_get( 'last_changed', 'comment' );
+ if ( ! $last_changed ) {
+ $last_changed = microtime();
+ wp_cache_set( 'last_changed', $last_changed, 'comment' );
+ }
+ $cache_key = "get_comments:$key:$last_changed";
+
+ if ( $cache = wp_cache_get( $cache_key, 'comment' ) )
+ return $cache;
+
+ $post_id = absint($post_id);
+
+ if ( 'hold' == $status )
+ $approved = "comment_approved = '0'";
+ elseif ( 'approve' == $status )
+ $approved = "comment_approved = '1'";
+ elseif ( ! empty( $status ) && 'all' != $status )
+ $approved = $wpdb->prepare( "comment_approved = %s", $status );
+ else
+ $approved = "( comment_approved = '0' OR comment_approved = '1' )";
+
+ $order = ( 'ASC' == strtoupper($order) ) ? 'ASC' : 'DESC';
+
+ if ( ! empty( $orderby ) ) {
+ $ordersby = is_array($orderby) ? $orderby : preg_split('/[,\s]/', $orderby);
+ $allowed_keys = array(
+ 'comment_agent',
+ 'comment_approved',
+ 'comment_author',
+ 'comment_author_email',
+ 'comment_author_IP',
+ 'comment_author_url',
+ 'comment_content',
+ 'comment_date',
+ 'comment_date_gmt',
+ 'comment_ID',
+ 'comment_karma',
+ 'comment_parent',
+ 'comment_post_ID',
+ 'comment_type',
+ 'user_id',
+ );
+ if ( ! empty( $this->query_vars['meta_key'] ) ) {
+ $allowed_keys[] = $this->query_vars['meta_key'];
+ $allowed_keys[] = 'meta_value';
+ $allowed_keys[] = 'meta_value_num';
+ }
+ $ordersby = array_intersect( $ordersby, $allowed_keys );
+ foreach ( $ordersby as $key => $value ) {
+ if ( $value == $this->query_vars['meta_key'] || $value == 'meta_value' ) {
+ $ordersby[ $key ] = "$wpdb->commentmeta.meta_value";
+ } elseif ( $value == 'meta_value_num' ) {
+ $ordersby[ $key ] = "$wpdb->commentmeta.meta_value+0";
+ }
+ }
+ $orderby = empty( $ordersby ) ? 'comment_date_gmt' : implode(', ', $ordersby);
+ } else {
+ $orderby = 'comment_date_gmt';
+ }
+
+ $number = absint($number);
+ $offset = absint($offset);
+
+ if ( !empty($number) ) {
+ if ( $offset )
+ $limits = 'LIMIT ' . $offset . ',' . $number;
+ else
+ $limits = 'LIMIT ' . $number;
+ } else {
+ $limits = '';
+ }
+
+ if ( $count )
+ $fields = 'COUNT(*)';
+ else
+ $fields = '*';
+
+ $join = '';
+ $where = $approved;
+
+ if ( ! empty($post_id) )
+ $where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
+ if ( '' !== $author_email )
+ $where .= $wpdb->prepare( ' AND comment_author_email = %s', $author_email );
+ if ( '' !== $karma )
+ $where .= $wpdb->prepare( ' AND comment_karma = %d', $karma );
+ if ( 'comment' == $type ) {
+ $where .= " AND comment_type = ''";
+ } elseif( 'pings' == $type ) {
+ $where .= ' AND comment_type IN ("pingback", "trackback")';
+ } elseif ( ! empty( $type ) ) {
+ $where .= $wpdb->prepare( ' AND comment_type = %s', $type );
+ }
+ if ( '' !== $parent )
+ $where .= $wpdb->prepare( ' AND comment_parent = %d', $parent );
+ if ( '' !== $user_id )
+ $where .= $wpdb->prepare( ' AND user_id = %d', $user_id );
+ if ( '' !== $search )
+ $where .= $this->get_search_sql( $search, array( 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_content' ) );
+
+ $post_fields = array_filter( compact( array( 'post_author', 'post_name', 'post_parent', 'post_status', 'post_type', ) ) );
+ if ( ! empty( $post_fields ) ) {
+ $join = "JOIN $wpdb->posts ON $wpdb->posts.ID = $wpdb->comments.comment_post_ID";
+ foreach( $post_fields as $field_name => $field_value )
+ $where .= $wpdb->prepare( " AND {$wpdb->posts}.{$field_name} = %s", $field_value );
+ }
+
+ if ( ! empty( $this->meta_query->queries ) ) {
+ $clauses = $this->meta_query->get_sql( 'comment', $wpdb->comments, 'comment_ID', $this );
+ $join .= $clauses['join'];
+ $where .= $clauses['where'];
+ $groupby = "{$wpdb->comments}.comment_ID";
+ }
+
+ $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits', 'groupby' );
+ $clauses = apply_filters_ref_array( 'comments_clauses', array( compact( $pieces ), &$this ) );
+ foreach ( $pieces as $piece )
+ $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
+
+ if ( $groupby )
+ $groupby = 'GROUP BY ' . $groupby;
+
+ $query = "SELECT $fields FROM $wpdb->comments $join WHERE $where $groupby ORDER BY $orderby $order $limits";
+
+ if ( $count )
+ return $wpdb->get_var( $query );
+
+ $comments = $wpdb->get_results( $query );
+ $comments = apply_filters_ref_array( 'the_comments', array( $comments, &$this ) );
+
+ wp_cache_add( $cache_key, $comments, 'comment' );
+
+ return $comments;
+ }
+
+ /*
+ * Used internally to generate an SQL string for searching across multiple columns
+ *
+ * @access protected
+ * @since 3.1.0
+ *
+ * @param string $string
+ * @param array $cols
+ * @return string
+ */
+ function get_search_sql( $string, $cols ) {
+ $string = esc_sql( like_escape( $string ) );
+
+ $searches = array();
+ foreach ( $cols as $col )
+ $searches[] = "$col LIKE '%$string%'";
+
+ return ' AND (' . implode(' OR ', $searches) . ')';
+ }
+}
+
+/**
+ * Retrieve all of the WordPress supported comment statuses.
+ *
+ * Comments have a limited set of valid status values, this provides the comment
+ * status values and descriptions.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.7.0
+ *
+ * @return array List of comment statuses.
+ */
+function get_comment_statuses() {
+ $status = array(
+ 'hold' => __('Unapproved'),
+ /* translators: comment status */
+ 'approve' => _x('Approved', 'adjective'),
+ /* translators: comment status */
+ 'spam' => _x('Spam', 'adjective'),
+ );
+
+ return $status;
+}
+
+/**
+ * The date the last comment was modified.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
+ * or 'server' locations.
+ * @return string Last comment modified date.
+ */
+function get_lastcommentmodified($timezone = 'server') {
+ global $wpdb;
+ static $cache_lastcommentmodified = array();
+
+ if ( isset($cache_lastcommentmodified[$timezone]) )
+ return $cache_lastcommentmodified[$timezone];
+
+ $add_seconds_server = date('Z');
+
+ switch ( strtolower($timezone)) {
+ case 'gmt':
+ $lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
+ break;
+ case 'blog':
+ $lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
+ break;
+ case 'server':
+ $lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
+ break;
+ }
+
+ $cache_lastcommentmodified[$timezone] = $lastcommentmodified;
+
+ return $lastcommentmodified;
+}
+
+/**
+ * The amount of comments in a post or total comments.
+ *
+ * A lot like {@link wp_count_comments()}, in that they both return comment
+ * stats (albeit with different types). The {@link wp_count_comments()} actual
+ * caches, but this function does not.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Optional. Comment amount in post if > 0, else total comments blog wide.
+ * @return array The amount of spam, approved, awaiting moderation, and total comments.
+ */
+function get_comment_count( $post_id = 0 ) {
+ global $wpdb;
+
+ $post_id = (int) $post_id;
+
+ $where = '';
+ if ( $post_id > 0 ) {
+ $where = $wpdb->prepare("WHERE comment_post_ID = %d", $post_id);
+ }
+
+ $totals = (array) $wpdb->get_results("
+ SELECT comment_approved, COUNT( * ) AS total
+ FROM {$wpdb->comments}
+ {$where}
+ GROUP BY comment_approved
+ ", ARRAY_A);
+
+ $comment_count = array(
+ "approved" => 0,
+ "awaiting_moderation" => 0,
+ "spam" => 0,
+ "total_comments" => 0
+ );
+
+ foreach ( $totals as $row ) {
+ switch ( $row['comment_approved'] ) {
+ case 'spam':
+ $comment_count['spam'] = $row['total'];
+ $comment_count["total_comments"] += $row['total'];
+ break;
+ case 1:
+ $comment_count['approved'] = $row['total'];
+ $comment_count['total_comments'] += $row['total'];
+ break;
+ case 0:
+ $comment_count['awaiting_moderation'] = $row['total'];
+ $comment_count['total_comments'] += $row['total'];
+ break;
+ default:
+ break;
+ }
+ }
+
+ return $comment_count;
+}
+
+//
+// Comment meta functions
+//
+
+/**
+ * Add meta data field to a comment.
+ *
+ * @since 2.9.0
+ * @uses add_metadata
+ * @link http://codex.wordpress.org/Function_Reference/add_comment_meta
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return int|bool Meta ID on success, false on failure.
+ */
+function add_comment_meta($comment_id, $meta_key, $meta_value, $unique = false) {
+ return add_metadata('comment', $comment_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a comment.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 2.9.0
+ * @uses delete_metadata
+ * @link http://codex.wordpress.org/Function_Reference/delete_comment_meta
+ *
+ * @param int $comment_id comment ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool True on success, false on failure.
+ */
+function delete_comment_meta($comment_id, $meta_key, $meta_value = '') {
+ return delete_metadata('comment', $comment_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve comment meta field for a comment.
+ *
+ * @since 2.9.0
+ * @uses get_metadata
+ * @link http://codex.wordpress.org/Function_Reference/get_comment_meta
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
+ * is true.
+ */
+function get_comment_meta($comment_id, $key = '', $single = false) {
+ return get_metadata('comment', $comment_id, $key, $single);
+}
+
+/**
+ * Update comment meta field based on comment ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and comment ID.
+ *
+ * If the meta field for the comment does not exist, it will be added.
+ *
+ * @since 2.9.0
+ * @uses update_metadata
+ * @link http://codex.wordpress.org/Function_Reference/update_comment_meta
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool True on success, false on failure.
+ */
+function update_comment_meta($comment_id, $meta_key, $meta_value, $prev_value = '') {
+ return update_metadata('comment', $comment_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Sets the cookies used to store an unauthenticated commentator's identity. Typically used
+ * to recall previous comments by this commentator that are still held in moderation.
+ *
+ * @param object $comment Comment object.
+ * @param object $user Comment author's object.
+ *
+ * @since 3.4.0
+ */
+function wp_set_comment_cookies($comment, $user) {
+ if ( $user->exists() )
+ return;
+
+ $comment_cookie_lifetime = apply_filters('comment_cookie_lifetime', 30000000);
+ setcookie('comment_author_' . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie('comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
+ setcookie('comment_author_url_' . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN);
+}
+
+/**
+ * Sanitizes the cookies sent to the user already.
+ *
+ * Will only do anything if the cookies have already been created for the user.
+ * Mostly used after cookies had been sent to use elsewhere.
+ *
+ * @since 2.0.4
+ */
+function sanitize_comment_cookies() {
+ if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) ) {
+ $comment_author = apply_filters('pre_comment_author_name', $_COOKIE['comment_author_'.COOKIEHASH]);
+ $comment_author = wp_unslash($comment_author);
+ $comment_author = esc_attr($comment_author);
+ $_COOKIE['comment_author_'.COOKIEHASH] = $comment_author;
+ }
+
+ if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) ) {
+ $comment_author_email = apply_filters('pre_comment_author_email', $_COOKIE['comment_author_email_'.COOKIEHASH]);
+ $comment_author_email = wp_unslash($comment_author_email);
+ $comment_author_email = esc_attr($comment_author_email);
+ $_COOKIE['comment_author_email_'.COOKIEHASH] = $comment_author_email;
+ }
+
+ if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) ) {
+ $comment_author_url = apply_filters('pre_comment_author_url', $_COOKIE['comment_author_url_'.COOKIEHASH]);
+ $comment_author_url = wp_unslash($comment_author_url);
+ $_COOKIE['comment_author_url_'.COOKIEHASH] = $comment_author_url;
+ }
+}
+
+/**
+ * Validates whether this comment is allowed to be made.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses apply_filters() Calls 'pre_comment_approved' hook on the type of comment
+ * @uses apply_filters() Calls 'comment_duplicate_trigger' hook on commentdata.
+ * @uses do_action() Calls 'check_comment_flood' hook on $comment_author_IP, $comment_author_email, and $comment_date_gmt
+ *
+ * @param array $commentdata Contains information on the comment
+ * @return mixed Signifies the approval status (0|1|'spam')
+ */
+function wp_allow_comment($commentdata) {
+ global $wpdb;
+ extract($commentdata, EXTR_SKIP);
+
+ // Simple duplicate check
+ // expected_slashed ($comment_post_ID, $comment_author, $comment_author_email, $comment_content)
+ $dupe = $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = %s AND comment_approved != 'trash' AND ( comment_author = %s ", wp_unslash( $comment_post_ID ), wp_unslash( $comment_parent ), wp_unslash( $comment_author ) );
+ if ( $comment_author_email )
+ $dupe .= $wpdb->prepare( "OR comment_author_email = %s ", wp_unslash( $comment_author_email ) );
+ $dupe .= $wpdb->prepare( ") AND comment_content = %s LIMIT 1", wp_unslash( $comment_content ) );
+ if ( $wpdb->get_var($dupe) ) {
+ do_action( 'comment_duplicate_trigger', $commentdata );
+ if ( defined('DOING_AJAX') )
+ die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
+
+ wp_die( __('Duplicate comment detected; it looks as though you&#8217;ve already said that!') );
+ }
+
+ do_action( 'check_comment_flood', $comment_author_IP, $comment_author_email, $comment_date_gmt );
+
+ if ( ! empty( $user_id ) ) {
+ $user = get_userdata( $user_id );
+ $post_author = $wpdb->get_var($wpdb->prepare("SELECT post_author FROM $wpdb->posts WHERE ID = %d LIMIT 1", $comment_post_ID));
+ }
+
+ if ( isset( $user ) && ( $user_id == $post_author || $user->has_cap( 'moderate_comments' ) ) ) {
+ // The author and the admins get respect.
+ $approved = 1;
+ } else {
+ // Everyone else's comments will be checked.
+ if ( check_comment($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent, $comment_type) )
+ $approved = 1;
+ else
+ $approved = 0;
+ if ( wp_blacklist_check($comment_author, $comment_author_email, $comment_author_url, $comment_content, $comment_author_IP, $comment_agent) )
+ $approved = 'spam';
+ }
+
+ $approved = apply_filters( 'pre_comment_approved', $approved, $commentdata );
+ return $approved;
+}
+
+/**
+ * Check whether comment flooding is occurring.
+ *
+ * Won't run, if current user can manage options, so to not block
+ * administrators.
+ *
+ * @since 2.3.0
+ * @uses $wpdb
+ * @uses apply_filters() Calls 'comment_flood_filter' filter with first
+ * parameter false, last comment timestamp, new comment timestamp.
+ * @uses do_action() Calls 'comment_flood_trigger' action with parameters with
+ * last comment timestamp and new comment timestamp.
+ *
+ * @param string $ip Comment IP.
+ * @param string $email Comment author email address.
+ * @param string $date MySQL time string.
+ */
+function check_comment_flood_db( $ip, $email, $date ) {
+ global $wpdb;
+ if ( current_user_can( 'manage_options' ) )
+ return; // don't throttle admins
+ $hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
+ if ( $lasttime = $wpdb->get_var( $wpdb->prepare( "SELECT `comment_date_gmt` FROM `$wpdb->comments` WHERE `comment_date_gmt` >= %s AND ( `comment_author_IP` = %s OR `comment_author_email` = %s ) ORDER BY `comment_date_gmt` DESC LIMIT 1", $hour_ago, $ip, $email ) ) ) {
+ $time_lastcomment = mysql2date('U', $lasttime, false);
+ $time_newcomment = mysql2date('U', $date, false);
+ $flood_die = apply_filters('comment_flood_filter', false, $time_lastcomment, $time_newcomment);
+ if ( $flood_die ) {
+ do_action('comment_flood_trigger', $time_lastcomment, $time_newcomment);
+
+ if ( defined('DOING_AJAX') )
+ die( __('You are posting comments too quickly. Slow down.') );
+
+ wp_die( __('You are posting comments too quickly. Slow down.'), '', array('response' => 403) );
+ }
+ }
+}
+
+/**
+ * Separates an array of comments into an array keyed by comment_type.
+ *
+ * @since 2.7.0
+ *
+ * @param array $comments Array of comments
+ * @return array Array of comments keyed by comment_type.
+ */
+function separate_comments(&$comments) {
+ $comments_by_type = array('comment' => array(), 'trackback' => array(), 'pingback' => array(), 'pings' => array());
+ $count = count($comments);
+ for ( $i = 0; $i < $count; $i++ ) {
+ $type = $comments[$i]->comment_type;
+ if ( empty($type) )
+ $type = 'comment';
+ $comments_by_type[$type][] = &$comments[$i];
+ if ( 'trackback' == $type || 'pingback' == $type )
+ $comments_by_type['pings'][] = &$comments[$i];
+ }
+
+ return $comments_by_type;
+}
+
+/**
+ * Calculate the total number of comment pages.
+ *
+ * @since 2.7.0
+ * @uses get_query_var() Used to fill in the default for $per_page parameter.
+ * @uses get_option() Used to fill in defaults for parameters.
+ * @uses Walker_Comment
+ *
+ * @param array $comments Optional array of comment objects. Defaults to $wp_query->comments
+ * @param int $per_page Optional comments per page.
+ * @param boolean $threaded Optional control over flat or threaded comments.
+ * @return int Number of comment pages.
+ */
+function get_comment_pages_count( $comments = null, $per_page = null, $threaded = null ) {
+ global $wp_query;
+
+ if ( null === $comments && null === $per_page && null === $threaded && !empty($wp_query->max_num_comment_pages) )
+ return $wp_query->max_num_comment_pages;
+
+ if ( !$comments || !is_array($comments) )
+ $comments = $wp_query->comments;
+
+ if ( empty($comments) )
+ return 0;
+
+ if ( !isset($per_page) )
+ $per_page = (int) get_query_var('comments_per_page');
+ if ( 0 === $per_page )
+ $per_page = (int) get_option('comments_per_page');
+ if ( 0 === $per_page )
+ return 1;
+
+ if ( !isset($threaded) )
+ $threaded = get_option('thread_comments');
+
+ if ( $threaded ) {
+ $walker = new Walker_Comment;
+ $count = ceil( $walker->get_number_of_root_elements( $comments ) / $per_page );
+ } else {
+ $count = ceil( count( $comments ) / $per_page );
+ }
+
+ return $count;
+}
+
+/**
+ * Calculate what page number a comment will appear on for comment paging.
+ *
+ * @since 2.7.0
+ * @uses get_comment() Gets the full comment of the $comment_ID parameter.
+ * @uses get_option() Get various settings to control function and defaults.
+ * @uses get_page_of_comment() Used to loop up to top level comment.
+ *
+ * @param int $comment_ID Comment ID.
+ * @param array $args Optional args.
+ * @return int|null Comment page number or null on error.
+ */
+function get_page_of_comment( $comment_ID, $args = array() ) {
+ global $wpdb;
+
+ if ( !$comment = get_comment( $comment_ID ) )
+ return;
+
+ $defaults = array( 'type' => 'all', 'page' => '', 'per_page' => '', 'max_depth' => '' );
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( '' === $args['per_page'] && get_option('page_comments') )
+ $args['per_page'] = get_query_var('comments_per_page');
+ if ( empty($args['per_page']) ) {
+ $args['per_page'] = 0;
+ $args['page'] = 0;
+ }
+ if ( $args['per_page'] < 1 )
+ return 1;
+
+ if ( '' === $args['max_depth'] ) {
+ if ( get_option('thread_comments') )
+ $args['max_depth'] = get_option('thread_comments_depth');
+ else
+ $args['max_depth'] = -1;
+ }
+
+ // Find this comment's top level parent if threading is enabled
+ if ( $args['max_depth'] > 1 && 0 != $comment->comment_parent )
+ return get_page_of_comment( $comment->comment_parent, $args );
+
+ $allowedtypes = array(
+ 'comment' => '',
+ 'pingback' => 'pingback',
+ 'trackback' => 'trackback',
+ );
+
+ $comtypewhere = ( 'all' != $args['type'] && isset($allowedtypes[$args['type']]) ) ? " AND comment_type = '" . $allowedtypes[$args['type']] . "'" : '';
+
+ // Count comments older than this one
+ $oldercoms = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_parent = 0 AND comment_approved = '1' AND comment_date_gmt < '%s'" . $comtypewhere, $comment->comment_post_ID, $comment->comment_date_gmt ) );
+
+ // No older comments? Then it's page #1.
+ if ( 0 == $oldercoms )
+ return 1;
+
+ // Divide comments older than this one by comments per page to get this comment's page number
+ return ceil( ( $oldercoms + 1 ) / $args['per_page'] );
+}
+
+/**
+ * Does comment contain blacklisted characters or words.
+ *
+ * @since 1.5.0
+ * @uses do_action() Calls 'wp_blacklist_check' hook for all parameters.
+ *
+ * @param string $author The author of the comment
+ * @param string $email The email of the comment
+ * @param string $url The url used in the comment
+ * @param string $comment The comment content
+ * @param string $user_ip The comment author IP address
+ * @param string $user_agent The author's browser user agent
+ * @return bool True if comment contains blacklisted content, false if comment does not
+ */
+function wp_blacklist_check($author, $email, $url, $comment, $user_ip, $user_agent) {
+ do_action('wp_blacklist_check', $author, $email, $url, $comment, $user_ip, $user_agent);
+
+ $mod_keys = trim( get_option('blacklist_keys') );
+ if ( '' == $mod_keys )
+ return false; // If moderation keys are empty
+ $words = explode("\n", $mod_keys );
+
+ foreach ( (array) $words as $word ) {
+ $word = trim($word);
+
+ // Skip empty lines
+ if ( empty($word) ) { continue; }
+
+ // Do some escaping magic so that '#' chars in the
+ // spam words don't break things:
+ $word = preg_quote($word, '#');
+
+ $pattern = "#$word#i";
+ if (
+ preg_match($pattern, $author)
+ || preg_match($pattern, $email)
+ || preg_match($pattern, $url)
+ || preg_match($pattern, $comment)
+ || preg_match($pattern, $user_ip)
+ || preg_match($pattern, $user_agent)
+ )
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Retrieve total comments for blog or single post.
+ *
+ * The properties of the returned object contain the 'moderated', 'approved',
+ * and spam comments for either the entire blog or single post. Those properties
+ * contain the amount of comments that match the status. The 'total_comments'
+ * property contains the integer of total comments.
+ *
+ * The comment stats are cached and then retrieved, if they already exist in the
+ * cache.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @return object Comment stats.
+ */
+function wp_count_comments( $post_id = 0 ) {
+ global $wpdb;
+
+ $post_id = (int) $post_id;
+
+ $stats = apply_filters('wp_count_comments', array(), $post_id);
+ if ( !empty($stats) )
+ return $stats;
+
+ $count = wp_cache_get("comments-{$post_id}", 'counts');
+
+ if ( false !== $count )
+ return $count;
+
+ $where = '';
+ if ( $post_id > 0 )
+ $where = $wpdb->prepare( "WHERE comment_post_ID = %d", $post_id );
+
+ $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );
+
+ $total = 0;
+ $approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
+ foreach ( (array) $count as $row ) {
+ // Don't count post-trashed toward totals
+ if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] )
+ $total += $row['num_comments'];
+ if ( isset( $approved[$row['comment_approved']] ) )
+ $stats[$approved[$row['comment_approved']]] = $row['num_comments'];
+ }
+
+ $stats['total_comments'] = $total;
+ foreach ( $approved as $key ) {
+ if ( empty($stats[$key]) )
+ $stats[$key] = 0;
+ }
+
+ $stats = (object) $stats;
+ wp_cache_set("comments-{$post_id}", $stats, 'counts');
+
+ return $stats;
+}
+
+/**
+ * Trashes or deletes a comment.
+ *
+ * The comment is moved to trash instead of permanently deleted unless trash is
+ * disabled, item is already in the trash, or $force_delete is true.
+ *
+ * The post comment count will be updated if the comment was approved and has a
+ * post ID available.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'delete_comment' hook on comment ID
+ * @uses do_action() Calls 'deleted_comment' hook on comment ID after deletion, on success
+ * @uses do_action() Calls 'wp_set_comment_status' hook on comment ID with 'delete' set for the second parameter
+ * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
+ *
+ * @param int $comment_id Comment ID
+ * @param bool $force_delete Whether to bypass trash and force deletion. Default is false.
+ * @return bool True on success, false on failure.
+ */
+function wp_delete_comment($comment_id, $force_delete = false) {
+ global $wpdb;
+ if (!$comment = get_comment($comment_id))
+ return false;
+
+ if ( !$force_delete && EMPTY_TRASH_DAYS && !in_array( wp_get_comment_status($comment_id), array( 'trash', 'spam' ) ) )
+ return wp_trash_comment($comment_id);
+
+ do_action('delete_comment', $comment_id);
+
+ // Move children up a level.
+ $children = $wpdb->get_col( $wpdb->prepare("SELECT comment_ID FROM $wpdb->comments WHERE comment_parent = %d", $comment_id) );
+ if ( !empty($children) ) {
+ $wpdb->update($wpdb->comments, array('comment_parent' => $comment->comment_parent), array('comment_parent' => $comment_id));
+ clean_comment_cache($children);
+ }
+
+ // Delete metadata
+ $meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->commentmeta WHERE comment_id = %d", $comment_id ) );
+ foreach ( $meta_ids as $mid )
+ delete_metadata_by_mid( 'comment', $mid );
+
+ if ( ! $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment_id ) ) )
+ return false;
+ do_action('deleted_comment', $comment_id);
+
+ $post_id = $comment->comment_post_ID;
+ if ( $post_id && $comment->comment_approved == 1 )
+ wp_update_comment_count($post_id);
+
+ clean_comment_cache($comment_id);
+
+ do_action('wp_set_comment_status', $comment_id, 'delete');
+ wp_transition_comment_status('delete', $comment->comment_approved, $comment);
+ return true;
+}
+
+/**
+ * Moves a comment to the Trash
+ *
+ * If trash is disabled, comment is permanently deleted.
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'trash_comment' before trashing
+ * @uses do_action() on 'trashed_comment' after trashing
+ * @uses wp_delete_comment() if trash is disabled
+ *
+ * @param int $comment_id Comment ID.
+ * @return bool True on success, false on failure.
+ */
+function wp_trash_comment($comment_id) {
+ if ( !EMPTY_TRASH_DAYS )
+ return wp_delete_comment($comment_id, true);
+
+ if ( !$comment = get_comment($comment_id) )
+ return false;
+
+ do_action('trash_comment', $comment_id);
+
+ if ( wp_set_comment_status($comment_id, 'trash') ) {
+ add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
+ add_comment_meta($comment_id, '_wp_trash_meta_time', time() );
+ do_action('trashed_comment', $comment_id);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Removes a comment from the Trash
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'untrash_comment' before untrashing
+ * @uses do_action() on 'untrashed_comment' after untrashing
+ *
+ * @param int $comment_id Comment ID.
+ * @return bool True on success, false on failure.
+ */
+function wp_untrash_comment($comment_id) {
+ if ( ! (int)$comment_id )
+ return false;
+
+ do_action('untrash_comment', $comment_id);
+
+ $status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
+ if ( empty($status) )
+ $status = '0';
+
+ if ( wp_set_comment_status($comment_id, $status) ) {
+ delete_comment_meta($comment_id, '_wp_trash_meta_time');
+ delete_comment_meta($comment_id, '_wp_trash_meta_status');
+ do_action('untrashed_comment', $comment_id);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Marks a comment as Spam
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'spam_comment' before spamming
+ * @uses do_action() on 'spammed_comment' after spamming
+ *
+ * @param int $comment_id Comment ID.
+ * @return bool True on success, false on failure.
+ */
+function wp_spam_comment($comment_id) {
+ if ( !$comment = get_comment($comment_id) )
+ return false;
+
+ do_action('spam_comment', $comment_id);
+
+ if ( wp_set_comment_status($comment_id, 'spam') ) {
+ add_comment_meta($comment_id, '_wp_trash_meta_status', $comment->comment_approved);
+ do_action('spammed_comment', $comment_id);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Removes a comment from the Spam
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'unspam_comment' before unspamming
+ * @uses do_action() on 'unspammed_comment' after unspamming
+ *
+ * @param int $comment_id Comment ID.
+ * @return bool True on success, false on failure.
+ */
+function wp_unspam_comment($comment_id) {
+ if ( ! (int)$comment_id )
+ return false;
+
+ do_action('unspam_comment', $comment_id);
+
+ $status = (string) get_comment_meta($comment_id, '_wp_trash_meta_status', true);
+ if ( empty($status) )
+ $status = '0';
+
+ if ( wp_set_comment_status($comment_id, $status) ) {
+ delete_comment_meta($comment_id, '_wp_trash_meta_status');
+ do_action('unspammed_comment', $comment_id);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * The status of a comment by ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $comment_id Comment ID
+ * @return string|bool Status might be 'trash', 'approved', 'unapproved', 'spam'. False on failure.
+ */
+function wp_get_comment_status($comment_id) {
+ $comment = get_comment($comment_id);
+ if ( !$comment )
+ return false;
+
+ $approved = $comment->comment_approved;
+
+ if ( $approved == null )
+ return false;
+ elseif ( $approved == '1' )
+ return 'approved';
+ elseif ( $approved == '0' )
+ return 'unapproved';
+ elseif ( $approved == 'spam' )
+ return 'spam';
+ elseif ( $approved == 'trash' )
+ return 'trash';
+ else
+ return false;
+}
+
+/**
+ * Call hooks for when a comment status transition occurs.
+ *
+ * Calls hooks for comment status transitions. If the new comment status is not the same
+ * as the previous comment status, then two hooks will be ran, the first is
+ * 'transition_comment_status' with new status, old status, and comment data. The
+ * next action called is 'comment_OLDSTATUS_to_NEWSTATUS' the NEWSTATUS is the
+ * $new_status parameter and the OLDSTATUS is $old_status parameter; it has the
+ * comment data.
+ *
+ * The final action will run whether or not the comment statuses are the same. The
+ * action is named 'comment_NEWSTATUS_COMMENTTYPE', NEWSTATUS is from the $new_status
+ * parameter and COMMENTTYPE is comment_type comment data.
+ *
+ * @since 2.7.0
+ *
+ * @param string $new_status New comment status.
+ * @param string $old_status Previous comment status.
+ * @param object $comment Comment data.
+ */
+function wp_transition_comment_status($new_status, $old_status, $comment) {
+ // Translate raw statuses to human readable formats for the hooks
+ // This is not a complete list of comment status, it's only the ones that need to be renamed
+ $comment_statuses = array(
+ 0 => 'unapproved',
+ 'hold' => 'unapproved', // wp_set_comment_status() uses "hold"
+ 1 => 'approved',
+ 'approve' => 'approved', // wp_set_comment_status() uses "approve"
+ );
+ if ( isset($comment_statuses[$new_status]) ) $new_status = $comment_statuses[$new_status];
+ if ( isset($comment_statuses[$old_status]) ) $old_status = $comment_statuses[$old_status];
+
+ // Call the hooks
+ if ( $new_status != $old_status ) {
+ do_action('transition_comment_status', $new_status, $old_status, $comment);
+ do_action("comment_{$old_status}_to_{$new_status}", $comment);
+ }
+ do_action("comment_{$new_status}_{$comment->comment_type}", $comment->comment_ID, $comment);
+}
+
+/**
+ * Get current commenter's name, email, and URL.
+ *
+ * Expects cookies content to already be sanitized. User of this function might
+ * wish to recheck the returned array for validity.
+ *
+ * @see sanitize_comment_cookies() Use to sanitize cookies
+ *
+ * @since 2.0.4
+ *
+ * @return array Comment author, email, url respectively.
+ */
+function wp_get_current_commenter() {
+ // Cookies should already be sanitized.
+
+ $comment_author = '';
+ if ( isset($_COOKIE['comment_author_'.COOKIEHASH]) )
+ $comment_author = $_COOKIE['comment_author_'.COOKIEHASH];
+
+ $comment_author_email = '';
+ if ( isset($_COOKIE['comment_author_email_'.COOKIEHASH]) )
+ $comment_author_email = $_COOKIE['comment_author_email_'.COOKIEHASH];
+
+ $comment_author_url = '';
+ if ( isset($_COOKIE['comment_author_url_'.COOKIEHASH]) )
+ $comment_author_url = $_COOKIE['comment_author_url_'.COOKIEHASH];
+
+ return apply_filters('wp_get_current_commenter', compact('comment_author', 'comment_author_email', 'comment_author_url'));
+}
+
+/**
+ * Inserts a comment to the database.
+ *
+ * The available comment data key names are 'comment_author_IP', 'comment_date',
+ * 'comment_date_gmt', 'comment_parent', 'comment_approved', and 'user_id'.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @param array $commentdata Contains information on the comment.
+ * @return int The new comment's ID.
+ */
+function wp_insert_comment($commentdata) {
+ global $wpdb;
+ extract(wp_unslash($commentdata), EXTR_SKIP);
+
+ if ( ! isset($comment_author_IP) )
+ $comment_author_IP = '';
+ if ( ! isset($comment_date) )
+ $comment_date = current_time('mysql');
+ if ( ! isset($comment_date_gmt) )
+ $comment_date_gmt = get_gmt_from_date($comment_date);
+ if ( ! isset($comment_parent) )
+ $comment_parent = 0;
+ if ( ! isset($comment_approved) )
+ $comment_approved = 1;
+ if ( ! isset($comment_karma) )
+ $comment_karma = 0;
+ if ( ! isset($user_id) )
+ $user_id = 0;
+ if ( ! isset($comment_type) )
+ $comment_type = '';
+
+ $data = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_author_IP', 'comment_date', 'comment_date_gmt', 'comment_content', 'comment_karma', 'comment_approved', 'comment_agent', 'comment_type', 'comment_parent', 'user_id');
+ $wpdb->insert($wpdb->comments, $data);
+
+ $id = (int) $wpdb->insert_id;
+
+ if ( $comment_approved == 1 )
+ wp_update_comment_count($comment_post_ID);
+
+ $comment = get_comment($id);
+ do_action('wp_insert_comment', $id, $comment);
+
+ wp_cache_set( 'last_changed', microtime(), 'comment' );
+
+ return $id;
+}
+
+/**
+ * Filters and sanitizes comment data.
+ *
+ * Sets the comment data 'filtered' field to true when finished. This can be
+ * checked as to whether the comment should be filtered and to keep from
+ * filtering the same comment more than once.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'pre_user_id' hook on comment author's user ID
+ * @uses apply_filters() Calls 'pre_comment_user_agent' hook on comment author's user agent
+ * @uses apply_filters() Calls 'pre_comment_author_name' hook on comment author's name
+ * @uses apply_filters() Calls 'pre_comment_content' hook on the comment's content
+ * @uses apply_filters() Calls 'pre_comment_user_ip' hook on comment author's IP
+ * @uses apply_filters() Calls 'pre_comment_author_url' hook on comment author's URL
+ * @uses apply_filters() Calls 'pre_comment_author_email' hook on comment author's email address
+ *
+ * @param array $commentdata Contains information on the comment.
+ * @return array Parsed comment information.
+ */
+function wp_filter_comment($commentdata) {
+ if ( isset($commentdata['user_ID']) )
+ $commentdata['user_id'] = apply_filters('pre_user_id', $commentdata['user_ID']);
+ elseif ( isset($commentdata['user_id']) )
+ $commentdata['user_id'] = apply_filters('pre_user_id', $commentdata['user_id']);
+ $commentdata['comment_agent'] = apply_filters('pre_comment_user_agent', ( isset( $commentdata['comment_agent'] ) ? $commentdata['comment_agent'] : '' ) );
+ $commentdata['comment_author'] = apply_filters('pre_comment_author_name', $commentdata['comment_author']);
+ $commentdata['comment_content'] = apply_filters('pre_comment_content', $commentdata['comment_content']);
+ $commentdata['comment_author_IP'] = apply_filters('pre_comment_user_ip', $commentdata['comment_author_IP']);
+ $commentdata['comment_author_url'] = apply_filters('pre_comment_author_url', $commentdata['comment_author_url']);
+ $commentdata['comment_author_email'] = apply_filters('pre_comment_author_email', $commentdata['comment_author_email']);
+ $commentdata['filtered'] = true;
+ return $commentdata;
+}
+
+/**
+ * Whether comment should be blocked because of comment flood.
+ *
+ * @since 2.1.0
+ *
+ * @param bool $block Whether plugin has already blocked comment.
+ * @param int $time_lastcomment Timestamp for last comment.
+ * @param int $time_newcomment Timestamp for new comment.
+ * @return bool Whether comment should be blocked.
+ */
+function wp_throttle_comment_flood($block, $time_lastcomment, $time_newcomment) {
+ if ( $block ) // a plugin has already blocked... we'll let that decision stand
+ return $block;
+ if ( ($time_newcomment - $time_lastcomment) < 15 )
+ return true;
+ return false;
+}
+
+/**
+ * Adds a new comment to the database.
+ *
+ * Filters new comment to ensure that the fields are sanitized and valid before
+ * inserting comment into database. Calls 'comment_post' action with comment ID
+ * and whether comment is approved by WordPress. Also has 'preprocess_comment'
+ * filter for processing the comment data before the function handles it.
+ *
+ * We use REMOTE_ADDR here directly. If you are behind a proxy, you should ensure
+ * that it is properly set, such as in wp-config.php, for your environment.
+ * See {@link http://core.trac.wordpress.org/ticket/9235}
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'preprocess_comment' hook on $commentdata parameter array before processing
+ * @uses do_action() Calls 'comment_post' hook on $comment_ID returned from adding the comment and if the comment was approved.
+ * @uses wp_filter_comment() Used to filter comment before adding comment.
+ * @uses wp_allow_comment() checks to see if comment is approved.
+ * @uses wp_insert_comment() Does the actual comment insertion to the database.
+ *
+ * @param array $commentdata Contains information on the comment.
+ * @return int The ID of the comment after adding.
+ */
+function wp_new_comment( $commentdata ) {
+ $commentdata = apply_filters('preprocess_comment', $commentdata);
+
+ $commentdata['comment_post_ID'] = (int) $commentdata['comment_post_ID'];
+ if ( isset($commentdata['user_ID']) )
+ $commentdata['user_id'] = $commentdata['user_ID'] = (int) $commentdata['user_ID'];
+ elseif ( isset($commentdata['user_id']) )
+ $commentdata['user_id'] = (int) $commentdata['user_id'];
+
+ $commentdata['comment_parent'] = isset($commentdata['comment_parent']) ? absint($commentdata['comment_parent']) : 0;
+ $parent_status = ( 0 < $commentdata['comment_parent'] ) ? wp_get_comment_status($commentdata['comment_parent']) : '';
+ $commentdata['comment_parent'] = ( 'approved' == $parent_status || 'unapproved' == $parent_status ) ? $commentdata['comment_parent'] : 0;
+
+ $commentdata['comment_author_IP'] = preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] );
+ $commentdata['comment_agent'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ) : '';
+
+ $commentdata['comment_date'] = current_time('mysql');
+ $commentdata['comment_date_gmt'] = current_time('mysql', 1);
+
+ $commentdata = wp_filter_comment($commentdata);
+
+ $commentdata['comment_approved'] = wp_allow_comment($commentdata);
+
+ $comment_ID = wp_insert_comment($commentdata);
+
+ do_action('comment_post', $comment_ID, $commentdata['comment_approved']);
+
+ if ( 'spam' !== $commentdata['comment_approved'] ) { // If it's spam save it silently for later crunching
+ if ( '0' == $commentdata['comment_approved'] )
+ wp_notify_moderator($comment_ID);
+
+ $post = get_post($commentdata['comment_post_ID']); // Don't notify if it's your own comment
+
+ if ( get_option('comments_notify') && $commentdata['comment_approved'] && ( ! isset( $commentdata['user_id'] ) || $post->post_author != $commentdata['user_id'] ) )
+ wp_notify_postauthor($comment_ID, isset( $commentdata['comment_type'] ) ? $commentdata['comment_type'] : '' );
+ }
+
+ return $comment_ID;
+}
+
+/**
+ * Sets the status of a comment.
+ *
+ * The 'wp_set_comment_status' action is called after the comment is handled.
+ * If the comment status is not in the list, then false is returned.
+ *
+ * @since 1.0.0
+ * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
+ *
+ * @param int $comment_id Comment ID.
+ * @param string $comment_status New comment status, either 'hold', 'approve', 'spam', or 'trash'.
+ * @param bool $wp_error Whether to return a WP_Error object if there is a failure. Default is false.
+ * @return bool|WP_Error True on success, false or WP_Error on failure.
+ */
+function wp_set_comment_status($comment_id, $comment_status, $wp_error = false) {
+ global $wpdb;
+
+ $status = '0';
+ switch ( $comment_status ) {
+ case 'hold':
+ case '0':
+ $status = '0';
+ break;
+ case 'approve':
+ case '1':
+ $status = '1';
+ if ( get_option('comments_notify') ) {
+ $comment = get_comment($comment_id);
+ wp_notify_postauthor($comment_id, $comment->comment_type);
+ }
+ break;
+ case 'spam':
+ $status = 'spam';
+ break;
+ case 'trash':
+ $status = 'trash';
+ break;
+ default:
+ return false;
+ }
+
+ $comment_old = clone get_comment($comment_id);
+
+ if ( !$wpdb->update( $wpdb->comments, array('comment_approved' => $status), array('comment_ID' => $comment_id) ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_update_error', __('Could not update comment status'), $wpdb->last_error);
+ else
+ return false;
+ }
+
+ clean_comment_cache($comment_id);
+
+ $comment = get_comment($comment_id);
+
+ do_action('wp_set_comment_status', $comment_id, $comment_status);
+ wp_transition_comment_status($comment_status, $comment_old->comment_approved, $comment);
+
+ wp_update_comment_count($comment->comment_post_ID);
+
+ return true;
+}
+
+/**
+ * Updates an existing comment in the database.
+ *
+ * Filters the comment and makes sure certain fields are valid before updating.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses wp_transition_comment_status() Passes new and old comment status along with $comment object
+ *
+ * @param array $commentarr Contains information on the comment.
+ * @return int Comment was updated if value is 1, or was not updated if value is 0.
+ */
+function wp_update_comment($commentarr) {
+ global $wpdb;
+
+ // First, get all of the original fields
+ $comment = get_comment($commentarr['comment_ID'], ARRAY_A);
+
+ // Escape data pulled from DB.
+ $comment = wp_slash($comment);
+
+ $old_status = $comment['comment_approved'];
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $commentarr = array_merge($comment, $commentarr);
+
+ $commentarr = wp_filter_comment( $commentarr );
+
+ // Now extract the merged array.
+ extract(wp_unslash($commentarr), EXTR_SKIP);
+
+ $comment_content = apply_filters('comment_save_pre', $comment_content);
+
+ $comment_date_gmt = get_gmt_from_date($comment_date);
+
+ if ( !isset($comment_approved) )
+ $comment_approved = 1;
+ else if ( 'hold' == $comment_approved )
+ $comment_approved = 0;
+ else if ( 'approve' == $comment_approved )
+ $comment_approved = 1;
+
+ $data = compact( 'comment_content', 'comment_author', 'comment_author_email', 'comment_approved', 'comment_karma', 'comment_author_url', 'comment_date', 'comment_date_gmt', 'comment_parent' );
+ $rval = $wpdb->update( $wpdb->comments, $data, compact( 'comment_ID' ) );
+
+ clean_comment_cache($comment_ID);
+ wp_update_comment_count($comment_post_ID);
+ do_action('edit_comment', $comment_ID);
+ $comment = get_comment($comment_ID);
+ wp_transition_comment_status($comment->comment_approved, $old_status, $comment);
+ return $rval;
+}
+
+/**
+ * Whether to defer comment counting.
+ *
+ * When setting $defer to true, all post comment counts will not be updated
+ * until $defer is set to false. When $defer is set to false, then all
+ * previously deferred updated post comment counts will then be automatically
+ * updated without having to call wp_update_comment_count() after.
+ *
+ * @since 2.5.0
+ * @staticvar bool $_defer
+ *
+ * @param bool $defer
+ * @return unknown
+ */
+function wp_defer_comment_counting($defer=null) {
+ static $_defer = false;
+
+ if ( is_bool($defer) ) {
+ $_defer = $defer;
+ // flush any deferred counts
+ if ( !$defer )
+ wp_update_comment_count( null, true );
+ }
+
+ return $_defer;
+}
+
+/**
+ * Updates the comment count for post(s).
+ *
+ * When $do_deferred is false (is by default) and the comments have been set to
+ * be deferred, the post_id will be added to a queue, which will be updated at a
+ * later date and only updated once per post ID.
+ *
+ * If the comments have not be set up to be deferred, then the post will be
+ * updated. When $do_deferred is set to true, then all previous deferred post
+ * IDs will be updated along with the current $post_id.
+ *
+ * @since 2.1.0
+ * @see wp_update_comment_count_now() For what could cause a false return value
+ *
+ * @param int $post_id Post ID
+ * @param bool $do_deferred Whether to process previously deferred post comment counts
+ * @return bool True on success, false on failure
+ */
+function wp_update_comment_count($post_id, $do_deferred=false) {
+ static $_deferred = array();
+
+ if ( $do_deferred ) {
+ $_deferred = array_unique($_deferred);
+ foreach ( $_deferred as $i => $_post_id ) {
+ wp_update_comment_count_now($_post_id);
+ unset( $_deferred[$i] ); /** @todo Move this outside of the foreach and reset $_deferred to an array instead */
+ }
+ }
+
+ if ( wp_defer_comment_counting() ) {
+ $_deferred[] = $post_id;
+ return true;
+ }
+ elseif ( $post_id ) {
+ return wp_update_comment_count_now($post_id);
+ }
+
+}
+
+/**
+ * Updates the comment count for the post.
+ *
+ * @since 2.5.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'wp_update_comment_count' hook on $post_id, $new, and $old
+ * @uses do_action() Calls 'edit_posts' hook on $post_id and $post
+ *
+ * @param int $post_id Post ID
+ * @return bool True on success, false on '0' $post_id or if post with ID does not exist.
+ */
+function wp_update_comment_count_now($post_id) {
+ global $wpdb;
+ $post_id = (int) $post_id;
+ if ( !$post_id )
+ return false;
+ if ( !$post = get_post($post_id) )
+ return false;
+
+ $old = (int) $post->comment_count;
+ $new = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1'", $post_id) );
+ $wpdb->update( $wpdb->posts, array('comment_count' => $new), array('ID' => $post_id) );
+
+ clean_post_cache( $post );
+
+ do_action('wp_update_comment_count', $post_id, $new, $old);
+ do_action('edit_post', $post_id, $post);
+
+ return true;
+}
+
+//
+// Ping and trackback functions.
+//
+
+/**
+ * Finds a pingback server URI based on the given URL.
+ *
+ * Checks the HTML for the rel="pingback" link and x-pingback headers. It does
+ * a check for the x-pingback headers first and returns that, if available. The
+ * check for the rel="pingback" has more overhead than just the header.
+ *
+ * @since 1.5.0
+ *
+ * @param string $url URL to ping.
+ * @param int $deprecated Not Used.
+ * @return bool|string False on failure, string containing URI on success.
+ */
+function discover_pingback_server_uri( $url, $deprecated = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.7' );
+
+ $pingback_str_dquote = 'rel="pingback"';
+ $pingback_str_squote = 'rel=\'pingback\'';
+
+ /** @todo Should use Filter Extension or custom preg_match instead. */
+ $parsed_url = parse_url($url);
+
+ if ( ! isset( $parsed_url['host'] ) ) // Not an URL. This should never happen.
+ return false;
+
+ //Do not search for a pingback server on our own uploads
+ $uploads_dir = wp_upload_dir();
+ if ( 0 === strpos($url, $uploads_dir['baseurl']) )
+ return false;
+
+ $response = wp_safe_remote_head( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ if ( wp_remote_retrieve_header( $response, 'x-pingback' ) )
+ return wp_remote_retrieve_header( $response, 'x-pingback' );
+
+ // Not an (x)html, sgml, or xml page, no use going further.
+ if ( preg_match('#(image|audio|video|model)/#is', wp_remote_retrieve_header( $response, 'content-type' )) )
+ return false;
+
+ // Now do a GET since we're going to look in the html headers (and we're sure it's not a binary file)
+ $response = wp_safe_remote_get( $url, array( 'timeout' => 2, 'httpversion' => '1.0' ) );
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ $contents = wp_remote_retrieve_body( $response );
+
+ $pingback_link_offset_dquote = strpos($contents, $pingback_str_dquote);
+ $pingback_link_offset_squote = strpos($contents, $pingback_str_squote);
+ if ( $pingback_link_offset_dquote || $pingback_link_offset_squote ) {
+ $quote = ($pingback_link_offset_dquote) ? '"' : '\'';
+ $pingback_link_offset = ($quote=='"') ? $pingback_link_offset_dquote : $pingback_link_offset_squote;
+ $pingback_href_pos = @strpos($contents, 'href=', $pingback_link_offset);
+ $pingback_href_start = $pingback_href_pos+6;
+ $pingback_href_end = @strpos($contents, $quote, $pingback_href_start);
+ $pingback_server_url_len = $pingback_href_end - $pingback_href_start;
+ $pingback_server_url = substr($contents, $pingback_href_start, $pingback_server_url_len);
+
+ // We may find rel="pingback" but an incomplete pingback URL
+ if ( $pingback_server_url_len > 0 ) { // We got it!
+ return $pingback_server_url;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Perform all pingbacks, enclosures, trackbacks, and send to pingback services.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ */
+function do_all_pings() {
+ global $wpdb;
+
+ // Do pingbacks
+ while ($ping = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_pingme' LIMIT 1")) {
+ delete_metadata_by_mid( 'post', $ping->meta_id );
+ pingback( $ping->post_content, $ping->ID );
+ }
+
+ // Do Enclosures
+ while ($enclosure = $wpdb->get_row("SELECT ID, post_content, meta_id FROM {$wpdb->posts}, {$wpdb->postmeta} WHERE {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id AND {$wpdb->postmeta}.meta_key = '_encloseme' LIMIT 1")) {
+ delete_metadata_by_mid( 'post', $enclosure->meta_id );
+ do_enclose( $enclosure->post_content, $enclosure->ID );
+ }
+
+ // Do Trackbacks
+ $trackbacks = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE to_ping <> '' AND post_status = 'publish'");
+ if ( is_array($trackbacks) )
+ foreach ( $trackbacks as $trackback )
+ do_trackbacks($trackback);
+
+ //Do Update Services/Generic Pings
+ generic_ping();
+}
+
+/**
+ * Perform trackbacks.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID to do trackbacks on.
+ */
+function do_trackbacks($post_id) {
+ global $wpdb;
+
+ $post = get_post( $post_id );
+ $to_ping = get_to_ping($post_id);
+ $pinged = get_pung($post_id);
+ if ( empty($to_ping) ) {
+ $wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
+ return;
+ }
+
+ if ( empty($post->post_excerpt) )
+ $excerpt = apply_filters('the_content', $post->post_content, $post->ID);
+ else
+ $excerpt = apply_filters('the_excerpt', $post->post_excerpt);
+ $excerpt = str_replace(']]>', ']]&gt;', $excerpt);
+ $excerpt = wp_html_excerpt($excerpt, 252, '&#8230;');
+
+ $post_title = apply_filters('the_title', $post->post_title, $post->ID);
+ $post_title = strip_tags($post_title);
+
+ if ( $to_ping ) {
+ foreach ( (array) $to_ping as $tb_ping ) {
+ $tb_ping = trim($tb_ping);
+ if ( !in_array($tb_ping, $pinged) ) {
+ trackback($tb_ping, $post_title, $excerpt, $post_id);
+ $pinged[] = $tb_ping;
+ } else {
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $tb_ping, $post_id) );
+ }
+ }
+ }
+}
+
+/**
+ * Sends pings to all of the ping site services.
+ *
+ * @since 1.2.0
+ *
+ * @param int $post_id Post ID. Not actually used.
+ * @return int Same as Post ID from parameter
+ */
+function generic_ping($post_id = 0) {
+ $services = get_option('ping_sites');
+
+ $services = explode("\n", $services);
+ foreach ( (array) $services as $service ) {
+ $service = trim($service);
+ if ( '' != $service )
+ weblog_ping($service);
+ }
+
+ return $post_id;
+}
+
+/**
+ * Pings back the links found in a post.
+ *
+ * @since 0.71
+ * @uses $wp_version
+ * @uses IXR_Client
+ *
+ * @param string $content Post content to check for links.
+ * @param int $post_ID Post ID.
+ */
+function pingback($content, $post_ID) {
+ global $wp_version;
+ include_once(ABSPATH . WPINC . '/class-IXR.php');
+ include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
+
+ // original code by Mort (http://mort.mine.nu:8080)
+ $post_links = array();
+
+ $pung = get_pung($post_ID);
+
+ // Variables
+ $ltrs = '\w';
+ $gunk = '/#~:.?+=&%@!\-';
+ $punc = '.:?\-';
+ $any = $ltrs . $gunk . $punc;
+
+ // Step 1
+ // Parsing the post, external links (if any) are stored in the $post_links array
+ // This regexp comes straight from phpfreaks.com
+ // http://www.phpfreaks.com/quickcode/Extract_All_URLs_on_a_Page/15.php
+ preg_match_all("{\b http : [$any] +? (?= [$punc] * [^$any] | $)}x", $content, $post_links_temp);
+
+ // Step 2.
+ // Walking thru the links array
+ // first we get rid of links pointing to sites, not to specific files
+ // Example:
+ // http://dummy-weblog.org
+ // http://dummy-weblog.org/
+ // http://dummy-weblog.org/post.php
+ // We don't wanna ping first and second types, even if they have a valid <link/>
+
+ foreach ( (array) $post_links_temp[0] as $link_test ) :
+ if ( !in_array($link_test, $pung) && (url_to_postid($link_test) != $post_ID) // If we haven't pung it already and it isn't a link to itself
+ && !is_local_attachment($link_test) ) : // Also, let's never ping local attachments.
+ if ( $test = @parse_url($link_test) ) {
+ if ( isset($test['query']) )
+ $post_links[] = $link_test;
+ elseif ( isset( $test['path'] ) && ( $test['path'] != '/' ) && ( $test['path'] != '' ) )
+ $post_links[] = $link_test;
+ }
+ endif;
+ endforeach;
+
+ $post_links = array_unique( $post_links );
+ do_action_ref_array( 'pre_ping', array( &$post_links, &$pung, $post_ID ) );
+
+ foreach ( (array) $post_links as $pagelinkedto ) {
+ $pingback_server_url = discover_pingback_server_uri( $pagelinkedto );
+
+ if ( $pingback_server_url ) {
+ @ set_time_limit( 60 );
+ // Now, the RPC call
+ $pagelinkedfrom = get_permalink($post_ID);
+
+ // using a timeout of 3 seconds should be enough to cover slow servers
+ $client = new WP_HTTP_IXR_Client($pingback_server_url);
+ $client->timeout = 3;
+ $client->useragent = apply_filters( 'pingback_useragent', $client->useragent . ' -- WordPress/' . $wp_version, $client->useragent, $pingback_server_url, $pagelinkedto, $pagelinkedfrom);
+ // when set to true, this outputs debug messages by itself
+ $client->debug = false;
+
+ if ( $client->query('pingback.ping', $pagelinkedfrom, $pagelinkedto) || ( isset($client->error->code) && 48 == $client->error->code ) ) // Already registered
+ add_ping( $post_ID, $pagelinkedto );
+ }
+ }
+}
+
+/**
+ * Check whether blog is public before returning sites.
+ *
+ * @since 2.1.0
+ *
+ * @param mixed $sites Will return if blog is public, will not return if not public.
+ * @return mixed Empty string if blog is not public, returns $sites, if site is public.
+ */
+function privacy_ping_filter($sites) {
+ if ( '0' != get_option('blog_public') )
+ return $sites;
+ else
+ return '';
+}
+
+/**
+ * Send a Trackback.
+ *
+ * Updates database when sending trackback to prevent duplicates.
+ *
+ * @since 0.71
+ * @uses $wpdb
+ *
+ * @param string $trackback_url URL to send trackbacks.
+ * @param string $title Title of post.
+ * @param string $excerpt Excerpt of post.
+ * @param int $ID Post ID.
+ * @return mixed Database query from update.
+ */
+function trackback($trackback_url, $title, $excerpt, $ID) {
+ global $wpdb;
+
+ if ( empty($trackback_url) )
+ return;
+
+ $options = array();
+ $options['timeout'] = 4;
+ $options['body'] = array(
+ 'title' => $title,
+ 'url' => get_permalink($ID),
+ 'blog_name' => get_option('blogname'),
+ 'excerpt' => $excerpt
+ );
+
+ $response = wp_safe_remote_post( $trackback_url, $options );
+
+ if ( is_wp_error( $response ) )
+ return;
+
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $ID) );
+ return $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $ID) );
+}
+
+/**
+ * Send a pingback.
+ *
+ * @since 1.2.0
+ * @uses $wp_version
+ * @uses IXR_Client
+ *
+ * @param string $server Host of blog to connect to.
+ * @param string $path Path to send the ping.
+ */
+function weblog_ping($server = '', $path = '') {
+ global $wp_version;
+ include_once(ABSPATH . WPINC . '/class-IXR.php');
+ include_once(ABSPATH . WPINC . '/class-wp-http-ixr-client.php');
+
+ // using a timeout of 3 seconds should be enough to cover slow servers
+ $client = new WP_HTTP_IXR_Client($server, ((!strlen(trim($path)) || ('/' == $path)) ? false : $path));
+ $client->timeout = 3;
+ $client->useragent .= ' -- WordPress/'.$wp_version;
+
+ // when set to true, this outputs debug messages by itself
+ $client->debug = false;
+ $home = trailingslashit( home_url() );
+ if ( !$client->query('weblogUpdates.extendedPing', get_option('blogname'), $home, get_bloginfo('rss2_url') ) ) // then try a normal ping
+ $client->query('weblogUpdates.ping', get_option('blogname'), $home);
+}
+
+/**
+ * Default filter attached to pingback_ping_source_uri to validate the pingback's Source URI
+ *
+ * @since 3.5.1
+ * @see wp_http_validate_url()
+ *
+ * @param string $source_uri
+ * @return string
+ */
+function pingback_ping_source_uri( $source_uri ) {
+ return (string) wp_http_validate_url( $source_uri );
+}
+
+/**
+ * Default filter attached to xmlrpc_pingback_error.
+ *
+ * Returns a generic pingback error code unless the error code is 48,
+ * which reports that the pingback is already registered.
+ *
+ * @since 3.5.1
+ * @link http://www.hixie.ch/specs/pingback/pingback#TOC3
+ *
+ * @param IXR_Error $ixr_error
+ * @return IXR_Error
+ */
+function xmlrpc_pingback_error( $ixr_error ) {
+ if ( $ixr_error->code === 48 )
+ return $ixr_error;
+ return new IXR_Error( 0, '' );
+}
+
+//
+// Cache
+//
+
+/**
+ * Removes comment ID from the comment cache.
+ *
+ * @since 2.3.0
+ * @package WordPress
+ * @subpackage Cache
+ *
+ * @param int|array $ids Comment ID or array of comment IDs to remove from cache
+ */
+function clean_comment_cache($ids) {
+ foreach ( (array) $ids as $id )
+ wp_cache_delete($id, 'comment');
+
+ wp_cache_set( 'last_changed', microtime(), 'comment' );
+}
+
+/**
+ * Updates the comment cache of given comments.
+ *
+ * Will add the comments in $comments to the cache. If comment ID already exists
+ * in the comment cache then it will not be updated. The comment is added to the
+ * cache using the comment group with the key using the ID of the comments.
+ *
+ * @since 2.3.0
+ * @package WordPress
+ * @subpackage Cache
+ *
+ * @param array $comments Array of comment row objects
+ */
+function update_comment_cache($comments) {
+ foreach ( (array) $comments as $comment )
+ wp_cache_add($comment->comment_ID, $comment, 'comment');
+}
+
+//
+// Internal
+//
+
+/**
+ * Close comments on old posts on the fly, without any extra DB queries. Hooked to the_posts.
+ *
+ * @access private
+ * @since 2.7.0
+ *
+ * @param object $posts Post data object.
+ * @param object $query Query object.
+ * @return object
+ */
+function _close_comments_for_old_posts( $posts, $query ) {
+ if ( empty( $posts ) || ! $query->is_singular() || ! get_option( 'close_comments_for_old_posts' ) )
+ return $posts;
+
+ $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
+ if ( ! in_array( $posts[0]->post_type, $post_types ) )
+ return $posts;
+
+ $days_old = (int) get_option( 'close_comments_days_old' );
+ if ( ! $days_old )
+ return $posts;
+
+ if ( time() - strtotime( $posts[0]->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) ) {
+ $posts[0]->comment_status = 'closed';
+ $posts[0]->ping_status = 'closed';
+ }
+
+ return $posts;
+}
+
+/**
+ * Close comments on an old post. Hooked to comments_open and pings_open.
+ *
+ * @access private
+ * @since 2.7.0
+ *
+ * @param bool $open Comments open or closed
+ * @param int $post_id Post ID
+ * @return bool $open
+ */
+function _close_comments_for_old_post( $open, $post_id ) {
+ if ( ! $open )
+ return $open;
+
+ if ( !get_option('close_comments_for_old_posts') )
+ return $open;
+
+ $days_old = (int) get_option('close_comments_days_old');
+ if ( !$days_old )
+ return $open;
+
+ $post = get_post($post_id);
+
+ $post_types = apply_filters( 'close_comments_for_post_types', array( 'post' ) );
+ if ( ! in_array( $post->post_type, $post_types ) )
+ return $open;
+
+ if ( time() - strtotime( $post->post_date_gmt ) > ( $days_old * DAY_IN_SECONDS ) )
+ return false;
+
+ return $open;
+}
diff --git a/src/wp-includes/compat.php b/src/wp-includes/compat.php
new file mode 100644
index 0000000000..cb2a5597c8
--- /dev/null
+++ b/src/wp-includes/compat.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
+ *
+ * @package PHP
+ * @access private
+ */
+
+// If gettext isn't available
+if ( !function_exists('_') ) {
+ function _($string) {
+ return $string;
+ }
+}
+
+if ( !function_exists('mb_substr') ):
+ function mb_substr( $str, $start, $length=null, $encoding=null ) {
+ return _mb_substr($str, $start, $length, $encoding);
+ }
+endif;
+
+function _mb_substr( $str, $start, $length=null, $encoding=null ) {
+ // the solution below, works only for utf-8, so in case of a different
+ // charset, just use built-in substr
+ $charset = get_option( 'blog_charset' );
+ if ( !in_array( $charset, array('utf8', 'utf-8', 'UTF8', 'UTF-8') ) ) {
+ return is_null( $length )? substr( $str, $start ) : substr( $str, $start, $length);
+ }
+ // use the regex unicode support to separate the UTF-8 characters into an array
+ preg_match_all( '/./us', $str, $match );
+ $chars = is_null( $length )? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
+ return implode( '', $chars );
+}
+
+if ( !function_exists('hash_hmac') ):
+function hash_hmac($algo, $data, $key, $raw_output = false) {
+ return _hash_hmac($algo, $data, $key, $raw_output);
+}
+endif;
+
+function _hash_hmac($algo, $data, $key, $raw_output = false) {
+ $packs = array('md5' => 'H32', 'sha1' => 'H40');
+
+ if ( !isset($packs[$algo]) )
+ return false;
+
+ $pack = $packs[$algo];
+
+ if (strlen($key) > 64)
+ $key = pack($pack, $algo($key));
+
+ $key = str_pad($key, 64, chr(0));
+
+ $ipad = (substr($key, 0, 64) ^ str_repeat(chr(0x36), 64));
+ $opad = (substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64));
+
+ $hmac = $algo($opad . pack($pack, $algo($ipad . $data)));
+
+ if ( $raw_output )
+ return pack( $pack, $hmac );
+ return $hmac;
+}
+
+if ( !function_exists('json_encode') ) {
+ function json_encode( $string ) {
+ global $wp_json;
+
+ if ( !is_a($wp_json, 'Services_JSON') ) {
+ require_once( ABSPATH . WPINC . '/class-json.php' );
+ $wp_json = new Services_JSON();
+ }
+
+ return $wp_json->encodeUnsafe( $string );
+ }
+}
+
+if ( !function_exists('json_decode') ) {
+ function json_decode( $string, $assoc_array = false ) {
+ global $wp_json;
+
+ if ( !is_a($wp_json, 'Services_JSON') ) {
+ require_once( ABSPATH . WPINC . '/class-json.php' );
+ $wp_json = new Services_JSON();
+ }
+
+ $res = $wp_json->decode( $string );
+ if ( $assoc_array )
+ $res = _json_decode_object_helper( $res );
+ return $res;
+ }
+ function _json_decode_object_helper($data) {
+ if ( is_object($data) )
+ $data = get_object_vars($data);
+ return is_array($data) ? array_map(__FUNCTION__, $data) : $data;
+ }
+}
diff --git a/src/wp-includes/cron.php b/src/wp-includes/cron.php
new file mode 100644
index 0000000000..6668dc546e
--- /dev/null
+++ b/src/wp-includes/cron.php
@@ -0,0 +1,414 @@
+<?php
+/**
+ * WordPress CRON API
+ *
+ * @package WordPress
+ */
+
+/**
+ * Schedules a hook to run only once.
+ *
+ * Schedules a hook which will be executed once by the WordPress actions core at
+ * a time which you specify. The action will fire off when someone visits your
+ * WordPress site, if the schedule time has passed.
+ *
+ * @since 2.1.0
+ * @link http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
+ *
+ * @param int $timestamp Timestamp for when to run the event.
+ * @param string $hook Action hook to execute when cron is run.
+ * @param array $args Optional. Arguments to pass to the hook's callback function.
+ */
+function wp_schedule_single_event( $timestamp, $hook, $args = array()) {
+ // don't schedule a duplicate if there's already an identical event due in the next 10 minutes
+ $next = wp_next_scheduled($hook, $args);
+ if ( $next && $next <= $timestamp + 10 * MINUTE_IN_SECONDS )
+ return;
+
+ $crons = _get_cron_array();
+ $event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => false, 'args' => $args );
+ $event = apply_filters('schedule_event', $event);
+
+ // A plugin disallowed this event
+ if ( ! $event )
+ return false;
+
+ $key = md5(serialize($event->args));
+
+ $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
+ uksort( $crons, "strnatcasecmp" );
+ _set_cron_array( $crons );
+}
+
+/**
+ * Schedule a periodic event.
+ *
+ * Schedules a hook which will be executed by the WordPress actions core on a
+ * specific interval, specified by you. The action will trigger when someone
+ * visits your WordPress site, if the scheduled time has passed.
+ *
+ * Valid values for the recurrence are hourly, daily and twicedaily. These can
+ * be extended using the cron_schedules filter in wp_get_schedules().
+ *
+ * Use wp_next_scheduled() to prevent duplicates
+ *
+ * @since 2.1.0
+ *
+ * @param int $timestamp Timestamp for when to run the event.
+ * @param string $recurrence How often the event should recur.
+ * @param string $hook Action hook to execute when cron is run.
+ * @param array $args Optional. Arguments to pass to the hook's callback function.
+ * @return bool|null False on failure, null when complete with scheduling event.
+ */
+function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
+ $crons = _get_cron_array();
+ $schedules = wp_get_schedules();
+
+ if ( !isset( $schedules[$recurrence] ) )
+ return false;
+
+ $event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] );
+ $event = apply_filters('schedule_event', $event);
+
+ // A plugin disallowed this event
+ if ( ! $event )
+ return false;
+
+ $key = md5(serialize($event->args));
+
+ $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
+ uksort( $crons, "strnatcasecmp" );
+ _set_cron_array( $crons );
+}
+
+/**
+ * Reschedule a recurring event.
+ *
+ * @since 2.1.0
+ *
+ * @param int $timestamp Timestamp for when to run the event.
+ * @param string $recurrence How often the event should recur.
+ * @param string $hook Action hook to execute when cron is run.
+ * @param array $args Optional. Arguments to pass to the hook's callback function.
+ * @return bool|null False on failure. Null when event is rescheduled.
+ */
+function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array()) {
+ $crons = _get_cron_array();
+ $schedules = wp_get_schedules();
+ $key = md5(serialize($args));
+ $interval = 0;
+
+ // First we try to get it from the schedule
+ if ( 0 == $interval )
+ $interval = $schedules[$recurrence]['interval'];
+ // Now we try to get it from the saved interval in case the schedule disappears
+ if ( 0 == $interval )
+ $interval = $crons[$timestamp][$hook][$key]['interval'];
+ // Now we assume something is wrong and fail to schedule
+ if ( 0 == $interval )
+ return false;
+
+ $now = time();
+
+ if ( $timestamp >= $now )
+ $timestamp = $now + $interval;
+ else
+ $timestamp = $now + ($interval - (($now - $timestamp) % $interval));
+
+ wp_schedule_event( $timestamp, $recurrence, $hook, $args );
+}
+
+/**
+ * Unschedule a previously scheduled cron job.
+ *
+ * The $timestamp and $hook parameters are required, so that the event can be
+ * identified.
+ *
+ * @since 2.1.0
+ *
+ * @param int $timestamp Timestamp for when to run the event.
+ * @param string $hook Action hook, the execution of which will be unscheduled.
+ * @param array $args Arguments to pass to the hook's callback function.
+ * Although not passed to a callback function, these arguments are used
+ * to uniquely identify the scheduled event, so they should be the same
+ * as those used when originally scheduling the event.
+ */
+function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
+ $crons = _get_cron_array();
+ $key = md5(serialize($args));
+ unset( $crons[$timestamp][$hook][$key] );
+ if ( empty($crons[$timestamp][$hook]) )
+ unset( $crons[$timestamp][$hook] );
+ if ( empty($crons[$timestamp]) )
+ unset( $crons[$timestamp] );
+ _set_cron_array( $crons );
+}
+
+/**
+ * Unschedule all cron jobs attached to a specific hook.
+ *
+ * @since 2.1.0
+ *
+ * @param string $hook Action hook, the execution of which will be unscheduled.
+ * @param array $args Optional. Arguments that were to be pass to the hook's callback function.
+ */
+function wp_clear_scheduled_hook( $hook, $args = array() ) {
+ // Backward compatibility
+ // Previously this function took the arguments as discrete vars rather than an array like the rest of the API
+ if ( !is_array($args) ) {
+ _deprecated_argument( __FUNCTION__, '3.0', __('This argument has changed to an array to match the behavior of the other cron functions.') );
+ $args = array_slice( func_get_args(), 1 );
+ }
+
+ while ( $timestamp = wp_next_scheduled( $hook, $args ) )
+ wp_unschedule_event( $timestamp, $hook, $args );
+}
+
+/**
+ * Retrieve the next timestamp for a cron event.
+ *
+ * @since 2.1.0
+ *
+ * @param string $hook Action hook to execute when cron is run.
+ * @param array $args Optional. Arguments to pass to the hook's callback function.
+ * @return bool|int The UNIX timestamp of the next time the scheduled event will occur.
+ */
+function wp_next_scheduled( $hook, $args = array() ) {
+ $crons = _get_cron_array();
+ $key = md5(serialize($args));
+ if ( empty($crons) )
+ return false;
+ foreach ( $crons as $timestamp => $cron ) {
+ if ( isset( $cron[$hook][$key] ) )
+ return $timestamp;
+ }
+ return false;
+}
+
+/**
+ * Send request to run cron through HTTP request that doesn't halt page loading.
+ *
+ * @since 2.1.0
+ *
+ * @return null Cron could not be spawned, because it is not needed to run.
+ */
+function spawn_cron( $gmt_time = 0 ) {
+
+ if ( ! $gmt_time )
+ $gmt_time = microtime( true );
+
+ if ( defined('DOING_CRON') || isset($_GET['doing_wp_cron']) )
+ return;
+
+ /*
+ * multiple processes on multiple web servers can run this code concurrently
+ * try to make this as atomic as possible by setting doing_cron switch
+ */
+ $lock = get_transient('doing_cron');
+
+ if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS )
+ $lock = 0;
+
+ // don't run if another process is currently running it or more than once every 60 sec.
+ if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
+ return;
+
+ //sanity check
+ $crons = _get_cron_array();
+ if ( !is_array($crons) )
+ return;
+
+ $keys = array_keys( $crons );
+ if ( isset($keys[0]) && $keys[0] > $gmt_time )
+ return;
+
+ if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON ) {
+ if ( !empty($_POST) || defined('DOING_AJAX') )
+ return;
+
+ $doing_wp_cron = sprintf( '%.22F', $gmt_time );
+ set_transient( 'doing_cron', $doing_wp_cron );
+
+ ob_start();
+ wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
+ echo ' ';
+
+ // flush any buffers and send the headers
+ while ( @ob_end_flush() );
+ flush();
+
+ WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
+ return;
+ }
+
+ $doing_wp_cron = sprintf( '%.22F', $gmt_time );
+ set_transient( 'doing_cron', $doing_wp_cron );
+
+ $cron_request = apply_filters( 'cron_request', array(
+ 'url' => site_url( 'wp-cron.php?doing_wp_cron=' . $doing_wp_cron ),
+ 'key' => $doing_wp_cron,
+ 'args' => array( 'timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters( 'https_local_ssl_verify', true ) )
+ ) );
+
+ wp_remote_post( $cron_request['url'], $cron_request['args'] );
+}
+
+/**
+ * Run scheduled callbacks or spawn cron for all scheduled events.
+ *
+ * @since 2.1.0
+ *
+ * @return null When doesn't need to run Cron.
+ */
+function wp_cron() {
+
+ // Prevent infinite loops caused by lack of wp-cron.php
+ if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) )
+ return;
+
+ if ( false === $crons = _get_cron_array() )
+ return;
+
+ $gmt_time = microtime( true );
+ $keys = array_keys( $crons );
+ if ( isset($keys[0]) && $keys[0] > $gmt_time )
+ return;
+
+ $schedules = wp_get_schedules();
+ foreach ( $crons as $timestamp => $cronhooks ) {
+ if ( $timestamp > $gmt_time ) break;
+ foreach ( (array) $cronhooks as $hook => $args ) {
+ if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
+ continue;
+ spawn_cron( $gmt_time );
+ break 2;
+ }
+ }
+}
+
+/**
+ * Retrieve supported and filtered Cron recurrences.
+ *
+ * The supported recurrences are 'hourly' and 'daily'. A plugin may add more by
+ * hooking into the 'cron_schedules' filter. The filter accepts an array of
+ * arrays. The outer array has a key that is the name of the schedule or for
+ * example 'weekly'. The value is an array with two keys, one is 'interval' and
+ * the other is 'display'.
+ *
+ * The 'interval' is a number in seconds of when the cron job should run. So for
+ * 'hourly', the time is 3600 or 60*60. For weekly, the value would be
+ * 60*60*24*7 or 604800. The value of 'interval' would then be 604800.
+ *
+ * The 'display' is the description. For the 'weekly' key, the 'display' would
+ * be <code>__('Once Weekly')</code>.
+ *
+ * For your plugin, you will be passed an array. you can easily add your
+ * schedule by doing the following.
+ * <code>
+ * // filter parameter variable name is 'array'
+ * $array['weekly'] = array(
+ * 'interval' => 604800,
+ * 'display' => __('Once Weekly')
+ * );
+ * </code>
+ *
+ * @since 2.1.0
+ *
+ * @return array
+ */
+function wp_get_schedules() {
+ $schedules = array(
+ 'hourly' => array( 'interval' => HOUR_IN_SECONDS, 'display' => __( 'Once Hourly' ) ),
+ 'twicedaily' => array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily' ) ),
+ 'daily' => array( 'interval' => DAY_IN_SECONDS, 'display' => __( 'Once Daily' ) ),
+ );
+ return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
+}
+
+/**
+ * Retrieve Cron schedule for hook with arguments.
+ *
+ * @since 2.1.0
+ *
+ * @param string $hook Action hook to execute when cron is run.
+ * @param array $args Optional. Arguments to pass to the hook's callback function.
+ * @return string|bool False, if no schedule. Schedule on success.
+ */
+function wp_get_schedule($hook, $args = array()) {
+ $crons = _get_cron_array();
+ $key = md5(serialize($args));
+ if ( empty($crons) )
+ return false;
+ foreach ( $crons as $timestamp => $cron ) {
+ if ( isset( $cron[$hook][$key] ) )
+ return $cron[$hook][$key]['schedule'];
+ }
+ return false;
+}
+
+//
+// Private functions
+//
+
+/**
+ * Retrieve cron info array option.
+ *
+ * @since 2.1.0
+ * @access private
+ *
+ * @return array CRON info array.
+ */
+function _get_cron_array() {
+ $cron = get_option('cron');
+ if ( ! is_array($cron) )
+ return false;
+
+ if ( !isset($cron['version']) )
+ $cron = _upgrade_cron_array($cron);
+
+ unset($cron['version']);
+
+ return $cron;
+}
+
+/**
+ * Updates the CRON option with the new CRON array.
+ *
+ * @since 2.1.0
+ * @access private
+ *
+ * @param array $cron Cron info array from {@link _get_cron_array()}.
+ */
+function _set_cron_array($cron) {
+ $cron['version'] = 2;
+ update_option( 'cron', $cron );
+}
+
+/**
+ * Upgrade a Cron info array.
+ *
+ * This function upgrades the Cron info array to version 2.
+ *
+ * @since 2.1.0
+ * @access private
+ *
+ * @param array $cron Cron info array from {@link _get_cron_array()}.
+ * @return array An upgraded Cron info array.
+ */
+function _upgrade_cron_array($cron) {
+ if ( isset($cron['version']) && 2 == $cron['version'])
+ return $cron;
+
+ $new_cron = array();
+
+ foreach ( (array) $cron as $timestamp => $hooks) {
+ foreach ( (array) $hooks as $hook => $args ) {
+ $key = md5(serialize($args['args']));
+ $new_cron[$timestamp][$hook][$key] = $args;
+ }
+ }
+
+ $new_cron['version'] = 2;
+ update_option( 'cron', $new_cron );
+ return $new_cron;
+}
diff --git a/src/wp-includes/css/admin-bar-rtl.css b/src/wp-includes/css/admin-bar-rtl.css
new file mode 100644
index 0000000000..a190f2122c
--- /dev/null
+++ b/src/wp-includes/css/admin-bar-rtl.css
@@ -0,0 +1,201 @@
+#wpadminbar * {
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+}
+
+#wpadminbar {
+ direction: rtl;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ left: auto;
+ right: 0;
+}
+
+#wpadminbar .quicklinks ul {
+ text-align: right;
+}
+
+#wpadminbar li {
+ float: right;
+}
+
+#wpadminbar .quicklinks > ul > li {
+ border-right: 0;
+ border-left: 1px solid #555;
+}
+
+#wpadminbar .quicklinks > ul > li > a,
+#wpadminbar .quicklinks > ul > li > .ab-empty-item {
+ border-right: 0;
+ border-left: 1px solid #333;
+}
+
+#wpadminbar .quicklinks .ab-top-secondary > li {
+ border-left: 0;
+ border-right: 1px solid #333;
+ float: left;
+}
+
+#wpadminbar .quicklinks .ab-top-secondary > li > a,
+#wpadminbar .quicklinks .ab-top-secondary > li > .ab-empty-item {
+ border-right: 1px solid #555;
+ border-left: 0;
+}
+
+#wpadminbar .menupop .ab-sub-wrapper,
+#wpadminbar .shortlink-input {
+ margin: 0 -1px 0 0;
+}
+
+#wpadminbar.ie7 .menupop .ab-sub-wrapper,
+#wpadminbar.ie7 .shortlink-input {
+ left: auto;
+ right: 0;
+}
+
+#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper {
+ right: auto;
+ left: 0;
+ margin: 0 0 0 -1px;
+}
+
+#wpadminbar .menupop li:hover > .ab-sub-wrapper,
+#wpadminbar .menupop li.hover > .ab-sub-wrapper {
+ margin-left: 0px;
+ margin-right: 100%;
+}
+
+#wpadminbar .ab-top-secondary .menupop li:hover > .ab-sub-wrapper,
+#wpadminbar .ab-top-secondary .menupop li.hover > .ab-sub-wrapper {
+ margin-left: inherit;
+ margin-right: 0;
+ left: 100%;
+ right: inherit;
+}
+
+#wpadminbar .menupop .menupop > .ab-item {
+ background-position: 5% -46px;
+ padding-left: 2em;
+ padding-right: 1em;
+}
+
+#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item {
+ background-position: 95% -20px;
+ padding-left: 1em;
+ padding-right: 2em;
+}
+
+#wpadminbar .quicklinks .menupop ul.ab-sub-secondary {
+ right: 0;
+ left: auto;
+}
+
+#wpadminbar .ab-top-secondary {
+ float: left;
+ right: auto;
+ left: 0;
+}
+
+#wpadminbar ul li:last-child,
+#wpadminbar ul li:last-child .ab-item {
+ border-left: 0;
+}
+
+#wpadminbar .screen-reader-shortcut:focus {
+ left: auto;
+ right: 6px;
+}
+
+/**
+ * My Account
+ */
+#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions > li {
+ margin-right: 88px;
+ margin-left: 16px;
+}
+
+#wp-admin-bar-user-actions > li > .ab-item {
+ padding-left: 0;
+ padding-right: 8px;
+}
+
+#wp-admin-bar-user-info .avatar {
+ left: auto;
+ right: -72px;
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
+ margin-left: -1px;
+ margin-right: 4px
+}
+
+/*
+ * My Sites
+ */
+#wpadminbar .quicklinks li .blavatar {
+ margin-right: 0px;
+ margin-left: 4px;
+}
+
+/*
+ * Search
+ */
+#wpadminbar #adminbarsearch .adminbar-input {
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+ padding: 0 24px 0 3px;
+ margin: 0;
+ background-position: 50% 2px;
+}
+
+#wpadminbar #adminbarsearch .adminbar-input:focus,
+#wpadminbar.ie7 #adminbarsearch .adminbar-input {
+ background-position: 99% 2px;
+}
+
+/**
+ * Comments icon
+ */
+#wpadminbar .ab-icon {
+ float: right;
+}
+
+.ie7 #wp-admin-bar-wp-logo > .ab-item .ab-icon {
+ position: static;
+}
+
+#wpadminbar.ie7 .ab-icon {
+ float: left;
+ left: 12px;
+}
+
+#wpadminbar .ab-label {
+ margin-left: 0px;
+ margin-right: 4px;
+ float: left;
+}
+
+#wpadminbar.ie7 .ab-label {
+ margin-right: 0;
+}
+
+#wpadminbar.ie7 #wp-admin-bar-comments > a {
+ min-width: 25px;
+}
+
+#wpadminbar a:hover .ab-comments-icon-arrow {
+ border-right-color: #bbb;
+}
+
+#wpadminbar .menupop .ab-sub-wrapper,
+#wpadminbar .shortlink-input {
+ right: 0;
+}
+
+#wpadminbar .quicklinks .menupop ul li a {
+ position: relative;
+}
+
+/**
+ * IE 6-targeted rules
+ */
+* html #wpadminbar .quicklinks ul li a {
+ float: right;
+}
diff --git a/src/wp-includes/css/admin-bar.css b/src/wp-includes/css/admin-bar.css
new file mode 100644
index 0000000000..270fa9a0a1
--- /dev/null
+++ b/src/wp-includes/css/admin-bar.css
@@ -0,0 +1,689 @@
+#wpadminbar * {
+ height: auto;
+ width: auto;
+ margin: 0;
+ padding: 0;
+ position: static;
+ text-transform: none;
+ letter-spacing: normal;
+ line-height: 1;
+ font: normal 13px/28px sans-serif;
+ color: #ccc;
+ text-shadow: #444 0px -1px 0px;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ -webkit-transition: none;
+ -moz-transition: none;
+ -o-transition: none;
+ transition: none;
+}
+
+#wpadminbar ul li:before,
+#wpadminbar ul li:after {
+ content: normal;
+}
+
+#wpadminbar a,
+#wpadminbar a:hover,
+#wpadminbar a img,
+#wpadminbar a img:hover {
+ outline: none;
+ border: none;
+ text-decoration: none;
+ background: none;
+}
+
+#wpadminbar a:focus,
+#wpadminbar a:active,
+#wpadminbar input[type="text"],
+#wpadminbar input[type="password"],
+#wpadminbar input[type="number"],
+#wpadminbar input[type="search"],
+#wpadminbar input[type="email"],
+#wpadminbar input[type="url"],
+#wpadminbar select,
+#wpadminbar textarea,
+#wpadminbar div {
+ outline: none;
+}
+
+#wpadminbar {
+ direction: ltr;
+ color: #ccc;
+ font: normal 13px/28px sans-serif;
+ height: 28px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ min-width: 600px; /* match the min-width of the body in wp-admin.css */
+ z-index: 99999;
+ background: #464646;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #373737), color-stop(18%, #464646));
+ background-image: -webkit-linear-gradient(bottom, #373737 0, #464646 5px);
+ background-image: -moz-linear-gradient(bottom, #373737 0, #464646 5px);
+ background-image: -o-linear-gradient(bottom, #373737 0, #464646 5px);
+ background-image: linear-gradient(to top, #373737 0, #464646 5px);
+}
+
+#wpadminbar .ab-sub-wrapper,
+#wpadminbar ul,
+#wpadminbar ul li {
+ background: none;
+ clear: none;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ text-indent: 0;
+ z-index: 99999;
+}
+
+#wpadminbar .quicklinks {
+ border-left: 1px solid transparent;
+}
+
+#wpadminbar .quicklinks ul {
+ text-align: left;
+}
+
+#wpadminbar li {
+ float: left;
+}
+
+#wpadminbar .ab-empty-item {
+ outline: none;
+}
+
+#wpadminbar .quicklinks > ul > li {
+ border-right: 1px solid #555;
+}
+
+#wpadminbar .quicklinks > ul > li > a,
+#wpadminbar .quicklinks > ul > li > .ab-empty-item {
+ border-right: 1px solid #333;
+}
+
+#wpadminbar .quicklinks .ab-top-secondary > li {
+ border-left: 1px solid #333;
+ border-right: 0;
+ float: right;
+}
+
+#wpadminbar .quicklinks .ab-top-secondary > li > a,
+#wpadminbar .quicklinks .ab-top-secondary > li > .ab-empty-item {
+ border-left: 1px solid #555;
+ border-right: 0;
+}
+
+#wpadminbar .quicklinks a,
+#wpadminbar .quicklinks .ab-empty-item,
+#wpadminbar .shortlink-input {
+ height: 28px;
+ display: block;
+ padding: 0 12px;
+ margin: 0;
+}
+
+#wpadminbar .menupop .ab-sub-wrapper,
+#wpadminbar .shortlink-input {
+ margin: 0 0 0 -1px;
+ padding: 0;
+ -webkit-box-shadow: 0 4px 4px rgba(0,0,0,0.2);
+ box-shadow: 0 4px 4px rgba(0,0,0,0.2);
+ background: #fff;
+ display: none;
+ position: absolute;
+ float: none;
+ border-width: 0 1px 1px 1px;
+ border-style: solid;
+ border-color: #dfdfdf;
+}
+
+#wpadminbar.ie7 .menupop .ab-sub-wrapper,
+#wpadminbar.ie7 .shortlink-input {
+ top: 28px;
+ left: 0;
+}
+
+#wpadminbar .ab-top-menu > .menupop > .ab-sub-wrapper {
+ min-width: 100%;
+}
+
+#wpadminbar .ab-top-secondary .menupop .ab-sub-wrapper {
+ right: 0;
+ left: auto;
+ margin: 0 -1px 0 0;
+}
+
+#wpadminbar .ab-sub-wrapper > .ab-submenu:first-child {
+ border-top: none;
+}
+
+#wpadminbar .ab-submenu {
+ padding: 6px 0;
+ border-top: 1px solid #dfdfdf;
+}
+
+#wpadminbar .selected .shortlink-input {
+ display: block;
+}
+
+#wpadminbar .quicklinks .menupop ul li {
+ float: none;
+}
+
+#wpadminbar .quicklinks .menupop ul li a strong {
+ font-weight: bold;
+}
+
+#wpadminbar .quicklinks .menupop ul li .ab-item,
+#wpadminbar .quicklinks .menupop ul li a strong,
+#wpadminbar .quicklinks .menupop.hover ul li .ab-item,
+#wpadminbar.nojs .quicklinks .menupop:hover ul li .ab-item,
+#wpadminbar .shortlink-input {
+ line-height: 26px;
+ height: 26px;
+ text-shadow: none;
+ white-space: nowrap;
+ min-width: 140px;
+}
+
+#wpadminbar .shortlink-input {
+ width: 200px;
+}
+
+#wpadminbar.nojs li:hover > .ab-sub-wrapper,
+#wpadminbar li.hover > .ab-sub-wrapper {
+ display: block;
+}
+
+#wpadminbar .menupop li:hover > .ab-sub-wrapper,
+#wpadminbar .menupop li.hover > .ab-sub-wrapper {
+ margin-left: 100%;
+ margin-top: -33px;
+ border-width: 1px;
+}
+
+#wpadminbar .ab-top-secondary .menupop li:hover > .ab-sub-wrapper,
+#wpadminbar .ab-top-secondary .menupop li.hover > .ab-sub-wrapper {
+ margin-left: 0;
+ left: inherit;
+ right: 100%;
+}
+
+#wpadminbar .ab-top-menu > li:hover > .ab-item,
+#wpadminbar .ab-top-menu > li.hover > .ab-item,
+#wpadminbar .ab-top-menu > li > .ab-item:focus,
+#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus {
+ color: #fafafa;
+ background: #222;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#3a3a3a), to(#222));
+ background-image: -webkit-linear-gradient(bottom, #3a3a3a, #222);
+ background-image: -moz-linear-gradient(bottom, #3a3a3a, #222);
+ background-image: -o-linear-gradient(bottom, #3a3a3a, #222);
+ background-image: linear-gradient(to top, #3a3a3a, #222);
+}
+
+#wpadminbar.nojs .ab-top-menu > li.menupop:hover > .ab-item,
+#wpadminbar .ab-top-menu > li.menupop.hover > .ab-item {
+ background: #fff;
+ color: #333;
+ text-shadow: none;
+ border-right-color: transparent;
+ border-left-color: transparent;
+}
+
+#wpadminbar .hover .ab-label,
+#wpadminbar.nojq .ab-item:focus .ab-label {
+ color: #fafafa;
+}
+
+#wpadminbar .menupop.hover .ab-label {
+ color: #333;
+ text-shadow: none;
+}
+
+#wpadminbar .menupop li:hover,
+#wpadminbar .menupop li.hover,
+#wpadminbar .quicklinks .menupop .ab-item:focus,
+#wpadminbar .quicklinks .ab-top-menu .menupop .ab-item:focus {
+ background-color: #eaf2fa;
+}
+
+#wpadminbar .ab-submenu .ab-item {
+ color: #333;
+ text-shadow: none;
+}
+
+#wpadminbar .quicklinks .menupop ul li a,
+#wpadminbar .quicklinks .menupop ul li a strong,
+#wpadminbar .quicklinks .menupop.hover ul li a,
+#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
+ color: #21759B;
+}
+
+#wpadminbar .menupop .menupop > .ab-item {
+ display: block;
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: 95% -20px;
+ background-repeat: no-repeat;
+ padding-right: 2em;
+}
+
+#wpadminbar .ab-top-secondary .menupop .menupop > .ab-item {
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: 5% -46px;
+ background-repeat: no-repeat;
+ padding-left: 2em;
+ padding-right: 1em;
+}
+
+#wpadminbar .quicklinks .menupop ul.ab-sub-secondary {
+ display: block;
+ position: relative;
+ right: auto;
+ margin: 0;
+ background: #eee;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+#wpadminbar .quicklinks .menupop .ab-sub-secondary > li:hover,
+#wpadminbar .quicklinks .menupop .ab-sub-secondary > li.hover,
+#wpadminbar .quicklinks .menupop .ab-sub-secondary > li .ab-item:focus {
+ background-color: #dfdfdf;
+}
+
+#wpadminbar .quicklinks a span#ab-updates {
+ background: #eee;
+ color: #333;
+ text-shadow: none;
+ display: inline;
+ padding: 2px 5px;
+ font-size: 10px;
+ font-weight: bold;
+ -webkit-border-radius: 10px;
+ border-radius: 10px;
+}
+
+#wpadminbar .quicklinks a:hover span#ab-updates {
+ background: #fff;
+ color: #000;
+}
+
+#wpadminbar .ab-top-secondary {
+ float: right;
+ background: #464646;
+ background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #373737), color-stop(18%, #464646));
+ background-image: -webkit-linear-gradient(bottom, #373737 0, #464646 5px);
+ background-image: -moz-linear-gradient(bottom, #373737 0, #464646 5px);
+ background-image: -o-linear-gradient(bottom, #373737 0, #464646 5px);
+ background-image: linear-gradient(to top, #373737 0, #464646 5px);
+}
+
+#wpadminbar ul li:last-child,
+#wpadminbar ul li:last-child .ab-item {
+ border-right: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+/**
+ * My Account
+ */
+#wp-admin-bar-my-account > ul {
+ min-width: 198px;
+}
+
+#wp-admin-bar-my-account.with-avatar > ul {
+ min-width: 270px;
+}
+
+#wpadminbar #wp-admin-bar-user-actions > li {
+ margin-left: 16px;
+ margin-right: 16px;
+}
+
+#wpadminbar #wp-admin-bar-my-account.with-avatar #wp-admin-bar-user-actions > li {
+ margin-left: 88px;
+}
+
+#wp-admin-bar-user-actions > li > .ab-item {
+ padding-left: 8px;
+}
+
+#wpadminbar #wp-admin-bar-user-info {
+ margin-top: 6px;
+ margin-bottom: 15px;
+ height: auto;
+ background: none;
+}
+
+#wp-admin-bar-user-info .avatar {
+ position: absolute;
+ left: -72px;
+ top: 4px;
+ width: 64px;
+ height: 64px;
+}
+
+#wpadminbar #wp-admin-bar-user-info a {
+ background: none;
+ height: auto;
+}
+
+#wpadminbar #wp-admin-bar-user-info span {
+ background: none;
+ padding: 0;
+ height: 18px;
+}
+
+#wpadminbar #wp-admin-bar-user-info .display-name,
+#wpadminbar #wp-admin-bar-user-info .username {
+ text-shadow: none;
+ display: block;
+}
+
+#wpadminbar #wp-admin-bar-user-info .display-name {
+ color: #333;
+}
+
+#wpadminbar #wp-admin-bar-user-info .username {
+ color: #999;
+ font-size: 11px;
+}
+
+#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
+ width: 16px;
+ height: 16px;
+ border: 1px solid #999;
+ padding: 0;
+ background: #eee;
+ line-height: 24px;
+ vertical-align: middle;
+ margin: -3px 0 0 6px;
+ float: none;
+ display: inline;
+}
+
+/*
+ * My Sites
+ */
+#wpadminbar .quicklinks li .blavatar {
+ vertical-align: middle;
+ margin: -3px 4px 0 0;
+ padding: 0;
+}
+
+#wpadminbar .quicklinks li div.blavatar {
+ background: url('../images/wpmini-blue.png') no-repeat;
+ height: 16px;
+ width: 16px;
+ display: inline-block;
+}
+
+/**
+ * Search
+ */
+#wpadminbar #wp-admin-bar-search .ab-item {
+ padding: 0;
+}
+
+#wpadminbar #wp-admin-bar-search .ab-item {
+ /* default background */
+ background: transparent;
+}
+
+#wpadminbar #adminbarsearch {
+ height: 28px;
+ padding: 0 2px;
+}
+
+#wpadminbar #adminbarsearch .adminbar-input {
+ font: 13px/24px sans-serif;
+ height: 24px;
+ width: 24px;
+ border: none;
+ padding: 0 3px 0 23px;
+ margin: 0;
+ color: #ccc;
+ text-shadow: #444 0px -1px 0px;
+ background-color: rgba( 255, 255, 255, 0 );
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: 3px 2px;
+ background-repeat: no-repeat;
+ outline: none;
+ cursor: pointer;
+
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+
+ -webkit-box-shadow: none;
+ box-shadow: none;
+
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+
+ -webkit-transition-duration: 400ms;
+ -webkit-transition-property: width, background;
+ -webkit-transition-timing-function: ease;
+ -moz-transition-duration: 400ms;
+ -moz-transition-property: width, background;
+ -moz-transition-timing-function: ease;
+ -o-transition-duration: 400ms;
+ -o-transition-property: width, background;
+ -o-transition-timing-function: ease;
+}
+
+#wpadminbar.ie7 #adminbarsearch .adminbar-input {
+ margin-top: 1px;
+ width: 120px;
+}
+
+#wpadminbar #adminbarsearch .adminbar-input:focus {
+ color: #555;
+ text-shadow: 0 1px 0 #fff;
+ width: 200px;
+ background-color: rgba( 255, 255, 255, 0.9 );
+ cursor: text;
+}
+
+#wpadminbar.ie8 #adminbarsearch .adminbar-input {
+ background-color: #464646;
+}
+
+#wpadminbar.ie8 #adminbarsearch .adminbar-input:focus {
+ background-color: #fff;
+}
+
+/* Two rules to ensure browser recognition */
+#wpadminbar #adminbarsearch .adminbar-input::-webkit-input-placeholder {
+ color: #ddd;
+}
+
+#wpadminbar #adminbarsearch .adminbar-input:-moz-placeholder {
+ color: #ddd;
+}
+
+#wpadminbar #adminbarsearch .adminbar-button {
+ display: none;
+}
+
+/**
+ * Site Menu
+ */
+#wpadminbar #wp-admin-bar-appearance {
+ border-top: none;
+ margin-top: -12px;
+}
+
+/**
+ * Site Menu
+ */
+#wpadminbar #wp-admin-bar-appearance {
+ border-top: none;
+ margin-top: -12px;
+}
+
+/**
+ * ICONS
+ */
+#wpadminbar .ab-icon {
+ position: relative;
+ float: left;
+ width: 16px;
+ height: 16px;
+ margin-top: 6px;
+}
+
+#wpadminbar .ab-label {
+ margin-left: 4px;
+}
+
+/**
+ * WP Logo icon
+ */
+#wp-admin-bar-wp-logo > .ab-item .ab-icon {
+ width: 20px;
+ height: 20px;
+ margin-top: 4px;
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: 0 -76px;
+ background-repeat: no-repeat;
+}
+
+#wpadminbar.nojs #wp-admin-bar-wp-logo:hover > .ab-item .ab-icon,
+#wpadminbar #wp-admin-bar-wp-logo.hover > .ab-item .ab-icon {
+ background-position: 0 -104px;
+}
+
+/**
+ * Updates icon
+ */
+#wp-admin-bar-updates > .ab-item .ab-icon {
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: -2px -159px;
+ background-repeat: no-repeat;
+}
+
+/**
+ * Comments icon
+ */
+#wp-admin-bar-comments > .ab-item .ab-icon {
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: -1px -134px;
+ background-repeat: no-repeat;
+}
+
+#wpadminbar span.count-0 {
+ display: none;
+}
+
+/**
+ * Add New icon
+ */
+#wpadminbar #wp-admin-bar-new-content > .ab-item .ab-icon {
+ background-image: url(../images/admin-bar-sprite.png?d=20120830);
+ background-position: -2px -182px;
+ background-repeat: no-repeat;
+}
+
+/**
+ * Add New icon
+ */
+#wpadminbar.nojs #wp-admin-bar-new-content:hover > .ab-item .ab-icon,
+#wpadminbar #wp-admin-bar-new-content.hover > .ab-item .ab-icon {
+ background-position: -2px -203px;
+}
+
+/**
+ * Customize support classes
+ */
+.no-customize-support .hide-if-no-customize,
+.customize-support .hide-if-customize,
+.no-customize-support.wp-core-ui .hide-if-no-customize,
+.no-customize-support .wp-core-ui .hide-if-no-customize,
+.customize-support.wp-core-ui .hide-if-customize,
+.customize-support .wp-core-ui .hide-if-customize {
+ display: none;
+}
+
+/**
+ * Retina display 2x icons
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ #wpadminbar .menupop .menupop > .ab-item,
+ #wpadminbar .ab-top-secondary .menupop .menupop > .ab-item,
+ #wpadminbar #adminbarsearch .adminbar-input,
+ #wp-admin-bar-wp-logo > .ab-item .ab-icon,
+ #wp-admin-bar-updates > .ab-item .ab-icon,
+ #wp-admin-bar-comments > .ab-item .ab-icon,
+ #wpadminbar #wp-admin-bar-new-content > .ab-item .ab-icon {
+ background-image: url(../images/admin-bar-sprite-2x.png?d=20120830);
+ background-size: 20px 220px;
+ }
+
+ #wpadminbar .quicklinks li div.blavatar {
+ background: url('../images/wpmini-blue-2x.png') no-repeat;
+ background-size: 16px 16px;
+ }
+}
+
+/* Skip link */
+#wpadminbar .screen-reader-text,
+#wpadminbar .screen-reader-text span {
+ position: absolute;
+ left: -1000em;
+ top: -1000em;
+ height: 1px;
+ width: 1px;
+ overflow: hidden;
+}
+
+#wpadminbar .screen-reader-shortcut {
+ position: absolute;
+ top: -1000em;
+}
+
+#wpadminbar .screen-reader-shortcut:focus {
+ left: 6px;
+ top: 7px;
+ height: auto;
+ width: auto;
+ display: block;
+ font-size: 14px;
+ font-weight: bold;
+ padding: 15px 23px 14px;
+ background: #f1f1f1;
+ color: #21759b;
+ text-shadow: none;
+ border-radius: 3px;
+ z-index: 100000;
+ line-height: normal;
+ -webkit-box-shadow: 0 0 2px 2px rgba(0,0,0,.6);
+ box-shadow: 0 0 2px 2px rgba(0,0,0,.6);
+ text-decoration: none;
+}
+
+/**
+ * IE 6-targeted rules
+ */
+* html #wpadminbar {
+ overflow: hidden;
+ position: absolute;
+}
+
+* html #wpadminbar .quicklinks ul li a {
+ float: left;
+}
+
+* html #wpadminbar .menupop a span {
+ background-image: none;
+}
diff --git a/src/wp-includes/css/buttons.css b/src/wp-includes/css/buttons.css
new file mode 100644
index 0000000000..5ae473c85c
--- /dev/null
+++ b/src/wp-includes/css/buttons.css
@@ -0,0 +1,288 @@
+/* ----------------------------------------------------------------------------
+
+
+WordPress-style Buttons
+=======================
+Create a button by adding the `.button` class to an element. For backwards
+compatibility, we support several other classes (such as `.button-secondary`),
+but these will *not* work with the stackable classes described below.
+
+Button Styles
+-------------
+To display a primary button style, add the `.button-primary` class to a button.
+
+Button Sizes
+------------
+Adjust a button's size by adding the `.button-large` or `.button-small` class.
+
+Button States
+-------------
+Lock the state of a button by adding the name of the pseudoclass as
+an actual class (e.g. `.hover` for `:hover`).
+
+
+TABLE OF CONTENTS:
+------------------
+ 1.0 - Button Layouts
+ 2.0 - Default Button Style
+ 3.0 - Primary Button Style
+ 4.0 - Button Groups
+
+---------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------------
+ 1.0 - Button Layouts
+---------------------------------------------------------------------------- */
+
+.wp-core-ui .button,
+.wp-core-ui .button-primary,
+.wp-core-ui .button-secondary {
+ display: inline-block;
+ text-decoration: none;
+ font-size: 12px;
+ line-height: 23px;
+ height: 24px;
+ margin: 0;
+ padding: 0 10px 1px;
+ cursor: pointer;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-radius: 3px;
+ -webkit-appearance: none;
+ border-radius: 3px;
+ white-space: nowrap;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+/* Remove the dotted border on :focus and the extra padding in Firefox */
+.wp-core-ui button::-moz-focus-inner,
+.wp-core-ui input[type="reset"]::-moz-focus-inner,
+.wp-core-ui input[type="button"]::-moz-focus-inner,
+.wp-core-ui input[type="submit"]::-moz-focus-inner {
+ border-width: 1px 0;
+ border-style: solid none;
+ border-color: transparent;
+ padding: 0;
+}
+
+.wp-core-ui .button.button-large,
+.wp-core-ui .button-group.button-large .button {
+ height: 30px;
+ line-height: 28px;
+ padding: 0 12px 2px;
+}
+
+.wp-core-ui .button.button-small,
+.wp-core-ui .button-group.button-small .button {
+ height: 21px;
+ line-height: 20px;
+ padding: 0 8px 1px;
+}
+
+.wp-core-ui .button.button-hero,
+.wp-core-ui .button-group.button-hero .button {
+ font-size: 14px;
+ height: 46px;
+ line-height: 44px;
+ padding: 0 36px;
+}
+
+.wp-core-ui .button:active {
+ outline: none;
+}
+
+.wp-core-ui .button.hidden {
+ display: none;
+}
+
+/* ----------------------------------------------------------------------------
+ 2.0 - Default Button Style
+---------------------------------------------------------------------------- */
+
+.wp-core-ui .button,
+.wp-core-ui .button-secondary {
+ background: #f3f3f3;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#f4f4f4));
+ background-image: -webkit-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: -moz-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: -o-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: linear-gradient(to bottom, #fefefe, #f4f4f4);
+ border-color: #bbb;
+ color: #333;
+ text-shadow: 0 1px 0 #fff;
+}
+
+.wp-core-ui .button.hover,
+.wp-core-ui .button:hover,
+.wp-core-ui .button-secondary:hover,
+.wp-core-ui .button.focus,
+.wp-core-ui .button:focus,
+.wp-core-ui .button-secondary:focus {
+ background: #f3f3f3;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f3f3f3));
+ background-image: -webkit-linear-gradient(top, #fff, #f3f3f3);
+ background-image: -moz-linear-gradient(top, #fff, #f3f3f3);
+ background-image: -ms-linear-gradient(top, #fff, #f3f3f3);
+ background-image: -o-linear-gradient(top, #fff, #f3f3f3);
+ background-image: linear-gradient(to bottom, #fff, #f3f3f3);
+ border-color: #999;
+ color: #222;
+}
+
+.wp-core-ui .button.focus,
+.wp-core-ui .button:focus,
+.wp-core-ui .button-secondary:focus {
+ -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
+ box-shadow: 1px 1px 1px rgba(0,0,0,.2);
+}
+
+.wp-core-ui .button.active,
+.wp-core-ui .button.active:hover,
+.wp-core-ui .button.active:focus,
+.wp-core-ui .button:active,
+.wp-core-ui .button-secondary:active {
+ background: #eee;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#fefefe));
+ background-image: -webkit-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: -moz-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: -ms-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: -o-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: linear-gradient(to bottom, #f4f4f4, #fefefe);
+ border-color: #999;
+ color: #333;
+ text-shadow: 0 -1px 0 #fff;
+ -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
+ box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
+}
+
+.wp-core-ui .button[disabled],
+.wp-core-ui .button:disabled,
+.wp-core-ui .button-secondary[disabled],
+.wp-core-ui .button-secondary:disabled,
+.wp-core-ui .button-disabled {
+ color: #aaa !important;
+ border-color: #ddd !important;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f9f9f9), to(#f4f4f4)) !important;
+ background-image: -webkit-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
+ background-image: -moz-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
+ background-image: -ms-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
+ background-image: -o-linear-gradient(top, #f9f9f9, #f4f4f4) !important;
+ background-image: linear-gradient(to bottom, #f9f9f9, #f4f4f4) !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ text-shadow: 0 1px 0 #fff !important;
+ cursor: default;
+}
+
+/* ----------------------------------------------------------------------------
+ 3.0 - Primary Button Style
+---------------------------------------------------------------------------- */
+
+.wp-core-ui .button-primary {
+ background-color: #21759b;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#2a95c5), to(#21759b));
+ background-image: -webkit-linear-gradient(top, #2a95c5, #21759b);
+ background-image: -moz-linear-gradient(top, #2a95c5, #21759b);
+ background-image: -ms-linear-gradient(top, #2a95c5, #21759b);
+ background-image: -o-linear-gradient(top, #2a95c5, #21759b);
+ background-image: linear-gradient(to bottom, #2a95c5, #21759b);
+ border-color: #21759b;
+ border-bottom-color: #1e6a8d;
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.5);
+ box-shadow: inset 0 1px 0 rgba(120,200,230,0.5);
+ color: #fff;
+ text-decoration: none;
+ text-shadow: 0 1px 0 rgba(0,0,0,0.1);
+}
+
+.wp-core-ui .button-primary.hover,
+.wp-core-ui .button-primary:hover,
+.wp-core-ui .button-primary.focus,
+.wp-core-ui .button-primary:focus {
+ background-color: #278ab7;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#2e9fd2), to(#21759b));
+ background-image: -webkit-linear-gradient(top, #2e9fd2, #21759b);
+ background-image: -moz-linear-gradient(top, #2e9fd2, #21759b);
+ background-image: -ms-linear-gradient(top, #2e9fd2, #21759b);
+ background-image: -o-linear-gradient(top, #2e9fd2, #21759b);
+ background-image: linear-gradient(to bottom, #2e9fd2, #21759b);
+ border-color: #1b607f;
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.6);
+ box-shadow: inset 0 1px 0 rgba(120,200,230,0.6);
+ color: #fff;
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
+}
+
+.wp-core-ui .button-primary.focus,
+.wp-core-ui .button-primary:focus {
+ border-color: #0e3950;
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,0.6), 1px 1px 2px rgba(0,0,0,0.4);
+ box-shadow: inset 0 1px 0 rgba(120,200,230,0.6), 1px 1px 2px rgba(0,0,0,0.4);
+}
+
+.wp-core-ui .button-primary.active,
+.wp-core-ui .button-primary.active:hover,
+.wp-core-ui .button-primary.active:focus,
+.wp-core-ui .button-primary:active {
+ background: #1b607f;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#21759b), to(#278ab7));
+ background-image: -webkit-linear-gradient(top, #21759b, #278ab7);
+ background-image: -moz-linear-gradient(top, #21759b, #278ab7);
+ background-image: -ms-linear-gradient(top, #21759b, #278ab7);
+ background-image: -o-linear-gradient(top, #21759b, #278ab7);
+ background-image: linear-gradient(to bottom, #21759b, #278ab7);
+ border-color: #124560 #2382ae #2382ae #2382ae;
+ color: rgba(255,255,255,0.95);
+ -webkit-box-shadow: inset 0 1px 0 rgba(0,0,0,0.1);
+ box-shadow: inset 0 1px 0 rgba(0,0,0,0.1);
+ text-shadow: 0 1px 0 rgba(0,0,0,0.1);
+}
+
+.wp-core-ui .button-primary[disabled],
+.wp-core-ui .button-primary:disabled,
+.wp-core-ui .button-primary-disabled {
+ color: #94cde7 !important;
+ background: #298cba !important;
+ border-color: #1b607f !important;
+ -webkit-box-shadow: none !important;
+ box-shadow: none !important;
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.1) !important;
+ cursor: default;
+}
+
+/* ----------------------------------------------------------------------------
+ 4.0 - Button Groups
+---------------------------------------------------------------------------- */
+
+.wp-core-ui .button-group {
+ position: relative;
+ display: inline-block;
+ white-space: nowrap;
+ font-size: 0;
+ vertical-align: middle;
+}
+
+.wp-core-ui .button-group > .button {
+ display: inline-block;
+ border-radius: 0;
+ margin-right: -1px;
+ z-index: 10;
+}
+
+.wp-core-ui .button-group > .button-primary {
+ z-index: 100;
+}
+
+.wp-core-ui .button-group > .button:hover {
+ z-index: 20;
+}
+
+.wp-core-ui .button-group > .button:first-child {
+ border-radius: 3px 0 0 3px;
+}
+
+.wp-core-ui .button-group > .button:last-child {
+ border-radius: 0 3px 3px 0;
+}
diff --git a/src/wp-includes/css/editor.css b/src/wp-includes/css/editor.css
new file mode 100644
index 0000000000..1728560879
--- /dev/null
+++ b/src/wp-includes/css/editor.css
@@ -0,0 +1,2289 @@
+
+/*------------------------------------------------------------------------------
+ TinyMCE and Quicklinks toolbars
+------------------------------------------------------------------------------*/
+
+/* wp_theme/ui.css */
+.wp_themeSkin table,
+.wp_themeSkin tbody,
+.wp_themeSkin a,
+.wp_themeSkin img,
+.wp_themeSkin tr,
+.wp_themeSkin div,
+.wp_themeSkin td,
+.wp_themeSkin iframe,
+.wp_themeSkin span,
+.wp_themeSkin *,
+.wp_themeSkin .mceText {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ white-space: nowrap;
+ text-decoration: none;
+ font-weight: normal;
+ cursor: default;
+ vertical-align: baseline;
+ width: auto;
+ border-collapse: separate;
+}
+
+.wp_themeSkin a:hover,
+.wp_themeSkin a:link,
+.wp_themeSkin a:visited,
+.wp_themeSkin a:active {
+ text-decoration: none;
+ font-weight: normal;
+ cursor: default;
+}
+
+.wp_themeSkin table td {
+ vertical-align: middle;
+}
+
+.wp_themeSkin *,
+.wp_themeSkin a:hover,
+.wp_themeSkin a:link,
+.wp_themeSkin a:visited,
+.wp_themeSkin a:active {
+ color: #555;
+}
+
+/* Containers */
+.wp_themeSkin table {}
+
+.wp_themeSkin iframe {
+ display: block;
+}
+
+.wp_themeSkin #mce_fullscreen_ifr {
+ background-color: #fff;
+}
+
+.wp_themeSkin .mceToolbar {
+ padding: 1px;
+}
+
+/* External */
+.wp_themeSkin .mceExternalToolbar {
+ position: absolute;
+ border-bottom: 0;
+ display: none;
+}
+
+.wp_themeSkin .mceExternalToolbar td.mceToolbar {
+ padding-right: 13px;
+}
+
+.wp_themeSkin .mceExternalClose {
+ position: absolute;
+ top: 3px;
+ right: 3px;
+ width: 7px;
+ height: 7px;
+ background: url("../js/tinymce/themes/advanced/img/icons.gif") -820px 0;
+}
+
+/* Layout */
+.wp_themeSkin table.mceToolbar,
+.wp_themeSkin tr.mceFirst .mceToolbar tr td,
+.wp_themeSkin tr.mceLast .mceToolbar tr td {
+ border: 0;
+ margin: 0;
+ padding: 0;
+}
+
+.wp_themeSkin table.mceLayout {
+ border: 0;
+}
+
+.wp_themeSkin .mceStatusbar {
+ display: block;
+ font-family: sans-serif;
+ font-size: 12px;
+ line-height: 16px;
+ padding: 0 0 0 8px;
+ overflow: visible;
+ height: 20px;
+ border-top: 1px solid #dfdfdf;
+ color: #000;
+ background-color: #f5f5f5;
+}
+
+.rtl .wp_themeSkin .mceStatusbar {
+ padding: 0 8px 0 0;
+}
+
+.wp_themeSkin .mceStatusbar * {
+ color: #555;
+}
+
+.wp_themeSkin .mceStatusbar div {
+ float: left;
+ padding: 2px;
+}
+
+.rtl .wp_themeSkin .mceStatusbar div {
+ float: right;
+}
+
+.wp_themeSkin .mceStatusbar a.mceResize {
+ display: block;
+ float: right;
+ background: url("../js/tinymce/themes/advanced/img/icons.gif") -800px 0;
+ width: 20px;
+ height: 20px;
+ cursor: se-resize;
+}
+
+.rtl .wp_themeSkin .mceStatusbar a.mceResize {
+ float: left;
+}
+
+.wp_themeSkin .mceStatusbar a:hover {
+ text-decoration: underline;
+}
+
+.wp_themeSkin table.mceToolbar {
+ margin: 0 6px 2px;
+}
+
+.wp_themeSkin table.mceToolbar :active,
+.wp_themeSkin table.mceToolbar :focus,
+.wp_themeSkin table.mceToolbar:focus,
+.wp_themeSkin span.mceSeparator:focus {
+ outline: none;
+}
+
+.wp_themeSkin #content_toolbar1 {
+ margin-top: 2px;
+}
+
+.wp_themeSkin .mceToolbar .mceToolbarEndListBox span {
+ display: none;
+}
+
+.wp_themeSkin span.mceIcon,
+.wp_themeSkin img.mceIcon {
+ display: block;
+ width: 20px;
+ height: 20px;
+}
+
+.wp_themeSkin .mceIcon {
+ background: url("../js/tinymce/themes/advanced/img/icons.gif") no-repeat 20px 20px;
+}
+
+/* Button */
+.wp_themeSkin .mceButton {
+ display: block;
+ width: 20px;
+ height: 20px;
+ cursor: default;
+ padding: 1px 2px;
+ margin: 1px;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+}
+
+.wp_themeSkin a.mceButtonEnabled:hover {
+ background-image: inherit 0 -10px;
+}
+
+.wp_themeSkin .mceOldBoxModel a.mceButton span, .wp_themeSkin .mceOldBoxModel a.mceButton img {
+ margin: 0 0 0 1px;
+}
+
+.wp_themeSkin .mceButtonDisabled .mceIcon {
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+
+/* Separator */
+.wp_themeSkin .mceSeparator {
+ display: none;
+}
+
+/* ListBox */
+.wp_themeSkin .mceListBox,
+.wp_themeSkin .mceListBox a {
+ display: block;
+}
+
+.wp_themeSkin .mceListBox .mceText {
+ padding: 1px 4px 1px 5px;
+ width: 70px;
+ text-align: left;
+ text-decoration: none;
+ -webkit-border-bottom-left-radius: 2px;
+ -webkit-border-top-left-radius: 2px;
+ border-bottom-left-radius: 2px;
+ border-top-left-radius: 2px;
+ font-family: sans-serif;
+ font-size: 12px;
+ height: 20px;
+ line-height: 20px;
+ overflow: hidden;
+}
+
+.wp_themeSkin .mceListBox {
+ margin: 1px;
+ direction: ltr;
+ background-color: #fff;
+ border: 1px solid #ddd;
+ -webkit-box-shadow: inset 0 1px 1px -1px rgba(0, 0, 0, .2);
+ box-shadow: inset 0 1px 1px -1px rgba(0, 0, 0, .2);
+}
+
+.wp_themeSkin .mceListBox .mceOpen {
+ width: 12px;
+ height: 20px;
+ border-collapse: separate;
+ padding: 1px;
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-top-left-radius: 0;
+}
+
+.wp_themeSkin .mceListBox .mceFirst a {
+ border-style: solid;
+ border-width: 1px;
+ border-bottom-right-radius: 2px;
+ border-top-right-radius: 2px;
+}
+
+.wp_themeSkin .mceListBoxMenu .mce_formatPreview {
+ line-height: normal;
+}
+
+.wp_themeSkin .mceListBox .mceOpen,
+.wp_themeSkin .mceListBoxHover .mceOpen,
+.wp_themeSkin .mceListBoxSelected .mceOpen,
+.wp_themeSkin table.mceListBoxEnabled .mceOpen {
+ background-image: url("../images/down_arrow.gif");
+ background-position: 3px 1px;
+ background-repeat: no-repeat;
+}
+
+.wp_themeSkin .mceListBoxDisabled .mceText {
+ color: gray;
+}
+
+.wp_themeSkin .mceListBoxMenu {
+ overflow: auto;
+ overflow-x: hidden;
+}
+
+.wp_themeSkin .mceOldBoxModel .mceListBox .mceText {
+ height: 22px;
+}
+
+.wp_themeSkin select.mceListBox {
+ font-family: sans-serif;
+ font-size: 12px;
+ border-color: #b2b2b2;
+ background-color: #fff;
+}
+
+/* SplitButton */
+.wp_themeSkin .mceSplitButton a,
+.wp_themeSkin .mceSplitButton span {
+ display: block;
+ height: 20px;
+}
+
+.wp_themeSkin .mceSplitButton {
+ display: block;
+ direction: ltr;
+}
+
+.wp_themeSkin table.mceSplitButton td {
+ padding: 2px;
+ -webkit-border-radius: 2px;
+ border-radius: 2px;
+}
+
+.wp_themeSkin table.mceSplitButton:hover td {
+ background-image: inherit 0 -10px;
+}
+
+.wp_themeSkin .mceSplitButton a.mceAction {
+ height: 20px;
+ width: 20px;
+ padding: 1px 2px;
+ border-right: 0 none;
+}
+
+.wp_themeSkin .mceSplitButton span.mceAction {
+ background-image: url("../js/tinymce/themes/advanced/img/icons.gif");
+ background-repeat: no-repeat;
+ background-color: transparent;
+ width: 20px;
+}
+
+.wp_themeSkin .mceSplitButton a.mceOpen {
+ width: 11px;
+ height: 20px;
+ background-position: 0px 2px;
+ background-repeat: no-repeat;
+ padding: 1px 0;
+}
+
+.wp_themeSkin .mceSplitButton span.mceOpen {
+ display: none;
+}
+
+.wp_themeSkin .mceSplitButtonDisabled .mceAction {
+ opacity: 0.3;
+ filter: alpha(opacity=30);
+}
+
+.wp_themeSkin .mceListBox a.mceText,
+.wp_themeSkin .mceSplitButton a.mceAction {
+ -webkit-border-bottom-left-radius: 2px;
+ -webkit-border-top-left-radius: 2px;
+ border-bottom-left-radius: 2px;
+ border-top-left-radius: 2px;
+}
+
+.wp_themeSkin .mceSplitButton a.mceOpen,
+.wp_themeSkin .mceListBox a.mceOpen {
+ -webkit-border-bottom-right-radius: 2px;
+ -webkit-border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+ border-top-right-radius: 2px;
+}
+
+.wp_themeSkin span.mce_undo,
+.wp_themeSkin span.mce_redo,
+.wp_themeSkin span.mce_bullist,
+.wp_themeSkin span.mce_numlist,
+.wp_themeSkin span.mce_blockquote,
+.wp_themeSkin span.mce_charmap,
+.wp_themeSkin span.mce_bold,
+.wp_themeSkin span.mce_italic,
+.wp_themeSkin span.mce_underline,
+.wp_themeSkin span.mce_justifyleft,
+.wp_themeSkin span.mce_justifyright,
+.wp_themeSkin span.mce_justifycenter,
+.wp_themeSkin span.mce_justifyfull,
+.wp_themeSkin span.mce_indent,
+.wp_themeSkin span.mce_outdent,
+.wp_themeSkin span.mce_link,
+.wp_themeSkin span.mce_unlink,
+.wp_themeSkin span.mce_help,
+.wp_themeSkin span.mce_removeformat,
+.wp_themeSkin span.mce_fullscreen,
+.wp_themeSkin span.mce_wp_fullscreen,
+.wp_themeSkin span.mce_media,
+.wp_themeSkin span.mce_pastetext,
+.wp_themeSkin span.mce_pasteword,
+.wp_themeSkin span.mce_wp_help,
+.wp_themeSkin span.mce_wp_adv,
+.wp_themeSkin span.mce_wp_more,
+.wp_themeSkin span.mce_strikethrough,
+.wp_themeSkin span.mce_spellchecker,
+.wp_themeSkin span.mce_forecolor,
+.wp_themeSkin .mce_forecolorpicker,
+.wp_themeSkin .mceSplitButton .mce_spellchecker span.mce_spellchecker,
+.wp_themeSkin .mceSplitButton .mce_forecolor span.mce_forecolor,
+.wp_themeSkin .mceSplitButton span.mce_numlist,
+.wp_themeSkin .mceSplitButton span.mce_bullist {
+ background-image: url('../images/wpicons.png?ver=20120720');
+}
+
+/* ColorSplitButton */
+.wp_themeSkin div.mceColorSplitMenu table {
+ background-color: #ebebeb;
+ border-color: #bbb;
+}
+
+.wp_themeSkin .mceColorSplitMenu td {
+ padding: 2px;
+}
+
+.wp_themeSkin .mceColorSplitMenu a {
+ display: block;
+ width: 9px;
+ height: 9px;
+ overflow: hidden;
+ border-color: #B2B2B2;
+}
+
+.wp_themeSkin .mceColorSplitMenu td.mceMoreColors {
+ padding: 1px 3px 1px 1px;
+}
+
+.wp_themeSkin .mceColorSplitMenu a.mceMoreColors {
+ width: 100%;
+ height: auto;
+ text-align: center;
+ font-family: Tahoma,Verdana,Arial,Helvetica;
+ font-size: 11px;
+ line-height: 20px;
+ border-color: #fff;
+}
+
+.wp_themeSkin .mceColorSplitMenu a.mceMoreColors:hover {}
+.wp_themeSkin a.mceMoreColors:hover {}
+.wp_themeSkin .mceColorPreview {
+ margin: -5px 0 0 2px;
+ width: 16px;
+ height: 4px;
+ overflow: hidden;
+}
+
+/* Menu */
+.wp_themeSkin .mceMenu {
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 1000;
+ border-color: #ddd;
+ direction: ltr;
+}
+
+.wp_themeSkin .mceNoIcons span.mceIcon {
+ width: 0;
+}
+
+.wp_themeSkin .mceNoIcons a .mceText {
+ padding-left: 10px;
+}
+
+.wp_themeSkin .mceMenu table {
+ background-color: #ebeaeb;
+}
+
+.wp_themeSkin .mceMenu a,
+.wp_themeSkin .mceMenu span,
+.wp_themeSkin .mceMenu {
+ display: block;
+}
+
+.wp_themeSkin .mceMenu td {
+ height: 20px;overflow: hidden;
+}
+
+.wp_themeSkin .mceMenu a {
+ position: relative;
+ padding: 3px 0 4px 0;
+ text-decoration: none !important;
+}
+
+.wp_themeSkin .mceMenu .mceText {
+ position: relative;
+ display: block;
+ font-family: Tahoma,Verdana,Arial,Helvetica;
+ cursor: default;
+ margin: 0;
+ padding: 0 25px;
+ color: #000;
+}
+
+.wp_themeSkin .mceMenu span.mceText, .wp_themeSkin .mceMenu .mcePreview {
+ font-size: 12px;
+}
+
+.wp_themeSkin .mceMenu pre.mceText {
+ font-family: Monospace;
+}
+
+.wp_themeSkin .mceMenu .mceIcon {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 22px;
+}
+
+.wp_themeSkin .mceMenu .mceMenuItemEnabled a:hover,
+.wp_themeSkin .mceMenu .mceMenuItemActive {
+ background-color: #f5f5f5;
+}
+
+.wp_themeSkin td.mceMenuItemSeparator {
+ height: 1px;
+ background-color: #aaa;
+}
+
+.wp_themeSkin .mceMenuItemTitle a {
+ border-top: 0;
+ border-right: 0;
+ border-left: 0;
+ border-bottom: 1px solid #aaa;
+ text-decoration: none !important;
+ background-color: #ccc;
+}
+
+.wp_themeSkin .mceMenuItemTitle span.mceText {
+ font-weight: bold;
+ padding-left: 4px;
+ color: #000;
+}
+
+.wp_themeSkin .mceMenuItemSelected .mceIcon {
+ background: url("../js/tinymce/themes/advanced/skins/default/img/menu_check.gif");
+ color: #888;
+}
+
+.wp_themeSkin .mceNoIcons .mceMenuItemSelected a {
+ background: url("../js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif") no-repeat -6px center;
+}
+
+.wp_themeSkin .mceMenu span.mceMenuLine {
+ display: none;
+}
+
+.wp_themeSkin .mceMenuItemSub a {
+ background: url("../js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif") no-repeat top right;
+}
+
+/* Progress,Resize */
+.wp_themeSkin .mceBlocker {
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 1000;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+ background: #FFF;
+}
+
+.wp_themeSkin .mceProgress {
+ position: absolute;
+ left: 0;
+ top: 0;
+ z-index: 1001;
+ background: url("../js/tinymce/themes/advanced/skins/default/img/progress.gif") no-repeat;
+ width: 32px;
+ height: 32px;
+ margin: -16px 0 0 -16px;
+}
+
+.wp_themeSkin .mcePlaceHolder {
+ border: 1px dotted gray;
+}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {
+ text-align: right;
+ padding: 0 4px 0 0;
+}
+
+.mceRtl .mceMenuItem .mceText {
+ text-align: right;
+}
+
+/* Formats */
+.wp_themeSkin .mce_p span.mceText {}
+.wp_themeSkin .mce_address span.mceText {
+ font-style: italic;
+}
+
+.wp_themeSkin .mce_pre span.mceText {
+ font-family: monospace;
+}
+
+.wp_themeSkin .mce_h1 span.mceText {
+ font-weight: bolder;
+ font-size: 18px;
+}
+
+.wp_themeSkin .mce_h2 span.mceText {
+ font-weight: bolder;
+ font-size: 16px;
+}
+
+.wp_themeSkin .mce_h3 span.mceText {
+ font-weight: bolder;
+ font-size: 14px;
+}
+
+.wp_themeSkin .mce_h4 span.mceText {
+ font-weight: bolder;
+ font-size: 12px;
+}
+
+.wp_themeSkin .mce_h5 span.mceText {
+ font-weight: bolder;
+ font-size: 11px;
+}
+
+.wp_themeSkin .mce_h6 span.mceText {
+ font-weight: bolder;
+ font-size: 10px;
+}
+
+/* Theme */
+.wp_themeSkin span.mce_undo {background-position:-500px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_undo,
+.wp_themeSkin .mceButtonActive span.mce_undo {background-position:-500px 0}
+
+.wp_themeSkin span.mce_redo {background-position:-480px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_redo,
+.wp_themeSkin .mceButtonActive span.mce_redo {background-position:-480px 0}
+
+.wp_themeSkin span.mce_bullist {background-position:-40px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_bullist,
+.wp_themeSkin .mceButtonActive span.mce_bullist,
+.wp_themeSkin .mceSplitButton:hover span.mce_bullist {background-position:-40px 0}
+
+.wp_themeSkin span.mce_numlist {background-position:-60px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_numlist,
+.wp_themeSkin .mceButtonActive span.mce_numlist,
+.wp_themeSkin .mceSplitButton:hover span.mce_numlist {background-position:-60px 0}
+
+.wp_themeSkin span.mce_blockquote {background-position:-80px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_blockquote,
+.wp_themeSkin .mceButtonActive span.mce_blockquote {background-position:-80px 0}
+
+.wp_themeSkin span.mce_charmap {background-position:-420px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_charmap,
+.wp_themeSkin .mceButtonActive span.mce_charmap {background-position:-420px 0}
+
+.wp_themeSkin span.mce_bold {background-position:0 -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_bold,
+.wp_themeSkin .mceButtonActive span.mce_bold {background-position:0 0}
+
+.wp_themeSkin span.mce_italic {background-position:-20px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_italic,
+.wp_themeSkin .mceButtonActive span.mce_italic {background-position:-20px 0}
+
+.wp_themeSkin span.mce_underline {background-position:-280px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_underline,
+.wp_themeSkin .mceButtonActive span.mce_underline {background-position:-280px 0}
+
+.wp_themeSkin span.mce_justifyleft {background-position:-100px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_justifyleft,
+.wp_themeSkin .mceButtonActive span.mce_justifyleft {background-position:-100px 0}
+
+.wp_themeSkin span.mce_justifyright {background-position:-140px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_justifyright,
+.wp_themeSkin .mceButtonActive span.mce_justifyright {background-position:-140px 0}
+
+.wp_themeSkin span.mce_justifycenter {background-position:-120px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_justifycenter,
+.wp_themeSkin .mceButtonActive span.mce_justifycenter {background-position:-120px 0}
+
+.wp_themeSkin span.mce_justifyfull {background-position:-300px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_justifyfull,
+.wp_themeSkin .mceButtonActive span.mce_justifyfull {background-position:-300px 0}
+
+.wp_themeSkin span.mce_indent {background-position:-460px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_indent,
+.wp_themeSkin .mceButtonActive span.mce_indent {background-position:-460px 0}
+
+.wp_themeSkin span.mce_outdent {background-position:-440px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_outdent,
+.wp_themeSkin .mceButtonActive span.mce_outdent {background-position:-440px 0}
+
+.wp_themeSkin span.mce_link {background-position:-160px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_link,
+.wp_themeSkin .mceButtonActive span.mce_link {background-position:-160px 0}
+
+.wp_themeSkin span.mce_unlink {background-position:-180px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_unlink,
+.wp_themeSkin .mceButtonActive span.mce_unlink {background-position:-180px 0}
+
+.wp_themeSkin span.mce_help {background-position:-520px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_help,
+.wp_themeSkin .mceButtonActive span.mce_help {background-position:-520px 0}
+
+.wp_themeSkin span.mce_removeformat {background-position:-380px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_removeformat,
+.wp_themeSkin .mceButtonActive span.mce_removeformat {background-position:-380px 0}
+
+.wp_themeSkin span.mce_strikethrough {background-position:-540px -20px;}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_strikethrough,
+.wp_themeSkin .mceButtonActive span.mce_strikethrough {background-position:-540px 0}
+
+.wp_themeSkin .mceSplitButton .mce_forecolor span.mce_forecolor {background-position:-320px -20px}
+.wp_themeSkin .mceSplitButtonEnabled:hover span.mce_forecolor,
+.wp_themeSkin .mceSplitButtonSelected span.mce_forecolor {background-position:-320px 0}
+
+.wp_themeSkin .mce_forecolorpicker {background-position:-320px -20px}
+
+/* Plugins in WP */
+.wp_themeSkin span.mce_fullscreen {background-position:-240px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_fullscreen,
+.wp_themeSkin .mceButtonActive span.mce_fullscreen {background-position:-240px 0}
+
+.wp_themeSkin span.mce_wp_fullscreen {background-position:-240px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_wp_fullscreen,
+.wp_themeSkin .mceButtonActive span.mce_wp_fullscreen {background-position:-240px 0}
+
+.wp_themeSkin span.mce_media {background-position:-400px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_media,
+.wp_themeSkin .mceButtonActive span.mce_media {background-position:-400px 0}
+
+.wp_themeSkin span.mce_pastetext {background-position:-340px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_pastetext,
+.wp_themeSkin .mceButtonActive span.mce_pastetext {background-position:-340px 0}
+
+.wp_themeSkin span.mce_pasteword {background-position:-360px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_pasteword,
+.wp_themeSkin .mceButtonActive span.mce_pasteword {background-position:-360px 0}
+
+.wp_themeSkin span.mce_spellchecker {background-position:-220px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_spellchecker,
+.wp_themeSkin .mceSplitButtonEnabled:hover span.mce_spellchecker,
+.wp_themeSkin .mceButtonActive span.mce_spellchecker,
+.wp_themeSkin .mceSplitButtonSelected span.mce_spellchecker {background-position:-220px 0}
+
+.wp_themeSkin span.mce_wp_help {background-position:-520px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_wp_help,
+.wp_themeSkin .mceButtonActive span.mce_wp_help {background-position:-520px 0}
+
+.wp_themeSkin span.mce_wp_adv {background-position:-260px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_wp_adv,
+.wp_themeSkin .mceButtonActive span.mce_wp_adv {background-position:-260px 0}
+
+.wp_themeSkin span.mce_wp_more {background-position:-200px -20px}
+.wp_themeSkin .mceButtonEnabled:hover span.mce_wp_more,
+.wp_themeSkin .mceButtonActive span.mce_wp_more {background-position:-200px 0}
+
+/* Default icons */
+.wp_themeSkin span.mce_cleanup {background-position:-380px -20px}
+.wp_themeSkin span.mce_anchor {background-position:-200px 0}
+.wp_themeSkin span.mce_sub {background-position:-600px 0}
+.wp_themeSkin span.mce_sup {background-position:-620px 0}
+.wp_themeSkin span.mce_newdocument {background-position:-520px 0}
+.wp_themeSkin span.mce_image {background-position:-380px 0}
+.wp_themeSkin span.mce_code {background-position:-260px 0}
+.wp_themeSkin span.mce_hr {background-position:-360px 0}
+.wp_themeSkin span.mce_visualaid {background-position:-660px 0}
+.wp_themeSkin span.mce_paste {background-position:-560px 0}
+.wp_themeSkin span.mce_copy {background-position:-700px 0}
+.wp_themeSkin span.mce_cut {background-position:-680px 0}
+.wp_themeSkin .mce_backcolor span.mceAction {background-position:-760px 0}
+.wp_themeSkin .mce_backcolorpicker {background-position:-760px 0}
+
+/* Plugins */
+.wp_themeSkin span.mce_advhr {background-position:-0px -20px}
+.wp_themeSkin span.mce_ltr {background-position:-20px -20px}
+.wp_themeSkin span.mce_rtl {background-position:-40px -20px}
+.wp_themeSkin span.mce_emotions {background-position:-60px -20px}
+.wp_themeSkin span.mce_fullpage {background-position:-80px -20px}
+.wp_themeSkin span.mce_iespell {background-position:-120px -20px}
+.wp_themeSkin span.mce_insertdate {background-position:-140px -20px}
+.wp_themeSkin span.mce_inserttime {background-position:-160px -20px}
+.wp_themeSkin span.mce_absolute {background-position:-180px -20px}
+.wp_themeSkin span.mce_backward {background-position:-200px -20px}
+.wp_themeSkin span.mce_forward {background-position:-220px -20px}
+.wp_themeSkin span.mce_insert_layer {background-position:-240px -20px}
+.wp_themeSkin span.mce_insertlayer {background-position:-260px -20px}
+.wp_themeSkin span.mce_movebackward {background-position:-280px -20px}
+.wp_themeSkin span.mce_moveforward {background-position:-300px -20px}
+.wp_themeSkin span.mce_nonbreaking {background-position:-340px -20px}
+.wp_themeSkin span.mce_selectall {background-position:-400px -20px}
+.wp_themeSkin span.mce_preview {background-position:-420px -20px}
+.wp_themeSkin span.mce_print {background-position:-440px -20px}
+.wp_themeSkin span.mce_cancel {background-position:-460px -20px}
+.wp_themeSkin span.mce_save {background-position:-480px -20px}
+.wp_themeSkin span.mce_replace {background-position:-500px -20px}
+.wp_themeSkin span.mce_search {background-position:-520px -20px}
+.wp_themeSkin span.mce_styleprops {background-position:-560px -20px}
+.wp_themeSkin span.mce_table {background-position:-580px -20px}
+.wp_themeSkin span.mce_cell_props {background-position:-600px -20px}
+.wp_themeSkin span.mce_delete_table {background-position:-620px -20px}
+.wp_themeSkin span.mce_delete_col {background-position:-640px -20px}
+.wp_themeSkin span.mce_delete_row {background-position:-660px -20px}
+.wp_themeSkin span.mce_col_after {background-position:-680px -20px}
+.wp_themeSkin span.mce_col_before {background-position:-700px -20px}
+.wp_themeSkin span.mce_row_after {background-position:-720px -20px}
+.wp_themeSkin span.mce_row_before {background-position:-740px -20px}
+.wp_themeSkin span.mce_merge_cells {background-position:-760px -20px}
+.wp_themeSkin span.mce_table_props {background-position:-980px -20px}
+.wp_themeSkin span.mce_row_props {background-position:-780px -20px}
+.wp_themeSkin span.mce_split_cells {background-position:-800px -20px}
+.wp_themeSkin span.mce_template {background-position:-820px -20px}
+.wp_themeSkin span.mce_visualchars {background-position:-840px -20px}
+.wp_themeSkin span.mce_abbr {background-position:-860px -20px}
+.wp_themeSkin span.mce_acronym {background-position:-880px -20px}
+.wp_themeSkin span.mce_attribs {background-position:-900px -20px}
+.wp_themeSkin span.mce_cite {background-position:-920px -20px}
+.wp_themeSkin span.mce_del {background-position:-940px -20px}
+.wp_themeSkin span.mce_ins {background-position:-960px -20px}
+.wp_themeSkin span.mce_pagebreak {background-position:0 -40px}
+.wp_themeSkin span.mce_restoredraft {background-position:-20px -40px}
+.wp_themeSkin span.mce_visualblocks {background-position: -40px -40px}
+
+/* border */
+.wp_themeSkin .mceExternalToolbar,
+.wp_themeSkin .mceButton,
+.wp_themeSkin a.mceButtonEnabled:hover,
+.wp_themeSkin a.mceButtonActive,
+.wp_themeSkin a.mceButtonSelected,
+.wp_themeSkin .mceListBox .mceText,
+.wp_themeSkin .mceListBox .mceOpen,
+.wp_themeSkin select.mceListBox,
+.wp_themeSkin .mceSplitButton a.mceAction,
+.wp_themeSkin .mceSplitButton a.mceOpen,
+.wp_themeSkin .mceSplitButton a.mceOpen:hover,
+.wp_themeSkin .mceSplitButtonSelected a.mceOpen,
+.wp_themeSkin table.mceSplitButtonEnabled:hover a.mceAction,
+.wp_themeSkin .mceSplitButton a.mceAction:hover,
+.wp_themeSkin div.mceColorSplitMenu table,
+.wp_themeSkin .mceColorSplitMenu a,
+.wp_themeSkin .mceColorSplitMenu a.mceMoreColors,
+.wp_themeSkin .mceColorSplitMenu a.mceMoreColors:hover,
+.wp_themeSkin a.mceMoreColors:hover,
+.wp_themeSkin .mceMenu {
+ border-style: solid;
+ border-width: 1px;
+}
+.wp_themeSkin .mceListBox .mceText {
+ border-right: 0 none;
+}
+.wp_themeSkin iframe {
+ background: transparent;
+}
+
+.wp_themeSkin .mceButton {
+ border-color: transparent;
+}
+
+.wp_themeSkin .mceListBox .mceText,
+.wp_themeSkin .mceListBox .mceOpen {
+ border-color: transparent;
+}
+
+.wp_themeSkin a.mceButtonEnabled:hover,
+.wp_themeSkin table.mceSplitButton:hover {
+ border-color: #bbb;
+ background: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#e5e5e5), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #e5e5e5, #fff);
+ background-image: -moz-linear-gradient(bottom, #e5e5e5, #fff);
+ background-image: -o-linear-gradient(bottom, #e5e5e5, #fff);
+ background-image: linear-gradient(to top, #e5e5e5, #fff);
+}
+
+.wp_themeSkin a.mceButton:active,
+.wp_themeSkin a.mceButtonEnabled:active,
+.wp_themeSkin a.mceButtonSelected:active,
+.wp_themeSkin a.mceButtonActive,
+.wp_themeSkin a.mceButtonActive:active,
+.wp_themeSkin a.mceButtonActive:hover,
+.wp_themeSkin .mceSplitButtonSelected table,
+.wp_themeSkin .mceSplitButtonSelected table:hover {
+ outline: none;
+ border-color: #999 #ccc #ccc #999;
+ background: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#f6f6f6), to(#e3e3e3));
+ background-image: -webkit-linear-gradient(bottom, #f6f6f6, #e3e3e3);
+ background-image: -moz-linear-gradient(bottom, #f6f6f6, #e3e3e3);
+ background-image: -o-linear-gradient(bottom, #f6f6f6, #e3e3e3);
+ background-image: linear-gradient(to top, #f6f6f6, #e3e3e3);
+}
+
+.wp_themeSkin .mceSplitButtonSelected table a.mceOpen,
+.wp_themeSkin .mceSplitButtonSelected table a.mceAction {
+ border-color: #999 #ccc #ccc #999;
+}
+
+.wp_themeSkin .mceButtonDisabled {
+ border-color: transparent;
+}
+
+.wp_themeSkin .mceListBox .mceOpen {
+ border-left: 0;
+}
+
+.wp_themeSkin .mceListBoxEnabled:hover,
+.wp_themeSkin .mceListBoxEnabled:active,
+.wp_themeSkin .mceListBoxHover,
+.wp_themeSkin .mceListBoxHover:active,
+.wp_themeSkin .mceListBoxSelected {
+ -webkit-box-shadow: inset 0 1px 1px -1px rgba(0, 0, 0, .3);
+ box-shadow: inset 0 1px 1px -1px rgba(0, 0, 0, .3);
+ border-color: #bbb;
+}
+
+/* SplitButton */
+.wp_themeSkin .mceSplitButton .mceLast span.mceOpen .mceIconOnly {
+ display: block;
+}
+
+.wp_themeSkin .mceSplitButton a.mceAction,
+.wp_themeSkin .mceSplitButton a.mceOpen {
+ border-color: transparent;
+}
+
+.wp_themeSkin .mceSplitButton:hover a {
+ border-color: #bbb;
+}
+
+.wp_themeSkin .mceSplitButtonEnabled a.mceOpen,
+.wp_themeSkin .mceSplitButtonSelected a.mceOpen,
+.wp_themeSkin .mceSplitButtonActive a.mceOpen,
+.wp_themeSkin .mceSplitButtonEnabled:hover a.mceOpen {
+ background-image: url("../images/down_arrow.gif");
+ background-position: 1px 2px;
+ background-repeat: no-repeat;
+ border-left: 0;
+}
+
+.wp_themeSkin .mceSplitButtonActive td {
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.wp_themeSkin .mceColorSplitMenu a.mceMoreColors:hover {
+ border-color: #0A246A;
+ background-color: #B6BDD2;
+}
+
+.wp_themeSkin a.mceMoreColors:hover {
+ border-color: #0A246A;
+}
+
+.wp_themeSkin .mceMenuItemDisabled .mceText {
+ color: #888;
+}
+
+#mceModalBlocker {
+ background: #000;
+}
+
+/* WP specific */
+.wp-editor-wrap {
+ position: relative;
+}
+
+.wp-editor-area {
+ font-family: Consolas, Monaco, monospace;
+ padding: 10px;
+ margin: 1px 0 0;
+ line-height: 150%;
+ border: 0 none;
+ outline: none;
+ display: block;
+ resize: vertical;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.wp-editor-tools {
+ height: 30px;
+ padding: 0 10px 0 0;
+}
+
+.rtl .wp-editor-tools {
+ padding: 0 0 0 10px;
+}
+
+.wp-editor-container {
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ border-color: #ccc #ccc #dfdfdf;
+}
+
+.wp-editor-container textarea.wp-editor-area {
+ width: 100%;
+ margin: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.quicktags-toolbar,
+.wp_themeSkin tr.mceFirst td.mceToolbar {
+ border-bottom: 1px solid #d1d1d1;
+ background: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#e5e5e5), to(#f4f4f4));
+ background-image: -webkit-linear-gradient(bottom, #e5e5e5, #f4f4f4);
+ background-image: -moz-linear-gradient(bottom, #e5e5e5, #f4f4f4);
+ background-image: -o-linear-gradient(bottom, #e5e5e5, #f4f4f4);
+ background-image: linear-gradient(to top, #e5e5e5, #f4f4f4);
+}
+
+.wp-switch-editor {
+ height: 18px;
+ font: 13px/18px Arial,Helvetica,sans-serif normal;
+ margin: 5px 5px 0 0;
+ padding: 4px 5px 2px;
+ float: right;
+ cursor: pointer;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ background-color: #f1f1f1;
+ border-color: #dfdfdf #dfdfdf #ccc;
+ color: #999;
+}
+
+html[dir="rtl"] .wp-switch-editor {
+ float: left;
+}
+
+.wp-switch-editor:active {
+ background-color: #f1f1f1;
+}
+
+.wp-switch-editor:hover {
+ text-decoration: none !important;
+}
+
+.js .tmce-active .wp-editor-area {
+ color: white;
+}
+
+.tmce-active .quicktags-toolbar {
+ display: none;
+}
+
+.tmce-active .switch-tmce,
+.html-active .switch-html {
+ border-color: #ccc #ccc #f4f4f4;
+ background-color: #f4f4f4;
+ color: #555;
+}
+
+.wp-media-buttons .button {
+ margin-right: 5px;
+}
+
+.rtl .wp-media-buttons .button {
+ margin-right: 0;
+ margin-left: 5px;
+}
+
+.wp-media-buttons .insert-media {
+ padding-left: 0.4em;
+}
+
+.rtl .wp-media-buttons .insert-media {
+ padding-left: 10px;
+ padding-right: 0.4em;
+}
+
+.wp-media-buttons a {
+ text-decoration: none;
+ color: #464646;
+ font-size: 12px;
+}
+
+.wp-media-buttons img {
+ padding: 0 4px;
+ vertical-align: middle;
+}
+
+.wp-media-buttons span.wp-media-buttons-icon {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ vertical-align: text-top;
+ margin: 0 2px;
+}
+
+.wp-media-buttons .add_media span.wp-media-buttons-icon {
+ background: url('../../wp-admin/images/media-button.png') no-repeat top left;
+}
+
+.quicktags-toolbar {
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+ padding: 2px 8px 0;
+ min-height: 29px;
+}
+
+.quicktags-toolbar > div {
+ padding: 2px 4px 0;
+}
+
+.quicktags-toolbar input {
+ margin: 2px 1px 4px;
+ line-height: 18px;
+ display: inline-block;
+ min-width: 26px;
+ padding: 2px 4px;
+ font: 12px/18px Arial, Helvetica, sans-serif normal;
+ color: #464646;
+ border: 1px solid #c3c3c3;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#e3e3e3), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #e3e3e3, #fff);
+ background-image: -moz-linear-gradient(bottom, #e3e3e3, #fff);
+ background-image: -o-linear-gradient(bottom, #e3e3e3, #fff);
+ background-image: linear-gradient(to top, #e3e3e3, #fff);
+}
+
+.quicktags-toolbar input:hover {
+ border-color: #aaa;
+ background: #ddd;
+}
+
+.quicktags-toolbar input[value="link"] {
+ text-decoration: underline;
+}
+
+.quicktags-toolbar input[value="del"] {
+ text-decoration: line-through;
+}
+
+.quicktags-toolbar input[value="i"] {
+ font-style: italic;
+}
+
+.quicktags-toolbar input[value="b"] {
+ font-weight: bold;
+}
+
+#wp_editbtns,
+#wp_gallerybtns {
+ padding: 2px;
+ position: absolute;
+ display: none;
+ z-index: 155000;
+}
+
+#wp_editimgbtn,
+#wp_delimgbtn,
+#wp_editgallery,
+#wp_delgallery {
+ border-color: #999;
+ background-color: #eee;
+ margin: 2px;
+ padding: 2px;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+#wp_editimgbtn:hover,
+#wp_delimgbtn:hover,
+#wp_editgallery:hover,
+#wp_delgallery:hover {
+ border-color: #555;
+ background-color: #ccc;
+}
+
+/*------------------------------------------------------------------------------
+ wp-link
+------------------------------------------------------------------------------*/
+
+#wp-link {
+ background-color: #F5F5F5;
+ line-height: 1.4em;
+ font-size: 12px;
+}
+
+#wp-link ol,
+#wp-link ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+#wp-link input[type="text"] {
+ -webkit-box-sizing: border-box;
+}
+
+#wp-link input[type="text"],
+#wp-link textarea {
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ font-size: 12px;
+ margin: 1px;
+ padding: 3px;
+}
+
+#wp-link #link-options {
+ padding: 10px 0 14px;
+ border-bottom: 1px solid #dfdfdf;
+ margin: 0 6px 14px;
+}
+
+#wp-link p.howto {
+ margin: 3px;
+}
+
+#wp-link #internal-toggle {
+ display: inline-block;
+ cursor: pointer;
+ padding-left: 18px;
+}
+
+#wp-link .toggle-arrow {
+ background: transparent url( '../images/toggle-arrow.png' ) top left no-repeat;
+ height: 23px;
+ line-height: 23px;
+}
+
+#wp-link .toggle-arrow-active {
+ background-position: center left;
+}
+
+#wp-link label input[type="text"] {
+ width: 360px;
+ margin-top: 5px;
+}
+
+#wp-link #link-options label span,
+#wp-link #search-panel label span.search-label {
+ display: inline-block;
+ width: 80px;
+ text-align: right;
+ padding-right: 5px;
+}
+
+#wp-link .link-search-field {
+ float: left;
+ width: 220px;
+}
+
+#wp-link .link-search-wrapper {
+ margin: 5px 6px 9px;
+ display: block;
+ overflow: hidden;
+}
+
+#wp-link .link-search-wrapper span {
+ float: left;
+ margin-top: 4px;
+}
+
+#wp-link .link-search-wrapper .spinner {
+ display: none;
+ vertical-align: text-bottom;
+}
+
+#wp-link .link-target {
+ width: auto;
+ padding: 3px 0 0;
+ margin: 0 0 0 87px;
+ font-size: 11px;
+}
+
+#wp-link .query-results {
+ border: 1px #dfdfdf solid;
+ margin: 0 5px 5px;
+ background: #fff;
+ height: 185px;
+ overflow: auto;
+ position: relative;
+}
+
+#wp-link li,
+#wp-link .query-notice {
+ clear: both;
+ margin-bottom: 0;
+ border-bottom: 1px solid #f1f1f1;
+ color: #333;
+ padding: 4px 6px;
+ cursor: pointer;
+ position: relative;
+}
+
+#wp-link li:hover {
+ background: #eaf2fa;
+ color: #151515;
+}
+
+#wp-link li.unselectable {
+ border-bottom: 1px solid #dfdfdf;
+}
+
+#wp-link li.unselectable:hover {
+ background: #fff;
+ cursor: auto;
+ color: #333;
+}
+
+#wp-link li.selected {
+ background: #ddd;
+ color: #333;
+}
+
+#wp-link li.selected .item-title {
+ font-weight: bold;
+}
+
+#wp-link .item-title {
+ display: inline-block;
+ width: 80%;
+}
+
+#wp-link .item-info {
+ text-transform: uppercase;
+ color: #666;
+ font-size: 11px;
+ position: absolute;
+ right: 5px;
+ top: 4px;
+ bottom: 0;
+}
+
+#wp-link #search-results {
+ display: none;
+}
+
+#wp-link #search-panel {
+ float: left;
+ width: 100%;
+}
+
+#wp-link .river-waiting {
+ display: none;
+ padding: 10px 0;
+}
+
+#wp-link .river-waiting .spinner {
+ margin: 0 auto;
+ display: block;
+}
+
+#wp-link .submitbox {
+ padding: 5px 10px;
+ font-size: 11px;
+ overflow: auto;
+ height: 29px;
+}
+
+#wp-link-cancel {
+ line-height: 25px;
+ float: left;
+}
+
+#wp-link-update {
+ line-height: 23px;
+ float: right;
+}
+
+/*!
+ * jQuery UI CSS Framework 1.10.1
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+ display: none;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+ content: "";
+ display: table;
+ border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+ clear: both;
+}
+.ui-helper-clearfix {
+ min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter:Alpha(Opacity=0);
+}
+
+.ui-front {
+ z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+ cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+ display: block;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+
+/*!
+ * jQuery UI Resizable 1.10.1
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable {
+ position: relative;
+}
+.ui-resizable-handle {
+ position: absolute;
+ font-size: 0.1px;
+ display: block;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+ display: none;
+}
+.ui-resizable-n {
+ cursor: n-resize;
+ height: 7px;
+ width: 100%;
+ top: -5px;
+ left: 0;
+}
+.ui-resizable-s {
+ cursor: s-resize;
+ height: 7px;
+ width: 100%;
+ bottom: -5px;
+ left: 0;
+}
+.ui-resizable-e {
+ cursor: e-resize;
+ width: 7px;
+ right: -5px;
+ top: 0;
+ height: 100%;
+}
+.ui-resizable-w {
+ cursor: w-resize;
+ width: 7px;
+ left: -5px;
+ top: 0;
+ height: 100%;
+}
+.ui-resizable-se {
+ cursor: se-resize;
+ width: 12px;
+ height: 12px;
+ right: 1px;
+ bottom: 1px;
+}
+.ui-resizable-sw {
+ cursor: sw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ bottom: -5px;
+}
+.ui-resizable-nw {
+ cursor: nw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ top: -5px;
+}
+.ui-resizable-ne {
+ cursor: ne-resize;
+ width: 9px;
+ height: 9px;
+ right: -5px;
+ top: -5px;
+}
+
+/*!
+ * jQuery UI Dialog 1.10.1
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: .2em;
+ outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+ padding: .4em 1em;
+ position: relative;
+}
+.ui-dialog .ui-dialog-title {
+ float: left;
+ margin: .1em 0;
+ white-space: nowrap;
+ width: 90%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+ position: absolute;
+ right: .3em;
+ top: 50%;
+ width: 21px;
+ margin: -10px 0 0 0;
+ padding: 1px;
+ height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+ position: relative;
+ border: 0;
+ padding: .5em 1em;
+ background: none;
+ overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+ text-align: left;
+ border-width: 1px 0 0 0;
+ background-image: none;
+ margin-top: .5em;
+ padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+ float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+ margin: .5em .4em .5em 0;
+ cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+ width: 12px;
+ height: 12px;
+ right: -5px;
+ bottom: -5px;
+ background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+ cursor: move;
+}
+
+/* WP jQuery Dialog Theme */
+.wp-dialog {
+ padding: 0;
+ z-index: 300002;
+ border: 1px solid #999;
+ -webkit-box-shadow: 0px 0px 16px rgba( 0,0,0,0.3 );
+ box-shadow: 0px 0px 16px rgba( 0,0,0,0.3 );
+ background-color: #f5f5f5;
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+}
+
+.wp-dialog .ui-dialog-title {
+ display: block;
+ text-align: center;
+ padding: 1px 0 2px;
+}
+
+.wp-dialog .ui-dialog-titlebar {
+ padding: 0 1em;
+ background-color: #444;
+ font-weight: bold;
+ font-size: 11px;
+ line-height: 18px;
+ color: #e5e5e5;
+ -webkit-border-top-left-radius: 3px;
+ border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+.wp-dialog .ui-dialog-content {
+ padding: 0;
+}
+
+.wp-dialog .ui-dialog-titlebar-close {
+ cursor: pointer;
+ -webkit-appearance: none;
+ border: 0;
+ width: 29px;
+ height: 16px;
+ top: 13px;
+ right: 6px;
+ background: url('../js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif') no-repeat -87px -16px;
+}
+
+.wp-dialog .ui-dialog-titlebar-close .ui-button-text {
+ display: none;
+}
+
+.wp-dialog .ui-dialog-titlebar-close:hover,
+.wp-dialog .ui-dialog-titlebar-close:focus {
+ background-position: -87px -32px;
+}
+
+.ui-widget-overlay {
+ z-index: 300001;
+ background-color: #000;
+ opacity: 0.6;
+ filter: alpha(opacity=60);
+}
+
+.rtl .wp-dialog .ui-dialog-titlebar-close {
+ right: auto;
+ left: 6px;
+}
+
+/*
+RTL
+*/
+.rtl #wp-link #internal-toggle {
+ padding-right: 18px;
+ padding-left: 0;
+}
+
+.rtl #wp-link #link-options label span,
+.rtl #wp-link #search-panel label span.search-label {
+ text-align: left;
+ padding-right: 0;
+ padding-left: 5px;
+}
+
+.rtl #wp-link #link-options label #url-field {
+ direction: ltr;
+}
+
+.rtl #wp-link .link-search-field,
+.rtl #wp-link .link-search-wrapper span {
+ float: right;
+}
+
+.rtl #wp-link .link-target {
+ margin-right: 87px;
+ margin-left: 0;
+}
+
+.rtl #wp-link .item-info {
+ left: 5px;
+ right: auto;
+ top: 4px;
+ bottom: 0;
+}
+
+.rtl #wp-link #search-panel {
+ float: right;
+}
+
+.rtl #wp-link-cancel {
+ float: right;
+}
+
+.rtl #wp-link-update {
+ float: left;
+}
+
+.rtl #wp-link .toggle-arrow {
+ background-position: top right;
+}
+
+.rtl #wp-link .toggle-arrow-active {
+ background-position: center right;
+}
+
+.rtl .wp_themeSkin .mceListBox .mceText {
+ text-align: right;
+}
+
+.rtl .wp_themeSkin .mceNoIcons a .mceText {
+ padding-right: 10px;
+ padding-left: 25px;
+}
+
+.rtl .mceListBoxMenu.mceNoIcons {
+ direction: rtl;
+}
+
+.clearlooks2 .mceFocus .mceTop .mceLeft {
+ background: #444444;
+ border-left: 1px solid #999;
+ border-top: 1px solid #999;
+ -webkit-border-top-left-radius: 3px;
+ border-top-left-radius: 3px;
+}
+
+.clearlooks2 .mceFocus .mceTop .mceRight {
+ background: #444444;
+ border-right: 1px solid #999;
+ border-top: 1px solid #999;
+ -webkit-border-top-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+.clearlooks2 .mceMiddle .mceLeft {
+ background: #f1f1f1;
+ border-left: 1px solid #999;
+}
+
+.clearlooks2 .mceMiddle .mceRight {
+ background: #f1f1f1;
+ border-right: 1px solid #999;
+}
+
+.clearlooks2 .mceBottom {
+ background: #f1f1f1;
+ border-bottom: 1px solid #999;
+}
+
+.clearlooks2 .mceBottom .mceLeft {
+ background: #f1f1f1;
+ border-bottom: 1px solid #999;
+ border-left: 1px solid #999;
+}
+
+.clearlooks2 .mceBottom .mceCenter {
+ background: #f1f1f1;
+ border-bottom: 1px solid #999;
+}
+
+.clearlooks2 .mceBottom .mceRight {
+ background: #f1f1f1;
+ border-bottom: 1px solid #999;
+ border-right: 1px solid #999;
+}
+
+.clearlooks2 .mceFocus .mceTop span {
+ color: #e5e5e5;
+}
+
+
+/* Distraction Free Writing mode
+ * =Overlay Styles
+-------------------------------------------------------------- */
+.fullscreen-overlay {
+ z-index: 149999;
+ display: none;
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ filter: inherit;
+}
+
+.fullscreen-active .fullscreen-overlay,
+.fullscreen-active #wp-fullscreen-body {
+ display: block;
+}
+
+.fullscreen-fader {
+ z-index: 200000;
+}
+
+.fullscreen-active .fullscreen-fader {
+ display: none;
+}
+
+/* =Overlay Body
+-------------------------------------------------------------- */
+#wp-fullscreen-body {
+ width: 100%;
+ z-index: 150005;
+ display: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ font-size: 12px;
+}
+
+#wp-fullscreen-wrap {
+ margin: 0 auto 50px;
+ position: relative;
+ padding-top: 60px;
+}
+
+#wp-fullscreen-title {
+ font-size: 1.7em;
+ line-height: 100%;
+ outline: medium none;
+ padding: 6px 7px;
+ width: 100%;
+ margin-bottom: 30px;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+#wp-fullscreen-container {
+ padding: 4px 10px 50px;
+}
+
+#wp-fullscreen-title,
+#wp-fullscreen-container {
+ -webkit-border-radius: 0;
+ border-radius: 0;
+ border: 1px dashed transparent;
+ background: transparent;
+ -moz-transition-property: border-color;
+ -moz-transition-duration: 0.6s;
+ -webkit-transition-property: border-color;
+ -webkit-transition-duration: 0.6s;
+ -o-transition-property: border-color;
+ -o-transition-duration: 0.6s;
+ transition-property: border-color;
+ transition-duration: 0.6s;
+}
+
+#wp_mce_fullscreen {
+ width: 100%;
+ min-height: 300px;
+ border: 0;
+ background: transparent;
+ font-family: Consolas, Monaco, monospace;
+ line-height: 1.6em;
+ padding: 0;
+ overflow-y: hidden;
+ outline: none;
+ resize: none;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+#wp-fullscreen-tagline {
+ color: #BBBBBB;
+ font-size: 18px;
+ float: right;
+ padding-top: 5px;
+}
+
+/* =Top bar
+-------------------------------------------------------------- */
+#fullscreen-topbar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 150050;
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ min-width: 800px;
+ width: 100%;
+ height: 40px;
+}
+
+#wp-fullscreen-toolbar {
+ padding: 6px 10px 0;
+ clear: both;
+ max-width: 1100px;
+ min-width: 820px;
+ margin: 0 auto;
+}
+
+#wp-fullscreen-mode-bar,
+#wp-fullscreen-button-bar,
+#wp-fullscreen-close,
+#wp-fullscreen-count {
+ float: left;
+}
+
+#wp-fullscreen-save {
+ float: right;
+ padding: 2px 2px 0 5px;
+}
+
+#wp-fullscreen-count,
+#wp-fullscreen-close {
+ padding-top: 5px;
+}
+
+#wp-fullscreen-central-toolbar {
+ margin: auto;
+ padding: 0;
+}
+
+#wp-fullscreen-buttons > div {
+ float: left;
+}
+
+#wp-fullscreen-mode-bar {
+ padding: 1px 14px 0 0;
+}
+
+#wp-fullscreen-modes a {
+ display: block;
+ font-size: 11px;
+ text-decoration: none;
+ float: left;
+ margin: 1px 0 0 0;
+ padding: 2px 6px 2px;
+ border-width: 1px 1px 1px 0;
+ border-style: solid;
+ border-color: #bbb;
+ color: #777;
+ text-shadow: 0 1px 0 #fff;
+ background-color: #f4f4f4;
+ background: #f4f4f4;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#e4e4e4), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(bottom, #e4e4e4, #f9f9f9);
+ background-image: -moz-linear-gradient(bottom, #e4e4e4, #f9f9f9);
+ background-image: -o-linear-gradient(bottom, #e4e4e4, #f9f9f9);
+ background-image: linear-gradient(to top, #e4e4e4, #f9f9f9);
+}
+
+#wp-fullscreen-modes a:hover,
+.wp-html-mode #wp-fullscreen-modes a:last-child,
+.wp-tmce-mode #wp-fullscreen-modes a:first-child {
+ color: #333;
+ border-color: #999;
+ background: #eee;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e4e4e4), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(top, #e4e4e4, #f9f9f9);
+ background-image: -moz-linear-gradient(top, #e4e4e4, #f9f9f9);
+ background-image: -o-linear-gradient(top, #e4e4e4, #f9f9f9);
+ background-image: linear-gradient(to bottom, #e4e4e4, #f9f9f9);
+}
+
+#wp-fullscreen-modes a:first-child {
+ border-width: 1px;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-bottom-left-radius: 3px;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+#wp-fullscreen-modes a:last-child {
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-bottom-right-radius: 3px;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+#wp-fullscreen-buttons .active a {
+ background: inherit;
+}
+
+#wp-fullscreen-buttons .hidden {
+ display: none;
+}
+
+#wp-fullscreen-buttons .disabled {
+ opacity: 0.5;
+}
+
+.wp-html-mode #wp-fullscreen-buttons div {
+ display: none;
+}
+
+.wp-html-mode #wp-fullscreen-buttons div.wp-fullscreen-both {
+ display: block;
+}
+
+#fullscreen-topbar.fullscreen-make-sticky {
+ display: block !important;
+}
+
+#wp-fullscreen-save img {
+ vertical-align: middle;
+}
+
+#wp-fullscreen-save img,
+#wp-fullscreen-save span {
+ padding-right: 4px;
+ display: none;
+}
+
+#wp-fullscreen-buttons #wp_fs_image span.mce_image {
+ background-image: url('../../wp-admin/images/media-button.png');
+ background-position: 2px 2px;
+}
+
+/* =Thickbox Adjustments
+-------------------------------------------------------------- */
+.fullscreen-active #TB_overlay {
+ z-index: 150100;
+}
+
+.fullscreen-active #TB_window {
+ z-index: 150102;
+}
+
+/* =TinyMCE Adjustments
+-------------------------------------------------------------- */
+#wp_mce_fullscreen_ifr {
+ background: transparent;
+}
+
+#wp_mce_fullscreen_parent #wp_mce_fullscreen_tbl tr.mceFirst {
+ display : none;
+}
+
+#wp-fullscreen-container .wp_themeSkin table td {
+ vertical-align: top;
+}
+
+/* Colors */
+.fullscreen-overlay {
+ background: #fff;
+}
+
+.wp-fullscreen-focus #wp-fullscreen-title,
+.wp-fullscreen-focus #wp-fullscreen-container {
+ border-color: #ccc;
+}
+
+#fullscreen-topbar {
+ border-bottom-color: #DFDFDF;
+ background: #f1f1f1;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#ececec), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: -moz-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: -o-linear-gradient(bottom, #ececec, #f9f9f9);
+ background-image: linear-gradient(to top, #ececec, #f9f9f9);
+}
+
+/* =CSS 3 transitions
+-------------------------------------------------------------- */
+
+.fade-1000,
+.fade-600,
+.fade-400,
+.fade-300 {
+ opacity: 0;
+ -moz-transition-property: opacity;
+ -webkit-transition-property: opacity;
+ -o-transition-property: opacity;
+ transition-property: opacity;
+}
+
+.fade-1000 {
+ -moz-transition-duration: 1s;
+ -webkit-transition-duration: 1s;
+ -o-transition-duration: 1s;
+ transition-duration: 1s;
+}
+
+.fade-600 {
+ -moz-transition-duration: 0.6s;
+ -webkit-transition-duration: 0.6s;
+ -o-transition-duration: 0.6s;
+ transition-duration: 0.6s;
+}
+
+.fade-400 {
+ -moz-transition-duration: 0.4s;
+ -webkit-transition-duration: 0.4s;
+ -o-transition-duration: 0.4s;
+ transition-duration: 0.4s;
+}
+
+.fade-300 {
+ -moz-transition-duration: 0.3s;
+ -webkit-transition-duration: 0.3s;
+ -o-transition-duration: 0.3s;
+ transition-duration: 0.3s;
+}
+
+.fade-trigger {
+ opacity: 1;
+}
+
+/* Distraction Free Writing - RTL
+ * =Overlay Styles
+-------------------------------------------------------------- */
+
+/* No RTL for now, this space intentionally left blank */
+
+/* =Overlay Body
+-------------------------------------------------------------- */
+.rtl #wp-fullscreen-tagline {
+ float: left;
+}
+
+/* =Top bar
+-------------------------------------------------------------- */
+.rtl #fullscreen-topbar {
+ left:auto;
+ right: 0;
+}
+
+.rtl #wp-fullscreen-mode-bar,
+.rtl #wp-fullscreen-button-bar,
+.rtl #wp-fullscreen-close,
+.rtl #wp-fullscreen-count {
+ float: right;
+}
+
+.rtl #wp-fullscreen-save {
+ float: left;
+}
+
+.rtl #wp-fullscreen-save {
+ padding: 2px 5px 0 2px;
+}
+
+.rtl #wp-fullscreen-buttons > div {
+ float: right;
+}
+
+.rtl #wp-fullscreen-mode-bar {
+ padding: 1px 0 0 14px;
+}
+
+.rtl #wp-fullscreen-modes a {
+ float: right;
+ border-width: 1px 0 1px 1px;
+}
+
+.rtl #wp-fullscreen-modes a:first-child {
+ -webkit-border-top-left-radius: 0;
+ -webkit-border-top-right-radius: 3px;
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-bottom-right-radius: 3px;
+ border-width: 1px;
+ border-top-left-radius: 0;
+ border-top-right-radius: 3px;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 3px;
+}
+
+.rtl #wp-fullscreen-modes a:last-child {
+ -webkit-border-top-right-radius: 0;
+ -webkit-border-top-left-radius: 3px;
+ -webkit-border-bottom-right-radius: 0;
+ -webkit-border-bottom-left-radius: 3px;
+ border-top-right-radius: 0;
+ border-top-left-radius: 3px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 3px;
+}
+
+.rtl #wp-fullscreen-save img,
+.rtl #wp-fullscreen-save span {
+ padding-right: 0;
+ padding-left: 4px;
+}
+
+/* =Thickbox Adjustments
+-------------------------------------------------------------- */
+/* No RTL for now, this space intentionally left blank */
+
+
+/* =TinyMCE Adjustments
+-------------------------------------------------------------- */
+/* No RTL for now, this space intentionally left blank */
+
+
+/* HiDPI */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ .wp_themeSkin span.mce_undo,
+ .wp_themeSkin span.mce_redo,
+ .wp_themeSkin span.mce_bullist,
+ .wp_themeSkin span.mce_numlist,
+ .wp_themeSkin span.mce_blockquote,
+ .wp_themeSkin span.mce_charmap,
+ .wp_themeSkin span.mce_bold,
+ .wp_themeSkin span.mce_italic,
+ .wp_themeSkin span.mce_underline,
+ .wp_themeSkin span.mce_justifyleft,
+ .wp_themeSkin span.mce_justifyright,
+ .wp_themeSkin span.mce_justifycenter,
+ .wp_themeSkin span.mce_justifyfull,
+ .wp_themeSkin span.mce_indent,
+ .wp_themeSkin span.mce_outdent,
+ .wp_themeSkin span.mce_link,
+ .wp_themeSkin span.mce_unlink,
+ .wp_themeSkin span.mce_help,
+ .wp_themeSkin span.mce_removeformat,
+ .wp_themeSkin span.mce_fullscreen,
+ .wp_themeSkin span.mce_wp_fullscreen,
+ .wp_themeSkin span.mce_media,
+ .wp_themeSkin span.mce_pastetext,
+ .wp_themeSkin span.mce_pasteword,
+ .wp_themeSkin span.mce_wp_help,
+ .wp_themeSkin span.mce_wp_adv,
+ .wp_themeSkin span.mce_wp_more,
+ .wp_themeSkin span.mce_strikethrough,
+ .wp_themeSkin span.mce_spellchecker,
+ .wp_themeSkin span.mce_forecolor,
+ .wp_themeSkin .mce_forecolorpicker,
+ .wp_themeSkin .mceSplitButton .mce_spellchecker span.mce_spellchecker,
+ .wp_themeSkin .mceSplitButton .mce_forecolor span.mce_forecolor,
+ .wp_themeSkin .mceSplitButton span.mce_numlist,
+ .wp_themeSkin .mceSplitButton span.mce_bullist {
+ background-image: url('../images/wpicons-2x.png?ver=20120720');
+ background-size: 560px 40px;
+ }
+
+ .wp-media-buttons .add_media span.wp-media-buttons-icon,
+ #wp-fullscreen-buttons #wp_fs_image span.mce_image {
+ background-image: url('../../wp-admin/images/media-button-2x.png');
+ background-size: 16px 16px;
+ }
+
+ .wp_themeSkin .mceListBox .mceOpen,
+ .wp_themeSkin .mceListBoxHover .mceOpen,
+ .wp_themeSkin .mceListBoxSelected .mceOpen,
+ .wp_themeSkin table.mceListBoxEnabled .mceOpen {
+ background-image: url('../images/down_arrow-2x.gif');
+ background-size: 10px 20px;
+ }
+
+ .wp_themeSkin .mceSplitButtonEnabled a.mceOpen,
+ .wp_themeSkin .mceSplitButtonSelected a.mceOpen,
+ .wp_themeSkin .mceSplitButtonActive a.mceOpen,
+ .wp_themeSkin .mceSplitButtonEnabled:hover a.mceOpen {
+ background-image: url('../images/down_arrow-2x.gif');
+ background-size: 10px 20px;
+ }
+
+ #wp-link .toggle-arrow {
+ background: transparent url('../images/toggle-arrow-2x.png') top left no-repeat;
+ background-size: 19px 69px;
+ }
+}
diff --git a/src/wp-includes/css/jquery-ui-dialog.css b/src/wp-includes/css/jquery-ui-dialog.css
new file mode 100644
index 0000000000..9c75fbdfc8
--- /dev/null
+++ b/src/wp-includes/css/jquery-ui-dialog.css
@@ -0,0 +1,307 @@
+/*!
+ * jQuery UI CSS Framework 1.10.1
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+ display: none;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+ content: "";
+ display: table;
+ border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+ clear: both;
+}
+.ui-helper-clearfix {
+ min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter:Alpha(Opacity=0);
+}
+
+.ui-front {
+ z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+ cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+ display: block;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+
+/*!
+ * jQuery UI Resizable 1.10.1
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable {
+ position: relative;
+}
+.ui-resizable-handle {
+ position: absolute;
+ font-size: 0.1px;
+ display: block;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+ display: none;
+}
+.ui-resizable-n {
+ cursor: n-resize;
+ height: 7px;
+ width: 100%;
+ top: -5px;
+ left: 0;
+}
+.ui-resizable-s {
+ cursor: s-resize;
+ height: 7px;
+ width: 100%;
+ bottom: -5px;
+ left: 0;
+}
+.ui-resizable-e {
+ cursor: e-resize;
+ width: 7px;
+ right: -5px;
+ top: 0;
+ height: 100%;
+}
+.ui-resizable-w {
+ cursor: w-resize;
+ width: 7px;
+ left: -5px;
+ top: 0;
+ height: 100%;
+}
+.ui-resizable-se {
+ cursor: se-resize;
+ width: 12px;
+ height: 12px;
+ right: 1px;
+ bottom: 1px;
+}
+.ui-resizable-sw {
+ cursor: sw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ bottom: -5px;
+}
+.ui-resizable-nw {
+ cursor: nw-resize;
+ width: 9px;
+ height: 9px;
+ left: -5px;
+ top: -5px;
+}
+.ui-resizable-ne {
+ cursor: ne-resize;
+ width: 9px;
+ height: 9px;
+ right: -5px;
+ top: -5px;
+}
+
+/*!
+ * jQuery UI Dialog 1.10.1
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: .2em;
+ outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+ padding: .4em 1em;
+ position: relative;
+}
+.ui-dialog .ui-dialog-title {
+ float: left;
+ margin: .1em 0;
+ white-space: nowrap;
+ width: 90%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+ position: absolute;
+ right: .3em;
+ top: 50%;
+ width: 21px;
+ margin: -10px 0 0 0;
+ padding: 1px;
+ height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+ position: relative;
+ border: 0;
+ padding: .5em 1em;
+ background: none;
+ overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+ text-align: left;
+ border-width: 1px 0 0 0;
+ background-image: none;
+ margin-top: .5em;
+ padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+ float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+ margin: .5em .4em .5em 0;
+ cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+ width: 12px;
+ height: 12px;
+ right: -5px;
+ bottom: -5px;
+ background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+ cursor: move;
+}
+
+/* WP jQuery Dialog Theme */
+.wp-dialog {
+ padding: 0;
+ z-index: 300002;
+ border: 1px solid #999;
+ -webkit-box-shadow: 0px 0px 16px rgba( 0,0,0,0.3 );
+ box-shadow: 0px 0px 16px rgba( 0,0,0,0.3 );
+ background-color: #f5f5f5;
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+}
+
+.wp-dialog .ui-dialog-title {
+ display: block;
+ text-align: center;
+ padding: 1px 0 2px;
+}
+
+.wp-dialog .ui-dialog-titlebar {
+ padding: 0 1em;
+ background-color: #444;
+ font-weight: bold;
+ font-size: 11px;
+ line-height: 18px;
+ color: #e5e5e5;
+ -webkit-border-top-left-radius: 3px;
+ border-top-left-radius: 3px;
+ -webkit-border-top-right-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+.wp-dialog .ui-dialog-content {
+ padding: 0;
+}
+
+.wp-dialog .ui-dialog-titlebar-close {
+ cursor: pointer;
+ -webkit-appearance: none;
+ border: 0;
+ width: 29px;
+ height: 16px;
+ top: 13px;
+ right: 6px;
+ background: url('../js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif') no-repeat -87px -16px;
+}
+
+.wp-dialog .ui-dialog-titlebar-close .ui-button-text {
+ display: none;
+}
+
+.wp-dialog .ui-dialog-titlebar-close:hover,
+.wp-dialog .ui-dialog-titlebar-close:focus {
+ background-position: -87px -32px;
+}
+
+.ui-widget-overlay {
+ z-index: 300001;
+ background-color: #000;
+ opacity: 0.6;
+ filter: alpha(opacity=60);
+}
diff --git a/src/wp-includes/css/media-views-rtl.css b/src/wp-includes/css/media-views-rtl.css
new file mode 100644
index 0000000000..f260bb2313
--- /dev/null
+++ b/src/wp-includes/css/media-views-rtl.css
@@ -0,0 +1,312 @@
+/**
+ * Modal
+ */
+.media-modal-close {
+ right: auto;
+ left: 7px;
+}
+
+/**
+ * Toolbar
+ */
+.media-toolbar-primary {
+ float: left;
+}
+
+.media-toolbar-secondary {
+ float: right;
+}
+
+.media-toolbar-primary > .media-button,
+.media-toolbar-primary > .media-button-group {
+ margin-left: 0;
+ margin-right: 10px;
+ float: right;
+}
+
+.media-toolbar-secondary > .media-button,
+.media-toolbar-secondary > .media-button-group {
+ margin-right: 0;
+ margin-left: 10px;
+ float: right;
+}
+
+/**
+ * Sidebar
+ */
+.media-sidebar {
+ right: auto;
+ left: 0;
+ border-left: 0;
+ border-right: 1px solid #dfdfdf;
+}
+
+.media-sidebar .setting {
+ float: right;
+}
+
+.media-sidebar .setting .link-to-custom {
+ direction: ltr;
+}
+
+.media-sidebar .setting span {
+ margin-right: 0;
+ margin-left: 4%;
+}
+
+.media-sidebar .setting span,
+.compat-item label span {
+ float: right;
+ text-align: left;
+}
+
+.media-sidebar .setting input,
+.media-sidebar .setting textarea {
+ float: left;
+}
+
+.compat-item {
+ float: right;
+}
+
+.compat-item .label {
+ margin-right: 0;
+ margin-left: 4%;
+ float: right;
+ text-align: left;
+}
+
+.compat-item .field {
+ float: left;
+ padding-right: 0;
+ padding-left: 1px;
+}
+
+/**
+ * Menu
+ */
+.media-menu {
+ border-right: 0;
+ border-left: 1px solid #d9d9d9;
+ box-shadow: inset 6px 0 6px -6px rgba( 0, 0, 0, 0.2 )
+}
+
+/**
+ * Router
+ */
+.media-router > a {
+ float: right;
+ border-right: 0;
+ border-left: 1px solid #dfdfdf;
+}
+.media-router > a:last-child {
+ border-left: 0;
+}
+
+/**
+ * Frame
+ */
+.media-frame-menu {
+ left: auto;
+ right: 0;
+}
+
+.media-frame-title,
+.media-frame-router,
+.media-frame-content,
+.media-frame-toolbar {
+ left: 0;
+ right: 200px;
+}
+
+.media-frame.hide-menu .media-frame-title,
+.media-frame.hide-menu .media-frame-router,
+.media-frame.hide-menu .media-frame-toolbar,
+.media-frame.hide-menu .media-frame-content {
+ right: 0;
+}
+
+.media-frame.hide-menu .media-frame-menu {
+ left: auto;
+ right: -200px;
+}
+
+/**
+ * Attachment Browser Filters
+ */
+.media-frame select.attachment-filters {
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+/**
+ * Search
+ */
+.media-toolbar-secondary .search {
+ margin-right: 0;
+ margin-left: 16px;
+}
+
+/**
+ * Attachments
+ */
+.attachments {
+ padding-right: 0;
+ padding-left: 16px;
+}
+
+/**
+ * Attachment
+ */
+.attachment {
+ float: right;
+}
+
+.attachment .thumbnail {
+ left: auto;
+ right: 0;
+}
+
+.attachment .close {
+ right: auto;
+ left: 5px;
+}
+
+.attachment .check {
+ right: auto;
+ left: -7px;
+}
+
+/**
+ * Attachments Browser
+ */
+.attachments-browser .media-toolbar {
+ right: 0;
+ left: 300px;
+}
+
+.attachments-browser .attachments,
+.attachments-browser .uploader-inline {
+ right: 0;
+ left: 300px;
+}
+
+
+/**
+ * Progress Bar
+ */
+.attachment-preview .media-progress-bar {
+ left: auto;
+ right: 15%;
+}
+
+.media-sidebar .media-uploader-status .upload-dismiss-errors {
+ right: auto;
+ left: 0;
+}
+
+.upload-errors .upload-error-label {
+ margin-right: 0;
+ margin-left: 8px;
+ float: right;
+ margin-top: -3px;
+}
+
+/**
+ * Selection
+ */
+.media-selection {
+ right: 0;
+ left: 350px;
+ padding: 0 16px 0 0;
+}
+
+.media-selection .selection-info {
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+.media-selection .selection-info a {
+ float: right;
+ border-right: 0;
+ border-left: 1px solid #dfdfdf;
+ margin: 1px -8px 1px 8px;
+}
+
+.media-selection .selection-info a:last-child {
+ border-right: 1px;
+ border-left: 0;
+ margin-left: 0;
+ margin-right: -8px;
+}
+
+.media-selection:after {
+ right: auto;
+ left: 0;
+ background-image: -webkit-gradient(linear, left top, right top, from( rgba( 255, 255, 255, 1 ) ), to( rgba( 255, 255, 255, 0 ) ));
+ background-image: -webkit-linear-gradient(left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+ background-image: -moz-linear-gradient(left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+ background-image: -o-linear-gradient(left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+ background-image: linear-gradient(to right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+}
+
+/**
+ * Attachment Details
+ */
+.attachment-info .thumbnail {
+ float: right;
+ margin-right: 0;
+ margin-left: 10px;
+}
+
+.attachment-info .details {
+ float: right;
+}
+
+/**
+ * Attachment Display Settings
+ */
+.attachment-display-settings {
+ float: right;
+}
+
+/**
+ * Embed from URL
+ */
+.embed-url span {
+ display: block;
+ padding: 4px 2px 6px 0;
+}
+
+.media-embed .thumbnail {
+ float: right;
+}
+
+.media-embed .setting {
+ float: right;
+}
+
+.media-frame .embed-url input,
+.media-frame .link-to-custom {
+ direction: ltr;
+}
+
+/**
+ * Responsive layout
+ */
+@media only screen and (max-width: 900px) {
+ .media-frame-title,
+ .media-frame-router,
+ .media-frame-content,
+ .media-frame-toolbar {
+ left: 0;
+ right: 140px;
+ }
+
+ .attachments-browser .attachments,
+ .attachments-browser .uploader-inline,
+ .attachments-browser .media-toolbar {
+ right: 0;
+ left: 180px;
+ }
+}
diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css
new file mode 100644
index 0000000000..43061561a8
--- /dev/null
+++ b/src/wp-includes/css/media-views.css
@@ -0,0 +1,1673 @@
+/**
+ * Base Styles
+ */
+.media-modal,
+.media-frame {
+ font-family: sans-serif;
+ font-size: 12px;
+}
+
+.media-frame input,
+.media-frame textarea {
+ padding: 6px 8px;
+ line-height: 16px;
+}
+
+.media-frame select,
+.wp-admin .media-frame select {
+ line-height: 28px;
+ margin-top: 3px;
+}
+
+.media-frame a {
+ border-bottom: none;
+ color: #21759b;
+}
+
+.media-frame a:hover {
+ color: #d54e21;
+}
+
+.media-frame a.button {
+ color: #333;
+}
+
+.media-frame a.button:hover {
+ color: #222;
+}
+
+.media-frame a.button-primary,
+.media-frame a.button-primary:hover {
+ color: #fff;
+}
+
+.media-frame input[type="text"],
+.media-frame input[type="password"],
+.media-frame input[type="number"],
+.media-frame input[type="search"],
+.media-frame input[type="email"],
+.media-frame input[type="url"],
+.media-frame textarea,
+.media-frame select {
+ font-family: sans-serif;
+ font-size: 12px;
+ -moz-box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -ms-box-sizing: border-box; /* ie8 only */
+ box-sizing: border-box;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #dfdfdf;
+}
+
+.media-frame select {
+ height: 24px;
+ padding: 2px;
+}
+
+.media-frame input:disabled,
+.media-frame textarea:disabled,
+.media-frame input[readonly],
+.media-frame textarea[readonly] {
+ background-color: #eee;
+}
+
+.media-frame input[type="search"] {
+ -webkit-appearance: textfield;
+}
+
+.media-frame :-moz-placeholder {
+ color: #a9a9a9;
+}
+
+/* Enable draggable on IE10 touch events until it's rolled into jQuery UI core */
+.ui-sortable,
+.ui-draggable {
+ -ms-touch-action: none;
+}
+
+/**
+ * Modal
+ */
+.media-modal {
+ position: fixed;
+ top: 30px;
+ left: 30px;
+ right: 30px;
+ bottom: 30px;
+ z-index: 160000;
+}
+
+.media-modal-backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ min-height: 360px;
+ background: #000;
+ opacity: 0.7;
+ z-index: 159900;
+}
+
+.media-modal-close {
+ position: absolute;
+ top: 7px;
+ right: 7px;
+ width: 30px;
+ height: 30px;
+ z-index: 1000;
+}
+.media-modal-close span {
+ display: block;
+ margin: 8px auto 0;
+ width: 15px;
+ height: 15px;
+ background-position: -100px 0;
+}
+
+.media-modal-close:active {
+ outline: 0;
+}
+
+.media-modal-content {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: auto;
+ min-height: 300px;
+ background: #fff;
+}
+
+.media-modal-icon {
+ background-image: url(../images/uploader-icons.png);
+ background-repeat: no-repeat;
+}
+
+/**
+ * Toolbar
+ */
+.media-toolbar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 100;
+ height: 60px;
+ padding: 0 16px;
+ border: 0 solid #dfdfdf;
+ overflow: hidden;
+}
+
+.media-toolbar-primary {
+ float: right;
+ height: 100%;
+}
+
+.media-toolbar-secondary {
+ float: left;
+ height: 100%;
+}
+
+.media-toolbar-primary > .media-button,
+.media-toolbar-primary > .media-button-group {
+ margin-left: 10px;
+ float: left;
+ margin-top: 15px;
+}
+
+.media-toolbar-secondary > .media-button,
+.media-toolbar-secondary > .media-button-group {
+ margin-right: 10px;
+ float: left;
+ margin-top: 15px;
+}
+
+/**
+ * Sidebar
+ */
+.media-sidebar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 267px;
+ padding: 0 16px 24px;
+ z-index: 75;
+ background: #f5f5f5;
+ border-left: 1px solid #dfdfdf;
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+}
+
+.hide-toolbar .media-sidebar {
+ bottom: 0;
+}
+
+.media-sidebar .sidebar-title {
+ font-weight: 200;
+ font-size: 20px;
+ margin: 0;
+ padding: 12px 10px 10px;
+ line-height: 28px;
+}
+
+.media-sidebar .sidebar-content {
+ padding: 0 10px;
+ margin-bottom: 130px;
+}
+
+.media-sidebar .search {
+ display: block;
+ width: 100%;
+}
+
+.media-sidebar h3 {
+ position: relative;
+ font-weight: bold;
+ text-transform: uppercase;
+ font-size: 12px;
+ color: #777;
+ text-shadow: 0 1px 0 #fff;
+ margin: 24px 0 8px;
+}
+
+.media-sidebar .setting {
+ display: block;
+ float: left;
+ width: 100%;
+ margin: 1px 0;
+}
+
+.media-sidebar .setting label {
+ display: block;
+}
+
+.media-sidebar .setting .link-to-custom {
+ margin: 3px 0;
+}
+
+.media-sidebar .setting span {
+ min-width: 30%;
+ margin-right: 4%;
+ font-size: 12px;
+}
+
+.media-sidebar .setting select {
+ max-width: 65%;
+}
+
+.media-sidebar .setting input[type="checkbox"] {
+ width: auto;
+ float: none;
+ margin-top: 8px;
+ padding: 0;
+}
+
+.media-sidebar .setting span,
+.compat-item label span {
+ float: left;
+ min-height: 22px;
+ padding-top: 8px;
+ line-height: 16px;
+ text-align: right;
+ font-weight: normal;
+ color: #999;
+ text-shadow: 0 1px 0 #fff;
+}
+
+.media-sidebar .setting input,
+.media-sidebar .setting textarea {
+ width: 65%;
+ float: right;
+}
+
+.media-sidebar .setting textarea,
+.compat-item .field textarea {
+ height: 62px;
+ resize: vertical;
+}
+
+.media-sidebar select {
+ margin-top: 3px;
+}
+
+.compat-item {
+ float: left;
+ width: 100%;
+ overflow: hidden;
+}
+
+.compat-item table {
+ width: 100%;
+ table-layout: fixed;
+ border-spacing: 0;
+ border: 0;
+}
+
+.compat-item tr {
+ padding: 2px 0;
+ display: block;
+ overflow: hidden;
+}
+
+.compat-item .label,
+.compat-item .field {
+ display: block;
+ margin: 0;
+ padding: 0;
+}
+
+.compat-item .label {
+ min-width: 30%;
+ margin-right: 4%;
+ float: left;
+ text-align: right;
+}
+
+.compat-item .label span {
+ display: block;
+ width: 100%;
+}
+
+.compat-item .field {
+ float: right;
+ width: 65%;
+ padding-right: 1px;
+}
+
+.compat-item .field input {
+ width: 100%;
+ margin: 0;
+}
+
+
+/**
+ * Menu
+ */
+.media-menu {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: 0;
+ padding: 16px 0;
+ border-right: 1px solid #d9d9d9;
+ box-shadow: inset -6px 0 6px -6px rgba( 0, 0, 0, 0.2 );
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.media-menu > a {
+ display: block;
+ position: relative;
+ padding: 4px 20px;
+ margin: 0;
+ line-height: 18px;
+ font-size: 14px;
+ color: #21759B;
+ text-shadow: 0 1px 0 #fff;
+ text-decoration: none;
+}
+
+.media-menu > a:hover {
+ color: #21759B;
+ background: rgba( 0, 0, 0, 0.04 );
+}
+
+.media-menu > a:active {
+ outline: none;
+}
+
+.media-menu .active,
+.media-menu .active:hover {
+ color: #333;
+ font-weight: bold;
+}
+
+.media-menu .separator {
+ height: 0;
+ margin: 12px 20px;
+ padding: 0;
+ border-top: 1px solid #dfdfdf;
+ border-bottom: 1px solid #fff;
+}
+
+/**
+ * Menu
+ */
+.media-router {
+ position: relative;
+ padding: 0 6px;
+ margin: 0;
+ clear: both;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.media-router > a {
+ position: relative;
+ float: left;
+ padding: 2px 10px;
+ margin: 0;
+ height: 18px;
+ line-height: 18px;
+ font-size: 14px;
+ border-right: 1px solid #dfdfdf;
+ text-shadow: 0 1px 0 #fff;
+ text-decoration: none;
+}
+
+.media-router > a:last-child {
+ border-right: 0;
+}
+
+.media-router > a:active,
+.media-router > a:focus {
+ outline: none;
+}
+
+.media-router .active,
+.media-router .active:hover {
+ color: #333;
+}
+
+.media-router .active:after {
+ content: '';
+ display: block;
+ margin: -100px auto 0;
+ width: 7px;
+ height: 7px;
+ background: #fff;
+ box-shadow: 1px 1px 1px rgba( 0, 0, 0, 0.2 );
+ z-index: 300;
+
+ -webkit-transform: rotate( 45deg ) translate( 75px, 75px );
+ -moz-transform: rotate( 45deg ) translate( 75px, 75px );
+ -ms-transform: rotate( 45deg ) translate( 75px, 75px );
+ -o-transform: rotate( 45deg ) translate( 75px, 75px );
+ transform: rotate( 45deg ) translate( 75px, 75px );
+}
+
+/**
+ * Frame
+ */
+.media-frame {
+ overflow: hidden;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.media-frame-menu {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 199px;
+ z-index: 150;
+}
+
+.media-frame-title {
+ position: absolute;
+ top: 0;
+ left: 200px;
+ right: 0;
+ height: 45px;
+ z-index: 200;
+}
+
+.media-frame-router {
+ position: absolute;
+ top: 45px;
+ left: 200px;
+ right: 0;
+ height: 30px;
+ z-index: 200;
+ border-bottom: 1px solid #dfdfdf;
+ box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
+}
+
+.media-frame-content {
+ position: absolute;
+ top: 75px;
+ left: 200px;
+ right: 0;
+ bottom: 61px;
+ height: auto;
+ width: auto;
+ margin: 0;
+ overflow: auto;
+}
+
+.media-frame-toolbar {
+ position: absolute;
+ left: 200px;
+ right: 0;
+ bottom: 0;
+ height: 60px;
+ z-index: 100;
+ border: 0 solid #dfdfdf;
+ border-width: 1px 0 0 0;
+ box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.1 );
+}
+
+.media-frame.hide-menu .media-frame-title,
+.media-frame.hide-menu .media-frame-router,
+.media-frame.hide-menu .media-frame-toolbar,
+.media-frame.hide-menu .media-frame-content {
+ left: 0;
+}
+
+.media-frame.hide-menu .media-frame-menu {
+ left: -200px;
+}
+
+.media-frame.hide-toolbar .media-frame-content {
+ bottom: 0;
+}
+
+.media-frame.hide-toolbar .media-frame-toolbar {
+ bottom: -61px;
+}
+
+.media-frame.hide-router .media-frame-content {
+ top: 45px;
+}
+
+.media-frame.hide-router .media-frame-router {
+ display: none;
+}
+
+.media-frame.hide-router .media-frame-title {
+ border-bottom: 1px solid #dfdfdf;
+ box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
+}
+
+.media-frame .media-toolbar .add-to-gallery {
+ display: none;
+}
+
+.media-frame-title h1 {
+ padding: 0 16px;
+ font-size: 22px;
+ font-weight: 200;
+ line-height: 45px;
+ margin: 0;
+}
+
+/**
+ * Iframes
+ */
+.media-frame .media-iframe {
+ overflow: hidden;
+}
+
+.media-frame .media-iframe,
+.media-frame .media-iframe iframe {
+ height: 100%;
+ width: 100%;
+ border: 0;
+}
+
+/**
+ * Attachment Browser Filters
+ */
+.media-frame select.attachment-filters {
+ margin-top: 11px;
+ margin-right: 10px;
+}
+
+/**
+ * Search
+ */
+.media-frame .search {
+ margin-top: 11px;
+ padding: 4px;
+ line-height: 18px;
+ font-size: 13px;
+ color: #464646;
+ font-family: sans-serif;
+ -webkit-appearance: none;
+}
+
+.media-toolbar-secondary .search {
+ margin-right: 16px;
+}
+
+/**
+ * Attachments
+ */
+.attachments {
+ margin: 0;
+ padding-right: 16px;
+ -webkit-overflow-scrolling: touch;
+}
+
+/**
+ * Attachment
+ */
+.attachment {
+ position: relative;
+ float: left;
+
+ padding: 0;
+ margin: 0 10px 20px;
+ color: #464646;
+ list-style: none;
+ text-align: center;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+
+.selected.attachment {
+ box-shadow:
+ 0 0 0 1px #fff,
+ 0 0 0 3px #ccc;
+}
+
+.details.attachment {
+ box-shadow:
+ 0 0 0 1px #fff,
+ 0 0 0 5px #1e8cbe;
+}
+
+.attachment-preview {
+ position: relative;
+ width: 199px;
+ height: 199px;
+ box-shadow:
+ inset 0 0 15px rgba( 0, 0, 0, 0.1 ),
+ inset 0 0 0 1px rgba( 0, 0, 0, 0.05 );
+ background: #eee;
+ cursor: pointer;
+}
+
+.attachment .icon {
+ margin: 0 auto;
+ overflow: hidden;
+ padding-top: 20%;
+}
+
+.attachment .thumbnail {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ margin: 0 auto;
+ overflow: hidden;
+ max-width: 100%;
+ max-height: 100%;
+}
+
+.attachment-preview .thumbnail:after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
+ overflow: hidden;
+}
+
+.attachment .thumbnail img {
+ top: 0;
+ left: 0;
+}
+
+.attachment .thumbnail .centered {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ -webkit-transform: translate( 50%, 50% );
+ -moz-transform: translate( 50%, 50% );
+ -ms-transform: translate( 50%, 50% );
+ -o-transform: translate( 50%, 50% );
+ transform: translate( 50%, 50% );
+}
+
+.attachment .thumbnail .centered img {
+ -webkit-transform: translate( -50%, -50% );
+ -moz-transform: translate( -50%, -50% );
+ -ms-transform: translate( -50%, -50% );
+ -o-transform: translate( -50%, -50% );
+ transform: translate( -50%, -50% );
+}
+
+.attachment .filename {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+ max-height: 100%;
+
+ word-wrap: break-word;
+ text-align: center;
+ font-weight: bold;
+ background: rgba( 255, 255, 255, 0.8 );
+ box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.15 );
+}
+
+.attachment .filename div {
+ padding: 5px 10px;
+}
+
+.attachment-preview .thumbnail {
+ width: 199px;
+ height: 199px;
+}
+
+.attachment .thumbnail img {
+ position: absolute;
+}
+
+.attachment .close {
+ display: none;
+ position: absolute;
+ top: 5px;
+ right: 5px;
+ height: 22px;
+ width: 22px;
+ padding: 0;
+ font-size: 20px;
+ line-height: 20px;
+ text-align: center;
+ text-decoration: none;
+ color: #464646;
+ background-color: #fff;
+ background-position: -96px 4px;
+ border-width: 0;
+ border-radius: 3px;
+ box-shadow: 0 0 0 1px rgba( 0, 0, 0, 0.3 );
+}
+
+.attachment .close:hover {
+ box-shadow: 0 0 0 1px rgba( 0, 0, 0, 0.6 );
+}
+
+.attachment:hover .close {
+ display: block;
+}
+
+.attachment .check {
+ display: none;
+ height: 24px;
+ width: 24px;
+ position: absolute;
+ top: -7px;
+ right: -7px;
+ outline: none;
+
+ border: 1px solid #fff;
+ border-radius: 3px;
+ box-shadow: 0 0 0 1px rgba( 0, 0, 0, 0.4 );
+
+ background: #f1f1f1;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f1f1f1), to(#e1e1e1));
+ background-image: -webkit-linear-gradient(top, #f1f1f1, #e1e1e1);
+ background-image: -moz-linear-gradient(top, #f1f1f1, #e1e1e1);
+ background-image: -o-linear-gradient(top, #f1f1f1, #e1e1e1);
+ background-image: linear-gradient(to bottom, #f1f1f1, #e1e1e1);
+}
+
+.attachment .check div {
+ background-position: -1px 0;
+ height: 15px;
+ width: 15px;
+ margin: 5px;
+}
+
+.attachment .check:hover div {
+ background-position: -40px 0;
+}
+
+.attachment.selected .check {
+ display: block;
+}
+
+.attachment.details .check {
+ box-shadow: 0 0 0 1px #1e8cbe;
+
+ background: #1e8cbe;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#1e8cbe), to(#0074a2));
+ background-image: -webkit-linear-gradient(top, #1e8cbe, #0074a2);
+ background-image: -moz-linear-gradient(top, #1e8cbe, #0074a2);
+ background-image: -o-linear-gradient(top, #1e8cbe, #0074a2);
+ background-image: linear-gradient(to bottom, #1e8cbe, #0074a2);
+}
+
+.attachment.details .check div {
+ background-position: -21px 0;
+}
+
+.attachment.details .check:hover div {
+ background-position: -60px 0;
+}
+
+.media-frame .attachment .describe {
+ position: relative;
+ display: block;
+ width: 100%;
+ margin: -1px 0 0;
+ padding: 8px;
+ font-size: 12px;
+ border-radius: 0;
+}
+
+/**
+ * Attachments Browser
+ */
+.media-frame .attachments-browser {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+.attachments-browser .media-toolbar {
+ right: 300px;
+ height: 50px;
+}
+
+.attachments-browser .media-toolbar-primary > .media-button,
+.attachments-browser .media-toolbar-primary > .media-button-group,
+.attachments-browser .media-toolbar-secondary > .media-button,
+.attachments-browser .media-toolbar-secondary > .media-button-group {
+ margin-top: 10px;
+}
+
+.attachments-browser .attachments,
+.attachments-browser .uploader-inline {
+ position: absolute;
+ top: 50px;
+ left: 0;
+ right: 300px;
+ bottom: 0;
+ overflow: auto;
+}
+
+.attachments-browser .instructions {
+ display: inline-block;
+ margin-top: 16px;
+ line-height: 18px;
+ font-size: 13px;
+ color: #999;
+}
+
+/**
+ * Progress Bar
+ */
+.media-progress-bar {
+ position: relative;
+ height: 10px;
+ width: 70%;
+ margin: 10px auto;
+ border-radius: 10px;
+ background: #dfdfdf;
+ background: rgba( 0, 0, 0, 0.1 );
+}
+
+.media-progress-bar div {
+ height: 10px;
+ min-width: 20px;
+ width: 0;
+ background: #aaa;
+ background: rgba( 0, 0, 0, 0.2 );
+ border-radius: 10px;
+ -webkit-transition: width 300ms;
+ -moz-transition: width 300ms;
+ -ms-transition: width 300ms;
+ -o-transition: width 300ms;
+ transition: width 300ms;
+}
+
+.media-uploader-status .media-progress-bar {
+ display: none;
+ width: 100%;
+}
+
+.uploading.media-uploader-status .media-progress-bar {
+ display: block;
+}
+
+.attachment-preview .media-progress-bar {
+ position: absolute;
+ top: 50%;
+ left: 15%;
+ width: 70%;
+ margin: -5px 0 0 0;
+}
+
+.media-uploader-status {
+ position: relative;
+ margin: 0 auto;
+ padding-bottom: 10px;
+ max-width: 400px;
+}
+
+.media-sidebar .media-uploader-status {
+ border-bottom: 1px solid #dfdfdf;
+ box-shadow: 0 1px 0 #fff;
+}
+
+.uploader-inline .media-uploader-status h3 {
+ display: none;
+}
+
+.media-uploader-status .upload-details {
+ display: none;
+ font-size: 12px;
+ color: #666;
+ text-shadow: 0 1px 0 #fff;
+}
+
+.uploading.media-uploader-status .upload-details {
+ display: block;
+}
+
+.media-uploader-status .upload-detail-separator {
+ padding: 0 4px;
+}
+
+.media-uploader-status .upload-count {
+ color: #464646;
+}
+
+.media-uploader-status .upload-dismiss-errors,
+.media-uploader-status .upload-errors {
+ display: none;
+}
+
+.errors.media-uploader-status .upload-dismiss-errors,
+.errors.media-uploader-status .upload-errors {
+ display: block;
+}
+
+.media-uploader-status .upload-dismiss-errors {
+ text-decoration: none;
+}
+
+.media-sidebar .media-uploader-status .upload-dismiss-errors {
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+
+.upload-errors .upload-error {
+ margin: 8px auto 0 auto;
+ padding: 8px;
+ border: 1px #c00 solid;
+ background: #ffebe8;
+ border-radius: 3px;
+}
+
+.upload-errors .upload-error-label {
+ padding: 2px 4px;
+ margin-right: 8px;
+ font-weight: bold;
+ color: #fff;
+ background: #e00;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e00), to(#a00));
+ background-image: -webkit-linear-gradient(top, #e00, #a00);
+ background-image: -moz-linear-gradient(top, #e00, #a00);
+ background-image: -o-linear-gradient(top, #e00, #a00);
+ background-image: linear-gradient(to bottom, #e00, #a00);
+ border-radius: 3px;
+}
+
+.upload-errors .upload-error-message {
+ display: block;
+ padding-top: 8px;
+ color: #b44;
+ word-wrap: break-word;
+}
+
+.uploader-window {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba( 0, 86, 132, 0.9 );
+
+ z-index: 250000;
+ display: none;
+ text-align: center;
+ opacity: 0;
+
+ -webkit-transition: opacity 250ms;
+ -moz-transition: opacity 250ms;
+ -ms-transition: opacity 250ms;
+ -o-transition: opacity 250ms;
+ transition: opacity 250ms;
+}
+
+.uploader-window-content {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ right: 10px;
+ bottom: 10px;
+ border: 1px dashed #fff;
+}
+
+.uploader-window h3 {
+ position: absolute;
+ top: 50%;
+ left: 0;
+ right: 0;
+ -webkit-transform: translateY( -50% );
+ -moz-transform: translateY( -50% );
+ -ms-transform: translateY( -50% );
+ -o-transform: translateY( -50% );
+ transform: translateY( -50% );
+
+ font-size: 20px;
+ font-weight: 200;
+ color: #fff;
+ padding: 0;
+}
+
+.uploader-window .media-progress-bar {
+ margin-top: 20px;
+ max-width: 300px;
+ background: transparent;
+ border-color: #fff;
+ display: none;
+}
+
+.uploader-window .media-progress-bar div {
+ background: #fff;
+}
+
+.uploading .uploader-window .media-progress-bar {
+ display: block;
+}
+
+.media-frame .uploader-inline {
+ margin: 20px;
+ padding: 20px;
+ text-align: center;
+}
+
+.uploader-inline-content {
+ position: absolute;
+ top: 30%;
+ left: 0;
+ right: 0;
+}
+
+.uploader-inline-content .upload-ui {
+ margin: 4em 0;
+}
+
+.uploader-inline-content .post-upload-ui {
+ margin-bottom: 2em;
+}
+
+.uploader-inline .has-upload-message .upload-ui {
+ margin: 0 0 4em;
+}
+
+.uploader-inline h3 {
+ font-size: 20px;
+ line-height: 28px;
+ font-weight: 200;
+ margin-bottom: 1.6em;
+}
+
+.uploader-inline .has-upload-message .upload-instructions {
+ font-size: 14px;
+ color: #464646;
+ font-weight: normal;
+}
+
+.uploader-inline .drop-instructions {
+ display: none;
+}
+
+.supports-drag-drop .uploader-inline .drop-instructions {
+ display: block;
+}
+
+.uploader-inline p {
+ font-size: 12px;
+}
+
+.uploader-inline .media-progress-bar {
+ display: none;
+}
+
+.uploading.uploader-inline .media-progress-bar {
+ display: block;
+}
+
+.uploader-inline .browser {
+ display: inline-block !important;
+}
+
+/**
+ * Selection
+ */
+.media-selection {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 350px;
+ height: 60px;
+ padding: 0 0 0 16px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
+.media-selection .selection-info {
+ display: inline-block;
+ font-size: 12px;
+ height: 60px;
+ margin-right: 10px;
+ vertical-align: top;
+}
+
+.media-selection.empty,
+.media-selection.editing {
+ display: none;
+}
+
+.media-selection.one .edit-selection {
+ display: none;
+}
+
+.media-selection .count {
+ display: block;
+ padding-top: 12px;
+ font-size: 14px;
+ line-height: 20px;
+ font-weight: bold;
+}
+
+.media-selection .selection-info a {
+ display: block;
+ float: left;
+ padding: 1px 8px;
+ margin: 1px 8px 1px -8px;
+ line-height: 16px;
+ text-decoration: none;
+ border-right: 1px solid #dfdfdf;
+ color: #21759B;
+}
+
+.media-selection .selection-info a:hover {
+ background: #21759B;
+ color: #fff;
+ border-color: transparent;
+}
+
+.media-selection .selection-info a:last-child {
+ border-right: 0;
+ margin-right: 0;
+}
+
+.media-selection .selection-info .clear-selection {
+ color: red;
+}
+
+.media-selection .selection-info .clear-selection:hover {
+ background: red;
+}
+
+.media-selection .selection-view {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.media-selection .attachments {
+ display: inline-block;
+ height: 48px;
+ margin-top: 5px;
+ overflow: hidden;
+ vertical-align: top;
+}
+
+.media-selection .attachment .icon {
+ width: 50%;
+}
+
+.attachment.selection.selected {
+ box-shadow: none;
+}
+
+.attachment.selection.details {
+ box-shadow:
+ 0 0 0 1px #fff,
+ 0 0 0 4px #1e8cbe;
+}
+
+.media-selection .attachment.selection.details {
+ box-shadow:
+ 0 0 0 1px #fff,
+ 0 0 0 3px #1e8cbe;
+}
+
+.media-selection:after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 25px;
+ background-image: -webkit-gradient(linear, right top, left top, from( rgba( 255, 255, 255, 1 ) ), to( rgba( 255, 255, 255, 0 ) ));
+ background-image: -webkit-linear-gradient(right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+ background-image: -moz-linear-gradient(right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+ background-image: -o-linear-gradient(right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+ background-image: linear-gradient(to left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
+}
+
+.media-selection .attachment .filename {
+ display: none;
+}
+
+/**
+ * Spinner
+ */
+
+.media-frame .spinner {
+ background: url(../images/wpspin.gif) no-repeat;
+ background-size: 16px 16px;
+ display: none;
+ opacity: 0.7;
+ filter: alpha(opacity=70);
+ width: 16px;
+ height: 16px;
+ margin: 0;
+}
+
+.media-sidebar .settings-save-status {
+ background: #f5f5f5;
+ float: right;
+ text-transform: none;
+ z-index: 10;
+}
+
+.media-sidebar .settings-save-status .spinner {
+ margin: 0 5px 0;
+}
+
+.media-sidebar .settings-save-status .saved {
+ float: right;
+ display: none;
+}
+
+.media-sidebar .save-waiting .settings-save-status .spinner,
+.media-sidebar .save-complete .settings-save-status .saved {
+ display: block;
+}
+
+/**
+ * Attachment Details
+ */
+.attachment-details {
+ position: relative;
+ overflow: auto;
+}
+
+.attachment-info {
+ overflow: hidden;
+ min-height: 60px;
+ margin-bottom: 16px;
+ line-height: 18px;
+ color: #999;
+ border-bottom: 1px solid #e5e5e5;
+ box-shadow: 0 1px 0 #fff;
+ padding-bottom: 11px;
+}
+
+.attachment-info .filename {
+ font-weight: bold;
+ color: #464646;
+ word-wrap: break-word;
+}
+
+.attachment-info .thumbnail {
+ position: relative;
+ float: left;
+ max-width: 120px;
+ max-height: 120px;
+ margin-top: 5px;
+ margin-right: 10px;
+ margin-bottom: 5px;
+}
+
+.uploading .attachment-info .thumbnail {
+ width: 120px;
+ height: 80px;
+ box-shadow: inset 0 0 15px rgba( 0, 0, 0, 0.1 );
+}
+
+.uploading .attachment-info .media-progress-bar {
+ margin-top: 35px;
+}
+
+.attachment-info .thumbnail:after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.15 );
+ overflow: hidden;
+}
+
+.attachment-info .thumbnail img {
+ display: block;
+ max-width: 120px;
+ max-height: 120px;
+ margin: 0 auto;
+}
+
+.attachment-info .details {
+ float: left;
+ font-size: 12px;
+ max-width: 100%;
+}
+
+.attachment-info .edit-attachment,
+.attachment-info .refresh-attachment,
+.attachment-info .delete-attachment {
+ display: block;
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+.attachment-info .refresh-attachment,
+.attachment-details.needs-refresh .attachment-info .edit-attachment {
+ display: none;
+}
+
+.attachment-details.needs-refresh .attachment-info .refresh-attachment,
+.attachment-info .edit-attachment {
+ display: block;
+}
+
+.attachment-info .delete-attachment {
+ color: #bc0b0b;
+}
+
+.attachment-info .delete-attachment:hover {
+ color: red;
+}
+
+/**
+ * Attachment Display Settings
+ */
+.attachment-display-settings {
+ width: 100%;
+ float: left;
+ overflow: hidden;
+}
+
+.attachment-display-settings h4 {
+ margin: 1.4em 0 0.4em;
+}
+
+.gallery-settings {
+ overflow: hidden;
+}
+
+/**
+ * Embed from URL
+ */
+.embed-url {
+ display: block;
+ position: relative;
+ padding: 0 16px 7px;
+ margin: 0;
+ z-index: 250;
+ background: #fff;
+ border-bottom: 1px solid #dfdfdf;
+ box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
+ font-size: 18px;
+ font-weight: 200;
+}
+
+.media-frame .embed-url input {
+ font-size: 18px;
+ padding: 12px 14px;
+ width: 100%;
+ min-width: 200px;
+ box-shadow: inset 2px 2px 4px -2px rgba( 0, 0, 0, 0.1 );
+}
+
+.media-frame .embed-url .spinner {
+ position: absolute;
+ top: 16px;
+ right: 26px;
+}
+
+.media-frame .embed-loading .embed-url .spinner {
+ display: block;
+}
+
+.embed-link-settings,
+.embed-image-settings {
+ position: absolute;
+ background: #f5f5f5;
+ top: 57px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 16px 16px 32px;
+ overflow: auto;
+}
+
+.media-embed .thumbnail {
+ max-width: 100%;
+ max-height: 200px;
+ position: relative;
+ float: left;
+}
+
+.media-embed .thumbnail img {
+ max-height: 200px;
+ display: block;
+}
+
+.media-embed .thumbnail:after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ box-shadow: inset 0 0 0 1px rgba( 0, 0, 0, 0.1 );
+ overflow: hidden;
+}
+
+.media-embed .setting {
+ width: 100%;
+ margin-top: 10px;
+ float: left;
+ display: block;
+ clear: both;
+}
+
+.media-embed .setting span {
+ display: block;
+ width: 200px;
+ font-size: 13px;
+ line-height: 24px;
+ color: #999;
+ text-shadow: 0 1px 0 #fff;
+}
+
+.media-embed .setting .button-group {
+ margin: 2px 0;
+}
+
+.media-embed .setting input,
+.media-embed .setting textarea {
+ display: block;
+ width: 100%;
+ max-width: 400px;
+ margin: 1px 0;
+}
+
+/**
+ * IE7 Fixes
+ */
+.ie7 .media-frame .attachments-browser {
+ position: static;
+}
+
+.ie7 .media-frame .embed-url input {
+ margin-top: 4px;
+ width: 90%;
+}
+
+.ie7 .compat-item {
+ width: 99%;
+}
+
+.ie7 .attachment-display-settings {
+ width: auto;
+}
+
+.ie7 .attachment-preview,
+.ie7 .attachment-preview .thumbnail {
+ width: 120px;
+ height: 120px;
+}
+
+.ie7 .media-frame .attachment .describe {
+ width: 102px;
+}
+
+.ie7 .media-sidebar .setting select {
+ max-width: 55%;
+}
+
+.ie7 .media-sidebar .setting input,
+.ie7 .media-sidebar .setting textarea {
+ width: 55%;
+}
+
+.ie7 .media-sidebar .setting .link-to-custom {
+ float: left;
+}
+
+@media only screen and (max-width: 960px) {
+ .media-frame-content .media-toolbar-primary .search,
+ .media-frame-content .media-toolbar-secondary .attachment-filters {
+ max-width: 120px;
+ }
+}
+
+/**
+ * Responsive layout
+ */
+@media only screen and (max-width: 900px) {
+ .media-frame-menu {
+ width: 139px;
+ }
+
+ .media-menu > a {
+ padding: 4px 10px;
+ }
+
+ .media-frame-title,
+ .media-frame-router,
+ .media-frame-content,
+ .media-frame-toolbar {
+ left: 140px;
+ }
+
+ .media-sidebar {
+ width: 159px;
+ padding: 0 10px 24px;
+ }
+
+ .attachments-browser .attachments,
+ .attachments-browser .uploader-inline,
+ .attachments-browser .media-toolbar {
+ right: 180px;
+ }
+
+ .media-sidebar .setting input,
+ .media-sidebar .setting textarea,
+ .media-sidebar .setting span,
+ .compat-item label span {
+ float: none;
+ }
+
+ .media-sidebar .setting span,
+ .compat-item label span {
+ text-align: inherit;
+ display: block;
+ min-height: 16px;
+ margin: 0;
+ padding: 8px 2px 0;
+ }
+
+ .media-sidebar .setting input,
+ .media-sidebar .setting textarea,
+ .media-sidebar .setting select {
+ width: 98%;
+ max-width: none;
+ }
+
+ .media-sidebar .setting select.columns {
+ width: auto;
+ }
+
+ .media-frame input,
+ .media-frame textarea,
+ .media-frame .search {
+ padding: 3px 6px;
+ }
+
+ .media-frame-content .attachment .icon {
+ top: 40%;
+ }
+
+ .media-selection {
+ min-width: 120px;
+ }
+
+ .media-selection:after {
+ background: none;
+ }
+
+ .media-selection .attachments {
+ display: none;
+ }
+
+ .media-menu .separator {
+ margin: 12px 10px;
+ }
+}
+
+@media only screen and (max-width: 800px) {
+ .media-frame-content .media-toolbar .instructions {
+ display: none;
+ }
+}
+
+@media only screen and (max-width: 680px) {
+ .media-frame-content .media-toolbar .search,
+ .media-frame-content .media-toolbar .attachment-filters {
+ max-width: 85px;
+ }
+}
+
+/* Use the same min-width as in the admin */
+@media only screen and (max-width: 600px) {
+ .media-modal {
+ width: 540px;
+ position: absolute;
+ }
+
+ .media-modal-backdrop {
+ width: 600px;
+ position: absolute;
+ }
+}
+
+/**
+ * HiDPI Displays
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ .media-modal-icon {
+ background-image: url(../images/uploader-icons-2x.png);
+ background-size: 134px 15px;
+ }
+
+ .media-frame .spinner {
+ background-image: url(../images/wpspin-2x.gif);
+ }
+} \ No newline at end of file
diff --git a/src/wp-includes/css/wp-auth-check.css b/src/wp-includes/css/wp-auth-check.css
new file mode 100644
index 0000000000..f51017b59f
--- /dev/null
+++ b/src/wp-includes/css/wp-auth-check.css
@@ -0,0 +1,94 @@
+/*------------------------------------------------------------------------------
+ Interim login dialog
+------------------------------------------------------------------------------*/
+
+#wp-auth-check-wrap.hidden {
+ display: none;
+}
+
+#wp-auth-check-wrap #wp-auth-check-bg {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: #000;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+ z-index: 1000000;
+}
+
+#wp-auth-check-wrap #wp-auth-check {
+ position: fixed;
+ left: 50%;
+ overflow: hidden;
+ top: 40px;
+ bottom: 20px;
+ max-height: 415px;
+ width: 380px;
+ margin: 0 0 0 -190px;
+ padding: 30px 0 0;
+ background-color: #fbfbfb;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ z-index: 1000001;
+}
+
+#wp-auth-check-wrap.fallback #wp-auth-check {
+ max-height: 180px;
+ overflow: auto;
+}
+
+#wp-auth-check-wrap #wp-auth-check-form {
+ background: url(../images/wpspin-2x.gif) no-repeat center center;
+ background-size: 16px 16px;
+ height: 100%;
+}
+
+#wp-auth-check-wrap #wp-auth-check-form iframe {
+ height: 100%;
+ width: 100%;
+ overflow: auto;
+}
+
+#wp-auth-check-wrap .wp-auth-check-close {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ height: 14px;
+ width: 14px;
+ cursor: pointer;
+ background-image: url(../images/uploader-icons.png);
+ background-repeat: no-repeat;
+ background-position: -100px 0;
+}
+
+#wp-auth-check-wrap .wp-auth-check-close:focus {
+ outline: 1px dotted #888;
+}
+
+#wp-auth-check-wrap .wp-auth-fallback-expired {
+ outline: 0;
+}
+
+#wp-auth-check-wrap .wp-auth-fallback {
+ font-size: 14px;
+ line-height: 21px;
+ padding: 0 25px;
+ display: none;
+}
+
+#wp-auth-check-wrap.fallback .wp-auth-fallback,
+#wp-auth-check-wrap.fallback .wp-auth-check-close {
+ display: block;
+}
+
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ #wp-auth-check-wrap .wp-auth-check-close {
+ background-image: url(../images/uploader-icons-2x.png);
+ background-size: 134px 15px;
+ }
+}
diff --git a/src/wp-includes/css/wp-pointer.css b/src/wp-includes/css/wp-pointer.css
new file mode 100644
index 0000000000..c5566f3f91
--- /dev/null
+++ b/src/wp-includes/css/wp-pointer.css
@@ -0,0 +1,228 @@
+.wp-pointer {
+}
+
+.wp-pointer-content {
+ padding: 0 0 10px;
+ position: relative;
+ font-size: 13px;
+
+ background: #fff;
+ border-style: solid;
+ border-width: 1px;
+ /* Fallback for non-rgba-compliant browsers */
+ border-color: #dfdfdf;
+ /* Use rgba to look better against non-white backgrounds. */
+ border-color: rgba(0,0,0,.125);
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+
+ -webkit-box-shadow: 0 2px 4px rgba(0,0,0,.19);
+ box-shadow: 0 2px 4px rgba(0,0,0,.19);
+}
+
+.wp-pointer-content h3 {
+ position: relative;
+ margin: 0 0 5px;
+ padding: 15px 18px 14px 60px;
+ line-height: 1.4em;
+ font-size: 14px;
+ color: #fff;
+ border-radius: 3px 3px 0 0;
+ text-shadow: 0 -1px 0 rgba(0,0,0,0.3);
+ background: #8cc1e9;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#72a7cf), to(#8cc1e9));
+ background-image: -webkit-linear-gradient(bottom, #72a7cf, #8cc1e9);
+ background-image: -moz-linear-gradient(bottom, #72a7cf, #8cc1e9);
+ background-image: -o-linear-gradient(bottom, #72a7cf, #8cc1e9);
+ background-image: linear-gradient(to top, #72a7cf, #8cc1e9);
+}
+
+.wp-pointer-content h3:before {
+ position: absolute;
+ top: 0;
+ left: 15px;
+ content: ' ';
+ width: 36px;
+ height: 100%;
+ background: url('../images/icon-pointer-flag.png') 0 50% no-repeat;
+}
+
+.wp-pointer-content p {
+ padding: 0 15px;
+}
+
+.wp-pointer-buttons {
+ margin: 0;
+ padding: 5px 15px;
+ overflow: auto;
+}
+
+.wp-pointer-buttons a {
+ float: right;
+ display: inline-block;
+ text-decoration: none;
+}
+
+.wp-pointer-buttons a.close {
+ padding-left:3px;
+ position: relative;
+}
+
+.wp-pointer-buttons a.close:before {
+ content: ' ';
+ width:10px;
+ height:100%;
+ position:absolute;
+ left:-10px;
+ background:url('../images/xit.gif') 0 50% no-repeat;
+}
+
+.wp-pointer-buttons a.close:hover:before {
+ background-position:100% 50%;
+}
+
+/* The arrow base class must take up no space, even with transparent borders. */
+.wp-pointer-arrow,
+.wp-pointer-arrow-inner {
+ position: absolute;
+ width: 0;
+ height: 0;
+}
+
+.wp-pointer-arrow {
+ z-index: 10;
+ background:url('../images/arrow-pointer-blue.png') 0 0 no-repeat;
+}
+
+.wp-pointer-arrow-inner {
+ z-index: 20;
+}
+
+/* Make Room for the Arrow! */
+.wp-pointer-top,
+.wp-pointer-undefined {
+ padding-top: 13px;
+}
+
+.wp-pointer-bottom {
+ padding-bottom: 13px;
+}
+
+.wp-pointer-left {
+ padding-left: 13px;
+}
+
+.wp-pointer-right {
+ padding-right: 13px;
+}
+
+/* Base Size & Positioning */
+.wp-pointer-top .wp-pointer-arrow,
+.wp-pointer-bottom .wp-pointer-arrow,
+.wp-pointer-undefined .wp-pointer-arrow {
+ left: 50px;
+ width: 30px;
+ height: 14px;
+}
+
+.wp-pointer-left .wp-pointer-arrow,
+.wp-pointer-right .wp-pointer-arrow {
+ top: 50%;
+ margin-top: -15px;
+ width: 14px;
+ height: 30px;
+}
+
+/* Arrow Sprite */
+.wp-pointer-top .wp-pointer-arrow,
+.wp-pointer-undefined .wp-pointer-arrow {
+ top: 0;
+ background-position: 0 0;
+}
+
+.wp-pointer-bottom .wp-pointer-arrow {
+ bottom: 0;
+ background-position: 0 -46px;
+}
+
+.wp-pointer-left .wp-pointer-arrow {
+ left: 0;
+ background-position: 0 -15px;
+}
+
+.wp-pointer-right .wp-pointer-arrow {
+ right:0;
+ background-position:-16px -15px;
+}
+
+/* - RTL
+------------------------------------------------------------------------------*/
+
+.rtl .wp-pointer-content h3 {
+ padding-right: 60px;
+ padding-left: 18px;
+}
+
+.rtl .wp-pointer-content h3:before {
+ right: 15px;
+}
+
+.rtl .wp-pointer-buttons a {
+ float: left;
+}
+
+.rtl .wp-pointer-buttons a.close {
+ padding-right:3px;
+ padding-left: 0;
+}
+
+.rtl .wp-pointer-buttons a.close:before {
+ right:-10px;
+}
+
+.rtl .wp-pointer-top .wp-pointer-arrow,
+.rtl .wp-pointer-bottom .wp-pointer-arrow,
+.rtl .wp-pointer-undefined .wp-pointer-arrow {
+ right: 50px;
+}
+
+/**
+ * HiDPI Displays
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+
+ .wp-pointer-buttons a.close:before {
+ background-image: url('../images/xit-2x.gif');
+ background-size: 20px auto;
+ }
+
+ .wp-pointer-content h3:before {
+ background-image: url('../images/icon-pointer-flag-2x.png');
+ background-size: 36px auto;
+ }
+
+ .wp-pointer-arrow {
+ background: url('../images/arrow-pointer-blue-2x.png') 0 0 no-repeat;
+ background-size: 30px 60px;
+ }
+
+ .wp-pointer-top .wp-pointer-arrow,
+ .wp-pointer-undefined .wp-pointer-arrow {
+ background-position: 0 1px;
+ }
+
+ .wp-pointer-bottom .wp-pointer-arrow {
+ background-position: 0 -47px;
+ }
+
+ .wp-pointer-left .wp-pointer-arrow {
+ background-position: 1px -15px;
+ }
+
+ .wp-pointer-right .wp-pointer-arrow {
+ background-position:-17px -15px;
+ }
+}
diff --git a/src/wp-includes/default-constants.php b/src/wp-includes/default-constants.php
new file mode 100644
index 0000000000..358c1018f3
--- /dev/null
+++ b/src/wp-includes/default-constants.php
@@ -0,0 +1,309 @@
+<?php
+/**
+ * Defines constants and global variables that can be overridden, generally in wp-config.php.
+ *
+ * @package WordPress
+ */
+
+/**
+ * Defines initial WordPress constants
+ *
+ * @see wp_debug_mode()
+ *
+ * @since 3.0.0
+ */
+function wp_initial_constants() {
+ global $blog_id;
+
+ // set memory limits
+ if ( !defined('WP_MEMORY_LIMIT') ) {
+ if( is_multisite() ) {
+ define('WP_MEMORY_LIMIT', '64M');
+ } else {
+ define('WP_MEMORY_LIMIT', '40M');
+ }
+ }
+
+ if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) ) {
+ define( 'WP_MAX_MEMORY_LIMIT', '256M' );
+ }
+
+ /**
+ * The $blog_id global, which you can change in the config allows you to create a simple
+ * multiple blog installation using just one WordPress and changing $blog_id around.
+ *
+ * @global int $blog_id
+ * @since 2.0.0
+ */
+ if ( ! isset($blog_id) )
+ $blog_id = 1;
+
+ // set memory limits.
+ if ( function_exists( 'memory_get_usage' ) ) {
+ $current_limit = @ini_get( 'memory_limit' );
+ if ( -1 != $current_limit && ( -1 == WP_MEMORY_LIMIT || ( intval( $current_limit ) < abs( intval( WP_MEMORY_LIMIT ) ) ) ) )
+ @ini_set( 'memory_limit', WP_MEMORY_LIMIT );
+ }
+
+ if ( !defined('WP_CONTENT_DIR') )
+ define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' ); // no trailing slash, full paths only - WP_CONTENT_URL is defined further down
+
+ // Add define('WP_DEBUG', true); to wp-config.php to enable display of notices during development.
+ if ( !defined('WP_DEBUG') )
+ define( 'WP_DEBUG', false );
+
+ // Add define('WP_DEBUG_DISPLAY', null); to wp-config.php use the globally configured setting for
+ // display_errors and not force errors to be displayed. Use false to force display_errors off.
+ if ( !defined('WP_DEBUG_DISPLAY') )
+ define( 'WP_DEBUG_DISPLAY', true );
+
+ // Add define('WP_DEBUG_LOG', true); to enable error logging to wp-content/debug.log.
+ if ( !defined('WP_DEBUG_LOG') )
+ define('WP_DEBUG_LOG', false);
+
+ if ( !defined('WP_CACHE') )
+ define('WP_CACHE', false);
+
+ /**
+ * Private
+ */
+ if ( !defined('MEDIA_TRASH') )
+ define('MEDIA_TRASH', false);
+
+ if ( !defined('SHORTINIT') )
+ define('SHORTINIT', false);
+
+ // Constants for expressing human-readable intervals
+ // in their respective number of seconds.
+ define( 'MINUTE_IN_SECONDS', 60 );
+ define( 'HOUR_IN_SECONDS', 60 * MINUTE_IN_SECONDS );
+ define( 'DAY_IN_SECONDS', 24 * HOUR_IN_SECONDS );
+ define( 'WEEK_IN_SECONDS', 7 * DAY_IN_SECONDS );
+ define( 'YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS );
+}
+
+/**
+ * Defines plugin directory WordPress constants
+ *
+ * Defines must-use plugin directory constants, which may be overridden in the sunrise.php drop-in
+ *
+ * @since 3.0.0
+ */
+function wp_plugin_directory_constants() {
+ if ( !defined('WP_CONTENT_URL') )
+ define( 'WP_CONTENT_URL', get_option('siteurl') . '/wp-content'); // full url - WP_CONTENT_DIR is defined further up
+
+ /**
+ * Allows for the plugins directory to be moved from the default location.
+ *
+ * @since 2.6.0
+ */
+ if ( !defined('WP_PLUGIN_DIR') )
+ define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' ); // full path, no trailing slash
+
+ /**
+ * Allows for the plugins directory to be moved from the default location.
+ *
+ * @since 2.6.0
+ */
+ if ( !defined('WP_PLUGIN_URL') )
+ define( 'WP_PLUGIN_URL', WP_CONTENT_URL . '/plugins' ); // full url, no trailing slash
+
+ /**
+ * Allows for the plugins directory to be moved from the default location.
+ *
+ * @since 2.1.0
+ * @deprecated
+ */
+ if ( !defined('PLUGINDIR') )
+ define( 'PLUGINDIR', 'wp-content/plugins' ); // Relative to ABSPATH. For back compat.
+
+ /**
+ * Allows for the mu-plugins directory to be moved from the default location.
+ *
+ * @since 2.8.0
+ */
+ if ( !defined('WPMU_PLUGIN_DIR') )
+ define( 'WPMU_PLUGIN_DIR', WP_CONTENT_DIR . '/mu-plugins' ); // full path, no trailing slash
+
+ /**
+ * Allows for the mu-plugins directory to be moved from the default location.
+ *
+ * @since 2.8.0
+ */
+ if ( !defined('WPMU_PLUGIN_URL') )
+ define( 'WPMU_PLUGIN_URL', WP_CONTENT_URL . '/mu-plugins' ); // full url, no trailing slash
+
+ /**
+ * Allows for the mu-plugins directory to be moved from the default location.
+ *
+ * @since 2.8.0
+ * @deprecated
+ */
+ if ( !defined( 'MUPLUGINDIR' ) )
+ define( 'MUPLUGINDIR', 'wp-content/mu-plugins' ); // Relative to ABSPATH. For back compat.
+}
+
+/**
+ * Defines cookie related WordPress constants
+ *
+ * Defines constants after multisite is loaded. Cookie-related constants may be overridden in ms_network_cookies().
+ * @since 3.0.0
+ */
+function wp_cookie_constants() {
+ /**
+ * Used to guarantee unique hash cookies
+ * @since 1.5
+ */
+ if ( !defined( 'COOKIEHASH' ) ) {
+ $siteurl = get_site_option( 'siteurl' );
+ if ( $siteurl )
+ define( 'COOKIEHASH', md5( $siteurl ) );
+ else
+ define( 'COOKIEHASH', '' );
+ }
+
+ /**
+ * @since 2.0.0
+ */
+ if ( !defined('USER_COOKIE') )
+ define('USER_COOKIE', 'wordpressuser_' . COOKIEHASH);
+
+ /**
+ * @since 2.0.0
+ */
+ if ( !defined('PASS_COOKIE') )
+ define('PASS_COOKIE', 'wordpresspass_' . COOKIEHASH);
+
+ /**
+ * @since 2.5.0
+ */
+ if ( !defined('AUTH_COOKIE') )
+ define('AUTH_COOKIE', 'wordpress_' . COOKIEHASH);
+
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined('SECURE_AUTH_COOKIE') )
+ define('SECURE_AUTH_COOKIE', 'wordpress_sec_' . COOKIEHASH);
+
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined('LOGGED_IN_COOKIE') )
+ define('LOGGED_IN_COOKIE', 'wordpress_logged_in_' . COOKIEHASH);
+
+ /**
+ * @since 2.3.0
+ */
+ if ( !defined('TEST_COOKIE') )
+ define('TEST_COOKIE', 'wordpress_test_cookie');
+
+ /**
+ * @since 1.2.0
+ */
+ if ( !defined('COOKIEPATH') )
+ define('COOKIEPATH', preg_replace('|https?://[^/]+|i', '', get_option('home') . '/' ) );
+
+ /**
+ * @since 1.5.0
+ */
+ if ( !defined('SITECOOKIEPATH') )
+ define('SITECOOKIEPATH', preg_replace('|https?://[^/]+|i', '', get_option('siteurl') . '/' ) );
+
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined('ADMIN_COOKIE_PATH') )
+ define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH . 'wp-admin' );
+
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined('PLUGINS_COOKIE_PATH') )
+ define( 'PLUGINS_COOKIE_PATH', preg_replace('|https?://[^/]+|i', '', WP_PLUGIN_URL) );
+
+ /**
+ * @since 2.0.0
+ */
+ if ( !defined('COOKIE_DOMAIN') )
+ define('COOKIE_DOMAIN', false);
+}
+
+/**
+ * Defines cookie related WordPress constants
+ *
+ * @since 3.0.0
+ */
+function wp_ssl_constants() {
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined('FORCE_SSL_ADMIN') )
+ define('FORCE_SSL_ADMIN', false);
+ force_ssl_admin(FORCE_SSL_ADMIN);
+
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined('FORCE_SSL_LOGIN') )
+ define('FORCE_SSL_LOGIN', false);
+ force_ssl_login(FORCE_SSL_LOGIN);
+}
+
+/**
+ * Defines functionality related WordPress constants
+ *
+ * @since 3.0.0
+ */
+function wp_functionality_constants() {
+ /**
+ * @since 2.5.0
+ */
+ if ( !defined( 'AUTOSAVE_INTERVAL' ) )
+ define( 'AUTOSAVE_INTERVAL', 60 );
+
+ /**
+ * @since 2.9.0
+ */
+ if ( !defined( 'EMPTY_TRASH_DAYS' ) )
+ define( 'EMPTY_TRASH_DAYS', 30 );
+
+ if ( !defined('WP_POST_REVISIONS') )
+ define('WP_POST_REVISIONS', true);
+
+ /**
+ * @since 3.3.0
+ */
+ if ( !defined( 'WP_CRON_LOCK_TIMEOUT' ) )
+ define('WP_CRON_LOCK_TIMEOUT', 60); // In seconds
+}
+
+/**
+ * Defines templating related WordPress constants
+ *
+ * @since 3.0.0
+ */
+function wp_templating_constants() {
+ /**
+ * Filesystem path to the current active template directory
+ * @since 1.5.0
+ */
+ define('TEMPLATEPATH', get_template_directory());
+
+ /**
+ * Filesystem path to the current active template stylesheet directory
+ * @since 2.1.0
+ */
+ define('STYLESHEETPATH', get_stylesheet_directory());
+
+ /**
+ * Slug of the default theme for this install.
+ * Used as the default theme when installing new sites.
+ * Will be used as the fallback if the current theme doesn't exist.
+ * @since 3.0.0
+ */
+ if ( !defined('WP_DEFAULT_THEME') )
+ define( 'WP_DEFAULT_THEME', 'twentythirteen' );
+
+}
diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php
new file mode 100644
index 0000000000..531fd538e4
--- /dev/null
+++ b/src/wp-includes/default-filters.php
@@ -0,0 +1,308 @@
+<?php
+/**
+ * Sets up the default filters and actions for most
+ * of the WordPress hooks.
+ *
+ * If you need to remove a default hook, this file will
+ * give you the priority for which to use to remove the
+ * hook.
+ *
+ * Not all of the default hooks are found in default-filters.php
+ *
+ * @package WordPress
+ */
+
+// Strip, trim, kses, special chars for string saves
+foreach ( array( 'pre_term_name', 'pre_comment_author_name', 'pre_link_name', 'pre_link_target', 'pre_link_rel', 'pre_user_display_name', 'pre_user_first_name', 'pre_user_last_name', 'pre_user_nickname' ) as $filter ) {
+ add_filter( $filter, 'sanitize_text_field' );
+ add_filter( $filter, 'wp_filter_kses' );
+ add_filter( $filter, '_wp_specialchars', 30 );
+}
+
+// Strip, kses, special chars for string display
+foreach ( array( 'term_name', 'comment_author_name', 'link_name', 'link_target', 'link_rel', 'user_display_name', 'user_first_name', 'user_last_name', 'user_nickname' ) as $filter ) {
+ if ( is_admin() ) {
+ // These are expensive. Run only on admin pages for defense in depth.
+ add_filter( $filter, 'sanitize_text_field' );
+ add_filter( $filter, 'wp_kses_data' );
+ }
+ add_filter( $filter, '_wp_specialchars', 30 );
+}
+
+// Kses only for textarea saves
+foreach ( array( 'pre_term_description', 'pre_link_description', 'pre_link_notes', 'pre_user_description' ) as $filter ) {
+ add_filter( $filter, 'wp_filter_kses' );
+}
+
+// Kses only for textarea admin displays
+if ( is_admin() ) {
+ foreach ( array( 'term_description', 'link_description', 'link_notes', 'user_description' ) as $filter ) {
+ add_filter( $filter, 'wp_kses_data' );
+ }
+ add_filter( 'comment_text', 'wp_kses_post' );
+}
+
+// Email saves
+foreach ( array( 'pre_comment_author_email', 'pre_user_email' ) as $filter ) {
+ add_filter( $filter, 'trim' );
+ add_filter( $filter, 'sanitize_email' );
+ add_filter( $filter, 'wp_filter_kses' );
+}
+
+// Email admin display
+foreach ( array( 'comment_author_email', 'user_email' ) as $filter ) {
+ add_filter( $filter, 'sanitize_email' );
+ if ( is_admin() )
+ add_filter( $filter, 'wp_kses_data' );
+}
+
+// Save URL
+foreach ( array( 'pre_comment_author_url', 'pre_user_url', 'pre_link_url', 'pre_link_image',
+ 'pre_link_rss', 'pre_post_guid' ) as $filter ) {
+ add_filter( $filter, 'wp_strip_all_tags' );
+ add_filter( $filter, 'esc_url_raw' );
+ add_filter( $filter, 'wp_filter_kses' );
+}
+
+// Display URL
+foreach ( array( 'user_url', 'link_url', 'link_image', 'link_rss', 'comment_url', 'post_guid' ) as $filter ) {
+ if ( is_admin() )
+ add_filter( $filter, 'wp_strip_all_tags' );
+ add_filter( $filter, 'esc_url' );
+ if ( is_admin() )
+ add_filter( $filter, 'wp_kses_data' );
+}
+
+// Slugs
+foreach ( array( 'pre_term_slug' ) as $filter ) {
+ add_filter( $filter, 'sanitize_title' );
+}
+
+// Keys
+foreach ( array( 'pre_post_type', 'pre_post_status', 'pre_post_comment_status', 'pre_post_ping_status' ) as $filter ) {
+ add_filter( $filter, 'sanitize_key' );
+}
+
+// Mime types
+add_filter( 'pre_post_mime_type', 'sanitize_mime_type' );
+add_filter( 'post_mime_type', 'sanitize_mime_type' );
+
+// Places to balance tags on input
+foreach ( array( 'content_save_pre', 'excerpt_save_pre', 'comment_save_pre', 'pre_comment_content' ) as $filter ) {
+ add_filter( $filter, 'balanceTags', 50 );
+}
+
+// Format strings for display.
+foreach ( array( 'comment_author', 'term_name', 'link_name', 'link_description', 'link_notes', 'bloginfo', 'wp_title', 'widget_title' ) as $filter ) {
+ add_filter( $filter, 'wptexturize' );
+ add_filter( $filter, 'convert_chars' );
+ add_filter( $filter, 'esc_html' );
+}
+
+// Format WordPress
+foreach ( array( 'the_content', 'the_title' ) as $filter )
+ add_filter( $filter, 'capital_P_dangit', 11 );
+add_filter( 'comment_text', 'capital_P_dangit', 31 );
+
+// Format titles
+foreach ( array( 'single_post_title', 'single_cat_title', 'single_tag_title', 'single_month_title', 'nav_menu_attr_title', 'nav_menu_description' ) as $filter ) {
+ add_filter( $filter, 'wptexturize' );
+ add_filter( $filter, 'strip_tags' );
+}
+
+// Format text area for display.
+foreach ( array( 'term_description' ) as $filter ) {
+ add_filter( $filter, 'wptexturize' );
+ add_filter( $filter, 'convert_chars' );
+ add_filter( $filter, 'wpautop' );
+ add_filter( $filter, 'shortcode_unautop');
+}
+
+// Format for RSS
+foreach ( array( 'term_name_rss' ) as $filter ) {
+ add_filter( $filter, 'convert_chars' );
+}
+
+// Pre save hierarchy
+add_filter( 'wp_insert_post_parent', 'wp_check_post_hierarchy_for_loops', 10, 2 );
+add_filter( 'wp_update_term_parent', 'wp_check_term_hierarchy_for_loops', 10, 3 );
+
+// Display filters
+add_filter( 'the_title', 'wptexturize' );
+add_filter( 'the_title', 'convert_chars' );
+add_filter( 'the_title', 'trim' );
+
+add_filter( 'the_content', 'wptexturize' );
+add_filter( 'the_content', 'convert_smilies' );
+add_filter( 'the_content', 'convert_chars' );
+add_filter( 'the_content', 'wpautop' );
+add_filter( 'the_content', 'shortcode_unautop' );
+add_filter( 'the_content', 'prepend_attachment' );
+
+add_filter( 'the_excerpt', 'wptexturize' );
+add_filter( 'the_excerpt', 'convert_smilies' );
+add_filter( 'the_excerpt', 'convert_chars' );
+add_filter( 'the_excerpt', 'wpautop' );
+add_filter( 'the_excerpt', 'shortcode_unautop');
+add_filter( 'get_the_excerpt', 'wp_trim_excerpt' );
+
+add_filter( 'comment_text', 'wptexturize' );
+add_filter( 'comment_text', 'convert_chars' );
+add_filter( 'comment_text', 'make_clickable', 9 );
+add_filter( 'comment_text', 'force_balance_tags', 25 );
+add_filter( 'comment_text', 'convert_smilies', 20 );
+add_filter( 'comment_text', 'wpautop', 30 );
+
+add_filter( 'comment_excerpt', 'convert_chars' );
+
+add_filter( 'list_cats', 'wptexturize' );
+
+add_filter( 'wp_sprintf', 'wp_sprintf_l', 10, 2 );
+
+// RSS filters
+add_filter( 'the_title_rss', 'strip_tags' );
+add_filter( 'the_title_rss', 'ent2ncr', 8 );
+add_filter( 'the_title_rss', 'esc_html' );
+add_filter( 'the_content_rss', 'ent2ncr', 8 );
+add_filter( 'the_excerpt_rss', 'convert_chars' );
+add_filter( 'the_excerpt_rss', 'ent2ncr', 8 );
+add_filter( 'comment_author_rss', 'ent2ncr', 8 );
+add_filter( 'comment_text_rss', 'ent2ncr', 8 );
+add_filter( 'comment_text_rss', 'esc_html' );
+add_filter( 'bloginfo_rss', 'ent2ncr', 8 );
+add_filter( 'the_author', 'ent2ncr', 8 );
+
+// Misc filters
+add_filter( 'option_ping_sites', 'privacy_ping_filter' );
+add_filter( 'option_blog_charset', '_wp_specialchars' ); // IMPORTANT: This must not be wp_specialchars() or esc_html() or it'll cause an infinite loop
+add_filter( 'option_blog_charset', '_canonical_charset' );
+add_filter( 'option_home', '_config_wp_home' );
+add_filter( 'option_siteurl', '_config_wp_siteurl' );
+add_filter( 'tiny_mce_before_init', '_mce_set_direction' );
+add_filter( 'pre_kses', 'wp_pre_kses_less_than' );
+add_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 );
+add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 3 );
+add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 );
+add_filter( 'pre_comment_content', 'wp_rel_nofollow', 15 );
+add_filter( 'comment_email', 'antispambot' );
+add_filter( 'option_tag_base', '_wp_filter_taxonomy_base' );
+add_filter( 'option_category_base', '_wp_filter_taxonomy_base' );
+add_filter( 'the_posts', '_close_comments_for_old_posts', 10, 2);
+add_filter( 'comments_open', '_close_comments_for_old_post', 10, 2 );
+add_filter( 'pings_open', '_close_comments_for_old_post', 10, 2 );
+add_filter( 'editable_slug', 'urldecode' );
+add_filter( 'editable_slug', 'esc_textarea' );
+add_filter( 'nav_menu_meta_box_object', '_wp_nav_menu_meta_box_object' );
+add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' );
+add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' );
+
+add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 );
+
+// Actions
+add_action( 'wp_head', 'wp_enqueue_scripts', 1 );
+add_action( 'wp_head', 'feed_links', 2 );
+add_action( 'wp_head', 'feed_links_extra', 3 );
+add_action( 'wp_head', 'rsd_link' );
+add_action( 'wp_head', 'wlwmanifest_link' );
+add_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
+add_action( 'wp_head', 'locale_stylesheet' );
+add_action( 'publish_future_post', 'check_and_publish_future_post', 10, 1 );
+add_action( 'wp_head', 'noindex', 1 );
+add_action( 'wp_head', 'wp_print_styles', 8 );
+add_action( 'wp_head', 'wp_print_head_scripts', 9 );
+add_action( 'wp_head', 'wp_generator' );
+add_action( 'wp_head', 'rel_canonical' );
+add_action( 'wp_footer', 'wp_print_footer_scripts', 20 );
+add_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 );
+add_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );
+add_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
+add_action( 'init', 'check_theme_switched', 99 );
+add_action( 'after_switch_theme', '_wp_sidebars_changed' );
+
+if ( isset( $_GET['replytocom'] ) )
+ add_action( 'wp_head', 'wp_no_robots' );
+
+// Login actions
+add_action( 'login_head', 'wp_print_head_scripts', 9 );
+add_action( 'login_footer', 'wp_print_footer_scripts', 20 );
+add_action( 'login_init', 'send_frame_options_header', 10, 0 );
+
+// Feed Generator Tags
+foreach ( array( 'rss2_head', 'commentsrss2_head', 'rss_head', 'rdf_header', 'atom_head', 'comments_atom_head', 'opml_head', 'app_head' ) as $action ) {
+ add_action( $action, 'the_generator' );
+}
+
+// WP Cron
+if ( !defined( 'DOING_CRON' ) )
+ add_action( 'init', 'wp_cron' );
+
+// 2 Actions 2 Furious
+add_action( 'do_feed_rdf', 'do_feed_rdf', 10, 1 );
+add_action( 'do_feed_rss', 'do_feed_rss', 10, 1 );
+add_action( 'do_feed_rss2', 'do_feed_rss2', 10, 1 );
+add_action( 'do_feed_atom', 'do_feed_atom', 10, 1 );
+add_action( 'do_pings', 'do_all_pings', 10, 1 );
+add_action( 'do_robots', 'do_robots' );
+add_action( 'set_comment_cookies', 'wp_set_comment_cookies', 10, 2 );
+add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies' );
+add_action( 'admin_print_scripts', 'print_head_scripts', 20 );
+add_action( 'admin_print_footer_scripts', '_wp_footer_scripts' );
+add_action( 'admin_print_styles', 'print_admin_styles', 20 );
+add_action( 'init', 'smilies_init', 5 );
+add_action( 'plugins_loaded', 'wp_maybe_load_widgets', 0 );
+add_action( 'plugins_loaded', 'wp_maybe_load_embeds', 0 );
+add_action( 'shutdown', 'wp_ob_end_flush_all', 1 );
+add_action( 'post_updated', 'wp_save_post_revision', 10, 1 );
+add_action( 'publish_post', '_publish_post_hook', 5, 1 );
+add_action( 'transition_post_status', '_transition_post_status', 5, 3 );
+add_action( 'transition_post_status', '_update_term_count_on_transition_post_status', 10, 3 );
+add_action( 'comment_form', 'wp_comment_form_unfiltered_html_nonce' );
+add_action( 'wp_scheduled_delete', 'wp_scheduled_delete' );
+add_action( 'wp_scheduled_auto_draft_delete', 'wp_delete_auto_drafts' );
+add_action( 'admin_init', 'send_frame_options_header', 10, 0 );
+add_action( 'importer_scheduled_cleanup', 'wp_delete_attachment' );
+add_action( 'upgrader_scheduled_cleanup', 'wp_delete_attachment' );
+add_action( 'welcome_panel', 'wp_welcome_panel' );
+
+// Navigation menu actions
+add_action( 'delete_post', '_wp_delete_post_menu_item' );
+add_action( 'delete_term', '_wp_delete_tax_menu_item' );
+add_action( 'transition_post_status', '_wp_auto_add_pages_to_menu', 10, 3 );
+
+// Post Thumbnail CSS class filtering
+add_action( 'begin_fetch_post_thumbnail_html', '_wp_post_thumbnail_class_filter_add' );
+add_action( 'end_fetch_post_thumbnail_html', '_wp_post_thumbnail_class_filter_remove' );
+
+// Redirect Old Slugs
+add_action( 'template_redirect', 'wp_old_slug_redirect' );
+add_action( 'post_updated', 'wp_check_for_changed_slugs', 12, 3 );
+
+// Nonce check for Post Previews
+add_action( 'init', '_show_post_preview' );
+
+// Timezone
+add_filter( 'pre_option_gmt_offset','wp_timezone_override_offset' );
+
+// Admin Color Schemes
+add_action( 'admin_init', 'register_admin_color_schemes', 1);
+add_action( 'admin_color_scheme_picker', 'admin_color_scheme_picker' );
+
+// If the upgrade hasn't run yet, assume link manager is used.
+add_filter( 'default_option_link_manager_enabled', '__return_true' );
+
+// This option no longer exists; tell plugins we always support auto-embedding.
+add_filter( 'default_option_embed_autourls', '__return_true' );
+
+// Default settings for heartbeat
+add_filter( 'heartbeat_settings', 'wp_heartbeat_settings' );
+
+// Check if the user is logged out
+add_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
+add_filter( 'heartbeat_received', 'wp_auth_check', 10, 2 );
+add_filter( 'heartbeat_nopriv_received', 'wp_auth_check', 10, 2 );
+
+// Default authentication filters
+add_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
+add_filter( 'authenticate', 'wp_authenticate_spam_check', 99 );
+
+unset($filter, $action);
diff --git a/src/wp-includes/default-widgets.php b/src/wp-includes/default-widgets.php
new file mode 100644
index 0000000000..09d5811f1c
--- /dev/null
+++ b/src/wp-includes/default-widgets.php
@@ -0,0 +1,1206 @@
+<?php
+/**
+ * Default Widgets
+ *
+ * @package WordPress
+ * @subpackage Widgets
+ */
+
+/**
+ * Pages widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Pages extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_pages', 'description' => __( 'Your site&#8217;s WordPress Pages') );
+ parent::__construct('pages', __('Pages'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract( $args );
+
+ $title = apply_filters('widget_title', empty( $instance['title'] ) ? __( 'Pages' ) : $instance['title'], $instance, $this->id_base);
+ $sortby = empty( $instance['sortby'] ) ? 'menu_order' : $instance['sortby'];
+ $exclude = empty( $instance['exclude'] ) ? '' : $instance['exclude'];
+
+ if ( $sortby == 'menu_order' )
+ $sortby = 'menu_order, post_title';
+
+ $out = wp_list_pages( apply_filters('widget_pages_args', array('title_li' => '', 'echo' => 0, 'sort_column' => $sortby, 'exclude' => $exclude) ) );
+
+ if ( !empty( $out ) ) {
+ echo $before_widget;
+ if ( $title)
+ echo $before_title . $title . $after_title;
+ ?>
+ <ul>
+ <?php echo $out; ?>
+ </ul>
+ <?php
+ echo $after_widget;
+ }
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+ if ( in_array( $new_instance['sortby'], array( 'post_title', 'menu_order', 'ID' ) ) ) {
+ $instance['sortby'] = $new_instance['sortby'];
+ } else {
+ $instance['sortby'] = 'menu_order';
+ }
+
+ $instance['exclude'] = strip_tags( $new_instance['exclude'] );
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ //Defaults
+ $instance = wp_parse_args( (array) $instance, array( 'sortby' => 'post_title', 'title' => '', 'exclude' => '') );
+ $title = esc_attr( $instance['title'] );
+ $exclude = esc_attr( $instance['exclude'] );
+ ?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
+ <p>
+ <label for="<?php echo $this->get_field_id('sortby'); ?>"><?php _e( 'Sort by:' ); ?></label>
+ <select name="<?php echo $this->get_field_name('sortby'); ?>" id="<?php echo $this->get_field_id('sortby'); ?>" class="widefat">
+ <option value="post_title"<?php selected( $instance['sortby'], 'post_title' ); ?>><?php _e('Page title'); ?></option>
+ <option value="menu_order"<?php selected( $instance['sortby'], 'menu_order' ); ?>><?php _e('Page order'); ?></option>
+ <option value="ID"<?php selected( $instance['sortby'], 'ID' ); ?>><?php _e( 'Page ID' ); ?></option>
+ </select>
+ </p>
+ <p>
+ <label for="<?php echo $this->get_field_id('exclude'); ?>"><?php _e( 'Exclude:' ); ?></label> <input type="text" value="<?php echo $exclude; ?>" name="<?php echo $this->get_field_name('exclude'); ?>" id="<?php echo $this->get_field_id('exclude'); ?>" class="widefat" />
+ <br />
+ <small><?php _e( 'Page IDs, separated by commas.' ); ?></small>
+ </p>
+<?php
+ }
+
+}
+
+/**
+ * Links widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Links extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('description' => __( "Your blogroll" ) );
+ parent::__construct('links', __('Links'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args, EXTR_SKIP);
+
+ $show_description = isset($instance['description']) ? $instance['description'] : false;
+ $show_name = isset($instance['name']) ? $instance['name'] : false;
+ $show_rating = isset($instance['rating']) ? $instance['rating'] : false;
+ $show_images = isset($instance['images']) ? $instance['images'] : true;
+ $category = isset($instance['category']) ? $instance['category'] : false;
+ $orderby = isset( $instance['orderby'] ) ? $instance['orderby'] : 'name';
+ $order = $orderby == 'rating' ? 'DESC' : 'ASC';
+ $limit = isset( $instance['limit'] ) ? $instance['limit'] : -1;
+
+ $before_widget = preg_replace('/id="[^"]*"/','id="%id"', $before_widget);
+ wp_list_bookmarks(apply_filters('widget_links_args', array(
+ 'title_before' => $before_title, 'title_after' => $after_title,
+ 'category_before' => $before_widget, 'category_after' => $after_widget,
+ 'show_images' => $show_images, 'show_description' => $show_description,
+ 'show_name' => $show_name, 'show_rating' => $show_rating,
+ 'category' => $category, 'class' => 'linkcat widget',
+ 'orderby' => $orderby, 'order' => $order,
+ 'limit' => $limit,
+ )));
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $new_instance = (array) $new_instance;
+ $instance = array( 'images' => 0, 'name' => 0, 'description' => 0, 'rating' => 0 );
+ foreach ( $instance as $field => $val ) {
+ if ( isset($new_instance[$field]) )
+ $instance[$field] = 1;
+ }
+
+ $instance['orderby'] = 'name';
+ if ( in_array( $new_instance['orderby'], array( 'name', 'rating', 'id', 'rand' ) ) )
+ $instance['orderby'] = $new_instance['orderby'];
+
+ $instance['category'] = intval( $new_instance['category'] );
+ $instance['limit'] = ! empty( $new_instance['limit'] ) ? intval( $new_instance['limit'] ) : -1;
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+
+ //Defaults
+ $instance = wp_parse_args( (array) $instance, array( 'images' => true, 'name' => true, 'description' => false, 'rating' => false, 'category' => false, 'orderby' => 'name', 'limit' => -1 ) );
+ $link_cats = get_terms( 'link_category' );
+ if ( ! $limit = intval( $instance['limit'] ) )
+ $limit = -1;
+?>
+ <p>
+ <label for="<?php echo $this->get_field_id('category'); ?>"><?php _e( 'Select Link Category:' ); ?></label>
+ <select class="widefat" id="<?php echo $this->get_field_id('category'); ?>" name="<?php echo $this->get_field_name('category'); ?>">
+ <option value=""><?php _ex('All Links', 'links widget'); ?></option>
+ <?php
+ foreach ( $link_cats as $link_cat ) {
+ echo '<option value="' . intval( $link_cat->term_id ) . '"'
+ . selected( $instance['category'], $link_cat->term_id, false )
+ . '>' . $link_cat->name . "</option>\n";
+ }
+ ?>
+ </select>
+ <label for="<?php echo $this->get_field_id('orderby'); ?>"><?php _e( 'Sort by:' ); ?></label>
+ <select name="<?php echo $this->get_field_name('orderby'); ?>" id="<?php echo $this->get_field_id('orderby'); ?>" class="widefat">
+ <option value="name"<?php selected( $instance['orderby'], 'name' ); ?>><?php _e( 'Link title' ); ?></option>
+ <option value="rating"<?php selected( $instance['orderby'], 'rating' ); ?>><?php _e( 'Link rating' ); ?></option>
+ <option value="id"<?php selected( $instance['orderby'], 'id' ); ?>><?php _e( 'Link ID' ); ?></option>
+ <option value="rand"<?php selected( $instance['orderby'], 'rand' ); ?>><?php _ex( 'Random', 'Links widget' ); ?></option>
+ </select>
+ </p>
+ <p>
+ <input class="checkbox" type="checkbox" <?php checked($instance['images'], true) ?> id="<?php echo $this->get_field_id('images'); ?>" name="<?php echo $this->get_field_name('images'); ?>" />
+ <label for="<?php echo $this->get_field_id('images'); ?>"><?php _e('Show Link Image'); ?></label><br />
+ <input class="checkbox" type="checkbox" <?php checked($instance['name'], true) ?> id="<?php echo $this->get_field_id('name'); ?>" name="<?php echo $this->get_field_name('name'); ?>" />
+ <label for="<?php echo $this->get_field_id('name'); ?>"><?php _e('Show Link Name'); ?></label><br />
+ <input class="checkbox" type="checkbox" <?php checked($instance['description'], true) ?> id="<?php echo $this->get_field_id('description'); ?>" name="<?php echo $this->get_field_name('description'); ?>" />
+ <label for="<?php echo $this->get_field_id('description'); ?>"><?php _e('Show Link Description'); ?></label><br />
+ <input class="checkbox" type="checkbox" <?php checked($instance['rating'], true) ?> id="<?php echo $this->get_field_id('rating'); ?>" name="<?php echo $this->get_field_name('rating'); ?>" />
+ <label for="<?php echo $this->get_field_id('rating'); ?>"><?php _e('Show Link Rating'); ?></label>
+ </p>
+ <p>
+ <label for="<?php echo $this->get_field_id('limit'); ?>"><?php _e( 'Number of links to show:' ); ?></label>
+ <input id="<?php echo $this->get_field_id('limit'); ?>" name="<?php echo $this->get_field_name('limit'); ?>" type="text" value="<?php echo $limit == -1 ? '' : intval( $limit ); ?>" size="3" />
+ </p>
+<?php
+ }
+}
+
+/**
+ * Search widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Search extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_search', 'description' => __( "A search form for your site") );
+ parent::__construct('search', __('Search'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args);
+ $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
+
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+
+ // Use current theme search form if it exists
+ get_search_form();
+
+ echo $after_widget;
+ }
+
+ function form( $instance ) {
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
+ $title = $instance['title'];
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></label></p>
+<?php
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $new_instance = wp_parse_args((array) $new_instance, array( 'title' => ''));
+ $instance['title'] = strip_tags($new_instance['title']);
+ return $instance;
+ }
+
+}
+
+/**
+ * Archives widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Archives extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_archive', 'description' => __( 'A monthly archive of your site&#8217;s posts') );
+ parent::__construct('archives', __('Archives'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args);
+ $c = ! empty( $instance['count'] ) ? '1' : '0';
+ $d = ! empty( $instance['dropdown'] ) ? '1' : '0';
+ $title = apply_filters('widget_title', empty($instance['title']) ? __('Archives') : $instance['title'], $instance, $this->id_base);
+
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+
+ if ( $d ) {
+?>
+ <select name="archive-dropdown" onchange='document.location.href=this.options[this.selectedIndex].value;'> <option value=""><?php echo esc_attr(__('Select Month')); ?></option> <?php wp_get_archives(apply_filters('widget_archives_dropdown_args', array('type' => 'monthly', 'format' => 'option', 'show_post_count' => $c))); ?> </select>
+<?php
+ } else {
+?>
+ <ul>
+ <?php wp_get_archives(apply_filters('widget_archives_args', array('type' => 'monthly', 'show_post_count' => $c))); ?>
+ </ul>
+<?php
+ }
+
+ echo $after_widget;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $new_instance = wp_parse_args( (array) $new_instance, array( 'title' => '', 'count' => 0, 'dropdown' => '') );
+ $instance['title'] = strip_tags($new_instance['title']);
+ $instance['count'] = $new_instance['count'] ? 1 : 0;
+ $instance['dropdown'] = $new_instance['dropdown'] ? 1 : 0;
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'count' => 0, 'dropdown' => '') );
+ $title = strip_tags($instance['title']);
+ $count = $instance['count'] ? 'checked="checked"' : '';
+ $dropdown = $instance['dropdown'] ? 'checked="checked"' : '';
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></p>
+ <p>
+ <input class="checkbox" type="checkbox" <?php echo $dropdown; ?> id="<?php echo $this->get_field_id('dropdown'); ?>" name="<?php echo $this->get_field_name('dropdown'); ?>" /> <label for="<?php echo $this->get_field_id('dropdown'); ?>"><?php _e('Display as dropdown'); ?></label>
+ <br/>
+ <input class="checkbox" type="checkbox" <?php echo $count; ?> id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>" /> <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e('Show post counts'); ?></label>
+ </p>
+<?php
+ }
+}
+
+/**
+ * Meta widget class
+ *
+ * Displays log in/out, RSS feed links, etc.
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Meta extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_meta', 'description' => __( "Log in/out, admin, feed and WordPress links") );
+ parent::__construct('meta', __('Meta'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args);
+ $title = apply_filters('widget_title', empty($instance['title']) ? __('Meta') : $instance['title'], $instance, $this->id_base);
+
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+?>
+ <ul>
+ <?php wp_register(); ?>
+ <li><?php wp_loginout(); ?></li>
+ <li><a href="<?php bloginfo('rss2_url'); ?>" title="<?php echo esc_attr(__('Syndicate this site using RSS 2.0')); ?>"><?php _e('Entries <abbr title="Really Simple Syndication">RSS</abbr>'); ?></a></li>
+ <li><a href="<?php bloginfo('comments_rss2_url'); ?>" title="<?php echo esc_attr(__('The latest comments to all posts in RSS')); ?>"><?php _e('Comments <abbr title="Really Simple Syndication">RSS</abbr>'); ?></a></li>
+ <?php echo apply_filters( 'widget_meta_poweredby', sprintf( '<li><a href="%s" title="%s">%s</a></li>',
+ esc_url( __( 'http://wordpress.org/' ) ),
+ esc_attr__( 'Powered by WordPress, state-of-the-art semantic personal publishing platform.' ),
+ _x( 'WordPress.org', 'meta widget link text' )
+ ) ); ?>
+ <?php wp_meta(); ?>
+ </ul>
+<?php
+ echo $after_widget;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
+ $title = strip_tags($instance['title']);
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></p>
+<?php
+ }
+}
+
+/**
+ * Calendar widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Calendar extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_calendar', 'description' => __( 'A calendar of your site&#8217;s posts') );
+ parent::__construct('calendar', __('Calendar'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args);
+ $title = apply_filters('widget_title', empty($instance['title']) ? '' : $instance['title'], $instance, $this->id_base);
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+ echo '<div id="calendar_wrap">';
+ get_calendar();
+ echo '</div>';
+ echo $after_widget;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '' ) );
+ $title = strip_tags($instance['title']);
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></p>
+<?php
+ }
+}
+
+/**
+ * Text widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Text extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_text', 'description' => __('Arbitrary text or HTML'));
+ $control_ops = array('width' => 400, 'height' => 350);
+ parent::__construct('text', __('Text'), $widget_ops, $control_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args);
+ $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
+ $text = apply_filters( 'widget_text', empty( $instance['text'] ) ? '' : $instance['text'], $instance );
+ echo $before_widget;
+ if ( !empty( $title ) ) { echo $before_title . $title . $after_title; } ?>
+ <div class="textwidget"><?php echo !empty( $instance['filter'] ) ? wpautop( $text ) : $text; ?></div>
+ <?php
+ echo $after_widget;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+ if ( current_user_can('unfiltered_html') )
+ $instance['text'] = $new_instance['text'];
+ else
+ $instance['text'] = stripslashes( wp_filter_post_kses( addslashes($new_instance['text']) ) ); // wp_filter_post_kses() expects slashed
+ $instance['filter'] = isset($new_instance['filter']);
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '', 'text' => '' ) );
+ $title = strip_tags($instance['title']);
+ $text = esc_textarea($instance['text']);
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" /></p>
+
+ <textarea class="widefat" rows="16" cols="20" id="<?php echo $this->get_field_id('text'); ?>" name="<?php echo $this->get_field_name('text'); ?>"><?php echo $text; ?></textarea>
+
+ <p><input id="<?php echo $this->get_field_id('filter'); ?>" name="<?php echo $this->get_field_name('filter'); ?>" type="checkbox" <?php checked(isset($instance['filter']) ? $instance['filter'] : 0); ?> />&nbsp;<label for="<?php echo $this->get_field_id('filter'); ?>"><?php _e('Automatically add paragraphs'); ?></label></p>
+<?php
+ }
+}
+
+/**
+ * Categories widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Categories extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array( 'classname' => 'widget_categories', 'description' => __( "A list or dropdown of categories" ) );
+ parent::__construct('categories', __('Categories'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract( $args );
+
+ $title = apply_filters('widget_title', empty( $instance['title'] ) ? __( 'Categories' ) : $instance['title'], $instance, $this->id_base);
+ $c = ! empty( $instance['count'] ) ? '1' : '0';
+ $h = ! empty( $instance['hierarchical'] ) ? '1' : '0';
+ $d = ! empty( $instance['dropdown'] ) ? '1' : '0';
+
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+
+ $cat_args = array('orderby' => 'name', 'show_count' => $c, 'hierarchical' => $h);
+
+ if ( $d ) {
+ $cat_args['show_option_none'] = __('Select Category');
+ wp_dropdown_categories(apply_filters('widget_categories_dropdown_args', $cat_args));
+?>
+
+<script type='text/javascript'>
+/* <![CDATA[ */
+ var dropdown = document.getElementById("cat");
+ function onCatChange() {
+ if ( dropdown.options[dropdown.selectedIndex].value > 0 ) {
+ location.href = "<?php echo home_url(); ?>/?cat="+dropdown.options[dropdown.selectedIndex].value;
+ }
+ }
+ dropdown.onchange = onCatChange;
+/* ]]> */
+</script>
+
+<?php
+ } else {
+?>
+ <ul>
+<?php
+ $cat_args['title_li'] = '';
+ wp_list_categories(apply_filters('widget_categories_args', $cat_args));
+?>
+ </ul>
+<?php
+ }
+
+ echo $after_widget;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+ $instance['count'] = !empty($new_instance['count']) ? 1 : 0;
+ $instance['hierarchical'] = !empty($new_instance['hierarchical']) ? 1 : 0;
+ $instance['dropdown'] = !empty($new_instance['dropdown']) ? 1 : 0;
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ //Defaults
+ $instance = wp_parse_args( (array) $instance, array( 'title' => '') );
+ $title = esc_attr( $instance['title'] );
+ $count = isset($instance['count']) ? (bool) $instance['count'] :false;
+ $hierarchical = isset( $instance['hierarchical'] ) ? (bool) $instance['hierarchical'] : false;
+ $dropdown = isset( $instance['dropdown'] ) ? (bool) $instance['dropdown'] : false;
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e( 'Title:' ); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" /></p>
+
+ <p><input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('dropdown'); ?>" name="<?php echo $this->get_field_name('dropdown'); ?>"<?php checked( $dropdown ); ?> />
+ <label for="<?php echo $this->get_field_id('dropdown'); ?>"><?php _e( 'Display as dropdown' ); ?></label><br />
+
+ <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('count'); ?>" name="<?php echo $this->get_field_name('count'); ?>"<?php checked( $count ); ?> />
+ <label for="<?php echo $this->get_field_id('count'); ?>"><?php _e( 'Show post counts' ); ?></label><br />
+
+ <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id('hierarchical'); ?>" name="<?php echo $this->get_field_name('hierarchical'); ?>"<?php checked( $hierarchical ); ?> />
+ <label for="<?php echo $this->get_field_id('hierarchical'); ?>"><?php _e( 'Show hierarchy' ); ?></label></p>
+<?php
+ }
+
+}
+
+/**
+ * Recent_Posts widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Recent_Posts extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_recent_entries', 'description' => __( "The most recent posts on your site") );
+ parent::__construct('recent-posts', __('Recent Posts'), $widget_ops);
+ $this->alt_option_name = 'widget_recent_entries';
+
+ add_action( 'save_post', array($this, 'flush_widget_cache') );
+ add_action( 'deleted_post', array($this, 'flush_widget_cache') );
+ add_action( 'switch_theme', array($this, 'flush_widget_cache') );
+ }
+
+ function widget($args, $instance) {
+ $cache = wp_cache_get('widget_recent_posts', 'widget');
+
+ if ( !is_array($cache) )
+ $cache = array();
+
+ if ( ! isset( $args['widget_id'] ) )
+ $args['widget_id'] = $this->id;
+
+ if ( isset( $cache[ $args['widget_id'] ] ) ) {
+ echo $cache[ $args['widget_id'] ];
+ return;
+ }
+
+ ob_start();
+ extract($args);
+
+ $title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Posts' );
+ $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
+ $number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 10;
+ if ( ! $number )
+ $number = 10;
+ $show_date = isset( $instance['show_date'] ) ? $instance['show_date'] : false;
+
+ $r = new WP_Query( apply_filters( 'widget_posts_args', array( 'posts_per_page' => $number, 'no_found_rows' => true, 'post_status' => 'publish', 'ignore_sticky_posts' => true ) ) );
+ if ($r->have_posts()) :
+?>
+ <?php echo $before_widget; ?>
+ <?php if ( $title ) echo $before_title . $title . $after_title; ?>
+ <ul>
+ <?php while ( $r->have_posts() ) : $r->the_post(); ?>
+ <li>
+ <a href="<?php the_permalink() ?>" title="<?php echo esc_attr( get_the_title() ? get_the_title() : get_the_ID() ); ?>"><?php if ( get_the_title() ) the_title(); else the_ID(); ?></a>
+ <?php if ( $show_date ) : ?>
+ <span class="post-date"><?php echo get_the_date(); ?></span>
+ <?php endif; ?>
+ </li>
+ <?php endwhile; ?>
+ </ul>
+ <?php echo $after_widget; ?>
+<?php
+ // Reset the global $the_post as this query will have stomped on it
+ wp_reset_postdata();
+
+ endif;
+
+ $cache[$args['widget_id']] = ob_get_flush();
+ wp_cache_set('widget_recent_posts', $cache, 'widget');
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+ $instance['number'] = (int) $new_instance['number'];
+ $instance['show_date'] = isset( $new_instance['show_date'] ) ? (bool) $new_instance['show_date'] : false;
+ $this->flush_widget_cache();
+
+ $alloptions = wp_cache_get( 'alloptions', 'options' );
+ if ( isset($alloptions['widget_recent_entries']) )
+ delete_option('widget_recent_entries');
+
+ return $instance;
+ }
+
+ function flush_widget_cache() {
+ wp_cache_delete('widget_recent_posts', 'widget');
+ }
+
+ function form( $instance ) {
+ $title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
+ $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
+ $show_date = isset( $instance['show_date'] ) ? (bool) $instance['show_date'] : false;
+?>
+ <p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo $title; ?>" /></p>
+
+ <p><label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of posts to show:' ); ?></label>
+ <input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" type="text" value="<?php echo $number; ?>" size="3" /></p>
+
+ <p><input class="checkbox" type="checkbox" <?php checked( $show_date ); ?> id="<?php echo $this->get_field_id( 'show_date' ); ?>" name="<?php echo $this->get_field_name( 'show_date' ); ?>" />
+ <label for="<?php echo $this->get_field_id( 'show_date' ); ?>"><?php _e( 'Display post date?' ); ?></label></p>
+<?php
+ }
+}
+
+/**
+ * Recent_Comments widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Recent_Comments extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'The most recent comments' ) );
+ parent::__construct('recent-comments', __('Recent Comments'), $widget_ops);
+ $this->alt_option_name = 'widget_recent_comments';
+
+ if ( is_active_widget(false, false, $this->id_base) )
+ add_action( 'wp_head', array($this, 'recent_comments_style') );
+
+ add_action( 'comment_post', array($this, 'flush_widget_cache') );
+ add_action( 'transition_comment_status', array($this, 'flush_widget_cache') );
+ }
+
+ function recent_comments_style() {
+ if ( ! current_theme_supports( 'widgets' ) // Temp hack #14876
+ || ! apply_filters( 'show_recent_comments_widget_style', true, $this->id_base ) )
+ return;
+ ?>
+ <style type="text/css">.recentcomments a{display:inline !important;padding:0 !important;margin:0 !important;}</style>
+<?php
+ }
+
+ function flush_widget_cache() {
+ wp_cache_delete('widget_recent_comments', 'widget');
+ }
+
+ function widget( $args, $instance ) {
+ global $comments, $comment;
+
+ $cache = wp_cache_get('widget_recent_comments', 'widget');
+
+ if ( ! is_array( $cache ) )
+ $cache = array();
+
+ if ( ! isset( $args['widget_id'] ) )
+ $args['widget_id'] = $this->id;
+
+ if ( isset( $cache[ $args['widget_id'] ] ) ) {
+ echo $cache[ $args['widget_id'] ];
+ return;
+ }
+
+ extract($args, EXTR_SKIP);
+ $output = '';
+
+ $title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'Recent Comments' );
+ $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
+ $number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
+ if ( ! $number )
+ $number = 5;
+
+ $comments = get_comments( apply_filters( 'widget_comments_args', array( 'number' => $number, 'status' => 'approve', 'post_status' => 'publish' ) ) );
+ $output .= $before_widget;
+ if ( $title )
+ $output .= $before_title . $title . $after_title;
+
+ $output .= '<ul id="recentcomments">';
+ if ( $comments ) {
+ // Prime cache for associated posts. (Prime post term cache if we need it for permalinks.)
+ $post_ids = array_unique( wp_list_pluck( $comments, 'comment_post_ID' ) );
+ _prime_post_caches( $post_ids, strpos( get_option( 'permalink_structure' ), '%category%' ), false );
+
+ foreach ( (array) $comments as $comment) {
+ $output .= '<li class="recentcomments">' . /* translators: comments widget: 1: comment author, 2: post link */ sprintf(_x('%1$s on %2$s', 'widgets'), get_comment_author_link(), '<a href="' . esc_url( get_comment_link($comment->comment_ID) ) . '">' . get_the_title($comment->comment_post_ID) . '</a>') . '</li>';
+ }
+ }
+ $output .= '</ul>';
+ $output .= $after_widget;
+
+ echo $output;
+ $cache[$args['widget_id']] = $output;
+ wp_cache_set('widget_recent_comments', $cache, 'widget');
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance = $old_instance;
+ $instance['title'] = strip_tags($new_instance['title']);
+ $instance['number'] = absint( $new_instance['number'] );
+ $this->flush_widget_cache();
+
+ $alloptions = wp_cache_get( 'alloptions', 'options' );
+ if ( isset($alloptions['widget_recent_comments']) )
+ delete_option('widget_recent_comments');
+
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
+ $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
+?>
+ <p><label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'Title:' ); ?></label>
+ <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo $title; ?>" /></p>
+
+ <p><label for="<?php echo $this->get_field_id( 'number' ); ?>"><?php _e( 'Number of comments to show:' ); ?></label>
+ <input id="<?php echo $this->get_field_id( 'number' ); ?>" name="<?php echo $this->get_field_name( 'number' ); ?>" type="text" value="<?php echo $number; ?>" size="3" /></p>
+<?php
+ }
+}
+
+/**
+ * RSS widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_RSS extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array( 'description' => __('Entries from any RSS or Atom feed') );
+ $control_ops = array( 'width' => 400, 'height' => 200 );
+ parent::__construct( 'rss', __('RSS'), $widget_ops, $control_ops );
+ }
+
+ function widget($args, $instance) {
+
+ if ( isset($instance['error']) && $instance['error'] )
+ return;
+
+ extract($args, EXTR_SKIP);
+
+ $url = ! empty( $instance['url'] ) ? $instance['url'] : '';
+ while ( stristr($url, 'http') != $url )
+ $url = substr($url, 1);
+
+ if ( empty($url) )
+ return;
+
+ // self-url destruction sequence
+ if ( in_array( untrailingslashit( $url ), array( site_url(), home_url() ) ) )
+ return;
+
+ $rss = fetch_feed($url);
+ $title = $instance['title'];
+ $desc = '';
+ $link = '';
+
+ if ( ! is_wp_error($rss) ) {
+ $desc = esc_attr(strip_tags(@html_entity_decode($rss->get_description(), ENT_QUOTES, get_option('blog_charset'))));
+ if ( empty($title) )
+ $title = esc_html(strip_tags($rss->get_title()));
+ $link = esc_url(strip_tags($rss->get_permalink()));
+ while ( stristr($link, 'http') != $link )
+ $link = substr($link, 1);
+ }
+
+ if ( empty($title) )
+ $title = empty($desc) ? __('Unknown Feed') : $desc;
+
+ $title = apply_filters('widget_title', $title, $instance, $this->id_base);
+ $url = esc_url(strip_tags($url));
+ $icon = includes_url('images/rss.png');
+ if ( $title )
+ $title = "<a class='rsswidget' href='$url' title='" . esc_attr__( 'Syndicate this content' ) ."'><img style='border:0' width='14' height='14' src='$icon' alt='RSS' /></a> <a class='rsswidget' href='$link' title='$desc'>$title</a>";
+
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+ wp_widget_rss_output( $rss, $instance );
+ echo $after_widget;
+
+ if ( ! is_wp_error($rss) )
+ $rss->__destruct();
+ unset($rss);
+ }
+
+ function update($new_instance, $old_instance) {
+ $testurl = ( isset( $new_instance['url'] ) && ( !isset( $old_instance['url'] ) || ( $new_instance['url'] != $old_instance['url'] ) ) );
+ return wp_widget_rss_process( $new_instance, $testurl );
+ }
+
+ function form($instance) {
+
+ if ( empty($instance) )
+ $instance = array( 'title' => '', 'url' => '', 'items' => 10, 'error' => false, 'show_summary' => 0, 'show_author' => 0, 'show_date' => 0 );
+ $instance['number'] = $this->number;
+
+ wp_widget_rss_form( $instance );
+ }
+}
+
+/**
+ * Display the RSS entries in a list.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array|object $rss RSS url.
+ * @param array $args Widget arguments.
+ */
+function wp_widget_rss_output( $rss, $args = array() ) {
+ if ( is_string( $rss ) ) {
+ $rss = fetch_feed($rss);
+ } elseif ( is_array($rss) && isset($rss['url']) ) {
+ $args = $rss;
+ $rss = fetch_feed($rss['url']);
+ } elseif ( !is_object($rss) ) {
+ return;
+ }
+
+ if ( is_wp_error($rss) ) {
+ if ( is_admin() || current_user_can('manage_options') )
+ echo '<p>' . sprintf( __('<strong>RSS Error</strong>: %s'), $rss->get_error_message() ) . '</p>';
+ return;
+ }
+
+ $default_args = array( 'show_author' => 0, 'show_date' => 0, 'show_summary' => 0 );
+ $args = wp_parse_args( $args, $default_args );
+ extract( $args, EXTR_SKIP );
+
+ $items = (int) $items;
+ if ( $items < 1 || 20 < $items )
+ $items = 10;
+ $show_summary = (int) $show_summary;
+ $show_author = (int) $show_author;
+ $show_date = (int) $show_date;
+
+ if ( !$rss->get_item_quantity() ) {
+ echo '<ul><li>' . __( 'An error has occurred, which probably means the feed is down. Try again later.' ) . '</li></ul>';
+ $rss->__destruct();
+ unset($rss);
+ return;
+ }
+
+ echo '<ul>';
+ foreach ( $rss->get_items(0, $items) as $item ) {
+ $link = $item->get_link();
+ while ( stristr($link, 'http') != $link )
+ $link = substr($link, 1);
+ $link = esc_url(strip_tags($link));
+ $title = esc_attr(strip_tags($item->get_title()));
+ if ( empty($title) )
+ $title = __('Untitled');
+
+ $desc = str_replace( array("\n", "\r"), ' ', esc_attr( strip_tags( @html_entity_decode( $item->get_description(), ENT_QUOTES, get_option('blog_charset') ) ) ) );
+ $excerpt = wp_html_excerpt( $desc, 360 );
+
+ // Append ellipsis. Change existing [...] to [&hellip;].
+ if ( '[...]' == substr( $excerpt, -5 ) )
+ $excerpt = substr( $excerpt, 0, -5 ) . '[&hellip;]';
+ elseif ( '[&hellip;]' != substr( $excerpt, -10 ) && $desc != $excerpt )
+ $excerpt .= ' [&hellip;]';
+
+ $excerpt = esc_html( $excerpt );
+
+ if ( $show_summary ) {
+ $summary = "<div class='rssSummary'>$excerpt</div>";
+ } else {
+ $summary = '';
+ }
+
+ $date = '';
+ if ( $show_date ) {
+ $date = $item->get_date( 'U' );
+
+ if ( $date ) {
+ $date = ' <span class="rss-date">' . date_i18n( get_option( 'date_format' ), $date ) . '</span>';
+ }
+ }
+
+ $author = '';
+ if ( $show_author ) {
+ $author = $item->get_author();
+ if ( is_object($author) ) {
+ $author = $author->get_name();
+ $author = ' <cite>' . esc_html( strip_tags( $author ) ) . '</cite>';
+ }
+ }
+
+ if ( $link == '' ) {
+ echo "<li>$title{$date}{$summary}{$author}</li>";
+ } else {
+ echo "<li><a class='rsswidget' href='$link' title='$desc'>$title</a>{$date}{$summary}{$author}</li>";
+ }
+ }
+ echo '</ul>';
+ $rss->__destruct();
+ unset($rss);
+}
+
+/**
+ * Display RSS widget options form.
+ *
+ * The options for what fields are displayed for the RSS form are all booleans
+ * and are as follows: 'url', 'title', 'items', 'show_summary', 'show_author',
+ * 'show_date'.
+ *
+ * @since 2.5.0
+ *
+ * @param array|string $args Values for input fields.
+ * @param array $inputs Override default display options.
+ */
+function wp_widget_rss_form( $args, $inputs = null ) {
+
+ $default_inputs = array( 'url' => true, 'title' => true, 'items' => true, 'show_summary' => true, 'show_author' => true, 'show_date' => true );
+ $inputs = wp_parse_args( $inputs, $default_inputs );
+ extract( $args );
+ extract( $inputs, EXTR_SKIP);
+
+ $number = esc_attr( $number );
+ $title = esc_attr( $title );
+ $url = esc_url( $url );
+ $items = (int) $items;
+ if ( $items < 1 || 20 < $items )
+ $items = 10;
+ $show_summary = (int) $show_summary;
+ $show_author = (int) $show_author;
+ $show_date = (int) $show_date;
+
+ if ( !empty($error) )
+ echo '<p class="widget-error"><strong>' . sprintf( __('RSS Error: %s'), $error) . '</strong></p>';
+
+ if ( $inputs['url'] ) :
+?>
+ <p><label for="rss-url-<?php echo $number; ?>"><?php _e('Enter the RSS feed URL here:'); ?></label>
+ <input class="widefat" id="rss-url-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][url]" type="text" value="<?php echo $url; ?>" /></p>
+<?php endif; if ( $inputs['title'] ) : ?>
+ <p><label for="rss-title-<?php echo $number; ?>"><?php _e('Give the feed a title (optional):'); ?></label>
+ <input class="widefat" id="rss-title-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][title]" type="text" value="<?php echo $title; ?>" /></p>
+<?php endif; if ( $inputs['items'] ) : ?>
+ <p><label for="rss-items-<?php echo $number; ?>"><?php _e('How many items would you like to display?'); ?></label>
+ <select id="rss-items-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][items]">
+<?php
+ for ( $i = 1; $i <= 20; ++$i )
+ echo "<option value='$i' " . selected( $items, $i, false ) . ">$i</option>";
+?>
+ </select></p>
+<?php endif; if ( $inputs['show_summary'] ) : ?>
+ <p><input id="rss-show-summary-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_summary]" type="checkbox" value="1" <?php if ( $show_summary ) echo 'checked="checked"'; ?>/>
+ <label for="rss-show-summary-<?php echo $number; ?>"><?php _e('Display item content?'); ?></label></p>
+<?php endif; if ( $inputs['show_author'] ) : ?>
+ <p><input id="rss-show-author-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_author]" type="checkbox" value="1" <?php if ( $show_author ) echo 'checked="checked"'; ?>/>
+ <label for="rss-show-author-<?php echo $number; ?>"><?php _e('Display item author if available?'); ?></label></p>
+<?php endif; if ( $inputs['show_date'] ) : ?>
+ <p><input id="rss-show-date-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][show_date]" type="checkbox" value="1" <?php if ( $show_date ) echo 'checked="checked"'; ?>/>
+ <label for="rss-show-date-<?php echo $number; ?>"><?php _e('Display item date?'); ?></label></p>
+<?php
+ endif;
+ foreach ( array_keys($default_inputs) as $input ) :
+ if ( 'hidden' === $inputs[$input] ) :
+ $id = str_replace( '_', '-', $input );
+?>
+ <input type="hidden" id="rss-<?php echo $id; ?>-<?php echo $number; ?>" name="widget-rss[<?php echo $number; ?>][<?php echo $input; ?>]" value="<?php echo $$input; ?>" />
+<?php
+ endif;
+ endforeach;
+}
+
+/**
+ * Process RSS feed widget data and optionally retrieve feed items.
+ *
+ * The feed widget can not have more than 20 items or it will reset back to the
+ * default, which is 10.
+ *
+ * The resulting array has the feed title, feed url, feed link (from channel),
+ * feed items, error (if any), and whether to show summary, author, and date.
+ * All respectively in the order of the array elements.
+ *
+ * @since 2.5.0
+ *
+ * @param array $widget_rss RSS widget feed data. Expects unescaped data.
+ * @param bool $check_feed Optional, default is true. Whether to check feed for errors.
+ * @return array
+ */
+function wp_widget_rss_process( $widget_rss, $check_feed = true ) {
+ $items = (int) $widget_rss['items'];
+ if ( $items < 1 || 20 < $items )
+ $items = 10;
+ $url = esc_url_raw(strip_tags( $widget_rss['url'] ));
+ $title = trim(strip_tags( $widget_rss['title'] ));
+ $show_summary = isset($widget_rss['show_summary']) ? (int) $widget_rss['show_summary'] : 0;
+ $show_author = isset($widget_rss['show_author']) ? (int) $widget_rss['show_author'] :0;
+ $show_date = isset($widget_rss['show_date']) ? (int) $widget_rss['show_date'] : 0;
+
+ if ( $check_feed ) {
+ $rss = fetch_feed($url);
+ $error = false;
+ $link = '';
+ if ( is_wp_error($rss) ) {
+ $error = $rss->get_error_message();
+ } else {
+ $link = esc_url(strip_tags($rss->get_permalink()));
+ while ( stristr($link, 'http') != $link )
+ $link = substr($link, 1);
+
+ $rss->__destruct();
+ unset($rss);
+ }
+ }
+
+ return compact( 'title', 'url', 'link', 'items', 'error', 'show_summary', 'show_author', 'show_date' );
+}
+
+/**
+ * Tag cloud widget class
+ *
+ * @since 2.8.0
+ */
+class WP_Widget_Tag_Cloud extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array( 'description' => __( "Your most used tags in cloud format") );
+ parent::__construct('tag_cloud', __('Tag Cloud'), $widget_ops);
+ }
+
+ function widget( $args, $instance ) {
+ extract($args);
+ $current_taxonomy = $this->_get_current_taxonomy($instance);
+ if ( !empty($instance['title']) ) {
+ $title = $instance['title'];
+ } else {
+ if ( 'post_tag' == $current_taxonomy ) {
+ $title = __('Tags');
+ } else {
+ $tax = get_taxonomy($current_taxonomy);
+ $title = $tax->labels->name;
+ }
+ }
+ $title = apply_filters('widget_title', $title, $instance, $this->id_base);
+
+ echo $before_widget;
+ if ( $title )
+ echo $before_title . $title . $after_title;
+ echo '<div class="tagcloud">';
+ wp_tag_cloud( apply_filters('widget_tag_cloud_args', array('taxonomy' => $current_taxonomy) ) );
+ echo "</div>\n";
+ echo $after_widget;
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance['title'] = strip_tags(stripslashes($new_instance['title']));
+ $instance['taxonomy'] = stripslashes($new_instance['taxonomy']);
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $current_taxonomy = $this->_get_current_taxonomy($instance);
+?>
+ <p><label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:') ?></label>
+ <input type="text" class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php if (isset ( $instance['title'])) {echo esc_attr( $instance['title'] );} ?>" /></p>
+ <p><label for="<?php echo $this->get_field_id('taxonomy'); ?>"><?php _e('Taxonomy:') ?></label>
+ <select class="widefat" id="<?php echo $this->get_field_id('taxonomy'); ?>" name="<?php echo $this->get_field_name('taxonomy'); ?>">
+ <?php foreach ( get_taxonomies() as $taxonomy ) :
+ $tax = get_taxonomy($taxonomy);
+ if ( !$tax->show_tagcloud || empty($tax->labels->name) )
+ continue;
+ ?>
+ <option value="<?php echo esc_attr($taxonomy) ?>" <?php selected($taxonomy, $current_taxonomy) ?>><?php echo $tax->labels->name; ?></option>
+ <?php endforeach; ?>
+ </select></p><?php
+ }
+
+ function _get_current_taxonomy($instance) {
+ if ( !empty($instance['taxonomy']) && taxonomy_exists($instance['taxonomy']) )
+ return $instance['taxonomy'];
+
+ return 'post_tag';
+ }
+}
+
+/**
+ * Navigation Menu widget class
+ *
+ * @since 3.0.0
+ */
+ class WP_Nav_Menu_Widget extends WP_Widget {
+
+ function __construct() {
+ $widget_ops = array( 'description' => __('Use this widget to add one of your custom menus as a widget.') );
+ parent::__construct( 'nav_menu', __('Custom Menu'), $widget_ops );
+ }
+
+ function widget($args, $instance) {
+ // Get menu
+ $nav_menu = ! empty( $instance['nav_menu'] ) ? wp_get_nav_menu_object( $instance['nav_menu'] ) : false;
+
+ if ( !$nav_menu )
+ return;
+
+ $instance['title'] = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
+
+ echo $args['before_widget'];
+
+ if ( !empty($instance['title']) )
+ echo $args['before_title'] . $instance['title'] . $args['after_title'];
+
+ wp_nav_menu( array( 'fallback_cb' => '', 'menu' => $nav_menu ) );
+
+ echo $args['after_widget'];
+ }
+
+ function update( $new_instance, $old_instance ) {
+ $instance['title'] = strip_tags( stripslashes($new_instance['title']) );
+ $instance['nav_menu'] = (int) $new_instance['nav_menu'];
+ return $instance;
+ }
+
+ function form( $instance ) {
+ $title = isset( $instance['title'] ) ? $instance['title'] : '';
+ $nav_menu = isset( $instance['nav_menu'] ) ? $instance['nav_menu'] : '';
+
+ // Get menus
+ $menus = get_terms( 'nav_menu', array( 'hide_empty' => false ) );
+
+ // If no menus exists, direct the user to go and create some.
+ if ( !$menus ) {
+ echo '<p>'. sprintf( __('No menus have been created yet. <a href="%s">Create some</a>.'), admin_url('nav-menus.php') ) .'</p>';
+ return;
+ }
+ ?>
+ <p>
+ <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:') ?></label>
+ <input type="text" class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" value="<?php echo $title; ?>" />
+ </p>
+ <p>
+ <label for="<?php echo $this->get_field_id('nav_menu'); ?>"><?php _e('Select Menu:'); ?></label>
+ <select id="<?php echo $this->get_field_id('nav_menu'); ?>" name="<?php echo $this->get_field_name('nav_menu'); ?>">
+ <?php
+ foreach ( $menus as $menu ) {
+ echo '<option value="' . $menu->term_id . '"'
+ . selected( $nav_menu, $menu->term_id, false )
+ . '>'. $menu->name . '</option>';
+ }
+ ?>
+ </select>
+ </p>
+ <?php
+ }
+}
+
+/**
+ * Register all of the default WordPress widgets on startup.
+ *
+ * Calls 'widgets_init' action after all of the WordPress widgets have been
+ * registered.
+ *
+ * @since 2.2.0
+ */
+function wp_widgets_init() {
+ if ( !is_blog_installed() )
+ return;
+
+ register_widget('WP_Widget_Pages');
+
+ register_widget('WP_Widget_Calendar');
+
+ register_widget('WP_Widget_Archives');
+
+ if ( get_option( 'link_manager_enabled' ) )
+ register_widget('WP_Widget_Links');
+
+ register_widget('WP_Widget_Meta');
+
+ register_widget('WP_Widget_Search');
+
+ register_widget('WP_Widget_Text');
+
+ register_widget('WP_Widget_Categories');
+
+ register_widget('WP_Widget_Recent_Posts');
+
+ register_widget('WP_Widget_Recent_Comments');
+
+ register_widget('WP_Widget_RSS');
+
+ register_widget('WP_Widget_Tag_Cloud');
+
+ register_widget('WP_Nav_Menu_Widget');
+
+ do_action('widgets_init');
+}
+
+add_action('init', 'wp_widgets_init', 1);
diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php
new file mode 100644
index 0000000000..d86709a74b
--- /dev/null
+++ b/src/wp-includes/deprecated.php
@@ -0,0 +1,3380 @@
+<?php
+/**
+ * Deprecated functions from past WordPress versions. You shouldn't use these
+ * functions and look for the alternatives instead. The functions will be
+ * removed in a later version.
+ *
+ * @package WordPress
+ * @subpackage Deprecated
+ */
+
+/*
+ * Deprecated functions come here to die.
+ */
+
+/**
+ * Entire Post data.
+ *
+ * @since 0.71
+ * @deprecated 1.5.1
+ * @deprecated Use get_post()
+ * @see get_post()
+ *
+ * @param int $postid
+ * @return array
+ */
+function get_postdata($postid) {
+ _deprecated_function( __FUNCTION__, '1.5.1', 'get_post()' );
+
+ $post = get_post($postid);
+
+ $postdata = array (
+ 'ID' => $post->ID,
+ 'Author_ID' => $post->post_author,
+ 'Date' => $post->post_date,
+ 'Content' => $post->post_content,
+ 'Excerpt' => $post->post_excerpt,
+ 'Title' => $post->post_title,
+ 'Category' => $post->post_category,
+ 'post_status' => $post->post_status,
+ 'comment_status' => $post->comment_status,
+ 'ping_status' => $post->ping_status,
+ 'post_password' => $post->post_password,
+ 'to_ping' => $post->to_ping,
+ 'pinged' => $post->pinged,
+ 'post_type' => $post->post_type,
+ 'post_name' => $post->post_name
+ );
+
+ return $postdata;
+}
+
+/**
+ * Sets up the WordPress Loop.
+ *
+ * @since 1.0.1
+ * @deprecated 1.5
+ * @deprecated Use The Loop - {@link http://codex.wordpress.org/The_Loop Use new WordPress Loop}
+ */
+function start_wp() {
+ global $wp_query;
+
+ _deprecated_function( __FUNCTION__, '1.5', __('new WordPress Loop') );
+
+ // Since the old style loop is being used, advance the query iterator here.
+ $wp_query->next_post();
+
+ setup_postdata( get_post() );
+}
+
+/**
+ * Return or Print Category ID.
+ *
+ * @since 0.71
+ * @deprecated 0.71
+ * @deprecated use get_the_category()
+ * @see get_the_category()
+ *
+ * @param bool $echo
+ * @return null|int
+ */
+function the_category_ID($echo = true) {
+ _deprecated_function( __FUNCTION__, '0.71', 'get_the_category()' );
+
+ // Grab the first cat in the list.
+ $categories = get_the_category();
+ $cat = $categories[0]->term_id;
+
+ if ( $echo )
+ echo $cat;
+
+ return $cat;
+}
+
+/**
+ * Print category with optional text before and after.
+ *
+ * @since 0.71
+ * @deprecated 0.71
+ * @deprecated use get_the_category_by_ID()
+ * @see get_the_category_by_ID()
+ *
+ * @param string $before
+ * @param string $after
+ */
+function the_category_head($before='', $after='') {
+ global $currentcat, $previouscat;
+
+ _deprecated_function( __FUNCTION__, '0.71', 'get_the_category_by_ID()' );
+
+ // Grab the first cat in the list.
+ $categories = get_the_category();
+ $currentcat = $categories[0]->category_id;
+ if ( $currentcat != $previouscat ) {
+ echo $before;
+ echo get_the_category_by_ID($currentcat);
+ echo $after;
+ $previouscat = $currentcat;
+ }
+}
+
+/**
+ * Prints link to the previous post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use previous_post_link()
+ * @see previous_post_link()
+ *
+ * @param string $format
+ * @param string $previous
+ * @param string $title
+ * @param string $in_same_cat
+ * @param int $limitprev
+ * @param string $excluded_categories
+ */
+function previous_post($format='%', $previous='previous post: ', $title='yes', $in_same_cat='no', $limitprev=1, $excluded_categories='') {
+
+ _deprecated_function( __FUNCTION__, '2.0', 'previous_post_link()' );
+
+ if ( empty($in_same_cat) || 'no' == $in_same_cat )
+ $in_same_cat = false;
+ else
+ $in_same_cat = true;
+
+ $post = get_previous_post($in_same_cat, $excluded_categories);
+
+ if ( !$post )
+ return;
+
+ $string = '<a href="'.get_permalink($post->ID).'">'.$previous;
+ if ( 'yes' == $title )
+ $string .= apply_filters('the_title', $post->post_title, $post->ID);
+ $string .= '</a>';
+ $format = str_replace('%', $string, $format);
+ echo $format;
+}
+
+/**
+ * Prints link to the next post.
+ *
+ * @since 0.71
+ * @deprecated 2.0
+ * @deprecated Use next_post_link()
+ * @see next_post_link()
+ *
+ * @param string $format
+ * @param string $next
+ * @param string $title
+ * @param string $in_same_cat
+ * @param int $limitnext
+ * @param string $excluded_categories
+ */
+function next_post($format='%', $next='next post: ', $title='yes', $in_same_cat='no', $limitnext=1, $excluded_categories='') {
+ _deprecated_function( __FUNCTION__, '2.0', 'next_post_link()' );
+
+ if ( empty($in_same_cat) || 'no' == $in_same_cat )
+ $in_same_cat = false;
+ else
+ $in_same_cat = true;
+
+ $post = get_next_post($in_same_cat, $excluded_categories);
+
+ if ( !$post )
+ return;
+
+ $string = '<a href="'.get_permalink($post->ID).'">'.$next;
+ if ( 'yes' == $title )
+ $string .= apply_filters('the_title', $post->post_title, $post->ID);
+ $string .= '</a>';
+ $format = str_replace('%', $string, $format);
+ echo $format;
+}
+
+/**
+ * Whether user can create a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $blog_id Not Used
+ * @param int $category_id Not Used
+ * @return bool
+ */
+function user_can_create_post($user_id, $blog_id = 1, $category_id = 'None') {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ $author_data = get_userdata($user_id);
+ return ($author_data->user_level > 1);
+}
+
+/**
+ * Whether user can create a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $blog_id Not Used
+ * @param int $category_id Not Used
+ * @return bool
+ */
+function user_can_create_draft($user_id, $blog_id = 1, $category_id = 'None') {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ $author_data = get_userdata($user_id);
+ return ($author_data->user_level >= 1);
+}
+
+/**
+ * Whether user can edit a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $post_id
+ * @param int $blog_id Not Used
+ * @return bool
+ */
+function user_can_edit_post($user_id, $post_id, $blog_id = 1) {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ $author_data = get_userdata($user_id);
+ $post = get_post($post_id);
+ $post_author_data = get_userdata($post->post_author);
+
+ if ( (($user_id == $post_author_data->ID) && !($post->post_status == 'publish' && $author_data->user_level < 2))
+ || ($author_data->user_level > $post_author_data->user_level)
+ || ($author_data->user_level >= 10) ) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Whether user can delete a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $post_id
+ * @param int $blog_id Not Used
+ * @return bool
+ */
+function user_can_delete_post($user_id, $post_id, $blog_id = 1) {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ // right now if one can edit, one can delete
+ return user_can_edit_post($user_id, $post_id, $blog_id);
+}
+
+/**
+ * Whether user can set new posts' dates.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $blog_id Not Used
+ * @param int $category_id Not Used
+ * @return bool
+ */
+function user_can_set_post_date($user_id, $blog_id = 1, $category_id = 'None') {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ $author_data = get_userdata($user_id);
+ return (($author_data->user_level > 4) && user_can_create_post($user_id, $blog_id, $category_id));
+}
+
+/**
+ * Whether user can delete a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $post_id
+ * @param int $blog_id Not Used
+ * @return bool returns true if $user_id can edit $post_id's date
+ */
+function user_can_edit_post_date($user_id, $post_id, $blog_id = 1) {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ $author_data = get_userdata($user_id);
+ return (($author_data->user_level > 4) && user_can_edit_post($user_id, $post_id, $blog_id));
+}
+
+/**
+ * Whether user can delete a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $post_id
+ * @param int $blog_id Not Used
+ * @return bool returns true if $user_id can edit $post_id's comments
+ */
+function user_can_edit_post_comments($user_id, $post_id, $blog_id = 1) {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ // right now if one can edit a post, one can edit comments made on it
+ return user_can_edit_post($user_id, $post_id, $blog_id);
+}
+
+/**
+ * Whether user can delete a post.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $post_id
+ * @param int $blog_id Not Used
+ * @return bool returns true if $user_id can delete $post_id's comments
+ */
+function user_can_delete_post_comments($user_id, $post_id, $blog_id = 1) {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ // right now if one can edit comments, one can delete comments
+ return user_can_edit_post_comments($user_id, $post_id, $blog_id);
+}
+
+/**
+ * Can user can edit other user.
+ *
+ * @since 1.5
+ * @deprecated 2.0
+ * @deprecated Use current_user_can()
+ * @see current_user_can()
+ *
+ * @param int $user_id
+ * @param int $other_user
+ * @return bool
+ */
+function user_can_edit_user($user_id, $other_user) {
+ _deprecated_function( __FUNCTION__, '2.0', 'current_user_can()' );
+
+ $user = get_userdata($user_id);
+ $other = get_userdata($other_user);
+ if ( $user->user_level > $other->user_level || $user->user_level > 8 || $user->ID == $other->ID )
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Gets the links associated with category $cat_name.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use get_bookmarks()
+ * @see get_bookmarks()
+ *
+ * @param string $cat_name Optional. The category name to use. If no match is found uses all.
+ * @param string $before Optional. The html to output before the link.
+ * @param string $after Optional. The html to output after the link.
+ * @param string $between Optional. The html to output between the link/image and its description. Not used if no image or $show_images is true.
+ * @param bool $show_images Optional. Whether to show images (if defined).
+ * @param string $orderby Optional. The order to output the links. E.g. 'id', 'name', 'url', 'description' or 'rating'. Or maybe owner.
+ * If you start the name with an underscore the order will be reversed. You can also specify 'rand' as the order which will return links in a
+ * random order.
+ * @param bool $show_description Optional. Whether to show the description if show_images=false/not defined.
+ * @param bool $show_rating Optional. Show rating stars/chars.
+ * @param int $limit Optional. Limit to X entries. If not specified, all entries are shown.
+ * @param int $show_updated Optional. Whether to show last updated timestamp
+ */
+function get_linksbyname($cat_name = "noname", $before = '', $after = '<br />', $between = " ", $show_images = true, $orderby = 'id',
+ $show_description = true, $show_rating = false,
+ $limit = -1, $show_updated = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmarks()' );
+
+ $cat_id = -1;
+ $cat = get_term_by('name', $cat_name, 'link_category');
+ if ( $cat )
+ $cat_id = $cat->term_id;
+
+ get_links($cat_id, $before, $after, $between, $show_images, $orderby, $show_description, $show_rating, $limit, $show_updated);
+}
+
+/**
+ * Gets the links associated with the named category.
+ *
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use wp_list_bookmarks()
+ * @see wp_list_bookmarks()
+ *
+ * @param string $category The category to use.
+ * @param string $args
+ * @return bool|null
+ */
+function wp_get_linksbyname($category, $args = '') {
+ _deprecated_function(__FUNCTION__, '2.1', 'wp_list_bookmarks()');
+
+ $defaults = array(
+ 'after' => '<br />',
+ 'before' => '',
+ 'categorize' => 0,
+ 'category_after' => '',
+ 'category_before' => '',
+ 'category_name' => $category,
+ 'show_description' => 1,
+ 'title_li' => '',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ return wp_list_bookmarks($r);
+}
+
+/**
+ * Gets an array of link objects associated with category $cat_name.
+ *
+ * <code>
+ * $links = get_linkobjectsbyname('fred');
+ * foreach ($links as $link) {
+ * echo '<li>'.$link->link_name.'</li>';
+ * }
+ * </code>
+ *
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use get_bookmarks()
+ * @see get_bookmarks()
+ *
+ * @param string $cat_name The category name to use. If no match is found uses all.
+ * @param string $orderby The order to output the links. E.g. 'id', 'name', 'url', 'description', or 'rating'.
+ * Or maybe owner. If you start the name with an underscore the order will be reversed. You can also
+ * specify 'rand' as the order which will return links in a random order.
+ * @param int $limit Limit to X entries. If not specified, all entries are shown.
+ * @return unknown
+ */
+function get_linkobjectsbyname($cat_name = "noname" , $orderby = 'name', $limit = -1) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmarks()' );
+
+ $cat_id = -1;
+ $cat = get_term_by('name', $cat_name, 'link_category');
+ if ( $cat )
+ $cat_id = $cat->term_id;
+
+ return get_linkobjects($cat_id, $orderby, $limit);
+}
+
+/**
+ * Gets an array of link objects associated with category n.
+ *
+ * Usage:
+ * <code>
+ * $links = get_linkobjects(1);
+ * if ($links) {
+ * foreach ($links as $link) {
+ * echo '<li>'.$link->link_name.'<br />'.$link->link_description.'</li>';
+ * }
+ * }
+ * </code>
+ *
+ * Fields are:
+ * <ol>
+ * <li>link_id</li>
+ * <li>link_url</li>
+ * <li>link_name</li>
+ * <li>link_image</li>
+ * <li>link_target</li>
+ * <li>link_category</li>
+ * <li>link_description</li>
+ * <li>link_visible</li>
+ * <li>link_owner</li>
+ * <li>link_rating</li>
+ * <li>link_updated</li>
+ * <li>link_rel</li>
+ * <li>link_notes</li>
+ * </ol>
+ *
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use get_bookmarks()
+ * @see get_bookmarks()
+ *
+ * @param int $category The category to use. If no category supplied uses all
+ * @param string $orderby the order to output the links. E.g. 'id', 'name', 'url',
+ * 'description', or 'rating'. Or maybe owner. If you start the name with an
+ * underscore the order will be reversed. You can also specify 'rand' as the
+ * order which will return links in a random order.
+ * @param int $limit Limit to X entries. If not specified, all entries are shown.
+ * @return unknown
+ */
+function get_linkobjects($category = 0, $orderby = 'name', $limit = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmarks()' );
+
+ $links = get_bookmarks( array( 'category' => $category, 'orderby' => $orderby, 'limit' => $limit ) ) ;
+
+ $links_array = array();
+ foreach ($links as $link)
+ $links_array[] = $link;
+
+ return $links_array;
+}
+
+/**
+ * Gets the links associated with category 'cat_name' and display rating stars/chars.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use get_bookmarks()
+ * @see get_bookmarks()
+ *
+ * @param string $cat_name The category name to use. If no match is found uses all
+ * @param string $before The html to output before the link
+ * @param string $after The html to output after the link
+ * @param string $between The html to output between the link/image and its description. Not used if no image or show_images is true
+ * @param bool $show_images Whether to show images (if defined).
+ * @param string $orderby the order to output the links. E.g. 'id', 'name', 'url',
+ * 'description', or 'rating'. Or maybe owner. If you start the name with an
+ * underscore the order will be reversed. You can also specify 'rand' as the
+ * order which will return links in a random order.
+ * @param bool $show_description Whether to show the description if show_images=false/not defined
+ * @param int $limit Limit to X entries. If not specified, all entries are shown.
+ * @param int $show_updated Whether to show last updated timestamp
+ */
+function get_linksbyname_withrating($cat_name = "noname", $before = '', $after = '<br />', $between = " ",
+ $show_images = true, $orderby = 'id', $show_description = true, $limit = -1, $show_updated = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmarks()' );
+
+ get_linksbyname($cat_name, $before, $after, $between, $show_images, $orderby, $show_description, true, $limit, $show_updated);
+}
+
+/**
+ * Gets the links associated with category n and display rating stars/chars.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use get_bookmarks()
+ * @see get_bookmarks()
+ *
+ * @param int $category The category to use. If no category supplied uses all
+ * @param string $before The html to output before the link
+ * @param string $after The html to output after the link
+ * @param string $between The html to output between the link/image and its description. Not used if no image or show_images == true
+ * @param bool $show_images Whether to show images (if defined).
+ * @param string $orderby The order to output the links. E.g. 'id', 'name', 'url',
+ * 'description', or 'rating'. Or maybe owner. If you start the name with an
+ * underscore the order will be reversed. You can also specify 'rand' as the
+ * order which will return links in a random order.
+ * @param bool $show_description Whether to show the description if show_images=false/not defined.
+ * @param string $limit Limit to X entries. If not specified, all entries are shown.
+ * @param int $show_updated Whether to show last updated timestamp
+ */
+function get_links_withrating($category = -1, $before = '', $after = '<br />', $between = " ", $show_images = true,
+ $orderby = 'id', $show_description = true, $limit = -1, $show_updated = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmarks()' );
+
+ get_links($category, $before, $after, $between, $show_images, $orderby, $show_description, true, $limit, $show_updated);
+}
+
+/**
+ * Gets the auto_toggle setting.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated No alternative function available
+ *
+ * @param int $id The category to get. If no category supplied uses 0
+ * @return int Only returns 0.
+ */
+function get_autotoggle($id = 0) {
+ _deprecated_function( __FUNCTION__, '2.1' );
+ return 0;
+}
+
+/**
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use wp_list_categories()
+ * @see wp_list_categories()
+ *
+ * @param int $optionall
+ * @param string $all
+ * @param string $sort_column
+ * @param string $sort_order
+ * @param string $file
+ * @param bool $list
+ * @param int $optiondates
+ * @param int $optioncount
+ * @param int $hide_empty
+ * @param int $use_desc_for_title
+ * @param bool $children
+ * @param int $child_of
+ * @param int $categories
+ * @param int $recurse
+ * @param string $feed
+ * @param string $feed_image
+ * @param string $exclude
+ * @param bool $hierarchical
+ * @return unknown
+ */
+function list_cats($optionall = 1, $all = 'All', $sort_column = 'ID', $sort_order = 'asc', $file = '', $list = true, $optiondates = 0,
+ $optioncount = 0, $hide_empty = 1, $use_desc_for_title = 1, $children=false, $child_of=0, $categories=0,
+ $recurse=0, $feed = '', $feed_image = '', $exclude = '', $hierarchical=false) {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_list_categories()' );
+
+ $query = compact('optionall', 'all', 'sort_column', 'sort_order', 'file', 'list', 'optiondates', 'optioncount', 'hide_empty', 'use_desc_for_title', 'children',
+ 'child_of', 'categories', 'recurse', 'feed', 'feed_image', 'exclude', 'hierarchical');
+ return wp_list_cats($query);
+}
+
+/**
+ * @since 1.2
+ * @deprecated 2.1
+ * @deprecated Use wp_list_categories()
+ * @see wp_list_categories()
+ *
+ * @param string|array $args
+ * @return unknown
+ */
+function wp_list_cats($args = '') {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_list_categories()' );
+
+ $r = wp_parse_args( $args );
+
+ // Map to new names.
+ if ( isset($r['optionall']) && isset($r['all']))
+ $r['show_option_all'] = $r['all'];
+ if ( isset($r['sort_column']) )
+ $r['orderby'] = $r['sort_column'];
+ if ( isset($r['sort_order']) )
+ $r['order'] = $r['sort_order'];
+ if ( isset($r['optiondates']) )
+ $r['show_last_update'] = $r['optiondates'];
+ if ( isset($r['optioncount']) )
+ $r['show_count'] = $r['optioncount'];
+ if ( isset($r['list']) )
+ $r['style'] = $r['list'] ? 'list' : 'break';
+ $r['title_li'] = '';
+
+ return wp_list_categories($r);
+}
+
+/**
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use wp_dropdown_categories()
+ * @see wp_dropdown_categories()
+ *
+ * @param int $optionall
+ * @param string $all
+ * @param string $orderby
+ * @param string $order
+ * @param int $show_last_update
+ * @param int $show_count
+ * @param int $hide_empty
+ * @param bool $optionnone
+ * @param int $selected
+ * @param int $exclude
+ * @return unknown
+ */
+function dropdown_cats($optionall = 1, $all = 'All', $orderby = 'ID', $order = 'asc',
+ $show_last_update = 0, $show_count = 0, $hide_empty = 1, $optionnone = false,
+ $selected = 0, $exclude = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_dropdown_categories()' );
+
+ $show_option_all = '';
+ if ( $optionall )
+ $show_option_all = $all;
+
+ $show_option_none = '';
+ if ( $optionnone )
+ $show_option_none = __('None');
+
+ $vars = compact('show_option_all', 'show_option_none', 'orderby', 'order',
+ 'show_last_update', 'show_count', 'hide_empty', 'selected', 'exclude');
+ $query = add_query_arg($vars, '');
+ return wp_dropdown_categories($query);
+}
+
+/**
+ * @since 1.2
+ * @deprecated 2.1
+ * @deprecated Use wp_list_authors()
+ * @see wp_list_authors()
+ *
+ * @param bool $optioncount
+ * @param bool $exclude_admin
+ * @param bool $show_fullname
+ * @param bool $hide_empty
+ * @param string $feed
+ * @param string $feed_image
+ * @return unknown
+ */
+function list_authors($optioncount = false, $exclude_admin = true, $show_fullname = false, $hide_empty = true, $feed = '', $feed_image = '') {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_list_authors()' );
+
+ $args = compact('optioncount', 'exclude_admin', 'show_fullname', 'hide_empty', 'feed', 'feed_image');
+ return wp_list_authors($args);
+}
+
+/**
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use wp_get_post_categories()
+ * @see wp_get_post_categories()
+ *
+ * @param int $blogid Not Used
+ * @param int $post_ID
+ * @return unknown
+ */
+function wp_get_post_cats($blogid = '1', $post_ID = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_get_post_categories()' );
+ return wp_get_post_categories($post_ID);
+}
+
+/**
+ * Sets the categories that the post id belongs to.
+ *
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use wp_set_post_categories()
+ * @see wp_set_post_categories()
+ *
+ * @param int $blogid Not used
+ * @param int $post_ID
+ * @param array $post_categories
+ * @return unknown
+ */
+function wp_set_post_cats($blogid = '1', $post_ID = 0, $post_categories = array()) {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_set_post_categories()' );
+ return wp_set_post_categories($post_ID, $post_categories);
+}
+
+/**
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use wp_get_archives()
+ * @see wp_get_archives()
+ *
+ * @param string $type
+ * @param string $limit
+ * @param string $format
+ * @param string $before
+ * @param string $after
+ * @param bool $show_post_count
+ * @return unknown
+ */
+function get_archives($type='', $limit='', $format='html', $before = '', $after = '', $show_post_count = false) {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_get_archives()' );
+ $args = compact('type', 'limit', 'format', 'before', 'after', 'show_post_count');
+ return wp_get_archives($args);
+}
+
+/**
+ * Returns or Prints link to the author's posts.
+ *
+ * @since 1.2
+ * @deprecated 2.1
+ * @deprecated Use get_author_posts_url()
+ * @see get_author_posts_url()
+ *
+ * @param bool $echo
+ * @param int $author_id
+ * @param string $author_nicename Optional.
+ * @return string|null
+ */
+function get_author_link($echo, $author_id, $author_nicename = '') {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_author_posts_url()' );
+
+ $link = get_author_posts_url($author_id, $author_nicename);
+
+ if ( $echo )
+ echo $link;
+ return $link;
+}
+
+/**
+ * Print list of pages based on arguments.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use wp_link_pages()
+ * @see wp_link_pages()
+ *
+ * @param string $before
+ * @param string $after
+ * @param string $next_or_number
+ * @param string $nextpagelink
+ * @param string $previouspagelink
+ * @param string $pagelink
+ * @param string $more_file
+ * @return string
+ */
+function link_pages($before='<br />', $after='<br />', $next_or_number='number', $nextpagelink='next page', $previouspagelink='previous page',
+ $pagelink='%', $more_file='') {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_link_pages()' );
+
+ $args = compact('before', 'after', 'next_or_number', 'nextpagelink', 'previouspagelink', 'pagelink', 'more_file');
+ return wp_link_pages($args);
+}
+
+/**
+ * Get value based on option.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use get_option()
+ * @see get_option()
+ *
+ * @param string $option
+ * @return string
+ */
+function get_settings($option) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_option()' );
+
+ return get_option($option);
+}
+
+/**
+ * Print the permalink of the current post in the loop.
+ *
+ * @since 0.71
+ * @deprecated 1.2
+ * @deprecated Use the_permalink()
+ * @see the_permalink()
+ */
+function permalink_link() {
+ _deprecated_function( __FUNCTION__, '1.2', 'the_permalink()' );
+ the_permalink();
+}
+
+/**
+ * Print the permalink to the RSS feed.
+ *
+ * @since 0.71
+ * @deprecated 2.3
+ * @deprecated Use the_permalink_rss()
+ * @see the_permalink_rss()
+ *
+ * @param string $deprecated
+ */
+function permalink_single_rss($deprecated = '') {
+ _deprecated_function( __FUNCTION__, '2.3', 'the_permalink_rss()' );
+ the_permalink_rss();
+}
+
+/**
+ * Gets the links associated with category.
+ *
+ * @see get_links() for argument information that can be used in $args
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use wp_list_bookmarks()
+ * @see wp_list_bookmarks()
+ *
+ * @param string $args a query string
+ * @return null|string
+ */
+function wp_get_links($args = '') {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_list_bookmarks()' );
+
+ if ( strpos( $args, '=' ) === false ) {
+ $cat_id = $args;
+ $args = add_query_arg( 'category', $cat_id, $args );
+ }
+
+ $defaults = array(
+ 'after' => '<br />',
+ 'before' => '',
+ 'between' => ' ',
+ 'categorize' => 0,
+ 'category' => '',
+ 'echo' => true,
+ 'limit' => -1,
+ 'orderby' => 'name',
+ 'show_description' => true,
+ 'show_images' => true,
+ 'show_rating' => false,
+ 'show_updated' => true,
+ 'title_li' => '',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ return wp_list_bookmarks($r);
+}
+
+/**
+ * Gets the links associated with category by id.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use get_bookmarks()
+ * @see get_bookmarks()
+ *
+ * @param int $category The category to use. If no category supplied uses all
+ * @param string $before the html to output before the link
+ * @param string $after the html to output after the link
+ * @param string $between the html to output between the link/image and its description.
+ * Not used if no image or show_images == true
+ * @param bool $show_images whether to show images (if defined).
+ * @param string $orderby the order to output the links. E.g. 'id', 'name', 'url',
+ * 'description', or 'rating'. Or maybe owner. If you start the name with an
+ * underscore the order will be reversed. You can also specify 'rand' as the order
+ * which will return links in a random order.
+ * @param bool $show_description whether to show the description if show_images=false/not defined.
+ * @param bool $show_rating show rating stars/chars
+ * @param int $limit Limit to X entries. If not specified, all entries are shown.
+ * @param int $show_updated whether to show last updated timestamp
+ * @param bool $echo whether to echo the results, or return them instead
+ * @return null|string
+ */
+function get_links($category = -1, $before = '', $after = '<br />', $between = ' ', $show_images = true, $orderby = 'name',
+ $show_description = true, $show_rating = false, $limit = -1, $show_updated = 1, $echo = true) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmarks()' );
+
+ $order = 'ASC';
+ if ( substr($orderby, 0, 1) == '_' ) {
+ $order = 'DESC';
+ $orderby = substr($orderby, 1);
+ }
+
+ if ( $category == -1 ) //get_bookmarks uses '' to signify all categories
+ $category = '';
+
+ $results = get_bookmarks(array('category' => $category, 'orderby' => $orderby, 'order' => $order, 'show_updated' => $show_updated, 'limit' => $limit));
+
+ if ( !$results )
+ return;
+
+ $output = '';
+
+ foreach ( (array) $results as $row ) {
+ if ( !isset($row->recently_updated) )
+ $row->recently_updated = false;
+ $output .= $before;
+ if ( $show_updated && $row->recently_updated )
+ $output .= get_option('links_recently_updated_prepend');
+ $the_link = '#';
+ if ( !empty($row->link_url) )
+ $the_link = esc_url($row->link_url);
+ $rel = $row->link_rel;
+ if ( '' != $rel )
+ $rel = ' rel="' . $rel . '"';
+
+ $desc = esc_attr(sanitize_bookmark_field('link_description', $row->link_description, $row->link_id, 'display'));
+ $name = esc_attr(sanitize_bookmark_field('link_name', $row->link_name, $row->link_id, 'display'));
+ $title = $desc;
+
+ if ( $show_updated )
+ if (substr($row->link_updated_f, 0, 2) != '00')
+ $title .= ' ('.__('Last updated') . ' ' . date(get_option('links_updated_date_format'), $row->link_updated_f + (get_option('gmt_offset') * HOUR_IN_SECONDS)) . ')';
+
+ if ( '' != $title )
+ $title = ' title="' . $title . '"';
+
+ $alt = ' alt="' . $name . '"';
+
+ $target = $row->link_target;
+ if ( '' != $target )
+ $target = ' target="' . $target . '"';
+
+ $output .= '<a href="' . $the_link . '"' . $rel . $title . $target. '>';
+
+ if ( $row->link_image != null && $show_images ) {
+ if ( strpos($row->link_image, 'http') !== false )
+ $output .= "<img src=\"$row->link_image\" $alt $title />";
+ else // If it's a relative path
+ $output .= "<img src=\"" . get_option('siteurl') . "$row->link_image\" $alt $title />";
+ } else {
+ $output .= $name;
+ }
+
+ $output .= '</a>';
+
+ if ( $show_updated && $row->recently_updated )
+ $output .= get_option('links_recently_updated_append');
+
+ if ( $show_description && '' != $desc )
+ $output .= $between . $desc;
+
+ if ($show_rating) {
+ $output .= $between . get_linkrating($row);
+ }
+
+ $output .= "$after\n";
+ } // end while
+
+ if ( !$echo )
+ return $output;
+ echo $output;
+}
+
+/**
+ * Output entire list of links by category.
+ *
+ * Output a list of all links, listed by category, using the settings in
+ * $wpdb->linkcategories and output it as a nested HTML unordered list.
+ *
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use wp_list_bookmarks()
+ * @see wp_list_bookmarks()
+ *
+ * @param string $order Sort link categories by 'name' or 'id'
+ */
+function get_links_list($order = 'name') {
+ _deprecated_function( __FUNCTION__, '2.1', 'wp_list_bookmarks()' );
+
+ $order = strtolower($order);
+
+ // Handle link category sorting
+ $direction = 'ASC';
+ if ( '_' == substr($order,0,1) ) {
+ $direction = 'DESC';
+ $order = substr($order,1);
+ }
+
+ if ( !isset($direction) )
+ $direction = '';
+
+ $cats = get_categories(array('type' => 'link', 'orderby' => $order, 'order' => $direction, 'hierarchical' => 0));
+
+ // Display each category
+ if ( $cats ) {
+ foreach ( (array) $cats as $cat ) {
+ // Handle each category.
+
+ // Display the category name
+ echo ' <li id="linkcat-' . $cat->term_id . '" class="linkcat"><h2>' . apply_filters('link_category', $cat->name ) . "</h2>\n\t<ul>\n";
+ // Call get_links() with all the appropriate params
+ get_links($cat->term_id, '<li>', "</li>", "\n", true, 'name', false);
+
+ // Close the last category
+ echo "\n\t</ul>\n</li>\n";
+ }
+ }
+}
+
+/**
+ * Show the link to the links popup and the number of links.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated {@internal Use function instead is unknown}}
+ *
+ * @param string $text the text of the link
+ * @param int $width the width of the popup window
+ * @param int $height the height of the popup window
+ * @param string $file the page to open in the popup window
+ * @param bool $count the number of links in the db
+ */
+function links_popup_script($text = 'Links', $width=400, $height=400, $file='links.all.php', $count = true) {
+ _deprecated_function( __FUNCTION__, '2.1' );
+}
+
+/**
+ * @since 1.0.1
+ * @deprecated 2.1
+ * @deprecated Use sanitize_bookmark_field()
+ * @see sanitize_bookmark_field()
+ *
+ * @param object $link
+ * @return unknown
+ */
+function get_linkrating($link) {
+ _deprecated_function( __FUNCTION__, '2.1', 'sanitize_bookmark_field()' );
+ return sanitize_bookmark_field('link_rating', $link->link_rating, $link->link_id, 'display');
+}
+
+/**
+ * Gets the name of category by id.
+ *
+ * @since 0.71
+ * @deprecated 2.1
+ * @deprecated Use get_category()
+ * @see get_category()
+ *
+ * @param int $id The category to get. If no category supplied uses 0
+ * @return string
+ */
+function get_linkcatname($id = 0) {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_category()' );
+
+ $id = (int) $id;
+
+ if ( empty($id) )
+ return '';
+
+ $cats = wp_get_link_cats($id);
+
+ if ( empty($cats) || ! is_array($cats) )
+ return '';
+
+ $cat_id = (int) $cats[0]; // Take the first cat.
+
+ $cat = get_category($cat_id);
+ return $cat->name;
+}
+
+/**
+ * Print RSS comment feed link.
+ *
+ * @since 1.0.1
+ * @deprecated 2.5
+ * @deprecated Use post_comments_feed_link()
+ * @see post_comments_feed_link()
+ *
+ * @param string $link_text
+ */
+function comments_rss_link($link_text = 'Comments RSS') {
+ _deprecated_function( __FUNCTION__, '2.5', 'post_comments_feed_link()' );
+ post_comments_feed_link($link_text);
+}
+
+/**
+ * Print/Return link to category RSS2 feed.
+ *
+ * @since 1.2
+ * @deprecated 2.5
+ * @deprecated Use get_category_feed_link()
+ * @see get_category_feed_link()
+ *
+ * @param bool $echo
+ * @param int $cat_ID
+ * @return string|null
+ */
+function get_category_rss_link($echo = false, $cat_ID = 1) {
+ _deprecated_function( __FUNCTION__, '2.5', 'get_category_feed_link()' );
+
+ $link = get_category_feed_link($cat_ID, 'rss2');
+
+ if ( $echo )
+ echo $link;
+ return $link;
+}
+
+/**
+ * Print/Return link to author RSS feed.
+ *
+ * @since 1.2
+ * @deprecated 2.5
+ * @deprecated Use get_author_feed_link()
+ * @see get_author_feed_link()
+ *
+ * @param bool $echo
+ * @param int $author_id
+ * @return string|null
+ */
+function get_author_rss_link($echo = false, $author_id = 1) {
+ _deprecated_function( __FUNCTION__, '2.5', 'get_author_feed_link()' );
+
+ $link = get_author_feed_link($author_id);
+ if ( $echo )
+ echo $link;
+ return $link;
+}
+
+/**
+ * Return link to the post RSS feed.
+ *
+ * @since 1.5
+ * @deprecated 2.2
+ * @deprecated Use get_post_comments_feed_link()
+ * @see get_post_comments_feed_link()
+ *
+ * @return string
+ */
+function comments_rss() {
+ _deprecated_function( __FUNCTION__, '2.2', 'get_post_comments_feed_link()' );
+ return esc_url( get_post_comments_feed_link() );
+}
+
+/**
+ * An alias of wp_create_user().
+ *
+ * @since 2.0
+ * @deprecated 2.0
+ * @deprecated Use wp_create_user()
+ * @see wp_create_user()
+ *
+ * @param string $username The user's username.
+ * @param string $password The user's password.
+ * @param string $email The user's email (optional).
+ * @return int The new user's ID.
+ */
+function create_user($username, $password, $email) {
+ _deprecated_function( __FUNCTION__, '2.0', 'wp_create_user()' );
+ return wp_create_user($username, $password, $email);
+}
+
+/**
+ * Unused function.
+ *
+ * @deprecated 2.5
+*/
+function gzip_compression() {
+ _deprecated_function( __FUNCTION__, '2.5' );
+ return false;
+}
+
+/**
+ * Retrieve an array of comment data about comment $comment_ID.
+ *
+ * @since 0.71
+ * @deprecated 2.7
+ * @deprecated Use get_comment()
+ * @see get_comment()
+ *
+ * @param int $comment_ID The ID of the comment
+ * @param int $no_cache Whether to use the cache (cast to bool)
+ * @param bool $include_unapproved Whether to include unapproved comments
+ * @return array The comment data
+ */
+function get_commentdata( $comment_ID, $no_cache = 0, $include_unapproved = false ) {
+ _deprecated_function( __FUNCTION__, '2.7', 'get_comment()' );
+ return get_comment($comment_ID, ARRAY_A);
+}
+
+/**
+ * Retrieve the category name by the category ID.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use get_cat_name()
+ * @see get_cat_name()
+ *
+ * @param int $cat_ID Category ID
+ * @return string category name
+ */
+function get_catname( $cat_ID ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_cat_name()' );
+ return get_cat_name( $cat_ID );
+}
+
+/**
+ * Retrieve category children list separated before and after the term IDs.
+ *
+ * @since 1.2.0
+ * @deprecated 2.8
+ * @deprecated Use get_term_children()
+ * @see get_term_children()
+ *
+ * @param int $id Category ID to retrieve children.
+ * @param string $before Optional. Prepend before category term ID.
+ * @param string $after Optional, default is empty string. Append after category term ID.
+ * @param array $visited Optional. Category Term IDs that have already been added.
+ * @return string
+ */
+function get_category_children( $id, $before = '/', $after = '', $visited = array() ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_term_children()' );
+ if ( 0 == $id )
+ return '';
+
+ $chain = '';
+ /** TODO: consult hierarchy */
+ $cat_ids = get_all_category_ids();
+ foreach ( (array) $cat_ids as $cat_id ) {
+ if ( $cat_id == $id )
+ continue;
+
+ $category = get_category( $cat_id );
+ if ( is_wp_error( $category ) )
+ return $category;
+ if ( $category->parent == $id && !in_array( $category->term_id, $visited ) ) {
+ $visited[] = $category->term_id;
+ $chain .= $before.$category->term_id.$after;
+ $chain .= get_category_children( $category->term_id, $before, $after );
+ }
+ }
+ return $chain;
+}
+
+/**
+ * Retrieve the description of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('description')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's description.
+ */
+function get_the_author_description() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'description\')' );
+ return get_the_author_meta('description');
+}
+
+/**
+ * Display the description of the author of the current post.
+ *
+ * @since 1.0.0
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('description')
+ * @see the_author_meta()
+ */
+function the_author_description() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'description\')' );
+ the_author_meta('description');
+}
+
+/**
+ * Retrieve the login name of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('login')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's login name (username).
+ */
+function get_the_author_login() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'login\')' );
+ return get_the_author_meta('login');
+}
+
+/**
+ * Display the login name of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('login')
+ * @see the_author_meta()
+ */
+function the_author_login() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'login\')' );
+ the_author_meta('login');
+}
+
+/**
+ * Retrieve the first name of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('first_name')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's first name.
+ */
+function get_the_author_firstname() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'first_name\')' );
+ return get_the_author_meta('first_name');
+}
+
+/**
+ * Display the first name of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('first_name')
+ * @see the_author_meta()
+ */
+function the_author_firstname() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'first_name\')' );
+ the_author_meta('first_name');
+}
+
+/**
+ * Retrieve the last name of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('last_name')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's last name.
+ */
+function get_the_author_lastname() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'last_name\')' );
+ return get_the_author_meta('last_name');
+}
+
+/**
+ * Display the last name of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('last_name')
+ * @see the_author_meta()
+ */
+function the_author_lastname() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'last_name\')' );
+ the_author_meta('last_name');
+}
+
+/**
+ * Retrieve the nickname of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('nickname')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's nickname.
+ */
+function get_the_author_nickname() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'nickname\')' );
+ return get_the_author_meta('nickname');
+}
+
+/**
+ * Display the nickname of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('nickname')
+ * @see the_author_meta()
+ */
+function the_author_nickname() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'nickname\')' );
+ the_author_meta('nickname');
+}
+
+/**
+ * Retrieve the email of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('email')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's username.
+ */
+function get_the_author_email() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'email\')' );
+ return get_the_author_meta('email');
+}
+
+/**
+ * Display the email of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('email')
+ * @see the_author_meta()
+ */
+function the_author_email() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'email\')' );
+ the_author_meta('email');
+}
+
+/**
+ * Retrieve the ICQ number of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('icq')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's ICQ number.
+ */
+function get_the_author_icq() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'icq\')' );
+ return get_the_author_meta('icq');
+}
+
+/**
+ * Display the ICQ number of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('icq')
+ * @see the_author_meta()
+ */
+function the_author_icq() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'icq\')' );
+ the_author_meta('icq');
+}
+
+/**
+ * Retrieve the Yahoo! IM name of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('yim')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's Yahoo! IM name.
+ */
+function get_the_author_yim() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'yim\')' );
+ return get_the_author_meta('yim');
+}
+
+/**
+ * Display the Yahoo! IM name of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('yim')
+ * @see the_author_meta()
+ */
+function the_author_yim() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'yim\')' );
+ the_author_meta('yim');
+}
+
+/**
+ * Retrieve the MSN address of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('msn')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's MSN address.
+ */
+function get_the_author_msn() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'msn\')' );
+ return get_the_author_meta('msn');
+}
+
+/**
+ * Display the MSN address of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('msn')
+ * @see the_author_meta()
+ */
+function the_author_msn() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'msn\')' );
+ the_author_meta('msn');
+}
+
+/**
+ * Retrieve the AIM address of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('aim')
+ * @see get_the_author_meta()
+ *
+ * @return string The author's AIM address.
+ */
+function get_the_author_aim() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'aim\')' );
+ return get_the_author_meta('aim');
+}
+
+/**
+ * Display the AIM address of the author of the current post.
+ *
+ * @since 0.71
+ * @see the_author_meta()
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('aim')
+ */
+function the_author_aim() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'aim\')' );
+ the_author_meta('aim');
+}
+
+/**
+ * Retrieve the specified author's preferred display name.
+ *
+ * @since 1.0.0
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('display_name')
+ * @see get_the_author_meta()
+ *
+ * @param int $auth_id The ID of the author.
+ * @return string The author's display name.
+ */
+function get_author_name( $auth_id = false ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'display_name\')' );
+ return get_the_author_meta('display_name', $auth_id);
+}
+
+/**
+ * Retrieve the URL to the home page of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('url')
+ * @see get_the_author_meta()
+ *
+ * @return string The URL to the author's page.
+ */
+function get_the_author_url() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'url\')' );
+ return get_the_author_meta('url');
+}
+
+/**
+ * Display the URL to the home page of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('url')
+ * @see the_author_meta()
+ */
+function the_author_url() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'url\')' );
+ the_author_meta('url');
+}
+
+/**
+ * Retrieve the ID of the author of the current post.
+ *
+ * @since 1.5
+ * @deprecated 2.8
+ * @deprecated Use get_the_author_meta('ID')
+ * @see get_the_author_meta()
+ *
+ * @return int The author's ID.
+ */
+function get_the_author_ID() {
+ _deprecated_function( __FUNCTION__, '2.8', 'get_the_author_meta(\'ID\')' );
+ return get_the_author_meta('ID');
+}
+
+/**
+ * Display the ID of the author of the current post.
+ *
+ * @since 0.71
+ * @deprecated 2.8
+ * @deprecated Use the_author_meta('ID')
+ * @see the_author_meta()
+*/
+function the_author_ID() {
+ _deprecated_function( __FUNCTION__, '2.8', 'the_author_meta(\'ID\')' );
+ the_author_meta('ID');
+}
+
+/**
+ * Display the post content for the feed.
+ *
+ * For encoding the html or the $encode_html parameter, there are three possible
+ * values. '0' will make urls footnotes and use make_url_footnote(). '1' will
+ * encode special characters and automatically display all of the content. The
+ * value of '2' will strip all HTML tags from the content.
+ *
+ * Also note that you cannot set the amount of words and not set the html
+ * encoding. If that is the case, then the html encoding will default to 2,
+ * which will strip all HTML tags.
+ *
+ * To restrict the amount of words of the content, you can use the cut
+ * parameter. If the content is less than the amount, then there won't be any
+ * dots added to the end. If there is content left over, then dots will be added
+ * and the rest of the content will be removed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 0.71
+ * @uses apply_filters() Calls 'the_content_rss' on the content before processing.
+ *
+ * @deprecated 2.9.0
+ * @deprecated Use the_content_feed()
+ * @see the_content_feed()
+ *
+ * @param string $more_link_text Optional. Text to display when more content is available but not displayed.
+ * @param int|bool $stripteaser Optional. Default is 0.
+ * @param string $more_file Optional.
+ * @param int $cut Optional. Amount of words to keep for the content.
+ * @param int $encode_html Optional. How to encode the content.
+ */
+function the_content_rss($more_link_text='(more...)', $stripteaser=0, $more_file='', $cut = 0, $encode_html = 0) {
+ _deprecated_function( __FUNCTION__, '2.9', 'the_content_feed' );
+ $content = get_the_content($more_link_text, $stripteaser);
+ $content = apply_filters('the_content_rss', $content);
+ if ( $cut && !$encode_html )
+ $encode_html = 2;
+ if ( 1== $encode_html ) {
+ $content = esc_html($content);
+ $cut = 0;
+ } elseif ( 0 == $encode_html ) {
+ $content = make_url_footnote($content);
+ } elseif ( 2 == $encode_html ) {
+ $content = strip_tags($content);
+ }
+ if ( $cut ) {
+ $blah = explode(' ', $content);
+ if ( count($blah) > $cut ) {
+ $k = $cut;
+ $use_dotdotdot = 1;
+ } else {
+ $k = count($blah);
+ $use_dotdotdot = 0;
+ }
+
+ /** @todo Check performance, might be faster to use array slice instead. */
+ for ( $i=0; $i<$k; $i++ )
+ $excerpt .= $blah[$i].' ';
+ $excerpt .= ($use_dotdotdot) ? '...' : '';
+ $content = $excerpt;
+ }
+ $content = str_replace(']]>', ']]&gt;', $content);
+ echo $content;
+}
+
+/**
+ * Strip HTML and put links at the bottom of stripped content.
+ *
+ * Searches for all of the links, strips them out of the content, and places
+ * them at the bottom of the content with numbers.
+ *
+ * @since 0.71
+ * @deprecated 2.9.0
+ *
+ * @param string $content Content to get links
+ * @return string HTML stripped out of content with links at the bottom.
+ */
+function make_url_footnote( $content ) {
+ _deprecated_function( __FUNCTION__, '2.9', '' );
+ preg_match_all( '/<a(.+?)href=\"(.+?)\"(.*?)>(.+?)<\/a>/', $content, $matches );
+ $links_summary = "\n";
+ for ( $i=0; $i<count($matches[0]); $i++ ) {
+ $link_match = $matches[0][$i];
+ $link_number = '['.($i+1).']';
+ $link_url = $matches[2][$i];
+ $link_text = $matches[4][$i];
+ $content = str_replace( $link_match, $link_text . ' ' . $link_number, $content );
+ $link_url = ( ( strtolower( substr( $link_url, 0, 7 ) ) != 'http://' ) && ( strtolower( substr( $link_url, 0, 8 ) ) != 'https://' ) ) ? get_option( 'home' ) . $link_url : $link_url;
+ $links_summary .= "\n" . $link_number . ' ' . $link_url;
+ }
+ $content = strip_tags( $content );
+ $content .= $links_summary;
+ return $content;
+}
+
+/**
+ * Retrieve translated string with vertical bar context
+ *
+ * Quite a few times, there will be collisions with similar translatable text
+ * found in more than two places but with different translated context.
+ *
+ * In order to use the separate contexts, the _c() function is used and the
+ * translatable string uses a pipe ('|') which has the context the string is in.
+ *
+ * When the translated string is returned, it is everything before the pipe, not
+ * including the pipe character. If there is no pipe in the translated text then
+ * everything is returned.
+ *
+ * @since 2.2.0
+ * @deprecated 2.9.0
+ * @deprecated Use _x()
+ * @see _x()
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated context string without pipe
+ */
+function _c( $text, $domain = 'default' ) {
+ _deprecated_function( __FUNCTION__, '2.9', '_x()' );
+ return before_last_bar( translate( $text, $domain ) );
+}
+
+/**
+ * Translates $text like translate(), but assumes that the text
+ * contains a context after its last vertical bar.
+ *
+ * @since 2.5
+ * @uses translate()
+ * @deprecated 3.0.0
+ * @deprecated Use _x()
+ * @see _x()
+ *
+ * @param string $text Text to translate
+ * @param string $domain Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function translate_with_context( $text, $domain = 'default' ) {
+ _deprecated_function( __FUNCTION__, '2.9', '_x()' );
+ return before_last_bar( translate( $text, $domain ) );
+}
+
+/**
+ * A version of _n(), which supports contexts.
+ * Strips everything from the translation after the last bar.
+ *
+ * @since 2.7.0
+ * @deprecated 3.0.0
+ * @deprecated Use _nx()
+ * @see _nx()
+ * @see _n() For parameters.
+ * @see _c() For parameters. _c() is deprecated.
+ *
+ */
+function _nc( $single, $plural, $number, $domain = 'default' ) {
+ _deprecated_function( __FUNCTION__, '2.9', '_nx()' );
+ return before_last_bar( _n( $single, $plural, $number, $domain ) );
+}
+
+/**
+ * Retrieve the plural or single form based on the amount.
+ *
+ * @since 1.2.0
+ * @deprecated 2.8.0
+ * @deprecated Use _n()
+ * @see _n()
+ */
+function __ngettext() {
+ _deprecated_function( __FUNCTION__, '2.8', '_n()' );
+ $args = func_get_args();
+ return call_user_func_array('_n', $args);
+}
+
+/**
+ * Register plural strings in POT file, but don't translate them.
+ *
+ * @since 2.5
+ * @deprecated 2.8.0
+ * @deprecated Use _n_noop()
+ * @see _n_noop()
+ */
+function __ngettext_noop() {
+ _deprecated_function( __FUNCTION__, '2.8', '_n_noop()' );
+ $args = func_get_args();
+ return call_user_func_array('_n_noop', $args);
+
+}
+
+/**
+ * Retrieve all autoload options, or all options if no autoloaded ones exist.
+ *
+ * @since 1.0.0
+ * @deprecated 3.0.0
+ * @deprecated Use wp_load_alloptions())
+ * @see wp_load_alloptions()
+ *
+ * @return array List of all options.
+ */
+function get_alloptions() {
+ _deprecated_function( __FUNCTION__, '3.0', 'wp_load_alloptions()' );
+ return wp_load_alloptions();
+}
+
+/**
+ * Retrieve HTML content of attachment image with link.
+ *
+ * @since 2.0.0
+ * @deprecated 2.5.0
+ * @deprecated Use wp_get_attachment_link()
+ * @see wp_get_attachment_link()
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default is false. Whether to use full size image.
+ * @param array $max_dims Optional. Max image dimensions.
+ * @param bool $permalink Optional, default is false. Whether to include permalink to image.
+ * @return string
+ */
+function get_the_attachment_link($id = 0, $fullsize = false, $max_dims = false, $permalink = false) {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_get_attachment_link()' );
+ $id = (int) $id;
+ $_post = get_post($id);
+
+ if ( ('attachment' != $_post->post_type) || !$url = wp_get_attachment_url($_post->ID) )
+ return __('Missing Attachment');
+
+ if ( $permalink )
+ $url = get_attachment_link($_post->ID);
+
+ $post_title = esc_attr($_post->post_title);
+
+ $innerHTML = get_attachment_innerHTML($_post->ID, $fullsize, $max_dims);
+ return "<a href='$url' title='$post_title'>$innerHTML</a>";
+}
+
+/**
+ * Retrieve icon URL and Path.
+ *
+ * @since 2.1.0
+ * @deprecated 2.5.0
+ * @deprecated Use wp_get_attachment_image_src()
+ * @see wp_get_attachment_image_src()
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default to false. Whether to have full image.
+ * @return array Icon URL and full path to file, respectively.
+ */
+function get_attachment_icon_src( $id = 0, $fullsize = false ) {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_get_attachment_image_src()' );
+ $id = (int) $id;
+ if ( !$post = get_post($id) )
+ return false;
+
+ $file = get_attached_file( $post->ID );
+
+ if ( !$fullsize && $src = wp_get_attachment_thumb_url( $post->ID ) ) {
+ // We have a thumbnail desired, specified and existing
+
+ $src_file = basename($src);
+ $class = 'attachmentthumb';
+ } elseif ( wp_attachment_is_image( $post->ID ) ) {
+ // We have an image without a thumbnail
+
+ $src = wp_get_attachment_url( $post->ID );
+ $src_file = & $file;
+ $class = 'attachmentimage';
+ } elseif ( $src = wp_mime_type_icon( $post->ID ) ) {
+ // No thumb, no image. We'll look for a mime-related icon instead.
+
+ $icon_dir = apply_filters( 'icon_dir', get_template_directory() . '/images' );
+ $src_file = $icon_dir . '/' . basename($src);
+ }
+
+ if ( !isset($src) || !$src )
+ return false;
+
+ return array($src, $src_file);
+}
+
+/**
+ * Retrieve HTML content of icon attachment image element.
+ *
+ * @since 2.0.0
+ * @deprecated 2.5.0
+ * @deprecated Use wp_get_attachment_image()
+ * @see wp_get_attachment_image()
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default to false. Whether to have full size image.
+ * @param array $max_dims Optional. Dimensions of image.
+ * @return string HTML content.
+ */
+function get_attachment_icon( $id = 0, $fullsize = false, $max_dims = false ) {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_get_attachment_image()' );
+ $id = (int) $id;
+ if ( !$post = get_post($id) )
+ return false;
+
+ if ( !$src = get_attachment_icon_src( $post->ID, $fullsize ) )
+ return false;
+
+ list($src, $src_file) = $src;
+
+ // Do we need to constrain the image?
+ if ( ($max_dims = apply_filters('attachment_max_dims', $max_dims)) && file_exists($src_file) ) {
+
+ $imagesize = getimagesize($src_file);
+
+ if (($imagesize[0] > $max_dims[0]) || $imagesize[1] > $max_dims[1] ) {
+ $actual_aspect = $imagesize[0] / $imagesize[1];
+ $desired_aspect = $max_dims[0] / $max_dims[1];
+
+ if ( $actual_aspect >= $desired_aspect ) {
+ $height = $actual_aspect * $max_dims[0];
+ $constraint = "width='{$max_dims[0]}' ";
+ $post->iconsize = array($max_dims[0], $height);
+ } else {
+ $width = $max_dims[1] / $actual_aspect;
+ $constraint = "height='{$max_dims[1]}' ";
+ $post->iconsize = array($width, $max_dims[1]);
+ }
+ } else {
+ $post->iconsize = array($imagesize[0], $imagesize[1]);
+ $constraint = '';
+ }
+ } else {
+ $constraint = '';
+ }
+
+ $post_title = esc_attr($post->post_title);
+
+ $icon = "<img src='$src' title='$post_title' alt='$post_title' $constraint/>";
+
+ return apply_filters( 'attachment_icon', $icon, $post->ID );
+}
+
+/**
+ * Retrieve HTML content of image element.
+ *
+ * @since 2.0.0
+ * @deprecated 2.5.0
+ * @deprecated Use wp_get_attachment_image()
+ * @see wp_get_attachment_image()
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default to false. Whether to have full size image.
+ * @param array $max_dims Optional. Dimensions of image.
+ * @return string
+ */
+function get_attachment_innerHTML($id = 0, $fullsize = false, $max_dims = false) {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_get_attachment_image()' );
+ $id = (int) $id;
+ if ( !$post = get_post($id) )
+ return false;
+
+ if ( $innerHTML = get_attachment_icon($post->ID, $fullsize, $max_dims))
+ return $innerHTML;
+
+ $innerHTML = esc_attr($post->post_title);
+
+ return apply_filters('attachment_innerHTML', $innerHTML, $post->ID);
+}
+
+/**
+ * Retrieve bookmark data based on ID.
+ *
+ * @since 2.0.0
+ * @deprecated 2.1.0
+ * @deprecated Use get_bookmark()
+ * @see get_bookmark()
+ *
+ * @param int $bookmark_id ID of link
+ * @param string $output OBJECT, ARRAY_N, or ARRAY_A
+ * @return object|array
+ */
+function get_link($bookmark_id, $output = OBJECT, $filter = 'raw') {
+ _deprecated_function( __FUNCTION__, '2.1', 'get_bookmark()' );
+ return get_bookmark($bookmark_id, $output, $filter);
+}
+
+/**
+ * Performs esc_url() for database or redirect usage.
+ *
+ * @since 2.3.1
+ * @deprecated 2.8.0
+ * @deprecated Use esc_url_raw()
+ * @see esc_url_raw()
+ *
+ * @param string $url The URL to be cleaned.
+ * @param array $protocols An array of acceptable protocols.
+ * @return string The cleaned URL.
+ */
+function sanitize_url( $url, $protocols = null ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'esc_url_raw()' );
+ return esc_url_raw( $url, $protocols );
+}
+
+/**
+ * Checks and cleans a URL.
+ *
+ * A number of characters are removed from the URL. If the URL is for displaying
+ * (the default behaviour) ampersands are also replaced. The 'clean_url' filter
+ * is applied to the returned cleaned URL.
+ *
+ * @since 1.2.0
+ * @deprecated 3.0.0
+ * @deprecated Use esc_url()
+ * @see Alias for esc_url()
+ *
+ * @param string $url The URL to be cleaned.
+ * @param array $protocols Optional. An array of acceptable protocols.
+ * @param string $context Optional. How the URL will be used. Default is 'display'.
+ * @return string The cleaned $url after the 'clean_url' filter is applied.
+ */
+function clean_url( $url, $protocols = null, $context = 'display' ) {
+ if ( $context == 'db' )
+ _deprecated_function( 'clean_url( $context = \'db\' )', '3.0', 'esc_url_raw()' );
+ else
+ _deprecated_function( __FUNCTION__, '3.0', 'esc_url()' );
+ return esc_url( $url, $protocols, $context );
+}
+
+/**
+ * Escape single quotes, specialchar double quotes, and fix line endings.
+ *
+ * The filter 'js_escape' is also applied by esc_js()
+ *
+ * @since 2.0.4
+ * @deprecated 2.8.0
+ * @deprecated Use esc_js()
+ * @see esc_js()
+ *
+ * @param string $text The text to be escaped.
+ * @return string Escaped text.
+ */
+function js_escape( $text ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'esc_js()' );
+ return esc_js( $text );
+}
+
+/**
+ * Escaping for HTML blocks.
+ *
+ * @deprecated 2.8.0
+ * @deprecated Use esc_html()
+ * @see esc_html()
+ */
+function wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'esc_html()' );
+ if ( func_num_args() > 1 ) { // Maintain backwards compat for people passing additional args
+ $args = func_get_args();
+ return call_user_func_array( '_wp_specialchars', $args );
+ } else {
+ return esc_html( $string );
+ }
+}
+
+/**
+ * Escaping for HTML attributes.
+ *
+ * @since 2.0.6
+ * @deprecated 2.8.0
+ * @deprecated Use esc_attr()
+ * @see esc_attr()
+ *
+ * @param string $text
+ * @return string
+ */
+function attribute_escape( $text ) {
+ _deprecated_function( __FUNCTION__, '2.8', 'esc_attr()' );
+ return esc_attr( $text );
+}
+
+/**
+ * Register widget for sidebar with backwards compatibility.
+ *
+ * Allows $name to be an array that accepts either three elements to grab the
+ * first element and the third for the name or just uses the first element of
+ * the array for the name.
+ *
+ * Passes to {@link wp_register_sidebar_widget()} after argument list and
+ * backwards compatibility is complete.
+ *
+ * @since 2.2.0
+ * @deprecated 2.8.0
+ * @deprecated Use wp_register_sidebar_widget()
+ * @see wp_register_sidebar_widget()
+ *
+ * @param string|int $name Widget ID.
+ * @param callback $output_callback Run when widget is called.
+ * @param string $classname Classname widget option.
+ * @param mixed $params,... Widget parameters.
+ */
+function register_sidebar_widget($name, $output_callback, $classname = '') {
+ _deprecated_function( __FUNCTION__, '2.8', 'wp_register_sidebar_widget()' );
+ // Compat
+ if ( is_array($name) ) {
+ if ( count($name) == 3 )
+ $name = sprintf($name[0], $name[2]);
+ else
+ $name = $name[0];
+ }
+
+ $id = sanitize_title($name);
+ $options = array();
+ if ( !empty($classname) && is_string($classname) )
+ $options['classname'] = $classname;
+ $params = array_slice(func_get_args(), 2);
+ $args = array($id, $name, $output_callback, $options);
+ if ( !empty($params) )
+ $args = array_merge($args, $params);
+
+ call_user_func_array('wp_register_sidebar_widget', $args);
+}
+
+/**
+ * Alias of {@link wp_unregister_sidebar_widget()}.
+ *
+ * @since 2.2.0
+ * @deprecated 2.8.0
+ * @deprecated Use wp_unregister_sidebar_widget()
+ * @see wp_unregister_sidebar_widget()
+ *
+ * @param int|string $id Widget ID.
+ */
+function unregister_sidebar_widget($id) {
+ _deprecated_function( __FUNCTION__, '2.8', 'wp_unregister_sidebar_widget()' );
+ return wp_unregister_sidebar_widget($id);
+}
+
+/**
+ * Registers widget control callback for customizing options.
+ *
+ * Allows $name to be an array that accepts either three elements to grab the
+ * first element and the third for the name or just uses the first element of
+ * the array for the name.
+ *
+ * Passes to {@link wp_register_widget_control()} after the argument list has
+ * been compiled.
+ *
+ * @since 2.2.0
+ * @deprecated 2.8.0
+ * @deprecated Use wp_register_widget_control()
+ * @see wp_register_widget_control()
+ *
+ * @param int|string $name Sidebar ID.
+ * @param callback $control_callback Widget control callback to display and process form.
+ * @param int $width Widget width.
+ * @param int $height Widget height.
+ */
+function register_widget_control($name, $control_callback, $width = '', $height = '') {
+ _deprecated_function( __FUNCTION__, '2.8', 'wp_register_widget_control()' );
+ // Compat
+ if ( is_array($name) ) {
+ if ( count($name) == 3 )
+ $name = sprintf($name[0], $name[2]);
+ else
+ $name = $name[0];
+ }
+
+ $id = sanitize_title($name);
+ $options = array();
+ if ( !empty($width) )
+ $options['width'] = $width;
+ if ( !empty($height) )
+ $options['height'] = $height;
+ $params = array_slice(func_get_args(), 4);
+ $args = array($id, $name, $control_callback, $options);
+ if ( !empty($params) )
+ $args = array_merge($args, $params);
+
+ call_user_func_array('wp_register_widget_control', $args);
+}
+
+/**
+ * Alias of {@link wp_unregister_widget_control()}.
+ *
+ * @since 2.2.0
+ * @deprecated 2.8.0
+ * @deprecated Use wp_unregister_widget_control()
+ * @see wp_unregister_widget_control()
+ *
+ * @param int|string $id Widget ID.
+ */
+function unregister_widget_control($id) {
+ _deprecated_function( __FUNCTION__, '2.8', 'wp_unregister_widget_control()' );
+ return wp_unregister_widget_control($id);
+}
+
+/**
+ * Remove user meta data.
+ *
+ * @since 2.0.0
+ * @deprecated 3.0.0
+ * @deprecated Use delete_user_meta()
+ * @see delete_user_meta()
+ *
+ * @param int $user_id User ID.
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @return bool True deletion completed and false if user_id is not a number.
+ */
+function delete_usermeta( $user_id, $meta_key, $meta_value = '' ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'delete_user_meta()' );
+ global $wpdb;
+ if ( !is_numeric( $user_id ) )
+ return false;
+ $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+
+ if ( is_array($meta_value) || is_object($meta_value) )
+ $meta_value = serialize($meta_value);
+ $meta_value = trim( $meta_value );
+
+ $cur = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+
+ if ( $cur && $cur->umeta_id )
+ do_action( 'delete_usermeta', $cur->umeta_id, $user_id, $meta_key, $meta_value );
+
+ if ( ! empty($meta_value) )
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s AND meta_value = %s", $user_id, $meta_key, $meta_value) );
+ else
+ $wpdb->query( $wpdb->prepare("DELETE FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+
+ clean_user_cache( $user_id );
+ wp_cache_delete( $user_id, 'user_meta' );
+
+ if ( $cur && $cur->umeta_id )
+ do_action( 'deleted_usermeta', $cur->umeta_id, $user_id, $meta_key, $meta_value );
+
+ return true;
+}
+
+/**
+ * Retrieve user metadata.
+ *
+ * If $user_id is not a number, then the function will fail over with a 'false'
+ * boolean return value. Other returned values depend on whether there is only
+ * one item to be returned, which be that single item type. If there is more
+ * than one metadata value, then it will be list of metadata values.
+ *
+ * @since 2.0.0
+ * @deprecated 3.0.0
+ * @deprecated Use get_user_meta()
+ * @see get_user_meta()
+ *
+ * @param int $user_id User ID
+ * @param string $meta_key Optional. Metadata key.
+ * @return mixed
+ */
+function get_usermeta( $user_id, $meta_key = '' ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'get_user_meta()' );
+ global $wpdb;
+ $user_id = (int) $user_id;
+
+ if ( !$user_id )
+ return false;
+
+ if ( !empty($meta_key) ) {
+ $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+ $user = wp_cache_get($user_id, 'users');
+ // Check the cached user object
+ if ( false !== $user && isset($user->$meta_key) )
+ $metas = array($user->$meta_key);
+ else
+ $metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+ } else {
+ $metas = $wpdb->get_col( $wpdb->prepare("SELECT meta_value FROM $wpdb->usermeta WHERE user_id = %d", $user_id) );
+ }
+
+ if ( empty($metas) ) {
+ if ( empty($meta_key) )
+ return array();
+ else
+ return '';
+ }
+
+ $metas = array_map('maybe_unserialize', $metas);
+
+ if ( count($metas) == 1 )
+ return $metas[0];
+ else
+ return $metas;
+}
+
+/**
+ * Update metadata of user.
+ *
+ * There is no need to serialize values, they will be serialized if it is
+ * needed. The metadata key can only be a string with underscores. All else will
+ * be removed.
+ *
+ * Will remove the metadata, if the meta value is empty.
+ *
+ * @since 2.0.0
+ * @deprecated 3.0.0
+ * @deprecated Use update_user_meta()
+ * @see update_user_meta()
+ *
+ * @param int $user_id User ID
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @return bool True on successful update, false on failure.
+ */
+function update_usermeta( $user_id, $meta_key, $meta_value ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'update_user_meta()' );
+ global $wpdb;
+ if ( !is_numeric( $user_id ) )
+ return false;
+ $meta_key = preg_replace('|[^a-z0-9_]|i', '', $meta_key);
+
+ /** @todo Might need fix because usermeta data is assumed to be already escaped */
+ if ( is_string($meta_value) )
+ $meta_value = stripslashes($meta_value);
+ $meta_value = maybe_serialize($meta_value);
+
+ if (empty($meta_value)) {
+ return delete_usermeta($user_id, $meta_key);
+ }
+
+ $cur = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $user_id, $meta_key) );
+
+ if ( $cur )
+ do_action( 'update_usermeta', $cur->umeta_id, $user_id, $meta_key, $meta_value );
+
+ if ( !$cur )
+ $wpdb->insert($wpdb->usermeta, compact('user_id', 'meta_key', 'meta_value') );
+ else if ( $cur->meta_value != $meta_value )
+ $wpdb->update($wpdb->usermeta, compact('meta_value'), compact('user_id', 'meta_key') );
+ else
+ return false;
+
+ clean_user_cache( $user_id );
+ wp_cache_delete( $user_id, 'user_meta' );
+
+ if ( !$cur )
+ do_action( 'added_usermeta', $wpdb->insert_id, $user_id, $meta_key, $meta_value );
+ else
+ do_action( 'updated_usermeta', $cur->umeta_id, $user_id, $meta_key, $meta_value );
+
+ return true;
+}
+
+/**
+ * Get users for the blog.
+ *
+ * For setups that use the multi-blog feature. Can be used outside of the
+ * multi-blog feature.
+ *
+ * @since 2.2.0
+ * @deprecated 3.1.0
+ * @uses $wpdb WordPress database object for queries
+ * @uses $blog_id The Blog id of the blog for those that use more than one blog
+ *
+ * @param int $id Blog ID.
+ * @return array List of users that are part of that Blog ID
+ */
+function get_users_of_blog( $id = '' ) {
+ _deprecated_function( __FUNCTION__, '3.1', 'get_users()' );
+
+ global $wpdb, $blog_id;
+ if ( empty($id) )
+ $id = (int) $blog_id;
+ $blog_prefix = $wpdb->get_blog_prefix($id);
+ $users = $wpdb->get_results( "SELECT user_id, user_id AS ID, user_login, display_name, user_email, meta_value FROM $wpdb->users, $wpdb->usermeta WHERE {$wpdb->users}.ID = {$wpdb->usermeta}.user_id AND meta_key = '{$blog_prefix}capabilities' ORDER BY {$wpdb->usermeta}.user_id" );
+ return $users;
+}
+
+/**
+ * Enable/disable automatic general feed link outputting.
+ *
+ * @since 2.8.0
+ * @deprecated 3.0.0
+ * @deprecated Use add_theme_support( 'automatic-feed-links' )
+ *
+ * @param boolean $add Optional, default is true. Add or remove links. Defaults to true.
+ */
+function automatic_feed_links( $add = true ) {
+ _deprecated_function( __FUNCTION__, '3.0', "add_theme_support( 'automatic-feed-links' )" );
+
+ if ( $add )
+ add_theme_support( 'automatic-feed-links' );
+ else
+ remove_action( 'wp_head', 'feed_links_extra', 3 ); // Just do this yourself in 3.0+
+}
+
+/**
+ * Retrieve user data based on field.
+ *
+ * @since 1.5.0
+ * @deprecated 3.0.0
+ * @deprecated Use get_the_author_meta()
+ * @see get_the_author_meta()
+ */
+function get_profile( $field, $user = false ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'get_the_author_meta()' );
+ if ( $user ) {
+ $user = get_user_by( 'login', $user );
+ $user = $user->ID;
+ }
+ return get_the_author_meta( $field, $user );
+}
+
+/**
+ * Number of posts user has written.
+ *
+ * @since 0.71
+ * @deprecated 3.0.0
+ * @deprecated Use count_user_posts()
+ * @see count_user_posts()
+ */
+function get_usernumposts( $userid ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'count_user_posts()' );
+ return count_user_posts( $userid );
+}
+
+/**
+ * Callback used to change %uXXXX to &#YYY; syntax
+ *
+ * @since 2.8.0
+ * @access private
+ * @deprecated 3.0.0
+ *
+ * @param array $matches Single Match
+ * @return string An HTML entity
+ */
+function funky_javascript_callback($matches) {
+ return "&#".base_convert($matches[1],16,10).";";
+}
+
+/**
+ * Fixes javascript bugs in browsers.
+ *
+ * Converts unicode characters to HTML numbered entities.
+ *
+ * @since 1.5.0
+ * @uses $is_macIE
+ * @uses $is_winIE
+ * @deprecated 3.0.0
+ *
+ * @param string $text Text to be made safe.
+ * @return string Fixed text.
+ */
+function funky_javascript_fix($text) {
+ _deprecated_function( __FUNCTION__, '3.0' );
+ // Fixes for browsers' javascript bugs
+ global $is_macIE, $is_winIE;
+
+ if ( $is_winIE || $is_macIE )
+ $text = preg_replace_callback("/\%u([0-9A-F]{4,4})/",
+ "funky_javascript_callback",
+ $text);
+
+ return $text;
+}
+
+/**
+ * Checks that the taxonomy name exists.
+ *
+ * @since 2.3.0
+ * @deprecated 3.0.0
+ * @deprecated Use taxonomy_exists()
+ * @see taxonomy_exists()
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @return bool Whether the taxonomy exists.
+ */
+function is_taxonomy( $taxonomy ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'taxonomy_exists()' );
+ return taxonomy_exists( $taxonomy );
+}
+
+/**
+ * Check if Term exists.
+ *
+ * @since 2.3.0
+ * @deprecated 3.0.0
+ * @deprecated Use term_exists()
+ * @see term_exists()
+ *
+ * @param int|string $term The term to check
+ * @param string $taxonomy The taxonomy name to use
+ * @param int $parent ID of parent term under which to confine the exists search.
+ * @return mixed Get the term id or Term Object, if exists.
+ */
+function is_term( $term, $taxonomy = '', $parent = 0 ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'term_exists()' );
+ return term_exists( $term, $taxonomy, $parent );
+}
+
+/**
+ * Is the current admin page generated by a plugin?
+ *
+ * @since 1.5.0
+ * @deprecated 3.1.0
+ * @deprecated Use global $plugin_page and/or get_plugin_page_hookname() hooks.
+ *
+ * @global $plugin_page
+ *
+ * @return bool
+ */
+function is_plugin_page() {
+ _deprecated_function( __FUNCTION__, '3.1' );
+
+ global $plugin_page;
+
+ if ( isset($plugin_page) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Update the categories cache.
+ *
+ * This function does not appear to be used anymore or does not appear to be
+ * needed. It might be a legacy function left over from when there was a need
+ * for updating the category cache.
+ *
+ * @since 1.5.0
+ * @deprecated 3.1.0
+ *
+ * @return bool Always return True
+ */
+function update_category_cache() {
+ _deprecated_function( __FUNCTION__, '3.1' );
+
+ return true;
+}
+
+/**
+ * Check for PHP timezone support
+ *
+ * @since 2.9.0
+ * @deprecated 3.2.0
+ *
+ * @return bool
+ */
+function wp_timezone_supported() {
+ _deprecated_function( __FUNCTION__, '3.2' );
+
+ return true;
+}
+
+/**
+ * Display editor: TinyMCE, HTML, or both.
+ *
+ * @since 2.1.0
+ * @deprecated 3.3.0
+ * @deprecated Use wp_editor()
+ * @see wp_editor()
+ *
+ * @param string $content Textarea content.
+ * @param string $id Optional, default is 'content'. HTML ID attribute value.
+ * @param string $prev_id Optional, not used
+ * @param bool $media_buttons Optional, default is true. Whether to display media buttons.
+ * @param int $tab_index Optional, not used
+ */
+function the_editor($content, $id = 'content', $prev_id = 'title', $media_buttons = true, $tab_index = 2, $extended = true) {
+ _deprecated_function( __FUNCTION__, '3.3', 'wp_editor()' );
+
+ wp_editor( $content, $id, array( 'media_buttons' => $media_buttons ) );
+ return;
+}
+
+/**
+ * Perform the query to get the $metavalues array(s) needed by _fill_user and _fill_many_users
+ *
+ * @since 3.0.0
+ * @deprecated 3.3.0
+ *
+ * @param array $ids User ID numbers list.
+ * @return array of arrays. The array is indexed by user_id, containing $metavalues object arrays.
+ */
+function get_user_metavalues($ids) {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ $objects = array();
+
+ $ids = array_map('intval', $ids);
+ foreach ( $ids as $id )
+ $objects[$id] = array();
+
+ $metas = update_meta_cache('user', $ids);
+
+ foreach ( $metas as $id => $meta ) {
+ foreach ( $meta as $key => $metavalues ) {
+ foreach ( $metavalues as $value ) {
+ $objects[$id][] = (object)array( 'user_id' => $id, 'meta_key' => $key, 'meta_value' => $value);
+ }
+ }
+ }
+
+ return $objects;
+}
+
+/**
+ * Sanitize every user field.
+ *
+ * If the context is 'raw', then the user object or array will get minimal santization of the int fields.
+ *
+ * @since 2.3.0
+ * @deprecated 3.3.0
+ *
+ * @param object|array $user The User Object or Array
+ * @param string $context Optional, default is 'display'. How to sanitize user fields.
+ * @return object|array The now sanitized User Object or Array (will be the same type as $user)
+ */
+function sanitize_user_object($user, $context = 'display') {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ if ( is_object($user) ) {
+ if ( !isset($user->ID) )
+ $user->ID = 0;
+ if ( !is_a( $user, 'WP_User' ) ) {
+ $vars = get_object_vars($user);
+ foreach ( array_keys($vars) as $field ) {
+ if ( is_string($user->$field) || is_numeric($user->$field) )
+ $user->$field = sanitize_user_field($field, $user->$field, $user->ID, $context);
+ }
+ }
+ $user->filter = $context;
+ } else {
+ if ( !isset($user['ID']) )
+ $user['ID'] = 0;
+ foreach ( array_keys($user) as $field )
+ $user[$field] = sanitize_user_field($field, $user[$field], $user['ID'], $context);
+ $user['filter'] = $context;
+ }
+
+ return $user;
+}
+
+/**
+ * Get boundary post relational link.
+ *
+ * Can either be start or end post relational link.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ *
+ * @param string $title Optional. Link title format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ * @param bool $start Optional, default is true. Whether to display link to first or last post.
+ * @return string
+ */
+function get_boundary_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '', $start = true) {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ $posts = get_boundary_post($in_same_cat, $excluded_categories, $start);
+ // If there is no post stop.
+ if ( empty($posts) )
+ return;
+
+ // Even though we limited get_posts to return only 1 item it still returns an array of objects.
+ $post = $posts[0];
+
+ if ( empty($post->post_title) )
+ $post->post_title = $start ? __('First Post') : __('Last Post');
+
+ $date = mysql2date(get_option('date_format'), $post->post_date);
+
+ $title = str_replace('%title', $post->post_title, $title);
+ $title = str_replace('%date', $date, $title);
+ $title = apply_filters('the_title', $title, $post->ID);
+
+ $link = $start ? "<link rel='start' title='" : "<link rel='end' title='";
+ $link .= esc_attr($title);
+ $link .= "' href='" . get_permalink($post) . "' />\n";
+
+ $boundary = $start ? 'start' : 'end';
+ return apply_filters( "{$boundary}_post_rel_link", $link );
+}
+
+/**
+ * Display relational link for the first post.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ *
+ * @param string $title Optional. Link title format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param string $excluded_categories Optional. Excluded categories IDs.
+ */
+function start_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ echo get_boundary_post_rel_link($title, $in_same_cat, $excluded_categories, true);
+}
+
+/**
+ * Get site index relational link.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ *
+ * @return string
+ */
+function get_index_rel_link() {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ $link = "<link rel='index' title='" . esc_attr( get_bloginfo( 'name', 'display' ) ) . "' href='" . esc_url( user_trailingslashit( get_bloginfo( 'url', 'display' ) ) ) . "' />\n";
+ return apply_filters( "index_rel_link", $link );
+}
+
+/**
+ * Display relational link for the site index.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ */
+function index_rel_link() {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ echo get_index_rel_link();
+}
+
+/**
+ * Get parent post relational link.
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ *
+ * @param string $title Optional. Link title format.
+ * @return string
+ */
+function get_parent_post_rel_link($title = '%title') {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ if ( ! empty( $GLOBALS['post'] ) && ! empty( $GLOBALS['post']->post_parent ) )
+ $post = get_post($GLOBALS['post']->post_parent);
+
+ if ( empty($post) )
+ return;
+
+ $date = mysql2date(get_option('date_format'), $post->post_date);
+
+ $title = str_replace('%title', $post->post_title, $title);
+ $title = str_replace('%date', $date, $title);
+ $title = apply_filters('the_title', $title, $post->ID);
+
+ $link = "<link rel='up' title='";
+ $link .= esc_attr( $title );
+ $link .= "' href='" . get_permalink($post) . "' />\n";
+
+ return apply_filters( "parent_post_rel_link", $link );
+}
+
+/**
+ * Display relational link for parent item
+ *
+ * @since 2.8.0
+ * @deprecated 3.3.0
+ */
+function parent_post_rel_link($title = '%title') {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ echo get_parent_post_rel_link($title);
+}
+
+/**
+ * Add the "Dashboard"/"Visit Site" menu.
+ *
+ * @since 3.2.0
+ * @deprecated 3.3.0
+ */
+function wp_admin_bar_dashboard_view_site_menu( $wp_admin_bar ) {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ $user_id = get_current_user_id();
+
+ if ( 0 != $user_id ) {
+ if ( is_admin() )
+ $wp_admin_bar->add_menu( array( 'id' => 'view-site', 'title' => __( 'Visit Site' ), 'href' => home_url() ) );
+ elseif ( is_multisite() )
+ $wp_admin_bar->add_menu( array( 'id' => 'dashboard', 'title' => __( 'Dashboard' ), 'href' => get_dashboard_url( $user_id ) ) );
+ else
+ $wp_admin_bar->add_menu( array( 'id' => 'dashboard', 'title' => __( 'Dashboard' ), 'href' => admin_url() ) );
+ }
+}
+
+/**
+ * Checks if the current user belong to a given blog.
+ *
+ * @since MU
+ * @deprecated 3.3.0
+ * @deprecated Use is_user_member_of_blog()
+ * @see is_user_member_of_blog()
+ *
+ * @param int $blog_id Blog ID
+ * @return bool True if the current users belong to $blog_id, false if not.
+ */
+function is_blog_user( $blog_id = 0 ) {
+ _deprecated_function( __FUNCTION__, '3.3', 'is_user_member_of_blog()' );
+
+ return is_user_member_of_blog( get_current_user_id(), $blog_id );
+}
+
+/**
+ * Open the file handle for debugging.
+ *
+ * @since 0.71
+ * @deprecated Use error_log()
+ * @link http://www.php.net/manual/en/function.error-log.php
+ * @deprecated 3.4.0
+ */
+function debug_fopen( $filename, $mode ) {
+ _deprecated_function( __FUNCTION__, 'error_log()' );
+ return false;
+}
+
+/**
+ * Write contents to the file used for debugging.
+ *
+ * @since 0.71
+ * @deprecated Use error_log() instead.
+ * @link http://www.php.net/manual/en/function.error-log.php
+ * @deprecated 3.4.0
+ */
+function debug_fwrite( $fp, $string ) {
+ _deprecated_function( __FUNCTION__, 'error_log()' );
+ if ( ! empty( $GLOBALS['debug'] ) )
+ error_log( $string );
+}
+
+/**
+ * Close the debugging file handle.
+ *
+ * @since 0.71
+ * @deprecated Use error_log()
+ * @link http://www.php.net/manual/en/function.error-log.php
+ * @deprecated 3.4.0
+ */
+function debug_fclose( $fp ) {
+ _deprecated_function( __FUNCTION__, 'error_log()' );
+}
+
+/**
+ * Retrieve list of themes with theme data in theme directory.
+ *
+ * The theme is broken, if it doesn't have a parent theme and is missing either
+ * style.css and, or index.php. If the theme has a parent theme then it is
+ * broken, if it is missing style.css; index.php is optional.
+ *
+ * @since 1.5.0
+ * @deprecated 3.4.0
+ * @deprecated Use wp_get_themes()
+ * @see wp_get_themes()
+ *
+ * @return array Theme list with theme data.
+ */
+function get_themes() {
+ _deprecated_function( __FUNCTION__, '3.4', 'wp_get_themes()' );
+
+ global $wp_themes;
+ if ( isset( $wp_themes ) )
+ return $wp_themes;
+
+ $themes = wp_get_themes();
+ $wp_themes = array();
+
+ foreach ( $themes as $theme ) {
+ $name = $theme->get('Name');
+ if ( isset( $wp_themes[ $name ] ) )
+ $wp_themes[ $name . '/' . $theme->get_stylesheet() ] = $theme;
+ else
+ $wp_themes[ $name ] = $theme;
+ }
+
+ return $wp_themes;
+}
+
+/**
+ * Retrieve theme data.
+ *
+ * @since 1.5.0
+ * @deprecated 3.4.0
+ * @deprecated Use wp_get_theme()
+ * @see wp_get_theme()
+ *
+ * @param string $theme Theme name.
+ * @return array|null Null, if theme name does not exist. Theme data, if exists.
+ */
+function get_theme( $theme ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'wp_get_theme( $stylesheet )' );
+
+ $themes = get_themes();
+ if ( is_array( $themes ) && array_key_exists( $theme, $themes ) )
+ return $themes[ $theme ];
+ return null;
+}
+
+/**
+ * Retrieve current theme name.
+ *
+ * @since 1.5.0
+ * @deprecated 3.4.0
+ * @deprecated Use (string) wp_get_theme()
+ * @see wp_get_theme()
+ *
+ * @return string
+ */
+function get_current_theme() {
+ _deprecated_function( __FUNCTION__, '3.4', 'wp_get_theme()' );
+
+ if ( $theme = get_option( 'current_theme' ) )
+ return $theme;
+
+ return wp_get_theme()->get('Name');
+}
+
+/**
+ * Accepts matches array from preg_replace_callback in wpautop() or a string.
+ *
+ * Ensures that the contents of a <<pre>>...<</pre>> HTML block are not
+ * converted into paragraphs or line-breaks.
+ *
+ * @since 1.2.0
+ * @deprecated 3.4.0
+ *
+ * @param array|string $matches The array or string
+ * @return string The pre block without paragraph/line-break conversion.
+ */
+function clean_pre($matches) {
+ _deprecated_function( __FUNCTION__, '3.4' );
+
+ if ( is_array($matches) )
+ $text = $matches[1] . $matches[2] . "</pre>";
+ else
+ $text = $matches;
+
+ $text = str_replace(array('<br />', '<br/>', '<br>'), array('', '', ''), $text);
+ $text = str_replace('<p>', "\n", $text);
+ $text = str_replace('</p>', '', $text);
+
+ return $text;
+}
+
+
+/**
+ * Add callbacks for image header display.
+ *
+ * @since 2.1.0
+ * @deprecated 3.4.0
+ * @deprecated Use add_theme_support('custom-header', $args)
+ * @see add_theme_support()
+ *
+ * @param callback $wp_head_callback Call on 'wp_head' action.
+ * @param callback $admin_head_callback Call on custom header administration screen.
+ * @param callback $admin_preview_callback Output a custom header image div on the custom header administration screen. Optional.
+ */
+function add_custom_image_header( $wp_head_callback, $admin_head_callback, $admin_preview_callback = '' ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'add_theme_support( \'custom-header\', $args )' );
+ $args = array(
+ 'wp-head-callback' => $wp_head_callback,
+ 'admin-head-callback' => $admin_head_callback,
+ );
+ if ( $admin_preview_callback )
+ $args['admin-preview-callback'] = $admin_preview_callback;
+ return add_theme_support( 'custom-header', $args );
+}
+
+/**
+ * Remove image header support.
+ *
+ * @since 3.1.0
+ * @deprecated 3.4.0
+ * @deprecated Use remove_theme_support('custom-header')
+ * @see remove_theme_support()
+ *
+ * @return bool Whether support was removed.
+ */
+function remove_custom_image_header() {
+ _deprecated_function( __FUNCTION__, '3.4', 'remove_theme_support( \'custom-header\' )' );
+ return remove_theme_support( 'custom-header' );
+}
+
+/**
+ * Add callbacks for background image display.
+ *
+ * @since 3.0.0
+ * @deprecated 3.4.0
+ * @deprecated Use add_theme_support('custom-background, $args)
+ * @see add_theme_support()
+ *
+ * @param callback $wp_head_callback Call on 'wp_head' action.
+ * @param callback $admin_head_callback Call on custom background administration screen.
+ * @param callback $admin_preview_callback Output a custom background image div on the custom background administration screen. Optional.
+ */
+function add_custom_background( $wp_head_callback = '', $admin_head_callback = '', $admin_preview_callback = '' ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'add_theme_support( \'custom-background\', $args )' );
+ $args = array();
+ if ( $wp_head_callback )
+ $args['wp-head-callback'] = $wp_head_callback;
+ if ( $admin_head_callback )
+ $args['admin-head-callback'] = $admin_head_callback;
+ if ( $admin_preview_callback )
+ $args['admin-preview-callback'] = $admin_preview_callback;
+ return add_theme_support( 'custom-background', $args );
+}
+
+/**
+ * Remove custom background support.
+ *
+ * @since 3.1.0
+ * @see add_custom_background()
+ *
+ * @return bool Whether support was removed.
+ */
+function remove_custom_background() {
+ _deprecated_function( __FUNCTION__, '3.4', 'remove_theme_support( \'custom-background\' )' );
+ return remove_theme_support( 'custom-background' );
+}
+
+/**
+ * Retrieve theme data from parsed theme file.
+ *
+ * @since 1.5.0
+ * @deprecated 3.4.0
+ * @deprecated Use wp_get_theme()
+ * @see wp_get_theme()
+ *
+ * @param string $theme_file Theme file path.
+ * @return array Theme data.
+ */
+function get_theme_data( $theme_file ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'wp_get_theme()' );
+ $theme = new WP_Theme( basename( dirname( $theme_file ) ), dirname( dirname( $theme_file ) ) );
+
+ $theme_data = array(
+ 'Name' => $theme->get('Name'),
+ 'URI' => $theme->display('ThemeURI', true, false),
+ 'Description' => $theme->display('Description', true, false),
+ 'Author' => $theme->display('Author', true, false),
+ 'AuthorURI' => $theme->display('AuthorURI', true, false),
+ 'Version' => $theme->get('Version'),
+ 'Template' => $theme->get('Template'),
+ 'Status' => $theme->get('Status'),
+ 'Tags' => $theme->get('Tags'),
+ 'Title' => $theme->get('Name'),
+ 'AuthorName' => $theme->get('Author'),
+ );
+
+ foreach ( apply_filters( 'extra_theme_headers', array() ) as $extra_header ) {
+ if ( ! isset( $theme_data[ $extra_header ] ) )
+ $theme_data[ $extra_header ] = $theme->get( $extra_header );
+ }
+
+ return $theme_data;
+}
+
+/**
+ * Alias of update_post_cache().
+ *
+ * @see update_post_cache() Posts and pages are the same, alias is intentional
+ *
+ * @since 1.5.1
+ * @deprecated 3.4.0
+ *
+ * @param array $pages list of page objects
+ */
+function update_page_cache( &$pages ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'update_post_cache()' );
+
+ update_post_cache( $pages );
+}
+
+/**
+ * Will clean the page in the cache.
+ *
+ * Clean (read: delete) page from cache that matches $id. Will also clean cache
+ * associated with 'all_page_ids' and 'get_pages'.
+ *
+ * @since 2.0.0
+ * @deprecated 3.4.0
+ *
+ * @uses do_action() Will call the 'clean_page_cache' hook action.
+ *
+ * @param int $id Page ID to clean
+ */
+function clean_page_cache( $id ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'clean_post_cache()' );
+
+ clean_post_cache( $id );
+}
+
+/**
+ * Retrieve nonce action "Are you sure" message.
+ *
+ * Deprecated in 3.4.1 and 3.5.0. Backported to 3.3.3.
+ *
+ * @since 2.0.4
+ * @deprecated 3.4.1
+ * @deprecated Use wp_nonce_ays()
+ * @see wp_nonce_ays()
+ *
+ * @param string $action Nonce action.
+ * @return string Are you sure message.
+ */
+function wp_explain_nonce( $action ) {
+ _deprecated_function( __FUNCTION__, '3.4.1', 'wp_nonce_ays()' );
+ return __( 'Are you sure you want to do this?' );
+}
+
+/**
+ * Display "sticky" CSS class, if a post is sticky.
+ *
+ * @since 2.7.0
+ * @deprecated 3.5.0
+ * @deprecated Use post_class()
+ * @see post_class()
+ *
+ * @param int $post_id An optional post ID.
+ */
+function sticky_class( $post_id = null ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'post_class()' );
+ if ( is_sticky( $post_id ) )
+ echo ' sticky';
+}
+
+/**
+ * Retrieve post ancestors.
+ *
+ * This is no longer needed as WP_Post lazy-loads the ancestors
+ * property with get_post_ancestors().
+ *
+ * @since 2.3.4
+ * @deprecated 3.5.0
+ * @see get_post_ancestors()
+ */
+function _get_post_ancestors( &$post ) {
+ _deprecated_function( __FUNCTION__, '3.5' );
+}
+
+/**
+ * Load an image from a string, if PHP supports it.
+ *
+ * @since 2.1.0
+ * @deprecated 3.5.0
+ * @see wp_get_image_editor()
+ *
+ * @param string $file Filename of the image to load.
+ * @return resource The resulting image resource on success, Error string on failure.
+ */
+function wp_load_image( $file ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'wp_get_image_editor()' );
+
+ if ( is_numeric( $file ) )
+ $file = get_attached_file( $file );
+
+ if ( ! is_file( $file ) )
+ return sprintf(__('File &#8220;%s&#8221; doesn&#8217;t exist?'), $file);
+
+ if ( ! function_exists('imagecreatefromstring') )
+ return __('The GD image library is not installed.');
+
+ // Set artificially high because GD uses uncompressed images in memory
+ @ini_set( 'memory_limit', apply_filters( 'image_memory_limit', WP_MAX_MEMORY_LIMIT ) );
+ $image = imagecreatefromstring( file_get_contents( $file ) );
+
+ if ( !is_resource( $image ) )
+ return sprintf(__('File &#8220;%s&#8221; is not an image.'), $file);
+
+ return $image;
+}
+
+/**
+ * Scale down an image to fit a particular size and save a new copy of the image.
+ *
+ * The PNG transparency will be preserved using the function, as well as the
+ * image type. If the file going in is PNG, then the resized image is going to
+ * be PNG. The only supported image types are PNG, GIF, and JPEG.
+ *
+ * Some functionality requires API to exist, so some PHP version may lose out
+ * support. This is not the fault of WordPress (where functionality is
+ * downgraded, not actual defects), but of your PHP version.
+ *
+ * @since 2.5.0
+ * @deprecated 3.5.0
+ * @see wp_get_image_editor()
+ *
+ * @param string $file Image file path.
+ * @param int $max_w Maximum width to resize to.
+ * @param int $max_h Maximum height to resize to.
+ * @param bool $crop Optional. Whether to crop image or resize.
+ * @param string $suffix Optional. File suffix.
+ * @param string $dest_path Optional. New image file path.
+ * @param int $jpeg_quality Optional, default is 90. Image quality percentage.
+ * @return mixed WP_Error on failure. String with new destination path.
+ */
+function image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'wp_get_image_editor()' );
+
+ $editor = wp_get_image_editor( $file );
+ if ( is_wp_error( $editor ) )
+ return $editor;
+ $editor->set_quality( $jpeg_quality );
+
+ $resized = $editor->resize( $max_w, $max_h, $crop );
+ if ( is_wp_error( $resized ) )
+ return $resized;
+
+ $dest_file = $editor->generate_filename( $suffix, $dest_path );
+ $saved = $editor->save( $dest_file );
+
+ if ( is_wp_error( $saved ) )
+ return $saved;
+
+ return $dest_file;
+}
+
+/**
+ * Retrieve a single post, based on post ID.
+ *
+ * Has categories in 'post_category' property or key. Has tags in 'tags_input'
+ * property or key.
+ *
+ * @since 1.0.0
+ * @deprecated 3.5.0
+ * @see get_post()
+ *
+ * @param int $postid Post ID.
+ * @param string $mode How to return result, either OBJECT, ARRAY_N, or ARRAY_A.
+ * @return object|array Post object or array holding post contents and information
+ */
+function wp_get_single_post( $postid = 0, $mode = OBJECT ) {
+ _deprecated_function( __FUNCTION__, '3.5', 'get_post()' );
+ return get_post( $postid, $mode );
+}
+
+/**
+ * Check that the user login name and password is correct.
+ *
+ * @since 0.71
+ * @deprecated 3.5.0
+ * @deprecated Use wp_authenticate()
+ * @see wp_authenticate()
+ *
+ * @param string $user_login User name.
+ * @param string $user_pass User password.
+ * @return bool False if does not authenticate, true if username and password authenticates.
+ */
+function user_pass_ok($user_login, $user_pass) {
+ _deprecated_function( __FUNCTION__, '3.5', 'wp_authenticate()' );
+ $user = wp_authenticate( $user_login, $user_pass );
+ if ( is_wp_error( $user ) )
+ return false;
+
+ return true;
+}
+
+/**
+ * Callback formerly fired on the save_post hook. No longer needed.
+ *
+ * @since 2.3.0
+ * @deprecated 3.5.0
+ */
+function _save_post_hook() {}
+
+/**
+ * Check if the installed version of GD supports particular image type
+ *
+ * @since 2.9.0
+ * @deprecated 3.5.0
+ * @see wp_image_editor_supports()
+ *
+ * @param string $mime_type
+ * @return bool
+ */
+function gd_edit_image_support($mime_type) {
+ _deprecated_function( __FUNCTION__, '3.5', 'wp_image_editor_supports()' );
+
+ if ( function_exists('imagetypes') ) {
+ switch( $mime_type ) {
+ case 'image/jpeg':
+ return (imagetypes() & IMG_JPG) != 0;
+ case 'image/png':
+ return (imagetypes() & IMG_PNG) != 0;
+ case 'image/gif':
+ return (imagetypes() & IMG_GIF) != 0;
+ }
+ } else {
+ switch( $mime_type ) {
+ case 'image/jpeg':
+ return function_exists('imagecreatefromjpeg');
+ case 'image/png':
+ return function_exists('imagecreatefrompng');
+ case 'image/gif':
+ return function_exists('imagecreatefromgif');
+ }
+ }
+ return false;
+}
+
+/**
+ * Converts an integer byte value to a shorthand byte value.
+ *
+ * @since 2.3.0
+ * @deprecated 3.6.0
+ * @deprecated Use size_format()
+ *
+ * @param int $bytes An integer byte value.
+ * @return string A shorthand byte value.
+ */
+function wp_convert_bytes_to_hr( $bytes ) {
+ _deprecated_function( __FUNCTION__, '3.6', 'size_format()' );
+
+ $units = array( 0 => 'B', 1 => 'kB', 2 => 'MB', 3 => 'GB', 4 => 'TB' );
+ $log = log( $bytes, 1024 );
+ $power = (int) $log;
+ $size = pow( 1024, $log - $power );
+
+ if ( ! is_nan( $size ) && array_key_exists( $power, $units ) ) {
+ $unit = $units[ $power ];
+ } else {
+ $size = $bytes;
+ $unit = $units[0];
+ }
+
+ return $size . $unit;
+}
diff --git a/src/wp-includes/feed-atom-comments.php b/src/wp-includes/feed-atom-comments.php
new file mode 100644
index 0000000000..1a89c47955
--- /dev/null
+++ b/src/wp-includes/feed-atom-comments.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Atom Feed Template for displaying Atom Comments feed.
+ *
+ * @package WordPress
+ */
+
+header('Content-Type: ' . feed_content_type('atom') . '; charset=' . get_option('blog_charset'), true);
+echo '<?xml version="1.0" encoding="' . get_option('blog_charset') . '" ?' . '>';
+?>
+<feed
+ xmlns="http://www.w3.org/2005/Atom"
+ xml:lang="<?php bloginfo_rss( 'language' ); ?>"
+ xmlns:thr="http://purl.org/syndication/thread/1.0"
+ <?php do_action('atom_ns'); do_action('atom_comments_ns'); ?>
+>
+ <title type="text"><?php
+ if ( is_singular() )
+ printf( ent2ncr( __( 'Comments on %s' ) ), get_the_title_rss() );
+ elseif ( is_search() )
+ printf( ent2ncr( __( 'Comments for %1$s searching on %2$s' ) ), get_bloginfo_rss( 'name' ), get_search_query() );
+ else
+ printf( ent2ncr( __( 'Comments for %s' ) ), get_bloginfo_rss( 'name' ) . get_wp_title_rss() );
+ ?></title>
+ <subtitle type="text"><?php bloginfo_rss('description'); ?></subtitle>
+
+ <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastcommentmodified('GMT'), false); ?></updated>
+
+<?php if ( is_singular() ) { ?>
+ <link rel="alternate" type="<?php bloginfo_rss('html_type'); ?>" href="<?php comments_link_feed(); ?>" />
+ <link rel="self" type="application/atom+xml" href="<?php echo esc_url( get_post_comments_feed_link('', 'atom') ); ?>" />
+ <id><?php echo esc_url( get_post_comments_feed_link('', 'atom') ); ?></id>
+<?php } elseif(is_search()) { ?>
+ <link rel="alternate" type="<?php bloginfo_rss('html_type'); ?>" href="<?php echo home_url() . '?s=' . get_search_query(); ?>" />
+ <link rel="self" type="application/atom+xml" href="<?php echo get_search_comments_feed_link('', 'atom'); ?>" />
+ <id><?php echo get_search_comments_feed_link('', 'atom'); ?></id>
+<?php } else { ?>
+ <link rel="alternate" type="<?php bloginfo_rss('html_type'); ?>" href="<?php bloginfo_rss('url'); ?>" />
+ <link rel="self" type="application/atom+xml" href="<?php bloginfo_rss('comments_atom_url'); ?>" />
+ <id><?php bloginfo_rss('comments_atom_url'); ?></id>
+<?php } ?>
+<?php do_action('comments_atom_head'); ?>
+<?php
+if ( have_comments() ) : while ( have_comments() ) : the_comment();
+ $comment_post = $GLOBALS['post'] = get_post( $comment->comment_post_ID );
+?>
+ <entry>
+ <title><?php
+ if ( !is_singular() ) {
+ $title = get_the_title($comment_post->ID);
+ $title = apply_filters('the_title_rss', $title);
+ printf(ent2ncr(__('Comment on %1$s by %2$s')), $title, get_comment_author_rss());
+ } else {
+ printf(ent2ncr(__('By: %s')), get_comment_author_rss());
+ }
+ ?></title>
+ <link rel="alternate" href="<?php comment_link(); ?>" type="<?php bloginfo_rss('html_type'); ?>" />
+
+ <author>
+ <name><?php comment_author_rss(); ?></name>
+ <?php if (get_comment_author_url()) echo '<uri>' . get_comment_author_url() . '</uri>'; ?>
+
+ </author>
+
+ <id><?php comment_guid(); ?></id>
+ <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_comment_time('Y-m-d H:i:s', true, false), false); ?></updated>
+ <published><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_comment_time('Y-m-d H:i:s', true, false), false); ?></published>
+<?php if ( post_password_required($comment_post) ) : ?>
+ <content type="html" xml:base="<?php comment_link(); ?>"><![CDATA[<?php echo get_the_password_form(); ?>]]></content>
+<?php else : // post pass ?>
+ <content type="html" xml:base="<?php comment_link(); ?>"><![CDATA[<?php comment_text(); ?>]]></content>
+<?php endif; // post pass
+ // Return comment threading information (http://www.ietf.org/rfc/rfc4685.txt)
+ if ( $comment->comment_parent == 0 ) : // This comment is top level ?>
+ <thr:in-reply-to ref="<?php the_guid(); ?>" href="<?php the_permalink_rss() ?>" type="<?php bloginfo_rss('html_type'); ?>" />
+<?php else : // This comment is in reply to another comment
+ $parent_comment = get_comment($comment->comment_parent);
+ // The rel attribute below and the id tag above should be GUIDs, but WP doesn't create them for comments (unlike posts). Either way, it's more important that they both use the same system
+?>
+ <thr:in-reply-to ref="<?php comment_guid($parent_comment) ?>" href="<?php echo get_comment_link($parent_comment) ?>" type="<?php bloginfo_rss('html_type'); ?>" />
+<?php endif;
+ do_action('comment_atom_entry', $comment->comment_ID, $comment_post->ID);
+?>
+ </entry>
+<?php endwhile; endif; ?>
+</feed>
diff --git a/src/wp-includes/feed-atom.php b/src/wp-includes/feed-atom.php
new file mode 100644
index 0000000000..983c8f4a3d
--- /dev/null
+++ b/src/wp-includes/feed-atom.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Atom Feed Template for displaying Atom Posts feed.
+ *
+ * @package WordPress
+ */
+
+header('Content-Type: ' . feed_content_type('atom') . '; charset=' . get_option('blog_charset'), true);
+$more = 1;
+
+echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
+<feed
+ xmlns="http://www.w3.org/2005/Atom"
+ xmlns:thr="http://purl.org/syndication/thread/1.0"
+ xml:lang="<?php bloginfo_rss( 'language' ); ?>"
+ xml:base="<?php bloginfo_rss('url') ?>/wp-atom.php"
+ <?php do_action('atom_ns'); ?>
+ >
+ <title type="text"><?php bloginfo_rss('name'); wp_title_rss(); ?></title>
+ <subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
+
+ <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT'), false); ?></updated>
+
+ <link rel="alternate" type="<?php bloginfo_rss('html_type'); ?>" href="<?php bloginfo_rss('url') ?>" />
+ <id><?php bloginfo('atom_url'); ?></id>
+ <link rel="self" type="application/atom+xml" href="<?php self_link(); ?>" />
+
+ <?php do_action('atom_head'); ?>
+ <?php while (have_posts()) : the_post(); ?>
+ <entry>
+ <author>
+ <name><?php the_author() ?></name>
+ <?php $author_url = get_the_author_meta('url'); if ( !empty($author_url) ) : ?>
+ <uri><?php the_author_meta('url')?></uri>
+ <?php endif;
+ do_action('atom_author'); ?>
+ </author>
+ <title type="<?php html_type_rss(); ?>"><![CDATA[<?php the_title_rss() ?>]]></title>
+ <link rel="alternate" type="<?php bloginfo_rss('html_type'); ?>" href="<?php the_permalink_rss() ?>" />
+ <id><?php the_guid() ; ?></id>
+ <updated><?php echo get_post_modified_time('Y-m-d\TH:i:s\Z', true); ?></updated>
+ <published><?php echo get_post_time('Y-m-d\TH:i:s\Z', true); ?></published>
+ <?php the_category_rss('atom') ?>
+ <summary type="<?php html_type_rss(); ?>"><![CDATA[<?php the_excerpt_rss(); ?>]]></summary>
+<?php if ( !get_option('rss_use_excerpt') ) : ?>
+ <content type="<?php html_type_rss(); ?>" xml:base="<?php the_permalink_rss() ?>"><![CDATA[<?php the_content_feed('atom') ?>]]></content>
+<?php endif; ?>
+<?php atom_enclosure(); ?>
+<?php do_action('atom_entry'); ?>
+ <link rel="replies" type="<?php bloginfo_rss('html_type'); ?>" href="<?php the_permalink_rss() ?>#comments" thr:count="<?php echo get_comments_number()?>"/>
+ <link rel="replies" type="application/atom+xml" href="<?php echo esc_url( get_post_comments_feed_link(0, 'atom') ); ?>" thr:count="<?php echo get_comments_number()?>"/>
+ <thr:total><?php echo get_comments_number()?></thr:total>
+ </entry>
+ <?php endwhile ; ?>
+</feed>
diff --git a/src/wp-includes/feed-rdf.php b/src/wp-includes/feed-rdf.php
new file mode 100644
index 0000000000..3a0daf1fd6
--- /dev/null
+++ b/src/wp-includes/feed-rdf.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * RSS 1 RDF Feed Template for displaying RSS 1 Posts feed.
+ *
+ * @package WordPress
+ */
+
+header('Content-Type: ' . feed_content_type('rdf') . '; charset=' . get_option('blog_charset'), true);
+$more = 1;
+
+echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
+<rdf:RDF
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
+ xmlns:admin="http://webns.net/mvcb/"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ <?php do_action('rdf_ns'); ?>
+>
+<channel rdf:about="<?php bloginfo_rss("url") ?>">
+ <title><?php bloginfo_rss('name'); wp_title_rss(); ?></title>
+ <link><?php bloginfo_rss('url') ?></link>
+ <description><?php bloginfo_rss('description') ?></description>
+ <dc:date><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT'), false); ?></dc:date>
+ <sy:updatePeriod><?php echo apply_filters( 'rss_update_period', 'hourly' ); ?></sy:updatePeriod>
+ <sy:updateFrequency><?php echo apply_filters( 'rss_update_frequency', '1' ); ?></sy:updateFrequency>
+ <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
+ <?php do_action('rdf_header'); ?>
+ <items>
+ <rdf:Seq>
+ <?php while (have_posts()): the_post(); ?>
+ <rdf:li rdf:resource="<?php the_permalink_rss() ?>"/>
+ <?php endwhile; ?>
+ </rdf:Seq>
+ </items>
+</channel>
+<?php rewind_posts(); while (have_posts()): the_post(); ?>
+<item rdf:about="<?php the_permalink_rss() ?>">
+ <title><?php the_title_rss() ?></title>
+ <link><?php the_permalink_rss() ?></link>
+ <dc:date><?php echo mysql2date('Y-m-d\TH:i:s\Z', $post->post_date_gmt, false); ?></dc:date>
+ <dc:creator><?php the_author() ?></dc:creator>
+ <?php the_category_rss('rdf') ?>
+<?php if (get_option('rss_use_excerpt')) : ?>
+ <description><?php the_excerpt_rss() ?></description>
+<?php else : ?>
+ <description><?php the_excerpt_rss() ?></description>
+ <content:encoded><![CDATA[<?php the_content_feed('rdf') ?>]]></content:encoded>
+<?php endif; ?>
+ <?php do_action('rdf_item'); ?>
+</item>
+<?php endwhile; ?>
+</rdf:RDF>
diff --git a/src/wp-includes/feed-rss.php b/src/wp-includes/feed-rss.php
new file mode 100644
index 0000000000..2e6c933845
--- /dev/null
+++ b/src/wp-includes/feed-rss.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * RSS 0.92 Feed Template for displaying RSS 0.92 Posts feed.
+ *
+ * @package WordPress
+ */
+
+header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
+$more = 1;
+
+echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
+<rss version="0.92">
+<channel>
+ <title><?php bloginfo_rss('name'); wp_title_rss(); ?></title>
+ <link><?php bloginfo_rss('url') ?></link>
+ <description><?php bloginfo_rss('description') ?></description>
+ <lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>
+ <docs>http://backend.userland.com/rss092</docs>
+ <language><?php bloginfo_rss( 'language' ); ?></language>
+ <?php do_action('rss_head'); ?>
+
+<?php while (have_posts()) : the_post(); ?>
+ <item>
+ <title><?php the_title_rss() ?></title>
+ <description><![CDATA[<?php the_excerpt_rss() ?>]]></description>
+ <link><?php the_permalink_rss() ?></link>
+ <?php do_action('rss_item'); ?>
+ </item>
+<?php endwhile; ?>
+</channel>
+</rss>
diff --git a/src/wp-includes/feed-rss2-comments.php b/src/wp-includes/feed-rss2-comments.php
new file mode 100644
index 0000000000..a6a91016a6
--- /dev/null
+++ b/src/wp-includes/feed-rss2-comments.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * RSS2 Feed Template for displaying RSS2 Comments feed.
+ *
+ * @package WordPress
+ */
+
+header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
+
+echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>';
+?>
+<rss version="2.0"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
+ <?php do_action('rss2_ns'); do_action('rss2_comments_ns'); ?>
+ >
+<channel>
+ <title><?php
+ if ( is_singular() )
+ printf( ent2ncr( __( 'Comments on: %s' ) ), get_the_title_rss() );
+ elseif ( is_search() )
+ printf( ent2ncr( __( 'Comments for %1$s searching on %2$s' ) ), get_bloginfo_rss( 'name' ), get_search_query() );
+ else
+ printf( ent2ncr( __( 'Comments for %s' ) ), get_bloginfo_rss( 'name' ) . get_wp_title_rss() );
+ ?></title>
+ <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
+ <link><?php (is_single()) ? the_permalink_rss() : bloginfo_rss("url") ?></link>
+ <description><?php bloginfo_rss("description") ?></description>
+ <lastBuildDate><?php echo mysql2date('r', get_lastcommentmodified('GMT')); ?></lastBuildDate>
+ <sy:updatePeriod><?php echo apply_filters( 'rss_update_period', 'hourly' ); ?></sy:updatePeriod>
+ <sy:updateFrequency><?php echo apply_filters( 'rss_update_frequency', '1' ); ?></sy:updateFrequency>
+ <?php do_action('commentsrss2_head'); ?>
+<?php
+if ( have_comments() ) : while ( have_comments() ) : the_comment();
+ $comment_post = $GLOBALS['post'] = get_post( $comment->comment_post_ID );
+?>
+ <item>
+ <title><?php
+ if ( !is_singular() ) {
+ $title = get_the_title($comment_post->ID);
+ $title = apply_filters('the_title_rss', $title);
+ printf(ent2ncr(__('Comment on %1$s by %2$s')), $title, get_comment_author_rss());
+ } else {
+ printf(ent2ncr(__('By: %s')), get_comment_author_rss());
+ }
+ ?></title>
+ <link><?php comment_link() ?></link>
+ <dc:creator><?php echo get_comment_author_rss() ?></dc:creator>
+ <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_comment_time('Y-m-d H:i:s', true, false), false); ?></pubDate>
+ <guid isPermaLink="false"><?php comment_guid() ?></guid>
+<?php if ( post_password_required($comment_post) ) : ?>
+ <description><?php echo ent2ncr(__('Protected Comments: Please enter your password to view comments.')); ?></description>
+ <content:encoded><![CDATA[<?php echo get_the_password_form() ?>]]></content:encoded>
+<?php else : // post pass ?>
+ <description><![CDATA[<?php comment_text_rss() ?>]]></description>
+ <content:encoded><![CDATA[<?php comment_text() ?>]]></content:encoded>
+<?php endif; // post pass
+ do_action('commentrss2_item', $comment->comment_ID, $comment_post->ID);
+?>
+ </item>
+<?php endwhile; endif; ?>
+</channel>
+</rss>
diff --git a/src/wp-includes/feed-rss2.php b/src/wp-includes/feed-rss2.php
new file mode 100644
index 0000000000..a20aa1ea34
--- /dev/null
+++ b/src/wp-includes/feed-rss2.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * RSS2 Feed Template for displaying RSS2 Posts feed.
+ *
+ * @package WordPress
+ */
+
+header('Content-Type: ' . feed_content_type('rss-http') . '; charset=' . get_option('blog_charset'), true);
+$more = 1;
+
+echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
+
+<rss version="2.0"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
+ xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
+ <?php do_action('rss2_ns'); ?>
+>
+
+<channel>
+ <title><?php bloginfo_rss('name'); wp_title_rss(); ?></title>
+ <atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
+ <link><?php bloginfo_rss('url') ?></link>
+ <description><?php bloginfo_rss("description") ?></description>
+ <lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>
+ <language><?php bloginfo_rss( 'language' ); ?></language>
+ <sy:updatePeriod><?php echo apply_filters( 'rss_update_period', 'hourly' ); ?></sy:updatePeriod>
+ <sy:updateFrequency><?php echo apply_filters( 'rss_update_frequency', '1' ); ?></sy:updateFrequency>
+ <?php do_action('rss2_head'); ?>
+ <?php while( have_posts()) : the_post(); ?>
+ <item>
+ <title><?php the_title_rss() ?></title>
+ <link><?php the_permalink_rss() ?></link>
+ <comments><?php comments_link_feed(); ?></comments>
+ <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_post_time('Y-m-d H:i:s', true), false); ?></pubDate>
+ <dc:creator><?php the_author() ?></dc:creator>
+ <?php the_category_rss('rss2') ?>
+
+ <guid isPermaLink="false"><?php the_guid(); ?></guid>
+<?php if (get_option('rss_use_excerpt')) : ?>
+ <description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
+<?php else : ?>
+ <description><![CDATA[<?php the_excerpt_rss(); ?>]]></description>
+ <?php $content = get_the_content_feed('rss2'); ?>
+ <?php if ( strlen( $content ) > 0 ) : ?>
+ <content:encoded><![CDATA[<?php echo $content; ?>]]></content:encoded>
+ <?php else : ?>
+ <content:encoded><![CDATA[<?php the_excerpt_rss(); ?>]]></content:encoded>
+ <?php endif; ?>
+<?php endif; ?>
+ <wfw:commentRss><?php echo esc_url( get_post_comments_feed_link(null, 'rss2') ); ?></wfw:commentRss>
+ <slash:comments><?php echo get_comments_number(); ?></slash:comments>
+<?php rss_enclosure(); ?>
+ <?php do_action('rss2_item'); ?>
+ </item>
+ <?php endwhile; ?>
+</channel>
+</rss>
diff --git a/src/wp-includes/feed.php b/src/wp-includes/feed.php
new file mode 100644
index 0000000000..4f775aa799
--- /dev/null
+++ b/src/wp-includes/feed.php
@@ -0,0 +1,552 @@
+<?php
+/**
+ * WordPress Feed API
+ *
+ * Many of the functions used in here belong in The Loop, or The Loop for the
+ * Feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ */
+
+/**
+ * RSS container for the bloginfo function.
+ *
+ * You can retrieve anything that you can using the get_bloginfo() function.
+ * Everything will be stripped of tags and characters converted, when the values
+ * are retrieved for use in the feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 1.5.1
+ * @uses apply_filters() Calls 'get_bloginfo_rss' hook with two parameters.
+ * @see get_bloginfo() For the list of possible values to display.
+ *
+ * @param string $show See get_bloginfo() for possible values.
+ * @return string
+ */
+function get_bloginfo_rss($show = '') {
+ $info = strip_tags(get_bloginfo($show));
+ return apply_filters('get_bloginfo_rss', convert_chars($info), $show);
+}
+
+/**
+ * Display RSS container for the bloginfo function.
+ *
+ * You can retrieve anything that you can using the get_bloginfo() function.
+ * Everything will be stripped of tags and characters converted, when the values
+ * are retrieved for use in the feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 0.71
+ * @uses apply_filters() Calls 'bloginfo_rss' hook with two parameters.
+ * @see get_bloginfo() For the list of possible values to display.
+ *
+ * @param string $show See get_bloginfo() for possible values.
+ */
+function bloginfo_rss($show = '') {
+ echo apply_filters('bloginfo_rss', get_bloginfo_rss($show), $show);
+}
+
+/**
+ * Retrieve the default feed.
+ *
+ * The default feed is 'rss2', unless a plugin changes it through the
+ * 'default_feed' filter.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5
+ * @uses apply_filters() Calls 'default_feed' hook on the default feed string.
+ *
+ * @return string Default feed, or for example 'rss2', 'atom', etc.
+ */
+function get_default_feed() {
+ $default_feed = apply_filters('default_feed', 'rss2');
+ return 'rss' == $default_feed ? 'rss2' : $default_feed;
+}
+
+/**
+ * Retrieve the blog title for the feed title.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.2.0
+ * @uses apply_filters() Calls 'get_wp_title_rss' hook on title.
+ * @uses wp_title() See function for $sep parameter usage.
+ *
+ * @param string $sep Optional.How to separate the title. See wp_title() for more info.
+ * @return string Error message on failure or blog title on success.
+ */
+function get_wp_title_rss($sep = '&#187;') {
+ $title = wp_title($sep, false);
+ if ( is_wp_error( $title ) )
+ return $title->get_error_message();
+ $title = apply_filters( 'get_wp_title_rss', $title, $sep );
+ return $title;
+}
+
+/**
+ * Display the blog title for display of the feed title.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.2.0
+ * @uses apply_filters() Calls 'wp_title_rss' on the blog title.
+ * @see wp_title() $sep parameter usage.
+ *
+ * @param string $sep Optional.
+ */
+function wp_title_rss( $sep = '&#187;' ) {
+ echo apply_filters( 'wp_title_rss', get_wp_title_rss( $sep ), $sep );
+}
+
+/**
+ * Retrieve the current post title for the feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'the_title_rss' on the post title.
+ *
+ * @return string Current post title.
+ */
+function get_the_title_rss() {
+ $title = get_the_title();
+ $title = apply_filters('the_title_rss', $title);
+ return $title;
+}
+
+/**
+ * Display the post title in the feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 0.71
+ * @uses get_the_title_rss() Used to retrieve current post title.
+ */
+function the_title_rss() {
+ echo get_the_title_rss();
+}
+
+/**
+ * Retrieve the post content for feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.9.0
+ * @uses apply_filters() Calls 'the_content_feed' on the content before processing.
+ * @see get_the_content()
+ *
+ * @param string $feed_type The type of feed. rss2 | atom | rss | rdf
+ * @return string The filtered content.
+ */
+function get_the_content_feed($feed_type = null) {
+ if ( !$feed_type )
+ $feed_type = get_default_feed();
+
+ $content = apply_filters('the_content', get_the_content());
+ $content = str_replace(']]>', ']]&gt;', $content);
+ return apply_filters('the_content_feed', $content, $feed_type);
+}
+
+/**
+ * Display the post content for feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.9.0
+ * @uses apply_filters() Calls 'the_content_feed' on the content before processing.
+ * @see get_the_content()
+ *
+ * @param string $feed_type The type of feed. rss2 | atom | rss | rdf
+ */
+function the_content_feed($feed_type = null) {
+ echo get_the_content_feed($feed_type);
+}
+
+/**
+ * Display the post excerpt for the feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 0.71
+ * @uses apply_filters() Calls 'the_excerpt_rss' hook on the excerpt.
+ */
+function the_excerpt_rss() {
+ $output = get_the_excerpt();
+ echo apply_filters('the_excerpt_rss', $output);
+}
+
+/**
+ * Display the permalink to the post for use in feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.3.0
+ * @uses apply_filters() Call 'the_permalink_rss' on the post permalink
+ */
+function the_permalink_rss() {
+ echo esc_url( apply_filters('the_permalink_rss', get_permalink() ));
+}
+
+/**
+ * Outputs the link to the comments for the current post in an xml safe way
+ *
+ * @since 3.0.0
+ * @return none
+ */
+function comments_link_feed() {
+ echo esc_url( apply_filters( 'comments_link_feed', get_comments_link() ) );
+}
+
+/**
+ * Display the feed GUID for the current comment.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param int|object $comment_id Optional comment object or id. Defaults to global comment object.
+ */
+function comment_guid($comment_id = null) {
+ echo esc_url( get_comment_guid($comment_id) );
+}
+
+/**
+ * Retrieve the feed GUID for the current comment.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param int|object $comment_id Optional comment object or id. Defaults to global comment object.
+ * @return bool|string false on failure or guid for comment on success.
+ */
+function get_comment_guid($comment_id = null) {
+ $comment = get_comment($comment_id);
+
+ if ( !is_object($comment) )
+ return false;
+
+ return get_the_guid($comment->comment_post_ID) . '#comment-' . $comment->comment_ID;
+}
+
+/**
+ * Display the link to the comments.
+ *
+ * @since 1.5.0
+ */
+function comment_link() {
+ echo esc_url( apply_filters( 'comment_link', get_comment_link() ) );
+}
+
+/**
+ * Retrieve the current comment author for use in the feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'comment_author_rss' hook on comment author.
+ * @uses get_comment_author()
+ *
+ * @return string Comment Author
+ */
+function get_comment_author_rss() {
+ return apply_filters('comment_author_rss', get_comment_author() );
+}
+
+/**
+ * Display the current comment author in the feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 1.0.0
+ */
+function comment_author_rss() {
+ echo get_comment_author_rss();
+}
+
+/**
+ * Display the current comment content for use in the feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 1.0.0
+ * @uses apply_filters() Calls 'comment_text_rss' filter on comment content.
+ * @uses get_comment_text()
+ */
+function comment_text_rss() {
+ $comment_text = get_comment_text();
+ $comment_text = apply_filters('comment_text_rss', $comment_text);
+ echo $comment_text;
+}
+
+/**
+ * Retrieve all of the post categories, formatted for use in feeds.
+ *
+ * All of the categories for the current post in the feed loop, will be
+ * retrieved and have feed markup added, so that they can easily be added to the
+ * RSS2, Atom, or RSS1 and RSS0.91 RDF feeds.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.1.0
+ * @uses apply_filters()
+ *
+ * @param string $type Optional, default is the type returned by get_default_feed().
+ * @return string All of the post categories for displaying in the feed.
+ */
+function get_the_category_rss($type = null) {
+ if ( empty($type) )
+ $type = get_default_feed();
+ $categories = get_the_category();
+ $tags = get_the_tags();
+ $the_list = '';
+ $cat_names = array();
+
+ $filter = 'rss';
+ if ( 'atom' == $type )
+ $filter = 'raw';
+
+ if ( !empty($categories) ) foreach ( (array) $categories as $category ) {
+ $cat_names[] = sanitize_term_field('name', $category->name, $category->term_id, 'category', $filter);
+ }
+
+ if ( !empty($tags) ) foreach ( (array) $tags as $tag ) {
+ $cat_names[] = sanitize_term_field('name', $tag->name, $tag->term_id, 'post_tag', $filter);
+ }
+
+ $cat_names = array_unique($cat_names);
+
+ foreach ( $cat_names as $cat_name ) {
+ if ( 'rdf' == $type )
+ $the_list .= "\t\t<dc:subject><![CDATA[$cat_name]]></dc:subject>\n";
+ elseif ( 'atom' == $type )
+ $the_list .= sprintf( '<category scheme="%1$s" term="%2$s" />', esc_attr( apply_filters( 'get_bloginfo_rss', get_bloginfo( 'url' ) ) ), esc_attr( $cat_name ) );
+ else
+ $the_list .= "\t\t<category><![CDATA[" . @html_entity_decode( $cat_name, ENT_COMPAT, get_option('blog_charset') ) . "]]></category>\n";
+ }
+
+ return apply_filters('the_category_rss', $the_list, $type);
+}
+
+/**
+ * Display the post categories in the feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 0.71
+ * @see get_the_category_rss() For better explanation.
+ *
+ * @param string $type Optional, default is the type returned by get_default_feed().
+ */
+function the_category_rss($type = null) {
+ echo get_the_category_rss($type);
+}
+
+/**
+ * Display the HTML type based on the blog setting.
+ *
+ * The two possible values are either 'xhtml' or 'html'.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.2.0
+ */
+function html_type_rss() {
+ $type = get_bloginfo('html_type');
+ if (strpos($type, 'xhtml') !== false)
+ $type = 'xhtml';
+ else
+ $type = 'html';
+ echo $type;
+}
+
+/**
+ * Display the rss enclosure for the current post.
+ *
+ * Uses the global $post to check whether the post requires a password and if
+ * the user has the password for the post. If not then it will return before
+ * displaying.
+ *
+ * Also uses the function get_post_custom() to get the post's 'enclosure'
+ * metadata field and parses the value to display the enclosure(s). The
+ * enclosure(s) consist of enclosure HTML tag(s) with a URI and other
+ * attributes.
+ *
+ * @package WordPress
+ * @subpackage Template
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'rss_enclosure' hook on rss enclosure.
+ * @uses get_post_custom() To get the current post enclosure metadata.
+ */
+function rss_enclosure() {
+ if ( post_password_required() )
+ return;
+
+ foreach ( (array) get_post_custom() as $key => $val) {
+ if ($key == 'enclosure') {
+ foreach ( (array) $val as $enc ) {
+ $enclosure = explode("\n", $enc);
+
+ // only get the first element, e.g. audio/mpeg from 'audio/mpeg mpga mp2 mp3'
+ $t = preg_split('/[ \t]/', trim($enclosure[2]) );
+ $type = $t[0];
+
+ echo apply_filters('rss_enclosure', '<enclosure url="' . trim(htmlspecialchars($enclosure[0])) . '" length="' . trim($enclosure[1]) . '" type="' . $type . '" />' . "\n");
+ }
+ }
+ }
+}
+
+/**
+ * Display the atom enclosure for the current post.
+ *
+ * Uses the global $post to check whether the post requires a password and if
+ * the user has the password for the post. If not then it will return before
+ * displaying.
+ *
+ * Also uses the function get_post_custom() to get the post's 'enclosure'
+ * metadata field and parses the value to display the enclosure(s). The
+ * enclosure(s) consist of link HTML tag(s) with a URI and other attributes.
+ *
+ * @package WordPress
+ * @subpackage Template
+ * @since 2.2.0
+ * @uses apply_filters() Calls 'atom_enclosure' hook on atom enclosure.
+ * @uses get_post_custom() To get the current post enclosure metadata.
+ */
+function atom_enclosure() {
+ if ( post_password_required() )
+ return;
+
+ foreach ( (array) get_post_custom() as $key => $val ) {
+ if ($key == 'enclosure') {
+ foreach ( (array) $val as $enc ) {
+ $enclosure = explode("\n", $enc);
+ echo apply_filters('atom_enclosure', '<link href="' . trim(htmlspecialchars($enclosure[0])) . '" rel="enclosure" length="' . trim($enclosure[1]) . '" type="' . trim($enclosure[2]) . '" />' . "\n");
+ }
+ }
+ }
+}
+
+/**
+ * Determine the type of a string of data with the data formatted.
+ *
+ * Tell whether the type is text, html, or xhtml, per RFC 4287 section 3.1.
+ *
+ * In the case of WordPress, text is defined as containing no markup,
+ * xhtml is defined as "well formed", and html as tag soup (i.e., the rest).
+ *
+ * Container div tags are added to xhtml values, per section 3.1.1.3.
+ *
+ * @link http://www.atomenabled.org/developers/syndication/atom-format-spec.php#rfc.section.3.1
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5
+ *
+ * @param string $data Input string
+ * @return array array(type, value)
+ */
+function prep_atom_text_construct($data) {
+ if (strpos($data, '<') === false && strpos($data, '&') === false) {
+ return array('text', $data);
+ }
+
+ $parser = xml_parser_create();
+ xml_parse($parser, '<div>' . $data . '</div>', true);
+ $code = xml_get_error_code($parser);
+ xml_parser_free($parser);
+
+ if (!$code) {
+ if (strpos($data, '<') === false) {
+ return array('text', $data);
+ } else {
+ $data = "<div xmlns='http://www.w3.org/1999/xhtml'>$data</div>";
+ return array('xhtml', $data);
+ }
+ }
+
+ if (strpos($data, ']]>') == false) {
+ return array('html', "<![CDATA[$data]]>");
+ } else {
+ return array('html', htmlspecialchars($data));
+ }
+}
+
+/**
+ * Display the link for the currently displayed feed in a XSS safe way.
+ *
+ * Generate a correct link for the atom:self element.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5
+ */
+function self_link() {
+ $host = @parse_url(home_url());
+ echo esc_url( apply_filters( 'self_link', set_url_scheme( 'http://' . $host['host'] . wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) );
+}
+
+/**
+ * Return the content type for specified feed type.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.8.0
+ */
+function feed_content_type( $type = '' ) {
+ if ( empty($type) )
+ $type = get_default_feed();
+
+ $types = array(
+ 'rss' => 'application/rss+xml',
+ 'rss2' => 'application/rss+xml',
+ 'rss-http' => 'text/xml',
+ 'atom' => 'application/atom+xml',
+ 'rdf' => 'application/rdf+xml'
+ );
+
+ $content_type = ( !empty($types[$type]) ) ? $types[$type] : 'application/octet-stream';
+
+ return apply_filters( 'feed_content_type', $content_type, $type );
+}
+
+/**
+ * Build SimplePie object based on RSS or Atom feed from URL.
+ *
+ * @since 2.8
+ *
+ * @param mixed $url URL of feed to retrieve. If an array of URLs, the feeds are merged
+ * using SimplePie's multifeed feature.
+ * See also {@link ​http://simplepie.org/wiki/faq/typical_multifeed_gotchas}
+ *
+ * @return WP_Error|SimplePie WP_Error object on failure or SimplePie object on success
+ */
+function fetch_feed( $url ) {
+ require_once ( ABSPATH . WPINC . '/class-feed.php' );
+
+ $feed = new SimplePie();
+
+ $feed->set_sanitize_class( 'WP_SimplePie_Sanitize_KSES' );
+ // We must manually overwrite $feed->sanitize because SimplePie's
+ // constructor sets it before we have a chance to set the sanitization class
+ $feed->sanitize = new WP_SimplePie_Sanitize_KSES();
+
+ $feed->set_cache_class( 'WP_Feed_Cache' );
+ $feed->set_file_class( 'WP_SimplePie_File' );
+
+ $feed->set_feed_url( $url );
+ $feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $url ) );
+ do_action_ref_array( 'wp_feed_options', array( &$feed, $url ) );
+ $feed->init();
+ $feed->handle_content_type();
+
+ if ( $feed->error() )
+ return new WP_Error( 'simplepie-error', $feed->error() );
+
+ return $feed;
+}
diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php
new file mode 100644
index 0000000000..98bae804b1
--- /dev/null
+++ b/src/wp-includes/formatting.php
@@ -0,0 +1,3432 @@
+<?php
+/**
+ * Main WordPress Formatting API.
+ *
+ * Handles many functions for formatting output.
+ *
+ * @package WordPress
+ */
+
+/**
+ * Replaces common plain text characters into formatted entities
+ *
+ * As an example,
+ * <code>
+ * 'cause today's effort makes it worth tomorrow's "holiday"...
+ * </code>
+ * Becomes:
+ * <code>
+ * &#8217;cause today&#8217;s effort makes it worth tomorrow&#8217;s &#8220;holiday&#8221;&#8230;
+ * </code>
+ * Code within certain html blocks are skipped.
+ *
+ * @since 0.71
+ * @uses $wp_cockneyreplace Array of formatted entities for certain common phrases
+ *
+ * @param string $text The text to be formatted
+ * @return string The string replaced with html entities
+ */
+function wptexturize($text) {
+ global $wp_cockneyreplace;
+ static $static_characters, $static_replacements, $dynamic_characters, $dynamic_replacements,
+ $default_no_texturize_tags, $default_no_texturize_shortcodes;
+
+ // No need to set up these static variables more than once
+ if ( ! isset( $static_characters ) ) {
+ /* translators: opening curly double quote */
+ $opening_quote = _x( '&#8220;', 'opening curly double quote' );
+ /* translators: closing curly double quote */
+ $closing_quote = _x( '&#8221;', 'closing curly double quote' );
+
+ /* translators: apostrophe, for example in 'cause or can't */
+ $apos = _x( '&#8217;', 'apostrophe' );
+
+ /* translators: prime, for example in 9' (nine feet) */
+ $prime = _x( '&#8242;', 'prime' );
+ /* translators: double prime, for example in 9" (nine inches) */
+ $double_prime = _x( '&#8243;', 'double prime' );
+
+ /* translators: opening curly single quote */
+ $opening_single_quote = _x( '&#8216;', 'opening curly single quote' );
+ /* translators: closing curly single quote */
+ $closing_single_quote = _x( '&#8217;', 'closing curly single quote' );
+
+ /* translators: en dash */
+ $en_dash = _x( '&#8211;', 'en dash' );
+ /* translators: em dash */
+ $em_dash = _x( '&#8212;', 'em dash' );
+
+ $default_no_texturize_tags = array('pre', 'code', 'kbd', 'style', 'script', 'tt');
+ $default_no_texturize_shortcodes = array('code');
+
+ // if a plugin has provided an autocorrect array, use it
+ if ( isset($wp_cockneyreplace) ) {
+ $cockney = array_keys($wp_cockneyreplace);
+ $cockneyreplace = array_values($wp_cockneyreplace);
+ } elseif ( "'" != $apos ) { // Only bother if we're doing a replacement.
+ $cockney = array( "'tain't", "'twere", "'twas", "'tis", "'twill", "'til", "'bout", "'nuff", "'round", "'cause" );
+ $cockneyreplace = array( $apos . "tain" . $apos . "t", $apos . "twere", $apos . "twas", $apos . "tis", $apos . "twill", $apos . "til", $apos . "bout", $apos . "nuff", $apos . "round", $apos . "cause" );
+ } else {
+ $cockney = $cockneyreplace = array();
+ }
+
+ $static_characters = array_merge( array( '---', ' -- ', '--', ' - ', 'xn&#8211;', '...', '``', '\'\'', ' (tm)' ), $cockney );
+ $static_replacements = array_merge( array( $em_dash, ' ' . $em_dash . ' ', $en_dash, ' ' . $en_dash . ' ', 'xn--', '&#8230;', $opening_quote, $closing_quote, ' &#8482;' ), $cockneyreplace );
+
+ $dynamic = array();
+ if ( "'" != $apos ) {
+ $dynamic[ '/\'(\d\d(?:&#8217;|\')?s)/' ] = $apos . '$1'; // '99's
+ $dynamic[ '/\'(\d)/' ] = $apos . '$1'; // '99
+ }
+ if ( "'" != $opening_single_quote )
+ $dynamic[ '/(\s|\A|[([{<]|")\'/' ] = '$1' . $opening_single_quote; // opening single quote, even after (, {, <, [
+ if ( '"' != $double_prime )
+ $dynamic[ '/(\d)"/' ] = '$1' . $double_prime; // 9" (double prime)
+ if ( "'" != $prime )
+ $dynamic[ '/(\d)\'/' ] = '$1' . $prime; // 9' (prime)
+ if ( "'" != $apos )
+ $dynamic[ '/(\S)\'([^\'\s])/' ] = '$1' . $apos . '$2'; // apostrophe in a word
+ if ( '"' != $opening_quote )
+ $dynamic[ '/(\s|\A|[([{<])"(?!\s)/' ] = '$1' . $opening_quote . '$2'; // opening double quote, even after (, {, <, [
+ if ( '"' != $closing_quote )
+ $dynamic[ '/"(\s|\S|\Z)/' ] = $closing_quote . '$1'; // closing double quote
+ if ( "'" != $closing_single_quote )
+ $dynamic[ '/\'([\s.]|\Z)/' ] = $closing_single_quote . '$1'; // closing single quote
+
+ $dynamic[ '/\b(\d+)x(\d+)\b/' ] = '$1&#215;$2'; // 9x9 (times)
+
+ $dynamic_characters = array_keys( $dynamic );
+ $dynamic_replacements = array_values( $dynamic );
+ }
+
+ // Transform into regexp sub-expression used in _wptexturize_pushpop_element
+ // Must do this every time in case plugins use these filters in a context sensitive manner
+ $no_texturize_tags = '(' . implode('|', apply_filters('no_texturize_tags', $default_no_texturize_tags) ) . ')';
+ $no_texturize_shortcodes = '(' . implode('|', apply_filters('no_texturize_shortcodes', $default_no_texturize_shortcodes) ) . ')';
+
+ $no_texturize_tags_stack = array();
+ $no_texturize_shortcodes_stack = array();
+
+ $textarr = preg_split('/(<.*>|\[.*\])/Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ foreach ( $textarr as &$curl ) {
+ if ( empty( $curl ) )
+ continue;
+
+ // Only call _wptexturize_pushpop_element if first char is correct tag opening
+ $first = $curl[0];
+ if ( '<' === $first ) {
+ _wptexturize_pushpop_element($curl, $no_texturize_tags_stack, $no_texturize_tags, '<', '>');
+ } elseif ( '[' === $first ) {
+ _wptexturize_pushpop_element($curl, $no_texturize_shortcodes_stack, $no_texturize_shortcodes, '[', ']');
+ } elseif ( empty($no_texturize_shortcodes_stack) && empty($no_texturize_tags_stack) ) {
+ // This is not a tag, nor is the texturization disabled static strings
+ $curl = str_replace($static_characters, $static_replacements, $curl);
+ // regular expressions
+ $curl = preg_replace($dynamic_characters, $dynamic_replacements, $curl);
+ }
+ $curl = preg_replace('/&([^#])(?![a-zA-Z1-4]{1,8};)/', '&#038;$1', $curl);
+ }
+ return implode( '', $textarr );
+}
+
+/**
+ * Search for disabled element tags. Push element to stack on tag open and pop
+ * on tag close. Assumes first character of $text is tag opening.
+ *
+ * @since 2.9.0
+ * @access private
+ *
+ * @param string $text Text to check. First character is assumed to be $opening
+ * @param array $stack Array used as stack of opened tag elements
+ * @param string $disabled_elements Tags to match against formatted as regexp sub-expression
+ * @param string $opening Tag opening character, assumed to be 1 character long
+ * @param string $closing Tag closing character
+ */
+function _wptexturize_pushpop_element($text, &$stack, $disabled_elements, $opening = '<', $closing = '>') {
+ // Check if it is a closing tag -- otherwise assume opening tag
+ if (strncmp($opening . '/', $text, 2)) {
+ // Opening? Check $text+1 against disabled elements
+ if (preg_match('/^' . $disabled_elements . '\b/', substr($text, 1), $matches)) {
+ /*
+ * This disables texturize until we find a closing tag of our type
+ * (e.g. <pre>) even if there was invalid nesting before that
+ *
+ * Example: in the case <pre>sadsadasd</code>"baba"</pre>
+ * "baba" won't be texturize
+ */
+
+ array_push($stack, $matches[1]);
+ }
+ } else {
+ // Closing? Check $text+2 against disabled elements
+ $c = preg_quote($closing, '/');
+ if (preg_match('/^' . $disabled_elements . $c . '/', substr($text, 2), $matches)) {
+ $last = array_pop($stack);
+
+ // Make sure it matches the opening tag
+ if ($last != $matches[1])
+ array_push($stack, $last);
+ }
+ }
+}
+
+/**
+ * Replaces double line-breaks with paragraph elements.
+ *
+ * A group of regex replaces used to identify text formatted with newlines and
+ * replace double line-breaks with HTML paragraph tags. The remaining
+ * line-breaks after conversion become <<br />> tags, unless $br is set to '0'
+ * or 'false'.
+ *
+ * @since 0.71
+ *
+ * @param string $pee The text which has to be formatted.
+ * @param bool $br Optional. If set, this will convert all remaining line-breaks after paragraphing. Default true.
+ * @return string Text which has been converted into correct paragraph tags.
+ */
+function wpautop($pee, $br = true) {
+ $pre_tags = array();
+
+ if ( trim($pee) === '' )
+ return '';
+
+ $pee = $pee . "\n"; // just to make things a little easier, pad the end
+
+ if ( strpos($pee, '<pre') !== false ) {
+ $pee_parts = explode( '</pre>', $pee );
+ $last_pee = array_pop($pee_parts);
+ $pee = '';
+ $i = 0;
+
+ foreach ( $pee_parts as $pee_part ) {
+ $start = strpos($pee_part, '<pre');
+
+ // Malformed html?
+ if ( $start === false ) {
+ $pee .= $pee_part;
+ continue;
+ }
+
+ $name = "<pre wp-pre-tag-$i></pre>";
+ $pre_tags[$name] = substr( $pee_part, $start ) . '</pre>';
+
+ $pee .= substr( $pee_part, 0, $start ) . $name;
+ $i++;
+ }
+
+ $pee .= $last_pee;
+ }
+
+ $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
+ // Space things out a little
+ $allblocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|option|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|noscript|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)';
+ $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
+ $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
+ $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
+ if ( strpos($pee, '<object') !== false ) {
+ $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
+ $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
+ }
+ $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
+ // make paragraphs, including one at the end
+ $pees = preg_split('/\n\s*\n/', $pee, -1, PREG_SPLIT_NO_EMPTY);
+ $pee = '';
+ foreach ( $pees as $tinkle )
+ $pee .= '<p>' . trim($tinkle, "\n") . "</p>\n";
+ $pee = preg_replace('|<p>\s*</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
+ $pee = preg_replace('!<p>([^<]+)</(div|address|form)>!', "<p>$1</p></$2>", $pee);
+ $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
+ $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
+ $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
+ $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
+ $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
+ $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
+ if ( $br ) {
+ $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', '_autop_newline_preservation_helper', $pee);
+ $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
+ $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
+ }
+ $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
+ $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
+ $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
+
+ if ( !empty($pre_tags) )
+ $pee = str_replace(array_keys($pre_tags), array_values($pre_tags), $pee);
+
+ return $pee;
+}
+
+/**
+ * Newline preservation help function for wpautop
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param array $matches preg_replace_callback matches array
+ * @return string
+ */
+function _autop_newline_preservation_helper( $matches ) {
+ return str_replace("\n", "<WPPreserveNewline />", $matches[0]);
+}
+
+/**
+ * Don't auto-p wrap shortcodes that stand alone
+ *
+ * Ensures that shortcodes are not wrapped in <<p>>...<</p>>.
+ *
+ * @since 2.9.0
+ *
+ * @param string $pee The content.
+ * @return string The filtered content.
+ */
+function shortcode_unautop( $pee ) {
+ global $shortcode_tags;
+
+ if ( empty( $shortcode_tags ) || !is_array( $shortcode_tags ) ) {
+ return $pee;
+ }
+
+ $tagregexp = join( '|', array_map( 'preg_quote', array_keys( $shortcode_tags ) ) );
+
+ $pattern =
+ '/'
+ . '<p>' // Opening paragraph
+ . '\\s*+' // Optional leading whitespace
+ . '(' // 1: The shortcode
+ . '\\[' // Opening bracket
+ . "($tagregexp)" // 2: Shortcode name
+ . '(?![\\w-])' // Not followed by word character or hyphen
+ // Unroll the loop: Inside the opening shortcode tag
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash
+ . '(?:'
+ . '\\/(?!\\])' // A forward slash not followed by a closing bracket
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash
+ . ')*?'
+ . '(?:'
+ . '\\/\\]' // Self closing tag and closing bracket
+ . '|'
+ . '\\]' // Closing bracket
+ . '(?:' // Unroll the loop: Optionally, anything between the opening and closing shortcode tags
+ . '[^\\[]*+' // Not an opening bracket
+ . '(?:'
+ . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
+ . '[^\\[]*+' // Not an opening bracket
+ . ')*+'
+ . '\\[\\/\\2\\]' // Closing shortcode tag
+ . ')?'
+ . ')'
+ . ')'
+ . '\\s*+' // optional trailing whitespace
+ . '<\\/p>' // closing paragraph
+ . '/s';
+
+ return preg_replace( $pattern, '$1', $pee );
+}
+
+/**
+ * Checks to see if a string is utf8 encoded.
+ *
+ * NOTE: This function checks for 5-Byte sequences, UTF8
+ * has Bytes Sequences with a maximum length of 4.
+ *
+ * @author bmorel at ssi dot fr (modified)
+ * @since 1.2.1
+ *
+ * @param string $str The string to be checked
+ * @return bool True if $str fits a UTF-8 model, false otherwise.
+ */
+function seems_utf8($str) {
+ $length = strlen($str);
+ for ($i=0; $i < $length; $i++) {
+ $c = ord($str[$i]);
+ if ($c < 0x80) $n = 0; # 0bbbbbbb
+ elseif (($c & 0xE0) == 0xC0) $n=1; # 110bbbbb
+ elseif (($c & 0xF0) == 0xE0) $n=2; # 1110bbbb
+ elseif (($c & 0xF8) == 0xF0) $n=3; # 11110bbb
+ elseif (($c & 0xFC) == 0xF8) $n=4; # 111110bb
+ elseif (($c & 0xFE) == 0xFC) $n=5; # 1111110b
+ else return false; # Does not match any model
+ for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ?
+ if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Converts a number of special characters into their HTML entities.
+ *
+ * Specifically deals with: &, <, >, ", and '.
+ *
+ * $quote_style can be set to ENT_COMPAT to encode " to
+ * &quot;, or ENT_QUOTES to do both. Default is ENT_NOQUOTES where no quotes are encoded.
+ *
+ * @since 1.2.2
+ * @access private
+ *
+ * @param string $string The text which is to be encoded.
+ * @param mixed $quote_style Optional. Converts double quotes if set to ENT_COMPAT, both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES. Also compatible with old values; converting single quotes if set to 'single', double if set to 'double' or both if otherwise set. Default is ENT_NOQUOTES.
+ * @param string $charset Optional. The character encoding of the string. Default is false.
+ * @param boolean $double_encode Optional. Whether to encode existing html entities. Default is false.
+ * @return string The encoded text with HTML entities.
+ */
+function _wp_specialchars( $string, $quote_style = ENT_NOQUOTES, $charset = false, $double_encode = false ) {
+ $string = (string) $string;
+
+ if ( 0 === strlen( $string ) )
+ return '';
+
+ // Don't bother if there are no specialchars - saves some processing
+ if ( ! preg_match( '/[&<>"\']/', $string ) )
+ return $string;
+
+ // Account for the previous behaviour of the function when the $quote_style is not an accepted value
+ if ( empty( $quote_style ) )
+ $quote_style = ENT_NOQUOTES;
+ elseif ( ! in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) )
+ $quote_style = ENT_QUOTES;
+
+ // Store the site charset as a static to avoid multiple calls to wp_load_alloptions()
+ if ( ! $charset ) {
+ static $_charset;
+ if ( ! isset( $_charset ) ) {
+ $alloptions = wp_load_alloptions();
+ $_charset = isset( $alloptions['blog_charset'] ) ? $alloptions['blog_charset'] : '';
+ }
+ $charset = $_charset;
+ }
+
+ if ( in_array( $charset, array( 'utf8', 'utf-8', 'UTF8' ) ) )
+ $charset = 'UTF-8';
+
+ $_quote_style = $quote_style;
+
+ if ( $quote_style === 'double' ) {
+ $quote_style = ENT_COMPAT;
+ $_quote_style = ENT_COMPAT;
+ } elseif ( $quote_style === 'single' ) {
+ $quote_style = ENT_NOQUOTES;
+ }
+
+ // Handle double encoding ourselves
+ if ( $double_encode ) {
+ $string = @htmlspecialchars( $string, $quote_style, $charset );
+ } else {
+ // Decode &amp; into &
+ $string = wp_specialchars_decode( $string, $_quote_style );
+
+ // Guarantee every &entity; is valid or re-encode the &
+ $string = wp_kses_normalize_entities( $string );
+
+ // Now re-encode everything except &entity;
+ $string = preg_split( '/(&#?x?[0-9a-z]+;)/i', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
+
+ for ( $i = 0; $i < count( $string ); $i += 2 )
+ $string[$i] = @htmlspecialchars( $string[$i], $quote_style, $charset );
+
+ $string = implode( '', $string );
+ }
+
+ // Backwards compatibility
+ if ( 'single' === $_quote_style )
+ $string = str_replace( "'", '&#039;', $string );
+
+ return $string;
+}
+
+/**
+ * Converts a number of HTML entities into their special characters.
+ *
+ * Specifically deals with: &, <, >, ", and '.
+ *
+ * $quote_style can be set to ENT_COMPAT to decode " entities,
+ * or ENT_QUOTES to do both " and '. Default is ENT_NOQUOTES where no quotes are decoded.
+ *
+ * @since 2.8.0
+ *
+ * @param string $string The text which is to be decoded.
+ * @param mixed $quote_style Optional. Converts double quotes if set to ENT_COMPAT, both single and double if set to ENT_QUOTES or none if set to ENT_NOQUOTES. Also compatible with old _wp_specialchars() values; converting single quotes if set to 'single', double if set to 'double' or both if otherwise set. Default is ENT_NOQUOTES.
+ * @return string The decoded text without HTML entities.
+ */
+function wp_specialchars_decode( $string, $quote_style = ENT_NOQUOTES ) {
+ $string = (string) $string;
+
+ if ( 0 === strlen( $string ) ) {
+ return '';
+ }
+
+ // Don't bother if there are no entities - saves a lot of processing
+ if ( strpos( $string, '&' ) === false ) {
+ return $string;
+ }
+
+ // Match the previous behaviour of _wp_specialchars() when the $quote_style is not an accepted value
+ if ( empty( $quote_style ) ) {
+ $quote_style = ENT_NOQUOTES;
+ } elseif ( !in_array( $quote_style, array( 0, 2, 3, 'single', 'double' ), true ) ) {
+ $quote_style = ENT_QUOTES;
+ }
+
+ // More complete than get_html_translation_table( HTML_SPECIALCHARS )
+ $single = array( '&#039;' => '\'', '&#x27;' => '\'' );
+ $single_preg = array( '/&#0*39;/' => '&#039;', '/&#x0*27;/i' => '&#x27;' );
+ $double = array( '&quot;' => '"', '&#034;' => '"', '&#x22;' => '"' );
+ $double_preg = array( '/&#0*34;/' => '&#034;', '/&#x0*22;/i' => '&#x22;' );
+ $others = array( '&lt;' => '<', '&#060;' => '<', '&gt;' => '>', '&#062;' => '>', '&amp;' => '&', '&#038;' => '&', '&#x26;' => '&' );
+ $others_preg = array( '/&#0*60;/' => '&#060;', '/&#0*62;/' => '&#062;', '/&#0*38;/' => '&#038;', '/&#x0*26;/i' => '&#x26;' );
+
+ if ( $quote_style === ENT_QUOTES ) {
+ $translation = array_merge( $single, $double, $others );
+ $translation_preg = array_merge( $single_preg, $double_preg, $others_preg );
+ } elseif ( $quote_style === ENT_COMPAT || $quote_style === 'double' ) {
+ $translation = array_merge( $double, $others );
+ $translation_preg = array_merge( $double_preg, $others_preg );
+ } elseif ( $quote_style === 'single' ) {
+ $translation = array_merge( $single, $others );
+ $translation_preg = array_merge( $single_preg, $others_preg );
+ } elseif ( $quote_style === ENT_NOQUOTES ) {
+ $translation = $others;
+ $translation_preg = $others_preg;
+ }
+
+ // Remove zero padding on numeric entities
+ $string = preg_replace( array_keys( $translation_preg ), array_values( $translation_preg ), $string );
+
+ // Replace characters according to translation table
+ return strtr( $string, $translation );
+}
+
+/**
+ * Checks for invalid UTF8 in a string.
+ *
+ * @since 2.8.0
+ *
+ * @param string $string The text which is to be checked.
+ * @param boolean $strip Optional. Whether to attempt to strip out invalid UTF8. Default is false.
+ * @return string The checked text.
+ */
+function wp_check_invalid_utf8( $string, $strip = false ) {
+ $string = (string) $string;
+
+ if ( 0 === strlen( $string ) ) {
+ return '';
+ }
+
+ // Store the site charset as a static to avoid multiple calls to get_option()
+ static $is_utf8;
+ if ( !isset( $is_utf8 ) ) {
+ $is_utf8 = in_array( get_option( 'blog_charset' ), array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) );
+ }
+ if ( !$is_utf8 ) {
+ return $string;
+ }
+
+ // Check for support for utf8 in the installed PCRE library once and store the result in a static
+ static $utf8_pcre;
+ if ( !isset( $utf8_pcre ) ) {
+ $utf8_pcre = @preg_match( '/^./u', 'a' );
+ }
+ // We can't demand utf8 in the PCRE installation, so just return the string in those cases
+ if ( !$utf8_pcre ) {
+ return $string;
+ }
+
+ // preg_match fails when it encounters invalid UTF8 in $string
+ if ( 1 === @preg_match( '/^./us', $string ) ) {
+ return $string;
+ }
+
+ // Attempt to strip the bad chars if requested (not recommended)
+ if ( $strip && function_exists( 'iconv' ) ) {
+ return iconv( 'utf-8', 'utf-8', $string );
+ }
+
+ return '';
+}
+
+/**
+ * Encode the Unicode values to be used in the URI.
+ *
+ * @since 1.5.0
+ *
+ * @param string $utf8_string
+ * @param int $length Max length of the string
+ * @return string String with Unicode encoded for URI.
+ */
+function utf8_uri_encode( $utf8_string, $length = 0 ) {
+ $unicode = '';
+ $values = array();
+ $num_octets = 1;
+ $unicode_length = 0;
+
+ $string_length = strlen( $utf8_string );
+ for ($i = 0; $i < $string_length; $i++ ) {
+
+ $value = ord( $utf8_string[ $i ] );
+
+ if ( $value < 128 ) {
+ if ( $length && ( $unicode_length >= $length ) )
+ break;
+ $unicode .= chr($value);
+ $unicode_length++;
+ } else {
+ if ( count( $values ) == 0 ) $num_octets = ( $value < 224 ) ? 2 : 3;
+
+ $values[] = $value;
+
+ if ( $length && ( $unicode_length + ($num_octets * 3) ) > $length )
+ break;
+ if ( count( $values ) == $num_octets ) {
+ if ($num_octets == 3) {
+ $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]) . '%' . dechex($values[2]);
+ $unicode_length += 9;
+ } else {
+ $unicode .= '%' . dechex($values[0]) . '%' . dechex($values[1]);
+ $unicode_length += 6;
+ }
+
+ $values = array();
+ $num_octets = 1;
+ }
+ }
+ }
+
+ return $unicode;
+}
+
+/**
+ * Converts all accent characters to ASCII characters.
+ *
+ * If there are no accent characters, then the string given is just returned.
+ *
+ * @since 1.2.1
+ *
+ * @param string $string Text that might have accent characters
+ * @return string Filtered string with replaced "nice" characters.
+ */
+function remove_accents($string) {
+ if ( !preg_match('/[\x80-\xff]/', $string) )
+ return $string;
+
+ if (seems_utf8($string)) {
+ $chars = array(
+ // Decompositions for Latin-1 Supplement
+ chr(194).chr(170) => 'a', chr(194).chr(186) => 'o',
+ chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
+ chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
+ chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
+ chr(195).chr(134) => 'AE',chr(195).chr(135) => 'C',
+ chr(195).chr(136) => 'E', chr(195).chr(137) => 'E',
+ chr(195).chr(138) => 'E', chr(195).chr(139) => 'E',
+ chr(195).chr(140) => 'I', chr(195).chr(141) => 'I',
+ chr(195).chr(142) => 'I', chr(195).chr(143) => 'I',
+ chr(195).chr(144) => 'D', chr(195).chr(145) => 'N',
+ chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
+ chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
+ chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
+ chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
+ chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
+ chr(195).chr(158) => 'TH',chr(195).chr(159) => 's',
+ chr(195).chr(160) => 'a', chr(195).chr(161) => 'a',
+ chr(195).chr(162) => 'a', chr(195).chr(163) => 'a',
+ chr(195).chr(164) => 'a', chr(195).chr(165) => 'a',
+ chr(195).chr(166) => 'ae',chr(195).chr(167) => 'c',
+ chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
+ chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
+ chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
+ chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
+ chr(195).chr(176) => 'd', chr(195).chr(177) => 'n',
+ chr(195).chr(178) => 'o', chr(195).chr(179) => 'o',
+ chr(195).chr(180) => 'o', chr(195).chr(181) => 'o',
+ chr(195).chr(182) => 'o', chr(195).chr(184) => 'o',
+ chr(195).chr(185) => 'u', chr(195).chr(186) => 'u',
+ chr(195).chr(187) => 'u', chr(195).chr(188) => 'u',
+ chr(195).chr(189) => 'y', chr(195).chr(190) => 'th',
+ chr(195).chr(191) => 'y', chr(195).chr(152) => 'O',
+ // Decompositions for Latin Extended-A
+ chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
+ chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
+ chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
+ chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
+ chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
+ chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
+ chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
+ chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
+ chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
+ chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
+ chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
+ chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
+ chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
+ chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
+ chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
+ chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
+ chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
+ chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
+ chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
+ chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
+ chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
+ chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
+ chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
+ chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
+ chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
+ chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
+ chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
+ chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
+ chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
+ chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
+ chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
+ chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
+ chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
+ chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
+ chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
+ chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
+ chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
+ chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
+ chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
+ chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
+ chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
+ chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
+ chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
+ chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
+ chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
+ chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
+ chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
+ chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
+ chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
+ chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
+ chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
+ chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
+ chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
+ chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
+ chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
+ chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
+ chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
+ chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
+ chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
+ chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
+ chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
+ chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
+ chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
+ chr(197).chr(190) => 'z', chr(197).chr(191) => 's',
+ // Decompositions for Latin Extended-B
+ chr(200).chr(152) => 'S', chr(200).chr(153) => 's',
+ chr(200).chr(154) => 'T', chr(200).chr(155) => 't',
+ // Euro Sign
+ chr(226).chr(130).chr(172) => 'E',
+ // GBP (Pound) Sign
+ chr(194).chr(163) => '',
+ // Vowels with diacritic (Vietnamese)
+ // unmarked
+ chr(198).chr(160) => 'O', chr(198).chr(161) => 'o',
+ chr(198).chr(175) => 'U', chr(198).chr(176) => 'u',
+ // grave accent
+ chr(225).chr(186).chr(166) => 'A', chr(225).chr(186).chr(167) => 'a',
+ chr(225).chr(186).chr(176) => 'A', chr(225).chr(186).chr(177) => 'a',
+ chr(225).chr(187).chr(128) => 'E', chr(225).chr(187).chr(129) => 'e',
+ chr(225).chr(187).chr(146) => 'O', chr(225).chr(187).chr(147) => 'o',
+ chr(225).chr(187).chr(156) => 'O', chr(225).chr(187).chr(157) => 'o',
+ chr(225).chr(187).chr(170) => 'U', chr(225).chr(187).chr(171) => 'u',
+ chr(225).chr(187).chr(178) => 'Y', chr(225).chr(187).chr(179) => 'y',
+ // hook
+ chr(225).chr(186).chr(162) => 'A', chr(225).chr(186).chr(163) => 'a',
+ chr(225).chr(186).chr(168) => 'A', chr(225).chr(186).chr(169) => 'a',
+ chr(225).chr(186).chr(178) => 'A', chr(225).chr(186).chr(179) => 'a',
+ chr(225).chr(186).chr(186) => 'E', chr(225).chr(186).chr(187) => 'e',
+ chr(225).chr(187).chr(130) => 'E', chr(225).chr(187).chr(131) => 'e',
+ chr(225).chr(187).chr(136) => 'I', chr(225).chr(187).chr(137) => 'i',
+ chr(225).chr(187).chr(142) => 'O', chr(225).chr(187).chr(143) => 'o',
+ chr(225).chr(187).chr(148) => 'O', chr(225).chr(187).chr(149) => 'o',
+ chr(225).chr(187).chr(158) => 'O', chr(225).chr(187).chr(159) => 'o',
+ chr(225).chr(187).chr(166) => 'U', chr(225).chr(187).chr(167) => 'u',
+ chr(225).chr(187).chr(172) => 'U', chr(225).chr(187).chr(173) => 'u',
+ chr(225).chr(187).chr(182) => 'Y', chr(225).chr(187).chr(183) => 'y',
+ // tilde
+ chr(225).chr(186).chr(170) => 'A', chr(225).chr(186).chr(171) => 'a',
+ chr(225).chr(186).chr(180) => 'A', chr(225).chr(186).chr(181) => 'a',
+ chr(225).chr(186).chr(188) => 'E', chr(225).chr(186).chr(189) => 'e',
+ chr(225).chr(187).chr(132) => 'E', chr(225).chr(187).chr(133) => 'e',
+ chr(225).chr(187).chr(150) => 'O', chr(225).chr(187).chr(151) => 'o',
+ chr(225).chr(187).chr(160) => 'O', chr(225).chr(187).chr(161) => 'o',
+ chr(225).chr(187).chr(174) => 'U', chr(225).chr(187).chr(175) => 'u',
+ chr(225).chr(187).chr(184) => 'Y', chr(225).chr(187).chr(185) => 'y',
+ // acute accent
+ chr(225).chr(186).chr(164) => 'A', chr(225).chr(186).chr(165) => 'a',
+ chr(225).chr(186).chr(174) => 'A', chr(225).chr(186).chr(175) => 'a',
+ chr(225).chr(186).chr(190) => 'E', chr(225).chr(186).chr(191) => 'e',
+ chr(225).chr(187).chr(144) => 'O', chr(225).chr(187).chr(145) => 'o',
+ chr(225).chr(187).chr(154) => 'O', chr(225).chr(187).chr(155) => 'o',
+ chr(225).chr(187).chr(168) => 'U', chr(225).chr(187).chr(169) => 'u',
+ // dot below
+ chr(225).chr(186).chr(160) => 'A', chr(225).chr(186).chr(161) => 'a',
+ chr(225).chr(186).chr(172) => 'A', chr(225).chr(186).chr(173) => 'a',
+ chr(225).chr(186).chr(182) => 'A', chr(225).chr(186).chr(183) => 'a',
+ chr(225).chr(186).chr(184) => 'E', chr(225).chr(186).chr(185) => 'e',
+ chr(225).chr(187).chr(134) => 'E', chr(225).chr(187).chr(135) => 'e',
+ chr(225).chr(187).chr(138) => 'I', chr(225).chr(187).chr(139) => 'i',
+ chr(225).chr(187).chr(140) => 'O', chr(225).chr(187).chr(141) => 'o',
+ chr(225).chr(187).chr(152) => 'O', chr(225).chr(187).chr(153) => 'o',
+ chr(225).chr(187).chr(162) => 'O', chr(225).chr(187).chr(163) => 'o',
+ chr(225).chr(187).chr(164) => 'U', chr(225).chr(187).chr(165) => 'u',
+ chr(225).chr(187).chr(176) => 'U', chr(225).chr(187).chr(177) => 'u',
+ chr(225).chr(187).chr(180) => 'Y', chr(225).chr(187).chr(181) => 'y',
+ // Vowels with diacritic (Chinese, Hanyu Pinyin)
+ chr(201).chr(145) => 'a',
+ // macron
+ chr(199).chr(149) => 'U', chr(199).chr(150) => 'u',
+ // acute accent
+ chr(199).chr(151) => 'U', chr(199).chr(152) => 'u',
+ // caron
+ chr(199).chr(141) => 'A', chr(199).chr(142) => 'a',
+ chr(199).chr(143) => 'I', chr(199).chr(144) => 'i',
+ chr(199).chr(145) => 'O', chr(199).chr(146) => 'o',
+ chr(199).chr(147) => 'U', chr(199).chr(148) => 'u',
+ chr(199).chr(153) => 'U', chr(199).chr(154) => 'u',
+ // grave accent
+ chr(199).chr(155) => 'U', chr(199).chr(156) => 'u',
+ );
+
+ // Used for locale-specific rules
+ $locale = get_locale();
+
+ if ( 'de_DE' == $locale ) {
+ $chars[ chr(195).chr(132) ] = 'Ae';
+ $chars[ chr(195).chr(164) ] = 'ae';
+ $chars[ chr(195).chr(150) ] = 'Oe';
+ $chars[ chr(195).chr(182) ] = 'oe';
+ $chars[ chr(195).chr(156) ] = 'Ue';
+ $chars[ chr(195).chr(188) ] = 'ue';
+ $chars[ chr(195).chr(159) ] = 'ss';
+ }
+
+ $string = strtr($string, $chars);
+ } else {
+ // Assume ISO-8859-1 if not UTF-8
+ $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158)
+ .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194)
+ .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202)
+ .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210)
+ .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218)
+ .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227)
+ .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235)
+ .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243)
+ .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251)
+ .chr(252).chr(253).chr(255);
+
+ $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
+
+ $string = strtr($string, $chars['in'], $chars['out']);
+ $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
+ $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
+ $string = str_replace($double_chars['in'], $double_chars['out'], $string);
+ }
+
+ return $string;
+}
+
+/**
+ * Sanitizes a filename, replacing whitespace with dashes.
+ *
+ * Removes special characters that are illegal in filenames on certain
+ * operating systems and special characters requiring special escaping
+ * to manipulate at the command line. Replaces spaces and consecutive
+ * dashes with a single dash. Trims period, dash and underscore from beginning
+ * and end of filename.
+ *
+ * @since 2.1.0
+ *
+ * @param string $filename The filename to be sanitized
+ * @return string The sanitized filename
+ */
+function sanitize_file_name( $filename ) {
+ $filename_raw = $filename;
+ $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", chr(0));
+ $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $filename_raw);
+ $filename = str_replace($special_chars, '', $filename);
+ $filename = preg_replace('/[\s-]+/', '-', $filename);
+ $filename = trim($filename, '.-_');
+
+ // Split the filename into a base and extension[s]
+ $parts = explode('.', $filename);
+
+ // Return if only one extension
+ if ( count($parts) <= 2 )
+ return apply_filters('sanitize_file_name', $filename, $filename_raw);
+
+ // Process multiple extensions
+ $filename = array_shift($parts);
+ $extension = array_pop($parts);
+ $mimes = get_allowed_mime_types();
+
+ // Loop over any intermediate extensions. Munge them with a trailing underscore if they are a 2 - 5 character
+ // long alpha string not in the extension whitelist.
+ foreach ( (array) $parts as $part) {
+ $filename .= '.' . $part;
+
+ if ( preg_match("/^[a-zA-Z]{2,5}\d?$/", $part) ) {
+ $allowed = false;
+ foreach ( $mimes as $ext_preg => $mime_match ) {
+ $ext_preg = '!^(' . $ext_preg . ')$!i';
+ if ( preg_match( $ext_preg, $part ) ) {
+ $allowed = true;
+ break;
+ }
+ }
+ if ( !$allowed )
+ $filename .= '_';
+ }
+ }
+ $filename .= '.' . $extension;
+
+ return apply_filters('sanitize_file_name', $filename, $filename_raw);
+}
+
+/**
+ * Sanitizes a username, stripping out unsafe characters.
+ *
+ * Removes tags, octets, entities, and if strict is enabled, will only keep
+ * alphanumeric, _, space, ., -, @. After sanitizing, it passes the username,
+ * raw username (the username in the parameter), and the value of $strict as
+ * parameters for the 'sanitize_user' filter.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'sanitize_user' hook on username, raw username,
+ * and $strict parameter.
+ *
+ * @param string $username The username to be sanitized.
+ * @param bool $strict If set limits $username to specific characters. Default false.
+ * @return string The sanitized username, after passing through filters.
+ */
+function sanitize_user( $username, $strict = false ) {
+ $raw_username = $username;
+ $username = wp_strip_all_tags( $username );
+ $username = remove_accents( $username );
+ // Kill octets
+ $username = preg_replace( '|%([a-fA-F0-9][a-fA-F0-9])|', '', $username );
+ $username = preg_replace( '/&.+?;/', '', $username ); // Kill entities
+
+ // If strict, reduce to ASCII for max portability.
+ if ( $strict )
+ $username = preg_replace( '|[^a-z0-9 _.\-@]|i', '', $username );
+
+ $username = trim( $username );
+ // Consolidate contiguous whitespace
+ $username = preg_replace( '|\s+|', ' ', $username );
+
+ return apply_filters( 'sanitize_user', $username, $raw_username, $strict );
+}
+
+/**
+ * Sanitizes a string key.
+ *
+ * Keys are used as internal identifiers. Lowercase alphanumeric characters, dashes and underscores are allowed.
+ *
+ * @since 3.0.0
+ *
+ * @param string $key String key
+ * @return string Sanitized key
+ */
+function sanitize_key( $key ) {
+ $raw_key = $key;
+ $key = strtolower( $key );
+ $key = preg_replace( '/[^a-z0-9_\-]/', '', $key );
+ return apply_filters( 'sanitize_key', $key, $raw_key );
+}
+
+/**
+ * Sanitizes a title, or returns a fallback title.
+ *
+ * Specifically, HTML and PHP tags are stripped. Further actions can be added
+ * via the plugin API. If $title is empty and $fallback_title is set, the latter
+ * will be used.
+ *
+ * @since 1.0.0
+ *
+ * @param string $title The string to be sanitized.
+ * @param string $fallback_title Optional. A title to use if $title is empty.
+ * @param string $context Optional. The operation for which the string is sanitized
+ * @return string The sanitized string.
+ */
+function sanitize_title( $title, $fallback_title = '', $context = 'save' ) {
+ $raw_title = $title;
+
+ if ( 'save' == $context )
+ $title = remove_accents($title);
+
+ $title = apply_filters('sanitize_title', $title, $raw_title, $context);
+
+ if ( '' === $title || false === $title )
+ $title = $fallback_title;
+
+ return $title;
+}
+
+/**
+ * Sanitizes a title with the 'query' context.
+ *
+ * Used for querying the database for a value from URL.
+ *
+ * @since 3.1.0
+ * @uses sanitize_title()
+ *
+ * @param string $title The string to be sanitized.
+ * @return string The sanitized string.
+ */
+function sanitize_title_for_query( $title ) {
+ return sanitize_title( $title, '', 'query' );
+}
+
+/**
+ * Sanitizes a title, replacing whitespace and a few other characters with dashes.
+ *
+ * Limits the output to alphanumeric characters, underscore (_) and dash (-).
+ * Whitespace becomes a dash.
+ *
+ * @since 1.2.0
+ *
+ * @param string $title The title to be sanitized.
+ * @param string $raw_title Optional. Not used.
+ * @param string $context Optional. The operation for which the string is sanitized.
+ * @return string The sanitized title.
+ */
+function sanitize_title_with_dashes( $title, $raw_title = '', $context = 'display' ) {
+ $title = strip_tags($title);
+ // Preserve escaped octets.
+ $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
+ // Remove percent signs that are not part of an octet.
+ $title = str_replace('%', '', $title);
+ // Restore octets.
+ $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);
+
+ if (seems_utf8($title)) {
+ if (function_exists('mb_strtolower')) {
+ $title = mb_strtolower($title, 'UTF-8');
+ }
+ $title = utf8_uri_encode($title, 200);
+ }
+
+ $title = strtolower($title);
+ $title = preg_replace('/&.+?;/', '', $title); // kill entities
+ $title = str_replace('.', '-', $title);
+
+ if ( 'save' == $context ) {
+ // Convert nbsp, ndash and mdash to hyphens
+ $title = str_replace( array( '%c2%a0', '%e2%80%93', '%e2%80%94' ), '-', $title );
+
+ // Strip these characters entirely
+ $title = str_replace( array(
+ // iexcl and iquest
+ '%c2%a1', '%c2%bf',
+ // angle quotes
+ '%c2%ab', '%c2%bb', '%e2%80%b9', '%e2%80%ba',
+ // curly quotes
+ '%e2%80%98', '%e2%80%99', '%e2%80%9c', '%e2%80%9d',
+ '%e2%80%9a', '%e2%80%9b', '%e2%80%9e', '%e2%80%9f',
+ // copy, reg, deg, hellip and trade
+ '%c2%a9', '%c2%ae', '%c2%b0', '%e2%80%a6', '%e2%84%a2',
+ // acute accents
+ '%c2%b4', '%cb%8a', '%cc%81', '%cd%81',
+ // grave accent, macron, caron
+ '%cc%80', '%cc%84', '%cc%8c',
+ ), '', $title );
+
+ // Convert times to x
+ $title = str_replace( '%c3%97', 'x', $title );
+ }
+
+ $title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
+ $title = preg_replace('/\s+/', '-', $title);
+ $title = preg_replace('|-+|', '-', $title);
+ $title = trim($title, '-');
+
+ return $title;
+}
+
+/**
+ * Ensures a string is a valid SQL order by clause.
+ *
+ * Accepts one or more columns, with or without ASC/DESC, and also accepts
+ * RAND().
+ *
+ * @since 2.5.1
+ *
+ * @param string $orderby Order by string to be checked.
+ * @return string|bool Returns the order by clause if it is a match, false otherwise.
+ */
+function sanitize_sql_orderby( $orderby ){
+ preg_match('/^\s*([a-z0-9_]+(\s+(ASC|DESC))?(\s*,\s*|\s*$))+|^\s*RAND\(\s*\)\s*$/i', $orderby, $obmatches);
+ if ( !$obmatches )
+ return false;
+ return $orderby;
+}
+
+/**
+ * Sanitizes an HTML classname to ensure it only contains valid characters.
+ *
+ * Strips the string down to A-Z,a-z,0-9,_,-. If this results in an empty
+ * string then it will return the alternative value supplied.
+ *
+ * @todo Expand to support the full range of CDATA that a class attribute can contain.
+ *
+ * @since 2.8.0
+ *
+ * @param string $class The classname to be sanitized
+ * @param string $fallback Optional. The value to return if the sanitization end's up as an empty string.
+ * Defaults to an empty string.
+ * @return string The sanitized value
+ */
+function sanitize_html_class( $class, $fallback = '' ) {
+ //Strip out any % encoded octets
+ $sanitized = preg_replace( '|%[a-fA-F0-9][a-fA-F0-9]|', '', $class );
+
+ //Limit to A-Z,a-z,0-9,_,-
+ $sanitized = preg_replace( '/[^A-Za-z0-9_-]/', '', $sanitized );
+
+ if ( '' == $sanitized )
+ $sanitized = $fallback;
+
+ return apply_filters( 'sanitize_html_class', $sanitized, $class, $fallback );
+}
+
+/**
+ * Converts a number of characters from a string.
+ *
+ * Metadata tags <<title>> and <<category>> are removed, <<br>> and <<hr>> are
+ * converted into correct XHTML and Unicode characters are converted to the
+ * valid range.
+ *
+ * @since 0.71
+ *
+ * @param string $content String of characters to be converted.
+ * @param string $deprecated Not used.
+ * @return string Converted string.
+ */
+function convert_chars($content, $deprecated = '') {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '0.71' );
+
+ // Translation of invalid Unicode references range to valid range
+ $wp_htmltranswinuni = array(
+ '&#128;' => '&#8364;', // the Euro sign
+ '&#129;' => '',
+ '&#130;' => '&#8218;', // these are Windows CP1252 specific characters
+ '&#131;' => '&#402;', // they would look weird on non-Windows browsers
+ '&#132;' => '&#8222;',
+ '&#133;' => '&#8230;',
+ '&#134;' => '&#8224;',
+ '&#135;' => '&#8225;',
+ '&#136;' => '&#710;',
+ '&#137;' => '&#8240;',
+ '&#138;' => '&#352;',
+ '&#139;' => '&#8249;',
+ '&#140;' => '&#338;',
+ '&#141;' => '',
+ '&#142;' => '&#381;',
+ '&#143;' => '',
+ '&#144;' => '',
+ '&#145;' => '&#8216;',
+ '&#146;' => '&#8217;',
+ '&#147;' => '&#8220;',
+ '&#148;' => '&#8221;',
+ '&#149;' => '&#8226;',
+ '&#150;' => '&#8211;',
+ '&#151;' => '&#8212;',
+ '&#152;' => '&#732;',
+ '&#153;' => '&#8482;',
+ '&#154;' => '&#353;',
+ '&#155;' => '&#8250;',
+ '&#156;' => '&#339;',
+ '&#157;' => '',
+ '&#158;' => '&#382;',
+ '&#159;' => '&#376;'
+ );
+
+ // Remove metadata tags
+ $content = preg_replace('/<title>(.+?)<\/title>/','',$content);
+ $content = preg_replace('/<category>(.+?)<\/category>/','',$content);
+
+ // Converts lone & characters into &#38; (a.k.a. &amp;)
+ $content = preg_replace('/&([^#])(?![a-z1-4]{1,8};)/i', '&#038;$1', $content);
+
+ // Fix Word pasting
+ $content = strtr($content, $wp_htmltranswinuni);
+
+ // Just a little XHTML help
+ $content = str_replace('<br>', '<br />', $content);
+ $content = str_replace('<hr>', '<hr />', $content);
+
+ return $content;
+}
+
+/**
+ * Balances tags if forced to, or if the 'use_balanceTags' option is set to true.
+ *
+ * @since 0.71
+ *
+ * @param string $text Text to be balanced
+ * @param bool $force If true, forces balancing, ignoring the value of the option. Default false.
+ * @return string Balanced text
+ */
+function balanceTags( $text, $force = false ) {
+ if ( $force || get_option('use_balanceTags') == 1 )
+ return force_balance_tags( $text );
+ else
+ return $text;
+}
+
+/**
+ * Balances tags of string using a modified stack.
+ *
+ * @since 2.0.4
+ *
+ * @author Leonard Lin <leonard@acm.org>
+ * @license GPL
+ * @copyright November 4, 2001
+ * @version 1.1
+ * @todo Make better - change loop condition to $text in 1.2
+ * @internal Modified by Scott Reilly (coffee2code) 02 Aug 2004
+ * 1.1 Fixed handling of append/stack pop order of end text
+ * Added Cleaning Hooks
+ * 1.0 First Version
+ *
+ * @param string $text Text to be balanced.
+ * @return string Balanced text.
+ */
+function force_balance_tags( $text ) {
+ $tagstack = array();
+ $stacksize = 0;
+ $tagqueue = '';
+ $newtext = '';
+ // Known single-entity/self-closing tags
+ $single_tags = array( 'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param', 'source' );
+ // Tags that can be immediately nested within themselves
+ $nestable_tags = array( 'blockquote', 'div', 'object', 'q', 'span' );
+
+ // WP bug fix for comments - in case you REALLY meant to type '< !--'
+ $text = str_replace('< !--', '< !--', $text);
+ // WP bug fix for LOVE <3 (and other situations with '<' before a number)
+ $text = preg_replace('#<([0-9]{1})#', '&lt;$1', $text);
+
+ while ( preg_match("/<(\/?[\w:]*)\s*([^>]*)>/", $text, $regex) ) {
+ $newtext .= $tagqueue;
+
+ $i = strpos($text, $regex[0]);
+ $l = strlen($regex[0]);
+
+ // clear the shifter
+ $tagqueue = '';
+ // Pop or Push
+ if ( isset($regex[1][0]) && '/' == $regex[1][0] ) { // End Tag
+ $tag = strtolower(substr($regex[1],1));
+ // if too many closing tags
+ if( $stacksize <= 0 ) {
+ $tag = '';
+ // or close to be safe $tag = '/' . $tag;
+ }
+ // if stacktop value = tag close value then pop
+ else if ( $tagstack[$stacksize - 1] == $tag ) { // found closing tag
+ $tag = '</' . $tag . '>'; // Close Tag
+ // Pop
+ array_pop( $tagstack );
+ $stacksize--;
+ } else { // closing tag not at top, search for it
+ for ( $j = $stacksize-1; $j >= 0; $j-- ) {
+ if ( $tagstack[$j] == $tag ) {
+ // add tag to tagqueue
+ for ( $k = $stacksize-1; $k >= $j; $k--) {
+ $tagqueue .= '</' . array_pop( $tagstack ) . '>';
+ $stacksize--;
+ }
+ break;
+ }
+ }
+ $tag = '';
+ }
+ } else { // Begin Tag
+ $tag = strtolower($regex[1]);
+
+ // Tag Cleaning
+
+ // If it's an empty tag "< >", do nothing
+ if ( '' == $tag ) {
+ // do nothing
+ }
+ // ElseIf it presents itself as a self-closing tag...
+ elseif ( substr( $regex[2], -1 ) == '/' ) {
+ // ...but it isn't a known single-entity self-closing tag, then don't let it be treated as such and
+ // immediately close it with a closing tag (the tag will encapsulate no text as a result)
+ if ( ! in_array( $tag, $single_tags ) )
+ $regex[2] = trim( substr( $regex[2], 0, -1 ) ) . "></$tag";
+ }
+ // ElseIf it's a known single-entity tag but it doesn't close itself, do so
+ elseif ( in_array($tag, $single_tags) ) {
+ $regex[2] .= '/';
+ }
+ // Else it's not a single-entity tag
+ else {
+ // If the top of the stack is the same as the tag we want to push, close previous tag
+ if ( $stacksize > 0 && !in_array($tag, $nestable_tags) && $tagstack[$stacksize - 1] == $tag ) {
+ $tagqueue = '</' . array_pop( $tagstack ) . '>';
+ $stacksize--;
+ }
+ $stacksize = array_push( $tagstack, $tag );
+ }
+
+ // Attributes
+ $attributes = $regex[2];
+ if( ! empty( $attributes ) && $attributes[0] != '>' )
+ $attributes = ' ' . $attributes;
+
+ $tag = '<' . $tag . $attributes . '>';
+ //If already queuing a close tag, then put this tag on, too
+ if ( !empty($tagqueue) ) {
+ $tagqueue .= $tag;
+ $tag = '';
+ }
+ }
+ $newtext .= substr($text, 0, $i) . $tag;
+ $text = substr($text, $i + $l);
+ }
+
+ // Clear Tag Queue
+ $newtext .= $tagqueue;
+
+ // Add Remaining text
+ $newtext .= $text;
+
+ // Empty Stack
+ while( $x = array_pop($tagstack) )
+ $newtext .= '</' . $x . '>'; // Add remaining tags to close
+
+ // WP fix for the bug with HTML comments
+ $newtext = str_replace("< !--","<!--",$newtext);
+ $newtext = str_replace("< !--","< !--",$newtext);
+
+ return $newtext;
+}
+
+/**
+ * Acts on text which is about to be edited.
+ *
+ * The $content is run through esc_textarea(), which uses htmlspecialchars()
+ * to convert special characters to HTML entities. If $richedit is set to true,
+ * it is simply a holder for the 'format_to_edit' filter.
+ *
+ * @since 0.71
+ *
+ * @param string $content The text about to be edited.
+ * @param bool $richedit Whether the $content should not pass through htmlspecialchars(). Default false (meaning it will be passed).
+ * @return string The text after the filter (and possibly htmlspecialchars()) has been run.
+ */
+function format_to_edit( $content, $richedit = false ) {
+ $content = apply_filters( 'format_to_edit', $content );
+ if ( ! $richedit )
+ $content = esc_textarea( $content );
+ return $content;
+}
+
+/**
+ * Holder for the 'format_to_post' filter.
+ *
+ * @since 0.71
+ *
+ * @param string $content The text to pass through the filter.
+ * @return string Text returned from the 'format_to_post' filter.
+ */
+function format_to_post($content) {
+ $content = apply_filters('format_to_post', $content);
+ return $content;
+}
+
+/**
+ * Add leading zeros when necessary.
+ *
+ * If you set the threshold to '4' and the number is '10', then you will get
+ * back '0010'. If you set the threshold to '4' and the number is '5000', then you
+ * will get back '5000'.
+ *
+ * Uses sprintf to append the amount of zeros based on the $threshold parameter
+ * and the size of the number. If the number is large enough, then no zeros will
+ * be appended.
+ *
+ * @since 0.71
+ *
+ * @param mixed $number Number to append zeros to if not greater than threshold.
+ * @param int $threshold Digit places number needs to be to not have zeros added.
+ * @return string Adds leading zeros to number if needed.
+ */
+function zeroise($number, $threshold) {
+ return sprintf('%0'.$threshold.'s', $number);
+}
+
+/**
+ * Adds backslashes before letters and before a number at the start of a string.
+ *
+ * @since 0.71
+ *
+ * @param string $string Value to which backslashes will be added.
+ * @return string String with backslashes inserted.
+ */
+function backslashit($string) {
+ if ( isset( $string[0] ) && $string[0] >= '0' && $string[0] <= '9' )
+ $string = '\\\\' . $string;
+ return addcslashes( $string, 'A..Za..z' );
+}
+
+/**
+ * Appends a trailing slash.
+ *
+ * Will remove trailing slash if it exists already before adding a trailing
+ * slash. This prevents double slashing a string or path.
+ *
+ * The primary use of this is for paths and thus should be used for paths. It is
+ * not restricted to paths and offers no specific path support.
+ *
+ * @since 1.2.0
+ * @uses untrailingslashit() Unslashes string if it was slashed already.
+ *
+ * @param string $string What to add the trailing slash to.
+ * @return string String with trailing slash added.
+ */
+function trailingslashit($string) {
+ return untrailingslashit($string) . '/';
+}
+
+/**
+ * Removes trailing slash if it exists.
+ *
+ * The primary use of this is for paths and thus should be used for paths. It is
+ * not restricted to paths and offers no specific path support.
+ *
+ * @since 2.2.0
+ *
+ * @param string $string What to remove the trailing slash from.
+ * @return string String without the trailing slash.
+ */
+function untrailingslashit($string) {
+ return rtrim($string, '/');
+}
+
+/**
+ * Adds slashes to escape strings.
+ *
+ * Slashes will first be removed if magic_quotes_gpc is set, see {@link
+ * http://www.php.net/magic_quotes} for more details.
+ *
+ * @since 0.71
+ *
+ * @param string $gpc The string returned from HTTP request data.
+ * @return string Returns a string escaped with slashes.
+ */
+function addslashes_gpc($gpc) {
+ if ( get_magic_quotes_gpc() )
+ $gpc = stripslashes($gpc);
+
+ return wp_slash($gpc);
+}
+
+/**
+ * Navigates through an array and removes slashes from the values.
+ *
+ * If an array is passed, the array_map() function causes a callback to pass the
+ * value back to the function. The slashes from this value will removed.
+ *
+ * @since 2.0.0
+ *
+ * @param mixed $value The value to be stripped.
+ * @return mixed Stripped value.
+ */
+function stripslashes_deep($value) {
+ if ( is_array($value) ) {
+ $value = array_map('stripslashes_deep', $value);
+ } elseif ( is_object($value) ) {
+ $vars = get_object_vars( $value );
+ foreach ($vars as $key=>$data) {
+ $value->{$key} = stripslashes_deep( $data );
+ }
+ } elseif ( is_string( $value ) ) {
+ $value = stripslashes($value);
+ }
+
+ return $value;
+}
+
+/**
+ * Navigates through an array and encodes the values to be used in a URL.
+ *
+ *
+ * @since 2.2.0
+ *
+ * @param array|string $value The array or string to be encoded.
+ * @return array|string $value The encoded array (or string from the callback).
+ */
+function urlencode_deep($value) {
+ $value = is_array($value) ? array_map('urlencode_deep', $value) : urlencode($value);
+ return $value;
+}
+
+/**
+ * Navigates through an array and raw encodes the values to be used in a URL.
+ *
+ * @since 3.4.0
+ *
+ * @param array|string $value The array or string to be encoded.
+ * @return array|string $value The encoded array (or string from the callback).
+ */
+function rawurlencode_deep( $value ) {
+ return is_array( $value ) ? array_map( 'rawurlencode_deep', $value ) : rawurlencode( $value );
+}
+
+/**
+ * Converts email addresses characters to HTML entities to block spam bots.
+ *
+ * @since 0.71
+ *
+ * @param string $emailaddy Email address.
+ * @param int $mailto Optional. Range from 0 to 1. Used for encoding.
+ * @return string Converted email address.
+ */
+function antispambot($emailaddy, $mailto=0) {
+ $emailNOSPAMaddy = '';
+ srand ((float) microtime() * 1000000);
+ for ($i = 0; $i < strlen($emailaddy); $i = $i + 1) {
+ $j = floor(rand(0, 1+$mailto));
+ if ($j==0) {
+ $emailNOSPAMaddy .= '&#'.ord(substr($emailaddy,$i,1)).';';
+ } elseif ($j==1) {
+ $emailNOSPAMaddy .= substr($emailaddy,$i,1);
+ } elseif ($j==2) {
+ $emailNOSPAMaddy .= '%'.zeroise(dechex(ord(substr($emailaddy, $i, 1))), 2);
+ }
+ }
+ $emailNOSPAMaddy = str_replace('@','&#64;',$emailNOSPAMaddy);
+ return $emailNOSPAMaddy;
+}
+
+/**
+ * Callback to convert URI match to HTML A element.
+ *
+ * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
+ * make_clickable()}.
+ *
+ * @since 2.3.2
+ * @access private
+ *
+ * @param array $matches Single Regex Match.
+ * @return string HTML A element with URI address.
+ */
+function _make_url_clickable_cb($matches) {
+ $url = $matches[2];
+
+ if ( ')' == $matches[3] && strpos( $url, '(' ) ) {
+ // If the trailing character is a closing parethesis, and the URL has an opening parenthesis in it, add the closing parenthesis to the URL.
+ // Then we can let the parenthesis balancer do its thing below.
+ $url .= $matches[3];
+ $suffix = '';
+ } else {
+ $suffix = $matches[3];
+ }
+
+ // Include parentheses in the URL only if paired
+ while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
+ $suffix = strrchr( $url, ')' ) . $suffix;
+ $url = substr( $url, 0, strrpos( $url, ')' ) );
+ }
+
+ $url = esc_url($url);
+ if ( empty($url) )
+ return $matches[0];
+
+ return $matches[1] . "<a href=\"$url\" rel=\"nofollow\">$url</a>" . $suffix;
+}
+
+/**
+ * Callback to convert URL match to HTML A element.
+ *
+ * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
+ * make_clickable()}.
+ *
+ * @since 2.3.2
+ * @access private
+ *
+ * @param array $matches Single Regex Match.
+ * @return string HTML A element with URL address.
+ */
+function _make_web_ftp_clickable_cb($matches) {
+ $ret = '';
+ $dest = $matches[2];
+ $dest = 'http://' . $dest;
+ $dest = esc_url($dest);
+ if ( empty($dest) )
+ return $matches[0];
+
+ // removed trailing [.,;:)] from URL
+ if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
+ $ret = substr($dest, -1);
+ $dest = substr($dest, 0, strlen($dest)-1);
+ }
+ return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\">$dest</a>$ret";
+}
+
+/**
+ * Callback to convert email address match to HTML A element.
+ *
+ * This function was backported from 2.5.0 to 2.3.2. Regex callback for {@link
+ * make_clickable()}.
+ *
+ * @since 2.3.2
+ * @access private
+ *
+ * @param array $matches Single Regex Match.
+ * @return string HTML A element with email address.
+ */
+function _make_email_clickable_cb($matches) {
+ $email = $matches[2] . '@' . $matches[3];
+ return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
+}
+
+/**
+ * Convert plaintext URI to HTML links.
+ *
+ * Converts URI, www and ftp, and email addresses. Finishes by fixing links
+ * within links.
+ *
+ * @since 0.71
+ *
+ * @param string $text Content to convert URIs.
+ * @return string Content with converted URIs.
+ */
+function make_clickable( $text ) {
+ $r = '';
+ $textarr = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
+ foreach ( $textarr as $piece ) {
+ if ( empty( $piece ) || ( $piece[0] == '<' && ! preg_match('|^<\s*[\w]{1,20}+://|', $piece) ) ) {
+ $r .= $piece;
+ continue;
+ }
+
+ // Long strings might contain expensive edge cases ...
+ if ( 10000 < strlen( $piece ) ) {
+ // ... break it up
+ foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
+ if ( 2101 < strlen( $chunk ) ) {
+ $r .= $chunk; // Too big, no whitespace: bail.
+ } else {
+ $r .= make_clickable( $chunk );
+ }
+ }
+ } else {
+ $ret = " $piece "; // Pad with whitespace to simplify the regexes
+
+ $url_clickable = '~
+ ([\\s(<.,;:!?]) # 1: Leading whitespace, or punctuation
+ ( # 2: URL
+ [\\w]{1,20}+:// # Scheme and hier-part prefix
+ (?=\S{1,2000}\s) # Limit to URLs less than about 2000 characters long
+ [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+ # Non-punctuation URL character
+ (?: # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
+ [\'.,;:!?)] # Punctuation URL character
+ [\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
+ )*
+ )
+ (\)?) # 3: Trailing closing parenthesis (for parethesis balancing post processing)
+ ~xS'; // The regex is a non-anchored pattern and does not have a single fixed starting character.
+ // Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
+
+ $ret = preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $ret );
+
+ $ret = preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret );
+ $ret = preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret );
+
+ $ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
+ $r .= $ret;
+ }
+ }
+
+ // Cleanup of accidental links within links
+ $r = preg_replace( '#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i', "$1$3</a>", $r );
+ return $r;
+}
+
+/**
+ * Breaks a string into chunks by splitting at whitespace characters.
+ * The length of each returned chunk is as close to the specified length goal as possible,
+ * with the caveat that each chunk includes its trailing delimiter.
+ * Chunks longer than the goal are guaranteed to not have any inner whitespace.
+ *
+ * Joining the returned chunks with empty delimiters reconstructs the input string losslessly.
+ *
+ * Input string must have no null characters (or eventual transformations on output chunks must not care about null characters)
+ *
+ * <code>
+ * _split_str_by_whitespace( "1234 67890 1234 67890a cd 1234 890 123456789 1234567890a 45678 1 3 5 7 90 ", 10 ) ==
+ * array (
+ * 0 => '1234 67890 ', // 11 characters: Perfect split
+ * 1 => '1234 ', // 5 characters: '1234 67890a' was too long
+ * 2 => '67890a cd ', // 10 characters: '67890a cd 1234' was too long
+ * 3 => '1234 890 ', // 11 characters: Perfect split
+ * 4 => '123456789 ', // 10 characters: '123456789 1234567890a' was too long
+ * 5 => '1234567890a ', // 12 characters: Too long, but no inner whitespace on which to split
+ * 6 => ' 45678 ', // 11 characters: Perfect split
+ * 7 => '1 3 5 7 9', // 9 characters: End of $string
+ * );
+ * </code>
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string $string The string to split.
+ * @param int $goal The desired chunk length.
+ * @return array Numeric array of chunks.
+ */
+function _split_str_by_whitespace( $string, $goal ) {
+ $chunks = array();
+
+ $string_nullspace = strtr( $string, "\r\n\t\v\f ", "\000\000\000\000\000\000" );
+
+ while ( $goal < strlen( $string_nullspace ) ) {
+ $pos = strrpos( substr( $string_nullspace, 0, $goal + 1 ), "\000" );
+
+ if ( false === $pos ) {
+ $pos = strpos( $string_nullspace, "\000", $goal + 1 );
+ if ( false === $pos ) {
+ break;
+ }
+ }
+
+ $chunks[] = substr( $string, 0, $pos + 1 );
+ $string = substr( $string, $pos + 1 );
+ $string_nullspace = substr( $string_nullspace, $pos + 1 );
+ }
+
+ if ( $string ) {
+ $chunks[] = $string;
+ }
+
+ return $chunks;
+}
+
+/**
+ * Adds rel nofollow string to all HTML A elements in content.
+ *
+ * @since 1.5.0
+ *
+ * @param string $text Content that may contain HTML A elements.
+ * @return string Converted content.
+ */
+function wp_rel_nofollow( $text ) {
+ // This is a pre save filter, so text is already escaped.
+ $text = stripslashes($text);
+ $text = preg_replace_callback('|<a (.+?)>|i', 'wp_rel_nofollow_callback', $text);
+ $text = wp_slash($text);
+ return $text;
+}
+
+/**
+ * Callback to add rel=nofollow string to HTML A element.
+ *
+ * Will remove already existing rel="nofollow" and rel='nofollow' from the
+ * string to prevent from invalidating (X)HTML.
+ *
+ * @since 2.3.0
+ *
+ * @param array $matches Single Match
+ * @return string HTML A Element with rel nofollow.
+ */
+function wp_rel_nofollow_callback( $matches ) {
+ $text = $matches[1];
+ $text = str_replace(array(' rel="nofollow"', " rel='nofollow'"), '', $text);
+ return "<a $text rel=\"nofollow\">";
+}
+
+/**
+ * Convert one smiley code to the icon graphic file equivalent.
+ *
+ * Looks up one smiley code in the $wpsmiliestrans global array and returns an
+ * <img> string for that smiley.
+ *
+ * @global array $wpsmiliestrans
+ * @since 2.8.0
+ *
+ * @param string $smiley Smiley code to convert to image.
+ * @return string Image string for smiley.
+ */
+function translate_smiley($smiley) {
+ global $wpsmiliestrans;
+
+ if (count($smiley) == 0) {
+ return '';
+ }
+
+ $smiley = trim(reset($smiley));
+ $img = $wpsmiliestrans[$smiley];
+ $smiley_masked = esc_attr($smiley);
+
+ $srcurl = apply_filters('smilies_src', includes_url("images/smilies/$img"), $img, site_url());
+
+ return " <img src='$srcurl' alt='$smiley_masked' class='wp-smiley' /> ";
+}
+
+/**
+ * Convert text equivalent of smilies to images.
+ *
+ * Will only convert smilies if the option 'use_smilies' is true and the global
+ * used in the function isn't empty.
+ *
+ * @since 0.71
+ * @uses $wp_smiliessearch
+ *
+ * @param string $text Content to convert smilies from text.
+ * @return string Converted content with text smilies replaced with images.
+ */
+function convert_smilies($text) {
+ global $wp_smiliessearch;
+ $output = '';
+ if ( get_option('use_smilies') && !empty($wp_smiliessearch) ) {
+ // HTML loop taken from texturize function, could possible be consolidated
+ $textarr = preg_split("/(<.*>)/U", $text, -1, PREG_SPLIT_DELIM_CAPTURE); // capture the tags as well as in between
+ $stop = count($textarr);// loop stuff
+ for ($i = 0; $i < $stop; $i++) {
+ $content = $textarr[$i];
+ if ((strlen($content) > 0) && ('<' != $content[0])) { // If it's not a tag
+ $content = preg_replace_callback($wp_smiliessearch, 'translate_smiley', $content);
+ }
+ $output .= $content;
+ }
+ } else {
+ // return default text.
+ $output = $text;
+ }
+ return $output;
+}
+
+/**
+ * Verifies that an email is valid.
+ *
+ * Does not grok i18n domains. Not RFC compliant.
+ *
+ * @since 0.71
+ *
+ * @param string $email Email address to verify.
+ * @param boolean $deprecated Deprecated.
+ * @return string|bool Either false or the valid email address.
+ */
+function is_email( $email, $deprecated = false ) {
+ if ( ! empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '3.0' );
+
+ // Test for the minimum length the email can be
+ if ( strlen( $email ) < 3 ) {
+ return apply_filters( 'is_email', false, $email, 'email_too_short' );
+ }
+
+ // Test for an @ character after the first position
+ if ( strpos( $email, '@', 1 ) === false ) {
+ return apply_filters( 'is_email', false, $email, 'email_no_at' );
+ }
+
+ // Split out the local and domain parts
+ list( $local, $domain ) = explode( '@', $email, 2 );
+
+ // LOCAL PART
+ // Test for invalid characters
+ if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
+ return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
+ }
+
+ // DOMAIN PART
+ // Test for sequences of periods
+ if ( preg_match( '/\.{2,}/', $domain ) ) {
+ return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
+ }
+
+ // Test for leading and trailing periods and whitespace
+ if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
+ return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
+ }
+
+ // Split the domain into subs
+ $subs = explode( '.', $domain );
+
+ // Assume the domain will have at least two subs
+ if ( 2 > count( $subs ) ) {
+ return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
+ }
+
+ // Loop through each sub
+ foreach ( $subs as $sub ) {
+ // Test for leading and trailing hyphens and whitespace
+ if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
+ return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
+ }
+
+ // Test for invalid characters
+ if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
+ return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
+ }
+ }
+
+ // Congratulations your email made it!
+ return apply_filters( 'is_email', $email, $email, null );
+}
+
+/**
+ * Convert to ASCII from email subjects.
+ *
+ * @since 1.2.0
+ *
+ * @param string $string Subject line
+ * @return string Converted string to ASCII
+ */
+function wp_iso_descrambler($string) {
+ /* this may only work with iso-8859-1, I'm afraid */
+ if (!preg_match('#\=\?(.+)\?Q\?(.+)\?\=#i', $string, $matches)) {
+ return $string;
+ } else {
+ $subject = str_replace('_', ' ', $matches[2]);
+ $subject = preg_replace_callback('#\=([0-9a-f]{2})#i', '_wp_iso_convert', $subject);
+ return $subject;
+ }
+}
+
+/**
+ * Helper function to convert hex encoded chars to ASCII
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param array $match The preg_replace_callback matches array
+ * @return array Converted chars
+ */
+function _wp_iso_convert( $match ) {
+ return chr( hexdec( strtolower( $match[1] ) ) );
+}
+
+/**
+ * Returns a date in the GMT equivalent.
+ *
+ * Requires and returns a date in the Y-m-d H:i:s format. If there is a
+ * timezone_string available, the date is assumed to be in that timezone,
+ * otherwise it simply subtracts the value of the 'gmt_offset' option. Return
+ * format can be overridden using the $format parameter.
+ *
+ * @since 1.2.0
+ *
+ * @uses get_option() to retrieve the value of 'gmt_offset'.
+ * @param string $string The date to be converted.
+ * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
+ * @return string GMT version of the date provided.
+ */
+function get_gmt_from_date( $string, $format = 'Y-m-d H:i:s' ) {
+ $tz = get_option( 'timezone_string' );
+ if ( $tz ) {
+ $datetime = date_create( $string, new DateTimeZone( $tz ) );
+ if ( ! $datetime )
+ return gmdate( $format, 0 );
+ $datetime->setTimezone( new DateTimeZone( 'UTC' ) );
+ $string_gmt = $datetime->format( $format );
+ } else {
+ if ( ! preg_match( '#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches ) )
+ return gmdate( $format, 0 );
+ $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
+ $string_gmt = gmdate( $format, $string_time - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
+ }
+ return $string_gmt;
+}
+
+/**
+ * Converts a GMT date into the correct format for the blog.
+ *
+ * Requires and returns a date in the Y-m-d H:i:s format. If there is a
+ * timezone_string available, the returned date is in that timezone, otherwise
+ * it simply adds the value of gmt_offset. Return format can be overridden
+ * using the $format parameter
+ *
+ * @since 1.2.0
+ *
+ * @param string $string The date to be converted.
+ * @param string $format The format string for the returned date (default is Y-m-d H:i:s)
+ * @return string Formatted date relative to the timezone / GMT offset.
+ */
+function get_date_from_gmt( $string, $format = 'Y-m-d H:i:s' ) {
+ $tz = get_option( 'timezone_string' );
+ if ( $tz ) {
+ $datetime = date_create( $string, new DateTimeZone( 'UTC' ) );
+ if ( ! $datetime )
+ return date( $format, 0 );
+ $datetime->setTimezone( new DateTimeZone( $tz ) );
+ $string_localtime = $datetime->format( $format );
+ } else {
+ if ( ! preg_match('#([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2}) ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})#', $string, $matches) )
+ return date( $format, 0 );
+ $string_time = gmmktime( $matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1] );
+ $string_localtime = gmdate( $format, $string_time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
+ }
+ return $string_localtime;
+}
+
+/**
+ * Computes an offset in seconds from an iso8601 timezone.
+ *
+ * @since 1.5.0
+ *
+ * @param string $timezone Either 'Z' for 0 offset or '±hhmm'.
+ * @return int|float The offset in seconds.
+ */
+function iso8601_timezone_to_offset($timezone) {
+ // $timezone is either 'Z' or '[+|-]hhmm'
+ if ($timezone == 'Z') {
+ $offset = 0;
+ } else {
+ $sign = (substr($timezone, 0, 1) == '+') ? 1 : -1;
+ $hours = intval(substr($timezone, 1, 2));
+ $minutes = intval(substr($timezone, 3, 4)) / 60;
+ $offset = $sign * HOUR_IN_SECONDS * ($hours + $minutes);
+ }
+ return $offset;
+}
+
+/**
+ * Converts an iso8601 date to MySQL DateTime format used by post_date[_gmt].
+ *
+ * @since 1.5.0
+ *
+ * @param string $date_string Date and time in ISO 8601 format {@link http://en.wikipedia.org/wiki/ISO_8601}.
+ * @param string $timezone Optional. If set to GMT returns the time minus gmt_offset. Default is 'user'.
+ * @return string The date and time in MySQL DateTime format - Y-m-d H:i:s.
+ */
+function iso8601_to_datetime($date_string, $timezone = 'user') {
+ $timezone = strtolower($timezone);
+
+ if ($timezone == 'gmt') {
+
+ preg_match('#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', $date_string, $date_bits);
+
+ if (!empty($date_bits[7])) { // we have a timezone, so let's compute an offset
+ $offset = iso8601_timezone_to_offset($date_bits[7]);
+ } else { // we don't have a timezone, so we assume user local timezone (not server's!)
+ $offset = HOUR_IN_SECONDS * get_option('gmt_offset');
+ }
+
+ $timestamp = gmmktime($date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1]);
+ $timestamp -= $offset;
+
+ return gmdate('Y-m-d H:i:s', $timestamp);
+
+ } else if ($timezone == 'user') {
+ return preg_replace('#([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(Z|[\+|\-][0-9]{2,4}){0,1}#', '$1-$2-$3 $4:$5:$6', $date_string);
+ }
+}
+
+/**
+ * Adds a element attributes to open links in new windows.
+ *
+ * Comment text in popup windows should be filtered through this. Right now it's
+ * a moderately dumb function, ideally it would detect whether a target or rel
+ * attribute was already there and adjust its actions accordingly.
+ *
+ * @since 0.71
+ *
+ * @param string $text Content to replace links to open in a new window.
+ * @return string Content that has filtered links.
+ */
+function popuplinks($text) {
+ $text = preg_replace('/<a (.+?)>/i', "<a $1 target='_blank' rel='external'>", $text);
+ return $text;
+}
+
+/**
+ * Strips out all characters that are not allowable in an email.
+ *
+ * @since 1.5.0
+ *
+ * @param string $email Email address to filter.
+ * @return string Filtered email address.
+ */
+function sanitize_email( $email ) {
+ // Test for the minimum length the email can be
+ if ( strlen( $email ) < 3 ) {
+ return apply_filters( 'sanitize_email', '', $email, 'email_too_short' );
+ }
+
+ // Test for an @ character after the first position
+ if ( strpos( $email, '@', 1 ) === false ) {
+ return apply_filters( 'sanitize_email', '', $email, 'email_no_at' );
+ }
+
+ // Split out the local and domain parts
+ list( $local, $domain ) = explode( '@', $email, 2 );
+
+ // LOCAL PART
+ // Test for invalid characters
+ $local = preg_replace( '/[^a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]/', '', $local );
+ if ( '' === $local ) {
+ return apply_filters( 'sanitize_email', '', $email, 'local_invalid_chars' );
+ }
+
+ // DOMAIN PART
+ // Test for sequences of periods
+ $domain = preg_replace( '/\.{2,}/', '', $domain );
+ if ( '' === $domain ) {
+ return apply_filters( 'sanitize_email', '', $email, 'domain_period_sequence' );
+ }
+
+ // Test for leading and trailing periods and whitespace
+ $domain = trim( $domain, " \t\n\r\0\x0B." );
+ if ( '' === $domain ) {
+ return apply_filters( 'sanitize_email', '', $email, 'domain_period_limits' );
+ }
+
+ // Split the domain into subs
+ $subs = explode( '.', $domain );
+
+ // Assume the domain will have at least two subs
+ if ( 2 > count( $subs ) ) {
+ return apply_filters( 'sanitize_email', '', $email, 'domain_no_periods' );
+ }
+
+ // Create an array that will contain valid subs
+ $new_subs = array();
+
+ // Loop through each sub
+ foreach ( $subs as $sub ) {
+ // Test for leading and trailing hyphens
+ $sub = trim( $sub, " \t\n\r\0\x0B-" );
+
+ // Test for invalid characters
+ $sub = preg_replace( '/[^a-z0-9-]+/i', '', $sub );
+
+ // If there's anything left, add it to the valid subs
+ if ( '' !== $sub ) {
+ $new_subs[] = $sub;
+ }
+ }
+
+ // If there aren't 2 or more valid subs
+ if ( 2 > count( $new_subs ) ) {
+ return apply_filters( 'sanitize_email', '', $email, 'domain_no_valid_subs' );
+ }
+
+ // Join valid subs into the new domain
+ $domain = join( '.', $new_subs );
+
+ // Put the email back together
+ $email = $local . '@' . $domain;
+
+ // Congratulations your email made it!
+ return apply_filters( 'sanitize_email', $email, $email, null );
+}
+
+/**
+ * Determines the difference between two timestamps.
+ *
+ * The difference is returned in a human readable format such as "1 hour",
+ * "5 mins", "2 days".
+ *
+ * @since 1.5.0
+ *
+ * @param int $from Unix timestamp from which the difference begins.
+ * @param int $to Optional. Unix timestamp to end the time difference. Default becomes time() if not set.
+ * @return string Human readable time difference.
+ */
+function human_time_diff( $from, $to = '' ) {
+ if ( empty( $to ) )
+ $to = time();
+
+ $diff = (int) abs( $to - $from );
+
+ if ( $diff < HOUR_IN_SECONDS ) {
+ $mins = round( $diff / MINUTE_IN_SECONDS );
+ if ( $mins <= 1 )
+ $mins = 1;
+ /* translators: min=minute */
+ $since = sprintf( _n( '%s min', '%s mins', $mins ), $mins );
+ } elseif ( $diff < DAY_IN_SECONDS && $diff >= HOUR_IN_SECONDS ) {
+ $hours = round( $diff / HOUR_IN_SECONDS );
+ if ( $hours <= 1 )
+ $hours = 1;
+ $since = sprintf( _n( '%s hour', '%s hours', $hours ), $hours );
+ } elseif ( $diff < WEEK_IN_SECONDS && $diff >= DAY_IN_SECONDS ) {
+ $days = round( $diff / DAY_IN_SECONDS );
+ if ( $days <= 1 )
+ $days = 1;
+ $since = sprintf( _n( '%s day', '%s days', $days ), $days );
+ } elseif ( $diff < 30 * DAY_IN_SECONDS && $diff >= WEEK_IN_SECONDS ) {
+ $weeks = round( $diff / WEEK_IN_SECONDS );
+ if ( $weeks <= 1 )
+ $weeks = 1;
+ $since = sprintf( _n( '%s week', '%s weeks', $weeks ), $weeks );
+ } elseif ( $diff < YEAR_IN_SECONDS && $diff >= 30 * DAY_IN_SECONDS ) {
+ $months = round( $diff / ( 30 * DAY_IN_SECONDS ) );
+ if ( $months <= 1 )
+ $months = 1;
+ $since = sprintf( _n( '%s month', '%s months', $months ), $months );
+ } elseif ( $diff >= YEAR_IN_SECONDS ) {
+ $years = round( $diff / YEAR_IN_SECONDS );
+ if ( $years <= 1 )
+ $years = 1;
+ $since = sprintf( _n( '%s year', '%s years', $years ), $years );
+ }
+
+ return $since;
+}
+
+/**
+ * Generates an excerpt from the content, if needed.
+ *
+ * The excerpt word amount will be 55 words and if the amount is greater than
+ * that, then the string ' [&hellip;]' will be appended to the excerpt. If the string
+ * is less than 55 words, then the content will be returned as is.
+ *
+ * The 55 word limit can be modified by plugins/themes using the excerpt_length filter
+ * The ' [&hellip;]' string can be modified by plugins/themes using the excerpt_more filter
+ *
+ * @since 1.5.0
+ *
+ * @param string $text Optional. The excerpt. If set to empty, an excerpt is generated.
+ * @return string The excerpt.
+ */
+function wp_trim_excerpt($text = '') {
+ $raw_excerpt = $text;
+ if ( '' == $text ) {
+ $text = get_the_content('');
+
+ $text = strip_shortcodes( $text );
+
+ $text = apply_filters('the_content', $text);
+ $text = str_replace(']]>', ']]&gt;', $text);
+ $excerpt_length = apply_filters('excerpt_length', 55);
+ $excerpt_more = apply_filters('excerpt_more', ' ' . '[&hellip;]');
+ $text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
+ }
+ return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
+}
+
+/**
+ * Trims text to a certain number of words.
+ *
+ * This function is localized. For languages that count 'words' by the individual
+ * character (such as East Asian languages), the $num_words argument will apply
+ * to the number of individual characters.
+ *
+ * @since 3.3.0
+ *
+ * @param string $text Text to trim.
+ * @param int $num_words Number of words. Default 55.
+ * @param string $more Optional. What to append if $text needs to be trimmed. Default '&hellip;'.
+ * @return string Trimmed text.
+ */
+function wp_trim_words( $text, $num_words = 55, $more = null ) {
+ if ( null === $more )
+ $more = __( '&hellip;' );
+ $original_text = $text;
+ $text = wp_strip_all_tags( $text );
+ /* translators: If your word count is based on single characters (East Asian characters),
+ enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
+ if ( 'characters' == _x( 'words', 'word count: words or characters?' ) && preg_match( '/^utf\-?8$/i', get_option( 'blog_charset' ) ) ) {
+ $text = trim( preg_replace( "/[\n\r\t ]+/", ' ', $text ), ' ' );
+ preg_match_all( '/./u', $text, $words_array );
+ $words_array = array_slice( $words_array[0], 0, $num_words + 1 );
+ $sep = '';
+ } else {
+ $words_array = preg_split( "/[\n\r\t ]+/", $text, $num_words + 1, PREG_SPLIT_NO_EMPTY );
+ $sep = ' ';
+ }
+ if ( count( $words_array ) > $num_words ) {
+ array_pop( $words_array );
+ $text = implode( $sep, $words_array );
+ $text = $text . $more;
+ } else {
+ $text = implode( $sep, $words_array );
+ }
+ return apply_filters( 'wp_trim_words', $text, $num_words, $more, $original_text );
+}
+
+/**
+ * Converts named entities into numbered entities.
+ *
+ * @since 1.5.1
+ *
+ * @param string $text The text within which entities will be converted.
+ * @return string Text with converted entities.
+ */
+function ent2ncr($text) {
+
+ // Allow a plugin to short-circuit and override the mappings.
+ $filtered = apply_filters( 'pre_ent2ncr', null, $text );
+ if( null !== $filtered )
+ return $filtered;
+
+ $to_ncr = array(
+ '&quot;' => '&#34;',
+ '&amp;' => '&#38;',
+ '&lt;' => '&#60;',
+ '&gt;' => '&#62;',
+ '|' => '&#124;',
+ '&nbsp;' => '&#160;',
+ '&iexcl;' => '&#161;',
+ '&cent;' => '&#162;',
+ '&pound;' => '&#163;',
+ '&curren;' => '&#164;',
+ '&yen;' => '&#165;',
+ '&brvbar;' => '&#166;',
+ '&brkbar;' => '&#166;',
+ '&sect;' => '&#167;',
+ '&uml;' => '&#168;',
+ '&die;' => '&#168;',
+ '&copy;' => '&#169;',
+ '&ordf;' => '&#170;',
+ '&laquo;' => '&#171;',
+ '&not;' => '&#172;',
+ '&shy;' => '&#173;',
+ '&reg;' => '&#174;',
+ '&macr;' => '&#175;',
+ '&hibar;' => '&#175;',
+ '&deg;' => '&#176;',
+ '&plusmn;' => '&#177;',
+ '&sup2;' => '&#178;',
+ '&sup3;' => '&#179;',
+ '&acute;' => '&#180;',
+ '&micro;' => '&#181;',
+ '&para;' => '&#182;',
+ '&middot;' => '&#183;',
+ '&cedil;' => '&#184;',
+ '&sup1;' => '&#185;',
+ '&ordm;' => '&#186;',
+ '&raquo;' => '&#187;',
+ '&frac14;' => '&#188;',
+ '&frac12;' => '&#189;',
+ '&frac34;' => '&#190;',
+ '&iquest;' => '&#191;',
+ '&Agrave;' => '&#192;',
+ '&Aacute;' => '&#193;',
+ '&Acirc;' => '&#194;',
+ '&Atilde;' => '&#195;',
+ '&Auml;' => '&#196;',
+ '&Aring;' => '&#197;',
+ '&AElig;' => '&#198;',
+ '&Ccedil;' => '&#199;',
+ '&Egrave;' => '&#200;',
+ '&Eacute;' => '&#201;',
+ '&Ecirc;' => '&#202;',
+ '&Euml;' => '&#203;',
+ '&Igrave;' => '&#204;',
+ '&Iacute;' => '&#205;',
+ '&Icirc;' => '&#206;',
+ '&Iuml;' => '&#207;',
+ '&ETH;' => '&#208;',
+ '&Ntilde;' => '&#209;',
+ '&Ograve;' => '&#210;',
+ '&Oacute;' => '&#211;',
+ '&Ocirc;' => '&#212;',
+ '&Otilde;' => '&#213;',
+ '&Ouml;' => '&#214;',
+ '&times;' => '&#215;',
+ '&Oslash;' => '&#216;',
+ '&Ugrave;' => '&#217;',
+ '&Uacute;' => '&#218;',
+ '&Ucirc;' => '&#219;',
+ '&Uuml;' => '&#220;',
+ '&Yacute;' => '&#221;',
+ '&THORN;' => '&#222;',
+ '&szlig;' => '&#223;',
+ '&agrave;' => '&#224;',
+ '&aacute;' => '&#225;',
+ '&acirc;' => '&#226;',
+ '&atilde;' => '&#227;',
+ '&auml;' => '&#228;',
+ '&aring;' => '&#229;',
+ '&aelig;' => '&#230;',
+ '&ccedil;' => '&#231;',
+ '&egrave;' => '&#232;',
+ '&eacute;' => '&#233;',
+ '&ecirc;' => '&#234;',
+ '&euml;' => '&#235;',
+ '&igrave;' => '&#236;',
+ '&iacute;' => '&#237;',
+ '&icirc;' => '&#238;',
+ '&iuml;' => '&#239;',
+ '&eth;' => '&#240;',
+ '&ntilde;' => '&#241;',
+ '&ograve;' => '&#242;',
+ '&oacute;' => '&#243;',
+ '&ocirc;' => '&#244;',
+ '&otilde;' => '&#245;',
+ '&ouml;' => '&#246;',
+ '&divide;' => '&#247;',
+ '&oslash;' => '&#248;',
+ '&ugrave;' => '&#249;',
+ '&uacute;' => '&#250;',
+ '&ucirc;' => '&#251;',
+ '&uuml;' => '&#252;',
+ '&yacute;' => '&#253;',
+ '&thorn;' => '&#254;',
+ '&yuml;' => '&#255;',
+ '&OElig;' => '&#338;',
+ '&oelig;' => '&#339;',
+ '&Scaron;' => '&#352;',
+ '&scaron;' => '&#353;',
+ '&Yuml;' => '&#376;',
+ '&fnof;' => '&#402;',
+ '&circ;' => '&#710;',
+ '&tilde;' => '&#732;',
+ '&Alpha;' => '&#913;',
+ '&Beta;' => '&#914;',
+ '&Gamma;' => '&#915;',
+ '&Delta;' => '&#916;',
+ '&Epsilon;' => '&#917;',
+ '&Zeta;' => '&#918;',
+ '&Eta;' => '&#919;',
+ '&Theta;' => '&#920;',
+ '&Iota;' => '&#921;',
+ '&Kappa;' => '&#922;',
+ '&Lambda;' => '&#923;',
+ '&Mu;' => '&#924;',
+ '&Nu;' => '&#925;',
+ '&Xi;' => '&#926;',
+ '&Omicron;' => '&#927;',
+ '&Pi;' => '&#928;',
+ '&Rho;' => '&#929;',
+ '&Sigma;' => '&#931;',
+ '&Tau;' => '&#932;',
+ '&Upsilon;' => '&#933;',
+ '&Phi;' => '&#934;',
+ '&Chi;' => '&#935;',
+ '&Psi;' => '&#936;',
+ '&Omega;' => '&#937;',
+ '&alpha;' => '&#945;',
+ '&beta;' => '&#946;',
+ '&gamma;' => '&#947;',
+ '&delta;' => '&#948;',
+ '&epsilon;' => '&#949;',
+ '&zeta;' => '&#950;',
+ '&eta;' => '&#951;',
+ '&theta;' => '&#952;',
+ '&iota;' => '&#953;',
+ '&kappa;' => '&#954;',
+ '&lambda;' => '&#955;',
+ '&mu;' => '&#956;',
+ '&nu;' => '&#957;',
+ '&xi;' => '&#958;',
+ '&omicron;' => '&#959;',
+ '&pi;' => '&#960;',
+ '&rho;' => '&#961;',
+ '&sigmaf;' => '&#962;',
+ '&sigma;' => '&#963;',
+ '&tau;' => '&#964;',
+ '&upsilon;' => '&#965;',
+ '&phi;' => '&#966;',
+ '&chi;' => '&#967;',
+ '&psi;' => '&#968;',
+ '&omega;' => '&#969;',
+ '&thetasym;' => '&#977;',
+ '&upsih;' => '&#978;',
+ '&piv;' => '&#982;',
+ '&ensp;' => '&#8194;',
+ '&emsp;' => '&#8195;',
+ '&thinsp;' => '&#8201;',
+ '&zwnj;' => '&#8204;',
+ '&zwj;' => '&#8205;',
+ '&lrm;' => '&#8206;',
+ '&rlm;' => '&#8207;',
+ '&ndash;' => '&#8211;',
+ '&mdash;' => '&#8212;',
+ '&lsquo;' => '&#8216;',
+ '&rsquo;' => '&#8217;',
+ '&sbquo;' => '&#8218;',
+ '&ldquo;' => '&#8220;',
+ '&rdquo;' => '&#8221;',
+ '&bdquo;' => '&#8222;',
+ '&dagger;' => '&#8224;',
+ '&Dagger;' => '&#8225;',
+ '&bull;' => '&#8226;',
+ '&hellip;' => '&#8230;',
+ '&permil;' => '&#8240;',
+ '&prime;' => '&#8242;',
+ '&Prime;' => '&#8243;',
+ '&lsaquo;' => '&#8249;',
+ '&rsaquo;' => '&#8250;',
+ '&oline;' => '&#8254;',
+ '&frasl;' => '&#8260;',
+ '&euro;' => '&#8364;',
+ '&image;' => '&#8465;',
+ '&weierp;' => '&#8472;',
+ '&real;' => '&#8476;',
+ '&trade;' => '&#8482;',
+ '&alefsym;' => '&#8501;',
+ '&crarr;' => '&#8629;',
+ '&lArr;' => '&#8656;',
+ '&uArr;' => '&#8657;',
+ '&rArr;' => '&#8658;',
+ '&dArr;' => '&#8659;',
+ '&hArr;' => '&#8660;',
+ '&forall;' => '&#8704;',
+ '&part;' => '&#8706;',
+ '&exist;' => '&#8707;',
+ '&empty;' => '&#8709;',
+ '&nabla;' => '&#8711;',
+ '&isin;' => '&#8712;',
+ '&notin;' => '&#8713;',
+ '&ni;' => '&#8715;',
+ '&prod;' => '&#8719;',
+ '&sum;' => '&#8721;',
+ '&minus;' => '&#8722;',
+ '&lowast;' => '&#8727;',
+ '&radic;' => '&#8730;',
+ '&prop;' => '&#8733;',
+ '&infin;' => '&#8734;',
+ '&ang;' => '&#8736;',
+ '&and;' => '&#8743;',
+ '&or;' => '&#8744;',
+ '&cap;' => '&#8745;',
+ '&cup;' => '&#8746;',
+ '&int;' => '&#8747;',
+ '&there4;' => '&#8756;',
+ '&sim;' => '&#8764;',
+ '&cong;' => '&#8773;',
+ '&asymp;' => '&#8776;',
+ '&ne;' => '&#8800;',
+ '&equiv;' => '&#8801;',
+ '&le;' => '&#8804;',
+ '&ge;' => '&#8805;',
+ '&sub;' => '&#8834;',
+ '&sup;' => '&#8835;',
+ '&nsub;' => '&#8836;',
+ '&sube;' => '&#8838;',
+ '&supe;' => '&#8839;',
+ '&oplus;' => '&#8853;',
+ '&otimes;' => '&#8855;',
+ '&perp;' => '&#8869;',
+ '&sdot;' => '&#8901;',
+ '&lceil;' => '&#8968;',
+ '&rceil;' => '&#8969;',
+ '&lfloor;' => '&#8970;',
+ '&rfloor;' => '&#8971;',
+ '&lang;' => '&#9001;',
+ '&rang;' => '&#9002;',
+ '&larr;' => '&#8592;',
+ '&uarr;' => '&#8593;',
+ '&rarr;' => '&#8594;',
+ '&darr;' => '&#8595;',
+ '&harr;' => '&#8596;',
+ '&loz;' => '&#9674;',
+ '&spades;' => '&#9824;',
+ '&clubs;' => '&#9827;',
+ '&hearts;' => '&#9829;',
+ '&diams;' => '&#9830;'
+ );
+
+ return str_replace( array_keys($to_ncr), array_values($to_ncr), $text );
+}
+
+/**
+ * Formats text for the rich text editor.
+ *
+ * The filter 'richedit_pre' is applied here. If $text is empty the filter will
+ * be applied to an empty string.
+ *
+ * @since 2.0.0
+ *
+ * @param string $text The text to be formatted.
+ * @return string The formatted text after filter is applied.
+ */
+function wp_richedit_pre($text) {
+ // Filtering a blank results in an annoying <br />\n
+ if ( empty($text) ) return apply_filters('richedit_pre', '');
+
+ $output = convert_chars($text);
+ $output = wpautop($output);
+ $output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) );
+
+ return apply_filters('richedit_pre', $output);
+}
+
+/**
+ * Formats text for the HTML editor.
+ *
+ * Unless $output is empty it will pass through htmlspecialchars before the
+ * 'htmledit_pre' filter is applied.
+ *
+ * @since 2.5.0
+ *
+ * @param string $output The text to be formatted.
+ * @return string Formatted text after filter applied.
+ */
+function wp_htmledit_pre($output) {
+ if ( !empty($output) )
+ $output = htmlspecialchars($output, ENT_NOQUOTES, get_option( 'blog_charset' ) ); // convert only < > &
+
+ return apply_filters('htmledit_pre', $output);
+}
+
+/**
+ * Perform a deep string replace operation to ensure the values in $search are no longer present
+ *
+ * Repeats the replacement operation until it no longer replaces anything so as to remove "nested" values
+ * e.g. $subject = '%0%0%0DDD', $search ='%0D', $result ='' rather than the '%0%0DD' that
+ * str_replace would return
+ *
+ * @since 2.8.1
+ * @access private
+ *
+ * @param string|array $search
+ * @param string $subject
+ * @return string The processed string
+ */
+function _deep_replace( $search, $subject ) {
+ $found = true;
+ $subject = (string) $subject;
+ while ( $found ) {
+ $found = false;
+ foreach ( (array) $search as $val ) {
+ while ( strpos( $subject, $val ) !== false ) {
+ $found = true;
+ $subject = str_replace( $val, '', $subject );
+ }
+ }
+ }
+
+ return $subject;
+}
+
+/**
+ * Escapes data for use in a MySQL query.
+ *
+ * Usually you should prepare queries using wpdb::prepare().
+ * Sometimes, spot-escaping is required or useful. One example
+ * is preparing an array for use in an IN clause.
+ *
+ * @since 2.8.0
+ * @param string|array $data Unescaped data
+ * @return string|array Escaped data
+ */
+function esc_sql( $data ) {
+ global $wpdb;
+ return $wpdb->_escape( $data );
+}
+
+/**
+ * Checks and cleans a URL.
+ *
+ * A number of characters are removed from the URL. If the URL is for displaying
+ * (the default behaviour) ampersands are also replaced. The 'clean_url' filter
+ * is applied to the returned cleaned URL.
+ *
+ * @since 2.8.0
+ * @uses wp_kses_bad_protocol() To only permit protocols in the URL set
+ * via $protocols or the common ones set in the function.
+ *
+ * @param string $url The URL to be cleaned.
+ * @param array $protocols Optional. An array of acceptable protocols.
+ * Defaults to 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn' if not set.
+ * @param string $_context Private. Use esc_url_raw() for database usage.
+ * @return string The cleaned $url after the 'clean_url' filter is applied.
+ */
+function esc_url( $url, $protocols = null, $_context = 'display' ) {
+ $original_url = $url;
+
+ if ( '' == $url )
+ return $url;
+ $url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url);
+ $strip = array('%0d', '%0a', '%0D', '%0A');
+ $url = _deep_replace($strip, $url);
+ $url = str_replace(';//', '://', $url);
+ /* If the URL doesn't appear to contain a scheme, we
+ * presume it needs http:// appended (unless a relative
+ * link starting with /, # or ? or a php file).
+ */
+ if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) &&
+ ! preg_match('/^[a-z0-9-]+?\.php/i', $url) )
+ $url = 'http://' . $url;
+
+ // Replace ampersands and single quotes only when displaying.
+ if ( 'display' == $_context ) {
+ $url = wp_kses_normalize_entities( $url );
+ $url = str_replace( '&amp;', '&#038;', $url );
+ $url = str_replace( "'", '&#039;', $url );
+ }
+
+ if ( '/' === $url[0] ) {
+ $good_protocol_url = $url;
+ } else {
+ if ( ! is_array( $protocols ) )
+ $protocols = wp_allowed_protocols();
+ $good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
+ if ( strtolower( $good_protocol_url ) != strtolower( $url ) )
+ return '';
+ }
+
+ return apply_filters('clean_url', $good_protocol_url, $original_url, $_context);
+}
+
+/**
+ * Performs esc_url() for database usage.
+ *
+ * @since 2.8.0
+ * @uses esc_url()
+ *
+ * @param string $url The URL to be cleaned.
+ * @param array $protocols An array of acceptable protocols.
+ * @return string The cleaned URL.
+ */
+function esc_url_raw( $url, $protocols = null ) {
+ return esc_url( $url, $protocols, 'db' );
+}
+
+/**
+ * Convert entities, while preserving already-encoded entities.
+ *
+ * @link http://www.php.net/htmlentities Borrowed from the PHP Manual user notes.
+ *
+ * @since 1.2.2
+ *
+ * @param string $myHTML The text to be converted.
+ * @return string Converted text.
+ */
+function htmlentities2($myHTML) {
+ $translation_table = get_html_translation_table( HTML_ENTITIES, ENT_QUOTES );
+ $translation_table[chr(38)] = '&';
+ return preg_replace( "/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,3};)/", "&amp;", strtr($myHTML, $translation_table) );
+}
+
+/**
+ * Escape single quotes, htmlspecialchar " < > &, and fix line endings.
+ *
+ * Escapes text strings for echoing in JS. It is intended to be used for inline JS
+ * (in a tag attribute, for example onclick="..."). Note that the strings have to
+ * be in single quotes. The filter 'js_escape' is also applied here.
+ *
+ * @since 2.8.0
+ *
+ * @param string $text The text to be escaped.
+ * @return string Escaped text.
+ */
+function esc_js( $text ) {
+ $safe_text = wp_check_invalid_utf8( $text );
+ $safe_text = _wp_specialchars( $safe_text, ENT_COMPAT );
+ $safe_text = preg_replace( '/&#(x)?0*(?(1)27|39);?/i', "'", stripslashes( $safe_text ) );
+ $safe_text = str_replace( "\r", '', $safe_text );
+ $safe_text = str_replace( "\n", '\\n', addslashes( $safe_text ) );
+ return apply_filters( 'js_escape', $safe_text, $text );
+}
+
+/**
+ * Escaping for HTML blocks.
+ *
+ * @since 2.8.0
+ *
+ * @param string $text
+ * @return string
+ */
+function esc_html( $text ) {
+ $safe_text = wp_check_invalid_utf8( $text );
+ $safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
+ return apply_filters( 'esc_html', $safe_text, $text );
+}
+
+/**
+ * Escaping for HTML attributes.
+ *
+ * @since 2.8.0
+ *
+ * @param string $text
+ * @return string
+ */
+function esc_attr( $text ) {
+ $safe_text = wp_check_invalid_utf8( $text );
+ $safe_text = _wp_specialchars( $safe_text, ENT_QUOTES );
+ return apply_filters( 'attribute_escape', $safe_text, $text );
+}
+
+/**
+ * Escaping for textarea values.
+ *
+ * @since 3.1.0
+ *
+ * @param string $text
+ * @return string
+ */
+function esc_textarea( $text ) {
+ $safe_text = htmlspecialchars( $text, ENT_QUOTES, get_option( 'blog_charset' ) );
+ return apply_filters( 'esc_textarea', $safe_text, $text );
+}
+
+/**
+ * Escape an HTML tag name.
+ *
+ * @since 2.5.0
+ *
+ * @param string $tag_name
+ * @return string
+ */
+function tag_escape($tag_name) {
+ $safe_tag = strtolower( preg_replace('/[^a-zA-Z0-9_:]/', '', $tag_name) );
+ return apply_filters('tag_escape', $safe_tag, $tag_name);
+}
+
+/**
+ * Escapes text for SQL LIKE special characters % and _.
+ *
+ * @since 2.5.0
+ *
+ * @param string $text The text to be escaped.
+ * @return string text, safe for inclusion in LIKE query.
+ */
+function like_escape($text) {
+ return str_replace(array("%", "_"), array("\\%", "\\_"), $text);
+}
+
+/**
+ * Convert full URL paths to absolute paths.
+ *
+ * Removes the http or https protocols and the domain. Keeps the path '/' at the
+ * beginning, so it isn't a true relative link, but from the web root base.
+ *
+ * @since 2.1.0
+ *
+ * @param string $link Full URL path.
+ * @return string Absolute path.
+ */
+function wp_make_link_relative( $link ) {
+ return preg_replace( '|https?://[^/]+(/.*)|i', '$1', $link );
+}
+
+/**
+ * Sanitises various option values based on the nature of the option.
+ *
+ * This is basically a switch statement which will pass $value through a number
+ * of functions depending on the $option.
+ *
+ * @since 2.0.5
+ *
+ * @param string $option The name of the option.
+ * @param string $value The unsanitised value.
+ * @return string Sanitized value.
+ */
+function sanitize_option($option, $value) {
+
+ switch ( $option ) {
+ case 'admin_email' :
+ case 'new_admin_email' :
+ $value = sanitize_email( $value );
+ if ( ! is_email( $value ) ) {
+ $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
+ if ( function_exists( 'add_settings_error' ) )
+ add_settings_error( $option, 'invalid_admin_email', __( 'The email address entered did not appear to be a valid email address. Please enter a valid email address.' ) );
+ }
+ break;
+
+ case 'thumbnail_size_w':
+ case 'thumbnail_size_h':
+ case 'medium_size_w':
+ case 'medium_size_h':
+ case 'large_size_w':
+ case 'large_size_h':
+ case 'mailserver_port':
+ case 'comment_max_links':
+ case 'page_on_front':
+ case 'page_for_posts':
+ case 'rss_excerpt_length':
+ case 'default_category':
+ case 'default_email_category':
+ case 'default_link_category':
+ case 'close_comments_days_old':
+ case 'comments_per_page':
+ case 'thread_comments_depth':
+ case 'users_can_register':
+ case 'start_of_week':
+ $value = absint( $value );
+ break;
+
+ case 'posts_per_page':
+ case 'posts_per_rss':
+ $value = (int) $value;
+ if ( empty($value) )
+ $value = 1;
+ if ( $value < -1 )
+ $value = abs($value);
+ break;
+
+ case 'default_ping_status':
+ case 'default_comment_status':
+ // Options that if not there have 0 value but need to be something like "closed"
+ if ( $value == '0' || $value == '')
+ $value = 'closed';
+ break;
+
+ case 'blogdescription':
+ case 'blogname':
+ $value = wp_kses_post( $value );
+ $value = esc_html( $value );
+ break;
+
+ case 'blog_charset':
+ $value = preg_replace('/[^a-zA-Z0-9_-]/', '', $value); // strips slashes
+ break;
+
+ case 'blog_public':
+ // This is the value if the settings checkbox is not checked on POST. Don't rely on this.
+ if ( null === $value )
+ $value = 1;
+ else
+ $value = intval( $value );
+ break;
+
+ case 'date_format':
+ case 'time_format':
+ case 'mailserver_url':
+ case 'mailserver_login':
+ case 'mailserver_pass':
+ case 'upload_path':
+ $value = strip_tags( $value );
+ $value = wp_kses_data( $value );
+ break;
+
+ case 'ping_sites':
+ $value = explode( "\n", $value );
+ $value = array_filter( array_map( 'trim', $value ) );
+ $value = array_filter( array_map( 'esc_url_raw', $value ) );
+ $value = implode( "\n", $value );
+ break;
+
+ case 'gmt_offset':
+ $value = preg_replace('/[^0-9:.-]/', '', $value); // strips slashes
+ break;
+
+ case 'siteurl':
+ if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
+ $value = esc_url_raw($value);
+ } else {
+ $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
+ if ( function_exists('add_settings_error') )
+ add_settings_error('siteurl', 'invalid_siteurl', __('The WordPress address you entered did not appear to be a valid URL. Please enter a valid URL.'));
+ }
+ break;
+
+ case 'home':
+ if ( (bool)preg_match( '#http(s?)://(.+)#i', $value) ) {
+ $value = esc_url_raw($value);
+ } else {
+ $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
+ if ( function_exists('add_settings_error') )
+ add_settings_error('home', 'invalid_home', __('The Site address you entered did not appear to be a valid URL. Please enter a valid URL.'));
+ }
+ break;
+
+ case 'WPLANG':
+ $allowed = get_available_languages();
+ if ( ! in_array( $value, $allowed ) && ! empty( $value ) )
+ $value = get_option( $option );
+ break;
+
+ case 'illegal_names':
+ if ( ! is_array( $value ) )
+ $value = explode( ' ', $value );
+
+ $value = array_values( array_filter( array_map( 'trim', $value ) ) );
+
+ if ( ! $value )
+ $value = '';
+ break;
+
+ case 'limited_email_domains':
+ case 'banned_email_domains':
+ if ( ! is_array( $value ) )
+ $value = explode( "\n", $value );
+
+ $domains = array_values( array_filter( array_map( 'trim', $value ) ) );
+ $value = array();
+
+ foreach ( $domains as $domain ) {
+ if ( ! preg_match( '/(--|\.\.)/', $domain ) && preg_match( '|^([a-zA-Z0-9-\.])+$|', $domain ) )
+ $value[] = $domain;
+ }
+ if ( ! $value )
+ $value = '';
+ break;
+
+ case 'timezone_string':
+ $allowed_zones = timezone_identifiers_list();
+ if ( ! in_array( $value, $allowed_zones ) && ! empty( $value ) ) {
+ $value = get_option( $option ); // Resets option to stored value in the case of failed sanitization
+ if ( function_exists('add_settings_error') )
+ add_settings_error('timezone_string', 'invalid_timezone_string', __('The timezone you have entered is not valid. Please select a valid timezone.') );
+ }
+ break;
+
+ case 'permalink_structure':
+ case 'category_base':
+ case 'tag_base':
+ $value = esc_url_raw( $value );
+ $value = str_replace( 'http://', '', $value );
+ break;
+ }
+
+ $value = apply_filters("sanitize_option_{$option}", $value, $option);
+
+ return $value;
+}
+
+/**
+ * Parses a string into variables to be stored in an array.
+ *
+ * Uses {@link http://www.php.net/parse_str parse_str()} and stripslashes if
+ * {@link http://www.php.net/magic_quotes magic_quotes_gpc} is on.
+ *
+ * @since 2.2.1
+ * @uses apply_filters() for the 'wp_parse_str' filter.
+ *
+ * @param string $string The string to be parsed.
+ * @param array $array Variables will be stored in this array.
+ */
+function wp_parse_str( $string, &$array ) {
+ parse_str( $string, $array );
+ if ( get_magic_quotes_gpc() )
+ $array = stripslashes_deep( $array );
+ $array = apply_filters( 'wp_parse_str', $array );
+}
+
+/**
+ * Convert lone less than signs.
+ *
+ * KSES already converts lone greater than signs.
+ *
+ * @uses wp_pre_kses_less_than_callback in the callback function.
+ * @since 2.3.0
+ *
+ * @param string $text Text to be converted.
+ * @return string Converted text.
+ */
+function wp_pre_kses_less_than( $text ) {
+ return preg_replace_callback('%<[^>]*?((?=<)|>|$)%', 'wp_pre_kses_less_than_callback', $text);
+}
+
+/**
+ * Callback function used by preg_replace.
+ *
+ * @uses esc_html to format the $matches text.
+ * @since 2.3.0
+ *
+ * @param array $matches Populated by matches to preg_replace.
+ * @return string The text returned after esc_html if needed.
+ */
+function wp_pre_kses_less_than_callback( $matches ) {
+ if ( false === strpos($matches[0], '>') )
+ return esc_html($matches[0]);
+ return $matches[0];
+}
+
+/**
+ * WordPress implementation of PHP sprintf() with filters.
+ *
+ * @since 2.5.0
+ * @link http://www.php.net/sprintf
+ *
+ * @param string $pattern The string which formatted args are inserted.
+ * @param mixed $args,... Arguments to be formatted into the $pattern string.
+ * @return string The formatted string.
+ */
+function wp_sprintf( $pattern ) {
+ $args = func_get_args();
+ $len = strlen($pattern);
+ $start = 0;
+ $result = '';
+ $arg_index = 0;
+ while ( $len > $start ) {
+ // Last character: append and break
+ if ( strlen($pattern) - 1 == $start ) {
+ $result .= substr($pattern, -1);
+ break;
+ }
+
+ // Literal %: append and continue
+ if ( substr($pattern, $start, 2) == '%%' ) {
+ $start += 2;
+ $result .= '%';
+ continue;
+ }
+
+ // Get fragment before next %
+ $end = strpos($pattern, '%', $start + 1);
+ if ( false === $end )
+ $end = $len;
+ $fragment = substr($pattern, $start, $end - $start);
+
+ // Fragment has a specifier
+ if ( $pattern[$start] == '%' ) {
+ // Find numbered arguments or take the next one in order
+ if ( preg_match('/^%(\d+)\$/', $fragment, $matches) ) {
+ $arg = isset($args[$matches[1]]) ? $args[$matches[1]] : '';
+ $fragment = str_replace("%{$matches[1]}$", '%', $fragment);
+ } else {
+ ++$arg_index;
+ $arg = isset($args[$arg_index]) ? $args[$arg_index] : '';
+ }
+
+ // Apply filters OR sprintf
+ $_fragment = apply_filters( 'wp_sprintf', $fragment, $arg );
+ if ( $_fragment != $fragment )
+ $fragment = $_fragment;
+ else
+ $fragment = sprintf($fragment, strval($arg) );
+ }
+
+ // Append to result and move to next fragment
+ $result .= $fragment;
+ $start = $end;
+ }
+ return $result;
+}
+
+/**
+ * Localize list items before the rest of the content.
+ *
+ * The '%l' must be at the first characters can then contain the rest of the
+ * content. The list items will have ', ', ', and', and ' and ' added depending
+ * on the amount of list items in the $args parameter.
+ *
+ * @since 2.5.0
+ *
+ * @param string $pattern Content containing '%l' at the beginning.
+ * @param array $args List items to prepend to the content and replace '%l'.
+ * @return string Localized list items and rest of the content.
+ */
+function wp_sprintf_l($pattern, $args) {
+ // Not a match
+ if ( substr($pattern, 0, 2) != '%l' )
+ return $pattern;
+
+ // Nothing to work with
+ if ( empty($args) )
+ return '';
+
+ // Translate and filter the delimiter set (avoid ampersands and entities here)
+ $l = apply_filters('wp_sprintf_l', array(
+ /* translators: used between list items, there is a space after the comma */
+ 'between' => __(', '),
+ /* translators: used between list items, there is a space after the and */
+ 'between_last_two' => __(', and '),
+ /* translators: used between only two list items, there is a space after the and */
+ 'between_only_two' => __(' and '),
+ ));
+
+ $args = (array) $args;
+ $result = array_shift($args);
+ if ( count($args) == 1 )
+ $result .= $l['between_only_two'] . array_shift($args);
+ // Loop when more than two args
+ $i = count($args);
+ while ( $i ) {
+ $arg = array_shift($args);
+ $i--;
+ if ( 0 == $i )
+ $result .= $l['between_last_two'] . $arg;
+ else
+ $result .= $l['between'] . $arg;
+ }
+ return $result . substr($pattern, 2);
+}
+
+/**
+ * Safely extracts not more than the first $count characters from html string.
+ *
+ * UTF-8, tags and entities safe prefix extraction. Entities inside will *NOT*
+ * be counted as one character. For example &amp; will be counted as 4, &lt; as
+ * 3, etc.
+ *
+ * @since 2.5.0
+ *
+ * @param string $str String to get the excerpt from.
+ * @param integer $count Maximum number of characters to take.
+ * @param string $more Optional. What to append if $str needs to be trimmed. Defaults to empty string.
+ * @return string The excerpt.
+ */
+function wp_html_excerpt( $str, $count, $more = null ) {
+ if ( null === $more )
+ $more = '';
+ $str = wp_strip_all_tags( $str, true );
+ $excerpt = mb_substr( $str, 0, $count );
+ // remove part of an entity at the end
+ $excerpt = preg_replace( '/&[^;\s]{0,6}$/', '', $excerpt );
+ if ( $str != $excerpt )
+ $excerpt = trim( $excerpt ) . $more;
+ return $excerpt;
+}
+
+/**
+ * Add a Base url to relative links in passed content.
+ *
+ * By default it supports the 'src' and 'href' attributes. However this can be
+ * changed via the 3rd param.
+ *
+ * @since 2.7.0
+ *
+ * @param string $content String to search for links in.
+ * @param string $base The base URL to prefix to links.
+ * @param array $attrs The attributes which should be processed.
+ * @return string The processed content.
+ */
+function links_add_base_url( $content, $base, $attrs = array('src', 'href') ) {
+ global $_links_add_base;
+ $_links_add_base = $base;
+ $attrs = implode('|', (array)$attrs);
+ return preg_replace_callback( "!($attrs)=(['\"])(.+?)\\2!i", '_links_add_base', $content );
+}
+
+/**
+ * Callback to add a base url to relative links in passed content.
+ *
+ * @since 2.7.0
+ * @access private
+ *
+ * @param string $m The matched link.
+ * @return string The processed link.
+ */
+function _links_add_base($m) {
+ global $_links_add_base;
+ //1 = attribute name 2 = quotation mark 3 = URL
+ return $m[1] . '=' . $m[2] .
+ ( preg_match( '#^(\w{1,20}):#', $m[3], $protocol ) && in_array( $protocol[1], wp_allowed_protocols() ) ?
+ $m[3] :
+ path_join( $_links_add_base, $m[3] ) )
+ . $m[2];
+}
+
+/**
+ * Adds a Target attribute to all links in passed content.
+ *
+ * This function by default only applies to <a> tags, however this can be
+ * modified by the 3rd param.
+ *
+ * <b>NOTE:</b> Any current target attributed will be stripped and replaced.
+ *
+ * @since 2.7.0
+ *
+ * @param string $content String to search for links in.
+ * @param string $target The Target to add to the links.
+ * @param array $tags An array of tags to apply to.
+ * @return string The processed content.
+ */
+function links_add_target( $content, $target = '_blank', $tags = array('a') ) {
+ global $_links_add_target;
+ $_links_add_target = $target;
+ $tags = implode('|', (array)$tags);
+ return preg_replace_callback( "!<($tags)(.+?)>!i", '_links_add_target', $content );
+}
+
+/**
+ * Callback to add a target attribute to all links in passed content.
+ *
+ * @since 2.7.0
+ * @access private
+ *
+ * @param string $m The matched link.
+ * @return string The processed link.
+ */
+function _links_add_target( $m ) {
+ global $_links_add_target;
+ $tag = $m[1];
+ $link = preg_replace('|(target=([\'"])(.*?)\2)|i', '', $m[2]);
+ return '<' . $tag . $link . ' target="' . esc_attr( $_links_add_target ) . '">';
+}
+
+/**
+ * Normalize EOL characters and strip duplicate whitespace.
+ *
+ * @since 2.7.0
+ *
+ * @param string $str The string to normalize.
+ * @return string The normalized string.
+ */
+function normalize_whitespace( $str ) {
+ $str = trim( $str );
+ $str = str_replace( "\r", "\n", $str );
+ $str = preg_replace( array( '/\n+/', '/[ \t]+/' ), array( "\n", ' ' ), $str );
+ return $str;
+}
+
+/**
+ * Properly strip all HTML tags including script and style
+ *
+ * @since 2.9.0
+ *
+ * @param string $string String containing HTML tags
+ * @param bool $remove_breaks optional Whether to remove left over line breaks and white space chars
+ * @return string The processed string.
+ */
+function wp_strip_all_tags($string, $remove_breaks = false) {
+ $string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
+ $string = strip_tags($string);
+
+ if ( $remove_breaks )
+ $string = preg_replace('/[\r\n\t ]+/', ' ', $string);
+
+ return trim( $string );
+}
+
+/**
+ * Sanitize a string from user input or from the db
+ *
+ * check for invalid UTF-8,
+ * Convert single < characters to entity,
+ * strip all tags,
+ * remove line breaks, tabs and extra white space,
+ * strip octets.
+ *
+ * @since 2.9.0
+ *
+ * @param string $str
+ * @return string
+ */
+function sanitize_text_field($str) {
+ $filtered = wp_check_invalid_utf8( $str );
+
+ if ( strpos($filtered, '<') !== false ) {
+ $filtered = wp_pre_kses_less_than( $filtered );
+ // This will strip extra whitespace for us.
+ $filtered = wp_strip_all_tags( $filtered, true );
+ } else {
+ $filtered = trim( preg_replace('/[\r\n\t ]+/', ' ', $filtered) );
+ }
+
+ $found = false;
+ while ( preg_match('/%[a-f0-9]{2}/i', $filtered, $match) ) {
+ $filtered = str_replace($match[0], '', $filtered);
+ $found = true;
+ }
+
+ if ( $found ) {
+ // Strip out the whitespace that may now exist after removing the octets.
+ $filtered = trim( preg_replace('/ +/', ' ', $filtered) );
+ }
+
+ return apply_filters('sanitize_text_field', $filtered, $str);
+}
+
+/**
+ * i18n friendly version of basename()
+ *
+ * @since 3.1.0
+ *
+ * @param string $path A path.
+ * @param string $suffix If the filename ends in suffix this will also be cut off.
+ * @return string
+ */
+function wp_basename( $path, $suffix = '' ) {
+ return urldecode( basename( str_replace( array( '%2F', '%5C' ), '/', urlencode( $path ) ), $suffix ) );
+}
+
+/**
+ * Forever eliminate "Wordpress" from the planet (or at least the little bit we can influence).
+ *
+ * Violating our coding standards for a good function name.
+ *
+ * @since 3.0.0
+ */
+function capital_P_dangit( $text ) {
+ // Simple replacement for titles
+ if ( 'the_title' === current_filter() )
+ return str_replace( 'Wordpress', 'WordPress', $text );
+ // Still here? Use the more judicious replacement
+ static $dblq = false;
+ if ( false === $dblq )
+ $dblq = _x( '&#8220;', 'opening curly double quote' );
+ return str_replace(
+ array( ' Wordpress', '&#8216;Wordpress', $dblq . 'Wordpress', '>Wordpress', '(Wordpress' ),
+ array( ' WordPress', '&#8216;WordPress', $dblq . 'WordPress', '>WordPress', '(WordPress' ),
+ $text );
+
+}
+
+/**
+ * Sanitize a mime type
+ *
+ * @since 3.1.3
+ *
+ * @param string $mime_type Mime type
+ * @return string Sanitized mime type
+ */
+function sanitize_mime_type( $mime_type ) {
+ $sani_mime_type = preg_replace( '/[^-+*.a-zA-Z0-9\/]/', '', $mime_type );
+ return apply_filters( 'sanitize_mime_type', $sani_mime_type, $mime_type );
+}
+
+/**
+ * Sanitize space or carriage return separated URLs that are used to send trackbacks.
+ *
+ * @since 3.4.0
+ *
+ * @param string $to_ping Space or carriage return separated URLs
+ * @return string URLs starting with the http or https protocol, separated by a carriage return.
+ */
+function sanitize_trackback_urls( $to_ping ) {
+ $urls_to_ping = preg_split( '/[\r\n\t ]/', trim( $to_ping ), -1, PREG_SPLIT_NO_EMPTY );
+ foreach ( $urls_to_ping as $k => $url ) {
+ if ( !preg_match( '#^https?://.#i', $url ) )
+ unset( $urls_to_ping[$k] );
+ }
+ $urls_to_ping = array_map( 'esc_url_raw', $urls_to_ping );
+ $urls_to_ping = implode( "\n", $urls_to_ping );
+ return apply_filters( 'sanitize_trackback_urls', $urls_to_ping, $to_ping );
+}
+
+/**
+ * Add slashes to a string or array of strings.
+ *
+ * This should be used when preparing data for core API that expects slashed data.
+ * This should not be used to escape data going directly into an SQL query.
+ *
+ * @since 3.6.0
+ *
+ * @param string|array $value String or array of strings to slash.
+ * @return string|array Slashed $value
+ */
+function wp_slash( $value ) {
+ if ( is_array( $value ) ) {
+ foreach ( $value as $k => $v ) {
+ if ( is_array( $v ) ) {
+ $value[$k] = wp_slash( $v );
+ } else {
+ $value[$k] = addslashes( $v );
+ }
+ }
+ } else {
+ $value = addslashes( $value );
+ }
+
+ return $value;
+}
+
+/**
+ * Remove slashes from a string or array of strings.
+ *
+ * This should be used to remove slashes from data passed to core API that
+ * expects data to be unslashed.
+ *
+ * @since 3.6.0
+ *
+ * @param string|array $value String or array of strings to unslash.
+ * @return string|array Unslashed $value
+ */
+function wp_unslash( $value ) {
+ return stripslashes_deep( $value );
+}
+
+/**
+ * Extract and return the first URL from passed content.
+ *
+ * @since 3.6.0
+ *
+ * @param string $content A string which might contain a URL.
+ * @return string The found URL.
+ */
+function get_url_in_content( $content ) {
+ if ( empty( $content ) )
+ return '';
+
+ if ( preg_match( '/<a\s[^>]*?href=([\'"])(.+?)\1/is', $content, $matches ) )
+ return esc_url_raw( $matches[2] );
+
+ return false;
+}
diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
new file mode 100644
index 0000000000..820069518d
--- /dev/null
+++ b/src/wp-includes/functions.php
@@ -0,0 +1,4043 @@
+<?php
+/**
+ * Main WordPress API
+ *
+ * @package WordPress
+ */
+
+require( ABSPATH . WPINC . '/option.php' );
+
+/**
+ * Converts given date string into a different format.
+ *
+ * $format should be either a PHP date format string, e.g. 'U' for a Unix
+ * timestamp, or 'G' for a Unix timestamp assuming that $date is GMT.
+ *
+ * If $translate is true then the given date and format string will
+ * be passed to date_i18n() for translation.
+ *
+ * @since 0.71
+ *
+ * @param string $format Format of the date to return.
+ * @param string $date Date string to convert.
+ * @param bool $translate Whether the return date should be translated. Default is true.
+ * @return string|int Formatted date string, or Unix timestamp.
+ */
+function mysql2date( $format, $date, $translate = true ) {
+ if ( empty( $date ) )
+ return false;
+
+ if ( 'G' == $format )
+ return strtotime( $date . ' +0000' );
+
+ $i = strtotime( $date );
+
+ if ( 'U' == $format )
+ return $i;
+
+ if ( $translate )
+ return date_i18n( $format, $i );
+ else
+ return date( $format, $i );
+}
+
+/**
+ * Retrieve the current time based on specified type.
+ *
+ * The 'mysql' type will return the time in the format for MySQL DATETIME field.
+ * The 'timestamp' type will return the current timestamp.
+ *
+ * If $gmt is set to either '1' or 'true', then both types will use GMT time.
+ * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
+ *
+ * @since 1.0.0
+ *
+ * @param string $type Either 'mysql' or 'timestamp'.
+ * @param int|bool $gmt Optional. Whether to use GMT timezone. Default is false.
+ * @return int|string String if $type is 'gmt', int if $type is 'timestamp'.
+ */
+function current_time( $type, $gmt = 0 ) {
+ switch ( $type ) {
+ case 'mysql':
+ return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
+ break;
+ case 'timestamp':
+ return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
+ break;
+ }
+}
+
+/**
+ * Retrieve the date in localized format, based on timestamp.
+ *
+ * If the locale specifies the locale month and weekday, then the locale will
+ * take over the format for the date. If it isn't, then the date format string
+ * will be used instead.
+ *
+ * @since 0.71
+ *
+ * @param string $dateformatstring Format to display the date.
+ * @param int $unixtimestamp Optional. Unix timestamp.
+ * @param bool $gmt Optional, default is false. Whether to convert to GMT for time.
+ * @return string The date, translated if locale specifies it.
+ */
+function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
+ global $wp_locale;
+ $i = $unixtimestamp;
+
+ if ( false === $i ) {
+ if ( ! $gmt )
+ $i = current_time( 'timestamp' );
+ else
+ $i = time();
+ // we should not let date() interfere with our
+ // specially computed timestamp
+ $gmt = true;
+ }
+
+ // store original value for language with untypical grammars
+ // see http://core.trac.wordpress.org/ticket/9396
+ $req_format = $dateformatstring;
+
+ $datefunc = $gmt? 'gmdate' : 'date';
+
+ if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
+ $datemonth = $wp_locale->get_month( $datefunc( 'm', $i ) );
+ $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
+ $dateweekday = $wp_locale->get_weekday( $datefunc( 'w', $i ) );
+ $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
+ $datemeridiem = $wp_locale->get_meridiem( $datefunc( 'a', $i ) );
+ $datemeridiem_capital = $wp_locale->get_meridiem( $datefunc( 'A', $i ) );
+ $dateformatstring = ' '.$dateformatstring;
+ $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
+ $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
+ $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
+ $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
+ $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
+ $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
+
+ $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
+ }
+ $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
+ $timezone_formats_re = implode( '|', $timezone_formats );
+ if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
+ $timezone_string = get_option( 'timezone_string' );
+ if ( $timezone_string ) {
+ $timezone_object = timezone_open( $timezone_string );
+ $date_object = date_create( null, $timezone_object );
+ foreach( $timezone_formats as $timezone_format ) {
+ if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
+ $formatted = date_format( $date_object, $timezone_format );
+ $dateformatstring = ' '.$dateformatstring;
+ $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
+ $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
+ }
+ }
+ }
+ }
+ $j = @$datefunc( $dateformatstring, $i );
+ // allow plugins to redo this entirely for languages with untypical grammars
+ $j = apply_filters('date_i18n', $j, $req_format, $i, $gmt);
+ return $j;
+}
+
+/**
+ * Convert integer number to format based on the locale.
+ *
+ * @since 2.3.0
+ *
+ * @param int $number The number to convert based on locale.
+ * @param int $decimals Precision of the number of decimal places.
+ * @return string Converted number in string format.
+ */
+function number_format_i18n( $number, $decimals = 0 ) {
+ global $wp_locale;
+ $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
+ return apply_filters( 'number_format_i18n', $formatted );
+}
+
+/**
+ * Convert number of bytes largest unit bytes will fit into.
+ *
+ * It is easier to read 1kB than 1024 bytes and 1MB than 1048576 bytes. Converts
+ * number of bytes to human readable number by taking the number of that unit
+ * that the bytes will go into it. Supports TB value.
+ *
+ * Please note that integers in PHP are limited to 32 bits, unless they are on
+ * 64 bit architecture, then they have 64 bit size. If you need to place the
+ * larger size then what PHP integer type will hold, then use a string. It will
+ * be converted to a double, which should always have 64 bit length.
+ *
+ * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
+ * @link http://en.wikipedia.org/wiki/Byte
+ *
+ * @since 2.3.0
+ *
+ * @param int|string $bytes Number of bytes. Note max integer size for integers.
+ * @param int $decimals Precision of number of decimal places. Deprecated.
+ * @return bool|string False on failure. Number string on success.
+ */
+function size_format( $bytes, $decimals = 0 ) {
+ $quant = array(
+ // ========================= Origin ====
+ 'TB' => 1099511627776, // pow( 1024, 4)
+ 'GB' => 1073741824, // pow( 1024, 3)
+ 'MB' => 1048576, // pow( 1024, 2)
+ 'kB' => 1024, // pow( 1024, 1)
+ 'B ' => 1, // pow( 1024, 0)
+ );
+ foreach ( $quant as $unit => $mag )
+ if ( doubleval($bytes) >= $mag )
+ return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
+
+ return false;
+}
+
+/**
+ * Get the week start and end from the datetime or date string from mysql.
+ *
+ * @since 0.71
+ *
+ * @param string $mysqlstring Date or datetime field type from mysql.
+ * @param int $start_of_week Optional. Start of the week as an integer.
+ * @return array Keys are 'start' and 'end'.
+ */
+function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
+ $my = substr( $mysqlstring, 0, 4 ); // Mysql string Year
+ $mm = substr( $mysqlstring, 8, 2 ); // Mysql string Month
+ $md = substr( $mysqlstring, 5, 2 ); // Mysql string day
+ $day = mktime( 0, 0, 0, $md, $mm, $my ); // The timestamp for mysqlstring day.
+ $weekday = date( 'w', $day ); // The day of the week from the timestamp
+ if ( !is_numeric($start_of_week) )
+ $start_of_week = get_option( 'start_of_week' );
+
+ if ( $weekday < $start_of_week )
+ $weekday += 7;
+
+ $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week ); // The most recent week start day on or before $day
+ $end = $start + 7 * DAY_IN_SECONDS - 1; // $start + 7 days - 1 second
+ return compact( 'start', 'end' );
+}
+
+/**
+ * Unserialize value only if it was serialized.
+ *
+ * @since 2.0.0
+ *
+ * @param string $original Maybe unserialized original, if is needed.
+ * @return mixed Unserialized data can be any type.
+ */
+function maybe_unserialize( $original ) {
+ if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
+ return @unserialize( $original );
+ return $original;
+}
+
+/**
+ * Check value to find if it was serialized.
+ *
+ * If $data is not an string, then returned value will always be false.
+ * Serialized data is always a string.
+ *
+ * @since 2.0.5
+ *
+ * @param mixed $data Value to check to see if was serialized.
+ * @return bool False if not serialized and true if it was.
+ */
+function is_serialized( $data ) {
+ // if it isn't a string, it isn't serialized
+ if ( ! is_string( $data ) )
+ return false;
+ $data = trim( $data );
+ if ( 'N;' == $data )
+ return true;
+ $length = strlen( $data );
+ if ( $length < 4 )
+ return false;
+ if ( ':' !== $data[1] )
+ return false;
+ $lastc = $data[$length-1];
+ if ( ';' !== $lastc && '}' !== $lastc )
+ return false;
+ $token = $data[0];
+ switch ( $token ) {
+ case 's' :
+ if ( '"' !== $data[$length-2] )
+ return false;
+ case 'a' :
+ case 'O' :
+ return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
+ case 'b' :
+ case 'i' :
+ case 'd' :
+ return (bool) preg_match( "/^{$token}:[0-9.E-]+;\$/", $data );
+ }
+ return false;
+}
+
+/**
+ * Check whether serialized data is of string type.
+ *
+ * @since 2.0.5
+ *
+ * @param mixed $data Serialized data
+ * @return bool False if not a serialized string, true if it is.
+ */
+function is_serialized_string( $data ) {
+ // if it isn't a string, it isn't a serialized string
+ if ( !is_string( $data ) )
+ return false;
+ $data = trim( $data );
+ $length = strlen( $data );
+ if ( $length < 4 )
+ return false;
+ elseif ( ':' !== $data[1] )
+ return false;
+ elseif ( ';' !== $data[$length-1] )
+ return false;
+ elseif ( $data[0] !== 's' )
+ return false;
+ elseif ( '"' !== $data[$length-2] )
+ return false;
+ else
+ return true;
+}
+
+/**
+ * Serialize data, if needed.
+ *
+ * @since 2.0.5
+ *
+ * @param mixed $data Data that might be serialized.
+ * @return mixed A scalar data
+ */
+function maybe_serialize( $data ) {
+ if ( is_array( $data ) || is_object( $data ) )
+ return serialize( $data );
+
+ // Double serialization is required for backward compatibility.
+ // See http://core.trac.wordpress.org/ticket/12930
+ if ( is_serialized( $data ) )
+ return serialize( $data );
+
+ return $data;
+}
+
+/**
+ * Retrieve post title from XMLRPC XML.
+ *
+ * If the title element is not part of the XML, then the default post title from
+ * the $post_default_title will be used instead.
+ *
+ * @package WordPress
+ * @subpackage XMLRPC
+ * @since 0.71
+ *
+ * @global string $post_default_title Default XMLRPC post title.
+ *
+ * @param string $content XMLRPC XML Request content
+ * @return string Post title
+ */
+function xmlrpc_getposttitle( $content ) {
+ global $post_default_title;
+ if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
+ $post_title = $matchtitle[1];
+ } else {
+ $post_title = $post_default_title;
+ }
+ return $post_title;
+}
+
+/**
+ * Retrieve the post category or categories from XMLRPC XML.
+ *
+ * If the category element is not found, then the default post category will be
+ * used. The return type then would be what $post_default_category. If the
+ * category is found, then it will always be an array.
+ *
+ * @package WordPress
+ * @subpackage XMLRPC
+ * @since 0.71
+ *
+ * @global string $post_default_category Default XMLRPC post category.
+ *
+ * @param string $content XMLRPC XML Request content
+ * @return string|array List of categories or category name.
+ */
+function xmlrpc_getpostcategory( $content ) {
+ global $post_default_category;
+ if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
+ $post_category = trim( $matchcat[1], ',' );
+ $post_category = explode( ',', $post_category );
+ } else {
+ $post_category = $post_default_category;
+ }
+ return $post_category;
+}
+
+/**
+ * XMLRPC XML content without title and category elements.
+ *
+ * @package WordPress
+ * @subpackage XMLRPC
+ * @since 0.71
+ *
+ * @param string $content XMLRPC XML Request content
+ * @return string XMLRPC XML Request content without title and category elements.
+ */
+function xmlrpc_removepostdata( $content ) {
+ $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
+ $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
+ $content = trim( $content );
+ return $content;
+}
+
+/**
+ * Check content for video and audio links to add as enclosures.
+ *
+ * Will not add enclosures that have already been added and will
+ * remove enclosures that are no longer in the post. This is called as
+ * pingbacks and trackbacks.
+ *
+ * @package WordPress
+ * @since 1.5.0
+ *
+ * @uses $wpdb
+ *
+ * @param string $content Post Content
+ * @param int $post_ID Post ID
+ */
+function do_enclose( $content, $post_ID ) {
+ global $wpdb;
+
+ //TODO: Tidy this ghetto code up and make the debug code optional
+ include_once( ABSPATH . WPINC . '/class-IXR.php' );
+
+ $post_links = array();
+
+ $pung = get_enclosed( $post_ID );
+
+ $ltrs = '\w';
+ $gunk = '/#~:.?+=&%@!\-';
+ $punc = '.:?\-';
+ $any = $ltrs . $gunk . $punc;
+
+ preg_match_all( "{\b https? : [$any] +? (?= [$punc] * [^$any] | $)}x", $content, $post_links_temp );
+
+ foreach ( $pung as $link_test ) {
+ if ( !in_array( $link_test, $post_links_temp[0] ) ) { // link no longer in post
+ $mids = $wpdb->get_col( $wpdb->prepare("SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE (%s)", $post_ID, like_escape( $link_test ) . '%') );
+ foreach ( $mids as $mid )
+ delete_metadata_by_mid( 'post', $mid );
+ }
+ }
+
+ foreach ( (array) $post_links_temp[0] as $link_test ) {
+ if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
+ $test = @parse_url( $link_test );
+ if ( false === $test )
+ continue;
+ if ( isset( $test['query'] ) )
+ $post_links[] = $link_test;
+ elseif ( isset($test['path']) && ( $test['path'] != '/' ) && ($test['path'] != '' ) )
+ $post_links[] = $link_test;
+ }
+ }
+
+ foreach ( (array) $post_links as $url ) {
+ if ( $url != '' && !$wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE (%s)", $post_ID, like_escape( $url ) . '%' ) ) ) {
+
+ if ( $headers = wp_get_http_headers( $url) ) {
+ $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
+ $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
+ $allowed_types = array( 'video', 'audio' );
+
+ // Check to see if we can figure out the mime type from
+ // the extension
+ $url_parts = @parse_url( $url );
+ if ( false !== $url_parts ) {
+ $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
+ if ( !empty( $extension ) ) {
+ foreach ( wp_get_mime_types() as $exts => $mime ) {
+ if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
+ $type = $mime;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
+ add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Perform a HTTP HEAD or GET request.
+ *
+ * If $file_path is a writable filename, this will do a GET request and write
+ * the file to that path.
+ *
+ * @since 2.5.0
+ *
+ * @param string $url URL to fetch.
+ * @param string|bool $file_path Optional. File path to write request to.
+ * @param int $red (private) The number of Redirects followed, Upon 5 being hit, returns false.
+ * @return bool|string False on failure and string of headers if HEAD request.
+ */
+function wp_get_http( $url, $file_path = false, $red = 1 ) {
+ @set_time_limit( 60 );
+
+ if ( $red > 5 )
+ return false;
+
+ $options = array();
+ $options['redirection'] = 5;
+
+ if ( false == $file_path )
+ $options['method'] = 'HEAD';
+ else
+ $options['method'] = 'GET';
+
+ $response = wp_safe_remote_request( $url, $options );
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ $headers = wp_remote_retrieve_headers( $response );
+ $headers['response'] = wp_remote_retrieve_response_code( $response );
+
+ // WP_HTTP no longer follows redirects for HEAD requests.
+ if ( 'HEAD' == $options['method'] && in_array($headers['response'], array(301, 302)) && isset( $headers['location'] ) ) {
+ return wp_get_http( $headers['location'], $file_path, ++$red );
+ }
+
+ if ( false == $file_path )
+ return $headers;
+
+ // GET request - write it to the supplied filename
+ $out_fp = fopen($file_path, 'w');
+ if ( !$out_fp )
+ return $headers;
+
+ fwrite( $out_fp, wp_remote_retrieve_body( $response ) );
+ fclose($out_fp);
+ clearstatcache();
+
+ return $headers;
+}
+
+/**
+ * Retrieve HTTP Headers from URL.
+ *
+ * @since 1.5.1
+ *
+ * @param string $url
+ * @param bool $deprecated Not Used.
+ * @return bool|string False on failure, headers on success.
+ */
+function wp_get_http_headers( $url, $deprecated = false ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.7' );
+
+ $response = wp_safe_remote_head( $url );
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ return wp_remote_retrieve_headers( $response );
+}
+
+/**
+ * Whether today is a new day.
+ *
+ * @since 0.71
+ * @uses $day Today
+ * @uses $previousday Previous day
+ *
+ * @return int 1 when new day, 0 if not a new day.
+ */
+function is_new_day() {
+ global $currentday, $previousday;
+ if ( $currentday != $previousday )
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * Build URL query based on an associative and, or indexed array.
+ *
+ * This is a convenient function for easily building url queries. It sets the
+ * separator to '&' and uses _http_build_query() function.
+ *
+ * @see _http_build_query() Used to build the query
+ * @link http://us2.php.net/manual/en/function.http-build-query.php more on what
+ * http_build_query() does.
+ *
+ * @since 2.3.0
+ *
+ * @param array $data URL-encode key/value pairs.
+ * @return string URL encoded string
+ */
+function build_query( $data ) {
+ return _http_build_query( $data, null, '&', '', false );
+}
+
+// from php.net (modified by Mark Jaquith to behave like the native PHP5 function)
+function _http_build_query($data, $prefix=null, $sep=null, $key='', $urlencode=true) {
+ $ret = array();
+
+ foreach ( (array) $data as $k => $v ) {
+ if ( $urlencode)
+ $k = urlencode($k);
+ if ( is_int($k) && $prefix != null )
+ $k = $prefix.$k;
+ if ( !empty($key) )
+ $k = $key . '%5B' . $k . '%5D';
+ if ( $v === null )
+ continue;
+ elseif ( $v === FALSE )
+ $v = '0';
+
+ if ( is_array($v) || is_object($v) )
+ array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
+ elseif ( $urlencode )
+ array_push($ret, $k.'='.urlencode($v));
+ else
+ array_push($ret, $k.'='.$v);
+ }
+
+ if ( null === $sep )
+ $sep = ini_get('arg_separator.output');
+
+ return implode($sep, $ret);
+}
+
+/**
+ * Retrieve a modified URL query string.
+ *
+ * You can rebuild the URL and append a new query variable to the URL query by
+ * using this function. You can also retrieve the full URL with query data.
+ *
+ * Adding a single key & value or an associative array. Setting a key value to
+ * an empty string removes the key. Omitting oldquery_or_uri uses the $_SERVER
+ * value. Additional values provided are expected to be encoded appropriately
+ * with urlencode() or rawurlencode().
+ *
+ * @since 1.5.0
+ *
+ * @param mixed $param1 Either newkey or an associative_array
+ * @param mixed $param2 Either newvalue or oldquery or uri
+ * @param mixed $param3 Optional. Old query or uri
+ * @return string New URL query string.
+ */
+function add_query_arg() {
+ $ret = '';
+ $args = func_get_args();
+ if ( is_array( $args[0] ) ) {
+ if ( count( $args ) < 2 || false === $args[1] )
+ $uri = $_SERVER['REQUEST_URI'];
+ else
+ $uri = $args[1];
+ } else {
+ if ( count( $args ) < 3 || false === $args[2] )
+ $uri = $_SERVER['REQUEST_URI'];
+ else
+ $uri = $args[2];
+ }
+
+ if ( $frag = strstr( $uri, '#' ) )
+ $uri = substr( $uri, 0, -strlen( $frag ) );
+ else
+ $frag = '';
+
+ if ( 0 === stripos( $uri, 'http://' ) ) {
+ $protocol = 'http://';
+ $uri = substr( $uri, 7 );
+ } elseif ( 0 === stripos( $uri, 'https://' ) ) {
+ $protocol = 'https://';
+ $uri = substr( $uri, 8 );
+ } else {
+ $protocol = '';
+ }
+
+ if ( strpos( $uri, '?' ) !== false ) {
+ $parts = explode( '?', $uri, 2 );
+ if ( 1 == count( $parts ) ) {
+ $base = '?';
+ $query = $parts[0];
+ } else {
+ $base = $parts[0] . '?';
+ $query = $parts[1];
+ }
+ } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
+ $base = $uri . '?';
+ $query = '';
+ } else {
+ $base = '';
+ $query = $uri;
+ }
+
+ wp_parse_str( $query, $qs );
+ $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
+ if ( is_array( $args[0] ) ) {
+ $kayvees = $args[0];
+ $qs = array_merge( $qs, $kayvees );
+ } else {
+ $qs[ $args[0] ] = $args[1];
+ }
+
+ foreach ( $qs as $k => $v ) {
+ if ( $v === false )
+ unset( $qs[$k] );
+ }
+
+ $ret = build_query( $qs );
+ $ret = trim( $ret, '?' );
+ $ret = preg_replace( '#=(&|$)#', '$1', $ret );
+ $ret = $protocol . $base . $ret . $frag;
+ $ret = rtrim( $ret, '?' );
+ return $ret;
+}
+
+/**
+ * Removes an item or list from the query string.
+ *
+ * @since 1.5.0
+ *
+ * @param string|array $key Query key or keys to remove.
+ * @param bool $query When false uses the $_SERVER value.
+ * @return string New URL query string.
+ */
+function remove_query_arg( $key, $query=false ) {
+ if ( is_array( $key ) ) { // removing multiple keys
+ foreach ( $key as $k )
+ $query = add_query_arg( $k, false, $query );
+ return $query;
+ }
+ return add_query_arg( $key, false, $query );
+}
+
+/**
+ * Walks the array while sanitizing the contents.
+ *
+ * @since 0.71
+ *
+ * @param array $array Array to walk while sanitizing contents.
+ * @return array Sanitized $array.
+ */
+function add_magic_quotes( $array ) {
+ foreach ( (array) $array as $k => $v ) {
+ if ( is_array( $v ) ) {
+ $array[$k] = add_magic_quotes( $v );
+ } else {
+ $array[$k] = addslashes( $v );
+ }
+ }
+ return $array;
+}
+
+/**
+ * HTTP request for URI to retrieve content.
+ *
+ * @since 1.5.1
+ * @uses wp_remote_get()
+ *
+ * @param string $uri URI/URL of web page to retrieve.
+ * @return bool|string HTTP content. False on failure.
+ */
+function wp_remote_fopen( $uri ) {
+ $parsed_url = @parse_url( $uri );
+
+ if ( !$parsed_url || !is_array( $parsed_url ) )
+ return false;
+
+ $options = array();
+ $options['timeout'] = 10;
+
+ $response = wp_safe_remote_get( $uri, $options );
+
+ if ( is_wp_error( $response ) )
+ return false;
+
+ return wp_remote_retrieve_body( $response );
+}
+
+/**
+ * Set up the WordPress query.
+ *
+ * @since 2.0.0
+ *
+ * @param string $query_vars Default WP_Query arguments.
+ */
+function wp( $query_vars = '' ) {
+ global $wp, $wp_query, $wp_the_query;
+ $wp->main( $query_vars );
+
+ if ( !isset($wp_the_query) )
+ $wp_the_query = $wp_query;
+}
+
+/**
+ * Retrieve the description for the HTTP status.
+ *
+ * @since 2.3.0
+ *
+ * @param int $code HTTP status code.
+ * @return string Empty string if not found, or description if found.
+ */
+function get_status_header_desc( $code ) {
+ global $wp_header_to_desc;
+
+ $code = absint( $code );
+
+ if ( !isset( $wp_header_to_desc ) ) {
+ $wp_header_to_desc = array(
+ 100 => 'Continue',
+ 101 => 'Switching Protocols',
+ 102 => 'Processing',
+
+ 200 => 'OK',
+ 201 => 'Created',
+ 202 => 'Accepted',
+ 203 => 'Non-Authoritative Information',
+ 204 => 'No Content',
+ 205 => 'Reset Content',
+ 206 => 'Partial Content',
+ 207 => 'Multi-Status',
+ 226 => 'IM Used',
+
+ 300 => 'Multiple Choices',
+ 301 => 'Moved Permanently',
+ 302 => 'Found',
+ 303 => 'See Other',
+ 304 => 'Not Modified',
+ 305 => 'Use Proxy',
+ 306 => 'Reserved',
+ 307 => 'Temporary Redirect',
+
+ 400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
+ 422 => 'Unprocessable Entity',
+ 423 => 'Locked',
+ 424 => 'Failed Dependency',
+ 426 => 'Upgrade Required',
+
+ 500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported',
+ 506 => 'Variant Also Negotiates',
+ 507 => 'Insufficient Storage',
+ 510 => 'Not Extended'
+ );
+ }
+
+ if ( isset( $wp_header_to_desc[$code] ) )
+ return $wp_header_to_desc[$code];
+ else
+ return '';
+}
+
+/**
+ * Set HTTP status header.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'status_header' on status header string, HTTP
+ * HTTP code, HTTP code description, and protocol string as separate
+ * parameters.
+ *
+ * @param int $header HTTP status code
+ * @return unknown
+ */
+function status_header( $header ) {
+ $text = get_status_header_desc( $header );
+
+ if ( empty( $text ) )
+ return false;
+
+ $protocol = $_SERVER["SERVER_PROTOCOL"];
+ if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
+ $protocol = 'HTTP/1.0';
+ $status_header = "$protocol $header $text";
+ if ( function_exists( 'apply_filters' ) )
+ $status_header = apply_filters( 'status_header', $status_header, $header, $text, $protocol );
+
+ return @header( $status_header, true, $header );
+}
+
+/**
+ * Gets the header information to prevent caching.
+ *
+ * The several different headers cover the different ways cache prevention is handled
+ * by different browsers
+ *
+ * @since 2.8.0
+ *
+ * @uses apply_filters()
+ * @return array The associative array of header names and field values.
+ */
+function wp_get_nocache_headers() {
+ $headers = array(
+ 'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
+ 'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
+ 'Pragma' => 'no-cache',
+ );
+
+ if ( function_exists('apply_filters') ) {
+ $headers = (array) apply_filters('nocache_headers', $headers);
+ }
+ $headers['Last-Modified'] = false;
+ return $headers;
+}
+
+/**
+ * Sets the headers to prevent caching for the different browsers.
+ *
+ * Different browsers support different nocache headers, so several headers must
+ * be sent so that all of them get the point that no caching should occur.
+ *
+ * @since 2.0.0
+ * @uses wp_get_nocache_headers()
+ */
+function nocache_headers() {
+ $headers = wp_get_nocache_headers();
+
+ unset( $headers['Last-Modified'] );
+
+ // In PHP 5.3+, make sure we are not sending a Last-Modified header.
+ if ( function_exists( 'header_remove' ) ) {
+ @header_remove( 'Last-Modified' );
+ } else {
+ // In PHP 5.2, send an empty Last-Modified header, but only as a
+ // last resort to override a header already sent. #WP23021
+ foreach ( headers_list() as $header ) {
+ if ( 0 === stripos( $header, 'Last-Modified' ) ) {
+ $headers['Last-Modified'] = '';
+ break;
+ }
+ }
+ }
+
+ foreach( $headers as $name => $field_value )
+ @header("{$name}: {$field_value}");
+}
+
+/**
+ * Set the headers for caching for 10 days with JavaScript content type.
+ *
+ * @since 2.1.0
+ */
+function cache_javascript_headers() {
+ $expiresOffset = 10 * DAY_IN_SECONDS;
+ header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
+ header( "Vary: Accept-Encoding" ); // Handle proxies
+ header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
+}
+
+/**
+ * Retrieve the number of database queries during the WordPress execution.
+ *
+ * @since 2.0.0
+ *
+ * @return int Number of database queries
+ */
+function get_num_queries() {
+ global $wpdb;
+ return $wpdb->num_queries;
+}
+
+/**
+ * Whether input is yes or no. Must be 'y' to be true.
+ *
+ * @since 1.0.0
+ *
+ * @param string $yn Character string containing either 'y' or 'n'
+ * @return bool True if yes, false on anything else
+ */
+function bool_from_yn( $yn ) {
+ return ( strtolower( $yn ) == 'y' );
+}
+
+/**
+ * Loads the feed template from the use of an action hook.
+ *
+ * If the feed action does not have a hook, then the function will die with a
+ * message telling the visitor that the feed is not valid.
+ *
+ * It is better to only have one hook for each feed.
+ *
+ * @since 2.1.0
+ * @uses $wp_query Used to tell if the use a comment feed.
+ * @uses do_action() Calls 'do_feed_$feed' hook, if a hook exists for the feed.
+ */
+function do_feed() {
+ global $wp_query;
+
+ $feed = get_query_var( 'feed' );
+
+ // Remove the pad, if present.
+ $feed = preg_replace( '/^_+/', '', $feed );
+
+ if ( $feed == '' || $feed == 'feed' )
+ $feed = get_default_feed();
+
+ $hook = 'do_feed_' . $feed;
+ if ( !has_action($hook) ) {
+ $message = sprintf( __( 'ERROR: %s is not a valid feed template.' ), esc_html($feed));
+ wp_die( $message, '', array( 'response' => 404 ) );
+ }
+
+ do_action( $hook, $wp_query->is_comment_feed );
+}
+
+/**
+ * Load the RDF RSS 0.91 Feed template.
+ *
+ * @since 2.1.0
+ */
+function do_feed_rdf() {
+ load_template( ABSPATH . WPINC . '/feed-rdf.php' );
+}
+
+/**
+ * Load the RSS 1.0 Feed Template.
+ *
+ * @since 2.1.0
+ */
+function do_feed_rss() {
+ load_template( ABSPATH . WPINC . '/feed-rss.php' );
+}
+
+/**
+ * Load either the RSS2 comment feed or the RSS2 posts feed.
+ *
+ * @since 2.1.0
+ *
+ * @param bool $for_comments True for the comment feed, false for normal feed.
+ */
+function do_feed_rss2( $for_comments ) {
+ if ( $for_comments )
+ load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
+ else
+ load_template( ABSPATH . WPINC . '/feed-rss2.php' );
+}
+
+/**
+ * Load either Atom comment feed or Atom posts feed.
+ *
+ * @since 2.1.0
+ *
+ * @param bool $for_comments True for the comment feed, false for normal feed.
+ */
+function do_feed_atom( $for_comments ) {
+ if ($for_comments)
+ load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
+ else
+ load_template( ABSPATH . WPINC . '/feed-atom.php' );
+}
+
+/**
+ * Display the robots.txt file content.
+ *
+ * The echo content should be with usage of the permalinks or for creating the
+ * robots.txt file.
+ *
+ * @since 2.1.0
+ * @uses do_action() Calls 'do_robotstxt' hook for displaying robots.txt rules.
+ */
+function do_robots() {
+ header( 'Content-Type: text/plain; charset=utf-8' );
+
+ do_action( 'do_robotstxt' );
+
+ $output = "User-agent: *\n";
+ $public = get_option( 'blog_public' );
+ if ( '0' == $public ) {
+ $output .= "Disallow: /\n";
+ } else {
+ $site_url = parse_url( site_url() );
+ $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
+ $output .= "Disallow: $path/wp-admin/\n";
+ $output .= "Disallow: $path/wp-includes/\n";
+ }
+
+ echo apply_filters('robots_txt', $output, $public);
+}
+
+/**
+ * Test whether blog is already installed.
+ *
+ * The cache will be checked first. If you have a cache plugin, which saves the
+ * cache values, then this will work. If you use the default WordPress cache,
+ * and the database goes away, then you might have problems.
+ *
+ * Checks for the option siteurl for whether WordPress is installed.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @return bool Whether blog is already installed.
+ */
+function is_blog_installed() {
+ global $wpdb;
+
+ // Check cache first. If options table goes away and we have true cached, oh well.
+ if ( wp_cache_get( 'is_blog_installed' ) )
+ return true;
+
+ $suppress = $wpdb->suppress_errors();
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ $alloptions = wp_load_alloptions();
+ }
+ // If siteurl is not set to autoload, check it specifically
+ if ( !isset( $alloptions['siteurl'] ) )
+ $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
+ else
+ $installed = $alloptions['siteurl'];
+ $wpdb->suppress_errors( $suppress );
+
+ $installed = !empty( $installed );
+ wp_cache_set( 'is_blog_installed', $installed );
+
+ if ( $installed )
+ return true;
+
+ // If visiting repair.php, return true and let it take over.
+ if ( defined( 'WP_REPAIRING' ) )
+ return true;
+
+ $suppress = $wpdb->suppress_errors();
+
+ // Loop over the WP tables. If none exist, then scratch install is allowed.
+ // If one or more exist, suggest table repair since we got here because the options
+ // table could not be accessed.
+ $wp_tables = $wpdb->tables();
+ foreach ( $wp_tables as $table ) {
+ // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install.
+ if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
+ continue;
+ if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
+ continue;
+
+ if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
+ continue;
+
+ // One or more tables exist. We are insane.
+
+ wp_load_translations_early();
+
+ // Die with a DB error.
+ $wpdb->error = sprintf( __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ), 'maint/repair.php?referrer=is_blog_installed' );
+ dead_db();
+ }
+
+ $wpdb->suppress_errors( $suppress );
+
+ wp_cache_set( 'is_blog_installed', false );
+
+ return false;
+}
+
+/**
+ * Retrieve URL with nonce added to URL query.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @param string $actionurl URL to add nonce action.
+ * @param string $action Optional. Nonce action name.
+ * @param string $name Optional. Nonce name.
+ * @return string URL with nonce action added.
+ */
+function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
+ $actionurl = str_replace( '&amp;', '&', $actionurl );
+ return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
+}
+
+/**
+ * Retrieve or display nonce hidden field for forms.
+ *
+ * The nonce field is used to validate that the contents of the form came from
+ * the location on the current site and not somewhere else. The nonce does not
+ * offer absolute protection, but should protect against most cases. It is very
+ * important to use nonce field in forms.
+ *
+ * The $action and $name are optional, but if you want to have better security,
+ * it is strongly suggested to set those two parameters. It is easier to just
+ * call the function without any parameters, because validation of the nonce
+ * doesn't require any parameters, but since crackers know what the default is
+ * it won't be difficult for them to find a way around your nonce and cause
+ * damage.
+ *
+ * The input name will be whatever $name value you gave. The input value will be
+ * the nonce creation value.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @param string $action Optional. Action name.
+ * @param string $name Optional. Nonce name.
+ * @param bool $referer Optional, default true. Whether to set the referer field for validation.
+ * @param bool $echo Optional, default true. Whether to display or return hidden form field.
+ * @return string Nonce field.
+ */
+function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
+ $name = esc_attr( $name );
+ $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
+
+ if ( $referer )
+ $nonce_field .= wp_referer_field( false );
+
+ if ( $echo )
+ echo $nonce_field;
+
+ return $nonce_field;
+}
+
+/**
+ * Retrieve or display referer hidden field for forms.
+ *
+ * The referer link is the current Request URI from the server super global. The
+ * input name is '_wp_http_referer', in case you wanted to check manually.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @param bool $echo Whether to echo or return the referer field.
+ * @return string Referer field.
+ */
+function wp_referer_field( $echo = true ) {
+ $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
+
+ if ( $echo )
+ echo $referer_field;
+ return $referer_field;
+}
+
+/**
+ * Retrieve or display original referer hidden field for forms.
+ *
+ * The input name is '_wp_original_http_referer' and will be either the same
+ * value of {@link wp_referer_field()}, if that was posted already or it will
+ * be the current page, if it doesn't exist.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @param bool $echo Whether to echo the original http referer
+ * @param string $jump_back_to Optional, default is 'current'. Can be 'previous' or page you want to jump back to.
+ * @return string Original referer field.
+ */
+function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
+ if ( ! $ref = wp_get_original_referer() ) {
+ $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
+ }
+ $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
+ if ( $echo )
+ echo $orig_referer_field;
+ return $orig_referer_field;
+}
+
+/**
+ * Retrieve referer from '_wp_http_referer' or HTTP referer. If it's the same
+ * as the current request URL, will return false.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @return string|bool False on failure. Referer URL on success.
+ */
+function wp_get_referer() {
+ $ref = false;
+ if ( ! empty( $_REQUEST['_wp_http_referer'] ) )
+ $ref = wp_unslash( $_REQUEST['_wp_http_referer'] );
+ else if ( ! empty( $_SERVER['HTTP_REFERER'] ) )
+ $ref = wp_unslash( $_SERVER['HTTP_REFERER'] );
+
+ if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) )
+ return wp_unslash( $ref );
+ return false;
+}
+
+/**
+ * Retrieve original referer that was posted, if it exists.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @return string|bool False if no original referer or original referer if set.
+ */
+function wp_get_original_referer() {
+ if ( !empty( $_REQUEST['_wp_original_http_referer'] ) )
+ return wp_unslash( $_REQUEST['_wp_original_http_referer'] );
+ return false;
+}
+
+/**
+ * Recursive directory creation based on full path.
+ *
+ * Will attempt to set permissions on folders.
+ *
+ * @since 2.0.1
+ *
+ * @param string $target Full path to attempt to create.
+ * @return bool Whether the path was created. True if path already exists.
+ */
+function wp_mkdir_p( $target ) {
+ $wrapper = null;
+
+ // strip the protocol
+ if( wp_is_stream( $target ) ) {
+ list( $wrapper, $target ) = explode( '://', $target, 2 );
+ }
+
+ // from php.net/mkdir user contributed notes
+ $target = str_replace( '//', '/', $target );
+
+ // put the wrapper back on the target
+ if( $wrapper !== null ) {
+ $target = $wrapper . '://' . $target;
+ }
+
+ // safe mode fails with a trailing slash under certain PHP versions.
+ $target = rtrim($target, '/'); // Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
+ if ( empty($target) )
+ $target = '/';
+
+ if ( file_exists( $target ) )
+ return @is_dir( $target );
+
+ // Attempting to create the directory may clutter up our display.
+ if ( @mkdir( $target ) ) {
+ $stat = @stat( dirname( $target ) );
+ $dir_perms = $stat['mode'] & 0007777; // Get the permission bits.
+ @chmod( $target, $dir_perms );
+ return true;
+ } elseif ( is_dir( dirname( $target ) ) ) {
+ return false;
+ }
+
+ // If the above failed, attempt to create the parent node, then try again.
+ if ( ( $target != '/' ) && ( wp_mkdir_p( dirname( $target ) ) ) )
+ return wp_mkdir_p( $target );
+
+ return false;
+}
+
+/**
+ * Test if a give filesystem path is absolute ('/foo/bar', 'c:\windows').
+ *
+ * @since 2.5.0
+ *
+ * @param string $path File path
+ * @return bool True if path is absolute, false is not absolute.
+ */
+function path_is_absolute( $path ) {
+ // this is definitive if true but fails if $path does not exist or contains a symbolic link
+ if ( realpath($path) == $path )
+ return true;
+
+ if ( strlen($path) == 0 || $path[0] == '.' )
+ return false;
+
+ // windows allows absolute paths like this
+ if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
+ return true;
+
+ // a path starting with / or \ is absolute; anything else is relative
+ return ( $path[0] == '/' || $path[0] == '\\' );
+}
+
+/**
+ * Join two filesystem paths together (e.g. 'give me $path relative to $base').
+ *
+ * If the $path is absolute, then it the full path is returned.
+ *
+ * @since 2.5.0
+ *
+ * @param string $base
+ * @param string $path
+ * @return string The path with the base or absolute path.
+ */
+function path_join( $base, $path ) {
+ if ( path_is_absolute($path) )
+ return $path;
+
+ return rtrim($base, '/') . '/' . ltrim($path, '/');
+}
+
+/**
+ * Determines a writable directory for temporary files.
+ * Function's preference is the return value of <code>sys_get_temp_dir()</code>,
+ * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
+ * before finally defaulting to /tmp/
+ *
+ * In the event that this function does not find a writable location,
+ * It may be overridden by the <code>WP_TEMP_DIR</code> constant in
+ * your <code>wp-config.php</code> file.
+ *
+ * @since 2.5.0
+ *
+ * @return string Writable temporary directory
+ */
+function get_temp_dir() {
+ static $temp;
+ if ( defined('WP_TEMP_DIR') )
+ return trailingslashit(WP_TEMP_DIR);
+
+ if ( $temp )
+ return trailingslashit( rtrim( $temp, '\\' ) );
+
+ if ( function_exists('sys_get_temp_dir') ) {
+ $temp = sys_get_temp_dir();
+ if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
+ return trailingslashit( rtrim( $temp, '\\' ) );
+ }
+
+ $temp = ini_get('upload_tmp_dir');
+ if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
+ return trailingslashit( rtrim( $temp, '\\' ) );
+
+ $temp = WP_CONTENT_DIR . '/';
+ if ( is_dir( $temp ) && wp_is_writable( $temp ) )
+ return $temp;
+
+ $temp = '/tmp/';
+ return $temp;
+}
+
+/**
+ * Determine if a directory is writable.
+ *
+ * This function is used to work around certain ACL issues
+ * in PHP primarily affecting Windows Servers.
+ *
+ * @see win_is_writable()
+ *
+ * @since 3.6.0
+ *
+ * @param string $path
+ * @return bool
+ */
+function wp_is_writable( $path ) {
+ if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
+ return win_is_writable( $path );
+ else
+ return @is_writable( $path );
+}
+
+/**
+ * Workaround for Windows bug in is_writable() function
+ *
+ * PHP has issues with Windows ACL's for determine if a
+ * directory is writable or not, this works around them by
+ * checking the ability to open files rather than relying
+ * upon PHP to interprate the OS ACL.
+ *
+ * @link http://bugs.php.net/bug.php?id=27609
+ * @link http://bugs.php.net/bug.php?id=30931
+ *
+ * @since 2.8.0
+ *
+ * @param string $path
+ * @return bool
+ */
+function win_is_writable( $path ) {
+
+ if ( $path[strlen( $path ) - 1] == '/' ) // if it looks like a directory, check a random file within the directory
+ return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
+ else if ( is_dir( $path ) ) // If it's a directory (and not a file) check a random file within the directory
+ return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
+
+ // check tmp file for read/write capabilities
+ $should_delete_tmp_file = !file_exists( $path );
+ $f = @fopen( $path, 'a' );
+ if ( $f === false )
+ return false;
+ fclose( $f );
+ if ( $should_delete_tmp_file )
+ unlink( $path );
+ return true;
+}
+
+/**
+ * Get an array containing the current upload directory's path and url.
+ *
+ * Checks the 'upload_path' option, which should be from the web root folder,
+ * and if it isn't empty it will be used. If it is empty, then the path will be
+ * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
+ * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
+ *
+ * The upload URL path is set either by the 'upload_url_path' option or by using
+ * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
+ *
+ * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
+ * the administration settings panel), then the time will be used. The format
+ * will be year first and then month.
+ *
+ * If the path couldn't be created, then an error will be returned with the key
+ * 'error' containing the error message. The error suggests that the parent
+ * directory is not writable by the server.
+ *
+ * On success, the returned array will have many indices:
+ * 'path' - base directory and sub directory or full path to upload directory.
+ * 'url' - base url and sub directory or absolute URL to upload directory.
+ * 'subdir' - sub directory if uploads use year/month folders option is on.
+ * 'basedir' - path without subdir.
+ * 'baseurl' - URL path without subdir.
+ * 'error' - set to false.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'upload_dir' on returned array.
+ *
+ * @param string $time Optional. Time formatted in 'yyyy/mm'.
+ * @return array See above for description.
+ */
+function wp_upload_dir( $time = null ) {
+ $siteurl = get_option( 'siteurl' );
+ $upload_path = trim( get_option( 'upload_path' ) );
+
+ if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
+ $dir = WP_CONTENT_DIR . '/uploads';
+ } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
+ // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
+ $dir = path_join( ABSPATH, $upload_path );
+ } else {
+ $dir = $upload_path;
+ }
+
+ if ( !$url = get_option( 'upload_url_path' ) ) {
+ if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
+ $url = WP_CONTENT_URL . '/uploads';
+ else
+ $url = trailingslashit( $siteurl ) . $upload_path;
+ }
+
+ // Obey the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
+ // We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
+ if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
+ $dir = ABSPATH . UPLOADS;
+ $url = trailingslashit( $siteurl ) . UPLOADS;
+ }
+
+ // If multisite (and if not the main site in a post-MU network)
+ if ( is_multisite() && ! ( is_main_site() && defined( 'MULTISITE' ) ) ) {
+
+ if ( ! get_site_option( 'ms_files_rewriting' ) ) {
+ // If ms-files rewriting is disabled (networks created post-3.5), it is fairly straightforward:
+ // Append sites/%d if we're not on the main site (for post-MU networks). (The extra directory
+ // prevents a four-digit ID from conflicting with a year-based directory for the main site.
+ // But if a MU-era network has disabled ms-files rewriting manually, they don't need the extra
+ // directory, as they never had wp-content/uploads for the main site.)
+
+ if ( defined( 'MULTISITE' ) )
+ $ms_dir = '/sites/' . get_current_blog_id();
+ else
+ $ms_dir = '/' . get_current_blog_id();
+
+ $dir .= $ms_dir;
+ $url .= $ms_dir;
+
+ } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
+ // Handle the old-form ms-files.php rewriting if the network still has that enabled.
+ // When ms-files rewriting is enabled, then we only listen to UPLOADS when:
+ // 1) we are not on the main site in a post-MU network,
+ // as wp-content/uploads is used there, and
+ // 2) we are not switched, as ms_upload_constants() hardcodes
+ // these constants to reflect the original blog ID.
+ //
+ // Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
+ // (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
+ // as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
+ // rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
+
+ if ( defined( 'BLOGUPLOADDIR' ) )
+ $dir = untrailingslashit( BLOGUPLOADDIR );
+ else
+ $dir = ABSPATH . UPLOADS;
+ $url = trailingslashit( $siteurl ) . 'files';
+ }
+ }
+
+ $basedir = $dir;
+ $baseurl = $url;
+
+ $subdir = '';
+ if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
+ // Generate the yearly and monthly dirs
+ if ( !$time )
+ $time = current_time( 'mysql' );
+ $y = substr( $time, 0, 4 );
+ $m = substr( $time, 5, 2 );
+ $subdir = "/$y/$m";
+ }
+
+ $dir .= $subdir;
+ $url .= $subdir;
+
+ $uploads = apply_filters( 'upload_dir',
+ array(
+ 'path' => $dir,
+ 'url' => $url,
+ 'subdir' => $subdir,
+ 'basedir' => $basedir,
+ 'baseurl' => $baseurl,
+ 'error' => false,
+ ) );
+
+ // Make sure we have an uploads dir
+ if ( ! wp_mkdir_p( $uploads['path'] ) ) {
+ if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
+ $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
+ else
+ $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
+
+ $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
+ $uploads['error'] = $message;
+ }
+
+ return $uploads;
+}
+
+/**
+ * Get a filename that is sanitized and unique for the given directory.
+ *
+ * If the filename is not unique, then a number will be added to the filename
+ * before the extension, and will continue adding numbers until the filename is
+ * unique.
+ *
+ * The callback is passed three parameters, the first one is the directory, the
+ * second is the filename, and the third is the extension.
+ *
+ * @since 2.5.0
+ *
+ * @param string $dir
+ * @param string $filename
+ * @param mixed $unique_filename_callback Callback.
+ * @return string New filename, if given wasn't unique.
+ */
+function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
+ // sanitize the file name before we begin processing
+ $filename = sanitize_file_name($filename);
+
+ // separate the filename into a name and extension
+ $info = pathinfo($filename);
+ $ext = !empty($info['extension']) ? '.' . $info['extension'] : '';
+ $name = basename($filename, $ext);
+
+ // edge case: if file is named '.ext', treat as an empty name
+ if ( $name === $ext )
+ $name = '';
+
+ // Increment the file number until we have a unique file to save in $dir. Use callback if supplied.
+ if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
+ $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
+ } else {
+ $number = '';
+
+ // change '.ext' to lower case
+ if ( $ext && strtolower($ext) != $ext ) {
+ $ext2 = strtolower($ext);
+ $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
+
+ // check for both lower and upper case extension or image sub-sizes may be overwritten
+ while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
+ $new_number = $number + 1;
+ $filename = str_replace( "$number$ext", "$new_number$ext", $filename );
+ $filename2 = str_replace( "$number$ext2", "$new_number$ext2", $filename2 );
+ $number = $new_number;
+ }
+ return $filename2;
+ }
+
+ while ( file_exists( $dir . "/$filename" ) ) {
+ if ( '' == "$number$ext" )
+ $filename = $filename . ++$number . $ext;
+ else
+ $filename = str_replace( "$number$ext", ++$number . $ext, $filename );
+ }
+ }
+
+ return $filename;
+}
+
+/**
+ * Create a file in the upload folder with given content.
+ *
+ * If there is an error, then the key 'error' will exist with the error message.
+ * If success, then the key 'file' will have the unique file path, the 'url' key
+ * will have the link to the new file. and the 'error' key will be set to false.
+ *
+ * This function will not move an uploaded file to the upload folder. It will
+ * create a new file with the content in $bits parameter. If you move the upload
+ * file, read the content of the uploaded file, and then you can give the
+ * filename and content to this function, which will add it to the upload
+ * folder.
+ *
+ * The permissions will be set on the new file automatically by this function.
+ *
+ * @since 2.0.0
+ *
+ * @param string $name
+ * @param null $deprecated Never used. Set to null.
+ * @param mixed $bits File content
+ * @param string $time Optional. Time formatted in 'yyyy/mm'.
+ * @return array
+ */
+function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.0' );
+
+ if ( empty( $name ) )
+ return array( 'error' => __( 'Empty filename' ) );
+
+ $wp_filetype = wp_check_filetype( $name );
+ if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
+ return array( 'error' => __( 'Invalid file type' ) );
+
+ $upload = wp_upload_dir( $time );
+
+ if ( $upload['error'] !== false )
+ return $upload;
+
+ $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
+ if ( !is_array( $upload_bits_error ) ) {
+ $upload[ 'error' ] = $upload_bits_error;
+ return $upload;
+ }
+
+ $filename = wp_unique_filename( $upload['path'], $name );
+
+ $new_file = $upload['path'] . "/$filename";
+ if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
+ if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
+ $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
+ else
+ $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
+
+ $message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
+ return array( 'error' => $message );
+ }
+
+ $ifp = @ fopen( $new_file, 'wb' );
+ if ( ! $ifp )
+ return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
+
+ @fwrite( $ifp, $bits );
+ fclose( $ifp );
+ clearstatcache();
+
+ // Set correct file permissions
+ $stat = @ stat( dirname( $new_file ) );
+ $perms = $stat['mode'] & 0007777;
+ $perms = $perms & 0000666;
+ @ chmod( $new_file, $perms );
+ clearstatcache();
+
+ // Compute the URL
+ $url = $upload['url'] . "/$filename";
+
+ return array( 'file' => $new_file, 'url' => $url, 'error' => false );
+}
+
+/**
+ * Retrieve the file type based on the extension name.
+ *
+ * @package WordPress
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'ext2type' hook on default supported types.
+ *
+ * @param string $ext The extension to search.
+ * @return string|null The file type, example: audio, video, document, spreadsheet, etc. Null if not found.
+ */
+function wp_ext2type( $ext ) {
+ $ext2type = apply_filters( 'ext2type', array(
+ 'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
+ 'video' => array( 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
+ 'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'rtf', 'wp', 'wpd' ),
+ 'spreadsheet' => array( 'numbers', 'ods', 'xls', 'xlsx', 'xlsm', 'xlsb' ),
+ 'interactive' => array( 'swf', 'key', 'ppt', 'pptx', 'pptm', 'pps', 'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
+ 'text' => array( 'asc', 'csv', 'tsv', 'txt' ),
+ 'archive' => array( 'bz2', 'cab', 'dmg', 'gz', 'rar', 'sea', 'sit', 'sqx', 'tar', 'tgz', 'zip', '7z' ),
+ 'code' => array( 'css', 'htm', 'html', 'php', 'js' ),
+ ));
+ foreach ( $ext2type as $type => $exts )
+ if ( in_array( $ext, $exts ) )
+ return $type;
+}
+
+/**
+ * Retrieve the file type from the file name.
+ *
+ * You can optionally define the mime array, if needed.
+ *
+ * @since 2.0.4
+ *
+ * @param string $filename File name or path.
+ * @param array $mimes Optional. Key is the file extension with value as the mime type.
+ * @return array Values with extension first and mime type.
+ */
+function wp_check_filetype( $filename, $mimes = null ) {
+ if ( empty($mimes) )
+ $mimes = get_allowed_mime_types();
+ $type = false;
+ $ext = false;
+
+ foreach ( $mimes as $ext_preg => $mime_match ) {
+ $ext_preg = '!\.(' . $ext_preg . ')$!i';
+ if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
+ $type = $mime_match;
+ $ext = $ext_matches[1];
+ break;
+ }
+ }
+
+ return compact( 'ext', 'type' );
+}
+
+/**
+ * Attempt to determine the real file type of a file.
+ * If unable to, the file name extension will be used to determine type.
+ *
+ * If it's determined that the extension does not match the file's real type,
+ * then the "proper_filename" value will be set with a proper filename and extension.
+ *
+ * Currently this function only supports validating images known to getimagesize().
+ *
+ * @since 3.0.0
+ *
+ * @param string $file Full path to the image.
+ * @param string $filename The filename of the image (may differ from $file due to $file being in a tmp directory)
+ * @param array $mimes Optional. Key is the file extension with value as the mime type.
+ * @return array Values for the extension, MIME, and either a corrected filename or false if original $filename is valid
+ */
+function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
+
+ $proper_filename = false;
+
+ // Do basic extension validation and MIME mapping
+ $wp_filetype = wp_check_filetype( $filename, $mimes );
+ extract( $wp_filetype );
+
+ // We can't do any further validation without a file to work with
+ if ( ! file_exists( $file ) )
+ return compact( 'ext', 'type', 'proper_filename' );
+
+ // We're able to validate images using GD
+ if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
+
+ // Attempt to figure out what type of image it actually is
+ $imgstats = @getimagesize( $file );
+
+ // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
+ if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
+ // This is a simplified array of MIMEs that getimagesize() can detect and their extensions
+ // You shouldn't need to use this filter, but it's here just in case
+ $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
+ 'image/jpeg' => 'jpg',
+ 'image/png' => 'png',
+ 'image/gif' => 'gif',
+ 'image/bmp' => 'bmp',
+ 'image/tiff' => 'tif',
+ ) );
+
+ // Replace whatever is after the last period in the filename with the correct extension
+ if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
+ $filename_parts = explode( '.', $filename );
+ array_pop( $filename_parts );
+ $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
+ $new_filename = implode( '.', $filename_parts );
+
+ if ( $new_filename != $filename )
+ $proper_filename = $new_filename; // Mark that it changed
+
+ // Redefine the extension / MIME
+ $wp_filetype = wp_check_filetype( $new_filename, $mimes );
+ extract( $wp_filetype );
+ }
+ }
+ }
+
+ // Let plugins try and validate other types of files
+ // Should return an array in the style of array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename )
+ return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
+}
+
+/**
+ * Retrieve list of mime types and file extensions.
+ *
+ * @since 3.5.0
+ *
+ * @uses apply_filters() Calls 'mime_types' on returned array. This filter should
+ * be used to add types, not remove them. To remove types use the upload_mimes filter.
+ *
+ * @return array Array of mime types keyed by the file extension regex corresponding to those types.
+ */
+function wp_get_mime_types() {
+ // Accepted MIME types are set here as PCRE unless provided.
+ return apply_filters( 'mime_types', array(
+ // Image formats
+ 'jpg|jpeg|jpe' => 'image/jpeg',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+ 'bmp' => 'image/bmp',
+ 'tif|tiff' => 'image/tiff',
+ 'ico' => 'image/x-icon',
+ // Video formats
+ 'asf|asx' => 'video/x-ms-asf',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wm' => 'video/x-ms-wm',
+ 'avi' => 'video/avi',
+ 'divx' => 'video/divx',
+ 'flv' => 'video/x-flv',
+ 'mov|qt' => 'video/quicktime',
+ 'mpeg|mpg|mpe' => 'video/mpeg',
+ 'mp4|m4v' => 'video/mp4',
+ 'ogv' => 'video/ogg',
+ 'webm' => 'video/webm',
+ 'mkv' => 'video/x-matroska',
+ // Text formats
+ 'txt|asc|c|cc|h' => 'text/plain',
+ 'csv' => 'text/csv',
+ 'tsv' => 'text/tab-separated-values',
+ 'ics' => 'text/calendar',
+ 'rtx' => 'text/richtext',
+ 'css' => 'text/css',
+ 'htm|html' => 'text/html',
+ // Audio formats
+ 'mp3|m4a|m4b' => 'audio/mpeg',
+ 'ra|ram' => 'audio/x-realaudio',
+ 'wav' => 'audio/wav',
+ 'ogg|oga' => 'audio/ogg',
+ 'mid|midi' => 'audio/midi',
+ 'wma' => 'audio/x-ms-wma',
+ 'wax' => 'audio/x-ms-wax',
+ 'mka' => 'audio/x-matroska',
+ // Misc application formats
+ 'rtf' => 'application/rtf',
+ 'js' => 'application/javascript',
+ 'pdf' => 'application/pdf',
+ 'swf' => 'application/x-shockwave-flash',
+ 'class' => 'application/java',
+ 'tar' => 'application/x-tar',
+ 'zip' => 'application/zip',
+ 'gz|gzip' => 'application/x-gzip',
+ 'rar' => 'application/rar',
+ '7z' => 'application/x-7z-compressed',
+ 'exe' => 'application/x-msdownload',
+ // MS Office formats
+ 'doc' => 'application/msword',
+ 'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
+ 'wri' => 'application/vnd.ms-write',
+ 'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
+ 'mdb' => 'application/vnd.ms-access',
+ 'mpp' => 'application/vnd.ms-project',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
+ 'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
+ // OpenOffice formats
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ // WordPerfect formats
+ 'wp|wpd' => 'application/wordperfect',
+ // iWork formats
+ 'key' => 'application/vnd.apple.keynote',
+ 'numbers' => 'application/vnd.apple.numbers',
+ 'pages' => 'application/vnd.apple.pages',
+ ) );
+}
+/**
+ * Retrieve list of allowed mime types and file extensions.
+ *
+ * @since 2.8.6
+ *
+ * @uses apply_filters() Calls 'upload_mimes' on returned array
+ * @uses wp_get_upload_mime_types() to fetch the list of mime types
+ *
+ * @return array Array of mime types keyed by the file extension regex corresponding to those types.
+ */
+function get_allowed_mime_types() {
+ return apply_filters( 'upload_mimes', wp_get_mime_types() );
+}
+
+/**
+ * Display "Are You Sure" message to confirm the action being taken.
+ *
+ * If the action has the nonce explain message, then it will be displayed along
+ * with the "Are you sure?" message.
+ *
+ * @package WordPress
+ * @subpackage Security
+ * @since 2.0.4
+ *
+ * @param string $action The nonce action.
+ */
+function wp_nonce_ays( $action ) {
+ $title = __( 'WordPress Failure Notice' );
+ if ( 'log-out' == $action ) {
+ $html = sprintf( __( 'You are attempting to log out of %s' ), get_bloginfo( 'name' ) ) . '</p><p>';
+ $html .= sprintf( __( "Do you really want to <a href='%s'>log out</a>?"), wp_logout_url() );
+ } else {
+ $html = __( 'Are you sure you want to do this?' );
+ if ( wp_get_referer() )
+ $html .= "</p><p><a href='" . esc_url( remove_query_arg( 'updated', wp_get_referer() ) ) . "'>" . __( 'Please try again.' ) . "</a>";
+ }
+
+ wp_die( $html, $title, array('response' => 403) );
+}
+
+/**
+ * Kill WordPress execution and display HTML message with error message.
+ *
+ * This function complements the die() PHP function. The difference is that
+ * HTML will be displayed to the user. It is recommended to use this function
+ * only, when the execution should not continue any further. It is not
+ * recommended to call this function very often and try to handle as many errors
+ * as possible silently.
+ *
+ * @since 2.0.4
+ *
+ * @param string $message Error message.
+ * @param string $title Error title.
+ * @param string|array $args Optional arguments to control behavior.
+ */
+function wp_die( $message = '', $title = '', $args = array() ) {
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
+ $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
+ elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
+ $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
+ else
+ $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
+
+ call_user_func( $function, $message, $title, $args );
+}
+
+/**
+ * Kill WordPress execution and display HTML message with error message.
+ *
+ * This is the default handler for wp_die if you want a custom one for your
+ * site then you can overload using the wp_die_handler filter in wp_die
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param string $message Error message.
+ * @param string $title Error title.
+ * @param string|array $args Optional arguments to control behavior.
+ */
+function _default_wp_die_handler( $message, $title = '', $args = array() ) {
+ $defaults = array( 'response' => 500 );
+ $r = wp_parse_args($args, $defaults);
+
+ $have_gettext = function_exists('__');
+
+ if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
+ if ( empty( $title ) ) {
+ $error_data = $message->get_error_data();
+ if ( is_array( $error_data ) && isset( $error_data['title'] ) )
+ $title = $error_data['title'];
+ }
+ $errors = $message->get_error_messages();
+ switch ( count( $errors ) ) :
+ case 0 :
+ $message = '';
+ break;
+ case 1 :
+ $message = "<p>{$errors[0]}</p>";
+ break;
+ default :
+ $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
+ break;
+ endswitch;
+ } elseif ( is_string( $message ) ) {
+ $message = "<p>$message</p>";
+ }
+
+ if ( isset( $r['back_link'] ) && $r['back_link'] ) {
+ $back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
+ $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
+ }
+
+ if ( ! did_action( 'admin_head' ) ) :
+ if ( !headers_sent() ) {
+ status_header( $r['response'] );
+ nocache_headers();
+ header( 'Content-Type: text/html; charset=utf-8' );
+ }
+
+ if ( empty($title) )
+ $title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
+
+ $text_direction = 'ltr';
+ if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
+ $text_direction = 'rtl';
+ elseif ( function_exists( 'is_rtl' ) && is_rtl() )
+ $text_direction = 'rtl';
+?>
+<!DOCTYPE html>
+<!-- Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" <?php if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) language_attributes(); else echo "dir='$text_direction'"; ?>>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title><?php echo $title ?></title>
+ <style type="text/css">
+ html {
+ background: #f9f9f9;
+ }
+ body {
+ background: #fff;
+ color: #333;
+ font-family: sans-serif;
+ margin: 2em auto;
+ padding: 1em 2em;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ border: 1px solid #dfdfdf;
+ max-width: 700px;
+ }
+ h1 {
+ border-bottom: 1px solid #dadada;
+ clear: both;
+ color: #666;
+ font: 24px Georgia, "Times New Roman", Times, serif;
+ margin: 30px 0 0 0;
+ padding: 0;
+ padding-bottom: 7px;
+ }
+ #error-page {
+ margin-top: 50px;
+ }
+ #error-page p {
+ font-size: 14px;
+ line-height: 1.5;
+ margin: 25px 0 20px;
+ }
+ #error-page code {
+ font-family: Consolas, Monaco, monospace;
+ }
+ ul li {
+ margin-bottom: 10px;
+ font-size: 14px ;
+ }
+ a {
+ color: #21759B;
+ text-decoration: none;
+ }
+ a:hover {
+ color: #D54E21;
+ }
+ .button {
+ display: inline-block;
+ text-decoration: none;
+ font-size: 14px;
+ line-height: 23px;
+ height: 24px;
+ margin: 0;
+ padding: 0 10px 1px;
+ cursor: pointer;
+ border-width: 1px;
+ border-style: solid;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ white-space: nowrap;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ background: #f3f3f3;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fefefe), to(#f4f4f4));
+ background-image: -webkit-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: -moz-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: -o-linear-gradient(top, #fefefe, #f4f4f4);
+ background-image: linear-gradient(to bottom, #fefefe, #f4f4f4);
+ border-color: #bbb;
+ color: #333;
+ text-shadow: 0 1px 0 #fff;
+ }
+
+ .button.button-large {
+ height: 29px;
+ line-height: 28px;
+ padding: 0 12px;
+ }
+
+ .button:hover,
+ .button:focus {
+ background: #f3f3f3;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f3f3f3));
+ background-image: -webkit-linear-gradient(top, #fff, #f3f3f3);
+ background-image: -moz-linear-gradient(top, #fff, #f3f3f3);
+ background-image: -ms-linear-gradient(top, #fff, #f3f3f3);
+ background-image: -o-linear-gradient(top, #fff, #f3f3f3);
+ background-image: linear-gradient(to bottom, #fff, #f3f3f3);
+ border-color: #999;
+ color: #222;
+ }
+
+ .button:focus {
+ -webkit-box-shadow: 1px 1px 1px rgba(0,0,0,.2);
+ box-shadow: 1px 1px 1px rgba(0,0,0,.2);
+ }
+
+ .button:active {
+ outline: none;
+ background: #eee;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f4f4f4), to(#fefefe));
+ background-image: -webkit-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: -moz-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: -ms-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: -o-linear-gradient(top, #f4f4f4, #fefefe);
+ background-image: linear-gradient(to bottom, #f4f4f4, #fefefe);
+ border-color: #999;
+ color: #333;
+ text-shadow: 0 -1px 0 #fff;
+ -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
+ box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
+ }
+
+ <?php if ( 'rtl' == $text_direction ) : ?>
+ body { font-family: Tahoma, Arial; }
+ <?php endif; ?>
+ </style>
+</head>
+<body id="error-page">
+<?php endif; // ! did_action( 'admin_head' ) ?>
+ <?php echo $message; ?>
+</body>
+</html>
+<?php
+ die();
+}
+
+/**
+ * Kill WordPress execution and display XML message with error message.
+ *
+ * This is the handler for wp_die when processing XMLRPC requests.
+ *
+ * @since 3.2.0
+ * @access private
+ *
+ * @param string $message Error message.
+ * @param string $title Error title.
+ * @param string|array $args Optional arguments to control behavior.
+ */
+function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
+ global $wp_xmlrpc_server;
+ $defaults = array( 'response' => 500 );
+
+ $r = wp_parse_args($args, $defaults);
+
+ if ( $wp_xmlrpc_server ) {
+ $error = new IXR_Error( $r['response'] , $message);
+ $wp_xmlrpc_server->output( $error->getXml() );
+ }
+ die();
+}
+
+/**
+ * Kill WordPress ajax execution.
+ *
+ * This is the handler for wp_die when processing Ajax requests.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string $message Optional. Response to print.
+ */
+function _ajax_wp_die_handler( $message = '' ) {
+ if ( is_scalar( $message ) )
+ die( (string) $message );
+ die( '0' );
+}
+
+/**
+ * Kill WordPress execution.
+ *
+ * This is the handler for wp_die when processing APP requests.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @param string $message Optional. Response to print.
+ */
+function _scalar_wp_die_handler( $message = '' ) {
+ if ( is_scalar( $message ) )
+ die( (string) $message );
+ die();
+}
+
+/**
+ * Send a JSON response back to an Ajax request.
+ *
+ * @since 3.5.0
+ *
+ * @param mixed $response Variable (usually an array or object) to encode as JSON, then print and die.
+ */
+function wp_send_json( $response ) {
+ @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
+ echo json_encode( $response );
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
+ wp_die();
+ else
+ die;
+}
+
+/**
+ * Send a JSON response back to an Ajax request, indicating success.
+ *
+ * @since 3.5.0
+ *
+ * @param mixed $data Data to encode as JSON, then print and die.
+ */
+function wp_send_json_success( $data = null ) {
+ $response = array( 'success' => true );
+
+ if ( isset( $data ) )
+ $response['data'] = $data;
+
+ wp_send_json( $response );
+}
+
+/**
+ * Send a JSON response back to an Ajax request, indicating failure.
+ *
+ * @since 3.5.0
+ *
+ * @param mixed $data Data to encode as JSON, then print and die.
+ */
+function wp_send_json_error( $data = null ) {
+ $response = array( 'success' => false );
+
+ if ( isset( $data ) )
+ $response['data'] = $data;
+
+ wp_send_json( $response );
+}
+
+/**
+ * Retrieve the WordPress home page URL.
+ *
+ * If the constant named 'WP_HOME' exists, then it will be used and returned by
+ * the function. This can be used to counter the redirection on your local
+ * development environment.
+ *
+ * @access private
+ * @package WordPress
+ * @since 2.2.0
+ *
+ * @param string $url URL for the home location
+ * @return string Homepage location.
+ */
+function _config_wp_home( $url = '' ) {
+ if ( defined( 'WP_HOME' ) )
+ return untrailingslashit( WP_HOME );
+ return $url;
+}
+
+/**
+ * Retrieve the WordPress site URL.
+ *
+ * If the constant named 'WP_SITEURL' is defined, then the value in that
+ * constant will always be returned. This can be used for debugging a site on
+ * your localhost while not having to change the database to your URL.
+ *
+ * @access private
+ * @package WordPress
+ * @since 2.2.0
+ *
+ * @param string $url URL to set the WordPress site location.
+ * @return string The WordPress Site URL
+ */
+function _config_wp_siteurl( $url = '' ) {
+ if ( defined( 'WP_SITEURL' ) )
+ return untrailingslashit( WP_SITEURL );
+ return $url;
+}
+
+/**
+ * Set the localized direction for MCE plugin.
+ *
+ * Will only set the direction to 'rtl', if the WordPress locale has the text
+ * direction set to 'rtl'.
+ *
+ * Fills in the 'directionality', 'plugins', and 'theme_advanced_button1' array
+ * keys. These keys are then returned in the $input array.
+ *
+ * @access private
+ * @package WordPress
+ * @subpackage MCE
+ * @since 2.1.0
+ *
+ * @param array $input MCE plugin array.
+ * @return array Direction set for 'rtl', if needed by locale.
+ */
+function _mce_set_direction( $input ) {
+ if ( is_rtl() ) {
+ $input['directionality'] = 'rtl';
+ $input['plugins'] .= ',directionality';
+ $input['theme_advanced_buttons1'] .= ',ltr';
+ }
+
+ return $input;
+}
+
+/**
+ * Convert smiley code to the icon graphic file equivalent.
+ *
+ * You can turn off smilies, by going to the write setting screen and unchecking
+ * the box, or by setting 'use_smilies' option to false or removing the option.
+ *
+ * Plugins may override the default smiley list by setting the $wpsmiliestrans
+ * to an array, with the key the code the blogger types in and the value the
+ * image file.
+ *
+ * The $wp_smiliessearch global is for the regular expression and is set each
+ * time the function is called.
+ *
+ * The full list of smilies can be found in the function and won't be listed in
+ * the description. Probably should create a Codex page for it, so that it is
+ * available.
+ *
+ * @global array $wpsmiliestrans
+ * @global array $wp_smiliessearch
+ * @since 2.2.0
+ */
+function smilies_init() {
+ global $wpsmiliestrans, $wp_smiliessearch;
+
+ // don't bother setting up smilies if they are disabled
+ if ( !get_option( 'use_smilies' ) )
+ return;
+
+ if ( !isset( $wpsmiliestrans ) ) {
+ $wpsmiliestrans = array(
+ ':mrgreen:' => 'icon_mrgreen.gif',
+ ':neutral:' => 'icon_neutral.gif',
+ ':twisted:' => 'icon_twisted.gif',
+ ':arrow:' => 'icon_arrow.gif',
+ ':shock:' => 'icon_eek.gif',
+ ':smile:' => 'icon_smile.gif',
+ ':???:' => 'icon_confused.gif',
+ ':cool:' => 'icon_cool.gif',
+ ':evil:' => 'icon_evil.gif',
+ ':grin:' => 'icon_biggrin.gif',
+ ':idea:' => 'icon_idea.gif',
+ ':oops:' => 'icon_redface.gif',
+ ':razz:' => 'icon_razz.gif',
+ ':roll:' => 'icon_rolleyes.gif',
+ ':wink:' => 'icon_wink.gif',
+ ':cry:' => 'icon_cry.gif',
+ ':eek:' => 'icon_surprised.gif',
+ ':lol:' => 'icon_lol.gif',
+ ':mad:' => 'icon_mad.gif',
+ ':sad:' => 'icon_sad.gif',
+ '8-)' => 'icon_cool.gif',
+ '8-O' => 'icon_eek.gif',
+ ':-(' => 'icon_sad.gif',
+ ':-)' => 'icon_smile.gif',
+ ':-?' => 'icon_confused.gif',
+ ':-D' => 'icon_biggrin.gif',
+ ':-P' => 'icon_razz.gif',
+ ':-o' => 'icon_surprised.gif',
+ ':-x' => 'icon_mad.gif',
+ ':-|' => 'icon_neutral.gif',
+ ';-)' => 'icon_wink.gif',
+ // This one transformation breaks regular text with frequency.
+ // '8)' => 'icon_cool.gif',
+ '8O' => 'icon_eek.gif',
+ ':(' => 'icon_sad.gif',
+ ':)' => 'icon_smile.gif',
+ ':?' => 'icon_confused.gif',
+ ':D' => 'icon_biggrin.gif',
+ ':P' => 'icon_razz.gif',
+ ':o' => 'icon_surprised.gif',
+ ':x' => 'icon_mad.gif',
+ ':|' => 'icon_neutral.gif',
+ ';)' => 'icon_wink.gif',
+ ':!:' => 'icon_exclaim.gif',
+ ':?:' => 'icon_question.gif',
+ );
+ }
+
+ if (count($wpsmiliestrans) == 0) {
+ return;
+ }
+
+ /*
+ * NOTE: we sort the smilies in reverse key order. This is to make sure
+ * we match the longest possible smilie (:???: vs :?) as the regular
+ * expression used below is first-match
+ */
+ krsort($wpsmiliestrans);
+
+ $wp_smiliessearch = '/(?:\s|^)';
+
+ $subchar = '';
+ foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
+ $firstchar = substr($smiley, 0, 1);
+ $rest = substr($smiley, 1);
+
+ // new subpattern?
+ if ($firstchar != $subchar) {
+ if ($subchar != '') {
+ $wp_smiliessearch .= ')|(?:\s|^)';
+ }
+ $subchar = $firstchar;
+ $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
+ } else {
+ $wp_smiliessearch .= '|';
+ }
+ $wp_smiliessearch .= preg_quote($rest, '/');
+ }
+
+ $wp_smiliessearch .= ')(?:\s|$)/m';
+}
+
+/**
+ * Merge user defined arguments into defaults array.
+ *
+ * This function is used throughout WordPress to allow for both string or array
+ * to be merged into another array.
+ *
+ * @since 2.2.0
+ *
+ * @param string|array $args Value to merge with $defaults
+ * @param array $defaults Array that serves as the defaults.
+ * @return array Merged user defined values with defaults.
+ */
+function wp_parse_args( $args, $defaults = '' ) {
+ if ( is_object( $args ) )
+ $r = get_object_vars( $args );
+ elseif ( is_array( $args ) )
+ $r =& $args;
+ else
+ wp_parse_str( $args, $r );
+
+ if ( is_array( $defaults ) )
+ return array_merge( $defaults, $r );
+ return $r;
+}
+
+/**
+ * Clean up an array, comma- or space-separated list of IDs.
+ *
+ * @since 3.0.0
+ *
+ * @param array|string $list
+ * @return array Sanitized array of IDs
+ */
+function wp_parse_id_list( $list ) {
+ if ( !is_array($list) )
+ $list = preg_split('/[\s,]+/', $list);
+
+ return array_unique(array_map('absint', $list));
+}
+
+/**
+ * Extract a slice of an array, given a list of keys.
+ *
+ * @since 3.1.0
+ *
+ * @param array $array The original array
+ * @param array $keys The list of keys
+ * @return array The array slice
+ */
+function wp_array_slice_assoc( $array, $keys ) {
+ $slice = array();
+ foreach ( $keys as $key )
+ if ( isset( $array[ $key ] ) )
+ $slice[ $key ] = $array[ $key ];
+
+ return $slice;
+}
+
+/**
+ * Filters a list of objects, based on a set of key => value arguments.
+ *
+ * @since 3.0.0
+ *
+ * @param array $list An array of objects to filter
+ * @param array $args An array of key => value arguments to match against each object
+ * @param string $operator The logical operation to perform. 'or' means only one element
+ * from the array needs to match; 'and' means all elements must match. The default is 'and'.
+ * @param bool|string $field A field from the object to place instead of the entire object
+ * @return array A list of objects or object fields
+ */
+function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
+ if ( ! is_array( $list ) )
+ return array();
+
+ $list = wp_list_filter( $list, $args, $operator );
+
+ if ( $field )
+ $list = wp_list_pluck( $list, $field );
+
+ return $list;
+}
+
+/**
+ * Filters a list of objects, based on a set of key => value arguments.
+ *
+ * @since 3.1.0
+ *
+ * @param array $list An array of objects to filter
+ * @param array $args An array of key => value arguments to match against each object
+ * @param string $operator The logical operation to perform:
+ * 'AND' means all elements from the array must match;
+ * 'OR' means only one element needs to match;
+ * 'NOT' means no elements may match.
+ * The default is 'AND'.
+ * @return array
+ */
+function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
+ if ( ! is_array( $list ) )
+ return array();
+
+ if ( empty( $args ) )
+ return $list;
+
+ $operator = strtoupper( $operator );
+ $count = count( $args );
+ $filtered = array();
+
+ foreach ( $list as $key => $obj ) {
+ $to_match = (array) $obj;
+
+ $matched = 0;
+ foreach ( $args as $m_key => $m_value ) {
+ if ( array_key_exists( $m_key, $to_match ) && $m_value == $to_match[ $m_key ] )
+ $matched++;
+ }
+
+ if ( ( 'AND' == $operator && $matched == $count )
+ || ( 'OR' == $operator && $matched > 0 )
+ || ( 'NOT' == $operator && 0 == $matched ) ) {
+ $filtered[$key] = $obj;
+ }
+ }
+
+ return $filtered;
+}
+
+/**
+ * Pluck a certain field out of each object in a list.
+ *
+ * @since 3.1.0
+ *
+ * @param array $list A list of objects or arrays
+ * @param int|string $field A field from the object to place instead of the entire object
+ * @return array
+ */
+function wp_list_pluck( $list, $field ) {
+ foreach ( $list as $key => $value ) {
+ if ( is_object( $value ) )
+ $list[ $key ] = $value->$field;
+ else
+ $list[ $key ] = $value[ $field ];
+ }
+
+ return $list;
+}
+
+/**
+ * Determines if Widgets library should be loaded.
+ *
+ * Checks to make sure that the widgets library hasn't already been loaded. If
+ * it hasn't, then it will load the widgets library and run an action hook.
+ *
+ * @since 2.2.0
+ * @uses add_action() Calls '_admin_menu' hook with 'wp_widgets_add_menu' value.
+ */
+function wp_maybe_load_widgets() {
+ if ( ! apply_filters('load_default_widgets', true) )
+ return;
+ require_once( ABSPATH . WPINC . '/default-widgets.php' );
+ add_action( '_admin_menu', 'wp_widgets_add_menu' );
+}
+
+/**
+ * Append the Widgets menu to the themes main menu.
+ *
+ * @since 2.2.0
+ * @uses $submenu The administration submenu list.
+ */
+function wp_widgets_add_menu() {
+ global $submenu;
+
+ if ( ! current_theme_supports( 'widgets' ) )
+ return;
+
+ $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
+ ksort( $submenu['themes.php'], SORT_NUMERIC );
+}
+
+/**
+ * Flush all output buffers for PHP 5.2.
+ *
+ * Make sure all output buffers are flushed before our singletons our destroyed.
+ *
+ * @since 2.2.0
+ */
+function wp_ob_end_flush_all() {
+ $levels = ob_get_level();
+ for ($i=0; $i<$levels; $i++)
+ ob_end_flush();
+}
+
+/**
+ * Load custom DB error or display WordPress DB error.
+ *
+ * If a file exists in the wp-content directory named db-error.php, then it will
+ * be loaded instead of displaying the WordPress DB error. If it is not found,
+ * then the WordPress DB error will be displayed instead.
+ *
+ * The WordPress DB error sets the HTTP status header to 500 to try to prevent
+ * search engines from caching the message. Custom DB messages should do the
+ * same.
+ *
+ * This function was backported to WordPress 2.3.2, but originally was added
+ * in WordPress 2.5.0.
+ *
+ * @since 2.3.2
+ * @uses $wpdb
+ */
+function dead_db() {
+ global $wpdb;
+
+ // Load custom DB error template, if present.
+ if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
+ require_once( WP_CONTENT_DIR . '/db-error.php' );
+ die();
+ }
+
+ // If installing or in the admin, provide the verbose message.
+ if ( defined('WP_INSTALLING') || defined('WP_ADMIN') )
+ wp_die($wpdb->error);
+
+ // Otherwise, be terse.
+ status_header( 500 );
+ nocache_headers();
+ header( 'Content-Type: text/html; charset=utf-8' );
+
+ wp_load_translations_early();
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title><?php _e( 'Database Error' ); ?></title>
+
+</head>
+<body>
+ <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
+</body>
+</html>
+<?php
+ die();
+}
+
+/**
+ * Converts value to nonnegative integer.
+ *
+ * @since 2.5.0
+ *
+ * @param mixed $maybeint Data you wish to have converted to a nonnegative integer
+ * @return int An nonnegative integer
+ */
+function absint( $maybeint ) {
+ return abs( intval( $maybeint ) );
+}
+
+/**
+ * Determines if the blog can be accessed over SSL.
+ *
+ * Determines if blog can be accessed over SSL by using cURL to access the site
+ * using the https in the siteurl. Requires cURL extension to work correctly.
+ *
+ * @since 2.5.0
+ *
+ * @param string $url
+ * @return bool Whether SSL access is available
+ */
+function url_is_accessable_via_ssl($url)
+{
+ if ( in_array( 'curl', get_loaded_extensions() ) ) {
+ $ssl = set_url_scheme( $url, 'https' );
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $ssl);
+ curl_setopt($ch, CURLOPT_FAILONERROR, true);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
+
+ curl_exec($ch);
+
+ $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close ($ch);
+
+ if ($status == 200 || $status == 401) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Marks a function as deprecated and informs when it has been used.
+ *
+ * There is a hook deprecated_function_run that will be called that can be used
+ * to get the backtrace up to what file and function called the deprecated
+ * function.
+ *
+ * The current behavior is to trigger a user error if WP_DEBUG is true.
+ *
+ * This function is to be used in every function that is deprecated.
+ *
+ * @package WordPress
+ * @subpackage Debug
+ * @since 2.5.0
+ * @access private
+ *
+ * @uses do_action() Calls 'deprecated_function_run' and passes the function name, what to use instead,
+ * and the version the function was deprecated in.
+ * @uses apply_filters() Calls 'deprecated_function_trigger_error' and expects boolean value of true to do
+ * trigger or false to not trigger error.
+ *
+ * @param string $function The function that was called
+ * @param string $version The version of WordPress that deprecated the function
+ * @param string $replacement Optional. The function that should have been called
+ */
+function _deprecated_function( $function, $version, $replacement = null ) {
+
+ do_action( 'deprecated_function_run', $function, $replacement, $version );
+
+ // Allow plugin to filter the output error trigger
+ if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
+ if ( function_exists( '__' ) ) {
+ if ( ! is_null( $replacement ) )
+ trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
+ else
+ trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
+ } else {
+ if ( ! is_null( $replacement ) )
+ trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
+ else
+ trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
+ }
+ }
+}
+
+/**
+ * Marks a file as deprecated and informs when it has been used.
+ *
+ * There is a hook deprecated_file_included that will be called that can be used
+ * to get the backtrace up to what file and function included the deprecated
+ * file.
+ *
+ * The current behavior is to trigger a user error if WP_DEBUG is true.
+ *
+ * This function is to be used in every file that is deprecated.
+ *
+ * @package WordPress
+ * @subpackage Debug
+ * @since 2.5.0
+ * @access private
+ *
+ * @uses do_action() Calls 'deprecated_file_included' and passes the file name, what to use instead,
+ * the version in which the file was deprecated, and any message regarding the change.
+ * @uses apply_filters() Calls 'deprecated_file_trigger_error' and expects boolean value of true to do
+ * trigger or false to not trigger error.
+ *
+ * @param string $file The file that was included
+ * @param string $version The version of WordPress that deprecated the file
+ * @param string $replacement Optional. The file that should have been included based on ABSPATH
+ * @param string $message Optional. A message regarding the change
+ */
+function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
+
+ do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
+
+ // Allow plugin to filter the output error trigger
+ if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
+ $message = empty( $message ) ? '' : ' ' . $message;
+ if ( function_exists( '__' ) ) {
+ if ( ! is_null( $replacement ) )
+ trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
+ else
+ trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
+ } else {
+ if ( ! is_null( $replacement ) )
+ trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
+ else
+ trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
+ }
+ }
+}
+/**
+ * Marks a function argument as deprecated and informs when it has been used.
+ *
+ * This function is to be used whenever a deprecated function argument is used.
+ * Before this function is called, the argument must be checked for whether it was
+ * used by comparing it to its default value or evaluating whether it is empty.
+ * For example:
+ * <code>
+ * if ( !empty($deprecated) )
+ * _deprecated_argument( __FUNCTION__, '3.0' );
+ * </code>
+ *
+ * There is a hook deprecated_argument_run that will be called that can be used
+ * to get the backtrace up to what file and function used the deprecated
+ * argument.
+ *
+ * The current behavior is to trigger a user error if WP_DEBUG is true.
+ *
+ * @package WordPress
+ * @subpackage Debug
+ * @since 3.0.0
+ * @access private
+ *
+ * @uses do_action() Calls 'deprecated_argument_run' and passes the function name, a message on the change,
+ * and the version in which the argument was deprecated.
+ * @uses apply_filters() Calls 'deprecated_argument_trigger_error' and expects boolean value of true to do
+ * trigger or false to not trigger error.
+ *
+ * @param string $function The function that was called
+ * @param string $version The version of WordPress that deprecated the argument used
+ * @param string $message Optional. A message regarding the change.
+ */
+function _deprecated_argument( $function, $version, $message = null ) {
+
+ do_action( 'deprecated_argument_run', $function, $message, $version );
+
+ // Allow plugin to filter the output error trigger
+ if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
+ if ( function_exists( '__' ) ) {
+ if ( ! is_null( $message ) )
+ trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
+ else
+ trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
+ } else {
+ if ( ! is_null( $message ) )
+ trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
+ else
+ trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
+ }
+ }
+}
+
+/**
+ * Marks something as being incorrectly called.
+ *
+ * There is a hook doing_it_wrong_run that will be called that can be used
+ * to get the backtrace up to what file and function called the deprecated
+ * function.
+ *
+ * The current behavior is to trigger a user error if WP_DEBUG is true.
+ *
+ * @package WordPress
+ * @subpackage Debug
+ * @since 3.1.0
+ * @access private
+ *
+ * @uses do_action() Calls 'doing_it_wrong_run' and passes the function arguments.
+ * @uses apply_filters() Calls 'doing_it_wrong_trigger_error' and expects boolean value of true to do
+ * trigger or false to not trigger error.
+ *
+ * @param string $function The function that was called.
+ * @param string $message A message explaining what has been done incorrectly.
+ * @param string $version The version of WordPress where the message was added.
+ */
+function _doing_it_wrong( $function, $message, $version ) {
+
+ do_action( 'doing_it_wrong_run', $function, $message, $version );
+
+ // Allow plugin to filter the output error trigger
+ if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
+ if ( function_exists( '__' ) ) {
+ $version = is_null( $version ) ? '' : sprintf( __( '(This message was added in version %s.)' ), $version );
+ $message .= ' ' . __( 'Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.' );
+ trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
+ } else {
+ $version = is_null( $version ) ? '' : sprintf( '(This message was added in version %s.)', $version );
+ $message .= ' Please see <a href="http://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information.';
+ trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
+ }
+ }
+}
+
+/**
+ * Is the server running earlier than 1.5.0 version of lighttpd?
+ *
+ * @since 2.5.0
+ *
+ * @return bool Whether the server is running lighttpd < 1.5.0
+ */
+function is_lighttpd_before_150() {
+ $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
+ $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
+ return 'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
+}
+
+/**
+ * Does the specified module exist in the Apache config?
+ *
+ * @since 2.5.0
+ *
+ * @param string $mod e.g. mod_rewrite
+ * @param bool $default The default return value if the module is not found
+ * @return bool
+ */
+function apache_mod_loaded($mod, $default = false) {
+ global $is_apache;
+
+ if ( !$is_apache )
+ return false;
+
+ if ( function_exists('apache_get_modules') ) {
+ $mods = apache_get_modules();
+ if ( in_array($mod, $mods) )
+ return true;
+ } elseif ( function_exists('phpinfo') ) {
+ ob_start();
+ phpinfo(8);
+ $phpinfo = ob_get_clean();
+ if ( false !== strpos($phpinfo, $mod) )
+ return true;
+ }
+ return $default;
+}
+
+/**
+ * Check if IIS 7+ supports pretty permalinks.
+ *
+ * @since 2.8.0
+ *
+ * @return bool
+ */
+function iis7_supports_permalinks() {
+ global $is_iis7;
+
+ $supports_permalinks = false;
+ if ( $is_iis7 ) {
+ /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
+ * easily update the xml configuration file, hence we just bail out and tell user that
+ * pretty permalinks cannot be used.
+ *
+ * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
+ * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
+ * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
+ * via ISAPI then pretty permalinks will not work.
+ */
+ $supports_permalinks = class_exists('DOMDocument') && isset($_SERVER['IIS_UrlRewriteModule']) && ( php_sapi_name() == 'cgi-fcgi' );
+ }
+
+ return apply_filters('iis7_supports_permalinks', $supports_permalinks);
+}
+
+/**
+ * File validates against allowed set of defined rules.
+ *
+ * A return value of '1' means that the $file contains either '..' or './'. A
+ * return value of '2' means that the $file contains ':' after the first
+ * character. A return value of '3' means that the file is not in the allowed
+ * files list.
+ *
+ * @since 1.2.0
+ *
+ * @param string $file File path.
+ * @param array $allowed_files List of allowed files.
+ * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
+ */
+function validate_file( $file, $allowed_files = '' ) {
+ if ( false !== strpos( $file, '..' ) )
+ return 1;
+
+ if ( false !== strpos( $file, './' ) )
+ return 1;
+
+ if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
+ return 3;
+
+ if (':' == substr( $file, 1, 1 ) )
+ return 2;
+
+ return 0;
+}
+
+/**
+ * Determine if SSL is used.
+ *
+ * @since 2.6.0
+ *
+ * @return bool True if SSL, false if not used.
+ */
+function is_ssl() {
+ if ( isset($_SERVER['HTTPS']) ) {
+ if ( 'on' == strtolower($_SERVER['HTTPS']) )
+ return true;
+ if ( '1' == $_SERVER['HTTPS'] )
+ return true;
+ } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Whether SSL login should be forced.
+ *
+ * @since 2.6.0
+ *
+ * @param string|bool $force Optional.
+ * @return bool True if forced, false if not forced.
+ */
+function force_ssl_login( $force = null ) {
+ static $forced = false;
+
+ if ( !is_null( $force ) ) {
+ $old_forced = $forced;
+ $forced = $force;
+ return $old_forced;
+ }
+
+ return $forced;
+}
+
+/**
+ * Whether to force SSL used for the Administration Screens.
+ *
+ * @since 2.6.0
+ *
+ * @param string|bool $force
+ * @return bool True if forced, false if not forced.
+ */
+function force_ssl_admin( $force = null ) {
+ static $forced = false;
+
+ if ( !is_null( $force ) ) {
+ $old_forced = $forced;
+ $forced = $force;
+ return $old_forced;
+ }
+
+ return $forced;
+}
+
+/**
+ * Guess the URL for the site.
+ *
+ * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
+ * directory.
+ *
+ * @since 2.6.0
+ *
+ * @return string
+ */
+function wp_guess_url() {
+ if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
+ $url = WP_SITEURL;
+ } else {
+ $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
+ $url = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $schema . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ }
+
+ return rtrim($url, '/');
+}
+
+/**
+ * Temporarily suspend cache additions.
+ *
+ * Stops more data being added to the cache, but still allows cache retrieval.
+ * This is useful for actions, such as imports, when a lot of data would otherwise
+ * be almost uselessly added to the cache.
+ *
+ * Suspension lasts for a single page load at most. Remember to call this
+ * function again if you wish to re-enable cache adds earlier.
+ *
+ * @since 3.3.0
+ *
+ * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
+ * @return bool The current suspend setting
+ */
+function wp_suspend_cache_addition( $suspend = null ) {
+ static $_suspend = false;
+
+ if ( is_bool( $suspend ) )
+ $_suspend = $suspend;
+
+ return $_suspend;
+}
+
+/**
+ * Suspend cache invalidation.
+ *
+ * Turns cache invalidation on and off. Useful during imports where you don't wont to do invalidations
+ * every time a post is inserted. Callers must be sure that what they are doing won't lead to an inconsistent
+ * cache when invalidation is suspended.
+ *
+ * @since 2.7.0
+ *
+ * @param bool $suspend Whether to suspend or enable cache invalidation
+ * @return bool The current suspend setting
+ */
+function wp_suspend_cache_invalidation($suspend = true) {
+ global $_wp_suspend_cache_invalidation;
+
+ $current_suspend = $_wp_suspend_cache_invalidation;
+ $_wp_suspend_cache_invalidation = $suspend;
+ return $current_suspend;
+}
+
+/**
+ * Is main site?
+ *
+ *
+ * @since 3.0.0
+ * @package WordPress
+ *
+ * @param int $blog_id optional blog id to test (default current blog)
+ * @return bool True if not multisite or $blog_id is main site
+ */
+function is_main_site( $blog_id = '' ) {
+ global $current_site;
+
+ if ( ! is_multisite() )
+ return true;
+
+ if ( ! $blog_id )
+ $blog_id = get_current_blog_id();
+
+ return $blog_id == $current_site->blog_id;
+}
+
+/**
+ * Whether global terms are enabled.
+ *
+ *
+ * @since 3.0.0
+ * @package WordPress
+ *
+ * @return bool True if multisite and global terms enabled
+ */
+function global_terms_enabled() {
+ if ( ! is_multisite() )
+ return false;
+
+ static $global_terms = null;
+ if ( is_null( $global_terms ) ) {
+ $filter = apply_filters( 'global_terms_enabled', null );
+ if ( ! is_null( $filter ) )
+ $global_terms = (bool) $filter;
+ else
+ $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
+ }
+ return $global_terms;
+}
+
+/**
+ * gmt_offset modification for smart timezone handling.
+ *
+ * Overrides the gmt_offset option if we have a timezone_string available.
+ *
+ * @since 2.8.0
+ *
+ * @return float|bool
+ */
+function wp_timezone_override_offset() {
+ if ( !$timezone_string = get_option( 'timezone_string' ) ) {
+ return false;
+ }
+
+ $timezone_object = timezone_open( $timezone_string );
+ $datetime_object = date_create();
+ if ( false === $timezone_object || false === $datetime_object ) {
+ return false;
+ }
+ return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
+}
+
+/**
+ * {@internal Missing Short Description}}
+ *
+ * @since 2.9.0
+ *
+ * @param unknown_type $a
+ * @param unknown_type $b
+ * @return int
+ */
+function _wp_timezone_choice_usort_callback( $a, $b ) {
+ // Don't use translated versions of Etc
+ if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
+ // Make the order of these more like the old dropdown
+ if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
+ return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
+ }
+ if ( 'UTC' === $a['city'] ) {
+ if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
+ return 1;
+ }
+ return -1;
+ }
+ if ( 'UTC' === $b['city'] ) {
+ if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
+ return -1;
+ }
+ return 1;
+ }
+ return strnatcasecmp( $a['city'], $b['city'] );
+ }
+ if ( $a['t_continent'] == $b['t_continent'] ) {
+ if ( $a['t_city'] == $b['t_city'] ) {
+ return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
+ }
+ return strnatcasecmp( $a['t_city'], $b['t_city'] );
+ } else {
+ // Force Etc to the bottom of the list
+ if ( 'Etc' === $a['continent'] ) {
+ return 1;
+ }
+ if ( 'Etc' === $b['continent'] ) {
+ return -1;
+ }
+ return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
+ }
+}
+
+/**
+ * Gives a nicely formatted list of timezone strings.
+ *
+ * @since 2.9.0
+ *
+ * @param string $selected_zone Selected Zone
+ * @return string
+ */
+function wp_timezone_choice( $selected_zone ) {
+ static $mo_loaded = false;
+
+ $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
+
+ // Load translations for continents and cities
+ if ( !$mo_loaded ) {
+ $locale = get_locale();
+ $mofile = WP_LANG_DIR . '/continents-cities-' . $locale . '.mo';
+ load_textdomain( 'continents-cities', $mofile );
+ $mo_loaded = true;
+ }
+
+ $zonen = array();
+ foreach ( timezone_identifiers_list() as $zone ) {
+ $zone = explode( '/', $zone );
+ if ( !in_array( $zone[0], $continents ) ) {
+ continue;
+ }
+
+ // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
+ $exists = array(
+ 0 => ( isset( $zone[0] ) && $zone[0] ),
+ 1 => ( isset( $zone[1] ) && $zone[1] ),
+ 2 => ( isset( $zone[2] ) && $zone[2] ),
+ );
+ $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
+ $exists[4] = ( $exists[1] && $exists[3] );
+ $exists[5] = ( $exists[2] && $exists[3] );
+
+ $zonen[] = array(
+ 'continent' => ( $exists[0] ? $zone[0] : '' ),
+ 'city' => ( $exists[1] ? $zone[1] : '' ),
+ 'subcity' => ( $exists[2] ? $zone[2] : '' ),
+ 't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
+ 't_city' => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
+ 't_subcity' => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
+ );
+ }
+ usort( $zonen, '_wp_timezone_choice_usort_callback' );
+
+ $structure = array();
+
+ if ( empty( $selected_zone ) ) {
+ $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
+ }
+
+ foreach ( $zonen as $key => $zone ) {
+ // Build value in an array to join later
+ $value = array( $zone['continent'] );
+
+ if ( empty( $zone['city'] ) ) {
+ // It's at the continent level (generally won't happen)
+ $display = $zone['t_continent'];
+ } else {
+ // It's inside a continent group
+
+ // Continent optgroup
+ if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
+ $label = $zone['t_continent'];
+ $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
+ }
+
+ // Add the city to the value
+ $value[] = $zone['city'];
+
+ $display = $zone['t_city'];
+ if ( !empty( $zone['subcity'] ) ) {
+ // Add the subcity to the value
+ $value[] = $zone['subcity'];
+ $display .= ' - ' . $zone['t_subcity'];
+ }
+ }
+
+ // Build the value
+ $value = join( '/', $value );
+ $selected = '';
+ if ( $value === $selected_zone ) {
+ $selected = 'selected="selected" ';
+ }
+ $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
+
+ // Close continent optgroup
+ if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
+ $structure[] = '</optgroup>';
+ }
+ }
+
+ // Do UTC
+ $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
+ $selected = '';
+ if ( 'UTC' === $selected_zone )
+ $selected = 'selected="selected" ';
+ $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
+ $structure[] = '</optgroup>';
+
+ // Do manual UTC offsets
+ $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
+ $offset_range = array (-12, -11.5, -11, -10.5, -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5,
+ 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6, 6.5, 7, 7.5, 8, 8.5, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 13.75, 14);
+ foreach ( $offset_range as $offset ) {
+ if ( 0 <= $offset )
+ $offset_name = '+' . $offset;
+ else
+ $offset_name = (string) $offset;
+
+ $offset_value = $offset_name;
+ $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
+ $offset_name = 'UTC' . $offset_name;
+ $offset_value = 'UTC' . $offset_value;
+ $selected = '';
+ if ( $offset_value === $selected_zone )
+ $selected = 'selected="selected" ';
+ $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
+
+ }
+ $structure[] = '</optgroup>';
+
+ return join( "\n", $structure );
+}
+
+/**
+ * Strip close comment and close php tags from file headers used by WP.
+ * See http://core.trac.wordpress.org/ticket/8497
+ *
+ * @since 2.8.0
+ *
+ * @param string $str
+ * @return string
+ */
+function _cleanup_header_comment($str) {
+ return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
+}
+
+/**
+ * Permanently deletes posts, pages, attachments, and comments which have been in the trash for EMPTY_TRASH_DAYS.
+ *
+ * @since 2.9.0
+ */
+function wp_scheduled_delete() {
+ global $wpdb;
+
+ $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
+
+ $posts_to_delete = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
+
+ foreach ( (array) $posts_to_delete as $post ) {
+ $post_id = (int) $post['post_id'];
+ if ( !$post_id )
+ continue;
+
+ $del_post = get_post($post_id);
+
+ if ( !$del_post || 'trash' != $del_post->post_status ) {
+ delete_post_meta($post_id, '_wp_trash_meta_status');
+ delete_post_meta($post_id, '_wp_trash_meta_time');
+ } else {
+ wp_delete_post($post_id);
+ }
+ }
+
+ $comments_to_delete = $wpdb->get_results($wpdb->prepare("SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
+
+ foreach ( (array) $comments_to_delete as $comment ) {
+ $comment_id = (int) $comment['comment_id'];
+ if ( !$comment_id )
+ continue;
+
+ $del_comment = get_comment($comment_id);
+
+ if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
+ delete_comment_meta($comment_id, '_wp_trash_meta_time');
+ delete_comment_meta($comment_id, '_wp_trash_meta_status');
+ } else {
+ wp_delete_comment($comment_id);
+ }
+ }
+}
+
+/**
+ * Retrieve metadata from a file.
+ *
+ * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
+ * Each piece of metadata must be on its own line. Fields can not span multiple
+ * lines, the value will get cut at the end of the first line.
+ *
+ * If the file data is not within that first 8kiB, then the author should correct
+ * their plugin file and move the data headers to the top.
+ *
+ * @see http://codex.wordpress.org/File_Header
+ *
+ * @since 2.9.0
+ * @param string $file Path to the file
+ * @param array $default_headers List of headers, in the format array('HeaderKey' => 'Header Name')
+ * @param string $context If specified adds filter hook "extra_{$context}_headers"
+ */
+function get_file_data( $file, $default_headers, $context = '' ) {
+ // We don't need to write to the file, so just open for reading.
+ $fp = fopen( $file, 'r' );
+
+ // Pull only the first 8kiB of the file in.
+ $file_data = fread( $fp, 8192 );
+
+ // PHP will close file handle, but we are good citizens.
+ fclose( $fp );
+
+ // Make sure we catch CR-only line endings.
+ $file_data = str_replace( "\r", "\n", $file_data );
+
+ if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
+ $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
+ $all_headers = array_merge( $extra_headers, (array) $default_headers );
+ } else {
+ $all_headers = $default_headers;
+ }
+
+ foreach ( $all_headers as $field => $regex ) {
+ if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
+ $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
+ else
+ $all_headers[ $field ] = '';
+ }
+
+ return $all_headers;
+}
+
+/**
+ * Used internally to tidy up the search terms.
+ *
+ * @access private
+ * @since 2.9.0
+ *
+ * @param string $t
+ * @return string
+ */
+function _search_terms_tidy($t) {
+ return trim($t, "\"'\n\r ");
+}
+
+/**
+ * Returns true.
+ *
+ * Useful for returning true to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_false()
+ * @return bool true
+ */
+function __return_true() {
+ return true;
+}
+
+/**
+ * Returns false.
+ *
+ * Useful for returning false to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_true()
+ * @return bool false
+ */
+function __return_false() {
+ return false;
+}
+
+/**
+ * Returns 0.
+ *
+ * Useful for returning 0 to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_zero()
+ * @return int 0
+ */
+function __return_zero() {
+ return 0;
+}
+
+/**
+ * Returns an empty array.
+ *
+ * Useful for returning an empty array to filters easily.
+ *
+ * @since 3.0.0
+ * @see __return_zero()
+ * @return array Empty array
+ */
+function __return_empty_array() {
+ return array();
+}
+
+/**
+ * Returns null.
+ *
+ * Useful for returning null to filters easily.
+ *
+ * @since 3.4.0
+ * @return null
+ */
+function __return_null() {
+ return null;
+}
+
+/**
+ * Send a HTTP header to disable content type sniffing in browsers which support it.
+ *
+ * @link http://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
+ * @link http://src.chromium.org/viewvc/chrome?view=rev&revision=6985
+ *
+ * @since 3.0.0
+ * @return none
+ */
+function send_nosniff_header() {
+ @header( 'X-Content-Type-Options: nosniff' );
+}
+
+/**
+ * Returns a MySQL expression for selecting the week number based on the start_of_week option.
+ *
+ * @internal
+ * @since 3.0.0
+ * @param string $column
+ * @return string
+ */
+function _wp_mysql_week( $column ) {
+ switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
+ default :
+ case 0 :
+ return "WEEK( $column, 0 )";
+ case 1 :
+ return "WEEK( $column, 1 )";
+ case 2 :
+ case 3 :
+ case 4 :
+ case 5 :
+ case 6 :
+ return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
+ }
+}
+
+/**
+ * Finds hierarchy loops using a callback function that maps object IDs to parent IDs.
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param callback $callback function that accepts ( ID, $callback_args ) and outputs parent_ID
+ * @param int $start The ID to start the loop check at
+ * @param int $start_parent the parent_ID of $start to use instead of calling $callback( $start ). Use null to always use $callback
+ * @param array $callback_args optional additional arguments to send to $callback
+ * @return array IDs of all members of loop
+ */
+function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
+ $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
+
+ if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
+ return array();
+
+ return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
+}
+
+/**
+ * Uses the "The Tortoise and the Hare" algorithm to detect loops.
+ *
+ * For every step of the algorithm, the hare takes two steps and the tortoise one.
+ * If the hare ever laps the tortoise, there must be a loop.
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param callback $callback function that accepts ( ID, callback_arg, ... ) and outputs parent_ID
+ * @param int $start The ID to start the loop check at
+ * @param array $override an array of ( ID => parent_ID, ... ) to use instead of $callback
+ * @param array $callback_args optional additional arguments to send to $callback
+ * @param bool $_return_loop Return loop members or just detect presence of loop?
+ * Only set to true if you already know the given $start is part of a loop
+ * (otherwise the returned array might include branches)
+ * @return mixed scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if $_return_loop
+ */
+function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
+ $tortoise = $hare = $evanescent_hare = $start;
+ $return = array();
+
+ // Set evanescent_hare to one past hare
+ // Increment hare two steps
+ while (
+ $tortoise
+ &&
+ ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
+ &&
+ ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
+ ) {
+ if ( $_return_loop )
+ $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
+
+ // tortoise got lapped - must be a loop
+ if ( $tortoise == $evanescent_hare || $tortoise == $hare )
+ return $_return_loop ? $return : $tortoise;
+
+ // Increment tortoise by one step
+ $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
+ }
+
+ return false;
+}
+
+/**
+ * Send a HTTP header to limit rendering of pages to same origin iframes.
+ *
+ * @link https://developer.mozilla.org/en/the_x-frame-options_response_header
+ *
+ * @since 3.1.3
+ * @return none
+ */
+function send_frame_options_header() {
+ @header( 'X-Frame-Options: SAMEORIGIN' );
+}
+
+/**
+ * Retrieve a list of protocols to allow in HTML attributes.
+ *
+ * @since 3.3.0
+ * @see wp_kses()
+ * @see esc_url()
+ *
+ * @return array Array of allowed protocols
+ */
+function wp_allowed_protocols() {
+ static $protocols;
+
+ if ( empty( $protocols ) ) {
+ $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp' );
+ $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
+ }
+
+ return $protocols;
+}
+
+/**
+ * Return a comma separated string of functions that have been called to get to the current point in code.
+ *
+ * @link http://core.trac.wordpress.org/ticket/19589
+ * @since 3.4
+ *
+ * @param string $ignore_class A class to ignore all function calls within - useful when you want to just give info about the callee
+ * @param int $skip_frames A number of stack frames to skip - useful for unwinding back to the source of the issue
+ * @param bool $pretty Whether or not you want a comma separated string or raw array returned
+ * @return string|array Either a string containing a reversed comma separated trace or an array of individual calls.
+ */
+function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
+ if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
+ $trace = debug_backtrace( false );
+ else
+ $trace = debug_backtrace();
+
+ $caller = array();
+ $check_class = ! is_null( $ignore_class );
+ $skip_frames++; // skip this function
+
+ foreach ( $trace as $call ) {
+ if ( $skip_frames > 0 ) {
+ $skip_frames--;
+ } elseif ( isset( $call['class'] ) ) {
+ if ( $check_class && $ignore_class == $call['class'] )
+ continue; // Filter out calls
+
+ $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
+ } else {
+ if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
+ $caller[] = "{$call['function']}('{$call['args'][0]}')";
+ } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
+ $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
+ } else {
+ $caller[] = $call['function'];
+ }
+ }
+ }
+ if ( $pretty )
+ return join( ', ', array_reverse( $caller ) );
+ else
+ return $caller;
+}
+
+/**
+ * Retrieve ids that are not already present in the cache
+ *
+ * @since 3.4.0
+ *
+ * @param array $object_ids ID list
+ * @param string $cache_key The cache bucket to check against
+ *
+ * @return array
+ */
+function _get_non_cached_ids( $object_ids, $cache_key ) {
+ $clean = array();
+ foreach ( $object_ids as $id ) {
+ $id = (int) $id;
+ if ( !wp_cache_get( $id, $cache_key ) ) {
+ $clean[] = $id;
+ }
+ }
+
+ return $clean;
+}
+
+/**
+ * Test if the current device has the capability to upload files.
+ *
+ * @since 3.4.0
+ * @access private
+ *
+ * @return bool true|false
+ */
+function _device_can_upload() {
+ if ( ! wp_is_mobile() )
+ return true;
+
+ $ua = $_SERVER['HTTP_USER_AGENT'];
+
+ if ( strpos($ua, 'iPhone') !== false
+ || strpos($ua, 'iPad') !== false
+ || strpos($ua, 'iPod') !== false ) {
+ return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
+ }
+
+ return true;
+}
+
+/**
+ * Test if a given path is a stream URL
+ *
+ * @param string $path The resource path or URL
+ * @return bool True if the path is a stream URL
+ */
+function wp_is_stream( $path ) {
+ $wrappers = stream_get_wrappers();
+ $wrappers_re = '(' . join('|', $wrappers) . ')';
+
+ return preg_match( "!^$wrappers_re://!", $path ) === 1;
+}
+
+/**
+ * Test if the supplied date is valid for the Gregorian calendar
+ *
+ * @since 3.5.0
+ *
+ * @return bool true|false
+ */
+function wp_checkdate( $month, $day, $year, $source_date ) {
+ return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
+}
+
+/**
+ * Load the auth check for monitoring whether the user is still logged in.
+ *
+ * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
+ *
+ * This is disabled for certain screens where a login screen could cause an
+ * inconvenient interruption. A filter called wp_auth_check_load can be used
+ * for fine-grained control.
+ *
+ * @since 3.6.0
+ */
+function wp_auth_check_load() {
+ if ( ! is_admin() && ! is_user_logged_in() )
+ return;
+
+ if ( defined( 'IFRAME_REQUEST' ) )
+ return;
+
+ $screen = get_current_screen();
+ $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
+ $show = ! in_array( $screen->id, $hidden );
+
+ if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
+ wp_enqueue_style( 'wp-auth-check' );
+ wp_enqueue_script( 'wp-auth-check' );
+
+ add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
+ add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
+ }
+}
+
+/**
+ * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
+ *
+ * @since 3.6.0
+ */
+function wp_auth_check_html() {
+ $login_url = wp_login_url();
+ $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
+ $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
+
+ if ( $same_domain && force_ssl_login() && ! force_ssl_admin() )
+ $same_domain = false;
+
+ // Let plugins change this if they know better.
+ $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
+ $wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
+
+ ?>
+ <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
+ <div id="wp-auth-check-bg"></div>
+ <div id="wp-auth-check">
+ <div class="wp-auth-check-close" tabindex="0" title="<?php esc_attr_e('Close'); ?>"></div>
+ <?php
+
+ if ( $same_domain ) {
+ ?>
+ <div id="wp-auth-check-form" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
+ <?php
+ }
+
+ ?>
+ <div class="wp-auth-fallback">
+ <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
+ <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
+ <?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
+ </div>
+ </div>
+ </div>
+ <?php
+}
+
+/**
+ * Check whether a user is still logged in, for the heartbeat.
+ *
+ * Send a result that shows a log-in box if the user is no longer logged in,
+ * or if their cookie is within the grace period.
+ *
+ * @since 3.6.0
+ */
+function wp_auth_check( $response, $data ) {
+ $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
+ return $response;
+}
+
+/**
+ * Return RegEx body to liberally match an opening HTML tag that:
+ * 1. Is self-closing or
+ * 2. Has no body but has a closing tag of the same name or
+ * 3. Contains a body and a closing tag of the same name
+ *
+ * Note: this RegEx does not balance inner tags and does not attempt to produce valid HTML
+ *
+ * @since 3.6.0
+ *
+ * @param string $tag An HTML tag name. Example: 'video'
+ * @return string
+ */
+function get_tag_regex( $tag ) {
+ if ( empty( $tag ) )
+ return;
+ return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
+}
+
+/**
+ * Return a canonical form of the provided charset appropriate for passing to PHP
+ * functions such as htmlspecialchars() and charset html attributes.
+ *
+ * @link http://core.trac.wordpress.org/ticket/23688
+ * @since 3.6.0
+ *
+ * @param string A charset name
+ * @return string The canonical form of the charset
+ */
+function _canonical_charset( $charset ) {
+ if ( 'UTF-8' === $charset || 'utf-8' === $charset || 'utf8' === $charset ||
+ 'UTF8' === $charset )
+ return 'UTF-8';
+
+ if ( 'ISO-8859-1' === $charset || 'iso-8859-1' === $charset ||
+ 'iso8859-1' === $charset || 'ISO8859-1' === $charset )
+ return 'ISO-8859-1';
+
+ return $charset;
+}
diff --git a/src/wp-includes/functions.wp-scripts.php b/src/wp-includes/functions.wp-scripts.php
new file mode 100644
index 0000000000..32778ab5a2
--- /dev/null
+++ b/src/wp-includes/functions.wp-scripts.php
@@ -0,0 +1,205 @@
+<?php
+/**
+ * BackPress script procedural API.
+ *
+ * @package BackPress
+ * @since r16
+ */
+
+/**
+ * Prints script tags in document head.
+ *
+ * Called by admin-header.php and by wp_head hook. Since it is called by wp_head
+ * on every page load, the function does not instantiate the WP_Scripts object
+ * unless script names are explicitly passed. Does make use of already
+ * instantiated $wp_scripts if present. Use provided wp_print_scripts hook to
+ * register/enqueue new scripts.
+ *
+ * @since r16
+ * @see WP_Dependencies::print_scripts()
+ */
+function wp_print_scripts( $handles = false ) {
+ do_action( 'wp_print_scripts' );
+ if ( '' === $handles ) // for wp_head
+ $handles = false;
+
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+
+ if ( !$handles )
+ return array(); // No need to instantiate if nothing is there.
+ else
+ $wp_scripts = new WP_Scripts();
+ }
+
+ return $wp_scripts->do_items( $handles );
+}
+
+/**
+ * Register new Javascript file.
+ *
+ * @since r16
+ * @param string $handle Script name
+ * @param string $src Script url
+ * @param array $deps (optional) Array of script names on which this script depends
+ * @param string|bool $ver (optional) Script version (used for cache busting), set to null to disable
+ * @param bool $in_footer (optional) Whether to enqueue the script before </head> or before </body>
+ * @return null
+ */
+function wp_register_script( $handle, $src, $deps = array(), $ver = false, $in_footer = false ) {
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_scripts = new WP_Scripts();
+ }
+
+ $wp_scripts->add( $handle, $src, $deps, $ver );
+ if ( $in_footer )
+ $wp_scripts->add_data( $handle, 'group', 1 );
+}
+
+/**
+ * Wrapper for $wp_scripts->localize().
+ *
+ * Used to localize a script.
+ * Works only if the script has already been added.
+ * Accepts an associative array $l10n and creates JS object:
+ * "$object_name" = {
+ * key: value,
+ * key: value,
+ * ...
+ * }
+ * See http://core.trac.wordpress.org/ticket/11520 for more information.
+ *
+ * @since r16
+ *
+ * @param string $handle The script handle that was registered or used in script-loader
+ * @param string $object_name Name for the created JS object. This is passed directly so it should be qualified JS variable /[a-zA-Z0-9_]+/
+ * @param array $l10n Associative PHP array containing the translated strings. HTML entities will be converted and the array will be JSON encoded.
+ * @return bool Whether the localization was added successfully.
+ */
+function wp_localize_script( $handle, $object_name, $l10n ) {
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+
+ return false;
+ }
+
+ return $wp_scripts->localize( $handle, $object_name, $l10n );
+}
+
+/**
+ * Remove a registered script.
+ *
+ * @since r16
+ * @see WP_Scripts::remove() For parameter information.
+ */
+function wp_deregister_script( $handle ) {
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_scripts = new WP_Scripts();
+ }
+
+ // Do not allow accidental or negligent deregistering of critical scripts in the admin. Show minimal remorse if the correct hook is used.
+ if ( is_admin() && 'admin_enqueue_scripts' !== current_filter() ) {
+ $no = array(
+ 'jquery', 'jquery-core', 'jquery-migrate', 'jquery-ui-core', 'jquery-ui-accordion',
+ 'jquery-ui-autocomplete', 'jquery-ui-button', 'jquery-ui-datepicker', 'jquery-ui-dialog',
+ 'jquery-ui-draggable', 'jquery-ui-droppable', 'jquery-ui-menu', 'jquery-ui-mouse',
+ 'jquery-ui-position', 'jquery-ui-progressbar', 'jquery-ui-resizable', 'jquery-ui-selectable',
+ 'jquery-ui-slider', 'jquery-ui-sortable', 'jquery-ui-spinner', 'jquery-ui-tabs',
+ 'jquery-ui-tooltip', 'jquery-ui-widget',
+ 'underscore', 'backbone',
+ );
+
+ if ( in_array( $handle, $no ) ) {
+ $message = sprintf( __( 'Do not deregister the %1$s script in the administration area. To target the frontend theme, use the %2$s hook.' ),
+ "<code>$handle</code>", '<code>wp_enqueue_scripts</code>' );
+ _doing_it_wrong( __FUNCTION__, $message, '3.6' );
+ return;
+ }
+ }
+
+ $wp_scripts->remove( $handle );
+}
+
+/**
+ * Enqueues script.
+ *
+ * Registers the script if src provided (does NOT overwrite) and enqueues.
+ *
+ * @since r16
+ * @see wp_register_script() For parameter information.
+ */
+function wp_enqueue_script( $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) {
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_scripts = new WP_Scripts();
+ }
+
+ if ( $src ) {
+ $_handle = explode('?', $handle);
+ $wp_scripts->add( $_handle[0], $src, $deps, $ver );
+ if ( $in_footer )
+ $wp_scripts->add_data( $_handle[0], 'group', 1 );
+ }
+ $wp_scripts->enqueue( $handle );
+}
+
+/**
+ * Remove an enqueued script.
+ *
+ * @since WP 3.1
+ * @see WP_Scripts::dequeue() For parameter information.
+ */
+function wp_dequeue_script( $handle ) {
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_scripts = new WP_Scripts();
+ }
+
+ $wp_scripts->dequeue( $handle );
+}
+
+/**
+ * Check whether script has been added to WordPress Scripts.
+ *
+ * By default, checks if the script has been enqueued. You can also
+ * pass 'registered' to $list, to see if the script is registered,
+ * and you can check processing statuses with 'to_do' and 'done'.
+ *
+ * @since WP unknown; BP unknown
+ *
+ * @param string $handle Name of the script.
+ * @param string $list Optional. Defaults to 'enqueued'. Values are
+ * 'registered', 'enqueued' (or 'queue'), 'to_do', and 'done'.
+ * @return bool Whether script is in the list.
+ */
+function wp_script_is( $handle, $list = 'enqueued' ) {
+ global $wp_scripts;
+ if ( ! is_a( $wp_scripts, 'WP_Scripts' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_scripts = new WP_Scripts();
+ }
+
+ return (bool) $wp_scripts->query( $handle, $list );
+}
diff --git a/src/wp-includes/functions.wp-styles.php b/src/wp-includes/functions.wp-styles.php
new file mode 100644
index 0000000000..617fd8241d
--- /dev/null
+++ b/src/wp-includes/functions.wp-styles.php
@@ -0,0 +1,218 @@
+<?php
+/**
+ * BackPress styles procedural API.
+ *
+ * @package BackPress
+ * @since r79
+ */
+
+/**
+ * Display styles that are in the queue or part of $handles.
+ *
+ * @since r79
+ * @uses do_action() Calls 'wp_print_styles' hook.
+ * @global object $wp_styles The WP_Styles object for printing styles.
+ *
+ * @param array|bool $handles Styles to be printed. An empty array prints the queue,
+ * an array with one string prints that style, and an array of strings prints those styles.
+ * @return bool True on success, false on failure.
+ */
+function wp_print_styles( $handles = false ) {
+ if ( '' === $handles ) // for wp_head
+ $handles = false;
+
+ if ( ! $handles )
+ do_action( 'wp_print_styles' );
+
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+
+ if ( !$handles )
+ return array(); // No need to instantiate if nothing is there.
+ else
+ $wp_styles = new WP_Styles();
+ }
+
+ return $wp_styles->do_items( $handles );
+}
+
+/**
+ * Adds extra CSS.
+ *
+ * Works only if the stylesheet has already been added.
+ * Accepts a string $data containing the CSS. If two or more CSS code blocks are
+ * added to the same stylesheet $handle, they will be printed in the order
+ * they were added, i.e. the latter added styles can redeclare the previous.
+ *
+ * @since 3.3.0
+ * @see WP_Scripts::add_inline_style()
+ */
+function wp_add_inline_style( $handle, $data ) {
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_styles = new WP_Styles();
+ }
+
+ return $wp_styles->add_inline_style( $handle, $data );
+}
+
+/**
+ * Register CSS style file.
+ *
+ * @since r79
+ * @see WP_Styles::add() For additional information.
+ * @global object $wp_styles The WP_Styles object for printing styles.
+ * @link http://www.w3.org/TR/CSS2/media.html#media-types List of CSS media types.
+ *
+ * @param string $handle Name of the stylesheet.
+ * @param string|bool $src Path to the stylesheet from the root directory of WordPress. Example: '/css/mystyle.css'.
+ * @param array $deps Array of handles of any stylesheet that this stylesheet depends on.
+ * (Stylesheets that must be loaded before this stylesheet.) Pass an empty array if there are no dependencies.
+ * @param string|bool $ver String specifying the stylesheet version number. Set to null to disable.
+ * Used to ensure that the correct version is sent to the client regardless of caching.
+ * @param string $media The media for which this stylesheet has been defined.
+ */
+function wp_register_style( $handle, $src, $deps = array(), $ver = false, $media = 'all' ) {
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_styles = new WP_Styles();
+ }
+
+ $wp_styles->add( $handle, $src, $deps, $ver, $media );
+}
+
+/**
+ * Remove a registered CSS file.
+ *
+ * @since r79
+ * @see WP_Styles::remove() For additional information.
+ * @global object $wp_styles The WP_Styles object for printing styles.
+ *
+ * @param string $handle Name of the stylesheet.
+ */
+function wp_deregister_style( $handle ) {
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_styles = new WP_Styles();
+ }
+
+ $wp_styles->remove( $handle );
+}
+
+/**
+ * Enqueue a CSS style file.
+ *
+ * Registers the style if src provided (does NOT overwrite) and enqueues.
+ *
+ * @since r79
+ * @see WP_Styles::add(), WP_Styles::enqueue()
+ * @global object $wp_styles The WP_Styles object for printing styles.
+ * @link http://www.w3.org/TR/CSS2/media.html#media-types List of CSS media types.
+ *
+ * @param string $handle Name of the stylesheet.
+ * @param string|bool $src Path to the stylesheet from the root directory of WordPress. Example: '/css/mystyle.css'.
+ * @param array $deps Array of handles (names) of any stylesheet that this stylesheet depends on.
+ * (Stylesheets that must be loaded before this stylesheet.) Pass an empty array if there are no dependencies.
+ * @param string|bool $ver String specifying the stylesheet version number, if it has one. This parameter
+ * is used to ensure that the correct version is sent to the client regardless of caching, and so should be included
+ * if a version number is available and makes sense for the stylesheet.
+ * @param string $media The media for which this stylesheet has been defined.
+ */
+function wp_enqueue_style( $handle, $src = false, $deps = array(), $ver = false, $media = 'all' ) {
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_styles = new WP_Styles();
+ }
+
+ if ( $src ) {
+ $_handle = explode('?', $handle);
+ $wp_styles->add( $_handle[0], $src, $deps, $ver, $media );
+ }
+ $wp_styles->enqueue( $handle );
+}
+
+/**
+ * Remove an enqueued style.
+ *
+ * @since WP 3.1
+ * @see WP_Styles::dequeue() For parameter information.
+ */
+function wp_dequeue_style( $handle ) {
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_styles = new WP_Styles();
+ }
+
+ $wp_styles->dequeue( $handle );
+}
+
+/**
+ * Check whether style has been added to WordPress Styles.
+ *
+ * By default, checks if the style has been enqueued. You can also
+ * pass 'registered' to $list, to see if the style is registered,
+ * and you can check processing statuses with 'to_do' and 'done'.
+ *
+ * @since WP unknown; BP unknown
+ * @global object $wp_styles The WP_Styles object for printing styles.
+ *
+ * @param string $handle Name of the stylesheet.
+ * @param string $list Optional. Defaults to 'enqueued'. Values are
+ * 'registered', 'enqueued' (or 'queue'), 'to_do', and 'done'.
+ * @return bool Whether style is in the list.
+ */
+function wp_style_is( $handle, $list = 'enqueued' ) {
+ global $wp_styles;
+ if ( ! is_a( $wp_styles, 'WP_Styles' ) ) {
+ if ( ! did_action( 'init' ) )
+ _doing_it_wrong( __FUNCTION__, sprintf( __( 'Scripts and styles should not be registered or enqueued until the %1$s, %2$s, or %3$s hooks.' ),
+ '<code>wp_enqueue_scripts</code>', '<code>admin_enqueue_scripts</code>', '<code>login_enqueue_scripts</code>' ), '3.3' );
+ $wp_styles = new WP_Styles();
+ }
+
+ return (bool) $wp_styles->query( $handle, $list );
+}
+
+/**
+ * Add metadata to CSS style files.
+ *
+ * Works only if the stylesheet has already been added.
+ * Possible values for $key and $value:
+ *
+ * conditional string comments for IE 6, lte IE 7 etc.
+ * rtl bool|string to declare an RTL stylesheet
+ * suffix string optional suffix, used in combination with RTL
+ * alt bool for rel="alternate stylesheet"
+ * title string for preferred/alternate stylesheets
+ *
+ * @since 3.6.0
+ * @see WP_Dependencies::add_data()
+ *
+ * @param string $handle Script name.
+ * @param string $key Name of data point for which we're storing a value.
+ * Values are 'conditional', 'rtl', and 'suffix', and 'alt', 'title'.
+ * @param mixed $data
+ * @return bool True on success, false on failure.
+ */
+function wp_style_add_data( $handle, $key, $value ) {
+ global $wp_styles;
+ return $wp_styles->add_data( $handle, $key, $value );
+}
diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php
new file mode 100644
index 0000000000..b586762473
--- /dev/null
+++ b/src/wp-includes/general-template.php
@@ -0,0 +1,2339 @@
+<?php
+/**
+ * General template tags that can go anywhere in a template.
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Load header template.
+ *
+ * Includes the header template for a theme or if a name is specified then a
+ * specialised header will be included.
+ *
+ * For the parameter, if the file is called "header-special.php" then specify
+ * "special".
+ *
+ * @uses locate_template()
+ * @since 1.5.0
+ * @uses do_action() Calls 'get_header' action.
+ *
+ * @param string $name The name of the specialised header.
+ */
+function get_header( $name = null ) {
+ do_action( 'get_header', $name );
+
+ $templates = array();
+ $name = (string) $name;
+ if ( '' !== $name )
+ $templates[] = "header-{$name}.php";
+
+ $templates[] = 'header.php';
+
+ // Backward compat code will be removed in a future release
+ if ('' == locate_template($templates, true))
+ load_template( ABSPATH . WPINC . '/theme-compat/header.php');
+}
+
+/**
+ * Load footer template.
+ *
+ * Includes the footer template for a theme or if a name is specified then a
+ * specialised footer will be included.
+ *
+ * For the parameter, if the file is called "footer-special.php" then specify
+ * "special".
+ *
+ * @uses locate_template()
+ * @since 1.5.0
+ * @uses do_action() Calls 'get_footer' action.
+ *
+ * @param string $name The name of the specialised footer.
+ */
+function get_footer( $name = null ) {
+ do_action( 'get_footer', $name );
+
+ $templates = array();
+ $name = (string) $name;
+ if ( '' !== $name )
+ $templates[] = "footer-{$name}.php";
+
+ $templates[] = 'footer.php';
+
+ // Backward compat code will be removed in a future release
+ if ('' == locate_template($templates, true))
+ load_template( ABSPATH . WPINC . '/theme-compat/footer.php');
+}
+
+/**
+ * Load sidebar template.
+ *
+ * Includes the sidebar template for a theme or if a name is specified then a
+ * specialised sidebar will be included.
+ *
+ * For the parameter, if the file is called "sidebar-special.php" then specify
+ * "special".
+ *
+ * @uses locate_template()
+ * @since 1.5.0
+ * @uses do_action() Calls 'get_sidebar' action.
+ *
+ * @param string $name The name of the specialised sidebar.
+ */
+function get_sidebar( $name = null ) {
+ do_action( 'get_sidebar', $name );
+
+ $templates = array();
+ $name = (string) $name;
+ if ( '' !== $name )
+ $templates[] = "sidebar-{$name}.php";
+
+ $templates[] = 'sidebar.php';
+
+ // Backward compat code will be removed in a future release
+ if ('' == locate_template($templates, true))
+ load_template( ABSPATH . WPINC . '/theme-compat/sidebar.php');
+}
+
+/**
+ * Load a template part into a template
+ *
+ * Makes it easy for a theme to reuse sections of code in a easy to overload way
+ * for child themes.
+ *
+ * Includes the named template part for a theme or if a name is specified then a
+ * specialised part will be included. If the theme contains no {slug}.php file
+ * then no template will be included.
+ *
+ * The template is included using require, not require_once, so you may include the
+ * same template part multiple times.
+ *
+ * For the $name parameter, if the file is called "{slug}-special.php" then specify
+ * "special".
+ *
+ * @uses locate_template()
+ * @since 3.0.0
+ * @uses do_action() Calls 'get_template_part_{$slug}' action.
+ *
+ * @param string $slug The slug name for the generic template.
+ * @param string $name The name of the specialised template.
+ */
+function get_template_part( $slug, $name = null ) {
+ do_action( "get_template_part_{$slug}", $slug, $name );
+
+ $templates = array();
+ $name = (string) $name;
+ if ( '' !== $name )
+ $templates[] = "{$slug}-{$name}.php";
+
+ $templates[] = "{$slug}.php";
+
+ locate_template($templates, true, false);
+}
+
+/**
+ * Display search form.
+ *
+ * Will first attempt to locate the searchform.php file in either the child or
+ * the parent, then load it. If it doesn't exist, then the default search form
+ * will be displayed. The default search form is HTML, which will be displayed.
+ * There is a filter applied to the search form HTML in order to edit or replace
+ * it. The filter is 'get_search_form'.
+ *
+ * This function is primarily used by themes which want to hardcode the search
+ * form into the sidebar and also by the search widget in WordPress.
+ *
+ * There is also an action that is called whenever the function is run called,
+ * 'pre_get_search_form'. This can be useful for outputting JavaScript that the
+ * search relies on or various formatting that applies to the beginning of the
+ * search. To give a few examples of what it can be used for.
+ *
+ * @since 2.7.0
+ * @uses apply_filters() Calls 'search_form_format' filter to determine which type to use for the search field.
+ * If set to 'html5', it changes to search input type and adds placeholder text.
+ *
+ * @param boolean $echo Default to echo and not return the form.
+ * @return string|null String when retrieving, null when displaying or if searchform.php exists.
+ */
+function get_search_form( $echo = true ) {
+ do_action( 'pre_get_search_form' );
+
+ $format = current_theme_supports( 'html5', 'search-form' ) ? 'html5' : 'xhtml';
+ $format = apply_filters( 'search_form_format', $format );
+
+ $search_form_template = locate_template( 'searchform.php' );
+ if ( '' != $search_form_template ) {
+ ob_start();
+ require( $search_form_template );
+ $form = ob_get_clean();
+ } else {
+ if ( 'html5' == $format ) {
+ $form = '<form role="search" method="get" class="search-form" action="' . esc_url( home_url( '/' ) ) . '">
+ <label>
+ <span class="screen-reader-text">' . _x( 'Search for:', 'label' ) . '</span>
+ <input type="search" class="search-field" placeholder="' . esc_attr_x( 'Search &hellip;', 'placeholder' ) . '" value="' . get_search_query() . '" name="s" title="' . _x( 'Search for:', 'label' ) . '" />
+ </label>
+ <input type="submit" class="search-submit" value="'. esc_attr_x( 'Search', 'submit button' ) .'" />
+ </form>';
+ } else {
+ $form = '<form role="search" method="get" id="searchform" class="searchform" action="' . esc_url( home_url( '/' ) ) . '">
+ <div>
+ <label class="screen-reader-text" for="s">' . _x( 'Search for:', 'label' ) . '</label>
+ <input type="text" value="' . get_search_query() . '" name="s" id="s" />
+ <input type="submit" id="searchsubmit" value="'. esc_attr_x( 'Search', 'submit button' ) .'" />
+ </div>
+ </form>';
+ }
+ }
+
+ $result = apply_filters( 'get_search_form', $form );
+ if ( null === $result )
+ $result = $form;
+
+ if ( $echo )
+ echo $result;
+ else
+ return $result;
+}
+
+/**
+ * Display the Log In/Out link.
+ *
+ * Displays a link, which allows users to navigate to the Log In page to log in
+ * or log out depending on whether they are currently logged in.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'loginout' hook on HTML link content.
+ *
+ * @param string $redirect Optional path to redirect to on login/logout.
+ * @param boolean $echo Default to echo and not return the link.
+ * @return string|null String when retrieving, null when displaying.
+ */
+function wp_loginout($redirect = '', $echo = true) {
+ if ( ! is_user_logged_in() )
+ $link = '<a href="' . esc_url( wp_login_url($redirect) ) . '">' . __('Log in') . '</a>';
+ else
+ $link = '<a href="' . esc_url( wp_logout_url($redirect) ) . '">' . __('Log out') . '</a>';
+
+ if ( $echo )
+ echo apply_filters('loginout', $link);
+ else
+ return apply_filters('loginout', $link);
+}
+
+/**
+ * Returns the Log Out URL.
+ *
+ * Returns the URL that allows the user to log out of the site.
+ *
+ * @since 2.7.0
+ * @uses wp_nonce_url() To protect against CSRF.
+ * @uses site_url() To generate the log out URL.
+ * @uses apply_filters() calls 'logout_url' hook on final logout URL.
+ *
+ * @param string $redirect Path to redirect to on logout.
+ * @return string A log out URL.
+ */
+function wp_logout_url($redirect = '') {
+ $args = array( 'action' => 'logout' );
+ if ( !empty($redirect) ) {
+ $args['redirect_to'] = urlencode( $redirect );
+ }
+
+ $logout_url = add_query_arg($args, site_url('wp-login.php', 'login'));
+ $logout_url = wp_nonce_url( $logout_url, 'log-out' );
+
+ return apply_filters('logout_url', $logout_url, $redirect);
+}
+
+/**
+ * Returns the Log In URL.
+ *
+ * Returns the URL that allows the user to log in to the site.
+ *
+ * @since 2.7.0
+ * @uses site_url() To generate the log in URL.
+ * @uses apply_filters() calls 'login_url' hook on final login URL.
+ *
+ * @param string $redirect Path to redirect to on login.
+ * @param bool $force_reauth Whether to force reauthorization, even if a cookie is present. Default is false.
+ * @return string A log in URL.
+ */
+function wp_login_url($redirect = '', $force_reauth = false) {
+ $login_url = site_url('wp-login.php', 'login');
+
+ if ( !empty($redirect) )
+ $login_url = add_query_arg('redirect_to', urlencode($redirect), $login_url);
+
+ if ( $force_reauth )
+ $login_url = add_query_arg('reauth', '1', $login_url);
+
+ return apply_filters('login_url', $login_url, $redirect);
+}
+
+/**
+ * Returns the user registration URL.
+ *
+ * Returns the URL that allows the user to register on the site.
+ *
+ * @since 3.6.0
+ * @uses site_url() To generate the registration URL.
+ * @uses apply_filters() calls 'register_url' hook on final URL.
+ *
+ * @return string
+ */
+function wp_registration_url() {
+ return apply_filters( 'register_url', site_url( 'wp-login.php?action=register', 'login' ) );
+}
+
+/**
+ * Provides a simple login form for use anywhere within WordPress. By default, it echoes
+ * the HTML immediately. Pass array('echo'=>false) to return the string instead.
+ *
+ * @since 3.0.0
+ * @param array $args Configuration options to modify the form output.
+ * @return string|null String when retrieving, null when displaying.
+ */
+function wp_login_form( $args = array() ) {
+ $defaults = array(
+ 'echo' => true,
+ 'redirect' => ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], // Default redirect is back to the current page
+ 'form_id' => 'loginform',
+ 'label_username' => __( 'Username' ),
+ 'label_password' => __( 'Password' ),
+ 'label_remember' => __( 'Remember Me' ),
+ 'label_log_in' => __( 'Log In' ),
+ 'id_username' => 'user_login',
+ 'id_password' => 'user_pass',
+ 'id_remember' => 'rememberme',
+ 'id_submit' => 'wp-submit',
+ 'remember' => true,
+ 'value_username' => '',
+ 'value_remember' => false, // Set this to true to default the "Remember me" checkbox to checked
+ );
+ $args = wp_parse_args( $args, apply_filters( 'login_form_defaults', $defaults ) );
+
+ $form = '
+ <form name="' . $args['form_id'] . '" id="' . $args['form_id'] . '" action="' . esc_url( site_url( 'wp-login.php', 'login_post' ) ) . '" method="post">
+ ' . apply_filters( 'login_form_top', '', $args ) . '
+ <p class="login-username">
+ <label for="' . esc_attr( $args['id_username'] ) . '">' . esc_html( $args['label_username'] ) . '</label>
+ <input type="text" name="log" id="' . esc_attr( $args['id_username'] ) . '" class="input" value="' . esc_attr( $args['value_username'] ) . '" size="20" />
+ </p>
+ <p class="login-password">
+ <label for="' . esc_attr( $args['id_password'] ) . '">' . esc_html( $args['label_password'] ) . '</label>
+ <input type="password" name="pwd" id="' . esc_attr( $args['id_password'] ) . '" class="input" value="" size="20" />
+ </p>
+ ' . apply_filters( 'login_form_middle', '', $args ) . '
+ ' . ( $args['remember'] ? '<p class="login-remember"><label><input name="rememberme" type="checkbox" id="' . esc_attr( $args['id_remember'] ) . '" value="forever"' . ( $args['value_remember'] ? ' checked="checked"' : '' ) . ' /> ' . esc_html( $args['label_remember'] ) . '</label></p>' : '' ) . '
+ <p class="login-submit">
+ <input type="submit" name="wp-submit" id="' . esc_attr( $args['id_submit'] ) . '" class="button-primary" value="' . esc_attr( $args['label_log_in'] ) . '" />
+ <input type="hidden" name="redirect_to" value="' . esc_url( $args['redirect'] ) . '" />
+ </p>
+ ' . apply_filters( 'login_form_bottom', '', $args ) . '
+ </form>';
+
+ if ( $args['echo'] )
+ echo $form;
+ else
+ return $form;
+}
+
+/**
+ * Returns the Lost Password URL.
+ *
+ * Returns the URL that allows the user to retrieve the lost password
+ *
+ * @since 2.8.0
+ * @uses site_url() To generate the lost password URL
+ * @uses apply_filters() calls 'lostpassword_url' hook on the lostpassword url
+ *
+ * @param string $redirect Path to redirect to on login.
+ * @return string Lost password URL.
+ */
+function wp_lostpassword_url( $redirect = '' ) {
+ $args = array( 'action' => 'lostpassword' );
+ if ( !empty($redirect) ) {
+ $args['redirect_to'] = $redirect;
+ }
+
+ $lostpassword_url = add_query_arg( $args, network_site_url('wp-login.php', 'login') );
+ return apply_filters( 'lostpassword_url', $lostpassword_url, $redirect );
+}
+
+/**
+ * Display the Registration or Admin link.
+ *
+ * Display a link which allows the user to navigate to the registration page if
+ * not logged in and registration is enabled or to the dashboard if logged in.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'register' hook on register / admin link content.
+ *
+ * @param string $before Text to output before the link (defaults to <li>).
+ * @param string $after Text to output after the link (defaults to </li>).
+ * @param boolean $echo Default to echo and not return the link.
+ * @return string|null String when retrieving, null when displaying.
+ */
+function wp_register( $before = '<li>', $after = '</li>', $echo = true ) {
+
+ if ( ! is_user_logged_in() ) {
+ if ( get_option('users_can_register') )
+ $link = $before . '<a href="' . esc_url( wp_registration_url() ) . '">' . __('Register') . '</a>' . $after;
+ else
+ $link = '';
+ } else {
+ $link = $before . '<a href="' . admin_url() . '">' . __('Site Admin') . '</a>' . $after;
+ }
+
+ if ( $echo )
+ echo apply_filters('register', $link);
+ else
+ return apply_filters('register', $link);
+}
+
+/**
+ * Theme container function for the 'wp_meta' action.
+ *
+ * The 'wp_meta' action can have several purposes, depending on how you use it,
+ * but one purpose might have been to allow for theme switching.
+ *
+ * @since 1.5.0
+ * @link http://trac.wordpress.org/ticket/1458 Explanation of 'wp_meta' action.
+ * @uses do_action() Calls 'wp_meta' hook.
+ */
+function wp_meta() {
+ do_action('wp_meta');
+}
+
+/**
+ * Display information about the blog.
+ *
+ * @see get_bloginfo() For possible values for the parameter.
+ * @since 0.71
+ *
+ * @param string $show What to display.
+ */
+function bloginfo( $show='' ) {
+ echo get_bloginfo( $show, 'display' );
+}
+
+/**
+ * Retrieve information about the blog.
+ *
+ * Some show parameter values are deprecated and will be removed in future
+ * versions. These options will trigger the _deprecated_argument() function.
+ * The deprecated blog info options are listed in the function contents.
+ *
+ * The possible values for the 'show' parameter are listed below.
+ * <ol>
+ * <li><strong>url</strong> - Blog URI to homepage.</li>
+ * <li><strong>wpurl</strong> - Blog URI path to WordPress.</li>
+ * <li><strong>description</strong> - Secondary title</li>
+ * </ol>
+ *
+ * The feed URL options can be retrieved from 'rdf_url' (RSS 0.91),
+ * 'rss_url' (RSS 1.0), 'rss2_url' (RSS 2.0), or 'atom_url' (Atom feed). The
+ * comment feeds can be retrieved from the 'comments_atom_url' (Atom comment
+ * feed) or 'comments_rss2_url' (RSS 2.0 comment feed).
+ *
+ * @since 0.71
+ *
+ * @param string $show Blog info to retrieve.
+ * @param string $filter How to filter what is retrieved.
+ * @return string Mostly string values, might be empty.
+ */
+function get_bloginfo( $show = '', $filter = 'raw' ) {
+
+ switch( $show ) {
+ case 'home' : // DEPRECATED
+ case 'siteurl' : // DEPRECATED
+ _deprecated_argument( __FUNCTION__, '2.2', sprintf( __('The <code>%s</code> option is deprecated for the family of <code>bloginfo()</code> functions.' ), $show ) . ' ' . sprintf( __( 'Use the <code>%s</code> option instead.' ), 'url' ) );
+ case 'url' :
+ $output = home_url();
+ break;
+ case 'wpurl' :
+ $output = site_url();
+ break;
+ case 'description':
+ $output = get_option('blogdescription');
+ break;
+ case 'rdf_url':
+ $output = get_feed_link('rdf');
+ break;
+ case 'rss_url':
+ $output = get_feed_link('rss');
+ break;
+ case 'rss2_url':
+ $output = get_feed_link('rss2');
+ break;
+ case 'atom_url':
+ $output = get_feed_link('atom');
+ break;
+ case 'comments_atom_url':
+ $output = get_feed_link('comments_atom');
+ break;
+ case 'comments_rss2_url':
+ $output = get_feed_link('comments_rss2');
+ break;
+ case 'pingback_url':
+ $output = get_option('siteurl') .'/xmlrpc.php';
+ break;
+ case 'stylesheet_url':
+ $output = get_stylesheet_uri();
+ break;
+ case 'stylesheet_directory':
+ $output = get_stylesheet_directory_uri();
+ break;
+ case 'template_directory':
+ case 'template_url':
+ $output = get_template_directory_uri();
+ break;
+ case 'admin_email':
+ $output = get_option('admin_email');
+ break;
+ case 'charset':
+ $output = get_option('blog_charset');
+ if ('' == $output) $output = 'UTF-8';
+ break;
+ case 'html_type' :
+ $output = get_option('html_type');
+ break;
+ case 'version':
+ global $wp_version;
+ $output = $wp_version;
+ break;
+ case 'language':
+ $output = get_locale();
+ $output = str_replace('_', '-', $output);
+ break;
+ case 'text_direction':
+ //_deprecated_argument( __FUNCTION__, '2.2', sprintf( __('The <code>%s</code> option is deprecated for the family of <code>bloginfo()</code> functions.' ), $show ) . ' ' . sprintf( __( 'Use the <code>%s</code> function instead.' ), 'is_rtl()' ) );
+ if ( function_exists( 'is_rtl' ) ) {
+ $output = is_rtl() ? 'rtl' : 'ltr';
+ } else {
+ $output = 'ltr';
+ }
+ break;
+ case 'name':
+ default:
+ $output = get_option('blogname');
+ break;
+ }
+
+ $url = true;
+ if (strpos($show, 'url') === false &&
+ strpos($show, 'directory') === false &&
+ strpos($show, 'home') === false)
+ $url = false;
+
+ if ( 'display' == $filter ) {
+ if ( $url )
+ $output = apply_filters('bloginfo_url', $output, $show);
+ else
+ $output = apply_filters('bloginfo', $output, $show);
+ }
+
+ return $output;
+}
+
+/**
+ * Display or retrieve page title for all areas of blog.
+ *
+ * By default, the page title will display the separator before the page title,
+ * so that the blog title will be before the page title. This is not good for
+ * title display, since the blog title shows up on most tabs and not what is
+ * important, which is the page that the user is looking at.
+ *
+ * There are also SEO benefits to having the blog title after or to the 'right'
+ * or the page title. However, it is mostly common sense to have the blog title
+ * to the right with most browsers supporting tabs. You can achieve this by
+ * using the seplocation parameter and setting the value to 'right'. This change
+ * was introduced around 2.5.0, in case backwards compatibility of themes is
+ * important.
+ *
+ * @since 1.0.0
+ *
+ * @param string $sep Optional, default is '&raquo;'. How to separate the various items within the page title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @param string $seplocation Optional. Direction to display title, 'right'.
+ * @return string|null String on retrieve, null when displaying.
+ */
+function wp_title($sep = '&raquo;', $display = true, $seplocation = '') {
+ global $wpdb, $wp_locale;
+
+ $m = get_query_var('m');
+ $year = get_query_var('year');
+ $monthnum = get_query_var('monthnum');
+ $day = get_query_var('day');
+ $search = get_query_var('s');
+ $title = '';
+
+ $t_sep = '%WP_TITILE_SEP%'; // Temporary separator, for accurate flipping, if necessary
+
+ // If there is a post
+ if ( is_single() || ( is_home() && !is_front_page() ) || ( is_page() && !is_front_page() ) ) {
+ $title = single_post_title( '', false );
+ }
+
+ // If there's a category or tag
+ if ( is_category() || is_tag() ) {
+ $title = single_term_title( '', false );
+ }
+
+ // If there's a taxonomy
+ if ( is_tax() ) {
+ $term = get_queried_object();
+ $tax = get_taxonomy( $term->taxonomy );
+ $title = single_term_title( $tax->labels->name . $t_sep, false );
+ }
+
+ // If there's an author
+ if ( is_author() ) {
+ $author = get_queried_object();
+ $title = $author->display_name;
+ }
+
+ // If there's a post type archive
+ if ( is_post_type_archive() )
+ $title = post_type_archive_title( '', false );
+
+ // If there's a month
+ if ( is_archive() && !empty($m) ) {
+ $my_year = substr($m, 0, 4);
+ $my_month = $wp_locale->get_month(substr($m, 4, 2));
+ $my_day = intval(substr($m, 6, 2));
+ $title = $my_year . ( $my_month ? $t_sep . $my_month : '' ) . ( $my_day ? $t_sep . $my_day : '' );
+ }
+
+ // If there's a year
+ if ( is_archive() && !empty($year) ) {
+ $title = $year;
+ if ( !empty($monthnum) )
+ $title .= $t_sep . $wp_locale->get_month($monthnum);
+ if ( !empty($day) )
+ $title .= $t_sep . zeroise($day, 2);
+ }
+
+ // If it's a search
+ if ( is_search() ) {
+ /* translators: 1: separator, 2: search phrase */
+ $title = sprintf(__('Search Results %1$s %2$s'), $t_sep, strip_tags($search));
+ }
+
+ // If it's a 404 page
+ if ( is_404() ) {
+ $title = __('Page not found');
+ }
+
+ $prefix = '';
+ if ( !empty($title) )
+ $prefix = " $sep ";
+
+ // Determines position of the separator and direction of the breadcrumb
+ if ( 'right' == $seplocation ) { // sep on right, so reverse the order
+ $title_array = explode( $t_sep, $title );
+ $title_array = array_reverse( $title_array );
+ $title = implode( " $sep ", $title_array ) . $prefix;
+ } else {
+ $title_array = explode( $t_sep, $title );
+ $title = $prefix . implode( " $sep ", $title_array );
+ }
+
+ $title = apply_filters('wp_title', $title, $sep, $seplocation);
+
+ // Send it out
+ if ( $display )
+ echo $title;
+ else
+ return $title;
+
+}
+
+/**
+ * Display or retrieve page title for post.
+ *
+ * This is optimized for single.php template file for displaying the post title.
+ *
+ * It does not support placing the separator after the title, but by leaving the
+ * prefix parameter empty, you can set the title separator manually. The prefix
+ * does not automatically place a space between the prefix, so if there should
+ * be a space, the parameter value will need to have it at the end.
+ *
+ * @since 0.71
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function single_post_title($prefix = '', $display = true) {
+ $_post = get_queried_object();
+
+ if ( !isset($_post->post_title) )
+ return;
+
+ $title = apply_filters('single_post_title', $_post->post_title, $_post);
+ if ( $display )
+ echo $prefix . $title;
+ else
+ return $title;
+}
+
+/**
+ * Display or retrieve title for a post type archive.
+ *
+ * This is optimized for archive.php and archive-{$post_type}.php template files
+ * for displaying the title of the post type.
+ *
+ * @since 3.1.0
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function post_type_archive_title( $prefix = '', $display = true ) {
+ if ( ! is_post_type_archive() )
+ return;
+
+ $post_type_obj = get_queried_object();
+ $title = apply_filters('post_type_archive_title', $post_type_obj->labels->name );
+
+ if ( $display )
+ echo $prefix . $title;
+ else
+ return $title;
+}
+
+/**
+ * Display or retrieve page title for category archive.
+ *
+ * This is useful for category template file or files, because it is optimized
+ * for category page title and with less overhead than {@link wp_title()}.
+ *
+ * It does not support placing the separator after the title, but by leaving the
+ * prefix parameter empty, you can set the title separator manually. The prefix
+ * does not automatically place a space between the prefix, so if there should
+ * be a space, the parameter value will need to have it at the end.
+ *
+ * @since 0.71
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function single_cat_title( $prefix = '', $display = true ) {
+ return single_term_title( $prefix, $display );
+}
+
+/**
+ * Display or retrieve page title for tag post archive.
+ *
+ * Useful for tag template files for displaying the tag page title. It has less
+ * overhead than {@link wp_title()}, because of its limited implementation.
+ *
+ * It does not support placing the separator after the title, but by leaving the
+ * prefix parameter empty, you can set the title separator manually. The prefix
+ * does not automatically place a space between the prefix, so if there should
+ * be a space, the parameter value will need to have it at the end.
+ *
+ * @since 2.3.0
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function single_tag_title( $prefix = '', $display = true ) {
+ return single_term_title( $prefix, $display );
+}
+
+/**
+ * Display or retrieve page title for taxonomy term archive.
+ *
+ * Useful for taxonomy term template files for displaying the taxonomy term page title.
+ * It has less overhead than {@link wp_title()}, because of its limited implementation.
+ *
+ * It does not support placing the separator after the title, but by leaving the
+ * prefix parameter empty, you can set the title separator manually. The prefix
+ * does not automatically place a space between the prefix, so if there should
+ * be a space, the parameter value will need to have it at the end.
+ *
+ * @since 3.1.0
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function single_term_title( $prefix = '', $display = true ) {
+ $term = get_queried_object();
+
+ if ( !$term )
+ return;
+
+ if ( is_category() )
+ $term_name = apply_filters( 'single_cat_title', $term->name );
+ elseif ( is_tag() )
+ $term_name = apply_filters( 'single_tag_title', $term->name );
+ elseif ( is_tax() )
+ $term_name = apply_filters( 'single_term_title', $term->name );
+ else
+ return;
+
+ if ( empty( $term_name ) )
+ return;
+
+ if ( $display )
+ echo $prefix . $term_name;
+ else
+ return $term_name;
+}
+
+/**
+ * Display or retrieve page title for post archive based on date.
+ *
+ * Useful for when the template only needs to display the month and year, if
+ * either are available. Optimized for just this purpose, so if it is all that
+ * is needed, should be better than {@link wp_title()}.
+ *
+ * It does not support placing the separator after the title, but by leaving the
+ * prefix parameter empty, you can set the title separator manually. The prefix
+ * does not automatically place a space between the prefix, so if there should
+ * be a space, the parameter value will need to have it at the end.
+ *
+ * @since 0.71
+ *
+ * @param string $prefix Optional. What to display before the title.
+ * @param bool $display Optional, default is true. Whether to display or retrieve title.
+ * @return string|null Title when retrieving, null when displaying or failure.
+ */
+function single_month_title($prefix = '', $display = true ) {
+ global $wp_locale;
+
+ $m = get_query_var('m');
+ $year = get_query_var('year');
+ $monthnum = get_query_var('monthnum');
+
+ if ( !empty($monthnum) && !empty($year) ) {
+ $my_year = $year;
+ $my_month = $wp_locale->get_month($monthnum);
+ } elseif ( !empty($m) ) {
+ $my_year = substr($m, 0, 4);
+ $my_month = $wp_locale->get_month(substr($m, 4, 2));
+ }
+
+ if ( empty($my_month) )
+ return false;
+
+ $result = $prefix . $my_month . $prefix . $my_year;
+
+ if ( !$display )
+ return $result;
+ echo $result;
+}
+
+/**
+ * Retrieve archive link content based on predefined or custom code.
+ *
+ * The format can be one of four styles. The 'link' for head element, 'option'
+ * for use in the select element, 'html' for use in list (either ol or ul HTML
+ * elements). Custom content is also supported using the before and after
+ * parameters.
+ *
+ * The 'link' format uses the link HTML element with the <em>archives</em>
+ * relationship. The before and after parameters are not used. The text
+ * parameter is used to describe the link.
+ *
+ * The 'option' format uses the option HTML element for use in select element.
+ * The value is the url parameter and the before and after parameters are used
+ * between the text description.
+ *
+ * The 'html' format, which is the default, uses the li HTML element for use in
+ * the list HTML elements. The before parameter is before the link and the after
+ * parameter is after the closing link.
+ *
+ * The custom format uses the before parameter before the link ('a' HTML
+ * element) and the after parameter after the closing link tag. If the above
+ * three values for the format are not used, then custom format is assumed.
+ *
+ * @since 1.0.0
+ *
+ * @param string $url URL to archive.
+ * @param string $text Archive text description.
+ * @param string $format Optional, default is 'html'. Can be 'link', 'option', 'html', or custom.
+ * @param string $before Optional.
+ * @param string $after Optional.
+ * @return string HTML link content for archive.
+ */
+function get_archives_link($url, $text, $format = 'html', $before = '', $after = '') {
+ $text = wptexturize($text);
+ $title_text = esc_attr($text);
+ $url = esc_url($url);
+
+ if ('link' == $format)
+ $link_html = "\t<link rel='archives' title='$title_text' href='$url' />\n";
+ elseif ('option' == $format)
+ $link_html = "\t<option value='$url'>$before $text $after</option>\n";
+ elseif ('html' == $format)
+ $link_html = "\t<li>$before<a href='$url' title='$title_text'>$text</a>$after</li>\n";
+ else // custom
+ $link_html = "\t$before<a href='$url' title='$title_text'>$text</a>$after\n";
+
+ $link_html = apply_filters( 'get_archives_link', $link_html );
+
+ return $link_html;
+}
+
+/**
+ * Display archive links based on type and format.
+ *
+ * The 'type' argument offers a few choices and by default will display monthly
+ * archive links. The other options for values are 'daily', 'weekly', 'monthly',
+ * 'yearly', 'postbypost' or 'alpha'. Both 'postbypost' and 'alpha' display the
+ * same archive link list, the difference between the two is that 'alpha'
+ * will order by post title and 'postbypost' will order by post date.
+ *
+ * The date archives will logically display dates with links to the archive post
+ * page. The 'postbypost' and 'alpha' values for 'type' argument will display
+ * the post titles.
+ *
+ * The 'limit' argument will only display a limited amount of links, specified
+ * by the 'limit' integer value. By default, there is no limit. The
+ * 'show_post_count' argument will show how many posts are within the archive.
+ * By default, the 'show_post_count' argument is set to false.
+ *
+ * For the 'format', 'before', and 'after' arguments, see {@link
+ * get_archives_link()}. The values of these arguments have to do with that
+ * function.
+ *
+ * @since 1.2.0
+ *
+ * @param string|array $args Optional. Override defaults.
+ * @return string|null String when retrieving, null when displaying.
+ */
+function wp_get_archives($args = '') {
+ global $wpdb, $wp_locale;
+
+ $defaults = array(
+ 'type' => 'monthly', 'limit' => '',
+ 'format' => 'html', 'before' => '',
+ 'after' => '', 'show_post_count' => false,
+ 'echo' => 1, 'order' => 'DESC',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ if ( '' == $type )
+ $type = 'monthly';
+
+ if ( '' != $limit ) {
+ $limit = absint($limit);
+ $limit = ' LIMIT '.$limit;
+ }
+
+ $order = strtoupper( $order );
+ if ( $order !== 'ASC' )
+ $order = 'DESC';
+
+ // this is what will separate dates on weekly archive links
+ $archive_week_separator = '&#8211;';
+
+ // over-ride general date format ? 0 = no: use the date format set in Options, 1 = yes: over-ride
+ $archive_date_format_over_ride = 0;
+
+ // options for daily archive (only if you over-ride the general date format)
+ $archive_day_date_format = 'Y/m/d';
+
+ // options for weekly archive (only if you over-ride the general date format)
+ $archive_week_start_date_format = 'Y/m/d';
+ $archive_week_end_date_format = 'Y/m/d';
+
+ if ( !$archive_date_format_over_ride ) {
+ $archive_day_date_format = get_option('date_format');
+ $archive_week_start_date_format = get_option('date_format');
+ $archive_week_end_date_format = get_option('date_format');
+ }
+
+ $where = apply_filters( 'getarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'", $r );
+ $join = apply_filters( 'getarchives_join', '', $r );
+
+ $output = '';
+
+ $last_changed = wp_cache_get( 'last_changed', 'posts' );
+ if ( ! $last_changed ) {
+ $last_changed = microtime();
+ wp_cache_set( 'last_changed', $last_changed, 'posts' );
+ }
+
+ if ( 'monthly' == $type ) {
+ $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date $order $limit";
+ $key = md5( $query );
+ $key = "wp_get_archives:$key:$last_changed";
+ if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
+ $results = $wpdb->get_results( $query );
+ wp_cache_set( $key, $results, 'posts' );
+ }
+ if ( $results ) {
+ $afterafter = $after;
+ foreach ( (array) $results as $result ) {
+ $url = get_month_link( $result->year, $result->month );
+ /* translators: 1: month name, 2: 4-digit year */
+ $text = sprintf(__('%1$s %2$d'), $wp_locale->get_month($result->month), $result->year);
+ if ( $show_post_count )
+ $after = '&nbsp;('.$result->posts.')' . $afterafter;
+ $output .= get_archives_link($url, $text, $format, $before, $after);
+ }
+ }
+ } elseif ('yearly' == $type) {
+ $query = "SELECT YEAR(post_date) AS `year`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date) ORDER BY post_date $order $limit";
+ $key = md5( $query );
+ $key = "wp_get_archives:$key:$last_changed";
+ if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
+ $results = $wpdb->get_results( $query );
+ wp_cache_set( $key, $results, 'posts' );
+ }
+ if ( $results ) {
+ $afterafter = $after;
+ foreach ( (array) $results as $result) {
+ $url = get_year_link($result->year);
+ $text = sprintf('%d', $result->year);
+ if ($show_post_count)
+ $after = '&nbsp;('.$result->posts.')' . $afterafter;
+ $output .= get_archives_link($url, $text, $format, $before, $after);
+ }
+ }
+ } elseif ( 'daily' == $type ) {
+ $query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, DAYOFMONTH(post_date) AS `dayofmonth`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date), DAYOFMONTH(post_date) ORDER BY post_date $order $limit";
+ $key = md5( $query );
+ $key = "wp_get_archives:$key:$last_changed";
+ if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
+ $results = $wpdb->get_results( $query );
+ $cache[ $key ] = $results;
+ wp_cache_set( $key, $results, 'posts' );
+ }
+ if ( $results ) {
+ $afterafter = $after;
+ foreach ( (array) $results as $result ) {
+ $url = get_day_link($result->year, $result->month, $result->dayofmonth);
+ $date = sprintf('%1$d-%2$02d-%3$02d 00:00:00', $result->year, $result->month, $result->dayofmonth);
+ $text = mysql2date($archive_day_date_format, $date);
+ if ($show_post_count)
+ $after = '&nbsp;('.$result->posts.')'.$afterafter;
+ $output .= get_archives_link($url, $text, $format, $before, $after);
+ }
+ }
+ } elseif ( 'weekly' == $type ) {
+ $week = _wp_mysql_week( '`post_date`' );
+ $query = "SELECT DISTINCT $week AS `week`, YEAR( `post_date` ) AS `yr`, DATE_FORMAT( `post_date`, '%Y-%m-%d' ) AS `yyyymmdd`, count( `ID` ) AS `posts` FROM `$wpdb->posts` $join $where GROUP BY $week, YEAR( `post_date` ) ORDER BY `post_date` $order $limit";
+ $key = md5( $query );
+ $key = "wp_get_archives:$key:$last_changed";
+ if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
+ $results = $wpdb->get_results( $query );
+ wp_cache_set( $key, $results, 'posts' );
+ }
+ $arc_w_last = '';
+ $afterafter = $after;
+ if ( $results ) {
+ foreach ( (array) $results as $result ) {
+ if ( $result->week != $arc_w_last ) {
+ $arc_year = $result->yr;
+ $arc_w_last = $result->week;
+ $arc_week = get_weekstartend($result->yyyymmdd, get_option('start_of_week'));
+ $arc_week_start = date_i18n($archive_week_start_date_format, $arc_week['start']);
+ $arc_week_end = date_i18n($archive_week_end_date_format, $arc_week['end']);
+ $url = sprintf('%1$s/%2$s%3$sm%4$s%5$s%6$sw%7$s%8$d', home_url(), '', '?', '=', $arc_year, '&amp;', '=', $result->week);
+ $text = $arc_week_start . $archive_week_separator . $arc_week_end;
+ if ($show_post_count)
+ $after = '&nbsp;('.$result->posts.')'.$afterafter;
+ $output .= get_archives_link($url, $text, $format, $before, $after);
+ }
+ }
+ }
+ } elseif ( ( 'postbypost' == $type ) || ('alpha' == $type) ) {
+ $orderby = ('alpha' == $type) ? 'post_title ASC ' : 'post_date DESC ';
+ $query = "SELECT * FROM $wpdb->posts $join $where ORDER BY $orderby $limit";
+ $key = md5( $query );
+ $key = "wp_get_archives:$key:$last_changed";
+ if ( ! $results = wp_cache_get( $key, 'posts' ) ) {
+ $results = $wpdb->get_results( $query );
+ wp_cache_set( $key, $results, 'posts' );
+ }
+ if ( $results ) {
+ foreach ( (array) $results as $result ) {
+ if ( $result->post_date != '0000-00-00 00:00:00' ) {
+ $url = get_permalink( $result );
+ if ( $result->post_title )
+ $text = strip_tags( apply_filters( 'the_title', $result->post_title, $result->ID ) );
+ else
+ $text = $result->ID;
+ $output .= get_archives_link($url, $text, $format, $before, $after);
+ }
+ }
+ }
+ }
+ if ( $echo )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Get number of days since the start of the week.
+ *
+ * @since 1.5.0
+ *
+ * @param int $num Number of day.
+ * @return int Days since the start of the week.
+ */
+function calendar_week_mod($num) {
+ $base = 7;
+ return ($num - $base*floor($num/$base));
+}
+
+/**
+ * Display calendar with days that have posts as links.
+ *
+ * The calendar is cached, which will be retrieved, if it exists. If there are
+ * no posts for the month, then it will not be displayed.
+ *
+ * @since 1.0.0
+ * @uses calendar_week_mod()
+ *
+ * @param bool $initial Optional, default is true. Use initial calendar names.
+ * @param bool $echo Optional, default is true. Set to false for return.
+ * @return string|null String when retrieving, null when displaying.
+ */
+function get_calendar($initial = true, $echo = true) {
+ global $wpdb, $m, $monthnum, $year, $wp_locale, $posts;
+
+ $cache = array();
+ $key = md5( $m . $monthnum . $year );
+ if ( $cache = wp_cache_get( 'get_calendar', 'calendar' ) ) {
+ if ( is_array($cache) && isset( $cache[ $key ] ) ) {
+ if ( $echo ) {
+ echo apply_filters( 'get_calendar', $cache[$key] );
+ return;
+ } else {
+ return apply_filters( 'get_calendar', $cache[$key] );
+ }
+ }
+ }
+
+ if ( !is_array($cache) )
+ $cache = array();
+
+ // Quick check. If we have no posts at all, abort!
+ if ( !$posts ) {
+ $gotsome = $wpdb->get_var("SELECT 1 as test FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' LIMIT 1");
+ if ( !$gotsome ) {
+ $cache[ $key ] = '';
+ wp_cache_set( 'get_calendar', $cache, 'calendar' );
+ return;
+ }
+ }
+
+ if ( isset($_GET['w']) )
+ $w = ''.intval($_GET['w']);
+
+ // week_begins = 0 stands for Sunday
+ $week_begins = intval(get_option('start_of_week'));
+
+ // Let's figure out when we are
+ if ( !empty($monthnum) && !empty($year) ) {
+ $thismonth = ''.zeroise(intval($monthnum), 2);
+ $thisyear = ''.intval($year);
+ } elseif ( !empty($w) ) {
+ // We need to get the month from MySQL
+ $thisyear = ''.intval(substr($m, 0, 4));
+ $d = (($w - 1) * 7) + 6; //it seems MySQL's weeks disagree with PHP's
+ $thismonth = $wpdb->get_var("SELECT DATE_FORMAT((DATE_ADD('{$thisyear}0101', INTERVAL $d DAY) ), '%m')");
+ } elseif ( !empty($m) ) {
+ $thisyear = ''.intval(substr($m, 0, 4));
+ if ( strlen($m) < 6 )
+ $thismonth = '01';
+ else
+ $thismonth = ''.zeroise(intval(substr($m, 4, 2)), 2);
+ } else {
+ $thisyear = gmdate('Y', current_time('timestamp'));
+ $thismonth = gmdate('m', current_time('timestamp'));
+ }
+
+ $unixmonth = mktime(0, 0 , 0, $thismonth, 1, $thisyear);
+ $last_day = date('t', $unixmonth);
+
+ // Get the next and previous month and year with at least one post
+ $previous = $wpdb->get_row("SELECT MONTH(post_date) AS month, YEAR(post_date) AS year
+ FROM $wpdb->posts
+ WHERE post_date < '$thisyear-$thismonth-01'
+ AND post_type = 'post' AND post_status = 'publish'
+ ORDER BY post_date DESC
+ LIMIT 1");
+ $next = $wpdb->get_row("SELECT MONTH(post_date) AS month, YEAR(post_date) AS year
+ FROM $wpdb->posts
+ WHERE post_date > '$thisyear-$thismonth-{$last_day} 23:59:59'
+ AND post_type = 'post' AND post_status = 'publish'
+ ORDER BY post_date ASC
+ LIMIT 1");
+
+ /* translators: Calendar caption: 1: month name, 2: 4-digit year */
+ $calendar_caption = _x('%1$s %2$s', 'calendar caption');
+ $calendar_output = '<table id="wp-calendar">
+ <caption>' . sprintf($calendar_caption, $wp_locale->get_month($thismonth), date('Y', $unixmonth)) . '</caption>
+ <thead>
+ <tr>';
+
+ $myweek = array();
+
+ for ( $wdcount=0; $wdcount<=6; $wdcount++ ) {
+ $myweek[] = $wp_locale->get_weekday(($wdcount+$week_begins)%7);
+ }
+
+ foreach ( $myweek as $wd ) {
+ $day_name = (true == $initial) ? $wp_locale->get_weekday_initial($wd) : $wp_locale->get_weekday_abbrev($wd);
+ $wd = esc_attr($wd);
+ $calendar_output .= "\n\t\t<th scope=\"col\" title=\"$wd\">$day_name</th>";
+ }
+
+ $calendar_output .= '
+ </tr>
+ </thead>
+
+ <tfoot>
+ <tr>';
+
+ if ( $previous ) {
+ $calendar_output .= "\n\t\t".'<td colspan="3" id="prev"><a href="' . get_month_link($previous->year, $previous->month) . '" title="' . esc_attr( sprintf(__('View posts for %1$s %2$s'), $wp_locale->get_month($previous->month), date('Y', mktime(0, 0 , 0, $previous->month, 1, $previous->year)))) . '">&laquo; ' . $wp_locale->get_month_abbrev($wp_locale->get_month($previous->month)) . '</a></td>';
+ } else {
+ $calendar_output .= "\n\t\t".'<td colspan="3" id="prev" class="pad">&nbsp;</td>';
+ }
+
+ $calendar_output .= "\n\t\t".'<td class="pad">&nbsp;</td>';
+
+ if ( $next ) {
+ $calendar_output .= "\n\t\t".'<td colspan="3" id="next"><a href="' . get_month_link($next->year, $next->month) . '" title="' . esc_attr( sprintf(__('View posts for %1$s %2$s'), $wp_locale->get_month($next->month), date('Y', mktime(0, 0 , 0, $next->month, 1, $next->year))) ) . '">' . $wp_locale->get_month_abbrev($wp_locale->get_month($next->month)) . ' &raquo;</a></td>';
+ } else {
+ $calendar_output .= "\n\t\t".'<td colspan="3" id="next" class="pad">&nbsp;</td>';
+ }
+
+ $calendar_output .= '
+ </tr>
+ </tfoot>
+
+ <tbody>
+ <tr>';
+
+ // Get days with posts
+ $dayswithposts = $wpdb->get_results("SELECT DISTINCT DAYOFMONTH(post_date)
+ FROM $wpdb->posts WHERE post_date >= '{$thisyear}-{$thismonth}-01 00:00:00'
+ AND post_type = 'post' AND post_status = 'publish'
+ AND post_date <= '{$thisyear}-{$thismonth}-{$last_day} 23:59:59'", ARRAY_N);
+ if ( $dayswithposts ) {
+ foreach ( (array) $dayswithposts as $daywith ) {
+ $daywithpost[] = $daywith[0];
+ }
+ } else {
+ $daywithpost = array();
+ }
+
+ if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false || stripos($_SERVER['HTTP_USER_AGENT'], 'camino') !== false || stripos($_SERVER['HTTP_USER_AGENT'], 'safari') !== false)
+ $ak_title_separator = "\n";
+ else
+ $ak_title_separator = ', ';
+
+ $ak_titles_for_day = array();
+ $ak_post_titles = $wpdb->get_results("SELECT ID, post_title, DAYOFMONTH(post_date) as dom "
+ ."FROM $wpdb->posts "
+ ."WHERE post_date >= '{$thisyear}-{$thismonth}-01 00:00:00' "
+ ."AND post_date <= '{$thisyear}-{$thismonth}-{$last_day} 23:59:59' "
+ ."AND post_type = 'post' AND post_status = 'publish'"
+ );
+ if ( $ak_post_titles ) {
+ foreach ( (array) $ak_post_titles as $ak_post_title ) {
+
+ $post_title = esc_attr( apply_filters( 'the_title', $ak_post_title->post_title, $ak_post_title->ID ) );
+
+ if ( empty($ak_titles_for_day['day_'.$ak_post_title->dom]) )
+ $ak_titles_for_day['day_'.$ak_post_title->dom] = '';
+ if ( empty($ak_titles_for_day["$ak_post_title->dom"]) ) // first one
+ $ak_titles_for_day["$ak_post_title->dom"] = $post_title;
+ else
+ $ak_titles_for_day["$ak_post_title->dom"] .= $ak_title_separator . $post_title;
+ }
+ }
+
+ // See how much we should pad in the beginning
+ $pad = calendar_week_mod(date('w', $unixmonth)-$week_begins);
+ if ( 0 != $pad )
+ $calendar_output .= "\n\t\t".'<td colspan="'. esc_attr($pad) .'" class="pad">&nbsp;</td>';
+
+ $daysinmonth = intval(date('t', $unixmonth));
+ for ( $day = 1; $day <= $daysinmonth; ++$day ) {
+ if ( isset($newrow) && $newrow )
+ $calendar_output .= "\n\t</tr>\n\t<tr>\n\t\t";
+ $newrow = false;
+
+ if ( $day == gmdate('j', current_time('timestamp')) && $thismonth == gmdate('m', current_time('timestamp')) && $thisyear == gmdate('Y', current_time('timestamp')) )
+ $calendar_output .= '<td id="today">';
+ else
+ $calendar_output .= '<td>';
+
+ if ( in_array($day, $daywithpost) ) // any posts today?
+ $calendar_output .= '<a href="' . get_day_link( $thisyear, $thismonth, $day ) . '" title="' . esc_attr( $ak_titles_for_day[ $day ] ) . "\">$day</a>";
+ else
+ $calendar_output .= $day;
+ $calendar_output .= '</td>';
+
+ if ( 6 == calendar_week_mod(date('w', mktime(0, 0 , 0, $thismonth, $day, $thisyear))-$week_begins) )
+ $newrow = true;
+ }
+
+ $pad = 7 - calendar_week_mod(date('w', mktime(0, 0 , 0, $thismonth, $day, $thisyear))-$week_begins);
+ if ( $pad != 0 && $pad != 7 )
+ $calendar_output .= "\n\t\t".'<td class="pad" colspan="'. esc_attr($pad) .'">&nbsp;</td>';
+
+ $calendar_output .= "\n\t</tr>\n\t</tbody>\n\t</table>";
+
+ $cache[ $key ] = $calendar_output;
+ wp_cache_set( 'get_calendar', $cache, 'calendar' );
+
+ if ( $echo )
+ echo apply_filters( 'get_calendar', $calendar_output );
+ else
+ return apply_filters( 'get_calendar', $calendar_output );
+
+}
+
+/**
+ * Purge the cached results of get_calendar.
+ *
+ * @see get_calendar
+ * @since 2.1.0
+ */
+function delete_get_calendar_cache() {
+ wp_cache_delete( 'get_calendar', 'calendar' );
+}
+add_action( 'save_post', 'delete_get_calendar_cache' );
+add_action( 'delete_post', 'delete_get_calendar_cache' );
+add_action( 'update_option_start_of_week', 'delete_get_calendar_cache' );
+add_action( 'update_option_gmt_offset', 'delete_get_calendar_cache' );
+
+/**
+ * Display all of the allowed tags in HTML format with attributes.
+ *
+ * This is useful for displaying in the comment area, which elements and
+ * attributes are supported. As well as any plugins which want to display it.
+ *
+ * @since 1.0.1
+ * @uses $allowedtags
+ *
+ * @return string HTML allowed tags entity encoded.
+ */
+function allowed_tags() {
+ global $allowedtags;
+ $allowed = '';
+ foreach ( (array) $allowedtags as $tag => $attributes ) {
+ $allowed .= '<'.$tag;
+ if ( 0 < count($attributes) ) {
+ foreach ( $attributes as $attribute => $limits ) {
+ $allowed .= ' '.$attribute.'=""';
+ }
+ }
+ $allowed .= '> ';
+ }
+ return htmlentities($allowed);
+}
+
+/***** Date/Time tags *****/
+
+/**
+ * Outputs the date in iso8601 format for xml files.
+ *
+ * @since 1.0.0
+ */
+function the_date_xml() {
+ echo mysql2date( 'Y-m-d', get_post()->post_date, false );
+}
+
+/**
+ * Display or Retrieve the date the current $post was written (once per date)
+ *
+ * Will only output the date if the current post's date is different from the
+ * previous one output.
+ *
+ * i.e. Only one date listing will show per day worth of posts shown in the loop, even if the
+ * function is called several times for each post.
+ *
+ * HTML output can be filtered with 'the_date'.
+ * Date string output can be filtered with 'get_the_date'.
+ *
+ * @since 0.71
+ * @uses get_the_date()
+ * @param string $d Optional. PHP date format defaults to the date_format option if not specified.
+ * @param string $before Optional. Output before the date.
+ * @param string $after Optional. Output after the date.
+ * @param bool $echo Optional, default is display. Whether to echo the date or return it.
+ * @return string|null Null if displaying, string if retrieving.
+ */
+function the_date( $d = '', $before = '', $after = '', $echo = true ) {
+ global $currentday, $previousday;
+ $the_date = '';
+ if ( $currentday != $previousday ) {
+ $the_date .= $before;
+ $the_date .= get_the_date( $d );
+ $the_date .= $after;
+ $previousday = $currentday;
+
+ $the_date = apply_filters('the_date', $the_date, $d, $before, $after);
+
+ if ( $echo )
+ echo $the_date;
+ else
+ return $the_date;
+ }
+
+ return null;
+}
+
+/**
+ * Retrieve the date the current $post was written.
+ *
+ * Unlike the_date() this function will always return the date.
+ * Modify output with 'get_the_date' filter.
+ *
+ * @since 3.0.0
+ *
+ * @param string $d Optional. PHP date format defaults to the date_format option if not specified.
+ * @return string|null Null if displaying, string if retrieving.
+ */
+function get_the_date( $d = '' ) {
+ $post = get_post();
+ $the_date = '';
+
+ if ( '' == $d )
+ $the_date .= mysql2date(get_option('date_format'), $post->post_date);
+ else
+ $the_date .= mysql2date($d, $post->post_date);
+
+ return apply_filters('get_the_date', $the_date, $d);
+}
+
+/**
+ * Display the date on which the post was last modified.
+ *
+ * @since 2.1.0
+ *
+ * @param string $d Optional. PHP date format defaults to the date_format option if not specified.
+ * @param string $before Optional. Output before the date.
+ * @param string $after Optional. Output after the date.
+ * @param bool $echo Optional, default is display. Whether to echo the date or return it.
+ * @return string|null Null if displaying, string if retrieving.
+ */
+function the_modified_date($d = '', $before='', $after='', $echo = true) {
+
+ $the_modified_date = $before . get_the_modified_date($d) . $after;
+ $the_modified_date = apply_filters('the_modified_date', $the_modified_date, $d, $before, $after);
+
+ if ( $echo )
+ echo $the_modified_date;
+ else
+ return $the_modified_date;
+
+}
+
+/**
+ * Retrieve the date on which the post was last modified.
+ *
+ * @since 2.1.0
+ *
+ * @param string $d Optional. PHP date format. Defaults to the "date_format" option
+ * @return string
+ */
+function get_the_modified_date($d = '') {
+ if ( '' == $d )
+ $the_time = get_post_modified_time(get_option('date_format'), null, null, true);
+ else
+ $the_time = get_post_modified_time($d, null, null, true);
+ return apply_filters('get_the_modified_date', $the_time, $d);
+}
+
+/**
+ * Display the time at which the post was written.
+ *
+ * @since 0.71
+ *
+ * @param string $d Either 'G', 'U', or php date format.
+ */
+function the_time( $d = '' ) {
+ echo apply_filters('the_time', get_the_time( $d ), $d);
+}
+
+/**
+ * Retrieve the time at which the post was written.
+ *
+ * @since 1.5.0
+ *
+ * @param string $d Optional Either 'G', 'U', or php date format defaults to the value specified in the time_format option.
+ * @param int|object $post Optional post ID or object. Default is global $post object.
+ * @return string
+ */
+function get_the_time( $d = '', $post = null ) {
+ $post = get_post($post);
+
+ if ( '' == $d )
+ $the_time = get_post_time(get_option('time_format'), false, $post, true);
+ else
+ $the_time = get_post_time($d, false, $post, true);
+ return apply_filters('get_the_time', $the_time, $d, $post);
+}
+
+/**
+ * Retrieve the time at which the post was written.
+ *
+ * @since 2.0.0
+ *
+ * @param string $d Optional Either 'G', 'U', or php date format.
+ * @param bool $gmt Optional, default is false. Whether to return the gmt time.
+ * @param int|object $post Optional post ID or object. Default is global $post object.
+ * @param bool $translate Whether to translate the time string
+ * @return string
+ */
+function get_post_time( $d = 'U', $gmt = false, $post = null, $translate = false ) { // returns timestamp
+ $post = get_post($post);
+
+ if ( $gmt )
+ $time = $post->post_date_gmt;
+ else
+ $time = $post->post_date;
+
+ $time = mysql2date($d, $time, $translate);
+ return apply_filters('get_post_time', $time, $d, $gmt);
+}
+
+/**
+ * Display the time at which the post was last modified.
+ *
+ * @since 2.0.0
+ *
+ * @param string $d Optional Either 'G', 'U', or php date format defaults to the value specified in the time_format option.
+ */
+function the_modified_time($d = '') {
+ echo apply_filters('the_modified_time', get_the_modified_time($d), $d);
+}
+
+/**
+ * Retrieve the time at which the post was last modified.
+ *
+ * @since 2.0.0
+ *
+ * @param string $d Optional Either 'G', 'U', or php date format defaults to the value specified in the time_format option.
+ * @return string
+ */
+function get_the_modified_time($d = '') {
+ if ( '' == $d )
+ $the_time = get_post_modified_time(get_option('time_format'), null, null, true);
+ else
+ $the_time = get_post_modified_time($d, null, null, true);
+ return apply_filters('get_the_modified_time', $the_time, $d);
+}
+
+/**
+ * Retrieve the time at which the post was last modified.
+ *
+ * @since 2.0.0
+ *
+ * @param string $d Optional, default is 'U'. Either 'G', 'U', or php date format.
+ * @param bool $gmt Optional, default is false. Whether to return the gmt time.
+ * @param int|object $post Optional, default is global post object. A post_id or post object
+ * @param bool $translate Optional, default is false. Whether to translate the result
+ * @return string Returns timestamp
+ */
+function get_post_modified_time( $d = 'U', $gmt = false, $post = null, $translate = false ) {
+ $post = get_post($post);
+
+ if ( $gmt )
+ $time = $post->post_modified_gmt;
+ else
+ $time = $post->post_modified;
+ $time = mysql2date($d, $time, $translate);
+
+ return apply_filters('get_post_modified_time', $time, $d, $gmt);
+}
+
+/**
+ * Display the weekday on which the post was written.
+ *
+ * @since 0.71
+ * @uses $wp_locale
+ * @uses $post
+ */
+function the_weekday() {
+ global $wp_locale;
+ $the_weekday = $wp_locale->get_weekday( mysql2date( 'w', get_post()->post_date, false ) );
+ $the_weekday = apply_filters('the_weekday', $the_weekday);
+ echo $the_weekday;
+}
+
+/**
+ * Display the weekday on which the post was written.
+ *
+ * Will only output the weekday if the current post's weekday is different from
+ * the previous one output.
+ *
+ * @since 0.71
+ *
+ * @param string $before Optional Output before the date.
+ * @param string $after Optional Output after the date.
+ */
+function the_weekday_date($before='',$after='') {
+ global $wp_locale, $currentday, $previousweekday;
+ $the_weekday_date = '';
+ if ( $currentday != $previousweekday ) {
+ $the_weekday_date .= $before;
+ $the_weekday_date .= $wp_locale->get_weekday( mysql2date( 'w', get_post()->post_date, false ) );
+ $the_weekday_date .= $after;
+ $previousweekday = $currentday;
+ }
+ $the_weekday_date = apply_filters('the_weekday_date', $the_weekday_date, $before, $after);
+ echo $the_weekday_date;
+}
+
+/**
+ * Fire the wp_head action
+ *
+ * @since 1.2.0
+ * @uses do_action() Calls 'wp_head' hook.
+ */
+function wp_head() {
+ do_action('wp_head');
+}
+
+/**
+ * Fire the wp_footer action
+ *
+ * @since 1.5.1
+ * @uses do_action() Calls 'wp_footer' hook.
+ */
+function wp_footer() {
+ do_action('wp_footer');
+}
+
+/**
+ * Display the links to the general feeds.
+ *
+ * @since 2.8.0
+ *
+ * @param array $args Optional arguments.
+ */
+function feed_links( $args = array() ) {
+ if ( !current_theme_supports('automatic-feed-links') )
+ return;
+
+ $defaults = array(
+ /* translators: Separator between blog name and feed type in feed links */
+ 'separator' => _x('&raquo;', 'feed link'),
+ /* translators: 1: blog title, 2: separator (raquo) */
+ 'feedtitle' => __('%1$s %2$s Feed'),
+ /* translators: 1: blog title, 2: separator (raquo) */
+ 'comstitle' => __('%1$s %2$s Comments Feed'),
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr(sprintf( $args['feedtitle'], get_bloginfo('name'), $args['separator'] )) . '" href="' . get_feed_link() . "\" />\n";
+ echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr(sprintf( $args['comstitle'], get_bloginfo('name'), $args['separator'] )) . '" href="' . get_feed_link( 'comments_' . get_default_feed() ) . "\" />\n";
+}
+
+/**
+ * Display the links to the extra feeds such as category feeds.
+ *
+ * @since 2.8.0
+ *
+ * @param array $args Optional arguments.
+ */
+function feed_links_extra( $args = array() ) {
+ $defaults = array(
+ /* translators: Separator between blog name and feed type in feed links */
+ 'separator' => _x('&raquo;', 'feed link'),
+ /* translators: 1: blog name, 2: separator(raquo), 3: post title */
+ 'singletitle' => __('%1$s %2$s %3$s Comments Feed'),
+ /* translators: 1: blog name, 2: separator(raquo), 3: category name */
+ 'cattitle' => __('%1$s %2$s %3$s Category Feed'),
+ /* translators: 1: blog name, 2: separator(raquo), 3: tag name */
+ 'tagtitle' => __('%1$s %2$s %3$s Tag Feed'),
+ /* translators: 1: blog name, 2: separator(raquo), 3: author name */
+ 'authortitle' => __('%1$s %2$s Posts by %3$s Feed'),
+ /* translators: 1: blog name, 2: separator(raquo), 3: search phrase */
+ 'searchtitle' => __('%1$s %2$s Search Results for &#8220;%3$s&#8221; Feed'),
+ /* translators: 1: blog name, 2: separator(raquo), 3: post type name */
+ 'posttypetitle' => __('%1$s %2$s %3$s Feed'),
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( is_single() || is_page() ) {
+ $id = 0;
+ $post = get_post( $id );
+
+ if ( comments_open() || pings_open() || $post->comment_count > 0 ) {
+ $title = sprintf( $args['singletitle'], get_bloginfo('name'), $args['separator'], esc_html( get_the_title() ) );
+ $href = get_post_comments_feed_link( $post->ID );
+ }
+ } elseif ( is_category() ) {
+ $term = get_queried_object();
+
+ $title = sprintf( $args['cattitle'], get_bloginfo('name'), $args['separator'], $term->name );
+ $href = get_category_feed_link( $term->term_id );
+ } elseif ( is_tag() ) {
+ $term = get_queried_object();
+
+ $title = sprintf( $args['tagtitle'], get_bloginfo('name'), $args['separator'], $term->name );
+ $href = get_tag_feed_link( $term->term_id );
+ } elseif ( is_author() ) {
+ $author_id = intval( get_query_var('author') );
+
+ $title = sprintf( $args['authortitle'], get_bloginfo('name'), $args['separator'], get_the_author_meta( 'display_name', $author_id ) );
+ $href = get_author_feed_link( $author_id );
+ } elseif ( is_search() ) {
+ $title = sprintf( $args['searchtitle'], get_bloginfo('name'), $args['separator'], get_search_query( false ) );
+ $href = get_search_feed_link();
+ } elseif ( is_post_type_archive() ) {
+ $title = sprintf( $args['posttypetitle'], get_bloginfo('name'), $args['separator'], post_type_archive_title( '', false ) );
+ $href = get_post_type_archive_feed_link( get_queried_object()->name );
+ }
+
+ if ( isset($title) && isset($href) )
+ echo '<link rel="alternate" type="' . feed_content_type() . '" title="' . esc_attr( $title ) . '" href="' . esc_url( $href ) . '" />' . "\n";
+}
+
+/**
+ * Display the link to the Really Simple Discovery service endpoint.
+ *
+ * @link http://archipelago.phrasewise.com/rsd
+ * @since 2.0.0
+ */
+function rsd_link() {
+ echo '<link rel="EditURI" type="application/rsd+xml" title="RSD" href="' . get_bloginfo('wpurl') . "/xmlrpc.php?rsd\" />\n";
+}
+
+/**
+ * Display the link to the Windows Live Writer manifest file.
+ *
+ * @link http://msdn.microsoft.com/en-us/library/bb463265.aspx
+ * @since 2.3.1
+ */
+function wlwmanifest_link() {
+ echo '<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="'
+ . get_bloginfo('wpurl') . '/wp-includes/wlwmanifest.xml" /> ' . "\n";
+}
+
+/**
+ * Display a noindex meta tag if required by the blog configuration.
+ *
+ * If a blog is marked as not being public then the noindex meta tag will be
+ * output to tell web robots not to index the page content. Add this to the wp_head action.
+ * Typical usage is as a wp_head callback. add_action( 'wp_head', 'noindex' );
+ *
+ * @see wp_no_robots
+ *
+ * @since 2.1.0
+ */
+function noindex() {
+ // If the blog is not public, tell robots to go away.
+ if ( '0' == get_option('blog_public') )
+ wp_no_robots();
+}
+
+/**
+ * Display a noindex meta tag.
+ *
+ * Outputs a noindex meta tag that tells web robots not to index the page content.
+ * Typical usage is as a wp_head callback. add_action( 'wp_head', 'wp_no_robots' );
+ *
+ * @since 3.3.0
+ */
+function wp_no_robots() {
+ echo "<meta name='robots' content='noindex,nofollow' />\n";
+}
+
+/**
+ * Determine if TinyMCE is available.
+ *
+ * Checks to see if the user has deleted the tinymce files to slim down there WordPress install.
+ *
+ * @since 2.1.0
+ *
+ * @return bool Whether TinyMCE exists.
+ */
+function rich_edit_exists() {
+ global $wp_rich_edit_exists;
+ if ( !isset($wp_rich_edit_exists) )
+ $wp_rich_edit_exists = file_exists(ABSPATH . WPINC . '/js/tinymce/tiny_mce.js');
+ return $wp_rich_edit_exists;
+}
+
+/**
+ * Whether the user should have a WYSIWIG editor.
+ *
+ * Checks that the user requires a WYSIWIG editor and that the editor is
+ * supported in the users browser.
+ *
+ * @since 2.0.0
+ *
+ * @return bool
+ */
+function user_can_richedit() {
+ global $wp_rich_edit, $is_gecko, $is_opera, $is_safari, $is_chrome, $is_IE;
+
+ if ( !isset($wp_rich_edit) ) {
+ $wp_rich_edit = false;
+
+ if ( get_user_option( 'rich_editing' ) == 'true' || ! is_user_logged_in() ) { // default to 'true' for logged out users
+ if ( $is_safari ) {
+ $wp_rich_edit = ! wp_is_mobile() || ( preg_match( '!AppleWebKit/(\d+)!', $_SERVER['HTTP_USER_AGENT'], $match ) && intval( $match[1] ) >= 534 );
+ } elseif ( $is_gecko || $is_chrome || $is_IE || ( $is_opera && !wp_is_mobile() ) ) {
+ $wp_rich_edit = true;
+ }
+ }
+ }
+
+ return apply_filters('user_can_richedit', $wp_rich_edit);
+}
+
+/**
+ * Find out which editor should be displayed by default.
+ *
+ * Works out which of the two editors to display as the current editor for a
+ * user. The 'html' setting is for the "Text" editor tab.
+ *
+ * @since 2.5.0
+ *
+ * @return string Either 'tinymce', or 'html', or 'test'
+ */
+function wp_default_editor() {
+ $r = user_can_richedit() ? 'tinymce' : 'html'; // defaults
+ if ( $user = wp_get_current_user() ) { // look for cookie
+ $ed = get_user_setting('editor', 'tinymce');
+ $r = ( in_array($ed, array('tinymce', 'html', 'test') ) ) ? $ed : $r;
+ }
+ return apply_filters( 'wp_default_editor', $r ); // filter
+}
+
+/**
+ * Renders an editor.
+ *
+ * Using this function is the proper way to output all needed components for both TinyMCE and Quicktags.
+ * _WP_Editors should not be used directly. See http://core.trac.wordpress.org/ticket/17144.
+ *
+ * NOTE: Once initialized the TinyMCE editor cannot be safely moved in the DOM. For that reason
+ * running wp_editor() inside of a metabox is not a good idea unless only Quicktags is used.
+ * On the post edit screen several actions can be used to include additional editors
+ * containing TinyMCE: 'edit_page_form', 'edit_form_advanced' and 'dbx_post_sidebar'.
+ * See http://core.trac.wordpress.org/ticket/19173 for more information.
+ *
+ * @see wp-includes/class-wp-editor.php
+ * @since 3.3.0
+ *
+ * @param string $content Initial content for the editor.
+ * @param string $editor_id HTML ID attribute value for the textarea and TinyMCE. Can only be /[a-z]+/.
+ * @param array $settings See _WP_Editors::editor().
+ */
+function wp_editor( $content, $editor_id, $settings = array() ) {
+ if ( ! class_exists( '_WP_Editors' ) )
+ require( ABSPATH . WPINC . '/class-wp-editor.php' );
+
+ _WP_Editors::editor($content, $editor_id, $settings);
+}
+
+/**
+ * Retrieve the contents of the search WordPress query variable.
+ *
+ * The search query string is passed through {@link esc_attr()}
+ * to ensure that it is safe for placing in an html attribute.
+ *
+ * @since 2.3.0
+ * @uses esc_attr()
+ *
+ * @param bool $escaped Whether the result is escaped. Default true.
+ * Only use when you are later escaping it. Do not use unescaped.
+ * @return string
+ */
+function get_search_query( $escaped = true ) {
+ $query = apply_filters( 'get_search_query', get_query_var( 's' ) );
+ if ( $escaped )
+ $query = esc_attr( $query );
+ return $query;
+}
+
+/**
+ * Display the contents of the search query variable.
+ *
+ * The search query string is passed through {@link esc_attr()}
+ * to ensure that it is safe for placing in an html attribute.
+ *
+ * @uses esc_attr()
+ * @since 2.1.0
+ */
+function the_search_query() {
+ echo esc_attr( apply_filters( 'the_search_query', get_search_query( false ) ) );
+}
+
+/**
+ * Display the language attributes for the html tag.
+ *
+ * Builds up a set of html attributes containing the text direction and language
+ * information for the page.
+ *
+ * @since 2.1.0
+ *
+ * @param string $doctype The type of html document (xhtml|html).
+ */
+function language_attributes($doctype = 'html') {
+ $attributes = array();
+ $output = '';
+
+ if ( function_exists( 'is_rtl' ) && is_rtl() )
+ $attributes[] = 'dir="rtl"';
+
+ if ( $lang = get_bloginfo('language') ) {
+ if ( get_option('html_type') == 'text/html' || $doctype == 'html' )
+ $attributes[] = "lang=\"$lang\"";
+
+ if ( get_option('html_type') != 'text/html' || $doctype == 'xhtml' )
+ $attributes[] = "xml:lang=\"$lang\"";
+ }
+
+ $output = implode(' ', $attributes);
+ $output = apply_filters('language_attributes', $output);
+ echo $output;
+}
+
+/**
+ * Retrieve paginated link for archive post pages.
+ *
+ * Technically, the function can be used to create paginated link list for any
+ * area. The 'base' argument is used to reference the url, which will be used to
+ * create the paginated links. The 'format' argument is then used for replacing
+ * the page number. It is however, most likely and by default, to be used on the
+ * archive post pages.
+ *
+ * The 'type' argument controls format of the returned value. The default is
+ * 'plain', which is just a string with the links separated by a newline
+ * character. The other possible values are either 'array' or 'list'. The
+ * 'array' value will return an array of the paginated link list to offer full
+ * control of display. The 'list' value will place all of the paginated links in
+ * an unordered HTML list.
+ *
+ * The 'total' argument is the total amount of pages and is an integer. The
+ * 'current' argument is the current page number and is also an integer.
+ *
+ * An example of the 'base' argument is "http://example.com/all_posts.php%_%"
+ * and the '%_%' is required. The '%_%' will be replaced by the contents of in
+ * the 'format' argument. An example for the 'format' argument is "?page=%#%"
+ * and the '%#%' is also required. The '%#%' will be replaced with the page
+ * number.
+ *
+ * You can include the previous and next links in the list by setting the
+ * 'prev_next' argument to true, which it is by default. You can set the
+ * previous text, by using the 'prev_text' argument. You can set the next text
+ * by setting the 'next_text' argument.
+ *
+ * If the 'show_all' argument is set to true, then it will show all of the pages
+ * instead of a short list of the pages near the current page. By default, the
+ * 'show_all' is set to false and controlled by the 'end_size' and 'mid_size'
+ * arguments. The 'end_size' argument is how many numbers on either the start
+ * and the end list edges, by default is 1. The 'mid_size' argument is how many
+ * numbers to either side of current page, but not including current page.
+ *
+ * It is possible to add query vars to the link by using the 'add_args' argument
+ * and see {@link add_query_arg()} for more information.
+ *
+ * @since 2.1.0
+ *
+ * @param string|array $args Optional. Override defaults.
+ * @return array|string String of page links or array of page links.
+ */
+function paginate_links( $args = '' ) {
+ $defaults = array(
+ 'base' => '%_%', // http://example.com/all_posts.php%_% : %_% is replaced by format (below)
+ 'format' => '?page=%#%', // ?page=%#% : %#% is replaced by the page number
+ 'total' => 1,
+ 'current' => 0,
+ 'show_all' => false,
+ 'prev_next' => true,
+ 'prev_text' => __('&laquo; Previous'),
+ 'next_text' => __('Next &raquo;'),
+ 'end_size' => 1,
+ 'mid_size' => 2,
+ 'type' => 'plain',
+ 'add_args' => false, // array of query args to add
+ 'add_fragment' => ''
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+ extract($args, EXTR_SKIP);
+
+ // Who knows what else people pass in $args
+ $total = (int) $total;
+ if ( $total < 2 )
+ return;
+ $current = (int) $current;
+ $end_size = 0 < (int) $end_size ? (int) $end_size : 1; // Out of bounds? Make it the default.
+ $mid_size = 0 <= (int) $mid_size ? (int) $mid_size : 2;
+ $add_args = is_array($add_args) ? $add_args : false;
+ $r = '';
+ $page_links = array();
+ $n = 0;
+ $dots = false;
+
+ if ( $prev_next && $current && 1 < $current ) :
+ $link = str_replace('%_%', 2 == $current ? '' : $format, $base);
+ $link = str_replace('%#%', $current - 1, $link);
+ if ( $add_args )
+ $link = add_query_arg( $add_args, $link );
+ $link .= $add_fragment;
+ $page_links[] = '<a class="prev page-numbers" href="' . esc_url( apply_filters( 'paginate_links', $link ) ) . '">' . $prev_text . '</a>';
+ endif;
+ for ( $n = 1; $n <= $total; $n++ ) :
+ $n_display = number_format_i18n($n);
+ if ( $n == $current ) :
+ $page_links[] = "<span class='page-numbers current'>$n_display</span>";
+ $dots = true;
+ else :
+ if ( $show_all || ( $n <= $end_size || ( $current && $n >= $current - $mid_size && $n <= $current + $mid_size ) || $n > $total - $end_size ) ) :
+ $link = str_replace('%_%', 1 == $n ? '' : $format, $base);
+ $link = str_replace('%#%', $n, $link);
+ if ( $add_args )
+ $link = add_query_arg( $add_args, $link );
+ $link .= $add_fragment;
+ $page_links[] = "<a class='page-numbers' href='" . esc_url( apply_filters( 'paginate_links', $link ) ) . "'>$n_display</a>";
+ $dots = true;
+ elseif ( $dots && !$show_all ) :
+ $page_links[] = '<span class="page-numbers dots">' . __( '&hellip;' ) . '</span>';
+ $dots = false;
+ endif;
+ endif;
+ endfor;
+ if ( $prev_next && $current && ( $current < $total || -1 == $total ) ) :
+ $link = str_replace('%_%', $format, $base);
+ $link = str_replace('%#%', $current + 1, $link);
+ if ( $add_args )
+ $link = add_query_arg( $add_args, $link );
+ $link .= $add_fragment;
+ $page_links[] = '<a class="next page-numbers" href="' . esc_url( apply_filters( 'paginate_links', $link ) ) . '">' . $next_text . '</a>';
+ endif;
+ switch ( $type ) :
+ case 'array' :
+ return $page_links;
+ break;
+ case 'list' :
+ $r .= "<ul class='page-numbers'>\n\t<li>";
+ $r .= join("</li>\n\t<li>", $page_links);
+ $r .= "</li>\n</ul>\n";
+ break;
+ default :
+ $r = join("\n", $page_links);
+ break;
+ endswitch;
+ return $r;
+}
+
+/**
+ * Registers an admin colour scheme css file.
+ *
+ * Allows a plugin to register a new admin colour scheme. For example:
+ * <code>
+ * wp_admin_css_color('classic', __('Classic'), admin_url("css/colors-classic.css"),
+ * array('#07273E', '#14568A', '#D54E21', '#2683AE'));
+ * </code>
+ *
+ * @since 2.5.0
+ *
+ * @param string $key The unique key for this theme.
+ * @param string $name The name of the theme.
+ * @param string $url The url of the css file containing the colour scheme.
+ * @param array $colors Optional An array of CSS color definitions which are used to give the user a feel for the theme.
+ */
+function wp_admin_css_color($key, $name, $url, $colors = array()) {
+ global $_wp_admin_css_colors;
+
+ if ( !isset($_wp_admin_css_colors) )
+ $_wp_admin_css_colors = array();
+
+ $_wp_admin_css_colors[$key] = (object) array('name' => $name, 'url' => $url, 'colors' => $colors);
+}
+
+/**
+ * Registers the default Admin color schemes
+ *
+ * @since 3.0.0
+ */
+function register_admin_color_schemes() {
+ wp_admin_css_color( 'classic', _x( 'Blue', 'admin color scheme' ), admin_url( 'css/colors-classic.min.css' ),
+ array( '#5589aa', '#cfdfe9', '#d1e5ee', '#eff8ff' ) );
+ wp_admin_css_color( 'fresh', _x( 'Gray', 'admin color scheme' ), admin_url( 'css/colors-fresh.min.css' ),
+ array( '#555', '#a0a0a0', '#ccc', '#f1f1f1' ) );
+}
+
+/**
+ * Display the URL of a WordPress admin CSS file.
+ *
+ * @see WP_Styles::_css_href and its style_loader_src filter.
+ *
+ * @since 2.3.0
+ *
+ * @param string $file file relative to wp-admin/ without its ".css" extension.
+ */
+function wp_admin_css_uri( $file = 'wp-admin' ) {
+ if ( defined('WP_INSTALLING') ) {
+ $_file = "./$file.css";
+ } else {
+ $_file = admin_url("$file.css");
+ }
+ $_file = add_query_arg( 'version', get_bloginfo( 'version' ), $_file );
+
+ return apply_filters( 'wp_admin_css_uri', $_file, $file );
+}
+
+/**
+ * Enqueues or directly prints a stylesheet link to the specified CSS file.
+ *
+ * "Intelligently" decides to enqueue or to print the CSS file. If the
+ * 'wp_print_styles' action has *not* yet been called, the CSS file will be
+ * enqueued. If the wp_print_styles action *has* been called, the CSS link will
+ * be printed. Printing may be forced by passing true as the $force_echo
+ * (second) parameter.
+ *
+ * For backward compatibility with WordPress 2.3 calling method: If the $file
+ * (first) parameter does not correspond to a registered CSS file, we assume
+ * $file is a file relative to wp-admin/ without its ".css" extension. A
+ * stylesheet link to that generated URL is printed.
+ *
+ * @package WordPress
+ * @since 2.3.0
+ * @uses $wp_styles WordPress Styles Object
+ *
+ * @param string $file Optional. Style handle name or file name (without ".css" extension) relative
+ * to wp-admin/. Defaults to 'wp-admin'.
+ * @param bool $force_echo Optional. Force the stylesheet link to be printed rather than enqueued.
+ */
+function wp_admin_css( $file = 'wp-admin', $force_echo = false ) {
+ global $wp_styles;
+ if ( !is_a($wp_styles, 'WP_Styles') )
+ $wp_styles = new WP_Styles();
+
+ // For backward compatibility
+ $handle = 0 === strpos( $file, 'css/' ) ? substr( $file, 4 ) : $file;
+
+ if ( $wp_styles->query( $handle ) ) {
+ if ( $force_echo || did_action( 'wp_print_styles' ) ) // we already printed the style queue. Print this one immediately
+ wp_print_styles( $handle );
+ else // Add to style queue
+ wp_enqueue_style( $handle );
+ return;
+ }
+
+ echo apply_filters( 'wp_admin_css', "<link rel='stylesheet' href='" . esc_url( wp_admin_css_uri( $file ) ) . "' type='text/css' />\n", $file );
+ if ( function_exists( 'is_rtl' ) && is_rtl() )
+ echo apply_filters( 'wp_admin_css', "<link rel='stylesheet' href='" . esc_url( wp_admin_css_uri( "$file-rtl" ) ) . "' type='text/css' />\n", "$file-rtl" );
+}
+
+/**
+ * Enqueues the default ThickBox js and css.
+ *
+ * If any of the settings need to be changed, this can be done with another js
+ * file similar to media-upload.js. That file should
+ * require array('thickbox') to ensure it is loaded after.
+ *
+ * @since 2.5.0
+ */
+function add_thickbox() {
+ wp_enqueue_script( 'thickbox' );
+ wp_enqueue_style( 'thickbox' );
+
+ if ( is_network_admin() )
+ add_action( 'admin_head', '_thickbox_path_admin_subfolder' );
+}
+
+/**
+ * Display the XHTML generator that is generated on the wp_head hook.
+ *
+ * @since 2.5.0
+ */
+function wp_generator() {
+ the_generator( apply_filters( 'wp_generator_type', 'xhtml' ) );
+}
+
+/**
+ * Display the generator XML or Comment for RSS, ATOM, etc.
+ *
+ * Returns the correct generator type for the requested output format. Allows
+ * for a plugin to filter generators overall the the_generator filter.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'the_generator' hook.
+ *
+ * @param string $type The type of generator to output - (html|xhtml|atom|rss2|rdf|comment|export).
+ */
+function the_generator( $type ) {
+ echo apply_filters('the_generator', get_the_generator($type), $type) . "\n";
+}
+
+/**
+ * Creates the generator XML or Comment for RSS, ATOM, etc.
+ *
+ * Returns the correct generator type for the requested output format. Allows
+ * for a plugin to filter generators on an individual basis using the
+ * 'get_the_generator_{$type}' filter.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'get_the_generator_$type' hook.
+ *
+ * @param string $type The type of generator to return - (html|xhtml|atom|rss2|rdf|comment|export).
+ * @return string The HTML content for the generator.
+ */
+function get_the_generator( $type = '' ) {
+ if ( empty( $type ) ) {
+
+ $current_filter = current_filter();
+ if ( empty( $current_filter ) )
+ return;
+
+ switch ( $current_filter ) {
+ case 'rss2_head' :
+ case 'commentsrss2_head' :
+ $type = 'rss2';
+ break;
+ case 'rss_head' :
+ case 'opml_head' :
+ $type = 'comment';
+ break;
+ case 'rdf_header' :
+ $type = 'rdf';
+ break;
+ case 'atom_head' :
+ case 'comments_atom_head' :
+ case 'app_head' :
+ $type = 'atom';
+ break;
+ }
+ }
+
+ switch ( $type ) {
+ case 'html':
+ $gen = '<meta name="generator" content="WordPress ' . get_bloginfo( 'version' ) . '">';
+ break;
+ case 'xhtml':
+ $gen = '<meta name="generator" content="WordPress ' . get_bloginfo( 'version' ) . '" />';
+ break;
+ case 'atom':
+ $gen = '<generator uri="http://wordpress.org/" version="' . get_bloginfo_rss( 'version' ) . '">WordPress</generator>';
+ break;
+ case 'rss2':
+ $gen = '<generator>http://wordpress.org/?v=' . get_bloginfo_rss( 'version' ) . '</generator>';
+ break;
+ case 'rdf':
+ $gen = '<admin:generatorAgent rdf:resource="http://wordpress.org/?v=' . get_bloginfo_rss( 'version' ) . '" />';
+ break;
+ case 'comment':
+ $gen = '<!-- generator="WordPress/' . get_bloginfo( 'version' ) . '" -->';
+ break;
+ case 'export':
+ $gen = '<!-- generator="WordPress/' . get_bloginfo_rss('version') . '" created="'. date('Y-m-d H:i') . '" -->';
+ break;
+ }
+ return apply_filters( "get_the_generator_{$type}", $gen, $type );
+}
+
+/**
+ * Outputs the html checked attribute.
+ *
+ * Compares the first two arguments and if identical marks as checked
+ *
+ * @since 1.0.0
+ *
+ * @param mixed $checked One of the values to compare
+ * @param mixed $current (true) The other value to compare if not just true
+ * @param bool $echo Whether to echo or just return the string
+ * @return string html attribute or empty string
+ */
+function checked( $checked, $current = true, $echo = true ) {
+ return __checked_selected_helper( $checked, $current, $echo, 'checked' );
+}
+
+/**
+ * Outputs the html selected attribute.
+ *
+ * Compares the first two arguments and if identical marks as selected
+ *
+ * @since 1.0.0
+ *
+ * @param mixed $selected One of the values to compare
+ * @param mixed $current (true) The other value to compare if not just true
+ * @param bool $echo Whether to echo or just return the string
+ * @return string html attribute or empty string
+ */
+function selected( $selected, $current = true, $echo = true ) {
+ return __checked_selected_helper( $selected, $current, $echo, 'selected' );
+}
+
+/**
+ * Outputs the html disabled attribute.
+ *
+ * Compares the first two arguments and if identical marks as disabled
+ *
+ * @since 3.0.0
+ *
+ * @param mixed $disabled One of the values to compare
+ * @param mixed $current (true) The other value to compare if not just true
+ * @param bool $echo Whether to echo or just return the string
+ * @return string html attribute or empty string
+ */
+function disabled( $disabled, $current = true, $echo = true ) {
+ return __checked_selected_helper( $disabled, $current, $echo, 'disabled' );
+}
+
+/**
+ * Private helper function for checked, selected, and disabled.
+ *
+ * Compares the first two arguments and if identical marks as $type
+ *
+ * @since 2.8.0
+ * @access private
+ *
+ * @param mixed $helper One of the values to compare
+ * @param mixed $current (true) The other value to compare if not just true
+ * @param bool $echo Whether to echo or just return the string
+ * @param string $type The type of checked|selected|disabled we are doing
+ * @return string html attribute or empty string
+ */
+function __checked_selected_helper( $helper, $current, $echo, $type ) {
+ if ( (string) $helper === (string) $current )
+ $result = " $type='$type'";
+ else
+ $result = '';
+
+ if ( $echo )
+ echo $result;
+
+ return $result;
+}
+
+/**
+ * Default settings for heartbeat
+ *
+ * Outputs the nonce used in the heartbeat XHR
+ *
+ * @since 3.6.0
+ *
+ * @param array $settings
+ * @return array $settings
+ */
+function wp_heartbeat_settings( $settings ) {
+ if ( ! is_admin() )
+ $settings['ajaxurl'] = admin_url( 'admin-ajax.php', 'relative' );
+
+ if ( is_user_logged_in() )
+ $settings['nonce'] = wp_create_nonce( 'heartbeat-nonce' );
+
+ return $settings;
+}
diff --git a/src/wp-includes/http.php b/src/wp-includes/http.php
new file mode 100644
index 0000000000..59dfa55ce9
--- /dev/null
+++ b/src/wp-includes/http.php
@@ -0,0 +1,519 @@
+<?php
+/**
+ * Simple and uniform HTTP request API.
+ *
+ * Will eventually replace and standardize the WordPress HTTP requests made.
+ *
+ * @link http://trac.wordpress.org/ticket/4779 HTTP API Proposal
+ *
+ * @package WordPress
+ * @subpackage HTTP
+ * @since 2.7.0
+ */
+
+/**
+ * Returns the initialized WP_Http Object
+ *
+ * @since 2.7.0
+ * @access private
+ *
+ * @return WP_Http HTTP Transport object.
+ */
+function _wp_http_get_object() {
+ static $http;
+
+ if ( is_null($http) )
+ $http = new WP_Http();
+
+ return $http;
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @see wp_remote_request() For more information on the response array format
+ * and default arguments.
+ *
+ * @since 3.6.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_request( $url, $args = array() ) {
+ $args['reject_unsafe_urls'] = true;
+ $http = _wp_http_get_object();
+ return $http->request( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request using the GET method.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @see wp_remote_request() For more information on the response array format
+ * and default arguments.
+ *
+ * @since 3.6.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_get( $url, $args = array() ) {
+ $args['reject_unsafe_urls'] = true;
+ $http = _wp_http_get_object();
+ return $http->get( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request using the POST method.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @see wp_remote_request() For more information on the response array format
+ * and default arguments.
+ *
+ * @since 3.6.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_post( $url, $args = array() ) {
+ $args['reject_unsafe_urls'] = true;
+ $http = _wp_http_get_object();
+ return $http->post( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from a safe HTTP request using the HEAD method.
+ *
+ * This function is ideal when the HTTP request is being made to an arbitrary
+ * URL. The URL is validated to avoid redirection and request forgery attacks.
+ *
+ * @see wp_remote_request() For more information on the response array format
+ * and default arguments.
+ *
+ * @since 3.6.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_safe_remote_head( $url, $args = array() ) {
+ $args['reject_unsafe_urls'] = true;
+ $http = _wp_http_get_object();
+ return $http->head( $url, $args );
+}
+
+/**
+ * Retrieve the raw response from the HTTP request.
+ *
+ * The array structure is a little complex.
+ *
+ * <code>
+ * $res = array( 'headers' => array(), 'response' => array('code' => int, 'message' => string) );
+ * </code>
+ *
+ * All of the headers in $res['headers'] are with the name as the key and the
+ * value as the value. So to get the User-Agent, you would do the following.
+ *
+ * <code>
+ * $user_agent = $res['headers']['user-agent'];
+ * </code>
+ *
+ * The body is the raw response content and can be retrieved from $res['body'].
+ *
+ * This function is called first to make the request and there are other API
+ * functions to abstract out the above convoluted setup.
+ *
+ * List of default arguments:
+ * 'method' => 'GET'
+ * - Default 'GET' for wp_remote_get()
+ * - Default 'POST' for wp_remote_post()
+ * - Default 'HEAD' for wp_remote_head()
+ * 'timeout' => 5
+ * 'redirection' => 5
+ * 'httpversion' => '1.0'
+ * 'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
+ * 'blocking' => true
+ * 'headers' => array()
+ * 'cookies' => array()
+ * 'body' => null
+ * 'compress' => false,
+ * 'decompress' => true,
+ * 'sslverify' => true,
+ * 'stream' => false,
+ * 'filename' => null
+ *
+ * @since 2.7.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_request($url, $args = array()) {
+ $objFetchSite = _wp_http_get_object();
+ return $objFetchSite->request($url, $args);
+}
+
+/**
+ * Retrieve the raw response from the HTTP request using the GET method.
+ *
+ * @see wp_remote_request() For more information on the response array format and default arguments.
+ *
+ * @since 2.7.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_get($url, $args = array()) {
+ $objFetchSite = _wp_http_get_object();
+ return $objFetchSite->get($url, $args);
+}
+
+/**
+ * Retrieve the raw response from the HTTP request using the POST method.
+ *
+ * @see wp_remote_request() For more information on the response array format and default arguments.
+ *
+ * @since 2.7.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_post($url, $args = array()) {
+ $objFetchSite = _wp_http_get_object();
+ return $objFetchSite->post($url, $args);
+}
+
+/**
+ * Retrieve the raw response from the HTTP request using the HEAD method.
+ *
+ * @see wp_remote_request() For more information on the response array format and default arguments.
+ *
+ * @since 2.7.0
+ *
+ * @param string $url Site URL to retrieve.
+ * @param array $args Optional. Override the defaults.
+ * @return WP_Error|array The response or WP_Error on failure.
+ */
+function wp_remote_head($url, $args = array()) {
+ $objFetchSite = _wp_http_get_object();
+ return $objFetchSite->head($url, $args);
+}
+
+/**
+ * Retrieve only the headers from the raw response.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return array The headers of the response. Empty array if incorrect parameter given.
+ */
+function wp_remote_retrieve_headers(&$response) {
+ if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
+ return array();
+
+ return $response['headers'];
+}
+
+/**
+ * Retrieve a single header by name from the raw response.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response
+ * @param string $header Header name to retrieve value from.
+ * @return string The header value. Empty string on if incorrect parameter given, or if the header doesn't exist.
+ */
+function wp_remote_retrieve_header(&$response, $header) {
+ if ( is_wp_error($response) || ! isset($response['headers']) || ! is_array($response['headers']))
+ return '';
+
+ if ( array_key_exists($header, $response['headers']) )
+ return $response['headers'][$header];
+
+ return '';
+}
+
+/**
+ * Retrieve only the response code from the raw response.
+ *
+ * Will return an empty array if incorrect parameter value is given.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return string the response code. Empty string on incorrect parameter given.
+ */
+function wp_remote_retrieve_response_code(&$response) {
+ if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
+ return '';
+
+ return $response['response']['code'];
+}
+
+/**
+ * Retrieve only the response message from the raw response.
+ *
+ * Will return an empty array if incorrect parameter value is given.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return string The response message. Empty string on incorrect parameter given.
+ */
+function wp_remote_retrieve_response_message(&$response) {
+ if ( is_wp_error($response) || ! isset($response['response']) || ! is_array($response['response']))
+ return '';
+
+ return $response['response']['message'];
+}
+
+/**
+ * Retrieve only the body from the raw response.
+ *
+ * @since 2.7.0
+ *
+ * @param array $response HTTP response.
+ * @return string The body of the response. Empty string if no body or incorrect parameter given.
+ */
+function wp_remote_retrieve_body(&$response) {
+ if ( is_wp_error($response) || ! isset($response['body']) )
+ return '';
+
+ return $response['body'];
+}
+
+/**
+ * Determines if there is an HTTP Transport that can process this request.
+ *
+ * @since 3.2.0
+ *
+ * @param array $capabilities Array of capabilities to test or a wp_remote_request() $args array.
+ * @param string $url Optional. If given, will check if the URL requires SSL and adds that requirement to the capabilities array.
+ *
+ * @return bool
+ */
+function wp_http_supports( $capabilities = array(), $url = null ) {
+ $objFetchSite = _wp_http_get_object();
+
+ $capabilities = wp_parse_args( $capabilities );
+
+ $count = count( $capabilities );
+
+ // If we have a numeric $capabilities array, spoof a wp_remote_request() associative $args array
+ if ( $count && count( array_filter( array_keys( $capabilities ), 'is_numeric' ) ) == $count ) {
+ $capabilities = array_combine( array_values( $capabilities ), array_fill( 0, $count, true ) );
+ }
+
+ if ( $url && !isset( $capabilities['ssl'] ) ) {
+ $scheme = parse_url( $url, PHP_URL_SCHEME );
+ if ( 'https' == $scheme || 'ssl' == $scheme ) {
+ $capabilities['ssl'] = true;
+ }
+ }
+
+ return (bool) $objFetchSite->_get_first_available_transport( $capabilities );
+}
+
+/**
+ * Get the HTTP Origin of the current request.
+ *
+ * @since 3.4.0
+ *
+ * @return string URL of the origin. Empty string if no origin.
+ */
+function get_http_origin() {
+ $origin = '';
+ if ( ! empty ( $_SERVER[ 'HTTP_ORIGIN' ] ) )
+ $origin = $_SERVER[ 'HTTP_ORIGIN' ];
+
+ return apply_filters( 'http_origin', $origin );
+}
+
+/**
+ * Retrieve list of allowed http origins.
+ *
+ * @since 3.4.0
+ *
+ * @return array Array of origin URLs.
+ */
+function get_allowed_http_origins() {
+ $admin_origin = parse_url( admin_url() );
+ $home_origin = parse_url( home_url() );
+
+ // @todo preserve port?
+ $allowed_origins = array_unique( array(
+ 'http://' . $admin_origin[ 'host' ],
+ 'https://' . $admin_origin[ 'host' ],
+ 'http://' . $home_origin[ 'host' ],
+ 'https://' . $home_origin[ 'host' ],
+ ) );
+
+ return apply_filters( 'allowed_http_origins' , $allowed_origins );
+}
+
+/**
+ * Determines if the http origin is an authorized one.
+ *
+ * @since 3.4.0
+ *
+ * @param string Origin URL. If not provided, the value of get_http_origin() is used.
+ * @return bool True if the origin is allowed. False otherwise.
+ */
+function is_allowed_http_origin( $origin = null ) {
+ $origin_arg = $origin;
+
+ if ( null === $origin )
+ $origin = get_http_origin();
+
+ if ( $origin && ! in_array( $origin, get_allowed_http_origins() ) )
+ $origin = '';
+
+ return apply_filters( 'allowed_http_origin', $origin, $origin_arg );
+}
+
+/**
+ * Send Access-Control-Allow-Origin and related headers if the current request
+ * is from an allowed origin.
+ *
+ * If the request is an OPTIONS request, the script exits with either access
+ * control headers sent, or a 403 response if the origin is not allowed. For
+ * other request methods, you will receive a return value.
+ *
+ * @since 3.4.0
+ *
+ * @return bool|string Returns the origin URL if headers are sent. Returns false
+ * if headers are not sent.
+ */
+function send_origin_headers() {
+ $origin = get_http_origin();
+
+ if ( is_allowed_http_origin( $origin ) ) {
+ @header( 'Access-Control-Allow-Origin: ' . $origin );
+ @header( 'Access-Control-Allow-Credentials: true' );
+ if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] )
+ exit;
+ return $origin;
+ }
+
+ if ( 'OPTIONS' === $_SERVER['REQUEST_METHOD'] ) {
+ status_header( 403 );
+ exit;
+ }
+
+ return false;
+}
+
+/**
+ * Validate a URL for safe use in the HTTP API.
+ *
+ * @since 3.5.2
+ *
+ * @return mixed URL or false on failure.
+ */
+function wp_http_validate_url( $url ) {
+ $url = wp_kses_bad_protocol( $url, array( 'http', 'https' ) );
+ if ( ! $url )
+ return false;
+
+ $parsed_url = @parse_url( $url );
+ if ( ! $parsed_url || empty( $parsed_url['host'] ) )
+ return false;
+
+ if ( isset( $parsed_url['user'] ) || isset( $parsed_url['pass'] ) )
+ return false;
+
+ if ( false !== strpos( $parsed_url['host'], ':' ) )
+ return false;
+
+ $parsed_home = @parse_url( get_option( 'home' ) );
+
+ $same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );
+
+ if ( ! $same_host ) {
+ $host = trim( $parsed_url['host'], '.' );
+ if ( preg_match( '#^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$#', $host ) ) {
+ $ip = $host;
+ } else {
+ $ip = gethostbyname( $host );
+ if ( $ip === $host ) // Error condition for gethostbyname()
+ $ip = false;
+ }
+ if ( $ip ) {
+ $parts = array_map( 'intval', explode( '.', $ip ) );
+ if ( '127.0.0.1' === $ip
+ || ( 10 === $parts[0] )
+ || ( 172 === $parts[0] && 16 <= $parts[1] && 31 >= $parts[1] )
+ || ( 192 === $parts[0] && 168 === $parts[1] )
+ ) {
+ // If host appears local, reject unless specifically allowed.
+ if ( ! apply_filters( 'http_request_host_is_external', false, $host, $url ) )
+ return false;
+ }
+ }
+ }
+
+ if ( empty( $parsed_url['port'] ) )
+ return $url;
+
+ $port = $parsed_url['port'];
+ if ( 80 === $port || 443 === $port || 8080 === $port )
+ return $url;
+
+ if ( $parsed_home && $same_host && $parsed_home['port'] === $port )
+ return $url;
+
+ return false;
+}
+
+/**
+ * Whitelists allowed redirect hosts for safe HTTP requests as well.
+ *
+ * Attached to the http_request_host_is_external filter.
+ *
+ * @since 3.6.0
+ *
+ * @param bool $is_external
+ * @param string $host
+ * @return bool
+ */
+function allowed_http_request_hosts( $is_external, $host ) {
+ if ( ! $is_external && wp_validate_redirect( 'http://' . $host ) )
+ $is_external = true;
+ return $is_external;
+}
+
+/**
+ * Whitelists any domain in a multisite installation for safe HTTP requests.
+ *
+ * Attached to the http_request_host_is_external filter.
+ *
+ * @since 3.6.0
+ *
+ * @param bool $is_external
+ * @param string $host
+ * @return bool
+ */
+function ms_allowed_http_request_hosts( $is_external, $host ) {
+ global $wpdb, $current_site;
+ static $queried = array();
+ if ( $is_external )
+ return $is_external;
+ if ( $host === $current_site->domain )
+ return true;
+ if ( isset( $queried[ $host ] ) )
+ return $queried[ $host ];
+ $queried[ $host ] = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM $wpdb->blogs WHERE domain = %s LIMIT 1", $host ) );
+ return $queried[ $host ];
+}
diff --git a/src/wp-includes/images/admin-bar-sprite-2x.png b/src/wp-includes/images/admin-bar-sprite-2x.png
new file mode 100644
index 0000000000..9accbee7d3
--- /dev/null
+++ b/src/wp-includes/images/admin-bar-sprite-2x.png
Binary files differ
diff --git a/src/wp-includes/images/admin-bar-sprite.png b/src/wp-includes/images/admin-bar-sprite.png
new file mode 100644
index 0000000000..744c65a441
--- /dev/null
+++ b/src/wp-includes/images/admin-bar-sprite.png
Binary files differ
diff --git a/src/wp-includes/images/arrow-pointer-blue-2x.png b/src/wp-includes/images/arrow-pointer-blue-2x.png
new file mode 100644
index 0000000000..ec1f7770bc
--- /dev/null
+++ b/src/wp-includes/images/arrow-pointer-blue-2x.png
Binary files differ
diff --git a/src/wp-includes/images/arrow-pointer-blue.png b/src/wp-includes/images/arrow-pointer-blue.png
new file mode 100644
index 0000000000..65b42feb43
--- /dev/null
+++ b/src/wp-includes/images/arrow-pointer-blue.png
Binary files differ
diff --git a/src/wp-includes/images/blank.gif b/src/wp-includes/images/blank.gif
new file mode 100644
index 0000000000..e565824aaf
--- /dev/null
+++ b/src/wp-includes/images/blank.gif
Binary files differ
diff --git a/src/wp-includes/images/crystal/archive.png b/src/wp-includes/images/crystal/archive.png
new file mode 100644
index 0000000000..2fe9fec5a3
--- /dev/null
+++ b/src/wp-includes/images/crystal/archive.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/audio.png b/src/wp-includes/images/crystal/audio.png
new file mode 100644
index 0000000000..1d347bc2f6
--- /dev/null
+++ b/src/wp-includes/images/crystal/audio.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/code.png b/src/wp-includes/images/crystal/code.png
new file mode 100644
index 0000000000..2fa960856a
--- /dev/null
+++ b/src/wp-includes/images/crystal/code.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/default.png b/src/wp-includes/images/crystal/default.png
new file mode 100644
index 0000000000..83d80ee7fd
--- /dev/null
+++ b/src/wp-includes/images/crystal/default.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/document.png b/src/wp-includes/images/crystal/document.png
new file mode 100644
index 0000000000..a6342cfb37
--- /dev/null
+++ b/src/wp-includes/images/crystal/document.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/interactive.png b/src/wp-includes/images/crystal/interactive.png
new file mode 100644
index 0000000000..687248b042
--- /dev/null
+++ b/src/wp-includes/images/crystal/interactive.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/license.txt b/src/wp-includes/images/crystal/license.txt
new file mode 100644
index 0000000000..cdabd2fd41
--- /dev/null
+++ b/src/wp-includes/images/crystal/license.txt
@@ -0,0 +1,9 @@
+Crystal Project Icons
+by Everaldo Coelho
+http://everaldo.com
+
+Released under LGPL
+
+Modified February 2008
+for WordPress
+http://wordpress.org \ No newline at end of file
diff --git a/src/wp-includes/images/crystal/spreadsheet.png b/src/wp-includes/images/crystal/spreadsheet.png
new file mode 100644
index 0000000000..402b2596ad
--- /dev/null
+++ b/src/wp-includes/images/crystal/spreadsheet.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/text.png b/src/wp-includes/images/crystal/text.png
new file mode 100644
index 0000000000..3ef6672bf3
--- /dev/null
+++ b/src/wp-includes/images/crystal/text.png
Binary files differ
diff --git a/src/wp-includes/images/crystal/video.png b/src/wp-includes/images/crystal/video.png
new file mode 100644
index 0000000000..bd58b9b043
--- /dev/null
+++ b/src/wp-includes/images/crystal/video.png
Binary files differ
diff --git a/src/wp-includes/images/down_arrow-2x.gif b/src/wp-includes/images/down_arrow-2x.gif
new file mode 100644
index 0000000000..2408bd5fe2
--- /dev/null
+++ b/src/wp-includes/images/down_arrow-2x.gif
Binary files differ
diff --git a/src/wp-includes/images/down_arrow.gif b/src/wp-includes/images/down_arrow.gif
new file mode 100644
index 0000000000..687b241eec
--- /dev/null
+++ b/src/wp-includes/images/down_arrow.gif
Binary files differ
diff --git a/src/wp-includes/images/icon-pointer-flag-2x.png b/src/wp-includes/images/icon-pointer-flag-2x.png
new file mode 100644
index 0000000000..99a2c2ab00
--- /dev/null
+++ b/src/wp-includes/images/icon-pointer-flag-2x.png
Binary files differ
diff --git a/src/wp-includes/images/icon-pointer-flag.png b/src/wp-includes/images/icon-pointer-flag.png
new file mode 100644
index 0000000000..6bb48c0fca
--- /dev/null
+++ b/src/wp-includes/images/icon-pointer-flag.png
Binary files differ
diff --git a/src/wp-includes/images/rss-2x.png b/src/wp-includes/images/rss-2x.png
new file mode 100644
index 0000000000..7b525cf131
--- /dev/null
+++ b/src/wp-includes/images/rss-2x.png
Binary files differ
diff --git a/src/wp-includes/images/rss.png b/src/wp-includes/images/rss.png
new file mode 100644
index 0000000000..9707305e35
--- /dev/null
+++ b/src/wp-includes/images/rss.png
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_arrow.gif b/src/wp-includes/images/smilies/icon_arrow.gif
new file mode 100644
index 0000000000..2880055cc0
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_arrow.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_biggrin.gif b/src/wp-includes/images/smilies/icon_biggrin.gif
new file mode 100644
index 0000000000..d3527723c6
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_biggrin.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_confused.gif b/src/wp-includes/images/smilies/icon_confused.gif
new file mode 100644
index 0000000000..0c49e06983
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_confused.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_cool.gif b/src/wp-includes/images/smilies/icon_cool.gif
new file mode 100644
index 0000000000..cead0306c0
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_cool.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_cry.gif b/src/wp-includes/images/smilies/icon_cry.gif
new file mode 100644
index 0000000000..7d54b1f994
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_cry.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_eek.gif b/src/wp-includes/images/smilies/icon_eek.gif
new file mode 100644
index 0000000000..5d3978106a
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_eek.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_evil.gif b/src/wp-includes/images/smilies/icon_evil.gif
new file mode 100644
index 0000000000..ab1aa8e123
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_evil.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_exclaim.gif b/src/wp-includes/images/smilies/icon_exclaim.gif
new file mode 100644
index 0000000000..6e50e2eecd
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_exclaim.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_idea.gif b/src/wp-includes/images/smilies/icon_idea.gif
new file mode 100644
index 0000000000..a40ae0d7e8
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_idea.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_lol.gif b/src/wp-includes/images/smilies/icon_lol.gif
new file mode 100644
index 0000000000..374ba150fb
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_lol.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_mad.gif b/src/wp-includes/images/smilies/icon_mad.gif
new file mode 100644
index 0000000000..1f6c3c2fb4
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_mad.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_mrgreen.gif b/src/wp-includes/images/smilies/icon_mrgreen.gif
new file mode 100644
index 0000000000..b54cd0f946
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_mrgreen.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_neutral.gif b/src/wp-includes/images/smilies/icon_neutral.gif
new file mode 100644
index 0000000000..4f311567ed
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_neutral.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_question.gif b/src/wp-includes/images/smilies/icon_question.gif
new file mode 100644
index 0000000000..9d072265bb
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_question.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_razz.gif b/src/wp-includes/images/smilies/icon_razz.gif
new file mode 100644
index 0000000000..29da2a2fcc
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_razz.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_redface.gif b/src/wp-includes/images/smilies/icon_redface.gif
new file mode 100644
index 0000000000..ad7628320c
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_redface.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_rolleyes.gif b/src/wp-includes/images/smilies/icon_rolleyes.gif
new file mode 100644
index 0000000000..d7f5f2f4b1
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_rolleyes.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_sad.gif b/src/wp-includes/images/smilies/icon_sad.gif
new file mode 100644
index 0000000000..d2ac78c04b
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_sad.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_smile.gif b/src/wp-includes/images/smilies/icon_smile.gif
new file mode 100644
index 0000000000..7b1f6d3044
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_smile.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_surprised.gif b/src/wp-includes/images/smilies/icon_surprised.gif
new file mode 100644
index 0000000000..cb21424319
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_surprised.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_twisted.gif b/src/wp-includes/images/smilies/icon_twisted.gif
new file mode 100644
index 0000000000..502fe247e8
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_twisted.gif
Binary files differ
diff --git a/src/wp-includes/images/smilies/icon_wink.gif b/src/wp-includes/images/smilies/icon_wink.gif
new file mode 100644
index 0000000000..d148288042
--- /dev/null
+++ b/src/wp-includes/images/smilies/icon_wink.gif
Binary files differ
diff --git a/src/wp-includes/images/toggle-arrow-2x.png b/src/wp-includes/images/toggle-arrow-2x.png
new file mode 100644
index 0000000000..a282075b06
--- /dev/null
+++ b/src/wp-includes/images/toggle-arrow-2x.png
Binary files differ
diff --git a/src/wp-includes/images/toggle-arrow.png b/src/wp-includes/images/toggle-arrow.png
new file mode 100644
index 0000000000..bfb6494262
--- /dev/null
+++ b/src/wp-includes/images/toggle-arrow.png
Binary files differ
diff --git a/src/wp-includes/images/uploader-icons-2x.png b/src/wp-includes/images/uploader-icons-2x.png
new file mode 100644
index 0000000000..d40389c763
--- /dev/null
+++ b/src/wp-includes/images/uploader-icons-2x.png
Binary files differ
diff --git a/src/wp-includes/images/uploader-icons.png b/src/wp-includes/images/uploader-icons.png
new file mode 100644
index 0000000000..b72a074b08
--- /dev/null
+++ b/src/wp-includes/images/uploader-icons.png
Binary files differ
diff --git a/src/wp-includes/images/wlw/wp-comments.png b/src/wp-includes/images/wlw/wp-comments.png
new file mode 100644
index 0000000000..6bc3d523f4
--- /dev/null
+++ b/src/wp-includes/images/wlw/wp-comments.png
Binary files differ
diff --git a/src/wp-includes/images/wlw/wp-icon.png b/src/wp-includes/images/wlw/wp-icon.png
new file mode 100644
index 0000000000..c3523833aa
--- /dev/null
+++ b/src/wp-includes/images/wlw/wp-icon.png
Binary files differ
diff --git a/src/wp-includes/images/wlw/wp-watermark.png b/src/wp-includes/images/wlw/wp-watermark.png
new file mode 100644
index 0000000000..c9741fa02f
--- /dev/null
+++ b/src/wp-includes/images/wlw/wp-watermark.png
Binary files differ
diff --git a/src/wp-includes/images/wpicons-2x.png b/src/wp-includes/images/wpicons-2x.png
new file mode 100644
index 0000000000..07390dcb1e
--- /dev/null
+++ b/src/wp-includes/images/wpicons-2x.png
Binary files differ
diff --git a/src/wp-includes/images/wpicons.png b/src/wp-includes/images/wpicons.png
new file mode 100644
index 0000000000..8eef01eed8
--- /dev/null
+++ b/src/wp-includes/images/wpicons.png
Binary files differ
diff --git a/src/wp-includes/images/wpmini-blue-2x.png b/src/wp-includes/images/wpmini-blue-2x.png
new file mode 100644
index 0000000000..3bfb20a06d
--- /dev/null
+++ b/src/wp-includes/images/wpmini-blue-2x.png
Binary files differ
diff --git a/src/wp-includes/images/wpmini-blue.png b/src/wp-includes/images/wpmini-blue.png
new file mode 100644
index 0000000000..a619762050
--- /dev/null
+++ b/src/wp-includes/images/wpmini-blue.png
Binary files differ
diff --git a/src/wp-includes/images/wpspin-2x.gif b/src/wp-includes/images/wpspin-2x.gif
new file mode 100644
index 0000000000..fe2d5c0fcb
--- /dev/null
+++ b/src/wp-includes/images/wpspin-2x.gif
Binary files differ
diff --git a/src/wp-includes/images/wpspin.gif b/src/wp-includes/images/wpspin.gif
new file mode 100644
index 0000000000..e10b97ff9d
--- /dev/null
+++ b/src/wp-includes/images/wpspin.gif
Binary files differ
diff --git a/src/wp-includes/images/xit-2x.gif b/src/wp-includes/images/xit-2x.gif
new file mode 100644
index 0000000000..64ab2ce789
--- /dev/null
+++ b/src/wp-includes/images/xit-2x.gif
Binary files differ
diff --git a/src/wp-includes/images/xit.gif b/src/wp-includes/images/xit.gif
new file mode 100644
index 0000000000..80c251fdd7
--- /dev/null
+++ b/src/wp-includes/images/xit.gif
Binary files differ
diff --git a/src/wp-includes/js/admin-bar.js b/src/wp-includes/js/admin-bar.js
new file mode 100644
index 0000000000..b75823ce8b
--- /dev/null
+++ b/src/wp-includes/js/admin-bar.js
@@ -0,0 +1,343 @@
+// use jQuery and hoverIntent if loaded
+if ( typeof(jQuery) != 'undefined' ) {
+ if ( typeof(jQuery.fn.hoverIntent) == 'undefined' ) {
+ // hoverIntent r6 - Copy of wp-includes/js/hoverIntent.min.js
+ (function(a){a.fn.hoverIntent=function(m,d,h){var j={interval:100,sensitivity:7,timeout:0};if(typeof m==="object"){j=a.extend(j,m)}else{if(a.isFunction(d)){j=a.extend(j,{over:m,out:d,selector:h})}else{j=a.extend(j,{over:m,out:m,selector:d})}}var l,k,g,f;var e=function(n){l=n.pageX;k=n.pageY};var c=function(o,n){n.hoverIntent_t=clearTimeout(n.hoverIntent_t);if((Math.abs(g-l)+Math.abs(f-k))<j.sensitivity){a(n).off("mousemove.hoverIntent",e);n.hoverIntent_s=1;return j.over.apply(n,[o])}else{g=l;f=k;n.hoverIntent_t=setTimeout(function(){c(o,n)},j.interval)}};var i=function(o,n){n.hoverIntent_t=clearTimeout(n.hoverIntent_t);n.hoverIntent_s=0;return j.out.apply(n,[o])};var b=function(p){var o=jQuery.extend({},p);var n=this;if(n.hoverIntent_t){n.hoverIntent_t=clearTimeout(n.hoverIntent_t)}if(p.type=="mouseenter"){g=o.pageX;f=o.pageY;a(n).on("mousemove.hoverIntent",e);if(n.hoverIntent_s!=1){n.hoverIntent_t=setTimeout(function(){c(o,n)},j.interval)}}else{a(n).off("mousemove.hoverIntent",e);if(n.hoverIntent_s==1){n.hoverIntent_t=setTimeout(function(){i(o,n)},j.timeout)}}};return this.on({"mouseenter.hoverIntent":b,"mouseleave.hoverIntent":b},j.selector)}})(jQuery);
+ }
+ jQuery(document).ready(function($){
+ var adminbar = $('#wpadminbar'), refresh, touchOpen, touchClose, disableHoverIntent = false;
+
+ refresh = function(i, el){ // force the browser to refresh the tabbing index
+ var node = $(el), tab = node.attr('tabindex');
+ if ( tab )
+ node.attr('tabindex', '0').attr('tabindex', tab);
+ };
+
+ touchOpen = function(unbind) {
+ adminbar.find('li.menupop').on('click.wp-mobile-hover', function(e) {
+ var el = $(this);
+
+ if ( !el.hasClass('hover') ) {
+ e.preventDefault();
+ adminbar.find('li.menupop.hover').removeClass('hover');
+ el.addClass('hover');
+ }
+
+ if ( unbind ) {
+ $('li.menupop').off('click.wp-mobile-hover');
+ disableHoverIntent = false;
+ }
+ });
+ };
+
+ touchClose = function() {
+ var mobileEvent = /Mobile\/.+Safari/.test(navigator.userAgent) ? 'touchstart' : 'click';
+ // close any open drop-downs when the click/touch is not on the toolbar
+ $(document.body).on( mobileEvent+'.wp-mobile-hover', function(e) {
+ if ( !$(e.target).closest('#wpadminbar').length )
+ adminbar.find('li.menupop.hover').removeClass('hover');
+ });
+ };
+
+ adminbar.removeClass('nojq').removeClass('nojs');
+
+ if ( 'ontouchstart' in window ) {
+ adminbar.on('touchstart', function(){
+ touchOpen(true);
+ disableHoverIntent = true;
+ });
+ touchClose();
+ } else if ( /IEMobile\/[1-9]/.test(navigator.userAgent) ) {
+ touchOpen();
+ touchClose();
+ }
+
+ adminbar.find('li.menupop').hoverIntent({
+ over: function(e){
+ if ( disableHoverIntent )
+ return;
+
+ $(this).addClass('hover');
+ },
+ out: function(e){
+ if ( disableHoverIntent )
+ return;
+
+ $(this).removeClass('hover');
+ },
+ timeout: 180,
+ sensitivity: 7,
+ interval: 100
+ });
+
+ if ( window.location.hash )
+ window.scrollBy( 0, -32 );
+
+ $('#wp-admin-bar-get-shortlink').click(function(e){
+ e.preventDefault();
+ $(this).addClass('selected').children('.shortlink-input').blur(function(){
+ $(this).parents('#wp-admin-bar-get-shortlink').removeClass('selected');
+ }).focus().select();
+ });
+
+ $('#wpadminbar li.menupop > .ab-item').bind('keydown.adminbar', function(e){
+ if ( e.which != 13 )
+ return;
+
+ var target = $(e.target), wrap = target.closest('ab-sub-wrapper');
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ if ( !wrap.length )
+ wrap = $('#wpadminbar .quicklinks');
+
+ wrap.find('.menupop').removeClass('hover');
+ target.parent().toggleClass('hover');
+ target.siblings('.ab-sub-wrapper').find('.ab-item').each(refresh);
+ }).each(refresh);
+
+ $('#wpadminbar .ab-item').bind('keydown.adminbar', function(e){
+ if ( e.which != 27 )
+ return;
+
+ var target = $(e.target);
+
+ e.stopPropagation();
+ e.preventDefault();
+
+ target.closest('.hover').removeClass('hover').children('.ab-item').focus();
+ target.siblings('.ab-sub-wrapper').find('.ab-item').each(refresh);
+ });
+
+ $('#wpadminbar').click( function(e) {
+ if ( e.target.id != 'wpadminbar' && e.target.id != 'wp-admin-bar-top-secondary' )
+ return;
+
+ e.preventDefault();
+ $('html, body').animate({ scrollTop: 0 }, 'fast');
+ });
+
+ // fix focus bug in WebKit
+ $('.screen-reader-shortcut').keydown( function(e) {
+ if ( 13 != e.which )
+ return;
+
+ var id = $(this).attr('href');
+
+ var ua = navigator.userAgent.toLowerCase();
+ if ( ua.indexOf('applewebkit') != -1 && id && id.charAt(0) == '#' ) {
+ setTimeout(function () {
+ $(id).focus();
+ }, 100);
+ }
+ });
+
+ // Empty sessionStorage on logging out
+ if ( 'sessionStorage' in window ) {
+ $('#wp-admin-bar-logout a').click( function() {
+ try {
+ for ( var key in sessionStorage ) {
+ if ( key.indexOf('wp-autosave-') != -1 )
+ sessionStorage.removeItem(key);
+ }
+ } catch(e) {}
+ });
+ }
+ });
+} else {
+ (function(d, w) {
+ var addEvent = function( obj, type, fn ) {
+ if ( obj.addEventListener )
+ obj.addEventListener(type, fn, false);
+ else if ( obj.attachEvent )
+ obj.attachEvent('on' + type, function() { return fn.call(obj, window.event);});
+ },
+
+ aB, hc = new RegExp('\\bhover\\b', 'g'), q = [],
+ rselected = new RegExp('\\bselected\\b', 'g'),
+
+ /**
+ * Get the timeout ID of the given element
+ */
+ getTOID = function(el) {
+ var i = q.length;
+ while ( i-- ) {
+ if ( q[i] && el == q[i][1] )
+ return q[i][0];
+ }
+ return false;
+ },
+
+ addHoverClass = function(t) {
+ var i, id, inA, hovering, ul, li,
+ ancestors = [],
+ ancestorLength = 0;
+
+ while ( t && t != aB && t != d ) {
+ if ( 'LI' == t.nodeName.toUpperCase() ) {
+ ancestors[ ancestors.length ] = t;
+ id = getTOID(t);
+ if ( id )
+ clearTimeout( id );
+ t.className = t.className ? ( t.className.replace(hc, '') + ' hover' ) : 'hover';
+ hovering = t;
+ }
+ t = t.parentNode;
+ }
+
+ // Remove any selected classes.
+ if ( hovering && hovering.parentNode ) {
+ ul = hovering.parentNode;
+ if ( ul && 'UL' == ul.nodeName.toUpperCase() ) {
+ i = ul.childNodes.length;
+ while ( i-- ) {
+ li = ul.childNodes[i];
+ if ( li != hovering )
+ li.className = li.className ? li.className.replace( rselected, '' ) : '';
+ }
+ }
+ }
+
+ /* remove the hover class for any objects not in the immediate element's ancestry */
+ i = q.length;
+ while ( i-- ) {
+ inA = false;
+ ancestorLength = ancestors.length;
+ while( ancestorLength-- ) {
+ if ( ancestors[ ancestorLength ] == q[i][1] )
+ inA = true;
+ }
+
+ if ( ! inA )
+ q[i][1].className = q[i][1].className ? q[i][1].className.replace(hc, '') : '';
+ }
+ },
+
+ removeHoverClass = function(t) {
+ while ( t && t != aB && t != d ) {
+ if ( 'LI' == t.nodeName.toUpperCase() ) {
+ (function(t) {
+ var to = setTimeout(function() {
+ t.className = t.className ? t.className.replace(hc, '') : '';
+ }, 500);
+ q[q.length] = [to, t];
+ })(t);
+ }
+ t = t.parentNode;
+ }
+ },
+
+ clickShortlink = function(e) {
+ var i, l, node,
+ t = e.target || e.srcElement;
+
+ // Make t the shortlink menu item, or return.
+ while ( true ) {
+ // Check if we've gone past the shortlink node,
+ // or if the user is clicking on the input.
+ if ( ! t || t == d || t == aB )
+ return;
+ // Check if we've found the shortlink node.
+ if ( t.id && t.id == 'wp-admin-bar-get-shortlink' )
+ break;
+ t = t.parentNode;
+ }
+
+ // IE doesn't support preventDefault, and does support returnValue
+ if ( e.preventDefault )
+ e.preventDefault();
+ e.returnValue = false;
+
+ if ( -1 == t.className.indexOf('selected') )
+ t.className += ' selected';
+
+ for ( i = 0, l = t.childNodes.length; i < l; i++ ) {
+ node = t.childNodes[i];
+ if ( node.className && -1 != node.className.indexOf('shortlink-input') ) {
+ node.focus();
+ node.select();
+ node.onblur = function() {
+ t.className = t.className ? t.className.replace( rselected, '' ) : '';
+ };
+ break;
+ }
+ }
+ return false;
+ },
+
+ scrollToTop = function(t) {
+ var distance, speed, step, steps, timer, speed_step;
+
+ // Ensure that the #wpadminbar was the target of the click.
+ if ( t.id != 'wpadminbar' && t.id != 'wp-admin-bar-top-secondary' )
+ return;
+
+ distance = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
+
+ if ( distance < 1 )
+ return;
+
+ speed_step = distance > 800 ? 130 : 100;
+ speed = Math.min( 12, Math.round( distance / speed_step ) );
+ step = distance > 800 ? Math.round( distance / 30 ) : Math.round( distance / 20 );
+ steps = [];
+ timer = 0;
+
+ // Animate scrolling to the top of the page by generating steps to
+ // the top of the page and shifting to each step at a set interval.
+ while ( distance ) {
+ distance -= step;
+ if ( distance < 0 )
+ distance = 0;
+ steps.push( distance );
+
+ setTimeout( function() {
+ window.scrollTo( 0, steps.shift() );
+ }, timer * speed );
+
+ timer++;
+ }
+ };
+
+ addEvent(w, 'load', function() {
+ aB = d.getElementById('wpadminbar');
+
+ if ( d.body && aB ) {
+ d.body.appendChild( aB );
+
+ if ( aB.className )
+ aB.className = aB.className.replace(/nojs/, '');
+
+ addEvent(aB, 'mouseover', function(e) {
+ addHoverClass( e.target || e.srcElement );
+ });
+
+ addEvent(aB, 'mouseout', function(e) {
+ removeHoverClass( e.target || e.srcElement );
+ });
+
+ addEvent(aB, 'click', clickShortlink );
+
+ addEvent(aB, 'click', function(e) {
+ scrollToTop( e.target || e.srcElement );
+ });
+
+ addEvent( document.getElementById('wp-admin-bar-logout'), 'click', function() {
+ if ( 'sessionStorage' in window ) {
+ try {
+ for ( var key in sessionStorage ) {
+ if ( key.indexOf('wp-autosave-') != -1 )
+ sessionStorage.removeItem(key);
+ }
+ } catch(e) {}
+ }
+ });
+ }
+
+ if ( w.location.hash )
+ w.scrollBy(0,-32);
+ });
+ })(document, window);
+
+}
diff --git a/src/wp-includes/js/autosave.js b/src/wp-includes/js/autosave.js
new file mode 100644
index 0000000000..6cd6a47fd7
--- /dev/null
+++ b/src/wp-includes/js/autosave.js
@@ -0,0 +1,702 @@
+var autosave, autosaveLast = '', autosavePeriodical, autosaveDelayPreview = false, notSaved = true, blockSave = false, fullscreen, autosaveLockRelease = true;
+
+jQuery(document).ready( function($) {
+
+ if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' ) {
+ autosaveLast = wp.autosave.getCompareString({
+ post_title : $('#title').val() || '',
+ content : switchEditors.pre_wpautop( $('#content').val() ) || '',
+ excerpt : $('#excerpt').val() || ''
+ });
+ } else {
+ autosaveLast = wp.autosave.getCompareString();
+ }
+
+ autosavePeriodical = $.schedule({time: autosaveL10n.autosaveInterval * 1000, func: function() { autosave(); }, repeat: true, protect: true});
+
+ //Disable autosave after the form has been submitted
+ $("#post").submit(function() {
+ $.cancel(autosavePeriodical);
+ autosaveLockRelease = false;
+ });
+
+ $('input[type="submit"], a.submitdelete', '#submitpost').click(function(){
+ blockSave = true;
+ window.onbeforeunload = null;
+ $(':button, :submit', '#submitpost').each(function(){
+ var t = $(this);
+ if ( t.hasClass('button-primary') )
+ t.addClass('button-primary-disabled');
+ else
+ t.addClass('button-disabled');
+ });
+ if ( $(this).attr('id') == 'publish' )
+ $('#major-publishing-actions .spinner').show();
+ else
+ $('#minor-publishing .spinner').show();
+ });
+
+ window.onbeforeunload = function(){
+ var editor = typeof(tinymce) != 'undefined' ? tinymce.activeEditor : false, compareString;
+
+ if ( editor && ! editor.isHidden() ) {
+ if ( editor.isDirty() )
+ return autosaveL10n.saveAlert;
+ } else {
+ if ( fullscreen && fullscreen.settings.visible ) {
+ compareString = wp.autosave.getCompareString({
+ post_title: $('#wp-fullscreen-title').val() || '',
+ content: $('#wp_mce_fullscreen').val() || '',
+ excerpt: $('#excerpt').val() || ''
+ });
+ } else {
+ compareString = wp.autosave.getCompareString();
+ }
+
+ if ( compareString != autosaveLast )
+ return autosaveL10n.saveAlert;
+ }
+ };
+
+ $(window).unload( function(e) {
+ if ( ! autosaveLockRelease )
+ return;
+
+ // unload fires (twice) on removing the Thickbox iframe. Make sure we process only the main document unload.
+ if ( e.target && e.target.nodeName != '#document' )
+ return;
+
+ $.ajax({
+ type: 'POST',
+ url: ajaxurl,
+ async: false,
+ data: {
+ action: 'wp-remove-post-lock',
+ _wpnonce: $('#_wpnonce').val(),
+ post_ID: $('#post_ID').val(),
+ active_post_lock: $('#active_post_lock').val()
+ }
+ });
+ } );
+
+ // preview
+ $('#post-preview').click(function(){
+ if ( $('#auto_draft').val() == '1' && notSaved ) {
+ autosaveDelayPreview = true;
+ autosave();
+ return false;
+ }
+ doPreview();
+ return false;
+ });
+
+ doPreview = function() {
+ $('input#wp-preview').val('dopreview');
+ $('form#post').attr('target', 'wp-preview').submit().attr('target', '');
+
+ /*
+ * Workaround for WebKit bug preventing a form submitting twice to the same action.
+ * https://bugs.webkit.org/show_bug.cgi?id=28633
+ */
+ var ua = navigator.userAgent.toLowerCase();
+ if ( ua.indexOf('safari') != -1 && ua.indexOf('chrome') == -1 ) {
+ $('form#post').attr('action', function(index, value) {
+ return value + '?t=' + new Date().getTime();
+ });
+ }
+
+ $('input#wp-preview').val('');
+ }
+
+ // This code is meant to allow tabbing from Title to Post content.
+ $('#title').on('keydown.editor-focus', function(e) {
+ var ed;
+
+ if ( e.which != 9 )
+ return;
+
+ if ( !e.ctrlKey && !e.altKey && !e.shiftKey ) {
+ if ( typeof(tinymce) != 'undefined' )
+ ed = tinymce.get('content');
+
+ if ( ed && !ed.isHidden() ) {
+ $(this).one('keyup', function(e){
+ $('#content_tbl td.mceToolbar > a').focus();
+ });
+ } else {
+ $('#content').focus();
+ }
+
+ e.preventDefault();
+ }
+ });
+
+ // autosave new posts after a title is typed but not if Publish or Save Draft is clicked
+ if ( '1' == $('#auto_draft').val() ) {
+ $('#title').blur( function() {
+ if ( !this.value || $('#auto_draft').val() != '1' )
+ return;
+ delayed_autosave();
+ });
+ }
+
+ // When connection is lost, keep user from submitting changes.
+ $(document).on('heartbeat-connection-lost.autosave', function( e, error ) {
+ if ( 'timeout' === error ) {
+ var notice = $('#lost-connection-notice');
+ if ( ! wp.autosave.local.hasStorage ) {
+ notice.find('.hide-if-no-sessionstorage').hide();
+ }
+ notice.show();
+ autosave_disable_buttons();
+ }
+ }).on('heartbeat-connection-restored.autosave', function() {
+ $('#lost-connection-notice').hide();
+ autosave_enable_buttons();
+ });
+});
+
+function autosave_parse_response( response ) {
+ var res = wpAjax.parseAjaxResponse(response, 'autosave'), post_id, sup;
+
+ if ( res && res.responses && res.responses.length ) {
+ if ( res.responses[0].supplemental ) {
+ sup = res.responses[0].supplemental;
+
+ jQuery.each( sup, function( selector, value ) {
+ if ( selector.match(/^replace-/) )
+ jQuery( '#' + selector.replace('replace-', '') ).val( value );
+ });
+ }
+
+ // if no errors: add slug UI and update autosave-message
+ if ( !res.errors ) {
+ if ( post_id = parseInt( res.responses[0].id, 10 ) )
+ autosave_update_slug( post_id );
+
+ if ( res.responses[0].data ) // update autosave message
+ jQuery('.autosave-message').text( res.responses[0].data );
+ }
+ }
+
+ return res;
+}
+
+// called when autosaving pre-existing post
+function autosave_saved(response) {
+ blockSave = false;
+ autosave_parse_response(response); // parse the ajax response
+ autosave_enable_buttons(); // re-enable disabled form buttons
+}
+
+// called when autosaving new post
+function autosave_saved_new(response) {
+ blockSave = false;
+ var res = autosave_parse_response(response), post_id;
+
+ if ( res && res.responses.length && !res.errors ) {
+ // An ID is sent only for real auto-saves, not for autosave=0 "keepalive" saves
+ post_id = parseInt( res.responses[0].id, 10 );
+
+ if ( post_id ) {
+ notSaved = false;
+ jQuery('#auto_draft').val('0'); // No longer an auto-draft
+ }
+
+ autosave_enable_buttons();
+
+ if ( autosaveDelayPreview ) {
+ autosaveDelayPreview = false;
+ doPreview();
+ }
+ } else {
+ autosave_enable_buttons(); // re-enable disabled form buttons
+ }
+}
+
+function autosave_update_slug(post_id) {
+ // create slug area only if not already there
+ if ( 'undefined' != makeSlugeditClickable && jQuery.isFunction(makeSlugeditClickable) && !jQuery('#edit-slug-box > *').size() ) {
+ jQuery.post( ajaxurl, {
+ action: 'sample-permalink',
+ post_id: post_id,
+ new_title: fullscreen && fullscreen.settings.visible ? jQuery('#wp-fullscreen-title').val() : jQuery('#title').val(),
+ samplepermalinknonce: jQuery('#samplepermalinknonce').val()
+ },
+ function(data) {
+ if ( data !== '-1' ) {
+ var box = jQuery('#edit-slug-box');
+ box.html(data);
+ if (box.hasClass('hidden')) {
+ box.fadeIn('fast', function () {
+ box.removeClass('hidden');
+ });
+ }
+ makeSlugeditClickable();
+ }
+ }
+ );
+ }
+}
+
+function autosave_loading() {
+ jQuery('.autosave-message').html(autosaveL10n.savingText);
+}
+
+function autosave_enable_buttons() {
+ jQuery(document).trigger('autosave-enable-buttons');
+ if ( ! wp.heartbeat || ! wp.heartbeat.hasConnectionError() ) {
+ // delay that a bit to avoid some rare collisions while the DOM is being updated.
+ setTimeout(function(){
+ var parent = jQuery('#submitpost');
+ parent.find(':button, :submit').removeAttr('disabled');
+ parent.find('.spinner').hide();
+ }, 500);
+ }
+}
+
+function autosave_disable_buttons() {
+ jQuery(document).trigger('autosave-disable-buttons');
+ jQuery('#submitpost').find(':button, :submit').prop('disabled', true);
+ // Re-enable 5 sec later. Just gives autosave a head start to avoid collisions.
+ setTimeout( autosave_enable_buttons, 5000 );
+}
+
+function delayed_autosave() {
+ setTimeout(function(){
+ if ( blockSave )
+ return;
+ autosave();
+ }, 200);
+}
+
+autosave = function() {
+ var post_data = wp.autosave.getPostData(),
+ compareString,
+ successCallback;
+
+ blockSave = true;
+
+ // post_data.content cannot be retrieved at the moment
+ if ( ! post_data.autosave )
+ return false;
+
+ // No autosave while thickbox is open (media buttons)
+ if ( jQuery("#TB_window").css('display') == 'block' )
+ return false;
+
+ compareString = wp.autosave.getCompareString( post_data );
+
+ // Nothing to save or no change.
+ if ( compareString == autosaveLast )
+ return false;
+
+ autosaveLast = compareString;
+ jQuery(document).triggerHandler('wpcountwords', [ post_data["content"] ]);
+
+ // Disable buttons until we know the save completed.
+ autosave_disable_buttons();
+
+ if ( post_data["auto_draft"] == '1' ) {
+ successCallback = autosave_saved_new; // new post
+ } else {
+ successCallback = autosave_saved; // pre-existing post
+ }
+
+ jQuery.ajax({
+ data: post_data,
+ beforeSend: autosave_loading,
+ type: "POST",
+ url: ajaxurl,
+ success: successCallback
+ });
+
+ return true;
+}
+
+// Autosave in localStorage
+// set as simple object/mixin for now
+window.wp = window.wp || {};
+wp.autosave = wp.autosave || {};
+
+(function($){
+// Returns the data for saving in both localStorage and autosaves to the server
+wp.autosave.getPostData = function() {
+ var ed = typeof tinymce != 'undefined' ? tinymce.activeEditor : null, post_name, parent_id, cats = [],
+ data = {
+ action: 'autosave',
+ autosave: true,
+ post_id: $('#post_ID').val() || 0,
+ autosavenonce: $('#autosavenonce').val() || '',
+ post_type: $('#post_type').val() || '',
+ post_author: $('#post_author').val() || '',
+ excerpt: $('#excerpt').val() || ''
+ };
+
+ if ( ed && !ed.isHidden() ) {
+ // Don't run while the tinymce spellcheck is on. It resets all found words.
+ if ( ed.plugins.spellchecker && ed.plugins.spellchecker.active ) {
+ data.autosave = false;
+ return data;
+ } else {
+ if ( 'mce_fullscreen' == ed.id )
+ tinymce.get('content').setContent(ed.getContent({format : 'raw'}), {format : 'raw'});
+
+ tinymce.triggerSave();
+ }
+ }
+
+ if ( typeof fullscreen != 'undefined' && fullscreen.settings.visible ) {
+ data['post_title'] = $('#wp-fullscreen-title').val() || '';
+ data['content'] = $('#wp_mce_fullscreen').val() || '';
+ } else {
+ data['post_title'] = $('#title').val() || '';
+ data['content'] = $('#content').val() || '';
+ }
+
+ /*
+ // We haven't been saving tags with autosave since 2.8... Start again?
+ $('.the-tags').each( function() {
+ data[this.name] = this.value;
+ });
+ */
+
+ $('input[id^="in-category-"]:checked').each( function() {
+ cats.push(this.value);
+ });
+ data['catslist'] = cats.join(',');
+
+ if ( post_name = $('#post_name').val() )
+ data['post_name'] = post_name;
+
+ if ( parent_id = $('#parent_id').val() )
+ data['parent_id'] = parent_id;
+
+ if ( $('#comment_status').prop('checked') )
+ data['comment_status'] = 'open';
+
+ if ( $('#ping_status').prop('checked') )
+ data['ping_status'] = 'open';
+
+ if ( $('#auto_draft').val() == '1' )
+ data['auto_draft'] = '1';
+
+ return data;
+};
+
+// Concatenate title, content and excerpt. Used to track changes when auto-saving.
+wp.autosave.getCompareString = function( post_data ) {
+ if ( typeof post_data === 'object' ) {
+ return ( post_data.post_title || '' ) + '::' + ( post_data.content || '' ) + '::' + ( post_data.excerpt || '' );
+ }
+
+ return ( $('#title').val() || '' ) + '::' + ( $('#content').val() || '' ) + '::' + ( $('#excerpt').val() || '' );
+};
+
+wp.autosave.local = {
+
+ lastSavedData: '',
+ blog_id: 0,
+ hasStorage: false,
+
+ // Check if the browser supports sessionStorage and it's not disabled
+ checkStorage: function() {
+ var test = Math.random(), result = false;
+
+ try {
+ sessionStorage.setItem('wp-test', test);
+ result = sessionStorage.getItem('wp-test') == test;
+ sessionStorage.removeItem('wp-test');
+ } catch(e) {}
+
+ this.hasStorage = result;
+ return result;
+ },
+
+ /**
+ * Initialize the local storage
+ *
+ * @return mixed False if no sessionStorage in the browser or an Object containing all post_data for this blog
+ */
+ getStorage: function() {
+ var stored_obj = false;
+ // Separate local storage containers for each blog_id
+ if ( this.hasStorage && this.blog_id ) {
+ stored_obj = sessionStorage.getItem( 'wp-autosave-' + this.blog_id );
+
+ if ( stored_obj )
+ stored_obj = JSON.parse( stored_obj );
+ else
+ stored_obj = {};
+ }
+
+ return stored_obj;
+ },
+
+ /**
+ * Set the storage for this blog
+ *
+ * Confirms that the data was saved successfully.
+ *
+ * @return bool
+ */
+ setStorage: function( stored_obj ) {
+ var key;
+
+ if ( this.hasStorage && this.blog_id ) {
+ key = 'wp-autosave-' + this.blog_id;
+ sessionStorage.setItem( key, JSON.stringify( stored_obj ) );
+ return sessionStorage.getItem( key ) !== null;
+ }
+
+ return false;
+ },
+
+ /**
+ * Get the saved post data for the current post
+ *
+ * @return mixed False if no storage or no data or the post_data as an Object
+ */
+ getData: function() {
+ var stored = this.getStorage(), post_id = $('#post_ID').val();
+
+ if ( !stored || !post_id )
+ return false;
+
+ return stored[ 'post_' + post_id ] || false;
+ },
+
+ /**
+ * Set (save or delete) post data in the storage.
+ *
+ * If stored_data evaluates to 'false' the storage key for the current post will be removed
+ *
+ * $param stored_data The post data to store or null/false/empty to delete the key
+ * @return bool
+ */
+ setData: function( stored_data ) {
+ var stored = this.getStorage(), post_id = $('#post_ID').val();
+
+ if ( !stored || !post_id )
+ return false;
+
+ if ( stored_data )
+ stored[ 'post_' + post_id ] = stored_data;
+ else if ( stored.hasOwnProperty( 'post_' + post_id ) )
+ delete stored[ 'post_' + post_id ];
+ else
+ return false;
+
+ return this.setStorage(stored);
+ },
+
+ /**
+ * Save post data for the current post
+ *
+ * Runs on a 15 sec. schedule, saves when there are differences in the post title or content.
+ * When the optional data is provided, updates the last saved post data.
+ *
+ * $param data optional Object The post data for saving, minimum 'post_title' and 'content'
+ * @return bool
+ */
+ save: function( data ) {
+ var result = false, post_data, compareString;
+
+ if ( ! data ) {
+ post_data = wp.autosave.getPostData();
+ } else {
+ post_data = this.getData() || {};
+ $.extend( post_data, data );
+ post_data.autosave = true;
+ }
+
+ // Cannot get the post data at the moment
+ if ( ! post_data.autosave )
+ return false;
+
+ compareString = wp.autosave.getCompareString( post_data );
+
+ // If the content, title and excerpt did not change since the last save, don't save again
+ if ( compareString == this.lastSavedData )
+ return false;
+
+ post_data['save_time'] = (new Date()).getTime();
+ post_data['status'] = $('#post_status').val() || '';
+ result = this.setData( post_data );
+
+ if ( result )
+ this.lastSavedData = compareString;
+
+ return result;
+ },
+
+ // Initialize and run checkPost() on loading the script (before TinyMCE init)
+ init: function( settings ) {
+ var self = this;
+
+ // Check if the browser supports sessionStorage and it's not disabled
+ if ( ! this.checkStorage() )
+ return;
+
+ // Don't run if the post type supports neither 'editor' (textarea#content) nor 'excerpt'.
+ if ( ! $('#content').length && ! $('#excerpt').length )
+ return;
+
+ if ( settings )
+ $.extend( this, settings );
+
+ if ( !this.blog_id )
+ this.blog_id = typeof window.autosaveL10n != 'undefined' ? window.autosaveL10n.blog_id : 0;
+
+ $(document).ready( function(){ self.run(); } );
+ },
+
+ // Run on DOM ready
+ run: function() {
+ var self = this;
+
+ // Check if the local post data is different than the loaded post data.
+ this.checkPost();
+
+ // Set the schedule
+ this.schedule = $.schedule({
+ time: 15 * 1000,
+ func: function() { wp.autosave.local.save(); },
+ repeat: true,
+ protect: true
+ });
+
+ $('form#post').on('submit.autosave-local', function() {
+ var editor = typeof tinymce != 'undefined' && tinymce.get('content'), post_id = $('#post_ID').val() || 0;
+
+ if ( editor && ! editor.isHidden() ) {
+ // Last onSubmit event in the editor, needs to run after the content has been moved to the textarea.
+ editor.onSubmit.add( function() {
+ wp.autosave.local.save({
+ post_title: $('#title').val() || '',
+ content: $('#content').val() || '',
+ excerpt: $('#excerpt').val() || ''
+ });
+ });
+ } else {
+ self.save({
+ post_title: $('#title').val() || '',
+ content: $('#content').val() || '',
+ excerpt: $('#excerpt').val() || ''
+ });
+ }
+
+ wpCookies.set( 'wp-saving-post-' + post_id, 'check' );
+ });
+ },
+
+ // Strip whitespace and compare two strings
+ compare: function( str1, str2 ) {
+ function remove( string ) {
+ return string.toString().replace(/[\x20\t\r\n\f]+/g, '');
+ }
+
+ return ( remove( str1 || '' ) == remove( str2 || '' ) );
+ },
+
+ /**
+ * Check if the saved data for the current post (if any) is different than the loaded post data on the screen
+ *
+ * Shows a standard message letting the user restore the post data if different.
+ *
+ * @return void
+ */
+ checkPost: function() {
+ var self = this, post_data = this.getData(), content, post_title, excerpt, notice,
+ post_id = $('#post_ID').val() || 0, cookie = wpCookies.get( 'wp-saving-post-' + post_id );
+
+ if ( ! post_data )
+ return;
+
+ if ( cookie ) {
+ wpCookies.remove( 'wp-saving-post-' + post_id );
+
+ if ( cookie == 'saved' ) {
+ // The post was saved properly, remove old data and bail
+ this.setData( false );
+ return;
+ }
+ }
+
+ // There is a newer autosave. Don't show two "restore" notices at the same time.
+ if ( $('#has-newer-autosave').length )
+ return;
+
+ content = $('#content').val() || '';
+ post_title = $('#title').val() || '';
+ excerpt = $('#excerpt').val() || '';
+
+ if ( $('#wp-content-wrap').hasClass('tmce-active') && typeof switchEditors != 'undefined' )
+ content = switchEditors.pre_wpautop( content );
+
+ // cookie == 'check' means the post was not saved properly, always show #local-storage-notice
+ if ( cookie != 'check' && this.compare( content, post_data.content ) && this.compare( post_title, post_data.post_title ) && this.compare( excerpt, post_data.excerpt ) ) {
+ return;
+ }
+
+ this.restore_post_data = post_data;
+ this.undo_post_data = {
+ content: content,
+ post_title: post_title,
+ excerpt: excerpt
+ };
+
+ notice = $('#local-storage-notice');
+ $('.wrap h2').first().after( notice.addClass('updated').show() );
+
+ notice.on( 'click', function(e) {
+ var target = $( e.target );
+
+ if ( target.hasClass('restore-backup') ) {
+ self.restorePost( self.restore_post_data );
+ target.parent().hide();
+ $(this).find('p.undo-restore').show();
+ } else if ( target.hasClass('undo-restore-backup') ) {
+ self.restorePost( self.undo_post_data );
+ target.parent().hide();
+ $(this).find('p.local-restore').show();
+ }
+
+ e.preventDefault();
+ });
+ },
+
+ // Restore the current title, content and excerpt from post_data.
+ restorePost: function( post_data ) {
+ var editor;
+
+ if ( post_data ) {
+ // Set the last saved data
+ this.lastSavedData = wp.autosave.getCompareString( post_data );
+
+ if ( $('#title').val() != post_data.post_title )
+ $('#title').focus().val( post_data.post_title || '' );
+
+ $('#excerpt').val( post_data.excerpt || '' );
+ editor = typeof tinymce != 'undefined' && tinymce.get('content');
+
+ if ( editor && ! editor.isHidden() && typeof switchEditors != 'undefined' ) {
+ // Make sure there's an undo level in the editor
+ editor.undoManager.add();
+ editor.setContent( post_data.content ? switchEditors.wpautop( post_data.content ) : '' );
+ } else {
+ // Make sure the Text editor is selected
+ $('#content-html').click();
+ $('#content').val( post_data.content );
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+};
+
+wp.autosave.local.init();
+
+}(jQuery));
diff --git a/src/wp-includes/js/backbone.min.js b/src/wp-includes/js/backbone.min.js
new file mode 100644
index 0000000000..8555ecaf29
--- /dev/null
+++ b/src/wp-includes/js/backbone.min.js
@@ -0,0 +1,7 @@
+// Backbone.js 1.0.0
+
+// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
+// Backbone may be freely distributed under the MIT license.
+// For all details and documentation:
+// http://backbonejs.org
+(function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.0.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o<u;o++){t=a[o];if(n=this._events[t]){this._events[t]=r=[];if(e||i){for(c=0,f=n.length;c<f;c++){s=n[c];if(e&&e!==s.callback&&e!==s.callback._callback||i&&i!==s.context){r.push(s)}}}if(!r.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=s.call(arguments,1);if(!l(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)c(i,e);if(r)c(r,arguments);return this},stopListening:function(t,e,i){var r=this._listeners;if(!r)return this;var s=!e&&!i;if(typeof e==="object")i=this;if(t)(r={})[t._listenerId]=t;for(var n in r){r[n].off(e,i,this);if(s)delete this._listeners[n]}return this}};var u=/\s+/;var l=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(u.test(i)){var n=i.split(u);for(var a=0,h=n.length;a<h;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var c=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],h=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,h);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e)}};var f={listenTo:"on",listenToOnce:"once"};h.each(f,function(t,e){o[e]=function(e,i,r){var s=this._listeners||(this._listeners={});var n=e._listenerId||(e._listenerId=h.uniqueId("l"));s[n]=e;if(typeof i==="object")r=this;e[t](i,r,this);return this}});o.bind=o.on;o.unbind=o.off;h.extend(a,o);var d=a.Model=function(t,e){var i;var r=t||{};e||(e={});this.cid=h.uniqueId("c");this.attributes={};h.extend(this,h.pick(e,p));if(e.parse)r=this.parse(r,e)||{};if(i=h.result(this,"defaults")){r=h.defaults({},r,i)}this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};var p=["url","urlRoot","collection"];h.extend(d.prototype,o,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return h.clone(this.attributes)},sync:function(){return a.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return h.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,i){var r,s,n,a,o,u,l,c;if(t==null)return this;if(typeof t==="object"){s=t;i=e}else{(s={})[t]=e}i||(i={});if(!this._validate(s,i))return false;n=i.unset;o=i.silent;a=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=h.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in s)this.id=s[this.idAttribute];for(r in s){e=s[r];if(!h.isEqual(c[r],e))a.push(r);if(!h.isEqual(l[r],e)){this.changed[r]=e}else{delete this.changed[r]}n?delete c[r]:c[r]=e}if(!o){if(a.length)this._pending=true;for(var f=0,d=a.length;f<d;f++){this.trigger("change:"+a[f],this,c[a[f]],i)}}if(u)return this;if(!o){while(this._pending){this._pending=false;this.trigger("change",this,i)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,h.extend({},e,{unset:true}))},clear:function(t){var e={};for(var i in this.attributes)e[i]=void 0;return this.set(e,h.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!h.isEmpty(this.changed);return h.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?h.clone(this.changed):false;var e,i=false;var r=this._changing?this._previousAttributes:this.attributes;for(var s in t){if(h.isEqual(r[s],e=t[s]))continue;(i||(i={}))[s]=e}return i},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return h.clone(this._previousAttributes)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var i=t.success;t.success=function(r){if(!e.set(e.parse(r,t),t))return false;if(i)i(e,r,t);e.trigger("sync",e,r,t)};R(this,t);return this.sync("read",this,t)},save:function(t,e,i){var r,s,n,a=this.attributes;if(t==null||typeof t==="object"){r=t;i=e}else{(r={})[t]=e}if(r&&(!i||!i.wait)&&!this.set(r,i))return false;i=h.extend({validate:true},i);if(!this._validate(r,i))return false;if(r&&i.wait){this.attributes=h.extend({},a,r)}if(i.parse===void 0)i.parse=true;var o=this;var u=i.success;i.success=function(t){o.attributes=a;var e=o.parse(t,i);if(i.wait)e=h.extend(r||{},e);if(h.isObject(e)&&!o.set(e,i)){return false}if(u)u(o,t,i);o.trigger("sync",o,t,i)};R(this,i);s=this.isNew()?"create":i.patch?"patch":"update";if(s==="patch")i.attrs=r;n=this.sync(s,this,i);if(r&&i.wait)this.attributes=a;return n},destroy:function(t){t=t?h.clone(t):{};var e=this;var i=t.success;var r=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(s){if(t.wait||e.isNew())r();if(i)i(e,s,t);if(!e.isNew())e.trigger("sync",e,s,t)};if(this.isNew()){t.success();return false}R(this,t);var s=this.sync("delete",this,t);if(!t.wait)r();return s},url:function(){var t=h.result(this,"urlRoot")||h.result(this.collection,"url")||U();if(this.isNew())return t;return t+(t.charAt(t.length-1)==="/"?"":"/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return this.id==null},isValid:function(t){return this._validate({},h.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=h.extend({},this.attributes,t);var i=this.validationError=this.validate(t,e)||null;if(!i)return true;this.trigger("invalid",this,i,h.extend(e||{},{validationError:i}));return false}});var v=["keys","values","pairs","invert","pick","omit"];h.each(v,function(t){d.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.attributes);return h[t].apply(h,e)}});var g=a.Collection=function(t,e){e||(e={});if(e.url)this.url=e.url;if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,h.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,merge:false,remove:false};h.extend(g.prototype,o,{model:d,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return a.sync.apply(this,arguments)},add:function(t,e){return this.set(t,h.defaults(e||{},y))},remove:function(t,e){t=h.isArray(t)?t.slice():[t];e||(e={});var i,r,s,n;for(i=0,r=t.length;i<r;i++){n=this.get(t[i]);if(!n)continue;delete this._byId[n.id];delete this._byId[n.cid];s=this.indexOf(n);this.models.splice(s,1);this.length--;if(!e.silent){e.index=s;n.trigger("remove",n,this,e)}this._removeReference(n)}return this},set:function(t,e){e=h.defaults(e||{},m);if(e.parse)t=this.parse(t,e);if(!h.isArray(t))t=t?[t]:[];var i,s,a,o,u,l;var c=e.at;var f=this.comparator&&c==null&&e.sort!==false;var d=h.isString(this.comparator)?this.comparator:null;var p=[],v=[],g={};for(i=0,s=t.length;i<s;i++){if(!(a=this._prepareModel(t[i],e)))continue;if(u=this.get(a)){if(e.remove)g[u.cid]=true;if(e.merge){u.set(a.attributes,e);if(f&&!l&&u.hasChanged(d))l=true}}else if(e.add){p.push(a);a.on("all",this._onModelEvent,this);this._byId[a.cid]=a;if(a.id!=null)this._byId[a.id]=a}}if(e.remove){for(i=0,s=this.length;i<s;++i){if(!g[(a=this.models[i]).cid])v.push(a)}if(v.length)this.remove(v,e)}if(p.length){if(f)l=true;this.length+=p.length;if(c!=null){n.apply(this.models,[c,0].concat(p))}else{r.apply(this.models,p)}}if(l)this.sort({silent:true});if(e.silent)return this;for(i=0,s=p.length;i<s;i++){(a=p[i]).trigger("add",a,this,e)}if(l)this.trigger("sort",this,e);return this},reset:function(t,e){e||(e={});for(var i=0,r=this.models.length;i<r;i++){this._removeReference(this.models[i])}e.previousModels=this.models;this._reset();this.add(t,h.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return this},push:function(t,e){t=this._prepareModel(t,e);this.add(t,h.extend({at:this.length},e));return t},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){t=this._prepareModel(t,e);this.add(t,h.extend({at:0},e));return t},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(t,e){return this.models.slice(t,e)},get:function(t){if(t==null)return void 0;return this._byId[t.id!=null?t.id:t.cid||t]},at:function(t){return this.models[t]},where:function(t,e){if(h.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(h.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(h.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},sortedIndex:function(t,e,i){e||(e=this.comparator);var r=h.isFunction(e)?e:function(t){return t.get(e)};return h.sortedIndex(this.models,t,r,i)},pluck:function(t){return h.invoke(this.models,"get",t)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var i=this;t.success=function(r){var s=t.reset?"reset":"set";i[s](r,t);if(e)e(i,r,t);i.trigger("sync",i,r,t)};R(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?h.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var i=this;var r=e.success;e.success=function(s){if(e.wait)i.add(t,e);if(r)r(t,s,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof d){if(!t.collection)t.collection=this;return t}e||(e={});e.collection=this;var i=new this.model(t,e);if(!i._validate(t,e)){this.trigger("invalid",this,t,e);return false}return i},_removeReference:function(t){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","indexOf","shuffle","lastIndexOf","isEmpty","chain"];h.each(_,function(t){g.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.models);return h[t].apply(h,e)}});var w=["groupBy","countBy","sortBy"];h.each(w,function(t){g.prototype[t]=function(e,i){var r=h.isFunction(e)?e:function(t){return t.get(e)};return h[t](this.models,r,i)}});var b=a.View=function(t){this.cid=h.uniqueId("view");this._configure(t||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\S+)\s*(.*)$/;var E=["model","collection","el","id","attributes","className","tagName","events"];h.extend(b.prototype,o,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,e){if(this.$el)this.undelegateEvents();this.$el=t instanceof a.$?t:a.$(t);this.el=this.$el[0];if(e!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=h.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var i=t[e];if(!h.isFunction(i))i=this[t[e]];if(!i)continue;var r=e.match(x);var s=r[1],n=r[2];i=h.bind(i,this);s+=".delegateEvents"+this.cid;if(n===""){this.$el.on(s,i)}else{this.$el.on(s,n,i)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_configure:function(t){if(this.options)t=h.extend({},h.result(this,"options"),t);h.extend(this,h.pick(t,E));this.options=t},_ensureElement:function(){if(!this.el){var t=h.extend({},h.result(this,"attributes"));if(this.id)t.id=h.result(this,"id");if(this.className)t["class"]=h.result(this,"className");var e=a.$("<"+h.result(this,"tagName")+">").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=k[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&window.ActiveXObject&&!(window.external&&window.external.msActiveXFilteringEnabled)){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var k={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var S=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var $=/\((.*?)\)/g;var T=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(S.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace($,"(?:$1)?").replace(T,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var P=/^\/+|\/+$/g;var O=/msie [\w.]+/;var C=/\/$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.substr(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({},{root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=O.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(P,"/");if(r&&this._wantsHashChange){this.iframe=a.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;this.navigate(e)}if(this._hasPushState){a.$(window).on("popstate",this.checkUrl)}else if(this._wantsHashChange&&"onhashchange"in window&&!r){a.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=e;var s=this.location;var n=s.pathname.replace(/[^\/]$/,"$&/")===this.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!n){this.fragment=this.getFragment(null,true);this.location.replace(this.root+this.location.search+"#"+this.fragment);return true}else if(this._wantsPushState&&this._hasPushState&&n&&s.hash){this.fragment=this.getHash().replace(N,"");this.history.replaceState({},document.title,this.root+this.fragment+s.search)}if(!this.options.silent)return this.loadUrl()},stop:function(){a.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);I.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(t){var e=this.fragment=this.getFragment(t);var i=h.any(this.handlers,function(t){if(t.route.test(e)){t.callback(e);return true}});return i},navigate:function(t,e){if(!I.started)return false;if(!e||e===true)e={trigger:e};t=this.getFragment(t||"");if(this.fragment===t)return;this.fragment=t;var i=this.root+t;if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});a.history=new I;var j=function(t,e){var i=this;var r;if(t&&h.has(t,"constructor")){r=t.constructor}else{r=function(){return i.apply(this,arguments)}}h.extend(r,i,e);var s=function(){this.constructor=r};s.prototype=i.prototype;r.prototype=new s;if(t)h.extend(r.prototype,t);r.__super__=i.prototype;return r};d.extend=g.extend=S.extend=b.extend=I.extend=j;var U=function(){throw new Error('A "url" property or function must be specified')};var R=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}}}).call(this);
diff --git a/src/wp-includes/js/colorpicker.js b/src/wp-includes/js/colorpicker.js
new file mode 100644
index 0000000000..61c94bb9b3
--- /dev/null
+++ b/src/wp-includes/js/colorpicker.js
@@ -0,0 +1,707 @@
+// ===================================================================
+// Author: Matt Kruse <matt@mattkruse.com>
+// WWW: http://www.mattkruse.com/
+//
+// NOTICE: You may use this code for any purpose, commercial or
+// private, without any further permission from the author. You may
+// remove this notice from your final code if you wish, however it is
+// appreciated by the author if at least my web site address is kept.
+//
+// You may *NOT* re-distribute this code in any way except through its
+// use. That means, you can include it in your product, or your web
+// site, or any other form where the code is actually being used. You
+// may not put the plain javascript up on your site for download or
+// include it in your javascript libraries for download.
+// If you wish to share this code with others, please just point them
+// to the URL instead.
+// Please DO NOT link directly to my .js files from your site. Copy
+// the files to your server and use them there. Thank you.
+// ===================================================================
+
+
+/* SOURCE FILE: AnchorPosition.js */
+
+/*
+AnchorPosition.js
+Author: Matt Kruse
+Last modified: 10/11/02
+
+DESCRIPTION: These functions find the position of an <A> tag in a document,
+so other elements can be positioned relative to it.
+
+COMPATABILITY: Netscape 4.x,6.x,Mozilla, IE 5.x,6.x on Windows. Some small
+positioning errors - usually with Window positioning - occur on the
+Macintosh platform.
+
+FUNCTIONS:
+getAnchorPosition(anchorname)
+ Returns an Object() having .x and .y properties of the pixel coordinates
+ of the upper-left corner of the anchor. Position is relative to the PAGE.
+
+getAnchorWindowPosition(anchorname)
+ Returns an Object() having .x and .y properties of the pixel coordinates
+ of the upper-left corner of the anchor, relative to the WHOLE SCREEN.
+
+NOTES:
+
+1) For popping up separate browser windows, use getAnchorWindowPosition.
+ Otherwise, use getAnchorPosition
+
+2) Your anchor tag MUST contain both NAME and ID attributes which are the
+ same. For example:
+ <A NAME="test" ID="test"> </A>
+
+3) There must be at least a space between <A> </A> for IE5.5 to see the
+ anchor tag correctly. Do not do <A></A> with no space.
+*/
+
+// getAnchorPosition(anchorname)
+// This function returns an object having .x and .y properties which are the coordinates
+// of the named anchor, relative to the page.
+function getAnchorPosition(anchorname) {
+ // This function will return an Object with x and y properties
+ var useWindow=false;
+ var coordinates=new Object();
+ var x=0,y=0;
+ // Browser capability sniffing
+ var use_gebi=false, use_css=false, use_layers=false;
+ if (document.getElementById) { use_gebi=true; }
+ else if (document.all) { use_css=true; }
+ else if (document.layers) { use_layers=true; }
+ // Logic to find position
+ if (use_gebi && document.all) {
+ x=AnchorPosition_getPageOffsetLeft(document.all[anchorname]);
+ y=AnchorPosition_getPageOffsetTop(document.all[anchorname]);
+ }
+ else if (use_gebi) {
+ var o=document.getElementById(anchorname);
+ x=AnchorPosition_getPageOffsetLeft(o);
+ y=AnchorPosition_getPageOffsetTop(o);
+ }
+ else if (use_css) {
+ x=AnchorPosition_getPageOffsetLeft(document.all[anchorname]);
+ y=AnchorPosition_getPageOffsetTop(document.all[anchorname]);
+ }
+ else if (use_layers) {
+ var found=0;
+ for (var i=0; i<document.anchors.length; i++) {
+ if (document.anchors[i].name==anchorname) { found=1; break; }
+ }
+ if (found==0) {
+ coordinates.x=0; coordinates.y=0; return coordinates;
+ }
+ x=document.anchors[i].x;
+ y=document.anchors[i].y;
+ }
+ else {
+ coordinates.x=0; coordinates.y=0; return coordinates;
+ }
+ coordinates.x=x;
+ coordinates.y=y;
+ return coordinates;
+ }
+
+// getAnchorWindowPosition(anchorname)
+// This function returns an object having .x and .y properties which are the coordinates
+// of the named anchor, relative to the window
+function getAnchorWindowPosition(anchorname) {
+ var coordinates=getAnchorPosition(anchorname);
+ var x=0;
+ var y=0;
+ if (document.getElementById) {
+ if (isNaN(window.screenX)) {
+ x=coordinates.x-document.body.scrollLeft+window.screenLeft;
+ y=coordinates.y-document.body.scrollTop+window.screenTop;
+ }
+ else {
+ x=coordinates.x+window.screenX+(window.outerWidth-window.innerWidth)-window.pageXOffset;
+ y=coordinates.y+window.screenY+(window.outerHeight-24-window.innerHeight)-window.pageYOffset;
+ }
+ }
+ else if (document.all) {
+ x=coordinates.x-document.body.scrollLeft+window.screenLeft;
+ y=coordinates.y-document.body.scrollTop+window.screenTop;
+ }
+ else if (document.layers) {
+ x=coordinates.x+window.screenX+(window.outerWidth-window.innerWidth)-window.pageXOffset;
+ y=coordinates.y+window.screenY+(window.outerHeight-24-window.innerHeight)-window.pageYOffset;
+ }
+ coordinates.x=x;
+ coordinates.y=y;
+ return coordinates;
+ }
+
+// Functions for IE to get position of an object
+function AnchorPosition_getPageOffsetLeft (el) {
+ var ol=el.offsetLeft;
+ while ((el=el.offsetParent) != null) { ol += el.offsetLeft; }
+ return ol;
+ }
+function AnchorPosition_getWindowOffsetLeft (el) {
+ return AnchorPosition_getPageOffsetLeft(el)-document.body.scrollLeft;
+ }
+function AnchorPosition_getPageOffsetTop (el) {
+ var ot=el.offsetTop;
+ while((el=el.offsetParent) != null) { ot += el.offsetTop; }
+ return ot;
+ }
+function AnchorPosition_getWindowOffsetTop (el) {
+ return AnchorPosition_getPageOffsetTop(el)-document.body.scrollTop;
+ }
+
+/* SOURCE FILE: PopupWindow.js */
+
+/*
+PopupWindow.js
+Author: Matt Kruse
+Last modified: 02/16/04
+
+DESCRIPTION: This object allows you to easily and quickly popup a window
+in a certain place. The window can either be a DIV or a separate browser
+window.
+
+COMPATABILITY: Works with Netscape 4.x, 6.x, IE 5.x on Windows. Some small
+positioning errors - usually with Window positioning - occur on the
+Macintosh platform. Due to bugs in Netscape 4.x, populating the popup
+window with <STYLE> tags may cause errors.
+
+USAGE:
+// Create an object for a WINDOW popup
+var win = new PopupWindow();
+
+// Create an object for a DIV window using the DIV named 'mydiv'
+var win = new PopupWindow('mydiv');
+
+// Set the window to automatically hide itself when the user clicks
+// anywhere else on the page except the popup
+win.autoHide();
+
+// Show the window relative to the anchor name passed in
+win.showPopup(anchorname);
+
+// Hide the popup
+win.hidePopup();
+
+// Set the size of the popup window (only applies to WINDOW popups
+win.setSize(width,height);
+
+// Populate the contents of the popup window that will be shown. If you
+// change the contents while it is displayed, you will need to refresh()
+win.populate(string);
+
+// set the URL of the window, rather than populating its contents
+// manually
+win.setUrl("http://www.site.com/");
+
+// Refresh the contents of the popup
+win.refresh();
+
+// Specify how many pixels to the right of the anchor the popup will appear
+win.offsetX = 50;
+
+// Specify how many pixels below the anchor the popup will appear
+win.offsetY = 100;
+
+NOTES:
+1) Requires the functions in AnchorPosition.js
+
+2) Your anchor tag MUST contain both NAME and ID attributes which are the
+ same. For example:
+ <A NAME="test" ID="test"> </A>
+
+3) There must be at least a space between <A> </A> for IE5.5 to see the
+ anchor tag correctly. Do not do <A></A> with no space.
+
+4) When a PopupWindow object is created, a handler for 'onmouseup' is
+ attached to any event handler you may have already defined. Do NOT define
+ an event handler for 'onmouseup' after you define a PopupWindow object or
+ the autoHide() will not work correctly.
+*/
+
+// Set the position of the popup window based on the anchor
+function PopupWindow_getXYPosition(anchorname) {
+ var coordinates;
+ if (this.type == "WINDOW") {
+ coordinates = getAnchorWindowPosition(anchorname);
+ }
+ else {
+ coordinates = getAnchorPosition(anchorname);
+ }
+ this.x = coordinates.x;
+ this.y = coordinates.y;
+ }
+// Set width/height of DIV/popup window
+function PopupWindow_setSize(width,height) {
+ this.width = width;
+ this.height = height;
+ }
+// Fill the window with contents
+function PopupWindow_populate(contents) {
+ this.contents = contents;
+ this.populated = false;
+ }
+// Set the URL to go to
+function PopupWindow_setUrl(url) {
+ this.url = url;
+ }
+// Set the window popup properties
+function PopupWindow_setWindowProperties(props) {
+ this.windowProperties = props;
+ }
+// Refresh the displayed contents of the popup
+function PopupWindow_refresh() {
+ if (this.divName != null) {
+ // refresh the DIV object
+ if (this.use_gebi) {
+ document.getElementById(this.divName).innerHTML = this.contents;
+ }
+ else if (this.use_css) {
+ document.all[this.divName].innerHTML = this.contents;
+ }
+ else if (this.use_layers) {
+ var d = document.layers[this.divName];
+ d.document.open();
+ d.document.writeln(this.contents);
+ d.document.close();
+ }
+ }
+ else {
+ if (this.popupWindow != null && !this.popupWindow.closed) {
+ if (this.url!="") {
+ this.popupWindow.location.href=this.url;
+ }
+ else {
+ this.popupWindow.document.open();
+ this.popupWindow.document.writeln(this.contents);
+ this.popupWindow.document.close();
+ }
+ this.popupWindow.focus();
+ }
+ }
+ }
+// Position and show the popup, relative to an anchor object
+function PopupWindow_showPopup(anchorname) {
+ this.getXYPosition(anchorname);
+ this.x += this.offsetX;
+ this.y += this.offsetY;
+ if (!this.populated && (this.contents != "")) {
+ this.populated = true;
+ this.refresh();
+ }
+ if (this.divName != null) {
+ // Show the DIV object
+ if (this.use_gebi) {
+ document.getElementById(this.divName).style.left = this.x + "px";
+ document.getElementById(this.divName).style.top = this.y;
+ document.getElementById(this.divName).style.visibility = "visible";
+ }
+ else if (this.use_css) {
+ document.all[this.divName].style.left = this.x;
+ document.all[this.divName].style.top = this.y;
+ document.all[this.divName].style.visibility = "visible";
+ }
+ else if (this.use_layers) {
+ document.layers[this.divName].left = this.x;
+ document.layers[this.divName].top = this.y;
+ document.layers[this.divName].visibility = "visible";
+ }
+ }
+ else {
+ if (this.popupWindow == null || this.popupWindow.closed) {
+ // If the popup window will go off-screen, move it so it doesn't
+ if (this.x<0) { this.x=0; }
+ if (this.y<0) { this.y=0; }
+ if (screen && screen.availHeight) {
+ if ((this.y + this.height) > screen.availHeight) {
+ this.y = screen.availHeight - this.height;
+ }
+ }
+ if (screen && screen.availWidth) {
+ if ((this.x + this.width) > screen.availWidth) {
+ this.x = screen.availWidth - this.width;
+ }
+ }
+ var avoidAboutBlank = window.opera || ( document.layers && !navigator.mimeTypes['*'] ) || navigator.vendor == 'KDE' || ( document.childNodes && !document.all && !navigator.taintEnabled );
+ this.popupWindow = window.open(avoidAboutBlank?"":"about:blank","window_"+anchorname,this.windowProperties+",width="+this.width+",height="+this.height+",screenX="+this.x+",left="+this.x+",screenY="+this.y+",top="+this.y+"");
+ }
+ this.refresh();
+ }
+ }
+// Hide the popup
+function PopupWindow_hidePopup() {
+ if (this.divName != null) {
+ if (this.use_gebi) {
+ document.getElementById(this.divName).style.visibility = "hidden";
+ }
+ else if (this.use_css) {
+ document.all[this.divName].style.visibility = "hidden";
+ }
+ else if (this.use_layers) {
+ document.layers[this.divName].visibility = "hidden";
+ }
+ }
+ else {
+ if (this.popupWindow && !this.popupWindow.closed) {
+ this.popupWindow.close();
+ this.popupWindow = null;
+ }
+ }
+ }
+// Pass an event and return whether or not it was the popup DIV that was clicked
+function PopupWindow_isClicked(e) {
+ if (this.divName != null) {
+ if (this.use_layers) {
+ var clickX = e.pageX;
+ var clickY = e.pageY;
+ var t = document.layers[this.divName];
+ if ((clickX > t.left) && (clickX < t.left+t.clip.width) && (clickY > t.top) && (clickY < t.top+t.clip.height)) {
+ return true;
+ }
+ else { return false; }
+ }
+ else if (document.all) { // Need to hard-code this to trap IE for error-handling
+ var t = window.event.srcElement;
+ while (t.parentElement != null) {
+ if (t.id==this.divName) {
+ return true;
+ }
+ t = t.parentElement;
+ }
+ return false;
+ }
+ else if (this.use_gebi && e) {
+ var t = e.originalTarget;
+ while (t.parentNode != null) {
+ if (t.id==this.divName) {
+ return true;
+ }
+ t = t.parentNode;
+ }
+ return false;
+ }
+ return false;
+ }
+ return false;
+ }
+
+// Check an onMouseDown event to see if we should hide
+function PopupWindow_hideIfNotClicked(e) {
+ if (this.autoHideEnabled && !this.isClicked(e)) {
+ this.hidePopup();
+ }
+ }
+// Call this to make the DIV disable automatically when mouse is clicked outside it
+function PopupWindow_autoHide() {
+ this.autoHideEnabled = true;
+ }
+// This global function checks all PopupWindow objects onmouseup to see if they should be hidden
+function PopupWindow_hidePopupWindows(e) {
+ for (var i=0; i<popupWindowObjects.length; i++) {
+ if (popupWindowObjects[i] != null) {
+ var p = popupWindowObjects[i];
+ p.hideIfNotClicked(e);
+ }
+ }
+ }
+// Run this immediately to attach the event listener
+function PopupWindow_attachListener() {
+ if (document.layers) {
+ document.captureEvents(Event.MOUSEUP);
+ }
+ window.popupWindowOldEventListener = document.onmouseup;
+ if (window.popupWindowOldEventListener != null) {
+ document.onmouseup = new Function("window.popupWindowOldEventListener(); PopupWindow_hidePopupWindows();");
+ }
+ else {
+ document.onmouseup = PopupWindow_hidePopupWindows;
+ }
+ }
+// CONSTRUCTOR for the PopupWindow object
+// Pass it a DIV name to use a DHTML popup, otherwise will default to window popup
+function PopupWindow() {
+ if (!window.popupWindowIndex) { window.popupWindowIndex = 0; }
+ if (!window.popupWindowObjects) { window.popupWindowObjects = new Array(); }
+ if (!window.listenerAttached) {
+ window.listenerAttached = true;
+ PopupWindow_attachListener();
+ }
+ this.index = popupWindowIndex++;
+ popupWindowObjects[this.index] = this;
+ this.divName = null;
+ this.popupWindow = null;
+ this.width=0;
+ this.height=0;
+ this.populated = false;
+ this.visible = false;
+ this.autoHideEnabled = false;
+
+ this.contents = "";
+ this.url="";
+ this.windowProperties="toolbar=no,location=no,status=no,menubar=no,scrollbars=auto,resizable,alwaysRaised,dependent,titlebar=no";
+ if (arguments.length>0) {
+ this.type="DIV";
+ this.divName = arguments[0];
+ }
+ else {
+ this.type="WINDOW";
+ }
+ this.use_gebi = false;
+ this.use_css = false;
+ this.use_layers = false;
+ if (document.getElementById) { this.use_gebi = true; }
+ else if (document.all) { this.use_css = true; }
+ else if (document.layers) { this.use_layers = true; }
+ else { this.type = "WINDOW"; }
+ this.offsetX = 0;
+ this.offsetY = 0;
+ // Method mappings
+ this.getXYPosition = PopupWindow_getXYPosition;
+ this.populate = PopupWindow_populate;
+ this.setUrl = PopupWindow_setUrl;
+ this.setWindowProperties = PopupWindow_setWindowProperties;
+ this.refresh = PopupWindow_refresh;
+ this.showPopup = PopupWindow_showPopup;
+ this.hidePopup = PopupWindow_hidePopup;
+ this.setSize = PopupWindow_setSize;
+ this.isClicked = PopupWindow_isClicked;
+ this.autoHide = PopupWindow_autoHide;
+ this.hideIfNotClicked = PopupWindow_hideIfNotClicked;
+ }
+
+/* SOURCE FILE: ColorPicker2.js */
+
+/*
+Last modified: 02/24/2003
+
+DESCRIPTION: This widget is used to select a color, in hexadecimal #RRGGBB
+form. It uses a color "swatch" to display the standard 216-color web-safe
+palette. The user can then click on a color to select it.
+
+COMPATABILITY: See notes in AnchorPosition.js and PopupWindow.js.
+Only the latest DHTML-capable browsers will show the color and hex values
+at the bottom as your mouse goes over them.
+
+USAGE:
+// Create a new ColorPicker object using DHTML popup
+var cp = new ColorPicker();
+
+// Create a new ColorPicker object using Window Popup
+var cp = new ColorPicker('window');
+
+// Add a link in your page to trigger the popup. For example:
+<A HREF="#" onClick="cp.show('pick');return false;" NAME="pick" ID="pick">Pick</A>
+
+// Or use the built-in "select" function to do the dirty work for you:
+<A HREF="#" onClick="cp.select(document.forms[0].color,'pick');return false;" NAME="pick" ID="pick">Pick</A>
+
+// If using DHTML popup, write out the required DIV tag near the bottom
+// of your page.
+<SCRIPT LANGUAGE="JavaScript">cp.writeDiv()</SCRIPT>
+
+// Write the 'pickColor' function that will be called when the user clicks
+// a color and do something with the value. This is only required if you
+// want to do something other than simply populate a form field, which is
+// what the 'select' function will give you.
+function pickColor(color) {
+ field.value = color;
+ }
+
+NOTES:
+1) Requires the functions in AnchorPosition.js and PopupWindow.js
+
+2) Your anchor tag MUST contain both NAME and ID attributes which are the
+ same. For example:
+ <A NAME="test" ID="test"> </A>
+
+3) There must be at least a space between <A> </A> for IE5.5 to see the
+ anchor tag correctly. Do not do <A></A> with no space.
+
+4) When a ColorPicker object is created, a handler for 'onmouseup' is
+ attached to any event handler you may have already defined. Do NOT define
+ an event handler for 'onmouseup' after you define a ColorPicker object or
+ the color picker will not hide itself correctly.
+*/
+ColorPicker_targetInput = null;
+function ColorPicker_writeDiv() {
+ document.writeln("<DIV ID=\"colorPickerDiv\" STYLE=\"position:absolute;visibility:hidden;\"> </DIV>");
+ }
+
+function ColorPicker_show(anchorname) {
+ this.showPopup(anchorname);
+ }
+
+function ColorPicker_pickColor(color,obj) {
+ obj.hidePopup();
+ pickColor(color);
+ }
+
+// A Default "pickColor" function to accept the color passed back from popup.
+// User can over-ride this with their own function.
+function pickColor(color) {
+ if (ColorPicker_targetInput==null) {
+ alert("Target Input is null, which means you either didn't use the 'select' function or you have no defined your own 'pickColor' function to handle the picked color!");
+ return;
+ }
+ ColorPicker_targetInput.value = color;
+ }
+
+// This function is the easiest way to popup the window, select a color, and
+// have the value populate a form field, which is what most people want to do.
+function ColorPicker_select(inputobj,linkname) {
+ if (inputobj.type!="text" && inputobj.type!="hidden" && inputobj.type!="textarea") {
+ alert("colorpicker.select: Input object passed is not a valid form input object");
+ window.ColorPicker_targetInput=null;
+ return;
+ }
+ window.ColorPicker_targetInput = inputobj;
+ this.show(linkname);
+ }
+
+// This function runs when you move your mouse over a color block, if you have a newer browser
+function ColorPicker_highlightColor(c) {
+ var thedoc = (arguments.length>1)?arguments[1]:window.document;
+ var d = thedoc.getElementById("colorPickerSelectedColor");
+ d.style.backgroundColor = c;
+ d = thedoc.getElementById("colorPickerSelectedColorValue");
+ d.innerHTML = c;
+ }
+
+function ColorPicker() {
+ var windowMode = false;
+ // Create a new PopupWindow object
+ if (arguments.length==0) {
+ var divname = "colorPickerDiv";
+ }
+ else if (arguments[0] == "window") {
+ var divname = '';
+ windowMode = true;
+ }
+ else {
+ var divname = arguments[0];
+ }
+
+ if (divname != "") {
+ var cp = new PopupWindow(divname);
+ }
+ else {
+ var cp = new PopupWindow();
+ cp.setSize(225,250);
+ }
+
+ // Object variables
+ cp.currentValue = "#FFFFFF";
+
+ // Method Mappings
+ cp.writeDiv = ColorPicker_writeDiv;
+ cp.highlightColor = ColorPicker_highlightColor;
+ cp.show = ColorPicker_show;
+ cp.select = ColorPicker_select;
+
+ // Code to populate color picker window
+ var colors = new Array( "#4180B6","#69AEE7","#000000","#000033","#000066","#000099","#0000CC","#0000FF","#330000","#330033","#330066","#330099",
+ "#3300CC","#3300FF","#660000","#660033","#660066","#660099","#6600CC","#6600FF","#990000","#990033","#990066","#990099",
+ "#9900CC","#9900FF","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#FF0000","#FF0033","#FF0066","#FF0099",
+ "#FF00CC","#FF00FF","#7FFFFF","#7FFFFF","#7FF7F7","#7FEFEF","#7FE7E7","#7FDFDF","#7FD7D7","#7FCFCF","#7FC7C7","#7FBFBF",
+ "#7FB7B7","#7FAFAF","#7FA7A7","#7F9F9F","#7F9797","#7F8F8F","#7F8787","#7F7F7F","#7F7777","#7F6F6F","#7F6767","#7F5F5F",
+ "#7F5757","#7F4F4F","#7F4747","#7F3F3F","#7F3737","#7F2F2F","#7F2727","#7F1F1F","#7F1717","#7F0F0F","#7F0707","#7F0000",
+
+ "#4180B6","#69AEE7","#003300","#003333","#003366","#003399","#0033CC","#0033FF","#333300","#333333","#333366","#333399",
+ "#3333CC","#3333FF","#663300","#663333","#663366","#663399","#6633CC","#6633FF","#993300","#993333","#993366","#993399",
+ "#9933CC","#9933FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#FF3300","#FF3333","#FF3366","#FF3399",
+ "#FF33CC","#FF33FF","#FF7FFF","#FF7FFF","#F77FF7","#EF7FEF","#E77FE7","#DF7FDF","#D77FD7","#CF7FCF","#C77FC7","#BF7FBF",
+ "#B77FB7","#AF7FAF","#A77FA7","#9F7F9F","#977F97","#8F7F8F","#877F87","#7F7F7F","#777F77","#6F7F6F","#677F67","#5F7F5F",
+ "#577F57","#4F7F4F","#477F47","#3F7F3F","#377F37","#2F7F2F","#277F27","#1F7F1F","#177F17","#0F7F0F","#077F07","#007F00",
+
+ "#4180B6","#69AEE7","#006600","#006633","#006666","#006699","#0066CC","#0066FF","#336600","#336633","#336666","#336699",
+ "#3366CC","#3366FF","#666600","#666633","#666666","#666699","#6666CC","#6666FF","#996600","#996633","#996666","#996699",
+ "#9966CC","#9966FF","#CC6600","#CC6633","#CC6666","#CC6699","#CC66CC","#CC66FF","#FF6600","#FF6633","#FF6666","#FF6699",
+ "#FF66CC","#FF66FF","#FFFF7F","#FFFF7F","#F7F77F","#EFEF7F","#E7E77F","#DFDF7F","#D7D77F","#CFCF7F","#C7C77F","#BFBF7F",
+ "#B7B77F","#AFAF7F","#A7A77F","#9F9F7F","#97977F","#8F8F7F","#87877F","#7F7F7F","#77777F","#6F6F7F","#67677F","#5F5F7F",
+ "#57577F","#4F4F7F","#47477F","#3F3F7F","#37377F","#2F2F7F","#27277F","#1F1F7F","#17177F","#0F0F7F","#07077F","#00007F",
+
+ "#4180B6","#69AEE7","#009900","#009933","#009966","#009999","#0099CC","#0099FF","#339900","#339933","#339966","#339999",
+ "#3399CC","#3399FF","#669900","#669933","#669966","#669999","#6699CC","#6699FF","#999900","#999933","#999966","#999999",
+ "#9999CC","#9999FF","#CC9900","#CC9933","#CC9966","#CC9999","#CC99CC","#CC99FF","#FF9900","#FF9933","#FF9966","#FF9999",
+ "#FF99CC","#FF99FF","#3FFFFF","#3FFFFF","#3FF7F7","#3FEFEF","#3FE7E7","#3FDFDF","#3FD7D7","#3FCFCF","#3FC7C7","#3FBFBF",
+ "#3FB7B7","#3FAFAF","#3FA7A7","#3F9F9F","#3F9797","#3F8F8F","#3F8787","#3F7F7F","#3F7777","#3F6F6F","#3F6767","#3F5F5F",
+ "#3F5757","#3F4F4F","#3F4747","#3F3F3F","#3F3737","#3F2F2F","#3F2727","#3F1F1F","#3F1717","#3F0F0F","#3F0707","#3F0000",
+
+ "#4180B6","#69AEE7","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#33CC00","#33CC33","#33CC66","#33CC99",
+ "#33CCCC","#33CCFF","#66CC00","#66CC33","#66CC66","#66CC99","#66CCCC","#66CCFF","#99CC00","#99CC33","#99CC66","#99CC99",
+ "#99CCCC","#99CCFF","#CCCC00","#CCCC33","#CCCC66","#CCCC99","#CCCCCC","#CCCCFF","#FFCC00","#FFCC33","#FFCC66","#FFCC99",
+ "#FFCCCC","#FFCCFF","#FF3FFF","#FF3FFF","#F73FF7","#EF3FEF","#E73FE7","#DF3FDF","#D73FD7","#CF3FCF","#C73FC7","#BF3FBF",
+ "#B73FB7","#AF3FAF","#A73FA7","#9F3F9F","#973F97","#8F3F8F","#873F87","#7F3F7F","#773F77","#6F3F6F","#673F67","#5F3F5F",
+ "#573F57","#4F3F4F","#473F47","#3F3F3F","#373F37","#2F3F2F","#273F27","#1F3F1F","#173F17","#0F3F0F","#073F07","#003F00",
+
+ "#4180B6","#69AEE7","#00FF00","#00FF33","#00FF66","#00FF99","#00FFCC","#00FFFF","#33FF00","#33FF33","#33FF66","#33FF99",
+ "#33FFCC","#33FFFF","#66FF00","#66FF33","#66FF66","#66FF99","#66FFCC","#66FFFF","#99FF00","#99FF33","#99FF66","#99FF99",
+ "#99FFCC","#99FFFF","#CCFF00","#CCFF33","#CCFF66","#CCFF99","#CCFFCC","#CCFFFF","#FFFF00","#FFFF33","#FFFF66","#FFFF99",
+ "#FFFFCC","#FFFFFF","#FFFF3F","#FFFF3F","#F7F73F","#EFEF3F","#E7E73F","#DFDF3F","#D7D73F","#CFCF3F","#C7C73F","#BFBF3F",
+ "#B7B73F","#AFAF3F","#A7A73F","#9F9F3F","#97973F","#8F8F3F","#87873F","#7F7F3F","#77773F","#6F6F3F","#67673F","#5F5F3F",
+ "#57573F","#4F4F3F","#47473F","#3F3F3F","#37373F","#2F2F3F","#27273F","#1F1F3F","#17173F","#0F0F3F","#07073F","#00003F",
+
+ "#4180B6","#69AEE7","#FFFFFF","#FFEEEE","#FFDDDD","#FFCCCC","#FFBBBB","#FFAAAA","#FF9999","#FF8888","#FF7777","#FF6666",
+ "#FF5555","#FF4444","#FF3333","#FF2222","#FF1111","#FF0000","#FF0000","#FF0000","#FF0000","#EE0000","#DD0000","#CC0000",
+ "#BB0000","#AA0000","#990000","#880000","#770000","#660000","#550000","#440000","#330000","#220000","#110000","#000000",
+ "#000000","#000000","#000000","#001111","#002222","#003333","#004444","#005555","#006666","#007777","#008888","#009999",
+ "#00AAAA","#00BBBB","#00CCCC","#00DDDD","#00EEEE","#00FFFF","#00FFFF","#00FFFF","#00FFFF","#11FFFF","#22FFFF","#33FFFF",
+ "#44FFFF","#55FFFF","#66FFFF","#77FFFF","#88FFFF","#99FFFF","#AAFFFF","#BBFFFF","#CCFFFF","#DDFFFF","#EEFFFF","#FFFFFF",
+
+ "#4180B6","#69AEE7","#FFFFFF","#EEFFEE","#DDFFDD","#CCFFCC","#BBFFBB","#AAFFAA","#99FF99","#88FF88","#77FF77","#66FF66",
+ "#55FF55","#44FF44","#33FF33","#22FF22","#11FF11","#00FF00","#00FF00","#00FF00","#00FF00","#00EE00","#00DD00","#00CC00",
+ "#00BB00","#00AA00","#009900","#008800","#007700","#006600","#005500","#004400","#003300","#002200","#001100","#000000",
+ "#000000","#000000","#000000","#110011","#220022","#330033","#440044","#550055","#660066","#770077","#880088","#990099",
+ "#AA00AA","#BB00BB","#CC00CC","#DD00DD","#EE00EE","#FF00FF","#FF00FF","#FF00FF","#FF00FF","#FF11FF","#FF22FF","#FF33FF",
+ "#FF44FF","#FF55FF","#FF66FF","#FF77FF","#FF88FF","#FF99FF","#FFAAFF","#FFBBFF","#FFCCFF","#FFDDFF","#FFEEFF","#FFFFFF",
+
+ "#4180B6","#69AEE7","#FFFFFF","#EEEEFF","#DDDDFF","#CCCCFF","#BBBBFF","#AAAAFF","#9999FF","#8888FF","#7777FF","#6666FF",
+ "#5555FF","#4444FF","#3333FF","#2222FF","#1111FF","#0000FF","#0000FF","#0000FF","#0000FF","#0000EE","#0000DD","#0000CC",
+ "#0000BB","#0000AA","#000099","#000088","#000077","#000066","#000055","#000044","#000033","#000022","#000011","#000000",
+ "#000000","#000000","#000000","#111100","#222200","#333300","#444400","#555500","#666600","#777700","#888800","#999900",
+ "#AAAA00","#BBBB00","#CCCC00","#DDDD00","#EEEE00","#FFFF00","#FFFF00","#FFFF00","#FFFF00","#FFFF11","#FFFF22","#FFFF33",
+ "#FFFF44","#FFFF55","#FFFF66","#FFFF77","#FFFF88","#FFFF99","#FFFFAA","#FFFFBB","#FFFFCC","#FFFFDD","#FFFFEE","#FFFFFF",
+
+ "#4180B6","#69AEE7","#FFFFFF","#FFFFFF","#FBFBFB","#F7F7F7","#F3F3F3","#EFEFEF","#EBEBEB","#E7E7E7","#E3E3E3","#DFDFDF",
+ "#DBDBDB","#D7D7D7","#D3D3D3","#CFCFCF","#CBCBCB","#C7C7C7","#C3C3C3","#BFBFBF","#BBBBBB","#B7B7B7","#B3B3B3","#AFAFAF",
+ "#ABABAB","#A7A7A7","#A3A3A3","#9F9F9F","#9B9B9B","#979797","#939393","#8F8F8F","#8B8B8B","#878787","#838383","#7F7F7F",
+ "#7B7B7B","#777777","#737373","#6F6F6F","#6B6B6B","#676767","#636363","#5F5F5F","#5B5B5B","#575757","#535353","#4F4F4F",
+ "#4B4B4B","#474747","#434343","#3F3F3F","#3B3B3B","#373737","#333333","#2F2F2F","#2B2B2B","#272727","#232323","#1F1F1F",
+ "#1B1B1B","#171717","#131313","#0F0F0F","#0B0B0B","#070707","#030303","#000000","#000000","#000000","#000000","#000000");
+ var total = colors.length;
+ var width = 72;
+ var cp_contents = "";
+ var windowRef = (windowMode)?"window.opener.":"";
+ if (windowMode) {
+ cp_contents += "<html><head><title>Select Color</title></head>";
+ cp_contents += "<body marginwidth=0 marginheight=0 leftmargin=0 topmargin=0><span style='text-align: center;'>";
+ }
+ cp_contents += "<table style='border: none;' cellspacing=0 cellpadding=0>";
+ var use_highlight = (document.getElementById || document.all)?true:false;
+ for (var i=0; i<total; i++) {
+ if ((i % width) == 0) { cp_contents += "<tr>"; }
+ if (use_highlight) { var mo = 'onMouseOver="'+windowRef+'ColorPicker_highlightColor(\''+colors[i]+'\',window.document)"'; }
+ else { mo = ""; }
+ cp_contents += '<td style="background-color: '+colors[i]+';"><a href="javascript:void()" onclick="'+windowRef+'ColorPicker_pickColor(\''+colors[i]+'\','+windowRef+'window.popupWindowObjects['+cp.index+']);return false;" '+mo+'>&nbsp;</a></td>';
+ if ( ((i+1)>=total) || (((i+1) % width) == 0)) {
+ cp_contents += "</tr>";
+ }
+ }
+ // If the browser supports dynamically changing TD cells, add the fancy stuff
+ if (document.getElementById) {
+ var width1 = Math.floor(width/2);
+ var width2 = width = width1;
+ cp_contents += "<tr><td colspan='"+width1+"' style='background-color: #FFF;' ID='colorPickerSelectedColor'>&nbsp;</td><td colspan='"+width2+"' style='text-align: center;' id='colorPickerSelectedColorValue'>#FFFFFF</td></tr>";
+ }
+ cp_contents += "</table>";
+ if (windowMode) {
+ cp_contents += "</span></body></html>";
+ }
+ // end populate code
+
+ // Write the contents to the popup object
+ cp.populate(cp_contents+"\n");
+ // Move the table down a bit so you can see it
+ cp.offsetY = 25;
+ cp.autoHide();
+ return cp;
+ }
diff --git a/src/wp-includes/js/comment-reply.js b/src/wp-includes/js/comment-reply.js
new file mode 100644
index 0000000000..20154253a4
--- /dev/null
+++ b/src/wp-includes/js/comment-reply.js
@@ -0,0 +1,48 @@
+
+addComment = {
+ moveForm : function(commId, parentId, respondId, postId) {
+ var t = this, div, comm = t.I(commId), respond = t.I(respondId), cancel = t.I('cancel-comment-reply-link'), parent = t.I('comment_parent'), post = t.I('comment_post_ID');
+
+ if ( ! comm || ! respond || ! cancel || ! parent )
+ return;
+
+ t.respondId = respondId;
+ postId = postId || false;
+
+ if ( ! t.I('wp-temp-form-div') ) {
+ div = document.createElement('div');
+ div.id = 'wp-temp-form-div';
+ div.style.display = 'none';
+ respond.parentNode.insertBefore(div, respond);
+ }
+
+ comm.parentNode.insertBefore(respond, comm.nextSibling);
+ if ( post && postId )
+ post.value = postId;
+ parent.value = parentId;
+ cancel.style.display = '';
+
+ cancel.onclick = function() {
+ var t = addComment, temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId);
+
+ if ( ! temp || ! respond )
+ return;
+
+ t.I('comment_parent').value = '0';
+ temp.parentNode.insertBefore(respond, temp);
+ temp.parentNode.removeChild(temp);
+ this.style.display = 'none';
+ this.onclick = null;
+ return false;
+ }
+
+ try { t.I('comment').focus(); }
+ catch(e) {}
+
+ return false;
+ },
+
+ I : function(e) {
+ return document.getElementById(e);
+ }
+}
diff --git a/src/wp-includes/js/crop/cropper.css b/src/wp-includes/js/crop/cropper.css
new file mode 100644
index 0000000000..b2799c49a5
--- /dev/null
+++ b/src/wp-includes/js/crop/cropper.css
@@ -0,0 +1,165 @@
+.imgCrop_wrap {
+ /* width: 500px; @done_in_js */
+ /* height: 375px; @done_in_js */
+ position: relative;
+ cursor: crosshair;
+}
+
+/* an extra classname is applied for Opera < 9.0 to fix its lack of opacity support */
+.imgCrop_wrap.opera8 .imgCrop_overlay,
+.imgCrop_wrap.opera8 .imgCrop_clickArea {
+ background-color: transparent;
+}
+
+/* fix for IE displaying all boxes at line-height by default, although they are still 1 pixel high until we combine them with the pointless span */
+.imgCrop_wrap,
+.imgCrop_wrap * {
+ font-size: 0;
+}
+
+.imgCrop_overlay {
+ background-color: #000;
+ opacity: 0.5;
+ filter:alpha(opacity=50);
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.imgCrop_selArea {
+ position: absolute;
+ /* @done_in_js
+ top: 20px;
+ left: 20px;
+ width: 200px;
+ height: 200px;
+ background: transparent url(castle.jpg) no-repeat -210px -110px;
+ */
+ cursor: move;
+ z-index: 2;
+}
+
+/* clickArea is all a fix for IE 5.5 & 6 to allow the user to click on the given area */
+.imgCrop_clickArea {
+ width: 100%;
+ height: 100%;
+ background-color: #FFF;
+ opacity: 0.01;
+ filter:alpha(opacity=01);
+}
+
+.imgCrop_marqueeHoriz {
+ position: absolute;
+ width: 100%;
+ height: 1px;
+ background: transparent url(marqueeHoriz.gif) repeat-x 0 0;
+ z-index: 3;
+}
+
+.imgCrop_marqueeVert {
+ position: absolute;
+ height: 100%;
+ width: 1px;
+ background: transparent url(marqueeVert.gif) repeat-y 0 0;
+ z-index: 3;
+}
+
+.imgCrop_marqueeNorth { top: 0; left: 0; }
+.imgCrop_marqueeEast { top: 0; right: 0; }
+.imgCrop_marqueeSouth { bottom: 0px; left: 0; }
+.imgCrop_marqueeWest { top: 0; left: 0; }
+
+
+.imgCrop_handle {
+ position: absolute;
+ border: 1px solid #333;
+ width: 6px;
+ height: 6px;
+ background: #FFF;
+ opacity: 0.5;
+ filter:alpha(opacity=50);
+ z-index: 4;
+}
+
+/* fix IE 5 box model */
+* html .imgCrop_handle {
+ width: 8px;
+ height: 8px;
+ wid\th: 6px;
+ hei\ght: 6px;
+}
+
+.imgCrop_handleN {
+ top: -3px;
+ left: 0;
+ /* margin-left: 49%; @done_in_js */
+ cursor: n-resize;
+}
+
+.imgCrop_handleNE {
+ top: -3px;
+ right: -3px;
+ cursor: ne-resize;
+}
+
+.imgCrop_handleE {
+ top: 0;
+ right: -3px;
+ /* margin-top: 49%; @done_in_js */
+ cursor: e-resize;
+}
+
+.imgCrop_handleSE {
+ right: -3px;
+ bottom: -3px;
+ cursor: se-resize;
+}
+
+.imgCrop_handleS {
+ right: 0;
+ bottom: -3px;
+ /* margin-right: 49%; @done_in_js */
+ cursor: s-resize;
+}
+
+.imgCrop_handleSW {
+ left: -3px;
+ bottom: -3px;
+ cursor: sw-resize;
+}
+
+.imgCrop_handleW {
+ top: 0;
+ left: -3px;
+ /* margin-top: 49%; @done_in_js */
+ cursor: e-resize;
+}
+
+.imgCrop_handleNW {
+ top: -3px;
+ left: -3px;
+ cursor: nw-resize;
+}
+
+/**
+ * Create an area to click & drag around on as the default browser behaviour is to let you drag the image
+ */
+.imgCrop_dragArea {
+ width: 100%;
+ height: 100%;
+ z-index: 200;
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+
+.imgCrop_previewWrap {
+ /* width: 200px; @done_in_js */
+ /* height: 200px; @done_in_js */
+ overflow: hidden;
+ position: relative;
+}
+
+.imgCrop_previewWrap img {
+ position: absolute;
+} \ No newline at end of file
diff --git a/src/wp-includes/js/crop/cropper.js b/src/wp-includes/js/crop/cropper.js
new file mode 100644
index 0000000000..d0cb8e4cca
--- /dev/null
+++ b/src/wp-includes/js/crop/cropper.js
@@ -0,0 +1,516 @@
+/**
+ * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * See scriptaculous.js for full scriptaculous licence
+ */
+
+var CropDraggable=Class.create();
+Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){
+this.options=Object.extend({drawMethod:function(){
+}},arguments[1]||{});
+this.element=$(_1);
+this.handle=this.element;
+this.delta=this.currentDelta();
+this.dragging=false;
+this.eventMouseDown=this.initDrag.bindAsEventListener(this);
+Event.observe(this.handle,"mousedown",this.eventMouseDown);
+Draggables.register(this);
+},draw:function(_2){
+var _3=Position.cumulativeOffset(this.element);
+var d=this.currentDelta();
+_3[0]-=d[0];
+_3[1]-=d[1];
+var p=[0,1].map(function(i){
+return (_2[i]-_3[i]-this.offset[i]);
+}.bind(this));
+this.options.drawMethod(p);
+}});
+var Cropper={};
+Cropper.Img=Class.create();
+Cropper.Img.prototype={initialize:function(_7,_8){
+this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true},_8||{});
+if(this.options.minWidth>0&&this.options.minHeight>0){
+this.options.ratioDim.x=this.options.minWidth;
+this.options.ratioDim.y=this.options.minHeight;
+}
+this.img=$(_7);
+this.clickCoords={x:0,y:0};
+this.dragging=false;
+this.resizing=false;
+this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent);
+this.isIE=/MSIE/.test(navigator.userAgent);
+this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent);
+this.ratioX=0;
+this.ratioY=0;
+this.attached=false;
+$A(document.getElementsByTagName("script")).each(function(s){
+if(s.src.match(/cropper\.js/)){
+var _a=s.src.replace(/cropper\.js(.*)?/,"");
+var _b=document.createElement("link");
+_b.rel="stylesheet";
+_b.type="text/css";
+_b.href=_a+"cropper.css";
+_b.media="screen";
+document.getElementsByTagName("head")[0].appendChild(_b);
+}
+});
+if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){
+var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y);
+this.ratioX=this.options.ratioDim.x/_c;
+this.ratioY=this.options.ratioDim.y/_c;
+}
+this.subInitialize();
+if(this.img.complete||this.isWebKit){
+this.onLoad();
+}else{
+Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this));
+}
+},getGCD:function(a,b){return 1;
+if(b==0){
+return a;
+}
+return this.getGCD(b,a%b);
+},onLoad:function(){
+var _f="imgCrop_";
+var _10=this.img.parentNode;
+var _11="";
+if(this.isOpera8){
+_11=" opera8";
+}
+this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11});
+if(this.isIE){
+this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]);
+this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]);
+this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]);
+this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]);
+var _12=[this.north,this.east,this.south,this.west];
+}else{
+this.overlay=Builder.node("div",{"class":_f+"overlay"});
+var _12=[this.overlay];
+}
+this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12);
+this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"});
+this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"});
+this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"});
+this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"});
+this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"});
+this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"});
+this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"});
+this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"});
+this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]);
+Element.setStyle($(this.selArea),{backgroundColor:"transparent",backgroundRepeat:"no-repeat",backgroundPosition:"0 0"});
+this.imgWrap.appendChild(this.img);
+this.imgWrap.appendChild(this.dragArea);
+this.dragArea.appendChild(this.selArea);
+this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"}));
+_10.appendChild(this.imgWrap);
+Event.observe(this.dragArea,"mousedown",this.startDrag.bindAsEventListener(this));
+Event.observe(document,"mousemove",this.onDrag.bindAsEventListener(this));
+Event.observe(document,"mouseup",this.endCrop.bindAsEventListener(this));
+var _13=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
+for(var i=0;i<_13.length;i++){
+Event.observe(_13[i],"mousedown",this.startResize.bindAsEventListener(this));
+}
+if(this.options.captureKeys){
+Event.observe(document,"keydown",this.handleKeys.bindAsEventListener(this));
+}
+new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)});
+this.setParams();
+},setParams:function(){
+this.imgW=this.img.width;
+this.imgH=this.img.height;
+if(!this.isIE){
+Element.setStyle($(this.overlay),{width:this.imgW+"px",height:this.imgH+"px"});
+Element.hide($(this.overlay));
+Element.setStyle($(this.selArea),{backgroundImage:"url("+this.img.src+")"});
+}else{
+Element.setStyle($(this.north),{height:0});
+Element.setStyle($(this.east),{width:0,height:0});
+Element.setStyle($(this.south),{height:0});
+Element.setStyle($(this.west),{width:0,height:0});
+}
+Element.setStyle($(this.imgWrap),{"width":this.imgW+"px","height":this.imgH+"px"});
+Element.hide($(this.selArea));
+var _15=Position.positionedOffset(this.imgWrap);
+this.wrapOffsets={"top":_15[1],"left":_15[0]};
+var _16={x1:0,y1:0,x2:0,y2:0};
+this.setAreaCoords(_16);
+if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0&&this.options.displayOnInit){
+_16.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2);
+_16.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2);
+_16.x2=_16.x1+this.options.ratioDim.x;
+_16.y2=_16.y1+this.options.ratioDim.y;
+Element.show(this.selArea);
+this.drawArea();
+this.endCrop();
+}
+this.attached=true;
+},remove:function(){
+this.attached=false;
+this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap);
+this.imgWrap.parentNode.removeChild(this.imgWrap);
+Event.stopObserving(this.dragArea,"mousedown",this.startDrag.bindAsEventListener(this));
+Event.stopObserving(document,"mousemove",this.onDrag.bindAsEventListener(this));
+Event.stopObserving(document,"mouseup",this.endCrop.bindAsEventListener(this));
+var _17=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW];
+for(var i=0;i<_17.length;i++){
+Event.stopObserving(_17[i],"mousedown",this.startResize.bindAsEventListener(this));
+}
+if(this.options.captureKeys){
+Event.stopObserving(document,"keydown",this.handleKeys.bindAsEventListener(this));
+}
+},reset:function(){
+if(!this.attached){
+this.onLoad();
+}else{
+this.setParams();
+}
+this.endCrop();
+},handleKeys:function(e){
+var dir={x:0,y:0};
+if(!this.dragging){
+switch(e.keyCode){
+case (37):
+dir.x=-1;
+break;
+case (38):
+dir.y=-1;
+break;
+case (39):
+dir.x=1;
+break;
+case (40):
+dir.y=1;
+break;
+}
+if(dir.x!=0||dir.y!=0){
+if(e.shiftKey){
+dir.x*=10;
+dir.y*=10;
+}
+this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]);
+Event.stop(e);
+}
+}
+},calcW:function(){
+return (this.areaCoords.x2-this.areaCoords.x1);
+},calcH:function(){
+return (this.areaCoords.y2-this.areaCoords.y1);
+},moveArea:function(_1b){
+this.setAreaCoords({x1:_1b[0],y1:_1b[1],x2:_1b[0]+this.calcW(),y2:_1b[1]+this.calcH()},true);
+this.drawArea();
+},cloneCoords:function(_1c){
+return {x1:_1c.x1,y1:_1c.y1,x2:_1c.x2,y2:_1c.y2};
+},setAreaCoords:function(_1d,_1e,_1f,_20,_21){
+var _22=typeof _1e!="undefined"?_1e:false;
+var _23=typeof _1f!="undefined"?_1f:false;
+if(_1e){
+var _24=_1d.x2-_1d.x1;
+var _25=_1d.y2-_1d.y1;
+if(_1d.x1<0){
+_1d.x1=0;
+_1d.x2=_24;
+}
+if(_1d.y1<0){
+_1d.y1=0;
+_1d.y2=_25;
+}
+if(_1d.x2>this.imgW){
+_1d.x2=this.imgW;
+_1d.x1=this.imgW-_24;
+}
+if(_1d.y2>this.imgH){
+_1d.y2=this.imgH;
+_1d.y1=this.imgH-_25;
+}
+}else{
+if(_1d.x1<0){
+_1d.x1=0;
+}
+if(_1d.y1<0){
+_1d.y1=0;
+}
+if(_1d.x2>this.imgW){
+_1d.x2=this.imgW;
+}
+if(_1d.y2>this.imgH){
+_1d.y2=this.imgH;
+}
+if(typeof (_20)!="undefined"){
+if(this.ratioX>0){
+this.applyRatio(_1d,{x:this.ratioX,y:this.ratioY},_20,_21);
+}else{
+if(_23){
+this.applyRatio(_1d,{x:1,y:1},_20,_21);
+}
+}
+var _26={a1:_1d.x1,a2:_1d.x2};
+var _27={a1:_1d.y1,a2:_1d.y2};
+var _28=this.options.minWidth;
+var _29=this.options.minHeight;
+if((_28==0||_29==0)&&_23){
+if(_28>0){
+_29=_28;
+}else{
+if(_29>0){
+_28=_29;
+}
+}
+}
+this.applyMinDimension(_26,_28,_20.x,{min:0,max:this.imgW});
+this.applyMinDimension(_27,_29,_20.y,{min:0,max:this.imgH});
+_1d={x1:_26.a1,y1:_27.a1,x2:_26.a2,y2:_27.a2};
+}
+}
+this.areaCoords=_1d;
+},applyMinDimension:function(_2a,_2b,_2c,_2d){
+if((_2a.a2-_2a.a1)<_2b){
+if(_2c==1){
+_2a.a2=_2a.a1+_2b;
+}else{
+_2a.a1=_2a.a2-_2b;
+}
+if(_2a.a1<_2d.min){
+_2a.a1=_2d.min;
+_2a.a2=_2b;
+}else{
+if(_2a.a2>_2d.max){
+_2a.a1=_2d.max-_2b;
+_2a.a2=_2d.max;
+}
+}
+}
+},applyRatio:function(_2e,_2f,_30,_31){
+var _32;
+if(_31=="N"||_31=="S"){
+_32=this.applyRatioToAxis({a1:_2e.y1,b1:_2e.x1,a2:_2e.y2,b2:_2e.x2},{a:_2f.y,b:_2f.x},{a:_30.y,b:_30.x},{min:0,max:this.imgW});
+_2e.x1=_32.b1;
+_2e.y1=_32.a1;
+_2e.x2=_32.b2;
+_2e.y2=_32.a2;
+}else{
+_32=this.applyRatioToAxis({a1:_2e.x1,b1:_2e.y1,a2:_2e.x2,b2:_2e.y2},{a:_2f.x,b:_2f.y},{a:_30.x,b:_30.y},{min:0,max:this.imgH});
+_2e.x1=_32.a1;
+_2e.y1=_32.b1;
+_2e.x2=_32.a2;
+_2e.y2=_32.b2;
+}
+},applyRatioToAxis:function(_33,_34,_35,_36){
+var _37=Object.extend(_33,{});
+var _38=_37.a2-_37.a1;
+var _3a=Math.floor(_38*_34.b/_34.a);
+var _3b;
+var _3c;
+var _3d=null;
+if(_35.b==1){
+_3b=_37.b1+_3a;
+if(_3b>_36.max){
+_3b=_36.max;
+_3d=_3b-_37.b1;
+}
+_37.b2=_3b;
+}else{
+_3b=_37.b2-_3a;
+if(_3b<_36.min){
+_3b=_36.min;
+_3d=_3b+_37.b2;
+}
+_37.b1=_3b;
+}
+if(_3d!=null){
+_3c=Math.floor(_3d*_34.a/_34.b);
+if(_35.a==1){
+_37.a2=_37.a1+_3c;
+}else{
+_37.a1=_37.a1=_37.a2-_3c;
+}
+}
+return _37;
+},drawArea:function(){
+if(!this.isIE){
+Element.show($(this.overlay));
+}
+var _3e=this.calcW();
+var _3f=this.calcH();
+var _40=this.areaCoords.x2;
+var _41=this.areaCoords.y2;
+var _42=this.selArea.style;
+_42.left=this.areaCoords.x1+"px";
+_42.top=this.areaCoords.y1+"px";
+_42.width=_3e+"px";
+_42.height=_3f+"px";
+var _43=Math.ceil((_3e-6)/2)+"px";
+var _44=Math.ceil((_3f-6)/2)+"px";
+this.handleN.style.left=_43;
+this.handleE.style.top=_44;
+this.handleS.style.left=_43;
+this.handleW.style.top=_44;
+if(this.isIE){
+this.north.style.height=this.areaCoords.y1+"px";
+var _45=this.east.style;
+_45.top=this.areaCoords.y1+"px";
+_45.height=_3f+"px";
+_45.left=_40+"px";
+_45.width=(this.img.width-_40)+"px";
+var _46=this.south.style;
+_46.top=_41+"px";
+_46.height=(this.img.height-_41)+"px";
+var _47=this.west.style;
+_47.top=this.areaCoords.y1+"px";
+_47.height=_3f+"px";
+_47.width=this.areaCoords.x1+"px";
+}else{
+_42.backgroundPosition="-"+this.areaCoords.x1+"px "+"-"+this.areaCoords.y1+"px";
+}
+this.subDrawArea();
+this.forceReRender();
+},forceReRender:function(){
+if(this.isIE||this.isWebKit){
+var n=document.createTextNode(" ");
+var d,el,fixEL,i;
+if(this.isIE){
+fixEl=this.selArea;
+}else{
+if(this.isWebKit){
+fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0];
+d=Builder.node("div","");
+d.style.visibility="hidden";
+var _4a=["SE","S","SW"];
+for(i=0;i<_4a.length;i++){
+el=document.getElementsByClassName("imgCrop_handle"+_4a[i],this.selArea)[0];
+if(el.childNodes.length){
+el.removeChild(el.childNodes[0]);
+}
+el.appendChild(d);
+}
+}
+}
+fixEl.appendChild(n);
+fixEl.removeChild(n);
+}
+},startResize:function(e){
+this.startCoords=this.cloneCoords(this.areaCoords);
+this.resizing=true;
+this.resizeHandle=Element.classNames(Event.element(e)).toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,"");
+Event.stop(e);
+},startDrag:function(e){
+Element.show(this.selArea);
+this.clickCoords=this.getCurPos(e);
+this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y});
+this.dragging=true;
+this.onDrag(e);
+Event.stop(e);
+},getCurPos:function(e){
+return curPos={x:Event.pointerX(e)-this.wrapOffsets.left,y:Event.pointerY(e)-this.wrapOffsets.top};
+},onDrag:function(e){
+var _4f=null;
+if(this.dragging||this.resizing){
+var _50=this.getCurPos(e);
+var _51=this.cloneCoords(this.areaCoords);
+var _52={x:1,y:1};
+}
+if(this.dragging){
+if(_50.x<this.clickCoords.x){
+_52.x=-1;
+}
+if(_50.y<this.clickCoords.y){
+_52.y=-1;
+}
+this.transformCoords(_50.x,this.clickCoords.x,_51,"x");
+this.transformCoords(_50.y,this.clickCoords.y,_51,"y");
+}else{
+if(this.resizing){
+_4f=this.resizeHandle;
+if(_4f.match(/E/)){
+this.transformCoords(_50.x,this.startCoords.x1,_51,"x");
+if(_50.x<this.startCoords.x1){
+_52.x=-1;
+}
+}else{
+if(_4f.match(/W/)){
+this.transformCoords(_50.x,this.startCoords.x2,_51,"x");
+if(_50.x<this.startCoords.x2){
+_52.x=-1;
+}
+}
+}
+if(_4f.match(/N/)){
+this.transformCoords(_50.y,this.startCoords.y2,_51,"y");
+if(_50.y<this.startCoords.y2){
+_52.y=-1;
+}
+}else{
+if(_4f.match(/S/)){
+this.transformCoords(_50.y,this.startCoords.y1,_51,"y");
+if(_50.y<this.startCoords.y1){
+_52.y=-1;
+}
+}
+}
+}
+}
+if(this.dragging||this.resizing){
+this.setAreaCoords(_51,false,e.shiftKey,_52,_4f);
+this.drawArea();
+Event.stop(e);
+}
+},transformCoords:function(_53,_54,_55,_56){
+var _57=new Array();
+if(_53<_54){
+_57[0]=_53;
+_57[1]=_54;
+}else{
+_57[0]=_54;
+_57[1]=_53;
+}
+if(_56=="x"){
+_55.x1=_57[0];
+_55.x2=_57[1];
+}else{
+_55.y1=_57[0];
+_55.y2=_57[1];
+}
+},endCrop:function(){
+this.dragging=false;
+this.resizing=false;
+this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()});
+},subInitialize:function(){
+},subDrawArea:function(){
+}};
+Cropper.ImgWithPreview=Class.create();
+Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){
+this.hasPreviewImg=false;
+if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){
+this.previewWrap=$(this.options.previewWrap);
+this.previewImg=this.img.cloneNode(false);
+this.options.displayOnInit=true;
+this.hasPreviewImg=true;
+Element.addClassName(this.previewWrap,"imgCrop_previewWrap");
+Element.setStyle(this.previewWrap,{width:this.options.minWidth+"px",height:this.options.minHeight+"px"});
+this.previewWrap.appendChild(this.previewImg);
+}
+},subDrawArea:function(){
+if(this.hasPreviewImg){
+var _58=this.calcW();
+var _59=this.calcH();
+var _5a={x:this.imgW/_58,y:this.imgH/_59};
+var _5b={x:_58/this.options.minWidth,y:_59/this.options.minHeight};
+var _5c={w:Math.ceil(this.options.minWidth*_5a.x)+"px",h:Math.ceil(this.options.minHeight*_5a.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_5b.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_5b.y)+"px"};
+var _5d=this.previewImg.style;
+_5d.width=_5c.w;
+_5d.height=_5c.h;
+_5d.left=_5c.x;
+_5d.top=_5c.y;
+}
+}});
diff --git a/src/wp-includes/js/crop/marqueeHoriz.gif b/src/wp-includes/js/crop/marqueeHoriz.gif
new file mode 100644
index 0000000000..685950394c
--- /dev/null
+++ b/src/wp-includes/js/crop/marqueeHoriz.gif
Binary files differ
diff --git a/src/wp-includes/js/crop/marqueeVert.gif b/src/wp-includes/js/crop/marqueeVert.gif
new file mode 100644
index 0000000000..ee55e203f8
--- /dev/null
+++ b/src/wp-includes/js/crop/marqueeVert.gif
Binary files differ
diff --git a/src/wp-includes/js/customize-base.js b/src/wp-includes/js/customize-base.js
new file mode 100644
index 0000000000..81d37716e6
--- /dev/null
+++ b/src/wp-includes/js/customize-base.js
@@ -0,0 +1,585 @@
+window.wp = window.wp || {};
+
+(function( exports, $ ){
+ var api, extend, ctor, inherits,
+ slice = Array.prototype.slice;
+
+ /* =====================================================================
+ * Micro-inheritance - thank you, backbone.js.
+ * ===================================================================== */
+
+ extend = function( protoProps, classProps ) {
+ var child = inherits( this, protoProps, classProps );
+ child.extend = this.extend;
+ return child;
+ };
+
+ // Shared empty constructor function to aid in prototype-chain creation.
+ ctor = function() {};
+
+ // Helper function to correctly set up the prototype chain, for subclasses.
+ // Similar to `goog.inherits`, but uses a hash of prototype properties and
+ // class properties to be extended.
+ inherits = function( parent, protoProps, staticProps ) {
+ var child;
+
+ // The constructor function for the new subclass is either defined by you
+ // (the "constructor" property in your `extend` definition), or defaulted
+ // by us to simply call `super()`.
+ if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) {
+ child = protoProps.constructor;
+ } else {
+ child = function() {
+ // Storing the result `super()` before returning the value
+ // prevents a bug in Opera where, if the constructor returns
+ // a function, Opera will reject the return value in favor of
+ // the original object. This causes all sorts of trouble.
+ var result = parent.apply( this, arguments );
+ return result;
+ };
+ }
+
+ // Inherit class (static) properties from parent.
+ $.extend( child, parent );
+
+ // Set the prototype chain to inherit from `parent`, without calling
+ // `parent`'s constructor function.
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor();
+
+ // Add prototype properties (instance properties) to the subclass,
+ // if supplied.
+ if ( protoProps )
+ $.extend( child.prototype, protoProps );
+
+ // Add static properties to the constructor function, if supplied.
+ if ( staticProps )
+ $.extend( child, staticProps );
+
+ // Correctly set child's `prototype.constructor`.
+ child.prototype.constructor = child;
+
+ // Set a convenience property in case the parent's prototype is needed later.
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+
+ api = {};
+
+ /* =====================================================================
+ * Base class.
+ * ===================================================================== */
+
+ api.Class = function( applicator, argsArray, options ) {
+ var magic, args = arguments;
+
+ if ( applicator && argsArray && api.Class.applicator === applicator ) {
+ args = argsArray;
+ $.extend( this, options || {} );
+ }
+
+ magic = this;
+ if ( this.instance ) {
+ magic = function() {
+ return magic.instance.apply( magic, arguments );
+ };
+
+ $.extend( magic, this );
+ }
+
+ magic.initialize.apply( magic, args );
+ return magic;
+ };
+
+ api.Class.applicator = {};
+
+ api.Class.prototype.initialize = function() {};
+
+ /*
+ * Checks whether a given instance extended a constructor.
+ *
+ * The magic surrounding the instance parameter causes the instanceof
+ * keyword to return inaccurate results; it defaults to the function's
+ * prototype instead of the constructor chain. Hence this function.
+ */
+ api.Class.prototype.extended = function( constructor ) {
+ var proto = this;
+
+ while ( typeof proto.constructor !== 'undefined' ) {
+ if ( proto.constructor === constructor )
+ return true;
+ if ( typeof proto.constructor.__super__ === 'undefined' )
+ return false;
+ proto = proto.constructor.__super__;
+ }
+ return false;
+ };
+
+ api.Class.extend = extend;
+
+ /* =====================================================================
+ * Events mixin.
+ * ===================================================================== */
+
+ api.Events = {
+ trigger: function( id ) {
+ if ( this.topics && this.topics[ id ] )
+ this.topics[ id ].fireWith( this, slice.call( arguments, 1 ) );
+ return this;
+ },
+
+ bind: function( id, callback ) {
+ this.topics = this.topics || {};
+ this.topics[ id ] = this.topics[ id ] || $.Callbacks();
+ this.topics[ id ].add.apply( this.topics[ id ], slice.call( arguments, 1 ) );
+ return this;
+ },
+
+ unbind: function( id, callback ) {
+ if ( this.topics && this.topics[ id ] )
+ this.topics[ id ].remove.apply( this.topics[ id ], slice.call( arguments, 1 ) );
+ return this;
+ }
+ };
+
+ /* =====================================================================
+ * Observable values that support two-way binding.
+ * ===================================================================== */
+
+ api.Value = api.Class.extend({
+ initialize: function( initial, options ) {
+ this._value = initial; // @todo: potentially change this to a this.set() call.
+ this.callbacks = $.Callbacks();
+
+ $.extend( this, options || {} );
+
+ this.set = $.proxy( this.set, this );
+ },
+
+ /*
+ * Magic. Returns a function that will become the instance.
+ * Set to null to prevent the instance from extending a function.
+ */
+ instance: function() {
+ return arguments.length ? this.set.apply( this, arguments ) : this.get();
+ },
+
+ get: function() {
+ return this._value;
+ },
+
+ set: function( to ) {
+ var from = this._value;
+
+ to = this._setter.apply( this, arguments );
+ to = this.validate( to );
+
+ // Bail if the sanitized value is null or unchanged.
+ if ( null === to || this._value === to )
+ return this;
+
+ this._value = to;
+
+ this.callbacks.fireWith( this, [ to, from ] );
+
+ return this;
+ },
+
+ _setter: function( to ) {
+ return to;
+ },
+
+ setter: function( callback ) {
+ var from = this.get();
+ this._setter = callback;
+ // Temporarily clear value so setter can decide if it's valid.
+ this._value = null;
+ this.set( from );
+ return this;
+ },
+
+ resetSetter: function() {
+ this._setter = this.constructor.prototype._setter;
+ this.set( this.get() );
+ return this;
+ },
+
+ validate: function( value ) {
+ return value;
+ },
+
+ bind: function( callback ) {
+ this.callbacks.add.apply( this.callbacks, arguments );
+ return this;
+ },
+
+ unbind: function( callback ) {
+ this.callbacks.remove.apply( this.callbacks, arguments );
+ return this;
+ },
+
+ link: function() { // values*
+ var set = this.set;
+ $.each( arguments, function() {
+ this.bind( set );
+ });
+ return this;
+ },
+
+ unlink: function() { // values*
+ var set = this.set;
+ $.each( arguments, function() {
+ this.unbind( set );
+ });
+ return this;
+ },
+
+ sync: function() { // values*
+ var that = this;
+ $.each( arguments, function() {
+ that.link( this );
+ this.link( that );
+ });
+ return this;
+ },
+
+ unsync: function() { // values*
+ var that = this;
+ $.each( arguments, function() {
+ that.unlink( this );
+ this.unlink( that );
+ });
+ return this;
+ }
+ });
+
+ /* =====================================================================
+ * A collection of observable values.
+ * ===================================================================== */
+
+ api.Values = api.Class.extend({
+ defaultConstructor: api.Value,
+
+ initialize: function( options ) {
+ $.extend( this, options || {} );
+
+ this._value = {};
+ this._deferreds = {};
+ },
+
+ instance: function( id ) {
+ if ( arguments.length === 1 )
+ return this.value( id );
+
+ return this.when.apply( this, arguments );
+ },
+
+ value: function( id ) {
+ return this._value[ id ];
+ },
+
+ has: function( id ) {
+ return typeof this._value[ id ] !== 'undefined';
+ },
+
+ add: function( id, value ) {
+ if ( this.has( id ) )
+ return this.value( id );
+
+ this._value[ id ] = value;
+ value.parent = this;
+ if ( value.extended( api.Value ) )
+ value.bind( this._change );
+
+ this.trigger( 'add', value );
+
+ if ( this._deferreds[ id ] )
+ this._deferreds[ id ].resolve();
+
+ return this._value[ id ];
+ },
+
+ create: function( id ) {
+ return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
+ },
+
+ each: function( callback, context ) {
+ context = typeof context === 'undefined' ? this : context;
+
+ $.each( this._value, function( key, obj ) {
+ callback.call( context, obj, key );
+ });
+ },
+
+ remove: function( id ) {
+ var value;
+
+ if ( this.has( id ) ) {
+ value = this.value( id );
+ this.trigger( 'remove', value );
+ if ( value.extended( api.Value ) )
+ value.unbind( this._change );
+ delete value.parent;
+ }
+
+ delete this._value[ id ];
+ delete this._deferreds[ id ];
+ },
+
+ /**
+ * Runs a callback once all requested values exist.
+ *
+ * when( ids*, [callback] );
+ *
+ * For example:
+ * when( id1, id2, id3, function( value1, value2, value3 ) {} );
+ *
+ * @returns $.Deferred.promise();
+ */
+ when: function() {
+ var self = this,
+ ids = slice.call( arguments ),
+ dfd = $.Deferred();
+
+ // If the last argument is a callback, bind it to .done()
+ if ( $.isFunction( ids[ ids.length - 1 ] ) )
+ dfd.done( ids.pop() );
+
+ $.when.apply( $, $.map( ids, function( id ) {
+ if ( self.has( id ) )
+ return;
+
+ return self._deferreds[ id ] = self._deferreds[ id ] || $.Deferred();
+ })).done( function() {
+ var values = $.map( ids, function( id ) {
+ return self( id );
+ });
+
+ // If a value is missing, we've used at least one expired deferred.
+ // Call Values.when again to generate a new deferred.
+ if ( values.length !== ids.length ) {
+ // ids.push( callback );
+ self.when.apply( self, ids ).done( function() {
+ dfd.resolveWith( self, values );
+ });
+ return;
+ }
+
+ dfd.resolveWith( self, values );
+ });
+
+ return dfd.promise();
+ },
+
+ _change: function() {
+ this.parent.trigger( 'change', this );
+ }
+ });
+
+ $.extend( api.Values.prototype, api.Events );
+
+ /* =====================================================================
+ * An observable value that syncs with an element.
+ *
+ * Handles inputs, selects, and textareas by default.
+ * ===================================================================== */
+
+ api.ensure = function( element ) {
+ return typeof element == 'string' ? $( element ) : element;
+ };
+
+ api.Element = api.Value.extend({
+ initialize: function( element, options ) {
+ var self = this,
+ synchronizer = api.Element.synchronizer.html,
+ type, update, refresh;
+
+ this.element = api.ensure( element );
+ this.events = '';
+
+ if ( this.element.is('input, select, textarea') ) {
+ this.events += 'change';
+ synchronizer = api.Element.synchronizer.val;
+
+ if ( this.element.is('input') ) {
+ type = this.element.prop('type');
+ if ( api.Element.synchronizer[ type ] )
+ synchronizer = api.Element.synchronizer[ type ];
+ if ( 'text' === type || 'password' === type )
+ this.events += ' keyup';
+ } else if ( this.element.is('textarea') ) {
+ this.events += ' keyup';
+ }
+ }
+
+ api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
+ this._value = this.get();
+
+ update = this.update;
+ refresh = this.refresh;
+
+ this.update = function( to ) {
+ if ( to !== refresh.call( self ) )
+ update.apply( this, arguments );
+ };
+ this.refresh = function() {
+ self.set( refresh.call( self ) );
+ };
+
+ this.bind( this.update );
+ this.element.bind( this.events, this.refresh );
+ },
+
+ find: function( selector ) {
+ return $( selector, this.element );
+ },
+
+ refresh: function() {},
+
+ update: function() {}
+ });
+
+ api.Element.synchronizer = {};
+
+ $.each( [ 'html', 'val' ], function( i, method ) {
+ api.Element.synchronizer[ method ] = {
+ update: function( to ) {
+ this.element[ method ]( to );
+ },
+ refresh: function() {
+ return this.element[ method ]();
+ }
+ };
+ });
+
+ api.Element.synchronizer.checkbox = {
+ update: function( to ) {
+ this.element.prop( 'checked', to );
+ },
+ refresh: function() {
+ return this.element.prop( 'checked' );
+ }
+ };
+
+ api.Element.synchronizer.radio = {
+ update: function( to ) {
+ this.element.filter( function() {
+ return this.value === to;
+ }).prop( 'checked', true );
+ },
+ refresh: function() {
+ return this.element.filter( ':checked' ).val();
+ }
+ };
+
+ /* =====================================================================
+ * Messenger for postMessage.
+ * ===================================================================== */
+
+ $.support.postMessage = !! window.postMessage;
+
+ api.Messenger = api.Class.extend({
+ add: function( key, initial, options ) {
+ return this[ key ] = new api.Value( initial, options );
+ },
+
+ /**
+ * Initialize Messenger.
+ *
+ * @param {object} params Parameters to configure the messenger.
+ * {string} .url The URL to communicate with.
+ * {window} .targetWindow The window instance to communicate with. Default window.parent.
+ * {string} .channel If provided, will send the channel with each message and only accept messages a matching channel.
+ * @param {object} options Extend any instance parameter or method with this object.
+ */
+ initialize: function( params, options ) {
+ // Target the parent frame by default, but only if a parent frame exists.
+ var defaultTarget = window.parent == window ? null : window.parent;
+
+ $.extend( this, options || {} );
+
+ this.add( 'channel', params.channel );
+ this.add( 'url', params.url || '' );
+ this.add( 'targetWindow', params.targetWindow || defaultTarget );
+ this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
+ return to.replace( /([^:]+:\/\/[^\/]+).*/, '$1' );
+ });
+
+ // Since we want jQuery to treat the receive function as unique
+ // to this instance, we give the function a new guid.
+ //
+ // This will prevent every Messenger's receive function from being
+ // unbound when calling $.off( 'message', this.receive );
+ this.receive = $.proxy( this.receive, this );
+ this.receive.guid = $.guid++;
+
+ $( window ).on( 'message', this.receive );
+ },
+
+ destroy: function() {
+ $( window ).off( 'message', this.receive );
+ },
+
+ receive: function( event ) {
+ var message;
+
+ event = event.originalEvent;
+
+ if ( ! this.targetWindow() )
+ return;
+
+ // Check to make sure the origin is valid.
+ if ( this.origin() && event.origin !== this.origin() )
+ return;
+
+ message = JSON.parse( event.data );
+
+ // Check required message properties.
+ if ( ! message || ! message.id || typeof message.data === 'undefined' )
+ return;
+
+ // Check if channel names match.
+ if ( ( message.channel || this.channel() ) && this.channel() !== message.channel )
+ return;
+
+ this.trigger( message.id, message.data );
+ },
+
+ send: function( id, data ) {
+ var message;
+
+ data = typeof data === 'undefined' ? null : data;
+
+ if ( ! this.url() || ! this.targetWindow() )
+ return;
+
+ message = { id: id, data: data };
+ if ( this.channel() )
+ message.channel = this.channel();
+
+ this.targetWindow().postMessage( JSON.stringify( message ), this.origin() );
+ }
+ });
+
+ // Add the Events mixin to api.Messenger.
+ $.extend( api.Messenger.prototype, api.Events );
+
+ /* =====================================================================
+ * Core customize object.
+ * ===================================================================== */
+
+ api = $.extend( new api.Values(), api );
+ api.get = function() {
+ var result = {};
+
+ this.each( function( obj, key ) {
+ result[ key ] = obj.get();
+ });
+
+ return result;
+ };
+
+ // Expose the API to the world.
+ exports.customize = api;
+})( wp, jQuery );
diff --git a/src/wp-includes/js/customize-loader.js b/src/wp-includes/js/customize-loader.js
new file mode 100644
index 0000000000..2ecbbe0fbf
--- /dev/null
+++ b/src/wp-includes/js/customize-loader.js
@@ -0,0 +1,164 @@
+window.wp = window.wp || {};
+
+(function( exports, $ ){
+ var api = wp.customize,
+ Loader;
+
+ $.extend( $.support, {
+ history: !! ( window.history && history.pushState ),
+ hashchange: ('onhashchange' in window) && (document.documentMode === undefined || document.documentMode > 7)
+ });
+
+ Loader = $.extend( {}, api.Events, {
+ initialize: function() {
+ this.body = $( document.body );
+
+ // Ensure the loader is supported.
+ // Check for settings, postMessage support, and whether we require CORS support.
+ if ( ! Loader.settings || ! $.support.postMessage || ( ! $.support.cors && Loader.settings.isCrossDomain ) ) {
+ return;
+ }
+
+ this.window = $( window );
+ this.element = $( '<div id="customize-container" />' ).appendTo( this.body );
+
+ this.bind( 'open', this.overlay.show );
+ this.bind( 'close', this.overlay.hide );
+
+ $('#wpbody').on( 'click', '.load-customize', function( event ) {
+ event.preventDefault();
+
+ // Store a reference to the link that opened the customizer.
+ Loader.link = $(this);
+ // Load the theme.
+ Loader.open( Loader.link.attr('href') );
+ });
+
+ // Add navigation listeners.
+ if ( $.support.history )
+ this.window.on( 'popstate', Loader.popstate );
+
+ if ( $.support.hashchange ) {
+ this.window.on( 'hashchange', Loader.hashchange );
+ this.window.triggerHandler( 'hashchange' );
+ }
+ },
+
+ popstate: function( e ) {
+ var state = e.originalEvent.state;
+ if ( state && state.customize )
+ Loader.open( state.customize );
+ else if ( Loader.active )
+ Loader.close();
+ },
+
+ hashchange: function( e ) {
+ var hash = window.location.toString().split('#')[1];
+
+ if ( hash && 0 === hash.indexOf( 'wp_customize=on' ) )
+ Loader.open( Loader.settings.url + '?' + hash );
+
+ if ( ! hash && ! $.support.history )
+ Loader.close();
+ },
+
+ open: function( src ) {
+ var hash;
+
+ if ( this.active )
+ return;
+
+ // Load the full page on mobile devices.
+ if ( Loader.settings.browser.mobile )
+ return window.location = src;
+
+ this.active = true;
+ this.body.addClass('customize-loading');
+
+ this.iframe = $( '<iframe />', { src: src }).appendTo( this.element );
+ this.iframe.one( 'load', this.loaded );
+
+ // Create a postMessage connection with the iframe.
+ this.messenger = new api.Messenger({
+ url: src,
+ channel: 'loader',
+ targetWindow: this.iframe[0].contentWindow
+ });
+
+ // Wait for the connection from the iframe before sending any postMessage events.
+ this.messenger.bind( 'ready', function() {
+ Loader.messenger.send( 'back' );
+ });
+
+ this.messenger.bind( 'close', function() {
+ if ( $.support.history )
+ history.back();
+ else if ( $.support.hashchange )
+ window.location.hash = '';
+ else
+ Loader.close();
+ });
+
+ this.messenger.bind( 'activated', function( location ) {
+ if ( location )
+ window.location = location;
+ });
+
+ hash = src.split('?')[1];
+
+ // Ensure we don't call pushState if the user hit the forward button.
+ if ( $.support.history && window.location.href !== src )
+ history.pushState( { customize: src }, '', src );
+ else if ( ! $.support.history && $.support.hashchange && hash )
+ window.location.hash = 'wp_customize=on&' + hash;
+
+ this.trigger( 'open' );
+ },
+
+ opened: function() {
+ Loader.body.addClass( 'customize-active full-overlay-active' );
+ },
+
+ close: function() {
+ if ( ! this.active )
+ return;
+ this.active = false;
+
+ this.trigger( 'close' );
+
+ // Return focus to link that was originally clicked.
+ if ( this.link )
+ this.link.focus();
+ },
+
+ closed: function() {
+ Loader.iframe.remove();
+ Loader.messenger.destroy();
+ Loader.iframe = null;
+ Loader.messenger = null;
+ Loader.body.removeClass( 'customize-active full-overlay-active' ).removeClass( 'customize-loading' );
+ },
+
+ loaded: function() {
+ Loader.body.removeClass('customize-loading');
+ },
+
+ overlay: {
+ show: function() {
+ this.element.fadeIn( 200, Loader.opened );
+ },
+
+ hide: function() {
+ this.element.fadeOut( 200, Loader.closed );
+ }
+ }
+ });
+
+ $( function() {
+ Loader.settings = _wpCustomizeLoaderSettings;
+ Loader.initialize();
+ });
+
+ // Expose the API to the world.
+ api.Loader = Loader;
+})( wp, jQuery );
diff --git a/src/wp-includes/js/customize-preview.js b/src/wp-includes/js/customize-preview.js
new file mode 100644
index 0000000000..caefe653a9
--- /dev/null
+++ b/src/wp-includes/js/customize-preview.js
@@ -0,0 +1,146 @@
+(function( exports, $ ){
+ var api = wp.customize,
+ debounce;
+
+ debounce = function( fn, delay, context ) {
+ var timeout;
+ return function() {
+ var args = arguments;
+
+ context = context || this;
+
+ clearTimeout( timeout );
+ timeout = setTimeout( function() {
+ timeout = null;
+ fn.apply( context, args );
+ }, delay );
+ };
+ };
+
+ api.Preview = api.Messenger.extend({
+ /**
+ * Requires params:
+ * - url - the URL of preview frame
+ */
+ initialize: function( params, options ) {
+ var self = this;
+
+ api.Messenger.prototype.initialize.call( this, params, options );
+
+ this.body = $( document.body );
+ this.body.on( 'click.preview', 'a', function( event ) {
+ event.preventDefault();
+ self.send( 'scroll', 0 );
+ self.send( 'url', $(this).prop('href') );
+ });
+
+ // You cannot submit forms.
+ // @todo: Allow form submissions by mixing $_POST data with the customize setting $_POST data.
+ this.body.on( 'submit.preview', 'form', function( event ) {
+ event.preventDefault();
+ });
+
+ this.window = $( window );
+ this.window.on( 'scroll.preview', debounce( function() {
+ self.send( 'scroll', self.window.scrollTop() );
+ }, 200 ));
+
+ this.bind( 'scroll', function( distance ) {
+ self.window.scrollTop( distance );
+ });
+ }
+ });
+
+ $( function() {
+ api.settings = window._wpCustomizeSettings;
+ if ( ! api.settings )
+ return;
+
+ var preview, bg;
+
+ preview = new api.Preview({
+ url: window.location.href,
+ channel: api.settings.channel
+ });
+
+ preview.bind( 'settings', function( values ) {
+ $.each( values, function( id, value ) {
+ if ( api.has( id ) )
+ api( id ).set( value );
+ else
+ api.create( id, value );
+ });
+ });
+
+ preview.trigger( 'settings', api.settings.values );
+
+ preview.bind( 'setting', function( args ) {
+ var value;
+
+ args = args.slice();
+
+ if ( value = api( args.shift() ) )
+ value.set.apply( value, args );
+ });
+
+ preview.bind( 'sync', function( events ) {
+ $.each( events, function( event, args ) {
+ preview.trigger( event, args );
+ });
+ preview.send( 'synced' );
+ });
+
+ preview.bind( 'active', function() {
+ if ( api.settings.nonce )
+ preview.send( 'nonce', api.settings.nonce );
+ });
+
+ preview.send( 'ready' );
+
+ /* Custom Backgrounds */
+ bg = $.map(['color', 'image', 'position_x', 'repeat', 'attachment'], function( prop ) {
+ return 'background_' + prop;
+ });
+
+ api.when.apply( api, bg ).done( function( color, image, position_x, repeat, attachment ) {
+ var body = $(document.body),
+ head = $('head'),
+ style = $('#custom-background-css'),
+ update;
+
+ // If custom backgrounds are active and we can't find the
+ // default output, bail.
+ if ( body.hasClass('custom-background') && ! style.length )
+ return;
+
+ update = function() {
+ var css = '';
+
+ // The body will support custom backgrounds if either
+ // the color or image are set.
+ //
+ // See get_body_class() in /wp-includes/post-template.php
+ body.toggleClass( 'custom-background', !! ( color() || image() ) );
+
+ if ( color() )
+ css += 'background-color: ' + color() + ';';
+
+ if ( image() ) {
+ css += 'background-image: url("' + image() + '");';
+ css += 'background-position: top ' + position_x() + ';';
+ css += 'background-repeat: ' + repeat() + ';';
+ css += 'background-attachment: ' + attachment() + ';';
+ }
+
+ // Refresh the stylesheet by removing and recreating it.
+ style.remove();
+ style = $('<style type="text/css" id="custom-background-css">body.custom-background { ' + css + ' }</style>').appendTo( head );
+ };
+
+ $.each( arguments, function() {
+ this.bind( update );
+ });
+ });
+ });
+
+})( wp, jQuery );
diff --git a/src/wp-includes/js/heartbeat.js b/src/wp-includes/js/heartbeat.js
new file mode 100644
index 0000000000..8023600659
--- /dev/null
+++ b/src/wp-includes/js/heartbeat.js
@@ -0,0 +1,461 @@
+/**
+ * Heartbeat API
+ *
+ * Note: this API is "experimental" meaning it will likely change a lot
+ * in the next few releases based on feedback from 3.6.0. If you intend
+ * to use it, please follow the development closely.
+ *
+ * Heartbeat is a simple server polling API that sends XHR requests to
+ * the server every 15 seconds and triggers events (or callbacks) upon
+ * receiving data. Currently these 'ticks' handle transports for post locking,
+ * login-expiration warnings, and related tasks while a user is logged in.
+ *
+ * Available filters in ajax-actions.php:
+ * - heartbeat_received
+ * - heartbeat_send
+ * - heartbeat_tick
+ * - heartbeat_nopriv_received
+ * - heartbeat_nopriv_send
+ * - heartbeat_nopriv_tick
+ * @see wp_ajax_nopriv_heartbeat(), wp_ajax_heartbeat()
+ *
+ * @since 3.6.0
+ */
+
+ // Ensure the global `wp` object exists.
+window.wp = window.wp || {};
+
+(function($){
+ var Heartbeat = function() {
+ var self = this,
+ running,
+ beat,
+ screenId = typeof pagenow != 'undefined' ? pagenow : '',
+ url = typeof ajaxurl != 'undefined' ? ajaxurl : '',
+ settings,
+ tick = 0,
+ queue = {},
+ interval,
+ connecting,
+ countdown = 0,
+ errorcount = 0,
+ tempInterval,
+ hasFocus = true,
+ isUserActive,
+ userActiveEvents,
+ winBlurTimeout,
+ frameBlurTimeout = -1,
+ hasConnectionError = false;
+
+ /**
+ * Returns a boolean that's indicative of whether or not there is a connection error
+ *
+ * @returns boolean
+ */
+ this.hasConnectionError = function() {
+ return hasConnectionError;
+ };
+
+ if ( typeof( window.heartbeatSettings ) == 'object' ) {
+ settings = $.extend( {}, window.heartbeatSettings );
+
+ // Add private vars
+ url = settings.ajaxurl || url;
+ delete settings.ajaxurl;
+ delete settings.nonce;
+
+ interval = settings.interval || 15; // default interval
+ delete settings.interval;
+ // The interval can be from 15 to 60 sec. and can be set temporarily to 5 sec.
+ if ( interval < 15 )
+ interval = 15;
+ else if ( interval > 60 )
+ interval = 60;
+
+ interval = interval * 1000;
+
+ // 'screenId' can be added from settings on the front-end where the JS global 'pagenow' is not set
+ screenId = screenId || settings.screenId || 'front';
+ delete settings.screenId;
+
+ // Add or overwrite public vars
+ $.extend( this, settings );
+ }
+
+ function time(s) {
+ if ( s )
+ return parseInt( (new Date()).getTime() / 1000 );
+
+ return (new Date()).getTime();
+ }
+
+ function isLocalFrame( frame ) {
+ var origin, src = frame.src;
+
+ if ( src && /^https?:\/\//.test( src ) ) {
+ origin = window.location.origin ? window.location.origin : window.location.protocol + '//' + window.location.host;
+
+ if ( src.indexOf( origin ) !== 0 )
+ return false;
+ }
+
+ try {
+ if ( frame.contentWindow.document )
+ return true;
+ } catch(e) {}
+
+ return false;
+ }
+
+ // Set error state and fire an event on XHR errors or timeout
+ function errorstate( error ) {
+ var trigger;
+
+ if ( error ) {
+ switch ( error ) {
+ case 'abort':
+ // do nothing
+ break;
+ case 'timeout':
+ // no response for 30 sec.
+ trigger = true;
+ break;
+ case 'parsererror':
+ case 'error':
+ case 'empty':
+ case 'unknown':
+ errorcount++;
+
+ if ( errorcount > 2 )
+ trigger = true;
+
+ break;
+ }
+
+ if ( trigger && ! self.hasConnectionError() ) {
+ hasConnectionError = true;
+ $(document).trigger( 'heartbeat-connection-lost', [error] );
+ }
+ } else if ( self.hasConnectionError() ) {
+ errorcount = 0;
+ hasConnectionError = false;
+ $(document).trigger( 'heartbeat-connection-restored' );
+ }
+ }
+
+ function connect() {
+ var send = {}, data, i, empty = true,
+ nonce = typeof window.heartbeatSettings == 'object' ? window.heartbeatSettings.nonce : '';
+ tick = time();
+
+ data = $.extend( {}, queue );
+ // Clear the data queue, anything added after this point will be send on the next tick
+ queue = {};
+
+ $(document).trigger( 'heartbeat-send', [data] );
+
+ for ( i in data ) {
+ if ( data.hasOwnProperty( i ) ) {
+ empty = false;
+ break;
+ }
+ }
+
+ // If nothing to send (nothing is expecting a response),
+ // schedule the next tick and bail
+ if ( empty && ! self.hasConnectionError() ) {
+ connecting = false;
+ next();
+ return;
+ }
+
+ send.data = data;
+ send.interval = interval / 1000;
+ send._nonce = nonce;
+ send.action = 'heartbeat';
+ send.screen_id = screenId;
+ send.has_focus = hasFocus;
+
+ connecting = true;
+ self.xhr = $.ajax({
+ url: url,
+ type: 'post',
+ timeout: 30000, // throw an error if not completed after 30 sec.
+ data: send,
+ dataType: 'json'
+ }).done( function( response, textStatus, jqXHR ) {
+ var new_interval;
+
+ if ( ! response )
+ return errorstate( 'empty' );
+
+ // Clear error state
+ if ( self.hasConnectionError() )
+ errorstate();
+
+ if ( response.nonces_expired ) {
+ $(document).trigger( 'heartbeat-nonces-expired' );
+ return;
+ }
+
+ // Change the interval from PHP
+ if ( response.heartbeat_interval ) {
+ new_interval = response.heartbeat_interval;
+ delete response.heartbeat_interval;
+ }
+
+ self.tick( response, textStatus, jqXHR );
+
+ // do this last, can trigger the next XHR if connection time > 5 sec. and new_interval == 'fast'
+ if ( new_interval )
+ self.interval.call( self, new_interval );
+ }).always( function() {
+ connecting = false;
+ next();
+ }).fail( function( jqXHR, textStatus, error ) {
+ errorstate( textStatus || 'unknown' );
+ self.error( jqXHR, textStatus, error );
+ });
+ }
+
+ function next() {
+ var delta = time() - tick, t = interval;
+
+ if ( ! running )
+ return;
+
+ if ( ! hasFocus ) {
+ t = 100000; // 100 sec. Post locks expire after 120 sec.
+ } else if ( countdown > 0 && tempInterval ) {
+ t = tempInterval;
+ countdown--;
+ }
+
+ window.clearTimeout(beat);
+
+ if ( delta < t ) {
+ beat = window.setTimeout(
+ function(){
+ if ( running )
+ connect();
+ },
+ t - delta
+ );
+ } else {
+ connect();
+ }
+ }
+
+ function blurred() {
+ window.clearTimeout(winBlurTimeout);
+ window.clearTimeout(frameBlurTimeout);
+ winBlurTimeout = frameBlurTimeout = 0;
+
+ hasFocus = false;
+ }
+
+ function focused() {
+ window.clearTimeout(winBlurTimeout);
+ window.clearTimeout(frameBlurTimeout);
+ winBlurTimeout = frameBlurTimeout = 0;
+
+ isUserActive = time();
+
+ if ( hasFocus )
+ return;
+
+ hasFocus = true;
+ window.clearTimeout(beat);
+
+ if ( ! connecting )
+ next();
+ }
+
+ function setFrameEvents() {
+ $('iframe').each( function( i, frame ){
+ if ( ! isLocalFrame( frame ) )
+ return;
+
+ if ( $.data( frame, 'wp-heartbeat-focus' ) )
+ return;
+
+ $.data( frame, 'wp-heartbeat-focus', 1 );
+
+ $( frame.contentWindow ).on( 'focus.wp-heartbeat-focus', function(e) {
+ focused();
+ }).on('blur.wp-heartbeat-focus', function(e) {
+ setFrameEvents();
+ frameBlurTimeout = window.setTimeout( function(){ blurred(); }, 500 );
+ });
+ });
+ }
+
+ $(window).on( 'blur.wp-heartbeat-focus', function(e) {
+ setFrameEvents();
+ winBlurTimeout = window.setTimeout( function(){ blurred(); }, 500 );
+ }).on( 'focus.wp-heartbeat-focus', function() {
+ $('iframe').each( function( i, frame ) {
+ if ( !isLocalFrame( frame ) )
+ return;
+
+ $.removeData( frame, 'wp-heartbeat-focus' );
+ $( frame.contentWindow ).off( '.wp-heartbeat-focus' );
+ });
+
+ focused();
+ });
+
+ function userIsActive() {
+ userActiveEvents = false;
+ $(document).off( '.wp-heartbeat-active' );
+ $('iframe').each( function( i, frame ) {
+ if ( ! isLocalFrame( frame ) )
+ return;
+
+ $( frame.contentWindow ).off( '.wp-heartbeat-active' );
+ });
+
+ focused();
+ }
+
+ // Set 'hasFocus = true' if user is active and the window is in the background.
+ // Set 'hasFocus = false' if the user has been inactive (no mouse or keyboard activity) for 5 min. even when the window has focus.
+ function checkUserActive() {
+ var lastActive = isUserActive ? time() - isUserActive : 0;
+
+ // Throttle down when no mouse or keyboard activity for 5 min
+ if ( lastActive > 300000 && hasFocus )
+ blurred();
+
+ if ( ! userActiveEvents ) {
+ $(document).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } );
+
+ $('iframe').each( function( i, frame ) {
+ if ( ! isLocalFrame( frame ) )
+ return;
+
+ $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } );
+ });
+
+ userActiveEvents = true;
+ }
+ }
+
+ // Check for user activity every 30 seconds.
+ window.setInterval( function(){ checkUserActive(); }, 30000 );
+ $(document).ready( function() {
+ // Start one tick (15 sec) after DOM ready
+ running = true;
+ tick = time();
+ next();
+ });
+
+ this.hasFocus = function() {
+ return hasFocus;
+ };
+
+ /**
+ * Get/Set the interval
+ *
+ * When setting to 'fast', the interval is 5 sec. for the next 30 ticks (for 2 min and 30 sec).
+ * If the window doesn't have focus, the interval slows down to 2 min.
+ *
+ * @param string speed Interval speed: 'fast' (5sec), 'standard' (15sec) default, 'slow' (60sec)
+ * @param string ticks Used with speed = 'fast', how many ticks before the speed reverts back
+ * @return int Current interval in seconds
+ */
+ this.interval = function( speed, ticks ) {
+ var reset, seconds;
+ ticks = parseInt( ticks, 10 ) || 30;
+ ticks = ticks < 1 || ticks > 30 ? 30 : ticks;
+
+ if ( speed ) {
+ switch ( speed ) {
+ case 'fast':
+ seconds = 5;
+ countdown = ticks;
+ break;
+ case 'slow':
+ seconds = 60;
+ countdown = 0;
+ break;
+ case 'long-polling':
+ // Allow long polling, (experimental)
+ interval = 0;
+ return 0;
+ break;
+ default:
+ seconds = 15;
+ countdown = 0;
+ }
+
+ // Reset when the new interval value is lower than the current one
+ reset = seconds * 1000 < interval;
+
+ if ( countdown > 0 ) {
+ tempInterval = seconds * 1000;
+ } else {
+ interval = seconds * 1000;
+ tempInterval = 0;
+ }
+
+ if ( reset )
+ next();
+ }
+
+ if ( ! hasFocus )
+ return 120;
+
+ return tempInterval ? tempInterval / 1000 : interval / 1000;
+ };
+
+ /**
+ * Enqueue data to send with the next XHR
+ *
+ * As the data is sent later, this function doesn't return the XHR response.
+ * To see the response, use the custom jQuery event 'heartbeat-tick' on the document, example:
+ * $(document).on( 'heartbeat-tick.myname', function( event, data, textStatus, jqXHR ) {
+ * // code
+ * });
+ * If the same 'handle' is used more than once, the data is not overwritten when the third argument is 'true'.
+ * Use wp.heartbeat.isQueued('handle') to see if any data is already queued for that handle.
+ *
+ * $param string handle Unique handle for the data. The handle is used in PHP to receive the data.
+ * $param mixed data The data to send.
+ * $param bool dont_overwrite Whether to overwrite existing data in the queue.
+ * $return bool Whether the data was queued or not.
+ */
+ this.enqueue = function( handle, data, dont_overwrite ) {
+ if ( handle ) {
+ if ( queue.hasOwnProperty( handle ) && dont_overwrite )
+ return false;
+
+ queue[handle] = data;
+ return true;
+ }
+ return false;
+ };
+
+ /**
+ * Check if data with a particular handle is queued
+ *
+ * $param string handle The handle for the data
+ * $return mixed The data queued with that handle or null
+ */
+ this.isQueued = function( handle ) {
+ return queue[handle];
+ };
+ };
+
+ $.extend( Heartbeat.prototype, {
+ tick: function( data, textStatus, jqXHR ) {
+ $(document).trigger( 'heartbeat-tick', [data, textStatus, jqXHR] );
+ },
+ error: function( jqXHR, textStatus, error ) {
+ $(document).trigger( 'heartbeat-error', [jqXHR, textStatus, error] );
+ }
+ });
+
+ wp.heartbeat = new Heartbeat();
+
+}(jQuery));
diff --git a/src/wp-includes/js/hoverIntent.js b/src/wp-includes/js/hoverIntent.js
new file mode 100644
index 0000000000..88e0e8a241
--- /dev/null
+++ b/src/wp-includes/js/hoverIntent.js
@@ -0,0 +1,115 @@
+/*!
+ * hoverIntent r7 // 2013.03.11 // jQuery 1.9.1+
+ * http://cherne.net/brian/resources/jquery.hoverIntent.html
+ *
+ * You may use hoverIntent under the terms of the MIT license. Basically that
+ * means you are free to use hoverIntent as long as this header is left intact.
+ * Copyright 2007, 2013 Brian Cherne
+ */
+
+/* hoverIntent is similar to jQuery's built-in "hover" method except that
+ * instead of firing the handlerIn function immediately, hoverIntent checks
+ * to see if the user's mouse has slowed down (beneath the sensitivity
+ * threshold) before firing the event. The handlerOut function is only
+ * called after a matching handlerIn.
+ *
+ * // basic usage ... just like .hover()
+ * .hoverIntent( handlerIn, handlerOut )
+ * .hoverIntent( handlerInOut )
+ *
+ * // basic usage ... with event delegation!
+ * .hoverIntent( handlerIn, handlerOut, selector )
+ * .hoverIntent( handlerInOut, selector )
+ *
+ * // using a basic configuration object
+ * .hoverIntent( config )
+ *
+ * @param handlerIn function OR configuration object
+ * @param handlerOut function OR selector for delegation OR undefined
+ * @param selector selector OR undefined
+ * @author Brian Cherne <brian(at)cherne(dot)net>
+ */
+(function($) {
+ $.fn.hoverIntent = function(handlerIn,handlerOut,selector) {
+
+ // default configuration values
+ var cfg = {
+ interval: 100,
+ sensitivity: 7,
+ timeout: 0
+ };
+
+ if ( typeof handlerIn === "object" ) {
+ cfg = $.extend(cfg, handlerIn );
+ } else if ($.isFunction(handlerOut)) {
+ cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } );
+ } else {
+ cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } );
+ }
+
+ // instantiate variables
+ // cX, cY = current X and Y position of mouse, updated by mousemove event
+ // pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
+ var cX, cY, pX, pY;
+
+ // A private function for getting mouse position
+ var track = function(ev) {
+ cX = ev.pageX;
+ cY = ev.pageY;
+ };
+
+ // A private function for comparing current and previous mouse position
+ var compare = function(ev,ob) {
+ ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+ // compare mouse positions to see if they've crossed the threshold
+ if ( ( Math.abs(pX-cX) + Math.abs(pY-cY) ) < cfg.sensitivity ) {
+ $(ob).off("mousemove.hoverIntent",track);
+ // set hoverIntent state to true (so mouseOut can be called)
+ ob.hoverIntent_s = 1;
+ return cfg.over.apply(ob,[ev]);
+ } else {
+ // set previous coordinates for next time
+ pX = cX; pY = cY;
+ // use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
+ ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
+ }
+ };
+
+ // A private function for delaying the mouseOut function
+ var delay = function(ev,ob) {
+ ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
+ ob.hoverIntent_s = 0;
+ return cfg.out.apply(ob,[ev]);
+ };
+
+ // A private function for handling mouse 'hovering'
+ var handleHover = function(e) {
+ // copy objects to be passed into t (required for event object to be passed in IE)
+ var ev = jQuery.extend({},e);
+ var ob = this;
+
+ // cancel hoverIntent timer if it exists
+ if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
+
+ // if e.type == "mouseenter"
+ if (e.type == "mouseenter") {
+ // set "previous" X and Y position based on initial entry point
+ pX = ev.pageX; pY = ev.pageY;
+ // update "current" X and Y position based on mousemove
+ $(ob).on("mousemove.hoverIntent",track);
+ // start polling interval (self-calling timeout) to compare mouse coordinates over time
+ if (ob.hoverIntent_s != 1) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
+
+ // else e.type == "mouseleave"
+ } else {
+ // unbind expensive mousemove event
+ $(ob).off("mousemove.hoverIntent",track);
+ // if hoverIntent state is true, then call the mouseOut function after the specified delay
+ if (ob.hoverIntent_s == 1) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
+ }
+ };
+
+ // listen for mouseenter and mouseleave
+ return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector);
+ };
+})(jQuery);
diff --git a/src/wp-includes/js/imgareaselect/border-anim-h.gif b/src/wp-includes/js/imgareaselect/border-anim-h.gif
new file mode 100644
index 0000000000..a964ebd717
--- /dev/null
+++ b/src/wp-includes/js/imgareaselect/border-anim-h.gif
Binary files differ
diff --git a/src/wp-includes/js/imgareaselect/border-anim-v.gif b/src/wp-includes/js/imgareaselect/border-anim-v.gif
new file mode 100644
index 0000000000..aa319935e4
--- /dev/null
+++ b/src/wp-includes/js/imgareaselect/border-anim-v.gif
Binary files differ
diff --git a/src/wp-includes/js/imgareaselect/imgareaselect.css b/src/wp-includes/js/imgareaselect/imgareaselect.css
new file mode 100644
index 0000000000..fd587a69d3
--- /dev/null
+++ b/src/wp-includes/js/imgareaselect/imgareaselect.css
@@ -0,0 +1,41 @@
+/*
+ * imgAreaSelect animated border style
+ */
+
+.imgareaselect-border1 {
+ background: url(border-anim-v.gif) repeat-y left top;
+}
+
+.imgareaselect-border2 {
+ background: url(border-anim-h.gif) repeat-x left top;
+}
+
+.imgareaselect-border3 {
+ background: url(border-anim-v.gif) repeat-y right top;
+}
+
+.imgareaselect-border4 {
+ background: url(border-anim-h.gif) repeat-x left bottom;
+}
+
+.imgareaselect-border1, .imgareaselect-border2,
+.imgareaselect-border3, .imgareaselect-border4 {
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+}
+
+.imgareaselect-handle {
+ background-color: #fff;
+ border: solid 1px #000;
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+}
+
+.imgareaselect-outer {
+ background-color: #000;
+ filter: alpha(opacity=50);
+ opacity: 0.5;
+}
+
+.imgareaselect-selection {
+}
diff --git a/src/wp-includes/js/imgareaselect/jquery.imgareaselect.js b/src/wp-includes/js/imgareaselect/jquery.imgareaselect.js
new file mode 100644
index 0000000000..28860461b6
--- /dev/null
+++ b/src/wp-includes/js/imgareaselect/jquery.imgareaselect.js
@@ -0,0 +1,1198 @@
+/*
+ * imgAreaSelect jQuery plugin
+ * version 0.9.9
+ *
+ * Copyright (c) 2008-2011 Michal Wojciechowski (odyniec.net)
+ *
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://odyniec.net/projects/imgareaselect/
+ *
+ */
+
+(function($) {
+
+/*
+ * Math functions will be used extensively, so it's convenient to make a few
+ * shortcuts
+ */
+var abs = Math.abs,
+ max = Math.max,
+ min = Math.min,
+ round = Math.round;
+
+/**
+ * Create a new HTML div element
+ *
+ * @return A jQuery object representing the new element
+ */
+function div() {
+ return $('<div/>');
+}
+
+/**
+ * imgAreaSelect initialization
+ *
+ * @param img
+ * A HTML image element to attach the plugin to
+ * @param options
+ * An options object
+ */
+$.imgAreaSelect = function (img, options) {
+ var
+ /* jQuery object representing the image */
+ $img = $(img),
+
+ /* Has the image finished loading? */
+ imgLoaded,
+
+ /* Plugin elements */
+
+ /* Container box */
+ $box = div(),
+ /* Selection area */
+ $area = div(),
+ /* Border (four divs) */
+ $border = div().add(div()).add(div()).add(div()),
+ /* Outer area (four divs) */
+ $outer = div().add(div()).add(div()).add(div()),
+ /* Handles (empty by default, initialized in setOptions()) */
+ $handles = $([]),
+
+ /*
+ * Additional element to work around a cursor problem in Opera
+ * (explained later)
+ */
+ $areaOpera,
+
+ /* Image position (relative to viewport) */
+ left, top,
+
+ /* Image offset (as returned by .offset()) */
+ imgOfs = { left: 0, top: 0 },
+
+ /* Image dimensions (as returned by .width() and .height()) */
+ imgWidth, imgHeight,
+
+ /*
+ * jQuery object representing the parent element that the plugin
+ * elements are appended to
+ */
+ $parent,
+
+ /* Parent element offset (as returned by .offset()) */
+ parOfs = { left: 0, top: 0 },
+
+ /* Base z-index for plugin elements */
+ zIndex = 0,
+
+ /* Plugin elements position */
+ position = 'absolute',
+
+ /* X/Y coordinates of the starting point for move/resize operations */
+ startX, startY,
+
+ /* Horizontal and vertical scaling factors */
+ scaleX, scaleY,
+
+ /* Current resize mode ("nw", "se", etc.) */
+ resize,
+
+ /* Selection area constraints */
+ minWidth, minHeight, maxWidth, maxHeight,
+
+ /* Aspect ratio to maintain (floating point number) */
+ aspectRatio,
+
+ /* Are the plugin elements currently displayed? */
+ shown,
+
+ /* Current selection (relative to parent element) */
+ x1, y1, x2, y2,
+
+ /* Current selection (relative to scaled image) */
+ selection = { x1: 0, y1: 0, x2: 0, y2: 0, width: 0, height: 0 },
+
+ /* Document element */
+ docElem = document.documentElement,
+
+ /* Various helper variables used throughout the code */
+ $p, d, i, o, w, h, adjusted;
+
+ /*
+ * Translate selection coordinates (relative to scaled image) to viewport
+ * coordinates (relative to parent element)
+ */
+
+ /**
+ * Translate selection X to viewport X
+ *
+ * @param x
+ * Selection X
+ * @return Viewport X
+ */
+ function viewX(x) {
+ return x + imgOfs.left - parOfs.left;
+ }
+
+ /**
+ * Translate selection Y to viewport Y
+ *
+ * @param y
+ * Selection Y
+ * @return Viewport Y
+ */
+ function viewY(y) {
+ return y + imgOfs.top - parOfs.top;
+ }
+
+ /*
+ * Translate viewport coordinates to selection coordinates
+ */
+
+ /**
+ * Translate viewport X to selection X
+ *
+ * @param x
+ * Viewport X
+ * @return Selection X
+ */
+ function selX(x) {
+ return x - imgOfs.left + parOfs.left;
+ }
+
+ /**
+ * Translate viewport Y to selection Y
+ *
+ * @param y
+ * Viewport Y
+ * @return Selection Y
+ */
+ function selY(y) {
+ return y - imgOfs.top + parOfs.top;
+ }
+
+ /*
+ * Translate event coordinates (relative to document) to viewport
+ * coordinates
+ */
+
+ /**
+ * Get event X and translate it to viewport X
+ *
+ * @param event
+ * The event object
+ * @return Viewport X
+ */
+ function evX(event) {
+ return event.pageX - parOfs.left;
+ }
+
+ /**
+ * Get event Y and translate it to viewport Y
+ *
+ * @param event
+ * The event object
+ * @return Viewport Y
+ */
+ function evY(event) {
+ return event.pageY - parOfs.top;
+ }
+
+ /**
+ * Get the current selection
+ *
+ * @param noScale
+ * If set to <code>true</code>, scaling is not applied to the
+ * returned selection
+ * @return Selection object
+ */
+ function getSelection(noScale) {
+ var sx = noScale || scaleX, sy = noScale || scaleY;
+
+ return { x1: round(selection.x1 * sx),
+ y1: round(selection.y1 * sy),
+ x2: round(selection.x2 * sx),
+ y2: round(selection.y2 * sy),
+ width: round(selection.x2 * sx) - round(selection.x1 * sx),
+ height: round(selection.y2 * sy) - round(selection.y1 * sy) };
+ }
+
+ /**
+ * Set the current selection
+ *
+ * @param x1
+ * X coordinate of the upper left corner of the selection area
+ * @param y1
+ * Y coordinate of the upper left corner of the selection area
+ * @param x2
+ * X coordinate of the lower right corner of the selection area
+ * @param y2
+ * Y coordinate of the lower right corner of the selection area
+ * @param noScale
+ * If set to <code>true</code>, scaling is not applied to the
+ * new selection
+ */
+ function setSelection(x1, y1, x2, y2, noScale) {
+ var sx = noScale || scaleX, sy = noScale || scaleY;
+
+ selection = {
+ x1: round(x1 / sx || 0),
+ y1: round(y1 / sy || 0),
+ x2: round(x2 / sx || 0),
+ y2: round(y2 / sy || 0)
+ };
+
+ selection.width = selection.x2 - selection.x1;
+ selection.height = selection.y2 - selection.y1;
+ }
+
+ /**
+ * Recalculate image and parent offsets
+ */
+ function adjust() {
+ /*
+ * Do not adjust if image width is not a positive number. This might
+ * happen when imgAreaSelect is put on a parent element which is then
+ * hidden.
+ */
+ if (!$img.width())
+ return;
+
+ /*
+ * Get image offset. The .offset() method returns float values, so they
+ * need to be rounded.
+ */
+ imgOfs = { left: round($img.offset().left), top: round($img.offset().top) };
+
+ /* Get image dimensions */
+ imgWidth = $img.innerWidth();
+ imgHeight = $img.innerHeight();
+
+ imgOfs.top += ($img.outerHeight() - imgHeight) >> 1;
+ imgOfs.left += ($img.outerWidth() - imgWidth) >> 1;
+
+ /* Set minimum and maximum selection area dimensions */
+ minWidth = round(options.minWidth / scaleX) || 0;
+ minHeight = round(options.minHeight / scaleY) || 0;
+ maxWidth = round(min(options.maxWidth / scaleX || 1<<24, imgWidth));
+ maxHeight = round(min(options.maxHeight / scaleY || 1<<24, imgHeight));
+
+ /*
+ * Workaround for jQuery 1.3.2 incorrect offset calculation, originally
+ * observed in Safari 3. Firefox 2 is also affected.
+ */
+ if ($().jquery == '1.3.2' && position == 'fixed' &&
+ !docElem['getBoundingClientRect'])
+ {
+ imgOfs.top += max(document.body.scrollTop, docElem.scrollTop);
+ imgOfs.left += max(document.body.scrollLeft, docElem.scrollLeft);
+ }
+
+ /* Determine parent element offset */
+ parOfs = /absolute|relative/.test($parent.css('position')) ?
+ { left: round($parent.offset().left) - $parent.scrollLeft(),
+ top: round($parent.offset().top) - $parent.scrollTop() } :
+ position == 'fixed' ?
+ { left: $(document).scrollLeft(), top: $(document).scrollTop() } :
+ { left: 0, top: 0 };
+
+ left = viewX(0);
+ top = viewY(0);
+
+ /*
+ * Check if selection area is within image boundaries, adjust if
+ * necessary
+ */
+ if (selection.x2 > imgWidth || selection.y2 > imgHeight)
+ doResize();
+ }
+
+ /**
+ * Update plugin elements
+ *
+ * @param resetKeyPress
+ * If set to <code>false</code>, this instance's keypress
+ * event handler is not activated
+ */
+ function update(resetKeyPress) {
+ /* If plugin elements are hidden, do nothing */
+ if (!shown) return;
+
+ /*
+ * Set the position and size of the container box and the selection area
+ * inside it
+ */
+ $box.css({ left: viewX(selection.x1), top: viewY(selection.y1) })
+ .add($area).width(w = selection.width).height(h = selection.height);
+
+ /*
+ * Reset the position of selection area, borders, and handles (IE6/IE7
+ * position them incorrectly if we don't do this)
+ */
+ $area.add($border).add($handles).css({ left: 0, top: 0 });
+
+ /* Set border dimensions */
+ $border
+ .width(max(w - $border.outerWidth() + $border.innerWidth(), 0))
+ .height(max(h - $border.outerHeight() + $border.innerHeight(), 0));
+
+ /* Arrange the outer area elements */
+ $($outer[0]).css({ left: left, top: top,
+ width: selection.x1, height: imgHeight });
+ $($outer[1]).css({ left: left + selection.x1, top: top,
+ width: w, height: selection.y1 });
+ $($outer[2]).css({ left: left + selection.x2, top: top,
+ width: imgWidth - selection.x2, height: imgHeight });
+ $($outer[3]).css({ left: left + selection.x1, top: top + selection.y2,
+ width: w, height: imgHeight - selection.y2 });
+
+ w -= $handles.outerWidth();
+ h -= $handles.outerHeight();
+
+ /* Arrange handles */
+ switch ($handles.length) {
+ case 8:
+ $($handles[4]).css({ left: w >> 1 });
+ $($handles[5]).css({ left: w, top: h >> 1 });
+ $($handles[6]).css({ left: w >> 1, top: h });
+ $($handles[7]).css({ top: h >> 1 });
+ case 4:
+ $handles.slice(1,3).css({ left: w });
+ $handles.slice(2,4).css({ top: h });
+ }
+
+ if (resetKeyPress !== false) {
+ /*
+ * Need to reset the document keypress event handler -- unbind the
+ * current handler
+ */
+ if ($.imgAreaSelect.keyPress != docKeyPress)
+ $(document).unbind($.imgAreaSelect.keyPress,
+ $.imgAreaSelect.onKeyPress);
+
+ if (options.keys)
+ /*
+ * Set the document keypress event handler to this instance's
+ * docKeyPress() function
+ */
+ $(document)[$.imgAreaSelect.keyPress](
+ $.imgAreaSelect.onKeyPress = docKeyPress);
+ }
+
+ /*
+ * Internet Explorer displays 1px-wide dashed borders incorrectly by
+ * filling the spaces between dashes with white. Toggling the margin
+ * property between 0 and "auto" fixes this in IE6 and IE7 (IE8 is still
+ * broken). This workaround is not perfect, as it requires setTimeout()
+ * and thus causes the border to flicker a bit, but I haven't found a
+ * better solution.
+ *
+ * Note: This only happens with CSS borders, set with the borderWidth,
+ * borderOpacity, borderColor1, and borderColor2 options (which are now
+ * deprecated). Borders created with GIF background images are fine.
+ */
+ if ($.browser.msie && $border.outerWidth() - $border.innerWidth() == 2) {
+ $border.css('margin', 0);
+ setTimeout(function () { $border.css('margin', 'auto'); }, 0);
+ }
+ }
+
+ /**
+ * Do the complete update sequence: recalculate offsets, update the
+ * elements, and set the correct values of x1, y1, x2, and y2.
+ *
+ * @param resetKeyPress
+ * If set to <code>false</code>, this instance's keypress
+ * event handler is not activated
+ */
+ function doUpdate(resetKeyPress) {
+ adjust();
+ update(resetKeyPress);
+ x1 = viewX(selection.x1); y1 = viewY(selection.y1);
+ x2 = viewX(selection.x2); y2 = viewY(selection.y2);
+ }
+
+ /**
+ * Hide or fade out an element (or multiple elements)
+ *
+ * @param $elem
+ * A jQuery object containing the element(s) to hide/fade out
+ * @param fn
+ * Callback function to be called when fadeOut() completes
+ */
+ function hide($elem, fn) {
+ options.fadeSpeed ? $elem.fadeOut(options.fadeSpeed, fn) : $elem.hide();
+ }
+
+ /**
+ * Selection area mousemove event handler
+ *
+ * @param event
+ * The event object
+ */
+ function areaMouseMove(event) {
+ var x = selX(evX(event)) - selection.x1,
+ y = selY(evY(event)) - selection.y1;
+
+ if (!adjusted) {
+ adjust();
+ adjusted = true;
+
+ $box.one('mouseout', function () { adjusted = false; });
+ }
+
+ /* Clear the resize mode */
+ resize = '';
+
+ if (options.resizable) {
+ /*
+ * Check if the mouse pointer is over the resize margin area and set
+ * the resize mode accordingly
+ */
+ if (y <= options.resizeMargin)
+ resize = 'n';
+ else if (y >= selection.height - options.resizeMargin)
+ resize = 's';
+ if (x <= options.resizeMargin)
+ resize += 'w';
+ else if (x >= selection.width - options.resizeMargin)
+ resize += 'e';
+ }
+
+ $box.css('cursor', resize ? resize + '-resize' :
+ options.movable ? 'move' : '');
+ if ($areaOpera)
+ $areaOpera.toggle();
+ }
+
+ /**
+ * Document mouseup event handler
+ *
+ * @param event
+ * The event object
+ */
+ function docMouseUp(event) {
+ /* Set back the default cursor */
+ $('body').css('cursor', '');
+ /*
+ * If autoHide is enabled, or if the selection has zero width/height,
+ * hide the selection and the outer area
+ */
+ if (options.autoHide || selection.width * selection.height == 0)
+ hide($box.add($outer), function () { $(this).hide(); });
+
+ $(document).unbind('mousemove', selectingMouseMove);
+ $box.mousemove(areaMouseMove);
+
+ options.onSelectEnd(img, getSelection());
+ }
+
+ /**
+ * Selection area mousedown event handler
+ *
+ * @param event
+ * The event object
+ * @return false
+ */
+ function areaMouseDown(event) {
+ if (event.which != 1) return false;
+
+ adjust();
+
+ if (resize) {
+ /* Resize mode is in effect */
+ $('body').css('cursor', resize + '-resize');
+
+ x1 = viewX(selection[/w/.test(resize) ? 'x2' : 'x1']);
+ y1 = viewY(selection[/n/.test(resize) ? 'y2' : 'y1']);
+
+ $(document).mousemove(selectingMouseMove)
+ .one('mouseup', docMouseUp);
+ $box.unbind('mousemove', areaMouseMove);
+ }
+ else if (options.movable) {
+ startX = left + selection.x1 - evX(event);
+ startY = top + selection.y1 - evY(event);
+
+ $box.unbind('mousemove', areaMouseMove);
+
+ $(document).mousemove(movingMouseMove)
+ .one('mouseup', function () {
+ options.onSelectEnd(img, getSelection());
+
+ $(document).unbind('mousemove', movingMouseMove);
+ $box.mousemove(areaMouseMove);
+ });
+ }
+ else
+ $img.mousedown(event);
+
+ return false;
+ }
+
+ /**
+ * Adjust the x2/y2 coordinates to maintain aspect ratio (if defined)
+ *
+ * @param xFirst
+ * If set to <code>true</code>, calculate x2 first. Otherwise,
+ * calculate y2 first.
+ */
+ function fixAspectRatio(xFirst) {
+ if (aspectRatio)
+ if (xFirst) {
+ x2 = max(left, min(left + imgWidth,
+ x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1)));
+ y2 = round(max(top, min(top + imgHeight,
+ y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1))));
+ x2 = round(x2);
+ }
+ else {
+ y2 = max(top, min(top + imgHeight,
+ y1 + abs(x2 - x1) / aspectRatio * (y2 > y1 || -1)));
+ x2 = round(max(left, min(left + imgWidth,
+ x1 + abs(y2 - y1) * aspectRatio * (x2 > x1 || -1))));
+ y2 = round(y2);
+ }
+ }
+
+ /**
+ * Resize the selection area respecting the minimum/maximum dimensions and
+ * aspect ratio
+ */
+ function doResize() {
+ /*
+ * Make sure the top left corner of the selection area stays within
+ * image boundaries (it might not if the image source was dynamically
+ * changed).
+ */
+ x1 = min(x1, left + imgWidth);
+ y1 = min(y1, top + imgHeight);
+
+ if (abs(x2 - x1) < minWidth) {
+ /* Selection width is smaller than minWidth */
+ x2 = x1 - minWidth * (x2 < x1 || -1);
+
+ if (x2 < left)
+ x1 = left + minWidth;
+ else if (x2 > left + imgWidth)
+ x1 = left + imgWidth - minWidth;
+ }
+
+ if (abs(y2 - y1) < minHeight) {
+ /* Selection height is smaller than minHeight */
+ y2 = y1 - minHeight * (y2 < y1 || -1);
+
+ if (y2 < top)
+ y1 = top + minHeight;
+ else if (y2 > top + imgHeight)
+ y1 = top + imgHeight - minHeight;
+ }
+
+ x2 = max(left, min(x2, left + imgWidth));
+ y2 = max(top, min(y2, top + imgHeight));
+
+ fixAspectRatio(abs(x2 - x1) < abs(y2 - y1) * aspectRatio);
+
+ if (abs(x2 - x1) > maxWidth) {
+ /* Selection width is greater than maxWidth */
+ x2 = x1 - maxWidth * (x2 < x1 || -1);
+ fixAspectRatio();
+ }
+
+ if (abs(y2 - y1) > maxHeight) {
+ /* Selection height is greater than maxHeight */
+ y2 = y1 - maxHeight * (y2 < y1 || -1);
+ fixAspectRatio(true);
+ }
+
+ selection = { x1: selX(min(x1, x2)), x2: selX(max(x1, x2)),
+ y1: selY(min(y1, y2)), y2: selY(max(y1, y2)),
+ width: abs(x2 - x1), height: abs(y2 - y1) };
+
+ update();
+
+ options.onSelectChange(img, getSelection());
+ }
+
+ /**
+ * Mousemove event handler triggered when the user is selecting an area
+ *
+ * @param event
+ * The event object
+ * @return false
+ */
+ function selectingMouseMove(event) {
+ x2 = /w|e|^$/.test(resize) || aspectRatio ? evX(event) : viewX(selection.x2);
+ y2 = /n|s|^$/.test(resize) || aspectRatio ? evY(event) : viewY(selection.y2);
+
+ doResize();
+
+ return false;
+ }
+
+ /**
+ * Move the selection area
+ *
+ * @param newX1
+ * New viewport X1
+ * @param newY1
+ * New viewport Y1
+ */
+ function doMove(newX1, newY1) {
+ x2 = (x1 = newX1) + selection.width;
+ y2 = (y1 = newY1) + selection.height;
+
+ $.extend(selection, { x1: selX(x1), y1: selY(y1), x2: selX(x2),
+ y2: selY(y2) });
+
+ update();
+
+ options.onSelectChange(img, getSelection());
+ }
+
+ /**
+ * Mousemove event handler triggered when the selection area is being moved
+ *
+ * @param event
+ * The event object
+ * @return false
+ */
+ function movingMouseMove(event) {
+ x1 = max(left, min(startX + evX(event), left + imgWidth - selection.width));
+ y1 = max(top, min(startY + evY(event), top + imgHeight - selection.height));
+
+ doMove(x1, y1);
+
+ event.preventDefault();
+ return false;
+ }
+
+ /**
+ * Start selection
+ */
+ function startSelection() {
+ $(document).unbind('mousemove', startSelection);
+ adjust();
+
+ x2 = x1;
+ y2 = y1;
+ doResize();
+
+ resize = '';
+
+ if (!$outer.is(':visible'))
+ /* Show the plugin elements */
+ $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
+
+ shown = true;
+
+ $(document).unbind('mouseup', cancelSelection)
+ .mousemove(selectingMouseMove).one('mouseup', docMouseUp);
+ $box.unbind('mousemove', areaMouseMove);
+
+ options.onSelectStart(img, getSelection());
+ }
+
+ /**
+ * Cancel selection
+ */
+ function cancelSelection() {
+ $(document).unbind('mousemove', startSelection)
+ .unbind('mouseup', cancelSelection);
+ hide($box.add($outer));
+
+ setSelection(selX(x1), selY(y1), selX(x1), selY(y1));
+
+ /* If this is an API call, callback functions should not be triggered */
+ if (!(this instanceof $.imgAreaSelect)) {
+ options.onSelectChange(img, getSelection());
+ options.onSelectEnd(img, getSelection());
+ }
+ }
+
+ /**
+ * Image mousedown event handler
+ *
+ * @param event
+ * The event object
+ * @return false
+ */
+ function imgMouseDown(event) {
+ /* Ignore the event if animation is in progress */
+ if (event.which != 1 || $outer.is(':animated')) return false;
+
+ adjust();
+ startX = x1 = evX(event);
+ startY = y1 = evY(event);
+
+ /* Selection will start when the mouse is moved */
+ $(document).mousemove(startSelection).mouseup(cancelSelection);
+
+ return false;
+ }
+
+ /**
+ * Window resize event handler
+ */
+ function windowResize() {
+ doUpdate(false);
+ }
+
+ /**
+ * Image load event handler. This is the final part of the initialization
+ * process.
+ */
+ function imgLoad() {
+ imgLoaded = true;
+
+ /* Set options */
+ setOptions(options = $.extend({
+ classPrefix: 'imgareaselect',
+ movable: true,
+ parent: 'body',
+ resizable: true,
+ resizeMargin: 10,
+ onInit: function () {},
+ onSelectStart: function () {},
+ onSelectChange: function () {},
+ onSelectEnd: function () {}
+ }, options));
+
+ $box.add($outer).css({ visibility: '' });
+
+ if (options.show) {
+ shown = true;
+ adjust();
+ update();
+ $box.add($outer).hide().fadeIn(options.fadeSpeed||0);
+ }
+
+ /*
+ * Call the onInit callback. The setTimeout() call is used to ensure
+ * that the plugin has been fully initialized and the object instance is
+ * available (so that it can be obtained in the callback).
+ */
+ setTimeout(function () { options.onInit(img, getSelection()); }, 0);
+ }
+
+ /**
+ * Document keypress event handler
+ *
+ * @param event
+ * The event object
+ * @return false
+ */
+ var docKeyPress = function(event) {
+ var k = options.keys, d, t, key = event.keyCode;
+
+ d = !isNaN(k.alt) && (event.altKey || event.originalEvent.altKey) ? k.alt :
+ !isNaN(k.ctrl) && event.ctrlKey ? k.ctrl :
+ !isNaN(k.shift) && event.shiftKey ? k.shift :
+ !isNaN(k.arrows) ? k.arrows : 10;
+
+ if (k.arrows == 'resize' || (k.shift == 'resize' && event.shiftKey) ||
+ (k.ctrl == 'resize' && event.ctrlKey) ||
+ (k.alt == 'resize' && (event.altKey || event.originalEvent.altKey)))
+ {
+ /* Resize selection */
+
+ switch (key) {
+ case 37:
+ /* Left */
+ d = -d;
+ case 39:
+ /* Right */
+ t = max(x1, x2);
+ x1 = min(x1, x2);
+ x2 = max(t + d, x1);
+ fixAspectRatio();
+ break;
+ case 38:
+ /* Up */
+ d = -d;
+ case 40:
+ /* Down */
+ t = max(y1, y2);
+ y1 = min(y1, y2);
+ y2 = max(t + d, y1);
+ fixAspectRatio(true);
+ break;
+ default:
+ return;
+ }
+
+ doResize();
+ }
+ else {
+ /* Move selection */
+
+ x1 = min(x1, x2);
+ y1 = min(y1, y2);
+
+ switch (key) {
+ case 37:
+ /* Left */
+ doMove(max(x1 - d, left), y1);
+ break;
+ case 38:
+ /* Up */
+ doMove(x1, max(y1 - d, top));
+ break;
+ case 39:
+ /* Right */
+ doMove(x1 + min(d, imgWidth - selX(x2)), y1);
+ break;
+ case 40:
+ /* Down */
+ doMove(x1, y1 + min(d, imgHeight - selY(y2)));
+ break;
+ default:
+ return;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * Apply style options to plugin element (or multiple elements)
+ *
+ * @param $elem
+ * A jQuery object representing the element(s) to style
+ * @param props
+ * An object that maps option names to corresponding CSS
+ * properties
+ */
+ function styleOptions($elem, props) {
+ for (var option in props)
+ if (options[option] !== undefined)
+ $elem.css(props[option], options[option]);
+ }
+
+ /**
+ * Set plugin options
+ *
+ * @param newOptions
+ * The new options object
+ */
+ function setOptions(newOptions) {
+ if (newOptions.parent)
+ ($parent = $(newOptions.parent)).append($box.add($outer));
+
+ /* Merge the new options with the existing ones */
+ $.extend(options, newOptions);
+
+ adjust();
+
+ if (newOptions.handles != null) {
+ /* Recreate selection area handles */
+ $handles.remove();
+ $handles = $([]);
+
+ i = newOptions.handles ? newOptions.handles == 'corners' ? 4 : 8 : 0;
+
+ while (i--)
+ $handles = $handles.add(div());
+
+ /* Add a class to handles and set the CSS properties */
+ $handles.addClass(options.classPrefix + '-handle').css({
+ position: 'absolute',
+ /*
+ * The font-size property needs to be set to zero, otherwise
+ * Internet Explorer makes the handles too large
+ */
+ fontSize: 0,
+ zIndex: zIndex + 1 || 1
+ });
+
+ /*
+ * If handle width/height has not been set with CSS rules, set the
+ * default 5px
+ */
+ if (!parseInt($handles.css('width')) >= 0)
+ $handles.width(5).height(5);
+
+ /*
+ * If the borderWidth option is in use, add a solid border to
+ * handles
+ */
+ if (o = options.borderWidth)
+ $handles.css({ borderWidth: o, borderStyle: 'solid' });
+
+ /* Apply other style options */
+ styleOptions($handles, { borderColor1: 'border-color',
+ borderColor2: 'background-color',
+ borderOpacity: 'opacity' });
+ }
+
+ /* Calculate scale factors */
+ scaleX = options.imageWidth / imgWidth || 1;
+ scaleY = options.imageHeight / imgHeight || 1;
+
+ /* Set selection */
+ if (newOptions.x1 != null) {
+ setSelection(newOptions.x1, newOptions.y1, newOptions.x2,
+ newOptions.y2);
+ newOptions.show = !newOptions.hide;
+ }
+
+ if (newOptions.keys)
+ /* Enable keyboard support */
+ options.keys = $.extend({ shift: 1, ctrl: 'resize' },
+ newOptions.keys);
+
+ /* Add classes to plugin elements */
+ $outer.addClass(options.classPrefix + '-outer');
+ $area.addClass(options.classPrefix + '-selection');
+ for (i = 0; i++ < 4;)
+ $($border[i-1]).addClass(options.classPrefix + '-border' + i);
+
+ /* Apply style options */
+ styleOptions($area, { selectionColor: 'background-color',
+ selectionOpacity: 'opacity' });
+ styleOptions($border, { borderOpacity: 'opacity',
+ borderWidth: 'border-width' });
+ styleOptions($outer, { outerColor: 'background-color',
+ outerOpacity: 'opacity' });
+ if (o = options.borderColor1)
+ $($border[0]).css({ borderStyle: 'solid', borderColor: o });
+ if (o = options.borderColor2)
+ $($border[1]).css({ borderStyle: 'dashed', borderColor: o });
+
+ /* Append all the selection area elements to the container box */
+ $box.append($area.add($border).add($areaOpera).add($handles));
+
+ if ($.browser.msie) {
+ if (o = $outer.css('filter').match(/opacity=(\d+)/))
+ $outer.css('opacity', o[1]/100);
+ if (o = $border.css('filter').match(/opacity=(\d+)/))
+ $border.css('opacity', o[1]/100);
+ }
+
+ if (newOptions.hide)
+ hide($box.add($outer));
+ else if (newOptions.show && imgLoaded) {
+ shown = true;
+ $box.add($outer).fadeIn(options.fadeSpeed||0);
+ doUpdate();
+ }
+
+ /* Calculate the aspect ratio factor */
+ aspectRatio = (d = (options.aspectRatio || '').split(/:/))[0] / d[1];
+
+ $img.add($outer).unbind('mousedown', imgMouseDown);
+
+ if (options.disable || options.enable === false) {
+ /* Disable the plugin */
+ $box.unbind('mousemove', areaMouseMove).unbind('mousedown', areaMouseDown);
+ $(window).unbind('resize', windowResize);
+ }
+ else {
+ if (options.enable || options.disable === false) {
+ /* Enable the plugin */
+ if (options.resizable || options.movable)
+ $box.mousemove(areaMouseMove).mousedown(areaMouseDown);
+
+ $(window).resize(windowResize);
+ }
+
+ if (!options.persistent)
+ $img.add($outer).mousedown(imgMouseDown);
+ }
+
+ options.enable = options.disable = undefined;
+ }
+
+ /**
+ * Remove plugin completely
+ */
+ this.remove = function () {
+ /*
+ * Call setOptions with { disable: true } to unbind the event handlers
+ */
+ setOptions({ disable: true });
+ $box.add($outer).remove();
+ };
+
+ /*
+ * Public API
+ */
+
+ /**
+ * Get current options
+ *
+ * @return An object containing the set of options currently in use
+ */
+ this.getOptions = function () { return options; };
+
+ /**
+ * Set plugin options
+ *
+ * @param newOptions
+ * The new options object
+ */
+ this.setOptions = setOptions;
+
+ /**
+ * Get the current selection
+ *
+ * @param noScale
+ * If set to <code>true</code>, scaling is not applied to the
+ * returned selection
+ * @return Selection object
+ */
+ this.getSelection = getSelection;
+
+ /**
+ * Set the current selection
+ *
+ * @param x1
+ * X coordinate of the upper left corner of the selection area
+ * @param y1
+ * Y coordinate of the upper left corner of the selection area
+ * @param x2
+ * X coordinate of the lower right corner of the selection area
+ * @param y2
+ * Y coordinate of the lower right corner of the selection area
+ * @param noScale
+ * If set to <code>true</code>, scaling is not applied to the
+ * new selection
+ */
+ this.setSelection = setSelection;
+
+ /**
+ * Cancel selection
+ */
+ this.cancelSelection = cancelSelection;
+
+ /**
+ * Update plugin elements
+ *
+ * @param resetKeyPress
+ * If set to <code>false</code>, this instance's keypress
+ * event handler is not activated
+ */
+ this.update = doUpdate;
+
+ /*
+ * Traverse the image's parent elements (up to <body>) and find the
+ * highest z-index
+ */
+ $p = $img;
+
+ while ($p.length) {
+ zIndex = max(zIndex,
+ !isNaN($p.css('z-index')) ? $p.css('z-index') : zIndex);
+ /* Also check if any of the ancestor elements has fixed position */
+ if ($p.css('position') == 'fixed')
+ position = 'fixed';
+
+ $p = $p.parent(':not(body)');
+ }
+
+ /*
+ * If z-index is given as an option, it overrides the one found by the
+ * above loop
+ */
+ zIndex = options.zIndex || zIndex;
+
+ if ($.browser.msie)
+ $img.attr('unselectable', 'on');
+
+ /*
+ * In MSIE and WebKit, we need to use the keydown event instead of keypress
+ */
+ $.imgAreaSelect.keyPress = $.browser.msie ||
+ $.browser.safari ? 'keydown' : 'keypress';
+
+ /*
+ * There is a bug affecting the CSS cursor property in Opera (observed in
+ * versions up to 10.00) that prevents the cursor from being updated unless
+ * the mouse leaves and enters the element again. To trigger the mouseover
+ * event, we're adding an additional div to $box and we're going to toggle
+ * it when mouse moves inside the selection area.
+ */
+ if ($.browser.opera)
+ $areaOpera = div().css({ width: '100%', height: '100%',
+ position: 'absolute', zIndex: zIndex + 2 || 2 });
+
+ /*
+ * We initially set visibility to "hidden" as a workaround for a weird
+ * behaviour observed in Google Chrome 1.0.154.53 (on Windows XP). Normally
+ * we would just set display to "none", but, for some reason, if we do so
+ * then Chrome refuses to later display the element with .show() or
+ * .fadeIn().
+ */
+ $box.add($outer).css({ visibility: 'hidden', position: position,
+ overflow: 'hidden', zIndex: zIndex || '0' });
+ $box.css({ zIndex: zIndex + 2 || 2 });
+ $area.add($border).css({ position: 'absolute', fontSize: 0 });
+
+ /*
+ * If the image has been fully loaded, or if it is not really an image (eg.
+ * a div), call imgLoad() immediately; otherwise, bind it to be called once
+ * on image load event.
+ */
+ img.complete || img.readyState == 'complete' || !$img.is('img') ?
+ imgLoad() : $img.one('load', imgLoad);
+
+ /*
+ * MSIE 9.0 doesn't always fire the image load event -- resetting the src
+ * attribute seems to trigger it. The check is for version 7 and above to
+ * accommodate for MSIE 9 running in compatibility mode.
+ */
+ if (!imgLoaded && $.browser.msie && $.browser.version >= 7)
+ img.src = img.src;
+};
+
+/**
+ * Invoke imgAreaSelect on a jQuery object containing the image(s)
+ *
+ * @param options
+ * Options object
+ * @return The jQuery object or a reference to imgAreaSelect instance (if the
+ * <code>instance</code> option was specified)
+ */
+$.fn.imgAreaSelect = function (options) {
+ options = options || {};
+
+ this.each(function () {
+ /* Is there already an imgAreaSelect instance bound to this element? */
+ if ($(this).data('imgAreaSelect')) {
+ /* Yes there is -- is it supposed to be removed? */
+ if (options.remove) {
+ /* Remove the plugin */
+ $(this).data('imgAreaSelect').remove();
+ $(this).removeData('imgAreaSelect');
+ }
+ else
+ /* Reset options */
+ $(this).data('imgAreaSelect').setOptions(options);
+ }
+ else if (!options.remove) {
+ /* No exising instance -- create a new one */
+
+ /*
+ * If neither the "enable" nor the "disable" option is present, add
+ * "enable" as the default
+ */
+ if (options.enable === undefined && options.disable === undefined)
+ options.enable = true;
+
+ $(this).data('imgAreaSelect', new $.imgAreaSelect(this, options));
+ }
+ });
+
+ if (options.instance)
+ /*
+ * Return the imgAreaSelect instance bound to the first element in the
+ * set
+ */
+ return $(this).data('imgAreaSelect');
+
+ return this;
+};
+
+})(jQuery);
diff --git a/src/wp-includes/js/imgareaselect/jquery.imgareaselect.min.js b/src/wp-includes/js/imgareaselect/jquery.imgareaselect.min.js
new file mode 100644
index 0000000000..0f949681fe
--- /dev/null
+++ b/src/wp-includes/js/imgareaselect/jquery.imgareaselect.min.js
@@ -0,0 +1 @@
+(function(e){var b=Math.abs,a=Math.max,d=Math.min,c=Math.round;function f(){return e("<div/>")}e.imgAreaSelect=function(s,X){var az=e(s),Z,av=f(),ai=f(),K=f().add(f()).add(f()).add(f()),ab=f().add(f()).add(f()).add(f()),O=e([]),V,n,q,aC={left:0,top:0},Q,j,C,P={left:0,top:0},D=0,ag="absolute",T,S,ad,ac,L,E,U,W,am,Y,N,A,aD,z,aB,y={x1:0,y1:0,x2:0,y2:0,width:0,height:0},p=document.documentElement,l,au,ap,aj,af,aq,x;function J(h){return h+aC.left-P.left}function I(h){return h+aC.top-P.top}function H(h){return h-aC.left+P.left}function B(h){return h-aC.top+P.top}function ao(h){return h.pageX-P.left}function al(h){return h.pageY-P.top}function G(h){var o=h||ad,i=h||ac;return{x1:c(y.x1*o),y1:c(y.y1*i),x2:c(y.x2*o),y2:c(y.y2*i),width:c(y.x2*o)-c(y.x1*o),height:c(y.y2*i)-c(y.y1*i)}}function ah(i,w,h,o,aE){var aG=aE||ad,aF=aE||ac;y={x1:c(i/aG||0),y1:c(w/aF||0),x2:c(h/aG||0),y2:c(o/aF||0)};y.width=y.x2-y.x1;y.height=y.y2-y.y1}function ar(){if(!az.width()){return}aC={left:c(az.offset().left),top:c(az.offset().top)};Q=az.innerWidth();j=az.innerHeight();aC.top+=(az.outerHeight()-j)>>1;aC.left+=(az.outerWidth()-Q)>>1;E=c(X.minWidth/ad)||0;U=c(X.minHeight/ac)||0;W=c(d(X.maxWidth/ad||1<<24,Q));am=c(d(X.maxHeight/ac||1<<24,j));if(e().jquery=="1.3.2"&&ag=="fixed"&&!p.getBoundingClientRect){aC.top+=a(document.body.scrollTop,p.scrollTop);aC.left+=a(document.body.scrollLeft,p.scrollLeft)}P=/absolute|relative/.test(C.css("position"))?{left:c(C.offset().left)-C.scrollLeft(),top:c(C.offset().top)-C.scrollTop()}:ag=="fixed"?{left:e(document).scrollLeft(),top:e(document).scrollTop()}:{left:0,top:0};n=J(0);q=I(0);if(y.x2>Q||y.y2>j){ay()}}function aa(h){if(!N){return}av.css({left:J(y.x1),top:I(y.y1)}).add(ai).width(af=y.width).height(aq=y.height);ai.add(K).add(O).css({left:0,top:0});K.width(a(af-K.outerWidth()+K.innerWidth(),0)).height(a(aq-K.outerHeight()+K.innerHeight(),0));e(ab[0]).css({left:n,top:q,width:y.x1,height:j});e(ab[1]).css({left:n+y.x1,top:q,width:af,height:y.y1});e(ab[2]).css({left:n+y.x2,top:q,width:Q-y.x2,height:j});e(ab[3]).css({left:n+y.x1,top:q+y.y2,width:af,height:j-y.y2});af-=O.outerWidth();aq-=O.outerHeight();switch(O.length){case 8:e(O[4]).css({left:af>>1});e(O[5]).css({left:af,top:aq>>1});e(O[6]).css({left:af>>1,top:aq});e(O[7]).css({top:aq>>1});case 4:O.slice(1,3).css({left:af});O.slice(2,4).css({top:aq})}if(h!==false){if(e.imgAreaSelect.keyPress!=aw){e(document).unbind(e.imgAreaSelect.keyPress,e.imgAreaSelect.onKeyPress)}if(X.keys){e(document)[e.imgAreaSelect.keyPress](e.imgAreaSelect.onKeyPress=aw)}}if(e.browser.msie&&K.outerWidth()-K.innerWidth()==2){K.css("margin",0);setTimeout(function(){K.css("margin","auto")},0)}}function u(h){ar();aa(h);A=J(y.x1);aD=I(y.y1);z=J(y.x2);aB=I(y.y2)}function ak(h,i){X.fadeSpeed?h.fadeOut(X.fadeSpeed,i):h.hide()}function F(i){var h=H(ao(i))-y.x1,o=B(al(i))-y.y1;if(!x){ar();x=true;av.one("mouseout",function(){x=false})}L="";if(X.resizable){if(o<=X.resizeMargin){L="n"}else{if(o>=y.height-X.resizeMargin){L="s"}}if(h<=X.resizeMargin){L+="w"}else{if(h>=y.width-X.resizeMargin){L+="e"}}}av.css("cursor",L?L+"-resize":X.movable?"move":"");if(V){V.toggle()}}function an(h){e("body").css("cursor","");if(X.autoHide||y.width*y.height==0){ak(av.add(ab),function(){e(this).hide()})}e(document).unbind("mousemove",ae);av.mousemove(F);X.onSelectEnd(s,G())}function t(h){if(h.which!=1){return false}ar();if(L){e("body").css("cursor",L+"-resize");A=J(y[/w/.test(L)?"x2":"x1"]);aD=I(y[/n/.test(L)?"y2":"y1"]);e(document).mousemove(ae).one("mouseup",an);av.unbind("mousemove",F)}else{if(X.movable){T=n+y.x1-ao(h);S=q+y.y1-al(h);av.unbind("mousemove",F);e(document).mousemove(g).one("mouseup",function(){X.onSelectEnd(s,G());e(document).unbind("mousemove",g);av.mousemove(F)})}else{az.mousedown(h)}}return false}function r(h){if(Y){if(h){z=a(n,d(n+Q,A+b(aB-aD)*Y*(z>A||-1)));aB=c(a(q,d(q+j,aD+b(z-A)/Y*(aB>aD||-1))));z=c(z)}else{aB=a(q,d(q+j,aD+b(z-A)/Y*(aB>aD||-1)));z=c(a(n,d(n+Q,A+b(aB-aD)*Y*(z>A||-1))));aB=c(aB)}}}function ay(){A=d(A,n+Q);aD=d(aD,q+j);if(b(z-A)<E){z=A-E*(z<A||-1);if(z<n){A=n+E}else{if(z>n+Q){A=n+Q-E}}}if(b(aB-aD)<U){aB=aD-U*(aB<aD||-1);if(aB<q){aD=q+U}else{if(aB>q+j){aD=q+j-U}}}z=a(n,d(z,n+Q));aB=a(q,d(aB,q+j));r(b(z-A)<b(aB-aD)*Y);if(b(z-A)>W){z=A-W*(z<A||-1);r()}if(b(aB-aD)>am){aB=aD-am*(aB<aD||-1);r(true)}y={x1:H(d(A,z)),x2:H(a(A,z)),y1:B(d(aD,aB)),y2:B(a(aD,aB)),width:b(z-A),height:b(aB-aD)};aa();X.onSelectChange(s,G())}function ae(h){z=/w|e|^$/.test(L)||Y?ao(h):J(y.x2);aB=/n|s|^$/.test(L)||Y?al(h):I(y.y2);ay();return false}function R(h,i){z=(A=h)+y.width;aB=(aD=i)+y.height;e.extend(y,{x1:H(A),y1:B(aD),x2:H(z),y2:B(aB)});aa();X.onSelectChange(s,G())}function g(h){A=a(n,d(T+ao(h),n+Q-y.width));aD=a(q,d(S+al(h),q+j-y.height));R(A,aD);h.preventDefault();return false}function aA(){e(document).unbind("mousemove",aA);ar();z=A;aB=aD;ay();L="";if(!ab.is(":visible")){av.add(ab).hide().fadeIn(X.fadeSpeed||0)}N=true;e(document).unbind("mouseup",at).mousemove(ae).one("mouseup",an);av.unbind("mousemove",F);X.onSelectStart(s,G())}function at(){e(document).unbind("mousemove",aA).unbind("mouseup",at);ak(av.add(ab));ah(H(A),B(aD),H(A),B(aD));if(!(this instanceof e.imgAreaSelect)){X.onSelectChange(s,G());X.onSelectEnd(s,G())}}function m(h){if(h.which!=1||ab.is(":animated")){return false}ar();T=A=ao(h);S=aD=al(h);e(document).mousemove(aA).mouseup(at);return false}function v(){u(false)}function ax(){Z=true;M(X=e.extend({classPrefix:"imgareaselect",movable:true,parent:"body",resizable:true,resizeMargin:10,onInit:function(){},onSelectStart:function(){},onSelectChange:function(){},onSelectEnd:function(){}},X));av.add(ab).css({visibility:""});if(X.show){N=true;ar();aa();av.add(ab).hide().fadeIn(X.fadeSpeed||0)}setTimeout(function(){X.onInit(s,G())},0)}var aw=function(w){var h=X.keys,aE,o,i=w.keyCode;aE=!isNaN(h.alt)&&(w.altKey||w.originalEvent.altKey)?h.alt:!isNaN(h.ctrl)&&w.ctrlKey?h.ctrl:!isNaN(h.shift)&&w.shiftKey?h.shift:!isNaN(h.arrows)?h.arrows:10;if(h.arrows=="resize"||(h.shift=="resize"&&w.shiftKey)||(h.ctrl=="resize"&&w.ctrlKey)||(h.alt=="resize"&&(w.altKey||w.originalEvent.altKey))){switch(i){case 37:aE=-aE;case 39:o=a(A,z);A=d(A,z);z=a(o+aE,A);r();break;case 38:aE=-aE;case 40:o=a(aD,aB);aD=d(aD,aB);aB=a(o+aE,aD);r(true);break;default:return}ay()}else{A=d(A,z);aD=d(aD,aB);switch(i){case 37:R(a(A-aE,n),aD);break;case 38:R(A,a(aD-aE,q));break;case 39:R(A+d(aE,Q-H(z)),aD);break;case 40:R(A,aD+d(aE,j-B(aB)));break;default:return}}return false};function k(h,o){for(var i in o){if(X[i]!==undefined){h.css(o[i],X[i])}}}function M(h){if(h.parent){(C=e(h.parent)).append(av.add(ab))}e.extend(X,h);ar();if(h.handles!=null){O.remove();O=e([]);ap=h.handles?h.handles=="corners"?4:8:0;while(ap--){O=O.add(f())}O.addClass(X.classPrefix+"-handle").css({position:"absolute",fontSize:0,zIndex:D+1||1});if(!parseInt(O.css("width"))>=0){O.width(5).height(5)}if(aj=X.borderWidth){O.css({borderWidth:aj,borderStyle:"solid"})}k(O,{borderColor1:"border-color",borderColor2:"background-color",borderOpacity:"opacity"})}ad=X.imageWidth/Q||1;ac=X.imageHeight/j||1;if(h.x1!=null){ah(h.x1,h.y1,h.x2,h.y2);h.show=!h.hide}if(h.keys){X.keys=e.extend({shift:1,ctrl:"resize"},h.keys)}ab.addClass(X.classPrefix+"-outer");ai.addClass(X.classPrefix+"-selection");for(ap=0;ap++<4;){e(K[ap-1]).addClass(X.classPrefix+"-border"+ap)}k(ai,{selectionColor:"background-color",selectionOpacity:"opacity"});k(K,{borderOpacity:"opacity",borderWidth:"border-width"});k(ab,{outerColor:"background-color",outerOpacity:"opacity"});if(aj=X.borderColor1){e(K[0]).css({borderStyle:"solid",borderColor:aj})}if(aj=X.borderColor2){e(K[1]).css({borderStyle:"dashed",borderColor:aj})}av.append(ai.add(K).add(V).add(O));if(e.browser.msie){if(aj=ab.css("filter").match(/opacity=(\d+)/)){ab.css("opacity",aj[1]/100)}if(aj=K.css("filter").match(/opacity=(\d+)/)){K.css("opacity",aj[1]/100)}}if(h.hide){ak(av.add(ab))}else{if(h.show&&Z){N=true;av.add(ab).fadeIn(X.fadeSpeed||0);u()}}Y=(au=(X.aspectRatio||"").split(/:/))[0]/au[1];az.add(ab).unbind("mousedown",m);if(X.disable||X.enable===false){av.unbind("mousemove",F).unbind("mousedown",t);e(window).unbind("resize",v)}else{if(X.enable||X.disable===false){if(X.resizable||X.movable){av.mousemove(F).mousedown(t)}e(window).resize(v)}if(!X.persistent){az.add(ab).mousedown(m)}}X.enable=X.disable=undefined}this.remove=function(){M({disable:true});av.add(ab).remove()};this.getOptions=function(){return X};this.setOptions=M;this.getSelection=G;this.setSelection=ah;this.cancelSelection=at;this.update=u;l=az;while(l.length){D=a(D,!isNaN(l.css("z-index"))?l.css("z-index"):D);if(l.css("position")=="fixed"){ag="fixed"}l=l.parent(":not(body)")}D=X.zIndex||D;if(e.browser.msie){az.attr("unselectable","on")}e.imgAreaSelect.keyPress=e.browser.msie||e.browser.safari?"keydown":"keypress";if(e.browser.opera){V=f().css({width:"100%",height:"100%",position:"absolute",zIndex:D+2||2})}av.add(ab).css({visibility:"hidden",position:ag,overflow:"hidden",zIndex:D||"0"});av.css({zIndex:D+2||2});ai.add(K).css({position:"absolute",fontSize:0});s.complete||s.readyState=="complete"||!az.is("img")?ax():az.one("load",ax);if(!Z&&e.browser.msie&&e.browser.version>=7){s.src=s.src}};e.fn.imgAreaSelect=function(g){g=g||{};this.each(function(){if(e(this).data("imgAreaSelect")){if(g.remove){e(this).data("imgAreaSelect").remove();e(this).removeData("imgAreaSelect")}else{e(this).data("imgAreaSelect").setOptions(g)}}else{if(!g.remove){if(g.enable===undefined&&g.disable===undefined){g.enable=true}e(this).data("imgAreaSelect",new e.imgAreaSelect(this,g))}}});if(g.instance){return e(this).data("imgAreaSelect")}return this}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jcrop/Jcrop.gif b/src/wp-includes/js/jcrop/Jcrop.gif
new file mode 100644
index 0000000000..0e24ab1b12
--- /dev/null
+++ b/src/wp-includes/js/jcrop/Jcrop.gif
Binary files differ
diff --git a/src/wp-includes/js/jcrop/jquery.Jcrop.min.css b/src/wp-includes/js/jcrop/jquery.Jcrop.min.css
new file mode 100644
index 0000000000..f438f33d53
--- /dev/null
+++ b/src/wp-includes/js/jcrop/jquery.Jcrop.min.css
@@ -0,0 +1,28 @@
+/* jquery.Jcrop.min.css v0.9.10 (build:20120429) */
+.jcrop-holder{direction:ltr;text-align:left;}
+.jcrop-vline,.jcrop-hline{background:#FFF url(Jcrop.gif) top left repeat;font-size:0;position:absolute;}
+.jcrop-vline{height:100%;width:1px!important;}
+.jcrop-hline{height:1px!important;width:100%;}
+.jcrop-vline.right{right:0;}
+.jcrop-hline.bottom{bottom:0;}
+.jcrop-handle{background-color:#333;border:1px #eee solid;font-size:1px;}
+.jcrop-tracker{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;-webkit-user-select:none;height:100%;width:100%;}
+.jcrop-handle.ord-n{left:50%;margin-left:-4px;margin-top:-4px;top:0;}
+.jcrop-handle.ord-s{bottom:0;left:50%;margin-bottom:-4px;margin-left:-4px;}
+.jcrop-handle.ord-e{margin-right:-4px;margin-top:-4px;right:0;top:50%;}
+.jcrop-handle.ord-w{left:0;margin-left:-4px;margin-top:-4px;top:50%;}
+.jcrop-handle.ord-nw{left:0;margin-left:-4px;margin-top:-4px;top:0;}
+.jcrop-handle.ord-ne{margin-right:-4px;margin-top:-4px;right:0;top:0;}
+.jcrop-handle.ord-se{bottom:0;margin-bottom:-4px;margin-right:-4px;right:0;}
+.jcrop-handle.ord-sw{bottom:0;left:0;margin-bottom:-4px;margin-left:-4px;}
+.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{height:7px;width:100%;}
+.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{height:100%;width:7px;}
+.jcrop-dragbar.ord-n{margin-top:-4px;}
+.jcrop-dragbar.ord-s{bottom:0;margin-bottom:-4px;}
+.jcrop-dragbar.ord-e{margin-right:-4px;right:0;}
+.jcrop-dragbar.ord-w{margin-left:-4px;}
+.jcrop-light .jcrop-vline,.jcrop-light .jcrop-hline{background:#FFF;filter:Alpha(opacity=70)!important;opacity:.70!important;}
+.jcrop-light .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#000;border-color:#FFF;border-radius:3px;}
+.jcrop-dark .jcrop-vline,.jcrop-dark .jcrop-hline{background:#000;filter:Alpha(opacity=70)!important;opacity:.7!important;}
+.jcrop-dark .jcrop-handle{-moz-border-radius:3px;-webkit-border-radius:3px;background-color:#FFF;border-color:#000;border-radius:3px;}
+.jcrop-holder img,img.jcrop-preview{max-width:none;}
diff --git a/src/wp-includes/js/jcrop/jquery.Jcrop.min.js b/src/wp-includes/js/jcrop/jquery.Jcrop.min.js
new file mode 100644
index 0000000000..2df51ad6db
--- /dev/null
+++ b/src/wp-includes/js/jcrop/jquery.Jcrop.min.js
@@ -0,0 +1,22 @@
+/**
+ * jquery.Jcrop.min.js v0.9.10 (build:20120429)
+ * jQuery Image Cropping Plugin - released under MIT License
+ * Copyright (c) 2008-2012 Tapmodo Interactive LLC
+ * https://github.com/tapmodo/Jcrop
+ */
+(function(a){a.Jcrop=function(b,c){function h(a){return a+"px"}function i(a){return d.baseClass+"-"+a}function j(){return a.fx.step.hasOwnProperty("backgroundColor")}function k(b){var c=a(b).offset();return[c.left,c.top]}function l(a){return[a.pageX-e[0],a.pageY-e[1]]}function m(b){typeof b!="object"&&(b={}),d=a.extend(d,b),a.each(["onChange","onSelect","onRelease","onDblClick"],function(a,b){typeof d[b]!="function"&&(d[b]=function(){})})}function n(a,b){e=k(E),bd.setCursor(a==="move"?a:a+"-resize");if(a==="move")return bd.activateHandlers(p(b),u);var c=ba.getFixed(),d=q(a),f=ba.getCorner(q(d));ba.setPressed(ba.getCorner(d)),ba.setCurrent(f),bd.activateHandlers(o(a,c),u)}function o(a,b){return function(c){if(!d.aspectRatio)switch(a){case"e":c[1]=b.y2;break;case"w":c[1]=b.y2;break;case"n":c[0]=b.x2;break;case"s":c[0]=b.x2}else switch(a){case"e":c[1]=b.y+1;break;case"w":c[1]=b.y+1;break;case"n":c[0]=b.x+1;break;case"s":c[0]=b.x+1}ba.setCurrent(c),bc.update()}}function p(a){var b=a;return be.watchKeys(),function(
+a){ba.moveOffset([a[0]-b[0],a[1]-b[1]]),b=a,bc.update()}}function q(a){switch(a){case"n":return"sw";case"s":return"nw";case"e":return"nw";case"w":return"ne";case"ne":return"sw";case"nw":return"se";case"se":return"nw";case"sw":return"ne"}}function r(a){return function(b){return d.disabled?!1:a==="move"&&!d.allowMove?!1:(e=k(E),X=!0,n(a,l(b)),b.stopPropagation(),b.preventDefault(),!1)}}function s(a,b,c){var d=a.width(),e=a.height();d>b&&b>0&&(d=b,e=b/a.width()*a.height()),e>c&&c>0&&(e=c,d=c/a.height()*a.width()),U=a.width()/d,V=a.height()/e,a.width(d).height(e)}function t(a){return{x:a.x*U,y:a.y*V,x2:a.x2*U,y2:a.y2*V,w:a.w*U,h:a.h*V}}function u(a){var b=ba.getFixed();b.w>d.minSelect[0]&&b.h>d.minSelect[1]?(bc.enableHandles(),bc.done()):bc.release(),bd.setCursor(d.allowSelect?"crosshair":"default")}function v(a){if(d.disabled)return!1;if(!d.allowSelect)return!1;X=!0,e=k(E),bc.disableHandles(),bd.setCursor("crosshair");var b=l(a);return ba.setPressed(b),bc.update(),bd.activateHandlers(w,u),be.watchKeys(),a.stopPropagation
+(),a.preventDefault(),!1}function w(a){ba.setCurrent(a),bc.update()}function z(){var b=a("<div></div>").addClass(i("tracker"));return a.browser.msie&&b.css({opacity:0,backgroundColor:"white"}),b}function bf(a){H.removeClass().addClass(i("holder")).addClass(a)}function bg(a,b){function t(){window.setTimeout(u,l)}var c=a[0]/U,e=a[1]/V,f=a[2]/U,g=a[3]/V;if(Y)return;var h=ba.flipCoords(c,e,f,g),i=ba.getFixed(),j=[i.x,i.y,i.x2,i.y2],k=j,l=d.animationDelay,m=h[0]-j[0],n=h[1]-j[1],o=h[2]-j[2],p=h[3]-j[3],q=0,r=d.swingSpeed;x=k[0],y=k[1],f=k[2],g=k[3],bc.animMode(!0);var s,u=function(){return function(){q+=(100-q)/r,k[0]=x+q/100*m,k[1]=y+q/100*n,k[2]=f+q/100*o,k[3]=g+q/100*p,q>=99.8&&(q=100),q<100?(bi(k),t()):(bc.done(),typeof b=="function"&&b.call(bt))}}();t()}function bh(a){bi([a[0]/U,a[1]/V,a[2]/U,a[3]/V]),d.onSelect.call(bt,t(ba.getFixed())),bc.enableHandles()}function bi(a){ba.setPressed([a[0],a[1]]),ba.setCurrent([a[2],a[3]]),bc.update()}function bj(){return t(ba.getFixed())}function bk(){return ba.getFixed()}function bl
+(a){m(a),bs()}function bm(){d.disabled=!0,bc.disableHandles(),bc.setCursor("default"),bd.setCursor("default")}function bn(){d.disabled=!1,bs()}function bo(){bc.done(),bd.activateHandlers(null,null)}function bp(){H.remove(),B.show(),a(b).removeData("Jcrop")}function bq(a,b){bc.release(),bm();var c=new Image;c.onload=function(){var e=c.width,f=c.height,g=d.boxWidth,h=d.boxHeight;E.width(e).height(f),E.attr("src",a),I.attr("src",a),s(E,g,h),F=E.width(),G=E.height(),I.width(F).height(G),N.width(F+M*2).height(G+M*2),H.width(F).height(G),bb.resize(F,G),bn(),typeof b=="function"&&b.call(bt)},c.src=a}function br(a,b,c){var e=b||d.bgColor;d.bgFade&&j()&&d.fadeTime&&!c?a.animate({backgroundColor:e},{queue:!1,duration:d.fadeTime}):a.css("backgroundColor",e)}function bs(a){d.allowResize?a?bc.enableOnly():bc.enableHandles():bc.disableHandles(),bd.setCursor(d.allowSelect?"crosshair":"default"),bc.setCursor(d.allowMove?"move":"default"),d.hasOwnProperty("trueSize")&&(U=d.trueSize[0]/F,V=d.trueSize[1]/G),d.hasOwnProperty("setSelect"
+)&&(bh(d.setSelect),bc.done(),delete d.setSelect),bb.refresh(),d.bgColor!=O&&(br(d.shade?bb.getShades():H,d.shade?d.shadeColor||d.bgColor:d.bgColor),O=d.bgColor),P!=d.bgOpacity&&(P=d.bgOpacity,d.shade?bb.refresh():bc.setBgOpacity(P)),Q=d.maxSize[0]||0,R=d.maxSize[1]||0,S=d.minSize[0]||0,T=d.minSize[1]||0,d.hasOwnProperty("outerImage")&&(E.attr("src",d.outerImage),delete d.outerImage),bc.refresh()}var d=a.extend({},a.Jcrop.defaults),e,f,g=!1;a.browser.msie&&a.browser.version.split(".")[0]==="6"&&(g=!0),typeof b!="object"&&(b=a(b)[0]),typeof c!="object"&&(c={}),m(c);var A={border:"none",visibility:"visible",margin:0,padding:0,position:"absolute",top:0,left:0},B=a(b),C=!0;if(b.tagName=="IMG"){if(B[0].width!=0&&B[0].height!=0)B.width(B[0].width),B.height(B[0].height);else{var D=new Image;D.src=B[0].src,B.width(D.width),B.height(D.height)}var E=B.clone().removeAttr("id").css(A).show();E.width(B.width()),E.height(B.height()),B.after(E).hide()}else E=B.css(A).show(),C=!1,d.shade===null&&(d.shade=!0);s(E,d.boxWidth,d.
+boxHeight);var F=E.width(),G=E.height(),H=a("<div />").width(F).height(G).addClass(i("holder")).css({position:"relative",backgroundColor:d.bgColor}).insertAfter(B).append(E);d.addClass&&H.addClass(d.addClass);var I=a("<div />"),J=a("<div />").width("100%").height("100%").css({zIndex:310,position:"absolute",overflow:"hidden"}),K=a("<div />").width("100%").height("100%").css("zIndex",320),L=a("<div />").css({position:"absolute",zIndex:600}).dblclick(function(){var a=ba.getFixed();d.onDblClick.call(bt,a)}).insertBefore(E).append(J,K);C&&(I=a("<img />").attr("src",E.attr("src")).css(A).width(F).height(G),J.append(I)),g&&L.css({overflowY:"hidden"});var M=d.boundary,N=z().width(F+M*2).height(G+M*2).css({position:"absolute",top:h(-M),left:h(-M),zIndex:290}).mousedown(v),O=d.bgColor,P=d.bgOpacity,Q,R,S,T,U,V,W=!0,X,Y,Z;e=k(E);var _=function(){function a(){var a={},b=["touchstart","touchmove","touchend"],c=document.createElement("div"),d;try{for(d=0;d<b.length;d++){var e=b[d];e="on"+e;var f=e in c;f||(c.setAttribute(e,"return;"
+),f=typeof c[e]=="function"),a[b[d]]=f}return a.touchstart&&a.touchend&&a.touchmove}catch(g){return!1}}function b(){return d.touchSupport===!0||d.touchSupport===!1?d.touchSupport:a()}return{createDragger:function(a){return function(b){return b.pageX=b.originalEvent.changedTouches[0].pageX,b.pageY=b.originalEvent.changedTouches[0].pageY,d.disabled?!1:a==="move"&&!d.allowMove?!1:(X=!0,n(a,l(b)),b.stopPropagation(),b.preventDefault(),!1)}},newSelection:function(a){return a.pageX=a.originalEvent.changedTouches[0].pageX,a.pageY=a.originalEvent.changedTouches[0].pageY,v(a)},isSupported:a,support:b()}}(),ba=function(){function h(d){d=n(d),c=a=d[0],e=b=d[1]}function i(a){a=n(a),f=a[0]-c,g=a[1]-e,c=a[0],e=a[1]}function j(){return[f,g]}function k(d){var f=d[0],g=d[1];0>a+f&&(f-=f+a),0>b+g&&(g-=g+b),G<e+g&&(g+=G-(e+g)),F<c+f&&(f+=F-(c+f)),a+=f,c+=f,b+=g,e+=g}function l(a){var b=m();switch(a){case"ne":return[b.x2,b.y];case"nw":return[b.x,b.y];case"se":return[b.x2,b.y2];case"sw":return[b.x,b.y2]}}function m(){if(!d.aspectRatio
+)return p();var f=d.aspectRatio,g=d.minSize[0]/U,h=d.maxSize[0]/U,i=d.maxSize[1]/V,j=c-a,k=e-b,l=Math.abs(j),m=Math.abs(k),n=l/m,r,s,t,u;return h===0&&(h=F*10),i===0&&(i=G*10),n<f?(s=e,t=m*f,r=j<0?a-t:t+a,r<0?(r=0,u=Math.abs((r-a)/f),s=k<0?b-u:u+b):r>F&&(r=F,u=Math.abs((r-a)/f),s=k<0?b-u:u+b)):(r=c,u=l/f,s=k<0?b-u:b+u,s<0?(s=0,t=Math.abs((s-b)*f),r=j<0?a-t:t+a):s>G&&(s=G,t=Math.abs(s-b)*f,r=j<0?a-t:t+a)),r>a?(r-a<g?r=a+g:r-a>h&&(r=a+h),s>b?s=b+(r-a)/f:s=b-(r-a)/f):r<a&&(a-r<g?r=a-g:a-r>h&&(r=a-h),s>b?s=b+(a-r)/f:s=b-(a-r)/f),r<0?(a-=r,r=0):r>F&&(a-=r-F,r=F),s<0?(b-=s,s=0):s>G&&(b-=s-G,s=G),q(o(a,b,r,s))}function n(a){return a[0]<0&&(a[0]=0),a[1]<0&&(a[1]=0),a[0]>F&&(a[0]=F),a[1]>G&&(a[1]=G),[a[0],a[1]]}function o(a,b,c,d){var e=a,f=c,g=b,h=d;return c<a&&(e=c,f=a),d<b&&(g=d,h=b),[e,g,f,h]}function p(){var d=c-a,f=e-b,g;return Q&&Math.abs(d)>Q&&(c=d>0?a+Q:a-Q),R&&Math.abs(f)>R&&(e=f>0?b+R:b-R),T/V&&Math.abs(f)<T/V&&(e=f>0?b+T/V:b-T/V),S/U&&Math.abs(d)<S/U&&(c=d>0?a+S/U:a-S/U),a<0&&(c-=a,a-=a),b<0&&(e-=b,b-=b),c<0&&
+(a-=c,c-=c),e<0&&(b-=e,e-=e),c>F&&(g=c-F,a-=g,c-=g),e>G&&(g=e-G,b-=g,e-=g),a>F&&(g=a-G,e-=g,b-=g),b>G&&(g=b-G,e-=g,b-=g),q(o(a,b,c,e))}function q(a){return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]}}var a=0,b=0,c=0,e=0,f,g;return{flipCoords:o,setPressed:h,setCurrent:i,getOffset:j,moveOffset:k,getCorner:l,getFixed:m}}(),bb=function(){function f(a,b){e.left.css({height:h(b)}),e.right.css({height:h(b)})}function g(){return i(ba.getFixed())}function i(a){e.top.css({left:h(a.x),width:h(a.w),height:h(a.y)}),e.bottom.css({top:h(a.y2),left:h(a.x),width:h(a.w),height:h(G-a.y2)}),e.right.css({left:h(a.x2),width:h(F-a.x2)}),e.left.css({width:h(a.x)})}function j(){return a("<div />").css({position:"absolute",backgroundColor:d.shadeColor||d.bgColor}).appendTo(c)}function k(){b||(b=!0,c.insertBefore(E),g(),bc.setBgOpacity(1,0,1),I.hide(),l(d.shadeColor||d.bgColor,1),bc.isAwake()?n(d.bgOpacity,1):n(1,1))}function l(a,b){br(p(),a,b)}function m(){b&&(c.remove(),I.show(),b=!1,bc.isAwake()?bc.setBgOpacity(d.bgOpacity
+,1,1):(bc.setBgOpacity(1,1,1),bc.disableHandles()),br(H,0,1))}function n(a,e){b&&(d.bgFade&&!e?c.animate({opacity:1-a},{queue:!1,duration:d.fadeTime}):c.css({opacity:1-a}))}function o(){d.shade?k():m(),bc.isAwake()&&n(d.bgOpacity)}function p(){return c.children()}var b=!1,c=a("<div />").css({position:"absolute",zIndex:240,opacity:0}),e={top:j(),left:j().height(G),right:j().height(G),bottom:j()};return{update:g,updateRaw:i,getShades:p,setBgColor:l,enable:k,disable:m,resize:f,refresh:o,opacity:n}}(),bc=function(){function k(b){var c=a("<div />").css({position:"absolute",opacity:d.borderOpacity}).addClass(i(b));return J.append(c),c}function l(b,c){var d=a("<div />").mousedown(r(b)).css({cursor:b+"-resize",position:"absolute",zIndex:c}).addClass("ord-"+b);return _.support&&d.bind("touchstart.jcrop",_.createDragger(b)),K.append(d),d}function m(a){var b=d.handleSize;return l(a,c++).css({opacity:d.handleOpacity}).width(b).height(b).addClass(i("handle"))}function n(a){return l(a,c++).addClass("jcrop-dragbar")}function o
+(a){var b;for(b=0;b<a.length;b++)g[a[b]]=n(a[b])}function p(a){var b,c;for(c=0;c<a.length;c++){switch(a[c]){case"n":b="hline";break;case"s":b="hline bottom";break;case"e":b="vline right";break;case"w":b="vline"}e[a[c]]=k(b)}}function q(a){var b;for(b=0;b<a.length;b++)f[a[b]]=m(a[b])}function s(a,b){d.shade||I.css({top:h(-b),left:h(-a)}),L.css({top:h(b),left:h(a)})}function u(a,b){L.width(a).height(b)}function v(){var a=ba.getFixed();ba.setPressed([a.x,a.y]),ba.setCurrent([a.x2,a.y2]),w()}function w(a){if(b)return x(a)}function x(a){var c=ba.getFixed();u(c.w,c.h),s(c.x,c.y),d.shade&&bb.updateRaw(c),b||A(),a?d.onSelect.call(bt,t(c)):d.onChange.call(bt,t(c))}function y(a,c,e){if(!b&&!c)return;d.bgFade&&!e?E.animate({opacity:a},{queue:!1,duration:d.fadeTime}):E.css("opacity",a)}function A(){L.show(),d.shade?bb.opacity(P):y(P,!0),b=!0}function B(){F(),L.hide(),d.shade?bb.opacity(1):y(1),b=!1,d.onRelease.call(bt)}function C(){j&&K.show()}function D(){j=!0;if(d.allowResize)return K.show(),!0}function F(){j=!1,K.hide(
+)}function G(a){Y===a?F():D()}function H(){G(!1),v()}var b,c=370,e={},f={},g={},j=!1;d.dragEdges&&a.isArray(d.createDragbars)&&o(d.createDragbars),a.isArray(d.createHandles)&&q(d.createHandles),d.drawBorders&&a.isArray(d.createBorders)&&p(d.createBorders),a(document).bind("touchstart.jcrop-ios",function(b){a(b.currentTarget).hasClass("jcrop-tracker")&&b.stopPropagation()});var M=z().mousedown(r("move")).css({cursor:"move",position:"absolute",zIndex:360});return _.support&&M.bind("touchstart.jcrop",_.createDragger("move")),J.append(M),F(),{updateVisible:w,update:x,release:B,refresh:v,isAwake:function(){return b},setCursor:function(a){M.css("cursor",a)},enableHandles:D,enableOnly:function(){j=!0},showHandles:C,disableHandles:F,animMode:G,setBgOpacity:y,done:H}}(),bd=function(){function f(){N.css({zIndex:450}),_.support&&a(document).bind("touchmove.jcrop",k).bind("touchend.jcrop",m),e&&a(document).bind("mousemove.jcrop",h).bind("mouseup.jcrop",i)}function g(){N.css({zIndex:290}),a(document).unbind(".jcrop")}function h
+(a){return b(l(a)),!1}function i(a){return a.preventDefault(),a.stopPropagation(),X&&(X=!1,c(l(a)),bc.isAwake()&&d.onSelect.call(bt,t(ba.getFixed())),g(),b=function(){},c=function(){}),!1}function j(a,d){return X=!0,b=a,c=d,f(),!1}function k(a){return a.pageX=a.originalEvent.changedTouches[0].pageX,a.pageY=a.originalEvent.changedTouches[0].pageY,h(a)}function m(a){return a.pageX=a.originalEvent.changedTouches[0].pageX,a.pageY=a.originalEvent.changedTouches[0].pageY,i(a)}function n(a){N.css("cursor",a)}var b=function(){},c=function(){},e=d.trackDocument;return e||N.mousemove(h).mouseup(i).mouseout(i),E.before(N),{activateHandlers:j,setCursor:n}}(),be=function(){function e(){d.keySupport&&(b.show(),b.focus())}function f(a){b.hide()}function h(a,b,c){d.allowMove&&(ba.moveOffset([b,c]),bc.updateVisible(!0)),a.preventDefault(),a.stopPropagation()}function i(a){if(a.ctrlKey||a.metaKey)return!0;Z=a.shiftKey?!0:!1;var b=Z?10:1;switch(a.keyCode){case 37:h(a,-b,0);break;case 39:h(a,b,0);break;case 38:h(a,0,-b);break;case 40
+:h(a,0,b);break;case 27:d.allowSelect&&bc.release();break;case 9:return!0}return!1}var b=a('<input type="radio" />').css({position:"fixed",left:"-120px",width:"12px"}),c=a("<div />").css({position:"absolute",overflow:"hidden"}).append(b);return d.keySupport&&(b.keydown(i).blur(f),g||!d.fixedSupport?(b.css({position:"absolute",left:"-20px"}),c.append(b).insertBefore(E)):b.insertBefore(E)),{watchKeys:e}}();_.support&&N.bind("touchstart.jcrop",_.newSelection),K.hide(),bs(!0);var bt={setImage:bq,animateTo:bg,setSelect:bh,setOptions:bl,tellSelect:bj,tellScaled:bk,setClass:bf,disable:bm,enable:bn,cancel:bo,release:bc.release,destroy:bp,focus:be.watchKeys,getBounds:function(){return[F*U,G*V]},getWidgetSize:function(){return[F,G]},getScaleFactor:function(){return[U,V]},getOptions:function(){return d},ui:{holder:H,selection:L}};return a.browser.msie&&H.bind("selectstart",function(){return!1}),B.data("Jcrop",bt),bt},a.fn.Jcrop=function(b,c){var d;return this.each(function(){if(a(this).data("Jcrop")){if(b==="api")return a
+(this).data("Jcrop");a(this).data("Jcrop").setOptions(b)}else this.tagName=="IMG"?a.Jcrop.Loader(this,function(){a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d)}):(a(this).css({display:"block",visibility:"hidden"}),d=a.Jcrop(this,b),a.isFunction(c)&&c.call(d))}),this},a.Jcrop.Loader=function(b,c,d){function g(){f.complete?(e.unbind(".jcloader"),a.isFunction(c)&&c.call(f)):window.setTimeout(g,50)}var e=a(b),f=e[0];e.bind("load.jcloader",g).bind("error.jcloader",function(b){e.unbind(".jcloader"),a.isFunction(d)&&d.call(f)}),f.complete&&a.isFunction(c)&&(e.unbind(".jcloader"),c.call(f))},a.Jcrop.defaults={allowSelect:!0,allowMove:!0,allowResize:!0,trackDocument:!0,baseClass:"jcrop",addClass:null,bgColor:"black",bgOpacity:.6,bgFade:!1,borderOpacity:.4,handleOpacity:.5,handleSize:7,aspectRatio:0,keySupport:!0,createHandles:["n","s","e","w","nw","ne","se","sw"],createDragbars:["n","s","e","w"],createBorders:["n","s","e","w"],drawBorders:!0,dragEdges:!0,fixedSupport:!0,
+touchSupport:null,shade:null,boxWidth:0,boxHeight:0,boundary:2,fadeTime:400,animationDelay:20,swingSpeed:3,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){},onDblClick:function(){},onRelease:function(){}}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery-migrate.js b/src/wp-includes/js/jquery/jquery-migrate.js
new file mode 100644
index 0000000000..dbe8cbd4d8
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery-migrate.js
@@ -0,0 +1,521 @@
+/*!
+ * jQuery Migrate - v1.2.1 - 2013-05-08
+ * https://github.com/jquery/jquery-migrate
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ */
+(function( jQuery, window, undefined ) {
+// See http://bugs.jquery.com/ticket/13335
+// "use strict";
+
+
+var warnedAbout = {};
+
+// List of warnings already given; public read only
+jQuery.migrateWarnings = [];
+
+// Set to true to prevent console output; migrateWarnings still maintained
+// jQuery.migrateMute = false;
+
+// Show a message on the console so devs know we're active
+if ( !jQuery.migrateMute && window.console && window.console.log ) {
+ window.console.log("JQMIGRATE: Logging is active");
+}
+
+// Set to false to disable traces that appear with warnings
+if ( jQuery.migrateTrace === undefined ) {
+ jQuery.migrateTrace = true;
+}
+
+// Forget any warnings we've already given; public
+jQuery.migrateReset = function() {
+ warnedAbout = {};
+ jQuery.migrateWarnings.length = 0;
+};
+
+function migrateWarn( msg) {
+ var console = window.console;
+ if ( !warnedAbout[ msg ] ) {
+ warnedAbout[ msg ] = true;
+ jQuery.migrateWarnings.push( msg );
+ if ( console && console.warn && !jQuery.migrateMute ) {
+ console.warn( "JQMIGRATE: " + msg );
+ if ( jQuery.migrateTrace && console.trace ) {
+ console.trace();
+ }
+ }
+ }
+}
+
+function migrateWarnProp( obj, prop, value, msg ) {
+ if ( Object.defineProperty ) {
+ // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
+ // allow property to be overwritten in case some other plugin wants it
+ try {
+ Object.defineProperty( obj, prop, {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ migrateWarn( msg );
+ return value;
+ },
+ set: function( newValue ) {
+ migrateWarn( msg );
+ value = newValue;
+ }
+ });
+ return;
+ } catch( err ) {
+ // IE8 is a dope about Object.defineProperty, can't warn there
+ }
+ }
+
+ // Non-ES5 (or broken) browser; just set the property
+ jQuery._definePropertyBroken = true;
+ obj[ prop ] = value;
+}
+
+if ( document.compatMode === "BackCompat" ) {
+ // jQuery has never supported or tested Quirks Mode
+ migrateWarn( "jQuery is not compatible with Quirks Mode" );
+}
+
+
+var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
+ oldAttr = jQuery.attr,
+ valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
+ function() { return null; },
+ valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
+ function() { return undefined; },
+ rnoType = /^(?:input|button)$/i,
+ rnoAttrNodeType = /^[238]$/,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ ruseDefault = /^(?:checked|selected)$/i;
+
+// jQuery.attrFn
+migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
+
+jQuery.attr = function( elem, name, value, pass ) {
+ var lowerName = name.toLowerCase(),
+ nType = elem && elem.nodeType;
+
+ if ( pass ) {
+ // Since pass is used internally, we only warn for new jQuery
+ // versions where there isn't a pass arg in the formal params
+ if ( oldAttr.length < 4 ) {
+ migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
+ }
+ if ( elem && !rnoAttrNodeType.test( nType ) &&
+ (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+ }
+
+ // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
+ // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
+ if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
+ migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
+ }
+
+ // Restore boolHook for boolean property/attribute synchronization
+ if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
+ jQuery.attrHooks[ lowerName ] = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" &&
+ ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+ };
+
+ // Warn only for attributes that can remain distinct from their properties post-1.9
+ if ( ruseDefault.test( lowerName ) ) {
+ migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+ }
+ }
+
+ return oldAttr.call( jQuery, elem, name, value );
+};
+
+// attrHooks: value
+jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrGet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value') no longer gets properties");
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrSet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+};
+
+
+var matched, browser,
+ oldInit = jQuery.fn.init,
+ oldParseJSON = jQuery.parseJSON,
+ // Note: XSS check is done below after string is trimmed
+ rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
+
+// $(html) "looks like html" rule change
+jQuery.fn.init = function( selector, context, rootjQuery ) {
+ var match;
+
+ if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
+ (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+ // This is an HTML string according to the "old" rules; is it still?
+ if ( selector.charAt( 0 ) !== "<" ) {
+ migrateWarn("$(html) HTML strings must start with '<' character");
+ }
+ if ( match[ 3 ] ) {
+ migrateWarn("$(html) HTML text after last tag is ignored");
+ }
+ // Consistently reject any HTML-like string starting with a hash (#9521)
+ // Note that this may break jQuery 1.6.x code that otherwise would work.
+ if ( match[ 0 ].charAt( 0 ) === "#" ) {
+ migrateWarn("HTML string cannot start with a '#' character");
+ jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+ }
+ // Now process using loose rules; let pre-1.8 play too
+ if ( context && context.context ) {
+ // jQuery object as context; parseHTML expects a DOM object
+ context = context.context;
+ }
+ if ( jQuery.parseHTML ) {
+ return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
+ context, rootjQuery );
+ }
+ }
+ return oldInit.apply( this, arguments );
+};
+jQuery.fn.init.prototype = jQuery.fn;
+
+// Let $.parseJSON(falsy_value) return null
+jQuery.parseJSON = function( json ) {
+ if ( !json && json !== null ) {
+ migrateWarn("jQuery.parseJSON requires a valid JSON string");
+ return null;
+ }
+ return oldParseJSON.apply( this, arguments );
+};
+
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+// Don't clobber any existing jQuery.browser in case it's different
+if ( !jQuery.browser ) {
+ matched = jQuery.uaMatch( navigator.userAgent );
+ browser = {};
+
+ if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+ // Chrome is Webkit, but Webkit is also Safari.
+ if ( browser.chrome ) {
+ browser.webkit = true;
+ } else if ( browser.webkit ) {
+ browser.safari = true;
+ }
+
+ jQuery.browser = browser;
+}
+
+// Warn if the code tries to get jQuery.browser
+migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ migrateWarn( "jQuery.sub() is deprecated" );
+ return jQuerySub;
+};
+
+
+// Ensure that $.ajax gets the new parseJSON defined in core.js
+jQuery.ajaxSetup({
+ converters: {
+ "text json": jQuery.parseJSON
+ }
+});
+
+
+var oldFnData = jQuery.fn.data;
+
+jQuery.fn.data = function( name ) {
+ var ret, evt,
+ elem = this[0];
+
+ // Handles 1.7 which has this behavior and 1.8 which doesn't
+ if ( elem && name === "events" && arguments.length === 1 ) {
+ ret = jQuery.data( elem, name );
+ evt = jQuery._data( elem, name );
+ if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
+ migrateWarn("Use of jQuery.fn.data('events') is deprecated");
+ return evt;
+ }
+ }
+ return oldFnData.apply( this, arguments );
+};
+
+
+var rscriptType = /\/(java|ecma)script/i,
+ oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
+
+jQuery.fn.andSelf = function() {
+ migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+ return oldSelf.apply( this, arguments );
+};
+
+// Since jQuery.clean is used internally on older versions, we only shim if it's missing
+if ( !jQuery.clean ) {
+ jQuery.clean = function( elems, context, fragment, scripts ) {
+ // Set context per 1.8 logic
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ migrateWarn("jQuery.clean() is deprecated");
+
+ var i, elem, handleScript, jsTags,
+ ret = [];
+
+ jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
+
+ // Complex logic lifted directly from jQuery 1.8
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var eventAdd = jQuery.event.add,
+ eventRemove = jQuery.event.remove,
+ eventTrigger = jQuery.event.trigger,
+ oldToggle = jQuery.fn.toggle,
+ oldLive = jQuery.fn.live,
+ oldDie = jQuery.fn.die,
+ ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
+ rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ hoverHack = function( events ) {
+ if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
+ return events;
+ }
+ if ( rhoverHack.test( events ) ) {
+ migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
+ }
+ return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+// Event props removed in 1.9, put them back if needed; no practical way to warn them
+if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
+ jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
+}
+
+// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
+if ( jQuery.event.dispatch ) {
+ migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
+}
+
+// Support for 'hover' pseudo-event and ajax event warnings
+jQuery.event.add = function( elem, types, handler, data, selector ){
+ if ( elem !== document && rajaxEvent.test( types ) ) {
+ migrateWarn( "AJAX events should be attached to document: " + types );
+ }
+ eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
+};
+jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
+ eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
+};
+
+jQuery.fn.error = function() {
+ var args = Array.prototype.slice.call( arguments, 0);
+ migrateWarn("jQuery.fn.error() is deprecated");
+ args.splice( 0, 0, "error" );
+ if ( arguments.length ) {
+ return this.bind.apply( this, args );
+ }
+ // error event should not bubble to window, although it does pre-1.7
+ this.triggerHandler.apply( this, args );
+ return this;
+};
+
+jQuery.fn.toggle = function( fn, fn2 ) {
+
+ // Don't mess with animation or css toggles
+ if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
+ return oldToggle.apply( this, arguments );
+ }
+ migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
+
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+};
+
+jQuery.fn.live = function( types, data, fn ) {
+ migrateWarn("jQuery.fn.live() is deprecated");
+ if ( oldLive ) {
+ return oldLive.apply( this, arguments );
+ }
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+};
+
+jQuery.fn.die = function( types, fn ) {
+ migrateWarn("jQuery.fn.die() is deprecated");
+ if ( oldDie ) {
+ return oldDie.apply( this, arguments );
+ }
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+};
+
+// Turn global events into document-triggered events
+jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
+ if ( !elem && !rajaxEvent.test( event ) ) {
+ migrateWarn( "Global events are undocumented and deprecated" );
+ }
+ return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
+};
+jQuery.each( ajaxEvents.split("|"),
+ function( _, name ) {
+ jQuery.event.special[ name ] = {
+ setup: function() {
+ var elem = this;
+
+ // The document needs no shimming; must be !== for oldIE
+ if ( elem !== document ) {
+ jQuery.event.add( document, name + "." + jQuery.guid, function() {
+ jQuery.event.trigger( name, null, elem, true );
+ });
+ jQuery._data( this, name, jQuery.guid++ );
+ }
+ return false;
+ },
+ teardown: function() {
+ if ( this !== document ) {
+ jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
+ }
+ return false;
+ }
+ };
+ }
+);
+
+
+})( jQuery, window );
diff --git a/src/wp-includes/js/jquery/jquery-migrate.min.js b/src/wp-includes/js/jquery/jquery-migrate.min.js
new file mode 100644
index 0000000000..8b7ec47a2d
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery-migrate.min.js
@@ -0,0 +1,2 @@
+/*! jQuery Migrate v1.2.1 | (c) 2005, 2013 jQuery Foundation, Inc. and other contributors | jquery.org/license */
+jQuery.migrateMute===void 0&&(jQuery.migrateMute=!0),function(e,t,n){function r(n){var r=t.console;i[n]||(i[n]=!0,e.migrateWarnings.push(n),r&&r.warn&&!e.migrateMute&&(r.warn("JQMIGRATE: "+n),e.migrateTrace&&r.trace&&r.trace()))}function a(t,a,i,o){if(Object.defineProperty)try{return Object.defineProperty(t,a,{configurable:!0,enumerable:!0,get:function(){return r(o),i},set:function(e){r(o),i=e}}),n}catch(s){}e._definePropertyBroken=!0,t[a]=i}var i={};e.migrateWarnings=[],!e.migrateMute&&t.console&&t.console.log&&t.console.log("JQMIGRATE: Logging is active"),e.migrateTrace===n&&(e.migrateTrace=!0),e.migrateReset=function(){i={},e.migrateWarnings.length=0},"BackCompat"===document.compatMode&&r("jQuery is not compatible with Quirks Mode");var o=e("<input/>",{size:1}).attr("size")&&e.attrFn,s=e.attr,u=e.attrHooks.value&&e.attrHooks.value.get||function(){return null},c=e.attrHooks.value&&e.attrHooks.value.set||function(){return n},l=/^(?:input|button)$/i,d=/^[238]$/,p=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,f=/^(?:checked|selected)$/i;a(e,"attrFn",o||{},"jQuery.attrFn is deprecated"),e.attr=function(t,a,i,u){var c=a.toLowerCase(),g=t&&t.nodeType;return u&&(4>s.length&&r("jQuery.fn.attr( props, pass ) is deprecated"),t&&!d.test(g)&&(o?a in o:e.isFunction(e.fn[a])))?e(t)[a](i):("type"===a&&i!==n&&l.test(t.nodeName)&&t.parentNode&&r("Can't change the 'type' of an input or button in IE 6/7/8"),!e.attrHooks[c]&&p.test(c)&&(e.attrHooks[c]={get:function(t,r){var a,i=e.prop(t,r);return i===!0||"boolean"!=typeof i&&(a=t.getAttributeNode(r))&&a.nodeValue!==!1?r.toLowerCase():n},set:function(t,n,r){var a;return n===!1?e.removeAttr(t,r):(a=e.propFix[r]||r,a in t&&(t[a]=!0),t.setAttribute(r,r.toLowerCase())),r}},f.test(c)&&r("jQuery.fn.attr('"+c+"') may use property instead of attribute")),s.call(e,t,a,i))},e.attrHooks.value={get:function(e,t){var n=(e.nodeName||"").toLowerCase();return"button"===n?u.apply(this,arguments):("input"!==n&&"option"!==n&&r("jQuery.fn.attr('value') no longer gets properties"),t in e?e.value:null)},set:function(e,t){var a=(e.nodeName||"").toLowerCase();return"button"===a?c.apply(this,arguments):("input"!==a&&"option"!==a&&r("jQuery.fn.attr('value', val) no longer sets properties"),e.value=t,n)}};var g,h,v=e.fn.init,m=e.parseJSON,y=/^([^<]*)(<[\w\W]+>)([^>]*)$/;e.fn.init=function(t,n,a){var i;return t&&"string"==typeof t&&!e.isPlainObject(n)&&(i=y.exec(e.trim(t)))&&i[0]&&("<"!==t.charAt(0)&&r("$(html) HTML strings must start with '<' character"),i[3]&&r("$(html) HTML text after last tag is ignored"),"#"===i[0].charAt(0)&&(r("HTML string cannot start with a '#' character"),e.error("JQMIGRATE: Invalid selector string (XSS)")),n&&n.context&&(n=n.context),e.parseHTML)?v.call(this,e.parseHTML(i[2],n,!0),n,a):v.apply(this,arguments)},e.fn.init.prototype=e.fn,e.parseJSON=function(e){return e||null===e?m.apply(this,arguments):(r("jQuery.parseJSON requires a valid JSON string"),null)},e.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e.browser||(g=e.uaMatch(navigator.userAgent),h={},g.browser&&(h[g.browser]=!0,h.version=g.version),h.chrome?h.webkit=!0:h.webkit&&(h.safari=!0),e.browser=h),a(e,"browser",e.browser,"jQuery.browser is deprecated"),e.sub=function(){function t(e,n){return new t.fn.init(e,n)}e.extend(!0,t,this),t.superclass=this,t.fn=t.prototype=this(),t.fn.constructor=t,t.sub=this.sub,t.fn.init=function(r,a){return a&&a instanceof e&&!(a instanceof t)&&(a=t(a)),e.fn.init.call(this,r,a,n)},t.fn.init.prototype=t.fn;var n=t(document);return r("jQuery.sub() is deprecated"),t},e.ajaxSetup({converters:{"text json":e.parseJSON}});var b=e.fn.data;e.fn.data=function(t){var a,i,o=this[0];return!o||"events"!==t||1!==arguments.length||(a=e.data(o,t),i=e._data(o,t),a!==n&&a!==i||i===n)?b.apply(this,arguments):(r("Use of jQuery.fn.data('events') is deprecated"),i)};var j=/\/(java|ecma)script/i,w=e.fn.andSelf||e.fn.addBack;e.fn.andSelf=function(){return r("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"),w.apply(this,arguments)},e.clean||(e.clean=function(t,a,i,o){a=a||document,a=!a.nodeType&&a[0]||a,a=a.ownerDocument||a,r("jQuery.clean() is deprecated");var s,u,c,l,d=[];if(e.merge(d,e.buildFragment(t,a).childNodes),i)for(c=function(e){return!e.type||j.test(e.type)?o?o.push(e.parentNode?e.parentNode.removeChild(e):e):i.appendChild(e):n},s=0;null!=(u=d[s]);s++)e.nodeName(u,"script")&&c(u)||(i.appendChild(u),u.getElementsByTagName!==n&&(l=e.grep(e.merge([],u.getElementsByTagName("script")),c),d.splice.apply(d,[s+1,0].concat(l)),s+=l.length));return d});var Q=e.event.add,x=e.event.remove,k=e.event.trigger,N=e.fn.toggle,T=e.fn.live,M=e.fn.die,S="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",C=RegExp("\\b(?:"+S+")\\b"),H=/(?:^|\s)hover(\.\S+|)\b/,A=function(t){return"string"!=typeof t||e.event.special.hover?t:(H.test(t)&&r("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'"),t&&t.replace(H,"mouseenter$1 mouseleave$1"))};e.event.props&&"attrChange"!==e.event.props[0]&&e.event.props.unshift("attrChange","attrName","relatedNode","srcElement"),e.event.dispatch&&a(e.event,"handle",e.event.dispatch,"jQuery.event.handle is undocumented and deprecated"),e.event.add=function(e,t,n,a,i){e!==document&&C.test(t)&&r("AJAX events should be attached to document: "+t),Q.call(this,e,A(t||""),n,a,i)},e.event.remove=function(e,t,n,r,a){x.call(this,e,A(t)||"",n,r,a)},e.fn.error=function(){var e=Array.prototype.slice.call(arguments,0);return r("jQuery.fn.error() is deprecated"),e.splice(0,0,"error"),arguments.length?this.bind.apply(this,e):(this.triggerHandler.apply(this,e),this)},e.fn.toggle=function(t,n){if(!e.isFunction(t)||!e.isFunction(n))return N.apply(this,arguments);r("jQuery.fn.toggle(handler, handler...) is deprecated");var a=arguments,i=t.guid||e.guid++,o=0,s=function(n){var r=(e._data(this,"lastToggle"+t.guid)||0)%o;return e._data(this,"lastToggle"+t.guid,r+1),n.preventDefault(),a[r].apply(this,arguments)||!1};for(s.guid=i;a.length>o;)a[o++].guid=i;return this.click(s)},e.fn.live=function(t,n,a){return r("jQuery.fn.live() is deprecated"),T?T.apply(this,arguments):(e(this.context).on(t,this.selector,n,a),this)},e.fn.die=function(t,n){return r("jQuery.fn.die() is deprecated"),M?M.apply(this,arguments):(e(this.context).off(t,this.selector||"**",n),this)},e.event.trigger=function(e,t,n,a){return n||C.test(e)||r("Global events are undocumented and deprecated"),k.call(this,e,t,n||document,a)},e.each(S.split("|"),function(t,n){e.event.special[n]={setup:function(){var t=this;return t!==document&&(e.event.add(document,n+"."+e.guid,function(){e.event.trigger(n,null,t,!0)}),e._data(this,n,e.guid++)),!1},teardown:function(){return this!==document&&e.event.remove(document,n+"."+e._data(this,n)),!1}}})}(jQuery,window); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.color.min.js b/src/wp-includes/js/jquery/jquery.color.min.js
new file mode 100644
index 0000000000..d0dbfa83ff
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.color.min.js
@@ -0,0 +1,2 @@
+/*! jQuery Color v@2.1.1 with SVG Color Names http://github.com/jquery/jquery-color | jquery.org/license */
+(function(a,b){function m(a,b,c){var d=h[b.type]||{};return a==null?c||!b.def?null:b.def:(a=d.floor?~~a:parseFloat(a),isNaN(a)?b.def:d.mod?(a+d.mod)%d.mod:0>a?0:d.max<a?d.max:a)}function n(b){var c=f(),d=c._rgba=[];return b=b.toLowerCase(),l(e,function(a,e){var f,h=e.re.exec(b),i=h&&e.parse(h),j=e.space||"rgba";if(i)return f=c[j](i),c[g[j].cache]=f[g[j].cache],d=c._rgba=f._rgba,!1}),d.length?(d.join()==="0,0,0,0"&&a.extend(d,k.transparent),c):k[b]}function o(a,b,c){return c=(c+1)%1,c*6<1?a+(b-a)*c*6:c*2<1?b:c*3<2?a+(b-a)*(2/3-c)*6:a}var c="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",d=/^([\-+])=\s*(\d+\.?\d*)/,e=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(a){return[a[1],a[2],a[3],a[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(a){return[a[1]*2.55,a[2]*2.55,a[3]*2.55,a[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(a){return[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(a){return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(a){return[a[1],a[2]/100,a[3]/100,a[4]]}}],f=a.Color=function(b,c,d,e){return new a.Color.fn.parse(b,c,d,e)},g={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},h={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},i=f.support={},j=a("<p>")[0],k,l=a.each;j.style.cssText="background-color:rgba(1,1,1,.5)",i.rgba=j.style.backgroundColor.indexOf("rgba")>-1,l(g,function(a,b){b.cache="_"+a,b.props.alpha={idx:3,type:"percent",def:1}}),f.fn=a.extend(f.prototype,{parse:function(c,d,e,h){if(c===b)return this._rgba=[null,null,null,null],this;if(c.jquery||c.nodeType)c=a(c).css(d),d=b;var i=this,j=a.type(c),o=this._rgba=[];d!==b&&(c=[c,d,e,h],j="array");if(j==="string")return this.parse(n(c)||k._default);if(j==="array")return l(g.rgba.props,function(a,b){o[b.idx]=m(c[b.idx],b)}),this;if(j==="object")return c instanceof f?l(g,function(a,b){c[b.cache]&&(i[b.cache]=c[b.cache].slice())}):l(g,function(b,d){var e=d.cache;l(d.props,function(a,b){if(!i[e]&&d.to){if(a==="alpha"||c[a]==null)return;i[e]=d.to(i._rgba)}i[e][b.idx]=m(c[a],b,!0)}),i[e]&&a.inArray(null,i[e].slice(0,3))<0&&(i[e][3]=1,d.from&&(i._rgba=d.from(i[e])))}),this},is:function(a){var b=f(a),c=!0,d=this;return l(g,function(a,e){var f,g=b[e.cache];return g&&(f=d[e.cache]||e.to&&e.to(d._rgba)||[],l(e.props,function(a,b){if(g[b.idx]!=null)return c=g[b.idx]===f[b.idx],c})),c}),c},_space:function(){var a=[],b=this;return l(g,function(c,d){b[d.cache]&&a.push(c)}),a.pop()},transition:function(a,b){var c=f(a),d=c._space(),e=g[d],i=this.alpha()===0?f("transparent"):this,j=i[e.cache]||e.to(i._rgba),k=j.slice();return c=c[e.cache],l(e.props,function(a,d){var e=d.idx,f=j[e],g=c[e],i=h[d.type]||{};if(g===null)return;f===null?k[e]=g:(i.mod&&(g-f>i.mod/2?f+=i.mod:f-g>i.mod/2&&(f-=i.mod)),k[e]=m((g-f)*b+f,d))}),this[d](k)},blend:function(b){if(this._rgba[3]===1)return this;var c=this._rgba.slice(),d=c.pop(),e=f(b)._rgba;return f(a.map(c,function(a,b){return(1-d)*e[b]+d*a}))},toRgbaString:function(){var b="rgba(",c=a.map(this._rgba,function(a,b){return a==null?b>2?1:0:a});return c[3]===1&&(c.pop(),b="rgb("),b+c.join()+")"},toHslaString:function(){var b="hsla(",c=a.map(this.hsla(),function(a,b){return a==null&&(a=b>2?1:0),b&&b<3&&(a=Math.round(a*100)+"%"),a});return c[3]===1&&(c.pop(),b="hsl("),b+c.join()+")"},toHexString:function(b){var c=this._rgba.slice(),d=c.pop();return b&&c.push(~~(d*255)),"#"+a.map(c,function(a){return a=(a||0).toString(16),a.length===1?"0"+a:a}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}}),f.fn.parse.prototype=f.fn,g.hsla.to=function(a){if(a[0]==null||a[1]==null||a[2]==null)return[null,null,null,a[3]];var b=a[0]/255,c=a[1]/255,d=a[2]/255,e=a[3],f=Math.max(b,c,d),g=Math.min(b,c,d),h=f-g,i=f+g,j=i*.5,k,l;return g===f?k=0:b===f?k=60*(c-d)/h+360:c===f?k=60*(d-b)/h+120:k=60*(b-c)/h+240,h===0?l=0:j<=.5?l=h/i:l=h/(2-i),[Math.round(k)%360,l,j,e==null?1:e]},g.hsla.from=function(a){if(a[0]==null||a[1]==null||a[2]==null)return[null,null,null,a[3]];var b=a[0]/360,c=a[1],d=a[2],e=a[3],f=d<=.5?d*(1+c):d+c-d*c,g=2*d-f;return[Math.round(o(g,f,b+1/3)*255),Math.round(o(g,f,b)*255),Math.round(o(g,f,b-1/3)*255),e]},l(g,function(c,e){var g=e.props,h=e.cache,i=e.to,j=e.from;f.fn[c]=function(c){i&&!this[h]&&(this[h]=i(this._rgba));if(c===b)return this[h].slice();var d,e=a.type(c),k=e==="array"||e==="object"?c:arguments,n=this[h].slice();return l(g,function(a,b){var c=k[e==="object"?a:b.idx];c==null&&(c=n[b.idx]),n[b.idx]=m(c,b)}),j?(d=f(j(n)),d[h]=n,d):f(n)},l(g,function(b,e){if(f.fn[b])return;f.fn[b]=function(f){var g=a.type(f),h=b==="alpha"?this._hsla?"hsla":"rgba":c,i=this[h](),j=i[e.idx],k;return g==="undefined"?j:(g==="function"&&(f=f.call(this,j),g=a.type(f)),f==null&&e.empty?this:(g==="string"&&(k=d.exec(f),k&&(f=j+parseFloat(k[2])*(k[1]==="+"?1:-1))),i[e.idx]=f,this[h](i)))}})}),f.hook=function(b){var c=b.split(" ");l(c,function(b,c){a.cssHooks[c]={set:function(b,d){var e,g,h="";if(a.type(d)!=="string"||(e=n(d))){d=f(e||d);if(!i.rgba&&d._rgba[3]!==1){g=c==="backgroundColor"?b.parentNode:b;while((h===""||h==="transparent")&&g&&g.style)try{h=a.css(g,"backgroundColor"),g=g.parentNode}catch(j){}d=d.blend(h&&h!=="transparent"?h:"_default")}d=d.toRgbaString()}try{b.style[c]=d}catch(j){}}},a.fx.step[c]=function(b){b.colorInit||(b.start=f(b.elem,c),b.end=f(b.end),b.colorInit=!0),a.cssHooks[c].set(b.elem,b.start.transition(b.end,b.pos))}})},f.hook(c),a.cssHooks.borderColor={expand:function(a){var b={};return l(["Top","Right","Bottom","Left"],function(c,d){b["border"+d+"Color"]=a}),b}},k=a.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}})(jQuery),jQuery.extend(jQuery.Color.names,{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",blanchedalmond:"#ffebcd",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",limegreen:"#32cd32",linen:"#faf0e6",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",oldlace:"#fdf5e6",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",whitesmoke:"#f5f5f5",yellowgreen:"#9acd32"});
diff --git a/src/wp-includes/js/jquery/jquery.form.js b/src/wp-includes/js/jquery/jquery.form.js
new file mode 100644
index 0000000000..d0cb23c238
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.form.js
@@ -0,0 +1,825 @@
+/*!
+ * jQuery Form Plugin
+ * version: 2.73 (03-MAY-2011)
+ * @requires jQuery v1.3.2 or later
+ *
+ * Examples and documentation at: http://malsup.com/jquery/form/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+;(function($) {
+
+/*
+ Usage Note:
+ -----------
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
+ functions are intended to be exclusive. Use ajaxSubmit if you want
+ to bind your own submit handler to the form. For example,
+
+ $(document).ready(function() {
+ $('#myForm').bind('submit', function(e) {
+ e.preventDefault(); // <-- important
+ $(this).ajaxSubmit({
+ target: '#output'
+ });
+ });
+ });
+
+ Use ajaxForm when you want the plugin to manage all the event binding
+ for you. For example,
+
+ $(document).ready(function() {
+ $('#myForm').ajaxForm({
+ target: '#output'
+ });
+ });
+
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
+ at the appropriate time.
+*/
+
+/**
+ * ajaxSubmit() provides a mechanism for immediately submitting
+ * an HTML form using AJAX.
+ */
+$.fn.ajaxSubmit = function(options) {
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
+ if (!this.length) {
+ log('ajaxSubmit: skipping submit process - no element selected');
+ return this;
+ }
+
+ if (typeof options == 'function') {
+ options = { success: options };
+ }
+
+ var action = this.attr('action');
+ var url = (typeof action === 'string') ? $.trim(action) : '';
+ if (url) {
+ // clean url (don't include hash vaue)
+ url = (url.match(/^([^#]+)/)||[])[1];
+ }
+ url = url || window.location.href || '';
+
+ options = $.extend(true, {
+ url: url,
+ success: $.ajaxSettings.success,
+ type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57)
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
+ }, options);
+
+ // hook for manipulating the form data before it is extracted;
+ // convenient for use with rich editors like tinyMCE or FCKEditor
+ var veto = {};
+ this.trigger('form-pre-serialize', [this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
+ return this;
+ }
+
+ // provide opportunity to alter form data before it is serialized
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
+ return this;
+ }
+
+ var n,v,a = this.formToArray(options.semantic);
+ if (options.data) {
+ options.extraData = options.data;
+ for (n in options.data) {
+ if(options.data[n] instanceof Array) {
+ for (var k in options.data[n]) {
+ a.push( { name: n, value: options.data[n][k] } );
+ }
+ }
+ else {
+ v = options.data[n];
+ v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
+ a.push( { name: n, value: v } );
+ }
+ }
+ }
+
+ // give pre-submit callback an opportunity to abort the submit
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
+ return this;
+ }
+
+ // fire vetoable 'validate' event
+ this.trigger('form-submit-validate', [a, this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
+ return this;
+ }
+
+ var q = $.param(a);
+
+ if (options.type.toUpperCase() == 'GET') {
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
+ options.data = null; // data is null for 'get'
+ }
+ else {
+ options.data = q; // data is the query string for 'post'
+ }
+
+ var $form = this, callbacks = [];
+ if (options.resetForm) {
+ callbacks.push(function() { $form.resetForm(); });
+ }
+ if (options.clearForm) {
+ callbacks.push(function() { $form.clearForm(); });
+ }
+
+ // perform a load on the target only if dataType is not provided
+ if (!options.dataType && options.target) {
+ var oldSuccess = options.success || function(){};
+ callbacks.push(function(data) {
+ var fn = options.replaceTarget ? 'replaceWith' : 'html';
+ $(options.target)[fn](data).each(oldSuccess, arguments);
+ });
+ }
+ else if (options.success) {
+ callbacks.push(options.success);
+ }
+
+ options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
+ var context = options.context || options; // jQuery 1.4+ supports scope context
+ for (var i=0, max=callbacks.length; i < max; i++) {
+ callbacks[i].apply(context, [data, status, xhr || $form, $form]);
+ }
+ };
+
+ // are there files to upload?
+ var fileInputs = $('input:file', this).length > 0;
+ var mp = 'multipart/form-data';
+ var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
+
+ // options.iframe allows user to force iframe mode
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
+ if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
+ if (options.closeKeepAlive) {
+ $.get(options.closeKeepAlive, fileUpload);
+ }
+ else {
+ fileUpload();
+ }
+ }
+ else {
+ $.ajax(options);
+ }
+
+ // fire 'notify' event
+ this.trigger('form-submit-notify', [this, options]);
+ return this;
+
+
+ // private function for handling file uploads (hat tip to YAHOO!)
+ function fileUpload() {
+ var form = $form[0];
+
+ if ($(':input[name=submit],:input[id=submit]', form).length) {
+ // if there is an input with a name or id of 'submit' then we won't be
+ // able to invoke the submit fn on the form (at least not x-browser)
+ alert('Error: Form elements must not have name or id of "submit".');
+ return;
+ }
+
+ var s = $.extend(true, {}, $.ajaxSettings, options);
+ s.context = s.context || s;
+ var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
+ var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />');
+ var io = $io[0];
+
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+
+ var xhr = { // mock object
+ aborted: 0,
+ responseText: null,
+ responseXML: null,
+ status: 0,
+ statusText: 'n/a',
+ getAllResponseHeaders: function() {},
+ getResponseHeader: function() {},
+ setRequestHeader: function() {},
+ abort: function(status) {
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
+ log('aborting upload... ' + e);
+ this.aborted = 1;
+ $io.attr('src', s.iframeSrc); // abort op in progress
+ xhr.error = e;
+ s.error && s.error.call(s.context, xhr, e, e);
+ g && $.event.trigger("ajaxError", [xhr, s, e]);
+ s.complete && s.complete.call(s.context, xhr, e);
+ }
+ };
+
+ var g = s.global;
+ // trigger ajax global events so that activity/block indicators work like normal
+ if (g && ! $.active++) {
+ $.event.trigger("ajaxStart");
+ }
+ if (g) {
+ $.event.trigger("ajaxSend", [xhr, s]);
+ }
+
+ if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+ if (s.global) {
+ $.active--;
+ }
+ return;
+ }
+ if (xhr.aborted) {
+ return;
+ }
+
+ var timedOut = 0, timeoutHandle;
+
+ // add submitting element to data if we know it
+ var sub = form.clk;
+ if (sub) {
+ var n = sub.name;
+ if (n && !sub.disabled) {
+ s.extraData = s.extraData || {};
+ s.extraData[n] = sub.value;
+ if (sub.type == "image") {
+ s.extraData[n+'.x'] = form.clk_x;
+ s.extraData[n+'.y'] = form.clk_y;
+ }
+ }
+ }
+
+ // take a breath so that pending repaints get some cpu time before the upload starts
+ function doSubmit() {
+ // make sure form attrs are set
+ var t = $form.attr('target'), a = $form.attr('action');
+
+ // update form attrs in IE friendly way
+ form.setAttribute('target',id);
+ if (form.getAttribute('method') != 'POST') {
+ form.setAttribute('method', 'POST');
+ }
+ if (form.getAttribute('action') != s.url) {
+ form.setAttribute('action', s.url);
+ }
+
+ // ie borks in some cases when setting encoding
+ if (! s.skipEncodingOverride) {
+ $form.attr({
+ encoding: 'multipart/form-data',
+ enctype: 'multipart/form-data'
+ });
+ }
+
+ // support timout
+ if (s.timeout) {
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(true); }, s.timeout);
+ }
+
+ // add "extra" data to form if provided in options
+ var extraInputs = [];
+ try {
+ if (s.extraData) {
+ for (var n in s.extraData) {
+ extraInputs.push(
+ $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
+ .appendTo(form)[0]);
+ }
+ }
+
+ // add iframe to doc and submit the form
+ $io.appendTo('body');
+ io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
+ form.submit();
+ }
+ finally {
+ // reset attrs and remove "extra" input elements
+ form.setAttribute('action',a);
+ if(t) {
+ form.setAttribute('target', t);
+ } else {
+ $form.removeAttr('target');
+ }
+ $(extraInputs).remove();
+ }
+ }
+
+ if (s.forceSync) {
+ doSubmit();
+ }
+ else {
+ setTimeout(doSubmit, 10); // this lets dom updates render
+ }
+
+ var data, doc, domCheckCount = 50, callbackProcessed;
+
+ function cb(e) {
+ if (xhr.aborted || callbackProcessed) {
+ return;
+ }
+ if (e === true && xhr) {
+ xhr.abort('timeout');
+ return;
+ }
+
+ var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
+ if (!doc || doc.location.href == s.iframeSrc) {
+ // response not received yet
+ if (!timedOut)
+ return;
+ }
+ io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
+
+ var ok = true;
+ try {
+ if (timedOut) {
+ throw 'timeout';
+ }
+
+ var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+ log('isXml='+isXml);
+ if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
+ if (--domCheckCount) {
+ // in some browsers (Opera) the iframe DOM is not always traversable when
+ // the onload callback fires, so we loop a bit to accommodate
+ log('requeing onLoad callback, DOM not available');
+ setTimeout(cb, 250);
+ return;
+ }
+ // let this fall through because server response could be an empty document
+ //log('Could not access iframe DOM after mutiple tries.');
+ //throw 'DOMException: not available';
+ }
+
+ //log('response detected');
+ xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null;
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+ if (isXml)
+ s.dataType = 'xml';
+ xhr.getResponseHeader = function(header){
+ var headers = {'content-type': s.dataType};
+ return headers[header];
+ };
+
+ var scr = /(json|script|text)/.test(s.dataType);
+ if (scr || s.textarea) {
+ // see if user embedded response in textarea
+ var ta = doc.getElementsByTagName('textarea')[0];
+ if (ta) {
+ xhr.responseText = ta.value;
+ }
+ else if (scr) {
+ // account for browsers injecting pre around json response
+ var pre = doc.getElementsByTagName('pre')[0];
+ var b = doc.getElementsByTagName('body')[0];
+ if (pre) {
+ xhr.responseText = pre.textContent;
+ }
+ else if (b) {
+ xhr.responseText = b.innerHTML;
+ }
+ }
+ }
+ else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
+ xhr.responseXML = toXml(xhr.responseText);
+ }
+
+ data = httpData(xhr, s.dataType, s);
+ }
+ catch(e){
+ log('error caught:',e);
+ ok = false;
+ xhr.error = e;
+ s.error && s.error.call(s.context, xhr, 'error', e);
+ g && $.event.trigger("ajaxError", [xhr, s, e]);
+ }
+
+ if (xhr.aborted) {
+ log('upload aborted');
+ ok = false;
+ }
+
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+ if (ok) {
+ s.success && s.success.call(s.context, data, 'success', xhr);
+ g && $.event.trigger("ajaxSuccess", [xhr, s]);
+ }
+
+ g && $.event.trigger("ajaxComplete", [xhr, s]);
+
+ if (g && ! --$.active) {
+ $.event.trigger("ajaxStop");
+ }
+
+ s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error');
+
+ callbackProcessed = true;
+ if (s.timeout)
+ clearTimeout(timeoutHandle);
+
+ // clean up
+ setTimeout(function() {
+ $io.removeData('form-plugin-onload');
+ $io.remove();
+ xhr.responseXML = null;
+ }, 100);
+ }
+
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+ if (window.ActiveXObject) {
+ doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML(s);
+ }
+ else {
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
+ }
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+ };
+ var parseJSON = $.parseJSON || function(s) {
+ return window['eval']('(' + s + ')');
+ };
+
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+ var ct = xhr.getResponseHeader('content-type') || '',
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if (xml && data.documentElement.nodeName === 'parsererror') {
+ $.error && $.error('parsererror');
+ }
+ if (s && s.dataFilter) {
+ data = s.dataFilter(data, type);
+ }
+ if (typeof data === 'string') {
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+ data = parseJSON(data);
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+ $.globalEval(data);
+ }
+ }
+ return data;
+ };
+ }
+};
+
+/**
+ * ajaxForm() provides a mechanism for fully automating form submission.
+ *
+ * The advantages of using this method instead of ajaxSubmit() are:
+ *
+ * 1: This method will include coordinates for <input type="image" /> elements (if the element
+ * is used to submit the form).
+ * 2. This method will include the submit element's name/value data (for the element that was
+ * used to submit the form).
+ * 3. This method binds the submit() method to the form for you.
+ *
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
+ * passes the options argument along after properly binding events for submit elements and
+ * the form itself.
+ */
+$.fn.ajaxForm = function(options) {
+ // in jQuery 1.3+ we can fix mistakes with the ready state
+ if (this.length === 0) {
+ var o = { s: this.selector, c: this.context };
+ if (!$.isReady && o.s) {
+ log('DOM not ready, queuing ajaxForm');
+ $(function() {
+ $(o.s,o.c).ajaxForm(options);
+ });
+ return this;
+ }
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+ return this;
+ }
+
+ return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
+ if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+ e.preventDefault();
+ $(this).ajaxSubmit(options);
+ }
+ }).bind('click.form-plugin', function(e) {
+ var target = e.target;
+ var $el = $(target);
+ if (!($el.is(":submit,input:image"))) {
+ // is this a child element of the submit el? (ex: a span within a button)
+ var t = $el.closest(':submit');
+ if (t.length == 0) {
+ return;
+ }
+ target = t[0];
+ }
+ var form = this;
+ form.clk = target;
+ if (target.type == 'image') {
+ if (e.offsetX != undefined) {
+ form.clk_x = e.offsetX;
+ form.clk_y = e.offsetY;
+ } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
+ var offset = $el.offset();
+ form.clk_x = e.pageX - offset.left;
+ form.clk_y = e.pageY - offset.top;
+ } else {
+ form.clk_x = e.pageX - target.offsetLeft;
+ form.clk_y = e.pageY - target.offsetTop;
+ }
+ }
+ // clear form vars
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+ });
+};
+
+// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
+$.fn.ajaxFormUnbind = function() {
+ return this.unbind('submit.form-plugin click.form-plugin');
+};
+
+/**
+ * formToArray() gathers form element data into an array of objects that can
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
+ * Each object in the array has both a 'name' and 'value' property. An example of
+ * an array for a simple login form might be:
+ *
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
+ *
+ * It is this array that is passed to pre-submit callback functions provided to the
+ * ajaxSubmit() and ajaxForm() methods.
+ */
+$.fn.formToArray = function(semantic) {
+ var a = [];
+ if (this.length === 0) {
+ return a;
+ }
+
+ var form = this[0];
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
+ if (!els) {
+ return a;
+ }
+
+ var i,j,n,v,el,max,jmax;
+ for(i=0, max=els.length; i < max; i++) {
+ el = els[i];
+ n = el.name;
+ if (!n) {
+ continue;
+ }
+
+ if (semantic && form.clk && el.type == "image") {
+ // handle image inputs on the fly when semantic == true
+ if(!el.disabled && form.clk == el) {
+ a.push({name: n, value: $(el).val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ continue;
+ }
+
+ v = $.fieldValue(el, true);
+ if (v && v.constructor == Array) {
+ for(j=0, jmax=v.length; j < jmax; j++) {
+ a.push({name: n, value: v[j]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: n, value: v});
+ }
+ }
+
+ if (!semantic && form.clk) {
+ // input type=='image' are not found in elements array! handle it here
+ var $input = $(form.clk), input = $input[0];
+ n = input.name;
+ if (n && !input.disabled && input.type == 'image') {
+ a.push({name: n, value: $input.val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ }
+ return a;
+};
+
+/**
+ * Serializes form data into a 'submittable' string. This method will return a string
+ * in the format: name1=value1&amp;name2=value2
+ */
+$.fn.formSerialize = function(semantic) {
+ //hand off to jQuery.param for proper encoding
+ return $.param(this.formToArray(semantic));
+};
+
+/**
+ * Serializes all field elements in the jQuery object into a query string.
+ * This method will return a string in the format: name1=value1&amp;name2=value2
+ */
+$.fn.fieldSerialize = function(successful) {
+ var a = [];
+ this.each(function() {
+ var n = this.name;
+ if (!n) {
+ return;
+ }
+ var v = $.fieldValue(this, successful);
+ if (v && v.constructor == Array) {
+ for (var i=0,max=v.length; i < max; i++) {
+ a.push({name: n, value: v[i]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: this.name, value: v});
+ }
+ });
+ //hand off to jQuery.param for proper encoding
+ return $.param(a);
+};
+
+/**
+ * Returns the value(s) of the element in the matched set. For example, consider the following form:
+ *
+ * <form><fieldset>
+ * <input name="A" type="text" />
+ * <input name="A" type="text" />
+ * <input name="B" type="checkbox" value="B1" />
+ * <input name="B" type="checkbox" value="B2"/>
+ * <input name="C" type="radio" value="C1" />
+ * <input name="C" type="radio" value="C2" />
+ * </fieldset></form>
+ *
+ * var v = $(':text').fieldValue();
+ * // if no values are entered into the text inputs
+ * v == ['','']
+ * // if values entered into the text inputs are 'foo' and 'bar'
+ * v == ['foo','bar']
+ *
+ * var v = $(':checkbox').fieldValue();
+ * // if neither checkbox is checked
+ * v === undefined
+ * // if both checkboxes are checked
+ * v == ['B1', 'B2']
+ *
+ * var v = $(':radio').fieldValue();
+ * // if neither radio is checked
+ * v === undefined
+ * // if first radio is checked
+ * v == ['C1']
+ *
+ * The successful argument controls whether or not the field element must be 'successful'
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
+ * The default value of the successful argument is true. If this value is false the value(s)
+ * for each element is returned.
+ *
+ * Note: This method *always* returns an array. If no valid value can be determined the
+ * array will be empty, otherwise it will contain one or more values.
+ */
+$.fn.fieldValue = function(successful) {
+ for (var val=[], i=0, max=this.length; i < max; i++) {
+ var el = this[i];
+ var v = $.fieldValue(el, successful);
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+ continue;
+ }
+ v.constructor == Array ? $.merge(val, v) : val.push(v);
+ }
+ return val;
+};
+
+/**
+ * Returns the value of the field element.
+ */
+$.fieldValue = function(el, successful) {
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+ if (successful === undefined) {
+ successful = true;
+ }
+
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+ tag == 'select' && el.selectedIndex == -1)) {
+ return null;
+ }
+
+ if (tag == 'select') {
+ var index = el.selectedIndex;
+ if (index < 0) {
+ return null;
+ }
+ var a = [], ops = el.options;
+ var one = (t == 'select-one');
+ var max = (one ? index+1 : ops.length);
+ for(var i=(one ? index : 0); i < max; i++) {
+ var op = ops[i];
+ if (op.selected) {
+ var v = op.value;
+ if (!v) { // extra pain for IE...
+ v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
+ }
+ if (one) {
+ return v;
+ }
+ a.push(v);
+ }
+ }
+ return a;
+ }
+ return $(el).val();
+};
+
+/**
+ * Clears the form data. Takes the following actions on the form's input fields:
+ * - input text fields will have their 'value' property set to the empty string
+ * - select elements will have their 'selectedIndex' property set to -1
+ * - checkbox and radio inputs will have their 'checked' property set to false
+ * - inputs of type submit, button, reset, and hidden will *not* be effected
+ * - button elements will *not* be effected
+ */
+$.fn.clearForm = function() {
+ return this.each(function() {
+ $('input,select,textarea', this).clearFields();
+ });
+};
+
+/**
+ * Clears the selected form elements.
+ */
+$.fn.clearFields = $.fn.clearInputs = function() {
+ return this.each(function() {
+ var t = this.type, tag = this.tagName.toLowerCase();
+ if (t == 'text' || t == 'password' || tag == 'textarea') {
+ this.value = '';
+ }
+ else if (t == 'checkbox' || t == 'radio') {
+ this.checked = false;
+ }
+ else if (tag == 'select') {
+ this.selectedIndex = -1;
+ }
+ });
+};
+
+/**
+ * Resets the form data. Causes all form elements to be reset to their original value.
+ */
+$.fn.resetForm = function() {
+ return this.each(function() {
+ // guard against an input with the name of 'reset'
+ // note that IE reports the reset function as an 'object'
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+ this.reset();
+ }
+ });
+};
+
+/**
+ * Enables or disables any matching elements.
+ */
+$.fn.enable = function(b) {
+ if (b === undefined) {
+ b = true;
+ }
+ return this.each(function() {
+ this.disabled = !b;
+ });
+};
+
+/**
+ * Checks/unchecks any matching checkboxes or radio buttons and
+ * selects/deselects and matching option elements.
+ */
+$.fn.selected = function(select) {
+ if (select === undefined) {
+ select = true;
+ }
+ return this.each(function() {
+ var t = this.type;
+ if (t == 'checkbox' || t == 'radio') {
+ this.checked = select;
+ }
+ else if (this.tagName.toLowerCase() == 'option') {
+ var $sel = $(this).parent('select');
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
+ // deselect all other options
+ $sel.find('option').selected(false);
+ }
+ this.selected = select;
+ }
+ });
+};
+
+// helper fn for console logging
+// set $.fn.ajaxSubmit.debug to true to enable debug logging
+function log() {
+ if ($.fn.ajaxSubmit.debug) {
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ else if (window.opera && window.opera.postError) {
+ window.opera.postError(msg);
+ }
+ }
+};
+
+})(jQuery);
diff --git a/src/wp-includes/js/jquery/jquery.form.min.js b/src/wp-includes/js/jquery/jquery.form.min.js
new file mode 100644
index 0000000000..45ddd2f6c8
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.form.min.js
@@ -0,0 +1,11 @@
+/*!
+ * jQuery Form Plugin
+ * version: 2.73 (03-MAY-2011)
+ * @requires jQuery v1.3.2 or later
+ *
+ * Examples and documentation at: http://malsup.com/jquery/form/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+(function(b){b.fn.ajaxSubmit=function(t){if(!this.length){a("ajaxSubmit: skipping submit process - no element selected");return this}if(typeof t=="function"){t={success:t}}var h=this.attr("action");var d=(typeof h==="string")?b.trim(h):"";if(d){d=(d.match(/^([^#]+)/)||[])[1]}d=d||window.location.href||"";t=b.extend(true,{url:d,success:b.ajaxSettings.success,type:this[0].getAttribute("method")||"GET",iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},t);var u={};this.trigger("form-pre-serialize",[this,t,u]);if(u.veto){a("ajaxSubmit: submit vetoed via form-pre-serialize trigger");return this}if(t.beforeSerialize&&t.beforeSerialize(this,t)===false){a("ajaxSubmit: submit aborted via beforeSerialize callback");return this}var f,p,m=this.formToArray(t.semantic);if(t.data){t.extraData=t.data;for(f in t.data){if(t.data[f] instanceof Array){for(var i in t.data[f]){m.push({name:f,value:t.data[f][i]})}}else{p=t.data[f];p=b.isFunction(p)?p():p;m.push({name:f,value:p})}}}if(t.beforeSubmit&&t.beforeSubmit(m,this,t)===false){a("ajaxSubmit: submit aborted via beforeSubmit callback");return this}this.trigger("form-submit-validate",[m,this,t,u]);if(u.veto){a("ajaxSubmit: submit vetoed via form-submit-validate trigger");return this}var c=b.param(m);if(t.type.toUpperCase()=="GET"){t.url+=(t.url.indexOf("?")>=0?"&":"?")+c;t.data=null}else{t.data=c}var s=this,l=[];if(t.resetForm){l.push(function(){s.resetForm()})}if(t.clearForm){l.push(function(){s.clearForm()})}if(!t.dataType&&t.target){var r=t.success||function(){};l.push(function(n){var k=t.replaceTarget?"replaceWith":"html";b(t.target)[k](n).each(r,arguments)})}else{if(t.success){l.push(t.success)}}t.success=function(w,n,x){var v=t.context||t;for(var q=0,k=l.length;q<k;q++){l[q].apply(v,[w,n,x||s,s])}};var g=b("input:file",this).length>0;var e="multipart/form-data";var j=(s.attr("enctype")==e||s.attr("encoding")==e);if(t.iframe!==false&&(g||t.iframe||j)){if(t.closeKeepAlive){b.get(t.closeKeepAlive,o)}else{o()}}else{b.ajax(t)}this.trigger("form-submit-notify",[this,t]);return this;function o(){var v=s[0];if(b(":input[name=submit],:input[id=submit]",v).length){alert('Error: Form elements must not have name or id of "submit".');return}var D=b.extend(true,{},b.ajaxSettings,t);D.context=D.context||D;var G="jqFormIO"+(new Date().getTime()),A="_"+G;var x=b('<iframe id="'+G+'" name="'+G+'" src="'+D.iframeSrc+'" />');var B=x[0];x.css({position:"absolute",top:"-1000px",left:"-1000px"});var y={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(n){var O=(n==="timeout"?"timeout":"aborted");a("aborting upload... "+O);this.aborted=1;x.attr("src",D.iframeSrc);y.error=O;D.error&&D.error.call(D.context,y,O,O);K&&b.event.trigger("ajaxError",[y,D,O]);D.complete&&D.complete.call(D.context,y,O)}};var K=D.global;if(K&&!b.active++){b.event.trigger("ajaxStart")}if(K){b.event.trigger("ajaxSend",[y,D])}if(D.beforeSend&&D.beforeSend.call(D.context,y,D)===false){if(D.global){b.active--}return}if(y.aborted){return}var J=0,C;var z=v.clk;if(z){var H=z.name;if(H&&!z.disabled){D.extraData=D.extraData||{};D.extraData[H]=z.value;if(z.type=="image"){D.extraData[H+".x"]=v.clk_x;D.extraData[H+".y"]=v.clk_y}}}function I(){var Q=s.attr("target"),O=s.attr("action");v.setAttribute("target",G);if(v.getAttribute("method")!="POST"){v.setAttribute("method","POST")}if(v.getAttribute("action")!=D.url){v.setAttribute("action",D.url)}if(!D.skipEncodingOverride){s.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"})}if(D.timeout){C=setTimeout(function(){J=true;F(true)},D.timeout)}var P=[];try{if(D.extraData){for(var R in D.extraData){P.push(b('<input type="hidden" name="'+R+'" value="'+D.extraData[R]+'" />').appendTo(v)[0])}}x.appendTo("body");B.attachEvent?B.attachEvent("onload",F):B.addEventListener("load",F,false);v.submit()}finally{v.setAttribute("action",O);if(Q){v.setAttribute("target",Q)}else{s.removeAttr("target")}b(P).remove()}}if(D.forceSync){I()}else{setTimeout(I,10)}var M,N,L=50,w;function F(T){if(y.aborted||w){return}if(T===true&&y){y.abort("timeout");return}var S=B.contentWindow?B.contentWindow.document:B.contentDocument?B.contentDocument:B.document;if(!S||S.location.href==D.iframeSrc){if(!J){return}}B.detachEvent?B.detachEvent("onload",F):B.removeEventListener("load",F,false);var P=true;try{if(J){throw"timeout"}var U=D.dataType=="xml"||S.XMLDocument||b.isXMLDoc(S);a("isXml="+U);if(!U&&window.opera&&(S.body==null||S.body.innerHTML=="")){if(--L){a("requeing onLoad callback, DOM not available");setTimeout(F,250);return}}y.responseText=S.body?S.body.innerHTML:S.documentElement?S.documentElement.innerHTML:null;y.responseXML=S.XMLDocument?S.XMLDocument:S;if(U){D.dataType="xml"}y.getResponseHeader=function(W){var V={"content-type":D.dataType};return V[W]};var R=/(json|script|text)/.test(D.dataType);if(R||D.textarea){var O=S.getElementsByTagName("textarea")[0];if(O){y.responseText=O.value}else{if(R){var Q=S.getElementsByTagName("pre")[0];var n=S.getElementsByTagName("body")[0];if(Q){y.responseText=Q.textContent}else{if(n){y.responseText=n.innerHTML}}}}}else{if(D.dataType=="xml"&&!y.responseXML&&y.responseText!=null){y.responseXML=E(y.responseText)}}M=k(y,D.dataType,D)}catch(T){a("error caught:",T);P=false;y.error=T;D.error&&D.error.call(D.context,y,"error",T);K&&b.event.trigger("ajaxError",[y,D,T])}if(y.aborted){a("upload aborted");P=false}if(P){D.success&&D.success.call(D.context,M,"success",y);K&&b.event.trigger("ajaxSuccess",[y,D])}K&&b.event.trigger("ajaxComplete",[y,D]);if(K&&!--b.active){b.event.trigger("ajaxStop")}D.complete&&D.complete.call(D.context,y,P?"success":"error");w=true;if(D.timeout){clearTimeout(C)}setTimeout(function(){x.removeData("form-plugin-onload");x.remove();y.responseXML=null},100)}var E=b.parseXML||function(n,O){if(window.ActiveXObject){O=new ActiveXObject("Microsoft.XMLDOM");O.async="false";O.loadXML(n)}else{O=(new DOMParser()).parseFromString(n,"text/xml")}return(O&&O.documentElement&&O.documentElement.nodeName!="parsererror")?O:null};var q=b.parseJSON||function(n){return window["eval"]("("+n+")")};var k=function(S,Q,P){var O=S.getResponseHeader("content-type")||"",n=Q==="xml"||!Q&&O.indexOf("xml")>=0,R=n?S.responseXML:S.responseText;if(n&&R.documentElement.nodeName==="parsererror"){b.error&&b.error("parsererror")}if(P&&P.dataFilter){R=P.dataFilter(R,Q)}if(typeof R==="string"){if(Q==="json"||!Q&&O.indexOf("json")>=0){R=q(R)}else{if(Q==="script"||!Q&&O.indexOf("javascript")>=0){b.globalEval(R)}}}return R}}};b.fn.ajaxForm=function(c){if(this.length===0){var d={s:this.selector,c:this.context};if(!b.isReady&&d.s){a("DOM not ready, queuing ajaxForm");b(function(){b(d.s,d.c).ajaxForm(c)});return this}a("terminating; zero elements found by selector"+(b.isReady?"":" (DOM not ready)"));return this}return this.ajaxFormUnbind().bind("submit.form-plugin",function(f){if(!f.isDefaultPrevented()){f.preventDefault();b(this).ajaxSubmit(c)}}).bind("click.form-plugin",function(j){var i=j.target;var g=b(i);if(!(g.is(":submit,input:image"))){var f=g.closest(":submit");if(f.length==0){return}i=f[0]}var h=this;h.clk=i;if(i.type=="image"){if(j.offsetX!=undefined){h.clk_x=j.offsetX;h.clk_y=j.offsetY}else{if(typeof b.fn.offset=="function"){var k=g.offset();h.clk_x=j.pageX-k.left;h.clk_y=j.pageY-k.top}else{h.clk_x=j.pageX-i.offsetLeft;h.clk_y=j.pageY-i.offsetTop}}}setTimeout(function(){h.clk=h.clk_x=h.clk_y=null},100)})};b.fn.ajaxFormUnbind=function(){return this.unbind("submit.form-plugin click.form-plugin")};b.fn.formToArray=function(q){var p=[];if(this.length===0){return p}var d=this[0];var g=q?d.getElementsByTagName("*"):d.elements;if(!g){return p}var k,h,f,r,e,m,c;for(k=0,m=g.length;k<m;k++){e=g[k];f=e.name;if(!f){continue}if(q&&d.clk&&e.type=="image"){if(!e.disabled&&d.clk==e){p.push({name:f,value:b(e).val()});p.push({name:f+".x",value:d.clk_x},{name:f+".y",value:d.clk_y})}continue}r=b.fieldValue(e,true);if(r&&r.constructor==Array){for(h=0,c=r.length;h<c;h++){p.push({name:f,value:r[h]})}}else{if(r!==null&&typeof r!="undefined"){p.push({name:f,value:r})}}}if(!q&&d.clk){var l=b(d.clk),o=l[0];f=o.name;if(f&&!o.disabled&&o.type=="image"){p.push({name:f,value:l.val()});p.push({name:f+".x",value:d.clk_x},{name:f+".y",value:d.clk_y})}}return p};b.fn.formSerialize=function(c){return b.param(this.formToArray(c))};b.fn.fieldSerialize=function(d){var c=[];this.each(function(){var h=this.name;if(!h){return}var f=b.fieldValue(this,d);if(f&&f.constructor==Array){for(var g=0,e=f.length;g<e;g++){c.push({name:h,value:f[g]})}}else{if(f!==null&&typeof f!="undefined"){c.push({name:this.name,value:f})}}});return b.param(c)};b.fn.fieldValue=function(h){for(var g=[],e=0,c=this.length;e<c;e++){var f=this[e];var d=b.fieldValue(f,h);if(d===null||typeof d=="undefined"||(d.constructor==Array&&!d.length)){continue}d.constructor==Array?b.merge(g,d):g.push(d)}return g};b.fieldValue=function(c,j){var e=c.name,p=c.type,q=c.tagName.toLowerCase();if(j===undefined){j=true}if(j&&(!e||c.disabled||p=="reset"||p=="button"||(p=="checkbox"||p=="radio")&&!c.checked||(p=="submit"||p=="image")&&c.form&&c.form.clk!=c||q=="select"&&c.selectedIndex==-1)){return null}if(q=="select"){var k=c.selectedIndex;if(k<0){return null}var m=[],d=c.options;var g=(p=="select-one");var l=(g?k+1:d.length);for(var f=(g?k:0);f<l;f++){var h=d[f];if(h.selected){var o=h.value;if(!o){o=(h.attributes&&h.attributes.value&&!(h.attributes.value.specified))?h.text:h.value}if(g){return o}m.push(o)}}return m}return b(c).val()};b.fn.clearForm=function(){return this.each(function(){b("input,select,textarea",this).clearFields()})};b.fn.clearFields=b.fn.clearInputs=function(){return this.each(function(){var d=this.type,c=this.tagName.toLowerCase();if(d=="text"||d=="password"||c=="textarea"){this.value=""}else{if(d=="checkbox"||d=="radio"){this.checked=false}else{if(c=="select"){this.selectedIndex=-1}}}})};b.fn.resetForm=function(){return this.each(function(){if(typeof this.reset=="function"||(typeof this.reset=="object"&&!this.reset.nodeType)){this.reset()}})};b.fn.enable=function(c){if(c===undefined){c=true}return this.each(function(){this.disabled=!c})};b.fn.selected=function(c){if(c===undefined){c=true}return this.each(function(){var d=this.type;if(d=="checkbox"||d=="radio"){this.checked=c}else{if(this.tagName.toLowerCase()=="option"){var e=b(this).parent("select");if(c&&e[0]&&e[0].type=="select-one"){e.find("option").selected(false)}this.selected=c}}})};function a(){if(b.fn.ajaxSubmit.debug){var c="[jquery.form] "+Array.prototype.join.call(arguments,"");if(window.console&&window.console.log){window.console.log(c)}else{if(window.opera&&window.opera.postError){window.opera.postError(c)}}}}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.hotkeys.js b/src/wp-includes/js/jquery/jquery.hotkeys.js
new file mode 100644
index 0000000000..85fa1ffcb9
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.hotkeys.js
@@ -0,0 +1,131 @@
+/******************************************************************************************************************************
+
+ * @ Original idea by by Binny V A, Original version: 2.00.A
+ * @ http://www.openjs.com/scripts/events/keyboard_shortcuts/
+ * @ Original License : BSD
+
+ * @ jQuery Plugin by Tzury Bar Yochay
+ mail: tzury.by@gmail.com
+ blog: evalinux.wordpress.com
+ face: facebook.com/profile.php?id=513676303
+
+ (c) Copyrights 2007
+
+ * @ jQuery Plugin version Beta (0.0.2)
+ * @ License: jQuery-License.
+
+TODO:
+ add queue support (as in gmail) e.g. 'x' then 'y', etc.
+ add mouse + mouse wheel events.
+
+USAGE:
+ $.hotkeys.add('Ctrl+c', function(){ alert('copy anyone?');});
+ $.hotkeys.add('Ctrl+c', {target:'div#editor', type:'keyup', propagate: true},function(){ alert('copy anyone?');});>
+ $.hotkeys.remove('Ctrl+c');
+ $.hotkeys.remove('Ctrl+c', {target:'div#editor', type:'keypress'});
+
+******************************************************************************************************************************/
+(function (jQuery){
+ this.version = '(beta)(0.0.3)';
+ this.all = {};
+ this.special_keys = {
+ 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll', 20: 'capslock',
+ 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',35:'end', 33: 'pageup',
+ 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down', 112:'f1',113:'f2', 114:'f3',
+ 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8', 120:'f9', 121:'f10', 122:'f11', 123:'f12'};
+
+ this.shift_nums = { "`":"~", "1":"!", "2":"@", "3":"#", "4":"$", "5":"%", "6":"^", "7":"&",
+ "8":"*", "9":"(", "0":")", "-":"_", "=":"+", ";":":", "'":"\"", ",":"<",
+ ".":">", "/":"?", "\\":"|" };
+
+ this.add = function(combi, options, callback) {
+ if (jQuery.isFunction(options)){
+ callback = options;
+ options = {};
+ }
+ var opt = {},
+ defaults = {type: 'keydown', propagate: false, disableInInput: false, target: jQuery('html')[0]},
+ that = this;
+ opt = jQuery.extend( opt , defaults, options || {} );
+ combi = combi.toLowerCase();
+
+ // inspect if keystroke matches
+ var inspector = function(event) {
+ // WP: not needed with newer jQuery
+ // event = jQuery.event.fix(event); // jQuery event normalization.
+ var element = event.target;
+ // @ TextNode -> nodeType == 3
+ // WP: not needed with newer jQuery
+ // element = (element.nodeType==3) ? element.parentNode : element;
+
+ if(opt['disableInInput']) { // Disable shortcut keys in Input, Textarea fields
+ var target = jQuery(element);
+ if( target.is("input") || target.is("textarea")){
+ return;
+ }
+ }
+ var code = event.which,
+ type = event.type,
+ character = String.fromCharCode(code).toLowerCase(),
+ special = that.special_keys[code],
+ shift = event.shiftKey,
+ ctrl = event.ctrlKey,
+ alt= event.altKey,
+ meta = event.metaKey,
+ propagate = true, // default behaivour
+ mapPoint = null;
+
+ // in opera + safari, the event.target is unpredictable.
+ // for example: 'keydown' might be associated with HtmlBodyElement
+ // or the element where you last clicked with your mouse.
+ // WP: needed for all browsers
+ // if (jQuery.browser.opera || jQuery.browser.safari){
+ while (!that.all[element] && element.parentNode){
+ element = element.parentNode;
+ }
+ // }
+ var cbMap = that.all[element].events[type].callbackMap;
+ if(!shift && !ctrl && !alt && !meta) { // No Modifiers
+ mapPoint = cbMap[special] || cbMap[character]
+ }
+ // deals with combinaitons (alt|ctrl|shift+anything)
+ else{
+ var modif = '';
+ if(alt) modif +='alt+';
+ if(ctrl) modif+= 'ctrl+';
+ if(shift) modif += 'shift+';
+ if(meta) modif += 'meta+';
+ // modifiers + special keys or modifiers + characters or modifiers + shift characters
+ mapPoint = cbMap[modif+special] || cbMap[modif+character] || cbMap[modif+that.shift_nums[character]]
+ }
+ if (mapPoint){
+ mapPoint.cb(event);
+ if(!mapPoint.propagate) {
+ event.stopPropagation();
+ event.preventDefault();
+ return false;
+ }
+ }
+ };
+ // first hook for this element
+ if (!this.all[opt.target]){
+ this.all[opt.target] = {events:{}};
+ }
+ if (!this.all[opt.target].events[opt.type]){
+ this.all[opt.target].events[opt.type] = {callbackMap: {}}
+ jQuery.event.add(opt.target, opt.type, inspector);
+ }
+ this.all[opt.target].events[opt.type].callbackMap[combi] = {cb: callback, propagate:opt.propagate};
+ return jQuery;
+ };
+ this.remove = function(exp, opt) {
+ opt = opt || {};
+ target = opt.target || jQuery('html')[0];
+ type = opt.type || 'keydown';
+ exp = exp.toLowerCase();
+ delete this.all[target].events[type].callbackMap[exp]
+ return jQuery;
+ };
+ jQuery.hotkeys = this;
+ return jQuery;
+})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.hotkeys.min.js b/src/wp-includes/js/jquery/jquery.hotkeys.min.js
new file mode 100644
index 0000000000..3c2f66aa62
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.hotkeys.min.js
@@ -0,0 +1 @@
+(function(a){this.version="(beta)(0.0.3)";this.all={};this.special_keys={27:"esc",9:"tab",32:"space",13:"return",8:"backspace",145:"scroll",20:"capslock",144:"numlock",19:"pause",45:"insert",36:"home",46:"del",35:"end",33:"pageup",34:"pagedown",37:"left",38:"up",39:"right",40:"down",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12"};this.shift_nums={"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":":","'":'"',",":"<",".":">","/":"?","\\":"|"};this.add=function(c,b,h){if(a.isFunction(b)){h=b;b={}}var d={},f={type:"keydown",propagate:false,disableInInput:false,target:a("html")[0]},e=this;d=a.extend(d,f,b||{});c=c.toLowerCase();var g=function(j){var o=j.target;if(d.disableInInput){var s=a(o);if(s.is("input")||s.is("textarea")){return}}var l=j.which,u=j.type,r=String.fromCharCode(l).toLowerCase(),t=e.special_keys[l],m=j.shiftKey,i=j.ctrlKey,p=j.altKey,w=j.metaKey,q=true,k=null;while(!e.all[o]&&o.parentNode){o=o.parentNode}var v=e.all[o].events[u].callbackMap;if(!m&&!i&&!p&&!w){k=v[t]||v[r]}else{var n="";if(p){n+="alt+"}if(i){n+="ctrl+"}if(m){n+="shift+"}if(w){n+="meta+"}k=v[n+t]||v[n+r]||v[n+e.shift_nums[r]]}if(k){k.cb(j);if(!k.propagate){j.stopPropagation();j.preventDefault();return false}}};if(!this.all[d.target]){this.all[d.target]={events:{}}}if(!this.all[d.target].events[d.type]){this.all[d.target].events[d.type]={callbackMap:{}};a.event.add(d.target,d.type,g)}this.all[d.target].events[d.type].callbackMap[c]={cb:h,propagate:d.propagate};return a};this.remove=function(c,b){b=b||{};target=b.target||a("html")[0];type=b.type||"keydown";c=c.toLowerCase();delete this.all[target].events[type].callbackMap[c];return a};a.hotkeys=this;return a})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.js b/src/wp-includes/js/jquery/jquery.js
new file mode 100644
index 0000000000..40c1aa1009
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.js
@@ -0,0 +1,7 @@
+/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-1.10.2.min.map
+*/
+(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
+}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
+u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window);
+jQuery.noConflict();
diff --git a/src/wp-includes/js/jquery/jquery.masonry.min.js b/src/wp-includes/js/jquery/jquery.masonry.min.js
new file mode 100644
index 0000000000..67be98867b
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.masonry.min.js
@@ -0,0 +1,10 @@
+/**
+ * jQuery Masonry v2.1.05
+ * A dynamic layout plugin for jQuery
+ * The flip-side of CSS Floats
+ * http://masonry.desandro.com
+ *
+ * Licensed under the MIT license.
+ * Copyright 2012 David DeSandro
+ */
+(function(a,b,c){"use strict";var d=b.event,e;d.special.smartresize={setup:function(){b(this).bind("resize",d.special.smartresize.handler)},teardown:function(){b(this).unbind("resize",d.special.smartresize.handler)},handler:function(a,c){var d=this,f=arguments;a.type="smartresize",e&&clearTimeout(e),e=setTimeout(function(){b.event.handle.apply(d,f)},c==="execAsap"?0:100)}},b.fn.smartresize=function(a){return a?this.bind("smartresize",a):this.trigger("smartresize",["execAsap"])},b.Mason=function(a,c){this.element=b(c),this._create(a),this._init()},b.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},b.Mason.prototype={_filterFindBricks:function(a){var b=this.options.itemSelector;return b?a.filter(b).add(a.find(b)):a},_getBricks:function(a){var b=this._filterFindBricks(a).css({position:"absolute"}).addClass("masonry-brick");return b},_create:function(c){this.options=b.extend(!0,{},b.Mason.settings,c),this.styleQueue=[];var d=this.element[0].style;this.originalStyle={height:d.height||""};var e=this.options.containerStyle;for(var f in e)this.originalStyle[f]=d[f]||"";this.element.css(e),this.horizontalDirection=this.options.isRTL?"right":"left",this.offset={x:parseInt(this.element.css("padding-"+this.horizontalDirection),10),y:parseInt(this.element.css("padding-top"),10)},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var g=this;setTimeout(function(){g.element.addClass("masonry")},0),this.options.isResizable&&b(a).bind("smartresize.masonry",function(){g.resize()}),this.reloadItems()},_init:function(a){this._getColumns(),this._reLayout(a)},option:function(a,c){b.isPlainObject(a)&&(this.options=b.extend(!0,this.options,a))},layout:function(a,b){for(var c=0,d=a.length;c<d;c++)this._placeBrick(a[c]);var e={};e.height=Math.max.apply(Math,this.colYs);if(this.options.isFitWidth){var f=0;c=this.cols;while(--c){if(this.colYs[c]!==0)break;f++}e.width=(this.cols-f)*this.columnWidth-this.options.gutterWidth}this.styleQueue.push({$el:this.element,style:e});var g=this.isLaidOut?this.options.isAnimated?"animate":"css":"css",h=this.options.animationOptions,i;for(c=0,d=this.styleQueue.length;c<d;c++)i=this.styleQueue[c],i.$el[g](i.style,h);this.styleQueue=[],b&&b.call(a),this.isLaidOut=!0},_getColumns:function(){var a=this.options.isFitWidth?this.element.parent():this.element,b=a.width();this.columnWidth=this.isFluid?this.options.columnWidth(b):this.options.columnWidth||this.$bricks.outerWidth(!0)||b,this.columnWidth+=this.options.gutterWidth,this.cols=Math.floor((b+this.options.gutterWidth)/this.columnWidth),this.cols=Math.max(this.cols,1)},_placeBrick:function(a){var c=b(a),d,e,f,g,h;d=Math.ceil(c.outerWidth(!0)/this.columnWidth),d=Math.min(d,this.cols);if(d===1)f=this.colYs;else{e=this.cols+1-d,f=[];for(h=0;h<e;h++)g=this.colYs.slice(h,h+d),f[h]=Math.max.apply(Math,g)}var i=Math.min.apply(Math,f),j=0;for(var k=0,l=f.length;k<l;k++)if(f[k]===i){j=k;break}var m={top:i+this.offset.y};m[this.horizontalDirection]=this.columnWidth*j+this.offset.x,this.styleQueue.push({$el:c,style:m});var n=i+c.outerHeight(!0),o=this.cols+1-l;for(k=0;k<o;k++)this.colYs[j+k]=n},resize:function(){var a=this.cols;this._getColumns(),(this.isFluid||this.cols!==a)&&this._reLayout()},_reLayout:function(a){var b=this.cols;this.colYs=[];while(b--)this.colYs.push(0);this.layout(this.$bricks,a)},reloadItems:function(){this.$bricks=this._getBricks(this.element.children())},reload:function(a){this.reloadItems(),this._init(a)},appended:function(a,b,c){if(b){this._filterFindBricks(a).css({top:this.element.height()});var d=this;setTimeout(function(){d._appended(a,c)},1)}else this._appended(a,c)},_appended:function(a,b){var c=this._getBricks(a);this.$bricks=this.$bricks.add(c),this.layout(c,b)},remove:function(a){this.$bricks=this.$bricks.not(a),a.remove()},destroy:function(){this.$bricks.removeClass("masonry-brick").each(function(){this.style.position="",this.style.top="",this.style.left=""});var c=this.element[0].style;for(var d in this.originalStyle)c[d]=this.originalStyle[d];this.element.unbind(".masonry").removeClass("masonry").removeData("masonry"),b(a).unbind(".masonry")}},b.fn.imagesLoaded=function(a){function h(){a.call(c,d)}function i(a){var c=a.target;c.src!==f&&b.inArray(c,g)===-1&&(g.push(c),--e<=0&&(setTimeout(h),d.unbind(".imagesLoaded",i)))}var c=this,d=c.find("img").add(c.filter("img")),e=d.length,f="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",g=[];return e||h(),d.bind("load.imagesLoaded error.imagesLoaded",i).each(function(){var a=this.src;this.src=f,this.src=a}),c};var f=function(b){a.console&&a.console.error(b)};b.fn.masonry=function(a){if(typeof a=="string"){var c=Array.prototype.slice.call(arguments,1);this.each(function(){var d=b.data(this,"masonry");if(!d){f("cannot call methods on masonry prior to initialization; attempted to call method '"+a+"'");return}if(!b.isFunction(d[a])||a.charAt(0)==="_"){f("no such method '"+a+"' for masonry instance");return}d[a].apply(d,c)})}else this.each(function(){var c=b.data(this,"masonry");c?(c.option(a||{}),c._init()):b.data(this,"masonry",new b.Mason(a,this))});return this}})(window,jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.query.js b/src/wp-includes/js/jquery/jquery.query.js
new file mode 100644
index 0000000000..ea5801ff2b
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.query.js
@@ -0,0 +1,11 @@
+/**
+ * jQuery.query - Query String Modification and Creation for jQuery
+ * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
+ * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
+ * Date: 2009/8/13
+ *
+ * @author Blair Mitchelmore
+ * @version 2.1.7
+ *
+ **/
+new function(e){var d=e.separator||"&";var c=e.spaces===false?false:true;var a=e.suffix===false?"":"[]";var g=e.prefix===false?false:true;var b=g?e.hash===true?"#":"?":"";var f=e.numbers===false?false:true;jQuery.query=new function(){var h=function(m,l){return m!=undefined&&m!==null&&(!!l?m.constructor==l:true)};var i=function(r){var l,q=/\[([^[]*)\]/g,n=/^([^[]+)(\[.*\])?$/.exec(r),o=n[1],p=[];while(l=q.exec(n[2])){p.push(l[1])}return[o,p]};var k=function(s,r,q){var t,p=r.shift();if(typeof s!="object"){s=null}if(p===""){if(!s){s=[]}if(h(s,Array)){s.push(r.length==0?q:k(null,r.slice(0),q))}else{if(h(s,Object)){var n=0;while(s[n++]!=null){}s[--n]=r.length==0?q:k(s[n],r.slice(0),q)}else{s=[];s.push(r.length==0?q:k(null,r.slice(0),q))}}}else{if(p&&p.match(/^\s*[0-9]+\s*$/)){var m=parseInt(p,10);if(!s){s=[]}s[m]=r.length==0?q:k(s[m],r.slice(0),q)}else{if(p){var m=p.replace(/^\s*|\s*$/g,"");if(!s){s={}}if(h(s,Array)){var l={};for(var n=0;n<s.length;++n){l[n]=s[n]}s=l}s[m]=r.length==0?q:k(s[m],r.slice(0),q)}else{return q}}}return s};var j=function(l){var m=this;m.keys={};if(l.queryObject){jQuery.each(l.get(),function(n,o){m.SET(n,o)})}else{jQuery.each(arguments,function(){var n=""+this;n=n.replace(/^[?#]/,"");n=n.replace(/[;&]$/,"");if(c){n=n.replace(/[+]/g," ")}jQuery.each(n.split(/[&;]/),function(){var o=decodeURIComponent(this.split("=")[0]||"");var p=decodeURIComponent(this.split("=")[1]||"");if(!o){return}if(f){if(/^[+-]?[0-9]+\.[0-9]*$/.test(p)){p=parseFloat(p)}else{if(/^[+-]?[0-9]+$/.test(p)){p=parseInt(p,10)}}}p=(!p&&p!==0)?true:p;if(p!==false&&p!==true&&typeof p!="number"){p=p}m.SET(o,p)})})}return m};j.prototype={queryObject:true,has:function(l,m){var n=this.get(l);return h(n,m)},GET:function(m){if(!h(m)){return this.keys}var l=i(m),n=l[0],p=l[1];var o=this.keys[n];while(o!=null&&p.length!=0){o=o[p.shift()]}return typeof o=="number"?o:o||""},get:function(l){var m=this.GET(l);if(h(m,Object)){return jQuery.extend(true,{},m)}else{if(h(m,Array)){return m.slice(0)}}return m},SET:function(m,r){var o=!h(r)?null:r;var l=i(m),n=l[0],q=l[1];var p=this.keys[n];this.keys[n]=k(p,q.slice(0),o);return this},set:function(l,m){return this.copy().SET(l,m)},REMOVE:function(l){return this.SET(l,null).COMPACT()},remove:function(l){return this.copy().REMOVE(l)},EMPTY:function(){var l=this;jQuery.each(l.keys,function(m,n){delete l.keys[m]});return l},load:function(l){var n=l.replace(/^.*?[#](.+?)(?:\?.+)?$/,"$1");var m=l.replace(/^.*?[?](.+?)(?:#.+)?$/,"$1");return new j(l.length==m.length?"":m,l.length==n.length?"":n)},empty:function(){return this.copy().EMPTY()},copy:function(){return new j(this)},COMPACT:function(){function l(o){var n=typeof o=="object"?h(o,Array)?[]:{}:o;if(typeof o=="object"){function m(r,p,q){if(h(r,Array)){r.push(q)}else{r[p]=q}}jQuery.each(o,function(p,q){if(!h(q)){return true}m(n,p,l(q))})}return n}this.keys=l(this.keys);return this},compact:function(){return this.copy().COMPACT()},toString:function(){var n=0,r=[],q=[],m=this;var o=function(s){s=s+"";if(c){s=s.replace(/ /g,"+")}return encodeURIComponent(s)};var l=function(s,t,u){if(!h(u)||u===false){return}var v=[o(t)];if(u!==true){v.push("=");v.push(o(u))}s.push(v.join(""))};var p=function(t,s){var u=function(v){return !s||s==""?[v].join(""):[s,"[",v,"]"].join("")};jQuery.each(t,function(v,w){if(typeof w=="object"){p(w,u(v))}else{l(q,u(v),w)}})};p(this.keys);if(q.length>0){r.push(b)}r.push(q.join(d));return r.join("")}};return new j(location.search,location.hash)}}(jQuery.query||{});
diff --git a/src/wp-includes/js/jquery/jquery.schedule.js b/src/wp-includes/js/jquery/jquery.schedule.js
new file mode 100644
index 0000000000..f00e7b39e5
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.schedule.js
@@ -0,0 +1,36 @@
+
+(function($){$.scheduler=function(){this.bucket={};return;};$.scheduler.prototype={schedule:function(){var ctx={"id":null,"time":1000,"repeat":false,"protect":false,"obj":null,"func":function(){},"args":[]};function _isfn(fn){return(!!fn&&typeof fn!="string"&&typeof fn[0]=="undefined"&&RegExp("function","i").test(fn+""));};var i=0;var override=false;if(typeof arguments[i]=="object"&&arguments.length>1){override=true;i++;}
+if(typeof arguments[i]=="object"){for(var option in arguments[i])
+if(typeof ctx[option]!="undefined")
+ctx[option]=arguments[i][option];i++;}
+if(typeof arguments[i]=="number"||(typeof arguments[i]=="string"&&arguments[i].match(RegExp("^[0-9]+[smhdw]$"))))
+ctx["time"]=arguments[i++];if(typeof arguments[i]=="boolean")
+ctx["repeat"]=arguments[i++];if(typeof arguments[i]=="boolean")
+ctx["protect"]=arguments[i++];if(typeof arguments[i]=="object"&&typeof arguments[i+1]=="string"&&_isfn(arguments[i][arguments[i+1]])){ctx["obj"]=arguments[i++];ctx["func"]=arguments[i++];}
+else if(typeof arguments[i]!="undefined"&&(_isfn(arguments[i])||typeof arguments[i]=="string"))
+ctx["func"]=arguments[i++];while(typeof arguments[i]!="undefined")
+ctx["args"].push(arguments[i++]);if(override){if(typeof arguments[1]=="object"){for(var option in arguments[0])
+if(typeof ctx[option]!="undefined"&&typeof arguments[1][option]=="undefined")
+ctx[option]=arguments[0][option];}
+else{for(var option in arguments[0])
+if(typeof ctx[option]!="undefined")
+ctx[option]=arguments[0][option];}
+i++;}
+ctx["_scheduler"]=this;ctx["_handle"]=null;var match=String(ctx["time"]).match(RegExp("^([0-9]+)([smhdw])$"));if(match&&match[0]!="undefined"&&match[1]!="undefined")
+ctx["time"]=String(parseInt(match[1])*{s:1000,m:1000*60,h:1000*60*60,d:1000*60*60*24,w:1000*60*60*24*7}[match[2]]);if(ctx["id"]==null)
+ctx["id"]=(String(ctx["repeat"])+":"
++String(ctx["protect"])+":"
++String(ctx["time"])+":"
++String(ctx["obj"])+":"
++String(ctx["func"])+":"
++String(ctx["args"]));if(ctx["protect"])
+if(typeof this.bucket[ctx["id"]]!="undefined")
+return this.bucket[ctx["id"]];if(!_isfn(ctx["func"])){if(ctx["obj"]!=null&&typeof ctx["obj"]=="object"&&typeof ctx["func"]=="string"&&_isfn(ctx["obj"][ctx["func"]]))
+ctx["func"]=ctx["obj"][ctx["func"]];else
+ctx["func"]=eval("function () { "+ctx["func"]+" }");}
+ctx["_handle"]=this._schedule(ctx);this.bucket[ctx["id"]]=ctx;return ctx;},reschedule:function(ctx){if(typeof ctx=="string")
+ctx=this.bucket[ctx];ctx["_handle"]=this._schedule(ctx);return ctx;},_schedule:function(ctx){var trampoline=function(){var obj=(ctx["obj"]!=null?ctx["obj"]:ctx);(ctx["func"]).apply(obj,ctx["args"]);if(typeof(ctx["_scheduler"]).bucket[ctx["id"]]!="undefined"&&ctx["repeat"])
+(ctx["_scheduler"])._schedule(ctx);else
+delete(ctx["_scheduler"]).bucket[ctx["id"]];};return setTimeout(trampoline,ctx["time"]);},cancel:function(ctx){if(typeof ctx=="string")
+ctx=this.bucket[ctx];if(typeof ctx=="object"){clearTimeout(ctx["_handle"]);delete this.bucket[ctx["id"]];}}};$.extend({scheduler$:new $.scheduler(),schedule:function(){return $.scheduler$.schedule.apply($.scheduler$,arguments)},reschedule:function(){return $.scheduler$.reschedule.apply($.scheduler$,arguments)},cancel:function(){return $.scheduler$.cancel.apply($.scheduler$,arguments)}});$.fn.extend({schedule:function(){var a=[{}];for(var i=0;i<arguments.length;i++)
+a.push(arguments[i]);return this.each(function(){a[0]={"id":this,"obj":this};return $.schedule.apply($,a);});}});})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.serialize-object.js b/src/wp-includes/js/jquery/jquery.serialize-object.js
new file mode 100644
index 0000000000..03b905bf5b
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.serialize-object.js
@@ -0,0 +1,31 @@
+/*!
+ * jQuery serializeObject - v0.2 - 1/20/2010
+ * http://benalman.com/projects/jquery-misc-plugins/
+ *
+ * Copyright (c) 2010 "Cowboy" Ben Alman
+ * Dual licensed under the MIT and GPL licenses.
+ * http://benalman.com/about/license/
+ */
+
+// Whereas .serializeArray() serializes a form into an array, .serializeObject()
+// serializes a form into an (arguably more useful) object.
+
+(function($,undefined){
+ '$:nomunge'; // Used by YUI compressor.
+
+ $.fn.serializeObject = function(){
+ var obj = {};
+
+ $.each( this.serializeArray(), function(i,o){
+ var n = o.name,
+ v = o.value;
+
+ obj[n] = obj[n] === undefined ? v
+ : $.isArray( obj[n] ) ? obj[n].concat( v )
+ : [ obj[n], v ];
+ });
+
+ return obj;
+ };
+
+})(jQuery);
diff --git a/src/wp-includes/js/jquery/jquery.table-hotkeys.js b/src/wp-includes/js/jquery/jquery.table-hotkeys.js
new file mode 100644
index 0000000000..f8b17602e3
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.table-hotkeys.js
@@ -0,0 +1,99 @@
+(function($){
+ $.fn.filter_visible = function(depth) {
+ depth = depth || 3;
+ var is_visible = function() {
+ var p = $(this), i;
+ for(i=0; i<depth-1; ++i) {
+ if (!p.is(':visible')) return false;
+ p = p.parent();
+ }
+ return true;
+ }
+ return this.filter(is_visible);
+ };
+ $.table_hotkeys = function(table, keys, opts) {
+ opts = $.extend($.table_hotkeys.defaults, opts);
+ var selected_class, destructive_class, set_current_row, adjacent_row_callback, get_adjacent_row, adjacent_row, prev_row, next_row, check, get_first_row, get_last_row, make_key_callback, first_row;
+
+ selected_class = opts.class_prefix + opts.selected_suffix;
+ destructive_class = opts.class_prefix + opts.destructive_suffix
+ set_current_row = function (tr) {
+ if ($.table_hotkeys.current_row) $.table_hotkeys.current_row.removeClass(selected_class);
+ tr.addClass(selected_class);
+ tr[0].scrollIntoView(false);
+ $.table_hotkeys.current_row = tr;
+ };
+ adjacent_row_callback = function(which) {
+ if (!adjacent_row(which) && $.isFunction(opts[which+'_page_link_cb'])) {
+ opts[which+'_page_link_cb']();
+ }
+ };
+ get_adjacent_row = function(which) {
+ var first_row, method;
+
+ if (!$.table_hotkeys.current_row) {
+ first_row = get_first_row();
+ $.table_hotkeys.current_row = first_row;
+ return first_row[0];
+ }
+ method = 'prev' == which? $.fn.prevAll : $.fn.nextAll;
+ return method.call($.table_hotkeys.current_row, opts.cycle_expr).filter_visible()[0];
+ };
+ adjacent_row = function(which) {
+ var adj = get_adjacent_row(which);
+ if (!adj) return false;
+ set_current_row($(adj));
+ return true;
+ };
+ prev_row = function() { return adjacent_row('prev'); };
+ next_row = function() { return adjacent_row('next'); };
+ check = function() {
+ $(opts.checkbox_expr, $.table_hotkeys.current_row).each(function() {
+ this.checked = !this.checked;
+ });
+ };
+ get_first_row = function() {
+ return $(opts.cycle_expr, table).filter_visible().eq(opts.start_row_index);
+ };
+ get_last_row = function() {
+ var rows = $(opts.cycle_expr, table).filter_visible();
+ return rows.eq(rows.length-1);
+ };
+ make_key_callback = function(expr) {
+ return function() {
+ if ( null == $.table_hotkeys.current_row ) return false;
+ var clickable = $(expr, $.table_hotkeys.current_row);
+ if (!clickable.length) return false;
+ if (clickable.is('.'+destructive_class)) next_row() || prev_row();
+ clickable.click();
+ }
+ };
+ first_row = get_first_row();
+ if (!first_row.length) return;
+ if (opts.highlight_first)
+ set_current_row(first_row);
+ else if (opts.highlight_last)
+ set_current_row(get_last_row());
+ $.hotkeys.add(opts.prev_key, opts.hotkeys_opts, function() {return adjacent_row_callback('prev')});
+ $.hotkeys.add(opts.next_key, opts.hotkeys_opts, function() {return adjacent_row_callback('next')});
+ $.hotkeys.add(opts.mark_key, opts.hotkeys_opts, check);
+ $.each(keys, function() {
+ var callback, key;
+
+ if ($.isFunction(this[1])) {
+ callback = this[1];
+ key = this[0];
+ $.hotkeys.add(key, opts.hotkeys_opts, function(event) { return callback(event, $.table_hotkeys.current_row); });
+ } else {
+ key = this;
+ $.hotkeys.add(key, opts.hotkeys_opts, make_key_callback('.'+opts.class_prefix+key));
+ }
+ });
+
+ };
+ $.table_hotkeys.current_row = null;
+ $.table_hotkeys.defaults = {cycle_expr: 'tr', class_prefix: 'vim-', selected_suffix: 'current',
+ destructive_suffix: 'destructive', hotkeys_opts: {disableInInput: true, type: 'keypress'},
+ checkbox_expr: ':checkbox', next_key: 'j', prev_key: 'k', mark_key: 'x',
+ start_row_index: 2, highlight_first: false, highlight_last: false, next_page_link_cb: false, prev_page_link_cb: false};
+})(jQuery);
diff --git a/src/wp-includes/js/jquery/jquery.table-hotkeys.min.js b/src/wp-includes/js/jquery/jquery.table-hotkeys.min.js
new file mode 100644
index 0000000000..b4aa238ebb
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.table-hotkeys.min.js
@@ -0,0 +1 @@
+(function(a){a.fn.filter_visible=function(c){c=c||3;var b=function(){var e=a(this),d;for(d=0;d<c-1;++d){if(!e.is(":visible")){return false}e=e.parent()}return true};return this.filter(b)};a.table_hotkeys=function(p,q,b){b=a.extend(a.table_hotkeys.defaults,b);var i,l,e,f,m,d,k,o,c,h,g,n,j;i=b.class_prefix+b.selected_suffix;l=b.class_prefix+b.destructive_suffix;e=function(r){if(a.table_hotkeys.current_row){a.table_hotkeys.current_row.removeClass(i)}r.addClass(i);r[0].scrollIntoView(false);a.table_hotkeys.current_row=r};f=function(r){if(!d(r)&&a.isFunction(b[r+"_page_link_cb"])){b[r+"_page_link_cb"]()}};m=function(s){var r,t;if(!a.table_hotkeys.current_row){r=h();a.table_hotkeys.current_row=r;return r[0]}t="prev"==s?a.fn.prevAll:a.fn.nextAll;return t.call(a.table_hotkeys.current_row,b.cycle_expr).filter_visible()[0]};d=function(s){var r=m(s);if(!r){return false}e(a(r));return true};k=function(){return d("prev")};o=function(){return d("next")};c=function(){a(b.checkbox_expr,a.table_hotkeys.current_row).each(function(){this.checked=!this.checked})};h=function(){return a(b.cycle_expr,p).filter_visible().eq(b.start_row_index)};g=function(){var r=a(b.cycle_expr,p).filter_visible();return r.eq(r.length-1)};n=function(r){return function(){if(null==a.table_hotkeys.current_row){return false}var s=a(r,a.table_hotkeys.current_row);if(!s.length){return false}if(s.is("."+l)){o()||k()}s.click()}};j=h();if(!j.length){return}if(b.highlight_first){e(j)}else{if(b.highlight_last){e(g())}}a.hotkeys.add(b.prev_key,b.hotkeys_opts,function(){return f("prev")});a.hotkeys.add(b.next_key,b.hotkeys_opts,function(){return f("next")});a.hotkeys.add(b.mark_key,b.hotkeys_opts,c);a.each(q,function(){var s,r;if(a.isFunction(this[1])){s=this[1];r=this[0];a.hotkeys.add(r,b.hotkeys_opts,function(t){return s(t,a.table_hotkeys.current_row)})}else{r=this;a.hotkeys.add(r,b.hotkeys_opts,n("."+b.class_prefix+r))}})};a.table_hotkeys.current_row=null;a.table_hotkeys.defaults={cycle_expr:"tr",class_prefix:"vim-",selected_suffix:"current",destructive_suffix:"destructive",hotkeys_opts:{disableInInput:true,type:"keypress"},checkbox_expr:":checkbox",next_key:"j",prev_key:"k",mark_key:"x",start_row_index:2,highlight_first:false,highlight_last:false,next_page_link_cb:false,prev_page_link_cb:false}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/jquery.ui.touch-punch.js b/src/wp-includes/js/jquery/jquery.ui.touch-punch.js
new file mode 100644
index 0000000000..e10607a8f1
--- /dev/null
+++ b/src/wp-includes/js/jquery/jquery.ui.touch-punch.js
@@ -0,0 +1,11 @@
+/*!
+ * jQuery UI Touch Punch 0.2.2
+ *
+ * Copyright 2011, Dave Furfero
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ */
+(function(b){b.support.touch="ontouchend" in document;if(!b.support.touch){return}var c=b.ui.mouse.prototype,e=c._mouseInit,a;function d(g,h){if(g.originalEvent.touches.length>1){return}g.preventDefault();var i=g.originalEvent.changedTouches[0],f=document.createEvent("MouseEvents");f.initMouseEvent(h,true,true,window,1,i.screenX,i.screenY,i.clientX,i.clientY,false,false,false,false,0,null);g.target.dispatchEvent(f)}c._touchStart=function(g){var f=this;if(a||!f._mouseCapture(g.originalEvent.changedTouches[0])){return}a=true;f._touchMoved=false;d(g,"mouseover");d(g,"mousemove");d(g,"mousedown")};c._touchMove=function(f){if(!a){return}this._touchMoved=true;d(f,"mousemove")};c._touchEnd=function(f){if(!a){return}d(f,"mouseup");d(f,"mouseout");if(!this._touchMoved){d(f,"click")}a=false};c._mouseInit=function(){var f=this;f.element.bind("touchstart",b.proxy(f,"_touchStart")).bind("touchmove",b.proxy(f,"_touchMove")).bind("touchend",b.proxy(f,"_touchEnd"));e.call(f)}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/suggest.js b/src/wp-includes/js/jquery/suggest.js
new file mode 100644
index 0000000000..3060507ff8
--- /dev/null
+++ b/src/wp-includes/js/jquery/suggest.js
@@ -0,0 +1,315 @@
+/*
+ * jquery.suggest 1.1b - 2007-08-06
+ * Patched by Mark Jaquith with Alexander Dick's "multiple items" patch to allow for auto-suggesting of more than one tag before submitting
+ * See: http://www.vulgarisoip.com/2007/06/29/jquerysuggest-an-alternative-jquery-based-autocomplete-library/#comment-7228
+ *
+ * Uses code and techniques from following libraries:
+ * 1. http://www.dyve.net/jquery/?autocomplete
+ * 2. http://dev.jquery.com/browser/trunk/plugins/interface/iautocompleter.js
+ *
+ * All the new stuff written by Peter Vulgaris (www.vulgarisoip.com)
+ * Feel free to do whatever you want with this file
+ *
+ */
+
+(function($) {
+
+ $.suggest = function(input, options) {
+ var $input, $results, timeout, prevLength, cache, cacheSize;
+
+ $input = $(input).attr("autocomplete", "off");
+ $results = $("<ul/>");
+
+ timeout = false; // hold timeout ID for suggestion results to appear
+ prevLength = 0; // last recorded length of $input.val()
+ cache = []; // cache MRU list
+ cacheSize = 0; // size of cache in chars (bytes?)
+
+ $results.addClass(options.resultsClass).appendTo('body');
+
+
+ resetPosition();
+ $(window)
+ .load(resetPosition) // just in case user is changing size of page while loading
+ .resize(resetPosition);
+
+ $input.blur(function() {
+ setTimeout(function() { $results.hide() }, 200);
+ });
+
+ $input.keydown(processKey);
+
+ function resetPosition() {
+ // requires jquery.dimension plugin
+ var offset = $input.offset();
+ $results.css({
+ top: (offset.top + input.offsetHeight) + 'px',
+ left: offset.left + 'px'
+ });
+ }
+
+
+ function processKey(e) {
+
+ // handling up/down/escape requires results to be visible
+ // handling enter/tab requires that AND a result to be selected
+ if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
+ (/^13$|^9$/.test(e.keyCode) && getCurrentResult())) {
+
+ if (e.preventDefault)
+ e.preventDefault();
+ if (e.stopPropagation)
+ e.stopPropagation();
+
+ e.cancelBubble = true;
+ e.returnValue = false;
+
+ switch(e.keyCode) {
+
+ case 38: // up
+ prevResult();
+ break;
+
+ case 40: // down
+ nextResult();
+ break;
+
+ case 9: // tab
+ case 13: // return
+ selectCurrentResult();
+ break;
+
+ case 27: // escape
+ $results.hide();
+ break;
+
+ }
+
+ } else if ($input.val().length != prevLength) {
+
+ if (timeout)
+ clearTimeout(timeout);
+ timeout = setTimeout(suggest, options.delay);
+ prevLength = $input.val().length;
+
+ }
+
+
+ }
+
+
+ function suggest() {
+
+ var q = $.trim($input.val()), multipleSepPos, items;
+
+ if ( options.multiple ) {
+ multipleSepPos = q.lastIndexOf(options.multipleSep);
+ if ( multipleSepPos != -1 ) {
+ q = $.trim(q.substr(multipleSepPos + options.multipleSep.length));
+ }
+ }
+ if (q.length >= options.minchars) {
+
+ cached = checkCache(q);
+
+ if (cached) {
+
+ displayItems(cached['items']);
+
+ } else {
+
+ $.get(options.source, {q: q}, function(txt) {
+
+ $results.hide();
+
+ items = parseTxt(txt, q);
+
+ displayItems(items);
+ addToCache(q, items, txt.length);
+
+ });
+
+ }
+
+ } else {
+
+ $results.hide();
+
+ }
+
+ }
+
+
+ function checkCache(q) {
+ var i;
+ for (i = 0; i < cache.length; i++)
+ if (cache[i]['q'] == q) {
+ cache.unshift(cache.splice(i, 1)[0]);
+ return cache[0];
+ }
+
+ return false;
+
+ }
+
+ function addToCache(q, items, size) {
+ var cached;
+ while (cache.length && (cacheSize + size > options.maxCacheSize)) {
+ cached = cache.pop();
+ cacheSize -= cached['size'];
+ }
+
+ cache.push({
+ q: q,
+ size: size,
+ items: items
+ });
+
+ cacheSize += size;
+
+ }
+
+ function displayItems(items) {
+ var html = '', i;
+ if (!items)
+ return;
+
+ if (!items.length) {
+ $results.hide();
+ return;
+ }
+
+ resetPosition(); // when the form moves after the page has loaded
+
+ for (i = 0; i < items.length; i++)
+ html += '<li>' + items[i] + '</li>';
+
+ $results.html(html).show();
+
+ $results
+ .children('li')
+ .mouseover(function() {
+ $results.children('li').removeClass(options.selectClass);
+ $(this).addClass(options.selectClass);
+ })
+ .click(function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ selectCurrentResult();
+ });
+
+ }
+
+ function parseTxt(txt, q) {
+
+ var items = [], tokens = txt.split(options.delimiter), i, token;
+
+ // parse returned data for non-empty items
+ for (i = 0; i < tokens.length; i++) {
+ token = $.trim(tokens[i]);
+ if (token) {
+ token = token.replace(
+ new RegExp(q, 'ig'),
+ function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
+ );
+ items[items.length] = token;
+ }
+ }
+
+ return items;
+ }
+
+ function getCurrentResult() {
+ var $currentResult;
+ if (!$results.is(':visible'))
+ return false;
+
+ $currentResult = $results.children('li.' + options.selectClass);
+
+ if (!$currentResult.length)
+ $currentResult = false;
+
+ return $currentResult;
+
+ }
+
+ function selectCurrentResult() {
+
+ $currentResult = getCurrentResult();
+
+ if ($currentResult) {
+ if ( options.multiple ) {
+ if ( $input.val().indexOf(options.multipleSep) != -1 ) {
+ $currentVal = $input.val().substr( 0, ( $input.val().lastIndexOf(options.multipleSep) + options.multipleSep.length ) );
+ } else {
+ $currentVal = "";
+ }
+ $input.val( $currentVal + $currentResult.text() + options.multipleSep);
+ $input.focus();
+ } else {
+ $input.val($currentResult.text());
+ }
+ $results.hide();
+
+ if (options.onSelect)
+ options.onSelect.apply($input[0]);
+
+ }
+
+ }
+
+ function nextResult() {
+
+ $currentResult = getCurrentResult();
+
+ if ($currentResult)
+ $currentResult
+ .removeClass(options.selectClass)
+ .next()
+ .addClass(options.selectClass);
+ else
+ $results.children('li:first-child').addClass(options.selectClass);
+
+ }
+
+ function prevResult() {
+ var $currentResult = getCurrentResult();
+
+ if ($currentResult)
+ $currentResult
+ .removeClass(options.selectClass)
+ .prev()
+ .addClass(options.selectClass);
+ else
+ $results.children('li:last-child').addClass(options.selectClass);
+
+ }
+ }
+
+ $.fn.suggest = function(source, options) {
+
+ if (!source)
+ return;
+
+ options = options || {};
+ options.multiple = options.multiple || false;
+ options.multipleSep = options.multipleSep || ", ";
+ options.source = source;
+ options.delay = options.delay || 100;
+ options.resultsClass = options.resultsClass || 'ac_results';
+ options.selectClass = options.selectClass || 'ac_over';
+ options.matchClass = options.matchClass || 'ac_match';
+ options.minchars = options.minchars || 2;
+ options.delimiter = options.delimiter || '\n';
+ options.onSelect = options.onSelect || false;
+ options.maxCacheSize = options.maxCacheSize || 65536;
+
+ this.each(function() {
+ new $.suggest(this, options);
+ });
+
+ return this;
+
+ };
+
+})(jQuery);
diff --git a/src/wp-includes/js/jquery/suggest.min.js b/src/wp-includes/js/jquery/suggest.min.js
new file mode 100644
index 0000000000..d28a7fb269
--- /dev/null
+++ b/src/wp-includes/js/jquery/suggest.min.js
@@ -0,0 +1 @@
+(function(a){a.suggest=function(n,f){var c,e,m,d,p,o;c=a(n).attr("autocomplete","off");e=a("<ul/>");m=false;d=0;p=[];o=0;e.addClass(f.resultsClass).appendTo("body");i();a(window).load(i).resize(i);c.blur(function(){setTimeout(function(){e.hide()},200)});c.keydown(l);function i(){var u=c.offset();e.css({top:(u.top+n.offsetHeight)+"px",left:u.left+"px"})}function l(u){if((/27$|38$|40$/.test(u.keyCode)&&e.is(":visible"))||(/^13$|^9$/.test(u.keyCode)&&s())){if(u.preventDefault){u.preventDefault()}if(u.stopPropagation){u.stopPropagation()}u.cancelBubble=true;u.returnValue=false;switch(u.keyCode){case 38:j();break;case 40:r();break;case 9:case 13:q();break;case 27:e.hide();break}}else{if(c.val().length!=d){if(m){clearTimeout(m)}m=setTimeout(k,f.delay);d=c.val().length}}}function k(){var w=a.trim(c.val()),v,u;if(f.multiple){v=w.lastIndexOf(f.multipleSep);if(v!=-1){w=a.trim(w.substr(v+f.multipleSep.length))}}if(w.length>=f.minchars){cached=t(w);if(cached){h(cached.items)}else{a.get(f.source,{q:w},function(x){e.hide();u=b(x,w);h(u);g(w,u,x.length)})}}else{e.hide()}}function t(v){var u;for(u=0;u<p.length;u++){if(p[u]["q"]==v){p.unshift(p.splice(u,1)[0]);return p[0]}}return false}function g(x,u,v){var w;while(p.length&&(o+v>f.maxCacheSize)){w=p.pop();o-=w.size}p.push({q:x,size:v,items:u});o+=v}function h(u){var w="",v;if(!u){return}if(!u.length){e.hide();return}i();for(v=0;v<u.length;v++){w+="<li>"+u[v]+"</li>"}e.html(w).show();e.children("li").mouseover(function(){e.children("li").removeClass(f.selectClass);a(this).addClass(f.selectClass)}).click(function(x){x.preventDefault();x.stopPropagation();q()})}function b(u,y){var v=[],z=u.split(f.delimiter),x,w;for(x=0;x<z.length;x++){w=a.trim(z[x]);if(w){w=w.replace(new RegExp(y,"ig"),function(A){return'<span class="'+f.matchClass+'">'+A+"</span>"});v[v.length]=w}}return v}function s(){var u;if(!e.is(":visible")){return false}u=e.children("li."+f.selectClass);if(!u.length){u=false}return u}function q(){$currentResult=s();if($currentResult){if(f.multiple){if(c.val().indexOf(f.multipleSep)!=-1){$currentVal=c.val().substr(0,(c.val().lastIndexOf(f.multipleSep)+f.multipleSep.length))}else{$currentVal=""}c.val($currentVal+$currentResult.text()+f.multipleSep);c.focus()}else{c.val($currentResult.text())}e.hide();if(f.onSelect){f.onSelect.apply(c[0])}}}function r(){$currentResult=s();if($currentResult){$currentResult.removeClass(f.selectClass).next().addClass(f.selectClass)}else{e.children("li:first-child").addClass(f.selectClass)}}function j(){var u=s();if(u){u.removeClass(f.selectClass).prev().addClass(f.selectClass)}else{e.children("li:last-child").addClass(f.selectClass)}}};a.fn.suggest=function(c,b){if(!c){return}b=b||{};b.multiple=b.multiple||false;b.multipleSep=b.multipleSep||", ";b.source=c;b.delay=b.delay||100;b.resultsClass=b.resultsClass||"ac_results";b.selectClass=b.selectClass||"ac_over";b.matchClass=b.matchClass||"ac_match";b.minchars=b.minchars||2;b.delimiter=b.delimiter||"\n";b.onSelect=b.onSelect||false;b.maxCacheSize=b.maxCacheSize||65536;this.each(function(){new a.suggest(this,b)});return this}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.accordion.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.accordion.min.js
new file mode 100644
index 0000000000..d2e2d573ef
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.accordion.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){var e=0,i={},s={};i.height=i.paddingTop=i.paddingBottom=i.borderTopWidth=i.borderBottomWidth="hide",s.height=s.paddingTop=s.paddingBottom=s.borderTopWidth=s.borderBottomWidth="show",t.widget("ui.accordion",{version:"1.10.3",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t(),content:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("<span>").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),undefined):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),"disabled"===t&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e),undefined)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),a=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:a=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:a=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:a=this.headers[0];break;case i.END:a=this.headers[s-1]}a&&(t(e.target).attr("tabIndex",-1),t(a).attr("tabIndex",0),a.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide()},_refresh:function(){var i,s=this.options,n=s.heightStyle,a=this.element.parent(),o=this.accordionId="ui-accordion-"+(this.element.attr("id")||++e);this.active=this._findActive(s.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(e){var i=t(this),s=i.attr("id"),n=i.next(),a=n.attr("id");s||(s=o+"-header-"+e,i.attr("id",s)),a||(a=o+"-panel-"+e,n.attr("id",a)),i.attr("aria-controls",a),n.attr("aria-labelledby",s)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(s.event),"fill"===n?(i=a.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.headers.each(function(){i-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===n&&(i=0,this.headers.next().each(function(){i=Math.max(i,t(this).css("height","").height())}).height(i))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),a=n[0]===s[0],o=a&&i.collapsible,r=o?t():n.next(),h=s.next(),l={oldHeader:s,oldPanel:h,newHeader:o?t():n,newPanel:r};e.preventDefault(),a&&!i.collapsible||this._trigger("beforeActivate",e,l)===!1||(i.active=o?!1:this.headers.index(n),this.active=a?t():n,this._toggle(l),s.removeClass("ui-accordion-header-active ui-state-active"),i.icons&&s.children(".ui-accordion-header-icon").removeClass(i.icons.activeHeader).addClass(i.icons.header),a||(n.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),i.icons&&n.children(".ui-accordion-header-icon").removeClass(i.icons.header).addClass(i.icons.activeHeader),n.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-expanded":"false","aria-hidden":"true"}),s.prev().attr("aria-selected","false"),i.length&&s.length?s.prev().attr("tabIndex",-1):i.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(t,e,n){var a,o,r,h=this,l=0,c=t.length&&(!e.length||t.index()<e.index()),u=this.options.animate||{},d=c&&u.down||u,p=function(){h._toggleComplete(n)};return"number"==typeof d&&(r=d),"string"==typeof d&&(o=d),o=o||d.easing||u.easing,r=r||d.duration||u.duration,e.length?t.length?(a=t.show().outerHeight(),e.animate(i,{duration:r,easing:o,step:function(t,e){e.now=Math.round(t)}}),t.hide().animate(s,{duration:r,easing:o,complete:p,step:function(t,i){i.now=Math.round(t),"height"!==i.prop?l+=i.now:"content"!==h.options.heightStyle&&(i.now=Math.round(a-e.outerHeight()-l),l=0)}}),undefined):e.animate(i,r,o,p):t.animate(s,r,o,p)},_toggleComplete:function(t){var e=t.oldPanel;e.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all"),e.length&&(e.parent()[0].className=e.parent()[0].className),this._trigger("activate",null,t)}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js
new file mode 100644
index 0000000000..4081f8c7a6
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){var e=0;t.widget("ui.autocomplete",{version:"1.10.3",defaultElement:"<input>",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),a="textarea"===n,o="input"===n;this.isMultiLine=a?!0:o?!1:this.element.prop("isContentEditable"),this.valueMethod=this.element[a||o?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,undefined;e=!1,s=!1,i=!1;var a=t.ui.keyCode;switch(n.keyCode){case a.PAGE_UP:e=!0,this._move("previousPage",n);break;case a.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case a.UP:e=!0,this._keyEvent("previous",n);break;case a.DOWN:e=!0,this._keyEvent("next",n);break;case a.ENTER:case a.NUMPAD_ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case a.TAB:this.menu.active&&this.menu.select(n);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),undefined;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),undefined):(this._searchTimeout(t),undefined)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,undefined):(clearTimeout(this.searching),this.close(t),this._change(t),undefined)}}),this._initSource(),this.menu=t("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().data("ui-menu"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur});var i=this.menu.element[0];t(e.target).closest(".ui-menu-item").length||this._delay(function(){var e=this;this.document.one("mousedown",function(s){s.target===e.element[0]||s.target===i||t.contains(i,s.target)||e.close()})})},menufocus:function(e,i){if(this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type)))return this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),undefined;var s=i.item.data("ui-autocomplete-item");!1!==this._trigger("focus",e,{item:s})?e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(s.value):this.liveRegion.text(s.value)},menuselect:function(t,e){var i=e.item.data("ui-autocomplete-item"),s=this.previous;this.element[0]!==this.document[0].activeElement&&(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s,this.selectedItem=i})),!1!==this._trigger("select",t,{item:i})&&this._value(i.value),this.term=this._value(),this.close(t),this.selectedItem=i}}),this.liveRegion=t("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertBefore(this.element),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e||(e=this.element.closest(".ui-front")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){this.term!==this._value()&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length<this.options.minLength?this.close(e):this._trigger("search",e)!==!1?this._search(t):undefined},_search:function(t){this.pending++,this.element.addClass("ui-autocomplete-loading"),this.cancelSearch=!1,this.source({term:t},this._response())},_response:function(){var t=this,i=++e;return function(s){i===e&&t.__response(s),t.pending--,t.pending||t.element.removeClass("ui-autocomplete-loading")}},__response:function(t){t&&(t=this._normalize(t)),this._trigger("response",null,{content:t}),!this.options.disabled&&t&&t.length&&!this.cancelSearch?(this._suggest(t),this._trigger("open")):this._close()},close:function(t){this.cancelSearch=!0,this._close(t)},_close:function(t){this.menu.element.is(":visible")&&(this.menu.element.hide(),this.menu.blur(),this.isNewMenu=!0,this._trigger("close",t))},_change:function(t){this.previous!==this._value()&&this._trigger("change",t,{item:this.selectedItem})},_normalize:function(e){return e.length&&e[0].label&&e[0].value?e:t.map(e,function(e){return"string"==typeof e?{label:e,value:e}:t.extend({label:e.label||e.value,value:e.value||e.label},e)})},_suggest:function(e){var i=this.menu.element.empty();this._renderMenu(i,e),this.isNewMenu=!0,this.menu.refresh(),i.show(),this._resizeMenu(),i.position(t.extend({of:this.element},this.options.position)),this.options.autoFocus&&this.menu.next()},_resizeMenu:function(){var t=this.menu.element;t.outerWidth(Math.max(t.width("").outerWidth()+1,this.element.outerWidth()))},_renderMenu:function(e,i){var s=this;t.each(i,function(t,i){s._renderItemData(e,i)})},_renderItemData:function(t,e){return this._renderItem(t,e).data("ui-autocomplete-item",e)},_renderItem:function(e,i){return t("<li>").append(t("<a>").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this._value(this.term),this.menu.blur(),undefined):(this.menu[t](e),undefined):(this.search(null,e),undefined)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(t){var e;this._superApply(arguments),this.options.disabled||this.cancelSearch||(e=t&&t.length?this.options.messages.results(t.length):this.options.messages.noResults,this.liveRegion.text(e))}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.button.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.button.min.js
new file mode 100644
index 0000000000..d294ce05fb
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.button.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){var e,i,s,n,a="ui-button ui-widget ui-state-default ui-corner-all",o="ui-state-hover ui-state-active ",r="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",h=function(){var e=t(this);setTimeout(function(){e.find(":ui-button").button("refresh")},1)},l=function(e){var i=e.name,s=e.form,n=t([]);return i&&(i=i.replace(/'/g,"\\'"),n=s?t(s).find("[name='"+i+"']"):t("[name='"+i+"']",e.ownerDocument).filter(function(){return!this.form})),n};t.widget("ui.button",{version:"1.10.3",defaultElement:"<button>",options:{disabled:null,text:!0,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,h),"boolean"!=typeof this.options.disabled?this.options.disabled=!!this.element.prop("disabled"):this.element.prop("disabled",this.options.disabled),this._determineButtonType(),this.hasTitle=!!this.buttonElement.attr("title");var o=this,r=this.options,c="checkbox"===this.type||"radio"===this.type,u=c?"":"ui-state-active",d="ui-state-focus";null===r.label&&(r.label="input"===this.type?this.buttonElement.val():this.buttonElement.html()),this._hoverable(this.buttonElement),this.buttonElement.addClass(a).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){r.disabled||this===e&&t(this).addClass("ui-state-active")}).bind("mouseleave"+this.eventNamespace,function(){r.disabled||t(this).removeClass(u)}).bind("click"+this.eventNamespace,function(t){r.disabled&&(t.preventDefault(),t.stopImmediatePropagation())}),this.element.bind("focus"+this.eventNamespace,function(){o.buttonElement.addClass(d)}).bind("blur"+this.eventNamespace,function(){o.buttonElement.removeClass(d)}),c&&(this.element.bind("change"+this.eventNamespace,function(){n||o.refresh()}),this.buttonElement.bind("mousedown"+this.eventNamespace,function(t){r.disabled||(n=!1,i=t.pageX,s=t.pageY)}).bind("mouseup"+this.eventNamespace,function(t){r.disabled||(i!==t.pageX||s!==t.pageY)&&(n=!0)})),"checkbox"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){return r.disabled||n?!1:undefined}):"radio"===this.type?this.buttonElement.bind("click"+this.eventNamespace,function(){if(r.disabled||n)return!1;t(this).addClass("ui-state-active"),o.buttonElement.attr("aria-pressed","true");var e=o.element[0];l(e).not(e).map(function(){return t(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed","false")}):(this.buttonElement.bind("mousedown"+this.eventNamespace,function(){return r.disabled?!1:(t(this).addClass("ui-state-active"),e=this,o.document.one("mouseup",function(){e=null}),undefined)}).bind("mouseup"+this.eventNamespace,function(){return r.disabled?!1:(t(this).removeClass("ui-state-active"),undefined)}).bind("keydown"+this.eventNamespace,function(e){return r.disabled?!1:((e.keyCode===t.ui.keyCode.SPACE||e.keyCode===t.ui.keyCode.ENTER)&&t(this).addClass("ui-state-active"),undefined)}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){t(this).removeClass("ui-state-active")}),this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===t.ui.keyCode.SPACE&&t(this).click()})),this._setOption("disabled",r.disabled),this._resetButton()},_determineButtonType:function(){var t,e,i;this.type=this.element.is("[type=checkbox]")?"checkbox":this.element.is("[type=radio]")?"radio":this.element.is("input")?"input":"button","checkbox"===this.type||"radio"===this.type?(t=this.element.parents().last(),e="label[for='"+this.element.attr("id")+"']",this.buttonElement=t.find(e),this.buttonElement.length||(t=t.length?t.siblings():this.element.siblings(),this.buttonElement=t.filter(e),this.buttonElement.length||(this.buttonElement=t.find(e))),this.element.addClass("ui-helper-hidden-accessible"),i=this.element.is(":checked"),i&&this.buttonElement.addClass("ui-state-active"),this.buttonElement.prop("aria-pressed",i)):this.buttonElement=this.element},widget:function(){return this.buttonElement},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible"),this.buttonElement.removeClass(a+" "+o+" "+r).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html()),this.hasTitle||this.buttonElement.removeAttr("title")},_setOption:function(t,e){return this._super(t,e),"disabled"===t?(e?this.element.prop("disabled",!0):this.element.prop("disabled",!1),undefined):(this._resetButton(),undefined)},refresh:function(){var e=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");e!==this.options.disabled&&this._setOption("disabled",e),"radio"===this.type?l(this.element[0]).each(function(){t(this).is(":checked")?t(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true"):t(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false")}):"checkbox"===this.type&&(this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true"):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false"))},_resetButton:function(){if("input"===this.type)return this.options.label&&this.element.val(this.options.label),undefined;var e=this.buttonElement.removeClass(r),i=t("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(e.empty()).text(),s=this.options.icons,n=s.primary&&s.secondary,a=[];s.primary||s.secondary?(this.options.text&&a.push("ui-button-text-icon"+(n?"s":s.primary?"-primary":"-secondary")),s.primary&&e.prepend("<span class='ui-button-icon-primary ui-icon "+s.primary+"'></span>"),s.secondary&&e.append("<span class='ui-button-icon-secondary ui-icon "+s.secondary+"'></span>"),this.options.text||(a.push(n?"ui-button-icons-only":"ui-button-icon-only"),this.hasTitle||e.attr("title",t.trim(i)))):a.push("ui-button-text-only"),e.addClass(a.join(" "))}}),t.widget("ui.buttonset",{version:"1.10.3",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(t,e){"disabled"===t&&this.buttons.button("option",t,e),this._super(t,e)},refresh:function(){var e="rtl"===this.element.css("direction");this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(e?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(e?"ui-corner-left":"ui-corner-right").end().end()},_destroy:function(){this.element.removeClass("ui-buttonset"),this.buttons.map(function(){return t(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy")}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.core.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.core.min.js
new file mode 100644
index 0000000000..e96efd4ff8
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.core.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e,t){function i(t,i){var a,n,r,o=t.nodeName.toLowerCase();return"area"===o?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&s(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var a=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var s,a,n=e(this[0]);n.length&&n[0]!==document;){if(s=n.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(a=parseInt(n.css("zIndex"),10),!isNaN(a)&&0!==a))return a;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++a)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var s=e.attr(t,"tabindex"),a=isNaN(s);return(a||s>=0)&&i(t,!a)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(i,s){function a(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===s?["Left","Right"]:["Top","Bottom"],r=s.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+s]=function(i){return i===t?o["inner"+s].call(this):this.each(function(){e(this).css(r,a(this,i)+"px")})},e.fn["outer"+s]=function(t,i){return"number"!=typeof t?o["outer"+s].call(this,t):this.each(function(){e(this).css(r,a(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i){var s,a=e.plugins[t];if(a&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(s=0;a.length>s;s++)e.options[a[s][0]]&&a[s][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",a=!1;return t[s]>0?!0:(t[s]=1,a=t[s]>0,t[s]=0,a)}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js
new file mode 100644
index 0000000000..bd4b62ed6e
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t,e){function i(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.dpDiv=s(t("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"))}function s(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(i,"mouseout",function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(i,"mouseover",function(){t.datepicker._isDisabledDatepicker(a.inline?e.parent()[0]:a.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))})}function n(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}t.extend(t.ui,{datepicker:{version:"1.10.3"}});var a,r="datepicker";t.extend(i.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(t){return n(this._defaults,t||{}),this},_attachDatepicker:function(e,i){var s,n,a;s=e.nodeName.toLowerCase(),n="div"===s||"span"===s,e.id||(this.uuid+=1,e.id="dp"+this.uuid),a=this._newInst(t(e),n),a.settings=t.extend({},i||{}),"input"===s?this._connectDatepicker(e,a):n&&this._inlineDatepicker(e,a)},_newInst:function(e,i){var n=e[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:n,input:e,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:i,dpDiv:i?s(t("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")):this.dpDiv}},_connectDatepicker:function(e,i){var s=t(e);i.append=t([]),i.trigger=t([]),s.hasClass(this.markerClassName)||(this._attachments(s,i),s.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp),this._autoSize(i),t.data(e,r,i),i.settings.disabled&&this._disableDatepicker(e))},_attachments:function(e,i){var s,n,a,r=this._get(i,"appendText"),o=this._get(i,"isRTL");i.append&&i.append.remove(),r&&(i.append=t("<span class='"+this._appendClass+"'>"+r+"</span>"),e[o?"before":"after"](i.append)),e.unbind("focus",this._showDatepicker),i.trigger&&i.trigger.remove(),s=this._get(i,"showOn"),("focus"===s||"both"===s)&&e.focus(this._showDatepicker),("button"===s||"both"===s)&&(n=this._get(i,"buttonText"),a=this._get(i,"buttonImage"),i.trigger=t(this._get(i,"buttonImageOnly")?t("<img/>").addClass(this._triggerClass).attr({src:a,alt:n,title:n}):t("<button type='button'></button>").addClass(this._triggerClass).html(a?t("<img/>").attr({src:a,alt:n,title:n}):n)),e[o?"before":"after"](i.trigger),i.trigger.click(function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,a=new Date(2009,11,20),r=this._get(t,"dateFormat");r.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},a.setMonth(e(this._get(t,r.match(/MM/)?"monthNames":"monthNamesShort"))),a.setDate(e(this._get(t,r.match(/DD/)?"dayNames":"dayNamesShort"))+20-a.getDay())),t.input.attr("size",this._formatDate(t,a).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,r,i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,a,o){var h,l,c,u,d,p=this._dialogInst;return p||(this.uuid+=1,h="dp"+this.uuid,this._dialogInput=t("<input type='text' id='"+h+"' style='position: absolute; top: -100px; width: 0px;'/>"),this._dialogInput.keydown(this._doKeyDown),t("body").append(this._dialogInput),p=this._dialogInst=this._newInst(this._dialogInput,!1),p.settings={},t.data(this._dialogInput[0],r,p)),n(p.settings,a||{}),i=i&&i.constructor===Date?this._formatDate(p,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(l=document.documentElement.clientWidth,c=document.documentElement.clientHeight,u=document.documentElement.scrollLeft||document.body.scrollLeft,d=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[l/2-100+u,c/2-150+d]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),p.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],r,p),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,r);s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,r),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty())},_enableDatepicker:function(e){var i,s,n=t(e),a=t.data(e,r);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,a.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),a=t.data(e,r);n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,a.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,r)}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(i,s,a){var r,o,h,l,c=this._getInst(i);return 2===arguments.length&&"string"==typeof s?"defaults"===s?t.extend({},t.datepicker._defaults):c?"all"===s?t.extend({},c.settings):this._get(c,s):null:(r=s||{},"string"==typeof s&&(r={},r[s]=a),c&&(this._curInst===c&&this._hideDatepicker(),o=this._getDateDatepicker(i,!0),h=this._getMinMaxDate(c,"min"),l=this._getMinMaxDate(c,"max"),n(c.settings,r),null!==h&&r.dateFormat!==e&&r.minDate===e&&(c.settings.minDate=this._formatDate(c,h)),null!==l&&r.dateFormat!==e&&r.maxDate===e&&(c.settings.maxDate=this._formatDate(c,l)),"disabled"in r&&(r.disabled?this._disableDatepicker(i):this._enableDatepicker(i)),this._attachments(t(i),c),this._autoSize(c),this._setDate(c,o),this._updateAlternate(c),this._updateDatepicker(c)),e)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,a=t.datepicker._getInst(e.target),r=!0,o=a.dpDiv.is(".ui-datepicker-rtl");if(a._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),r=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",a.dpDiv),n[0]&&t.datepicker._selectDay(e.target,a.selectedMonth,a.selectedYear,n[0]),i=t.datepicker._get(a,"onSelect"),i?(s=t.datepicker._formatDate(a),i.apply(a.input?a.input[0]:null,[s,a])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(a,"stepBigMonths"):-t.datepicker._get(a,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(a,"stepBigMonths"):+t.datepicker._get(a,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),r=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),r=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,o?1:-1,"D"),r=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(a,"stepBigMonths"):-t.datepicker._get(a,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),r=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,o?-1:1,"D"),r=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(a,"stepBigMonths"):+t.datepicker._get(a,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),r=e.ctrlKey||e.metaKey;break;default:r=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):r=!1;r&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(i){var s,n,a=t.datepicker._getInst(i.target);return t.datepicker._get(a,"constrainInput")?(s=t.datepicker._possibleChars(t.datepicker._get(a,"dateFormat")),n=String.fromCharCode(null==i.charCode?i.keyCode:i.charCode),i.ctrlKey||i.metaKey||" ">n||!s||s.indexOf(n)>-1):e},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var i,s,a,r,o,h,l;i=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==i&&(t.datepicker._curInst.dpDiv.stop(!0,!0),i&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),s=t.datepicker._get(i,"beforeShow"),a=s?s.apply(e,[e,i]):{},a!==!1&&(n(i.settings,a),i.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(i),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),r=!1,t(e).parents().each(function(){return r|="fixed"===t(this).css("position"),!r}),o={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,i.dpDiv.empty(),i.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(i),o=t.datepicker._checkOffset(i,o,r),i.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":r?"fixed":"absolute",display:"none",left:o.left+"px",top:o.top+"px"}),i.inline||(h=t.datepicker._get(i,"showAnim"),l=t.datepicker._get(i,"duration"),i.dpDiv.zIndex(t(e).zIndex()+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[h]?i.dpDiv.show(h,t.datepicker._get(i,"showOptions"),l):i.dpDiv[h||"show"](h?l:null),t.datepicker._shouldFocusInput(i)&&i.input.focus(),t.datepicker._curInst=i))}},_updateDatepicker:function(e){this.maxRows=4,a=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e),e.dpDiv.find("."+this._dayOverClass+" a").mouseover();var i,s=this._getNumberOfMonths(e),n=s[1],r=17;e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",r*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.focus(),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),a=e.dpDiv.outerHeight(),r=e.input?e.input.outerWidth():0,o=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-r:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+o?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+a>l&&l>a?Math.abs(a+o):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,a,o=this._curInst;!o||e&&o!==t.data(e,r)||this._datepickerShowing&&(i=this._get(o,"showAnim"),s=this._get(o,"duration"),n=function(){t.datepicker._tidyDialog(o)},t.effects&&(t.effects.effect[i]||t.effects[i])?o.dpDiv.hide(i,t.datepicker._get(o,"showOptions"),s,n):o.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,a=this._get(o,"onClose"),a&&a.apply(o.input?o.input[0]:null,[o.input?o.input.val():"",o]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),a=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(a,i+("M"===s?this._get(a,"showCurrentAtPos"):0),s),this._updateDatepicker(a))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),a=this._getInst(n[0]);a["selected"+("M"===s?"Month":"Year")]=a["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(a),this._adjustDate(n)},_selectDay:function(e,i,s,n){var a,r=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(r[0])||(a=this._getInst(r[0]),a.selectedDay=a.currentDay=t("a",n).html(),a.selectedMonth=a.currentMonth=i,a.selectedYear=a.currentYear=s,this._selectDate(e,this._formatDate(a,a.currentDay,a.currentMonth,a.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),a=this._getInst(n[0]);i=null!=i?i:this._formatDate(a),a.input&&a.input.val(i),this._updateAlternate(a),s=this._get(a,"onSelect"),s?s.apply(a.input?a.input[0]:null,[i,a]):a.input&&a.input.trigger("change"),a.inline?this._updateDatepicker(a):(this._hideDatepicker(),this._lastInput=a.input[0],"object"!=typeof a.input[0]&&a.input.focus(),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,a=this._get(e,"altField");a&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(a).each(function(){t(this).val(n)}))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(i,s,n){if(null==i||null==s)throw"Invalid arguments";if(s="object"==typeof s?""+s:s+"",""===s)return null;var a,r,o,h,l=0,c=(n?n.shortYearCutoff:null)||this._defaults.shortYearCutoff,u="string"!=typeof c?c:(new Date).getFullYear()%100+parseInt(c,10),d=(n?n.dayNamesShort:null)||this._defaults.dayNamesShort,p=(n?n.dayNames:null)||this._defaults.dayNames,f=(n?n.monthNamesShort:null)||this._defaults.monthNamesShort,m=(n?n.monthNames:null)||this._defaults.monthNames,g=-1,v=-1,_=-1,b=-1,y=!1,x=function(t){var e=i.length>a+1&&i.charAt(a+1)===t;return e&&a++,e},k=function(t){var e=x(t),i="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n=RegExp("^\\d{1,"+i+"}"),a=s.substring(l).match(n);if(!a)throw"Missing number at position "+l;return l+=a[0].length,parseInt(a[0],10)},w=function(i,n,a){var r=-1,o=t.map(x(i)?a:n,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(o,function(t,i){var n=i[1];return s.substr(l,n.length).toLowerCase()===n.toLowerCase()?(r=i[0],l+=n.length,!1):e}),-1!==r)return r+1;throw"Unknown name at position "+l},D=function(){if(s.charAt(l)!==i.charAt(a))throw"Unexpected literal at position "+l;l++};for(a=0;i.length>a;a++)if(y)"'"!==i.charAt(a)||x("'")?D():y=!1;else switch(i.charAt(a)){case"d":_=k("d");break;case"D":w("D",d,p);break;case"o":b=k("o");break;case"m":v=k("m");break;case"M":v=w("M",f,m);break;case"y":g=k("y");break;case"@":h=new Date(k("@")),g=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"!":h=new Date((k("!")-this._ticksTo1970)/1e4),g=h.getFullYear(),v=h.getMonth()+1,_=h.getDate();break;case"'":x("'")?D():y=!0;break;default:D()}if(s.length>l&&(o=s.substr(l),!/^\s+/.test(o)))throw"Extra/unparsed characters found in date: "+o;if(-1===g?g=(new Date).getFullYear():100>g&&(g+=(new Date).getFullYear()-(new Date).getFullYear()%100+(u>=g?0:-100)),b>-1)for(v=1,_=b;;){if(r=this._getDaysInMonth(g,v-1),r>=_)break;v++,_-=r}if(h=this._daylightSavingAdjust(new Date(g,v-1,_)),h.getFullYear()!==g||h.getMonth()+1!==v||h.getDate()!==_)throw"Invalid date";return h},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,a=(i?i.dayNames:null)||this._defaults.dayNames,r=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,o=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,a);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),r,o);break;case"y":u+=h("y")?e.getFullYear():(10>e.getYear()%100?"0":"")+e.getYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,i){return t.settings[i]!==e?t.settings[i]:this._defaults[i]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),a=n,r=this._getFormatConfig(t);try{a=this.parseDate(i,s,r)||n}catch(o){s=e?"":s}t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),t.currentDay=s?a.getDate():0,t.currentMonth=s?a.getMonth():0,t.currentYear=s?a.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},a=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,a=n.getFullYear(),r=n.getMonth(),o=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":o+=parseInt(l[1],10);break;case"w":case"W":o+=7*parseInt(l[1],10);break;case"m":case"M":r+=parseInt(l[1],10),o=Math.min(o,t.datepicker._getDaysInMonth(a,r));break;case"y":case"Y":a+=parseInt(l[1],10),o=Math.min(o,t.datepicker._getDaysInMonth(a,r))}l=h.exec(i)}return new Date(a,r,o)},r=null==i||""===i?s:"string"==typeof i?a(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return r=r&&"Invalid Date"==""+r?s:r,r&&(r.setHours(0),r.setMinutes(0),r.setSeconds(0),r.setMilliseconds(0)),this._daylightSavingAdjust(r)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,a=t.selectedYear,r=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=r.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=r.getMonth(),t.drawYear=t.selectedYear=t.currentYear=r.getFullYear(),n===t.selectedMonth&&a===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).bind(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,a,r,o,h,l,c,u,d,p,f,m,g,v,_,b,y,x,k,w,D,T,C,M,S,N,I,P,A,z,H,E,F,O,W,j,R=new Date,L=this._daylightSavingAdjust(new Date(R.getFullYear(),R.getMonth(),R.getDate())),Y=this._get(t,"isRTL"),B=this._get(t,"showButtonPanel"),J=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),Q=this._getNumberOfMonths(t),V=this._get(t,"showCurrentAtPos"),U=this._get(t,"stepMonths"),q=1!==Q[0]||1!==Q[1],X=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),G=this._getMinMaxDate(t,"min"),$=this._getMinMaxDate(t,"max"),Z=t.drawMonth-V,te=t.drawYear;if(0>Z&&(Z+=12,te--),$)for(e=this._daylightSavingAdjust(new Date($.getFullYear(),$.getMonth()-Q[0]*Q[1]+1,$.getDate())),e=G&&G>e?G:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-U,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>":J?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+i+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"e":"w")+"'>"+i+"</span></a>",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+U,1)),this._getFormatConfig(t)):n,a=this._canAdjustMonth(t,1,te,Z)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>":J?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+n+"'><span class='ui-icon ui-icon-circle-triangle-"+(Y?"w":"e")+"'>"+n+"</span></a>",r=this._get(t,"currentText"),o=this._get(t,"gotoCurrent")&&t.currentDay?X:L,r=K?this.formatDate(r,o,this._getFormatConfig(t)):r,h=t.inline?"":"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+this._get(t,"closeText")+"</button>",l=B?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(Y?h:"")+(this._isInRange(t,o)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'>"+r+"</button>":"")+(Y?"":h)+"</div>":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),m=this._get(t,"monthNamesShort"),g=this._get(t,"beforeShowDay"),v=this._get(t,"showOtherMonths"),_=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;Q[0]>k;k++){for(w="",this.maxRows=4,D=0;Q[1]>D;D++){if(T=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),C=" ui-corner-all",M="",q){if(M+="<div class='ui-datepicker-group",Q[1]>1)switch(D){case 0:M+=" ui-datepicker-group-first",C=" ui-corner-"+(Y?"right":"left");break;case Q[1]-1:M+=" ui-datepicker-group-last",C=" ui-corner-"+(Y?"left":"right");break;default:M+=" ui-datepicker-group-middle",C=""}M+="'>"}for(M+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+C+"'>"+(/all|left/.test(C)&&0===k?Y?a:s:"")+(/all|right/.test(C)&&0===k?Y?s:a:"")+this._generateMonthYearHeader(t,Z,te,G,$,k>0||D>0,f,m)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>",S=u?"<th class='ui-datepicker-week-col'>"+this._get(t,"weekHeader")+"</th>":"",x=0;7>x;x++)N=(x+c)%7,S+="<th"+((x+c+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+d[N]+"'>"+p[N]+"</span></th>";for(M+=S+"</tr></thead><tbody>",I=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,I)),P=(this._getFirstDayOfMonth(te,Z)-c+7)%7,A=Math.ceil((P+I)/7),z=q?this.maxRows>A?this.maxRows:A:A,this.maxRows=z,H=this._daylightSavingAdjust(new Date(te,Z,1-P)),E=0;z>E;E++){for(M+="<tr>",F=u?"<td class='ui-datepicker-week-col'>"+this._get(t,"calculateWeek")(H)+"</td>":"",x=0;7>x;x++)O=g?g.apply(t.input?t.input[0]:null,[H]):[!0,""],W=H.getMonth()!==Z,j=W&&!_||!O[0]||G&&G>H||$&&H>$,F+="<td class='"+((x+c+6)%7>=5?" ui-datepicker-week-end":"")+(W?" ui-datepicker-other-month":"")+(H.getTime()===T.getTime()&&Z===t.selectedMonth&&t._keyEvent||b.getTime()===H.getTime()&&b.getTime()===T.getTime()?" "+this._dayOverClass:"")+(j?" "+this._unselectableClass+" ui-state-disabled":"")+(W&&!v?"":" "+O[1]+(H.getTime()===X.getTime()?" "+this._currentClass:"")+(H.getTime()===L.getTime()?" ui-datepicker-today":""))+"'"+(W&&!v||!O[2]?"":" title='"+O[2].replace(/'/g,"&#39;")+"'")+(j?"":" data-handler='selectDay' data-event='click' data-month='"+H.getMonth()+"' data-year='"+H.getFullYear()+"'")+">"+(W&&!v?"&#xa0;":j?"<span class='ui-state-default'>"+H.getDate()+"</span>":"<a class='ui-state-default"+(H.getTime()===L.getTime()?" ui-state-highlight":"")+(H.getTime()===X.getTime()?" ui-state-active":"")+(W?" ui-priority-secondary":"")+"' href='#'>"+H.getDate()+"</a>")+"</td>",H.setDate(H.getDate()+1),H=this._daylightSavingAdjust(H);M+=F+"</tr>"}Z++,Z>11&&(Z=0,te++),M+="</tbody></table>"+(q?"</div>"+(Q[0]>0&&D===Q[1]-1?"<div class='ui-datepicker-row-break'></div>":""):""),w+=M}y+=w}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,a,r,o){var h,l,c,u,d,p,f,m,g=this._get(t,"changeMonth"),v=this._get(t,"changeYear"),_=this._get(t,"showMonthAfterYear"),b="<div class='ui-datepicker-title'>",y="";if(a||!g)y+="<span class='ui-datepicker-month'>"+r[e]+"</span>";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>",c=0;12>c;c++)(!h||c>=s.getMonth())&&(!l||n.getMonth()>=c)&&(y+="<option value='"+c+"'"+(c===e?" selected='selected'":"")+">"+o[c]+"</option>");y+="</select>"}if(_||(b+=y+(!a&&g&&v?"":"&#xa0;")),!t.yearshtml)if(t.yearshtml="",a||!v)b+="<span class='ui-datepicker-year'>"+i+"</span>";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);
+return isNaN(e)?d:e},f=p(u[0]),m=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,m=n?Math.min(m,n.getFullYear()):m,t.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";m>=f;f++)t.yearshtml+="<option value='"+f+"'"+(f===i?" selected='selected'":"")+">"+f+"</option>";t.yearshtml+="</select>",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),_&&(b+=(!a&&g&&v?"":"&#xa0;")+y),b+="</div>"},_adjustInstDate:function(t,e,i){var s=t.drawYear+("Y"===i?e:0),n=t.drawMonth+("M"===i?e:0),a=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),r=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,a)));t.selectedDay=r.getDate(),t.drawMonth=t.selectedMonth=r.getMonth(),t.drawYear=t.selectedYear=r.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),a=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&a.setDate(this._getDaysInMonth(a.getFullYear(),a.getMonth())),this._isInRange(t,a)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),a=this._getMinMaxDate(t,"max"),r=null,o=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),r=parseInt(i[0],10),o=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(r+=s),i[1].match(/[+\-].*/)&&(o+=s)),(!n||e.getTime()>=n.getTime())&&(!a||e.getTime()<=a.getTime())&&(!r||e.getFullYear()>=r)&&(!o||o>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).mousedown(t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new i,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.10.3"})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.dialog.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.dialog.min.js
new file mode 100644
index 0000000000..990f202196
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.dialog.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){var e={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};t.widget("ui.dialog",{version:"1.10.3",options:{appendTo:"body",autoOpen:!0,buttons:[],closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),this.options.title=this.options.title||this.originalTitle,this._createWrapper(),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._destroyOverlay(),this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach(),this.uiDialog.stop(!0,!0).remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._destroyOverlay(),this.opener.filter(":focusable").focus().length||t(this.document[0].activeElement).blur(),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(t,e){var i=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;return i&&!e&&this._trigger("focus",t),i},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),undefined):(this._isOpen=!0,this.opener=t(this.document[0].activeElement),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._trigger("open"),undefined)},_focusTabbable:function(){var t=this.element.find("[autofocus]");t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).focus()},_keepFocus:function(e){function i(){var e=this.document[0].activeElement,i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),undefined;if(e.keyCode===t.ui.keyCode.TAB){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(n.focus(1),e.preventDefault()):(s.focus(1),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.focus()}}),this.uiDialogTitlebarClose=t("<button></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:!1}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar),this._title(e),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title||t.html("&#160;"),t.text(this.options.title)},_createButtonPane:function(){this.uiDialogButtonPane=t("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this.uiDialog.removeClass("ui-dialog-buttons"),undefined):(t.each(i,function(i,s){var n,a;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,s.click=function(){n.apply(e.element[0],arguments)},a={icons:s.icons,text:s.showText},delete s.icons,delete s.showText,t("<button></button>",s).button(a).appendTo(e.uiButtonSet)}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),undefined)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){t(this).addClass("ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,a){s.position=[a.position.left-i.document.scrollLeft(),a.position.top-i.document.scrollTop()],t(this).removeClass("ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(a))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,a=this.uiDialog.css("position"),o="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:o,start:function(s,n){t(this).addClass("ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,a){s.height=t(this).height(),s.width=t(this).width(),t(this).removeClass("ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(a))}}).css("position",a)},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(s){var n=this,a=!1,o={};t.each(s,function(t,s){n._setOption(t,s),t in e&&(a=!0),t in i&&(o[t]=s)}),a&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",o)},_setOption:function(t,e){var i,s,n=this.uiDialog;"dialogClass"===t&&n.removeClass(this.options.dialogClass).addClass(e),"disabled"!==t&&(this._super(t,e),"appendTo"===t&&this.uiDialog.appendTo(this._appendTo()),"buttons"===t&&this._createButtons(),"closeText"===t&&this.uiDialogTitlebarClose.button({label:""+e}),"draggable"===t&&(i=n.is(":data(ui-draggable)"),i&&!e&&n.draggable("destroy"),!i&&e&&this._makeDraggable()),"position"===t&&this._position(),"resizable"===t&&(s=n.is(":data(ui-resizable)"),s&&!e&&n.resizable("destroy"),s&&"string"==typeof e&&n.resizable("option","handles",e),s||e===!1||this._makeResizable()),"title"===t&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("<div>").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=this,i=this.widgetFullName;t.ui.dialog.overlayInstances||this._delay(function(){t.ui.dialog.overlayInstances&&this.document.bind("focusin.dialog",function(s){e._allowInteraction(s)||(s.preventDefault(),t(".ui-dialog:visible:last .ui-dialog-content").data(i)._focusTabbable())})}),this.overlay=t("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo()),this._on(this.overlay,{mousedown:"_keepFocus"}),t.ui.dialog.overlayInstances++}},_destroyOverlay:function(){this.options.modal&&this.overlay&&(t.ui.dialog.overlayInstances--,t.ui.dialog.overlayInstances||this.document.unbind("focusin.dialog"),this.overlay.remove(),this.overlay=null)}}),t.ui.dialog.overlayInstances=0,t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{_position:function(){var e,i=this.options.position,s=[],n=[0,0];i?(("string"==typeof i||"object"==typeof i&&"0"in i)&&(s=i.split?i.split(" "):[i[0],i[1]],1===s.length&&(s[1]=s[0]),t.each(["left","top"],function(t,e){+s[t]===s[t]&&(n[t]=s[t],s[t]=e)}),i={my:s[0]+(0>n[0]?n[0]:"+"+n[0])+" "+s[1]+(0>n[1]?n[1]:"+"+n[1]),at:s.join(" ")}),i=t.extend({},t.ui.dialog.prototype.options.position,i)):i=t.ui.dialog.prototype.options.position,e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.position(i),e||this.uiDialog.hide()}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.draggable.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.draggable.min.js
new file mode 100644
index 0000000000..ac92817f3b
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.draggable.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){e.widget("ui.draggable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var i=this.options;return this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(e(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){e("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"original"!==this.options.helper||e.contains(this.element[0].ownerDocument,this.element[0])?("invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1):!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;return n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):"document"===n.containment?(this.containment=[0,0,e(document).width()-this.helperProportions.width-this.margins.left,(e(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):n.containment.constructor===Array?(this.containment=n.containment,undefined):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),undefined):(this.containment=null,undefined)},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent;return this.offset.scroll||(this.offset.scroll={top:n.scrollTop(),left:n.scrollLeft()}),{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top)*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)*s}},_generatePosition:function(t){var i,s,n,a,o=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=t.pageX,l=t.pageY;return this.offset.scroll||(this.offset.scroll={top:r.scrollTop(),left:r.scrollLeft()}),this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),t.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),t.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s]),"drag"===t&&(this.positionAbs=this._convertPositionTo("absolute")),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i){var s=e(this).data("ui-draggable"),n=s.options,a=e.extend({},i,{item:s.element});s.sortables=[],e(n.connectToSortable).each(function(){var i=e.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",t,a))})},stop:function(t,i){var s=e(this).data("ui-draggable"),n=e.extend({},i,{item:s.element});e.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(t),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",t,n))})},drag:function(t,i){var s=e(this).data("ui-draggable"),n=this;e.each(s.sortables,function(){var a=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(a=!0,e.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&e.contains(o.instance.element[0],this.instance.element[0])&&(a=!1),a})),a?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=e(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},t.target=this.instance.currentItem[0],this.instance._mouseCapture(t,!0),this.instance._mouseStart(t,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",t),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(t)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",t,this.instance._uiHash(this.instance)),this.instance._mouseStop(t,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",t),s.dropped=!1)})}}),e.ui.plugin.add("draggable","cursor",{start:function(){var t=e("body"),i=e(this).data("ui-draggable").options;t.css("cursor")&&(i._cursor=t.css("cursor")),t.css("cursor",i.cursor)},stop:function(){var t=e(this).data("ui-draggable").options;t._cursor&&e("body").css("cursor",t._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._opacity&&e(i.helper).css("opacity",s._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(){var t=e(this).data("ui-draggable");t.scrollParent[0]!==document&&"HTML"!==t.scrollParent[0].tagName&&(t.overflowOffset=t.scrollParent.offset())},drag:function(t){var i=e(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-t.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:t.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-t.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:t.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(t.pageY-e(document).scrollTop()<s.scrollSensitivity?n=e(document).scrollTop(e(document).scrollTop()-s.scrollSpeed):e(window).height()-(t.pageY-e(document).scrollTop())<s.scrollSensitivity&&(n=e(document).scrollTop(e(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(t.pageX-e(document).scrollLeft()<s.scrollSensitivity?n=e(document).scrollLeft(e(document).scrollLeft()-s.scrollSpeed):e(window).width()-(t.pageX-e(document).scrollLeft())<s.scrollSensitivity&&(n=e(document).scrollLeft(e(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&e.ui.ddmanager&&!s.dropBehaviour&&e.ui.ddmanager.prepareOffsets(i,t)}}),e.ui.plugin.add("draggable","snap",{start:function(){var t=e(this).data("ui-draggable"),i=t.options;t.snapElements=[],e(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=e(this),s=i.offset();this!==t.element[0]&&t.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(t,i){var s,n,a,o,r,h,l,u,c,d,p=e(this).data("ui-draggable"),f=p.options,m=f.snapTolerance,g=i.offset.left,v=g+p.helperProportions.width,b=i.offset.top,y=b+p.helperProportions.height;for(c=p.snapElements.length-1;c>=0;c--)r=p.snapElements[c].left,h=r+p.snapElements[c].width,l=p.snapElements[c].top,u=l+p.snapElements[c].height,r-m>v||g>h+m||l-m>y||b>u+m||!e.contains(p.snapElements[c].item.ownerDocument,p.snapElements[c].item)?(p.snapElements[c].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(s=m>=Math.abs(l-y),n=m>=Math.abs(u-b),a=m>=Math.abs(r-v),o=m>=Math.abs(h-g),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||a||o,"outer"!==f.snapMode&&(s=m>=Math.abs(l-b),n=m>=Math.abs(u-y),a=m>=Math.abs(r-g),o=m>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u-p.helperProportions.height,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[c].snapping&&(s||n||a||o||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=s||n||a||o||d)}}),e.ui.plugin.add("draggable","stack",{start:function(){var t,i=this.data("ui-draggable").options,s=e.makeArray(e(i.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});s.length&&(t=parseInt(e(s[0]).css("zIndex"),10)||0,e(s).each(function(i){e(this).css("zIndex",t+i)}),this.css("zIndex",t+s.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._zIndex&&e(i.helper).css("zIndex",s._zIndex)}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.droppable.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.droppable.min.js
new file mode 100644
index 0000000000..ba7b194003
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.droppable.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){function t(e,t,i){return e>t&&t+i>e}e.widget("ui.droppable",{version:"1.10.3",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var t=this.options,i=t.accept;this.isover=!1,this.isout=!0,this.accept=e.isFunction(i)?i:function(e){return e.is(i)},this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight},e.ui.ddmanager.droppables[t.scope]=e.ui.ddmanager.droppables[t.scope]||[],e.ui.ddmanager.droppables[t.scope].push(this),t.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){for(var t=0,i=e.ui.ddmanager.droppables[this.options.scope];i.length>t;t++)i[t]===this&&i.splice(t,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(t,i){"accept"===t&&(this.accept=e.isFunction(i)?i:function(e){return e.is(i)}),e.Widget.prototype._setOption.apply(this,arguments)},_activate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",t,this.ui(i))},_deactivate:function(t){var i=e.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",t,this.ui(i))},_over:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",t,this.ui(i)))},_out:function(t){var i=e.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",t,this.ui(i)))},_drop:function(t,i){var s=i||e.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var t=e.data(this,"ui-droppable");return t.options.greedy&&!t.options.disabled&&t.options.scope===s.options.scope&&t.accept.call(t.element[0],s.currentItem||s.element)&&e.ui.intersect(s,e.extend(t,{offset:t.element.offset()}),t.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",t,this.ui(s)),this.element):!1):!1},ui:function(e){return{draggable:e.currentItem||e.element,helper:e.helper,position:e.position,offset:e.positionAbs}}}),e.ui.intersect=function(e,i,s){if(!i.offset)return!1;var n,a,o=(e.positionAbs||e.position.absolute).left,r=o+e.helperProportions.width,h=(e.positionAbs||e.position.absolute).top,l=h+e.helperProportions.height,u=i.offset.left,c=u+i.proportions.width,d=i.offset.top,p=d+i.proportions.height;switch(s){case"fit":return o>=u&&c>=r&&h>=d&&p>=l;case"intersect":return o+e.helperProportions.width/2>u&&c>r-e.helperProportions.width/2&&h+e.helperProportions.height/2>d&&p>l-e.helperProportions.height/2;case"pointer":return n=(e.positionAbs||e.position.absolute).left+(e.clickOffset||e.offset.click).left,a=(e.positionAbs||e.position.absolute).top+(e.clickOffset||e.offset.click).top,t(a,d,i.proportions.height)&&t(n,u,i.proportions.width);case"touch":return(h>=d&&p>=h||l>=d&&p>=l||d>h&&l>p)&&(o>=u&&c>=o||r>=u&&c>=r||u>o&&r>c);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,i){var s,n,a=e.ui.ddmanager.droppables[t.options.scope]||[],o=i?i.type:null,r=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();e:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||t&&!a[s].accept.call(a[s].element[0],t.currentItem||t.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions.height=0;continue e}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions={width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight})}},drop:function(t,i){var s=!1;return e.each((e.ui.ddmanager.droppables[t.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&e.ui.intersect(t,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],t.currentItem||t.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(t,i){t.element.parentsUntil("body").bind("scroll.droppable",function(){t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)})},drag:function(t,i){t.options.refreshPositions&&e.ui.ddmanager.prepareOffsets(t,i),e.each(e.ui.ddmanager.droppables[t.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=e.ui.intersect(t,this,this.options.tolerance),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return e.data(this,"ui-droppable").options.scope===n}),a.length&&(s=e.data(a[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(t,i){t.element.parentsUntil("body").unbind("scroll.droppable"),t.options.refreshPositions||e.ui.ddmanager.prepareOffsets(t,i)}}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js
new file mode 100644
index 0000000000..ea34c3ccdd
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){var e=/up|down|vertical/,i=/up|left|vertical|horizontal/;t.effects.effect.blind=function(s,n){var a,o,r,h=t(this),l=["position","top","bottom","left","right","height","width"],c=t.effects.setMode(h,s.mode||"hide"),u=s.direction||"up",d=e.test(u),p=d?"height":"width",f=d?"top":"left",m=i.test(u),g={},v="show"===c;h.parent().is(".ui-effects-wrapper")?t.effects.save(h.parent(),l):t.effects.save(h,l),h.show(),a=t.effects.createWrapper(h).css({overflow:"hidden"}),o=a[p](),r=parseFloat(a.css(f))||0,g[p]=v?o:0,m||(h.css(d?"bottom":"right",0).css(d?"top":"left","auto").css({position:"absolute"}),g[f]=v?r:o+r),v&&(a.css(p,0),m||a.css(f,r+o)),a.animate(g,{duration:s.duration,easing:s.easing,queue:!1,complete:function(){"hide"===c&&h.hide(),t.effects.restore(h,l),t.effects.removeWrapper(h),n()}})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js
new file mode 100644
index 0000000000..05a74f6eb7
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.bounce=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(o,e.mode||"effect"),l="hide"===h,c="show"===h,u=e.direction||"up",d=e.distance,p=e.times||5,f=2*p+(c||l?1:0),m=e.duration/f,g=e.easing,v="up"===u||"down"===u?"top":"left",_="up"===u||"left"===u,b=o.queue(),y=b.length;for((c||l)&&r.push("opacity"),t.effects.save(o,r),o.show(),t.effects.createWrapper(o),d||(d=o["top"===v?"outerHeight":"outerWidth"]()/3),c&&(a={opacity:1},a[v]=0,o.css("opacity",0).css(v,_?2*-d:2*d).animate(a,m,g)),l&&(d/=Math.pow(2,p-1)),a={},a[v]=0,s=0;p>s;s++)n={},n[v]=(_?"-=":"+=")+d,o.animate(n,m,g).animate(a,m,g),d=l?2*d:d/2;l&&(n={opacity:0},n[v]=(_?"-=":"+=")+d,o.animate(n,m,g)),o.queue(function(){l&&o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}),y>1&&b.splice.apply(b,[1,0].concat(b.splice(y,f+1))),o.dequeue()}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js
new file mode 100644
index 0000000000..5b15f8ef0a
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.clip=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","height","width"],h=t.effects.setMode(o,e.mode||"hide"),l="show"===h,c=e.direction||"vertical",u="vertical"===c,d=u?"height":"width",p=u?"top":"left",f={};t.effects.save(o,r),o.show(),s=t.effects.createWrapper(o).css({overflow:"hidden"}),n="IMG"===o[0].tagName?s:o,a=n[d](),l&&(n.css(d,0),n.css(p,a/2)),f[d]=l?a:0,f[p]=l?0:a/2,n.animate(f,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){l||o.hide(),t.effects.restore(o,r),t.effects.removeWrapper(o),i()}})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js
new file mode 100644
index 0000000000..02d148a161
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.drop=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","opacity","height","width"],o=t.effects.setMode(n,e.mode||"hide"),r="show"===o,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h?"pos":"neg",u={opacity:r?1:0};t.effects.save(n,a),n.show(),t.effects.createWrapper(n),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0)/2,r&&n.css("opacity",0).css(l,"pos"===c?-s:s),u[l]=(r?"pos"===c?"+=":"-=":"pos"===c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js
new file mode 100644
index 0000000000..096ff58f59
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.explode=function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),m||p.hide(),i()}var a,o,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=t.effects.setMode(p,e.mode||"hide"),m="show"===f,g=p.show().css("visibility","hidden").offset(),v=Math.ceil(p.outerWidth()/d),_=Math.ceil(p.outerHeight()/u),b=[];for(a=0;u>a;a++)for(h=g.top+a*_,c=a-(u-1)/2,o=0;d>o;o++)r=g.left+o*v,l=o-(d-1)/2,p.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-o*v,top:-a*_}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:v,height:_,left:r+(m?l*v:0),top:h+(m?c*_:0),opacity:m?0:1}).animate({left:r+(m?0:l*v),top:h+(m?0:c*_),opacity:m?1:0},e.duration||500,e.easing,s)}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js
new file mode 100644
index 0000000000..09d3a0ec04
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.fade=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"toggle");s.animate({opacity:n},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js
new file mode 100644
index 0000000000..6b323bcd3e
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.fold=function(e,i){var s,n,a=t(this),o=["position","top","bottom","left","right","height","width"],r=t.effects.setMode(a,e.mode||"hide"),h="show"===r,l="hide"===r,c=e.size||15,u=/([0-9]+)%/.exec(c),d=!!e.horizFirst,p=h!==d,f=p?["width","height"]:["height","width"],m=e.duration/2,g={},v={};t.effects.save(a,o),a.show(),s=t.effects.createWrapper(a).css({overflow:"hidden"}),n=p?[s.width(),s.height()]:[s.height(),s.width()],u&&(c=parseInt(u[1],10)/100*n[l?0:1]),h&&s.css(d?{height:0,width:c}:{height:c,width:0}),g[f[0]]=h?n[0]:c,v[f[1]]=h?n[1]:0,s.animate(g,m,e.easing).animate(v,m,e.easing,function(){l&&a.hide(),t.effects.restore(a,o),t.effects.removeWrapper(a),i()})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js
new file mode 100644
index 0000000000..8aac9b3147
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.highlight=function(e,i){var s=t(this),n=["backgroundImage","backgroundColor","opacity"],a=t.effects.setMode(s,e.mode||"show"),o={backgroundColor:s.css("backgroundColor")};"hide"===a&&(o.opacity=0),t.effects.save(s,n),s.show().css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(o,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===a&&s.hide(),t.effects.restore(s,n),i()}})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js
new file mode 100644
index 0000000000..1338dfa979
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.pulsate=function(e,i){var s,n=t(this),a=t.effects.setMode(n,e.mode||"show"),o="show"===a,r="hide"===a,h=o||"hide"===a,l=2*(e.times||5)+(h?1:0),c=e.duration/l,u=0,d=n.queue(),p=d.length;for((o||!n.is(":visible"))&&(n.css("opacity",0).show(),u=1),s=1;l>s;s++)n.animate({opacity:u},c,e.easing),u=1-u;n.animate({opacity:u},c,e.easing),n.queue(function(){r&&n.hide(),i()}),p>1&&d.splice.apply(d,[1,0].concat(d.splice(p,l+1))),n.dequeue()}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js
new file mode 100644
index 0000000000..0be8b0f317
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.puff=function(e,i){var s=t(this),n=t.effects.setMode(s,e.mode||"hide"),a="hide"===n,o=parseInt(e.percent,10)||150,r=o/100,h={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()};t.extend(e,{effect:"scale",queue:!1,fade:!0,mode:n,complete:i,percent:a?o:100,from:a?h:{height:h.height*r,width:h.width*r,outerHeight:h.outerHeight*r,outerWidth:h.outerWidth*r}}),s.effect(e)},t.effects.effect.scale=function(e,i){var s=t(this),n=t.extend(!0,{},e),a=t.effects.setMode(s,e.mode||"effect"),o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"hide"===a?0:100),r=e.direction||"both",h=e.origin,l={height:s.height(),width:s.width(),outerHeight:s.outerHeight(),outerWidth:s.outerWidth()},c={y:"horizontal"!==r?o/100:1,x:"vertical"!==r?o/100:1};n.effect="size",n.queue=!1,n.complete=i,"effect"!==a&&(n.origin=h||["middle","center"],n.restore=!0),n.from=e.from||("show"===a?{height:0,width:0,outerHeight:0,outerWidth:0}:l),n.to={height:l.height*c.y,width:l.width*c.x,outerHeight:l.outerHeight*c.y,outerWidth:l.outerWidth*c.x},n.fade&&("show"===a&&(n.from.opacity=0,n.to.opacity=1),"hide"===a&&(n.from.opacity=1,n.to.opacity=0)),s.effect(n)},t.effects.effect.size=function(e,i){var s,n,a,o=t(this),r=["position","top","bottom","left","right","width","height","overflow","opacity"],h=["position","top","bottom","left","right","overflow","opacity"],l=["width","height","overflow"],c=["fontSize"],u=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],d=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=t.effects.setMode(o,e.mode||"effect"),f=e.restore||"effect"!==p,m=e.scale||"both",g=e.origin||["middle","center"],v=o.css("position"),_=f?r:h,b={height:0,width:0,outerHeight:0,outerWidth:0};"show"===p&&o.show(),s={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},"toggle"===e.mode&&"show"===p?(o.from=e.to||b,o.to=e.from||s):(o.from=e.from||("show"===p?b:s),o.to=e.to||("hide"===p?b:s)),a={from:{y:o.from.height/s.height,x:o.from.width/s.width},to:{y:o.to.height/s.height,x:o.to.width/s.width}},("box"===m||"both"===m)&&(a.from.y!==a.to.y&&(_=_.concat(u),o.from=t.effects.setTransition(o,u,a.from.y,o.from),o.to=t.effects.setTransition(o,u,a.to.y,o.to)),a.from.x!==a.to.x&&(_=_.concat(d),o.from=t.effects.setTransition(o,d,a.from.x,o.from),o.to=t.effects.setTransition(o,d,a.to.x,o.to))),("content"===m||"both"===m)&&a.from.y!==a.to.y&&(_=_.concat(c).concat(l),o.from=t.effects.setTransition(o,c,a.from.y,o.from),o.to=t.effects.setTransition(o,c,a.to.y,o.to)),t.effects.save(o,_),o.show(),t.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),g&&(n=t.effects.getBaseline(g,s),o.from.top=(s.outerHeight-o.outerHeight())*n.y,o.from.left=(s.outerWidth-o.outerWidth())*n.x,o.to.top=(s.outerHeight-o.to.outerHeight)*n.y,o.to.left=(s.outerWidth-o.to.outerWidth)*n.x),o.css(o.from),("content"===m||"both"===m)&&(u=u.concat(["marginTop","marginBottom"]).concat(c),d=d.concat(["marginLeft","marginRight"]),l=r.concat(u).concat(d),o.find("*[width]").each(function(){var i=t(this),s={height:i.height(),width:i.width(),outerHeight:i.outerHeight(),outerWidth:i.outerWidth()};f&&t.effects.save(i,l),i.from={height:s.height*a.from.y,width:s.width*a.from.x,outerHeight:s.outerHeight*a.from.y,outerWidth:s.outerWidth*a.from.x},i.to={height:s.height*a.to.y,width:s.width*a.to.x,outerHeight:s.height*a.to.y,outerWidth:s.width*a.to.x},a.from.y!==a.to.y&&(i.from=t.effects.setTransition(i,u,a.from.y,i.from),i.to=t.effects.setTransition(i,u,a.to.y,i.to)),a.from.x!==a.to.x&&(i.from=t.effects.setTransition(i,d,a.from.x,i.from),i.to=t.effects.setTransition(i,d,a.to.x,i.to)),i.css(i.from),i.animate(i.to,e.duration,e.easing,function(){f&&t.effects.restore(i,l)})})),o.animate(o.to,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){0===o.to.opacity&&o.css("opacity",o.from.opacity),"hide"===p&&o.hide(),t.effects.restore(o,_),f||("static"===v?o.css({position:"relative",top:o.to.top,left:o.to.left}):t.each(["top","left"],function(t,e){o.css(e,function(e,i){var s=parseInt(i,10),n=t?o.to.left:o.to.top;return"auto"===i?n+"px":s+n+"px"})})),t.effects.removeWrapper(o),i()}})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js
new file mode 100644
index 0000000000..8bfffec5f0
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.shake=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","height","width"],o=t.effects.setMode(n,e.mode||"effect"),r=e.direction||"left",h=e.distance||20,l=e.times||3,c=2*l+1,u=Math.round(e.duration/c),d="up"===r||"down"===r?"top":"left",p="up"===r||"left"===r,f={},m={},g={},v=n.queue(),_=v.length;for(t.effects.save(n,a),n.show(),t.effects.createWrapper(n),f[d]=(p?"-=":"+=")+h,m[d]=(p?"+=":"-=")+2*h,g[d]=(p?"-=":"+=")+2*h,n.animate(f,u,e.easing),s=1;l>s;s++)n.animate(m,u,e.easing).animate(g,u,e.easing);n.animate(m,u,e.easing).animate(f,u/2,e.easing).queue(function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}),_>1&&v.splice.apply(v,[1,0].concat(v.splice(_,c+1))),n.dequeue()}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js
new file mode 100644
index 0000000000..b3de22e04f
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.slide=function(e,i){var s,n=t(this),a=["position","top","bottom","left","right","width","height"],o=t.effects.setMode(n,e.mode||"show"),r="show"===o,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u={};t.effects.save(n,a),n.show(),s=e.distance||n["top"===l?"outerHeight":"outerWidth"](!0),t.effects.createWrapper(n).css({overflow:"hidden"}),r&&n.css(l,c?isNaN(s)?"-"+s:-s:s),u[l]=(r?c?"+=":"-=":c?"-=":"+=")+s,n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){"hide"===o&&n.hide(),t.effects.restore(n,a),t.effects.removeWrapper(n),i()}})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js
new file mode 100644
index 0000000000..cec83690d8
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.effects.effect.transfer=function(e,i){var s=t(this),n=t(e.to),a="fixed"===n.css("position"),o=t("body"),r=a?o.scrollTop():0,h=a?o.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:a?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),i()})}})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.effect.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.effect.min.js
new file mode 100644
index 0000000000..50fbc7992b
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.effect.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t,e){var i="ui-effects-";t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,a){var o,r=a.re.exec(i),h=r&&a.parse(r),l=a.space||"rgba";return h?(o=s[l](h),s[c[l].cache]=o[c[l].cache],n=s._rgba=o._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,a.transparent),s):a[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var a,o="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("<p>")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,o,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(o),o=e);var u=this,d=t.type(n),p=this._rgba=[];return o!==e&&(n=[n,o,r,h],d="array"),"string"===d?this.parse(s(n)||a._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var a=s.cache;f(s.props,function(t,e){if(!u[a]&&s.to){if("alpha"===t||null==n[t])return;u[a]=s.to(u._rgba)}u[a][e.idx]=i(n[t],e,!0)}),u[a]&&0>t.inArray(null,u[a].slice(0,3))&&(u[a][3]=1,s.from&&(u._rgba=s.from(u[a])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,a){var o,r=i[a.cache];return r&&(o=n[a.cache]||a.to&&a.to(n._rgba)||[],f(a.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===o[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),a=c[n],o=0===this.alpha()?l("transparent"):this,r=o[a.cache]||a.to(o._rgba),h=r.slice();return s=s[a.cache],f(a.props,function(t,n){var a=n.idx,o=r[a],l=s[a],c=u[n.type]||{};null!==l&&(null===o?h[a]=l:(c.mod&&(l-o>c.mod/2?o+=c.mod:o-l>c.mod/2&&(o-=c.mod)),h[a]=i((l-o)*e+o,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,a=t[2]/255,o=t[3],r=Math.max(s,n,a),h=Math.min(s,n,a),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-a)/l+360:n===r?60*(a-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==o?1:o]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],a=t[3],o=.5>=s?s*(1+i):s+i-s*i,r=2*s-o;return[Math.round(255*n(r,o,e+1/3)),Math.round(255*n(r,o,e)),Math.round(255*n(r,o,e-1/3)),a]},f(c,function(s,n){var a=n.props,o=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[o]&&(this[o]=h(this._rgba)),s===e)return this[o].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[o].slice();return f(a,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[o]=d,n):l(d)},f(a,function(e,i){l.fn[e]||(l.fn[e]=function(n){var a,o=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===o?c:("function"===o&&(n=n.call(this,c),o=t.type(n)),null==n&&i.empty?this:("string"===o&&(a=r.exec(n),a&&(n=c+parseFloat(a[2])*("+"===a[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var a,o,r="";if("transparent"!==n&&("string"!==t.type(n)||(a=s(n)))){if(n=l(a||n),!d.rgba&&1!==n._rgba[3]){for(o="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&o&&o.style;)try{r=t.css(o,"backgroundColor"),o=o.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(o),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},a=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,a={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(a[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(a[i]=n[i]);return a}function s(e,i){var s,n,o={};for(s in i)n=i[s],e[s]!==n&&(a[s]||(t.fx.step[s]||!isNaN(parseFloat(n)))&&(o[s]=n));return o}var n=["add","remove","toggle"],a={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(jQuery.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(e,a,o,r){var h=t.speed(a,o,r);return this.queue(function(){var a,o=t(this),r=o.attr("class")||"",l=h.children?o.find("*").addBack():o;l=l.map(function(){var e=t(this);return{el:e,start:i(this)}}),a=function(){t.each(n,function(t,i){e[i]&&o[i+"Class"](e[i])})},a(),l=l.map(function(){return this.end=i(this.el[0]),this.diff=s(this.start,this.end),this}),o.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){a(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(o[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,a){return s?t.effects.animateClass.call(this,{add:i},s,n,a):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,a){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,a):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(i){return function(s,n,a,o,r){return"boolean"==typeof n||n===e?a?t.effects.animateClass.call(this,n?{add:s}:{remove:s},a,o,r):i.apply(this,arguments):t.effects.animateClass.call(this,{toggle:s},n,a,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,a){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,a)}})}(),function(){function s(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function n(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}t.extend(t.effects,{version:"1.10.3",save:function(t,e){for(var s=0;e.length>s;s++)null!==e[s]&&t.data(i+e[s],t[0].style[e[s]])},restore:function(t,s){var n,a;for(a=0;s.length>a;a++)null!==s[a]&&(n=t.data(i+s[a]),n===e&&(n=""),t.css(s[a],n))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},a=document.activeElement;try{a.id}catch(o){a=document.body}return e.wrap(s),(e[0]===a||t.contains(e[0],a))&&t(a).focus(),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).focus()),e},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var a=e.cssUnit(i);a[0]>0&&(n[i]=a[0]*s+a[1])}),n}}),t.fn.extend({effect:function(){function e(e){function s(){t.isFunction(a)&&a.call(n[0]),t.isFunction(e)&&e()}var n=t(this),a=i.complete,r=i.mode;(n.is(":hidden")?"hide"===r:"show"===r)?(n[r](),s()):o.call(n[0],i,s)}var i=s.apply(this,arguments),n=i.mode,a=i.queue,o=t.effects.effect[i.effect];return t.fx.off||!o?n?this[n](i.duration,i.complete):this.each(function(){i.complete&&i.complete.call(this)}):a===!1?this.each(e):this.queue(a||"fx",e)},show:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="show",this.effect.call(this,i)}}(t.fn.show),hide:function(t){return function(e){if(n(e))return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="hide",this.effect.call(this,i)}}(t.fn.hide),toggle:function(t){return function(e){if(n(e)||"boolean"==typeof e)return t.apply(this,arguments);var i=s.apply(this,arguments);return i.mode="toggle",this.effect.call(this,i)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s}})}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}()})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.menu.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.menu.min.js
new file mode 100644
index 0000000000..113d53fb1c
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.menu.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){t.widget("ui.menu",{version:"1.10.3",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,t.proxy(function(t){this.options.disabled&&t.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(t){t.preventDefault()},"click .ui-state-disabled > a":function(t){t.preventDefault()},"click .ui-menu-item:has(a)":function(e){var i=t(e.target).closest(".ui-menu-item");!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.mouseHandled=!0,this.select(e),i.has(".ui-menu").length?this.expand(e):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){var i=t(e.currentTarget);i.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(e,i)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.children(".ui-menu-item").eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(e){t(e.target).closest(".ui-menu").length||this.collapseAll(e),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){function i(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var s,n,a,o,r,h=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:h=!1,n=this.previousFilter||"",a=String.fromCharCode(e.keyCode),o=!1,clearTimeout(this.filterTimer),a===n?o=!0:a=n+a,r=RegExp("^"+i(a),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())}),s=o&&-1!==s.index(this.active.next())?this.active.nextAll(".ui-menu-item"):s,s.length||(a=String.fromCharCode(e.keyCode),r=RegExp("^"+i(a),"i"),s=this.activeMenu.children(".ui-menu-item").filter(function(){return r.test(t(this).children("a").text())})),s.length?(this.focus(e,s),s.length>1?(this.previousFilter=a,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}h&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i=this.options.icons.submenu,s=this.element.find(this.options.menus);s.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),s=e.prev("a"),n=t("<span>").addClass("ui-menu-icon ui-icon "+i).data("ui-menu-submenu-carat",!0);s.attr("aria-haspopup","true").prepend(n),e.attr("aria-labelledby",s.attr("id"))}),e=s.add(this.element),e.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),e.children(":not(.ui-menu-item)").each(function(){var e=t(this);/[^\-\u2014\u2013\s]/.test(e.text())||e.addClass("ui-widget-content ui-menu-divider")}),e.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),this._super(t,e)},focus:function(t,e){var i,s;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,a,o,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,a=this.activeMenu.scrollTop(),o=this.activeMenu.height(),r=e.height(),0>n?this.activeMenu.scrollTop(a+n):n+r>o&&this.activeMenu.scrollTop(a+n-o+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.children(".ui-menu-item")[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())),undefined):(this.next(e),undefined)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.children(".ui-menu-item").first())),undefined):(this.next(e),undefined)},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight")},select:function(e){this.active=this.active||t(e.target).closest(".ui-menu-item");var i={item:this.active};this.active.has(".ui-menu").length||this.collapseAll(e,!0),this._trigger("select",e,i)}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.mouse.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.mouse.min.js
new file mode 100644
index 0000000000..b7361fb7a9
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.mouse.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.3",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.position.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.position.min.js
new file mode 100644
index 0000000000..9bd2ecd47d
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.position.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t,e){function i(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function s(e,i){return parseInt(t.css(e,i),10)||0}function n(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,c=/top|center|bottom/,u=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(a!==e)return a;var i,s,n=t("<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>"),o=n.children()[0];return t("body").append(n),i=o.offsetWidth,n.css("overflow","scroll"),s=o.offsetWidth,i===s&&(s=n[0].clientWidth),n.remove(),a=i-s},getScrollInfo:function(e){var i=e.isWindow?"":e.element.css("overflow-x"),s=e.isWindow?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.width<e.element[0].scrollWidth,a="scroll"===s||"auto"===s&&e.height<e.element[0].scrollHeight;return{width:a?t.position.scrollbarWidth():0,height:n?t.position.scrollbarWidth():0}},getWithinInfo:function(e){var i=t(e||window),s=t.isWindow(i[0]);return{element:i,isWindow:s,offset:i.offset()||{left:0,top:0},scrollLeft:i.scrollLeft(),scrollTop:i.scrollTop(),width:s?i.width():i.outerWidth(),height:s?i.height():i.outerHeight()}}},t.fn.position=function(e){if(!e||!e.of)return f.apply(this,arguments);e=t.extend({},e);var a,p,m,g,v,b,_=t(e.of),y=t.position.getWithinInfo(e.within),w=t.position.getScrollInfo(y),x=(e.collision||"flip").split(" "),k={};return b=n(_),_[0].preventDefault&&(e.at="left top"),p=b.width,m=b.height,g=b.offset,v=t.extend({},g),t.each(["my","at"],function(){var t,i,s=(e[this]||"").split(" ");1===s.length&&(s=l.test(s[0])?s.concat(["center"]):c.test(s[0])?["center"].concat(s):["center","center"]),s[0]=l.test(s[0])?s[0]:"center",s[1]=c.test(s[1])?s[1]:"center",t=u.exec(s[0]),i=u.exec(s[1]),k[this]=[t?t[0]:0,i?i[0]:0],e[this]=[d.exec(s[0])[0],d.exec(s[1])[0]]}),1===x.length&&(x[1]=x[0]),"right"===e.at[0]?v.left+=p:"center"===e.at[0]&&(v.left+=p/2),"bottom"===e.at[1]?v.top+=m:"center"===e.at[1]&&(v.top+=m/2),a=i(k.at,p,m),v.left+=a[0],v.top+=a[1],this.each(function(){var n,l,c=t(this),u=c.outerWidth(),d=c.outerHeight(),f=s(this,"marginLeft"),b=s(this,"marginTop"),D=u+f+s(this,"marginRight")+w.width,T=d+b+s(this,"marginBottom")+w.height,C=t.extend({},v),M=i(k.my,c.outerWidth(),c.outerHeight());"right"===e.my[0]?C.left-=u:"center"===e.my[0]&&(C.left-=u/2),"bottom"===e.my[1]?C.top-=d:"center"===e.my[1]&&(C.top-=d/2),C.left+=M[0],C.top+=M[1],t.support.offsetFractions||(C.left=h(C.left),C.top=h(C.top)),n={marginLeft:f,marginTop:b},t.each(["left","top"],function(i,s){t.ui.position[x[i]]&&t.ui.position[x[i]][s](C,{targetWidth:p,targetHeight:m,elemWidth:u,elemHeight:d,collisionPosition:n,collisionWidth:D,collisionHeight:T,offset:[a[0]+M[0],a[1]+M[1]],my:e.my,at:e.at,within:y,elem:c})}),e.using&&(l=function(t){var i=g.left-C.left,s=i+p-u,n=g.top-C.top,a=n+m-d,h={target:{element:_,left:g.left,top:g.top,width:p,height:m},element:{element:c,left:C.left,top:C.top,width:u,height:d},horizontal:0>s?"left":i>0?"right":"center",vertical:0>a?"top":n>0?"bottom":"middle"};u>p&&p>r(i+s)&&(h.horizontal="center"),d>m&&m>r(n+a)&&(h.vertical="middle"),h.important=o(r(i),r(s))>o(r(n),r(a))?"horizontal":"vertical",e.using.call(this,t,h)}),c.offset(t.extend(C,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-o-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-o-a,(0>i||r(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-o-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-o-a,t.top+p+f+m>c&&(0>s||r(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,t.top+p+f+m>u&&(i>0||u>r(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,a,o=document.getElementsByTagName("body")[0],r=document.createElement("div");e=document.createElement(o?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},o&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(a in s)e.style[a]=s[a];e.appendChild(r),i=o||document.documentElement,i.insertBefore(e,i.firstChild),r.style.cssText="position: absolute; left: 10.7432222px;",n=t(r).offset().left,t.support.offsetFractions=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js
new file mode 100644
index 0000000000..432ec0260a
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t,e){t.widget("ui.progressbar",{version:"1.10.3",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min}),this.valueDiv=t("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(t){return t===e?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),e)},_constrainedValue:function(t){return t===e&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(i.toFixed(0)+"%"),this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.resizable.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.resizable.min.js
new file mode 100644
index 0000000000..1c29259e4f
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.resizable.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){function t(e){return parseInt(e,10)||0}function i(e){return!isNaN(parseInt(e,10))}e.widget("ui.resizable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("<div class='ui-resizable-handle "+a+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=e(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=t(this.helper.css("left")),n=t(this.helper.css("top")),o.containment&&(s+=e(o.containment).scrollLeft()||0,n+=e(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(t){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,u=this.size.height,c=t.pageX-a.left||0,d=t.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[t,c,d]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==u&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(n)||this._trigger("resize",t,this.ui()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&e.ui.hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||e)&&(t=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,t>o.minWidth&&(o.minWidth=t),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(e){this.offset=this.helper.offset(),i(e.left)&&(this.position.left=e.left),i(e.top)&&(this.position.top=e.top),i(e.height)&&(this.size.height=e.height),i(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,s=this.size,n=this.axis;return i(e.height)?e.width=e.height*this.aspectRatio:i(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===n&&(e.left=t.left+(s.width-e.width),e.top=null),"nw"===n&&(e.top=t.top+(s.height-e.height),e.left=t.left+(s.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,s=this.axis,n=i(e.width)&&t.maxWidth&&t.maxWidth<e.width,a=i(e.height)&&t.maxHeight&&t.maxHeight<e.height,o=i(e.width)&&t.minWidth&&t.minWidth>e.width,r=i(e.height)&&t.minHeight&&t.minHeight>e.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,u=/sw|nw|w/.test(s),c=/nw|ne|n/.test(s);return o&&(e.width=t.minWidth),r&&(e.height=t.minHeight),n&&(e.width=t.maxWidth),a&&(e.height=t.maxHeight),o&&u&&(e.left=h-t.minWidth),n&&u&&(e.left=h-t.maxWidth),r&&c&&(e.top=l-t.minHeight),a&&c&&(e.top=l-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var e,t,i,s,n,a=this.helper||this.element;for(e=0;this._proportionallyResizeElements.length>e;e++){if(n=this._proportionallyResizeElements[e],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],t=0;i.length>t;t++)this.borderDif[t]=(parseInt(i[t],10)||0)+(parseInt(s[t],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&e.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=e(this).data("ui-resizable"),u=l.options,c=l.element,d=u.containment,p=d instanceof e?d.get(0):/parent/.test(d)?c.parent().get(0):d;p&&(l.containerElement=e(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(i=e(p),s=[],e(["Top","Right","Left","Bottom"]).each(function(e,n){s[e]=t(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=e.ui.hasScroll(p,"left")?p.scrollWidth:o,h=e.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(t){var i,s,n,a,o=e(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,c={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(c=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-c.left),u&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-c.left:o.offset.left-c.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-c.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=o.parentData.left),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).data("ui-resizable");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).data("ui-resizable");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size,n=t.originalSize,a=t.originalPosition,o=t.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,u=Math.round((s.width-n.width)/h)*h,c=Math.round((s.height-n.height)/l)*l,d=n.width+u,p=n.height+c,f=i.maxWidth&&d>i.maxWidth,m=i.maxHeight&&p>i.maxHeight,g=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,g&&(d+=h),v&&(p+=l),f&&(d-=h),m&&(p-=l),/^(se|s|e)$/.test(o)?(t.size.width=d,t.size.height=p):/^(ne)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.top=a.top-c):/^(sw)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.left=a.left-u):(t.size.width=d,t.size.height=p,t.position.top=a.top-c,t.position.left=a.left-u)}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.selectable.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.selectable.min.js
new file mode 100644
index 0000000000..2ac1c60c7a
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.selectable.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){e.widget("ui.selectable",e.ui.mouse,{version:"1.10.3",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var t,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){t=e(i.options.filter,i.element[0]),t.addClass("ui-selectee"),t.each(function(){var t=e(this),i=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:i.left,top:i.top,right:i.left+t.outerWidth(),bottom:i.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=t.addClass("ui-selectee"),this._mouseInit(),this.helper=e("<div class='ui-selectable-helper'></div>")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var i=this,s=this.options;this.opos=[t.pageX,t.pageY],this.options.disabled||(this.selectees=e(s.filter,this.element[0]),this._trigger("start",t),e(s.appendTo).append(this.helper),this.helper.css({left:t.pageX,top:t.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=e.data(this,"selectable-item");s.startselected=!0,t.metaKey||t.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",t,{unselecting:s.element}))}),e(t.target).parents().addBack().each(function(){var s,n=e.data(this,"selectable-item");return n?(s=!t.metaKey&&!t.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",t,{selecting:n.element}):i._trigger("unselecting",t,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(t){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=t.pageX,h=t.pageY;return a>r&&(i=r,r=a,a=i),o>h&&(i=h,h=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:h-o}),this.selectees.each(function(){var i=e.data(this,"selectable-item"),l=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?l=!(i.left>r||a>i.right||i.top>h||o>i.bottom):"fit"===n.tolerance&&(l=i.left>a&&r>i.right&&i.top>o&&h>i.bottom),l?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",t,{selecting:i.element}))):(i.selecting&&((t.metaKey||t.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",t,{unselecting:i.element}))),i.selected&&(t.metaKey||t.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",t,{unselecting:i.element})))))}),!1}},_mouseStop:function(t){var i=this;return this.dragged=!1,e(".ui-unselecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",t,{unselected:s.element})}),e(".ui-selecting",this.element[0]).each(function(){var s=e.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",t,{selected:s.element})}),this._trigger("stop",t),this.helper.remove(),!1}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.slider.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.slider.min.js
new file mode 100644
index 0000000000..7e31927217
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.slider.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){var e=5;t.widget("ui.slider",t.ui.mouse,{version:"1.10.3",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"),this._refresh(),this._setOption("disabled",this.options.disabled),this._animateOff=!1},_refresh:function(){this._createRange(),this._createHandles(),this._setupEvents(),this._refreshValue()},_createHandles:function(){var e,i,s=this.options,n=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),a="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",o=[];for(i=s.values&&s.values.length||1,n.length>i&&(n.slice(i).remove(),n=n.slice(0,i)),e=n.length;i>e;e++)o.push(a);this.handles=n.add(t(o.join("")).appendTo(this.element)),this.handle=this.handles.eq(0),this.handles.each(function(e){t(this).data("ui-slider-handle-index",e)})},_createRange:function(){var e=this.options,i="";e.range?(e.range===!0&&(e.values?e.values.length&&2!==e.values.length?e.values=[e.values[0],e.values[0]]:t.isArray(e.values)&&(e.values=e.values.slice(0)):e.values=[this._valueMin(),this._valueMin()]),this.range&&this.range.length?this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({left:"",bottom:""}):(this.range=t("<div></div>").appendTo(this.element),i="ui-slider-range ui-widget-header ui-corner-all"),this.range.addClass(i+("min"===e.range||"max"===e.range?" ui-slider-range-"+e.range:""))):this.range=t([])},_setupEvents:function(){var t=this.handles.add(this.range).filter("a");this._off(t),this._on(t,this._handleEvents),this._hoverable(t),this._focusable(t)},_destroy:function(){this.handles.remove(),this.range.remove(),this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all"),this._mouseDestroy()},_mouseCapture:function(e){var i,s,n,a,o,r,h,l,u=this,c=this.options;return c.disabled?!1:(this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()},this.elementOffset=this.element.offset(),i={x:e.pageX,y:e.pageY},s=this._normValueFromMouse(i),n=this._valueMax()-this._valueMin()+1,this.handles.each(function(e){var i=Math.abs(s-u.values(e));(n>i||n===i&&(e===u._lastChangedValue||u.values(e)===c.min))&&(n=i,a=t(this),o=e)}),r=this._start(e,o),r===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,a.addClass("ui-state-active").focus(),h=a.offset(),l=!t(e.target).parents().addBack().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:e.pageX-h.left-a.width()/2,top:e.pageY-h.top-a.height()/2-(parseInt(a.css("borderTopWidth"),10)||0)-(parseInt(a.css("borderBottomWidth"),10)||0)+(parseInt(a.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(e,o,s),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(t){var e={x:t.pageX,y:t.pageY},i=this._normValueFromMouse(e);return this._slide(t,this._handleIndex,i),!1},_mouseStop:function(t){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(t,this._handleIndex),this._change(t,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation="vertical"===this.options.orientation?"vertical":"horizontal"},_normValueFromMouse:function(t){var e,i,s,n,a;return"horizontal"===this.orientation?(e=this.elementSize.width,i=t.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(e=this.elementSize.height,i=t.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),s=i/e,s>1&&(s=1),0>s&&(s=0),"vertical"===this.orientation&&(s=1-s),n=this._valueMax()-this._valueMin(),a=this._valueMin()+s*n,this._trimAlignValue(a)},_start:function(t,e){var i={handle:this.handles[e],value:this.value()};return this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("start",t,i)},_slide:function(t,e,i){var s,n,a;this.options.values&&this.options.values.length?(s=this.values(e?0:1),2===this.options.values.length&&this.options.range===!0&&(0===e&&i>s||1===e&&s>i)&&(i=s),i!==this.values(e)&&(n=this.values(),n[e]=i,a=this._trigger("slide",t,{handle:this.handles[e],value:i,values:n}),s=this.values(e?0:1),a!==!1&&this.values(e,i,!0))):i!==this.value()&&(a=this._trigger("slide",t,{handle:this.handles[e],value:i}),a!==!1&&this.value(i))},_stop:function(t,e){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._trigger("stop",t,i)},_change:function(t,e){if(!this._keySliding&&!this._mouseSliding){var i={handle:this.handles[e],value:this.value()};this.options.values&&this.options.values.length&&(i.value=this.values(e),i.values=this.values()),this._lastChangedValue=e,this._trigger("change",t,i)}},value:function(t){return arguments.length?(this.options.value=this._trimAlignValue(t),this._refreshValue(),this._change(null,0),undefined):this._value()},values:function(e,i){var s,n,a;if(arguments.length>1)return this.options.values[e]=this._trimAlignValue(i),this._refreshValue(),this._change(null,e),undefined;if(!arguments.length)return this._values();if(!t.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(e):this.value();for(s=this.options.values,n=arguments[0],a=0;s.length>a;a+=1)s[a]=this._trimAlignValue(n[a]),this._change(null,a);this._refreshValue()},_setOption:function(e,i){var s,n=0;switch("range"===e&&this.options.range===!0&&("min"===i?(this.options.value=this._values(0),this.options.values=null):"max"===i&&(this.options.value=this._values(this.options.values.length-1),this.options.values=null)),t.isArray(this.options.values)&&(n=this.options.values.length),t.Widget.prototype._setOption.apply(this,arguments),e){case"orientation":this._detectOrientation(),this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation),this._refreshValue();break;case"value":this._animateOff=!0,this._refreshValue(),this._change(null,0),this._animateOff=!1;break;case"values":for(this._animateOff=!0,this._refreshValue(),s=0;n>s;s+=1)this._change(null,s);this._animateOff=!1;break;case"min":case"max":this._animateOff=!0,this._refreshValue(),this._animateOff=!1;break;case"range":this._animateOff=!0,this._refresh(),this._animateOff=!1}},_value:function(){var t=this.options.value;return t=this._trimAlignValue(t)},_values:function(t){var e,i,s;if(arguments.length)return e=this.options.values[t],e=this._trimAlignValue(e);if(this.options.values&&this.options.values.length){for(i=this.options.values.slice(),s=0;i.length>s;s+=1)i[s]=this._trimAlignValue(i[s]);return i}return[]},_trimAlignValue:function(t){if(this._valueMin()>=t)return this._valueMin();if(t>=this._valueMax())return this._valueMax();var e=this.options.step>0?this.options.step:1,i=(t-this._valueMin())%e,s=t-i;return 2*Math.abs(i)>=e&&(s+=i>0?e:-e),parseFloat(s.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var e,i,s,n,a,o=this.options.range,r=this.options,h=this,l=this._animateOff?!1:r.animate,u={};this.options.values&&this.options.values.length?this.handles.each(function(s){i=100*((h.values(s)-h._valueMin())/(h._valueMax()-h._valueMin())),u["horizontal"===h.orientation?"left":"bottom"]=i+"%",t(this).stop(1,1)[l?"animate":"css"](u,r.animate),h.options.range===!0&&("horizontal"===h.orientation?(0===s&&h.range.stop(1,1)[l?"animate":"css"]({left:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({width:i-e+"%"},{queue:!1,duration:r.animate})):(0===s&&h.range.stop(1,1)[l?"animate":"css"]({bottom:i+"%"},r.animate),1===s&&h.range[l?"animate":"css"]({height:i-e+"%"},{queue:!1,duration:r.animate}))),e=i}):(s=this.value(),n=this._valueMin(),a=this._valueMax(),i=a!==n?100*((s-n)/(a-n)):0,u["horizontal"===this.orientation?"left":"bottom"]=i+"%",this.handle.stop(1,1)[l?"animate":"css"](u,r.animate),"min"===o&&"horizontal"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({width:i+"%"},r.animate),"max"===o&&"horizontal"===this.orientation&&this.range[l?"animate":"css"]({width:100-i+"%"},{queue:!1,duration:r.animate}),"min"===o&&"vertical"===this.orientation&&this.range.stop(1,1)[l?"animate":"css"]({height:i+"%"},r.animate),"max"===o&&"vertical"===this.orientation&&this.range[l?"animate":"css"]({height:100-i+"%"},{queue:!1,duration:r.animate}))},_handleEvents:{keydown:function(i){var s,n,a,o,r=t(i.target).data("ui-slider-handle-index");switch(i.keyCode){case t.ui.keyCode.HOME:case t.ui.keyCode.END:case t.ui.keyCode.PAGE_UP:case t.ui.keyCode.PAGE_DOWN:case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(i.preventDefault(),!this._keySliding&&(this._keySliding=!0,t(i.target).addClass("ui-state-active"),s=this._start(i,r),s===!1))return}switch(o=this.options.step,n=a=this.options.values&&this.options.values.length?this.values(r):this.value(),i.keyCode){case t.ui.keyCode.HOME:a=this._valueMin();break;case t.ui.keyCode.END:a=this._valueMax();break;case t.ui.keyCode.PAGE_UP:a=this._trimAlignValue(n+(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.PAGE_DOWN:a=this._trimAlignValue(n-(this._valueMax()-this._valueMin())/e);break;case t.ui.keyCode.UP:case t.ui.keyCode.RIGHT:if(n===this._valueMax())return;a=this._trimAlignValue(n+o);break;case t.ui.keyCode.DOWN:case t.ui.keyCode.LEFT:if(n===this._valueMin())return;a=this._trimAlignValue(n-o)}this._slide(i,r,a)},click:function(t){t.preventDefault()},keyup:function(e){var i=t(e.target).data("ui-slider-handle-index");this._keySliding&&(this._keySliding=!1,this._stop(e,i),this._change(e,i),t(e.target).removeClass("ui-state-active"))}}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.sortable.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.sortable.min.js
new file mode 100644
index 0000000000..1a84db7ae1
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.sortable.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.3",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,a=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,a.widgetName+"-item")===a?(s=t(this),!1):undefined}),t.data(e.target,a.widgetName+"-item")===a&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,a,o=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),o.containment&&this._setContainment(),o.cursor&&"auto"!==o.cursor&&(a=this.document.find("body"),this.storedCursor=a.css("cursor"),a.css("cursor",o.cursor),this.storedStylesheet=t("<style>*{ cursor: "+o.cursor+" !important; }</style>").appendTo(a)),o.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",o.opacity)),o.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",o.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!o.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,a,o=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY<o.scrollSensitivity?this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop+o.scrollSpeed:e.pageY-this.overflowOffset.top<o.scrollSensitivity&&(this.scrollParent[0].scrollTop=r=this.scrollParent[0].scrollTop-o.scrollSpeed),this.overflowOffset.left+this.scrollParent[0].offsetWidth-e.pageX<o.scrollSensitivity?this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft+o.scrollSpeed:e.pageX-this.overflowOffset.left<o.scrollSensitivity&&(this.scrollParent[0].scrollLeft=r=this.scrollParent[0].scrollLeft-o.scrollSpeed)):(e.pageY-t(document).scrollTop()<o.scrollSensitivity?r=t(document).scrollTop(t(document).scrollTop()-o.scrollSpeed):t(window).height()-(e.pageY-t(document).scrollTop())<o.scrollSensitivity&&(r=t(document).scrollTop(t(document).scrollTop()+o.scrollSpeed)),e.pageX-t(document).scrollLeft()<o.scrollSensitivity?r=t(document).scrollLeft(t(document).scrollLeft()-o.scrollSpeed):t(window).width()-(e.pageX-t(document).scrollLeft())<o.scrollSensitivity&&(r=t(document).scrollLeft(t(document).scrollLeft()+o.scrollSpeed))),r!==!1&&t.ui.ddmanager&&!o.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e)),this.positionAbs=this._convertPositionTo("absolute"),this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),i=this.items.length-1;i>=0;i--)if(s=this.items[i],n=s.item[0],a=this._intersectsWithPointer(s),a&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===a?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===a?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),a=this.options.axis,o={};a&&"x"!==a||(o.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),a&&"y"!==a||(o.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(o,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,a=t.left,o=a+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>a&&o>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>a&&o>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,a=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return n?this.floating?o&&"right"===o||"down"===a?2:1:a&&("down"===a?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return this.floating&&a?"right"===a&&s||"left"===a&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){var i,s,n,a,o=[],r=[],h=this._connectWith();if(h&&e)for(i=h.length-1;i>=0;i--)for(n=t(h[i]),s=n.length-1;s>=0;s--)a=t.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&r.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(r.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),i=r.length-1;i>=0;i--)r[i][0].each(function(){o.push(this)});return t(o)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,a,o,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)a=t.data(n[s],this.widgetFullName),a&&a!==this&&!a.options.disabled&&(u.push([t.isFunction(a.options.items)?a.options.items.call(a.element[0],e,{item:this.currentItem}):t(a.options.items,a.element),a]),this.containers.push(a));for(i=u.length-1;i>=0;i--)for(o=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",o),c.push({item:h,instance:o,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,a;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),a=n.offset(),s.left=a.left,s.top=a.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)a=this.containers[i].element.offset(),this.containers[i].containerCache.left=a.left,this.containers[i].containerCache.top=a.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?e.currentItem.children().each(function(){t("<td>&#160;</td>",e.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,a,o,r,h,l,c,u,d,p,f=null,m=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],m=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[m].containerCache.over||(this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1);else{for(o=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],a=this.items.length-1;a>=0;a--)t.contains(this.containers[m].element[0],this.items[a].item[0])&&this.items[a].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[a].top,this.items[a].height))&&(u=this.items[a].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[a][l]-c)&&(d=!0,u+=this.items[a][l]),o>Math.abs(u-c)&&(o=Math.abs(u-c),r=this.items[a],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[m])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[m].element,!0),this._trigger("change",s,this._uiHash()),this.containers[m]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[m],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[m]._trigger("over",s,this._uiHash(this)),this.containers[m].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,a=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():a?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():a?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,a=e.pageX,o=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.left<this.containment[0]&&(a=this.containment[0]+this.offset.click.left),e.pageY-this.offset.click.top<this.containment[1]&&(o=this.containment[1]+this.offset.click.top),e.pageX-this.offset.click.left>this.containment[2]&&(a=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1],o=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((a-this.originalPageX)/n.grid[0])*n.grid[0],a=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:o-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:a-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)("auto"===this._storedCSS[i]||"static"===this._storedCSS[i])&&(this._storedCSS[i]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;i>=0;i--)e||s.push(function(t){return function(e){t._trigger("deactivate",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(function(t){return function(e){t._trigger("out",e,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(i=0;s.length>i;i++)s[i].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.spinner.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.spinner.min.js
new file mode 100644
index 0000000000..62cd8de6a7
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.spinner.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){function e(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.widget("ui.spinner",{version:"1.10.3",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e={},i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);void 0!==n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var t=this.element[0]===this.document[0].activeElement;t||(this.element.focus(),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var t=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=t.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(.5*t.height())&&t.height()>0&&t.height(t.height()),this.options.disabled&&this.disable()},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"},_buttonHtml:function(){return"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'><span class='ui-icon "+this.options.icons.up+"'>&#9650;</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>&#9660;</span>"+"</a>"},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){if("culture"===t||"numberFormat"===t){var i=this._parse(this.element.val());return this.options[t]=e,this.element.val(this._format(i)),void 0}("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(e.up),this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(e.down)),this._super(t,e),"disabled"===t&&(e?(this.element.prop("disabled",!0),this.buttons.button("disable")):(this.element.prop("disabled",!1),this.buttons.button("enable")))},_setOptions:e(function(t){this._super(t),this._value(this.element.val())}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",!1).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:e(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:e(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:e(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:e(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(e(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.tabs.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.tabs.min.js
new file mode 100644
index 0000000000..e2f2ecb168
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.tabs.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t,e){function i(){return++n}function s(t){return t.hash.length>1&&decodeURIComponent(t.href.replace(a,""))===decodeURIComponent(location.href.replace(a,""))}var n=0,a=/#.*$/;t.widget("ui.tabs",{version:"1.10.3",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var e=this,i=this.options;this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",i.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var i=this.options.active,s=this.options.collapsible,n=location.hash.substring(1);return null===i&&(n&&this.tabs.each(function(s,a){return t(a).attr("aria-controls")===n?(i=s,!1):e}),null===i&&(i=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===i||-1===i)&&(i=this.tabs.length?0:!1)),i!==!1&&(i=this.tabs.index(this.tabs.eq(i)),-1===i&&(i=s?!1:0)),!s&&i===!1&&this.anchors.length&&(i=0),i},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(i){var s=t(this.document[0].activeElement).closest("li"),n=this.tabs.index(s),a=!0;if(!this._handlePageNav(i)){switch(i.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:n++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:a=!1,n--;break;case t.ui.keyCode.END:n=this.anchors.length-1;break;case t.ui.keyCode.HOME:n=0;break;case t.ui.keyCode.SPACE:return i.preventDefault(),clearTimeout(this.activating),this._activate(n),e;case t.ui.keyCode.ENTER:return i.preventDefault(),clearTimeout(this.activating),this._activate(n===this.options.active?!1:n),e;default:return}i.preventDefault(),clearTimeout(this.activating),n=this._focusNextTab(n,a),i.ctrlKey||(s.attr("aria-selected","false"),this.tabs.eq(n).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",n)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.focus())},_handlePageNav:function(i){return i.altKey&&i.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):i.altKey&&i.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):e},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).focus(),t},_setOption:function(t,i){return"active"===t?(this._activate(i),e):"disabled"===t?(this._setupDisabled(i),e):(this._super(t,i),"collapsible"===t&&(this.element.toggleClass("ui-tabs-collapsible",i),i||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(i),"heightStyle"===t&&this._setupHeightStyle(i),e)},_tabId:function(t){return t.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=t(),this.anchors.each(function(i,n){var a,o,r,h=t(n).uniqueId().attr("id"),l=t(n).closest("li"),u=l.attr("aria-controls");s(n)?(a=n.hash,o=e.element.find(e._sanitizeSelector(a))):(r=e._tabId(l),a="#"+r,o=e.element.find(a),o.length||(o=e._createPanel(r),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),u&&l.data("ui-tabs-aria-controls",u),l.attr({"aria-controls":a.substring(1),"aria-labelledby":h}),o.attr("aria-labelledby",h)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(e){return t("<div>").attr("id",e).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(e){t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1);for(var i,s=0;i=this.tabs[s];s++)e===!0||-1!==t.inArray(s,e)?t(i).addClass("ui-state-disabled").attr("aria-disabled","true"):t(i).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=e},_setupEvents:function(e){var i={click:function(t){t.preventDefault()}};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),a=n.closest("li"),o=a[0]===s[0],r=o&&i.collapsible,h=r?t():this._getPanelForTab(a),l=s.length?this._getPanelForTab(s):t(),u={oldTab:s,oldPanel:l,newTab:r?t():a,newPanel:h};e.preventDefault(),a.hasClass("ui-state-disabled")||a.hasClass("ui-tabs-loading")||this.running||o&&!i.collapsible||this._trigger("beforeActivate",e,u)===!1||(i.active=r?!1:this.tabs.index(a),this.active=o?t():a,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(a),e),this._toggle(e,u))},_toggle:function(e,i){function s(){a.running=!1,a._trigger("activate",e,i)}function n(){i.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),o.length&&a.options.show?a._show(o,a.options.show,s):(o.show(),s())}var a=this,o=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),n()}):(i.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),r.hide(),n()),r.attr({"aria-expanded":"false","aria-hidden":"true"}),i.oldTab.attr("aria-selected","false"),o.length&&r.length?i.oldTab.attr("tabIndex",-1):o.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),o.attr({"aria-expanded":"true","aria-hidden":"false"}),i.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(t){return"string"==typeof t&&(t=this.anchors.index(this.anchors.filter("[href$='"+t+"']"))),t},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(i){var s=this.options.disabled;s!==!1&&(i===e?s=!1:(i=this._getIndex(i),s=t.isArray(s)?t.map(s,function(t){return t!==i?t:null}):t.map(this.tabs,function(t,e){return e!==i?e:null})),this._setupDisabled(s))},disable:function(i){var s=this.options.disabled;if(s!==!0){if(i===e)s=!0;else{if(i=this._getIndex(i),-1!==t.inArray(i,s))return;s=t.isArray(s)?t.merge([i],s).sort():[i]}this._setupDisabled(s)}},load:function(e,i){e=this._getIndex(e);var n=this,a=this.tabs.eq(e),o=a.find(".ui-tabs-anchor"),r=this._getPanelForTab(a),h={tab:a,panel:r};s(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,h)),this.xhr&&"canceled"!==this.xhr.statusText&&(a.addClass("ui-tabs-loading"),r.attr("aria-busy","true"),this.xhr.success(function(t){setTimeout(function(){r.html(t),n._trigger("load",i,h)},1)}).complete(function(t,e){setTimeout(function(){"abort"===e&&n.panels.stop(!1,!0),a.removeClass("ui-tabs-loading"),r.removeAttr("aria-busy"),t===n.xhr&&delete n.xhr},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href"),beforeSend:function(e,a){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:a},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js
new file mode 100644
index 0000000000..48e52d9303
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(t){function e(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))}function i(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")}var s=0;t.widget("ui.tooltip",{version:"1.10.3",options:{content:function(){var e=t(this).attr("title")||"";return t("<a>").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(e,i){var s=this;return"disabled"===e?(this[i?"_disable":"_enable"](),this.options[e]=i,void 0):(this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e)}),void 0)},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0)}),this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.is("[title]")&&e.data("ui-tooltip-title",e.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))})},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,a=e?e.type:null;return"string"==typeof s?this._open(e,t,s):(i=s.call(t[0],function(i){t.data("ui-tooltip-open")&&n._delay(function(){e&&(e.type=a),this._open(e,t,i)})}),i&&this._open(e,t,i),void 0)},_open:function(i,s,n){function a(t){l.of=t,o.is(":hidden")||o.position(l)}var o,r,h,l=t.extend({},this.options.position);if(n){if(o=this._find(s),o.length)return o.find(".ui-tooltip-content").html(n),void 0;s.is("[title]")&&(i&&"mouseover"===i.type?s.attr("title",""):s.removeAttr("title")),o=this._tooltip(s),e(s,o.attr("id")),o.find(".ui-tooltip-content").html(n),this.options.track&&i&&/^mouse/.test(i.type)?(this._on(this.document,{mousemove:a}),a(i)):o.position(t.extend({of:s},this.options.position)),o.hide(),this._show(o,this.options.show),this.options.show&&this.options.show.delay&&(h=this.delayedShow=setInterval(function(){o.is(":visible")&&(a(l.of),clearInterval(h))},t.fx.interval)),this._trigger("open",i,{tooltip:o}),r={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var i=t.Event(e);i.currentTarget=s[0],this.close(i,!0)}},remove:function(){this._removeTooltip(o)}},i&&"mouseover"!==i.type||(r.mouseleave="close"),i&&"focusin"!==i.type||(r.focusout="close"),this._on(!0,s,r)}},close:function(e){var s=this,n=t(e?e.currentTarget:this.element),a=this._find(n);this.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&n.attr("title",n.data("ui-tooltip-title")),i(n),a.stop(!0),this._hide(a,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),this.closing=!0,this._trigger("close",e,{tooltip:a}),this.closing=!1)},_tooltip:function(e){var i="ui-tooltip-"+s++,n=t("<div>").attr({id:i,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return t("<div>").addClass("ui-tooltip-content").appendTo(n),n.appendTo(this.document[0].body),this.tooltips[i]=e,n},_find:function(e){var i=e.data("ui-tooltip-id");return i?t("#"+i):t()},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s[0],e.close(n,!0),t("#"+i).remove(),s.data("ui-tooltip-title")&&(s.attr("title",s.data("ui-tooltip-title")),s.removeData("ui-tooltip-title"))})}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/jquery/ui/jquery.ui.widget.min.js b/src/wp-includes/js/jquery/ui/jquery.ui.widget.min.js
new file mode 100644
index 0000000000..d2358d39d5
--- /dev/null
+++ b/src/wp-includes/js/jquery/ui/jquery.ui.widget.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-05-03
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery); \ No newline at end of file
diff --git a/src/wp-includes/js/json2.js b/src/wp-includes/js/json2.js
new file mode 100644
index 0000000000..b4c02d3f08
--- /dev/null
+++ b/src/wp-includes/js/json2.js
@@ -0,0 +1,480 @@
+/*
+ http://www.JSON.org/json2.js
+ 2011-02-23
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the value
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+*/
+
+/*jslint evil: true, strict: false, regexp: false */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+var JSON;
+if (!JSON) {
+ JSON = {};
+}
+
+(function () {
+ "use strict";
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf()) ?
+ this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z' : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' : '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' : gap ?
+ '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ if (typeof rep[i] === 'string') {
+ k = rep[i];
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' : gap ?
+ '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' :
+ '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.prototype.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ text = String(text);
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/
+ .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
diff --git a/src/wp-includes/js/mce-view.js b/src/wp-includes/js/mce-view.js
new file mode 100644
index 0000000000..912c4c7ce4
--- /dev/null
+++ b/src/wp-includes/js/mce-view.js
@@ -0,0 +1,349 @@
+// Ensure the global `wp` object exists.
+window.wp = window.wp || {};
+
+(function($){
+ var views = {},
+ instances = {};
+
+ // Create the `wp.mce` object if necessary.
+ wp.mce = wp.mce || {};
+
+ // wp.mce.view
+ // -----------
+ // A set of utilities that simplifies adding custom UI within a TinyMCE editor.
+ // At its core, it serves as a series of converters, transforming text to a
+ // custom UI, and back again.
+ wp.mce.view = {
+ // ### defaults
+ defaults: {
+ // The default properties used for objects with the `pattern` key in
+ // `wp.mce.view.add()`.
+ pattern: {
+ view: Backbone.View,
+ text: function( instance ) {
+ return instance.options.original;
+ },
+
+ toView: function( content ) {
+ if ( ! this.pattern )
+ return;
+
+ this.pattern.lastIndex = 0;
+ var match = this.pattern.exec( content );
+
+ if ( ! match )
+ return;
+
+ return {
+ index: match.index,
+ content: match[0],
+ options: {
+ original: match[0],
+ results: match
+ }
+ };
+ }
+ },
+
+ // The default properties used for objects with the `shortcode` key in
+ // `wp.mce.view.add()`.
+ shortcode: {
+ view: Backbone.View,
+ text: function( instance ) {
+ return instance.options.shortcode.string();
+ },
+
+ toView: function( content ) {
+ var match = wp.shortcode.next( this.shortcode, content );
+
+ if ( ! match )
+ return;
+
+ return {
+ index: match.index,
+ content: match.content,
+ options: {
+ shortcode: match.shortcode
+ }
+ };
+ }
+ }
+ },
+
+ // ### add( id, options )
+ // Registers a new TinyMCE view.
+ //
+ // Accepts a unique `id` and an `options` object.
+ //
+ // `options` accepts the following properties:
+ //
+ // * `pattern` is the regular expression used to scan the content and
+ // detect matching views.
+ //
+ // * `view` is a `Backbone.View` constructor. If a plain object is
+ // provided, it will automatically extend the parent constructor
+ // (usually `Backbone.View`). Views are instantiated when the `pattern`
+ // is successfully matched. The instance's `options` object is provided
+ // with the `original` matched value, the match `results` including
+ // capture groups, and the `viewType`, which is the constructor's `id`.
+ //
+ // * `extend` an existing view by passing in its `id`. The current
+ // view will inherit all properties from the parent view, and if
+ // `view` is set to a plain object, it will extend the parent `view`
+ // constructor.
+ //
+ // * `text` is a method that accepts an instance of the `view`
+ // constructor and transforms it into a text representation.
+ add: function( id, options ) {
+ var parent, remove, base, properties;
+
+ // Fetch the parent view or the default options.
+ if ( options.extend )
+ parent = wp.mce.view.get( options.extend );
+ else if ( options.shortcode )
+ parent = wp.mce.view.defaults.shortcode;
+ else
+ parent = wp.mce.view.defaults.pattern;
+
+ // Extend the `options` object with the parent's properties.
+ _.defaults( options, parent );
+ options.id = id;
+
+ // Create properties used to enhance the view for use in TinyMCE.
+ properties = {
+ // Ensure the wrapper element and references to the view are
+ // removed. Otherwise, removed views could randomly restore.
+ remove: function() {
+ delete instances[ this.el.id ];
+ this.$el.parent().remove();
+
+ // Trigger the inherited `remove` method.
+ if ( remove )
+ remove.apply( this, arguments );
+
+ return this;
+ }
+ };
+
+ // If the `view` provided was an object, use the parent's
+ // `view` constructor as a base. If a `view` constructor
+ // was provided, treat that as the base.
+ if ( _.isFunction( options.view ) ) {
+ base = options.view;
+ } else {
+ base = parent.view;
+ remove = options.view.remove;
+ _.defaults( properties, options.view );
+ }
+
+ // If there's a `remove` method on the `base` view that wasn't
+ // created by this method, inherit it.
+ if ( ! remove && ! base._mceview )
+ remove = base.prototype.remove;
+
+ // Automatically create the new `Backbone.View` constructor.
+ options.view = base.extend( properties, {
+ // Flag that the new view has been created by `wp.mce.view`.
+ _mceview: true
+ });
+
+ views[ id ] = options;
+ },
+
+ // ### get( id )
+ // Returns a TinyMCE view options object.
+ get: function( id ) {
+ return views[ id ];
+ },
+
+ // ### remove( id )
+ // Unregisters a TinyMCE view.
+ remove: function( id ) {
+ delete views[ id ];
+ },
+
+ // ### toViews( content )
+ // Scans a `content` string for each view's pattern, replacing any
+ // matches with wrapper elements, and creates a new view instance for
+ // every match.
+ //
+ // To render the views, call `wp.mce.view.render( scope )`.
+ toViews: function( content ) {
+ var pieces = [ { content: content } ],
+ current;
+
+ _.each( views, function( view, viewType ) {
+ current = pieces.slice();
+ pieces = [];
+
+ _.each( current, function( piece ) {
+ var remaining = piece.content,
+ result;
+
+ // Ignore processed pieces, but retain their location.
+ if ( piece.processed ) {
+ pieces.push( piece );
+ return;
+ }
+
+ // Iterate through the string progressively matching views
+ // and slicing the string as we go.
+ while ( remaining && (result = view.toView( remaining )) ) {
+ // Any text before the match becomes an unprocessed piece.
+ if ( result.index )
+ pieces.push({ content: remaining.substring( 0, result.index ) });
+
+ // Add the processed piece for the match.
+ pieces.push({
+ content: wp.mce.view.toView( viewType, result.options ),
+ processed: true
+ });
+
+ // Update the remaining content.
+ remaining = remaining.slice( result.index + result.content.length );
+ }
+
+ // There are no additional matches. If any content remains,
+ // add it as an unprocessed piece.
+ if ( remaining )
+ pieces.push({ content: remaining });
+ });
+ });
+
+ return _.pluck( pieces, 'content' ).join('');
+ },
+
+ toView: function( viewType, options ) {
+ var view = wp.mce.view.get( viewType ),
+ instance, id;
+
+ if ( ! view )
+ return '';
+
+ // Create a new view instance.
+ instance = new view.view( _.extend( options || {}, {
+ viewType: viewType
+ }) );
+
+ // Use the view's `id` if it already exists. Otherwise,
+ // create a new `id`.
+ id = instance.el.id = instance.el.id || _.uniqueId('__wpmce-');
+ instances[ id ] = instance;
+
+ // Create a dummy `$wrapper` property to allow `$wrapper` to be
+ // called in the view's `render` method without a conditional.
+ instance.$wrapper = $();
+
+ return wp.html.string({
+ // If the view is a span, wrap it in a span.
+ tag: 'span' === instance.tagName ? 'span' : 'div',
+
+ attrs: {
+ 'class': 'wp-view-wrap wp-view-type-' + viewType,
+ 'data-wp-view': id,
+ 'contenteditable': false
+ }
+ });
+ },
+
+ // ### render( scope )
+ // Renders any view instances inside a DOM node `scope`.
+ //
+ // View instances are detected by the presence of wrapper elements.
+ // To generate wrapper elements, pass your content through
+ // `wp.mce.view.toViews( content )`.
+ render: function( scope ) {
+ $( '.wp-view-wrap', scope ).each( function() {
+ var wrapper = $(this),
+ view = wp.mce.view.instance( this );
+
+ if ( ! view )
+ return;
+
+ // Link the real wrapper to the view.
+ view.$wrapper = wrapper;
+ // Render the view.
+ view.render();
+ // Detach the view element to ensure events are not unbound.
+ view.$el.detach();
+
+ // Empty the wrapper, attach the view element to the wrapper,
+ // and add an ending marker to the wrapper to help regexes
+ // scan the HTML string.
+ wrapper.empty().append( view.el ).append('<span data-wp-view-end class="wp-view-end"></span>');
+ });
+ },
+
+ // ### toText( content )
+ // Scans an HTML `content` string and replaces any view instances with
+ // their respective text representations.
+ toText: function( content ) {
+ return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span[^>]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g, function( match, id ) {
+ var instance = instances[ id ],
+ view;
+
+ if ( instance )
+ view = wp.mce.view.get( instance.options.viewType );
+
+ return instance && view ? view.text( instance ) : '';
+ });
+ },
+
+ // ### Remove internal TinyMCE attributes.
+ removeInternalAttrs: function( attrs ) {
+ var result = {};
+ _.each( attrs, function( value, attr ) {
+ if ( -1 === attr.indexOf('data-mce') )
+ result[ attr ] = value;
+ });
+ return result;
+ },
+
+ // ### Parse an attribute string and removes internal TinyMCE attributes.
+ attrs: function( content ) {
+ return wp.mce.view.removeInternalAttrs( wp.html.attrs( content ) );
+ },
+
+ // ### instance( scope )
+ //
+ // Accepts a MCE view wrapper `node` (i.e. a node with the
+ // `wp-view-wrap` class).
+ instance: function( node ) {
+ var id = $( node ).data('wp-view');
+
+ if ( id )
+ return instances[ id ];
+ },
+
+ // ### Select a view.
+ //
+ // Accepts a MCE view wrapper `node` (i.e. a node with the
+ // `wp-view-wrap` class).
+ select: function( node ) {
+ var $node = $(node);
+
+ // Bail if node is already selected.
+ if ( $node.hasClass('selected') )
+ return;
+
+ $node.addClass('selected');
+ $( node.firstChild ).trigger('select');
+ },
+
+ // ### Deselect a view.
+ //
+ // Accepts a MCE view wrapper `node` (i.e. a node with the
+ // `wp-view-wrap` class).
+ deselect: function( node ) {
+ var $node = $(node);
+
+ // Bail if node is already selected.
+ if ( ! $node.hasClass('selected') )
+ return;
+
+ $node.removeClass('selected');
+ $( node.firstChild ).trigger('deselect');
+ }
+ };
+
+}(jQuery)); \ No newline at end of file
diff --git a/src/wp-includes/js/media-editor.js b/src/wp-includes/js/media-editor.js
new file mode 100644
index 0000000000..fc497cd84d
--- /dev/null
+++ b/src/wp-includes/js/media-editor.js
@@ -0,0 +1,708 @@
+// WordPress, TinyMCE, and Media
+// -----------------------------
+(function($){
+ // Stores the editors' `wp.media.controller.Frame` instances.
+ var workflows = {};
+
+ wp.media.string = {
+ // Joins the `props` and `attachment` objects,
+ // outputting the proper object format based on the
+ // attachment's type.
+ props: function( props, attachment ) {
+ var link, linkUrl, size, sizes, fallbacks,
+ defaultProps = wp.media.view.settings.defaultProps;
+
+ // Final fallbacks run after all processing has been completed.
+ fallbacks = function( props ) {
+ // Generate alt fallbacks and strip tags.
+ if ( 'image' === props.type && ! props.alt ) {
+ props.alt = props.caption || props.title || '';
+ props.alt = props.alt.replace( /<\/?[^>]+>/g, '' );
+ props.alt = props.alt.replace( /[\r\n]+/g, ' ' );
+ }
+
+ return props;
+ };
+
+ props = props ? _.clone( props ) : {};
+
+ if ( attachment && attachment.type )
+ props.type = attachment.type;
+
+ if ( 'image' === props.type ) {
+ props = _.defaults( props || {}, {
+ align: defaultProps.align || getUserSetting( 'align', 'none' ),
+ size: defaultProps.size || getUserSetting( 'imgsize', 'medium' ),
+ url: '',
+ classes: []
+ });
+ }
+
+ // All attachment-specific settings follow.
+ if ( ! attachment )
+ return fallbacks( props );
+
+ props.title = props.title || attachment.title;
+
+ link = props.link || defaultProps.link || getUserSetting( 'urlbutton', 'file' );
+ if ( 'file' === link || 'embed' === link )
+ linkUrl = attachment.url;
+ else if ( 'post' === link )
+ linkUrl = attachment.link;
+ else if ( 'custom' === link )
+ linkUrl = props.linkUrl;
+ props.linkUrl = linkUrl || '';
+
+ // Format properties for images.
+ if ( 'image' === attachment.type ) {
+ props.classes.push( 'wp-image-' + attachment.id );
+
+ sizes = attachment.sizes;
+ size = sizes && sizes[ props.size ] ? sizes[ props.size ] : attachment;
+
+ _.extend( props, _.pick( attachment, 'align', 'caption', 'alt' ), {
+ width: size.width,
+ height: size.height,
+ src: size.url,
+ captionId: 'attachment_' + attachment.id
+ });
+ } else if ( 'video' === attachment.type || 'audio' === attachment.type ) {
+ _.extend( props, _.pick( attachment, 'title', 'type', 'icon', 'mime' ) );
+ // Format properties for non-images.
+ } else {
+ props.title = props.title || attachment.filename;
+ props.rel = props.rel || 'attachment wp-att-' + attachment.id;
+ }
+
+ return fallbacks( props );
+ },
+
+ link: function( props, attachment ) {
+ var options;
+
+ props = wp.media.string.props( props, attachment );
+
+ options = {
+ tag: 'a',
+ content: props.title,
+ attrs: {
+ href: props.linkUrl
+ }
+ };
+
+ if ( props.rel )
+ options.attrs.rel = props.rel;
+
+ return wp.html.string( options );
+ },
+
+ audio: function( props, attachment ) {
+ return wp.media.string._audioVideo( 'audio', props, attachment );
+ },
+
+ video: function( props, attachment ) {
+ return wp.media.string._audioVideo( 'video', props, attachment );
+ },
+
+ _audioVideo: function( type, props, attachment ) {
+ var shortcode, html, extension;
+
+ props = wp.media.string.props( props, attachment );
+ if ( props.link !== 'embed' )
+ return wp.media.string.link( props );
+
+ shortcode = {};
+
+ if ( 'video' === type ) {
+ if ( attachment.width )
+ shortcode.width = attachment.width;
+
+ if ( attachment.height )
+ shortcode.height = attachment.height;
+ }
+
+ extension = attachment.filename.split('.').pop();
+
+ if ( _.contains( wp.media.view.settings.embedExts, extension ) ) {
+ shortcode[extension] = attachment.url;
+ } else {
+ // Render unsupported audio and video files as links.
+ return wp.media.string.link( props );
+ }
+
+ html = wp.shortcode.string({
+ tag: type,
+ attrs: shortcode
+ });
+
+ return html;
+ },
+
+ image: function( props, attachment ) {
+ var img = {},
+ options, classes, shortcode, html;
+
+ props = wp.media.string.props( props, attachment );
+ classes = props.classes || [];
+
+ img.src = typeof attachment !== 'undefined' ? attachment.url : props.url;
+ _.extend( img, _.pick( props, 'width', 'height', 'alt' ) );
+
+ // Only assign the align class to the image if we're not printing
+ // a caption, since the alignment is sent to the shortcode.
+ if ( props.align && ! props.caption )
+ classes.push( 'align' + props.align );
+
+ if ( props.size )
+ classes.push( 'size-' + props.size );
+
+ img['class'] = _.compact( classes ).join(' ');
+
+ // Generate `img` tag options.
+ options = {
+ tag: 'img',
+ attrs: img,
+ single: true
+ };
+
+ // Generate the `a` element options, if they exist.
+ if ( props.linkUrl ) {
+ options = {
+ tag: 'a',
+ attrs: {
+ href: props.linkUrl
+ },
+ content: options
+ };
+ }
+
+ html = wp.html.string( options );
+
+ // Generate the caption shortcode.
+ if ( props.caption ) {
+ shortcode = {};
+
+ if ( img.width )
+ shortcode.width = img.width;
+
+ if ( props.captionId )
+ shortcode.id = props.captionId;
+
+ if ( props.align )
+ shortcode.align = 'align' + props.align;
+
+ html = wp.shortcode.string({
+ tag: 'caption',
+ attrs: shortcode,
+ content: html + ' ' + props.caption
+ });
+ }
+
+ return html;
+ }
+ };
+
+ wp.media.gallery = (function() {
+ var galleries = {};
+
+ return {
+ defaults: {
+ order: 'ASC',
+ id: wp.media.view.settings.post.id,
+ itemtag: 'dl',
+ icontag: 'dt',
+ captiontag: 'dd',
+ columns: '3',
+ link: 'post',
+ size: 'thumbnail',
+ orderby: 'menu_order ID'
+ },
+
+ attachments: function( shortcode ) {
+ var shortcodeString = shortcode.string(),
+ result = galleries[ shortcodeString ],
+ attrs, args, query, others;
+
+ delete galleries[ shortcodeString ];
+
+ if ( result )
+ return result;
+
+ // Fill the default shortcode attributes.
+ attrs = _.defaults( shortcode.attrs.named, wp.media.gallery.defaults );
+ args = _.pick( attrs, 'orderby', 'order' );
+
+ args.type = 'image';
+ args.perPage = -1;
+
+ // Mark the `orderby` override attribute.
+ if ( 'rand' === attrs.orderby )
+ attrs._orderbyRandom = true;
+
+ // Map the `orderby` attribute to the corresponding model property.
+ if ( ! attrs.orderby || /^menu_order(?: ID)?$/i.test( attrs.orderby ) )
+ args.orderby = 'menuOrder';
+
+ // Map the `ids` param to the correct query args.
+ if ( attrs.ids ) {
+ args.post__in = attrs.ids.split(',');
+ args.orderby = 'post__in';
+ } else if ( attrs.include ) {
+ args.post__in = attrs.include.split(',');
+ }
+
+ if ( attrs.exclude )
+ args.post__not_in = attrs.exclude.split(',');
+
+ if ( ! args.post__in )
+ args.uploadedTo = attrs.id;
+
+ // Collect the attributes that were not included in `args`.
+ others = _.omit( attrs, 'id', 'ids', 'include', 'exclude', 'orderby', 'order' );
+
+ query = wp.media.query( args );
+ query.gallery = new Backbone.Model( others );
+ return query;
+ },
+
+ shortcode: function( attachments ) {
+ var props = attachments.props.toJSON(),
+ attrs = _.pick( props, 'orderby', 'order' ),
+ shortcode, clone;
+
+ if ( attachments.gallery )
+ _.extend( attrs, attachments.gallery.toJSON() );
+
+ // Convert all gallery shortcodes to use the `ids` property.
+ // Ignore `post__in` and `post__not_in`; the attachments in
+ // the collection will already reflect those properties.
+ attrs.ids = attachments.pluck('id');
+
+ // Copy the `uploadedTo` post ID.
+ if ( props.uploadedTo )
+ attrs.id = props.uploadedTo;
+
+ // Check if the gallery is randomly ordered.
+ if ( attrs._orderbyRandom )
+ attrs.orderby = 'rand';
+ delete attrs._orderbyRandom;
+
+ // If the `ids` attribute is set and `orderby` attribute
+ // is the default value, clear it for cleaner output.
+ if ( attrs.ids && 'post__in' === attrs.orderby )
+ delete attrs.orderby;
+
+ // Remove default attributes from the shortcode.
+ _.each( wp.media.gallery.defaults, function( value, key ) {
+ if ( value === attrs[ key ] )
+ delete attrs[ key ];
+ });
+
+ shortcode = new wp.shortcode({
+ tag: 'gallery',
+ attrs: attrs,
+ type: 'single'
+ });
+
+ // Use a cloned version of the gallery.
+ clone = new wp.media.model.Attachments( attachments.models, {
+ props: props
+ });
+ clone.gallery = attachments.gallery;
+ galleries[ shortcode.string() ] = clone;
+
+ return shortcode;
+ },
+
+ edit: function( content ) {
+ var shortcode = wp.shortcode.next( 'gallery', content ),
+ defaultPostId = wp.media.gallery.defaults.id,
+ attachments, selection;
+
+ // Bail if we didn't match the shortcode or all of the content.
+ if ( ! shortcode || shortcode.content !== content )
+ return;
+
+ // Ignore the rest of the match object.
+ shortcode = shortcode.shortcode;
+
+ if ( _.isUndefined( shortcode.get('id') ) && ! _.isUndefined( defaultPostId ) )
+ shortcode.set( 'id', defaultPostId );
+
+ attachments = wp.media.gallery.attachments( shortcode );
+
+ selection = new wp.media.model.Selection( attachments.models, {
+ props: attachments.props.toJSON(),
+ multiple: true
+ });
+
+ selection.gallery = attachments.gallery;
+
+ // Fetch the query's attachments, and then break ties from the
+ // query to allow for sorting.
+ selection.more().done( function() {
+ // Break ties with the query.
+ selection.props.set({ query: false });
+ selection.unmirror();
+ selection.props.unset('orderby');
+ });
+
+ // Destroy the previous gallery frame.
+ if ( this.frame )
+ this.frame.dispose();
+
+ // Store the current gallery frame.
+ this.frame = wp.media({
+ frame: 'post',
+ state: 'gallery-edit',
+ title: wp.media.view.l10n.editGalleryTitle,
+ editing: true,
+ multiple: true,
+ selection: selection
+ }).open();
+
+ return this.frame;
+ }
+ };
+ }());
+
+ wp.media.featuredImage = {
+ get: function() {
+ return wp.media.view.settings.post.featuredImageId;
+ },
+
+ set: function( id ) {
+ var settings = wp.media.view.settings;
+
+ settings.post.featuredImageId = id;
+
+ wp.media.post( 'set-post-thumbnail', {
+ json: true,
+ post_id: settings.post.id,
+ thumbnail_id: settings.post.featuredImageId,
+ _wpnonce: settings.post.nonce
+ }).done( function( html ) {
+ $( '.inside', '#postimagediv' ).html( html );
+ });
+ },
+
+ frame: function() {
+ if ( this._frame )
+ return this._frame;
+
+ this._frame = wp.media({
+ state: 'featured-image',
+ states: [ new wp.media.controller.FeaturedImage() ]
+ });
+
+ this._frame.on( 'toolbar:create:featured-image', function( toolbar ) {
+ this.createSelectToolbar( toolbar, {
+ text: wp.media.view.l10n.setFeaturedImage
+ });
+ }, this._frame );
+
+ this._frame.state('featured-image').on( 'select', this.select );
+ return this._frame;
+ },
+
+ select: function() {
+ var settings = wp.media.view.settings,
+ selection = this.get('selection').single();
+
+ if ( ! settings.post.featuredImageId )
+ return;
+
+ wp.media.featuredImage.set( selection ? selection.id : -1 );
+ },
+
+ init: function() {
+ // Open the content media manager to the 'featured image' tab when
+ // the post thumbnail is clicked.
+ $('#postimagediv').on( 'click', '#set-post-thumbnail', function( event ) {
+ event.preventDefault();
+ // Stop propagation to prevent thickbox from activating.
+ event.stopPropagation();
+
+ wp.media.featuredImage.frame().open();
+
+ // Update the featured image id when the 'remove' link is clicked.
+ }).on( 'click', '#remove-post-thumbnail', function() {
+ wp.media.view.settings.post.featuredImageId = -1;
+ });
+ }
+ };
+
+ $( wp.media.featuredImage.init );
+
+ wp.media.editor = {
+ insert: function( h ) {
+ var mce = typeof(tinymce) != 'undefined',
+ qt = typeof(QTags) != 'undefined',
+ wpActiveEditor = window.wpActiveEditor,
+ ed;
+
+ // Delegate to the global `send_to_editor` if it exists.
+ // This attempts to play nice with any themes/plugins that have
+ // overridden the insert functionality.
+ if ( window.send_to_editor )
+ return window.send_to_editor.apply( this, arguments );
+
+ if ( ! wpActiveEditor ) {
+ if ( mce && tinymce.activeEditor ) {
+ ed = tinymce.activeEditor;
+ wpActiveEditor = window.wpActiveEditor = ed.id;
+ } else if ( !qt ) {
+ return false;
+ }
+ } else if ( mce ) {
+ if ( tinymce.activeEditor && (tinymce.activeEditor.id == 'mce_fullscreen' || tinymce.activeEditor.id == 'wp_mce_fullscreen') )
+ ed = tinymce.activeEditor;
+ else
+ ed = tinymce.get(wpActiveEditor);
+ }
+
+ if ( ed && !ed.isHidden() ) {
+ // restore caret position on IE
+ if ( tinymce.isIE && ed.windowManager.insertimagebookmark )
+ ed.selection.moveToBookmark(ed.windowManager.insertimagebookmark);
+
+ if ( h.indexOf('[caption') !== -1 ) {
+ if ( ed.wpSetImgCaption )
+ h = ed.wpSetImgCaption(h);
+ } else if ( h.indexOf('[gallery') !== -1 ) {
+ if ( ed.plugins.wpgallery )
+ h = ed.plugins.wpgallery._do_gallery(h);
+ } else if ( h.indexOf('[embed') === 0 ) {
+ if ( ed.plugins.wordpress )
+ h = ed.plugins.wordpress._setEmbed(h);
+ }
+
+ ed.execCommand('mceInsertContent', false, h);
+ } else if ( qt ) {
+ QTags.insertContent(h);
+ } else {
+ document.getElementById(wpActiveEditor).value += h;
+ }
+
+ // If the old thickbox remove function exists, call it in case
+ // a theme/plugin overloaded it.
+ if ( window.tb_remove )
+ try { window.tb_remove(); } catch( e ) {}
+ },
+
+ add: function( id, options ) {
+ var workflow = this.get( id );
+
+ if ( workflow ) // only add once: if exists return existing
+ return workflow;
+
+ workflow = workflows[ id ] = wp.media( _.defaults( options || {}, {
+ frame: 'post',
+ state: 'insert',
+ title: wp.media.view.l10n.addMedia,
+ multiple: true
+ } ) );
+
+ workflow.on( 'insert', function( selection ) {
+ var state = workflow.state();
+
+ selection = selection || state.get('selection');
+
+ if ( ! selection )
+ return;
+
+ $.when.apply( $, selection.map( function( attachment ) {
+ var display = state.display( attachment ).toJSON();
+ return this.send.attachment( display, attachment.toJSON() );
+ }, this ) ).done( function() {
+ wp.media.editor.insert( _.toArray( arguments ).join("\n\n") );
+ });
+ }, this );
+
+ workflow.state('gallery-edit').on( 'update', function( selection ) {
+ this.insert( wp.media.gallery.shortcode( selection ).string() );
+ }, this );
+
+ workflow.state('embed').on( 'select', function() {
+ var state = workflow.state(),
+ type = state.get('type'),
+ embed = state.props.toJSON();
+
+ embed.url = embed.url || '';
+
+ if ( 'link' === type ) {
+ _.defaults( embed, {
+ title: embed.url,
+ linkUrl: embed.url
+ });
+
+ this.send.link( embed ).done( function( resp ) {
+ wp.media.editor.insert( resp );
+ });
+
+ } else if ( 'image' === type ) {
+ _.defaults( embed, {
+ title: embed.url,
+ linkUrl: '',
+ align: 'none',
+ link: 'none'
+ });
+
+ if ( 'none' === embed.link )
+ embed.linkUrl = '';
+ else if ( 'file' === embed.link )
+ embed.linkUrl = embed.url;
+
+ this.insert( wp.media.string.image( embed ) );
+ }
+ }, this );
+
+ workflow.state('featured-image').on( 'select', wp.media.featuredImage.select );
+ workflow.setState( workflow.options.state );
+ return workflow;
+ },
+
+ id: function( id ) {
+ if ( id )
+ return id;
+
+ // If an empty `id` is provided, default to `wpActiveEditor`.
+ id = wpActiveEditor;
+
+ // If that doesn't work, fall back to `tinymce.activeEditor.id`.
+ if ( ! id && typeof tinymce !== 'undefined' && tinymce.activeEditor )
+ id = tinymce.activeEditor.id;
+
+ // Last but not least, fall back to the empty string.
+ id = id || '';
+ return id;
+ },
+
+ get: function( id ) {
+ id = this.id( id );
+ return workflows[ id ];
+ },
+
+ remove: function( id ) {
+ id = this.id( id );
+ delete workflows[ id ];
+ },
+
+ send: {
+ attachment: function( props, attachment ) {
+ var caption = attachment.caption,
+ options, html;
+
+ // If captions are disabled, clear the caption.
+ if ( ! wp.media.view.settings.captions )
+ delete attachment.caption;
+
+ props = wp.media.string.props( props, attachment );
+
+ options = {
+ id: attachment.id,
+ post_content: attachment.description,
+ post_excerpt: caption
+ };
+
+ if ( props.linkUrl )
+ options.url = props.linkUrl;
+
+ if ( 'image' === attachment.type ) {
+ html = wp.media.string.image( props );
+
+ _.each({
+ align: 'align',
+ size: 'image-size',
+ alt: 'image_alt'
+ }, function( option, prop ) {
+ if ( props[ prop ] )
+ options[ option ] = props[ prop ];
+ });
+ } else if ( 'video' === attachment.type ) {
+ html = wp.media.string.video( props, attachment );
+ } else if ( 'audio' === attachment.type ) {
+ html = wp.media.string.audio( props, attachment );
+ } else {
+ html = wp.media.string.link( props );
+ options.post_title = props.title;
+ }
+
+ return wp.media.post( 'send-attachment-to-editor', {
+ nonce: wp.media.view.settings.nonce.sendToEditor,
+ attachment: options,
+ html: html,
+ post_id: wp.media.view.settings.post.id
+ });
+ },
+
+ link: function( embed ) {
+ return wp.media.post( 'send-link-to-editor', {
+ nonce: wp.media.view.settings.nonce.sendToEditor,
+ src: embed.linkUrl,
+ title: embed.title,
+ html: wp.media.string.link( embed ),
+ post_id: wp.media.view.settings.post.id
+ });
+ }
+ },
+
+ open: function( id, options ) {
+ var workflow, editor;
+
+ options = options || {};
+
+ id = this.id( id );
+
+ // Save a bookmark of the caret position in IE.
+ if ( typeof tinymce !== 'undefined' ) {
+ editor = tinymce.get( id );
+
+ if ( tinymce.isIE && editor && ! editor.isHidden() ) {
+ editor.focus();
+ editor.windowManager.insertimagebookmark = editor.selection.getBookmark();
+ }
+ }
+
+ workflow = this.get( id );
+
+ // Redo workflow if state has changed
+ if ( ! workflow || ( workflow.options && options.state !== workflow.options.state ) )
+ workflow = this.add( id, options );
+
+ return workflow.open();
+ },
+
+ init: function() {
+ $(document.body).on( 'click', '.insert-media', function( event ) {
+ var $this = $(this),
+ editor = $this.data('editor'),
+ options = {
+ frame: 'post',
+ state: 'insert',
+ title: wp.media.view.l10n.addMedia,
+ multiple: true
+ };
+
+ event.preventDefault();
+
+ // Remove focus from the `.insert-media` button.
+ // Prevents Opera from showing the outline of the button
+ // above the modal.
+ //
+ // See: http://core.trac.wordpress.org/ticket/22445
+ $this.blur();
+
+ if ( $this.hasClass( 'gallery' ) ) {
+ options.state = 'gallery';
+ options.title = wp.media.view.l10n.createGalleryTitle;
+ }
+
+ wp.media.editor.open( editor, options );
+ });
+ }
+ };
+
+ _.bindAll( wp.media.editor, 'open' );
+ $( wp.media.editor.init );
+}(jQuery));
diff --git a/src/wp-includes/js/media-models.js b/src/wp-includes/js/media-models.js
new file mode 100644
index 0000000000..f501b69fc6
--- /dev/null
+++ b/src/wp-includes/js/media-models.js
@@ -0,0 +1,862 @@
+window.wp = window.wp || {};
+
+(function($){
+ var Attachment, Attachments, Query, compare, l10n, media;
+
+ /**
+ * wp.media( attributes )
+ *
+ * Handles the default media experience. Automatically creates
+ * and opens a media frame, and returns the result.
+ * Does nothing if the controllers do not exist.
+ *
+ * @param {object} attributes The properties passed to the main media controller.
+ * @return {object} A media workflow.
+ */
+ media = wp.media = function( attributes ) {
+ var MediaFrame = media.view.MediaFrame,
+ frame;
+
+ if ( ! MediaFrame )
+ return;
+
+ attributes = _.defaults( attributes || {}, {
+ frame: 'select'
+ });
+
+ if ( 'select' === attributes.frame && MediaFrame.Select )
+ frame = new MediaFrame.Select( attributes );
+ else if ( 'post' === attributes.frame && MediaFrame.Post )
+ frame = new MediaFrame.Post( attributes );
+
+ delete attributes.frame;
+
+ return frame;
+ };
+
+ _.extend( media, { model: {}, view: {}, controller: {}, frames: {} });
+
+ // Link any localized strings.
+ l10n = media.model.l10n = typeof _wpMediaModelsL10n === 'undefined' ? {} : _wpMediaModelsL10n;
+
+ // Link any settings.
+ media.model.settings = l10n.settings || {};
+ delete l10n.settings;
+
+ /**
+ * ========================================================================
+ * UTILITIES
+ * ========================================================================
+ */
+
+ /**
+ * A basic comparator.
+ *
+ * @param {mixed} a The primary parameter to compare.
+ * @param {mixed} b The primary parameter to compare.
+ * @param {string} ac The fallback parameter to compare, a's cid.
+ * @param {string} bc The fallback parameter to compare, b's cid.
+ * @return {number} -1: a should come before b.
+ * 0: a and b are of the same rank.
+ * 1: b should come before a.
+ */
+ compare = function( a, b, ac, bc ) {
+ if ( _.isEqual( a, b ) )
+ return ac === bc ? 0 : (ac > bc ? -1 : 1);
+ else
+ return a > b ? -1 : 1;
+ };
+
+ _.extend( media, {
+ /**
+ * media.template( id )
+ *
+ * Fetches a template by id.
+ * See wp.template() in `wp-includes/js/wp-util.js`.
+ */
+ template: wp.template,
+
+ /**
+ * media.post( [action], [data] )
+ *
+ * Sends a POST request to WordPress.
+ * See wp.ajax.post() in `wp-includes/js/wp-util.js`.
+ */
+ post: wp.ajax.post,
+
+ /**
+ * media.ajax( [action], [options] )
+ *
+ * Sends an XHR request to WordPress.
+ * See wp.ajax.send() in `wp-includes/js/wp-util.js`.
+ */
+ ajax: wp.ajax.send,
+
+ // Scales a set of dimensions to fit within bounding dimensions.
+ fit: function( dimensions ) {
+ var width = dimensions.width,
+ height = dimensions.height,
+ maxWidth = dimensions.maxWidth,
+ maxHeight = dimensions.maxHeight,
+ constraint;
+
+ // Compare ratios between the two values to determine which
+ // max to constrain by. If a max value doesn't exist, then the
+ // opposite side is the constraint.
+ if ( ! _.isUndefined( maxWidth ) && ! _.isUndefined( maxHeight ) ) {
+ constraint = ( width / height > maxWidth / maxHeight ) ? 'width' : 'height';
+ } else if ( _.isUndefined( maxHeight ) ) {
+ constraint = 'width';
+ } else if ( _.isUndefined( maxWidth ) && height > maxHeight ) {
+ constraint = 'height';
+ }
+
+ // If the value of the constrained side is larger than the max,
+ // then scale the values. Otherwise return the originals; they fit.
+ if ( 'width' === constraint && width > maxWidth ) {
+ return {
+ width : maxWidth,
+ height: Math.round( maxWidth * height / width )
+ };
+ } else if ( 'height' === constraint && height > maxHeight ) {
+ return {
+ width : Math.round( maxHeight * width / height ),
+ height: maxHeight
+ };
+ } else {
+ return {
+ width : width,
+ height: height
+ };
+ }
+ },
+
+ // Truncates a string by injecting an ellipsis into the middle.
+ // Useful for filenames.
+ truncate: function( string, length, replacement ) {
+ length = length || 30;
+ replacement = replacement || '&hellip;';
+
+ if ( string.length <= length )
+ return string;
+
+ return string.substr( 0, length / 2 ) + replacement + string.substr( -1 * length / 2 );
+ }
+ });
+
+
+ /**
+ * ========================================================================
+ * MODELS
+ * ========================================================================
+ */
+
+ /**
+ * wp.media.attachment
+ */
+ media.attachment = function( id ) {
+ return Attachment.get( id );
+ };
+
+ /**
+ * wp.media.model.Attachment
+ */
+ Attachment = media.model.Attachment = Backbone.Model.extend({
+ sync: function( method, model, options ) {
+ // If the attachment does not yet have an `id`, return an instantly
+ // rejected promise. Otherwise, all of our requests will fail.
+ if ( _.isUndefined( this.id ) )
+ return $.Deferred().rejectWith( this ).promise();
+
+ // Overload the `read` request so Attachment.fetch() functions correctly.
+ if ( 'read' === method ) {
+ options = options || {};
+ options.context = this;
+ options.data = _.extend( options.data || {}, {
+ action: 'get-attachment',
+ id: this.id
+ });
+ return media.ajax( options );
+
+ // Overload the `update` request so properties can be saved.
+ } else if ( 'update' === method ) {
+ // If we do not have the necessary nonce, fail immeditately.
+ if ( ! this.get('nonces') || ! this.get('nonces').update )
+ return $.Deferred().rejectWith( this ).promise();
+
+ options = options || {};
+ options.context = this;
+
+ // Set the action and ID.
+ options.data = _.extend( options.data || {}, {
+ action: 'save-attachment',
+ id: this.id,
+ nonce: this.get('nonces').update,
+ post_id: media.model.settings.post.id
+ });
+
+ // Record the values of the changed attributes.
+ if ( model.hasChanged() ) {
+ options.data.changes = {};
+
+ _.each( model.changed, function( value, key ) {
+ options.data.changes[ key ] = this.get( key );
+ }, this );
+ }
+
+ return media.ajax( options );
+
+ // Overload the `delete` request so attachments can be removed.
+ // This will permanently delete an attachment.
+ } else if ( 'delete' === method ) {
+ options = options || {};
+
+ if ( ! options.wait )
+ this.destroyed = true;
+
+ options.context = this;
+ options.data = _.extend( options.data || {}, {
+ action: 'delete-post',
+ id: this.id,
+ _wpnonce: this.get('nonces')['delete']
+ });
+
+ return media.ajax( options ).done( function() {
+ this.destroyed = true;
+ }).fail( function() {
+ this.destroyed = false;
+ });
+
+ // Otherwise, fall back to `Backbone.sync()`.
+ } else {
+ return Backbone.Model.prototype.sync.apply( this, arguments );
+ }
+ },
+
+ parse: function( resp, xhr ) {
+ if ( ! resp )
+ return resp;
+
+ // Convert date strings into Date objects.
+ resp.date = new Date( resp.date );
+ resp.modified = new Date( resp.modified );
+ return resp;
+ },
+
+ saveCompat: function( data, options ) {
+ var model = this;
+
+ // If we do not have the necessary nonce, fail immeditately.
+ if ( ! this.get('nonces') || ! this.get('nonces').update )
+ return $.Deferred().rejectWith( this ).promise();
+
+ return media.post( 'save-attachment-compat', _.defaults({
+ id: this.id,
+ nonce: this.get('nonces').update,
+ post_id: media.model.settings.post.id
+ }, data ) ).done( function( resp, status, xhr ) {
+ model.set( model.parse( resp, xhr ), options );
+ });
+ }
+ }, {
+ create: function( attrs ) {
+ return Attachments.all.push( attrs );
+ },
+
+ get: _.memoize( function( id, attachment ) {
+ return Attachments.all.push( attachment || { id: id } );
+ })
+ });
+
+ /**
+ * wp.media.model.Attachments
+ */
+ Attachments = media.model.Attachments = Backbone.Collection.extend({
+ model: Attachment,
+
+ initialize: function( models, options ) {
+ options = options || {};
+
+ this.props = new Backbone.Model();
+ this.filters = options.filters || {};
+
+ // Bind default `change` events to the `props` model.
+ this.props.on( 'change', this._changeFilteredProps, this );
+
+ this.props.on( 'change:order', this._changeOrder, this );
+ this.props.on( 'change:orderby', this._changeOrderby, this );
+ this.props.on( 'change:query', this._changeQuery, this );
+
+ // Set the `props` model and fill the default property values.
+ this.props.set( _.defaults( options.props || {} ) );
+
+ // Observe another `Attachments` collection if one is provided.
+ if ( options.observe )
+ this.observe( options.observe );
+ },
+
+ // Automatically sort the collection when the order changes.
+ _changeOrder: function( model, order ) {
+ if ( this.comparator )
+ this.sort();
+ },
+
+ // Set the default comparator only when the `orderby` property is set.
+ _changeOrderby: function( model, orderby ) {
+ // If a different comparator is defined, bail.
+ if ( this.comparator && this.comparator !== Attachments.comparator )
+ return;
+
+ if ( orderby && 'post__in' !== orderby )
+ this.comparator = Attachments.comparator;
+ else
+ delete this.comparator;
+ },
+
+ // If the `query` property is set to true, query the server using
+ // the `props` values, and sync the results to this collection.
+ _changeQuery: function( model, query ) {
+ if ( query ) {
+ this.props.on( 'change', this._requery, this );
+ this._requery();
+ } else {
+ this.props.off( 'change', this._requery, this );
+ }
+ },
+
+ _changeFilteredProps: function( model, options ) {
+ // If this is a query, updating the collection will be handled by
+ // `this._requery()`.
+ if ( this.props.get('query') )
+ return;
+
+ var changed = _.chain( model.changed ).map( function( t, prop ) {
+ var filter = Attachments.filters[ prop ],
+ term = model.get( prop );
+
+ if ( ! filter )
+ return;
+
+ if ( term && ! this.filters[ prop ] )
+ this.filters[ prop ] = filter;
+ else if ( ! term && this.filters[ prop ] === filter )
+ delete this.filters[ prop ];
+ else
+ return;
+
+ // Record the change.
+ return true;
+ }, this ).any().value();
+
+ if ( ! changed )
+ return;
+
+ // If no `Attachments` model is provided to source the searches
+ // from, then automatically generate a source from the existing
+ // models.
+ if ( ! this._source )
+ this._source = new Attachments( this.models );
+
+ this.reset( this._source.filter( this.validator, this ) );
+ },
+
+ validateDestroyed: false,
+
+ validator: function( attachment ) {
+ if ( ! this.validateDestroyed && attachment.destroyed )
+ return false;
+ return _.all( this.filters, function( filter, key ) {
+ return !! filter.call( this, attachment );
+ }, this );
+ },
+
+ validate: function( attachment, options ) {
+ var valid = this.validator( attachment ),
+ hasAttachment = !! this.get( attachment.cid );
+
+ if ( ! valid && hasAttachment )
+ this.remove( attachment, options );
+ else if ( valid && ! hasAttachment )
+ this.add( attachment, options );
+
+ return this;
+ },
+
+ validateAll: function( attachments, options ) {
+ options = options || {};
+
+ _.each( attachments.models, function( attachment ) {
+ this.validate( attachment, { silent: true });
+ }, this );
+
+ if ( ! options.silent )
+ this.trigger( 'reset', this, options );
+
+ return this;
+ },
+
+ observe: function( attachments ) {
+ this.observers = this.observers || [];
+ this.observers.push( attachments );
+
+ attachments.on( 'add change remove', this._validateHandler, this );
+ attachments.on( 'reset', this._validateAllHandler, this );
+ this.validateAll( attachments );
+ return this;
+ },
+
+ unobserve: function( attachments ) {
+ if ( attachments ) {
+ attachments.off( null, null, this );
+ this.observers = _.without( this.observers, attachments );
+
+ } else {
+ _.each( this.observers, function( attachments ) {
+ attachments.off( null, null, this );
+ }, this );
+ delete this.observers;
+ }
+
+ return this;
+ },
+
+ _validateHandler: function( attachment, attachments, options ) {
+ // If we're not mirroring this `attachments` collection,
+ // only retain the `silent` option.
+ options = attachments === this.mirroring ? options : {
+ silent: options && options.silent
+ };
+
+ return this.validate( attachment, options );
+ },
+
+ _validateAllHandler: function( attachments, options ) {
+ return this.validateAll( attachments, options );
+ },
+
+ mirror: function( attachments ) {
+ if ( this.mirroring && this.mirroring === attachments )
+ return this;
+
+ this.unmirror();
+ this.mirroring = attachments;
+
+ // Clear the collection silently. A `reset` event will be fired
+ // when `observe()` calls `validateAll()`.
+ this.reset( [], { silent: true } );
+ this.observe( attachments );
+
+ return this;
+ },
+
+ unmirror: function() {
+ if ( ! this.mirroring )
+ return;
+
+ this.unobserve( this.mirroring );
+ delete this.mirroring;
+ },
+
+ more: function( options ) {
+ var deferred = $.Deferred(),
+ mirroring = this.mirroring,
+ attachments = this;
+
+ if ( ! mirroring || ! mirroring.more )
+ return deferred.resolveWith( this ).promise();
+
+ // If we're mirroring another collection, forward `more` to
+ // the mirrored collection. Account for a race condition by
+ // checking if we're still mirroring that collection when
+ // the request resolves.
+ mirroring.more( options ).done( function() {
+ if ( this === attachments.mirroring )
+ deferred.resolveWith( this );
+ });
+
+ return deferred.promise();
+ },
+
+ hasMore: function() {
+ return this.mirroring ? this.mirroring.hasMore() : false;
+ },
+
+ parse: function( resp, xhr ) {
+ if ( ! _.isArray( resp ) )
+ resp = [resp];
+
+ return _.map( resp, function( attrs ) {
+ var id, attachment, newAttributes;
+
+ if ( attrs instanceof Backbone.Model ) {
+ id = attrs.get( 'id' );
+ attrs = attrs.attributes;
+ } else {
+ id = attrs.id;
+ }
+
+ attachment = Attachment.get( id );
+ newAttributes = attachment.parse( attrs, xhr );
+
+ if ( ! _.isEqual( attachment.attributes, newAttributes ) )
+ attachment.set( newAttributes );
+
+ return attachment;
+ });
+ },
+
+ _requery: function() {
+ if ( this.props.get('query') )
+ this.mirror( Query.get( this.props.toJSON() ) );
+ },
+
+ // If this collection is sorted by `menuOrder`, recalculates and saves
+ // the menu order to the database.
+ saveMenuOrder: function() {
+ if ( 'menuOrder' !== this.props.get('orderby') )
+ return;
+
+ // Removes any uploading attachments, updates each attachment's
+ // menu order, and returns an object with an { id: menuOrder }
+ // mapping to pass to the request.
+ var attachments = this.chain().filter( function( attachment ) {
+ return ! _.isUndefined( attachment.id );
+ }).map( function( attachment, index ) {
+ // Indices start at 1.
+ index = index + 1;
+ attachment.set( 'menuOrder', index );
+ return [ attachment.id, index ];
+ }).object().value();
+
+ if ( _.isEmpty( attachments ) )
+ return;
+
+ return media.post( 'save-attachment-order', {
+ nonce: media.model.settings.post.nonce,
+ post_id: media.model.settings.post.id,
+ attachments: attachments
+ });
+ }
+ }, {
+ comparator: function( a, b, options ) {
+ var key = this.props.get('orderby'),
+ order = this.props.get('order') || 'DESC',
+ ac = a.cid,
+ bc = b.cid;
+
+ a = a.get( key );
+ b = b.get( key );
+
+ if ( 'date' === key || 'modified' === key ) {
+ a = a || new Date();
+ b = b || new Date();
+ }
+
+ // If `options.ties` is set, don't enforce the `cid` tiebreaker.
+ if ( options && options.ties )
+ ac = bc = null;
+
+ return ( 'DESC' === order ) ? compare( a, b, ac, bc ) : compare( b, a, bc, ac );
+ },
+
+ filters: {
+ // Note that this client-side searching is *not* equivalent
+ // to our server-side searching.
+ search: function( attachment ) {
+ if ( ! this.props.get('search') )
+ return true;
+
+ return _.any(['title','filename','description','caption','name'], function( key ) {
+ var value = attachment.get( key );
+ return value && -1 !== value.search( this.props.get('search') );
+ }, this );
+ },
+
+ type: function( attachment ) {
+ var type = this.props.get('type');
+ return ! type || -1 !== type.indexOf( attachment.get('type') );
+ },
+
+ uploadedTo: function( attachment ) {
+ var uploadedTo = this.props.get('uploadedTo');
+ if ( _.isUndefined( uploadedTo ) )
+ return true;
+
+ return uploadedTo === attachment.get('uploadedTo');
+ }
+ }
+ });
+
+ Attachments.all = new Attachments();
+
+ /**
+ * wp.media.query
+ */
+ media.query = function( props ) {
+ return new Attachments( null, {
+ props: _.extend( _.defaults( props || {}, { orderby: 'date' } ), { query: true } )
+ });
+ };
+
+ /**
+ * wp.media.model.Query
+ *
+ * A set of attachments that corresponds to a set of consecutively paged
+ * queries on the server.
+ *
+ * Note: Do NOT change this.args after the query has been initialized.
+ * Things will break.
+ */
+ Query = media.model.Query = Attachments.extend({
+ initialize: function( models, options ) {
+ var allowed;
+
+ options = options || {};
+ Attachments.prototype.initialize.apply( this, arguments );
+
+ this.args = options.args;
+ this._hasMore = true;
+ this.created = new Date();
+
+ this.filters.order = function( attachment ) {
+ var orderby = this.props.get('orderby'),
+ order = this.props.get('order');
+
+ if ( ! this.comparator )
+ return true;
+
+ // We want any items that can be placed before the last
+ // item in the set. If we add any items after the last
+ // item, then we can't guarantee the set is complete.
+ if ( this.length ) {
+ return 1 !== this.comparator( attachment, this.last(), { ties: true });
+
+ // Handle the case where there are no items yet and
+ // we're sorting for recent items. In that case, we want
+ // changes that occurred after we created the query.
+ } else if ( 'DESC' === order && ( 'date' === orderby || 'modified' === orderby ) ) {
+ return attachment.get( orderby ) >= this.created;
+
+ // If we're sorting by menu order and we have no items,
+ // accept any items that have the default menu order (0).
+ } else if ( 'ASC' === order && 'menuOrder' === orderby ) {
+ return attachment.get( orderby ) === 0;
+ }
+
+ // Otherwise, we don't want any items yet.
+ return false;
+ };
+
+ // Observe the central `wp.Uploader.queue` collection to watch for
+ // new matches for the query.
+ //
+ // Only observe when a limited number of query args are set. There
+ // are no filters for other properties, so observing will result in
+ // false positives in those queries.
+ allowed = [ 's', 'order', 'orderby', 'posts_per_page', 'post_mime_type', 'post_parent' ];
+ if ( wp.Uploader && _( this.args ).chain().keys().difference( allowed ).isEmpty().value() )
+ this.observe( wp.Uploader.queue );
+ },
+
+ hasMore: function() {
+ return this._hasMore;
+ },
+
+ more: function( options ) {
+ var query = this;
+
+ if ( this._more && 'pending' === this._more.state() )
+ return this._more;
+
+ if ( ! this.hasMore() )
+ return $.Deferred().resolveWith( this ).promise();
+
+ options = options || {};
+ options.remove = false;
+
+ return this._more = this.fetch( options ).done( function( resp ) {
+ if ( _.isEmpty( resp ) || -1 === this.args.posts_per_page || resp.length < this.args.posts_per_page )
+ query._hasMore = false;
+ });
+ },
+
+ sync: function( method, model, options ) {
+ var fallback;
+
+ // Overload the read method so Attachment.fetch() functions correctly.
+ if ( 'read' === method ) {
+ options = options || {};
+ options.context = this;
+ options.data = _.extend( options.data || {}, {
+ action: 'query-attachments',
+ post_id: media.model.settings.post.id
+ });
+
+ // Clone the args so manipulation is non-destructive.
+ args = _.clone( this.args );
+
+ // Determine which page to query.
+ if ( -1 !== args.posts_per_page )
+ args.paged = Math.floor( this.length / args.posts_per_page ) + 1;
+
+ options.data.query = args;
+ return media.ajax( options );
+
+ // Otherwise, fall back to Backbone.sync()
+ } else {
+ fallback = Attachments.prototype.sync ? Attachments.prototype : Backbone;
+ return fallback.sync.apply( this, arguments );
+ }
+ }
+ }, {
+ defaultProps: {
+ orderby: 'date',
+ order: 'DESC'
+ },
+
+ defaultArgs: {
+ posts_per_page: 40
+ },
+
+ orderby: {
+ allowed: [ 'name', 'author', 'date', 'title', 'modified', 'uploadedTo', 'id', 'post__in', 'menuOrder' ],
+ valuemap: {
+ 'id': 'ID',
+ 'uploadedTo': 'parent',
+ 'menuOrder': 'menu_order ID'
+ }
+ },
+
+ propmap: {
+ 'search': 's',
+ 'type': 'post_mime_type',
+ 'perPage': 'posts_per_page',
+ 'menuOrder': 'menu_order',
+ 'uploadedTo': 'post_parent'
+ },
+
+ // Caches query objects so queries can be easily reused.
+ get: (function(){
+ var queries = [];
+
+ return function( props, options ) {
+ var args = {},
+ orderby = Query.orderby,
+ defaults = Query.defaultProps,
+ query;
+
+ // Remove the `query` property. This isn't linked to a query,
+ // this *is* the query.
+ delete props.query;
+
+ // Fill default args.
+ _.defaults( props, defaults );
+
+ // Normalize the order.
+ props.order = props.order.toUpperCase();
+ if ( 'DESC' !== props.order && 'ASC' !== props.order )
+ props.order = defaults.order.toUpperCase();
+
+ // Ensure we have a valid orderby value.
+ if ( ! _.contains( orderby.allowed, props.orderby ) )
+ props.orderby = defaults.orderby;
+
+ // Generate the query `args` object.
+ // Correct any differing property names.
+ _.each( props, function( value, prop ) {
+ if ( _.isNull( value ) )
+ return;
+
+ args[ Query.propmap[ prop ] || prop ] = value;
+ });
+
+ // Fill any other default query args.
+ _.defaults( args, Query.defaultArgs );
+
+ // `props.orderby` does not always map directly to `args.orderby`.
+ // Substitute exceptions specified in orderby.keymap.
+ args.orderby = orderby.valuemap[ props.orderby ] || props.orderby;
+
+ // Search the query cache for matches.
+ query = _.find( queries, function( query ) {
+ return _.isEqual( query.args, args );
+ });
+
+ // Otherwise, create a new query and add it to the cache.
+ if ( ! query ) {
+ query = new Query( [], _.extend( options || {}, {
+ props: props,
+ args: args
+ } ) );
+ queries.push( query );
+ }
+
+ return query;
+ };
+ }())
+ });
+
+ /**
+ * wp.media.model.Selection
+ *
+ * Used to manage a selection of attachments in the views.
+ */
+ media.model.Selection = Attachments.extend({
+ initialize: function( models, options ) {
+ Attachments.prototype.initialize.apply( this, arguments );
+ this.multiple = options && options.multiple;
+
+ // Refresh the `single` model whenever the selection changes.
+ // Binds `single` instead of using the context argument to ensure
+ // it receives no parameters.
+ this.on( 'add remove reset', _.bind( this.single, this, false ) );
+ },
+
+ // Override the selection's add method.
+ // If the workflow does not support multiple
+ // selected attachments, reset the selection.
+ add: function( models, options ) {
+ if ( ! this.multiple )
+ this.remove( this.models );
+
+ return Attachments.prototype.add.call( this, models, options );
+ },
+
+ single: function( model ) {
+ var previous = this._single;
+
+ // If a `model` is provided, use it as the single model.
+ if ( model )
+ this._single = model;
+
+ // If the single model isn't in the selection, remove it.
+ if ( this._single && ! this.get( this._single.cid ) )
+ delete this._single;
+
+ this._single = this._single || this.last();
+
+ // If single has changed, fire an event.
+ if ( this._single !== previous ) {
+ if ( previous ) {
+ previous.trigger( 'selection:unsingle', previous, this );
+
+ // If the model was already removed, trigger the collection
+ // event manually.
+ if ( ! this.get( previous.cid ) )
+ this.trigger( 'selection:unsingle', previous, this );
+ }
+ if ( this._single )
+ this._single.trigger( 'selection:single', this._single, this );
+ }
+
+ // Return the single model, or the last model as a fallback.
+ return this._single;
+ }
+ });
+
+ // Clean up. Prevents mobile browsers caching
+ $(window).on('unload', function(){
+ window.wp = null;
+ });
+
+}(jQuery)); \ No newline at end of file
diff --git a/src/wp-includes/js/media-views.js b/src/wp-includes/js/media-views.js
new file mode 100644
index 0000000000..a14a57b042
--- /dev/null
+++ b/src/wp-includes/js/media-views.js
@@ -0,0 +1,3966 @@
+(function($){
+ var media = wp.media,
+ Attachment = media.model.Attachment,
+ Attachments = media.model.Attachments,
+ Query = media.model.Query,
+ l10n;
+
+ // Link any localized strings.
+ l10n = media.view.l10n = typeof _wpMediaViewsL10n === 'undefined' ? {} : _wpMediaViewsL10n;
+
+ // Link any settings.
+ media.view.settings = l10n.settings || {};
+ delete l10n.settings;
+
+ // Copy the `post` setting over to the model settings.
+ media.model.settings.post = media.view.settings.post;
+
+ // Check if the browser supports CSS 3.0 transitions
+ $.support.transition = (function(){
+ var style = document.documentElement.style,
+ transitions = {
+ WebkitTransition: 'webkitTransitionEnd',
+ MozTransition: 'transitionend',
+ OTransition: 'oTransitionEnd otransitionend',
+ transition: 'transitionend'
+ }, transition;
+
+ transition = _.find( _.keys( transitions ), function( transition ) {
+ return ! _.isUndefined( style[ transition ] );
+ });
+
+ return transition && {
+ end: transitions[ transition ]
+ };
+ }());
+
+ // Makes it easier to bind events using transitions.
+ media.transition = function( selector, sensitivity ) {
+ var deferred = $.Deferred();
+
+ sensitivity = sensitivity || 2000;
+
+ if ( $.support.transition ) {
+ if ( ! (selector instanceof $) )
+ selector = $( selector );
+
+ // Resolve the deferred when the first element finishes animating.
+ selector.first().one( $.support.transition.end, deferred.resolve );
+
+ // Just in case the event doesn't trigger, fire a callback.
+ _.delay( deferred.resolve, sensitivity );
+
+ // Otherwise, execute on the spot.
+ } else {
+ deferred.resolve();
+ }
+
+ return deferred.promise();
+ };
+
+ /**
+ * ========================================================================
+ * CONTROLLERS
+ * ========================================================================
+ */
+
+ /**
+ * wp.media.controller.Region
+ */
+ media.controller.Region = function( options ) {
+ _.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
+ };
+
+ // Use Backbone's self-propagating `extend` inheritance method.
+ media.controller.Region.extend = Backbone.Model.extend;
+
+ _.extend( media.controller.Region.prototype, {
+ mode: function( mode ) {
+ if ( ! mode )
+ return this._mode;
+
+ // Bail if we're trying to change to the current mode.
+ if ( mode === this._mode )
+ return this;
+
+ this.trigger('deactivate');
+ this._mode = mode;
+ this.render( mode );
+ this.trigger('activate');
+ return this;
+ },
+
+ render: function( mode ) {
+ // If no mode is provided, just re-render the current mode.
+ // If the provided mode isn't active, perform a full switch.
+ if ( mode && mode !== this._mode )
+ return this.mode( mode );
+
+ var set = { view: null },
+ view;
+
+ this.trigger( 'create', set );
+ view = set.view;
+ this.trigger( 'render', view );
+ if ( view )
+ this.set( view );
+ return this;
+ },
+
+ get: function() {
+ return this.view.views.first( this.selector );
+ },
+
+ set: function( views, options ) {
+ if ( options )
+ options.add = false;
+ return this.view.views.set( this.selector, views, options );
+ },
+
+ trigger: function( event ) {
+ var base;
+ if ( ! this._mode )
+ return;
+
+ var args = _.toArray( arguments );
+ base = this.id + ':' + event;
+
+ // Trigger `region:action:mode` event.
+ args[0] = base + ':' + this._mode;
+ this.view.trigger.apply( this.view, args );
+
+ // Trigger `region:action` event.
+ args[0] = base;
+ this.view.trigger.apply( this.view, args );
+ return this;
+ }
+ });
+
+ /**
+ * wp.media.controller.StateMachine
+ */
+ media.controller.StateMachine = function( states ) {
+ this.states = new Backbone.Collection( states );
+ };
+
+ // Use Backbone's self-propagating `extend` inheritance method.
+ media.controller.StateMachine.extend = Backbone.Model.extend;
+
+ // Add events to the `StateMachine`.
+ _.extend( media.controller.StateMachine.prototype, Backbone.Events, {
+
+ // Fetch a state.
+ //
+ // If no `id` is provided, returns the active state.
+ //
+ // Implicitly creates states.
+ state: function( id ) {
+ // Ensure that the `states` collection exists so the `StateMachine`
+ // can be used as a mixin.
+ this.states = this.states || new Backbone.Collection();
+
+ // Default to the active state.
+ id = id || this._state;
+
+ if ( id && ! this.states.get( id ) )
+ this.states.add({ id: id });
+ return this.states.get( id );
+ },
+
+ // Sets the active state.
+ setState: function( id ) {
+ var previous = this.state();
+
+ // Bail if we're trying to select the current state, if we haven't
+ // created the `states` collection, or are trying to select a state
+ // that does not exist.
+ if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) )
+ return this;
+
+ if ( previous ) {
+ previous.trigger('deactivate');
+ this._lastState = previous.id;
+ }
+
+ this._state = id;
+ this.state().trigger('activate');
+
+ return this;
+ },
+
+ // Returns the previous active state.
+ //
+ // Call the `state()` method with no parameters to retrieve the current
+ // active state.
+ lastState: function() {
+ if ( this._lastState )
+ return this.state( this._lastState );
+ }
+ });
+
+ // Map methods from the `states` collection to the `StateMachine` itself.
+ _.each([ 'on', 'off', 'trigger' ], function( method ) {
+ media.controller.StateMachine.prototype[ method ] = function() {
+ // Ensure that the `states` collection exists so the `StateMachine`
+ // can be used as a mixin.
+ this.states = this.states || new Backbone.Collection();
+ // Forward the method to the `states` collection.
+ this.states[ method ].apply( this.states, arguments );
+ return this;
+ };
+ });
+
+
+ // wp.media.controller.State
+ // ---------------------------
+ media.controller.State = Backbone.Model.extend({
+ constructor: function() {
+ this.on( 'activate', this._preActivate, this );
+ this.on( 'activate', this.activate, this );
+ this.on( 'activate', this._postActivate, this );
+ this.on( 'deactivate', this._deactivate, this );
+ this.on( 'deactivate', this.deactivate, this );
+ this.on( 'reset', this.reset, this );
+ this.on( 'ready', this._ready, this );
+ this.on( 'ready', this.ready, this );
+ Backbone.Model.apply( this, arguments );
+ this.on( 'change:menu', this._updateMenu, this );
+ },
+
+ ready: function() {},
+ activate: function() {},
+ deactivate: function() {},
+ reset: function() {},
+
+ _ready: function() {
+ this._updateMenu();
+ },
+
+ _preActivate: function() {
+ this.active = true;
+ },
+
+ _postActivate: function() {
+ this.on( 'change:menu', this._menu, this );
+ this.on( 'change:titleMode', this._title, this );
+ this.on( 'change:content', this._content, this );
+ this.on( 'change:toolbar', this._toolbar, this );
+
+ this.frame.on( 'title:render:default', this._renderTitle, this );
+
+ this._title();
+ this._menu();
+ this._toolbar();
+ this._content();
+ this._router();
+ },
+
+
+ _deactivate: function() {
+ this.active = false;
+
+ this.frame.off( 'title:render:default', this._renderTitle, this );
+
+ this.off( 'change:menu', this._menu, this );
+ this.off( 'change:titleMode', this._title, this );
+ this.off( 'change:content', this._content, this );
+ this.off( 'change:toolbar', this._toolbar, this );
+ },
+
+ _title: function() {
+ this.frame.title.render( this.get('titleMode') || 'default' );
+ },
+
+ _renderTitle: function( view ) {
+ view.$el.text( this.get('title') || '' );
+ },
+
+ _router: function() {
+ var router = this.frame.router,
+ mode = this.get('router'),
+ view;
+
+ this.frame.$el.toggleClass( 'hide-router', ! mode );
+ if ( ! mode )
+ return;
+
+ this.frame.router.render( mode );
+
+ view = router.get();
+ if ( view && view.select )
+ view.select( this.frame.content.mode() );
+ },
+
+ _menu: function() {
+ var menu = this.frame.menu,
+ mode = this.get('menu'),
+ view;
+
+ if ( ! mode )
+ return;
+
+ menu.mode( mode );
+
+ view = menu.get();
+ if ( view && view.select )
+ view.select( this.id );
+ },
+
+ _updateMenu: function() {
+ var previous = this.previous('menu'),
+ menu = this.get('menu');
+
+ if ( previous )
+ this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
+
+ if ( menu )
+ this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
+ },
+
+ _renderMenu: function( view ) {
+ var menuItem = this.get('menuItem'),
+ title = this.get('title'),
+ priority = this.get('priority');
+
+ if ( ! menuItem && title ) {
+ menuItem = { text: title };
+
+ if ( priority )
+ menuItem.priority = priority;
+ }
+
+ if ( ! menuItem )
+ return;
+
+ view.set( this.id, menuItem );
+ }
+ });
+
+ _.each(['toolbar','content'], function( region ) {
+ media.controller.State.prototype[ '_' + region ] = function() {
+ var mode = this.get( region );
+ if ( mode )
+ this.frame[ region ].render( mode );
+ };
+ });
+
+ // wp.media.controller.Library
+ // ---------------------------
+ media.controller.Library = media.controller.State.extend({
+ defaults: {
+ id: 'library',
+ multiple: false, // false, 'add', 'reset'
+ describe: false,
+ toolbar: 'select',
+ sidebar: 'settings',
+ content: 'upload',
+ router: 'browse',
+ menu: 'default',
+ searchable: true,
+ filterable: false,
+ sortable: true,
+ title: l10n.mediaLibraryTitle,
+
+ // Uses a user setting to override the content mode.
+ contentUserSetting: true,
+
+ // Sync the selection from the last state when 'multiple' matches.
+ syncSelection: true
+ },
+
+ initialize: function() {
+ var selection = this.get('selection'),
+ props;
+
+ // If a library isn't provided, query all media items.
+ if ( ! this.get('library') )
+ this.set( 'library', media.query() );
+
+ // If a selection instance isn't provided, create one.
+ if ( ! (selection instanceof media.model.Selection) ) {
+ props = selection;
+
+ if ( ! props ) {
+ props = this.get('library').props.toJSON();
+ props = _.omit( props, 'orderby', 'query' );
+ }
+
+ // If the `selection` attribute is set to an object,
+ // it will use those values as the selection instance's
+ // `props` model. Otherwise, it will copy the library's
+ // `props` model.
+ this.set( 'selection', new media.model.Selection( null, {
+ multiple: this.get('multiple'),
+ props: props
+ }) );
+ }
+
+ if ( ! this.get('edge') )
+ this.set( 'edge', 120 );
+
+ if ( ! this.get('gutter') )
+ this.set( 'gutter', 8 );
+
+ this.resetDisplays();
+ },
+
+ activate: function() {
+ this.syncSelection();
+
+ wp.Uploader.queue.on( 'add', this.uploading, this );
+
+ this.get('selection').on( 'add remove reset', this.refreshContent, this );
+
+ if ( this.get('contentUserSetting') ) {
+ this.frame.on( 'content:activate', this.saveContentMode, this );
+ this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
+ }
+ },
+
+ deactivate: function() {
+ this.recordSelection();
+
+ this.frame.off( 'content:activate', this.saveContentMode, this );
+
+ // Unbind all event handlers that use this state as the context
+ // from the selection.
+ this.get('selection').off( null, null, this );
+
+ wp.Uploader.queue.off( null, null, this );
+ },
+
+ reset: function() {
+ this.get('selection').reset();
+ this.resetDisplays();
+ this.refreshContent();
+ },
+
+ resetDisplays: function() {
+ var defaultProps = media.view.settings.defaultProps;
+ this._displays = [];
+ this._defaultDisplaySettings = {
+ align: defaultProps.align || getUserSetting( 'align', 'none' ),
+ size: defaultProps.size || getUserSetting( 'imgsize', 'medium' ),
+ link: defaultProps.link || getUserSetting( 'urlbutton', 'file' )
+ };
+ },
+
+ display: function( attachment ) {
+ var displays = this._displays;
+
+ if ( ! displays[ attachment.cid ] )
+ displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
+
+ return displays[ attachment.cid ];
+ },
+
+ defaultDisplaySettings: function( attachment ) {
+ settings = this._defaultDisplaySettings;
+ if ( settings.canEmbed = this.canEmbed( attachment ) )
+ settings.link = 'embed';
+ return settings;
+ },
+
+ canEmbed: function( attachment ) {
+ // If uploading, we know the filename but not the mime type.
+ if ( ! attachment.get('uploading') ) {
+ var type = attachment.get('type');
+ if ( type !== 'audio' && type !== 'video' )
+ return false;
+ }
+
+ return _.contains( media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
+ },
+
+ syncSelection: function() {
+ var selection = this.get('selection'),
+ manager = this.frame._selection;
+
+ if ( ! this.get('syncSelection') || ! manager || ! selection )
+ return;
+
+ // If the selection supports multiple items, validate the stored
+ // attachments based on the new selection's conditions. Record
+ // the attachments that are not included; we'll maintain a
+ // reference to those. Other attachments are considered in flux.
+ if ( selection.multiple ) {
+ selection.reset( [], { silent: true });
+ selection.validateAll( manager.attachments );
+ manager.difference = _.difference( manager.attachments.models, selection.models );
+ }
+
+ // Sync the selection's single item with the master.
+ selection.single( manager.single );
+ },
+
+ recordSelection: function() {
+ var selection = this.get('selection'),
+ manager = this.frame._selection,
+ filtered;
+
+ if ( ! this.get('syncSelection') || ! manager || ! selection )
+ return;
+
+ // Record the currently active attachments, which is a combination
+ // of the selection's attachments and the set of selected
+ // attachments that this specific selection considered invalid.
+ // Reset the difference and record the single attachment.
+ if ( selection.multiple ) {
+ manager.attachments.reset( selection.toArray().concat( manager.difference ) );
+ manager.difference = [];
+ } else {
+ manager.attachments.add( selection.toArray() );
+ }
+
+ manager.single = selection._single;
+ },
+
+ refreshContent: function() {
+ var selection = this.get('selection'),
+ frame = this.frame,
+ router = frame.router.get(),
+ mode = frame.content.mode();
+
+ // If the state is active, no items are selected, and the current
+ // content mode is not an option in the state's router (provided
+ // the state has a router), reset the content mode to the default.
+ if ( this.active && ! selection.length && router && ! router.get( mode ) )
+ this.frame.content.render( this.get('content') );
+ },
+
+ uploading: function( attachment ) {
+ var content = this.frame.content;
+
+ // If the uploader was selected, navigate to the browser.
+ if ( 'upload' === content.mode() )
+ this.frame.content.mode('browse');
+
+ // Automatically select any uploading attachments.
+ //
+ // Selections that don't support multiple attachments automatically
+ // limit themselves to one attachment (in this case, the last
+ // attachment in the upload queue).
+ this.get('selection').add( attachment );
+ },
+
+ saveContentMode: function() {
+ // Only track the browse router on library states.
+ if ( 'browse' !== this.get('router') )
+ return;
+
+ var mode = this.frame.content.mode(),
+ view = this.frame.router.get();
+
+ if ( view && view.get( mode ) )
+ setUserSetting( 'libraryContent', mode );
+ }
+ });
+
+ // wp.media.controller.GalleryEdit
+ // -------------------------------
+ media.controller.GalleryEdit = media.controller.Library.extend({
+ defaults: {
+ id: 'gallery-edit',
+ multiple: false,
+ describe: true,
+ edge: 199,
+ editing: false,
+ sortable: true,
+ searchable: false,
+ toolbar: 'gallery-edit',
+ content: 'browse',
+ title: l10n.editGalleryTitle,
+ priority: 60,
+ dragInfo: true,
+
+ // Don't sync the selection, as the Edit Gallery library
+ // *is* the selection.
+ syncSelection: false
+ },
+
+ initialize: function() {
+ // If we haven't been provided a `library`, create a `Selection`.
+ if ( ! this.get('library') )
+ this.set( 'library', new media.model.Selection() );
+
+ // The single `Attachment` view to be used in the `Attachments` view.
+ if ( ! this.get('AttachmentView') )
+ this.set( 'AttachmentView', media.view.Attachment.EditLibrary );
+ media.controller.Library.prototype.initialize.apply( this, arguments );
+ },
+
+ activate: function() {
+ var library = this.get('library');
+
+ // Limit the library to images only.
+ library.props.set( 'type', 'image' );
+
+ // Watch for uploaded attachments.
+ this.get('library').observe( wp.Uploader.queue );
+
+ this.frame.on( 'content:render:browse', this.gallerySettings, this );
+
+ media.controller.Library.prototype.activate.apply( this, arguments );
+ },
+
+ deactivate: function() {
+ // Stop watching for uploaded attachments.
+ this.get('library').unobserve( wp.Uploader.queue );
+
+ this.frame.off( 'content:render:browse', this.gallerySettings, this );
+
+ media.controller.Library.prototype.deactivate.apply( this, arguments );
+ },
+
+ gallerySettings: function( browser ) {
+ var library = this.get('library');
+
+ if ( ! library || ! browser )
+ return;
+
+ library.gallery = library.gallery || new Backbone.Model();
+
+ browser.sidebar.set({
+ gallery: new media.view.Settings.Gallery({
+ controller: this,
+ model: library.gallery,
+ priority: 40
+ })
+ });
+
+ browser.toolbar.set( 'reverse', {
+ text: l10n.reverseOrder,
+ priority: 80,
+
+ click: function() {
+ library.reset( library.toArray().reverse() );
+ }
+ });
+ }
+ });
+
+ // wp.media.controller.GalleryAdd
+ // ---------------------------------
+ media.controller.GalleryAdd = media.controller.Library.extend({
+ defaults: _.defaults({
+ id: 'gallery-library',
+ filterable: 'uploaded',
+ multiple: 'add',
+ menu: 'gallery',
+ toolbar: 'gallery-add',
+ title: l10n.addToGalleryTitle,
+ priority: 100,
+
+ // Don't sync the selection, as the Edit Gallery library
+ // *is* the selection.
+ syncSelection: false
+ }, media.controller.Library.prototype.defaults ),
+
+ initialize: function() {
+ // If we haven't been provided a `library`, create a `Selection`.
+ if ( ! this.get('library') )
+ this.set( 'library', media.query({ type: 'image' }) );
+
+ media.controller.Library.prototype.initialize.apply( this, arguments );
+ },
+
+ activate: function() {
+ var library = this.get('library'),
+ edit = this.frame.state('gallery-edit').get('library');
+
+ if ( this.editLibrary && this.editLibrary !== edit )
+ library.unobserve( this.editLibrary );
+
+ // Accepts attachments that exist in the original library and
+ // that do not exist in gallery's library.
+ library.validator = function( attachment ) {
+ return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && media.model.Selection.prototype.validator.apply( this, arguments );
+ };
+
+ // Reset the library to ensure that all attachments are re-added
+ // to the collection. Do so silently, as calling `observe` will
+ // trigger the `reset` event.
+ library.reset( library.mirroring.models, { silent: true });
+ library.observe( edit );
+ this.editLibrary = edit;
+
+ media.controller.Library.prototype.activate.apply( this, arguments );
+ }
+ });
+
+ // wp.media.controller.FeaturedImage
+ // ---------------------------------
+ media.controller.FeaturedImage = media.controller.Library.extend({
+ defaults: _.defaults({
+ id: 'featured-image',
+ filterable: 'uploaded',
+ multiple: false,
+ toolbar: 'featured-image',
+ title: l10n.setFeaturedImageTitle,
+ priority: 60,
+
+ syncSelection: false
+ }, media.controller.Library.prototype.defaults ),
+
+ initialize: function() {
+ var library, comparator;
+
+ // If we haven't been provided a `library`, create a `Selection`.
+ if ( ! this.get('library') )
+ this.set( 'library', media.query({ type: 'image' }) );
+
+ media.controller.Library.prototype.initialize.apply( this, arguments );
+
+ library = this.get('library');
+ comparator = library.comparator;
+
+ // Overload the library's comparator to push items that are not in
+ // the mirrored query to the front of the aggregate collection.
+ library.comparator = function( a, b ) {
+ var aInQuery = !! this.mirroring.get( a.cid ),
+ bInQuery = !! this.mirroring.get( b.cid );
+
+ if ( ! aInQuery && bInQuery )
+ return -1;
+ else if ( aInQuery && ! bInQuery )
+ return 1;
+ else
+ return comparator.apply( this, arguments );
+ };
+
+ // Add all items in the selection to the library, so any featured
+ // images that are not initially loaded still appear.
+ library.observe( this.get('selection') );
+ },
+
+ activate: function() {
+ this.updateSelection();
+ this.frame.on( 'open', this.updateSelection, this );
+ media.controller.Library.prototype.activate.apply( this, arguments );
+ },
+
+ deactivate: function() {
+ this.frame.off( 'open', this.updateSelection, this );
+ media.controller.Library.prototype.deactivate.apply( this, arguments );
+ },
+
+ updateSelection: function() {
+ var selection = this.get('selection'),
+ id = media.view.settings.post.featuredImageId,
+ attachment;
+
+ if ( '' !== id && -1 !== id ) {
+ attachment = Attachment.get( id );
+ attachment.fetch();
+ }
+
+ selection.reset( attachment ? [ attachment ] : [] );
+ }
+ });
+
+
+ // wp.media.controller.Embed
+ // -------------------------
+ media.controller.Embed = media.controller.State.extend({
+ defaults: {
+ id: 'embed',
+ url: '',
+ menu: 'default',
+ content: 'embed',
+ toolbar: 'main-embed',
+ type: 'link',
+
+ title: l10n.insertFromUrlTitle,
+ priority: 120
+ },
+
+ // The amount of time used when debouncing the scan.
+ sensitivity: 200,
+
+ initialize: function() {
+ this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
+ this.props = new Backbone.Model({ url: '' });
+ this.props.on( 'change:url', this.debouncedScan, this );
+ this.props.on( 'change:url', this.refresh, this );
+ this.on( 'scan', this.scanImage, this );
+ },
+
+ scan: function() {
+ var scanners,
+ embed = this,
+ attributes = {
+ type: 'link',
+ scanners: []
+ };
+
+ // Scan is triggered with the list of `attributes` to set on the
+ // state, useful for the 'type' attribute and 'scanners' attribute,
+ // an array of promise objects for asynchronous scan operations.
+ if ( this.props.get('url') )
+ this.trigger( 'scan', attributes );
+
+ if ( attributes.scanners.length ) {
+ scanners = attributes.scanners = $.when.apply( $, attributes.scanners );
+ scanners.always( function() {
+ if ( embed.get('scanners') === scanners )
+ embed.set( 'loading', false );
+ });
+ } else {
+ attributes.scanners = null;
+ }
+
+ attributes.loading = !! attributes.scanners;
+ this.set( attributes );
+ },
+
+ scanImage: function( attributes ) {
+ var frame = this.frame,
+ state = this,
+ url = this.props.get('url'),
+ image = new Image(),
+ deferred = $.Deferred();
+
+ attributes.scanners.push( deferred.promise() );
+
+ // Try to load the image and find its width/height.
+ image.onload = function() {
+ deferred.resolve();
+
+ if ( state !== frame.state() || url !== state.props.get('url') )
+ return;
+
+ state.set({
+ type: 'image'
+ });
+
+ state.props.set({
+ width: image.width,
+ height: image.height
+ });
+ };
+
+ image.onerror = deferred.reject;
+ image.src = url;
+ },
+
+ refresh: function() {
+ this.frame.toolbar.get().refresh();
+ },
+
+ reset: function() {
+ this.props.clear().set({ url: '' });
+
+ if ( this.active )
+ this.refresh();
+ }
+ });
+
+ /**
+ * ========================================================================
+ * VIEWS
+ * ========================================================================
+ */
+
+ // wp.media.View
+ // -------------
+ //
+ // The base view class.
+ //
+ // Undelegating events, removing events from the model, and
+ // removing events from the controller mirror the code for
+ // `Backbone.View.dispose` in Backbone 0.9.8 development.
+ //
+ // This behavior has since been removed, and should not be used
+ // outside of the media manager.
+ media.View = wp.Backbone.View.extend({
+ constructor: function( options ) {
+ if ( options && options.controller )
+ this.controller = options.controller;
+
+ wp.Backbone.View.apply( this, arguments );
+ },
+
+ dispose: function() {
+ // Undelegating events, removing events from the model, and
+ // removing events from the controller mirror the code for
+ // `Backbone.View.dispose` in Backbone 0.9.8 development.
+ this.undelegateEvents();
+
+ if ( this.model && this.model.off )
+ this.model.off( null, null, this );
+
+ if ( this.collection && this.collection.off )
+ this.collection.off( null, null, this );
+
+ // Unbind controller events.
+ if ( this.controller && this.controller.off )
+ this.controller.off( null, null, this );
+
+ return this;
+ },
+
+ remove: function() {
+ this.dispose();
+ return wp.Backbone.View.prototype.remove.apply( this, arguments );
+ }
+ });
+
+ /**
+ * wp.media.view.Frame
+ */
+ media.view.Frame = media.View.extend({
+ initialize: function() {
+ this._createRegions();
+ this._createStates();
+ },
+
+ _createRegions: function() {
+ // Clone the regions array.
+ this.regions = this.regions ? this.regions.slice() : [];
+
+ // Initialize regions.
+ _.each( this.regions, function( region ) {
+ this[ region ] = new media.controller.Region({
+ view: this,
+ id: region,
+ selector: '.media-frame-' + region
+ });
+ }, this );
+ },
+
+ _createStates: function() {
+ // Create the default `states` collection.
+ this.states = new Backbone.Collection( null, {
+ model: media.controller.State
+ });
+
+ // Ensure states have a reference to the frame.
+ this.states.on( 'add', function( model ) {
+ model.frame = this;
+ model.trigger('ready');
+ }, this );
+
+ if ( this.options.states )
+ this.states.add( this.options.states );
+ },
+
+ reset: function() {
+ this.states.invoke( 'trigger', 'reset' );
+ return this;
+ }
+ });
+
+ // Make the `Frame` a `StateMachine`.
+ _.extend( media.view.Frame.prototype, media.controller.StateMachine.prototype );
+
+ /**
+ * wp.media.view.MediaFrame
+ */
+ media.view.MediaFrame = media.view.Frame.extend({
+ className: 'media-frame',
+ template: media.template('media-frame'),
+ regions: ['menu','title','content','toolbar','router'],
+
+ initialize: function() {
+ media.view.Frame.prototype.initialize.apply( this, arguments );
+
+ _.defaults( this.options, {
+ title: '',
+ modal: true,
+ uploader: true
+ });
+
+ // Ensure core UI is enabled.
+ this.$el.addClass('wp-core-ui');
+
+ // Initialize modal container view.
+ if ( this.options.modal ) {
+ this.modal = new media.view.Modal({
+ controller: this,
+ title: this.options.title
+ });
+
+ this.modal.content( this );
+ }
+
+ // Force the uploader off if the upload limit has been exceeded or
+ // if the browser isn't supported.
+ if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported )
+ this.options.uploader = false;
+
+ // Initialize window-wide uploader.
+ if ( this.options.uploader ) {
+ this.uploader = new media.view.UploaderWindow({
+ controller: this,
+ uploader: {
+ dropzone: this.modal ? this.modal.$el : this.$el,
+ container: this.$el
+ }
+ });
+ this.views.set( '.media-frame-uploader', this.uploader );
+ }
+
+ this.on( 'attach', _.bind( this.views.ready, this.views ), this );
+
+ // Bind default title creation.
+ this.on( 'title:create:default', this.createTitle, this );
+ this.title.mode('default');
+
+ // Bind default menu.
+ this.on( 'menu:create:default', this.createMenu, this );
+ },
+
+ render: function() {
+ // Activate the default state if no active state exists.
+ if ( ! this.state() && this.options.state )
+ this.setState( this.options.state );
+
+ return media.view.Frame.prototype.render.apply( this, arguments );
+ },
+
+ createTitle: function( title ) {
+ title.view = new media.View({
+ controller: this,
+ tagName: 'h1'
+ });
+ },
+
+ createMenu: function( menu ) {
+ menu.view = new media.view.Menu({
+ controller: this
+ });
+ },
+
+ createToolbar: function( toolbar ) {
+ toolbar.view = new media.view.Toolbar({
+ controller: this
+ });
+ },
+
+ createRouter: function( router ) {
+ router.view = new media.view.Router({
+ controller: this
+ });
+ },
+
+ createIframeStates: function( options ) {
+ var settings = media.view.settings,
+ tabs = settings.tabs,
+ tabUrl = settings.tabUrl,
+ $postId;
+
+ if ( ! tabs || ! tabUrl )
+ return;
+
+ // Add the post ID to the tab URL if it exists.
+ $postId = $('#post_ID');
+ if ( $postId.length )
+ tabUrl += '&post_id=' + $postId.val();
+
+ // Generate the tab states.
+ _.each( tabs, function( title, id ) {
+ var frame = this.state( 'iframe:' + id ).set( _.defaults({
+ tab: id,
+ src: tabUrl + '&tab=' + id,
+ title: title,
+ content: 'iframe',
+ menu: 'default'
+ }, options ) );
+ }, this );
+
+ this.on( 'content:create:iframe', this.iframeContent, this );
+ this.on( 'menu:render:default', this.iframeMenu, this );
+ this.on( 'open', this.hijackThickbox, this );
+ this.on( 'close', this.restoreThickbox, this );
+ },
+
+ iframeContent: function( content ) {
+ this.$el.addClass('hide-toolbar');
+ content.view = new media.view.Iframe({
+ controller: this
+ });
+ },
+
+ iframeMenu: function( view ) {
+ var views = {};
+
+ if ( ! view )
+ return;
+
+ _.each( media.view.settings.tabs, function( title, id ) {
+ views[ 'iframe:' + id ] = {
+ text: this.state( 'iframe:' + id ).get('title'),
+ priority: 200
+ };
+ }, this );
+
+ view.set( views );
+ },
+
+ hijackThickbox: function() {
+ var frame = this;
+
+ if ( ! window.tb_remove || this._tb_remove )
+ return;
+
+ this._tb_remove = window.tb_remove;
+ window.tb_remove = function() {
+ frame.close();
+ frame.reset();
+ frame.setState( frame.options.state );
+ frame._tb_remove.call( window );
+ };
+ },
+
+ restoreThickbox: function() {
+ if ( ! this._tb_remove )
+ return;
+
+ window.tb_remove = this._tb_remove;
+ delete this._tb_remove;
+ }
+ });
+
+ // Map some of the modal's methods to the frame.
+ _.each(['open','close','attach','detach','escape'], function( method ) {
+ media.view.MediaFrame.prototype[ method ] = function( view ) {
+ if ( this.modal )
+ this.modal[ method ].apply( this.modal, arguments );
+ return this;
+ };
+ });
+
+ /**
+ * wp.media.view.MediaFrame.Select
+ */
+ media.view.MediaFrame.Select = media.view.MediaFrame.extend({
+ initialize: function() {
+ media.view.MediaFrame.prototype.initialize.apply( this, arguments );
+
+ _.defaults( this.options, {
+ selection: [],
+ library: {},
+ multiple: false,
+ state: 'library'
+ });
+
+ this.createSelection();
+ this.createStates();
+ this.bindHandlers();
+ },
+
+ createSelection: function() {
+ var controller = this,
+ selection = this.options.selection;
+
+ if ( ! (selection instanceof media.model.Selection) ) {
+ this.options.selection = new media.model.Selection( selection, {
+ multiple: this.options.multiple
+ });
+ }
+
+ this._selection = {
+ attachments: new Attachments(),
+ difference: []
+ };
+ },
+
+ createStates: function() {
+ var options = this.options;
+
+ if ( this.options.states )
+ return;
+
+ // Add the default states.
+ this.states.add([
+ // Main states.
+ new media.controller.Library({
+ library: media.query( options.library ),
+ multiple: options.multiple,
+ title: options.title,
+ priority: 20
+ })
+ ]);
+ },
+
+ bindHandlers: function() {
+ this.on( 'router:create:browse', this.createRouter, this );
+ this.on( 'router:render:browse', this.browseRouter, this );
+ this.on( 'content:create:browse', this.browseContent, this );
+ this.on( 'content:render:upload', this.uploadContent, this );
+ this.on( 'toolbar:create:select', this.createSelectToolbar, this );
+ },
+
+ // Routers
+ browseRouter: function( view ) {
+ view.set({
+ upload: {
+ text: l10n.uploadFilesTitle,
+ priority: 20
+ },
+ browse: {
+ text: l10n.mediaLibraryTitle,
+ priority: 40
+ }
+ });
+ },
+
+ // Content
+ browseContent: function( content ) {
+ var state = this.state();
+
+ this.$el.removeClass('hide-toolbar');
+
+ // Browse our library of attachments.
+ content.view = new media.view.AttachmentsBrowser({
+ controller: this,
+ collection: state.get('library'),
+ selection: state.get('selection'),
+ model: state,
+ sortable: state.get('sortable'),
+ search: state.get('searchable'),
+ filters: state.get('filterable'),
+ display: state.get('displaySettings'),
+ dragInfo: state.get('dragInfo'),
+
+ AttachmentView: state.get('AttachmentView')
+ });
+ },
+
+ uploadContent: function() {
+ this.$el.removeClass('hide-toolbar');
+ this.content.set( new media.view.UploaderInline({
+ controller: this
+ }) );
+ },
+
+ // Toolbars
+ createSelectToolbar: function( toolbar, options ) {
+ options = options || this.options.button || {};
+ options.controller = this;
+
+ toolbar.view = new media.view.Toolbar.Select( options );
+ }
+ });
+
+ /**
+ * wp.media.view.MediaFrame.Post
+ */
+ media.view.MediaFrame.Post = media.view.MediaFrame.Select.extend({
+ initialize: function() {
+ _.defaults( this.options, {
+ multiple: true,
+ editing: false,
+ state: 'insert'
+ });
+
+ media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
+ this.createIframeStates();
+ },
+
+ createStates: function() {
+ var options = this.options;
+
+ // Add the default states.
+ this.states.add([
+ // Main states.
+ new media.controller.Library({
+ id: 'insert',
+ title: l10n.insertMediaTitle,
+ priority: 20,
+ toolbar: 'main-insert',
+ filterable: 'all',
+ library: media.query( options.library ),
+ multiple: options.multiple ? 'reset' : false,
+ editable: true,
+
+ // If the user isn't allowed to edit fields,
+ // can they still edit it locally?
+ allowLocalEdits: true,
+
+ // Show the attachment display settings.
+ displaySettings: true,
+ // Update user settings when users adjust the
+ // attachment display settings.
+ displayUserSettings: true
+ }),
+
+ new media.controller.Library({
+ id: 'gallery',
+ title: l10n.createGalleryTitle,
+ priority: 40,
+ toolbar: 'main-gallery',
+ filterable: 'uploaded',
+ multiple: 'add',
+ editable: false,
+
+ library: media.query( _.defaults({
+ type: 'image'
+ }, options.library ) )
+ }),
+
+ // Embed states.
+ new media.controller.Embed(),
+
+ // Gallery states.
+ new media.controller.GalleryEdit({
+ library: options.selection,
+ editing: options.editing,
+ menu: 'gallery'
+ }),
+
+ new media.controller.GalleryAdd()
+ ]);
+
+
+ if ( media.view.settings.post.featuredImageId ) {
+ this.states.add( new media.controller.FeaturedImage() );
+ }
+ },
+
+ bindHandlers: function() {
+ media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
+ this.on( 'menu:create:gallery', this.createMenu, this );
+ this.on( 'toolbar:create:main-insert', this.createToolbar, this );
+ this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
+ this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
+ this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
+
+ var handlers = {
+ menu: {
+ 'default': 'mainMenu',
+ 'gallery': 'galleryMenu'
+ },
+
+ content: {
+ 'embed': 'embedContent',
+ 'edit-selection': 'editSelectionContent'
+ },
+
+ toolbar: {
+ 'main-insert': 'mainInsertToolbar',
+ 'main-gallery': 'mainGalleryToolbar',
+ 'gallery-edit': 'galleryEditToolbar',
+ 'gallery-add': 'galleryAddToolbar'
+ }
+ };
+
+ _.each( handlers, function( regionHandlers, region ) {
+ _.each( regionHandlers, function( callback, handler ) {
+ this.on( region + ':render:' + handler, this[ callback ], this );
+ }, this );
+ }, this );
+ },
+
+ // Menus
+ mainMenu: function( view ) {
+ view.set({
+ 'library-separator': new media.View({
+ className: 'separator',
+ priority: 100
+ })
+ });
+ },
+
+ galleryMenu: function( view ) {
+ var lastState = this.lastState(),
+ previous = lastState && lastState.id,
+ frame = this;
+
+ view.set({
+ cancel: {
+ text: l10n.cancelGalleryTitle,
+ priority: 20,
+ click: function() {
+ if ( previous )
+ frame.setState( previous );
+ else
+ frame.close();
+ }
+ },
+ separateCancel: new media.View({
+ className: 'separator',
+ priority: 40
+ })
+ });
+ },
+
+ // Content
+ embedContent: function() {
+ var view = new media.view.Embed({
+ controller: this,
+ model: this.state()
+ }).render();
+
+ this.content.set( view );
+ view.url.focus();
+ },
+
+ editSelectionContent: function() {
+ var state = this.state(),
+ selection = state.get('selection'),
+ view;
+
+ view = new media.view.AttachmentsBrowser({
+ controller: this,
+ collection: selection,
+ selection: selection,
+ model: state,
+ sortable: true,
+ search: false,
+ dragInfo: true,
+
+ AttachmentView: media.view.Attachment.EditSelection
+ }).render();
+
+ view.toolbar.set( 'backToLibrary', {
+ text: l10n.returnToLibrary,
+ priority: -100,
+
+ click: function() {
+ this.controller.content.mode('browse');
+ }
+ });
+
+ // Browse our library of attachments.
+ this.content.set( view );
+ },
+
+ // Toolbars
+ selectionStatusToolbar: function( view ) {
+ var editable = this.state().get('editable');
+
+ view.set( 'selection', new media.view.Selection({
+ controller: this,
+ collection: this.state().get('selection'),
+ priority: -40,
+
+ // If the selection is editable, pass the callback to
+ // switch the content mode.
+ editable: editable && function() {
+ this.controller.content.mode('edit-selection');
+ }
+ }).render() );
+ },
+
+ mainInsertToolbar: function( view ) {
+ var controller = this;
+
+ this.selectionStatusToolbar( view );
+
+ view.set( 'insert', {
+ style: 'primary',
+ priority: 80,
+ text: l10n.insertIntoPost,
+ requires: { selection: true },
+
+ click: function() {
+ var state = controller.state(),
+ selection = state.get('selection');
+
+ controller.close();
+ state.trigger( 'insert', selection ).reset();
+ }
+ });
+ },
+
+ mainGalleryToolbar: function( view ) {
+ var controller = this;
+
+ this.selectionStatusToolbar( view );
+
+ view.set( 'gallery', {
+ style: 'primary',
+ text: l10n.createNewGallery,
+ priority: 60,
+ requires: { selection: true },
+
+ click: function() {
+ var selection = controller.state().get('selection'),
+ edit = controller.state('gallery-edit'),
+ models = selection.where({ type: 'image' });
+
+ edit.set( 'library', new media.model.Selection( models, {
+ props: selection.props.toJSON(),
+ multiple: true
+ }) );
+
+ this.controller.setState('gallery-edit');
+ }
+ });
+ },
+
+ featuredImageToolbar: function( toolbar ) {
+ this.createSelectToolbar( toolbar, {
+ text: l10n.setFeaturedImage,
+ state: this.options.state
+ });
+ },
+
+ mainEmbedToolbar: function( toolbar ) {
+ toolbar.view = new media.view.Toolbar.Embed({
+ controller: this
+ });
+ },
+
+ galleryEditToolbar: function() {
+ var editing = this.state().get('editing');
+ this.toolbar.set( new media.view.Toolbar({
+ controller: this,
+ items: {
+ insert: {
+ style: 'primary',
+ text: editing ? l10n.updateGallery : l10n.insertGallery,
+ priority: 80,
+ requires: { library: true },
+
+ click: function() {
+ var controller = this.controller,
+ state = controller.state();
+
+ controller.close();
+ state.trigger( 'update', state.get('library') );
+
+ // Restore and reset the default state.
+ controller.setState( controller.options.state );
+ controller.reset();
+ }
+ }
+ }
+ }) );
+ },
+
+ galleryAddToolbar: function() {
+ this.toolbar.set( new media.view.Toolbar({
+ controller: this,
+ items: {
+ insert: {
+ style: 'primary',
+ text: l10n.addToGallery,
+ priority: 80,
+ requires: { selection: true },
+
+ click: function() {
+ var controller = this.controller,
+ state = controller.state(),
+ edit = controller.state('gallery-edit');
+
+ edit.get('library').add( state.get('selection').models );
+ state.trigger('reset');
+ controller.setState('gallery-edit');
+ }
+ }
+ }
+ }) );
+ }
+ });
+
+ /**
+ * wp.media.view.Modal
+ */
+ media.view.Modal = media.View.extend({
+ tagName: 'div',
+ template: media.template('media-modal'),
+
+ attributes: {
+ tabindex: 0
+ },
+
+ events: {
+ 'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
+ 'keydown': 'keydown'
+ },
+
+ initialize: function() {
+ _.defaults( this.options, {
+ container: document.body,
+ title: '',
+ propagate: true,
+ freeze: true
+ });
+ },
+
+ prepare: function() {
+ return {
+ title: this.options.title
+ };
+ },
+
+ attach: function() {
+ if ( this.views.attached )
+ return this;
+
+ if ( ! this.views.rendered )
+ this.render();
+
+ this.$el.appendTo( this.options.container );
+
+ // Manually mark the view as attached and trigger ready.
+ this.views.attached = true;
+ this.views.ready();
+
+ return this.propagate('attach');
+ },
+
+ detach: function() {
+ if ( this.$el.is(':visible') )
+ this.close();
+
+ this.$el.detach();
+ this.views.attached = false;
+ return this.propagate('detach');
+ },
+
+ open: function() {
+ var $el = this.$el,
+ options = this.options;
+
+ if ( $el.is(':visible') )
+ return this;
+
+ if ( ! this.views.attached )
+ this.attach();
+
+ // If the `freeze` option is set, record the window's scroll position.
+ if ( options.freeze ) {
+ this._freeze = {
+ scrollTop: $( window ).scrollTop()
+ };
+ }
+
+ $el.show().focus();
+ return this.propagate('open');
+ },
+
+ close: function( options ) {
+ var freeze = this._freeze;
+
+ if ( ! this.views.attached || ! this.$el.is(':visible') )
+ return this;
+
+ this.$el.hide();
+ this.propagate('close');
+
+ // If the `freeze` option is set, restore the container's scroll position.
+ if ( freeze ) {
+ $( window ).scrollTop( freeze.scrollTop );
+ }
+
+ if ( options && options.escape )
+ this.propagate('escape');
+
+ return this;
+ },
+
+ escape: function() {
+ return this.close({ escape: true });
+ },
+
+ escapeHandler: function( event ) {
+ event.preventDefault();
+ this.escape();
+ },
+
+ content: function( content ) {
+ this.views.set( '.media-modal-content', content );
+ return this;
+ },
+
+ // Triggers a modal event and if the `propagate` option is set,
+ // forwards events to the modal's controller.
+ propagate: function( id ) {
+ this.trigger( id );
+
+ if ( this.options.propagate )
+ this.controller.trigger( id );
+
+ return this;
+ },
+
+ keydown: function( event ) {
+ // Close the modal when escape is pressed.
+ if ( 27 === event.which ) {
+ event.preventDefault();
+ this.escape();
+ return;
+ }
+ }
+ });
+
+ // wp.media.view.FocusManager
+ // ----------------------------
+ media.view.FocusManager = media.View.extend({
+ events: {
+ keydown: 'recordTab',
+ focusin: 'updateIndex'
+ },
+
+ focus: function() {
+ if ( _.isUndefined( this.index ) )
+ return;
+
+ // Update our collection of `$tabbables`.
+ this.$tabbables = this.$(':tabbable');
+
+ // If tab is saved, focus it.
+ this.$tabbables.eq( this.index ).focus();
+ },
+
+ recordTab: function( event ) {
+ // Look for the tab key.
+ if ( 9 !== event.keyCode )
+ return;
+
+ // First try to update the index.
+ if ( _.isUndefined( this.index ) )
+ this.updateIndex( event );
+
+ // If we still don't have an index, bail.
+ if ( _.isUndefined( this.index ) )
+ return;
+
+ var index = this.index + ( event.shiftKey ? -1 : 1 );
+
+ if ( index >= 0 && index < this.$tabbables.length )
+ this.index = index;
+ else
+ delete this.index;
+ },
+
+ updateIndex: function( event ) {
+ this.$tabbables = this.$(':tabbable');
+
+ var index = this.$tabbables.index( event.target );
+
+ if ( -1 === index )
+ delete this.index;
+ else
+ this.index = index;
+ }
+ });
+
+ // wp.media.view.UploaderWindow
+ // ----------------------------
+ media.view.UploaderWindow = media.View.extend({
+ tagName: 'div',
+ className: 'uploader-window',
+ template: media.template('uploader-window'),
+
+ initialize: function() {
+ var uploader;
+
+ this.$browser = $('<a href="#" class="browser" />').hide().appendTo('body');
+
+ uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
+ dropzone: this.$el,
+ browser: this.$browser,
+ params: {}
+ });
+
+ // Ensure the dropzone is a jQuery collection.
+ if ( uploader.dropzone && ! (uploader.dropzone instanceof $) )
+ uploader.dropzone = $( uploader.dropzone );
+
+ this.controller.on( 'activate', this.refresh, this );
+ },
+
+ refresh: function() {
+ if ( this.uploader )
+ this.uploader.refresh();
+ },
+
+ ready: function() {
+ var postId = media.view.settings.post.id,
+ dropzone;
+
+ // If the uploader already exists, bail.
+ if ( this.uploader )
+ return;
+
+ if ( postId )
+ this.options.uploader.params.post_id = postId;
+
+ this.uploader = new wp.Uploader( this.options.uploader );
+
+ dropzone = this.uploader.dropzone;
+ dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
+ dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
+ },
+
+ show: function() {
+ var $el = this.$el.show();
+
+ // Ensure that the animation is triggered by waiting until
+ // the transparent element is painted into the DOM.
+ _.defer( function() {
+ $el.css({ opacity: 1 });
+ });
+ },
+
+ hide: function() {
+ var $el = this.$el.css({ opacity: 0 });
+
+ media.transition( $el ).done( function() {
+ // Transition end events are subject to race conditions.
+ // Make sure that the value is set as intended.
+ if ( '0' === $el.css('opacity') )
+ $el.hide();
+ });
+ }
+ });
+
+ media.view.UploaderInline = media.View.extend({
+ tagName: 'div',
+ className: 'uploader-inline',
+ template: media.template('uploader-inline'),
+
+ initialize: function() {
+ _.defaults( this.options, {
+ message: '',
+ status: true
+ });
+
+ if ( ! this.options.$browser && this.controller.uploader )
+ this.options.$browser = this.controller.uploader.$browser;
+
+ if ( _.isUndefined( this.options.postId ) )
+ this.options.postId = media.view.settings.post.id;
+
+ if ( this.options.status ) {
+ this.views.set( '.upload-inline-status', new media.view.UploaderStatus({
+ controller: this.controller
+ }) );
+ }
+ },
+
+ dispose: function() {
+ if ( this.disposing )
+ return media.View.prototype.dispose.apply( this, arguments );
+
+ // Run remove on `dispose`, so we can be sure to refresh the
+ // uploader with a view-less DOM. Track whether we're disposing
+ // so we don't trigger an infinite loop.
+ this.disposing = true;
+ return this.remove();
+ },
+
+ remove: function() {
+ var result = media.View.prototype.remove.apply( this, arguments );
+
+ _.defer( _.bind( this.refresh, this ) );
+ return result;
+ },
+
+ refresh: function() {
+ var uploader = this.controller.uploader;
+
+ if ( uploader )
+ uploader.refresh();
+ },
+
+ ready: function() {
+ var $browser = this.options.$browser,
+ $placeholder;
+
+ if ( this.controller.uploader ) {
+ $placeholder = this.$('.browser');
+
+ // Check if we've already replaced the placeholder.
+ if ( $placeholder[0] === $browser[0] )
+ return;
+
+ $browser.detach().text( $placeholder.text() );
+ $browser[0].className = $placeholder[0].className;
+ $placeholder.replaceWith( $browser.show() );
+ }
+
+ this.refresh();
+ return this;
+ }
+ });
+
+ /**
+ * wp.media.view.UploaderStatus
+ */
+ media.view.UploaderStatus = media.View.extend({
+ className: 'media-uploader-status',
+ template: media.template('uploader-status'),
+
+ events: {
+ 'click .upload-dismiss-errors': 'dismiss'
+ },
+
+ initialize: function() {
+ this.queue = wp.Uploader.queue;
+ this.queue.on( 'add remove reset', this.visibility, this );
+ this.queue.on( 'add remove reset change:percent', this.progress, this );
+ this.queue.on( 'add remove reset change:uploading', this.info, this );
+
+ this.errors = wp.Uploader.errors;
+ this.errors.reset();
+ this.errors.on( 'add remove reset', this.visibility, this );
+ this.errors.on( 'add', this.error, this );
+ },
+
+ dispose: function() {
+ wp.Uploader.queue.off( null, null, this );
+ media.View.prototype.dispose.apply( this, arguments );
+ return this;
+ },
+
+ visibility: function() {
+ this.$el.toggleClass( 'uploading', !! this.queue.length );
+ this.$el.toggleClass( 'errors', !! this.errors.length );
+ this.$el.toggle( !! this.queue.length || !! this.errors.length );
+ },
+
+ ready: function() {
+ _.each({
+ '$bar': '.media-progress-bar div',
+ '$index': '.upload-index',
+ '$total': '.upload-total',
+ '$filename': '.upload-filename'
+ }, function( selector, key ) {
+ this[ key ] = this.$( selector );
+ }, this );
+
+ this.visibility();
+ this.progress();
+ this.info();
+ },
+
+ progress: function() {
+ var queue = this.queue,
+ $bar = this.$bar,
+ memo = 0;
+
+ if ( ! $bar || ! queue.length )
+ return;
+
+ $bar.width( ( queue.reduce( function( memo, attachment ) {
+ if ( ! attachment.get('uploading') )
+ return memo + 100;
+
+ var percent = attachment.get('percent');
+ return memo + ( _.isNumber( percent ) ? percent : 100 );
+ }, 0 ) / queue.length ) + '%' );
+ },
+
+ info: function() {
+ var queue = this.queue,
+ index = 0, active;
+
+ if ( ! queue.length )
+ return;
+
+ active = this.queue.find( function( attachment, i ) {
+ index = i;
+ return attachment.get('uploading');
+ });
+
+ this.$index.text( index + 1 );
+ this.$total.text( queue.length );
+ this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
+ },
+
+ filename: function( filename ) {
+ return media.truncate( _.escape( filename ), 24 );
+ },
+
+ error: function( error ) {
+ this.views.add( '.upload-errors', new media.view.UploaderStatusError({
+ filename: this.filename( error.get('file').name ),
+ message: error.get('message')
+ }), { at: 0 });
+ },
+
+ dismiss: function( event ) {
+ var errors = this.views.get('.upload-errors');
+
+ event.preventDefault();
+
+ if ( errors )
+ _.invoke( errors, 'remove' );
+ wp.Uploader.errors.reset();
+ }
+ });
+
+ media.view.UploaderStatusError = media.View.extend({
+ className: 'upload-error',
+ template: media.template('uploader-status-error')
+ });
+
+ /**
+ * wp.media.view.Toolbar
+ */
+ media.view.Toolbar = media.View.extend({
+ tagName: 'div',
+ className: 'media-toolbar',
+
+ initialize: function() {
+ var state = this.controller.state(),
+ selection = this.selection = state.get('selection'),
+ library = this.library = state.get('library');
+
+ this._views = {};
+
+ // The toolbar is composed of two `PriorityList` views.
+ this.primary = new media.view.PriorityList();
+ this.secondary = new media.view.PriorityList();
+ this.primary.$el.addClass('media-toolbar-primary');
+ this.secondary.$el.addClass('media-toolbar-secondary');
+
+ this.views.set([ this.secondary, this.primary ]);
+
+ if ( this.options.items )
+ this.set( this.options.items, { silent: true });
+
+ if ( ! this.options.silent )
+ this.render();
+
+ if ( selection )
+ selection.on( 'add remove reset', this.refresh, this );
+ if ( library )
+ library.on( 'add remove reset', this.refresh, this );
+ },
+
+ dispose: function() {
+ if ( this.selection )
+ this.selection.off( null, null, this );
+ if ( this.library )
+ this.library.off( null, null, this );
+ return media.View.prototype.dispose.apply( this, arguments );
+ },
+
+ ready: function() {
+ this.refresh();
+ },
+
+ set: function( id, view, options ) {
+ var list;
+ options = options || {};
+
+ // Accept an object with an `id` : `view` mapping.
+ if ( _.isObject( id ) ) {
+ _.each( id, function( view, id ) {
+ this.set( id, view, { silent: true });
+ }, this );
+
+ } else {
+ if ( ! ( view instanceof Backbone.View ) ) {
+ view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
+ view = new media.view.Button( view ).render();
+ }
+
+ view.controller = view.controller || this.controller;
+
+ this._views[ id ] = view;
+
+ list = view.options.priority < 0 ? 'secondary' : 'primary';
+ this[ list ].set( id, view, options );
+ }
+
+ if ( ! options.silent )
+ this.refresh();
+
+ return this;
+ },
+
+ get: function( id ) {
+ return this._views[ id ];
+ },
+
+ unset: function( id, options ) {
+ delete this._views[ id ];
+ this.primary.unset( id, options );
+ this.secondary.unset( id, options );
+
+ if ( ! options || ! options.silent )
+ this.refresh();
+ return this;
+ },
+
+ refresh: function() {
+ var state = this.controller.state(),
+ library = state.get('library'),
+ selection = state.get('selection');
+
+ _.each( this._views, function( button ) {
+ if ( ! button.model || ! button.options || ! button.options.requires )
+ return;
+
+ var requires = button.options.requires,
+ disabled = false;
+
+ // Prevent insertion of attachments if any of them are still uploading
+ disabled = _.some( selection.models, function( attachment ) {
+ return attachment.get('uploading') === true;
+ });
+
+ if ( requires.selection && selection && ! selection.length )
+ disabled = true;
+ else if ( requires.library && library && ! library.length )
+ disabled = true;
+
+ button.model.set( 'disabled', disabled );
+ });
+ }
+ });
+
+ // wp.media.view.Toolbar.Select
+ // ----------------------------
+ media.view.Toolbar.Select = media.view.Toolbar.extend({
+ initialize: function() {
+ var options = this.options,
+ controller = options.controller,
+ selection = controller.state().get('selection');
+
+ _.bindAll( this, 'clickSelect' );
+
+ _.defaults( options, {
+ event: 'select',
+ state: false,
+ reset: true,
+ close: true,
+ text: l10n.select,
+
+ // Does the button rely on the selection?
+ requires: {
+ selection: true
+ }
+ });
+
+ options.items = _.defaults( options.items || {}, {
+ select: {
+ style: 'primary',
+ text: options.text,
+ priority: 80,
+ click: this.clickSelect,
+ requires: options.requires
+ }
+ });
+
+ media.view.Toolbar.prototype.initialize.apply( this, arguments );
+ },
+
+ clickSelect: function() {
+ var options = this.options,
+ controller = this.controller;
+
+ if ( options.close )
+ controller.close();
+
+ if ( options.event )
+ controller.state().trigger( options.event );
+
+ if ( options.state )
+ controller.setState( options.state );
+
+ if ( options.reset )
+ controller.reset();
+ }
+ });
+
+ // wp.media.view.Toolbar.Embed
+ // ---------------------------
+ media.view.Toolbar.Embed = media.view.Toolbar.Select.extend({
+ initialize: function() {
+ _.defaults( this.options, {
+ text: l10n.insertIntoPost,
+ requires: false
+ });
+
+ media.view.Toolbar.Select.prototype.initialize.apply( this, arguments );
+ },
+
+ refresh: function() {
+ var url = this.controller.state().props.get('url');
+ this.get('select').model.set( 'disabled', ! url || url === 'http://' );
+
+ media.view.Toolbar.Select.prototype.refresh.apply( this, arguments );
+ }
+ });
+
+ /**
+ * wp.media.view.Button
+ */
+ media.view.Button = media.View.extend({
+ tagName: 'a',
+ className: 'media-button',
+ attributes: { href: '#' },
+
+ events: {
+ 'click': 'click'
+ },
+
+ defaults: {
+ text: '',
+ style: '',
+ size: 'large',
+ disabled: false
+ },
+
+ initialize: function() {
+ // Create a model with the provided `defaults`.
+ this.model = new Backbone.Model( this.defaults );
+
+ // If any of the `options` have a key from `defaults`, apply its
+ // value to the `model` and remove it from the `options object.
+ _.each( this.defaults, function( def, key ) {
+ var value = this.options[ key ];
+ if ( _.isUndefined( value ) )
+ return;
+
+ this.model.set( key, value );
+ delete this.options[ key ];
+ }, this );
+
+ this.model.on( 'change', this.render, this );
+ },
+
+ render: function() {
+ var classes = [ 'button', this.className ],
+ model = this.model.toJSON();
+
+ if ( model.style )
+ classes.push( 'button-' + model.style );
+
+ if ( model.size )
+ classes.push( 'button-' + model.size );
+
+ classes = _.uniq( classes.concat( this.options.classes ) );
+ this.el.className = classes.join(' ');
+
+ this.$el.attr( 'disabled', model.disabled );
+ this.$el.text( this.model.get('text') );
+
+ return this;
+ },
+
+ click: function( event ) {
+ if ( '#' === this.attributes.href )
+ event.preventDefault();
+
+ if ( this.options.click && ! this.model.get('disabled') )
+ this.options.click.apply( this, arguments );
+ }
+ });
+
+ /**
+ * wp.media.view.ButtonGroup
+ */
+ media.view.ButtonGroup = media.View.extend({
+ tagName: 'div',
+ className: 'button-group button-large media-button-group',
+
+ initialize: function() {
+ this.buttons = _.map( this.options.buttons || [], function( button ) {
+ if ( button instanceof Backbone.View )
+ return button;
+ else
+ return new media.view.Button( button ).render();
+ });
+
+ delete this.options.buttons;
+
+ if ( this.options.classes )
+ this.$el.addClass( this.options.classes );
+ },
+
+ render: function() {
+ this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
+ return this;
+ }
+ });
+
+ /**
+ * wp.media.view.PriorityList
+ */
+
+ media.view.PriorityList = media.View.extend({
+ tagName: 'div',
+
+ initialize: function() {
+ this._views = {};
+
+ this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
+ delete this.options.views;
+
+ if ( ! this.options.silent )
+ this.render();
+ },
+
+ set: function( id, view, options ) {
+ var priority, views, index;
+
+ options = options || {};
+
+ // Accept an object with an `id` : `view` mapping.
+ if ( _.isObject( id ) ) {
+ _.each( id, function( view, id ) {
+ this.set( id, view );
+ }, this );
+ return this;
+ }
+
+ if ( ! (view instanceof Backbone.View) )
+ view = this.toView( view, id, options );
+
+ view.controller = view.controller || this.controller;
+
+ this.unset( id );
+
+ priority = view.options.priority || 10;
+ views = this.views.get() || [];
+
+ _.find( views, function( existing, i ) {
+ if ( existing.options.priority > priority ) {
+ index = i;
+ return true;
+ }
+ });
+
+ this._views[ id ] = view;
+ this.views.add( view, {
+ at: _.isNumber( index ) ? index : views.length || 0
+ });
+
+ return this;
+ },
+
+ get: function( id ) {
+ return this._views[ id ];
+ },
+
+ unset: function( id ) {
+ var view = this.get( id );
+
+ if ( view )
+ view.remove();
+
+ delete this._views[ id ];
+ return this;
+ },
+
+ toView: function( options ) {
+ return new media.View( options );
+ }
+ });
+
+ /**
+ * wp.media.view.MenuItem
+ */
+ media.view.MenuItem = media.View.extend({
+ tagName: 'a',
+ className: 'media-menu-item',
+
+ attributes: {
+ href: '#'
+ },
+
+ events: {
+ 'click': '_click'
+ },
+
+ _click: function( event ) {
+ var clickOverride = this.options.click;
+
+ if ( event )
+ event.preventDefault();
+
+ if ( clickOverride )
+ clickOverride.call( this );
+ else
+ this.click();
+ },
+
+ click: function() {
+ var state = this.options.state;
+ if ( state )
+ this.controller.setState( state );
+ },
+
+ render: function() {
+ var options = this.options;
+
+ if ( options.text )
+ this.$el.text( options.text );
+ else if ( options.html )
+ this.$el.html( options.html );
+
+ return this;
+ }
+ });
+
+ /**
+ * wp.media.view.Menu
+ */
+ media.view.Menu = media.view.PriorityList.extend({
+ tagName: 'div',
+ className: 'media-menu',
+ property: 'state',
+ ItemView: media.view.MenuItem,
+ region: 'menu',
+
+ toView: function( options, id ) {
+ options = options || {};
+ options[ this.property ] = options[ this.property ] || id;
+ return new this.ItemView( options ).render();
+ },
+
+ ready: function() {
+ media.view.PriorityList.prototype.ready.apply( this, arguments );
+ this.visibility();
+ },
+
+ set: function() {
+ media.view.PriorityList.prototype.set.apply( this, arguments );
+ this.visibility();
+ },
+
+ unset: function() {
+ media.view.PriorityList.prototype.unset.apply( this, arguments );
+ this.visibility();
+ },
+
+ visibility: function() {
+ var region = this.region,
+ view = this.controller[ region ].get(),
+ views = this.views.get(),
+ hide = ! views || views.length < 2;
+
+ if ( this === view )
+ this.controller.$el.toggleClass( 'hide-' + region, hide );
+ },
+
+ select: function( id ) {
+ var view = this.get( id );
+
+ if ( ! view )
+ return;
+
+ this.deselect();
+ view.$el.addClass('active');
+ },
+
+ deselect: function() {
+ this.$el.children().removeClass('active');
+ }
+ });
+
+ /**
+ * wp.media.view.RouterItem
+ */
+ media.view.RouterItem = media.view.MenuItem.extend({
+ click: function() {
+ var contentMode = this.options.contentMode;
+ if ( contentMode )
+ this.controller.content.mode( contentMode );
+ }
+ });
+
+ /**
+ * wp.media.view.Router
+ */
+ media.view.Router = media.view.Menu.extend({
+ tagName: 'div',
+ className: 'media-router',
+ property: 'contentMode',
+ ItemView: media.view.RouterItem,
+ region: 'router',
+
+ initialize: function() {
+ this.controller.on( 'content:render', this.update, this );
+ media.view.Menu.prototype.initialize.apply( this, arguments );
+ },
+
+ update: function() {
+ var mode = this.controller.content.mode();
+ if ( mode )
+ this.select( mode );
+ }
+ });
+
+
+ /**
+ * wp.media.view.Sidebar
+ */
+ media.view.Sidebar = media.view.PriorityList.extend({
+ className: 'media-sidebar'
+ });
+
+ /**
+ * wp.media.view.Attachment
+ */
+ media.view.Attachment = media.View.extend({
+ tagName: 'li',
+ className: 'attachment',
+ template: media.template('attachment'),
+
+ events: {
+ 'click .attachment-preview': 'toggleSelectionHandler',
+ 'change [data-setting]': 'updateSetting',
+ 'change [data-setting] input': 'updateSetting',
+ 'change [data-setting] select': 'updateSetting',
+ 'change [data-setting] textarea': 'updateSetting',
+ 'click .close': 'removeFromLibrary',
+ 'click .check': 'removeFromSelection',
+ 'click a': 'preventDefault'
+ },
+
+ buttons: {},
+
+ initialize: function() {
+ var selection = this.options.selection;
+
+ this.model.on( 'change:sizes change:uploading', this.render, this );
+ this.model.on( 'change:title', this._syncTitle, this );
+ this.model.on( 'change:caption', this._syncCaption, this );
+ this.model.on( 'change:percent', this.progress, this );
+
+ // Update the selection.
+ this.model.on( 'add', this.select, this );
+ this.model.on( 'remove', this.deselect, this );
+ if ( selection )
+ selection.on( 'reset', this.updateSelect, this );
+
+ // Update the model's details view.
+ this.model.on( 'selection:single selection:unsingle', this.details, this );
+ this.details( this.model, this.controller.state().get('selection') );
+ },
+
+ dispose: function() {
+ var selection = this.options.selection;
+
+ // Make sure all settings are saved before removing the view.
+ this.updateAll();
+
+ if ( selection )
+ selection.off( null, null, this );
+
+ media.View.prototype.dispose.apply( this, arguments );
+ return this;
+ },
+
+ render: function() {
+ var options = _.defaults( this.model.toJSON(), {
+ orientation: 'landscape',
+ uploading: false,
+ type: '',
+ subtype: '',
+ icon: '',
+ filename: '',
+ caption: '',
+ title: '',
+ dateFormatted: '',
+ width: '',
+ height: '',
+ compat: false,
+ alt: '',
+ description: ''
+ });
+
+ options.buttons = this.buttons;
+ options.describe = this.controller.state().get('describe');
+
+ if ( 'image' === options.type )
+ options.size = this.imageSize();
+
+ options.can = {};
+ if ( options.nonces ) {
+ options.can.remove = !! options.nonces['delete'];
+ options.can.save = !! options.nonces.update;
+ }
+
+ if ( this.controller.state().get('allowLocalEdits') )
+ options.allowLocalEdits = true;
+
+ this.views.detach();
+ this.$el.html( this.template( options ) );
+
+ this.$el.toggleClass( 'uploading', options.uploading );
+ if ( options.uploading )
+ this.$bar = this.$('.media-progress-bar div');
+ else
+ delete this.$bar;
+
+ // Check if the model is selected.
+ this.updateSelect();
+
+ // Update the save status.
+ this.updateSave();
+
+ this.views.render();
+
+ return this;
+ },
+
+ progress: function() {
+ if ( this.$bar && this.$bar.length )
+ this.$bar.width( this.model.get('percent') + '%' );
+ },
+
+ toggleSelectionHandler: function( event ) {
+ var method;
+
+ if ( event.shiftKey )
+ method = 'between';
+ else if ( event.ctrlKey || event.metaKey )
+ method = 'toggle';
+
+ this.toggleSelection({
+ method: method
+ });
+ },
+
+ toggleSelection: function( options ) {
+ var collection = this.collection,
+ selection = this.options.selection,
+ model = this.model,
+ method = options && options.method,
+ single, between, models, singleIndex, modelIndex;
+
+ if ( ! selection )
+ return;
+
+ single = selection.single();
+ method = _.isUndefined( method ) ? selection.multiple : method;
+
+ // If the `method` is set to `between`, select all models that
+ // exist between the current and the selected model.
+ if ( 'between' === method && single && selection.multiple ) {
+ // If the models are the same, short-circuit.
+ if ( single === model )
+ return;
+
+ singleIndex = collection.indexOf( single );
+ modelIndex = collection.indexOf( this.model );
+
+ if ( singleIndex < modelIndex )
+ models = collection.models.slice( singleIndex, modelIndex + 1 );
+ else
+ models = collection.models.slice( modelIndex, singleIndex + 1 );
+
+ selection.add( models ).single( model );
+ return;
+
+ // If the `method` is set to `toggle`, just flip the selection
+ // status, regardless of whether the model is the single model.
+ } else if ( 'toggle' === method ) {
+ selection[ this.selected() ? 'remove' : 'add' ]( model ).single( model );
+ return;
+ }
+
+ if ( method !== 'add' )
+ method = 'reset';
+
+ if ( this.selected() ) {
+ // If the model is the single model, remove it.
+ // If it is not the same as the single model,
+ // it now becomes the single model.
+ selection[ single === model ? 'remove' : 'single' ]( model );
+ } else {
+ // If the model is not selected, run the `method` on the
+ // selection. By default, we `reset` the selection, but the
+ // `method` can be set to `add` the model to the selection.
+ selection[ method ]( model ).single( model );
+ }
+ },
+
+ updateSelect: function() {
+ this[ this.selected() ? 'select' : 'deselect' ]();
+ },
+
+ selected: function() {
+ var selection = this.options.selection;
+ if ( selection )
+ return !! selection.get( this.model.cid );
+ },
+
+ select: function( model, collection ) {
+ var selection = this.options.selection;
+
+ // Check if a selection exists and if it's the collection provided.
+ // If they're not the same collection, bail; we're in another
+ // selection's event loop.
+ if ( ! selection || ( collection && collection !== selection ) )
+ return;
+
+ this.$el.addClass('selected');
+ },
+
+ deselect: function( model, collection ) {
+ var selection = this.options.selection;
+
+ // Check if a selection exists and if it's the collection provided.
+ // If they're not the same collection, bail; we're in another
+ // selection's event loop.
+ if ( ! selection || ( collection && collection !== selection ) )
+ return;
+
+ this.$el.removeClass('selected');
+ },
+
+ details: function( model, collection ) {
+ var selection = this.options.selection,
+ details;
+
+ if ( selection !== collection )
+ return;
+
+ details = selection.single();
+ this.$el.toggleClass( 'details', details === this.model );
+ },
+
+ preventDefault: function( event ) {
+ event.preventDefault();
+ },
+
+ imageSize: function( size ) {
+ var sizes = this.model.get('sizes');
+
+ size = size || 'medium';
+
+ // Use the provided image size if possible.
+ if ( sizes && sizes[ size ] ) {
+ return _.clone( sizes[ size ] );
+ } else {
+ return {
+ url: this.model.get('url'),
+ width: this.model.get('width'),
+ height: this.model.get('height'),
+ orientation: this.model.get('orientation')
+ };
+ }
+ },
+
+ updateSetting: function( event ) {
+ var $setting = $( event.target ).closest('[data-setting]'),
+ setting, value;
+
+ if ( ! $setting.length )
+ return;
+
+ setting = $setting.data('setting');
+ value = event.target.value;
+
+ if ( this.model.get( setting ) !== value )
+ this.save( setting, value );
+ },
+
+ // Pass all the arguments to the model's save method.
+ //
+ // Records the aggregate status of all save requests and updates the
+ // view's classes accordingly.
+ save: function() {
+ var view = this,
+ save = this._save = this._save || { status: 'ready' },
+ request = this.model.save.apply( this.model, arguments ),
+ requests = save.requests ? $.when( request, save.requests ) : request;
+
+ // If we're waiting to remove 'Saved.', stop.
+ if ( save.savedTimer )
+ clearTimeout( save.savedTimer );
+
+ this.updateSave('waiting');
+ save.requests = requests;
+ requests.always( function() {
+ // If we've performed another request since this one, bail.
+ if ( save.requests !== requests )
+ return;
+
+ view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' );
+ save.savedTimer = setTimeout( function() {
+ view.updateSave('ready');
+ delete save.savedTimer;
+ }, 2000 );
+ });
+
+ },
+
+ updateSave: function( status ) {
+ var save = this._save = this._save || { status: 'ready' };
+
+ if ( status && status !== save.status ) {
+ this.$el.removeClass( 'save-' + save.status );
+ save.status = status;
+ }
+
+ this.$el.addClass( 'save-' + save.status );
+ return this;
+ },
+
+ updateAll: function() {
+ var $settings = this.$('[data-setting]'),
+ model = this.model,
+ changed;
+
+ changed = _.chain( $settings ).map( function( el ) {
+ var $input = $('input, textarea, select, [value]', el ),
+ setting, value;
+
+ if ( ! $input.length )
+ return;
+
+ setting = $(el).data('setting');
+ value = $input.val();
+
+ // Record the value if it changed.
+ if ( model.get( setting ) !== value )
+ return [ setting, value ];
+ }).compact().object().value();
+
+ if ( ! _.isEmpty( changed ) )
+ model.save( changed );
+ },
+
+ removeFromLibrary: function( event ) {
+ // Stop propagation so the model isn't selected.
+ event.stopPropagation();
+
+ this.collection.remove( this.model );
+ },
+
+ removeFromSelection: function( event ) {
+ var selection = this.options.selection;
+ if ( ! selection )
+ return;
+
+ // Stop propagation so the model isn't selected.
+ event.stopPropagation();
+
+ selection.remove( this.model );
+ }
+ });
+
+ // Ensure settings remain in sync between attachment views.
+ _.each({
+ caption: '_syncCaption',
+ title: '_syncTitle'
+ }, function( method, setting ) {
+ media.view.Attachment.prototype[ method ] = function( model, value ) {
+ var $setting = this.$('[data-setting="' + setting + '"]');
+
+ if ( ! $setting.length )
+ return this;
+
+ // If the updated value is in sync with the value in the DOM, there
+ // is no need to re-render. If we're currently editing the value,
+ // it will automatically be in sync, suppressing the re-render for
+ // the view we're editing, while updating any others.
+ if ( value === $setting.find('input, textarea, select, [value]').val() )
+ return this;
+
+ return this.render();
+ };
+ });
+
+ /**
+ * wp.media.view.Attachment.Library
+ */
+ media.view.Attachment.Library = media.view.Attachment.extend({
+ buttons: {
+ check: true
+ }
+ });
+
+ /**
+ * wp.media.view.Attachment.EditLibrary
+ */
+ media.view.Attachment.EditLibrary = media.view.Attachment.extend({
+ buttons: {
+ close: true
+ }
+ });
+
+ /**
+ * wp.media.view.Attachments
+ */
+ media.view.Attachments = media.View.extend({
+ tagName: 'ul',
+ className: 'attachments',
+
+ cssTemplate: media.template('attachments-css'),
+
+ events: {
+ 'scroll': 'scroll'
+ },
+
+ initialize: function() {
+ this.el.id = _.uniqueId('__attachments-view-');
+
+ _.defaults( this.options, {
+ refreshSensitivity: 200,
+ refreshThreshold: 3,
+ AttachmentView: media.view.Attachment,
+ sortable: false,
+ resize: true
+ });
+
+ this._viewsByCid = {};
+
+ this.collection.on( 'add', function( attachment, attachments, options ) {
+ this.views.add( this.createAttachmentView( attachment ), {
+ at: this.collection.indexOf( attachment )
+ });
+ }, this );
+
+ this.collection.on( 'remove', function( attachment, attachments, options ) {
+ var view = this._viewsByCid[ attachment.cid ];
+ delete this._viewsByCid[ attachment.cid ];
+
+ if ( view )
+ view.remove();
+ }, this );
+
+ this.collection.on( 'reset', this.render, this );
+
+ // Throttle the scroll handler.
+ this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
+
+ this.initSortable();
+
+ _.bindAll( this, 'css' );
+ this.model.on( 'change:edge change:gutter', this.css, this );
+ this._resizeCss = _.debounce( _.bind( this.css, this ), this.refreshSensitivity );
+ if ( this.options.resize )
+ $(window).on( 'resize.attachments', this._resizeCss );
+ this.css();
+ },
+
+ dispose: function() {
+ this.collection.props.off( null, null, this );
+ $(window).off( 'resize.attachments', this._resizeCss );
+ media.View.prototype.dispose.apply( this, arguments );
+ },
+
+ css: function() {
+ var $css = $( '#' + this.el.id + '-css' );
+
+ if ( $css.length )
+ $css.remove();
+
+ media.view.Attachments.$head().append( this.cssTemplate({
+ id: this.el.id,
+ edge: this.edge(),
+ gutter: this.model.get('gutter')
+ }) );
+ },
+
+ edge: function() {
+ var edge = this.model.get('edge'),
+ gutter, width, columns;
+
+ if ( ! this.$el.is(':visible') )
+ return edge;
+
+ gutter = this.model.get('gutter') * 2;
+ width = this.$el.width() - gutter;
+ columns = Math.ceil( width / ( edge + gutter ) );
+ edge = Math.floor( ( width - ( columns * gutter ) ) / columns );
+ return edge;
+ },
+
+ initSortable: function() {
+ var collection = this.collection;
+
+ if ( ! this.options.sortable || ! $.fn.sortable )
+ return;
+
+ this.$el.sortable( _.extend({
+ // If the `collection` has a `comparator`, disable sorting.
+ disabled: !! collection.comparator,
+
+ // Prevent attachments from being dragged outside the bounding
+ // box of the list.
+ containment: this.$el,
+
+ // Change the position of the attachment as soon as the
+ // mouse pointer overlaps a thumbnail.
+ tolerance: 'pointer',
+
+ // Record the initial `index` of the dragged model.
+ start: function( event, ui ) {
+ ui.item.data('sortableIndexStart', ui.item.index());
+ },
+
+ // Update the model's index in the collection.
+ // Do so silently, as the view is already accurate.
+ update: function( event, ui ) {
+ var model = collection.at( ui.item.data('sortableIndexStart') ),
+ comparator = collection.comparator;
+
+ // Temporarily disable the comparator to prevent `add`
+ // from re-sorting.
+ delete collection.comparator;
+
+ // Silently shift the model to its new index.
+ collection.remove( model, {
+ silent: true
+ }).add( model, {
+ silent: true,
+ at: ui.item.index()
+ });
+
+ // Restore the comparator.
+ collection.comparator = comparator;
+
+ // Fire the `reset` event to ensure other collections sync.
+ collection.trigger( 'reset', collection );
+
+ // If the collection is sorted by menu order,
+ // update the menu order.
+ collection.saveMenuOrder();
+ }
+ }, this.options.sortable ) );
+
+ // If the `orderby` property is changed on the `collection`,
+ // check to see if we have a `comparator`. If so, disable sorting.
+ collection.props.on( 'change:orderby', function() {
+ this.$el.sortable( 'option', 'disabled', !! collection.comparator );
+ }, this );
+
+ this.collection.props.on( 'change:orderby', this.refreshSortable, this );
+ this.refreshSortable();
+ },
+
+ refreshSortable: function() {
+ if ( ! this.options.sortable || ! $.fn.sortable )
+ return;
+
+ // If the `collection` has a `comparator`, disable sorting.
+ var collection = this.collection,
+ orderby = collection.props.get('orderby'),
+ enabled = 'menuOrder' === orderby || ! collection.comparator;
+
+ this.$el.sortable( 'option', 'disabled', ! enabled );
+ },
+
+ createAttachmentView: function( attachment ) {
+ var view = new this.options.AttachmentView({
+ controller: this.controller,
+ model: attachment,
+ collection: this.collection,
+ selection: this.options.selection
+ });
+
+ return this._viewsByCid[ attachment.cid ] = view;
+ },
+
+ prepare: function() {
+ // Create all of the Attachment views, and replace
+ // the list in a single DOM operation.
+ if ( this.collection.length ) {
+ this.views.set( this.collection.map( this.createAttachmentView, this ) );
+
+ // If there are no elements, clear the views and load some.
+ } else {
+ this.views.unset();
+ this.collection.more().done( this.scroll );
+ }
+ },
+
+ ready: function() {
+ // Trigger the scroll event to check if we're within the
+ // threshold to query for additional attachments.
+ this.scroll();
+ },
+
+ scroll: function( event ) {
+ // @todo: is this still necessary?
+ if ( ! this.$el.is(':visible') )
+ return;
+
+ if ( this.collection.hasMore() && this.el.scrollHeight < this.el.scrollTop + ( this.el.clientHeight * this.options.refreshThreshold ) ) {
+ this.collection.more().done( this.scroll );
+ }
+ }
+ }, {
+ $head: (function() {
+ var $head;
+ return function() {
+ return $head = $head || $('head');
+ };
+ }())
+ });
+
+ /**
+ * wp.media.view.Search
+ */
+ media.view.Search = media.View.extend({
+ tagName: 'input',
+ className: 'search',
+
+ attributes: {
+ type: 'search',
+ placeholder: l10n.search
+ },
+
+ events: {
+ 'input': 'search',
+ 'keyup': 'search',
+ 'change': 'search',
+ 'search': 'search'
+ },
+
+ render: function() {
+ this.el.value = this.model.escape('search');
+ return this;
+ },
+
+ search: function( event ) {
+ if ( event.target.value )
+ this.model.set( 'search', event.target.value );
+ else
+ this.model.unset('search');
+ }
+ });
+
+ /**
+ * wp.media.view.AttachmentFilters
+ */
+ media.view.AttachmentFilters = media.View.extend({
+ tagName: 'select',
+ className: 'attachment-filters',
+
+ events: {
+ change: 'change'
+ },
+
+ keys: [],
+
+ initialize: function() {
+ this.createFilters();
+ _.extend( this.filters, this.options.filters );
+
+ // Build `<option>` elements.
+ this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
+ return {
+ el: $('<option></option>').val(value).text(filter.text)[0],
+ priority: filter.priority || 50
+ };
+ }, this ).sortBy('priority').pluck('el').value() );
+
+ this.model.on( 'change', this.select, this );
+ this.select();
+ },
+
+ createFilters: function() {
+ this.filters = {};
+ },
+
+ change: function( event ) {
+ var filter = this.filters[ this.el.value ];
+
+ if ( filter )
+ this.model.set( filter.props );
+ },
+
+ select: function() {
+ var model = this.model,
+ value = 'all',
+ props = model.toJSON();
+
+ _.find( this.filters, function( filter, id ) {
+ var equal = _.all( filter.props, function( prop, key ) {
+ return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
+ });
+
+ if ( equal )
+ return value = id;
+ });
+
+ this.$el.val( value );
+ }
+ });
+
+ media.view.AttachmentFilters.Uploaded = media.view.AttachmentFilters.extend({
+ createFilters: function() {
+ var type = this.model.get('type'),
+ types = media.view.settings.mimeTypes,
+ text;
+
+ if ( types && type )
+ text = types[ type ];
+
+ this.filters = {
+ all: {
+ text: text || l10n.allMediaItems,
+ props: {
+ uploadedTo: null,
+ orderby: 'date',
+ order: 'DESC'
+ },
+ priority: 10
+ },
+
+ uploaded: {
+ text: l10n.uploadedToThisPost,
+ props: {
+ uploadedTo: media.view.settings.post.id,
+ orderby: 'menuOrder',
+ order: 'ASC'
+ },
+ priority: 20
+ }
+ };
+ }
+ });
+
+ media.view.AttachmentFilters.All = media.view.AttachmentFilters.extend({
+ createFilters: function() {
+ var filters = {};
+
+ _.each( media.view.settings.mimeTypes || {}, function( text, key ) {
+ filters[ key ] = {
+ text: text,
+ props: {
+ type: key,
+ uploadedTo: null,
+ orderby: 'date',
+ order: 'DESC'
+ }
+ };
+ });
+
+ filters.all = {
+ text: l10n.allMediaItems,
+ props: {
+ type: null,
+ uploadedTo: null,
+ orderby: 'date',
+ order: 'DESC'
+ },
+ priority: 10
+ };
+
+ filters.uploaded = {
+ text: l10n.uploadedToThisPost,
+ props: {
+ type: null,
+ uploadedTo: media.view.settings.post.id,
+ orderby: 'menuOrder',
+ order: 'ASC'
+ },
+ priority: 20
+ };
+
+ this.filters = filters;
+ }
+ });
+
+
+
+ /**
+ * wp.media.view.AttachmentsBrowser
+ */
+ media.view.AttachmentsBrowser = media.View.extend({
+ tagName: 'div',
+ className: 'attachments-browser',
+
+ initialize: function() {
+ _.defaults( this.options, {
+ filters: false,
+ search: true,
+ display: false,
+
+ AttachmentView: media.view.Attachment.Library
+ });
+
+ this.createToolbar();
+ this.updateContent();
+ this.createSidebar();
+
+ this.collection.on( 'add remove reset', this.updateContent, this );
+ },
+
+ dispose: function() {
+ this.options.selection.off( null, null, this );
+ media.View.prototype.dispose.apply( this, arguments );
+ return this;
+ },
+
+ createToolbar: function() {
+ var filters, FiltersConstructor;
+
+ this.toolbar = new media.view.Toolbar({
+ controller: this.controller
+ });
+
+ this.views.add( this.toolbar );
+
+ filters = this.options.filters;
+ if ( 'uploaded' === filters )
+ FiltersConstructor = media.view.AttachmentFilters.Uploaded;
+ else if ( 'all' === filters )
+ FiltersConstructor = media.view.AttachmentFilters.All;
+
+ if ( FiltersConstructor ) {
+ this.toolbar.set( 'filters', new FiltersConstructor({
+ controller: this.controller,
+ model: this.collection.props,
+ priority: -80
+ }).render() );
+ }
+
+ if ( this.options.search ) {
+ this.toolbar.set( 'search', new media.view.Search({
+ controller: this.controller,
+ model: this.collection.props,
+ priority: 60
+ }).render() );
+ }
+
+ if ( this.options.dragInfo ) {
+ this.toolbar.set( 'dragInfo', new media.View({
+ el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
+ priority: -40
+ }) );
+ }
+ },
+
+ updateContent: function() {
+ var view = this;
+
+ if( ! this.attachments )
+ this.createAttachments();
+
+ if ( ! this.collection.length ) {
+ this.collection.more().done( function() {
+ if ( ! view.collection.length )
+ view.createUploader();
+ });
+ }
+ },
+
+ removeContent: function() {
+ _.each(['attachments','uploader'], function( key ) {
+ if ( this[ key ] ) {
+ this[ key ].remove();
+ delete this[ key ];
+ }
+ }, this );
+ },
+
+ createUploader: function() {
+ this.removeContent();
+
+ this.uploader = new media.view.UploaderInline({
+ controller: this.controller,
+ status: false,
+ message: l10n.noItemsFound
+ });
+
+ this.views.add( this.uploader );
+ },
+
+ createAttachments: function() {
+ this.removeContent();
+
+ this.attachments = new media.view.Attachments({
+ controller: this.controller,
+ collection: this.collection,
+ selection: this.options.selection,
+ model: this.model,
+ sortable: this.options.sortable,
+
+ // The single `Attachment` view to be used in the `Attachments` view.
+ AttachmentView: this.options.AttachmentView
+ });
+
+ this.views.add( this.attachments );
+ },
+
+ createSidebar: function() {
+ var options = this.options,
+ selection = options.selection,
+ sidebar = this.sidebar = new media.view.Sidebar({
+ controller: this.controller
+ });
+
+ this.views.add( sidebar );
+
+ if ( this.controller.uploader ) {
+ sidebar.set( 'uploads', new media.view.UploaderStatus({
+ controller: this.controller,
+ priority: 40
+ }) );
+ }
+
+ selection.on( 'selection:single', this.createSingle, this );
+ selection.on( 'selection:unsingle', this.disposeSingle, this );
+
+ if ( selection.single() )
+ this.createSingle();
+ },
+
+ createSingle: function() {
+ var sidebar = this.sidebar,
+ single = this.options.selection.single(),
+ views = {};
+
+ sidebar.set( 'details', new media.view.Attachment.Details({
+ controller: this.controller,
+ model: single,
+ priority: 80
+ }) );
+
+ sidebar.set( 'compat', new media.view.AttachmentCompat({
+ controller: this.controller,
+ model: single,
+ priority: 120
+ }) );
+
+ if ( this.options.display ) {
+ sidebar.set( 'display', new media.view.Settings.AttachmentDisplay({
+ controller: this.controller,
+ model: this.model.display( single ),
+ attachment: single,
+ priority: 160,
+ userSettings: this.model.get('displayUserSettings')
+ }) );
+ }
+ },
+
+ disposeSingle: function() {
+ var sidebar = this.sidebar;
+ sidebar.unset('details');
+ sidebar.unset('compat');
+ sidebar.unset('display');
+ }
+ });
+
+ /**
+ * wp.media.view.Selection
+ */
+ media.view.Selection = media.View.extend({
+ tagName: 'div',
+ className: 'media-selection',
+ template: media.template('media-selection'),
+
+ events: {
+ 'click .edit-selection': 'edit',
+ 'click .clear-selection': 'clear'
+ },
+
+ initialize: function() {
+ _.defaults( this.options, {
+ editable: false,
+ clearable: true
+ });
+
+ this.attachments = new media.view.Attachments.Selection({
+ controller: this.controller,
+ collection: this.collection,
+ selection: this.collection,
+ model: new Backbone.Model({
+ edge: 40,
+ gutter: 5
+ })
+ });
+
+ this.views.set( '.selection-view', this.attachments );
+ this.collection.on( 'add remove reset', this.refresh, this );
+ this.controller.on( 'content:activate', this.refresh, this );
+ },
+
+ ready: function() {
+ this.refresh();
+ },
+
+ refresh: function() {
+ // If the selection hasn't been rendered, bail.
+ if ( ! this.$el.children().length )
+ return;
+
+ var collection = this.collection,
+ editing = 'edit-selection' === this.controller.content.mode();
+
+ // If nothing is selected, display nothing.
+ this.$el.toggleClass( 'empty', ! collection.length );
+ this.$el.toggleClass( 'one', 1 === collection.length );
+ this.$el.toggleClass( 'editing', editing );
+
+ this.$('.count').text( l10n.selected.replace('%d', collection.length) );
+ },
+
+ edit: function( event ) {
+ event.preventDefault();
+ if ( this.options.editable )
+ this.options.editable.call( this, this.collection );
+ },
+
+ clear: function( event ) {
+ event.preventDefault();
+ this.collection.reset();
+ }
+ });
+
+
+ /**
+ * wp.media.view.Attachment.Selection
+ */
+ media.view.Attachment.Selection = media.view.Attachment.extend({
+ className: 'attachment selection',
+
+ // On click, just select the model, instead of removing the model from
+ // the selection.
+ toggleSelection: function() {
+ this.options.selection.single( this.model );
+ }
+ });
+
+ /**
+ * wp.media.view.Attachments.Selection
+ */
+ media.view.Attachments.Selection = media.view.Attachments.extend({
+ events: {},
+ initialize: function() {
+ _.defaults( this.options, {
+ sortable: true,
+ resize: false,
+
+ // The single `Attachment` view to be used in the `Attachments` view.
+ AttachmentView: media.view.Attachment.Selection
+ });
+ return media.view.Attachments.prototype.initialize.apply( this, arguments );
+ }
+ });
+
+ /**
+ * wp.media.view.Attachments.EditSelection
+ */
+ media.view.Attachment.EditSelection = media.view.Attachment.Selection.extend({
+ buttons: {
+ close: true
+ }
+ });
+
+
+ /**
+ * wp.media.view.Settings
+ */
+ media.view.Settings = media.View.extend({
+ events: {
+ 'click button': 'updateHandler',
+ 'change input': 'updateHandler',
+ 'change select': 'updateHandler',
+ 'change textarea': 'updateHandler'
+ },
+
+ initialize: function() {
+ this.model = this.model || new Backbone.Model();
+ this.model.on( 'change', this.updateChanges, this );
+ },
+
+ prepare: function() {
+ return _.defaults({
+ model: this.model.toJSON()
+ }, this.options );
+ },
+
+ render: function() {
+ media.View.prototype.render.apply( this, arguments );
+ // Select the correct values.
+ _( this.model.attributes ).chain().keys().each( this.update, this );
+ return this;
+ },
+
+ update: function( key ) {
+ var value = this.model.get( key ),
+ $setting = this.$('[data-setting="' + key + '"]'),
+ $buttons, $value;
+
+ // Bail if we didn't find a matching setting.
+ if ( ! $setting.length )
+ return;
+
+ // Attempt to determine how the setting is rendered and update
+ // the selected value.
+
+ // Handle dropdowns.
+ if ( $setting.is('select') ) {
+ $value = $setting.find('[value="' + value + '"]');
+
+ if ( $value.length ) {
+ $setting.find('option').prop( 'selected', false );
+ $value.prop( 'selected', true );
+ } else {
+ // If we can't find the desired value, record what *is* selected.
+ this.model.set( key, $setting.find(':selected').val() );
+ }
+
+
+ // Handle button groups.
+ } else if ( $setting.hasClass('button-group') ) {
+ $buttons = $setting.find('button').removeClass('active');
+ $buttons.filter( '[value="' + value + '"]' ).addClass('active');
+
+ // Handle text inputs and textareas.
+ } else if ( $setting.is('input[type="text"], textarea') ) {
+ if ( ! $setting.is(':focus') )
+ $setting.val( value );
+
+ // Handle checkboxes.
+ } else if ( $setting.is('input[type="checkbox"]') ) {
+ $setting.attr( 'checked', !! value );
+ }
+ },
+
+ updateHandler: function( event ) {
+ var $setting = $( event.target ).closest('[data-setting]'),
+ value = event.target.value,
+ userSetting;
+
+ event.preventDefault();
+
+ if ( ! $setting.length )
+ return;
+
+ // Use the correct value for checkboxes.
+ if ( $setting.is('input[type="checkbox"]') )
+ value = $setting[0].checked;
+
+ // Update the corresponding setting.
+ this.model.set( $setting.data('setting'), value );
+
+ // If the setting has a corresponding user setting,
+ // update that as well.
+ if ( userSetting = $setting.data('userSetting') )
+ setUserSetting( userSetting, value );
+ },
+
+ updateChanges: function( model, options ) {
+ if ( model.hasChanged() )
+ _( model.changed ).chain().keys().each( this.update, this );
+ }
+ });
+
+ /**
+ * wp.media.view.Settings.AttachmentDisplay
+ */
+ media.view.Settings.AttachmentDisplay = media.view.Settings.extend({
+ className: 'attachment-display-settings',
+ template: media.template('attachment-display-settings'),
+
+ initialize: function() {
+ var attachment = this.options.attachment;
+
+ _.defaults( this.options, {
+ userSettings: false
+ });
+
+ media.view.Settings.prototype.initialize.apply( this, arguments );
+ this.model.on( 'change:link', this.updateLinkTo, this );
+
+ if ( attachment )
+ attachment.on( 'change:uploading', this.render, this );
+ },
+
+ dispose: function() {
+ var attachment = this.options.attachment;
+ if ( attachment )
+ attachment.off( null, null, this );
+
+ media.view.Settings.prototype.dispose.apply( this, arguments );
+ },
+
+ render: function() {
+ var attachment = this.options.attachment;
+ if ( attachment ) {
+ _.extend( this.options, {
+ sizes: attachment.get('sizes'),
+ type: attachment.get('type')
+ });
+ }
+
+ media.view.Settings.prototype.render.call( this );
+ this.updateLinkTo();
+ return this;
+ },
+
+ updateLinkTo: function() {
+ var linkTo = this.model.get('link'),
+ $input = this.$('.link-to-custom'),
+ attachment = this.options.attachment;
+
+ if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
+ $input.hide();
+ return;
+ }
+
+ if ( attachment ) {
+ if ( 'post' === linkTo ) {
+ $input.val( attachment.get('link') );
+ } else if ( 'file' === linkTo ) {
+ $input.val( attachment.get('url') );
+ } else if ( ! this.model.get('linkUrl') ) {
+ $input.val('http://');
+ }
+
+ $input.prop( 'readonly', 'custom' !== linkTo );
+ }
+
+ $input.show();
+
+ // If the input is visible, focus and select its contents.
+ if ( $input.is(':visible') )
+ $input.focus()[0].select();
+ }
+ });
+
+ /**
+ * wp.media.view.Settings.Gallery
+ */
+ media.view.Settings.Gallery = media.view.Settings.extend({
+ className: 'gallery-settings',
+ template: media.template('gallery-settings')
+ });
+
+ /**
+ * wp.media.view.Attachment.Details
+ */
+ media.view.Attachment.Details = media.view.Attachment.extend({
+ tagName: 'div',
+ className: 'attachment-details',
+ template: media.template('attachment-details'),
+
+ events: {
+ 'change [data-setting]': 'updateSetting',
+ 'change [data-setting] input': 'updateSetting',
+ 'change [data-setting] select': 'updateSetting',
+ 'change [data-setting] textarea': 'updateSetting',
+ 'click .delete-attachment': 'deleteAttachment',
+ 'click .edit-attachment': 'editAttachment',
+ 'click .refresh-attachment': 'refreshAttachment'
+ },
+
+ initialize: function() {
+ this.focusManager = new media.view.FocusManager({
+ el: this.el
+ });
+
+ media.view.Attachment.prototype.initialize.apply( this, arguments );
+ },
+
+ render: function() {
+ media.view.Attachment.prototype.render.apply( this, arguments );
+ this.focusManager.focus();
+ return this;
+ },
+
+ deleteAttachment: function( event ) {
+ event.preventDefault();
+
+ if ( confirm( l10n.warnDelete ) )
+ this.model.destroy();
+ },
+
+ editAttachment: function( event ) {
+ this.$el.addClass('needs-refresh');
+ },
+
+ refreshAttachment: function( event ) {
+ this.$el.removeClass('needs-refresh');
+ event.preventDefault();
+ this.model.fetch();
+ }
+ });
+
+ /**
+ * wp.media.view.AttachmentCompat
+ */
+ media.view.AttachmentCompat = media.View.extend({
+ tagName: 'form',
+ className: 'compat-item',
+
+ events: {
+ 'submit': 'preventDefault',
+ 'change input': 'save',
+ 'change select': 'save',
+ 'change textarea': 'save'
+ },
+
+ initialize: function() {
+ this.focusManager = new media.view.FocusManager({
+ el: this.el
+ });
+
+ this.model.on( 'change:compat', this.render, this );
+ },
+
+ dispose: function() {
+ if ( this.$(':focus').length )
+ this.save();
+
+ return media.View.prototype.dispose.apply( this, arguments );
+ },
+
+ render: function() {
+ var compat = this.model.get('compat');
+ if ( ! compat || ! compat.item )
+ return;
+
+ this.views.detach();
+ this.$el.html( compat.item );
+ this.views.render();
+
+ this.focusManager.focus();
+ return this;
+ },
+
+ preventDefault: function( event ) {
+ event.preventDefault();
+ },
+
+ save: function( event ) {
+ var data = {};
+
+ if ( event )
+ event.preventDefault();
+
+ _.each( this.$el.serializeArray(), function( pair ) {
+ data[ pair.name ] = pair.value;
+ });
+
+ this.model.saveCompat( data );
+ }
+ });
+
+ /**
+ * wp.media.view.Iframe
+ */
+ media.view.Iframe = media.View.extend({
+ className: 'media-iframe',
+
+ render: function() {
+ this.views.detach();
+ this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
+ this.views.render();
+ return this;
+ }
+ });
+
+ /**
+ * wp.media.view.Embed
+ */
+ media.view.Embed = media.View.extend({
+ className: 'media-embed',
+
+ initialize: function() {
+ this.url = new media.view.EmbedUrl({
+ controller: this.controller,
+ model: this.model.props
+ }).render();
+
+ this.views.set([ this.url ]);
+ this.refresh();
+ this.model.on( 'change:type', this.refresh, this );
+ this.model.on( 'change:loading', this.loading, this );
+ },
+
+ settings: function( view ) {
+ if ( this._settings )
+ this._settings.remove();
+ this._settings = view;
+ this.views.add( view );
+ },
+
+ refresh: function() {
+ var type = this.model.get('type'),
+ constructor;
+
+ if ( 'image' === type )
+ constructor = media.view.EmbedImage;
+ else if ( 'link' === type )
+ constructor = media.view.EmbedLink;
+ else
+ return;
+
+ this.settings( new constructor({
+ controller: this.controller,
+ model: this.model.props,
+ priority: 40
+ }) );
+ },
+
+ loading: function() {
+ this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
+ }
+ });
+
+ /**
+ * wp.media.view.EmbedUrl
+ */
+ media.view.EmbedUrl = media.View.extend({
+ tagName: 'label',
+ className: 'embed-url',
+
+ events: {
+ 'input': 'url',
+ 'keyup': 'url',
+ 'change': 'url'
+ },
+
+ initialize: function() {
+ this.$input = $('<input/>').attr( 'type', 'text' ).val( this.model.get('url') );
+ this.input = this.$input[0];
+
+ this.spinner = $('<span class="spinner" />')[0];
+ this.$el.append([ this.input, this.spinner ]);
+
+ this.model.on( 'change:url', this.render, this );
+ },
+
+ render: function() {
+ var $input = this.$input;
+
+ if ( $input.is(':focus') )
+ return;
+
+ this.input.value = this.model.get('url') || 'http://';
+ media.View.prototype.render.apply( this, arguments );
+ return this;
+ },
+
+ ready: function() {
+ this.focus();
+ },
+
+ url: function( event ) {
+ this.model.set( 'url', event.target.value );
+ },
+
+ focus: function() {
+ var $input = this.$input;
+ // If the input is visible, focus and select its contents.
+ if ( $input.is(':visible') )
+ $input.focus()[0].select();
+ }
+ });
+
+ /**
+ * wp.media.view.EmbedLink
+ */
+ media.view.EmbedLink = media.view.Settings.extend({
+ className: 'embed-link-settings',
+ template: media.template('embed-link-settings')
+ });
+
+ /**
+ * wp.media.view.EmbedImage
+ */
+ media.view.EmbedImage = media.view.Settings.AttachmentDisplay.extend({
+ className: 'embed-image-settings',
+ template: media.template('embed-image-settings'),
+
+ initialize: function() {
+ media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
+ this.model.on( 'change:url', this.updateImage, this );
+ },
+
+ updateImage: function() {
+ this.$('img').attr( 'src', this.model.get('url') );
+ }
+ });
+}(jQuery)); \ No newline at end of file
diff --git a/src/wp-includes/js/mediaelement/background.png b/src/wp-includes/js/mediaelement/background.png
new file mode 100644
index 0000000000..fd428412ae
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/background.png
Binary files differ
diff --git a/src/wp-includes/js/mediaelement/bigplay.png b/src/wp-includes/js/mediaelement/bigplay.png
new file mode 100644
index 0000000000..694553e31c
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/bigplay.png
Binary files differ
diff --git a/src/wp-includes/js/mediaelement/bigplay.svg b/src/wp-includes/js/mediaelement/bigplay.svg
new file mode 100644
index 0000000000..c2f62bbc0d
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/bigplay.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?> <!-- Generator: Adobe Fireworks CS6, Export SVG Extension by Aaron Beall (http://fireworks.abeall.com) . Version: 0.6.1 --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg id="bigplay-gradient.fw-Page%201" viewBox="0 0 100 200" style="background-color:#ffffff00" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" x="0px" y="0px" width="100px" height="200px" > <defs> <radialGradient id="gradient1" cx="50%" cy="50%" r="50%"> <stop stop-color="#222222" stop-opacity="0" offset="70%"/> <stop stop-color="#222222" stop-opacity="0.0118" offset="70.202%"/> <stop stop-color="#333333" stop-opacity="1" offset="85%"/> <stop stop-color="#333333" stop-opacity="0" offset="100%"/> </radialGradient> <radialGradient id="gradient2" cx="50%" cy="50%" r="50%"> <stop stop-color="#bbbbbb" stop-opacity="0" offset="70%"/> <stop stop-color="#bbbbbb" stop-opacity="0.0118" offset="70.202%"/> <stop stop-color="#bbbbbb" stop-opacity="1" offset="85%"/> <stop stop-color="#bbbbbb" stop-opacity="0" offset="100%"/> </radialGradient> <filter id="filter1" x="-100%" y="-100%" width="300%" height="300%"> <!-- Glow --> <feColorMatrix result="out" in="SourceGraphic" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.251 0"/> <feMorphology result="out" in="out" operator="dilate" radius="3"/> <feGaussianBlur result="out" in="out" stdDeviation="1.5"/> <feBlend in="SourceGraphic" in2="out" mode="normal" result="Glow1"/> </filter> <filter id="filter2" x="-100%" y="-100%" width="300%" height="300%"> <!-- Glow --> <feColorMatrix result="out" in="SourceGraphic" type="matrix" values="0 0 0 0.8667 0 0 0 0 0.8667 0 0 0 0 0.8667 0 0 0 0 0.251 0"/> <feMorphology result="out" in="out" operator="dilate" radius="3"/> <feGaussianBlur result="out" in="out" stdDeviation="1.5"/> <feBlend in="SourceGraphic" in2="out" mode="normal" result="Glow2"/> </filter> </defs> <g id="Background"> </g> <g id="dark%20shadow"> <path d="M 22 50 C 22 34.5358 34.5358 22 50 22 C 65.4642 22 78 34.5358 78 50 C 78 65.4642 65.4642 78 50 78 C 34.5358 78 22 65.4642 22 50 ZM 5 50 C 5 74.8531 25.1469 95 50 95 C 74.8531 95 95 74.8531 95 50 C 95 25.1469 74.8531 5 50 5 C 25.1469 5 5 25.1469 5 50 Z" fill="url(#gradient1)"/> <path d="M 22 150 C 22 134.5358 34.5358 122 50 122 C 65.4642 122 78 134.5358 78 150 C 78 165.4642 65.4642 178 50 178 C 34.5358 178 22 165.4642 22 150 ZM 5 150 C 5 174.8531 25.1469 195 50 195 C 74.8531 195 95 174.8531 95 150 C 95 125.1469 74.8531 105 50 105 C 25.1469 105 5 125.1469 5 150 Z" fill="url(#gradient2)"/> </g> <g id="dark"> <path id="Polygon" filter="url(#filter1)" d="M 72.5 49.5 L 38.75 68.9856 L 38.75 30.0144 L 72.5 49.5 Z" fill="#ffffff"/> <path id="Ellipse" d="M 13 50.5 C 13 29.7891 29.7891 13 50.5 13 C 71.2109 13 88 29.7891 88 50.5 C 88 71.2109 71.2109 88 50.5 88 C 29.7891 88 13 71.2109 13 50.5 Z" stroke="#ffffff" stroke-width="5" fill="none"/> </g> <g id="light"> <path id="Polygon2" filter="url(#filter2)" d="M 72.5 149.5 L 38.75 168.9856 L 38.75 130.0144 L 72.5 149.5 Z" fill="#ffffff"/> <path id="Ellipse2" d="M 13 150.5 C 13 129.7891 29.7891 113 50.5 113 C 71.2109 113 88 129.7891 88 150.5 C 88 171.211 71.2109 188 50.5 188 C 29.7891 188 13 171.211 13 150.5 Z" stroke="#ffffff" stroke-width="5" fill="none"/> </g> </svg> \ No newline at end of file
diff --git a/src/wp-includes/js/mediaelement/controls.png b/src/wp-includes/js/mediaelement/controls.png
new file mode 100644
index 0000000000..f6a857d800
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/controls.png
Binary files differ
diff --git a/src/wp-includes/js/mediaelement/controls.svg b/src/wp-includes/js/mediaelement/controls.svg
new file mode 100644
index 0000000000..af3bd41606
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/controls.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?> <!-- Generator: Adobe Fireworks CS6, Export SVG Extension by Aaron Beall (http://fireworks.abeall.com) . Version: 0.6.1 --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg id="controls.fw-Page%201" viewBox="0 0 144 32" style="background-color:#ffffff00" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" x="0px" y="0px" width="144px" height="32px" > <defs> <radialGradient id="gradient1" cx="50%" cy="50%" r="50%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#f2f2f2" stop-opacity="0.2" offset="100%"/> </radialGradient> <linearGradient id="gradient2" x1="50%" y1="-7.8652%" x2="50%" y2="249.6629%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient3" x1="50%" y1="0%" x2="50%" y2="238.75%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient4" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient5" x1="50%" y1="-33.3333%" x2="50%" y2="152.0833%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient6" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient7" x1="50%" y1="-33.3333%" x2="50%" y2="152.0833%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient8" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient9" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient10" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient11" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient12" x1="50%" y1="0%" x2="50%" y2="238.75%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient13" x1="40%" y1="-140%" x2="40%" y2="98.75%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient14" x1="50%" y1="0%" x2="50%" y2="238.75%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient15" x1="60%" y1="-140%" x2="60%" y2="98.75%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient16" x1="50%" y1="0%" x2="50%" y2="298.4375%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient17" x1="50%" y1="0%" x2="50%" y2="238.75%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient18" x1="50%" y1="-200%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient19" x1="50%" y1="-200%" x2="50%" y2="110.9375%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient20" x1="55%" y1="0%" x2="55%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="100%"/> </linearGradient> <linearGradient id="gradient21" x1="50%" y1="0%" x2="50%" y2="100%"> <stop stop-color="#ffffff" stop-opacity="1" offset="0%"/> <stop stop-color="#c8c8c8" stop-opacity="1" offset="99.4444%"/> </linearGradient> </defs> <g id="BG"> </g> <g id="controls"> <path id="Line" d="M 98.5 7.5 L 109.5 7.5 " stroke="#ffffff" stroke-width="1" fill="none"/> <path id="Line2" d="M 98.5 3.5 L 109.5 3.5 " stroke="#ffffff" stroke-width="1" fill="none"/> <path id="Line3" d="M 98.5 11.5 L 109.5 11.5 " stroke="#ffffff" stroke-width="1" fill="none"/> <path id="Ellipse" d="M 108 11.5 C 108 10.6716 108.4477 10 109 10 C 109.5523 10 110 10.6716 110 11.5 C 110 12.3284 109.5523 13 109 13 C 108.4477 13 108 12.3284 108 11.5 Z" fill="#ffffff"/> <path id="Ellipse2" d="M 104 7.5 C 104 6.6716 104.4477 6 105 6 C 105.5523 6 106 6.6716 106 7.5 C 106 8.3284 105.5523 9 105 9 C 104.4477 9 104 8.3284 104 7.5 Z" fill="#ffffff"/> <path id="Ellipse3" d="M 108 3.5 C 108 2.6716 108.4477 2 109 2 C 109.5523 2 110 2.6716 110 3.5 C 110 4.3284 109.5523 5 109 5 C 108.4477 5 108 4.3284 108 3.5 Z" fill="#ffffff"/> </g> <g id="backlight"> <g id="off"> <rect x="83" y="21" width="10" height="6" stroke="#ffffff" stroke-width="1" fill="#333333"/> </g> <g id="on"> <path id="Ellipse4" d="M 81 8 C 81 5.2385 84.134 3 88 3 C 91.866 3 95 5.2385 95 8 C 95 10.7615 91.866 13 88 13 C 84.134 13 81 10.7615 81 8 Z" fill="url(#gradient1)"/> <rect x="83" y="5" width="10" height="6" stroke="#ffffff" stroke-width="1" fill="#333333"/> </g> </g> <g id="loop"> <g id="on2"> <path d="M 73.795 4.205 C 75.2155 4.8785 76.2 6.3234 76.2 8 C 76.2 10.3196 74.3196 12.2 72 12.2 C 69.6804 12.2 67.8 10.3196 67.8 8 C 67.8 6.3234 68.7845 4.8785 70.205 4.205 L 68.875 2.875 C 67.1501 3.9289 66 5.8306 66 8 C 66 11.3138 68.6862 14 72 14 C 75.3138 14 78 11.3138 78 8 C 78 5.8306 76.8499 3.9289 75.125 2.875 L 73.795 4.205 Z" fill="url(#gradient2)"/> <path d="M 71 2 L 66 2 L 71 7 L 71 2 Z" fill="url(#gradient3)"/> </g> <g id="off2"> <path d="M 73.795 20.205 C 75.2155 20.8785 76.2 22.3234 76.2 24 C 76.2 26.3196 74.3196 28.2 72 28.2 C 69.6804 28.2 67.8 26.3196 67.8 24 C 67.8 22.3234 68.7845 20.8785 70.205 20.205 L 68.875 18.875 C 67.1501 19.9289 66 21.8306 66 24 C 66 27.3138 68.6862 30 72 30 C 75.3138 30 78 27.3138 78 24 C 78 21.8306 76.8499 19.9289 75.125 18.875 L 73.795 20.205 Z" fill="#a8a8b7"/> <path d="M 71 18 L 66 18 L 71 23 L 71 18 Z" fill="#a8a8b7"/> </g> </g> <g id="cc"> <rect visibility="hidden" x="49" y="2" width="14" height="12" stroke="#b0b0b0" stroke-width="1" fill="none"/> <text visibility="hidden" x="49" y="17" width="14" fill="#ffffff" style="font-size: 10px; color: #ffffff; font-family: Arial; text-align: center; "><tspan><![CDATA[cc]]></tspan></text> <path d="M 55 7 C 50.2813 3.7813 50.063 12.9405 55 10 " stroke="#ffffff" stroke-width="1" fill="none"/> <path d="M 60 7 C 55.2813 3.7813 55.063 12.9405 60 10 " stroke="#ffffff" stroke-width="1" fill="none"/> <path d="M 50 3 L 62 3 L 62 13 L 50 13 L 50 3 ZM 49 2 L 49 14 L 63 14 L 63 2 L 49 2 Z" fill="url(#gradient4)"/> <rect x="49" y="2" width="14" height="12" fill="none"/> </g> <g id="volume"> <g id="no%20sound"> <rect x="17" y="5" width="5" height="6" fill="url(#gradient5)"/> <path d="M 21 5 L 25 2 L 25 14 L 21 11.0625 L 21 5 Z" fill="url(#gradient6)"/> </g> <g id="sound%20bars"> <rect x="17" y="21" width="5" height="6" fill="url(#gradient7)"/> <path d="M 21 21 L 25 18 L 25 30 L 21 27.0625 L 21 21 Z" fill="url(#gradient8)"/> <path d="M 27 18 C 27 18 30.0625 17.375 30 24 C 29.9375 30.625 27 30 27 30 " stroke="#ffffff" stroke-width="1" fill="none"/> <path d="M 26 21.0079 C 26 21.0079 28.041 20.6962 27.9994 24 C 27.9577 27.3038 26 26.9921 26 26.9921 " stroke="#ffffff" stroke-width="1" fill="none"/> </g> </g> <g id="play/pause"> <g id="play"> <path id="Polygon" d="M 14 8.5 L 3 14 L 3 3 L 14 8.5 Z" fill="url(#gradient9)"/> </g> <g id="pause"> <rect x="3" y="18" width="3" height="12" fill="url(#gradient10)"/> <rect x="10" y="18" width="3" height="12" fill="url(#gradient11)"/> </g> </g> <g id="fullscreen"> <g id="enter%201"> <path d="M 34 2 L 39 2 L 34 7 L 34 2 Z" fill="url(#gradient12)"/> <path d="M 34 14 L 39 14 L 34 9 L 34 14 Z" fill="url(#gradient13)"/> <path d="M 46 2 L 41 2 L 46 7 L 46 2 Z" fill="url(#gradient14)"/> <path d="M 46 14 L 41 14 L 46 9 L 46 14 Z" fill="url(#gradient15)"/> </g> <g id="exit"> <path d="M 42 22 L 46 22 L 42 18 L 42 22 Z" fill="url(#gradient16)"/> <path d="M 38 22 L 38 18 L 34 22 L 38 22 Z" fill="url(#gradient17)"/> <path d="M 38 26 L 34 26 L 38 30 L 38 26 Z" fill="url(#gradient18)"/> <path d="M 42 26 L 42 30 L 46 26 L 42 26 Z" fill="url(#gradient19)"/> </g> </g> <g id="stop"> <rect x="115" y="3" width="10" height="10" fill="url(#gradient20)"/> </g> <g id="chooser"> <path d="M 135.2346 6.1522 C 136.2551 5.7295 137.4251 6.2141 137.8478 7.2346 C 138.2704 8.2551 137.7859 9.425 136.7654 9.8478 C 135.7449 10.2705 134.5749 9.7859 134.1522 8.7654 C 133.7295 7.7449 134.2141 6.5749 135.2346 6.1522 ZM 133.2735 1.4176 L 136 4.0054 L 138.7265 1.4176 L 138.8246 5.1754 L 142.5824 5.2735 L 139.9946 8 L 142.5824 10.7265 L 138.8246 10.8246 L 138.7265 14.5824 L 136 11.9946 L 133.2735 14.5824 L 133.1754 10.8246 L 129.4176 10.7265 L 132.0054 8 L 129.4176 5.2735 L 133.1754 5.1754 L 133.2735 1.4176 Z" fill="url(#gradient21)"/> </g> </svg> \ No newline at end of file
diff --git a/src/wp-includes/js/mediaelement/flashmediaelement.swf b/src/wp-includes/js/mediaelement/flashmediaelement.swf
new file mode 100644
index 0000000000..c5d205a0ad
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/flashmediaelement.swf
Binary files differ
diff --git a/src/wp-includes/js/mediaelement/loading.gif b/src/wp-includes/js/mediaelement/loading.gif
new file mode 100644
index 0000000000..612222be5e
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/loading.gif
Binary files differ
diff --git a/src/wp-includes/js/mediaelement/mediaelement-and-player.min.js b/src/wp-includes/js/mediaelement/mediaelement-and-player.min.js
new file mode 100644
index 0000000000..f9d9a0b992
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/mediaelement-and-player.min.js
@@ -0,0 +1,173 @@
+/*!
+* MediaElement.js
+* HTML5 <video> and <audio> shim and player
+* http://mediaelementjs.com/
+*
+* Creates a JavaScript object that mimics HTML5 MediaElement API
+* for browsers that don't understand HTML5 or can't play the provided codec
+* Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
+*
+* Copyright 2010-2013, John Dyer (http://j.hn)
+* License: MIT
+*
+*/var mejs=mejs||{};mejs.version="2.13.0";mejs.meIndex=0;
+mejs.plugins={silverlight:[{version:[3,0],types:["video/mp4","video/m4v","video/mov","video/wmv","audio/wma","audio/m4a","audio/mp3","audio/wav","audio/mpeg"]}],flash:[{version:[9,0,124],types:["video/mp4","video/m4v","video/mov","video/flv","video/rtmp","video/x-flv","audio/flv","audio/x-flv","audio/mp3","audio/m4a","audio/mpeg","video/youtube","video/x-youtube"]}],youtube:[{version:null,types:["video/youtube","video/x-youtube","audio/youtube","audio/x-youtube"]}],vimeo:[{version:null,types:["video/vimeo",
+"video/x-vimeo"]}]};
+mejs.Utility={encodeUrl:function(a){return encodeURIComponent(a)},escapeHTML:function(a){return a.toString().split("&").join("&amp;").split("<").join("&lt;").split('"').join("&quot;")},absolutizeUrl:function(a){var b=document.createElement("div");b.innerHTML='<a href="'+this.escapeHTML(a)+'">x</a>';return b.firstChild.href},getScriptPath:function(a){for(var b=0,c,d="",e="",f,g,h=document.getElementsByTagName("script"),l=h.length,j=a.length;b<l;b++){f=h[b].src;c=f.lastIndexOf("/");if(c>-1){g=f.substring(c+
+1);f=f.substring(0,c+1)}else{g=f;f=""}for(c=0;c<j;c++){e=a[c];e=g.indexOf(e);if(e>-1){d=f;break}}if(d!=="")break}return d},secondsToTimeCode:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;var e=Math.floor(a/3600)%24,f=Math.floor(a/60)%60,g=Math.floor(a%60);a=Math.floor((a%1*d).toFixed(3));return(b||e>0?(e<10?"0"+e:e)+":":"")+(f<10?"0"+f:f)+":"+(g<10?"0"+g:g)+(c?":"+(a<10?"0"+a:a):"")},timeCodeToSeconds:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d==
+"undefined")d=25;a=a.split(":");b=parseInt(a[0],10);var e=parseInt(a[1],10),f=parseInt(a[2],10),g=0,h=0;if(c)g=parseInt(a[3])/d;return h=b*3600+e*60+f+g},convertSMPTEtoSeconds:function(a){if(typeof a!="string")return false;a=a.replace(",",".");var b=0,c=a.indexOf(".")!=-1?a.split(".")[1].length:0,d=1;a=a.split(":").reverse();for(var e=0;e<a.length;e++){d=1;if(e>0)d=Math.pow(60,e);b+=Number(a[e])*d}return Number(b.toFixed(c))},removeSwf:function(a){var b=document.getElementById(a);if(b&&/object|embed/i.test(b.nodeName))if(mejs.MediaFeatures.isIE){b.style.display=
+"none";(function(){b.readyState==4?mejs.Utility.removeObjectInIE(a):setTimeout(arguments.callee,10)})()}else b.parentNode.removeChild(b)},removeObjectInIE:function(a){if(a=document.getElementById(a)){for(var b in a)if(typeof a[b]=="function")a[b]=null;a.parentNode.removeChild(a)}}};
+mejs.PluginDetector={hasPluginVersion:function(a,b){var c=this.plugins[a];b[1]=b[1]||0;b[2]=b[2]||0;return c[0]>b[0]||c[0]==b[0]&&c[1]>b[1]||c[0]==b[0]&&c[1]==b[1]&&c[2]>=b[2]?true:false},nav:window.navigator,ua:window.navigator.userAgent.toLowerCase(),plugins:[],addPlugin:function(a,b,c,d,e){this.plugins[a]=this.detectPlugin(b,c,d,e)},detectPlugin:function(a,b,c,d){var e=[0,0,0],f;if(typeof this.nav.plugins!="undefined"&&typeof this.nav.plugins[a]=="object"){if((c=this.nav.plugins[a].description)&&
+!(typeof this.nav.mimeTypes!="undefined"&&this.nav.mimeTypes[b]&&!this.nav.mimeTypes[b].enabledPlugin)){e=c.replace(a,"").replace(/^\s+/,"").replace(/\sr/gi,".").split(".");for(a=0;a<e.length;a++)e[a]=parseInt(e[a].match(/\d+/),10)}}else if(typeof window.ActiveXObject!="undefined")try{if(f=new ActiveXObject(c))e=d(f)}catch(g){}return e}};
+mejs.PluginDetector.addPlugin("flash","Shockwave Flash","application/x-shockwave-flash","ShockwaveFlash.ShockwaveFlash",function(a){var b=[];if(a=a.GetVariable("$version")){a=a.split(" ")[1].split(",");b=[parseInt(a[0],10),parseInt(a[1],10),parseInt(a[2],10)]}return b});
+mejs.PluginDetector.addPlugin("silverlight","Silverlight Plug-In","application/x-silverlight-2","AgControl.AgControl",function(a){var b=[0,0,0,0],c=function(d,e,f,g){for(;d.isVersionSupported(e[0]+"."+e[1]+"."+e[2]+"."+e[3]);)e[f]+=g;e[f]-=g};c(a,b,0,1);c(a,b,1,1);c(a,b,2,1E4);c(a,b,2,1E3);c(a,b,2,100);c(a,b,2,10);c(a,b,2,1);c(a,b,3,1);return b});
+mejs.MediaFeatures={init:function(){var a=this,b=document,c=mejs.PluginDetector.nav,d=mejs.PluginDetector.ua.toLowerCase(),e,f=["source","track","audio","video"];a.isiPad=d.match(/ipad/i)!==null;a.isiPhone=d.match(/iphone/i)!==null;a.isiOS=a.isiPhone||a.isiPad;a.isAndroid=d.match(/android/i)!==null;a.isBustedAndroid=d.match(/android 2\.[12]/)!==null;a.isBustedNativeHTTPS=location.protocol==="https:"&&(d.match(/android [12]\./)!==null||d.match(/macintosh.* version.* safari/)!==null);a.isIE=c.appName.toLowerCase().indexOf("microsoft")!=
+-1;a.isChrome=d.match(/chrome/gi)!==null;a.isFirefox=d.match(/firefox/gi)!==null;a.isWebkit=d.match(/webkit/gi)!==null;a.isGecko=d.match(/gecko/gi)!==null&&!a.isWebkit;a.isOpera=d.match(/opera/gi)!==null;a.hasTouch="ontouchstart"in window&&window.ontouchstart!=null;a.svg=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect;for(c=0;c<f.length;c++)e=document.createElement(f[c]);a.supportsMediaTag=typeof e.canPlayType!=="undefined"||a.isBustedAndroid;
+try{e.canPlayType("video/mp4")}catch(g){a.supportsMediaTag=false}a.hasSemiNativeFullScreen=typeof e.webkitEnterFullscreen!=="undefined";a.hasWebkitNativeFullScreen=typeof e.webkitRequestFullScreen!=="undefined";a.hasMozNativeFullScreen=typeof e.mozRequestFullScreen!=="undefined";a.hasTrueNativeFullScreen=a.hasWebkitNativeFullScreen||a.hasMozNativeFullScreen;a.nativeFullScreenEnabled=a.hasTrueNativeFullScreen;if(a.hasMozNativeFullScreen)a.nativeFullScreenEnabled=e.mozFullScreenEnabled;if(this.isChrome)a.hasSemiNativeFullScreen=
+false;if(a.hasTrueNativeFullScreen){a.fullScreenEventName=a.hasWebkitNativeFullScreen?"webkitfullscreenchange":"mozfullscreenchange";a.isFullScreen=function(){if(e.mozRequestFullScreen)return b.mozFullScreen;else if(e.webkitRequestFullScreen)return b.webkitIsFullScreen};a.requestFullScreen=function(h){if(a.hasWebkitNativeFullScreen)h.webkitRequestFullScreen();else a.hasMozNativeFullScreen&&h.mozRequestFullScreen()};a.cancelFullScreen=function(){if(a.hasWebkitNativeFullScreen)document.webkitCancelFullScreen();
+else a.hasMozNativeFullScreen&&document.mozCancelFullScreen()}}if(a.hasSemiNativeFullScreen&&d.match(/mac os x 10_5/i)){a.hasNativeFullScreen=false;a.hasSemiNativeFullScreen=false}}};mejs.MediaFeatures.init();
+mejs.HtmlMediaElement={pluginType:"native",isFullScreen:false,setCurrentTime:function(a){this.currentTime=a},setMuted:function(a){this.muted=a},setVolume:function(a){this.volume=a},stop:function(){this.pause()},setSrc:function(a){for(var b=this.getElementsByTagName("source");b.length>0;)this.removeChild(b[0]);if(typeof a=="string")this.src=a;else{var c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type)){this.src=c.src;break}}}},setVideoSize:function(a,b){this.width=a;this.height=b}};
+mejs.PluginMediaElement=function(a,b,c){this.id=a;this.pluginType=b;this.src=c;this.events={};this.attributes={}};
+mejs.PluginMediaElement.prototype={pluginElement:null,pluginType:"",isFullScreen:false,playbackRate:-1,defaultPlaybackRate:-1,seekable:[],played:[],paused:true,ended:false,seeking:false,duration:0,error:null,tagName:"",muted:false,volume:1,currentTime:0,play:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.playVideo():this.pluginApi.playMedia();this.paused=false}},load:function(){if(this.pluginApi!=null){this.pluginType!="youtube"&&this.pluginApi.loadMedia();this.paused=
+false}},pause:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.pauseVideo():this.pluginApi.pauseMedia();this.paused=true}},stop:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.stopVideo():this.pluginApi.stopMedia();this.paused=true}},canPlayType:function(a){var b,c,d,e=mejs.plugins[this.pluginType];for(b=0;b<e.length;b++){d=e[b];if(mejs.PluginDetector.hasPluginVersion(this.pluginType,d.version))for(c=0;c<d.types.length;c++)if(a==d.types[c])return"probably"}return""},
+positionFullscreenButton:function(a,b,c){this.pluginApi!=null&&this.pluginApi.positionFullscreenButton&&this.pluginApi.positionFullscreenButton(Math.floor(a),Math.floor(b),c)},hideFullscreenButton:function(){this.pluginApi!=null&&this.pluginApi.hideFullscreenButton&&this.pluginApi.hideFullscreenButton()},setSrc:function(a){if(typeof a=="string"){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(a));this.src=mejs.Utility.absolutizeUrl(a)}else{var b,c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type)){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(c.src));
+this.src=mejs.Utility.absolutizeUrl(a);break}}}},setCurrentTime:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.seekTo(a):this.pluginApi.setCurrentTime(a);this.currentTime=a}},setVolume:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.setVolume(a*100):this.pluginApi.setVolume(a);this.volume=a}},setMuted:function(a){if(this.pluginApi!=null){if(this.pluginType=="youtube"){a?this.pluginApi.mute():this.pluginApi.unMute();this.muted=a;this.dispatchEvent("volumechange")}else this.pluginApi.setMuted(a);
+this.muted=a}},setVideoSize:function(a,b){if(this.pluginElement.style){this.pluginElement.style.width=a+"px";this.pluginElement.style.height=b+"px"}this.pluginApi!=null&&this.pluginApi.setVideoSize&&this.pluginApi.setVideoSize(a,b)},setFullscreen:function(a){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.pluginApi.setFullscreen(a)},enterFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.setFullscreen(true)},exitFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&
+this.setFullscreen(false)},addEventListener:function(a,b){this.events[a]=this.events[a]||[];this.events[a].push(b)},removeEventListener:function(a,b){if(!a){this.events={};return true}var c=this.events[a];if(!c)return true;if(!b){this.events[a]=[];return true}for(i=0;i<c.length;i++)if(c[i]===b){this.events[a].splice(i,1);return true}return false},dispatchEvent:function(a){var b,c,d=this.events[a];if(d){c=Array.prototype.slice.call(arguments,1);for(b=0;b<d.length;b++)d[b].apply(null,c)}},hasAttribute:function(a){return a in
+this.attributes},removeAttribute:function(a){delete this.attributes[a]},getAttribute:function(a){if(this.hasAttribute(a))return this.attributes[a];return""},setAttribute:function(a,b){this.attributes[a]=b},remove:function(){mejs.Utility.removeSwf(this.pluginElement.id);mejs.MediaPluginBridge.unregisterPluginElement(this.pluginElement.id)}};
+mejs.MediaPluginBridge={pluginMediaElements:{},htmlMediaElements:{},registerPluginElement:function(a,b,c){this.pluginMediaElements[a]=b;this.htmlMediaElements[a]=c},unregisterPluginElement:function(a){delete this.pluginMediaElements[a];delete this.htmlMediaElements[a]},initPlugin:function(a){var b=this.pluginMediaElements[a],c=this.htmlMediaElements[a];if(b){switch(b.pluginType){case "flash":b.pluginElement=b.pluginApi=document.getElementById(a);break;case "silverlight":b.pluginElement=document.getElementById(b.id);
+b.pluginApi=b.pluginElement.Content.MediaElementJS}b.pluginApi!=null&&b.success&&b.success(b,c)}},fireEvent:function(a,b,c){var d,e;if(a=this.pluginMediaElements[a]){b={type:b,target:a};for(d in c){a[d]=c[d];b[d]=c[d]}e=c.bufferedTime||0;b.target.buffered=b.buffered={start:function(){return 0},end:function(){return e},length:1};a.dispatchEvent(b.type,b)}}};
+mejs.MediaElementDefaults={mode:"auto",plugins:["flash","silverlight","youtube","vimeo"],enablePluginDebug:false,httpsBasicAuthSite:false,type:"",pluginPath:mejs.Utility.getScriptPath(["mediaelement.js","mediaelement.min.js","mediaelement-and-player.js","mediaelement-and-player.min.js"]),flashName:"flashmediaelement.swf",flashStreamer:"",enablePluginSmoothing:false,enablePseudoStreaming:false,pseudoStreamingStartQueryParam:"start",silverlightName:"silverlightmediaelement.xap",defaultVideoWidth:480,
+defaultVideoHeight:270,pluginWidth:-1,pluginHeight:-1,pluginVars:[],timerRate:250,startVolume:0.8,success:function(){},error:function(){}};mejs.MediaElement=function(a,b){return mejs.HtmlMediaElementShim.create(a,b)};
+mejs.HtmlMediaElementShim={create:function(a,b){var c=mejs.MediaElementDefaults,d=typeof a=="string"?document.getElementById(a):a,e=d.tagName.toLowerCase(),f=e==="audio"||e==="video",g=f?d.getAttribute("src"):d.getAttribute("href");e=d.getAttribute("poster");var h=d.getAttribute("autoplay"),l=d.getAttribute("preload"),j=d.getAttribute("controls"),k;for(k in b)c[k]=b[k];g=typeof g=="undefined"||g===null||g==""?null:g;e=typeof e=="undefined"||e===null?"":e;l=typeof l=="undefined"||l===null||l==="false"?
+"none":l;h=!(typeof h=="undefined"||h===null||h==="false");j=!(typeof j=="undefined"||j===null||j==="false");k=this.determinePlayback(d,c,mejs.MediaFeatures.supportsMediaTag,f,g);k.url=k.url!==null?mejs.Utility.absolutizeUrl(k.url):"";if(k.method=="native"){if(mejs.MediaFeatures.isBustedAndroid){d.src=k.url;d.addEventListener("click",function(){d.play()},false)}return this.updateNative(k,c,h,l)}else if(k.method!=="")return this.createPlugin(k,c,e,h,l,j);else{this.createErrorMessage(k,c,e);return this}},
+determinePlayback:function(a,b,c,d,e){var f=[],g,h,l,j={method:"",url:"",htmlMediaElement:a,isVideo:a.tagName.toLowerCase()!="audio"},k;if(typeof b.type!="undefined"&&b.type!=="")if(typeof b.type=="string")f.push({type:b.type,url:e});else for(g=0;g<b.type.length;g++)f.push({type:b.type[g],url:e});else if(e!==null){l=this.formatType(e,a.getAttribute("type"));f.push({type:l,url:e})}else for(g=0;g<a.childNodes.length;g++){h=a.childNodes[g];if(h.nodeType==1&&h.tagName.toLowerCase()=="source"){e=h.getAttribute("src");
+l=this.formatType(e,h.getAttribute("type"));h=h.getAttribute("media");if(!h||!window.matchMedia||window.matchMedia&&window.matchMedia(h).matches)f.push({type:l,url:e})}}if(!d&&f.length>0&&f[0].url!==null&&this.getTypeFromFile(f[0].url).indexOf("audio")>-1)j.isVideo=false;if(mejs.MediaFeatures.isBustedAndroid)a.canPlayType=function(m){return m.match(/video\/(mp4|m4v)/gi)!==null?"maybe":""};if(c&&(b.mode==="auto"||b.mode==="auto_plugin"||b.mode==="native")&&!(mejs.MediaFeatures.isBustedNativeHTTPS&&
+b.httpsBasicAuthSite===true)){if(!d){g=document.createElement(j.isVideo?"video":"audio");a.parentNode.insertBefore(g,a);a.style.display="none";j.htmlMediaElement=a=g}for(g=0;g<f.length;g++)if(a.canPlayType(f[g].type).replace(/no/,"")!==""||a.canPlayType(f[g].type.replace(/mp3/,"mpeg")).replace(/no/,"")!==""){j.method="native";j.url=f[g].url;break}if(j.method==="native"){if(j.url!==null)a.src=j.url;if(b.mode!=="auto_plugin")return j}}if(b.mode==="auto"||b.mode==="auto_plugin"||b.mode==="shim")for(g=
+0;g<f.length;g++){l=f[g].type;for(a=0;a<b.plugins.length;a++){e=b.plugins[a];h=mejs.plugins[e];for(c=0;c<h.length;c++){k=h[c];if(k.version==null||mejs.PluginDetector.hasPluginVersion(e,k.version))for(d=0;d<k.types.length;d++)if(l==k.types[d]){j.method=e;j.url=f[g].url;return j}}}}if(b.mode==="auto_plugin"&&j.method==="native")return j;if(j.method===""&&f.length>0)j.url=f[0].url;return j},formatType:function(a,b){return a&&!b?this.getTypeFromFile(a):b&&~b.indexOf(";")?b.substr(0,b.indexOf(";")):b},
+getTypeFromFile:function(a){a=a.split("?")[0];a=a.substring(a.lastIndexOf(".")+1).toLowerCase();return(/(mp4|m4v|ogg|ogv|webm|webmv|flv|wmv|mpeg|mov)/gi.test(a)?"video":"audio")+"/"+this.getTypeFromExtension(a)},getTypeFromExtension:function(a){switch(a){case "mp4":case "m4v":return"mp4";case "webm":case "webma":case "webmv":return"webm";case "ogg":case "oga":case "ogv":return"ogg";default:return a}},createErrorMessage:function(a,b,c){var d=a.htmlMediaElement,e=document.createElement("div");e.className=
+"me-cannotplay";try{e.style.width=d.width+"px";e.style.height=d.height+"px"}catch(f){}e.innerHTML=b.customError?b.customError:c!==""?'<a href="'+a.url+'"><img src="'+c+'" width="100%" height="100%" /></a>':'<a href="'+a.url+'"><span>'+mejs.i18n.t("Download File")+"</span></a>";d.parentNode.insertBefore(e,d);d.style.display="none";b.error(d)},createPlugin:function(a,b,c,d,e,f){c=a.htmlMediaElement;var g=1,h=1,l="me_"+a.method+"_"+mejs.meIndex++,j=new mejs.PluginMediaElement(l,a.method,a.url),k=document.createElement("div"),
+m;j.tagName=c.tagName;for(m=0;m<c.attributes.length;m++){var n=c.attributes[m];n.specified==true&&j.setAttribute(n.name,n.value)}for(m=c.parentNode;m!==null&&m.tagName.toLowerCase()!="body";){if(m.parentNode.tagName.toLowerCase()=="p"){m.parentNode.parentNode.insertBefore(m,m.parentNode);break}m=m.parentNode}if(a.isVideo){g=b.pluginWidth>0?b.pluginWidth:b.videoWidth>0?b.videoWidth:c.getAttribute("width")!==null?c.getAttribute("width"):b.defaultVideoWidth;h=b.pluginHeight>0?b.pluginHeight:b.videoHeight>
+0?b.videoHeight:c.getAttribute("height")!==null?c.getAttribute("height"):b.defaultVideoHeight;g=mejs.Utility.encodeUrl(g);h=mejs.Utility.encodeUrl(h)}else if(b.enablePluginDebug){g=320;h=240}j.success=b.success;mejs.MediaPluginBridge.registerPluginElement(l,j,c);k.className="me-plugin";k.id=l+"_container";a.isVideo?c.parentNode.insertBefore(k,c):document.body.insertBefore(k,document.body.childNodes[0]);d=["id="+l,"isvideo="+(a.isVideo?"true":"false"),"autoplay="+(d?"true":"false"),"preload="+e,"width="+
+g,"startvolume="+b.startVolume,"timerrate="+b.timerRate,"flashstreamer="+b.flashStreamer,"height="+h,"pseudostreamstart="+b.pseudoStreamingStartQueryParam];if(a.url!==null)a.method=="flash"?d.push("file="+mejs.Utility.encodeUrl(a.url)):d.push("file="+a.url);b.enablePluginDebug&&d.push("debug=true");b.enablePluginSmoothing&&d.push("smoothing=true");b.enablePseudoStreaming&&d.push("pseudostreaming=true");f&&d.push("controls=true");if(b.pluginVars)d=d.concat(b.pluginVars);switch(a.method){case "silverlight":k.innerHTML=
+'<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="'+l+'" name="'+l+'" width="'+g+'" height="'+h+'" class="mejs-shim"><param name="initParams" value="'+d.join(",")+'" /><param name="windowless" value="true" /><param name="background" value="black" /><param name="minRuntimeVersion" value="3.0.0.0" /><param name="autoUpgrade" value="true" /><param name="source" value="'+b.pluginPath+b.silverlightName+'" /></object>';break;case "flash":if(mejs.MediaFeatures.isIE){a=
+document.createElement("div");k.appendChild(a);a.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+l+'" width="'+g+'" height="'+h+'" class="mejs-shim"><param name="movie" value="'+b.pluginPath+b.flashName+"?x="+new Date+'" /><param name="flashvars" value="'+d.join("&amp;")+'" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else k.innerHTML=
+'<embed id="'+l+'" name="'+l+'" play="true" loop="false" quality="high" bgcolor="#000000" wmode="transparent" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" src="'+b.pluginPath+b.flashName+'" flashvars="'+d.join("&")+'" width="'+g+'" height="'+h+'" class="mejs-shim"></embed>';break;case "youtube":b=a.url.substr(a.url.lastIndexOf("=")+1);youtubeSettings={container:k,containerId:k.id,pluginMediaElement:j,pluginId:l,
+videoId:b,height:h,width:g};mejs.PluginDetector.hasPluginVersion("flash",[10,0,0])?mejs.YouTubeApi.createFlash(youtubeSettings):mejs.YouTubeApi.enqueueIframe(youtubeSettings);break;case "vimeo":j.vimeoid=a.url.substr(a.url.lastIndexOf("/")+1);k.innerHTML='<iframe src="http://player.vimeo.com/video/'+j.vimeoid+'?portrait=0&byline=0&title=0" width="'+g+'" height="'+h+'" frameborder="0" class="mejs-shim"></iframe>'}c.style.display="none";c.removeAttribute("autoplay");return j},updateNative:function(a,
+b){var c=a.htmlMediaElement,d;for(d in mejs.HtmlMediaElement)c[d]=mejs.HtmlMediaElement[d];b.success(c,c);return c}};
+mejs.YouTubeApi={isIframeStarted:false,isIframeLoaded:false,loadIframeApi:function(){if(!this.isIframeStarted){var a=document.createElement("script");a.src="//www.youtube.com/player_api";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);this.isIframeStarted=true}},iframeQueue:[],enqueueIframe:function(a){if(this.isLoaded)this.createIframe(a);else{this.loadIframeApi();this.iframeQueue.push(a)}},createIframe:function(a){var b=a.pluginMediaElement,c=new YT.Player(a.containerId,
+{height:a.height,width:a.width,videoId:a.videoId,playerVars:{controls:0},events:{onReady:function(){a.pluginMediaElement.pluginApi=c;mejs.MediaPluginBridge.initPlugin(a.pluginId);setInterval(function(){mejs.YouTubeApi.createEvent(c,b,"timeupdate")},250)},onStateChange:function(d){mejs.YouTubeApi.handleStateChange(d.data,c,b)}}})},createEvent:function(a,b,c){c={type:c,target:b};if(a&&a.getDuration){b.currentTime=c.currentTime=a.getCurrentTime();b.duration=c.duration=a.getDuration();c.paused=b.paused;
+c.ended=b.ended;c.muted=a.isMuted();c.volume=a.getVolume()/100;c.bytesTotal=a.getVideoBytesTotal();c.bufferedBytes=a.getVideoBytesLoaded();var d=c.bufferedBytes/c.bytesTotal*c.duration;c.target.buffered=c.buffered={start:function(){return 0},end:function(){return d},length:1}}b.dispatchEvent(c.type,c)},iFrameReady:function(){for(this.isIframeLoaded=this.isLoaded=true;this.iframeQueue.length>0;)this.createIframe(this.iframeQueue.pop())},flashPlayers:{},createFlash:function(a){this.flashPlayers[a.pluginId]=
+a;var b,c="//www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid="+a.pluginId+"&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0";if(mejs.MediaFeatures.isIE){b=document.createElement("div");a.container.appendChild(b);b.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+a.pluginId+'" width="'+a.width+'" height="'+a.height+'" class="mejs-shim"><param name="movie" value="'+
+c+'" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else a.container.innerHTML='<object type="application/x-shockwave-flash" id="'+a.pluginId+'" data="'+c+'" width="'+a.width+'" height="'+a.height+'" style="visibility: visible; " class="mejs-shim"><param name="allowScriptAccess" value="always"><param name="wmode" value="transparent"></object>'},flashReady:function(a){var b=this.flashPlayers[a],c=
+document.getElementById(a),d=b.pluginMediaElement;d.pluginApi=d.pluginElement=c;mejs.MediaPluginBridge.initPlugin(a);c.cueVideoById(b.videoId);a=b.containerId+"_callback";window[a]=function(e){mejs.YouTubeApi.handleStateChange(e,c,d)};c.addEventListener("onStateChange",a);setInterval(function(){mejs.YouTubeApi.createEvent(c,d,"timeupdate")},250)},handleStateChange:function(a,b,c){switch(a){case -1:c.paused=true;c.ended=true;mejs.YouTubeApi.createEvent(b,c,"loadedmetadata");break;case 0:c.paused=false;
+c.ended=true;mejs.YouTubeApi.createEvent(b,c,"ended");break;case 1:c.paused=false;c.ended=false;mejs.YouTubeApi.createEvent(b,c,"play");mejs.YouTubeApi.createEvent(b,c,"playing");break;case 2:c.paused=true;c.ended=false;mejs.YouTubeApi.createEvent(b,c,"pause");break;case 3:mejs.YouTubeApi.createEvent(b,c,"progress")}}};function onYouTubePlayerAPIReady(){mejs.YouTubeApi.iFrameReady()}function onYouTubePlayerReady(a){mejs.YouTubeApi.flashReady(a)}window.mejs=mejs;window.MediaElement=mejs.MediaElement;
+(function(a,b){var c={locale:{language:"",strings:{}},methods:{}};c.locale.getLanguage=function(){return c.locale.language||navigator.language};if(typeof mejsL10n!="undefined")c.locale.language=mejsL10n.language;c.locale.INIT_LANGUAGE=c.locale.getLanguage();c.methods.checkPlain=function(d){var e,f,g={"&":"&amp;",'"':"&quot;","<":"&lt;",">":"&gt;"};d=String(d);for(e in g)if(g.hasOwnProperty(e)){f=RegExp(e,"g");d=d.replace(f,g[e])}return d};c.methods.formatString=function(d,e){for(var f in e){switch(f.charAt(0)){case "@":e[f]=
+c.methods.checkPlain(e[f]);break;case "!":break;default:e[f]='<em class="placeholder">'+c.methods.checkPlain(e[f])+"</em>"}d=d.replace(f,e[f])}return d};c.methods.t=function(d,e,f){if(c.locale.strings&&c.locale.strings[f.context]&&c.locale.strings[f.context][d])d=c.locale.strings[f.context][d];if(e)d=c.methods.formatString(d,e);return d};c.t=function(d,e,f){if(typeof d==="string"&&d.length>0){var g=c.locale.getLanguage();f=f||{context:g};return c.methods.t(d,e,f)}else throw{name:"InvalidArgumentException",
+message:"First argument is either not a string or empty."};};b.i18n=c})(document,mejs);(function(a){if(typeof mejsL10n!="undefined")a[mejsL10n.language]=mejsL10n.strings})(mejs.i18n.locale.strings);(function(a){a.de={Fullscreen:"Vollbild","Go Fullscreen":"Vollbild an","Turn off Fullscreen":"Vollbild aus",Close:"Schlie\u00dfen"}})(mejs.i18n.locale.strings);
+(function(a){a.zh={Fullscreen:"\u5168\u87a2\u5e55","Go Fullscreen":"\u5168\u5c4f\u6a21\u5f0f","Turn off Fullscreen":"\u9000\u51fa\u5168\u5c4f\u6a21\u5f0f",Close:"\u95dc\u9589"}})(mejs.i18n.locale.strings);
+
+/*!
+ * MediaElementPlayer
+ * http://mediaelementjs.com/
+ *
+ * Creates a controller bar for HTML5 <video> add <audio> tags
+ * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
+ *
+ * Copyright 2010-2013, John Dyer (http://j.hn/)
+ * License: MIT
+ *
+ */if(typeof jQuery!="undefined")mejs.$=jQuery;else if(typeof ender!="undefined")mejs.$=ender;
+(function(f){mejs.MepDefaults={poster:"",showPosterWhenEnded:false,defaultVideoWidth:480,defaultVideoHeight:270,videoWidth:-1,videoHeight:-1,defaultAudioWidth:400,defaultAudioHeight:30,defaultSeekBackwardInterval:function(a){return a.duration*0.05},defaultSeekForwardInterval:function(a){return a.duration*0.05},audioWidth:-1,audioHeight:-1,startVolume:0.8,loop:false,autoRewind:true,enableAutosize:true,alwaysShowHours:false,showTimecodeFrameCount:false,framesPerSecond:25,autosizeProgress:true,alwaysShowControls:false,
+hideVideoControlsOnLoad:false,clickToPlayPause:true,iPadUseNativeControls:false,iPhoneUseNativeControls:false,AndroidUseNativeControls:false,features:["playpause","current","progress","duration","tracks","volume","fullscreen"],isVideo:true,enableKeyboard:true,pauseOtherPlayers:true,keyActions:[{keys:[32,179],action:function(a,b){b.paused||b.ended?b.play():b.pause()}},{keys:[38],action:function(a,b){b.setVolume(Math.min(b.volume+0.1,1))}},{keys:[40],action:function(a,b){b.setVolume(Math.max(b.volume-
+0.1,0))}},{keys:[37,227],action:function(a,b){if(!isNaN(b.duration)&&b.duration>0){if(a.isVideo){a.showControls();a.startControlsTimer()}var c=Math.max(b.currentTime-a.options.defaultSeekBackwardInterval(b),0);b.setCurrentTime(c)}}},{keys:[39,228],action:function(a,b){if(!isNaN(b.duration)&&b.duration>0){if(a.isVideo){a.showControls();a.startControlsTimer()}var c=Math.min(b.currentTime+a.options.defaultSeekForwardInterval(b),b.duration);b.setCurrentTime(c)}}},{keys:[70],action:function(a){if(typeof a.enterFullScreen!=
+"undefined")a.isFullScreen?a.exitFullScreen():a.enterFullScreen()}}]};mejs.mepIndex=0;mejs.players={};mejs.MediaElementPlayer=function(a,b){if(!(this instanceof mejs.MediaElementPlayer))return new mejs.MediaElementPlayer(a,b);this.$media=this.$node=f(a);this.node=this.media=this.$media[0];if(typeof this.node.player!="undefined")return this.node.player;else this.node.player=this;if(typeof b=="undefined")b=this.$node.data("mejsoptions");this.options=f.extend({},mejs.MepDefaults,b);this.id="mep_"+mejs.mepIndex++;
+mejs.players[this.id]=this;this.init();return this};mejs.MediaElementPlayer.prototype={hasFocus:false,controlsAreVisible:true,init:function(){var a=this,b=mejs.MediaFeatures,c=f.extend(true,{},a.options,{success:function(d,g){a.meReady(d,g)},error:function(d){a.handleError(d)}}),e=a.media.tagName.toLowerCase();a.isDynamic=e!=="audio"&&e!=="video";a.isVideo=a.isDynamic?a.options.isVideo:e!=="audio"&&a.options.isVideo;if(b.isiPad&&a.options.iPadUseNativeControls||b.isiPhone&&a.options.iPhoneUseNativeControls){a.$media.attr("controls",
+"controls");if(b.isiPad&&a.media.getAttribute("autoplay")!==null){a.media.load();a.media.play()}}else if(!(b.isAndroid&&a.options.AndroidUseNativeControls)){a.$media.removeAttr("controls");a.container=f('<div id="'+a.id+'" class="mejs-container '+(mejs.MediaFeatures.svg?"svg":"no-svg")+'"><div class="mejs-inner"><div class="mejs-mediaelement"></div><div class="mejs-layers"></div><div class="mejs-controls"></div><div class="mejs-clear"></div></div></div>').addClass(a.$media[0].className).insertBefore(a.$media);
+a.container.addClass((b.isAndroid?"mejs-android ":"")+(b.isiOS?"mejs-ios ":"")+(b.isiPad?"mejs-ipad ":"")+(b.isiPhone?"mejs-iphone ":"")+(a.isVideo?"mejs-video ":"mejs-audio "));if(b.isiOS){b=a.$media.clone();a.container.find(".mejs-mediaelement").append(b);a.$media.remove();a.$node=a.$media=b;a.node=a.media=b[0]}else a.container.find(".mejs-mediaelement").append(a.$media);a.controls=a.container.find(".mejs-controls");a.layers=a.container.find(".mejs-layers");b=a.isVideo?"video":"audio";e=b.substring(0,
+1).toUpperCase()+b.substring(1);a.width=a.options[b+"Width"]>0||a.options[b+"Width"].toString().indexOf("%")>-1?a.options[b+"Width"]:a.media.style.width!==""&&a.media.style.width!==null?a.media.style.width:a.media.getAttribute("width")!==null?a.$media.attr("width"):a.options["default"+e+"Width"];a.height=a.options[b+"Height"]>0||a.options[b+"Height"].toString().indexOf("%")>-1?a.options[b+"Height"]:a.media.style.height!==""&&a.media.style.height!==null?a.media.style.height:a.$media[0].getAttribute("height")!==
+null?a.$media.attr("height"):a.options["default"+e+"Height"];a.setPlayerSize(a.width,a.height);c.pluginWidth=a.width;c.pluginHeight=a.height}mejs.MediaElement(a.$media[0],c);typeof a.container!="undefined"&&a.controlsAreVisible&&a.container.trigger("controlsshown")},showControls:function(a){var b=this;a=typeof a=="undefined"||a;if(!b.controlsAreVisible){if(a){b.controls.css("visibility","visible").stop(true,true).fadeIn(200,function(){b.controlsAreVisible=true;b.container.trigger("controlsshown")});
+b.container.find(".mejs-control").css("visibility","visible").stop(true,true).fadeIn(200,function(){b.controlsAreVisible=true})}else{b.controls.css("visibility","visible").css("display","block");b.container.find(".mejs-control").css("visibility","visible").css("display","block");b.controlsAreVisible=true;b.container.trigger("controlsshown")}b.setControlsSize()}},hideControls:function(a){var b=this;a=typeof a=="undefined"||a;if(!(!b.controlsAreVisible||b.options.alwaysShowControls))if(a){b.controls.stop(true,
+true).fadeOut(200,function(){f(this).css("visibility","hidden").css("display","block");b.controlsAreVisible=false;b.container.trigger("controlshidden")});b.container.find(".mejs-control").stop(true,true).fadeOut(200,function(){f(this).css("visibility","hidden").css("display","block")})}else{b.controls.css("visibility","hidden").css("display","block");b.container.find(".mejs-control").css("visibility","hidden").css("display","block");b.controlsAreVisible=false;b.container.trigger("controlshidden")}},
+controlsTimer:null,startControlsTimer:function(a){var b=this;a=typeof a!="undefined"?a:1500;b.killControlsTimer("start");b.controlsTimer=setTimeout(function(){b.hideControls();b.killControlsTimer("hide")},a)},killControlsTimer:function(){if(this.controlsTimer!==null){clearTimeout(this.controlsTimer);delete this.controlsTimer;this.controlsTimer=null}},controlsEnabled:true,disableControls:function(){this.killControlsTimer();this.hideControls(false);this.controlsEnabled=false},enableControls:function(){this.showControls(false);
+this.controlsEnabled=true},meReady:function(a,b){var c=this,e=mejs.MediaFeatures,d=b.getAttribute("autoplay");d=!(typeof d=="undefined"||d===null||d==="false");var g;if(!c.created){c.created=true;c.media=a;c.domNode=b;if(!(e.isAndroid&&c.options.AndroidUseNativeControls)&&!(e.isiPad&&c.options.iPadUseNativeControls)&&!(e.isiPhone&&c.options.iPhoneUseNativeControls)){c.buildposter(c,c.controls,c.layers,c.media);c.buildkeyboard(c,c.controls,c.layers,c.media);c.buildoverlays(c,c.controls,c.layers,c.media);
+c.findTracks();for(g in c.options.features){e=c.options.features[g];if(c["build"+e])try{c["build"+e](c,c.controls,c.layers,c.media)}catch(k){}}c.container.trigger("controlsready");c.setPlayerSize(c.width,c.height);c.setControlsSize();if(c.isVideo){if(mejs.MediaFeatures.hasTouch)c.$media.bind("touchstart",function(){if(c.controlsAreVisible)c.hideControls(false);else c.controlsEnabled&&c.showControls(false)});else{mejs.MediaElementPlayer.prototype.clickToPlayPauseCallback=function(){if(c.options.clickToPlayPause)c.media.paused?
+c.media.play():c.media.pause()};c.media.addEventListener("click",c.clickToPlayPauseCallback,false);c.container.bind("mouseenter mouseover",function(){if(c.controlsEnabled)if(!c.options.alwaysShowControls){c.killControlsTimer("enter");c.showControls();c.startControlsTimer(2500)}}).bind("mousemove",function(){if(c.controlsEnabled){c.controlsAreVisible||c.showControls();c.options.alwaysShowControls||c.startControlsTimer(2500)}}).bind("mouseleave",function(){c.controlsEnabled&&!c.media.paused&&!c.options.alwaysShowControls&&
+c.startControlsTimer(1E3)})}c.options.hideVideoControlsOnLoad&&c.hideControls(false);d&&!c.options.alwaysShowControls&&c.hideControls();c.options.enableAutosize&&c.media.addEventListener("loadedmetadata",function(j){if(c.options.videoHeight<=0&&c.domNode.getAttribute("height")===null&&!isNaN(j.target.videoHeight)){c.setPlayerSize(j.target.videoWidth,j.target.videoHeight);c.setControlsSize();c.media.setVideoSize(j.target.videoWidth,j.target.videoHeight)}},false)}a.addEventListener("play",function(){for(var j in mejs.players){var m=
+mejs.players[j];m.id!=c.id&&c.options.pauseOtherPlayers&&!m.paused&&!m.ended&&m.pause();m.hasFocus=false}c.hasFocus=true},false);c.media.addEventListener("ended",function(){if(c.options.autoRewind)try{c.media.setCurrentTime(0)}catch(j){}c.media.pause();c.setProgressRail&&c.setProgressRail();c.setCurrentRail&&c.setCurrentRail();if(c.options.loop)c.media.play();else!c.options.alwaysShowControls&&c.controlsEnabled&&c.showControls()},false);c.media.addEventListener("loadedmetadata",function(){c.updateDuration&&
+c.updateDuration();c.updateCurrent&&c.updateCurrent();if(!c.isFullScreen){c.setPlayerSize(c.width,c.height);c.setControlsSize()}},false);setTimeout(function(){c.setPlayerSize(c.width,c.height);c.setControlsSize()},50);c.globalBind("resize",function(){c.isFullScreen||mejs.MediaFeatures.hasTrueNativeFullScreen&&document.webkitIsFullScreen||c.setPlayerSize(c.width,c.height);c.setControlsSize()});c.media.pluginType=="youtube"&&c.container.find(".mejs-overlay-play").hide()}if(d&&a.pluginType=="native"){a.load();
+a.play()}if(c.options.success)typeof c.options.success=="string"?window[c.options.success](c.media,c.domNode,c):c.options.success(c.media,c.domNode,c)}},handleError:function(a){this.controls.hide();this.options.error&&this.options.error(a)},setPlayerSize:function(a,b){if(typeof a!="undefined")this.width=a;if(typeof b!="undefined")this.height=b;if(this.height.toString().indexOf("%")>0||this.$node.css("max-width")==="100%"||parseInt(this.$node.css("max-width").replace(/px/,""),10)/this.$node.offsetParent().width()===
+1||this.$node[0].currentStyle&&this.$node[0].currentStyle.maxWidth==="100%"){var c=this.isVideo?this.media.videoWidth&&this.media.videoWidth>0?this.media.videoWidth:this.options.defaultVideoWidth:this.options.defaultAudioWidth,e=this.isVideo?this.media.videoHeight&&this.media.videoHeight>0?this.media.videoHeight:this.options.defaultVideoHeight:this.options.defaultAudioHeight,d=this.container.parent().closest(":visible").width();c=this.isVideo||!this.options.autosizeProgress?parseInt(d*e/c,10):e;if(this.container.parent()[0].tagName.toLowerCase()===
+"body"){d=f(window).width();c=f(window).height()}if(c!=0&&d!=0){this.container.width(d).height(c);this.$media.add(this.container.find(".mejs-shim")).width("100%").height("100%");this.isVideo&&this.media.setVideoSize&&this.media.setVideoSize(d,c);this.layers.children(".mejs-layer").width("100%").height("100%")}}else{this.container.width(this.width).height(this.height);this.layers.children(".mejs-layer").width(this.width).height(this.height)}d=this.layers.find(".mejs-overlay-play");c=d.find(".mejs-overlay-button");
+d.height(this.container.height()-this.controls.height());c.css("margin-top","-"+(c.height()/2-this.controls.height()/2).toString()+"px")},setControlsSize:function(){var a=0,b=0,c=this.controls.find(".mejs-time-rail"),e=this.controls.find(".mejs-time-total");this.controls.find(".mejs-time-current");this.controls.find(".mejs-time-loaded");var d=c.siblings();if(this.options&&!this.options.autosizeProgress)b=parseInt(c.css("width"));if(b===0||!b){d.each(function(){var g=f(this);if(g.css("position")!=
+"absolute"&&g.is(":visible"))a+=f(this).outerWidth(true)});b=this.controls.width()-a-(c.outerWidth(true)-c.width())}c.width(b);e.width(b-(e.outerWidth(true)-e.width()));this.setProgressRail&&this.setProgressRail();this.setCurrentRail&&this.setCurrentRail()},buildposter:function(a,b,c,e){var d=f('<div class="mejs-poster mejs-layer"></div>').appendTo(c);b=a.$media.attr("poster");if(a.options.poster!=="")b=a.options.poster;b!==""&&b!=null?this.setPoster(b):d.hide();e.addEventListener("play",function(){d.hide()},
+false);a.options.showPosterWhenEnded&&a.options.autoRewind&&e.addEventListener("ended",function(){d.show()},false)},setPoster:function(a){var b=this.container.find(".mejs-poster"),c=b.find("img");if(c.length==0)c=f('<img width="100%" height="100%" />').appendTo(b);c.attr("src",a);b.css({"background-image":"url("+a+")"})},buildoverlays:function(a,b,c,e){var d=this;if(a.isVideo){var g=f('<div class="mejs-overlay mejs-layer"><div class="mejs-overlay-loading"><span></span></div></div>').hide().appendTo(c),
+k=f('<div class="mejs-overlay mejs-layer"><div class="mejs-overlay-error"></div></div>').hide().appendTo(c),j=f('<div class="mejs-overlay mejs-layer mejs-overlay-play"><div class="mejs-overlay-button"></div></div>').appendTo(c).click(function(){if(d.options.clickToPlayPause)e.paused?e.play():e.pause()});e.addEventListener("play",function(){j.hide();g.hide();b.find(".mejs-time-buffering").hide();k.hide()},false);e.addEventListener("playing",function(){j.hide();g.hide();b.find(".mejs-time-buffering").hide();
+k.hide()},false);e.addEventListener("seeking",function(){g.show();b.find(".mejs-time-buffering").show()},false);e.addEventListener("seeked",function(){g.hide();b.find(".mejs-time-buffering").hide()},false);e.addEventListener("pause",function(){mejs.MediaFeatures.isiPhone||j.show()},false);e.addEventListener("waiting",function(){g.show();b.find(".mejs-time-buffering").show()},false);e.addEventListener("loadeddata",function(){g.show();b.find(".mejs-time-buffering").show()},false);e.addEventListener("canplay",
+function(){g.hide();b.find(".mejs-time-buffering").hide()},false);e.addEventListener("error",function(){g.hide();b.find(".mejs-time-buffering").hide();k.show();k.find("mejs-overlay-error").html("Error loading this resource")},false)}},buildkeyboard:function(a,b,c,e){this.globalBind("keydown",function(d){if(a.hasFocus&&a.options.enableKeyboard)for(var g=0,k=a.options.keyActions.length;g<k;g++)for(var j=a.options.keyActions[g],m=0,q=j.keys.length;m<q;m++)if(d.keyCode==j.keys[m]){d.preventDefault();
+j.action(a,e,d.keyCode);return false}return true});this.globalBind("click",function(d){if(f(d.target).closest(".mejs-container").length==0)a.hasFocus=false})},findTracks:function(){var a=this,b=a.$media.find("track");a.tracks=[];b.each(function(c,e){e=f(e);a.tracks.push({srclang:e.attr("srclang")?e.attr("srclang").toLowerCase():"",src:e.attr("src"),kind:e.attr("kind"),label:e.attr("label")||"",entries:[],isLoaded:false})})},changeSkin:function(a){this.container[0].className="mejs-container "+a;this.setPlayerSize(this.width,
+this.height);this.setControlsSize()},play:function(){this.media.play()},pause:function(){try{this.media.pause()}catch(a){}},load:function(){this.media.load()},setMuted:function(a){this.media.setMuted(a)},setCurrentTime:function(a){this.media.setCurrentTime(a)},getCurrentTime:function(){return this.media.currentTime},setVolume:function(a){this.media.setVolume(a)},getVolume:function(){return this.media.volume},setSrc:function(a){this.media.setSrc(a)},remove:function(){var a,b;for(a in this.options.features){b=
+this.options.features[a];if(this["clean"+b])try{this["clean"+b](this)}catch(c){}}if(this.isDynamic)this.$node.insertBefore(this.container);else{this.$media.prop("controls",true);this.$node.clone().show().insertBefore(this.container);this.$node.remove()}this.media.pluginType!=="native"&&this.media.remove();delete mejs.players[this.id];this.container.remove();this.globalUnbind();delete this.node.player}};(function(){function a(c,e){var d={d:[],w:[]};f.each((c||"").split(" "),function(g,k){var j=k+"."+
+e;if(j.indexOf(".")===0){d.d.push(j);d.w.push(j)}else d[b.test(k)?"w":"d"].push(j)});d.d=d.d.join(" ");d.w=d.w.join(" ");return d}var b=/^((after|before)print|(before)?unload|hashchange|message|o(ff|n)line|page(hide|show)|popstate|resize|storage)\b/;mejs.MediaElementPlayer.prototype.globalBind=function(c,e,d){c=a(c,this.id);c.d&&f(document).bind(c.d,e,d);c.w&&f(window).bind(c.w,e,d)};mejs.MediaElementPlayer.prototype.globalUnbind=function(c,e){c=a(c,this.id);c.d&&f(document).unbind(c.d,e);c.w&&f(window).unbind(c.w,
+e)}})();if(typeof jQuery!="undefined")jQuery.fn.mediaelementplayer=function(a){a===false?this.each(function(){var b=jQuery(this).data("mediaelementplayer");b&&b.remove();jQuery(this).removeData("mediaelementplayer")}):this.each(function(){jQuery(this).data("mediaelementplayer",new mejs.MediaElementPlayer(this,a))});return this};f(document).ready(function(){f(".mejs-player").mediaelementplayer()});window.MediaElementPlayer=mejs.MediaElementPlayer})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{playpauseText:mejs.i18n.t("Play/Pause")});f.extend(MediaElementPlayer.prototype,{buildplaypause:function(a,b,c,e){var d=f('<div class="mejs-button mejs-playpause-button mejs-play" ><button type="button" aria-controls="'+this.id+'" title="'+this.options.playpauseText+'" aria-label="'+this.options.playpauseText+'"></button></div>').appendTo(b).click(function(g){g.preventDefault();e.paused?e.play():e.pause();return false});e.addEventListener("play",function(){d.removeClass("mejs-play").addClass("mejs-pause")},
+false);e.addEventListener("playing",function(){d.removeClass("mejs-play").addClass("mejs-pause")},false);e.addEventListener("pause",function(){d.removeClass("mejs-pause").addClass("mejs-play")},false);e.addEventListener("paused",function(){d.removeClass("mejs-pause").addClass("mejs-play")},false)}})})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{stopText:"Stop"});f.extend(MediaElementPlayer.prototype,{buildstop:function(a,b,c,e){f('<div class="mejs-button mejs-stop-button mejs-stop"><button type="button" aria-controls="'+this.id+'" title="'+this.options.stopText+'" aria-label="'+this.options.stopText+'"></button></div>').appendTo(b).click(function(){e.paused||e.pause();if(e.currentTime>0){e.setCurrentTime(0);e.pause();b.find(".mejs-time-current").width("0px");b.find(".mejs-time-handle").css("left",
+"0px");b.find(".mejs-time-float-current").html(mejs.Utility.secondsToTimeCode(0));b.find(".mejs-currenttime").html(mejs.Utility.secondsToTimeCode(0));c.find(".mejs-poster").show()}})}})})(mejs.$);
+(function(f){f.extend(MediaElementPlayer.prototype,{buildprogress:function(a,b,c,e){f('<div class="mejs-time-rail"><span class="mejs-time-total"><span class="mejs-time-buffering"></span><span class="mejs-time-loaded"></span><span class="mejs-time-current"></span><span class="mejs-time-handle"></span><span class="mejs-time-float"><span class="mejs-time-float-current">00:00</span><span class="mejs-time-float-corner"></span></span></span></div>').appendTo(b);b.find(".mejs-time-buffering").hide();var d=
+this,g=b.find(".mejs-time-total");c=b.find(".mejs-time-loaded");var k=b.find(".mejs-time-current"),j=b.find(".mejs-time-handle"),m=b.find(".mejs-time-float"),q=b.find(".mejs-time-float-current"),p=function(h){h=h.pageX;var l=g.offset(),r=g.outerWidth(true),n=0,o=n=0;if(e.duration){if(h<l.left)h=l.left;else if(h>r+l.left)h=r+l.left;o=h-l.left;n=o/r;n=n<=0.02?0:n*e.duration;t&&n!==e.currentTime&&e.setCurrentTime(n);if(!mejs.MediaFeatures.hasTouch){m.css("left",o);q.html(mejs.Utility.secondsToTimeCode(n));
+m.show()}}},t=false;g.bind("mousedown",function(h){if(h.which===1){t=true;p(h);d.globalBind("mousemove.dur",function(l){p(l)});d.globalBind("mouseup.dur",function(){t=false;m.hide();d.globalUnbind(".dur")});return false}}).bind("mouseenter",function(){d.globalBind("mousemove.dur",function(h){p(h)});mejs.MediaFeatures.hasTouch||m.show()}).bind("mouseleave",function(){if(!t){d.globalUnbind(".dur");m.hide()}});e.addEventListener("progress",function(h){a.setProgressRail(h);a.setCurrentRail(h)},false);
+e.addEventListener("timeupdate",function(h){a.setProgressRail(h);a.setCurrentRail(h)},false);d.loaded=c;d.total=g;d.current=k;d.handle=j},setProgressRail:function(a){var b=a!=undefined?a.target:this.media,c=null;if(b&&b.buffered&&b.buffered.length>0&&b.buffered.end&&b.duration)c=b.buffered.end(0)/b.duration;else if(b&&b.bytesTotal!=undefined&&b.bytesTotal>0&&b.bufferedBytes!=undefined)c=b.bufferedBytes/b.bytesTotal;else if(a&&a.lengthComputable&&a.total!=0)c=a.loaded/a.total;if(c!==null){c=Math.min(1,
+Math.max(0,c));this.loaded&&this.total&&this.loaded.width(this.total.width()*c)}},setCurrentRail:function(){if(this.media.currentTime!=undefined&&this.media.duration)if(this.total&&this.handle){var a=Math.round(this.total.width()*this.media.currentTime/this.media.duration),b=a-Math.round(this.handle.outerWidth(true)/2);this.current.width(a);this.handle.css("left",b)}}})})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{duration:-1,timeAndDurationSeparator:"<span> | </span>"});f.extend(MediaElementPlayer.prototype,{buildcurrent:function(a,b,c,e){f('<div class="mejs-time"><span class="mejs-currenttime">'+(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00")+"</span></div>").appendTo(b);this.currenttime=this.controls.find(".mejs-currenttime");e.addEventListener("timeupdate",function(){a.updateCurrent()},false)},buildduration:function(a,b,
+c,e){if(b.children().last().find(".mejs-currenttime").length>0)f(this.options.timeAndDurationSeparator+'<span class="mejs-duration">'+(this.options.duration>0?mejs.Utility.secondsToTimeCode(this.options.duration,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25):(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00"))+"</span>").appendTo(b.find(".mejs-time"));else{b.find(".mejs-currenttime").parent().addClass("mejs-currenttime-container");
+f('<div class="mejs-time mejs-duration-container"><span class="mejs-duration">'+(this.options.duration>0?mejs.Utility.secondsToTimeCode(this.options.duration,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25):(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00"))+"</span></div>").appendTo(b)}this.durationD=this.controls.find(".mejs-duration");e.addEventListener("timeupdate",function(){a.updateDuration()},
+false)},updateCurrent:function(){if(this.currenttime)this.currenttime.html(mejs.Utility.secondsToTimeCode(this.media.currentTime,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25))},updateDuration:function(){this.container.toggleClass("mejs-long-video",this.media.duration>3600);if(this.durationD&&(this.options.duration>0||this.media.duration))this.durationD.html(mejs.Utility.secondsToTimeCode(this.options.duration>0?this.options.duration:
+this.media.duration,this.options.alwaysShowHours,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25))}})})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{muteText:mejs.i18n.t("Mute Toggle"),hideVolumeOnTouchDevices:true,audioVolume:"horizontal",videoVolume:"vertical"});f.extend(MediaElementPlayer.prototype,{buildvolume:function(a,b,c,e){if(!(mejs.MediaFeatures.hasTouch&&this.options.hideVolumeOnTouchDevices)){var d=this,g=d.isVideo?d.options.videoVolume:d.options.audioVolume,k=g=="horizontal"?f('<div class="mejs-button mejs-volume-button mejs-mute"><button type="button" aria-controls="'+d.id+'" title="'+d.options.muteText+
+'" aria-label="'+d.options.muteText+'"></button></div><div class="mejs-horizontal-volume-slider"><div class="mejs-horizontal-volume-total"></div><div class="mejs-horizontal-volume-current"></div><div class="mejs-horizontal-volume-handle"></div></div>').appendTo(b):f('<div class="mejs-button mejs-volume-button mejs-mute"><button type="button" aria-controls="'+d.id+'" title="'+d.options.muteText+'" aria-label="'+d.options.muteText+'"></button><div class="mejs-volume-slider"><div class="mejs-volume-total"></div><div class="mejs-volume-current"></div><div class="mejs-volume-handle"></div></div></div>').appendTo(b),
+j=d.container.find(".mejs-volume-slider, .mejs-horizontal-volume-slider"),m=d.container.find(".mejs-volume-total, .mejs-horizontal-volume-total"),q=d.container.find(".mejs-volume-current, .mejs-horizontal-volume-current"),p=d.container.find(".mejs-volume-handle, .mejs-horizontal-volume-handle"),t=function(n,o){if(!j.is(":visible")&&typeof o=="undefined"){j.show();t(n,true);j.hide()}else{n=Math.max(0,n);n=Math.min(n,1);n==0?k.removeClass("mejs-mute").addClass("mejs-unmute"):k.removeClass("mejs-unmute").addClass("mejs-mute");
+if(g=="vertical"){var s=m.height(),u=m.position(),v=s-s*n;p.css("top",Math.round(u.top+v-p.height()/2));q.height(s-v);q.css("top",u.top+v)}else{s=m.width();u=m.position();s=s*n;p.css("left",Math.round(u.left+s-p.width()/2));q.width(Math.round(s))}}},h=function(n){var o=null,s=m.offset();if(g=="vertical"){o=m.height();parseInt(m.css("top").replace(/px/,""),10);o=(o-(n.pageY-s.top))/o;if(s.top==0||s.left==0)return}else{o=m.width();o=(n.pageX-s.left)/o}o=Math.max(0,o);o=Math.min(o,1);t(o);o==0?e.setMuted(true):
+e.setMuted(false);e.setVolume(o)},l=false,r=false;k.hover(function(){j.show();r=true},function(){r=false;!l&&g=="vertical"&&j.hide()});j.bind("mouseover",function(){r=true}).bind("mousedown",function(n){h(n);d.globalBind("mousemove.vol",function(o){h(o)});d.globalBind("mouseup.vol",function(){l=false;d.globalUnbind(".vol");!r&&g=="vertical"&&j.hide()});l=true;return false});k.find("button").click(function(){e.setMuted(!e.muted)});e.addEventListener("volumechange",function(){if(!l)if(e.muted){t(0);
+k.removeClass("mejs-mute").addClass("mejs-unmute")}else{t(e.volume);k.removeClass("mejs-unmute").addClass("mejs-mute")}},false);if(d.container.is(":visible")){t(a.options.startVolume);a.options.startVolume===0&&e.setMuted(true);e.pluginType==="native"&&e.setVolume(a.options.startVolume)}}}})})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{usePluginFullScreen:true,newWindowCallback:function(){return""},fullscreenText:mejs.i18n.t("Fullscreen")});f.extend(MediaElementPlayer.prototype,{isFullScreen:false,isNativeFullScreen:false,isInIframe:false,buildfullscreen:function(a,b,c,e){if(a.isVideo){a.isInIframe=window.location!=window.parent.location;if(mejs.MediaFeatures.hasTrueNativeFullScreen){c=function(){if(a.isFullScreen)if(mejs.MediaFeatures.isFullScreen()){a.isNativeFullScreen=true;a.setControlsSize()}else{a.isNativeFullScreen=
+false;a.exitFullScreen()}};mejs.MediaFeatures.hasMozNativeFullScreen?a.globalBind(mejs.MediaFeatures.fullScreenEventName,c):a.container.bind(mejs.MediaFeatures.fullScreenEventName,c)}var d=this,g=f('<div class="mejs-button mejs-fullscreen-button"><button type="button" aria-controls="'+d.id+'" title="'+d.options.fullscreenText+'" aria-label="'+d.options.fullscreenText+'"></button></div>').appendTo(b);if(d.media.pluginType==="native"||!d.options.usePluginFullScreen&&!mejs.MediaFeatures.isFirefox)g.click(function(){mejs.MediaFeatures.hasTrueNativeFullScreen&&
+mejs.MediaFeatures.isFullScreen()||a.isFullScreen?a.exitFullScreen():a.enterFullScreen()});else{var k=null;if(function(){var h=document.createElement("x"),l=document.documentElement,r=window.getComputedStyle;if(!("pointerEvents"in h.style))return false;h.style.pointerEvents="auto";h.style.pointerEvents="x";l.appendChild(h);r=r&&r(h,"").pointerEvents==="auto";l.removeChild(h);return!!r}()&&!mejs.MediaFeatures.isOpera){var j=false,m=function(){if(j){for(var h in q)q[h].hide();g.css("pointer-events",
+"");d.controls.css("pointer-events","");d.media.removeEventListener("click",d.clickToPlayPauseCallback);j=false}},q={};b=["top","left","right","bottom"];var p,t=function(){var h=g.offset().left-d.container.offset().left,l=g.offset().top-d.container.offset().top,r=g.outerWidth(true),n=g.outerHeight(true),o=d.container.width(),s=d.container.height();for(p in q)q[p].css({position:"absolute",top:0,left:0});q.top.width(o).height(l);q.left.width(h).height(n).css({top:l});q.right.width(o-h-r).height(n).css({top:l,
+left:h+r});q.bottom.width(o).height(s-n-l).css({top:l+n})};d.globalBind("resize",function(){t()});p=0;for(c=b.length;p<c;p++)q[b[p]]=f('<div class="mejs-fullscreen-hover" />').appendTo(d.container).mouseover(m).hide();g.on("mouseover",function(){if(!d.isFullScreen){var h=g.offset(),l=a.container.offset();e.positionFullscreenButton(h.left-l.left,h.top-l.top,false);g.css("pointer-events","none");d.controls.css("pointer-events","none");d.media.addEventListener("click",d.clickToPlayPauseCallback);for(p in q)q[p].show();
+t();j=true}});e.addEventListener("fullscreenchange",function(){d.isFullScreen=!d.isFullScreen;d.isFullScreen?d.media.removeEventListener("click",d.clickToPlayPauseCallback):d.media.addEventListener("click",d.clickToPlayPauseCallback);m()});d.globalBind("mousemove",function(h){if(j){var l=g.offset();if(h.pageY<l.top||h.pageY>l.top+g.outerHeight(true)||h.pageX<l.left||h.pageX>l.left+g.outerWidth(true)){g.css("pointer-events","");d.controls.css("pointer-events","");j=false}}})}else g.on("mouseover",
+function(){if(k!==null){clearTimeout(k);delete k}var h=g.offset(),l=a.container.offset();e.positionFullscreenButton(h.left-l.left,h.top-l.top,true)}).on("mouseout",function(){if(k!==null){clearTimeout(k);delete k}k=setTimeout(function(){e.hideFullscreenButton()},1500)})}a.fullscreenBtn=g;d.globalBind("keydown",function(h){if((mejs.MediaFeatures.hasTrueNativeFullScreen&&mejs.MediaFeatures.isFullScreen()||d.isFullScreen)&&h.keyCode==27)a.exitFullScreen()})}},cleanfullscreen:function(a){a.exitFullScreen()},
+containerSizeTimeout:null,enterFullScreen:function(){var a=this;if(!(a.media.pluginType!=="native"&&(mejs.MediaFeatures.isFirefox||a.options.usePluginFullScreen))){f(document.documentElement).addClass("mejs-fullscreen");normalHeight=a.container.height();normalWidth=a.container.width();if(a.media.pluginType==="native")if(mejs.MediaFeatures.hasTrueNativeFullScreen){mejs.MediaFeatures.requestFullScreen(a.container[0]);a.isInIframe&&setTimeout(function c(){if(a.isNativeFullScreen)f(window).width()!==
+screen.width?a.exitFullScreen():setTimeout(c,500)},500)}else if(mejs.MediaFeatures.hasSemiNativeFullScreen){a.media.webkitEnterFullscreen();return}if(a.isInIframe){var b=a.options.newWindowCallback(this);if(b!=="")if(mejs.MediaFeatures.hasTrueNativeFullScreen)setTimeout(function(){if(!a.isNativeFullScreen){a.pause();window.open(b,a.id,"top=0,left=0,width="+screen.availWidth+",height="+screen.availHeight+",resizable=yes,scrollbars=no,status=no,toolbar=no")}},250);else{a.pause();window.open(b,a.id,
+"top=0,left=0,width="+screen.availWidth+",height="+screen.availHeight+",resizable=yes,scrollbars=no,status=no,toolbar=no");return}}a.container.addClass("mejs-container-fullscreen").width("100%").height("100%");a.containerSizeTimeout=setTimeout(function(){a.container.css({width:"100%",height:"100%"});a.setControlsSize()},500);if(a.media.pluginType==="native")a.$media.width("100%").height("100%");else{a.container.find(".mejs-shim").width("100%").height("100%");a.media.setVideoSize(f(window).width(),
+f(window).height())}a.layers.children("div").width("100%").height("100%");a.fullscreenBtn&&a.fullscreenBtn.removeClass("mejs-fullscreen").addClass("mejs-unfullscreen");a.setControlsSize();a.isFullScreen=true}},exitFullScreen:function(){clearTimeout(this.containerSizeTimeout);if(this.media.pluginType!=="native"&&mejs.MediaFeatures.isFirefox)this.media.setFullscreen(false);else{if(mejs.MediaFeatures.hasTrueNativeFullScreen&&(mejs.MediaFeatures.isFullScreen()||this.isFullScreen))mejs.MediaFeatures.cancelFullScreen();
+f(document.documentElement).removeClass("mejs-fullscreen");this.container.removeClass("mejs-container-fullscreen").width(normalWidth).height(normalHeight);if(this.media.pluginType==="native")this.$media.width(normalWidth).height(normalHeight);else{this.container.find(".mejs-shim").width(normalWidth).height(normalHeight);this.media.setVideoSize(normalWidth,normalHeight)}this.layers.children("div").width(normalWidth).height(normalHeight);this.fullscreenBtn.removeClass("mejs-unfullscreen").addClass("mejs-fullscreen");
+this.setControlsSize();this.isFullScreen=false}}})})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{startLanguage:"",tracksText:mejs.i18n.t("Captions/Subtitles"),hideCaptionsButtonWhenEmpty:true,toggleCaptionsButtonWhenOnlyOne:false,slidesSelector:""});f.extend(MediaElementPlayer.prototype,{hasChapters:false,buildtracks:function(a,b,c,e){if(a.tracks.length!=0){var d;if(this.domNode.textTracks)for(d=this.domNode.textTracks.length-1;d>=0;d--)this.domNode.textTracks[d].mode="hidden";a.chapters=f('<div class="mejs-chapters mejs-layer"></div>').prependTo(c).hide();a.captions=
+f('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position mejs-captions-position-hover"><span class="mejs-captions-text"></span></div></div>').prependTo(c).hide();a.captionsText=a.captions.find(".mejs-captions-text");a.captionsButton=f('<div class="mejs-button mejs-captions-button"><button type="button" aria-controls="'+this.id+'" title="'+this.options.tracksText+'" aria-label="'+this.options.tracksText+'"></button><div class="mejs-captions-selector"><ul><li><input type="radio" name="'+
+a.id+'_captions" id="'+a.id+'_captions_none" value="none" checked="checked" /><label for="'+a.id+'_captions_none">'+mejs.i18n.t("None")+"</label></li></ul></div></div>").appendTo(b);for(d=b=0;d<a.tracks.length;d++)a.tracks[d].kind=="subtitles"&&b++;this.options.toggleCaptionsButtonWhenOnlyOne&&b==1?a.captionsButton.on("click",function(){a.setTrack(a.selectedTrack==null?a.tracks[0].srclang:"none")}):a.captionsButton.hover(function(){f(this).find(".mejs-captions-selector").css("visibility","visible")},
+function(){f(this).find(".mejs-captions-selector").css("visibility","hidden")}).on("click","input[type=radio]",function(){lang=this.value;a.setTrack(lang)});a.options.alwaysShowControls?a.container.find(".mejs-captions-position").addClass("mejs-captions-position-hover"):a.container.bind("controlsshown",function(){a.container.find(".mejs-captions-position").addClass("mejs-captions-position-hover")}).bind("controlshidden",function(){e.paused||a.container.find(".mejs-captions-position").removeClass("mejs-captions-position-hover")});
+a.trackToLoad=-1;a.selectedTrack=null;a.isLoadingTrack=false;for(d=0;d<a.tracks.length;d++)a.tracks[d].kind=="subtitles"&&a.addTrackButton(a.tracks[d].srclang,a.tracks[d].label);a.loadNextTrack();e.addEventListener("timeupdate",function(){a.displayCaptions()},false);if(a.options.slidesSelector!=""){a.slidesContainer=f(a.options.slidesSelector);e.addEventListener("timeupdate",function(){a.displaySlides()},false)}e.addEventListener("loadedmetadata",function(){a.displayChapters()},false);a.container.hover(function(){if(a.hasChapters){a.chapters.css("visibility",
+"visible");a.chapters.fadeIn(200).height(a.chapters.find(".mejs-chapter").outerHeight())}},function(){a.hasChapters&&!e.paused&&a.chapters.fadeOut(200,function(){f(this).css("visibility","hidden");f(this).css("display","block")})});a.node.getAttribute("autoplay")!==null&&a.chapters.css("visibility","hidden")}},setTrack:function(a){var b;if(a=="none"){this.selectedTrack=null;this.captionsButton.removeClass("mejs-captions-enabled")}else for(b=0;b<this.tracks.length;b++)if(this.tracks[b].srclang==a){this.selectedTrack==
+null&&this.captionsButton.addClass("mejs-captions-enabled");this.selectedTrack=this.tracks[b];this.captions.attr("lang",this.selectedTrack.srclang);this.displayCaptions();break}},loadNextTrack:function(){this.trackToLoad++;if(this.trackToLoad<this.tracks.length){this.isLoadingTrack=true;this.loadTrack(this.trackToLoad)}else{this.isLoadingTrack=false;this.checkForTracks()}},loadTrack:function(a){var b=this,c=b.tracks[a];f.ajax({url:c.src,dataType:"text",success:function(e){c.entries=typeof e=="string"&&
+/<tt\s+xml/ig.exec(e)?mejs.TrackFormatParser.dfxp.parse(e):mejs.TrackFormatParser.webvvt.parse(e);c.isLoaded=true;b.enableTrackButton(c.srclang,c.label);b.loadNextTrack();c.kind=="chapters"&&b.media.addEventListener("play",function(){b.media.duration>0&&b.displayChapters(c)},false);c.kind=="slides"&&b.setupSlides(c)},error:function(){b.loadNextTrack()}})},enableTrackButton:function(a,b){if(b==="")b=mejs.language.codes[a]||a;this.captionsButton.find("input[value="+a+"]").prop("disabled",false).siblings("label").html(b);
+this.options.startLanguage==a&&f("#"+this.id+"_captions_"+a).click();this.adjustLanguageBox()},addTrackButton:function(a,b){if(b==="")b=mejs.language.codes[a]||a;this.captionsButton.find("ul").append(f('<li><input type="radio" name="'+this.id+'_captions" id="'+this.id+"_captions_"+a+'" value="'+a+'" disabled="disabled" /><label for="'+this.id+"_captions_"+a+'">'+b+" (loading)</label></li>"));this.adjustLanguageBox();this.container.find(".mejs-captions-translations option[value="+a+"]").remove()},
+adjustLanguageBox:function(){this.captionsButton.find(".mejs-captions-selector").height(this.captionsButton.find(".mejs-captions-selector ul").outerHeight(true)+this.captionsButton.find(".mejs-captions-translations").outerHeight(true))},checkForTracks:function(){var a=false;if(this.options.hideCaptionsButtonWhenEmpty){for(i=0;i<this.tracks.length;i++)if(this.tracks[i].kind=="subtitles"){a=true;break}if(!a){this.captionsButton.hide();this.setControlsSize()}}},displayCaptions:function(){if(typeof this.tracks!=
+"undefined"){var a,b=this.selectedTrack;if(b!=null&&b.isLoaded)for(a=0;a<b.entries.times.length;a++)if(this.media.currentTime>=b.entries.times[a].start&&this.media.currentTime<=b.entries.times[a].stop){this.captionsText.html(b.entries.text[a]);this.captions.show().height(0);return}this.captions.hide()}},setupSlides:function(a){this.slides=a;this.slides.entries.imgs=[this.slides.entries.text.length];this.showSlide(0)},showSlide:function(a){if(!(typeof this.tracks=="undefined"||typeof this.slidesContainer==
+"undefined")){var b=this,c=b.slides.entries.text[a],e=b.slides.entries.imgs[a];if(typeof e=="undefined"||typeof e.fadeIn=="undefined")b.slides.entries.imgs[a]=e=f('<img src="'+c+'">').on("load",function(){e.appendTo(b.slidesContainer).hide().fadeIn().siblings(":visible").fadeOut()});else!e.is(":visible")&&!e.is(":animated")&&e.fadeIn().siblings(":visible").fadeOut()}},displaySlides:function(){if(typeof this.slides!="undefined"){var a=this.slides,b;for(b=0;b<a.entries.times.length;b++)if(this.media.currentTime>=
+a.entries.times[b].start&&this.media.currentTime<=a.entries.times[b].stop){this.showSlide(b);break}}},displayChapters:function(){var a;for(a=0;a<this.tracks.length;a++)if(this.tracks[a].kind=="chapters"&&this.tracks[a].isLoaded){this.drawChapters(this.tracks[a]);this.hasChapters=true;break}},drawChapters:function(a){var b=this,c,e,d=e=0;b.chapters.empty();for(c=0;c<a.entries.times.length;c++){e=a.entries.times[c].stop-a.entries.times[c].start;e=Math.floor(e/b.media.duration*100);if(e+d>100||c==a.entries.times.length-
+1&&e+d<100)e=100-d;b.chapters.append(f('<div class="mejs-chapter" rel="'+a.entries.times[c].start+'" style="left: '+d.toString()+"%;width: "+e.toString()+'%;"><div class="mejs-chapter-block'+(c==a.entries.times.length-1?" mejs-chapter-block-last":"")+'"><span class="ch-title">'+a.entries.text[c]+'</span><span class="ch-time">'+mejs.Utility.secondsToTimeCode(a.entries.times[c].start)+"&ndash;"+mejs.Utility.secondsToTimeCode(a.entries.times[c].stop)+"</span></div></div>"));d+=e}b.chapters.find("div.mejs-chapter").click(function(){b.media.setCurrentTime(parseFloat(f(this).attr("rel")));
+b.media.paused&&b.media.play()});b.chapters.show()}});mejs.language={codes:{af:"Afrikaans",sq:"Albanian",ar:"Arabic",be:"Belarusian",bg:"Bulgarian",ca:"Catalan",zh:"Chinese","zh-cn":"Chinese Simplified","zh-tw":"Chinese Traditional",hr:"Croatian",cs:"Czech",da:"Danish",nl:"Dutch",en:"English",et:"Estonian",tl:"Filipino",fi:"Finnish",fr:"French",gl:"Galician",de:"German",el:"Greek",ht:"Haitian Creole",iw:"Hebrew",hi:"Hindi",hu:"Hungarian",is:"Icelandic",id:"Indonesian",ga:"Irish",it:"Italian",ja:"Japanese",
+ko:"Korean",lv:"Latvian",lt:"Lithuanian",mk:"Macedonian",ms:"Malay",mt:"Maltese",no:"Norwegian",fa:"Persian",pl:"Polish",pt:"Portuguese",ro:"Romanian",ru:"Russian",sr:"Serbian",sk:"Slovak",sl:"Slovenian",es:"Spanish",sw:"Swahili",sv:"Swedish",tl:"Tagalog",th:"Thai",tr:"Turkish",uk:"Ukrainian",vi:"Vietnamese",cy:"Welsh",yi:"Yiddish"}};mejs.TrackFormatParser={webvvt:{pattern_identifier:/^([a-zA-z]+-)?[0-9]+$/,pattern_timecode:/^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
+parse:function(a){var b=0;a=mejs.TrackFormatParser.split2(a,/\r?\n/);for(var c={text:[],times:[]},e,d;b<a.length;b++)if(this.pattern_identifier.exec(a[b])){b++;if((e=this.pattern_timecode.exec(a[b]))&&b<a.length){b++;d=a[b];for(b++;a[b]!==""&&b<a.length;){d=d+"\n"+a[b];b++}d=f.trim(d).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,"<a href='$1' target='_blank'>$1</a>");c.text.push(d);c.times.push({start:mejs.Utility.convertSMPTEtoSeconds(e[1])==0?0.2:mejs.Utility.convertSMPTEtoSeconds(e[1]),
+stop:mejs.Utility.convertSMPTEtoSeconds(e[3]),settings:e[5]})}}return c}},dfxp:{parse:function(a){a=f(a).filter("tt");var b=0;b=a.children("div").eq(0);var c=b.find("p");b=a.find("#"+b.attr("style"));var e,d;a={text:[],times:[]};if(b.length){d=b.removeAttr("id").get(0).attributes;if(d.length){e={};for(b=0;b<d.length;b++)e[d[b].name.split(":")[1]]=d[b].value}}for(b=0;b<c.length;b++){var g;d={start:null,stop:null,style:null};if(c.eq(b).attr("begin"))d.start=mejs.Utility.convertSMPTEtoSeconds(c.eq(b).attr("begin"));
+if(!d.start&&c.eq(b-1).attr("end"))d.start=mejs.Utility.convertSMPTEtoSeconds(c.eq(b-1).attr("end"));if(c.eq(b).attr("end"))d.stop=mejs.Utility.convertSMPTEtoSeconds(c.eq(b).attr("end"));if(!d.stop&&c.eq(b+1).attr("begin"))d.stop=mejs.Utility.convertSMPTEtoSeconds(c.eq(b+1).attr("begin"));if(e){g="";for(var k in e)g+=k+":"+e[k]+";"}if(g)d.style=g;if(d.start==0)d.start=0.2;a.times.push(d);d=f.trim(c.eq(b).html()).replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
+"<a href='$1' target='_blank'>$1</a>");a.text.push(d);if(a.times.start==0)a.times.start=2}return a}},split2:function(a,b){return a.split(b)}};if("x\n\ny".split(/\n/gi).length!=3)mejs.TrackFormatParser.split2=function(a,b){var c=[],e="",d;for(d=0;d<a.length;d++){e+=a.substring(d,d+1);if(b.test(e)){c.push(e.replace(b,""));e=""}}c.push(e);return c}})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{contextMenuItems:[{render:function(a){if(typeof a.enterFullScreen=="undefined")return null;return a.isFullScreen?mejs.i18n.t("Turn off Fullscreen"):mejs.i18n.t("Go Fullscreen")},click:function(a){a.isFullScreen?a.exitFullScreen():a.enterFullScreen()}},{render:function(a){return a.media.muted?mejs.i18n.t("Unmute"):mejs.i18n.t("Mute")},click:function(a){a.media.muted?a.setMuted(false):a.setMuted(true)}},{isSeparator:true},{render:function(){return mejs.i18n.t("Download Video")},
+click:function(a){window.location.href=a.media.currentSrc}}]});f.extend(MediaElementPlayer.prototype,{buildcontextmenu:function(a){a.contextMenu=f('<div class="mejs-contextmenu"></div>').appendTo(f("body")).hide();a.container.bind("contextmenu",function(b){if(a.isContextMenuEnabled){b.preventDefault();a.renderContextMenu(b.clientX-1,b.clientY-1);return false}});a.container.bind("click",function(){a.contextMenu.hide()});a.contextMenu.bind("mouseleave",function(){a.startContextMenuTimer()})},cleancontextmenu:function(a){a.contextMenu.remove()},
+isContextMenuEnabled:true,enableContextMenu:function(){this.isContextMenuEnabled=true},disableContextMenu:function(){this.isContextMenuEnabled=false},contextMenuTimeout:null,startContextMenuTimer:function(){var a=this;a.killContextMenuTimer();a.contextMenuTimer=setTimeout(function(){a.hideContextMenu();a.killContextMenuTimer()},750)},killContextMenuTimer:function(){var a=this.contextMenuTimer;if(a!=null){clearTimeout(a);delete a}},hideContextMenu:function(){this.contextMenu.hide()},renderContextMenu:function(a,
+b){for(var c=this,e="",d=c.options.contextMenuItems,g=0,k=d.length;g<k;g++)if(d[g].isSeparator)e+='<div class="mejs-contextmenu-separator"></div>';else{var j=d[g].render(c);if(j!=null)e+='<div class="mejs-contextmenu-item" data-itemindex="'+g+'" id="element-'+Math.random()*1E6+'">'+j+"</div>"}c.contextMenu.empty().append(f(e)).css({top:b,left:a}).show();c.contextMenu.find(".mejs-contextmenu-item").each(function(){var m=f(this),q=parseInt(m.data("itemindex"),10),p=c.options.contextMenuItems[q];typeof p.show!=
+"undefined"&&p.show(m,c);m.click(function(){typeof p.click!="undefined"&&p.click(c);c.contextMenu.hide()})});setTimeout(function(){c.killControlsTimer("rev3")},100)}})})(mejs.$);
+(function(f){f.extend(mejs.MepDefaults,{postrollCloseText:mejs.i18n.t("Close")});f.extend(MediaElementPlayer.prototype,{buildpostroll:function(a,b,c){var e=this.container.find('link[rel="postroll"]').attr("href");if(typeof e!=="undefined"){a.postroll=f('<div class="mejs-postroll-layer mejs-layer"><a class="mejs-postroll-close" onclick="$(this).parent().hide();return false;">'+this.options.postrollCloseText+'</a><div class="mejs-postroll-layer-content"></div></div>').prependTo(c).hide();this.media.addEventListener("ended",
+function(){f.ajax({dataType:"html",url:e,success:function(d){c.find(".mejs-postroll-layer-content").html(d)}});a.postroll.show()},false)}}})})(mejs.$);
+
diff --git a/src/wp-includes/js/mediaelement/mediaelementplayer.min.css b/src/wp-includes/js/mediaelement/mediaelementplayer.min.css
new file mode 100644
index 0000000000..5d88e84e5d
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/mediaelementplayer.min.css
@@ -0,0 +1 @@
+.mejs-container{position:relative;background:#000;font-family:Helvetica,Arial;text-align:left;vertical-align:top;text-indent:0;}.me-plugin{position:absolute;}.mejs-embed,.mejs-embed body{width:100%;height:100%;margin:0;padding:0;background:#000;overflow:hidden;}.mejs-fullscreen{overflow:hidden!important;}.mejs-container-fullscreen{position:fixed;left:0;top:0;right:0;bottom:0;overflow:hidden;z-index:1000;}.mejs-container-fullscreen .mejs-mediaelement,.mejs-container-fullscreen video{width:100%;height:100%;}.mejs-clear{clear:both;}.mejs-background{position:absolute;top:0;left:0;}.mejs-mediaelement{position:absolute;top:0;left:0;width:100%;height:100%;}.mejs-poster{position:absolute;top:0;left:0;background-size:contain;background-position:50% 50%;background-repeat:no-repeat;}:root .mejs-poster img{display:none;}.mejs-poster img{border:0;padding:0;border:0;}.mejs-overlay{position:absolute;top:0;left:0;}.mejs-overlay-play{cursor:pointer;}.mejs-overlay-button{position:absolute;top:50%;left:50%;width:100px;height:100px;margin:-50px 0 0 -50px;background:url(bigplay.svg) no-repeat;}.no-svg .mejs-overlay-button{background-image:url(bigplay.png);}.mejs-overlay:hover .mejs-overlay-button{background-position:0 -100px;}.mejs-overlay-loading{position:absolute;top:50%;left:50%;width:80px;height:80px;margin:-40px 0 0 -40px;background:#333;background:url(background.png);background:rgba(0,0,0,0.9);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(50,50,50,0.9)),to(rgba(0,0,0,0.9)));background:-webkit-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:-moz-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:-o-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:-ms-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:linear-gradient(rgba(50,50,50,0.9),rgba(0,0,0,0.9));}.mejs-overlay-loading span{display:block;width:80px;height:80px;background:transparent url(loading.gif) 50% 50% no-repeat;}.mejs-container .mejs-controls{position:absolute;list-style-type:none;margin:0;padding:0;bottom:0;left:0;background:url(background.png);background:rgba(0,0,0,0.7);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(50,50,50,0.7)),to(rgba(0,0,0,0.7)));background:-webkit-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-moz-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-o-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-ms-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:linear-gradient(rgba(50,50,50,0.7),rgba(0,0,0,0.7));height:30px;width:100%;}.mejs-container .mejs-controls div{list-style-type:none;background-image:none;display:block;float:left;margin:0;padding:0;width:26px;height:26px;font-size:11px;line-height:11px;font-family:Helvetica,Arial;border:0;}.mejs-controls .mejs-button button{cursor:pointer;display:block;font-size:0;line-height:0;text-decoration:none;margin:7px 5px;padding:0;position:absolute;height:16px;width:16px;border:0;background:transparent url(controls.svg) no-repeat;}.no-svg .mejs-controls .mejs-button button{background-image:url(controls.png);}.mejs-controls .mejs-button button:focus{outline:solid 1px yellow;}.mejs-container .mejs-controls .mejs-time{color:#fff;display:block;height:17px;width:auto;padding:8px 3px 0 3px;overflow:hidden;text-align:center;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;}.mejs-container .mejs-controls .mejs-time span{color:#fff;font-size:11px;line-height:12px;display:block;float:left;margin:1px 2px 0 0;width:auto;}.mejs-controls .mejs-play button{background-position:0 0;}.mejs-controls .mejs-pause button{background-position:0 -16px;}.mejs-controls .mejs-stop button{background-position:-112px 0;}.mejs-controls div.mejs-time-rail{direction:ltr;width:200px;padding-top:5px;}.mejs-controls .mejs-time-rail span{display:block;position:absolute;width:180px;height:10px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;}.mejs-controls .mejs-time-rail .mejs-time-total{margin:5px;background:#333;background:rgba(50,50,50,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(30,30,30,0.8)),to(rgba(60,60,60,0.8)));background:-webkit-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-moz-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-o-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-ms-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:linear-gradient(rgba(30,30,30,0.8),rgba(60,60,60,0.8));}.mejs-controls .mejs-time-rail .mejs-time-buffering{width:100%;background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:15px 15px;-moz-background-size:15px 15px;-o-background-size:15px 15px;background-size:15px 15px;-webkit-animation:buffering-stripes 2s linear infinite;-moz-animation:buffering-stripes 2s linear infinite;-ms-animation:buffering-stripes 2s linear infinite;-o-animation:buffering-stripes 2s linear infinite;animation:buffering-stripes 2s linear infinite;}@-webkit-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@-moz-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@-ms-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@-o-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}.mejs-controls .mejs-time-rail .mejs-time-loaded{background:#3caac8;background:rgba(60,170,200,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(44,124,145,0.8)),to(rgba(78,183,212,0.8)));background:-webkit-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:-moz-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:-o-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:-ms-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:linear-gradient(rgba(44,124,145,0.8),rgba(78,183,212,0.8));width:0;}.mejs-controls .mejs-time-rail .mejs-time-current{background:#fff;background:rgba(255,255,255,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(255,255,255,0.9)),to(rgba(200,200,200,0.8)));background:-webkit-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-moz-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-o-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-ms-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:linear-gradient(rgba(255,255,255,0.9),rgba(200,200,200,0.8));width:0;}.mejs-controls .mejs-time-rail .mejs-time-handle{display:none;position:absolute;margin:0;width:10px;background:#fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;cursor:pointer;border:solid 2px #333;top:-2px;text-align:center;}.mejs-controls .mejs-time-rail .mejs-time-float{position:absolute;display:none;background:#eee;width:36px;height:17px;border:solid 1px #333;top:-26px;margin-left:-18px;text-align:center;color:#111;}.mejs-controls .mejs-time-rail .mejs-time-float-current{margin:2px;width:30px;display:block;text-align:center;left:0;}.mejs-controls .mejs-time-rail .mejs-time-float-corner{position:absolute;display:block;width:0;height:0;line-height:0;border:solid 5px #eee;border-color:#eee transparent transparent transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;top:15px;left:13px;}.mejs-long-video .mejs-controls .mejs-time-rail .mejs-time-float{width:48px;}.mejs-long-video .mejs-controls .mejs-time-rail .mejs-time-float-current{width:44px;}.mejs-long-video .mejs-controls .mejs-time-rail .mejs-time-float-corner{left:18px;}.mejs-controls .mejs-fullscreen-button button{background-position:-32px 0;}.mejs-controls .mejs-unfullscreen button{background-position:-32px -16px;}.mejs-controls .mejs-mute button{background-position:-16px -16px;}.mejs-controls .mejs-unmute button{background-position:-16px 0;}.mejs-controls .mejs-volume-button{position:relative;}.mejs-controls .mejs-volume-button .mejs-volume-slider{display:none;height:115px;width:25px;background:url(background.png);background:rgba(50,50,50,0.7);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;top:-115px;left:0;z-index:1;position:absolute;margin:0;}.mejs-controls .mejs-volume-button:hover{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-total{position:absolute;left:11px;top:8px;width:2px;height:100px;background:#ddd;background:rgba(255,255,255,0.5);margin:0;}.mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-current{position:absolute;left:11px;top:8px;width:2px;height:100px;background:#ddd;background:rgba(255,255,255,0.9);margin:0;}.mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-handle{position:absolute;left:4px;top:-3px;width:16px;height:6px;background:#ddd;background:rgba(255,255,255,0.9);cursor:N-resize;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;margin:0;}.mejs-controls div.mejs-horizontal-volume-slider{height:26px;width:60px;position:relative;}.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total{position:absolute;left:0;top:11px;width:50px;height:8px;margin:0;padding:0;font-size:1px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background:#333;background:rgba(50,50,50,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(30,30,30,0.8)),to(rgba(60,60,60,0.8)));background:-webkit-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-moz-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-o-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-ms-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:linear-gradient(rgba(30,30,30,0.8),rgba(60,60,60,0.8));}.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current{position:absolute;left:0;top:11px;width:50px;height:8px;margin:0;padding:0;font-size:1px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background:#fff;background:rgba(255,255,255,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(255,255,255,0.9)),to(rgba(200,200,200,0.8)));background:-webkit-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-moz-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-o-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-ms-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:linear-gradient(rgba(255,255,255,0.9),rgba(200,200,200,0.8));}.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-handle{display:none;}.mejs-controls .mejs-captions-button{position:relative;}.mejs-controls .mejs-captions-button button{background-position:-48px 0;}.mejs-controls .mejs-captions-button .mejs-captions-selector{visibility:hidden;position:absolute;bottom:26px;right:-10px;width:130px;height:100px;background:url(background.png);background:rgba(50,50,50,0.7);border:solid 1px transparent;padding:10px;overflow:hidden;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul{margin:0;padding:0;display:block;list-style-type:none!important;overflow:hidden;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul li{margin:0 0 6px 0;padding:0;list-style-type:none!important;display:block;color:#fff;overflow:hidden;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul li input{clear:both;float:left;margin:3px 3px 0 5px;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul li label{width:100px;float:left;padding:4px 0 0 0;line-height:15px;font-family:helvetica,arial;font-size:10px;}.mejs-controls .mejs-captions-button .mejs-captions-translations{font-size:10px;margin:0 0 5px 0;}.mejs-chapters{position:absolute;top:0;left:0;-xborder-right:solid 1px #fff;width:10000px;z-index:1;}.mejs-chapters .mejs-chapter{position:absolute;float:left;background:#222;background:rgba(0,0,0,0.7);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(50,50,50,0.7)),to(rgba(0,0,0,0.7)));background:-webkit-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-moz-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-o-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-ms-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:linear-gradient(rgba(50,50,50,0.7),rgba(0,0,0,0.7));filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,startColorstr=#323232,endColorstr=#000000);overflow:hidden;border:0;}.mejs-chapters .mejs-chapter .mejs-chapter-block{font-size:11px;color:#fff;padding:5px;display:block;border-right:solid 1px #333;border-bottom:solid 1px #333;cursor:pointer;}.mejs-chapters .mejs-chapter .mejs-chapter-block-last{border-right:none;}.mejs-chapters .mejs-chapter .mejs-chapter-block:hover{background:#666;background:rgba(102,102,102,0.7);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(102,102,102,0.7)),to(rgba(50,50,50,0.6)));background:-webkit-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:-moz-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:-o-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:-ms-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:linear-gradient(rgba(102,102,102,0.7),rgba(50,50,50,0.6));filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,startColorstr=#666666,endColorstr=#323232);}.mejs-chapters .mejs-chapter .mejs-chapter-block .ch-title{font-size:12px;font-weight:bold;display:block;white-space:nowrap;text-overflow:ellipsis;margin:0 0 3px 0;line-height:12px;}.mejs-chapters .mejs-chapter .mejs-chapter-block .ch-timespan{font-size:12px;line-height:12px;margin:3px 0 4px 0;display:block;white-space:nowrap;text-overflow:ellipsis;}.mejs-captions-layer{position:absolute;bottom:0;left:0;text-align:center;line-height:22px;font-size:12px;color:#fff;}.mejs-captions-layer a{color:#fff;text-decoration:underline;}.mejs-captions-layer[lang=ar]{font-size:20px;font-weight:normal;}.mejs-captions-position{position:absolute;width:100%;bottom:15px;left:0;}.mejs-captions-position-hover{bottom:45px;}.mejs-captions-text{padding:3px 5px;background:url(background.png);background:rgba(20,20,20,0.8);}.me-cannotplay a{color:#fff;font-weight:bold;}.me-cannotplay span{padding:15px;display:block;}.mejs-controls .mejs-loop-off button{background-position:-64px -16px;}.mejs-controls .mejs-loop-on button{background-position:-64px 0;}.mejs-controls .mejs-backlight-off button{background-position:-80px -16px;}.mejs-controls .mejs-backlight-on button{background-position:-80px 0;}.mejs-controls .mejs-picturecontrols-button{background-position:-96px 0;}.mejs-contextmenu{position:absolute;width:150px;padding:10px;border-radius:4px;top:0;left:0;background:#fff;border:solid 1px #999;z-index:1001;}.mejs-contextmenu .mejs-contextmenu-separator{height:1px;font-size:0;margin:5px 6px;background:#333;}.mejs-contextmenu .mejs-contextmenu-item{font-family:Helvetica,Arial;font-size:12px;padding:4px 6px;cursor:pointer;color:#333;}.mejs-contextmenu .mejs-contextmenu-item:hover{background:#2C7C91;color:#fff;}.mejs-controls .mejs-sourcechooser-button{position:relative;}.mejs-controls .mejs-sourcechooser-button button{background-position:-128px 0;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector{visibility:hidden;position:absolute;bottom:26px;right:-10px;width:130px;height:100px;background:url(background.png);background:rgba(50,50,50,0.7);border:solid 1px transparent;padding:10px;overflow:hidden;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul{margin:0;padding:0;display:block;list-style-type:none!important;overflow:hidden;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li{margin:0 0 6px 0;padding:0;list-style-type:none!important;display:block;color:#fff;overflow:hidden;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li input{clear:both;float:left;margin:3px 3px 0 5px;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li label{width:100px;float:left;padding:4px 0 0 0;line-height:15px;font-family:helvetica,arial;font-size:10px;}.mejs-postroll-layer{position:absolute;bottom:0;left:0;width:100%;height:100%;background:url(background.png);background:rgba(50,50,50,0.7);z-index:1000;overflow:hidden;}.mejs-postroll-layer-content{width:100%;height:100%;}.mejs-postroll-close{position:absolute;right:0;top:0;background:url(background.png);background:rgba(50,50,50,0.7);color:#fff;padding:4px;z-index:100;cursor:pointer;} \ No newline at end of file
diff --git a/src/wp-includes/js/mediaelement/silverlightmediaelement.xap b/src/wp-includes/js/mediaelement/silverlightmediaelement.xap
new file mode 100644
index 0000000000..9d55c2e46a
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/silverlightmediaelement.xap
Binary files differ
diff --git a/src/wp-includes/js/mediaelement/wp-mediaelement.css b/src/wp-includes/js/mediaelement/wp-mediaelement.css
new file mode 100644
index 0000000000..18ad94855b
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/wp-mediaelement.css
@@ -0,0 +1,15 @@
+.mejs-container, .mejs-embed, .mejs-embed body {
+ background: #464646;
+}
+
+.mejs-controls .mejs-time-rail .mejs-time-loaded {
+ background: #21759b;
+}
+
+.mejs-controls .mejs-time-rail .mejs-time-current {
+ background: #d54e21;
+}
+
+.me-cannotplay {
+ width: auto !important;
+}
diff --git a/src/wp-includes/js/mediaelement/wp-mediaelement.js b/src/wp-includes/js/mediaelement/wp-mediaelement.js
new file mode 100644
index 0000000000..fb09e3cde3
--- /dev/null
+++ b/src/wp-includes/js/mediaelement/wp-mediaelement.js
@@ -0,0 +1,15 @@
+(function ($) {
+ // add mime-type aliases to MediaElement plugin support
+ mejs.plugins.silverlight[0].types.push('video/x-ms-wmv');
+ mejs.plugins.silverlight[0].types.push('audio/x-ms-wma');
+
+ $(function () {
+ var settings = {};
+
+ if ( typeof _wpmejsSettings !== 'undefined' )
+ settings.pluginPath = _wpmejsSettings.pluginPath;
+
+ $('.wp-audio-shortcode, .wp-video-shortcode').mediaelementplayer( settings );
+ });
+
+}(jQuery));
diff --git a/src/wp-includes/js/plupload/changelog.txt b/src/wp-includes/js/plupload/changelog.txt
new file mode 100644
index 0000000000..7aaff4c8bf
--- /dev/null
+++ b/src/wp-includes/js/plupload/changelog.txt
@@ -0,0 +1,241 @@
+Version 1.5.7 (2013-04-10)
+ HTML5: Workaround for squish problem in iOS6, when uploading resized images.
+ HTML5: Fix failing workaround for FormData+Blob bug on Android...
+ HTML5: Allow multiple uploads on iOS.
+ Include VB build script that doesn't depend on Ant and is said to be native to Windows.
+Version 1.5.6 (2013-02-28)
+ Fix regression: getPos() wrong on ie6/7.
+ HTML5: Send file as binary string if it was mangled, even if multipart is set to false.
+ HTML5: Add workaround Android browsers, that are unable to properly send blobs in FormData.
+ HTML4/Flash/Silverlight: Destroy fails to cleanup everything when container not defined.
+ UI, Queue: Use html() instead of text(), otherwise special characters fail to display properly.
+ UI, Queue: Use on() instead of delegate() or live(). Update examples to use jQuery 1.9.0 by default.
+ Queue: Blur rename input field when ESC is pressed.
+ Additional language packs: Slovak.
+Version 1.5.5 (2013-01-23)
+ UI Widget: Fix sortable feature, broken in jQuery UI 1.9.
+ Queue: Replace live() with delegate(), as live() was removed from jQuery 1.9.
+ HTML5: window.getComputedStyle in Firefox doesn't support dashed rulenames - use zIndex instead of z-index.
+ HTML5/Flash/Silverlight/Gears: Process JPEGs, if quality parameter is present, whatever the scale factor.
+ Flash: Survive invalid EXIF tag offsets.
+ Flash: Allow only letters, digits and underscore in runtime id to avoid script injection.
+ SilverLight: Prepend ampersand to the query string, for non multipart cases (as in Flash and HTML5).
+ Add mime types for m2v,3gp,3g2 extensions.
+Version 1.5.4 (2012-04-12)
+ Flash: Disable scripting if swf was loaded from another domain.
+Version 1.5.3 (2012-04-05)
+ HTML5: Check if xhr object is initialized, before calling abort() on it.
+ HTML4: Postpone form removal until uploaders state changes, to avoid error on resuming stopped uploads.
+ BrowserPlus: Fix mechanical typo, that caused error during mime type check.
+ BrowserPlus: browserPlus.Uploader.Cancel() has two required parameters, dies with the error if not passed.
+ Flash: Improve runtime's behaviour during upload cancellation.
+ Flash: Survive the case when GPSVersionID contains unexpected value.
+ Flash: Fix random freeze in Chrome's bundled Flash Player.
+ Flash: Avoid the silent break when URLStream not yet open, but close is called on it.
+ Flash: Move Destroy handler out of Flash:Init handler, since it might be called not only after Flash:Init but also before it.
+ Flash: Avoid warning during build with mxmlc.
+ Try removeEventListener first in IE and only if it fails - detachEvent.
+ Fix plupload.getPos to return proper value in IE8+.
+ Do not initiate plupload.STARTED state, if file queue is empty.
+ Additional language packs: Estonian, Polish, Korean, French-Canadian, Greek, Persian/Farsi.
+Version 1.5.2 (2012-01-06)
+ UI Widget: Do not show UI if no runtime can be initialized.
+ UI Widget: Timely update file size and total size if resize in action.
+ UI Widget: Constrain renaming feature to queued files only.
+ UI Widget: Disable Add button properly, if requested, rather then just hide.
+ HTML4/HTML5/BrowserPlus: Avoid adding mime type twice to dialog trigger.
+ HTML5: fix regression, when unresized images were failing on FF3.6.
+ HTML5: Constrain Gecko 2,5,6 workaround to multipart mode only.
+ HTML5/Flash: Take into account weird possibilities of ExifVersion being a string, rather then standard Undefined.
+ Flash: Simplify event dispatching in BitmapDataUnlimited class, in order to avoid freezing on resizing in FP11.
+ Add ability to disable file dialog trigger on request (uploader.disableBrowse(true/false)).
+ Support for immediate abort of upload process, be it chunked upload or regular one.
+ Abort all activity, before destroying uploader.
+ Revive temporary file removal logic in upload.php.
+ Fix potential vulnerability in dump.php and upload.php.
+ Additional MIME types: application/vnd.openxmlformats-officedocument.*, application/x-javascript, application/json, text/css,css, application/vnd.oasis.opendocument.formula-templat.
+ Additional language packs: Hungarian, Croatian, Serbian, Romanian.
+Version 1.5.1.1 (2011-09-27)
+ HTML5: Fix mechanical typo, that successfully broke drag and drop, wherever could.
+Version 1.5.1 (2011-09-26)
+ HTML4: Add support for server responses in HTML format.
+ HTML5: Disable multiple file selection in Safari 5.x for Windows (see #363).
+ HTML5: Gecko 2/5/6 should upload chunks as binary strings when in chunking mode and client side resize is requested.
+ Flash: Enforce URLStream mode when custom headers are passed.
+ Flash: Fix embedding problems in IE9 (and all other IEs).
+ Flash/Gears/BrowserPlus/SilverLight: Expose multi_selection feature, to be used in required_features (mainly to overcome Safari for Windows problem).
+ SilverLight: Properly handle custom and null headers.
+ UploadComplete moved to fire after the last StateChanged event.
+ Additional language packs: Finnish.
+Version 1.5b (2011-09-11)
+ UI Widget: Fix sortable logic.
+ UI Widget: Fix bug, when message was displayed simultaneously across all Plupload UI instances on the page.
+ UI Widget: notify() method is now public - users can throw their own messages into the widget header.
+ HTML4/HTML5: Revise input[type=file] placement logic to support cursor styling on Geko 2+.
+ HTML5: Revise Drag'n'Drop detection logic.
+ HTML5: Make Exif and GPS information available to user, introduce two new events: ExifData and GpsData.
+ HTML5: Add support for File.prototype.slice() method (mozSlice/webkitSlice) in order to be able to upload files in chunks without preloading.
+ HTML5: Remove any JPEG headers before restoring them, 'cause user agent (like Chrome), might be inserting it's own.
+ Flash: Remove a limit on the depth of image header check, since it still fails in some cases and performance gain is negligible.
+ Flash: Fix regression, when runtime hanged when not images where passed in as images.
+ SilverLight: Fix bug, when JSON serializer was failing on null.
+ SilverLight: Remove cast to integer for chunk boundary, which resulted in a wrong size for last chunks on huge files.
+ SilverLight: Increase read buffer, add disposal of ImageStream and FileStream, optimize for performance.
+ Updated build.xml to include language packs in release package under js/ folder.
+ Gears/BrowserPlus: Add support for * file filter.
+ BeforeUpload now can cancel upload if required.
+ Additional MIME types: text/csv, image/photoshop, video/x-ms-wmv, video/avi, video/webm support
+ Additional language packs: Japanese
+ Cleaned examples.
+Version 1.4.3.2 (2011-04-13)
+ Fixed bug in HTML5 runtime, when was reduced by a factor of 100 after every upload.
+Version 1.4.3.1 (2011-04-12)
+ Fixed build script, mistakenly populating jquery.plupload.queue directory from jquery.ui.plupload sources.
+ Fixed script urls in all examples, build script now will alter them automatically from dev to release when needed.
+ Fixed isEmptyObj undefined error in HTML4 runtime.
+ Fixed bug in UI Widget preventing UploadComplete from triggering.
+Version 1.4.3 (2011-04-11)
+ Added Latvian language pack and updated French.
+ Fixed bug in Flash runtime when JPEG header was not investigated deep enough to reach SOFn marker in large images.
+ Fixed bug, when PNGs were cropped to width in Flash runtimes, rather then resized.
+ Fixed Flash to allow multiple uploading of the same file, with different settings.
+ Fixed Flash runtime to clean anonymous listeners properly.
+ Fixed HTML5 runtime to resolve to mimeType in case-insensitive way.
+ Fixed HTML5/Flash/SilverLight/Gears runtimes for inconsistency in naming of chunks feature, comparing to other runtimes.
+ Fixed HTML4/HTML5 runtimes for input[type=file] to outsize contaner effectively enough to fill the whole click area.
+ Fixed all runtimes to preserve position (relative/absolute) rule on containers that already have it.
+ Fixed SilverLight runtime to support large files (over 2GB).
+ Restructured the examples, src and build scripts to make it more clear that jQuery is optional.
+ Added support for *.* filter.
+ Added support for preserving ICC and IPTC headers when resizing JPEGs.
+ Added Image.onerror/onabort handlers to HTML5 in order to gracefully bypass faulty images.
+ Added ability to drop image size (by lowering quality), while preserving original dimension (HTML5/Flash/Gears).
+ Ported EXIF, ICC, IPTC preservation code to Flash runtime.
+Version 1.4.2 (2011-02-20)
+ Added Brazilian Portuguese, German, Russian and Spanish translations.
+ Added support for file_data_name option to SilverLight runtime.
+ Added support for better quality image resizing to Flash runtime.
+ Added support for properly handling images with dimensions up to 8191x8191 pixels to Flash runtime.
+ Added 'updatelist' event to UI Widget, which will be triggered every time file list will get redrawn.
+ Added support for dynamically changing options to UI Widget.
+ Fixed HTML4 runtime bug, when UploadFile handler was attached twice.
+ Fixed HTML5 to use FileReader.readAsBinaryString() instead of File.getAsBinary() on newer WebKit browsers (like Chrome 9).
+ Fixed Flash runtime from sending duplicate Filename param, when using FileReference.upload().
+ Updated S3 example to illustrate support for a proper progress indication.
+Version 1.4.1 (2011-02-01)
+ Added an example on how to use Plupload with Amazon S3 written in PHP but can easily be ported to other languages.
+ Fixed bug where hidden input elements wasn't created when the multiple_queues option wasn't used.
+ Fixed bug where FF4 would produce an exception about missing BlobBuilder.
+Version 1.4.0 (2011-01-26)
+ Added removeEvent and removeAllEvents methods and modified addEvent accordingly, in order to support dynamic unload.
+ Added unbindAll method.
+ Added UploadComplete event, which fires when internal iterator reaches the end of the queue.
+ Added public destroy method to plupload object, new event - Destroy, and corresponding handlers to all runtimes.
+ Added Czech, Italian, French, Dutch translations.
+ Added support for translatable error messages.
+ Added two new options: browse_button_hover and browse_button_active, in order to support browse_button interactivity.
+ Added support for 'multi_selection: false' to Silverlight runtime.
+ Added support for video/mp4, video/x-m4v and audio/mp4 MIME Types.
+ Added artificial sendAsBinary method to XMLHttpRequest.prototype for browsers that have support for BlobBuilder and typed arrays.
+ Added version tracking variable into plupload object and version comment to the header of every file.
+ Fixed measurements of browse_button element in order to size and position input[type=file] element to fit it fully.
+ Fixed Flash runtime behavior for multiple_select=false and other simpleUpload usage cases: basically new FileReference has to be created for every select dialog.
+ Fixed browser sniffer to match only Safari, for fakeSafariDragDrop (seems like Safari on Mac doesn't require it either).
+ Fixed so that ExternalInterface escapes strings properly, before passing them to JS.
+ Fixed eventual reinitialization of flash/silverlight runtimes, especially for cases when object wrapper needed to be programmatically hidden and then shown again.
+ Fixed so that Plupload will now ignore files with duplicate names when adding to the queue, in one set. Mainly introduced to work around Safari on Windows bug (https://bugs.webkit.org/show_bug.cgi?id=37957).
+ Fixed bug, when final UploadProgress was firing after FileUploaded for Flash simpleUpload.
+ Fixed bug where upload would fail if an error was produced inside the FilesAdded event.
+ Fixed bug in Flash runtime when it used a wrong size when resizing, but not chunking.
+ Fixed bug in Silverlight runtime that would keep sending 0 byte packages when a picture was chunked before resized.
+ Disabled blur filter (is going to be replaced with some bilinear resampling in next release).
+ Completely revised UI Widget, to be more jQuery UI oriented. Optionally depends on UI Button, UI Sortable, UI ProgressBar.
+Version 1.3.0 (2010-11-24)
+ Added new jQuery UI widget that supports jQuery UI themes.
+ Added new multiple_queues option that enables you to upload multiple times in the queue widgets.
+ Added support for crossdomain loading of the XAP and SWF files and crossdomain upload.
+ Added new multiple_queues option that enables you to upload multiple times in the queue widgets.
+ Added support for crossdomain loading of the XAP and SWF files and crossdomain upload.
+ Added preinit/init options to to ease up the binding of custom events to queueWidget and the Uploader class.
+ Added drag/drop support for Safari until they fix the broken drag/drop support on Windows.
+ Added events example file that show how to bind all events and display event specific data.
+ Added support for retaining Exif data on images when they where resized using the HTML5 runtime.
+ Fixed logic issue with the upload.php example file. Chunking wasn't working correctly.
+ Fixed issue with HTML4 not handling the form encoding correctly on older IE versions. Patch contributed by jinxdone.
+ Fixed so the HTML4 runtime only submits the defined multipart_params arguments.
+ Fixes issue where it wasn't possible to dynamically override url or mutlipart_params for the HTML4 runtime.
+ Fixed so all runtimes pass the name, chunk and chunks parameters as multipart parameters instead of querystring parameters.
+ Fixed so files are read using the newer FileReader class if it's available if not it tries the older getAsXXX on Gecko.
+ Fixed bug where IE 9 beta 1 wouldn't render Silverlight properly.
+ Fixed bug where Flash would do extra empty requests if images below a specific size would be uploaded.
+ Fixed bug where Google Gears would resize and re-encode images even if the it wasn't changed in scale.
+ Fixed bug where the HTML5 runtime wouldn't free memory after each request on Gecko.
+Version 1.2.4 (2010-09-08)
+ Added new BeforeUpload event to make it easier to override settings before a file is uploaded.
+ Added new automatic usage of FileReference in Flash if it's possible. Contributed by Marcel Jackwerth.
+ Added new chunking support for Chrome 5 and Firefox 3.6 using the HTML 5 runtime.
+ Added new multipart upload support for WebKit using the HTML 5 runtime and the FormData object.
+ Added new image scaling method for the Flash runtime contributed by rcoopman.
+ Added new alert error message if the user selected invalid files.
+ Added new automatic unique name generation to the example.php script. Contributed by Brandon Kelly.
+ Changed so the default upload method is multipart and the default chunk size is 0.
+ Fixed progress issue with the HTML5 runtime running on Gecko.
+ Fixed so longer extensions can be used such as .tar.gz.
+ Fixed so the file extension is retained when using the unique_names option.
+Version 1.2.3 (2010-05-27)
+ Added new drag/drop support for HTML5 running on Chrome beta.
+ Added new multipart state for the features object. It's now possible to detect multipart support.
+ Added new getFeatures function to all runtime. Basic concept by Javier Martinez Fernandez.
+ Fixed bug where runtimes where initialized even if they didn't match the required_features setting.
+Version 1.2.2.1 (2010-05-04)
+ Added new headers option, enables you to set custom headers for the upload requests.
+ Fixed bug where the file extension checking was case sensitive.
+Version 1.2.2 (2010-04-26)
+ Added new file_data_name option that enables you to set the multipart file data param. Patch contributed by Alex Ganov.
+ Added new FILE_SIZE_ERROR type that will be triggered if the user selected a file that is to large or zero bytes.
+ Added new FILE_EXTENSION_ERROR type that will be triggered if you add a file with an invalid file extension.
+ Added new required_features setting, enables you to specify a list of required features that the runtime must have.
+ Fixed so the plupload.buildUrl function uses the UTF compatible encodeURIComponent method instead of escape.
+ Fixed so that all file types can be selected if you don't specify a filter setting.
+ Fixed so more valid HTTP status codes are accepted as valid responses.
+ Fixed so all runtimes fills the features object with available features.
+ Fixed some issues with the HTML4 runtime if there wasn't any existing forms on the page.
+ Fixed some conflict issues with HTML4 runtime and forms with the input names of action or target.
+ Fixed bug where some Gecko versions would produce exceptions when checking the HTTP status of a XHR.
+Version 1.2.1 (2010-03-22)
+ Fixed bug with incorrect aspect ratio in Flash image scaling.
+ Fixed bug where chunked uploads could get scrambled in the Flash runtime. Patch contributed by Grady Werner.
+ Fixed bug where a beta version of Chrome wouldn't handle drag/drop correctly because of missing drag effect.
+ Fixed so the HTML 4 runtime displays N/A for file sizes and the progress is based on uploaded files instead of bytes.
+ Fixed so chunking can be disabled properly in Flash but that will affect the progress bar.
+ Fixed so queue widget displays the drag/drop message if file queue is emptied.
+ Fixed small files are uploaded as one single chunk and not forced into 4 chunks in the Flash runtime.
+Version 1.2 (2010-03-09)
+ Added new rename file support for jQuery queue widget, click on a file name to rename it if it's enabled.
+ Added official ChunkUploaded event, it similar to FileUploaded but executed for each chunk.
+ Added bytes per second support to total queue progress.
+ Added better error handling to core API using the new Error event.
+ Added better error handling to jQuery queue widget.
+ Fixed so chunking uploads is dispatch from JS not from inside Flash/Silverlight.
+Version 1.1.1 (2010-02-25)
+ Added new setup setting to queue widget. Makes it easier to bind custom events to uploader instance.
+ Fixed so it's possible to disable chunking compleatly. It's now disabled by default.
+ Fixed bug where multipart mode was enabled all the time in the Flash runtime.
+ Fixed bug where chunked uploading in Silverlight would fail.
+ Fixed bug where the delete button was visible while uploading.
+ Fixed bug where unique_names setting wasn't working when the core API was used.
+ Fixed bug where the queue widget wouldn't display the currently uploaded file if the unique_names was enabled.
+Version 1.1 (2010-02-24)
+ Added new multipart and multipart_params support.
+ Added new container option, enables you to specify where flash/silverlight objects would be added.
+ Added chunking support to BrowserPlus runtime, contributed by Steve Spencer.
+ Added FileUploaded event that fires when a file is uploaded.
+ Added more easily understandable buttons to queue widget.
+ Added html4 runtime, contributed by Ryan Demmer.
+ Fixed issues with i18n support and added a Swedish and Danish language pack.
+ Fixed bug where the Flash runtime could do empty requests if the image was scaled down.
+ Fixed bug where uploading small images in Silverlight would produce an exception.
+ Fixed so the runtime list can include whitespace or missing runtimes. Patch contributed by Øyvind Sean Kinsey.
+ Fixed so to large files are ignored and never dispatched to the FilesAdded event.
+Version 1.0 (2010-02-03)
+ First official release of Plupload.
diff --git a/src/wp-includes/js/plupload/handlers.js b/src/wp-includes/js/plupload/handlers.js
new file mode 100644
index 0000000000..0b9937c4db
--- /dev/null
+++ b/src/wp-includes/js/plupload/handlers.js
@@ -0,0 +1,491 @@
+var topWin = window.dialogArguments || opener || parent || top, uploader, uploader_init;
+
+function fileDialogStart() {
+ jQuery("#media-upload-error").empty();
+}
+
+// progress and success handlers for media multi uploads
+function fileQueued(fileObj) {
+ // Get rid of unused form
+ jQuery('.media-blank').remove();
+
+ var items = jQuery('#media-items').children(), postid = post_id || 0;
+
+ // Collapse a single item
+ if ( items.length == 1 ) {
+ items.removeClass('open').find('.slidetoggle').slideUp(200);
+ }
+ // Create a progress bar containing the filename
+ jQuery('<div class="media-item">')
+ .attr( 'id', 'media-item-' + fileObj.id )
+ .addClass('child-of-' + postid)
+ .append('<div class="progress"><div class="percent">0%</div><div class="bar"></div></div>',
+ jQuery('<div class="filename original">').text( ' ' + fileObj.name ))
+ .appendTo( jQuery('#media-items' ) );
+
+ // Disable submit
+ jQuery('#insert-gallery').prop('disabled', true);
+}
+
+function uploadStart() {
+ try {
+ if ( typeof topWin.tb_remove != 'undefined' )
+ topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove);
+ } catch(e){}
+
+ return true;
+}
+
+function uploadProgress(up, file) {
+ var item = jQuery('#media-item-' + file.id);
+
+ jQuery('.bar', item).width( (200 * file.loaded) / file.size );
+ jQuery('.percent', item).html( file.percent + '%' );
+}
+
+// check to see if a large file failed to upload
+function fileUploading(up, file) {
+ var hundredmb = 100 * 1024 * 1024, max = parseInt(up.settings.max_file_size, 10);
+
+ if ( max > hundredmb && file.size > hundredmb ) {
+ setTimeout(function(){
+ var done;
+
+ if ( file.status < 3 && file.loaded == 0 ) { // not uploading
+ wpFileError(file, pluploadL10n.big_upload_failed.replace('%1$s', '<a class="uploader-html" href="#">').replace('%2$s', '</a>'));
+ up.stop(); // stops the whole queue
+ up.removeFile(file);
+ up.start(); // restart the queue
+ }
+ }, 10000); // wait for 10 sec. for the file to start uploading
+ }
+}
+
+function updateMediaForm() {
+ var items = jQuery('#media-items').children();
+
+ // Just one file, no need for collapsible part
+ if ( items.length == 1 ) {
+ items.addClass('open').find('.slidetoggle').show();
+ jQuery('.insert-gallery').hide();
+ } else if ( items.length > 1 ) {
+ items.removeClass('open');
+ // Only show Gallery button when there are at least two files.
+ jQuery('.insert-gallery').show();
+ }
+
+ // Only show Save buttons when there is at least one file.
+ if ( items.not('.media-blank').length > 0 )
+ jQuery('.savebutton').show();
+ else
+ jQuery('.savebutton').hide();
+}
+
+function uploadSuccess(fileObj, serverData) {
+ var item = jQuery('#media-item-' + fileObj.id);
+
+ // on success serverData should be numeric, fix bug in html4 runtime returning the serverData wrapped in a <pre> tag
+ serverData = serverData.replace(/^<pre>(\d+)<\/pre>$/, '$1');
+
+ // if async-upload returned an error message, place it in the media item div and return
+ if ( serverData.match(/media-upload-error|error-div/) ) {
+ item.html(serverData);
+ return;
+ } else {
+ jQuery('.percent', item).html( pluploadL10n.crunching );
+ }
+
+ prepareMediaItem(fileObj, serverData);
+ updateMediaForm();
+
+ // Increment the counter.
+ if ( post_id && item.hasClass('child-of-' + post_id) )
+ jQuery('#attachments-count').text(1 * jQuery('#attachments-count').text() + 1);
+}
+
+function setResize(arg) {
+ if ( arg ) {
+ if ( uploader.features.jpgresize )
+ uploader.settings['resize'] = { width: resize_width, height: resize_height, quality: 100 };
+ else
+ uploader.settings.multipart_params.image_resize = true;
+ } else {
+ delete(uploader.settings.resize);
+ delete(uploader.settings.multipart_params.image_resize);
+ }
+}
+
+function prepareMediaItem(fileObj, serverData) {
+ var f = ( typeof shortform == 'undefined' ) ? 1 : 2, item = jQuery('#media-item-' + fileObj.id);
+ if ( f == 2 && shortform > 2 )
+ f = shortform;
+
+ try {
+ if ( typeof topWin.tb_remove != 'undefined' )
+ topWin.jQuery('#TB_overlay').click(topWin.tb_remove);
+ } catch(e){}
+
+ if ( isNaN(serverData) || !serverData ) { // Old style: Append the HTML returned by the server -- thumbnail and form inputs
+ item.append(serverData);
+ prepareMediaItemInit(fileObj);
+ } else { // New style: server data is just the attachment ID, fetch the thumbnail and form html from the server
+ item.load('async-upload.php', {attachment_id:serverData, fetch:f}, function(){prepareMediaItemInit(fileObj);updateMediaForm()});
+ }
+}
+
+function prepareMediaItemInit(fileObj) {
+ var item = jQuery('#media-item-' + fileObj.id);
+ // Clone the thumbnail as a "pinkynail" -- a tiny image to the left of the filename
+ jQuery('.thumbnail', item).clone().attr('class', 'pinkynail toggle').prependTo(item);
+
+ // Replace the original filename with the new (unique) one assigned during upload
+ jQuery('.filename.original', item).replaceWith( jQuery('.filename.new', item) );
+
+ // Bind AJAX to the new Delete button
+ jQuery('a.delete', item).click(function(){
+ // Tell the server to delete it. TODO: handle exceptions
+ jQuery.ajax({
+ url: ajaxurl,
+ type: 'post',
+ success: deleteSuccess,
+ error: deleteError,
+ id: fileObj.id,
+ data: {
+ id : this.id.replace(/[^0-9]/g, ''),
+ action : 'trash-post',
+ _ajax_nonce : this.href.replace(/^.*wpnonce=/,'')
+ }
+ });
+ return false;
+ });
+
+ // Bind AJAX to the new Undo button
+ jQuery('a.undo', item).click(function(){
+ // Tell the server to untrash it. TODO: handle exceptions
+ jQuery.ajax({
+ url: ajaxurl,
+ type: 'post',
+ id: fileObj.id,
+ data: {
+ id : this.id.replace(/[^0-9]/g,''),
+ action: 'untrash-post',
+ _ajax_nonce: this.href.replace(/^.*wpnonce=/,'')
+ },
+ success: function(data, textStatus){
+ var item = jQuery('#media-item-' + fileObj.id);
+
+ if ( type = jQuery('#type-of-' + fileObj.id).val() )
+ jQuery('#' + type + '-counter').text(jQuery('#' + type + '-counter').text()-0+1);
+
+ if ( post_id && item.hasClass('child-of-'+post_id) )
+ jQuery('#attachments-count').text(jQuery('#attachments-count').text()-0+1);
+
+ jQuery('.filename .trashnotice', item).remove();
+ jQuery('.filename .title', item).css('font-weight','normal');
+ jQuery('a.undo', item).addClass('hidden');
+ jQuery('.menu_order_input', item).show();
+ item.css( {backgroundColor:'#ceb'} ).animate( {backgroundColor: '#fff'}, { queue: false, duration: 500, complete: function(){ jQuery(this).css({backgroundColor:''}); } }).removeClass('undo');
+ }
+ });
+ return false;
+ });
+
+ // Open this item if it says to start open (e.g. to display an error)
+ jQuery('#media-item-' + fileObj.id + '.startopen').removeClass('startopen').addClass('open').find('slidetoggle').fadeIn();
+}
+
+// generic error message
+function wpQueueError(message) {
+ jQuery('#media-upload-error').show().html( '<div class="error"><p>' + message + '</p></div>' );
+}
+
+// file-specific error messages
+function wpFileError(fileObj, message) {
+ itemAjaxError(fileObj.id, message);
+}
+
+function itemAjaxError(id, message) {
+ var item = jQuery('#media-item-' + id), filename = item.find('.filename').text(), last_err = item.data('last-err');
+
+ if ( last_err == id ) // prevent firing an error for the same file twice
+ return;
+
+ item.html('<div class="error-div">'
+ + '<a class="dismiss" href="#">' + pluploadL10n.dismiss + '</a>'
+ + '<strong>' + pluploadL10n.error_uploading.replace('%s', jQuery.trim(filename)) + '</strong> '
+ + message
+ + '</div>').data('last-err', id);
+}
+
+function deleteSuccess(data, textStatus) {
+ if ( data == '-1' )
+ return itemAjaxError(this.id, 'You do not have permission. Has your session expired?');
+
+ if ( data == '0' )
+ return itemAjaxError(this.id, 'Could not be deleted. Has it been deleted already?');
+
+ var id = this.id, item = jQuery('#media-item-' + id);
+
+ // Decrement the counters.
+ if ( type = jQuery('#type-of-' + id).val() )
+ jQuery('#' + type + '-counter').text( jQuery('#' + type + '-counter').text() - 1 );
+
+ if ( post_id && item.hasClass('child-of-'+post_id) )
+ jQuery('#attachments-count').text( jQuery('#attachments-count').text() - 1 );
+
+ if ( jQuery('form.type-form #media-items').children().length == 1 && jQuery('.hidden', '#media-items').length > 0 ) {
+ jQuery('.toggle').toggle();
+ jQuery('.slidetoggle').slideUp(200).siblings().removeClass('hidden');
+ }
+
+ // Vanish it.
+ jQuery('.toggle', item).toggle();
+ jQuery('.slidetoggle', item).slideUp(200).siblings().removeClass('hidden');
+ item.css( {backgroundColor:'#faa'} ).animate( {backgroundColor:'#f4f4f4'}, {queue:false, duration:500} ).addClass('undo');
+
+ jQuery('.filename:empty', item).remove();
+ jQuery('.filename .title', item).css('font-weight','bold');
+ jQuery('.filename', item).append('<span class="trashnotice"> ' + pluploadL10n.deleted + ' </span>').siblings('a.toggle').hide();
+ jQuery('.filename', item).append( jQuery('a.undo', item).removeClass('hidden') );
+ jQuery('.menu_order_input', item).hide();
+
+ return;
+}
+
+function deleteError(X, textStatus, errorThrown) {
+ // TODO
+}
+
+function uploadComplete() {
+ jQuery('#insert-gallery').prop('disabled', false);
+}
+
+function switchUploader(s) {
+ if ( s ) {
+ deleteUserSetting('uploader');
+ jQuery('.media-upload-form').removeClass('html-uploader');
+
+ if ( typeof(uploader) == 'object' )
+ uploader.refresh();
+ } else {
+ setUserSetting('uploader', '1'); // 1 == html uploader
+ jQuery('.media-upload-form').addClass('html-uploader');
+ }
+}
+
+function dndHelper(s) {
+ var d = document.getElementById('dnd-helper');
+
+ if ( s ) {
+ d.style.display = 'block';
+ } else {
+ d.style.display = 'none';
+ }
+}
+
+function uploadError(fileObj, errorCode, message, uploader) {
+ var hundredmb = 100 * 1024 * 1024, max;
+
+ switch (errorCode) {
+ case plupload.FAILED:
+ wpFileError(fileObj, pluploadL10n.upload_failed);
+ break;
+ case plupload.FILE_EXTENSION_ERROR:
+ wpFileError(fileObj, pluploadL10n.invalid_filetype);
+ break;
+ case plupload.FILE_SIZE_ERROR:
+ uploadSizeError(uploader, fileObj);
+ break;
+ case plupload.IMAGE_FORMAT_ERROR:
+ wpFileError(fileObj, pluploadL10n.not_an_image);
+ break;
+ case plupload.IMAGE_MEMORY_ERROR:
+ wpFileError(fileObj, pluploadL10n.image_memory_exceeded);
+ break;
+ case plupload.IMAGE_DIMENSIONS_ERROR:
+ wpFileError(fileObj, pluploadL10n.image_dimensions_exceeded);
+ break;
+ case plupload.GENERIC_ERROR:
+ wpQueueError(pluploadL10n.upload_failed);
+ break;
+ case plupload.IO_ERROR:
+ max = parseInt(uploader.settings.max_file_size, 10);
+
+ if ( max > hundredmb && fileObj.size > hundredmb )
+ wpFileError(fileObj, pluploadL10n.big_upload_failed.replace('%1$s', '<a class="uploader-html" href="#">').replace('%2$s', '</a>'));
+ else
+ wpQueueError(pluploadL10n.io_error);
+ break;
+ case plupload.HTTP_ERROR:
+ wpQueueError(pluploadL10n.http_error);
+ break;
+ case plupload.INIT_ERROR:
+ jQuery('.media-upload-form').addClass('html-uploader');
+ break;
+ case plupload.SECURITY_ERROR:
+ wpQueueError(pluploadL10n.security_error);
+ break;
+/* case plupload.UPLOAD_ERROR.UPLOAD_STOPPED:
+ case plupload.UPLOAD_ERROR.FILE_CANCELLED:
+ jQuery('#media-item-' + fileObj.id).remove();
+ break;*/
+ default:
+ wpFileError(fileObj, pluploadL10n.default_error);
+ }
+}
+
+function uploadSizeError( up, file, over100mb ) {
+ var message;
+
+ if ( over100mb )
+ message = pluploadL10n.big_upload_queued.replace('%s', file.name) + ' ' + pluploadL10n.big_upload_failed.replace('%1$s', '<a class="uploader-html" href="#">').replace('%2$s', '</a>');
+ else
+ message = pluploadL10n.file_exceeds_size_limit.replace('%s', file.name);
+
+ jQuery('#media-items').append('<div id="media-item-' + file.id + '" class="media-item error"><p>' + message + '</p></div>');
+ up.removeFile(file);
+}
+
+jQuery(document).ready(function($){
+ $('.media-upload-form').bind('click.uploader', function(e) {
+ var target = $(e.target), tr, c;
+
+ if ( target.is('input[type="radio"]') ) { // remember the last used image size and alignment
+ tr = target.closest('tr');
+
+ if ( tr.hasClass('align') )
+ setUserSetting('align', target.val());
+ else if ( tr.hasClass('image-size') )
+ setUserSetting('imgsize', target.val());
+
+ } else if ( target.is('button.button') ) { // remember the last used image link url
+ c = e.target.className || '';
+ c = c.match(/url([^ '"]+)/);
+
+ if ( c && c[1] ) {
+ setUserSetting('urlbutton', c[1]);
+ target.siblings('.urlfield').val( target.data('link-url') );
+ }
+ } else if ( target.is('a.dismiss') ) {
+ target.parents('.media-item').fadeOut(200, function(){
+ $(this).remove();
+ });
+ } else if ( target.is('.upload-flash-bypass a') || target.is('a.uploader-html') ) { // switch uploader to html4
+ $('#media-items, p.submit, span.big-file-warning').css('display', 'none');
+ switchUploader(0);
+ e.preventDefault();
+ } else if ( target.is('.upload-html-bypass a') ) { // switch uploader to multi-file
+ $('#media-items, p.submit, span.big-file-warning').css('display', '');
+ switchUploader(1);
+ e.preventDefault();
+ } else if ( target.is('a.describe-toggle-on') ) { // Show
+ target.parent().addClass('open');
+ target.siblings('.slidetoggle').fadeIn(250, function(){
+ var S = $(window).scrollTop(), H = $(window).height(), top = $(this).offset().top, h = $(this).height(), b, B;
+
+ if ( H && top && h ) {
+ b = top + h;
+ B = S + H;
+
+ if ( b > B ) {
+ if ( b - B < top - S )
+ window.scrollBy(0, (b - B) + 10);
+ else
+ window.scrollBy(0, top - S - 40);
+ }
+ }
+ });
+ e.preventDefault();
+ } else if ( target.is('a.describe-toggle-off') ) { // Hide
+ target.siblings('.slidetoggle').fadeOut(250, function(){
+ target.parent().removeClass('open');
+ });
+ e.preventDefault();
+ }
+ });
+
+ // init and set the uploader
+ uploader_init = function() {
+ uploader = new plupload.Uploader(wpUploaderInit);
+
+ $('#image_resize').bind('change', function() {
+ var arg = $(this).prop('checked');
+
+ setResize( arg );
+
+ if ( arg )
+ setUserSetting('upload_resize', '1');
+ else
+ deleteUserSetting('upload_resize');
+ });
+
+ uploader.bind('Init', function(up) {
+ var uploaddiv = $('#plupload-upload-ui');
+
+ setResize( getUserSetting('upload_resize', false) );
+
+ if ( up.features.dragdrop && ! $(document.body).hasClass('mobile') ) {
+ uploaddiv.addClass('drag-drop');
+ $('#drag-drop-area').bind('dragover.wp-uploader', function(){ // dragenter doesn't fire right :(
+ uploaddiv.addClass('drag-over');
+ }).bind('dragleave.wp-uploader, drop.wp-uploader', function(){
+ uploaddiv.removeClass('drag-over');
+ });
+ } else {
+ uploaddiv.removeClass('drag-drop');
+ $('#drag-drop-area').unbind('.wp-uploader');
+ }
+
+ if ( up.runtime == 'html4' )
+ $('.upload-flash-bypass').hide();
+ });
+
+ uploader.init();
+
+ uploader.bind('FilesAdded', function(up, files) {
+ var hundredmb = 100 * 1024 * 1024, max = parseInt(up.settings.max_file_size, 10);
+
+ $('#media-upload-error').html('');
+ uploadStart();
+
+ plupload.each(files, function(file){
+ if ( max > hundredmb && file.size > hundredmb && up.runtime != 'html5' )
+ uploadSizeError( up, file, true );
+ else
+ fileQueued(file);
+ });
+
+ up.refresh();
+ up.start();
+ });
+
+ uploader.bind('BeforeUpload', function(up, file) {
+ // something
+ });
+
+ uploader.bind('UploadFile', function(up, file) {
+ fileUploading(up, file);
+ });
+
+ uploader.bind('UploadProgress', function(up, file) {
+ uploadProgress(up, file);
+ });
+
+ uploader.bind('Error', function(up, err) {
+ uploadError(err.file, err.code, err.message, up);
+ up.refresh();
+ });
+
+ uploader.bind('FileUploaded', function(up, file, response) {
+ uploadSuccess(file, response.response);
+ });
+
+ uploader.bind('UploadComplete', function(up, files) {
+ uploadComplete();
+ });
+ }
+
+ if ( typeof(wpUploaderInit) == 'object' )
+ uploader_init();
+
+});
diff --git a/src/wp-includes/js/plupload/license.txt b/src/wp-includes/js/plupload/license.txt
new file mode 100644
index 0000000000..d511905c16
--- /dev/null
+++ b/src/wp-includes/js/plupload/license.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/wp-includes/js/plupload/plupload.flash.js b/src/wp-includes/js/plupload/plupload.flash.js
new file mode 100644
index 0000000000..7d3f0087c8
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.flash.js
@@ -0,0 +1 @@
+(function(f,b,d,e){var a={},g={};function c(){var h;try{h=navigator.plugins["Shockwave Flash"];h=h.description}catch(j){try{h=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(i){h="0.0"}}h=h.match(/\d+/g);return parseFloat(h[0]+"."+h[1])}d.flash={trigger:function(j,h,i){setTimeout(function(){var m=a[j],l,k;if(m){m.trigger("Flash:"+h,i)}},0)}};d.runtimes.Flash=d.addRuntime("flash",{getFeatures:function(){return{jpgresize:true,pngresize:true,maxWidth:8091,maxHeight:8091,chunks:true,progress:true,multipart:true,multi_selection:true}},init:function(m,o){var k,l,h=0,i=b.body;if(c()<10){o({success:false});return}g[m.id]=false;a[m.id]=m;k=b.getElementById(m.settings.browse_button);l=b.createElement("div");l.id=m.id+"_flash_container";d.extend(l.style,{position:"absolute",top:"0px",background:m.settings.shim_bgcolor||"transparent",zIndex:99999,width:"100%",height:"100%"});l.className="plupload flash";if(m.settings.container){i=b.getElementById(m.settings.container);if(d.getStyle(i,"position")==="static"){i.style.position="relative"}}i.appendChild(l);(function(){var p,q;p='<object id="'+m.id+'_flash" type="application/x-shockwave-flash" data="'+m.settings.flash_swf_url+'" ';if(d.ua.ie){p+='classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '}p+='width="100%" height="100%" style="outline:0"><param name="movie" value="'+m.settings.flash_swf_url+'" /><param name="flashvars" value="id='+escape(m.id)+'" /><param name="wmode" value="transparent" /><param name="allowscriptaccess" value="always" /></object>';if(d.ua.ie){q=b.createElement("div");l.appendChild(q);q.outerHTML=p;q=null}else{l.innerHTML=p}}());function n(){return b.getElementById(m.id+"_flash")}function j(){if(h++>5000){o({success:false});return}if(g[m.id]===false){setTimeout(j,1)}}j();k=l=null;m.bind("Destroy",function(p){var q;d.removeAllEvents(b.body,p.id);delete g[p.id];delete a[p.id];q=b.getElementById(p.id+"_flash_container");if(q){q.parentNode.removeChild(q)}});m.bind("Flash:Init",function(){var r={},q;try{n().setFileFilters(m.settings.filters,m.settings.multi_selection)}catch(p){o({success:false});return}if(g[m.id]){return}g[m.id]=true;m.bind("UploadFile",function(s,u){var v=s.settings,t=m.settings.resize||{};n().uploadFile(r[u.id],v.url,{name:u.target_name||u.name,mime:d.mimeTypes[u.name.replace(/^.+\.([^.]+)/,"$1").toLowerCase()]||"application/octet-stream",chunk_size:v.chunk_size,width:t.width,height:t.height,quality:t.quality,multipart:v.multipart,multipart_params:v.multipart_params||{},file_data_name:v.file_data_name,format:/\.(jpg|jpeg)$/i.test(u.name)?"jpg":"png",headers:v.headers,urlstream_upload:v.urlstream_upload})});m.bind("CancelUpload",function(){n().cancelUpload()});m.bind("Flash:UploadProcess",function(t,s){var u=t.getFile(r[s.id]);if(u.status!=d.FAILED){u.loaded=s.loaded;u.size=s.size;t.trigger("UploadProgress",u)}});m.bind("Flash:UploadChunkComplete",function(s,u){var v,t=s.getFile(r[u.id]);v={chunk:u.chunk,chunks:u.chunks,response:u.text};s.trigger("ChunkUploaded",t,v);if(t.status!==d.FAILED&&s.state!==d.STOPPED){n().uploadNextChunk()}if(u.chunk==u.chunks-1){t.status=d.DONE;s.trigger("FileUploaded",t,{response:u.text})}});m.bind("Flash:SelectFiles",function(s,v){var u,t,w=[],x;for(t=0;t<v.length;t++){u=v[t];x=d.guid();r[x]=u.id;r[u.id]=x;w.push(new d.File(x,u.name,u.size))}if(w.length){m.trigger("FilesAdded",w)}});m.bind("Flash:SecurityError",function(s,t){m.trigger("Error",{code:d.SECURITY_ERROR,message:d.translate("Security error."),details:t.message,file:m.getFile(r[t.id])})});m.bind("Flash:GenericError",function(s,t){m.trigger("Error",{code:d.GENERIC_ERROR,message:d.translate("Generic error."),details:t.message,file:m.getFile(r[t.id])})});m.bind("Flash:IOError",function(s,t){m.trigger("Error",{code:d.IO_ERROR,message:d.translate("IO error."),details:t.message,file:m.getFile(r[t.id])})});m.bind("Flash:ImageError",function(s,t){m.trigger("Error",{code:parseInt(t.code,10),message:d.translate("Image error."),file:m.getFile(r[t.id])})});m.bind("Flash:StageEvent:rollOver",function(s){var t,u;t=b.getElementById(m.settings.browse_button);u=s.settings.browse_button_hover;if(t&&u){d.addClass(t,u)}});m.bind("Flash:StageEvent:rollOut",function(s){var t,u;t=b.getElementById(m.settings.browse_button);u=s.settings.browse_button_hover;if(t&&u){d.removeClass(t,u)}});m.bind("Flash:StageEvent:mouseDown",function(s){var t,u;t=b.getElementById(m.settings.browse_button);u=s.settings.browse_button_active;if(t&&u){d.addClass(t,u);d.addEvent(b.body,"mouseup",function(){d.removeClass(t,u)},s.id)}});m.bind("Flash:StageEvent:mouseUp",function(s){var t,u;t=b.getElementById(m.settings.browse_button);u=s.settings.browse_button_active;if(t&&u){d.removeClass(t,u)}});m.bind("Flash:ExifData",function(s,t){m.trigger("ExifData",m.getFile(r[t.id]),t.data)});m.bind("Flash:GpsData",function(s,t){m.trigger("GpsData",m.getFile(r[t.id]),t.data)});m.bind("QueueChanged",function(s){m.refresh()});m.bind("FilesRemoved",function(s,u){var t;for(t=0;t<u.length;t++){n().removeFile(r[u[t].id])}});m.bind("StateChanged",function(s){m.refresh()});m.bind("Refresh",function(s){var t,u,v;n().setFileFilters(m.settings.filters,m.settings.multi_selection);t=b.getElementById(s.settings.browse_button);if(t){u=d.getPos(t,b.getElementById(s.settings.container));v=d.getSize(t);d.extend(b.getElementById(s.id+"_flash_container").style,{top:u.y+"px",left:u.x+"px",width:v.w+"px",height:v.h+"px"})}});m.bind("DisableBrowse",function(s,t){n().disableBrowse(t)});o({success:true})})}})})(window,document,plupload); \ No newline at end of file
diff --git a/src/wp-includes/js/plupload/plupload.flash.swf b/src/wp-includes/js/plupload/plupload.flash.swf
new file mode 100644
index 0000000000..416b08fed1
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.flash.swf
Binary files differ
diff --git a/src/wp-includes/js/plupload/plupload.html4.js b/src/wp-includes/js/plupload/plupload.html4.js
new file mode 100644
index 0000000000..0a8f4033e3
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.html4.js
@@ -0,0 +1 @@
+(function(d,a,b,c){function e(f){return a.getElementById(f)}b.runtimes.Html4=b.addRuntime("html4",{getFeatures:function(){return{multipart:true,triggerDialog:(b.ua.gecko&&d.FormData||b.ua.webkit)}},init:function(f,g){f.bind("Init",function(p){var j=a.body,n,h="javascript",k,x,q,z=[],r=/MSIE/.test(navigator.userAgent),t=[],m=p.settings.filters,o,l,s,w;no_type_restriction:for(o=0;o<m.length;o++){l=m[o].extensions.split(/,/);for(w=0;w<l.length;w++){if(l[w]==="*"){t=[];break no_type_restriction}s=b.mimeTypes[l[w]];if(s&&b.inArray(s,t)===-1){t.push(s)}}}t=t.join(",");function v(){var B,y,i,A;q=b.guid();z.push(q);B=a.createElement("form");B.setAttribute("id","form_"+q);B.setAttribute("method","post");B.setAttribute("enctype","multipart/form-data");B.setAttribute("encoding","multipart/form-data");B.setAttribute("target",p.id+"_iframe");B.style.position="absolute";y=a.createElement("input");y.setAttribute("id","input_"+q);y.setAttribute("type","file");y.setAttribute("accept",t);y.setAttribute("size",1);A=e(p.settings.browse_button);if(p.features.triggerDialog&&A){b.addEvent(e(p.settings.browse_button),"click",function(C){if(!y.disabled){y.click()}C.preventDefault()},p.id)}b.extend(y.style,{width:"100%",height:"100%",opacity:0,fontSize:"99px",cursor:"pointer"});b.extend(B.style,{overflow:"hidden"});i=p.settings.shim_bgcolor;if(i){B.style.background=i}if(r){b.extend(y.style,{filter:"alpha(opacity=0)"})}b.addEvent(y,"change",function(F){var D=F.target,C,E=[],G;if(D.value){e("form_"+q).style.top=-1048575+"px";C=D.value.replace(/\\/g,"/");C=C.substring(C.length,C.lastIndexOf("/")+1);E.push(new b.File(q,C));if(!p.features.triggerDialog){b.removeAllEvents(B,p.id)}else{b.removeEvent(A,"click",p.id)}b.removeEvent(y,"change",p.id);v();if(E.length){f.trigger("FilesAdded",E)}}},p.id);B.appendChild(y);j.appendChild(B);p.refresh()}function u(){var i=a.createElement("div");i.innerHTML='<iframe id="'+p.id+'_iframe" name="'+p.id+'_iframe" src="'+h+':&quot;&quot;" style="display:none"></iframe>';n=i.firstChild;j.appendChild(n);b.addEvent(n,"load",function(C){var D=C.target,B,y;if(!k){return}try{B=D.contentWindow.document||D.contentDocument||d.frames[D.id].document}catch(A){p.trigger("Error",{code:b.SECURITY_ERROR,message:b.translate("Security error."),file:k});return}y=B.documentElement.innerText||B.documentElement.textContent;if(y){k.status=b.DONE;k.loaded=1025;k.percent=100;p.trigger("UploadProgress",k);p.trigger("FileUploaded",k,{response:y})}},p.id)}if(p.settings.container){j=e(p.settings.container);if(b.getStyle(j,"position")==="static"){j.style.position="relative"}}p.bind("UploadFile",function(i,A){var B,y;if(A.status==b.DONE||A.status==b.FAILED||i.state==b.STOPPED){return}B=e("form_"+A.id);y=e("input_"+A.id);y.setAttribute("name",i.settings.file_data_name);B.setAttribute("action",i.settings.url);b.each(b.extend({name:A.target_name||A.name},i.settings.multipart_params),function(E,C){var D=a.createElement("input");b.extend(D,{type:"hidden",name:C,value:E});B.insertBefore(D,B.firstChild)});k=A;e("form_"+q).style.top=-1048575+"px";B.submit()});p.bind("FileUploaded",function(i){i.refresh()});p.bind("StateChanged",function(i){if(i.state==b.STARTED){u()}else{if(i.state==b.STOPPED){d.setTimeout(function(){b.removeEvent(n,"load",i.id);if(n.parentNode){n.parentNode.removeChild(n)}},0)}}b.each(i.files,function(A,y){if(A.status===b.DONE||A.status===b.FAILED){var B=e("form_"+A.id);if(B){B.parentNode.removeChild(B)}}})});p.bind("Refresh",function(y){var F,A,B,C,i,G,H,E,D;F=e(y.settings.browse_button);if(F){i=b.getPos(F,e(y.settings.container));G=b.getSize(F);H=e("form_"+q);E=e("input_"+q);b.extend(H.style,{top:i.y+"px",left:i.x+"px",width:G.w+"px",height:G.h+"px"});if(y.features.triggerDialog){if(b.getStyle(F,"position")==="static"){b.extend(F.style,{position:"relative"})}D=parseInt(F.style.zIndex,10);if(isNaN(D)){D=0}b.extend(F.style,{zIndex:D});b.extend(H.style,{zIndex:D-1})}B=y.settings.browse_button_hover;C=y.settings.browse_button_active;A=y.features.triggerDialog?F:H;if(B){b.addEvent(A,"mouseover",function(){b.addClass(F,B)},y.id);b.addEvent(A,"mouseout",function(){b.removeClass(F,B)},y.id)}if(C){b.addEvent(A,"mousedown",function(){b.addClass(F,C)},y.id);b.addEvent(a.body,"mouseup",function(){b.removeClass(F,C)},y.id)}}});f.bind("FilesRemoved",function(y,B){var A,C;for(A=0;A<B.length;A++){C=e("form_"+B[A].id);if(C){C.parentNode.removeChild(C)}}});f.bind("DisableBrowse",function(i,A){var y=a.getElementById("input_"+q);if(y){y.disabled=A}});f.bind("Destroy",function(i){var y,A,B,C={inputContainer:"form_"+q,inputFile:"input_"+q,browseButton:i.settings.browse_button};for(y in C){A=e(C[y]);if(A){b.removeAllEvents(A,i.id)}}b.removeAllEvents(a.body,i.id);b.each(z,function(E,D){B=e("form_"+E);if(B){B.parentNode.removeChild(B)}})});v()});g({success:true})}})})(window,document,plupload); \ No newline at end of file
diff --git a/src/wp-includes/js/plupload/plupload.html5.js b/src/wp-includes/js/plupload/plupload.html5.js
new file mode 100644
index 0000000000..a4b2a1fc0a
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.html5.js
@@ -0,0 +1 @@
+(function(k,m,l,g){var d={},j;function c(s){var r=s.naturalWidth,u=s.naturalHeight;if(r*u>1024*1024){var t=m.createElement("canvas");t.width=t.height=1;var q=t.getContext("2d");q.drawImage(s,-r+1,0);return q.getImageData(0,0,1,1).data[3]===0}else{return false}}function f(u,r,z){var q=m.createElement("canvas");q.width=1;q.height=z;var A=q.getContext("2d");A.drawImage(u,0,0);var t=A.getImageData(0,0,1,z).data;var x=0;var v=z;var y=z;while(y>x){var s=t[(y-1)*4+3];if(s===0){v=y}else{x=y}y=(v+x)>>1}var w=(y/z);return(w===0)?1:w}function o(K,s,t){var v=K.naturalWidth,z=K.naturalHeight;var E=t.width,B=t.height;var F=s.getContext("2d");F.save();var r=c(K);if(r){v/=2;z/=2}var I=1024;var q=m.createElement("canvas");q.width=q.height=I;var u=q.getContext("2d");var G=f(K,v,z);var A=0;while(A<z){var J=A+I>z?z-A:I;var C=0;while(C<v){var D=C+I>v?v-C:I;u.clearRect(0,0,I,I);u.drawImage(K,-C,-A);var x=(C*E/v)<<0;var y=Math.ceil(D*E/v);var w=(A*B/z/G)<<0;var H=Math.ceil(J*B/z/G);F.drawImage(q,0,0,D,J,x,w,y,H);C+=I}A+=I}F.restore();q=u=null}function p(r,s){var q;if("FileReader" in k){q=new FileReader();q.readAsDataURL(r);q.onload=function(){s(q.result)}}else{return s(r.getAsDataURL())}}function n(r,s){var q;if("FileReader" in k){q=new FileReader();q.readAsBinaryString(r);q.onload=function(){s(q.result)}}else{return s(r.getAsBinary())}}function e(u,s,q,y){var t,r,x,v,w=this;p(d[u.id],function(z){t=m.createElement("canvas");t.style.display="none";m.body.appendChild(t);x=new Image();x.onerror=x.onabort=function(){y({success:false})};x.onload=function(){var F,A,C,B,E;if(!s.width){s.width=x.width}if(!s.height){s.height=x.height}v=Math.min(s.width/x.width,s.height/x.height);if(v<1){F=Math.round(x.width*v);A=Math.round(x.height*v)}else{if(s.quality&&q==="image/jpeg"){F=x.width;A=x.height}else{y({success:false});return}}t.width=F;t.height=A;o(x,t,{width:F,height:A});if(q==="image/jpeg"){B=new h(atob(z.substring(z.indexOf("base64,")+7)));if(B.headers&&B.headers.length){E=new a();if(E.init(B.get("exif")[0])){E.setExif("PixelXDimension",F);E.setExif("PixelYDimension",A);B.set("exif",E.getBinary());if(w.hasEventListener("ExifData")){w.trigger("ExifData",u,E.EXIF())}if(w.hasEventListener("GpsData")){w.trigger("GpsData",u,E.GPS())}}}}if(s.quality&&q==="image/jpeg"){try{z=t.toDataURL(q,s.quality/100)}catch(D){z=t.toDataURL(q)}}else{z=t.toDataURL(q)}z=z.substring(z.indexOf("base64,")+7);z=atob(z);if(B&&B.headers&&B.headers.length){z=B.restore(z);B.purge()}t.parentNode.removeChild(t);y({success:true,data:z})};x.src=z})}l.runtimes.Html5=l.addRuntime("html5",{getFeatures:function(){var v,r,u,t,s,q;r=u=s=q=false;if(k.XMLHttpRequest){v=new XMLHttpRequest();u=!!v.upload;r=!!(v.sendAsBinary||v.upload)}if(r){t=!!(v.sendAsBinary||(k.Uint8Array&&k.ArrayBuffer));s=!!(File&&(File.prototype.getAsDataURL||k.FileReader)&&t);q=!!(File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice))}j=l.ua.safari&&l.ua.windows;return{html5:r,dragdrop:(function(){var w=m.createElement("div");return("draggable" in w)||("ondragstart" in w&&"ondrop" in w)}()),jpgresize:s,pngresize:s,multipart:s||!!k.FileReader||!!k.FormData,canSendBinary:t,cantSendBlobInFormData:!!(l.ua.gecko&&k.FormData&&k.FileReader&&!FileReader.prototype.readAsArrayBuffer)||l.ua.android,progress:u,chunks:q,multi_selection:!(l.ua.safari&&l.ua.windows),triggerDialog:(l.ua.gecko&&k.FormData||l.ua.webkit)}},init:function(s,u){var q,t;function r(z){var x,w,y=[],A,v={};for(w=0;w<z.length;w++){x=z[w];if(v[x.name]&&l.ua.safari&&l.ua.windows){continue}v[x.name]=true;A=l.guid();d[A]=x;y.push(new l.File(A,x.fileName||x.name,x.fileSize||x.size))}if(y.length){s.trigger("FilesAdded",y)}}q=this.getFeatures();if(!q.html5){u({success:false});return}s.bind("Init",function(A){var J,I,F=[],z,G,w=A.settings.filters,x,E,v=m.body,H;J=m.createElement("div");J.id=A.id+"_html5_container";l.extend(J.style,{position:"absolute",background:s.settings.shim_bgcolor||"transparent",width:"100px",height:"100px",overflow:"hidden",zIndex:99999,opacity:s.settings.shim_bgcolor?"":0});J.className="plupload html5";if(s.settings.container){v=m.getElementById(s.settings.container);if(l.getStyle(v,"position")==="static"){v.style.position="relative"}}v.appendChild(J);no_type_restriction:for(z=0;z<w.length;z++){x=w[z].extensions.split(/,/);for(G=0;G<x.length;G++){if(x[G]==="*"){F=[];break no_type_restriction}E=l.mimeTypes[x[G]];if(E&&l.inArray(E,F)===-1){F.push(E)}}}J.innerHTML='<input id="'+s.id+'_html5" style="font-size:999px" type="file" accept="'+F.join(",")+'" '+(s.settings.multi_selection&&s.features.multi_selection?'multiple="multiple"':"")+" />";J.scrollTop=100;H=m.getElementById(s.id+"_html5");if(A.features.triggerDialog){l.extend(H.style,{position:"absolute",width:"100%",height:"100%"})}else{l.extend(H.style,{cssFloat:"right",styleFloat:"right"})}H.onchange=function(){r(this.files);this.value=""};I=m.getElementById(A.settings.browse_button);if(I){var C=A.settings.browse_button_hover,D=A.settings.browse_button_active,B=A.features.triggerDialog?I:J;if(C){l.addEvent(B,"mouseover",function(){l.addClass(I,C)},A.id);l.addEvent(B,"mouseout",function(){l.removeClass(I,C)},A.id)}if(D){l.addEvent(B,"mousedown",function(){l.addClass(I,D)},A.id);l.addEvent(m.body,"mouseup",function(){l.removeClass(I,D)},A.id)}if(A.features.triggerDialog){l.addEvent(I,"click",function(K){var y=m.getElementById(A.id+"_html5");if(y&&!y.disabled){y.click()}K.preventDefault()},A.id)}}});s.bind("PostInit",function(){var v=m.getElementById(s.settings.drop_element);if(v){if(j){l.addEvent(v,"dragenter",function(z){var y,w,x;y=m.getElementById(s.id+"_drop");if(!y){y=m.createElement("input");y.setAttribute("type","file");y.setAttribute("id",s.id+"_drop");y.setAttribute("multiple","multiple");l.addEvent(y,"change",function(){r(this.files);l.removeEvent(y,"change",s.id);y.parentNode.removeChild(y)},s.id);l.addEvent(y,"dragover",function(A){A.stopPropagation()},s.id);v.appendChild(y)}w=l.getPos(v,m.getElementById(s.settings.container));x=l.getSize(v);if(l.getStyle(v,"position")==="static"){l.extend(v.style,{position:"relative"})}l.extend(y.style,{position:"absolute",display:"block",top:0,left:0,width:x.w+"px",height:x.h+"px",opacity:0})},s.id);return}l.addEvent(v,"dragover",function(w){w.preventDefault()},s.id);l.addEvent(v,"drop",function(x){var w=x.dataTransfer;if(w&&w.files){r(w.files)}x.preventDefault()},s.id)}});s.bind("Refresh",function(v){var w,x,y,A,z;w=m.getElementById(s.settings.browse_button);if(w){x=l.getPos(w,m.getElementById(v.settings.container));y=l.getSize(w);A=m.getElementById(s.id+"_html5_container");l.extend(A.style,{top:x.y+"px",left:x.x+"px",width:y.w+"px",height:y.h+"px"});if(s.features.triggerDialog){if(l.getStyle(w,"position")==="static"){l.extend(w.style,{position:"relative"})}z=parseInt(l.getStyle(w,"zIndex"),10);if(isNaN(z)){z=0}l.extend(w.style,{zIndex:z});l.extend(A.style,{zIndex:z-1})}}});s.bind("DisableBrowse",function(v,x){var w=m.getElementById(v.id+"_html5");if(w){w.disabled=x}});s.bind("CancelUpload",function(){if(t&&t.abort){t.abort()}});s.bind("UploadFile",function(v,x){var y=v.settings,B,w;function A(D,G,C){var E;if(File.prototype.slice){try{D.slice();return D.slice(G,C)}catch(F){return D.slice(G,C-G)}}else{if(E=File.prototype.webkitSlice||File.prototype.mozSlice){return E.call(D,G,C)}else{return null}}}function z(C){var F=0,E=0;function D(){var L,P,N,O,K,M,H,G=v.settings.url;function J(S){if(t.sendAsBinary){t.sendAsBinary(S)}else{if(v.features.canSendBinary){var Q=new Uint8Array(S.length);for(var R=0;R<S.length;R++){Q[R]=(S.charCodeAt(R)&255)}t.send(Q.buffer)}}}function I(R){var V=0,W="----pluploadboundary"+l.guid(),T,S="--",U="\r\n",Q="";t=new XMLHttpRequest;if(t.upload){t.upload.onprogress=function(X){x.loaded=Math.min(x.size,E+X.loaded-V);v.trigger("UploadProgress",x)}}t.onreadystatechange=function(){var X,Z;if(t.readyState==4&&v.state!==l.STOPPED){try{X=t.status}catch(Y){X=0}if(X>=400){v.trigger("Error",{code:l.HTTP_ERROR,message:l.translate("HTTP Error."),file:x,status:X})}else{if(N){Z={chunk:F,chunks:N,response:t.responseText,status:X};v.trigger("ChunkUploaded",x,Z);E+=M;if(Z.cancelled){x.status=l.FAILED;return}x.loaded=Math.min(x.size,(F+1)*K)}else{x.loaded=x.size}v.trigger("UploadProgress",x);R=L=T=Q=null;if(!N||++F>=N){x.status=l.DONE;v.trigger("FileUploaded",x,{response:t.responseText,status:X})}else{D()}}}};if(v.settings.multipart&&q.multipart){O.name=x.target_name||x.name;t.open("post",G,true);l.each(v.settings.headers,function(Y,X){t.setRequestHeader(X,Y)});if(typeof(R)!=="string"&&!!k.FormData){T=new FormData();l.each(l.extend(O,v.settings.multipart_params),function(Y,X){T.append(X,Y)});T.append(v.settings.file_data_name,R);t.send(T);return}if(typeof(R)==="string"){t.setRequestHeader("Content-Type","multipart/form-data; boundary="+W);l.each(l.extend(O,v.settings.multipart_params),function(Y,X){Q+=S+W+U+'Content-Disposition: form-data; name="'+X+'"'+U+U;Q+=unescape(encodeURIComponent(Y))+U});H=l.mimeTypes[x.name.replace(/^.+\.([^.]+)/,"$1").toLowerCase()]||"application/octet-stream";Q+=S+W+U+'Content-Disposition: form-data; name="'+v.settings.file_data_name+'"; filename="'+unescape(encodeURIComponent(x.name))+'"'+U+"Content-Type: "+H+U+U+R+U+S+W+S+U;V=Q.length-R.length;R=Q;J(R);return}}G=l.buildUrl(v.settings.url,l.extend(O,v.settings.multipart_params));t.open("post",G,true);t.setRequestHeader("Content-Type","application/octet-stream");l.each(v.settings.headers,function(Y,X){t.setRequestHeader(X,Y)});if(typeof(R)==="string"){J(R)}else{t.send(R)}}if(x.status==l.DONE||x.status==l.FAILED||v.state==l.STOPPED){return}O={name:x.target_name||x.name};if(y.chunk_size&&x.size>y.chunk_size&&(q.chunks||typeof(C)=="string")){K=y.chunk_size;N=Math.ceil(x.size/K);M=Math.min(K,x.size-(F*K));if(typeof(C)=="string"){L=C.substring(F*K,F*K+M)}else{L=A(C,F*K,F*K+M)}O.chunk=F;O.chunks=N}else{M=x.size;L=C}if(v.settings.multipart&&q.multipart&&typeof(L)!=="string"&&k.FileReader&&q.cantSendBlobInFormData&&q.chunks&&v.settings.chunk_size){(function(){var Q=new FileReader();Q.onload=function(){I(Q.result);Q=null};Q.readAsBinaryString(L)}())}else{I(L)}}D()}B=d[x.id];if(q.jpgresize&&v.settings.resize&&/\.(png|jpg|jpeg)$/i.test(x.name)){e.call(v,x,v.settings.resize,/\.png$/i.test(x.name)?"image/png":"image/jpeg",function(C){if(C.success){x.size=C.data.length;z(C.data)}else{if(q.chunks){z(B)}else{n(B,z)}}})}else{if(!q.chunks&&q.jpgresize){n(B,z)}else{z(B)}}});s.bind("Destroy",function(v){var x,y,w=m.body,z={inputContainer:v.id+"_html5_container",inputFile:v.id+"_html5",browseButton:v.settings.browse_button,dropElm:v.settings.drop_element};for(x in z){y=m.getElementById(z[x]);if(y){l.removeAllEvents(y,v.id)}}l.removeAllEvents(m.body,v.id);if(v.settings.container){w=m.getElementById(v.settings.container)}w.removeChild(m.getElementById(z.inputContainer))});u({success:true})}});function b(){var t=false,r;function u(w,y){var v=t?0:-8*(y-1),z=0,x;for(x=0;x<y;x++){z|=(r.charCodeAt(w+x)<<Math.abs(v+x*8))}return z}function q(x,v,w){var w=arguments.length===3?w:r.length-v-1;r=r.substr(0,v)+x+r.substr(w+v)}function s(w,x,z){var A="",v=t?0:-8*(z-1),y;for(y=0;y<z;y++){A+=String.fromCharCode((x>>Math.abs(v+y*8))&255)}q(A,w,z)}return{II:function(v){if(v===g){return t}else{t=v}},init:function(v){t=false;r=v},SEGMENT:function(v,x,w){switch(arguments.length){case 1:return r.substr(v,r.length-v-1);case 2:return r.substr(v,x);case 3:q(w,v,x);break;default:return r}},BYTE:function(v){return u(v,1)},SHORT:function(v){return u(v,2)},LONG:function(v,w){if(w===g){return u(v,4)}else{s(v,w,4)}},SLONG:function(v){var w=u(v,4);return(w>2147483647?w-4294967296:w)},STRING:function(v,w){var x="";for(w+=v;v<w;v++){x+=String.fromCharCode(u(v,1))}return x}}}function h(v){var x={65505:{app:"EXIF",name:"APP1",signature:"Exif\0"},65506:{app:"ICC",name:"APP2",signature:"ICC_PROFILE\0"},65517:{app:"IPTC",name:"APP13",signature:"Photoshop 3.0\0"}},w=[],u,q,s=g,t=0,r;u=new b();u.init(v);if(u.SHORT(0)!==65496){return}q=2;r=Math.min(1048576,v.length);while(q<=r){s=u.SHORT(q);if(s>=65488&&s<=65495){q+=2;continue}if(s===65498||s===65497){break}t=u.SHORT(q+2)+2;if(x[s]&&u.STRING(q+4,x[s].signature.length)===x[s].signature){w.push({hex:s,app:x[s].app.toUpperCase(),name:x[s].name.toUpperCase(),start:q,length:t,segment:u.SEGMENT(q,t)})}q+=t}u.init(null);return{headers:w,restore:function(B){u.init(B);var z=new h(B);if(!z.headers){return false}for(var A=z.headers.length;A>0;A--){var C=z.headers[A-1];u.SEGMENT(C.start,C.length,"")}z.purge();q=u.SHORT(2)==65504?4+u.SHORT(4):2;for(var A=0,y=w.length;A<y;A++){u.SEGMENT(q,0,w[A].segment);q+=w[A].length}return u.SEGMENT()},get:function(A){var B=[];for(var z=0,y=w.length;z<y;z++){if(w[z].app===A.toUpperCase()){B.push(w[z].segment)}}return B},set:function(B,A){var C=[];if(typeof(A)==="string"){C.push(A)}else{C=A}for(var z=ii=0,y=w.length;z<y;z++){if(w[z].app===B.toUpperCase()){w[z].segment=C[ii];w[z].length=C[ii].length;ii++}if(ii>=C.length){break}}},purge:function(){w=[];u.init(null)}}}function a(){var t,q,r={},w;t=new b();q={tiff:{274:"Orientation",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"}};w={ColorSpace:{1:"sRGB",0:"Uncalibrated"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{1:"Daylight",2:"Fliorescent",3:"Tungsten",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 -5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire.",1:"Flash fired.",5:"Strobe return light not detected.",7:"Strobe return light detected.",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},ExposureMode:{0:"Auto exposure",1:"Manual exposure",2:"Auto bracket"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}};function s(x,F){var z=t.SHORT(x),C,I,J,E,D,y,A,G,H=[],B={};for(C=0;C<z;C++){A=y=x+12*C+2;J=F[t.SHORT(A)];if(J===g){continue}E=t.SHORT(A+=2);D=t.LONG(A+=2);A+=4;H=[];switch(E){case 1:case 7:if(D>4){A=t.LONG(A)+r.tiffHeader}for(I=0;I<D;I++){H[I]=t.BYTE(A+I)}break;case 2:if(D>4){A=t.LONG(A)+r.tiffHeader}B[J]=t.STRING(A,D-1);continue;case 3:if(D>2){A=t.LONG(A)+r.tiffHeader}for(I=0;I<D;I++){H[I]=t.SHORT(A+I*2)}break;case 4:if(D>1){A=t.LONG(A)+r.tiffHeader}for(I=0;I<D;I++){H[I]=t.LONG(A+I*4)}break;case 5:A=t.LONG(A)+r.tiffHeader;for(I=0;I<D;I++){H[I]=t.LONG(A+I*4)/t.LONG(A+I*4+4)}break;case 9:A=t.LONG(A)+r.tiffHeader;for(I=0;I<D;I++){H[I]=t.SLONG(A+I*4)}break;case 10:A=t.LONG(A)+r.tiffHeader;for(I=0;I<D;I++){H[I]=t.SLONG(A+I*4)/t.SLONG(A+I*4+4)}break;default:continue}G=(D==1?H[0]:H);if(w.hasOwnProperty(J)&&typeof G!="object"){B[J]=w[J][G]}else{B[J]=G}}return B}function v(){var y=g,x=r.tiffHeader;t.II(t.SHORT(x)==18761);if(t.SHORT(x+=2)!==42){return false}r.IFD0=r.tiffHeader+t.LONG(x+=2);y=s(r.IFD0,q.tiff);r.exifIFD=("ExifIFDPointer" in y?r.tiffHeader+y.ExifIFDPointer:g);r.gpsIFD=("GPSInfoIFDPointer" in y?r.tiffHeader+y.GPSInfoIFDPointer:g);return true}function u(z,x,C){var E,B,A,D=0;if(typeof(x)==="string"){var y=q[z.toLowerCase()];for(hex in y){if(y[hex]===x){x=hex;break}}}E=r[z.toLowerCase()+"IFD"];B=t.SHORT(E);for(i=0;i<B;i++){A=E+12*i+2;if(t.SHORT(A)==x){D=A+8;break}}if(!D){return false}t.LONG(D,C);return true}return{init:function(x){r={tiffHeader:10};if(x===g||!x.length){return false}t.init(x);if(t.SHORT(0)===65505&&t.STRING(4,5).toUpperCase()==="EXIF\0"){return v()}return false},EXIF:function(){var y;y=s(r.exifIFD,q.exif);if(y.ExifVersion&&l.typeOf(y.ExifVersion)==="array"){for(var z=0,x="";z<y.ExifVersion.length;z++){x+=String.fromCharCode(y.ExifVersion[z])}y.ExifVersion=x}return y},GPS:function(){var x;x=s(r.gpsIFD,q.gps);if(x.GPSVersionID){x.GPSVersionID=x.GPSVersionID.join(".")}return x},setExif:function(x,y){if(x!=="PixelXDimension"&&x!=="PixelYDimension"){return false}return u("exif",x,y)},getBinary:function(){return t.SEGMENT()}}}})(window,document,plupload); \ No newline at end of file
diff --git a/src/wp-includes/js/plupload/plupload.js b/src/wp-includes/js/plupload/plupload.js
new file mode 100644
index 0000000000..5b3ffb7161
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.js
@@ -0,0 +1,2 @@
+/*1.5.7*/
+(function(){var f=0,k=[],m={},i={},a={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},l=/[<>&\"\']/g,b,c=window.setTimeout,d={},e;function h(){this.returnValue=false}function j(){this.cancelBubble=true}(function(n){var o=n.split(/,/),p,r,q;for(p=0;p<o.length;p+=2){q=o[p+1].split(/ /);for(r=0;r<q.length;r++){i[q[r]]=o[p]}}})("application/msword,doc dot,application/pdf,pdf,application/pgp-signature,pgp,application/postscript,ps ai eps,application/rtf,rtf,application/vnd.ms-excel,xls xlb,application/vnd.ms-powerpoint,ppt pps pot,application/zip,zip,application/x-shockwave-flash,swf swfl,application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx,application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx,application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx,application/vnd.openxmlformats-officedocument.presentationml.template,potx,application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx,application/x-javascript,js,application/json,json,audio/mpeg,mpga mpega mp2 mp3,audio/x-wav,wav,audio/mp4,m4a,image/bmp,bmp,image/gif,gif,image/jpeg,jpeg jpg jpe,image/photoshop,psd,image/png,png,image/svg+xml,svg svgz,image/tiff,tiff tif,text/plain,asc txt text diff log,text/html,htm html xhtml,text/css,css,text/csv,csv,text/rtf,rtf,video/mpeg,mpeg mpg mpe m2v,video/quicktime,qt mov,video/mp4,mp4,video/x-m4v,m4v,video/x-flv,flv,video/x-ms-wmv,wmv,video/avi,avi,video/webm,webm,video/3gpp,3gp,video/3gpp2,3g2,video/vnd.rn-realvideo,rv,application/vnd.oasis.opendocument.formula-template,otf,application/octet-stream,exe");var g={VERSION:"1.5.7",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,IMAGE_FORMAT_ERROR:-700,IMAGE_MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,mimeTypes:i,ua:(function(){var r=navigator,q=r.userAgent,s=r.vendor,o,n,p;o=/WebKit/.test(q);p=o&&s.indexOf("Apple")!==-1;n=window.opera&&window.opera.buildNumber;return{windows:navigator.platform.indexOf("Win")!==-1,android:/Android/.test(q),ie:!o&&!n&&(/MSIE/gi).test(q)&&(/Explorer/gi).test(r.appName),webkit:o,gecko:!o&&/Gecko/.test(q),safari:p,opera:!!n}}()),typeOf:function(n){return({}).toString.call(n).match(/\s([a-z|A-Z]+)/)[1].toLowerCase()},extend:function(n){g.each(arguments,function(o,p){if(p>0){g.each(o,function(r,q){n[q]=r})}});return n},cleanName:function(n){var o,p;p=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"];for(o=0;o<p.length;o+=2){n=n.replace(p[o],p[o+1])}n=n.replace(/\s+/g,"_");n=n.replace(/[^a-z0-9_\-\.]+/gi,"");return n},addRuntime:function(n,o){o.name=n;k[n]=o;k.push(o);return o},guid:function(){var n=new Date().getTime().toString(32),o;for(o=0;o<5;o++){n+=Math.floor(Math.random()*65535).toString(32)}return(g.guidPrefix||"p")+n+(f++).toString(32)},buildUrl:function(o,n){var p="";g.each(n,function(r,q){p+=(p?"&":"")+encodeURIComponent(q)+"="+encodeURIComponent(r)});if(p){o+=(o.indexOf("?")>0?"&":"?")+p}return o},each:function(q,r){var p,o,n;if(q){p=q.length;if(p===b){for(o in q){if(q.hasOwnProperty(o)){if(r(q[o],o)===false){return}}}}else{for(n=0;n<p;n++){if(r(q[n],n)===false){return}}}}},formatSize:function(n){if(n===b||/\D/.test(n)){return g.translate("N/A")}if(n>1073741824){return Math.round(n/1073741824,1)+" GB"}if(n>1048576){return Math.round(n/1048576,1)+" MB"}if(n>1024){return Math.round(n/1024,1)+" KB"}return n+" b"},getPos:function(o,s){var t=0,r=0,v,u=document,p,q;o=o;s=s||u.body;function n(B){var z,A,w=0,C=0;if(B){A=B.getBoundingClientRect();z=u.compatMode==="CSS1Compat"?u.documentElement:u.body;w=A.left+z.scrollLeft;C=A.top+z.scrollTop}return{x:w,y:C}}if(o&&o.getBoundingClientRect&&g.ua.ie&&(!u.documentMode||u.documentMode<8)){p=n(o);q=n(s);return{x:p.x-q.x,y:p.y-q.y}}v=o;while(v&&v!=s&&v.nodeType){t+=v.offsetLeft||0;r+=v.offsetTop||0;v=v.offsetParent}v=o.parentNode;while(v&&v!=s&&v.nodeType){t-=v.scrollLeft||0;r-=v.scrollTop||0;v=v.parentNode}return{x:t,y:r}},getSize:function(n){return{w:n.offsetWidth||n.clientWidth,h:n.offsetHeight||n.clientHeight}},parseSize:function(n){var o;if(typeof(n)=="string"){n=/^([0-9]+)([mgk]?)$/.exec(n.toLowerCase().replace(/[^0-9mkg]/g,""));o=n[2];n=+n[1];if(o=="g"){n*=1073741824}if(o=="m"){n*=1048576}if(o=="k"){n*=1024}}return n},xmlEncode:function(n){return n?(""+n).replace(l,function(o){return a[o]?"&"+a[o]+";":o}):n},toArray:function(p){var o,n=[];for(o=0;o<p.length;o++){n[o]=p[o]}return n},inArray:function(p,q){if(q){if(Array.prototype.indexOf){return Array.prototype.indexOf.call(q,p)}for(var n=0,o=q.length;n<o;n++){if(q[n]===p){return n}}}return -1},addI18n:function(n){return g.extend(m,n)},translate:function(n){return m[n]||n},isEmptyObj:function(n){if(n===b){return true}for(var o in n){return false}return true},hasClass:function(p,o){var n;if(p.className==""){return false}n=new RegExp("(^|\\s+)"+o+"(\\s+|$)");return n.test(p.className)},addClass:function(o,n){if(!g.hasClass(o,n)){o.className=o.className==""?n:o.className.replace(/\s+$/,"")+" "+n}},removeClass:function(p,o){var n=new RegExp("(^|\\s+)"+o+"(\\s+|$)");p.className=p.className.replace(n,function(r,q,s){return q===" "&&s===" "?" ":""})},getStyle:function(o,n){if(o.currentStyle){return o.currentStyle[n]}else{if(window.getComputedStyle){return window.getComputedStyle(o,null)[n]}}},addEvent:function(s,n,t){var r,q,p,o;o=arguments[3];n=n.toLowerCase();if(e===b){e="Plupload_"+g.guid()}if(s.addEventListener){r=t;s.addEventListener(n,r,false)}else{if(s.attachEvent){r=function(){var u=window.event;if(!u.target){u.target=u.srcElement}u.preventDefault=h;u.stopPropagation=j;t(u)};s.attachEvent("on"+n,r)}}if(s[e]===b){s[e]=g.guid()}if(!d.hasOwnProperty(s[e])){d[s[e]]={}}q=d[s[e]];if(!q.hasOwnProperty(n)){q[n]=[]}q[n].push({func:r,orig:t,key:o})},removeEvent:function(s,n){var q,t,p;if(typeof(arguments[2])=="function"){t=arguments[2]}else{p=arguments[2]}n=n.toLowerCase();if(s[e]&&d[s[e]]&&d[s[e]][n]){q=d[s[e]][n]}else{return}for(var o=q.length-1;o>=0;o--){if(q[o].key===p||q[o].orig===t){if(s.removeEventListener){s.removeEventListener(n,q[o].func,false)}else{if(s.detachEvent){s.detachEvent("on"+n,q[o].func)}}q[o].orig=null;q[o].func=null;q.splice(o,1);if(t!==b){break}}}if(!q.length){delete d[s[e]][n]}if(g.isEmptyObj(d[s[e]])){delete d[s[e]];try{delete s[e]}catch(r){s[e]=b}}},removeAllEvents:function(o){var n=arguments[1];if(o[e]===b||!o[e]){return}g.each(d[o[e]],function(q,p){g.removeEvent(o,p,n)})}};g.Uploader=function(r){var o={},u,t=[],q,p=false;u=new g.QueueProgress();r=g.extend({chunk_size:0,multipart:true,multi_selection:true,file_data_name:"file",filters:[]},r);function s(){var w,x=0,v;if(this.state==g.STARTED){for(v=0;v<t.length;v++){if(!w&&t[v].status==g.QUEUED){w=t[v];w.status=g.UPLOADING;if(this.trigger("BeforeUpload",w)){this.trigger("UploadFile",w)}}else{x++}}if(x==t.length){this.stop();this.trigger("UploadComplete",t)}}}function n(){var w,v;u.reset();for(w=0;w<t.length;w++){v=t[w];if(v.size!==b){u.size+=v.size;u.loaded+=v.loaded}else{u.size=b}if(v.status==g.DONE){u.uploaded++}else{if(v.status==g.FAILED){u.failed++}else{u.queued++}}}if(u.size===b){u.percent=t.length>0?Math.ceil(u.uploaded/t.length*100):0}else{u.bytesPerSec=Math.ceil(u.loaded/((+new Date()-q||1)/1000));u.percent=u.size>0?Math.ceil(u.loaded/u.size*100):0}}g.extend(this,{state:g.STOPPED,runtime:"",features:{},files:t,settings:r,total:u,id:g.guid(),init:function(){var A=this,B,x,w,z=0,y;if(typeof(r.preinit)=="function"){r.preinit(A)}else{g.each(r.preinit,function(D,C){A.bind(C,D)})}r.page_url=r.page_url||document.location.pathname.replace(/\/[^\/]+$/g,"/");if(!/^(\w+:\/\/|\/)/.test(r.url)){r.url=r.page_url+r.url}r.chunk_size=g.parseSize(r.chunk_size);r.max_file_size=g.parseSize(r.max_file_size);A.bind("FilesAdded",function(C,F){var E,D,H=0,I,G=r.filters;if(G&&G.length){I=[];g.each(G,function(J){g.each(J.extensions.split(/,/),function(K){if(/^\s*\*\s*$/.test(K)){I.push("\\.*")}else{I.push("\\."+K.replace(new RegExp("["+("/^$.*+?|()[]{}\\".replace(/./g,"\\$&"))+"]","g"),"\\$&"))}})});I=new RegExp(I.join("|")+"$","i")}for(E=0;E<F.length;E++){D=F[E];D.loaded=0;D.percent=0;D.status=g.QUEUED;if(I&&!I.test(D.name)){C.trigger("Error",{code:g.FILE_EXTENSION_ERROR,message:g.translate("File extension error."),file:D});continue}if(D.size!==b&&D.size>r.max_file_size){C.trigger("Error",{code:g.FILE_SIZE_ERROR,message:g.translate("File size error."),file:D});continue}t.push(D);H++}if(H){c(function(){A.trigger("QueueChanged");A.refresh()},1)}else{return false}});if(r.unique_names){A.bind("UploadFile",function(C,D){var F=D.name.match(/\.([^.]+)$/),E="tmp";if(F){E=F[1]}D.target_name=D.id+"."+E})}A.bind("UploadProgress",function(C,D){D.percent=D.size>0?Math.ceil(D.loaded/D.size*100):100;n()});A.bind("StateChanged",function(C){if(C.state==g.STARTED){q=(+new Date())}else{if(C.state==g.STOPPED){for(B=C.files.length-1;B>=0;B--){if(C.files[B].status==g.UPLOADING){C.files[B].status=g.QUEUED;n()}}}}});A.bind("QueueChanged",n);A.bind("Error",function(C,D){if(D.file){D.file.status=g.FAILED;n();if(C.state==g.STARTED){c(function(){s.call(A)},1)}}});A.bind("FileUploaded",function(C,D){D.status=g.DONE;D.loaded=D.size;C.trigger("UploadProgress",D);c(function(){s.call(A)},1)});if(r.runtimes){x=[];y=r.runtimes.split(/\s?,\s?/);for(B=0;B<y.length;B++){if(k[y[B]]){x.push(k[y[B]])}}}else{x=k}function v(){var F=x[z++],E,C,D;if(F){E=F.getFeatures();C=A.settings.required_features;if(C){C=C.split(",");for(D=0;D<C.length;D++){if(!E[C[D]]){v();return}}}F.init(A,function(G){if(G&&G.success){A.features=E;A.runtime=F.name;A.trigger("Init",{runtime:F.name});A.trigger("PostInit");A.refresh()}else{v()}})}else{A.trigger("Error",{code:g.INIT_ERROR,message:g.translate("Init error.")})}}v();if(typeof(r.init)=="function"){r.init(A)}else{g.each(r.init,function(D,C){A.bind(C,D)})}},refresh:function(){this.trigger("Refresh")},start:function(){if(t.length&&this.state!=g.STARTED){this.state=g.STARTED;this.trigger("StateChanged");s.call(this)}},stop:function(){if(this.state!=g.STOPPED){this.state=g.STOPPED;this.trigger("CancelUpload");this.trigger("StateChanged")}},disableBrowse:function(){p=arguments[0]!==b?arguments[0]:true;this.trigger("DisableBrowse",p)},getFile:function(w){var v;for(v=t.length-1;v>=0;v--){if(t[v].id===w){return t[v]}}},removeFile:function(w){var v;for(v=t.length-1;v>=0;v--){if(t[v].id===w.id){return this.splice(v,1)[0]}}},splice:function(x,v){var w;w=t.splice(x===b?0:x,v===b?t.length:v);this.trigger("FilesRemoved",w);this.trigger("QueueChanged");return w},trigger:function(w){var y=o[w.toLowerCase()],x,v;if(y){v=Array.prototype.slice.call(arguments);v[0]=this;for(x=0;x<y.length;x++){if(y[x].func.apply(y[x].scope,v)===false){return false}}}return true},hasEventListener:function(v){return !!o[v.toLowerCase()]},bind:function(v,x,w){var y;v=v.toLowerCase();y=o[v]||[];y.push({func:x,scope:w||this});o[v]=y},unbind:function(v){v=v.toLowerCase();var y=o[v],w,x=arguments[1];if(y){if(x!==b){for(w=y.length-1;w>=0;w--){if(y[w].func===x){y.splice(w,1);break}}}else{y=[]}if(!y.length){delete o[v]}}},unbindAll:function(){var v=this;g.each(o,function(x,w){v.unbind(w)})},destroy:function(){this.stop();this.trigger("Destroy");this.unbindAll()}})};g.File=function(q,o,p){var n=this;n.id=q;n.name=o;n.size=p;n.loaded=0;n.percent=0;n.status=0};g.Runtime=function(){this.getFeatures=function(){};this.init=function(n,o){}};g.QueueProgress=function(){var n=this;n.size=0;n.loaded=0;n.uploaded=0;n.failed=0;n.queued=0;n.percent=0;n.bytesPerSec=0;n.reset=function(){n.size=n.loaded=n.uploaded=n.failed=n.queued=n.percent=n.bytesPerSec=0}};g.runtimes={};window.plupload=g})(); \ No newline at end of file
diff --git a/src/wp-includes/js/plupload/plupload.silverlight.js b/src/wp-includes/js/plupload/plupload.silverlight.js
new file mode 100644
index 0000000000..ccaa95a000
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.silverlight.js
@@ -0,0 +1 @@
+(function(g,b,d,e){var a={},h={};function c(o){var n,m=typeof o,j,l,k;if(o===e||o===null){return"null"}if(m==="string"){n="\bb\tt\nn\ff\rr\"\"''\\\\";return'"'+o.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g,function(q,p){var i=n.indexOf(p);if(i+1){return"\\"+n.charAt(i+1)}q=p.charCodeAt().toString(16);return"\\u"+"0000".substring(q.length)+q})+'"'}if(m=="object"){j=o.length!==e;n="";if(j){for(l=0;l<o.length;l++){if(n){n+=","}n+=c(o[l])}n="["+n+"]"}else{for(k in o){if(o.hasOwnProperty(k)){if(n){n+=","}n+=c(k)+":"+c(o[k])}}n="{"+n+"}"}return n}return""+o}function f(r){var u=false,i=null,n=null,j,k,l,t,m,p=0;try{try{n=new ActiveXObject("AgControl.AgControl");if(n.IsVersionSupported(r)){u=true}n=null}catch(q){var o=navigator.plugins["Silverlight Plug-In"];if(o){j=o.description;if(j==="1.0.30226.2"){j="2.0.30226.2"}k=j.split(".");while(k.length>3){k.pop()}while(k.length<4){k.push(0)}l=r.split(".");while(l.length>4){l.pop()}do{t=parseInt(l[p],10);m=parseInt(k[p],10);p++}while(p<l.length&&t===m);if(t<=m&&!isNaN(t)){u=true}}}}catch(s){u=false}return u}d.silverlight={trigger:function(n,k){var m=a[n],l,j;if(m){j=d.toArray(arguments).slice(1);j[0]="Silverlight:"+k;setTimeout(function(){m.trigger.apply(m,j)},0)}}};d.runtimes.Silverlight=d.addRuntime("silverlight",{getFeatures:function(){return{jpgresize:true,pngresize:true,chunks:true,progress:true,multipart:true,multi_selection:true}},init:function(p,q){var o,m="",n=p.settings.filters,l,k=b.body;if(!f("2.0.31005.0")||(g.opera&&g.opera.buildNumber)){q({success:false});return}h[p.id]=false;a[p.id]=p;o=b.createElement("div");o.id=p.id+"_silverlight_container";d.extend(o.style,{position:"absolute",top:"0px",background:p.settings.shim_bgcolor||"transparent",zIndex:99999,width:"100px",height:"100px",overflow:"hidden",opacity:p.settings.shim_bgcolor||b.documentMode>8?"":0.01});o.className="plupload silverlight";if(p.settings.container){k=b.getElementById(p.settings.container);if(d.getStyle(k,"position")==="static"){k.style.position="relative"}}k.appendChild(o);for(l=0;l<n.length;l++){m+=(m!=""?"|":"")+n[l].title+" | *."+n[l].extensions.replace(/,/g,";*.")}o.innerHTML='<object id="'+p.id+'_silverlight" data="data:application/x-silverlight," type="application/x-silverlight-2" style="outline:none;" width="1024" height="1024"><param name="source" value="'+p.settings.silverlight_xap_url+'"/><param name="background" value="Transparent"/><param name="windowless" value="true"/><param name="enablehtmlaccess" value="true"/><param name="initParams" value="id='+p.id+",filter="+m+",multiselect="+p.settings.multi_selection+'"/></object>';function j(){return b.getElementById(p.id+"_silverlight").content.Upload}p.bind("Silverlight:Init",function(){var i,r={};if(h[p.id]){return}h[p.id]=true;p.bind("Silverlight:StartSelectFiles",function(s){i=[]});p.bind("Silverlight:SelectFile",function(s,v,t,u){var w;w=d.guid();r[w]=v;r[v]=w;i.push(new d.File(w,t,u))});p.bind("Silverlight:SelectSuccessful",function(){if(i.length){p.trigger("FilesAdded",i)}});p.bind("Silverlight:UploadChunkError",function(s,v,t,w,u){p.trigger("Error",{code:d.IO_ERROR,message:"IO Error.",details:u,file:s.getFile(r[v])})});p.bind("Silverlight:UploadFileProgress",function(s,w,t,v){var u=s.getFile(r[w]);if(u.status!=d.FAILED){u.size=v;u.loaded=t;s.trigger("UploadProgress",u)}});p.bind("Refresh",function(s){var t,u,v;t=b.getElementById(s.settings.browse_button);if(t){u=d.getPos(t,b.getElementById(s.settings.container));v=d.getSize(t);d.extend(b.getElementById(s.id+"_silverlight_container").style,{top:u.y+"px",left:u.x+"px",width:v.w+"px",height:v.h+"px"})}});p.bind("Silverlight:UploadChunkSuccessful",function(s,v,t,y,x){var w,u=s.getFile(r[v]);w={chunk:t,chunks:y,response:x};s.trigger("ChunkUploaded",u,w);if(u.status!=d.FAILED&&s.state!==d.STOPPED){j().UploadNextChunk()}if(t==y-1){u.status=d.DONE;s.trigger("FileUploaded",u,{response:x})}});p.bind("Silverlight:UploadSuccessful",function(s,v,t){var u=s.getFile(r[v]);u.status=d.DONE;s.trigger("FileUploaded",u,{response:t})});p.bind("FilesRemoved",function(s,u){var t;for(t=0;t<u.length;t++){j().RemoveFile(r[u[t].id])}});p.bind("UploadFile",function(s,u){var v=s.settings,t=v.resize||{};j().UploadFile(r[u.id],s.settings.url,c({name:u.target_name||u.name,mime:d.mimeTypes[u.name.replace(/^.+\.([^.]+)/,"$1").toLowerCase()]||"application/octet-stream",chunk_size:v.chunk_size,image_width:t.width,image_height:t.height,image_quality:t.quality,multipart:!!v.multipart,multipart_params:v.multipart_params||{},file_data_name:v.file_data_name,headers:v.headers}))});p.bind("CancelUpload",function(){j().CancelUpload()});p.bind("Silverlight:MouseEnter",function(s){var t,u;t=b.getElementById(p.settings.browse_button);u=s.settings.browse_button_hover;if(t&&u){d.addClass(t,u)}});p.bind("Silverlight:MouseLeave",function(s){var t,u;t=b.getElementById(p.settings.browse_button);u=s.settings.browse_button_hover;if(t&&u){d.removeClass(t,u)}});p.bind("Silverlight:MouseLeftButtonDown",function(s){var t,u;t=b.getElementById(p.settings.browse_button);u=s.settings.browse_button_active;if(t&&u){d.addClass(t,u);d.addEvent(b.body,"mouseup",function(){d.removeClass(t,u)})}});p.bind("Sliverlight:StartSelectFiles",function(s){var t,u;t=b.getElementById(p.settings.browse_button);u=s.settings.browse_button_active;if(t&&u){d.removeClass(t,u)}});p.bind("DisableBrowse",function(s,t){j().DisableBrowse(t)});p.bind("Destroy",function(s){var t;d.removeAllEvents(b.body,s.id);delete h[s.id];delete a[s.id];t=b.getElementById(s.id+"_silverlight_container");if(t){t.parentNode.removeChild(t)}});q({success:true})})}})})(window,document,plupload); \ No newline at end of file
diff --git a/src/wp-includes/js/plupload/plupload.silverlight.xap b/src/wp-includes/js/plupload/plupload.silverlight.xap
new file mode 100644
index 0000000000..e1584d3b1a
--- /dev/null
+++ b/src/wp-includes/js/plupload/plupload.silverlight.xap
Binary files differ
diff --git a/src/wp-includes/js/plupload/wp-plupload.js b/src/wp-includes/js/plupload/wp-plupload.js
new file mode 100644
index 0000000000..dc91674930
--- /dev/null
+++ b/src/wp-includes/js/plupload/wp-plupload.js
@@ -0,0 +1,343 @@
+window.wp = window.wp || {};
+
+(function( exports, $ ) {
+ var Uploader;
+
+ if ( typeof _wpPluploadSettings === 'undefined' )
+ return;
+
+ /*
+ * An object that helps create a WordPress uploader using plupload.
+ *
+ * @param options - object - The options passed to the new plupload instance.
+ * Accepts the following parameters:
+ * - container - The id of uploader container.
+ * - browser - The id of button to trigger the file select.
+ * - dropzone - The id of file drop target.
+ * - plupload - An object of parameters to pass to the plupload instance.
+ * - params - An object of parameters to pass to $_POST when uploading the file.
+ * Extends this.plupload.multipart_params under the hood.
+ *
+ * @param attributes - object - Attributes and methods for this specific instance.
+ */
+ Uploader = function( options ) {
+ var self = this,
+ elements = {
+ container: 'container',
+ browser: 'browse_button',
+ dropzone: 'drop_element'
+ },
+ key, error;
+
+ this.supports = {
+ upload: Uploader.browser.supported
+ };
+
+ this.supported = this.supports.upload;
+
+ if ( ! this.supported )
+ return;
+
+ // Use deep extend to ensure that multipart_params and other objects are cloned.
+ this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults );
+ this.container = document.body; // Set default container.
+
+ // Extend the instance with options
+ //
+ // Use deep extend to allow options.plupload to override individual
+ // default plupload keys.
+ $.extend( true, this, options );
+
+ // Proxy all methods so this always refers to the current instance.
+ for ( key in this ) {
+ if ( $.isFunction( this[ key ] ) )
+ this[ key ] = $.proxy( this[ key ], this );
+ }
+
+ // Ensure all elements are jQuery elements and have id attributes
+ // Then set the proper plupload arguments to the ids.
+ for ( key in elements ) {
+ if ( ! this[ key ] )
+ continue;
+
+ this[ key ] = $( this[ key ] ).first();
+
+ if ( ! this[ key ].length ) {
+ delete this[ key ];
+ continue;
+ }
+
+ if ( ! this[ key ].prop('id') )
+ this[ key ].prop( 'id', '__wp-uploader-id-' + Uploader.uuid++ );
+ this.plupload[ elements[ key ] ] = this[ key ].prop('id');
+ }
+
+ // If the uploader has neither a browse button nor a dropzone, bail.
+ if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) )
+ return;
+
+ this.uploader = new plupload.Uploader( this.plupload );
+ delete this.plupload;
+
+ // Set default params and remove this.params alias.
+ this.param( this.params || {} );
+ delete this.params;
+
+ error = function( message, data, file ) {
+ if ( file.attachment )
+ file.attachment.destroy();
+
+ Uploader.errors.unshift({
+ message: message || pluploadL10n.default_error,
+ data: data,
+ file: file
+ });
+
+ self.error( message, data, file );
+ };
+
+ this.uploader.init();
+
+ this.supports.dragdrop = this.uploader.features.dragdrop && ! Uploader.browser.mobile;
+
+ // Generate drag/drop helper classes.
+ (function( dropzone, supported ) {
+ var timer, active;
+
+ if ( ! dropzone )
+ return;
+
+ dropzone.toggleClass( 'supports-drag-drop', !! supported );
+
+ if ( ! supported )
+ return dropzone.unbind('.wp-uploader');
+
+ // 'dragenter' doesn't fire correctly,
+ // simulate it with a limited 'dragover'
+ dropzone.bind( 'dragover.wp-uploader', function(){
+ if ( timer )
+ clearTimeout( timer );
+
+ if ( active )
+ return;
+
+ dropzone.trigger('dropzone:enter').addClass('drag-over');
+ active = true;
+ });
+
+ dropzone.bind('dragleave.wp-uploader, drop.wp-uploader', function(){
+ // Using an instant timer prevents the drag-over class from
+ // being quickly removed and re-added when elements inside the
+ // dropzone are repositioned.
+ //
+ // See http://core.trac.wordpress.org/ticket/21705
+ timer = setTimeout( function() {
+ active = false;
+ dropzone.trigger('dropzone:leave').removeClass('drag-over');
+ }, 0 );
+ });
+ }( this.dropzone, this.supports.dragdrop ));
+
+ if ( this.browser ) {
+ this.browser.on( 'mouseenter', this.refresh );
+ } else {
+ this.uploader.disableBrowse( true );
+ // If HTML5 mode, hide the auto-created file container.
+ $('#' + this.uploader.id + '_html5_container').hide();
+ }
+
+ this.uploader.bind( 'FilesAdded', function( up, files ) {
+ _.each( files, function( file ) {
+ var attributes, image;
+
+ // Ignore failed uploads.
+ if ( plupload.FAILED === file.status )
+ return;
+
+ // Generate attributes for a new `Attachment` model.
+ attributes = _.extend({
+ file: file,
+ uploading: true,
+ date: new Date(),
+ filename: file.name,
+ menuOrder: 0,
+ uploadedTo: wp.media.model.settings.post.id
+ }, _.pick( file, 'loaded', 'size', 'percent' ) );
+
+ // Handle early mime type scanning for images.
+ image = /(?:jpe?g|png|gif)$/i.exec( file.name );
+
+ // Did we find an image?
+ if ( image ) {
+ attributes.type = 'image';
+
+ // `jpeg`, `png` and `gif` are valid subtypes.
+ // `jpg` is not, so map it to `jpeg`.
+ attributes.subtype = ( 'jpg' === image[0] ) ? 'jpeg' : image[0];
+ }
+
+ // Create the `Attachment`.
+ file.attachment = wp.media.model.Attachment.create( attributes );
+
+ Uploader.queue.add( file.attachment );
+
+ self.added( file.attachment );
+ });
+
+ up.refresh();
+ up.start();
+ });
+
+ this.uploader.bind( 'UploadProgress', function( up, file ) {
+ file.attachment.set( _.pick( file, 'loaded', 'percent' ) );
+ self.progress( file.attachment );
+ });
+
+ this.uploader.bind( 'FileUploaded', function( up, file, response ) {
+ var complete;
+
+ try {
+ response = JSON.parse( response.response );
+ } catch ( e ) {
+ return error( pluploadL10n.default_error, e, file );
+ }
+
+ if ( ! _.isObject( response ) || _.isUndefined( response.success ) )
+ return error( pluploadL10n.default_error, null, file );
+ else if ( ! response.success )
+ return error( response.data && response.data.message, response.data, file );
+
+ _.each(['file','loaded','size','percent'], function( key ) {
+ file.attachment.unset( key );
+ });
+
+ file.attachment.set( _.extend( response.data, { uploading: false }) );
+ wp.media.model.Attachment.get( response.data.id, file.attachment );
+
+ complete = Uploader.queue.all( function( attachment ) {
+ return ! attachment.get('uploading');
+ });
+
+ if ( complete )
+ Uploader.queue.reset();
+
+ self.success( file.attachment );
+ });
+
+ this.uploader.bind( 'Error', function( up, pluploadError ) {
+ var message = pluploadL10n.default_error,
+ key;
+
+ // Check for plupload errors.
+ for ( key in Uploader.errorMap ) {
+ if ( pluploadError.code === plupload[ key ] ) {
+ message = Uploader.errorMap[ key ];
+ if ( _.isFunction( message ) )
+ message = message( pluploadError.file, pluploadError );
+ break;
+ }
+ }
+
+ error( message, pluploadError, pluploadError.file );
+ up.refresh();
+ });
+
+ this.init();
+ };
+
+ // Adds the 'defaults' and 'browser' properties.
+ $.extend( Uploader, _wpPluploadSettings );
+
+ Uploader.uuid = 0;
+
+ Uploader.errorMap = {
+ 'FAILED': pluploadL10n.upload_failed,
+ 'FILE_EXTENSION_ERROR': pluploadL10n.invalid_filetype,
+ 'IMAGE_FORMAT_ERROR': pluploadL10n.not_an_image,
+ 'IMAGE_MEMORY_ERROR': pluploadL10n.image_memory_exceeded,
+ 'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded,
+ 'GENERIC_ERROR': pluploadL10n.upload_failed,
+ 'IO_ERROR': pluploadL10n.io_error,
+ 'HTTP_ERROR': pluploadL10n.http_error,
+ 'SECURITY_ERROR': pluploadL10n.security_error,
+
+ 'FILE_SIZE_ERROR': function( file ) {
+ return pluploadL10n.file_exceeds_size_limit.replace('%s', file.name);
+ }
+ };
+
+ $.extend( Uploader.prototype, {
+ /**
+ * Acts as a shortcut to extending the uploader's multipart_params object.
+ *
+ * param( key )
+ * Returns the value of the key.
+ *
+ * param( key, value )
+ * Sets the value of a key.
+ *
+ * param( map )
+ * Sets values for a map of data.
+ */
+ param: function( key, value ) {
+ if ( arguments.length === 1 && typeof key === 'string' )
+ return this.uploader.settings.multipart_params[ key ];
+
+ if ( arguments.length > 1 ) {
+ this.uploader.settings.multipart_params[ key ] = value;
+ } else {
+ $.extend( this.uploader.settings.multipart_params, key );
+ }
+ },
+
+ init: function() {},
+ error: function() {},
+ success: function() {},
+ added: function() {},
+ progress: function() {},
+ complete: function() {},
+ refresh: function() {
+ var node, attached, container, id;
+
+ if ( this.browser ) {
+ node = this.browser[0];
+
+ // Check if the browser node is in the DOM.
+ while ( node ) {
+ if ( node === document.body ) {
+ attached = true;
+ break;
+ }
+ node = node.parentNode;
+ }
+
+ // If the browser node is not attached to the DOM, use a
+ // temporary container to house it, as the browser button
+ // shims require the button to exist in the DOM at all times.
+ if ( ! attached ) {
+ id = 'wp-uploader-browser-' + this.uploader.id;
+
+ container = $( '#' + id );
+ if ( ! container.length ) {
+ container = $('<div class="wp-uploader-browser" />').css({
+ position: 'fixed',
+ top: '-1000px',
+ left: '-1000px',
+ height: 0,
+ width: 0
+ }).attr( 'id', 'wp-uploader-browser-' + this.uploader.id ).appendTo('body');
+ }
+
+ container.append( this.browser );
+ }
+ }
+
+ this.uploader.refresh();
+ }
+ });
+
+ Uploader.queue = new wp.media.model.Attachments( [], { query: false });
+ Uploader.errors = new Backbone.Collection();
+
+ exports.Uploader = Uploader;
+})( wp, jQuery );
diff --git a/src/wp-includes/js/quicktags.js b/src/wp-includes/js/quicktags.js
new file mode 100644
index 0000000000..202c1cbacf
--- /dev/null
+++ b/src/wp-includes/js/quicktags.js
@@ -0,0 +1,620 @@
+/*
+ * Quicktags
+ *
+ * This is the HTML editor in WordPress. It can be attached to any textarea and will
+ * append a toolbar above it. This script is self-contained (does not require external libraries).
+ *
+ * Run quicktags(settings) to initialize it, where settings is an object containing up to 3 properties:
+ * settings = {
+ * id : 'my_id', the HTML ID of the textarea, required
+ * buttons: '' Comma separated list of the names of the default buttons to show. Optional.
+ * Current list of default button names: 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close';
+ * }
+ *
+ * The settings can also be a string quicktags_id.
+ *
+ * quicktags_id string The ID of the textarea that will be the editor canvas
+ * buttons string Comma separated list of the default buttons names that will be shown in that instance.
+ */
+
+// new edit toolbar used with permission
+// by Alex King
+// http://www.alexking.org/
+
+var QTags, edButtons = [], edCanvas,
+
+/**
+ * Back-compat
+ *
+ * Define all former global functions so plugins that hack quicktags.js directly don't cause fatal errors.
+ */
+edAddTag = function(){},
+edCheckOpenTags = function(){},
+edCloseAllTags = function(){},
+edInsertImage = function(){},
+edInsertLink = function(){},
+edInsertTag = function(){},
+edLink = function(){},
+edQuickLink = function(){},
+edRemoveTag = function(){},
+edShowButton = function(){},
+edShowLinks = function(){},
+edSpell = function(){},
+edToolbar = function(){};
+
+/**
+ * Initialize new instance of the Quicktags editor
+ */
+function quicktags(settings) {
+ return new QTags(settings);
+}
+
+/**
+ * Inserts content at the caret in the active editor (textarea)
+ *
+ * Added for back compatibility
+ * @see QTags.insertContent()
+ */
+function edInsertContent(bah, txt) {
+ return QTags.insertContent(txt);
+}
+
+/**
+ * Adds a button to all instances of the editor
+ *
+ * Added for back compatibility, use QTags.addButton() as it gives more flexibility like type of button, button placement, etc.
+ * @see QTags.addButton()
+ */
+function edButton(id, display, tagStart, tagEnd, access, open) {
+ return QTags.addButton( id, display, tagStart, tagEnd, access, '', -1 );
+}
+
+(function(){
+ // private stuff is prefixed with an underscore
+ var _domReady = function(func) {
+ var t, i, DOMContentLoaded;
+
+ if ( typeof jQuery != 'undefined' ) {
+ jQuery(document).ready(func);
+ } else {
+ t = _domReady;
+ t.funcs = [];
+
+ t.ready = function() {
+ if ( ! t.isReady ) {
+ t.isReady = true;
+ for ( i = 0; i < t.funcs.length; i++ ) {
+ t.funcs[i]();
+ }
+ }
+ };
+
+ if ( t.isReady ) {
+ func();
+ } else {
+ t.funcs.push(func);
+ }
+
+ if ( ! t.eventAttached ) {
+ if ( document.addEventListener ) {
+ DOMContentLoaded = function(){document.removeEventListener('DOMContentLoaded', DOMContentLoaded, false);t.ready();};
+ document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
+ window.addEventListener('load', t.ready, false);
+ } else if ( document.attachEvent ) {
+ DOMContentLoaded = function(){if (document.readyState === 'complete'){ document.detachEvent('onreadystatechange', DOMContentLoaded);t.ready();}};
+ document.attachEvent('onreadystatechange', DOMContentLoaded);
+ window.attachEvent('onload', t.ready);
+
+ (function(){
+ try {
+ document.documentElement.doScroll("left");
+ } catch(e) {
+ setTimeout(arguments.callee, 50);
+ return;
+ }
+
+ t.ready();
+ })();
+ }
+
+ t.eventAttached = true;
+ }
+ }
+ },
+
+ _datetime = (function() {
+ var now = new Date(), zeroise;
+
+ zeroise = function(number) {
+ var str = number.toString();
+
+ if ( str.length < 2 )
+ str = "0" + str;
+
+ return str;
+ }
+
+ return now.getUTCFullYear() + '-' +
+ zeroise( now.getUTCMonth() + 1 ) + '-' +
+ zeroise( now.getUTCDate() ) + 'T' +
+ zeroise( now.getUTCHours() ) + ':' +
+ zeroise( now.getUTCMinutes() ) + ':' +
+ zeroise( now.getUTCSeconds() ) +
+ '+00:00';
+ })(),
+ qt;
+
+ qt = QTags = function(settings) {
+ if ( typeof(settings) == 'string' )
+ settings = {id: settings};
+ else if ( typeof(settings) != 'object' )
+ return false;
+
+ var t = this,
+ id = settings.id,
+ canvas = document.getElementById(id),
+ name = 'qt_' + id,
+ tb, onclick, toolbar_id;
+
+ if ( !id || !canvas )
+ return false;
+
+ t.name = name;
+ t.id = id;
+ t.canvas = canvas;
+ t.settings = settings;
+
+ if ( id == 'content' && typeof(adminpage) == 'string' && ( adminpage == 'post-new-php' || adminpage == 'post-php' ) ) {
+ // back compat hack :-(
+ edCanvas = canvas;
+ toolbar_id = 'ed_toolbar';
+ } else {
+ toolbar_id = name + '_toolbar';
+ }
+
+ tb = document.createElement('div');
+ tb.id = toolbar_id;
+ tb.className = 'quicktags-toolbar';
+
+ canvas.parentNode.insertBefore(tb, canvas);
+ t.toolbar = tb;
+
+ // listen for click events
+ onclick = function(e) {
+ e = e || window.event;
+ var target = e.target || e.srcElement, visible = target.clientWidth || target.offsetWidth, i;
+
+ // don't call the callback on pressing the accesskey when the button is not visible
+ if ( !visible )
+ return;
+
+ // as long as it has the class ed_button, execute the callback
+ if ( / ed_button /.test(' ' + target.className + ' ') ) {
+ // we have to reassign canvas here
+ t.canvas = canvas = document.getElementById(id);
+ i = target.id.replace(name + '_', '');
+
+ if ( t.theButtons[i] )
+ t.theButtons[i].callback.call(t.theButtons[i], target, canvas, t);
+ }
+ };
+
+ if ( tb.addEventListener ) {
+ tb.addEventListener('click', onclick, false);
+ } else if ( tb.attachEvent ) {
+ tb.attachEvent('onclick', onclick);
+ }
+
+ t.getButton = function(id) {
+ return t.theButtons[id];
+ };
+
+ t.getButtonElement = function(id) {
+ return document.getElementById(name + '_' + id);
+ };
+
+ qt.instances[id] = t;
+
+ if ( !qt.instances[0] ) {
+ qt.instances[0] = qt.instances[id];
+ _domReady( function(){ qt._buttonsInit(); } );
+ }
+ };
+
+ qt.instances = {};
+
+ qt.getInstance = function(id) {
+ return qt.instances[id];
+ };
+
+ qt._buttonsInit = function() {
+ var t = this, canvas, name, settings, theButtons, html, inst, ed, id, i, use,
+ defaults = ',strong,em,link,block,del,ins,img,ul,ol,li,code,more,close,';
+
+ for ( inst in t.instances ) {
+ if ( inst == 0 )
+ continue;
+
+ ed = t.instances[inst];
+ canvas = ed.canvas;
+ name = ed.name;
+ settings = ed.settings;
+ html = '';
+ theButtons = {};
+ use = '';
+
+ // set buttons
+ if ( settings.buttons )
+ use = ','+settings.buttons+',';
+
+ for ( i in edButtons ) {
+ if ( !edButtons[i] )
+ continue;
+
+ id = edButtons[i].id;
+ if ( use && defaults.indexOf(','+id+',') != -1 && use.indexOf(','+id+',') == -1 )
+ continue;
+
+ if ( !edButtons[i].instance || edButtons[i].instance == inst ) {
+ theButtons[id] = edButtons[i];
+
+ if ( edButtons[i].html )
+ html += edButtons[i].html(name + '_');
+ }
+ }
+
+ if ( use && use.indexOf(',fullscreen,') != -1 ) {
+ theButtons['fullscreen'] = new qt.FullscreenButton();
+ html += theButtons['fullscreen'].html(name + '_');
+ }
+
+
+ if ( 'rtl' == document.getElementsByTagName('html')[0].dir ) {
+ theButtons['textdirection'] = new qt.TextDirectionButton();
+ html += theButtons['textdirection'].html(name + '_');
+ }
+
+ ed.toolbar.innerHTML = html;
+ ed.theButtons = theButtons;
+ }
+ t.buttonsInitDone = true;
+ };
+
+ /**
+ * Main API function for adding a button to Quicktags
+ *
+ * Adds qt.Button or qt.TagButton depending on the args. The first three args are always required.
+ * To be able to add button(s) to Quicktags, your script should be enqueued as dependent
+ * on "quicktags" and outputted in the footer. If you are echoing JS directly from PHP,
+ * use add_action( 'admin_print_footer_scripts', 'output_my_js', 100 ) or add_action( 'wp_footer', 'output_my_js', 100 )
+ *
+ * Minimum required to add a button that calls an external function:
+ * QTags.addButton( 'my_id', 'my button', my_callback );
+ * function my_callback() { alert('yeah!'); }
+ *
+ * Minimum required to add a button that inserts a tag:
+ * QTags.addButton( 'my_id', 'my button', '<span>', '</span>' );
+ * QTags.addButton( 'my_id2', 'my button', '<br />' );
+ *
+ * @param string id Required. Button HTML ID
+ * @param string display Required. Button's value="..."
+ * @param string|function arg1 Required. Either a starting tag to be inserted like "<span>" or a callback that is executed when the button is clicked.
+ * @param string arg2 Optional. Ending tag like "</span>"
+ * @param string access_key Optional. Access key for the button.
+ * @param string title Optional. Button's title="..."
+ * @param int priority Optional. Number representing the desired position of the button in the toolbar. 1 - 9 = first, 11 - 19 = second, 21 - 29 = third, etc.
+ * @param string instance Optional. Limit the button to a specifric instance of Quicktags, add to all instances if not present.
+ * @return mixed null or the button object that is needed for back-compat.
+ */
+ qt.addButton = function( id, display, arg1, arg2, access_key, title, priority, instance ) {
+ var btn;
+
+ if ( !id || !display )
+ return;
+
+ priority = priority || 0;
+ arg2 = arg2 || '';
+
+ if ( typeof(arg1) === 'function' ) {
+ btn = new qt.Button(id, display, access_key, title, instance);
+ btn.callback = arg1;
+ } else if ( typeof(arg1) === 'string' ) {
+ btn = new qt.TagButton(id, display, arg1, arg2, access_key, title, instance);
+ } else {
+ return;
+ }
+
+ if ( priority == -1 ) // back-compat
+ return btn;
+
+ if ( priority > 0 ) {
+ while ( typeof(edButtons[priority]) != 'undefined' ) {
+ priority++
+ }
+
+ edButtons[priority] = btn;
+ } else {
+ edButtons[edButtons.length] = btn;
+ }
+
+ if ( this.buttonsInitDone )
+ this._buttonsInit(); // add the button HTML to all instances toolbars if addButton() was called too late
+ };
+
+ qt.insertContent = function(content) {
+ var sel, startPos, endPos, scrollTop, text, canvas = document.getElementById(wpActiveEditor);
+
+ if ( !canvas )
+ return false;
+
+ if ( document.selection ) { //IE
+ canvas.focus();
+ sel = document.selection.createRange();
+ sel.text = content;
+ canvas.focus();
+ } else if ( canvas.selectionStart || canvas.selectionStart == '0' ) { // FF, WebKit, Opera
+ text = canvas.value;
+ startPos = canvas.selectionStart;
+ endPos = canvas.selectionEnd;
+ scrollTop = canvas.scrollTop;
+
+ canvas.value = text.substring(0, startPos) + content + text.substring(endPos, text.length);
+
+ canvas.focus();
+ canvas.selectionStart = startPos + content.length;
+ canvas.selectionEnd = startPos + content.length;
+ canvas.scrollTop = scrollTop;
+ } else {
+ canvas.value += content;
+ canvas.focus();
+ }
+ return true;
+ };
+
+ // a plain, dumb button
+ qt.Button = function(id, display, access, title, instance) {
+ var t = this;
+ t.id = id;
+ t.display = display;
+ t.access = access;
+ t.title = title || '';
+ t.instance = instance || '';
+ };
+ qt.Button.prototype.html = function(idPrefix) {
+ var access = this.access ? ' accesskey="' + this.access + '"' : '';
+ return '<input type="button" id="' + idPrefix + this.id + '"' + access + ' class="ed_button" title="' + this.title + '" value="' + this.display + '" />';
+ };
+ qt.Button.prototype.callback = function(){};
+
+ // a button that inserts HTML tag
+ qt.TagButton = function(id, display, tagStart, tagEnd, access, title, instance) {
+ var t = this;
+ qt.Button.call(t, id, display, access, title, instance);
+ t.tagStart = tagStart;
+ t.tagEnd = tagEnd;
+ };
+ qt.TagButton.prototype = new qt.Button();
+ qt.TagButton.prototype.openTag = function(e, ed) {
+ var t = this;
+
+ if ( ! ed.openTags ) {
+ ed.openTags = [];
+ }
+ if ( t.tagEnd ) {
+ ed.openTags.push(t.id);
+ e.value = '/' + e.value;
+ }
+ };
+ qt.TagButton.prototype.closeTag = function(e, ed) {
+ var t = this, i = t.isOpen(ed);
+
+ if ( i !== false ) {
+ ed.openTags.splice(i, 1);
+ }
+
+ e.value = t.display;
+ };
+ // whether a tag is open or not. Returns false if not open, or current open depth of the tag
+ qt.TagButton.prototype.isOpen = function (ed) {
+ var t = this, i = 0, ret = false;
+ if ( ed.openTags ) {
+ while ( ret === false && i < ed.openTags.length ) {
+ ret = ed.openTags[i] == t.id ? i : false;
+ i ++;
+ }
+ } else {
+ ret = false;
+ }
+ return ret;
+ };
+ qt.TagButton.prototype.callback = function(element, canvas, ed) {
+ var t = this, startPos, endPos, cursorPos, scrollTop, v = canvas.value, l, r, i, sel, endTag = v ? t.tagEnd : '';
+
+ if ( document.selection ) { // IE
+ canvas.focus();
+ sel = document.selection.createRange();
+ if ( sel.text.length > 0 ) {
+ if ( !t.tagEnd )
+ sel.text = sel.text + t.tagStart;
+ else
+ sel.text = t.tagStart + sel.text + endTag;
+ } else {
+ if ( !t.tagEnd ) {
+ sel.text = t.tagStart;
+ } else if ( t.isOpen(ed) === false ) {
+ sel.text = t.tagStart;
+ t.openTag(element, ed);
+ } else {
+ sel.text = endTag;
+ t.closeTag(element, ed);
+ }
+ }
+ canvas.focus();
+ } else if ( canvas.selectionStart || canvas.selectionStart == '0' ) { // FF, WebKit, Opera
+ startPos = canvas.selectionStart;
+ endPos = canvas.selectionEnd;
+ cursorPos = endPos;
+ scrollTop = canvas.scrollTop;
+ l = v.substring(0, startPos); // left of the selection
+ r = v.substring(endPos, v.length); // right of the selection
+ i = v.substring(startPos, endPos); // inside the selection
+ if ( startPos != endPos ) {
+ if ( !t.tagEnd ) {
+ canvas.value = l + i + t.tagStart + r; // insert self closing tags after the selection
+ cursorPos += t.tagStart.length;
+ } else {
+ canvas.value = l + t.tagStart + i + endTag + r;
+ cursorPos += t.tagStart.length + endTag.length;
+ }
+ } else {
+ if ( !t.tagEnd ) {
+ canvas.value = l + t.tagStart + r;
+ cursorPos = startPos + t.tagStart.length;
+ } else if ( t.isOpen(ed) === false ) {
+ canvas.value = l + t.tagStart + r;
+ t.openTag(element, ed);
+ cursorPos = startPos + t.tagStart.length;
+ } else {
+ canvas.value = l + endTag + r;
+ cursorPos = startPos + endTag.length;
+ t.closeTag(element, ed);
+ }
+ }
+
+ canvas.focus();
+ canvas.selectionStart = cursorPos;
+ canvas.selectionEnd = cursorPos;
+ canvas.scrollTop = scrollTop;
+ } else { // other browsers?
+ if ( !endTag ) {
+ canvas.value += t.tagStart;
+ } else if ( t.isOpen(ed) !== false ) {
+ canvas.value += t.tagStart;
+ t.openTag(element, ed);
+ } else {
+ canvas.value += endTag;
+ t.closeTag(element, ed);
+ }
+ canvas.focus();
+ }
+ };
+
+ // removed
+ qt.SpellButton = function() {};
+
+ // the close tags button
+ qt.CloseButton = function() {
+ qt.Button.call(this, 'close', quicktagsL10n.closeTags, '', quicktagsL10n.closeAllOpenTags);
+ };
+
+ qt.CloseButton.prototype = new qt.Button();
+
+ qt._close = function(e, c, ed) {
+ var button, element, tbo = ed.openTags;
+
+ if ( tbo ) {
+ while ( tbo.length > 0 ) {
+ button = ed.getButton(tbo[tbo.length - 1]);
+ element = document.getElementById(ed.name + '_' + button.id);
+
+ if ( e )
+ button.callback.call(button, element, c, ed);
+ else
+ button.closeTag(element, ed);
+ }
+ }
+ };
+
+ qt.CloseButton.prototype.callback = qt._close;
+
+ qt.closeAllTags = function(editor_id) {
+ var ed = this.getInstance(editor_id);
+ qt._close('', ed.canvas, ed);
+ };
+
+ // the link button
+ qt.LinkButton = function() {
+ qt.TagButton.call(this, 'link', 'link', '', '</a>', 'a');
+ };
+ qt.LinkButton.prototype = new qt.TagButton();
+ qt.LinkButton.prototype.callback = function(e, c, ed, defaultValue) {
+ var URL, t = this;
+
+ if ( typeof(wpLink) != 'undefined' ) {
+ wpLink.open();
+ return;
+ }
+
+ if ( ! defaultValue )
+ defaultValue = 'http://';
+
+ if ( t.isOpen(ed) === false ) {
+ URL = prompt(quicktagsL10n.enterURL, defaultValue);
+ if ( URL ) {
+ t.tagStart = '<a href="' + URL + '">';
+ qt.TagButton.prototype.callback.call(t, e, c, ed);
+ }
+ } else {
+ qt.TagButton.prototype.callback.call(t, e, c, ed);
+ }
+ };
+
+ // the img button
+ qt.ImgButton = function() {
+ qt.TagButton.call(this, 'img', 'img', '', '', 'm');
+ };
+ qt.ImgButton.prototype = new qt.TagButton();
+ qt.ImgButton.prototype.callback = function(e, c, ed, defaultValue) {
+ if ( ! defaultValue ) {
+ defaultValue = 'http://';
+ }
+ var src = prompt(quicktagsL10n.enterImageURL, defaultValue), alt;
+ if ( src ) {
+ alt = prompt(quicktagsL10n.enterImageDescription, '');
+ this.tagStart = '<img src="' + src + '" alt="' + alt + '" />';
+ qt.TagButton.prototype.callback.call(this, e, c, ed);
+ }
+ };
+
+ qt.FullscreenButton = function() {
+ qt.Button.call(this, 'fullscreen', quicktagsL10n.fullscreen, 'f', quicktagsL10n.toggleFullscreen);
+ };
+ qt.FullscreenButton.prototype = new qt.Button();
+ qt.FullscreenButton.prototype.callback = function(e, c) {
+ if ( !c.id || typeof(fullscreen) == 'undefined' )
+ return;
+
+ fullscreen.on();
+ };
+
+ qt.TextDirectionButton = function() {
+ qt.Button.call(this, 'textdirection', quicktagsL10n.textdirection, '', quicktagsL10n.toggleTextdirection)
+ };
+ qt.TextDirectionButton.prototype = new qt.Button();
+ qt.TextDirectionButton.prototype.callback = function(e, c) {
+ var isRTL = ( 'rtl' == document.getElementsByTagName('html')[0].dir ),
+ currentDirection = c.style.direction;
+
+ if ( ! currentDirection )
+ currentDirection = ( isRTL ) ? 'rtl' : 'ltr';
+
+ c.style.direction = ( 'rtl' == currentDirection ) ? 'ltr' : 'rtl';
+ c.focus();
+ }
+
+ // ensure backward compatibility
+ edButtons[10] = new qt.TagButton('strong','b','<strong>','</strong>','b');
+ edButtons[20] = new qt.TagButton('em','i','<em>','</em>','i'),
+ edButtons[30] = new qt.LinkButton(), // special case
+ edButtons[40] = new qt.TagButton('block','b-quote','\n\n<blockquote>','</blockquote>\n\n','q'),
+ edButtons[50] = new qt.TagButton('del','del','<del datetime="' + _datetime + '">','</del>','d'),
+ edButtons[60] = new qt.TagButton('ins','ins','<ins datetime="' + _datetime + '">','</ins>','s'),
+ edButtons[70] = new qt.ImgButton(), // special case
+ edButtons[80] = new qt.TagButton('ul','ul','<ul>\n','</ul>\n\n','u'),
+ edButtons[90] = new qt.TagButton('ol','ol','<ol>\n','</ol>\n\n','o'),
+ edButtons[100] = new qt.TagButton('li','li','\t<li>','</li>\n','l'),
+ edButtons[110] = new qt.TagButton('code','code','<code>','</code>','c'),
+ edButtons[120] = new qt.TagButton('more','more','<!--more-->','','t'),
+ edButtons[140] = new qt.CloseButton()
+
+})();
diff --git a/src/wp-includes/js/shortcode.js b/src/wp-includes/js/shortcode.js
new file mode 100644
index 0000000000..0f83a445bc
--- /dev/null
+++ b/src/wp-includes/js/shortcode.js
@@ -0,0 +1,342 @@
+// Utility functions for parsing and handling shortcodes in Javascript.
+
+// Ensure the global `wp` object exists.
+window.wp = window.wp || {};
+
+(function(){
+ wp.shortcode = {
+ // ### Find the next matching shortcode
+ //
+ // Given a shortcode `tag`, a block of `text`, and an optional starting
+ // `index`, returns the next matching shortcode or `undefined`.
+ //
+ // Shortcodes are formatted as an object that contains the match
+ // `content`, the matching `index`, and the parsed `shortcode` object.
+ next: function( tag, text, index ) {
+ var re = wp.shortcode.regexp( tag ),
+ match, result;
+
+ re.lastIndex = index || 0;
+ match = re.exec( text );
+
+ if ( ! match )
+ return;
+
+ // If we matched an escaped shortcode, try again.
+ if ( match[1] === '[' && match[7] === ']' )
+ return wp.shortcode.next( tag, text, re.lastIndex );
+
+ result = {
+ index: match.index,
+ content: match[0],
+ shortcode: wp.shortcode.fromMatch( match )
+ };
+
+ // If we matched a leading `[`, strip it from the match
+ // and increment the index accordingly.
+ if ( match[1] ) {
+ result.match = result.match.slice( 1 );
+ result.index++;
+ }
+
+ // If we matched a trailing `]`, strip it from the match.
+ if ( match[7] )
+ result.match = result.match.slice( 0, -1 );
+
+ return result;
+ },
+
+ // ### Replace matching shortcodes in a block of text
+ //
+ // Accepts a shortcode `tag`, content `text` to scan, and a `callback`
+ // to process the shortcode matches and return a replacement string.
+ // Returns the `text` with all shortcodes replaced.
+ //
+ // Shortcode matches are objects that contain the shortcode `tag`,
+ // a shortcode `attrs` object, the `content` between shortcode tags,
+ // and a boolean flag to indicate if the match was a `single` tag.
+ replace: function( tag, text, callback ) {
+ return text.replace( wp.shortcode.regexp( tag ), function( match, left, tag, attrs, slash, content, closing, right, offset ) {
+ // If both extra brackets exist, the shortcode has been
+ // properly escaped.
+ if ( left === '[' && right === ']' )
+ return match;
+
+ // Create the match object and pass it through the callback.
+ var result = callback( wp.shortcode.fromMatch( arguments ) );
+
+ // Make sure to return any of the extra brackets if they
+ // weren't used to escape the shortcode.
+ return result ? left + result + right : match;
+ });
+ },
+
+ // ### Generate a string from shortcode parameters
+ //
+ // Creates a `wp.shortcode` instance and returns a string.
+ //
+ // Accepts the same `options` as the `wp.shortcode()` constructor,
+ // containing a `tag` string, a string or object of `attrs`, a boolean
+ // indicating whether to format the shortcode using a `single` tag, and a
+ // `content` string.
+ string: function( options ) {
+ return new wp.shortcode( options ).string();
+ },
+
+ // ### Generate a RegExp to identify a shortcode
+ //
+ // The base regex is functionally equivalent to the one found in
+ // `get_shortcode_regex()` in `wp-includes/shortcodes.php`.
+ //
+ // Capture groups:
+ //
+ // 1. An extra `[` to allow for escaping shortcodes with double `[[]]`
+ // 2. The shortcode name
+ // 3. The shortcode argument list
+ // 4. The self closing `/`
+ // 5. The content of a shortcode when it wraps some content.
+ // 6. The closing tag.
+ // 7. An extra `]` to allow for escaping shortcodes with double `[[]]`
+ regexp: _.memoize( function( tag ) {
+ return new RegExp( '\\[(\\[?)(' + tag + ')(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)', 'g' );
+ }),
+
+
+ // ### Parse shortcode attributes
+ //
+ // Shortcodes accept many types of attributes. These can chiefly be
+ // divided into named and numeric attributes:
+ //
+ // Named attributes are assigned on a key/value basis, while numeric
+ // attributes are treated as an array.
+ //
+ // Named attributes can be formatted as either `name="value"`,
+ // `name='value'`, or `name=value`. Numeric attributes can be formatted
+ // as `"value"` or just `value`.
+ attrs: _.memoize( function( text ) {
+ var named = {},
+ numeric = [],
+ pattern, match;
+
+ // This regular expression is reused from `shortcode_parse_atts()`
+ // in `wp-includes/shortcodes.php`.
+ //
+ // Capture groups:
+ //
+ // 1. An attribute name, that corresponds to...
+ // 2. a value in double quotes.
+ // 3. An attribute name, that corresponds to...
+ // 4. a value in single quotes.
+ // 5. An attribute name, that corresponds to...
+ // 6. an unquoted value.
+ // 7. A numeric attribute in double quotes.
+ // 8. An unquoted numeric attribute.
+ pattern = /(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/g;
+
+ // Map zero-width spaces to actual spaces.
+ text = text.replace( /[\u00a0\u200b]/g, ' ' );
+
+ // Match and normalize attributes.
+ while ( (match = pattern.exec( text )) ) {
+ if ( match[1] ) {
+ named[ match[1].toLowerCase() ] = match[2];
+ } else if ( match[3] ) {
+ named[ match[3].toLowerCase() ] = match[4];
+ } else if ( match[5] ) {
+ named[ match[5].toLowerCase() ] = match[6];
+ } else if ( match[7] ) {
+ numeric.push( match[7] );
+ } else if ( match[8] ) {
+ numeric.push( match[8] );
+ }
+ }
+
+ return {
+ named: named,
+ numeric: numeric
+ };
+ }),
+
+ // ### Generate a Shortcode Object from a RegExp match
+ // Accepts a `match` object from calling `regexp.exec()` on a `RegExp`
+ // generated by `wp.shortcode.regexp()`. `match` can also be set to the
+ // `arguments` from a callback passed to `regexp.replace()`.
+ fromMatch: function( match ) {
+ var type;
+
+ if ( match[4] )
+ type = 'self-closing';
+ else if ( match[6] )
+ type = 'closed';
+ else
+ type = 'single';
+
+ return new wp.shortcode({
+ tag: match[2],
+ attrs: match[3],
+ type: type,
+ content: match[5]
+ });
+ }
+ };
+
+
+ // Shortcode Objects
+ // -----------------
+ //
+ // Shortcode objects are generated automatically when using the main
+ // `wp.shortcode` methods: `next()`, `replace()`, and `string()`.
+ //
+ // To access a raw representation of a shortcode, pass an `options` object,
+ // containing a `tag` string, a string or object of `attrs`, a string
+ // indicating the `type` of the shortcode ('single', 'self-closing', or
+ // 'closed'), and a `content` string.
+ wp.shortcode = _.extend( function( options ) {
+ _.extend( this, _.pick( options || {}, 'tag', 'attrs', 'type', 'content' ) );
+
+ var attrs = this.attrs;
+
+ // Ensure we have a correctly formatted `attrs` object.
+ this.attrs = {
+ named: {},
+ numeric: []
+ };
+
+ if ( ! attrs )
+ return;
+
+ // Parse a string of attributes.
+ if ( _.isString( attrs ) ) {
+ this.attrs = wp.shortcode.attrs( attrs );
+
+ // Identify a correctly formatted `attrs` object.
+ } else if ( _.isEqual( _.keys( attrs ), [ 'named', 'numeric' ] ) ) {
+ this.attrs = attrs;
+
+ // Handle a flat object of attributes.
+ } else {
+ _.each( options.attrs, function( value, key ) {
+ this.set( key, value );
+ }, this );
+ }
+ }, wp.shortcode );
+
+ _.extend( wp.shortcode.prototype, {
+ // ### Get a shortcode attribute
+ //
+ // Automatically detects whether `attr` is named or numeric and routes
+ // it accordingly.
+ get: function( attr ) {
+ return this.attrs[ _.isNumber( attr ) ? 'numeric' : 'named' ][ attr ];
+ },
+
+ // ### Set a shortcode attribute
+ //
+ // Automatically detects whether `attr` is named or numeric and routes
+ // it accordingly.
+ set: function( attr, value ) {
+ this.attrs[ _.isNumber( attr ) ? 'numeric' : 'named' ][ attr ] = value;
+ return this;
+ },
+
+ // ### Transform the shortcode match into a string
+ string: function() {
+ var text = '[' + this.tag;
+
+ _.each( this.attrs.numeric, function( value ) {
+ if ( /\s/.test( value ) )
+ text += ' "' + value + '"';
+ else
+ text += ' ' + value;
+ });
+
+ _.each( this.attrs.named, function( value, name ) {
+ text += ' ' + name + '="' + value + '"';
+ });
+
+ // If the tag is marked as `single` or `self-closing`, close the
+ // tag and ignore any additional content.
+ if ( 'single' === this.type )
+ return text + ']';
+ else if ( 'self-closing' === this.type )
+ return text + ' /]';
+
+ // Complete the opening tag.
+ text += ']';
+
+ if ( this.content )
+ text += this.content;
+
+ // Add the closing tag.
+ return text + '[/' + this.tag + ']';
+ }
+ });
+}());
+
+// HTML utility functions
+// ----------------------
+//
+// Experimental. These functions may change or be removed in the future.
+(function(){
+ wp.html = _.extend( wp.html || {}, {
+ // ### Parse HTML attributes.
+ //
+ // Converts `content` to a set of parsed HTML attributes.
+ // Utilizes `wp.shortcode.attrs( content )`, which is a valid superset of
+ // the HTML attribute specification. Reformats the attributes into an
+ // object that contains the `attrs` with `key:value` mapping, and a record
+ // of the attributes that were entered using `empty` attribute syntax (i.e.
+ // with no value).
+ attrs: function( content ) {
+ var result, attrs;
+
+ // If `content` ends in a slash, strip it.
+ if ( '/' === content[ content.length - 1 ] )
+ content = content.slice( 0, -1 );
+
+ result = wp.shortcode.attrs( content );
+ attrs = result.named;
+
+ _.each( result.numeric, function( key ) {
+ if ( /\s/.test( key ) )
+ return;
+
+ attrs[ key ] = '';
+ });
+
+ return attrs;
+ },
+
+ // ### Convert an HTML-representation of an object to a string.
+ string: function( options ) {
+ var text = '<' + options.tag,
+ content = options.content || '';
+
+ _.each( options.attrs, function( value, attr ) {
+ text += ' ' + attr;
+
+ // Use empty attribute notation where possible.
+ if ( '' === value )
+ return;
+
+ // Convert boolean values to strings.
+ if ( _.isBoolean( value ) )
+ value = value ? 'true' : 'false';
+
+ text += '="' + value + '"';
+ });
+
+ // Return the result if it is a self-closing tag.
+ if ( options.single )
+ return text + ' />';
+
+ // Complete the opening tag.
+ text += '>';
+
+ // If `content` is an object, recursively call this function.
+ text += _.isObject( content ) ? wp.html.string( content ) : content;
+
+ return text + '</' + options.tag + '>';
+ }
+ });
+}()); \ No newline at end of file
diff --git a/src/wp-includes/js/swfobject.js b/src/wp-includes/js/swfobject.js
new file mode 100644
index 0000000000..87e61553b3
--- /dev/null
+++ b/src/wp-includes/js/swfobject.js
@@ -0,0 +1,4 @@
+/* SWFObject v2.2 <http://code.google.com/p/swfobject/>
+ is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+*/
+var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y<X;Y++){U[Y]()}}function K(X){if(J){X()}else{U[U.length]=X}}function s(Y){if(typeof O.addEventListener!=D){O.addEventListener("load",Y,false)}else{if(typeof j.addEventListener!=D){j.addEventListener("load",Y,false)}else{if(typeof O.attachEvent!=D){i(O,"onload",Y)}else{if(typeof O.onload=="function"){var X=O.onload;O.onload=function(){X();Y()}}else{O.onload=Y}}}}}function h(){if(T){V()}else{H()}}function V(){var X=j.getElementsByTagName("body")[0];var aa=C(r);aa.setAttribute("type",q);var Z=X.appendChild(aa);if(Z){var Y=0;(function(){if(typeof Z.GetVariable!=D){var ab=Z.GetVariable("$version");if(ab){ab=ab.split(" ")[1].split(",");M.pv=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}else{if(Y<10){Y++;setTimeout(arguments.callee,10);return}}X.removeChild(aa);Z=null;H()})()}else{H()}}function H(){var ag=o.length;if(ag>0){for(var af=0;af<ag;af++){var Y=o[af].id;var ab=o[af].callbackFn;var aa={success:false,id:Y};if(M.pv[0]>0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad<ac;ad++){if(X[ad].getAttribute("name").toLowerCase()!="movie"){ah[X[ad].getAttribute("name")]=X[ad].getAttribute("value")}}P(ai,ah,Y,ab)}else{p(ae);if(ab){ab(aa)}}}}}else{w(Y,true);if(ab){var Z=z(Y);if(Z&&typeof Z.SetVariable!=D){aa.success=true;aa.ref=Z}ab(aa)}}}}}function z(aa){var X=null;var Y=c(aa);if(Y&&Y.nodeName=="OBJECT"){if(typeof Y.SetVariable!=D){X=Y}else{var Z=Y.getElementsByTagName(r)[0];if(Z){X=Z}}}return X}function A(){return !a&&F("6.0.65")&&(M.win||M.mac)&&!(M.wk&&M.wk<312)}function P(aa,ab,X,Z){a=true;E=Z||null;B={success:false,id:X};var ae=c(X);if(ae){if(ae.nodeName=="OBJECT"){l=g(ae);Q=null}else{l=ae;Q=X}aa.id=R;if(typeof aa.width==D||(!/%$/.test(aa.width)&&parseInt(aa.width,10)<310)){aa.width="310"}if(typeof aa.height==D||(!/%$/.test(aa.height)&&parseInt(aa.height,10)<137)){aa.height="137"}j.title=j.title.slice(0,47)+" - Flash Player Installation";var ad=M.ie&&M.win?"ActiveX":"PlugIn",ac="MMredirectURL="+encodeURI(O.location).toString().replace(/&/g,"%26")+"&MMplayerType="+ad+"&MMdoctitle="+j.title;if(typeof ab.flashvars!=D){ab.flashvars+="&"+ac}else{ab.flashvars=ac}if(M.ie&&M.win&&ae.readyState!=4){var Y=C("div");X+="SWFObjectNew";Y.setAttribute("id",X);ae.parentNode.insertBefore(Y,ae);ae.style.display="none";(function(){if(ae.readyState==4){ae.parentNode.removeChild(ae)}else{setTimeout(arguments.callee,10)}})()}u(aa,ab,X)}}function p(Y){if(M.ie&&M.win&&Y.readyState!=4){var X=C("div");Y.parentNode.insertBefore(X,Y);X.parentNode.replaceChild(g(Y),X);Y.style.display="none";(function(){if(Y.readyState==4){Y.parentNode.removeChild(Y)}else{setTimeout(arguments.callee,10)}})()}else{Y.parentNode.replaceChild(g(Y),Y)}}function g(ab){var aa=C("div");if(M.win&&M.ie){aa.innerHTML=ab.innerHTML}else{var Y=ab.getElementsByTagName(r)[0];if(Y){var ad=Y.childNodes;if(ad){var X=ad.length;for(var Z=0;Z<X;Z++){if(!(ad[Z].nodeType==1&&ad[Z].nodeName=="PARAM")&&!(ad[Z].nodeType==8)){aa.appendChild(ad[Z].cloneNode(true))}}}}}return aa}function u(ai,ag,Y){var X,aa=c(Y);if(M.wk&&M.wk<312){return X}if(aa){if(typeof ai.id==D){ai.id=Y}if(M.ie&&M.win){var ah="";for(var ae in ai){if(ai[ae]!=Object.prototype[ae]){if(ae.toLowerCase()=="data"){ag.movie=ai[ae]}else{if(ae.toLowerCase()=="styleclass"){ah+=' class="'+ai[ae]+'"'}else{if(ae.toLowerCase()!="classid"){ah+=" "+ae+'="'+ai[ae]+'"'}}}}}var af="";for(var ad in ag){if(ag[ad]!=Object.prototype[ad]){af+='<param name="'+ad+'" value="'+ag[ad]+'" />'}}aa.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+ah+">"+af+"</object>";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab<ac;ab++){I[ab][0].detachEvent(I[ab][1],I[ab][2])}var Z=N.length;for(var aa=0;aa<Z;aa++){y(N[aa])}for(var Y in M){M[Y]=null}M=null;for(var X in swfobject){swfobject[X]=null}swfobject=null})}}();return{registerObject:function(ab,X,aa,Z){if(M.w3&&ab&&X){var Y={};Y.id=ab;Y.swfVersion=X;Y.expressInstall=aa;Y.callbackFn=Z;o[o.length]=Y;w(ab,false)}else{if(Z){Z({success:false,id:ab})}}},getObjectById:function(X){if(M.w3){return z(X)}},embedSWF:function(ab,ah,ae,ag,Y,aa,Z,ad,af,ac){var X={success:false,id:ah};if(M.w3&&!(M.wk&&M.wk<312)&&ab&&ah&&ae&&ag&&Y){w(ah,false);K(function(){ae+="";ag+="";var aj={};if(af&&typeof af===r){for(var al in af){aj[al]=af[al]}}aj.data=ab;aj.width=ae;aj.height=ag;var am={};if(ad&&typeof ad===r){for(var ak in ad){am[ak]=ad[ak]}}if(Z&&typeof Z===r){for(var ai in Z){if(typeof am.flashvars!=D){am.flashvars+="&"+ai+"="+Z[ai]}else{am.flashvars=ai+"="+Z[ai]}}}if(F(Y)){var an=u(aj,am,ah);if(aj.id==ah){w(ah,true)}X.success=true;X.ref=an}else{if(aa&&A()){aj.data=aa;P(aj,am,ah,ac);return}else{w(ah,true)}}if(ac){ac(X)}})}else{if(ac){ac(X)}}},switchOffAutoHideShow:function(){m=false},ua:M,getFlashPlayerVersion:function(){return{major:M.pv[0],minor:M.pv[1],release:M.pv[2]}},hasFlashPlayerVersion:F,createSWF:function(Z,Y,X){if(M.w3){return u(Z,Y,X)}else{return undefined}},showExpressInstall:function(Z,aa,X,Y){if(M.w3&&A()){P(Z,aa,X,Y)}},removeSWF:function(X){if(M.w3){y(X)}},createCSS:function(aa,Z,Y,X){if(M.w3){v(aa,Z,Y,X)}},addDomLoadEvent:K,addLoadEvent:s,getQueryParamValue:function(aa){var Z=j.location.search||j.location.hash;if(Z){if(/\?/.test(Z)){Z=Z.split("?")[1]}if(aa==null){return L(Z)}var Y=Z.split("&");for(var X=0;X<Y.length;X++){if(Y[X].substring(0,Y[X].indexOf("="))==aa){return L(Y[X].substring((Y[X].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(a){var X=c(R);if(X&&l){X.parentNode.replaceChild(l,X);if(Q){w(Q,true);if(M.ie&&M.win){l.style.display="block"}}if(E){E(B)}}a=false}}}}(); \ No newline at end of file
diff --git a/src/wp-includes/js/swfupload/handlers.js b/src/wp-includes/js/swfupload/handlers.js
new file mode 100644
index 0000000000..f38172c38d
--- /dev/null
+++ b/src/wp-includes/js/swfupload/handlers.js
@@ -0,0 +1,375 @@
+var topWin = window.dialogArguments || opener || parent || top;
+
+function fileDialogStart() {
+ jQuery("#media-upload-error").empty();
+}
+
+// progress and success handlers for media multi uploads
+function fileQueued(fileObj) {
+ // Get rid of unused form
+ jQuery('.media-blank').remove();
+ // Collapse a single item
+ if ( jQuery('form.type-form #media-items').children().length == 1 && jQuery('.hidden', '#media-items').length > 0 ) {
+ jQuery('.describe-toggle-on').show();
+ jQuery('.describe-toggle-off').hide();
+ jQuery('.slidetoggle').slideUp(200).siblings().removeClass('hidden');
+ }
+ // Create a progress bar containing the filename
+ jQuery('<div class="media-item">')
+ .attr( 'id', 'media-item-' + fileObj.id )
+ .addClass('child-of-' + post_id)
+ .append('<div class="progress"><div class="bar"></div></div>',
+ jQuery('<div class="filename original"><span class="percent"></span>').text( ' ' + fileObj.name ))
+ .appendTo( jQuery('#media-items' ) );
+ // Display the progress div
+ jQuery('.progress', '#media-item-' + fileObj.id).show();
+
+ // Disable submit and enable cancel
+ jQuery('#insert-gallery').prop('disabled', true);
+ jQuery('#cancel-upload').prop('disabled', false);
+}
+
+function uploadStart(fileObj) {
+ try {
+ if ( typeof topWin.tb_remove != 'undefined' )
+ topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove);
+ } catch(e){}
+
+ return true;
+}
+
+function uploadProgress(fileObj, bytesDone, bytesTotal) {
+ // Lengthen the progress bar
+ var w = jQuery('#media-items').width() - 2, item = jQuery('#media-item-' + fileObj.id);
+ jQuery('.bar', item).width( w * bytesDone / bytesTotal );
+ jQuery('.percent', item).html( Math.ceil(bytesDone / bytesTotal * 100) + '%' );
+
+ if ( bytesDone == bytesTotal )
+ jQuery('.bar', item).html('<strong class="crunching">' + swfuploadL10n.crunching + '</strong>');
+}
+
+function prepareMediaItem(fileObj, serverData) {
+ var f = ( typeof shortform == 'undefined' ) ? 1 : 2, item = jQuery('#media-item-' + fileObj.id);
+ // Move the progress bar to 100%
+ jQuery('.bar', item).remove();
+ jQuery('.progress', item).hide();
+
+ try {
+ if ( typeof topWin.tb_remove != 'undefined' )
+ topWin.jQuery('#TB_overlay').click(topWin.tb_remove);
+ } catch(e){}
+
+ // Old style: Append the HTML returned by the server -- thumbnail and form inputs
+ if ( isNaN(serverData) || !serverData ) {
+ item.append(serverData);
+ prepareMediaItemInit(fileObj);
+ }
+ // New style: server data is just the attachment ID, fetch the thumbnail and form html from the server
+ else {
+ item.load('async-upload.php', {attachment_id:serverData, fetch:f}, function(){prepareMediaItemInit(fileObj);updateMediaForm()});
+ }
+}
+
+function prepareMediaItemInit(fileObj) {
+ var item = jQuery('#media-item-' + fileObj.id);
+ // Clone the thumbnail as a "pinkynail" -- a tiny image to the left of the filename
+ jQuery('.thumbnail', item).clone().attr('class', 'pinkynail toggle').prependTo(item);
+
+ // Replace the original filename with the new (unique) one assigned during upload
+ jQuery('.filename.original', item).replaceWith( jQuery('.filename.new', item) );
+
+ // Also bind toggle to the links
+ jQuery('a.toggle', item).click(function(){
+ jQuery(this).siblings('.slidetoggle').slideToggle(350, function(){
+ var w = jQuery(window).height(), t = jQuery(this).offset().top, h = jQuery(this).height(), b;
+
+ if ( w && t && h ) {
+ b = t + h;
+
+ if ( b > w && (h + 48) < w )
+ window.scrollBy(0, b - w + 13);
+ else if ( b > w )
+ window.scrollTo(0, t - 36);
+ }
+ });
+ jQuery(this).siblings('.toggle').andSelf().toggle();
+ jQuery(this).siblings('a.toggle').focus();
+ return false;
+ });
+
+ // Bind AJAX to the new Delete button
+ jQuery('a.delete', item).click(function(){
+ // Tell the server to delete it. TODO: handle exceptions
+ jQuery.ajax({
+ url: ajaxurl,
+ type: 'post',
+ success: deleteSuccess,
+ error: deleteError,
+ id: fileObj.id,
+ data: {
+ id : this.id.replace(/[^0-9]/g, ''),
+ action : 'trash-post',
+ _ajax_nonce : this.href.replace(/^.*wpnonce=/,'')
+ }
+ });
+ return false;
+ });
+
+ // Bind AJAX to the new Undo button
+ jQuery('a.undo', item).click(function(){
+ // Tell the server to untrash it. TODO: handle exceptions
+ jQuery.ajax({
+ url: ajaxurl,
+ type: 'post',
+ id: fileObj.id,
+ data: {
+ id : this.id.replace(/[^0-9]/g,''),
+ action: 'untrash-post',
+ _ajax_nonce: this.href.replace(/^.*wpnonce=/,'')
+ },
+ success: function(data, textStatus){
+ var item = jQuery('#media-item-' + fileObj.id);
+
+ if ( type = jQuery('#type-of-' + fileObj.id).val() )
+ jQuery('#' + type + '-counter').text(jQuery('#' + type + '-counter').text()-0+1);
+ if ( item.hasClass('child-of-'+post_id) )
+ jQuery('#attachments-count').text(jQuery('#attachments-count').text()-0+1);
+
+ jQuery('.filename .trashnotice', item).remove();
+ jQuery('.filename .title', item).css('font-weight','normal');
+ jQuery('a.undo', item).addClass('hidden');
+ jQuery('a.describe-toggle-on, .menu_order_input', item).show();
+ item.css( {backgroundColor:'#ceb'} ).animate( {backgroundColor: '#fff'}, { queue: false, duration: 500, complete: function(){ jQuery(this).css({backgroundColor:''}); } }).removeClass('undo');
+ }
+ });
+ return false;
+ });
+
+ // Open this item if it says to start open (e.g. to display an error)
+ jQuery('#media-item-' + fileObj.id + '.startopen').removeClass('startopen').slideToggle(500).siblings('.toggle').toggle();
+}
+
+function itemAjaxError(id, html) {
+ var item = jQuery('#media-item-' + id);
+ var filename = jQuery('.filename', item).text();
+
+ item.html('<div class="error-div">'
+ + '<a class="dismiss" href="#">' + swfuploadL10n.dismiss + '</a>'
+ + '<strong>' + swfuploadL10n.error_uploading.replace('%s', filename) + '</strong><br />'
+ + html
+ + '</div>');
+ item.find('a.dismiss').click(function(){jQuery(this).parents('.media-item').slideUp(200, function(){jQuery(this).remove();})});
+}
+
+function deleteSuccess(data, textStatus) {
+ if ( data == '-1' )
+ return itemAjaxError(this.id, 'You do not have permission. Has your session expired?');
+ if ( data == '0' )
+ return itemAjaxError(this.id, 'Could not be deleted. Has it been deleted already?');
+
+ var id = this.id, item = jQuery('#media-item-' + id);
+
+ // Decrement the counters.
+ if ( type = jQuery('#type-of-' + id).val() )
+ jQuery('#' + type + '-counter').text( jQuery('#' + type + '-counter').text() - 1 );
+ if ( item.hasClass('child-of-'+post_id) )
+ jQuery('#attachments-count').text( jQuery('#attachments-count').text() - 1 );
+
+ if ( jQuery('form.type-form #media-items').children().length == 1 && jQuery('.hidden', '#media-items').length > 0 ) {
+ jQuery('.toggle').toggle();
+ jQuery('.slidetoggle').slideUp(200).siblings().removeClass('hidden');
+ }
+
+ // Vanish it.
+ jQuery('.toggle', item).toggle();
+ jQuery('.slidetoggle', item).slideUp(200).siblings().removeClass('hidden');
+ item.css( {backgroundColor:'#faa'} ).animate( {backgroundColor:'#f4f4f4'}, {queue:false, duration:500} ).addClass('undo');
+
+ jQuery('.filename:empty', item).remove();
+ jQuery('.filename .title', item).css('font-weight','bold');
+ jQuery('.filename', item).append('<span class="trashnotice"> ' + swfuploadL10n.deleted + ' </span>').siblings('a.toggle').hide();
+ jQuery('.filename', item).append( jQuery('a.undo', item).removeClass('hidden') );
+ jQuery('.menu_order_input', item).hide();
+
+ return;
+}
+
+function deleteError(X, textStatus, errorThrown) {
+ // TODO
+}
+
+function updateMediaForm() {
+ var one = jQuery('form.type-form #media-items').children(), items = jQuery('#media-items').children();
+
+ // Just one file, no need for collapsible part
+ if ( one.length == 1 ) {
+ jQuery('.slidetoggle', one).slideDown(500).siblings().addClass('hidden').filter('.toggle').toggle();
+ }
+
+ // Only show Save buttons when there is at least one file.
+ if ( items.not('.media-blank').length > 0 )
+ jQuery('.savebutton').show();
+ else
+ jQuery('.savebutton').hide();
+
+ // Only show Gallery button when there are at least two files.
+ if ( items.length > 1 )
+ jQuery('.insert-gallery').show();
+ else
+ jQuery('.insert-gallery').hide();
+}
+
+function uploadSuccess(fileObj, serverData) {
+ // if async-upload returned an error message, place it in the media item div and return
+ if ( serverData.match('media-upload-error') ) {
+ jQuery('#media-item-' + fileObj.id).html(serverData);
+ return;
+ }
+
+ prepareMediaItem(fileObj, serverData);
+ updateMediaForm();
+
+ // Increment the counter.
+ if ( jQuery('#media-item-' + fileObj.id).hasClass('child-of-' + post_id) )
+ jQuery('#attachments-count').text(1 * jQuery('#attachments-count').text() + 1);
+}
+
+function uploadComplete(fileObj) {
+ // If no more uploads queued, enable the submit button
+ if ( swfu.getStats().files_queued == 0 ) {
+ jQuery('#cancel-upload').prop('disabled', true);
+ jQuery('#insert-gallery').prop('disabled', false);
+ }
+}
+
+
+// wp-specific error handlers
+
+// generic message
+function wpQueueError(message) {
+ jQuery('#media-upload-error').show().text(message);
+}
+
+// file-specific message
+function wpFileError(fileObj, message) {
+ var item = jQuery('#media-item-' + fileObj.id);
+ var filename = jQuery('.filename', item).text();
+
+ item.html('<div class="error-div">'
+ + '<a class="dismiss" href="#">' + swfuploadL10n.dismiss + '</a>'
+ + '<strong>' + swfuploadL10n.error_uploading.replace('%s', filename) + '</strong><br />'
+ + message
+ + '</div>');
+ item.find('a.dismiss').click(function(){jQuery(this).parents('.media-item').slideUp(200, function(){jQuery(this).remove();})});
+}
+
+function fileQueueError(fileObj, error_code, message) {
+ // Handle this error separately because we don't want to create a FileProgress element for it.
+ if ( error_code == SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED ) {
+ wpQueueError(swfuploadL10n.queue_limit_exceeded);
+ }
+ else if ( error_code == SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT ) {
+ fileQueued(fileObj);
+ wpFileError(fileObj, swfuploadL10n.file_exceeds_size_limit);
+ }
+ else if ( error_code == SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE ) {
+ fileQueued(fileObj);
+ wpFileError(fileObj, swfuploadL10n.zero_byte_file);
+ }
+ else if ( error_code == SWFUpload.QUEUE_ERROR.INVALID_FILETYPE ) {
+ fileQueued(fileObj);
+ wpFileError(fileObj, swfuploadL10n.invalid_filetype);
+ }
+ else {
+ wpQueueError(swfuploadL10n.default_error);
+ }
+}
+
+function fileDialogComplete(num_files_queued) {
+ try {
+ if (num_files_queued > 0) {
+ this.startUpload();
+ }
+ } catch (ex) {
+ this.debug(ex);
+ }
+}
+
+function switchUploader(s) {
+ var f = document.getElementById(swfu.customSettings.swfupload_element_id), h = document.getElementById(swfu.customSettings.degraded_element_id);
+ if ( s ) {
+ f.style.display = 'block';
+ h.style.display = 'none';
+ } else {
+ f.style.display = 'none';
+ h.style.display = 'block';
+ }
+}
+
+function swfuploadPreLoad() {
+ if ( !uploaderMode ) {
+ switchUploader(1);
+ } else {
+ switchUploader(0);
+ }
+}
+
+function swfuploadLoadFailed() {
+ switchUploader(0);
+ jQuery('.upload-html-bypass').hide();
+}
+
+function uploadError(fileObj, errorCode, message) {
+
+ switch (errorCode) {
+ case SWFUpload.UPLOAD_ERROR.MISSING_UPLOAD_URL:
+ wpFileError(fileObj, swfuploadL10n.missing_upload_url);
+ break;
+ case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:
+ wpFileError(fileObj, swfuploadL10n.upload_limit_exceeded);
+ break;
+ case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:
+ wpQueueError(swfuploadL10n.http_error);
+ break;
+ case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:
+ wpQueueError(swfuploadL10n.upload_failed);
+ break;
+ case SWFUpload.UPLOAD_ERROR.IO_ERROR:
+ wpQueueError(swfuploadL10n.io_error);
+ break;
+ case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:
+ wpQueueError(swfuploadL10n.security_error);
+ break;
+ case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:
+ case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:
+ jQuery('#media-item-' + fileObj.id).remove();
+ break;
+ default:
+ wpFileError(fileObj, swfuploadL10n.default_error);
+ }
+}
+
+function cancelUpload() {
+ swfu.cancelQueue();
+}
+
+// remember the last used image size, alignment and url
+jQuery(document).ready(function($){
+ $('input[type="radio"]', '#media-items').live('click', function(){
+ var tr = $(this).closest('tr');
+
+ if ( $(tr).hasClass('align') )
+ setUserSetting('align', $(this).val());
+ else if ( $(tr).hasClass('image-size') )
+ setUserSetting('imgsize', $(this).val());
+ });
+
+ $('button.button', '#media-items').live('click', function(){
+ var c = this.className || '';
+ c = c.match(/url([^ '"]+)/);
+ if ( c && c[1] ) {
+ setUserSetting('urlbutton', c[1]);
+ $(this).siblings('.urlfield').val( $(this).attr('title') );
+ }
+ });
+});
diff --git a/src/wp-includes/js/swfupload/handlers.min.js b/src/wp-includes/js/swfupload/handlers.min.js
new file mode 100644
index 0000000000..5aaa8ee2d9
--- /dev/null
+++ b/src/wp-includes/js/swfupload/handlers.min.js
@@ -0,0 +1 @@
+var topWin=window.dialogArguments||opener||parent||top;function fileDialogStart(){jQuery("#media-upload-error").empty()}function fileQueued(a){jQuery(".media-blank").remove();if(jQuery("form.type-form #media-items").children().length==1&&jQuery(".hidden","#media-items").length>0){jQuery(".describe-toggle-on").show();jQuery(".describe-toggle-off").hide();jQuery(".slidetoggle").slideUp(200).siblings().removeClass("hidden")}jQuery('<div class="media-item">').attr("id","media-item-"+a.id).addClass("child-of-"+post_id).append('<div class="progress"><div class="bar"></div></div>',jQuery('<div class="filename original"><span class="percent"></span>').text(" "+a.name)).appendTo(jQuery("#media-items"));jQuery(".progress","#media-item-"+a.id).show();jQuery("#insert-gallery").prop("disabled",true);jQuery("#cancel-upload").prop("disabled",false)}function uploadStart(a){try{if(typeof topWin.tb_remove!="undefined"){topWin.jQuery("#TB_overlay").unbind("click",topWin.tb_remove)}}catch(b){}return true}function uploadProgress(e,b,d){var a=jQuery("#media-items").width()-2,c=jQuery("#media-item-"+e.id);jQuery(".bar",c).width(a*b/d);jQuery(".percent",c).html(Math.ceil(b/d*100)+"%");if(b==d){jQuery(".bar",c).html('<strong class="crunching">'+swfuploadL10n.crunching+"</strong>")}}function prepareMediaItem(c,a){var d=(typeof shortform=="undefined")?1:2,b=jQuery("#media-item-"+c.id);jQuery(".bar",b).remove();jQuery(".progress",b).hide();try{if(typeof topWin.tb_remove!="undefined"){topWin.jQuery("#TB_overlay").click(topWin.tb_remove)}}catch(g){}if(isNaN(a)||!a){b.append(a);prepareMediaItemInit(c)}else{b.load("async-upload.php",{attachment_id:a,fetch:d},function(){prepareMediaItemInit(c);updateMediaForm()})}}function prepareMediaItemInit(b){var a=jQuery("#media-item-"+b.id);jQuery(".thumbnail",a).clone().attr("class","pinkynail toggle").prependTo(a);jQuery(".filename.original",a).replaceWith(jQuery(".filename.new",a));jQuery("a.toggle",a).click(function(){jQuery(this).siblings(".slidetoggle").slideToggle(350,function(){var d=jQuery(window).height(),e=jQuery(this).offset().top,f=jQuery(this).height(),c;if(d&&e&&f){c=e+f;if(c>d&&(f+48)<d){window.scrollBy(0,c-d+13)}else{if(c>d){window.scrollTo(0,e-36)}}}});jQuery(this).siblings(".toggle").andSelf().toggle();jQuery(this).siblings("a.toggle").focus();return false});jQuery("a.delete",a).click(function(){jQuery.ajax({url:ajaxurl,type:"post",success:deleteSuccess,error:deleteError,id:b.id,data:{id:this.id.replace(/[^0-9]/g,""),action:"trash-post",_ajax_nonce:this.href.replace(/^.*wpnonce=/,"")}});return false});jQuery("a.undo",a).click(function(){jQuery.ajax({url:ajaxurl,type:"post",id:b.id,data:{id:this.id.replace(/[^0-9]/g,""),action:"untrash-post",_ajax_nonce:this.href.replace(/^.*wpnonce=/,"")},success:function(d,e){var c=jQuery("#media-item-"+b.id);if(type=jQuery("#type-of-"+b.id).val()){jQuery("#"+type+"-counter").text(jQuery("#"+type+"-counter").text()-0+1)}if(c.hasClass("child-of-"+post_id)){jQuery("#attachments-count").text(jQuery("#attachments-count").text()-0+1)}jQuery(".filename .trashnotice",c).remove();jQuery(".filename .title",c).css("font-weight","normal");jQuery("a.undo",c).addClass("hidden");jQuery("a.describe-toggle-on, .menu_order_input",c).show();c.css({backgroundColor:"#ceb"}).animate({backgroundColor:"#fff"},{queue:false,duration:500,complete:function(){jQuery(this).css({backgroundColor:""})}}).removeClass("undo")}});return false});jQuery("#media-item-"+b.id+".startopen").removeClass("startopen").slideToggle(500).siblings(".toggle").toggle()}function itemAjaxError(d,b){var c=jQuery("#media-item-"+d);var a=jQuery(".filename",c).text();c.html('<div class="error-div"><a class="dismiss" href="#">'+swfuploadL10n.dismiss+"</a><strong>"+swfuploadL10n.error_uploading.replace("%s",a)+"</strong><br />"+b+"</div>");c.find("a.dismiss").click(function(){jQuery(this).parents(".media-item").slideUp(200,function(){jQuery(this).remove()})})}function deleteSuccess(b,d){if(b=="-1"){return itemAjaxError(this.id,"You do not have permission. Has your session expired?")}if(b=="0"){return itemAjaxError(this.id,"Could not be deleted. Has it been deleted already?")}var c=this.id,a=jQuery("#media-item-"+c);if(type=jQuery("#type-of-"+c).val()){jQuery("#"+type+"-counter").text(jQuery("#"+type+"-counter").text()-1)}if(a.hasClass("child-of-"+post_id)){jQuery("#attachments-count").text(jQuery("#attachments-count").text()-1)}if(jQuery("form.type-form #media-items").children().length==1&&jQuery(".hidden","#media-items").length>0){jQuery(".toggle").toggle();jQuery(".slidetoggle").slideUp(200).siblings().removeClass("hidden")}jQuery(".toggle",a).toggle();jQuery(".slidetoggle",a).slideUp(200).siblings().removeClass("hidden");a.css({backgroundColor:"#faa"}).animate({backgroundColor:"#f4f4f4"},{queue:false,duration:500}).addClass("undo");jQuery(".filename:empty",a).remove();jQuery(".filename .title",a).css("font-weight","bold");jQuery(".filename",a).append('<span class="trashnotice"> '+swfuploadL10n.deleted+" </span>").siblings("a.toggle").hide();jQuery(".filename",a).append(jQuery("a.undo",a).removeClass("hidden"));jQuery(".menu_order_input",a).hide();return}function deleteError(c,b,a){}function updateMediaForm(){var b=jQuery("form.type-form #media-items").children(),a=jQuery("#media-items").children();if(b.length==1){jQuery(".slidetoggle",b).slideDown(500).siblings().addClass("hidden").filter(".toggle").toggle()}if(a.not(".media-blank").length>0){jQuery(".savebutton").show()}else{jQuery(".savebutton").hide()}if(a.length>1){jQuery(".insert-gallery").show()}else{jQuery(".insert-gallery").hide()}}function uploadSuccess(b,a){if(a.match("media-upload-error")){jQuery("#media-item-"+b.id).html(a);return}prepareMediaItem(b,a);updateMediaForm();if(jQuery("#media-item-"+b.id).hasClass("child-of-"+post_id)){jQuery("#attachments-count").text(1*jQuery("#attachments-count").text()+1)}}function uploadComplete(a){if(swfu.getStats().files_queued==0){jQuery("#cancel-upload").prop("disabled",true);jQuery("#insert-gallery").prop("disabled",false)}}function wpQueueError(a){jQuery("#media-upload-error").show().text(a)}function wpFileError(d,c){var b=jQuery("#media-item-"+d.id);var a=jQuery(".filename",b).text();b.html('<div class="error-div"><a class="dismiss" href="#">'+swfuploadL10n.dismiss+"</a><strong>"+swfuploadL10n.error_uploading.replace("%s",a)+"</strong><br />"+c+"</div>");b.find("a.dismiss").click(function(){jQuery(this).parents(".media-item").slideUp(200,function(){jQuery(this).remove()})})}function fileQueueError(c,a,b){if(a==SWFUpload.QUEUE_ERROR.QUEUE_LIMIT_EXCEEDED){wpQueueError(swfuploadL10n.queue_limit_exceeded)}else{if(a==SWFUpload.QUEUE_ERROR.FILE_EXCEEDS_SIZE_LIMIT){fileQueued(c);wpFileError(c,swfuploadL10n.file_exceeds_size_limit)}else{if(a==SWFUpload.QUEUE_ERROR.ZERO_BYTE_FILE){fileQueued(c);wpFileError(c,swfuploadL10n.zero_byte_file)}else{if(a==SWFUpload.QUEUE_ERROR.INVALID_FILETYPE){fileQueued(c);wpFileError(c,swfuploadL10n.invalid_filetype)}else{wpQueueError(swfuploadL10n.default_error)}}}}}function fileDialogComplete(b){try{if(b>0){this.startUpload()}}catch(a){this.debug(a)}}function switchUploader(b){var c=document.getElementById(swfu.customSettings.swfupload_element_id),a=document.getElementById(swfu.customSettings.degraded_element_id);if(b){c.style.display="block";a.style.display="none"}else{c.style.display="none";a.style.display="block"}}function swfuploadPreLoad(){if(!uploaderMode){switchUploader(1)}else{switchUploader(0)}}function swfuploadLoadFailed(){switchUploader(0);jQuery(".upload-html-bypass").hide()}function uploadError(b,c,a){switch(c){case SWFUpload.UPLOAD_ERROR.MISSING_UPLOAD_URL:wpFileError(b,swfuploadL10n.missing_upload_url);break;case SWFUpload.UPLOAD_ERROR.UPLOAD_LIMIT_EXCEEDED:wpFileError(b,swfuploadL10n.upload_limit_exceeded);break;case SWFUpload.UPLOAD_ERROR.HTTP_ERROR:wpQueueError(swfuploadL10n.http_error);break;case SWFUpload.UPLOAD_ERROR.UPLOAD_FAILED:wpQueueError(swfuploadL10n.upload_failed);break;case SWFUpload.UPLOAD_ERROR.IO_ERROR:wpQueueError(swfuploadL10n.io_error);break;case SWFUpload.UPLOAD_ERROR.SECURITY_ERROR:wpQueueError(swfuploadL10n.security_error);break;case SWFUpload.UPLOAD_ERROR.UPLOAD_STOPPED:case SWFUpload.UPLOAD_ERROR.FILE_CANCELLED:jQuery("#media-item-"+b.id).remove();break;default:wpFileError(b,swfuploadL10n.default_error)}}function cancelUpload(){swfu.cancelQueue()}jQuery(document).ready(function(a){a('input[type="radio"]',"#media-items").live("click",function(){var b=a(this).closest("tr");if(a(b).hasClass("align")){setUserSetting("align",a(this).val())}else{if(a(b).hasClass("image-size")){setUserSetting("imgsize",a(this).val())}}});a("button.button","#media-items").live("click",function(){var b=this.className||"";b=b.match(/url([^ '"]+)/);if(b&&b[1]){setUserSetting("urlbutton",b[1]);a(this).siblings(".urlfield").val(a(this).attr("title"))}})}); \ No newline at end of file
diff --git a/src/wp-includes/js/swfupload/license.txt b/src/wp-includes/js/swfupload/license.txt
new file mode 100644
index 0000000000..8252ca9e24
--- /dev/null
+++ b/src/wp-includes/js/swfupload/license.txt
@@ -0,0 +1,32 @@
+/**
+ * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
+ *
+ * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
+ *
+ * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ */
+
+The MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. \ No newline at end of file
diff --git a/src/wp-includes/js/swfupload/plugins/swfupload.cookies.js b/src/wp-includes/js/swfupload/plugins/swfupload.cookies.js
new file mode 100644
index 0000000000..dd3b78bbcf
--- /dev/null
+++ b/src/wp-includes/js/swfupload/plugins/swfupload.cookies.js
@@ -0,0 +1,53 @@
+/*
+ Cookie Plug-in
+
+ This plug in automatically gets all the cookies for this site and adds them to the post_params.
+ Cookies are loaded only on initialization. The refreshCookies function can be called to update the post_params.
+ The cookies will override any other post params with the same name.
+*/
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.prototype.initSettings = function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.refreshCookies(false); // The false parameter must be sent since SWFUpload has not initialzed at this point
+ };
+ }(SWFUpload.prototype.initSettings);
+
+ // refreshes the post_params and updates SWFUpload. The sendToFlash parameters is optional and defaults to True
+ SWFUpload.prototype.refreshCookies = function (sendToFlash) {
+ if (sendToFlash === undefined) {
+ sendToFlash = true;
+ }
+ sendToFlash = !!sendToFlash;
+
+ // Get the post_params object
+ var postParams = this.settings.post_params;
+
+ // Get the cookies
+ var i, cookieArray = document.cookie.split(';'), caLength = cookieArray.length, c, eqIndex, name, value;
+ for (i = 0; i < caLength; i++) {
+ c = cookieArray[i];
+
+ // Left Trim spaces
+ while (c.charAt(0) === " ") {
+ c = c.substring(1, c.length);
+ }
+ eqIndex = c.indexOf("=");
+ if (eqIndex > 0) {
+ name = c.substring(0, eqIndex);
+ value = c.substring(eqIndex + 1);
+ postParams[name] = value;
+ }
+ }
+
+ if (sendToFlash) {
+ this.setPostParams(postParams);
+ }
+ };
+
+}
diff --git a/src/wp-includes/js/swfupload/plugins/swfupload.queue.js b/src/wp-includes/js/swfupload/plugins/swfupload.queue.js
new file mode 100644
index 0000000000..f09933e387
--- /dev/null
+++ b/src/wp-includes/js/swfupload/plugins/swfupload.queue.js
@@ -0,0 +1,98 @@
+/*
+ Queue Plug-in
+
+ Features:
+ *Adds a cancelQueue() method for cancelling the entire queue.
+ *All queued files are uploaded when startUpload() is called.
+ *If false is returned from uploadComplete then the queue upload is stopped.
+ If false is not returned (strict comparison) then the queue upload is continued.
+ *Adds a QueueComplete event that is fired when all the queued files have finished uploading.
+ Set the event handler with the queue_complete_handler setting.
+
+ */
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.queue = {};
+
+ SWFUpload.prototype.initSettings = (function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.queueSettings = {};
+
+ this.queueSettings.queue_cancelled_flag = false;
+ this.queueSettings.queue_upload_count = 0;
+
+ this.queueSettings.user_upload_complete_handler = this.settings.upload_complete_handler;
+ this.queueSettings.user_upload_start_handler = this.settings.upload_start_handler;
+ this.settings.upload_complete_handler = SWFUpload.queue.uploadCompleteHandler;
+ this.settings.upload_start_handler = SWFUpload.queue.uploadStartHandler;
+
+ this.settings.queue_complete_handler = this.settings.queue_complete_handler || null;
+ };
+ })(SWFUpload.prototype.initSettings);
+
+ SWFUpload.prototype.startUpload = function (fileID) {
+ this.queueSettings.queue_cancelled_flag = false;
+ this.callFlash("StartUpload", [fileID]);
+ };
+
+ SWFUpload.prototype.cancelQueue = function () {
+ this.queueSettings.queue_cancelled_flag = true;
+ this.stopUpload();
+
+ var stats = this.getStats();
+ while (stats.files_queued > 0) {
+ this.cancelUpload();
+ stats = this.getStats();
+ }
+ };
+
+ SWFUpload.queue.uploadStartHandler = function (file) {
+ var returnValue;
+ if (typeof(this.queueSettings.user_upload_start_handler) === "function") {
+ returnValue = this.queueSettings.user_upload_start_handler.call(this, file);
+ }
+
+ // To prevent upload a real "FALSE" value must be returned, otherwise default to a real "TRUE" value.
+ returnValue = (returnValue === false) ? false : true;
+
+ this.queueSettings.queue_cancelled_flag = !returnValue;
+
+ return returnValue;
+ };
+
+ SWFUpload.queue.uploadCompleteHandler = function (file) {
+ var user_upload_complete_handler = this.queueSettings.user_upload_complete_handler;
+ var continueUpload;
+
+ if (file.filestatus === SWFUpload.FILE_STATUS.COMPLETE) {
+ this.queueSettings.queue_upload_count++;
+ }
+
+ if (typeof(user_upload_complete_handler) === "function") {
+ continueUpload = (user_upload_complete_handler.call(this, file) === false) ? false : true;
+ } else if (file.filestatus === SWFUpload.FILE_STATUS.QUEUED) {
+ // If the file was stopped and re-queued don't restart the upload
+ continueUpload = false;
+ } else {
+ continueUpload = true;
+ }
+
+ if (continueUpload) {
+ var stats = this.getStats();
+ if (stats.files_queued > 0 && this.queueSettings.queue_cancelled_flag === false) {
+ this.startUpload();
+ } else if (this.queueSettings.queue_cancelled_flag === false) {
+ this.queueEvent("queue_complete_handler", [this.queueSettings.queue_upload_count]);
+ this.queueSettings.queue_upload_count = 0;
+ } else {
+ this.queueSettings.queue_cancelled_flag = false;
+ this.queueSettings.queue_upload_count = 0;
+ }
+ }
+ };
+}
diff --git a/src/wp-includes/js/swfupload/plugins/swfupload.speed.js b/src/wp-includes/js/swfupload/plugins/swfupload.speed.js
new file mode 100644
index 0000000000..3245c9c7db
--- /dev/null
+++ b/src/wp-includes/js/swfupload/plugins/swfupload.speed.js
@@ -0,0 +1,342 @@
+/*
+ Speed Plug-in
+
+ Features:
+ *Adds several properties to the 'file' object indicated upload speed, time left, upload time, etc.
+ - currentSpeed -- String indicating the upload speed, bytes per second
+ - averageSpeed -- Overall average upload speed, bytes per second
+ - movingAverageSpeed -- Speed over averaged over the last several measurements, bytes per second
+ - timeRemaining -- Estimated remaining upload time in seconds
+ - timeElapsed -- Number of seconds passed for this upload
+ - percentUploaded -- Percentage of the file uploaded (0 to 100)
+ - sizeUploaded -- Formatted size uploaded so far, bytes
+
+ *Adds setting 'moving_average_history_size' for defining the window size used to calculate the moving average speed.
+
+ *Adds several Formatting functions for formatting that values provided on the file object.
+ - SWFUpload.speed.formatBPS(bps) -- outputs string formatted in the best units (Gbps, Mbps, Kbps, bps)
+ - SWFUpload.speed.formatTime(seconds) -- outputs string formatted in the best units (x Hr y M z S)
+ - SWFUpload.speed.formatSize(bytes) -- outputs string formatted in the best units (w GB x MB y KB z B )
+ - SWFUpload.speed.formatPercent(percent) -- outputs string formatted with a percent sign (x.xx %)
+ - SWFUpload.speed.formatUnits(baseNumber, divisionArray, unitLabelArray, fractionalBoolean)
+ - Formats a number using the division array to determine how to apply the labels in the Label Array
+ - factionalBoolean indicates whether the number should be returned as a single fractional number with a unit (speed)
+ or as several numbers labeled with units (time)
+ */
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.speed = {};
+
+ SWFUpload.prototype.initSettings = (function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ // List used to keep the speed stats for the files we are tracking
+ this.fileSpeedStats = {};
+ this.speedSettings = {};
+
+ this.ensureDefault("moving_average_history_size", "10");
+
+ this.speedSettings.user_file_queued_handler = this.settings.file_queued_handler;
+ this.speedSettings.user_file_queue_error_handler = this.settings.file_queue_error_handler;
+ this.speedSettings.user_upload_start_handler = this.settings.upload_start_handler;
+ this.speedSettings.user_upload_error_handler = this.settings.upload_error_handler;
+ this.speedSettings.user_upload_progress_handler = this.settings.upload_progress_handler;
+ this.speedSettings.user_upload_success_handler = this.settings.upload_success_handler;
+ this.speedSettings.user_upload_complete_handler = this.settings.upload_complete_handler;
+
+ this.settings.file_queued_handler = SWFUpload.speed.fileQueuedHandler;
+ this.settings.file_queue_error_handler = SWFUpload.speed.fileQueueErrorHandler;
+ this.settings.upload_start_handler = SWFUpload.speed.uploadStartHandler;
+ this.settings.upload_error_handler = SWFUpload.speed.uploadErrorHandler;
+ this.settings.upload_progress_handler = SWFUpload.speed.uploadProgressHandler;
+ this.settings.upload_success_handler = SWFUpload.speed.uploadSuccessHandler;
+ this.settings.upload_complete_handler = SWFUpload.speed.uploadCompleteHandler;
+
+ delete this.ensureDefault;
+ };
+ })(SWFUpload.prototype.initSettings);
+
+
+ SWFUpload.speed.fileQueuedHandler = function (file) {
+ if (typeof this.speedSettings.user_file_queued_handler === "function") {
+ file = SWFUpload.speed.extendFile(file);
+
+ return this.speedSettings.user_file_queued_handler.call(this, file);
+ }
+ };
+
+ SWFUpload.speed.fileQueueErrorHandler = function (file, errorCode, message) {
+ if (typeof this.speedSettings.user_file_queue_error_handler === "function") {
+ file = SWFUpload.speed.extendFile(file);
+
+ return this.speedSettings.user_file_queue_error_handler.call(this, file, errorCode, message);
+ }
+ };
+
+ SWFUpload.speed.uploadStartHandler = function (file) {
+ if (typeof this.speedSettings.user_upload_start_handler === "function") {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ return this.speedSettings.user_upload_start_handler.call(this, file);
+ }
+ };
+
+ SWFUpload.speed.uploadErrorHandler = function (file, errorCode, message) {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ SWFUpload.speed.removeTracking(file, this.fileSpeedStats);
+
+ if (typeof this.speedSettings.user_upload_error_handler === "function") {
+ return this.speedSettings.user_upload_error_handler.call(this, file, errorCode, message);
+ }
+ };
+ SWFUpload.speed.uploadProgressHandler = function (file, bytesComplete, bytesTotal) {
+ this.updateTracking(file, bytesComplete);
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+
+ if (typeof this.speedSettings.user_upload_progress_handler === "function") {
+ return this.speedSettings.user_upload_progress_handler.call(this, file, bytesComplete, bytesTotal);
+ }
+ };
+
+ SWFUpload.speed.uploadSuccessHandler = function (file, serverData) {
+ if (typeof this.speedSettings.user_upload_success_handler === "function") {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ return this.speedSettings.user_upload_success_handler.call(this, file, serverData);
+ }
+ };
+ SWFUpload.speed.uploadCompleteHandler = function (file) {
+ file = SWFUpload.speed.extendFile(file, this.fileSpeedStats);
+ SWFUpload.speed.removeTracking(file, this.fileSpeedStats);
+
+ if (typeof this.speedSettings.user_upload_complete_handler === "function") {
+ return this.speedSettings.user_upload_complete_handler.call(this, file);
+ }
+ };
+
+ // Private: extends the file object with the speed plugin values
+ SWFUpload.speed.extendFile = function (file, trackingList) {
+ var tracking;
+
+ if (trackingList) {
+ tracking = trackingList[file.id];
+ }
+
+ if (tracking) {
+ file.currentSpeed = tracking.currentSpeed;
+ file.averageSpeed = tracking.averageSpeed;
+ file.movingAverageSpeed = tracking.movingAverageSpeed;
+ file.timeRemaining = tracking.timeRemaining;
+ file.timeElapsed = tracking.timeElapsed;
+ file.percentUploaded = tracking.percentUploaded;
+ file.sizeUploaded = tracking.bytesUploaded;
+
+ } else {
+ file.currentSpeed = 0;
+ file.averageSpeed = 0;
+ file.movingAverageSpeed = 0;
+ file.timeRemaining = 0;
+ file.timeElapsed = 0;
+ file.percentUploaded = 0;
+ file.sizeUploaded = 0;
+ }
+
+ return file;
+ };
+
+ // Private: Updates the speed tracking object, or creates it if necessary
+ SWFUpload.prototype.updateTracking = function (file, bytesUploaded) {
+ var tracking = this.fileSpeedStats[file.id];
+ if (!tracking) {
+ this.fileSpeedStats[file.id] = tracking = {};
+ }
+
+ // Sanity check inputs
+ bytesUploaded = bytesUploaded || tracking.bytesUploaded || 0;
+ if (bytesUploaded < 0) {
+ bytesUploaded = 0;
+ }
+ if (bytesUploaded > file.size) {
+ bytesUploaded = file.size;
+ }
+
+ var tickTime = (new Date()).getTime();
+ if (!tracking.startTime) {
+ tracking.startTime = (new Date()).getTime();
+ tracking.lastTime = tracking.startTime;
+ tracking.currentSpeed = 0;
+ tracking.averageSpeed = 0;
+ tracking.movingAverageSpeed = 0;
+ tracking.movingAverageHistory = [];
+ tracking.timeRemaining = 0;
+ tracking.timeElapsed = 0;
+ tracking.percentUploaded = bytesUploaded / file.size;
+ tracking.bytesUploaded = bytesUploaded;
+ } else if (tracking.startTime > tickTime) {
+ this.debug("When backwards in time");
+ } else {
+ // Get time and deltas
+ var now = (new Date()).getTime();
+ var lastTime = tracking.lastTime;
+ var deltaTime = now - lastTime;
+ var deltaBytes = bytesUploaded - tracking.bytesUploaded;
+
+ if (deltaBytes === 0 || deltaTime === 0) {
+ return tracking;
+ }
+
+ // Update tracking object
+ tracking.lastTime = now;
+ tracking.bytesUploaded = bytesUploaded;
+
+ // Calculate speeds
+ tracking.currentSpeed = (deltaBytes * 8 ) / (deltaTime / 1000);
+ tracking.averageSpeed = (tracking.bytesUploaded * 8) / ((now - tracking.startTime) / 1000);
+
+ // Calculate moving average
+ tracking.movingAverageHistory.push(tracking.currentSpeed);
+ if (tracking.movingAverageHistory.length > this.settings.moving_average_history_size) {
+ tracking.movingAverageHistory.shift();
+ }
+
+ tracking.movingAverageSpeed = SWFUpload.speed.calculateMovingAverage(tracking.movingAverageHistory);
+
+ // Update times
+ tracking.timeRemaining = (file.size - tracking.bytesUploaded) * 8 / tracking.movingAverageSpeed;
+ tracking.timeElapsed = (now - tracking.startTime) / 1000;
+
+ // Update percent
+ tracking.percentUploaded = (tracking.bytesUploaded / file.size * 100);
+ }
+
+ return tracking;
+ };
+ SWFUpload.speed.removeTracking = function (file, trackingList) {
+ try {
+ trackingList[file.id] = null;
+ delete trackingList[file.id];
+ } catch (ex) {
+ }
+ };
+
+ SWFUpload.speed.formatUnits = function (baseNumber, unitDivisors, unitLabels, singleFractional) {
+ var i, unit, unitDivisor, unitLabel;
+
+ if (baseNumber === 0) {
+ return "0 " + unitLabels[unitLabels.length - 1];
+ }
+
+ if (singleFractional) {
+ unit = baseNumber;
+ unitLabel = unitLabels.length >= unitDivisors.length ? unitLabels[unitDivisors.length - 1] : "";
+ for (i = 0; i < unitDivisors.length; i++) {
+ if (baseNumber >= unitDivisors[i]) {
+ unit = (baseNumber / unitDivisors[i]).toFixed(2);
+ unitLabel = unitLabels.length >= i ? " " + unitLabels[i] : "";
+ break;
+ }
+ }
+
+ return unit + unitLabel;
+ } else {
+ var formattedStrings = [];
+ var remainder = baseNumber;
+
+ for (i = 0; i < unitDivisors.length; i++) {
+ unitDivisor = unitDivisors[i];
+ unitLabel = unitLabels.length > i ? " " + unitLabels[i] : "";
+
+ unit = remainder / unitDivisor;
+ if (i < unitDivisors.length -1) {
+ unit = Math.floor(unit);
+ } else {
+ unit = unit.toFixed(2);
+ }
+ if (unit > 0) {
+ remainder = remainder % unitDivisor;
+
+ formattedStrings.push(unit + unitLabel);
+ }
+ }
+
+ return formattedStrings.join(" ");
+ }
+ };
+
+ SWFUpload.speed.formatBPS = function (baseNumber) {
+ var bpsUnits = [1073741824, 1048576, 1024, 1], bpsUnitLabels = ["Gbps", "Mbps", "Kbps", "bps"];
+ return SWFUpload.speed.formatUnits(baseNumber, bpsUnits, bpsUnitLabels, true);
+
+ };
+ SWFUpload.speed.formatTime = function (baseNumber) {
+ var timeUnits = [86400, 3600, 60, 1], timeUnitLabels = ["d", "h", "m", "s"];
+ return SWFUpload.speed.formatUnits(baseNumber, timeUnits, timeUnitLabels, false);
+
+ };
+ SWFUpload.speed.formatBytes = function (baseNumber) {
+ var sizeUnits = [1073741824, 1048576, 1024, 1], sizeUnitLabels = ["GB", "MB", "KB", "bytes"];
+ return SWFUpload.speed.formatUnits(baseNumber, sizeUnits, sizeUnitLabels, true);
+
+ };
+ SWFUpload.speed.formatPercent = function (baseNumber) {
+ return baseNumber.toFixed(2) + " %";
+ };
+
+ SWFUpload.speed.calculateMovingAverage = function (history) {
+ var vals = [], size, sum = 0.0, mean = 0.0, varianceTemp = 0.0, variance = 0.0, standardDev = 0.0;
+ var i;
+ var mSum = 0, mCount = 0;
+
+ size = history.length;
+
+ // Check for sufficient data
+ if (size >= 8) {
+ // Clone the array and Calculate sum of the values
+ for (i = 0; i < size; i++) {
+ vals[i] = history[i];
+ sum += vals[i];
+ }
+
+ mean = sum / size;
+
+ // Calculate variance for the set
+ for (i = 0; i < size; i++) {
+ varianceTemp += Math.pow((vals[i] - mean), 2);
+ }
+
+ variance = varianceTemp / size;
+ standardDev = Math.sqrt(variance);
+
+ //Standardize the Data
+ for (i = 0; i < size; i++) {
+ vals[i] = (vals[i] - mean) / standardDev;
+ }
+
+ // Calculate the average excluding outliers
+ var deviationRange = 2.0;
+ for (i = 0; i < size; i++) {
+
+ if (vals[i] <= deviationRange && vals[i] >= -deviationRange) {
+ mCount++;
+ mSum += history[i];
+ }
+ }
+
+ } else {
+ // Calculate the average (not enough data points to remove outliers)
+ mCount = size;
+ for (i = 0; i < size; i++) {
+ mSum += history[i];
+ }
+ }
+
+ return mSum / mCount;
+ };
+
+} \ No newline at end of file
diff --git a/src/wp-includes/js/swfupload/plugins/swfupload.swfobject.js b/src/wp-includes/js/swfupload/plugins/swfupload.swfobject.js
new file mode 100644
index 0000000000..cb7aa8043d
--- /dev/null
+++ b/src/wp-includes/js/swfupload/plugins/swfupload.swfobject.js
@@ -0,0 +1,105 @@
+/*
+ SWFUpload.SWFObject Plugin
+
+ Summary:
+ This plugin uses SWFObject to embed SWFUpload dynamically in the page. SWFObject provides accurate Flash Player detection and DOM Ready loading.
+ This plugin replaces the Graceful Degradation plugin.
+
+ Features:
+ * swfupload_load_failed_hander event
+ * swfupload_pre_load_handler event
+ * minimum_flash_version setting (default: "9.0.28")
+ * SWFUpload.onload event for early loading
+
+ Usage:
+ Provide handlers and settings as needed. When using the SWFUpload.SWFObject plugin you should initialize SWFUploading
+ in SWFUpload.onload rather than in window.onload. When initialized this way SWFUpload can load earlier preventing the UI flicker
+ that was seen using the Graceful Degradation plugin.
+
+ <script type="text/javascript">
+ var swfu;
+ SWFUpload.onload = function () {
+ swfu = new SWFUpload({
+ minimum_flash_version: "9.0.28",
+ swfupload_pre_load_handler: swfuploadPreLoad,
+ swfupload_load_failed_handler: swfuploadLoadFailed
+ });
+ };
+ </script>
+
+ Notes:
+ You must provide set minimum_flash_version setting to "8" if you are using SWFUpload for Flash Player 8.
+ The swfuploadLoadFailed event is only fired if the minimum version of Flash Player is not met. Other issues such as missing SWF files, browser bugs
+ or corrupt Flash Player installations will not trigger this event.
+ The swfuploadPreLoad event is fired as soon as the minimum version of Flash Player is found. It does not wait for SWFUpload to load and can
+ be used to prepare the SWFUploadUI and hide alternate content.
+ swfobject's onDomReady event is cross-browser safe but will default to the window.onload event when DOMReady is not supported by the browser.
+ Early DOM Loading is supported in major modern browsers but cannot be guaranteed for every browser ever made.
+*/
+
+
+// SWFObject v2.1 must be loaded
+
+var SWFUpload;
+if (typeof(SWFUpload) === "function") {
+ SWFUpload.onload = function () {};
+
+ swfobject.addDomLoadEvent(function () {
+ if (typeof(SWFUpload.onload) === "function") {
+ setTimeout(function(){SWFUpload.onload.call(window);}, 200);
+ }
+ });
+
+ SWFUpload.prototype.initSettings = (function (oldInitSettings) {
+ return function () {
+ if (typeof(oldInitSettings) === "function") {
+ oldInitSettings.call(this);
+ }
+
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ this.ensureDefault("minimum_flash_version", "9.0.28");
+ this.ensureDefault("swfupload_pre_load_handler", null);
+ this.ensureDefault("swfupload_load_failed_handler", null);
+
+ delete this.ensureDefault;
+
+ };
+ })(SWFUpload.prototype.initSettings);
+
+
+ SWFUpload.prototype.loadFlash = function (oldLoadFlash) {
+ return function () {
+ var hasFlash = swfobject.hasFlashPlayerVersion(this.settings.minimum_flash_version);
+
+ if (hasFlash) {
+ this.queueEvent("swfupload_pre_load_handler");
+ if (typeof(oldLoadFlash) === "function") {
+ oldLoadFlash.call(this);
+ }
+ } else {
+ this.queueEvent("swfupload_load_failed_handler");
+ }
+ };
+
+ }(SWFUpload.prototype.loadFlash);
+
+ SWFUpload.prototype.displayDebugInfo = function (oldDisplayDebugInfo) {
+ return function () {
+ if (typeof(oldDisplayDebugInfo) === "function") {
+ oldDisplayDebugInfo.call(this);
+ }
+
+ this.debug(
+ [
+ "SWFUpload.SWFObject Plugin settings:", "\n",
+ "\t", "minimum_flash_version: ", this.settings.minimum_flash_version, "\n",
+ "\t", "swfupload_pre_load_handler assigned: ", (typeof(this.settings.swfupload_pre_load_handler) === "function").toString(), "\n",
+ "\t", "swfupload_load_failed_handler assigned: ", (typeof(this.settings.swfupload_load_failed_handler) === "function").toString(), "\n",
+ ].join("")
+ );
+ };
+ }(SWFUpload.prototype.displayDebugInfo);
+}
diff --git a/src/wp-includes/js/swfupload/swfupload.js b/src/wp-includes/js/swfupload/swfupload.js
new file mode 100644
index 0000000000..e65b19cb29
--- /dev/null
+++ b/src/wp-includes/js/swfupload/swfupload.js
@@ -0,0 +1,980 @@
+/**
+ * SWFUpload: http://www.swfupload.org, http://swfupload.googlecode.com
+ *
+ * mmSWFUpload 1.0: Flash upload dialog - http://profandesign.se/swfupload/, http://www.vinterwebb.se/
+ *
+ * SWFUpload is (c) 2006-2007 Lars Huring, Olov Nilzén and Mammon Media and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * SWFUpload 2 is (c) 2007-2008 Jake Roberts and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ */
+
+
+/* ******************* */
+/* Constructor & Init */
+/* ******************* */
+var SWFUpload;
+
+if (SWFUpload == undefined) {
+ SWFUpload = function (settings) {
+ this.initSWFUpload(settings);
+ };
+}
+
+SWFUpload.prototype.initSWFUpload = function (settings) {
+ try {
+ this.customSettings = {}; // A container where developers can place their own settings associated with this instance.
+ this.settings = settings;
+ this.eventQueue = [];
+ this.movieName = "SWFUpload_" + SWFUpload.movieCount++;
+ this.movieElement = null;
+
+
+ // Setup global control tracking
+ SWFUpload.instances[this.movieName] = this;
+
+ // Load the settings. Load the Flash movie.
+ this.initSettings();
+ this.loadFlash();
+ this.displayDebugInfo();
+ } catch (ex) {
+ delete SWFUpload.instances[this.movieName];
+ throw ex;
+ }
+};
+
+/* *************** */
+/* Static Members */
+/* *************** */
+SWFUpload.instances = {};
+SWFUpload.movieCount = 0;
+SWFUpload.version = "2.2.0 2009-03-25";
+SWFUpload.QUEUE_ERROR = {
+ QUEUE_LIMIT_EXCEEDED : -100,
+ FILE_EXCEEDS_SIZE_LIMIT : -110,
+ ZERO_BYTE_FILE : -120,
+ INVALID_FILETYPE : -130
+};
+SWFUpload.UPLOAD_ERROR = {
+ HTTP_ERROR : -200,
+ MISSING_UPLOAD_URL : -210,
+ IO_ERROR : -220,
+ SECURITY_ERROR : -230,
+ UPLOAD_LIMIT_EXCEEDED : -240,
+ UPLOAD_FAILED : -250,
+ SPECIFIED_FILE_ID_NOT_FOUND : -260,
+ FILE_VALIDATION_FAILED : -270,
+ FILE_CANCELLED : -280,
+ UPLOAD_STOPPED : -290
+};
+SWFUpload.FILE_STATUS = {
+ QUEUED : -1,
+ IN_PROGRESS : -2,
+ ERROR : -3,
+ COMPLETE : -4,
+ CANCELLED : -5
+};
+SWFUpload.BUTTON_ACTION = {
+ SELECT_FILE : -100,
+ SELECT_FILES : -110,
+ START_UPLOAD : -120
+};
+SWFUpload.CURSOR = {
+ ARROW : -1,
+ HAND : -2
+};
+SWFUpload.WINDOW_MODE = {
+ WINDOW : "window",
+ TRANSPARENT : "transparent",
+ OPAQUE : "opaque"
+};
+
+// Private: takes a URL, determines if it is relative and converts to an absolute URL
+// using the current site. Only processes the URL if it can, otherwise returns the URL untouched
+SWFUpload.completeURL = function(url) {
+ if (typeof(url) !== "string" || url.match(/^https?:\/\//i) || url.match(/^\//)) {
+ return url;
+ }
+
+ var currentURL = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
+
+ var indexSlash = window.location.pathname.lastIndexOf("/");
+ if (indexSlash <= 0) {
+ path = "/";
+ } else {
+ path = window.location.pathname.substr(0, indexSlash) + "/";
+ }
+
+ return /*currentURL +*/ path + url;
+
+};
+
+
+/* ******************** */
+/* Instance Members */
+/* ******************** */
+
+// Private: initSettings ensures that all the
+// settings are set, getting a default value if one was not assigned.
+SWFUpload.prototype.initSettings = function () {
+ this.ensureDefault = function (settingName, defaultValue) {
+ this.settings[settingName] = (this.settings[settingName] == undefined) ? defaultValue : this.settings[settingName];
+ };
+
+ // Upload backend settings
+ this.ensureDefault("upload_url", "");
+ this.ensureDefault("preserve_relative_urls", false);
+ this.ensureDefault("file_post_name", "Filedata");
+ this.ensureDefault("post_params", {});
+ this.ensureDefault("use_query_string", false);
+ this.ensureDefault("requeue_on_error", false);
+ this.ensureDefault("http_success", []);
+ this.ensureDefault("assume_success_timeout", 0);
+
+ // File Settings
+ this.ensureDefault("file_types", "*.*");
+ this.ensureDefault("file_types_description", "All Files");
+ this.ensureDefault("file_size_limit", 0); // Default zero means "unlimited"
+ this.ensureDefault("file_upload_limit", 0);
+ this.ensureDefault("file_queue_limit", 0);
+
+ // Flash Settings
+ this.ensureDefault("flash_url", "swfupload.swf");
+ this.ensureDefault("prevent_swf_caching", true);
+
+ // Button Settings
+ this.ensureDefault("button_image_url", "");
+ this.ensureDefault("button_width", 1);
+ this.ensureDefault("button_height", 1);
+ this.ensureDefault("button_text", "");
+ this.ensureDefault("button_text_style", "color: #000000; font-size: 16pt;");
+ this.ensureDefault("button_text_top_padding", 0);
+ this.ensureDefault("button_text_left_padding", 0);
+ this.ensureDefault("button_action", SWFUpload.BUTTON_ACTION.SELECT_FILES);
+ this.ensureDefault("button_disabled", false);
+ this.ensureDefault("button_placeholder_id", "");
+ this.ensureDefault("button_placeholder", null);
+ this.ensureDefault("button_cursor", SWFUpload.CURSOR.ARROW);
+ this.ensureDefault("button_window_mode", SWFUpload.WINDOW_MODE.WINDOW);
+
+ // Debug Settings
+ this.ensureDefault("debug", false);
+ this.settings.debug_enabled = this.settings.debug; // Here to maintain v2 API
+
+ // Event Handlers
+ this.settings.return_upload_start_handler = this.returnUploadStart;
+ this.ensureDefault("swfupload_loaded_handler", null);
+ this.ensureDefault("file_dialog_start_handler", null);
+ this.ensureDefault("file_queued_handler", null);
+ this.ensureDefault("file_queue_error_handler", null);
+ this.ensureDefault("file_dialog_complete_handler", null);
+
+ this.ensureDefault("upload_start_handler", null);
+ this.ensureDefault("upload_progress_handler", null);
+ this.ensureDefault("upload_error_handler", null);
+ this.ensureDefault("upload_success_handler", null);
+ this.ensureDefault("upload_complete_handler", null);
+
+ this.ensureDefault("debug_handler", this.debugMessage);
+
+ this.ensureDefault("custom_settings", {});
+
+ // Other settings
+ this.customSettings = this.settings.custom_settings;
+
+ // Update the flash url if needed
+ if (!!this.settings.prevent_swf_caching) {
+ this.settings.flash_url = this.settings.flash_url + (this.settings.flash_url.indexOf("?") < 0 ? "?" : "&") + "preventswfcaching=" + new Date().getTime();
+ }
+
+ if (!this.settings.preserve_relative_urls) {
+ //this.settings.flash_url = SWFUpload.completeURL(this.settings.flash_url); // Don't need to do this one since flash doesn't look at it
+ this.settings.upload_url = SWFUpload.completeURL(this.settings.upload_url);
+ this.settings.button_image_url = SWFUpload.completeURL(this.settings.button_image_url);
+ }
+
+ delete this.ensureDefault;
+};
+
+// Private: loadFlash replaces the button_placeholder element with the flash movie.
+SWFUpload.prototype.loadFlash = function () {
+ var targetElement, tempParent;
+
+ // Make sure an element with the ID we are going to use doesn't already exist
+ if (document.getElementById(this.movieName) !== null) {
+ throw "ID " + this.movieName + " is already in use. The Flash Object could not be added";
+ }
+
+ // Get the element where we will be placing the flash movie
+ targetElement = document.getElementById(this.settings.button_placeholder_id) || this.settings.button_placeholder;
+
+ if (targetElement == undefined) {
+ throw "Could not find the placeholder element: " + this.settings.button_placeholder_id;
+ }
+
+ // Append the container and load the flash
+ tempParent = document.createElement("div");
+ tempParent.innerHTML = this.getFlashHTML(); // Using innerHTML is non-standard but the only sensible way to dynamically add Flash in IE (and maybe other browsers)
+ targetElement.parentNode.replaceChild(tempParent.firstChild, targetElement);
+
+ // Fix IE Flash/Form bug
+ if (window[this.movieName] == undefined) {
+ window[this.movieName] = this.getMovieElement();
+ }
+
+};
+
+// Private: getFlashHTML generates the object tag needed to embed the flash in to the document
+SWFUpload.prototype.getFlashHTML = function () {
+ // Flash Satay object syntax: http://www.alistapart.com/articles/flashsatay
+ return ['<object id="', this.movieName, '" type="application/x-shockwave-flash" data="', this.settings.flash_url, '" width="', this.settings.button_width, '" height="', this.settings.button_height, '" class="swfupload">',
+ '<param name="wmode" value="', this.settings.button_window_mode, '" />',
+ '<param name="movie" value="', this.settings.flash_url, '" />',
+ '<param name="quality" value="high" />',
+ '<param name="menu" value="false" />',
+ '<param name="allowScriptAccess" value="always" />',
+ '<param name="flashvars" value="' + this.getFlashVars() + '" />',
+ '</object>'].join("");
+};
+
+// Private: getFlashVars builds the parameter string that will be passed
+// to flash in the flashvars param.
+SWFUpload.prototype.getFlashVars = function () {
+ // Build a string from the post param object
+ var paramString = this.buildParamString();
+ var httpSuccessString = this.settings.http_success.join(",");
+
+ // Build the parameter string
+ return ["movieName=", encodeURIComponent(this.movieName),
+ "&amp;uploadURL=", encodeURIComponent(this.settings.upload_url),
+ "&amp;useQueryString=", encodeURIComponent(this.settings.use_query_string),
+ "&amp;requeueOnError=", encodeURIComponent(this.settings.requeue_on_error),
+ "&amp;httpSuccess=", encodeURIComponent(httpSuccessString),
+ "&amp;assumeSuccessTimeout=", encodeURIComponent(this.settings.assume_success_timeout),
+ "&amp;params=", encodeURIComponent(paramString),
+ "&amp;filePostName=", encodeURIComponent(this.settings.file_post_name),
+ "&amp;fileTypes=", encodeURIComponent(this.settings.file_types),
+ "&amp;fileTypesDescription=", encodeURIComponent(this.settings.file_types_description),
+ "&amp;fileSizeLimit=", encodeURIComponent(this.settings.file_size_limit),
+ "&amp;fileUploadLimit=", encodeURIComponent(this.settings.file_upload_limit),
+ "&amp;fileQueueLimit=", encodeURIComponent(this.settings.file_queue_limit),
+ "&amp;debugEnabled=", encodeURIComponent(this.settings.debug_enabled),
+ "&amp;buttonImageURL=", encodeURIComponent(this.settings.button_image_url),
+ "&amp;buttonWidth=", encodeURIComponent(this.settings.button_width),
+ "&amp;buttonHeight=", encodeURIComponent(this.settings.button_height),
+ "&amp;buttonText=", encodeURIComponent(this.settings.button_text),
+ "&amp;buttonTextTopPadding=", encodeURIComponent(this.settings.button_text_top_padding),
+ "&amp;buttonTextLeftPadding=", encodeURIComponent(this.settings.button_text_left_padding),
+ "&amp;buttonTextStyle=", encodeURIComponent(this.settings.button_text_style),
+ "&amp;buttonAction=", encodeURIComponent(this.settings.button_action),
+ "&amp;buttonDisabled=", encodeURIComponent(this.settings.button_disabled),
+ "&amp;buttonCursor=", encodeURIComponent(this.settings.button_cursor)
+ ].join("");
+};
+
+// Public: getMovieElement retrieves the DOM reference to the Flash element added by SWFUpload
+// The element is cached after the first lookup
+SWFUpload.prototype.getMovieElement = function () {
+ if (this.movieElement == undefined) {
+ this.movieElement = document.getElementById(this.movieName);
+ }
+
+ if (this.movieElement === null) {
+ throw "Could not find Flash element";
+ }
+
+ return this.movieElement;
+};
+
+// Private: buildParamString takes the name/value pairs in the post_params setting object
+// and joins them up in to a string formatted "name=value&amp;name=value"
+SWFUpload.prototype.buildParamString = function () {
+ var postParams = this.settings.post_params;
+ var paramStringPairs = [];
+
+ if (typeof(postParams) === "object") {
+ for (var name in postParams) {
+ if (postParams.hasOwnProperty(name)) {
+ paramStringPairs.push(encodeURIComponent(name.toString()) + "=" + encodeURIComponent(postParams[name].toString()));
+ }
+ }
+ }
+
+ return paramStringPairs.join("&amp;");
+};
+
+// Public: Used to remove a SWFUpload instance from the page. This method strives to remove
+// all references to the SWF, and other objects so memory is properly freed.
+// Returns true if everything was destroyed. Returns a false if a failure occurs leaving SWFUpload in an inconsistant state.
+// Credits: Major improvements provided by steffen
+SWFUpload.prototype.destroy = function () {
+ try {
+ // Make sure Flash is done before we try to remove it
+ this.cancelUpload(null, false);
+
+
+ // Remove the SWFUpload DOM nodes
+ var movieElement = null;
+ movieElement = this.getMovieElement();
+
+ if (movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
+ // Loop through all the movie's properties and remove all function references (DOM/JS IE 6/7 memory leak workaround)
+ for (var i in movieElement) {
+ try {
+ if (typeof(movieElement[i]) === "function") {
+ movieElement[i] = null;
+ }
+ } catch (ex1) {}
+ }
+
+ // Remove the Movie Element from the page
+ try {
+ movieElement.parentNode.removeChild(movieElement);
+ } catch (ex) {}
+ }
+
+ // Remove IE form fix reference
+ window[this.movieName] = null;
+
+ // Destroy other references
+ SWFUpload.instances[this.movieName] = null;
+ delete SWFUpload.instances[this.movieName];
+
+ this.movieElement = null;
+ this.settings = null;
+ this.customSettings = null;
+ this.eventQueue = null;
+ this.movieName = null;
+
+
+ return true;
+ } catch (ex2) {
+ return false;
+ }
+};
+
+
+// Public: displayDebugInfo prints out settings and configuration
+// information about this SWFUpload instance.
+// This function (and any references to it) can be deleted when placing
+// SWFUpload in production.
+SWFUpload.prototype.displayDebugInfo = function () {
+ this.debug(
+ [
+ "---SWFUpload Instance Info---\n",
+ "Version: ", SWFUpload.version, "\n",
+ "Movie Name: ", this.movieName, "\n",
+ "Settings:\n",
+ "\t", "upload_url: ", this.settings.upload_url, "\n",
+ "\t", "flash_url: ", this.settings.flash_url, "\n",
+ "\t", "use_query_string: ", this.settings.use_query_string.toString(), "\n",
+ "\t", "requeue_on_error: ", this.settings.requeue_on_error.toString(), "\n",
+ "\t", "http_success: ", this.settings.http_success.join(", "), "\n",
+ "\t", "assume_success_timeout: ", this.settings.assume_success_timeout, "\n",
+ "\t", "file_post_name: ", this.settings.file_post_name, "\n",
+ "\t", "post_params: ", this.settings.post_params.toString(), "\n",
+ "\t", "file_types: ", this.settings.file_types, "\n",
+ "\t", "file_types_description: ", this.settings.file_types_description, "\n",
+ "\t", "file_size_limit: ", this.settings.file_size_limit, "\n",
+ "\t", "file_upload_limit: ", this.settings.file_upload_limit, "\n",
+ "\t", "file_queue_limit: ", this.settings.file_queue_limit, "\n",
+ "\t", "debug: ", this.settings.debug.toString(), "\n",
+
+ "\t", "prevent_swf_caching: ", this.settings.prevent_swf_caching.toString(), "\n",
+
+ "\t", "button_placeholder_id: ", this.settings.button_placeholder_id.toString(), "\n",
+ "\t", "button_placeholder: ", (this.settings.button_placeholder ? "Set" : "Not Set"), "\n",
+ "\t", "button_image_url: ", this.settings.button_image_url.toString(), "\n",
+ "\t", "button_width: ", this.settings.button_width.toString(), "\n",
+ "\t", "button_height: ", this.settings.button_height.toString(), "\n",
+ "\t", "button_text: ", this.settings.button_text.toString(), "\n",
+ "\t", "button_text_style: ", this.settings.button_text_style.toString(), "\n",
+ "\t", "button_text_top_padding: ", this.settings.button_text_top_padding.toString(), "\n",
+ "\t", "button_text_left_padding: ", this.settings.button_text_left_padding.toString(), "\n",
+ "\t", "button_action: ", this.settings.button_action.toString(), "\n",
+ "\t", "button_disabled: ", this.settings.button_disabled.toString(), "\n",
+
+ "\t", "custom_settings: ", this.settings.custom_settings.toString(), "\n",
+ "Event Handlers:\n",
+ "\t", "swfupload_loaded_handler assigned: ", (typeof this.settings.swfupload_loaded_handler === "function").toString(), "\n",
+ "\t", "file_dialog_start_handler assigned: ", (typeof this.settings.file_dialog_start_handler === "function").toString(), "\n",
+ "\t", "file_queued_handler assigned: ", (typeof this.settings.file_queued_handler === "function").toString(), "\n",
+ "\t", "file_queue_error_handler assigned: ", (typeof this.settings.file_queue_error_handler === "function").toString(), "\n",
+ "\t", "upload_start_handler assigned: ", (typeof this.settings.upload_start_handler === "function").toString(), "\n",
+ "\t", "upload_progress_handler assigned: ", (typeof this.settings.upload_progress_handler === "function").toString(), "\n",
+ "\t", "upload_error_handler assigned: ", (typeof this.settings.upload_error_handler === "function").toString(), "\n",
+ "\t", "upload_success_handler assigned: ", (typeof this.settings.upload_success_handler === "function").toString(), "\n",
+ "\t", "upload_complete_handler assigned: ", (typeof this.settings.upload_complete_handler === "function").toString(), "\n",
+ "\t", "debug_handler assigned: ", (typeof this.settings.debug_handler === "function").toString(), "\n"
+ ].join("")
+ );
+};
+
+/* Note: addSetting and getSetting are no longer used by SWFUpload but are included
+ the maintain v2 API compatibility
+*/
+// Public: (Deprecated) addSetting adds a setting value. If the value given is undefined or null then the default_value is used.
+SWFUpload.prototype.addSetting = function (name, value, default_value) {
+ if (value == undefined) {
+ return (this.settings[name] = default_value);
+ } else {
+ return (this.settings[name] = value);
+ }
+};
+
+// Public: (Deprecated) getSetting gets a setting. Returns an empty string if the setting was not found.
+SWFUpload.prototype.getSetting = function (name) {
+ if (this.settings[name] != undefined) {
+ return this.settings[name];
+ }
+
+ return "";
+};
+
+
+
+// Private: callFlash handles function calls made to the Flash element.
+// Calls are made with a setTimeout for some functions to work around
+// bugs in the ExternalInterface library.
+SWFUpload.prototype.callFlash = function (functionName, argumentArray) {
+ argumentArray = argumentArray || [];
+
+ var movieElement = this.getMovieElement();
+ var returnValue, returnString;
+
+ // Flash's method if calling ExternalInterface methods (code adapted from MooTools).
+ try {
+ returnString = movieElement.CallFunction('<invoke name="' + functionName + '" returntype="javascript">' + __flash__argumentsToXML(argumentArray, 0) + '</invoke>');
+ returnValue = eval(returnString);
+ } catch (ex) {
+ throw "Call to " + functionName + " failed";
+ }
+
+ // Unescape file post param values
+ if (returnValue != undefined && typeof returnValue.post === "object") {
+ returnValue = this.unescapeFilePostParams(returnValue);
+ }
+
+ return returnValue;
+};
+
+/* *****************************
+ -- Flash control methods --
+ Your UI should use these
+ to operate SWFUpload
+ ***************************** */
+
+// WARNING: this function does not work in Flash Player 10
+// Public: selectFile causes a File Selection Dialog window to appear. This
+// dialog only allows 1 file to be selected.
+SWFUpload.prototype.selectFile = function () {
+ this.callFlash("SelectFile");
+};
+
+// WARNING: this function does not work in Flash Player 10
+// Public: selectFiles causes a File Selection Dialog window to appear/ This
+// dialog allows the user to select any number of files
+// Flash Bug Warning: Flash limits the number of selectable files based on the combined length of the file names.
+// If the selection name length is too long the dialog will fail in an unpredictable manner. There is no work-around
+// for this bug.
+SWFUpload.prototype.selectFiles = function () {
+ this.callFlash("SelectFiles");
+};
+
+
+// Public: startUpload starts uploading the first file in the queue unless
+// the optional parameter 'fileID' specifies the ID
+SWFUpload.prototype.startUpload = function (fileID) {
+ this.callFlash("StartUpload", [fileID]);
+};
+
+// Public: cancelUpload cancels any queued file. The fileID parameter may be the file ID or index.
+// If you do not specify a fileID the current uploading file or first file in the queue is cancelled.
+// If you do not want the uploadError event to trigger you can specify false for the triggerErrorEvent parameter.
+SWFUpload.prototype.cancelUpload = function (fileID, triggerErrorEvent) {
+ if (triggerErrorEvent !== false) {
+ triggerErrorEvent = true;
+ }
+ this.callFlash("CancelUpload", [fileID, triggerErrorEvent]);
+};
+
+// Public: stopUpload stops the current upload and requeues the file at the beginning of the queue.
+// If nothing is currently uploading then nothing happens.
+SWFUpload.prototype.stopUpload = function () {
+ this.callFlash("StopUpload");
+};
+
+/* ************************
+ * Settings methods
+ * These methods change the SWFUpload settings.
+ * SWFUpload settings should not be changed directly on the settings object
+ * since many of the settings need to be passed to Flash in order to take
+ * effect.
+ * *********************** */
+
+// Public: getStats gets the file statistics object.
+SWFUpload.prototype.getStats = function () {
+ return this.callFlash("GetStats");
+};
+
+// Public: setStats changes the SWFUpload statistics. You shouldn't need to
+// change the statistics but you can. Changing the statistics does not
+// affect SWFUpload accept for the successful_uploads count which is used
+// by the upload_limit setting to determine how many files the user may upload.
+SWFUpload.prototype.setStats = function (statsObject) {
+ this.callFlash("SetStats", [statsObject]);
+};
+
+// Public: getFile retrieves a File object by ID or Index. If the file is
+// not found then 'null' is returned.
+SWFUpload.prototype.getFile = function (fileID) {
+ if (typeof(fileID) === "number") {
+ return this.callFlash("GetFileByIndex", [fileID]);
+ } else {
+ return this.callFlash("GetFile", [fileID]);
+ }
+};
+
+// Public: addFileParam sets a name/value pair that will be posted with the
+// file specified by the Files ID. If the name already exists then the
+// exiting value will be overwritten.
+SWFUpload.prototype.addFileParam = function (fileID, name, value) {
+ return this.callFlash("AddFileParam", [fileID, name, value]);
+};
+
+// Public: removeFileParam removes a previously set (by addFileParam) name/value
+// pair from the specified file.
+SWFUpload.prototype.removeFileParam = function (fileID, name) {
+ this.callFlash("RemoveFileParam", [fileID, name]);
+};
+
+// Public: setUploadUrl changes the upload_url setting.
+SWFUpload.prototype.setUploadURL = function (url) {
+ this.settings.upload_url = url.toString();
+ this.callFlash("SetUploadURL", [url]);
+};
+
+// Public: setPostParams changes the post_params setting
+SWFUpload.prototype.setPostParams = function (paramsObject) {
+ this.settings.post_params = paramsObject;
+ this.callFlash("SetPostParams", [paramsObject]);
+};
+
+// Public: addPostParam adds post name/value pair. Each name can have only one value.
+SWFUpload.prototype.addPostParam = function (name, value) {
+ this.settings.post_params[name] = value;
+ this.callFlash("SetPostParams", [this.settings.post_params]);
+};
+
+// Public: removePostParam deletes post name/value pair.
+SWFUpload.prototype.removePostParam = function (name) {
+ delete this.settings.post_params[name];
+ this.callFlash("SetPostParams", [this.settings.post_params]);
+};
+
+// Public: setFileTypes changes the file_types setting and the file_types_description setting
+SWFUpload.prototype.setFileTypes = function (types, description) {
+ this.settings.file_types = types;
+ this.settings.file_types_description = description;
+ this.callFlash("SetFileTypes", [types, description]);
+};
+
+// Public: setFileSizeLimit changes the file_size_limit setting
+SWFUpload.prototype.setFileSizeLimit = function (fileSizeLimit) {
+ this.settings.file_size_limit = fileSizeLimit;
+ this.callFlash("SetFileSizeLimit", [fileSizeLimit]);
+};
+
+// Public: setFileUploadLimit changes the file_upload_limit setting
+SWFUpload.prototype.setFileUploadLimit = function (fileUploadLimit) {
+ this.settings.file_upload_limit = fileUploadLimit;
+ this.callFlash("SetFileUploadLimit", [fileUploadLimit]);
+};
+
+// Public: setFileQueueLimit changes the file_queue_limit setting
+SWFUpload.prototype.setFileQueueLimit = function (fileQueueLimit) {
+ this.settings.file_queue_limit = fileQueueLimit;
+ this.callFlash("SetFileQueueLimit", [fileQueueLimit]);
+};
+
+// Public: setFilePostName changes the file_post_name setting
+SWFUpload.prototype.setFilePostName = function (filePostName) {
+ this.settings.file_post_name = filePostName;
+ this.callFlash("SetFilePostName", [filePostName]);
+};
+
+// Public: setUseQueryString changes the use_query_string setting
+SWFUpload.prototype.setUseQueryString = function (useQueryString) {
+ this.settings.use_query_string = useQueryString;
+ this.callFlash("SetUseQueryString", [useQueryString]);
+};
+
+// Public: setRequeueOnError changes the requeue_on_error setting
+SWFUpload.prototype.setRequeueOnError = function (requeueOnError) {
+ this.settings.requeue_on_error = requeueOnError;
+ this.callFlash("SetRequeueOnError", [requeueOnError]);
+};
+
+// Public: setHTTPSuccess changes the http_success setting
+SWFUpload.prototype.setHTTPSuccess = function (http_status_codes) {
+ if (typeof http_status_codes === "string") {
+ http_status_codes = http_status_codes.replace(" ", "").split(",");
+ }
+
+ this.settings.http_success = http_status_codes;
+ this.callFlash("SetHTTPSuccess", [http_status_codes]);
+};
+
+// Public: setHTTPSuccess changes the http_success setting
+SWFUpload.prototype.setAssumeSuccessTimeout = function (timeout_seconds) {
+ this.settings.assume_success_timeout = timeout_seconds;
+ this.callFlash("SetAssumeSuccessTimeout", [timeout_seconds]);
+};
+
+// Public: setDebugEnabled changes the debug_enabled setting
+SWFUpload.prototype.setDebugEnabled = function (debugEnabled) {
+ this.settings.debug_enabled = debugEnabled;
+ this.callFlash("SetDebugEnabled", [debugEnabled]);
+};
+
+// Public: setButtonImageURL loads a button image sprite
+SWFUpload.prototype.setButtonImageURL = function (buttonImageURL) {
+ if (buttonImageURL == undefined) {
+ buttonImageURL = "";
+ }
+
+ this.settings.button_image_url = buttonImageURL;
+ this.callFlash("SetButtonImageURL", [buttonImageURL]);
+};
+
+// Public: setButtonDimensions resizes the Flash Movie and button
+SWFUpload.prototype.setButtonDimensions = function (width, height) {
+ this.settings.button_width = width;
+ this.settings.button_height = height;
+
+ var movie = this.getMovieElement();
+ if (movie != undefined) {
+ movie.style.width = width + "px";
+ movie.style.height = height + "px";
+ }
+
+ this.callFlash("SetButtonDimensions", [width, height]);
+};
+// Public: setButtonText Changes the text overlaid on the button
+SWFUpload.prototype.setButtonText = function (html) {
+ this.settings.button_text = html;
+ this.callFlash("SetButtonText", [html]);
+};
+// Public: setButtonTextPadding changes the top and left padding of the text overlay
+SWFUpload.prototype.setButtonTextPadding = function (left, top) {
+ this.settings.button_text_top_padding = top;
+ this.settings.button_text_left_padding = left;
+ this.callFlash("SetButtonTextPadding", [left, top]);
+};
+
+// Public: setButtonTextStyle changes the CSS used to style the HTML/Text overlaid on the button
+SWFUpload.prototype.setButtonTextStyle = function (css) {
+ this.settings.button_text_style = css;
+ this.callFlash("SetButtonTextStyle", [css]);
+};
+// Public: setButtonDisabled disables/enables the button
+SWFUpload.prototype.setButtonDisabled = function (isDisabled) {
+ this.settings.button_disabled = isDisabled;
+ this.callFlash("SetButtonDisabled", [isDisabled]);
+};
+// Public: setButtonAction sets the action that occurs when the button is clicked
+SWFUpload.prototype.setButtonAction = function (buttonAction) {
+ this.settings.button_action = buttonAction;
+ this.callFlash("SetButtonAction", [buttonAction]);
+};
+
+// Public: setButtonCursor changes the mouse cursor displayed when hovering over the button
+SWFUpload.prototype.setButtonCursor = function (cursor) {
+ this.settings.button_cursor = cursor;
+ this.callFlash("SetButtonCursor", [cursor]);
+};
+
+/* *******************************
+ Flash Event Interfaces
+ These functions are used by Flash to trigger the various
+ events.
+
+ All these functions a Private.
+
+ Because the ExternalInterface library is buggy the event calls
+ are added to a queue and the queue then executed by a setTimeout.
+ This ensures that events are executed in a determinate order and that
+ the ExternalInterface bugs are avoided.
+******************************* */
+
+SWFUpload.prototype.queueEvent = function (handlerName, argumentArray) {
+ // Warning: Don't call this.debug inside here or you'll create an infinite loop
+
+ if (argumentArray == undefined) {
+ argumentArray = [];
+ } else if (!(argumentArray instanceof Array)) {
+ argumentArray = [argumentArray];
+ }
+
+ var self = this;
+ if (typeof this.settings[handlerName] === "function") {
+ // Queue the event
+ this.eventQueue.push(function () {
+ this.settings[handlerName].apply(this, argumentArray);
+ });
+
+ // Execute the next queued event
+ setTimeout(function () {
+ self.executeNextEvent();
+ }, 0);
+
+ } else if (this.settings[handlerName] !== null) {
+ throw "Event handler " + handlerName + " is unknown or is not a function";
+ }
+};
+
+// Private: Causes the next event in the queue to be executed. Since events are queued using a setTimeout
+// we must queue them in order to garentee that they are executed in order.
+SWFUpload.prototype.executeNextEvent = function () {
+ // Warning: Don't call this.debug inside here or you'll create an infinite loop
+
+ var f = this.eventQueue ? this.eventQueue.shift() : null;
+ if (typeof(f) === "function") {
+ f.apply(this);
+ }
+};
+
+// Private: unescapeFileParams is part of a workaround for a flash bug where objects passed through ExternalInterface cannot have
+// properties that contain characters that are not valid for JavaScript identifiers. To work around this
+// the Flash Component escapes the parameter names and we must unescape again before passing them along.
+SWFUpload.prototype.unescapeFilePostParams = function (file) {
+ var reg = /[$]([0-9a-f]{4})/i;
+ var unescapedPost = {};
+ var uk;
+
+ if (file != undefined) {
+ for (var k in file.post) {
+ if (file.post.hasOwnProperty(k)) {
+ uk = k;
+ var match;
+ while ((match = reg.exec(uk)) !== null) {
+ uk = uk.replace(match[0], String.fromCharCode(parseInt("0x" + match[1], 16)));
+ }
+ unescapedPost[uk] = file.post[k];
+ }
+ }
+
+ file.post = unescapedPost;
+ }
+
+ return file;
+};
+
+// Private: Called by Flash to see if JS can call in to Flash (test if External Interface is working)
+SWFUpload.prototype.testExternalInterface = function () {
+ try {
+ return this.callFlash("TestExternalInterface");
+ } catch (ex) {
+ return false;
+ }
+};
+
+// Private: This event is called by Flash when it has finished loading. Don't modify this.
+// Use the swfupload_loaded_handler event setting to execute custom code when SWFUpload has loaded.
+SWFUpload.prototype.flashReady = function () {
+ // Check that the movie element is loaded correctly with its ExternalInterface methods defined
+ var movieElement = this.getMovieElement();
+
+ if (!movieElement) {
+ this.debug("Flash called back ready but the flash movie can't be found.");
+ return;
+ }
+
+ this.cleanUp(movieElement);
+
+ this.queueEvent("swfupload_loaded_handler");
+};
+
+// Private: removes Flash added fuctions to the DOM node to prevent memory leaks in IE.
+// This function is called by Flash each time the ExternalInterface functions are created.
+SWFUpload.prototype.cleanUp = function (movieElement) {
+ // Pro-actively unhook all the Flash functions
+ try {
+ if (this.movieElement && typeof(movieElement.CallFunction) === "unknown") { // We only want to do this in IE
+ this.debug("Removing Flash functions hooks (this should only run in IE and should prevent memory leaks)");
+ for (var key in movieElement) {
+ try {
+ if (typeof(movieElement[key]) === "function") {
+ movieElement[key] = null;
+ }
+ } catch (ex) {
+ }
+ }
+ }
+ } catch (ex1) {
+
+ }
+
+ // Fix Flashes own cleanup code so if the SWFMovie was removed from the page
+ // it doesn't display errors.
+ window["__flash__removeCallback"] = function (instance, name) {
+ try {
+ if (instance) {
+ instance[name] = null;
+ }
+ } catch (flashEx) {
+
+ }
+ };
+
+};
+
+
+/* This is a chance to do something before the browse window opens */
+SWFUpload.prototype.fileDialogStart = function () {
+ this.queueEvent("file_dialog_start_handler");
+};
+
+
+/* Called when a file is successfully added to the queue. */
+SWFUpload.prototype.fileQueued = function (file) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("file_queued_handler", file);
+};
+
+
+/* Handle errors that occur when an attempt to queue a file fails. */
+SWFUpload.prototype.fileQueueError = function (file, errorCode, message) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("file_queue_error_handler", [file, errorCode, message]);
+};
+
+/* Called after the file dialog has closed and the selected files have been queued.
+ You could call startUpload here if you want the queued files to begin uploading immediately. */
+SWFUpload.prototype.fileDialogComplete = function (numFilesSelected, numFilesQueued, numFilesInQueue) {
+ this.queueEvent("file_dialog_complete_handler", [numFilesSelected, numFilesQueued, numFilesInQueue]);
+};
+
+SWFUpload.prototype.uploadStart = function (file) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("return_upload_start_handler", file);
+};
+
+SWFUpload.prototype.returnUploadStart = function (file) {
+ var returnValue;
+ if (typeof this.settings.upload_start_handler === "function") {
+ file = this.unescapeFilePostParams(file);
+ returnValue = this.settings.upload_start_handler.call(this, file);
+ } else if (this.settings.upload_start_handler != undefined) {
+ throw "upload_start_handler must be a function";
+ }
+
+ // Convert undefined to true so if nothing is returned from the upload_start_handler it is
+ // interpretted as 'true'.
+ if (returnValue === undefined) {
+ returnValue = true;
+ }
+
+ returnValue = !!returnValue;
+
+ this.callFlash("ReturnUploadStart", [returnValue]);
+};
+
+
+
+SWFUpload.prototype.uploadProgress = function (file, bytesComplete, bytesTotal) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_progress_handler", [file, bytesComplete, bytesTotal]);
+};
+
+SWFUpload.prototype.uploadError = function (file, errorCode, message) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_error_handler", [file, errorCode, message]);
+};
+
+SWFUpload.prototype.uploadSuccess = function (file, serverData, responseReceived) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_success_handler", [file, serverData, responseReceived]);
+};
+
+SWFUpload.prototype.uploadComplete = function (file) {
+ file = this.unescapeFilePostParams(file);
+ this.queueEvent("upload_complete_handler", file);
+};
+
+/* Called by SWFUpload JavaScript and Flash functions when debug is enabled. By default it writes messages to the
+ internal debug console. You can override this event and have messages written where you want. */
+SWFUpload.prototype.debug = function (message) {
+ this.queueEvent("debug_handler", message);
+};
+
+
+/* **********************************
+ Debug Console
+ The debug console is a self contained, in page location
+ for debug message to be sent. The Debug Console adds
+ itself to the body if necessary.
+
+ The console is automatically scrolled as messages appear.
+
+ If you are using your own debug handler or when you deploy to production and
+ have debug disabled you can remove these functions to reduce the file size
+ and complexity.
+********************************** */
+
+// Private: debugMessage is the default debug_handler. If you want to print debug messages
+// call the debug() function. When overriding the function your own function should
+// check to see if the debug setting is true before outputting debug information.
+SWFUpload.prototype.debugMessage = function (message) {
+ if (this.settings.debug) {
+ var exceptionMessage, exceptionValues = [];
+
+ // Check for an exception object and print it nicely
+ if (typeof message === "object" && typeof message.name === "string" && typeof message.message === "string") {
+ for (var key in message) {
+ if (message.hasOwnProperty(key)) {
+ exceptionValues.push(key + ": " + message[key]);
+ }
+ }
+ exceptionMessage = exceptionValues.join("\n") || "";
+ exceptionValues = exceptionMessage.split("\n");
+ exceptionMessage = "EXCEPTION: " + exceptionValues.join("\nEXCEPTION: ");
+ SWFUpload.Console.writeLine(exceptionMessage);
+ } else {
+ SWFUpload.Console.writeLine(message);
+ }
+ }
+};
+
+SWFUpload.Console = {};
+SWFUpload.Console.writeLine = function (message) {
+ var console, documentForm;
+
+ try {
+ console = document.getElementById("SWFUpload_Console");
+
+ if (!console) {
+ documentForm = document.createElement("form");
+ document.getElementsByTagName("body")[0].appendChild(documentForm);
+
+ console = document.createElement("textarea");
+ console.id = "SWFUpload_Console";
+ console.style.fontFamily = "monospace";
+ console.setAttribute("wrap", "off");
+ console.wrap = "off";
+ console.style.overflow = "auto";
+ console.style.width = "700px";
+ console.style.height = "350px";
+ console.style.margin = "5px";
+ documentForm.appendChild(console);
+ }
+
+ console.value += message + "\n";
+
+ console.scrollTop = console.scrollHeight - console.clientHeight;
+ } catch (ex) {
+ alert("Exception: " + ex.name + " Message: " + ex.message);
+ }
+};
diff --git a/src/wp-includes/js/swfupload/swfupload.swf b/src/wp-includes/js/swfupload/swfupload.swf
new file mode 100644
index 0000000000..7d94bbab5d
--- /dev/null
+++ b/src/wp-includes/js/swfupload/swfupload.swf
Binary files differ
diff --git a/src/wp-includes/js/thickbox/loadingAnimation.gif b/src/wp-includes/js/thickbox/loadingAnimation.gif
new file mode 100644
index 0000000000..030d4de59d
--- /dev/null
+++ b/src/wp-includes/js/thickbox/loadingAnimation.gif
Binary files differ
diff --git a/src/wp-includes/js/thickbox/macFFBgHack.png b/src/wp-includes/js/thickbox/macFFBgHack.png
new file mode 100644
index 0000000000..a032659389
--- /dev/null
+++ b/src/wp-includes/js/thickbox/macFFBgHack.png
Binary files differ
diff --git a/src/wp-includes/js/thickbox/tb-close-2x.png b/src/wp-includes/js/thickbox/tb-close-2x.png
new file mode 100644
index 0000000000..fb820d6fde
--- /dev/null
+++ b/src/wp-includes/js/thickbox/tb-close-2x.png
Binary files differ
diff --git a/src/wp-includes/js/thickbox/tb-close.png b/src/wp-includes/js/thickbox/tb-close.png
new file mode 100644
index 0000000000..06d04070b6
--- /dev/null
+++ b/src/wp-includes/js/thickbox/tb-close.png
Binary files differ
diff --git a/src/wp-includes/js/thickbox/thickbox.css b/src/wp-includes/js/thickbox/thickbox.css
new file mode 100644
index 0000000000..53438f104b
--- /dev/null
+++ b/src/wp-includes/js/thickbox/thickbox.css
@@ -0,0 +1,178 @@
+
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+#TB_window {
+ font: 12px sans-serif;
+ color: #333333;
+}
+
+#TB_secondLine {
+ font: 10px sans-serif;
+ color:#666666;
+}
+
+#TB_window a:link {color: #666666;}
+#TB_window a:visited {color: #666666;}
+#TB_window a:hover {color: #000;}
+#TB_window a:active {color: #666666;}
+#TB_window a:focus{color: #666666;}
+
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+#TB_overlay {
+ position: fixed;
+ z-index:100;
+ top: 0px;
+ left: 0px;
+ height:100%;
+ width:100%;
+}
+
+.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;}
+.TB_overlayBG {
+ background-color:#000;
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=75)";
+ filter:alpha(opacity=75);
+ -moz-opacity: 0.75;
+ opacity: 0.75;
+}
+
+* html #TB_overlay { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_window {
+ position: fixed;
+ background: #ffffff;
+ z-index: 102;
+ color:#000000;
+ visibility: hidden;
+ text-align:left;
+ top:50%;
+ left:50%;
+ border: 1px solid #555;
+ -moz-box-shadow: rgba(0,0,0,1) 0 4px 30px;
+ -webkit-box-shadow: rgba(0,0,0,1) 0 4px 30px;
+ -khtml-box-shadow: rgba(0,0,0,1) 0 4px 30px;
+ box-shadow: rgba(0,0,0,1) 0 4px 30px;
+}
+
+* html #TB_window { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_window img#TB_Image {
+ display:block;
+ margin: 15px 0 0 15px;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ border-top: 1px solid #666;
+ border-left: 1px solid #666;
+}
+
+#TB_caption{
+ height:25px;
+ padding:7px 30px 10px 25px;
+ float:left;
+}
+
+#TB_closeWindow{
+ height:25px;
+ padding:11px 25px 10px 0;
+ float:right;
+}
+
+#TB_closeAjaxWindow{
+ padding:6px 10px 0;
+ text-align:right;
+ float:right;
+}
+
+#TB_ajaxWindowTitle{
+ float:left;
+ padding:6px 10px 0;
+}
+
+#TB_title{
+ background-color:#e8e8e8;
+ height:27px;
+}
+
+#TB_ajaxContent{
+ clear:both;
+ padding:2px 15px 15px 15px;
+ overflow:auto;
+ text-align:left;
+ line-height:1.4em;
+}
+
+#TB_ajaxContent.TB_modal{
+ padding:15px;
+}
+
+#TB_ajaxContent p{
+ padding:5px 0px 5px 0px;
+}
+
+#TB_load{
+ position: fixed;
+ display:none;
+ z-index:103;
+ top: 50%;
+ left: 50%;
+ background-color: #E8E8E8;
+ border: 1px solid #555;
+ margin: -45px 0pt 0pt -125px;
+ padding: 40px 15px 15px;
+}
+
+* html #TB_load { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_HideSelect{
+ z-index:99;
+ position:fixed;
+ top: 0;
+ left: 0;
+ background-color:#fff;
+ border:none;
+ filter:alpha(opacity=0);
+ -moz-opacity: 0;
+ opacity: 0;
+ height:100%;
+ width:100%;
+}
+
+* html #TB_HideSelect { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_iframeContent{
+ clear:both;
+ border:none;
+ margin-bottom:-1px;
+ _margin-bottom:1px;
+}
+
+.tb-close-icon {
+ background: url('tb-close.png') no-repeat;
+ height: 15px;
+ width: 15px;
+}
+
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ .tb-close-icon {
+ background: url('tb-close-2x.png') no-repeat;
+ background-size: 15px;
+ }
+} \ No newline at end of file
diff --git a/src/wp-includes/js/thickbox/thickbox.js b/src/wp-includes/js/thickbox/thickbox.js
new file mode 100644
index 0000000000..e874446b80
--- /dev/null
+++ b/src/wp-includes/js/thickbox/thickbox.js
@@ -0,0 +1,319 @@
+/*
+ * Thickbox 3.1 - One Box To Rule Them All.
+ * By Cody Lindley (http://www.codylindley.com)
+ * Copyright (c) 2007 cody lindley
+ * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+if ( typeof tb_pathToImage != 'string' ) {
+ var tb_pathToImage = thickboxL10n.loadingAnimation;
+}
+
+/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/
+
+//on page load call tb_init
+jQuery(document).ready(function(){
+ tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
+ imgLoader = new Image();// preload image
+ imgLoader.src = tb_pathToImage;
+});
+
+//add thickbox to href & area elements that have a class of .thickbox
+function tb_init(domChunk){
+ jQuery('body').on('click', domChunk, tb_click);
+}
+
+function tb_click(){
+ var t = this.title || this.name || null;
+ var a = this.href || this.alt;
+ var g = this.rel || false;
+ tb_show(t,a,g);
+ this.blur();
+ return false;
+}
+
+function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link
+
+ try {
+ if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
+ jQuery("body","html").css({height: "100%", width: "100%"});
+ jQuery("html").css("overflow","hidden");
+ if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
+ jQuery("body").append("<iframe id='TB_HideSelect'>"+thickboxL10n.noiframes+"</iframe><div id='TB_overlay'></div><div id='TB_window'></div>");
+ jQuery("#TB_overlay").click(tb_remove);
+ }
+ }else{//all others
+ if(document.getElementById("TB_overlay") === null){
+ jQuery("body").append("<div id='TB_overlay'></div><div id='TB_window'></div>");
+ jQuery("#TB_overlay").click(tb_remove);
+ }
+ }
+
+ if(tb_detectMacXFF()){
+ jQuery("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
+ }else{
+ jQuery("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
+ }
+
+ if(caption===null){caption="";}
+ jQuery("body").append("<div id='TB_load'><img src='"+imgLoader.src+"' width='208' /></div>");//add loader to the page
+ jQuery('#TB_load').show();//show loader
+
+ var baseURL;
+ if(url.indexOf("?")!==-1){ //ff there is a query string involved
+ baseURL = url.substr(0, url.indexOf("?"));
+ }else{
+ baseURL = url;
+ }
+
+ var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
+ var urlType = baseURL.toLowerCase().match(urlString);
+
+ if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
+
+ TB_PrevCaption = "";
+ TB_PrevURL = "";
+ TB_PrevHTML = "";
+ TB_NextCaption = "";
+ TB_NextURL = "";
+ TB_NextHTML = "";
+ TB_imageCount = "";
+ TB_FoundURL = false;
+ if(imageGroup){
+ TB_TempArray = jQuery("a[rel="+imageGroup+"]").get();
+ for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
+ var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
+ if (!(TB_TempArray[TB_Counter].href == url)) {
+ if (TB_FoundURL) {
+ TB_NextCaption = TB_TempArray[TB_Counter].title;
+ TB_NextURL = TB_TempArray[TB_Counter].href;
+ TB_NextHTML = "<span id='TB_next'>&nbsp;&nbsp;<a href='#'>"+thickboxL10n.next+"</a></span>";
+ } else {
+ TB_PrevCaption = TB_TempArray[TB_Counter].title;
+ TB_PrevURL = TB_TempArray[TB_Counter].href;
+ TB_PrevHTML = "<span id='TB_prev'>&nbsp;&nbsp;<a href='#'>"+thickboxL10n.prev+"</a></span>";
+ }
+ } else {
+ TB_FoundURL = true;
+ TB_imageCount = thickboxL10n.image + ' ' + (TB_Counter + 1) + ' ' + thickboxL10n.of + ' ' + (TB_TempArray.length);
+ }
+ }
+ }
+
+ imgPreloader = new Image();
+ imgPreloader.onload = function(){
+ imgPreloader.onload = null;
+
+ // Resizing large images - orginal by Christian Montoya edited by me.
+ var pagesize = tb_getPageSize();
+ var x = pagesize[0] - 150;
+ var y = pagesize[1] - 150;
+ var imageWidth = imgPreloader.width;
+ var imageHeight = imgPreloader.height;
+ if (imageWidth > x) {
+ imageHeight = imageHeight * (x / imageWidth);
+ imageWidth = x;
+ if (imageHeight > y) {
+ imageWidth = imageWidth * (y / imageHeight);
+ imageHeight = y;
+ }
+ } else if (imageHeight > y) {
+ imageWidth = imageWidth * (y / imageHeight);
+ imageHeight = y;
+ if (imageWidth > x) {
+ imageHeight = imageHeight * (x / imageWidth);
+ imageWidth = x;
+ }
+ }
+ // End Resizing
+
+ TB_WIDTH = imageWidth + 30;
+ TB_HEIGHT = imageHeight + 60;
+ jQuery("#TB_window").append("<a href='' id='TB_ImageOff' title='"+thickboxL10n.close+"'><img id='TB_Image' src='"+url+"' width='"+imageWidth+"' height='"+imageHeight+"' alt='"+caption+"'/></a>" + "<div id='TB_caption'>"+caption+"<div id='TB_secondLine'>" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='"+thickboxL10n.close+"'><div class='tb-close-icon'></div></a></div>");
+
+ jQuery("#TB_closeWindowButton").click(tb_remove);
+
+ if (!(TB_PrevHTML === "")) {
+ function goPrev(){
+ if(jQuery(document).unbind("click",goPrev)){jQuery(document).unbind("click",goPrev);}
+ jQuery("#TB_window").remove();
+ jQuery("body").append("<div id='TB_window'></div>");
+ tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
+ return false;
+ }
+ jQuery("#TB_prev").click(goPrev);
+ }
+
+ if (!(TB_NextHTML === "")) {
+ function goNext(){
+ jQuery("#TB_window").remove();
+ jQuery("body").append("<div id='TB_window'></div>");
+ tb_show(TB_NextCaption, TB_NextURL, imageGroup);
+ return false;
+ }
+ jQuery("#TB_next").click(goNext);
+
+ }
+
+ jQuery(document).bind('keydown.thickbox', function(e){
+ e.stopImmediatePropagation();
+
+ if ( e.which == 27 ){ // close
+ if ( ! jQuery(document).triggerHandler( 'wp_CloseOnEscape', [{ event: e, what: 'thickbox', cb: tb_remove }] ) )
+ tb_remove();
+
+ } else if ( e.which == 190 ){ // display previous image
+ if(!(TB_NextHTML == "")){
+ jQuery(document).unbind('thickbox');
+ goNext();
+ }
+ } else if ( e.which == 188 ){ // display next image
+ if(!(TB_PrevHTML == "")){
+ jQuery(document).unbind('thickbox');
+ goPrev();
+ }
+ }
+ return false;
+ });
+
+ tb_position();
+ jQuery("#TB_load").remove();
+ jQuery("#TB_ImageOff").click(tb_remove);
+ jQuery("#TB_window").css({'visibility':'visible'}); //for safari using css instead of show
+ };
+
+ imgPreloader.src = url;
+ }else{//code to show html
+
+ var queryString = url.replace(/^[^\?]+\??/,'');
+ var params = tb_parseQuery( queryString );
+
+ TB_WIDTH = (params['width']*1) + 30 || 630; //defaults to 630 if no paramaters were added to URL
+ TB_HEIGHT = (params['height']*1) + 40 || 440; //defaults to 440 if no paramaters were added to URL
+ ajaxContentW = TB_WIDTH - 30;
+ ajaxContentH = TB_HEIGHT - 45;
+
+ if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window
+ urlNoQuery = url.split('TB_');
+ jQuery("#TB_iframeContent").remove();
+ if(params['modal'] != "true"){//iframe no modal
+ jQuery("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='"+thickboxL10n.close+"'><div class='tb-close-icon'></div></a></div></div><iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;' >"+thickboxL10n.noiframes+"</iframe>");
+ }else{//iframe modal
+ jQuery("#TB_overlay").unbind();
+ jQuery("#TB_window").append("<iframe frameborder='0' hspace='0' src='"+urlNoQuery[0]+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW + 29)+"px;height:"+(ajaxContentH + 17)+"px;'>"+thickboxL10n.noiframes+"</iframe>");
+ }
+ }else{// not an iframe, ajax
+ if(jQuery("#TB_window").css("visibility") != "visible"){
+ if(params['modal'] != "true"){//ajax no modal
+ jQuery("#TB_window").append("<div id='TB_title'><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'><div class='tb-close-icon'></div></a></div></div><div id='TB_ajaxContent' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px'></div>");
+ }else{//ajax modal
+ jQuery("#TB_overlay").unbind();
+ jQuery("#TB_window").append("<div id='TB_ajaxContent' class='TB_modal' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px;'></div>");
+ }
+ }else{//this means the window is already up, we are just loading new content via ajax
+ jQuery("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
+ jQuery("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
+ jQuery("#TB_ajaxContent")[0].scrollTop = 0;
+ jQuery("#TB_ajaxWindowTitle").html(caption);
+ }
+ }
+
+ jQuery("#TB_closeWindowButton").click(tb_remove);
+
+ if(url.indexOf('TB_inline') != -1){
+ jQuery("#TB_ajaxContent").append(jQuery('#' + params['inlineId']).children());
+ jQuery("#TB_window").bind('tb_unload', function () {
+ jQuery('#' + params['inlineId']).append( jQuery("#TB_ajaxContent").children() ); // move elements back when you're finished
+ });
+ tb_position();
+ jQuery("#TB_load").remove();
+ jQuery("#TB_window").css({'visibility':'visible'});
+ }else if(url.indexOf('TB_iframe') != -1){
+ tb_position();
+ jQuery("#TB_load").remove();
+ jQuery("#TB_window").css({'visibility':'visible'});
+ }else{
+ jQuery("#TB_ajaxContent").load(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method
+ tb_position();
+ jQuery("#TB_load").remove();
+ tb_init("#TB_ajaxContent a.thickbox");
+ jQuery("#TB_window").css({'visibility':'visible'});
+ });
+ }
+
+ }
+
+ if(!params['modal']){
+ jQuery(document).bind('keyup.thickbox', function(e){
+
+ if ( e.which == 27 ){ // close
+ e.stopImmediatePropagation();
+ if ( ! jQuery(document).triggerHandler( 'wp_CloseOnEscape', [{ event: e, what: 'thickbox', cb: tb_remove }] ) )
+ tb_remove();
+
+ return false;
+ }
+ });
+ }
+
+ } catch(e) {
+ //nothing here
+ }
+}
+
+//helper functions below
+function tb_showIframe(){
+ jQuery("#TB_load").remove();
+ jQuery("#TB_window").css({'visibility':'visible'});
+}
+
+function tb_remove() {
+ jQuery("#TB_imageOff").unbind("click");
+ jQuery("#TB_closeWindowButton").unbind("click");
+ jQuery("#TB_window").fadeOut("fast",function(){jQuery('#TB_window,#TB_overlay,#TB_HideSelect').trigger("tb_unload").unbind().remove();});
+ jQuery("#TB_load").remove();
+ if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
+ jQuery("body","html").css({height: "auto", width: "auto"});
+ jQuery("html").css("overflow","");
+ }
+ jQuery(document).unbind('.thickbox');
+ return false;
+}
+
+function tb_position() {
+var isIE6 = typeof document.body.style.maxHeight === "undefined";
+jQuery("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});
+ if ( ! isIE6 ) { // take away IE6
+ jQuery("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});
+ }
+}
+
+function tb_parseQuery ( query ) {
+ var Params = {};
+ if ( ! query ) {return Params;}// return empty object
+ var Pairs = query.split(/[;&]/);
+ for ( var i = 0; i < Pairs.length; i++ ) {
+ var KeyVal = Pairs[i].split('=');
+ if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
+ var key = unescape( KeyVal[0] );
+ var val = unescape( KeyVal[1] );
+ val = val.replace(/\+/g, ' ');
+ Params[key] = val;
+ }
+ return Params;
+}
+
+function tb_getPageSize(){
+ var de = document.documentElement;
+ var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
+ var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
+ arrayPageSize = [w,h];
+ return arrayPageSize;
+}
+
+function tb_detectMacXFF() {
+ var userAgent = navigator.userAgent.toLowerCase();
+ if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
+ return true;
+ }
+}
diff --git a/src/wp-includes/js/tinymce/langs/wp-langs-en.js b/src/wp-includes/js/tinymce/langs/wp-langs-en.js
new file mode 100644
index 0000000000..8afafa61fd
--- /dev/null
+++ b/src/wp-includes/js/tinymce/langs/wp-langs-en.js
@@ -0,0 +1,504 @@
+tinyMCE.addI18n({en:{
+common:{
+edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?",
+apply:"Apply",
+insert:"Insert",
+update:"Update",
+cancel:"Cancel",
+close:"Close",
+browse:"Browse",
+class_name:"Class",
+not_set:"-- Not set --",
+clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.",
+clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",
+popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",
+invalid_data:"ERROR: Invalid values entered, these are marked in red.",
+invalid_data_number:"{#field} must be a number",
+invalid_data_min:"{#field} must be a number greater than {#min}",
+invalid_data_size:"{#field} must be a number or percentage",
+more_colors:"More colors"
+},
+colors:{
+"000000":"Black",
+"993300":"Burnt orange",
+"333300":"Dark olive",
+"003300":"Dark green",
+"003366":"Dark azure",
+"000080":"Navy Blue",
+"333399":"Indigo",
+"333333":"Very dark gray",
+"800000":"Maroon",
+"FF6600":"Orange",
+"808000":"Olive",
+"008000":"Green",
+"008080":"Teal",
+"0000FF":"Blue",
+"666699":"Grayish blue",
+"808080":"Gray",
+"FF0000":"Red",
+"FF9900":"Amber",
+"99CC00":"Yellow green",
+"339966":"Sea green",
+"33CCCC":"Turquoise",
+"3366FF":"Royal blue",
+"800080":"Purple",
+"999999":"Medium gray",
+"FF00FF":"Magenta",
+"FFCC00":"Gold",
+"FFFF00":"Yellow",
+"00FF00":"Lime",
+"00FFFF":"Aqua",
+"00CCFF":"Sky blue",
+"993366":"Brown",
+"C0C0C0":"Silver",
+"FF99CC":"Pink",
+"FFCC99":"Peach",
+"FFFF99":"Light yellow",
+"CCFFCC":"Pale green",
+"CCFFFF":"Pale cyan",
+"99CCFF":"Light sky blue",
+"CC99FF":"Plum",
+"FFFFFF":"White"
+},
+contextmenu:{
+align:"Alignment",
+left:"Left",
+center:"Center",
+right:"Right",
+full:"Full"
+},
+insertdatetime:{
+date_fmt:"%Y-%m-%d",
+time_fmt:"%H:%M:%S",
+insertdate_desc:"Insert date",
+inserttime_desc:"Insert time",
+months_long:"January,February,March,April,May,June,July,August,September,October,November,December",
+months_short:"Jan_January_abbreviation,Feb_February_abbreviation,Mar_March_abbreviation,Apr_April_abbreviation,May_May_abbreviation,Jun_June_abbreviation,Jul_July_abbreviation,Aug_August_abbreviation,Sep_September_abbreviation,Oct_October_abbreviation,Nov_November_abbreviation,Dec_December_abbreviation",
+day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
+day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat"
+},
+print:{
+print_desc:"Print"
+},
+preview:{
+preview_desc:"Preview"
+},
+directionality:{
+ltr_desc:"Direction left to right",
+rtl_desc:"Direction right to left"
+},
+layer:{
+insertlayer_desc:"Insert new layer",
+forward_desc:"Move forward",
+backward_desc:"Move backward",
+absolute_desc:"Toggle absolute positioning",
+content:"New layer..."
+},
+save:{
+save_desc:"Save",
+cancel_desc:"Cancel all changes"
+},
+nonbreaking:{
+nonbreaking_desc:"Insert non-breaking space character"
+},
+iespell:{
+iespell_desc:"Run spell checking",
+download:"ieSpell not detected. Do you want to install it now?"
+},
+advhr:{
+advhr_desc:"Horizontal rule"
+},
+emotions:{
+emotions_desc:"Emotions"
+},
+searchreplace:{
+search_desc:"Find",
+replace_desc:"Find/Replace"
+},
+advimage:{
+image_desc:"Insert/edit image"
+},
+advlink:{
+link_desc:"Insert/edit link"
+},
+xhtmlxtras:{
+cite_desc:"Citation",
+abbr_desc:"Abbreviation",
+acronym_desc:"Acronym",
+del_desc:"Deletion",
+ins_desc:"Insertion",
+attribs_desc:"Insert/Edit Attributes"
+},
+style:{
+desc:"Edit CSS Style"
+},
+paste:{
+paste_text_desc:"Paste as Plain Text",
+paste_word_desc:"Paste from Word",
+selectall_desc:"Select All",
+plaintext_mode_sticky:"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.",
+plaintext_mode:"Paste is now in plain text mode. Click again to toggle back to regular paste mode."
+},
+paste_dlg:{
+text_title:"Use CTRL + V on your keyboard to paste the text into the window.",
+text_linebreaks:"Keep linebreaks",
+word_title:"Use CTRL + V on your keyboard to paste the text into the window."
+},
+table:{
+desc:"Inserts a new table",
+row_before_desc:"Insert row before",
+row_after_desc:"Insert row after",
+delete_row_desc:"Delete row",
+col_before_desc:"Insert column before",
+col_after_desc:"Insert column after",
+delete_col_desc:"Remove column",
+split_cells_desc:"Split merged table cells",
+merge_cells_desc:"Merge table cells",
+row_desc:"Table row properties",
+cell_desc:"Table cell properties",
+props_desc:"Table properties",
+paste_row_before_desc:"Paste table row before",
+paste_row_after_desc:"Paste table row after",
+cut_row_desc:"Cut table row",
+copy_row_desc:"Copy table row",
+del:"Delete table",
+row:"Row",
+col:"Column",
+cell:"Cell"
+},
+autosave:{
+unload_msg:"The changes you made will be lost if you navigate away from this page."
+},
+fullscreen:{
+desc:"Toggle fullscreen mode (Alt + Shift + G)"
+},
+media:{
+desc:"Insert / edit embedded media",
+edit:"Edit embedded media"
+},
+fullpage:{
+desc:"Document properties"
+},
+template:{
+desc:"Insert predefined template content"
+},
+visualchars:{
+desc:"Visual control characters on/off."
+},
+spellchecker:{
+desc:"Toggle spellchecker (Alt + Shift + N)",
+menu:"Spellchecker settings",
+ignore_word:"Ignore word",
+ignore_words:"Ignore all",
+langs:"Languages",
+wait:"Please wait...",
+sug:"Suggestions",
+no_sug:"No suggestions",
+no_mpell:"No misspellings found.",
+learn_word:"Learn word"
+},
+pagebreak:{
+desc:"Insert Page Break"
+},
+advlist:{
+types:"Types",
+def:"Default",
+lower_alpha:"Lower alpha",
+lower_greek:"Lower greek",
+lower_roman:"Lower roman",
+upper_alpha:"Upper alpha",
+upper_roman:"Upper roman",
+circle:"Circle",
+disc:"Disc",
+square:"Square"
+},
+aria:{
+rich_text_area:"Rich Text Area"
+},
+wordcount:{
+words:"Words: "
+}
+}});
+
+tinyMCE.addI18n("en.advanced",{
+style_select:"Styles",
+font_size:"Font size",
+fontdefault:"Font family",
+block:"Format",
+paragraph:"Paragraph",
+div:"Div",
+address:"Address",
+pre:"Preformatted",
+h1:"Heading 1",
+h2:"Heading 2",
+h3:"Heading 3",
+h4:"Heading 4",
+h5:"Heading 5",
+h6:"Heading 6",
+blockquote:"Blockquote",
+code:"Code",
+samp:"Code sample",
+dt:"Definition term ",
+dd:"Definition description",
+bold_desc:"Bold (Ctrl + B)",
+italic_desc:"Italic (Ctrl + I)",
+underline_desc:"Underline",
+striketrough_desc:"Strikethrough (Alt + Shift + D)",
+justifyleft_desc:"Align Left (Alt + Shift + L)",
+justifycenter_desc:"Align Center (Alt + Shift + C)",
+justifyright_desc:"Align Right (Alt + Shift + R)",
+justifyfull_desc:"Align Full (Alt + Shift + J)",
+bullist_desc:"Unordered list (Alt + Shift + U)",
+numlist_desc:"Ordered list (Alt + Shift + O)",
+outdent_desc:"Outdent",
+indent_desc:"Indent",
+undo_desc:"Undo (Ctrl + Z)",
+redo_desc:"Redo (Ctrl + Y)",
+link_desc:"Insert/edit link (Alt + Shift + A)",
+unlink_desc:"Unlink (Alt + Shift + S)",
+image_desc:"Insert/edit image (Alt + Shift + M)",
+cleanup_desc:"Cleanup messy code",
+code_desc:"Edit HTML Source",
+sub_desc:"Subscript",
+sup_desc:"Superscript",
+hr_desc:"Insert horizontal ruler",
+removeformat_desc:"Remove formatting",
+forecolor_desc:"Select text color",
+backcolor_desc:"Select background color",
+charmap_desc:"Insert custom character",
+visualaid_desc:"Toggle guidelines/invisible elements",
+anchor_desc:"Insert/edit anchor",
+cut_desc:"Cut",
+copy_desc:"Copy",
+paste_desc:"Paste",
+image_props_desc:"Image properties",
+newdocument_desc:"New document",
+help_desc:"Help",
+blockquote_desc:"Blockquote (Alt + Shift + Q)",
+clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.",
+path:"Path",
+newdocument:"Are you sure you want to clear all contents?",
+toolbar_focus:"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X",
+more_colors:"More colors",
+shortcuts_desc:"Accessibility Help",
+help_shortcut:" Press ALT F10 for toolbar. Press ALT 0 for help.",
+rich_text_area:"Rich Text Area",
+toolbar:"Toolbar"
+});
+
+tinyMCE.addI18n("en.advanced_dlg",{
+about_title:"About TinyMCE",
+about_general:"About",
+about_help:"Help",
+about_license:"License",
+about_plugins:"Plugins",
+about_plugin:"Plugin",
+about_author:"Author",
+about_version:"Version",
+about_loaded:"Loaded plugins",
+anchor_title:"Insert/edit anchor",
+anchor_name:"Anchor name",
+code_title:"HTML Source Editor",
+code_wordwrap:"Word wrap",
+colorpicker_title:"Select a color",
+colorpicker_picker_tab:"Picker",
+colorpicker_picker_title:"Color picker",
+colorpicker_palette_tab:"Palette",
+colorpicker_palette_title:"Palette colors",
+colorpicker_named_tab:"Named",
+colorpicker_named_title:"Named colors",
+colorpicker_color:"Color:",
+colorpicker_name:"Name:",
+charmap_title:"Select custom character",
+charmap_usage:"Use left and right arrows to navigate.",
+image_title:"Insert/edit image",
+image_src:"Image URL",
+image_alt:"Image description",
+image_list:"Image list",
+image_border:"Border",
+image_dimensions:"Dimensions",
+image_vspace:"Vertical space",
+image_hspace:"Horizontal space",
+image_align:"Alignment",
+image_align_baseline:"Baseline",
+image_align_top:"Top",
+image_align_middle:"Middle",
+image_align_bottom:"Bottom",
+image_align_texttop:"Text top",
+image_align_textbottom:"Text bottom",
+image_align_left:"Left",
+image_align_right:"Right",
+link_title:"Insert/edit link",
+link_url:"Link URL",
+link_target:"Target",
+link_target_same:"Open link in the same window",
+link_target_blank:"Open link in a new window",
+link_titlefield:"Title",
+link_is_email:"The URL you entered seems to be an email address, do you want to add the required mailto: prefix?",
+link_is_external:"The URL you entered seems to external link, do you want to add the required http:// prefix?",
+link_list:"Link list",
+accessibility_help:"Accessibility Help",
+accessibility_usage_title:"General Usage"
+});
+
+tinyMCE.addI18n("en.media_dlg",{
+title:"Insert / edit embedded media",
+general:"General",
+advanced:"Advanced",
+file:"File/URL",
+list:"List",
+size:"Dimensions",
+preview:"Preview",
+constrain_proportions:"Constrain proportions",
+type:"Type",
+id:"Id",
+name:"Name",
+class_name:"Class",
+vspace:"V-Space",
+hspace:"H-Space",
+play:"Auto play",
+loop:"Loop",
+menu:"Show menu",
+quality:"Quality",
+scale:"Scale",
+align:"Align",
+salign:"SAlign",
+wmode:"WMode",
+bgcolor:"Background",
+base:"Base",
+flashvars:"Flashvars",
+liveconnect:"SWLiveConnect",
+autohref:"AutoHREF",
+cache:"Cache",
+hidden:"Hidden",
+controller:"Controller",
+kioskmode:"Kiosk mode",
+playeveryframe:"Play every frame",
+targetcache:"Target cache",
+correction:"No correction",
+enablejavascript:"Enable JavaScript",
+starttime:"Start time",
+endtime:"End time",
+href:"href",
+qtsrcchokespeed:"Choke speed",
+target:"Target",
+volume:"Volume",
+autostart:"Auto start",
+enabled:"Enabled",
+fullscreen:"Fullscreen",
+invokeurls:"Invoke URLs",
+mute:"Mute",
+stretchtofit:"Stretch to fit",
+windowlessvideo:"Windowless video",
+balance:"Balance",
+baseurl:"Base URL",
+captioningid:"Captioning id",
+currentmarker:"Current marker",
+currentposition:"Current position",
+defaultframe:"Default frame",
+playcount:"Play count",
+rate:"Rate",
+uimode:"UI Mode",
+flash_options:"Flash options",
+qt_options:"QuickTime options",
+wmp_options:"Windows media player options",
+rmp_options:"Real media player options",
+shockwave_options:"Shockwave options",
+autogotourl:"Auto goto URL",
+center:"Center",
+imagestatus:"Image status",
+maintainaspect:"Maintain aspect",
+nojava:"No java",
+prefetch:"Prefetch",
+shuffle:"Shuffle",
+console:"Console",
+numloop:"Num loops",
+controls:"Controls",
+scriptcallbacks:"Script callbacks",
+swstretchstyle:"Stretch style",
+swstretchhalign:"Stretch H-Align",
+swstretchvalign:"Stretch V-Align",
+sound:"Sound",
+progress:"Progress",
+qtsrc:"QT Src",
+qt_stream_warn:"Streamed rtsp resources should be added to the QT Src field under the advanced tab.",
+align_top:"Top",
+align_right:"Right",
+align_bottom:"Bottom",
+align_left:"Left",
+align_center:"Center",
+align_top_left:"Top left",
+align_top_right:"Top right",
+align_bottom_left:"Bottom left",
+align_bottom_right:"Bottom right",
+flv_options:"Flash video options",
+flv_scalemode:"Scale mode",
+flv_buffer:"Buffer",
+flv_startimage:"Start image",
+flv_starttime:"Start time",
+flv_defaultvolume:"Default volume",
+flv_hiddengui:"Hidden GUI",
+flv_autostart:"Auto start",
+flv_loop:"Loop",
+flv_showscalemodes:"Show scale modes",
+flv_smoothvideo:"Smooth video",
+flv_jscallback:"JS Callback",
+html5_video_options:"HTML5 Video Options",
+altsource1:"Alternative source 1",
+altsource2:"Alternative source 2",
+preload:"Preload",
+poster:"Poster",
+source:"Source"
+});
+
+tinyMCE.addI18n("en.wordpress",{
+wp_adv_desc:"Show/Hide Kitchen Sink (Alt + Shift + Z)",
+wp_more_desc:"Insert More Tag (Alt + Shift + T)",
+wp_page_desc:"Insert Page break (Alt + Shift + P)",
+wp_help_desc:"Help (Alt + Shift + H)",
+wp_more_alt:"More...",
+wp_page_alt:"Next page...",
+add_media:"Add Media",
+add_image:"Add an Image",
+add_video:"Add Video",
+add_audio:"Add Audio",
+editgallery:"Edit Gallery",
+delgallery:"Delete Gallery",
+wp_fullscreen_desc:"Distraction Free Writing mode (Alt + Shift + W)"
+});
+
+tinyMCE.addI18n("en.wpeditimage",{
+edit_img:"Edit Image",
+del_img:"Delete Image",
+adv_settings:"Advanced Settings",
+none:"None",
+size:"Size",
+thumbnail:"Thumbnail",
+medium:"Medium",
+full_size:"Full Size",
+current_link:"Current Link",
+link_to_img:"Link to Image",
+link_help:"Enter a link URL or click above for presets.",
+adv_img_settings:"Advanced Image Settings",
+source:"Source",
+width:"Width",
+height:"Height",
+orig_size:"Original Size",
+css:"CSS Class",
+adv_link_settings:"Advanced Link Settings",
+link_rel:"Link Rel",
+height:"Height",
+orig_size:"Original Size",
+css:"CSS Class",
+s60:"60%",
+s70:"70%",
+s80:"80%",
+s90:"90%",
+s100:"100%",
+s110:"110%",
+s120:"120%",
+s130:"130%",
+img_title:"Title",
+caption:"Caption",
+alt:"Alternative Text"
+});
diff --git a/src/wp-includes/js/tinymce/langs/wp-langs.php b/src/wp-includes/js/tinymce/langs/wp-langs.php
new file mode 100644
index 0000000000..9de90c2e0b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/langs/wp-langs.php
@@ -0,0 +1,565 @@
+<?php
+
+if ( ! defined( 'ABSPATH' ) )
+ exit;
+
+if ( ! class_exists( '_WP_Editors' ) )
+ require( ABSPATH . WPINC . '/class-wp-editor.php' );
+
+// deprecated, not used
+function mce_escape($text) {
+ return esc_js($text);
+}
+
+function wp_mce_translation() {
+
+ $default = array(
+ 'common' => array(
+ 'edit_confirm' => __('Do you want to use the WYSIWYG mode for this textarea?'),
+ 'apply' => __('Apply'),
+ 'insert' => __('Insert'),
+ 'update' => __('Update'),
+ 'cancel' => __('Cancel'),
+ 'close' => __('Close'),
+ 'browse' => __('Browse'),
+ 'class_name' => __('Class'),
+ 'not_set' => __('-- Not set --'),
+ 'clipboard_msg' => __('Copy/Cut/Paste is not available in Mozilla and Firefox.'),
+ 'clipboard_no_support' => __('Currently not supported by your browser, use keyboard shortcuts instead.'),
+ 'popup_blocked' => __('Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.'),
+ 'invalid_data' => __('ERROR: Invalid values entered, these are marked in red.'),
+ 'invalid_data_number' => __('{#field} must be a number'),
+ 'invalid_data_min' => __('{#field} must be a number greater than {#min}'),
+ 'invalid_data_size' => __('{#field} must be a number or percentage'),
+ 'more_colors' => __('More colors')
+ ),
+
+ 'colors' => array(
+ '000000' => __('Black'),
+ '993300' => __('Burnt orange'),
+ '333300' => __('Dark olive'),
+ '003300' => __('Dark green'),
+ '003366' => __('Dark azure'),
+ '000080' => __('Navy Blue'),
+ '333399' => __('Indigo'),
+ '333333' => __('Very dark gray'),
+ '800000' => __('Maroon'),
+ 'FF6600' => __('Orange'),
+ '808000' => __('Olive'),
+ '008000' => __('Green'),
+ '008080' => __('Teal'),
+ '0000FF' => __('Blue'),
+ '666699' => __('Grayish blue'),
+ '808080' => __('Gray'),
+ 'FF0000' => __('Red'),
+ 'FF9900' => __('Amber'),
+ '99CC00' => __('Yellow green'),
+ '339966' => __('Sea green'),
+ '33CCCC' => __('Turquoise'),
+ '3366FF' => __('Royal blue'),
+ '800080' => __('Purple'),
+ '999999' => __('Medium gray'),
+ 'FF00FF' => __('Magenta'),
+ 'FFCC00' => __('Gold'),
+ 'FFFF00' => __('Yellow'),
+ '00FF00' => __('Lime'),
+ '00FFFF' => __('Aqua'),
+ '00CCFF' => __('Sky blue'),
+ '993366' => __('Brown'),
+ 'C0C0C0' => __('Silver'),
+ 'FF99CC' => __('Pink'),
+ 'FFCC99' => __('Peach'),
+ 'FFFF99' => __('Light yellow'),
+ 'CCFFCC' => __('Pale green'),
+ 'CCFFFF' => __('Pale cyan'),
+ '99CCFF' => __('Light sky blue'),
+ 'CC99FF' => __('Plum'),
+ 'FFFFFF' => __('White')
+ ),
+
+ 'contextmenu' => array(
+ 'align' => __('Alignment'), /* translators: alignment */
+ 'left' => __('Left'), /* translators: alignment */
+ 'center' => __('Center'), /* translators: alignment */
+ 'right' => __('Right'), /* translators: alignment */
+ 'full' => __('Full') /* translators: alignment */
+ ),
+
+ 'insertdatetime' => array(
+ 'date_fmt' => __('%Y-%m-%d'), /* translators: year, month, date */
+ 'time_fmt' => __('%H:%M:%S'), /* translators: hours, minutes, seconds */
+ 'insertdate_desc' => __('Insert date'),
+ 'inserttime_desc' => __('Insert time'),
+ 'months_long' => __('January').','.__('February').','.__('March').','.__('April').','.__('May').','.__('June').','.__('July').','.__('August').','.__('September').','.__('October').','.__('November').','.__('December'),
+ 'months_short' => __('Jan_January_abbreviation').','.__('Feb_February_abbreviation').','.__('Mar_March_abbreviation').','.__('Apr_April_abbreviation').','.__('May_May_abbreviation').','.__('Jun_June_abbreviation').','.__('Jul_July_abbreviation').','.__('Aug_August_abbreviation').','.__('Sep_September_abbreviation').','.__('Oct_October_abbreviation').','.__('Nov_November_abbreviation').','.__('Dec_December_abbreviation'),
+ 'day_long' => __('Sunday').','.__('Monday').','.__('Tuesday').','.__('Wednesday').','.__('Thursday').','.__('Friday').','.__('Saturday'),
+ 'day_short' => __('Sun').','.__('Mon').','.__('Tue').','.__('Wed').','.__('Thu').','.__('Fri').','.__('Sat')
+ ),
+
+ 'print' => array(
+ 'print_desc' => __('Print')
+ ),
+
+ 'preview' => array(
+ 'preview_desc' => __('Preview')
+ ),
+
+ 'directionality' => array(
+ 'ltr_desc' => __('Direction left to right'),
+ 'rtl_desc' => __('Direction right to left')
+ ),
+
+ 'layer' => array(
+ 'insertlayer_desc' => __('Insert new layer'),
+ 'forward_desc' => __('Move forward'),
+ 'backward_desc' => __('Move backward'),
+ 'absolute_desc' => __('Toggle absolute positioning'),
+ 'content' => __('New layer...')
+ ),
+
+ 'save' => array(
+ 'save_desc' => __('Save'),
+ 'cancel_desc' => __('Cancel all changes')
+ ),
+
+ 'nonbreaking' => array(
+ 'nonbreaking_desc' => __('Insert non-breaking space character')
+ ),
+
+ 'iespell' => array(
+ 'iespell_desc' => __('Run spell checking'),
+ 'download' => __('ieSpell not detected. Do you want to install it now?')
+ ),
+
+ 'advhr' => array(
+ 'advhr_desc' => __('Horizontal rule')
+ ),
+
+ 'emotions' => array(
+ 'emotions_desc' => __('Emotions')
+ ),
+
+ 'searchreplace' => array(
+ 'search_desc' => __('Find'),
+ 'replace_desc' => __('Find/Replace')
+ ),
+
+ 'advimage' => array(
+ 'image_desc' => __('Insert/edit image')
+ ),
+
+ 'advlink' => array(
+ 'link_desc' => __('Insert/edit link')
+ ),
+
+ 'xhtmlxtras' => array(
+ 'cite_desc' => __('Citation'),
+ 'abbr_desc' => __('Abbreviation'),
+ 'acronym_desc' => __('Acronym'),
+ 'del_desc' => __('Deletion'),
+ 'ins_desc' => __('Insertion'),
+ 'attribs_desc' => __('Insert/Edit Attributes')
+ ),
+
+ 'style' => array(
+ 'desc' => __('Edit CSS Style')
+ ),
+
+ 'paste' => array(
+ 'paste_text_desc' => __('Paste as Plain Text'),
+ 'paste_word_desc' => __('Paste from Word'),
+ 'selectall_desc' => __('Select All'),
+ 'plaintext_mode_sticky' => __('Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.'),
+ 'plaintext_mode' => __('Paste is now in plain text mode. Click again to toggle back to regular paste mode.')
+ ),
+
+ 'paste_dlg' => array(
+ 'text_title' => __('Use CTRL+V on your keyboard to paste the text into the window.'),
+ 'text_linebreaks' => __('Keep linebreaks'),
+ 'word_title' => __('Use CTRL+V on your keyboard to paste the text into the window.')
+ ),
+
+ 'table' => array(
+ 'desc' => __('Inserts a new table'),
+ 'row_before_desc' => __('Insert row before'),
+ 'row_after_desc' => __('Insert row after'),
+ 'delete_row_desc' => __('Delete row'),
+ 'col_before_desc' => __('Insert column before'),
+ 'col_after_desc' => __('Insert column after'),
+ 'delete_col_desc' => __('Remove column'),
+ 'split_cells_desc' => __('Split merged table cells'),
+ 'merge_cells_desc' => __('Merge table cells'),
+ 'row_desc' => __('Table row properties'),
+ 'cell_desc' => __('Table cell properties'),
+ 'props_desc' => __('Table properties'),
+ 'paste_row_before_desc' => __('Paste table row before'),
+ 'paste_row_after_desc' => __('Paste table row after'),
+ 'cut_row_desc' => __('Cut table row'),
+ 'copy_row_desc' => __('Copy table row'),
+ 'del' => __('Delete table'),
+ 'row' => __('Row'),
+ 'col' => __('Column'),
+ 'cell' => __('Cell')
+ ),
+
+ 'autosave' => array(
+ 'unload_msg' => __('The changes you made will be lost if you navigate away from this page.')
+ ),
+
+ 'fullscreen' => array(
+ 'desc' => __('Toggle fullscreen mode (Alt + Shift + G)')
+ ),
+
+ 'media' => array(
+ 'desc' => __('Insert / edit embedded media'),
+ 'edit' => __('Edit embedded media')
+ ),
+
+ 'fullpage' => array(
+ 'desc' => __('Document properties')
+ ),
+
+ 'template' => array(
+ 'desc' => __('Insert predefined template content')
+ ),
+
+ 'visualchars' => array(
+ 'desc' => __('Visual control characters on/off.')
+ ),
+
+ 'spellchecker' => array(
+ 'desc' => __('Toggle spellchecker (Alt + Shift + N)'),
+ 'menu' => __('Spellchecker settings'),
+ 'ignore_word' => __('Ignore word'),
+ 'ignore_words' => __('Ignore all'),
+ 'langs' => __('Languages'),
+ 'wait' => __('Please wait...'),
+ 'sug' => __('Suggestions'),
+ 'no_sug' => __('No suggestions'),
+ 'no_mpell' => __('No misspellings found.'),
+ 'learn_word' => __('Learn word')
+ ),
+
+ 'pagebreak' => array(
+ 'desc' => __('Insert Page Break')
+ ),
+
+ 'advlist' => array(
+ 'types' => __('Types'),
+ 'def' => __('Default'),
+ 'lower_alpha' => __('Lower alpha'),
+ 'lower_greek' => __('Lower greek'),
+ 'lower_roman' => __('Lower roman'),
+ 'upper_alpha' => __('Upper alpha'),
+ 'upper_roman' => __('Upper roman'),
+ 'circle' => __('Circle'),
+ 'disc' => __('Disc'),
+ 'square' => __('Square')
+ ),
+
+ 'aria' => array(
+ 'rich_text_area' => __('Rich Text Area')
+ ),
+
+ 'wordcount' => array(
+ 'words' => __('Words:')
+ )
+ );
+
+ $advanced = array(
+ 'style_select' => __('Styles'), /* translators: TinyMCE inline styles */
+ 'font_size' => __('Font size'),
+ 'fontdefault' => __('Font family'),
+ 'block' => __('Format'),
+ 'paragraph' => __('Paragraph'),
+ 'div' => __('Div'),
+ 'address' => __('Address'),
+ 'pre' => __('Preformatted'),
+ 'h1' => __('Heading 1'),
+ 'h2' => __('Heading 2'),
+ 'h3' => __('Heading 3'),
+ 'h4' => __('Heading 4'),
+ 'h5' => __('Heading 5'),
+ 'h6' => __('Heading 6'),
+ 'blockquote' => __('Blockquote'),
+ 'code' => __('Code'),
+ 'samp' => __('Code sample'),
+ 'dt' => __('Definition term '),
+ 'dd' => __('Definition description'),
+ 'bold_desc' => __('Bold (Ctrl + B)'),
+ 'italic_desc' => __('Italic (Ctrl + I)'),
+ 'underline_desc' => __('Underline'),
+ 'striketrough_desc' => __('Strikethrough (Alt + Shift + D)'),
+ 'justifyleft_desc' => __('Align Left (Alt + Shift + L)'),
+ 'justifycenter_desc' => __('Align Center (Alt + Shift + C)'),
+ 'justifyright_desc' => __('Align Right (Alt + Shift + R)'),
+ 'justifyfull_desc' => __('Align Full (Alt + Shift + J)'),
+ 'bullist_desc' => __('Unordered list (Alt + Shift + U)'),
+ 'numlist_desc' => __('Ordered list (Alt + Shift + O)'),
+ 'outdent_desc' => __('Outdent'),
+ 'indent_desc' => __('Indent'),
+ 'undo_desc' => __('Undo (Ctrl + Z)'),
+ 'redo_desc' => __('Redo (Ctrl + Y)'),
+ 'link_desc' => __('Insert/edit link (Alt + Shift + A)'),
+ 'unlink_desc' => __('Unlink (Alt + Shift + S)'),
+ 'image_desc' => __('Insert/edit image (Alt + Shift + M)'),
+ 'cleanup_desc' => __('Cleanup messy code'),
+ 'code_desc' => __('Edit HTML Source'),
+ 'sub_desc' => __('Subscript'),
+ 'sup_desc' => __('Superscript'),
+ 'hr_desc' => __('Insert horizontal ruler'),
+ 'removeformat_desc' => __('Remove formatting'),
+ 'forecolor_desc' => __('Select text color'),
+ 'backcolor_desc' => __('Select background color'),
+ 'charmap_desc' => __('Insert custom character'),
+ 'visualaid_desc' => __('Toggle guidelines/invisible elements'),
+ 'anchor_desc' => __('Insert/edit anchor'),
+ 'cut_desc' => __('Cut'),
+ 'copy_desc' => __('Copy'),
+ 'paste_desc' => __('Paste'),
+ 'image_props_desc' => __('Image properties'),
+ 'newdocument_desc' => __('New document'),
+ 'help_desc' => __('Help'),
+ 'blockquote_desc' => __('Blockquote (Alt + Shift + Q)'),
+ 'clipboard_msg' => __('Copy/Cut/Paste is not available in Mozilla and Firefox.'),
+ 'path' => __('Path'),
+ 'newdocument' => __('Are you sure you want to clear all contents?'),
+ 'toolbar_focus' => __('Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X'),
+ 'more_colors' => __('More colors'),
+ 'shortcuts_desc' => __('Accessibility Help'),
+ 'help_shortcut' => __('Press ALT F10 for toolbar. Press ALT 0 for help.'),
+ 'rich_text_area' => __('Rich Text Area'),
+ 'toolbar' => __('Toolbar')
+ );
+
+ $advanced_dlg = array(
+ 'about_title' => __('About TinyMCE'),
+ 'about_general' => __('About'),
+ 'about_help' => __('Help'),
+ 'about_license' => __('License'),
+ 'about_plugins' => __('Plugins'),
+ 'about_plugin' => __('Plugin'),
+ 'about_author' => __('Author'),
+ 'about_version' => __('Version'),
+ 'about_loaded' => __('Loaded plugins'),
+ 'anchor_title' => __('Insert/edit anchor'),
+ 'anchor_name' => __('Anchor name'),
+ 'code_title' => __('HTML Source Editor'),
+ 'code_wordwrap' => __('Word wrap'),
+ 'colorpicker_title' => __('Select a color'),
+ 'colorpicker_picker_tab' => __('Picker'),
+ 'colorpicker_picker_title' => __('Color picker'),
+ 'colorpicker_palette_tab' => __('Palette'),
+ 'colorpicker_palette_title' => __('Palette colors'),
+ 'colorpicker_named_tab' => __('Named'),
+ 'colorpicker_named_title' => __('Named colors'),
+ 'colorpicker_color' => __('Color:'),
+ 'colorpicker_name' => _x('Name:', 'html attribute'),
+ 'charmap_title' => __('Select custom character'),
+ 'charmap_usage' => __('Use left and right arrows to navigate.'),
+ 'image_title' => __('Insert/edit image'),
+ 'image_src' => __('Image URL'),
+ 'image_alt' => __('Image description'),
+ 'image_list' => __('Image list'),
+ 'image_border' => __('Border'),
+ 'image_dimensions' => __('Dimensions'),
+ 'image_vspace' => __('Vertical space'),
+ 'image_hspace' => __('Horizontal space'),
+ 'image_align' => __('Alignment'),
+ 'image_align_baseline' => __('Baseline'),
+ 'image_align_top' => __('Top'),
+ 'image_align_middle' => __('Middle'),
+ 'image_align_bottom' => __('Bottom'),
+ 'image_align_texttop' => __('Text top'),
+ 'image_align_textbottom' => __('Text bottom'),
+ 'image_align_left' => __('Left'),
+ 'image_align_right' => __('Right'),
+ 'link_title' => __('Insert/edit link'),
+ 'link_url' => __('Link URL'),
+ 'link_target' => __('Target'),
+ 'link_target_same' => __('Open link in the same window'),
+ 'link_target_blank' => __('Open link in a new window'),
+ 'link_titlefield' => __('Title'),
+ 'link_is_email' => __('The URL you entered seems to be an email address, do you want to add the required mailto: prefix?'),
+ 'link_is_external' => __('The URL you entered seems to external link, do you want to add the required http:// prefix?'),
+ 'link_list' => __('Link list'),
+ 'accessibility_help' => __('Accessibility Help'),
+ 'accessibility_usage_title' => __('General Usage')
+ );
+
+ $media_dlg = array(
+ 'title' => __('Insert / edit embedded media'),
+ 'general' => __('General'),
+ 'advanced' => __('Advanced'),
+ 'file' => __('File/URL'),
+ 'list' => __('List'),
+ 'size' => __('Dimensions'),
+ 'preview' => __('Preview'),
+ 'constrain_proportions' => __('Constrain proportions'),
+ 'type' => __('Type'),
+ 'id' => __('Id'),
+ 'name' => _x('Name', 'html attribute'),
+ 'class_name' => __('Class'),
+ 'vspace' => __('V-Space'),
+ 'hspace' => __('H-Space'),
+ 'play' => __('Auto play'),
+ 'loop' => __('Loop'),
+ 'menu' => __('Show menu'),
+ 'quality' => __('Quality'),
+ 'scale' => __('Scale'),
+ 'align' => __('Align'),
+ 'salign' => __('SAlign'),
+ 'wmode' => __('WMode'),
+ 'bgcolor' => __('Background'),
+ 'base' => __('Base'),
+ 'flashvars' => __('Flashvars'),
+ 'liveconnect' => __('SWLiveConnect'),
+ 'autohref' => __('AutoHREF'),
+ 'cache' => __('Cache'),
+ 'hidden' => __('Hidden'),
+ 'controller' => __('Controller'),
+ 'kioskmode' => __('Kiosk mode'),
+ 'playeveryframe' => __('Play every frame'),
+ 'targetcache' => __('Target cache'),
+ 'correction' => __('No correction'),
+ 'enablejavascript' => __('Enable JavaScript'),
+ 'starttime' => __('Start time'),
+ 'endtime' => __('End time'),
+ 'href' => __('href'),
+ 'qtsrcchokespeed' => __('Choke speed'),
+ 'target' => __('Target'),
+ 'volume' => __('Volume'),
+ 'autostart' => __('Auto start'),
+ 'enabled' => __('Enabled'),
+ 'fullscreen' => __('Fullscreen'),
+ 'invokeurls' => __('Invoke URLs'),
+ 'mute' => __('Mute'),
+ 'stretchtofit' => __('Stretch to fit'),
+ 'windowlessvideo' => __('Windowless video'),
+ 'balance' => __('Balance'),
+ 'baseurl' => __('Base URL'),
+ 'captioningid' => __('Captioning id'),
+ 'currentmarker' => __('Current marker'),
+ 'currentposition' => __('Current position'),
+ 'defaultframe' => __('Default frame'),
+ 'playcount' => __('Play count'),
+ 'rate' => __('Rate'),
+ 'uimode' => __('UI Mode'),
+ 'flash_options' => __('Flash options'),
+ 'qt_options' => __('QuickTime options'),
+ 'wmp_options' => __('Windows media player options'),
+ 'rmp_options' => __('Real media player options'),
+ 'shockwave_options' => __('Shockwave options'),
+ 'autogotourl' => __('Auto goto URL'),
+ 'center' => __('Center'),
+ 'imagestatus' => __('Image status'),
+ 'maintainaspect' => __('Maintain aspect'),
+ 'nojava' => __('No java'),
+ 'prefetch' => __('Prefetch'),
+ 'shuffle' => __('Shuffle'),
+ 'console' => __('Console'),
+ 'numloop' => __('Num loops'),
+ 'controls' => __('Controls'),
+ 'scriptcallbacks' => __('Script callbacks'),
+ 'swstretchstyle' => __('Stretch style'),
+ 'swstretchhalign' => __('Stretch H-Align'),
+ 'swstretchvalign' => __('Stretch V-Align'),
+ 'sound' => __('Sound'),
+ 'progress' => __('Progress'),
+ 'qtsrc' => __('QT Src'),
+ 'qt_stream_warn' => __('Streamed rtsp resources should be added to the QT Src field under the advanced tab.'),
+ 'align_top' => __('Top'),
+ 'align_right' => __('Right'),
+ 'align_bottom' => __('Bottom'),
+ 'align_left' => __('Left'),
+ 'align_center' => __('Center'),
+ 'align_top_left' => __('Top left'),
+ 'align_top_right' => __('Top right'),
+ 'align_bottom_left' => __('Bottom left'),
+ 'align_bottom_right' => __('Bottom right'),
+ 'flv_options' => __('Flash video options'),
+ 'flv_scalemode' => __('Scale mode'),
+ 'flv_buffer' => __('Buffer'),
+ 'flv_startimage' => __('Start image'),
+ 'flv_starttime' => __('Start time'),
+ 'flv_defaultvolume' => __('Default volume'),
+ 'flv_hiddengui' => __('Hidden GUI'),
+ 'flv_autostart' => __('Auto start'),
+ 'flv_loop' => __('Loop'),
+ 'flv_showscalemodes' => __('Show scale modes'),
+ 'flv_smoothvideo' => __('Smooth video'),
+ 'flv_jscallback' => __('JS Callback'),
+ 'html5_video_options' => __('HTML5 Video Options'),
+ 'altsource1' => __('Alternative source 1'),
+ 'altsource2' => __('Alternative source 2'),
+ 'preload' => __('Preload'),
+ 'poster' => __('Poster'),
+ 'source' => __('Source')
+ );
+
+ $wordpress = array(
+ 'wp_adv_desc' => __('Show/Hide Kitchen Sink (Alt + Shift + Z)'),
+ 'wp_more_desc' => __('Insert More Tag (Alt + Shift + T)'),
+ 'wp_page_desc' => __('Insert Page break (Alt + Shift + P)'),
+ 'wp_help_desc' => __('Help (Alt + Shift + H)'),
+ 'wp_more_alt' => __('More...'),
+ 'wp_page_alt' => __('Next page...'),
+ 'add_media' => __('Add Media'),
+ 'add_image' => __('Add an Image'),
+ 'add_video' => __('Add Video'),
+ 'add_audio' => __('Add Audio'),
+ 'editgallery' => __('Edit Gallery'),
+ 'delgallery' => __('Delete Gallery'),
+ 'wp_fullscreen_desc' => __('Distraction Free Writing mode (Alt + Shift + W)')
+ );
+
+ $wpeditimage = array(
+ 'edit_img' => __('Edit Image'),
+ 'del_img' => __('Delete Image'),
+ 'adv_settings' => __('Advanced Settings'),
+ 'none' => __('None'),
+ 'size' => __('Size'),
+ 'thumbnail' => __('Thumbnail'),
+ 'medium' => __('Medium'),
+ 'full_size' => __('Full Size'),
+ 'current_link' => __('Current Link'),
+ 'link_to_img' => __('Link to Image'),
+ 'link_help' => __('Enter a link URL or click above for presets.'),
+ 'adv_img_settings' => __('Advanced Image Settings'),
+ 'source' => __('Source'),
+ 'width' => __('Width'),
+ 'height' => __('Height'),
+ 'orig_size' => __('Original Size'),
+ 'css' => __('CSS Class'),
+ 'adv_link_settings' => __('Advanced Link Settings'),
+ 'link_rel' => __('Link Rel'),
+ 'height' => __('Height'),
+ 'orig_size' => __('Original Size'),
+ 'css' => __('CSS Class'),
+ 's60' => __('60%'),
+ 's70' => __('70%'),
+ 's80' => __('80%'),
+ 's90' => __('90%'),
+ 's100' => __('100%'),
+ 's110' => __('110%'),
+ 's120' => __('120%'),
+ 's130' => __('130%'),
+ 'img_title' => __('Title'),
+ 'caption' => __('Caption'),
+ 'alt' => __('Alternative Text')
+ );
+
+ $locale = _WP_Editors::$mce_locale;
+
+ $translated = 'tinyMCE.addI18n({' . $locale . ':' . json_encode( $default ) . "});\n";
+ $translated .= 'tinyMCE.addI18n("' . $locale . '.advanced", ' . json_encode( $advanced ) . ");\n";
+ $translated .= 'tinyMCE.addI18n("' . $locale . '.advanced_dlg", ' . json_encode( $advanced_dlg ) . ");\n";
+ $translated .= 'tinyMCE.addI18n("' . $locale . '.media_dlg", ' . json_encode( $media_dlg ) . ");\n";
+ $translated .= 'tinyMCE.addI18n("' . $locale . '.wordpress", ' . json_encode( $wordpress ) . ");\n";
+ $translated .= 'tinyMCE.addI18n("' . $locale . '.wpeditimage", ' . json_encode( $wpeditimage ) . ');';
+
+ return $translated;
+}
+
+$lang = wp_mce_translation();
+
diff --git a/src/wp-includes/js/tinymce/license.txt b/src/wp-includes/js/tinymce/license.txt
new file mode 100644
index 0000000000..1837b0acbe
--- /dev/null
+++ b/src/wp-includes/js/tinymce/license.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/wp-includes/js/tinymce/mark_loaded_src.js b/src/wp-includes/js/tinymce/mark_loaded_src.js
new file mode 100644
index 0000000000..2b53192671
--- /dev/null
+++ b/src/wp-includes/js/tinymce/mark_loaded_src.js
@@ -0,0 +1,20 @@
+(function(){
+ if ( typeof tinyMCEPreInit === 'undefined' )
+ return;
+
+ var t = tinyMCEPreInit, baseurl = t.base, markDone = tinymce.ScriptLoader.markDone, lang = t.ref.language,
+ theme = t.ref.theme, plugins = t.ref.plugins, suffix = t.suffix;
+
+ markDone( baseurl+'/langs/'+lang+'.js' );
+ markDone( baseurl+'/themes/'+theme+'/editor_template'+suffix+'.js' );
+ markDone( baseurl+'/themes/'+theme+'/langs/'+lang+'.js' );
+ markDone( baseurl+'/themes/'+theme+'/langs/'+lang+'_dlg.js' );
+
+ tinymce.each( plugins.split(','), function(plugin){
+ if ( plugin && plugin.charAt(0) != '-' ) {
+ markDone( baseurl+'/plugins/'+plugin+'/editor_plugin'+suffix+'.js' );
+ markDone( baseurl+'/plugins/'+plugin+'/langs/'+lang+'.js' );
+ markDone( baseurl+'/plugins/'+plugin+'/langs/'+lang+'_dlg.js' )
+ }
+ });
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/directionality/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/directionality/editor_plugin.js
new file mode 100644
index 0000000000..90847e78e3
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/directionality/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.Directionality",{init:function(b,c){var d=this;d.editor=b;function a(e){var h=b.dom,g,f=b.selection.getSelectedBlocks();if(f.length){g=h.getAttrib(f[0],"dir");tinymce.each(f,function(i){if(!h.getParent(i.parentNode,"*[dir='"+e+"']",h.getRoot())){if(g!=e){h.setAttrib(i,"dir",e)}else{h.setAttrib(i,"dir",null)}}});b.nodeChanged()}}b.addCommand("mceDirectionLTR",function(){a("ltr")});b.addCommand("mceDirectionRTL",function(){a("rtl")});b.addButton("ltr",{title:"directionality.ltr_desc",cmd:"mceDirectionLTR"});b.addButton("rtl",{title:"directionality.rtl_desc",cmd:"mceDirectionRTL"});b.onNodeChange.add(d._nodeChange,d)},getInfo:function(){return{longname:"Directionality",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(b,a,e){var d=b.dom,c;e=d.getParent(e,d.isBlock);if(!e){a.setDisabled("ltr",1);a.setDisabled("rtl",1);return}c=d.getAttrib(e,"dir");a.setActive("ltr",c=="ltr");a.setDisabled("ltr",0);a.setActive("rtl",c=="rtl");a.setDisabled("rtl",0)}});tinymce.PluginManager.add("directionality",tinymce.plugins.Directionality)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/directionality/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/directionality/editor_plugin_src.js
new file mode 100644
index 0000000000..c90732bbd6
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/directionality/editor_plugin_src.js
@@ -0,0 +1,85 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.Directionality', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ function setDir(dir) {
+ var dom = ed.dom, curDir, blocks = ed.selection.getSelectedBlocks();
+
+ if (blocks.length) {
+ curDir = dom.getAttrib(blocks[0], "dir");
+
+ tinymce.each(blocks, function(block) {
+ // Add dir to block if the parent block doesn't already have that dir
+ if (!dom.getParent(block.parentNode, "*[dir='" + dir + "']", dom.getRoot())) {
+ if (curDir != dir) {
+ dom.setAttrib(block, "dir", dir);
+ } else {
+ dom.setAttrib(block, "dir", null);
+ }
+ }
+ });
+
+ ed.nodeChanged();
+ }
+ }
+
+ ed.addCommand('mceDirectionLTR', function() {
+ setDir("ltr");
+ });
+
+ ed.addCommand('mceDirectionRTL', function() {
+ setDir("rtl");
+ });
+
+ ed.addButton('ltr', {title : 'directionality.ltr_desc', cmd : 'mceDirectionLTR'});
+ ed.addButton('rtl', {title : 'directionality.rtl_desc', cmd : 'mceDirectionRTL'});
+
+ ed.onNodeChange.add(t._nodeChange, t);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Directionality',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ _nodeChange : function(ed, cm, n) {
+ var dom = ed.dom, dir;
+
+ n = dom.getParent(n, dom.isBlock);
+ if (!n) {
+ cm.setDisabled('ltr', 1);
+ cm.setDisabled('rtl', 1);
+ return;
+ }
+
+ dir = dom.getAttrib(n, 'dir');
+ cm.setActive('ltr', dir == "ltr");
+ cm.setDisabled('ltr', 0);
+ cm.setActive('rtl', dir == "rtl");
+ cm.setDisabled('rtl', 0);
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('directionality', tinymce.plugins.Directionality);
+})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.js
new file mode 100644
index 0000000000..a2eb034839
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.DOM;tinymce.create("tinymce.plugins.FullScreenPlugin",{init:function(d,e){var f=this,g={},c,b;f.editor=d;d.addCommand("mceFullScreen",function(){var i,j=a.doc.documentElement;if(d.getParam("fullscreen_is_enabled")){if(d.getParam("fullscreen_new_window")){closeFullscreen()}else{a.win.setTimeout(function(){tinymce.dom.Event.remove(a.win,"resize",f.resizeFunc);tinyMCE.get(d.getParam("fullscreen_editor_id")).setContent(d.getContent());tinyMCE.remove(d);a.remove("mce_fullscreen_container");j.style.overflow=d.getParam("fullscreen_html_overflow");a.setStyle(a.doc.body,"overflow",d.getParam("fullscreen_overflow"));a.win.scrollTo(d.getParam("fullscreen_scrollx"),d.getParam("fullscreen_scrolly"));tinyMCE.settings=tinyMCE.oldSettings},10)}return}if(d.getParam("fullscreen_new_window")){i=a.win.open(e+"/fullscreen.htm","mceFullScreenPopup","fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width="+screen.availWidth+",height="+screen.availHeight);try{i.resizeTo(screen.availWidth,screen.availHeight)}catch(h){}}else{tinyMCE.oldSettings=tinyMCE.settings;g.fullscreen_overflow=a.getStyle(a.doc.body,"overflow",1)||"auto";g.fullscreen_html_overflow=a.getStyle(j,"overflow",1);c=a.getViewPort();g.fullscreen_scrollx=c.x;g.fullscreen_scrolly=c.y;if(tinymce.isOpera&&g.fullscreen_overflow=="visible"){g.fullscreen_overflow="auto"}if(tinymce.isIE&&g.fullscreen_overflow=="scroll"){g.fullscreen_overflow="auto"}if(tinymce.isIE&&(g.fullscreen_html_overflow=="visible"||g.fullscreen_html_overflow=="scroll")){g.fullscreen_html_overflow="auto"}if(g.fullscreen_overflow=="0px"){g.fullscreen_overflow=""}a.setStyle(a.doc.body,"overflow","hidden");j.style.overflow="hidden";c=a.getViewPort();a.win.scrollTo(0,0);if(tinymce.isIE){c.h-=1}if(tinymce.isIE6||document.compatMode=="BackCompat"){b="absolute;top:"+c.y}else{b="fixed;top:0"}n=a.add(a.doc.body,"div",{id:"mce_fullscreen_container",style:"position:"+b+";left:0;width:"+c.w+"px;height:"+c.h+"px;z-index:200000;"});a.add(n,"div",{id:"mce_fullscreen"});tinymce.each(d.settings,function(k,l){g[l]=k});g.id="mce_fullscreen";g.width=n.clientWidth;g.height=n.clientHeight-15;g.fullscreen_is_enabled=true;g.fullscreen_editor_id=d.id;g.theme_advanced_resizing=false;g.save_onsavecallback=function(){d.setContent(tinyMCE.get(g.id).getContent());d.execCommand("mceSave")};tinymce.each(d.getParam("fullscreen_settings"),function(m,l){g[l]=m});if(g.theme_advanced_toolbar_location==="external"){g.theme_advanced_toolbar_location="top"}f.fullscreenEditor=new tinymce.Editor("mce_fullscreen",g);f.fullscreenEditor.onInit.add(function(){f.fullscreenEditor.setContent(d.getContent());f.fullscreenEditor.focus()});f.fullscreenEditor.render();f.fullscreenElement=new tinymce.dom.Element("mce_fullscreen_container");f.fullscreenElement.update();f.resizeFunc=tinymce.dom.Event.add(a.win,"resize",function(){var o=tinymce.DOM.getViewPort(),l=f.fullscreenEditor,k,m;k=l.dom.getSize(l.getContainer().getElementsByTagName("table")[0]);m=l.dom.getSize(l.getContainer().getElementsByTagName("iframe")[0]);l.theme.resizeTo(o.w-k.w+m.w,o.h-k.h+m.h)})}});d.addButton("fullscreen",{title:"fullscreen.desc",cmd:"mceFullScreen"});d.onNodeChange.add(function(i,h){h.setActive("fullscreen",i.getParam("fullscreen_is_enabled"))})},getInfo:function(){return{longname:"Fullscreen",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("fullscreen",tinymce.plugins.FullScreenPlugin)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin_src.js
new file mode 100644
index 0000000000..a24a95657f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/fullscreen/editor_plugin_src.js
@@ -0,0 +1,159 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.plugins.FullScreenPlugin', {
+ init : function(ed, url) {
+ var t = this, s = {}, vp, posCss;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceFullScreen', function() {
+ var win, de = DOM.doc.documentElement;
+
+ if (ed.getParam('fullscreen_is_enabled')) {
+ if (ed.getParam('fullscreen_new_window'))
+ closeFullscreen(); // Call to close in new window
+ else {
+ DOM.win.setTimeout(function() {
+ tinymce.dom.Event.remove(DOM.win, 'resize', t.resizeFunc);
+ tinyMCE.get(ed.getParam('fullscreen_editor_id')).setContent(ed.getContent());
+ tinyMCE.remove(ed);
+ DOM.remove('mce_fullscreen_container');
+ de.style.overflow = ed.getParam('fullscreen_html_overflow');
+ DOM.setStyle(DOM.doc.body, 'overflow', ed.getParam('fullscreen_overflow'));
+ DOM.win.scrollTo(ed.getParam('fullscreen_scrollx'), ed.getParam('fullscreen_scrolly'));
+ tinyMCE.settings = tinyMCE.oldSettings; // Restore old settings
+ }, 10);
+ }
+
+ return;
+ }
+
+ if (ed.getParam('fullscreen_new_window')) {
+ win = DOM.win.open(url + "/fullscreen.htm", "mceFullScreenPopup", "fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width=" + screen.availWidth + ",height=" + screen.availHeight);
+ try {
+ win.resizeTo(screen.availWidth, screen.availHeight);
+ } catch (e) {
+ // Ignore
+ }
+ } else {
+ tinyMCE.oldSettings = tinyMCE.settings; // Store old settings
+ s.fullscreen_overflow = DOM.getStyle(DOM.doc.body, 'overflow', 1) || 'auto';
+ s.fullscreen_html_overflow = DOM.getStyle(de, 'overflow', 1);
+ vp = DOM.getViewPort();
+ s.fullscreen_scrollx = vp.x;
+ s.fullscreen_scrolly = vp.y;
+
+ // Fixes an Opera bug where the scrollbars doesn't reappear
+ if (tinymce.isOpera && s.fullscreen_overflow == 'visible')
+ s.fullscreen_overflow = 'auto';
+
+ // Fixes an IE bug where horizontal scrollbars would appear
+ if (tinymce.isIE && s.fullscreen_overflow == 'scroll')
+ s.fullscreen_overflow = 'auto';
+
+ // Fixes an IE bug where the scrollbars doesn't reappear
+ if (tinymce.isIE && (s.fullscreen_html_overflow == 'visible' || s.fullscreen_html_overflow == 'scroll'))
+ s.fullscreen_html_overflow = 'auto';
+
+ if (s.fullscreen_overflow == '0px')
+ s.fullscreen_overflow = '';
+
+ DOM.setStyle(DOM.doc.body, 'overflow', 'hidden');
+ de.style.overflow = 'hidden'; //Fix for IE6/7
+ vp = DOM.getViewPort();
+ DOM.win.scrollTo(0, 0);
+
+ if (tinymce.isIE)
+ vp.h -= 1;
+
+ // Use fixed position if it exists
+ if (tinymce.isIE6 || document.compatMode == 'BackCompat')
+ posCss = 'absolute;top:' + vp.y;
+ else
+ posCss = 'fixed;top:0';
+
+ n = DOM.add(DOM.doc.body, 'div', {
+ id : 'mce_fullscreen_container',
+ style : 'position:' + posCss + ';left:0;width:' + vp.w + 'px;height:' + vp.h + 'px;z-index:200000;'});
+ DOM.add(n, 'div', {id : 'mce_fullscreen'});
+
+ tinymce.each(ed.settings, function(v, n) {
+ s[n] = v;
+ });
+
+ s.id = 'mce_fullscreen';
+ s.width = n.clientWidth;
+ s.height = n.clientHeight - 15;
+ s.fullscreen_is_enabled = true;
+ s.fullscreen_editor_id = ed.id;
+ s.theme_advanced_resizing = false;
+ s.save_onsavecallback = function() {
+ ed.setContent(tinyMCE.get(s.id).getContent());
+ ed.execCommand('mceSave');
+ };
+
+ tinymce.each(ed.getParam('fullscreen_settings'), function(v, k) {
+ s[k] = v;
+ });
+
+ if (s.theme_advanced_toolbar_location === 'external')
+ s.theme_advanced_toolbar_location = 'top';
+
+ t.fullscreenEditor = new tinymce.Editor('mce_fullscreen', s);
+ t.fullscreenEditor.onInit.add(function() {
+ t.fullscreenEditor.setContent(ed.getContent());
+ t.fullscreenEditor.focus();
+ });
+
+ t.fullscreenEditor.render();
+
+ t.fullscreenElement = new tinymce.dom.Element('mce_fullscreen_container');
+ t.fullscreenElement.update();
+ //document.body.overflow = 'hidden';
+
+ t.resizeFunc = tinymce.dom.Event.add(DOM.win, 'resize', function() {
+ var vp = tinymce.DOM.getViewPort(), fed = t.fullscreenEditor, outerSize, innerSize;
+
+ // Get outer/inner size to get a delta size that can be used to calc the new iframe size
+ outerSize = fed.dom.getSize(fed.getContainer().getElementsByTagName('table')[0]);
+ innerSize = fed.dom.getSize(fed.getContainer().getElementsByTagName('iframe')[0]);
+
+ fed.theme.resizeTo(vp.w - outerSize.w + innerSize.w, vp.h - outerSize.h + innerSize.h);
+ });
+ }
+ });
+
+ // Register buttons
+ ed.addButton('fullscreen', {title : 'fullscreen.desc', cmd : 'mceFullScreen'});
+
+ ed.onNodeChange.add(function(ed, cm) {
+ cm.setActive('fullscreen', ed.getParam('fullscreen_is_enabled'));
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Fullscreen',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('fullscreen', tinymce.plugins.FullScreenPlugin);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/fullscreen/fullscreen.htm b/src/wp-includes/js/tinymce/plugins/fullscreen/fullscreen.htm
new file mode 100644
index 0000000000..e21c29c750
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/fullscreen/fullscreen.htm
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title></title>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <script type="text/javascript" src="../../tiny_mce.js?ver=358-20121205"></script>
+ <script type="text/javascript">
+ function patchCallback(settings, key) {
+ if (settings[key])
+ settings[key] = "window.opener." + settings[key];
+ }
+
+ var settings = {}, paSe = window.opener.tinyMCE.activeEditor.settings, oeID = window.opener.tinyMCE.activeEditor.id;
+
+ // Clone array
+ for (var n in paSe)
+ settings[n] = paSe[n];
+
+ // Override options for fullscreen
+ for (var n in paSe.fullscreen_settings)
+ settings[n] = paSe.fullscreen_settings[n];
+
+ // Patch callbacks, make them point to window.opener
+ patchCallback(settings, 'urlconverter_callback');
+ patchCallback(settings, 'insertlink_callback');
+ patchCallback(settings, 'insertimage_callback');
+ patchCallback(settings, 'setupcontent_callback');
+ patchCallback(settings, 'save_callback');
+ patchCallback(settings, 'onchange_callback');
+ patchCallback(settings, 'init_instance_callback');
+ patchCallback(settings, 'file_browser_callback');
+ patchCallback(settings, 'cleanup_callback');
+ patchCallback(settings, 'execcommand_callback');
+ patchCallback(settings, 'oninit');
+
+ // Set options
+ delete settings.id;
+ settings['mode'] = 'exact';
+ settings['elements'] = 'fullscreenarea';
+ settings['add_unload_trigger'] = false;
+ settings['ask'] = false;
+ settings['document_base_url'] = window.opener.tinyMCE.activeEditor.documentBaseURI.getURI();
+ settings['fullscreen_is_enabled'] = true;
+ settings['fullscreen_editor_id'] = oeID;
+ settings['theme_advanced_resizing'] = false;
+ settings['strict_loading_mode'] = true;
+
+ settings.save_onsavecallback = function() {
+ window.opener.tinyMCE.get(oeID).setContent(tinyMCE.get('fullscreenarea').getContent({format : 'raw'}), {format : 'raw'});
+ window.opener.tinyMCE.get(oeID).execCommand('mceSave');
+ window.close();
+ };
+
+ function unloadHandler(e) {
+ moveContent();
+ }
+
+ function moveContent() {
+ window.opener.tinyMCE.get(oeID).setContent(tinyMCE.activeEditor.getContent());
+ }
+
+ function closeFullscreen() {
+ moveContent();
+ window.close();
+ }
+
+ function doParentSubmit() {
+ moveContent();
+
+ if (window.opener.tinyMCE.selectedInstance.formElement.form)
+ window.opener.tinyMCE.selectedInstance.formElement.form.submit();
+
+ window.close();
+
+ return false;
+ }
+
+ function render() {
+ var e = document.getElementById('fullscreenarea'), vp, ed, ow, oh, dom = tinymce.DOM;
+
+ e.value = window.opener.tinyMCE.get(oeID).getContent();
+
+ vp = dom.getViewPort();
+ settings.width = vp.w;
+ settings.height = vp.h - 15;
+
+ tinymce.dom.Event.add(window, 'resize', function() {
+ var vp = dom.getViewPort();
+
+ tinyMCE.activeEditor.theme.resizeTo(vp.w, vp.h);
+ });
+
+ tinyMCE.init(settings);
+ }
+
+ // Add onunload
+ tinymce.dom.Event.add(window, "beforeunload", unloadHandler);
+ </script>
+</head>
+<body style="margin:0;overflow:hidden;width:100%;height:100%" scrolling="no" scroll="no">
+<form onsubmit="doParentSubmit();">
+<textarea id="fullscreenarea" style="width:100%; height:100%"></textarea>
+</form>
+
+<script type="text/javascript">
+ render();
+</script>
+
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js
new file mode 100644
index 0000000000..8bb96f9cbe
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var d=tinymce.DOM,b=tinymce.dom.Element,a=tinymce.dom.Event,e=tinymce.each,c=tinymce.is;tinymce.create("tinymce.plugins.InlinePopups",{init:function(f,g){f.onBeforeRenderUI.add(function(){f.windowManager=new tinymce.InlineWindowManager(f);d.loadCSS(g+"/skins/"+(f.settings.inlinepopups_skin||"clearlooks2")+"/window.css")})},getInfo:function(){return{longname:"InlinePopups",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.create("tinymce.InlineWindowManager:tinymce.WindowManager",{InlineWindowManager:function(f){var g=this;g.parent(f);g.zIndex=300000;g.count=0;g.windows={}},open:function(s,j){var z=this,i,k="",r=z.editor,g=0,v=0,h,m,o,q,l,x,y,n;s=s||{};j=j||{};if(!s.inline){return z.parent(s,j)}n=z._frontWindow();if(n&&d.get(n.id+"_ifr")){n.focussedElement=d.get(n.id+"_ifr").contentWindow.document.activeElement}if(!s.type){z.bookmark=r.selection.getBookmark(1)}i=d.uniqueId();h=d.getViewPort();s.width=parseInt(s.width||320);s.height=parseInt(s.height||240)+(tinymce.isIE?8:0);s.min_width=parseInt(s.min_width||150);s.min_height=parseInt(s.min_height||100);s.max_width=parseInt(s.max_width||2000);s.max_height=parseInt(s.max_height||2000);s.left=s.left||Math.round(Math.max(h.x,h.x+(h.w/2)-(s.width/2)));s.top=s.top||Math.round(Math.max(h.y,h.y+(h.h/2)-(s.height/2)));s.movable=s.resizable=true;j.mce_width=s.width;j.mce_height=s.height;j.mce_inline=true;j.mce_window_id=i;j.mce_auto_focus=s.auto_focus;z.features=s;z.params=j;z.onOpen.dispatch(z,s,j);if(s.type){k+=" mceModal";if(s.type){k+=" mce"+s.type.substring(0,1).toUpperCase()+s.type.substring(1)}s.resizable=false}if(s.statusbar){k+=" mceStatusbar"}if(s.resizable){k+=" mceResizable"}if(s.minimizable){k+=" mceMinimizable"}if(s.maximizable){k+=" mceMaximizable"}if(s.movable){k+=" mceMovable"}z._addAll(d.doc.body,["div",{id:i,role:"dialog","aria-labelledby":s.type?i+"_content":i+"_title","class":(r.settings.inlinepopups_skin||"clearlooks2")+(tinymce.isIE&&window.getSelection?" ie9":""),style:"width:100px;height:100px"},["div",{id:i+"_wrapper","class":"mceWrapper"+k},["div",{id:i+"_top","class":"mceTop"},["div",{"class":"mceLeft"}],["div",{"class":"mceCenter"}],["div",{"class":"mceRight"}],["span",{id:i+"_title"},s.title||""]],["div",{id:i+"_middle","class":"mceMiddle"},["div",{id:i+"_left","class":"mceLeft",tabindex:"0"}],["span",{id:i+"_content"}],["div",{id:i+"_right","class":"mceRight",tabindex:"0"}]],["div",{id:i+"_bottom","class":"mceBottom"},["div",{"class":"mceLeft"}],["div",{"class":"mceCenter"}],["div",{"class":"mceRight"}],["span",{id:i+"_status"},"Content"]],["a",{"class":"mceMove",tabindex:"-1",href:"javascript:;"}],["a",{"class":"mceMin",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceMax",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceMed",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceClose",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{id:i+"_resize_n","class":"mceResize mceResizeN",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_s","class":"mceResize mceResizeS",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_w","class":"mceResize mceResizeW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_e","class":"mceResize mceResizeE",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_nw","class":"mceResize mceResizeNW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_ne","class":"mceResize mceResizeNE",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_sw","class":"mceResize mceResizeSW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_se","class":"mceResize mceResizeSE",tabindex:"-1",href:"javascript:;"}]]]);d.setStyles(i,{top:-10000,left:-10000});if(tinymce.isGecko){d.setStyle(i,"overflow","auto")}if(!s.type){g+=d.get(i+"_left").clientWidth;g+=d.get(i+"_right").clientWidth;v+=d.get(i+"_top").clientHeight;v+=d.get(i+"_bottom").clientHeight}d.setStyles(i,{top:s.top,left:s.left,width:s.width+g,height:s.height+v});y=s.url||s.file;if(y){if(tinymce.relaxedDomain){y+=(y.indexOf("?")==-1?"?":"&")+"mce_rdomain="+tinymce.relaxedDomain}y=tinymce._addVer(y)}if(!s.type){d.add(i+"_content","iframe",{id:i+"_ifr",src:'javascript:""',frameBorder:0,style:"border:0;width:10px;height:10px"});d.setStyles(i+"_ifr",{width:s.width,height:s.height});d.setAttrib(i+"_ifr","src",y)}else{d.add(i+"_wrapper","a",{id:i+"_ok","class":"mceButton mceOk",href:"javascript:;",onmousedown:"return false;"},"Ok");if(s.type=="confirm"){d.add(i+"_wrapper","a",{"class":"mceButton mceCancel",href:"javascript:;",onmousedown:"return false;"},"Cancel")}d.add(i+"_middle","div",{"class":"mceIcon"});d.setHTML(i+"_content",s.content.replace("\n","<br />"));a.add(i,"keyup",function(f){var p=27;if(f.keyCode===p){s.button_func(false);return a.cancel(f)}});a.add(i,"keydown",function(f){var t,p=9;if(f.keyCode===p){t=d.select("a.mceCancel",i+"_wrapper")[0];if(t&&t!==f.target){t.focus()}else{d.get(i+"_ok").focus()}return a.cancel(f)}})}o=a.add(i,"mousedown",function(t){var u=t.target,f,p;f=z.windows[i];z.focus(i);if(u.nodeName=="A"||u.nodeName=="a"){if(u.className=="mceClose"){z.close(null,i);return a.cancel(t)}else{if(u.className=="mceMax"){f.oldPos=f.element.getXY();f.oldSize=f.element.getSize();p=d.getViewPort();p.w-=2;p.h-=2;f.element.moveTo(p.x,p.y);f.element.resizeTo(p.w,p.h);d.setStyles(i+"_ifr",{width:p.w-f.deltaWidth,height:p.h-f.deltaHeight});d.addClass(i+"_wrapper","mceMaximized")}else{if(u.className=="mceMed"){f.element.moveTo(f.oldPos.x,f.oldPos.y);f.element.resizeTo(f.oldSize.w,f.oldSize.h);f.iframeElement.resizeTo(f.oldSize.w-f.deltaWidth,f.oldSize.h-f.deltaHeight);d.removeClass(i+"_wrapper","mceMaximized")}else{if(u.className=="mceMove"){return z._startDrag(i,t,u.className)}else{if(d.hasClass(u,"mceResize")){return z._startDrag(i,t,u.className.substring(13))}}}}}}});q=a.add(i,"click",function(f){var p=f.target;z.focus(i);if(p.nodeName=="A"||p.nodeName=="a"){switch(p.className){case"mceClose":z.close(null,i);return a.cancel(f);case"mceButton mceOk":case"mceButton mceCancel":s.button_func(p.className=="mceButton mceOk");return a.cancel(f)}}});a.add([i+"_left",i+"_right"],"focus",function(p){var t=d.get(i+"_ifr");if(t){var f=t.contentWindow.document.body;var u=d.select(":input:enabled,*[tabindex=0]",f);if(p.target.id===(i+"_left")){u[u.length-1].focus()}else{u[0].focus()}}else{d.get(i+"_ok").focus()}});x=z.windows[i]={id:i,mousedown_func:o,click_func:q,element:new b(i,{blocker:1,container:r.getContainer()}),iframeElement:new b(i+"_ifr"),features:s,deltaWidth:g,deltaHeight:v};x.iframeElement.on("focus",function(){z.focus(i)});if(z.count==0&&z.editor.getParam("dialog_type","modal")=="modal"){d.add(d.doc.body,"div",{id:"mceModalBlocker","class":(z.editor.settings.inlinepopups_skin||"clearlooks2")+"_modalBlocker",style:{zIndex:z.zIndex-1}});d.show("mceModalBlocker");d.setAttrib(d.doc.body,"aria-hidden","true")}else{d.setStyle("mceModalBlocker","z-index",z.zIndex-1)}if(tinymce.isIE6||/Firefox\/2\./.test(navigator.userAgent)||(tinymce.isIE&&!d.boxModel)){d.setStyles("mceModalBlocker",{position:"absolute",left:h.x,top:h.y,width:h.w-2,height:h.h-2})}d.setAttrib(i,"aria-hidden","false");z.focus(i);z._fixIELayout(i,1);if(d.get(i+"_ok")){d.get(i+"_ok").focus()}z.count++;return x},focus:function(h){var g=this,f;if(f=g.windows[h]){f.zIndex=this.zIndex++;f.element.setStyle("zIndex",f.zIndex);f.element.update();h=h+"_wrapper";d.removeClass(g.lastId,"mceFocus");d.addClass(h,"mceFocus");g.lastId=h;if(f.focussedElement){f.focussedElement.focus()}else{if(d.get(h+"_ok")){d.get(f.id+"_ok").focus()}else{if(d.get(f.id+"_ifr")){d.get(f.id+"_ifr").focus()}}}}},_addAll:function(k,h){var g,l,f=this,j=tinymce.DOM;if(c(h,"string")){k.appendChild(j.doc.createTextNode(h))}else{if(h.length){k=k.appendChild(j.create(h[0],h[1]));for(g=2;g<h.length;g++){f._addAll(k,h[g])}}}},_startDrag:function(v,G,E){var o=this,u,z,C=d.doc,f,l=o.windows[v],h=l.element,y=h.getXY(),x,q,F,g,A,s,r,j,i,m,k,n,B;g={x:0,y:0};A=d.getViewPort();A.w-=2;A.h-=2;j=G.screenX;i=G.screenY;m=k=n=B=0;u=a.add(C,"mouseup",function(p){a.remove(C,"mouseup",u);a.remove(C,"mousemove",z);if(f){f.remove()}h.moveBy(m,k);h.resizeBy(n,B);q=h.getSize();d.setStyles(v+"_ifr",{width:q.w-l.deltaWidth,height:q.h-l.deltaHeight});o._fixIELayout(v,1);return a.cancel(p)});if(E!="Move"){D()}function D(){if(f){return}o._fixIELayout(v,0);d.add(C.body,"div",{id:"mceEventBlocker","class":"mceEventBlocker "+(o.editor.settings.inlinepopups_skin||"clearlooks2"),style:{zIndex:o.zIndex+1}});if(tinymce.isIE6||(tinymce.isIE&&!d.boxModel)){d.setStyles("mceEventBlocker",{position:"absolute",left:A.x,top:A.y,width:A.w-2,height:A.h-2})}f=new b("mceEventBlocker");f.update();x=h.getXY();q=h.getSize();s=g.x+x.x-A.x;r=g.y+x.y-A.y;d.add(f.get(),"div",{id:"mcePlaceHolder","class":"mcePlaceHolder",style:{left:s,top:r,width:q.w,height:q.h}});F=new b("mcePlaceHolder")}z=a.add(C,"mousemove",function(w){var p,H,t;D();p=w.screenX-j;H=w.screenY-i;switch(E){case"ResizeW":m=p;n=0-p;break;case"ResizeE":n=p;break;case"ResizeN":case"ResizeNW":case"ResizeNE":if(E=="ResizeNW"){m=p;n=0-p}else{if(E=="ResizeNE"){n=p}}k=H;B=0-H;break;case"ResizeS":case"ResizeSW":case"ResizeSE":if(E=="ResizeSW"){m=p;n=0-p}else{if(E=="ResizeSE"){n=p}}B=H;break;case"mceMove":m=p;k=H;break}if(n<(t=l.features.min_width-q.w)){if(m!==0){m+=n-t}n=t}if(B<(t=l.features.min_height-q.h)){if(k!==0){k+=B-t}B=t}n=Math.min(n,l.features.max_width-q.w);B=Math.min(B,l.features.max_height-q.h);m=Math.max(m,A.x-(s+A.x));k=Math.max(k,A.y-(r+A.y));m=Math.min(m,(A.w+A.x)-(s+q.w+A.x));k=Math.min(k,(A.h+A.y)-(r+q.h+A.y));if(m+k!==0){if(s+m<0){m=0}if(r+k<0){k=0}F.moveTo(s+m,r+k)}if(n+B!==0){F.resizeTo(q.w+n,q.h+B)}return a.cancel(w)});return a.cancel(G)},resizeBy:function(g,h,i){var f=this.windows[i];if(f){f.element.resizeBy(g,h);f.iframeElement.resizeBy(g,h)}},close:function(i,k){var g=this,f,j=d.doc,h,k;k=g._findId(k||i);if(!g.windows[k]){g.parent(i);return}g.count--;if(g.count==0){d.remove("mceModalBlocker");d.setAttrib(d.doc.body,"aria-hidden","false");g.editor.focus()}if(f=g.windows[k]){g.onClose.dispatch(g);a.remove(j,"mousedown",f.mousedownFunc);a.remove(j,"click",f.clickFunc);a.clear(k);a.clear(k+"_ifr");d.setAttrib(k+"_ifr","src",'javascript:""');f.element.remove();delete g.windows[k];h=g._frontWindow();if(h){g.focus(h.id)}}},_frontWindow:function(){var g,f=0;e(this.windows,function(h){if(h.zIndex>f){g=h;f=h.zIndex}});return g},setTitle:function(f,g){var h;f=this._findId(f);if(h=d.get(f+"_title")){h.innerHTML=d.encode(g)}},alert:function(g,f,j){var i=this,h;h=i.open({title:i,type:"alert",button_func:function(k){if(f){f.call(k||i,k)}i.close(null,h.id)},content:d.encode(i.editor.getLang(g,g)),inline:1,width:400,height:130})},confirm:function(g,f,j){var i=this,h;h=i.open({title:i,type:"confirm",button_func:function(k){if(f){f.call(k||i,k)}i.close(null,h.id)},content:d.encode(i.editor.getLang(g,g)),inline:1,width:400,height:130})},_findId:function(f){var g=this;if(typeof(f)=="string"){return f}e(g.windows,function(h){var i=d.get(h.id+"_ifr");if(i&&f==i.contentWindow){f=h.id;return false}});return f},_fixIELayout:function(i,h){var f,g;if(!tinymce.isIE6){return}e(["n","s","w","e","nw","ne","sw","se"],function(j){var k=d.get(i+"_resize_"+j);d.setStyles(k,{width:h?k.clientWidth:"",height:h?k.clientHeight:"",cursor:d.getStyle(k,"cursor",1)});d.setStyle(i+"_bottom","bottom","-1px");k=0});if(f=this.windows[i]){f.element.hide();f.element.show();e(d.select("div,a",i),function(k,j){if(k.currentStyle.backgroundImage!="none"){g=new Image();g.src=k.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/,"$1")}});d.get(i).style.filter=""}}});tinymce.PluginManager.add("inlinepopups",tinymce.plugins.InlinePopups)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin_src.js
new file mode 100644
index 0000000000..2a6f3ad299
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/editor_plugin_src.js
@@ -0,0 +1,699 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM, Element = tinymce.dom.Element, Event = tinymce.dom.Event, each = tinymce.each, is = tinymce.is;
+
+ tinymce.create('tinymce.plugins.InlinePopups', {
+ init : function(ed, url) {
+ // Replace window manager
+ ed.onBeforeRenderUI.add(function() {
+ ed.windowManager = new tinymce.InlineWindowManager(ed);
+ DOM.loadCSS(url + '/skins/' + (ed.settings.inlinepopups_skin || 'clearlooks2') + "/window.css");
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'InlinePopups',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ tinymce.create('tinymce.InlineWindowManager:tinymce.WindowManager', {
+ InlineWindowManager : function(ed) {
+ var t = this;
+
+ t.parent(ed);
+ t.zIndex = 300000;
+ t.count = 0;
+ t.windows = {};
+ },
+
+ open : function(f, p) {
+ var t = this, id, opt = '', ed = t.editor, dw = 0, dh = 0, vp, po, mdf, clf, we, w, u, parentWindow;
+
+ f = f || {};
+ p = p || {};
+
+ // Run native windows
+ if (!f.inline)
+ return t.parent(f, p);
+
+ parentWindow = t._frontWindow();
+ if (parentWindow && DOM.get(parentWindow.id + '_ifr')) {
+ parentWindow.focussedElement = DOM.get(parentWindow.id + '_ifr').contentWindow.document.activeElement;
+ }
+
+ // Only store selection if the type is a normal window
+ if (!f.type)
+ t.bookmark = ed.selection.getBookmark(1);
+
+ id = DOM.uniqueId();
+ vp = DOM.getViewPort();
+ f.width = parseInt(f.width || 320);
+ f.height = parseInt(f.height || 240) + (tinymce.isIE ? 8 : 0);
+ f.min_width = parseInt(f.min_width || 150);
+ f.min_height = parseInt(f.min_height || 100);
+ f.max_width = parseInt(f.max_width || 2000);
+ f.max_height = parseInt(f.max_height || 2000);
+ f.left = f.left || Math.round(Math.max(vp.x, vp.x + (vp.w / 2.0) - (f.width / 2.0)));
+ f.top = f.top || Math.round(Math.max(vp.y, vp.y + (vp.h / 2.0) - (f.height / 2.0)));
+ f.movable = f.resizable = true;
+ p.mce_width = f.width;
+ p.mce_height = f.height;
+ p.mce_inline = true;
+ p.mce_window_id = id;
+ p.mce_auto_focus = f.auto_focus;
+
+ // Transpose
+// po = DOM.getPos(ed.getContainer());
+// f.left -= po.x;
+// f.top -= po.y;
+
+ t.features = f;
+ t.params = p;
+ t.onOpen.dispatch(t, f, p);
+
+ if (f.type) {
+ opt += ' mceModal';
+
+ if (f.type)
+ opt += ' mce' + f.type.substring(0, 1).toUpperCase() + f.type.substring(1);
+
+ f.resizable = false;
+ }
+
+ if (f.statusbar)
+ opt += ' mceStatusbar';
+
+ if (f.resizable)
+ opt += ' mceResizable';
+
+ if (f.minimizable)
+ opt += ' mceMinimizable';
+
+ if (f.maximizable)
+ opt += ' mceMaximizable';
+
+ if (f.movable)
+ opt += ' mceMovable';
+
+ // Create DOM objects
+ t._addAll(DOM.doc.body,
+ ['div', {id : id, role : 'dialog', 'aria-labelledby': f.type ? id + '_content' : id + '_title', 'class' : (ed.settings.inlinepopups_skin || 'clearlooks2') + (tinymce.isIE && window.getSelection ? ' ie9' : ''), style : 'width:100px;height:100px'},
+ ['div', {id : id + '_wrapper', 'class' : 'mceWrapper' + opt},
+ ['div', {id : id + '_top', 'class' : 'mceTop'},
+ ['div', {'class' : 'mceLeft'}],
+ ['div', {'class' : 'mceCenter'}],
+ ['div', {'class' : 'mceRight'}],
+ ['span', {id : id + '_title'}, f.title || '']
+ ],
+
+ ['div', {id : id + '_middle', 'class' : 'mceMiddle'},
+ ['div', {id : id + '_left', 'class' : 'mceLeft', tabindex : '0'}],
+ ['span', {id : id + '_content'}],
+ ['div', {id : id + '_right', 'class' : 'mceRight', tabindex : '0'}]
+ ],
+
+ ['div', {id : id + '_bottom', 'class' : 'mceBottom'},
+ ['div', {'class' : 'mceLeft'}],
+ ['div', {'class' : 'mceCenter'}],
+ ['div', {'class' : 'mceRight'}],
+ ['span', {id : id + '_status'}, 'Content']
+ ],
+
+ ['a', {'class' : 'mceMove', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {'class' : 'mceMin', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {'class' : 'mceMax', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {'class' : 'mceMed', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {'class' : 'mceClose', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {id : id + '_resize_n', 'class' : 'mceResize mceResizeN', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_s', 'class' : 'mceResize mceResizeS', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_w', 'class' : 'mceResize mceResizeW', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_e', 'class' : 'mceResize mceResizeE', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_nw', 'class' : 'mceResize mceResizeNW', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_ne', 'class' : 'mceResize mceResizeNE', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_sw', 'class' : 'mceResize mceResizeSW', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_se', 'class' : 'mceResize mceResizeSE', tabindex : '-1', href : 'javascript:;'}]
+ ]
+ ]
+ );
+
+ DOM.setStyles(id, {top : -10000, left : -10000});
+
+ // Fix gecko rendering bug, where the editors iframe messed with window contents
+ if (tinymce.isGecko)
+ DOM.setStyle(id, 'overflow', 'auto');
+
+ // Measure borders
+ if (!f.type) {
+ dw += DOM.get(id + '_left').clientWidth;
+ dw += DOM.get(id + '_right').clientWidth;
+ dh += DOM.get(id + '_top').clientHeight;
+ dh += DOM.get(id + '_bottom').clientHeight;
+ }
+
+ // Resize window
+ DOM.setStyles(id, {top : f.top, left : f.left, width : f.width + dw, height : f.height + dh});
+
+ u = f.url || f.file;
+ if (u) {
+ if (tinymce.relaxedDomain)
+ u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain;
+
+ u = tinymce._addVer(u);
+ }
+
+ if (!f.type) {
+ DOM.add(id + '_content', 'iframe', {id : id + '_ifr', src : 'javascript:""', frameBorder : 0, style : 'border:0;width:10px;height:10px'});
+ DOM.setStyles(id + '_ifr', {width : f.width, height : f.height});
+ DOM.setAttrib(id + '_ifr', 'src', u);
+ } else {
+ DOM.add(id + '_wrapper', 'a', {id : id + '_ok', 'class' : 'mceButton mceOk', href : 'javascript:;', onmousedown : 'return false;'}, 'Ok');
+
+ if (f.type == 'confirm')
+ DOM.add(id + '_wrapper', 'a', {'class' : 'mceButton mceCancel', href : 'javascript:;', onmousedown : 'return false;'}, 'Cancel');
+
+ DOM.add(id + '_middle', 'div', {'class' : 'mceIcon'});
+ DOM.setHTML(id + '_content', f.content.replace('\n', '<br />'));
+
+ Event.add(id, 'keyup', function(evt) {
+ var VK_ESCAPE = 27;
+ if (evt.keyCode === VK_ESCAPE) {
+ f.button_func(false);
+ return Event.cancel(evt);
+ }
+ });
+
+ Event.add(id, 'keydown', function(evt) {
+ var cancelButton, VK_TAB = 9;
+ if (evt.keyCode === VK_TAB) {
+ cancelButton = DOM.select('a.mceCancel', id + '_wrapper')[0];
+ if (cancelButton && cancelButton !== evt.target) {
+ cancelButton.focus();
+ } else {
+ DOM.get(id + '_ok').focus();
+ }
+ return Event.cancel(evt);
+ }
+ });
+ }
+
+ // Register events
+ mdf = Event.add(id, 'mousedown', function(e) {
+ var n = e.target, w, vp;
+
+ w = t.windows[id];
+ t.focus(id);
+
+ if (n.nodeName == 'A' || n.nodeName == 'a') {
+ if (n.className == 'mceClose') {
+ t.close(null, id);
+ return Event.cancel(e);
+ } else if (n.className == 'mceMax') {
+ w.oldPos = w.element.getXY();
+ w.oldSize = w.element.getSize();
+
+ vp = DOM.getViewPort();
+
+ // Reduce viewport size to avoid scrollbars
+ vp.w -= 2;
+ vp.h -= 2;
+
+ w.element.moveTo(vp.x, vp.y);
+ w.element.resizeTo(vp.w, vp.h);
+ DOM.setStyles(id + '_ifr', {width : vp.w - w.deltaWidth, height : vp.h - w.deltaHeight});
+ DOM.addClass(id + '_wrapper', 'mceMaximized');
+ } else if (n.className == 'mceMed') {
+ // Reset to old size
+ w.element.moveTo(w.oldPos.x, w.oldPos.y);
+ w.element.resizeTo(w.oldSize.w, w.oldSize.h);
+ w.iframeElement.resizeTo(w.oldSize.w - w.deltaWidth, w.oldSize.h - w.deltaHeight);
+
+ DOM.removeClass(id + '_wrapper', 'mceMaximized');
+ } else if (n.className == 'mceMove')
+ return t._startDrag(id, e, n.className);
+ else if (DOM.hasClass(n, 'mceResize'))
+ return t._startDrag(id, e, n.className.substring(13));
+ }
+ });
+
+ clf = Event.add(id, 'click', function(e) {
+ var n = e.target;
+
+ t.focus(id);
+
+ if (n.nodeName == 'A' || n.nodeName == 'a') {
+ switch (n.className) {
+ case 'mceClose':
+ t.close(null, id);
+ return Event.cancel(e);
+
+ case 'mceButton mceOk':
+ case 'mceButton mceCancel':
+ f.button_func(n.className == 'mceButton mceOk');
+ return Event.cancel(e);
+ }
+ }
+ });
+
+ // Make sure the tab order loops within the dialog.
+ Event.add([id + '_left', id + '_right'], 'focus', function(evt) {
+ var iframe = DOM.get(id + '_ifr');
+ if (iframe) {
+ var body = iframe.contentWindow.document.body;
+ var focusable = DOM.select(':input:enabled,*[tabindex=0]', body);
+ if (evt.target.id === (id + '_left')) {
+ focusable[focusable.length - 1].focus();
+ } else {
+ focusable[0].focus();
+ }
+ } else {
+ DOM.get(id + '_ok').focus();
+ }
+ });
+
+ // Add window
+ w = t.windows[id] = {
+ id : id,
+ mousedown_func : mdf,
+ click_func : clf,
+ element : new Element(id, {blocker : 1, container : ed.getContainer()}),
+ iframeElement : new Element(id + '_ifr'),
+ features : f,
+ deltaWidth : dw,
+ deltaHeight : dh
+ };
+
+ w.iframeElement.on('focus', function() {
+ t.focus(id);
+ });
+
+ // Setup blocker
+ if (t.count == 0 && t.editor.getParam('dialog_type', 'modal') == 'modal') {
+ DOM.add(DOM.doc.body, 'div', {
+ id : 'mceModalBlocker',
+ 'class' : (t.editor.settings.inlinepopups_skin || 'clearlooks2') + '_modalBlocker',
+ style : {zIndex : t.zIndex - 1}
+ });
+
+ DOM.show('mceModalBlocker'); // Reduces flicker in IE
+ DOM.setAttrib(DOM.doc.body, 'aria-hidden', 'true');
+ } else
+ DOM.setStyle('mceModalBlocker', 'z-index', t.zIndex - 1);
+
+ if (tinymce.isIE6 || /Firefox\/2\./.test(navigator.userAgent) || (tinymce.isIE && !DOM.boxModel))
+ DOM.setStyles('mceModalBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2});
+
+ DOM.setAttrib(id, 'aria-hidden', 'false');
+ t.focus(id);
+ t._fixIELayout(id, 1);
+
+ // Focus ok button
+ if (DOM.get(id + '_ok'))
+ DOM.get(id + '_ok').focus();
+ t.count++;
+
+ return w;
+ },
+
+ focus : function(id) {
+ var t = this, w;
+
+ if (w = t.windows[id]) {
+ w.zIndex = this.zIndex++;
+ w.element.setStyle('zIndex', w.zIndex);
+ w.element.update();
+
+ id = id + '_wrapper';
+ DOM.removeClass(t.lastId, 'mceFocus');
+ DOM.addClass(id, 'mceFocus');
+ t.lastId = id;
+
+ if (w.focussedElement) {
+ w.focussedElement.focus();
+ } else if (DOM.get(id + '_ok')) {
+ DOM.get(w.id + '_ok').focus();
+ } else if (DOM.get(w.id + '_ifr')) {
+ DOM.get(w.id + '_ifr').focus();
+ }
+ }
+ },
+
+ _addAll : function(te, ne) {
+ var i, n, t = this, dom = tinymce.DOM;
+
+ if (is(ne, 'string'))
+ te.appendChild(dom.doc.createTextNode(ne));
+ else if (ne.length) {
+ te = te.appendChild(dom.create(ne[0], ne[1]));
+
+ for (i=2; i<ne.length; i++)
+ t._addAll(te, ne[i]);
+ }
+ },
+
+ _startDrag : function(id, se, ac) {
+ var t = this, mu, mm, d = DOM.doc, eb, w = t.windows[id], we = w.element, sp = we.getXY(), p, sz, ph, cp, vp, sx, sy, sex, sey, dx, dy, dw, dh;
+
+ // Get positons and sizes
+// cp = DOM.getPos(t.editor.getContainer());
+ cp = {x : 0, y : 0};
+ vp = DOM.getViewPort();
+
+ // Reduce viewport size to avoid scrollbars while dragging
+ vp.w -= 2;
+ vp.h -= 2;
+
+ sex = se.screenX;
+ sey = se.screenY;
+ dx = dy = dw = dh = 0;
+
+ // Handle mouse up
+ mu = Event.add(d, 'mouseup', function(e) {
+ Event.remove(d, 'mouseup', mu);
+ Event.remove(d, 'mousemove', mm);
+
+ if (eb)
+ eb.remove();
+
+ we.moveBy(dx, dy);
+ we.resizeBy(dw, dh);
+ sz = we.getSize();
+ DOM.setStyles(id + '_ifr', {width : sz.w - w.deltaWidth, height : sz.h - w.deltaHeight});
+ t._fixIELayout(id, 1);
+
+ return Event.cancel(e);
+ });
+
+ if (ac != 'Move')
+ startMove();
+
+ function startMove() {
+ if (eb)
+ return;
+
+ t._fixIELayout(id, 0);
+
+ // Setup event blocker
+ DOM.add(d.body, 'div', {
+ id : 'mceEventBlocker',
+ 'class' : 'mceEventBlocker ' + (t.editor.settings.inlinepopups_skin || 'clearlooks2'),
+ style : {zIndex : t.zIndex + 1}
+ });
+
+ if (tinymce.isIE6 || (tinymce.isIE && !DOM.boxModel))
+ DOM.setStyles('mceEventBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2});
+
+ eb = new Element('mceEventBlocker');
+ eb.update();
+
+ // Setup placeholder
+ p = we.getXY();
+ sz = we.getSize();
+ sx = cp.x + p.x - vp.x;
+ sy = cp.y + p.y - vp.y;
+ DOM.add(eb.get(), 'div', {id : 'mcePlaceHolder', 'class' : 'mcePlaceHolder', style : {left : sx, top : sy, width : sz.w, height : sz.h}});
+ ph = new Element('mcePlaceHolder');
+ };
+
+ // Handle mouse move/drag
+ mm = Event.add(d, 'mousemove', function(e) {
+ var x, y, v;
+
+ startMove();
+
+ x = e.screenX - sex;
+ y = e.screenY - sey;
+
+ switch (ac) {
+ case 'ResizeW':
+ dx = x;
+ dw = 0 - x;
+ break;
+
+ case 'ResizeE':
+ dw = x;
+ break;
+
+ case 'ResizeN':
+ case 'ResizeNW':
+ case 'ResizeNE':
+ if (ac == "ResizeNW") {
+ dx = x;
+ dw = 0 - x;
+ } else if (ac == "ResizeNE")
+ dw = x;
+
+ dy = y;
+ dh = 0 - y;
+ break;
+
+ case 'ResizeS':
+ case 'ResizeSW':
+ case 'ResizeSE':
+ if (ac == "ResizeSW") {
+ dx = x;
+ dw = 0 - x;
+ } else if (ac == "ResizeSE")
+ dw = x;
+
+ dh = y;
+ break;
+
+ case 'mceMove':
+ dx = x;
+ dy = y;
+ break;
+ }
+
+ // Boundary check
+ if (dw < (v = w.features.min_width - sz.w)) {
+ if (dx !== 0)
+ dx += dw - v;
+
+ dw = v;
+ }
+
+ if (dh < (v = w.features.min_height - sz.h)) {
+ if (dy !== 0)
+ dy += dh - v;
+
+ dh = v;
+ }
+
+ dw = Math.min(dw, w.features.max_width - sz.w);
+ dh = Math.min(dh, w.features.max_height - sz.h);
+ dx = Math.max(dx, vp.x - (sx + vp.x));
+ dy = Math.max(dy, vp.y - (sy + vp.y));
+ dx = Math.min(dx, (vp.w + vp.x) - (sx + sz.w + vp.x));
+ dy = Math.min(dy, (vp.h + vp.y) - (sy + sz.h + vp.y));
+
+ // Move if needed
+ if (dx + dy !== 0) {
+ if (sx + dx < 0)
+ dx = 0;
+
+ if (sy + dy < 0)
+ dy = 0;
+
+ ph.moveTo(sx + dx, sy + dy);
+ }
+
+ // Resize if needed
+ if (dw + dh !== 0)
+ ph.resizeTo(sz.w + dw, sz.h + dh);
+
+ return Event.cancel(e);
+ });
+
+ return Event.cancel(se);
+ },
+
+ resizeBy : function(dw, dh, id) {
+ var w = this.windows[id];
+
+ if (w) {
+ w.element.resizeBy(dw, dh);
+ w.iframeElement.resizeBy(dw, dh);
+ }
+ },
+
+ close : function(win, id) {
+ var t = this, w, d = DOM.doc, fw, id;
+
+ id = t._findId(id || win);
+
+ // Probably not inline
+ if (!t.windows[id]) {
+ t.parent(win);
+ return;
+ }
+
+ t.count--;
+
+ if (t.count == 0) {
+ DOM.remove('mceModalBlocker');
+ DOM.setAttrib(DOM.doc.body, 'aria-hidden', 'false');
+ t.editor.focus();
+ }
+
+ if (w = t.windows[id]) {
+ t.onClose.dispatch(t);
+ Event.remove(d, 'mousedown', w.mousedownFunc);
+ Event.remove(d, 'click', w.clickFunc);
+ Event.clear(id);
+ Event.clear(id + '_ifr');
+
+ DOM.setAttrib(id + '_ifr', 'src', 'javascript:""'); // Prevent leak
+ w.element.remove();
+ delete t.windows[id];
+
+ fw = t._frontWindow();
+
+ if (fw)
+ t.focus(fw.id);
+ }
+ },
+
+ // Find front most window
+ _frontWindow : function() {
+ var fw, ix = 0;
+ // Find front most window and focus that
+ each (this.windows, function(w) {
+ if (w.zIndex > ix) {
+ fw = w;
+ ix = w.zIndex;
+ }
+ });
+ return fw;
+ },
+
+ setTitle : function(w, ti) {
+ var e;
+
+ w = this._findId(w);
+
+ if (e = DOM.get(w + '_title'))
+ e.innerHTML = DOM.encode(ti);
+ },
+
+ alert : function(txt, cb, s) {
+ var t = this, w;
+
+ w = t.open({
+ title : t,
+ type : 'alert',
+ button_func : function(s) {
+ if (cb)
+ cb.call(s || t, s);
+
+ t.close(null, w.id);
+ },
+ content : DOM.encode(t.editor.getLang(txt, txt)),
+ inline : 1,
+ width : 400,
+ height : 130
+ });
+ },
+
+ confirm : function(txt, cb, s) {
+ var t = this, w;
+
+ w = t.open({
+ title : t,
+ type : 'confirm',
+ button_func : function(s) {
+ if (cb)
+ cb.call(s || t, s);
+
+ t.close(null, w.id);
+ },
+ content : DOM.encode(t.editor.getLang(txt, txt)),
+ inline : 1,
+ width : 400,
+ height : 130
+ });
+ },
+
+ // Internal functions
+
+ _findId : function(w) {
+ var t = this;
+
+ if (typeof(w) == 'string')
+ return w;
+
+ each(t.windows, function(wo) {
+ var ifr = DOM.get(wo.id + '_ifr');
+
+ if (ifr && w == ifr.contentWindow) {
+ w = wo.id;
+ return false;
+ }
+ });
+
+ return w;
+ },
+
+ _fixIELayout : function(id, s) {
+ var w, img;
+
+ if (!tinymce.isIE6)
+ return;
+
+ // Fixes the bug where hover flickers and does odd things in IE6
+ each(['n','s','w','e','nw','ne','sw','se'], function(v) {
+ var e = DOM.get(id + '_resize_' + v);
+
+ DOM.setStyles(e, {
+ width : s ? e.clientWidth : '',
+ height : s ? e.clientHeight : '',
+ cursor : DOM.getStyle(e, 'cursor', 1)
+ });
+
+ DOM.setStyle(id + "_bottom", 'bottom', '-1px');
+
+ e = 0;
+ });
+
+ // Fixes graphics glitch
+ if (w = this.windows[id]) {
+ // Fixes rendering bug after resize
+ w.element.hide();
+ w.element.show();
+
+ // Forced a repaint of the window
+ //DOM.get(id).style.filter = '';
+
+ // IE has a bug where images used in CSS won't get loaded
+ // sometimes when the cache in the browser is disabled
+ // This fix tries to solve it by loading the images using the image object
+ each(DOM.select('div,a', id), function(e, i) {
+ if (e.currentStyle.backgroundImage != 'none') {
+ img = new Image();
+ img.src = e.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/, '$1');
+ }
+ });
+
+ DOM.get(id).style.filter = '';
+ }
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('inlinepopups', tinymce.plugins.InlinePopups);
+})();
+
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif
new file mode 100644
index 0000000000..219139857e
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gif
new file mode 100644
index 0000000000..f957e49a3d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif
new file mode 100644
index 0000000000..b408ae1fe7
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif
new file mode 100644
index 0000000000..20acbbf7ae
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif
new file mode 100644
index 0000000000..d5de1cc236
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/drag.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/drag.gif
new file mode 100644
index 0000000000..a5f068385d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/drag.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif
new file mode 100644
index 0000000000..c2a2ad454d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif
new file mode 100644
index 0000000000..0b4cc3682a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css
new file mode 100644
index 0000000000..ad07434df4
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css
@@ -0,0 +1,126 @@
+/* Clearlooks 2 */
+
+/* Reset */
+.clearlooks2, .clearlooks2 div, .clearlooks2 span, .clearlooks2 a {vertical-align:baseline; text-align:left; position:absolute; border:0; padding:0; margin:0; background:transparent; font-family:Arial,Verdana; font-size:11px; color:#000; text-decoration:none; font-weight:normal; width:auto; height:auto; overflow:hidden; display:block}
+
+/* General */
+.clearlooks2 {position:absolute; direction:ltr}
+.clearlooks2 .mceWrapper {position:static}
+.mceEventBlocker {position:fixed; left:0; top:0; background:url(img/horizontal.gif) no-repeat 0 -75px; width:100%; height:100%}
+.clearlooks2 .mcePlaceHolder {border:1px solid #000; background:#888; top:0; left:0; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50)}
+.clearlooks2_modalBlocker {position:fixed; left:0; top:0; width:100%; height:100%; background:#FFF; opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60); display:none}
+
+/* Top */
+.clearlooks2 .mceTop,
+.clearlooks2 .mceTop div {
+ top:0;
+ width:100%;
+ height:23px
+}
+.clearlooks2 .mceTop .mceLeft {
+ width:55%;
+ background-image: none;
+ border-style: solid none none solid;
+ border-width: 1px;
+}
+.clearlooks2 .mceTop .mceCenter {
+}
+.clearlooks2 .mceTop .mceRight {
+ right:0;
+ width:55%;
+ height:23px;
+ background-image: none;
+ border-style: solid solid none none;
+ border-width: 1px;
+}
+.clearlooks2 .mceTop span {
+ width:100%;
+ font: 12px/20px bold "Lucida Grande","Lucida Sans Unicode",Tahoma,Verdana,sans-serif;
+ text-align:center;
+ vertical-align:middle;
+ line-height:23px;
+ font-weight:bold;
+}
+.clearlooks2 .mceFocus .mceTop .mceLeft {
+ background-image: none;
+ border-style: solid none none solid;
+ border-width: 1px;
+}
+.clearlooks2 .mceFocus .mceTop .mceCenter {
+}
+.clearlooks2 .mceFocus .mceTop .mceRight {
+ background-image: none;
+ border-style: solid solid none none;
+ border-width: 1px;
+}
+.clearlooks2 .mceFocus .mceTop span {
+color:#FFF
+}
+
+/* Middle */
+.clearlooks2 .mceMiddle, .clearlooks2 .mceMiddle div {top:0}
+.clearlooks2 .mceMiddle {width:100%; height:100%; clip:rect(23px auto auto auto)}
+.clearlooks2 .mceMiddle .mceLeft {left:0; width:5px; height:100%; background:#E4F2FD;border-left:1px solid #c6d9e9}
+.clearlooks2 .mceMiddle span {top:23px; left:5px; width:100%; height:100%; background:#FFF}
+.clearlooks2 .mceMiddle .mceRight {right:0; width:5px; height:100%; background:#E4F2FD;border-right:1px solid #c6d9e9}
+
+/* Bottom */
+.clearlooks2 .mceBottom, .clearlooks2 .mceBottom div {height:6px}
+.clearlooks2 .mceBottom {left:0; bottom:0; width:100%;background:#E4F2FD;border-bottom:1px solid #c6d9e9}
+.clearlooks2 .mceBottom div {top:0}
+.clearlooks2 .mceBottom .mceLeft {left:0; width:5px; background:#E4F2FD ;border-left:1px solid #c6d9e9}
+.clearlooks2 .mceBottom .mceCenter {left:5px; width:100%}
+.clearlooks2 .mceBottom .mceRight {right:0; width:6px; background:#E4F2FD url(img/drag.gif) no-repeat;border-right:1px solid #c6d9e9}
+.clearlooks2 .mceBottom span {display:none}
+.clearlooks2 .mceStatusbar .mceBottom, .clearlooks2 .mceStatusbar .mceBottom div {height:23px}
+.clearlooks2 .mceStatusbar .mceBottom .mceLeft {background:url(img/corners.gif) -29px 0}
+.clearlooks2 .mceStatusbar .mceBottom .mceCenter {background:url(img/horizontal.gif) 0 -52px}
+.clearlooks2 .mceStatusbar .mceBottom .mceRight {background:url(img/corners.gif) -24px 0}
+.clearlooks2 .mceStatusbar .mceBottom span {display:block; left:7px; font-family:Arial, Verdana; font-size:11px; line-height:23px}
+
+/* Actions */
+.clearlooks2 a {width:29px; height:16px; top:3px;}
+.clearlooks2 .mceClose {right:6px; background:url(img/buttons.gif) -87px 0}
+.clearlooks2 .mceMin {display:none; right:68px; background:url(img/buttons.gif) 0 0}
+.clearlooks2 .mceMed {display:none; right:37px; background:url(img/buttons.gif) -29px 0}
+.clearlooks2 .mceMax {display:none; right:37px; background:url(img/buttons.gif) -58px 0}
+.clearlooks2 .mceMove {display:none;width:100%;cursor:move;background:url(img/corners.gif) no-repeat -100px -100px}
+.clearlooks2 .mceMovable .mceMove {display:block}
+.clearlooks2 .mceFocus .mceClose {right:6px; background:url(img/buttons.gif) -87px -16px}
+.clearlooks2 .mceFocus .mceMin {right:68px; background:url(img/buttons.gif) 0 -16px}
+.clearlooks2 .mceFocus .mceMed {right:37px; background:url(img/buttons.gif) -29px -16px}
+.clearlooks2 .mceFocus .mceMax {right:37px; background:url(img/buttons.gif) -58px -16px}
+.clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px}
+.clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px}
+.clearlooks2 .mceFocus .mceMin:hover {right:68px; background:url(img/buttons.gif) 0 -32px}
+.clearlooks2 .mceFocus .mceMed:hover {right:37px; background:url(img/buttons.gif) -29px -32px}
+.clearlooks2 .mceFocus .mceMax:hover {right:37px; background:url(img/buttons.gif) -58px -32px}
+
+/* Resize */
+.clearlooks2 .mceResize {top:auto; left:auto; display:none; width:5px; height:5px; background:url(img/horizontal.gif) no-repeat 0 -75px}
+.clearlooks2 .mceResizable .mceResize {display:block}
+.clearlooks2 .mceResizable .mceMin, .clearlooks2 .mceMax {display:none}
+.clearlooks2 .mceMinimizable .mceMin {display:block}
+.clearlooks2 .mceMaximizable .mceMax {display:block}
+.clearlooks2 .mceMaximized .mceMed {display:block}
+.clearlooks2 .mceMaximized .mceMax {display:none}
+.clearlooks2 a.mceResizeN {top:0; left:0; width:100%; cursor:n-resize}
+.clearlooks2 a.mceResizeNW {top:0; left:0; cursor:nw-resize}
+.clearlooks2 a.mceResizeNE {top:0; right:0; cursor:ne-resize}
+.clearlooks2 a.mceResizeW {top:0; left:0; height:100%; cursor:w-resize;}
+.clearlooks2 a.mceResizeE {top:0; right:0; height:100%; cursor:e-resize}
+.clearlooks2 a.mceResizeS {bottom:0; left:0; width:100%; cursor:s-resize}
+.clearlooks2 a.mceResizeSW {bottom:0; left:0; cursor:sw-resize}
+.clearlooks2 a.mceResizeSE {bottom:0; right:0; cursor:se-resize}
+
+/* Alert/Confirm */
+.clearlooks2 .mceButton {font-weight:bold; bottom:10px; width:80px; height:30px; background:url(img/button.gif); line-height:30px; vertical-align:middle; text-align:center; outline:0}
+.clearlooks2 .mceMiddle .mceIcon {left:15px; top:35px; width:32px; height:32px}
+.clearlooks2 .mceAlert .mceMiddle span, .clearlooks2 .mceConfirm .mceMiddle span {background:transparent;left:60px; top:35px; width:320px; height:50px; font-weight:bold; overflow:auto; white-space:normal}
+.clearlooks2 a:hover {font-weight:bold;}
+.clearlooks2 .mceAlert .mceMiddle, .clearlooks2 .mceConfirm .mceMiddle {background:#F9F9F9}
+.clearlooks2 .mceAlert .mceOk {left:50%; top:auto; margin-left: -40px}
+.clearlooks2 .mceAlert .mceIcon {background:url(img/alert.gif)}
+.clearlooks2 .mceConfirm .mceOk {left:50%; top:auto; margin-left: -90px}
+.clearlooks2 .mceConfirm .mceCancel {left:50%; top:auto}
+.clearlooks2 .mceConfirm .mceIcon {background:url(img/confirm.gif)}
diff --git a/src/wp-includes/js/tinymce/plugins/inlinepopups/template.htm b/src/wp-includes/js/tinymce/plugins/inlinepopups/template.htm
new file mode 100644
index 0000000000..289b7acb54
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/inlinepopups/template.htm
@@ -0,0 +1,387 @@
+<!-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Template for dialogs</title>
+<link rel="stylesheet" type="text/css" href="skins/clearlooks2/window.css?ver=358-20121205" />
+</head>
+<body>
+
+<div class="mceEditor">
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px;">
+ <div class="mceWrapper">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Blured</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px;">
+ <div class="mceWrapper mceMovable mceFocus">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Focused</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px; top:120px;">
+ <div class="mceWrapper mceMovable mceFocus mceStatusbar">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px; top:120px;">
+ <div class="mceWrapper mceMovable mceFocus mceStatusbar mceResizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar, Resizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px; top:230px;">
+ <div class="mceWrapper mceMovable mceFocus mceResizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Resizable, Maximizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px; top:230px;">
+ <div class="mceWrapper mceMovable mceStatusbar mceResizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Blurred, Maximizable, Statusbar, Resizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px; top:340px;">
+ <div class="mceWrapper mceMovable mceFocus mceResizable mceMaximized mceMinimizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Maximized, Maximizable, Minimizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px; top:340px;">
+ <div class="mceWrapper mceMovable mceStatusbar mceResizable mceMaximized mceMinimizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Blured</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:130px; left:10px; top:450px;">
+ <div class="mceWrapper mceMovable mceFocus mceModal mceAlert">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Alert</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ </span>
+ <div class="mceRight"></div>
+ <div class="mceIcon"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceButton mceOk" href="#">Ok</a>
+ <a class="mceClose" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:130px; left:420px; top:450px;">
+ <div class="mceWrapper mceMovable mceFocus mceModal mceConfirm">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Confirm</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ </span>
+ <div class="mceRight"></div>
+ <div class="mceIcon"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceButton mceOk" href="#">Ok</a>
+ <a class="mceButton mceCancel" href="#">Cancel</a>
+ <a class="mceClose" href="#"></a>
+ </div>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/plugins/media/css/media.css b/src/wp-includes/js/tinymce/plugins/media/css/media.css
new file mode 100644
index 0000000000..fd04898ca5
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/css/media.css
@@ -0,0 +1,17 @@
+#id, #name, #hspace, #vspace, #class_name, #align { width: 100px }
+#hspace, #vspace { width: 50px }
+#flash_quality, #flash_align, #flash_scale, #flash_salign, #flash_wmode { width: 100px }
+#flash_base, #flash_flashvars, #html5_altsource1, #html5_altsource2, #html5_poster { width: 240px }
+#width, #height { width: 40px }
+#src, #media_type { width: 250px }
+#class { width: 120px }
+#prev { margin: 0; border: 1px solid black; width: 380px; height: 260px; overflow: auto }
+.panel_wrapper div.current { height: 420px; overflow: auto }
+#flash_options, #shockwave_options, #qt_options, #wmp_options, #rmp_options { display: none }
+.mceAddSelectValue { background-color: #DDDDDD }
+#qt_starttime, #qt_endtime, #qt_fov, #qt_href, #qt_moveid, #qt_moviename, #qt_node, #qt_pan, #qt_qtsrc, #qt_qtsrcchokespeed, #qt_target, #qt_tilt, #qt_urlsubstituten, #qt_volume { width: 70px }
+#wmp_balance, #wmp_baseurl, #wmp_captioningid, #wmp_currentmarker, #wmp_currentposition, #wmp_defaultframe, #wmp_playcount, #wmp_rate, #wmp_uimode, #wmp_volume { width: 70px }
+#rmp_console, #rmp_numloop, #rmp_controls, #rmp_scriptcallbacks { width: 70px }
+#shockwave_swvolume, #shockwave_swframe, #shockwave_swurl, #shockwave_swstretchvalign, #shockwave_swstretchhalign, #shockwave_swstretchstyle { width: 90px }
+#qt_qtsrc { width: 200px }
+iframe {border: 1px solid gray}
diff --git a/src/wp-includes/js/tinymce/plugins/media/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/media/editor_plugin.js
new file mode 100644
index 0000000000..9ac42e0d21
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var b=tinymce.explode("id,name,width,height,style,align,class,hspace,vspace,bgcolor,type"),a=tinymce.makeMap(b.join(",")),f=tinymce.html.Node,d,i,h=tinymce.util.JSON,g;d=[["Flash","d27cdb6e-ae6d-11cf-96b8-444553540000","application/x-shockwave-flash","http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],["ShockWave","166b1bca-3f9c-11cf-8075-444553540000","application/x-director","http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"],["WindowsMedia","6bf52a52-394a-11d3-b153-00c04f79faa6,22d6f312-b0f6-11d0-94ab-0080c74c7e95,05589fa1-c356-11ce-bf01-00aa0055595a","application/x-mplayer2","http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"],["QuickTime","02bf25d5-8c17-4b23-bc80-d3488abddc6b","video/quicktime","http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"],["RealMedia","cfcdaa03-8be4-11cf-b84b-0020afbbccfa","audio/x-pn-realaudio-plugin","http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],["Java","8ad9c840-044e-11d1-b3e9-00805f499d93","application/x-java-applet","http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"],["Silverlight","dfeaf541-f3e1-4c24-acac-99c30715084a","application/x-silverlight-2"],["Iframe"],["Video"],["EmbeddedAudio"],["Audio"]];function e(j){return typeof(j)=="string"?j.replace(/[^0-9%]/g,""):j}function c(m){var l,j,k;if(m&&!m.splice){j=[];for(k=0;true;k++){if(m[k]){j[k]=m[k]}else{break}}return j}return m}tinymce.create("tinymce.plugins.MediaPlugin",{init:function(n,j){var r=this,l={},m,p,q,k;function o(s){return s&&s.nodeName==="IMG"&&n.dom.hasClass(s,"mceItemMedia")}r.editor=n;r.url=j;i="";for(m=0;m<d.length;m++){k=d[m][0];q={name:k,clsids:tinymce.explode(d[m][1]||""),mimes:tinymce.explode(d[m][2]||""),codebase:d[m][3]};for(p=0;p<q.clsids.length;p++){l["clsid:"+q.clsids[p]]=q}for(p=0;p<q.mimes.length;p++){l[q.mimes[p]]=q}l["mceItem"+k]=q;l[k.toLowerCase()]=q;i+=(i?"|":"")+k}tinymce.each(n.getParam("media_types","video=mp4,m4v,ogv,webm;silverlight=xap;flash=swf,flv;shockwave=dcr;quicktime=mov,qt,mpg,mpeg;shockwave=dcr;windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;realmedia=rm,ra,ram;java=jar;audio=mp3,ogg").split(";"),function(v){var s,u,t;v=v.split(/=/);u=tinymce.explode(v[1].toLowerCase());for(s=0;s<u.length;s++){t=l[v[0].toLowerCase()];if(t){l[u[s]]=t}}});i=new RegExp("write("+i+")\\(([^)]+)\\)");r.lookup=l;n.onPreInit.add(function(){n.schema.addValidElements("object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]");n.parser.addNodeFilter("object,embed,video,audio,script,iframe",function(s){var t=s.length;while(t--){r.objectToImg(s[t])}});n.serializer.addNodeFilter("img",function(s,u,t){var v=s.length,w;while(v--){w=s[v];if((w.attr("class")||"").indexOf("mceItemMedia")!==-1){r.imgToObject(w,t)}}})});n.onInit.add(function(){if(n.theme&&n.theme.onResolveName){n.theme.onResolveName.add(function(s,t){if(t.name==="img"&&n.dom.hasClass(t.node,"mceItemMedia")){t.name="media"}})}if(n&&n.plugins.contextmenu){n.plugins.contextmenu.onContextMenu.add(function(t,u,s){if(s.nodeName==="IMG"&&s.className.indexOf("mceItemMedia")!==-1){u.add({title:"media.edit",icon:"media",cmd:"mceMedia"})}})}});n.addCommand("mceMedia",function(){var t,s;s=n.selection.getNode();if(o(s)){t=n.dom.getAttrib(s,"data-mce-json");if(t){t=h.parse(t);tinymce.each(b,function(u){var v=n.dom.getAttrib(s,u);if(v){t[u]=v}});t.type=r.getType(s.className).name.toLowerCase()}}if(!t){t={type:"flash",video:{sources:[]},params:{}}}n.windowManager.open({file:j+"/media.htm",width:430+parseInt(n.getLang("media.delta_width",0)),height:500+parseInt(n.getLang("media.delta_height",0)),inline:1},{plugin_url:j,data:t})});n.addButton("media",{title:"media.desc",cmd:"mceMedia"});n.onNodeChange.add(function(t,s,u){s.setActive("media",o(u))})},convertUrl:function(l,o){var k=this,n=k.editor,m=n.settings,p=m.url_converter,j=m.url_converter_scope||k;if(!l){return l}if(o){return n.documentBaseURI.toAbsolute(l)}return p.call(j,l,"src","object")},getInfo:function(){return{longname:"Media",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media",version:tinymce.majorVersion+"."+tinymce.minorVersion}},dataToImg:function(m,k){var r=this,o=r.editor,p=o.documentBaseURI,j,q,n,l;m.params.src=r.convertUrl(m.params.src,k);q=m.video.attrs;if(q){q.src=r.convertUrl(q.src,k)}if(q){q.poster=r.convertUrl(q.poster,k)}j=c(m.video.sources);if(j){for(l=0;l<j.length;l++){j[l].src=r.convertUrl(j[l].src,k)}}n=r.editor.dom.create("img",{id:m.id,style:m.style,align:m.align,hspace:m.hspace,vspace:m.vspace,src:r.editor.theme.url+"/img/trans.gif","class":"mceItemMedia mceItem"+r.getType(m.type).name,"data-mce-json":h.serialize(m,"'")});n.width=m.width=e(m.width||(m.type=="audio"?"300":"320"));n.height=m.height=e(m.height||(m.type=="audio"?"32":"240"));return n},dataToHtml:function(j,k){return this.editor.serializer.serialize(this.dataToImg(j,k),{forced_root_block:"",force_absolute:k})},htmlToData:function(l){var k,j,m;m={type:"flash",video:{sources:[]},params:{}};k=this.editor.parser.parse(l);j=k.getAll("img")[0];if(j){m=h.parse(j.attr("data-mce-json"));m.type=this.getType(j.attr("class")).name.toLowerCase();tinymce.each(b,function(n){var o=j.attr(n);if(o){m[n]=o}})}return m},getType:function(m){var k,j,l;j=tinymce.explode(m," ");for(k=0;k<j.length;k++){l=this.lookup[j[k]];if(l){return l}}},imgToObject:function(z,o){var u=this,p=u.editor,C,H,j,t,I,y,G,w,k,E,s,q,A,D,m,x,l,B,F;function r(n,J){var N,M,O,L,K;K=p.getParam("flash_video_player_url",u.convertUrl(u.url+"/moxieplayer.swf"));if(K){N=p.documentBaseURI;G.params.src=K;if(p.getParam("flash_video_player_absvideourl",true)){n=N.toAbsolute(n||"",true);J=N.toAbsolute(J||"",true)}O="";M=p.getParam("flash_video_player_flashvars",{url:"$url",poster:"$poster"});tinymce.each(M,function(Q,P){Q=Q.replace(/\$url/,n||"");Q=Q.replace(/\$poster/,J||"");if(Q.length>0){O+=(O?"&":"")+P+"="+escape(Q)}});if(O.length){G.params.flashvars=O}L=p.getParam("flash_video_player_params",{allowfullscreen:true,allowscriptaccess:true});tinymce.each(L,function(Q,P){G.params[P]=""+Q})}}G=z.attr("data-mce-json");if(!G){return}G=h.parse(G);q=this.getType(z.attr("class"));B=z.attr("data-mce-style");if(!B){B=z.attr("style");if(B){B=p.dom.serializeStyle(p.dom.parseStyle(B,"img"))}}G.width=z.attr("width")||G.width;G.height=z.attr("height")||G.height;if(q.name==="Iframe"){x=new f("iframe",1);tinymce.each(b,function(n){var J=z.attr(n);if(n=="class"&&J){J=J.replace(/mceItem.+ ?/g,"")}if(J&&J.length>0){x.attr(n,J)}});for(I in G.params){x.attr(I,G.params[I])}x.attr({style:B,src:G.params.src});z.replace(x);return}if(this.editor.settings.media_use_script){x=new f("script",1).attr("type","text/javascript");y=new f("#text",3);y.value="write"+q.name+"("+h.serialize(tinymce.extend(G.params,{width:z.attr("width"),height:z.attr("height")}))+");";x.append(y);z.replace(x);return}if(q.name==="Video"&&G.video.sources[0]){C=new f("video",1).attr(tinymce.extend({id:z.attr("id"),width:e(z.attr("width")),height:e(z.attr("height")),style:B},G.video.attrs));if(G.video.attrs){l=G.video.attrs.poster}k=G.video.sources=c(G.video.sources);for(A=0;A<k.length;A++){if(/\.mp4$/.test(k[A].src)){m=k[A].src}}if(!k[0].type){C.attr("src",k[0].src);k.splice(0,1)}for(A=0;A<k.length;A++){w=new f("source",1).attr(k[A]);w.shortEnded=true;C.append(w)}if(m){r(m,l);q=u.getType("flash")}else{G.params.src=""}}if(q.name==="Audio"&&G.video.sources[0]){F=new f("audio",1).attr(tinymce.extend({id:z.attr("id"),width:e(z.attr("width")),height:e(z.attr("height")),style:B},G.video.attrs));if(G.video.attrs){l=G.video.attrs.poster}k=G.video.sources=c(G.video.sources);if(!k[0].type){F.attr("src",k[0].src);k.splice(0,1)}for(A=0;A<k.length;A++){w=new f("source",1).attr(k[A]);w.shortEnded=true;F.append(w)}G.params.src=""}if(q.name==="EmbeddedAudio"){j=new f("embed",1);j.shortEnded=true;j.attr({id:z.attr("id"),width:e(z.attr("width")),height:e(z.attr("height")),style:B,type:z.attr("type")});for(I in G.params){j.attr(I,G.params[I])}tinymce.each(b,function(n){if(G[n]&&n!="type"){j.attr(n,G[n])}});G.params.src=""}if(G.params.src){if(/\.flv$/i.test(G.params.src)){r(G.params.src,"")}if(o&&o.force_absolute){G.params.src=p.documentBaseURI.toAbsolute(G.params.src)}H=new f("object",1).attr({id:z.attr("id"),width:e(z.attr("width")),height:e(z.attr("height")),style:B});tinymce.each(b,function(n){var J=G[n];if(n=="class"&&J){J=J.replace(/mceItem.+ ?/g,"")}if(J&&n!="type"){H.attr(n,J)}});for(I in G.params){s=new f("param",1);s.shortEnded=true;y=G.params[I];if(I==="src"&&q.name==="WindowsMedia"){I="url"}s.attr({name:I,value:y});H.append(s)}if(this.editor.getParam("media_strict",true)){H.attr({data:G.params.src,type:q.mimes[0]})}else{H.attr({classid:"clsid:"+q.clsids[0],codebase:q.codebase});j=new f("embed",1);j.shortEnded=true;j.attr({id:z.attr("id"),width:e(z.attr("width")),height:e(z.attr("height")),style:B,type:q.mimes[0]});for(I in G.params){j.attr(I,G.params[I])}tinymce.each(b,function(n){if(G[n]&&n!="type"){j.attr(n,G[n])}});H.append(j)}if(G.object_html){y=new f("#text",3);y.raw=true;y.value=G.object_html;H.append(y)}if(C){C.append(H)}}if(C){if(G.video_html){y=new f("#text",3);y.raw=true;y.value=G.video_html;C.append(y)}}if(F){if(G.video_html){y=new f("#text",3);y.raw=true;y.value=G.video_html;F.append(y)}}var v=C||F||H||j;if(v){z.replace(v)}else{z.remove()}},objectToImg:function(C){var L,k,F,s,M,N,y,A,x,G,E,t,q,I,B,l,K,o,H=this.lookup,m,z,v=this.editor.settings.url_converter,n=this.editor.settings.url_converter_scope,w,r,D,j;function u(O){return new tinymce.html.Serializer({inner:true,validate:false}).serialize(O)}function J(P,O){return H[(P.attr(O)||"").toLowerCase()]}function p(P){var O=P.replace(/^.*\.([^.]+)$/,"$1");return H[O.toLowerCase()||""]}if(!C.parent){return}if(C.name==="script"){if(C.firstChild){m=i.exec(C.firstChild.value)}if(!m){return}o=m[1];K={video:{},params:h.parse(m[2])};A=K.params.width;x=K.params.height}K=K||{video:{},params:{}};M=new f("img",1);M.attr({src:this.editor.theme.url+"/img/trans.gif"});N=C.name;if(N==="video"||N=="audio"){F=C;L=C.getAll("object")[0];k=C.getAll("embed")[0];A=F.attr("width");x=F.attr("height");y=F.attr("id");K.video={attrs:{},sources:[]};z=K.video.attrs;for(N in F.attributes.map){z[N]=F.attributes.map[N]}B=C.attr("src");if(B){K.video.sources.push({src:v.call(n,B,"src",C.name)})}l=F.getAll("source");for(E=0;E<l.length;E++){B=l[E].remove();K.video.sources.push({src:v.call(n,B.attr("src"),"src","source"),type:B.attr("type"),media:B.attr("media")})}if(z.poster){z.poster=v.call(n,z.poster,"poster",C.name)}}if(C.name==="object"){L=C;k=C.getAll("embed")[0]}if(C.name==="embed"){k=C}if(C.name==="iframe"){s=C;o="Iframe"}if(L){A=A||L.attr("width");x=x||L.attr("height");G=G||L.attr("style");y=y||L.attr("id");w=w||L.attr("hspace");r=r||L.attr("vspace");D=D||L.attr("align");j=j||L.attr("bgcolor");K.name=L.attr("name");I=L.getAll("param");for(E=0;E<I.length;E++){q=I[E];N=q.remove().attr("name");if(!a[N]){K.params[N]=q.attr("value")}}K.params.src=K.params.src||L.attr("data")}if(k){A=A||k.attr("width");x=x||k.attr("height");G=G||k.attr("style");y=y||k.attr("id");w=w||k.attr("hspace");r=r||k.attr("vspace");D=D||k.attr("align");j=j||k.attr("bgcolor");for(N in k.attributes.map){if(!a[N]&&!K.params[N]){K.params[N]=k.attributes.map[N]}}}if(s){A=e(s.attr("width"));x=e(s.attr("height"));G=G||s.attr("style");y=s.attr("id");w=s.attr("hspace");r=s.attr("vspace");D=s.attr("align");j=s.attr("bgcolor");tinymce.each(b,function(O){M.attr(O,s.attr(O))});for(N in s.attributes.map){if(!a[N]&&!K.params[N]){K.params[N]=s.attributes.map[N]}}}if(K.params.movie){K.params.src=K.params.src||K.params.movie;delete K.params.movie}if(K.params.src){K.params.src=v.call(n,K.params.src,"src","object")}if(F){if(C.name==="video"){o=H.video.name}else{if(C.name==="audio"){o=H.audio.name}}}if(L&&!o){o=(J(L,"clsid")||J(L,"classid")||J(L,"type")||{}).name}if(k&&!o){o=(J(k,"type")||p(K.params.src)||{}).name}if(k&&o=="EmbeddedAudio"){K.params.type=k.attr("type")}C.replace(M);if(k){k.remove()}if(L){t=u(L.remove());if(t){K.object_html=t}}if(F){t=u(F.remove());if(t){K.video_html=t}}K.hspace=w;K.vspace=r;K.align=D;K.bgcolor=j;M.attr({id:y,"class":"mceItemMedia mceItem"+(o||"Flash"),style:G,width:A||(C.name=="audio"?"300":"320"),height:x||(C.name=="audio"?"32":"240"),hspace:w,vspace:r,align:D,bgcolor:j,"data-mce-json":h.serialize(K,"'")})}});tinymce.PluginManager.add("media",tinymce.plugins.MediaPlugin)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/media/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/media/editor_plugin_src.js
new file mode 100644
index 0000000000..517ef48604
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/editor_plugin_src.js
@@ -0,0 +1,897 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var rootAttributes = tinymce.explode('id,name,width,height,style,align,class,hspace,vspace,bgcolor,type'), excludedAttrs = tinymce.makeMap(rootAttributes.join(',')), Node = tinymce.html.Node,
+ mediaTypes, scriptRegExp, JSON = tinymce.util.JSON, mimeTypes;
+
+ // Media types supported by this plugin
+ mediaTypes = [
+ // Type, clsid:s, mime types, codebase
+ ["Flash", "d27cdb6e-ae6d-11cf-96b8-444553540000", "application/x-shockwave-flash", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],
+ ["ShockWave", "166b1bca-3f9c-11cf-8075-444553540000", "application/x-director", "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"],
+ ["WindowsMedia", "6bf52a52-394a-11d3-b153-00c04f79faa6,22d6f312-b0f6-11d0-94ab-0080c74c7e95,05589fa1-c356-11ce-bf01-00aa0055595a", "application/x-mplayer2", "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"],
+ ["QuickTime", "02bf25d5-8c17-4b23-bc80-d3488abddc6b", "video/quicktime", "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"],
+ ["RealMedia", "cfcdaa03-8be4-11cf-b84b-0020afbbccfa", "audio/x-pn-realaudio-plugin", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],
+ ["Java", "8ad9c840-044e-11d1-b3e9-00805f499d93", "application/x-java-applet", "http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"],
+ ["Silverlight", "dfeaf541-f3e1-4c24-acac-99c30715084a", "application/x-silverlight-2"],
+ ["Iframe"],
+ ["Video"],
+ ["EmbeddedAudio"],
+ ["Audio"]
+ ];
+
+ function normalizeSize(size) {
+ return typeof(size) == "string" ? size.replace(/[^0-9%]/g, '') : size;
+ }
+
+ function toArray(obj) {
+ var undef, out, i;
+
+ if (obj && !obj.splice) {
+ out = [];
+
+ for (i = 0; true; i++) {
+ if (obj[i])
+ out[i] = obj[i];
+ else
+ break;
+ }
+
+ return out;
+ }
+
+ return obj;
+ };
+
+ tinymce.create('tinymce.plugins.MediaPlugin', {
+ init : function(ed, url) {
+ var self = this, lookup = {}, i, y, item, name;
+
+ function isMediaImg(node) {
+ return node && node.nodeName === 'IMG' && ed.dom.hasClass(node, 'mceItemMedia');
+ };
+
+ self.editor = ed;
+ self.url = url;
+
+ // Parse media types into a lookup table
+ scriptRegExp = '';
+ for (i = 0; i < mediaTypes.length; i++) {
+ name = mediaTypes[i][0];
+
+ item = {
+ name : name,
+ clsids : tinymce.explode(mediaTypes[i][1] || ''),
+ mimes : tinymce.explode(mediaTypes[i][2] || ''),
+ codebase : mediaTypes[i][3]
+ };
+
+ for (y = 0; y < item.clsids.length; y++)
+ lookup['clsid:' + item.clsids[y]] = item;
+
+ for (y = 0; y < item.mimes.length; y++)
+ lookup[item.mimes[y]] = item;
+
+ lookup['mceItem' + name] = item;
+ lookup[name.toLowerCase()] = item;
+
+ scriptRegExp += (scriptRegExp ? '|' : '') + name;
+ }
+
+ // Handle the media_types setting
+ tinymce.each(ed.getParam("media_types",
+ "video=mp4,m4v,ogv,webm;" +
+ "silverlight=xap;" +
+ "flash=swf,flv;" +
+ "shockwave=dcr;" +
+ "quicktime=mov,qt,mpg,mpeg;" +
+ "shockwave=dcr;" +
+ "windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;" +
+ "realmedia=rm,ra,ram;" +
+ "java=jar;" +
+ "audio=mp3,ogg"
+ ).split(';'), function(item) {
+ var i, extensions, type;
+
+ item = item.split(/=/);
+ extensions = tinymce.explode(item[1].toLowerCase());
+ for (i = 0; i < extensions.length; i++) {
+ type = lookup[item[0].toLowerCase()];
+
+ if (type)
+ lookup[extensions[i]] = type;
+ }
+ });
+
+ scriptRegExp = new RegExp('write(' + scriptRegExp + ')\\(([^)]+)\\)');
+ self.lookup = lookup;
+
+ ed.onPreInit.add(function() {
+ // Allow video elements
+ ed.schema.addValidElements('object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]');
+
+ // Convert video elements to image placeholder
+ ed.parser.addNodeFilter('object,embed,video,audio,script,iframe', function(nodes) {
+ var i = nodes.length;
+
+ while (i--)
+ self.objectToImg(nodes[i]);
+ });
+
+ // Convert image placeholders to video elements
+ ed.serializer.addNodeFilter('img', function(nodes, name, args) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ if ((node.attr('class') || '').indexOf('mceItemMedia') !== -1)
+ self.imgToObject(node, args);
+ }
+ });
+ });
+
+ ed.onInit.add(function() {
+ // Display "media" instead of "img" in element path
+ if (ed.theme && ed.theme.onResolveName) {
+ ed.theme.onResolveName.add(function(theme, path_object) {
+ if (path_object.name === 'img' && ed.dom.hasClass(path_object.node, 'mceItemMedia'))
+ path_object.name = 'media';
+ });
+ }
+
+ // Add contect menu if it's loaded
+ if (ed && ed.plugins.contextmenu) {
+ ed.plugins.contextmenu.onContextMenu.add(function(plugin, menu, element) {
+ if (element.nodeName === 'IMG' && element.className.indexOf('mceItemMedia') !== -1)
+ menu.add({title : 'media.edit', icon : 'media', cmd : 'mceMedia'});
+ });
+ }
+ });
+
+ // Register commands
+ ed.addCommand('mceMedia', function() {
+ var data, img;
+
+ img = ed.selection.getNode();
+ if (isMediaImg(img)) {
+ data = ed.dom.getAttrib(img, 'data-mce-json');
+ if (data) {
+ data = JSON.parse(data);
+
+ // Add some extra properties to the data object
+ tinymce.each(rootAttributes, function(name) {
+ var value = ed.dom.getAttrib(img, name);
+
+ if (value)
+ data[name] = value;
+ });
+
+ data.type = self.getType(img.className).name.toLowerCase();
+ }
+ }
+
+ if (!data) {
+ data = {
+ type : 'flash',
+ video: {sources:[]},
+ params: {}
+ };
+ }
+
+ ed.windowManager.open({
+ file : url + '/media.htm',
+ width : 430 + parseInt(ed.getLang('media.delta_width', 0)),
+ height : 500 + parseInt(ed.getLang('media.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url,
+ data : data
+ });
+ });
+
+ // Register buttons
+ ed.addButton('media', {title : 'media.desc', cmd : 'mceMedia'});
+
+ // Update media selection status
+ ed.onNodeChange.add(function(ed, cm, node) {
+ cm.setActive('media', isMediaImg(node));
+ });
+ },
+
+ convertUrl : function(url, force_absolute) {
+ var self = this, editor = self.editor, settings = editor.settings,
+ urlConverter = settings.url_converter,
+ urlConverterScope = settings.url_converter_scope || self;
+
+ if (!url)
+ return url;
+
+ if (force_absolute)
+ return editor.documentBaseURI.toAbsolute(url);
+
+ return urlConverter.call(urlConverterScope, url, 'src', 'object');
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Media',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ /**
+ * Converts the JSON data object to an img node.
+ */
+ dataToImg : function(data, force_absolute) {
+ var self = this, editor = self.editor, baseUri = editor.documentBaseURI, sources, attrs, img, i;
+
+ data.params.src = self.convertUrl(data.params.src, force_absolute);
+
+ attrs = data.video.attrs;
+ if (attrs)
+ attrs.src = self.convertUrl(attrs.src, force_absolute);
+
+ if (attrs)
+ attrs.poster = self.convertUrl(attrs.poster, force_absolute);
+
+ sources = toArray(data.video.sources);
+ if (sources) {
+ for (i = 0; i < sources.length; i++)
+ sources[i].src = self.convertUrl(sources[i].src, force_absolute);
+ }
+
+ img = self.editor.dom.create('img', {
+ id : data.id,
+ style : data.style,
+ align : data.align,
+ hspace : data.hspace,
+ vspace : data.vspace,
+ src : self.editor.theme.url + '/img/trans.gif',
+ 'class' : 'mceItemMedia mceItem' + self.getType(data.type).name,
+ 'data-mce-json' : JSON.serialize(data, "'")
+ });
+
+ img.width = data.width = normalizeSize(data.width || (data.type == 'audio' ? "300" : "320"));
+ img.height = data.height = normalizeSize(data.height || (data.type == 'audio' ? "32" : "240"));
+
+ return img;
+ },
+
+ /**
+ * Converts the JSON data object to a HTML string.
+ */
+ dataToHtml : function(data, force_absolute) {
+ return this.editor.serializer.serialize(this.dataToImg(data, force_absolute), {forced_root_block : '', force_absolute : force_absolute});
+ },
+
+ /**
+ * Converts the JSON data object to a HTML string.
+ */
+ htmlToData : function(html) {
+ var fragment, img, data;
+
+ data = {
+ type : 'flash',
+ video: {sources:[]},
+ params: {}
+ };
+
+ fragment = this.editor.parser.parse(html);
+ img = fragment.getAll('img')[0];
+
+ if (img) {
+ data = JSON.parse(img.attr('data-mce-json'));
+ data.type = this.getType(img.attr('class')).name.toLowerCase();
+
+ // Add some extra properties to the data object
+ tinymce.each(rootAttributes, function(name) {
+ var value = img.attr(name);
+
+ if (value)
+ data[name] = value;
+ });
+ }
+
+ return data;
+ },
+
+ /**
+ * Get type item by extension, class, clsid or mime type.
+ *
+ * @method getType
+ * @param {String} value Value to get type item by.
+ * @return {Object} Type item object or undefined.
+ */
+ getType : function(value) {
+ var i, values, typeItem;
+
+ // Find type by checking the classes
+ values = tinymce.explode(value, ' ');
+ for (i = 0; i < values.length; i++) {
+ typeItem = this.lookup[values[i]];
+
+ if (typeItem)
+ return typeItem;
+ }
+ },
+
+ /**
+ * Converts a tinymce.html.Node image element to video/object/embed.
+ */
+ imgToObject : function(node, args) {
+ var self = this, editor = self.editor, video, object, embed, iframe, name, value, data,
+ source, sources, params, param, typeItem, i, item, mp4Source, replacement,
+ posterSrc, style, audio;
+
+ // Adds the flash player
+ function addPlayer(video_src, poster_src) {
+ var baseUri, flashVars, flashVarsOutput, params, flashPlayer;
+
+ flashPlayer = editor.getParam('flash_video_player_url', self.convertUrl(self.url + '/moxieplayer.swf'));
+ if (flashPlayer) {
+ baseUri = editor.documentBaseURI;
+ data.params.src = flashPlayer;
+
+ // Convert the movie url to absolute urls
+ if (editor.getParam('flash_video_player_absvideourl', true)) {
+ video_src = baseUri.toAbsolute(video_src || '', true);
+ poster_src = baseUri.toAbsolute(poster_src || '', true);
+ }
+
+ // Generate flash vars
+ flashVarsOutput = '';
+ flashVars = editor.getParam('flash_video_player_flashvars', {url : '$url', poster : '$poster'});
+ tinymce.each(flashVars, function(value, name) {
+ // Replace $url and $poster variables in flashvars value
+ value = value.replace(/\$url/, video_src || '');
+ value = value.replace(/\$poster/, poster_src || '');
+
+ if (value.length > 0)
+ flashVarsOutput += (flashVarsOutput ? '&' : '') + name + '=' + escape(value);
+ });
+
+ if (flashVarsOutput.length)
+ data.params.flashvars = flashVarsOutput;
+
+ params = editor.getParam('flash_video_player_params', {
+ allowfullscreen: true,
+ allowscriptaccess: true
+ });
+
+ tinymce.each(params, function(value, name) {
+ data.params[name] = "" + value;
+ });
+ }
+ };
+
+ data = node.attr('data-mce-json');
+ if (!data)
+ return;
+
+ data = JSON.parse(data);
+ typeItem = this.getType(node.attr('class'));
+
+ style = node.attr('data-mce-style');
+ if (!style) {
+ style = node.attr('style');
+
+ if (style)
+ style = editor.dom.serializeStyle(editor.dom.parseStyle(style, 'img'));
+ }
+
+ // Use node width/height to override the data width/height when the placeholder is resized
+ data.width = node.attr('width') || data.width;
+ data.height = node.attr('height') || data.height;
+
+ // Handle iframe
+ if (typeItem.name === 'Iframe') {
+ replacement = new Node('iframe', 1);
+
+ tinymce.each(rootAttributes, function(name) {
+ var value = node.attr(name);
+
+ if (name == 'class' && value)
+ value = value.replace(/mceItem.+ ?/g, '');
+
+ if (value && value.length > 0)
+ replacement.attr(name, value);
+ });
+
+ for (name in data.params)
+ replacement.attr(name, data.params[name]);
+
+ replacement.attr({
+ style: style,
+ src: data.params.src
+ });
+
+ node.replace(replacement);
+
+ return;
+ }
+
+ // Handle scripts
+ if (this.editor.settings.media_use_script) {
+ replacement = new Node('script', 1).attr('type', 'text/javascript');
+
+ value = new Node('#text', 3);
+ value.value = 'write' + typeItem.name + '(' + JSON.serialize(tinymce.extend(data.params, {
+ width: node.attr('width'),
+ height: node.attr('height')
+ })) + ');';
+
+ replacement.append(value);
+ node.replace(replacement);
+
+ return;
+ }
+
+ // Add HTML5 video element
+ if (typeItem.name === 'Video' && data.video.sources && data.video.sources[0]) {
+ // Create new object element
+ video = new Node('video', 1).attr(tinymce.extend({
+ id : node.attr('id'),
+ width: normalizeSize(node.attr('width')),
+ height: normalizeSize(node.attr('height')),
+ style : style
+ }, data.video.attrs));
+
+ // Get poster source and use that for flash fallback
+ if (data.video.attrs)
+ posterSrc = data.video.attrs.poster;
+
+ sources = data.video.sources = toArray(data.video.sources);
+ for (i = 0; i < sources.length; i++) {
+ if (/\.mp4$/.test(sources[i].src))
+ mp4Source = sources[i].src;
+ }
+
+ if (!sources[0].type) {
+ video.attr('src', sources[0].src);
+ sources.splice(0, 1);
+ }
+
+ for (i = 0; i < sources.length; i++) {
+ source = new Node('source', 1).attr(sources[i]);
+ source.shortEnded = true;
+ video.append(source);
+ }
+
+ // Create flash fallback for video if we have a mp4 source
+ if (mp4Source) {
+ addPlayer(mp4Source, posterSrc);
+ typeItem = self.getType('flash');
+ } else
+ data.params.src = '';
+ }
+
+ // Add HTML5 audio element
+ if (typeItem.name === 'Audio' && data.video.sources && data.video.sources[0]) {
+ // Create new object element
+ audio = new Node('audio', 1).attr(tinymce.extend({
+ id : node.attr('id'),
+ width: normalizeSize(node.attr('width')),
+ height: normalizeSize(node.attr('height')),
+ style : style
+ }, data.video.attrs));
+
+ // Get poster source and use that for flash fallback
+ if (data.video.attrs)
+ posterSrc = data.video.attrs.poster;
+
+ sources = data.video.sources = toArray(data.video.sources);
+ if (!sources[0].type) {
+ audio.attr('src', sources[0].src);
+ sources.splice(0, 1);
+ }
+
+ for (i = 0; i < sources.length; i++) {
+ source = new Node('source', 1).attr(sources[i]);
+ source.shortEnded = true;
+ audio.append(source);
+ }
+
+ data.params.src = '';
+ }
+
+ if (typeItem.name === 'EmbeddedAudio') {
+ embed = new Node('embed', 1);
+ embed.shortEnded = true;
+ embed.attr({
+ id: node.attr('id'),
+ width: normalizeSize(node.attr('width')),
+ height: normalizeSize(node.attr('height')),
+ style : style,
+ type: node.attr('type')
+ });
+
+ for (name in data.params)
+ embed.attr(name, data.params[name]);
+
+ tinymce.each(rootAttributes, function(name) {
+ if (data[name] && name != 'type')
+ embed.attr(name, data[name]);
+ });
+
+ data.params.src = '';
+ }
+
+ // Do we have a params src then we can generate object
+ if (data.params.src) {
+ // Is flv movie add player for it
+ if (/\.flv$/i.test(data.params.src))
+ addPlayer(data.params.src, '');
+
+ if (args && args.force_absolute)
+ data.params.src = editor.documentBaseURI.toAbsolute(data.params.src);
+
+ // Create new object element
+ object = new Node('object', 1).attr({
+ id : node.attr('id'),
+ width: normalizeSize(node.attr('width')),
+ height: normalizeSize(node.attr('height')),
+ style : style
+ });
+
+ tinymce.each(rootAttributes, function(name) {
+ var value = data[name];
+
+ if (name == 'class' && value)
+ value = value.replace(/mceItem.+ ?/g, '');
+
+ if (value && name != 'type')
+ object.attr(name, value);
+ });
+
+ // Add params
+ for (name in data.params) {
+ param = new Node('param', 1);
+ param.shortEnded = true;
+ value = data.params[name];
+
+ // Windows media needs to use url instead of src for the media URL
+ if (name === 'src' && typeItem.name === 'WindowsMedia')
+ name = 'url';
+
+ param.attr({name: name, value: value});
+ object.append(param);
+ }
+
+ // Setup add type and classid if strict is disabled
+ if (this.editor.getParam('media_strict', true)) {
+ object.attr({
+ data: data.params.src,
+ type: typeItem.mimes[0]
+ });
+ } else {
+ if ( typeItem.clsids )
+ object.attr('clsid', typeItem.clsids[0]);
+ object.attr('codebase', typeItem.codebase);
+
+ embed = new Node('embed', 1);
+ embed.shortEnded = true;
+ embed.attr({
+ id: node.attr('id'),
+ width: normalizeSize(node.attr('width')),
+ height: normalizeSize(node.attr('height')),
+ style : style,
+ type: typeItem.mimes[0]
+ });
+
+ for (name in data.params)
+ embed.attr(name, data.params[name]);
+
+ tinymce.each(rootAttributes, function(name) {
+ if (data[name] && name != 'type')
+ embed.attr(name, data[name]);
+ });
+
+ object.append(embed);
+ }
+
+ // Insert raw HTML
+ if (data.object_html) {
+ value = new Node('#text', 3);
+ value.raw = true;
+ value.value = data.object_html;
+ object.append(value);
+ }
+
+ // Append object to video element if it exists
+ if (video)
+ video.append(object);
+ }
+
+ if (video) {
+ // Insert raw HTML
+ if (data.video_html) {
+ value = new Node('#text', 3);
+ value.raw = true;
+ value.value = data.video_html;
+ video.append(value);
+ }
+ }
+
+ if (audio) {
+ // Insert raw HTML
+ if (data.video_html) {
+ value = new Node('#text', 3);
+ value.raw = true;
+ value.value = data.video_html;
+ audio.append(value);
+ }
+ }
+
+ var n = video || audio || object || embed;
+ if (n)
+ node.replace(n);
+ else
+ node.remove();
+ },
+
+ /**
+ * Converts a tinymce.html.Node video/object/embed to an img element.
+ *
+ * The video/object/embed will be converted into an image placeholder with a JSON data attribute like this:
+ * <img class="mceItemMedia mceItemFlash" width="100" height="100" data-mce-json="{..}" />
+ *
+ * The JSON structure will be like this:
+ * {'params':{'flashvars':'something','quality':'high','src':'someurl'}, 'video':{'sources':[{src: 'someurl', type: 'video/mp4'}]}}
+ */
+ objectToImg : function(node) {
+ var object, embed, video, iframe, img, name, id, width, height, style, i, html,
+ param, params, source, sources, data, type, lookup = this.lookup,
+ matches, attrs, urlConverter = this.editor.settings.url_converter,
+ urlConverterScope = this.editor.settings.url_converter_scope,
+ hspace, vspace, align, bgcolor;
+
+ function getInnerHTML(node) {
+ return new tinymce.html.Serializer({
+ inner: true,
+ validate: false
+ }).serialize(node);
+ };
+
+ function lookupAttribute(o, attr) {
+ return lookup[(o.attr(attr) || '').toLowerCase()];
+ }
+
+ function lookupExtension(src) {
+ var ext = src.replace(/^.*\.([^.]+)$/, '$1');
+ return lookup[ext.toLowerCase() || ''];
+ }
+
+ // If node isn't in document
+ if (!node.parent)
+ return;
+
+ // Handle media scripts
+ if (node.name === 'script') {
+ if (node.firstChild)
+ matches = scriptRegExp.exec(node.firstChild.value);
+
+ if (!matches)
+ return;
+
+ type = matches[1];
+ data = {video : {}, params : JSON.parse(matches[2])};
+ width = data.params.width;
+ height = data.params.height;
+ }
+
+ // Setup data objects
+ data = data || {
+ video : {},
+ params : {}
+ };
+
+ // Setup new image object
+ img = new Node('img', 1);
+ img.attr({
+ src : this.editor.theme.url + '/img/trans.gif'
+ });
+
+ // Video element
+ name = node.name;
+ if (name === 'video' || name == 'audio') {
+ video = node;
+ object = node.getAll('object')[0];
+ embed = node.getAll('embed')[0];
+ width = video.attr('width');
+ height = video.attr('height');
+ id = video.attr('id');
+ data.video = {attrs : {}, sources : []};
+
+ // Get all video attributes
+ attrs = data.video.attrs;
+ for (name in video.attributes.map)
+ attrs[name] = video.attributes.map[name];
+
+ source = node.attr('src');
+ if (source)
+ data.video.sources.push({src : urlConverter.call(urlConverterScope, source, 'src', node.name)});
+
+ // Get all sources
+ sources = video.getAll("source");
+ for (i = 0; i < sources.length; i++) {
+ source = sources[i].remove();
+
+ data.video.sources.push({
+ src: urlConverter.call(urlConverterScope, source.attr('src'), 'src', 'source'),
+ type: source.attr('type'),
+ media: source.attr('media')
+ });
+ }
+
+ // Convert the poster URL
+ if (attrs.poster)
+ attrs.poster = urlConverter.call(urlConverterScope, attrs.poster, 'poster', node.name);
+ }
+
+ // Object element
+ if (node.name === 'object') {
+ object = node;
+ embed = node.getAll('embed')[0];
+ }
+
+ // Embed element
+ if (node.name === 'embed')
+ embed = node;
+
+ // Iframe element
+ if (node.name === 'iframe') {
+ iframe = node;
+ type = 'Iframe';
+ }
+
+ if (object) {
+ // Get width/height
+ width = width || object.attr('width');
+ height = height || object.attr('height');
+ style = style || object.attr('style');
+ id = id || object.attr('id');
+ hspace = hspace || object.attr('hspace');
+ vspace = vspace || object.attr('vspace');
+ align = align || object.attr('align');
+ bgcolor = bgcolor || object.attr('bgcolor');
+ data.name = object.attr('name');
+
+ // Get all object params
+ params = object.getAll("param");
+ for (i = 0; i < params.length; i++) {
+ param = params[i];
+ name = param.remove().attr('name');
+
+ if (!excludedAttrs[name])
+ data.params[name] = param.attr('value');
+ }
+
+ data.params.src = data.params.src || object.attr('data');
+ }
+
+ if (embed) {
+ // Get width/height
+ width = width || embed.attr('width');
+ height = height || embed.attr('height');
+ style = style || embed.attr('style');
+ id = id || embed.attr('id');
+ hspace = hspace || embed.attr('hspace');
+ vspace = vspace || embed.attr('vspace');
+ align = align || embed.attr('align');
+ bgcolor = bgcolor || embed.attr('bgcolor');
+
+ // Get all embed attributes
+ for (name in embed.attributes.map) {
+ if (!excludedAttrs[name] && !data.params[name])
+ data.params[name] = embed.attributes.map[name];
+ }
+ }
+
+ if (iframe) {
+ // Get width/height
+ width = normalizeSize(iframe.attr('width'));
+ height = normalizeSize(iframe.attr('height'));
+ style = style || iframe.attr('style');
+ id = iframe.attr('id');
+ hspace = iframe.attr('hspace');
+ vspace = iframe.attr('vspace');
+ align = iframe.attr('align');
+ bgcolor = iframe.attr('bgcolor');
+
+ tinymce.each(rootAttributes, function(name) {
+ img.attr(name, iframe.attr(name));
+ });
+
+ // Get all iframe attributes
+ for (name in iframe.attributes.map) {
+ if (!excludedAttrs[name] && !data.params[name])
+ data.params[name] = iframe.attributes.map[name];
+ }
+ }
+
+ // Use src not movie
+ if (data.params.movie) {
+ data.params.src = data.params.src || data.params.movie;
+ delete data.params.movie;
+ }
+
+ // Convert the URL to relative/absolute depending on configuration
+ if (data.params.src)
+ data.params.src = urlConverter.call(urlConverterScope, data.params.src, 'src', 'object');
+
+ if (video) {
+ if (node.name === 'video')
+ type = lookup.video.name;
+ else if (node.name === 'audio')
+ type = lookup.audio.name;
+ }
+
+ if (object && !type)
+ type = (lookupAttribute(object, 'clsid') || lookupAttribute(object, 'classid') || lookupAttribute(object, 'type') || {}).name;
+
+ if (embed && !type)
+ type = (lookupAttribute(embed, 'type') || lookupExtension(data.params.src) || {}).name;
+
+ // for embedded audio we preserve the original specified type
+ if (embed && type == 'EmbeddedAudio') {
+ data.params.type = embed.attr('type');
+ }
+
+ // Replace the video/object/embed element with a placeholder image containing the data
+ node.replace(img);
+
+ // Remove embed
+ if (embed)
+ embed.remove();
+
+ // Serialize the inner HTML of the object element
+ if (object) {
+ html = getInnerHTML(object.remove());
+
+ if (html)
+ data.object_html = html;
+ }
+
+ // Serialize the inner HTML of the video element
+ if (video) {
+ html = getInnerHTML(video.remove());
+
+ if (html)
+ data.video_html = html;
+ }
+
+ data.hspace = hspace;
+ data.vspace = vspace;
+ data.align = align;
+ data.bgcolor = bgcolor;
+
+ // Set width/height of placeholder
+ img.attr({
+ id : id,
+ 'class' : 'mceItemMedia mceItem' + (type || 'Flash'),
+ style : style,
+ width : width || (node.name == 'audio' ? "300" : "320"),
+ height : height || (node.name == 'audio' ? "32" : "240"),
+ hspace : hspace,
+ vspace : vspace,
+ align : align,
+ bgcolor : bgcolor,
+ "data-mce-json" : JSON.serialize(data, "'")
+ });
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('media', tinymce.plugins.MediaPlugin);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/media/js/embed.js b/src/wp-includes/js/tinymce/plugins/media/js/embed.js
new file mode 100644
index 0000000000..6fe25de090
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/js/embed.js
@@ -0,0 +1,73 @@
+/**
+ * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose.
+ */
+
+function writeFlash(p) {
+ writeEmbed(
+ 'D27CDB6E-AE6D-11cf-96B8-444553540000',
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+ 'application/x-shockwave-flash',
+ p
+ );
+}
+
+function writeShockWave(p) {
+ writeEmbed(
+ '166B1BCA-3F9C-11CF-8075-444553540000',
+ 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0',
+ 'application/x-director',
+ p
+ );
+}
+
+function writeQuickTime(p) {
+ writeEmbed(
+ '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
+ 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
+ 'video/quicktime',
+ p
+ );
+}
+
+function writeRealMedia(p) {
+ writeEmbed(
+ 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA',
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+ 'audio/x-pn-realaudio-plugin',
+ p
+ );
+}
+
+function writeWindowsMedia(p) {
+ p.url = p.src;
+ writeEmbed(
+ '6BF52A52-394A-11D3-B153-00C04F79FAA6',
+ 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701',
+ 'application/x-mplayer2',
+ p
+ );
+}
+
+function writeEmbed(cls, cb, mt, p) {
+ var h = '', n;
+
+ h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+ h += typeof(p.id) != "undefined" ? 'id="' + p.id + '"' : '';
+ h += typeof(p.name) != "undefined" ? 'name="' + p.name + '"' : '';
+ h += typeof(p.width) != "undefined" ? 'width="' + p.width + '"' : '';
+ h += typeof(p.height) != "undefined" ? 'height="' + p.height + '"' : '';
+ h += typeof(p.align) != "undefined" ? 'align="' + p.align + '"' : '';
+ h += '>';
+
+ for (n in p)
+ h += '<param name="' + n + '" value="' + p[n] + '">';
+
+ h += '<embed type="' + mt + '"';
+
+ for (n in p)
+ h += n + '="' + p[n] + '" ';
+
+ h += '></embed></object>';
+
+ document.write(h);
+}
diff --git a/src/wp-includes/js/tinymce/plugins/media/js/media.js b/src/wp-includes/js/tinymce/plugins/media/js/media.js
new file mode 100644
index 0000000000..b21abb5f3c
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/js/media.js
@@ -0,0 +1,513 @@
+(function() {
+ var url;
+
+ if (url = tinyMCEPopup.getParam("media_external_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+
+ function get(id) {
+ return document.getElementById(id);
+ }
+
+ function clone(obj) {
+ var i, len, copy, attr;
+
+ if (null == obj || "object" != typeof obj)
+ return obj;
+
+ // Handle Array
+ if ('length' in obj) {
+ copy = [];
+
+ for (i = 0, len = obj.length; i < len; ++i) {
+ copy[i] = clone(obj[i]);
+ }
+
+ return copy;
+ }
+
+ // Handle Object
+ copy = {};
+ for (attr in obj) {
+ if (obj.hasOwnProperty(attr))
+ copy[attr] = clone(obj[attr]);
+ }
+
+ return copy;
+ }
+
+ function getVal(id) {
+ var elm = get(id);
+
+ if (elm.nodeName == "SELECT")
+ return elm.options[elm.selectedIndex].value;
+
+ if (elm.type == "checkbox")
+ return elm.checked;
+
+ return elm.value;
+ }
+
+ function setVal(id, value, name) {
+ if (typeof(value) != 'undefined' && value != null) {
+ var elm = get(id);
+
+ if (elm.nodeName == "SELECT")
+ selectByValue(document.forms[0], id, value);
+ else if (elm.type == "checkbox") {
+ if (typeof(value) == 'string') {
+ value = value.toLowerCase();
+ value = (!name && value === 'true') || (name && value === name.toLowerCase());
+ }
+ elm.checked = !!value;
+ } else
+ elm.value = value;
+ }
+ }
+
+ window.Media = {
+ init : function() {
+ var html, editor, self = this;
+
+ self.editor = editor = tinyMCEPopup.editor;
+
+ // Setup file browsers and color pickers
+ get('filebrowsercontainer').innerHTML = getBrowserHTML('filebrowser','src','media','media');
+ get('qtsrcfilebrowsercontainer').innerHTML = getBrowserHTML('qtsrcfilebrowser','quicktime_qtsrc','media','media');
+ get('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+ get('video_altsource1_filebrowser').innerHTML = getBrowserHTML('video_filebrowser_altsource1','video_altsource1','media','media');
+ get('video_altsource2_filebrowser').innerHTML = getBrowserHTML('video_filebrowser_altsource2','video_altsource2','media','media');
+ get('audio_altsource1_filebrowser').innerHTML = getBrowserHTML('audio_filebrowser_altsource1','audio_altsource1','media','media');
+ get('audio_altsource2_filebrowser').innerHTML = getBrowserHTML('audio_filebrowser_altsource2','audio_altsource2','media','media');
+ get('video_poster_filebrowser').innerHTML = getBrowserHTML('filebrowser_poster','video_poster','image','media');
+
+ html = self.getMediaListHTML('medialist', 'src', 'media', 'media');
+ if (html == "")
+ get("linklistrow").style.display = 'none';
+ else
+ get("linklistcontainer").innerHTML = html;
+
+ if (isVisible('filebrowser'))
+ get('src').style.width = '230px';
+
+ if (isVisible('video_filebrowser_altsource1'))
+ get('video_altsource1').style.width = '220px';
+
+ if (isVisible('video_filebrowser_altsource2'))
+ get('video_altsource2').style.width = '220px';
+
+ if (isVisible('audio_filebrowser_altsource1'))
+ get('audio_altsource1').style.width = '220px';
+
+ if (isVisible('audio_filebrowser_altsource2'))
+ get('audio_altsource2').style.width = '220px';
+
+ if (isVisible('filebrowser_poster'))
+ get('video_poster').style.width = '220px';
+
+ editor.dom.setOuterHTML(get('media_type'), self.getMediaTypeHTML(editor));
+
+ self.setDefaultDialogSettings(editor);
+ self.data = clone(tinyMCEPopup.getWindowArg('data'));
+ self.dataToForm();
+ self.preview();
+
+ updateColor('bgcolor_pick', 'bgcolor');
+ },
+
+ insert : function() {
+ var editor = tinyMCEPopup.editor;
+
+ this.formToData();
+ editor.execCommand('mceRepaint');
+ tinyMCEPopup.restoreSelection();
+ editor.selection.setNode(editor.plugins.media.dataToImg(this.data));
+ tinyMCEPopup.close();
+ },
+
+ preview : function() {
+ get('prev').innerHTML = this.editor.plugins.media.dataToHtml(this.data, true);
+ },
+
+ moveStates : function(to_form, field) {
+ var data = this.data, editor = this.editor,
+ mediaPlugin = editor.plugins.media, ext, src, typeInfo, defaultStates, src;
+
+ defaultStates = {
+ // QuickTime
+ quicktime_autoplay : true,
+ quicktime_controller : true,
+
+ // Flash
+ flash_play : true,
+ flash_loop : true,
+ flash_menu : true,
+
+ // WindowsMedia
+ windowsmedia_autostart : true,
+ windowsmedia_enablecontextmenu : true,
+ windowsmedia_invokeurls : true,
+
+ // RealMedia
+ realmedia_autogotourl : true,
+ realmedia_imagestatus : true
+ };
+
+ function parseQueryParams(str) {
+ var out = {};
+
+ if (str) {
+ tinymce.each(str.split('&'), function(item) {
+ var parts = item.split('=');
+
+ out[unescape(parts[0])] = unescape(parts[1]);
+ });
+ }
+
+ return out;
+ };
+
+ function setOptions(type, names) {
+ var i, name, formItemName, value, list;
+
+ if (type == data.type || type == 'global') {
+ names = tinymce.explode(names);
+ for (i = 0; i < names.length; i++) {
+ name = names[i];
+ formItemName = type == 'global' ? name : type + '_' + name;
+
+ if (type == 'global')
+ list = data;
+ else if (type == 'video' || type == 'audio') {
+ list = data.video.attrs;
+
+ if (!list && !to_form)
+ data.video.attrs = list = {};
+ } else
+ list = data.params;
+
+ if (list) {
+ if (to_form) {
+ setVal(formItemName, list[name], type == 'video' || type == 'audio' ? name : '');
+ } else {
+ delete list[name];
+
+ value = getVal(formItemName);
+ if ((type == 'video' || type == 'audio') && value === true)
+ value = name;
+
+ if (defaultStates[formItemName]) {
+ if (value !== defaultStates[formItemName]) {
+ value = "" + value;
+ list[name] = value;
+ }
+ } else if (value) {
+ value = "" + value;
+ list[name] = value;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!to_form) {
+ data.type = get('media_type').options[get('media_type').selectedIndex].value;
+ data.width = getVal('width');
+ data.height = getVal('height');
+
+ // Switch type based on extension
+ src = getVal('src');
+ if (field == 'src') {
+ ext = src.replace(/^.*\.([^.]+)$/, '$1');
+ if (typeInfo = mediaPlugin.getType(ext))
+ data.type = typeInfo.name.toLowerCase();
+
+ setVal('media_type', data.type);
+ }
+
+ if (data.type == "video" || data.type == "audio") {
+ if (!data.video.sources)
+ data.video.sources = [];
+
+ data.video.sources[0] = {src: getVal('src')};
+ }
+ }
+
+ // Hide all fieldsets and show the one active
+ get('video_options').style.display = 'none';
+ get('audio_options').style.display = 'none';
+ get('flash_options').style.display = 'none';
+ get('quicktime_options').style.display = 'none';
+ get('shockwave_options').style.display = 'none';
+ get('windowsmedia_options').style.display = 'none';
+ get('realmedia_options').style.display = 'none';
+ get('embeddedaudio_options').style.display = 'none';
+
+ if (get(data.type + '_options'))
+ get(data.type + '_options').style.display = 'block';
+
+ setVal('media_type', data.type);
+
+ setOptions('flash', 'play,loop,menu,swliveconnect,quality,scale,salign,wmode,base,flashvars');
+ setOptions('quicktime', 'loop,autoplay,cache,controller,correction,enablejavascript,kioskmode,autohref,playeveryframe,targetcache,scale,starttime,endtime,target,qtsrcchokespeed,volume,qtsrc');
+ setOptions('shockwave', 'sound,progress,autostart,swliveconnect,swvolume,swstretchstyle,swstretchhalign,swstretchvalign');
+ setOptions('windowsmedia', 'autostart,enabled,enablecontextmenu,fullscreen,invokeurls,mute,stretchtofit,windowlessvideo,balance,baseurl,captioningid,currentmarker,currentposition,defaultframe,playcount,rate,uimode,volume');
+ setOptions('realmedia', 'autostart,loop,autogotourl,center,imagestatus,maintainaspect,nojava,prefetch,shuffle,console,controls,numloop,scriptcallbacks');
+ setOptions('video', 'poster,autoplay,loop,muted,preload,controls');
+ setOptions('audio', 'autoplay,loop,preload,controls');
+ setOptions('embeddedaudio', 'autoplay,loop,controls');
+ setOptions('global', 'id,name,vspace,hspace,bgcolor,align,width,height');
+
+ if (to_form) {
+ if (data.type == 'video') {
+ if (data.video.sources[0])
+ setVal('src', data.video.sources[0].src);
+
+ src = data.video.sources[1];
+ if (src)
+ setVal('video_altsource1', src.src);
+
+ src = data.video.sources[2];
+ if (src)
+ setVal('video_altsource2', src.src);
+ } else if (data.type == 'audio') {
+ if (data.video.sources[0])
+ setVal('src', data.video.sources[0].src);
+
+ src = data.video.sources[1];
+ if (src)
+ setVal('audio_altsource1', src.src);
+
+ src = data.video.sources[2];
+ if (src)
+ setVal('audio_altsource2', src.src);
+ } else {
+ // Check flash vars
+ if (data.type == 'flash') {
+ tinymce.each(editor.getParam('flash_video_player_flashvars', {url : '$url', poster : '$poster'}), function(value, name) {
+ if (value == '$url')
+ data.params.src = parseQueryParams(data.params.flashvars)[name] || data.params.src || '';
+ });
+ }
+
+ setVal('src', data.params.src);
+ }
+ } else {
+ src = getVal("src");
+
+ // YouTube Embed
+ if (src.match(/youtube\.com\/embed\/\w+/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ setVal('src', src);
+ setVal('media_type', data.type);
+ } else {
+ // YouTube *NEW*
+ if (src.match(/youtu\.be\/[a-z1-9.-_]+/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://www.youtube.com/embed/' + src.match(/youtu.be\/([a-z1-9.-_]+)/)[1];
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ // YouTube
+ if (src.match(/youtube\.com(.+)v=([^&]+)/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://www.youtube.com/embed/' + src.match(/v=([^&]+)/)[1];
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+ }
+
+ // Google video
+ if (src.match(/video\.google\.com(.+)docid=([^&]+)/)) {
+ data.width = 425;
+ data.height = 326;
+ data.type = 'flash';
+ src = 'http://video.google.com/googleplayer.swf?docId=' + src.match(/docid=([^&]+)/)[1] + '&hl=en';
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ // Vimeo
+ if (src.match(/vimeo\.com\/([0-9]+)/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://player.vimeo.com/video/' + src.match(/vimeo.com\/([0-9]+)/)[1];
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ // stream.cz
+ if (src.match(/stream\.cz\/((?!object).)*\/([0-9]+)/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://www.stream.cz/object/' + src.match(/stream.cz\/[^/]+\/([0-9]+)/)[1];
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ // Google maps
+ if (src.match(/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://maps.google.com/maps/ms?msid=' + src.match(/msid=(.+)/)[1] + "&output=embed";
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ if (data.type == 'video') {
+ if (!data.video.sources)
+ data.video.sources = [];
+
+ data.video.sources[0] = {src : src};
+
+ src = getVal("video_altsource1");
+ if (src)
+ data.video.sources[1] = {src : src};
+
+ src = getVal("video_altsource2");
+ if (src)
+ data.video.sources[2] = {src : src};
+ } else if (data.type == 'audio') {
+ if (!data.video.sources)
+ data.video.sources = [];
+
+ data.video.sources[0] = {src : src};
+
+ src = getVal("audio_altsource1");
+ if (src)
+ data.video.sources[1] = {src : src};
+
+ src = getVal("audio_altsource2");
+ if (src)
+ data.video.sources[2] = {src : src};
+ } else
+ data.params.src = src;
+
+ // Set default size
+ setVal('width', data.width || (data.type == 'audio' ? 300 : 320));
+ setVal('height', data.height || (data.type == 'audio' ? 32 : 240));
+ }
+ },
+
+ dataToForm : function() {
+ this.moveStates(true);
+ },
+
+ formToData : function(field) {
+ if (field == "width" || field == "height")
+ this.changeSize(field);
+
+ if (field == 'source') {
+ this.moveStates(false, field);
+ setVal('source', this.editor.plugins.media.dataToHtml(this.data));
+ this.panel = 'source';
+ } else {
+ if (this.panel == 'source') {
+ this.data = clone(this.editor.plugins.media.htmlToData(getVal('source')));
+ this.dataToForm();
+ this.panel = '';
+ }
+
+ this.moveStates(false, field);
+ this.preview();
+ }
+ },
+
+ beforeResize : function() {
+ this.width = parseInt(getVal('width') || (this.data.type == 'audio' ? "300" : "320"), 10);
+ this.height = parseInt(getVal('height') || (this.data.type == 'audio' ? "32" : "240"), 10);
+ },
+
+ changeSize : function(type) {
+ var width, height, scale, size;
+
+ if (get('constrain').checked) {
+ width = parseInt(getVal('width') || (this.data.type == 'audio' ? "300" : "320"), 10);
+ height = parseInt(getVal('height') || (this.data.type == 'audio' ? "32" : "240"), 10);
+
+ if (type == 'width') {
+ this.height = Math.round((width / this.width) * height);
+ setVal('height', this.height);
+ } else {
+ this.width = Math.round((height / this.height) * width);
+ setVal('width', this.width);
+ }
+ }
+ },
+
+ getMediaListHTML : function() {
+ if (typeof(tinyMCEMediaList) != "undefined" && tinyMCEMediaList.length > 0) {
+ var html = "";
+
+ html += '<select id="linklist" name="linklist" style="width: 250px" onchange="this.form.src.value=this.options[this.selectedIndex].value;Media.formToData(\'src\');">';
+ html += '<option value="">---</option>';
+
+ for (var i=0; i<tinyMCEMediaList.length; i++)
+ html += '<option value="' + tinyMCEMediaList[i][1] + '">' + tinyMCEMediaList[i][0] + '</option>';
+
+ html += '</select>';
+
+ return html;
+ }
+
+ return "";
+ },
+
+ getMediaTypeHTML : function(editor) {
+ function option(media_type, element) {
+ if (!editor.schema.getElementRule(element || media_type)) {
+ return '';
+ }
+
+ return '<option value="'+media_type+'">'+tinyMCEPopup.editor.translate("media_dlg."+media_type)+'</option>'
+ }
+
+ var html = "";
+
+ html += '<select id="media_type" name="media_type" onchange="Media.formToData(\'type\');">';
+ html += option("video");
+ html += option("audio");
+ html += option("flash", "object");
+ html += option("quicktime", "object");
+ html += option("shockwave", "object");
+ html += option("windowsmedia", "object");
+ html += option("realmedia", "object");
+ html += option("iframe");
+
+ if (editor.getParam('media_embedded_audio', false)) {
+ html += option('embeddedaudio', "object");
+ }
+
+ html += '</select>';
+ return html;
+ },
+
+ setDefaultDialogSettings : function(editor) {
+ var defaultDialogSettings = editor.getParam("media_dialog_defaults", {});
+ tinymce.each(defaultDialogSettings, function(v, k) {
+ setVal(k, v);
+ });
+ }
+ };
+
+ tinyMCEPopup.requireLangPack();
+ tinyMCEPopup.onInit.add(function() {
+ Media.init();
+ });
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/media/media.htm b/src/wp-includes/js/tinymce/plugins/media/media.htm
new file mode 100644
index 0000000000..f52888b4f7
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/media.htm
@@ -0,0 +1,922 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#media_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/media.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/validate.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js?ver=358-20121205"></script>
+ <link href="css/media.css?ver=358-20121205" rel="stylesheet" type="text/css" />
+</head>
+<body style="display: none" role="application">
+<form onsubmit="Media.insert();return false;" action="#">
+ <div class="tabs" role="presentation">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');Media.formToData();" onmousedown="return false;">{#media_dlg.general}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');Media.formToData();" onmousedown="return false;">{#media_dlg.advanced}</a></span></li>
+ <li id="source_tab" aria-controls="source_panel"><span><a href="javascript:mcTabs.displayTab('source_tab','source_panel');Media.formToData('source');" onmousedown="return false;">{#media_dlg.source}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#media_dlg.general}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="media_type">{#media_dlg.type}</label></td>
+ <td>
+ <select id="media_type"></select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="src">{#media_dlg.file}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="src" name="src" type="text" value="" class="mceFocus" onchange="Media.formToData();" /></td>
+ <td id="filebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr id="linklistrow">
+ <td><label for="linklist">{#media_dlg.list}</label></td>
+ <td id="linklistcontainer"><select id="linklist"><option value=""></option></select></td>
+ </tr>
+ <tr>
+ <td><label for="width">{#media_dlg.size}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="text" id="width" name="width" value="" class="size" onchange="Media.formToData('width');" onfocus="Media.beforeResize();" /> x <input type="text" id="height" name="height" value="" class="size" onfocus="Media.beforeResize();" onchange="Media.formToData('height');" /></td>
+ <td>&nbsp;&nbsp;<input id="constrain" type="checkbox" name="constrain" class="checkbox" checked="checked" /></td>
+ <td><label id="constrainlabel" for="constrain">{#media_dlg.constrain_proportions}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#media_dlg.preview}</legend>
+ <div id="prev"></div>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#media_dlg.advanced}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0" width="100%">
+ <tr>
+ <td><label for="id">{#media_dlg.id}</label></td>
+ <td><input type="text" id="id" name="id" onchange="Media.formToData();" /></td>
+ <td><label for="name">{#media_dlg.name}</label></td>
+ <td><input type="text" id="name" name="name" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="align">{#media_dlg.align}</label></td>
+ <td>
+ <select id="align" name="align" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="top">{#media_dlg.align_top}</option>
+ <option value="right">{#media_dlg.align_right}</option>
+ <option value="bottom">{#media_dlg.align_bottom}</option>
+ <option value="left">{#media_dlg.align_left}</option>
+ </select>
+ </td>
+
+ <td><label for="bgcolor">{#media_dlg.bgcolor}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');Media.formToData();" /></td>
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="vspace">{#media_dlg.vspace}</label></td>
+ <td><input type="text" id="vspace" name="vspace" class="number" onchange="Media.formToData();" /></td>
+ <td><label for="hspace">{#media_dlg.hspace}</label></td>
+ <td><input type="text" id="hspace" name="hspace" class="number" onchange="Media.formToData();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="video_options">
+ <legend>{#media_dlg.html5_video_options}</legend>
+
+ <table role="presentation">
+ <tr>
+ <td><label for="video_altsource1">{#media_dlg.altsource1}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="video_altsource1" name="video_altsource1" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="video_altsource1_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="video_altsource2">{#media_dlg.altsource2}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="video_altsource2" name="video_altsource2" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="video_altsource2_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="video_poster">{#media_dlg.poster}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="video_poster" name="video_poster" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="video_poster_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="video_preload">{#media_dlg.preload}</label></td>
+ <td>
+ <select id="video_preload" name="video_preload" onchange="Media.formToData();">
+ <option value="none">{#media_dlg.preload_none}</option>
+ <option value="metadata">{#media_dlg.preload_metadata}</option>
+ <option value="auto">{#media_dlg.preload_auto}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_autoplay" name="video_autoplay" onchange="Media.formToData();" /></td>
+ <td><label for="video_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_muted" name="video_muted" onchange="Media.formToData();" /></td>
+ <td><label for="video_muted">{#media_dlg.mute}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_loop" name="video_loop" onchange="Media.formToData();" /></td>
+ <td><label for="video_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_controls" name="video_controls" onchange="Media.formToData();" /></td>
+ <td><label for="video_controls">{#media_dlg.controls}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="embeddedaudio_options">
+ <legend>{#media_dlg.embedded_audio_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="embeddedaudio_autoplay" name="audio_autoplay" onchange="Media.formToData();" /></td>
+ <td><label for="audio_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="embeddedaudio_loop" name="audio_loop" onchange="Media.formToData();" /></td>
+ <td><label for="audio_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="embeddedaudio_controls" name="audio_controls" onchange="Media.formToData();" /></td>
+ <td><label for="audio_controls">{#media_dlg.controls}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="audio_options">
+ <legend>{#media_dlg.html5_audio_options}</legend>
+
+ <table role="presentation">
+ <tr>
+ <td><label for="audio_altsource1">{#media_dlg.altsource1}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="audio_altsource1" name="audio_altsource1" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="audio_altsource1_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="audio_altsource2">{#media_dlg.altsource2}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="audio_altsource2" name="audio_altsource2" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="audio_altsource2_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="audio_preload">{#media_dlg.preload}</label></td>
+ <td>
+ <select id="audio_preload" name="audio_preload" onchange="Media.formToData();">
+ <option value="none">{#media_dlg.preload_none}</option>
+ <option value="metadata">{#media_dlg.preload_metadata}</option>
+ <option value="auto">{#media_dlg.preload_auto}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="audio_autoplay" name="audio_autoplay" onchange="Media.formToData();" /></td>
+ <td><label for="audio_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="audio_loop" name="audio_loop" onchange="Media.formToData();" /></td>
+ <td><label for="audio_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="audio_controls" name="audio_controls" onchange="Media.formToData();" /></td>
+ <td><label for="audio_controls">{#media_dlg.controls}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="flash_options">
+ <legend>{#media_dlg.flash_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="flash_quality">{#media_dlg.quality}</label></td>
+ <td>
+ <select id="flash_quality" name="flash_quality" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="high">high</option>
+ <option value="low">low</option>
+ <option value="autolow">autolow</option>
+ <option value="autohigh">autohigh</option>
+ <option value="best">best</option>
+ </select>
+ </td>
+
+ <td><label for="flash_scale">{#media_dlg.scale}</label></td>
+ <td>
+ <select id="flash_scale" name="flash_scale" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="showall">showall</option>
+ <option value="noborder">noborder</option>
+ <option value="exactfit">exactfit</option>
+ <option value="noscale">noscale</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="flash_wmode">{#media_dlg.wmode}</label></td>
+ <td>
+ <select id="flash_wmode" name="flash_wmode" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="window">window</option>
+ <option value="opaque">opaque</option>
+ <option value="transparent">transparent</option>
+ </select>
+ </td>
+
+ <td><label for="flash_salign">{#media_dlg.salign}</label></td>
+ <td>
+ <select id="flash_salign" name="flash_salign" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="l">{#media_dlg.align_left}</option>
+ <option value="t">{#media_dlg.align_top}</option>
+ <option value="r">{#media_dlg.align_right}</option>
+ <option value="b">{#media_dlg.align_bottom}</option>
+ <option value="tl">{#media_dlg.align_top_left}</option>
+ <option value="tr">{#media_dlg.align_top_right}</option>
+ <option value="bl">{#media_dlg.align_bottom_left}</option>
+ <option value="br">{#media_dlg.align_bottom_right}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_play" name="flash_play" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="flash_play">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_loop" name="flash_loop" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="flash_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_menu" name="flash_menu" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="flash_menu">{#media_dlg.menu}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_swliveconnect" name="flash_swliveconnect" onchange="Media.formToData();" /></td>
+ <td><label for="flash_swliveconnect">{#media_dlg.liveconnect}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+
+ <table role="presentation">
+ <tr>
+ <td><label for="flash_base">{#media_dlg.base}</label></td>
+ <td><input type="text" id="flash_base" name="flash_base" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="flash_flashvars">{#media_dlg.flashvars}</label></td>
+ <td><input type="text" id="flash_flashvars" name="flash_flashvars" onchange="Media.formToData();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="quicktime_options">
+ <legend>{#media_dlg.qt_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_loop" name="quicktime_loop" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_autoplay" name="quicktime_autoplay" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_cache" name="quicktime_cache" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_cache">{#media_dlg.cache}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_controller" name="quicktime_controller" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_controller">{#media_dlg.controller}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_correction" name="quicktime_correction" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_correction">{#media_dlg.correction}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_enablejavascript" name="quicktime_enablejavascript" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_enablejavascript">{#media_dlg.enablejavascript}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_kioskmode" name="quicktime_kioskmode" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_kioskmode">{#media_dlg.kioskmode}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_autohref" name="quicktime_autohref" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_autohref">{#media_dlg.autohref}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_playeveryframe" name="quicktime_playeveryframe" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_playeveryframe">{#media_dlg.playeveryframe}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_targetcache" name="quicktime_targetcache" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_targetcache">{#media_dlg.targetcache}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_scale">{#media_dlg.scale}</label></td>
+ <td><select id="quicktime_scale" name="quicktime_scale" class="mceEditableSelect" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="tofit">tofit</option>
+ <option value="aspect">aspect</option>
+ </select>
+ </td>
+
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_starttime">{#media_dlg.starttime}</label></td>
+ <td><input type="text" id="quicktime_starttime" name="quicktime_starttime" onchange="Media.formToData();" /></td>
+
+ <td><label for="quicktime_endtime">{#media_dlg.endtime}</label></td>
+ <td><input type="text" id="quicktime_endtime" name="quicktime_endtime" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_target">{#media_dlg.target}</label></td>
+ <td><input type="text" id="quicktime_target" name="quicktime_target" onchange="Media.formToData();" /></td>
+
+ <td><label for="quicktime_href">{#media_dlg.href}</label></td>
+ <td><input type="text" id="quicktime_href" name="quicktime_href" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_qtsrcchokespeed">{#media_dlg.qtsrcchokespeed}</label></td>
+ <td><input type="text" id="quicktime_qtsrcchokespeed" name="quicktime_qtsrcchokespeed" onchange="Media.formToData();" /></td>
+
+ <td><label for="quicktime_volume">{#media_dlg.volume}</label></td>
+ <td><input type="text" id="quicktime_volume" name="quicktime_volume" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_qtsrc">{#media_dlg.qtsrc}</label></td>
+ <td colspan="4">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="quicktime_qtsrc" name="quicktime_qtsrc" onchange="Media.formToData();" /></td>
+ <td id="qtsrcfilebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="windowsmedia_options">
+ <legend>{#media_dlg.wmp_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_autostart" name="windowsmedia_autostart" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_autostart">{#media_dlg.autostart}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_enabled" name="windowsmedia_enabled" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_enabled">{#media_dlg.enabled}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_enablecontextmenu" name="windowsmedia_enablecontextmenu" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_enablecontextmenu">{#media_dlg.menu}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_fullscreen" name="windowsmedia_fullscreen" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_fullscreen">{#media_dlg.fullscreen}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_invokeurls" name="windowsmedia_invokeurls" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_invokeurls">{#media_dlg.invokeurls}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_mute" name="windowsmedia_mute" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_mute">{#media_dlg.mute}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_stretchtofit" name="windowsmedia_stretchtofit" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_stretchtofit">{#media_dlg.stretchtofit}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_windowlessvideo" name="windowsmedia_windowlessvideo" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_windowlessvideo">{#media_dlg.windowlessvideo}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_balance">{#media_dlg.balance}</label></td>
+ <td><input type="text" id="windowsmedia_balance" name="windowsmedia_balance" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_baseurl">{#media_dlg.baseurl}</label></td>
+ <td><input type="text" id="windowsmedia_baseurl" name="windowsmedia_baseurl" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_captioningid">{#media_dlg.captioningid}</label></td>
+ <td><input type="text" id="windowsmedia_captioningid" name="windowsmedia_captioningid" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_currentmarker">{#media_dlg.currentmarker}</label></td>
+ <td><input type="text" id="windowsmedia_currentmarker" name="windowsmedia_currentmarker" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_currentposition">{#media_dlg.currentposition}</label></td>
+ <td><input type="text" id="windowsmedia_currentposition" name="windowsmedia_currentposition" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_defaultframe">{#media_dlg.defaultframe}</label></td>
+ <td><input type="text" id="windowsmedia_defaultframe" name="windowsmedia_defaultframe" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_playcount">{#media_dlg.playcount}</label></td>
+ <td><input type="text" id="windowsmedia_playcount" name="windowsmedia_playcount" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_rate">{#media_dlg.rate}</label></td>
+ <td><input type="text" id="windowsmedia_rate" name="windowsmedia_rate" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_uimode">{#media_dlg.uimode}</label></td>
+ <td><input type="text" id="windowsmedia_uimode" name="windowsmedia_uimode" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_volume">{#media_dlg.volume}</label></td>
+ <td><input type="text" id="windowsmedia_volume" name="windowsmedia_volume" onchange="Media.formToData();" /></td>
+ </tr>
+
+ </table>
+ </fieldset>
+
+ <fieldset id="realmedia_options">
+ <legend>{#media_dlg.rmp_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_autostart" name="realmedia_autostart" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_autostart">{#media_dlg.autostart}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_loop" name="realmedia_loop" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_autogotourl" name="realmedia_autogotourl" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_autogotourl">{#media_dlg.autogotourl}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_center" name="realmedia_center" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_center">{#media_dlg.center}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_imagestatus" name="realmedia_imagestatus" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_imagestatus">{#media_dlg.imagestatus}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_maintainaspect" name="realmedia_maintainaspect" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_maintainaspect">{#media_dlg.maintainaspect}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_nojava" name="realmedia_nojava" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_nojava">{#media_dlg.nojava}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_prefetch" name="realmedia_prefetch" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_prefetch">{#media_dlg.prefetch}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_shuffle" name="realmedia_shuffle" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_shuffle">{#media_dlg.shuffle}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ &nbsp;
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="realmedia_console">{#media_dlg.console}</label></td>
+ <td><input type="text" id="realmedia_console" name="realmedia_console" onchange="Media.formToData();" /></td>
+
+ <td><label for="realmedia_controls">{#media_dlg.controls}</label></td>
+ <td><input type="text" id="realmedia_controls" name="realmedia_controls" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="realmedia_numloop">{#media_dlg.numloop}</label></td>
+ <td><input type="text" id="realmedia_numloop" name="realmedia_numloop" onchange="Media.formToData();" /></td>
+
+ <td><label for="realmedia_scriptcallbacks">{#media_dlg.scriptcallbacks}</label></td>
+ <td><input type="text" id="realmedia_scriptcallbacks" name="realmedia_scriptcallbacks" onchange="Media.formToData();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="shockwave_options">
+ <legend>{#media_dlg.shockwave_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="shockwave_swstretchstyle">{#media_dlg.swstretchstyle}</label></td>
+ <td>
+ <select id="shockwave_swstretchstyle" name="shockwave_swstretchstyle" onchange="Media.formToData();">
+ <option value="none">{#not_set}</option>
+ <option value="meet">Meet</option>
+ <option value="fill">Fill</option>
+ <option value="stage">Stage</option>
+ </select>
+ </td>
+
+ <td><label for="shockwave_swvolume">{#media_dlg.volume}</label></td>
+ <td><input type="text" id="shockwave_swvolume" name="shockwave_swvolume" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="shockwave_swstretchhalign">{#media_dlg.swstretchhalign}</label></td>
+ <td>
+ <select id="shockwave_swstretchhalign" name="shockwave_swstretchhalign" onchange="Media.formToData();">
+ <option value="none">{#not_set}</option>
+ <option value="left">{#media_dlg.align_left}</option>
+ <option value="center">{#media_dlg.align_center}</option>
+ <option value="right">{#media_dlg.align_right}</option>
+ </select>
+ </td>
+
+ <td><label for="shockwave_swstretchvalign">{#media_dlg.swstretchvalign}</label></td>
+ <td>
+ <select id="shockwave_swstretchvalign" name="shockwave_swstretchvalign" onchange="Media.formToData();">
+ <option value="none">{#not_set}</option>
+ <option value="meet">Meet</option>
+ <option value="fill">Fill</option>
+ <option value="stage">Stage</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_autostart" name="shockwave_autostart" onchange="Media.formToData();" checked="checked" /></td>
+ <td><label for="shockwave_autostart">{#media_dlg.autostart}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_sound" name="shockwave_sound" onchange="Media.formToData();" checked="checked" /></td>
+ <td><label for="shockwave_sound">{#media_dlg.sound}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_swliveconnect" name="shockwave_swliveconnect" onchange="Media.formToData();" /></td>
+ <td><label for="shockwave_swliveconnect">{#media_dlg.liveconnect}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_progress" name="shockwave_progress" onchange="Media.formToData();" checked="checked" /></td>
+ <td><label for="shockwave_progress">{#media_dlg.progress}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="source_panel" class="panel">
+ <fieldset>
+ <legend>{#media_dlg.source}</legend>
+ <textarea id="source" style="width: 99%; height: 390px"></textarea>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/plugins/media/moxieplayer.swf b/src/wp-includes/js/tinymce/plugins/media/moxieplayer.swf
new file mode 100644
index 0000000000..9c6daf9b73
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/media/moxieplayer.swf
@@ -0,0 +1 @@
+<html><body>You are being <a href="https://raw.github.com/moxiecode/moxieplayer/master/bin-release/moxieplayer.swf">redirected</a>.</body></html> \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/paste/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/paste/editor_plugin.js
new file mode 100644
index 0000000000..0ab05ebbb6
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/paste/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var c=tinymce.each,a={paste_auto_cleanup_on_paste:true,paste_enable_default_filters:true,paste_block_drop:false,paste_retain_style_properties:"none",paste_strip_class_attributes:"mso",paste_remove_spans:false,paste_remove_styles:false,paste_remove_styles_if_webkit:true,paste_convert_middot_lists:true,paste_convert_headers_to_strong:false,paste_dialog_width:"450",paste_dialog_height:"400",paste_max_consecutive_linebreaks:2,paste_text_use_dialog:false,paste_text_sticky:false,paste_text_sticky_default:false,paste_text_notifyalways:false,paste_text_linebreaktype:"combined",paste_text_replacements:[[/\u2026/g,"..."],[/[\x93\x94\u201c\u201d]/g,'"'],[/[\x60\x91\x92\u2018\u2019]/g,"'"]]};function b(d,e){return d.getParam(e,a[e])}tinymce.create("tinymce.plugins.PastePlugin",{init:function(d,e){var f=this;f.editor=d;f.url=e;f.onPreProcess=new tinymce.util.Dispatcher(f);f.onPostProcess=new tinymce.util.Dispatcher(f);f.onPreProcess.add(f._preProcess);f.onPostProcess.add(f._postProcess);f.onPreProcess.add(function(i,j){d.execCallback("paste_preprocess",i,j)});f.onPostProcess.add(function(i,j){d.execCallback("paste_postprocess",i,j)});d.onKeyDown.addToTop(function(i,j){if(((tinymce.isMac?j.metaKey:j.ctrlKey)&&j.keyCode==86)||(j.shiftKey&&j.keyCode==45)){return false}});d.pasteAsPlainText=b(d,"paste_text_sticky_default");function h(l,j){var k=d.dom,i;f.onPreProcess.dispatch(f,l);l.node=k.create("div",0,l.content);if(tinymce.isGecko){i=d.selection.getRng(true);if(i.startContainer==i.endContainer&&i.startContainer.nodeType==3){if(l.node.childNodes.length===1&&/^(p|h[1-6]|pre)$/i.test(l.node.firstChild.nodeName)&&l.content.indexOf("__MCE_ITEM__")===-1){k.remove(l.node.firstChild,true)}}}f.onPostProcess.dispatch(f,l);l.content=d.serializer.serialize(l.node,{getInner:1,forced_root_block:""});if((!j)&&(d.pasteAsPlainText)){f._insertPlainText(l.content);if(!b(d,"paste_text_sticky")){d.pasteAsPlainText=false;d.controlManager.setActive("pastetext",false)}}else{f._insert(l.content)}}d.addCommand("mceInsertClipboardContent",function(i,j){h(j,true)});if(!b(d,"paste_text_use_dialog")){d.addCommand("mcePasteText",function(j,i){var k=tinymce.util.Cookie;d.pasteAsPlainText=!d.pasteAsPlainText;d.controlManager.setActive("pastetext",d.pasteAsPlainText);if((d.pasteAsPlainText)&&(!k.get("tinymcePasteText"))){if(b(d,"paste_text_sticky")){d.windowManager.alert(d.translate("paste.plaintext_mode_sticky"))}else{d.windowManager.alert(d.translate("paste.plaintext_mode"))}if(!b(d,"paste_text_notifyalways")){k.set("tinymcePasteText","1",new Date(new Date().getFullYear()+1,12,31))}}})}d.addButton("pastetext",{title:"paste.paste_text_desc",cmd:"mcePasteText"});d.addButton("selectall",{title:"paste.selectall_desc",cmd:"selectall"});function g(s){var l,p,j,t,k=d.selection,o=d.dom,q=d.getBody(),i,r;if(s.clipboardData||o.doc.dataTransfer){r=(s.clipboardData||o.doc.dataTransfer).getData("Text");if(d.pasteAsPlainText){s.preventDefault();h({content:o.encode(r).replace(/\r?\n/g,"<br />")});return}}if(o.get("_mcePaste")){return}l=o.add(q,"div",{id:"_mcePaste","class":"mcePaste","data-mce-bogus":"1"},"\uFEFF\uFEFF");if(q!=d.getDoc().body){i=o.getPos(d.selection.getStart(),q).y}else{i=q.scrollTop+o.getViewPort(d.getWin()).y}o.setStyles(l,{position:"absolute",left:tinymce.isGecko?-40:0,top:i-25,width:1,height:1,overflow:"hidden"});if(tinymce.isIE){t=k.getRng();j=o.doc.body.createTextRange();j.moveToElementText(l);j.execCommand("Paste");o.remove(l);if(l.innerHTML==="\uFEFF\uFEFF"){d.execCommand("mcePasteWord");s.preventDefault();return}k.setRng(t);k.setContent("");setTimeout(function(){h({content:l.innerHTML})},0);return tinymce.dom.Event.cancel(s)}else{function m(n){n.preventDefault()}o.bind(d.getDoc(),"mousedown",m);o.bind(d.getDoc(),"keydown",m);p=d.selection.getRng();l=l.firstChild;j=d.getDoc().createRange();j.setStart(l,0);j.setEnd(l,2);k.setRng(j);window.setTimeout(function(){var u="",n;if(!o.select("div.mcePaste > div.mcePaste").length){n=o.select("div.mcePaste");c(n,function(w){var v=w.firstChild;if(v&&v.nodeName=="DIV"&&v.style.marginTop&&v.style.backgroundColor){o.remove(v,1)}c(o.select("span.Apple-style-span",w),function(x){o.remove(x,1)});c(o.select("br[data-mce-bogus]",w),function(x){o.remove(x)});if(w.parentNode.className!="mcePaste"){u+=w.innerHTML}})}else{u="<p>"+o.encode(r).replace(/\r?\n\r?\n/g,"</p><p>").replace(/\r?\n/g,"<br />")+"</p>"}c(o.select("div.mcePaste"),function(v){o.remove(v)});if(p){k.setRng(p)}h({content:u});o.unbind(d.getDoc(),"mousedown",m);o.unbind(d.getDoc(),"keydown",m)},0)}}if(b(d,"paste_auto_cleanup_on_paste")){if(tinymce.isOpera||/Firefox\/2/.test(navigator.userAgent)){d.onKeyDown.addToTop(function(i,j){if(((tinymce.isMac?j.metaKey:j.ctrlKey)&&j.keyCode==86)||(j.shiftKey&&j.keyCode==45)){g(j)}})}else{d.onPaste.addToTop(function(i,j){return g(j)})}}d.onInit.add(function(){d.controlManager.setActive("pastetext",d.pasteAsPlainText);if(b(d,"paste_block_drop")){d.dom.bind(d.getBody(),["dragend","dragover","draggesture","dragdrop","drop","drag"],function(i){i.preventDefault();i.stopPropagation();return false})}});f._legacySupport()},getInfo:function(){return{longname:"Paste text/word",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_preProcess:function(g,e){var k=this.editor,j=e.content,p=tinymce.grep,n=tinymce.explode,f=tinymce.trim,l,i;function d(h){c(h,function(o){if(o.constructor==RegExp){j=j.replace(o,"")}else{j=j.replace(o[0],o[1])}})}if(k.settings.paste_enable_default_filters==false){return}if(tinymce.isIE&&document.documentMode>=9&&/<(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)/.test(e.content)){d([[/(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g,"$1"]]);d([[/<br><br>/g,"<BR><BR>"],[/<br>/g," "],[/<BR><BR>/g,"<br>"]])}if(/class="?Mso|style="[^"]*\bmso-|w:WordDocument/i.test(j)||e.wordContent){e.wordContent=true;d([/^\s*(&nbsp;)+/gi,/(&nbsp;|<br[^>]*>)+\s*$/gi]);if(b(k,"paste_convert_headers_to_strong")){j=j.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi,"<p><strong>$1</strong></p>")}if(b(k,"paste_convert_middot_lists")){d([[/<!--\[if !supportLists\]-->/gi,"$&__MCE_ITEM__"],[/(<span[^>]+(?:mso-list:|:\s*symbol)[^>]+>)/gi,"$1__MCE_ITEM__"],[/(<p[^>]+(?:MsoListParagraph)[^>]+>)/gi,"$1__MCE_ITEM__"]])}d([/<!--[\s\S]+?-->/gi,/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/&nbsp;/gi,"\u00a0"]]);do{l=j.length;j=j.replace(/(<[a-z][^>]*\s)(?:id|name|language|type|on\w+|\w+:\w+)=(?:"[^"]*"|\w+)\s?/gi,"$1")}while(l!=j.length);if(b(k,"paste_retain_style_properties").replace(/^none$/i,"").length==0){j=j.replace(/<\/?span[^>]*>/gi,"")}else{d([[/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,function(o,h){return(h.length>0)?h.replace(/./," ").slice(Math.floor(h.length/2)).split("").join("\u00a0"):""}],[/(<[a-z][^>]*)\sstyle="([^"]*)"/gi,function(t,h,r){var u=[],o=0,q=n(f(r).replace(/&quot;/gi,"'"),";");c(q,function(s){var w,y,z=n(s,":");function x(A){return A+((A!=="0")&&(/\d$/.test(A)))?"px":""}if(z.length==2){w=z[0].toLowerCase();y=z[1].toLowerCase();switch(w){case"mso-padding-alt":case"mso-padding-top-alt":case"mso-padding-right-alt":case"mso-padding-bottom-alt":case"mso-padding-left-alt":case"mso-margin-alt":case"mso-margin-top-alt":case"mso-margin-right-alt":case"mso-margin-bottom-alt":case"mso-margin-left-alt":case"mso-table-layout-alt":case"mso-height":case"mso-width":case"mso-vertical-align-alt":u[o++]=w.replace(/^mso-|-alt$/g,"")+":"+x(y);return;case"horiz-align":u[o++]="text-align:"+y;return;case"vert-align":u[o++]="vertical-align:"+y;return;case"font-color":case"mso-foreground":u[o++]="color:"+y;return;case"mso-background":case"mso-highlight":u[o++]="background:"+y;return;case"mso-default-height":u[o++]="min-height:"+x(y);return;case"mso-default-width":u[o++]="min-width:"+x(y);return;case"mso-padding-between-alt":u[o++]="border-collapse:separate;border-spacing:"+x(y);return;case"text-line-through":if((y=="single")||(y=="double")){u[o++]="text-decoration:line-through"}return;case"mso-zero-height":if(y=="yes"){u[o++]="display:none"}return}if(/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/.test(w)){return}u[o++]=w+":"+z[1]}});if(o>0){return h+' style="'+u.join(";")+'"'}else{return h}}]])}}if(b(k,"paste_convert_headers_to_strong")){d([[/<h[1-6][^>]*>/gi,"<p><strong>"],[/<\/h[1-6][^>]*>/gi,"</strong></p>"]])}d([[/Version:[\d.]+\nStartHTML:\d+\nEndHTML:\d+\nStartFragment:\d+\nEndFragment:\d+/gi,""]]);i=b(k,"paste_strip_class_attributes");if(i!=="none"){function m(q,o){if(i==="all"){return""}var h=p(n(o.replace(/^(["'])(.*)\1$/,"$2")," "),function(r){return(/^(?!mso)/i.test(r))});return h.length?' class="'+h.join(" ")+'"':""}j=j.replace(/ class="([^"]+)"/gi,m);j=j.replace(/ class=([\-\w]+)/gi,m)}if(b(k,"paste_remove_spans")){j=j.replace(/<\/?span[^>]*>/gi,"")}e.content=j},_postProcess:function(g,i){var f=this,e=f.editor,h=e.dom,d;if(e.settings.paste_enable_default_filters==false){return}if(i.wordContent){c(h.select("a",i.node),function(j){if(!j.href||j.href.indexOf("#_Toc")!=-1){h.remove(j,1)}});if(b(e,"paste_convert_middot_lists")){f._convertLists(g,i)}d=b(e,"paste_retain_style_properties");if((tinymce.is(d,"string"))&&(d!=="all")&&(d!=="*")){d=tinymce.explode(d.replace(/^none$/i,""));c(h.select("*",i.node),function(m){var n={},k=0,l,o,j;if(d){for(l=0;l<d.length;l++){o=d[l];j=h.getStyle(m,o);if(j){n[o]=j;k++}}}h.setAttrib(m,"style","");if(d&&k>0){h.setStyles(m,n)}else{if(m.nodeName=="SPAN"&&!m.className){h.remove(m,true)}}})}}if(b(e,"paste_remove_styles")||(b(e,"paste_remove_styles_if_webkit")&&tinymce.isWebKit)){c(h.select("*[style]",i.node),function(j){j.removeAttribute("style");j.removeAttribute("data-mce-style")})}else{if(tinymce.isWebKit){c(h.select("*",i.node),function(j){j.removeAttribute("data-mce-style")})}}},_convertLists:function(g,e){var i=g.editor.dom,h,l,d=-1,f,m=[],k,j;c(i.select("p",e.node),function(t){var q,u="",s,r,n,o;for(q=t.firstChild;q&&q.nodeType==3;q=q.nextSibling){u+=q.nodeValue}u=t.innerHTML.replace(/<\/?\w+[^>]*>/gi,"").replace(/&nbsp;/g,"\u00a0");if(/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*\u00a0*/.test(u)){s="ul"}if(/^__MCE_ITEM__\s*\w+\.\s*\u00a0+/.test(u)){s="ol"}if(s){f=parseFloat(t.style.marginLeft||0);if(f>d){m.push(f)}if(!h||s!=k){h=i.create(s);i.insertAfter(h,t)}else{if(f>d){h=l.appendChild(i.create(s))}else{if(f<d){n=tinymce.inArray(m,f);o=i.getParents(h.parentNode,s);h=o[o.length-1-n]||h}}}c(i.select("span",t),function(v){var p=v.innerHTML.replace(/<\/?\w+[^>]*>/gi,"");if(s=="ul"&&/^__MCE_ITEM__[\u2022\u00b7\u00a7\u00d8o\u25CF]/.test(p)){i.remove(v)}else{if(/^__MCE_ITEM__[\s\S]*\w+\.(&nbsp;|\u00a0)*\s*/.test(p)){i.remove(v)}}});r=t.innerHTML;if(s=="ul"){r=t.innerHTML.replace(/__MCE_ITEM__/g,"").replace(/^[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*(&nbsp;|\u00a0)+\s*/,"")}else{r=t.innerHTML.replace(/__MCE_ITEM__/g,"").replace(/^\s*\w+\.(&nbsp;|\u00a0)+\s*/,"")}l=h.appendChild(i.create("li",0,r));i.remove(t);d=f;k=s}else{h=d=0}});j=e.node.innerHTML;if(j.indexOf("__MCE_ITEM__")!=-1){e.node.innerHTML=j.replace(/__MCE_ITEM__/g,"")}},_insert:function(f,d){var e=this.editor,g=e.selection.getRng();if(!e.selection.isCollapsed()&&g.startContainer!=g.endContainer){e.getDoc().execCommand("Delete",false,null)}e.execCommand("mceInsertContent",false,f,{skip_undo:d})},_insertPlainText:function(j){var h=this.editor,f=b(h,"paste_text_linebreaktype"),k=b(h,"paste_text_replacements"),g=tinymce.is;function e(m){c(m,function(n){if(n.constructor==RegExp){j=j.replace(n,"")}else{j=j.replace(n[0],n[1])}})}if((typeof(j)==="string")&&(j.length>0)){if(/<(?:p|br|h[1-6]|ul|ol|dl|table|t[rdh]|div|blockquote|fieldset|pre|address|center)[^>]*>/i.test(j)){e([/[\n\r]+/g])}else{e([/\r+/g])}e([[/<\/(?:p|h[1-6]|ul|ol|dl|table|div|blockquote|fieldset|pre|address|center)>/gi,"\n\n"],[/<br[^>]*>|<\/tr>/gi,"\n"],[/<\/t[dh]>\s*<t[dh][^>]*>/gi,"\t"],/<[a-z!\/?][^>]*>/gi,[/&nbsp;/gi," "],[/(?:(?!\n)\s)*(\n+)(?:(?!\n)\s)*/gi,"$1"]]);var d=Number(b(h,"paste_max_consecutive_linebreaks"));if(d>-1){var l=new RegExp("\n{"+(d+1)+",}","g");var i="";while(i.length<d){i+="\n"}e([[l,i]])}j=h.dom.decode(tinymce.html.Entities.encodeRaw(j));if(g(k,"array")){e(k)}else{if(g(k,"string")){e(new RegExp(k,"gi"))}}if(f=="none"){e([[/\n+/g," "]])}else{if(f=="br"){e([[/\n/g,"<br />"]])}else{if(f=="p"){e([[/\n+/g,"</p><p>"],[/^(.*<\/p>)(<p>)$/,"<p>$1"]])}else{e([[/\n\n/g,"</p><p>"],[/^(.*<\/p>)(<p>)$/,"<p>$1"],[/\n/g,"<br />"]])}}}h.execCommand("mceInsertContent",false,j)}},_legacySupport:function(){var e=this,d=e.editor;d.addCommand("mcePasteWord",function(){d.windowManager.open({file:e.url+"/pasteword.htm",width:parseInt(b(d,"paste_dialog_width")),height:parseInt(b(d,"paste_dialog_height")),inline:1})});if(b(d,"paste_text_use_dialog")){d.addCommand("mcePasteText",function(){d.windowManager.open({file:e.url+"/pastetext.htm",width:parseInt(b(d,"paste_dialog_width")),height:parseInt(b(d,"paste_dialog_height")),inline:1})})}d.addButton("pasteword",{title:"paste.paste_word_desc",cmd:"mcePasteWord"})}});tinymce.PluginManager.add("paste",tinymce.plugins.PastePlugin)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js
new file mode 100644
index 0000000000..c8230e9c9b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/paste/editor_plugin_src.js
@@ -0,0 +1,885 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var each = tinymce.each,
+ defs = {
+ paste_auto_cleanup_on_paste : true,
+ paste_enable_default_filters : true,
+ paste_block_drop : false,
+ paste_retain_style_properties : "none",
+ paste_strip_class_attributes : "mso",
+ paste_remove_spans : false,
+ paste_remove_styles : false,
+ paste_remove_styles_if_webkit : true,
+ paste_convert_middot_lists : true,
+ paste_convert_headers_to_strong : false,
+ paste_dialog_width : "450",
+ paste_dialog_height : "400",
+ paste_max_consecutive_linebreaks: 2,
+ paste_text_use_dialog : false,
+ paste_text_sticky : false,
+ paste_text_sticky_default : false,
+ paste_text_notifyalways : false,
+ paste_text_linebreaktype : "combined",
+ paste_text_replacements : [
+ [/\u2026/g, "..."],
+ [/[\x93\x94\u201c\u201d]/g, '"'],
+ [/[\x60\x91\x92\u2018\u2019]/g, "'"]
+ ]
+ };
+
+ function getParam(ed, name) {
+ return ed.getParam(name, defs[name]);
+ }
+
+ tinymce.create('tinymce.plugins.PastePlugin', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+ t.url = url;
+
+ // Setup plugin events
+ t.onPreProcess = new tinymce.util.Dispatcher(t);
+ t.onPostProcess = new tinymce.util.Dispatcher(t);
+
+ // Register default handlers
+ t.onPreProcess.add(t._preProcess);
+ t.onPostProcess.add(t._postProcess);
+
+ // Register optional preprocess handler
+ t.onPreProcess.add(function(pl, o) {
+ ed.execCallback('paste_preprocess', pl, o);
+ });
+
+ // Register optional postprocess
+ t.onPostProcess.add(function(pl, o) {
+ ed.execCallback('paste_postprocess', pl, o);
+ });
+
+ ed.onKeyDown.addToTop(function(ed, e) {
+ // Block ctrl+v from adding an undo level since the default logic in tinymce.Editor will add that
+ if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
+ return false; // Stop other listeners
+ });
+
+ // Initialize plain text flag
+ ed.pasteAsPlainText = getParam(ed, 'paste_text_sticky_default');
+
+ // This function executes the process handlers and inserts the contents
+ // force_rich overrides plain text mode set by user, important for pasting with execCommand
+ function process(o, force_rich) {
+ var dom = ed.dom, rng;
+
+ // Execute pre process handlers
+ t.onPreProcess.dispatch(t, o);
+
+ // Create DOM structure
+ o.node = dom.create('div', 0, o.content);
+
+ // If pasting inside the same element and the contents is only one block
+ // remove the block and keep the text since Firefox will copy parts of pre and h1-h6 as a pre element
+ if (tinymce.isGecko) {
+ rng = ed.selection.getRng(true);
+ if (rng.startContainer == rng.endContainer && rng.startContainer.nodeType == 3) {
+ // Is only one block node and it doesn't contain word stuff
+ if (o.node.childNodes.length === 1 && /^(p|h[1-6]|pre)$/i.test(o.node.firstChild.nodeName) && o.content.indexOf('__MCE_ITEM__') === -1)
+ dom.remove(o.node.firstChild, true);
+ }
+ }
+
+ // Execute post process handlers
+ t.onPostProcess.dispatch(t, o);
+
+ // Serialize content
+ o.content = ed.serializer.serialize(o.node, {getInner : 1, forced_root_block : ''});
+
+ // Plain text option active?
+ if ((!force_rich) && (ed.pasteAsPlainText)) {
+ t._insertPlainText(o.content);
+
+ if (!getParam(ed, "paste_text_sticky")) {
+ ed.pasteAsPlainText = false;
+ ed.controlManager.setActive("pastetext", false);
+ }
+ } else {
+ t._insert(o.content);
+ }
+ }
+
+ // Add command for external usage
+ ed.addCommand('mceInsertClipboardContent', function(u, o) {
+ process(o, true);
+ });
+
+ if (!getParam(ed, "paste_text_use_dialog")) {
+ ed.addCommand('mcePasteText', function(u, v) {
+ var cookie = tinymce.util.Cookie;
+
+ ed.pasteAsPlainText = !ed.pasteAsPlainText;
+ ed.controlManager.setActive('pastetext', ed.pasteAsPlainText);
+
+ if ((ed.pasteAsPlainText) && (!cookie.get("tinymcePasteText"))) {
+ if (getParam(ed, "paste_text_sticky")) {
+ ed.windowManager.alert(ed.translate('paste.plaintext_mode_sticky'));
+ } else {
+ ed.windowManager.alert(ed.translate('paste.plaintext_mode'));
+ }
+
+ if (!getParam(ed, "paste_text_notifyalways")) {
+ cookie.set("tinymcePasteText", "1", new Date(new Date().getFullYear() + 1, 12, 31))
+ }
+ }
+ });
+ }
+
+ ed.addButton('pastetext', {title: 'paste.paste_text_desc', cmd: 'mcePasteText'});
+ ed.addButton('selectall', {title: 'paste.selectall_desc', cmd: 'selectall'});
+
+ // This function grabs the contents from the clipboard by adding a
+ // hidden div and placing the caret inside it and after the browser paste
+ // is done it grabs that contents and processes that
+ function grabContent(e) {
+ var n, or, rng, oldRng, sel = ed.selection, dom = ed.dom, body = ed.getBody(), posY, textContent;
+
+ // Check if browser supports direct plaintext access
+ if (e.clipboardData || dom.doc.dataTransfer) {
+ textContent = (e.clipboardData || dom.doc.dataTransfer).getData('Text');
+
+ if (ed.pasteAsPlainText) {
+ e.preventDefault();
+ process({content : dom.encode(textContent).replace(/\r?\n/g, '<br />')});
+ return;
+ }
+ }
+
+ if (dom.get('_mcePaste'))
+ return;
+
+ // Create container to paste into
+ n = dom.add(body, 'div', {id : '_mcePaste', 'class' : 'mcePaste', 'data-mce-bogus' : '1'}, '\uFEFF\uFEFF');
+
+ // If contentEditable mode we need to find out the position of the closest element
+ if (body != ed.getDoc().body)
+ posY = dom.getPos(ed.selection.getStart(), body).y;
+ else
+ posY = body.scrollTop + dom.getViewPort(ed.getWin()).y;
+
+ // Styles needs to be applied after the element is added to the document since WebKit will otherwise remove all styles
+ // If also needs to be in view on IE or the paste would fail
+ dom.setStyles(n, {
+ position : 'absolute',
+ left : tinymce.isGecko ? -40 : 0, // Need to move it out of site on Gecko since it will othewise display a ghost resize rect for the div
+ top : posY - 25,
+ width : 1,
+ height : 1,
+ overflow : 'hidden'
+ });
+
+ if (tinymce.isIE) {
+ // Store away the old range
+ oldRng = sel.getRng();
+
+ // Select the container
+ rng = dom.doc.body.createTextRange();
+ rng.moveToElementText(n);
+ rng.execCommand('Paste');
+
+ // Remove container
+ dom.remove(n);
+
+ // Check if the contents was changed, if it wasn't then clipboard extraction failed probably due
+ // to IE security settings so we pass the junk though better than nothing right
+ if (n.innerHTML === '\uFEFF\uFEFF') {
+ ed.execCommand('mcePasteWord');
+ e.preventDefault();
+ return;
+ }
+
+ // Restore the old range and clear the contents before pasting
+ sel.setRng(oldRng);
+ sel.setContent('');
+
+ // For some odd reason we need to detach the the mceInsertContent call from the paste event
+ // It's like IE has a reference to the parent element that you paste in and the selection gets messed up
+ // when it tries to restore the selection
+ setTimeout(function() {
+ // Process contents
+ process({content : n.innerHTML});
+ }, 0);
+
+ // Block the real paste event
+ return tinymce.dom.Event.cancel(e);
+ } else {
+ function block(e) {
+ e.preventDefault();
+ };
+
+ // Block mousedown and click to prevent selection change
+ dom.bind(ed.getDoc(), 'mousedown', block);
+ dom.bind(ed.getDoc(), 'keydown', block);
+
+ or = ed.selection.getRng();
+
+ // Move select contents inside DIV
+ n = n.firstChild;
+ rng = ed.getDoc().createRange();
+ rng.setStart(n, 0);
+ rng.setEnd(n, 2);
+ sel.setRng(rng);
+
+ // Wait a while and grab the pasted contents
+ window.setTimeout(function() {
+ var h = '', nl;
+
+ // Paste divs duplicated in paste divs seems to happen when you paste plain text so lets first look for that broken behavior in WebKit
+ if (!dom.select('div.mcePaste > div.mcePaste').length) {
+ nl = dom.select('div.mcePaste');
+
+ // WebKit will split the div into multiple ones so this will loop through then all and join them to get the whole HTML string
+ each(nl, function(n) {
+ var child = n.firstChild;
+
+ // WebKit inserts a DIV container with lots of odd styles
+ if (child && child.nodeName == 'DIV' && child.style.marginTop && child.style.backgroundColor) {
+ dom.remove(child, 1);
+ }
+
+ // Remove apply style spans
+ each(dom.select('span.Apple-style-span', n), function(n) {
+ dom.remove(n, 1);
+ });
+
+ // Remove bogus br elements
+ each(dom.select('br[data-mce-bogus]', n), function(n) {
+ dom.remove(n);
+ });
+
+ // WebKit will make a copy of the DIV for each line of plain text pasted and insert them into the DIV
+ if (n.parentNode.className != 'mcePaste')
+ h += n.innerHTML;
+ });
+ } else {
+ // Found WebKit weirdness so force the content into paragraphs this seems to happen when you paste plain text from Nodepad etc
+ // So this logic will replace double enter with paragraphs and single enter with br so it kind of looks the same
+ h = '<p>' + dom.encode(textContent).replace(/\r?\n\r?\n/g, '</p><p>').replace(/\r?\n/g, '<br />') + '</p>';
+ }
+
+ // Remove the nodes
+ each(dom.select('div.mcePaste'), function(n) {
+ dom.remove(n);
+ });
+
+ // Restore the old selection
+ if (or)
+ sel.setRng(or);
+
+ process({content : h});
+
+ // Unblock events ones we got the contents
+ dom.unbind(ed.getDoc(), 'mousedown', block);
+ dom.unbind(ed.getDoc(), 'keydown', block);
+ }, 0);
+ }
+ }
+
+ // Check if we should use the new auto process method
+ if (getParam(ed, "paste_auto_cleanup_on_paste")) {
+ // Is it's Opera or older FF use key handler
+ if (tinymce.isOpera || /Firefox\/2/.test(navigator.userAgent)) {
+ ed.onKeyDown.addToTop(function(ed, e) {
+ if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
+ grabContent(e);
+ });
+ } else {
+ // Grab contents on paste event on Gecko and WebKit
+ ed.onPaste.addToTop(function(ed, e) {
+ return grabContent(e);
+ });
+ }
+ }
+
+ ed.onInit.add(function() {
+ ed.controlManager.setActive("pastetext", ed.pasteAsPlainText);
+
+ // Block all drag/drop events
+ if (getParam(ed, "paste_block_drop")) {
+ ed.dom.bind(ed.getBody(), ['dragend', 'dragover', 'draggesture', 'dragdrop', 'drop', 'drag'], function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+
+ return false;
+ });
+ }
+ });
+
+ // Add legacy support
+ t._legacySupport();
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Paste text/word',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ _preProcess : function(pl, o) {
+ var ed = this.editor,
+ h = o.content,
+ grep = tinymce.grep,
+ explode = tinymce.explode,
+ trim = tinymce.trim,
+ len, stripClass;
+
+ //console.log('Before preprocess:' + o.content);
+
+ function process(items) {
+ each(items, function(v) {
+ // Remove or replace
+ if (v.constructor == RegExp)
+ h = h.replace(v, '');
+ else
+ h = h.replace(v[0], v[1]);
+ });
+ }
+
+ if (ed.settings.paste_enable_default_filters == false) {
+ return;
+ }
+
+ // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser
+ if (tinymce.isIE && document.documentMode >= 9 && /<(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)/.test(o.content)) {
+ // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser
+ process([[/(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g, '$1']]);
+
+ // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
+ process([
+ [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
+ [/<br>/g, ' '], // Replace single br elements with space since they are word wrap BR:s
+ [/<BR><BR>/g, '<br>'] // Replace back the double brs but into a single BR
+ ]);
+ }
+
+ // Detect Word content and process it more aggressive
+ if (/class="?Mso|style="[^"]*\bmso-|w:WordDocument/i.test(h) || o.wordContent) {
+ o.wordContent = true; // Mark the pasted contents as word specific content
+ //console.log('Word contents detected.');
+
+ // Process away some basic content
+ process([
+ /^\s*(&nbsp;)+/gi, // &nbsp; entities at the start of contents
+ /(&nbsp;|<br[^>]*>)+\s*$/gi // &nbsp; entities at the end of contents
+ ]);
+
+ if (getParam(ed, "paste_convert_headers_to_strong")) {
+ h = h.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>");
+ }
+
+ if (getParam(ed, "paste_convert_middot_lists")) {
+ process([
+ [/<!--\[if !supportLists\]-->/gi, '$&__MCE_ITEM__'], // Convert supportLists to a list item marker
+ [/(<span[^>]+(?:mso-list:|:\s*symbol)[^>]+>)/gi, '$1__MCE_ITEM__'], // Convert mso-list and symbol spans to item markers
+ [/(<p[^>]+(?:MsoListParagraph)[^>]+>)/gi, '$1__MCE_ITEM__'] // Convert mso-list and symbol paragraphs to item markers (FF)
+ ]);
+ }
+
+ process([
+ // Word comments like conditional comments etc
+ /<!--[\s\S]+?-->/gi,
+
+ // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content, MS Office namespaced tags, and a few other tags
+ /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
+
+ // Convert <s> into <strike> for line-though
+ [/<(\/?)s>/gi, "<$1strike>"],
+
+ // Replace nsbp entites to char since it's easier to handle
+ [/&nbsp;/gi, "\u00a0"]
+ ]);
+
+ // Remove bad attributes, with or without quotes, ensuring that attribute text is really inside a tag.
+ // If JavaScript had a RegExp look-behind, we could have integrated this with the last process() array and got rid of the loop. But alas, it does not, so we cannot.
+ do {
+ len = h.length;
+ h = h.replace(/(<[a-z][^>]*\s)(?:id|name|language|type|on\w+|\w+:\w+)=(?:"[^"]*"|\w+)\s?/gi, "$1");
+ } while (len != h.length);
+
+ // Remove all spans if no styles is to be retained
+ if (getParam(ed, "paste_retain_style_properties").replace(/^none$/i, "").length == 0) {
+ h = h.replace(/<\/?span[^>]*>/gi, "");
+ } else {
+ // We're keeping styles, so at least clean them up.
+ // CSS Reference: http://msdn.microsoft.com/en-us/library/aa155477.aspx
+
+ process([
+ // Convert <span style="mso-spacerun:yes">___</span> to string of alternating breaking/non-breaking spaces of same length
+ [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
+ function(str, spaces) {
+ return (spaces.length > 0)? spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : "";
+ }
+ ],
+
+ // Examine all styles: delete junk, transform some, and keep the rest
+ [/(<[a-z][^>]*)\sstyle="([^"]*)"/gi,
+ function(str, tag, style) {
+ var n = [],
+ i = 0,
+ s = explode(trim(style).replace(/&quot;/gi, "'"), ";");
+
+ // Examine each style definition within the tag's style attribute
+ each(s, function(v) {
+ var name, value,
+ parts = explode(v, ":");
+
+ function ensureUnits(v) {
+ return v + ((v !== "0") && (/\d$/.test(v)))? "px" : "";
+ }
+
+ if (parts.length == 2) {
+ name = parts[0].toLowerCase();
+ value = parts[1].toLowerCase();
+
+ // Translate certain MS Office styles into their CSS equivalents
+ switch (name) {
+ case "mso-padding-alt":
+ case "mso-padding-top-alt":
+ case "mso-padding-right-alt":
+ case "mso-padding-bottom-alt":
+ case "mso-padding-left-alt":
+ case "mso-margin-alt":
+ case "mso-margin-top-alt":
+ case "mso-margin-right-alt":
+ case "mso-margin-bottom-alt":
+ case "mso-margin-left-alt":
+ case "mso-table-layout-alt":
+ case "mso-height":
+ case "mso-width":
+ case "mso-vertical-align-alt":
+ n[i++] = name.replace(/^mso-|-alt$/g, "") + ":" + ensureUnits(value);
+ return;
+
+ case "horiz-align":
+ n[i++] = "text-align:" + value;
+ return;
+
+ case "vert-align":
+ n[i++] = "vertical-align:" + value;
+ return;
+
+ case "font-color":
+ case "mso-foreground":
+ n[i++] = "color:" + value;
+ return;
+
+ case "mso-background":
+ case "mso-highlight":
+ n[i++] = "background:" + value;
+ return;
+
+ case "mso-default-height":
+ n[i++] = "min-height:" + ensureUnits(value);
+ return;
+
+ case "mso-default-width":
+ n[i++] = "min-width:" + ensureUnits(value);
+ return;
+
+ case "mso-padding-between-alt":
+ n[i++] = "border-collapse:separate;border-spacing:" + ensureUnits(value);
+ return;
+
+ case "text-line-through":
+ if ((value == "single") || (value == "double")) {
+ n[i++] = "text-decoration:line-through";
+ }
+ return;
+
+ case "mso-zero-height":
+ if (value == "yes") {
+ n[i++] = "display:none";
+ }
+ return;
+ }
+
+ // Eliminate all MS Office style definitions that have no CSS equivalent by examining the first characters in the name
+ if (/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/.test(name)) {
+ return;
+ }
+
+ // If it reached this point, it must be a valid CSS style
+ n[i++] = name + ":" + parts[1]; // Lower-case name, but keep value case
+ }
+ });
+
+ // If style attribute contained any valid styles the re-write it; otherwise delete style attribute.
+ if (i > 0) {
+ return tag + ' style="' + n.join(';') + '"';
+ } else {
+ return tag;
+ }
+ }
+ ]
+ ]);
+ }
+ }
+
+ // Replace headers with <strong>
+ if (getParam(ed, "paste_convert_headers_to_strong")) {
+ process([
+ [/<h[1-6][^>]*>/gi, "<p><strong>"],
+ [/<\/h[1-6][^>]*>/gi, "</strong></p>"]
+ ]);
+ }
+
+ process([
+ // Copy paste from Java like Open Office will produce this junk on FF
+ [/Version:[\d.]+\nStartHTML:\d+\nEndHTML:\d+\nStartFragment:\d+\nEndFragment:\d+/gi, '']
+ ]);
+
+ // Class attribute options are: leave all as-is ("none"), remove all ("all"), or remove only those starting with mso ("mso").
+ // Note:- paste_strip_class_attributes: "none", verify_css_classes: true is also a good variation.
+ stripClass = getParam(ed, "paste_strip_class_attributes");
+
+ if (stripClass !== "none") {
+ function removeClasses(match, g1) {
+ if (stripClass === "all")
+ return '';
+
+ var cls = grep(explode(g1.replace(/^(["'])(.*)\1$/, "$2"), " "),
+ function(v) {
+ return (/^(?!mso)/i.test(v));
+ }
+ );
+
+ return cls.length ? ' class="' + cls.join(" ") + '"' : '';
+ };
+
+ h = h.replace(/ class="([^"]+)"/gi, removeClasses);
+ h = h.replace(/ class=([\-\w]+)/gi, removeClasses);
+ }
+
+ // Remove spans option
+ if (getParam(ed, "paste_remove_spans")) {
+ h = h.replace(/<\/?span[^>]*>/gi, "");
+ }
+
+ //console.log('After preprocess:' + h);
+
+ o.content = h;
+ },
+
+ /**
+ * Various post process items.
+ */
+ _postProcess : function(pl, o) {
+ var t = this, ed = t.editor, dom = ed.dom, styleProps;
+
+ if (ed.settings.paste_enable_default_filters == false) {
+ return;
+ }
+
+ if (o.wordContent) {
+ // Remove named anchors or TOC links
+ each(dom.select('a', o.node), function(a) {
+ if (!a.href || a.href.indexOf('#_Toc') != -1)
+ dom.remove(a, 1);
+ });
+
+ if (getParam(ed, "paste_convert_middot_lists")) {
+ t._convertLists(pl, o);
+ }
+
+ // Process styles
+ styleProps = getParam(ed, "paste_retain_style_properties"); // retained properties
+
+ // Process only if a string was specified and not equal to "all" or "*"
+ if ((tinymce.is(styleProps, "string")) && (styleProps !== "all") && (styleProps !== "*")) {
+ styleProps = tinymce.explode(styleProps.replace(/^none$/i, ""));
+
+ // Retains some style properties
+ each(dom.select('*', o.node), function(el) {
+ var newStyle = {}, npc = 0, i, sp, sv;
+
+ // Store a subset of the existing styles
+ if (styleProps) {
+ for (i = 0; i < styleProps.length; i++) {
+ sp = styleProps[i];
+ sv = dom.getStyle(el, sp);
+
+ if (sv) {
+ newStyle[sp] = sv;
+ npc++;
+ }
+ }
+ }
+
+ // Remove all of the existing styles
+ dom.setAttrib(el, 'style', '');
+
+ if (styleProps && npc > 0)
+ dom.setStyles(el, newStyle); // Add back the stored subset of styles
+ else // Remove empty span tags that do not have class attributes
+ if (el.nodeName == 'SPAN' && !el.className)
+ dom.remove(el, true);
+ });
+ }
+ }
+
+ // Remove all style information or only specifically on WebKit to avoid the style bug on that browser
+ if (getParam(ed, "paste_remove_styles") || (getParam(ed, "paste_remove_styles_if_webkit") && tinymce.isWebKit)) {
+ each(dom.select('*[style]', o.node), function(el) {
+ el.removeAttribute('style');
+ el.removeAttribute('data-mce-style');
+ });
+ } else {
+ if (tinymce.isWebKit) {
+ // We need to compress the styles on WebKit since if you paste <img border="0" /> it will become <img border="0" style="... lots of junk ..." />
+ // Removing the mce_style that contains the real value will force the Serializer engine to compress the styles
+ each(dom.select('*', o.node), function(el) {
+ el.removeAttribute('data-mce-style');
+ });
+ }
+ }
+ },
+
+ /**
+ * Converts the most common bullet and number formats in Office into a real semantic UL/LI list.
+ */
+ _convertLists : function(pl, o) {
+ var dom = pl.editor.dom, listElm, li, lastMargin = -1, margin, levels = [], lastType, html;
+
+ // Convert middot lists into real semantic lists
+ each(dom.select('p', o.node), function(p) {
+ var sib, val = '', type, html, idx, parents;
+
+ // Get text node value at beginning of paragraph
+ for (sib = p.firstChild; sib && sib.nodeType == 3; sib = sib.nextSibling)
+ val += sib.nodeValue;
+
+ val = p.innerHTML.replace(/<\/?\w+[^>]*>/gi, '').replace(/&nbsp;/g, '\u00a0');
+
+ // Detect unordered lists look for bullets
+ if (/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*\u00a0*/.test(val))
+ type = 'ul';
+
+ // Detect ordered lists 1., a. or ixv.
+ if (/^__MCE_ITEM__\s*\w+\.\s*\u00a0+/.test(val))
+ type = 'ol';
+
+ // Check if node value matches the list pattern: o&nbsp;&nbsp;
+ if (type) {
+ margin = parseFloat(p.style.marginLeft || 0);
+
+ if (margin > lastMargin)
+ levels.push(margin);
+
+ if (!listElm || type != lastType) {
+ listElm = dom.create(type);
+ dom.insertAfter(listElm, p);
+ } else {
+ // Nested list element
+ if (margin > lastMargin) {
+ listElm = li.appendChild(dom.create(type));
+ } else if (margin < lastMargin) {
+ // Find parent level based on margin value
+ idx = tinymce.inArray(levels, margin);
+ parents = dom.getParents(listElm.parentNode, type);
+ listElm = parents[parents.length - 1 - idx] || listElm;
+ }
+ }
+
+ // Remove middot or number spans if they exists
+ each(dom.select('span', p), function(span) {
+ var html = span.innerHTML.replace(/<\/?\w+[^>]*>/gi, '');
+
+ // Remove span with the middot or the number
+ if (type == 'ul' && /^__MCE_ITEM__[\u2022\u00b7\u00a7\u00d8o\u25CF]/.test(html))
+ dom.remove(span);
+ else if (/^__MCE_ITEM__[\s\S]*\w+\.(&nbsp;|\u00a0)*\s*/.test(html))
+ dom.remove(span);
+ });
+
+ html = p.innerHTML;
+
+ // Remove middot/list items
+ if (type == 'ul')
+ html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*(&nbsp;|\u00a0)+\s*/, '');
+ else
+ html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^\s*\w+\.(&nbsp;|\u00a0)+\s*/, '');
+
+ // Create li and add paragraph data into the new li
+ li = listElm.appendChild(dom.create('li', 0, html));
+ dom.remove(p);
+
+ lastMargin = margin;
+ lastType = type;
+ } else
+ listElm = lastMargin = 0; // End list element
+ });
+
+ // Remove any left over makers
+ html = o.node.innerHTML;
+ if (html.indexOf('__MCE_ITEM__') != -1)
+ o.node.innerHTML = html.replace(/__MCE_ITEM__/g, '');
+ },
+
+ /**
+ * Inserts the specified contents at the caret position.
+ */
+ _insert : function(h, skip_undo) {
+ var ed = this.editor, r = ed.selection.getRng();
+
+ // First delete the contents seems to work better on WebKit when the selection spans multiple list items or multiple table cells.
+ if (!ed.selection.isCollapsed() && r.startContainer != r.endContainer)
+ ed.getDoc().execCommand('Delete', false, null);
+
+ ed.execCommand('mceInsertContent', false, h, {skip_undo : skip_undo});
+ },
+
+ /**
+ * Instead of the old plain text method which tried to re-create a paste operation, the
+ * new approach adds a plain text mode toggle switch that changes the behavior of paste.
+ * This function is passed the same input that the regular paste plugin produces.
+ * It performs additional scrubbing and produces (and inserts) the plain text.
+ * This approach leverages all of the great existing functionality in the paste
+ * plugin, and requires minimal changes to add the new functionality.
+ * Speednet - June 2009
+ */
+ _insertPlainText : function(content) {
+ var ed = this.editor,
+ linebr = getParam(ed, "paste_text_linebreaktype"),
+ rl = getParam(ed, "paste_text_replacements"),
+ is = tinymce.is;
+
+ function process(items) {
+ each(items, function(v) {
+ if (v.constructor == RegExp)
+ content = content.replace(v, "");
+ else
+ content = content.replace(v[0], v[1]);
+ });
+ };
+
+ if ((typeof(content) === "string") && (content.length > 0)) {
+ // If HTML content with line-breaking tags, then remove all cr/lf chars because only tags will break a line
+ if (/<(?:p|br|h[1-6]|ul|ol|dl|table|t[rdh]|div|blockquote|fieldset|pre|address|center)[^>]*>/i.test(content)) {
+ process([
+ /[\n\r]+/g
+ ]);
+ } else {
+ // Otherwise just get rid of carriage returns (only need linefeeds)
+ process([
+ /\r+/g
+ ]);
+ }
+
+ process([
+ [/<\/(?:p|h[1-6]|ul|ol|dl|table|div|blockquote|fieldset|pre|address|center)>/gi, "\n\n"], // Block tags get a blank line after them
+ [/<br[^>]*>|<\/tr>/gi, "\n"], // Single linebreak for <br /> tags and table rows
+ [/<\/t[dh]>\s*<t[dh][^>]*>/gi, "\t"], // Table cells get tabs betweem them
+ /<[a-z!\/?][^>]*>/gi, // Delete all remaining tags
+ [/&nbsp;/gi, " "], // Convert non-break spaces to regular spaces (remember, *plain text*)
+ [/(?:(?!\n)\s)*(\n+)(?:(?!\n)\s)*/gi, "$1"] // Cool little RegExp deletes whitespace around linebreak chars.
+ ]);
+
+ var maxLinebreaks = Number(getParam(ed, "paste_max_consecutive_linebreaks"));
+ if (maxLinebreaks > -1) {
+ var maxLinebreaksRegex = new RegExp("\n{" + (maxLinebreaks + 1) + ",}", "g");
+ var linebreakReplacement = "";
+
+ while (linebreakReplacement.length < maxLinebreaks) {
+ linebreakReplacement += "\n";
+ }
+
+ process([
+ [maxLinebreaksRegex, linebreakReplacement] // Limit max consecutive linebreaks
+ ]);
+ }
+
+ content = ed.dom.decode(tinymce.html.Entities.encodeRaw(content));
+
+ // Perform default or custom replacements
+ if (is(rl, "array")) {
+ process(rl);
+ } else if (is(rl, "string")) {
+ process(new RegExp(rl, "gi"));
+ }
+
+ // Treat paragraphs as specified in the config
+ if (linebr == "none") {
+ // Convert all line breaks to space
+ process([
+ [/\n+/g, " "]
+ ]);
+ } else if (linebr == "br") {
+ // Convert all line breaks to <br />
+ process([
+ [/\n/g, "<br />"]
+ ]);
+ } else if (linebr == "p") {
+ // Convert all line breaks to <p>...</p>
+ process([
+ [/\n+/g, "</p><p>"],
+ [/^(.*<\/p>)(<p>)$/, '<p>$1']
+ ]);
+ } else {
+ // defaults to "combined"
+ // Convert single line breaks to <br /> and double line breaks to <p>...</p>
+ process([
+ [/\n\n/g, "</p><p>"],
+ [/^(.*<\/p>)(<p>)$/, '<p>$1'],
+ [/\n/g, "<br />"]
+ ]);
+ }
+
+ ed.execCommand('mceInsertContent', false, content);
+ }
+ },
+
+ /**
+ * This method will open the old style paste dialogs. Some users might want the old behavior but still use the new cleanup engine.
+ */
+ _legacySupport : function() {
+ var t = this, ed = t.editor;
+
+ // Register command(s) for backwards compatibility
+ ed.addCommand("mcePasteWord", function() {
+ ed.windowManager.open({
+ file: t.url + "/pasteword.htm",
+ width: parseInt(getParam(ed, "paste_dialog_width")),
+ height: parseInt(getParam(ed, "paste_dialog_height")),
+ inline: 1
+ });
+ });
+
+ if (getParam(ed, "paste_text_use_dialog")) {
+ ed.addCommand("mcePasteText", function() {
+ ed.windowManager.open({
+ file : t.url + "/pastetext.htm",
+ width: parseInt(getParam(ed, "paste_dialog_width")),
+ height: parseInt(getParam(ed, "paste_dialog_height")),
+ inline : 1
+ });
+ });
+ }
+
+ // Register button for backwards compatibility
+ ed.addButton("pasteword", {title : "paste.paste_word_desc", cmd : "mcePasteWord"});
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add("paste", tinymce.plugins.PastePlugin);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/paste/js/pastetext.js b/src/wp-includes/js/tinymce/plugins/paste/js/pastetext.js
new file mode 100644
index 0000000000..81b1d6a01e
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/paste/js/pastetext.js
@@ -0,0 +1,36 @@
+tinyMCEPopup.requireLangPack();
+
+var PasteTextDialog = {
+ init : function() {
+ this.resize();
+ },
+
+ insert : function() {
+ var h = tinyMCEPopup.dom.encode(document.getElementById('content').value), lines;
+
+ // Convert linebreaks into paragraphs
+ if (document.getElementById('linebreaks').checked) {
+ lines = h.split(/\r?\n/);
+ if (lines.length > 1) {
+ h = '';
+ tinymce.each(lines, function(row) {
+ h += '<p>' + row + '</p>';
+ });
+ }
+ }
+
+ tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, {content : h});
+ tinyMCEPopup.close();
+ },
+
+ resize : function() {
+ var vp = tinyMCEPopup.dom.getViewPort(window), el;
+
+ el = document.getElementById('content');
+
+ el.style.width = (vp.w - 20) + 'px';
+ el.style.height = (vp.h - 90) + 'px';
+ }
+};
+
+tinyMCEPopup.onInit.add(PasteTextDialog.init, PasteTextDialog);
diff --git a/src/wp-includes/js/tinymce/plugins/paste/js/pasteword.js b/src/wp-includes/js/tinymce/plugins/paste/js/pasteword.js
new file mode 100644
index 0000000000..959bf3992d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/paste/js/pasteword.js
@@ -0,0 +1,51 @@
+tinyMCEPopup.requireLangPack();
+
+var PasteWordDialog = {
+ init : function() {
+ var ed = tinyMCEPopup.editor, el = document.getElementById('iframecontainer'), ifr, doc, css, cssHTML = '';
+
+ // Create iframe
+ el.innerHTML = '<iframe id="iframe" src="javascript:\'\';" frameBorder="0" style="border: 1px solid gray"></iframe>';
+ ifr = document.getElementById('iframe');
+ doc = ifr.contentWindow.document;
+
+ // Force absolute CSS urls
+ css = [ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css")];
+ css = css.concat(tinymce.explode(ed.settings.content_css) || []);
+ tinymce.each(css, function(u) {
+ cssHTML += '<link href="' + ed.documentBaseURI.toAbsolute('' + u) + '" rel="stylesheet" type="text/css" />';
+ });
+
+ // Write content into iframe
+ doc.open();
+ doc.write('<html><head>' + cssHTML + '</head><body class="mceContentBody" spellcheck="false"></body></html>');
+ doc.close();
+
+ doc.designMode = 'on';
+ this.resize();
+
+ window.setTimeout(function() {
+ ifr.contentWindow.focus();
+ }, 10);
+ },
+
+ insert : function() {
+ var h = document.getElementById('iframe').contentWindow.document.body.innerHTML;
+
+ tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, {content : h, wordContent : true});
+ tinyMCEPopup.close();
+ },
+
+ resize : function() {
+ var vp = tinyMCEPopup.dom.getViewPort(window), el;
+
+ el = document.getElementById('iframe');
+
+ if (el) {
+ el.style.width = (vp.w - 20) + 'px';
+ el.style.height = (vp.h - 90) + 'px';
+ }
+ }
+};
+
+tinyMCEPopup.onInit.add(PasteWordDialog.init, PasteWordDialog);
diff --git a/src/wp-includes/js/tinymce/plugins/paste/pastetext.htm b/src/wp-includes/js/tinymce/plugins/paste/pastetext.htm
new file mode 100644
index 0000000000..a1f735890c
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/paste/pastetext.htm
@@ -0,0 +1,27 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#paste.paste_text_desc}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/pastetext.js?ver=358-20121205"></script>
+</head>
+<body onresize="PasteTextDialog.resize();" style="display:none; overflow:hidden;">
+ <form name="source" onsubmit="return PasteTextDialog.insert();" action="#">
+ <div style="float: left" class="title">{#paste.paste_text_desc}</div>
+
+ <div style="float: right">
+ <input type="checkbox" name="linebreaks" id="linebreaks" class="wordWrapCode" checked="checked" /><label for="linebreaks">{#paste_dlg.text_linebreaks}</label>
+ </div>
+
+ <br style="clear: both" />
+
+ <div>{#paste_dlg.text_title}</div>
+
+ <textarea id="content" name="content" rows="15" cols="100" style="width: 100%; height: 100%; font-family: 'Courier New',Courier,mono; font-size: 12px;" dir="ltr" wrap="soft" class="mceFocus"></textarea>
+
+ <div class="mceActionPanel">
+ <input type="submit" name="insert" value="{#insert}" id="insert" />
+ <input type="button" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" id="cancel" />
+ </div>
+ </form>
+</body>
+</html> \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/paste/pasteword.htm b/src/wp-includes/js/tinymce/plugins/paste/pasteword.htm
new file mode 100644
index 0000000000..0cfef68193
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/paste/pasteword.htm
@@ -0,0 +1,21 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#paste.paste_word_desc}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/pasteword.js?ver=358-20121205"></script>
+</head>
+<body onresize="PasteWordDialog.resize();" style="display:none; overflow:hidden;">
+ <form name="source" onsubmit="return PasteWordDialog.insert();" action="#">
+ <div class="title">{#paste.paste_word_desc}</div>
+
+ <div>{#paste_dlg.word_title}</div>
+
+ <div id="iframecontainer"></div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt b/src/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt
new file mode 100644
index 0000000000..f41ec7fdb1
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/changelog.txt
@@ -0,0 +1,33 @@
+Version 2.0.6 (2011-09-29)
+ Fixed incorrect position of suggestion menu.
+ Fixed handling of mispelled words with no suggestions in PSpellShell engine.
+ Fixed PSpellShell command on Windows.
+ Fixed bug where Javascript error is produced when enchant_dict_suggest() returns unexpected result.
+Version 2.0.5 (2011-03-24)
+ Merged with the latest TinyMCE spellchecker version.
+Version 2.0.4 (2010-12-20)
+ Fixed issue with the JSON class not having the correct number of parameters to ord calls.
+Version 2.0.3 (2010-04-19)
+ Added standalone support. Will use native spellchecker for supported browsers.
+ Added @package phpdoc comments. Patch contributed by Jacob Santos.
+ Fixed some PHP missing function issue.
+Version 2.0.2 (2008-04-30)
+ Added new EnchantSpell engine class contributed by Michel Weimerskirch.
+ Added new general.remote_rpc_url option, enables you to proxy requests to another server.
+ Fixed security hole in PSpellShell.php file if PSpellShell engine was used.
+Version 2.0.1 (2008-03-07)
+ Fixed bug where spellchecker was auto focusing the editor in IE.
+Version 2.0 (2008-01-30)
+ Fixed bug where the suggestions menu was placed at an incorrect location.
+Version 2.0rc1 (2008-01-14)
+ Moved package from beta to release candidate.
+Version 2.0b3 (2007-12-xx)
+ Fixed bug where the suggestions menu could appear at the wrong location.
+Version 2.0b2 (2007-11-29)
+ Fixed bug where the spellchecker was removing the word when it was ignored.
+Version 2.0b1 (2007-11-21)
+ Moved spellchecker from alpha to beta status.
+Version 2.0a2 (2007-11-13)
+ Updated plugin so it works correctly with the TinyMCE 3.0a3 version.
+Version 2.0a1 (2007-11-01)
+ Rewritten version for TinyMCE 3.0 this new version uses JSON RPC.
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php
new file mode 100644
index 0000000000..cefc8cf2ce
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/EnchantSpell.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * This class was contributed by Michel Weimerskirch.
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+class EnchantSpell extends SpellChecker {
+ /**
+ * Spellchecks an array of words.
+ *
+ * @param String $lang Selected language code (like en_US or de_DE). Shortcodes like "en" and "de" work with enchant >= 1.4.1
+ * @param Array $words Array of words to check.
+ * @return Array of misspelled words.
+ */
+ function &checkWords($lang, $words) {
+ $r = enchant_broker_init();
+
+ if (enchant_broker_dict_exists($r,$lang)) {
+ $d = enchant_broker_request_dict($r, $lang);
+
+ $returnData = array();
+ foreach($words as $key => $value) {
+ $correct = enchant_dict_check($d, $value);
+ if(!$correct) {
+ $returnData[] = trim($value);
+ }
+ }
+
+ return $returnData;
+ enchant_broker_free_dict($d);
+ } else {
+
+ }
+ enchant_broker_free($r);
+ }
+
+ /**
+ * Returns suggestions for a specific word.
+ *
+ * @param String $lang Selected language code (like en_US or de_DE). Shortcodes like "en" and "de" work with enchant >= 1.4.1
+ * @param String $word Specific word to get suggestions for.
+ * @return Array of suggestions for the specified word.
+ */
+ function &getSuggestions($lang, $word) {
+ $r = enchant_broker_init();
+
+ if (enchant_broker_dict_exists($r,$lang)) {
+ $d = enchant_broker_request_dict($r, $lang);
+ $suggs = enchant_dict_suggest($d, $word);
+
+ // enchant_dict_suggest() sometimes returns NULL
+ if (!is_array($suggs))
+ $suggs = array();
+
+ enchant_broker_free_dict($d);
+ } else {
+ $suggs = array();
+ }
+
+ enchant_broker_free($r);
+
+ return $suggs;
+ }
+}
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php
new file mode 100644
index 0000000000..03e4a7848e
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/GoogleSpell.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+class GoogleSpell extends SpellChecker {
+ /**
+ * Spellchecks an array of words.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {Array} $words Array of words to spellcheck.
+ * @return {Array} Array of misspelled words.
+ */
+ function &checkWords($lang, $words) {
+ $wordstr = implode(' ', $words);
+ $matches = $this->_getMatches($lang, $wordstr);
+ $words = array();
+
+ for ($i=0; $i<count($matches); $i++)
+ $words[] = $this->_unhtmlentities(mb_substr($wordstr, $matches[$i][1], $matches[$i][2], "UTF-8"));
+
+ return $words;
+ }
+
+ /**
+ * Returns suggestions of for a specific word.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {String} $word Specific word to get suggestions for.
+ * @return {Array} Array of suggestions for the specified word.
+ */
+ function &getSuggestions($lang, $word) {
+ $sug = array();
+ $osug = array();
+ $matches = $this->_getMatches($lang, $word);
+
+ if (count($matches) > 0)
+ $sug = explode("\t", utf8_encode($this->_unhtmlentities($matches[0][4])));
+
+ // Remove empty
+ foreach ($sug as $item) {
+ if ($item)
+ $osug[] = $item;
+ }
+
+ return $osug;
+ }
+
+ protected function &_getMatches($lang, $str) {
+ $lang = preg_replace('/[^a-z\-]/i', '', $lang);
+ $str = preg_replace('/[\x00-\x1F\x7F]/', '', $str);
+ $server = "www.google.com";
+ $port = 443;
+ $path = "/tbproxy/spell?lang=" . $lang . "&hl=en";
+ $host = "www.google.com";
+ $url = "https://" . $server;
+
+ // Setup XML request
+ $xml = '<?xml version="1.0" encoding="utf-8" ?><spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1"><text>' . $str . '</text></spellrequest>';
+
+ $header = "POST ".$path." HTTP/1.0 \r\n";
+ $header .= "MIME-Version: 1.0 \r\n";
+ $header .= "Content-type: application/PTI26 \r\n";
+ $header .= "Content-length: ".strlen($xml)." \r\n";
+ $header .= "Content-transfer-encoding: text \r\n";
+ $header .= "Request-number: 1 \r\n";
+ $header .= "Document-type: Request \r\n";
+ $header .= "Interface-Version: Test 1.4 \r\n";
+ $header .= "Connection: close \r\n\r\n";
+ $header .= $xml;
+
+ // Use curl if it exists
+ if (function_exists('curl_init')) {
+ // Use curl
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL,$url);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $header);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+ $xml = curl_exec($ch);
+ curl_close($ch);
+ } else {
+ // Use raw sockets
+ $fp = fsockopen("ssl://" . $server, $port, $errno, $errstr, 30);
+ if ($fp) {
+ // Send request
+ fwrite($fp, $header);
+
+ // Read response
+ $xml = "";
+ while (!feof($fp))
+ $xml .= fgets($fp, 128);
+
+ fclose($fp);
+ } else
+ echo "Could not open SSL connection to google.";
+ }
+
+ // Grab and parse content
+ $matches = array();
+ preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $xml, $matches, PREG_SET_ORDER);
+
+ return $matches;
+ }
+
+ protected function _unhtmlentities($string) {
+ $string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
+ $string = preg_replace('~&#([0-9]+);~e', 'chr(\\1)', $string);
+
+ $trans_tbl = get_html_translation_table(HTML_ENTITIES);
+ $trans_tbl = array_flip($trans_tbl);
+
+ return strtr($string, $trans_tbl);
+ }
+}
+
+// Patch in multibyte support
+if (!function_exists('mb_substr')) {
+ function mb_substr($str, $start, $len = '', $encoding="UTF-8"){
+ $limit = strlen($str);
+
+ for ($s = 0; $start > 0;--$start) {// found the real start
+ if ($s >= $limit)
+ break;
+
+ if ($str[$s] <= "\x7F")
+ ++$s;
+ else {
+ ++$s; // skip length
+
+ while ($str[$s] >= "\x80" && $str[$s] <= "\xBF")
+ ++$s;
+ }
+ }
+
+ if ($len == '')
+ return substr($str, $s);
+ else
+ for ($e = $s; $len > 0; --$len) {//found the real end
+ if ($e >= $limit)
+ break;
+
+ if ($str[$e] <= "\x7F")
+ ++$e;
+ else {
+ ++$e;//skip length
+
+ while ($str[$e] >= "\x80" && $str[$e] <= "\xBF" && $e < $limit)
+ ++$e;
+ }
+ }
+
+ return substr($str, $s, $e - $s);
+ }
+}
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php
new file mode 100644
index 0000000000..3c6424d86e
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpell.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+class PSpell extends SpellChecker {
+ /**
+ * Spellchecks an array of words.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {Array} $words Array of words to spellcheck.
+ * @return {Array} Array of misspelled words.
+ */
+ function &checkWords($lang, $words) {
+ $plink = $this->_getPLink($lang);
+
+ $outWords = array();
+ foreach ($words as $word) {
+ if (!pspell_check($plink, trim($word)))
+ $outWords[] = utf8_encode($word);
+ }
+
+ return $outWords;
+ }
+
+ /**
+ * Returns suggestions of for a specific word.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {String} $word Specific word to get suggestions for.
+ * @return {Array} Array of suggestions for the specified word.
+ */
+ function &getSuggestions($lang, $word) {
+ $words = pspell_suggest($this->_getPLink($lang), $word);
+
+ for ($i=0; $i<count($words); $i++)
+ $words[$i] = utf8_encode($words[$i]);
+
+ return $words;
+ }
+
+ /**
+ * Opens a link for pspell.
+ */
+ function &_getPLink($lang) {
+ // Check for native PSpell support
+ if (!function_exists("pspell_new"))
+ $this->throwError("PSpell support not found in PHP installation.");
+
+ // Setup PSpell link
+ $plink = pspell_new(
+ $lang,
+ $this->_config['PSpell.spelling'],
+ $this->_config['PSpell.jargon'],
+ $this->_config['PSpell.encoding'],
+ $this->_config['PSpell.mode']
+ );
+
+ // Setup PSpell link
+/* if (!$plink) {
+ $pspellConfig = pspell_config_create(
+ $lang,
+ $this->_config['PSpell.spelling'],
+ $this->_config['PSpell.jargon'],
+ $this->_config['PSpell.encoding']
+ );
+
+ $plink = pspell_new_config($pspell_config);
+ }*/
+
+ if (!$plink)
+ $this->throwError("No PSpell link found opened.");
+
+ return $plink;
+ }
+}
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php
new file mode 100644
index 0000000000..3d6d4a9a26
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/PSpellShell.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+class PSpellShell extends SpellChecker {
+ /**
+ * Spellchecks an array of words.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {Array} $words Array of words to spellcheck.
+ * @return {Array} Array of misspelled words.
+ */
+ function &checkWords($lang, $words) {
+ $cmd = $this->_getCMD($lang);
+
+ if ($fh = fopen($this->_tmpfile, "w")) {
+ fwrite($fh, "!\n");
+
+ foreach($words as $key => $value)
+ fwrite($fh, "^" . $value . "\n");
+
+ fclose($fh);
+ } else
+ $this->throwError("PSpell support was not found.");
+
+ $data = shell_exec($cmd);
+ @unlink($this->_tmpfile);
+
+ $returnData = array();
+ $dataArr = preg_split("/[\r\n]/", $data, -1, PREG_SPLIT_NO_EMPTY);
+
+ foreach ($dataArr as $dstr) {
+ $matches = array();
+
+ // Skip this line.
+ if ($dstr[0] == "@")
+ continue;
+
+ preg_match("/(\&|#) ([^ ]+) .*/i", $dstr, $matches);
+
+ if (!empty($matches[2]))
+ $returnData[] = utf8_encode(trim($matches[2]));
+ }
+
+ return $returnData;
+ }
+
+ /**
+ * Returns suggestions of for a specific word.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {String} $word Specific word to get suggestions for.
+ * @return {Array} Array of suggestions for the specified word.
+ */
+ function &getSuggestions($lang, $word) {
+ $cmd = $this->_getCMD($lang);
+
+ if (function_exists("mb_convert_encoding"))
+ $word = mb_convert_encoding($word, "ISO-8859-1", mb_detect_encoding($word, "UTF-8"));
+ else
+ $word = utf8_encode($word);
+
+ if ($fh = fopen($this->_tmpfile, "w")) {
+ fwrite($fh, "!\n");
+ fwrite($fh, "^$word\n");
+ fclose($fh);
+ } else
+ $this->throwError("Error opening tmp file.");
+
+ $data = shell_exec($cmd);
+ @unlink($this->_tmpfile);
+
+ $returnData = array();
+ $dataArr = preg_split("/\n/", $data, -1, PREG_SPLIT_NO_EMPTY);
+
+ foreach($dataArr as $dstr) {
+ $matches = array();
+
+ // Skip this line.
+ if ($dstr[0] == "@")
+ continue;
+
+ preg_match("/\&[^:]+:(.*)/i", $dstr, $matches);
+
+ if (!empty($matches[1])) {
+ $words = array_slice(explode(',', $matches[1]), 0, 10);
+
+ for ($i=0; $i<count($words); $i++)
+ $words[$i] = trim($words[$i]);
+
+ return $words;
+ }
+ }
+
+ return array();
+ }
+
+ function _getCMD($lang) {
+ $this->_tmpfile = tempnam($this->_config['PSpellShell.tmp'], "tinyspell");
+
+ $file = $this->_tmpfile;
+ $lang = preg_replace("/[^-_a-z]/", "", strtolower($lang));
+ $bin = $this->_config['PSpellShell.aspell'];
+
+ if (preg_match("#win#i", php_uname()))
+ return "$bin -a --lang=$lang --encoding=utf-8 -H < $file 2>&1";
+
+ return "cat $file | $bin -a --lang=$lang --encoding=utf-8 -H";
+ }
+}
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php
new file mode 100644
index 0000000000..5d9205fe6e
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/SpellChecker.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+class SpellChecker {
+ /**
+ * Constructor.
+ *
+ * @param $config Configuration name/value array.
+ */
+ function SpellChecker(&$config) {
+ $this->_config = $config;
+ }
+
+ /**
+ * Simple loopback function everything that gets in will be send back.
+ *
+ * @param $args.. Arguments.
+ * @return {Array} Array of all input arguments.
+ */
+ function &loopback(/* args.. */) {
+ return func_get_args();
+ }
+
+ /**
+ * Spellchecks an array of words.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {Array} $words Array of words to spellcheck.
+ * @return {Array} Array of misspelled words.
+ */
+ function &checkWords($lang, $words) {
+ return $words;
+ }
+
+ /**
+ * Returns suggestions of for a specific word.
+ *
+ * @param {String} $lang Language code like sv or en.
+ * @param {String} $word Specific word to get suggestions for.
+ * @return {Array} Array of suggestions for the specified word.
+ */
+ function &getSuggestions($lang, $word) {
+ return array();
+ }
+
+ /**
+ * Throws an error message back to the user. This will stop all execution.
+ *
+ * @param {String} $str Message to send back to user.
+ */
+ function throwError($str) {
+ die('{"result":null,"id":null,"error":{"errstr":"' . addslashes($str) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
+ }
+}
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php
new file mode 100644
index 0000000000..1f2b92caa2
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php
@@ -0,0 +1,595 @@
+<?php
+/**
+ * $Id: JSON.php 40 2007-06-18 11:43:15Z spocke $
+ *
+ * @package MCManager.utils
+ * @author Moxiecode
+ * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+define('JSON_BOOL', 1);
+define('JSON_INT', 2);
+define('JSON_STR', 3);
+define('JSON_FLOAT', 4);
+define('JSON_NULL', 5);
+define('JSON_START_OBJ', 6);
+define('JSON_END_OBJ', 7);
+define('JSON_START_ARRAY', 8);
+define('JSON_END_ARRAY', 9);
+define('JSON_KEY', 10);
+define('JSON_SKIP', 11);
+
+define('JSON_IN_ARRAY', 30);
+define('JSON_IN_OBJECT', 40);
+define('JSON_IN_BETWEEN', 50);
+
+class Moxiecode_JSONReader {
+ var $_data, $_len, $_pos;
+ var $_value, $_token;
+ var $_location, $_lastLocations;
+ var $_needProp;
+
+ function Moxiecode_JSONReader($data) {
+ $this->_data = $data;
+ $this->_len = strlen($data);
+ $this->_pos = -1;
+ $this->_location = JSON_IN_BETWEEN;
+ $this->_lastLocations = array();
+ $this->_needProp = false;
+ }
+
+ function getToken() {
+ return $this->_token;
+ }
+
+ function getLocation() {
+ return $this->_location;
+ }
+
+ function getTokenName() {
+ switch ($this->_token) {
+ case JSON_BOOL:
+ return 'JSON_BOOL';
+
+ case JSON_INT:
+ return 'JSON_INT';
+
+ case JSON_STR:
+ return 'JSON_STR';
+
+ case JSON_FLOAT:
+ return 'JSON_FLOAT';
+
+ case JSON_NULL:
+ return 'JSON_NULL';
+
+ case JSON_START_OBJ:
+ return 'JSON_START_OBJ';
+
+ case JSON_END_OBJ:
+ return 'JSON_END_OBJ';
+
+ case JSON_START_ARRAY:
+ return 'JSON_START_ARRAY';
+
+ case JSON_END_ARRAY:
+ return 'JSON_END_ARRAY';
+
+ case JSON_KEY:
+ return 'JSON_KEY';
+ }
+
+ return 'UNKNOWN';
+ }
+
+ function getValue() {
+ return $this->_value;
+ }
+
+ function readToken() {
+ $chr = $this->read();
+
+ if ($chr != null) {
+ switch ($chr) {
+ case '[':
+ $this->_lastLocation[] = $this->_location;
+ $this->_location = JSON_IN_ARRAY;
+ $this->_token = JSON_START_ARRAY;
+ $this->_value = null;
+ $this->readAway();
+ return true;
+
+ case ']':
+ $this->_location = array_pop($this->_lastLocation);
+ $this->_token = JSON_END_ARRAY;
+ $this->_value = null;
+ $this->readAway();
+
+ if ($this->_location == JSON_IN_OBJECT)
+ $this->_needProp = true;
+
+ return true;
+
+ case '{':
+ $this->_lastLocation[] = $this->_location;
+ $this->_location = JSON_IN_OBJECT;
+ $this->_needProp = true;
+ $this->_token = JSON_START_OBJ;
+ $this->_value = null;
+ $this->readAway();
+ return true;
+
+ case '}':
+ $this->_location = array_pop($this->_lastLocation);
+ $this->_token = JSON_END_OBJ;
+ $this->_value = null;
+ $this->readAway();
+
+ if ($this->_location == JSON_IN_OBJECT)
+ $this->_needProp = true;
+
+ return true;
+
+ // String
+ case '"':
+ case '\'':
+ return $this->_readString($chr);
+
+ // Null
+ case 'n':
+ return $this->_readNull();
+
+ // Bool
+ case 't':
+ case 'f':
+ return $this->_readBool($chr);
+
+ default:
+ // Is number
+ if (is_numeric($chr) || $chr == '-' || $chr == '.')
+ return $this->_readNumber($chr);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function _readBool($chr) {
+ $this->_token = JSON_BOOL;
+ $this->_value = $chr == 't';
+
+ if ($chr == 't')
+ $this->skip(3); // rue
+ else
+ $this->skip(4); // alse
+
+ $this->readAway();
+
+ if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+ $this->_needProp = true;
+
+ return true;
+ }
+
+ function _readNull() {
+ $this->_token = JSON_NULL;
+ $this->_value = null;
+
+ $this->skip(3); // ull
+ $this->readAway();
+
+ if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+ $this->_needProp = true;
+
+ return true;
+ }
+
+ function _readString($quote) {
+ $output = "";
+ $this->_token = JSON_STR;
+ $endString = false;
+
+ while (($chr = $this->peek()) != -1) {
+ switch ($chr) {
+ case '\\':
+ // Read away slash
+ $this->read();
+
+ // Read escape code
+ $chr = $this->read();
+ switch ($chr) {
+ case 't':
+ $output .= "\t";
+ break;
+
+ case 'b':
+ $output .= "\b";
+ break;
+
+ case 'f':
+ $output .= "\f";
+ break;
+
+ case 'r':
+ $output .= "\r";
+ break;
+
+ case 'n':
+ $output .= "\n";
+ break;
+
+ case 'u':
+ $output .= $this->_int2utf8(hexdec($this->read(4)));
+ break;
+
+ default:
+ $output .= $chr;
+ break;
+ }
+
+ break;
+
+ case '\'':
+ case '"':
+ if ($chr == $quote)
+ $endString = true;
+
+ $chr = $this->read();
+ if ($chr != -1 && $chr != $quote)
+ $output .= $chr;
+
+ break;
+
+ default:
+ $output .= $this->read();
+ }
+
+ // String terminated
+ if ($endString)
+ break;
+ }
+
+ $this->readAway();
+ $this->_value = $output;
+
+ // Needed a property
+ if ($this->_needProp) {
+ $this->_token = JSON_KEY;
+ $this->_needProp = false;
+ return true;
+ }
+
+ if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+ $this->_needProp = true;
+
+ return true;
+ }
+
+ function _int2utf8($int) {
+ $int = intval($int);
+
+ switch ($int) {
+ case 0:
+ return chr(0);
+
+ case ($int & 0x7F):
+ return chr($int);
+
+ case ($int & 0x7FF):
+ return chr(0xC0 | (($int >> 6) & 0x1F)) . chr(0x80 | ($int & 0x3F));
+
+ case ($int & 0xFFFF):
+ return chr(0xE0 | (($int >> 12) & 0x0F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr (0x80 | ($int & 0x3F));
+
+ case ($int & 0x1FFFFF):
+ return chr(0xF0 | ($int >> 18)) . chr(0x80 | (($int >> 12) & 0x3F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr(0x80 | ($int & 0x3F));
+ }
+ }
+
+ function _readNumber($start) {
+ $value = "";
+ $isFloat = false;
+
+ $this->_token = JSON_INT;
+ $value .= $start;
+
+ while (($chr = $this->peek()) != -1) {
+ if (is_numeric($chr) || $chr == '-' || $chr == '.') {
+ if ($chr == '.')
+ $isFloat = true;
+
+ $value .= $this->read();
+ } else
+ break;
+ }
+
+ $this->readAway();
+
+ if ($isFloat) {
+ $this->_token = JSON_FLOAT;
+ $this->_value = floatval($value);
+ } else
+ $this->_value = intval($value);
+
+ if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+ $this->_needProp = true;
+
+ return true;
+ }
+
+ function readAway() {
+ while (($chr = $this->peek()) != null) {
+ if ($chr != ':' && $chr != ',' && $chr != ' ')
+ return;
+
+ $this->read();
+ }
+ }
+
+ function read($len = 1) {
+ if ($this->_pos < $this->_len) {
+ if ($len > 1) {
+ $str = substr($this->_data, $this->_pos + 1, $len);
+ $this->_pos += $len;
+
+ return $str;
+ } else
+ return $this->_data[++$this->_pos];
+ }
+
+ return null;
+ }
+
+ function skip($len) {
+ $this->_pos += $len;
+ }
+
+ function peek() {
+ if ($this->_pos < $this->_len)
+ return $this->_data[$this->_pos + 1];
+
+ return null;
+ }
+}
+
+/**
+ * This class handles JSON stuff.
+ *
+ * @package MCManager.utils
+ */
+class Moxiecode_JSON {
+ function Moxiecode_JSON() {
+ }
+
+ function decode($input) {
+ $reader = new Moxiecode_JSONReader($input);
+
+ return $this->readValue($reader);
+ }
+
+ function readValue(&$reader) {
+ $this->data = array();
+ $this->parents = array();
+ $this->cur =& $this->data;
+ $key = null;
+ $loc = JSON_IN_ARRAY;
+
+ while ($reader->readToken()) {
+ switch ($reader->getToken()) {
+ case JSON_STR:
+ case JSON_INT:
+ case JSON_BOOL:
+ case JSON_FLOAT:
+ case JSON_NULL:
+ switch ($reader->getLocation()) {
+ case JSON_IN_OBJECT:
+ $this->cur[$key] = $reader->getValue();
+ break;
+
+ case JSON_IN_ARRAY:
+ $this->cur[] = $reader->getValue();
+ break;
+
+ default:
+ return $reader->getValue();
+ }
+ break;
+
+ case JSON_KEY:
+ $key = $reader->getValue();
+ break;
+
+ case JSON_START_OBJ:
+ case JSON_START_ARRAY:
+ if ($loc == JSON_IN_OBJECT)
+ $this->addArray($key);
+ else
+ $this->addArray(null);
+
+ $cur =& $obj;
+
+ $loc = $reader->getLocation();
+ break;
+
+ case JSON_END_OBJ:
+ case JSON_END_ARRAY:
+ $loc = $reader->getLocation();
+
+ if (count($this->parents) > 0) {
+ $this->cur =& $this->parents[count($this->parents) - 1];
+ array_pop($this->parents);
+ }
+ break;
+ }
+ }
+
+ return $this->data[0];
+ }
+
+ // This method was needed since PHP is crapy and doesn't have pointers/references
+ function addArray($key) {
+ $this->parents[] =& $this->cur;
+ $ar = array();
+
+ if ($key)
+ $this->cur[$key] =& $ar;
+ else
+ $this->cur[] =& $ar;
+
+ $this->cur =& $ar;
+ }
+
+ function getDelim($index, &$reader) {
+ switch ($reader->getLocation()) {
+ case JSON_IN_ARRAY:
+ case JSON_IN_OBJECT:
+ if ($index > 0)
+ return ",";
+ break;
+ }
+
+ return "";
+ }
+
+ function encode($input) {
+ switch (gettype($input)) {
+ case 'boolean':
+ return $input ? 'true' : 'false';
+
+ case 'integer':
+ return (int) $input;
+
+ case 'float':
+ case 'double':
+ return (float) $input;
+
+ case 'NULL':
+ return 'null';
+
+ case 'string':
+ return $this->encodeString($input);
+
+ case 'array':
+ return $this->_encodeArray($input);
+
+ case 'object':
+ return $this->_encodeArray(get_object_vars($input));
+ }
+
+ return '';
+ }
+
+ function encodeString($input) {
+ // Needs to be escaped
+ if (preg_match('/[^a-zA-Z0-9]/', $input)) {
+ $output = '';
+
+ for ($i=0; $i<strlen($input); $i++) {
+ switch ($input[$i]) {
+ case "\b":
+ $output .= "\\b";
+ break;
+
+ case "\t":
+ $output .= "\\t";
+ break;
+
+ case "\f":
+ $output .= "\\f";
+ break;
+
+ case "\r":
+ $output .= "\\r";
+ break;
+
+ case "\n":
+ $output .= "\\n";
+ break;
+
+ case '\\':
+ $output .= "\\\\";
+ break;
+
+ case '\'':
+ $output .= "\\'";
+ break;
+
+ case '"':
+ $output .= '\"';
+ break;
+
+ default:
+ $byte = ord($input[$i]);
+
+ if (($byte & 0xE0) == 0xC0) {
+ $char = pack('C*', $byte, ord($input[$i + 1]));
+ $i += 1;
+ $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+ } if (($byte & 0xF0) == 0xE0) {
+ $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]));
+ $i += 2;
+ $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+ } if (($byte & 0xF8) == 0xF0) {
+ $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]));
+ $i += 3;
+ $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+ } if (($byte & 0xFC) == 0xF8) {
+ $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]));
+ $i += 4;
+ $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+ } if (($byte & 0xFE) == 0xFC) {
+ $char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]), ord($input[$i + 5]));
+ $i += 5;
+ $output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+ } else if ($byte < 128)
+ $output .= $input[$i];
+ }
+ }
+
+ return '"' . $output . '"';
+ }
+
+ return '"' . $input . '"';
+ }
+
+ function _utf82utf16($utf8) {
+ if (function_exists('mb_convert_encoding'))
+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+
+ switch (strlen($utf8)) {
+ case 1:
+ return $utf8;
+
+ case 2:
+ return chr(0x07 & (ord($utf8[0]) >> 2)) . chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
+
+ case 3:
+ return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))) . chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
+ }
+
+ return '';
+ }
+
+ function _encodeArray($input) {
+ $output = '';
+ $isIndexed = true;
+
+ $keys = array_keys($input);
+ for ($i=0; $i<count($keys); $i++) {
+ if (!is_int($keys[$i])) {
+ $output .= $this->encodeString($keys[$i]) . ':' . $this->encode($input[$keys[$i]]);
+ $isIndexed = false;
+ } else
+ $output .= $this->encode($input[$keys[$i]]);
+
+ if ($i != count($keys) - 1)
+ $output .= ',';
+ }
+
+ return $isIndexed ? '[' . $output . ']' : '{' . $output . '}';
+ }
+}
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php
new file mode 100644
index 0000000000..a1fb4cd09e
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/Logger.php
@@ -0,0 +1,268 @@
+<?php
+/**
+ * $Id: Logger.class.php 10 2007-05-27 10:55:12Z spocke $
+ *
+ * @package MCFileManager.filesystems
+ * @author Moxiecode
+ * @copyright Copyright © 2005, Moxiecode Systems AB, All rights reserved.
+ */
+
+// File type contstants
+define('MC_LOGGER_DEBUG', 0);
+define('MC_LOGGER_INFO', 10);
+define('MC_LOGGER_WARN', 20);
+define('MC_LOGGER_ERROR', 30);
+define('MC_LOGGER_FATAL', 40);
+
+/**
+ * Logging utility class. This class handles basic logging with levels, log rotation and custom log formats. It's
+ * designed to be compact but still powerful and flexible.
+ */
+class Moxiecode_Logger {
+ // Private fields
+ var $_path;
+ var $_filename;
+ var $_maxSize;
+ var $_maxFiles;
+ var $_maxSizeBytes;
+ var $_level;
+ var $_format;
+
+ /**
+ * Constructs a new logger instance.
+ */
+ function Moxiecode_Logger() {
+ $this->_path = "";
+ $this->_filename = "{level}.log";
+ $this->setMaxSize("100k");
+ $this->_maxFiles = 10;
+ $this->_level = MC_LOGGER_DEBUG;
+ $this->_format = "[{time}] [{level}] {message}";
+ }
+
+ /**
+ * Sets the current log level, use the MC_LOGGER constants.
+ *
+ * @param int $level Log level instance for example MC_LOGGER_DEBUG.
+ */
+ function setLevel($level) {
+ if (is_string($level)) {
+ switch (strtolower($level)) {
+ case "debug":
+ $level = MC_LOGGER_DEBUG;
+ break;
+
+ case "info":
+ $level = MC_LOGGER_INFO;
+ break;
+
+ case "warn":
+ case "warning":
+ $level = MC_LOGGER_WARN;
+ break;
+
+ case "error":
+ $level = MC_LOGGER_ERROR;
+ break;
+
+ case "fatal":
+ $level = MC_LOGGER_FATAL;
+ break;
+
+ default:
+ $level = MC_LOGGER_FATAL;
+ }
+ }
+
+ $this->_level = $level;
+ }
+
+ /**
+ * Returns the current log level for example MC_LOGGER_DEBUG.
+ *
+ * @return int Current log level for example MC_LOGGER_DEBUG.
+ */
+ function getLevel() {
+ return $this->_level;
+ }
+
+ function setPath($path) {
+ $this->_path = $path;
+ }
+
+ function getPath() {
+ return $this->_path;
+ }
+
+ function setFileName($file_name) {
+ $this->_filename = $file_name;
+ }
+
+ function getFileName() {
+ return $this->_filename;
+ }
+
+ function setFormat($format) {
+ $this->_format = $format;
+ }
+
+ function getFormat() {
+ return $this->_format;
+ }
+
+ function setMaxSize($size) {
+ // Fix log max size
+ $logMaxSizeBytes = intval(preg_replace("/[^0-9]/", "", $size));
+
+ // Is KB
+ if (strpos((strtolower($size)), "k") > 0)
+ $logMaxSizeBytes *= 1024;
+
+ // Is MB
+ if (strpos((strtolower($size)), "m") > 0)
+ $logMaxSizeBytes *= (1024 * 1024);
+
+ $this->_maxSizeBytes = $logMaxSizeBytes;
+ $this->_maxSize = $size;
+ }
+
+ function getMaxSize() {
+ return $this->_maxSize;
+ }
+
+ function setMaxFiles($max_files) {
+ $this->_maxFiles = $max_files;
+ }
+
+ function getMaxFiles() {
+ return $this->_maxFiles;
+ }
+
+ function debug($msg) {
+ $args = func_get_args();
+ $this->_logMsg(MC_LOGGER_DEBUG, implode(', ', $args));
+ }
+
+ function info($msg) {
+ $args = func_get_args();
+ $this->_logMsg(MC_LOGGER_INFO, implode(', ', $args));
+ }
+
+ function warn($msg) {
+ $args = func_get_args();
+ $this->_logMsg(MC_LOGGER_WARN, implode(', ', $args));
+ }
+
+ function error($msg) {
+ $args = func_get_args();
+ $this->_logMsg(MC_LOGGER_ERROR, implode(', ', $args));
+ }
+
+ function fatal($msg) {
+ $args = func_get_args();
+ $this->_logMsg(MC_LOGGER_FATAL, implode(', ', $args));
+ }
+
+ function isDebugEnabled() {
+ return $this->_level >= MC_LOGGER_DEBUG;
+ }
+
+ function isInfoEnabled() {
+ return $this->_level >= MC_LOGGER_INFO;
+ }
+
+ function isWarnEnabled() {
+ return $this->_level >= MC_LOGGER_WARN;
+ }
+
+ function isErrorEnabled() {
+ return $this->_level >= MC_LOGGER_ERROR;
+ }
+
+ function isFatalEnabled() {
+ return $this->_level >= MC_LOGGER_FATAL;
+ }
+
+ function _logMsg($level, $message) {
+ $roll = false;
+
+ if ($level < $this->_level)
+ return;
+
+ $logFile = $this->toOSPath($this->_path . "/" . $this->_filename);
+
+ switch ($level) {
+ case MC_LOGGER_DEBUG:
+ $levelName = "DEBUG";
+ break;
+
+ case MC_LOGGER_INFO:
+ $levelName = "INFO";
+ break;
+
+ case MC_LOGGER_WARN:
+ $levelName = "WARN";
+ break;
+
+ case MC_LOGGER_ERROR:
+ $levelName = "ERROR";
+ break;
+
+ case MC_LOGGER_FATAL:
+ $levelName = "FATAL";
+ break;
+ }
+
+ $logFile = str_replace('{level}', strtolower($levelName), $logFile);
+
+ $text = $this->_format;
+ $text = str_replace('{time}', date("Y-m-d H:i:s"), $text);
+ $text = str_replace('{level}', strtolower($levelName), $text);
+ $text = str_replace('{message}', $message, $text);
+ $message = $text . "\r\n";
+
+ // Check filesize
+ if (file_exists($logFile)) {
+ $size = @filesize($logFile);
+
+ if ($size + strlen($message) > $this->_maxSizeBytes)
+ $roll = true;
+ }
+
+ // Roll if the size is right
+ if ($roll) {
+ for ($i=$this->_maxFiles-1; $i>=1; $i--) {
+ $rfile = $this->toOSPath($logFile . "." . $i);
+ $nfile = $this->toOSPath($logFile . "." . ($i+1));
+
+ if (@file_exists($rfile))
+ @rename($rfile, $nfile);
+ }
+
+ @rename($logFile, $this->toOSPath($logFile . ".1"));
+
+ // Delete last logfile
+ $delfile = $this->toOSPath($logFile . "." . ($this->_maxFiles + 1));
+ if (@file_exists($delfile))
+ @unlink($delfile);
+ }
+
+ // Append log line
+ if (($fp = @fopen($logFile, "a")) != null) {
+ @fputs($fp, $message);
+ @fflush($fp);
+ @fclose($fp);
+ }
+ }
+
+ /**
+ * Converts a Unix path to OS specific path.
+ *
+ * @param String $path Unix path to convert.
+ */
+ function toOSPath($path) {
+ return str_replace("/", DIRECTORY_SEPARATOR, $path);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/config.php b/src/wp-includes/js/tinymce/plugins/spellchecker/config.php
new file mode 100644
index 0000000000..795495a664
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/config.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * config.php
+ *
+ * @package MCManager.includes
+ */
+ // General settings
+ $config['general.engine'] = 'GoogleSpell';
+ //$config['general.engine'] = 'PSpell';
+ //$config['general.engine'] = 'PSpellShell';
+ //$config['general.remote_rpc_url'] = 'http://some.other.site/some/url/rpc.php';
+
+ // PSpell settings
+ $config['PSpell.mode'] = PSPELL_FAST;
+ $config['PSpell.spelling'] = "";
+ $config['PSpell.jargon'] = "";
+ $config['PSpell.encoding'] = "";
+
+ // PSpellShell settings
+ $config['PSpellShell.mode'] = PSPELL_FAST;
+ $config['PSpellShell.aspell'] = '/usr/bin/aspell';
+ $config['PSpellShell.tmp'] = '/tmp';
+
+ // Windows PSpellShell settings
+ //$config['PSpellShell.aspell'] = '"c:\Program Files\Aspell\bin\aspell.exe"';
+ //$config['PSpellShell.tmp'] = 'c:/temp';
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/css/content.css b/src/wp-includes/js/tinymce/plugins/spellchecker/css/content.css
new file mode 100644
index 0000000000..656ce1eee6
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/css/content.css
@@ -0,0 +1 @@
+.mceItemHiddenSpellWord {background:url(../img/wline.gif) repeat-x bottom left; cursor:default;}
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin.js
new file mode 100644
index 0000000000..48549c9239
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.util.JSONRequest,c=tinymce.each,b=tinymce.DOM;tinymce.create("tinymce.plugins.SpellcheckerPlugin",{getInfo:function(){return{longname:"Spellchecker",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker",version:tinymce.majorVersion+"."+tinymce.minorVersion}},init:function(e,f){var g=this,d;g.url=f;g.editor=e;g.rpcUrl=e.getParam("spellchecker_rpc_url","{backend}");if(g.rpcUrl=="{backend}"){if(tinymce.isIE){return}g.hasSupport=true;e.onContextMenu.addToTop(function(h,i){if(g.active){return false}})}e.addCommand("mceSpellCheck",function(){if(g.rpcUrl=="{backend}"){g.editor.getBody().spellcheck=g.active=!g.active;return}if(!g.active){e.setProgressState(1);g._sendRPC("checkWords",[g.selectedLang,g._getWords()],function(h){if(h.length>0){g.active=1;g._markWords(h);e.setProgressState(0);e.nodeChanged()}else{e.setProgressState(0);if(e.getParam("spellchecker_report_no_misspellings",true)){e.windowManager.alert("spellchecker.no_mpell")}}})}else{g._done()}});if(e.settings.content_css!==false){e.contentCSS.push(f+"/css/content.css")}e.onClick.add(g._showMenu,g);e.onContextMenu.add(g._showMenu,g);e.onBeforeGetContent.add(function(){if(g.active){g._removeWords()}});e.onNodeChange.add(function(i,h){h.setActive("spellchecker",g.active)});e.onSetContent.add(function(){g._done()});e.onBeforeGetContent.add(function(){g._done()});e.onBeforeExecCommand.add(function(h,i){if(i=="mceFullScreen"){g._done()}});g.languages={};c(e.getParam("spellchecker_languages","+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv","hash"),function(i,h){if(h.indexOf("+")===0){h=h.substring(1);g.selectedLang=i}g.languages[h]=i})},createControl:function(h,d){var f=this,g,e=f.editor;if(h=="spellchecker"){if(f.rpcUrl=="{backend}"){if(f.hasSupport){g=d.createButton(h,{title:"spellchecker.desc",cmd:"mceSpellCheck",scope:f})}return g}g=d.createSplitButton(h,{title:"spellchecker.desc",cmd:"mceSpellCheck",scope:f});g.onRenderMenu.add(function(j,i){i.add({title:"spellchecker.langs","class":"mceMenuItemTitle"}).setDisabled(1);c(f.languages,function(n,m){var p={icon:1},l;p.onclick=function(){if(n==f.selectedLang){return}l.setSelected(1);f.selectedItem.setSelected(0);f.selectedItem=l;f.selectedLang=n};p.title=m;l=i.add(p);l.setSelected(n==f.selectedLang);if(n==f.selectedLang){f.selectedItem=l}})});return g}},_walk:function(i,g){var h=this.editor.getDoc(),e;if(h.createTreeWalker){e=h.createTreeWalker(i,NodeFilter.SHOW_TEXT,null,false);while((i=e.nextNode())!=null){g.call(this,i)}}else{tinymce.walk(i,g,"childNodes")}},_getSeparators:function(){var e="",d,f=this.editor.getParam("spellchecker_word_separator_chars",'\\s!"#$%&()*+,-./:;<=>?@[]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c');for(d=0;d<f.length;d++){e+="\\"+f.charAt(d)}return e},_getWords:function(){var e=this.editor,g=[],d="",f={},h=[];this._walk(e.getBody(),function(i){if(i.nodeType==3){d+=i.nodeValue+" "}});if(e.getParam("spellchecker_word_pattern")){h=d.match("("+e.getParam("spellchecker_word_pattern")+")","gi")}else{d=d.replace(new RegExp("([0-9]|["+this._getSeparators()+"])","g")," ");d=tinymce.trim(d.replace(/(\s+)/g," "));h=d.split(" ")}c(h,function(i){if(!f[i]){g.push(i);f[i]=1}});return g},_removeWords:function(d){var e=this.editor,h=e.dom,g=e.selection,f=g.getRng(true);c(h.select("span").reverse(),function(i){if(i&&(h.hasClass(i,"mceItemHiddenSpellWord")||h.hasClass(i,"mceItemHidden"))){if(!d||h.decode(i.innerHTML)==d){h.remove(i,1)}}});g.setRng(f)},_markWords:function(l){var h=this.editor,g=h.dom,j=h.getDoc(),i=h.selection,d=i.getRng(true),e=[],k=l.join("|"),m=this._getSeparators(),f=new RegExp("(^|["+m+"])("+k+")(?=["+m+"]|$)","g");this._walk(h.getBody(),function(o){if(o.nodeType==3){e.push(o)}});c(e,function(t){var r,q,o,s,p=t.nodeValue;if(f.test(p)){p=g.encode(p);q=g.create("span",{"class":"mceItemHidden"});if(tinymce.isIE){p=p.replace(f,"$1<mcespell>$2</mcespell>");while((s=p.indexOf("<mcespell>"))!=-1){o=p.substring(0,s);if(o.length){r=j.createTextNode(g.decode(o));q.appendChild(r)}p=p.substring(s+10);s=p.indexOf("</mcespell>");o=p.substring(0,s);p=p.substring(s+11);q.appendChild(g.create("span",{"class":"mceItemHiddenSpellWord"},o))}if(p.length){r=j.createTextNode(g.decode(p));q.appendChild(r)}}else{q.innerHTML=p.replace(f,'$1<span class="mceItemHiddenSpellWord">$2</span>')}g.replace(q,t)}});i.setRng(d)},_showMenu:function(h,j){var i=this,h=i.editor,d=i._menu,l,k=h.dom,g=k.getViewPort(h.getWin()),f=j.target;j=0;if(!d){d=h.controlManager.createDropMenu("spellcheckermenu",{"class":"mceNoIcons"});i._menu=d}if(k.hasClass(f,"mceItemHiddenSpellWord")){d.removeAll();d.add({title:"spellchecker.wait","class":"mceMenuItemTitle"}).setDisabled(1);i._sendRPC("getSuggestions",[i.selectedLang,k.decode(f.innerHTML)],function(m){var e;d.removeAll();if(m.length>0){d.add({title:"spellchecker.sug","class":"mceMenuItemTitle"}).setDisabled(1);c(m,function(n){d.add({title:n,onclick:function(){k.replace(h.getDoc().createTextNode(n),f);i._checkDone()}})});d.addSeparator()}else{d.add({title:"spellchecker.no_sug","class":"mceMenuItemTitle"}).setDisabled(1)}if(h.getParam("show_ignore_words",true)){e=i.editor.getParam("spellchecker_enable_ignore_rpc","");d.add({title:"spellchecker.ignore_word",onclick:function(){var n=f.innerHTML;k.remove(f,1);i._checkDone();if(e){h.setProgressState(1);i._sendRPC("ignoreWord",[i.selectedLang,n],function(o){h.setProgressState(0)})}}});d.add({title:"spellchecker.ignore_words",onclick:function(){var n=f.innerHTML;i._removeWords(k.decode(n));i._checkDone();if(e){h.setProgressState(1);i._sendRPC("ignoreWords",[i.selectedLang,n],function(o){h.setProgressState(0)})}}})}if(i.editor.getParam("spellchecker_enable_learn_rpc")){d.add({title:"spellchecker.learn_word",onclick:function(){var n=f.innerHTML;k.remove(f,1);i._checkDone();h.setProgressState(1);i._sendRPC("learnWord",[i.selectedLang,n],function(o){h.setProgressState(0)})}})}d.update()});l=b.getPos(h.getContentAreaContainer());d.settings.offset_x=l.x;d.settings.offset_y=l.y;h.selection.select(f);l=k.getPos(f);d.showMenu(l.x,l.y+f.offsetHeight-g.y);return tinymce.dom.Event.cancel(j)}else{d.hideMenu()}},_checkDone:function(){var e=this,d=e.editor,g=d.dom,f;c(g.select("span"),function(h){if(h&&g.hasClass(h,"mceItemHiddenSpellWord")){f=true;return false}});if(!f){e._done()}},_done:function(){var d=this,e=d.active;if(d.active){d.active=0;d._removeWords();if(d._menu){d._menu.hideMenu()}if(e){d.editor.nodeChanged()}}},_sendRPC:function(e,g,d){var f=this;a.sendRPC({url:f.rpcUrl,method:e,params:g,success:d,error:function(i,h){f.editor.setProgressState(0);f.editor.windowManager.alert(i.errstr||("Error response: "+h.responseText))}})}});tinymce.PluginManager.add("spellchecker",tinymce.plugins.SpellcheckerPlugin)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin_src.js
new file mode 100644
index 0000000000..925d2f21a6
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/editor_plugin_src.js
@@ -0,0 +1,436 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.plugins.SpellcheckerPlugin', {
+ getInfo : function() {
+ return {
+ longname : 'Spellchecker',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ init : function(ed, url) {
+ var t = this, cm;
+
+ t.url = url;
+ t.editor = ed;
+ t.rpcUrl = ed.getParam("spellchecker_rpc_url", "{backend}");
+
+ if (t.rpcUrl == '{backend}') {
+ // Sniff if the browser supports native spellchecking (Don't know of a better way)
+ if (tinymce.isIE)
+ return;
+
+ t.hasSupport = true;
+
+ // Disable the context menu when spellchecking is active
+ ed.onContextMenu.addToTop(function(ed, e) {
+ if (t.active)
+ return false;
+ });
+ }
+
+ // Register commands
+ ed.addCommand('mceSpellCheck', function() {
+ if (t.rpcUrl == '{backend}') {
+ // Enable/disable native spellchecker
+ t.editor.getBody().spellcheck = t.active = !t.active;
+ return;
+ }
+
+ if (!t.active) {
+ ed.setProgressState(1);
+ t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) {
+ if (r.length > 0) {
+ t.active = 1;
+ t._markWords(r);
+ ed.setProgressState(0);
+ ed.nodeChanged();
+ } else {
+ ed.setProgressState(0);
+
+ if (ed.getParam('spellchecker_report_no_misspellings', true))
+ ed.windowManager.alert('spellchecker.no_mpell');
+ }
+ });
+ } else
+ t._done();
+ });
+
+ if (ed.settings.content_css !== false)
+ ed.contentCSS.push(url + '/css/content.css');
+
+ ed.onClick.add(t._showMenu, t);
+ ed.onContextMenu.add(t._showMenu, t);
+ ed.onBeforeGetContent.add(function() {
+ if (t.active)
+ t._removeWords();
+ });
+
+ ed.onNodeChange.add(function(ed, cm) {
+ cm.setActive('spellchecker', t.active);
+ });
+
+ ed.onSetContent.add(function() {
+ t._done();
+ });
+
+ ed.onBeforeGetContent.add(function() {
+ t._done();
+ });
+
+ ed.onBeforeExecCommand.add(function(ed, cmd) {
+ if (cmd == 'mceFullScreen')
+ t._done();
+ });
+
+ // Find selected language
+ t.languages = {};
+ each(ed.getParam('spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv', 'hash'), function(v, k) {
+ if (k.indexOf('+') === 0) {
+ k = k.substring(1);
+ t.selectedLang = v;
+ }
+
+ t.languages[k] = v;
+ });
+ },
+
+ createControl : function(n, cm) {
+ var t = this, c, ed = t.editor;
+
+ if (n == 'spellchecker') {
+ // Use basic button if we use the native spellchecker
+ if (t.rpcUrl == '{backend}') {
+ // Create simple toggle button if we have native support
+ if (t.hasSupport)
+ c = cm.createButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});
+
+ return c;
+ }
+
+ c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});
+
+ c.onRenderMenu.add(function(c, m) {
+ m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+ each(t.languages, function(v, k) {
+ var o = {icon : 1}, mi;
+
+ o.onclick = function() {
+ if (v == t.selectedLang) {
+ return;
+ }
+ mi.setSelected(1);
+ t.selectedItem.setSelected(0);
+ t.selectedItem = mi;
+ t.selectedLang = v;
+ };
+
+ o.title = k;
+ mi = m.add(o);
+ mi.setSelected(v == t.selectedLang);
+
+ if (v == t.selectedLang)
+ t.selectedItem = mi;
+ })
+ });
+
+ return c;
+ }
+ },
+
+ // Internal functions
+
+ _walk : function(n, f) {
+ var d = this.editor.getDoc(), w;
+
+ if (d.createTreeWalker) {
+ w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
+
+ while ((n = w.nextNode()) != null)
+ f.call(this, n);
+ } else
+ tinymce.walk(n, f, 'childNodes');
+ },
+
+ _getSeparators : function() {
+ var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c');
+
+ // Build word separator regexp
+ for (i=0; i<str.length; i++)
+ re += '\\' + str.charAt(i);
+
+ return re;
+ },
+
+ _getWords : function() {
+ var ed = this.editor, wl = [], tx = '', lo = {}, rawWords = [];
+
+ // Get area text
+ this._walk(ed.getBody(), function(n) {
+ if (n.nodeType == 3)
+ tx += n.nodeValue + ' ';
+ });
+
+ // split the text up into individual words
+ if (ed.getParam('spellchecker_word_pattern')) {
+ // look for words that match the pattern
+ rawWords = tx.match('(' + ed.getParam('spellchecker_word_pattern') + ')', 'gi');
+ } else {
+ // Split words by separator
+ tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' ');
+ tx = tinymce.trim(tx.replace(/(\s+)/g, ' '));
+ rawWords = tx.split(' ');
+ }
+
+ // Build word array and remove duplicates
+ each(rawWords, function(v) {
+ if (!lo[v]) {
+ wl.push(v);
+ lo[v] = 1;
+ }
+ });
+
+ return wl;
+ },
+
+ _removeWords : function(w) {
+ var ed = this.editor, dom = ed.dom, se = ed.selection, r = se.getRng(true);
+
+ each(dom.select('span').reverse(), function(n) {
+ if (n && (dom.hasClass(n, 'mceItemHiddenSpellWord') || dom.hasClass(n, 'mceItemHidden'))) {
+ if (!w || dom.decode(n.innerHTML) == w)
+ dom.remove(n, 1);
+ }
+ });
+
+ se.setRng(r);
+ },
+
+ _markWords : function(wl) {
+ var ed = this.editor, dom = ed.dom, doc = ed.getDoc(), se = ed.selection, r = se.getRng(true), nl = [],
+ w = wl.join('|'), re = this._getSeparators(), rx = new RegExp('(^|[' + re + '])(' + w + ')(?=[' + re + ']|$)', 'g');
+
+ // Collect all text nodes
+ this._walk(ed.getBody(), function(n) {
+ if (n.nodeType == 3) {
+ nl.push(n);
+ }
+ });
+
+ // Wrap incorrect words in spans
+ each(nl, function(n) {
+ var node, elem, txt, pos, v = n.nodeValue;
+
+ if (rx.test(v)) {
+ // Encode the content
+ v = dom.encode(v);
+ // Create container element
+ elem = dom.create('span', {'class' : 'mceItemHidden'});
+
+ // Following code fixes IE issues by creating text nodes
+ // using DOM methods instead of innerHTML.
+ // Bug #3124: <PRE> elements content is broken after spellchecking.
+ // Bug #1408: Preceding whitespace characters are removed
+ // @TODO: I'm not sure that both are still issues on IE9.
+ if (tinymce.isIE) {
+ // Enclose mispelled words with temporal tag
+ v = v.replace(rx, '$1<mcespell>$2</mcespell>');
+ // Loop over the content finding mispelled words
+ while ((pos = v.indexOf('<mcespell>')) != -1) {
+ // Add text node for the content before the word
+ txt = v.substring(0, pos);
+ if (txt.length) {
+ node = doc.createTextNode(dom.decode(txt));
+ elem.appendChild(node);
+ }
+ v = v.substring(pos+10);
+ pos = v.indexOf('</mcespell>');
+ txt = v.substring(0, pos);
+ v = v.substring(pos+11);
+ // Add span element for the word
+ elem.appendChild(dom.create('span', {'class' : 'mceItemHiddenSpellWord'}, txt));
+ }
+ // Add text node for the rest of the content
+ if (v.length) {
+ node = doc.createTextNode(dom.decode(v));
+ elem.appendChild(node);
+ }
+ } else {
+ // Other browsers preserve whitespace characters on innerHTML usage
+ elem.innerHTML = v.replace(rx, '$1<span class="mceItemHiddenSpellWord">$2</span>');
+ }
+
+ // Finally, replace the node with the container
+ dom.replace(elem, n);
+ }
+ });
+
+ se.setRng(r);
+ },
+
+ _showMenu : function(ed, e) {
+ var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()), wordSpan = e.target;
+
+ e = 0; // Fixes IE memory leak
+
+ if (!m) {
+ m = ed.controlManager.createDropMenu('spellcheckermenu', {'class' : 'mceNoIcons'});
+ t._menu = m;
+ }
+
+ if (dom.hasClass(wordSpan, 'mceItemHiddenSpellWord')) {
+ m.removeAll();
+ m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+
+ t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(wordSpan.innerHTML)], function(r) {
+ var ignoreRpc;
+
+ m.removeAll();
+
+ if (r.length > 0) {
+ m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+ each(r, function(v) {
+ m.add({title : v, onclick : function() {
+ dom.replace(ed.getDoc().createTextNode(v), wordSpan);
+ t._checkDone();
+ }});
+ });
+
+ m.addSeparator();
+ } else
+ m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+
+ if (ed.getParam('show_ignore_words', true)) {
+ ignoreRpc = t.editor.getParam("spellchecker_enable_ignore_rpc", '');
+ m.add({
+ title : 'spellchecker.ignore_word',
+ onclick : function() {
+ var word = wordSpan.innerHTML;
+
+ dom.remove(wordSpan, 1);
+ t._checkDone();
+
+ // tell the server if we need to
+ if (ignoreRpc) {
+ ed.setProgressState(1);
+ t._sendRPC('ignoreWord', [t.selectedLang, word], function(r) {
+ ed.setProgressState(0);
+ });
+ }
+ }
+ });
+
+ m.add({
+ title : 'spellchecker.ignore_words',
+ onclick : function() {
+ var word = wordSpan.innerHTML;
+
+ t._removeWords(dom.decode(word));
+ t._checkDone();
+
+ // tell the server if we need to
+ if (ignoreRpc) {
+ ed.setProgressState(1);
+ t._sendRPC('ignoreWords', [t.selectedLang, word], function(r) {
+ ed.setProgressState(0);
+ });
+ }
+ }
+ });
+ }
+
+ if (t.editor.getParam("spellchecker_enable_learn_rpc")) {
+ m.add({
+ title : 'spellchecker.learn_word',
+ onclick : function() {
+ var word = wordSpan.innerHTML;
+
+ dom.remove(wordSpan, 1);
+ t._checkDone();
+
+ ed.setProgressState(1);
+ t._sendRPC('learnWord', [t.selectedLang, word], function(r) {
+ ed.setProgressState(0);
+ });
+ }
+ });
+ }
+
+ m.update();
+ });
+
+ p1 = DOM.getPos(ed.getContentAreaContainer());
+ m.settings.offset_x = p1.x;
+ m.settings.offset_y = p1.y;
+
+ ed.selection.select(wordSpan);
+ p1 = dom.getPos(wordSpan);
+ m.showMenu(p1.x, p1.y + wordSpan.offsetHeight - vp.y);
+
+ return tinymce.dom.Event.cancel(e);
+ } else
+ m.hideMenu();
+ },
+
+ _checkDone : function() {
+ var t = this, ed = t.editor, dom = ed.dom, o;
+
+ each(dom.select('span'), function(n) {
+ if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) {
+ o = true;
+ return false;
+ }
+ });
+
+ if (!o)
+ t._done();
+ },
+
+ _done : function() {
+ var t = this, la = t.active;
+
+ if (t.active) {
+ t.active = 0;
+ t._removeWords();
+
+ if (t._menu)
+ t._menu.hideMenu();
+
+ if (la)
+ t.editor.nodeChanged();
+ }
+ },
+
+ _sendRPC : function(m, p, cb) {
+ var t = this;
+
+ JSONRequest.sendRPC({
+ url : t.rpcUrl,
+ method : m,
+ params : p,
+ success : cb,
+ error : function(e, x) {
+ t.editor.setProgressState(0);
+ t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText));
+ }
+ });
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/img/wline.gif b/src/wp-includes/js/tinymce/plugins/spellchecker/img/wline.gif
new file mode 100644
index 0000000000..7d0a4dbca0
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/img/wline.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php b/src/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php
new file mode 100644
index 0000000000..ffea3a0c1f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/includes/general.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * general.php
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+@error_reporting(E_ALL ^ E_NOTICE);
+$config = array();
+
+require_once(dirname(__FILE__) . "/../classes/utils/Logger.php");
+require_once(dirname(__FILE__) . "/../classes/utils/JSON.php");
+require_once(dirname(__FILE__) . "/../config.php");
+require_once(dirname(__FILE__) . "/../classes/SpellChecker.php");
+
+if (isset($config['general.engine']))
+ require_once(dirname(__FILE__) . "/../classes/" . $config["general.engine"] . ".php");
+
+/**
+ * Returns an request value by name without magic quoting.
+ *
+ * @param String $name Name of parameter to get.
+ * @param String $default_value Default value to return if value not found.
+ * @return String request value by name without magic quoting or default value.
+ */
+function getRequestParam($name, $default_value = false) {
+ if (!isset($_REQUEST[$name]))
+ return $default_value;
+
+ if (is_array($_REQUEST[$name])) {
+ $newarray = array();
+
+ foreach ($_REQUEST[$name] as $name => $value)
+ $newarray[$name] = $value;
+
+ return $newarray;
+ }
+
+ return $_REQUEST[$name];
+}
+
+function &getLogger() {
+ global $mcLogger, $man;
+
+ if (isset($man))
+ $mcLogger = $man->getLogger();
+
+ if (!$mcLogger) {
+ $mcLogger = new Moxiecode_Logger();
+
+ // Set logger options
+ $mcLogger->setPath(dirname(__FILE__) . "/../logs");
+ $mcLogger->setMaxSize("100kb");
+ $mcLogger->setMaxFiles("10");
+ $mcLogger->setFormat("{time} - {message}");
+ }
+
+ return $mcLogger;
+}
+
+function debug($msg) {
+ $args = func_get_args();
+
+ $log = getLogger();
+ $log->debug(implode(', ', $args));
+}
+
+function info($msg) {
+ $args = func_get_args();
+
+ $log = getLogger();
+ $log->info(implode(', ', $args));
+}
+
+function error($msg) {
+ $args = func_get_args();
+
+ $log = getLogger();
+ $log->error(implode(', ', $args));
+}
+
+function warn($msg) {
+ $args = func_get_args();
+
+ $log = getLogger();
+ $log->warn(implode(', ', $args));
+}
+
+function fatal($msg) {
+ $args = func_get_args();
+
+ $log = getLogger();
+ $log->fatal(implode(', ', $args));
+}
+
+?> \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/spellchecker/rpc.php b/src/wp-includes/js/tinymce/plugins/spellchecker/rpc.php
new file mode 100644
index 0000000000..6a567348ce
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/spellchecker/rpc.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * $Id: rpc.php 915 2008-09-03 08:45:28Z spocke $
+ *
+ * @package MCManager.includes
+ * @author Moxiecode
+ * @copyright Copyright © 2004-2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+require_once("./includes/general.php");
+
+// Set RPC response headers
+header('Content-Type: text/plain');
+header('Content-Encoding: UTF-8');
+header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+header("Cache-Control: no-store, no-cache, must-revalidate");
+header("Cache-Control: post-check=0, pre-check=0", false);
+header("Pragma: no-cache");
+
+$raw = "";
+
+// Try param
+if (isset($_POST["json_data"]))
+ $raw = getRequestParam("json_data");
+
+// Try globals array
+if (!$raw && isset($_GLOBALS) && isset($_GLOBALS["HTTP_RAW_POST_DATA"]))
+ $raw = $_GLOBALS["HTTP_RAW_POST_DATA"];
+
+// Try globals variable
+if (!$raw && isset($HTTP_RAW_POST_DATA))
+ $raw = $HTTP_RAW_POST_DATA;
+
+// Try stream
+if (!$raw) {
+ if (!function_exists('file_get_contents')) {
+ $fp = fopen("php://input", "r");
+ if ($fp) {
+ $raw = "";
+
+ while (!feof($fp))
+ $raw = fread($fp, 1024);
+
+ fclose($fp);
+ }
+ } else
+ $raw = "" . file_get_contents("php://input");
+}
+
+// No input data
+if (!$raw)
+ die('{"result":null,"id":null,"error":{"errstr":"Could not get raw post data.","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
+
+// Passthrough request to remote server
+if (isset($config['general.remote_rpc_url'])) {
+ $url = parse_url($config['general.remote_rpc_url']);
+
+ // Setup request
+ $req = "POST " . $url["path"] . " HTTP/1.0\r\n";
+ $req .= "Connection: close\r\n";
+ $req .= "Host: " . $url['host'] . "\r\n";
+ $req .= "Content-Length: " . strlen($raw) . "\r\n";
+ $req .= "\r\n" . $raw;
+
+ if (!isset($url['port']) || !$url['port'])
+ $url['port'] = 80;
+
+ $errno = $errstr = "";
+
+ $socket = fsockopen($url['host'], intval($url['port']), $errno, $errstr, 30);
+ if ($socket) {
+ // Send request headers
+ fputs($socket, $req);
+
+ // Read response headers and data
+ $resp = "";
+ while (!feof($socket))
+ $resp .= fgets($socket, 4096);
+
+ fclose($socket);
+
+ // Split response header/data
+ $resp = explode("\r\n\r\n", $resp);
+ echo $resp[1]; // Output body
+ }
+
+ die();
+}
+
+// Get JSON data
+$json = new Moxiecode_JSON();
+$input = $json->decode($raw);
+
+// Execute RPC
+if (isset($config['general.engine'])) {
+ $spellchecker = new $config['general.engine']($config);
+ $result = call_user_func_array(array($spellchecker, $input['method']), $input['params']);
+} else
+ die('{"result":null,"id":null,"error":{"errstr":"You must choose an spellchecker engine in the config.php file.","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}');
+
+// Request and response id should always be the same
+$output = array(
+ "id" => $input->id,
+ "result" => $result,
+ "error" => null
+);
+
+// Return JSON encoded string
+echo $json->encode($output);
+
+?>
diff --git a/src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js b/src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js
new file mode 100644
index 0000000000..2c51291615
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var c=tinymce.DOM,a=tinymce.dom.Event,d=tinymce.each,b=tinymce.explode;tinymce.create("tinymce.plugins.TabFocusPlugin",{init:function(f,g){function e(i,j){if(j.keyCode===9){return a.cancel(j)}}function h(l,p){var j,m,o,n,k;function q(t){n=c.select(":input:enabled,*[tabindex]:not(iframe)");function s(v){return v.nodeName==="BODY"||(v.type!="hidden"&&!(v.style.display=="none")&&!(v.style.visibility=="hidden")&&s(v.parentNode))}function i(v){return v.attributes.tabIndex.specified||v.nodeName=="INPUT"||v.nodeName=="TEXTAREA"}function u(){return tinymce.isIE6||tinymce.isIE7}function r(v){return((!u()||i(v)))&&v.getAttribute("tabindex")!="-1"&&s(v)}d(n,function(w,v){if(w.id==l.id){j=v;return false}});if(t>0){for(m=j+1;m<n.length;m++){if(r(n[m])){return n[m]}}}else{for(m=j-1;m>=0;m--){if(r(n[m])){return n[m]}}}return null}if(p.keyCode===9){k=b(l.getParam("tab_focus",l.getParam("tabfocus_elements",":prev,:next")));if(k.length==1){k[1]=k[0];k[0]=":prev"}if(p.shiftKey){if(k[0]==":prev"){n=q(-1)}else{n=c.get(k[0])}}else{if(k[1]==":next"){n=q(1)}else{n=c.get(k[1])}}if(n){if(n.id&&(l=tinymce.get(n.id||n.name))){l.focus()}else{window.setTimeout(function(){if(!tinymce.isWebKit){window.focus()}n.focus()},10)}return a.cancel(p)}}}f.onKeyUp.add(e);if(tinymce.isGecko){f.onKeyPress.add(h);f.onKeyDown.add(e)}else{f.onKeyDown.add(h)}},getInfo:function(){return{longname:"Tabfocus",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("tabfocus",tinymce.plugins.TabFocusPlugin)})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js
new file mode 100644
index 0000000000..94f45320d6
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/tabfocus/editor_plugin_src.js
@@ -0,0 +1,122 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, explode = tinymce.explode;
+
+ tinymce.create('tinymce.plugins.TabFocusPlugin', {
+ init : function(ed, url) {
+ function tabCancel(ed, e) {
+ if (e.keyCode === 9)
+ return Event.cancel(e);
+ }
+
+ function tabHandler(ed, e) {
+ var x, i, f, el, v;
+
+ function find(d) {
+ el = DOM.select(':input:enabled,*[tabindex]:not(iframe)');
+
+ function canSelectRecursive(e) {
+ return e.nodeName==="BODY" || (e.type != 'hidden' &&
+ !(e.style.display == "none") &&
+ !(e.style.visibility == "hidden") && canSelectRecursive(e.parentNode));
+ }
+ function canSelectInOldIe(el) {
+ return el.attributes["tabIndex"].specified || el.nodeName == "INPUT" || el.nodeName == "TEXTAREA";
+ }
+ function isOldIe() {
+ return tinymce.isIE6 || tinymce.isIE7;
+ }
+ function canSelect(el) {
+ return ((!isOldIe() || canSelectInOldIe(el))) && el.getAttribute("tabindex") != '-1' && canSelectRecursive(el);
+ }
+
+ each(el, function(e, i) {
+ if (e.id == ed.id) {
+ x = i;
+ return false;
+ }
+ });
+ if (d > 0) {
+ for (i = x + 1; i < el.length; i++) {
+ if (canSelect(el[i]))
+ return el[i];
+ }
+ } else {
+ for (i = x - 1; i >= 0; i--) {
+ if (canSelect(el[i]))
+ return el[i];
+ }
+ }
+
+ return null;
+ }
+
+ if (e.keyCode === 9) {
+ v = explode(ed.getParam('tab_focus', ed.getParam('tabfocus_elements', ':prev,:next')));
+
+ if (v.length == 1) {
+ v[1] = v[0];
+ v[0] = ':prev';
+ }
+
+ // Find element to focus
+ if (e.shiftKey) {
+ if (v[0] == ':prev')
+ el = find(-1);
+ else
+ el = DOM.get(v[0]);
+ } else {
+ if (v[1] == ':next')
+ el = find(1);
+ else
+ el = DOM.get(v[1]);
+ }
+
+ if (el) {
+ if (el.id && (ed = tinymce.get(el.id || el.name)))
+ ed.focus();
+ else
+ window.setTimeout(function() {
+ if (!tinymce.isWebKit)
+ window.focus();
+ el.focus();
+ }, 10);
+
+ return Event.cancel(e);
+ }
+ }
+ }
+
+ ed.onKeyUp.add(tabCancel);
+
+ if (tinymce.isGecko) {
+ ed.onKeyPress.add(tabHandler);
+ ed.onKeyDown.add(tabCancel);
+ } else
+ ed.onKeyDown.add(tabHandler);
+
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Tabfocus',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('tabfocus', tinymce.plugins.TabFocusPlugin);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js
new file mode 100644
index 0000000000..653eb7c8b2
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js
@@ -0,0 +1,437 @@
+/**
+ * WordPress plugin.
+ */
+
+(function() {
+ var DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.plugins.WordPress', {
+ init : function(ed, url) {
+ var t = this, tbId = ed.getParam('wordpress_adv_toolbar', 'toolbar2'), last = 0, moreHTML, nextpageHTML, closeOnClick, mod_key, style;
+ moreHTML = '<img src="' + url + '/img/trans.gif" class="mce-wp-more mceItemNoResize" title="'+ed.getLang('wordpress.wp_more_alt')+'" />';
+ nextpageHTML = '<img src="' + url + '/img/trans.gif" class="mce-wp-nextpage mceItemNoResize" title="'+ed.getLang('wordpress.wp_page_alt')+'" />';
+
+ if ( getUserSetting('hidetb', '0') == '1' )
+ ed.settings.wordpress_adv_hidden = 0;
+
+ // Hides the specified toolbar and resizes the iframe
+ ed.onPostRender.add(function() {
+ var adv_toolbar = ed.controlManager.get(tbId);
+ if ( ed.getParam('wordpress_adv_hidden', 1) && adv_toolbar ) {
+ DOM.hide(adv_toolbar.id);
+ t._resizeIframe(ed, tbId, 28);
+ }
+ });
+
+ // Register commands
+ ed.addCommand('WP_More', function() {
+ ed.execCommand('mceInsertContent', 0, moreHTML);
+ });
+
+ ed.addCommand('WP_Page', function() {
+ ed.execCommand('mceInsertContent', 0, nextpageHTML);
+ });
+
+ ed.addCommand('WP_Help', function() {
+ ed.windowManager.open({
+ url : tinymce.baseURL + '/wp-mce-help.php',
+ width : 450,
+ height : 420,
+ inline : 1
+ });
+ });
+
+ ed.addCommand('WP_Adv', function() {
+ var cm = ed.controlManager, id = cm.get(tbId).id;
+
+ if ( 'undefined' == id )
+ return;
+
+ if ( DOM.isHidden(id) ) {
+ cm.setActive('wp_adv', 1);
+ DOM.show(id);
+ t._resizeIframe(ed, tbId, -28);
+ ed.settings.wordpress_adv_hidden = 0;
+ setUserSetting('hidetb', '1');
+ } else {
+ cm.setActive('wp_adv', 0);
+ DOM.hide(id);
+ t._resizeIframe(ed, tbId, 28);
+ ed.settings.wordpress_adv_hidden = 1;
+ setUserSetting('hidetb', '0');
+ }
+ });
+
+ ed.addCommand('WP_Medialib', function() {
+ if ( typeof wp !== 'undefined' && wp.media && wp.media.editor )
+ wp.media.editor.open( ed.id );
+ });
+
+ // Register buttons
+ ed.addButton('wp_more', {
+ title : 'wordpress.wp_more_desc',
+ cmd : 'WP_More'
+ });
+
+ ed.addButton('wp_page', {
+ title : 'wordpress.wp_page_desc',
+ image : url + '/img/page.gif',
+ cmd : 'WP_Page'
+ });
+
+ ed.addButton('wp_help', {
+ title : 'wordpress.wp_help_desc',
+ cmd : 'WP_Help'
+ });
+
+ ed.addButton('wp_adv', {
+ title : 'wordpress.wp_adv_desc',
+ cmd : 'WP_Adv'
+ });
+
+ // Add Media button
+ ed.addButton('add_media', {
+ title : 'wordpress.add_media',
+ image : url + '/img/image.gif',
+ cmd : 'WP_Medialib'
+ });
+
+ // Add Media buttons to fullscreen and handle align buttons for image captions
+ ed.onBeforeExecCommand.add(function(ed, cmd, ui, val, o) {
+ var DOM = tinymce.DOM, n, DL, DIV, cls, a, align;
+ if ( 'mceFullScreen' == cmd ) {
+ if ( 'mce_fullscreen' != ed.id && DOM.select('a.thickbox').length )
+ ed.settings.theme_advanced_buttons1 += ',|,add_media';
+ }
+
+ if ( 'JustifyLeft' == cmd || 'JustifyRight' == cmd || 'JustifyCenter' == cmd ) {
+ n = ed.selection.getNode();
+
+ if ( n.nodeName == 'IMG' ) {
+ align = cmd.substr(7).toLowerCase();
+ a = 'align' + align;
+ DL = ed.dom.getParent(n, 'dl.wp-caption');
+ DIV = ed.dom.getParent(n, 'div.mceTemp');
+
+ if ( DL && DIV ) {
+ cls = ed.dom.hasClass(DL, a) ? 'alignnone' : a;
+ DL.className = DL.className.replace(/align[^ '"]+\s?/g, '');
+ ed.dom.addClass(DL, cls);
+
+ if (cls == 'aligncenter')
+ ed.dom.addClass(DIV, 'mceIEcenter');
+ else
+ ed.dom.removeClass(DIV, 'mceIEcenter');
+
+ o.terminate = true;
+ ed.execCommand('mceRepaint');
+ } else {
+ if ( ed.dom.hasClass(n, a) )
+ ed.dom.addClass(n, 'alignnone');
+ else
+ ed.dom.removeClass(n, 'alignnone');
+ }
+ }
+ }
+
+ if ( tinymce.isWebKit && ( 'InsertUnorderedList' == cmd || 'InsertOrderedList' == cmd ) ) {
+ if ( !style )
+ style = ed.dom.create('style', {'type': 'text/css'}, '#tinymce,#tinymce span,#tinymce li,#tinymce li>span,#tinymce p,#tinymce p>span{font:medium sans-serif;color:#000;line-height:normal;}');
+
+ ed.getDoc().head.appendChild( style );
+ }
+ });
+
+ ed.onExecCommand.add( function( ed, cmd, ui, val ) {
+ if ( tinymce.isWebKit && style && ( 'InsertUnorderedList' == cmd || 'InsertOrderedList' == cmd ) )
+ ed.dom.remove( style );
+ });
+
+ ed.onInit.add(function(ed) {
+ var bodyClass = ed.getParam('body_class', ''), body = ed.getBody();
+
+ // add body classes
+ if ( bodyClass )
+ bodyClass = bodyClass.split(' ');
+ else
+ bodyClass = [];
+
+ if ( ed.getParam('directionality', '') == 'rtl' )
+ bodyClass.push('rtl');
+
+ if ( tinymce.isIE9 )
+ bodyClass.push('ie9');
+ else if ( tinymce.isIE8 )
+ bodyClass.push('ie8');
+ else if ( tinymce.isIE7 )
+ bodyClass.push('ie7');
+
+ if ( ed.id != 'wp_mce_fullscreen' && ed.id != 'mce_fullscreen' )
+ bodyClass.push('wp-editor');
+ else if ( ed.id == 'mce_fullscreen' )
+ bodyClass.push('mce-fullscreen');
+
+ tinymce.each( bodyClass, function(cls){
+ if ( cls )
+ ed.dom.addClass(body, cls);
+ });
+
+ // make sure these run last
+ ed.onNodeChange.add( function(ed, cm, e) {
+ var DL;
+
+ if ( e.nodeName == 'IMG' ) {
+ DL = ed.dom.getParent(e, 'dl.wp-caption');
+ } else if ( e.nodeName == 'DIV' && ed.dom.hasClass(e, 'mceTemp') ) {
+ DL = e.firstChild;
+
+ if ( ! ed.dom.hasClass(DL, 'wp-caption') )
+ DL = false;
+ }
+
+ if ( DL ) {
+ if ( ed.dom.hasClass(DL, 'alignleft') )
+ cm.setActive('justifyleft', 1);
+ else if ( ed.dom.hasClass(DL, 'alignright') )
+ cm.setActive('justifyright', 1);
+ else if ( ed.dom.hasClass(DL, 'aligncenter') )
+ cm.setActive('justifycenter', 1);
+ }
+ });
+
+ // remove invalid parent paragraphs when pasting HTML and/or switching to the HTML editor and back
+ ed.onBeforeSetContent.add(function(ed, o) {
+ if ( o.content ) {
+ o.content = o.content.replace(/<p>\s*<(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre|address)( [^>]*)?>/gi, '<$1$2>');
+ o.content = o.content.replace(/<\/(p|div|ul|ol|dl|table|blockquote|h[1-6]|fieldset|pre|address)>\s*<\/p>/gi, '</$1>');
+ }
+ });
+ });
+
+ // Word count
+ if ( 'undefined' != typeof(jQuery) ) {
+ ed.onKeyUp.add(function(ed, e) {
+ var k = e.keyCode || e.charCode;
+
+ if ( k == last )
+ return;
+
+ if ( 13 == k || 8 == last || 46 == last )
+ jQuery(document).triggerHandler('wpcountwords', [ ed.getContent({format : 'raw'}) ]);
+
+ last = k;
+ });
+ };
+
+ // keep empty paragraphs :(
+ ed.onSaveContent.addToTop(function(ed, o) {
+ o.content = o.content.replace(/<p>(<br ?\/?>|\u00a0|\uFEFF)?<\/p>/g, '<p>&nbsp;</p>');
+ });
+
+ ed.onSaveContent.add(function(ed, o) {
+ // If editor is hidden, we just want the textarea's value to be saved
+ if ( ed.isHidden() )
+ o.content = o.element.value;
+ else if ( ed.getParam('wpautop', true) && typeof(switchEditors) == 'object' )
+ o.content = switchEditors.pre_wpautop(o.content);
+ });
+
+ /* disable for now
+ ed.onBeforeSetContent.add(function(ed, o) {
+ o.content = t._setEmbed(o.content);
+ });
+
+ ed.onPostProcess.add(function(ed, o) {
+ if ( o.get )
+ o.content = t._getEmbed(o.content);
+ });
+ */
+
+ // Add listeners to handle more break
+ t._handleMoreBreak(ed, url);
+
+ // Add custom shortcuts
+ mod_key = 'alt+shift';
+
+ // if ( tinymce.isGecko ) // disable for mow, too many shortcuts conflicts
+ // mod_key = 'ctrl+alt';
+
+ ed.addShortcut(mod_key + '+c', 'justifycenter_desc', 'JustifyCenter');
+ ed.addShortcut(mod_key + '+r', 'justifyright_desc', 'JustifyRight');
+ ed.addShortcut(mod_key + '+l', 'justifyleft_desc', 'JustifyLeft');
+ ed.addShortcut(mod_key + '+j', 'justifyfull_desc', 'JustifyFull');
+ ed.addShortcut(mod_key + '+q', 'blockquote_desc', 'mceBlockQuote');
+ ed.addShortcut(mod_key + '+u', 'bullist_desc', 'InsertUnorderedList');
+ ed.addShortcut(mod_key + '+o', 'numlist_desc', 'InsertOrderedList');
+ ed.addShortcut(mod_key + '+n', 'spellchecker.desc', 'mceSpellCheck');
+ ed.addShortcut(mod_key + '+a', 'link_desc', 'WP_Link');
+ ed.addShortcut(mod_key + '+s', 'unlink_desc', 'unlink');
+ ed.addShortcut(mod_key + '+m', 'image_desc', 'WP_Medialib');
+ ed.addShortcut(mod_key + '+z', 'wordpress.wp_adv_desc', 'WP_Adv');
+ ed.addShortcut(mod_key + '+t', 'wordpress.wp_more_desc', 'WP_More');
+ ed.addShortcut(mod_key + '+d', 'striketrough_desc', 'Strikethrough');
+ ed.addShortcut(mod_key + '+h', 'help_desc', 'WP_Help');
+ ed.addShortcut(mod_key + '+p', 'wordpress.wp_page_desc', 'WP_Page');
+ ed.addShortcut('ctrl+s', 'save_desc', function(){if('function'==typeof autosave)autosave();});
+
+ if ( /\bwpfullscreen\b/.test(ed.settings.plugins) )
+ ed.addShortcut(mod_key + '+w', 'wordpress.wp_fullscreen_desc', 'wpFullScreen');
+ else if ( /\bfullscreen\b/.test(ed.settings.plugins) )
+ ed.addShortcut(mod_key + '+g', 'fullscreen.desc', 'mceFullScreen');
+
+ // popup buttons for images and the gallery
+ ed.onInit.add(function(ed) {
+ tinymce.dom.Event.add(ed.getWin(), 'scroll', function(e) {
+ ed.plugins.wordpress._hideButtons();
+ });
+ tinymce.dom.Event.add(ed.getBody(), 'dragstart', function(e) {
+ ed.plugins.wordpress._hideButtons();
+ });
+ });
+
+ ed.onBeforeExecCommand.add(function(ed, cmd, ui, val) {
+ ed.plugins.wordpress._hideButtons();
+ });
+
+ ed.onSaveContent.add(function(ed, o) {
+ ed.plugins.wordpress._hideButtons();
+ });
+
+ ed.onMouseDown.add(function(ed, e) {
+ if ( e.target.nodeName != 'IMG' )
+ ed.plugins.wordpress._hideButtons();
+ });
+
+ ed.onKeyDown.add(function(ed, e){
+ if ( e.which == tinymce.VK.DELETE || e.which == tinymce.VK.BACKSPACE )
+ ed.plugins.wordpress._hideButtons();
+ });
+
+ closeOnClick = function(e){
+ var id;
+
+ if ( e.target.id == 'mceModalBlocker' || e.target.className == 'ui-widget-overlay' ) {
+ for ( id in ed.windowManager.windows ) {
+ ed.windowManager.close(null, id);
+ }
+ }
+ }
+
+ // close popups when clicking on the background
+ tinymce.dom.Event.remove(document.body, 'click', closeOnClick);
+ tinymce.dom.Event.add(document.body, 'click', closeOnClick);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'WordPress Plugin',
+ author : 'WordPress', // add Moxiecode?
+ authorurl : 'http://wordpress.org',
+ infourl : 'http://wordpress.org',
+ version : '3.0'
+ };
+ },
+
+ // Internal functions
+ _setEmbed : function(c) {
+ return c.replace(/\[embed\]([\s\S]+?)\[\/embed\][\s\u00a0]*/g, function(a,b){
+ return '<img width="300" height="200" src="' + tinymce.baseURL + '/plugins/wordpress/img/trans.gif" class="wp-oembed mceItemNoResize" alt="'+b+'" title="'+b+'" />';
+ });
+ },
+
+ _getEmbed : function(c) {
+ return c.replace(/<img[^>]+>/g, function(a) {
+ if ( a.indexOf('class="wp-oembed') != -1 ) {
+ var u = a.match(/alt="([^\"]+)"/);
+ if ( u[1] )
+ a = '[embed]' + u[1] + '[/embed]';
+ }
+ return a;
+ });
+ },
+
+ _showButtons : function(n, id) {
+ var ed = tinyMCE.activeEditor, p1, p2, vp, DOM = tinymce.DOM, X, Y;
+
+ vp = ed.dom.getViewPort(ed.getWin());
+ p1 = DOM.getPos(ed.getContentAreaContainer());
+ p2 = ed.dom.getPos(n);
+
+ X = Math.max(p2.x - vp.x, 0) + p1.x;
+ Y = Math.max(p2.y - vp.y, 0) + p1.y;
+
+ DOM.setStyles(id, {
+ 'top' : Y+5+'px',
+ 'left' : X+5+'px',
+ 'display' : 'block'
+ });
+ },
+
+ _hideButtons : function() {
+ var DOM = tinymce.DOM;
+ DOM.hide( DOM.select('#wp_editbtns, #wp_gallerybtns') );
+ },
+
+ // Resizes the iframe by a relative height value
+ _resizeIframe : function(ed, tb_id, dy) {
+ var ifr = ed.getContentAreaContainer().firstChild;
+
+ DOM.setStyle(ifr, 'height', ifr.clientHeight + dy); // Resize iframe
+ ed.theme.deltaHeight += dy; // For resize cookie
+ },
+
+ _handleMoreBreak : function(ed, url) {
+ var moreHTML, nextpageHTML;
+
+ moreHTML = '<img src="' + url + '/img/trans.gif" alt="$1" class="mce-wp-more mceItemNoResize" title="'+ed.getLang('wordpress.wp_more_alt')+'" />';
+ nextpageHTML = '<img src="' + url + '/img/trans.gif" class="mce-wp-nextpage mceItemNoResize" title="'+ed.getLang('wordpress.wp_page_alt')+'" />';
+
+ // Display morebreak instead if img in element path
+ ed.onPostRender.add(function() {
+ if (ed.theme.onResolveName) {
+ ed.theme.onResolveName.add(function(th, o) {
+ if (o.node.nodeName == 'IMG') {
+ if ( ed.dom.hasClass(o.node, 'mce-wp-more') )
+ o.name = 'wpmore';
+ if ( ed.dom.hasClass(o.node, 'mce-wp-nextpage') )
+ o.name = 'wppage';
+ }
+
+ });
+ }
+ });
+
+ // Replace morebreak with images
+ ed.onBeforeSetContent.add(function(ed, o) {
+ if ( o.content ) {
+ o.content = o.content.replace(/<!--more(.*?)-->/g, moreHTML);
+ o.content = o.content.replace(/<!--nextpage-->/g, nextpageHTML);
+ }
+ });
+
+ // Replace images with morebreak
+ ed.onPostProcess.add(function(ed, o) {
+ if (o.get)
+ o.content = o.content.replace(/<img[^>]+>/g, function(im) {
+ if (im.indexOf('class="mce-wp-more') !== -1) {
+ var m, moretext = (m = im.match(/alt="(.*?)"/)) ? m[1] : '';
+ im = '<!--more'+moretext+'-->';
+ }
+ if (im.indexOf('class="mce-wp-nextpage') !== -1)
+ im = '<!--nextpage-->';
+
+ return im;
+ });
+ });
+
+ // Set active buttons if user selected pagebreak or more break
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setActive('wp_page', n.nodeName === 'IMG' && ed.dom.hasClass(n, 'mce-wp-nextpage'));
+ cm.setActive('wp_more', n.nodeName === 'IMG' && ed.dom.hasClass(n, 'mce-wp-more'));
+ });
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('wordpress', tinymce.plugins.WordPress);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/img/audio.gif b/src/wp-includes/js/tinymce/plugins/wordpress/img/audio.gif
new file mode 100644
index 0000000000..f8ad22383a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/img/audio.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/img/image.gif b/src/wp-includes/js/tinymce/plugins/wordpress/img/image.gif
new file mode 100644
index 0000000000..cf464afec1
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/img/image.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/img/media.gif b/src/wp-includes/js/tinymce/plugins/wordpress/img/media.gif
new file mode 100644
index 0000000000..786e4f55de
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/img/media.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/img/page.gif b/src/wp-includes/js/tinymce/plugins/wordpress/img/page.gif
new file mode 100644
index 0000000000..1cea78ac2b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/img/page.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif b/src/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif
new file mode 100644
index 0000000000..388486517f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wordpress/img/video.gif b/src/wp-includes/js/tinymce/plugins/wordpress/img/video.gif
new file mode 100644
index 0000000000..ddd20b1279
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wordpress/img/video.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin_src.js
new file mode 100644
index 0000000000..b301413b2d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpdialogs/editor_plugin_src.js
@@ -0,0 +1,80 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.WPDialogs', {
+ init : function(ed, url) {
+ tinymce.create('tinymce.WPWindowManager:tinymce.InlineWindowManager', {
+ WPWindowManager : function(ed) {
+ this.parent(ed);
+ },
+
+ open : function(f, p) {
+ var t = this, element;
+
+ if ( ! f.wpDialog )
+ return this.parent( f, p );
+ else if ( ! f.id )
+ return;
+
+ element = jQuery('#' + f.id);
+ if ( ! element.length )
+ return;
+
+ t.features = f;
+ t.params = p;
+ t.onOpen.dispatch(t, f, p);
+ t.element = t.windows[ f.id ] = element;
+
+ // Store selection
+ t.bookmark = t.editor.selection.getBookmark(1);
+
+ // Create the dialog if necessary
+ if ( ! element.data('wpdialog') ) {
+ element.wpdialog({
+ title: f.title,
+ width: f.width,
+ height: f.height,
+ modal: true,
+ dialogClass: 'wp-dialog',
+ zIndex: 300000
+ });
+ }
+
+ element.wpdialog('open');
+ },
+ close : function() {
+ if ( ! this.features.wpDialog )
+ return this.parent.apply( this, arguments );
+
+ this.element.wpdialog('close');
+ }
+ });
+
+ // Replace window manager
+ ed.onBeforeRenderUI.add(function() {
+ ed.windowManager = new tinymce.WPWindowManager(ed);
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'WPDialogs',
+ author : 'WordPress',
+ authorurl : 'http://wordpress.org',
+ infourl : 'http://wordpress.org',
+ version : '0.1'
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('wpdialogs', tinymce.plugins.WPDialogs);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/wpdialogs/js/popup.js b/src/wp-includes/js/tinymce/plugins/wpdialogs/js/popup.js
new file mode 100644
index 0000000000..e8c7d1d0ab
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpdialogs/js/popup.js
@@ -0,0 +1,432 @@
+/**
+ * popup.js
+ *
+ * An altered version of tinyMCEPopup to work in the same window as tinymce.
+ *
+ * ------------------------------------------------------------------
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+// Some global instances
+
+/**
+ * TinyMCE popup/dialog helper class. This gives you easy access to the
+ * parent editor instance and a bunch of other things. It's higly recommended
+ * that you load this script into your dialogs.
+ *
+ * @static
+ * @class tinyMCEPopup
+ */
+var tinyMCEPopup = {
+ /**
+ * Initializes the popup this will be called automatically.
+ *
+ * @method init
+ */
+ init : function() {
+ var t = this, w, ti;
+
+ // Find window & API
+ w = t.getWin();
+ tinymce = w.tinymce;
+ tinyMCE = w.tinyMCE;
+ t.editor = tinymce.EditorManager.activeEditor;
+ t.params = t.editor.windowManager.params;
+ t.features = t.editor.windowManager.features;
+ t.dom = tinymce.dom;
+
+ // Setup on init listeners
+ t.listeners = [];
+ t.onInit = {
+ add : function(f, s) {
+ t.listeners.push({func : f, scope : s});
+ }
+ };
+
+ t.isWindow = false;
+ t.id = t.features.id;
+ t.editor.windowManager.onOpen.dispatch(t.editor.windowManager, window);
+ },
+
+ /**
+ * Returns the reference to the parent window that opened the dialog.
+ *
+ * @method getWin
+ * @return {Window} Reference to the parent window that opened the dialog.
+ */
+ getWin : function() {
+ return window;
+ },
+
+ /**
+ * Returns a window argument/parameter by name.
+ *
+ * @method getWindowArg
+ * @param {String} n Name of the window argument to retrieve.
+ * @param {String} dv Optional default value to return.
+ * @return {String} Argument value or default value if it wasn't found.
+ */
+ getWindowArg : function(n, dv) {
+ var v = this.params[n];
+
+ return tinymce.is(v) ? v : dv;
+ },
+
+ /**
+ * Returns a editor parameter/config option value.
+ *
+ * @method getParam
+ * @param {String} n Name of the editor config option to retrieve.
+ * @param {String} dv Optional default value to return.
+ * @return {String} Parameter value or default value if it wasn't found.
+ */
+ getParam : function(n, dv) {
+ return this.editor.getParam(n, dv);
+ },
+
+ /**
+ * Returns a language item by key.
+ *
+ * @method getLang
+ * @param {String} n Language item like mydialog.something.
+ * @param {String} dv Optional default value to return.
+ * @return {String} Language value for the item like "my string" or the default value if it wasn't found.
+ */
+ getLang : function(n, dv) {
+ return this.editor.getLang(n, dv);
+ },
+
+ /**
+ * Executed a command on editor that opened the dialog/popup.
+ *
+ * @method execCommand
+ * @param {String} cmd Command to execute.
+ * @param {Boolean} ui Optional boolean value if the UI for the command should be presented or not.
+ * @param {Object} val Optional value to pass with the comman like an URL.
+ * @param {Object} a Optional arguments object.
+ */
+ execCommand : function(cmd, ui, val, a) {
+ a = a || {};
+ a.skip_focus = 1;
+
+ this.restoreSelection();
+ return this.editor.execCommand(cmd, ui, val, a);
+ },
+
+ /**
+ * Resizes the dialog to the inner size of the window. This is needed since various browsers
+ * have different border sizes on windows.
+ *
+ * @method resizeToInnerSize
+ */
+ resizeToInnerSize : function() {
+ var t = this;
+
+ // Detach it to workaround a Chrome specific bug
+ // https://sourceforge.net/tracker/?func=detail&atid=635682&aid=2926339&group_id=103281
+ setTimeout(function() {
+ var vp = t.dom.getViewPort(window);
+
+ t.editor.windowManager.resizeBy(
+ t.getWindowArg('mce_width') - vp.w,
+ t.getWindowArg('mce_height') - vp.h,
+ t.id || window
+ );
+ }, 0);
+ },
+
+ /**
+ * Will executed the specified string when the page has been loaded. This function
+ * was added for compatibility with the 2.x branch.
+ *
+ * @method executeOnLoad
+ * @param {String} s String to evalutate on init.
+ */
+ executeOnLoad : function(s) {
+ this.onInit.add(function() {
+ eval(s);
+ });
+ },
+
+ /**
+ * Stores the current editor selection for later restoration. This can be useful since some browsers
+ * loses its selection if a control element is selected/focused inside the dialogs.
+ *
+ * @method storeSelection
+ */
+ storeSelection : function() {
+ this.editor.windowManager.bookmark = tinyMCEPopup.editor.selection.getBookmark(1);
+ },
+
+ /**
+ * Restores any stored selection. This can be useful since some browsers
+ * loses its selection if a control element is selected/focused inside the dialogs.
+ *
+ * @method restoreSelection
+ */
+ restoreSelection : function() {
+ var t = tinyMCEPopup;
+
+ if (!t.isWindow && tinymce.isIE)
+ t.editor.selection.moveToBookmark(t.editor.windowManager.bookmark);
+ },
+
+ /**
+ * Loads a specific dialog language pack. If you pass in plugin_url as a arugment
+ * when you open the window it will load the <plugin url>/langs/<code>_dlg.js lang pack file.
+ *
+ * @method requireLangPack
+ */
+ requireLangPack : function() {
+ var t = this, u = t.getWindowArg('plugin_url') || t.getWindowArg('theme_url');
+
+ if (u && t.editor.settings.language && t.features.translate_i18n !== false) {
+ u += '/langs/' + t.editor.settings.language + '_dlg.js';
+
+ if (!tinymce.ScriptLoader.isDone(u)) {
+ document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"></script>');
+ tinymce.ScriptLoader.markDone(u);
+ }
+ }
+ },
+
+ /**
+ * Executes a color picker on the specified element id. When the user
+ * then selects a color it will be set as the value of the specified element.
+ *
+ * @method pickColor
+ * @param {DOMEvent} e DOM event object.
+ * @param {string} element_id Element id to be filled with the color value from the picker.
+ */
+ pickColor : function(e, element_id) {
+ this.execCommand('mceColorPicker', true, {
+ color : document.getElementById(element_id).value,
+ func : function(c) {
+ document.getElementById(element_id).value = c;
+
+ try {
+ document.getElementById(element_id).onchange();
+ } catch (ex) {
+ // Try fire event, ignore errors
+ }
+ }
+ });
+ },
+
+ /**
+ * Opens a filebrowser/imagebrowser this will set the output value from
+ * the browser as a value on the specified element.
+ *
+ * @method openBrowser
+ * @param {string} element_id Id of the element to set value in.
+ * @param {string} type Type of browser to open image/file/flash.
+ * @param {string} option Option name to get the file_broswer_callback function name from.
+ */
+ openBrowser : function(element_id, type, option) {
+ tinyMCEPopup.restoreSelection();
+ this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window);
+ },
+
+ /**
+ * Creates a confirm dialog. Please don't use the blocking behavior of this
+ * native version use the callback method instead then it can be extended.
+ *
+ * @method confirm
+ * @param {String} t Title for the new confirm dialog.
+ * @param {function} cb Callback function to be executed after the user has selected ok or cancel.
+ * @param {Object} s Optional scope to execute the callback in.
+ */
+ confirm : function(t, cb, s) {
+ this.editor.windowManager.confirm(t, cb, s, window);
+ },
+
+ /**
+ * Creates an alert dialog. Please don't use the blocking behavior of this
+ * native version use the callback method instead then it can be extended.
+ *
+ * @method alert
+ * @param {String} t Title for the new alert dialog.
+ * @param {function} cb Callback function to be executed after the user has selected ok.
+ * @param {Object} s Optional scope to execute the callback in.
+ */
+ alert : function(tx, cb, s) {
+ this.editor.windowManager.alert(tx, cb, s, window);
+ },
+
+ /**
+ * Closes the current window.
+ *
+ * @method close
+ */
+ close : function() {
+ var t = this;
+
+ // To avoid domain relaxing issue in Opera
+ function close() {
+ t.editor.windowManager.close(window);
+ t.editor = null;
+ };
+
+ if (tinymce.isOpera)
+ t.getWin().setTimeout(close, 0);
+ else
+ close();
+ },
+
+ // Internal functions
+
+ _restoreSelection : function() {
+ var e = window.event.srcElement;
+
+ if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button'))
+ tinyMCEPopup.restoreSelection();
+ },
+
+/* _restoreSelection : function() {
+ var e = window.event.srcElement;
+
+ // If user focus a non text input or textarea
+ if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text')
+ tinyMCEPopup.restoreSelection();
+ },*/
+
+ _onDOMLoaded : function() {
+ var t = tinyMCEPopup, ti = document.title, bm, h, nv;
+
+ if (t.domLoaded)
+ return;
+
+ t.domLoaded = 1;
+
+ tinyMCEPopup.init();
+
+ // Translate page
+ if (t.features.translate_i18n !== false) {
+ h = document.body.innerHTML;
+
+ // Replace a=x with a="x" in IE
+ if (tinymce.isIE)
+ h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"')
+
+ document.dir = t.editor.getParam('directionality','');
+
+ if ((nv = t.editor.translate(h)) && nv != h)
+ document.body.innerHTML = nv;
+
+ if ((nv = t.editor.translate(ti)) && nv != ti)
+ document.title = ti = nv;
+ }
+
+ document.body.style.display = '';
+
+ // Restore selection in IE when focus is placed on a non textarea or input element of the type text
+ if (tinymce.isIE) {
+ document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection);
+
+ // Add base target element for it since it would fail with modal dialogs
+ t.dom.add(t.dom.select('head')[0], 'base', {target : '_self'});
+ }
+
+ t.restoreSelection();
+
+ // Set inline title
+ if (!t.isWindow)
+ t.editor.windowManager.setTitle(window, ti);
+ else
+ window.focus();
+
+ if (!tinymce.isIE && !t.isWindow) {
+ tinymce.dom.Event._add(document, 'focus', function() {
+ t.editor.windowManager.focus(t.id);
+ });
+ }
+
+ // Patch for accessibility
+ tinymce.each(t.dom.select('select'), function(e) {
+ e.onkeydown = tinyMCEPopup._accessHandler;
+ });
+
+ // Call onInit
+ // Init must be called before focus so the selection won't get lost by the focus call
+ tinymce.each(t.listeners, function(o) {
+ o.func.call(o.scope, t.editor);
+ });
+
+ // Move focus to window
+ if (t.getWindowArg('mce_auto_focus', true)) {
+ window.focus();
+
+ // Focus element with mceFocus class
+ tinymce.each(document.forms, function(f) {
+ tinymce.each(f.elements, function(e) {
+ if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) {
+ e.focus();
+ return false; // Break loop
+ }
+ });
+ });
+ }
+
+ document.onkeyup = tinyMCEPopup._closeWinKeyHandler;
+ },
+
+ _accessHandler : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 13 || e.keyCode == 32) {
+ e = e.target || e.srcElement;
+
+ if (e.onchange)
+ e.onchange();
+
+ return tinymce.dom.Event.cancel(e);
+ }
+ },
+
+ _closeWinKeyHandler : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 27)
+ tinyMCEPopup.close();
+ },
+
+ _wait : function() {
+ // Use IE method
+ if (document.attachEvent) {
+ document.attachEvent("onreadystatechange", function() {
+ if (document.readyState === "complete") {
+ document.detachEvent("onreadystatechange", arguments.callee);
+ tinyMCEPopup._onDOMLoaded();
+ }
+ });
+
+ if (document.documentElement.doScroll && window == window.top) {
+ (function() {
+ if (tinyMCEPopup.domLoaded)
+ return;
+
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch (ex) {
+ setTimeout(arguments.callee, 0);
+ return;
+ }
+
+ tinyMCEPopup._onDOMLoaded();
+ })();
+ }
+
+ document.attachEvent('onload', tinyMCEPopup._onDOMLoaded);
+ } else if (document.addEventListener) {
+ window.addEventListener('DOMContentLoaded', tinyMCEPopup._onDOMLoaded, false);
+ window.addEventListener('load', tinyMCEPopup._onDOMLoaded, false);
+ }
+ }
+};
diff --git a/src/wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog.js b/src/wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog.js
new file mode 100644
index 0000000000..cb168ddfad
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog.js
@@ -0,0 +1,28 @@
+(function($){
+ $.ui.dialog.prototype.options.closeOnEscape = false;
+ $.widget('wp.wpdialog', $.ui.dialog, {
+ // Work around a bug in jQuery UI 1.9.1.
+ // http://bugs.jqueryui.com/ticket/8805
+ widgetEventPrefix: 'wpdialog',
+
+ open: function() {
+ var ed;
+
+ // Initialize tinyMCEPopup if it exists and the editor is active.
+ if ( tinyMCEPopup && typeof tinyMCE != 'undefined' && ( ed = tinyMCE.activeEditor ) && !ed.isHidden() ) {
+ tinyMCEPopup.init();
+ }
+
+ // Add beforeOpen event.
+ if ( this.isOpen() || false === this._trigger('beforeOpen') ) {
+ return;
+ }
+
+ // Open the dialog.
+ this._super();
+ // WebKit leaves focus in the TinyMCE editor unless we shift focus.
+ this.element.focus();
+ this._trigger('refresh');
+ }
+ });
+})(jQuery);
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css b/src/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css
new file mode 100644
index 0000000000..e380ad594a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css
@@ -0,0 +1,443 @@
+
+html, body {
+ background-color: #fff;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: sans-serif;
+ font-size: 12px;
+ line-height: 1.4em;
+}
+
+a.button {
+ padding: 4px 8px;
+}
+
+textarea,
+input,
+select {
+ font: inherit;
+ margin: 1px;
+ padding: 3px;
+}
+
+p.help {
+ margin: 4px 0;
+ font-size: 12px;
+ font-style: italic;
+}
+
+abbr.required {
+ color: #FF0000;
+ text-align: left;
+}
+
+img.alignright,
+.alignright {
+ float: right;
+ margin-left: 5px;
+}
+
+img.alignleft,
+.alignleft {
+ float: left;
+ margin-right: 5px;
+}
+
+img.aligncenter {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+label {
+ cursor: pointer;
+}
+
+th.label {
+ width: 107px;
+}
+
+#media-upload #basic th.label {
+ padding: 5px 5px 5px 0;
+}
+
+.show-align {
+ height: 200px;
+ width: 480px;
+ float: right;
+ background-color: #f1f1f1;
+ cursor: default;
+ -moz-user-select: none;
+ user-select: none;
+ overflow: hidden;
+}
+
+#img-edit {
+ border: 1px solid #dfdfdf;
+ width: 623px;
+ margin: 15px auto;
+}
+
+#media-upload .media-upload-form table.describe {
+ border-top-style: none;
+ border-top-width: 0;
+}
+
+#img_demo_txt {
+ font-size: 9px;
+ line-height: 13px;
+ font-family: Monaco,"Courier New",Courier,monospace;
+ color: #888;
+}
+
+#img_demo {
+ padding: 0;
+}
+
+#saveeditimg {
+ padding: 10px 0 0 5px;
+ border-top: 1px solid #ccc;
+}
+
+#sidemenu,
+#sidemenu li {
+ list-style: none;
+}
+
+#sidemenu li {
+ display: inline;
+}
+
+#sidemenu a {
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ border-top-style: solid;
+ border-top-width: 1px;
+ display: block;
+ float: left;
+ height: 28px;
+ line-height: 28px;
+ text-decoration: none;
+ text-align: center;
+ white-space: nowrap;
+ margin: 0;
+ padding: 0pt 7px;
+ background-color: #f9f9f9;
+ border-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+a {
+ color: #21759B;
+}
+
+a:hover,
+a:active,
+a:focus {
+ color: #D54E21;
+}
+
+#sidemenu a.current {
+ -webkit-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ border-style: solid;
+ border-width: 1px;
+ font-weight: normal;
+ background-color: #fff;
+ border-color: #dfdfdf #dfdfdf #fff;
+ color: #D54E21;
+}
+
+#adv_settings .field label {
+ padding: 0 5px 5px;
+}
+
+#media-upload h3 {
+ clear: both;
+ padding: 0pt 0pt 3px;
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+ font-family: Georgia,"Times New Roman",Times,serif;
+ font-size: 20px;
+ font-weight: normal;
+ line-height: normal;
+ margin: 0 0 10px -4px;
+ padding: 15px 0 3px;
+ border-bottom-color: #DADADA;
+ color: #5A5A5A;
+}
+
+#img_dim #width,
+#img_dim #height,
+#img_prop #border,
+#img_prop #vspace,
+#img_prop #hspace {
+ width: 36px;
+}
+
+#img_dim abbr {
+ padding: 0 4px;
+}
+
+#show_align_sp {
+ width: 115px;
+}
+
+#img_dim input,
+#img_prop input {
+ margin-right: 10px;
+}
+
+#basic .align .field label {
+ padding: 0 0 0 24px;
+}
+
+#basic {
+ padding-top: 2px;
+}
+
+td {
+ padding: 2px 0;
+}
+
+#img_size {
+ float: right;
+ text-align: center;
+ cursor: pointer;
+ background-color: #f1f1f1;
+ padding: 5px 0;
+ width: 45px;
+}
+
+#img_size div {
+ font-size: 10px;
+ padding: 2px;
+ border: 1px solid #f1f1f1;
+ line-height: 15px;
+ height: 15px;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ color: #07273E;
+}
+
+#img_size div#s100 {
+ border-color: #A3A3A3;
+ background-color: #E5E5E5;
+}
+
+#img_size_div {
+ width: 100px;
+ float: left;
+ cursor: default;
+}
+
+#img_size_title {
+ margin: 0 7px 5px;
+ text-align: right;
+ font-weight: bold;
+}
+
+#img_align_td {
+ padding: 2px 0 8px;
+}
+
+#media-upload tr.align td.field {
+ text-align: center;
+}
+
+.describe td {
+ vertical-align: middle;
+}
+
+#media-upload .describe th.label {
+ padding-top: .5em;
+ text-align: left;
+}
+
+#media-upload .describe {
+ border-top-width: 1px;
+ border-top-style: solid;
+ padding: 5px;
+ width: 100%;
+ clear: both;
+ cursor: default;
+}
+
+form {
+ margin: 1em;
+}
+
+.describe input[type="text"],
+.describe textarea {
+ width: 460px;
+ border: 1px solid #dfdfdf;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.media-upload-form label,
+.media-upload-form legend {
+ font-weight: bold;
+ font-size: 12px;
+ color: #464646;
+}
+
+.align .field label {
+ display: inline;
+ padding: 0 0 0 28px;
+ margin: 0 1em 0 0;
+}
+
+.image-align-none-label {
+ background: url(../../../../../../wp-admin/images/align-none.png) no-repeat center left;
+}
+
+.image-align-left-label {
+ background: url(../../../../../../wp-admin/images/align-left.png) no-repeat center left;
+}
+
+.image-align-center-label {
+ background: url(../../../../../../wp-admin/images/align-center.png) no-repeat center left;
+}
+
+.image-align-right-label {
+ background: url(../../../../../../wp-admin/images/align-right.png) no-repeat center left;
+}
+
+div#media-upload-header {
+ margin: 0;
+ padding: 0 5px;
+ font-weight: bold;
+ position: relative;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ height: 33px;
+ background-color: #f9f9f9;
+ border-bottom-color: #dfdfdf;
+}
+
+body#media-upload ul#sidemenu {
+ font-weight: normal;
+ margin: 0 5px;
+ position: relative;
+ left: 0px;
+ bottom: -4px;
+}
+
+div#media-upload-error {
+ margin: 1em;
+ font-weight: bold;
+}
+
+#TB_window #TB_title {
+ background-color: #222222;
+ color: #CFCFCF;
+}
+
+.hidden {
+ display: none;
+}
+
+/* RTL */
+body#media-upload.rtl ul#sidemenu {
+ left: auto;
+ right: 0;
+}
+
+.rtl #basic .align .field label {
+ display: block;
+ float: right;
+ padding: 0 24px 0 0;
+ margin: 5px 3px 5px 5px;
+}
+
+.rtl .align .field input {
+ display: block;
+ float: right;
+ margin: 5px 15px 5px 0;
+}
+
+.rtl tr.image-size label {
+ margin: 0;
+}
+
+.rtl tr.image-size input {
+ margin: 3px 15px 0 5px;
+}
+
+.rtl .image-align-none-label,
+.rtl .image-align-left-label,
+.rtl .image-align-center-label,
+.rtl .image-align-right-label {
+ background-position: center right;
+}
+
+#media-upload.rtl .describe th.label {
+ text-align: right;
+}
+
+.rtl .show-align,
+.rtl #img_size,
+.rtl .alignright,
+.rtl #img_demo.alignleft {
+ float: left;
+}
+
+.rtl tr.image-size label,
+.rtl tr.image-size input,
+.rtl #img_dim label,
+.rtl #img_dim input,
+.rtl #img_prop label,
+.rtl #img_prop input,
+.rtl #img_size_div,
+.rtl .alignleft,
+.rtl #img_demo.alignright {
+ float: right;
+}
+
+.rtl #img_dim label,
+.rtl #img_prop label {
+ margin: 5px 0pt;
+}
+
+.rtl #img_dim input,
+.rtl #img_prop input {
+ margin: 0 5px 0 10px;
+}
+
+.rtl #img_size_title {
+ text-align: left;
+}
+
+/**
+ * Retina display 2x icons
+ */
+@media print,
+ (-o-min-device-pixel-ratio: 5/4),
+ (-webkit-min-device-pixel-ratio: 1.25),
+ (min-resolution: 120dpi) {
+ .image-align-none-label {
+ background: url(../../../../../../wp-admin/images/align-none-2x.png) no-repeat center left;
+ background-size: auto 15px;
+ }
+
+ .image-align-left-label {
+ background: url(../../../../../../wp-admin/images/align-left-2x.png) no-repeat center left;
+ background-size: auto 15px;
+ }
+
+ .image-align-center-label {
+ background: url(../../../../../../wp-admin/images/align-center-2x.png) no-repeat center left;
+ background-size: auto 15px;
+ }
+
+ .image-align-right-label {
+ background: url(../../../../../../wp-admin/images/align-right-2x.png) no-repeat center left;
+ background-size: auto 15px;
+ }
+}
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html b/src/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html
new file mode 100644
index 0000000000..32d702b1a8
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html
@@ -0,0 +1,274 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<link rel="stylesheet" href="css/editimage.css?ver=358-20121205" type="text/css" media="all" />
+<link rel="stylesheet" href="../../../../css/buttons.css?ver=358-20121205" type="text/css" media="all" />
+<script type="text/javascript" src="js/editimage.min.js?ver=358-20121205"></script>
+<script type="text/javascript" src="../../utils/form_utils.js?ver=358-20121205"></script>
+<base target="_self" />
+</head>
+
+<body id="media-upload" class="wp-core-ui" style="display:none;">
+<script type="text/javascript">
+if ( 'rtl' == tinyMCEPopup.editor.getParam('directionality','') )
+ document.body.className += ' rtl';
+</script>
+<div id="media-upload-header">
+ <ul id="sidemenu">
+ <li><a href="javascript:;" id="tab_basic" class="current" onclick="wpImage.setTabs(this);">{#wpeditimage.edit_img}</a></li>
+ <li><a href="javascript:;" id="tab_advanced" onclick="wpImage.setTabs(this);">{#wpeditimage.adv_settings}</a></li>
+ </ul>
+</div>
+
+<div id="img-edit">
+<form class="media-upload-form" action="" onsubmit="wpImage.update();">
+ <div id="img_size_div">
+ <div id="img_size_title">{#wpeditimage.size}</div>
+ <div id="img_size" onmouseout="wpImage.showSizeRem()">
+ <div id="s130" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s130}</div>
+ <div id="s120" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s120}</div>
+ <div id="s110" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s110}</div>
+ <div id="s100" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s100}</div>
+ <div id="s90" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s90}</div>
+ <div id="s80" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s80}</div>
+ <div id="s70" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s70}</div>
+ <div id="s60" onmouseover="wpImage.showSize(this)" onclick="wpImage.imgEditSize(this)">{#wpeditimage.s60}</div>
+ </div>
+ </div>
+ <div class="show-align" id="show_align">
+ <img id="img_demo" src="img/image.png" alt="" />
+ <span id="img_demo_txt">
+ Lorem ipsum dolor sit amet consectetuer velit pretium euismod ipsum enim. Mi cursus at a mollis senectus id arcu gravida quis urna. Sed et felis id tempus Morbi mauris tincidunt enim In mauris. Pede eu risus velit libero natoque enim lorem adipiscing ipsum consequat. In malesuada et sociis tincidunt tempus pellentesque cursus convallis ipsum Suspendisse. Risus In ac quis ut Nunc convallis laoreet ante Suspendisse Nam. Amet amet urna condimentum Vestibulum sem at Curabitur lorem et cursus. Sodales tortor fermentum leo dui habitant Nunc Sed Vestibulum.
+ Ut lorem In penatibus libero id ipsum sagittis nec elit Sed. Condimentum eget Vivamus vel consectetuer lorem molestie turpis amet tellus id. Condimentum vel ridiculus Fusce sed pede Nam nunc sodales eros tempor. Sit lacus magna dictumst Curabitur fringilla auctor id vitae wisi facilisi. Fermentum eget turpis felis velit leo Nunc Proin orci molestie Praesent. Curabitur tellus scelerisque suscipit ut sem amet cursus mi Morbi eu. Donec libero Vestibulum augue et mollis accumsan ornare condimentum In enim. Leo eget ac consectetuer quis condimentum malesuada.
+ Condimentum commodo et Lorem fringilla malesuada libero volutpat sem tellus enim. Tincidunt sed at Aenean nec nonummy porttitor Nam Sed Nulla ut. Auctor leo In aliquet Curabitur eros et velit Quisque justo morbi. Et vel mauris sit nulla semper vitae et quis at dui. Id at elit laoreet justo eu mauris Quisque et interdum pharetra. Nullam accumsan interdum Maecenas condimentum quis quis Fusce a sollicitudin Sed. Non Quisque Vivamus congue porttitor non semper ipsum porttitor quis vel. Donec eros lacus volutpat et tincidunt sem convallis id venenatis sit. Consectetuer odio.
+ Semper faucibus Morbi nulla convallis orci Aliquam Sed porttitor et Pellentesque. Venenatis laoreet lorem id a a Morbi augue turpis id semper. Arcu volutpat ac mauris Vestibulum fringilla Aenean condimentum nibh sed id. Sagittis eu lacus orci urna tellus tellus pretium Curabitur dui nunc. Et nibh eu eu nibh adipiscing at lorem Vestibulum adipiscing augue. Magna convallis Phasellus dolor malesuada Curabitur ornare adipiscing tellus Aliquam tempus. Id Aliquam Integer augue Nulla consectetuer ac Donec Curabitur tincidunt et. Id vel Nunc amet lacus dui magna ridiculus penatibus laoreet Duis. Enim sagittis nibh quis Nulla nec laoreet vel Maecenas mattis vel.
+ </span>
+ </div>
+
+ <div id="div_basic">
+ <table id="basic" class="describe">
+ <tbody>
+
+ <tr class="align">
+ <th valign="top" scope="row" class="label">
+ <label for="img_align_td">
+ <span class="alignleft">{#contextmenu.align}</span>
+ </label>
+ </th>
+ <td class="field" id="img_align_td">
+ <input type="radio" onclick="wpImage.imgAlignCls('alignnone')" name="img_align" id="alignnone" value="alignnone" />
+ <label for="alignnone" class="align image-align-none-label">{#wpeditimage.none}</label>
+
+ <input type="radio" onclick="wpImage.imgAlignCls('alignleft')" name="img_align" id="alignleft" value="alignleft" />
+ <label for="alignleft" class="align image-align-left-label">{#contextmenu.left}</label>
+
+ <input type="radio" onclick="wpImage.imgAlignCls('aligncenter')" name="img_align" id="aligncenter" value="aligncenter" />
+ <label for="aligncenter" class="align image-align-center-label">{#contextmenu.center}</label>
+
+ <input type="radio" onclick="wpImage.imgAlignCls('alignright')" name="img_align" id="alignright" value="alignright" />
+ <label for="alignright" class="align image-align-right-label">{#contextmenu.right}</label>
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="img_title">
+ <span class="alignleft">{#wpeditimage.img_title}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="img_title" name="img_title" value="" aria-required="true" size="60" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="img_alt">
+ <span class="alignleft">{#wpeditimage.alt}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="img_alt" name="img_alt" value="" size="60" />
+ </td>
+ </tr>
+
+ <tr id="cap_field">
+ <th valign="top" scope="row" class="label">
+ <label for="img_cap">
+ <span class="alignleft">{#wpeditimage.caption}</span>
+ </label>
+ </th>
+ <td class="field">
+ <textarea id="img_cap_text"></textarea>
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="link_href">
+ <span class="alignleft" id="lb_link_href">{#advanced_dlg.link_url}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="link_href" name="link_href" value="" size="60" /><br />
+ <input type="button" class="button" onclick="wpImage.I('link_href').value='';" value="{#wpeditimage.none}" />
+ <input type="button" class="button" id="img_url_current" onclick="wpImage.img_seturl('current')" value="{#wpeditimage.current_link}" />
+ <input type="button" class="button" id="img_url_img" onclick="wpImage.img_seturl('link')" value="{#wpeditimage.link_to_img}" />
+ <p class="help">{#wpeditimage.link_help}</p>
+ </td>
+ </tr>
+ </tbody>
+ </table></div>
+
+ <div id="div_advanced" style="display:none;">
+ <h3>{#wpeditimage.adv_img_settings}</h3>
+ <table id="adv_settings_img" class="describe">
+ <tbody>
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="img_src">
+ <span class="alignleft">{#wpeditimage.source}</span>
+ <span class="alignright"><abbr title="required" class="required">*</abbr></span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="img_src" name="img_src" value="" onblur="wpImage.checkVal(this)" aria-required="true" size="60" />
+ </td>
+ </tr>
+
+ <tr id="img_dim">
+ <th valign="top" scope="row" class="label">
+ <label>
+ <span class="alignleft">{#wpeditimage.size}</span>
+ </label>
+ </th>
+ <td class="field">
+ <label for="width">{#wpeditimage.width}</label>
+ <input type="text" maxlength="5" id="width" name="width" value="" />
+
+ <label for="height">{#wpeditimage.height}</label>
+ <input type="text" maxlength="5" id="height" name="height" value="" />
+
+ <input type="button" class="button" id="orig_size" name="orig_size" value="{#wpeditimage.orig_size}" onclick="wpImage.origSize();" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="img_classes">
+ <span class="alignleft">{#wpeditimage.css}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="img_classes" name="img_classes" value="" size="60" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="img_style">
+ <span class="alignleft">{#advanced.style_select}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="img_style" name="img_style" value="" size="60" onblur="wpImage.demoSetStyle();" />
+ </td>
+ </tr>
+
+ <tr id="img_prop">
+ <th valign="top" scope="row" class="label">
+ <label for="img_prop">
+ <span class="alignleft">{#advanced.image_props_desc}</span>
+ </label>
+ </th>
+ <td class="field">
+ <label for="border">{#advanced_dlg.image_border}</label>
+ <input type="text" maxlength="5" id="border" name="border" value="" onblur="wpImage.updateStyle('border')" />
+
+ <label for="vspace">{#advanced_dlg.image_vspace}</label>
+ <input type="text" maxlength="5" id="vspace" name="vspace" value="" onblur="wpImage.updateStyle('vspace')" />
+
+ <label for="hspace">{#advanced_dlg.image_hspace}</label>
+ <input type="text" maxlength="5" id="hspace" name="hspace" value="" onblur="wpImage.updateStyle('hspace')" />
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <h3>{#wpeditimage.adv_link_settings}</h3>
+ <table id="adv_settings_link" class="describe">
+ <tbody>
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="link_title">
+ <span class="alignleft">{#advanced_dlg.link_titlefield}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="link_title" name="link_title" value="" size="60" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="link_rel">
+ <span class="alignleft">{#wpeditimage.link_rel}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="link_rel" name="link_rel" value="" size="60" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="link_classes">
+ <span class="alignleft">{#wpeditimage.css}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="link_classes" name="link_classes" value="" size="60" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label for="link_style">
+ <span class="alignleft">{#advanced.style_select}</span>
+ </label>
+ </th>
+ <td class="field">
+ <input type="text" id="link_style" name="link_style" value="" size="60" />
+ </td>
+ </tr>
+
+ <tr>
+ <th valign="top" scope="row" class="label">
+ <label>
+ <span class="alignleft">{#advanced_dlg.link_target}</span>
+ </label>
+ </th>
+ <td class="field">
+ <label for="link_target">
+ {#advanced_dlg.link_target_blank}
+ </label>
+ <input type="checkbox" id="link_target" name="link_target" value="_blank" />
+ </td>
+ </tr>
+ </tbody>
+ </table></div>
+
+ <div id="saveeditimg">
+ <input type="hidden" id="align" name="align" value="" />
+
+ <input type="submit" id="saveimg" class="button" value="{#update}" />
+ <input type="button" class="button" id="cancelimg" name="cancelimg" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</div>
+
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js
new file mode 100644
index 0000000000..17aa30e206
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/editor_plugin_src.js
@@ -0,0 +1,325 @@
+
+(function() {
+ tinymce.create('tinymce.plugins.wpEditImage', {
+ url: '',
+ editor: {},
+
+ init: function(ed, url) {
+ var t = this, mouse = {};
+
+ t.url = url;
+ t.editor = ed;
+ t._createButtons();
+
+ ed.addCommand('WP_EditImage', t._editImage);
+
+ ed.onInit.add(function(ed) {
+ ed.dom.events.add(ed.getBody(), 'mousedown', function(e) {
+ var parent;
+
+ if ( e.target.nodeName == 'IMG' && ( parent = ed.dom.getParent(e.target, 'div.mceTemp') ) ) {
+ if ( tinymce.isGecko )
+ ed.selection.select(parent);
+ else if ( tinymce.isWebKit )
+ ed.dom.events.prevent(e);
+ }
+ });
+
+ // when pressing Return inside a caption move the caret to a new parapraph under it
+ ed.dom.events.add(ed.getBody(), 'keydown', function(e) {
+ var n, DL, DIV, P, content;
+
+ if ( e.keyCode == 13 ) {
+ n = ed.selection.getNode();
+ DL = ed.dom.getParent(n, 'dl.wp-caption');
+
+ if ( DL )
+ DIV = ed.dom.getParent(DL, 'div.mceTemp');
+
+ if ( DIV ) {
+ ed.dom.events.cancel(e);
+ P = ed.dom.create('p', {}, '\uFEFF');
+ ed.dom.insertAfter( P, DIV );
+ ed.selection.setCursorLocation(P, 0);
+ return false;
+ }
+ }
+ });
+
+ // iOS6 doesn't show the buttons properly on click, show them on 'touchstart'
+ if ( 'ontouchstart' in window ) {
+ ed.dom.events.add(ed.getBody(), 'touchstart', function(e){
+ t._showButtons(e);
+ });
+ }
+ });
+
+ // resize the caption <dl> when the image is soft-resized by the user
+ ed.onMouseUp.add(function(ed, e) {
+ if ( tinymce.isWebKit || tinymce.isOpera )
+ return;
+
+ if ( mouse.x && (e.clientX != mouse.x || e.clientY != mouse.y) ) {
+ var n = ed.selection.getNode();
+
+ if ( 'IMG' == n.nodeName ) {
+ window.setTimeout(function(){
+ var DL = ed.dom.getParent(n, 'dl.wp-caption'), width;
+
+ if ( n.width != mouse.img_w || n.height != mouse.img_h )
+ n.className = n.className.replace(/size-[^ "']+/, '');
+
+ if ( DL ) {
+ width = ed.dom.getAttrib(n, 'width') || n.width;
+ width = parseInt(width, 10);
+ ed.dom.setStyle(DL, 'width', 10 + width);
+ ed.execCommand('mceRepaint');
+ }
+ }, 100);
+ }
+ }
+ mouse = {};
+ });
+
+ // show editimage buttons
+ ed.onMouseDown.add(function(ed, e){
+ t._showButtons(e);
+ });
+
+ ed.onBeforeSetContent.add(function(ed, o) {
+ o.content = ed.wpSetImgCaption(o.content);
+ });
+
+ ed.onPostProcess.add(function(ed, o) {
+ if (o.get)
+ o.content = ed.wpGetImgCaption(o.content);
+ });
+
+ ed.wpSetImgCaption = function(content) {
+ return t._do_shcode(content);
+ };
+
+ ed.wpGetImgCaption = function(content) {
+ return t._get_shcode(content);
+ };
+
+ // When inserting content, if the caret is inside a caption create new paragraph under
+ // and move the caret there
+ ed.onBeforeExecCommand.add(function(ed, cmd, ui, val) {
+ var node, p;
+
+ if ( cmd == 'mceInsertContent' ) {
+ node = ed.dom.getParent(ed.selection.getNode(), 'div.mceTemp');
+
+ if ( !node )
+ return;
+
+ p = ed.dom.create('p');
+ ed.dom.insertAfter( p, node );
+ ed.selection.setCursorLocation(p, 0);
+ }
+ });
+ },
+
+ _do_shcode : function(content) {
+ return content.replace(/(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?/g, function(a,b,c){
+ var id, cls, w, cap, div_cls, img, trim = tinymce.trim;
+
+ id = b.match(/id=['"]([^'"]*)['"] ?/);
+ if ( id )
+ b = b.replace(id[0], '');
+
+ cls = b.match(/align=['"]([^'"]*)['"] ?/);
+ if ( cls )
+ b = b.replace(cls[0], '');
+
+ w = b.match(/width=['"]([0-9]*)['"] ?/);
+ if ( w )
+ b = b.replace(w[0], '');
+
+ c = trim(c);
+ img = c.match(/((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)([\s\S]*)/i);
+
+ if ( img && img[2] ) {
+ cap = trim( img[2] );
+ img = trim( img[1] );
+ } else {
+ // old captions shortcode style
+ cap = trim(b).replace(/caption=['"]/, '').replace(/['"]$/, '');
+ img = c;
+ }
+
+ id = ( id && id[1] ) ? id[1] : '';
+ cls = ( cls && cls[1] ) ? cls[1] : 'alignnone';
+ w = ( w && w[1] ) ? w[1] : '';
+
+ if ( !w || !cap )
+ return c;
+
+ div_cls = 'mceTemp';
+ if ( cls == 'aligncenter' )
+ div_cls += ' mceIEcenter';
+
+ return '<div class="'+div_cls+'"><dl id="'+id+'" class="wp-caption '+cls+'" style="width: '+( 10 + parseInt(w) )+
+ 'px"><dt class="wp-caption-dt">'+img+'</dt><dd class="wp-caption-dd">'+cap+'</dd></dl></div>';
+ });
+ },
+
+ _get_shcode : function(content) {
+ return content.replace(/<div (?:id="attachment_|class="mceTemp)[^>]*>([\s\S]+?)<\/div>/g, function(a, b){
+ var ret = b.replace(/<dl ([^>]+)>\s*<dt [^>]+>([\s\S]+?)<\/dt>\s*<dd [^>]+>([\s\S]*?)<\/dd>\s*<\/dl>/gi, function(a,b,c,cap){
+ var id, cls, w;
+
+ w = c.match(/width="([0-9]*)"/);
+ w = ( w && w[1] ) ? w[1] : '';
+
+ if ( !w || !cap )
+ return c;
+
+ id = b.match(/id="([^"]*)"/);
+ id = ( id && id[1] ) ? id[1] : '';
+
+ cls = b.match(/class="([^"]*)"/);
+ cls = ( cls && cls[1] ) ? cls[1] : '';
+ cls = cls.match(/align[a-z]+/) || 'alignnone';
+
+ cap = cap.replace(/\r\n|\r/g, '\n').replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
+ // no line breaks inside HTML tags
+ return a.replace(/[\r\n\t]+/, ' ');
+ });
+
+ // convert remaining line breaks to <br>
+ cap = cap.replace(/\s*\n\s*/g, '<br />');
+
+ return '[caption id="'+id+'" align="'+cls+'" width="'+w+'"]'+c+' '+cap+'[/caption]';
+ });
+
+ if ( ret.indexOf('[caption') !== 0 ) {
+ // the caption html seems brocken, try to find the image that may be wrapped in a link
+ // and may be followed by <p> with the caption text.
+ ret = b.replace(/[\s\S]*?((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)(<p>[\s\S]*<\/p>)?[\s\S]*/gi, '<p>$1</p>$2');
+ }
+
+ return ret;
+ });
+ },
+
+ _createButtons : function() {
+ var t = this, ed = tinymce.activeEditor, DOM = tinymce.DOM, editButton, dellButton, isRetina;
+
+ if ( DOM.get('wp_editbtns') )
+ return;
+
+ isRetina = ( window.devicePixelRatio && window.devicePixelRatio > 1 ) || // WebKit, Opera
+ ( window.matchMedia && window.matchMedia('(min-resolution:130dpi)').matches ); // Firefox, IE10, Opera
+
+ DOM.add(document.body, 'div', {
+ id : 'wp_editbtns',
+ style : 'display:none;'
+ });
+
+ editButton = DOM.add('wp_editbtns', 'img', {
+ src : isRetina ? t.url+'/img/image-2x.png' : t.url+'/img/image.png',
+ id : 'wp_editimgbtn',
+ width : '24',
+ height : '24',
+ title : ed.getLang('wpeditimage.edit_img')
+ });
+
+ tinymce.dom.Event.add(editButton, 'mousedown', function(e) {
+ t._editImage();
+ ed.plugins.wordpress._hideButtons();
+ });
+
+ dellButton = DOM.add('wp_editbtns', 'img', {
+ src : isRetina ? t.url+'/img/delete-2x.png' : t.url+'/img/delete.png',
+ id : 'wp_delimgbtn',
+ width : '24',
+ height : '24',
+ title : ed.getLang('wpeditimage.del_img')
+ });
+
+ tinymce.dom.Event.add(dellButton, 'mousedown', function(e) {
+ var ed = tinymce.activeEditor, el = ed.selection.getNode(), parent;
+
+ if ( el.nodeName == 'IMG' && ed.dom.getAttrib(el, 'class').indexOf('mceItem') == -1 ) {
+ if ( (parent = ed.dom.getParent(el, 'div')) && ed.dom.hasClass(parent, 'mceTemp') ) {
+ ed.dom.remove(parent);
+ } else {
+ if ( el.parentNode.nodeName == 'A' && el.parentNode.childNodes.length == 1 )
+ el = el.parentNode;
+
+ if ( el.parentNode.nodeName == 'P' && el.parentNode.childNodes.length == 1 )
+ el = el.parentNode;
+
+ ed.dom.remove(el);
+ }
+
+ ed.execCommand('mceRepaint');
+ return false;
+ }
+ ed.plugins.wordpress._hideButtons();
+ });
+ },
+
+ _editImage : function() {
+ var ed = tinymce.activeEditor, url = this.url, el = ed.selection.getNode(), vp, H, W, cls = el.className;
+
+ if ( cls.indexOf('mceItem') != -1 || cls.indexOf('wpGallery') != -1 || el.nodeName != 'IMG' )
+ return;
+
+ vp = tinymce.DOM.getViewPort();
+ H = 680 < (vp.h - 70) ? 680 : vp.h - 70;
+ W = 650 < vp.w ? 650 : vp.w;
+
+ ed.windowManager.open({
+ file: url + '/editimage.html',
+ width: W+'px',
+ height: H+'px',
+ inline: true
+ });
+ },
+
+ _showButtons : function(e) {
+ var ed = this.editor, target = e.target;
+
+ if ( target.nodeName != 'IMG' ) {
+ if ( target.firstChild && target.firstChild.nodeName == 'IMG' && target.childNodes.length == 1 ) {
+ target = target.firstChild;
+ } else {
+ ed.plugins.wordpress._hideButtons();
+ return;
+ }
+ }
+
+ if ( ed.dom.getAttrib(target, 'class').indexOf('mceItem') == -1 ) {
+ mouse = {
+ x: e.clientX,
+ y: e.clientY,
+ img_w: target.clientWidth,
+ img_h: target.clientHeight
+ };
+
+ if ( e.type == 'touchstart' ) {
+ ed.selection.select(target);
+ ed.dom.events.cancel(e);
+ }
+
+ ed.plugins.wordpress._hideButtons();
+ ed.plugins.wordpress._showButtons(target, 'wp_editbtns');
+ }
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Edit Image',
+ author : 'WordPress',
+ authorurl : 'http://wordpress.org',
+ infourl : '',
+ version : "1.0"
+ };
+ }
+ });
+
+ tinymce.PluginManager.add('wpeditimage', tinymce.plugins.wpEditImage);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete-2x.png b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete-2x.png
new file mode 100644
index 0000000000..859d853548
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete-2x.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete.png b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete.png
new file mode 100644
index 0000000000..fe537f0a70
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/delete.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/img/image-2x.png b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/image-2x.png
new file mode 100644
index 0000000000..b3843ce511
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/image-2x.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/img/image.png b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/image.png
new file mode 100644
index 0000000000..ee6f0755f5
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/img/image.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.js b/src/wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.js
new file mode 100644
index 0000000000..18e781179f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpeditimage/js/editimage.js
@@ -0,0 +1,613 @@
+
+var tinymce = null, tinyMCEPopup, tinyMCE, wpImage;
+
+tinyMCEPopup = {
+ init: function() {
+ var t = this, w, ti;
+
+ // Find window & API
+ w = t.getWin();
+ tinymce = w.tinymce;
+ tinyMCE = w.tinyMCE;
+ t.editor = tinymce.EditorManager.activeEditor;
+ t.params = t.editor.windowManager.params;
+ t.features = t.editor.windowManager.features;
+
+ // Setup local DOM
+ t.dom = t.editor.windowManager.createInstance('tinymce.dom.DOMUtils', document);
+ t.editor.windowManager.onOpen.dispatch(t.editor.windowManager, window);
+ },
+
+ getWin : function() {
+ return (!window.frameElement && window.dialogArguments) || opener || parent || top;
+ },
+
+ getParam : function(n, dv) {
+ return this.editor.getParam(n, dv);
+ },
+
+ close : function() {
+ var t = this;
+
+ // To avoid domain relaxing issue in Opera
+ function close() {
+ t.editor.windowManager.close(window);
+ tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup
+ };
+
+ if (tinymce.isOpera)
+ t.getWin().setTimeout(close, 0);
+ else
+ close();
+ },
+
+ execCommand : function(cmd, ui, val, a) {
+ a = a || {};
+ a.skip_focus = 1;
+
+ this.restoreSelection();
+ return this.editor.execCommand(cmd, ui, val, a);
+ },
+
+ storeSelection : function() {
+ this.editor.windowManager.bookmark = tinyMCEPopup.editor.selection.getBookmark(1);
+ },
+
+ restoreSelection : function() {
+ var t = tinyMCEPopup;
+
+ if ( tinymce.isIE )
+ t.editor.selection.moveToBookmark(t.editor.windowManager.bookmark);
+ }
+}
+tinyMCEPopup.init();
+
+wpImage = {
+ preInit : function() {
+ // import colors stylesheet from parent
+ var ed = tinyMCEPopup.editor, win = tinyMCEPopup.getWin(), styles = win.document.styleSheets, url, i;
+
+ for ( i = 0; i < styles.length; i++ ) {
+ url = styles.item(i).href;
+ if ( url && url.indexOf('colors') != -1 ) {
+ document.getElementsByTagName('head')[0].appendChild( ed.dom.create('link', {rel:'stylesheet', href: url}) );
+ break;
+ }
+ }
+ },
+
+ I : function(e) {
+ return document.getElementById(e);
+ },
+
+ current : '',
+ link : '',
+ link_rel : '',
+ target_value : '',
+ current_size_sel : 's100',
+ width : '',
+ height : '',
+ align : '',
+ img_alt : '',
+
+ setTabs : function(tab) {
+ var t = this;
+
+ if ( 'current' == tab.className ) return false;
+ t.I('div_advanced').style.display = ( 'tab_advanced' == tab.id ) ? 'block' : 'none';
+ t.I('div_basic').style.display = ( 'tab_basic' == tab.id ) ? 'block' : 'none';
+ t.I('tab_basic').className = t.I('tab_advanced').className = '';
+ tab.className = 'current';
+ return false;
+ },
+
+ img_seturl : function(u) {
+ var t = this, rel = t.I('link_rel').value;
+
+ if ( 'current' == u ) {
+ t.I('link_href').value = t.current;
+ t.I('link_rel').value = t.link_rel;
+ } else {
+ t.I('link_href').value = t.link;
+ if ( rel ) {
+ rel = rel.replace( /attachment|wp-att-[0-9]+/gi, '' );
+ t.I('link_rel').value = tinymce.trim(rel);
+ }
+ }
+ },
+
+ imgAlignCls : function(v) {
+ var t = this, cls = t.I('img_classes').value;
+
+ t.I('img_demo').className = t.align = v;
+
+ cls = cls.replace( /align[^ "']+/gi, '' );
+ cls += (' ' + v);
+ cls = cls.replace( /\s+/g, ' ' ).replace( /^\s/, '' );
+
+ if ( 'aligncenter' == v ) {
+ t.I('hspace').value = '';
+ t.updateStyle('hspace');
+ }
+
+ t.I('img_classes').value = cls;
+ },
+
+ showSize : function(el) {
+ var t = this, demo = t.I('img_demo'), w = t.width, h = t.height, id = el.id || 's100', size;
+
+ size = parseInt(id.substring(1)) / 200;
+ demo.width = Math.round(w * size);
+ demo.height = Math.round(h * size);
+
+ t.showSizeClear();
+ el.style.borderColor = '#A3A3A3';
+ el.style.backgroundColor = '#E5E5E5';
+ },
+
+ showSizeSet : function() {
+ var t = this, s130, s120, s110;
+
+ if ( (t.width * 1.3) > parseInt(t.preloadImg.width) ) {
+ s130 = t.I('s130'), s120 = t.I('s120'), s110 = t.I('s110');
+
+ s130.onclick = s120.onclick = s110.onclick = null;
+ s130.onmouseover = s120.onmouseover = s110.onmouseover = null;
+ s130.style.color = s120.style.color = s110.style.color = '#aaa';
+ }
+ },
+
+ showSizeRem : function() {
+ var t = this, demo = t.I('img_demo'), f = document.forms[0];
+
+ demo.width = Math.round(f.width.value * 0.5);
+ demo.height = Math.round(f.height.value * 0.5);
+ t.showSizeClear();
+ t.I(t.current_size_sel).style.borderColor = '#A3A3A3';
+ t.I(t.current_size_sel).style.backgroundColor = '#E5E5E5';
+
+ return false;
+ },
+
+ showSizeClear : function() {
+ var divs = this.I('img_size').getElementsByTagName('div'), i;
+
+ for ( i = 0; i < divs.length; i++ ) {
+ divs[i].style.borderColor = '#f1f1f1';
+ divs[i].style.backgroundColor = '#f1f1f1';
+ }
+ },
+
+ imgEditSize : function(el) {
+ var t = this, f = document.forms[0], W, H, w, h, id;
+
+ if ( ! t.preloadImg || ! t.preloadImg.width || ! t.preloadImg.height )
+ return;
+
+ W = parseInt(t.preloadImg.width), H = parseInt(t.preloadImg.height), w = t.width || W, h = t.height || H, id = el.id || 's100';
+
+ size = parseInt(id.substring(1)) / 100;
+
+ w = Math.round(w * size);
+ h = Math.round(h * size);
+
+ f.width.value = Math.min(W, w);
+ f.height.value = Math.min(H, h);
+
+ t.current_size_sel = id;
+ t.demoSetSize();
+ },
+
+ demoSetSize : function(img) {
+ var demo = this.I('img_demo'), f = document.forms[0];
+
+ demo.width = f.width.value ? Math.round(f.width.value * 0.5) : '';
+ demo.height = f.height.value ? Math.round(f.height.value * 0.5) : '';
+ },
+
+ demoSetStyle : function() {
+ var f = document.forms[0], demo = this.I('img_demo'), dom = tinyMCEPopup.editor.dom;
+
+ if (demo) {
+ dom.setAttrib(demo, 'style', f.img_style.value);
+ dom.setStyle(demo, 'width', '');
+ dom.setStyle(demo, 'height', '');
+ }
+ },
+
+ origSize : function() {
+ var t = this, f = document.forms[0], el = t.I('s100');
+
+ f.width.value = t.width = t.preloadImg.width;
+ f.height.value = t.height = t.preloadImg.height;
+ t.showSizeSet();
+ t.demoSetSize();
+ t.showSize(el);
+ },
+
+ init : function() {
+ var ed = tinyMCEPopup.editor, h;
+
+ h = document.body.innerHTML;
+ document.body.innerHTML = ed.translate(h);
+ window.setTimeout( function(){wpImage.setup();}, 500 );
+ },
+
+ setup : function() {
+ var t = this, c, el, link, fname, f = document.forms[0], ed = tinyMCEPopup.editor,
+ d = t.I('img_demo'), dom = tinyMCEPopup.dom, DL, DD, caption = '', dlc, pa;
+
+ document.dir = tinyMCEPopup.editor.getParam('directionality','');
+
+ if ( tinyMCEPopup.editor.getParam('wpeditimage_disable_captions', false) )
+ t.I('cap_field').style.display = 'none';
+
+ tinyMCEPopup.restoreSelection();
+ el = ed.selection.getNode();
+ if (el.nodeName != 'IMG')
+ return;
+
+ f.img_src.value = d.src = link = ed.dom.getAttrib(el, 'src');
+ ed.dom.setStyle(el, 'float', '');
+ t.getImageData();
+ c = ed.dom.getAttrib(el, 'class');
+
+ if ( DL = dom.getParent(el, 'dl') ) {
+ dlc = ed.dom.getAttrib(DL, 'class');
+ dlc = dlc.match(/align[^ "']+/i);
+ if ( dlc && ! dom.hasClass(el, dlc) ) {
+ c += ' '+dlc;
+ tinymce.trim(c);
+ }
+
+ DD = ed.dom.select('dd.wp-caption-dd', DL);
+ if ( DD && DD[0] )
+ caption = ed.serializer.serialize(DD[0]).replace(/^<p>/, '').replace(/<\/p>$/, '');
+ }
+
+ f.img_cap_text.value = caption;
+ f.img_title.value = ed.dom.getAttrib(el, 'title');
+ f.img_alt.value = ed.dom.getAttrib(el, 'alt');
+ f.border.value = ed.dom.getAttrib(el, 'border');
+ f.vspace.value = ed.dom.getAttrib(el, 'vspace');
+ f.hspace.value = ed.dom.getAttrib(el, 'hspace');
+ f.align.value = ed.dom.getAttrib(el, 'align');
+ f.width.value = t.width = ed.dom.getAttrib(el, 'width');
+ f.height.value = t.height = ed.dom.getAttrib(el, 'height');
+ f.img_classes.value = c;
+ f.img_style.value = ed.dom.getAttrib(el, 'style');
+
+ // Move attribs to styles
+ if ( dom.getAttrib(el, 'hspace') )
+ t.updateStyle('hspace');
+
+ if ( dom.getAttrib(el, 'border') )
+ t.updateStyle('border');
+
+ if ( dom.getAttrib(el, 'vspace') )
+ t.updateStyle('vspace');
+
+ if ( pa = ed.dom.getParent(el, 'A') ) {
+ f.link_href.value = t.current = ed.dom.getAttrib(pa, 'href');
+ f.link_title.value = ed.dom.getAttrib(pa, 'title');
+ f.link_rel.value = t.link_rel = ed.dom.getAttrib(pa, 'rel');
+ f.link_style.value = ed.dom.getAttrib(pa, 'style');
+ t.target_value = ed.dom.getAttrib(pa, 'target');
+ f.link_classes.value = ed.dom.getAttrib(pa, 'class');
+ }
+
+ f.link_target.checked = ( t.target_value && t.target_value == '_blank' ) ? 'checked' : '';
+
+ fname = link.substring( link.lastIndexOf('/') );
+ fname = fname.replace(/-[0-9]{2,4}x[0-9]{2,4}/, '' );
+ t.link = link.substring( 0, link.lastIndexOf('/') ) + fname;
+
+ if ( c.indexOf('alignleft') != -1 ) {
+ t.I('alignleft').checked = "checked";
+ d.className = t.align = "alignleft";
+ } else if ( c.indexOf('aligncenter') != -1 ) {
+ t.I('aligncenter').checked = "checked";
+ d.className = t.align = "aligncenter";
+ } else if ( c.indexOf('alignright') != -1 ) {
+ t.I('alignright').checked = "checked";
+ d.className = t.align = "alignright";
+ } else if ( c.indexOf('alignnone') != -1 ) {
+ t.I('alignnone').checked = "checked";
+ d.className = t.align = "alignnone";
+ }
+
+ if ( t.width && t.preloadImg.width )
+ t.showSizeSet();
+
+ document.body.style.display = '';
+ },
+
+ remove : function() {
+ var ed = tinyMCEPopup.editor, p, el;
+
+ tinyMCEPopup.restoreSelection();
+ el = ed.selection.getNode();
+ if (el.nodeName != 'IMG') return;
+
+ if ( (p = ed.dom.getParent(el, 'div')) && ed.dom.hasClass(p, 'mceTemp') )
+ ed.dom.remove(p);
+ else if ( (p = ed.dom.getParent(el, 'A')) && p.childNodes.length == 1 )
+ ed.dom.remove(p);
+ else ed.dom.remove(el);
+
+ ed.execCommand('mceRepaint');
+ tinyMCEPopup.close();
+ return;
+ },
+
+ update : function() {
+ var t = this, f = document.forms[0], ed = tinyMCEPopup.editor, el, b, fixSafari = null,
+ DL, P, A, DIV, do_caption = null, img_class = f.img_classes.value, html,
+ id, cap_id = '', cap, DT, DD, cap_width, div_cls, lnk = '', pa, aa, caption;
+
+ tinyMCEPopup.restoreSelection();
+ el = ed.selection.getNode();
+
+ if (el.nodeName != 'IMG') return;
+ if (f.img_src.value === '') {
+ t.remove();
+ return;
+ }
+
+ if ( f.img_cap_text.value != '' && f.width.value != '' ) {
+ do_caption = 1;
+ img_class = img_class.replace( /align[^ "']+\s?/gi, '' );
+ }
+
+ A = ed.dom.getParent(el, 'a');
+ P = ed.dom.getParent(el, 'p');
+ DL = ed.dom.getParent(el, 'dl');
+ DIV = ed.dom.getParent(el, 'div');
+
+ tinyMCEPopup.execCommand("mceBeginUndoLevel");
+
+ if ( f.width.value != el.width || f.height.value != el.height )
+ img_class = img_class.replace(/size-[^ "']+/, '');
+
+ ed.dom.setAttribs(el, {
+ src : f.img_src.value,
+ title : f.img_title.value,
+ alt : f.img_alt.value,
+ width : f.width.value,
+ height : f.height.value,
+ style : f.img_style.value,
+ 'class' : img_class
+ });
+
+ if ( f.link_href.value ) {
+ // Create new anchor elements
+ if ( A == null ) {
+ if ( ! f.link_href.value.match(/https?:\/\//i) )
+ f.link_href.value = tinyMCEPopup.editor.documentBaseURI.toAbsolute(f.link_href.value);
+
+ ed.getDoc().execCommand("unlink", false, null);
+ tinyMCEPopup.execCommand("mceInsertLink", false, "#mce_temp_url#", {skip_undo : 1});
+
+ tinymce.each(ed.dom.select("a"), function(n) {
+ if ( ed.dom.getAttrib(n, 'href') == '#mce_temp_url#' ) {
+
+ ed.dom.setAttribs(n, {
+ href : f.link_href.value,
+ title : f.link_title.value,
+ rel : f.link_rel.value,
+ target : (f.link_target.checked == true) ? '_blank' : '',
+ 'class' : f.link_classes.value,
+ style : f.link_style.value
+ });
+ }
+ });
+ } else {
+ ed.dom.setAttribs(A, {
+ href : f.link_href.value,
+ title : f.link_title.value,
+ rel : f.link_rel.value,
+ target : (f.link_target.checked == true) ? '_blank' : '',
+ 'class' : f.link_classes.value,
+ style : f.link_style.value
+ });
+ }
+ }
+
+ if ( do_caption ) {
+ cap_width = 10 + parseInt(f.width.value);
+ div_cls = (t.align == 'aligncenter') ? 'mceTemp mceIEcenter' : 'mceTemp';
+ caption = f.img_cap_text.value;
+
+ caption = caption.replace(/\r\n|\r/g, '\n').replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
+ return a.replace(/[\r\n\t]+/, ' ');
+ });
+
+ caption = caption.replace(/\s*\n\s*/g, '<br />');
+
+ if ( DL ) {
+ ed.dom.setAttribs(DL, {
+ 'class' : 'wp-caption '+t.align,
+ style : 'width: '+cap_width+'px;'
+ });
+
+ if ( DIV )
+ ed.dom.setAttrib(DIV, 'class', div_cls);
+
+ if ( (DT = ed.dom.getParent(el, 'dt')) && (DD = DT.nextSibling) && ed.dom.hasClass(DD, 'wp-caption-dd') )
+ ed.dom.setHTML(DD, caption);
+
+ } else {
+ if ( (id = f.img_classes.value.match( /wp-image-([0-9]{1,6})/ )) && id[1] )
+ cap_id = 'attachment_'+id[1];
+
+ if ( f.link_href.value && (lnk = ed.dom.getParent(el, 'a')) ) {
+ if ( lnk.childNodes.length == 1 ) {
+ html = ed.dom.getOuterHTML(lnk);
+ } else {
+ html = ed.dom.getOuterHTML(lnk);
+ html = html.match(/<a [^>]+>/i);
+ html = html+ed.dom.getOuterHTML(el)+'</a>';
+ }
+ } else {
+ html = ed.dom.getOuterHTML(el);
+ }
+
+ html = '<dl id="'+cap_id+'" class="wp-caption '+t.align+'" style="width: '+cap_width+
+ 'px"><dt class="wp-caption-dt">'+html+'</dt><dd class="wp-caption-dd">'+caption+'</dd></dl>';
+
+ cap = ed.dom.create('div', {'class': div_cls}, html);
+
+ if ( P ) {
+ P.parentNode.insertBefore(cap, P);
+ if ( P.childNodes.length == 1 )
+ ed.dom.remove(P);
+ else if ( lnk && lnk.childNodes.length == 1 )
+ ed.dom.remove(lnk);
+ else ed.dom.remove(el);
+ } else if ( pa = ed.dom.getParent(el, 'TD,TH,LI') ) {
+ pa.appendChild(cap);
+ if ( lnk && lnk.childNodes.length == 1 )
+ ed.dom.remove(lnk);
+ else ed.dom.remove(el);
+ }
+ }
+
+ } else {
+ if ( DL && DIV ) {
+ if ( f.link_href.value && (aa = ed.dom.getParent(el, 'a')) ) html = ed.dom.getOuterHTML(aa);
+ else html = ed.dom.getOuterHTML(el);
+
+ P = ed.dom.create('p', {}, html);
+ DIV.parentNode.insertBefore(P, DIV);
+ ed.dom.remove(DIV);
+ }
+ }
+
+ if ( f.img_classes.value.indexOf('aligncenter') != -1 ) {
+ if ( P && ( ! P.style || P.style.textAlign != 'center' ) )
+ ed.dom.setStyle(P, 'textAlign', 'center');
+ } else {
+ if ( P && P.style && P.style.textAlign == 'center' )
+ ed.dom.setStyle(P, 'textAlign', '');
+ }
+
+ if ( ! f.link_href.value && A ) {
+ b = ed.selection.getBookmark();
+ ed.dom.remove(A, 1);
+ ed.selection.moveToBookmark(b);
+ }
+
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ ed.execCommand('mceRepaint');
+ tinyMCEPopup.close();
+ },
+
+ updateStyle : function(ty) {
+ var dom = tinyMCEPopup.dom, v, f = document.forms[0], img = dom.create('img', {style : f.img_style.value});
+
+ if (tinyMCEPopup.editor.settings.inline_styles) {
+ // Handle align
+ if (ty == 'align') {
+ dom.setStyle(img, 'float', '');
+ dom.setStyle(img, 'vertical-align', '');
+
+ v = f.align.value;
+ if (v) {
+ if (v == 'left' || v == 'right')
+ dom.setStyle(img, 'float', v);
+ else
+ img.style.verticalAlign = v;
+ }
+ }
+
+ // Handle border
+ if (ty == 'border') {
+ dom.setStyle(img, 'border', '');
+
+ v = f.border.value;
+ if (v || v == '0') {
+ if (v == '0')
+ img.style.border = '0';
+ else
+ img.style.border = v + 'px solid black';
+ }
+ }
+
+ // Handle hspace
+ if (ty == 'hspace') {
+ dom.setStyle(img, 'marginLeft', '');
+ dom.setStyle(img, 'marginRight', '');
+
+ v = f.hspace.value;
+ if (v) {
+ img.style.marginLeft = v + 'px';
+ img.style.marginRight = v + 'px';
+ }
+ }
+
+ // Handle vspace
+ if (ty == 'vspace') {
+ dom.setStyle(img, 'marginTop', '');
+ dom.setStyle(img, 'marginBottom', '');
+
+ v = f.vspace.value;
+ if (v) {
+ img.style.marginTop = v + 'px';
+ img.style.marginBottom = v + 'px';
+ }
+ }
+
+ // Merge
+ f.img_style.value = dom.serializeStyle(dom.parseStyle(img.style.cssText));
+ this.demoSetStyle();
+ }
+ },
+
+ checkVal : function(f) {
+
+ if ( f.value == '' ) {
+ // if ( f.id == 'width' ) f.value = this.width || this.preloadImg.width;
+ // if ( f.id == 'height' ) f.value = this.height || this.preloadImg.height;
+ if ( f.id == 'img_src' ) f.value = this.I('img_demo').src || this.preloadImg.src;
+ }
+ },
+
+ resetImageData : function() {
+ var f = document.forms[0];
+
+ f.width.value = f.height.value = '';
+ },
+
+ updateImageData : function() {
+ var f = document.forms[0], t = wpImage, w = f.width.value, h = f.height.value;
+
+ if ( !w && h )
+ w = f.width.value = t.width = Math.round( t.preloadImg.width / (t.preloadImg.height / h) );
+ else if ( w && !h )
+ h = f.height.value = t.height = Math.round( t.preloadImg.height / (t.preloadImg.width / w) );
+
+ if ( !w )
+ f.width.value = t.width = t.preloadImg.width;
+
+ if ( !h )
+ f.height.value = t.height = t.preloadImg.height;
+
+ t.showSizeSet();
+ t.demoSetSize();
+ if ( f.img_style.value )
+ t.demoSetStyle();
+ },
+
+ getImageData : function() {
+ var t = wpImage, f = document.forms[0];
+
+ t.preloadImg = new Image();
+ t.preloadImg.onload = t.updateImageData;
+ t.preloadImg.onerror = t.resetImageData;
+ t.preloadImg.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(f.img_src.value);
+ }
+};
+
+window.onload = function(){wpImage.init();}
+wpImage.preInit();
+
diff --git a/src/wp-includes/js/tinymce/plugins/wpfullscreen/css/wp-fullscreen.css b/src/wp-includes/js/tinymce/plugins/wpfullscreen/css/wp-fullscreen.css
new file mode 100644
index 0000000000..686fedf29c
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpfullscreen/css/wp-fullscreen.css
@@ -0,0 +1,13 @@
+/*
+Distraction Free Writing mode TinyMCE Styles
+*/
+
+html,
+body {
+ background: transparent;
+ width: auto !important;
+ max-width: none !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ min-height: 0 !important;
+}
diff --git a/src/wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin_src.js
new file mode 100644
index 0000000000..4618fcfe67
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpfullscreen/editor_plugin_src.js
@@ -0,0 +1,189 @@
+/**
+ * WP Fullscreen TinyMCE plugin
+ *
+ * Contains code from Moxiecode Systems AB released under LGPL http://tinymce.moxiecode.com/license
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.wpFullscreenPlugin', {
+ resize_timeout: false,
+
+ init : function(ed, url) {
+ var t = this, oldHeight = 0, s = {}, DOM = tinymce.DOM;
+
+ // Register commands
+ ed.addCommand('wpFullScreenClose', function() {
+ // this removes the editor, content has to be saved first with tinyMCE.execCommand('wpFullScreenSave');
+ if ( ed.getParam('wp_fullscreen_is_enabled') ) {
+ DOM.win.setTimeout(function() {
+ tinyMCE.remove(ed);
+ DOM.remove('wp_mce_fullscreen_parent');
+ tinyMCE.settings = tinyMCE.oldSettings; // Restore old settings
+ }, 10);
+ }
+ });
+
+ ed.addCommand('wpFullScreenSave', function() {
+ var ed = tinyMCE.get('wp_mce_fullscreen'), edd;
+
+ ed.focus();
+ edd = tinyMCE.get( ed.getParam('wp_fullscreen_editor_id') );
+
+ edd.setContent( ed.getContent({format : 'raw'}), {format : 'raw'} );
+ });
+
+ ed.addCommand('wpFullScreenInit', function() {
+ var d, b, fsed;
+
+ ed = tinyMCE.activeEditor;
+ d = ed.getDoc();
+ b = d.body;
+
+ tinyMCE.oldSettings = tinyMCE.settings; // Store old settings
+
+ tinymce.each(ed.settings, function(v, n) {
+ s[n] = v;
+ });
+
+ s.id = 'wp_mce_fullscreen';
+ s.wp_fullscreen_is_enabled = true;
+ s.wp_fullscreen_editor_id = ed.id;
+ s.theme_advanced_resizing = false;
+ s.theme_advanced_statusbar_location = 'none';
+ s.content_css = s.content_css ? s.content_css + ',' + s.wp_fullscreen_content_css : s.wp_fullscreen_content_css;
+ s.height = tinymce.isIE ? b.scrollHeight : b.offsetHeight;
+
+ tinymce.each(ed.getParam('wp_fullscreen_settings'), function(v, k) {
+ s[k] = v;
+ });
+
+ fsed = new tinymce.Editor('wp_mce_fullscreen', s);
+ fsed.onInit.add(function(edd) {
+ var DOM = tinymce.DOM, buttons = DOM.select('a.mceButton', DOM.get('wp-fullscreen-buttons'));
+
+ if ( !ed.isHidden() )
+ edd.setContent( ed.getContent() );
+ else
+ edd.setContent( switchEditors.wpautop( edd.getElement().value ) );
+
+ setTimeout(function(){ // add last
+ edd.onNodeChange.add(function(ed, cm, e){
+ tinymce.each(buttons, function(c) {
+ var btn, cls;
+
+ if ( btn = DOM.get( 'wp_mce_fullscreen_' + c.id.substr(6) ) ) {
+ cls = btn.className;
+
+ if ( cls )
+ c.className = cls;
+ }
+ });
+ });
+ }, 1000);
+
+ edd.dom.addClass(edd.getBody(), 'wp-fullscreen-editor');
+ edd.focus();
+ });
+
+ fsed.render();
+
+ if ( 'undefined' != fullscreen ) {
+ fsed.dom.bind( fsed.dom.doc, 'mousemove', function(e){
+ fullscreen.bounder( 'showToolbar', 'hideToolbar', 2000, e );
+ });
+ }
+ });
+
+ ed.addCommand('wpFullScreen', function() {
+ if ( typeof(fullscreen) == 'undefined' )
+ return;
+
+ if ( 'wp_mce_fullscreen' == ed.id )
+ fullscreen.off();
+ else
+ fullscreen.on();
+ });
+
+ // Register buttons
+ ed.addButton('wp_fullscreen', {
+ title : 'wordpress.wp_fullscreen_desc',
+ cmd : 'wpFullScreen'
+ });
+
+ // END fullscreen
+//----------------------------------------------------------------
+ // START autoresize
+
+ if ( ed.getParam('fullscreen_is_enabled') || !ed.getParam('wp_fullscreen_is_enabled') )
+ return;
+
+ /**
+ * This method gets executed each time the editor needs to resize.
+ */
+ function resize(editor, e) {
+ var DOM = tinymce.DOM, body = ed.getBody(), ifr = DOM.get(ed.id + '_ifr'), height, y = ed.dom.win.scrollY;
+
+ if ( t.resize_timeout )
+ return;
+
+ // sometimes several events are fired few ms apart, trottle down resizing a little
+ t.resize_timeout = true;
+ setTimeout(function(){
+ t.resize_timeout = false;
+ }, 500);
+
+ height = body.scrollHeight > 300 ? body.scrollHeight : 300;
+
+ if ( height != ifr.scrollHeight ) {
+ DOM.setStyle(ifr, 'height', height + 'px');
+ ed.getWin().scrollTo(0, 0); // iframe window object, make sure there's no scrolling
+ }
+
+ // WebKit scrolls to top on paste...
+ if ( e && e.type == 'paste' && tinymce.isWebKit ) {
+ setTimeout(function(){
+ ed.dom.win.scrollTo(0, y);
+ }, 40);
+ }
+ };
+
+ // Add appropriate listeners for resizing content area
+ ed.onInit.add(function(ed, l) {
+ ed.onChange.add(resize);
+ ed.onSetContent.add(resize);
+ ed.onPaste.add(resize);
+ ed.onKeyUp.add(resize);
+ ed.onPostRender.add(resize);
+
+ ed.getBody().style.overflowY = "hidden";
+ });
+
+ if ( ed.getParam('autoresize_on_init', true) ) {
+ ed.onLoadContent.add(function(ed, l) {
+ // Because the content area resizes when its content CSS loads,
+ // and we can't easily add a listener to its onload event,
+ // we'll just trigger a resize after a short loading period
+ setTimeout(function() {
+ resize();
+ }, 1200);
+ });
+ }
+
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
+ ed.addCommand('wpAutoResize', resize);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'WP Fullscreen',
+ author : 'WordPress',
+ authorurl : 'http://wordpress.org',
+ infourl : '',
+ version : '1.0'
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('wpfullscreen', tinymce.plugins.wpFullscreenPlugin);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wpgallery/editor_plugin_src.js
new file mode 100644
index 0000000000..986304dc62
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpgallery/editor_plugin_src.js
@@ -0,0 +1,156 @@
+
+(function() {
+ tinymce.create('tinymce.plugins.wpGallery', {
+
+ init : function(ed, url) {
+ var t = this;
+
+ t.url = url;
+ t.editor = ed;
+ t._createButtons();
+
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('...');
+ ed.addCommand('WP_Gallery', function() {
+ if ( tinymce.isIE )
+ ed.selection.moveToBookmark( ed.wpGalleryBookmark );
+
+ var el = ed.selection.getNode(),
+ gallery = wp.media.gallery,
+ frame;
+
+ // Check if the `wp.media.gallery` API exists.
+ if ( typeof wp === 'undefined' || ! wp.media || ! wp.media.gallery )
+ return;
+
+ // Make sure we've selected a gallery node.
+ if ( el.nodeName != 'IMG' || ed.dom.getAttrib(el, 'class').indexOf('wp-gallery') == -1 )
+ return;
+
+ frame = gallery.edit( '[' + ed.dom.getAttrib( el, 'title' ) + ']' );
+
+ frame.state('gallery-edit').on( 'update', function( selection ) {
+ var shortcode = gallery.shortcode( selection ).string().slice( 1, -1 );
+ ed.dom.setAttrib( el, 'title', shortcode );
+ });
+ });
+
+ ed.onInit.add(function(ed) {
+ // iOS6 doesn't show the buttons properly on click, show them on 'touchstart'
+ if ( 'ontouchstart' in window ) {
+ ed.dom.events.add(ed.getBody(), 'touchstart', function(e){
+ var target = e.target;
+
+ if ( target.nodeName == 'IMG' && ed.dom.hasClass(target, 'wp-gallery') ) {
+ ed.selection.select(target);
+ ed.dom.events.cancel(e);
+ ed.plugins.wordpress._hideButtons();
+ ed.plugins.wordpress._showButtons(target, 'wp_gallerybtns');
+ }
+ });
+ }
+ });
+
+ ed.onMouseDown.add(function(ed, e) {
+ if ( e.target.nodeName == 'IMG' && ed.dom.hasClass(e.target, 'wp-gallery') ) {
+ ed.plugins.wordpress._hideButtons();
+ ed.plugins.wordpress._showButtons(e.target, 'wp_gallerybtns');
+ }
+ });
+
+ ed.onBeforeSetContent.add(function(ed, o) {
+ o.content = t._do_gallery(o.content);
+ });
+
+ ed.onPostProcess.add(function(ed, o) {
+ if (o.get)
+ o.content = t._get_gallery(o.content);
+ });
+ },
+
+ _do_gallery : function(co) {
+ return co.replace(/\[gallery([^\]]*)\]/g, function(a,b){
+ return '<img src="'+tinymce.baseURL+'/plugins/wpgallery/img/t.gif" class="wp-gallery mceItem" title="gallery'+tinymce.DOM.encode(b)+'" />';
+ });
+ },
+
+ _get_gallery : function(co) {
+
+ function getAttr(s, n) {
+ n = new RegExp(n + '=\"([^\"]+)\"', 'g').exec(s);
+ return n ? tinymce.DOM.decode(n[1]) : '';
+ };
+
+ return co.replace(/(?:<p[^>]*>)*(<img[^>]+>)(?:<\/p>)*/g, function(a,im) {
+ var cls = getAttr(im, 'class');
+
+ if ( cls.indexOf('wp-gallery') != -1 )
+ return '<p>['+tinymce.trim(getAttr(im, 'title'))+']</p>';
+
+ return a;
+ });
+ },
+
+ _createButtons : function() {
+ var t = this, ed = tinymce.activeEditor, DOM = tinymce.DOM, editButton, dellButton, isRetina;
+
+ if ( DOM.get('wp_gallerybtns') )
+ return;
+
+ isRetina = ( window.devicePixelRatio && window.devicePixelRatio > 1 ) || // WebKit, Opera
+ ( window.matchMedia && window.matchMedia('(min-resolution:130dpi)').matches ); // Firefox, IE10, Opera
+
+ DOM.add(document.body, 'div', {
+ id : 'wp_gallerybtns',
+ style : 'display:none;'
+ });
+
+ editButton = DOM.add('wp_gallerybtns', 'img', {
+ src : isRetina ? t.url+'/img/edit-2x.png' : t.url+'/img/edit.png',
+ id : 'wp_editgallery',
+ width : '24',
+ height : '24',
+ title : ed.getLang('wordpress.editgallery')
+ });
+
+ tinymce.dom.Event.add(editButton, 'mousedown', function(e) {
+ var ed = tinymce.activeEditor;
+ ed.wpGalleryBookmark = ed.selection.getBookmark('simple');
+ ed.execCommand("WP_Gallery");
+ ed.plugins.wordpress._hideButtons();
+ });
+
+ dellButton = DOM.add('wp_gallerybtns', 'img', {
+ src : isRetina ? t.url+'/img/delete-2x.png' : t.url+'/img/delete.png',
+ id : 'wp_delgallery',
+ width : '24',
+ height : '24',
+ title : ed.getLang('wordpress.delgallery')
+ });
+
+ tinymce.dom.Event.add(dellButton, 'mousedown', function(e) {
+ var ed = tinymce.activeEditor, el = ed.selection.getNode();
+
+ if ( el.nodeName == 'IMG' && ed.dom.hasClass(el, 'wp-gallery') ) {
+ ed.dom.remove(el);
+
+ ed.execCommand('mceRepaint');
+ ed.dom.events.cancel(e);
+ }
+
+ ed.plugins.wordpress._hideButtons();
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Gallery Settings',
+ author : 'WordPress',
+ authorurl : 'http://wordpress.org',
+ infourl : '',
+ version : "1.0"
+ };
+ }
+ });
+
+ tinymce.PluginManager.add('wpgallery', tinymce.plugins.wpGallery);
+})();
diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/img/delete-2x.png b/src/wp-includes/js/tinymce/plugins/wpgallery/img/delete-2x.png
new file mode 100644
index 0000000000..859d853548
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpgallery/img/delete-2x.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/img/delete.png b/src/wp-includes/js/tinymce/plugins/wpgallery/img/delete.png
new file mode 100644
index 0000000000..fe537f0a70
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpgallery/img/delete.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/img/edit-2x.png b/src/wp-includes/js/tinymce/plugins/wpgallery/img/edit-2x.png
new file mode 100644
index 0000000000..b43dc234a7
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpgallery/img/edit-2x.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/img/edit.png b/src/wp-includes/js/tinymce/plugins/wpgallery/img/edit.png
new file mode 100644
index 0000000000..793193bf92
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpgallery/img/edit.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wpgallery/img/t.gif b/src/wp-includes/js/tinymce/plugins/wpgallery/img/t.gif
new file mode 100644
index 0000000000..388486517f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpgallery/img/t.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/plugins/wplink/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wplink/editor_plugin_src.js
new file mode 100644
index 0000000000..f36e86369b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wplink/editor_plugin_src.js
@@ -0,0 +1,59 @@
+(function() {
+ tinymce.create('tinymce.plugins.wpLink', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished its initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ var disabled = true;
+
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
+ ed.addCommand('WP_Link', function() {
+ if ( disabled )
+ return;
+ ed.windowManager.open({
+ id : 'wp-link',
+ width : 480,
+ height : "auto",
+ wpDialog : true,
+ title : ed.getLang('advlink.link_desc')
+ }, {
+ plugin_url : url // Plugin absolute URL
+ });
+ });
+
+ // Register example button
+ ed.addButton('link', {
+ title : 'advanced.link_desc',
+ cmd : 'WP_Link'
+ });
+
+ ed.onNodeChange.add(function(ed, cm, n, co) {
+ disabled = co && n.nodeName != 'A';
+ });
+ },
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'WordPress Link Dialog',
+ author : 'WordPress',
+ authorurl : 'http://wordpress.org',
+ infourl : '',
+ version : "1.0"
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('wplink', tinymce.plugins.wpLink);
+})();
+
diff --git a/src/wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js b/src/wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js
new file mode 100644
index 0000000000..f7044c461a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/plugins/wpview/editor_plugin_src.js
@@ -0,0 +1,188 @@
+/**
+ * WordPress View plugin.
+ */
+
+(function() {
+ var VK = tinymce.VK,
+ TreeWalker = tinymce.dom.TreeWalker,
+ selected;
+
+ tinymce.create('tinymce.plugins.wpView', {
+ init : function( editor, url ) {
+ var wpView = this;
+
+ // Check if the `wp.mce` API exists.
+ if ( typeof wp === 'undefined' || ! wp.mce )
+ return;
+
+ editor.onPreInit.add( function( editor ) {
+ // Add elements so we can set `contenteditable` to false.
+ editor.schema.addValidElements('div[*],span[*]');
+ });
+
+ // When the editor's content changes, scan the new content for
+ // matching view patterns, and transform the matches into
+ // view wrappers. Since the editor's DOM is outdated at this point,
+ // we'll wait to render the views.
+ editor.onBeforeSetContent.add( function( editor, o ) {
+ if ( ! o.content )
+ return;
+
+ o.content = wp.mce.view.toViews( o.content );
+ });
+
+ // When the editor's content has been updated and the DOM has been
+ // processed, render the views in the document.
+ editor.onSetContent.add( function( editor, o ) {
+ wp.mce.view.render( editor.getDoc() );
+ });
+
+ editor.onInit.add( function( editor ) {
+
+ // When a view is selected, ensure content that is being pasted
+ // or inserted is added to a text node (instead of the view).
+ editor.selection.onBeforeSetContent.add( function( selection, o ) {
+ var view = wpView.getParentView( selection.getNode() ),
+ walker, target;
+
+ // If the selection is not within a view, bail.
+ if ( ! view )
+ return;
+
+ // If there are no additional nodes or the next node is a
+ // view, create a text node after the current view.
+ if ( ! view.nextSibling || wpView.isView( view.nextSibling ) ) {
+ target = editor.getDoc().createTextNode('');
+ editor.dom.insertAfter( target, view );
+
+ // Otherwise, find the next text node.
+ } else {
+ walker = new TreeWalker( view.nextSibling, view.nextSibling );
+ target = walker.next();
+ }
+
+ // Select the `target` text node.
+ selection.select( target );
+ selection.collapse( true );
+ });
+
+ // When the selection's content changes, scan any new content
+ // for matching views and immediately render them.
+ //
+ // Runs on paste and on inserting nodes/html.
+ editor.selection.onSetContent.add( function( selection, o ) {
+ if ( ! o.context )
+ return;
+
+ var node = selection.getNode();
+
+ if ( ! node.innerHTML )
+ return;
+
+ node.innerHTML = wp.mce.view.toViews( node.innerHTML );
+ wp.mce.view.render( node );
+ });
+ });
+
+ // When the editor's contents are being accessed as a string,
+ // transform any views back to their text representations.
+ editor.onPostProcess.add( function( editor, o ) {
+ if ( ( ! o.get && ! o.save ) || ! o.content )
+ return;
+
+ o.content = wp.mce.view.toText( o.content );
+ });
+
+ // Triggers when the selection is changed.
+ // Add the event handler to the top of the stack.
+ editor.onNodeChange.addToTop( function( editor, controlManager, node, collapsed, o ) {
+ var view = wpView.getParentView( node );
+
+ // Update the selected view.
+ if ( view ) {
+ wpView.select( view );
+
+ // Prevent the selection from propagating to other plugins.
+ return false;
+
+ // If we've clicked off of the selected view, deselect it.
+ } else {
+ wpView.deselect();
+ }
+ });
+
+ editor.onKeyDown.addToTop( function( editor, event ) {
+ var keyCode = event.keyCode,
+ view, instance;
+
+ // If a view isn't selected, let the event go on its merry way.
+ if ( ! selected )
+ return;
+
+ // If the caret is not within the selected view, deselect the
+ // view and bail.
+ view = wpView.getParentView( editor.selection.getNode() );
+ if ( view !== selected ) {
+ wpView.deselect();
+ return;
+ }
+
+ // If delete or backspace is pressed, delete the view.
+ if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) {
+ if ( (instance = wp.mce.view.instance( selected )) ) {
+ instance.remove();
+ wpView.deselect();
+ }
+ }
+
+ // Let keypresses that involve the command or control keys through.
+ // Also, let any of the F# keys through.
+ if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) )
+ return;
+
+ event.preventDefault();
+ });
+ },
+
+ getParentView : function( node ) {
+ while ( node ) {
+ if ( this.isView( node ) )
+ return node;
+
+ node = node.parentNode;
+ }
+ },
+
+ isView : function( node ) {
+ return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className );
+ },
+
+ select : function( view ) {
+ if ( view === selected )
+ return;
+
+ this.deselect();
+ selected = view;
+ wp.mce.view.select( selected );
+ },
+
+ deselect : function() {
+ if ( selected )
+ wp.mce.view.deselect( selected );
+ selected = null;
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'WordPress Views',
+ author : 'WordPress',
+ authorurl : 'http://wordpress.org',
+ infourl : 'http://wordpress.org',
+ version : '1.0'
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView );
+})(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/themes/advanced/about.htm b/src/wp-includes/js/tinymce/themes/advanced/about.htm
new file mode 100644
index 0000000000..c7ff0a4c4c
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/about.htm
@@ -0,0 +1,52 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.about_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/about.js?ver=358-20121205"></script>
+</head>
+<body id="about" style="display: none">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advanced_dlg.about_general}</a></span></li>
+ <li id="help_tab" style="display:none" aria-hidden="true" aria-controls="help_panel"><span><a href="javascript:mcTabs.displayTab('help_tab','help_panel');" onmousedown="return false;">{#advanced_dlg.about_help}</a></span></li>
+ <li id="plugins_tab" aria-controls="plugins_panel"><span><a href="javascript:mcTabs.displayTab('plugins_tab','plugins_panel');" onmousedown="return false;">{#advanced_dlg.about_plugins}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <h3>{#advanced_dlg.about_title}</h3>
+ <p>Version: <span id="version"></span> (<span id="date"></span>)</p>
+ <p>TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under <a href="../../license.txt" target="_blank">LGPL</a>
+ by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.</p>
+ <p>Copyright &copy; 2003-2008, <a href="http://www.moxiecode.com" target="_blank">Moxiecode Systems AB</a>, All rights reserved.</p>
+ <p>For more information about this software visit the <a href="http://tinymce.moxiecode.com" target="_blank">TinyMCE website</a>.</p>
+
+ <div id="buttoncontainer">
+ <a href="http://www.moxiecode.com" target="_blank"><img src="http://tinymce.moxiecode.com/images/gotmoxie.png" alt="Got Moxie?" border="0" /></a>
+ </div>
+ </div>
+
+ <div id="plugins_panel" class="panel">
+ <div id="pluginscontainer">
+ <h3>{#advanced_dlg.about_loaded}</h3>
+
+ <div id="plugintablecontainer">
+ </div>
+
+ <p>&nbsp;</p>
+ </div>
+ </div>
+
+ <div id="help_panel" class="panel noscroll" style="overflow: visible;">
+ <div id="iframecontainer"></div>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="button" id="cancel" name="cancel" value="{#close}" onclick="tinyMCEPopup.close();" />
+ </div>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/anchor.htm b/src/wp-includes/js/tinymce/themes/advanced/anchor.htm
new file mode 100644
index 0000000000..6571a72d74
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/anchor.htm
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.anchor_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/anchor.js?ver=358-20121205"></script>
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<form onsubmit="AnchorDialog.update();return false;" action="#">
+ <table border="0" cellpadding="4" cellspacing="0" role="presentation">
+ <tr>
+ <td colspan="2" class="title" id="app_title">{#advanced_dlg.anchor_title}</td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="anchorName">{#advanced_dlg.anchor_name}:</label></td>
+ <td><input name="anchorName" type="text" class="mceFocus" id="anchorName" value="" style="width: 200px" aria-required="true" /></td>
+ </tr>
+ </table>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/charmap.htm b/src/wp-includes/js/tinymce/themes/advanced/charmap.htm
new file mode 100644
index 0000000000..41bfaf178b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/charmap.htm
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.charmap_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/charmap.js?ver=358-20121205"></script>
+</head>
+<body id="charmap" style="display:none" role="application">
+<table align="center" border="0" cellspacing="0" cellpadding="2" role="presentation">
+ <tr>
+ <td colspan="2" class="title" ><label for="charmapView" id="charmap_label">{#advanced_dlg.charmap_title}</label></td>
+ </tr>
+ <tr>
+ <td id="charmapView" rowspan="2" align="left" valign="top">
+ <!-- Chars will be rendered here -->
+ </td>
+ <td width="100" align="center" valign="top">
+ <table border="0" cellpadding="0" cellspacing="0" width="100" style="height:100px" role="presentation">
+ <tr>
+ <td id="codeV">&nbsp;</td>
+ </tr>
+ <tr>
+ <td id="codeN">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="bottom" style="padding-bottom: 3px;">
+ <table width="100" align="center" border="0" cellpadding="2" cellspacing="0" role="presentation">
+ <tr>
+ <td align="center" style="border-left: 1px solid #666699; border-top: 1px solid #666699; border-right: 1px solid #666699;"><label for="codeA">HTML-Code</label></td>
+ </tr>
+ <tr>
+ <td style="font-size: 16px; font-weight: bold; border-left: 1px solid #666699; border-bottom: 1px solid #666699; border-right: 1px solid #666699;" id="codeA" align="center">&nbsp;</td>
+ </tr>
+ <tr>
+ <td style="font-size: 1px;">&nbsp;</td>
+ </tr>
+ <tr>
+ <td align="center" style="border-left: 1px solid #666699; border-top: 1px solid #666699; border-right: 1px solid #666699;"><label for="codeB">NUM-Code</label></td>
+ </tr>
+ <tr>
+ <td style="font-size: 16px; font-weight: bold; border-left: 1px solid #666699; border-bottom: 1px solid #666699; border-right: 1px solid #666699;" id="codeB" align="center">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" id="charmap_usage">{#advanced_dlg.charmap_usage}</td>
+ </tr>
+
+</table>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/color_picker.htm b/src/wp-includes/js/tinymce/themes/advanced/color_picker.htm
new file mode 100644
index 0000000000..208cdbd365
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/color_picker.htm
@@ -0,0 +1,70 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.colorpicker_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/color_picker.js?ver=358-20121205"></script>
+</head>
+<body id="colorpicker" style="display: none" role="application" aria-labelledby="app_label">
+ <span class="mceVoiceLabel" id="app_label" style="display:none;">{#advanced_dlg.colorpicker_title}</span>
+<form onsubmit="insertAction();return false" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="picker_tab" aria-controls="picker_panel" class="current"><span><a href="javascript:mcTabs.displayTab('picker_tab','picker_panel');" onmousedown="return false;">{#advanced_dlg.colorpicker_picker_tab}</a></span></li>
+ <li id="rgb_tab" aria-controls="rgb_panel"><span><a href="javascript:;" onclick="mcTabs.displayTab('rgb_tab','rgb_panel');" onmousedown="return false;">{#advanced_dlg.colorpicker_palette_tab}</a></span></li>
+ <li id="named_tab" aria-controls="named_panel"><span><a href="javascript:;" onclick="javascript:mcTabs.displayTab('named_tab','named_panel');" onmousedown="return false;">{#advanced_dlg.colorpicker_named_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="picker_panel" class="panel current">
+ <fieldset>
+ <legend>{#advanced_dlg.colorpicker_picker_title}</legend>
+ <div id="picker">
+ <img id="colors" src="img/colorpicker.jpg" onclick="computeColor(event)" onmousedown="isMouseDown = true;return false;" onmouseup="isMouseDown = false;" onmousemove="if (isMouseDown && isMouseOver) computeColor(event); return false;" onmouseover="isMouseOver=true;" onmouseout="isMouseOver=false;" alt="" />
+
+ <div id="light">
+ <!-- Will be filled with divs -->
+ </div>
+
+ <br style="clear: both" />
+ </div>
+ </fieldset>
+ </div>
+
+ <div id="rgb_panel" class="panel">
+ <fieldset>
+ <legend id="webcolors_title">{#advanced_dlg.colorpicker_palette_title}</legend>
+ <div id="webcolors">
+ <!-- Gets filled with web safe colors-->
+ </div>
+
+ <br style="clear: both" />
+ </fieldset>
+ </div>
+
+ <div id="named_panel" class="panel">
+ <fieldset id="named_picker_label">
+ <legend id="named_title">{#advanced_dlg.colorpicker_named_title}</legend>
+ <div id="namedcolors" role="listbox" tabindex="0" aria-labelledby="named_picker_label">
+ <!-- Gets filled with named colors-->
+ </div>
+
+ <br style="clear: both" />
+
+ <div id="colornamecontainer">
+ {#advanced_dlg.colorpicker_name} <span id="colorname"></span>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#apply}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();"/>
+ <div id="preview_wrapper"><div id="previewblock"><label for="color">{#advanced_dlg.colorpicker_color}</label> <input id="color" type="text" size="8" class="text mceFocus" aria-required="true" /></div><span id="preview"></span></div>
+ </div>
+</form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/editor_template.js b/src/wp-includes/js/tinymce/themes/advanced/editor_template.js
new file mode 100644
index 0000000000..4b8d563757
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/editor_template.js
@@ -0,0 +1 @@
+(function(h){var i=h.DOM,g=h.dom.Event,c=h.extend,f=h.each,a=h.util.Cookie,e,d=h.explode;function b(p,m){var k,l,o=p.dom,j="",n,r;previewStyles=p.settings.preview_styles;if(previewStyles===false){return""}if(!previewStyles){previewStyles="font-family font-size font-weight text-decoration text-transform color background-color"}function q(s){return s.replace(/%(\w+)/g,"")}k=m.block||m.inline||"span";l=o.create(k);f(m.styles,function(t,s){t=q(t);if(t){o.setStyle(l,s,t)}});f(m.attributes,function(t,s){t=q(t);if(t){o.setAttrib(l,s,t)}});f(m.classes,function(s){s=q(s);if(!o.hasClass(l,s)){o.addClass(l,s)}});o.setStyles(l,{position:"absolute",left:-65535});p.getBody().appendChild(l);n=o.getStyle(p.getBody(),"fontSize",true);n=/px$/.test(n)?parseInt(n,10):0;f(previewStyles.split(" "),function(s){var t=o.getStyle(l,s,true);if(s=="background-color"&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(t)){t=o.getStyle(p.getBody(),s,true);if(o.toHex(t).toLowerCase()=="#ffffff"){return}}if(s=="font-size"){if(/em|%$/.test(t)){if(n===0){return}t=parseFloat(t,10)/(/%$/.test(t)?100:1);t=(t*n)+"px"}}j+=s+":"+t+";"});o.remove(l);return j}h.ThemeManager.requireLangPack("advanced");h.create("tinymce.themes.AdvancedTheme",{sizes:[8,10,12,14,18,24,36],controls:{bold:["bold_desc","Bold"],italic:["italic_desc","Italic"],underline:["underline_desc","Underline"],strikethrough:["striketrough_desc","Strikethrough"],justifyleft:["justifyleft_desc","JustifyLeft"],justifycenter:["justifycenter_desc","JustifyCenter"],justifyright:["justifyright_desc","JustifyRight"],justifyfull:["justifyfull_desc","JustifyFull"],bullist:["bullist_desc","InsertUnorderedList"],numlist:["numlist_desc","InsertOrderedList"],outdent:["outdent_desc","Outdent"],indent:["indent_desc","Indent"],cut:["cut_desc","Cut"],copy:["copy_desc","Copy"],paste:["paste_desc","Paste"],undo:["undo_desc","Undo"],redo:["redo_desc","Redo"],link:["link_desc","mceLink"],unlink:["unlink_desc","unlink"],image:["image_desc","mceImage"],cleanup:["cleanup_desc","mceCleanup"],help:["help_desc","mceHelp"],code:["code_desc","mceCodeEditor"],hr:["hr_desc","InsertHorizontalRule"],removeformat:["removeformat_desc","RemoveFormat"],sub:["sub_desc","subscript"],sup:["sup_desc","superscript"],forecolor:["forecolor_desc","ForeColor"],forecolorpicker:["forecolor_desc","mceForeColor"],backcolor:["backcolor_desc","HiliteColor"],backcolorpicker:["backcolor_desc","mceBackColor"],charmap:["charmap_desc","mceCharMap"],visualaid:["visualaid_desc","mceToggleVisualAid"],anchor:["anchor_desc","mceInsertAnchor"],newdocument:["newdocument_desc","mceNewDocument"],blockquote:["blockquote_desc","mceBlockQuote"]},stateControls:["bold","italic","underline","strikethrough","bullist","numlist","justifyleft","justifycenter","justifyright","justifyfull","sub","sup","blockquote"],init:function(k,l){var m=this,n,j,p;m.editor=k;m.url=l;m.onResolveName=new h.util.Dispatcher(this);n=k.settings;k.forcedHighContrastMode=k.settings.detect_highcontrast&&m._isHighContrast();k.settings.skin=k.forcedHighContrastMode?"highcontrast":k.settings.skin;if(!n.theme_advanced_buttons1){n=c({theme_advanced_buttons1:"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect",theme_advanced_buttons2:"bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code",theme_advanced_buttons3:"hr,removeformat,visualaid,|,sub,sup,|,charmap"},n)}m.settings=n=c({theme_advanced_path:true,theme_advanced_toolbar_location:"top",theme_advanced_blockformats:"p,address,pre,h1,h2,h3,h4,h5,h6",theme_advanced_toolbar_align:"left",theme_advanced_statusbar_location:"bottom",theme_advanced_fonts:"Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",theme_advanced_more_colors:1,theme_advanced_row_height:23,theme_advanced_resize_horizontal:1,theme_advanced_resizing_use_cookie:1,theme_advanced_font_sizes:"1,2,3,4,5,6,7",theme_advanced_font_selector:"span",theme_advanced_show_current_color:0,readonly:k.settings.readonly},n);if(!n.font_size_style_values){n.font_size_style_values="8pt,10pt,12pt,14pt,18pt,24pt,36pt"}if(h.is(n.theme_advanced_font_sizes,"string")){n.font_size_style_values=h.explode(n.font_size_style_values);n.font_size_classes=h.explode(n.font_size_classes||"");p={};k.settings.theme_advanced_font_sizes=n.theme_advanced_font_sizes;f(k.getParam("theme_advanced_font_sizes","","hash"),function(r,q){var o;if(q==r&&r>=1&&r<=7){q=r+" ("+m.sizes[r-1]+"pt)";o=n.font_size_classes[r-1];r=n.font_size_style_values[r-1]||(m.sizes[r-1]+"pt")}if(/^\s*\./.test(r)){o=r.replace(/\./g,"")}p[q]=o?{"class":o}:{fontSize:r}});n.theme_advanced_font_sizes=p}if((j=n.theme_advanced_path_location)&&j!="none"){n.theme_advanced_statusbar_location=n.theme_advanced_path_location}if(n.theme_advanced_statusbar_location=="none"){n.theme_advanced_statusbar_location=0}if(k.settings.content_css!==false){k.contentCSS.push(k.baseURI.toAbsolute(l+"/skins/"+k.settings.skin+"/content.css"))}k.onInit.add(function(){if(!k.settings.readonly){k.onNodeChange.add(m._nodeChanged,m);k.onKeyUp.add(m._updateUndoStatus,m);k.onMouseUp.add(m._updateUndoStatus,m);k.dom.bind(k.dom.getRoot(),"dragend",function(){m._updateUndoStatus(k)})}});k.onSetProgressState.add(function(r,o,s){var t,u=r.id,q;if(o){m.progressTimer=setTimeout(function(){t=r.getContainer();t=t.insertBefore(i.create("DIV",{style:"position:relative"}),t.firstChild);q=i.get(r.id+"_tbl");i.add(t,"div",{id:u+"_blocker","class":"mceBlocker",style:{width:q.clientWidth+2,height:q.clientHeight+2}});i.add(t,"div",{id:u+"_progress","class":"mceProgress",style:{left:q.clientWidth/2,top:q.clientHeight/2}})},s||0)}else{i.remove(u+"_blocker");i.remove(u+"_progress");clearTimeout(m.progressTimer)}});i.loadCSS(n.editor_css?k.documentBaseURI.toAbsolute(n.editor_css):l+"/skins/"+k.settings.skin+"/ui.css");if(n.skin_variant){i.loadCSS(l+"/skins/"+k.settings.skin+"/ui_"+n.skin_variant+".css")}},_isHighContrast:function(){var j,k=i.add(i.getRoot(),"div",{style:"background-color: rgb(171,239,86);"});j=(i.getStyle(k,"background-color",true)+"").toLowerCase().replace(/ /g,"");i.remove(k);return j!="rgb(171,239,86)"&&j!="#abef56"},createControl:function(m,j){var k,l;if(l=j.createControl(m)){return l}switch(m){case"styleselect":return this._createStyleSelect();case"formatselect":return this._createBlockFormats();case"fontselect":return this._createFontSelect();case"fontsizeselect":return this._createFontSizeSelect();case"forecolor":return this._createForeColorMenu();case"backcolor":return this._createBackColorMenu()}if((k=this.controls[m])){return j.createButton(m,{title:"advanced."+k[0],cmd:k[1],ui:k[2],value:k[3]})}},execCommand:function(l,k,m){var j=this["_"+l];if(j){j.call(this,k,m);return true}return false},_importClasses:function(l){var j=this.editor,k=j.controlManager.get("styleselect");if(k.getLength()==0){f(j.dom.getClasses(),function(q,m){var p="style_"+m,n;n={inline:"span",attributes:{"class":q["class"]},selector:"*"};j.formatter.register(p,n);k.add(q["class"],p,{style:function(){return b(j,n)}})})}},_createStyleSelect:function(o){var l=this,j=l.editor,k=j.controlManager,m;m=k.createListBox("styleselect",{title:"advanced.style_select",onselect:function(q){var r,n=[],p;f(m.items,function(s){n.push(s.value)});j.focus();j.undoManager.add();r=j.formatter.matchAll(n);h.each(r,function(s){if(!q||s==q){if(s){j.formatter.remove(s)}p=true}});if(!p){j.formatter.apply(q)}j.undoManager.add();j.nodeChanged();return false}});j.onPreInit.add(function(){var p=0,n=j.getParam("style_formats");if(n){f(n,function(q){var r,s=0;f(q,function(){s++});if(s>1){r=q.name=q.name||"style_"+(p++);j.formatter.register(r,q);m.add(q.title,r,{style:function(){return b(j,q)}})}else{m.add(q.title)}})}else{f(j.getParam("theme_advanced_styles","","hash"),function(t,s){var r,q;if(t){r="style_"+(p++);q={inline:"span",classes:t,selector:"*"};j.formatter.register(r,q);m.add(l.editor.translate(s),r,{style:function(){return b(j,q)}})}})}});if(m.getLength()==0){m.onPostRender.add(function(p,q){if(!m.NativeListBox){g.add(q.id+"_text","focus",l._importClasses,l);g.add(q.id+"_text","mousedown",l._importClasses,l);g.add(q.id+"_open","focus",l._importClasses,l);g.add(q.id+"_open","mousedown",l._importClasses,l)}else{g.add(q.id,"focus",l._importClasses,l)}})}return m},_createFontSelect:function(){var l,k=this,j=k.editor;l=j.controlManager.createListBox("fontselect",{title:"advanced.fontdefault",onselect:function(m){var n=l.items[l.selectedIndex];if(!m&&n){j.execCommand("FontName",false,n.value);return}j.execCommand("FontName",false,m);l.select(function(o){return m==o});if(n&&n.value==m){l.select(null)}return false}});if(l){f(j.getParam("theme_advanced_fonts",k.settings.theme_advanced_fonts,"hash"),function(n,m){l.add(j.translate(m),n,{style:n.indexOf("dings")==-1?"font-family:"+n:""})})}return l},_createFontSizeSelect:function(){var m=this,k=m.editor,n,l=0,j=[];n=k.controlManager.createListBox("fontsizeselect",{title:"advanced.font_size",onselect:function(o){var p=n.items[n.selectedIndex];if(!o&&p){p=p.value;if(p["class"]){k.formatter.toggle("fontsize_class",{value:p["class"]});k.undoManager.add();k.nodeChanged()}else{k.execCommand("FontSize",false,p.fontSize)}return}if(o["class"]){k.focus();k.undoManager.add();k.formatter.toggle("fontsize_class",{value:o["class"]});k.undoManager.add();k.nodeChanged()}else{k.execCommand("FontSize",false,o.fontSize)}n.select(function(q){return o==q});if(p&&(p.value.fontSize==o.fontSize||p.value["class"]&&p.value["class"]==o["class"])){n.select(null)}return false}});if(n){f(m.settings.theme_advanced_font_sizes,function(p,o){var q=p.fontSize;if(q>=1&&q<=7){q=m.sizes[parseInt(q)-1]+"pt"}n.add(o,p,{style:"font-size:"+q,"class":"mceFontSize"+(l++)+(" "+(p["class"]||""))})})}return n},_createBlockFormats:function(){var l,j={p:"advanced.paragraph",address:"advanced.address",pre:"advanced.pre",h1:"advanced.h1",h2:"advanced.h2",h3:"advanced.h3",h4:"advanced.h4",h5:"advanced.h5",h6:"advanced.h6",div:"advanced.div",blockquote:"advanced.blockquote",code:"advanced.code",dt:"advanced.dt",dd:"advanced.dd",samp:"advanced.samp"},k=this;l=k.editor.controlManager.createListBox("formatselect",{title:"advanced.block",onselect:function(m){k.editor.execCommand("FormatBlock",false,m);return false}});if(l){f(k.editor.getParam("theme_advanced_blockformats",k.settings.theme_advanced_blockformats,"hash"),function(n,m){l.add(k.editor.translate(m!=n?m:j[n]),n,{"class":"mce_formatPreview mce_"+n,style:function(){return b(k.editor,{block:n})}})})}return l},_createForeColorMenu:function(){var n,k=this,l=k.settings,m={},j;if(l.theme_advanced_more_colors){m.more_colors_func=function(){k._mceColorPicker(0,{color:n.value,func:function(o){n.setColor(o)}})}}if(j=l.theme_advanced_text_colors){m.colors=j}if(l.theme_advanced_default_foreground_color){m.default_color=l.theme_advanced_default_foreground_color}m.title="advanced.forecolor_desc";m.cmd="ForeColor";m.scope=this;n=k.editor.controlManager.createColorSplitButton("forecolor",m);return n},_createBackColorMenu:function(){var n,k=this,l=k.settings,m={},j;if(l.theme_advanced_more_colors){m.more_colors_func=function(){k._mceColorPicker(0,{color:n.value,func:function(o){n.setColor(o)}})}}if(j=l.theme_advanced_background_colors){m.colors=j}if(l.theme_advanced_default_background_color){m.default_color=l.theme_advanced_default_background_color}m.title="advanced.backcolor_desc";m.cmd="HiliteColor";m.scope=this;n=k.editor.controlManager.createColorSplitButton("backcolor",m);return n},renderUI:function(l){var q,m,r,w=this,u=w.editor,x=w.settings,v,k,j;if(u.settings){u.settings.aria_label=x.aria_label+u.getLang("advanced.help_shortcut")}q=k=i.create("span",{role:"application","aria-labelledby":u.id+"_voice",id:u.id+"_parent","class":"mceEditor "+u.settings.skin+"Skin"+(x.skin_variant?" "+u.settings.skin+"Skin"+w._ufirst(x.skin_variant):"")+(u.settings.directionality=="rtl"?" mceRtl":"")});i.add(q,"span",{"class":"mceVoiceLabel",style:"display:none;",id:u.id+"_voice"},x.aria_label);if(!i.boxModel){q=i.add(q,"div",{"class":"mceOldBoxModel"})}q=v=i.add(q,"table",{role:"presentation",id:u.id+"_tbl","class":"mceLayout",cellSpacing:0,cellPadding:0});q=r=i.add(q,"tbody");switch((x.theme_advanced_layout_manager||"").toLowerCase()){case"rowlayout":m=w._rowLayout(x,r,l);break;case"customlayout":m=u.execCallback("theme_advanced_custom_layout",x,r,l,k);break;default:m=w._simpleLayout(x,r,l,k)}q=l.targetNode;j=v.rows;i.addClass(j[0],"mceFirst");i.addClass(j[j.length-1],"mceLast");f(i.select("tr",r),function(o){i.addClass(o.firstChild,"mceFirst");i.addClass(o.childNodes[o.childNodes.length-1],"mceLast")});if(i.get(x.theme_advanced_toolbar_container)){i.get(x.theme_advanced_toolbar_container).appendChild(k)}else{i.insertAfter(k,q)}g.add(u.id+"_path_row","click",function(n){n=n.target;if(n.nodeName=="A"){w._sel(n.className.replace(/^.*mcePath_([0-9]+).*$/,"$1"));return false}});if(!u.getParam("accessibility_focus")){g.add(i.add(k,"a",{href:"#"},"<!-- IE -->"),"focus",function(){tinyMCE.get(u.id).focus()})}if(x.theme_advanced_toolbar_location=="external"){l.deltaHeight=0}w.deltaHeight=l.deltaHeight;l.targetNode=null;u.onKeyDown.add(function(p,n){var s=121,o=122;if(n.altKey){if(n.keyCode===s){if(h.isWebKit){window.focus()}w.toolbarGroup.focus();return g.cancel(n)}else{if(n.keyCode===o){i.get(p.id+"_path_row").focus();return g.cancel(n)}}}});u.addShortcut("alt+0","","mceShortcuts",w);return{iframeContainer:m,editorContainer:u.id+"_parent",sizeContainer:v,deltaHeight:l.deltaHeight}},getInfo:function(){return{longname:"Advanced theme",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",version:h.majorVersion+"."+h.minorVersion}},resizeBy:function(j,k){var l=i.get(this.editor.id+"_ifr");this.resizeTo(l.clientWidth+j,l.clientHeight+k)},resizeTo:function(j,n,l){var k=this.editor,m=this.settings,o=i.get(k.id+"_tbl"),p=i.get(k.id+"_ifr");j=Math.max(m.theme_advanced_resizing_min_width||100,j);n=Math.max(m.theme_advanced_resizing_min_height||100,n);j=Math.min(m.theme_advanced_resizing_max_width||65535,j);n=Math.min(m.theme_advanced_resizing_max_height||65535,n);i.setStyle(o,"height","");i.setStyle(p,"height",n);if(m.theme_advanced_resize_horizontal){i.setStyle(o,"width","");i.setStyle(p,"width",j);if(j<o.clientWidth){j=o.clientWidth;i.setStyle(p,"width",o.clientWidth)}}if(l&&m.theme_advanced_resizing_use_cookie){a.setHash("TinyMCE_"+k.id+"_size",{cw:j,ch:n})}},destroy:function(){var j=this.editor.id;g.clear(j+"_resize");g.clear(j+"_path_row");g.clear(j+"_external_close")},_simpleLayout:function(z,u,l,j){var y=this,v=y.editor,w=z.theme_advanced_toolbar_location,q=z.theme_advanced_statusbar_location,m,k,r,x;if(z.readonly){m=i.add(u,"tr");m=k=i.add(m,"td",{"class":"mceIframeContainer"});return k}if(w=="top"){y._addToolbars(u,l)}if(w=="external"){m=x=i.create("div",{style:"position:relative"});m=i.add(m,"div",{id:v.id+"_external","class":"mceExternalToolbar"});i.add(m,"a",{id:v.id+"_external_close",href:"javascript:;","class":"mceExternalClose"});m=i.add(m,"table",{id:v.id+"_tblext",cellSpacing:0,cellPadding:0});r=i.add(m,"tbody");if(j.firstChild.className=="mceOldBoxModel"){j.firstChild.appendChild(x)}else{j.insertBefore(x,j.firstChild)}y._addToolbars(r,l);v.onMouseUp.add(function(){var o=i.get(v.id+"_external");i.show(o);i.hide(e);var n=g.add(v.id+"_external_close","click",function(){i.hide(v.id+"_external");g.remove(v.id+"_external_close","click",n);return false});i.show(o);i.setStyle(o,"top",0-i.getRect(v.id+"_tblext").h-1);i.hide(o);i.show(o);o.style.filter="";e=v.id+"_external";o=null})}if(q=="top"){y._addStatusBar(u,l)}if(!z.theme_advanced_toolbar_container){m=i.add(u,"tr");m=k=i.add(m,"td",{"class":"mceIframeContainer"})}if(w=="bottom"){y._addToolbars(u,l)}if(q=="bottom"){y._addStatusBar(u,l)}return k},_rowLayout:function(x,p,l){var w=this,q=w.editor,v,y,j=q.controlManager,m,k,u,r;v=x.theme_advanced_containers_default_class||"";y=x.theme_advanced_containers_default_align||"center";f(d(x.theme_advanced_containers||""),function(s,o){var n=x["theme_advanced_container_"+s]||"";switch(s.toLowerCase()){case"mceeditor":m=i.add(p,"tr");m=k=i.add(m,"td",{"class":"mceIframeContainer"});break;case"mceelementpath":w._addStatusBar(p,l);break;default:r=(x["theme_advanced_container_"+s+"_align"]||y).toLowerCase();r="mce"+w._ufirst(r);m=i.add(i.add(p,"tr"),"td",{"class":"mceToolbar "+(x["theme_advanced_container_"+s+"_class"]||v)+" "+r||y});u=j.createToolbar("toolbar"+o);w._addControls(n,u);i.setHTML(m,u.renderHTML());l.deltaHeight-=x.theme_advanced_row_height}});return k},_addControls:function(k,j){var l=this,m=l.settings,n,o=l.editor.controlManager;if(m.theme_advanced_disable&&!l._disabled){n={};f(d(m.theme_advanced_disable),function(p){n[p]=1});l._disabled=n}else{n=l._disabled}f(d(k),function(q){var p;if(n&&n[q]){return}if(q=="tablecontrols"){f(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"],function(r){r=l.createControl(r,o);if(r){j.add(r)}});return}p=l.createControl(q,o);if(p){j.add(p)}})},_addToolbars:function(y,k){var B=this,q,p,u=B.editor,C=B.settings,A,j=u.controlManager,w,l,r=[],z,x,m=false;x=j.createToolbarGroup("toolbargroup",{name:u.getLang("advanced.toolbar"),tab_focus_toolbar:u.getParam("theme_advanced_tab_focus_toolbar")});B.toolbarGroup=x;z=C.theme_advanced_toolbar_align.toLowerCase();z="mce"+B._ufirst(z);l=i.add(i.add(y,"tr",{role:"presentation"}),"td",{"class":"mceToolbar "+z,role:"toolbar"});for(q=1;(A=C["theme_advanced_buttons"+q]);q++){m=true;p=j.createToolbar("toolbar"+q,{"class":"mceToolbarRow"+q});if(C["theme_advanced_buttons"+q+"_add"]){A+=","+C["theme_advanced_buttons"+q+"_add"]}if(C["theme_advanced_buttons"+q+"_add_before"]){A=C["theme_advanced_buttons"+q+"_add_before"]+","+A}B._addControls(A,p);x.add(p);k.deltaHeight-=C.theme_advanced_row_height}if(!m){k.deltaHeight-=C.theme_advanced_row_height}r.push(x.renderHTML());r.push(i.createHTML("a",{href:"#",accesskey:"z",title:u.getLang("advanced.toolbar_focus"),onfocus:"tinyMCE.getInstanceById('"+u.id+"').focus();"},"<!-- IE -->"));i.setHTML(l,r.join(""))},_addStatusBar:function(p,k){var l,w=this,q=w.editor,x=w.settings,j,u,v,m;l=i.add(p,"tr");l=m=i.add(l,"td",{"class":"mceStatusbar"});l=i.add(l,"div",{id:q.id+"_path_row",role:"group","aria-labelledby":q.id+"_path_voice"});if(x.theme_advanced_path){i.add(l,"span",{id:q.id+"_path_voice"},q.translate("advanced.path"));i.add(l,"span",{},": ")}else{i.add(l,"span",{},"&#160;")}if(x.theme_advanced_resizing){i.add(m,"a",{id:q.id+"_resize",href:"javascript:;",onclick:"return false;","class":"mceResize",tabIndex:"-1"});if(x.theme_advanced_resizing_use_cookie){q.onPostRender.add(function(){var n=a.getHash("TinyMCE_"+q.id+"_size"),r=i.get(q.id+"_tbl");if(!n){return}w.resizeTo(n.cw,n.ch)})}q.onPostRender.add(function(){g.add(q.id+"_resize","click",function(n){n.preventDefault()});g.add(q.id+"_resize","mousedown",function(E){var t,r,s,o,D,A,B,G,n,F,y;function z(H){H.preventDefault();n=B+(H.screenX-D);F=G+(H.screenY-A);w.resizeTo(n,F)}function C(H){g.remove(i.doc,"mousemove",t);g.remove(q.getDoc(),"mousemove",r);g.remove(i.doc,"mouseup",s);g.remove(q.getDoc(),"mouseup",o);n=B+(H.screenX-D);F=G+(H.screenY-A);w.resizeTo(n,F,true);q.nodeChanged()}E.preventDefault();D=E.screenX;A=E.screenY;y=i.get(w.editor.id+"_ifr");B=n=y.clientWidth;G=F=y.clientHeight;t=g.add(i.doc,"mousemove",z);r=g.add(q.getDoc(),"mousemove",z);s=g.add(i.doc,"mouseup",C);o=g.add(q.getDoc(),"mouseup",C)})})}k.deltaHeight-=21;l=p=null},_updateUndoStatus:function(k){var j=k.controlManager,l=k.undoManager;j.setDisabled("undo",!l.hasUndo()&&!l.typing);j.setDisabled("redo",!l.hasRedo())},_nodeChanged:function(o,u,E,r,F){var z=this,D,G=0,y,H,A=z.settings,x,l,w,C,m,k,j;h.each(z.stateControls,function(n){u.setActive(n,o.queryCommandState(z.controls[n][1]))});function q(p){var s,n=F.parents,t=p;if(typeof(p)=="string"){t=function(v){return v.nodeName==p}}for(s=0;s<n.length;s++){if(t(n[s])){return n[s]}}}u.setActive("visualaid",o.hasVisual);z._updateUndoStatus(o);u.setDisabled("outdent",!o.queryCommandState("Outdent"));D=q("A");if(H=u.get("link")){H.setDisabled((!D&&r)||(D&&!D.href));H.setActive(!!D&&(!D.name&&!D.id))}if(H=u.get("unlink")){H.setDisabled(!D&&r);H.setActive(!!D&&!D.name&&!D.id)}if(H=u.get("anchor")){H.setActive(!r&&!!D&&(D.name||(D.id&&!D.href)))}D=q("IMG");if(H=u.get("image")){H.setActive(!r&&!!D&&E.className.indexOf("mceItem")==-1)}if(H=u.get("styleselect")){z._importClasses();k=[];f(H.items,function(n){k.push(n.value)});j=o.formatter.matchAll(k);H.select(j[0]);h.each(j,function(p,n){if(n>0){H.mark(p)}})}if(H=u.get("formatselect")){D=q(o.dom.isBlock);if(D){H.select(D.nodeName.toLowerCase())}}q(function(p){if(p.nodeName==="SPAN"){if(!x&&p.className){x=p.className}}if(o.dom.is(p,A.theme_advanced_font_selector)){if(!l&&p.style.fontSize){l=p.style.fontSize}if(!w&&p.style.fontFamily){w=p.style.fontFamily.replace(/[\"\']+/g,"").replace(/^([^,]+).*/,"$1").toLowerCase()}if(!C&&p.style.color){C=p.style.color}if(!m&&p.style.backgroundColor){m=p.style.backgroundColor}}return false});if(H=u.get("fontselect")){H.select(function(n){return n.replace(/^([^,]+).*/,"$1").toLowerCase()==w})}if(H=u.get("fontsizeselect")){if(A.theme_advanced_runtime_fontsize&&!l&&!x){l=o.dom.getStyle(E,"fontSize",true)}H.select(function(n){if(n.fontSize&&n.fontSize===l){return true}if(n["class"]&&n["class"]===x){return true}})}if(A.theme_advanced_show_current_color){function B(p,n){if(H=u.get(p)){if(!n){n=H.settings.default_color}if(n!==H.value){H.displayColor(n)}}}B("forecolor",C);B("backcolor",m)}if(A.theme_advanced_show_current_color){function B(p,n){if(H=u.get(p)){if(!n){n=H.settings.default_color}if(n!==H.value){H.displayColor(n)}}}B("forecolor",C);B("backcolor",m)}if(A.theme_advanced_path&&A.theme_advanced_statusbar_location){D=i.get(o.id+"_path")||i.add(o.id+"_path_row","span",{id:o.id+"_path"});if(z.statusKeyboardNavigation){z.statusKeyboardNavigation.destroy();z.statusKeyboardNavigation=null}i.setHTML(D,"");q(function(I){var p=I.nodeName.toLowerCase(),s,v,t="";if(I.nodeType!=1||p==="br"||I.getAttribute("data-mce-bogus")||i.hasClass(I,"mceItemHidden")||i.hasClass(I,"mceItemRemoved")){return}if(h.isIE&&I.scopeName!=="HTML"&&I.scopeName){p=I.scopeName+":"+p}p=p.replace(/mce\:/g,"");switch(p){case"b":p="strong";break;case"i":p="em";break;case"img":if(y=i.getAttrib(I,"src")){t+="src: "+y+" "}break;case"a":if(y=i.getAttrib(I,"name")){t+="name: "+y+" ";p+="#"+y}if(y=i.getAttrib(I,"href")){t+="href: "+y+" "}break;case"font":if(y=i.getAttrib(I,"face")){t+="font: "+y+" "}if(y=i.getAttrib(I,"size")){t+="size: "+y+" "}if(y=i.getAttrib(I,"color")){t+="color: "+y+" "}break;case"span":if(y=i.getAttrib(I,"style")){t+="style: "+y+" "}break}if(y=i.getAttrib(I,"id")){t+="id: "+y+" "}if(y=I.className){y=y.replace(/\b\s*(webkit|mce|Apple-)\w+\s*\b/g,"");if(y){t+="class: "+y+" ";if(o.dom.isBlock(I)||p=="img"||p=="span"){p+="."+y}}}p=p.replace(/(html:)/g,"");p={name:p,node:I,title:t};z.onResolveName.dispatch(z,p);t=p.title;p=p.name;v=i.create("a",{href:"javascript:;",role:"button",onmousedown:"return false;",title:t,"class":"mcePath_"+(G++)},p);if(D.hasChildNodes()){D.insertBefore(i.create("span",{"aria-hidden":"true"},"\u00a0\u00bb "),D.firstChild);D.insertBefore(v,D.firstChild)}else{D.appendChild(v)}},o.getBody());if(i.select("a",D).length>0){z.statusKeyboardNavigation=new h.ui.KeyboardNavigation({root:o.id+"_path_row",items:i.select("a",D),excludeFromTabOrder:true,onCancel:function(){o.focus()}},i)}}},_sel:function(j){this.editor.execCommand("mceSelectNodeDepth",false,j)},_mceInsertAnchor:function(l,k){var j=this.editor;j.windowManager.open({url:this.url+"/anchor.htm",width:320+parseInt(j.getLang("advanced.anchor_delta_width",0)),height:90+parseInt(j.getLang("advanced.anchor_delta_height",0)),inline:true},{theme_url:this.url})},_mceCharMap:function(){var j=this.editor;j.windowManager.open({url:this.url+"/charmap.htm",width:550+parseInt(j.getLang("advanced.charmap_delta_width",0)),height:265+parseInt(j.getLang("advanced.charmap_delta_height",0)),inline:true},{theme_url:this.url})},_mceHelp:function(){var j=this.editor;j.windowManager.open({url:this.url+"/about.htm",width:480,height:380,inline:true},{theme_url:this.url})},_mceShortcuts:function(){var j=this.editor;j.windowManager.open({url:this.url+"/shortcuts.htm",width:480,height:380,inline:true},{theme_url:this.url})},_mceColorPicker:function(l,k){var j=this.editor;k=k||{};j.windowManager.open({url:this.url+"/color_picker.htm",width:375+parseInt(j.getLang("advanced.colorpicker_delta_width",0)),height:250+parseInt(j.getLang("advanced.colorpicker_delta_height",0)),close_previous:false,inline:true},{input_color:k.color,func:k.func,theme_url:this.url})},_mceCodeEditor:function(k,l){var j=this.editor;j.windowManager.open({url:this.url+"/source_editor.htm",width:parseInt(j.getParam("theme_advanced_source_editor_width",720)),height:parseInt(j.getParam("theme_advanced_source_editor_height",580)),inline:true,resizable:true,maximizable:true},{theme_url:this.url})},_mceImage:function(k,l){var j=this.editor;if(j.dom.getAttrib(j.selection.getNode(),"class","").indexOf("mceItem")!=-1){return}j.windowManager.open({url:this.url+"/image.htm",width:355+parseInt(j.getLang("advanced.image_delta_width",0)),height:275+parseInt(j.getLang("advanced.image_delta_height",0)),inline:true},{theme_url:this.url})},_mceLink:function(k,l){var j=this.editor;j.windowManager.open({url:this.url+"/link.htm",width:310+parseInt(j.getLang("advanced.link_delta_width",0)),height:200+parseInt(j.getLang("advanced.link_delta_height",0)),inline:true},{theme_url:this.url})},_mceNewDocument:function(){var j=this.editor;j.windowManager.confirm("advanced.newdocument",function(k){if(k){j.execCommand("mceSetContent",false,"")}})},_mceForeColor:function(){var j=this;this._mceColorPicker(0,{color:j.fgColor,func:function(k){j.fgColor=k;j.editor.execCommand("ForeColor",false,k)}})},_mceBackColor:function(){var j=this;this._mceColorPicker(0,{color:j.bgColor,func:function(k){j.bgColor=k;j.editor.execCommand("HiliteColor",false,k)}})},_ufirst:function(j){return j.substring(0,1).toUpperCase()+j.substring(1)}});h.ThemeManager.add("advanced",h.themes.AdvancedTheme)}(tinymce)); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/themes/advanced/editor_template_src.js b/src/wp-includes/js/tinymce/themes/advanced/editor_template_src.js
new file mode 100644
index 0000000000..84039ce2ac
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/editor_template_src.js
@@ -0,0 +1,1490 @@
+/**
+ * editor_template_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode;
+
+ // Generates a preview for a format
+ function getPreviewCss(ed, fmt) {
+ var name, previewElm, dom = ed.dom, previewCss = '', parentFontSize, previewStylesName;
+
+ previewStyles = ed.settings.preview_styles;
+
+ // No preview forced
+ if (previewStyles === false)
+ return '';
+
+ // Default preview
+ if (!previewStyles)
+ previewStyles = 'font-family font-size font-weight text-decoration text-transform color background-color';
+
+ // Removes any variables since these can't be previewed
+ function removeVars(val) {
+ return val.replace(/%(\w+)/g, '');
+ };
+
+ // Create block/inline element to use for preview
+ name = fmt.block || fmt.inline || 'span';
+ previewElm = dom.create(name);
+
+ // Add format styles to preview element
+ each(fmt.styles, function(value, name) {
+ value = removeVars(value);
+
+ if (value)
+ dom.setStyle(previewElm, name, value);
+ });
+
+ // Add attributes to preview element
+ each(fmt.attributes, function(value, name) {
+ value = removeVars(value);
+
+ if (value)
+ dom.setAttrib(previewElm, name, value);
+ });
+
+ // Add classes to preview element
+ each(fmt.classes, function(value) {
+ value = removeVars(value);
+
+ if (!dom.hasClass(previewElm, value))
+ dom.addClass(previewElm, value);
+ });
+
+ // Add the previewElm outside the visual area
+ dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
+ ed.getBody().appendChild(previewElm);
+
+ // Get parent container font size so we can compute px values out of em/% for older IE:s
+ parentFontSize = dom.getStyle(ed.getBody(), 'fontSize', true);
+ parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
+
+ each(previewStyles.split(' '), function(name) {
+ var value = dom.getStyle(previewElm, name, true);
+
+ // If background is transparent then check if the body has a background color we can use
+ if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
+ value = dom.getStyle(ed.getBody(), name, true);
+
+ // Ignore white since it's the default color, not the nicest fix
+ if (dom.toHex(value).toLowerCase() == '#ffffff') {
+ return;
+ }
+ }
+
+ // Old IE won't calculate the font size so we need to do that manually
+ if (name == 'font-size') {
+ if (/em|%$/.test(value)) {
+ if (parentFontSize === 0) {
+ return;
+ }
+
+ // Convert font size from em/% to px
+ value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
+ value = (value * parentFontSize) + 'px';
+ }
+ }
+
+ previewCss += name + ':' + value + ';';
+ });
+
+ dom.remove(previewElm);
+
+ return previewCss;
+ };
+
+ // Tell it to load theme specific language pack(s)
+ tinymce.ThemeManager.requireLangPack('advanced');
+
+ tinymce.create('tinymce.themes.AdvancedTheme', {
+ sizes : [8, 10, 12, 14, 18, 24, 36],
+
+ // Control name lookup, format: title, command
+ controls : {
+ bold : ['bold_desc', 'Bold'],
+ italic : ['italic_desc', 'Italic'],
+ underline : ['underline_desc', 'Underline'],
+ strikethrough : ['striketrough_desc', 'Strikethrough'],
+ justifyleft : ['justifyleft_desc', 'JustifyLeft'],
+ justifycenter : ['justifycenter_desc', 'JustifyCenter'],
+ justifyright : ['justifyright_desc', 'JustifyRight'],
+ justifyfull : ['justifyfull_desc', 'JustifyFull'],
+ bullist : ['bullist_desc', 'InsertUnorderedList'],
+ numlist : ['numlist_desc', 'InsertOrderedList'],
+ outdent : ['outdent_desc', 'Outdent'],
+ indent : ['indent_desc', 'Indent'],
+ cut : ['cut_desc', 'Cut'],
+ copy : ['copy_desc', 'Copy'],
+ paste : ['paste_desc', 'Paste'],
+ undo : ['undo_desc', 'Undo'],
+ redo : ['redo_desc', 'Redo'],
+ link : ['link_desc', 'mceLink'],
+ unlink : ['unlink_desc', 'unlink'],
+ image : ['image_desc', 'mceImage'],
+ cleanup : ['cleanup_desc', 'mceCleanup'],
+ help : ['help_desc', 'mceHelp'],
+ code : ['code_desc', 'mceCodeEditor'],
+ hr : ['hr_desc', 'InsertHorizontalRule'],
+ removeformat : ['removeformat_desc', 'RemoveFormat'],
+ sub : ['sub_desc', 'subscript'],
+ sup : ['sup_desc', 'superscript'],
+ forecolor : ['forecolor_desc', 'ForeColor'],
+ forecolorpicker : ['forecolor_desc', 'mceForeColor'],
+ backcolor : ['backcolor_desc', 'HiliteColor'],
+ backcolorpicker : ['backcolor_desc', 'mceBackColor'],
+ charmap : ['charmap_desc', 'mceCharMap'],
+ visualaid : ['visualaid_desc', 'mceToggleVisualAid'],
+ anchor : ['anchor_desc', 'mceInsertAnchor'],
+ newdocument : ['newdocument_desc', 'mceNewDocument'],
+ blockquote : ['blockquote_desc', 'mceBlockQuote']
+ },
+
+ stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'],
+
+ init : function(ed, url) {
+ var t = this, s, v, o;
+
+ t.editor = ed;
+ t.url = url;
+ t.onResolveName = new tinymce.util.Dispatcher(this);
+ s = ed.settings;
+
+ ed.forcedHighContrastMode = ed.settings.detect_highcontrast && t._isHighContrast();
+ ed.settings.skin = ed.forcedHighContrastMode ? 'highcontrast' : ed.settings.skin;
+
+ // Setup default buttons
+ if (!s.theme_advanced_buttons1) {
+ s = extend({
+ theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect",
+ theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code",
+ theme_advanced_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap"
+ }, s);
+ }
+
+ // Default settings
+ t.settings = s = extend({
+ theme_advanced_path : true,
+ theme_advanced_toolbar_location : 'top',
+ theme_advanced_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6",
+ theme_advanced_toolbar_align : "left",
+ theme_advanced_statusbar_location : "bottom",
+ theme_advanced_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",
+ theme_advanced_more_colors : 1,
+ theme_advanced_row_height : 23,
+ theme_advanced_resize_horizontal : 1,
+ theme_advanced_resizing_use_cookie : 1,
+ theme_advanced_font_sizes : "1,2,3,4,5,6,7",
+ theme_advanced_font_selector : "span",
+ theme_advanced_show_current_color: 0,
+ readonly : ed.settings.readonly
+ }, s);
+
+ // Setup default font_size_style_values
+ if (!s.font_size_style_values)
+ s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt";
+
+ if (tinymce.is(s.theme_advanced_font_sizes, 'string')) {
+ s.font_size_style_values = tinymce.explode(s.font_size_style_values);
+ s.font_size_classes = tinymce.explode(s.font_size_classes || '');
+
+ // Parse string value
+ o = {};
+ ed.settings.theme_advanced_font_sizes = s.theme_advanced_font_sizes;
+ each(ed.getParam('theme_advanced_font_sizes', '', 'hash'), function(v, k) {
+ var cl;
+
+ if (k == v && v >= 1 && v <= 7) {
+ k = v + ' (' + t.sizes[v - 1] + 'pt)';
+ cl = s.font_size_classes[v - 1];
+ v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt');
+ }
+
+ if (/^\s*\./.test(v))
+ cl = v.replace(/\./g, '');
+
+ o[k] = cl ? {'class' : cl} : {fontSize : v};
+ });
+
+ s.theme_advanced_font_sizes = o;
+ }
+
+ if ((v = s.theme_advanced_path_location) && v != 'none')
+ s.theme_advanced_statusbar_location = s.theme_advanced_path_location;
+
+ if (s.theme_advanced_statusbar_location == 'none')
+ s.theme_advanced_statusbar_location = 0;
+
+ if (ed.settings.content_css !== false)
+ ed.contentCSS.push(ed.baseURI.toAbsolute(url + "/skins/" + ed.settings.skin + "/content.css"));
+
+ // Init editor
+ ed.onInit.add(function() {
+ if (!ed.settings.readonly) {
+ ed.onNodeChange.add(t._nodeChanged, t);
+ ed.onKeyUp.add(t._updateUndoStatus, t);
+ ed.onMouseUp.add(t._updateUndoStatus, t);
+ ed.dom.bind(ed.dom.getRoot(), 'dragend', function() {
+ t._updateUndoStatus(ed);
+ });
+ }
+ });
+
+ ed.onSetProgressState.add(function(ed, b, ti) {
+ var co, id = ed.id, tb;
+
+ if (b) {
+ t.progressTimer = setTimeout(function() {
+ co = ed.getContainer();
+ co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild);
+ tb = DOM.get(ed.id + '_tbl');
+
+ DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}});
+ DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}});
+ }, ti || 0);
+ } else {
+ DOM.remove(id + '_blocker');
+ DOM.remove(id + '_progress');
+ clearTimeout(t.progressTimer);
+ }
+ });
+
+ DOM.loadCSS(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css");
+
+ if (s.skin_variant)
+ DOM.loadCSS(url + "/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css");
+ },
+
+ _isHighContrast : function() {
+ var actualColor, div = DOM.add(DOM.getRoot(), 'div', {'style': 'background-color: rgb(171,239,86);'});
+
+ actualColor = (DOM.getStyle(div, 'background-color', true) + '').toLowerCase().replace(/ /g, '');
+ DOM.remove(div);
+
+ return actualColor != 'rgb(171,239,86)' && actualColor != '#abef56';
+ },
+
+ createControl : function(n, cf) {
+ var cd, c;
+
+ if (c = cf.createControl(n))
+ return c;
+
+ switch (n) {
+ case "styleselect":
+ return this._createStyleSelect();
+
+ case "formatselect":
+ return this._createBlockFormats();
+
+ case "fontselect":
+ return this._createFontSelect();
+
+ case "fontsizeselect":
+ return this._createFontSizeSelect();
+
+ case "forecolor":
+ return this._createForeColorMenu();
+
+ case "backcolor":
+ return this._createBackColorMenu();
+ }
+
+ if ((cd = this.controls[n]))
+ return cf.createButton(n, {title : "advanced." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]});
+ },
+
+ execCommand : function(cmd, ui, val) {
+ var f = this['_' + cmd];
+
+ if (f) {
+ f.call(this, ui, val);
+ return true;
+ }
+
+ return false;
+ },
+
+ _importClasses : function(e) {
+ var ed = this.editor, ctrl = ed.controlManager.get('styleselect');
+
+ if (ctrl.getLength() == 0) {
+ each(ed.dom.getClasses(), function(o, idx) {
+ var name = 'style_' + idx, fmt;
+
+ fmt = {
+ inline : 'span',
+ attributes : {'class' : o['class']},
+ selector : '*'
+ };
+
+ ed.formatter.register(name, fmt);
+
+ ctrl.add(o['class'], name, {
+ style: function() {
+ return getPreviewCss(ed, fmt);
+ }
+ });
+ });
+ }
+ },
+
+ _createStyleSelect : function(n) {
+ var t = this, ed = t.editor, ctrlMan = ed.controlManager, ctrl;
+
+ // Setup style select box
+ ctrl = ctrlMan.createListBox('styleselect', {
+ title : 'advanced.style_select',
+ onselect : function(name) {
+ var matches, formatNames = [], removedFormat;
+
+ each(ctrl.items, function(item) {
+ formatNames.push(item.value);
+ });
+
+ ed.focus();
+ ed.undoManager.add();
+
+ // Toggle off the current format(s)
+ matches = ed.formatter.matchAll(formatNames);
+ tinymce.each(matches, function(match) {
+ if (!name || match == name) {
+ if (match)
+ ed.formatter.remove(match);
+
+ removedFormat = true;
+ }
+ });
+
+ if (!removedFormat)
+ ed.formatter.apply(name);
+
+ ed.undoManager.add();
+ ed.nodeChanged();
+
+ return false; // No auto select
+ }
+ });
+
+ // Handle specified format
+ ed.onPreInit.add(function() {
+ var counter = 0, formats = ed.getParam('style_formats');
+
+ if (formats) {
+ each(formats, function(fmt) {
+ var name, keys = 0;
+
+ each(fmt, function() {keys++;});
+
+ if (keys > 1) {
+ name = fmt.name = fmt.name || 'style_' + (counter++);
+ ed.formatter.register(name, fmt);
+ ctrl.add(fmt.title, name, {
+ style: function() {
+ return getPreviewCss(ed, fmt);
+ }
+ });
+ } else
+ ctrl.add(fmt.title);
+ });
+ } else {
+ each(ed.getParam('theme_advanced_styles', '', 'hash'), function(val, key) {
+ var name, fmt;
+
+ if (val) {
+ name = 'style_' + (counter++);
+ fmt = {
+ inline : 'span',
+ classes : val,
+ selector : '*'
+ };
+
+ ed.formatter.register(name, fmt);
+ ctrl.add(t.editor.translate(key), name, {
+ style: function() {
+ return getPreviewCss(ed, fmt);
+ }
+ });
+ }
+ });
+ }
+ });
+
+ // Auto import classes if the ctrl box is empty
+ if (ctrl.getLength() == 0) {
+ ctrl.onPostRender.add(function(ed, n) {
+ if (!ctrl.NativeListBox) {
+ Event.add(n.id + '_text', 'focus', t._importClasses, t);
+ Event.add(n.id + '_text', 'mousedown', t._importClasses, t);
+ Event.add(n.id + '_open', 'focus', t._importClasses, t);
+ Event.add(n.id + '_open', 'mousedown', t._importClasses, t);
+ } else
+ Event.add(n.id, 'focus', t._importClasses, t);
+ });
+ }
+
+ return ctrl;
+ },
+
+ _createFontSelect : function() {
+ var c, t = this, ed = t.editor;
+
+ c = ed.controlManager.createListBox('fontselect', {
+ title : 'advanced.fontdefault',
+ onselect : function(v) {
+ var cur = c.items[c.selectedIndex];
+
+ if (!v && cur) {
+ ed.execCommand('FontName', false, cur.value);
+ return;
+ }
+
+ ed.execCommand('FontName', false, v);
+
+ // Fake selection, execCommand will fire a nodeChange and update the selection
+ c.select(function(sv) {
+ return v == sv;
+ });
+
+ if (cur && cur.value == v) {
+ c.select(null);
+ }
+
+ return false; // No auto select
+ }
+ });
+
+ if (c) {
+ each(ed.getParam('theme_advanced_fonts', t.settings.theme_advanced_fonts, 'hash'), function(v, k) {
+ c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''});
+ });
+ }
+
+ return c;
+ },
+
+ _createFontSizeSelect : function() {
+ var t = this, ed = t.editor, c, i = 0, cl = [];
+
+ c = ed.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', onselect : function(v) {
+ var cur = c.items[c.selectedIndex];
+
+ if (!v && cur) {
+ cur = cur.value;
+
+ if (cur['class']) {
+ ed.formatter.toggle('fontsize_class', {value : cur['class']});
+ ed.undoManager.add();
+ ed.nodeChanged();
+ } else {
+ ed.execCommand('FontSize', false, cur.fontSize);
+ }
+
+ return;
+ }
+
+ if (v['class']) {
+ ed.focus();
+ ed.undoManager.add();
+ ed.formatter.toggle('fontsize_class', {value : v['class']});
+ ed.undoManager.add();
+ ed.nodeChanged();
+ } else
+ ed.execCommand('FontSize', false, v.fontSize);
+
+ // Fake selection, execCommand will fire a nodeChange and update the selection
+ c.select(function(sv) {
+ return v == sv;
+ });
+
+ if (cur && (cur.value.fontSize == v.fontSize || cur.value['class'] && cur.value['class'] == v['class'])) {
+ c.select(null);
+ }
+
+ return false; // No auto select
+ }});
+
+ if (c) {
+ each(t.settings.theme_advanced_font_sizes, function(v, k) {
+ var fz = v.fontSize;
+
+ if (fz >= 1 && fz <= 7)
+ fz = t.sizes[parseInt(fz) - 1] + 'pt';
+
+ c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))});
+ });
+ }
+
+ return c;
+ },
+
+ _createBlockFormats : function() {
+ var c, fmts = {
+ p : 'advanced.paragraph',
+ address : 'advanced.address',
+ pre : 'advanced.pre',
+ h1 : 'advanced.h1',
+ h2 : 'advanced.h2',
+ h3 : 'advanced.h3',
+ h4 : 'advanced.h4',
+ h5 : 'advanced.h5',
+ h6 : 'advanced.h6',
+ div : 'advanced.div',
+ blockquote : 'advanced.blockquote',
+ code : 'advanced.code',
+ dt : 'advanced.dt',
+ dd : 'advanced.dd',
+ samp : 'advanced.samp'
+ }, t = this;
+
+ c = t.editor.controlManager.createListBox('formatselect', {title : 'advanced.block', onselect : function(v) {
+ t.editor.execCommand('FormatBlock', false, v);
+ return false;
+ }});
+
+ if (c) {
+ each(t.editor.getParam('theme_advanced_blockformats', t.settings.theme_advanced_blockformats, 'hash'), function(v, k) {
+ c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v, style: function() {
+ return getPreviewCss(t.editor, {block: v});
+ }});
+ });
+ }
+
+ return c;
+ },
+
+ _createForeColorMenu : function() {
+ var c, t = this, s = t.settings, o = {}, v;
+
+ if (s.theme_advanced_more_colors) {
+ o.more_colors_func = function() {
+ t._mceColorPicker(0, {
+ color : c.value,
+ func : function(co) {
+ c.setColor(co);
+ }
+ });
+ };
+ }
+
+ if (v = s.theme_advanced_text_colors)
+ o.colors = v;
+
+ if (s.theme_advanced_default_foreground_color)
+ o.default_color = s.theme_advanced_default_foreground_color;
+
+ o.title = 'advanced.forecolor_desc';
+ o.cmd = 'ForeColor';
+ o.scope = this;
+
+ c = t.editor.controlManager.createColorSplitButton('forecolor', o);
+
+ return c;
+ },
+
+ _createBackColorMenu : function() {
+ var c, t = this, s = t.settings, o = {}, v;
+
+ if (s.theme_advanced_more_colors) {
+ o.more_colors_func = function() {
+ t._mceColorPicker(0, {
+ color : c.value,
+ func : function(co) {
+ c.setColor(co);
+ }
+ });
+ };
+ }
+
+ if (v = s.theme_advanced_background_colors)
+ o.colors = v;
+
+ if (s.theme_advanced_default_background_color)
+ o.default_color = s.theme_advanced_default_background_color;
+
+ o.title = 'advanced.backcolor_desc';
+ o.cmd = 'HiliteColor';
+ o.scope = this;
+
+ c = t.editor.controlManager.createColorSplitButton('backcolor', o);
+
+ return c;
+ },
+
+ renderUI : function(o) {
+ var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl;
+
+ if (ed.settings) {
+ ed.settings.aria_label = s.aria_label + ed.getLang('advanced.help_shortcut');
+ }
+
+ // TODO: ACC Should have an aria-describedby attribute which is user-configurable to describe what this field is actually for.
+ // Maybe actually inherit it from the original textara?
+ n = p = DOM.create('span', {role : 'application', 'aria-labelledby' : ed.id + '_voice', id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '') + (ed.settings.directionality == "rtl" ? ' mceRtl' : '')});
+ DOM.add(n, 'span', {'class': 'mceVoiceLabel', 'style': 'display:none;', id: ed.id + '_voice'}, s.aria_label);
+
+ if (!DOM.boxModel)
+ n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'});
+
+ n = sc = DOM.add(n, 'table', {role : "presentation", id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0});
+ n = tb = DOM.add(n, 'tbody');
+
+ switch ((s.theme_advanced_layout_manager || '').toLowerCase()) {
+ case "rowlayout":
+ ic = t._rowLayout(s, tb, o);
+ break;
+
+ case "customlayout":
+ ic = ed.execCallback("theme_advanced_custom_layout", s, tb, o, p);
+ break;
+
+ default:
+ ic = t._simpleLayout(s, tb, o, p);
+ }
+
+ n = o.targetNode;
+
+ // Add classes to first and last TRs
+ nl = sc.rows;
+ DOM.addClass(nl[0], 'mceFirst');
+ DOM.addClass(nl[nl.length - 1], 'mceLast');
+
+ // Add classes to first and last TDs
+ each(DOM.select('tr', tb), function(n) {
+ DOM.addClass(n.firstChild, 'mceFirst');
+ DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast');
+ });
+
+ if (DOM.get(s.theme_advanced_toolbar_container))
+ DOM.get(s.theme_advanced_toolbar_container).appendChild(p);
+ else
+ DOM.insertAfter(p, n);
+
+ Event.add(ed.id + '_path_row', 'click', function(e) {
+ e = e.target;
+
+ if (e.nodeName == 'A') {
+ t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1'));
+ return false;
+ }
+ });
+/*
+ if (DOM.get(ed.id + '_path_row')) {
+ Event.add(ed.id + '_tbl', 'mouseover', function(e) {
+ var re;
+
+ e = e.target;
+
+ if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) {
+ re = DOM.get(ed.id + '_path_row');
+ t.lastPath = re.innerHTML;
+ DOM.setHTML(re, e.parentNode.title);
+ }
+ });
+
+ Event.add(ed.id + '_tbl', 'mouseout', function(e) {
+ if (t.lastPath) {
+ DOM.setHTML(ed.id + '_path_row', t.lastPath);
+ t.lastPath = 0;
+ }
+ });
+ }
+*/
+
+ if (!ed.getParam('accessibility_focus'))
+ Event.add(DOM.add(p, 'a', {href : '#'}, '<!-- IE -->'), 'focus', function() {tinyMCE.get(ed.id).focus();});
+
+ if (s.theme_advanced_toolbar_location == 'external')
+ o.deltaHeight = 0;
+
+ t.deltaHeight = o.deltaHeight;
+ o.targetNode = null;
+
+ ed.onKeyDown.add(function(ed, evt) {
+ var DOM_VK_F10 = 121, DOM_VK_F11 = 122;
+
+ if (evt.altKey) {
+ if (evt.keyCode === DOM_VK_F10) {
+ // Make sure focus is given to toolbar in Safari.
+ // We can't do this in IE as it prevents giving focus to toolbar when editor is in a frame
+ if (tinymce.isWebKit) {
+ window.focus();
+ }
+ t.toolbarGroup.focus();
+ return Event.cancel(evt);
+ } else if (evt.keyCode === DOM_VK_F11) {
+ DOM.get(ed.id + '_path_row').focus();
+ return Event.cancel(evt);
+ }
+ }
+ });
+
+ // alt+0 is the UK recommended shortcut for accessing the list of access controls.
+ ed.addShortcut('alt+0', '', 'mceShortcuts', t);
+
+ return {
+ iframeContainer : ic,
+ editorContainer : ed.id + '_parent',
+ sizeContainer : sc,
+ deltaHeight : o.deltaHeight
+ };
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Advanced theme',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ }
+ },
+
+ resizeBy : function(dw, dh) {
+ var e = DOM.get(this.editor.id + '_ifr');
+
+ this.resizeTo(e.clientWidth + dw, e.clientHeight + dh);
+ },
+
+ resizeTo : function(w, h, store) {
+ var ed = this.editor, s = this.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr');
+
+ // Boundery fix box
+ w = Math.max(s.theme_advanced_resizing_min_width || 100, w);
+ h = Math.max(s.theme_advanced_resizing_min_height || 100, h);
+ w = Math.min(s.theme_advanced_resizing_max_width || 0xFFFF, w);
+ h = Math.min(s.theme_advanced_resizing_max_height || 0xFFFF, h);
+
+ // Resize iframe and container
+ DOM.setStyle(e, 'height', '');
+ DOM.setStyle(ifr, 'height', h);
+
+ if (s.theme_advanced_resize_horizontal) {
+ DOM.setStyle(e, 'width', '');
+ DOM.setStyle(ifr, 'width', w);
+
+ // Make sure that the size is never smaller than the over all ui
+ if (w < e.clientWidth) {
+ w = e.clientWidth;
+ DOM.setStyle(ifr, 'width', e.clientWidth);
+ }
+ }
+
+ // Store away the size
+ if (store && s.theme_advanced_resizing_use_cookie) {
+ Cookie.setHash("TinyMCE_" + ed.id + "_size", {
+ cw : w,
+ ch : h
+ });
+ }
+ },
+
+ destroy : function() {
+ var id = this.editor.id;
+
+ Event.clear(id + '_resize');
+ Event.clear(id + '_path_row');
+ Event.clear(id + '_external_close');
+ },
+
+ // Internal functions
+
+ _simpleLayout : function(s, tb, o, p) {
+ var t = this, ed = t.editor, lo = s.theme_advanced_toolbar_location, sl = s.theme_advanced_statusbar_location, n, ic, etb, c;
+
+ if (s.readonly) {
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'});
+ return ic;
+ }
+
+ // Create toolbar container at top
+ if (lo == 'top')
+ t._addToolbars(tb, o);
+
+ // Create external toolbar
+ if (lo == 'external') {
+ n = c = DOM.create('div', {style : 'position:relative'});
+ n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'});
+ DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'});
+ n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0});
+ etb = DOM.add(n, 'tbody');
+
+ if (p.firstChild.className == 'mceOldBoxModel')
+ p.firstChild.appendChild(c);
+ else
+ p.insertBefore(c, p.firstChild);
+
+ t._addToolbars(etb, o);
+
+ ed.onMouseUp.add(function() {
+ var e = DOM.get(ed.id + '_external');
+ DOM.show(e);
+
+ DOM.hide(lastExtID);
+
+ var f = Event.add(ed.id + '_external_close', 'click', function() {
+ DOM.hide(ed.id + '_external');
+ Event.remove(ed.id + '_external_close', 'click', f);
+ return false;
+ });
+
+ DOM.show(e);
+ DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1);
+
+ // Fixes IE rendering bug
+ DOM.hide(e);
+ DOM.show(e);
+ e.style.filter = '';
+
+ lastExtID = ed.id + '_external';
+
+ e = null;
+ });
+ }
+
+ if (sl == 'top')
+ t._addStatusBar(tb, o);
+
+ // Create iframe container
+ if (!s.theme_advanced_toolbar_container) {
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'});
+ }
+
+ // Create toolbar container at bottom
+ if (lo == 'bottom')
+ t._addToolbars(tb, o);
+
+ if (sl == 'bottom')
+ t._addStatusBar(tb, o);
+
+ return ic;
+ },
+
+ _rowLayout : function(s, tb, o) {
+ var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a;
+
+ dc = s.theme_advanced_containers_default_class || '';
+ da = s.theme_advanced_containers_default_align || 'center';
+
+ each(explode(s.theme_advanced_containers || ''), function(c, i) {
+ var v = s['theme_advanced_container_' + c] || '';
+
+ switch (c.toLowerCase()) {
+ case 'mceeditor':
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'});
+ break;
+
+ case 'mceelementpath':
+ t._addStatusBar(tb, o);
+ break;
+
+ default:
+ a = (s['theme_advanced_container_' + c + '_align'] || da).toLowerCase();
+ a = 'mce' + t._ufirst(a);
+
+ n = DOM.add(DOM.add(tb, 'tr'), 'td', {
+ 'class' : 'mceToolbar ' + (s['theme_advanced_container_' + c + '_class'] || dc) + ' ' + a || da
+ });
+
+ to = cf.createToolbar("toolbar" + i);
+ t._addControls(v, to);
+ DOM.setHTML(n, to.renderHTML());
+ o.deltaHeight -= s.theme_advanced_row_height;
+ }
+ });
+
+ return ic;
+ },
+
+ _addControls : function(v, tb) {
+ var t = this, s = t.settings, di, cf = t.editor.controlManager;
+
+ if (s.theme_advanced_disable && !t._disabled) {
+ di = {};
+
+ each(explode(s.theme_advanced_disable), function(v) {
+ di[v] = 1;
+ });
+
+ t._disabled = di;
+ } else
+ di = t._disabled;
+
+ each(explode(v), function(n) {
+ var c;
+
+ if (di && di[n])
+ return;
+
+ // Compatiblity with 2.x
+ if (n == 'tablecontrols') {
+ each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) {
+ n = t.createControl(n, cf);
+
+ if (n)
+ tb.add(n);
+ });
+
+ return;
+ }
+
+ c = t.createControl(n, cf);
+
+ if (c)
+ tb.add(c);
+ });
+ },
+
+ _addToolbars : function(c, o) {
+ var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, h = [], a, toolbarGroup, toolbarsExist = false;
+
+ toolbarGroup = cf.createToolbarGroup('toolbargroup', {
+ 'name': ed.getLang('advanced.toolbar'),
+ 'tab_focus_toolbar':ed.getParam('theme_advanced_tab_focus_toolbar')
+ });
+
+ t.toolbarGroup = toolbarGroup;
+
+ a = s.theme_advanced_toolbar_align.toLowerCase();
+ a = 'mce' + t._ufirst(a);
+
+ n = DOM.add(DOM.add(c, 'tr', {role: 'presentation'}), 'td', {'class' : 'mceToolbar ' + a, "role":"toolbar"});
+
+ // Create toolbar and add the controls
+ for (i=1; (v = s['theme_advanced_buttons' + i]); i++) {
+ toolbarsExist = true;
+ tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i});
+
+ if (s['theme_advanced_buttons' + i + '_add'])
+ v += ',' + s['theme_advanced_buttons' + i + '_add'];
+
+ if (s['theme_advanced_buttons' + i + '_add_before'])
+ v = s['theme_advanced_buttons' + i + '_add_before'] + ',' + v;
+
+ t._addControls(v, tb);
+ toolbarGroup.add(tb);
+
+ o.deltaHeight -= s.theme_advanced_row_height;
+ }
+ // Handle case when there are no toolbar buttons and ensure editor height is adjusted accordingly
+ if (!toolbarsExist)
+ o.deltaHeight -= s.theme_advanced_row_height;
+ h.push(toolbarGroup.renderHTML());
+ h.push(DOM.createHTML('a', {href : '#', accesskey : 'z', title : ed.getLang("advanced.toolbar_focus"), onfocus : 'tinyMCE.getInstanceById(\'' + ed.id + '\').focus();'}, '<!-- IE -->'));
+ DOM.setHTML(n, h.join(''));
+ },
+
+ _addStatusBar : function(tb, o) {
+ var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td;
+
+ n = DOM.add(tb, 'tr');
+ n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'});
+ n = DOM.add(n, 'div', {id : ed.id + '_path_row', 'role': 'group', 'aria-labelledby': ed.id + '_path_voice'});
+ if (s.theme_advanced_path) {
+ DOM.add(n, 'span', {id: ed.id + '_path_voice'}, ed.translate('advanced.path'));
+ DOM.add(n, 'span', {}, ': ');
+ } else {
+ DOM.add(n, 'span', {}, '&#160;');
+ }
+
+
+ if (s.theme_advanced_resizing) {
+ DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize', tabIndex:"-1"});
+
+ if (s.theme_advanced_resizing_use_cookie) {
+ ed.onPostRender.add(function() {
+ var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl');
+
+ if (!o)
+ return;
+
+ t.resizeTo(o.cw, o.ch);
+ });
+ }
+
+ ed.onPostRender.add(function() {
+ Event.add(ed.id + '_resize', 'click', function(e) {
+ e.preventDefault();
+ });
+
+ Event.add(ed.id + '_resize', 'mousedown', function(e) {
+ var mouseMoveHandler1, mouseMoveHandler2,
+ mouseUpHandler1, mouseUpHandler2,
+ startX, startY, startWidth, startHeight, width, height, ifrElm;
+
+ function resizeOnMove(e) {
+ e.preventDefault();
+
+ width = startWidth + (e.screenX - startX);
+ height = startHeight + (e.screenY - startY);
+
+ t.resizeTo(width, height);
+ };
+
+ function endResize(e) {
+ // Stop listening
+ Event.remove(DOM.doc, 'mousemove', mouseMoveHandler1);
+ Event.remove(ed.getDoc(), 'mousemove', mouseMoveHandler2);
+ Event.remove(DOM.doc, 'mouseup', mouseUpHandler1);
+ Event.remove(ed.getDoc(), 'mouseup', mouseUpHandler2);
+
+ width = startWidth + (e.screenX - startX);
+ height = startHeight + (e.screenY - startY);
+ t.resizeTo(width, height, true);
+
+ ed.nodeChanged();
+ };
+
+ e.preventDefault();
+
+ // Get the current rect size
+ startX = e.screenX;
+ startY = e.screenY;
+ ifrElm = DOM.get(t.editor.id + '_ifr');
+ startWidth = width = ifrElm.clientWidth;
+ startHeight = height = ifrElm.clientHeight;
+
+ // Register envent handlers
+ mouseMoveHandler1 = Event.add(DOM.doc, 'mousemove', resizeOnMove);
+ mouseMoveHandler2 = Event.add(ed.getDoc(), 'mousemove', resizeOnMove);
+ mouseUpHandler1 = Event.add(DOM.doc, 'mouseup', endResize);
+ mouseUpHandler2 = Event.add(ed.getDoc(), 'mouseup', endResize);
+ });
+ });
+ }
+
+ o.deltaHeight -= 21;
+ n = tb = null;
+ },
+
+ _updateUndoStatus : function(ed) {
+ var cm = ed.controlManager, um = ed.undoManager;
+
+ cm.setDisabled('undo', !um.hasUndo() && !um.typing);
+ cm.setDisabled('redo', !um.hasRedo());
+ },
+
+ _nodeChanged : function(ed, cm, n, co, ob) {
+ var t = this, p, de = 0, v, c, s = t.settings, cl, fz, fn, fc, bc, formatNames, matches;
+
+ tinymce.each(t.stateControls, function(c) {
+ cm.setActive(c, ed.queryCommandState(t.controls[c][1]));
+ });
+
+ function getParent(name) {
+ var i, parents = ob.parents, func = name;
+
+ if (typeof(name) == 'string') {
+ func = function(node) {
+ return node.nodeName == name;
+ };
+ }
+
+ for (i = 0; i < parents.length; i++) {
+ if (func(parents[i]))
+ return parents[i];
+ }
+ };
+
+ cm.setActive('visualaid', ed.hasVisual);
+ t._updateUndoStatus(ed);
+ cm.setDisabled('outdent', !ed.queryCommandState('Outdent'));
+
+ p = getParent('A');
+ if (c = cm.get('link')) {
+ c.setDisabled((!p && co) || (p && !p.href));
+ c.setActive(!!p && (!p.name && !p.id));
+ }
+
+ if (c = cm.get('unlink')) {
+ c.setDisabled(!p && co);
+ c.setActive(!!p && !p.name && !p.id);
+ }
+
+ if (c = cm.get('anchor')) {
+ c.setActive(!co && !!p && (p.name || (p.id && !p.href)));
+ }
+
+ p = getParent('IMG');
+ if (c = cm.get('image'))
+ c.setActive(!co && !!p && n.className.indexOf('mceItem') == -1);
+
+ if (c = cm.get('styleselect')) {
+ t._importClasses();
+
+ formatNames = [];
+ each(c.items, function(item) {
+ formatNames.push(item.value);
+ });
+
+ matches = ed.formatter.matchAll(formatNames);
+ c.select(matches[0]);
+ tinymce.each(matches, function(match, index) {
+ if (index > 0) {
+ c.mark(match);
+ }
+ });
+ }
+
+ if (c = cm.get('formatselect')) {
+ p = getParent(ed.dom.isBlock);
+
+ if (p)
+ c.select(p.nodeName.toLowerCase());
+ }
+
+ // Find out current fontSize, fontFamily and fontClass
+ getParent(function(n) {
+ if (n.nodeName === 'SPAN') {
+ if (!cl && n.className)
+ cl = n.className;
+ }
+
+ if (ed.dom.is(n, s.theme_advanced_font_selector)) {
+ if (!fz && n.style.fontSize)
+ fz = n.style.fontSize;
+
+ if (!fn && n.style.fontFamily)
+ fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase();
+
+ if (!fc && n.style.color)
+ fc = n.style.color;
+
+ if (!bc && n.style.backgroundColor)
+ bc = n.style.backgroundColor;
+ }
+
+ return false;
+ });
+
+ if (c = cm.get('fontselect')) {
+ c.select(function(v) {
+ return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn;
+ });
+ }
+
+ // Select font size
+ if (c = cm.get('fontsizeselect')) {
+ // Use computed style
+ if (s.theme_advanced_runtime_fontsize && !fz && !cl)
+ fz = ed.dom.getStyle(n, 'fontSize', true);
+
+ c.select(function(v) {
+ if (v.fontSize && v.fontSize === fz)
+ return true;
+
+ if (v['class'] && v['class'] === cl)
+ return true;
+ });
+ }
+
+ if (s.theme_advanced_show_current_color) {
+ function updateColor(controlId, color) {
+ if (c = cm.get(controlId)) {
+ if (!color)
+ color = c.settings.default_color;
+ if (color !== c.value) {
+ c.displayColor(color);
+ }
+ }
+ }
+ updateColor('forecolor', fc);
+ updateColor('backcolor', bc);
+ }
+
+ if (s.theme_advanced_show_current_color) {
+ function updateColor(controlId, color) {
+ if (c = cm.get(controlId)) {
+ if (!color)
+ color = c.settings.default_color;
+ if (color !== c.value) {
+ c.displayColor(color);
+ }
+ }
+ };
+
+ updateColor('forecolor', fc);
+ updateColor('backcolor', bc);
+ }
+
+ if (s.theme_advanced_path && s.theme_advanced_statusbar_location) {
+ p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'});
+
+ if (t.statusKeyboardNavigation) {
+ t.statusKeyboardNavigation.destroy();
+ t.statusKeyboardNavigation = null;
+ }
+
+ DOM.setHTML(p, '');
+
+ getParent(function(n) {
+ var na = n.nodeName.toLowerCase(), u, pi, ti = '';
+
+ // Ignore non element and bogus/hidden elements
+ if (n.nodeType != 1 || na === 'br' || n.getAttribute('data-mce-bogus') || DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved'))
+ return;
+
+ // Handle prefix
+ if (tinymce.isIE && n.scopeName !== 'HTML' && n.scopeName)
+ na = n.scopeName + ':' + na;
+
+ // Remove internal prefix
+ na = na.replace(/mce\:/g, '');
+
+ // Handle node name
+ switch (na) {
+ case 'b':
+ na = 'strong';
+ break;
+
+ case 'i':
+ na = 'em';
+ break;
+
+ case 'img':
+ if (v = DOM.getAttrib(n, 'src'))
+ ti += 'src: ' + v + ' ';
+
+ break;
+
+ case 'a':
+ if (v = DOM.getAttrib(n, 'name')) {
+ ti += 'name: ' + v + ' ';
+ na += '#' + v;
+ }
+
+ if (v = DOM.getAttrib(n, 'href'))
+ ti += 'href: ' + v + ' ';
+
+ break;
+
+ case 'font':
+ if (v = DOM.getAttrib(n, 'face'))
+ ti += 'font: ' + v + ' ';
+
+ if (v = DOM.getAttrib(n, 'size'))
+ ti += 'size: ' + v + ' ';
+
+ if (v = DOM.getAttrib(n, 'color'))
+ ti += 'color: ' + v + ' ';
+
+ break;
+
+ case 'span':
+ if (v = DOM.getAttrib(n, 'style'))
+ ti += 'style: ' + v + ' ';
+
+ break;
+ }
+
+ if (v = DOM.getAttrib(n, 'id'))
+ ti += 'id: ' + v + ' ';
+
+ if (v = n.className) {
+ v = v.replace(/\b\s*(webkit|mce|Apple-)\w+\s*\b/g, '');
+
+ if (v) {
+ ti += 'class: ' + v + ' ';
+
+ if (ed.dom.isBlock(n) || na == 'img' || na == 'span')
+ na += '.' + v;
+ }
+ }
+
+ na = na.replace(/(html:)/g, '');
+ na = {name : na, node : n, title : ti};
+ t.onResolveName.dispatch(t, na);
+ ti = na.title;
+ na = na.name;
+
+ //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');";
+ pi = DOM.create('a', {'href' : "javascript:;", role: 'button', onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na);
+
+ if (p.hasChildNodes()) {
+ p.insertBefore(DOM.create('span', {'aria-hidden': 'true'}, '\u00a0\u00bb '), p.firstChild);
+ p.insertBefore(pi, p.firstChild);
+ } else
+ p.appendChild(pi);
+ }, ed.getBody());
+
+ if (DOM.select('a', p).length > 0) {
+ t.statusKeyboardNavigation = new tinymce.ui.KeyboardNavigation({
+ root: ed.id + "_path_row",
+ items: DOM.select('a', p),
+ excludeFromTabOrder: true,
+ onCancel: function() {
+ ed.focus();
+ }
+ }, DOM);
+ }
+ }
+ },
+
+ // Commands gets called by execCommand
+
+ _sel : function(v) {
+ this.editor.execCommand('mceSelectNodeDepth', false, v);
+ },
+
+ _mceInsertAnchor : function(ui, v) {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/anchor.htm',
+ width : 320 + parseInt(ed.getLang('advanced.anchor_delta_width', 0)),
+ height : 90 + parseInt(ed.getLang('advanced.anchor_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceCharMap : function() {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/charmap.htm',
+ width : 550 + parseInt(ed.getLang('advanced.charmap_delta_width', 0)),
+ height : 265 + parseInt(ed.getLang('advanced.charmap_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceHelp : function() {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/about.htm',
+ width : 480,
+ height : 380,
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceShortcuts : function() {
+ var ed = this.editor;
+ ed.windowManager.open({
+ url: this.url + '/shortcuts.htm',
+ width: 480,
+ height: 380,
+ inline: true
+ }, {
+ theme_url: this.url
+ });
+ },
+
+ _mceColorPicker : function(u, v) {
+ var ed = this.editor;
+
+ v = v || {};
+
+ ed.windowManager.open({
+ url : this.url + '/color_picker.htm',
+ width : 375 + parseInt(ed.getLang('advanced.colorpicker_delta_width', 0)),
+ height : 250 + parseInt(ed.getLang('advanced.colorpicker_delta_height', 0)),
+ close_previous : false,
+ inline : true
+ }, {
+ input_color : v.color,
+ func : v.func,
+ theme_url : this.url
+ });
+ },
+
+ _mceCodeEditor : function(ui, val) {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/source_editor.htm',
+ width : parseInt(ed.getParam("theme_advanced_source_editor_width", 720)),
+ height : parseInt(ed.getParam("theme_advanced_source_editor_height", 580)),
+ inline : true,
+ resizable : true,
+ maximizable : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceImage : function(ui, val) {
+ var ed = this.editor;
+
+ // Internal image object like a flash placeholder
+ if (ed.dom.getAttrib(ed.selection.getNode(), 'class', '').indexOf('mceItem') != -1)
+ return;
+
+ ed.windowManager.open({
+ url : this.url + '/image.htm',
+ width : 355 + parseInt(ed.getLang('advanced.image_delta_width', 0)),
+ height : 275 + parseInt(ed.getLang('advanced.image_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceLink : function(ui, val) {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/link.htm',
+ width : 310 + parseInt(ed.getLang('advanced.link_delta_width', 0)),
+ height : 200 + parseInt(ed.getLang('advanced.link_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceNewDocument : function() {
+ var ed = this.editor;
+
+ ed.windowManager.confirm('advanced.newdocument', function(s) {
+ if (s)
+ ed.execCommand('mceSetContent', false, '');
+ });
+ },
+
+ _mceForeColor : function() {
+ var t = this;
+
+ this._mceColorPicker(0, {
+ color: t.fgColor,
+ func : function(co) {
+ t.fgColor = co;
+ t.editor.execCommand('ForeColor', false, co);
+ }
+ });
+ },
+
+ _mceBackColor : function() {
+ var t = this;
+
+ this._mceColorPicker(0, {
+ color: t.bgColor,
+ func : function(co) {
+ t.bgColor = co;
+ t.editor.execCommand('HiliteColor', false, co);
+ }
+ });
+ },
+
+ _ufirst : function(s) {
+ return s.substring(0, 1).toUpperCase() + s.substring(1);
+ }
+ });
+
+ tinymce.ThemeManager.add('advanced', tinymce.themes.AdvancedTheme);
+}(tinymce));
diff --git a/src/wp-includes/js/tinymce/themes/advanced/image.htm b/src/wp-includes/js/tinymce/themes/advanced/image.htm
new file mode 100644
index 0000000000..1a3d72e258
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/image.htm
@@ -0,0 +1,80 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.image_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/image.js?ver=358-20121205"></script>
+</head>
+<body id="image" style="display: none">
+<form onsubmit="ImageDialog.update();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advanced_dlg.image_title}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="nowrap"><label for="src">{#advanced_dlg.image_src}</label></td>
+ <td><table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="src" name="src" type="text" class="mceFocus" value="" style="width: 200px" onchange="ImageDialog.getImageData();" /></td>
+ <td id="srcbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="image_list">{#advanced_dlg.image_list}</label></td>
+ <td><select id="image_list" name="image_list" onchange="document.getElementById('src').value=this.options[this.selectedIndex].value;document.getElementById('alt').value=this.options[this.selectedIndex].text;"></select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="alt">{#advanced_dlg.image_alt}</label></td>
+ <td><input id="alt" name="alt" type="text" value="" style="width: 200px" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="align">{#advanced_dlg.image_align}</label></td>
+ <td><select id="align" name="align" onchange="ImageDialog.updateStyle();">
+ <option value="">{#not_set}</option>
+ <option value="baseline">{#advanced_dlg.image_align_baseline}</option>
+ <option value="top">{#advanced_dlg.image_align_top}</option>
+ <option value="middle">{#advanced_dlg.image_align_middle}</option>
+ <option value="bottom">{#advanced_dlg.image_align_bottom}</option>
+ <option value="text-top">{#advanced_dlg.image_align_texttop}</option>
+ <option value="text-bottom">{#advanced_dlg.image_align_textbottom}</option>
+ <option value="left">{#advanced_dlg.image_align_left}</option>
+ <option value="right">{#advanced_dlg.image_align_right}</option>
+ </select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="width">{#advanced_dlg.image_dimensions}</label></td>
+ <td><input id="width" name="width" type="text" value="" size="3" maxlength="5" />
+ x
+ <input id="height" name="height" type="text" value="" size="3" maxlength="5" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="border">{#advanced_dlg.image_border}</label></td>
+ <td><input id="border" name="border" type="text" value="" size="3" maxlength="3" onchange="ImageDialog.updateStyle();" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="vspace">{#advanced_dlg.image_vspace}</label></td>
+ <td><input id="vspace" name="vspace" type="text" value="" size="3" maxlength="3" onchange="ImageDialog.updateStyle();" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="hspace">{#advanced_dlg.image_hspace}</label></td>
+ <td><input id="hspace" name="hspace" type="text" value="" size="3" maxlength="3" onchange="ImageDialog.updateStyle();" /></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/colorpicker.jpg b/src/wp-includes/js/tinymce/themes/advanced/img/colorpicker.jpg
new file mode 100644
index 0000000000..b1a377aba7
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/colorpicker.jpg
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/flash.gif b/src/wp-includes/js/tinymce/themes/advanced/img/flash.gif
new file mode 100644
index 0000000000..dec3f7c702
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/flash.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/gotmoxie.png b/src/wp-includes/js/tinymce/themes/advanced/img/gotmoxie.png
new file mode 100644
index 0000000000..1af3e3e6c5
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/gotmoxie.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/icons.gif b/src/wp-includes/js/tinymce/themes/advanced/img/icons.gif
new file mode 100644
index 0000000000..ca22249018
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/icons.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/iframe.gif b/src/wp-includes/js/tinymce/themes/advanced/img/iframe.gif
new file mode 100644
index 0000000000..410c7ad084
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/iframe.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/pagebreak.gif b/src/wp-includes/js/tinymce/themes/advanced/img/pagebreak.gif
new file mode 100644
index 0000000000..acdf4085f3
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/pagebreak.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/quicktime.gif b/src/wp-includes/js/tinymce/themes/advanced/img/quicktime.gif
new file mode 100644
index 0000000000..8f10e7aa6b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/quicktime.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/realmedia.gif b/src/wp-includes/js/tinymce/themes/advanced/img/realmedia.gif
new file mode 100644
index 0000000000..fdfe0b9ac0
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/realmedia.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/shockwave.gif b/src/wp-includes/js/tinymce/themes/advanced/img/shockwave.gif
new file mode 100644
index 0000000000..9314d04470
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/shockwave.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/trans.gif b/src/wp-includes/js/tinymce/themes/advanced/img/trans.gif
new file mode 100644
index 0000000000..388486517f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/trans.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/video.gif b/src/wp-includes/js/tinymce/themes/advanced/img/video.gif
new file mode 100644
index 0000000000..3570104077
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/video.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/img/windowsmedia.gif b/src/wp-includes/js/tinymce/themes/advanced/img/windowsmedia.gif
new file mode 100644
index 0000000000..ab50f2d887
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/img/windowsmedia.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/about.js b/src/wp-includes/js/tinymce/themes/advanced/js/about.js
new file mode 100644
index 0000000000..daf4909ad2
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/about.js
@@ -0,0 +1,73 @@
+tinyMCEPopup.requireLangPack();
+
+function init() {
+ var ed, tcont;
+
+ tinyMCEPopup.resizeToInnerSize();
+ ed = tinyMCEPopup.editor;
+
+ // Give FF some time
+ window.setTimeout(insertHelpIFrame, 10);
+
+ tcont = document.getElementById('plugintablecontainer');
+ document.getElementById('plugins_tab').style.display = 'none';
+
+ var html = "";
+ html += '<table id="plugintable">';
+ html += '<thead>';
+ html += '<tr>';
+ html += '<td>' + ed.getLang('advanced_dlg.about_plugin') + '</td>';
+ html += '<td>' + ed.getLang('advanced_dlg.about_author') + '</td>';
+ html += '<td>' + ed.getLang('advanced_dlg.about_version') + '</td>';
+ html += '</tr>';
+ html += '</thead>';
+ html += '<tbody>';
+
+ tinymce.each(ed.plugins, function(p, n) {
+ var info;
+
+ if (!p.getInfo)
+ return;
+
+ html += '<tr>';
+
+ info = p.getInfo();
+
+ if (info.infourl != null && info.infourl != '')
+ html += '<td width="50%" title="' + n + '"><a href="' + info.infourl + '" target="_blank">' + info.longname + '</a></td>';
+ else
+ html += '<td width="50%" title="' + n + '">' + info.longname + '</td>';
+
+ if (info.authorurl != null && info.authorurl != '')
+ html += '<td width="35%"><a href="' + info.authorurl + '" target="_blank">' + info.author + '</a></td>';
+ else
+ html += '<td width="35%">' + info.author + '</td>';
+
+ html += '<td width="15%">' + info.version + '</td>';
+ html += '</tr>';
+
+ document.getElementById('plugins_tab').style.display = '';
+
+ });
+
+ html += '</tbody>';
+ html += '</table>';
+
+ tcont.innerHTML = html;
+
+ tinyMCEPopup.dom.get('version').innerHTML = tinymce.majorVersion + "." + tinymce.minorVersion;
+ tinyMCEPopup.dom.get('date').innerHTML = tinymce.releaseDate;
+}
+
+function insertHelpIFrame() {
+ var html;
+
+ if (tinyMCEPopup.getParam('docs_url')) {
+ html = '<iframe width="100%" height="300" src="' + tinyMCEPopup.editor.baseURI.toAbsolute(tinyMCEPopup.getParam('docs_url')) + '"></iframe>';
+ document.getElementById('iframecontainer').innerHTML = html;
+ document.getElementById('help_tab').style.display = 'block';
+ document.getElementById('help_tab').setAttribute("aria-hidden", "false");
+ }
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/anchor.js b/src/wp-includes/js/tinymce/themes/advanced/js/anchor.js
new file mode 100644
index 0000000000..a3a018635b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/anchor.js
@@ -0,0 +1,56 @@
+tinyMCEPopup.requireLangPack();
+
+var AnchorDialog = {
+ init : function(ed) {
+ var action, elm, f = document.forms[0];
+
+ this.editor = ed;
+ elm = ed.dom.getParent(ed.selection.getNode(), 'A');
+ v = ed.dom.getAttrib(elm, 'name') || ed.dom.getAttrib(elm, 'id');
+
+ if (v) {
+ this.action = 'update';
+ f.anchorName.value = v;
+ }
+
+ f.insert.value = ed.getLang(elm ? 'update' : 'insert');
+ },
+
+ update : function() {
+ var ed = this.editor, elm, name = document.forms[0].anchorName.value, attribName;
+
+ if (!name || !/^[a-z][a-z0-9\-\_:\.]*$/i.test(name)) {
+ tinyMCEPopup.alert('advanced_dlg.anchor_invalid');
+ return;
+ }
+
+ tinyMCEPopup.restoreSelection();
+
+ if (this.action != 'update')
+ ed.selection.collapse(1);
+
+ var aRule = ed.schema.getElementRule('a');
+ if (!aRule || aRule.attributes.name) {
+ attribName = 'name';
+ } else {
+ attribName = 'id';
+ }
+
+ elm = ed.dom.getParent(ed.selection.getNode(), 'A');
+ if (elm) {
+ elm.setAttribute(attribName, name);
+ elm[attribName] = name;
+ ed.undoManager.add();
+ } else {
+ // create with zero-sized nbsp so that in Webkit where anchor is on last line by itself caret cannot be placed after it
+ var attrs = {'class' : 'mceItemAnchor'};
+ attrs[attribName] = name;
+ ed.execCommand('mceInsertContent', 0, ed.dom.createHTML('a', attrs, '\uFEFF'));
+ ed.nodeChanged();
+ }
+
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.onInit.add(AnchorDialog.init, AnchorDialog);
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/charmap.js b/src/wp-includes/js/tinymce/themes/advanced/js/charmap.js
new file mode 100644
index 0000000000..cbb4172bac
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/charmap.js
@@ -0,0 +1,363 @@
+/**
+ * charmap.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+tinyMCEPopup.requireLangPack();
+
+var charmap = [
+ ['&nbsp;', '&#160;', true, 'no-break space'],
+ ['&amp;', '&#38;', true, 'ampersand'],
+ ['&quot;', '&#34;', true, 'quotation mark'],
+// finance
+ ['&cent;', '&#162;', true, 'cent sign'],
+ ['&euro;', '&#8364;', true, 'euro sign'],
+ ['&pound;', '&#163;', true, 'pound sign'],
+ ['&yen;', '&#165;', true, 'yen sign'],
+// signs
+ ['&copy;', '&#169;', true, 'copyright sign'],
+ ['&reg;', '&#174;', true, 'registered sign'],
+ ['&trade;', '&#8482;', true, 'trade mark sign'],
+ ['&permil;', '&#8240;', true, 'per mille sign'],
+ ['&micro;', '&#181;', true, 'micro sign'],
+ ['&middot;', '&#183;', true, 'middle dot'],
+ ['&bull;', '&#8226;', true, 'bullet'],
+ ['&hellip;', '&#8230;', true, 'three dot leader'],
+ ['&prime;', '&#8242;', true, 'minutes / feet'],
+ ['&Prime;', '&#8243;', true, 'seconds / inches'],
+ ['&sect;', '&#167;', true, 'section sign'],
+ ['&para;', '&#182;', true, 'paragraph sign'],
+ ['&szlig;', '&#223;', true, 'sharp s / ess-zed'],
+// quotations
+ ['&lsaquo;', '&#8249;', true, 'single left-pointing angle quotation mark'],
+ ['&rsaquo;', '&#8250;', true, 'single right-pointing angle quotation mark'],
+ ['&laquo;', '&#171;', true, 'left pointing guillemet'],
+ ['&raquo;', '&#187;', true, 'right pointing guillemet'],
+ ['&lsquo;', '&#8216;', true, 'left single quotation mark'],
+ ['&rsquo;', '&#8217;', true, 'right single quotation mark'],
+ ['&ldquo;', '&#8220;', true, 'left double quotation mark'],
+ ['&rdquo;', '&#8221;', true, 'right double quotation mark'],
+ ['&sbquo;', '&#8218;', true, 'single low-9 quotation mark'],
+ ['&bdquo;', '&#8222;', true, 'double low-9 quotation mark'],
+ ['&lt;', '&#60;', true, 'less-than sign'],
+ ['&gt;', '&#62;', true, 'greater-than sign'],
+ ['&le;', '&#8804;', true, 'less-than or equal to'],
+ ['&ge;', '&#8805;', true, 'greater-than or equal to'],
+ ['&ndash;', '&#8211;', true, 'en dash'],
+ ['&mdash;', '&#8212;', true, 'em dash'],
+ ['&macr;', '&#175;', true, 'macron'],
+ ['&oline;', '&#8254;', true, 'overline'],
+ ['&curren;', '&#164;', true, 'currency sign'],
+ ['&brvbar;', '&#166;', true, 'broken bar'],
+ ['&uml;', '&#168;', true, 'diaeresis'],
+ ['&iexcl;', '&#161;', true, 'inverted exclamation mark'],
+ ['&iquest;', '&#191;', true, 'turned question mark'],
+ ['&circ;', '&#710;', true, 'circumflex accent'],
+ ['&tilde;', '&#732;', true, 'small tilde'],
+ ['&deg;', '&#176;', true, 'degree sign'],
+ ['&minus;', '&#8722;', true, 'minus sign'],
+ ['&plusmn;', '&#177;', true, 'plus-minus sign'],
+ ['&divide;', '&#247;', true, 'division sign'],
+ ['&frasl;', '&#8260;', true, 'fraction slash'],
+ ['&times;', '&#215;', true, 'multiplication sign'],
+ ['&sup1;', '&#185;', true, 'superscript one'],
+ ['&sup2;', '&#178;', true, 'superscript two'],
+ ['&sup3;', '&#179;', true, 'superscript three'],
+ ['&frac14;', '&#188;', true, 'fraction one quarter'],
+ ['&frac12;', '&#189;', true, 'fraction one half'],
+ ['&frac34;', '&#190;', true, 'fraction three quarters'],
+// math / logical
+ ['&fnof;', '&#402;', true, 'function / florin'],
+ ['&int;', '&#8747;', true, 'integral'],
+ ['&sum;', '&#8721;', true, 'n-ary sumation'],
+ ['&infin;', '&#8734;', true, 'infinity'],
+ ['&radic;', '&#8730;', true, 'square root'],
+ ['&sim;', '&#8764;', false,'similar to'],
+ ['&cong;', '&#8773;', false,'approximately equal to'],
+ ['&asymp;', '&#8776;', true, 'almost equal to'],
+ ['&ne;', '&#8800;', true, 'not equal to'],
+ ['&equiv;', '&#8801;', true, 'identical to'],
+ ['&isin;', '&#8712;', false,'element of'],
+ ['&notin;', '&#8713;', false,'not an element of'],
+ ['&ni;', '&#8715;', false,'contains as member'],
+ ['&prod;', '&#8719;', true, 'n-ary product'],
+ ['&and;', '&#8743;', false,'logical and'],
+ ['&or;', '&#8744;', false,'logical or'],
+ ['&not;', '&#172;', true, 'not sign'],
+ ['&cap;', '&#8745;', true, 'intersection'],
+ ['&cup;', '&#8746;', false,'union'],
+ ['&part;', '&#8706;', true, 'partial differential'],
+ ['&forall;', '&#8704;', false,'for all'],
+ ['&exist;', '&#8707;', false,'there exists'],
+ ['&empty;', '&#8709;', false,'diameter'],
+ ['&nabla;', '&#8711;', false,'backward difference'],
+ ['&lowast;', '&#8727;', false,'asterisk operator'],
+ ['&prop;', '&#8733;', false,'proportional to'],
+ ['&ang;', '&#8736;', false,'angle'],
+// undefined
+ ['&acute;', '&#180;', true, 'acute accent'],
+ ['&cedil;', '&#184;', true, 'cedilla'],
+ ['&ordf;', '&#170;', true, 'feminine ordinal indicator'],
+ ['&ordm;', '&#186;', true, 'masculine ordinal indicator'],
+ ['&dagger;', '&#8224;', true, 'dagger'],
+ ['&Dagger;', '&#8225;', true, 'double dagger'],
+// alphabetical special chars
+ ['&Agrave;', '&#192;', true, 'A - grave'],
+ ['&Aacute;', '&#193;', true, 'A - acute'],
+ ['&Acirc;', '&#194;', true, 'A - circumflex'],
+ ['&Atilde;', '&#195;', true, 'A - tilde'],
+ ['&Auml;', '&#196;', true, 'A - diaeresis'],
+ ['&Aring;', '&#197;', true, 'A - ring above'],
+ ['&AElig;', '&#198;', true, 'ligature AE'],
+ ['&Ccedil;', '&#199;', true, 'C - cedilla'],
+ ['&Egrave;', '&#200;', true, 'E - grave'],
+ ['&Eacute;', '&#201;', true, 'E - acute'],
+ ['&Ecirc;', '&#202;', true, 'E - circumflex'],
+ ['&Euml;', '&#203;', true, 'E - diaeresis'],
+ ['&Igrave;', '&#204;', true, 'I - grave'],
+ ['&Iacute;', '&#205;', true, 'I - acute'],
+ ['&Icirc;', '&#206;', true, 'I - circumflex'],
+ ['&Iuml;', '&#207;', true, 'I - diaeresis'],
+ ['&ETH;', '&#208;', true, 'ETH'],
+ ['&Ntilde;', '&#209;', true, 'N - tilde'],
+ ['&Ograve;', '&#210;', true, 'O - grave'],
+ ['&Oacute;', '&#211;', true, 'O - acute'],
+ ['&Ocirc;', '&#212;', true, 'O - circumflex'],
+ ['&Otilde;', '&#213;', true, 'O - tilde'],
+ ['&Ouml;', '&#214;', true, 'O - diaeresis'],
+ ['&Oslash;', '&#216;', true, 'O - slash'],
+ ['&OElig;', '&#338;', true, 'ligature OE'],
+ ['&Scaron;', '&#352;', true, 'S - caron'],
+ ['&Ugrave;', '&#217;', true, 'U - grave'],
+ ['&Uacute;', '&#218;', true, 'U - acute'],
+ ['&Ucirc;', '&#219;', true, 'U - circumflex'],
+ ['&Uuml;', '&#220;', true, 'U - diaeresis'],
+ ['&Yacute;', '&#221;', true, 'Y - acute'],
+ ['&Yuml;', '&#376;', true, 'Y - diaeresis'],
+ ['&THORN;', '&#222;', true, 'THORN'],
+ ['&agrave;', '&#224;', true, 'a - grave'],
+ ['&aacute;', '&#225;', true, 'a - acute'],
+ ['&acirc;', '&#226;', true, 'a - circumflex'],
+ ['&atilde;', '&#227;', true, 'a - tilde'],
+ ['&auml;', '&#228;', true, 'a - diaeresis'],
+ ['&aring;', '&#229;', true, 'a - ring above'],
+ ['&aelig;', '&#230;', true, 'ligature ae'],
+ ['&ccedil;', '&#231;', true, 'c - cedilla'],
+ ['&egrave;', '&#232;', true, 'e - grave'],
+ ['&eacute;', '&#233;', true, 'e - acute'],
+ ['&ecirc;', '&#234;', true, 'e - circumflex'],
+ ['&euml;', '&#235;', true, 'e - diaeresis'],
+ ['&igrave;', '&#236;', true, 'i - grave'],
+ ['&iacute;', '&#237;', true, 'i - acute'],
+ ['&icirc;', '&#238;', true, 'i - circumflex'],
+ ['&iuml;', '&#239;', true, 'i - diaeresis'],
+ ['&eth;', '&#240;', true, 'eth'],
+ ['&ntilde;', '&#241;', true, 'n - tilde'],
+ ['&ograve;', '&#242;', true, 'o - grave'],
+ ['&oacute;', '&#243;', true, 'o - acute'],
+ ['&ocirc;', '&#244;', true, 'o - circumflex'],
+ ['&otilde;', '&#245;', true, 'o - tilde'],
+ ['&ouml;', '&#246;', true, 'o - diaeresis'],
+ ['&oslash;', '&#248;', true, 'o slash'],
+ ['&oelig;', '&#339;', true, 'ligature oe'],
+ ['&scaron;', '&#353;', true, 's - caron'],
+ ['&ugrave;', '&#249;', true, 'u - grave'],
+ ['&uacute;', '&#250;', true, 'u - acute'],
+ ['&ucirc;', '&#251;', true, 'u - circumflex'],
+ ['&uuml;', '&#252;', true, 'u - diaeresis'],
+ ['&yacute;', '&#253;', true, 'y - acute'],
+ ['&thorn;', '&#254;', true, 'thorn'],
+ ['&yuml;', '&#255;', true, 'y - diaeresis'],
+ ['&Alpha;', '&#913;', true, 'Alpha'],
+ ['&Beta;', '&#914;', true, 'Beta'],
+ ['&Gamma;', '&#915;', true, 'Gamma'],
+ ['&Delta;', '&#916;', true, 'Delta'],
+ ['&Epsilon;', '&#917;', true, 'Epsilon'],
+ ['&Zeta;', '&#918;', true, 'Zeta'],
+ ['&Eta;', '&#919;', true, 'Eta'],
+ ['&Theta;', '&#920;', true, 'Theta'],
+ ['&Iota;', '&#921;', true, 'Iota'],
+ ['&Kappa;', '&#922;', true, 'Kappa'],
+ ['&Lambda;', '&#923;', true, 'Lambda'],
+ ['&Mu;', '&#924;', true, 'Mu'],
+ ['&Nu;', '&#925;', true, 'Nu'],
+ ['&Xi;', '&#926;', true, 'Xi'],
+ ['&Omicron;', '&#927;', true, 'Omicron'],
+ ['&Pi;', '&#928;', true, 'Pi'],
+ ['&Rho;', '&#929;', true, 'Rho'],
+ ['&Sigma;', '&#931;', true, 'Sigma'],
+ ['&Tau;', '&#932;', true, 'Tau'],
+ ['&Upsilon;', '&#933;', true, 'Upsilon'],
+ ['&Phi;', '&#934;', true, 'Phi'],
+ ['&Chi;', '&#935;', true, 'Chi'],
+ ['&Psi;', '&#936;', true, 'Psi'],
+ ['&Omega;', '&#937;', true, 'Omega'],
+ ['&alpha;', '&#945;', true, 'alpha'],
+ ['&beta;', '&#946;', true, 'beta'],
+ ['&gamma;', '&#947;', true, 'gamma'],
+ ['&delta;', '&#948;', true, 'delta'],
+ ['&epsilon;', '&#949;', true, 'epsilon'],
+ ['&zeta;', '&#950;', true, 'zeta'],
+ ['&eta;', '&#951;', true, 'eta'],
+ ['&theta;', '&#952;', true, 'theta'],
+ ['&iota;', '&#953;', true, 'iota'],
+ ['&kappa;', '&#954;', true, 'kappa'],
+ ['&lambda;', '&#955;', true, 'lambda'],
+ ['&mu;', '&#956;', true, 'mu'],
+ ['&nu;', '&#957;', true, 'nu'],
+ ['&xi;', '&#958;', true, 'xi'],
+ ['&omicron;', '&#959;', true, 'omicron'],
+ ['&pi;', '&#960;', true, 'pi'],
+ ['&rho;', '&#961;', true, 'rho'],
+ ['&sigmaf;', '&#962;', true, 'final sigma'],
+ ['&sigma;', '&#963;', true, 'sigma'],
+ ['&tau;', '&#964;', true, 'tau'],
+ ['&upsilon;', '&#965;', true, 'upsilon'],
+ ['&phi;', '&#966;', true, 'phi'],
+ ['&chi;', '&#967;', true, 'chi'],
+ ['&psi;', '&#968;', true, 'psi'],
+ ['&omega;', '&#969;', true, 'omega'],
+// symbols
+ ['&alefsym;', '&#8501;', false,'alef symbol'],
+ ['&piv;', '&#982;', false,'pi symbol'],
+ ['&real;', '&#8476;', false,'real part symbol'],
+ ['&thetasym;','&#977;', false,'theta symbol'],
+ ['&upsih;', '&#978;', false,'upsilon - hook symbol'],
+ ['&weierp;', '&#8472;', false,'Weierstrass p'],
+ ['&image;', '&#8465;', false,'imaginary part'],
+// arrows
+ ['&larr;', '&#8592;', true, 'leftwards arrow'],
+ ['&uarr;', '&#8593;', true, 'upwards arrow'],
+ ['&rarr;', '&#8594;', true, 'rightwards arrow'],
+ ['&darr;', '&#8595;', true, 'downwards arrow'],
+ ['&harr;', '&#8596;', true, 'left right arrow'],
+ ['&crarr;', '&#8629;', false,'carriage return'],
+ ['&lArr;', '&#8656;', false,'leftwards double arrow'],
+ ['&uArr;', '&#8657;', false,'upwards double arrow'],
+ ['&rArr;', '&#8658;', false,'rightwards double arrow'],
+ ['&dArr;', '&#8659;', false,'downwards double arrow'],
+ ['&hArr;', '&#8660;', false,'left right double arrow'],
+ ['&there4;', '&#8756;', false,'therefore'],
+ ['&sub;', '&#8834;', false,'subset of'],
+ ['&sup;', '&#8835;', false,'superset of'],
+ ['&nsub;', '&#8836;', false,'not a subset of'],
+ ['&sube;', '&#8838;', false,'subset of or equal to'],
+ ['&supe;', '&#8839;', false,'superset of or equal to'],
+ ['&oplus;', '&#8853;', false,'circled plus'],
+ ['&otimes;', '&#8855;', false,'circled times'],
+ ['&perp;', '&#8869;', false,'perpendicular'],
+ ['&sdot;', '&#8901;', false,'dot operator'],
+ ['&lceil;', '&#8968;', false,'left ceiling'],
+ ['&rceil;', '&#8969;', false,'right ceiling'],
+ ['&lfloor;', '&#8970;', false,'left floor'],
+ ['&rfloor;', '&#8971;', false,'right floor'],
+ ['&lang;', '&#9001;', false,'left-pointing angle bracket'],
+ ['&rang;', '&#9002;', false,'right-pointing angle bracket'],
+ ['&loz;', '&#9674;', true, 'lozenge'],
+ ['&spades;', '&#9824;', true, 'black spade suit'],
+ ['&clubs;', '&#9827;', true, 'black club suit'],
+ ['&hearts;', '&#9829;', true, 'black heart suit'],
+ ['&diams;', '&#9830;', true, 'black diamond suit'],
+ ['&ensp;', '&#8194;', false,'en space'],
+ ['&emsp;', '&#8195;', false,'em space'],
+ ['&thinsp;', '&#8201;', false,'thin space'],
+ ['&zwnj;', '&#8204;', false,'zero width non-joiner'],
+ ['&zwj;', '&#8205;', false,'zero width joiner'],
+ ['&lrm;', '&#8206;', false,'left-to-right mark'],
+ ['&rlm;', '&#8207;', false,'right-to-left mark'],
+ ['&shy;', '&#173;', false,'soft hyphen']
+];
+
+tinyMCEPopup.onInit.add(function() {
+ tinyMCEPopup.dom.setHTML('charmapView', renderCharMapHTML());
+ addKeyboardNavigation();
+});
+
+function addKeyboardNavigation(){
+ var tableElm, cells, settings;
+
+ cells = tinyMCEPopup.dom.select("a.charmaplink", "charmapgroup");
+
+ settings ={
+ root: "charmapgroup",
+ items: cells
+ };
+ cells[0].tabindex=0;
+ tinyMCEPopup.dom.addClass(cells[0], "mceFocus");
+ if (tinymce.isGecko) {
+ cells[0].focus();
+ } else {
+ setTimeout(function(){
+ cells[0].focus();
+ }, 100);
+ }
+ tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', settings, tinyMCEPopup.dom);
+}
+
+function renderCharMapHTML() {
+ var charsPerRow = 20, tdWidth=20, tdHeight=20, i;
+ var html = '<div id="charmapgroup" aria-labelledby="charmap_label" tabindex="0" role="listbox">'+
+ '<table role="presentation" border="0" cellspacing="1" cellpadding="0" width="' + (tdWidth*charsPerRow) +
+ '"><tr height="' + tdHeight + '">';
+ var cols=-1;
+
+ for (i=0; i<charmap.length; i++) {
+ var previewCharFn;
+
+ if (charmap[i][2]==true) {
+ cols++;
+ previewCharFn = 'previewChar(\'' + charmap[i][1].substring(1,charmap[i][1].length) + '\',\'' + charmap[i][0].substring(1,charmap[i][0].length) + '\',\'' + charmap[i][3] + '\');';
+ html += ''
+ + '<td class="charmap">'
+ + '<a class="charmaplink" role="button" onmouseover="'+previewCharFn+'" onfocus="'+previewCharFn+'" href="javascript:void(0)" onclick="insertChar(\'' + charmap[i][1].substring(2,charmap[i][1].length-1) + '\');" onclick="return false;" onmousedown="return false;" title="' + charmap[i][3] + ' '+ tinyMCEPopup.editor.translate("advanced_dlg.charmap_usage")+'">'
+ + charmap[i][1]
+ + '</a></td>';
+ if ((cols+1) % charsPerRow == 0)
+ html += '</tr><tr height="' + tdHeight + '">';
+ }
+ }
+
+ if (cols % charsPerRow > 0) {
+ var padd = charsPerRow - (cols % charsPerRow);
+ for (var i=0; i<padd-1; i++)
+ html += '<td width="' + tdWidth + '" height="' + tdHeight + '" class="charmap">&nbsp;</td>';
+ }
+
+ html += '</tr></table></div>';
+ html = html.replace(/<tr height="20"><\/tr>/g, '');
+
+ return html;
+}
+
+function insertChar(chr) {
+ tinyMCEPopup.execCommand('mceInsertContent', false, '&#' + chr + ';');
+
+ // Refocus in window
+ if (tinyMCEPopup.isWindow)
+ window.focus();
+
+ tinyMCEPopup.editor.focus();
+ tinyMCEPopup.close();
+}
+
+function previewChar(codeA, codeB, codeN) {
+ var elmA = document.getElementById('codeA');
+ var elmB = document.getElementById('codeB');
+ var elmV = document.getElementById('codeV');
+ var elmN = document.getElementById('codeN');
+
+ if (codeA=='#160;') {
+ elmV.innerHTML = '__';
+ } else {
+ elmV.innerHTML = '&' + codeA;
+ }
+
+ elmB.innerHTML = '&amp;' + codeA;
+ elmA.innerHTML = '&amp;' + codeB;
+ elmN.innerHTML = codeN;
+}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/color_picker.js b/src/wp-includes/js/tinymce/themes/advanced/js/color_picker.js
new file mode 100644
index 0000000000..cc891c1711
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/color_picker.js
@@ -0,0 +1,345 @@
+tinyMCEPopup.requireLangPack();
+
+var detail = 50, strhex = "0123456789abcdef", i, isMouseDown = false, isMouseOver = false;
+
+var colors = [
+ "#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033",
+ "#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099",
+ "#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff",
+ "#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033",
+ "#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399",
+ "#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff",
+ "#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333",
+ "#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399",
+ "#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff",
+ "#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633",
+ "#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699",
+ "#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff",
+ "#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633",
+ "#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999",
+ "#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff",
+ "#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933",
+ "#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999",
+ "#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff",
+ "#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33",
+ "#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99",
+ "#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff",
+ "#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33",
+ "#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99",
+ "#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff",
+ "#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33",
+ "#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99",
+ "#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff"
+];
+
+var named = {
+ '#F0F8FF':'Alice Blue','#FAEBD7':'Antique White','#00FFFF':'Aqua','#7FFFD4':'Aquamarine','#F0FFFF':'Azure','#F5F5DC':'Beige',
+ '#FFE4C4':'Bisque','#000000':'Black','#FFEBCD':'Blanched Almond','#0000FF':'Blue','#8A2BE2':'Blue Violet','#A52A2A':'Brown',
+ '#DEB887':'Burly Wood','#5F9EA0':'Cadet Blue','#7FFF00':'Chartreuse','#D2691E':'Chocolate','#FF7F50':'Coral','#6495ED':'Cornflower Blue',
+ '#FFF8DC':'Cornsilk','#DC143C':'Crimson','#00FFFF':'Cyan','#00008B':'Dark Blue','#008B8B':'Dark Cyan','#B8860B':'Dark Golden Rod',
+ '#A9A9A9':'Dark Gray','#A9A9A9':'Dark Grey','#006400':'Dark Green','#BDB76B':'Dark Khaki','#8B008B':'Dark Magenta','#556B2F':'Dark Olive Green',
+ '#FF8C00':'Darkorange','#9932CC':'Dark Orchid','#8B0000':'Dark Red','#E9967A':'Dark Salmon','#8FBC8F':'Dark Sea Green','#483D8B':'Dark Slate Blue',
+ '#2F4F4F':'Dark Slate Gray','#2F4F4F':'Dark Slate Grey','#00CED1':'Dark Turquoise','#9400D3':'Dark Violet','#FF1493':'Deep Pink','#00BFFF':'Deep Sky Blue',
+ '#696969':'Dim Gray','#696969':'Dim Grey','#1E90FF':'Dodger Blue','#B22222':'Fire Brick','#FFFAF0':'Floral White','#228B22':'Forest Green',
+ '#FF00FF':'Fuchsia','#DCDCDC':'Gainsboro','#F8F8FF':'Ghost White','#FFD700':'Gold','#DAA520':'Golden Rod','#808080':'Gray','#808080':'Grey',
+ '#008000':'Green','#ADFF2F':'Green Yellow','#F0FFF0':'Honey Dew','#FF69B4':'Hot Pink','#CD5C5C':'Indian Red','#4B0082':'Indigo','#FFFFF0':'Ivory',
+ '#F0E68C':'Khaki','#E6E6FA':'Lavender','#FFF0F5':'Lavender Blush','#7CFC00':'Lawn Green','#FFFACD':'Lemon Chiffon','#ADD8E6':'Light Blue',
+ '#F08080':'Light Coral','#E0FFFF':'Light Cyan','#FAFAD2':'Light Golden Rod Yellow','#D3D3D3':'Light Gray','#D3D3D3':'Light Grey','#90EE90':'Light Green',
+ '#FFB6C1':'Light Pink','#FFA07A':'Light Salmon','#20B2AA':'Light Sea Green','#87CEFA':'Light Sky Blue','#778899':'Light Slate Gray','#778899':'Light Slate Grey',
+ '#B0C4DE':'Light Steel Blue','#FFFFE0':'Light Yellow','#00FF00':'Lime','#32CD32':'Lime Green','#FAF0E6':'Linen','#FF00FF':'Magenta','#800000':'Maroon',
+ '#66CDAA':'Medium Aqua Marine','#0000CD':'Medium Blue','#BA55D3':'Medium Orchid','#9370D8':'Medium Purple','#3CB371':'Medium Sea Green','#7B68EE':'Medium Slate Blue',
+ '#00FA9A':'Medium Spring Green','#48D1CC':'Medium Turquoise','#C71585':'Medium Violet Red','#191970':'Midnight Blue','#F5FFFA':'Mint Cream','#FFE4E1':'Misty Rose','#FFE4B5':'Moccasin',
+ '#FFDEAD':'Navajo White','#000080':'Navy','#FDF5E6':'Old Lace','#808000':'Olive','#6B8E23':'Olive Drab','#FFA500':'Orange','#FF4500':'Orange Red','#DA70D6':'Orchid',
+ '#EEE8AA':'Pale Golden Rod','#98FB98':'Pale Green','#AFEEEE':'Pale Turquoise','#D87093':'Pale Violet Red','#FFEFD5':'Papaya Whip','#FFDAB9':'Peach Puff',
+ '#CD853F':'Peru','#FFC0CB':'Pink','#DDA0DD':'Plum','#B0E0E6':'Powder Blue','#800080':'Purple','#FF0000':'Red','#BC8F8F':'Rosy Brown','#4169E1':'Royal Blue',
+ '#8B4513':'Saddle Brown','#FA8072':'Salmon','#F4A460':'Sandy Brown','#2E8B57':'Sea Green','#FFF5EE':'Sea Shell','#A0522D':'Sienna','#C0C0C0':'Silver',
+ '#87CEEB':'Sky Blue','#6A5ACD':'Slate Blue','#708090':'Slate Gray','#708090':'Slate Grey','#FFFAFA':'Snow','#00FF7F':'Spring Green',
+ '#4682B4':'Steel Blue','#D2B48C':'Tan','#008080':'Teal','#D8BFD8':'Thistle','#FF6347':'Tomato','#40E0D0':'Turquoise','#EE82EE':'Violet',
+ '#F5DEB3':'Wheat','#FFFFFF':'White','#F5F5F5':'White Smoke','#FFFF00':'Yellow','#9ACD32':'Yellow Green'
+};
+
+var namedLookup = {};
+
+function init() {
+ var inputColor = convertRGBToHex(tinyMCEPopup.getWindowArg('input_color')), key, value;
+
+ tinyMCEPopup.resizeToInnerSize();
+
+ generatePicker();
+ generateWebColors();
+ generateNamedColors();
+
+ if (inputColor) {
+ changeFinalColor(inputColor);
+
+ col = convertHexToRGB(inputColor);
+
+ if (col)
+ updateLight(col.r, col.g, col.b);
+ }
+
+ for (key in named) {
+ value = named[key];
+ namedLookup[value.replace(/\s+/, '').toLowerCase()] = key.replace(/#/, '').toLowerCase();
+ }
+}
+
+function toHexColor(color) {
+ var matches, red, green, blue, toInt = parseInt;
+
+ function hex(value) {
+ value = parseInt(value).toString(16);
+
+ return value.length > 1 ? value : '0' + value; // Padd with leading zero
+ };
+
+ color = tinymce.trim(color);
+ color = color.replace(/^[#]/, '').toLowerCase(); // remove leading '#'
+ color = namedLookup[color] || color;
+
+ matches = /^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/.exec(color);
+
+ if (matches) {
+ red = toInt(matches[1]);
+ green = toInt(matches[2]);
+ blue = toInt(matches[3]);
+ } else {
+ matches = /^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/.exec(color);
+
+ if (matches) {
+ red = toInt(matches[1], 16);
+ green = toInt(matches[2], 16);
+ blue = toInt(matches[3], 16);
+ } else {
+ matches = /^([0-9a-f])([0-9a-f])([0-9a-f])$/.exec(color);
+
+ if (matches) {
+ red = toInt(matches[1] + matches[1], 16);
+ green = toInt(matches[2] + matches[2], 16);
+ blue = toInt(matches[3] + matches[3], 16);
+ } else {
+ return '';
+ }
+ }
+ }
+
+ return '#' + hex(red) + hex(green) + hex(blue);
+}
+
+function insertAction() {
+ var color = document.getElementById("color").value, f = tinyMCEPopup.getWindowArg('func');
+
+ var hexColor = toHexColor(color);
+
+ if (hexColor === '') {
+ var text = tinyMCEPopup.editor.getLang('advanced_dlg.invalid_color_value');
+ tinyMCEPopup.alert(text + ': ' + color);
+ }
+ else {
+ tinyMCEPopup.restoreSelection();
+
+ if (f)
+ f(hexColor);
+
+ tinyMCEPopup.close();
+ }
+}
+
+function showColor(color, name) {
+ if (name)
+ document.getElementById("colorname").innerHTML = name;
+
+ document.getElementById("preview").style.backgroundColor = color;
+ document.getElementById("color").value = color.toUpperCase();
+}
+
+function convertRGBToHex(col) {
+ var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+ if (!col)
+ return col;
+
+ var rgb = col.replace(re, "$1,$2,$3").split(',');
+ if (rgb.length == 3) {
+ r = parseInt(rgb[0]).toString(16);
+ g = parseInt(rgb[1]).toString(16);
+ b = parseInt(rgb[2]).toString(16);
+
+ r = r.length == 1 ? '0' + r : r;
+ g = g.length == 1 ? '0' + g : g;
+ b = b.length == 1 ? '0' + b : b;
+
+ return "#" + r + g + b;
+ }
+
+ return col;
+}
+
+function convertHexToRGB(col) {
+ if (col.indexOf('#') != -1) {
+ col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+ r = parseInt(col.substring(0, 2), 16);
+ g = parseInt(col.substring(2, 4), 16);
+ b = parseInt(col.substring(4, 6), 16);
+
+ return {r : r, g : g, b : b};
+ }
+
+ return null;
+}
+
+function generatePicker() {
+ var el = document.getElementById('light'), h = '', i;
+
+ for (i = 0; i < detail; i++){
+ h += '<div id="gs'+i+'" style="background-color:#000000; width:15px; height:3px; border-style:none; border-width:0px;"'
+ + ' onclick="changeFinalColor(this.style.backgroundColor)"'
+ + ' onmousedown="isMouseDown = true; return false;"'
+ + ' onmouseup="isMouseDown = false;"'
+ + ' onmousemove="if (isMouseDown && isMouseOver) changeFinalColor(this.style.backgroundColor); return false;"'
+ + ' onmouseover="isMouseOver = true;"'
+ + ' onmouseout="isMouseOver = false;"'
+ + '></div>';
+ }
+
+ el.innerHTML = h;
+}
+
+function generateWebColors() {
+ var el = document.getElementById('webcolors'), h = '', i;
+
+ if (el.className == 'generated')
+ return;
+
+ // TODO: VoiceOver doesn't seem to support legend as a label referenced by labelledby.
+ h += '<div role="listbox" aria-labelledby="webcolors_title" tabindex="0"><table role="presentation" border="0" cellspacing="1" cellpadding="0">'
+ + '<tr>';
+
+ for (i=0; i<colors.length; i++) {
+ h += '<td bgcolor="' + colors[i] + '" width="10" height="10">'
+ + '<a href="javascript:insertAction();" role="option" tabindex="-1" aria-labelledby="web_colors_' + i + '" onfocus="showColor(\'' + colors[i] + '\');" onmouseover="showColor(\'' + colors[i] + '\');" style="display:block;width:10px;height:10px;overflow:hidden;">';
+ if (tinyMCEPopup.editor.forcedHighContrastMode) {
+ h += '<canvas class="mceColorSwatch" height="10" width="10" data-color="' + colors[i] + '"></canvas>';
+ }
+ h += '<span class="mceVoiceLabel" style="display:none;" id="web_colors_' + i + '">' + colors[i].toUpperCase() + '</span>';
+ h += '</a></td>';
+ if ((i+1) % 18 == 0)
+ h += '</tr><tr>';
+ }
+
+ h += '</table></div>';
+
+ el.innerHTML = h;
+ el.className = 'generated';
+
+ paintCanvas(el);
+ enableKeyboardNavigation(el.firstChild);
+}
+
+function paintCanvas(el) {
+ tinyMCEPopup.getWin().tinymce.each(tinyMCEPopup.dom.select('canvas.mceColorSwatch', el), function(canvas) {
+ var context;
+ if (canvas.getContext && (context = canvas.getContext("2d"))) {
+ context.fillStyle = canvas.getAttribute('data-color');
+ context.fillRect(0, 0, 10, 10);
+ }
+ });
+}
+function generateNamedColors() {
+ var el = document.getElementById('namedcolors'), h = '', n, v, i = 0;
+
+ if (el.className == 'generated')
+ return;
+
+ for (n in named) {
+ v = named[n];
+ h += '<a href="javascript:insertAction();" role="option" tabindex="-1" aria-labelledby="named_colors_' + i + '" onfocus="showColor(\'' + n + '\',\'' + v + '\');" onmouseover="showColor(\'' + n + '\',\'' + v + '\');" style="background-color: ' + n + '">';
+ if (tinyMCEPopup.editor.forcedHighContrastMode) {
+ h += '<canvas class="mceColorSwatch" height="10" width="10" data-color="' + colors[i] + '"></canvas>';
+ }
+ h += '<span class="mceVoiceLabel" style="display:none;" id="named_colors_' + i + '">' + v + '</span>';
+ h += '</a>';
+ i++;
+ }
+
+ el.innerHTML = h;
+ el.className = 'generated';
+
+ paintCanvas(el);
+ enableKeyboardNavigation(el);
+}
+
+function enableKeyboardNavigation(el) {
+ tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', {
+ root: el,
+ items: tinyMCEPopup.dom.select('a', el)
+ }, tinyMCEPopup.dom);
+}
+
+function dechex(n) {
+ return strhex.charAt(Math.floor(n / 16)) + strhex.charAt(n % 16);
+}
+
+function computeColor(e) {
+ var x, y, partWidth, partDetail, imHeight, r, g, b, coef, i, finalCoef, finalR, finalG, finalB, pos = tinyMCEPopup.dom.getPos(e.target);
+
+ x = e.offsetX ? e.offsetX : (e.target ? e.clientX - pos.x : 0);
+ y = e.offsetY ? e.offsetY : (e.target ? e.clientY - pos.y : 0);
+
+ partWidth = document.getElementById('colors').width / 6;
+ partDetail = detail / 2;
+ imHeight = document.getElementById('colors').height;
+
+ r = (x >= 0)*(x < partWidth)*255 + (x >= partWidth)*(x < 2*partWidth)*(2*255 - x * 255 / partWidth) + (x >= 4*partWidth)*(x < 5*partWidth)*(-4*255 + x * 255 / partWidth) + (x >= 5*partWidth)*(x < 6*partWidth)*255;
+ g = (x >= 0)*(x < partWidth)*(x * 255 / partWidth) + (x >= partWidth)*(x < 3*partWidth)*255 + (x >= 3*partWidth)*(x < 4*partWidth)*(4*255 - x * 255 / partWidth);
+ b = (x >= 2*partWidth)*(x < 3*partWidth)*(-2*255 + x * 255 / partWidth) + (x >= 3*partWidth)*(x < 5*partWidth)*255 + (x >= 5*partWidth)*(x < 6*partWidth)*(6*255 - x * 255 / partWidth);
+
+ coef = (imHeight - y) / imHeight;
+ r = 128 + (r - 128) * coef;
+ g = 128 + (g - 128) * coef;
+ b = 128 + (b - 128) * coef;
+
+ changeFinalColor('#' + dechex(r) + dechex(g) + dechex(b));
+ updateLight(r, g, b);
+}
+
+function updateLight(r, g, b) {
+ var i, partDetail = detail / 2, finalCoef, finalR, finalG, finalB, color;
+
+ for (i=0; i<detail; i++) {
+ if ((i>=0) && (i<partDetail)) {
+ finalCoef = i / partDetail;
+ finalR = dechex(255 - (255 - r) * finalCoef);
+ finalG = dechex(255 - (255 - g) * finalCoef);
+ finalB = dechex(255 - (255 - b) * finalCoef);
+ } else {
+ finalCoef = 2 - i / partDetail;
+ finalR = dechex(r * finalCoef);
+ finalG = dechex(g * finalCoef);
+ finalB = dechex(b * finalCoef);
+ }
+
+ color = finalR + finalG + finalB;
+
+ setCol('gs' + i, '#'+color);
+ }
+}
+
+function changeFinalColor(color) {
+ if (color.indexOf('#') == -1)
+ color = convertRGBToHex(color);
+
+ setCol('preview', color);
+ document.getElementById('color').value = color;
+}
+
+function setCol(e, c) {
+ try {
+ document.getElementById(e).style.backgroundColor = c;
+ } catch (ex) {
+ // Ignore IE warning
+ }
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/image.js b/src/wp-includes/js/tinymce/themes/advanced/js/image.js
new file mode 100644
index 0000000000..3f93e2d321
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/image.js
@@ -0,0 +1,253 @@
+var ImageDialog = {
+ preInit : function() {
+ var url;
+
+ tinyMCEPopup.requireLangPack();
+
+ if (url = tinyMCEPopup.getParam("external_image_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+ },
+
+ init : function() {
+ var f = document.forms[0], ed = tinyMCEPopup.editor;
+
+ // Setup browse button
+ document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image');
+ if (isVisible('srcbrowser'))
+ document.getElementById('src').style.width = '180px';
+
+ e = ed.selection.getNode();
+
+ this.fillFileList('image_list', tinyMCEPopup.getParam('external_image_list', 'tinyMCEImageList'));
+
+ if (e.nodeName == 'IMG') {
+ f.src.value = ed.dom.getAttrib(e, 'src');
+ f.alt.value = ed.dom.getAttrib(e, 'alt');
+ f.border.value = this.getAttrib(e, 'border');
+ f.vspace.value = this.getAttrib(e, 'vspace');
+ f.hspace.value = this.getAttrib(e, 'hspace');
+ f.width.value = ed.dom.getAttrib(e, 'width');
+ f.height.value = ed.dom.getAttrib(e, 'height');
+ f.insert.value = ed.getLang('update');
+ this.styleVal = ed.dom.getAttrib(e, 'style');
+ selectByValue(f, 'image_list', f.src.value);
+ selectByValue(f, 'align', this.getAttrib(e, 'align'));
+ this.updateStyle();
+ }
+ },
+
+ fillFileList : function(id, l) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ l = typeof(l) === 'function' ? l() : window[l];
+
+ if (l && l.length > 0) {
+ lst.options[lst.options.length] = new Option('', '');
+
+ tinymce.each(l, function(o) {
+ lst.options[lst.options.length] = new Option(o[0], o[1]);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ update : function() {
+ var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, args = {}, el;
+
+ tinyMCEPopup.restoreSelection();
+
+ if (f.src.value === '') {
+ if (ed.selection.getNode().nodeName == 'IMG') {
+ ed.dom.remove(ed.selection.getNode());
+ ed.execCommand('mceRepaint');
+ }
+
+ tinyMCEPopup.close();
+ return;
+ }
+
+ if (!ed.settings.inline_styles) {
+ args = tinymce.extend(args, {
+ vspace : nl.vspace.value,
+ hspace : nl.hspace.value,
+ border : nl.border.value,
+ align : getSelectValue(f, 'align')
+ });
+ } else
+ args.style = this.styleVal;
+
+ tinymce.extend(args, {
+ src : f.src.value.replace(/ /g, '%20'),
+ alt : f.alt.value,
+ width : f.width.value,
+ height : f.height.value
+ });
+
+ el = ed.selection.getNode();
+
+ if (el && el.nodeName == 'IMG') {
+ ed.dom.setAttribs(el, args);
+ tinyMCEPopup.editor.execCommand('mceRepaint');
+ tinyMCEPopup.editor.focus();
+ } else {
+ tinymce.each(args, function(value, name) {
+ if (value === "") {
+ delete args[name];
+ }
+ });
+
+ ed.execCommand('mceInsertContent', false, tinyMCEPopup.editor.dom.createHTML('img', args), {skip_undo : 1});
+ ed.undoManager.add();
+ }
+
+ tinyMCEPopup.close();
+ },
+
+ updateStyle : function() {
+ var dom = tinyMCEPopup.dom, st = {}, v, f = document.forms[0];
+
+ if (tinyMCEPopup.editor.settings.inline_styles) {
+ tinymce.each(tinyMCEPopup.dom.parseStyle(this.styleVal), function(value, key) {
+ st[key] = value;
+ });
+
+ // Handle align
+ v = getSelectValue(f, 'align');
+ if (v) {
+ if (v == 'left' || v == 'right') {
+ st['float'] = v;
+ delete st['vertical-align'];
+ } else {
+ st['vertical-align'] = v;
+ delete st['float'];
+ }
+ } else {
+ delete st['float'];
+ delete st['vertical-align'];
+ }
+
+ // Handle border
+ v = f.border.value;
+ if (v || v == '0') {
+ if (v == '0')
+ st['border'] = '0';
+ else
+ st['border'] = v + 'px solid black';
+ } else
+ delete st['border'];
+
+ // Handle hspace
+ v = f.hspace.value;
+ if (v) {
+ delete st['margin'];
+ st['margin-left'] = v + 'px';
+ st['margin-right'] = v + 'px';
+ } else {
+ delete st['margin-left'];
+ delete st['margin-right'];
+ }
+
+ // Handle vspace
+ v = f.vspace.value;
+ if (v) {
+ delete st['margin'];
+ st['margin-top'] = v + 'px';
+ st['margin-bottom'] = v + 'px';
+ } else {
+ delete st['margin-top'];
+ delete st['margin-bottom'];
+ }
+
+ // Merge
+ st = tinyMCEPopup.dom.parseStyle(dom.serializeStyle(st), 'img');
+ this.styleVal = dom.serializeStyle(st, 'img');
+ }
+ },
+
+ getAttrib : function(e, at) {
+ var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2;
+
+ if (ed.settings.inline_styles) {
+ switch (at) {
+ case 'align':
+ if (v = dom.getStyle(e, 'float'))
+ return v;
+
+ if (v = dom.getStyle(e, 'vertical-align'))
+ return v;
+
+ break;
+
+ case 'hspace':
+ v = dom.getStyle(e, 'margin-left')
+ v2 = dom.getStyle(e, 'margin-right');
+ if (v && v == v2)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+
+ case 'vspace':
+ v = dom.getStyle(e, 'margin-top')
+ v2 = dom.getStyle(e, 'margin-bottom');
+ if (v && v == v2)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+
+ case 'border':
+ v = 0;
+
+ tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) {
+ sv = dom.getStyle(e, 'border-' + sv + '-width');
+
+ // False or not the same as prev
+ if (!sv || (sv != v && v !== 0)) {
+ v = 0;
+ return false;
+ }
+
+ if (sv)
+ v = sv;
+ });
+
+ if (v)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+ }
+ }
+
+ if (v = dom.getAttrib(e, at))
+ return v;
+
+ return '';
+ },
+
+ resetImageData : function() {
+ var f = document.forms[0];
+
+ f.width.value = f.height.value = "";
+ },
+
+ updateImageData : function() {
+ var f = document.forms[0], t = ImageDialog;
+
+ if (f.width.value == "")
+ f.width.value = t.preloadImg.width;
+
+ if (f.height.value == "")
+ f.height.value = t.preloadImg.height;
+ },
+
+ getImageData : function() {
+ var f = document.forms[0];
+
+ this.preloadImg = new Image();
+ this.preloadImg.onload = this.updateImageData;
+ this.preloadImg.onerror = this.resetImageData;
+ this.preloadImg.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(f.src.value);
+ }
+};
+
+ImageDialog.preInit();
+tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog);
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/link.js b/src/wp-includes/js/tinymce/themes/advanced/js/link.js
new file mode 100644
index 0000000000..b08b2ba9c2
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/link.js
@@ -0,0 +1,159 @@
+tinyMCEPopup.requireLangPack();
+
+var LinkDialog = {
+ preInit : function() {
+ var url;
+
+ if (url = tinyMCEPopup.getParam("external_link_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+ },
+
+ init : function() {
+ var f = document.forms[0], ed = tinyMCEPopup.editor;
+
+ // Setup browse button
+ document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser', 'href', 'file', 'theme_advanced_link');
+ if (isVisible('hrefbrowser'))
+ document.getElementById('href').style.width = '180px';
+
+ this.fillClassList('class_list');
+ this.fillFileList('link_list', 'tinyMCELinkList');
+ this.fillTargetList('target_list');
+
+ if (e = ed.dom.getParent(ed.selection.getNode(), 'A')) {
+ f.href.value = ed.dom.getAttrib(e, 'href');
+ f.linktitle.value = ed.dom.getAttrib(e, 'title');
+ f.insert.value = ed.getLang('update');
+ selectByValue(f, 'link_list', f.href.value);
+ selectByValue(f, 'target_list', ed.dom.getAttrib(e, 'target'));
+ selectByValue(f, 'class_list', ed.dom.getAttrib(e, 'class'));
+ }
+ },
+
+ update : function() {
+ var f = document.forms[0], ed = tinyMCEPopup.editor, e, b, href = f.href.value.replace(/ /g, '%20');
+
+ tinyMCEPopup.restoreSelection();
+ e = ed.dom.getParent(ed.selection.getNode(), 'A');
+
+ // Remove element if there is no href
+ if (!f.href.value) {
+ if (e) {
+ b = ed.selection.getBookmark();
+ ed.dom.remove(e, 1);
+ ed.selection.moveToBookmark(b);
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+ return;
+ }
+ }
+
+ // Create new anchor elements
+ if (e == null) {
+ ed.getDoc().execCommand("unlink", false, null);
+ tinyMCEPopup.execCommand("mceInsertLink", false, "#mce_temp_url#", {skip_undo : 1});
+
+ tinymce.each(ed.dom.select("a"), function(n) {
+ if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') {
+ e = n;
+
+ ed.dom.setAttribs(e, {
+ href : href,
+ title : f.linktitle.value,
+ target : f.target_list ? getSelectValue(f, "target_list") : null,
+ 'class' : f.class_list ? getSelectValue(f, "class_list") : null
+ });
+ }
+ });
+ } else {
+ ed.dom.setAttribs(e, {
+ href : href,
+ title : f.linktitle.value
+ });
+
+ if (f.target_list) {
+ ed.dom.setAttrib(e, 'target', getSelectValue(f, "target_list"));
+ }
+
+ if (f.class_list) {
+ ed.dom.setAttrib(e, 'class', getSelectValue(f, "class_list"));
+ }
+ }
+
+ // Don't move caret if selection was image
+ if (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') {
+ ed.focus();
+ ed.selection.select(e);
+ ed.selection.collapse(0);
+ tinyMCEPopup.storeSelection();
+ }
+
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+ },
+
+ checkPrefix : function(n) {
+ if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_email')))
+ n.value = 'mailto:' + n.value;
+
+ if (/^\s*www\./i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_external')))
+ n.value = 'http://' + n.value;
+ },
+
+ fillFileList : function(id, l) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ l = window[l];
+
+ if (l && l.length > 0) {
+ lst.options[lst.options.length] = new Option('', '');
+
+ tinymce.each(l, function(o) {
+ lst.options[lst.options.length] = new Option(o[0], o[1]);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ fillClassList : function(id) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ if (v = tinyMCEPopup.getParam('theme_advanced_styles')) {
+ cl = [];
+
+ tinymce.each(v.split(';'), function(v) {
+ var p = v.split('=');
+
+ cl.push({'title' : p[0], 'class' : p[1]});
+ });
+ } else
+ cl = tinyMCEPopup.editor.dom.getClasses();
+
+ if (cl.length > 0) {
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+
+ tinymce.each(cl, function(o) {
+ lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ fillTargetList : function(id) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v;
+
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_same'), '_self');
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_blank'), '_blank');
+
+ if (v = tinyMCEPopup.getParam('theme_advanced_link_targets')) {
+ tinymce.each(v.split(','), function(v) {
+ v = v.split('=');
+ lst.options[lst.options.length] = new Option(v[0], v[1]);
+ });
+ }
+ }
+};
+
+LinkDialog.preInit();
+tinyMCEPopup.onInit.add(LinkDialog.init, LinkDialog);
diff --git a/src/wp-includes/js/tinymce/themes/advanced/js/source_editor.js b/src/wp-includes/js/tinymce/themes/advanced/js/source_editor.js
new file mode 100644
index 0000000000..d4179371a0
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/js/source_editor.js
@@ -0,0 +1,78 @@
+tinyMCEPopup.requireLangPack();
+tinyMCEPopup.onInit.add(onLoadInit);
+
+function saveContent() {
+ tinyMCEPopup.editor.setContent(document.getElementById('htmlSource').value, {source_view : true});
+ tinyMCEPopup.close();
+}
+
+function onLoadInit() {
+ tinyMCEPopup.resizeToInnerSize();
+
+ // Remove Gecko spellchecking
+ if (tinymce.isGecko)
+ document.body.spellcheck = tinyMCEPopup.editor.getParam("gecko_spellcheck");
+
+ document.getElementById('htmlSource').value = tinyMCEPopup.editor.getContent({source_view : true});
+
+ if (tinyMCEPopup.editor.getParam("theme_advanced_source_editor_wrap", true)) {
+ turnWrapOn();
+ document.getElementById('wraped').checked = true;
+ }
+
+ resizeInputs();
+}
+
+function setWrap(val) {
+ var v, n, s = document.getElementById('htmlSource');
+
+ s.wrap = val;
+
+ if (!tinymce.isIE) {
+ v = s.value;
+ n = s.cloneNode(false);
+ n.setAttribute("wrap", val);
+ s.parentNode.replaceChild(n, s);
+ n.value = v;
+ }
+}
+
+function setWhiteSpaceCss(value) {
+ var el = document.getElementById('htmlSource');
+ tinymce.DOM.setStyle(el, 'white-space', value);
+}
+
+function turnWrapOff() {
+ if (tinymce.isWebKit) {
+ setWhiteSpaceCss('pre');
+ } else {
+ setWrap('off');
+ }
+}
+
+function turnWrapOn() {
+ if (tinymce.isWebKit) {
+ setWhiteSpaceCss('pre-wrap');
+ } else {
+ setWrap('soft');
+ }
+}
+
+function toggleWordWrap(elm) {
+ if (elm.checked) {
+ turnWrapOn();
+ } else {
+ turnWrapOff();
+ }
+}
+
+function resizeInputs() {
+ var vp = tinyMCEPopup.dom.getViewPort(window), el;
+
+ el = document.getElementById('htmlSource');
+
+ if (el) {
+ el.style.width = (vp.w - 20) + 'px';
+ el.style.height = (vp.h - 65) + 'px';
+ }
+}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/link.htm b/src/wp-includes/js/tinymce/themes/advanced/link.htm
new file mode 100644
index 0000000000..0180002be1
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/link.htm
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.link_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="../../utils/validate.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/link.js?ver=358-20121205"></script>
+</head>
+<body id="link" style="display: none">
+<form onsubmit="LinkDialog.update();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advanced_dlg.link_title}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="nowrap"><label for="href">{#advanced_dlg.link_url}</label></td>
+ <td><table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="href" name="href" type="text" class="mceFocus" value="" style="width: 200px" onchange="LinkDialog.checkPrefix(this);" /></td>
+ <td id="hrefbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="link_list">{#advanced_dlg.link_list}</label></td>
+ <td><select id="link_list" name="link_list" onchange="document.getElementById('href').value=this.options[this.selectedIndex].value;"></select></td>
+ </tr>
+ <tr>
+ <td><label id="targetlistlabel" for="targetlist">{#advanced_dlg.link_target}</label></td>
+ <td><select id="target_list" name="target_list"></select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="linktitle">{#advanced_dlg.link_titlefield}</label></td>
+ <td><input id="linktitle" name="linktitle" type="text" value="" style="width: 200px" /></td>
+ </tr>
+ <tr>
+ <td><label for="class_list">{#class_name}</label></td>
+ <td><select id="class_list" name="class_list"></select></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/shortcuts.htm b/src/wp-includes/js/tinymce/themes/advanced/shortcuts.htm
new file mode 100644
index 0000000000..781801e058
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/shortcuts.htm
@@ -0,0 +1,47 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>{#advanced_dlg.accessibility_help}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript">tinyMCEPopup.requireLangPack();</script>
+ </head>
+ <body id="content">
+ <h1>{#advanced_dlg.accessibility_usage_title}</h1>
+ <h2>Toolbars</h2>
+ <p>Press ALT-F10 to move focus to the toolbars. Navigate through the buttons using the arrow keys.
+ Press enter to activate a button and return focus to the editor.
+ Press escape to return focus to the editor without performing any actions.</p>
+
+ <h2>Status Bar</h2>
+ <p>To access the editor status bar, press ALT-F11. Use the left and right arrow keys to navigate between elements in the path.
+ Press enter or space to select an element. Press escape to return focus to the editor without changing the selection.</p>
+
+ <h2>Context Menu</h2>
+ <p>Press shift-F10 to activate the context menu. Use the up and down arrow keys to move between menu items. To open sub-menus press the right arrow key.
+ To close submenus press the left arrow key. Press escape to close the context menu.</p>
+
+ <h1>Keyboard Shortcuts</h1>
+ <table>
+ <thead>
+ <tr>
+ <th>Keystroke</th>
+ <th>Function</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Control-B</td><td>Bold</td>
+ </tr>
+ <tr>
+ <td>Control-I</td><td>Italic</td>
+ </tr>
+ <tr>
+ <td>Control-Z</td><td>Undo</td>
+ </tr>
+ <tr>
+ <td>Control-Y</td><td>Redo</td>
+ </tr>
+ </tbody>
+ </table>
+ </body>
+</html>
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/content.css b/src/wp-includes/js/tinymce/themes/advanced/skins/default/content.css
new file mode 100644
index 0000000000..4d63ca9810
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/content.css
@@ -0,0 +1,50 @@
+body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;}
+body {background:#FFF;}
+body.mceForceColors {background:#FFF; color:#000;}
+body.mceBrowserDefaults {background:transparent; color:inherit; font-size:inherit; font-family:inherit;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; -webkit-user-select:all; -webkit-user-modify:read-only; -moz-user-select:all; -moz-user-modify:read-only; width:11px !important; height:11px !important; background:url(img/items.gif) no-repeat center center}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+/* IE */
+* html body {
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
+
+.mceItemMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc}
+.mceItemShockWave {background-image:url(../../img/shockwave.gif)}
+.mceItemFlash {background-image:url(../../img/flash.gif)}
+.mceItemQuickTime {background-image:url(../../img/quicktime.gif)}
+.mceItemWindowsMedia {background-image:url(../../img/windowsmedia.gif)}
+.mceItemRealMedia {background-image:url(../../img/realmedia.gif)}
+.mceItemVideo {background-image:url(../../img/video.gif)}
+.mceItemAudio {background-image:url(../../img/video.gif)}
+.mceItemEmbeddedAudio {background-image:url(../../img/video.gif)}
+.mceItemIframe {background-image:url(../../img/iframe.gif)}
+.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../../img/pagebreak.gif) no-repeat center top;}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/dialog.css b/src/wp-includes/js/tinymce/themes/advanced/skins/default/dialog.css
new file mode 100644
index 0000000000..8950ba3851
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/dialog.css
@@ -0,0 +1,118 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDDDDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+background:#F0F0EE;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#F0F0EE;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;}
+a:hover {color:#2B6FB6;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;}
+input.invalid {border:1px solid #EE0000;}
+input {background:#FFF; border:1px solid #CCC;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #808080;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert, #cancel, input.button, .updateButton {
+border:0; margin:0; padding:0;
+font-weight:bold;
+width:94px; height:26px;
+background:url(img/buttons.png) 0 -26px;
+cursor:pointer;
+padding-bottom:2px;
+float:left;
+}
+
+#insert {background:url(img/buttons.png) 0 -52px}
+#cancel {background:url(img/buttons.png) 0 0; float:right}
+
+/* Browse */
+a.pickcolor, a.browse {text-decoration:none}
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor:hover span.disabled {}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal; background:url(img/tabs.gif) repeat-x 0 -72px;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; background:url(img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;}
+.tabs li.current {background:url(img/tabs.gif) no-repeat 0 -18px; margin-right:2px;}
+.tabs span {float:left; display:block; background:url(img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;}
+.tabs .current span {background:url(img/tabs.gif) no-repeat right -54px;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
+#colorpicker #picker_panel fieldset {margin:auto;width:325px;}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/buttons.png b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/buttons.png
new file mode 100644
index 0000000000..1e53560e0a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/buttons.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/items.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/items.gif
new file mode 100644
index 0000000000..d2f93671ca
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/items.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif
new file mode 100644
index 0000000000..85e31dfb2d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_check.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_check.gif
new file mode 100644
index 0000000000..adfdddccd7
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/menu_check.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/progress.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/progress.gif
new file mode 100644
index 0000000000..5bb90fd6a4
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/progress.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/tabs.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/tabs.gif
new file mode 100644
index 0000000000..06812cb410
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/img/tabs.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/default/ui.css b/src/wp-includes/js/tinymce/themes/advanced/skins/default/ui.css
new file mode 100644
index 0000000000..2e8c658891
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/default/ui.css
@@ -0,0 +1,219 @@
+/* Reset */
+.defaultSkin table, .defaultSkin tbody, .defaultSkin a, .defaultSkin img, .defaultSkin tr, .defaultSkin div, .defaultSkin td, .defaultSkin iframe, .defaultSkin span, .defaultSkin *, .defaultSkin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left}
+.defaultSkin a:hover, .defaultSkin a:link, .defaultSkin a:visited, .defaultSkin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000}
+.defaultSkin table td {vertical-align:middle}
+
+/* Containers */
+.defaultSkin table {direction:ltr;background:transparent}
+.defaultSkin iframe {display:block;}
+.defaultSkin .mceToolbar {height:26px}
+.defaultSkin .mceLeft {text-align:left}
+.defaultSkin .mceRight {text-align:right}
+
+/* External */
+.defaultSkin .mceExternalToolbar {position:absolute; border:1px solid #CCC; border-bottom:0; display:none;}
+.defaultSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;}
+.defaultSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0}
+
+/* Layout */
+.defaultSkin table.mceLayout {border:0; border-left:1px solid #CCC; border-right:1px solid #CCC}
+.defaultSkin table.mceLayout tr.mceFirst td {border-top:1px solid #CCC}
+.defaultSkin table.mceLayout tr.mceLast td {border-bottom:1px solid #CCC}
+.defaultSkin table.mceToolbar, .defaultSkin tr.mceFirst .mceToolbar tr td, .defaultSkin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0;}
+.defaultSkin td.mceToolbar {background:#F0F0EE; padding-top:1px; vertical-align:top}
+.defaultSkin .mceIframeContainer {border-top:1px solid #CCC; border-bottom:1px solid #CCC}
+.defaultSkin .mceStatusbar {background:#F0F0EE; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; display:block; height:20px}
+.defaultSkin .mceStatusbar div {float:left; margin:2px}
+.defaultSkin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0}
+.defaultSkin .mceStatusbar a:hover {text-decoration:underline}
+.defaultSkin table.mceToolbar {margin-left:3px}
+.defaultSkin span.mceIcon, .defaultSkin img.mceIcon {display:block; width:20px; height:20px}
+.defaultSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px}
+.defaultSkin td.mceCenter {text-align:center;}
+.defaultSkin td.mceCenter table {margin:0 auto; text-align:left;}
+.defaultSkin td.mceRight table {margin:0 0 0 auto;}
+
+/* Button */
+.defaultSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px; margin-right:1px}
+.defaultSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0}
+.defaultSkin a.mceButtonActive, .defaultSkin a.mceButtonSelected {border:1px solid #0A246A; background-color:#C2CBE0}
+.defaultSkin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.defaultSkin .mceButtonLabeled {width:auto}
+.defaultSkin .mceButtonLabeled span.mceIcon {float:left}
+.defaultSkin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica}
+.defaultSkin .mceButtonDisabled .mceButtonLabel {color:#888}
+
+/* Separator */
+.defaultSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:2px 2px 0 4px}
+
+/* ListBox */
+.defaultSkin .mceListBox, .defaultSkin .mceListBox a {display:block}
+.defaultSkin .mceListBox .mceText {padding-left:4px; width:70px; text-align:left; border:1px solid #CCC; border-right:0; background:#FFF; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden}
+.defaultSkin .mceListBox .mceOpen {width:9px; height:20px; background:url(../../img/icons.gif) -741px 0; margin-right:2px; border:1px solid #CCC;}
+.defaultSkin table.mceListBoxEnabled:hover .mceText, .defaultSkin .mceListBoxHover .mceText, .defaultSkin .mceListBoxSelected .mceText {border:1px solid #A2ABC0; border-right:0; background:#FFF}
+.defaultSkin table.mceListBoxEnabled:hover .mceOpen, .defaultSkin .mceListBoxHover .mceOpen, .defaultSkin .mceListBoxSelected .mceOpen {background-color:#FFF; border:1px solid #A2ABC0}
+.defaultSkin .mceListBoxDisabled a.mceText {color:gray; background-color:transparent;}
+.defaultSkin .mceListBoxMenu {overflow:auto; overflow-x:hidden}
+.defaultSkin .mceOldBoxModel .mceListBox .mceText {height:22px}
+.defaultSkin .mceOldBoxModel .mceListBox .mceOpen {width:11px; height:22px;}
+.defaultSkin select.mceNativeListBox {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:7pt; background:#F0F0EE; border:1px solid gray; margin-right:2px;}
+
+/* SplitButton */
+.defaultSkin .mceSplitButton {width:32px; height:20px; direction:ltr}
+.defaultSkin .mceSplitButton a, .defaultSkin .mceSplitButton span {height:20px; display:block}
+.defaultSkin .mceSplitButton a.mceAction {width:20px; border:1px solid #F0F0EE; border-right:0;}
+.defaultSkin .mceSplitButton span.mceAction {width:20px; background-image:url(../../img/icons.gif);}
+.defaultSkin .mceSplitButton a.mceOpen {width:9px; background:url(../../img/icons.gif) -741px 0; border:1px solid #F0F0EE;}
+.defaultSkin .mceSplitButton span.mceOpen {display:none}
+.defaultSkin table.mceSplitButtonEnabled:hover a.mceAction, .defaultSkin .mceSplitButtonHover a.mceAction, .defaultSkin .mceSplitButtonSelected a.mceAction {border:1px solid #0A246A; border-right:0; background-color:#B2BBD0}
+.defaultSkin table.mceSplitButtonEnabled:hover a.mceOpen, .defaultSkin .mceSplitButtonHover a.mceOpen, .defaultSkin .mceSplitButtonSelected a.mceOpen {background-color:#B2BBD0; border:1px solid #0A246A;}
+.defaultSkin .mceSplitButtonDisabled .mceAction, .defaultSkin .mceSplitButtonDisabled a.mceOpen {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.defaultSkin .mceSplitButtonActive a.mceAction {border:1px solid #0A246A; background-color:#C2CBE0}
+.defaultSkin .mceSplitButtonActive a.mceOpen {border-left:0;}
+
+/* ColorSplitButton */
+.defaultSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray}
+.defaultSkin .mceColorSplitMenu td {padding:2px}
+.defaultSkin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080}
+.defaultSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px}
+.defaultSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF}
+.defaultSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2}
+.defaultSkin a.mceMoreColors:hover {border:1px solid #0A246A}
+.defaultSkin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a}
+.defaultSkin .mce_forecolor span.mceAction, .defaultSkin .mce_backcolor span.mceAction {overflow:hidden; height:16px}
+
+/* Menu */
+.defaultSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #D4D0C8; direction:ltr}
+.defaultSkin .mceNoIcons span.mceIcon {width:0;}
+.defaultSkin .mceNoIcons a .mceText {padding-left:10px}
+.defaultSkin .mceMenu table {background:#FFF}
+.defaultSkin .mceMenu a, .defaultSkin .mceMenu span, .defaultSkin .mceMenu {display:block}
+.defaultSkin .mceMenu td {height:20px}
+.defaultSkin .mceMenu a {position:relative;padding:3px 0 4px 0}
+.defaultSkin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block}
+.defaultSkin .mceMenu span.mceText, .defaultSkin .mceMenu .mcePreview {font-size:11px}
+.defaultSkin .mceMenu pre.mceText {font-family:Monospace}
+.defaultSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;}
+.defaultSkin .mceMenu .mceMenuItemEnabled a:hover, .defaultSkin .mceMenu .mceMenuItemActive {background-color:#dbecf3}
+.defaultSkin td.mceMenuItemSeparator {background:#DDD; height:1px}
+.defaultSkin .mceMenuItemTitle a {border:0; background:#EEE; border-bottom:1px solid #DDD}
+.defaultSkin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px}
+.defaultSkin .mceMenuItemDisabled .mceText {color:#888}
+.defaultSkin .mceMenuItemSelected .mceIcon {background:url(img/menu_check.gif)}
+.defaultSkin .mceNoIcons .mceMenuItemSelected a {background:url(img/menu_arrow.gif) no-repeat -6px center}
+.defaultSkin .mceMenu span.mceMenuLine {display:none}
+.defaultSkin .mceMenuItemSub a {background:url(img/menu_arrow.gif) no-repeat top right;}
+.defaultSkin .mceMenuItem td, .defaultSkin .mceMenuItem th {line-height: normal}
+
+/* Progress,Resize */
+.defaultSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50); background:#FFF}
+.defaultSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0}
+.mceRtl .mceMenuItem .mceText {text-align: right}
+
+/* Formats */
+.defaultSkin .mce_formatPreview a {font-size:10px}
+.defaultSkin .mce_p span.mceText {}
+.defaultSkin .mce_address span.mceText {font-style:italic}
+.defaultSkin .mce_pre span.mceText {font-family:monospace}
+.defaultSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em}
+.defaultSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em}
+.defaultSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em}
+.defaultSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em}
+.defaultSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em}
+.defaultSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em}
+
+/* Theme */
+.defaultSkin span.mce_bold {background-position:0 0}
+.defaultSkin span.mce_italic {background-position:-60px 0}
+.defaultSkin span.mce_underline {background-position:-140px 0}
+.defaultSkin span.mce_strikethrough {background-position:-120px 0}
+.defaultSkin span.mce_undo {background-position:-160px 0}
+.defaultSkin span.mce_redo {background-position:-100px 0}
+.defaultSkin span.mce_cleanup {background-position:-40px 0}
+.defaultSkin span.mce_bullist {background-position:-20px 0}
+.defaultSkin span.mce_numlist {background-position:-80px 0}
+.defaultSkin span.mce_justifyleft {background-position:-460px 0}
+.defaultSkin span.mce_justifyright {background-position:-480px 0}
+.defaultSkin span.mce_justifycenter {background-position:-420px 0}
+.defaultSkin span.mce_justifyfull {background-position:-440px 0}
+.defaultSkin span.mce_anchor {background-position:-200px 0}
+.defaultSkin span.mce_indent {background-position:-400px 0}
+.defaultSkin span.mce_outdent {background-position:-540px 0}
+.defaultSkin span.mce_link {background-position:-500px 0}
+.defaultSkin span.mce_unlink {background-position:-640px 0}
+.defaultSkin span.mce_sub {background-position:-600px 0}
+.defaultSkin span.mce_sup {background-position:-620px 0}
+.defaultSkin span.mce_removeformat {background-position:-580px 0}
+.defaultSkin span.mce_newdocument {background-position:-520px 0}
+.defaultSkin span.mce_image {background-position:-380px 0}
+.defaultSkin span.mce_help {background-position:-340px 0}
+.defaultSkin span.mce_code {background-position:-260px 0}
+.defaultSkin span.mce_hr {background-position:-360px 0}
+.defaultSkin span.mce_visualaid {background-position:-660px 0}
+.defaultSkin span.mce_charmap {background-position:-240px 0}
+.defaultSkin span.mce_paste {background-position:-560px 0}
+.defaultSkin span.mce_copy {background-position:-700px 0}
+.defaultSkin span.mce_cut {background-position:-680px 0}
+.defaultSkin span.mce_blockquote {background-position:-220px 0}
+.defaultSkin .mce_forecolor span.mceAction {background-position:-720px 0}
+.defaultSkin .mce_backcolor span.mceAction {background-position:-760px 0}
+.defaultSkin span.mce_forecolorpicker {background-position:-720px 0}
+.defaultSkin span.mce_backcolorpicker {background-position:-760px 0}
+
+/* Plugins */
+.defaultSkin span.mce_advhr {background-position:-0px -20px}
+.defaultSkin span.mce_ltr {background-position:-20px -20px}
+.defaultSkin span.mce_rtl {background-position:-40px -20px}
+.defaultSkin span.mce_emotions {background-position:-60px -20px}
+.defaultSkin span.mce_fullpage {background-position:-80px -20px}
+.defaultSkin span.mce_fullscreen {background-position:-100px -20px}
+.defaultSkin span.mce_iespell {background-position:-120px -20px}
+.defaultSkin span.mce_insertdate {background-position:-140px -20px}
+.defaultSkin span.mce_inserttime {background-position:-160px -20px}
+.defaultSkin span.mce_absolute {background-position:-180px -20px}
+.defaultSkin span.mce_backward {background-position:-200px -20px}
+.defaultSkin span.mce_forward {background-position:-220px -20px}
+.defaultSkin span.mce_insert_layer {background-position:-240px -20px}
+.defaultSkin span.mce_insertlayer {background-position:-260px -20px}
+.defaultSkin span.mce_movebackward {background-position:-280px -20px}
+.defaultSkin span.mce_moveforward {background-position:-300px -20px}
+.defaultSkin span.mce_media {background-position:-320px -20px}
+.defaultSkin span.mce_nonbreaking {background-position:-340px -20px}
+.defaultSkin span.mce_pastetext {background-position:-360px -20px}
+.defaultSkin span.mce_pasteword {background-position:-380px -20px}
+.defaultSkin span.mce_selectall {background-position:-400px -20px}
+.defaultSkin span.mce_preview {background-position:-420px -20px}
+.defaultSkin span.mce_print {background-position:-440px -20px}
+.defaultSkin span.mce_cancel {background-position:-460px -20px}
+.defaultSkin span.mce_save {background-position:-480px -20px}
+.defaultSkin span.mce_replace {background-position:-500px -20px}
+.defaultSkin span.mce_search {background-position:-520px -20px}
+.defaultSkin span.mce_styleprops {background-position:-560px -20px}
+.defaultSkin span.mce_table {background-position:-580px -20px}
+.defaultSkin span.mce_cell_props {background-position:-600px -20px}
+.defaultSkin span.mce_delete_table {background-position:-620px -20px}
+.defaultSkin span.mce_delete_col {background-position:-640px -20px}
+.defaultSkin span.mce_delete_row {background-position:-660px -20px}
+.defaultSkin span.mce_col_after {background-position:-680px -20px}
+.defaultSkin span.mce_col_before {background-position:-700px -20px}
+.defaultSkin span.mce_row_after {background-position:-720px -20px}
+.defaultSkin span.mce_row_before {background-position:-740px -20px}
+.defaultSkin span.mce_merge_cells {background-position:-760px -20px}
+.defaultSkin span.mce_table_props {background-position:-980px -20px}
+.defaultSkin span.mce_row_props {background-position:-780px -20px}
+.defaultSkin span.mce_split_cells {background-position:-800px -20px}
+.defaultSkin span.mce_template {background-position:-820px -20px}
+.defaultSkin span.mce_visualchars {background-position:-840px -20px}
+.defaultSkin span.mce_abbr {background-position:-860px -20px}
+.defaultSkin span.mce_acronym {background-position:-880px -20px}
+.defaultSkin span.mce_attribs {background-position:-900px -20px}
+.defaultSkin span.mce_cite {background-position:-920px -20px}
+.defaultSkin span.mce_del {background-position:-940px -20px}
+.defaultSkin span.mce_ins {background-position:-960px -20px}
+.defaultSkin span.mce_pagebreak {background-position:0 -40px}
+.defaultSkin span.mce_restoredraft {background-position:-20px -40px}
+.defaultSkin span.mce_spellchecker {background-position:-540px -20px}
+.defaultSkin span.mce_visualblocks {background-position: -40px -40px}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/content.css b/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/content.css
new file mode 100644
index 0000000000..ee3d369d02
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/content.css
@@ -0,0 +1,24 @@
+body, td, pre { margin:8px;}
+body.mceForceColors {background:#FFF; color:#000;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/dialog.css b/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/dialog.css
new file mode 100644
index 0000000000..fa3c31a05d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/dialog.css
@@ -0,0 +1,106 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+background:#F0F0EE;
+color: black;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#F0F0EE; color:#000;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;background-color:transparent;}
+a:hover {color:#2B6FB6;background-color:transparent;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;background-color:transparent;}
+input.invalid {border:1px solid #EE0000;background-color:transparent;}
+input {background:#FFF; border:1px solid #CCC;color:black;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #808080;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert, #cancel, input.button, .updateButton {
+font-weight:bold;
+width:94px; height:23px;
+cursor:pointer;
+padding-bottom:2px;
+float:left;
+}
+
+#cancel {float:right}
+
+/* Browse */
+a.pickcolor, a.browse {text-decoration:none}
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor:hover span.disabled {}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; border: 1px solid black; border-bottom:0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block; cursor:pointer;}
+.tabs li.current {font-weight: bold; margin-right:2px;}
+.tabs span {float:left; display:block; padding:0px 10px 0 0;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/ui.css b/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/ui.css
new file mode 100644
index 0000000000..86829c59c1
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/highcontrast/ui.css
@@ -0,0 +1,106 @@
+/* Reset */
+.highcontrastSkin table, .highcontrastSkin tbody, .highcontrastSkin a, .highcontrastSkin img, .highcontrastSkin tr, .highcontrastSkin div, .highcontrastSkin td, .highcontrastSkin iframe, .highcontrastSkin span, .highcontrastSkin *, .highcontrastSkin .mceText {border:0; margin:0; padding:0; vertical-align:baseline; border-collapse:separate;}
+.highcontrastSkin a:hover, .highcontrastSkin a:link, .highcontrastSkin a:visited, .highcontrastSkin a:active {text-decoration:none; font-weight:normal; cursor:default;}
+.highcontrastSkin table td {vertical-align:middle}
+
+.highcontrastSkin .mceIconOnly {display: block !important;}
+
+/* External */
+.highcontrastSkin .mceExternalToolbar {position:absolute; border:1px solid; border-bottom:0; display:none; background-color: white;}
+.highcontrastSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;}
+.highcontrastSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px;}
+
+/* Layout */
+.highcontrastSkin table.mceLayout {border: 1px solid;}
+.highcontrastSkin .mceIframeContainer {border-top:1px solid; border-bottom:1px solid}
+.highcontrastSkin .mceStatusbar a:hover {text-decoration:underline}
+.highcontrastSkin .mceStatusbar {display:block; line-height:1.5em; overflow:visible;}
+.highcontrastSkin .mceStatusbar div {float:left}
+.highcontrastSkin .mceStatusbar a.mceResize {display:block; float:right; width:20px; height:20px; cursor:se-resize; outline:0}
+
+.highcontrastSkin .mceToolbar td { display: inline-block; float: left;}
+.highcontrastSkin .mceToolbar tr { display: block;}
+.highcontrastSkin .mceToolbar table { display: block; }
+
+/* Button */
+
+.highcontrastSkin .mceButton { display:block; margin: 2px; padding: 5px 10px;border: 1px solid; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -ms-border-radius: 3px; height: 2em;}
+.highcontrastSkin .mceButton .mceVoiceLabel { height: 100%; vertical-align: center; line-height: 2em}
+.highcontrastSkin .mceButtonDisabled .mceVoiceLabel { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);}
+.highcontrastSkin .mceButtonActive, .highcontrastSkin .mceButton:focus, .highcontrastSkin .mceButton:active { border: 5px solid; padding: 1px 6px;-webkit-focus-ring-color:none;outline:none;}
+
+/* Separator */
+.highcontrastSkin .mceSeparator {display:block; width:16px; height:26px;}
+
+/* ListBox */
+.highcontrastSkin .mceListBox { display: block; margin:2px;-webkit-focus-ring-color:none;outline:none;}
+.highcontrastSkin .mceListBox .mceText {padding: 5px 6px; line-height: 2em; width: 15ex; overflow: hidden;}
+.highcontrastSkin .mceListBoxDisabled .mceText { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);}
+.highcontrastSkin .mceListBox a.mceText { padding: 5px 10px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;}
+.highcontrastSkin .mceListBox a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-left: 0; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;}
+.highcontrastSkin .mceListBox:focus a.mceText, .highcontrastSkin .mceListBox:active a.mceText { border-width: 5px; padding: 1px 10px 1px 6px;}
+.highcontrastSkin .mceListBox:focus a.mceOpen, .highcontrastSkin .mceListBox:active a.mceOpen { border-width: 5px; padding: 1px 0px 1px 4px;}
+
+.highcontrastSkin .mceListBoxMenu {overflow-y:auto}
+
+/* SplitButton */
+.highcontrastSkin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+
+.highcontrastSkin .mceSplitButton { border-collapse: collapse; margin: 2px; height: 2em; line-height: 2em;-webkit-focus-ring-color:none;outline:none;}
+.highcontrastSkin .mceSplitButton td { display: table-cell; float: none; margin: 0; padding: 0; height: 2em;}
+.highcontrastSkin .mceSplitButton tr { display: table-row; }
+.highcontrastSkin table.mceSplitButton { display: table; }
+.highcontrastSkin .mceSplitButton a.mceAction { padding: 5px 10px; display: block; height: 2em; line-height: 2em; overflow: hidden; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;}
+.highcontrastSkin .mceSplitButton a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;}
+.highcontrastSkin .mceSplitButton .mceVoiceLabel { height: 2em; vertical-align: center; line-height: 2em; }
+.highcontrastSkin .mceSplitButton:focus a.mceAction, .highcontrastSkin .mceSplitButton:active a.mceAction { border-width: 5px; border-right-width: 1px; padding: 1px 10px 1px 6px;-webkit-focus-ring-color:none;outline:none;}
+.highcontrastSkin .mceSplitButton:focus a.mceOpen, .highcontrastSkin .mceSplitButton:active a.mceOpen { border-width: 5px; border-left-width: 1px; padding: 1px 0px 1px 4px;-webkit-focus-ring-color:none;outline:none;}
+
+/* Menu */
+.highcontrastSkin .mceNoIcons span.mceIcon {width:0;}
+.highcontrastSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid; direction:ltr}
+.highcontrastSkin .mceMenu table {background:white; color: black}
+.highcontrastSkin .mceNoIcons a .mceText {padding-left:10px}
+.highcontrastSkin .mceMenu a, .highcontrastSkin .mceMenu span, .highcontrastSkin .mceMenu {display:block;background:white; color: black}
+.highcontrastSkin .mceMenu td {height:2em}
+.highcontrastSkin .mceMenu a {position:relative;padding:3px 0 4px 0; display: block;}
+.highcontrastSkin .mceMenu .mceText {position:relative; display:block; cursor:default; margin:0; padding:0 25px 0 25px;}
+.highcontrastSkin .mceMenu pre.mceText {font-family:Monospace}
+.highcontrastSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:26px;}
+.highcontrastSkin td.mceMenuItemSeparator {border-top:1px solid; height:1px}
+.highcontrastSkin .mceMenuItemTitle a {border:0; border-bottom:1px solid}
+.highcontrastSkin .mceMenuItemTitle span.mceText {font-weight:bold; padding-left:4px}
+.highcontrastSkin .mceNoIcons .mceMenuItemSelected span.mceText:before {content: "\2713\A0";}
+.highcontrastSkin .mceMenu span.mceMenuLine {display:none}
+.highcontrastSkin .mceMenuItemSub a .mceText:after {content: "\A0\25B8"}
+.highcontrastSkin .mceMenuItem td, .highcontrastSkin .mceMenuItem th {line-height: normal}
+
+/* ColorSplitButton */
+.highcontrastSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid; color: #000}
+.highcontrastSkin .mceColorSplitMenu td {padding:2px}
+.highcontrastSkin .mceColorSplitMenu a {display:block; width:16px; height:16px; overflow:hidden; color:#000; margin: 0; padding: 0;}
+.highcontrastSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px}
+.highcontrastSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF}
+.highcontrastSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid; background-color:#B6BDD2}
+.highcontrastSkin a.mceMoreColors:hover {border:1px solid #0A246A; color: #000;}
+.highcontrastSkin .mceColorPreview {display:none;}
+.highcontrastSkin .mce_forecolor span.mceAction, .highcontrastSkin .mce_backcolor span.mceAction {height:17px;overflow:hidden}
+
+/* Progress,Resize */
+.highcontrastSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF}
+.highcontrastSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0}
+.mceRtl .mceMenuItem .mceText {text-align: right}
+
+/* Formats */
+.highcontrastSkin .mce_p span.mceText {}
+.highcontrastSkin .mce_address span.mceText {font-style:italic}
+.highcontrastSkin .mce_pre span.mceText {font-family:monospace}
+.highcontrastSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em}
+.highcontrastSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em}
+.highcontrastSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em}
+.highcontrastSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em}
+.highcontrastSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em}
+.highcontrastSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/content.css b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/content.css
new file mode 100644
index 0000000000..631fa0ec87
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/content.css
@@ -0,0 +1,48 @@
+body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;}
+body {background:#FFF;}
+body.mceForceColors {background:#FFF; color:#000;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+/* IE */
+* html body {
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
+
+.mceItemMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc}
+.mceItemShockWave {background-image:url(../../img/shockwave.gif)}
+.mceItemFlash {background-image:url(../../img/flash.gif)}
+.mceItemQuickTime {background-image:url(../../img/quicktime.gif)}
+.mceItemWindowsMedia {background-image:url(../../img/windowsmedia.gif)}
+.mceItemRealMedia {background-image:url(../../img/realmedia.gif)}
+.mceItemVideo {background-image:url(../../img/video.gif)}
+.mceItemAudio {background-image:url(../../img/video.gif)}
+.mceItemIframe {background-image:url(../../img/iframe.gif)}
+.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../../img/pagebreak.gif) no-repeat center top;}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/dialog.css b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/dialog.css
new file mode 100644
index 0000000000..84d2fe9722
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/dialog.css
@@ -0,0 +1,118 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDDDDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+background:#F0F0EE;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#F0F0EE;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;}
+a:hover {color:#2B6FB6;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;}
+input.invalid {border:1px solid #EE0000;}
+input {background:#FFF; border:1px solid #CCC;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #808080;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert, #cancel, input.button, .updateButton {
+border:0; margin:0; padding:0;
+font-weight:bold;
+width:94px; height:26px;
+background:url(../default/img/buttons.png) 0 -26px;
+cursor:pointer;
+padding-bottom:2px;
+float:left;
+}
+
+#insert {background:url(../default/img/buttons.png) 0 -52px}
+#cancel {background:url(../default/img/buttons.png) 0 0; float:right}
+
+/* Browse */
+a.pickcolor, a.browse {text-decoration:none}
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor:hover span.disabled {}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal; background:url(../default/img/tabs.gif) repeat-x 0 -72px;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; background:url(../default/img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;}
+.tabs li.current {background:url(../default/img/tabs.gif) no-repeat 0 -18px; margin-right:2px;}
+.tabs span {float:left; display:block; background:url(../default/img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;}
+.tabs .current span {background:url(../default/img/tabs.gif) no-repeat right -54px;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
+#colorpicker #picker_panel fieldset {margin:auto;width:325px;}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.png b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.png
new file mode 100644
index 0000000000..13a5cb0309
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.png b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.png
new file mode 100644
index 0000000000..7fc57f2bc2
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.png b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.png
new file mode 100644
index 0000000000..c0dcc6cac2
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui.css b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui.css
new file mode 100644
index 0000000000..abd5d8deba
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui.css
@@ -0,0 +1,222 @@
+/* Reset */
+.o2k7Skin table, .o2k7Skin tbody, .o2k7Skin a, .o2k7Skin img, .o2k7Skin tr, .o2k7Skin div, .o2k7Skin td, .o2k7Skin iframe, .o2k7Skin span, .o2k7Skin *, .o2k7Skin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left}
+.o2k7Skin a:hover, .o2k7Skin a:link, .o2k7Skin a:visited, .o2k7Skin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000}
+.o2k7Skin table td {vertical-align:middle}
+
+/* Containers */
+.o2k7Skin table {background:transparent}
+.o2k7Skin iframe {display:block;}
+.o2k7Skin .mceToolbar {height:26px}
+
+/* External */
+.o2k7Skin .mceExternalToolbar {position:absolute; border:1px solid #ABC6DD; border-bottom:0; display:none}
+.o2k7Skin .mceExternalToolbar td.mceToolbar {padding-right:13px;}
+.o2k7Skin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0}
+
+/* Layout */
+.o2k7Skin table.mceLayout {border:0; border-left:1px solid #ABC6DD; border-right:1px solid #ABC6DD}
+.o2k7Skin table.mceLayout tr.mceFirst td {border-top:1px solid #ABC6DD}
+.o2k7Skin table.mceLayout tr.mceLast td {border-bottom:1px solid #ABC6DD}
+.o2k7Skin table.mceToolbar, .o2k7Skin tr.mceFirst .mceToolbar tr td, .o2k7Skin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0}
+.o2k7Skin .mceIframeContainer {border-top:1px solid #ABC6DD; border-bottom:1px solid #ABC6DD}
+.o2k7Skin td.mceToolbar{background:#E5EFFD}
+.o2k7Skin .mceStatusbar {background:#E5EFFD; display:block; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; height:20px}
+.o2k7Skin .mceStatusbar div {float:left; padding:2px}
+.o2k7Skin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0}
+.o2k7Skin .mceStatusbar a:hover {text-decoration:underline}
+.o2k7Skin table.mceToolbar {margin-left:3px}
+.o2k7Skin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; margin-left:3px;}
+.o2k7Skin .mceToolbar td.mceFirst span {margin:0}
+.o2k7Skin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px}
+.o2k7Skin .mceToolbar .mceToolbarEndListBox span, .o2k7Skin .mceToolbar .mceToolbarStartListBox span {display:none}
+.o2k7Skin span.mceIcon, .o2k7Skin img.mceIcon {display:block; width:20px; height:20px}
+.o2k7Skin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px}
+.o2k7Skin td.mceCenter {text-align:center;}
+.o2k7Skin td.mceCenter table {margin:0 auto; text-align:left;}
+.o2k7Skin td.mceRight table {margin:0 0 0 auto;}
+
+/* Button */
+.o2k7Skin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px}
+.o2k7Skin a.mceButton span, .o2k7Skin a.mceButton img {margin-left:1px}
+.o2k7Skin .mceOldBoxModel a.mceButton span, .o2k7Skin .mceOldBoxModel a.mceButton img {margin:0 0 0 1px}
+.o2k7Skin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px}
+.o2k7Skin a.mceButtonActive, .o2k7Skin a.mceButtonSelected {background-position:0 -44px}
+.o2k7Skin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.o2k7Skin .mceButtonLabeled {width:auto}
+.o2k7Skin .mceButtonLabeled span.mceIcon {float:left}
+.o2k7Skin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica}
+.o2k7Skin .mceButtonDisabled .mceButtonLabel {color:#888}
+
+/* Separator */
+.o2k7Skin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px}
+
+/* ListBox */
+.o2k7Skin .mceListBox {padding-left: 3px}
+.o2k7Skin .mceListBox, .o2k7Skin .mceListBox a {display:block}
+.o2k7Skin .mceListBox .mceText {padding-left:4px; text-align:left; width:70px; border:1px solid #b3c7e1; border-right:0; background:#eaf2fb; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden}
+.o2k7Skin .mceListBox .mceOpen {width:14px; height:22px; background:url(img/button_bg.png) -66px 0}
+.o2k7Skin table.mceListBoxEnabled:hover .mceText, .o2k7Skin .mceListBoxHover .mceText, .o2k7Skin .mceListBoxSelected .mceText {background:#FFF}
+.o2k7Skin table.mceListBoxEnabled:hover .mceOpen, .o2k7Skin .mceListBoxHover .mceOpen, .o2k7Skin .mceListBoxSelected .mceOpen {background-position:-66px -22px}
+.o2k7Skin .mceListBoxDisabled .mceText {color:gray}
+.o2k7Skin .mceListBoxMenu {overflow:auto; overflow-x:hidden; margin-left:3px}
+.o2k7Skin .mceOldBoxModel .mceListBox .mceText {height:22px}
+.o2k7Skin select.mceListBox {font-family:Tahoma,Verdana,Arial,Helvetica; font-size:12px; border:1px solid #b3c7e1; background:#FFF;}
+
+/* SplitButton */
+.o2k7Skin .mceSplitButton, .o2k7Skin .mceSplitButton a, .o2k7Skin .mceSplitButton span {display:block; height:22px; direction:ltr}
+.o2k7Skin .mceSplitButton {background:url(img/button_bg.png)}
+.o2k7Skin .mceSplitButton a.mceAction {width:22px}
+.o2k7Skin .mceSplitButton span.mceAction {width:22px; background-image:url(../../img/icons.gif)}
+.o2k7Skin .mceSplitButton a.mceOpen {width:10px; background:url(img/button_bg.png) -44px 0}
+.o2k7Skin .mceSplitButton span.mceOpen {display:none}
+.o2k7Skin table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background:url(img/button_bg.png) 0 -22px}
+.o2k7Skin table.mceSplitButtonEnabled:hover a.mceOpen, .o2k7Skin .mceSplitButtonHover a.mceOpen, .o2k7Skin .mceSplitButtonSelected a.mceOpen {background-position:-44px -44px}
+.o2k7Skin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.o2k7Skin .mceSplitButtonActive {background-position:0 -44px}
+
+/* ColorSplitButton */
+.o2k7Skin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray}
+.o2k7Skin .mceColorSplitMenu td {padding:2px}
+.o2k7Skin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080}
+.o2k7Skin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px}
+.o2k7Skin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF}
+.o2k7Skin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2}
+.o2k7Skin a.mceMoreColors:hover {border:1px solid #0A246A}
+.o2k7Skin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a;overflow:hidden}
+.o2k7Skin .mce_forecolor span.mceAction, .o2k7Skin .mce_backcolor span.mceAction {height:15px;overflow:hidden}
+
+/* Menu */
+.o2k7Skin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #ABC6DD; direction:ltr}
+.o2k7Skin .mceNoIcons span.mceIcon {width:0;}
+.o2k7Skin .mceNoIcons a .mceText {padding-left:10px}
+.o2k7Skin .mceMenu table {background:#FFF}
+.o2k7Skin .mceMenu a, .o2k7Skin .mceMenu span, .o2k7Skin .mceMenu {display:block}
+.o2k7Skin .mceMenu td {height:20px}
+.o2k7Skin .mceMenu a {position:relative;padding:3px 0 4px 0}
+.o2k7Skin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block}
+.o2k7Skin .mceMenu span.mceText, .o2k7Skin .mceMenu .mcePreview {font-size:11px}
+.o2k7Skin .mceMenu pre.mceText {font-family:Monospace}
+.o2k7Skin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;}
+.o2k7Skin .mceMenu .mceMenuItemEnabled a:hover, .o2k7Skin .mceMenu .mceMenuItemActive {background-color:#dbecf3}
+.o2k7Skin td.mceMenuItemSeparator {background:#DDD; height:1px}
+.o2k7Skin .mceMenuItemTitle a {border:0; background:#E5EFFD; border-bottom:1px solid #ABC6DD}
+.o2k7Skin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px}
+.o2k7Skin .mceMenuItemDisabled .mceText {color:#888}
+.o2k7Skin .mceMenuItemSelected .mceIcon {background:url(../default/img/menu_check.gif)}
+.o2k7Skin .mceNoIcons .mceMenuItemSelected a {background:url(../default/img/menu_arrow.gif) no-repeat -6px center}
+.o2k7Skin .mceMenu span.mceMenuLine {display:none}
+.o2k7Skin .mceMenuItemSub a {background:url(../default/img/menu_arrow.gif) no-repeat top right;}
+.o2k7Skin .mceMenuItem td, .o2k7Skin .mceMenuItem th {line-height: normal}
+
+/* Progress,Resize */
+.o2k7Skin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF}
+.o2k7Skin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0}
+.mceRtl .mceMenuItem .mceText {text-align: right}
+
+/* Formats */
+.o2k7Skin .mce_formatPreview a {font-size:10px}
+.o2k7Skin .mce_p span.mceText {}
+.o2k7Skin .mce_address span.mceText {font-style:italic}
+.o2k7Skin .mce_pre span.mceText {font-family:monospace}
+.o2k7Skin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em}
+.o2k7Skin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em}
+.o2k7Skin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em}
+.o2k7Skin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em}
+.o2k7Skin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em}
+.o2k7Skin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em}
+
+/* Theme */
+.o2k7Skin span.mce_bold {background-position:0 0}
+.o2k7Skin span.mce_italic {background-position:-60px 0}
+.o2k7Skin span.mce_underline {background-position:-140px 0}
+.o2k7Skin span.mce_strikethrough {background-position:-120px 0}
+.o2k7Skin span.mce_undo {background-position:-160px 0}
+.o2k7Skin span.mce_redo {background-position:-100px 0}
+.o2k7Skin span.mce_cleanup {background-position:-40px 0}
+.o2k7Skin span.mce_bullist {background-position:-20px 0}
+.o2k7Skin span.mce_numlist {background-position:-80px 0}
+.o2k7Skin span.mce_justifyleft {background-position:-460px 0}
+.o2k7Skin span.mce_justifyright {background-position:-480px 0}
+.o2k7Skin span.mce_justifycenter {background-position:-420px 0}
+.o2k7Skin span.mce_justifyfull {background-position:-440px 0}
+.o2k7Skin span.mce_anchor {background-position:-200px 0}
+.o2k7Skin span.mce_indent {background-position:-400px 0}
+.o2k7Skin span.mce_outdent {background-position:-540px 0}
+.o2k7Skin span.mce_link {background-position:-500px 0}
+.o2k7Skin span.mce_unlink {background-position:-640px 0}
+.o2k7Skin span.mce_sub {background-position:-600px 0}
+.o2k7Skin span.mce_sup {background-position:-620px 0}
+.o2k7Skin span.mce_removeformat {background-position:-580px 0}
+.o2k7Skin span.mce_newdocument {background-position:-520px 0}
+.o2k7Skin span.mce_image {background-position:-380px 0}
+.o2k7Skin span.mce_help {background-position:-340px 0}
+.o2k7Skin span.mce_code {background-position:-260px 0}
+.o2k7Skin span.mce_hr {background-position:-360px 0}
+.o2k7Skin span.mce_visualaid {background-position:-660px 0}
+.o2k7Skin span.mce_charmap {background-position:-240px 0}
+.o2k7Skin span.mce_paste {background-position:-560px 0}
+.o2k7Skin span.mce_copy {background-position:-700px 0}
+.o2k7Skin span.mce_cut {background-position:-680px 0}
+.o2k7Skin span.mce_blockquote {background-position:-220px 0}
+.o2k7Skin .mce_forecolor span.mceAction {background-position:-720px 0}
+.o2k7Skin .mce_backcolor span.mceAction {background-position:-760px 0}
+.o2k7Skin span.mce_forecolorpicker {background-position:-720px 0}
+.o2k7Skin span.mce_backcolorpicker {background-position:-760px 0}
+
+/* Plugins */
+.o2k7Skin span.mce_advhr {background-position:-0px -20px}
+.o2k7Skin span.mce_ltr {background-position:-20px -20px}
+.o2k7Skin span.mce_rtl {background-position:-40px -20px}
+.o2k7Skin span.mce_emotions {background-position:-60px -20px}
+.o2k7Skin span.mce_fullpage {background-position:-80px -20px}
+.o2k7Skin span.mce_fullscreen {background-position:-100px -20px}
+.o2k7Skin span.mce_iespell {background-position:-120px -20px}
+.o2k7Skin span.mce_insertdate {background-position:-140px -20px}
+.o2k7Skin span.mce_inserttime {background-position:-160px -20px}
+.o2k7Skin span.mce_absolute {background-position:-180px -20px}
+.o2k7Skin span.mce_backward {background-position:-200px -20px}
+.o2k7Skin span.mce_forward {background-position:-220px -20px}
+.o2k7Skin span.mce_insert_layer {background-position:-240px -20px}
+.o2k7Skin span.mce_insertlayer {background-position:-260px -20px}
+.o2k7Skin span.mce_movebackward {background-position:-280px -20px}
+.o2k7Skin span.mce_moveforward {background-position:-300px -20px}
+.o2k7Skin span.mce_media {background-position:-320px -20px}
+.o2k7Skin span.mce_nonbreaking {background-position:-340px -20px}
+.o2k7Skin span.mce_pastetext {background-position:-360px -20px}
+.o2k7Skin span.mce_pasteword {background-position:-380px -20px}
+.o2k7Skin span.mce_selectall {background-position:-400px -20px}
+.o2k7Skin span.mce_preview {background-position:-420px -20px}
+.o2k7Skin span.mce_print {background-position:-440px -20px}
+.o2k7Skin span.mce_cancel {background-position:-460px -20px}
+.o2k7Skin span.mce_save {background-position:-480px -20px}
+.o2k7Skin span.mce_replace {background-position:-500px -20px}
+.o2k7Skin span.mce_search {background-position:-520px -20px}
+.o2k7Skin span.mce_styleprops {background-position:-560px -20px}
+.o2k7Skin span.mce_table {background-position:-580px -20px}
+.o2k7Skin span.mce_cell_props {background-position:-600px -20px}
+.o2k7Skin span.mce_delete_table {background-position:-620px -20px}
+.o2k7Skin span.mce_delete_col {background-position:-640px -20px}
+.o2k7Skin span.mce_delete_row {background-position:-660px -20px}
+.o2k7Skin span.mce_col_after {background-position:-680px -20px}
+.o2k7Skin span.mce_col_before {background-position:-700px -20px}
+.o2k7Skin span.mce_row_after {background-position:-720px -20px}
+.o2k7Skin span.mce_row_before {background-position:-740px -20px}
+.o2k7Skin span.mce_merge_cells {background-position:-760px -20px}
+.o2k7Skin span.mce_table_props {background-position:-980px -20px}
+.o2k7Skin span.mce_row_props {background-position:-780px -20px}
+.o2k7Skin span.mce_split_cells {background-position:-800px -20px}
+.o2k7Skin span.mce_template {background-position:-820px -20px}
+.o2k7Skin span.mce_visualchars {background-position:-840px -20px}
+.o2k7Skin span.mce_abbr {background-position:-860px -20px}
+.o2k7Skin span.mce_acronym {background-position:-880px -20px}
+.o2k7Skin span.mce_attribs {background-position:-900px -20px}
+.o2k7Skin span.mce_cite {background-position:-920px -20px}
+.o2k7Skin span.mce_del {background-position:-940px -20px}
+.o2k7Skin span.mce_ins {background-position:-960px -20px}
+.o2k7Skin span.mce_pagebreak {background-position:0 -40px}
+.o2k7Skin span.mce_restoredraft {background-position:-20px -40px}
+.o2k7Skin span.mce_spellchecker {background-position:-540px -20px}
+.o2k7Skin span.mce_visualblocks {background-position: -40px -40px}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_black.css b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_black.css
new file mode 100644
index 0000000000..85812cde3f
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_black.css
@@ -0,0 +1,8 @@
+/* Black */
+.o2k7SkinBlack .mceToolbar .mceToolbarStart span, .o2k7SkinBlack .mceToolbar .mceToolbarEnd span, .o2k7SkinBlack .mceButton, .o2k7SkinBlack .mceSplitButton, .o2k7SkinBlack .mceSeparator, .o2k7SkinBlack .mceSplitButton a.mceOpen, .o2k7SkinBlack .mceListBox a.mceOpen {background-image:url(img/button_bg_black.png)}
+.o2k7SkinBlack td.mceToolbar, .o2k7SkinBlack td.mceStatusbar, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack .mceMenuItemTitle span.mceText, .o2k7SkinBlack .mceStatusbar div, .o2k7SkinBlack .mceStatusbar span, .o2k7SkinBlack .mceStatusbar a {background:#535353; color:#FFF}
+.o2k7SkinBlack table.mceListBoxEnabled .mceText, o2k7SkinBlack .mceListBox .mceText {background:#FFF; border:1px solid #CBCFD4; border-bottom-color:#989FA9; border-right:0}
+.o2k7SkinBlack table.mceListBoxEnabled:hover .mceText, .o2k7SkinBlack .mceListBoxHover .mceText, .o2k7SkinBlack .mceListBoxSelected .mceText {background:#FFF; border:1px solid #FFBD69; border-right:0}
+.o2k7SkinBlack .mceExternalToolbar, .o2k7SkinBlack .mceListBox .mceText, .o2k7SkinBlack div.mceMenu, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceFirst td, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceLast td, .o2k7SkinBlack .mceIframeContainer {border-color: #535353;}
+.o2k7SkinBlack table.mceSplitButtonEnabled:hover a.mceAction, .o2k7SkinBlack .mceSplitButtonHover a.mceAction, .o2k7SkinBlack .mceSplitButtonSelected {background-image:url(img/button_bg_black.png)}
+.o2k7SkinBlack .mceMenu .mceMenuItemEnabled a:hover, .o2k7SkinBlack .mceMenu .mceMenuItemActive {background-color:#FFE7A1} \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css
new file mode 100644
index 0000000000..d64c361693
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css
@@ -0,0 +1,5 @@
+/* Silver */
+.o2k7SkinSilver .mceToolbar .mceToolbarStart span, .o2k7SkinSilver .mceButton, .o2k7SkinSilver .mceSplitButton, .o2k7SkinSilver .mceSeparator, .o2k7SkinSilver .mceSplitButton a.mceOpen, .o2k7SkinSilver .mceListBox a.mceOpen {background-image:url(img/button_bg_silver.png)}
+.o2k7SkinSilver td.mceToolbar, .o2k7SkinSilver td.mceStatusbar, .o2k7SkinSilver .mceMenuItemTitle a {background:#eee}
+.o2k7SkinSilver .mceListBox .mceText {background:#FFF}
+.o2k7SkinSilver .mceExternalToolbar, .o2k7SkinSilver .mceListBox .mceText, .o2k7SkinSilver div.mceMenu, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceFirst td, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceLast td, .o2k7SkinSilver .mceIframeContainer {border-color: #bbb}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css
new file mode 100644
index 0000000000..c979af99b5
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/content.css
@@ -0,0 +1,132 @@
+
+body.mceForceColors {background:#FFF; color:#000;}
+body.mceBrowserDefaults {background:transparent; color:inherit; font-size:inherit; font-family:inherit;}
+td {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; -webkit-user-select:all; -webkit-user-modify:read-only; -moz-user-select:all; -moz-user-modify:read-only; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat center center}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
+
+.mceItemMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc}
+.mceItemShockWave {background-image:url(../../img/shockwave.gif)}
+.mceItemFlash {background-image:url(../../img/flash.gif)}
+.mceItemQuickTime {background-image:url(../../img/quicktime.gif)}
+.mceItemWindowsMedia {background-image:url(../../img/windowsmedia.gif)}
+.mceItemRealMedia {background-image:url(../../img/realmedia.gif)}
+.mceItemVideo {background-image:url(../../img/video.gif)}
+.mceItemAudio {background-image:url(../../img/video.gif)}
+.mceItemIframe {background-image:url(../../img/iframe.gif)}
+.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../../img/pagebreak.gif) no-repeat center top;}
+
+/* WordPress styles */
+body {
+ font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
+ font-size: 13px;
+ line-height: 19px;
+ color: #333;
+ margin: 10px;
+}
+
+.aligncenter,
+dl.aligncenter {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.alignleft {
+ float: left;
+}
+
+.alignright {
+ float: right;
+}
+
+.wp-caption {
+ border: 1px solid #ddd;
+ text-align: center;
+ background-color: #f3f3f3;
+ padding-top: 4px;
+ margin: 10px 0;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.mceIEcenter {
+ text-align: center;
+}
+
+.wp-caption img {
+ margin: 0;
+ padding: 0;
+ border: 0 none;
+ -webkit-user-drag: none;
+}
+
+.wp-caption-dd {
+ font-size: 11px;
+ line-height: 17px;
+ padding: 0 4px 5px;
+ margin: 0;
+}
+
+pre {
+ font: 12px/18px Consolas, Monaco, monospace;
+}
+
+td {
+ color: #000;
+ font-size: 11px;
+ margin: 8px;
+}
+
+/* Styles for the WordPress plugins */
+img.mce-wp-nextpage,
+img.mce-wp-more {
+ border: 0;
+ border-top: 1px dotted #cccccc;
+ display: block;
+ width: 95%;
+ height: 12px;
+ margin: 15px auto 0;
+}
+
+img.mce-wp-more {
+ background: transparent url("img/more_bug.gif") no-repeat right top;
+}
+
+img.mce-wp-nextpage {
+ background: transparent url("img/page_bug.gif") no-repeat right top;
+}
+
+img.wp-gallery {
+ border: 1px dashed #888;
+ background: #f2f8ff url("img/gallery.png") no-repeat scroll center center;
+ width: 99%;
+ height: 250px;
+}
+
+img.wp-oembed {
+ border: 1px dashed #888;
+ background: #f7f5f2 url("img/embedded.png") no-repeat scroll center center;
+ width: 300px;
+ height: 250px;
+}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/dialog.css b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/dialog.css
new file mode 100644
index 0000000000..6eaf010a3a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/dialog.css
@@ -0,0 +1,140 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+background:#f1f1f1;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#f1f1f1;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;}
+a:hover {color:#2B6FB6;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+form {margin: 0;}
+fieldset {margin:0; padding:4px; border:1px solid #dfdfdf; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;}
+input.invalid {border:1px solid #EE0000;}
+input {background:#FFF; border:1px solid #dfdfdf;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #dfdfdf;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert,
+#cancel,
+#apply,
+.mceActionPanel .button,
+input.mceButton,
+.updateButton {
+ border: 1px solid #bbb;
+ margin:0;
+ padding:0 0 1px;
+ font-weight:bold;
+ font-size: 11px;
+ width:94px;
+ height:24px;
+ color:#000;
+ cursor:pointer;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+ background-color: #eee;
+ background-image: -webkit-gradient(linear, left bottom, left top, from(#ddd), to(#fff));
+ background-image: -webkit-linear-gradient(bottom, #ddd, #fff);
+ background-image: -moz-linear-gradient(bottom, #ddd, #fff);
+ background-image: -o-linear-gradient(bottom, #ddd, #fff);
+ background-image: linear-gradient(to top, #ddd, #fff);
+}
+
+#insert:hover,
+#cancel:hover,
+input.mceButton:hover,
+.updateButton:hover,
+#insert:focus,
+#cancel:focus,
+input.mceButton:focus,
+.updateButton:focus {
+ border: 1px solid #555;
+}
+
+.mceActionPanel #insert {
+ float: right;
+}
+
+/* Browse */
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; -moz-opacity:0.3; opacity:0.3; filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor, a.browse {text-decoration:none}
+div.iframecontainer {background: #fff;}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+#charmap #charmapView {background-color:#fff;}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal; background:url(img/tabs.gif) repeat-x 0 -72px;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; background:url(img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;}
+.tabs li.current {background:url(img/tabs.gif) no-repeat 0 -18px; margin-right:2px;}
+.tabs span {float:left; display:block; background:url(img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;}
+.tabs .current span {background:url(img/tabs.gif) no-repeat right -54px;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper {text-align:center; padding-top:4px; white-space: nowrap; float: right;}
+#colorpicker #insert, #colorpicker #cancel {width: 90px}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
+#colorpicker #picker_panel fieldset {margin:auto;width:325px;}
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/embedded.png b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/embedded.png
new file mode 100644
index 0000000000..09d71ede10
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/embedded.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/gallery.png b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/gallery.png
new file mode 100644
index 0000000000..e8c39fc889
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/gallery.png
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/more_bug.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/more_bug.gif
new file mode 100644
index 0000000000..4589cb4dc6
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/more_bug.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/page_bug.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/page_bug.gif
new file mode 100644
index 0000000000..a7fa1b2f04
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/page_bug.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/tabs.gif b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/tabs.gif
new file mode 100644
index 0000000000..06812cb410
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/tabs.gif
Binary files differ
diff --git a/src/wp-includes/js/tinymce/themes/advanced/source_editor.htm b/src/wp-includes/js/tinymce/themes/advanced/source_editor.htm
new file mode 100644
index 0000000000..5548c693e8
--- /dev/null
+++ b/src/wp-includes/js/tinymce/themes/advanced/source_editor.htm
@@ -0,0 +1,25 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.code_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js?ver=358-20121205"></script>
+ <script type="text/javascript" src="js/source_editor.js?ver=358-20121205"></script>
+</head>
+<body onresize="resizeInputs();" style="display:none; overflow:hidden;" spellcheck="false">
+ <form name="source" onsubmit="saveContent();return false;" action="#">
+ <div style="float: left" class="title"><label for="htmlSource">{#advanced_dlg.code_title}</label></div>
+
+ <div id="wrapline" style="float: right">
+ <input type="checkbox" name="wraped" id="wraped" onclick="toggleWordWrap(this);" class="wordWrapCode" /><label for="wraped">{#advanced_dlg.code_wordwrap}</label>
+ </div>
+
+ <br style="clear: both" />
+
+ <textarea name="htmlSource" id="htmlSource" rows="15" cols="100" style="width: 100%; height: 100%; font-family: 'Courier New',Courier,monospace; font-size: 12px;" dir="ltr" wrap="off" class="mceFocus"></textarea>
+
+ <div class="mceActionPanel">
+ <input type="submit" role="button" name="insert" value="{#update}" id="insert" />
+ <input type="button" role="button" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" id="cancel" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/tiny_mce.js b/src/wp-includes/js/tinymce/tiny_mce.js
new file mode 100644
index 0000000000..7814fdff01
--- /dev/null
+++ b/src/wp-includes/js/tinymce/tiny_mce.js
@@ -0,0 +1 @@
+(function(e){var a=/^\s*|\s*$/g,b,d="B".replace(/A(.)|B/,"$1")==="$1";var c={majorVersion:"3",minorVersion:"5.8-wp2",releaseDate:"2013-02-11",_init:function(){var s=this,q=document,o=navigator,g=o.userAgent,m,f,l,k,j,r;s.isOpera=e.opera&&opera.buildNumber;s.isWebKit=/WebKit/.test(g);s.isIE=!s.isWebKit&&!s.isOpera&&(/MSIE/gi).test(g)&&(/Explorer/gi).test(o.appName);s.isIE6=s.isIE&&/MSIE [56]/.test(g);s.isIE7=s.isIE&&/MSIE [7]/.test(g);s.isIE8=s.isIE&&/MSIE [8]/.test(g);s.isIE9=s.isIE&&/MSIE [9]/.test(g);s.isGecko=!s.isWebKit&&/Gecko/.test(g);s.isMac=g.indexOf("Mac")!=-1;s.isAir=/adobeair/i.test(g);s.isIDevice=/(iPad|iPhone)/.test(g);s.isIOS5=s.isIDevice&&g.match(/AppleWebKit\/(\d*)/)[1]>=534;if(e.tinyMCEPreInit){s.suffix=tinyMCEPreInit.suffix;s.baseURL=tinyMCEPreInit.base;s.query=tinyMCEPreInit.query;return}s.suffix="";f=q.getElementsByTagName("base");for(m=0;m<f.length;m++){r=f[m].href;if(r){if(/^https?:\/\/[^\/]+$/.test(r)){r+="/"}k=r?r.match(/.*\//)[0]:""}}function h(i){if(i.src&&/tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(i.src)){if(/_(src|dev)\.js/g.test(i.src)){s.suffix="_src"}if((j=i.src.indexOf("?"))!=-1){s.query=i.src.substring(j+1)}s.baseURL=i.src.substring(0,i.src.lastIndexOf("/"));if(k&&s.baseURL.indexOf("://")==-1&&s.baseURL.indexOf("/")!==0){s.baseURL=k+s.baseURL}return s.baseURL}return null}f=q.getElementsByTagName("script");for(m=0;m<f.length;m++){if(h(f[m])){return}}l=q.getElementsByTagName("head")[0];if(l){f=l.getElementsByTagName("script");for(m=0;m<f.length;m++){if(h(f[m])){return}}}return},is:function(g,f){if(!f){return g!==b}if(f=="array"&&c.isArray(g)){return true}return typeof(g)==f},isArray:Array.isArray||function(f){return Object.prototype.toString.call(f)==="[object Array]"},makeMap:function(f,j,h){var g;f=f||[];j=j||",";if(typeof(f)=="string"){f=f.split(j)}h=h||{};g=f.length;while(g--){h[f[g]]={}}return h},each:function(i,f,h){var j,g;if(!i){return 0}h=h||i;if(i.length!==b){for(j=0,g=i.length;j<g;j++){if(f.call(h,i[j],j,i)===false){return 0}}}else{for(j in i){if(i.hasOwnProperty(j)){if(f.call(h,i[j],j,i)===false){return 0}}}}return 1},map:function(g,h){var i=[];c.each(g,function(f){i.push(h(f))});return i},grep:function(g,h){var i=[];c.each(g,function(f){if(!h||h(f)){i.push(f)}});return i},inArray:function(g,h){var j,f;if(g){for(j=0,f=g.length;j<f;j++){if(g[j]===h){return j}}}return -1},extend:function(n,k){var j,f,h,g=arguments,m;for(j=1,f=g.length;j<f;j++){k=g[j];for(h in k){if(k.hasOwnProperty(h)){m=k[h];if(m!==b){n[h]=m}}}}return n},trim:function(f){return(f?""+f:"").replace(a,"")},create:function(o,f,j){var n=this,g,i,k,l,h,m=0;o=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(o);k=o[3].match(/(^|\.)(\w+)$/i)[2];i=n.createNS(o[3].replace(/\.\w+$/,""),j);if(i[k]){return}if(o[2]=="static"){i[k]=f;if(this.onCreate){this.onCreate(o[2],o[3],i[k])}return}if(!f[k]){f[k]=function(){};m=1}i[k]=f[k];n.extend(i[k].prototype,f);if(o[5]){g=n.resolve(o[5]).prototype;l=o[5].match(/\.(\w+)$/i)[1];h=i[k];if(m){i[k]=function(){return g[l].apply(this,arguments)}}else{i[k]=function(){this.parent=g[l];return h.apply(this,arguments)}}i[k].prototype[k]=i[k];n.each(g,function(p,q){i[k].prototype[q]=g[q]});n.each(f,function(p,q){if(g[q]){i[k].prototype[q]=function(){this.parent=g[q];return p.apply(this,arguments)}}else{if(q!=k){i[k].prototype[q]=p}}})}n.each(f["static"],function(p,q){i[k][q]=p});if(this.onCreate){this.onCreate(o[2],o[3],i[k].prototype)}},walk:function(i,h,j,g){g=g||this;if(i){if(j){i=i[j]}c.each(i,function(k,f){if(h.call(g,k,f,j)===false){return false}c.walk(k,h,j,g)})}},createNS:function(j,h){var g,f;h=h||e;j=j.split(".");for(g=0;g<j.length;g++){f=j[g];if(!h[f]){h[f]={}}h=h[f]}return h},resolve:function(j,h){var g,f;h=h||e;j=j.split(".");for(g=0,f=j.length;g<f;g++){h=h[j[g]];if(!h){break}}return h},addUnload:function(j,i){var h=this,g;g=function(){var f=h.unloads,l,m;if(f){for(m in f){l=f[m];if(l&&l.func){l.func.call(l.scope,1)}}if(e.detachEvent){e.detachEvent("onbeforeunload",k);e.detachEvent("onunload",g)}else{if(e.removeEventListener){e.removeEventListener("unload",g,false)}}h.unloads=l=f=w=g=0;if(e.CollectGarbage){CollectGarbage()}}};function k(){var l=document;function f(){l.detachEvent("onstop",f);if(g){g()}l=0}if(l.readyState=="interactive"){if(l){l.attachEvent("onstop",f)}e.setTimeout(function(){if(l){l.detachEvent("onstop",f)}},0)}}j={func:j,scope:i||this};if(!h.unloads){if(e.attachEvent){e.attachEvent("onunload",g);e.attachEvent("onbeforeunload",k)}else{if(e.addEventListener){e.addEventListener("unload",g,false)}}h.unloads=[j]}else{h.unloads.push(j)}return j},removeUnload:function(i){var g=this.unloads,h=null;c.each(g,function(j,f){if(j&&j.func==i){g.splice(f,1);h=i;return false}});return h},explode:function(f,g){if(!f||c.is(f,"array")){return f}return c.map(f.split(g||","),c.trim)},_addVer:function(g){var f;if(!this.query){return g}f=(g.indexOf("?")==-1?"?":"&")+this.query;if(g.indexOf("#")==-1){return g+f}return g.replace("#",f+"#")},_replace:function(h,f,g){if(d){return g.replace(h,function(){var l=f,j=arguments,k;for(k=0;k<j.length-2;k++){if(j[k]===b){l=l.replace(new RegExp("\\$"+k,"g"),"")}else{l=l.replace(new RegExp("\\$"+k,"g"),j[k])}}return l})}return g.replace(h,f)}};c._init();e.tinymce=e.tinyMCE=c})(window);tinymce.create("tinymce.util.Dispatcher",{scope:null,listeners:null,inDispatch:false,Dispatcher:function(a){this.scope=a||this;this.listeners=[]},add:function(b,a){this.listeners.push({cb:b,scope:a||this.scope});return b},addToTop:function(d,b){var a=this,c={cb:d,scope:b||a.scope};if(a.inDispatch){a.listeners=[c].concat(a.listeners)}else{a.listeners.unshift(c)}return d},remove:function(c){var b=this.listeners,a=null;tinymce.each(b,function(e,d){if(c==e.cb){a=e;b.splice(d,1);return false}});return a},dispatch:function(){var a=this,e,b=arguments,c,d=a.listeners,f;a.inDispatch=true;for(c=0;c<d.length;c++){f=d[c];e=f.cb.apply(f.scope,b.length>0?b:[f.scope]);if(e===false){break}}a.inDispatch=false;return e}});(function(){var a=tinymce.each;tinymce.create("tinymce.util.URI",{URI:function(e,g){var f=this,i,d,c,h;e=tinymce.trim(e);g=f.settings=g||{};if(/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e)){f.source=e;return}if(e.indexOf("/")===0&&e.indexOf("//")!==0){e=(g.base_uri?g.base_uri.protocol||"http":"http")+"://mce_host"+e}if(!/^[\w\-]*:?\/\//.test(e)){h=g.base_uri?g.base_uri.path:new tinymce.util.URI(location.href).directory;e=((g.base_uri&&g.base_uri.protocol)||"http")+"://mce_host"+f.toAbsPath(h,e)}e=e.replace(/@@/g,"(mce_at)");e=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e);a(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(b,j){var k=e[j];if(k){k=k.replace(/\(mce_at\)/g,"@@")}f[b]=k});c=g.base_uri;if(c){if(!f.protocol){f.protocol=c.protocol}if(!f.userInfo){f.userInfo=c.userInfo}if(!f.port&&f.host==="mce_host"){f.port=c.port}if(!f.host||f.host==="mce_host"){f.host=c.host}f.source=""}},setPath:function(c){var b=this;c=/^(.*?)\/?(\w+)?$/.exec(c);b.path=c[0];b.directory=c[1];b.file=c[2];b.source="";b.getURI()},toRelative:function(b){var d=this,f;if(b==="./"){return b}b=new tinymce.util.URI(b,{base_uri:d});if((b.host!="mce_host"&&d.host!=b.host&&b.host)||d.port!=b.port||d.protocol!=b.protocol){return b.getURI()}var c=d.getURI(),e=b.getURI();if(c==e||(c.charAt(c.length-1)=="/"&&c.substr(0,c.length-1)==e)){return c}f=d.toRelPath(d.path,b.path);if(b.query){f+="?"+b.query}if(b.anchor){f+="#"+b.anchor}return f},toAbsolute:function(b,c){b=new tinymce.util.URI(b,{base_uri:this});return b.getURI(this.host==b.host&&this.protocol==b.protocol?c:0)},toRelPath:function(g,h){var c,f=0,d="",e,b;g=g.substring(0,g.lastIndexOf("/"));g=g.split("/");c=h.split("/");if(g.length>=c.length){for(e=0,b=g.length;e<b;e++){if(e>=c.length||g[e]!=c[e]){f=e+1;break}}}if(g.length<c.length){for(e=0,b=c.length;e<b;e++){if(e>=g.length||g[e]!=c[e]){f=e+1;break}}}if(f===1){return h}for(e=0,b=g.length-(f-1);e<b;e++){d+="../"}for(e=f-1,b=c.length;e<b;e++){if(e!=f-1){d+="/"+c[e]}else{d+=c[e]}}return d},toAbsPath:function(e,f){var c,b=0,h=[],d,g;d=/\/$/.test(f)?"/":"";e=e.split("/");f=f.split("/");a(e,function(i){if(i){h.push(i)}});e=h;for(c=f.length-1,h=[];c>=0;c--){if(f[c].length===0||f[c]==="."){continue}if(f[c]===".."){b++;continue}if(b>0){b--;continue}h.push(f[c])}c=e.length-b;if(c<=0){g=h.reverse().join("/")}else{g=e.slice(0,c).join("/")+"/"+h.reverse().join("/")}if(g.indexOf("/")!==0){g="/"+g}if(d&&g.lastIndexOf("/")!==g.length-1){g+=d}return g},getURI:function(d){var c,b=this;if(!b.source||d){c="";if(!d){if(b.protocol){c+=b.protocol+"://"}if(b.userInfo){c+=b.userInfo+"@"}if(b.host){c+=b.host}if(b.port){c+=":"+b.port}}if(b.path){c+=b.path}if(b.query){c+="?"+b.query}if(b.anchor){c+="#"+b.anchor}b.source=c}return b.source}})})();(function(){var a=tinymce.each;tinymce.create("static tinymce.util.Cookie",{getHash:function(d){var b=this.get(d),c;if(b){a(b.split("&"),function(e){e=e.split("=");c=c||{};c[unescape(e[0])]=unescape(e[1])})}return c},setHash:function(j,b,g,f,i,c){var h="";a(b,function(e,d){h+=(!h?"":"&")+escape(d)+"="+escape(e)});this.set(j,h,g,f,i,c)},get:function(i){var h=document.cookie,g,f=i+"=",d;if(!h){return}d=h.indexOf("; "+f);if(d==-1){d=h.indexOf(f);if(d!==0){return null}}else{d+=2}g=h.indexOf(";",d);if(g==-1){g=h.length}return unescape(h.substring(d+f.length,g))},set:function(i,b,g,f,h,c){document.cookie=i+"="+escape(b)+((g)?"; expires="+g.toGMTString():"")+((f)?"; path="+escape(f):"")+((h)?"; domain="+h:"")+((c)?"; secure":"")},remove:function(c,e,d){var b=new Date();b.setTime(b.getTime()-1000);this.set(c,"",b,e,d)}})})();(function(){function serialize(o,quote){var i,v,t,name;quote=quote||'"';if(o==null){return"null"}t=typeof o;if(t=="string"){v="\bb\tt\nn\ff\rr\"\"''\\\\";return quote+o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(a,b){if(quote==='"'&&a==="'"){return a}i=v.indexOf(b);if(i+1){return"\\"+v.charAt(i+1)}a=b.charCodeAt().toString(16);return"\\u"+"0000".substring(a.length)+a})+quote}if(t=="object"){if(o.hasOwnProperty&&Object.prototype.toString.call(o)==="[object Array]"){for(i=0,v="[";i<o.length;i++){v+=(i>0?",":"")+serialize(o[i],quote)}return v+"]"}v="{";for(name in o){if(o.hasOwnProperty(name)){v+=typeof o[name]!="function"?(v.length>1?","+quote:quote)+name+quote+":"+serialize(o[name],quote):""}}return v+"}"}return""+o}tinymce.util.JSON={serialize:serialize,parse:function(s){try{return eval("("+s+")")}catch(ex){}}}})();tinymce.create("static tinymce.util.XHR",{send:function(g){var a,e,b=window,h=0;function f(){if(!g.async||a.readyState==4||h++>10000){if(g.success&&h<10000&&a.status==200){g.success.call(g.success_scope,""+a.responseText,a,g)}else{if(g.error){g.error.call(g.error_scope,h>10000?"TIMED_OUT":"GENERAL",a,g)}}a=null}else{b.setTimeout(f,10)}}g.scope=g.scope||this;g.success_scope=g.success_scope||g.scope;g.error_scope=g.error_scope||g.scope;g.async=g.async===false?false:true;g.data=g.data||"";function d(i){a=0;try{a=new ActiveXObject(i)}catch(c){}return a}a=b.XMLHttpRequest?new XMLHttpRequest():d("Microsoft.XMLHTTP")||d("Msxml2.XMLHTTP");if(a){if(a.overrideMimeType){a.overrideMimeType(g.content_type)}a.open(g.type||(g.data?"POST":"GET"),g.url,g.async);if(g.content_type){a.setRequestHeader("Content-Type",g.content_type)}a.setRequestHeader("X-Requested-With","XMLHttpRequest");a.send(g.data);if(!g.async){return f()}e=b.setTimeout(f,10)}}});(function(){var c=tinymce.extend,b=tinymce.util.JSON,a=tinymce.util.XHR;tinymce.create("tinymce.util.JSONRequest",{JSONRequest:function(d){this.settings=c({},d);this.count=0},send:function(f){var e=f.error,d=f.success;f=c(this.settings,f);f.success=function(h,g){h=b.parse(h);if(typeof(h)=="undefined"){h={error:"JSON Parse error."}}if(h.error){e.call(f.error_scope||f.scope,h.error,g)}else{d.call(f.success_scope||f.scope,h.result)}};f.error=function(h,g){if(e){e.call(f.error_scope||f.scope,h,g)}};f.data=b.serialize({id:f.id||"c"+(this.count++),method:f.method,params:f.params});f.content_type="application/json";a.send(f)},"static":{sendRPC:function(d){return new tinymce.util.JSONRequest().send(d)}}})}());(function(a){a.VK={BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(b){return b.shiftKey||b.ctrlKey||b.altKey},metaKeyPressed:function(b){return a.isMac?b.metaKey:b.ctrlKey&&!b.altKey}}})(tinymce);tinymce.util.Quirks=function(a){var j=tinymce.VK,f=j.BACKSPACE,k=j.DELETE,e=a.dom,l=a.selection,H=a.settings,v=a.parser,o=a.serializer,E=tinymce.each;function A(N,M){try{a.getDoc().execCommand(N,false,M)}catch(L){}}function n(){var L=a.getDoc().documentMode;return L?L:6}function z(L){return L.isDefaultPrevented()}function J(){function L(R){var N,P,M,S,O,Q,T;function U(){if(O.nodeType==3){if(R&&Q==O.length){return true}if(!R&&Q===0){return true}}}N=l.getRng();var V=[N.startContainer,N.startOffset,N.endContainer,N.endOffset];if(!N.collapsed){R=true}O=N[(R?"start":"end")+"Container"];Q=N[(R?"start":"end")+"Offset"];if(O.nodeType==3){P=e.getParent(N.startContainer,e.isBlock);if(R){P=e.getNext(P,e.isBlock)}if(P&&(U()||!N.collapsed)){M=e.create("em",{id:"__mceDel"});E(tinymce.grep(P.childNodes),function(W){M.appendChild(W)});P.appendChild(M)}}N=e.createRng();N.setStart(V[0],V[1]);N.setEnd(V[2],V[3]);l.setRng(N);a.getDoc().execCommand(R?"ForwardDelete":"Delete",false,null);if(M){S=l.getBookmark();while(T=e.get("__mceDel")){e.remove(T,true)}l.moveToBookmark(S)}}a.onKeyDown.add(function(M,O){var N;N=O.keyCode==k;if(!z(O)&&(N||O.keyCode==f)&&!j.modifierPressed(O)){O.preventDefault();L(N)}});a.addCommand("Delete",function(){L()})}function q(){function L(O){var N=e.create("body");var P=O.cloneContents();N.appendChild(P);return l.serializer.serialize(N,{format:"html"})}function M(N){var P=L(N);var Q=e.createRng();Q.selectNode(a.getBody());var O=L(Q);return P===O}a.onKeyDown.add(function(O,Q){var P=Q.keyCode,N;if(!z(Q)&&(P==k||P==f)){N=O.selection.isCollapsed();if(N&&!e.isEmpty(O.getBody())){return}if(tinymce.isIE&&!N){return}if(!N&&!M(O.selection.getRng())){return}O.setContent("");O.selection.setCursorLocation(O.getBody(),0);O.nodeChanged()}})}function I(){a.onKeyDown.add(function(L,M){if(!z(M)&&M.keyCode==65&&j.metaKeyPressed(M)){M.preventDefault();L.execCommand("SelectAll")}})}function K(){if(!a.settings.content_editable){e.bind(a.getDoc(),"focusin",function(L){l.setRng(l.getRng())});e.bind(a.getDoc(),"mousedown",function(L){if(L.target==a.getDoc().documentElement){a.getWin().focus();l.setRng(l.getRng())}})}}function B(){a.onKeyDown.add(function(L,O){if(!z(O)&&O.keyCode===f){if(l.isCollapsed()&&l.getRng(true).startOffset===0){var N=l.getNode();var M=N.previousSibling;if(M&&M.nodeName&&M.nodeName.toLowerCase()==="hr"){e.remove(M);tinymce.dom.Event.cancel(O)}}}})}function y(){if(!Range.prototype.getClientRects){a.onMouseDown.add(function(M,N){if(!z(N)&&N.target.nodeName==="HTML"){var L=M.getBody();L.blur();setTimeout(function(){L.focus()},0)}})}}function h(){a.onClick.add(function(L,M){M=M.target;if(/^(IMG|HR)$/.test(M.nodeName)){l.getSel().setBaseAndExtent(M,0,M,1)}if(M.nodeName=="A"&&e.hasClass(M,"mceItemAnchor")){l.select(M)}L.nodeChanged()})}function c(){function M(){var O=e.getAttribs(l.getStart().cloneNode(false));return function(){var P=l.getStart();if(P!==a.getBody()){e.setAttrib(P,"style",null);E(O,function(Q){P.setAttributeNode(Q.cloneNode(true))})}}}function L(){return !l.isCollapsed()&&e.getParent(l.getStart(),e.isBlock)!=e.getParent(l.getEnd(),e.isBlock)}function N(O,P){P.preventDefault();return false}a.onKeyPress.add(function(O,Q){var P;if(!z(Q)&&(Q.keyCode==8||Q.keyCode==46)&&L()){P=M();O.getDoc().execCommand("delete",false,null);P();Q.preventDefault();return false}});e.bind(a.getDoc(),"cut",function(P){var O;if(!z(P)&&L()){O=M();a.onKeyUp.addToTop(N);setTimeout(function(){O();a.onKeyUp.remove(N)},0)}})}function b(){var M,L;e.bind(a.getDoc(),"selectionchange",function(){if(L){clearTimeout(L);L=0}L=window.setTimeout(function(){var N=l.getRng();if(!M||!tinymce.dom.RangeUtils.compareRanges(N,M)){a.nodeChanged();M=N}},50)})}function x(){document.body.setAttribute("role","application")}function t(){a.onKeyDown.add(function(L,N){if(!z(N)&&N.keyCode===f){if(l.isCollapsed()&&l.getRng(true).startOffset===0){var M=l.getNode().previousSibling;if(M&&M.nodeName&&M.nodeName.toLowerCase()==="table"){return tinymce.dom.Event.cancel(N)}}}})}function C(){if(n()>7){return}A("RespectVisibilityInDesign",true);a.contentStyles.push(".mceHideBrInPre pre br {display: none}");e.addClass(a.getBody(),"mceHideBrInPre");v.addNodeFilter("pre",function(L,N){var O=L.length,Q,M,R,P;while(O--){Q=L[O].getAll("br");M=Q.length;while(M--){R=Q[M];P=R.prev;if(P&&P.type===3&&P.value.charAt(P.value-1)!="\n"){P.value+="\n"}else{R.parent.insert(new tinymce.html.Node("#text",3),R,true).value="\n"}}}});o.addNodeFilter("pre",function(L,N){var O=L.length,Q,M,R,P;while(O--){Q=L[O].getAll("br");M=Q.length;while(M--){R=Q[M];P=R.prev;if(P&&P.type==3){P.value=P.value.replace(/\r?\n$/,"")}}}})}function g(){e.bind(a.getBody(),"mouseup",function(N){var M,L=l.getNode();if(L.nodeName=="IMG"){if(M=e.getStyle(L,"width")){e.setAttrib(L,"width",M.replace(/[^0-9%]+/g,""));e.setStyle(L,"width","")}if(M=e.getStyle(L,"height")){e.setAttrib(L,"height",M.replace(/[^0-9%]+/g,""));e.setStyle(L,"height","")}}})}function d(){a.onKeyDown.add(function(R,S){var Q,L,M,O,P,T,N;Q=S.keyCode==k;if(!z(S)&&(Q||S.keyCode==f)&&!j.modifierPressed(S)){L=l.getRng();M=L.startContainer;O=L.startOffset;N=L.collapsed;if(M.nodeType==3&&M.nodeValue.length>0&&((O===0&&!N)||(N&&O===(Q?0:1)))){T=M.previousSibling;if(T&&T.nodeName=="IMG"){return}nonEmptyElements=R.schema.getNonEmptyElements();S.preventDefault();P=e.create("br",{id:"__tmp"});M.parentNode.insertBefore(P,M);R.getDoc().execCommand(Q?"ForwardDelete":"Delete",false,null);M=l.getRng().startContainer;T=M.previousSibling;if(T&&T.nodeType==1&&!e.isBlock(T)&&e.isEmpty(T)&&!nonEmptyElements[T.nodeName.toLowerCase()]){e.remove(T)}e.remove("__tmp")}}})}function G(){a.onKeyDown.add(function(P,Q){var N,M,R,L,O;if(z(Q)||Q.keyCode!=j.BACKSPACE){return}N=l.getRng();M=N.startContainer;R=N.startOffset;L=e.getRoot();O=M;if(!N.collapsed||R!==0){return}while(O&&O.parentNode&&O.parentNode.firstChild==O&&O.parentNode!=L){O=O.parentNode}if(O.tagName==="BLOCKQUOTE"){P.formatter.toggle("blockquote",null,O);N=e.createRng();N.setStart(M,0);N.setEnd(M,0);l.setRng(N)}})}function F(){function L(){a._refreshContentEditable();A("StyleWithCSS",false);A("enableInlineTableEditing",false);if(!H.object_resizing){A("enableObjectResizing",false)}}if(!H.readonly){a.onBeforeExecCommand.add(L);a.onMouseDown.add(L)}}function s(){function L(M,N){E(e.select("a"),function(Q){var O=Q.parentNode,P=e.getRoot();if(O.lastChild===Q){while(O&&!e.isBlock(O)){if(O.parentNode.lastChild!==O||O===P){return}O=O.parentNode}e.add(O,"br",{"data-mce-bogus":1})}})}a.onExecCommand.add(function(M,N){if(N==="CreateLink"){L(M)}});a.onSetContent.add(l.onSetContent.add(L))}function m(){if(H.forced_root_block){a.onInit.add(function(){A("DefaultParagraphSeparator",H.forced_root_block)})}}function p(){function L(N,M){if(!N||!M.initial){a.execCommand("mceRepaint")}}a.onUndo.add(L);a.onRedo.add(L);a.onSetContent.add(L)}function i(){a.onKeyDown.add(function(M,N){var L;if(!z(N)&&N.keyCode==f){L=M.getDoc().selection.createRange();if(L&&L.item){N.preventDefault();M.undoManager.beforeChange();e.remove(L.item(0));M.undoManager.add()}}})}function r(){var L;if(n()>=10){L="";E("p div h1 h2 h3 h4 h5 h6".split(" "),function(M,N){L+=(N>0?",":"")+M+":empty"});a.contentStyles.push(L+"{padding-right: 1px !important}")}}function u(){var N,M,ad,L,Y,ab,Z,ac,O,P,aa,W,V,X=document,T=a.getDoc();if(!H.object_resizing||H.webkit_fake_resize===false){return}A("enableObjectResizing",false);aa={n:[0.5,0,0,-1],e:[1,0.5,1,0],s:[0.5,1,0,1],w:[0,0.5,-1,0],nw:[0,0,-1,-1],ne:[1,0,1,-1],se:[1,1,1,1],sw:[0,1,-1,1]};function R(ah){var ag,af;ag=ah.screenX-ab;af=ah.screenY-Z;W=ag*Y[2]+ac;V=af*Y[3]+O;W=W<5?5:W;V=V<5?5:V;if(j.modifierPressed(ah)||(ad.nodeName=="IMG"&&Y[2]*Y[3]!==0)){W=Math.round(V/P);V=Math.round(W*P)}e.setStyles(L,{width:W,height:V});if(Y[2]<0&&L.clientWidth<=W){e.setStyle(L,"left",N+(ac-W))}if(Y[3]<0&&L.clientHeight<=V){e.setStyle(L,"top",M+(O-V))}}function ae(){function af(ag,ah){if(ah){if(ad.style[ag]||!a.schema.isValid(ad.nodeName.toLowerCase(),ag)){e.setStyle(ad,ag,ah)}else{e.setAttrib(ad,ag,ah)}}}af("width",W);af("height",V);e.unbind(T,"mousemove",R);e.unbind(T,"mouseup",ae);if(X!=T){e.unbind(X,"mousemove",R);e.unbind(X,"mouseup",ae)}e.remove(L);Q(ad)}function Q(ai){var ag,ah,af;S();ag=e.getPos(ai);N=ag.x;M=ag.y;ah=ai.offsetWidth;af=ai.offsetHeight;if(ad!=ai){ad=ai;W=V=0}E(aa,function(al,aj){var ak;ak=e.get("mceResizeHandle"+aj);if(!ak){ak=e.add(T.documentElement,"div",{id:"mceResizeHandle"+aj,"class":"mceResizeHandle",style:"cursor:"+aj+"-resize; margin:0; padding:0"});e.bind(ak,"mousedown",function(am){am.preventDefault();ae();ab=am.screenX;Z=am.screenY;ac=ad.clientWidth;O=ad.clientHeight;P=O/ac;Y=al;L=ad.cloneNode(true);e.addClass(L,"mceClonedResizable");e.setStyles(L,{left:N,top:M,margin:0});T.documentElement.appendChild(L);e.bind(T,"mousemove",R);e.bind(T,"mouseup",ae);if(X!=T){e.bind(X,"mousemove",R);e.bind(X,"mouseup",ae)}})}else{e.show(ak)}e.setStyles(ak,{left:(ah*al[0]+N)-(ak.offsetWidth/2),top:(af*al[1]+M)-(ak.offsetHeight/2)})});if(!tinymce.isOpera&&ad.nodeName=="IMG"){ad.setAttribute("data-mce-selected","1")}}function S(){if(ad){ad.removeAttribute("data-mce-selected")}for(var af in aa){e.hide("mceResizeHandle"+af)}}a.contentStyles.push(".mceResizeHandle {position: absolute;border: 1px solid black;background: #FFF;width: 5px;height: 5px;z-index: 10000}.mceResizeHandle:hover {background: #000}img[data-mce-selected] {outline: 1px solid black}img.mceClonedResizable, table.mceClonedResizable {position: absolute;outline: 1px dashed black;opacity: .5;z-index: 10000}");function U(){var af=e.getParent(l.getNode(),"table,img");E(e.select("img[data-mce-selected]"),function(ag){ag.removeAttribute("data-mce-selected")});if(af){Q(af)}else{S()}}a.onNodeChange.add(U);e.bind(T,"selectionchange",U);a.serializer.addAttributeFilter("data-mce-selected",function(af,ag){var ah=af.length;while(ah--){af[ah].attr(ag,null)}})}function D(){if(n()<9){v.addNodeFilter("noscript",function(L){var M=L.length,N,O;while(M--){N=L[M];O=N.firstChild;if(O){N.attr("data-mce-innertext",O.value)}}});o.addNodeFilter("noscript",function(L){var M=L.length,N,P,O;while(M--){N=L[M];P=L[M].firstChild;if(P){P.value=tinymce.html.Entities.decode(P.value)}else{O=N.attributes.map["data-mce-innertext"];if(O){N.attr("data-mce-innertext",null);P=new tinymce.html.Node("#text",3);P.value=O;P.raw=true;N.append(P)}}}})}}t();G();q();if(tinymce.isWebKit){d();J();K();h();m();if(tinymce.isIDevice){b()}else{u();I()}}if(tinymce.isIE){B();x();C();g();i();r();D()}if(tinymce.isGecko){B();y();c();F();s();p()}if(tinymce.isOpera){u()}};(function(j){var a,g,d,k=/[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,b=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,f=/[<>&\"\']/g,c=/&(#x|#)?([\w]+);/g,i={128:"\u20AC",130:"\u201A",131:"\u0192",132:"\u201E",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02C6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017D",145:"\u2018",146:"\u2019",147:"\u201C",148:"\u201D",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02DC",153:"\u2122",154:"\u0161",155:"\u203A",156:"\u0153",158:"\u017E",159:"\u0178"};g={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;"};d={"&lt;":"<","&gt;":">","&amp;":"&","&quot;":'"',"&apos;":"'"};function h(l){var m;m=document.createElement("div");m.innerHTML=l;return m.textContent||m.innerText||l}function e(m,p){var n,o,l,q={};if(m){m=m.split(",");p=p||10;for(n=0;n<m.length;n+=2){o=String.fromCharCode(parseInt(m[n],p));if(!g[o]){l="&"+m[n+1]+";";q[o]=l;q[l]=o}}return q}}a=e("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);j.html=j.html||{};j.html.Entities={encodeRaw:function(m,l){return m.replace(l?k:b,function(n){return g[n]||n})},encodeAllRaw:function(l){return(""+l).replace(f,function(m){return g[m]||m})},encodeNumeric:function(m,l){return m.replace(l?k:b,function(n){if(n.length>1){return"&#"+(((n.charCodeAt(0)-55296)*1024)+(n.charCodeAt(1)-56320)+65536)+";"}return g[n]||"&#"+n.charCodeAt(0)+";"})},encodeNamed:function(n,l,m){m=m||a;return n.replace(l?k:b,function(o){return g[o]||m[o]||o})},getEncodeFunc:function(l,o){var p=j.html.Entities;o=e(o)||a;function m(r,q){return r.replace(q?k:b,function(s){return g[s]||o[s]||"&#"+s.charCodeAt(0)+";"||s})}function n(r,q){return p.encodeNamed(r,q,o)}l=j.makeMap(l.replace(/\+/g,","));if(l.named&&l.numeric){return m}if(l.named){if(o){return n}return p.encodeNamed}if(l.numeric){return p.encodeNumeric}return p.encodeRaw},decode:function(l){return l.replace(c,function(n,m,o){if(m){o=parseInt(o,m.length===2?16:10);if(o>65535){o-=65536;return String.fromCharCode(55296+(o>>10),56320+(o&1023))}else{return i[o]||String.fromCharCode(o)}}return d[n]||a[n]||h(n)})}}})(tinymce);tinymce.html.Styles=function(d,f){var k=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,h=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,b=/\s*([^:]+):\s*([^;]+);?/g,l=/\s+$/,m=/rgb/,e,g,a={},j;d=d||{};j="\\\" \\' \\; \\: ; : \uFEFF".split(" ");for(g=0;g<j.length;g++){a[j[g]]="\uFEFF"+g;a["\uFEFF"+g]=j[g]}function c(n,q,p,i){function o(r){r=parseInt(r).toString(16);return r.length>1?r:"0"+r}return"#"+o(q)+o(p)+o(i)}return{toHex:function(i){return i.replace(k,c)},parse:function(s){var z={},q,n,x,r,v=d.url_converter,y=d.url_converter_scope||this;function p(D,G){var F,C,B,E;F=z[D+"-top"+G];if(!F){return}C=z[D+"-right"+G];if(F!=C){return}B=z[D+"-bottom"+G];if(C!=B){return}E=z[D+"-left"+G];if(B!=E){return}z[D+G]=E;delete z[D+"-top"+G];delete z[D+"-right"+G];delete z[D+"-bottom"+G];delete z[D+"-left"+G]}function u(C){var D=z[C],B;if(!D||D.indexOf(" ")<0){return}D=D.split(" ");B=D.length;while(B--){if(D[B]!==D[0]){return false}}z[C]=D[0];return true}function A(D,C,B,E){if(!u(C)){return}if(!u(B)){return}if(!u(E)){return}z[D]=z[C]+" "+z[B]+" "+z[E];delete z[C];delete z[B];delete z[E]}function t(B){r=true;return a[B]}function i(C,B){if(r){C=C.replace(/\uFEFF[0-9]/g,function(D){return a[D]})}if(!B){C=C.replace(/\\([\'\";:])/g,"$1")}return C}function o(C,B,F,E,G,D){G=G||D;if(G){G=i(G);return"'"+G.replace(/\'/g,"\\'")+"'"}B=i(B||F||E);if(v){B=v.call(y,B,"style")}return"url('"+B.replace(/\'/g,"\\'")+"')"}if(s){s=s.replace(/\\[\"\';:\uFEFF]/g,t).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(B){return B.replace(/[;:]/g,t)});while(q=b.exec(s)){n=q[1].replace(l,"").toLowerCase();x=q[2].replace(l,"");if(n&&x.length>0){if(n==="font-weight"&&x==="700"){x="bold"}else{if(n==="color"||n==="background-color"){x=x.toLowerCase()}}x=x.replace(k,c);x=x.replace(h,o);z[n]=r?i(x,true):x}b.lastIndex=q.index+q[0].length}p("border","");p("border","-width");p("border","-color");p("border","-style");p("padding","");p("margin","");A("border","border-width","border-style","border-color");if(z.border==="medium none"){delete z.border}}return z},serialize:function(p,r){var o="",n,q;function i(t){var x,u,s,v;x=f.styles[t];if(x){for(u=0,s=x.length;u<s;u++){t=x[u];v=p[t];if(v!==e&&v.length>0){o+=(o.length>0?" ":"")+t+": "+v+";"}}}}if(r&&f&&f.styles){i("*");i(r)}else{for(n in p){q=p[n];if(q!==e&&q.length>0){o+=(o.length>0?" ":"")+n+": "+q+";"}}}return o}}};(function(f){var a={},e=f.makeMap,g=f.each;function d(j,i){return j.split(i||",")}function h(m,l){var j,k={};function i(n){return n.replace(/[A-Z]+/g,function(o){return i(m[o])})}for(j in m){if(m.hasOwnProperty(j)){m[j]=i(m[j])}}i(l).replace(/#/g,"#text").replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g,function(q,o,n,p){n=d(n,"|");k[o]={attributes:e(n),attributesOrder:n,children:e(p,"|",{"#comment":{}})}});return k}function b(){var i=a.html5;if(!i){i=a.html5=h({A:"id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup",B:"#|a|abbr|area|audio|b|bdo|br|button|canvas|cite|code|command|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|meta|meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video|wbr",C:"#|a|abbr|area|address|article|aside|audio|b|bdo|blockquote|br|button|canvas|cite|code|command|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|menu|meta|meter|nav|noscript|ol|object|output|p|pre|progress|q|ruby|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|ul|var|video"},"html[A|manifest][body|head]head[A][base|command|link|meta|noscript|script|style|title]title[A][#]base[A|href|target][]link[A|href|rel|media|type|sizes][]meta[A|http-equiv|name|content|charset][]style[A|type|media|scoped][#]script[A|charset|type|src|defer|async][#]noscript[A][C]body[A][C]section[A][C]nav[A][C]article[A][C]aside[A][C]h1[A][B]h2[A][B]h3[A][B]h4[A][B]h5[A][B]h6[A][B]hgroup[A][h1|h2|h3|h4|h5|h6]header[A][C]footer[A][C]address[A][C]p[A][B]br[A][]pre[A][B]dialog[A][dd|dt]blockquote[A|cite][C]ol[A|start|reversed][li]ul[A][li]li[A|value][C]dl[A][dd|dt]dt[A][B]dd[A][C]a[A|href|target|ping|rel|media|type][B]em[A][B]strong[A][B]small[A][B]cite[A][B]q[A|cite][B]dfn[A][B]abbr[A][B]code[A][B]var[A][B]samp[A][B]kbd[A][B]sub[A][B]sup[A][B]i[A][B]b[A][B]mark[A][B]progress[A|value|max][B]meter[A|value|min|max|low|high|optimum][B]time[A|datetime][B]ruby[A][B|rt|rp]rt[A][B]rp[A][B]bdo[A][B]span[A][B]ins[A|cite|datetime][B]del[A|cite|datetime][B]figure[A][C|legend|figcaption]figcaption[A][C]img[A|alt|src|height|width|usemap|ismap][]iframe[A|name|src|height|width|sandbox|seamless][]embed[A|src|height|width|type][]object[A|data|type|height|width|usemap|name|form|classid][param]param[A|name|value][]details[A|open][C|legend]command[A|type|label|icon|disabled|checked|radiogroup][]menu[A|type|label][C|li]legend[A][C|B]div[A][C]source[A|src|type|media][]audio[A|src|autobuffer|autoplay|loop|controls][source]video[A|src|autobuffer|autoplay|loop|controls|width|height|poster][source]hr[A][]form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]fieldset[A|disabled|form|name][C|legend]label[A|form|for][B]input[A|type|accept|alt|autocomplete|autofocus|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value|name][]button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]datalist[A][B|option]optgroup[A|disabled|label][option]option[A|disabled|selected|label|value][]textarea[A|autofocus|disabled|form|maxlength|name|placeholder|readonly|required|rows|cols|wrap][]keygen[A|autofocus|challenge|disabled|form|keytype|name][]output[A|for|form|name][B]canvas[A|width|height][]map[A|name][B|C]area[A|shape|coords|href|alt|target|media|rel|ping|type][]mathml[A][]svg[A][]table[A|border][caption|colgroup|thead|tfoot|tbody|tr]caption[A][C]colgroup[A|span][col]col[A|span][]thead[A][tr]tfoot[A][tr]tbody[A][tr]tr[A][th|td]th[A|headers|rowspan|colspan|scope][B]td[A|headers|rowspan|colspan][C]wbr[A][]")}return i}function c(){var i=a.html4;if(!i){i=a.html4=h({Z:"H|K|N|O|P",Y:"X|form|R|Q",ZG:"E|span|width|align|char|charoff|valign",X:"p|T|div|U|W|isindex|fieldset|table",ZF:"E|align|char|charoff|valign",W:"pre|hr|blockquote|address|center|noframes",ZE:"abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height",ZD:"[E][S]",U:"ul|ol|dl|menu|dir",ZC:"p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q",T:"h1|h2|h3|h4|h5|h6",ZB:"X|S|Q",S:"R|P",ZA:"a|G|J|M|O|P",R:"a|H|K|N|O",Q:"noscript|P",P:"ins|del|script",O:"input|select|textarea|label|button",N:"M|L",M:"em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym",L:"sub|sup",K:"J|I",J:"tt|i|b|u|s|strike",I:"big|small|font|basefont",H:"G|F",G:"br|span|bdo",F:"object|applet|img|map|iframe",E:"A|B|C",D:"accesskey|tabindex|onfocus|onblur",C:"onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup",B:"lang|xml:lang|dir",A:"id|class|style|title"},"script[id|charset|type|language|src|defer|xml:space][]style[B|id|type|media|title|xml:space][]object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]param[id|name|value|valuetype|type][]p[E|align][#|S]a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]br[A|clear][]span[E][#|S]bdo[A|C|B][#|S]applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]h1[E|align][#|S]img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]map[B|C|A|name][X|form|Q|area]h2[E|align][#|S]iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]h3[E|align][#|S]tt[E][#|S]i[E][#|S]b[E][#|S]u[E][#|S]s[E][#|S]strike[E][#|S]big[E][#|S]small[E][#|S]font[A|B|size|color|face][#|S]basefont[id|size|color|face][]em[E][#|S]strong[E][#|S]dfn[E][#|S]code[E][#|S]q[E|cite][#|S]samp[E][#|S]kbd[E][#|S]var[E][#|S]cite[E][#|S]abbr[E][#|S]acronym[E][#|S]sub[E][#|S]sup[E][#|S]input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]optgroup[E|disabled|label][option]option[E|selected|disabled|label|value][]textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]label[E|for|accesskey|onfocus|onblur][#|S]button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]h4[E|align][#|S]ins[E|cite|datetime][#|Y]h5[E|align][#|S]del[E|cite|datetime][#|Y]h6[E|align][#|S]div[E|align][#|Y]ul[E|type|compact][li]li[E|type|value][#|Y]ol[E|type|compact|start][li]dl[E|compact][dt|dd]dt[E][#|S]dd[E][#|Y]menu[E|compact][li]dir[E|compact][li]pre[E|width|xml:space][#|ZA]hr[E|align|noshade|size|width][]blockquote[E|cite][#|Y]address[E][#|S|p]center[E][#|Y]noframes[E][#|Y]isindex[A|B|prompt][]fieldset[E][#|legend|Y]legend[E|accesskey|align][#|S]table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]caption[E|align][#|S]col[ZG][]colgroup[ZG][col]thead[ZF][tr]tr[ZF|bgcolor][th|td]th[E|ZE][#|Y]form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]noscript[E][#|Y]td[E|ZE][#|Y]tfoot[ZF][tr]tbody[ZF][tr]area[E|D|shape|coords|href|nohref|alt|target][]base[id|href|target][]body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]")}return i}f.html.Schema=function(A){var u=this,s={},k={},j=[],D,y;var o,q,z,r,v,n,p={};function m(F,E,H){var G=A[F];if(!G){G=a[F];if(!G){G=e(E," ",e(E.toUpperCase()," "));G=f.extend(G,H);a[F]=G}}else{G=e(G,",",e(G.toUpperCase()," "))}return G}A=A||{};y=A.schema=="html5"?b():c();if(A.verify_html===false){A.valid_elements="*[*]"}if(A.valid_styles){D={};g(A.valid_styles,function(F,E){D[E]=f.explode(F)})}o=m("whitespace_elements","pre script noscript style textarea");q=m("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr");z=m("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr");r=m("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls");n=m("non_empty_elements","td th iframe video audio object",z);textBlockElementsMap=m("text_block_elements","h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside nav figure");v=m("block_elements","hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex samp option datalist select optgroup",textBlockElementsMap);function i(E){return new RegExp("^"+E.replace(/([?+*])/g,".$1")+"$")}function C(L){var K,G,Z,V,aa,F,I,U,X,Q,Y,ac,O,J,W,E,S,H,ab,ad,P,T,N=/^([#+\-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,R=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,M=/[*?+]/;if(L){L=d(L);if(s["@"]){S=s["@"].attributes;H=s["@"].attributesOrder}for(K=0,G=L.length;K<G;K++){F=N.exec(L[K]);if(F){W=F[1];Q=F[2];E=F[3];X=F[4];O={};J=[];I={attributes:O,attributesOrder:J};if(W==="#"){I.paddEmpty=true}if(W==="-"){I.removeEmpty=true}if(S){for(ad in S){O[ad]=S[ad]}J.push.apply(J,H)}if(X){X=d(X,"|");for(Z=0,V=X.length;Z<V;Z++){F=R.exec(X[Z]);if(F){U={};ac=F[1];Y=F[2].replace(/::/g,":");W=F[3];T=F[4];if(ac==="!"){I.attributesRequired=I.attributesRequired||[];I.attributesRequired.push(Y);U.required=true}if(ac==="-"){delete O[Y];J.splice(f.inArray(J,Y),1);continue}if(W){if(W==="="){I.attributesDefault=I.attributesDefault||[];I.attributesDefault.push({name:Y,value:T});U.defaultValue=T}if(W===":"){I.attributesForced=I.attributesForced||[];I.attributesForced.push({name:Y,value:T});U.forcedValue=T}if(W==="<"){U.validValues=e(T,"?")}}if(M.test(Y)){I.attributePatterns=I.attributePatterns||[];U.pattern=i(Y);I.attributePatterns.push(U)}else{if(!O[Y]){J.push(Y)}O[Y]=U}}}}if(!S&&Q=="@"){S=O;H=J}if(E){I.outputName=Q;s[E]=I}if(M.test(Q)){I.pattern=i(Q);j.push(I)}else{s[Q]=I}}}}}function t(E){s={};j=[];C(E);g(y,function(G,F){k[F]=G.children})}function l(F){var E=/^(~)?(.+)$/;if(F){g(d(F),function(J){var H=E.exec(J),I=H[1]==="~",K=I?"span":"div",G=H[2];k[G]=k[K];p[G]=K;if(!I){v[G.toUpperCase()]={};v[G]={}}if(!s[G]){s[G]=s[K]}g(k,function(L,M){if(L[K]){L[G]=L[K]}})})}}function x(F){var E=/^([+\-]?)(\w+)\[([^\]]+)\]$/;if(F){g(d(F),function(J){var I=E.exec(J),G,H;if(I){H=I[1];if(H){G=k[I[2]]}else{G=k[I[2]]={"#comment":{}}}G=k[I[2]];g(d(I[3],"|"),function(K){if(H==="-"){delete G[K]}else{G[K]={}}})}})}}function B(E){var G=s[E],F;if(G){return G}F=j.length;while(F--){G=j[F];if(G.pattern.test(E)){return G}}}if(!A.valid_elements){g(y,function(F,E){s[E]={attributes:F.attributes,attributesOrder:F.attributesOrder};k[E]=F.children});if(A.schema!="html5"){g(d("strong/b,em/i"),function(E){E=d(E,"/");s[E[1]].outputName=E[0]})}s.img.attributesDefault=[{name:"alt",value:""}];g(d("ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr,strong,em,b,i"),function(E){if(s[E]){s[E].removeEmpty=true}});g(d("p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption"),function(E){s[E].paddEmpty=true})}else{t(A.valid_elements)}l(A.custom_elements);x(A.valid_children);C(A.extended_valid_elements);x("+ol[ul|ol],+ul[ul|ol]");if(A.invalid_elements){f.each(f.explode(A.invalid_elements),function(E){if(s[E]){delete s[E]}})}if(!B("span")){C("span[!data-mce-type|*]")}u.children=k;u.styles=D;u.getBoolAttrs=function(){return r};u.getBlockElements=function(){return v};u.getTextBlockElements=function(){return textBlockElementsMap};u.getShortEndedElements=function(){return z};u.getSelfClosingElements=function(){return q};u.getNonEmptyElements=function(){return n};u.getWhiteSpaceElements=function(){return o};u.isValidChild=function(E,G){var F=k[E];return !!(F&&F[G])};u.isValid=function(F,E){var H,G,I=B(F);if(I){if(E){if(I.attributes[E]){return true}H=I.attributePatterns;if(H){G=H.length;while(G--){if(H[G].pattern.test(F)){return true}}}}else{return true}}return false};u.getElementRule=B;u.getCustomElements=function(){return p};u.addValidElements=C;u.setValidElements=t;u.addCustomElements=l;u.addValidChildren=x;u.elements=s}})(tinymce);(function(a){a.html.SaxParser=function(c,e){var b=this,d=function(){};c=c||{};b.schema=e=e||new a.html.Schema();if(c.fix_self_closing!==false){c.fix_self_closing=true}a.each("comment cdata text start end pi doctype".split(" "),function(f){if(f){b[f]=c[f]||d}});b.parse=function(E){var n=this,g,G=0,I,B,A=[],N,Q,C,r,z,s,M,H,O,v,m,k,t,R,o,P,F,S,L,f,J,l,D,K,h,x=0,j=a.html.Entities.decode,y,q;function u(T){var V,U;V=A.length;while(V--){if(A[V].name===T){break}}if(V>=0){for(U=A.length-1;U>=V;U--){T=A[U];if(T.valid){n.end(T.name)}}A.length=V}}function p(U,T,Y,X,W){var Z,V;T=T.toLowerCase();Y=T in H?T:j(Y||X||W||"");if(v&&!z&&T.indexOf("data-")!==0){Z=P[T];if(!Z&&F){V=F.length;while(V--){Z=F[V];if(Z.pattern.test(T)){break}}if(V===-1){Z=null}}if(!Z){return}if(Z.validValues&&!(Y in Z.validValues)){return}}N.map[T]=Y;N.push({name:T,value:Y})}l=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([^>]+)>)|(?:([A-Za-z0-9\\-\\:\\.]+)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g");D=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:[^\"])*)\")|(?:\'((?:[^\'])*)\')|([^>\s]+)))?/g;K={script:/<\/script[^>]*>/gi,style:/<\/style[^>]*>/gi,noscript:/<\/noscript[^>]*>/gi};M=e.getShortEndedElements();J=c.self_closing_elements||e.getSelfClosingElements();H=e.getBoolAttrs();v=c.validate;s=c.remove_internals;y=c.fix_self_closing;q=a.isIE;o=/^:/;while(g=l.exec(E)){if(G<g.index){n.text(j(E.substr(G,g.index-G)))}if(I=g[6]){I=I.toLowerCase();if(q&&o.test(I)){I=I.substr(1)}u(I)}else{if(I=g[7]){I=I.toLowerCase();if(q&&o.test(I)){I=I.substr(1)}O=I in M;if(y&&J[I]&&A.length>0&&A[A.length-1].name===I){u(I)}if(!v||(m=e.getElementRule(I))){k=true;if(v){P=m.attributes;F=m.attributePatterns}if(R=g[8]){z=R.indexOf("data-mce-type")!==-1;if(z&&s){k=false}N=[];N.map={};R.replace(D,p)}else{N=[];N.map={}}if(v&&!z){S=m.attributesRequired;L=m.attributesDefault;f=m.attributesForced;if(f){Q=f.length;while(Q--){t=f[Q];r=t.name;h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}if(L){Q=L.length;while(Q--){t=L[Q];r=t.name;if(!(r in N.map)){h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}}if(S){Q=S.length;while(Q--){if(S[Q] in N.map){break}}if(Q===-1){k=false}}if(N.map["data-mce-bogus"]){k=false}}if(k){n.start(I,N,O)}}else{k=false}if(B=K[I]){B.lastIndex=G=g.index+g[0].length;if(g=B.exec(E)){if(k){C=E.substr(G,g.index-G)}G=g.index+g[0].length}else{C=E.substr(G);G=E.length}if(k&&C.length>0){n.text(C,true)}if(k){n.end(I)}l.lastIndex=G;continue}if(!O){if(!R||R.indexOf("/")!=R.length-1){A.push({name:I,valid:k})}else{if(k){n.end(I)}}}}else{if(I=g[1]){n.comment(I)}else{if(I=g[2]){n.cdata(I)}else{if(I=g[3]){n.doctype(I)}else{if(I=g[4]){n.pi(I,g[5])}}}}}}G=g.index+g[0].length}if(G<E.length){n.text(j(E.substr(G)))}for(Q=A.length-1;Q>=0;Q--){I=A[Q];if(I.valid){n.end(I.name)}}}}})(tinymce);(function(d){var c=/^[ \t\r\n]*$/,e={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};function a(k,l,j){var i,h,f=j?"lastChild":"firstChild",g=j?"prev":"next";if(k[f]){return k[f]}if(k!==l){i=k[g];if(i){return i}for(h=k.parent;h&&h!==l;h=h.parent){i=h[g];if(i){return i}}}}function b(f,g){this.name=f;this.type=g;if(g===1){this.attributes=[];this.attributes.map={}}}d.extend(b.prototype,{replace:function(g){var f=this;if(g.parent){g.remove()}f.insert(g,f);f.remove();return f},attr:function(h,l){var f=this,g,j,k;if(typeof h!=="string"){for(j in h){f.attr(j,h[j])}return f}if(g=f.attributes){if(l!==k){if(l===null){if(h in g.map){delete g.map[h];j=g.length;while(j--){if(g[j].name===h){g=g.splice(j,1);return f}}}return f}if(h in g.map){j=g.length;while(j--){if(g[j].name===h){g[j].value=l;break}}}else{g.push({name:h,value:l})}g.map[h]=l;return f}else{return g.map[h]}}},clone:function(){var g=this,n=new b(g.name,g.type),h,f,m,j,k;if(m=g.attributes){k=[];k.map={};for(h=0,f=m.length;h<f;h++){j=m[h];if(j.name!=="id"){k[k.length]={name:j.name,value:j.value};k.map[j.name]=j.value}}n.attributes=k}n.value=g.value;n.shortEnded=g.shortEnded;return n},wrap:function(g){var f=this;f.parent.insert(g,f);g.append(f);return f},unwrap:function(){var f=this,h,g;for(h=f.firstChild;h;){g=h.next;f.insert(h,f,true);h=g}f.remove()},remove:function(){var f=this,h=f.parent,g=f.next,i=f.prev;if(h){if(h.firstChild===f){h.firstChild=g;if(g){g.prev=null}}else{i.next=g}if(h.lastChild===f){h.lastChild=i;if(i){i.next=null}}else{g.prev=i}f.parent=f.next=f.prev=null}return f},append:function(h){var f=this,g;if(h.parent){h.remove()}g=f.lastChild;if(g){g.next=h;h.prev=g;f.lastChild=h}else{f.lastChild=f.firstChild=h}h.parent=f;return h},insert:function(h,f,i){var g;if(h.parent){h.remove()}g=f.parent||this;if(i){if(f===g.firstChild){g.firstChild=h}else{f.prev.next=h}h.prev=f.prev;h.next=f;f.prev=h}else{if(f===g.lastChild){g.lastChild=h}else{f.next.prev=h}h.next=f.next;h.prev=f;f.next=h}h.parent=g;return h},getAll:function(g){var f=this,h,i=[];for(h=f.firstChild;h;h=a(h,f)){if(h.name===g){i.push(h)}}return i},empty:function(){var g=this,f,h,j;if(g.firstChild){f=[];for(j=g.firstChild;j;j=a(j,g)){f.push(j)}h=f.length;while(h--){j=f[h];j.parent=j.firstChild=j.lastChild=j.next=j.prev=null}}g.firstChild=g.lastChild=null;return g},isEmpty:function(k){var f=this,j=f.firstChild,h,g;if(j){do{if(j.type===1){if(j.attributes.map["data-mce-bogus"]){continue}if(k[j.name]){return false}h=j.attributes.length;while(h--){g=j.attributes[h].name;if(g==="name"||g.indexOf("data-mce-")===0){return false}}}if(j.type===8){return false}if((j.type===3&&!c.test(j.value))){return false}}while(j=a(j,f))}return true},walk:function(f){return a(this,null,f)}});d.extend(b,{create:function(g,f){var i,h;i=new b(g,e[g]||1);if(f){for(h in f){i.attr(h,f[h])}}return i}});d.html.Node=b})(tinymce);(function(b){var a=b.html.Node;b.html.DomParser=function(g,h){var f=this,e={},d=[],i={},c={};g=g||{};g.validate="validate" in g?g.validate:true;g.root_name=g.root_name||"body";f.schema=h=h||new b.html.Schema();function j(n){var p,q,y,x,A,o,r,l,u,v,k,t,m,z,s;t=b.makeMap("tr,td,th,tbody,thead,tfoot,table");k=h.getNonEmptyElements();m=h.getTextBlockElements();for(p=0;p<n.length;p++){q=n[p];if(!q.parent||q.fixed){continue}if(m[q.name]&&q.parent.name=="li"){z=q.next;while(z){if(m[z.name]){z.name="li";z.fixed=true;q.parent.insert(z,q.parent)}else{break}z=z.next}q.unwrap(q);continue}x=[q];for(y=q.parent;y&&!h.isValidChild(y.name,q.name)&&!t[y.name];y=y.parent){x.push(y)}if(y&&x.length>1){x.reverse();A=o=f.filterNode(x[0].clone());for(u=0;u<x.length-1;u++){if(h.isValidChild(o.name,x[u].name)){r=f.filterNode(x[u].clone());o.append(r)}else{r=o}for(l=x[u].firstChild;l&&l!=x[u+1];){s=l.next;r.append(l);l=s}o=r}if(!A.isEmpty(k)){y.insert(A,x[0],true);y.insert(q,A)}else{y.insert(q,x[0],true)}y=x[0];if(y.isEmpty(k)||y.firstChild===y.lastChild&&y.firstChild.name==="br"){y.empty().remove()}}else{if(q.parent){if(q.name==="li"){z=q.prev;if(z&&(z.name==="ul"||z.name==="ul")){z.append(q);continue}z=q.next;if(z&&(z.name==="ul"||z.name==="ul")){z.insert(q,z.firstChild,true);continue}q.wrap(f.filterNode(new a("ul",1)));continue}if(h.isValidChild(q.parent.name,"div")&&h.isValidChild("div",q.name)){q.wrap(f.filterNode(new a("div",1)))}else{if(q.name==="style"||q.name==="script"){q.empty().remove()}else{q.unwrap()}}}}}}f.filterNode=function(m){var l,k,n;if(k in e){n=i[k];if(n){n.push(m)}else{i[k]=[m]}}l=d.length;while(l--){k=d[l].name;if(k in m.attributes.map){n=c[k];if(n){n.push(m)}else{c[k]=[m]}}}return m};f.addNodeFilter=function(k,l){b.each(b.explode(k),function(m){var n=e[m];if(!n){e[m]=n=[]}n.push(l)})};f.addAttributeFilter=function(k,l){b.each(b.explode(k),function(m){var n;for(n=0;n<d.length;n++){if(d[n].name===m){d[n].callbacks.push(l);return}}d.push({name:m,callbacks:[l]})})};f.parse=function(v,m){var n,J,B,A,D,C,x,r,F,N,z,o,E,M=[],L,t,k,y,s,p,u,q;m=m||{};i={};c={};o=b.extend(b.makeMap("script,style,head,html,body,title,meta,param"),h.getBlockElements());u=h.getNonEmptyElements();p=h.children;z=g.validate;q="forced_root_block" in m?m.forced_root_block:g.forced_root_block;s=h.getWhiteSpaceElements();E=/^[ \t\r\n]+/;t=/[ \t\r\n]+$/;k=/[ \t\r\n]+/g;y=/^[ \t\r\n]+$/;function G(){var O=J.firstChild,l,P;while(O){l=O.next;if(O.type==3||(O.type==1&&O.name!=="p"&&!o[O.name]&&!O.attr("data-mce-type"))){if(!P){P=K(q,1);J.insert(P,O);P.append(O)}else{P.append(O)}}else{P=null}O=l}}function K(l,O){var P=new a(l,O),Q;if(l in e){Q=i[l];if(Q){Q.push(P)}else{i[l]=[P]}}return P}function I(P){var Q,l,O;for(Q=P.prev;Q&&Q.type===3;){l=Q.value.replace(t,"");if(l.length>0){Q.value=l;Q=Q.prev}else{O=Q.prev;Q.remove();Q=O}}}function H(O){var P,l={};for(P in O){if(P!=="li"&&P!="p"){l[P]=O[P]}}return l}n=new b.html.SaxParser({validate:z,self_closing_elements:H(h.getSelfClosingElements()),cdata:function(l){B.append(K("#cdata",4)).value=l},text:function(P,l){var O;if(!L){P=P.replace(k," ");if(B.lastChild&&o[B.lastChild.name]){P=P.replace(E,"")}}if(P.length!==0){O=K("#text",3);O.raw=!!l;B.append(O).value=P}},comment:function(l){B.append(K("#comment",8)).value=l},pi:function(l,O){B.append(K(l,7)).value=O;I(B)},doctype:function(O){var l;l=B.append(K("#doctype",10));l.value=O;I(B)},start:function(l,W,P){var U,R,Q,O,S,X,V,T;Q=z?h.getElementRule(l):{};if(Q){U=K(Q.outputName||l,1);U.attributes=W;U.shortEnded=P;B.append(U);T=p[B.name];if(T&&p[U.name]&&!T[U.name]){M.push(U)}R=d.length;while(R--){S=d[R].name;if(S in W.map){F=c[S];if(F){F.push(U)}else{c[S]=[U]}}}if(o[l]){I(U)}if(!P){B=U}if(!L&&s[l]){L=true}}},end:function(l){var S,P,R,O,Q;P=z?h.getElementRule(l):{};if(P){if(o[l]){if(!L){S=B.firstChild;if(S&&S.type===3){R=S.value.replace(E,"");if(R.length>0){S.value=R;S=S.next}else{O=S.next;S.remove();S=O}while(S&&S.type===3){R=S.value;O=S.next;if(R.length===0||y.test(R)){S.remove();S=O}S=O}}S=B.lastChild;if(S&&S.type===3){R=S.value.replace(t,"");if(R.length>0){S.value=R;S=S.prev}else{O=S.prev;S.remove();S=O}while(S&&S.type===3){R=S.value;O=S.prev;if(R.length===0||y.test(R)){S.remove();S=O}S=O}}}}if(L&&s[l]){L=false}if(P.removeEmpty||P.paddEmpty){if(B.isEmpty(u)){if(P.paddEmpty){B.empty().append(new a("#text","3")).value="\u00a0"}else{if(!B.attributes.map.name&&!B.attributes.map.id){Q=B.parent;B.empty().remove();B=Q;return}}}}B=B.parent}}},h);J=B=new a(m.context||g.root_name,11);n.parse(v);if(z&&M.length){if(!m.context){j(M)}else{m.invalid=true}}if(q&&J.name=="body"){G()}if(!m.invalid){for(N in i){F=e[N];A=i[N];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(D=0,C=F.length;D<C;D++){F[D](A,N,m)}}for(D=0,C=d.length;D<C;D++){F=d[D];if(F.name in c){A=c[F.name];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(x=0,r=F.callbacks.length;x<r;x++){F.callbacks[x](A,F.name,m)}}}}return J};if(g.remove_trailing_brs){f.addNodeFilter("br",function(n,m){var r,q=n.length,o,v=b.extend({},h.getBlockElements()),k=h.getNonEmptyElements(),t,s,p,u;v.body=1;for(r=0;r<q;r++){o=n[r];t=o.parent;if(v[o.parent.name]&&o===t.lastChild){p=o.prev;while(p){u=p.name;if(u!=="span"||p.attr("data-mce-type")!=="bookmark"){if(u!=="br"){break}if(u==="br"){o=null;break}}p=p.prev}if(o){o.remove();if(t.isEmpty(k)){elementRule=h.getElementRule(t.name);if(elementRule){if(elementRule.removeEmpty){t.remove()}else{if(elementRule.paddEmpty){t.empty().append(new b.html.Node("#text",3)).value="\u00a0"}}}}}}else{s=o;while(t.firstChild===s&&t.lastChild===s){s=t;if(v[t.name]){break}t=t.parent}if(s===t){textNode=new b.html.Node("#text",3);textNode.value="\u00a0";o.replace(textNode)}}}})}if(!g.allow_html_in_named_anchor){f.addAttributeFilter("id,name",function(k,l){var n=k.length,p,m,o,q;while(n--){q=k[n];if(q.name==="a"&&q.firstChild&&!q.attr("href")){o=q.parent;p=q.lastChild;do{m=p.prev;o.insert(p,q);p=m}while(p)}}})}}})(tinymce);tinymce.html.Writer=function(e){var c=[],a,b,d,f,g;e=e||{};a=e.indent;b=tinymce.makeMap(e.indent_before||"");d=tinymce.makeMap(e.indent_after||"");f=tinymce.html.Entities.getEncodeFunc(e.entity_encoding||"raw",e.entities);g=e.element_format=="html";return{start:function(m,k,p){var n,j,h,o;if(a&&b[m]&&c.length>0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}c.push("<",m);if(k){for(n=0,j=k.length;n<j;n++){h=k[n];c.push(" ",h.name,'="',f(h.value,true),'"')}}if(!p||g){c[c.length]=">"}else{c[c.length]=" />"}if(p&&a&&d[m]&&c.length>0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}},end:function(h){var i;c.push("</",h,">");if(a&&d[h]&&c.length>0){i=c[c.length-1];if(i.length>0&&i!=="\n"){c.push("\n")}}},text:function(i,h){if(i.length>0){c[c.length]=h?i:f(i)}},cdata:function(h){c.push("<![CDATA[",h,"]]>")},comment:function(h){c.push("<!--",h,"-->")},pi:function(h,i){if(i){c.push("<?",h," ",i,"?>")}else{c.push("<?",h,"?>")}if(a){c.push("\n")}},doctype:function(h){c.push("<!DOCTYPE",h,">",a?"\n":"")},reset:function(){c.length=0},getContent:function(){return c.join("").replace(/\n$/,"")}}};(function(a){a.html.Serializer=function(c,d){var b=this,e=new a.html.Writer(c);c=c||{};c.validate="validate" in c?c.validate:true;b.schema=d=d||new a.html.Schema();b.writer=e;b.serialize=function(h){var g,i;i=c.validate;g={3:function(k,j){e.text(k.value,k.raw)},8:function(j){e.comment(j.value)},7:function(j){e.pi(j.name,j.value)},10:function(j){e.doctype(j.value)},4:function(j){e.cdata(j.value)},11:function(j){if((j=j.firstChild)){do{f(j)}while(j=j.next)}}};e.reset();function f(k){var t=g[k.type],j,o,s,r,p,u,n,m,q;if(!t){j=k.name;o=k.shortEnded;s=k.attributes;if(i&&s&&s.length>1){u=[];u.map={};q=d.getElementRule(k.name);for(n=0,m=q.attributesOrder.length;n<m;n++){r=q.attributesOrder[n];if(r in s.map){p=s.map[r];u.map[r]=p;u.push({name:r,value:p})}}for(n=0,m=s.length;n<m;n++){r=s[n].name;if(!(r in u.map)){p=s.map[r];u.map[r]=p;u.push({name:r,value:p})}}s=u}e.start(k.name,s,o);if(!o){if((k=k.firstChild)){do{f(k)}while(k=k.next)}e.end(j)}}else{t(k)}}if(h.type==1&&!c.inner){f(h)}else{g[11](h)}return e.getContent()}}})(tinymce);tinymce.dom={};(function(b,h){var g=!!document.addEventListener;function c(k,j,l,i){if(k.addEventListener){k.addEventListener(j,l,i||false)}else{if(k.attachEvent){k.attachEvent("on"+j,l)}}}function e(k,j,l,i){if(k.removeEventListener){k.removeEventListener(j,l,i||false)}else{if(k.detachEvent){k.detachEvent("on"+j,l)}}}function a(n,l){var i,k=l||{};function j(){return false}function m(){return true}for(i in n){if(i!=="layerX"&&i!=="layerY"){k[i]=n[i]}}if(!k.target){k.target=k.srcElement||document}k.preventDefault=function(){k.isDefaultPrevented=m;if(n){if(n.preventDefault){n.preventDefault()}else{n.returnValue=false}}};k.stopPropagation=function(){k.isPropagationStopped=m;if(n){if(n.stopPropagation){n.stopPropagation()}else{n.cancelBubble=true}}};k.stopImmediatePropagation=function(){k.isImmediatePropagationStopped=m;k.stopPropagation()};if(!k.isDefaultPrevented){k.isDefaultPrevented=j;k.isPropagationStopped=j;k.isImmediatePropagationStopped=j}return k}function d(m,n,l){var k=m.document,j={type:"ready"};function i(){if(!l.domLoaded){l.domLoaded=true;n(j)}}if(k.readyState=="complete"){i();return}if(g){c(m,"DOMContentLoaded",i)}else{c(k,"readystatechange",function(){if(k.readyState==="complete"){e(k,"readystatechange",arguments.callee);i()}});if(k.documentElement.doScroll&&m===m.top){(function(){try{k.documentElement.doScroll("left")}catch(o){setTimeout(arguments.callee,0);return}i()})()}}c(m,"load",i)}function f(k){var q=this,p={},i,o,n,m,l;m="onmouseenter" in document.documentElement;n="onfocusin" in document.documentElement;l={mouseenter:"mouseover",mouseleave:"mouseout"};i=1;q.domLoaded=false;q.events=p;function j(t,x){var s,u,r,v;s=p[x][t.type];if(s){for(u=0,r=s.length;u<r;u++){v=s[u];if(v&&v.func.call(v.scope,t)===false){t.preventDefault()}if(t.isImmediatePropagationStopped()){return}}}}q.bind=function(x,A,D,E){var s,t,u,r,B,z,C,v=window;function y(F){j(a(F||v.event),s)}if(!x||x.nodeType===3||x.nodeType===8){return}if(!x[h]){s=i++;x[h]=s;p[s]={}}else{s=x[h];if(!p[s]){p[s]={}}}E=E||x;A=A.split(" ");u=A.length;while(u--){r=A[u];z=y;B=C=false;if(r==="DOMContentLoaded"){r="ready"}if((q.domLoaded||x.readyState=="complete")&&r==="ready"){q.domLoaded=true;D.call(E,a({type:r}));continue}if(!m){B=l[r];if(B){z=function(F){var H,G;H=F.currentTarget;G=F.relatedTarget;if(G&&H.contains){G=H.contains(G)}else{while(G&&G!==H){G=G.parentNode}}if(!G){F=a(F||v.event);F.type=F.type==="mouseout"?"mouseleave":"mouseenter";F.target=H;j(F,s)}}}}if(!n&&(r==="focusin"||r==="focusout")){C=true;B=r==="focusin"?"focus":"blur";z=function(F){F=a(F||v.event);F.type=F.type==="focus"?"focusin":"focusout";j(F,s)}}t=p[s][r];if(!t){p[s][r]=t=[{func:D,scope:E}];t.fakeName=B;t.capture=C;t.nativeHandler=z;if(!g){t.proxyHandler=k(s)}if(r==="ready"){d(x,z,q)}else{c(x,B||r,g?z:t.proxyHandler,C)}}else{t.push({func:D,scope:E})}}x=t=0;return D};q.unbind=function(x,z,A){var s,u,v,B,r,t;if(!x||x.nodeType===3||x.nodeType===8){return q}s=x[h];if(s){t=p[s];if(z){z=z.split(" ");v=z.length;while(v--){r=z[v];u=t[r];if(u){if(A){B=u.length;while(B--){if(u[B].func===A){u.splice(B,1)}}}if(!A||u.length===0){delete t[r];e(x,u.fakeName||r,g?u.nativeHandler:u.proxyHandler,u.capture)}}}}else{for(r in t){u=t[r];e(x,u.fakeName||r,g?u.nativeHandler:u.proxyHandler,u.capture)}t={}}for(r in t){return q}delete p[s];try{delete x[h]}catch(y){x[h]=null}}return q};q.fire=function(u,s,r){var v,t;if(!u||u.nodeType===3||u.nodeType===8){return q}t=a(null,r);t.type=s;do{v=u[h];if(v){j(t,v)}u=u.parentNode||u.ownerDocument||u.defaultView||u.parentWindow}while(u&&!t.isPropagationStopped());return q};q.clean=function(u){var s,r,t=q.unbind;if(!u||u.nodeType===3||u.nodeType===8){return q}if(u[h]){t(u)}if(!u.getElementsByTagName){u=u.document}if(u&&u.getElementsByTagName){t(u);r=u.getElementsByTagName("*");s=r.length;while(s--){u=r[s];if(u[h]){t(u)}}}return q};q.callNativeHandler=function(s,r){if(p){p[s][r.type].nativeHandler(r)}};q.destory=function(){p={}};q.add=function(v,s,u,t){if(typeof(v)==="string"){v=document.getElementById(v)}if(v&&v instanceof Array){var r=v.length;while(r--){q.add(v[r],s,u,t)}return}if(s==="init"){s="ready"}return q.bind(v,s instanceof Array?s.join(" "):s,u,t)};q.remove=function(v,s,u,t){if(!v){return q}if(typeof(v)==="string"){v=document.getElementById(v)}if(v instanceof Array){var r=v.length;while(r--){q.remove(v[r],s,u,t)}return q}return q.unbind(v,s instanceof Array?s.join(" "):s,u)};q.clear=function(r){if(typeof(r)==="string"){r=document.getElementById(r)}return q.clean(r)};q.cancel=function(r){if(r){q.prevent(r);q.stop(r)}return false};q.prevent=function(r){if(!r.preventDefault){r=a(r)}r.preventDefault();return false};q.stop=function(r){if(!r.stopPropagation){r=a(r)}r.stopPropagation();return false}}b.EventUtils=f;b.Event=new f(function(i){return function(j){tinymce.dom.Event.callNativeHandler(i,j)}});b.Event.bind(window,"ready",function(){});b=0})(tinymce.dom,"data-mce-expando");tinymce.dom.TreeWalker=function(a,c){var b=a;function d(i,f,e,j){var h,g;if(i){if(!j&&i[f]){return i[f]}if(i!=c){h=i[e];if(h){return h}for(g=i.parentNode;g&&g!=c;g=g.parentNode){h=g[e];if(h){return h}}}}}this.current=function(){return b};this.next=function(e){return(b=d(b,"firstChild","nextSibling",e))};this.prev=function(e){return(b=d(b,"lastChild","previousSibling",e))}};(function(e){var g=e.each,d=e.is,f=e.isWebKit,b=e.isIE,h=e.html.Entities,c=/^([a-z0-9],?)+$/i,a=/^[ \t\r\n]*$/;e.create("tinymce.dom.DOMUtils",{doc:null,root:null,files:null,pixelStyles:/^(top|left|bottom|right|width|height|borderWidth)$/,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},DOMUtils:function(o,l){var k=this,i,j,n;k.doc=o;k.win=window;k.files={};k.cssFlicker=false;k.counter=0;k.stdMode=!e.isIE||o.documentMode>=8;k.boxModel=!e.isIE||o.compatMode=="CSS1Compat"||k.stdMode;k.hasOuterHTML="outerHTML" in o.createElement("a");k.settings=l=e.extend({keep_values:false,hex_colors:1},l);k.schema=l.schema;k.styles=new e.html.Styles({url_converter:l.url_converter,url_converter_scope:l.url_converter_scope},l.schema);if(e.isIE6){try{o.execCommand("BackgroundImageCache",false,true)}catch(m){k.cssFlicker=true}}k.fixDoc(o);k.events=l.ownEvents?new e.dom.EventUtils(l.proxy):e.dom.Event;e.addUnload(k.destroy,k);n=l.schema?l.schema.getBlockElements():{};k.isBlock=function(q){if(!q){return false}var p=q.nodeType;if(p){return !!(p===1&&n[q.nodeName])}return !!n[q]}},fixDoc:function(k){var j=this.settings,i;if(b&&j.schema){("abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video").replace(/\w+/g,function(l){k.createElement(l)});for(i in j.schema.getCustomElements()){k.createElement(i)}}},clone:function(k,i){var j=this,m,l;if(!b||k.nodeType!==1||i){return k.cloneNode(i)}l=j.doc;if(!i){m=l.createElement(k.nodeName);g(j.getAttribs(k),function(n){j.setAttrib(m,n.nodeName,j.getAttrib(k,n.nodeName))});return m}return m.firstChild},getRoot:function(){var i=this,j=i.settings;return(j&&i.get(j.root_element))||i.doc.body},getViewPort:function(j){var k,i;j=!j?this.win:j;k=j.document;i=this.boxModel?k.documentElement:k.body;return{x:j.pageXOffset||i.scrollLeft,y:j.pageYOffset||i.scrollTop,w:j.innerWidth||i.clientWidth,h:j.innerHeight||i.clientHeight}},getRect:function(l){var k,i=this,j;l=i.get(l);k=i.getPos(l);j=i.getSize(l);return{x:k.x,y:k.y,w:j.w,h:j.h}},getSize:function(l){var j=this,i,k;l=j.get(l);i=j.getStyle(l,"width");k=j.getStyle(l,"height");if(i.indexOf("px")===-1){i=0}if(k.indexOf("px")===-1){k=0}return{w:parseInt(i,10)||l.offsetWidth||l.clientWidth,h:parseInt(k,10)||l.offsetHeight||l.clientHeight}},getParent:function(k,j,i){return this.getParents(k,j,i,false)},getParents:function(s,m,k,q){var j=this,i,l=j.settings,p=[];s=j.get(s);q=q===undefined;if(l.strict_root){k=k||j.getRoot()}if(d(m,"string")){i=m;if(m==="*"){m=function(o){return o.nodeType==1}}else{m=function(o){return j.is(o,i)}}}while(s){if(s==k||!s.nodeType||s.nodeType===9){break}if(!m||m(s)){if(q){p.push(s)}else{return s}}s=s.parentNode}return q?p:null},get:function(i){var j;if(i&&this.doc&&typeof(i)=="string"){j=i;i=this.doc.getElementById(i);if(i&&i.id!==j){return this.doc.getElementsByName(j)[1]}}return i},getNext:function(j,i){return this._findSib(j,i,"nextSibling")},getPrev:function(j,i){return this._findSib(j,i,"previousSibling")},select:function(k,j){var i=this;return e.dom.Sizzle(k,i.get(j)||i.get(i.settings.root_element)||i.doc,[])},is:function(l,j){var k;if(l.length===undefined){if(j==="*"){return l.nodeType==1}if(c.test(j)){j=j.toLowerCase().split(/,/);l=l.nodeName.toLowerCase();for(k=j.length-1;k>=0;k--){if(j[k]==l){return true}}return false}}return e.dom.Sizzle.matches(j,l.nodeType?[l]:l).length>0},add:function(l,o,i,k,m){var j=this;return this.run(l,function(r){var q,n;q=d(o,"string")?j.doc.createElement(o):o;j.setAttribs(q,i);if(k){if(k.nodeType){q.appendChild(k)}else{j.setHTML(q,k)}}return !m?r.appendChild(q):q})},create:function(k,i,j){return this.add(this.doc.createElement(k),k,i,j,1)},createHTML:function(q,i,m){var p="",l=this,j;p+="<"+q;for(j in i){if(i.hasOwnProperty(j)){p+=" "+j+'="'+l.encode(i[j])+'"'}}if(typeof(m)!="undefined"){return p+">"+m+"</"+q+">"}return p+" />"},remove:function(i,j){return this.run(i,function(l){var m,k=l.parentNode;if(!k){return null}if(j){while(m=l.firstChild){if(!e.isIE||m.nodeType!==3||m.nodeValue){k.insertBefore(m,l)}else{l.removeChild(m)}}}return k.removeChild(l)})},setStyle:function(l,i,j){var k=this;return k.run(l,function(o){var n,m;n=o.style;i=i.replace(/-(\D)/g,function(q,p){return p.toUpperCase()});if(k.pixelStyles.test(i)&&(e.is(j,"number")||/^[\-0-9\.]+$/.test(j))){j+="px"}switch(i){case"opacity":if(b){n.filter=j===""?"":"alpha(opacity="+(j*100)+")";if(!l.currentStyle||!l.currentStyle.hasLayout){n.display="inline-block"}}n[i]=n["-moz-opacity"]=n["-khtml-opacity"]=j||"";break;case"float":b?n.styleFloat=j:n.cssFloat=j;break;default:n[i]=j||""}if(k.settings.update_styles){k.setAttrib(o,"data-mce-style")}})},getStyle:function(l,i,k){l=this.get(l);if(!l){return}if(this.doc.defaultView&&k){i=i.replace(/[A-Z]/g,function(m){return"-"+m});try{return this.doc.defaultView.getComputedStyle(l,null).getPropertyValue(i)}catch(j){return null}}i=i.replace(/-(\D)/g,function(n,m){return m.toUpperCase()});if(i=="float"){i=b?"styleFloat":"cssFloat"}if(l.currentStyle&&k){return l.currentStyle[i]}return l.style?l.style[i]:undefined},setStyles:function(l,m){var j=this,k=j.settings,i;i=k.update_styles;k.update_styles=0;g(m,function(o,p){j.setStyle(l,p,o)});k.update_styles=i;if(k.update_styles){j.setAttrib(l,k.cssText)}},removeAllAttribs:function(i){return this.run(i,function(l){var k,j=l.attributes;for(k=j.length-1;k>=0;k--){l.removeAttributeNode(j.item(k))}})},setAttrib:function(k,l,i){var j=this;if(!k||!l){return}if(j.settings.strict){l=l.toLowerCase()}return this.run(k,function(p){var o=j.settings;var m=p.getAttribute(l);if(i!==null){switch(l){case"style":if(!d(i,"string")){g(i,function(q,r){j.setStyle(p,r,q)});return}if(o.keep_values){if(i&&!j._isRes(i)){p.setAttribute("data-mce-style",i,2)}else{p.removeAttribute("data-mce-style",2)}}p.style.cssText=i;break;case"class":p.className=i||"";break;case"src":case"href":if(o.keep_values){if(o.url_converter){i=o.url_converter.call(o.url_converter_scope||j,i,l,p)}j.setAttrib(p,"data-mce-"+l,i,2)}break;case"shape":p.setAttribute("data-mce-style",i);break}}if(d(i)&&i!==null&&i.length!==0){p.setAttribute(l,""+i,2)}else{p.removeAttribute(l,2)}if(tinyMCE.activeEditor&&m!=i){var n=tinyMCE.activeEditor;n.onSetAttrib.dispatch(n,p,l,i)}})},setAttribs:function(j,k){var i=this;return this.run(j,function(l){g(k,function(m,o){i.setAttrib(l,o,m)})})},getAttrib:function(m,o,k){var i,j=this,l;m=j.get(m);if(!m||m.nodeType!==1){return k===l?false:k}if(!d(k)){k=""}if(/^(src|href|style|coords|shape)$/.test(o)){i=m.getAttribute("data-mce-"+o);if(i){return i}}if(b&&j.props[o]){i=m[j.props[o]];i=i&&i.nodeValue?i.nodeValue:i}if(!i){i=m.getAttribute(o,2)}if(/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(o)){if(m[j.props[o]]===true&&i===""){return o}return i?o:""}if(m.nodeName==="FORM"&&m.getAttributeNode(o)){return m.getAttributeNode(o).nodeValue}if(o==="style"){i=i||m.style.cssText;if(i){i=j.serializeStyle(j.parseStyle(i),m.nodeName);if(j.settings.keep_values&&!j._isRes(i)){m.setAttribute("data-mce-style",i)}}}if(f&&o==="class"&&i){i=i.replace(/(apple|webkit)\-[a-z\-]+/gi,"")}if(b){switch(o){case"rowspan":case"colspan":if(i===1){i=""}break;case"size":if(i==="+0"||i===20||i===0){i=""}break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":if(i===0){i=""}break;case"hspace":if(i===-1){i=""}break;case"maxlength":case"tabindex":if(i===32768||i===2147483647||i==="32768"){i=""}break;case"multiple":case"compact":case"noshade":case"nowrap":if(i===65535){return o}return k;case"shape":i=i.toLowerCase();break;default:if(o.indexOf("on")===0&&i){i=e._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1",""+i)}}}return(i!==l&&i!==null&&i!=="")?""+i:k},getPos:function(q,l){var j=this,i=0,p=0,m,o=j.doc,k;q=j.get(q);l=l||o.body;if(q){if(q.getBoundingClientRect){q=q.getBoundingClientRect();m=j.boxModel?o.documentElement:o.body;i=q.left+(o.documentElement.scrollLeft||o.body.scrollLeft)-m.clientTop;p=q.top+(o.documentElement.scrollTop||o.body.scrollTop)-m.clientLeft;return{x:i,y:p}}k=q;while(k&&k!=l&&k.nodeType){i+=k.offsetLeft||0;p+=k.offsetTop||0;k=k.offsetParent}k=q.parentNode;while(k&&k!=l&&k.nodeType){i-=k.scrollLeft||0;p-=k.scrollTop||0;k=k.parentNode}}return{x:i,y:p}},parseStyle:function(i){return this.styles.parse(i)},serializeStyle:function(j,i){return this.styles.serialize(j,i)},addStyle:function(j){var k=this.doc,i;styleElm=k.getElementById("mceDefaultStyles");if(!styleElm){styleElm=k.createElement("style"),styleElm.id="mceDefaultStyles";styleElm.type="text/css";i=k.getElementsByTagName("head")[0];if(i.firstChild){i.insertBefore(styleElm,i.firstChild)}else{i.appendChild(styleElm)}}if(styleElm.styleSheet){styleElm.styleSheet.cssText+=j}else{styleElm.appendChild(k.createTextNode(j))}},loadCSS:function(i){var k=this,l=k.doc,j;if(!i){i=""}j=l.getElementsByTagName("head")[0];g(i.split(","),function(m){var n;if(k.files[m]){return}k.files[m]=true;n=k.create("link",{rel:"stylesheet",href:e._addVer(m)});if(b&&l.documentMode&&l.recalc){n.onload=function(){if(l.recalc){l.recalc()}n.onload=null}}j.appendChild(n)})},addClass:function(i,j){return this.run(i,function(k){var l;if(!j){return 0}if(this.hasClass(k,j)){return k.className}l=this.removeClass(k,j);return k.className=(l!=""?(l+" "):"")+j})},removeClass:function(k,l){var i=this,j;return i.run(k,function(n){var m;if(i.hasClass(n,l)){if(!j){j=new RegExp("(^|\\s+)"+l+"(\\s+|$)","g")}m=n.className.replace(j," ");m=e.trim(m!=" "?m:"");n.className=m;if(!m){n.removeAttribute("class");n.removeAttribute("className")}return m}return n.className})},hasClass:function(j,i){j=this.get(j);if(!j||!i){return false}return(" "+j.className+" ").indexOf(" "+i+" ")!==-1},show:function(i){return this.setStyle(i,"display","block")},hide:function(i){return this.setStyle(i,"display","none")},isHidden:function(i){i=this.get(i);return !i||i.style.display=="none"||this.getStyle(i,"display")=="none"},uniqueId:function(i){return(!i?"mce_":i)+(this.counter++)},setHTML:function(k,j){var i=this;return i.run(k,function(m){if(b){while(m.firstChild){m.removeChild(m.firstChild)}try{m.innerHTML="<br />"+j;m.removeChild(m.firstChild)}catch(l){var n=i.create("div");n.innerHTML="<br />"+j;g(e.grep(n.childNodes),function(p,o){if(o&&m.canHaveHTML){m.appendChild(p)}})}}else{m.innerHTML=j}return j})},getOuterHTML:function(k){var j,i=this;k=i.get(k);if(!k){return null}if(k.nodeType===1&&i.hasOuterHTML){return k.outerHTML}j=(k.ownerDocument||i.doc).createElement("body");j.appendChild(k.cloneNode(true));return j.innerHTML},setOuterHTML:function(l,j,m){var i=this;function k(p,o,r){var s,q;q=r.createElement("body");q.innerHTML=o;s=q.lastChild;while(s){i.insertAfter(s.cloneNode(true),p);s=s.previousSibling}i.remove(p)}return this.run(l,function(o){o=i.get(o);if(o.nodeType==1){m=m||o.ownerDocument||i.doc;if(b){try{if(b&&o.nodeType==1){o.outerHTML=j}else{k(o,j,m)}}catch(n){k(o,j,m)}}else{k(o,j,m)}}})},decode:h.decode,encode:h.encodeAllRaw,insertAfter:function(i,j){j=this.get(j);return this.run(i,function(l){var k,m;k=j.parentNode;m=j.nextSibling;if(m){k.insertBefore(l,m)}else{k.appendChild(l)}return l})},replace:function(m,l,i){var j=this;if(d(l,"array")){m=m.cloneNode(true)}return j.run(l,function(k){if(i){g(e.grep(k.childNodes),function(n){m.appendChild(n)})}return k.parentNode.replaceChild(m,k)})},rename:function(l,i){var k=this,j;if(l.nodeName!=i.toUpperCase()){j=k.create(i);g(k.getAttribs(l),function(m){k.setAttrib(j,m.nodeName,k.getAttrib(l,m.nodeName))});k.replace(j,l,1)}return j||l},findCommonAncestor:function(k,i){var l=k,j;while(l){j=i;while(j&&l!=j){j=j.parentNode}if(l==j){break}l=l.parentNode}if(!l&&k.ownerDocument){return k.ownerDocument.documentElement}return l},toHex:function(i){var k=/^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(i);function j(l){l=parseInt(l,10).toString(16);return l.length>1?l:"0"+l}if(k){i="#"+j(k[1])+j(k[2])+j(k[3]);return i}return i},getClasses:function(){var n=this,j=[],m,o={},p=n.settings.class_filter,l;if(n.classes){return n.classes}function q(i){g(i.imports,function(s){q(s)});g(i.cssRules||i.rules,function(s){switch(s.type||1){case 1:if(s.selectorText){g(s.selectorText.split(","),function(r){r=r.replace(/^\s*|\s*$|^\s\./g,"");if(/\.mce/.test(r)||!/\.[\w\-]+$/.test(r)){return}l=r;r=e._replace(/.*\.([a-z0-9_\-]+).*/i,"$1",r);if(p&&!(r=p(r,l))){return}if(!o[r]){j.push({"class":r});o[r]=1}})}break;case 3:q(s.styleSheet);break}})}try{g(n.doc.styleSheets,q)}catch(k){}if(j.length>0){n.classes=j}return j},run:function(l,k,j){var i=this,m;if(i.doc&&typeof(l)==="string"){l=i.get(l)}if(!l){return false}j=j||this;if(!l.nodeType&&(l.length||l.length===0)){m=[];g(l,function(o,n){if(o){if(typeof(o)=="string"){o=i.doc.getElementById(o)}m.push(k.call(j,o,n))}});return m}return k.call(j,l)},getAttribs:function(j){var i;j=this.get(j);if(!j){return[]}if(b){i=[];if(j.nodeName=="OBJECT"){return j.attributes}if(j.nodeName==="OPTION"&&this.getAttrib(j,"selected")){i.push({specified:1,nodeName:"selected"})}j.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi,"").replace(/[\w:\-]+/gi,function(k){i.push({specified:1,nodeName:k})});return i}return j.attributes},isEmpty:function(m,k){var r=this,o,n,q,j,l,p=0;m=m.firstChild;if(m){j=new e.dom.TreeWalker(m,m.parentNode);k=k||r.schema?r.schema.getNonEmptyElements():null;do{q=m.nodeType;if(q===1){if(m.getAttribute("data-mce-bogus")){continue}l=m.nodeName.toLowerCase();if(k&&k[l]){if(l==="br"){p++;continue}return false}n=r.getAttribs(m);o=m.attributes.length;while(o--){l=m.attributes[o].nodeName;if(l==="name"||l==="data-mce-bookmark"){return false}}}if(q==8){return false}if((q===3&&!a.test(m.nodeValue))){return false}}while(m=j.next())}return p<=1},destroy:function(j){var i=this;i.win=i.doc=i.root=i.events=i.frag=null;if(!j){e.removeUnload(i.destroy)}},createRng:function(){var i=this.doc;return i.createRange?i.createRange():new e.dom.Range(this)},nodeIndex:function(m,n){var i=0,k,l,j;if(m){for(k=m.nodeType,m=m.previousSibling,l=m;m;m=m.previousSibling){j=m.nodeType;if(n&&j==3){if(j==k||!m.nodeValue.length){continue}}i++;k=j}}return i},split:function(m,l,p){var q=this,i=q.createRng(),n,k,o;function j(v){var t,s=v.childNodes,u=v.nodeType;function x(A){var z=A.previousSibling&&A.previousSibling.nodeName=="SPAN";var y=A.nextSibling&&A.nextSibling.nodeName=="SPAN";return z&&y}if(u==1&&v.getAttribute("data-mce-type")=="bookmark"){return}for(t=s.length-1;t>=0;t--){j(s[t])}if(u!=9){if(u==3&&v.nodeValue.length>0){var r=e.trim(v.nodeValue).length;if(!q.isBlock(v.parentNode)||r>0||r===0&&x(v)){return}}else{if(u==1){s=v.childNodes;if(s.length==1&&s[0]&&s[0].nodeType==1&&s[0].getAttribute("data-mce-type")=="bookmark"){v.parentNode.insertBefore(s[0],v)}if(s.length||/^(br|hr|input|img)$/i.test(v.nodeName)){return}}}q.remove(v)}return v}if(m&&l){i.setStart(m.parentNode,q.nodeIndex(m));i.setEnd(l.parentNode,q.nodeIndex(l));n=i.extractContents();i=q.createRng();i.setStart(l.parentNode,q.nodeIndex(l)+1);i.setEnd(m.parentNode,q.nodeIndex(m)+1);k=i.extractContents();o=m.parentNode;o.insertBefore(j(n),m);if(p){o.replaceChild(p,l)}else{o.insertBefore(l,m)}o.insertBefore(j(k),m);q.remove(m);return p||l}},bind:function(l,i,k,j){return this.events.add(l,i,k,j||this)},unbind:function(k,i,j){return this.events.remove(k,i,j)},fire:function(k,j,i){return this.events.fire(k,j,i)},getContentEditable:function(j){var i;if(j.nodeType!=1){return null}i=j.getAttribute("data-mce-contenteditable");if(i&&i!=="inherit"){return i}return j.contentEditable!=="inherit"?j.contentEditable:null},_findSib:function(l,i,j){var k=this,m=i;if(l){if(d(m,"string")){m=function(n){return k.is(n,i)}}for(l=l[j];l;l=l[j]){if(m(l)){return l}}}return null},_isRes:function(i){return/^(top|left|bottom|right|width|height)/i.test(i)||/;\s*(top|left|bottom|right|width|height)/i.test(i)}});e.DOM=new e.dom.DOMUtils(document,{process_html:0})})(tinymce);(function(a){function b(c){var O=this,e=c.doc,U=0,F=1,j=2,E=true,S=false,W="startOffset",h="startContainer",Q="endContainer",A="endOffset",k=tinymce.extend,n=c.nodeIndex;k(O,{startContainer:e,startOffset:0,endContainer:e,endOffset:0,collapsed:E,commonAncestorContainer:e,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:q,setEnd:s,setStartBefore:g,setStartAfter:J,setEndBefore:K,setEndAfter:u,collapse:B,selectNode:y,selectNodeContents:G,compareBoundaryPoints:v,deleteContents:p,extractContents:I,cloneContents:d,insertNode:D,surroundContents:N,cloneRange:L,toStringIE:T});function x(){return e.createDocumentFragment()}function q(X,t){C(E,X,t)}function s(X,t){C(S,X,t)}function g(t){q(t.parentNode,n(t))}function J(t){q(t.parentNode,n(t)+1)}function K(t){s(t.parentNode,n(t))}function u(t){s(t.parentNode,n(t)+1)}function B(t){if(t){O[Q]=O[h];O[A]=O[W]}else{O[h]=O[Q];O[W]=O[A]}O.collapsed=E}function y(t){g(t);u(t)}function G(t){q(t,0);s(t,t.nodeType===1?t.childNodes.length:t.nodeValue.length)}function v(aa,t){var ad=O[h],Y=O[W],ac=O[Q],X=O[A],ab=t.startContainer,af=t.startOffset,Z=t.endContainer,ae=t.endOffset;if(aa===0){return H(ad,Y,ab,af)}if(aa===1){return H(ac,X,ab,af)}if(aa===2){return H(ac,X,Z,ae)}if(aa===3){return H(ad,Y,Z,ae)}}function p(){l(j)}function I(){return l(U)}function d(){return l(F)}function D(aa){var X=this[h],t=this[W],Z,Y;if((X.nodeType===3||X.nodeType===4)&&X.nodeValue){if(!t){X.parentNode.insertBefore(aa,X)}else{if(t>=X.nodeValue.length){c.insertAfter(aa,X)}else{Z=X.splitText(t);X.parentNode.insertBefore(aa,Z)}}}else{if(X.childNodes.length>0){Y=X.childNodes[t]}if(Y){X.insertBefore(aa,Y)}else{X.appendChild(aa)}}}function N(X){var t=O.extractContents();O.insertNode(X);X.appendChild(t);O.selectNode(X)}function L(){return k(new b(c),{startContainer:O[h],startOffset:O[W],endContainer:O[Q],endOffset:O[A],collapsed:O.collapsed,commonAncestorContainer:O.commonAncestorContainer})}function P(t,X){var Y;if(t.nodeType==3){return t}if(X<0){return t}Y=t.firstChild;while(Y&&X>0){--X;Y=Y.nextSibling}if(Y){return Y}return t}function m(){return(O[h]==O[Q]&&O[W]==O[A])}function H(Z,ab,X,aa){var ac,Y,t,ad,af,ae;if(Z==X){if(ab==aa){return 0}if(ab<aa){return -1}return 1}ac=X;while(ac&&ac.parentNode!=Z){ac=ac.parentNode}if(ac){Y=0;t=Z.firstChild;while(t!=ac&&Y<ab){Y++;t=t.nextSibling}if(ab<=Y){return -1}return 1}ac=Z;while(ac&&ac.parentNode!=X){ac=ac.parentNode}if(ac){Y=0;t=X.firstChild;while(t!=ac&&Y<aa){Y++;t=t.nextSibling}if(Y<aa){return -1}return 1}ad=c.findCommonAncestor(Z,X);af=Z;while(af&&af.parentNode!=ad){af=af.parentNode}if(!af){af=ad}ae=X;while(ae&&ae.parentNode!=ad){ae=ae.parentNode}if(!ae){ae=ad}if(af==ae){return 0}t=ad.firstChild;while(t){if(t==af){return -1}if(t==ae){return 1}t=t.nextSibling}}function C(X,aa,Z){var t,Y;if(X){O[h]=aa;O[W]=Z}else{O[Q]=aa;O[A]=Z}t=O[Q];while(t.parentNode){t=t.parentNode}Y=O[h];while(Y.parentNode){Y=Y.parentNode}if(Y==t){if(H(O[h],O[W],O[Q],O[A])>0){O.collapse(X)}}else{O.collapse(X)}O.collapsed=m();O.commonAncestorContainer=c.findCommonAncestor(O[h],O[Q])}function l(ad){var ac,Z=0,af=0,X,ab,Y,aa,t,ae;if(O[h]==O[Q]){return f(ad)}for(ac=O[Q],X=ac.parentNode;X;ac=X,X=X.parentNode){if(X==O[h]){return r(ac,ad)}++Z}for(ac=O[h],X=ac.parentNode;X;ac=X,X=X.parentNode){if(X==O[Q]){return V(ac,ad)}++af}ab=af-Z;Y=O[h];while(ab>0){Y=Y.parentNode;ab--}aa=O[Q];while(ab<0){aa=aa.parentNode;ab++}for(t=Y.parentNode,ae=aa.parentNode;t!=ae;t=t.parentNode,ae=ae.parentNode){Y=t;aa=ae}return o(Y,aa,ad)}function f(ac){var ae,af,t,Y,Z,ad,aa,X,ab;if(ac!=j){ae=x()}if(O[W]==O[A]){return ae}if(O[h].nodeType==3){af=O[h].nodeValue;t=af.substring(O[W],O[A]);if(ac!=F){Y=O[h];X=O[W];ab=O[A]-O[W];if(X===0&&ab>=Y.nodeValue.length-1){Y.parentNode.removeChild(Y)}else{Y.deleteData(X,ab)}O.collapse(E)}if(ac==j){return}if(t.length>0){ae.appendChild(e.createTextNode(t))}return ae}Y=P(O[h],O[W]);Z=O[A]-O[W];while(Y&&Z>0){ad=Y.nextSibling;aa=z(Y,ac);if(ae){ae.appendChild(aa)}--Z;Y=ad}if(ac!=F){O.collapse(E)}return ae}function r(ad,aa){var ac,ab,X,t,Z,Y;if(aa!=j){ac=x()}ab=i(ad,aa);if(ac){ac.appendChild(ab)}X=n(ad);t=X-O[W];if(t<=0){if(aa!=F){O.setEndBefore(ad);O.collapse(S)}return ac}ab=ad.previousSibling;while(t>0){Z=ab.previousSibling;Y=z(ab,aa);if(ac){ac.insertBefore(Y,ac.firstChild)}--t;ab=Z}if(aa!=F){O.setEndBefore(ad);O.collapse(S)}return ac}function V(ab,aa){var ad,X,ac,t,Z,Y;if(aa!=j){ad=x()}ac=R(ab,aa);if(ad){ad.appendChild(ac)}X=n(ab);++X;t=O[A]-X;ac=ab.nextSibling;while(ac&&t>0){Z=ac.nextSibling;Y=z(ac,aa);if(ad){ad.appendChild(Y)}--t;ac=Z}if(aa!=F){O.setStartAfter(ab);O.collapse(E)}return ad}function o(ab,t,ae){var Y,ag,aa,ac,ad,X,af,Z;if(ae!=j){ag=x()}Y=R(ab,ae);if(ag){ag.appendChild(Y)}aa=ab.parentNode;ac=n(ab);ad=n(t);++ac;X=ad-ac;af=ab.nextSibling;while(X>0){Z=af.nextSibling;Y=z(af,ae);if(ag){ag.appendChild(Y)}af=Z;--X}Y=i(t,ae);if(ag){ag.appendChild(Y)}if(ae!=F){O.setStartAfter(ab);O.collapse(E)}return ag}function i(ac,ad){var Y=P(O[Q],O[A]-1),ae,ab,aa,t,X,Z=Y!=O[Q];if(Y==ac){return M(Y,Z,S,ad)}ae=Y.parentNode;ab=M(ae,S,S,ad);while(ae){while(Y){aa=Y.previousSibling;t=M(Y,Z,S,ad);if(ad!=j){ab.insertBefore(t,ab.firstChild)}Z=E;Y=aa}if(ae==ac){return ab}Y=ae.previousSibling;ae=ae.parentNode;X=M(ae,S,S,ad);if(ad!=j){X.appendChild(ab)}ab=X}}function R(ac,ad){var Z=P(O[h],O[W]),aa=Z!=O[h],ae,ab,Y,t,X;if(Z==ac){return M(Z,aa,E,ad)}ae=Z.parentNode;ab=M(ae,S,E,ad);while(ae){while(Z){Y=Z.nextSibling;t=M(Z,aa,E,ad);if(ad!=j){ab.appendChild(t)}aa=E;Z=Y}if(ae==ac){return ab}Z=ae.nextSibling;ae=ae.parentNode;X=M(ae,S,E,ad);if(ad!=j){X.appendChild(ab)}ab=X}}function M(t,aa,ad,ae){var Z,Y,ab,X,ac;if(aa){return z(t,ae)}if(t.nodeType==3){Z=t.nodeValue;if(ad){X=O[W];Y=Z.substring(X);ab=Z.substring(0,X)}else{X=O[A];Y=Z.substring(0,X);ab=Z.substring(X)}if(ae!=F){t.nodeValue=ab}if(ae==j){return}ac=c.clone(t,S);ac.nodeValue=Y;return ac}if(ae==j){return}return c.clone(t,S)}function z(X,t){if(t!=j){return t==F?c.clone(X,E):X}X.parentNode.removeChild(X)}function T(){return c.create("body",null,d()).outerText}return O}a.Range=b;b.prototype.toString=function(){return this.toStringIE()}})(tinymce.dom);(function(){function a(d){var b=this,h=d.dom,c=true,f=false;function e(i,j){var k,t=0,q,n,m,l,o,r,p=-1,s;k=i.duplicate();k.collapse(j);s=k.parentElement();if(s.ownerDocument!==d.dom.doc){return}while(s.contentEditable==="false"){s=s.parentNode}if(!s.hasChildNodes()){return{node:s,inside:1}}m=s.children;q=m.length-1;while(t<=q){r=Math.floor((t+q)/2);l=m[r];k.moveToElementText(l);p=k.compareEndPoints(j?"StartToStart":"EndToEnd",i);if(p>0){q=r-1}else{if(p<0){t=r+1}else{return{node:l}}}}if(p<0){if(!l){k.moveToElementText(s);k.collapse(true);l=s;n=true}else{k.collapse(false)}o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",1)===0||s!=k.parentElement()){break}o++}}else{k.collapse(true);o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",-1)===0||s!=k.parentElement()){break}o++}}return{node:l,position:p,offset:o,inside:n}}function g(){var i=d.getRng(),r=h.createRng(),l,k,p,q,m,j;l=i.item?i.item(0):i.parentElement();if(l.ownerDocument!=h.doc){return r}k=d.isCollapsed();if(i.item){r.setStart(l.parentNode,h.nodeIndex(l));r.setEnd(r.startContainer,r.startOffset+1);return r}function o(A){var u=e(i,A),s,y,z=0,x,v,t;s=u.node;y=u.offset;if(u.inside&&!s.hasChildNodes()){r[A?"setStart":"setEnd"](s,0);return}if(y===v){r[A?"setStartBefore":"setEndAfter"](s);return}if(u.position<0){x=u.inside?s.firstChild:s.nextSibling;if(!x){r[A?"setStartAfter":"setEndAfter"](s);return}if(!y){if(x.nodeType==3){r[A?"setStart":"setEnd"](x,0)}else{r[A?"setStartBefore":"setEndBefore"](x)}return}while(x){t=x.nodeValue;z+=t.length;if(z>=y){s=x;z-=y;z=t.length-z;break}x=x.nextSibling}}else{x=s.previousSibling;if(!x){return r[A?"setStartBefore":"setEndBefore"](s)}if(!y){if(s.nodeType==3){r[A?"setStart":"setEnd"](x,s.nodeValue.length)}else{r[A?"setStartAfter":"setEndAfter"](x)}return}while(x){z+=x.nodeValue.length;if(z>=y){s=x;z-=y;break}x=x.previousSibling}}r[A?"setStart":"setEnd"](s,z)}try{o(true);if(!k){o()}}catch(n){if(n.number==-2147024809){m=b.getBookmark(2);p=i.duplicate();p.collapse(true);l=p.parentElement();if(!k){p=i.duplicate();p.collapse(false);q=p.parentElement();q.innerHTML=q.innerHTML}l.innerHTML=l.innerHTML;b.moveToBookmark(m);i=d.getRng();o(true);if(!k){o()}}else{throw n}}return r}this.getBookmark=function(m){var j=d.getRng(),o,i,l={};function n(u){var t,p,s,r,q=[];t=u.parentNode;p=h.getRoot().parentNode;while(t!=p&&t.nodeType!==9){s=t.children;r=s.length;while(r--){if(u===s[r]){q.push(r);break}}u=t;t=t.parentNode}return q}function k(q){var p;p=e(j,q);if(p){return{position:p.position,offset:p.offset,indexes:n(p.node),inside:p.inside}}}if(m===2){if(!j.item){l.start=k(true);if(!d.isCollapsed()){l.end=k()}}else{l.start={ctrl:true,indexes:n(j.item(0))}}}return l};this.moveToBookmark=function(k){var j,i=h.doc.body;function m(o){var r,q,n,p;r=h.getRoot();for(q=o.length-1;q>=0;q--){p=r.children;n=o[q];if(n<=p.length-1){r=p[n]}}return r}function l(r){var n=k[r?"start":"end"],q,p,o;if(n){q=n.position>0;p=i.createTextRange();p.moveToElementText(m(n.indexes));offset=n.offset;if(offset!==o){p.collapse(n.inside||q);p.moveStart("character",q?-offset:offset)}else{p.collapse(r)}j.setEndPoint(r?"StartToStart":"EndToStart",p);if(r){j.collapse(true)}}}if(k.start){if(k.start.ctrl){j=i.createControlRange();j.addElement(m(k.start.indexes));j.select()}else{j=i.createTextRange();l(true);l();j.select()}}};this.addRange=function(i){var n,l,k,p,v,q,t,s=d.dom.doc,m=s.body,r,u;function j(C){var y,B,x,A,z;x=h.create("a");y=C?k:v;B=C?p:q;A=n.duplicate();if(y==s||y==s.documentElement){y=m;B=0}if(y.nodeType==3){y.parentNode.insertBefore(x,y);A.moveToElementText(x);A.moveStart("character",B);h.remove(x);n.setEndPoint(C?"StartToStart":"EndToEnd",A)}else{z=y.childNodes;if(z.length){if(B>=z.length){h.insertAfter(x,z[z.length-1])}else{y.insertBefore(x,z[B])}A.moveToElementText(x)}else{if(y.canHaveHTML){y.innerHTML="<span>\uFEFF</span>";x=y.firstChild;A.moveToElementText(x);A.collapse(f)}}n.setEndPoint(C?"StartToStart":"EndToEnd",A);h.remove(x)}}k=i.startContainer;p=i.startOffset;v=i.endContainer;q=i.endOffset;n=m.createTextRange();if(k==v&&k.nodeType==1){if(p==q&&!k.hasChildNodes()){if(k.canHaveHTML){t=k.previousSibling;if(t&&!t.hasChildNodes()&&h.isBlock(t)){t.innerHTML="\uFEFF"}else{t=null}k.innerHTML="<span>\uFEFF</span><span>\uFEFF</span>";n.moveToElementText(k.lastChild);n.select();h.doc.selection.clear();k.innerHTML="";if(t){t.innerHTML=""}return}else{p=h.nodeIndex(k);k=k.parentNode}}if(p==q-1){try{u=k.childNodes[p];l=m.createControlRange();l.addElement(u);l.select();r=d.getRng();if(r.item&&u===r.item(0)){return}}catch(o){}}}j(true);j();n.select()};this.getRangeAt=g}tinymce.dom.TridentSelection=a})();(function(){var n=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,i="sizcache",o=0,r=Object.prototype.toString,h=false,g=true,q=/\\/g,u=/\r\n/g,x=/\W/;[0,0].sort(function(){g=false;return 0});var d=function(C,e,F,G){F=F||[];e=e||document;var I=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!C||typeof C!=="string"){return F}var z,K,N,y,J,M,L,E,B=true,A=d.isXML(e),D=[],H=C;do{n.exec("");z=n.exec(H);if(z){H=z[3];D.push(z[1]);if(z[2]){y=z[3];break}}}while(z);if(D.length>1&&j.exec(C)){if(D.length===2&&k.relative[D[0]]){K=s(D[0]+D[1],e,G)}else{K=k.relative[D[0]]?[e]:d(D.shift(),e);while(D.length){C=D.shift();if(k.relative[C]){C+=D.shift()}K=s(C,K,G)}}}else{if(!G&&D.length>1&&e.nodeType===9&&!A&&k.match.ID.test(D[0])&&!k.match.ID.test(D[D.length-1])){J=d.find(D.shift(),e,A);e=J.expr?d.filter(J.expr,J.set)[0]:J.set[0]}if(e){J=G?{expr:D.pop(),set:l(G)}:d.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&e.parentNode?e.parentNode:e,A);K=J.expr?d.filter(J.expr,J.set):J.set;if(D.length>0){N=l(K)}else{B=false}while(D.length){M=D.pop();L=M;if(!k.relative[M]){M=""}else{L=D.pop()}if(L==null){L=e}k.relative[M](N,L,A)}}else{N=D=[]}}if(!N){N=K}if(!N){d.error(M||C)}if(r.call(N)==="[object Array]"){if(!B){F.push.apply(F,N)}else{if(e&&e.nodeType===1){for(E=0;N[E]!=null;E++){if(N[E]&&(N[E]===true||N[E].nodeType===1&&d.contains(e,N[E]))){F.push(K[E])}}}else{for(E=0;N[E]!=null;E++){if(N[E]&&N[E].nodeType===1){F.push(K[E])}}}}}else{l(N,F)}if(y){d(y,I,F,G);d.uniqueSort(F)}return F};d.uniqueSort=function(y){if(p){h=g;y.sort(p);if(h){for(var e=1;e<y.length;e++){if(y[e]===y[e-1]){y.splice(e--,1)}}}}return y};d.matches=function(e,y){return d(e,null,null,y)};d.matchesSelector=function(e,y){return d(y,null,null,[e]).length>0};d.find=function(E,e,F){var D,z,B,A,C,y;if(!E){return[]}for(z=0,B=k.order.length;z<B;z++){C=k.order[z];if((A=k.leftMatch[C].exec(E))){y=A[1];A.splice(1,1);if(y.substr(y.length-1)!=="\\"){A[1]=(A[1]||"").replace(q,"");D=k.find[C](A,e,F);if(D!=null){E=E.replace(k.match[C],"");break}}}}if(!D){D=typeof e.getElementsByTagName!=="undefined"?e.getElementsByTagName("*"):[]}return{set:D,expr:E}};d.filter=function(I,H,L,B){var D,e,G,N,K,y,A,C,J,z=I,M=[],F=H,E=H&&H[0]&&d.isXML(H[0]);while(I&&H.length){for(G in k.filter){if((D=k.leftMatch[G].exec(I))!=null&&D[2]){y=k.filter[G];A=D[1];e=false;D.splice(1,1);if(A.substr(A.length-1)==="\\"){continue}if(F===M){M=[]}if(k.preFilter[G]){D=k.preFilter[G](D,F,L,M,B,E);if(!D){e=N=true}else{if(D===true){continue}}}if(D){for(C=0;(K=F[C])!=null;C++){if(K){N=y(K,D,C,F);J=B^N;if(L&&N!=null){if(J){e=true}else{F[C]=false}}else{if(J){M.push(K);e=true}}}}}if(N!==undefined){if(!L){F=M}I=I.replace(k.match[G],"");if(!e){return[]}break}}}if(I===z){if(e==null){d.error(I)}else{break}}z=I}return F};d.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};var b=d.getText=function(B){var z,A,e=B.nodeType,y="";if(e){if(e===1||e===9||e===11){if(typeof B.textContent==="string"){return B.textContent}else{if(typeof B.innerText==="string"){return B.innerText.replace(u,"")}else{for(B=B.firstChild;B;B=B.nextSibling){y+=b(B)}}}}else{if(e===3||e===4){return B.nodeValue}}}else{for(z=0;(A=B[z]);z++){if(A.nodeType!==8){y+=b(A)}}}return y};var k=d.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")},type:function(e){return e.getAttribute("type")}},relative:{"+":function(D,y){var A=typeof y==="string",C=A&&!x.test(y),E=A&&!C;if(C){y=y.toLowerCase()}for(var z=0,e=D.length,B;z<e;z++){if((B=D[z])){while((B=B.previousSibling)&&B.nodeType!==1){}D[z]=E||B&&B.nodeName.toLowerCase()===y?B||false:B===y}}if(E){d.filter(y,D,true)}},">":function(D,y){var C,B=typeof y==="string",z=0,e=D.length;if(B&&!x.test(y)){y=y.toLowerCase();for(;z<e;z++){C=D[z];if(C){var A=C.parentNode;D[z]=A.nodeName.toLowerCase()===y?A:false}}}else{for(;z<e;z++){C=D[z];if(C){D[z]=B?C.parentNode:C.parentNode===y}}if(B){d.filter(y,D,true)}}},"":function(A,y,C){var B,z=o++,e=t;if(typeof y==="string"&&!x.test(y)){y=y.toLowerCase();B=y;e=a}e("parentNode",y,z,A,B,C)},"~":function(A,y,C){var B,z=o++,e=t;if(typeof y==="string"&&!x.test(y)){y=y.toLowerCase();B=y;e=a}e("previousSibling",y,z,A,B,C)}},find:{ID:function(y,z,A){if(typeof z.getElementById!=="undefined"&&!A){var e=z.getElementById(y[1]);return e&&e.parentNode?[e]:[]}},NAME:function(z,C){if(typeof C.getElementsByName!=="undefined"){var y=[],B=C.getElementsByName(z[1]);for(var A=0,e=B.length;A<e;A++){if(B[A].getAttribute("name")===z[1]){y.push(B[A])}}return y.length===0?null:y}},TAG:function(e,y){if(typeof y.getElementsByTagName!=="undefined"){return y.getElementsByTagName(e[1])}}},preFilter:{CLASS:function(A,y,z,e,D,E){A=" "+A[1].replace(q,"")+" ";if(E){return A}for(var B=0,C;(C=y[B])!=null;B++){if(C){if(D^(C.className&&(" "+C.className+" ").replace(/[\t\n\r]/g," ").indexOf(A)>=0)){if(!z){e.push(C)}}else{if(z){y[B]=false}}}}return false},ID:function(e){return e[1].replace(q,"")},TAG:function(y,e){return y[1].replace(q,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){d.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var y=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(y[1]+(y[2]||1))-0;e[3]=y[3]-0}else{if(e[2]){d.error(e[0])}}e[0]=o++;return e},ATTR:function(B,y,z,e,C,D){var A=B[1]=B[1].replace(q,"");if(!D&&k.attrMap[A]){B[1]=k.attrMap[A]}B[4]=(B[4]||B[5]||"").replace(q,"");if(B[2]==="~="){B[4]=" "+B[4]+" "}return B},PSEUDO:function(B,y,z,e,C){if(B[1]==="not"){if((n.exec(B[3])||"").length>1||/^\w/.test(B[3])){B[3]=d(B[3],null,null,y)}else{var A=d.filter(B[3],y,z,true^C);if(!z){e.push.apply(e,A)}return false}}else{if(k.match.POS.test(B[0])||k.match.CHILD.test(B[0])){return true}}return B},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(z,y,e){return !!d(e[3],z).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(z){var e=z.getAttribute("type"),y=z.type;return z.nodeName.toLowerCase()==="input"&&"text"===y&&(e===y||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===y.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===y.type},button:function(y){var e=y.nodeName.toLowerCase();return e==="input"&&"button"===y.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(y,e){return e===0},last:function(z,y,e,A){return y===A.length-1},even:function(y,e){return e%2===0},odd:function(y,e){return e%2===1},lt:function(z,y,e){return y<e[3]-0},gt:function(z,y,e){return y>e[3]-0},nth:function(z,y,e){return e[3]-0===y},eq:function(z,y,e){return e[3]-0===y}},filter:{PSEUDO:function(z,E,D,F){var e=E[1],y=k.filters[e];if(y){return y(z,D,E,F)}else{if(e==="contains"){return(z.textContent||z.innerText||b([z])||"").indexOf(E[3])>=0}else{if(e==="not"){var A=E[3];for(var C=0,B=A.length;C<B;C++){if(A[C]===z){return false}}return true}else{d.error(e)}}}},CHILD:function(z,B){var A,H,D,G,e,C,F,E=B[1],y=z;switch(E){case"only":case"first":while((y=y.previousSibling)){if(y.nodeType===1){return false}}if(E==="first"){return true}y=z;case"last":while((y=y.nextSibling)){if(y.nodeType===1){return false}}return true;case"nth":A=B[2];H=B[3];if(A===1&&H===0){return true}D=B[0];G=z.parentNode;if(G&&(G[i]!==D||!z.nodeIndex)){C=0;for(y=G.firstChild;y;y=y.nextSibling){if(y.nodeType===1){y.nodeIndex=++C}}G[i]=D}F=z.nodeIndex-H;if(A===0){return F===0}else{return(F%A===0&&F/A>=0)}}},ID:function(y,e){return y.nodeType===1&&y.getAttribute("id")===e},TAG:function(y,e){return(e==="*"&&y.nodeType===1)||!!y.nodeName&&y.nodeName.toLowerCase()===e},CLASS:function(y,e){return(" "+(y.className||y.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(C,A){var z=A[1],e=d.attr?d.attr(C,z):k.attrHandle[z]?k.attrHandle[z](C):C[z]!=null?C[z]:C.getAttribute(z),D=e+"",B=A[2],y=A[4];return e==null?B==="!=":!B&&d.attr?e!=null:B==="="?D===y:B==="*="?D.indexOf(y)>=0:B==="~="?(" "+D+" ").indexOf(y)>=0:!y?D&&e!==false:B==="!="?D!==y:B==="^="?D.indexOf(y)===0:B==="$="?D.substr(D.length-y.length)===y:B==="|="?D===y||D.substr(0,y.length+1)===y+"-":false},POS:function(B,y,z,C){var e=y[2],A=k.setFilters[e];if(A){return A(B,z,y,C)}}}};var j=k.match.POS,c=function(y,e){return"\\"+(e-0+1)};for(var f in k.match){k.match[f]=new RegExp(k.match[f].source+(/(?![^\[]*\])(?![^\(]*\))/.source));k.leftMatch[f]=new RegExp(/(^(?:.|\r|\n)*?)/.source+k.match[f].source.replace(/\\(\d+)/g,c))}k.match.globalPOS=j;var l=function(y,e){y=Array.prototype.slice.call(y,0);if(e){e.push.apply(e,y);return e}return y};try{Array.prototype.slice.call(document.documentElement.childNodes,0)[0].nodeType}catch(v){l=function(B,A){var z=0,y=A||[];if(r.call(B)==="[object Array]"){Array.prototype.push.apply(y,B)}else{if(typeof B.length==="number"){for(var e=B.length;z<e;z++){y.push(B[z])}}else{for(;B[z];z++){y.push(B[z])}}}return y}}var p,m;if(document.documentElement.compareDocumentPosition){p=function(y,e){if(y===e){h=true;return 0}if(!y.compareDocumentPosition||!e.compareDocumentPosition){return y.compareDocumentPosition?-1:1}return y.compareDocumentPosition(e)&4?-1:1}}else{p=function(F,E){if(F===E){h=true;return 0}else{if(F.sourceIndex&&E.sourceIndex){return F.sourceIndex-E.sourceIndex}}var C,y,z=[],e=[],B=F.parentNode,D=E.parentNode,G=B;if(B===D){return m(F,E)}else{if(!B){return -1}else{if(!D){return 1}}}while(G){z.unshift(G);G=G.parentNode}G=D;while(G){e.unshift(G);G=G.parentNode}C=z.length;y=e.length;for(var A=0;A<C&&A<y;A++){if(z[A]!==e[A]){return m(z[A],e[A])}}return A===C?m(F,e[A],-1):m(z[A],E,1)};m=function(y,e,z){if(y===e){return z}var A=y.nextSibling;while(A){if(A===e){return -1}A=A.nextSibling}return 1}}(function(){var y=document.createElement("div"),z="script"+(new Date()).getTime(),e=document.documentElement;y.innerHTML="<a name='"+z+"'/>";e.insertBefore(y,e.firstChild);if(document.getElementById(z)){k.find.ID=function(B,C,D){if(typeof C.getElementById!=="undefined"&&!D){var A=C.getElementById(B[1]);return A?A.id===B[1]||typeof A.getAttributeNode!=="undefined"&&A.getAttributeNode("id").nodeValue===B[1]?[A]:undefined:[]}};k.filter.ID=function(C,A){var B=typeof C.getAttributeNode!=="undefined"&&C.getAttributeNode("id");return C.nodeType===1&&B&&B.nodeValue===A}}e.removeChild(y);e=y=null})();(function(){var e=document.createElement("div");e.appendChild(document.createComment(""));if(e.getElementsByTagName("*").length>0){k.find.TAG=function(y,C){var B=C.getElementsByTagName(y[1]);if(y[1]==="*"){var A=[];for(var z=0;B[z];z++){if(B[z].nodeType===1){A.push(B[z])}}B=A}return B}}e.innerHTML="<a href='#'></a>";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){k.attrHandle.href=function(y){return y.getAttribute("href",2)}}e=null})();if(document.querySelectorAll){(function(){var e=d,A=document.createElement("div"),z="__sizzle__";A.innerHTML="<p class='TEST'></p>";if(A.querySelectorAll&&A.querySelectorAll(".TEST").length===0){return}d=function(L,C,G,K){C=C||document;if(!K&&!d.isXML(C)){var J=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(L);if(J&&(C.nodeType===1||C.nodeType===9)){if(J[1]){return l(C.getElementsByTagName(L),G)}else{if(J[2]&&k.find.CLASS&&C.getElementsByClassName){return l(C.getElementsByClassName(J[2]),G)}}}if(C.nodeType===9){if(L==="body"&&C.body){return l([C.body],G)}else{if(J&&J[3]){var F=C.getElementById(J[3]);if(F&&F.parentNode){if(F.id===J[3]){return l([F],G)}}else{return l([],G)}}}try{return l(C.querySelectorAll(L),G)}catch(H){}}else{if(C.nodeType===1&&C.nodeName.toLowerCase()!=="object"){var D=C,E=C.getAttribute("id"),B=E||z,N=C.parentNode,M=/^\s*[+~]/.test(L);if(!E){C.setAttribute("id",B)}else{B=B.replace(/'/g,"\\$&")}if(M&&N){C=C.parentNode}try{if(!M||N){return l(C.querySelectorAll("[id='"+B+"'] "+L),G)}}catch(I){}finally{if(!E){D.removeAttribute("id")}}}}}return e(L,C,G,K)};for(var y in e){d[y]=e[y]}A=null})()}(function(){var e=document.documentElement,z=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(z){var B=!z.call(document.createElement("div"),"div"),y=false;try{z.call(document.documentElement,"[test!='']:sizzle")}catch(A){y=true}d.matchesSelector=function(D,F){F=F.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!d.isXML(D)){try{if(y||!k.match.PSEUDO.test(F)&&!/!=/.test(F)){var C=z.call(D,F);if(C||!B||D.document&&D.document.nodeType!==11){return C}}}catch(E){}}return d(F,null,null,[D]).length>0}}})();(function(){var e=document.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}k.order.splice(1,0,"CLASS");k.find.CLASS=function(y,z,A){if(typeof z.getElementsByClassName!=="undefined"&&!A){return z.getElementsByClassName(y[1])}};e=null})();function a(y,D,C,G,E,F){for(var A=0,z=G.length;A<z;A++){var e=G[A];if(e){var B=false;e=e[y];while(e){if(e[i]===C){B=G[e.sizset];break}if(e.nodeType===1&&!F){e[i]=C;e.sizset=A}if(e.nodeName.toLowerCase()===D){B=e;break}e=e[y]}G[A]=B}}}function t(y,D,C,G,E,F){for(var A=0,z=G.length;A<z;A++){var e=G[A];if(e){var B=false;e=e[y];while(e){if(e[i]===C){B=G[e.sizset];break}if(e.nodeType===1){if(!F){e[i]=C;e.sizset=A}if(typeof D!=="string"){if(e===D){B=true;break}}else{if(d.filter(D,[e]).length>0){B=e;break}}}e=e[y]}G[A]=B}}}if(document.documentElement.contains){d.contains=function(y,e){return y!==e&&(y.contains?y.contains(e):true)}}else{if(document.documentElement.compareDocumentPosition){d.contains=function(y,e){return !!(y.compareDocumentPosition(e)&16)}}else{d.contains=function(){return false}}}d.isXML=function(e){var y=(e?e.ownerDocument||e:0).documentElement;return y?y.nodeName!=="HTML":false};var s=function(z,e,D){var C,E=[],B="",F=e.nodeType?[e]:e;while((C=k.match.PSEUDO.exec(z))){B+=C[0];z=z.replace(k.match.PSEUDO,"")}z=k.relative[z]?z+"*":z;for(var A=0,y=F.length;A<y;A++){d(z,F[A],E,D)}return d.filter(B,E)};window.tinymce.dom.Sizzle=d})();(function(a){a.dom.Element=function(f,d){var b=this,e,c;b.settings=d=d||{};b.id=f;b.dom=e=d.dom||a.DOM;if(!a.isIE){c=e.get(b.id)}a.each(("getPos,getRect,getParent,add,setStyle,getStyle,setStyles,setAttrib,setAttribs,getAttrib,addClass,removeClass,hasClass,getOuterHTML,setOuterHTML,remove,show,hide,isHidden,setHTML,get").split(/,/),function(g){b[g]=function(){var h=[f],j;for(j=0;j<arguments.length;j++){h.push(arguments[j])}h=e[g].apply(e,h);b.update(g);return h}});a.extend(b,{on:function(i,h,g){return a.dom.Event.add(b.id,i,h,g)},getXY:function(){return{x:parseInt(b.getStyle("left")),y:parseInt(b.getStyle("top"))}},getSize:function(){var g=e.get(b.id);return{w:parseInt(b.getStyle("width")||g.clientWidth),h:parseInt(b.getStyle("height")||g.clientHeight)}},moveTo:function(g,h){b.setStyles({left:g,top:h})},moveBy:function(g,i){var h=b.getXY();b.moveTo(h.x+g,h.y+i)},resizeTo:function(g,i){b.setStyles({width:g,height:i})},resizeBy:function(g,j){var i=b.getSize();b.resizeTo(i.w+g,i.h+j)},update:function(h){var g;if(a.isIE6&&d.blocker){h=h||"";if(h.indexOf("get")===0||h.indexOf("has")===0||h.indexOf("is")===0){return}if(h=="remove"){e.remove(b.blocker);return}if(!b.blocker){b.blocker=e.uniqueId();g=e.add(d.container||e.getRoot(),"iframe",{id:b.blocker,style:"position:absolute;",frameBorder:0,src:'javascript:""'});e.setStyle(g,"opacity",0)}else{g=e.get(b.blocker)}e.setStyles(g,{left:b.getStyle("left",1),top:b.getStyle("top",1),width:b.getStyle("width",1),height:b.getStyle("height",1),display:b.getStyle("display",1),zIndex:parseInt(b.getStyle("zIndex",1)||0)-1})}}})}})(tinymce);(function(d){function f(g){return g.replace(/[\n\r]+/g,"")}var c=d.is,b=d.isIE,e=d.each,a=d.dom.TreeWalker;d.create("tinymce.dom.Selection",{Selection:function(k,j,i,h){var g=this;g.dom=k;g.win=j;g.serializer=i;g.editor=h;e(["onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent"],function(l){g[l]=new d.util.Dispatcher(g)});if(!g.win.getSelection){g.tridentSel=new d.dom.TridentSelection(g)}if(d.isIE&&k.boxModel){this._fixIESelection()}d.addUnload(g.destroy,g)},setCursorLocation:function(i,j){var g=this;var h=g.dom.createRng();h.setStart(i,j);h.setEnd(i,j);g.setRng(h);g.collapse(false)},getContent:function(h){var g=this,i=g.getRng(),m=g.dom.create("body"),k=g.getSel(),j,l,o;h=h||{};j=l="";h.get=true;h.format=h.format||"html";h.forced_root_block="";g.onBeforeGetContent.dispatch(g,h);if(h.format=="text"){return g.isCollapsed()?"":(i.text||(k.toString?k.toString():""))}if(i.cloneContents){o=i.cloneContents();if(o){m.appendChild(o)}}else{if(c(i.item)||c(i.htmlText)){m.innerHTML="<br>"+(i.item?i.item(0).outerHTML:i.htmlText);m.removeChild(m.firstChild)}else{m.innerHTML=i.toString()}}if(/^\s/.test(m.innerHTML)){j=" "}if(/\s+$/.test(m.innerHTML)){l=" "}h.getInner=true;h.content=g.isCollapsed()?"":j+g.serializer.serialize(m,h)+l;g.onGetContent.dispatch(g,h);return h.content},setContent:function(h,j){var o=this,g=o.getRng(),k,l=o.win.document,n,m;j=j||{format:"html"};j.set=true;h=j.content=h;if(!j.no_events){o.onBeforeSetContent.dispatch(o,j)}h=j.content;if(g.insertNode){h+='<span id="__caret">_</span>';if(g.startContainer==l&&g.endContainer==l){l.body.innerHTML=h}else{g.deleteContents();if(l.body.childNodes.length===0){l.body.innerHTML=h}else{if(g.createContextualFragment){g.insertNode(g.createContextualFragment(h))}else{n=l.createDocumentFragment();m=l.createElement("div");n.appendChild(m);m.outerHTML=h;g.insertNode(n)}}}k=o.dom.get("__caret");g=l.createRange();g.setStartBefore(k);g.setEndBefore(k);o.setRng(g);o.dom.remove("__caret");try{o.setRng(g)}catch(i){}}else{if(g.item){l.execCommand("Delete",false,null);g=o.getRng()}if(/^\s+/.test(h)){g.pasteHTML('<span id="__mce_tmp">_</span>'+h);o.dom.remove("__mce_tmp")}else{g.pasteHTML(h)}}if(!j.no_events){o.onSetContent.dispatch(o,j)}},getStart:function(){var i=this,h=i.getRng(),j,g,l,k;if(h.duplicate||h.item){if(h.item){return h.item(0)}l=h.duplicate();l.collapse(1);j=l.parentElement();if(j.ownerDocument!==i.dom.doc){j=i.dom.getRoot()}g=k=h.parentElement();while(k=k.parentNode){if(k==j){j=g;break}}return j}else{j=h.startContainer;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[Math.min(j.childNodes.length-1,h.startOffset)]}if(j&&j.nodeType==3){return j.parentNode}return j}},getEnd:function(){var h=this,g=h.getRng(),j,i;if(g.duplicate||g.item){if(g.item){return g.item(0)}g=g.duplicate();g.collapse(0);j=g.parentElement();if(j.ownerDocument!==h.dom.doc){j=h.dom.getRoot()}if(j&&j.nodeName=="BODY"){return j.lastChild||j}return j}else{j=g.endContainer;i=g.endOffset;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[i>0?i-1:i]}if(j&&j.nodeType==3){return j.parentNode}return j}},getBookmark:function(s,v){var y=this,n=y.dom,h,k,j,o,i,p,q,m="\uFEFF",x;function g(z,A){var t=0;e(n.select(z),function(C,B){if(C==A){t=B}});return t}function u(t){function z(E){var A,D,C,B=E?"start":"end";A=t[B+"Container"];D=t[B+"Offset"];if(A.nodeType==1&&A.nodeName=="TR"){C=A.childNodes;A=C[Math.min(E?D:D-1,C.length-1)];if(A){D=E?0:A.childNodes.length;t["set"+(E?"Start":"End")](A,D)}}}z(true);z();return t}function l(){var z=y.getRng(true),t=n.getRoot(),A={};function B(E,J){var D=E[J?"startContainer":"endContainer"],I=E[J?"startOffset":"endOffset"],C=[],F,H,G=0;if(D.nodeType==3){if(v){for(F=D.previousSibling;F&&F.nodeType==3;F=F.previousSibling){I+=F.nodeValue.length}}C.push(I)}else{H=D.childNodes;if(I>=H.length&&H.length){G=1;I=Math.max(0,H.length-1)}C.push(y.dom.nodeIndex(H[I],v)+G)}for(;D&&D!=t;D=D.parentNode){C.push(y.dom.nodeIndex(D,v))}return C}A.start=B(z,true);if(!y.isCollapsed()){A.end=B(z)}return A}if(s==2){if(y.tridentSel){return y.tridentSel.getBookmark(s)}return l()}if(s){return{rng:y.getRng()}}h=y.getRng();j=n.uniqueId();o=tinyMCE.activeEditor.selection.isCollapsed();x="overflow:hidden;line-height:0px";if(h.duplicate||h.item){if(!h.item){k=h.duplicate();try{h.collapse();h.pasteHTML('<span data-mce-type="bookmark" id="'+j+'_start" style="'+x+'">'+m+"</span>");if(!o){k.collapse(false);h.moveToElementText(k.parentElement());if(h.compareEndPoints("StartToEnd",k)===0){k.move("character",-1)}k.pasteHTML('<span data-mce-type="bookmark" id="'+j+'_end" style="'+x+'">'+m+"</span>")}}catch(r){return null}}else{p=h.item(0);i=p.nodeName;return{name:i,index:g(i,p)}}}else{p=y.getNode();i=p.nodeName;if(i=="IMG"){return{name:i,index:g(i,p)}}k=u(h.cloneRange());if(!o){k.collapse(false);k.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_end",style:x},m))}h=u(h);h.collapse(true);h.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_start",style:x},m))}y.moveToBookmark({id:j,keep:1});return{id:j}},moveToBookmark:function(o){var s=this,m=s.dom,j,i,g,r,k,u,p,q;function h(A){var t=o[A?"start":"end"],x,y,z,v;if(t){z=t[0];for(y=r,x=t.length-1;x>=1;x--){v=y.childNodes;if(t[x]>v.length-1){return}y=v[t[x]]}if(y.nodeType===3){z=Math.min(t[0],y.nodeValue.length)}if(y.nodeType===1){z=Math.min(t[0],y.childNodes.length)}if(A){g.setStart(y,z)}else{g.setEnd(y,z)}}return true}function l(B){var v=m.get(o.id+"_"+B),A,t,y,z,x=o.keep;if(v){A=v.parentNode;if(B=="start"){if(!x){t=m.nodeIndex(v)}else{A=v.firstChild;t=1}k=u=A;p=q=t}else{if(!x){t=m.nodeIndex(v)}else{A=v.firstChild;t=1}u=A;q=t}if(!x){z=v.previousSibling;y=v.nextSibling;e(d.grep(v.childNodes),function(C){if(C.nodeType==3){C.nodeValue=C.nodeValue.replace(/\uFEFF/g,"")}});while(v=m.get(o.id+"_"+B)){m.remove(v,1)}if(z&&y&&z.nodeType==y.nodeType&&z.nodeType==3&&!d.isOpera){t=z.nodeValue.length;z.appendData(y.nodeValue);m.remove(y);if(B=="start"){k=u=z;p=q=t}else{u=z;q=t}}}}}function n(t){if(m.isBlock(t)&&!t.innerHTML&&!b){t.innerHTML='<br data-mce-bogus="1" />'}return t}if(o){if(o.start){g=m.createRng();r=m.getRoot();if(s.tridentSel){return s.tridentSel.moveToBookmark(o)}if(h(true)&&h()){s.setRng(g)}}else{if(o.id){l("start");l("end");if(k){g=m.createRng();g.setStart(n(k),p);g.setEnd(n(u),q);s.setRng(g)}}else{if(o.name){s.select(m.select(o.name)[o.index])}else{if(o.rng){s.setRng(o.rng)}}}}}},select:function(l,k){var j=this,m=j.dom,h=m.createRng(),g;function i(n,p){var o=new a(n,n);do{if(n.nodeType==3&&d.trim(n.nodeValue).length!==0){if(p){h.setStart(n,0)}else{h.setEnd(n,n.nodeValue.length)}return}if(n.nodeName=="BR"){if(p){h.setStartBefore(n)}else{h.setEndBefore(n)}return}}while(n=(p?o.next():o.prev()))}if(l){g=m.nodeIndex(l);h.setStart(l.parentNode,g);h.setEnd(l.parentNode,g+1);if(k){i(l,1);i(l)}j.setRng(h)}return l},isCollapsed:function(){var g=this,i=g.getRng(),h=g.getSel();if(!i||i.item){return false}if(i.compareEndPoints){return i.compareEndPoints("StartToEnd",i)===0}return !h||i.collapsed},collapse:function(g){var i=this,h=i.getRng(),j;if(h.item){j=h.item(0);h=i.win.document.body.createTextRange();h.moveToElementText(j)}h.collapse(!!g);i.setRng(h)},getSel:function(){var h=this,g=this.win;return g.getSelection?g.getSelection():g.document.selection},getRng:function(m){var h=this,j,g,l,k=h.win.document;if(m&&h.tridentSel){return h.tridentSel.getRangeAt(0)}try{if(j=h.getSel()){g=j.rangeCount>0?j.getRangeAt(0):(j.createRange?j.createRange():k.createRange())}}catch(i){}if(d.isIE&&g&&g.setStart&&k.selection.createRange().item){l=k.selection.createRange().item(0);g=k.createRange();g.setStartBefore(l);g.setEndAfter(l)}if(!g){g=k.createRange?k.createRange():k.body.createTextRange()}if(g.setStart&&g.startContainer.nodeType===9&&g.collapsed){l=h.dom.getRoot();g.setStart(l,0);g.setEnd(l,0)}if(h.selectedRange&&h.explicitRange){if(g.compareBoundaryPoints(g.START_TO_START,h.selectedRange)===0&&g.compareBoundaryPoints(g.END_TO_END,h.selectedRange)===0){g=h.explicitRange}else{h.selectedRange=null;h.explicitRange=null}}return g},setRng:function(k,g){var j,i=this;if(!i.tridentSel){j=i.getSel();if(j){i.explicitRange=k;try{j.removeAllRanges()}catch(h){}j.addRange(k);if(g===false&&j.extend){j.collapse(k.endContainer,k.endOffset);j.extend(k.startContainer,k.startOffset)}i.selectedRange=j.rangeCount>0?j.getRangeAt(0):null}}else{if(k.cloneRange){try{i.tridentSel.addRange(k);return}catch(h){}}try{k.select()}catch(h){}}},setNode:function(h){var g=this;g.setContent(g.dom.getOuterHTML(h));return h},getNode:function(){var i=this,h=i.getRng(),j=i.getSel(),m,l=h.startContainer,g=h.endContainer;function k(q,o){var p=q;while(q&&q.nodeType===3&&q.length===0){q=o?q.nextSibling:q.previousSibling}return q||p}if(!h){return i.dom.getRoot()}if(h.setStart){m=h.commonAncestorContainer;if(!h.collapsed){if(h.startContainer==h.endContainer){if(h.endOffset-h.startOffset<2){if(h.startContainer.hasChildNodes()){m=h.startContainer.childNodes[h.startOffset]}}}if(l.nodeType===3&&g.nodeType===3){if(l.length===h.startOffset){l=k(l.nextSibling,true)}else{l=l.parentNode}if(h.endOffset===0){g=k(g.previousSibling,false)}else{g=g.parentNode}if(l&&l===g){return l}}}if(m&&m.nodeType==3){return m.parentNode}return m}return h.item?h.item(0):h.parentElement()},getSelectedBlocks:function(p,h){var o=this,k=o.dom,m,l,i,j=[];m=k.getParent(p||o.getStart(),k.isBlock);l=k.getParent(h||o.getEnd(),k.isBlock);if(m){j.push(m)}if(m&&l&&m!=l){i=m;var g=new a(m,k.getRoot());while((i=g.next())&&i!=l){if(k.isBlock(i)){j.push(i)}}}if(l&&m!=l){j.push(l)}return j},isForward:function(){var i=this.dom,g=this.getSel(),j,h;if(!g||g.anchorNode==null||g.focusNode==null){return true}j=i.createRng();j.setStart(g.anchorNode,g.anchorOffset);j.collapse(true);h=i.createRng();h.setStart(g.focusNode,g.focusOffset);h.collapse(true);return j.compareBoundaryPoints(j.START_TO_START,h)<=0},normalize:function(){var h=this,g,m,l,j,i;function k(p){var o,r,n,s=h.dom,u=s.getRoot(),q,t,v;function y(z,A){var B=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(z=B[A?"prev":"next"]()){if(z.nodeName==="BR"){return true}}}function x(B,z){var C,A;z=z||o;C=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(q=C[B?"prev":"next"]()){if(q.nodeType===3&&q.nodeValue.length>0){o=q;r=B?q.nodeValue.length:0;m=true;return}if(s.isBlock(q)||t[q.nodeName.toLowerCase()]){return}A=q}if(l&&A){o=A;m=true;r=0}}o=g[(p?"start":"end")+"Container"];r=g[(p?"start":"end")+"Offset"];t=s.schema.getNonEmptyElements();if(o.nodeType===9){o=s.getRoot();r=0}if(o===u){if(p){q=o.childNodes[r>0?r-1:0];if(q){v=q.nodeName.toLowerCase();if(t[q.nodeName]||q.nodeName=="TABLE"){return}}}if(o.hasChildNodes()){o=o.childNodes[Math.min(!p&&r>0?r-1:r,o.childNodes.length-1)];r=0;if(o.hasChildNodes()&&!/TABLE/.test(o.nodeName)){q=o;n=new a(o,u);do{if(q.nodeType===3&&q.nodeValue.length>0){r=p?0:q.nodeValue.length;o=q;m=true;break}if(t[q.nodeName.toLowerCase()]){r=s.nodeIndex(q);o=q.parentNode;if(q.nodeName=="IMG"&&!p){r++}m=true;break}}while(q=(p?n.next():n.prev()))}}}if(l){if(o.nodeType===3&&r===0){x(true)}if(o.nodeType===1){q=o.childNodes[r];if(q&&q.nodeName==="BR"&&!y(q)&&!y(q,true)){x(true,o.childNodes[r])}}}if(p&&!l&&o.nodeType===3&&r===o.nodeValue.length){x(false)}if(m){g["set"+(p?"Start":"End")](o,r)}}if(d.isIE){return}g=h.getRng();l=g.collapsed;k(true);if(!l){k()}if(m){if(l){g.collapse(true)}h.setRng(g,h.isForward())}},selectorChanged:function(g,j){var h=this,i;if(!h.selectorChangedData){h.selectorChangedData={};i={};h.editor.onNodeChange.addToTop(function(l,k,o){var p=h.dom,m=p.getParents(o,null,p.getRoot()),n={};e(h.selectorChangedData,function(r,q){e(m,function(s){if(p.is(s,q)){if(!i[q]){e(r,function(t){t(true,{node:s,selector:q,parents:m})});i[q]=r}n[q]=r;return false}})});e(i,function(r,q){if(!n[q]){delete i[q];e(r,function(s){s(false,{node:o,selector:q,parents:m})})}})})}if(!h.selectorChangedData[g]){h.selectorChangedData[g]=[]}h.selectorChangedData[g].push(j);return h},scrollIntoView:function(k){var j,h,g=this,i=g.dom;h=i.getViewPort(g.editor.getWin());j=i.getPos(k).y;if(j<h.y||j+25>h.y+h.h){g.editor.getWin().scrollTo(0,j<h.y?j:j-h.h+25)}},destroy:function(h){var g=this;g.win=null;if(!h){d.removeUnload(g.destroy)}},_fixIESelection:function(){var h=this.dom,n=h.doc,i=n.body,k,o,g;function j(p,s){var q=i.createTextRange();try{q.moveToPoint(p,s)}catch(r){q=null}return q}function m(q){var p;if(q.button){p=j(q.x,q.y);if(p){if(p.compareEndPoints("StartToStart",o)>0){p.setEndPoint("StartToStart",o)}else{p.setEndPoint("EndToEnd",o)}p.select()}}else{l()}}function l(){var p=n.selection.createRange();if(o&&!p.item&&p.compareEndPoints("StartToEnd",p)===0){o.select()}h.unbind(n,"mouseup",l);h.unbind(n,"mousemove",m);o=k=0}n.documentElement.unselectable=true;h.bind(n,["mousedown","contextmenu"],function(p){if(p.target.nodeName==="HTML"){if(k){l()}g=n.documentElement;if(g.scrollHeight>g.clientHeight){return}k=1;o=j(p.x,p.y);if(o){h.bind(n,"mouseup",l);h.bind(n,"mousemove",m);h.win.focus();o.select()}}})}})})(tinymce);(function(a){a.dom.Serializer=function(e,i,f){var h,b,d=a.isIE,g=a.each,c;if(!e.apply_source_formatting){e.indent=false}i=i||a.DOM;f=f||new a.html.Schema(e);e.entity_encoding=e.entity_encoding||"named";e.remove_trailing_brs="remove_trailing_brs" in e?e.remove_trailing_brs:true;h=new a.util.Dispatcher(self);b=new a.util.Dispatcher(self);c=new a.html.DomParser(e,f);c.addAttributeFilter("src,href,style",function(k,j){var o=k.length,l,q,n="data-mce-"+j,p=e.url_converter,r=e.url_converter_scope,m;while(o--){l=k[o];q=l.attributes.map[n];if(q!==m){l.attr(j,q.length>0?q:null);l.attr(n,null)}else{q=l.attributes.map[j];if(j==="style"){q=i.serializeStyle(i.parseStyle(q),l.name)}else{if(p){q=p.call(r,q,j,l.name)}}l.attr(j,q.length>0?q:null)}}});c.addAttributeFilter("class",function(j,k){var l=j.length,m,n;while(l--){m=j[l];n=m.attr("class").replace(/(?:^|\s)mce(Item\w+|Selected)(?!\S)/g,"");m.attr("class",n.length>0?n:null)}});c.addAttributeFilter("data-mce-type",function(j,l,k){var m=j.length,n;while(m--){n=j[m];if(n.attributes.map["data-mce-type"]==="bookmark"&&!k.cleanup){n.remove()}}});c.addAttributeFilter("data-mce-expando",function(j,l,k){var m=j.length;while(m--){j[m].attr(l,null)}});c.addNodeFilter("noscript",function(j){var k=j.length,l;while(k--){l=j[k].firstChild;if(l){l.value=a.html.Entities.decode(l.value)}}});c.addNodeFilter("script,style",function(k,l){var m=k.length,n,o;function j(p){return p.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}while(m--){n=k[m];o=n.firstChild?n.firstChild.value:"";if(l==="script"){n.attr("type",(n.attr("type")||"text/javascript").replace(/^mce\-/,""));if(o.length>0){n.firstChild.value="// <![CDATA[\n"+j(o)+"\n// ]]>"}}else{if(o.length>0){n.firstChild.value="<!--\n"+j(o)+"\n-->"}}}});c.addNodeFilter("#comment",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.value.indexOf("[CDATA[")===0){m.name="#cdata";m.type=4;m.value=m.value.replace(/^\[CDATA\[|\]\]$/g,"")}else{if(m.value.indexOf("mce:protected ")===0){m.name="#text";m.type=3;m.raw=true;m.value=unescape(m.value).substr(14)}}}});c.addNodeFilter("xml:namespace,input",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.type===7){m.remove()}else{if(m.type===1){if(k==="input"&&!("type" in m.attributes.map)){m.attr("type","text")}}}}});if(e.fix_list_elements){c.addNodeFilter("ul,ol",function(k,l){var m=k.length,n,j;while(m--){n=k[m];j=n.parent;if(j.name==="ul"||j.name==="ol"){if(n.prev&&n.prev.name==="li"){n.prev.append(n)}}}})}c.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style",function(j,k){var l=j.length;while(l--){j[l].attr(k,null)}});return{schema:f,addNodeFilter:c.addNodeFilter,addAttributeFilter:c.addAttributeFilter,onPreProcess:h,onPostProcess:b,serialize:function(o,m){var l,p,k,j,n;if(d&&i.select("script,style,select,map").length>0){n=o.innerHTML;o=o.cloneNode(false);i.setHTML(o,n)}else{o=o.cloneNode(true)}l=o.ownerDocument.implementation;if(l.createHTMLDocument){p=l.createHTMLDocument("");g(o.nodeName=="BODY"?o.childNodes:[o],function(q){p.body.appendChild(p.importNode(q,true))});if(o.nodeName!="BODY"){o=p.body.firstChild}else{o=p.body}k=i.doc;i.doc=p}m=m||{};m.format=m.format||"html";if(!m.no_events){m.node=o;h.dispatch(self,m)}j=new a.html.Serializer(e,f);m.content=j.serialize(c.parse(a.trim(m.getInner?o.innerHTML:i.getOuterHTML(o)),m));if(!m.cleanup){m.content=m.content.replace(/\uFEFF/g,"")}if(!m.no_events){b.dispatch(self,m)}if(k){i.doc=k}m.node=null;return m.content},addRules:function(j){f.addValidElements(j)},setRules:function(j){f.setValidElements(j)}}}})(tinymce);(function(a){a.dom.ScriptLoader=function(h){var c=0,k=1,i=2,l={},j=[],e={},d=[],g=0,f;function b(m,v){var x=this,q=a.DOM,s,o,r,n;function p(){q.remove(n);if(s){s.onreadystatechange=s.onload=s=null}v()}function u(){if(typeof(console)!=="undefined"&&console.log){console.log("Failed to load: "+m)}}n=q.uniqueId();if(a.isIE6){o=new a.util.URI(m);r=location;if(o.host==r.hostname&&o.port==r.port&&(o.protocol+":")==r.protocol&&o.protocol.toLowerCase()!="file"){a.util.XHR.send({url:a._addVer(o.getURI()),success:function(y){var t=q.create("script",{type:"text/javascript"});t.text=y;document.getElementsByTagName("head")[0].appendChild(t);q.remove(t);p()},error:u});return}}s=document.createElement("script");s.id=n;s.type="text/javascript";s.src=a._addVer(m);if(!a.isIE){s.onload=p}s.onerror=u;if(!a.isOpera){s.onreadystatechange=function(){var t=s.readyState;if(t=="complete"||t=="loaded"){p()}}}(document.getElementsByTagName("head")[0]||document.body).appendChild(s)}this.isDone=function(m){return l[m]==i};this.markDone=function(m){l[m]=i};this.add=this.load=function(m,q,n){var o,p=l[m];if(p==f){j.push(m);l[m]=c}if(q){if(!e[m]){e[m]=[]}e[m].push({func:q,scope:n||this})}};this.loadQueue=function(n,m){this.loadScripts(j,n,m)};this.loadScripts=function(m,q,p){var o;function n(r){a.each(e[r],function(s){s.func.call(s.scope)});e[r]=f}d.push({func:q,scope:p||this});o=function(){var r=a.grep(m);m.length=0;a.each(r,function(s){if(l[s]==i){n(s);return}if(l[s]!=k){l[s]=k;g++;b(s,function(){l[s]=i;g--;n(s);o()})}});if(!g){a.each(d,function(s){s.func.call(s.scope)});d.length=0}};o()}};a.ScriptLoader=new a.dom.ScriptLoader()})(tinymce);(function(a){a.dom.RangeUtils=function(c){var b="\uFEFF";this.walk=function(d,s){var i=d.startContainer,l=d.startOffset,t=d.endContainer,m=d.endOffset,j,g,o,h,r,q,e;e=c.select("td.mceSelected,th.mceSelected");if(e.length>0){a.each(e,function(u){s([u])});return}function f(u){var v;v=u[0];if(v.nodeType===3&&v===i&&l>=v.nodeValue.length){u.splice(0,1)}v=u[u.length-1];if(m===0&&u.length>0&&v===t&&v.nodeType===3){u.splice(u.length-1,1)}return u}function p(x,v,u){var y=[];for(;x&&x!=u;x=x[v]){y.push(x)}return y}function n(v,u){do{if(v.parentNode==u){return v}v=v.parentNode}while(v)}function k(x,v,y){var u=y?"nextSibling":"previousSibling";for(h=x,r=h.parentNode;h&&h!=v;h=r){r=h.parentNode;q=p(h==x?h:h[u],u);if(q.length){if(!y){q.reverse()}s(f(q))}}}if(i.nodeType==1&&i.hasChildNodes()){i=i.childNodes[l]}if(t.nodeType==1&&t.hasChildNodes()){t=t.childNodes[Math.min(m-1,t.childNodes.length-1)]}if(i==t){return s(f([i]))}j=c.findCommonAncestor(i,t);for(h=i;h;h=h.parentNode){if(h===t){return k(i,j,true)}if(h===j){break}}for(h=t;h;h=h.parentNode){if(h===i){return k(t,j)}if(h===j){break}}g=n(i,j)||i;o=n(t,j)||t;k(i,g,true);q=p(g==i?g:g.nextSibling,"nextSibling",o==t?o.nextSibling:o);if(q.length){s(f(q))}k(t,o)};this.split=function(e){var h=e.startContainer,d=e.startOffset,i=e.endContainer,g=e.endOffset;function f(j,k){return j.splitText(k)}if(h==i&&h.nodeType==3){if(d>0&&d<h.nodeValue.length){i=f(h,d);h=i.previousSibling;if(g>d){g=g-d;h=i=f(i,g).previousSibling;g=i.nodeValue.length;d=0}else{g=0}}}else{if(h.nodeType==3&&d>0&&d<h.nodeValue.length){h=f(h,d);d=0}if(i.nodeType==3&&g>0&&g<i.nodeValue.length){i=f(i,g).previousSibling;g=i.nodeValue.length}}return{startContainer:h,startOffset:d,endContainer:i,endOffset:g}}};a.dom.RangeUtils.compareRanges=function(c,b){if(c&&b){if(c.item||c.duplicate){if(c.item&&b.item&&c.item(0)===b.item(0)){return true}if(c.isEqual&&b.isEqual&&b.isEqual(c)){return true}}else{return c.startContainer==b.startContainer&&c.startOffset==b.startOffset}}return false}})(tinymce);(function(b){var a=b.dom.Event,c=b.each;b.create("tinymce.ui.KeyboardNavigation",{KeyboardNavigation:function(e,f){var q=this,n=e.root,m=e.items,o=e.enableUpDown,i=e.enableLeftRight||!e.enableUpDown,l=e.excludeFromTabOrder,k,h,p,d,g;f=f||b.DOM;k=function(r){g=r.target.id};h=function(r){f.setAttrib(r.target.id,"tabindex","-1")};d=function(r){var s=f.get(g);f.setAttrib(s,"tabindex","0");s.focus()};q.focus=function(){f.get(g).focus()};q.destroy=function(){c(m,function(s){var t=f.get(s.id);f.unbind(t,"focus",k);f.unbind(t,"blur",h)});var r=f.get(n);f.unbind(r,"focus",d);f.unbind(r,"keydown",p);m=f=n=q.focus=k=h=p=d=null;q.destroy=function(){}};q.moveFocus=function(v,s){var r=-1,u=q.controls,t;if(!g){return}c(m,function(y,x){if(y.id===g){r=x;return false}});r+=v;if(r<0){r=m.length-1}else{if(r>=m.length){r=0}}t=m[r];f.setAttrib(g,"tabindex","-1");f.setAttrib(t.id,"tabindex","0");f.get(t.id).focus();if(e.actOnFocus){e.onAction(t.id)}if(s){a.cancel(s)}};p=function(z){var v=37,u=39,y=38,A=40,r=27,t=14,s=13,x=32;switch(z.keyCode){case v:if(i){q.moveFocus(-1)}a.cancel(z);break;case u:if(i){q.moveFocus(1)}a.cancel(z);break;case y:if(o){q.moveFocus(-1)}a.cancel(z);break;case A:if(o){q.moveFocus(1)}a.cancel(z);break;case r:if(e.onCancel){e.onCancel();a.cancel(z)}break;case t:case s:case x:if(e.onAction){e.onAction(g);a.cancel(z)}break}};c(m,function(t,r){var s,u;if(!t.id){t.id=f.uniqueId("_mce_item_")}u=f.get(t.id);if(l){f.bind(u,"blur",h);s="-1"}else{s=(r===0?"0":"-1")}u.setAttribute("tabindex",s);f.bind(u,"focus",k)});if(m[0]){g=m[0].id}f.setAttrib(n,"tabindex","-1");var j=f.get(n);f.bind(j,"focus",d);f.bind(j,"keydown",p)}})})(tinymce);(function(c){var b=c.DOM,a=c.is;c.create("tinymce.ui.Control",{Control:function(f,e,d){this.id=f;this.settings=e=e||{};this.rendered=false;this.onRender=new c.util.Dispatcher(this);this.classPrefix="";this.scope=e.scope||this;this.disabled=0;this.active=0;this.editor=d},setAriaProperty:function(f,e){var d=b.get(this.id+"_aria")||b.get(this.id);if(d){b.setAttrib(d,"aria-"+f,!!e)}},focus:function(){b.get(this.id).focus()},setDisabled:function(d){if(d!=this.disabled){this.setAriaProperty("disabled",d);this.setState("Disabled",d);this.setState("Enabled",!d);this.disabled=d}},isDisabled:function(){return this.disabled},setActive:function(d){if(d!=this.active){this.setState("Active",d);this.active=d;this.setAriaProperty("pressed",d)}},isActive:function(){return this.active},setState:function(f,d){var e=b.get(this.id);f=this.classPrefix+f;if(d){b.addClass(e,f)}else{b.removeClass(e,f)}},isRendered:function(){return this.rendered},renderHTML:function(){},renderTo:function(d){b.setHTML(d,this.renderHTML())},postRender:function(){var e=this,d;if(a(e.disabled)){d=e.disabled;e.disabled=-1;e.setDisabled(d)}if(a(e.active)){d=e.active;e.active=-1;e.setActive(d)}},remove:function(){b.remove(this.id);this.destroy()},destroy:function(){c.dom.Event.clear(this.id)}})})(tinymce);tinymce.create("tinymce.ui.Container:tinymce.ui.Control",{Container:function(c,b,a){this.parent(c,b,a);this.controls=[];this.lookup={}},add:function(a){this.lookup[a.id]=a;this.controls.push(a);return a},get:function(a){return this.lookup[a]}});tinymce.create("tinymce.ui.Separator:tinymce.ui.Control",{Separator:function(b,a){this.parent(b,a);this.classPrefix="mceSeparator";this.setDisabled(true)},renderHTML:function(){return tinymce.DOM.createHTML("span",{"class":this.classPrefix,role:"separator","aria-orientation":"vertical",tabindex:"-1"})}});(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.MenuItem:tinymce.ui.Control",{MenuItem:function(g,f){this.parent(g,f);this.classPrefix="mceMenuItem"},setSelected:function(f){this.setState("Selected",f);this.setAriaProperty("checked",!!f);this.selected=f},isSelected:function(){return this.selected},postRender:function(){var f=this;f.parent();if(c(f.selected)){f.setSelected(f.selected)}}})})(tinymce);(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.Menu:tinymce.ui.MenuItem",{Menu:function(h,g){var f=this;f.parent(h,g);f.items={};f.collapsed=false;f.menuCount=0;f.onAddItem=new d.util.Dispatcher(this)},expand:function(g){var f=this;if(g){a(f,function(h){if(h.expand){h.expand()}},"items",f)}f.collapsed=false},collapse:function(g){var f=this;if(g){a(f,function(h){if(h.collapse){h.collapse()}},"items",f)}f.collapsed=true},isCollapsed:function(){return this.collapsed},add:function(f){if(!f.settings){f=new d.ui.MenuItem(f.id||b.uniqueId(),f)}this.onAddItem.dispatch(this,f);return this.items[f.id]=f},addSeparator:function(){return this.add({separator:true})},addMenu:function(f){if(!f.collapse){f=this.createMenu(f)}this.menuCount++;return this.add(f)},hasMenus:function(){return this.menuCount!==0},remove:function(f){delete this.items[f.id]},removeAll:function(){var f=this;a(f,function(g){if(g.removeAll){g.removeAll()}else{g.remove()}g.destroy()},"items",f);f.items={}},createMenu:function(g){var f=new d.ui.Menu(g.id||b.uniqueId(),g);f.onAddItem.add(this.onAddItem.dispatch,this.onAddItem);return f}})})(tinymce);(function(e){var d=e.is,c=e.DOM,f=e.each,a=e.dom.Event,b=e.dom.Element;e.create("tinymce.ui.DropMenu:tinymce.ui.Menu",{DropMenu:function(h,g){g=g||{};g.container=g.container||c.doc.body;g.offset_x=g.offset_x||0;g.offset_y=g.offset_y||0;g.vp_offset_x=g.vp_offset_x||0;g.vp_offset_y=g.vp_offset_y||0;if(d(g.icons)&&!g.icons){g["class"]+=" mceNoIcons"}this.parent(h,g);this.onShowMenu=new e.util.Dispatcher(this);this.onHideMenu=new e.util.Dispatcher(this);this.classPrefix="mceMenu"},createMenu:function(j){var h=this,i=h.settings,g;j.container=j.container||i.container;j.parent=h;j.constrain=j.constrain||i.constrain;j["class"]=j["class"]||i["class"];j.vp_offset_x=j.vp_offset_x||i.vp_offset_x;j.vp_offset_y=j.vp_offset_y||i.vp_offset_y;j.keyboard_focus=i.keyboard_focus;g=new e.ui.DropMenu(j.id||c.uniqueId(),j);g.onAddItem.add(h.onAddItem.dispatch,h.onAddItem);return g},focus:function(){var g=this;if(g.keyboardNav){g.keyboardNav.focus()}},update:function(){var i=this,j=i.settings,g=c.get("menu_"+i.id+"_tbl"),l=c.get("menu_"+i.id+"_co"),h,k;h=j.max_width?Math.min(g.offsetWidth,j.max_width):g.offsetWidth;k=j.max_height?Math.min(g.offsetHeight,j.max_height):g.offsetHeight;if(!c.boxModel){i.element.setStyles({width:h+2,height:k+2})}else{i.element.setStyles({width:h,height:k})}if(j.max_width){c.setStyle(l,"width",h)}if(j.max_height){c.setStyle(l,"height",k);if(g.clientHeight<j.max_height){c.setStyle(l,"overflow","hidden")}}},showMenu:function(p,n,r){var z=this,A=z.settings,o,g=c.getViewPort(),u,l,v,q,i=2,k,j,m=z.classPrefix;z.collapse(1);if(z.isMenuVisible){return}if(!z.rendered){o=c.add(z.settings.container,z.renderNode());f(z.items,function(h){h.postRender()});z.element=new b("menu_"+z.id,{blocker:1,container:A.container})}else{o=c.get("menu_"+z.id)}if(!e.isOpera){c.setStyles(o,{left:-65535,top:-65535})}c.show(o);z.update();p+=A.offset_x||0;n+=A.offset_y||0;g.w-=4;g.h-=4;if(A.constrain){u=o.clientWidth-i;l=o.clientHeight-i;v=g.x+g.w;q=g.y+g.h;if((p+A.vp_offset_x+u)>v){p=r?r-u:Math.max(0,(v-A.vp_offset_x)-u)}if((n+A.vp_offset_y+l)>q){n=Math.max(0,(q-A.vp_offset_y)-l)}}c.setStyles(o,{left:p,top:n});z.element.update();z.isMenuVisible=1;z.mouseClickFunc=a.add(o,"click",function(s){var h;s=s.target;if(s&&(s=c.getParent(s,"tr"))&&!c.hasClass(s,m+"ItemSub")){h=z.items[s.id];if(h.isDisabled()){return}k=z;while(k){if(k.hideMenu){k.hideMenu()}k=k.settings.parent}if(h.settings.onclick){h.settings.onclick(s)}return false}});if(z.hasMenus()){z.mouseOverFunc=a.add(o,"mouseover",function(x){var h,t,s;x=x.target;if(x&&(x=c.getParent(x,"tr"))){h=z.items[x.id];if(z.lastMenu){z.lastMenu.collapse(1)}if(h.isDisabled()){return}if(x&&c.hasClass(x,m+"ItemSub")){t=c.getRect(x);h.showMenu((t.x+t.w-i),t.y-i,t.x);z.lastMenu=h;c.addClass(c.get(h.id).firstChild,m+"ItemActive")}}})}a.add(o,"keydown",z._keyHandler,z);z.onShowMenu.dispatch(z);if(A.keyboard_focus){z._setupKeyboardNav()}},hideMenu:function(j){var g=this,i=c.get("menu_"+g.id),h;if(!g.isMenuVisible){return}if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(i,"mouseover",g.mouseOverFunc);a.remove(i,"click",g.mouseClickFunc);a.remove(i,"keydown",g._keyHandler);c.hide(i);g.isMenuVisible=0;if(!j){g.collapse(1)}if(g.element){g.element.hide()}if(h=c.get(g.id)){c.removeClass(h.firstChild,g.classPrefix+"ItemActive")}g.onHideMenu.dispatch(g)},add:function(i){var g=this,h;i=g.parent(i);if(g.isRendered&&(h=c.get("menu_"+g.id))){g._add(c.select("tbody",h)[0],i)}return i},collapse:function(g){this.parent(g);this.hideMenu(1)},remove:function(g){c.remove(g.id);this.destroy();return this.parent(g)},destroy:function(){var g=this,h=c.get("menu_"+g.id);if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(h,"mouseover",g.mouseOverFunc);a.remove(c.select("a",h),"focus",g.mouseOverFunc);a.remove(h,"click",g.mouseClickFunc);a.remove(h,"keydown",g._keyHandler);if(g.element){g.element.remove()}c.remove(h)},renderNode:function(){var i=this,j=i.settings,l,h,k,g;g=c.create("div",{role:"listbox",id:"menu_"+i.id,"class":j["class"],style:"position:absolute;left:0;top:0;z-index:200000;outline:0"});if(i.settings.parent){c.setAttrib(g,"aria-parent","menu_"+i.settings.parent.id)}k=c.add(g,"div",{role:"presentation",id:"menu_"+i.id+"_co","class":i.classPrefix+(j["class"]?" "+j["class"]:"")});i.element=new b("menu_"+i.id,{blocker:1,container:j.container});if(j.menu_line){c.add(k,"span",{"class":i.classPrefix+"Line"})}l=c.add(k,"table",{role:"presentation",id:"menu_"+i.id+"_tbl",border:0,cellPadding:0,cellSpacing:0});h=c.add(l,"tbody");f(i.items,function(m){i._add(h,m)});i.rendered=true;return g},_setupKeyboardNav:function(){var i,h,g=this;i=c.get("menu_"+g.id);h=c.select("a[role=option]","menu_"+g.id);h.splice(0,0,i);g.keyboardNav=new e.ui.KeyboardNavigation({root:"menu_"+g.id,items:h,onCancel:function(){g.hideMenu()},enableUpDown:true});i.focus()},_keyHandler:function(g){var h=this,i;switch(g.keyCode){case 37:if(h.settings.parent){h.hideMenu();h.settings.parent.focus();a.cancel(g)}break;case 39:if(h.mouseOverFunc){h.mouseOverFunc(g)}break}},_add:function(j,h){var i,q=h.settings,p,l,k,m=this.classPrefix,g;if(q.separator){l=c.add(j,"tr",{id:h.id,"class":m+"ItemSeparator"});c.add(l,"td",{"class":m+"ItemSeparator"});if(i=l.previousSibling){c.addClass(i,"mceLast")}return}i=l=c.add(j,"tr",{id:h.id,"class":m+"Item "+m+"ItemEnabled"});i=k=c.add(i,q.titleItem?"th":"td");i=p=c.add(i,"a",{id:h.id+"_aria",role:q.titleItem?"presentation":"option",href:"javascript:;",onclick:"return false;",onmousedown:"return false;"});if(q.parent){c.setAttrib(p,"aria-haspopup","true");c.setAttrib(p,"aria-owns","menu_"+h.id)}c.addClass(k,q["class"]);g=c.add(i,"span",{"class":"mceIcon"+(q.icon?" mce_"+q.icon:"")});if(q.icon_src){c.add(g,"img",{src:q.icon_src})}i=c.add(i,q.element||"span",{"class":"mceText",title:h.settings.title},h.settings.title);if(h.settings.style){if(typeof h.settings.style=="function"){h.settings.style=h.settings.style()}c.setAttrib(i,"style",h.settings.style)}if(j.childNodes.length==1){c.addClass(l,"mceFirst")}if((i=l.previousSibling)&&c.hasClass(i,m+"ItemSeparator")){c.addClass(l,"mceFirst")}if(h.collapse){c.addClass(l,m+"ItemSub")}if(i=l.previousSibling){c.removeClass(i,"mceLast")}c.addClass(l,"mceLast")}})})(tinymce);(function(b){var a=b.DOM;b.create("tinymce.ui.Button:tinymce.ui.Control",{Button:function(e,d,c){this.parent(e,d,c);this.classPrefix="mceButton"},renderHTML:function(){var f=this.classPrefix,e=this.settings,d,c;c=a.encode(e.label||"");d='<a role="button" id="'+this.id+'" href="javascript:;" class="'+f+" "+f+"Enabled "+e["class"]+(c?" "+f+"Labeled":"")+'" onmousedown="return false;" onclick="return false;" aria-labelledby="'+this.id+'_voice" title="'+a.encode(e.title)+'">';if(e.image&&!(this.editor&&this.editor.forcedHighContrastMode)){d+='<span class="mceIcon '+e["class"]+'"><img class="mceIcon" src="'+e.image+'" alt="'+a.encode(e.title)+'" /></span>'+(c?'<span class="'+f+'Label">'+c+"</span>":"")}else{d+='<span class="mceIcon '+e["class"]+'"></span>'+(c?'<span class="'+f+'Label">'+c+"</span>":"")}d+='<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="'+this.id+'_voice">'+e.title+"</span>";d+="</a>";return d},postRender:function(){var d=this,e=d.settings,c;if(b.isIE&&d.editor){b.dom.Event.add(d.id,"mousedown",function(f){var g=d.editor.selection.getNode().nodeName;c=g==="IMG"?d.editor.selection.getBookmark():null})}b.dom.Event.add(d.id,"click",function(f){if(!d.isDisabled()){if(b.isIE&&d.editor&&c!==null){d.editor.selection.moveToBookmark(c)}return e.onclick.call(e.scope,f)}});b.dom.Event.add(d.id,"keydown",function(f){if(!d.isDisabled()&&f.keyCode==b.VK.SPACEBAR){b.dom.Event.cancel(f);return e.onclick.call(e.scope,f)}})}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.ListBox:tinymce.ui.Control",{ListBox:function(j,i,g){var h=this;h.parent(j,i,g);h.items=[];h.onChange=new a(h);h.onPostRender=new a(h);h.onAdd=new a(h);h.onRenderMenu=new e.util.Dispatcher(this);h.classPrefix="mceListBox";h.marked={}},select:function(h){var g=this,j,i;g.marked={};if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){var i=this,j,k,h;i.marked={};if(g!=i.selectedIndex){j=d.get(i.id+"_text");h=d.get(i.id+"_voiceDesc");k=i.items[g];if(k){i.selectedValue=k.value;i.selectedIndex=g;d.setHTML(j,d.encode(k.title));d.setHTML(h,i.settings.title+" - "+k.title);d.removeClass(j,"mceTitle");d.setAttrib(i.id,"aria-valuenow",k.title)}else{d.setHTML(j,d.encode(i.settings.title));d.setHTML(h,d.encode(i.settings.title));d.addClass(j,"mceTitle");i.selectedValue=i.selectedIndex=null;d.setAttrib(i.id,"aria-valuenow",i.settings.title)}j=0}},mark:function(g){this.marked[g]=true},add:function(j,g,i){var h=this;i=i||{};i=e.extend(i,{title:j,value:g});h.items.push(i);h.onAdd.dispatch(h,i)},getLength:function(){return this.items.length},renderHTML:function(){var j="",g=this,i=g.settings,k=g.classPrefix;j='<span role="listbox" aria-haspopup="true" aria-labelledby="'+g.id+'_voiceDesc" aria-describedby="'+g.id+'_voiceDesc"><table role="presentation" tabindex="0" id="'+g.id+'" cellpadding="0" cellspacing="0" class="'+k+" "+k+"Enabled"+(i["class"]?(" "+i["class"]):"")+'"><tbody><tr>';j+="<td>"+d.createHTML("span",{id:g.id+"_voiceDesc","class":"voiceLabel",style:"display:none;"},g.settings.title);j+=d.createHTML("a",{id:g.id+"_text",tabindex:-1,href:"javascript:;","class":"mceText",onclick:"return false;",onmousedown:"return false;"},d.encode(g.settings.title))+"</td>";j+="<td>"+d.createHTML("a",{id:g.id+"_open",tabindex:-1,href:"javascript:;","class":"mceOpen",onclick:"return false;",onmousedown:"return false;"},'<span><span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span></span>')+"</td>";j+="</tr></tbody></table></span>";return j},showMenu:function(){var h=this,j,i=d.get(this.id),g;if(h.isDisabled()||h.items.length===0){return}if(h.menu&&h.menu.isMenuVisible){return h.hideMenu()}if(!h.isMenuRendered){h.renderMenu();h.isMenuRendered=true}j=d.getPos(i);g=h.menu;g.settings.offset_x=j.x;g.settings.offset_y=j.y;g.settings.keyboard_focus=!e.isOpera;f(h.items,function(k){if(g.items[k.id]){g.items[k.id].setSelected(0)}});f(h.items,function(k){if(g.items[k.id]&&h.marked[k.value]){g.items[k.id].setSelected(1)}if(k.value===h.selectedValue){g.items[k.id].setSelected(1)}});g.showMenu(0,i.clientHeight);b.add(d.doc,"mousedown",h.hideMenu,h);d.addClass(h.id,h.classPrefix+"Selected")},hideMenu:function(h){var g=this;if(g.menu&&g.menu.isMenuVisible){d.removeClass(g.id,g.classPrefix+"Selected");if(h&&h.type=="mousedown"&&(h.target.id==g.id+"_text"||h.target.id==g.id+"_open")){return}if(!h||!d.getParent(h.target,".mceMenu")){d.removeClass(g.id,g.classPrefix+"Selected");b.remove(d.doc,"mousedown",g.hideMenu,g);g.menu.hideMenu()}}},renderMenu:function(){var h=this,g;g=h.settings.control_manager.createDropMenu(h.id+"_menu",{menu_line:1,"class":h.classPrefix+"Menu mceNoIcons",max_width:250,max_height:150});g.onHideMenu.add(function(){h.hideMenu();h.focus()});g.add({title:h.settings.title,"class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}});f(h.items,function(i){if(i.value===c){g.add({title:i.title,role:"option","class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}})}else{i.id=d.uniqueId();i.role="option";i.onclick=function(){if(h.settings.onselect(i.value)!==false){h.select(i.value)}};g.add(i)}});h.onRenderMenu.dispatch(h,g);h.menu=g},postRender:function(){var g=this,h=g.classPrefix;b.add(g.id,"click",g.showMenu,g);b.add(g.id,"keydown",function(i){if(i.keyCode==32){g.showMenu(i);b.cancel(i)}});b.add(g.id,"focus",function(){if(!g._focused){g.keyDownHandler=b.add(g.id,"keydown",function(i){if(i.keyCode==40){g.showMenu();b.cancel(i)}});g.keyPressHandler=b.add(g.id,"keypress",function(j){var i;if(j.keyCode==13){i=g.selectedValue;g.selectedValue=null;b.cancel(j);g.settings.onselect(i)}})}g._focused=1});b.add(g.id,"blur",function(){b.remove(g.id,"keydown",g.keyDownHandler);b.remove(g.id,"keypress",g.keyPressHandler);g._focused=0});if(e.isIE6||!d.boxModel){b.add(g.id,"mouseover",function(){if(!d.hasClass(g.id,h+"Disabled")){d.addClass(g.id,h+"Hover")}});b.add(g.id,"mouseout",function(){if(!d.hasClass(g.id,h+"Disabled")){d.removeClass(g.id,h+"Hover")}})}g.onPostRender.dispatch(g,d.get(g.id))},destroy:function(){this.parent();b.clear(this.id+"_text");b.clear(this.id+"_open")}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.NativeListBox:tinymce.ui.ListBox",{NativeListBox:function(h,g){this.parent(h,g);this.classPrefix="mceNativeListBox"},setDisabled:function(g){d.get(this.id).disabled=g;this.setAriaProperty("disabled",g)},isDisabled:function(){return d.get(this.id).disabled},select:function(h){var g=this,j,i;if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){d.get(this.id).selectedIndex=g+1;this.selectedValue=this.items[g]?this.items[g].value:null},add:function(k,h,g){var j,i=this;g=g||{};g.value=h;if(i.isRendered()){d.add(d.get(this.id),"option",g,k)}j={title:k,value:h,attribs:g};i.items.push(j);i.onAdd.dispatch(i,j)},getLength:function(){return this.items.length},renderHTML:function(){var i,g=this;i=d.createHTML("option",{value:""},"-- "+g.settings.title+" --");f(g.items,function(h){i+=d.createHTML("option",{value:h.value},h.title)});i=d.createHTML("select",{id:g.id,"class":"mceNativeListBox","aria-labelledby":g.id+"_aria"},i);i+=d.createHTML("span",{id:g.id+"_aria",style:"display: none"},g.settings.title);return i},postRender:function(){var h=this,i,j=true;h.rendered=true;function g(l){var k=h.items[l.target.selectedIndex-1];if(k&&(k=k.value)){h.onChange.dispatch(h,k);if(h.settings.onselect){h.settings.onselect(k)}}}b.add(h.id,"change",g);b.add(h.id,"keydown",function(l){var k;b.remove(h.id,"change",i);j=false;k=b.add(h.id,"blur",function(){if(j){return}j=true;b.add(h.id,"change",g);b.remove(h.id,"blur",k)});if(e.isWebKit&&(l.keyCode==37||l.keyCode==39)){return b.prevent(l)}if(l.keyCode==13||l.keyCode==32){g(l);return b.cancel(l)}});h.onPostRender.dispatch(h,d.get(h.id))}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.MenuButton:tinymce.ui.Button",{MenuButton:function(g,f,e){this.parent(g,f,e);this.onRenderMenu=new c.util.Dispatcher(this);f.menu_container=f.menu_container||b.doc.body},showMenu:function(){var g=this,j,i,h=b.get(g.id),f;if(g.isDisabled()){return}if(!g.isMenuRendered){g.renderMenu();g.isMenuRendered=true}if(g.isMenuVisible){return g.hideMenu()}j=b.getPos(g.settings.menu_container);i=b.getPos(h);f=g.menu;f.settings.offset_x=i.x;f.settings.offset_y=i.y;f.settings.vp_offset_x=i.x;f.settings.vp_offset_y=i.y;f.settings.keyboard_focus=g._focused;f.showMenu(0,h.firstChild.clientHeight);a.add(b.doc,"mousedown",g.hideMenu,g);g.setState("Selected",1);g.isMenuVisible=1},renderMenu:function(){var f=this,e;e=f.settings.control_manager.createDropMenu(f.id+"_menu",{menu_line:1,"class":this.classPrefix+"Menu",icons:f.settings.icons});e.onHideMenu.add(function(){f.hideMenu();f.focus()});f.onRenderMenu.dispatch(f,e);f.menu=e},hideMenu:function(g){var f=this;if(g&&g.type=="mousedown"&&b.getParent(g.target,function(h){return h.id===f.id||h.id===f.id+"_open"})){return}if(!g||!b.getParent(g.target,".mceMenu")){f.setState("Selected",0);a.remove(b.doc,"mousedown",f.hideMenu,f);if(f.menu){f.menu.hideMenu()}}f.isMenuVisible=0},postRender:function(){var e=this,f=e.settings;a.add(e.id,"click",function(){if(!e.isDisabled()){if(f.onclick){f.onclick(e.value)}e.showMenu()}})}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.SplitButton:tinymce.ui.MenuButton",{SplitButton:function(g,f,e){this.parent(g,f,e);this.classPrefix="mceSplitButton"},renderHTML:function(){var i,f=this,g=f.settings,e;i="<tbody><tr>";if(g.image){e=b.createHTML("img ",{src:g.image,role:"presentation","class":"mceAction "+g["class"]})}else{e=b.createHTML("span",{"class":"mceAction "+g["class"]},"")}e+=b.createHTML("span",{"class":"mceVoiceLabel mceIconOnly",id:f.id+"_voice",style:"display:none;"},g.title);i+="<td >"+b.createHTML("a",{role:"button",id:f.id+"_action",tabindex:"-1",href:"javascript:;","class":"mceAction "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"</td>";e=b.createHTML("span",{"class":"mceOpen "+g["class"]},'<span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span>');i+="<td >"+b.createHTML("a",{role:"button",id:f.id+"_open",tabindex:"-1",href:"javascript:;","class":"mceOpen "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"</td>";i+="</tr></tbody>";i=b.createHTML("table",{role:"presentation","class":"mceSplitButton mceSplitButtonEnabled "+g["class"],cellpadding:"0",cellspacing:"0",title:g.title},i);return b.createHTML("div",{id:f.id,role:"button",tabindex:"0","aria-labelledby":f.id+"_voice","aria-haspopup":"true"},i)},postRender:function(){var e=this,g=e.settings,f;if(g.onclick){f=function(h){if(!e.isDisabled()){g.onclick(e.value);a.cancel(h)}};a.add(e.id+"_action","click",f);a.add(e.id,["click","keydown"],function(h){var k=32,m=14,i=13,j=38,l=40;if((h.keyCode===32||h.keyCode===13||h.keyCode===14)&&!h.altKey&&!h.ctrlKey&&!h.metaKey){f();a.cancel(h)}else{if(h.type==="click"||h.keyCode===l){e.showMenu();a.cancel(h)}}})}a.add(e.id+"_open","click",function(h){e.showMenu();a.cancel(h)});a.add([e.id,e.id+"_open"],"focus",function(){e._focused=1});a.add([e.id,e.id+"_open"],"blur",function(){e._focused=0});if(c.isIE6||!b.boxModel){a.add(e.id,"mouseover",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.addClass(e.id,"mceSplitButtonHover")}});a.add(e.id,"mouseout",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.removeClass(e.id,"mceSplitButtonHover")}})}},destroy:function(){this.parent();a.clear(this.id+"_action");a.clear(this.id+"_open");a.clear(this.id)}})})(tinymce);(function(d){var c=d.DOM,a=d.dom.Event,b=d.is,e=d.each;d.create("tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton",{ColorSplitButton:function(i,h,f){var g=this;g.parent(i,h,f);g.settings=h=d.extend({colors:"000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF",grid_width:8,default_color:"#888888"},g.settings);g.onShowMenu=new d.util.Dispatcher(g);g.onHideMenu=new d.util.Dispatcher(g);g.value=h.default_color},showMenu:function(){var f=this,g,j,i,h;if(f.isDisabled()){return}if(!f.isMenuRendered){f.renderMenu();f.isMenuRendered=true}if(f.isMenuVisible){return f.hideMenu()}i=c.get(f.id);c.show(f.id+"_menu");c.addClass(i,"mceSplitButtonSelected");h=c.getPos(i);c.setStyles(f.id+"_menu",{left:h.x,top:h.y+i.firstChild.clientHeight,zIndex:200000});i=0;a.add(c.doc,"mousedown",f.hideMenu,f);f.onShowMenu.dispatch(f);if(f._focused){f._keyHandler=a.add(f.id+"_menu","keydown",function(k){if(k.keyCode==27){f.hideMenu()}});c.select("a",f.id+"_menu")[0].focus()}f.keyboardNav=new d.ui.KeyboardNavigation({root:f.id+"_menu",items:c.select("a",f.id+"_menu"),onCancel:function(){f.hideMenu();f.focus()}});f.keyboardNav.focus();f.isMenuVisible=1},hideMenu:function(g){var f=this;if(f.isMenuVisible){if(g&&g.type=="mousedown"&&c.getParent(g.target,function(h){return h.id===f.id+"_open"})){return}if(!g||!c.getParent(g.target,".mceSplitButtonMenu")){c.removeClass(f.id,"mceSplitButtonSelected");a.remove(c.doc,"mousedown",f.hideMenu,f);a.remove(f.id+"_menu","keydown",f._keyHandler);c.hide(f.id+"_menu")}f.isMenuVisible=0;f.onHideMenu.dispatch();f.keyboardNav.destroy()}},renderMenu:function(){var p=this,h,k=0,q=p.settings,g,j,l,o,f;o=c.add(q.menu_container,"div",{role:"listbox",id:p.id+"_menu","class":q.menu_class+" "+q["class"],style:"position:absolute;left:0;top:-1000px;"});h=c.add(o,"div",{"class":q["class"]+" mceSplitButtonMenu"});c.add(h,"span",{"class":"mceMenuLine"});g=c.add(h,"table",{role:"presentation","class":"mceColorSplitMenu"});j=c.add(g,"tbody");k=0;e(b(q.colors,"array")?q.colors:q.colors.split(","),function(m){m=m.replace(/^#/,"");if(!k--){l=c.add(j,"tr");k=q.grid_width-1}g=c.add(l,"td");var i={href:"javascript:;",style:{backgroundColor:"#"+m},title:p.editor.getLang("colors."+m,m),"data-mce-color":"#"+m};if(!d.isIE){i.role="option"}g=c.add(g,"a",i);if(p.editor.forcedHighContrastMode){g=c.add(g,"canvas",{width:16,height:16,"aria-hidden":"true"});if(g.getContext&&(f=g.getContext("2d"))){f.fillStyle="#"+m;f.fillRect(0,0,16,16)}else{c.remove(g)}}});if(q.more_colors_func){g=c.add(j,"tr");g=c.add(g,"td",{colspan:q.grid_width,"class":"mceMoreColors"});g=c.add(g,"a",{role:"option",id:p.id+"_more",href:"javascript:;",onclick:"return false;","class":"mceMoreColors"},q.more_colors_title);a.add(g,"click",function(i){q.more_colors_func.call(q.more_colors_scope||this);return a.cancel(i)})}c.addClass(h,"mceColorSplitMenu");a.add(p.id+"_menu","mousedown",function(i){return a.cancel(i)});a.add(p.id+"_menu","click",function(i){var m;i=c.getParent(i.target,"a",j);if(i&&i.nodeName.toLowerCase()=="a"&&(m=i.getAttribute("data-mce-color"))){p.setColor(m)}return false});return o},setColor:function(f){this.displayColor(f);this.hideMenu();this.settings.onselect(f)},displayColor:function(g){var f=this;c.setStyle(f.id+"_preview","backgroundColor",g);f.value=g},postRender:function(){var f=this,g=f.id;f.parent();c.add(g+"_action","div",{id:g+"_preview","class":"mceColorPreview"});c.setStyle(f.id+"_preview","backgroundColor",f.value)},destroy:function(){var f=this;f.parent();a.clear(f.id+"_menu");a.clear(f.id+"_more");c.remove(f.id+"_menu");if(f.keyboardNav){f.keyboardNav.destroy()}}})})(tinymce);(function(b){var d=b.DOM,c=b.each,a=b.dom.Event;b.create("tinymce.ui.ToolbarGroup:tinymce.ui.Container",{renderHTML:function(){var f=this,i=[],e=f.controls,j=b.each,g=f.settings;i.push('<div id="'+f.id+'" role="group" aria-labelledby="'+f.id+'_voice">');i.push("<span role='application'>");i.push('<span id="'+f.id+'_voice" class="mceVoiceLabel" style="display:none;">'+d.encode(g.name)+"</span>");j(e,function(h){i.push(h.renderHTML())});i.push("</span>");i.push("</div>");return i.join("")},focus:function(){var e=this;d.get(e.id).focus()},postRender:function(){var f=this,e=[];c(f.controls,function(g){c(g.controls,function(h){if(h.id){e.push(h)}})});f.keyNav=new b.ui.KeyboardNavigation({root:f.id,items:e,onCancel:function(){if(b.isWebKit){d.get(f.editor.id+"_ifr").focus()}f.editor.focus()},excludeFromTabOrder:!f.settings.tab_focus_toolbar})},destroy:function(){var e=this;e.parent();e.keyNav.destroy();a.clear(e.id)}})})(tinymce);(function(a){var c=a.DOM,b=a.each;a.create("tinymce.ui.Toolbar:tinymce.ui.Container",{renderHTML:function(){var m=this,f="",j,k,n=m.settings,e,d,g,l;l=m.controls;for(e=0;e<l.length;e++){k=l[e];d=l[e-1];g=l[e+1];if(e===0){j="mceToolbarStart";if(k.Button){j+=" mceToolbarStartButton"}else{if(k.SplitButton){j+=" mceToolbarStartSplitButton"}else{if(k.ListBox){j+=" mceToolbarStartListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,"<!-- IE -->"))}if(d&&k.ListBox){if(d.Button||d.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarEnd"},c.createHTML("span",null,"<!-- IE -->"))}}if(c.stdMode){f+='<td style="position: relative">'+k.renderHTML()+"</td>"}else{f+="<td>"+k.renderHTML()+"</td>"}if(g&&k.ListBox){if(g.Button||g.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarStart"},c.createHTML("span",null,"<!-- IE -->"))}}}j="mceToolbarEnd";if(k.Button){j+=" mceToolbarEndButton"}else{if(k.SplitButton){j+=" mceToolbarEndSplitButton"}else{if(k.ListBox){j+=" mceToolbarEndListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,"<!-- IE -->"));return c.createHTML("table",{id:m.id,"class":"mceToolbar"+(n["class"]?" "+n["class"]:""),cellpadding:"0",cellspacing:"0",align:m.settings.align||"",role:"presentation",tabindex:"-1"},"<tbody><tr>"+f+"</tr></tbody>")}})})(tinymce);(function(b){var a=b.util.Dispatcher,c=b.each;b.create("tinymce.AddOnManager",{AddOnManager:function(){var d=this;d.items=[];d.urls={};d.lookup={};d.onAdd=new a(d)},get:function(d){if(this.lookup[d]){return this.lookup[d].instance}else{return undefined}},dependencies:function(e){var d;if(this.lookup[e]){d=this.lookup[e].dependencies}return d||[]},requireLangPack:function(e){var d=b.settings;if(d&&d.language&&d.language_load!==false){b.ScriptLoader.add(this.urls[e]+"/langs/"+d.language+".js")}},add:function(f,e,d){this.items.push(e);this.lookup[f]={instance:e,dependencies:d};this.onAdd.dispatch(this,f,e);return e},createUrl:function(d,e){if(typeof e==="object"){return e}else{return{prefix:d.prefix,resource:e,suffix:d.suffix}}},addComponents:function(f,d){var e=this.urls[f];b.each(d,function(g){b.ScriptLoader.add(e+"/"+g)})},load:function(j,f,d,h){var g=this,e=f;function i(){var k=g.dependencies(j);b.each(k,function(m){var l=g.createUrl(f,m);g.load(l.resource,l,undefined,undefined)});if(d){if(h){d.call(h)}else{d.call(b.ScriptLoader)}}}if(g.urls[j]){return}if(typeof f==="object"){e=f.prefix+f.resource+f.suffix}if(e.indexOf("/")!==0&&e.indexOf("://")==-1){e=b.baseURL+"/"+e}g.urls[j]=e.substring(0,e.lastIndexOf("/"));if(g.lookup[j]){i()}else{b.ScriptLoader.add(e,i,h)}}});b.PluginManager=new b.AddOnManager();b.ThemeManager=new b.AddOnManager()}(tinymce));(function(j){var g=j.each,d=j.extend,k=j.DOM,i=j.dom.Event,f=j.ThemeManager,b=j.PluginManager,e=j.explode,h=j.util.Dispatcher,a,c=0;j.documentBaseURL=window.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,"");if(!/[\/\\]$/.test(j.documentBaseURL)){j.documentBaseURL+="/"}j.baseURL=new j.util.URI(j.documentBaseURL).toAbsolute(j.baseURL);j.baseURI=new j.util.URI(j.baseURL);j.onBeforeUnload=new h(j);i.add(window,"beforeunload",function(l){j.onBeforeUnload.dispatch(j,l)});j.onAddEditor=new h(j);j.onRemoveEditor=new h(j);j.EditorManager=d(j,{editors:[],i18n:{},activeEditor:null,init:function(x){var v=this,o,n=j.ScriptLoader,u,l=[],r;function q(t){var s=t.id;if(!s){s=t.name;if(s&&!k.get(s)){s=t.name}else{s=k.uniqueId()}t.setAttribute("id",s)}return s}function m(z,A,t){var y=z[A];if(!y){return}if(j.is(y,"string")){t=y.replace(/\.\w+$/,"");t=t?j.resolve(t):0;y=j.resolve(y)}return y.apply(t||this,Array.prototype.slice.call(arguments,2))}function p(t,s){return s.constructor===RegExp?s.test(t.className):k.hasClass(t,s)}v.settings=x;i.bind(window,"ready",function(){var s,t;m(x,"onpageload");switch(x.mode){case"exact":s=x.elements||"";if(s.length>0){g(e(s),function(y){if(k.get(y)){r=new j.Editor(y,x);l.push(r);r.render(1)}else{g(document.forms,function(z){g(z.elements,function(A){if(A.name===y){y="mce_editor_"+c++;k.setAttrib(A,"id",y);r=new j.Editor(y,x);l.push(r);r.render(1)}})})}})}break;case"textareas":case"specific_textareas":g(k.select("textarea"),function(y){if(x.editor_deselector&&p(y,x.editor_deselector)){return}if(!x.editor_selector||p(y,x.editor_selector)){r=new j.Editor(q(y),x);l.push(r);r.render(1)}});break;default:if(x.types){g(x.types,function(y){g(k.select(y.selector),function(A){var z=new j.Editor(q(A),j.extend({},x,y));l.push(z);z.render(1)})})}else{if(x.selector){g(k.select(x.selector),function(z){var y=new j.Editor(q(z),x);l.push(y);y.render(1)})}}}if(x.oninit){s=t=0;g(l,function(y){t++;if(!y.initialized){y.onInit.add(function(){s++;if(s==t){m(x,"oninit")}})}else{s++}if(s==t){m(x,"oninit")}})}})},get:function(l){if(l===a){return this.editors}if(!this.editors.hasOwnProperty(l)){return a}return this.editors[l]},getInstanceById:function(l){return this.get(l)},add:function(m){var l=this,n=l.editors;n[m.id]=m;n.push(m);l._setActive(m);l.onAddEditor.dispatch(l,m);return m},remove:function(n){var m=this,l,o=m.editors;if(!o[n.id]){return null}delete o[n.id];for(l=0;l<o.length;l++){if(o[l]==n){o.splice(l,1);break}}if(m.activeEditor==n){m._setActive(o[0])}n.destroy();m.onRemoveEditor.dispatch(m,n);return n},execCommand:function(r,p,o){var q=this,n=q.get(o),l;function m(){n.destroy();l.detachEvent("onunload",m);l=l.tinyMCE=l.tinymce=null}switch(r){case"mceFocus":n.focus();return true;case"mceAddEditor":case"mceAddControl":if(!q.get(o)){new j.Editor(o,q.settings).render()}return true;case"mceAddFrameControl":l=o.window;l.tinyMCE=tinyMCE;l.tinymce=j;j.DOM.doc=l.document;j.DOM.win=l;n=new j.Editor(o.element_id,o);n.render();if(j.isIE){l.attachEvent("onunload",m)}o.page_window=null;return true;case"mceRemoveEditor":case"mceRemoveControl":if(n){n.remove()}return true;case"mceToggleEditor":if(!n){q.execCommand("mceAddControl",0,o);return true}if(n.isHidden()){n.show()}else{n.hide()}return true}if(q.activeEditor){return q.activeEditor.execCommand(r,p,o)}return false},execInstanceCommand:function(p,o,n,m){var l=this.get(p);if(l){return l.execCommand(o,n,m)}return false},triggerSave:function(){g(this.editors,function(l){l.save()})},addI18n:function(n,q){var l,m=this.i18n;if(!j.is(n,"string")){g(n,function(r,p){g(r,function(t,s){g(t,function(v,u){if(s==="common"){m[p+"."+u]=v}else{m[p+"."+s+"."+u]=v}})})})}else{g(q,function(r,p){m[n+"."+p]=r})}},_setActive:function(l){this.selectedInstance=this.activeEditor=l}})})(tinymce);(function(k){var l=k.DOM,j=k.dom.Event,f=k.extend,i=k.each,a=k.isGecko,b=k.isIE,e=k.isWebKit,d=k.is,h=k.ThemeManager,c=k.PluginManager,g=k.explode;k.create("tinymce.Editor",{Editor:function(p,o){var m=this,n=true;m.settings=o=f({id:p,language:"en",theme:"advanced",skin:"default",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:k.documentBaseURL,add_form_submit_trigger:n,submit_patch:n,add_unload_trigger:n,convert_urls:n,relative_urls:n,remove_script_host:n,table_inline_editing:false,object_resizing:n,accessibility_focus:n,doctype:k.isIE6?'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">':"<!DOCTYPE>",visual:n,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",apply_source_formatting:n,directionality:"ltr",forced_root_block:"p",hidden_input:n,padd_empty_editor:n,render_ui:n,indentation:"30px",fix_table_elements:n,inline_styles:n,convert_fonts_to_spans:n,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",validate:n,entity_encoding:"named",url_converter:m.convertURL,url_converter_scope:m,ie7_compat:n},o);m.id=m.editorId=p;m.isNotDirty=false;m.plugins={};m.documentBaseURI=new k.util.URI(o.document_base_url||k.documentBaseURL,{base_uri:tinyMCE.baseURI});m.baseURI=k.baseURI;m.contentCSS=[];m.contentStyles=[];m.setupEvents();m.execCommands={};m.queryStateCommands={};m.queryValueCommands={};m.execCallback("setup",m)},render:function(o){var p=this,q=p.settings,r=p.id,m=k.ScriptLoader;if(!j.domLoaded){j.add(window,"ready",function(){p.render()});return}tinyMCE.settings=q;if(!p.getElement()){return}if(k.isIDevice&&!k.isIOS5){return}if(!/TEXTAREA|INPUT/i.test(p.getElement().nodeName)&&q.hidden_input&&l.getParent(r,"form")){l.insertAfter(l.create("input",{type:"hidden",name:r}),r)}if(!q.content_editable){p.orgVisibility=p.getElement().style.visibility;p.getElement().style.visibility="hidden"}if(k.WindowManager){p.windowManager=new k.WindowManager(p)}if(q.encoding=="xml"){p.onGetContent.add(function(s,t){if(t.save){t.content=l.encode(t.content)}})}if(q.add_form_submit_trigger){p.onSubmit.addToTop(function(){if(p.initialized){p.save();p.isNotDirty=1}})}if(q.add_unload_trigger){p._beforeUnload=tinyMCE.onBeforeUnload.add(function(){if(p.initialized&&!p.destroyed&&!p.isHidden()){p.save({format:"raw",no_events:true})}})}k.addUnload(p.destroy,p);if(q.submit_patch){p.onBeforeRenderUI.add(function(){var s=p.getElement().form;if(!s){return}if(s._mceOldSubmit){return}if(!s.submit.nodeType&&!s.submit.length){p.formElement=s;s._mceOldSubmit=s.submit;s.submit=function(){k.triggerSave();p.isNotDirty=1;return p.formElement._mceOldSubmit(p.formElement)}}s=null})}function n(){if(q.language&&q.language_load!==false){m.add(k.baseURL+"/langs/"+q.language+".js")}if(q.theme&&typeof q.theme!="function"&&q.theme.charAt(0)!="-"&&!h.urls[q.theme]){h.load(q.theme,"themes/"+q.theme+"/editor_template"+k.suffix+".js")}i(g(q.plugins),function(t){if(t&&!c.urls[t]){if(t.charAt(0)=="-"){t=t.substr(1,t.length);var s=c.dependencies(t);i(s,function(v){var u={prefix:"plugins/",resource:v,suffix:"/editor_plugin"+k.suffix+".js"};v=c.createUrl(u,v);c.load(v.resource,v)})}else{if(t=="safari"){return}c.load(t,{prefix:"plugins/",resource:t,suffix:"/editor_plugin"+k.suffix+".js"})}}});m.loadQueue(function(){if(!p.removed){p.init()}})}n()},init:function(){var q,G=this,H=G.settings,D,y,z,C=G.getElement(),p,m,E,v,B,F,x,r=[];k.add(G);H.aria_label=H.aria_label||l.getAttrib(C,"aria-label",G.getLang("aria.rich_text_area"));if(H.theme){if(typeof H.theme!="function"){H.theme=H.theme.replace(/-/,"");p=h.get(H.theme);G.theme=new p();if(G.theme.init){G.theme.init(G,h.urls[H.theme]||k.documentBaseURL.replace(/\/$/,""))}}else{G.theme=H.theme}}function A(s){var t=c.get(s),o=c.urls[s]||k.documentBaseURL.replace(/\/$/,""),n;if(t&&k.inArray(r,s)===-1){i(c.dependencies(s),function(u){A(u)});n=new t(G,o);G.plugins[s]=n;if(n.init){n.init(G,o);r.push(s)}}}i(g(H.plugins.replace(/\-/g,"")),A);if(H.popup_css!==false){if(H.popup_css){H.popup_css=G.documentBaseURI.toAbsolute(H.popup_css)}else{H.popup_css=G.baseURI.toAbsolute("themes/"+H.theme+"/skins/"+H.skin+"/dialog.css")}}if(H.popup_css_add){H.popup_css+=","+G.documentBaseURI.toAbsolute(H.popup_css_add)}G.controlManager=new k.ControlManager(G);G.onBeforeRenderUI.dispatch(G,G.controlManager);if(H.render_ui&&G.theme){G.orgDisplay=C.style.display;if(typeof H.theme!="function"){D=H.width||C.style.width||C.offsetWidth;y=H.height||C.style.height||C.offsetHeight;z=H.min_height||100;F=/^[0-9\.]+(|px)$/i;if(F.test(""+D)){D=Math.max(parseInt(D,10)+(p.deltaWidth||0),100)}if(F.test(""+y)){y=Math.max(parseInt(y,10)+(p.deltaHeight||0),z)}p=G.theme.renderUI({targetNode:C,width:D,height:y,deltaWidth:H.delta_width,deltaHeight:H.delta_height});l.setStyles(p.sizeContainer||p.editorContainer,{width:D,height:y});y=(p.iframeHeight||y)+(typeof(y)=="number"?(p.deltaHeight||0):"");if(y<z){y=z}}else{p=H.theme(G,C);if(p.editorContainer.nodeType){p.editorContainer=p.editorContainer.id=p.editorContainer.id||G.id+"_parent"}if(p.iframeContainer.nodeType){p.iframeContainer=p.iframeContainer.id=p.iframeContainer.id||G.id+"_iframecontainer"}y=p.iframeHeight||C.offsetHeight;if(b){G.onInit.add(function(n){n.dom.bind(n.getBody(),"beforedeactivate keydown",function(){n.lastIERng=n.selection.getRng()})})}}G.editorContainer=p.editorContainer}if(H.content_css){i(g(H.content_css),function(n){G.contentCSS.push(G.documentBaseURI.toAbsolute(n))})}if(H.content_style){G.contentStyles.push(H.content_style)}if(H.content_editable){C=q=p=null;return G.initContentBody()}if(document.domain&&location.hostname!=document.domain){k.relaxedDomain=document.domain}G.iframeHTML=H.doctype+'<html><head xmlns="http://www.w3.org/1999/xhtml">';if(H.document_base_url!=k.documentBaseURL){G.iframeHTML+='<base href="'+G.documentBaseURI.getURI()+'" />'}if(k.isIE8){if(H.ie7_compat){G.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=7" />'}else{G.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=edge" />'}}G.iframeHTML+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';for(x=0;x<G.contentCSS.length;x++){G.iframeHTML+='<link type="text/css" rel="stylesheet" href="'+G.contentCSS[x]+'" />'}G.contentCSS=[];v=H.body_id||"tinymce";if(v.indexOf("=")!=-1){v=G.getParam("body_id","","hash");v=v[G.id]||v}B=H.body_class||"";if(B.indexOf("=")!=-1){B=G.getParam("body_class","","hash");B=B[G.id]||""}G.iframeHTML+='</head><body id="'+v+'" class="mceContentBody '+B+'" onload="window.parent.tinyMCE.get(\''+G.id+"').onLoad.dispatch();\"><br></body></html>";if(k.relaxedDomain&&(b||(k.isOpera&&parseFloat(opera.version())<11))){E='javascript:(function(){document.open();document.domain="'+document.domain+'";var ed = window.parent.tinyMCE.get("'+G.id+'");document.write(ed.iframeHTML);document.close();ed.initContentBody();})()'}q=l.add(p.iframeContainer,"iframe",{id:G.id+"_ifr",src:E||'javascript:""',frameBorder:"0",allowTransparency:"true",title:H.aria_label,style:{width:"100%",height:y,display:"block"}});G.contentAreaContainer=p.iframeContainer;if(p.editorContainer){l.get(p.editorContainer).style.display=G.orgDisplay}C.style.visibility=G.orgVisibility;l.get(G.id).style.display="none";l.setAttrib(G.id,"aria-hidden",true);if(!k.relaxedDomain||!E){G.initContentBody()}C=q=p=null},initContentBody:function(){var n=this,p=n.settings,q=l.get(n.id),r=n.getDoc(),o,m,s;if((!b||!k.relaxedDomain)&&!p.content_editable){r.open();r.write(n.iframeHTML);r.close();if(k.relaxedDomain){r.domain=k.relaxedDomain}}if(p.content_editable){l.addClass(q,"mceContentBody");n.contentDocument=r=p.content_document||document;n.contentWindow=p.content_window||window;n.bodyElement=q;p.content_document=p.content_window=null}m=n.getBody();m.disabled=true;if(!p.readonly){m.contentEditable=n.getParam("content_editable_state",true)}m.disabled=false;n.schema=new k.html.Schema(p);n.dom=new k.dom.DOMUtils(r,{keep_values:true,url_converter:n.convertURL,url_converter_scope:n,hex_colors:p.force_hex_style_colors,class_filter:p.class_filter,update_styles:true,root_element:p.content_editable?n.id:null,schema:n.schema});n.parser=new k.html.DomParser(p,n.schema);n.parser.addAttributeFilter("src,href,style",function(t,u){var v=t.length,y,A=n.dom,z,x;while(v--){y=t[v];z=y.attr(u);x="data-mce-"+u;if(!y.attributes.map[x]){if(u==="style"){y.attr(x,A.serializeStyle(A.parseStyle(z),y.name))}else{y.attr(x,n.convertURL(z,u,y.name))}}}});n.parser.addNodeFilter("script",function(t,u){var v=t.length,x;while(v--){x=t[v];x.attr("type","mce-"+(x.attr("type")||"text/javascript"))}});n.parser.addNodeFilter("#cdata",function(t,u){var v=t.length,x;while(v--){x=t[v];x.type=8;x.name="#comment";x.value="[CDATA["+x.value+"]]"}});n.parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(u,v){var x=u.length,y,t=n.schema.getNonEmptyElements();while(x--){y=u[x];if(y.isEmpty(t)){y.empty().append(new k.html.Node("br",1)).shortEnded=true}}});n.serializer=new k.dom.Serializer(p,n.dom,n.schema);n.selection=new k.dom.Selection(n.dom,n.getWin(),n.serializer,n);n.formatter=new k.Formatter(n);n.undoManager=new k.UndoManager(n);n.forceBlocks=new k.ForceBlocks(n);n.enterKey=new k.EnterKey(n);n.editorCommands=new k.EditorCommands(n);n.onExecCommand.add(function(t,u){if(!/^(FontName|FontSize)$/.test(u)){n.nodeChanged()}});n.serializer.onPreProcess.add(function(t,u){return n.onPreProcess.dispatch(n,u,t)});n.serializer.onPostProcess.add(function(t,u){return n.onPostProcess.dispatch(n,u,t)});n.onPreInit.dispatch(n);if(!p.browser_spellcheck&&!p.gecko_spellcheck){r.body.spellcheck=false}if(!p.readonly){n.bindNativeEvents()}n.controlManager.onPostRender.dispatch(n,n.controlManager);n.onPostRender.dispatch(n);n.quirks=k.util.Quirks(n);if(p.directionality){m.dir=p.directionality}if(p.nowrap){m.style.whiteSpace="nowrap"}if(p.protect){n.onBeforeSetContent.add(function(t,u){i(p.protect,function(v){u.content=u.content.replace(v,function(x){return"<!--mce:protected "+escape(x)+"-->"})})})}n.onSetContent.add(function(){n.addVisual(n.getBody())});if(p.padd_empty_editor){n.onPostProcess.add(function(t,u){u.content=u.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/,"")})}n.load({initial:true,format:"html"});n.startContent=n.getContent({format:"raw"});n.initialized=true;n.onInit.dispatch(n);n.execCallback("setupcontent_callback",n.id,m,r);n.execCallback("init_instance_callback",n);n.focus(true);n.nodeChanged({initial:true});if(n.contentStyles.length>0){s="";i(n.contentStyles,function(t){s+=t+"\r\n"});n.dom.addStyle(s)}i(n.contentCSS,function(t){n.dom.loadCSS(t)});if(p.auto_focus){setTimeout(function(){var t=k.get(p.auto_focus);t.selection.select(t.getBody(),1);t.selection.collapse(1);t.getBody().focus();t.getWin().focus()},100)}q=r=m=null},focus:function(p){var o,u=this,t=u.selection,q=u.settings.content_editable,n,r,s=u.getDoc(),m;if(!p){if(u.lastIERng){t.setRng(u.lastIERng)}n=t.getRng();if(n.item){r=n.item(0)}u._refreshContentEditable();if(!q){u.getWin().focus()}if(k.isGecko||q){m=u.getBody();if(m.setActive){m.setActive()}else{m.focus()}if(q){t.normalize()}}if(r&&r.ownerDocument==s){n=s.body.createControlRange();n.addElement(r);n.select()}}if(k.activeEditor!=u){if((o=k.activeEditor)!=null){o.onDeactivate.dispatch(o,u)}u.onActivate.dispatch(u,o)}k._setActive(u)},execCallback:function(q){var m=this,p=m.settings[q],o;if(!p){return}if(m.callbackLookup&&(o=m.callbackLookup[q])){p=o.func;o=o.scope}if(d(p,"string")){o=p.replace(/\.\w+$/,"");o=o?k.resolve(o):0;p=k.resolve(p);m.callbackLookup=m.callbackLookup||{};m.callbackLookup[q]={func:p,scope:o}}return p.apply(o||m,Array.prototype.slice.call(arguments,1))},translate:function(m){var o=this.settings.language||"en",n=k.i18n;if(!m){return""}return n[o+"."+m]||m.replace(/\{\#([^\}]+)\}/g,function(q,p){return n[o+"."+p]||"{#"+p+"}"})},getLang:function(o,m){return k.i18n[(this.settings.language||"en")+"."+o]||(d(m)?m:"{#"+o+"}")},getParam:function(t,q,m){var r=k.trim,p=d(this.settings[t])?this.settings[t]:q,s;if(m==="hash"){s={};if(d(p,"string")){i(p.indexOf("=")>0?p.split(/[;,](?![^=;,]*(?:[;,]|$))/):p.split(","),function(n){n=n.split("=");if(n.length>1){s[r(n[0])]=r(n[1])}else{s[r(n[0])]=r(n)}})}else{s=p}return s}return p},nodeChanged:function(q){var m=this,n=m.selection,p;if(m.initialized){q=q||{};p=n.getStart()||m.getBody();p=b&&p.ownerDocument!=m.getDoc()?m.getBody():p;q.parents=[];m.dom.getParent(p,function(o){if(o.nodeName=="BODY"){return true}q.parents.push(o)});m.onNodeChange.dispatch(m,q?q.controlManager||m.controlManager:m.controlManager,p,n.isCollapsed(),q)}},addButton:function(n,o){var m=this;m.buttons=m.buttons||{};m.buttons[n]=o},addCommand:function(m,o,n){this.execCommands[m]={func:o,scope:n||this}},addQueryStateHandler:function(m,o,n){this.queryStateCommands[m]={func:o,scope:n||this}},addQueryValueHandler:function(m,o,n){this.queryValueCommands[m]={func:o,scope:n||this}},addShortcut:function(o,q,m,p){var n=this,r;if(n.settings.custom_shortcuts===false){return false}n.shortcuts=n.shortcuts||{};if(d(m,"string")){r=m;m=function(){n.execCommand(r,false,null)}}if(d(m,"object")){r=m;m=function(){n.execCommand(r[0],r[1],r[2])}}i(g(o),function(s){var t={func:m,scope:p||this,desc:n.translate(q),alt:false,ctrl:false,shift:false};i(g(s,"+"),function(u){switch(u){case"alt":case"ctrl":case"shift":t[u]=true;break;default:t.charCode=u.charCodeAt(0);t.keyCode=u.toUpperCase().charCodeAt(0)}});n.shortcuts[(t.ctrl?"ctrl":"")+","+(t.alt?"alt":"")+","+(t.shift?"shift":"")+","+t.keyCode]=t});return true},execCommand:function(u,r,x,m){var p=this,q=0,v,n;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(u)&&(!m||!m.skip_focus)){p.focus()}m=f({},m);p.onBeforeExecCommand.dispatch(p,u,r,x,m);if(m.terminate){return false}if(p.execCallback("execcommand_callback",p.id,p.selection.getNode(),u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(v=p.execCommands[u]){n=v.func.call(v.scope,r,x);if(n!==true){p.onExecCommand.dispatch(p,u,r,x,m);return n}}i(p.plugins,function(o){if(o.execCommand&&o.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);q=1;return false}});if(q){return true}if(p.theme&&p.theme.execCommand&&p.theme.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(p.editorCommands.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}p.getDoc().execCommand(u,r,x);p.onExecCommand.dispatch(p,u,r,x,m)},queryCommandState:function(q){var n=this,r,p;if(n._isHidden()){return}if(r=n.queryStateCommands[q]){p=r.func.call(r.scope);if(p!==true){return p}}r=n.editorCommands.queryCommandState(q);if(r!==-1){return r}try{return this.getDoc().queryCommandState(q)}catch(m){}},queryCommandValue:function(r){var n=this,q,p;if(n._isHidden()){return}if(q=n.queryValueCommands[r]){p=q.func.call(q.scope);if(p!==true){return p}}q=n.editorCommands.queryCommandValue(r);if(d(q)){return q}try{return this.getDoc().queryCommandValue(r)}catch(m){}},show:function(){var m=this;l.show(m.getContainer());l.hide(m.id);m.load()},hide:function(){var m=this,n=m.getDoc();if(b&&n){n.execCommand("SelectAll")}m.save();l.hide(m.getContainer());l.setStyle(m.id,"display",m.orgDisplay)},isHidden:function(){return !l.isHidden(this.id)},setProgressState:function(m,n,p){this.onSetProgressState.dispatch(this,m,n,p);return m},load:function(q){var m=this,p=m.getElement(),n;if(p){q=q||{};q.load=true;n=m.setContent(d(p.value)?p.value:p.innerHTML,q);q.element=p;if(!q.no_events){m.onLoadContent.dispatch(m,q)}q.element=p=null;return n}},save:function(r){var m=this,q=m.getElement(),n,p;if(!q||!m.initialized){return}r=r||{};r.save=true;r.element=q;n=r.content=m.getContent(r);if(!r.no_events){m.onSaveContent.dispatch(m,r)}n=r.content;if(!/TEXTAREA|INPUT/i.test(q.nodeName)){q.innerHTML=n;if(p=l.getParent(m.id,"form")){i(p.elements,function(o){if(o.name==m.id){o.value=n;return false}})}}else{q.value=n}r.element=q=null;return n},setContent:function(r,p){var o=this,n,m=o.getBody(),q;p=p||{};p.format=p.format||"html";p.set=true;p.content=r;if(!p.no_events){o.onBeforeSetContent.dispatch(o,p)}r=p.content;if(!k.isIE&&(r.length===0||/^\s+$/.test(r))){q=o.settings.forced_root_block;if(q){r="<"+q+'><br data-mce-bogus="1"></'+q+">"}else{r='<br data-mce-bogus="1">'}m.innerHTML=r;o.selection.select(m,true);o.selection.collapse(true);return}if(p.format!=="raw"){r=new k.html.Serializer({},o.schema).serialize(o.parser.parse(r))}p.content=k.trim(r);o.dom.setHTML(m,p.content);if(!p.no_events){o.onSetContent.dispatch(o,p)}if(!o.settings.content_editable||document.activeElement===o.getBody()){o.selection.normalize()}return p.content},getContent:function(o){var n=this,p,m=n.getBody();o=o||{};o.format=o.format||"html";o.get=true;o.getInner=true;if(!o.no_events){n.onBeforeGetContent.dispatch(n,o)}if(o.format=="raw"){p=m.innerHTML}else{if(o.format=="text"){p=m.innerText||m.textContent}else{p=n.serializer.serialize(m,o)}}if(o.format!="text"){o.content=k.trim(p)}else{o.content=p}if(!o.no_events){n.onGetContent.dispatch(n,o)}return o.content},isDirty:function(){var m=this;return k.trim(m.startContent)!=k.trim(m.getContent({format:"raw",no_events:1}))&&!m.isNotDirty},getContainer:function(){var m=this;if(!m.container){m.container=l.get(m.editorContainer||m.id+"_parent")}return m.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return l.get(this.settings.content_element||this.id)},getWin:function(){var m=this,n;if(!m.contentWindow){n=l.get(m.id+"_ifr");if(n){m.contentWindow=n.contentWindow}}return m.contentWindow},getDoc:function(){var m=this,n;if(!m.contentDocument){n=m.getWin();if(n){m.contentDocument=n.document}}return m.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(o,n,q){var m=this,p=m.settings;if(p.urlconverter_callback){return m.execCallback("urlconverter_callback",o,q,true,n)}if(!p.convert_urls||(q&&q.nodeName=="LINK")||o.indexOf("file:")===0){return o}if(p.relative_urls){return m.documentBaseURI.toRelative(o)}o=m.documentBaseURI.toAbsolute(o,p.remove_script_host);return o},addVisual:function(q){var n=this,o=n.settings,p=n.dom,m;q=q||n.getBody();if(!d(n.hasVisual)){n.hasVisual=o.visual}i(p.select("table,a",q),function(s){var r;switch(s.nodeName){case"TABLE":m=o.visual_table_class||"mceItemTable";r=p.getAttrib(s,"border");if(!r||r=="0"){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}return;case"A":if(!p.getAttrib(s,"href",false)){r=p.getAttrib(s,"name")||s.id;m="mceItemAnchor";if(r){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}}return}});n.onVisualAid.dispatch(n,q,n.hasVisual)},remove:function(){var m=this,o=m.getContainer(),n=m.getDoc();if(!m.removed){m.removed=1;if(b&&n){n.execCommand("SelectAll")}m.save();l.setStyle(m.id,"display",m.orgDisplay);if(!m.settings.content_editable){j.unbind(m.getWin());j.unbind(m.getDoc())}j.unbind(m.getBody());j.clear(o);m.execCallback("remove_instance_callback",m);m.onRemove.dispatch(m);m.onExecCommand.listeners=[];k.remove(m);l.remove(o)}},destroy:function(n){var m=this;if(m.destroyed){return}if(a){j.unbind(m.getDoc());j.unbind(m.getWin());j.unbind(m.getBody())}if(!n){k.removeUnload(m.destroy);tinyMCE.onBeforeUnload.remove(m._beforeUnload);if(m.theme&&m.theme.destroy){m.theme.destroy()}m.controlManager.destroy();m.selection.destroy();m.dom.destroy()}if(m.formElement){m.formElement.submit=m.formElement._mceOldSubmit;m.formElement._mceOldSubmit=null}m.contentAreaContainer=m.formElement=m.container=m.settings.content_element=m.bodyElement=m.contentDocument=m.contentWindow=null;if(m.selection){m.selection=m.selection.win=m.selection.dom=m.selection.dom.doc=null}m.destroyed=1},_refreshContentEditable:function(){var n=this,m,o;if(n._isHidden()){m=n.getBody();o=m.parentNode;o.removeChild(m);o.appendChild(m);m.focus()}},_isHidden:function(){var m;if(!a){return 0}m=this.selection.getSel();return(!m||!m.rangeCount||m.rangeCount===0)}})})(tinymce);(function(a){var b=a.each;a.Editor.prototype.setupEvents=function(){var c=this,d=c.settings;b(["onPreInit","onBeforeRenderUI","onPostRender","onLoad","onInit","onRemove","onActivate","onDeactivate","onClick","onEvent","onMouseUp","onMouseDown","onDblClick","onKeyDown","onKeyUp","onKeyPress","onContextMenu","onSubmit","onReset","onPaste","onPreProcess","onPostProcess","onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent","onLoadContent","onSaveContent","onNodeChange","onChange","onBeforeExecCommand","onExecCommand","onUndo","onRedo","onVisualAid","onSetProgressState","onSetAttrib"],function(e){c[e]=new a.util.Dispatcher(c)});if(d.cleanup_callback){c.onBeforeSetContent.add(function(e,f){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)});c.onPreProcess.add(function(e,f){if(f.set){e.execCallback("cleanup_callback","insert_to_editor_dom",f.node,f)}if(f.get){e.execCallback("cleanup_callback","get_from_editor_dom",f.node,f)}});c.onPostProcess.add(function(e,f){if(f.set){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)}if(f.get){f.content=e.execCallback("cleanup_callback","get_from_editor",f.content,f)}})}if(d.save_callback){c.onGetContent.add(function(e,f){if(f.save){f.content=e.execCallback("save_callback",e.id,f.content,e.getBody())}})}if(d.handle_event_callback){c.onEvent.add(function(f,g,h){if(c.execCallback("handle_event_callback",g,f,h)===false){g.preventDefault();g.stopPropagation()}})}if(d.handle_node_change_callback){c.onNodeChange.add(function(f,e,g){f.execCallback("handle_node_change_callback",f.id,g,-1,-1,true,f.selection.isCollapsed())})}if(d.save_callback){c.onSaveContent.add(function(e,g){var f=e.execCallback("save_callback",e.id,g.content,e.getBody());if(f){g.content=f}})}if(d.onchange_callback){c.onChange.add(function(f,e){f.execCallback("onchange_callback",f,e)})}};a.Editor.prototype.bindNativeEvents=function(){var l=this,f,d=l.settings,e=l.dom,h;h={mouseup:"onMouseUp",mousedown:"onMouseDown",click:"onClick",keyup:"onKeyUp",keydown:"onKeyDown",keypress:"onKeyPress",submit:"onSubmit",reset:"onReset",contextmenu:"onContextMenu",dblclick:"onDblClick",paste:"onPaste"};function c(i,m){var n=i.type;if(l.removed){return}if(l.onEvent.dispatch(l,i,m)!==false){l[h[i.fakeType||i.type]].dispatch(l,i,m)}}function j(i){l.focus(true)}function k(i,m){if(m.keyCode!=65||!a.VK.metaKeyPressed(m)){l.selection.normalize()}l.nodeChanged()}b(h,function(m,n){var i=d.content_editable?l.getBody():l.getDoc();switch(n){case"contextmenu":e.bind(i,n,c);break;case"paste":e.bind(l.getBody(),n,c);break;case"submit":case"reset":e.bind(l.getElement().form||a.DOM.getParent(l.id,"form"),n,c);break;default:e.bind(i,n,c)}});e.bind(d.content_editable?l.getBody():(a.isGecko?l.getDoc():l.getWin()),"focus",function(i){l.focus(true)});if(d.content_editable&&a.isOpera){e.bind(l.getBody(),"click",j);e.bind(l.getBody(),"keydown",j)}l.onMouseUp.add(k);l.onKeyUp.add(function(i,n){var m=n.keyCode;if((m>=33&&m<=36)||(m>=37&&m<=40)||m==13||m==45||m==46||m==8||(a.isMac&&(m==91||m==93))||n.ctrlKey){k(i,n)}});l.onReset.add(function(){l.setContent(l.startContent,{format:"raw"})});function g(m,i){if(m.altKey||m.ctrlKey||m.metaKey){b(l.shortcuts,function(n){var o=a.isMac?m.metaKey:m.ctrlKey;if(n.ctrl!=o||n.alt!=m.altKey||n.shift!=m.shiftKey){return}if(m.keyCode==n.keyCode||(m.charCode&&m.charCode==n.charCode)){m.preventDefault();if(i){n.func.call(n.scope)}return true}})}}l.onKeyUp.add(function(i,m){g(m)});l.onKeyPress.add(function(i,m){g(m)});l.onKeyDown.add(function(i,m){g(m,true)});if(a.isOpera){l.onClick.add(function(i,m){m.preventDefault()})}}})(tinymce);(function(d){var e=d.each,b,a=true,c=false;d.EditorCommands=function(n){var m=n.dom,p=n.selection,j={state:{},exec:{},value:{}},k=n.settings,q=n.formatter,o;function r(z,y,x){var v;z=z.toLowerCase();if(v=j.exec[z]){v(z,y,x);return a}return c}function l(x){var v;x=x.toLowerCase();if(v=j.state[x]){return v(x)}return -1}function h(x){var v;x=x.toLowerCase();if(v=j.value[x]){return v(x)}return c}function u(v,x){x=x||"exec";e(v,function(z,y){e(y.toLowerCase().split(","),function(A){j[x][A]=z})})}d.extend(this,{execCommand:r,queryCommandState:l,queryCommandValue:h,addCommands:u});function f(y,x,v){if(x===b){x=c}if(v===b){v=null}return n.getDoc().execCommand(y,x,v)}function t(v){return q.match(v)}function s(v,x){q.toggle(v,x?{value:x}:b)}function i(v){o=p.getBookmark(v)}function g(){p.moveToBookmark(o)}u({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){n.undoManager.add()},"Cut,Copy,Paste":function(z){var y=n.getDoc(),v;try{f(z)}catch(x){v=a}if(v||!y.queryCommandSupported(z)){if(d.isGecko){n.windowManager.confirm(n.getLang("clipboard_msg"),function(A){if(A){open("http://www.mozilla.org/editor/midasdemo/securityprefs.html","_blank")}})}else{n.windowManager.alert(n.getLang("clipboard_no_support"))}}},unlink:function(v){if(p.isCollapsed()){p.select(p.getNode())}f(v);p.collapse(c)},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(v){var x=v.substring(7);e("left,center,right,full".split(","),function(y){if(x!=y){q.remove("align"+y)}});s("align"+x);r("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(y){var v,x;f(y);v=m.getParent(p.getNode(),"ol,ul");if(v){x=v.parentNode;if(/^(H[1-6]|P|ADDRESS|PRE)$/.test(x.nodeName)){i();m.split(x,v);g()}}},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){s(v)},"ForeColor,HiliteColor,FontName":function(y,x,v){s(y,v)},FontSize:function(z,y,x){var v,A;if(x>=1&&x<=7){A=d.explode(k.font_size_style_values);v=d.explode(k.font_size_classes);if(v){x=v[x-1]||x}else{x=A[x-1]||x}}s(z,x)},RemoveFormat:function(v){q.remove(v)},mceBlockQuote:function(v){s("blockquote")},FormatBlock:function(y,x,v){return s(v||"p")},mceCleanup:function(){var v=p.getBookmark();n.setContent(n.getContent({cleanup:a}),{cleanup:a});p.moveToBookmark(v)},mceRemoveNode:function(z,y,x){var v=x||p.getNode();if(v!=n.getBody()){i();n.dom.remove(v,a);g()}},mceSelectNodeDepth:function(z,y,x){var v=0;m.getParent(p.getNode(),function(A){if(A.nodeType==1&&v++==x){p.select(A);return c}},n.getBody())},mceSelectNode:function(y,x,v){p.select(v)},mceInsertContent:function(B,I,K){var y,J,E,z,F,G,D,C,L,x,A,M,v,H;y=n.parser;J=new d.html.Serializer({},n.schema);v='<span id="mce_marker" data-mce-type="bookmark">\uFEFF</span>';G={content:K,format:"html"};p.onBeforeSetContent.dispatch(p,G);K=G.content;if(K.indexOf("{$caret}")==-1){K+="{$caret}"}K=K.replace(/\{\$caret\}/,v);if(!p.isCollapsed()){n.getDoc().execCommand("Delete",false,null)}E=p.getNode();G={context:E.nodeName.toLowerCase()};F=y.parse(K,G);A=F.lastChild;if(A.attr("id")=="mce_marker"){D=A;for(A=A.prev;A;A=A.walk(true)){if(A.type==3||!m.isBlock(A.name)){A.parent.insert(D,A,A.name==="br");break}}}if(!G.invalid){K=J.serialize(F);A=E.firstChild;M=E.lastChild;if(!A||(A===M&&A.nodeName==="BR")){m.setHTML(E,K)}else{p.setContent(K)}}else{p.setContent(v);E=p.getNode();z=n.getBody();if(E.nodeType==9){E=A=z}else{A=E}while(A!==z){E=A;A=A.parentNode}K=E==z?z.innerHTML:m.getOuterHTML(E);K=J.serialize(y.parse(K.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i,function(){return J.serialize(F)})));if(E==z){m.setHTML(z,K)}else{m.setOuterHTML(E,K)}}D=m.get("mce_marker");C=m.getRect(D);L=m.getViewPort(n.getWin());if((C.y+C.h>L.y+L.h||C.y<L.y)||(C.x>L.x+L.w||C.x<L.x)){H=d.isIE?n.getDoc().documentElement:n.getBody();H.scrollLeft=C.x;H.scrollTop=C.y-L.h+25}x=m.createRng();A=D.previousSibling;if(A&&A.nodeType==3){x.setStart(A,A.nodeValue.length)}else{x.setStartBefore(D);x.setEndBefore(D)}m.remove(D);p.setRng(x);p.onSetContent.dispatch(p,G);n.addVisual()},mceInsertRawHTML:function(y,x,v){p.setContent("tiny_mce_marker");n.setContent(n.getContent().replace(/tiny_mce_marker/g,function(){return v}))},mceToggleFormat:function(y,x,v){s(v)},mceSetContent:function(y,x,v){n.setContent(v)},"Indent,Outdent":function(z){var x,v,y;x=k.indentation;v=/[a-z%]+$/i.exec(x);x=parseInt(x);if(!l("InsertUnorderedList")&&!l("InsertOrderedList")){if(!k.forced_root_block&&!m.getParent(p.getNode(),m.isBlock)){q.apply("div")}e(p.getSelectedBlocks(),function(A){if(z=="outdent"){y=Math.max(0,parseInt(A.style.paddingLeft||0)-x);m.setStyle(A,"paddingLeft",y?y+v:"")}else{m.setStyle(A,"paddingLeft",(parseInt(A.style.paddingLeft||0)+x)+v)}})}else{f(z)}},mceRepaint:function(){var x;if(d.isGecko){try{i(a);if(p.getSel()){p.getSel().selectAllChildren(n.getBody())}p.collapse(a);g()}catch(v){}}},mceToggleFormat:function(y,x,v){q.toggle(v)},InsertHorizontalRule:function(){n.execCommand("mceInsertContent",false,"<hr />")},mceToggleVisualAid:function(){n.hasVisual=!n.hasVisual;n.addVisual()},mceReplaceContent:function(y,x,v){n.execCommand("mceInsertContent",false,v.replace(/\{\$selection\}/g,p.getContent({format:"text"})))},mceInsertLink:function(z,y,x){var v;if(typeof(x)=="string"){x={href:x}}v=m.getParent(p.getNode(),"a");x.href=x.href.replace(" ","%20");if(!v||!x.href){q.remove("link")}if(x.href){q.apply("link",x,v)}},selectAll:function(){var x=m.getRoot(),v=m.createRng();if(p.getRng().setStart){v.setStart(x,0);v.setEnd(x,x.childNodes.length);p.setRng(v)}else{f("SelectAll")}}});u({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(z){var x="align"+z.substring(7);var v=p.isCollapsed()?[m.getParent(p.getNode(),m.isBlock)]:p.getSelectedBlocks();var y=d.map(v,function(A){return !!q.matchNode(A,x)});return d.inArray(y,a)!==-1},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){return t(v)},mceBlockQuote:function(){return t("blockquote")},Outdent:function(){var v;if(k.inline_styles){if((v=m.getParent(p.getStart(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}if((v=m.getParent(p.getEnd(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}}return l("InsertUnorderedList")||l("InsertOrderedList")||(!k.inline_styles&&!!m.getParent(p.getNode(),"BLOCKQUOTE"))},"InsertUnorderedList,InsertOrderedList":function(x){var v=m.getParent(p.getNode(),"ul,ol");return v&&(x==="insertunorderedlist"&&v.tagName==="UL"||x==="insertorderedlist"&&v.tagName==="OL")}},"state");u({"FontSize,FontName":function(y){var x=0,v;if(v=m.getParent(p.getNode(),"span")){if(y=="fontsize"){x=v.style.fontSize}else{x=v.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()}}return x}},"value");u({Undo:function(){n.undoManager.undo()},Redo:function(){n.undoManager.redo()}})}})(tinymce);(function(b){var a=b.util.Dispatcher;b.UndoManager=function(h){var l,i=0,e=[],g,k,j,f;function c(){return b.trim(h.getContent({format:"raw",no_events:1}).replace(/<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>/g,""))}function d(){l.typing=false;l.add()}onBeforeAdd=new a(l);k=new a(l);j=new a(l);f=new a(l);k.add(function(m,n){if(m.hasUndo()){return h.onChange.dispatch(h,n,m)}});j.add(function(m,n){return h.onUndo.dispatch(h,n,m)});f.add(function(m,n){return h.onRedo.dispatch(h,n,m)});h.onInit.add(function(){l.add()});h.onBeforeExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.beforeChange()}});h.onExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.add()}});h.onSaveContent.add(d);h.dom.bind(h.dom.getRoot(),"dragend",d);h.dom.bind(h.getBody(),"focusout",function(m){if(!h.removed&&l.typing){d()}});h.onKeyUp.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45||n==13||o.ctrlKey){d()}});h.onKeyDown.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45){if(l.typing){d()}return}if((n<16||n>20)&&n!=224&&n!=91&&!l.typing){l.beforeChange();l.typing=true;l.add()}});h.onMouseDown.add(function(m,n){if(l.typing){d()}});h.addShortcut("ctrl+z","undo_desc","Undo");h.addShortcut("ctrl+y","redo_desc","Redo");l={data:e,typing:false,onBeforeAdd:onBeforeAdd,onAdd:k,onUndo:j,onRedo:f,beforeChange:function(){g=h.selection.getBookmark(2,true)},add:function(p){var m,n=h.settings,o;p=p||{};p.content=c();l.onBeforeAdd.dispatch(l,p);o=e[i];if(o&&o.content==p.content){return null}if(e[i]){e[i].beforeBookmark=g}if(n.custom_undo_redo_levels){if(e.length>n.custom_undo_redo_levels){for(m=0;m<e.length-1;m++){e[m]=e[m+1]}e.length--;i=e.length}}p.bookmark=h.selection.getBookmark(2,true);if(i<e.length-1){e.length=i+1}e.push(p);i=e.length-1;l.onAdd.dispatch(l,p);h.isNotDirty=0;return p},undo:function(){var n,m;if(l.typing){l.add();l.typing=false}if(i>0){n=e[--i];h.setContent(n.content,{format:"raw"});h.selection.moveToBookmark(n.beforeBookmark);l.onUndo.dispatch(l,n)}return n},redo:function(){var m;if(i<e.length-1){m=e[++i];h.setContent(m.content,{format:"raw"});h.selection.moveToBookmark(m.bookmark);l.onRedo.dispatch(l,m)}return m},clear:function(){e=[];i=0;l.typing=false},hasUndo:function(){return i>0||this.typing},hasRedo:function(){return i<e.length-1&&!this.typing}};return l}})(tinymce);tinymce.ForceBlocks=function(c){var b=c.settings,e=c.dom,a=c.selection,d=c.schema.getBlockElements();function f(){var j=a.getStart(),h=c.getBody(),g,k,o,s,q,i,l,m=-16777215,p,r;if(!j||j.nodeType!==1||!b.forced_root_block){return}while(j&&j!=h){if(d[j.nodeName]){return}j=j.parentNode}g=a.getRng();if(g.setStart){k=g.startContainer;o=g.startOffset;s=g.endContainer;q=g.endOffset}else{if(g.item){j=g.item(0);g=c.getDoc().body.createTextRange();g.moveToElementText(j)}r=g.parentElement().ownerDocument===c.getDoc();tmpRng=g.duplicate();tmpRng.collapse(true);o=tmpRng.move("character",m)*-1;if(!tmpRng.collapsed){tmpRng=g.duplicate();tmpRng.collapse(false);q=(tmpRng.move("character",m)*-1)-o}}j=h.firstChild;while(j){if(j.nodeType===3||(j.nodeType==1&&!d[j.nodeName])){if(j.nodeType===3&&j.nodeValue.length==0){l=j;j=j.nextSibling;e.remove(l);continue}if(!i){i=e.create(b.forced_root_block);j.parentNode.insertBefore(i,j);p=true}l=j;j=j.nextSibling;i.appendChild(l)}else{i=null;j=j.nextSibling}}if(p){if(g.setStart){g.setStart(k,o);g.setEnd(s,q);a.setRng(g)}else{if(r){try{g=c.getDoc().body.createTextRange();g.moveToElementText(h);g.collapse(true);g.moveStart("character",o);if(q>0){g.moveEnd("character",q)}g.select()}catch(n){}}}c.nodeChanged()}}if(b.forced_root_block){c.onKeyUp.add(f);c.onNodeChange.add(f)}};(function(c){var b=c.DOM,a=c.dom.Event,d=c.each,e=c.extend;c.create("tinymce.ControlManager",{ControlManager:function(f,j){var h=this,g;j=j||{};h.editor=f;h.controls={};h.onAdd=new c.util.Dispatcher(h);h.onPostRender=new c.util.Dispatcher(h);h.prefix=j.prefix||f.id+"_";h._cls={};h.onPostRender.add(function(){d(h.controls,function(i){i.postRender()})})},get:function(f){return this.controls[this.prefix+f]||this.controls[f]},setActive:function(h,f){var g=null;if(g=this.get(h)){g.setActive(f)}return g},setDisabled:function(h,f){var g=null;if(g=this.get(h)){g.setDisabled(f)}return g},add:function(g){var f=this;if(g){f.controls[g.id]=g;f.onAdd.dispatch(g,f)}return g},createControl:function(j){var o,k,g,h=this,m=h.editor,n,f;if(!h.controlFactories){h.controlFactories=[];d(m.plugins,function(i){if(i.createControl){h.controlFactories.push(i)}})}n=h.controlFactories;for(k=0,g=n.length;k<g;k++){o=n[k].createControl(j,h);if(o){return h.add(o)}}if(j==="|"||j==="separator"){return h.createSeparator()}if(m.buttons&&(o=m.buttons[j])){return h.createButton(j,o)}return h.add(o)},createDropMenu:function(f,n,h){var m=this,i=m.editor,j,g,k,l;n=e({"class":"mceDropDown",constrain:i.settings.constrain_menus},n);n["class"]=n["class"]+" "+i.getParam("skin")+"Skin";if(k=i.getParam("skin_variant")){n["class"]+=" "+i.getParam("skin")+"Skin"+k.substring(0,1).toUpperCase()+k.substring(1)}n["class"]+=i.settings.directionality=="rtl"?" mceRtl":"";f=m.prefix+f;l=h||m._cls.dropmenu||c.ui.DropMenu;j=m.controls[f]=new l(f,n);j.onAddItem.add(function(r,q){var p=q.settings;p.title=i.getLang(p.title,p.title);if(!p.onclick){p.onclick=function(o){if(p.cmd){i.execCommand(p.cmd,p.ui||false,p.value)}}}});i.onRemove.add(function(){j.destroy()});if(c.isIE){j.onShowMenu.add(function(){i.focus();g=i.selection.getBookmark(1)});j.onHideMenu.add(function(){if(g){i.selection.moveToBookmark(g);g=0}})}return m.add(j)},createListBox:function(f,n,h){var l=this,j=l.editor,i,k,m;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,scope:n.scope,control_manager:l},n);f=l.prefix+f;function g(o){return o.settings.use_accessible_selects&&!c.isGecko}if(j.settings.use_native_selects||g(j)){k=new c.ui.NativeListBox(f,n)}else{m=h||l._cls.listbox||c.ui.ListBox;k=new m(f,n,j)}l.controls[f]=k;if(c.isWebKit){k.onPostRender.add(function(p,o){a.add(o,"mousedown",function(){j.bookmark=j.selection.getBookmark(1)});a.add(o,"focus",function(){j.selection.moveToBookmark(j.bookmark);j.bookmark=null})})}if(k.hideMenu){j.onMouseDown.add(k.hideMenu,k)}return l.add(k)},createButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.label=g.translate(i.label);i.scope=i.scope||g;if(!i.onclick&&!i.menu_button){i.onclick=function(){g.execCommand(i.cmd,i.ui||false,i.value)}}i=e({title:i.title,"class":"mce_"+m,unavailable_prefix:g.getLang("unavailable",""),scope:i.scope,control_manager:h},i);m=h.prefix+m;if(i.menu_button){f=l||h._cls.menubutton||c.ui.MenuButton;k=new f(m,i,g);g.onMouseDown.add(k.hideMenu,k)}else{f=h._cls.button||c.ui.Button;k=new f(m,i,g)}return h.add(k)},createMenuButton:function(h,f,g){f=f||{};f.menu_button=1;return this.createButton(h,f,g)},createSplitButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.scope=i.scope||g;if(!i.onclick){i.onclick=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}if(!i.onselect){i.onselect=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}i=e({title:i.title,"class":"mce_"+m,scope:i.scope,control_manager:h},i);m=h.prefix+m;f=l||h._cls.splitbutton||c.ui.SplitButton;k=h.add(new f(m,i,g));g.onMouseDown.add(k.hideMenu,k);return k},createColorSplitButton:function(f,n,h){var l=this,j=l.editor,i,k,m,g;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onclick){n.onclick=function(o){if(c.isIE){g=j.selection.getBookmark(1)}j.execCommand(n.cmd,n.ui||false,o||n.value)}}if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,menu_class:j.getParam("skin")+"Skin",scope:n.scope,more_colors_title:j.getLang("more_colors")},n);f=l.prefix+f;m=h||l._cls.colorsplitbutton||c.ui.ColorSplitButton;k=new m(f,n,j);j.onMouseDown.add(k.hideMenu,k);j.onRemove.add(function(){k.destroy()});if(c.isIE){k.onShowMenu.add(function(){j.focus();g=j.selection.getBookmark(1)});k.onHideMenu.add(function(){if(g){j.selection.moveToBookmark(g);g=0}})}return l.add(k)},createToolbar:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||g._cls.toolbar||c.ui.Toolbar;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createToolbarGroup:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||this._cls.toolbarGroup||c.ui.ToolbarGroup;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createSeparator:function(g){var f=g||this._cls.separator||c.ui.Separator;return new f()},setControlType:function(g,f){return this._cls[g.toLowerCase()]=f},destroy:function(){d(this.controls,function(f){f.destroy()});this.controls=null}})})(tinymce);(function(d){var a=d.util.Dispatcher,e=d.each,c=d.isIE,b=d.isOpera;d.create("tinymce.WindowManager",{WindowManager:function(f){var g=this;g.editor=f;g.onOpen=new a(g);g.onClose=new a(g);g.params={};g.features={}},open:function(z,h){var v=this,k="",n,m,i=v.editor.settings.dialog_type=="modal",q,o,j,g=d.DOM.getViewPort(),r;z=z||{};h=h||{};o=b?g.w:screen.width;j=b?g.h:screen.height;z.name=z.name||"mc_"+new Date().getTime();z.width=parseInt(z.width||320);z.height=parseInt(z.height||240);z.resizable=true;z.left=z.left||parseInt(o/2)-(z.width/2);z.top=z.top||parseInt(j/2)-(z.height/2);h.inline=false;h.mce_width=z.width;h.mce_height=z.height;h.mce_auto_focus=z.auto_focus;if(i){if(c){z.center=true;z.help=false;z.dialogWidth=z.width+"px";z.dialogHeight=z.height+"px";z.scroll=z.scrollbars||false}}e(z,function(p,f){if(d.is(p,"boolean")){p=p?"yes":"no"}if(!/^(name|url)$/.test(f)){if(c&&i){k+=(k?";":"")+f+":"+p}else{k+=(k?",":"")+f+"="+p}}});v.features=z;v.params=h;v.onOpen.dispatch(v,z,h);r=z.url||z.file;r=d._addVer(r);try{if(c&&i){q=1;window.showModalDialog(r,window,k)}else{q=window.open(r,z.name,k)}}catch(l){}if(!q){alert(v.editor.getLang("popup_blocked"))}},close:function(f){f.close();this.onClose.dispatch(this)},createInstance:function(i,h,g,m,l,k){var j=d.resolve(i);return new j(h,g,m,l,k)},confirm:function(h,f,i,g){g=g||window;f.call(i||this,g.confirm(this._decode(this.editor.getLang(h,h))))},alert:function(h,f,j,g){var i=this;g=g||window;g.alert(i._decode(i.editor.getLang(h,h)));if(f){f.call(j||i)}},resizeBy:function(f,g,h){h.resizeBy(f,g)},_decode:function(f){return d.DOM.decode(f).replace(/\\n/g,"\n")}})}(tinymce));(function(a){a.Formatter=function(aa){var Q={},T=a.each,c=aa.dom,r=aa.selection,t=a.dom.TreeWalker,N=new a.dom.RangeUtils(c),d=aa.schema.isValidChild,A=a.isArray,H=c.isBlock,m=aa.settings.forced_root_block,s=c.nodeIndex,G="\uFEFF",e=/^(src|href|style)$/,X=false,C=true,P,D,x=c.getContentEditable;function I(ab){return !!aa.schema.getTextBlocks()[ab.toLowerCase()]}function n(ac,ab){return c.getParents(ac,ab,c.getRoot())}function b(ab){return ab.nodeType===1&&ab.id==="_mce_caret"}function j(){l({alignleft:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"left"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"center"},defaultBlock:"div"},{selector:"img",collapsed:false,styles:{display:"block",marginLeft:"auto",marginRight:"auto"}},{selector:"table",collapsed:false,styles:{marginLeft:"auto",marginRight:"auto"}}],alignright:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"right"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"right"}}],alignfull:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"justify"},defaultBlock:"div"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:true},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:true},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},wrap_links:false},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},wrap_links:false},fontname:{inline:"span",styles:{fontFamily:"%value"}},fontsize:{inline:"span",styles:{fontSize:"%value"}},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},link:{inline:"a",selector:"a",remove:"all",split:true,deep:true,onmatch:function(ab){return true},onformat:function(ad,ab,ac){T(ac,function(af,ae){c.setAttrib(ad,ae,af)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike",remove:"all",split:true,expand:false,block_expand:true,deep:true},{selector:"span",attributes:["style","class"],remove:"empty",split:true,expand:false,deep:true},{selector:"*",attributes:["style","class"],split:false,expand:false,deep:true}]});T("p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp".split(/\s/),function(ab){l(ab,{block:ab,remove:"all"})});l(aa.settings.formats)}function W(){aa.addShortcut("ctrl+b","bold_desc","Bold");aa.addShortcut("ctrl+i","italic_desc","Italic");aa.addShortcut("ctrl+u","underline_desc","Underline");for(var ab=1;ab<=6;ab++){aa.addShortcut("ctrl+"+ab,"",["FormatBlock",false,"h"+ab])}aa.addShortcut("ctrl+7","",["FormatBlock",false,"p"]);aa.addShortcut("ctrl+8","",["FormatBlock",false,"div"]);aa.addShortcut("ctrl+9","",["FormatBlock",false,"address"])}function V(ab){return ab?Q[ab]:Q}function l(ab,ac){if(ab){if(typeof(ab)!=="string"){T(ab,function(ae,ad){l(ad,ae)})}else{ac=ac.length?ac:[ac];T(ac,function(ad){if(ad.deep===D){ad.deep=!ad.selector}if(ad.split===D){ad.split=!ad.selector||ad.inline}if(ad.remove===D&&ad.selector&&!ad.inline){ad.remove="none"}if(ad.selector&&ad.inline){ad.mixed=true;ad.block_expand=true}if(typeof(ad.classes)==="string"){ad.classes=ad.classes.split(/\s+/)}});Q[ab]=ac}}}var i=function(ac){var ab;aa.dom.getParent(ac,function(ad){ab=aa.dom.getStyle(ad,"text-decoration");return ab&&ab!=="none"});return ab};var L=function(ab){var ac;if(ab.nodeType===1&&ab.parentNode&&ab.parentNode.nodeType===1){ac=i(ab.parentNode);if(aa.dom.getStyle(ab,"color")&&ac){aa.dom.setStyle(ab,"text-decoration",ac)}else{if(aa.dom.getStyle(ab,"textdecoration")===ac){aa.dom.setStyle(ab,"text-decoration",null)}}}};function Y(ae,al,ag){var ah=V(ae),am=ah[0],ak,ac,aj,ai=r.isCollapsed();function ab(aq,ap){ap=ap||am;if(aq){if(ap.onformat){ap.onformat(aq,ap,al,ag)}T(ap.styles,function(at,ar){c.setStyle(aq,ar,q(at,al))});T(ap.attributes,function(at,ar){c.setAttrib(aq,ar,q(at,al))});T(ap.classes,function(ar){ar=q(ar,al);if(!c.hasClass(aq,ar)){c.addClass(aq,ar)}})}}function af(){function ar(ay,aw){var ax=new t(aw);for(ag=ax.current();ag;ag=ax.prev()){if(ag.childNodes.length>1||ag==ay||ag.tagName=="BR"){return ag}}}var aq=aa.selection.getRng();var av=aq.startContainer;var ap=aq.endContainer;if(av!=ap&&aq.endOffset===0){var au=ar(av,ap);var at=au.nodeType==3?au.length:au.childNodes.length;aq.setEnd(au,at)}return aq}function ad(at,ay,aw,av,aq){var ap=[],ar=-1,ax,aA=-1,au=-1,az;T(at.childNodes,function(aC,aB){if(aC.nodeName==="UL"||aC.nodeName==="OL"){ar=aB;ax=aC;return false}});T(at.childNodes,function(aC,aB){if(aC.nodeName==="SPAN"&&c.getAttrib(aC,"data-mce-type")=="bookmark"){if(aC.id==ay.id+"_start"){aA=aB}else{if(aC.id==ay.id+"_end"){au=aB}}}});if(ar<=0||(aA<ar&&au>ar)){T(a.grep(at.childNodes),aq);return 0}else{az=c.clone(aw,X);T(a.grep(at.childNodes),function(aC,aB){if((aA<ar&&aB<ar)||(aA>ar&&aB>ar)){ap.push(aC);aC.parentNode.removeChild(aC)}});if(aA<ar){at.insertBefore(az,ax)}else{if(aA>ar){at.insertBefore(az,ax.nextSibling)}}av.push(az);T(ap,function(aB){az.appendChild(aB)});return az}}function an(aq,at,aw){var ap=[],av,ar,au=true;av=am.inline||am.block;ar=c.create(av);ab(ar);N.walk(aq,function(ax){var ay;function az(aA){var aF,aD,aB,aC,aE;aE=au;aF=aA.nodeName.toLowerCase();aD=aA.parentNode.nodeName.toLowerCase();if(aA.nodeType===1&&x(aA)){aE=au;au=x(aA)==="true";aC=true}if(g(aF,"br")){ay=0;if(am.block){c.remove(aA)}return}if(am.wrapper&&y(aA,ae,al)){ay=0;return}if(au&&!aC&&am.block&&!am.wrapper&&I(aF)){aA=c.rename(aA,av);ab(aA);ap.push(aA);ay=0;return}if(am.selector){T(ah,function(aG){if("collapsed" in aG&&aG.collapsed!==ai){return}if(c.is(aA,aG.selector)&&!b(aA)){ab(aA,aG);aB=true}});if(!am.inline||aB){ay=0;return}}if(au&&!aC&&d(av,aF)&&d(aD,av)&&!(!aw&&aA.nodeType===3&&aA.nodeValue.length===1&&aA.nodeValue.charCodeAt(0)===65279)&&!b(aA)&&(!am.inline||!H(aA))){if(!ay){ay=c.clone(ar,X);aA.parentNode.insertBefore(ay,aA);ap.push(ay)}ay.appendChild(aA)}else{if(aF=="li"&&at){ay=ad(aA,at,ar,ap,az)}else{ay=0;T(a.grep(aA.childNodes),az);if(aC){au=aE}ay=0}}}T(ax,az)});if(am.wrap_links===false){T(ap,function(ax){function ay(aC){var aB,aA,az;if(aC.nodeName==="A"){aA=c.clone(ar,X);ap.push(aA);az=a.grep(aC.childNodes);for(aB=0;aB<az.length;aB++){aA.appendChild(az[aB])}aC.appendChild(aA)}T(a.grep(aC.childNodes),ay)}ay(ax)})}T(ap,function(az){var ax;function aA(aC){var aB=0;T(aC.childNodes,function(aD){if(!f(aD)&&!K(aD)){aB++}});return aB}function ay(aB){var aD,aC;T(aB.childNodes,function(aE){if(aE.nodeType==1&&!K(aE)&&!b(aE)){aD=aE;return X}});if(aD&&h(aD,am)){aC=c.clone(aD,X);ab(aC);c.replace(aC,aB,C);c.remove(aD,1)}return aC||aB}ax=aA(az);if((ap.length>1||!H(az))&&ax===0){c.remove(az,1);return}if(am.inline||am.wrapper){if(!am.exact&&ax===1){az=ay(az)}T(ah,function(aB){T(c.select(aB.inline,az),function(aD){var aC;if(aB.wrap_links===false){aC=aD.parentNode;do{if(aC.nodeName==="A"){return}}while(aC=aC.parentNode)}Z(aB,al,aD,aB.exact?aD:null)})});if(y(az.parentNode,ae,al)){c.remove(az,1);az=0;return C}if(am.merge_with_parents){c.getParent(az.parentNode,function(aB){if(y(aB,ae,al)){c.remove(az,1);az=0;return C}})}if(az&&am.merge_siblings!==false){az=u(E(az),az);az=u(az,E(az,C))}}})}if(am){if(ag){if(ag.nodeType){ac=c.createRng();ac.setStartBefore(ag);ac.setEndAfter(ag);an(p(ac,ah),null,true)}else{an(ag,null,true)}}else{if(!ai||!am.inline||c.select("td.mceSelected,th.mceSelected").length){var ao=aa.selection.getNode();if(!m&&ah[0].defaultBlock&&!c.getParent(ao,c.isBlock)){Y(ah[0].defaultBlock)}aa.selection.setRng(af());ak=r.getBookmark();an(p(r.getRng(C),ah),ak);if(am.styles&&(am.styles.color||am.styles.textDecoration)){a.walk(ao,L,"childNodes");L(ao)}r.moveToBookmark(ak);R(r.getRng(C));aa.nodeChanged()}else{U("apply",ae,al)}}}}function B(ad,am,af){var ag=V(ad),ao=ag[0],ak,aj,ac,al=true;function ae(av){var au,at,ar,aq,ax,aw;if(av.nodeType===3){return}if(av.nodeType===1&&x(av)){ax=al;al=x(av)==="true";aw=true}au=a.grep(av.childNodes);if(al&&!aw){for(at=0,ar=ag.length;at<ar;at++){if(Z(ag[at],am,av,av)){break}}}if(ao.deep){if(au.length){for(at=0,ar=au.length;at<ar;at++){ae(au[at])}if(aw){al=ax}}}}function ah(aq){var ar;T(n(aq.parentNode).reverse(),function(at){var au;if(!ar&&at.id!="_start"&&at.id!="_end"){au=y(at,ad,am);if(au&&au.split!==false){ar=at}}});return ar}function ab(au,aq,aw,az){var aA,ay,ax,at,av,ar;if(au){ar=au.parentNode;for(aA=aq.parentNode;aA&&aA!=ar;aA=aA.parentNode){ay=c.clone(aA,X);for(av=0;av<ag.length;av++){if(Z(ag[av],am,ay,ay)){ay=0;break}}if(ay){if(ax){ay.appendChild(ax)}if(!at){at=ay}ax=ay}}if(az&&(!ao.mixed||!H(au))){aq=c.split(au,aq)}if(ax){aw.parentNode.insertBefore(ax,aw);at.appendChild(aw)}}return aq}function an(aq){return ab(ah(aq),aq,aq,true)}function ai(at){var ar=c.get(at?"_start":"_end"),aq=ar[at?"firstChild":"lastChild"];if(K(aq)){aq=aq[at?"firstChild":"lastChild"]}c.remove(ar,true);return aq}function ap(aq){var at,au,ar;aq=p(aq,ag,C);if(ao.split){at=M(aq,C);au=M(aq);if(at!=au){if(/^(TR|TD)$/.test(at.nodeName)&&at.firstChild){at=(at.nodeName=="TD"?at.firstChild:at.firstChild.firstChild)||at}at=S(at,"span",{id:"_start","data-mce-type":"bookmark"});au=S(au,"span",{id:"_end","data-mce-type":"bookmark"});an(at);an(au);at=ai(C);au=ai()}else{at=au=an(at)}aq.startContainer=at.parentNode;aq.startOffset=s(at);aq.endContainer=au.parentNode;aq.endOffset=s(au)+1}N.walk(aq,function(av){T(av,function(aw){ae(aw);if(aw.nodeType===1&&aa.dom.getStyle(aw,"text-decoration")==="underline"&&aw.parentNode&&i(aw.parentNode)==="underline"){Z({deep:false,exact:true,inline:"span",styles:{textDecoration:"underline"}},null,aw)}})})}if(af){if(af.nodeType){ac=c.createRng();ac.setStartBefore(af);ac.setEndAfter(af);ap(ac)}else{ap(af)}return}if(!r.isCollapsed()||!ao.inline||c.select("td.mceSelected,th.mceSelected").length){ak=r.getBookmark();ap(r.getRng(C));r.moveToBookmark(ak);if(ao.inline&&k(ad,am,r.getStart())){R(r.getRng(true))}aa.nodeChanged()}else{U("remove",ad,am)}}function F(ac,ae,ad){var ab=V(ac);if(k(ac,ae,ad)&&(!("toggle" in ab[0])||ab[0].toggle)){B(ac,ae,ad)}else{Y(ac,ae,ad)}}function y(ac,ab,ah,af){var ad=V(ab),ai,ag,ae;function aj(an,ap,aq){var am,ao,ak=ap[aq],al;if(ap.onmatch){return ap.onmatch(an,ap,aq)}if(ak){if(ak.length===D){for(am in ak){if(ak.hasOwnProperty(am)){if(aq==="attributes"){ao=c.getAttrib(an,am)}else{ao=O(an,am)}if(af&&!ao&&!ap.exact){return}if((!af||ap.exact)&&!g(ao,q(ak[am],ah))){return}}}}else{for(al=0;al<ak.length;al++){if(aq==="attributes"?c.getAttrib(an,ak[al]):O(an,ak[al])){return ap}}}}return ap}if(ad&&ac){for(ag=0;ag<ad.length;ag++){ai=ad[ag];if(h(ac,ai)&&aj(ac,ai,"attributes")&&aj(ac,ai,"styles")){if(ae=ai.classes){for(ag=0;ag<ae.length;ag++){if(!c.hasClass(ac,ae[ag])){return}}}return ai}}}}function k(ad,af,ae){var ac;function ab(ag){ag=c.getParent(ag,function(ah){return !!y(ah,ad,af,true)});return y(ag,ad,af)}if(ae){return ab(ae)}ae=r.getNode();if(ab(ae)){return C}ac=r.getStart();if(ac!=ae){if(ab(ac)){return C}}return X}function v(ai,ah){var af,ag=[],ae={},ad,ac,ab;af=r.getStart();c.getParent(af,function(al){var ak,aj;for(ak=0;ak<ai.length;ak++){aj=ai[ak];if(!ae[aj]&&y(al,aj,ah)){ae[aj]=true;ag.push(aj)}}},c.getRoot());return ag}function z(af){var ah=V(af),ae,ad,ag,ac,ab;if(ah){ae=r.getStart();ad=n(ae);for(ac=ah.length-1;ac>=0;ac--){ab=ah[ac].selector;if(!ab){return C}for(ag=ad.length-1;ag>=0;ag--){if(c.is(ad[ag],ab)){return C}}}}return X}function J(ab,ae,ac){var ad;if(!P){P={};ad={};aa.onNodeChange.addToTop(function(ag,af,ai){var ah=n(ai),aj={};T(P,function(ak,al){T(ah,function(am){if(y(am,al,{},ak.similar)){if(!ad[al]){T(ak,function(an){an(true,{node:am,format:al,parents:ah})});ad[al]=ak}aj[al]=ak;return false}})});T(ad,function(ak,al){if(!aj[al]){delete ad[al];T(ak,function(am){am(false,{node:ai,format:al,parents:ah})})}})})}T(ab.split(","),function(af){if(!P[af]){P[af]=[];P[af].similar=ac}P[af].push(ae)});return this}a.extend(this,{get:V,register:l,apply:Y,remove:B,toggle:F,match:k,matchAll:v,matchNode:y,canApply:z,formatChanged:J});j();W();function h(ab,ac){if(g(ab,ac.inline)){return C}if(g(ab,ac.block)){return C}if(ac.selector){return c.is(ab,ac.selector)}}function g(ac,ab){ac=ac||"";ab=ab||"";ac=""+(ac.nodeName||ac);ab=""+(ab.nodeName||ab);return ac.toLowerCase()==ab.toLowerCase()}function O(ac,ab){var ad=c.getStyle(ac,ab);if(ab=="color"||ab=="backgroundColor"){ad=c.toHex(ad)}if(ab=="fontWeight"&&ad==700){ad="bold"}return""+ad}function q(ab,ac){if(typeof(ab)!="string"){ab=ab(ac)}else{if(ac){ab=ab.replace(/%(\w+)/g,function(ae,ad){return ac[ad]||ae})}}return ab}function f(ab){return ab&&ab.nodeType===3&&/^([\t \r\n]+|)$/.test(ab.nodeValue)}function S(ad,ac,ab){var ae=c.create(ac,ab);ad.parentNode.insertBefore(ae,ad);ae.appendChild(ad);return ae}function p(ab,am,ae){var ap,an,ah,al,ad=ab.startContainer,ai=ab.startOffset,ar=ab.endContainer,ak=ab.endOffset;function ao(aA){var au,ax,az,aw,av,at;au=ax=aA?ad:ar;av=aA?"previousSibling":"nextSibling";at=c.getRoot();function ay(aB){return aB.nodeName=="BR"&&aB.getAttribute("data-mce-bogus")&&!aB.nextSibling}if(au.nodeType==3&&!f(au)){if(aA?ai>0:ak<au.nodeValue.length){return au}}for(;;){if(!am[0].block_expand&&H(ax)){return ax}for(aw=ax[av];aw;aw=aw[av]){if(!K(aw)&&!f(aw)&&!ay(aw)){return ax}}if(ax.parentNode==at){au=ax;break}ax=ax.parentNode}return au}function ag(at,au){if(au===D){au=at.nodeType===3?at.length:at.childNodes.length}while(at&&at.hasChildNodes()){at=at.childNodes[au];if(at){au=at.nodeType===3?at.length:at.childNodes.length}}return{node:at,offset:au}}if(ad.nodeType==1&&ad.hasChildNodes()){an=ad.childNodes.length-1;ad=ad.childNodes[ai>an?an:ai];if(ad.nodeType==3){ai=0}}if(ar.nodeType==1&&ar.hasChildNodes()){an=ar.childNodes.length-1;ar=ar.childNodes[ak>an?an:ak-1];if(ar.nodeType==3){ak=ar.nodeValue.length}}function aq(au){var at=au;while(at){if(at.nodeType===1&&x(at)){return x(at)==="false"?at:au}at=at.parentNode}return au}function aj(au,ay,aA){var ax,av,az,at;function aw(aC,aE){var aF,aB,aD=aC.nodeValue;if(typeof(aE)=="undefined"){aE=aA?aD.length:0}if(aA){aF=aD.lastIndexOf(" ",aE);aB=aD.lastIndexOf("\u00a0",aE);aF=aF>aB?aF:aB;if(aF!==-1&&!ae){aF++}}else{aF=aD.indexOf(" ",aE);aB=aD.indexOf("\u00a0",aE);aF=aF!==-1&&(aB===-1||aF<aB)?aF:aB}return aF}if(au.nodeType===3){az=aw(au,ay);if(az!==-1){return{container:au,offset:az}}at=au}ax=new t(au,c.getParent(au,H)||aa.getBody());while(av=ax[aA?"prev":"next"]()){if(av.nodeType===3){at=av;az=aw(av);if(az!==-1){return{container:av,offset:az}}}else{if(H(av)){break}}}if(at){if(aA){ay=0}else{ay=at.length}return{container:at,offset:ay}}}function af(au,at){var av,aw,ay,ax;if(au.nodeType==3&&au.nodeValue.length===0&&au[at]){au=au[at]}av=n(au);for(aw=0;aw<av.length;aw++){for(ay=0;ay<am.length;ay++){ax=am[ay];if("collapsed" in ax&&ax.collapsed!==ab.collapsed){continue}if(c.is(av[aw],ax.selector)){return av[aw]}}}return au}function ac(au,at,aw){var av;if(!am[0].wrapper){av=c.getParent(au,am[0].block)}if(!av){av=c.getParent(au.nodeType==3?au.parentNode:au,I)}if(av&&am[0].wrapper){av=n(av,"ul,ol").reverse()[0]||av}if(!av){av=au;while(av[at]&&!H(av[at])){av=av[at];if(g(av,"br")){break}}}return av||au}ad=aq(ad);ar=aq(ar);if(K(ad.parentNode)||K(ad)){ad=K(ad)?ad:ad.parentNode;ad=ad.nextSibling||ad;if(ad.nodeType==3){ai=0}}if(K(ar.parentNode)||K(ar)){ar=K(ar)?ar:ar.parentNode;ar=ar.previousSibling||ar;if(ar.nodeType==3){ak=ar.length}}if(am[0].inline){if(ab.collapsed){al=aj(ad,ai,true);if(al){ad=al.container;ai=al.offset}al=aj(ar,ak);if(al){ar=al.container;ak=al.offset}}ah=ag(ar,ak);if(ah.node){while(ah.node&&ah.offset===0&&ah.node.previousSibling){ah=ag(ah.node.previousSibling)}if(ah.node&&ah.offset>0&&ah.node.nodeType===3&&ah.node.nodeValue.charAt(ah.offset-1)===" "){if(ah.offset>1){ar=ah.node;ar.splitText(ah.offset-1)}}}}if(am[0].inline||am[0].block_expand){if(!am[0].inline||(ad.nodeType!=3||ai===0)){ad=ao(true)}if(!am[0].inline||(ar.nodeType!=3||ak===ar.nodeValue.length)){ar=ao()}}if(am[0].selector&&am[0].expand!==X&&!am[0].inline){ad=af(ad,"previousSibling");ar=af(ar,"nextSibling")}if(am[0].block||am[0].selector){ad=ac(ad,"previousSibling");ar=ac(ar,"nextSibling");if(am[0].block){if(!H(ad)){ad=ao(true)}if(!H(ar)){ar=ao()}}}if(ad.nodeType==1){ai=s(ad);ad=ad.parentNode}if(ar.nodeType==1){ak=s(ar)+1;ar=ar.parentNode}return{startContainer:ad,startOffset:ai,endContainer:ar,endOffset:ak}}function Z(ah,ag,ae,ab){var ad,ac,af;if(!h(ae,ah)){return X}if(ah.remove!="all"){T(ah.styles,function(aj,ai){aj=q(aj,ag);if(typeof(ai)==="number"){ai=aj;ab=0}if(!ab||g(O(ab,ai),aj)){c.setStyle(ae,ai,"")}af=1});if(af&&c.getAttrib(ae,"style")==""){ae.removeAttribute("style");ae.removeAttribute("data-mce-style")}T(ah.attributes,function(ak,ai){var aj;ak=q(ak,ag);if(typeof(ai)==="number"){ai=ak;ab=0}if(!ab||g(c.getAttrib(ab,ai),ak)){if(ai=="class"){ak=c.getAttrib(ae,ai);if(ak){aj="";T(ak.split(/\s+/),function(al){if(/mce\w+/.test(al)){aj+=(aj?" ":"")+al}});if(aj){c.setAttrib(ae,ai,aj);return}}}if(ai=="class"){ae.removeAttribute("className")}if(e.test(ai)){ae.removeAttribute("data-mce-"+ai)}ae.removeAttribute(ai)}});T(ah.classes,function(ai){ai=q(ai,ag);if(!ab||c.hasClass(ab,ai)){c.removeClass(ae,ai)}});ac=c.getAttribs(ae);for(ad=0;ad<ac.length;ad++){if(ac[ad].nodeName.indexOf("_")!==0){return X}}}if(ah.remove!="none"){o(ae,ah);return C}}function o(ad,ae){var ab=ad.parentNode,ac;function af(ah,ag,ai){ah=E(ah,ag,ai);return !ah||(ah.nodeName=="BR"||H(ah))}if(ae.block){if(!m){if(H(ad)&&!H(ab)){if(!af(ad,X)&&!af(ad.firstChild,C,1)){ad.insertBefore(c.create("br"),ad.firstChild)}if(!af(ad,C)&&!af(ad.lastChild,X,1)){ad.appendChild(c.create("br"))}}}else{if(ab==c.getRoot()){if(!ae.list_block||!g(ad,ae.list_block)){T(a.grep(ad.childNodes),function(ag){if(d(m,ag.nodeName.toLowerCase())){if(!ac){ac=S(ag,m)}else{ac.appendChild(ag)}}else{ac=0}})}}}}if(ae.selector&&ae.inline&&!g(ae.inline,ad)){return}c.remove(ad,1)}function E(ac,ab,ad){if(ac){ab=ab?"nextSibling":"previousSibling";for(ac=ad?ac:ac[ab];ac;ac=ac[ab]){if(ac.nodeType==1||!f(ac)){return ac}}}}function K(ab){return ab&&ab.nodeType==1&&ab.getAttribute("data-mce-type")=="bookmark"}function u(af,ae){var ab,ad,ac;function ah(ak,aj){if(ak.nodeName!=aj.nodeName){return X}function ai(am){var an={};T(c.getAttribs(am),function(ao){var ap=ao.nodeName.toLowerCase();if(ap.indexOf("_")!==0&&ap!=="style"){an[ap]=c.getAttrib(am,ap)}});return an}function al(ap,ao){var an,am;for(am in ap){if(ap.hasOwnProperty(am)){an=ao[am];if(an===D){return X}if(ap[am]!=an){return X}delete ao[am]}}for(am in ao){if(ao.hasOwnProperty(am)){return X}}return C}if(!al(ai(ak),ai(aj))){return X}if(!al(c.parseStyle(c.getAttrib(ak,"style")),c.parseStyle(c.getAttrib(aj,"style")))){return X}return C}function ag(aj,ai){for(ad=aj;ad;ad=ad[ai]){if(ad.nodeType==3&&ad.nodeValue.length!==0){return aj}if(ad.nodeType==1&&!K(ad)){return ad}}return aj}if(af&&ae){af=ag(af,"previousSibling");ae=ag(ae,"nextSibling");if(ah(af,ae)){for(ad=af.nextSibling;ad&&ad!=ae;){ac=ad;ad=ad.nextSibling;af.appendChild(ac)}c.remove(ae);T(a.grep(ae.childNodes),function(ai){af.appendChild(ai)});return af}}return ae}function I(ab){return/^(h[1-6]|p|div|pre|address|dl|dt|dd)$/.test(ab)}function M(ac,ag){var ab,af,ad,ae;ab=ac[ag?"startContainer":"endContainer"];af=ac[ag?"startOffset":"endOffset"];if(ab.nodeType==1){ad=ab.childNodes.length-1;if(!ag&&af){af--}ab=ab.childNodes[af>ad?ad:af]}if(ab.nodeType===3&&ag&&af>=ab.nodeValue.length){ab=new t(ab,aa.getBody()).next()||ab}if(ab.nodeType===3&&!ag&&af===0){ab=new t(ab,aa.getBody()).prev()||ab}return ab}function U(ak,ab,ai){var al="_mce_caret",ac=aa.settings.caret_debug;function ad(ap){var ao=c.create("span",{id:al,"data-mce-bogus":true,style:ac?"color:red":""});if(ap){ao.appendChild(aa.getDoc().createTextNode(G))}return ao}function aj(ap,ao){while(ap){if((ap.nodeType===3&&ap.nodeValue!==G)||ap.childNodes.length>1){return false}if(ao&&ap.nodeType===1){ao.push(ap)}ap=ap.firstChild}return true}function ag(ao){while(ao){if(ao.id===al){return ao}ao=ao.parentNode}}function af(ao){var ap;if(ao){ap=new t(ao,ao);for(ao=ap.current();ao;ao=ap.next()){if(ao.nodeType===3){return ao}}}}function ae(aq,ap){var ar,ao;if(!aq){aq=ag(r.getStart());if(!aq){while(aq=c.get(al)){ae(aq,false)}}}else{ao=r.getRng(true);if(aj(aq)){if(ap!==false){ao.setStartBefore(aq);ao.setEndBefore(aq)}c.remove(aq)}else{ar=af(aq);if(ar.nodeValue.charAt(0)===G){ar=ar.deleteData(0,1)}c.remove(aq,1)}r.setRng(ao)}}function ah(){var aq,ao,av,au,ar,ap,at;aq=r.getRng(true);au=aq.startOffset;ap=aq.startContainer;at=ap.nodeValue;ao=ag(r.getStart());if(ao){av=af(ao)}if(at&&au>0&&au<at.length&&/\w/.test(at.charAt(au))&&/\w/.test(at.charAt(au-1))){ar=r.getBookmark();aq.collapse(true);aq=p(aq,V(ab));aq=N.split(aq);Y(ab,ai,aq);r.moveToBookmark(ar)}else{if(!ao||av.nodeValue!==G){ao=ad(true);av=ao.firstChild;aq.insertNode(ao);au=1;Y(ab,ai,ao)}else{Y(ab,ai,ao)}r.setCursorLocation(av,au)}}function am(){var ao=r.getRng(true),ap,ar,av,au,aq,ay,ax=[],at,aw;ap=ao.startContainer;ar=ao.startOffset;aq=ap;if(ap.nodeType==3){if(ar!=ap.nodeValue.length||ap.nodeValue===G){au=true}aq=aq.parentNode}while(aq){if(y(aq,ab,ai)){ay=aq;break}if(aq.nextSibling){au=true}ax.push(aq);aq=aq.parentNode}if(!ay){return}if(au){av=r.getBookmark();ao.collapse(true);ao=p(ao,V(ab),true);ao=N.split(ao);B(ab,ai,ao);r.moveToBookmark(av)}else{aw=ad();aq=aw;for(at=ax.length-1;at>=0;at--){aq.appendChild(c.clone(ax[at],false));aq=aq.firstChild}aq.appendChild(c.doc.createTextNode(G));aq=aq.firstChild;c.insertAfter(aw,ay);r.setCursorLocation(aq,1)}}function an(){var ap,ao,aq;ao=ag(r.getStart());if(ao&&!c.isEmpty(ao)){a.walk(ao,function(ar){if(ar.nodeType==1&&ar.id!==al&&!c.isEmpty(ar)){c.setAttrib(ar,"data-mce-bogus",null)}},"childNodes")}}if(!self._hasCaretEvents){aa.onBeforeGetContent.addToTop(function(){var ao=[],ap;if(aj(ag(r.getStart()),ao)){ap=ao.length;while(ap--){c.setAttrib(ao[ap],"data-mce-bogus","1")}}});a.each("onMouseUp onKeyUp".split(" "),function(ao){aa[ao].addToTop(function(){ae();an()})});aa.onKeyDown.addToTop(function(ao,aq){var ap=aq.keyCode;if(ap==8||ap==37||ap==39){ae(ag(r.getStart()))}an()});r.onSetContent.add(an);self._hasCaretEvents=true}if(ak=="apply"){ah()}else{am()}}function R(ac){var ab=ac.startContainer,ai=ac.startOffset,ae,ah,ag,ad,af;if(ab.nodeType==3&&ai>=ab.nodeValue.length){ai=s(ab);ab=ab.parentNode;ae=true}if(ab.nodeType==1){ad=ab.childNodes;ab=ad[Math.min(ai,ad.length-1)];ah=new t(ab,c.getParent(ab,c.isBlock));if(ai>ad.length-1||ae){ah.next()}for(ag=ah.current();ag;ag=ah.next()){if(ag.nodeType==3&&!f(ag)){af=c.create("a",null,G);ag.parentNode.insertBefore(af,ag);ac.setStart(ag,0);r.setRng(ac);c.remove(af);return}}}}}})(tinymce);tinymce.onAddEditor.add(function(e,a){var d,h,g,c=a.settings;function b(j,i){e.each(i,function(l,k){if(l){g.setStyle(j,k,l)}});g.rename(j,"span")}function f(i,j){g=i.dom;if(c.convert_fonts_to_spans){e.each(g.select("font,u,strike",j.node),function(k){d[k.nodeName.toLowerCase()](a.dom,k)})}}if(c.inline_styles){h=e.explode(c.font_size_legacy_values);d={font:function(j,i){b(i,{backgroundColor:i.style.backgroundColor,color:i.color,fontFamily:i.face,fontSize:h[parseInt(i.size,10)-1]})},u:function(j,i){b(i,{textDecoration:"underline"})},strike:function(j,i){b(i,{textDecoration:"line-through"})}};a.onPreProcess.add(f);a.onSetContent.add(f);a.onInit.add(function(){a.selection.onSetContent.add(f)})}});(function(b){var a=b.dom.TreeWalker;b.EnterKey=function(f){var i=f.dom,e=f.selection,d=f.settings,h=f.undoManager,c=f.schema.getNonEmptyElements();function g(B){var v=e.getRng(true),G,j,A,u,p,M,C,o,k,n,t,J,x,D;function E(N){return N&&i.isBlock(N)&&!/^(TD|TH|CAPTION|FORM)$/.test(N.nodeName)&&!/^(fixed|absolute)/i.test(N.style.position)&&i.getContentEditable(N)!=="true"}function F(O){var N;if(b.isIE&&i.isBlock(O)){N=e.getRng();O.appendChild(i.create("span",null,"\u00a0"));e.select(O);O.lastChild.outerHTML="";e.setRng(N)}}function z(P){var O=P,Q=[],N;while(O=O.firstChild){if(i.isBlock(O)){return}if(O.nodeType==1&&!c[O.nodeName.toLowerCase()]){Q.push(O)}}N=Q.length;while(N--){O=Q[N];if(!O.hasChildNodes()||(O.firstChild==O.lastChild&&O.firstChild.nodeValue==="")){i.remove(O)}else{if(O.nodeName=="A"&&(O.innerText||O.textContent)===" "){i.remove(O)}}}}function m(O){var T,R,N,U,S,Q=O,P;N=i.createRng();if(O.hasChildNodes()){T=new a(O,O);while(R=T.current()){if(R.nodeType==3){N.setStart(R,0);N.setEnd(R,0);break}if(c[R.nodeName.toLowerCase()]){N.setStartBefore(R);N.setEndBefore(R);break}Q=R;R=T.next()}if(!R){N.setStart(Q,0);N.setEnd(Q,0)}}else{if(O.nodeName=="BR"){if(O.nextSibling&&i.isBlock(O.nextSibling)){if(!M||M<9){P=i.create("br");O.parentNode.insertBefore(P,O)}N.setStartBefore(O);N.setEndBefore(O)}else{N.setStartAfter(O);N.setEndAfter(O)}}else{N.setStart(O,0);N.setEnd(O,0)}}e.setRng(N);i.remove(P);S=i.getViewPort(f.getWin());U=i.getPos(O).y;if(U<S.y||U+25>S.y+S.h){f.getWin().scrollTo(0,U<S.y?U:U-S.h+25)}}function r(O){var P=A,R,Q,N;R=O||t=="TABLE"?i.create(O||x):p.cloneNode(false);N=R;if(d.keep_styles!==false){do{if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(P.nodeName)){if(P.id=="_mce_caret"){continue}Q=P.cloneNode(false);i.setAttrib(Q,"id","");if(R.hasChildNodes()){Q.appendChild(R.firstChild);R.appendChild(Q)}else{N=Q;R.appendChild(Q)}}}while(P=P.parentNode)}if(!b.isIE){N.innerHTML='<br data-mce-bogus="1">'}return R}function q(Q){var P,O,N;if(A.nodeType==3&&(Q?u>0:u<A.nodeValue.length)){return false}if(A.parentNode==p&&D&&!Q){return true}if(Q&&A.nodeType==1&&A==p.firstChild){return true}if(A.nodeName==="TABLE"||(A.previousSibling&&A.previousSibling.nodeName=="TABLE")){return(D&&!Q)||(!D&&Q)}P=new a(A,p);if(A.nodeType==3){if(Q&&u==0){P.prev()}else{if(!Q&&u==A.nodeValue.length){P.next()}}}while(O=P.current()){if(O.nodeType===1){if(!O.getAttribute("data-mce-bogus")){N=O.nodeName.toLowerCase();if(c[N]&&N!=="br"){return false}}}else{if(O.nodeType===3&&!/^[ \t\r\n]*$/.test(O.nodeValue)){return false}}if(Q){P.prev()}else{P.next()}}return true}function l(N,T){var U,S,P,R,Q,O=x||"P";S=i.getParent(N,i.isBlock);if(!S||!E(S)){S=S||j;if(!S.hasChildNodes()){U=i.create(O);S.appendChild(U);v.setStart(U,0);v.setEnd(U,0);return U}R=N;while(R.parentNode!=S){R=R.parentNode}while(R&&!i.isBlock(R)){P=R;R=R.previousSibling}if(P){U=i.create(O);P.parentNode.insertBefore(U,P);R=P;while(R&&!i.isBlock(R)){Q=R.nextSibling;U.appendChild(R);R=Q}v.setStart(N,T);v.setEnd(N,T)}}return N}function H(){function N(P){var O=n[P?"firstChild":"lastChild"];while(O){if(O.nodeType==1){break}O=O[P?"nextSibling":"previousSibling"]}return O===p}o=x?r(x):i.create("BR");if(N(true)&&N()){i.replace(o,n)}else{if(N(true)){n.parentNode.insertBefore(o,n)}else{if(N()){i.insertAfter(o,n);F(o)}else{G=v.cloneRange();G.setStartAfter(p);G.setEndAfter(n);k=G.extractContents();i.insertAfter(k,n);i.insertAfter(o,n)}}}i.remove(p);m(o);h.add()}function y(){var O=new a(A,p),N;while(N=O.next()){if(c[N.nodeName.toLowerCase()]||N.length>0){return true}}}function L(){var P,O,N;if(A&&A.nodeType==3&&u>=A.nodeValue.length){if(!b.isIE&&!y()){P=i.create("br");v.insertNode(P);v.setStartAfter(P);v.setEndAfter(P);O=true}}P=i.create("br");v.insertNode(P);if(b.isIE&&t=="PRE"&&(!M||M<8)){P.parentNode.insertBefore(i.doc.createTextNode("\r"),P)}N=i.create("span",{},"&nbsp;");P.parentNode.insertBefore(N,P);e.scrollIntoView(N);i.remove(N);if(!O){v.setStartAfter(P);v.setEndAfter(P)}else{v.setStartBefore(P);v.setEndBefore(P)}e.setRng(v);h.add()}function s(N){do{if(N.nodeType===3){N.nodeValue=N.nodeValue.replace(/^[\r\n]+/,"")}N=N.firstChild}while(N)}function K(P){var N=i.getRoot(),O,Q;O=P;while(O!==N&&i.getContentEditable(O)!=="false"){if(i.getContentEditable(O)==="true"){Q=O}O=O.parentNode}return O!==N?Q:N}function I(O){var N;if(!b.isIE){O.normalize();N=O.lastChild;if(!N||(/^(left|right)$/gi.test(i.getStyle(N,"float",true)))){i.add(O,"br")}}}if(!v.collapsed){f.execCommand("Delete");return}if(B.isDefaultPrevented()){return}A=v.startContainer;u=v.startOffset;x=(d.force_p_newlines?"p":"")||d.forced_root_block;x=x?x.toUpperCase():"";M=i.doc.documentMode;C=B.shiftKey;if(A.nodeType==1&&A.hasChildNodes()){D=u>A.childNodes.length-1;A=A.childNodes[Math.min(u,A.childNodes.length-1)]||A;if(D&&A.nodeType==3){u=A.nodeValue.length}else{u=0}}j=K(A);if(!j){return}h.beforeChange();if(!i.isBlock(j)&&j!=i.getRoot()){if(!x||C){L()}return}if((x&&!C)||(!x&&C)){A=l(A,u)}p=i.getParent(A,i.isBlock);n=p?i.getParent(p.parentNode,i.isBlock):null;t=p?p.nodeName.toUpperCase():"";J=n?n.nodeName.toUpperCase():"";if(J=="LI"&&!B.ctrlKey){p=n;t=J}if(t=="LI"){if(!x&&C){L();return}if(i.isEmpty(p)){if(/^(UL|OL|LI)$/.test(n.parentNode.nodeName)){return false}H();return}}if(t=="PRE"&&d.br_in_pre!==false){if(!C){L();return}}else{if((!x&&!C&&t!="LI")||(x&&C)){L();return}}x=x||"P";if(q()){if(/^(H[1-6]|PRE)$/.test(t)&&J!="HGROUP"){o=r(x)}else{o=r()}if(d.end_container_on_empty_block&&E(n)&&i.isEmpty(p)){o=i.split(n,p)}else{i.insertAfter(o,p)}m(o)}else{if(q(true)){o=p.parentNode.insertBefore(r(),p);F(o)}else{G=v.cloneRange();G.setEndAfter(p);k=G.extractContents();s(k);o=k.firstChild;i.insertAfter(k,p);z(o);I(p);m(o)}}i.setAttrib(o,"id","");h.add()}f.onKeyDown.add(function(k,j){if(j.keyCode==13){if(g(j)!==false){j.preventDefault()}}})}})(tinymce); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/tiny_mce_popup.js b/src/wp-includes/js/tinymce/tiny_mce_popup.js
new file mode 100644
index 0000000000..bb8e58c88a
--- /dev/null
+++ b/src/wp-includes/js/tinymce/tiny_mce_popup.js
@@ -0,0 +1,5 @@
+
+// Uncomment and change this document.domain value if you are loading the script cross subdomains
+// document.domain = 'moxiecode.com';
+
+var tinymce=null,tinyMCEPopup,tinyMCE;tinyMCEPopup={init:function(){var b=this,a,c;a=b.getWin();tinymce=a.tinymce;tinyMCE=a.tinyMCE;b.editor=tinymce.EditorManager.activeEditor;b.params=b.editor.windowManager.params;b.features=b.editor.windowManager.features;b.dom=b.editor.windowManager.createInstance("tinymce.dom.DOMUtils",document,{ownEvents:true,proxy:tinyMCEPopup._eventProxy});b.dom.bind(window,"ready",b._onDOMLoaded,b);if(b.features.popup_css!==false){b.dom.loadCSS(b.features.popup_css||b.editor.settings.popup_css)}b.listeners=[];b.onInit={add:function(e,d){b.listeners.push({func:e,scope:d})}};b.isWindow=!b.getWindowArg("mce_inline");b.id=b.getWindowArg("mce_window_id");b.editor.windowManager.onOpen.dispatch(b.editor.windowManager,window)},getWin:function(){return(!window.frameElement&&window.dialogArguments)||opener||parent||top},getWindowArg:function(c,b){var a=this.params[c];return tinymce.is(a)?a:b},getParam:function(b,a){return this.editor.getParam(b,a)},getLang:function(b,a){return this.editor.getLang(b,a)},execCommand:function(d,c,e,b){b=b||{};b.skip_focus=1;this.restoreSelection();return this.editor.execCommand(d,c,e,b)},resizeToInnerSize:function(){var a=this;setTimeout(function(){var b=a.dom.getViewPort(window);a.editor.windowManager.resizeBy(a.getWindowArg("mce_width")-b.w,a.getWindowArg("mce_height")-b.h,a.id||window)},10)},executeOnLoad:function(s){this.onInit.add(function(){eval(s)})},storeSelection:function(){this.editor.windowManager.bookmark=tinyMCEPopup.editor.selection.getBookmark(1)},restoreSelection:function(){var a=tinyMCEPopup;if(!a.isWindow&&tinymce.isIE){a.editor.selection.moveToBookmark(a.editor.windowManager.bookmark)}},requireLangPack:function(){var b=this,a=b.getWindowArg("plugin_url")||b.getWindowArg("theme_url");if(a&&b.editor.settings.language&&b.features.translate_i18n!==false&&b.editor.settings.language_load!==false){a+="/langs/"+b.editor.settings.language+"_dlg.js";if(!tinymce.ScriptLoader.isDone(a)){document.write('<script type="text/javascript" src="'+tinymce._addVer(a)+'"><\/script>');tinymce.ScriptLoader.markDone(a)}}},pickColor:function(b,a){this.execCommand("mceColorPicker",true,{color:document.getElementById(a).value,func:function(e){document.getElementById(a).value=e;try{document.getElementById(a).onchange()}catch(d){}}})},openBrowser:function(a,c,b){tinyMCEPopup.restoreSelection();this.editor.execCallback("file_browser_callback",a,document.getElementById(a).value,c,window)},confirm:function(b,a,c){this.editor.windowManager.confirm(b,a,c,window)},alert:function(b,a,c){this.editor.windowManager.alert(b,a,c,window)},close:function(){var a=this;function b(){a.editor.windowManager.close(window);tinymce=tinyMCE=a.editor=a.params=a.dom=a.dom.doc=null}if(tinymce.isOpera){a.getWin().setTimeout(b,0)}else{b()}},_restoreSelection:function(){var a=window.event.srcElement;if(a.nodeName=="INPUT"&&(a.type=="submit"||a.type=="button")){tinyMCEPopup.restoreSelection()}},_onDOMLoaded:function(){var b=tinyMCEPopup,d=document.title,e,c,a;if(b.features.translate_i18n!==false){c=document.body.innerHTML;if(tinymce.isIE){c=c.replace(/ (value|title|alt)=([^"][^\s>]+)/gi,' $1="$2"')}document.dir=b.editor.getParam("directionality","");if((a=b.editor.translate(c))&&a!=c){document.body.innerHTML=a}if((a=b.editor.translate(d))&&a!=d){document.title=d=a}}if(!b.editor.getParam("browser_preferred_colors",false)||!b.isWindow){b.dom.addClass(document.body,"forceColors")}document.body.style.display="";if(tinymce.isIE){document.attachEvent("onmouseup",tinyMCEPopup._restoreSelection);b.dom.add(b.dom.select("head")[0],"base",{target:"_self"})}b.restoreSelection();b.resizeToInnerSize();if(!b.isWindow){b.editor.windowManager.setTitle(window,d)}else{window.focus()}if(!tinymce.isIE&&!b.isWindow){b.dom.bind(document,"focus",function(){b.editor.windowManager.focus(b.id)})}tinymce.each(b.dom.select("select"),function(f){f.onkeydown=tinyMCEPopup._accessHandler});tinymce.each(b.listeners,function(f){f.func.call(f.scope,b.editor)});if(b.getWindowArg("mce_auto_focus",true)){window.focus();tinymce.each(document.forms,function(g){tinymce.each(g.elements,function(f){if(b.dom.hasClass(f,"mceFocus")&&!f.disabled){f.focus();return false}})})}document.onkeyup=tinyMCEPopup._closeWinKeyHandler},_accessHandler:function(a){a=a||window.event;if(a.keyCode==13||a.keyCode==32){var b=a.target||a.srcElement;if(b.onchange){b.onchange()}return tinymce.dom.Event.cancel(a)}},_closeWinKeyHandler:function(a){a=a||window.event;if(a.keyCode==27){tinyMCEPopup.close()}},_eventProxy:function(a){return function(b){tinyMCEPopup.dom.events.callNativeHandler(a,b)}}};tinyMCEPopup.init(); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/utils/editable_selects.js b/src/wp-includes/js/tinymce/utils/editable_selects.js
new file mode 100644
index 0000000000..4d9ffe272b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/utils/editable_selects.js
@@ -0,0 +1,70 @@
+/**
+ * editable_selects.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+var TinyMCE_EditableSelects = {
+ editSelectElm : null,
+
+ init : function() {
+ var nl = document.getElementsByTagName("select"), i, d = document, o;
+
+ for (i=0; i<nl.length; i++) {
+ if (nl[i].className.indexOf('mceEditableSelect') != -1) {
+ o = new Option(tinyMCEPopup.editor.translate('value'), '__mce_add_custom__');
+
+ o.className = 'mceAddSelectValue';
+
+ nl[i].options[nl[i].options.length] = o;
+ nl[i].onchange = TinyMCE_EditableSelects.onChangeEditableSelect;
+ }
+ }
+ },
+
+ onChangeEditableSelect : function(e) {
+ var d = document, ne, se = window.event ? window.event.srcElement : e.target;
+
+ if (se.options[se.selectedIndex].value == '__mce_add_custom__') {
+ ne = d.createElement("input");
+ ne.id = se.id + "_custom";
+ ne.name = se.name + "_custom";
+ ne.type = "text";
+
+ ne.style.width = se.offsetWidth + 'px';
+ se.parentNode.insertBefore(ne, se);
+ se.style.display = 'none';
+ ne.focus();
+ ne.onblur = TinyMCE_EditableSelects.onBlurEditableSelectInput;
+ ne.onkeydown = TinyMCE_EditableSelects.onKeyDown;
+ TinyMCE_EditableSelects.editSelectElm = se;
+ }
+ },
+
+ onBlurEditableSelectInput : function() {
+ var se = TinyMCE_EditableSelects.editSelectElm;
+
+ if (se) {
+ if (se.previousSibling.value != '') {
+ addSelectValue(document.forms[0], se.id, se.previousSibling.value, se.previousSibling.value);
+ selectByValue(document.forms[0], se.id, se.previousSibling.value);
+ } else
+ selectByValue(document.forms[0], se.id, '');
+
+ se.style.display = 'inline';
+ se.parentNode.removeChild(se.previousSibling);
+ TinyMCE_EditableSelects.editSelectElm = null;
+ }
+ },
+
+ onKeyDown : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 13)
+ TinyMCE_EditableSelects.onBlurEditableSelectInput();
+ }
+};
diff --git a/src/wp-includes/js/tinymce/utils/form_utils.js b/src/wp-includes/js/tinymce/utils/form_utils.js
new file mode 100644
index 0000000000..6f62fe606d
--- /dev/null
+++ b/src/wp-includes/js/tinymce/utils/form_utils.js
@@ -0,0 +1,210 @@
+/**
+ * form_utils.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+var themeBaseURL = tinyMCEPopup.editor.baseURI.toAbsolute('themes/' + tinyMCEPopup.getParam("theme"));
+
+function getColorPickerHTML(id, target_form_element) {
+ var h = "", dom = tinyMCEPopup.dom;
+
+ if (label = dom.select('label[for=' + target_form_element + ']')[0]) {
+ label.id = label.id || dom.uniqueId();
+ }
+
+ h += '<a role="button" aria-labelledby="' + id + '_label" id="' + id + '_link" href="javascript:;" onclick="tinyMCEPopup.pickColor(event,\'' + target_form_element +'\');" onmousedown="return false;" class="pickcolor">';
+ h += '<span id="' + id + '" title="' + tinyMCEPopup.getLang('browse') + '">&nbsp;<span id="' + id + '_label" class="mceVoiceLabel mceIconOnly" style="display:none;">' + tinyMCEPopup.getLang('browse') + '</span></span></a>';
+
+ return h;
+}
+
+function updateColor(img_id, form_element_id) {
+ document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value;
+}
+
+function setBrowserDisabled(id, state) {
+ var img = document.getElementById(id);
+ var lnk = document.getElementById(id + "_link");
+
+ if (lnk) {
+ if (state) {
+ lnk.setAttribute("realhref", lnk.getAttribute("href"));
+ lnk.removeAttribute("href");
+ tinyMCEPopup.dom.addClass(img, 'disabled');
+ } else {
+ if (lnk.getAttribute("realhref"))
+ lnk.setAttribute("href", lnk.getAttribute("realhref"));
+
+ tinyMCEPopup.dom.removeClass(img, 'disabled');
+ }
+ }
+}
+
+function getBrowserHTML(id, target_form_element, type, prefix) {
+ var option = prefix + "_" + type + "_browser_callback", cb, html;
+
+ cb = tinyMCEPopup.getParam(option, tinyMCEPopup.getParam("file_browser_callback"));
+
+ if (!cb)
+ return "";
+
+ html = "";
+ html += '<a id="' + id + '_link" href="javascript:openBrowser(\'' + id + '\',\'' + target_form_element + '\', \'' + type + '\',\'' + option + '\');" onmousedown="return false;" class="browse">';
+ html += '<span id="' + id + '" title="' + tinyMCEPopup.getLang('browse') + '">&nbsp;</span></a>';
+
+ return html;
+}
+
+function openBrowser(img_id, target_form_element, type, option) {
+ var img = document.getElementById(img_id);
+
+ if (img.className != "mceButtonDisabled")
+ tinyMCEPopup.openBrowser(target_form_element, type, option);
+}
+
+function selectByValue(form_obj, field_name, value, add_custom, ignore_case) {
+ if (!form_obj || !form_obj.elements[field_name])
+ return;
+
+ if (!value)
+ value = "";
+
+ var sel = form_obj.elements[field_name];
+
+ var found = false;
+ for (var i=0; i<sel.options.length; i++) {
+ var option = sel.options[i];
+
+ if (option.value == value || (ignore_case && option.value.toLowerCase() == value.toLowerCase())) {
+ option.selected = true;
+ found = true;
+ } else
+ option.selected = false;
+ }
+
+ if (!found && add_custom && value != '') {
+ var option = new Option(value, value);
+ option.selected = true;
+ sel.options[sel.options.length] = option;
+ sel.selectedIndex = sel.options.length - 1;
+ }
+
+ return found;
+}
+
+function getSelectValue(form_obj, field_name) {
+ var elm = form_obj.elements[field_name];
+
+ if (elm == null || elm.options == null || elm.selectedIndex === -1)
+ return "";
+
+ return elm.options[elm.selectedIndex].value;
+}
+
+function addSelectValue(form_obj, field_name, name, value) {
+ var s = form_obj.elements[field_name];
+ var o = new Option(name, value);
+ s.options[s.options.length] = o;
+}
+
+function addClassesToList(list_id, specific_option) {
+ // Setup class droplist
+ var styleSelectElm = document.getElementById(list_id);
+ var styles = tinyMCEPopup.getParam('theme_advanced_styles', false);
+ styles = tinyMCEPopup.getParam(specific_option, styles);
+
+ if (styles) {
+ var stylesAr = styles.split(';');
+
+ for (var i=0; i<stylesAr.length; i++) {
+ if (stylesAr != "") {
+ var key, value;
+
+ key = stylesAr[i].split('=')[0];
+ value = stylesAr[i].split('=')[1];
+
+ styleSelectElm.options[styleSelectElm.length] = new Option(key, value);
+ }
+ }
+ } else {
+ tinymce.each(tinyMCEPopup.editor.dom.getClasses(), function(o) {
+ styleSelectElm.options[styleSelectElm.length] = new Option(o.title || o['class'], o['class']);
+ });
+ }
+}
+
+function isVisible(element_id) {
+ var elm = document.getElementById(element_id);
+
+ return elm && elm.style.display != "none";
+}
+
+function convertRGBToHex(col) {
+ var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+ var rgb = col.replace(re, "$1,$2,$3").split(',');
+ if (rgb.length == 3) {
+ r = parseInt(rgb[0]).toString(16);
+ g = parseInt(rgb[1]).toString(16);
+ b = parseInt(rgb[2]).toString(16);
+
+ r = r.length == 1 ? '0' + r : r;
+ g = g.length == 1 ? '0' + g : g;
+ b = b.length == 1 ? '0' + b : b;
+
+ return "#" + r + g + b;
+ }
+
+ return col;
+}
+
+function convertHexToRGB(col) {
+ if (col.indexOf('#') != -1) {
+ col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+ r = parseInt(col.substring(0, 2), 16);
+ g = parseInt(col.substring(2, 4), 16);
+ b = parseInt(col.substring(4, 6), 16);
+
+ return "rgb(" + r + "," + g + "," + b + ")";
+ }
+
+ return col;
+}
+
+function trimSize(size) {
+ return size.replace(/([0-9\.]+)(px|%|in|cm|mm|em|ex|pt|pc)/i, '$1$2');
+}
+
+function getCSSSize(size) {
+ size = trimSize(size);
+
+ if (size == "")
+ return "";
+
+ // Add px
+ if (/^[0-9]+$/.test(size))
+ size += 'px';
+ // Sanity check, IE doesn't like broken values
+ else if (!(/^[0-9\.]+(px|%|in|cm|mm|em|ex|pt|pc)$/i.test(size)))
+ return "";
+
+ return size;
+}
+
+function getStyle(elm, attrib, style) {
+ var val = tinyMCEPopup.dom.getAttrib(elm, attrib);
+
+ if (val != '')
+ return '' + val;
+
+ if (typeof(style) == 'undefined')
+ style = attrib;
+
+ return tinyMCEPopup.dom.getStyle(elm, style);
+}
diff --git a/src/wp-includes/js/tinymce/utils/mctabs.js b/src/wp-includes/js/tinymce/utils/mctabs.js
new file mode 100644
index 0000000000..027ef40e74
--- /dev/null
+++ b/src/wp-includes/js/tinymce/utils/mctabs.js
@@ -0,0 +1,162 @@
+/**
+ * mctabs.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function MCTabs() {
+ this.settings = [];
+ this.onChange = tinyMCEPopup.editor.windowManager.createInstance('tinymce.util.Dispatcher');
+};
+
+MCTabs.prototype.init = function(settings) {
+ this.settings = settings;
+};
+
+MCTabs.prototype.getParam = function(name, default_value) {
+ var value = null;
+
+ value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+ // Fix bool values
+ if (value == "true" || value == "false")
+ return (value == "true");
+
+ return value;
+};
+
+MCTabs.prototype.showTab =function(tab){
+ tab.className = 'current';
+ tab.setAttribute("aria-selected", true);
+ tab.setAttribute("aria-expanded", true);
+ tab.tabIndex = 0;
+};
+
+MCTabs.prototype.hideTab =function(tab){
+ var t=this;
+
+ tab.className = '';
+ tab.setAttribute("aria-selected", false);
+ tab.setAttribute("aria-expanded", false);
+ tab.tabIndex = -1;
+};
+
+MCTabs.prototype.showPanel = function(panel) {
+ panel.className = 'current';
+ panel.setAttribute("aria-hidden", false);
+};
+
+MCTabs.prototype.hidePanel = function(panel) {
+ panel.className = 'panel';
+ panel.setAttribute("aria-hidden", true);
+};
+
+MCTabs.prototype.getPanelForTab = function(tabElm) {
+ return tinyMCEPopup.dom.getAttrib(tabElm, "aria-controls");
+};
+
+MCTabs.prototype.displayTab = function(tab_id, panel_id, avoid_focus) {
+ var panelElm, panelContainerElm, tabElm, tabContainerElm, selectionClass, nodes, i, t = this;
+
+ tabElm = document.getElementById(tab_id);
+
+ if (panel_id === undefined) {
+ panel_id = t.getPanelForTab(tabElm);
+ }
+
+ panelElm= document.getElementById(panel_id);
+ panelContainerElm = panelElm ? panelElm.parentNode : null;
+ tabContainerElm = tabElm ? tabElm.parentNode : null;
+ selectionClass = t.getParam('selection_class', 'current');
+
+ if (tabElm && tabContainerElm) {
+ nodes = tabContainerElm.childNodes;
+
+ // Hide all other tabs
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeName == "LI") {
+ t.hideTab(nodes[i]);
+ }
+ }
+
+ // Show selected tab
+ t.showTab(tabElm);
+ }
+
+ if (panelElm && panelContainerElm) {
+ nodes = panelContainerElm.childNodes;
+
+ // Hide all other panels
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeName == "DIV")
+ t.hidePanel(nodes[i]);
+ }
+
+ if (!avoid_focus) {
+ tabElm.focus();
+ }
+
+ // Show selected panel
+ t.showPanel(panelElm);
+ }
+};
+
+MCTabs.prototype.getAnchor = function() {
+ var pos, url = document.location.href;
+
+ if ((pos = url.lastIndexOf('#')) != -1)
+ return url.substring(pos + 1);
+
+ return "";
+};
+
+
+//Global instance
+var mcTabs = new MCTabs();
+
+tinyMCEPopup.onInit.add(function() {
+ var tinymce = tinyMCEPopup.getWin().tinymce, dom = tinyMCEPopup.dom, each = tinymce.each;
+
+ each(dom.select('div.tabs'), function(tabContainerElm) {
+ var keyNav;
+
+ dom.setAttrib(tabContainerElm, "role", "tablist");
+
+ var items = tinyMCEPopup.dom.select('li', tabContainerElm);
+ var action = function(id) {
+ mcTabs.displayTab(id, mcTabs.getPanelForTab(id));
+ mcTabs.onChange.dispatch(id);
+ };
+
+ each(items, function(item) {
+ dom.setAttrib(item, 'role', 'tab');
+ dom.bind(item, 'click', function(evt) {
+ action(item.id);
+ });
+ });
+
+ dom.bind(dom.getRoot(), 'keydown', function(evt) {
+ if (evt.keyCode === 9 && evt.ctrlKey && !evt.altKey) { // Tab
+ keyNav.moveFocus(evt.shiftKey ? -1 : 1);
+ tinymce.dom.Event.cancel(evt);
+ }
+ });
+
+ each(dom.select('a', tabContainerElm), function(a) {
+ dom.setAttrib(a, 'tabindex', '-1');
+ });
+
+ keyNav = tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', {
+ root: tabContainerElm,
+ items: items,
+ onAction: action,
+ actOnFocus: true,
+ enableLeftRight: true,
+ enableUpDown: true
+ }, tinyMCEPopup.dom);
+ });
+}); \ No newline at end of file
diff --git a/src/wp-includes/js/tinymce/utils/validate.js b/src/wp-includes/js/tinymce/utils/validate.js
new file mode 100644
index 0000000000..760d0290fd
--- /dev/null
+++ b/src/wp-includes/js/tinymce/utils/validate.js
@@ -0,0 +1,252 @@
+/**
+ * validate.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+/**
+ // String validation:
+
+ if (!Validator.isEmail('myemail'))
+ alert('Invalid email.');
+
+ // Form validation:
+
+ var f = document.forms['myform'];
+
+ if (!Validator.isEmail(f.myemail))
+ alert('Invalid email.');
+*/
+
+var Validator = {
+ isEmail : function(s) {
+ return this.test(s, '^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$');
+ },
+
+ isAbsUrl : function(s) {
+ return this.test(s, '^(news|telnet|nttp|file|http|ftp|https)://[-A-Za-z0-9\\.]+\\/?.*$');
+ },
+
+ isSize : function(s) {
+ return this.test(s, '^[0-9.]+(%|in|cm|mm|em|ex|pt|pc|px)?$');
+ },
+
+ isId : function(s) {
+ return this.test(s, '^[A-Za-z_]([A-Za-z0-9_])*$');
+ },
+
+ isEmpty : function(s) {
+ var nl, i;
+
+ if (s.nodeName == 'SELECT' && s.selectedIndex < 1)
+ return true;
+
+ if (s.type == 'checkbox' && !s.checked)
+ return true;
+
+ if (s.type == 'radio') {
+ for (i=0, nl = s.form.elements; i<nl.length; i++) {
+ if (nl[i].type == "radio" && nl[i].name == s.name && nl[i].checked)
+ return false;
+ }
+
+ return true;
+ }
+
+ return new RegExp('^\\s*$').test(s.nodeType == 1 ? s.value : s);
+ },
+
+ isNumber : function(s, d) {
+ return !isNaN(s.nodeType == 1 ? s.value : s) && (!d || !this.test(s, '^-?[0-9]*\\.[0-9]*$'));
+ },
+
+ test : function(s, p) {
+ s = s.nodeType == 1 ? s.value : s;
+
+ return s == '' || new RegExp(p).test(s);
+ }
+};
+
+var AutoValidator = {
+ settings : {
+ id_cls : 'id',
+ int_cls : 'int',
+ url_cls : 'url',
+ number_cls : 'number',
+ email_cls : 'email',
+ size_cls : 'size',
+ required_cls : 'required',
+ invalid_cls : 'invalid',
+ min_cls : 'min',
+ max_cls : 'max'
+ },
+
+ init : function(s) {
+ var n;
+
+ for (n in s)
+ this.settings[n] = s[n];
+ },
+
+ validate : function(f) {
+ var i, nl, s = this.settings, c = 0;
+
+ nl = this.tags(f, 'label');
+ for (i=0; i<nl.length; i++) {
+ this.removeClass(nl[i], s.invalid_cls);
+ nl[i].setAttribute('aria-invalid', false);
+ }
+
+ c += this.validateElms(f, 'input');
+ c += this.validateElms(f, 'select');
+ c += this.validateElms(f, 'textarea');
+
+ return c == 3;
+ },
+
+ invalidate : function(n) {
+ this.mark(n.form, n);
+ },
+
+ getErrorMessages : function(f) {
+ var nl, i, s = this.settings, field, msg, values, messages = [], ed = tinyMCEPopup.editor;
+ nl = this.tags(f, "label");
+ for (i=0; i<nl.length; i++) {
+ if (this.hasClass(nl[i], s.invalid_cls)) {
+ field = document.getElementById(nl[i].getAttribute("for"));
+ values = { field: nl[i].textContent };
+ if (this.hasClass(field, s.min_cls, true)) {
+ message = ed.getLang('invalid_data_min');
+ values.min = this.getNum(field, s.min_cls);
+ } else if (this.hasClass(field, s.number_cls)) {
+ message = ed.getLang('invalid_data_number');
+ } else if (this.hasClass(field, s.size_cls)) {
+ message = ed.getLang('invalid_data_size');
+ } else {
+ message = ed.getLang('invalid_data');
+ }
+
+ message = message.replace(/{\#([^}]+)\}/g, function(a, b) {
+ return values[b] || '{#' + b + '}';
+ });
+ messages.push(message);
+ }
+ }
+ return messages;
+ },
+
+ reset : function(e) {
+ var t = ['label', 'input', 'select', 'textarea'];
+ var i, j, nl, s = this.settings;
+
+ if (e == null)
+ return;
+
+ for (i=0; i<t.length; i++) {
+ nl = this.tags(e.form ? e.form : e, t[i]);
+ for (j=0; j<nl.length; j++) {
+ this.removeClass(nl[j], s.invalid_cls);
+ nl[j].setAttribute('aria-invalid', false);
+ }
+ }
+ },
+
+ validateElms : function(f, e) {
+ var nl, i, n, s = this.settings, st = true, va = Validator, v;
+
+ nl = this.tags(f, e);
+ for (i=0; i<nl.length; i++) {
+ n = nl[i];
+
+ this.removeClass(n, s.invalid_cls);
+
+ if (this.hasClass(n, s.required_cls) && va.isEmpty(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.number_cls) && !va.isNumber(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.int_cls) && !va.isNumber(n, true))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.url_cls) && !va.isAbsUrl(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.email_cls) && !va.isEmail(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.size_cls) && !va.isSize(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.id_cls) && !va.isId(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.min_cls, true)) {
+ v = this.getNum(n, s.min_cls);
+
+ if (isNaN(v) || parseInt(n.value) < parseInt(v))
+ st = this.mark(f, n);
+ }
+
+ if (this.hasClass(n, s.max_cls, true)) {
+ v = this.getNum(n, s.max_cls);
+
+ if (isNaN(v) || parseInt(n.value) > parseInt(v))
+ st = this.mark(f, n);
+ }
+ }
+
+ return st;
+ },
+
+ hasClass : function(n, c, d) {
+ return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className);
+ },
+
+ getNum : function(n, c) {
+ c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0];
+ c = c.replace(/[^0-9]/g, '');
+
+ return c;
+ },
+
+ addClass : function(n, c, b) {
+ var o = this.removeClass(n, c);
+ n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
+ },
+
+ removeClass : function(n, c) {
+ c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
+ return n.className = c != ' ' ? c : '';
+ },
+
+ tags : function(f, s) {
+ return f.getElementsByTagName(s);
+ },
+
+ mark : function(f, n) {
+ var s = this.settings;
+
+ this.addClass(n, s.invalid_cls);
+ n.setAttribute('aria-invalid', 'true');
+ this.markLabels(f, n, s.invalid_cls);
+
+ return false;
+ },
+
+ markLabels : function(f, n, ic) {
+ var nl, i;
+
+ nl = this.tags(f, "label");
+ for (i=0; i<nl.length; i++) {
+ if (nl[i].getAttribute("for") == n.id || nl[i].htmlFor == n.id)
+ this.addClass(nl[i], ic);
+ }
+
+ return null;
+ }
+};
diff --git a/src/wp-includes/js/tinymce/wp-mce-help.php b/src/wp-includes/js/tinymce/wp-mce-help.php
new file mode 100644
index 0000000000..88c728b447
--- /dev/null
+++ b/src/wp-includes/js/tinymce/wp-mce-help.php
@@ -0,0 +1,281 @@
+<?php
+/**
+ * @package TinyMCE
+ * @author Moxiecode
+ * @copyright Copyright © 2005-2006, Moxiecode Systems AB, All rights reserved.
+ */
+
+/** @ignore */
+require_once('../../../wp-load.php');
+header('Content-Type: text/html; charset=' . get_bloginfo('charset'));
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+<head>
+<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
+<title><?php _e('Rich Editor Help'); ?></title>
+<script type="text/javascript" src="tiny_mce_popup.js?ver=358-20121205"></script>
+<?php
+wp_admin_css( 'wp-admin', true );
+?>
+<style type="text/css">
+ body {
+ min-width: 0;
+ }
+ #wphead {
+ font-size: 80%;
+ border-top: 0;
+ color: #555;
+ background-color: #f1f1f1;
+ }
+ #wphead h1 {
+ font-size: 24px;
+ color: #555;
+ margin: 0;
+ padding: 10px;
+ }
+ #tabs {
+ padding: 15px 15px 3px;
+ background-color: #f1f1f1;
+ border-bottom: 1px solid #dfdfdf;
+ margin: 0;
+ }
+ #tabs li {
+ display: inline;
+ }
+ #tabs a.current {
+ background-color: #fff;
+ border-color: #dfdfdf;
+ border-bottom-color: #fff;
+ color: #d54e21;
+ }
+ #tabs a {
+ color: #2583AD;
+ padding: 6px;
+ border-width: 1px 1px 0;
+ border-style: solid solid none;
+ border-color: #f1f1f1;
+ text-decoration: none;
+ }
+ #tabs a:hover {
+ color: #d54e21;
+ }
+ .wrap h2 {
+ border-bottom-color: #dfdfdf;
+ color: #555;
+ margin: 5px 0;
+ padding: 0;
+ font-size: 18px;
+ }
+ #user_info {
+ right: 5%;
+ top: 5px;
+ }
+ h3 {
+ font-size: 1.1em;
+ margin-top: 10px;
+ margin-bottom: 0px;
+ }
+ #flipper {
+ margin: 0;
+ padding: 5px 20px 10px;
+ background-color: #fff;
+ border-left: 1px solid #dfdfdf;
+ border-bottom: 1px solid #dfdfdf;
+ }
+ * html {
+ overflow-x: hidden;
+ overflow-y: scroll;
+ }
+ #flipper div p {
+ margin-top: 0.4em;
+ margin-bottom: 0.8em;
+ text-align: justify;
+ }
+ th {
+ text-align: center;
+ }
+ .top th {
+ text-decoration: underline;
+ }
+ .top .key {
+ text-align: center;
+ width: 5em;
+ }
+ .top .action {
+ text-align: left;
+ }
+ .align {
+ border-left: 3px double #333;
+ border-right: 3px double #333;
+ }
+ .keys {
+ margin-bottom: 15px;
+ width: 100%;
+ border: 0 none;
+ }
+ .keys p {
+ display: inline-block;
+ margin: 0px;
+ padding: 0px;
+ }
+ .keys .left { text-align: left; }
+ .keys .center { text-align: center; }
+ .keys .right { text-align: right; }
+ td b {
+ font-family: "Times New Roman" Times serif;
+ }
+ #buttoncontainer {
+ text-align: center;
+ margin-bottom: 20px;
+ }
+ #buttoncontainer a, #buttoncontainer a:hover {
+ border-bottom: 0px;
+ }
+ .macos .win,
+ .windows .mac {
+ display: none;
+ }
+</style>
+<?php if ( is_rtl() ) : ?>
+<style type="text/css">
+ #wphead, #tabs {
+ padding-left: auto;
+ padding-right: 15px;
+ }
+ #flipper {
+ margin: 5px 0 3px 10px;
+ }
+ .keys .left, .top, .action { text-align: right; }
+ .keys .right { text-align: left; }
+ td b { font-family: Tahoma, "Times New Roman", Times, serif }
+</style>
+<?php endif; ?>
+</head>
+<body class="windows wp-core-ui">
+<script type="text/javascript">
+if ( tinymce.isMac )
+ document.body.className = document.body.className.replace(/windows/, 'macos');
+</script>
+
+<ul id="tabs">
+ <li><a id="tab1" href="javascript:flipTab(1)" title="<?php esc_attr_e('Basics of Rich Editing'); ?>" accesskey="1" class="current"><?php _e('Basics'); ?></a></li>
+ <li><a id="tab2" href="javascript:flipTab(2)" title="<?php esc_attr_e('Advanced use of the Rich Editor'); ?>" accesskey="2"><?php _e('Advanced'); ?></a></li>
+ <li><a id="tab3" href="javascript:flipTab(3)" title="<?php esc_attr_e('Hotkeys'); ?>" accesskey="3"><?php _e('Hotkeys'); ?></a></li>
+ <li><a id="tab4" href="javascript:flipTab(4)" title="<?php esc_attr_e('About the software'); ?>" accesskey="4"><?php _e('About'); ?></a></li>
+</ul>
+
+<div id="flipper" class="wrap">
+
+<div id="content1">
+ <h2><?php _e('Rich Editing Basics'); ?></h2>
+ <p><?php _e('<em>Rich editing</em>, also called WYSIWYG for What You See Is What You Get, means your text is formatted as you type. The rich editor creates HTML code behind the scenes while you concentrate on writing. Font styles, links and images all appear approximately as they will on the internet.'); ?></p>
+ <p><?php _e('WordPress includes a rich HTML editor that works well in all major web browsers used today. However editing HTML is not the same as typing text. Each web page has two major components: the structure, which is the actual HTML code and is produced by the editor as you type, and the display, that is applied to it by the currently selected WordPress theme and is defined in style.css. WordPress is producing valid XHTML 1.0 which means that inserting multiple line breaks (BR tags) after a paragraph would not produce white space on the web page. The BR tags will be removed as invalid by the internal HTML correcting functions.'); ?></p>
+ <p><?php _e('While using the editor, most basic keyboard shortcuts work like in any other text editor. For example: Shift+Enter inserts line break, Ctrl+C = copy, Ctrl+X = cut, Ctrl+Z = undo, Ctrl+Y = redo, Ctrl+A = select all, etc. (on Mac use the Command key instead of Ctrl). See the Hotkeys tab for all available keyboard shortcuts.'); ?></p>
+ <p><?php _e('If you do not like the way the rich editor works, you may turn it off from Your Profile submenu, under Users in the admin menu.'); ?></p>
+</div>
+
+<div id="content2" class="hidden">
+ <h2><?php _e('Advanced Rich Editing'); ?></h2>
+ <h3><?php _e('Images and Attachments'); ?></h3>
+ <p><?php _e('There is a button in the editor toolbar for inserting images that are already hosted somewhere on the internet. If you have a URL for an image, click this button and enter the URL in the box which appears.'); ?></p>
+ <p><?php _e('If you need to upload an image or another media file from your computer, you can use the Media Library button above the editor. The media library will attempt to create a thumbnail-sized copy from each uploaded image. To insert your image into the post, first click on the thumbnail to reveal a menu of options. When you have selected the options you like, click "Insert into Post" and your image or file will appear in the post you are editing.'); ?></p>
+ <h3><?php _e('HTML in the Rich Editor'); ?></h3>
+ <p><?php _e('Any HTML entered directly into the rich editor will show up as text when the post is viewed. What you see is what you get. When you want to include HTML elements that cannot be generated with the toolbar buttons, you must enter it by hand in the Text editor. Examples are tables and &lt;code&gt;. To do this, click the Text tab and edit the code, then switch back to Visual mode. If the code is valid and understood by the editor, you should see it rendered immediately.'); ?></p>
+ <h3><?php _e('Pasting in the Rich Editor'); ?></h3>
+ <p><?php _e('When pasting content from another web page the results can be inconsistent and depend on your browser and on the web page you are pasting from. The editor tries to correct any invalid HTML code that was pasted, but for best results try using the Text tab or one of the paste buttons that are on the second row. Alternatively try pasting paragraph by paragraph. In most browsers to select one paragraph at a time, triple-click on it.'); ?></p>
+ <p><?php _e('Pasting content from another application, like Word or Excel, is best done with the Paste from Word button on the second row, or in Text mode.'); ?></p>
+</div>
+
+<div id="content3" class="hidden">
+ <h2><?php _e('Writing at Full Speed'); ?></h2>
+ <p><?php _e('Rather than reaching for your mouse to click on the toolbar, use these access keys. Windows and Linux use Ctrl + letter. Macintosh uses Command + letter.'); ?></p>
+
+ <table class="keys">
+ <tr class="top"><th class="key center"><?php _e('Letter'); ?></th><th class="left"><?php _e('Action'); ?></th><th class="key center"><?php _e('Letter'); ?></th><th class="left"><?php _e('Action'); ?></th></tr>
+ <tr><th>c</th><td><?php _e('Copy'); ?></td><th>v</th><td><?php _e('Paste'); ?></td></tr>
+ <tr><th>a</th><td><?php _e('Select all'); ?></td><th>x</th><td><?php _e('Cut'); ?></td></tr>
+ <tr><th>z</th><td><?php _e('Undo'); ?></td><th>y</th><td><?php _e('Redo'); ?></td></tr>
+
+ <tr><th>b</th><td><?php _e('Bold'); ?></td><th>i</th><td><?php _e('Italic'); ?></td></tr>
+ <tr><th>u</th><td><?php _e('Underline'); ?></td><th>1</th><td><?php _e('Heading 1'); ?></td></tr>
+ <tr><th>2</th><td><?php _e('Heading 2'); ?></td><th>3</th><td><?php _e('Heading 3'); ?></td></tr>
+ <tr><th>4</th><td><?php _e('Heading 4'); ?></td><th>5</th><td><?php _e('Heading 5'); ?></td></tr>
+ <tr><th>6</th><td><?php _e('Heading 6'); ?></td><th>9</th><td><?php _e('Address'); ?></td></tr>
+ </table>
+
+ <p><?php _e('The following shortcuts use different access keys: Alt + Shift + letter.'); ?></p>
+ <table class="keys">
+ <tr class="top"><th class="key center"><?php _e('Letter'); ?></th><th class="left"><?php _e('Action'); ?></th><th class="key center"><?php _e('Letter'); ?></th><th class="left"><?php _e('Action'); ?></th></tr>
+ <tr><th>n</th><td><?php _e('Check Spelling'); ?></td><th>l</th><td><?php _e('Align Left'); ?></td></tr>
+ <tr><th>j</th><td><?php _e('Justify Text'); ?></td><th>c</th><td><?php _e('Align Center'); ?></td></tr>
+ <tr><th>d</th><td><span style="text-decoration: line-through;"><?php _e('Strikethrough'); ?></span></td><th>r</th><td><?php _e('Align Right'); ?></td></tr>
+ <tr><th>u</th><td><strong>&bull;</strong> <?php _e('List'); ?></td><th>a</th><td><?php _e('Insert link'); ?></td></tr>
+ <tr><th>o</th><td>1. <?php _e('List'); ?></td><th>s</th><td><?php _e('Remove link'); ?></td></tr>
+ <tr><th>q</th><td><?php _e('Quote'); ?></td><th>m</th><td><?php _e('Insert Image'); ?></td></tr>
+ <tr><th>w</th><td><?php _e('Distraction Free Writing mode'); ?></td><th>t</th><td><?php _e('Insert More Tag'); ?></td></tr>
+ <tr><th>p</th><td><?php _e('Insert Page Break tag'); ?></td><th>h</th><td><?php _e('Help'); ?></td></tr>
+ </table>
+
+ <p style="padding: 15px 10px 10px;"><?php _e('Editor width in Distraction Free Writing mode:'); ?></p>
+ <table class="keys">
+ <tr><th><span class="win">Alt +</span><span class="mac">Ctrl +</span></th><td><?php _e('Wider'); ?></td>
+ <th><span class="win">Alt -</span><span class="mac">Ctrl -</span></th><td><?php _e('Narrower'); ?></td></tr>
+ <tr><th><span class="win">Alt 0</span><span class="mac">Ctrl 0</span></th><td><?php _e('Default width'); ?></td><th></th><td></td></tr>
+ </table>
+</div>
+
+<div id="content4" class="hidden">
+ <h2><?php _e('About TinyMCE'); ?></h2>
+
+ <p><?php _e('Version:'); ?> <span id="version"></span> (<span id="date"></span>)</p>
+ <p><?php printf(__('TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor released as Open Source under %sLGPL</a> by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.'), '<a href="'.home_url('/wp-includes/js/tinymce/license.txt').'" target="_blank" title="'.esc_attr__('GNU Library General Public License').'">'); ?></p>
+ <p><?php _e('Copyright &copy; 2003-2011, <a href="http://www.moxiecode.com" target="_blank">Moxiecode Systems AB</a>, All rights reserved.'); ?></p>
+ <p><?php _e('For more information about this software visit the <a href="http://tinymce.com" target="_blank">TinyMCE website</a>.'); ?></p>
+
+ <div id="buttoncontainer">
+ <a href="http://www.moxiecode.com" target="_blank"><img src="themes/advanced/img/gotmoxie.png" alt="<?php esc_attr_e('Got Moxie?'); ?>" style="border: 0" /></a>
+ </div>
+
+</div>
+</div>
+
+<div class="mceActionPanel">
+ <div style="margin: 8px auto; text-align: center;padding-bottom: 10px;">
+ <input type="button" id="cancel" name="cancel" value="<?php esc_attr_e('Close'); ?>" title="<?php esc_attr_e('Close'); ?>" onclick="tinyMCEPopup.close();" />
+ </div>
+</div>
+<script type="text/javascript">
+ function d(id) { return document.getElementById(id); }
+
+ function flipTab(n) {
+ var i, c, t;
+
+ for ( i = 1; i <= 4; i++ ) {
+ c = d('content'+i.toString());
+ t = d('tab'+i.toString());
+ if ( n == i ) {
+ c.className = '';
+ t.className = 'current';
+ } else {
+ c.className = 'hidden';
+ t.className = '';
+ }
+ }
+ }
+
+ tinyMCEPopup.onInit.add(function() {
+ var win = tinyMCEPopup.getWin();
+
+ d('version').innerHTML = tinymce.majorVersion + "." + tinymce.minorVersion;
+ d('date').innerHTML = tinymce.releaseDate;
+
+ if ( win.fullscreen && win.fullscreen.settings.visible ) {
+ d('content1').className = 'hidden';
+ d('tabs').className = 'hidden';
+ d('content3').className = 'dfw';
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/src/wp-includes/js/tinymce/wp-tinymce-schema.js b/src/wp-includes/js/tinymce/wp-tinymce-schema.js
new file mode 100644
index 0000000000..503a56399b
--- /dev/null
+++ b/src/wp-includes/js/tinymce/wp-tinymce-schema.js
@@ -0,0 +1,940 @@
+/**
+ * TinyMCE Schema.js
+ *
+ * Duck-punched by WordPress core to support a sane schema superset.
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+(function(tinymce) {
+ var mapCache = {}, makeMap = tinymce.makeMap, each = tinymce.each;
+
+ function split(str, delim) {
+ return str.split(delim || ',');
+ };
+
+ /**
+ * Unpacks the specified lookup and string data it will also parse it into an object
+ * map with sub object for it's children. This will later also include the attributes.
+ */
+ function unpack(lookup, data) {
+ var key, elements = {};
+
+ function replace(value) {
+ return value.replace(/[A-Z]+/g, function(key) {
+ return replace(lookup[key]);
+ });
+ };
+
+ // Unpack lookup
+ for (key in lookup) {
+ if (lookup.hasOwnProperty(key))
+ lookup[key] = replace(lookup[key]);
+ }
+
+ // Unpack and parse data into object map
+ replace(data).replace(/#/g, '#text').replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g, function(str, name, attributes, children) {
+ attributes = split(attributes, '|');
+
+ elements[name] = {
+ attributes : makeMap(attributes),
+ attributesOrder : attributes,
+ children : makeMap(children, '|', {'#comment' : {}})
+ }
+ });
+
+ return elements;
+ };
+
+ /**
+ * Returns the HTML5 schema and caches it in the mapCache.
+ */
+ function getHTML5() {
+ var html5 = mapCache.html5;
+
+ if (!html5) {
+ html5 = mapCache.html5 = unpack({
+ A : 'accesskey|class|contextmenu|dir|draggable|dropzone|hidden|id|inert|itemid|itemprop|itemref|itemscope|itemtype|lang|spellcheck|style|tabindex|title|translate|item|role|subject|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
+ B : '#|a|abbr|area|audio|b|bdi|bdo|br|button|canvas|cite|code|command|data|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|math|meta|meter|noscript|object|output|progress|q|ruby|s|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|u|var|video|wbr',
+ C : '#|a|abbr|area|address|article|aside|audio|b|bdi|bdo|blockquote|br|button|canvas|cite|code|command|data|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|math|menu|meta|meter|nav|noscript|ol|object|output|p|pre|progress|q|ruby|s|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|u|ul|var|video|wbr'
+ }, 'html[A|manifest][body|head]' +
+ 'head[A][base|command|link|meta|noscript|script|style|title]' +
+ 'title[A][#]' +
+ 'base[A|href|target][]' +
+ 'link[A|href|rel|media|type|sizes|crossorigin|hreflang][]' +
+ 'meta[A|http-equiv|name|content|charset][]' +
+ 'style[A|type|media|scoped][#]' +
+ 'script[A|charset|type|src|defer|async|crossorigin][#]' +
+ 'noscript[A][C]' +
+ 'body[A|onafterprint|onbeforeprint|onbeforeunload|onblur|onerror|onfocus|onfullscreenchange|onfullscreenerror|onhashchange|onload|onmessage|onoffline|ononline|onpagehide|onpageshow|onpopstate|onresize|onscroll|onstorage|onunload][C]' +
+ 'section[A][C]' +
+ 'nav[A][C]' +
+ 'article[A][C]' +
+ 'aside[A][C]' +
+ 'h1[A][B]' +
+ 'h2[A][B]' +
+ 'h3[A][B]' +
+ 'h4[A][B]' +
+ 'h5[A][B]' +
+ 'h6[A][B]' +
+ 'hgroup[A][h1|h2|h3|h4|h5|h6]' +
+ 'header[A][C]' +
+ 'footer[A][C]' +
+ 'address[A][C]' +
+ 'p[A][B]' +
+ 'br[A][]' +
+ 'pre[A][B]' +
+ 'dialog[A|open][C|dd|dt]' +
+ 'blockquote[A|cite][C]' +
+ 'ol[A|start|reversed][li]' +
+ 'ul[A][li]' +
+ 'li[A|value][C]' +
+ 'dl[A][dd|dt]' +
+ 'dt[A][C|B]' +
+ 'dd[A][C]' +
+ 'a[A|href|target|download|ping|rel|media|type][B]' +
+ 'em[A][B]' +
+ 'strong[A][B]' +
+ 'small[A][B]' +
+ 's[A][B]' +
+ 'cite[A][B]' +
+ 'q[A|cite][B]' +
+ 'dfn[A][B]' +
+ 'abbr[A][B]' +
+ 'code[A][B]' +
+ 'var[A][B]' +
+ 'samp[A][B]' +
+ 'kbd[A][B]' +
+ 'sub[A][B]' +
+ 'sup[A][B]' +
+ 'i[A][B]' +
+ 'b[A][B]' +
+ 'u[A][B]' +
+ 'mark[A][B]' +
+ 'progress[A|value|max][B]' +
+ 'meter[A|value|min|max|low|high|optimum][B]' +
+ 'time[A|datetime][B]' +
+ 'ruby[A][B|rt|rp]' +
+ 'rt[A][B]' +
+ 'rp[A][B]' +
+ 'bdi[A][B]' +
+ 'bdo[A][B]' +
+ 'span[A][B]' +
+ 'ins[A|cite|datetime][C|B]' +
+ 'del[A|cite|datetime][C|B]' +
+ 'figure[A][C|legend|figcaption]' +
+ 'figcaption[A][C]' +
+ 'img[A|alt|src|srcset|crossorigin|usemap|ismap|width|height][]' +
+ 'iframe[A|name|src|srcdoc|height|width|sandbox|seamless|allowfullscreen][C|B]' +
+ 'embed[A|src|height|width|type][]' +
+ 'object[A|data|type|typemustmatch|name|usemap|form|width|height][C|B|param]' +
+ 'param[A|name|value][]' +
+ 'summary[A][B]' +
+ 'details[A|open][C|legend|summary]' +
+ 'command[A|type|label|icon|disabled|checked|radiogroup|command][]' +
+ 'menu[A|type|label][C|li]' +
+ 'legend[A][C|B]' +
+ 'div[A][C]' +
+ 'source[A|src|type|media][]' +
+ 'track[A|kind|src|srclang|label|default][]' +
+ 'audio[A|src|autobuffer|autoplay|loop|controls|crossorigin|preload|mediagroup|muted][C|source|track]' +
+ 'video[A|src|autobuffer|autoplay|loop|controls|width|height|poster|crossorigin|preload|mediagroup|muted][C|source|track]' +
+ 'hr[A][]' +
+ 'form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]' +
+ 'fieldset[A|disabled|form|name][C|legend]' +
+ 'label[A|form|for][B]' +
+ 'input[A|type|accept|alt|autocomplete|autofocus|checked|dirname|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|inputmode|list|max|maxlength|min|multiple|name|pattern|placeholder|readonly|required|size|src|step|value|width|files][]' +
+ 'button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|type|value][B]' +
+ 'select[A|autofocus|disabled|form|multiple|name|required|size][option|optgroup]' +
+ 'data[A|value][B]' +
+ 'datalist[A][B|option]' +
+ 'optgroup[A|disabled|label][option]' +
+ 'option[A|disabled|selected|label|value][#]' +
+ 'textarea[A|autocomplete|autofocus|cols|dirname|disabled|form|inputmode|maxlength|name|placeholder|readonly|required|rows|wrap][#]' +
+ 'keygen[A|autofocus|challenge|disabled|form|keytype|name][]' +
+ 'output[A|for|form|name][B]' +
+ 'canvas[A|width|height][a|button|input]' +
+ 'map[A|name][C|B]' +
+ 'area[A|alt|coords|shape|href|target|download|ping|rel|media|hreflang|type][]' +
+ 'math[A][]' +
+ 'svg[A][]' +
+ 'table[A][caption|colgroup|thead|tfoot|tbody|tr]' +
+ 'caption[A][C]' +
+ 'colgroup[A|span][col]' +
+ 'col[A|span][]' +
+ 'thead[A][tr]' +
+ 'tfoot[A][tr]' +
+ 'tbody[A][tr]' +
+ 'tr[A][th|td]' +
+ 'th[A|headers|rowspan|colspan|scope][C]' +
+ 'td[A|headers|rowspan|colspan][C]' +
+ 'wbr[A][]'
+ );
+ }
+
+ return html5;
+ };
+
+ /**
+ * Returns the HTML4 schema and caches it in the mapCache.
+ */
+ function getHTML4() {
+ var html4 = mapCache.html4;
+
+ if (!html4) {
+ // This is the XHTML 1.0 transitional elements with it's attributes and children packed to reduce it's size
+ html4 = mapCache.html4 = unpack({
+ Z : 'H|K|N|O|P',
+ Y : 'X|form|R|Q',
+ ZG : 'E|span|width|align|char|charoff|valign',
+ X : 'p|T|div|U|W|isindex|fieldset|table',
+ ZF : 'E|align|char|charoff|valign',
+ W : 'pre|hr|blockquote|address|center|noframes',
+ ZE : 'abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height',
+ ZD : '[E][S]',
+ U : 'ul|ol|dl|menu|dir',
+ ZC : 'p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q',
+ T : 'h1|h2|h3|h4|h5|h6',
+ ZB : 'X|S|Q',
+ S : 'R|P',
+ ZA : 'a|G|J|M|O|P',
+ R : 'a|H|K|N|O',
+ Q : 'noscript|P',
+ P : 'ins|del|script',
+ O : 'input|select|textarea|label|button',
+ N : 'M|L',
+ M : 'em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym',
+ L : 'sub|sup',
+ K : 'J|I',
+ J : 'tt|i|b|u|s|strike',
+ I : 'big|small|font|basefont',
+ H : 'G|F',
+ G : 'br|span|bdo',
+ F : 'object|applet|img|map|iframe',
+ E : 'A|B|C',
+ D : 'accesskey|tabindex|onfocus|onblur',
+ C : 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
+ B : 'lang|xml:lang|dir',
+ A : 'id|class|style|title'
+ }, 'script[id|charset|type|language|src|defer|xml:space][]' +
+ 'style[B|id|type|media|title|xml:space][]' +
+ 'object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]' +
+ 'param[id|name|value|valuetype|type][]' +
+ 'p[E|align][#|S]' +
+ 'a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]' +
+ 'br[A|clear][]' +
+ 'span[E][#|S]' +
+ 'bdo[A|C|B][#|S]' +
+ 'applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]' +
+ 'h1[E|align][#|S]' +
+ 'img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]' +
+ 'map[B|C|A|name][X|form|Q|area]' +
+ 'h2[E|align][#|S]' +
+ 'iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]' +
+ 'h3[E|align][#|S]' +
+ 'tt[E][#|S]' +
+ 'i[E][#|S]' +
+ 'b[E][#|S]' +
+ 'u[E][#|S]' +
+ 's[E][#|S]' +
+ 'strike[E][#|S]' +
+ 'big[E][#|S]' +
+ 'small[E][#|S]' +
+ 'font[A|B|size|color|face][#|S]' +
+ 'basefont[id|size|color|face][]' +
+ 'em[E][#|S]' +
+ 'strong[E][#|S]' +
+ 'dfn[E][#|S]' +
+ 'code[E][#|S]' +
+ 'q[E|cite][#|S]' +
+ 'samp[E][#|S]' +
+ 'kbd[E][#|S]' +
+ 'var[E][#|S]' +
+ 'cite[E][#|S]' +
+ 'abbr[E][#|S]' +
+ 'acronym[E][#|S]' +
+ 'sub[E][#|S]' +
+ 'sup[E][#|S]' +
+ 'input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]' +
+ 'select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]' +
+ 'optgroup[E|disabled|label][option]' +
+ 'option[E|selected|disabled|label|value][]' +
+ 'textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]' +
+ 'label[E|for|accesskey|onfocus|onblur][#|S]' +
+ 'button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]' +
+ 'h4[E|align][#|S]' +
+ 'ins[E|cite|datetime][#|Y]' +
+ 'h5[E|align][#|S]' +
+ 'del[E|cite|datetime][#|Y]' +
+ 'h6[E|align][#|S]' +
+ 'div[E|align][#|Y]' +
+ 'ul[E|type|compact][li]' +
+ 'li[E|type|value][#|Y]' +
+ 'ol[E|type|compact|start][li]' +
+ 'dl[E|compact][dt|dd]' +
+ 'dt[E][#|S]' +
+ 'dd[E][#|Y]' +
+ 'menu[E|compact][li]' +
+ 'dir[E|compact][li]' +
+ 'pre[E|width|xml:space][#|ZA]' +
+ 'hr[E|align|noshade|size|width][]' +
+ 'blockquote[E|cite][#|Y]' +
+ 'address[E][#|S|p]' +
+ 'center[E][#|Y]' +
+ 'noframes[E][#|Y]' +
+ 'isindex[A|B|prompt][]' +
+ 'fieldset[E][#|legend|Y]' +
+ 'legend[E|accesskey|align][#|S]' +
+ 'table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]' +
+ 'caption[E|align][#|S]' +
+ 'col[ZG][]' +
+ 'colgroup[ZG][col]' +
+ 'thead[ZF][tr]' +
+ 'tr[ZF|bgcolor][th|td]' +
+ 'th[E|ZE][#|Y]' +
+ 'form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]' +
+ 'noscript[E][#|Y]' +
+ 'td[E|ZE][#|Y]' +
+ 'tfoot[ZF][tr]' +
+ 'tbody[ZF][tr]' +
+ 'area[E|D|shape|coords|href|nohref|alt|target][]' +
+ 'base[id|href|target][]' +
+ 'body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]'
+ );
+ }
+
+ return html4;
+ };
+
+ /**
+ * WordPress Core
+ *
+ * Returns a schema that is the result of a deep merge between the HTML5
+ * and HTML4 schemas.
+ */
+ function getSaneSchema() {
+ var cachedMapCache = mapCache,
+ html5, html4;
+
+ if ( mapCache.sane )
+ return mapCache.sane;
+
+ // Bust the mapCache so we're not dealing with the other schema objects.
+ mapCache = {};
+ html5 = getHTML5();
+ html4 = getHTML4();
+ mapCache = cachedMapCache;
+
+ each( html4, function( html4settings, tag ) {
+ var html5settings = html5[ tag ],
+ difference = [];
+
+ // Merge tags missing in HTML5 mode.
+ if ( ! html5settings ) {
+ html5[ tag ] = html4settings;
+ return;
+ }
+
+ // Merge attributes missing from this HTML5 tag.
+ each( html4settings.attributes, function( attribute, key ) {
+ if ( ! html5settings.attributes[ key ] )
+ html5settings.attributes[ key ] = attribute;
+ });
+
+ // Merge any missing attributes into the attributes order.
+ each( html4settings.attributesOrder, function( key ) {
+ if ( -1 === tinymce.inArray( html5settings.attributesOrder, key ) )
+ difference.push( key );
+ });
+
+ html5settings.attributesOrder = html5settings.attributesOrder.concat( difference );
+
+ // Merge children missing from this HTML5 tag.
+ each( html4settings.children, function( child, key ) {
+ if ( ! html5settings.children[ key ] )
+ html5settings.children[ key ] = child;
+ });
+ });
+
+ return mapCache.sane = html5;
+ }
+
+ /**
+ * Schema validator class.
+ *
+ * @class tinymce.html.Schema
+ * @example
+ * if (tinymce.activeEditor.schema.isValidChild('p', 'span'))
+ * alert('span is valid child of p.');
+ *
+ * if (tinymce.activeEditor.schema.getElementRule('p'))
+ * alert('P is a valid element.');
+ *
+ * @class tinymce.html.Schema
+ * @version 3.4
+ */
+
+ /**
+ * Constructs a new Schema instance.
+ *
+ * @constructor
+ * @method Schema
+ * @param {Object} settings Name/value settings object.
+ */
+ tinymce.html.Schema = function(settings) {
+ var self = this, elements = {}, children = {}, patternElements = [], validStyles, schemaItems;
+ var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap, blockElementsMap, nonEmptyElementsMap, customElementsMap = {};
+
+ // Creates an lookup table map object for the specified option or the default value
+ function createLookupTable(option, default_value, extend) {
+ var value = settings[option];
+
+ if (!value) {
+ // Get cached default map or make it if needed
+ value = mapCache[option];
+
+ if (!value) {
+ value = makeMap(default_value, ' ', makeMap(default_value.toUpperCase(), ' '));
+ value = tinymce.extend(value, extend);
+
+ mapCache[option] = value;
+ }
+ } else {
+ // Create custom map
+ value = makeMap(value, ',', makeMap(value.toUpperCase(), ' '));
+ }
+
+ return value;
+ };
+
+ settings = settings || {};
+
+ /**
+ * WordPress core uses a sane schema in place of the default "HTML5" schema.
+ */
+ schemaItems = settings.schema == "html5" ? getSaneSchema() : getHTML4();
+
+ // Allow all elements and attributes if verify_html is set to false
+ if (settings.verify_html === false)
+ settings.valid_elements = '*[*]';
+
+ // Build styles list
+ if (settings.valid_styles) {
+ validStyles = {};
+
+ // Convert styles into a rule list
+ each(settings.valid_styles, function(value, key) {
+ validStyles[key] = tinymce.explode(value);
+ });
+ }
+
+ // Setup map objects
+ whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea');
+ selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
+ shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link meta param embed source wbr');
+ boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls');
+ nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object', shortEndedElementsMap);
+ textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
+ 'blockquote center dir fieldset header footer article section hgroup aside nav figure');
+ blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
+ 'th tr td li ol ul caption dl dt dd noscript menu isindex option datalist select optgroup', textBlockElementsMap);
+
+ // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
+ function patternToRegExp(str) {
+ return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
+ };
+
+ // Parses the specified valid_elements string and adds to the current rules
+ // This function is a bit hard to read since it's heavily optimized for speed
+ function addValidElements(valid_elements) {
+ var ei, el, ai, al, yl, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder,
+ prefix, outputName, globalAttributes, globalAttributesOrder, transElement, key, childKey, value,
+ elementRuleRegExp = /^([#+\-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,
+ attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,
+ hasPatternsRegExp = /[*?+]/;
+
+ if (valid_elements) {
+ // Split valid elements into an array with rules
+ valid_elements = split(valid_elements);
+
+ if (elements['@']) {
+ globalAttributes = elements['@'].attributes;
+ globalAttributesOrder = elements['@'].attributesOrder;
+ }
+
+ // Loop all rules
+ for (ei = 0, el = valid_elements.length; ei < el; ei++) {
+ // Parse element rule
+ matches = elementRuleRegExp.exec(valid_elements[ei]);
+ if (matches) {
+ // Setup local names for matches
+ prefix = matches[1];
+ elementName = matches[2];
+ outputName = matches[3];
+ attrData = matches[4];
+
+ // Create new attributes and attributesOrder
+ attributes = {};
+ attributesOrder = [];
+
+ // Create the new element
+ element = {
+ attributes : attributes,
+ attributesOrder : attributesOrder
+ };
+
+ // Padd empty elements prefix
+ if (prefix === '#')
+ element.paddEmpty = true;
+
+ // Remove empty elements prefix
+ if (prefix === '-')
+ element.removeEmpty = true;
+
+ // Copy attributes from global rule into current rule
+ if (globalAttributes) {
+ for (key in globalAttributes)
+ attributes[key] = globalAttributes[key];
+
+ attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
+ }
+
+ // Attributes defined
+ if (attrData) {
+ attrData = split(attrData, '|');
+ for (ai = 0, al = attrData.length; ai < al; ai++) {
+ matches = attrRuleRegExp.exec(attrData[ai]);
+ if (matches) {
+ attr = {};
+ attrType = matches[1];
+ attrName = matches[2].replace(/::/g, ':');
+ prefix = matches[3];
+ value = matches[4];
+
+ // Required
+ if (attrType === '!') {
+ element.attributesRequired = element.attributesRequired || [];
+ element.attributesRequired.push(attrName);
+ attr.required = true;
+ }
+
+ // Denied from global
+ if (attrType === '-') {
+ delete attributes[attrName];
+ attributesOrder.splice(tinymce.inArray(attributesOrder, attrName), 1);
+ continue;
+ }
+
+ // Default value
+ if (prefix) {
+ // Default value
+ if (prefix === '=') {
+ element.attributesDefault = element.attributesDefault || [];
+ element.attributesDefault.push({name: attrName, value: value});
+ attr.defaultValue = value;
+ }
+
+ // Forced value
+ if (prefix === ':') {
+ element.attributesForced = element.attributesForced || [];
+ element.attributesForced.push({name: attrName, value: value});
+ attr.forcedValue = value;
+ }
+
+ // Required values
+ if (prefix === '<')
+ attr.validValues = makeMap(value, '?');
+ }
+
+ // Check for attribute patterns
+ if (hasPatternsRegExp.test(attrName)) {
+ element.attributePatterns = element.attributePatterns || [];
+ attr.pattern = patternToRegExp(attrName);
+ element.attributePatterns.push(attr);
+ } else {
+ // Add attribute to order list if it doesn't already exist
+ if (!attributes[attrName])
+ attributesOrder.push(attrName);
+
+ attributes[attrName] = attr;
+ }
+ }
+ }
+ }
+
+ // Global rule, store away these for later usage
+ if (!globalAttributes && elementName == '@') {
+ globalAttributes = attributes;
+ globalAttributesOrder = attributesOrder;
+ }
+
+ // Handle substitute elements such as b/strong
+ if (outputName) {
+ element.outputName = elementName;
+ elements[outputName] = element;
+ }
+
+ // Add pattern or exact element
+ if (hasPatternsRegExp.test(elementName)) {
+ element.pattern = patternToRegExp(elementName);
+ patternElements.push(element);
+ } else
+ elements[elementName] = element;
+ }
+ }
+ }
+ };
+
+ function setValidElements(valid_elements) {
+ elements = {};
+ patternElements = [];
+
+ addValidElements(valid_elements);
+
+ each(schemaItems, function(element, name) {
+ children[name] = element.children;
+ });
+ };
+
+ // Adds custom non HTML elements to the schema
+ function addCustomElements(custom_elements) {
+ var customElementRegExp = /^(~)?(.+)$/;
+
+ if (custom_elements) {
+ each(split(custom_elements), function(rule) {
+ var matches = customElementRegExp.exec(rule),
+ inline = matches[1] === '~',
+ cloneName = inline ? 'span' : 'div',
+ name = matches[2];
+
+ children[name] = children[cloneName];
+ customElementsMap[name] = cloneName;
+
+ // If it's not marked as inline then add it to valid block elements
+ if (!inline) {
+ blockElementsMap[name.toUpperCase()] = {};
+ blockElementsMap[name] = {};
+ }
+
+ // Add elements clone if needed
+ if (!elements[name]) {
+ elements[name] = elements[cloneName];
+ }
+
+ // Add custom elements at span/div positions
+ each(children, function(element, child) {
+ if (element[cloneName])
+ element[name] = element[cloneName];
+ });
+ });
+ }
+ };
+
+ // Adds valid children to the schema object
+ function addValidChildren(valid_children) {
+ var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
+
+ if (valid_children) {
+ each(split(valid_children), function(rule) {
+ var matches = childRuleRegExp.exec(rule), parent, prefix;
+
+ if (matches) {
+ prefix = matches[1];
+
+ // Add/remove items from default
+ if (prefix)
+ parent = children[matches[2]];
+ else
+ parent = children[matches[2]] = {'#comment' : {}};
+
+ parent = children[matches[2]];
+
+ each(split(matches[3], '|'), function(child) {
+ if (prefix === '-')
+ delete parent[child];
+ else
+ parent[child] = {};
+ });
+ }
+ });
+ }
+ };
+
+ function getElementRule(name) {
+ var element = elements[name], i;
+
+ // Exact match found
+ if (element)
+ return element;
+
+ // No exact match then try the patterns
+ i = patternElements.length;
+ while (i--) {
+ element = patternElements[i];
+
+ if (element.pattern.test(name))
+ return element;
+ }
+ };
+
+ if (!settings.valid_elements) {
+ // No valid elements defined then clone the elements from the schema spec
+ each(schemaItems, function(element, name) {
+ elements[name] = {
+ attributes : element.attributes,
+ attributesOrder : element.attributesOrder
+ };
+
+ children[name] = element.children;
+ });
+
+ // Switch these on HTML4
+ if (settings.schema != "html5") {
+ each(split('strong/b,em/i'), function(item) {
+ item = split(item, '/');
+ elements[item[1]].outputName = item[0];
+ });
+ }
+
+ // Add default alt attribute for images
+ elements.img.attributesDefault = [{name: 'alt', value: ''}];
+
+ // Remove these if they are empty by default
+ each(split('ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr'), function(name) {
+ if (elements[name]) {
+ elements[name].removeEmpty = true;
+ }
+ });
+
+ // Padd these by default
+ each(split('p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption'), function(name) {
+ elements[name].paddEmpty = true;
+ });
+ } else
+ setValidElements(settings.valid_elements);
+
+ addCustomElements(settings.custom_elements);
+ addValidChildren(settings.valid_children);
+ addValidElements(settings.extended_valid_elements);
+
+ // Todo: Remove this when we fix list handling to be valid
+ addValidChildren('+ol[ul|ol],+ul[ul|ol]');
+
+ // Delete invalid elements
+ if (settings.invalid_elements) {
+ tinymce.each(tinymce.explode(settings.invalid_elements), function(item) {
+ if (elements[item])
+ delete elements[item];
+ });
+ }
+
+ // If the user didn't allow span only allow internal spans
+ if (!getElementRule('span'))
+ addValidElements('span[!data-mce-type|*]');
+
+ /**
+ * Name/value map object with valid parents and children to those parents.
+ *
+ * @example
+ * children = {
+ * div:{p:{}, h1:{}}
+ * };
+ * @field children
+ * @type {Object}
+ */
+ self.children = children;
+
+ /**
+ * Name/value map object with valid styles for each element.
+ *
+ * @field styles
+ * @type {Object}
+ */
+ self.styles = validStyles;
+
+ /**
+ * Returns a map with boolean attributes.
+ *
+ * @method getBoolAttrs
+ * @return {Object} Name/value lookup map for boolean attributes.
+ */
+ self.getBoolAttrs = function() {
+ return boolAttrMap;
+ };
+
+ /**
+ * Returns a map with block elements.
+ *
+ * @method getBlockElements
+ * @return {Object} Name/value lookup map for block elements.
+ */
+ self.getBlockElements = function() {
+ return blockElementsMap;
+ };
+
+ /**
+ * Returns a map with text block elements. Such as: p,h1-h6,div,address
+ *
+ * @method getTextBlockElements
+ * @return {Object} Name/value lookup map for block elements.
+ */
+ self.getTextBlockElements = function() {
+ return textBlockElementsMap;
+ };
+
+ /**
+ * Returns a map with short ended elements such as BR or IMG.
+ *
+ * @method getShortEndedElements
+ * @return {Object} Name/value lookup map for short ended elements.
+ */
+ self.getShortEndedElements = function() {
+ return shortEndedElementsMap;
+ };
+
+ /**
+ * Returns a map with self closing tags such as <li>.
+ *
+ * @method getSelfClosingElements
+ * @return {Object} Name/value lookup map for self closing tags elements.
+ */
+ self.getSelfClosingElements = function() {
+ return selfClosingElementsMap;
+ };
+
+ /**
+ * Returns a map with elements that should be treated as contents regardless if it has text
+ * content in them or not such as TD, VIDEO or IMG.
+ *
+ * @method getNonEmptyElements
+ * @return {Object} Name/value lookup map for non empty elements.
+ */
+ self.getNonEmptyElements = function() {
+ return nonEmptyElementsMap;
+ };
+
+ /**
+ * Returns a map with elements where white space is to be preserved like PRE or SCRIPT.
+ *
+ * @method getWhiteSpaceElements
+ * @return {Object} Name/value lookup map for white space elements.
+ */
+ self.getWhiteSpaceElements = function() {
+ return whiteSpaceElementsMap;
+ };
+
+ /**
+ * Returns true/false if the specified element and it's child is valid or not
+ * according to the schema.
+ *
+ * @method isValidChild
+ * @param {String} name Element name to check for.
+ * @param {String} child Element child to verify.
+ * @return {Boolean} True/false if the element is a valid child of the specified parent.
+ */
+ self.isValidChild = function(name, child) {
+ var parent = children[name];
+
+ return !!(parent && parent[child]);
+ };
+
+ /**
+ * Returns true/false if the specified element name and optional attribute is
+ * valid according to the schema.
+ *
+ * @method isValid
+ * @param {String} name Name of element to check.
+ * @param {String} attr Optional attribute name to check for.
+ * @return {Boolean} True/false if the element and attribute is valid.
+ */
+ self.isValid = function(name, attr) {
+ var attrPatterns, i, rule = getElementRule(name);
+
+ // Check if it's a valid element
+ if (rule) {
+ if (attr) {
+ // Check if attribute name exists
+ if (rule.attributes[attr]) {
+ return true;
+ }
+
+ // Check if attribute matches a regexp pattern
+ attrPatterns = rule.attributePatterns;
+ if (attrPatterns) {
+ i = attrPatterns.length;
+ while (i--) {
+ if (attrPatterns[i].pattern.test(name)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+
+ // No match
+ return false;
+ };
+
+ /**
+ * Returns true/false if the specified element is valid or not
+ * according to the schema.
+ *
+ * @method getElementRule
+ * @param {String} name Element name to check for.
+ * @return {Object} Element object or undefined if the element isn't valid.
+ */
+ self.getElementRule = getElementRule;
+
+ /**
+ * Returns an map object of all custom elements.
+ *
+ * @method getCustomElements
+ * @return {Object} Name/value map object of all custom elements.
+ */
+ self.getCustomElements = function() {
+ return customElementsMap;
+ };
+
+ /**
+ * Parses a valid elements string and adds it to the schema. The valid elements format is for example "element[attr=default|otherattr]".
+ * Existing rules will be replaced with the ones specified, so this extends the schema.
+ *
+ * @method addValidElements
+ * @param {String} valid_elements String in the valid elements format to be parsed.
+ */
+ self.addValidElements = addValidElements;
+
+ /**
+ * Parses a valid elements string and sets it to the schema. The valid elements format is for example "element[attr=default|otherattr]".
+ * Existing rules will be replaced with the ones specified, so this extends the schema.
+ *
+ * @method setValidElements
+ * @param {String} valid_elements String in the valid elements format to be parsed.
+ */
+ self.setValidElements = setValidElements;
+
+ /**
+ * Adds custom non HTML elements to the schema.
+ *
+ * @method addCustomElements
+ * @param {String} custom_elements Comma separated list of custom elements to add.
+ */
+ self.addCustomElements = addCustomElements;
+
+ /**
+ * Parses a valid children string and adds them to the schema structure. The valid children format is for example: "element[child1|child2]".
+ *
+ * @method addValidChildren
+ * @param {String} valid_children Valid children elements string to parse
+ */
+ self.addValidChildren = addValidChildren;
+
+ self.elements = elements;
+ };
+})(tinymce);
diff --git a/src/wp-includes/js/tinymce/wp-tinymce.js.gz b/src/wp-includes/js/tinymce/wp-tinymce.js.gz
new file mode 100644
index 0000000000..600163f068
--- /dev/null
+++ b/src/wp-includes/js/tinymce/wp-tinymce.js.gz
Binary files differ
diff --git a/src/wp-includes/js/tinymce/wp-tinymce.php b/src/wp-includes/js/tinymce/wp-tinymce.php
new file mode 100644
index 0000000000..83a003d720
--- /dev/null
+++ b/src/wp-includes/js/tinymce/wp-tinymce.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Disable error reporting
+ *
+ * Set this to error_reporting( E_ALL ) or error_reporting( E_ALL | E_STRICT ) for debugging
+ */
+error_reporting(0);
+
+$basepath = dirname(__FILE__);
+
+function get_file($path) {
+
+ if ( function_exists('realpath') )
+ $path = realpath($path);
+
+ if ( ! $path || ! @is_file($path) )
+ return false;
+
+ return @file_get_contents($path);
+}
+
+$expires_offset = 31536000; // 1 year
+
+header('Content-Type: application/x-javascript; charset=UTF-8');
+header('Vary: Accept-Encoding'); // Handle proxies
+header('Expires: ' . gmdate( "D, d M Y H:i:s", time() + $expires_offset ) . ' GMT');
+header("Cache-Control: public, max-age=$expires_offset");
+
+if ( isset($_GET['c']) && 1 == $_GET['c'] && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
+ && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && ( $file = get_file($basepath . '/wp-tinymce.js.gz') ) ) {
+
+ header('Content-Encoding: gzip');
+ echo $file;
+} else {
+ echo get_file($basepath . '/tiny_mce.js');
+ echo get_file($basepath . '/wp-tinymce-schema.js');
+}
+exit;
diff --git a/src/wp-includes/js/tw-sack.js b/src/wp-includes/js/tw-sack.js
new file mode 100644
index 0000000000..f93f2a429c
--- /dev/null
+++ b/src/wp-includes/js/tw-sack.js
@@ -0,0 +1,193 @@
+/* Simple AJAX Code-Kit (SACK) v1.6.1 */
+/* ©2005 Gregory Wild-Smith */
+/* www.twilightuniverse.com */
+/* Software licenced under a modified X11 licence,
+ see documentation or authors website for more details */
+
+function sack(file) {
+ this.xmlhttp = null;
+
+ this.resetData = function() {
+ this.method = "POST";
+ this.queryStringSeparator = "?";
+ this.argumentSeparator = "&";
+ this.URLString = "";
+ this.encodeURIString = true;
+ this.execute = false;
+ this.element = null;
+ this.elementObj = null;
+ this.requestFile = file;
+ this.vars = new Object();
+ this.responseStatus = new Array(2);
+ };
+
+ this.resetFunctions = function() {
+ this.onLoading = function() { };
+ this.onLoaded = function() { };
+ this.onInteractive = function() { };
+ this.onCompletion = function() { };
+ this.onError = function() { };
+ this.onFail = function() { };
+ };
+
+ this.reset = function() {
+ this.resetFunctions();
+ this.resetData();
+ };
+
+ this.createAJAX = function() {
+ try {
+ this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
+ } catch (e1) {
+ try {
+ this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
+ } catch (e2) {
+ this.xmlhttp = null;
+ }
+ }
+
+ if (! this.xmlhttp) {
+ if (typeof XMLHttpRequest != "undefined") {
+ this.xmlhttp = new XMLHttpRequest();
+ } else {
+ this.failed = true;
+ }
+ }
+ };
+
+ this.setVar = function(name, value){
+ this.vars[name] = Array(value, false);
+ };
+
+ this.encVar = function(name, value, returnvars) {
+ if (true == returnvars) {
+ return Array(encodeURIComponent(name), encodeURIComponent(value));
+ } else {
+ this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true);
+ }
+ }
+
+ this.processURLString = function(string, encode) {
+ encoded = encodeURIComponent(this.argumentSeparator);
+ regexp = new RegExp(this.argumentSeparator + "|" + encoded);
+ varArray = string.split(regexp);
+ for (i = 0; i < varArray.length; i++){
+ urlVars = varArray[i].split("=");
+ if (true == encode){
+ this.encVar(urlVars[0], urlVars[1]);
+ } else {
+ this.setVar(urlVars[0], urlVars[1]);
+ }
+ }
+ }
+
+ this.createURLString = function(urlstring) {
+ if (this.encodeURIString && this.URLString.length) {
+ this.processURLString(this.URLString, true);
+ }
+
+ if (urlstring) {
+ if (this.URLString.length) {
+ this.URLString += this.argumentSeparator + urlstring;
+ } else {
+ this.URLString = urlstring;
+ }
+ }
+
+ // prevents caching of URLString
+ this.setVar("rndval", new Date().getTime());
+
+ urlstringtemp = new Array();
+ for (key in this.vars) {
+ if (false == this.vars[key][1] && true == this.encodeURIString) {
+ encoded = this.encVar(key, this.vars[key][0], true);
+ delete this.vars[key];
+ this.vars[encoded[0]] = Array(encoded[1], true);
+ key = encoded[0];
+ }
+
+ urlstringtemp[urlstringtemp.length] = key + "=" + this.vars[key][0];
+ }
+ if (urlstring){
+ this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator);
+ } else {
+ this.URLString += urlstringtemp.join(this.argumentSeparator);
+ }
+ }
+
+ this.runResponse = function() {
+ eval(this.response);
+ }
+
+ this.runAJAX = function(urlstring) {
+ if (this.failed) {
+ this.onFail();
+ } else {
+ this.createURLString(urlstring);
+ if (this.element) {
+ this.elementObj = document.getElementById(this.element);
+ }
+ if (this.xmlhttp) {
+ var self = this;
+ if (this.method == "GET") {
+ totalurlstring = this.requestFile + this.queryStringSeparator + this.URLString;
+ this.xmlhttp.open(this.method, totalurlstring, true);
+ } else {
+ this.xmlhttp.open(this.method, this.requestFile, true);
+ try {
+ this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
+ } catch (e) { }
+ }
+
+ this.xmlhttp.onreadystatechange = function() {
+ switch (self.xmlhttp.readyState) {
+ case 1:
+ self.onLoading();
+ break;
+ case 2:
+ self.onLoaded();
+ break;
+ case 3:
+ self.onInteractive();
+ break;
+ case 4:
+ self.response = self.xmlhttp.responseText;
+ self.responseXML = self.xmlhttp.responseXML;
+ self.responseStatus[0] = self.xmlhttp.status;
+ self.responseStatus[1] = self.xmlhttp.statusText;
+
+ if (self.execute) {
+ self.runResponse();
+ }
+
+ if (self.elementObj) {
+ elemNodeName = self.elementObj.nodeName;
+ elemNodeName.toLowerCase();
+ if (elemNodeName == "input"
+ || elemNodeName == "select"
+ || elemNodeName == "option"
+ || elemNodeName == "textarea") {
+ self.elementObj.value = self.response;
+ } else {
+ self.elementObj.innerHTML = self.response;
+ }
+ }
+ if (self.responseStatus[0] == "200") {
+ self.onCompletion();
+ } else {
+ self.onError();
+ }
+
+ self.URLString = "";
+ break;
+ }
+ };
+
+ this.xmlhttp.send(this.URLString);
+ }
+ }
+ };
+
+ this.reset();
+ this.createAJAX();
+}
diff --git a/src/wp-includes/js/underscore.min.js b/src/wp-includes/js/underscore.min.js
new file mode 100644
index 0000000000..88d63a5b46
--- /dev/null
+++ b/src/wp-includes/js/underscore.min.js
@@ -0,0 +1,5 @@
+// Underscore.js 1.4.4
+// http://underscorejs.org
+// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore may be freely distributed under the MIT license.
+(function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),"value")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this); \ No newline at end of file
diff --git a/src/wp-includes/js/utils.js b/src/wp-includes/js/utils.js
new file mode 100644
index 0000000000..d7566362a4
--- /dev/null
+++ b/src/wp-includes/js/utils.js
@@ -0,0 +1,171 @@
+// utility functions
+
+var wpCookies = {
+// The following functions are from Cookie.js class in TinyMCE, Moxiecode, used under LGPL.
+
+ each : function(obj, cb, scope) {
+ var n, l;
+
+ if ( !obj )
+ return 0;
+
+ scope = scope || obj;
+
+ if ( typeof(obj.length) != 'undefined' ) {
+ for ( n = 0, l = obj.length; n < l; n++ ) {
+ if ( cb.call(scope, obj[n], n, obj) === false )
+ return 0;
+ }
+ } else {
+ for ( n in obj ) {
+ if ( obj.hasOwnProperty(n) ) {
+ if ( cb.call(scope, obj[n], n, obj) === false ) {
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+ },
+
+ /**
+ * Get a multi-values cookie.
+ * Returns a JS object with the name: 'value' pairs.
+ */
+ getHash : function(name) {
+ var all = this.get(name), ret;
+
+ if ( all ) {
+ this.each( all.split('&'), function(pair) {
+ pair = pair.split('=');
+ ret = ret || {};
+ ret[pair[0]] = pair[1];
+ });
+ }
+ return ret;
+ },
+
+ /**
+ * Set a multi-values cookie.
+ *
+ * 'values_obj' is the JS object that is stored. It is encoded as URI in wpCookies.set().
+ */
+ setHash : function(name, values_obj, expires, path, domain, secure) {
+ var str = '';
+
+ this.each(values_obj, function(val, key) {
+ str += (!str ? '' : '&') + key + '=' + val;
+ });
+
+ this.set(name, str, expires, path, domain, secure);
+ },
+
+ /**
+ * Get a cookie.
+ */
+ get : function(name) {
+ var cookie = document.cookie, e, p = name + "=", b;
+
+ if ( !cookie )
+ return;
+
+ b = cookie.indexOf("; " + p);
+
+ if ( b == -1 ) {
+ b = cookie.indexOf(p);
+
+ if ( b != 0 )
+ return null;
+
+ } else {
+ b += 2;
+ }
+
+ e = cookie.indexOf(";", b);
+
+ if ( e == -1 )
+ e = cookie.length;
+
+ return decodeURIComponent( cookie.substring(b + p.length, e) );
+ },
+
+ /**
+ * Set a cookie.
+ *
+ * The 'expires' arg can be either a JS Date() object set to the expiration date (back-compat)
+ * or the number of seconds until expiration
+ */
+ set : function(name, value, expires, path, domain, secure) {
+ var d = new Date();
+
+ if ( typeof(expires) == 'object' && expires.toGMTString ) {
+ expires = expires.toGMTString();
+ } else if ( parseInt(expires, 10) ) {
+ d.setTime( d.getTime() + ( parseInt(expires, 10) * 1000 ) ); // time must be in miliseconds
+ expires = d.toGMTString();
+ } else {
+ expires = '';
+ }
+
+ document.cookie = name + "=" + encodeURIComponent(value) +
+ ((expires) ? "; expires=" + expires : "") +
+ ((path) ? "; path=" + path : "") +
+ ((domain) ? "; domain=" + domain : "") +
+ ((secure) ? "; secure" : "");
+ },
+
+ /**
+ * Remove a cookie.
+ *
+ * This is done by setting it to an empty value and setting the expiration time in the past.
+ */
+ remove : function(name, path) {
+ this.set(name, '', -1000, path);
+ }
+};
+
+// Returns the value as string. Second arg or empty string is returned when value is not set.
+function getUserSetting( name, def ) {
+ var obj = getAllUserSettings();
+
+ if ( obj.hasOwnProperty(name) )
+ return obj[name];
+
+ if ( typeof def != 'undefined' )
+ return def;
+
+ return '';
+}
+
+// Both name and value must be only ASCII letters, numbers or underscore
+// and the shorter, the better (cookies can store maximum 4KB). Not suitable to store text.
+function setUserSetting( name, value, _del ) {
+ if ( 'object' !== typeof userSettings )
+ return false;
+
+ var cookie = 'wp-settings-' + userSettings.uid, all = wpCookies.getHash(cookie) || {}, path = userSettings.url,
+ n = name.toString().replace(/[^A-Za-z0-9_]/, ''), v = value.toString().replace(/[^A-Za-z0-9_]/, '');
+
+ if ( _del ) {
+ delete all[n];
+ } else {
+ all[n] = v;
+ }
+
+ wpCookies.setHash(cookie, all, 31536000, path);
+ wpCookies.set('wp-settings-time-'+userSettings.uid, userSettings.time, 31536000, path);
+
+ return name;
+}
+
+function deleteUserSetting( name ) {
+ return setUserSetting( name, '', 1 );
+}
+
+// Returns all settings as js object.
+function getAllUserSettings() {
+ if ( 'object' !== typeof userSettings )
+ return {};
+
+ return wpCookies.getHash('wp-settings-' + userSettings.uid) || {};
+}
diff --git a/src/wp-includes/js/wp-ajax-response.js b/src/wp-includes/js/wp-ajax-response.js
new file mode 100644
index 0000000000..d5b003cf56
--- /dev/null
+++ b/src/wp-includes/js/wp-ajax-response.js
@@ -0,0 +1,64 @@
+var wpAjax = jQuery.extend( {
+ unserialize: function( s ) {
+ var r = {}, q, pp, i, p;
+ if ( !s ) { return r; }
+ q = s.split('?'); if ( q[1] ) { s = q[1]; }
+ pp = s.split('&');
+ for ( i in pp ) {
+ if ( jQuery.isFunction(pp.hasOwnProperty) && !pp.hasOwnProperty(i) ) { continue; }
+ p = pp[i].split('=');
+ r[p[0]] = p[1];
+ }
+ return r;
+ },
+ parseAjaxResponse: function( x, r, e ) { // 1 = good, 0 = strange (bad data?), -1 = you lack permission
+ var parsed = {}, re = jQuery('#' + r).html(''), err = '';
+
+ if ( x && typeof x == 'object' && x.getElementsByTagName('wp_ajax') ) {
+ parsed.responses = [];
+ parsed.errors = false;
+ jQuery('response', x).each( function() {
+ var th = jQuery(this), child = jQuery(this.firstChild), response;
+ response = { action: th.attr('action'), what: child.get(0).nodeName, id: child.attr('id'), oldId: child.attr('old_id'), position: child.attr('position') };
+ response.data = jQuery( 'response_data', child ).text();
+ response.supplemental = {};
+ if ( !jQuery( 'supplemental', child ).children().each( function() {
+ response.supplemental[this.nodeName] = jQuery(this).text();
+ } ).size() ) { response.supplemental = false }
+ response.errors = [];
+ if ( !jQuery('wp_error', child).each( function() {
+ var code = jQuery(this).attr('code'), anError, errorData, formField;
+ anError = { code: code, message: this.firstChild.nodeValue, data: false };
+ errorData = jQuery('wp_error_data[code="' + code + '"]', x);
+ if ( errorData ) { anError.data = errorData.get(); }
+ formField = jQuery( 'form-field', errorData ).text();
+ if ( formField ) { code = formField; }
+ if ( e ) { wpAjax.invalidateForm( jQuery('#' + e + ' :input[name="' + code + '"]' ).parents('.form-field:first') ); }
+ err += '<p>' + anError.message + '</p>';
+ response.errors.push( anError );
+ parsed.errors = true;
+ } ).size() ) { response.errors = false; }
+ parsed.responses.push( response );
+ } );
+ if ( err.length ) { re.html( '<div class="error">' + err + '</div>' ); }
+ return parsed;
+ }
+ if ( isNaN(x) ) { return !re.html('<div class="error"><p>' + x + '</p></div>'); }
+ x = parseInt(x,10);
+ if ( -1 == x ) { return !re.html('<div class="error"><p>' + wpAjax.noPerm + '</p></div>'); }
+ else if ( 0 === x ) { return !re.html('<div class="error"><p>' + wpAjax.broken + '</p></div>'); }
+ return true;
+ },
+ invalidateForm: function ( selector ) {
+ return jQuery( selector ).addClass( 'form-invalid' ).find('input:visible').change( function() { jQuery(this).closest('.form-invalid').removeClass( 'form-invalid' ); } );
+ },
+ validateForm: function( selector ) {
+ selector = jQuery( selector );
+ return !wpAjax.invalidateForm( selector.find('.form-required').filter( function() { return jQuery('input:visible', this).val() == ''; } ) ).size();
+ }
+}, wpAjax || { noPerm: 'You do not have permission to do that.', broken: 'An unidentified error has occurred.' } );
+
+// Basic form validation
+jQuery(document).ready( function($){
+ $('form.validate').submit( function() { return wpAjax.validateForm( $(this) ); } );
+});
diff --git a/src/wp-includes/js/wp-auth-check.js b/src/wp-includes/js/wp-auth-check.js
new file mode 100644
index 0000000000..667143de5d
--- /dev/null
+++ b/src/wp-includes/js/wp-auth-check.js
@@ -0,0 +1,106 @@
+// Interim login dialog
+(function($){
+ var wrap, check, next;
+
+ function show() {
+ var parent = $('#wp-auth-check'), form = $('#wp-auth-check-form'), noframe = wrap.find('.wp-auth-fallback-expired'), frame, loaded = false;
+
+ if ( form.length ) {
+ // Add unload confirmation to counter (frame-busting) JS redirects
+ $(window).on( 'beforeunload.wp-auth-check', function(e) {
+ e.originalEvent.returnValue = window.authcheckL10n.beforeunload;
+ });
+
+ frame = $('<iframe id="wp-auth-check-frame" frameborder="0">').attr( 'title', noframe.text() );
+ frame.load( function(e) {
+ var height, body;
+
+ loaded = true;
+
+ try {
+ body = $(this).contents().find('body');
+ height = body.height();
+ } catch(e) {
+ wrap.addClass('fallback');
+ parent.css( 'max-height', '' );
+ form.remove();
+ noframe.focus();
+ return;
+ }
+
+ if ( height ) {
+ if ( body && body.hasClass('interim-login-success') )
+ hide();
+ else
+ parent.css( 'max-height', height + 40 + 'px' );
+ } else if ( ! body || ! body.length ) {
+ // Catch "silent" iframe origin exceptions in WebKit after another page is loaded in the iframe
+ wrap.addClass('fallback');
+ parent.css( 'max-height', '' );
+ form.remove();
+ noframe.focus();
+ }
+ }).attr( 'src', form.data('src') );
+
+ $('#wp-auth-check-form').append( frame );
+ }
+
+ wrap.removeClass('hidden');
+
+ if ( frame ) {
+ frame.focus();
+ // WebKit doesn't throw an error if the iframe fails to load because of "X-Frame-Options: DENY" header.
+ // Wait for 10 sec. and switch to the fallback text.
+ setTimeout( function() {
+ if ( ! loaded ) {
+ wrap.addClass('fallback');
+ form.remove();
+ noframe.focus();
+ }
+ }, 10000 );
+ } else {
+ noframe.focus();
+ }
+ }
+
+ function hide() {
+ $(window).off( 'beforeunload.wp-auth-check' );
+
+ // When on the Edit Post screen, speed up heartbeat after the user logs in to quickly refresh nonces
+ if ( typeof adminpage != 'undefined' && ( adminpage == 'post-php' || adminpage == 'post-new-php' )
+ && typeof wp != 'undefined' && wp.heartbeat ) {
+
+ wp.heartbeat.interval( 'fast', 1 );
+ }
+
+ wrap.fadeOut( 200, function() {
+ wrap.addClass('hidden').css('display', '');
+ $('#wp-auth-check-frame').remove();
+ });
+ }
+
+ function schedule() {
+ var interval = parseInt( window.authcheckL10n.interval, 10 ) || 180; // in seconds, default 3 min.
+ next = ( new Date() ).getTime() + ( interval * 1000 );
+ }
+
+ $( document ).on( 'heartbeat-tick.wp-auth-check', function( e, data ) {
+ if ( 'wp-auth-check' in data ) {
+ schedule();
+ if ( ! data['wp-auth-check'] && wrap.hasClass('hidden') )
+ show();
+ else if ( data['wp-auth-check'] && ! wrap.hasClass('hidden') )
+ hide();
+ }
+ }).on( 'heartbeat-send.wp-auth-check', function( e, data ) {
+ if ( ( new Date() ).getTime() > next )
+ data['wp-auth-check'] = true;
+ }).ready( function() {
+ schedule();
+ wrap = $('#wp-auth-check-wrap');
+ wrap.find('.wp-auth-check-close').on( 'click', function(e) {
+ hide();
+ });
+ });
+
+}(jQuery));
diff --git a/src/wp-includes/js/wp-backbone.js b/src/wp-includes/js/wp-backbone.js
new file mode 100644
index 0000000000..9e0041d4d0
--- /dev/null
+++ b/src/wp-includes/js/wp-backbone.js
@@ -0,0 +1,384 @@
+window.wp = window.wp || {};
+
+(function ($) {
+ // Create the WordPress Backbone namespace.
+ wp.Backbone = {};
+
+
+ // wp.Backbone.Subviews
+ // --------------------
+ //
+ // A subview manager.
+ wp.Backbone.Subviews = function( view, views ) {
+ this.view = view;
+ this._views = _.isArray( views ) ? { '': views } : views || {};
+ };
+
+ wp.Backbone.Subviews.extend = Backbone.Model.extend;
+
+ _.extend( wp.Backbone.Subviews.prototype, {
+ // ### Fetch all of the subviews
+ //
+ // Returns an array of all subviews.
+ all: function() {
+ return _.flatten( this._views );
+ },
+
+ // ### Get a selector's subviews
+ //
+ // Fetches all subviews that match a given `selector`.
+ //
+ // If no `selector` is provided, it will grab all subviews attached
+ // to the view's root.
+ get: function( selector ) {
+ selector = selector || '';
+ return this._views[ selector ];
+ },
+
+ // ### Get a selector's first subview
+ //
+ // Fetches the first subview that matches a given `selector`.
+ //
+ // If no `selector` is provided, it will grab the first subview
+ // attached to the view's root.
+ //
+ // Useful when a selector only has one subview at a time.
+ first: function( selector ) {
+ var views = this.get( selector );
+ return views && views.length ? views[0] : null;
+ },
+
+ // ### Register subview(s)
+ //
+ // Registers any number of `views` to a `selector`.
+ //
+ // When no `selector` is provided, the root selector (the empty string)
+ // is used. `views` accepts a `Backbone.View` instance or an array of
+ // `Backbone.View` instances.
+ //
+ // ---
+ //
+ // Accepts an `options` object, which has a significant effect on the
+ // resulting behavior.
+ //
+ // `options.silent` &ndash; *boolean, `false`*
+ // > If `options.silent` is true, no DOM modifications will be made.
+ //
+ // `options.add` &ndash; *boolean, `false`*
+ // > Use `Views.add()` as a shortcut for setting `options.add` to true.
+ //
+ // > By default, the provided `views` will replace
+ // any existing views associated with the selector. If `options.add`
+ // is true, the provided `views` will be added to the existing views.
+ //
+ // `options.at` &ndash; *integer, `undefined`*
+ // > When adding, to insert `views` at a specific index, use
+ // `options.at`. By default, `views` are added to the end of the array.
+ set: function( selector, views, options ) {
+ var existing, next;
+
+ if ( ! _.isString( selector ) ) {
+ options = views;
+ views = selector;
+ selector = '';
+ }
+
+ options = options || {};
+ views = _.isArray( views ) ? views : [ views ];
+ existing = this.get( selector );
+ next = views;
+
+ if ( existing ) {
+ if ( options.add ) {
+ if ( _.isUndefined( options.at ) ) {
+ next = existing.concat( views );
+ } else {
+ next = existing;
+ next.splice.apply( next, [ options.at, 0 ].concat( views ) );
+ }
+ } else {
+ _.each( next, function( view ) {
+ view.__detach = true;
+ });
+
+ _.each( existing, function( view ) {
+ if ( view.__detach )
+ view.$el.detach();
+ else
+ view.remove();
+ });
+
+ _.each( next, function( view ) {
+ delete view.__detach;
+ });
+ }
+ }
+
+ this._views[ selector ] = next;
+
+ _.each( views, function( subview ) {
+ var constructor = subview.Views || wp.Backbone.Subviews,
+ subviews = subview.views = subview.views || new constructor( subview );
+ subviews.parent = this.view;
+ subviews.selector = selector;
+ }, this );
+
+ if ( ! options.silent )
+ this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) );
+
+ return this;
+ },
+
+ // ### Add subview(s) to existing subviews
+ //
+ // An alias to `Views.set()`, which defaults `options.add` to true.
+ //
+ // Adds any number of `views` to a `selector`.
+ //
+ // When no `selector` is provided, the root selector (the empty string)
+ // is used. `views` accepts a `Backbone.View` instance or an array of
+ // `Backbone.View` instances.
+ //
+ // Use `Views.set()` when setting `options.add` to `false`.
+ //
+ // Accepts an `options` object. By default, provided `views` will be
+ // inserted at the end of the array of existing views. To insert
+ // `views` at a specific index, use `options.at`. If `options.silent`
+ // is true, no DOM modifications will be made.
+ //
+ // For more information on the `options` object, see `Views.set()`.
+ add: function( selector, views, options ) {
+ if ( ! _.isString( selector ) ) {
+ options = views;
+ views = selector;
+ selector = '';
+ }
+
+ return this.set( selector, views, _.extend({ add: true }, options ) );
+ },
+
+ // ### Stop tracking subviews
+ //
+ // Stops tracking `views` registered to a `selector`. If no `views` are
+ // set, then all of the `selector`'s subviews will be unregistered and
+ // removed.
+ //
+ // Accepts an `options` object. If `options.silent` is set, `remove`
+ // will *not* be triggered on the unregistered views.
+ unset: function( selector, views, options ) {
+ var existing;
+
+ if ( ! _.isString( selector ) ) {
+ options = views;
+ views = selector;
+ selector = '';
+ }
+
+ views = views || [];
+
+ if ( existing = this.get( selector ) ) {
+ views = _.isArray( views ) ? views : [ views ];
+ this._views[ selector ] = views.length ? _.difference( existing, views ) : [];
+ }
+
+ if ( ! options || ! options.silent )
+ _.invoke( views, 'remove' );
+
+ return this;
+ },
+
+ // ### Detach all subviews
+ //
+ // Detaches all subviews from the DOM.
+ //
+ // Helps to preserve all subview events when re-rendering the master
+ // view. Used in conjunction with `Views.render()`.
+ detach: function() {
+ $( _.pluck( this.all(), 'el' ) ).detach();
+ return this;
+ },
+
+ // ### Render all subviews
+ //
+ // Renders all subviews. Used in conjunction with `Views.detach()`.
+ render: function() {
+ var options = {
+ ready: this._isReady()
+ };
+
+ _.each( this._views, function( views, selector ) {
+ this._attach( selector, views, options );
+ }, this );
+
+ this.rendered = true;
+ return this;
+ },
+
+ // ### Remove all subviews
+ //
+ // Triggers the `remove()` method on all subviews. Detaches the master
+ // view from its parent. Resets the internals of the views manager.
+ //
+ // Accepts an `options` object. If `options.silent` is set, `unset`
+ // will *not* be triggered on the master view's parent.
+ remove: function( options ) {
+ if ( ! options || ! options.silent ) {
+ if ( this.parent && this.parent.views )
+ this.parent.views.unset( this.selector, this.view, { silent: true });
+ delete this.parent;
+ delete this.selector;
+ }
+
+ _.invoke( this.all(), 'remove' );
+ this._views = [];
+ return this;
+ },
+
+ // ### Replace a selector's subviews
+ //
+ // By default, sets the `$target` selector's html to the subview `els`.
+ //
+ // Can be overridden in subclasses.
+ replace: function( $target, els ) {
+ $target.html( els );
+ return this;
+ },
+
+ // ### Insert subviews into a selector
+ //
+ // By default, appends the subview `els` to the end of the `$target`
+ // selector. If `options.at` is set, inserts the subview `els` at the
+ // provided index.
+ //
+ // Can be overridden in subclasses.
+ insert: function( $target, els, options ) {
+ var at = options && options.at,
+ $children;
+
+ if ( _.isNumber( at ) && ($children = $target.children()).length > at )
+ $children.eq( at ).before( els );
+ else
+ $target.append( els );
+
+ return this;
+ },
+
+ // ### Trigger the ready event
+ //
+ // **Only use this method if you know what you're doing.**
+ // For performance reasons, this method does not check if the view is
+ // actually attached to the DOM. It's taking your word for it.
+ //
+ // Fires the ready event on the current view and all attached subviews.
+ ready: function() {
+ this.view.trigger('ready');
+
+ // Find all attached subviews, and call ready on them.
+ _.chain( this.all() ).map( function( view ) {
+ return view.views;
+ }).flatten().where({ attached: true }).invoke('ready');
+ },
+
+ // #### Internal. Attaches a series of views to a selector.
+ //
+ // Checks to see if a matching selector exists, renders the views,
+ // performs the proper DOM operation, and then checks if the view is
+ // attached to the document.
+ _attach: function( selector, views, options ) {
+ var $selector = selector ? this.view.$( selector ) : this.view.$el,
+ managers;
+
+ // Check if we found a location to attach the views.
+ if ( ! $selector.length )
+ return this;
+
+ managers = _.chain( views ).pluck('views').flatten().value();
+
+ // Render the views if necessary.
+ _.each( managers, function( manager ) {
+ if ( manager.rendered )
+ return;
+
+ manager.view.render();
+ manager.rendered = true;
+ }, this );
+
+ // Insert or replace the views.
+ this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options );
+
+ // Set attached and trigger ready if the current view is already
+ // attached to the DOM.
+ _.each( managers, function( manager ) {
+ manager.attached = true;
+
+ if ( options.ready )
+ manager.ready();
+ }, this );
+
+ return this;
+ },
+
+ // #### Internal. Checks if the current view is in the DOM.
+ _isReady: function() {
+ var node = this.view.el;
+ while ( node ) {
+ if ( node === document.body )
+ return true;
+ node = node.parentNode;
+ }
+
+ return false;
+ }
+ });
+
+
+ // wp.Backbone.View
+ // ----------------
+ //
+ // The base view class.
+ wp.Backbone.View = Backbone.View.extend({
+ // The constructor for the `Views` manager.
+ Subviews: wp.Backbone.Subviews,
+
+ constructor: function() {
+ this.views = new this.Subviews( this, this.views );
+ this.on( 'ready', this.ready, this );
+
+ Backbone.View.apply( this, arguments );
+ },
+
+ remove: function() {
+ var result = Backbone.View.prototype.remove.apply( this, arguments );
+
+ // Recursively remove child views.
+ if ( this.views )
+ this.views.remove();
+
+ return result;
+ },
+
+ render: function() {
+ var options;
+
+ if ( this.prepare )
+ options = this.prepare();
+
+ this.views.detach();
+
+ if ( this.template ) {
+ options = options || {};
+ this.trigger( 'prepare', options );
+ this.$el.html( this.template( options ) );
+ }
+
+ this.views.render();
+ return this;
+ },
+
+ prepare: function() {
+ return this.options;
+ },
+
+ ready: function() {}
+ });
+}(jQuery));
diff --git a/src/wp-includes/js/wp-list-revisions.js b/src/wp-includes/js/wp-list-revisions.js
new file mode 100644
index 0000000000..9c702c6595
--- /dev/null
+++ b/src/wp-includes/js/wp-list-revisions.js
@@ -0,0 +1,24 @@
+(function(w) {
+ var init = function() {
+ var pr = document.getElementById('post-revisions'),
+ inputs = pr ? pr.getElementsByTagName('input') : [];
+ pr.onclick = function() {
+ var i, checkCount = 0, side;
+ for ( i = 0; i < inputs.length; i++ ) {
+ checkCount += inputs[i].checked ? 1 : 0;
+ side = inputs[i].getAttribute('name');
+ if ( ! inputs[i].checked &&
+ ( 'left' == side && 1 > checkCount || 'right' == side && 1 < checkCount && ( ! inputs[i-1] || ! inputs[i-1].checked ) ) &&
+ ! ( inputs[i+1] && inputs[i+1].checked && 'right' == inputs[i+1].getAttribute('name') ) )
+ inputs[i].style.visibility = 'hidden';
+ else if ( 'left' == side || 'right' == side )
+ inputs[i].style.visibility = 'visible';
+ }
+ }
+ pr.onclick();
+ }
+ if ( w && w.addEventListener )
+ w.addEventListener('load', init, false);
+ else if ( w && w.attachEvent )
+ w.attachEvent('onload', init);
+})(window);
diff --git a/src/wp-includes/js/wp-lists.js b/src/wp-includes/js/wp-lists.js
new file mode 100644
index 0000000000..5decd3a845
--- /dev/null
+++ b/src/wp-includes/js/wp-lists.js
@@ -0,0 +1,464 @@
+(function($) {
+var fs = {add:'ajaxAdd',del:'ajaxDel',dim:'ajaxDim',process:'process',recolor:'recolor'}, wpList;
+
+wpList = {
+ settings: {
+ url: ajaxurl, type: 'POST',
+ response: 'ajax-response',
+
+ what: '',
+ alt: 'alternate', altOffset: 0,
+ addColor: null, delColor: null, dimAddColor: null, dimDelColor: null,
+
+ confirm: null,
+ addBefore: null, addAfter: null,
+ delBefore: null, delAfter: null,
+ dimBefore: null, dimAfter: null
+ },
+
+ nonce: function(e,s) {
+ var url = wpAjax.unserialize(e.attr('href'));
+ return s.nonce || url._ajax_nonce || $('#' + s.element + ' input[name="_ajax_nonce"]').val() || url._wpnonce || $('#' + s.element + ' input[name="_wpnonce"]').val() || 0;
+ },
+
+ parseData: function(e,t) {
+ var d = [], wpListsData;
+
+ try {
+ wpListsData = $(e).attr('data-wp-lists') || '';
+ wpListsData = wpListsData.match(new RegExp(t+':[\\S]+'));
+
+ if ( wpListsData )
+ d = wpListsData[0].split(':');
+ } catch(r) {}
+
+ return d;
+ },
+
+ pre: function(e,s,a) {
+ var bg, r;
+
+ s = $.extend( {}, this.wpList.settings, {
+ element: null,
+ nonce: 0,
+ target: e.get(0)
+ }, s || {} );
+
+ if ( $.isFunction( s.confirm ) ) {
+ if ( 'add' != a ) {
+ bg = $('#' + s.element).css('backgroundColor');
+ $('#' + s.element).css('backgroundColor', '#FF9966');
+ }
+ r = s.confirm.call(this, e, s, a, bg);
+
+ if ( 'add' != a )
+ $('#' + s.element).css('backgroundColor', bg );
+
+ if ( !r )
+ return false;
+ }
+
+ return s;
+ },
+
+ ajaxAdd: function( e, s ) {
+ e = $(e);
+ s = s || {};
+ var list = this, data = wpList.parseData(e,'add'), es, valid, formData, res, rres;
+
+ s = wpList.pre.call( list, e, s, 'add' );
+
+ s.element = data[2] || e.attr( 'id' ) || s.element || null;
+
+ if ( data[3] )
+ s.addColor = '#' + data[3];
+ else
+ s.addColor = s.addColor || '#FFFF33';
+
+ if ( !s )
+ return false;
+
+ if ( !e.is('[id="' + s.element + '-submit"]') )
+ return !wpList.add.call( list, e, s );
+
+ if ( !s.element )
+ return true;
+
+ s.action = 'add-' + s.what;
+
+ s.nonce = wpList.nonce(e,s);
+
+ es = $('#' + s.element + ' :input').not('[name="_ajax_nonce"], [name="_wpnonce"], [name="action"]');
+ valid = wpAjax.validateForm( '#' + s.element );
+
+ if ( !valid )
+ return false;
+
+ s.data = $.param( $.extend( { _ajax_nonce: s.nonce, action: s.action }, wpAjax.unserialize( data[4] || '' ) ) );
+ formData = $.isFunction(es.fieldSerialize) ? es.fieldSerialize() : es.serialize();
+
+ if ( formData )
+ s.data += '&' + formData;
+
+ if ( $.isFunction(s.addBefore) ) {
+ s = s.addBefore( s );
+ if ( !s )
+ return true;
+ }
+
+ if ( !s.data.match(/_ajax_nonce=[a-f0-9]+/) )
+ return true;
+
+ s.success = function(r) {
+ res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+
+ rres = r;
+
+ if ( !res || res.errors )
+ return false;
+
+ if ( true === res )
+ return true;
+
+ jQuery.each( res.responses, function() {
+ wpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
+ pos: this.position || 0,
+ id: this.id || 0,
+ oldId: this.oldId || null
+ } ) );
+ } );
+
+ list.wpList.recolor();
+ $(list).trigger( 'wpListAddEnd', [ s, list.wpList ] );
+ wpList.clear.call(list,'#' + s.element);
+ };
+
+ s.complete = function(x, st) {
+ if ( $.isFunction(s.addAfter) ) {
+ var _s = $.extend( { xml: x, status: st, parsed: res }, s );
+ s.addAfter( rres, _s );
+ }
+ };
+
+ $.ajax( s );
+ return false;
+ },
+
+ ajaxDel: function( e, s ) {
+ e = $(e);
+ s = s || {};
+ var list = this, data = wpList.parseData(e,'delete'), element, res, rres;
+
+ s = wpList.pre.call( list, e, s, 'delete' );
+
+ s.element = data[2] || s.element || null;
+
+ if ( data[3] )
+ s.delColor = '#' + data[3];
+ else
+ s.delColor = s.delColor || '#faa';
+
+ if ( !s || !s.element )
+ return false;
+
+ s.action = 'delete-' + s.what;
+
+ s.nonce = wpList.nonce(e,s);
+
+ s.data = $.extend(
+ { action: s.action, id: s.element.split('-').pop(), _ajax_nonce: s.nonce },
+ wpAjax.unserialize( data[4] || '' )
+ );
+
+ if ( $.isFunction(s.delBefore) ) {
+ s = s.delBefore( s, list );
+ if ( !s )
+ return true;
+ }
+
+ if ( !s.data._ajax_nonce )
+ return true;
+
+ element = $('#' + s.element);
+
+ if ( 'none' != s.delColor ) {
+ element.css( 'backgroundColor', s.delColor ).fadeOut( 350, function(){
+ list.wpList.recolor();
+ $(list).trigger( 'wpListDelEnd', [ s, list.wpList ] );
+ });
+ } else {
+ list.wpList.recolor();
+ $(list).trigger( 'wpListDelEnd', [ s, list.wpList ] );
+ }
+
+ s.success = function(r) {
+ res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+ rres = r;
+
+ if ( !res || res.errors ) {
+ element.stop().stop().css( 'backgroundColor', '#faa' ).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
+ return false;
+ }
+ };
+
+ s.complete = function(x, st) {
+ if ( $.isFunction(s.delAfter) ) {
+ element.queue( function() {
+ var _s = $.extend( { xml: x, status: st, parsed: res }, s );
+ s.delAfter( rres, _s );
+ }).dequeue();
+ }
+ }
+
+ $.ajax( s );
+ return false;
+ },
+
+ ajaxDim: function( e, s ) {
+ if ( $(e).parent().css('display') == 'none' ) // Prevent hidden links from being clicked by hotkeys
+ return false;
+
+ e = $(e);
+ s = s || {};
+
+ var list = this, data = wpList.parseData(e,'dim'), element, isClass, color, dimColor, res, rres;
+
+ s = wpList.pre.call( list, e, s, 'dim' );
+
+ s.element = data[2] || s.element || null;
+ s.dimClass = data[3] || s.dimClass || null;
+
+ if ( data[4] )
+ s.dimAddColor = '#' + data[4];
+ else
+ s.dimAddColor = s.dimAddColor || '#FFFF33';
+
+ if ( data[5] )
+ s.dimDelColor = '#' + data[5];
+ else
+ s.dimDelColor = s.dimDelColor || '#FF3333';
+
+ if ( !s || !s.element || !s.dimClass )
+ return true;
+
+ s.action = 'dim-' + s.what;
+
+ s.nonce = wpList.nonce(e,s);
+
+ s.data = $.extend(
+ { action: s.action, id: s.element.split('-').pop(), dimClass: s.dimClass, _ajax_nonce : s.nonce },
+ wpAjax.unserialize( data[6] || '' )
+ );
+
+ if ( $.isFunction(s.dimBefore) ) {
+ s = s.dimBefore( s );
+ if ( !s )
+ return true;
+ }
+
+ element = $('#' + s.element);
+ isClass = element.toggleClass(s.dimClass).is('.' + s.dimClass);
+ color = wpList.getColor( element );
+ element.toggleClass( s.dimClass );
+ dimColor = isClass ? s.dimAddColor : s.dimDelColor;
+
+ if ( 'none' != dimColor ) {
+ element
+ .animate( { backgroundColor: dimColor }, 'fast' )
+ .queue( function() { element.toggleClass(s.dimClass); $(this).dequeue(); } )
+ .animate( { backgroundColor: color }, { complete: function() {
+ $(this).css( 'backgroundColor', '' );
+ $(list).trigger( 'wpListDimEnd', [ s, list.wpList ] );
+ }
+ });
+ } else {
+ $(list).trigger( 'wpListDimEnd', [ s, list.wpList ] );
+ }
+
+ if ( !s.data._ajax_nonce )
+ return true;
+
+ s.success = function(r) {
+ res = wpAjax.parseAjaxResponse(r, s.response, s.element);
+ rres = r;
+
+ if ( !res || res.errors ) {
+ element.stop().stop().css( 'backgroundColor', '#FF3333' )[isClass?'removeClass':'addClass'](s.dimClass).show().queue( function() { list.wpList.recolor(); $(this).dequeue(); } );
+ return false;
+ }
+ };
+
+ s.complete = function(x, st) {
+ if ( $.isFunction(s.dimAfter) ) {
+ element.queue( function() {
+ var _s = $.extend( { xml: x, status: st, parsed: res }, s );
+ s.dimAfter( rres, _s );
+ }).dequeue();
+ }
+ };
+
+ $.ajax( s );
+ return false;
+ },
+
+ getColor: function( el ) {
+ var color = jQuery(el).css('backgroundColor');
+
+ return color || '#ffffff';
+ },
+
+ add: function( e, s ) {
+ e = $(e);
+
+ var list = $(this), old = false, _s = { pos: 0, id: 0, oldId: null }, ba, ref, color;
+
+ if ( 'string' == typeof s )
+ s = { what: s };
+
+ s = $.extend(_s, this.wpList.settings, s);
+
+ if ( !e.size() || !s.what )
+ return false;
+
+ if ( s.oldId )
+ old = $('#' + s.what + '-' + s.oldId);
+
+ if ( s.id && ( s.id != s.oldId || !old || !old.size() ) )
+ $('#' + s.what + '-' + s.id).remove();
+
+ if ( old && old.size() ) {
+ old.before(e);
+ old.remove();
+ } else if ( isNaN(s.pos) ) {
+ ba = 'after';
+
+ if ( '-' == s.pos.substr(0,1) ) {
+ s.pos = s.pos.substr(1);
+ ba = 'before';
+ }
+
+ ref = list.find( '#' + s.pos );
+
+ if ( 1 === ref.size() )
+ ref[ba](e);
+ else
+ list.append(e);
+
+ } else if ( 'comment' != s.what || 0 === $('#' + s.element).length ) {
+ if ( s.pos < 0 ) {
+ list.prepend(e);
+ } else {
+ list.append(e);
+ }
+ }
+
+ if ( s.alt ) {
+ if ( ( list.children(':visible').index( e[0] ) + s.altOffset ) % 2 ) { e.removeClass( s.alt ); }
+ else { e.addClass( s.alt ); }
+ }
+
+ if ( 'none' != s.addColor ) {
+ color = wpList.getColor( e );
+ e.css( 'backgroundColor', s.addColor ).animate( { backgroundColor: color }, { complete: function() { $(this).css( 'backgroundColor', '' ); } } );
+ }
+ list.each( function() { this.wpList.process( e ); } );
+ return e;
+ },
+
+ clear: function(e) {
+ var list = this, t, tag;
+
+ e = $(e);
+
+ if ( list.wpList && e.parents( '#' + list.id ).size() )
+ return;
+
+ e.find(':input').each( function() {
+ if ( $(this).parents('.form-no-clear').size() )
+ return;
+
+ t = this.type.toLowerCase();
+ tag = this.tagName.toLowerCase();
+
+ if ( 'text' == t || 'password' == t || 'textarea' == tag )
+ this.value = '';
+ else if ( 'checkbox' == t || 'radio' == t )
+ this.checked = false;
+ else if ( 'select' == tag )
+ this.selectedIndex = null;
+ });
+ },
+
+ process: function(el) {
+ var list = this,
+ $el = $(el || document);
+
+ $el.delegate( 'form[data-wp-lists^="add:' + list.id + ':"]', 'submit', function(){
+ return list.wpList.add(this);
+ });
+
+ $el.delegate( 'a[data-wp-lists^="add:' + list.id + ':"], input[data-wp-lists^="add:' + list.id + ':"]', 'click', function(){
+ return list.wpList.add(this);
+ });
+
+ $el.delegate( '[data-wp-lists^="delete:' + list.id + ':"]', 'click', function(){
+ return list.wpList.del(this);
+ });
+
+ $el.delegate( '[data-wp-lists^="dim:' + list.id + ':"]', 'click', function(){
+ return list.wpList.dim(this);
+ });
+ },
+
+ recolor: function() {
+ var list = this, items, eo;
+
+ if ( !list.wpList.settings.alt )
+ return;
+
+ items = $('.list-item:visible', list);
+
+ if ( !items.size() )
+ items = $(list).children(':visible');
+
+ eo = [':even',':odd'];
+
+ if ( list.wpList.settings.altOffset % 2 )
+ eo.reverse();
+
+ items.filter(eo[0]).addClass(list.wpList.settings.alt).end().filter(eo[1]).removeClass(list.wpList.settings.alt);
+ },
+
+ init: function() {
+ var lists = this;
+
+ lists.wpList.process = function(a) {
+ lists.each( function() {
+ this.wpList.process(a);
+ } );
+ };
+
+ lists.wpList.recolor = function() {
+ lists.each( function() {
+ this.wpList.recolor();
+ } );
+ };
+ }
+};
+
+$.fn.wpList = function( settings ) {
+ this.each( function() {
+ var _this = this;
+
+ this.wpList = { settings: $.extend( {}, wpList.settings, { what: wpList.parseData(this,'list')[1] || '' }, settings ) };
+ $.each( fs, function(i,f) { _this.wpList[i] = function( e, s ) { return wpList[f].call( _this, e, s ); }; } );
+ } );
+
+ wpList.init.call(this);
+
+ this.wpList.process();
+
+ return this;
+};
+
+})(jQuery);
diff --git a/src/wp-includes/js/wp-pointer.js b/src/wp-includes/js/wp-pointer.js
new file mode 100644
index 0000000000..23b0e43dfe
--- /dev/null
+++ b/src/wp-includes/js/wp-pointer.js
@@ -0,0 +1,281 @@
+/**
+ * Pointer jQuery widget.
+ */
+(function($){
+ var identifier = 0,
+ zindex = 9999;
+
+ $.widget("wp.pointer", {
+ options: {
+ pointerClass: 'wp-pointer',
+ pointerWidth: 320,
+ content: function( respond, event, t ) {
+ return $(this).text();
+ },
+ buttons: function( event, t ) {
+ var close = ( wpPointerL10n ) ? wpPointerL10n.dismiss : 'Dismiss',
+ button = $('<a class="close" href="#">' + close + '</a>');
+
+ return button.bind( 'click.pointer', function(e) {
+ e.preventDefault();
+ t.element.pointer('close');
+ });
+ },
+ position: 'top',
+ show: function( event, t ) {
+ t.pointer.show();
+ t.opened();
+ },
+ hide: function( event, t ) {
+ t.pointer.hide();
+ t.closed();
+ },
+ document: document
+ },
+
+ _create: function() {
+ var positioning,
+ family;
+
+ this.content = $('<div class="wp-pointer-content"></div>');
+ this.arrow = $('<div class="wp-pointer-arrow"><div class="wp-pointer-arrow-inner"></div></div>');
+
+ family = this.element.parents().add( this.element );
+ positioning = 'absolute';
+
+ if ( family.filter(function(){ return 'fixed' === $(this).css('position'); }).length )
+ positioning = 'fixed';
+
+ this.pointer = $('<div />')
+ .append( this.content )
+ .append( this.arrow )
+ .attr('id', 'wp-pointer-' + identifier++)
+ .addClass( this.options.pointerClass )
+ .css({'position': positioning, 'width': this.options.pointerWidth+'px', 'display': 'none'})
+ .appendTo( this.options.document.body );
+ },
+
+ _setOption: function( key, value ) {
+ var o = this.options,
+ tip = this.pointer;
+
+ // Handle document transfer
+ if ( key === "document" && value !== o.document ) {
+ tip.detach().appendTo( value.body );
+
+ // Handle class change
+ } else if ( key === "pointerClass" ) {
+ tip.removeClass( o.pointerClass ).addClass( value );
+ }
+
+ // Call super method.
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ // Reposition automatically
+ if ( key === "position" ) {
+ this.reposition();
+
+ // Update content automatically if pointer is open
+ } else if ( key === "content" && this.active ) {
+ this.update();
+ }
+ },
+
+ destroy: function() {
+ this.pointer.remove();
+ $.Widget.prototype.destroy.call( this );
+ },
+
+ widget: function() {
+ return this.pointer;
+ },
+
+ update: function( event ) {
+ var self = this,
+ o = this.options,
+ dfd = $.Deferred(),
+ content;
+
+ if ( o.disabled )
+ return;
+
+ dfd.done( function( content ) {
+ self._update( event, content );
+ })
+
+ // Either o.content is a string...
+ if ( typeof o.content === 'string' ) {
+ content = o.content;
+
+ // ...or o.content is a callback.
+ } else {
+ content = o.content.call( this.element[0], dfd.resolve, event, this._handoff() );
+ }
+
+ // If content is set, then complete the update.
+ if ( content )
+ dfd.resolve( content );
+
+ return dfd.promise();
+ },
+
+ /**
+ * Update is separated into two functions to allow events to defer
+ * updating the pointer (e.g. fetch content with ajax, etc).
+ */
+ _update: function( event, content ) {
+ var buttons,
+ o = this.options;
+
+ if ( ! content )
+ return;
+
+ this.pointer.stop(); // Kill any animations on the pointer.
+ this.content.html( content );
+
+ buttons = o.buttons.call( this.element[0], event, this._handoff() );
+ if ( buttons ) {
+ buttons.wrap('<div class="wp-pointer-buttons" />').parent().appendTo( this.content );
+ }
+
+ this.reposition();
+ },
+
+ reposition: function() {
+ var position;
+
+ if ( this.options.disabled )
+ return;
+
+ position = this._processPosition( this.options.position );
+
+ // Reposition pointer.
+ this.pointer.css({
+ top: 0,
+ left: 0,
+ zIndex: zindex++ // Increment the z-index so that it shows above other opened pointers.
+ }).show().position($.extend({
+ of: this.element,
+ collision: 'fit none'
+ }, position )); // the object comes before this.options.position so the user can override position.of.
+
+ this.repoint();
+ },
+
+ repoint: function() {
+ var o = this.options,
+ edge;
+
+ if ( o.disabled )
+ return;
+
+ edge = ( typeof o.position == 'string' ) ? o.position : o.position.edge;
+
+ // Remove arrow classes.
+ this.pointer[0].className = this.pointer[0].className.replace( /wp-pointer-[^\s'"]*/, '' );
+
+ // Add arrow class.
+ this.pointer.addClass( 'wp-pointer-' + edge );
+ },
+
+ _processPosition: function( position ) {
+ var opposite = {
+ top: 'bottom',
+ bottom: 'top',
+ left: 'right',
+ right: 'left'
+ },
+ result;
+
+ // If the position object is a string, it is shorthand for position.edge.
+ if ( typeof position == 'string' ) {
+ result = {
+ edge: position + ''
+ };
+ } else {
+ result = $.extend( {}, position );
+ }
+
+ if ( ! result.edge )
+ return result;
+
+ if ( result.edge == 'top' || result.edge == 'bottom' ) {
+ result.align = result.align || 'left';
+
+ result.at = result.at || result.align + ' ' + opposite[ result.edge ];
+ result.my = result.my || result.align + ' ' + result.edge;
+ } else {
+ result.align = result.align || 'top';
+
+ result.at = result.at || opposite[ result.edge ] + ' ' + result.align;
+ result.my = result.my || result.edge + ' ' + result.align;
+ }
+
+ return result;
+ },
+
+ open: function( event ) {
+ var self = this,
+ o = this.options;
+
+ if ( this.active || o.disabled || this.element.is(':hidden') )
+ return;
+
+ this.update().done( function() {
+ self._open( event );
+ });
+ },
+
+ _open: function( event ) {
+ var self = this,
+ o = this.options;
+
+ if ( this.active || o.disabled || this.element.is(':hidden') )
+ return;
+
+ this.active = true;
+
+ this._trigger( "open", event, this._handoff() );
+
+ this._trigger( "show", event, this._handoff({
+ opened: function() {
+ self._trigger( "opened", event, self._handoff() );
+ }
+ }));
+ },
+
+ close: function( event ) {
+ if ( !this.active || this.options.disabled )
+ return;
+
+ var self = this;
+ this.active = false;
+
+ this._trigger( "close", event, this._handoff() );
+ this._trigger( "hide", event, this._handoff({
+ closed: function() {
+ self._trigger( "closed", event, self._handoff() );
+ }
+ }));
+ },
+
+ sendToTop: function( event ) {
+ if ( this.active )
+ this.pointer.css( 'z-index', zindex++ );
+ },
+
+ toggle: function( event ) {
+ if ( this.pointer.is(':hidden') )
+ this.open( event );
+ else
+ this.close( event );
+ },
+
+ _handoff: function( extend ) {
+ return $.extend({
+ pointer: this.pointer,
+ element: this.element
+ }, extend);
+ }
+ });
+})(jQuery);
diff --git a/src/wp-includes/js/wp-util.js b/src/wp-includes/js/wp-util.js
new file mode 100644
index 0000000000..701ec3ea43
--- /dev/null
+++ b/src/wp-includes/js/wp-util.js
@@ -0,0 +1,105 @@
+window.wp = window.wp || {};
+
+(function ($) {
+ // Check for the utility settings.
+ var settings = typeof _wpUtilSettings === 'undefined' ? {} : _wpUtilSettings;
+
+ /**
+ * wp.template( id )
+ *
+ * Fetches a template by id.
+ *
+ * @param {string} id A string that corresponds to a DOM element with an id prefixed with "tmpl-".
+ * For example, "attachment" maps to "tmpl-attachment".
+ * @return {function} A function that lazily-compiles the template requested.
+ */
+ wp.template = _.memoize(function ( id ) {
+ var compiled,
+ options = {
+ evaluate: /<#([\s\S]+?)#>/g,
+ interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
+ escape: /\{\{([^\}]+?)\}\}(?!\})/g,
+ variable: 'data'
+ };
+
+ return function ( data ) {
+ compiled = compiled || _.template( $( '#tmpl-' + id ).html(), null, options );
+ return compiled( data );
+ };
+ });
+
+ // wp.ajax
+ // ------
+ //
+ // Tools for sending ajax requests with JSON responses and built in error handling.
+ // Mirrors and wraps jQuery's ajax APIs.
+ wp.ajax = {
+ settings: settings.ajax || {},
+
+ /**
+ * wp.ajax.post( [action], [data] )
+ *
+ * Sends a POST request to WordPress.
+ *
+ * @param {string} action The slug of the action to fire in WordPress.
+ * @param {object} data The data to populate $_POST with.
+ * @return {$.promise} A jQuery promise that represents the request.
+ */
+ post: function( action, data ) {
+ return wp.ajax.send({
+ data: _.isObject( action ) ? action : _.extend( data || {}, { action: action })
+ });
+ },
+
+ /**
+ * wp.ajax.send( [action], [options] )
+ *
+ * Sends a POST request to WordPress.
+ *
+ * @param {string} action The slug of the action to fire in WordPress.
+ * @param {object} options The options passed to jQuery.ajax.
+ * @return {$.promise} A jQuery promise that represents the request.
+ */
+ send: function( action, options ) {
+ if ( _.isObject( action ) ) {
+ options = action;
+ } else {
+ options = options || {};
+ options.data = _.extend( options.data || {}, { action: action });
+ }
+
+ options = _.defaults( options || {}, {
+ type: 'POST',
+ url: wp.ajax.settings.url,
+ context: this
+ });
+
+ return $.Deferred( function( deferred ) {
+ // Transfer success/error callbacks.
+ if ( options.success )
+ deferred.done( options.success );
+ if ( options.error )
+ deferred.fail( options.error );
+
+ delete options.success;
+ delete options.error;
+
+ // Use with PHP's wp_send_json_success() and wp_send_json_error()
+ $.ajax( options ).done( function( response ) {
+ // Treat a response of `1` as successful for backwards
+ // compatibility with existing handlers.
+ if ( response === '1' || response === 1 )
+ response = { success: true };
+
+ if ( _.isObject( response ) && ! _.isUndefined( response.success ) )
+ deferred[ response.success ? 'resolveWith' : 'rejectWith' ]( this, [response.data] );
+ else
+ deferred.rejectWith( this, [response] );
+ }).fail( function() {
+ deferred.rejectWith( this, arguments );
+ });
+ }).promise();
+ }
+ };
+
+}(jQuery));
diff --git a/src/wp-includes/js/wplink.js b/src/wp-includes/js/wplink.js
new file mode 100644
index 0000000000..4e4cec560b
--- /dev/null
+++ b/src/wp-includes/js/wplink.js
@@ -0,0 +1,608 @@
+var wpLink;
+
+(function($){
+ var inputs = {}, rivers = {}, ed, River, Query;
+
+ wpLink = {
+ timeToTriggerRiver: 150,
+ minRiverAJAXDuration: 200,
+ riverBottomThreshold: 5,
+ keySensitivity: 100,
+ lastSearch: '',
+ textarea: '',
+
+ init : function() {
+ inputs.dialog = $('#wp-link');
+ inputs.submit = $('#wp-link-submit');
+ // URL
+ inputs.url = $('#url-field');
+ inputs.nonce = $('#_ajax_linking_nonce');
+ // Secondary options
+ inputs.title = $('#link-title-field');
+ // Advanced Options
+ inputs.openInNewTab = $('#link-target-checkbox');
+ inputs.search = $('#search-field');
+ // Build Rivers
+ rivers.search = new River( $('#search-results') );
+ rivers.recent = new River( $('#most-recent-results') );
+ rivers.elements = $('.query-results', inputs.dialog);
+
+ // Bind event handlers
+ inputs.dialog.keydown( wpLink.keydown );
+ inputs.dialog.keyup( wpLink.keyup );
+ inputs.submit.click( function(e){
+ e.preventDefault();
+ wpLink.update();
+ });
+ $('#wp-link-cancel').click( function(e){
+ e.preventDefault();
+ wpLink.close();
+ });
+ $('#internal-toggle').click( wpLink.toggleInternalLinking );
+
+ rivers.elements.bind('river-select', wpLink.updateFields );
+
+ inputs.search.keyup( wpLink.searchInternalLinks );
+
+ inputs.dialog.bind('wpdialogrefresh', wpLink.refresh);
+ inputs.dialog.bind('wpdialogbeforeopen', wpLink.beforeOpen);
+ inputs.dialog.bind('wpdialogclose', wpLink.onClose);
+ },
+
+ beforeOpen : function() {
+ wpLink.range = null;
+
+ if ( ! wpLink.isMCE() && document.selection ) {
+ wpLink.textarea.focus();
+ wpLink.range = document.selection.createRange();
+ }
+ },
+
+ open : function() {
+ if ( !wpActiveEditor )
+ return;
+
+ this.textarea = $('#'+wpActiveEditor).get(0);
+
+ // Initialize the dialog if necessary (html mode).
+ if ( ! inputs.dialog.data('wpdialog') ) {
+ inputs.dialog.wpdialog({
+ title: wpLinkL10n.title,
+ width: 480,
+ height: 'auto',
+ modal: true,
+ dialogClass: 'wp-dialog'
+ });
+ }
+
+ inputs.dialog.wpdialog('open');
+ },
+
+ isMCE : function() {
+ return tinyMCEPopup && ( ed = tinyMCEPopup.editor ) && ! ed.isHidden();
+ },
+
+ refresh : function() {
+ // Refresh rivers (clear links, check visibility)
+ rivers.search.refresh();
+ rivers.recent.refresh();
+
+ if ( wpLink.isMCE() )
+ wpLink.mceRefresh();
+ else
+ wpLink.setDefaultValues();
+
+ // Focus the URL field and highlight its contents.
+ // If this is moved above the selection changes,
+ // IE will show a flashing cursor over the dialog.
+ inputs.url.focus()[0].select();
+ // Load the most recent results if this is the first time opening the panel.
+ if ( ! rivers.recent.ul.children().length )
+ rivers.recent.ajax();
+ },
+
+ mceRefresh : function() {
+ var e;
+ ed = tinyMCEPopup.editor;
+
+ tinyMCEPopup.restoreSelection();
+
+ // If link exists, select proper values.
+ if ( e = ed.dom.getParent(ed.selection.getNode(), 'A') ) {
+ // Set URL and description.
+ inputs.url.val( ed.dom.getAttrib(e, 'href') );
+ inputs.title.val( ed.dom.getAttrib(e, 'title') );
+ // Set open in new tab.
+ inputs.openInNewTab.prop('checked', ( "_blank" == ed.dom.getAttrib( e, 'target' ) ) );
+ // Update save prompt.
+ inputs.submit.val( wpLinkL10n.update );
+
+ // If there's no link, set the default values.
+ } else {
+ wpLink.setDefaultValues();
+ }
+
+ tinyMCEPopup.storeSelection();
+ },
+
+ close : function() {
+ if ( wpLink.isMCE() )
+ tinyMCEPopup.close();
+ else
+ inputs.dialog.wpdialog('close');
+ },
+
+ onClose: function() {
+ if ( ! wpLink.isMCE() ) {
+ wpLink.textarea.focus();
+ if ( wpLink.range ) {
+ wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
+ wpLink.range.select();
+ }
+ }
+ },
+
+ getAttrs : function() {
+ return {
+ href : inputs.url.val(),
+ title : inputs.title.val(),
+ target : inputs.openInNewTab.prop('checked') ? '_blank' : ''
+ };
+ },
+
+ update : function() {
+ if ( wpLink.isMCE() )
+ wpLink.mceUpdate();
+ else
+ wpLink.htmlUpdate();
+ },
+
+ htmlUpdate : function() {
+ var attrs, html, begin, end, cursor,
+ textarea = wpLink.textarea;
+
+ if ( ! textarea )
+ return;
+
+ attrs = wpLink.getAttrs();
+
+ // If there's no href, return.
+ if ( ! attrs.href || attrs.href == 'http://' )
+ return;
+
+ // Build HTML
+ html = '<a href="' + attrs.href + '"';
+
+ if ( attrs.title )
+ html += ' title="' + attrs.title + '"';
+ if ( attrs.target )
+ html += ' target="' + attrs.target + '"';
+
+ html += '>';
+
+ // Insert HTML
+ if ( document.selection && wpLink.range ) {
+ // IE
+ // Note: If no text is selected, IE will not place the cursor
+ // inside the closing tag.
+ textarea.focus();
+ wpLink.range.text = html + wpLink.range.text + '</a>';
+ wpLink.range.moveToBookmark( wpLink.range.getBookmark() );
+ wpLink.range.select();
+
+ wpLink.range = null;
+ } else if ( typeof textarea.selectionStart !== 'undefined' ) {
+ // W3C
+ begin = textarea.selectionStart;
+ end = textarea.selectionEnd;
+ selection = textarea.value.substring( begin, end );
+ html = html + selection + '</a>';
+ cursor = begin + html.length;
+
+ // If no next is selected, place the cursor inside the closing tag.
+ if ( begin == end )
+ cursor -= '</a>'.length;
+
+ textarea.value = textarea.value.substring( 0, begin )
+ + html
+ + textarea.value.substring( end, textarea.value.length );
+
+ // Update cursor position
+ textarea.selectionStart = textarea.selectionEnd = cursor;
+ }
+
+ wpLink.close();
+ textarea.focus();
+ },
+
+ mceUpdate : function() {
+ var ed = tinyMCEPopup.editor,
+ attrs = wpLink.getAttrs(),
+ e, b;
+
+ tinyMCEPopup.restoreSelection();
+ e = ed.dom.getParent(ed.selection.getNode(), 'A');
+
+ // If the values are empty, unlink and return
+ if ( ! attrs.href || attrs.href == 'http://' ) {
+ if ( e ) {
+ tinyMCEPopup.execCommand("mceBeginUndoLevel");
+ b = ed.selection.getBookmark();
+ ed.dom.remove(e, 1);
+ ed.selection.moveToBookmark(b);
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ wpLink.close();
+ }
+ return;
+ }
+
+ tinyMCEPopup.execCommand("mceBeginUndoLevel");
+
+ if (e == null) {
+ ed.getDoc().execCommand("unlink", false, null);
+ tinyMCEPopup.execCommand("mceInsertLink", false, "#mce_temp_url#", {skip_undo : 1});
+
+ tinymce.each(ed.dom.select("a"), function(n) {
+ if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') {
+ e = n;
+ ed.dom.setAttribs(e, attrs);
+ }
+ });
+
+ // Sometimes WebKit lets a user create a link where
+ // they shouldn't be able to. In this case, CreateLink
+ // injects "#mce_temp_url#" into their content. Fix it.
+ if ( $(e).text() == '#mce_temp_url#' ) {
+ ed.dom.remove(e);
+ e = null;
+ }
+ } else {
+ ed.dom.setAttribs(e, attrs);
+ }
+
+ // Don't move caret if selection was image
+ if ( e && (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') ) {
+ ed.focus();
+ ed.selection.select(e);
+ ed.selection.collapse(0);
+ tinyMCEPopup.storeSelection();
+ }
+
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ wpLink.close();
+ },
+
+ updateFields : function( e, li, originalEvent ) {
+ inputs.url.val( li.children('.item-permalink').val() );
+ inputs.title.val( li.hasClass('no-title') ? '' : li.children('.item-title').text() );
+ if ( originalEvent && originalEvent.type == "click" )
+ inputs.url.focus();
+ },
+ setDefaultValues : function() {
+ var selectedText,
+ textarea = wpLink.textarea;
+
+ // Set URL and description to defaults.
+ // Leave the new tab setting as-is.
+ inputs.url.val('http://');
+ inputs.title.val('');
+ if ( wpLink.isMCE() ) {
+ selectedText = tinyMCEPopup.editor.selection.getContent( { format: 'text' } );
+ } else {
+ if ( document.selection && wpLink.range ) {
+ selectedText = wpLink.range.text;
+ } else if ( typeof textarea.selectionStart !== 'undefined' ) {
+ selectedText = textarea.value.substring( textarea.selectionStart, textarea.selectionEnd );
+ }
+ }
+ if ( selectedText && ( selectedText = selectedText.replace( /^\s+|\s+$/g, '' ) ) ) {
+ if ( ! $('#search-panel').is(':visible') )
+ $('#internal-toggle').trigger('click');
+ inputs.search.val( selectedText ).trigger('keyup');
+ }
+
+ // Update save prompt.
+ inputs.submit.val( wpLinkL10n.save );
+ },
+
+ searchInternalLinks : function() {
+ var t = $(this), waiting,
+ search = t.val();
+
+ if ( search.length > 2 ) {
+ rivers.recent.hide();
+ rivers.search.show();
+
+ // Don't search if the keypress didn't change the title.
+ if ( wpLink.lastSearch == search )
+ return;
+
+ wpLink.lastSearch = search;
+ waiting = t.parent().find('.spinner').show();
+
+ rivers.search.change( search );
+ rivers.search.ajax( function(){ waiting.hide(); });
+ } else {
+ rivers.search.hide();
+ rivers.recent.show();
+ }
+ },
+
+ next : function() {
+ rivers.search.next();
+ rivers.recent.next();
+ },
+ prev : function() {
+ rivers.search.prev();
+ rivers.recent.prev();
+ },
+
+ keydown : function( event ) {
+ var fn, key = $.ui.keyCode;
+
+ switch( event.which ) {
+ case key.UP:
+ fn = 'prev';
+ case key.DOWN:
+ fn = fn || 'next';
+ clearInterval( wpLink.keyInterval );
+ wpLink[ fn ]();
+ wpLink.keyInterval = setInterval( wpLink[ fn ], wpLink.keySensitivity );
+ break;
+ default:
+ return;
+ }
+ event.preventDefault();
+ },
+ keyup: function( event ) {
+ var key = $.ui.keyCode;
+
+ switch( event.which ) {
+ case key.ESCAPE:
+ event.stopImmediatePropagation();
+ if ( ! $(document).triggerHandler( 'wp_CloseOnEscape', [{ event: event, what: 'wplink', cb: wpLink.close }] ) )
+ wpLink.close();
+
+ return false;
+ break;
+ case key.UP:
+ case key.DOWN:
+ clearInterval( wpLink.keyInterval );
+ break;
+ default:
+ return;
+ }
+ event.preventDefault();
+ },
+
+ delayedCallback : function( func, delay ) {
+ var timeoutTriggered, funcTriggered, funcArgs, funcContext;
+
+ if ( ! delay )
+ return func;
+
+ setTimeout( function() {
+ if ( funcTriggered )
+ return func.apply( funcContext, funcArgs );
+ // Otherwise, wait.
+ timeoutTriggered = true;
+ }, delay);
+
+ return function() {
+ if ( timeoutTriggered )
+ return func.apply( this, arguments );
+ // Otherwise, wait.
+ funcArgs = arguments;
+ funcContext = this;
+ funcTriggered = true;
+ };
+ },
+
+ toggleInternalLinking : function( event ) {
+ var panel = $('#search-panel'),
+ widget = inputs.dialog.wpdialog('widget'),
+ // We're about to toggle visibility; it's currently the opposite
+ visible = !panel.is(':visible'),
+ win = $(window);
+
+ $(this).toggleClass('toggle-arrow-active', visible);
+
+ inputs.dialog.height('auto');
+ panel.slideToggle( 300, function() {
+ setUserSetting('wplink', visible ? '1' : '0');
+ inputs[ visible ? 'search' : 'url' ].focus();
+
+ // Move the box if the box is now expanded, was opened in a collapsed state,
+ // and if it needs to be moved. (Judged by bottom not being positive or
+ // bottom being smaller than top.)
+ var scroll = win.scrollTop(),
+ top = widget.offset().top,
+ bottom = top + widget.outerHeight(),
+ diff = bottom - win.height();
+
+ if ( diff > scroll ) {
+ widget.animate({'top': diff < top ? top - diff : scroll }, 200);
+ }
+ });
+ event.preventDefault();
+ }
+ }
+
+ River = function( element, search ) {
+ var self = this;
+ this.element = element;
+ this.ul = element.children('ul');
+ this.waiting = element.find('.river-waiting');
+
+ this.change( search );
+ this.refresh();
+
+ element.scroll( function(){ self.maybeLoad(); });
+ element.delegate('li', 'click', function(e){ self.select( $(this), e ); });
+ };
+
+ $.extend( River.prototype, {
+ refresh: function() {
+ this.deselect();
+ this.visible = this.element.is(':visible');
+ },
+ show: function() {
+ if ( ! this.visible ) {
+ this.deselect();
+ this.element.show();
+ this.visible = true;
+ }
+ },
+ hide: function() {
+ this.element.hide();
+ this.visible = false;
+ },
+ // Selects a list item and triggers the river-select event.
+ select: function( li, event ) {
+ var liHeight, elHeight, liTop, elTop;
+
+ if ( li.hasClass('unselectable') || li == this.selected )
+ return;
+
+ this.deselect();
+ this.selected = li.addClass('selected');
+ // Make sure the element is visible
+ liHeight = li.outerHeight();
+ elHeight = this.element.height();
+ liTop = li.position().top;
+ elTop = this.element.scrollTop();
+
+ if ( liTop < 0 ) // Make first visible element
+ this.element.scrollTop( elTop + liTop );
+ else if ( liTop + liHeight > elHeight ) // Make last visible element
+ this.element.scrollTop( elTop + liTop - elHeight + liHeight );
+
+ // Trigger the river-select event
+ this.element.trigger('river-select', [ li, event, this ]);
+ },
+ deselect: function() {
+ if ( this.selected )
+ this.selected.removeClass('selected');
+ this.selected = false;
+ },
+ prev: function() {
+ if ( ! this.visible )
+ return;
+
+ var to;
+ if ( this.selected ) {
+ to = this.selected.prev('li');
+ if ( to.length )
+ this.select( to );
+ }
+ },
+ next: function() {
+ if ( ! this.visible )
+ return;
+
+ var to = this.selected ? this.selected.next('li') : $('li:not(.unselectable):first', this.element);
+ if ( to.length )
+ this.select( to );
+ },
+ ajax: function( callback ) {
+ var self = this,
+ delay = this.query.page == 1 ? 0 : wpLink.minRiverAJAXDuration,
+ response = wpLink.delayedCallback( function( results, params ) {
+ self.process( results, params );
+ if ( callback )
+ callback( results, params );
+ }, delay );
+
+ this.query.ajax( response );
+ },
+ change: function( search ) {
+ if ( this.query && this._search == search )
+ return;
+
+ this._search = search;
+ this.query = new Query( search );
+ this.element.scrollTop(0);
+ },
+ process: function( results, params ) {
+ var list = '', alt = true, classes = '',
+ firstPage = params.page == 1;
+
+ if ( !results ) {
+ if ( firstPage ) {
+ list += '<li class="unselectable"><span class="item-title"><em>'
+ + wpLinkL10n.noMatchesFound
+ + '</em></span></li>';
+ }
+ } else {
+ $.each( results, function() {
+ classes = alt ? 'alternate' : '';
+ classes += this['title'] ? '' : ' no-title';
+ list += classes ? '<li class="' + classes + '">' : '<li>';
+ list += '<input type="hidden" class="item-permalink" value="' + this['permalink'] + '" />';
+ list += '<span class="item-title">';
+ list += this['title'] ? this['title'] : wpLinkL10n.noTitle;
+ list += '</span><span class="item-info">' + this['info'] + '</span></li>';
+ alt = ! alt;
+ });
+ }
+
+ this.ul[ firstPage ? 'html' : 'append' ]( list );
+ },
+ maybeLoad: function() {
+ var self = this,
+ el = this.element,
+ bottom = el.scrollTop() + el.height();
+
+ if ( ! this.query.ready() || bottom < this.ul.height() - wpLink.riverBottomThreshold )
+ return;
+
+ setTimeout(function() {
+ var newTop = el.scrollTop(),
+ newBottom = newTop + el.height();
+
+ if ( ! self.query.ready() || newBottom < self.ul.height() - wpLink.riverBottomThreshold )
+ return;
+
+ self.waiting.show();
+ el.scrollTop( newTop + self.waiting.outerHeight() );
+
+ self.ajax( function() { self.waiting.hide(); });
+ }, wpLink.timeToTriggerRiver );
+ }
+ });
+
+ Query = function( search ) {
+ this.page = 1;
+ this.allLoaded = false;
+ this.querying = false;
+ this.search = search;
+ };
+
+ $.extend( Query.prototype, {
+ ready: function() {
+ return !( this.querying || this.allLoaded );
+ },
+ ajax: function( callback ) {
+ var self = this,
+ query = {
+ action : 'wp-link-ajax',
+ page : this.page,
+ '_ajax_linking_nonce' : inputs.nonce.val()
+ };
+
+ if ( this.search )
+ query.search = this.search;
+
+ this.querying = true;
+
+ $.post( ajaxurl, query, function(r) {
+ self.page++;
+ self.querying = false;
+ self.allLoaded = !r;
+ callback( r, query );
+ }, "json" );
+ }
+ });
+
+ $(document).ready( wpLink.init );
+})(jQuery);
diff --git a/src/wp-includes/kses.php b/src/wp-includes/kses.php
new file mode 100644
index 0000000000..4c42134e7a
--- /dev/null
+++ b/src/wp-includes/kses.php
@@ -0,0 +1,1473 @@
+<?php
+/**
+ * kses 0.2.2 - HTML/XHTML filter that only allows some elements and attributes
+ * Copyright (C) 2002, 2003, 2005 Ulf Harnhammar
+ *
+ * This program is free software and open source software; you can redistribute
+ * it and/or modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * [kses strips evil scripts!]
+ *
+ * Added wp_ prefix to avoid conflicts with existing kses users
+ *
+ * @version 0.2.2
+ * @copyright (C) 2002, 2003, 2005
+ * @author Ulf Harnhammar <http://advogato.org/person/metaur/>
+ *
+ * @package External
+ * @subpackage KSES
+ *
+ */
+
+/**
+ * You can override this in a plugin.
+ *
+ * The wp_kses_allowed_html filter is more powerful and supplies context.
+ * CUSTOM_TAGS is not recommended and should be considered deprecated.
+ *
+ * @see wp_kses_allowed_html()
+ *
+ * @since 1.2.0
+ */
+if ( ! defined( 'CUSTOM_TAGS' ) )
+ define( 'CUSTOM_TAGS', false );
+
+if ( ! CUSTOM_TAGS ) {
+ /**
+ * Kses global for default allowable HTML tags.
+ *
+ * Can be override by using CUSTOM_TAGS constant.
+ *
+ * @global array $allowedposttags
+ * @since 2.0.0
+ */
+ $allowedposttags = array(
+ 'address' => array(),
+ 'a' => array(
+ 'href' => true,
+ 'rel' => true,
+ 'rev' => true,
+ 'name' => true,
+ 'target' => true,
+ ),
+ 'abbr' => array(),
+ 'acronym' => array(),
+ 'area' => array(
+ 'alt' => true,
+ 'coords' => true,
+ 'href' => true,
+ 'nohref' => true,
+ 'shape' => true,
+ 'target' => true,
+ ),
+ 'article' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'aside' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'b' => array(),
+ 'big' => array(),
+ 'blockquote' => array(
+ 'cite' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'br' => array(),
+ 'button' => array(
+ 'disabled' => true,
+ 'name' => true,
+ 'type' => true,
+ 'value' => true,
+ ),
+ 'caption' => array(
+ 'align' => true,
+ ),
+ 'cite' => array(
+ 'dir' => true,
+ 'lang' => true,
+ ),
+ 'code' => array(),
+ 'col' => array(
+ 'align' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'span' => true,
+ 'dir' => true,
+ 'valign' => true,
+ 'width' => true,
+ ),
+ 'del' => array(
+ 'datetime' => true,
+ ),
+ 'dd' => array(),
+ 'details' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'open' => true,
+ 'xml:lang' => true,
+ ),
+ 'div' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'dl' => array(),
+ 'dt' => array(),
+ 'em' => array(),
+ 'fieldset' => array(),
+ 'figure' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'figcaption' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'font' => array(
+ 'color' => true,
+ 'face' => true,
+ 'size' => true,
+ ),
+ 'footer' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'form' => array(
+ 'action' => true,
+ 'accept' => true,
+ 'accept-charset' => true,
+ 'enctype' => true,
+ 'method' => true,
+ 'name' => true,
+ 'target' => true,
+ ),
+ 'h1' => array(
+ 'align' => true,
+ ),
+ 'h2' => array(
+ 'align' => true,
+ ),
+ 'h3' => array(
+ 'align' => true,
+ ),
+ 'h4' => array(
+ 'align' => true,
+ ),
+ 'h5' => array(
+ 'align' => true,
+ ),
+ 'h6' => array(
+ 'align' => true,
+ ),
+ 'header' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'hgroup' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'hr' => array(
+ 'align' => true,
+ 'noshade' => true,
+ 'size' => true,
+ 'width' => true,
+ ),
+ 'i' => array(),
+ 'img' => array(
+ 'alt' => true,
+ 'align' => true,
+ 'border' => true,
+ 'height' => true,
+ 'hspace' => true,
+ 'longdesc' => true,
+ 'vspace' => true,
+ 'src' => true,
+ 'usemap' => true,
+ 'width' => true,
+ ),
+ 'ins' => array(
+ 'datetime' => true,
+ 'cite' => true,
+ ),
+ 'kbd' => array(),
+ 'label' => array(
+ 'for' => true,
+ ),
+ 'legend' => array(
+ 'align' => true,
+ ),
+ 'li' => array(
+ 'align' => true,
+ ),
+ 'map' => array(
+ 'name' => true,
+ ),
+ 'menu' => array(
+ 'type' => true,
+ ),
+ 'nav' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'p' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'pre' => array(
+ 'width' => true,
+ ),
+ 'q' => array(
+ 'cite' => true,
+ ),
+ 's' => array(),
+ 'span' => array(
+ 'dir' => true,
+ 'align' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'section' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'small' => array(),
+ 'strike' => array(),
+ 'strong' => array(),
+ 'sub' => array(),
+ 'summary' => array(
+ 'align' => true,
+ 'dir' => true,
+ 'lang' => true,
+ 'xml:lang' => true,
+ ),
+ 'sup' => array(),
+ 'table' => array(
+ 'align' => true,
+ 'bgcolor' => true,
+ 'border' => true,
+ 'cellpadding' => true,
+ 'cellspacing' => true,
+ 'dir' => true,
+ 'rules' => true,
+ 'summary' => true,
+ 'width' => true,
+ ),
+ 'tbody' => array(
+ 'align' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'valign' => true,
+ ),
+ 'td' => array(
+ 'abbr' => true,
+ 'align' => true,
+ 'axis' => true,
+ 'bgcolor' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'colspan' => true,
+ 'dir' => true,
+ 'headers' => true,
+ 'height' => true,
+ 'nowrap' => true,
+ 'rowspan' => true,
+ 'scope' => true,
+ 'valign' => true,
+ 'width' => true,
+ ),
+ 'textarea' => array(
+ 'cols' => true,
+ 'rows' => true,
+ 'disabled' => true,
+ 'name' => true,
+ 'readonly' => true,
+ ),
+ 'tfoot' => array(
+ 'align' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'valign' => true,
+ ),
+ 'th' => array(
+ 'abbr' => true,
+ 'align' => true,
+ 'axis' => true,
+ 'bgcolor' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'colspan' => true,
+ 'headers' => true,
+ 'height' => true,
+ 'nowrap' => true,
+ 'rowspan' => true,
+ 'scope' => true,
+ 'valign' => true,
+ 'width' => true,
+ ),
+ 'thead' => array(
+ 'align' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'valign' => true,
+ ),
+ 'title' => array(),
+ 'tr' => array(
+ 'align' => true,
+ 'bgcolor' => true,
+ 'char' => true,
+ 'charoff' => true,
+ 'valign' => true,
+ ),
+ 'tt' => array(),
+ 'u' => array(),
+ 'ul' => array(
+ 'type' => true,
+ ),
+ 'ol' => array(
+ 'start' => true,
+ 'type' => true,
+ ),
+ 'var' => array(),
+ );
+
+ /**
+ * Kses allowed HTML elements.
+ *
+ * @global array $allowedtags
+ * @since 1.0.0
+ */
+ $allowedtags = array(
+ 'a' => array(
+ 'href' => true,
+ 'title' => true,
+ ),
+ 'abbr' => array(
+ 'title' => true,
+ ),
+ 'acronym' => array(
+ 'title' => true,
+ ),
+ 'b' => array(),
+ 'blockquote' => array(
+ 'cite' => true,
+ ),
+ 'cite' => array(),
+ 'code' => array(),
+ 'del' => array(
+ 'datetime' => true,
+ ),
+ 'em' => array(),
+ 'i' => array(),
+ 'q' => array(
+ 'cite' => true,
+ ),
+ 'strike' => array(),
+ 'strong' => array(),
+ );
+
+ $allowedentitynames = array(
+ 'nbsp', 'iexcl', 'cent', 'pound', 'curren', 'yen',
+ 'brvbar', 'sect', 'uml', 'copy', 'ordf', 'laquo',
+ 'not', 'shy', 'reg', 'macr', 'deg', 'plusmn',
+ 'acute', 'micro', 'para', 'middot', 'cedil', 'ordm',
+ 'raquo', 'iquest', 'Agrave', 'Aacute', 'Acirc', 'Atilde',
+ 'Auml', 'Aring', 'AElig', 'Ccedil', 'Egrave', 'Eacute',
+ 'Ecirc', 'Euml', 'Igrave', 'Iacute', 'Icirc', 'Iuml',
+ 'ETH', 'Ntilde', 'Ograve', 'Oacute', 'Ocirc', 'Otilde',
+ 'Ouml', 'times', 'Oslash', 'Ugrave', 'Uacute', 'Ucirc',
+ 'Uuml', 'Yacute', 'THORN', 'szlig', 'agrave', 'aacute',
+ 'acirc', 'atilde', 'auml', 'aring', 'aelig', 'ccedil',
+ 'egrave', 'eacute', 'ecirc', 'euml', 'igrave', 'iacute',
+ 'icirc', 'iuml', 'eth', 'ntilde', 'ograve', 'oacute',
+ 'ocirc', 'otilde', 'ouml', 'divide', 'oslash', 'ugrave',
+ 'uacute', 'ucirc', 'uuml', 'yacute', 'thorn', 'yuml',
+ 'quot', 'amp', 'lt', 'gt', 'apos', 'OElig',
+ 'oelig', 'Scaron', 'scaron', 'Yuml', 'circ', 'tilde',
+ 'ensp', 'emsp', 'thinsp', 'zwnj', 'zwj', 'lrm',
+ 'rlm', 'ndash', 'mdash', 'lsquo', 'rsquo', 'sbquo',
+ 'ldquo', 'rdquo', 'bdquo', 'dagger', 'Dagger', 'permil',
+ 'lsaquo', 'rsaquo', 'euro', 'fnof', 'Alpha', 'Beta',
+ 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta',
+ 'Iota', 'Kappa', 'Lambda', 'Mu', 'Nu', 'Xi',
+ 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon',
+ 'Phi', 'Chi', 'Psi', 'Omega', 'alpha', 'beta',
+ 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta',
+ 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi',
+ 'omicron', 'pi', 'rho', 'sigmaf', 'sigma', 'tau',
+ 'upsilon', 'phi', 'chi', 'psi', 'omega', 'thetasym',
+ 'upsih', 'piv', 'bull', 'hellip', 'prime', 'Prime',
+ 'oline', 'frasl', 'weierp', 'image', 'real', 'trade',
+ 'alefsym', 'larr', 'uarr', 'rarr', 'darr', 'harr',
+ 'crarr', 'lArr', 'uArr', 'rArr', 'dArr', 'hArr',
+ 'forall', 'part', 'exist', 'empty', 'nabla', 'isin',
+ 'notin', 'ni', 'prod', 'sum', 'minus', 'lowast',
+ 'radic', 'prop', 'infin', 'ang', 'and', 'or',
+ 'cap', 'cup', 'int', 'sim', 'cong', 'asymp',
+ 'ne', 'equiv', 'le', 'ge', 'sub', 'sup',
+ 'nsub', 'sube', 'supe', 'oplus', 'otimes', 'perp',
+ 'sdot', 'lceil', 'rceil', 'lfloor', 'rfloor', 'lang',
+ 'rang', 'loz', 'spades', 'clubs', 'hearts', 'diams',
+ );
+
+ $allowedposttags = array_map( '_wp_add_global_attributes', $allowedposttags );
+} else {
+ $allowedtags = wp_kses_array_lc( $allowedtags );
+ $allowedposttags = wp_kses_array_lc( $allowedposttags );
+}
+
+/**
+ * Filters content and keeps only allowable HTML elements.
+ *
+ * This function makes sure that only the allowed HTML element names, attribute
+ * names and attribute values plus only sane HTML entities will occur in
+ * $string. You have to remove any slashes from PHP's magic quotes before you
+ * call this function.
+ *
+ * The default allowed protocols are 'http', 'https', 'ftp', 'mailto', 'news',
+ * 'irc', 'gopher', 'nntp', 'feed', 'telnet, 'mms', 'rtsp' and 'svn'. This
+ * covers all common link protocols, except for 'javascript' which should not
+ * be allowed for untrusted users.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter through kses
+ * @param array $allowed_html List of allowed HTML elements
+ * @param array $allowed_protocols Optional. Allowed protocol in links.
+ * @return string Filtered content with only allowed HTML elements
+ */
+function wp_kses( $string, $allowed_html, $allowed_protocols = array() ) {
+ if ( empty( $allowed_protocols ) )
+ $allowed_protocols = wp_allowed_protocols();
+ $string = wp_kses_no_null($string);
+ $string = wp_kses_js_entities($string);
+ $string = wp_kses_normalize_entities($string);
+ $string = wp_kses_hook($string, $allowed_html, $allowed_protocols); // WP changed the order of these funcs and added args to wp_kses_hook
+ return wp_kses_split($string, $allowed_html, $allowed_protocols);
+}
+
+/**
+ * Return a list of allowed tags and attributes for a given context.
+ *
+ * @since 3.5.0
+ *
+ * @param string $context The context for which to retrieve tags. Allowed values are
+ * post | strip | data | entities or the name of a field filter such as pre_user_description.
+ * @return array List of allowed tags and their allowed attributes.
+ */
+function wp_kses_allowed_html( $context = '' ) {
+ global $allowedposttags, $allowedtags, $allowedentitynames;
+
+ if ( is_array( $context ) )
+ return apply_filters( 'wp_kses_allowed_html', $context, 'explicit' );
+
+ switch ( $context ) {
+ case 'post':
+ return apply_filters( 'wp_kses_allowed_html', $allowedposttags, $context );
+ break;
+ case 'user_description':
+ case 'pre_user_description':
+ $tags = $allowedtags;
+ $tags['a']['rel'] = true;
+ return apply_filters( 'wp_kses_allowed_html', $tags, $context );
+ break;
+ case 'strip':
+ return apply_filters( 'wp_kses_allowed_html', array(), $context );
+ break;
+ case 'entities':
+ return apply_filters( 'wp_kses_allowed_html', $allowedentitynames, $context);
+ break;
+ case 'data':
+ default:
+ return apply_filters( 'wp_kses_allowed_html', $allowedtags, $context );
+ }
+}
+
+/**
+ * You add any kses hooks here.
+ *
+ * There is currently only one kses WordPress hook and it is called here. All
+ * parameters are passed to the hooks and expected to receive a string.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter through kses
+ * @param array $allowed_html List of allowed HTML elements
+ * @param array $allowed_protocols Allowed protocol in links
+ * @return string Filtered content through 'pre_kses' hook
+ */
+function wp_kses_hook( $string, $allowed_html, $allowed_protocols ) {
+ $string = apply_filters('pre_kses', $string, $allowed_html, $allowed_protocols);
+ return $string;
+}
+
+/**
+ * This function returns kses' version number.
+ *
+ * @since 1.0.0
+ *
+ * @return string KSES Version Number
+ */
+function wp_kses_version() {
+ return '0.2.2';
+}
+
+/**
+ * Searches for HTML tags, no matter how malformed.
+ *
+ * It also matches stray ">" characters.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter
+ * @param array $allowed_html Allowed HTML elements
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Content with fixed HTML tags
+ */
+function wp_kses_split( $string, $allowed_html, $allowed_protocols ) {
+ global $pass_allowed_html, $pass_allowed_protocols;
+ $pass_allowed_html = $allowed_html;
+ $pass_allowed_protocols = $allowed_protocols;
+ return preg_replace_callback( '%(<!--.*?(-->|$))|(<[^>]*(>|$)|>)%', '_wp_kses_split_callback', $string );
+}
+
+/**
+ * Callback for wp_kses_split.
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _wp_kses_split_callback( $match ) {
+ global $pass_allowed_html, $pass_allowed_protocols;
+ return wp_kses_split2( $match[0], $pass_allowed_html, $pass_allowed_protocols );
+}
+
+/**
+ * Callback for wp_kses_split for fixing malformed HTML tags.
+ *
+ * This function does a lot of work. It rejects some very malformed things like
+ * <:::>. It returns an empty string, if the element isn't allowed (look ma, no
+ * strip_tags()!). Otherwise it splits the tag into an element and an attribute
+ * list.
+ *
+ * After the tag is split into an element and an attribute list, it is run
+ * through another filter which will remove illegal attributes and once that is
+ * completed, will be returned.
+ *
+ * @access private
+ * @since 1.0.0
+ * @uses wp_kses_attr()
+ *
+ * @param string $string Content to filter
+ * @param array $allowed_html Allowed HTML elements
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Fixed HTML element
+ */
+function wp_kses_split2($string, $allowed_html, $allowed_protocols) {
+ $string = wp_kses_stripslashes($string);
+
+ if (substr($string, 0, 1) != '<')
+ return '&gt;';
+ # It matched a ">" character
+
+ if ( '<!--' == substr( $string, 0, 4 ) ) {
+ $string = str_replace( array('<!--', '-->'), '', $string );
+ while ( $string != ($newstring = wp_kses($string, $allowed_html, $allowed_protocols)) )
+ $string = $newstring;
+ if ( $string == '' )
+ return '';
+ // prevent multiple dashes in comments
+ $string = preg_replace('/--+/', '-', $string);
+ // prevent three dashes closing a comment
+ $string = preg_replace('/-$/', '', $string);
+ return "<!--{$string}-->";
+ }
+ # Allow HTML comments
+
+ if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?$%', $string, $matches))
+ return '';
+ # It's seriously malformed
+
+ $slash = trim($matches[1]);
+ $elem = $matches[2];
+ $attrlist = $matches[3];
+
+ if ( ! is_array( $allowed_html ) )
+ $allowed_html = wp_kses_allowed_html( $allowed_html );
+
+ if ( ! isset($allowed_html[strtolower($elem)]) )
+ return '';
+ # They are using a not allowed HTML element
+
+ if ($slash != '')
+ return "</$elem>";
+ # No attributes are allowed for closing elements
+
+ return wp_kses_attr( $elem, $attrlist, $allowed_html, $allowed_protocols );
+}
+
+/**
+ * Removes all attributes, if none are allowed for this element.
+ *
+ * If some are allowed it calls wp_kses_hair() to split them further, and then
+ * it builds up new HTML code from the data that kses_hair() returns. It also
+ * removes "<" and ">" characters, if there are any left. One more thing it does
+ * is to check if the tag has a closing XHTML slash, and if it does, it puts one
+ * in the returned code as well.
+ *
+ * @since 1.0.0
+ *
+ * @param string $element HTML element/tag
+ * @param string $attr HTML attributes from HTML element to closing HTML element tag
+ * @param array $allowed_html Allowed HTML elements
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Sanitized HTML element
+ */
+function wp_kses_attr($element, $attr, $allowed_html, $allowed_protocols) {
+ # Is there a closing XHTML slash at the end of the attributes?
+
+ if ( ! is_array( $allowed_html ) )
+ $allowed_html = wp_kses_allowed_html( $allowed_html );
+
+ $xhtml_slash = '';
+ if (preg_match('%\s*/\s*$%', $attr))
+ $xhtml_slash = ' /';
+
+ # Are any attributes allowed at all for this element?
+ if ( ! isset($allowed_html[strtolower($element)]) || count($allowed_html[strtolower($element)]) == 0 )
+ return "<$element$xhtml_slash>";
+
+ # Split it
+ $attrarr = wp_kses_hair($attr, $allowed_protocols);
+
+ # Go through $attrarr, and save the allowed attributes for this element
+ # in $attr2
+ $attr2 = '';
+
+ $allowed_attr = $allowed_html[strtolower($element)];
+ foreach ($attrarr as $arreach) {
+ if ( ! isset( $allowed_attr[strtolower($arreach['name'])] ) )
+ continue; # the attribute is not allowed
+
+ $current = $allowed_attr[strtolower($arreach['name'])];
+ if ( $current == '' )
+ continue; # the attribute is not allowed
+
+ if ( strtolower( $arreach['name'] ) == 'style' ) {
+ $orig_value = $arreach['value'];
+ $value = safecss_filter_attr( $orig_value );
+
+ if ( empty( $value ) )
+ continue;
+
+ $arreach['value'] = $value;
+ $arreach['whole'] = str_replace( $orig_value, $value, $arreach['whole'] );
+ }
+
+ if ( ! is_array($current) ) {
+ $attr2 .= ' '.$arreach['whole'];
+ # there are no checks
+
+ } else {
+ # there are some checks
+ $ok = true;
+ foreach ($current as $currkey => $currval) {
+ if ( ! wp_kses_check_attr_val($arreach['value'], $arreach['vless'], $currkey, $currval) ) {
+ $ok = false;
+ break;
+ }
+ }
+
+ if ( $ok )
+ $attr2 .= ' '.$arreach['whole']; # it passed them
+ } # if !is_array($current)
+ } # foreach
+
+ # Remove any "<" or ">" characters
+ $attr2 = preg_replace('/[<>]/', '', $attr2);
+
+ return "<$element$attr2$xhtml_slash>";
+}
+
+/**
+ * Builds an attribute list from string containing attributes.
+ *
+ * This function does a lot of work. It parses an attribute list into an array
+ * with attribute data, and tries to do the right thing even if it gets weird
+ * input. It will add quotes around attribute values that don't have any quotes
+ * or apostrophes around them, to make it easier to produce HTML code that will
+ * conform to W3C's HTML specification. It will also remove bad URL protocols
+ * from attribute values. It also reduces duplicate attributes by using the
+ * attribute defined first (foo='bar' foo='baz' will result in foo='bar').
+ *
+ * @since 1.0.0
+ *
+ * @param string $attr Attribute list from HTML element to closing HTML element tag
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return array List of attributes after parsing
+ */
+function wp_kses_hair($attr, $allowed_protocols) {
+ $attrarr = array();
+ $mode = 0;
+ $attrname = '';
+ $uris = array('xmlns', 'profile', 'href', 'src', 'cite', 'classid', 'codebase', 'data', 'usemap', 'longdesc', 'action');
+
+ # Loop through the whole attribute list
+
+ while (strlen($attr) != 0) {
+ $working = 0; # Was the last operation successful?
+
+ switch ($mode) {
+ case 0 : # attribute name, href for instance
+
+ if (preg_match('/^([-a-zA-Z]+)/', $attr, $match)) {
+ $attrname = $match[1];
+ $working = $mode = 1;
+ $attr = preg_replace('/^[-a-zA-Z]+/', '', $attr);
+ }
+
+ break;
+
+ case 1 : # equals sign or valueless ("selected")
+
+ if (preg_match('/^\s*=\s*/', $attr)) # equals sign
+ {
+ $working = 1;
+ $mode = 2;
+ $attr = preg_replace('/^\s*=\s*/', '', $attr);
+ break;
+ }
+
+ if (preg_match('/^\s+/', $attr)) # valueless
+ {
+ $working = 1;
+ $mode = 0;
+ if(false === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
+ }
+ $attr = preg_replace('/^\s+/', '', $attr);
+ }
+
+ break;
+
+ case 2 : # attribute value, a URL after href= for instance
+
+ if (preg_match('%^"([^"]*)"(\s+|/?$)%', $attr, $match))
+ # "value"
+ {
+ $thisval = $match[1];
+ if ( in_array(strtolower($attrname), $uris) )
+ $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
+
+ if(false === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
+ }
+ $working = 1;
+ $mode = 0;
+ $attr = preg_replace('/^"[^"]*"(\s+|$)/', '', $attr);
+ break;
+ }
+
+ if (preg_match("%^'([^']*)'(\s+|/?$)%", $attr, $match))
+ # 'value'
+ {
+ $thisval = $match[1];
+ if ( in_array(strtolower($attrname), $uris) )
+ $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
+
+ if(false === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname='$thisval'", 'vless' => 'n');
+ }
+ $working = 1;
+ $mode = 0;
+ $attr = preg_replace("/^'[^']*'(\s+|$)/", '', $attr);
+ break;
+ }
+
+ if (preg_match("%^([^\s\"']+)(\s+|/?$)%", $attr, $match))
+ # value
+ {
+ $thisval = $match[1];
+ if ( in_array(strtolower($attrname), $uris) )
+ $thisval = wp_kses_bad_protocol($thisval, $allowed_protocols);
+
+ if(false === array_key_exists($attrname, $attrarr)) {
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => $thisval, 'whole' => "$attrname=\"$thisval\"", 'vless' => 'n');
+ }
+ # We add quotes to conform to W3C's HTML spec.
+ $working = 1;
+ $mode = 0;
+ $attr = preg_replace("%^[^\s\"']+(\s+|$)%", '', $attr);
+ }
+
+ break;
+ } # switch
+
+ if ($working == 0) # not well formed, remove and try again
+ {
+ $attr = wp_kses_html_error($attr);
+ $mode = 0;
+ }
+ } # while
+
+ if ($mode == 1 && false === array_key_exists($attrname, $attrarr))
+ # special case, for when the attribute list ends with a valueless
+ # attribute like "selected"
+ $attrarr[$attrname] = array ('name' => $attrname, 'value' => '', 'whole' => $attrname, 'vless' => 'y');
+
+ return $attrarr;
+}
+
+/**
+ * Performs different checks for attribute values.
+ *
+ * The currently implemented checks are "maxlen", "minlen", "maxval", "minval"
+ * and "valueless".
+ *
+ * @since 1.0.0
+ *
+ * @param string $value Attribute value
+ * @param string $vless Whether the value is valueless. Use 'y' or 'n'
+ * @param string $checkname What $checkvalue is checking for.
+ * @param mixed $checkvalue What constraint the value should pass
+ * @return bool Whether check passes
+ */
+function wp_kses_check_attr_val($value, $vless, $checkname, $checkvalue) {
+ $ok = true;
+
+ switch (strtolower($checkname)) {
+ case 'maxlen' :
+ # The maxlen check makes sure that the attribute value has a length not
+ # greater than the given value. This can be used to avoid Buffer Overflows
+ # in WWW clients and various Internet servers.
+
+ if (strlen($value) > $checkvalue)
+ $ok = false;
+ break;
+
+ case 'minlen' :
+ # The minlen check makes sure that the attribute value has a length not
+ # smaller than the given value.
+
+ if (strlen($value) < $checkvalue)
+ $ok = false;
+ break;
+
+ case 'maxval' :
+ # The maxval check does two things: it checks that the attribute value is
+ # an integer from 0 and up, without an excessive amount of zeroes or
+ # whitespace (to avoid Buffer Overflows). It also checks that the attribute
+ # value is not greater than the given value.
+ # This check can be used to avoid Denial of Service attacks.
+
+ if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
+ $ok = false;
+ if ($value > $checkvalue)
+ $ok = false;
+ break;
+
+ case 'minval' :
+ # The minval check makes sure that the attribute value is a positive integer,
+ # and that it is not smaller than the given value.
+
+ if (!preg_match('/^\s{0,6}[0-9]{1,6}\s{0,6}$/', $value))
+ $ok = false;
+ if ($value < $checkvalue)
+ $ok = false;
+ break;
+
+ case 'valueless' :
+ # The valueless check makes sure if the attribute has a value
+ # (like <a href="blah">) or not (<option selected>). If the given value
+ # is a "y" or a "Y", the attribute must not have a value.
+ # If the given value is an "n" or an "N", the attribute must have one.
+
+ if (strtolower($checkvalue) != $vless)
+ $ok = false;
+ break;
+ } # switch
+
+ return $ok;
+}
+
+/**
+ * Sanitize string from bad protocols.
+ *
+ * This function removes all non-allowed protocols from the beginning of
+ * $string. It ignores whitespace and the case of the letters, and it does
+ * understand HTML entities. It does its work in a while loop, so it won't be
+ * fooled by a string like "javascript:javascript:alert(57)".
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to filter bad protocols from
+ * @param array $allowed_protocols Allowed protocols to keep
+ * @return string Filtered content
+ */
+function wp_kses_bad_protocol($string, $allowed_protocols) {
+ $string = wp_kses_no_null($string);
+ $iterations = 0;
+
+ do {
+ $original_string = $string;
+ $string = wp_kses_bad_protocol_once($string, $allowed_protocols);
+ } while ( $original_string != $string && ++$iterations < 6 );
+
+ if ( $original_string != $string )
+ return '';
+
+ return $string;
+}
+
+/**
+ * Removes any null characters in $string.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string
+ * @return string
+ */
+function wp_kses_no_null($string) {
+ $string = preg_replace('/\0+/', '', $string);
+ $string = preg_replace('/(\\\\0)+/', '', $string);
+
+ return $string;
+}
+
+/**
+ * Strips slashes from in front of quotes.
+ *
+ * This function changes the character sequence \" to just ". It leaves all
+ * other slashes alone. It's really weird, but the quoting from
+ * preg_replace(//e) seems to require this.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string String to strip slashes
+ * @return string Fixed string with quoted slashes
+ */
+function wp_kses_stripslashes($string) {
+ return preg_replace('%\\\\"%', '"', $string);
+}
+
+/**
+ * Goes through an array and changes the keys to all lower case.
+ *
+ * @since 1.0.0
+ *
+ * @param array $inarray Unfiltered array
+ * @return array Fixed array with all lowercase keys
+ */
+function wp_kses_array_lc($inarray) {
+ $outarray = array ();
+
+ foreach ( (array) $inarray as $inkey => $inval) {
+ $outkey = strtolower($inkey);
+ $outarray[$outkey] = array ();
+
+ foreach ( (array) $inval as $inkey2 => $inval2) {
+ $outkey2 = strtolower($inkey2);
+ $outarray[$outkey][$outkey2] = $inval2;
+ } # foreach $inval
+ } # foreach $inarray
+
+ return $outarray;
+}
+
+/**
+ * Removes the HTML JavaScript entities found in early versions of Netscape 4.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string
+ * @return string
+ */
+function wp_kses_js_entities($string) {
+ return preg_replace('%&\s*\{[^}]*(\}\s*;?|$)%', '', $string);
+}
+
+/**
+ * Handles parsing errors in wp_kses_hair().
+ *
+ * The general plan is to remove everything to and including some whitespace,
+ * but it deals with quotes and apostrophes as well.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string
+ * @return string
+ */
+function wp_kses_html_error($string) {
+ return preg_replace('/^("[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*/', '', $string);
+}
+
+/**
+ * Sanitizes content from bad protocols and other characters.
+ *
+ * This function searches for URL protocols at the beginning of $string, while
+ * handling whitespace and HTML entities.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to check for bad protocols
+ * @param string $allowed_protocols Allowed protocols
+ * @return string Sanitized content
+ */
+function wp_kses_bad_protocol_once($string, $allowed_protocols, $count = 1 ) {
+ $string2 = preg_split( '/:|&#0*58;|&#x0*3a;/i', $string, 2 );
+ if ( isset($string2[1]) && ! preg_match('%/\?%', $string2[0]) ) {
+ $string = trim( $string2[1] );
+ $protocol = wp_kses_bad_protocol_once2( $string2[0], $allowed_protocols );
+ if ( 'feed:' == $protocol ) {
+ if ( $count > 2 )
+ return '';
+ $string = wp_kses_bad_protocol_once( $string, $allowed_protocols, ++$count );
+ if ( empty( $string ) )
+ return $string;
+ }
+ $string = $protocol . $string;
+ }
+
+ return $string;
+}
+
+/**
+ * Callback for wp_kses_bad_protocol_once() regular expression.
+ *
+ * This function processes URL protocols, checks to see if they're in the
+ * whitelist or not, and returns different data depending on the answer.
+ *
+ * @access private
+ * @since 1.0.0
+ *
+ * @param string $string URI scheme to check against the whitelist
+ * @param string $allowed_protocols Allowed protocols
+ * @return string Sanitized content
+ */
+function wp_kses_bad_protocol_once2( $string, $allowed_protocols ) {
+ $string2 = wp_kses_decode_entities($string);
+ $string2 = preg_replace('/\s/', '', $string2);
+ $string2 = wp_kses_no_null($string2);
+ $string2 = strtolower($string2);
+
+ $allowed = false;
+ foreach ( (array) $allowed_protocols as $one_protocol )
+ if ( strtolower($one_protocol) == $string2 ) {
+ $allowed = true;
+ break;
+ }
+
+ if ($allowed)
+ return "$string2:";
+ else
+ return '';
+}
+
+/**
+ * Converts and fixes HTML entities.
+ *
+ * This function normalizes HTML entities. It will convert "AT&T" to the correct
+ * "AT&amp;T", "&#00058;" to "&#58;", "&#XYZZY;" to "&amp;#XYZZY;" and so on.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to normalize entities
+ * @return string Content with normalized entities
+ */
+function wp_kses_normalize_entities($string) {
+ # Disarm all entities by converting & to &amp;
+
+ $string = str_replace('&', '&amp;', $string);
+
+ # Change back the allowed entities in our entity whitelist
+
+ $string = preg_replace_callback('/&amp;([A-Za-z]{2,8});/', 'wp_kses_named_entities', $string);
+ $string = preg_replace_callback('/&amp;#(0*[0-9]{1,7});/', 'wp_kses_normalize_entities2', $string);
+ $string = preg_replace_callback('/&amp;#[Xx](0*[0-9A-Fa-f]{1,6});/', 'wp_kses_normalize_entities3', $string);
+
+ return $string;
+}
+
+/**
+ * Callback for wp_kses_normalize_entities() regular expression.
+ *
+ * This function only accepts valid named entity references, which are finite,
+ * case-sensitive, and highly scrutinized by HTML and XML validators.
+ *
+ * @since 3.0.0
+ *
+ * @param array $matches preg_replace_callback() matches array
+ * @return string Correctly encoded entity
+ */
+function wp_kses_named_entities($matches) {
+ global $allowedentitynames;
+
+ if ( empty($matches[1]) )
+ return '';
+
+ $i = $matches[1];
+ return ( ( ! in_array($i, $allowedentitynames) ) ? "&amp;$i;" : "&$i;" );
+}
+
+/**
+ * Callback for wp_kses_normalize_entities() regular expression.
+ *
+ * This function helps wp_kses_normalize_entities() to only accept 16-bit values
+ * and nothing more for &#number; entities.
+ *
+ * @access private
+ * @since 1.0.0
+ *
+ * @param array $matches preg_replace_callback() matches array
+ * @return string Correctly encoded entity
+ */
+function wp_kses_normalize_entities2($matches) {
+ if ( empty($matches[1]) )
+ return '';
+
+ $i = $matches[1];
+ if (valid_unicode($i)) {
+ $i = str_pad(ltrim($i,'0'), 3, '0', STR_PAD_LEFT);
+ $i = "&#$i;";
+ } else {
+ $i = "&amp;#$i;";
+ }
+
+ return $i;
+}
+
+/**
+ * Callback for wp_kses_normalize_entities() for regular expression.
+ *
+ * This function helps wp_kses_normalize_entities() to only accept valid Unicode
+ * numeric entities in hex form.
+ *
+ * @access private
+ *
+ * @param array $matches preg_replace_callback() matches array
+ * @return string Correctly encoded entity
+ */
+function wp_kses_normalize_entities3($matches) {
+ if ( empty($matches[1]) )
+ return '';
+
+ $hexchars = $matches[1];
+ return ( ( ! valid_unicode(hexdec($hexchars)) ) ? "&amp;#x$hexchars;" : '&#x'.ltrim($hexchars,'0').';' );
+}
+
+/**
+ * Helper function to determine if a Unicode value is valid.
+ *
+ * @param int $i Unicode value
+ * @return bool True if the value was a valid Unicode number
+ */
+function valid_unicode($i) {
+ return ( $i == 0x9 || $i == 0xa || $i == 0xd ||
+ ($i >= 0x20 && $i <= 0xd7ff) ||
+ ($i >= 0xe000 && $i <= 0xfffd) ||
+ ($i >= 0x10000 && $i <= 0x10ffff) );
+}
+
+/**
+ * Convert all entities to their character counterparts.
+ *
+ * This function decodes numeric HTML entities (&#65; and &#x41;). It doesn't do
+ * anything with other entities like &auml;, but we don't need them in the URL
+ * protocol whitelisting system anyway.
+ *
+ * @since 1.0.0
+ *
+ * @param string $string Content to change entities
+ * @return string Content after decoded entities
+ */
+function wp_kses_decode_entities($string) {
+ $string = preg_replace_callback('/&#([0-9]+);/', '_wp_kses_decode_entities_chr', $string);
+ $string = preg_replace_callback('/&#[Xx]([0-9A-Fa-f]+);/', '_wp_kses_decode_entities_chr_hexdec', $string);
+
+ return $string;
+}
+
+/**
+ * Regex callback for wp_kses_decode_entities()
+ *
+ * @param array $match preg match
+ * @return string
+ */
+function _wp_kses_decode_entities_chr( $match ) {
+ return chr( $match[1] );
+}
+
+/**
+ * Regex callback for wp_kses_decode_entities()
+ *
+ * @param array $match preg match
+ * @return string
+ */
+function _wp_kses_decode_entities_chr_hexdec( $match ) {
+ return chr( hexdec( $match[1] ) );
+}
+
+/**
+ * Sanitize content with allowed HTML Kses rules.
+ *
+ * @since 1.0.0
+ * @uses $allowedtags
+ *
+ * @param string $data Content to filter, expected to be escaped with slashes
+ * @return string Filtered content
+ */
+function wp_filter_kses( $data ) {
+ return addslashes( wp_kses( stripslashes( $data ), current_filter() ) );
+}
+
+/**
+ * Sanitize content with allowed HTML Kses rules.
+ *
+ * @since 2.9.0
+ * @uses $allowedtags
+ *
+ * @param string $data Content to filter, expected to not be escaped
+ * @return string Filtered content
+ */
+function wp_kses_data( $data ) {
+ return wp_kses( $data , current_filter() );
+}
+
+/**
+ * Sanitize content for allowed HTML tags for post content.
+ *
+ * Post content refers to the page contents of the 'post' type and not $_POST
+ * data from forms.
+ *
+ * @since 2.0.0
+ *
+ * @param string $data Post content to filter, expected to be escaped with slashes
+ * @return string Filtered post content with allowed HTML tags and attributes intact.
+ */
+function wp_filter_post_kses($data) {
+ return addslashes ( wp_kses( stripslashes( $data ), 'post' ) );
+}
+
+/**
+ * Sanitize content for allowed HTML tags for post content.
+ *
+ * Post content refers to the page contents of the 'post' type and not $_POST
+ * data from forms.
+ *
+ * @since 2.9.0
+ *
+ * @param string $data Post content to filter
+ * @return string Filtered post content with allowed HTML tags and attributes intact.
+ */
+function wp_kses_post($data) {
+ return wp_kses( $data , 'post' );
+}
+
+/**
+ * Strips all of the HTML in the content.
+ *
+ * @since 2.1.0
+ *
+ * @param string $data Content to strip all HTML from
+ * @return string Filtered content without any HTML
+ */
+function wp_filter_nohtml_kses( $data ) {
+ return addslashes ( wp_kses( stripslashes( $data ), 'strip' ) );
+}
+
+/**
+ * Adds all Kses input form content filters.
+ *
+ * All hooks have default priority. The wp_filter_kses() function is added to
+ * the 'pre_comment_content' and 'title_save_pre' hooks.
+ *
+ * The wp_filter_post_kses() function is added to the 'content_save_pre',
+ * 'excerpt_save_pre', and 'content_filtered_save_pre' hooks.
+ *
+ * @since 2.0.0
+ * @uses add_filter() See description for what functions are added to what hooks.
+ */
+function kses_init_filters() {
+ // Normal filtering
+ add_filter('title_save_pre', 'wp_filter_kses');
+
+ // Comment filtering
+ if ( current_user_can( 'unfiltered_html' ) )
+ add_filter( 'pre_comment_content', 'wp_filter_post_kses' );
+ else
+ add_filter( 'pre_comment_content', 'wp_filter_kses' );
+
+ // Post filtering
+ add_filter('content_save_pre', 'wp_filter_post_kses');
+ add_filter('excerpt_save_pre', 'wp_filter_post_kses');
+ add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
+}
+
+/**
+ * Removes all Kses input form content filters.
+ *
+ * A quick procedural method to removing all of the filters that kses uses for
+ * content in WordPress Loop.
+ *
+ * Does not remove the kses_init() function from 'init' hook (priority is
+ * default). Also does not remove kses_init() function from 'set_current_user'
+ * hook (priority is also default).
+ *
+ * @since 2.0.6
+ */
+function kses_remove_filters() {
+ // Normal filtering
+ remove_filter('title_save_pre', 'wp_filter_kses');
+
+ // Comment filtering
+ remove_filter( 'pre_comment_content', 'wp_filter_post_kses' );
+ remove_filter( 'pre_comment_content', 'wp_filter_kses' );
+
+ // Post filtering
+ remove_filter('content_save_pre', 'wp_filter_post_kses');
+ remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
+ remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
+}
+
+/**
+ * Sets up most of the Kses filters for input form content.
+ *
+ * If you remove the kses_init() function from 'init' hook and
+ * 'set_current_user' (priority is default), then none of the Kses filter hooks
+ * will be added.
+ *
+ * First removes all of the Kses filters in case the current user does not need
+ * to have Kses filter the content. If the user does not have unfiltered_html
+ * capability, then Kses filters are added.
+ *
+ * @uses kses_remove_filters() Removes the Kses filters
+ * @uses kses_init_filters() Adds the Kses filters back if the user
+ * does not have unfiltered HTML capability.
+ * @since 2.0.0
+ */
+function kses_init() {
+ kses_remove_filters();
+
+ if (current_user_can('unfiltered_html') == false)
+ kses_init_filters();
+}
+
+add_action('init', 'kses_init');
+add_action('set_current_user', 'kses_init');
+
+/**
+ * Inline CSS filter
+ *
+ * @since 2.8.1
+ */
+function safecss_filter_attr( $css, $deprecated = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented
+
+ $css = wp_kses_no_null($css);
+ $css = str_replace(array("\n","\r","\t"), '', $css);
+
+ if ( preg_match( '%[\\(&=}]|/\*%', $css ) ) // remove any inline css containing \ ( & } = or comments
+ return '';
+
+ $css_array = explode( ';', trim( $css ) );
+ $allowed_attr = apply_filters( 'safe_style_css', array( 'text-align', 'margin', 'color', 'float',
+ 'border', 'background', 'background-color', 'border-bottom', 'border-bottom-color',
+ 'border-bottom-style', 'border-bottom-width', 'border-collapse', 'border-color', 'border-left',
+ 'border-left-color', 'border-left-style', 'border-left-width', 'border-right', 'border-right-color',
+ 'border-right-style', 'border-right-width', 'border-spacing', 'border-style', 'border-top',
+ 'border-top-color', 'border-top-style', 'border-top-width', 'border-width', 'caption-side',
+ 'clear', 'cursor', 'direction', 'font', 'font-family', 'font-size', 'font-style',
+ 'font-variant', 'font-weight', 'height', 'letter-spacing', 'line-height', 'margin-bottom',
+ 'margin-left', 'margin-right', 'margin-top', 'overflow', 'padding', 'padding-bottom',
+ 'padding-left', 'padding-right', 'padding-top', 'text-decoration', 'text-indent', 'vertical-align',
+ 'width' ) );
+
+ if ( empty($allowed_attr) )
+ return $css;
+
+ $css = '';
+ foreach ( $css_array as $css_item ) {
+ if ( $css_item == '' )
+ continue;
+ $css_item = trim( $css_item );
+ $found = false;
+ if ( strpos( $css_item, ':' ) === false ) {
+ $found = true;
+ } else {
+ $parts = explode( ':', $css_item );
+ if ( in_array( trim( $parts[0] ), $allowed_attr ) )
+ $found = true;
+ }
+ if ( $found ) {
+ if( $css != '' )
+ $css .= ';';
+ $css .= $css_item;
+ }
+ }
+
+ return $css;
+}
+
+/**
+ * Helper function to add global attributes to a tag in the allowed html list.
+ *
+ * @since 3.5.0
+ * @access private
+ *
+ * @param array $value An array of attributes.
+ * @return array The array of attributes with global attributes added.
+ */
+function _wp_add_global_attributes( $value ) {
+ $global_attributes = array(
+ 'class' => true,
+ 'id' => true,
+ 'style' => true,
+ 'title' => true,
+ );
+
+ if ( true === $value )
+ $value = array();
+
+ if ( is_array( $value ) )
+ return array_merge( $value, $global_attributes );
+
+ return $value;
+}
diff --git a/src/wp-includes/l10n.php b/src/wp-includes/l10n.php
new file mode 100644
index 0000000000..4df86ba60a
--- /dev/null
+++ b/src/wp-includes/l10n.php
@@ -0,0 +1,575 @@
+<?php
+/**
+ * WordPress Translation API
+ *
+ * @package WordPress
+ * @subpackage i18n
+ */
+
+/**
+ * Gets the current locale.
+ *
+ * If the locale is set, then it will filter the locale in the 'locale' filter
+ * hook and return the value.
+ *
+ * If the locale is not set already, then the WPLANG constant is used if it is
+ * defined. Then it is filtered through the 'locale' filter hook and the value
+ * for the locale global set and the locale is returned.
+ *
+ * The process to get the locale should only be done once, but the locale will
+ * always be filtered using the 'locale' hook.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'locale' hook on locale value.
+ * @uses $locale Gets the locale stored in the global.
+ *
+ * @return string The locale of the blog or from the 'locale' hook.
+ */
+function get_locale() {
+ global $locale;
+
+ if ( isset( $locale ) )
+ return apply_filters( 'locale', $locale );
+
+ // WPLANG is defined in wp-config.
+ if ( defined( 'WPLANG' ) )
+ $locale = WPLANG;
+
+ // If multisite, check options.
+ if ( is_multisite() ) {
+ // Don't check blog option when installing.
+ if ( defined( 'WP_INSTALLING' ) || ( false === $ms_locale = get_option( 'WPLANG' ) ) )
+ $ms_locale = get_site_option('WPLANG');
+
+ if ( $ms_locale !== false )
+ $locale = $ms_locale;
+ }
+
+ if ( empty( $locale ) )
+ $locale = 'en_US';
+
+ return apply_filters( 'locale', $locale );
+}
+
+/**
+ * Retrieves the translation of $text. If there is no translation, or
+ * the domain isn't loaded, the original text is returned.
+ *
+ * @see __() Don't use translate() directly, use __()
+ * @since 2.2.0
+ * @uses apply_filters() Calls 'gettext' on domain translated text
+ * with the untranslated text as second parameter.
+ *
+ * @param string $text Text to translate.
+ * @param string $domain Domain to retrieve the translated text.
+ * @return string Translated text
+ */
+function translate( $text, $domain = 'default' ) {
+ $translations = get_translations_for_domain( $domain );
+ return apply_filters( 'gettext', $translations->translate( $text ), $text, $domain );
+}
+
+function before_last_bar( $string ) {
+ $last_bar = strrpos( $string, '|' );
+ if ( false == $last_bar )
+ return $string;
+ else
+ return substr( $string, 0, $last_bar );
+}
+
+function translate_with_gettext_context( $text, $context, $domain = 'default' ) {
+ $translations = get_translations_for_domain( $domain );
+ return apply_filters( 'gettext_with_context', $translations->translate( $text, $context ), $text, $context, $domain );
+}
+
+/**
+ * Retrieves the translation of $text. If there is no translation, or
+ * the domain isn't loaded, the original text is returned.
+ *
+ * @see translate() An alias of translate()
+ * @since 2.1.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function __( $text, $domain = 'default' ) {
+ return translate( $text, $domain );
+}
+
+/**
+ * Retrieves the translation of $text and escapes it for safe use in an attribute.
+ * If there is no translation, or the domain isn't loaded, the original text is returned.
+ *
+ * @see translate() An alias of translate()
+ * @see esc_attr()
+ * @since 2.8.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function esc_attr__( $text, $domain = 'default' ) {
+ return esc_attr( translate( $text, $domain ) );
+}
+
+/**
+ * Retrieves the translation of $text and escapes it for safe use in HTML output.
+ * If there is no translation, or the domain isn't loaded, the original text is returned.
+ *
+ * @see translate() An alias of translate()
+ * @see esc_html()
+ * @since 2.8.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function esc_html__( $text, $domain = 'default' ) {
+ return esc_html( translate( $text, $domain ) );
+}
+
+/**
+ * Displays the returned translated text from translate().
+ *
+ * @see translate() Echoes returned translate() string
+ * @since 1.2.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ */
+function _e( $text, $domain = 'default' ) {
+ echo translate( $text, $domain );
+}
+
+/**
+ * Displays translated text that has been escaped for safe use in an attribute.
+ *
+ * @see translate() Echoes returned translate() string
+ * @see esc_attr()
+ * @since 2.8.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ */
+function esc_attr_e( $text, $domain = 'default' ) {
+ echo esc_attr( translate( $text, $domain ) );
+}
+
+/**
+ * Displays translated text that has been escaped for safe use in HTML output.
+ *
+ * @see translate() Echoes returned translate() string
+ * @see esc_html()
+ * @since 2.8.0
+ *
+ * @param string $text Text to translate
+ * @param string $domain Optional. Domain to retrieve the translated text
+ */
+function esc_html_e( $text, $domain = 'default' ) {
+ echo esc_html( translate( $text, $domain ) );
+}
+
+/**
+ * Retrieve translated string with gettext context
+ *
+ * Quite a few times, there will be collisions with similar translatable text
+ * found in more than two places but with different translated context.
+ *
+ * By including the context in the pot file translators can translate the two
+ * strings differently.
+ *
+ * @since 2.8.0
+ *
+ * @param string $text Text to translate
+ * @param string $context Context information for the translators
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated context string without pipe
+ */
+function _x( $text, $context, $domain = 'default' ) {
+ return translate_with_gettext_context( $text, $context, $domain );
+}
+
+/**
+ * Displays translated string with gettext context
+ *
+ * @see _x
+ * @since 3.0.0
+ *
+ * @param string $text Text to translate
+ * @param string $context Context information for the translators
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated context string without pipe
+ */
+function _ex( $text, $context, $domain = 'default' ) {
+ echo _x( $text, $context, $domain );
+}
+
+/**
+ * Displays translated string with gettext context and escapes it for safe use in an attribute.
+ *
+ * @see esc_attr()
+ * @since 2.8.0
+ *
+ * @param string $text Text to translate
+ * @param string $context Context information for the translators
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function esc_attr_x( $text, $context, $domain = 'default' ) {
+ return esc_attr( translate_with_gettext_context( $text, $context, $domain ) );
+}
+
+/**
+ * Displays translated string with gettext context and escapes it for safe use in HTML output.
+ *
+ * @see esc_html()
+ * @since 2.9.0
+ *
+ * @param string $text Text to translate
+ * @param string $context Context information for the translators
+ * @param string $domain Optional. Domain to retrieve the translated text
+ * @return string Translated text
+ */
+function esc_html_x( $text, $context, $domain = 'default' ) {
+ return esc_html( translate_with_gettext_context( $text, $context, $domain ) );
+}
+
+/**
+ * Retrieve the plural or single form based on the amount.
+ *
+ * If the domain is not set in the $l10n list, then a comparison will be made
+ * and either $plural or $single parameters returned.
+ *
+ * If the domain does exist, then the parameters $single, $plural, and $number
+ * will first be passed to the domain's ngettext method. Then it will be passed
+ * to the 'ngettext' filter hook along with the same parameters. The expected
+ * type will be a string.
+ *
+ * @since 2.8.0
+ * @uses $l10n Gets list of domain translated string (gettext_reader) objects
+ * @uses apply_filters() Calls 'ngettext' hook on domains text returned,
+ * along with $single, $plural, and $number parameters. Expected to return string.
+ *
+ * @param string $single The text that will be used if $number is 1
+ * @param string $plural The text that will be used if $number is not 1
+ * @param int $number The number to compare against to use either $single or $plural
+ * @param string $domain Optional. The domain identifier the text should be retrieved in
+ * @return string Either $single or $plural translated text
+ */
+function _n( $single, $plural, $number, $domain = 'default' ) {
+ $translations = get_translations_for_domain( $domain );
+ $translation = $translations->translate_plural( $single, $plural, $number );
+ return apply_filters( 'ngettext', $translation, $single, $plural, $number, $domain );
+}
+
+/**
+ * A hybrid of _n() and _x(). It supports contexts and plurals.
+ *
+ * @see _n()
+ * @see _x()
+ *
+ */
+function _nx($single, $plural, $number, $context, $domain = 'default') {
+ $translations = get_translations_for_domain( $domain );
+ $translation = $translations->translate_plural( $single, $plural, $number, $context );
+ return apply_filters( 'ngettext_with_context', $translation, $single, $plural, $number, $context, $domain );
+}
+
+/**
+ * Register plural strings in POT file, but don't translate them.
+ *
+ * Used when you want to keep structures with translatable plural strings and
+ * use them later.
+ *
+ * Example:
+ * $messages = array(
+ * 'post' => _n_noop('%s post', '%s posts'),
+ * 'page' => _n_noop('%s pages', '%s pages')
+ * );
+ * ...
+ * $message = $messages[$type];
+ * $usable_text = sprintf( translate_nooped_plural( $message, $count ), $count );
+ *
+ * @since 2.5
+ * @param string $singular Single form to be i18ned
+ * @param string $plural Plural form to be i18ned
+ * @param string $domain Optional. The domain identifier the text will be retrieved in
+ * @return array array($singular, $plural)
+ */
+function _n_noop( $singular, $plural, $domain = null ) {
+ return array( 0 => $singular, 1 => $plural, 'singular' => $singular, 'plural' => $plural, 'context' => null, 'domain' => $domain );
+}
+
+/**
+ * Register plural strings with context in POT file, but don't translate them.
+ *
+ * @see _n_noop()
+ */
+function _nx_noop( $singular, $plural, $context, $domain = null ) {
+ return array( 0 => $singular, 1 => $plural, 2 => $context, 'singular' => $singular, 'plural' => $plural, 'context' => $context, 'domain' => $domain );
+}
+
+/**
+ * Translate the result of _n_noop() or _nx_noop()
+ *
+ * @since 3.1
+ * @param array $nooped_plural Array with singular, plural and context keys, usually the result of _n_noop() or _nx_noop()
+ * @param int $count Number of objects
+ * @param string $domain Optional. The domain identifier the text should be retrieved in. If $nooped_plural contains
+ * a domain passed to _n_noop() or _nx_noop(), it will override this value.
+ */
+function translate_nooped_plural( $nooped_plural, $count, $domain = 'default' ) {
+ if ( $nooped_plural['domain'] )
+ $domain = $nooped_plural['domain'];
+
+ if ( $nooped_plural['context'] )
+ return _nx( $nooped_plural['singular'], $nooped_plural['plural'], $count, $nooped_plural['context'], $domain );
+ else
+ return _n( $nooped_plural['singular'], $nooped_plural['plural'], $count, $domain );
+}
+
+/**
+ * Loads a MO file into the domain $domain.
+ *
+ * If the domain already exists, the translations will be merged. If both
+ * sets have the same string, the translation from the original value will be taken.
+ *
+ * On success, the .mo file will be placed in the $l10n global by $domain
+ * and will be a MO object.
+ *
+ * @since 1.5.0
+ * @uses $l10n Gets list of domain translated string objects
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ * @param string $mofile Path to the .mo file
+ * @return bool True on success, false on failure
+ */
+function load_textdomain( $domain, $mofile ) {
+ global $l10n;
+
+ $plugin_override = apply_filters( 'override_load_textdomain', false, $domain, $mofile );
+
+ if ( true == $plugin_override ) {
+ return true;
+ }
+
+ do_action( 'load_textdomain', $domain, $mofile );
+
+ $mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
+
+ if ( !is_readable( $mofile ) ) return false;
+
+ $mo = new MO();
+ if ( !$mo->import_from_file( $mofile ) ) return false;
+
+ if ( isset( $l10n[$domain] ) )
+ $mo->merge_with( $l10n[$domain] );
+
+ $l10n[$domain] = &$mo;
+
+ return true;
+}
+
+/**
+ * Unloads translations for a domain
+ *
+ * @since 3.0.0
+ * @param string $domain Textdomain to be unloaded
+ * @return bool Whether textdomain was unloaded
+ */
+function unload_textdomain( $domain ) {
+ global $l10n;
+
+ $plugin_override = apply_filters( 'override_unload_textdomain', false, $domain );
+
+ if ( $plugin_override )
+ return true;
+
+ do_action( 'unload_textdomain', $domain );
+
+ if ( isset( $l10n[$domain] ) ) {
+ unset( $l10n[$domain] );
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Loads default translated strings based on locale.
+ *
+ * Loads the .mo file in WP_LANG_DIR constant path from WordPress root. The
+ * translated (.mo) file is named based on the locale.
+ *
+ * @since 1.5.0
+ */
+function load_default_textdomain() {
+ $locale = get_locale();
+
+ load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo" );
+
+ if ( ( is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) ) && ! file_exists( WP_LANG_DIR . "/admin-$locale.mo" ) ) {
+ load_textdomain( 'default', WP_LANG_DIR . "/ms-$locale.mo" );
+ return;
+ }
+
+ if ( is_admin() || ( defined( 'WP_REPAIRING' ) && WP_REPAIRING ) )
+ load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
+
+ if ( is_network_admin() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK ) )
+ load_textdomain( 'default', WP_LANG_DIR . "/admin-network-$locale.mo" );
+
+}
+
+/**
+ * Loads the plugin's translated strings.
+ *
+ * If the path is not given then it will be the root of the plugin directory.
+ * The .mo file should be named based on the domain with a dash, and then the locale exactly.
+ *
+ * @since 1.5.0
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ * @param string $abs_rel_path Optional. Relative path to ABSPATH of a folder,
+ * where the .mo file resides. Deprecated, but still functional until 2.7
+ * @param string $plugin_rel_path Optional. Relative path to WP_PLUGIN_DIR. This is the preferred argument to use. It takes precedence over $abs_rel_path
+ */
+function load_plugin_textdomain( $domain, $abs_rel_path = false, $plugin_rel_path = false ) {
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
+
+ if ( false !== $plugin_rel_path ) {
+ $path = WP_PLUGIN_DIR . '/' . trim( $plugin_rel_path, '/' );
+ } else if ( false !== $abs_rel_path ) {
+ _deprecated_argument( __FUNCTION__, '2.7' );
+ $path = ABSPATH . trim( $abs_rel_path, '/' );
+ } else {
+ $path = WP_PLUGIN_DIR;
+ }
+
+ $mofile = $path . '/'. $domain . '-' . $locale . '.mo';
+ return load_textdomain( $domain, $mofile );
+}
+
+/**
+ * Load the translated strings for a plugin residing in the mu-plugins dir.
+ *
+ * @since 3.0.0
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ * @param string $mu_plugin_rel_path Relative to WPMU_PLUGIN_DIR directory in which
+ * the MO file resides. Defaults to empty string.
+ */
+function load_muplugin_textdomain( $domain, $mu_plugin_rel_path = '' ) {
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
+ $path = WPMU_PLUGIN_DIR . '/' . ltrim( $mu_plugin_rel_path, '/' );
+ load_textdomain( $domain, trailingslashit( $path ) . "$domain-$locale.mo" );
+}
+
+/**
+ * Loads the theme's translated strings.
+ *
+ * If the current locale exists as a .mo file in the theme's root directory, it
+ * will be included in the translated strings by the $domain.
+ *
+ * The .mo files must be named based on the locale exactly.
+ *
+ * @since 1.5.0
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ */
+function load_theme_textdomain( $domain, $path = false ) {
+ $locale = apply_filters( 'theme_locale', get_locale(), $domain );
+
+ if ( ! $path )
+ $path = get_template_directory();
+
+ // Load the textdomain from the Theme provided location, or theme directory first
+ $mofile = "{$path}/{$locale}.mo";
+ if ( $loaded = load_textdomain($domain, $mofile) )
+ return $loaded;
+
+ // Else, load textdomain from the Language directory
+ $mofile = WP_LANG_DIR . "/themes/{$domain}-{$locale}.mo";
+ return load_textdomain($domain, $mofile);
+}
+
+/**
+ * Loads the child themes translated strings.
+ *
+ * If the current locale exists as a .mo file in the child themes root directory, it
+ * will be included in the translated strings by the $domain.
+ *
+ * The .mo files must be named based on the locale exactly.
+ *
+ * @since 2.9.0
+ *
+ * @param string $domain Unique identifier for retrieving translated strings
+ */
+function load_child_theme_textdomain( $domain, $path = false ) {
+ if ( ! $path )
+ $path = get_stylesheet_directory();
+ return load_theme_textdomain( $domain, $path );
+}
+
+/**
+ * Returns the Translations instance for a domain. If there isn't one,
+ * returns empty Translations instance.
+ *
+ * @param string $domain
+ * @return object A Translation instance
+ */
+function get_translations_for_domain( $domain ) {
+ global $l10n;
+ if ( !isset( $l10n[$domain] ) ) {
+ $l10n[$domain] = new NOOP_Translations;
+ }
+ return $l10n[$domain];
+}
+
+/**
+ * Whether there are translations for the domain
+ *
+ * @since 3.0.0
+ * @param string $domain
+ * @return bool Whether there are translations
+ */
+function is_textdomain_loaded( $domain ) {
+ global $l10n;
+ return isset( $l10n[$domain] );
+}
+
+/**
+ * Translates role name. Since the role names are in the database and
+ * not in the source there are dummy gettext calls to get them into the POT
+ * file and this function properly translates them back.
+ *
+ * The before_last_bar() call is needed, because older installs keep the roles
+ * using the old context format: 'Role name|User role' and just skipping the
+ * content after the last bar is easier than fixing them in the DB. New installs
+ * won't suffer from that problem.
+ */
+function translate_user_role( $name ) {
+ return translate_with_gettext_context( before_last_bar($name), 'User role' );
+}
+
+/**
+ * Get all available languages based on the presence of *.mo files in a given directory. The default directory is WP_LANG_DIR.
+ *
+ * @since 3.0.0
+ *
+ * @param string $dir A directory in which to search for language files. The default directory is WP_LANG_DIR.
+ * @return array Array of language codes or an empty array if no languages are present. Language codes are formed by stripping the .mo extension from the language file names.
+ */
+function get_available_languages( $dir = null ) {
+ $languages = array();
+
+ foreach( (array)glob( ( is_null( $dir) ? WP_LANG_DIR : $dir ) . '/*.mo' ) as $lang_file ) {
+ $lang_file = basename($lang_file, '.mo');
+ if ( 0 !== strpos( $lang_file, 'continents-cities' ) && 0 !== strpos( $lang_file, 'ms-' ) &&
+ 0 !== strpos( $lang_file, 'admin-' ))
+ $languages[] = $lang_file;
+ }
+
+ return $languages;
+} \ No newline at end of file
diff --git a/src/wp-includes/link-template.php b/src/wp-includes/link-template.php
new file mode 100644
index 0000000000..5fb61726fb
--- /dev/null
+++ b/src/wp-includes/link-template.php
@@ -0,0 +1,2442 @@
+<?php
+/**
+ * WordPress Link Template Functions
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Display the permalink for the current post.
+ *
+ * @since 1.2.0
+ * @uses apply_filters() Calls 'the_permalink' filter on the permalink string.
+ */
+function the_permalink() {
+ echo esc_url( apply_filters( 'the_permalink', get_permalink() ) );
+}
+
+/**
+ * Retrieve trailing slash string, if blog set for adding trailing slashes.
+ *
+ * Conditionally adds a trailing slash if the permalink structure has a trailing
+ * slash, strips the trailing slash if not. The string is passed through the
+ * 'user_trailingslashit' filter. Will remove trailing slash from string, if
+ * blog is not set to have them.
+ *
+ * @since 2.2.0
+ * @uses $wp_rewrite
+ *
+ * @param string $string URL with or without a trailing slash.
+ * @param string $type_of_url The type of URL being considered (e.g. single, category, etc) for use in the filter.
+ * @return string
+ */
+function user_trailingslashit($string, $type_of_url = '') {
+ global $wp_rewrite;
+ if ( $wp_rewrite->use_trailing_slashes )
+ $string = trailingslashit($string);
+ else
+ $string = untrailingslashit($string);
+
+ // Note that $type_of_url can be one of following:
+ // single, single_trackback, single_feed, single_paged, feed, category, page, year, month, day, paged, post_type_archive
+ $string = apply_filters('user_trailingslashit', $string, $type_of_url);
+ return $string;
+}
+
+/**
+ * Display permalink anchor for current post.
+ *
+ * The permalink mode title will use the post title for the 'a' element 'id'
+ * attribute. The id mode uses 'post-' with the post ID for the 'id' attribute.
+ *
+ * @since 0.71
+ *
+ * @param string $mode Permalink mode can be either 'title', 'id', or default, which is 'id'.
+ */
+function permalink_anchor( $mode = 'id' ) {
+ $post = get_post();
+ switch ( strtolower( $mode ) ) {
+ case 'title':
+ $title = sanitize_title( $post->post_title ) . '-' . $post->ID;
+ echo '<a id="'.$title.'"></a>';
+ break;
+ case 'id':
+ default:
+ echo '<a id="post-' . $post->ID . '"></a>';
+ break;
+ }
+}
+
+/**
+ * Retrieve full permalink for current post or post ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $leavename Optional, defaults to false. Whether to keep post name or page name.
+ * @return string
+ */
+function get_permalink( $id = 0, $leavename = false ) {
+ $rewritecode = array(
+ '%year%',
+ '%monthnum%',
+ '%day%',
+ '%hour%',
+ '%minute%',
+ '%second%',
+ $leavename? '' : '%postname%',
+ '%post_id%',
+ '%category%',
+ '%author%',
+ $leavename? '' : '%pagename%',
+ );
+
+ if ( is_object($id) && isset($id->filter) && 'sample' == $id->filter ) {
+ $post = $id;
+ $sample = true;
+ } else {
+ $post = get_post($id);
+ $sample = false;
+ }
+
+ if ( empty($post->ID) )
+ return false;
+
+ if ( $post->post_type == 'page' )
+ return get_page_link($post->ID, $leavename, $sample);
+ elseif ( $post->post_type == 'attachment' )
+ return get_attachment_link( $post->ID, $leavename );
+ elseif ( in_array($post->post_type, get_post_types( array('_builtin' => false) ) ) )
+ return get_post_permalink($post->ID, $leavename, $sample);
+
+ $permalink = get_option('permalink_structure');
+
+ $permalink = apply_filters('pre_post_link', $permalink, $post, $leavename);
+
+ if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft')) ) {
+ $unixtime = strtotime($post->post_date);
+
+ $category = '';
+ if ( strpos($permalink, '%category%') !== false ) {
+ $cats = get_the_category($post->ID);
+ if ( $cats ) {
+ usort($cats, '_usort_terms_by_ID'); // order by ID
+ $category_object = apply_filters( 'post_link_category', $cats[0], $cats, $post );
+ $category_object = get_term( $category_object, 'category' );
+ $category = $category_object->slug;
+ if ( $parent = $category_object->parent )
+ $category = get_category_parents($parent, false, '/', true) . $category;
+ }
+ // show default category in permalinks, without
+ // having to assign it explicitly
+ if ( empty($category) ) {
+ $default_category = get_category( get_option( 'default_category' ) );
+ $category = is_wp_error( $default_category ) ? '' : $default_category->slug;
+ }
+ }
+
+ $author = '';
+ if ( strpos($permalink, '%author%') !== false ) {
+ $authordata = get_userdata($post->post_author);
+ $author = $authordata->user_nicename;
+ }
+
+ $date = explode(" ",date('Y m d H i s', $unixtime));
+ $rewritereplace =
+ array(
+ $date[0],
+ $date[1],
+ $date[2],
+ $date[3],
+ $date[4],
+ $date[5],
+ $post->post_name,
+ $post->ID,
+ $category,
+ $author,
+ $post->post_name,
+ );
+ $permalink = home_url( str_replace($rewritecode, $rewritereplace, $permalink) );
+ $permalink = user_trailingslashit($permalink, 'single');
+ } else { // if they're not using the fancy permalink option
+ $permalink = home_url('?p=' . $post->ID);
+ }
+ return apply_filters('post_link', $permalink, $post, $leavename);
+}
+
+/**
+ * Retrieve the permalink for a post with a custom post type.
+ *
+ * @since 3.0.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $leavename Optional, defaults to false. Whether to keep post name.
+ * @param bool $sample Optional, defaults to false. Is it a sample permalink.
+ * @return string
+ */
+function get_post_permalink( $id = 0, $leavename = false, $sample = false ) {
+ global $wp_rewrite;
+
+ $post = get_post($id);
+
+ if ( is_wp_error( $post ) )
+ return $post;
+
+ $post_link = $wp_rewrite->get_extra_permastruct($post->post_type);
+
+ $slug = $post->post_name;
+
+ $draft_or_pending = isset($post->post_status) && in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) );
+
+ $post_type = get_post_type_object($post->post_type);
+
+ if ( !empty($post_link) && ( !$draft_or_pending || $sample ) ) {
+ if ( ! $leavename ) {
+ if ( $post_type->hierarchical )
+ $slug = get_page_uri($id);
+ $post_link = str_replace("%$post->post_type%", $slug, $post_link);
+ }
+ $post_link = home_url( user_trailingslashit($post_link) );
+ } else {
+ if ( $post_type->query_var && ( isset($post->post_status) && !$draft_or_pending ) )
+ $post_link = add_query_arg($post_type->query_var, $slug, '');
+ else
+ $post_link = add_query_arg(array('post_type' => $post->post_type, 'p' => $post->ID), '');
+ $post_link = home_url($post_link);
+ }
+
+ return apply_filters('post_type_link', $post_link, $post, $leavename, $sample);
+}
+
+/**
+ * Retrieve permalink from post ID.
+ *
+ * @since 1.0.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @param mixed $deprecated Not used.
+ * @return string
+ */
+function post_permalink( $post_id = 0, $deprecated = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '1.3' );
+
+ return get_permalink($post_id);
+}
+
+/**
+ * Retrieve the permalink for current page or page ID.
+ *
+ * Respects page_on_front. Use this one.
+ *
+ * @since 1.5.0
+ *
+ * @param int|object $post Optional. Post ID or object.
+ * @param bool $leavename Optional, defaults to false. Whether to keep page name.
+ * @param bool $sample Optional, defaults to false. Is it a sample permalink.
+ * @return string
+ */
+function get_page_link( $post = false, $leavename = false, $sample = false ) {
+ $post = get_post( $post );
+
+ if ( 'page' == get_option( 'show_on_front' ) && $post->ID == get_option( 'page_on_front' ) )
+ $link = home_url('/');
+ else
+ $link = _get_page_link( $post, $leavename, $sample );
+
+ return apply_filters( 'page_link', $link, $post->ID, $sample );
+}
+
+/**
+ * Retrieve the page permalink.
+ *
+ * Ignores page_on_front. Internal use only.
+ *
+ * @since 2.1.0
+ * @access private
+ *
+ * @param int|object $post Optional. Post ID or object.
+ * @param bool $leavename Optional. Leave name.
+ * @param bool $sample Optional. Sample permalink.
+ * @return string
+ */
+function _get_page_link( $post = false, $leavename = false, $sample = false ) {
+ global $wp_rewrite;
+
+ $post = get_post( $post );
+
+ $draft_or_pending = in_array( $post->post_status, array( 'draft', 'pending', 'auto-draft' ) );
+
+ $link = $wp_rewrite->get_page_permastruct();
+
+ if ( !empty($link) && ( ( isset($post->post_status) && !$draft_or_pending ) || $sample ) ) {
+ if ( ! $leavename ) {
+ $link = str_replace('%pagename%', get_page_uri( $post ), $link);
+ }
+
+ $link = home_url($link);
+ $link = user_trailingslashit($link, 'page');
+ } else {
+ $link = home_url( '?page_id=' . $post->ID );
+ }
+
+ return apply_filters( '_get_page_link', $link, $post->ID );
+}
+
+/**
+ * Retrieve permalink for attachment.
+ *
+ * This can be used in the WordPress Loop or outside of it.
+ *
+ * @since 2.0.0
+ *
+ * @param int|object $post Optional. Post ID or object.
+ * @param bool $leavename Optional. Leave name.
+ * @return string
+ */
+function get_attachment_link( $post = null, $leavename = false ) {
+ global $wp_rewrite;
+
+ $link = false;
+
+ $post = get_post( $post );
+ $parent = ( $post->post_parent > 0 && $post->post_parent != $post->ID ) ? get_post( $post->post_parent ) : false;
+
+ if ( $wp_rewrite->using_permalinks() && $parent ) {
+ if ( 'page' == $parent->post_type )
+ $parentlink = _get_page_link( $post->post_parent ); // Ignores page_on_front
+ else
+ $parentlink = get_permalink( $post->post_parent );
+
+ if ( is_numeric($post->post_name) || false !== strpos(get_option('permalink_structure'), '%category%') )
+ $name = 'attachment/' . $post->post_name; // <permalink>/<int>/ is paged so we use the explicit attachment marker
+ else
+ $name = $post->post_name;
+
+ if ( strpos($parentlink, '?') === false )
+ $link = user_trailingslashit( trailingslashit($parentlink) . '%postname%' );
+
+ if ( ! $leavename )
+ $link = str_replace( '%postname%', $name, $link );
+ }
+
+ if ( ! $link )
+ $link = home_url( '/?attachment_id=' . $post->ID );
+
+ return apply_filters( 'attachment_link', $link, $post->ID );
+}
+
+/**
+ * Retrieve the permalink for the year archives.
+ *
+ * @since 1.5.0
+ *
+ * @param int|bool $year False for current year or year for permalink.
+ * @return string
+ */
+function get_year_link($year) {
+ global $wp_rewrite;
+ if ( !$year )
+ $year = gmdate('Y', current_time('timestamp'));
+ $yearlink = $wp_rewrite->get_year_permastruct();
+ if ( !empty($yearlink) ) {
+ $yearlink = str_replace('%year%', $year, $yearlink);
+ return apply_filters('year_link', home_url( user_trailingslashit($yearlink, 'year') ), $year);
+ } else {
+ return apply_filters('year_link', home_url('?m=' . $year), $year);
+ }
+}
+
+/**
+ * Retrieve the permalink for the month archives with year.
+ *
+ * @since 1.0.0
+ *
+ * @param bool|int $year False for current year. Integer of year.
+ * @param bool|int $month False for current month. Integer of month.
+ * @return string
+ */
+function get_month_link($year, $month) {
+ global $wp_rewrite;
+ if ( !$year )
+ $year = gmdate('Y', current_time('timestamp'));
+ if ( !$month )
+ $month = gmdate('m', current_time('timestamp'));
+ $monthlink = $wp_rewrite->get_month_permastruct();
+ if ( !empty($monthlink) ) {
+ $monthlink = str_replace('%year%', $year, $monthlink);
+ $monthlink = str_replace('%monthnum%', zeroise(intval($month), 2), $monthlink);
+ return apply_filters('month_link', home_url( user_trailingslashit($monthlink, 'month') ), $year, $month);
+ } else {
+ return apply_filters('month_link', home_url( '?m=' . $year . zeroise($month, 2) ), $year, $month);
+ }
+}
+
+/**
+ * Retrieve the permalink for the day archives with year and month.
+ *
+ * @since 1.0.0
+ *
+ * @param bool|int $year False for current year. Integer of year.
+ * @param bool|int $month False for current month. Integer of month.
+ * @param bool|int $day False for current day. Integer of day.
+ * @return string
+ */
+function get_day_link($year, $month, $day) {
+ global $wp_rewrite;
+ if ( !$year )
+ $year = gmdate('Y', current_time('timestamp'));
+ if ( !$month )
+ $month = gmdate('m', current_time('timestamp'));
+ if ( !$day )
+ $day = gmdate('j', current_time('timestamp'));
+
+ $daylink = $wp_rewrite->get_day_permastruct();
+ if ( !empty($daylink) ) {
+ $daylink = str_replace('%year%', $year, $daylink);
+ $daylink = str_replace('%monthnum%', zeroise(intval($month), 2), $daylink);
+ $daylink = str_replace('%day%', zeroise(intval($day), 2), $daylink);
+ return apply_filters('day_link', home_url( user_trailingslashit($daylink, 'day') ), $year, $month, $day);
+ } else {
+ return apply_filters('day_link', home_url( '?m=' . $year . zeroise($month, 2) . zeroise($day, 2) ), $year, $month, $day);
+ }
+}
+
+/**
+ * Display the permalink for the feed type.
+ *
+ * @since 3.0.0
+ *
+ * @param string $anchor The link's anchor text.
+ * @param string $feed Optional, defaults to default feed. Feed type.
+ */
+function the_feed_link( $anchor, $feed = '' ) {
+ $link = '<a href="' . esc_url( get_feed_link( $feed ) ) . '">' . $anchor . '</a>';
+ echo apply_filters( 'the_feed_link', $link, $feed );
+}
+
+/**
+ * Retrieve the permalink for the feed type.
+ *
+ * @since 1.5.0
+ *
+ * @param string $feed Optional, defaults to default feed. Feed type.
+ * @return string
+ */
+function get_feed_link($feed = '') {
+ global $wp_rewrite;
+
+ $permalink = $wp_rewrite->get_feed_permastruct();
+ if ( '' != $permalink ) {
+ if ( false !== strpos($feed, 'comments_') ) {
+ $feed = str_replace('comments_', '', $feed);
+ $permalink = $wp_rewrite->get_comment_feed_permastruct();
+ }
+
+ if ( get_default_feed() == $feed )
+ $feed = '';
+
+ $permalink = str_replace('%feed%', $feed, $permalink);
+ $permalink = preg_replace('#/+#', '/', "/$permalink");
+ $output = home_url( user_trailingslashit($permalink, 'feed') );
+ } else {
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ if ( false !== strpos($feed, 'comments_') )
+ $feed = str_replace('comments_', 'comments-', $feed);
+
+ $output = home_url("?feed={$feed}");
+ }
+
+ return apply_filters('feed_link', $output, $feed);
+}
+
+/**
+ * Retrieve the permalink for the post comments feed.
+ *
+ * @since 2.2.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_post_comments_feed_link($post_id = 0, $feed = '') {
+ $post_id = absint( $post_id );
+
+ if ( ! $post_id )
+ $post_id = get_the_ID();
+
+ if ( empty( $feed ) )
+ $feed = get_default_feed();
+
+ if ( '' != get_option('permalink_structure') ) {
+ if ( 'page' == get_option('show_on_front') && $post_id == get_option('page_on_front') )
+ $url = _get_page_link( $post_id );
+ else
+ $url = get_permalink($post_id);
+
+ $url = trailingslashit($url) . 'feed';
+ if ( $feed != get_default_feed() )
+ $url .= "/$feed";
+ $url = user_trailingslashit($url, 'single_feed');
+ } else {
+ $type = get_post_field('post_type', $post_id);
+ if ( 'page' == $type )
+ $url = add_query_arg( array( 'feed' => $feed, 'page_id' => $post_id ), home_url( '/' ) );
+ else
+ $url = add_query_arg( array( 'feed' => $feed, 'p' => $post_id ), home_url( '/' ) );
+ }
+
+ return apply_filters('post_comments_feed_link', $url);
+}
+
+/**
+ * Display the comment feed link for a post.
+ *
+ * Prints out the comment feed link for a post. Link text is placed in the
+ * anchor. If no link text is specified, default text is used. If no post ID is
+ * specified, the current post is used.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param string $link_text Descriptive text.
+ * @param int $post_id Optional post ID. Default to current post.
+ * @param string $feed Optional. Feed format.
+ * @return string Link to the comment feed for the current post.
+*/
+function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '' ) {
+ $url = esc_url( get_post_comments_feed_link( $post_id, $feed ) );
+ if ( empty($link_text) )
+ $link_text = __('Comments Feed');
+
+ echo apply_filters( 'post_comments_feed_link_html', "<a href='$url'>$link_text</a>", $post_id, $feed );
+}
+
+/**
+ * Retrieve the feed link for a given author.
+ *
+ * Returns a link to the feed for all posts by a given author. A specific feed
+ * can be requested or left blank to get the default feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param int $author_id ID of an author.
+ * @param string $feed Optional. Feed type.
+ * @return string Link to the feed for the author specified by $author_id.
+*/
+function get_author_feed_link( $author_id, $feed = '' ) {
+ $author_id = (int) $author_id;
+ $permalink_structure = get_option('permalink_structure');
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ if ( '' == $permalink_structure ) {
+ $link = home_url("?feed=$feed&amp;author=" . $author_id);
+ } else {
+ $link = get_author_posts_url($author_id);
+ if ( $feed == get_default_feed() )
+ $feed_link = 'feed';
+ else
+ $feed_link = "feed/$feed";
+
+ $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
+ }
+
+ $link = apply_filters('author_feed_link', $link, $feed);
+
+ return $link;
+}
+
+/**
+ * Retrieve the feed link for a category.
+ *
+ * Returns a link to the feed for all posts in a given category. A specific feed
+ * can be requested or left blank to get the default feed.
+ *
+ * @package WordPress
+ * @subpackage Feed
+ * @since 2.5.0
+ *
+ * @param int $cat_id ID of a category.
+ * @param string $feed Optional. Feed type.
+ * @return string Link to the feed for the category specified by $cat_id.
+*/
+function get_category_feed_link($cat_id, $feed = '') {
+ return get_term_feed_link($cat_id, 'category', $feed);
+}
+
+/**
+ * Retrieve the feed link for a term.
+ *
+ * Returns a link to the feed for all posts in a given term. A specific feed
+ * can be requested or left blank to get the default feed.
+ *
+ * @since 3.0
+ *
+ * @param int $term_id ID of a category.
+ * @param string $taxonomy Optional. Taxonomy of $term_id
+ * @param string $feed Optional. Feed type.
+ * @return string Link to the feed for the term specified by $term_id and $taxonomy.
+*/
+function get_term_feed_link( $term_id, $taxonomy = 'category', $feed = '' ) {
+ $term_id = ( int ) $term_id;
+
+ $term = get_term( $term_id, $taxonomy );
+
+ if ( empty( $term ) || is_wp_error( $term ) )
+ return false;
+
+ if ( empty( $feed ) )
+ $feed = get_default_feed();
+
+ $permalink_structure = get_option( 'permalink_structure' );
+
+ if ( '' == $permalink_structure ) {
+ if ( 'category' == $taxonomy ) {
+ $link = home_url("?feed=$feed&amp;cat=$term_id");
+ }
+ elseif ( 'post_tag' == $taxonomy ) {
+ $link = home_url("?feed=$feed&amp;tag=$term->slug");
+ } else {
+ $t = get_taxonomy( $taxonomy );
+ $link = home_url("?feed=$feed&amp;$t->query_var=$term->slug");
+ }
+ } else {
+ $link = get_term_link( $term_id, $term->taxonomy );
+ if ( $feed == get_default_feed() )
+ $feed_link = 'feed';
+ else
+ $feed_link = "feed/$feed";
+
+ $link = trailingslashit( $link ) . user_trailingslashit( $feed_link, 'feed' );
+ }
+
+ if ( 'category' == $taxonomy )
+ $link = apply_filters( 'category_feed_link', $link, $feed );
+ elseif ( 'post_tag' == $taxonomy )
+ $link = apply_filters( 'tag_feed_link', $link, $feed );
+ else
+ $link = apply_filters( 'taxonomy_feed_link', $link, $feed, $taxonomy );
+
+ return $link;
+}
+
+/**
+ * Retrieve permalink for feed of tag.
+ *
+ * @since 2.3.0
+ *
+ * @param int $tag_id Tag ID.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_tag_feed_link($tag_id, $feed = '') {
+ return get_term_feed_link($tag_id, 'post_tag', $feed);
+}
+
+/**
+ * Retrieve edit tag link.
+ *
+ * @since 2.7.0
+ *
+ * @param int $tag_id Tag ID
+ * @param string $taxonomy Taxonomy
+ * @return string
+ */
+function get_edit_tag_link( $tag_id, $taxonomy = 'post_tag' ) {
+ return apply_filters( 'get_edit_tag_link', get_edit_term_link( $tag_id, $taxonomy ) );
+}
+
+/**
+ * Display or retrieve edit tag link with formatting.
+ *
+ * @since 2.7.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @param int|object $tag Tag object or ID
+ * @return string HTML content.
+ */
+function edit_tag_link( $link = '', $before = '', $after = '', $tag = null ) {
+ $link = edit_term_link( $link, '', '', false, $tag );
+ echo $before . apply_filters( 'edit_tag_link', $link ) . $after;
+}
+
+/**
+ * Retrieve edit term url.
+ *
+ * @since 3.1.0
+ *
+ * @param int $term_id Term ID
+ * @param string $taxonomy Taxonomy
+ * @param string $object_type The object type
+ * @return string
+ */
+function get_edit_term_link( $term_id, $taxonomy, $object_type = '' ) {
+ $tax = get_taxonomy( $taxonomy );
+ if ( !current_user_can( $tax->cap->edit_terms ) )
+ return;
+
+ $term = get_term( $term_id, $taxonomy );
+
+ $args = array(
+ 'action' => 'edit',
+ 'taxonomy' => $taxonomy,
+ 'tag_ID' => $term->term_id,
+ );
+
+ if ( $object_type )
+ $args['post_type'] = $object_type;
+
+ $location = add_query_arg( $args, admin_url( 'edit-tags.php' ) );
+
+ return apply_filters( 'get_edit_term_link', $location, $term_id, $taxonomy, $object_type );
+}
+
+/**
+ * Display or retrieve edit term link with formatting.
+ *
+ * @since 3.1.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @param object $term Term object
+ * @return string HTML content.
+ */
+function edit_term_link( $link = '', $before = '', $after = '', $term = null, $echo = true ) {
+ if ( is_null( $term ) ) {
+ $term = get_queried_object();
+ }
+
+ $tax = get_taxonomy( $term->taxonomy );
+ if ( !current_user_can($tax->cap->edit_terms) )
+ return;
+
+ if ( empty( $link ) )
+ $link = __('Edit This');
+
+ $link = '<a href="' . get_edit_term_link( $term->term_id, $term->taxonomy ) . '" title="' . $link . '">' . $link . '</a>';
+ $link = $before . apply_filters( 'edit_term_link', $link, $term->term_id ) . $after;
+
+ if ( $echo )
+ echo $link;
+ else
+ return $link;
+}
+
+/**
+* Retrieve permalink for search.
+*
+* @since 3.0.0
+* @param string $query Optional. The query string to use. If empty the current query is used.
+* @return string
+*/
+function get_search_link( $query = '' ) {
+ global $wp_rewrite;
+
+ if ( empty($query) )
+ $search = get_search_query( false );
+ else
+ $search = stripslashes($query);
+
+ $permastruct = $wp_rewrite->get_search_permastruct();
+
+ if ( empty( $permastruct ) ) {
+ $link = home_url('?s=' . urlencode($search) );
+ } else {
+ $search = urlencode($search);
+ $search = str_replace('%2F', '/', $search); // %2F(/) is not valid within a URL, send it unencoded.
+ $link = str_replace( '%search%', $search, $permastruct );
+ $link = home_url( user_trailingslashit( $link, 'search' ) );
+ }
+
+ return apply_filters( 'search_link', $link, $search );
+}
+
+/**
+ * Retrieve the permalink for the feed of the search results.
+ *
+ * @since 2.5.0
+ *
+ * @param string $search_query Optional. Search query.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_search_feed_link($search_query = '', $feed = '') {
+ global $wp_rewrite;
+ $link = get_search_link($search_query);
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ $permastruct = $wp_rewrite->get_search_permastruct();
+
+ if ( empty($permastruct) ) {
+ $link = add_query_arg('feed', $feed, $link);
+ } else {
+ $link = trailingslashit($link);
+ $link .= "feed/$feed/";
+ }
+
+ $link = apply_filters('search_feed_link', $link, $feed, 'posts');
+
+ return $link;
+}
+
+/**
+ * Retrieve the permalink for the comments feed of the search results.
+ *
+ * @since 2.5.0
+ *
+ * @param string $search_query Optional. Search query.
+ * @param string $feed Optional. Feed type.
+ * @return string
+ */
+function get_search_comments_feed_link($search_query = '', $feed = '') {
+ global $wp_rewrite;
+
+ if ( empty($feed) )
+ $feed = get_default_feed();
+
+ $link = get_search_feed_link($search_query, $feed);
+
+ $permastruct = $wp_rewrite->get_search_permastruct();
+
+ if ( empty($permastruct) )
+ $link = add_query_arg('feed', 'comments-' . $feed, $link);
+ else
+ $link = add_query_arg('withcomments', 1, $link);
+
+ $link = apply_filters('search_feed_link', $link, $feed, 'comments');
+
+ return $link;
+}
+
+/**
+ * Retrieve the permalink for a post type archive.
+ *
+ * @since 3.1.0
+ *
+ * @param string $post_type Post type
+ * @return string
+ */
+function get_post_type_archive_link( $post_type ) {
+ global $wp_rewrite;
+ if ( ! $post_type_obj = get_post_type_object( $post_type ) )
+ return false;
+
+ if ( ! $post_type_obj->has_archive )
+ return false;
+
+ if ( get_option( 'permalink_structure' ) && is_array( $post_type_obj->rewrite ) ) {
+ $struct = ( true === $post_type_obj->has_archive ) ? $post_type_obj->rewrite['slug'] : $post_type_obj->has_archive;
+ if ( $post_type_obj->rewrite['with_front'] )
+ $struct = $wp_rewrite->front . $struct;
+ else
+ $struct = $wp_rewrite->root . $struct;
+ $link = home_url( user_trailingslashit( $struct, 'post_type_archive' ) );
+ } else {
+ $link = home_url( '?post_type=' . $post_type );
+ }
+
+ return apply_filters( 'post_type_archive_link', $link, $post_type );
+}
+
+/**
+ * Retrieve the permalink for a post type archive feed.
+ *
+ * @since 3.1.0
+ *
+ * @param string $post_type Post type
+ * @param string $feed Optional. Feed type
+ * @return string
+ */
+function get_post_type_archive_feed_link( $post_type, $feed = '' ) {
+ $default_feed = get_default_feed();
+ if ( empty( $feed ) )
+ $feed = $default_feed;
+
+ if ( ! $link = get_post_type_archive_link( $post_type ) )
+ return false;
+
+ $post_type_obj = get_post_type_object( $post_type );
+ if ( get_option( 'permalink_structure' ) && is_array( $post_type_obj->rewrite ) && $post_type_obj->rewrite['feeds'] ) {
+ $link = trailingslashit( $link );
+ $link .= 'feed/';
+ if ( $feed != $default_feed )
+ $link .= "$feed/";
+ } else {
+ $link = add_query_arg( 'feed', $feed, $link );
+ }
+
+ return apply_filters( 'post_type_archive_feed_link', $link, $feed );
+}
+
+/**
+ * Retrieve edit posts link for post.
+ *
+ * Can be used within the WordPress loop or outside of it. Can be used with
+ * pages, posts, attachments, and revisions.
+ *
+ * @since 2.3.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param string $context Optional, defaults to display. How to write the '&', defaults to '&amp;'.
+ * @return string
+ */
+function get_edit_post_link( $id = 0, $context = 'display' ) {
+ if ( ! $post = get_post( $id ) )
+ return;
+
+ if ( 'revision' === $post->post_type )
+ $action = '';
+ elseif ( 'display' == $context )
+ $action = '&amp;action=edit';
+ else
+ $action = '&action=edit';
+
+ $post_type_object = get_post_type_object( $post->post_type );
+ if ( !$post_type_object )
+ return;
+
+ if ( !current_user_can( 'edit_post', $post->ID ) )
+ return;
+
+ return apply_filters( 'get_edit_post_link', admin_url( sprintf($post_type_object->_edit_link . $action, $post->ID) ), $post->ID, $context );
+}
+
+/**
+ * Display edit post link for post.
+ *
+ * @since 1.0.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @param int $id Optional. Post ID.
+ */
+function edit_post_link( $link = null, $before = '', $after = '', $id = 0 ) {
+ if ( !$post = get_post( $id ) )
+ return;
+
+ if ( !$url = get_edit_post_link( $post->ID ) )
+ return;
+
+ if ( null === $link )
+ $link = __('Edit This');
+
+ $post_type_obj = get_post_type_object( $post->post_type );
+ $link = '<a class="post-edit-link" href="' . $url . '" title="' . esc_attr( $post_type_obj->labels->edit_item ) . '">' . $link . '</a>';
+ echo $before . apply_filters( 'edit_post_link', $link, $post->ID ) . $after;
+}
+
+/**
+ * Retrieve delete posts link for post.
+ *
+ * Can be used within the WordPress loop or outside of it, with any post type.
+ *
+ * @since 2.9.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param string $deprecated Not used.
+ * @param bool $force_delete Whether to bypass trash and force deletion. Default is false.
+ * @return string
+ */
+function get_delete_post_link( $id = 0, $deprecated = '', $force_delete = false ) {
+ if ( ! empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '3.0' );
+
+ if ( !$post = get_post( $id ) )
+ return;
+
+ $post_type_object = get_post_type_object( $post->post_type );
+ if ( !$post_type_object )
+ return;
+
+ if ( !current_user_can( 'delete_post', $post->ID ) )
+ return;
+
+ $action = ( $force_delete || !EMPTY_TRASH_DAYS ) ? 'delete' : 'trash';
+
+ $delete_link = add_query_arg( 'action', $action, admin_url( sprintf( $post_type_object->_edit_link, $post->ID ) ) );
+
+ return apply_filters( 'get_delete_post_link', wp_nonce_url( $delete_link, "$action-post_{$post->ID}" ), $post->ID, $force_delete );
+}
+
+/**
+ * Retrieve edit comment link.
+ *
+ * @since 2.3.0
+ *
+ * @param int $comment_id Optional. Comment ID.
+ * @return string
+ */
+function get_edit_comment_link( $comment_id = 0 ) {
+ $comment = get_comment( $comment_id );
+
+ if ( !current_user_can( 'edit_comment', $comment->comment_ID ) )
+ return;
+
+ $location = admin_url('comment.php?action=editcomment&amp;c=') . $comment->comment_ID;
+ return apply_filters( 'get_edit_comment_link', $location );
+}
+
+/**
+ * Display or retrieve edit comment link with formatting.
+ *
+ * @since 1.0.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @return string|null HTML content, if $echo is set to false.
+ */
+function edit_comment_link( $link = null, $before = '', $after = '' ) {
+ global $comment;
+
+ if ( !current_user_can( 'edit_comment', $comment->comment_ID ) )
+ return;
+
+ if ( null === $link )
+ $link = __('Edit This');
+
+ $link = '<a class="comment-edit-link" href="' . get_edit_comment_link( $comment->comment_ID ) . '" title="' . esc_attr__( 'Edit comment' ) . '">' . $link . '</a>';
+ echo $before . apply_filters( 'edit_comment_link', $link, $comment->comment_ID ) . $after;
+}
+
+/**
+ * Display edit bookmark (literally a URL external to blog) link.
+ *
+ * @since 2.7.0
+ *
+ * @param int $link Optional. Bookmark ID.
+ * @return string
+ */
+function get_edit_bookmark_link( $link = 0 ) {
+ $link = get_bookmark( $link );
+
+ if ( !current_user_can('manage_links') )
+ return;
+
+ $location = admin_url('link.php?action=edit&amp;link_id=') . $link->link_id;
+ return apply_filters( 'get_edit_bookmark_link', $location, $link->link_id );
+}
+
+/**
+ * Display edit bookmark (literally a URL external to blog) link anchor content.
+ *
+ * @since 2.7.0
+ *
+ * @param string $link Optional. Anchor text.
+ * @param string $before Optional. Display before edit link.
+ * @param string $after Optional. Display after edit link.
+ * @param int $bookmark Optional. Bookmark ID.
+ */
+function edit_bookmark_link( $link = '', $before = '', $after = '', $bookmark = null ) {
+ $bookmark = get_bookmark($bookmark);
+
+ if ( !current_user_can('manage_links') )
+ return;
+
+ if ( empty($link) )
+ $link = __('Edit This');
+
+ $link = '<a href="' . get_edit_bookmark_link( $bookmark ) . '" title="' . esc_attr__( 'Edit Link' ) . '">' . $link . '</a>';
+ echo $before . apply_filters( 'edit_bookmark_link', $link, $bookmark->link_id ) . $after;
+}
+
+/**
+ * Retrieve edit user link
+ *
+ * @since 3.5.0
+ *
+ * @param int $user_id Optional. User ID. Defaults to the current user.
+ * @return string URL to edit user page or empty string.
+ */
+function get_edit_user_link( $user_id = null ) {
+ if ( ! $user_id )
+ $user_id = get_current_user_id();
+
+ if ( empty( $user_id ) || ! current_user_can( 'edit_user', $user_id ) )
+ return '';
+
+ $user = get_userdata( $user_id );
+
+ if ( ! $user )
+ return '';
+
+ if ( get_current_user_id() == $user->ID )
+ $link = get_edit_profile_url( $user->ID );
+ else
+ $link = add_query_arg( 'user_id', $user->ID, self_admin_url( 'user-edit.php' ) );
+
+ return apply_filters( 'get_edit_user_link', $link, $user->ID );
+}
+
+// Navigation links
+
+/**
+ * Retrieve previous post that is adjacent to current post.
+ *
+ * @since 1.5.0
+ *
+ * @param bool $in_same_cat Optional. Whether post should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ * @return mixed Post object if successful. Null if global $post is not set. Empty string if no corresponding post exists.
+ */
+function get_previous_post($in_same_cat = false, $excluded_categories = '') {
+ return get_adjacent_post($in_same_cat, $excluded_categories);
+}
+
+/**
+ * Retrieve next post that is adjacent to current post.
+ *
+ * @since 1.5.0
+ *
+ * @param bool $in_same_cat Optional. Whether post should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ * @return mixed Post object if successful. Null if global $post is not set. Empty string if no corresponding post exists.
+ */
+function get_next_post($in_same_cat = false, $excluded_categories = '') {
+ return get_adjacent_post($in_same_cat, $excluded_categories, false);
+}
+
+/**
+ * Retrieve adjacent post.
+ *
+ * Can either be next or previous post.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $in_same_cat Optional. Whether post should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ * @param bool $previous Optional. Whether to retrieve previous post.
+ * @return mixed Post object if successful. Null if global $post is not set. Empty string if no corresponding post exists.
+ */
+function get_adjacent_post( $in_same_cat = false, $excluded_categories = '', $previous = true ) {
+ global $wpdb;
+
+ if ( ! $post = get_post() )
+ return null;
+
+ $current_post_date = $post->post_date;
+
+ $join = '';
+ $posts_in_ex_cats_sql = '';
+ if ( $in_same_cat || ! empty( $excluded_categories ) ) {
+ $join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
+
+ if ( $in_same_cat ) {
+ if ( ! is_object_in_taxonomy( $post->post_type, 'category' ) )
+ return '';
+ $cat_array = wp_get_object_terms($post->ID, 'category', array('fields' => 'ids'));
+ if ( ! $cat_array || is_wp_error( $cat_array ) )
+ return '';
+ $join .= " AND tt.taxonomy = 'category' AND tt.term_id IN (" . implode(',', $cat_array) . ")";
+ }
+
+ $posts_in_ex_cats_sql = "AND tt.taxonomy = 'category'";
+ if ( ! empty( $excluded_categories ) ) {
+ if ( ! is_array( $excluded_categories ) ) {
+ // back-compat, $excluded_categories used to be IDs separated by " and "
+ if ( strpos( $excluded_categories, ' and ' ) !== false ) {
+ _deprecated_argument( __FUNCTION__, '3.3', sprintf( __( 'Use commas instead of %s to separate excluded categories.' ), "'and'" ) );
+ $excluded_categories = explode( ' and ', $excluded_categories );
+ } else {
+ $excluded_categories = explode( ',', $excluded_categories );
+ }
+ }
+
+ $excluded_categories = array_map( 'intval', $excluded_categories );
+
+ if ( ! empty( $cat_array ) ) {
+ $excluded_categories = array_diff($excluded_categories, $cat_array);
+ $posts_in_ex_cats_sql = '';
+ }
+
+ if ( !empty($excluded_categories) ) {
+ $posts_in_ex_cats_sql = " AND tt.taxonomy = 'category' AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')';
+ }
+ }
+ }
+
+ $adjacent = $previous ? 'previous' : 'next';
+ $op = $previous ? '<' : '>';
+ $order = $previous ? 'DESC' : 'ASC';
+
+ $join = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_cat, $excluded_categories );
+ $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_cats_sql", $current_post_date, $post->post_type), $in_same_cat, $excluded_categories );
+ $sort = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
+
+ $query = "SELECT p.ID FROM $wpdb->posts AS p $join $where $sort";
+ $query_key = 'adjacent_post_' . md5($query);
+ $result = wp_cache_get($query_key, 'counts');
+ if ( false !== $result ) {
+ if ( $result )
+ $result = get_post( $result );
+ return $result;
+ }
+
+ $result = $wpdb->get_var( $query );
+ if ( null === $result )
+ $result = '';
+
+ wp_cache_set($query_key, $result, 'counts');
+
+ if ( $result )
+ $result = get_post( $result );
+
+ return $result;
+}
+
+/**
+ * Get adjacent post relational link.
+ *
+ * Can either be next or previous post relational link.
+ *
+ * @since 2.8.0
+ *
+ * @param string $title Optional. Link title format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ * @param bool $previous Optional, default is true. Whether to display link to previous or next post.
+ * @return string
+ */
+function get_adjacent_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '', $previous = true) {
+ if ( $previous && is_attachment() && $post = get_post() )
+ $post = get_post( $post->post_parent );
+ else
+ $post = get_adjacent_post( $in_same_cat, $excluded_categories, $previous );
+
+ if ( empty($post) )
+ return;
+
+ $post_title = the_title_attribute( array( 'echo' => false, 'post' => $post ) );
+
+ if ( empty( $post_title ) )
+ $post_title = $previous ? __('Previous Post') : __('Next Post');
+
+ $date = mysql2date(get_option('date_format'), $post->post_date);
+
+ $title = str_replace('%title', $post_title, $title);
+ $title = str_replace('%date', $date, $title);
+
+ $link = $previous ? "<link rel='prev' title='" : "<link rel='next' title='";
+ $link .= esc_attr( $title );
+ $link .= "' href='" . get_permalink($post) . "' />\n";
+
+ $adjacent = $previous ? 'previous' : 'next';
+ return apply_filters( "{$adjacent}_post_rel_link", $link );
+}
+
+/**
+ * Display relational links for the posts adjacent to the current post.
+ *
+ * @since 2.8.0
+ *
+ * @param string $title Optional. Link title format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ */
+function adjacent_posts_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
+ echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', true);
+ echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', false);
+}
+
+/**
+ * Display relational links for the posts adjacent to the current post for single post pages.
+ *
+ * This is meant to be attached to actions like 'wp_head'. Do not call this directly in plugins or theme templates.
+ * @since 3.0.0
+ *
+ */
+function adjacent_posts_rel_link_wp_head() {
+ if ( !is_singular() || is_attachment() )
+ return;
+ adjacent_posts_rel_link();
+}
+
+/**
+ * Display relational link for the next post adjacent to the current post.
+ *
+ * @since 2.8.0
+ *
+ * @param string $title Optional. Link title format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ */
+function next_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
+ echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', false);
+}
+
+/**
+ * Display relational link for the previous post adjacent to the current post.
+ *
+ * @since 2.8.0
+ *
+ * @param string $title Optional. Link title format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ */
+function prev_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
+ echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', true);
+}
+
+/**
+ * Retrieve boundary post.
+ *
+ * Boundary being either the first or last post by publish date within the constraints specified
+ * by $in_same_cat or $excluded_categories.
+ *
+ * @since 2.8.0
+ *
+ * @param bool $in_same_cat Optional. Whether returned post should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ * @param bool $start Optional. Whether to retrieve first or last post.
+ * @return object
+ */
+function get_boundary_post( $in_same_cat = false, $excluded_categories = '', $start = true ) {
+ $post = get_post();
+ if ( ! $post || ! is_single() || is_attachment() )
+ return null;
+
+ $cat_array = array();
+ if( ! is_array( $excluded_categories ) )
+ $excluded_categories = explode( ',', $excluded_categories );
+
+ if ( $in_same_cat || ! empty( $excluded_categories ) ) {
+ if ( $in_same_cat )
+ $cat_array = wp_get_object_terms( $post->ID, 'category', array( 'fields' => 'ids' ) );
+
+ if ( ! empty( $excluded_categories ) ) {
+ $excluded_categories = array_map( 'intval', $excluded_categories );
+ $excluded_categories = array_diff( $excluded_categories, $cat_array );
+
+ $inverse_cats = array();
+ foreach ( $excluded_categories as $excluded_category )
+ $inverse_cats[] = $excluded_category * -1;
+ $excluded_categories = $inverse_cats;
+ }
+ }
+
+ $categories = implode( ',', array_merge( $cat_array, $excluded_categories ) );
+
+ $order = $start ? 'ASC' : 'DESC';
+
+ return get_posts( array('numberposts' => 1, 'category' => $categories, 'order' => $order, 'update_post_term_cache' => false, 'update_post_meta_cache' => false) );
+}
+
+/**
+ * Display previous post link that is adjacent to the current post.
+ *
+ * @since 1.5.0
+ *
+ * @param string $format Optional. Link anchor format.
+ * @param string $link Optional. Link permalink format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ */
+function previous_post_link($format='&laquo; %link', $link='%title', $in_same_cat = false, $excluded_categories = '') {
+ adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, true);
+}
+
+/**
+ * Display next post link that is adjacent to the current post.
+ *
+ * @since 1.5.0
+ *
+ * @param string $format Optional. Link anchor format.
+ * @param string $link Optional. Link permalink format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ */
+function next_post_link($format='%link &raquo;', $link='%title', $in_same_cat = false, $excluded_categories = '') {
+ adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, false);
+}
+
+/**
+ * Display adjacent post link.
+ *
+ * Can be either next post link or previous.
+ *
+ * @since 2.5.0
+ *
+ * @param string $format Link anchor format.
+ * @param string $link Link permalink format.
+ * @param bool $in_same_cat Optional. Whether link should be in a same category.
+ * @param array|string $excluded_categories Optional. Array or comma-separated list of excluded category IDs.
+ * @param bool $previous Optional, default is true. Whether to display link to previous or next post.
+ */
+function adjacent_post_link( $format, $link, $in_same_cat = false, $excluded_categories = '', $previous = true ) {
+ if ( $previous && is_attachment() )
+ $post = get_post( get_post()->post_parent );
+ else
+ $post = get_adjacent_post( $in_same_cat, $excluded_categories, $previous );
+
+ if ( ! $post ) {
+ $output = '';
+ } else {
+ $title = $post->post_title;
+
+ if ( empty( $post->post_title ) )
+ $title = $previous ? __( 'Previous Post' ) : __( 'Next Post' );
+
+ $title = apply_filters( 'the_title', $title, $post->ID );
+ $date = mysql2date( get_option( 'date_format' ), $post->post_date );
+ $rel = $previous ? 'prev' : 'next';
+
+ $string = '<a href="' . get_permalink( $post ) . '" rel="'.$rel.'">';
+ $inlink = str_replace( '%title', $title, $link );
+ $inlink = str_replace( '%date', $date, $inlink );
+ $inlink = $string . $inlink . '</a>';
+
+ $output = str_replace( '%link', $inlink, $format );
+ }
+
+ $adjacent = $previous ? 'previous' : 'next';
+
+ echo apply_filters( "{$adjacent}_post_link", $output, $format, $link, $post );
+}
+
+/**
+ * Retrieve links for page numbers.
+ *
+ * @since 1.5.0
+ *
+ * @param int $pagenum Optional. Page ID.
+ * @param bool $escape Optional. Whether to escape the URL for display, with esc_url(). Defaults to true.
+* Otherwise, prepares the URL with esc_url_raw().
+ * @return string
+ */
+function get_pagenum_link($pagenum = 1, $escape = true ) {
+ global $wp_rewrite;
+
+ $pagenum = (int) $pagenum;
+
+ $request = remove_query_arg( 'paged' );
+
+ $home_root = parse_url(home_url());
+ $home_root = ( isset($home_root['path']) ) ? $home_root['path'] : '';
+ $home_root = preg_quote( $home_root, '|' );
+
+ $request = preg_replace('|^'. $home_root . '|i', '', $request);
+ $request = preg_replace('|^/+|', '', $request);
+
+ if ( !$wp_rewrite->using_permalinks() || is_admin() ) {
+ $base = trailingslashit( get_bloginfo( 'url' ) );
+
+ if ( $pagenum > 1 ) {
+ $result = add_query_arg( 'paged', $pagenum, $base . $request );
+ } else {
+ $result = $base . $request;
+ }
+ } else {
+ $qs_regex = '|\?.*?$|';
+ preg_match( $qs_regex, $request, $qs_match );
+
+ if ( !empty( $qs_match[0] ) ) {
+ $query_string = $qs_match[0];
+ $request = preg_replace( $qs_regex, '', $request );
+ } else {
+ $query_string = '';
+ }
+
+ $request = preg_replace( "|$wp_rewrite->pagination_base/\d+/?$|", '', $request);
+ $request = preg_replace( '|^' . preg_quote( $wp_rewrite->index, '|' ) . '|i', '', $request);
+ $request = ltrim($request, '/');
+
+ $base = trailingslashit( get_bloginfo( 'url' ) );
+
+ if ( $wp_rewrite->using_index_permalinks() && ( $pagenum > 1 || '' != $request ) )
+ $base .= $wp_rewrite->index . '/';
+
+ if ( $pagenum > 1 ) {
+ $request = ( ( !empty( $request ) ) ? trailingslashit( $request ) : $request ) . user_trailingslashit( $wp_rewrite->pagination_base . "/" . $pagenum, 'paged' );
+ }
+
+ $result = $base . $request . $query_string;
+ }
+
+ $result = apply_filters('get_pagenum_link', $result);
+
+ if ( $escape )
+ return esc_url( $result );
+ else
+ return esc_url_raw( $result );
+}
+
+/**
+ * Retrieve next posts page link.
+ *
+ * Backported from 2.1.3 to 2.0.10.
+ *
+ * @since 2.0.10
+ *
+ * @param int $max_page Optional. Max pages.
+ * @return string
+ */
+function get_next_posts_page_link($max_page = 0) {
+ global $paged;
+
+ if ( !is_single() ) {
+ if ( !$paged )
+ $paged = 1;
+ $nextpage = intval($paged) + 1;
+ if ( !$max_page || $max_page >= $nextpage )
+ return get_pagenum_link($nextpage);
+ }
+}
+
+/**
+ * Display or return the next posts page link.
+ *
+ * @since 0.71
+ *
+ * @param int $max_page Optional. Max pages.
+ * @param boolean $echo Optional. Echo or return;
+ */
+function next_posts( $max_page = 0, $echo = true ) {
+ $output = esc_url( get_next_posts_page_link( $max_page ) );
+
+ if ( $echo )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Return the next posts page link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Content for link text.
+ * @param int $max_page Optional. Max pages.
+ * @return string|null
+ */
+function get_next_posts_link( $label = null, $max_page = 0 ) {
+ global $paged, $wp_query;
+
+ if ( !$max_page )
+ $max_page = $wp_query->max_num_pages;
+
+ if ( !$paged )
+ $paged = 1;
+
+ $nextpage = intval($paged) + 1;
+
+ if ( null === $label )
+ $label = __( 'Next Page &raquo;' );
+
+ if ( !is_single() && ( $nextpage <= $max_page ) ) {
+ $attr = apply_filters( 'next_posts_link_attributes', '' );
+ return '<a href="' . next_posts( $max_page, false ) . "\" $attr>" . preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $label) . '</a>';
+ }
+}
+
+/**
+ * Display the next posts page link.
+ *
+ * @since 0.71
+ * @uses get_next_posts_link()
+ *
+ * @param string $label Content for link text.
+ * @param int $max_page Optional. Max pages.
+ */
+function next_posts_link( $label = null, $max_page = 0 ) {
+ echo get_next_posts_link( $label, $max_page );
+}
+
+/**
+ * Retrieve previous posts page link.
+ *
+ * Will only return string, if not on a single page or post.
+ *
+ * Backported to 2.0.10 from 2.1.3.
+ *
+ * @since 2.0.10
+ *
+ * @return string|null
+ */
+function get_previous_posts_page_link() {
+ global $paged;
+
+ if ( !is_single() ) {
+ $nextpage = intval($paged) - 1;
+ if ( $nextpage < 1 )
+ $nextpage = 1;
+ return get_pagenum_link($nextpage);
+ }
+}
+
+/**
+ * Display or return the previous posts page link.
+ *
+ * @since 0.71
+ *
+ * @param boolean $echo Optional. Echo or return;
+ */
+function previous_posts( $echo = true ) {
+ $output = esc_url( get_previous_posts_page_link() );
+
+ if ( $echo )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Return the previous posts page link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Optional. Previous page link text.
+ * @return string|null
+ */
+function get_previous_posts_link( $label = null ) {
+ global $paged;
+
+ if ( null === $label )
+ $label = __( '&laquo; Previous Page' );
+
+ if ( !is_single() && $paged > 1 ) {
+ $attr = apply_filters( 'previous_posts_link_attributes', '' );
+ return '<a href="' . previous_posts( false ) . "\" $attr>". preg_replace( '/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $label ) .'</a>';
+ }
+}
+
+/**
+ * Display the previous posts page link.
+ *
+ * @since 0.71
+ * @uses get_previous_posts_link()
+ *
+ * @param string $label Optional. Previous page link text.
+ */
+function previous_posts_link( $label = null ) {
+ echo get_previous_posts_link( $label );
+}
+
+/**
+ * Return post pages link navigation for previous and next pages.
+ *
+ * @since 2.8
+ *
+ * @param string|array $args Optional args.
+ * @return string The posts link navigation.
+ */
+function get_posts_nav_link( $args = array() ) {
+ global $wp_query;
+
+ $return = '';
+
+ if ( !is_singular() ) {
+ $defaults = array(
+ 'sep' => ' &#8212; ',
+ 'prelabel' => __('&laquo; Previous Page'),
+ 'nxtlabel' => __('Next Page &raquo;'),
+ );
+ $args = wp_parse_args( $args, $defaults );
+
+ $max_num_pages = $wp_query->max_num_pages;
+ $paged = get_query_var('paged');
+
+ //only have sep if there's both prev and next results
+ if ($paged < 2 || $paged >= $max_num_pages) {
+ $args['sep'] = '';
+ }
+
+ if ( $max_num_pages > 1 ) {
+ $return = get_previous_posts_link($args['prelabel']);
+ $return .= preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $args['sep']);
+ $return .= get_next_posts_link($args['nxtlabel']);
+ }
+ }
+ return $return;
+
+}
+
+/**
+ * Display post pages link navigation for previous and next pages.
+ *
+ * @since 0.71
+ *
+ * @param string $sep Optional. Separator for posts navigation links.
+ * @param string $prelabel Optional. Label for previous pages.
+ * @param string $nxtlabel Optional Label for next pages.
+ */
+function posts_nav_link( $sep = '', $prelabel = '', $nxtlabel = '' ) {
+ $args = array_filter( compact('sep', 'prelabel', 'nxtlabel') );
+ echo get_posts_nav_link($args);
+}
+
+/**
+ * Retrieve comments page number link.
+ *
+ * @since 2.7.0
+ *
+ * @param int $pagenum Optional. Page number.
+ * @return string
+ */
+function get_comments_pagenum_link( $pagenum = 1, $max_page = 0 ) {
+ global $wp_rewrite;
+
+ $pagenum = (int) $pagenum;
+
+ $result = get_permalink();
+
+ if ( 'newest' == get_option('default_comments_page') ) {
+ if ( $pagenum != $max_page ) {
+ if ( $wp_rewrite->using_permalinks() )
+ $result = user_trailingslashit( trailingslashit($result) . 'comment-page-' . $pagenum, 'commentpaged');
+ else
+ $result = add_query_arg( 'cpage', $pagenum, $result );
+ }
+ } elseif ( $pagenum > 1 ) {
+ if ( $wp_rewrite->using_permalinks() )
+ $result = user_trailingslashit( trailingslashit($result) . 'comment-page-' . $pagenum, 'commentpaged');
+ else
+ $result = add_query_arg( 'cpage', $pagenum, $result );
+ }
+
+ $result .= '#comments';
+
+ $result = apply_filters('get_comments_pagenum_link', $result);
+
+ return $result;
+}
+
+/**
+ * Return the link to next comments page.
+ *
+ * @since 2.7.1
+ *
+ * @param string $label Optional. Label for link text.
+ * @param int $max_page Optional. Max page.
+ * @return string|null
+ */
+function get_next_comments_link( $label = '', $max_page = 0 ) {
+ global $wp_query;
+
+ if ( !is_singular() || !get_option('page_comments') )
+ return;
+
+ $page = get_query_var('cpage');
+
+ $nextpage = intval($page) + 1;
+
+ if ( empty($max_page) )
+ $max_page = $wp_query->max_num_comment_pages;
+
+ if ( empty($max_page) )
+ $max_page = get_comment_pages_count();
+
+ if ( $nextpage > $max_page )
+ return;
+
+ if ( empty($label) )
+ $label = __('Newer Comments &raquo;');
+
+ return '<a href="' . esc_url( get_comments_pagenum_link( $nextpage, $max_page ) ) . '" ' . apply_filters( 'next_comments_link_attributes', '' ) . '>'. preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $label) .'</a>';
+}
+
+/**
+ * Display the link to next comments page.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Optional. Label for link text.
+ * @param int $max_page Optional. Max page.
+ */
+function next_comments_link( $label = '', $max_page = 0 ) {
+ echo get_next_comments_link( $label, $max_page );
+}
+
+/**
+ * Return the previous comments page link.
+ *
+ * @since 2.7.1
+ *
+ * @param string $label Optional. Label for comments link text.
+ * @return string|null
+ */
+function get_previous_comments_link( $label = '' ) {
+ if ( !is_singular() || !get_option('page_comments') )
+ return;
+
+ $page = get_query_var('cpage');
+
+ if ( intval($page) <= 1 )
+ return;
+
+ $prevpage = intval($page) - 1;
+
+ if ( empty($label) )
+ $label = __('&laquo; Older Comments');
+
+ return '<a href="' . esc_url( get_comments_pagenum_link( $prevpage ) ) . '" ' . apply_filters( 'previous_comments_link_attributes', '' ) . '>' . preg_replace('/&([^#])(?![a-z]{1,8};)/i', '&#038;$1', $label) .'</a>';
+}
+
+/**
+ * Display the previous comments page link.
+ *
+ * @since 2.7.0
+ *
+ * @param string $label Optional. Label for comments link text.
+ */
+function previous_comments_link( $label = '' ) {
+ echo get_previous_comments_link( $label );
+}
+
+/**
+ * Create pagination links for the comments on the current post.
+ *
+ * @see paginate_links()
+ * @since 2.7.0
+ *
+ * @param string|array $args Optional args. See paginate_links().
+ * @return string Markup for pagination links.
+*/
+function paginate_comments_links($args = array()) {
+ global $wp_rewrite;
+
+ if ( !is_singular() || !get_option('page_comments') )
+ return;
+
+ $page = get_query_var('cpage');
+ if ( !$page )
+ $page = 1;
+ $max_page = get_comment_pages_count();
+ $defaults = array(
+ 'base' => add_query_arg( 'cpage', '%#%' ),
+ 'format' => '',
+ 'total' => $max_page,
+ 'current' => $page,
+ 'echo' => true,
+ 'add_fragment' => '#comments'
+ );
+ if ( $wp_rewrite->using_permalinks() )
+ $defaults['base'] = user_trailingslashit(trailingslashit(get_permalink()) . 'comment-page-%#%', 'commentpaged');
+
+ $args = wp_parse_args( $args, $defaults );
+ $page_links = paginate_links( $args );
+
+ if ( $args['echo'] )
+ echo $page_links;
+ else
+ return $page_links;
+}
+
+/**
+ * Retrieve the Press This bookmarklet link.
+ *
+ * Use this in 'a' element 'href' attribute.
+ *
+ * @since 2.6.0
+ *
+ * @return string
+ */
+function get_shortcut_link() {
+ // In case of breaking changes, version this. #WP20071
+ $link = "javascript:
+ var d=document,
+ w=window,
+ e=w.getSelection,
+ k=d.getSelection,
+ x=d.selection,
+ s=(e?e():(k)?k():(x?x.createRange().text:0)),
+ f='" . admin_url('press-this.php') . "',
+ l=d.location,
+ e=encodeURIComponent,
+ u=f+'?u='+e(l.href)+'&t='+e(d.title)+'&s='+e(s)+'&v=4';
+ a=function(){if(!w.open(u,'t','toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570'))l.href=u;};
+ if (/Firefox/.test(navigator.userAgent)) setTimeout(a, 0); else a();
+ void(0)";
+
+ $link = str_replace(array("\r", "\n", "\t"), '', $link);
+
+ return apply_filters('shortcut_link', $link);
+}
+
+/**
+ * Retrieve the home url for the current site.
+ *
+ * Returns the 'home' option with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @uses get_home_url()
+ *
+ * @param string $path (optional) Path relative to the home url.
+ * @param string $scheme (optional) Scheme to give the home url context. Currently 'http', 'https', or 'relative'.
+ * @return string Home url link with optional path appended.
+*/
+function home_url( $path = '', $scheme = null ) {
+ return get_home_url( null, $path, $scheme );
+}
+
+/**
+ * Retrieve the home url for a given site.
+ *
+ * Returns the 'home' option with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param int $blog_id (optional) Blog ID. Defaults to current blog.
+ * @param string $path (optional) Path relative to the home url.
+ * @param string $scheme (optional) Scheme to give the home url context. Currently 'http', 'https', or 'relative'.
+ * @return string Home url link with optional path appended.
+*/
+function get_home_url( $blog_id = null, $path = '', $scheme = null ) {
+ $orig_scheme = $scheme;
+
+ if ( empty( $blog_id ) || !is_multisite() ) {
+ $url = get_option( 'home' );
+ } else {
+ switch_to_blog( $blog_id );
+ $url = get_option( 'home' );
+ restore_current_blog();
+ }
+
+ if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ) ) ) {
+ if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $GLOBALS['pagenow'] )
+ $scheme = 'https';
+ else
+ $scheme = parse_url( $url, PHP_URL_SCHEME );
+ }
+
+ $url = set_url_scheme( $url, $scheme );
+
+ if ( $path && is_string( $path ) )
+ $url .= '/' . ltrim( $path, '/' );
+
+ return apply_filters( 'home_url', $url, $path, $orig_scheme, $blog_id );
+}
+
+/**
+ * Retrieve the site url for the current site.
+ *
+ * Returns the 'site_url' option with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @uses get_site_url()
+ *
+ * @param string $path Optional. Path relative to the site url.
+ * @param string $scheme Optional. Scheme to give the site url context. See set_url_scheme().
+ * @return string Site url link with optional path appended.
+*/
+function site_url( $path = '', $scheme = null ) {
+ return get_site_url( null, $path, $scheme );
+}
+
+/**
+ * Retrieve the site url for a given site.
+ *
+ * Returns the 'site_url' option with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param int $blog_id (optional) Blog ID. Defaults to current blog.
+ * @param string $path Optional. Path relative to the site url.
+ * @param string $scheme Optional. Scheme to give the site url context. Currently 'http', 'https', 'login', 'login_post', 'admin', or 'relative'.
+ * @return string Site url link with optional path appended.
+*/
+function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
+ if ( empty( $blog_id ) || !is_multisite() ) {
+ $url = get_option( 'siteurl' );
+ } else {
+ switch_to_blog( $blog_id );
+ $url = get_option( 'siteurl' );
+ restore_current_blog();
+ }
+
+ $url = set_url_scheme( $url, $scheme );
+
+ if ( $path && is_string( $path ) )
+ $url .= '/' . ltrim( $path, '/' );
+
+ return apply_filters( 'site_url', $url, $path, $scheme, $blog_id );
+}
+
+/**
+ * Retrieve the url to the admin area for the current site.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional path relative to the admin url.
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Admin url link with optional path appended.
+*/
+function admin_url( $path = '', $scheme = 'admin' ) {
+ return get_admin_url( null, $path, $scheme );
+}
+
+/**
+ * Retrieve the url to the admin area for a given site.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param int $blog_id (optional) Blog ID. Defaults to current blog.
+ * @param string $path Optional path relative to the admin url.
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Admin url link with optional path appended.
+*/
+function get_admin_url( $blog_id = null, $path = '', $scheme = 'admin' ) {
+ $url = get_site_url($blog_id, 'wp-admin/', $scheme);
+
+ if ( $path && is_string( $path ) )
+ $url .= ltrim( $path, '/' );
+
+ return apply_filters( 'admin_url', $url, $path, $blog_id );
+}
+
+/**
+ * Retrieve the url to the includes directory.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the includes url.
+ * @param string $scheme Optional. Scheme to give the includes url context.
+ * @return string Includes url link with optional path appended.
+*/
+function includes_url( $path = '', $scheme = null ) {
+ $url = site_url( '/' . WPINC . '/', $scheme );
+
+ if ( $path && is_string( $path ) )
+ $url .= ltrim($path, '/');
+
+ return apply_filters('includes_url', $url, $path);
+}
+
+/**
+ * Retrieve the url to the content directory.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the content url.
+ * @return string Content url link with optional path appended.
+*/
+function content_url($path = '') {
+ $url = set_url_scheme( WP_CONTENT_URL );
+
+ if ( $path && is_string( $path ) )
+ $url .= '/' . ltrim($path, '/');
+
+ return apply_filters('content_url', $url, $path);
+}
+
+/**
+ * Retrieve the url to the plugins directory or to a specific file within that directory.
+ * You can hardcode the plugin slug in $path or pass __FILE__ as a second argument to get the correct folder name.
+ *
+ * @package WordPress
+ * @since 2.6.0
+ *
+ * @param string $path Optional. Path relative to the plugins url.
+ * @param string $plugin Optional. The plugin file that you want to be relative to - i.e. pass in __FILE__
+ * @return string Plugins url link with optional path appended.
+*/
+function plugins_url($path = '', $plugin = '') {
+
+ $mu_plugin_dir = WPMU_PLUGIN_DIR;
+ foreach ( array('path', 'plugin', 'mu_plugin_dir') as $var ) {
+ $$var = str_replace('\\' ,'/', $$var); // sanitize for Win32 installs
+ $$var = preg_replace('|/+|', '/', $$var);
+ }
+
+ if ( !empty($plugin) && 0 === strpos($plugin, $mu_plugin_dir) )
+ $url = WPMU_PLUGIN_URL;
+ else
+ $url = WP_PLUGIN_URL;
+
+
+ $url = set_url_scheme( $url );
+
+ if ( !empty($plugin) && is_string($plugin) ) {
+ $folder = dirname(plugin_basename($plugin));
+ if ( '.' != $folder )
+ $url .= '/' . ltrim($folder, '/');
+ }
+
+ if ( $path && is_string( $path ) )
+ $url .= '/' . ltrim($path, '/');
+
+ return apply_filters('plugins_url', $url, $path, $plugin);
+}
+
+/**
+ * Retrieve the site url for the current network.
+ *
+ * Returns the site url with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param string $path Optional. Path relative to the site url.
+ * @param string $scheme Optional. Scheme to give the site url context. See set_url_scheme().
+ * @return string Site url link with optional path appended.
+*/
+function network_site_url( $path = '', $scheme = null ) {
+ global $current_site;
+
+ if ( ! is_multisite() )
+ return site_url($path, $scheme);
+
+ if ( 'relative' == $scheme )
+ $url = $current_site->path;
+ else
+ $url = set_url_scheme( 'http://' . $current_site->domain . $current_site->path, $scheme );
+
+ if ( $path && is_string( $path ) )
+ $url .= ltrim( $path, '/' );
+
+ return apply_filters( 'network_site_url', $url, $path, $scheme );
+}
+
+/**
+ * Retrieve the home url for the current network.
+ *
+ * Returns the home url with the appropriate protocol, 'https' if
+ * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
+ * overridden.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param string $path (optional) Path relative to the home url.
+ * @param string $scheme (optional) Scheme to give the home url context. Currently 'http', 'https', or 'relative'.
+ * @return string Home url link with optional path appended.
+*/
+function network_home_url( $path = '', $scheme = null ) {
+ global $current_site;
+
+ if ( ! is_multisite() )
+ return home_url($path, $scheme);
+
+ $orig_scheme = $scheme;
+
+ if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ) ) )
+ $scheme = is_ssl() && ! is_admin() ? 'https' : 'http';
+
+ if ( 'relative' == $scheme )
+ $url = $current_site->path;
+ else
+ $url = set_url_scheme( 'http://' . $current_site->domain . $current_site->path, $scheme );
+
+ if ( $path && is_string( $path ) )
+ $url .= ltrim( $path, '/' );
+
+ return apply_filters( 'network_home_url', $url, $path, $orig_scheme);
+}
+
+/**
+ * Retrieve the url to the admin area for the network.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param string $path Optional path relative to the admin url.
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Admin url link with optional path appended.
+*/
+function network_admin_url( $path = '', $scheme = 'admin' ) {
+ if ( ! is_multisite() )
+ return admin_url( $path, $scheme );
+
+ $url = network_site_url('wp-admin/network/', $scheme);
+
+ if ( $path && is_string( $path ) )
+ $url .= ltrim($path, '/');
+
+ return apply_filters('network_admin_url', $url, $path);
+}
+
+/**
+ * Retrieve the url to the admin area for the current user.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ *
+ * @param string $path Optional path relative to the admin url.
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Admin url link with optional path appended.
+*/
+function user_admin_url( $path = '', $scheme = 'admin' ) {
+ $url = network_site_url('wp-admin/user/', $scheme);
+
+ if ( $path && is_string( $path ) )
+ $url .= ltrim($path, '/');
+
+ return apply_filters('user_admin_url', $url, $path);
+}
+
+/**
+ * Retrieve the url to the admin area for either the current blog or the network depending on context.
+ *
+ * @package WordPress
+ * @since 3.1.0
+ *
+ * @param string $path Optional path relative to the admin url.
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Admin url link with optional path appended.
+*/
+function self_admin_url($path = '', $scheme = 'admin') {
+ if ( is_network_admin() )
+ return network_admin_url($path, $scheme);
+ elseif ( is_user_admin() )
+ return user_admin_url($path, $scheme);
+ else
+ return admin_url($path, $scheme);
+}
+
+/**
+ * Set the scheme for a URL
+ *
+ * @since 3.4.0
+ *
+ * @param string $url Absolute url that includes a scheme
+ * @param string $scheme Optional. Scheme to give $url. Currently 'http', 'https', 'login', 'login_post', 'admin', or 'relative'.
+ * @return string $url URL with chosen scheme.
+ */
+function set_url_scheme( $url, $scheme = null ) {
+ $orig_scheme = $scheme;
+ if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ) ) ) {
+ if ( ( 'login_post' == $scheme || 'rpc' == $scheme ) && ( force_ssl_login() || force_ssl_admin() ) )
+ $scheme = 'https';
+ elseif ( ( 'login' == $scheme ) && force_ssl_admin() )
+ $scheme = 'https';
+ elseif ( ( 'admin' == $scheme ) && force_ssl_admin() )
+ $scheme = 'https';
+ else
+ $scheme = ( is_ssl() ? 'https' : 'http' );
+ }
+
+ if ( 'relative' == $scheme )
+ $url = preg_replace( '#^.+://[^/]*#', '', $url );
+ else
+ $url = preg_replace( '#^.+://#', $scheme . '://', $url );
+
+ return apply_filters( 'set_url_scheme', $url, $scheme, $orig_scheme );
+}
+
+/**
+ * Get the URL to the user's dashboard.
+ *
+ * If a user does not belong to any site, the global user dashboard is used. If the user belongs to the current site,
+ * the dashboard for the current site is returned. If the user cannot edit the current site, the dashboard to the user's
+ * primary blog is returned.
+ *
+ * @since 3.1.0
+ *
+ * @param int $user_id User ID
+ * @param string $path Optional path relative to the dashboard. Use only paths known to both blog and user admins.
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Dashboard url link with optional path appended.
+ */
+function get_dashboard_url( $user_id, $path = '', $scheme = 'admin' ) {
+ $user_id = (int) $user_id;
+
+ $blogs = get_blogs_of_user( $user_id );
+ if ( ! is_super_admin() && empty($blogs) ) {
+ $url = user_admin_url( $path, $scheme );
+ } elseif ( ! is_multisite() ) {
+ $url = admin_url( $path, $scheme );
+ } else {
+ $current_blog = get_current_blog_id();
+ if ( $current_blog && ( is_super_admin( $user_id ) || in_array( $current_blog, array_keys( $blogs ) ) ) ) {
+ $url = admin_url( $path, $scheme );
+ } else {
+ $active = get_active_blog_for_user( $user_id );
+ if ( $active )
+ $url = get_admin_url( $active->blog_id, $path, $scheme );
+ else
+ $url = user_admin_url( $path, $scheme );
+ }
+ }
+
+ return apply_filters( 'user_dashboard_url', $url, $user_id, $path, $scheme);
+}
+
+/**
+ * Get the URL to the user's profile editor.
+ *
+ * @since 3.1.0
+ *
+ * @param int $user User ID
+ * @param string $scheme The scheme to use. Default is 'admin', which obeys force_ssl_admin() and is_ssl(). 'http' or 'https' can be passed to force those schemes.
+ * @return string Dashboard url link with optional path appended.
+ */
+function get_edit_profile_url( $user, $scheme = 'admin' ) {
+ $user = (int) $user;
+
+ if ( is_user_admin() )
+ $url = user_admin_url( 'profile.php', $scheme );
+ elseif ( is_network_admin() )
+ $url = network_admin_url( 'profile.php', $scheme );
+ else
+ $url = get_dashboard_url( $user, 'profile.php', $scheme );
+
+ return apply_filters( 'edit_profile_url', $url, $user, $scheme);
+}
+
+/**
+ * Output rel=canonical for singular queries.
+ *
+ * @package WordPress
+ * @since 2.9.0
+*/
+function rel_canonical() {
+ if ( !is_singular() )
+ return;
+
+ global $wp_the_query;
+ if ( !$id = $wp_the_query->get_queried_object_id() )
+ return;
+
+ $link = get_permalink( $id );
+
+ if ( $page = get_query_var('cpage') )
+ $link = get_comments_pagenum_link( $page );
+
+ echo "<link rel='canonical' href='$link' />\n";
+}
+
+/**
+ * Return a shortlink for a post, page, attachment, or blog.
+ *
+ * This function exists to provide a shortlink tag that all themes and plugins can target. A plugin must hook in to
+ * provide the actual shortlinks. Default shortlink support is limited to providing ?p= style links for posts.
+ * Plugins can short-circuit this function via the pre_get_shortlink filter or filter the output
+ * via the get_shortlink filter.
+ *
+ * @since 3.0.0.
+ *
+ * @param int $id A post or blog id. Default is 0, which means the current post or blog.
+ * @param string $context Whether the id is a 'blog' id, 'post' id, or 'media' id. If 'post', the post_type of the post is consulted. If 'query', the current query is consulted to determine the id and context. Default is 'post'.
+ * @param bool $allow_slugs Whether to allow post slugs in the shortlink. It is up to the plugin how and whether to honor this.
+ * @return string A shortlink or an empty string if no shortlink exists for the requested resource or if shortlinks are not enabled.
+ */
+function wp_get_shortlink($id = 0, $context = 'post', $allow_slugs = true) {
+ // Allow plugins to short-circuit this function.
+ $shortlink = apply_filters('pre_get_shortlink', false, $id, $context, $allow_slugs);
+ if ( false !== $shortlink )
+ return $shortlink;
+
+ global $wp_query;
+ $post_id = 0;
+ if ( 'query' == $context && is_single() ) {
+ $post_id = $wp_query->get_queried_object_id();
+ } elseif ( 'post' == $context ) {
+ $post = get_post($id);
+ $post_id = $post->ID;
+ }
+
+ $shortlink = '';
+
+ // Return p= link for posts.
+ if ( !empty($post_id) && '' != get_option('permalink_structure') ) {
+ $post = get_post($post_id);
+ if ( isset($post->post_type) && 'post' == $post->post_type )
+ $shortlink = home_url('?p=' . $post->ID);
+ }
+
+ return apply_filters('get_shortlink', $shortlink, $id, $context, $allow_slugs);
+}
+
+/**
+ * Inject rel=shortlink into head if a shortlink is defined for the current page.
+ *
+ * Attached to the wp_head action.
+ *
+ * @since 3.0.0
+ *
+ * @uses wp_get_shortlink()
+ */
+function wp_shortlink_wp_head() {
+ $shortlink = wp_get_shortlink( 0, 'query' );
+
+ if ( empty( $shortlink ) )
+ return;
+
+ echo "<link rel='shortlink' href='" . esc_url( $shortlink ) . "' />\n";
+}
+
+/**
+ * Send a Link: rel=shortlink header if a shortlink is defined for the current page.
+ *
+ * Attached to the wp action.
+ *
+ * @since 3.0.0
+ *
+ * @uses wp_get_shortlink()
+ */
+function wp_shortlink_header() {
+ if ( headers_sent() )
+ return;
+
+ $shortlink = wp_get_shortlink(0, 'query');
+
+ if ( empty($shortlink) )
+ return;
+
+ header('Link: <' . $shortlink . '>; rel=shortlink', false);
+}
+
+/**
+ * Display the Short Link for a Post
+ *
+ * Must be called from inside "The Loop"
+ *
+ * Call like the_shortlink(__('Shortlinkage FTW'))
+ *
+ * @since 3.0.0
+ *
+ * @param string $text Optional The link text or HTML to be displayed. Defaults to 'This is the short link.'
+ * @param string $title Optional The tooltip for the link. Must be sanitized. Defaults to the sanitized post title.
+ * @param string $before Optional HTML to display before the link.
+ * @param string $after Optional HTML to display after the link.
+ */
+function the_shortlink( $text = '', $title = '', $before = '', $after = '' ) {
+ $post = get_post();
+
+ if ( empty( $text ) )
+ $text = __('This is the short link.');
+
+ if ( empty( $title ) )
+ $title = the_title_attribute( array( 'echo' => false ) );
+
+ $shortlink = wp_get_shortlink( $post->ID );
+
+ if ( !empty( $shortlink ) ) {
+ $link = '<a rel="shortlink" href="' . esc_url( $shortlink ) . '" title="' . $title . '">' . $text . '</a>';
+ $link = apply_filters( 'the_shortlink', $link, $shortlink, $text, $title );
+ echo $before, $link, $after;
+ }
+}
diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php
new file mode 100644
index 0000000000..e1eb15e4bb
--- /dev/null
+++ b/src/wp-includes/load.php
@@ -0,0 +1,760 @@
+<?php
+/**
+ * These functions are needed to load WordPress.
+ *
+ * @internal This file must be parsable by PHP4.
+ *
+ * @package WordPress
+ */
+
+/**
+ * Turn register globals off.
+ *
+ * @access private
+ * @since 2.1.0
+ * @return null Will return null if register_globals PHP directive was disabled
+ */
+function wp_unregister_GLOBALS() {
+ if ( !ini_get( 'register_globals' ) )
+ return;
+
+ if ( isset( $_REQUEST['GLOBALS'] ) )
+ die( 'GLOBALS overwrite attempt detected' );
+
+ // Variables that shouldn't be unset
+ $no_unset = array( 'GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES', 'table_prefix' );
+
+ $input = array_merge( $_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset( $_SESSION ) && is_array( $_SESSION ) ? $_SESSION : array() );
+ foreach ( $input as $k => $v )
+ if ( !in_array( $k, $no_unset ) && isset( $GLOBALS[$k] ) ) {
+ unset( $GLOBALS[$k] );
+ }
+}
+
+/**
+ * Fix $_SERVER variables for various setups.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_fix_server_vars() {
+ global $PHP_SELF;
+
+ $default_server_values = array(
+ 'SERVER_SOFTWARE' => '',
+ 'REQUEST_URI' => '',
+ );
+
+ $_SERVER = array_merge( $default_server_values, $_SERVER );
+
+ // Fix for IIS when running with PHP ISAPI
+ if ( empty( $_SERVER['REQUEST_URI'] ) || ( php_sapi_name() != 'cgi-fcgi' && preg_match( '/^Microsoft-IIS\//', $_SERVER['SERVER_SOFTWARE'] ) ) ) {
+
+ // IIS Mod-Rewrite
+ if ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] ) ) {
+ $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_ORIGINAL_URL'];
+ }
+ // IIS Isapi_Rewrite
+ else if ( isset( $_SERVER['HTTP_X_REWRITE_URL'] ) ) {
+ $_SERVER['REQUEST_URI'] = $_SERVER['HTTP_X_REWRITE_URL'];
+ } else {
+ // Use ORIG_PATH_INFO if there is no PATH_INFO
+ if ( !isset( $_SERVER['PATH_INFO'] ) && isset( $_SERVER['ORIG_PATH_INFO'] ) )
+ $_SERVER['PATH_INFO'] = $_SERVER['ORIG_PATH_INFO'];
+
+ // Some IIS + PHP configurations puts the script-name in the path-info (No need to append it twice)
+ if ( isset( $_SERVER['PATH_INFO'] ) ) {
+ if ( $_SERVER['PATH_INFO'] == $_SERVER['SCRIPT_NAME'] )
+ $_SERVER['REQUEST_URI'] = $_SERVER['PATH_INFO'];
+ else
+ $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
+ }
+
+ // Append the query string if it exists and isn't null
+ if ( ! empty( $_SERVER['QUERY_STRING'] ) ) {
+ $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
+ }
+ }
+ }
+
+ // Fix for PHP as CGI hosts that set SCRIPT_FILENAME to something ending in php.cgi for all requests
+ if ( isset( $_SERVER['SCRIPT_FILENAME'] ) && ( strpos( $_SERVER['SCRIPT_FILENAME'], 'php.cgi' ) == strlen( $_SERVER['SCRIPT_FILENAME'] ) - 7 ) )
+ $_SERVER['SCRIPT_FILENAME'] = $_SERVER['PATH_TRANSLATED'];
+
+ // Fix for Dreamhost and other PHP as CGI hosts
+ if ( strpos( $_SERVER['SCRIPT_NAME'], 'php.cgi' ) !== false )
+ unset( $_SERVER['PATH_INFO'] );
+
+ // Fix empty PHP_SELF
+ $PHP_SELF = $_SERVER['PHP_SELF'];
+ if ( empty( $PHP_SELF ) )
+ $_SERVER['PHP_SELF'] = $PHP_SELF = preg_replace( '/(\?.*)?$/', '', $_SERVER["REQUEST_URI"] );
+}
+
+/**
+ * Check for the required PHP version, and the MySQL extension or a database drop-in.
+ *
+ * Dies if requirements are not met.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_check_php_mysql_versions() {
+ global $required_php_version, $wp_version;
+ $php_version = phpversion();
+ if ( version_compare( $required_php_version, $php_version, '>' ) ) {
+ wp_load_translations_early();
+ die( sprintf( __( 'Your server is running PHP version %1$s but WordPress %2$s requires at least %3$s.' ), $php_version, $wp_version, $required_php_version ) );
+ }
+
+ if ( ! extension_loaded( 'mysql' ) && ! file_exists( WP_CONTENT_DIR . '/db.php' ) ) {
+ wp_load_translations_early();
+ die( __( 'Your PHP installation appears to be missing the MySQL extension which is required by WordPress.' ) );
+ }
+}
+
+/**
+ * Don't load all of WordPress when handling a favicon.ico request.
+ * Instead, send the headers for a zero-length favicon and bail.
+ *
+ * @since 3.0.0
+ */
+function wp_favicon_request() {
+ if ( '/favicon.ico' == $_SERVER['REQUEST_URI'] ) {
+ header('Content-Type: image/vnd.microsoft.icon');
+ header('Content-Length: 0');
+ exit;
+ }
+}
+
+/**
+ * Dies with a maintenance message when conditions are met.
+ *
+ * Checks for a file in the WordPress root directory named ".maintenance".
+ * This file will contain the variable $upgrading, set to the time the file
+ * was created. If the file was created less than 10 minutes ago, WordPress
+ * enters maintenance mode and displays a message.
+ *
+ * The default message can be replaced by using a drop-in (maintenance.php in
+ * the wp-content directory).
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_maintenance() {
+ if ( !file_exists( ABSPATH . '.maintenance' ) || defined( 'WP_INSTALLING' ) )
+ return;
+
+ global $upgrading;
+
+ include( ABSPATH . '.maintenance' );
+ // If the $upgrading timestamp is older than 10 minutes, don't die.
+ if ( ( time() - $upgrading ) >= 600 )
+ return;
+
+ if ( file_exists( WP_CONTENT_DIR . '/maintenance.php' ) ) {
+ require_once( WP_CONTENT_DIR . '/maintenance.php' );
+ die();
+ }
+
+ wp_load_translations_early();
+
+ $protocol = $_SERVER["SERVER_PROTOCOL"];
+ if ( 'HTTP/1.1' != $protocol && 'HTTP/1.0' != $protocol )
+ $protocol = 'HTTP/1.0';
+ header( "$protocol 503 Service Unavailable", true, 503 );
+ header( 'Content-Type: text/html; charset=utf-8' );
+ header( 'Retry-After: 600' );
+?>
+ <!DOCTYPE html>
+ <html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title><?php _e( 'Maintenance' ); ?></title>
+
+ </head>
+ <body>
+ <h1><?php _e( 'Briefly unavailable for scheduled maintenance. Check back in a minute.' ); ?></h1>
+ </body>
+ </html>
+<?php
+ die();
+}
+
+/**
+ * PHP 5 standard microtime start capture.
+ *
+ * @access private
+ * @since 0.71
+ * @global float $timestart Seconds from when function is called.
+ * @return bool Always returns true.
+ */
+function timer_start() {
+ global $timestart;
+ $timestart = microtime( true );
+ return true;
+}
+
+/**
+ * Return and/or display the time from the page start to when function is called.
+ *
+ * You can get the results and print them by doing:
+ * <code>
+ * $nTimePageTookToExecute = timer_stop();
+ * echo $nTimePageTookToExecute;
+ * </code>
+ *
+ * Or instead, you can do:
+ * <code>
+ * timer_stop(1);
+ * </code>
+ * which will do what the above does. If you need the result, you can assign it to a variable, but
+ * in most cases, you only need to echo it.
+ *
+ * @since 0.71
+ * @global float $timestart Seconds from when timer_start() is called
+ * @global float $timeend Seconds from when function is called
+ *
+ * @param int $display Use '0' or null to not echo anything and 1 to echo the total time
+ * @param int $precision The amount of digits from the right of the decimal to display. Default is 3.
+ * @return float The "second.microsecond" finished time calculation
+ */
+function timer_stop( $display = 0, $precision = 3 ) { // if called like timer_stop(1), will echo $timetotal
+ global $timestart, $timeend;
+ $timeend = microtime( true );
+ $timetotal = $timeend - $timestart;
+ $r = ( function_exists( 'number_format_i18n' ) ) ? number_format_i18n( $timetotal, $precision ) : number_format( $timetotal, $precision );
+ if ( $display )
+ echo $r;
+ return $r;
+}
+
+/**
+ * Sets PHP error handling and handles WordPress debug mode.
+ *
+ * Uses three constants: WP_DEBUG, WP_DEBUG_DISPLAY, and WP_DEBUG_LOG. All three can be
+ * defined in wp-config.php. Example: <code> define( 'WP_DEBUG', true ); </code>
+ *
+ * WP_DEBUG_DISPLAY and WP_DEBUG_LOG perform no function unless WP_DEBUG is true.
+ * WP_DEBUG defaults to false.
+ *
+ * When WP_DEBUG is true, all PHP notices are reported. WordPress will also display
+ * notices, including one when a deprecated WordPress function, function argument,
+ * or file is used. Deprecated code may be removed from a later version.
+ *
+ * It is strongly recommended that plugin and theme developers use WP_DEBUG in their
+ * development environments.
+ *
+ * When WP_DEBUG_DISPLAY is true, WordPress will force errors to be displayed.
+ * WP_DEBUG_DISPLAY defaults to true. Defining it as null prevents WordPress from
+ * changing the global configuration setting. Defining WP_DEBUG_DISPLAY as false
+ * will force errors to be hidden.
+ *
+ * When WP_DEBUG_LOG is true, errors will be logged to wp-content/debug.log.
+ * WP_DEBUG_LOG defaults to false.
+ *
+ * Errors are never displayed for XML-RPC requests.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_debug_mode() {
+ if ( WP_DEBUG ) {
+ error_reporting( E_ALL );
+
+ if ( WP_DEBUG_DISPLAY )
+ ini_set( 'display_errors', 1 );
+ elseif ( null !== WP_DEBUG_DISPLAY )
+ ini_set( 'display_errors', 0 );
+
+ if ( WP_DEBUG_LOG ) {
+ ini_set( 'log_errors', 1 );
+ ini_set( 'error_log', WP_CONTENT_DIR . '/debug.log' );
+ }
+ } else {
+ error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
+ }
+ if ( defined( 'XMLRPC_REQUEST' ) )
+ ini_set( 'display_errors', 0 );
+}
+
+/**
+ * Sets the location of the language directory.
+ *
+ * To set directory manually, define <code>WP_LANG_DIR</code> in wp-config.php.
+ *
+ * If the language directory exists within WP_CONTENT_DIR, that is used.
+ * Otherwise if the language directory exists within WPINC, that's used.
+ * Finally, if neither of the preceding directories are found,
+ * WP_CONTENT_DIR/languages is used.
+ *
+ * The WP_LANG_DIR constant was introduced in 2.1.0.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_set_lang_dir() {
+ if ( !defined( 'WP_LANG_DIR' ) ) {
+ if ( file_exists( WP_CONTENT_DIR . '/languages' ) && @is_dir( WP_CONTENT_DIR . '/languages' ) || !@is_dir(ABSPATH . WPINC . '/languages') ) {
+ define( 'WP_LANG_DIR', WP_CONTENT_DIR . '/languages' ); // no leading slash, no trailing slash, full path, not relative to ABSPATH
+ if ( !defined( 'LANGDIR' ) ) {
+ // Old static relative path maintained for limited backwards compatibility - won't work in some cases
+ define( 'LANGDIR', 'wp-content/languages' );
+ }
+ } else {
+ define( 'WP_LANG_DIR', ABSPATH . WPINC . '/languages' ); // no leading slash, no trailing slash, full path, not relative to ABSPATH
+ if ( !defined( 'LANGDIR' ) ) {
+ // Old relative path maintained for backwards compatibility
+ define( 'LANGDIR', WPINC . '/languages' );
+ }
+ }
+ }
+}
+
+/**
+ * Load the correct database class file.
+ *
+ * This function is used to load the database class file either at runtime or by
+ * wp-admin/setup-config.php. We must globalize $wpdb to ensure that it is
+ * defined globally by the inline code in wp-db.php.
+ *
+ * @since 2.5.0
+ * @global $wpdb WordPress Database Object
+ */
+function require_wp_db() {
+ global $wpdb;
+
+ require_once( ABSPATH . WPINC . '/wp-db.php' );
+ if ( file_exists( WP_CONTENT_DIR . '/db.php' ) )
+ require_once( WP_CONTENT_DIR . '/db.php' );
+
+ if ( isset( $wpdb ) )
+ return;
+
+ $wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
+}
+
+/**
+ * Sets the database table prefix and the format specifiers for database table columns.
+ *
+ * Columns not listed here default to %s.
+ *
+ * @see wpdb::$field_types Since 2.8.0
+ * @see wpdb::prepare()
+ * @see wpdb::insert()
+ * @see wpdb::update()
+ * @see wpdb::set_prefix()
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_set_wpdb_vars() {
+ global $wpdb, $table_prefix;
+ if ( !empty( $wpdb->error ) )
+ dead_db();
+
+ $wpdb->field_types = array( 'post_author' => '%d', 'post_parent' => '%d', 'menu_order' => '%d', 'term_id' => '%d', 'term_group' => '%d', 'term_taxonomy_id' => '%d',
+ 'parent' => '%d', 'count' => '%d','object_id' => '%d', 'term_order' => '%d', 'ID' => '%d', 'comment_ID' => '%d', 'comment_post_ID' => '%d', 'comment_parent' => '%d',
+ 'user_id' => '%d', 'link_id' => '%d', 'link_owner' => '%d', 'link_rating' => '%d', 'option_id' => '%d', 'blog_id' => '%d', 'meta_id' => '%d', 'post_id' => '%d',
+ 'user_status' => '%d', 'umeta_id' => '%d', 'comment_karma' => '%d', 'comment_count' => '%d',
+ // multisite:
+ 'active' => '%d', 'cat_id' => '%d', 'deleted' => '%d', 'lang_id' => '%d', 'mature' => '%d', 'public' => '%d', 'site_id' => '%d', 'spam' => '%d',
+ );
+
+ $prefix = $wpdb->set_prefix( $table_prefix );
+
+ if ( is_wp_error( $prefix ) ) {
+ wp_load_translations_early();
+ wp_die( __( '<strong>ERROR</strong>: <code>$table_prefix</code> in <code>wp-config.php</code> can only contain numbers, letters, and underscores.' ) );
+ }
+}
+
+/**
+ * Starts the WordPress object cache.
+ *
+ * If an object-cache.php file exists in the wp-content directory,
+ * it uses that drop-in as an external object cache.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_start_object_cache() {
+ global $_wp_using_ext_object_cache, $blog_id;
+
+ $first_init = false;
+ if ( ! function_exists( 'wp_cache_init' ) ) {
+ if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
+ require_once ( WP_CONTENT_DIR . '/object-cache.php' );
+ $_wp_using_ext_object_cache = true;
+ } else {
+ require_once ( ABSPATH . WPINC . '/cache.php' );
+ $_wp_using_ext_object_cache = false;
+ }
+ $first_init = true;
+ } else if ( !$_wp_using_ext_object_cache && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
+ // Sometimes advanced-cache.php can load object-cache.php before it is loaded here.
+ // This breaks the function_exists check above and can result in $_wp_using_ext_object_cache
+ // being set incorrectly. Double check if an external cache exists.
+ $_wp_using_ext_object_cache = true;
+ }
+
+ // If cache supports reset, reset instead of init if already initialized.
+ // Reset signals to the cache that global IDs have changed and it may need to update keys
+ // and cleanup caches.
+ if ( ! $first_init && function_exists( 'wp_cache_switch_to_blog' ) )
+ wp_cache_switch_to_blog( $blog_id );
+ else
+ wp_cache_init();
+
+ if ( function_exists( 'wp_cache_add_global_groups' ) ) {
+ wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache' ) );
+ wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
+ }
+}
+
+/**
+ * Redirects to the installer if WordPress is not installed.
+ *
+ * Dies with an error message when multisite is enabled.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_not_installed() {
+ if ( is_multisite() ) {
+ if ( ! is_blog_installed() && ! defined( 'WP_INSTALLING' ) )
+ wp_die( __( 'The site you have requested is not installed properly. Please contact the system administrator.' ) );
+ } elseif ( ! is_blog_installed() && false === strpos( $_SERVER['PHP_SELF'], 'install.php' ) && !defined( 'WP_INSTALLING' ) ) {
+
+ $link = wp_guess_url() . '/wp-admin/install.php';
+
+ require( ABSPATH . WPINC . '/kses.php' );
+ require( ABSPATH . WPINC . '/pluggable.php' );
+ require( ABSPATH . WPINC . '/formatting.php' );
+ wp_redirect( $link );
+ die();
+ }
+}
+
+/**
+ * Returns array of must-use plugin files to be included in global scope.
+ *
+ * The default directory is wp-content/mu-plugins. To change the default directory
+ * manually, define <code>WPMU_PLUGIN_DIR</code> and <code>WPMU_PLUGIN_URL</code>
+ * in wp-config.php.
+ *
+ * @access private
+ * @since 3.0.0
+ * @return array Files to include
+ */
+function wp_get_mu_plugins() {
+ $mu_plugins = array();
+ if ( !is_dir( WPMU_PLUGIN_DIR ) )
+ return $mu_plugins;
+ if ( ! $dh = opendir( WPMU_PLUGIN_DIR ) )
+ return $mu_plugins;
+ while ( ( $plugin = readdir( $dh ) ) !== false ) {
+ if ( substr( $plugin, -4 ) == '.php' )
+ $mu_plugins[] = WPMU_PLUGIN_DIR . '/' . $plugin;
+ }
+ closedir( $dh );
+ sort( $mu_plugins );
+
+ return $mu_plugins;
+}
+
+/**
+ * Returns array of plugin files to be included in global scope.
+ *
+ * The default directory is wp-content/plugins. To change the default directory
+ * manually, define <code>WP_PLUGIN_DIR</code> and <code>WP_PLUGIN_URL</code>
+ * in wp-config.php.
+ *
+ * @access private
+ * @since 3.0.0
+ * @return array Files to include
+ */
+function wp_get_active_and_valid_plugins() {
+ $plugins = array();
+ $active_plugins = (array) get_option( 'active_plugins', array() );
+
+ // Check for hacks file if the option is enabled
+ if ( get_option( 'hack_file' ) && file_exists( ABSPATH . 'my-hacks.php' ) ) {
+ _deprecated_file( 'my-hacks.php', '1.5' );
+ array_unshift( $plugins, ABSPATH . 'my-hacks.php' );
+ }
+
+ if ( empty( $active_plugins ) || defined( 'WP_INSTALLING' ) )
+ return $plugins;
+
+ $network_plugins = is_multisite() ? wp_get_active_network_plugins() : false;
+
+ foreach ( $active_plugins as $plugin ) {
+ if ( ! validate_file( $plugin ) // $plugin must validate as file
+ && '.php' == substr( $plugin, -4 ) // $plugin must end with '.php'
+ && file_exists( WP_PLUGIN_DIR . '/' . $plugin ) // $plugin must exist
+ // not already included as a network plugin
+ && ( ! $network_plugins || ! in_array( WP_PLUGIN_DIR . '/' . $plugin, $network_plugins ) )
+ )
+ $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
+ }
+ return $plugins;
+}
+
+/**
+ * Sets internal encoding using mb_internal_encoding().
+ *
+ * In most cases the default internal encoding is latin1, which is of no use,
+ * since we want to use the mb_ functions for utf-8 strings.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_set_internal_encoding() {
+ if ( function_exists( 'mb_internal_encoding' ) ) {
+ $charset = get_option( 'blog_charset' );
+ if ( ! $charset || ! @mb_internal_encoding( $charset ) )
+ mb_internal_encoding( 'UTF-8' );
+ }
+}
+
+/**
+ * Add magic quotes to $_GET, $_POST, $_COOKIE, and $_SERVER.
+ *
+ * Also forces $_REQUEST to be $_GET + $_POST. If $_SERVER, $_COOKIE,
+ * or $_ENV are needed, use those superglobals directly.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function wp_magic_quotes() {
+ // If already slashed, strip.
+ if ( get_magic_quotes_gpc() ) {
+ $_GET = stripslashes_deep( $_GET );
+ $_POST = stripslashes_deep( $_POST );
+ $_COOKIE = stripslashes_deep( $_COOKIE );
+ }
+
+ // Escape with wpdb.
+ $_GET = add_magic_quotes( $_GET );
+ $_POST = add_magic_quotes( $_POST );
+ $_COOKIE = add_magic_quotes( $_COOKIE );
+ $_SERVER = add_magic_quotes( $_SERVER );
+
+ // Force REQUEST to be GET + POST.
+ $_REQUEST = array_merge( $_GET, $_POST );
+}
+
+/**
+ * Runs just before PHP shuts down execution.
+ *
+ * @access private
+ * @since 1.2.0
+ */
+function shutdown_action_hook() {
+ do_action( 'shutdown' );
+ wp_cache_close();
+}
+
+/**
+ * Copy an object.
+ *
+ * @since 2.7.0
+ * @deprecated 3.2
+ *
+ * @param object $object The object to clone
+ * @return object The cloned object
+ */
+
+function wp_clone( $object ) {
+ // Use parens for clone to accommodate PHP 4. See #17880
+ return clone( $object );
+}
+
+/**
+ * Whether the current request is for a network or blog admin page
+ *
+ * Does not inform on whether the user is an admin! Use capability checks to
+ * tell if the user should be accessing a section or not.
+ *
+ * @since 1.5.1
+ *
+ * @return bool True if inside WordPress administration pages.
+ */
+function is_admin() {
+ if ( isset( $GLOBALS['current_screen'] ) )
+ return $GLOBALS['current_screen']->in_admin();
+ elseif ( defined( 'WP_ADMIN' ) )
+ return WP_ADMIN;
+
+ return false;
+}
+
+/**
+ * Whether the current request is for a blog admin screen /wp-admin/
+ *
+ * Does not inform on whether the user is a blog admin! Use capability checks to
+ * tell if the user should be accessing a section or not.
+ *
+ * @since 3.1.0
+ *
+ * @return bool True if inside WordPress network administration pages.
+ */
+function is_blog_admin() {
+ if ( isset( $GLOBALS['current_screen'] ) )
+ return $GLOBALS['current_screen']->in_admin( 'site' );
+ elseif ( defined( 'WP_BLOG_ADMIN' ) )
+ return WP_BLOG_ADMIN;
+
+ return false;
+}
+
+/**
+ * Whether the current request is for a network admin screen /wp-admin/network/
+ *
+ * Does not inform on whether the user is a network admin! Use capability checks to
+ * tell if the user should be accessing a section or not.
+ *
+ * @since 3.1.0
+ *
+ * @return bool True if inside WordPress network administration pages.
+ */
+function is_network_admin() {
+ if ( isset( $GLOBALS['current_screen'] ) )
+ return $GLOBALS['current_screen']->in_admin( 'network' );
+ elseif ( defined( 'WP_NETWORK_ADMIN' ) )
+ return WP_NETWORK_ADMIN;
+
+ return false;
+}
+
+/**
+ * Whether the current request is for a user admin screen /wp-admin/user/
+ *
+ * Does not inform on whether the user is an admin! Use capability checks to
+ * tell if the user should be accessing a section or not.
+ *
+ * @since 3.1.0
+ *
+ * @return bool True if inside WordPress user administration pages.
+ */
+function is_user_admin() {
+ if ( isset( $GLOBALS['current_screen'] ) )
+ return $GLOBALS['current_screen']->in_admin( 'user' );
+ elseif ( defined( 'WP_USER_ADMIN' ) )
+ return WP_USER_ADMIN;
+
+ return false;
+}
+
+/**
+ * Whether Multisite support is enabled
+ *
+ * @since 3.0.0
+ *
+ * @return bool True if multisite is enabled, false otherwise.
+ */
+function is_multisite() {
+ if ( defined( 'MULTISITE' ) )
+ return MULTISITE;
+
+ if ( defined( 'SUBDOMAIN_INSTALL' ) || defined( 'VHOST' ) || defined( 'SUNRISE' ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Retrieve the current blog id
+ *
+ * @since 3.1.0
+ *
+ * @return int Blog id
+ */
+function get_current_blog_id() {
+ global $blog_id;
+ return absint($blog_id);
+}
+
+/**
+ * Attempts an early load of translations.
+ *
+ * Used for errors encountered during the initial loading process, before the locale has been
+ * properly detected and loaded.
+ *
+ * Designed for unusual load sequences (like setup-config.php) or for when the script will then
+ * terminate with an error, otherwise there is a risk that a file can be double-included.
+ *
+ * @since 3.4.0
+ * @access private
+ */
+function wp_load_translations_early() {
+ global $text_direction, $wp_locale;
+
+ static $loaded = false;
+ if ( $loaded )
+ return;
+ $loaded = true;
+
+ if ( function_exists( 'did_action' ) && did_action( 'init' ) )
+ return;
+
+ // We need $wp_local_package
+ require ABSPATH . WPINC . '/version.php';
+
+ // Translation and localization
+ require_once ABSPATH . WPINC . '/pomo/mo.php';
+ require_once ABSPATH . WPINC . '/l10n.php';
+ require_once ABSPATH . WPINC . '/locale.php';
+
+ // General libraries
+ require_once ABSPATH . WPINC . '/plugin.php';
+
+ $locales = $locations = array();
+
+ while ( true ) {
+ if ( defined( 'WPLANG' ) ) {
+ if ( '' == WPLANG )
+ break;
+ $locales[] = WPLANG;
+ }
+
+ if ( isset( $wp_local_package ) )
+ $locales[] = $wp_local_package;
+
+ if ( ! $locales )
+ break;
+
+ if ( defined( 'WP_LANG_DIR' ) && @is_dir( WP_LANG_DIR ) )
+ $locations[] = WP_LANG_DIR;
+
+ if ( defined( 'WP_CONTENT_DIR' ) && @is_dir( WP_CONTENT_DIR . '/languages' ) )
+ $locations[] = WP_CONTENT_DIR . '/languages';
+
+ if ( @is_dir( ABSPATH . 'wp-content/languages' ) )
+ $locations[] = ABSPATH . 'wp-content/languages';
+
+ if ( @is_dir( ABSPATH . WPINC . '/languages' ) )
+ $locations[] = ABSPATH . WPINC . '/languages';
+
+ if ( ! $locations )
+ break;
+
+ $locations = array_unique( $locations );
+
+ foreach ( $locales as $locale ) {
+ foreach ( $locations as $location ) {
+ if ( file_exists( $location . '/' . $locale . '.mo' ) ) {
+ load_textdomain( 'default', $location . '/' . $locale . '.mo' );
+ if ( defined( 'WP_SETUP_CONFIG' ) && file_exists( $location . '/admin-' . $locale . '.mo' ) )
+ load_textdomain( 'default', $location . '/admin-' . $locale . '.mo' );
+ break 2;
+ }
+ }
+ }
+
+ break;
+ }
+
+ $wp_locale = new WP_Locale();
+}
diff --git a/src/wp-includes/locale.php b/src/wp-includes/locale.php
new file mode 100644
index 0000000000..244d08a657
--- /dev/null
+++ b/src/wp-includes/locale.php
@@ -0,0 +1,356 @@
+<?php
+/**
+ * Date and Time Locale object
+ *
+ * @package WordPress
+ * @subpackage i18n
+ */
+
+/**
+ * Class that loads the calendar locale.
+ *
+ * @since 2.1.0
+ */
+class WP_Locale {
+ /**
+ * Stores the translated strings for the full weekday names.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $weekday;
+
+ /**
+ * Stores the translated strings for the one character weekday names.
+ *
+ * There is a hack to make sure that Tuesday and Thursday, as well
+ * as Sunday and Saturday, don't conflict. See init() method for more.
+ *
+ * @see WP_Locale::init() for how to handle the hack.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $weekday_initial;
+
+ /**
+ * Stores the translated strings for the abbreviated weekday names.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $weekday_abbrev;
+
+ /**
+ * Stores the translated strings for the full month names.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $month;
+
+ /**
+ * Stores the translated strings for the abbreviated month names.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $month_abbrev;
+
+ /**
+ * Stores the translated strings for 'am' and 'pm'.
+ *
+ * Also the capitalized versions.
+ *
+ * @since 2.1.0
+ * @var array
+ * @access private
+ */
+ var $meridiem;
+
+ /**
+ * The text direction of the locale language.
+ *
+ * Default is left to right 'ltr'.
+ *
+ * @since 2.1.0
+ * @var string
+ * @access private
+ */
+ var $text_direction = 'ltr';
+
+ /**
+ * Sets up the translated strings and object properties.
+ *
+ * The method creates the translatable strings for various
+ * calendar elements. Which allows for specifying locale
+ * specific calendar names and text direction.
+ *
+ * @since 2.1.0
+ * @access private
+ */
+ function init() {
+ // The Weekdays
+ $this->weekday[0] = /* translators: weekday */ __('Sunday');
+ $this->weekday[1] = /* translators: weekday */ __('Monday');
+ $this->weekday[2] = /* translators: weekday */ __('Tuesday');
+ $this->weekday[3] = /* translators: weekday */ __('Wednesday');
+ $this->weekday[4] = /* translators: weekday */ __('Thursday');
+ $this->weekday[5] = /* translators: weekday */ __('Friday');
+ $this->weekday[6] = /* translators: weekday */ __('Saturday');
+
+ // The first letter of each day. The _%day%_initial suffix is a hack to make
+ // sure the day initials are unique.
+ $this->weekday_initial[__('Sunday')] = /* translators: one-letter abbreviation of the weekday */ __('S_Sunday_initial');
+ $this->weekday_initial[__('Monday')] = /* translators: one-letter abbreviation of the weekday */ __('M_Monday_initial');
+ $this->weekday_initial[__('Tuesday')] = /* translators: one-letter abbreviation of the weekday */ __('T_Tuesday_initial');
+ $this->weekday_initial[__('Wednesday')] = /* translators: one-letter abbreviation of the weekday */ __('W_Wednesday_initial');
+ $this->weekday_initial[__('Thursday')] = /* translators: one-letter abbreviation of the weekday */ __('T_Thursday_initial');
+ $this->weekday_initial[__('Friday')] = /* translators: one-letter abbreviation of the weekday */ __('F_Friday_initial');
+ $this->weekday_initial[__('Saturday')] = /* translators: one-letter abbreviation of the weekday */ __('S_Saturday_initial');
+
+ foreach ($this->weekday_initial as $weekday_ => $weekday_initial_) {
+ $this->weekday_initial[$weekday_] = preg_replace('/_.+_initial$/', '', $weekday_initial_);
+ }
+
+ // Abbreviations for each day.
+ $this->weekday_abbrev[__('Sunday')] = /* translators: three-letter abbreviation of the weekday */ __('Sun');
+ $this->weekday_abbrev[__('Monday')] = /* translators: three-letter abbreviation of the weekday */ __('Mon');
+ $this->weekday_abbrev[__('Tuesday')] = /* translators: three-letter abbreviation of the weekday */ __('Tue');
+ $this->weekday_abbrev[__('Wednesday')] = /* translators: three-letter abbreviation of the weekday */ __('Wed');
+ $this->weekday_abbrev[__('Thursday')] = /* translators: three-letter abbreviation of the weekday */ __('Thu');
+ $this->weekday_abbrev[__('Friday')] = /* translators: three-letter abbreviation of the weekday */ __('Fri');
+ $this->weekday_abbrev[__('Saturday')] = /* translators: three-letter abbreviation of the weekday */ __('Sat');
+
+ // The Months
+ $this->month['01'] = /* translators: month name */ __('January');
+ $this->month['02'] = /* translators: month name */ __('February');
+ $this->month['03'] = /* translators: month name */ __('March');
+ $this->month['04'] = /* translators: month name */ __('April');
+ $this->month['05'] = /* translators: month name */ __('May');
+ $this->month['06'] = /* translators: month name */ __('June');
+ $this->month['07'] = /* translators: month name */ __('July');
+ $this->month['08'] = /* translators: month name */ __('August');
+ $this->month['09'] = /* translators: month name */ __('September');
+ $this->month['10'] = /* translators: month name */ __('October');
+ $this->month['11'] = /* translators: month name */ __('November');
+ $this->month['12'] = /* translators: month name */ __('December');
+
+ // Abbreviations for each month. Uses the same hack as above to get around the
+ // 'May' duplication.
+ $this->month_abbrev[__('January')] = /* translators: three-letter abbreviation of the month */ __('Jan_January_abbreviation');
+ $this->month_abbrev[__('February')] = /* translators: three-letter abbreviation of the month */ __('Feb_February_abbreviation');
+ $this->month_abbrev[__('March')] = /* translators: three-letter abbreviation of the month */ __('Mar_March_abbreviation');
+ $this->month_abbrev[__('April')] = /* translators: three-letter abbreviation of the month */ __('Apr_April_abbreviation');
+ $this->month_abbrev[__('May')] = /* translators: three-letter abbreviation of the month */ __('May_May_abbreviation');
+ $this->month_abbrev[__('June')] = /* translators: three-letter abbreviation of the month */ __('Jun_June_abbreviation');
+ $this->month_abbrev[__('July')] = /* translators: three-letter abbreviation of the month */ __('Jul_July_abbreviation');
+ $this->month_abbrev[__('August')] = /* translators: three-letter abbreviation of the month */ __('Aug_August_abbreviation');
+ $this->month_abbrev[__('September')] = /* translators: three-letter abbreviation of the month */ __('Sep_September_abbreviation');
+ $this->month_abbrev[__('October')] = /* translators: three-letter abbreviation of the month */ __('Oct_October_abbreviation');
+ $this->month_abbrev[__('November')] = /* translators: three-letter abbreviation of the month */ __('Nov_November_abbreviation');
+ $this->month_abbrev[__('December')] = /* translators: three-letter abbreviation of the month */ __('Dec_December_abbreviation');
+
+ foreach ($this->month_abbrev as $month_ => $month_abbrev_) {
+ $this->month_abbrev[$month_] = preg_replace('/_.+_abbreviation$/', '', $month_abbrev_);
+ }
+
+ // The Meridiems
+ $this->meridiem['am'] = __('am');
+ $this->meridiem['pm'] = __('pm');
+ $this->meridiem['AM'] = __('AM');
+ $this->meridiem['PM'] = __('PM');
+
+ // Numbers formatting
+ // See http://php.net/number_format
+
+ /* translators: $thousands_sep argument for http://php.net/number_format, default is , */
+ $trans = __('number_format_thousands_sep');
+ $this->number_format['thousands_sep'] = ('number_format_thousands_sep' == $trans) ? ',' : $trans;
+
+ /* translators: $dec_point argument for http://php.net/number_format, default is . */
+ $trans = __('number_format_decimal_point');
+ $this->number_format['decimal_point'] = ('number_format_decimal_point' == $trans) ? '.' : $trans;
+
+ // Set text direction.
+ if ( isset( $GLOBALS['text_direction'] ) )
+ $this->text_direction = $GLOBALS['text_direction'];
+ /* translators: 'rtl' or 'ltr'. This sets the text direction for WordPress. */
+ elseif ( 'rtl' == _x( 'ltr', 'text direction' ) )
+ $this->text_direction = 'rtl';
+ }
+
+ /**
+ * Retrieve the full translated weekday word.
+ *
+ * Week starts on translated Sunday and can be fetched
+ * by using 0 (zero). So the week starts with 0 (zero)
+ * and ends on Saturday with is fetched by using 6 (six).
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param int $weekday_number 0 for Sunday through 6 Saturday
+ * @return string Full translated weekday
+ */
+ function get_weekday($weekday_number) {
+ return $this->weekday[$weekday_number];
+ }
+
+ /**
+ * Retrieve the translated weekday initial.
+ *
+ * The weekday initial is retrieved by the translated
+ * full weekday word. When translating the weekday initial
+ * pay attention to make sure that the starting letter does
+ * not conflict.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $weekday_name
+ * @return string
+ */
+ function get_weekday_initial($weekday_name) {
+ return $this->weekday_initial[$weekday_name];
+ }
+
+ /**
+ * Retrieve the translated weekday abbreviation.
+ *
+ * The weekday abbreviation is retrieved by the translated
+ * full weekday word.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $weekday_name Full translated weekday word
+ * @return string Translated weekday abbreviation
+ */
+ function get_weekday_abbrev($weekday_name) {
+ return $this->weekday_abbrev[$weekday_name];
+ }
+
+ /**
+ * Retrieve the full translated month by month number.
+ *
+ * The $month_number parameter has to be a string
+ * because it must have the '0' in front of any number
+ * that is less than 10. Starts from '01' and ends at
+ * '12'.
+ *
+ * You can use an integer instead and it will add the
+ * '0' before the numbers less than 10 for you.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string|int $month_number '01' through '12'
+ * @return string Translated full month name
+ */
+ function get_month($month_number) {
+ return $this->month[zeroise($month_number, 2)];
+ }
+
+ /**
+ * Retrieve translated version of month abbreviation string.
+ *
+ * The $month_name parameter is expected to be the translated or
+ * translatable version of the month.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $month_name Translated month to get abbreviated version
+ * @return string Translated abbreviated month
+ */
+ function get_month_abbrev($month_name) {
+ return $this->month_abbrev[$month_name];
+ }
+
+ /**
+ * Retrieve translated version of meridiem string.
+ *
+ * The $meridiem parameter is expected to not be translated.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $meridiem Either 'am', 'pm', 'AM', or 'PM'. Not translated version.
+ * @return string Translated version
+ */
+ function get_meridiem($meridiem) {
+ return $this->meridiem[$meridiem];
+ }
+
+ /**
+ * Global variables are deprecated. For backwards compatibility only.
+ *
+ * @deprecated For backwards compatibility only.
+ * @access private
+ *
+ * @since 2.1.0
+ */
+ function register_globals() {
+ $GLOBALS['weekday'] = $this->weekday;
+ $GLOBALS['weekday_initial'] = $this->weekday_initial;
+ $GLOBALS['weekday_abbrev'] = $this->weekday_abbrev;
+ $GLOBALS['month'] = $this->month;
+ $GLOBALS['month_abbrev'] = $this->month_abbrev;
+ }
+
+ /**
+ * Constructor which calls helper methods to set up object variables
+ *
+ * @uses WP_Locale::init()
+ * @uses WP_Locale::register_globals()
+ * @since 2.1.0
+ *
+ * @return WP_Locale
+ */
+ function __construct() {
+ $this->init();
+ $this->register_globals();
+ }
+
+ /**
+ * Checks if current locale is RTL.
+ *
+ * @since 3.0.0
+ * @return bool Whether locale is RTL.
+ */
+ function is_rtl() {
+ return 'rtl' == $this->text_direction;
+ }
+
+ /**
+ * Private, unused function to add some date/time formats translated
+ * on wp-admin/options-general.php to the general POT.
+ *
+ * @since 3.6.0
+ */
+ function _strings_for_pot() {
+ /* translators: localized date format, see http://php.net/date */
+ __( 'F j, Y' );
+ /* translators: localized time format, see http://php.net/date */
+ __( 'g:i a' );
+ /* translators: localized date and time format, see http://php.net/date */
+ __( 'F j, Y g:i a' );
+ }
+}
+
+/**
+ * Checks if current locale is RTL.
+ *
+ * @since 3.0.0
+ * @return bool Whether locale is RTL.
+ */
+function is_rtl() {
+ global $wp_locale;
+ return $wp_locale->is_rtl();
+}
diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php
new file mode 100644
index 0000000000..6af7dc5f32
--- /dev/null
+++ b/src/wp-includes/media-template.php
@@ -0,0 +1,496 @@
+<?php
+/**
+ * WordPress media templates.
+ *
+ * @package WordPress
+ * @subpackage Media
+ * @since 3.5.0
+ */
+
+/**
+ * Prints the templates used in the media manager.
+ *
+ * @since 3.5.0
+ */
+function wp_print_media_templates() {
+ global $is_IE;
+ $class = 'media-modal wp-core-ui';
+ if ( $is_IE && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 7') !== false )
+ $class .= ' ie7';
+ ?>
+ <script type="text/html" id="tmpl-media-frame">
+ <div class="media-frame-menu"></div>
+ <div class="media-frame-title"></div>
+ <div class="media-frame-router"></div>
+ <div class="media-frame-content"></div>
+ <div class="media-frame-toolbar"></div>
+ <div class="media-frame-uploader"></div>
+ </script>
+
+ <script type="text/html" id="tmpl-media-modal">
+ <div class="<?php echo $class; ?>">
+ <a class="media-modal-close" href="#" title="<?php esc_attr_e('Close'); ?>"><span class="media-modal-icon"></span></a>
+ <div class="media-modal-content"></div>
+ </div>
+ <div class="media-modal-backdrop"></div>
+ </script>
+
+ <script type="text/html" id="tmpl-uploader-window">
+ <div class="uploader-window-content">
+ <h3><?php _e( 'Drop files to upload' ); ?></h3>
+ </div>
+ </script>
+
+ <script type="text/html" id="tmpl-uploader-inline">
+ <# var messageClass = data.message ? 'has-upload-message' : 'no-upload-message'; #>
+ <div class="uploader-inline-content {{ messageClass }}">
+ <# if ( data.message ) { #>
+ <h3 class="upload-message">{{ data.message }}</h3>
+ <# } #>
+ <?php if ( ! _device_can_upload() ) : ?>
+ <h3 class="upload-instructions"><?php printf( __('The web browser on your device cannot be used to upload files. You may be able to use the <a href="%s">native app for your device</a> instead.'), 'http://wordpress.org/mobile/' ); ?></h3>
+ <?php elseif ( is_multisite() && ! is_upload_space_available() ) : ?>
+ <h3 class="upload-instructions"><?php _e( 'Upload Limit Exceeded' ); ?></h3>
+ <?php do_action( 'upload_ui_over_quota' ); ?>
+
+ <?php else : ?>
+ <div class="upload-ui">
+ <h3 class="upload-instructions drop-instructions"><?php _e( 'Drop files anywhere to upload' ); ?></h3>
+ <a href="#" class="browser button button-hero"><?php _e( 'Select Files' ); ?></a>
+ </div>
+
+ <div class="upload-inline-status"></div>
+
+ <div class="post-upload-ui">
+ <?php
+ do_action( 'pre-upload-ui' );
+ do_action( 'pre-plupload-upload-ui' );
+
+ if ( 10 === remove_action( 'post-plupload-upload-ui', 'media_upload_flash_bypass' ) ) {
+ do_action( 'post-plupload-upload-ui' );
+ add_action( 'post-plupload-upload-ui', 'media_upload_flash_bypass' );
+ } else {
+ do_action( 'post-plupload-upload-ui' );
+ }
+
+ $upload_size_unit = $max_upload_size = wp_max_upload_size();
+ $byte_sizes = array( 'KB', 'MB', 'GB' );
+
+ for ( $u = -1; $upload_size_unit > 1024 && $u < count( $byte_sizes ) - 1; $u++ ) {
+ $upload_size_unit /= 1024;
+ }
+
+ if ( $u < 0 ) {
+ $upload_size_unit = 0;
+ $u = 0;
+ } else {
+ $upload_size_unit = (int) $upload_size_unit;
+ }
+
+ ?>
+
+ <p class="max-upload-size"><?php
+ printf( __( 'Maximum upload file size: %d%s.' ), esc_html($upload_size_unit), esc_html($byte_sizes[$u]) );
+ ?></p>
+
+ <?php if ( ( $GLOBALS['is_IE'] || $GLOBALS['is_opera']) && $max_upload_size > 100 * 1024 * 1024 ) :
+ $browser_uploader = admin_url( 'media-new.php?browser-uploader&post_id=' ) . '{{ data.postId }}';
+ ?>
+ <p class="big-file-warning"><?php printf( __( 'Your browser has some limitations uploading large files with the multi-file uploader. Please use the <a href="%1$s" target="%2$s">browser uploader</a> for files over 100MB.' ),
+ $browser_uploader, '_blank' ); ?></p>
+ <?php endif; ?>
+
+ <?php do_action( 'post-upload-ui' ); ?>
+ </div>
+ <?php endif; ?>
+ </div>
+ </script>
+
+ <script type="text/html" id="tmpl-uploader-status">
+ <h3><?php _e( 'Uploading' ); ?></h3>
+ <a class="upload-dismiss-errors" href="#"><?php _e('Dismiss Errors'); ?></a>
+
+ <div class="media-progress-bar"><div></div></div>
+ <div class="upload-details">
+ <span class="upload-count">
+ <span class="upload-index"></span> / <span class="upload-total"></span>
+ </span>
+ <span class="upload-detail-separator">&ndash;</span>
+ <span class="upload-filename"></span>
+ </div>
+ <div class="upload-errors"></div>
+ </script>
+
+ <script type="text/html" id="tmpl-uploader-status-error">
+ <span class="upload-error-label"><?php _e('Error'); ?></span>
+ <span class="upload-error-filename">{{{ data.filename }}}</span>
+ <span class="upload-error-message">{{ data.message }}</span>
+ </script>
+
+ <script type="text/html" id="tmpl-attachment">
+ <div class="attachment-preview type-{{ data.type }} subtype-{{ data.subtype }} {{ data.orientation }}">
+ <# if ( data.uploading ) { #>
+ <div class="media-progress-bar"><div></div></div>
+ <# } else if ( 'image' === data.type ) { #>
+ <div class="thumbnail">
+ <div class="centered">
+ <img src="{{ data.size.url }}" draggable="false" />
+ </div>
+ </div>
+ <# } else { #>
+ <img src="{{ data.icon }}" class="icon" draggable="false" />
+ <div class="filename">
+ <div>{{ data.filename }}</div>
+ </div>
+ <# } #>
+
+ <# if ( data.buttons.close ) { #>
+ <a class="close media-modal-icon" href="#" title="<?php _e('Remove'); ?>"></a>
+ <# } #>
+
+ <# if ( data.buttons.check ) { #>
+ <a class="check" href="#" title="<?php _e('Deselect'); ?>"><div class="media-modal-icon"></div></a>
+ <# } #>
+ </div>
+ <#
+ var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly';
+ if ( data.describe ) { #>
+ <# if ( 'image' === data.type ) { #>
+ <input type="text" value="{{ data.caption }}" class="describe" data-setting="caption"
+ placeholder="<?php esc_attr_e('Caption this image&hellip;'); ?>" {{ maybeReadOnly }} />
+ <# } else { #>
+ <input type="text" value="{{ data.title }}" class="describe" data-setting="title"
+ <# if ( 'video' === data.type ) { #>
+ placeholder="<?php esc_attr_e('Describe this video&hellip;'); ?>"
+ <# } else if ( 'audio' === data.type ) { #>
+ placeholder="<?php esc_attr_e('Describe this audio file&hellip;'); ?>"
+ <# } else { #>
+ placeholder="<?php esc_attr_e('Describe this media file&hellip;'); ?>"
+ <# } #> {{ maybeReadOnly }} />
+ <# } #>
+ <# } #>
+ </script>
+
+ <script type="text/html" id="tmpl-attachment-details">
+ <h3>
+ <?php _e('Attachment Details'); ?>
+
+ <span class="settings-save-status">
+ <span class="spinner"></span>
+ <span class="saved"><?php esc_html_e('Saved.'); ?></span>
+ </span>
+ </h3>
+ <div class="attachment-info">
+ <div class="thumbnail">
+ <# if ( data.uploading ) { #>
+ <div class="media-progress-bar"><div></div></div>
+ <# } else if ( 'image' === data.type ) { #>
+ <img src="{{ data.size.url }}" draggable="false" />
+ <# } else { #>
+ <img src="{{ data.icon }}" class="icon" draggable="false" />
+ <# } #>
+ </div>
+ <div class="details">
+ <div class="filename">{{ data.filename }}</div>
+ <div class="uploaded">{{ data.dateFormatted }}</div>
+
+ <# if ( 'image' === data.type && ! data.uploading ) { #>
+ <# if ( data.width && data.height ) { #>
+ <div class="dimensions">{{ data.width }} &times; {{ data.height }}</div>
+ <# } #>
+
+ <# if ( data.can.save ) { #>
+ <a class="edit-attachment" href="{{ data.editLink }}&amp;image-editor" target="_blank"><?php _e( 'Edit Image' ); ?></a>
+ <a class="refresh-attachment" href="#"><?php _e( 'Refresh' ); ?></a>
+ <# } #>
+ <# } #>
+
+ <# if ( data.fileLength ) { #>
+ <div class="file-length"><?php _e( 'Length:' ); ?> {{ data.fileLength }}</div>
+ <# } #>
+
+ <# if ( ! data.uploading && data.can.remove ) { #>
+ <a class="delete-attachment" href="#"><?php _e( 'Delete Permanently' ); ?></a>
+ <# } #>
+
+ <div class="compat-meta">
+ <# if ( data.compat && data.compat.meta ) { #>
+ {{{ data.compat.meta }}}
+ <# } #>
+ </div>
+ </div>
+ </div>
+
+ <# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #>
+ <label class="setting" data-setting="title">
+ <span><?php _e('Title'); ?></span>
+ <input type="text" value="{{ data.title }}" {{ maybeReadOnly }} />
+ </label>
+ <label class="setting" data-setting="caption">
+ <span><?php _e('Caption'); ?></span>
+ <textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea>
+ </label>
+ <# if ( 'image' === data.type ) { #>
+ <label class="setting" data-setting="alt">
+ <span><?php _e('Alt Text'); ?></span>
+ <input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
+ </label>
+ <# } #>
+ <label class="setting" data-setting="description">
+ <span><?php _e('Description'); ?></span>
+ <textarea {{ maybeReadOnly }}>{{ data.description }}</textarea>
+ </label>
+ </script>
+
+ <script type="text/html" id="tmpl-media-selection">
+ <div class="selection-info">
+ <span class="count"></span>
+ <# if ( data.editable ) { #>
+ <a class="edit-selection" href="#"><?php _e('Edit'); ?></a>
+ <# } #>
+ <# if ( data.clearable ) { #>
+ <a class="clear-selection" href="#"><?php _e('Clear'); ?></a>
+ <# } #>
+ </div>
+ <div class="selection-view"></div>
+ </script>
+
+ <script type="text/html" id="tmpl-attachment-display-settings">
+ <h3><?php _e('Attachment Display Settings'); ?></h3>
+
+ <# if ( 'image' === data.type ) { #>
+ <label class="setting">
+ <span><?php _e('Alignment'); ?></span>
+ <select class="alignment"
+ data-setting="align"
+ <# if ( data.userSettings ) { #>
+ data-user-setting="align"
+ <# } #>>
+
+ <option value="left">
+ <?php esc_attr_e('Left'); ?>
+ </option>
+ <option value="center">
+ <?php esc_attr_e('Center'); ?>
+ </option>
+ <option value="right">
+ <?php esc_attr_e('Right'); ?>
+ </option>
+ <option value="none" selected>
+ <?php esc_attr_e('None'); ?>
+ </option>
+ </select>
+ </label>
+ <# } #>
+
+ <div class="setting">
+ <label>
+ <# if ( data.model.canEmbed ) { #>
+ <span><?php _e('Embed or Link'); ?></span>
+ <# } else { #>
+ <span><?php _e('Link To'); ?></span>
+ <# } #>
+
+ <select class="link-to"
+ data-setting="link"
+ <# if ( data.userSettings && ! data.model.canEmbed ) { #>
+ data-user-setting="urlbutton"
+ <# } #>>
+
+ <# if ( data.model.canEmbed ) { #>
+ <option value="embed" selected>
+ <?php esc_attr_e('Embed Media Player'); ?>
+ </option>
+ <option value="file">
+ <# } else { #>
+ <option value="file" selected>
+ <# } #>
+ <# if ( data.model.canEmbed ) { #>
+ <?php esc_attr_e('Link to Media File'); ?>
+ <# } else { #>
+ <?php esc_attr_e('Media File'); ?>
+ <# } #>
+ </option>
+ <option value="post">
+ <# if ( data.model.canEmbed ) { #>
+ <?php esc_attr_e('Link to Attachment Page'); ?>
+ <# } else { #>
+ <?php esc_attr_e('Attachment Page'); ?>
+ <# } #>
+ </option>
+ <# if ( 'image' === data.type ) { #>
+ <option value="custom">
+ <?php esc_attr_e('Custom URL'); ?>
+ </option>
+ <option value="none">
+ <?php esc_attr_e('None'); ?>
+ </option>
+ <# } #>
+ </select>
+ </label>
+ <input type="text" class="link-to-custom" data-setting="linkUrl" />
+ </div>
+
+ <# if ( 'undefined' !== typeof data.sizes ) { #>
+ <label class="setting">
+ <span><?php _e('Size'); ?></span>
+ <select class="size" name="size"
+ data-setting="size"
+ <# if ( data.userSettings ) { #>
+ data-user-setting="imgsize"
+ <# } #>>
+ <?php
+
+ $sizes = apply_filters( 'image_size_names_choose', array(
+ 'thumbnail' => __('Thumbnail'),
+ 'medium' => __('Medium'),
+ 'large' => __('Large'),
+ 'full' => __('Full Size'),
+ ) );
+
+ foreach ( $sizes as $value => $name ) : ?>
+ <#
+ var size = data.sizes['<?php echo esc_js( $value ); ?>'];
+ if ( size ) { #>
+ <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, 'full' ); ?>>
+ <?php echo esc_html( $name ); ?> &ndash; {{ size.width }} &times; {{ size.height }}
+ </option>
+ <# } #>
+ <?php endforeach; ?>
+ </select>
+ </label>
+ <# } #>
+ </script>
+
+ <script type="text/html" id="tmpl-gallery-settings">
+ <h3><?php _e('Gallery Settings'); ?></h3>
+
+ <label class="setting">
+ <span><?php _e('Link To'); ?></span>
+ <select class="link-to"
+ data-setting="link"
+ <# if ( data.userSettings ) { #>
+ data-user-setting="urlbutton"
+ <# } #>>
+
+ <option value="post" selected>
+ <?php esc_attr_e('Attachment Page'); ?>
+ </option>
+ <option value="file">
+ <?php esc_attr_e('Media File'); ?>
+ </option>
+ <option value="none">
+ <?php esc_attr_e('None'); ?>
+ </option>
+ </select>
+ </label>
+
+ <label class="setting">
+ <span><?php _e('Columns'); ?></span>
+ <select class="columns" name="columns"
+ data-setting="columns">
+ <?php for ( $i = 1; $i <= 9; $i++ ) : ?>
+ <option value="<?php echo esc_attr( $i ); ?>" <?php selected( $i, 3 ); ?>>
+ <?php echo esc_html( $i ); ?>
+ </option>
+ <?php endfor; ?>
+ </select>
+ </label>
+
+ <label class="setting">
+ <span><?php _e( 'Random Order' ); ?></span>
+ <input type="checkbox" data-setting="_orderbyRandom" />
+ </label>
+ </script>
+
+ <script type="text/html" id="tmpl-embed-link-settings">
+ <label class="setting">
+ <span><?php _e('Title'); ?></span>
+ <input type="text" class="alignment" data-setting="title" />
+ </label>
+ </script>
+
+ <script type="text/html" id="tmpl-embed-image-settings">
+ <div class="thumbnail">
+ <img src="{{ data.model.url }}" draggable="false" />
+ </div>
+
+ <?php if ( ! apply_filters( 'disable_captions', '' ) ) : ?>
+ <label class="setting caption">
+ <span><?php _e('Caption'); ?></span>
+ <textarea data-setting="caption" />
+ </label>
+ <?php endif; ?>
+
+ <label class="setting alt-text">
+ <span><?php _e('Alt Text'); ?></span>
+ <input type="text" data-setting="alt" />
+ </label>
+
+ <div class="setting align">
+ <span><?php _e('Align'); ?></span>
+ <div class="button-group button-large" data-setting="align">
+ <button class="button" value="left">
+ <?php esc_attr_e('Left'); ?>
+ </button>
+ <button class="button" value="center">
+ <?php esc_attr_e('Center'); ?>
+ </button>
+ <button class="button" value="right">
+ <?php esc_attr_e('Right'); ?>
+ </button>
+ <button class="button active" value="none">
+ <?php esc_attr_e('None'); ?>
+ </button>
+ </div>
+ </div>
+
+ <div class="setting link-to">
+ <span><?php _e('Link To'); ?></span>
+ <div class="button-group button-large" data-setting="link">
+ <button class="button" value="file">
+ <?php esc_attr_e('Image URL'); ?>
+ </button>
+ <button class="button" value="custom">
+ <?php esc_attr_e('Custom URL'); ?>
+ </button>
+ <button class="button active" value="none">
+ <?php esc_attr_e('None'); ?>
+ </button>
+ </div>
+ <input type="text" class="link-to-custom" data-setting="linkUrl" />
+ </div>
+ </script>
+
+ <script type="text/html" id="tmpl-attachments-css">
+ <style type="text/css" id="{{ data.id }}-css">
+ #{{ data.id }} {
+ padding: 0 {{ data.gutter }}px;
+ }
+
+ #{{ data.id }} .attachment {
+ margin: {{ data.gutter }}px;
+ width: {{ data.edge }}px;
+ }
+
+ #{{ data.id }} .attachment-preview,
+ #{{ data.id }} .attachment-preview .thumbnail {
+ width: {{ data.edge }}px;
+ height: {{ data.edge }}px;
+ }
+
+ #{{ data.id }} .portrait .thumbnail img {
+ max-width: {{ data.edge }}px;
+ height: auto;
+ }
+
+ #{{ data.id }} .landscape .thumbnail img {
+ width: auto;
+ max-height: {{ data.edge }}px;
+ }
+ </style>
+ </script>
+ <?php
+
+ do_action( 'print_media_templates' );
+}
diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php
new file mode 100644
index 0000000000..6111f36370
--- /dev/null
+++ b/src/wp-includes/media.php
@@ -0,0 +1,2029 @@
+<?php
+/**
+ * WordPress API for media display.
+ *
+ * @package WordPress
+ * @subpackage Media
+ */
+
+/**
+ * Scale down the default size of an image.
+ *
+ * This is so that the image is a better fit for the editor and theme.
+ *
+ * The $size parameter accepts either an array or a string. The supported string
+ * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at
+ * 128 width and 96 height in pixels. Also supported for the string value is
+ * 'medium' and 'full'. The 'full' isn't actually supported, but any value other
+ * than the supported will result in the content_width size or 500 if that is
+ * not set.
+ *
+ * Finally, there is a filter named 'editor_max_image_size', that will be called
+ * on the calculated array for width and height, respectively. The second
+ * parameter will be the value that was in the $size parameter. The returned
+ * type for the hook is an array with the width as the first element and the
+ * height as the second element.
+ *
+ * @since 2.5.0
+ * @uses wp_constrain_dimensions() This function passes the widths and the heights.
+ *
+ * @param int $width Width of the image
+ * @param int $height Height of the image
+ * @param string|array $size Size of what the result image should be.
+ * @param context Could be 'display' (like in a theme) or 'edit' (like inserting into an editor)
+ * @return array Width and height of what the result image should resize to.
+ */
+function image_constrain_size_for_editor($width, $height, $size = 'medium', $context = null ) {
+ global $content_width, $_wp_additional_image_sizes;
+
+ if ( ! $context )
+ $context = is_admin() ? 'edit' : 'display';
+
+ if ( is_array($size) ) {
+ $max_width = $size[0];
+ $max_height = $size[1];
+ }
+ elseif ( $size == 'thumb' || $size == 'thumbnail' ) {
+ $max_width = intval(get_option('thumbnail_size_w'));
+ $max_height = intval(get_option('thumbnail_size_h'));
+ // last chance thumbnail size defaults
+ if ( !$max_width && !$max_height ) {
+ $max_width = 128;
+ $max_height = 96;
+ }
+ }
+ elseif ( $size == 'medium' ) {
+ $max_width = intval(get_option('medium_size_w'));
+ $max_height = intval(get_option('medium_size_h'));
+ // if no width is set, default to the theme content width if available
+ }
+ elseif ( $size == 'large' ) {
+ // We're inserting a large size image into the editor. If it's a really
+ // big image we'll scale it down to fit reasonably within the editor
+ // itself, and within the theme's content width if it's known. The user
+ // can resize it in the editor if they wish.
+ $max_width = intval(get_option('large_size_w'));
+ $max_height = intval(get_option('large_size_h'));
+ if ( intval($content_width) > 0 )
+ $max_width = min( intval($content_width), $max_width );
+ } elseif ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) && in_array( $size, array_keys( $_wp_additional_image_sizes ) ) ) {
+ $max_width = intval( $_wp_additional_image_sizes[$size]['width'] );
+ $max_height = intval( $_wp_additional_image_sizes[$size]['height'] );
+ if ( intval($content_width) > 0 && 'edit' == $context ) // Only in admin. Assume that theme authors know what they're doing.
+ $max_width = min( intval($content_width), $max_width );
+ }
+ // $size == 'full' has no constraint
+ else {
+ $max_width = $width;
+ $max_height = $height;
+ }
+
+ list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size, $context );
+
+ return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
+}
+
+/**
+ * Retrieve width and height attributes using given width and height values.
+ *
+ * Both attributes are required in the sense that both parameters must have a
+ * value, but are optional in that if you set them to false or null, then they
+ * will not be added to the returned string.
+ *
+ * You can set the value using a string, but it will only take numeric values.
+ * If you wish to put 'px' after the numbers, then it will be stripped out of
+ * the return.
+ *
+ * @since 2.5.0
+ *
+ * @param int|string $width Optional. Width attribute value.
+ * @param int|string $height Optional. Height attribute value.
+ * @return string HTML attributes for width and, or height.
+ */
+function image_hwstring($width, $height) {
+ $out = '';
+ if ($width)
+ $out .= 'width="'.intval($width).'" ';
+ if ($height)
+ $out .= 'height="'.intval($height).'" ';
+ return $out;
+}
+
+/**
+ * Scale an image to fit a particular size (such as 'thumb' or 'medium').
+ *
+ * Array with image url, width, height, and whether is intermediate size, in
+ * that order is returned on success is returned. $is_intermediate is true if
+ * $url is a resized image, false if it is the original.
+ *
+ * The URL might be the original image, or it might be a resized version. This
+ * function won't create a new resized copy, it will just return an already
+ * resized one if it exists.
+ *
+ * A plugin may use the 'image_downsize' filter to hook into and offer image
+ * resizing services for images. The hook must return an array with the same
+ * elements that are returned in the function. The first element being the URL
+ * to the new image that was resized.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'image_downsize' on $id and $size to provide
+ * resize services.
+ *
+ * @param int $id Attachment ID for image.
+ * @param array|string $size Optional, default is 'medium'. Size of image, either array or string.
+ * @return bool|array False on failure, array on success.
+ */
+function image_downsize($id, $size = 'medium') {
+
+ if ( !wp_attachment_is_image($id) )
+ return false;
+
+ // plugins can use this to provide resize services
+ if ( $out = apply_filters( 'image_downsize', false, $id, $size ) )
+ return $out;
+
+ $img_url = wp_get_attachment_url($id);
+ $meta = wp_get_attachment_metadata($id);
+ $width = $height = 0;
+ $is_intermediate = false;
+ $img_url_basename = wp_basename($img_url);
+
+ // try for a new style intermediate size
+ if ( $intermediate = image_get_intermediate_size($id, $size) ) {
+ $img_url = str_replace($img_url_basename, $intermediate['file'], $img_url);
+ $width = $intermediate['width'];
+ $height = $intermediate['height'];
+ $is_intermediate = true;
+ }
+ elseif ( $size == 'thumbnail' ) {
+ // fall back to the old thumbnail
+ if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) {
+ $img_url = str_replace($img_url_basename, wp_basename($thumb_file), $img_url);
+ $width = $info[0];
+ $height = $info[1];
+ $is_intermediate = true;
+ }
+ }
+ if ( !$width && !$height && isset( $meta['width'], $meta['height'] ) ) {
+ // any other type: use the real image
+ $width = $meta['width'];
+ $height = $meta['height'];
+ }
+
+ if ( $img_url) {
+ // we have the actual image size, but might need to further constrain it if content_width is narrower
+ list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size );
+
+ return array( $img_url, $width, $height, $is_intermediate );
+ }
+ return false;
+
+}
+
+/**
+ * Registers a new image size
+ *
+ * @since 2.9.0
+ */
+function add_image_size( $name, $width = 0, $height = 0, $crop = false ) {
+ global $_wp_additional_image_sizes;
+ $_wp_additional_image_sizes[$name] = array( 'width' => absint( $width ), 'height' => absint( $height ), 'crop' => (bool) $crop );
+}
+
+/**
+ * Registers an image size for the post thumbnail
+ *
+ * @since 2.9.0
+ */
+function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) {
+ add_image_size( 'post-thumbnail', $width, $height, $crop );
+}
+
+/**
+ * An <img src /> tag for an image attachment, scaling it down if requested.
+ *
+ * The filter 'get_image_tag_class' allows for changing the class name for the
+ * image without having to use regular expressions on the HTML content. The
+ * parameters are: what WordPress will use for the class, the Attachment ID,
+ * image align value, and the size the image should be.
+ *
+ * The second filter 'get_image_tag' has the HTML content, which can then be
+ * further manipulated by a plugin to change all attribute values and even HTML
+ * content.
+ *
+ * @since 2.5.0
+ *
+ * @uses apply_filters() The 'get_image_tag_class' filter is the IMG element
+ * class attribute.
+ * @uses apply_filters() The 'get_image_tag' filter is the full IMG element with
+ * all attributes.
+ *
+ * @param int $id Attachment ID.
+ * @param string $alt Image Description for the alt attribute.
+ * @param string $title Image Description for the title attribute.
+ * @param string $align Part of the class name for aligning the image.
+ * @param string $size Optional. Default is 'medium'.
+ * @return string HTML IMG element for given image attachment
+ */
+function get_image_tag($id, $alt, $title, $align, $size='medium') {
+
+ list( $img_src, $width, $height ) = image_downsize($id, $size);
+ $hwstring = image_hwstring($width, $height);
+
+ $title = $title ? 'title="' . esc_attr( $title ) . '" ' : '';
+
+ $class = 'align' . esc_attr($align) .' size-' . esc_attr($size) . ' wp-image-' . $id;
+ $class = apply_filters('get_image_tag_class', $class, $id, $align, $size);
+
+ $html = '<img src="' . esc_attr($img_src) . '" alt="' . esc_attr($alt) . '" ' . $title . $hwstring . 'class="' . $class . '" />';
+
+ $html = apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
+
+ return $html;
+}
+
+/**
+ * Calculates the new dimensions for a downsampled image.
+ *
+ * If either width or height are empty, no constraint is applied on
+ * that dimension.
+ *
+ * @since 2.5.0
+ *
+ * @param int $current_width Current width of the image.
+ * @param int $current_height Current height of the image.
+ * @param int $max_width Optional. Maximum wanted width.
+ * @param int $max_height Optional. Maximum wanted height.
+ * @return array First item is the width, the second item is the height.
+ */
+function wp_constrain_dimensions( $current_width, $current_height, $max_width=0, $max_height=0 ) {
+ if ( !$max_width and !$max_height )
+ return array( $current_width, $current_height );
+
+ $width_ratio = $height_ratio = 1.0;
+ $did_width = $did_height = false;
+
+ if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) {
+ $width_ratio = $max_width / $current_width;
+ $did_width = true;
+ }
+
+ if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) {
+ $height_ratio = $max_height / $current_height;
+ $did_height = true;
+ }
+
+ // Calculate the larger/smaller ratios
+ $smaller_ratio = min( $width_ratio, $height_ratio );
+ $larger_ratio = max( $width_ratio, $height_ratio );
+
+ if ( intval( $current_width * $larger_ratio ) > $max_width || intval( $current_height * $larger_ratio ) > $max_height )
+ // The larger ratio is too big. It would result in an overflow.
+ $ratio = $smaller_ratio;
+ else
+ // The larger ratio fits, and is likely to be a more "snug" fit.
+ $ratio = $larger_ratio;
+
+ $w = intval( $current_width * $ratio );
+ $h = intval( $current_height * $ratio );
+
+ // Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
+ // We also have issues with recursive calls resulting in an ever-changing result. Constraining to the result of a constraint should yield the original result.
+ // Thus we look for dimensions that are one pixel shy of the max value and bump them up
+ if ( $did_width && $w == $max_width - 1 )
+ $w = $max_width; // Round it up
+ if ( $did_height && $h == $max_height - 1 )
+ $h = $max_height; // Round it up
+
+ return array( $w, $h );
+}
+
+/**
+ * Retrieve calculated resized dimensions for use in WP_Image_Editor.
+ *
+ * Calculate dimensions and coordinates for a resized image that fits within a
+ * specified width and height. If $crop is true, the largest matching central
+ * portion of the image will be cropped out and resized to the required size.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'image_resize_dimensions' on $orig_w, $orig_h, $dest_w, $dest_h and
+ * $crop to provide custom resize dimensions.
+ *
+ * @param int $orig_w Original width.
+ * @param int $orig_h Original height.
+ * @param int $dest_w New width.
+ * @param int $dest_h New height.
+ * @param bool $crop Optional, default is false. Whether to crop image or resize.
+ * @return bool|array False on failure. Returned array matches parameters for imagecopyresampled() PHP function.
+ */
+function image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop = false) {
+
+ if ($orig_w <= 0 || $orig_h <= 0)
+ return false;
+ // at least one of dest_w or dest_h must be specific
+ if ($dest_w <= 0 && $dest_h <= 0)
+ return false;
+
+ // plugins can use this to provide custom resize dimensions
+ $output = apply_filters( 'image_resize_dimensions', null, $orig_w, $orig_h, $dest_w, $dest_h, $crop );
+ if ( null !== $output )
+ return $output;
+
+ if ( $crop ) {
+ // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
+ $aspect_ratio = $orig_w / $orig_h;
+ $new_w = min($dest_w, $orig_w);
+ $new_h = min($dest_h, $orig_h);
+
+ if ( !$new_w ) {
+ $new_w = intval($new_h * $aspect_ratio);
+ }
+
+ if ( !$new_h ) {
+ $new_h = intval($new_w / $aspect_ratio);
+ }
+
+ $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
+
+ $crop_w = round($new_w / $size_ratio);
+ $crop_h = round($new_h / $size_ratio);
+
+ $s_x = floor( ($orig_w - $crop_w) / 2 );
+ $s_y = floor( ($orig_h - $crop_h) / 2 );
+ } else {
+ // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
+ $crop_w = $orig_w;
+ $crop_h = $orig_h;
+
+ $s_x = 0;
+ $s_y = 0;
+
+ list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
+ }
+
+ // if the resulting image would be the same size or larger we don't want to resize it
+ if ( $new_w >= $orig_w && $new_h >= $orig_h )
+ return false;
+
+ // the return array matches the parameters to imagecopyresampled()
+ // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
+ return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
+
+}
+
+/**
+ * Resize an image to make a thumbnail or intermediate size.
+ *
+ * The returned array has the file size, the image width, and image height. The
+ * filter 'image_make_intermediate_size' can be used to hook in and change the
+ * values of the returned array. The only parameter is the resized file path.
+ *
+ * @since 2.5.0
+ *
+ * @param string $file File path.
+ * @param int $width Image width.
+ * @param int $height Image height.
+ * @param bool $crop Optional, default is false. Whether to crop image to specified height and width or resize.
+ * @return bool|array False, if no image was created. Metadata array on success.
+ */
+function image_make_intermediate_size( $file, $width, $height, $crop = false ) {
+ if ( $width || $height ) {
+ $editor = wp_get_image_editor( $file );
+
+ if ( is_wp_error( $editor ) || is_wp_error( $editor->resize( $width, $height, $crop ) ) )
+ return false;
+
+ $resized_file = $editor->save();
+
+ if ( ! is_wp_error( $resized_file ) && $resized_file ) {
+ unset( $resized_file['path'] );
+ return $resized_file;
+ }
+ }
+ return false;
+}
+
+/**
+ * Retrieve the image's intermediate size (resized) path, width, and height.
+ *
+ * The $size parameter can be an array with the width and height respectively.
+ * If the size matches the 'sizes' metadata array for width and height, then it
+ * will be used. If there is no direct match, then the nearest image size larger
+ * than the specified size will be used. If nothing is found, then the function
+ * will break out and return false.
+ *
+ * The metadata 'sizes' is used for compatible sizes that can be used for the
+ * parameter $size value.
+ *
+ * The url path will be given, when the $size parameter is a string.
+ *
+ * If you are passing an array for the $size, you should consider using
+ * add_image_size() so that a cropped version is generated. It's much more
+ * efficient than having to find the closest-sized image and then having the
+ * browser scale down the image.
+ *
+ * @since 2.5.0
+ * @see add_image_size()
+ *
+ * @param int $post_id Attachment ID for image.
+ * @param array|string $size Optional, default is 'thumbnail'. Size of image, either array or string.
+ * @return bool|array False on failure or array of file path, width, and height on success.
+ */
+function image_get_intermediate_size($post_id, $size='thumbnail') {
+ if ( !is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) )
+ return false;
+
+ // get the best one for a specified set of dimensions
+ if ( is_array($size) && !empty($imagedata['sizes']) ) {
+ foreach ( $imagedata['sizes'] as $_size => $data ) {
+ // already cropped to width or height; so use this size
+ if ( ( $data['width'] == $size[0] && $data['height'] <= $size[1] ) || ( $data['height'] == $size[1] && $data['width'] <= $size[0] ) ) {
+ $file = $data['file'];
+ list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
+ return compact( 'file', 'width', 'height' );
+ }
+ // add to lookup table: area => size
+ $areas[$data['width'] * $data['height']] = $_size;
+ }
+ if ( !$size || !empty($areas) ) {
+ // find for the smallest image not smaller than the desired size
+ ksort($areas);
+ foreach ( $areas as $_size ) {
+ $data = $imagedata['sizes'][$_size];
+ if ( $data['width'] >= $size[0] || $data['height'] >= $size[1] ) {
+ // Skip images with unexpectedly divergent aspect ratios (crops)
+ // First, we calculate what size the original image would be if constrained to a box the size of the current image in the loop
+ $maybe_cropped = image_resize_dimensions($imagedata['width'], $imagedata['height'], $data['width'], $data['height'], false );
+ // If the size doesn't match within one pixel, then it is of a different aspect ratio, so we skip it, unless it's the thumbnail size
+ if ( 'thumbnail' != $_size && ( !$maybe_cropped || ( $maybe_cropped[4] != $data['width'] && $maybe_cropped[4] + 1 != $data['width'] ) || ( $maybe_cropped[5] != $data['height'] && $maybe_cropped[5] + 1 != $data['height'] ) ) )
+ continue;
+ // If we're still here, then we're going to use this size
+ $file = $data['file'];
+ list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
+ return compact( 'file', 'width', 'height' );
+ }
+ }
+ }
+ }
+
+ if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) )
+ return false;
+
+ $data = $imagedata['sizes'][$size];
+ // include the full filesystem path of the intermediate file
+ if ( empty($data['path']) && !empty($data['file']) ) {
+ $file_url = wp_get_attachment_url($post_id);
+ $data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
+ $data['url'] = path_join( dirname($file_url), $data['file'] );
+ }
+ return $data;
+}
+
+/**
+ * Get the available image sizes
+ * @since 3.0.0
+ * @return array Returns a filtered array of image size strings
+ */
+function get_intermediate_image_sizes() {
+ global $_wp_additional_image_sizes;
+ $image_sizes = array('thumbnail', 'medium', 'large'); // Standard sizes
+ if ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) )
+ $image_sizes = array_merge( $image_sizes, array_keys( $_wp_additional_image_sizes ) );
+
+ return apply_filters( 'intermediate_image_sizes', $image_sizes );
+}
+
+/**
+ * Retrieve an image to represent an attachment.
+ *
+ * A mime icon for files, thumbnail or intermediate size for images.
+ *
+ * @since 2.5.0
+ *
+ * @param int $attachment_id Image attachment ID.
+ * @param string $size Optional, default is 'thumbnail'.
+ * @param bool $icon Optional, default is false. Whether it is an icon.
+ * @return bool|array Returns an array (url, width, height), or false, if no image is available.
+ */
+function wp_get_attachment_image_src($attachment_id, $size='thumbnail', $icon = false) {
+
+ // get a thumbnail or intermediate image if there is one
+ if ( $image = image_downsize($attachment_id, $size) )
+ return $image;
+
+ $src = false;
+
+ if ( $icon && $src = wp_mime_type_icon($attachment_id) ) {
+ $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
+ $src_file = $icon_dir . '/' . wp_basename($src);
+ @list($width, $height) = getimagesize($src_file);
+ }
+ if ( $src && $width && $height )
+ return array( $src, $width, $height );
+ return false;
+}
+
+/**
+ * Get an HTML img element representing an image attachment
+ *
+ * While $size will accept an array, it is better to register a size with
+ * add_image_size() so that a cropped version is generated. It's much more
+ * efficient than having to find the closest-sized image and then having the
+ * browser scale down the image.
+ *
+ * @see add_image_size()
+ * @uses apply_filters() Calls 'wp_get_attachment_image_attributes' hook on attributes array
+ * @uses wp_get_attachment_image_src() Gets attachment file URL and dimensions
+ * @since 2.5.0
+ *
+ * @param int $attachment_id Image attachment ID.
+ * @param string $size Optional, default is 'thumbnail'.
+ * @param bool $icon Optional, default is false. Whether it is an icon.
+ * @param mixed $attr Optional, attributes for the image markup.
+ * @return string HTML img element or empty string on failure.
+ */
+function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false, $attr = '') {
+
+ $html = '';
+ $image = wp_get_attachment_image_src($attachment_id, $size, $icon);
+ if ( $image ) {
+ list($src, $width, $height) = $image;
+ $hwstring = image_hwstring($width, $height);
+ if ( is_array($size) )
+ $size = join('x', $size);
+ $attachment = get_post($attachment_id);
+ $default_attr = array(
+ 'src' => $src,
+ 'class' => "attachment-$size",
+ 'alt' => trim(strip_tags( get_post_meta($attachment_id, '_wp_attachment_image_alt', true) )), // Use Alt field first
+ );
+ if ( empty($default_attr['alt']) )
+ $default_attr['alt'] = trim(strip_tags( $attachment->post_excerpt )); // If not, Use the Caption
+ if ( empty($default_attr['alt']) )
+ $default_attr['alt'] = trim(strip_tags( $attachment->post_title )); // Finally, use the title
+
+ $attr = wp_parse_args($attr, $default_attr);
+ $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment );
+ $attr = array_map( 'esc_attr', $attr );
+ $html = rtrim("<img $hwstring");
+ foreach ( $attr as $name => $value ) {
+ $html .= " $name=" . '"' . $value . '"';
+ }
+ $html .= ' />';
+ }
+
+ return $html;
+}
+
+/**
+ * Adds a 'wp-post-image' class to post thumbnails
+ * Uses the begin_fetch_post_thumbnail_html and end_fetch_post_thumbnail_html action hooks to
+ * dynamically add/remove itself so as to only filter post thumbnails
+ *
+ * @since 2.9.0
+ * @param array $attr Attributes including src, class, alt, title
+ * @return array
+ */
+function _wp_post_thumbnail_class_filter( $attr ) {
+ $attr['class'] .= ' wp-post-image';
+ return $attr;
+}
+
+/**
+ * Adds _wp_post_thumbnail_class_filter to the wp_get_attachment_image_attributes filter
+ *
+ * @since 2.9.0
+ */
+function _wp_post_thumbnail_class_filter_add( $attr ) {
+ add_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
+}
+
+/**
+ * Removes _wp_post_thumbnail_class_filter from the wp_get_attachment_image_attributes filter
+ *
+ * @since 2.9.0
+ */
+function _wp_post_thumbnail_class_filter_remove( $attr ) {
+ remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' );
+}
+
+add_shortcode('wp_caption', 'img_caption_shortcode');
+add_shortcode('caption', 'img_caption_shortcode');
+
+/**
+ * The Caption shortcode.
+ *
+ * Allows a plugin to replace the content that would otherwise be returned. The
+ * filter is 'img_caption_shortcode' and passes an empty string, the attr
+ * parameter and the content parameter values.
+ *
+ * The supported attributes for the shortcode are 'id', 'align', 'width', and
+ * 'caption'.
+ *
+ * @since 2.6.0
+ *
+ * @param array $attr Attributes attributed to the shortcode.
+ * @param string $content Optional. Shortcode content.
+ * @return string
+ */
+function img_caption_shortcode($attr, $content = null) {
+ // New-style shortcode with the caption inside the shortcode with the link and image tags.
+ if ( ! isset( $attr['caption'] ) ) {
+ if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
+ $content = $matches[1];
+ $attr['caption'] = trim( $matches[2] );
+ }
+ }
+
+ // Allow plugins/themes to override the default caption template.
+ $output = apply_filters('img_caption_shortcode', '', $attr, $content);
+ if ( $output != '' )
+ return $output;
+
+ extract(shortcode_atts(array(
+ 'id' => '',
+ 'align' => 'alignnone',
+ 'width' => '',
+ 'caption' => ''
+ ), $attr, 'caption'));
+
+ if ( 1 > (int) $width || empty($caption) )
+ return $content;
+
+ if ( $id ) $id = 'id="' . esc_attr($id) . '" ';
+
+ return '<div ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: ' . (10 + (int) $width) . 'px">'
+ . do_shortcode( $content ) . '<p class="wp-caption-text">' . $caption . '</p></div>';
+}
+
+add_shortcode('gallery', 'gallery_shortcode');
+
+/**
+ * The Gallery shortcode.
+ *
+ * This implements the functionality of the Gallery Shortcode for displaying
+ * WordPress images on a post.
+ *
+ * @since 2.5.0
+ *
+ * @param array $attr Attributes of the shortcode.
+ * @return string HTML content to display gallery.
+ */
+function gallery_shortcode($attr) {
+ $post = get_post();
+
+ static $instance = 0;
+ $instance++;
+
+ if ( ! empty( $attr['ids'] ) ) {
+ // 'ids' is explicitly ordered, unless you specify otherwise.
+ if ( empty( $attr['orderby'] ) )
+ $attr['orderby'] = 'post__in';
+ $attr['include'] = $attr['ids'];
+ }
+
+ // Allow plugins/themes to override the default gallery template.
+ $output = apply_filters('post_gallery', '', $attr);
+ if ( $output != '' )
+ return $output;
+
+ // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
+ if ( isset( $attr['orderby'] ) ) {
+ $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
+ if ( !$attr['orderby'] )
+ unset( $attr['orderby'] );
+ }
+
+ extract(shortcode_atts(array(
+ 'order' => 'ASC',
+ 'orderby' => 'menu_order ID',
+ 'id' => $post ? $post->ID : 0,
+ 'itemtag' => 'dl',
+ 'icontag' => 'dt',
+ 'captiontag' => 'dd',
+ 'columns' => 3,
+ 'size' => 'thumbnail',
+ 'include' => '',
+ 'exclude' => ''
+ ), $attr, 'gallery'));
+
+ $id = intval($id);
+ if ( 'RAND' == $order )
+ $orderby = 'none';
+
+ if ( !empty($include) ) {
+ $_attachments = get_posts( array('include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
+
+ $attachments = array();
+ foreach ( $_attachments as $key => $val ) {
+ $attachments[$val->ID] = $_attachments[$key];
+ }
+ } elseif ( !empty($exclude) ) {
+ $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
+ } else {
+ $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
+ }
+
+ if ( empty($attachments) )
+ return '';
+
+ if ( is_feed() ) {
+ $output = "\n";
+ foreach ( $attachments as $att_id => $attachment )
+ $output .= wp_get_attachment_link($att_id, $size, true) . "\n";
+ return $output;
+ }
+
+ $itemtag = tag_escape($itemtag);
+ $captiontag = tag_escape($captiontag);
+ $icontag = tag_escape($icontag);
+ $valid_tags = wp_kses_allowed_html( 'post' );
+ if ( ! isset( $valid_tags[ $itemtag ] ) )
+ $itemtag = 'dl';
+ if ( ! isset( $valid_tags[ $captiontag ] ) )
+ $captiontag = 'dd';
+ if ( ! isset( $valid_tags[ $icontag ] ) )
+ $icontag = 'dt';
+
+ $columns = intval($columns);
+ $itemwidth = $columns > 0 ? floor(100/$columns) : 100;
+ $float = is_rtl() ? 'right' : 'left';
+
+ $selector = "gallery-{$instance}";
+
+ $gallery_style = $gallery_div = '';
+ if ( apply_filters( 'use_default_gallery_style', true ) )
+ $gallery_style = "
+ <style type='text/css'>
+ #{$selector} {
+ margin: auto;
+ }
+ #{$selector} .gallery-item {
+ float: {$float};
+ margin-top: 10px;
+ text-align: center;
+ width: {$itemwidth}%;
+ }
+ #{$selector} img {
+ border: 2px solid #cfcfcf;
+ }
+ #{$selector} .gallery-caption {
+ margin-left: 0;
+ }
+ /* see gallery_shortcode() in wp-includes/media.php */
+ </style>";
+ $size_class = sanitize_html_class( $size );
+ $gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
+ $output = apply_filters( 'gallery_style', $gallery_style . "\n\t\t" . $gallery_div );
+
+ $i = 0;
+ foreach ( $attachments as $id => $attachment ) {
+ if ( ! empty( $attr['link'] ) && 'file' === $attr['link'] )
+ $image_output = wp_get_attachment_link( $id, $size, false, false );
+ elseif ( ! empty( $attr['link'] ) && 'none' === $attr['link'] )
+ $image_output = wp_get_attachment_image( $id, $size, false );
+ else
+ $image_output = wp_get_attachment_link( $id, $size, true, false );
+
+ $image_meta = wp_get_attachment_metadata( $id );
+
+ $orientation = '';
+ if ( isset( $image_meta['height'], $image_meta['width'] ) )
+ $orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
+
+ $output .= "<{$itemtag} class='gallery-item'>";
+ $output .= "
+ <{$icontag} class='gallery-icon {$orientation}'>
+ $image_output
+ </{$icontag}>";
+ if ( $captiontag && trim($attachment->post_excerpt) ) {
+ $output .= "
+ <{$captiontag} class='wp-caption-text gallery-caption'>
+ " . wptexturize($attachment->post_excerpt) . "
+ </{$captiontag}>";
+ }
+ $output .= "</{$itemtag}>";
+ if ( $columns > 0 && ++$i % $columns == 0 )
+ $output .= '<br style="clear: both" />';
+ }
+
+ $output .= "
+ <br style='clear: both;' />
+ </div>\n";
+
+ return $output;
+}
+
+/**
+ * Provide a No-JS Flash fallback as a last resort for audio / video
+ *
+ * @since 3.6.0
+ *
+ * @param string $url
+ * @return string Fallback HTML
+ */
+function wp_mediaelement_fallback( $url ) {
+ return apply_filters( 'wp_mediaelement_fallback', sprintf( '<a href="%1$s">%1$s</a>', esc_url( $url ) ), $url );
+}
+
+/**
+ * Return a filtered list of WP-supported audio formats
+ *
+ * @since 3.6.0
+ * @return array
+ */
+function wp_get_audio_extensions() {
+ return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'wma', 'm4a', 'wav' ) );
+}
+
+/**
+ * The Audio shortcode.
+ *
+ * This implements the functionality of the Audio Shortcode for displaying
+ * WordPress mp3s in a post.
+ *
+ * @since 3.6.0
+ *
+ * @param array $attr Attributes of the shortcode.
+ * @return string HTML content to display audio.
+ */
+function wp_audio_shortcode( $attr ) {
+ $post_id = get_post() ? get_the_ID() : 0;
+
+ static $instances = 0;
+ $instances++;
+
+ $audio = null;
+
+ $default_types = wp_get_audio_extensions();
+ $defaults_atts = array(
+ 'src' => '',
+ 'loop' => '',
+ 'autoplay' => '',
+ 'preload' => 'none'
+ );
+ foreach ( $default_types as $type )
+ $defaults_atts[$type] = '';
+
+ $atts = shortcode_atts( $defaults_atts, $attr, 'audio' );
+ extract( $atts );
+
+ $primary = false;
+ if ( ! empty( $src ) ) {
+ $type = wp_check_filetype( $src, wp_get_mime_types() );
+ if ( ! in_array( $type['ext'], $default_types ) )
+ return sprintf( '<a class="wp-embedded-audio" href="%s">%s</a>', esc_url( $src ), esc_html( $src ) );
+ $primary = true;
+ array_unshift( $default_types, 'src' );
+ } else {
+ foreach ( $default_types as $ext ) {
+ if ( ! empty( $$ext ) ) {
+ $type = wp_check_filetype( $$ext, wp_get_mime_types() );
+ if ( $type['ext'] === $ext )
+ $primary = true;
+ }
+ }
+ }
+
+ if ( ! $primary ) {
+ $audios = get_attached_media( 'audio', $post_id );
+ if ( empty( $audios ) )
+ return;
+
+ $audio = reset( $audios );
+ $src = wp_get_attachment_url( $audio->ID );
+ if ( empty( $src ) )
+ return;
+
+ array_unshift( $default_types, 'src' );
+ }
+
+ $library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
+ if ( 'mediaelement' === $library && did_action( 'init' ) ) {
+ wp_enqueue_style( 'wp-mediaelement' );
+ wp_enqueue_script( 'wp-mediaelement' );
+ }
+
+ $atts = array(
+ 'class' => apply_filters( 'wp_audio_shortcode_class', 'wp-audio-shortcode' ),
+ 'id' => sprintf( 'audio-%d-%d', $post_id, $instances ),
+ 'loop' => $loop,
+ 'autoplay' => $autoplay,
+ 'preload' => $preload,
+ 'style' => 'width: 100%',
+ );
+
+ // These ones should just be omitted altogether if they are blank
+ foreach ( array( 'loop', 'autoplay', 'preload' ) as $a ) {
+ if ( empty( $atts[$a] ) )
+ unset( $atts[$a] );
+ }
+
+ $attr_strings = array();
+ foreach ( $atts as $k => $v ) {
+ $attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
+ }
+
+ $html = '';
+ if ( 'mediaelement' === $library && 1 === $instances )
+ $html .= "<!--[if lt IE 9]><script>document.createElement('audio');</script><![endif]-->\n";
+ $html .= sprintf( '<audio %s controls="controls">', join( ' ', $attr_strings ) );
+
+ $fileurl = '';
+ $source = '<source type="%s" src="%s" />';
+ foreach ( $default_types as $fallback ) {
+ if ( ! empty( $$fallback ) ) {
+ if ( empty( $fileurl ) )
+ $fileurl = $$fallback;
+ $type = wp_check_filetype( $$fallback, wp_get_mime_types() );
+ $html .= sprintf( $source, $type['type'], esc_url( $$fallback ) );
+ }
+ }
+
+ if ( 'mediaelement' === $library )
+ $html .= wp_mediaelement_fallback( $fileurl );
+ $html .= '</audio>';
+
+ return apply_filters( 'wp_audio_shortcode', $html, $atts, $audio, $post_id, $library );
+}
+add_shortcode( 'audio', apply_filters( 'wp_audio_shortcode_handler', 'wp_audio_shortcode' ) );
+
+/**
+ * Return a filtered list of WP-supported video formats
+ *
+ * @since 3.6.0
+ * @return array
+ */
+function wp_get_video_extensions() {
+ return apply_filters( 'wp_video_extensions', array( 'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv' ) );
+}
+
+/**
+ * The Video shortcode.
+ *
+ * This implements the functionality of the Video Shortcode for displaying
+ * WordPress mp4s in a post.
+ *
+ * @since 3.6.0
+ *
+ * @param array $attr Attributes of the shortcode.
+ * @return string HTML content to display video.
+ */
+function wp_video_shortcode( $attr ) {
+ global $content_width;
+ $post_id = get_post() ? get_the_ID() : 0;
+
+ static $instances = 0;
+ $instances++;
+
+ $video = null;
+
+ $default_types = wp_get_video_extensions();
+ $defaults_atts = array(
+ 'src' => '',
+ 'poster' => '',
+ 'loop' => '',
+ 'autoplay' => '',
+ 'preload' => 'metadata',
+ 'height' => 360,
+ 'width' => empty( $content_width ) ? 640 : $content_width,
+ );
+
+ foreach ( $default_types as $type )
+ $defaults_atts[$type] = '';
+
+ $atts = shortcode_atts( $defaults_atts, $attr, 'video' );
+ extract( $atts );
+
+ $w = $width;
+ $h = $height;
+ if ( is_admin() && $width > 600 )
+ $w = 600;
+ elseif ( ! is_admin() && $w > $defaults_atts['width'] )
+ $w = $defaults_atts['width'];
+
+ if ( $w < $width )
+ $height = round( ( $h * $w ) / $width );
+
+ $width = $w;
+
+ $primary = false;
+ if ( ! empty( $src ) ) {
+ $type = wp_check_filetype( $src, wp_get_mime_types() );
+ if ( ! in_array( $type['ext'], $default_types ) )
+ return sprintf( '<a class="wp-embedded-video" href="%s">%s</a>', esc_url( $src ), esc_html( $src ) );
+ $primary = true;
+ array_unshift( $default_types, 'src' );
+ } else {
+ foreach ( $default_types as $ext ) {
+ if ( ! empty( $$ext ) ) {
+ $type = wp_check_filetype( $$ext, wp_get_mime_types() );
+ if ( $type['ext'] === $ext )
+ $primary = true;
+ }
+ }
+ }
+
+ if ( ! $primary ) {
+ $videos = get_attached_media( 'video', $post_id );
+ if ( empty( $videos ) )
+ return;
+
+ $video = reset( $videos );
+ $src = wp_get_attachment_url( $video->ID );
+ if ( empty( $src ) )
+ return;
+
+ array_unshift( $default_types, 'src' );
+ }
+
+ $library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
+ if ( 'mediaelement' === $library && did_action( 'init' ) ) {
+ wp_enqueue_style( 'wp-mediaelement' );
+ wp_enqueue_script( 'wp-mediaelement' );
+ }
+
+ $atts = array(
+ 'class' => apply_filters( 'wp_video_shortcode_class', 'wp-video-shortcode' ),
+ 'id' => sprintf( 'video-%d-%d', $post_id, $instances ),
+ 'width' => absint( $width ),
+ 'height' => absint( $height ),
+ 'poster' => esc_url( $poster ),
+ 'loop' => $loop,
+ 'autoplay' => $autoplay,
+ 'preload' => $preload,
+ );
+
+ // These ones should just be omitted altogether if they are blank
+ foreach ( array( 'poster', 'loop', 'autoplay', 'preload' ) as $a ) {
+ if ( empty( $atts[$a] ) )
+ unset( $atts[$a] );
+ }
+
+ $attr_strings = array();
+ foreach ( $atts as $k => $v ) {
+ $attr_strings[] = $k . '="' . esc_attr( $v ) . '"';
+ }
+
+ $html = '';
+ if ( 'mediaelement' === $library && 1 === $instances )
+ $html .= "<!--[if lt IE 9]><script>document.createElement('video');</script><![endif]-->\n";
+ $html .= sprintf( '<video %s controls="controls">', join( ' ', $attr_strings ) );
+
+ $fileurl = '';
+ $source = '<source type="%s" src="%s" />';
+ foreach ( $default_types as $fallback ) {
+ if ( ! empty( $$fallback ) ) {
+ if ( empty( $fileurl ) )
+ $fileurl = $$fallback;
+ $type = wp_check_filetype( $$fallback, wp_get_mime_types() );
+ // m4v sometimes shows up as video/mpeg which collides with mp4
+ if ( 'm4v' === $type['ext'] )
+ $type['type'] = 'video/m4v';
+ $html .= sprintf( $source, $type['type'], esc_url( $$fallback ) );
+ }
+ }
+ if ( 'mediaelement' === $library )
+ $html .= wp_mediaelement_fallback( $fileurl );
+ $html .= '</video>';
+
+ $html = sprintf( '<div style="width: %dpx; max-width: 100%%;">%s</div>', $width, $html );
+ return apply_filters( 'wp_video_shortcode', $html, $atts, $video, $post_id, $library );
+}
+add_shortcode( 'video', apply_filters( 'wp_video_shortcode_handler', 'wp_video_shortcode' ) );
+
+/**
+ * Display previous image link that has the same post parent.
+ *
+ * @since 2.5.0
+ * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string. 0 or 'none' will default to post_title or $text;
+ * @param string $text Optional, default is false. If included, link will reflect $text variable.
+ * @return string HTML content.
+ */
+function previous_image_link($size = 'thumbnail', $text = false) {
+ adjacent_image_link(true, $size, $text);
+}
+
+/**
+ * Display next image link that has the same post parent.
+ *
+ * @since 2.5.0
+ * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string. 0 or 'none' will default to post_title or $text;
+ * @param string $text Optional, default is false. If included, link will reflect $text variable.
+ * @return string HTML content.
+ */
+function next_image_link($size = 'thumbnail', $text = false) {
+ adjacent_image_link(false, $size, $text);
+}
+
+/**
+ * Display next or previous image link that has the same post parent.
+ *
+ * Retrieves the current attachment object from the $post global.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $prev Optional. Default is true to display previous link, false for next.
+ */
+function adjacent_image_link($prev = true, $size = 'thumbnail', $text = false) {
+ $post = get_post();
+ $attachments = array_values( get_children( array( 'post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID' ) ) );
+
+ foreach ( $attachments as $k => $attachment )
+ if ( $attachment->ID == $post->ID )
+ break;
+
+ $k = $prev ? $k - 1 : $k + 1;
+
+ $output = $attachment_id = null;
+ if ( isset( $attachments[ $k ] ) ) {
+ $attachment_id = $attachments[ $k ]->ID;
+ $output = wp_get_attachment_link( $attachment_id, $size, true, false, $text );
+ }
+
+ $adjacent = $prev ? 'previous' : 'next';
+ echo apply_filters( "{$adjacent}_image_link", $output, $attachment_id, $size, $text );
+}
+
+/**
+ * Retrieve taxonomies attached to the attachment.
+ *
+ * @since 2.5.0
+ *
+ * @param int|array|object $attachment Attachment ID, Attachment data array, or Attachment data object.
+ * @return array Empty array on failure. List of taxonomies on success.
+ */
+function get_attachment_taxonomies($attachment) {
+ if ( is_int( $attachment ) )
+ $attachment = get_post($attachment);
+ else if ( is_array($attachment) )
+ $attachment = (object) $attachment;
+
+ if ( ! is_object($attachment) )
+ return array();
+
+ $filename = basename($attachment->guid);
+
+ $objects = array('attachment');
+
+ if ( false !== strpos($filename, '.') )
+ $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
+ if ( !empty($attachment->post_mime_type) ) {
+ $objects[] = 'attachment:' . $attachment->post_mime_type;
+ if ( false !== strpos($attachment->post_mime_type, '/') )
+ foreach ( explode('/', $attachment->post_mime_type) as $token )
+ if ( !empty($token) )
+ $objects[] = "attachment:$token";
+ }
+
+ $taxonomies = array();
+ foreach ( $objects as $object )
+ if ( $taxes = get_object_taxonomies($object) )
+ $taxonomies = array_merge($taxonomies, $taxes);
+
+ return array_unique($taxonomies);
+}
+
+/**
+ * Return all of the taxonomy names that are registered for attachments.
+ *
+ * Handles mime-type-specific taxonomies such as attachment:image and attachment:video.
+ *
+ * @since 3.5.0
+ * @see get_attachment_taxonomies()
+ * @uses get_taxonomies()
+ *
+ * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
+ * @return array The names of all taxonomy of $object_type.
+ */
+function get_taxonomies_for_attachments( $output = 'names' ) {
+ $taxonomies = array();
+ foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy ) {
+ foreach ( $taxonomy->object_type as $object_type ) {
+ if ( 'attachment' == $object_type || 0 === strpos( $object_type, 'attachment:' ) ) {
+ if ( 'names' == $output )
+ $taxonomies[] = $taxonomy->name;
+ else
+ $taxonomies[ $taxonomy->name ] = $taxonomy;
+ break;
+ }
+ }
+ }
+
+ return $taxonomies;
+}
+
+/**
+ * Create new GD image resource with transparency support
+ * @TODO: Deprecate if possible.
+ *
+ * @since 2.9.0
+ *
+ * @param int $width Image width
+ * @param int $height Image height
+ * @return image resource
+ */
+function wp_imagecreatetruecolor($width, $height) {
+ $img = imagecreatetruecolor($width, $height);
+ if ( is_resource($img) && function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
+ imagealphablending($img, false);
+ imagesavealpha($img, true);
+ }
+ return $img;
+}
+
+/**
+ * Register an embed handler. This function should probably only be used for sites that do not support oEmbed.
+ *
+ * @since 2.9.0
+ * @see WP_Embed::register_handler()
+ */
+function wp_embed_register_handler( $id, $regex, $callback, $priority = 10 ) {
+ global $wp_embed;
+ $wp_embed->register_handler( $id, $regex, $callback, $priority );
+}
+
+/**
+ * Unregister a previously registered embed handler.
+ *
+ * @since 2.9.0
+ * @see WP_Embed::unregister_handler()
+ */
+function wp_embed_unregister_handler( $id, $priority = 10 ) {
+ global $wp_embed;
+ $wp_embed->unregister_handler( $id, $priority );
+}
+
+/**
+ * Create default array of embed parameters.
+ *
+ * The width defaults to the content width as specified by the theme. If the
+ * theme does not specify a content width, then 500px is used.
+ *
+ * The default height is 1.5 times the width, or 1000px, whichever is smaller.
+ *
+ * The 'embed_defaults' filter can be used to adjust either of these values.
+ *
+ * @since 2.9.0
+ *
+ * @return array Default embed parameters.
+ */
+function wp_embed_defaults() {
+ if ( ! empty( $GLOBALS['content_width'] ) )
+ $width = (int) $GLOBALS['content_width'];
+
+ if ( empty( $width ) )
+ $width = 500;
+
+ $height = min( ceil( $width * 1.5 ), 1000 );
+
+ return apply_filters( 'embed_defaults', compact( 'width', 'height' ) );
+}
+
+/**
+ * Based on a supplied width/height example, return the biggest possible dimensions based on the max width/height.
+ *
+ * @since 2.9.0
+ * @uses wp_constrain_dimensions() This function passes the widths and the heights.
+ *
+ * @param int $example_width The width of an example embed.
+ * @param int $example_height The height of an example embed.
+ * @param int $max_width The maximum allowed width.
+ * @param int $max_height The maximum allowed height.
+ * @return array The maximum possible width and height based on the example ratio.
+ */
+function wp_expand_dimensions( $example_width, $example_height, $max_width, $max_height ) {
+ $example_width = (int) $example_width;
+ $example_height = (int) $example_height;
+ $max_width = (int) $max_width;
+ $max_height = (int) $max_height;
+
+ return wp_constrain_dimensions( $example_width * 1000000, $example_height * 1000000, $max_width, $max_height );
+}
+
+/**
+ * Attempts to fetch the embed HTML for a provided URL using oEmbed.
+ *
+ * @since 2.9.0
+ * @see WP_oEmbed
+ *
+ * @uses _wp_oembed_get_object()
+ * @uses WP_oEmbed::get_html()
+ *
+ * @param string $url The URL that should be embedded.
+ * @param array $args Additional arguments and parameters.
+ * @return bool|string False on failure or the embed HTML on success.
+ */
+function wp_oembed_get( $url, $args = '' ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+ $oembed = _wp_oembed_get_object();
+ return $oembed->get_html( $url, $args );
+}
+
+/**
+ * Adds a URL format and oEmbed provider URL pair.
+ *
+ * @since 2.9.0
+ * @see WP_oEmbed
+ *
+ * @uses _wp_oembed_get_object()
+ *
+ * @param string $format The format of URL that this provider can handle. You can use asterisks as wildcards.
+ * @param string $provider The URL to the oEmbed provider.
+ * @param boolean $regex Whether the $format parameter is in a regex format.
+ */
+function wp_oembed_add_provider( $format, $provider, $regex = false ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+ $oembed = _wp_oembed_get_object();
+ $oembed->providers[$format] = array( $provider, $regex );
+}
+
+/**
+ * Removes an oEmbed provider.
+ *
+ * @since 3.5.0
+ * @see WP_oEmbed
+ *
+ * @uses _wp_oembed_get_object()
+ *
+ * @param string $format The URL format for the oEmbed provider to remove.
+ */
+function wp_oembed_remove_provider( $format ) {
+ require_once( ABSPATH . WPINC . '/class-oembed.php' );
+
+ $oembed = _wp_oembed_get_object();
+
+ if ( isset( $oembed->providers[ $format ] ) ) {
+ unset( $oembed->providers[ $format ] );
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Determines if default embed handlers should be loaded.
+ *
+ * Checks to make sure that the embeds library hasn't already been loaded. If
+ * it hasn't, then it will load the embeds library.
+ *
+ * @since 2.9.0
+ */
+function wp_maybe_load_embeds() {
+ if ( ! apply_filters( 'load_default_embeds', true ) )
+ return;
+ wp_embed_register_handler( 'googlevideo', '#http://video\.google\.([A-Za-z.]{2,5})/videoplay\?docid=([\d-]+)(.*?)#i', 'wp_embed_handler_googlevideo' );
+ wp_embed_register_handler( 'audio', '#^https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')$#i', apply_filters( 'wp_audio_embed_handler', 'wp_embed_handler_audio' ), 9999 );
+ wp_embed_register_handler( 'video', '#^https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')$#i', apply_filters( 'wp_video_embed_handler', 'wp_embed_handler_video' ), 9999 );
+}
+
+/**
+ * The Google Video embed handler callback. Google Video does not support oEmbed.
+ *
+ * @see WP_Embed::register_handler()
+ * @see WP_Embed::shortcode()
+ *
+ * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_googlevideo( $matches, $attr, $url, $rawattr ) {
+ // If the user supplied a fixed width AND height, use it
+ if ( !empty($rawattr['width']) && !empty($rawattr['height']) ) {
+ $width = (int) $rawattr['width'];
+ $height = (int) $rawattr['height'];
+ } else {
+ list( $width, $height ) = wp_expand_dimensions( 425, 344, $attr['width'], $attr['height'] );
+ }
+
+ return apply_filters( 'embed_googlevideo', '<embed type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docid=' . esc_attr($matches[2]) . '&amp;hl=en&amp;fs=true" style="width:' . esc_attr($width) . 'px;height:' . esc_attr($height) . 'px" allowFullScreen="true" allowScriptAccess="always" />', $matches, $attr, $url, $rawattr );
+}
+
+/**
+ * Audio embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_audio( $matches, $attr, $url, $rawattr ) {
+ $audio = sprintf( '[audio src="%s" /]', esc_url( $url ) );
+ return apply_filters( 'wp_embed_handler_audio', $audio, $attr, $url, $rawattr );
+}
+
+/**
+ * Video embed handler callback.
+ *
+ * @since 3.6.0
+ *
+ * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
+ * @param array $attr Embed attributes.
+ * @param string $url The original URL that was matched by the regex.
+ * @param array $rawattr The original unmodified attributes.
+ * @return string The embed HTML.
+ */
+function wp_embed_handler_video( $matches, $attr, $url, $rawattr ) {
+ $dimensions = '';
+ if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
+ $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
+ $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
+ }
+ $video = sprintf( '[video %s src="%s" /]', $dimensions, esc_url( $url ) );
+ return apply_filters( 'wp_embed_handler_video', $video, $attr, $url, $rawattr );
+}
+
+/**
+ * Converts a shorthand byte value to an integer byte value.
+ *
+ * @since 2.3.0
+ *
+ * @param string $size A shorthand byte value.
+ * @return int An integer byte value.
+ */
+function wp_convert_hr_to_bytes( $size ) {
+ $size = strtolower( $size );
+ $bytes = (int) $size;
+ if ( strpos( $size, 'k' ) !== false )
+ $bytes = intval( $size ) * 1024;
+ elseif ( strpos( $size, 'm' ) !== false )
+ $bytes = intval($size) * 1024 * 1024;
+ elseif ( strpos( $size, 'g' ) !== false )
+ $bytes = intval( $size ) * 1024 * 1024 * 1024;
+ return $bytes;
+}
+
+/**
+ * Determine the maximum upload size allowed in php.ini.
+ *
+ * @since 2.5.0
+ *
+ * @return int Allowed upload size.
+ */
+function wp_max_upload_size() {
+ $u_bytes = wp_convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
+ $p_bytes = wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) );
+ $bytes = apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
+ return $bytes;
+}
+
+/**
+ * Returns a WP_Image_Editor instance and loads file into it.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $path Path to file to load
+ * @param array $args Additional data. Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
+ * @return WP_Image_Editor|WP_Error
+ */
+function wp_get_image_editor( $path, $args = array() ) {
+ $args['path'] = $path;
+
+ if ( ! isset( $args['mime_type'] ) ) {
+ $file_info = wp_check_filetype( $args['path'] );
+
+ // If $file_info['type'] is false, then we let the editor attempt to
+ // figure out the file type, rather than forcing a failure based on extension.
+ if ( isset( $file_info ) && $file_info['type'] )
+ $args['mime_type'] = $file_info['type'];
+ }
+
+ $implementation = _wp_image_editor_choose( $args );
+
+ if ( $implementation ) {
+ $editor = new $implementation( $path );
+ $loaded = $editor->load();
+
+ if ( is_wp_error( $loaded ) )
+ return $loaded;
+
+ return $editor;
+ }
+
+ return new WP_Error( 'image_no_editor', __('No editor could be selected.') );
+}
+
+/**
+ * Tests whether there is an editor that supports a given mime type or methods.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string|array $args Array of requirements. Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
+ * @return boolean true if an eligible editor is found; false otherwise
+ */
+function wp_image_editor_supports( $args = array() ) {
+ return (bool) _wp_image_editor_choose( $args );
+}
+
+/**
+ * Tests which editors are capable of supporting the request.
+ *
+ * @since 3.5.0
+ * @access private
+ *
+ * @param array $args Additional data. Accepts { 'mime_type'=>string, 'methods'=>{string, string, ...} }
+ * @return string|bool Class name for the first editor that claims to support the request. False if no editor claims to support the request.
+ */
+function _wp_image_editor_choose( $args = array() ) {
+ require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
+ require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
+ require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
+
+ $implementations = apply_filters( 'wp_image_editors',
+ array( 'WP_Image_Editor_Imagick', 'WP_Image_Editor_GD' ) );
+
+ foreach ( $implementations as $implementation ) {
+ if ( ! call_user_func( array( $implementation, 'test' ), $args ) )
+ continue;
+
+ if ( isset( $args['mime_type'] ) &&
+ ! call_user_func(
+ array( $implementation, 'supports_mime_type' ),
+ $args['mime_type'] ) ) {
+ continue;
+ }
+
+ if ( isset( $args['methods'] ) &&
+ array_diff( $args['methods'], get_class_methods( $implementation ) ) ) {
+ continue;
+ }
+
+ return $implementation;
+ }
+
+ return false;
+}
+
+/**
+ * Prints default plupload arguments.
+ *
+ * @since 3.4.0
+ */
+function wp_plupload_default_settings() {
+ global $wp_scripts;
+
+ $data = $wp_scripts->get_data( 'wp-plupload', 'data' );
+ if ( $data && false !== strpos( $data, '_wpPluploadSettings' ) )
+ return;
+
+ $max_upload_size = wp_max_upload_size();
+
+ $defaults = array(
+ 'runtimes' => 'html5,silverlight,flash,html4',
+ 'file_data_name' => 'async-upload', // key passed to $_FILE.
+ 'multiple_queues' => true,
+ 'max_file_size' => $max_upload_size . 'b',
+ 'url' => admin_url( 'async-upload.php', 'relative' ),
+ 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
+ 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
+ 'filters' => array( array( 'title' => __( 'Allowed Files' ), 'extensions' => '*') ),
+ 'multipart' => true,
+ 'urlstream_upload' => true,
+ );
+
+ // Multi-file uploading doesn't currently work in iOS Safari,
+ // single-file allows the built-in camera to be used as source for images
+ if ( wp_is_mobile() )
+ $defaults['multi_selection'] = false;
+
+ $defaults = apply_filters( 'plupload_default_settings', $defaults );
+
+ $params = array(
+ 'action' => 'upload-attachment',
+ );
+
+ $params = apply_filters( 'plupload_default_params', $params );
+ $params['_wpnonce'] = wp_create_nonce( 'media-form' );
+ $defaults['multipart_params'] = $params;
+
+ $settings = array(
+ 'defaults' => $defaults,
+ 'browser' => array(
+ 'mobile' => wp_is_mobile(),
+ 'supported' => _device_can_upload(),
+ ),
+ 'limitExceeded' => is_multisite() && ! is_upload_space_available()
+ );
+
+ $script = 'var _wpPluploadSettings = ' . json_encode( $settings ) . ';';
+
+ if ( $data )
+ $script = "$data\n$script";
+
+ $wp_scripts->add_data( 'wp-plupload', 'data', $script );
+}
+add_action( 'customize_controls_enqueue_scripts', 'wp_plupload_default_settings' );
+
+/**
+ * Prepares an attachment post object for JS, where it is expected
+ * to be JSON-encoded and fit into an Attachment model.
+ *
+ * @since 3.5.0
+ *
+ * @param mixed $attachment Attachment ID or object.
+ * @return array Array of attachment details.
+ */
+function wp_prepare_attachment_for_js( $attachment ) {
+ if ( ! $attachment = get_post( $attachment ) )
+ return;
+
+ if ( 'attachment' != $attachment->post_type )
+ return;
+
+ $meta = wp_get_attachment_metadata( $attachment->ID );
+ if ( false !== strpos( $attachment->post_mime_type, '/' ) )
+ list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
+ else
+ list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
+
+ $attachment_url = wp_get_attachment_url( $attachment->ID );
+
+ $response = array(
+ 'id' => $attachment->ID,
+ 'title' => $attachment->post_title,
+ 'filename' => wp_basename( $attachment->guid ),
+ 'url' => $attachment_url,
+ 'link' => get_attachment_link( $attachment->ID ),
+ 'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
+ 'author' => $attachment->post_author,
+ 'description' => $attachment->post_content,
+ 'caption' => $attachment->post_excerpt,
+ 'name' => $attachment->post_name,
+ 'status' => $attachment->post_status,
+ 'uploadedTo' => $attachment->post_parent,
+ 'date' => strtotime( $attachment->post_date_gmt ) * 1000,
+ 'modified' => strtotime( $attachment->post_modified_gmt ) * 1000,
+ 'menuOrder' => $attachment->menu_order,
+ 'mime' => $attachment->post_mime_type,
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'icon' => wp_mime_type_icon( $attachment->ID ),
+ 'dateFormatted' => mysql2date( get_option('date_format'), $attachment->post_date ),
+ 'nonces' => array(
+ 'update' => false,
+ 'delete' => false,
+ ),
+ 'editLink' => false,
+ );
+
+ if ( current_user_can( 'edit_post', $attachment->ID ) ) {
+ $response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID );
+ $response['editLink'] = get_edit_post_link( $attachment->ID, 'raw' );
+ }
+
+ if ( current_user_can( 'delete_post', $attachment->ID ) )
+ $response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID );
+
+ if ( $meta && 'image' === $type ) {
+ $sizes = array();
+ $possible_sizes = apply_filters( 'image_size_names_choose', array(
+ 'thumbnail' => __('Thumbnail'),
+ 'medium' => __('Medium'),
+ 'large' => __('Large'),
+ 'full' => __('Full Size'),
+ ) );
+ unset( $possible_sizes['full'] );
+
+ // Loop through all potential sizes that may be chosen. Try to do this with some efficiency.
+ // First: run the image_downsize filter. If it returns something, we can use its data.
+ // If the filter does not return something, then image_downsize() is just an expensive
+ // way to check the image metadata, which we do second.
+ foreach ( $possible_sizes as $size => $label ) {
+ if ( $downsize = apply_filters( 'image_downsize', false, $attachment->ID, $size ) ) {
+ if ( ! $downsize[3] )
+ continue;
+ $sizes[ $size ] = array(
+ 'height' => $downsize[2],
+ 'width' => $downsize[1],
+ 'url' => $downsize[0],
+ 'orientation' => $downsize[2] > $downsize[1] ? 'portrait' : 'landscape',
+ );
+ } elseif ( isset( $meta['sizes'][ $size ] ) ) {
+ if ( ! isset( $base_url ) )
+ $base_url = str_replace( wp_basename( $attachment_url ), '', $attachment_url );
+
+ // Nothing from the filter, so consult image metadata if we have it.
+ $size_meta = $meta['sizes'][ $size ];
+
+ // We have the actual image size, but might need to further constrain it if content_width is narrower.
+ // Thumbnail, medium, and full sizes are also checked against the site's height/width options.
+ list( $width, $height ) = image_constrain_size_for_editor( $size_meta['width'], $size_meta['height'], $size, 'edit' );
+
+ $sizes[ $size ] = array(
+ 'height' => $height,
+ 'width' => $width,
+ 'url' => $base_url . $size_meta['file'],
+ 'orientation' => $height > $width ? 'portrait' : 'landscape',
+ );
+ }
+ }
+
+ $sizes['full'] = array( 'url' => $attachment_url );
+
+ if ( isset( $meta['height'], $meta['width'] ) ) {
+ $sizes['full']['height'] = $meta['height'];
+ $sizes['full']['width'] = $meta['width'];
+ $sizes['full']['orientation'] = $meta['height'] > $meta['width'] ? 'portrait' : 'landscape';
+ }
+
+ $response = array_merge( $response, array( 'sizes' => $sizes ), $sizes['full'] );
+ } elseif ( $meta && 'video' === $type ) {
+ if ( isset( $meta['width'] ) )
+ $response['width'] = (int) $meta['width'];
+ if ( isset( $meta['height'] ) )
+ $response['height'] = (int) $meta['height'];
+ }
+
+ if ( $meta && ( 'audio' === $type || 'video' === $type ) ) {
+ if ( isset( $meta['length_formatted'] ) )
+ $response['fileLength'] = $meta['length_formatted'];
+ }
+
+ if ( function_exists('get_compat_media_markup') )
+ $response['compat'] = get_compat_media_markup( $attachment->ID, array( 'in_modal' => true ) );
+
+ return apply_filters( 'wp_prepare_attachment_for_js', $response, $attachment, $meta );
+}
+
+/**
+ * Enqueues all scripts, styles, settings, and templates necessary to use
+ * all media JS APIs.
+ *
+ * @since 3.5.0
+ */
+function wp_enqueue_media( $args = array() ) {
+
+ // Enqueue me just once per page, please.
+ if ( did_action( 'wp_enqueue_media' ) )
+ return;
+
+ $defaults = array(
+ 'post' => null,
+ );
+ $args = wp_parse_args( $args, $defaults );
+
+ // We're going to pass the old thickbox media tabs to `media_upload_tabs`
+ // to ensure plugins will work. We will then unset those tabs.
+ $tabs = array(
+ // handler action suffix => tab label
+ 'type' => '',
+ 'type_url' => '',
+ 'gallery' => '',
+ 'library' => '',
+ );
+
+ $tabs = apply_filters( 'media_upload_tabs', $tabs );
+ unset( $tabs['type'], $tabs['type_url'], $tabs['gallery'], $tabs['library'] );
+
+ $props = array(
+ 'link' => get_option( 'image_default_link_type' ), // db default is 'file'
+ 'align' => get_option( 'image_default_align' ), // empty default
+ 'size' => get_option( 'image_default_size' ), // empty default
+ );
+
+ $settings = array(
+ 'tabs' => $tabs,
+ 'tabUrl' => add_query_arg( array( 'chromeless' => true ), admin_url('media-upload.php') ),
+ 'mimeTypes' => wp_list_pluck( get_post_mime_types(), 0 ),
+ 'captions' => ! apply_filters( 'disable_captions', '' ),
+ 'nonce' => array(
+ 'sendToEditor' => wp_create_nonce( 'media-send-to-editor' ),
+ ),
+ 'post' => array(
+ 'id' => 0,
+ ),
+ 'defaultProps' => $props,
+ 'embedExts' => array_merge( wp_get_audio_extensions(), wp_get_video_extensions() ),
+ );
+
+ $post = null;
+ if ( isset( $args['post'] ) ) {
+ $post = get_post( $args['post'] );
+ $settings['post'] = array(
+ 'id' => $post->ID,
+ 'nonce' => wp_create_nonce( 'update-post_' . $post->ID ),
+ );
+
+ if ( current_theme_supports( 'post-thumbnails', $post->post_type ) && post_type_supports( $post->post_type, 'thumbnail' ) ) {
+ $featured_image_id = get_post_meta( $post->ID, '_thumbnail_id', true );
+ $settings['post']['featuredImageId'] = $featured_image_id ? $featured_image_id : -1;
+ }
+ }
+
+ $hier = $post && is_post_type_hierarchical( $post->post_type );
+
+ $strings = array(
+ // Generic
+ 'url' => __( 'URL' ),
+ 'addMedia' => __( 'Add Media' ),
+ 'search' => __( 'Search' ),
+ 'select' => __( 'Select' ),
+ 'cancel' => __( 'Cancel' ),
+ /* translators: This is a would-be plural string used in the media manager.
+ If there is not a word you can use in your language to avoid issues with the
+ lack of plural support here, turn it into "selected: %d" then translate it.
+ */
+ 'selected' => __( '%d selected' ),
+ 'dragInfo' => __( 'Drag and drop to reorder images.' ),
+
+ // Upload
+ 'uploadFilesTitle' => __( 'Upload Files' ),
+ 'uploadImagesTitle' => __( 'Upload Images' ),
+
+ // Library
+ 'mediaLibraryTitle' => __( 'Media Library' ),
+ 'insertMediaTitle' => __( 'Insert Media' ),
+ 'createNewGallery' => __( 'Create a new gallery' ),
+ 'returnToLibrary' => __( '&#8592; Return to library' ),
+ 'allMediaItems' => __( 'All media items' ),
+ 'noItemsFound' => __( 'No items found.' ),
+ 'insertIntoPost' => $hier ? __( 'Insert into page' ) : __( 'Insert into post' ),
+ 'uploadedToThisPost' => $hier ? __( 'Uploaded to this page' ) : __( 'Uploaded to this post' ),
+ 'warnDelete' => __( "You are about to permanently delete this item.\n 'Cancel' to stop, 'OK' to delete." ),
+
+ // From URL
+ 'insertFromUrlTitle' => __( 'Insert from URL' ),
+
+ // Featured Images
+ 'setFeaturedImageTitle' => __( 'Set Featured Image' ),
+ 'setFeaturedImage' => __( 'Set featured image' ),
+
+ // Gallery
+ 'createGalleryTitle' => __( 'Create Gallery' ),
+ 'editGalleryTitle' => __( 'Edit Gallery' ),
+ 'cancelGalleryTitle' => __( '&#8592; Cancel Gallery' ),
+ 'insertGallery' => __( 'Insert gallery' ),
+ 'updateGallery' => __( 'Update gallery' ),
+ 'addToGallery' => __( 'Add to gallery' ),
+ 'addToGalleryTitle' => __( 'Add to Gallery' ),
+ 'reverseOrder' => __( 'Reverse order' ),
+ );
+
+ $settings = apply_filters( 'media_view_settings', $settings, $post );
+ $strings = apply_filters( 'media_view_strings', $strings, $post );
+
+ $strings['settings'] = $settings;
+
+ wp_localize_script( 'media-views', '_wpMediaViewsL10n', $strings );
+
+ wp_enqueue_script( 'media-editor' );
+ wp_enqueue_style( 'media-views' );
+ wp_plupload_default_settings();
+
+ require_once ABSPATH . WPINC . '/media-template.php';
+ add_action( 'admin_footer', 'wp_print_media_templates' );
+ add_action( 'wp_footer', 'wp_print_media_templates' );
+
+ do_action( 'wp_enqueue_media' );
+}
+
+/**
+ * Retrieve media attached to the passed post
+ *
+ * @since 3.6.0
+ *
+ * @param string $type (Mime) type of media desired
+ * @param mixed $post Post ID or object
+ * @return array Found attachments
+ */
+function get_attached_media( $type, $post = 0 ) {
+ if ( ! $post = get_post( $post ) )
+ return array();
+
+ $args = array(
+ 'post_parent' => $post->ID,
+ 'post_type' => 'attachment',
+ 'post_mime_type' => $type,
+ 'posts_per_page' => -1,
+ 'orderby' => 'menu_order',
+ 'order' => 'ASC',
+ );
+
+ $args = apply_filters( 'get_attached_media_args', $args, $type, $post );
+
+ $children = get_children( $args );
+
+ return (array) apply_filters( 'get_attached_media', $children, $type, $post );
+}
+
+/**
+ * Check the content blob for an <audio>, <video> <object>, <embed>, or <iframe>
+ *
+ * @since 3.6.0
+ *
+ * @param string $content A string which might contain media data.
+ * @param array $types array of media types: 'audio', 'video', 'object', 'embed', or 'iframe'
+ * @return array A list of found HTML media embeds
+ */
+function get_media_embedded_in_content( $content, $types = null ) {
+ $html = array();
+ $allowed_media_types = array( 'audio', 'video', 'object', 'embed', 'iframe' );
+ if ( ! empty( $types ) ) {
+ if ( ! is_array( $types ) )
+ $types = array( $types );
+ $allowed_media_types = array_intersect( $allowed_media_types, $types );
+ }
+
+ foreach ( $allowed_media_types as $tag ) {
+ if ( preg_match( '#' . get_tag_regex( $tag ) . '#', $content, $matches ) ) {
+ $html[] = $matches[0];
+ }
+ }
+
+ return $html;
+}
+
+/**
+ * Retrieve galleries from the passed post's content
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @param boolean $html Whether to return HTML or data in the array
+ * @return array A list of arrays, each containing gallery data and srcs parsed
+ * from the expanded shortcode
+ */
+function get_post_galleries( $post, $html = true ) {
+ if ( ! $post = get_post( $post ) )
+ return array();
+
+ if ( ! has_shortcode( $post->post_content, 'gallery' ) )
+ return array();
+
+ $galleries = array();
+ if ( preg_match_all( '/' . get_shortcode_regex() . '/s', $post->post_content, $matches, PREG_SET_ORDER ) ) {
+ foreach ( $matches as $shortcode ) {
+ if ( 'gallery' === $shortcode[2] ) {
+ $srcs = array();
+ $count = 1;
+
+ $gallery = do_shortcode_tag( $shortcode );
+ if ( $html ) {
+ $galleries[] = $gallery;
+ } else {
+ preg_match_all( '#src=([\'"])(.+?)\1#is', $gallery, $src, PREG_SET_ORDER );
+ if ( ! empty( $src ) ) {
+ foreach ( $src as $s )
+ $srcs[] = $s[2];
+ }
+
+ $data = shortcode_parse_atts( $shortcode[3] );
+ $data['src'] = array_values( array_unique( $srcs ) );
+ $galleries[] = $data;
+ }
+ }
+ }
+ }
+
+ return apply_filters( 'get_post_galleries', $galleries, $post );
+}
+
+/**
+ * Check a specified post's content for gallery and, if present, return the first
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @param boolean $html Whether to return HTML or data
+ * @return string|array Gallery data and srcs parsed from the expanded shortcode
+ */
+function get_post_gallery( $post = 0, $html = true ) {
+ $galleries = get_post_galleries( $post, $html );
+ $gallery = reset( $galleries );
+
+ return apply_filters( 'get_post_gallery', $gallery, $post, $galleries );
+}
+
+/**
+ * Retrieve the image srcs from galleries from a post's content, if present
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @return array A list of lists, each containing image srcs parsed
+ * from an expanded shortcode
+ */
+function get_post_galleries_images( $post = 0 ) {
+ $galleries = get_post_galleries( $post, false );
+ return wp_list_pluck( $galleries, 'src' );
+}
+
+/**
+ * Check a post's content for galleries and return the image srcs for the first found gallery
+ *
+ * @since 3.6.0
+ *
+ * @param mixed $post Optional. Post ID or object.
+ * @return array A list of a gallery's image srcs in order
+ */
+function get_post_gallery_images( $post = 0 ) {
+ $gallery = get_post_gallery( $post, false );
+ return empty( $gallery['src'] ) ? array() : $gallery['src'];
+}
diff --git a/src/wp-includes/meta.php b/src/wp-includes/meta.php
new file mode 100644
index 0000000000..22b03157ae
--- /dev/null
+++ b/src/wp-includes/meta.php
@@ -0,0 +1,914 @@
+<?php
+/**
+ * Metadata API
+ *
+ * Functions for retrieving and manipulating metadata of various WordPress object types. Metadata
+ * for an object is a represented by a simple key-value pair. Objects may contain multiple
+ * metadata entries that share the same key and differ only in their value.
+ *
+ * @package WordPress
+ * @subpackage Meta
+ * @since 2.9.0
+ */
+
+/**
+ * Add metadata for the specified object.
+ *
+ * @since 2.9.0
+ * @uses $wpdb WordPress database object for queries.
+ * @uses do_action() Calls 'added_{$meta_type}_meta' with meta_id of added metadata entry,
+ * object ID, meta key, and meta value
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $object_id ID of the object metadata is for
+ * @param string $meta_key Metadata key
+ * @param string $meta_value Metadata value
+ * @param bool $unique Optional, default is false. Whether the specified metadata key should be
+ * unique for the object. If true, and the object already has a value for the specified
+ * metadata key, no change will be made
+ * @return int|bool The meta ID on successful update, false on failure.
+ */
+function add_metadata($meta_type, $object_id, $meta_key, $meta_value, $unique = false) {
+ if ( !$meta_type || !$meta_key )
+ return false;
+
+ if ( !$object_id = absint($object_id) )
+ return false;
+
+ if ( ! $table = _get_meta_table($meta_type) )
+ return false;
+
+ global $wpdb;
+
+ $column = sanitize_key($meta_type . '_id');
+
+ // expected_slashed ($meta_key)
+ $meta_key = wp_unslash($meta_key);
+ $meta_value = wp_unslash($meta_value);
+ $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
+
+ $check = apply_filters( "add_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $unique );
+ if ( null !== $check )
+ return $check;
+
+ if ( $unique && $wpdb->get_var( $wpdb->prepare(
+ "SELECT COUNT(*) FROM $table WHERE meta_key = %s AND $column = %d",
+ $meta_key, $object_id ) ) )
+ return false;
+
+ $_meta_value = $meta_value;
+ $meta_value = maybe_serialize( $meta_value );
+
+ do_action( "add_{$meta_type}_meta", $object_id, $meta_key, $_meta_value );
+
+ $result = $wpdb->insert( $table, array(
+ $column => $object_id,
+ 'meta_key' => $meta_key,
+ 'meta_value' => $meta_value
+ ) );
+
+ if ( ! $result )
+ return false;
+
+ $mid = (int) $wpdb->insert_id;
+
+ wp_cache_delete($object_id, $meta_type . '_meta');
+
+ do_action( "added_{$meta_type}_meta", $mid, $object_id, $meta_key, $_meta_value );
+
+ return $mid;
+}
+
+/**
+ * Update metadata for the specified object. If no value already exists for the specified object
+ * ID and metadata key, the metadata will be added.
+ *
+ * @since 2.9.0
+ * @uses $wpdb WordPress database object for queries.
+ * @uses do_action() Calls 'update_{$meta_type}_meta' before updating metadata with meta_id of
+ * metadata entry to update, object ID, meta key, and meta value
+ * @uses do_action() Calls 'updated_{$meta_type}_meta' after updating metadata with meta_id of
+ * updated metadata entry, object ID, meta key, and meta value
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $object_id ID of the object metadata is for
+ * @param string $meta_key Metadata key
+ * @param string $meta_value Metadata value
+ * @param string $prev_value Optional. If specified, only update existing metadata entries with
+ * the specified value. Otherwise, update all entries.
+ * @return bool True on successful update, false on failure.
+ */
+function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_value = '') {
+ if ( !$meta_type || !$meta_key )
+ return false;
+
+ if ( !$object_id = absint($object_id) )
+ return false;
+
+ if ( ! $table = _get_meta_table($meta_type) )
+ return false;
+
+ global $wpdb;
+
+ $column = sanitize_key($meta_type . '_id');
+ $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+
+ // expected_slashed ($meta_key)
+ $meta_key = wp_unslash($meta_key);
+ $passed_value = $meta_value;
+ $meta_value = wp_unslash($meta_value);
+ $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
+
+ $check = apply_filters( "update_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $prev_value );
+ if ( null !== $check )
+ return (bool) $check;
+
+ // Compare existing value to new value if no prev value given and the key exists only once.
+ if ( empty($prev_value) ) {
+ $old_value = get_metadata($meta_type, $object_id, $meta_key);
+ if ( count($old_value) == 1 ) {
+ if ( $old_value[0] === $meta_value )
+ return false;
+ }
+ }
+
+ if ( ! $meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) ) )
+ return add_metadata($meta_type, $object_id, $meta_key, $passed_value);
+
+ $_meta_value = $meta_value;
+ $meta_value = maybe_serialize( $meta_value );
+
+ $data = compact( 'meta_value' );
+ $where = array( $column => $object_id, 'meta_key' => $meta_key );
+
+ if ( !empty( $prev_value ) ) {
+ $prev_value = maybe_serialize($prev_value);
+ $where['meta_value'] = $prev_value;
+ }
+
+ do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+
+ if ( 'post' == $meta_type )
+ do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+
+ $wpdb->update( $table, $data, $where );
+
+ wp_cache_delete($object_id, $meta_type . '_meta');
+
+ do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+
+ if ( 'post' == $meta_type )
+ do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+
+ return true;
+}
+
+/**
+ * Delete metadata for the specified object.
+ *
+ * @since 2.9.0
+ * @uses $wpdb WordPress database object for queries.
+ * @uses do_action() Calls 'deleted_{$meta_type}_meta' after deleting with meta_id of
+ * deleted metadata entries, object ID, meta key, and meta value
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $object_id ID of the object metadata is for
+ * @param string $meta_key Metadata key
+ * @param string $meta_value Optional. Metadata value. If specified, only delete metadata entries
+ * with this value. Otherwise, delete all entries with the specified meta_key.
+ * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries
+ * for all objects, ignoring the specified object_id. Otherwise, only delete matching
+ * metadata entries for the specified object_id.
+ * @return bool True on successful delete, false on failure.
+ */
+function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) {
+ if ( !$meta_type || !$meta_key )
+ return false;
+
+ if ( (!$object_id = absint($object_id)) && !$delete_all )
+ return false;
+
+ if ( ! $table = _get_meta_table($meta_type) )
+ return false;
+
+ global $wpdb;
+
+ $type_column = sanitize_key($meta_type . '_id');
+ $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+ // expected_slashed ($meta_key)
+ $meta_key = wp_unslash($meta_key);
+ $meta_value = wp_unslash($meta_value);
+
+ $check = apply_filters( "delete_{$meta_type}_metadata", null, $object_id, $meta_key, $meta_value, $delete_all );
+ if ( null !== $check )
+ return (bool) $check;
+
+ $_meta_value = $meta_value;
+ $meta_value = maybe_serialize( $meta_value );
+
+ $query = $wpdb->prepare( "SELECT $id_column FROM $table WHERE meta_key = %s", $meta_key );
+
+ if ( !$delete_all )
+ $query .= $wpdb->prepare(" AND $type_column = %d", $object_id );
+
+ if ( $meta_value )
+ $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );
+
+ $meta_ids = $wpdb->get_col( $query );
+ if ( !count( $meta_ids ) )
+ return false;
+
+ if ( $delete_all )
+ $object_ids = $wpdb->get_col( $wpdb->prepare( "SELECT $type_column FROM $table WHERE meta_key = %s", $meta_key ) );
+
+ do_action( "delete_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
+
+ // Old-style action.
+ if ( 'post' == $meta_type )
+ do_action( 'delete_postmeta', $meta_ids );
+
+ $query = "DELETE FROM $table WHERE $id_column IN( " . implode( ',', $meta_ids ) . " )";
+
+ $count = $wpdb->query($query);
+
+ if ( !$count )
+ return false;
+
+ if ( $delete_all ) {
+ foreach ( (array) $object_ids as $o_id ) {
+ wp_cache_delete($o_id, $meta_type . '_meta');
+ }
+ } else {
+ wp_cache_delete($object_id, $meta_type . '_meta');
+ }
+
+ do_action( "deleted_{$meta_type}_meta", $meta_ids, $object_id, $meta_key, $_meta_value );
+
+ // Old-style action.
+ if ( 'post' == $meta_type )
+ do_action( 'deleted_postmeta', $meta_ids );
+
+ return true;
+}
+
+/**
+ * Retrieve metadata for the specified object.
+ *
+ * @since 2.9.0
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $object_id ID of the object metadata is for
+ * @param string $meta_key Optional. Metadata key. If not specified, retrieve all metadata for
+ * the specified object.
+ * @param bool $single Optional, default is false. If true, return only the first value of the
+ * specified meta_key. This parameter has no effect if meta_key is not specified.
+ * @return string|array Single metadata value, or array of values
+ */
+function get_metadata($meta_type, $object_id, $meta_key = '', $single = false) {
+ if ( !$meta_type )
+ return false;
+
+ if ( !$object_id = absint($object_id) )
+ return false;
+
+ $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, $single );
+ if ( null !== $check ) {
+ if ( $single && is_array( $check ) )
+ return $check[0];
+ else
+ return $check;
+ }
+
+ $meta_cache = wp_cache_get($object_id, $meta_type . '_meta');
+
+ if ( !$meta_cache ) {
+ $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
+ $meta_cache = $meta_cache[$object_id];
+ }
+
+ if ( !$meta_key )
+ return $meta_cache;
+
+ if ( isset($meta_cache[$meta_key]) ) {
+ if ( $single )
+ return maybe_unserialize( $meta_cache[$meta_key][0] );
+ else
+ return array_map('maybe_unserialize', $meta_cache[$meta_key]);
+ }
+
+ if ($single)
+ return '';
+ else
+ return array();
+}
+
+/**
+ * Determine if a meta key is set for a given object
+ *
+ * @since 3.3.0
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $object_id ID of the object metadata is for
+ * @param string $meta_key Metadata key.
+ * @return boolean true of the key is set, false if not.
+ */
+function metadata_exists( $meta_type, $object_id, $meta_key ) {
+ if ( ! $meta_type )
+ return false;
+
+ if ( ! $object_id = absint( $object_id ) )
+ return false;
+
+ $check = apply_filters( "get_{$meta_type}_metadata", null, $object_id, $meta_key, true );
+ if ( null !== $check )
+ return true;
+
+ $meta_cache = wp_cache_get( $object_id, $meta_type . '_meta' );
+
+ if ( !$meta_cache ) {
+ $meta_cache = update_meta_cache( $meta_type, array( $object_id ) );
+ $meta_cache = $meta_cache[$object_id];
+ }
+
+ if ( isset( $meta_cache[ $meta_key ] ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Get meta data by meta ID
+ *
+ * @since 3.3.0
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $meta_id ID for a specific meta row
+ * @return object Meta object or false.
+ */
+function get_metadata_by_mid( $meta_type, $meta_id ) {
+ global $wpdb;
+
+ if ( ! $meta_type )
+ return false;
+
+ if ( !$meta_id = absint( $meta_id ) )
+ return false;
+
+ if ( ! $table = _get_meta_table($meta_type) )
+ return false;
+
+ $id_column = ( 'user' == $meta_type ) ? 'umeta_id' : 'meta_id';
+
+ $meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE $id_column = %d", $meta_id ) );
+
+ if ( empty( $meta ) )
+ return false;
+
+ if ( isset( $meta->meta_value ) )
+ $meta->meta_value = maybe_unserialize( $meta->meta_value );
+
+ return $meta;
+}
+
+/**
+ * Update meta data by meta ID
+ *
+ * @since 3.3.0
+ *
+ * @uses get_metadata_by_mid() Calls get_metadata_by_mid() to fetch the meta key, value
+ * and object_id of the given meta_id.
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $meta_id ID for a specific meta row
+ * @param string $meta_value Metadata value
+ * @param string $meta_key Optional, you can provide a meta key to update it
+ * @return bool True on successful update, false on failure.
+ */
+function update_metadata_by_mid( $meta_type, $meta_id, $meta_value, $meta_key = false ) {
+ global $wpdb;
+
+ // Make sure everything is valid.
+ if ( ! $meta_type )
+ return false;
+
+ if ( ! $meta_id = absint( $meta_id ) )
+ return false;
+
+ if ( ! $table = _get_meta_table( $meta_type ) )
+ return false;
+
+ $column = sanitize_key($meta_type . '_id');
+ $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+
+ // Fetch the meta and go on if it's found.
+ if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
+ $original_key = $meta->meta_key;
+ $original_value = $meta->meta_value;
+ $object_id = $meta->{$column};
+
+ // If a new meta_key (last parameter) was specified, change the meta key,
+ // otherwise use the original key in the update statement.
+ if ( false === $meta_key ) {
+ $meta_key = $original_key;
+ } elseif ( ! is_string( $meta_key ) ) {
+ return false;
+ }
+
+ // Sanitize the meta
+ $_meta_value = $meta_value;
+ $meta_value = sanitize_meta( $meta_key, $meta_value, $meta_type );
+ $meta_value = maybe_serialize( $meta_value );
+
+ // Format the data query arguments.
+ $data = array(
+ 'meta_key' => $meta_key,
+ 'meta_value' => $meta_value
+ );
+
+ // Format the where query arguments.
+ $where = array();
+ $where[$id_column] = $meta_id;
+
+ do_action( "update_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+
+ if ( 'post' == $meta_type )
+ do_action( 'update_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+
+ // Run the update query, all fields in $data are %s, $where is a %d.
+ $result = (bool) $wpdb->update( $table, $data, $where, '%s', '%d' );
+
+ // Clear the caches.
+ wp_cache_delete($object_id, $meta_type . '_meta');
+
+ do_action( "updated_{$meta_type}_meta", $meta_id, $object_id, $meta_key, $_meta_value );
+
+ if ( 'post' == $meta_type )
+ do_action( 'updated_postmeta', $meta_id, $object_id, $meta_key, $meta_value );
+
+ return $result;
+ }
+
+ // And if the meta was not found.
+ return false;
+}
+
+/**
+ * Delete meta data by meta ID
+ *
+ * @since 3.3.0
+ *
+ * @uses get_metadata_by_mid() Calls get_metadata_by_mid() to fetch the meta key, value
+ * and object_id of the given meta_id.
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int $meta_id ID for a specific meta row
+ * @return bool True on successful delete, false on failure.
+ */
+function delete_metadata_by_mid( $meta_type, $meta_id ) {
+ global $wpdb;
+
+ // Make sure everything is valid.
+ if ( ! $meta_type )
+ return false;
+
+ if ( ! $meta_id = absint( $meta_id ) )
+ return false;
+
+ if ( ! $table = _get_meta_table( $meta_type ) )
+ return false;
+
+ // object and id columns
+ $column = sanitize_key($meta_type . '_id');
+ $id_column = 'user' == $meta_type ? 'umeta_id' : 'meta_id';
+
+ // Fetch the meta and go on if it's found.
+ if ( $meta = get_metadata_by_mid( $meta_type, $meta_id ) ) {
+ $object_id = $meta->{$column};
+
+ do_action( "delete_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
+
+ // Old-style action.
+ if ( 'post' == $meta_type || 'comment' == $meta_type )
+ do_action( "delete_{$meta_type}meta", $meta_id );
+
+ // Run the query, will return true if deleted, false otherwise
+ $result = (bool) $wpdb->delete( $table, array( $id_column => $meta_id ) );
+
+ // Clear the caches.
+ wp_cache_delete($object_id, $meta_type . '_meta');
+
+ do_action( "deleted_{$meta_type}_meta", (array) $meta_id, $object_id, $meta->meta_key, $meta->meta_value );
+
+ // Old-style action.
+ if ( 'post' == $meta_type || 'comment' == $meta_type )
+ do_action( "deleted_{$meta_type}meta", $meta_id );
+
+ return $result;
+
+ }
+
+ // Meta id was not found.
+ return false;
+}
+
+/**
+ * Update the metadata cache for the specified objects.
+ *
+ * @since 2.9.0
+ * @uses $wpdb WordPress database object for queries.
+ *
+ * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user)
+ * @param int|array $object_ids array or comma delimited list of object IDs to update cache for
+ * @return mixed Metadata cache for the specified objects, or false on failure.
+ */
+function update_meta_cache($meta_type, $object_ids) {
+ if ( empty( $meta_type ) || empty( $object_ids ) )
+ return false;
+
+ if ( ! $table = _get_meta_table($meta_type) )
+ return false;
+
+ $column = sanitize_key($meta_type . '_id');
+
+ global $wpdb;
+
+ if ( !is_array($object_ids) ) {
+ $object_ids = preg_replace('|[^0-9,]|', '', $object_ids);
+ $object_ids = explode(',', $object_ids);
+ }
+
+ $object_ids = array_map('intval', $object_ids);
+
+ $cache_key = $meta_type . '_meta';
+ $ids = array();
+ $cache = array();
+ foreach ( $object_ids as $id ) {
+ $cached_object = wp_cache_get( $id, $cache_key );
+ if ( false === $cached_object )
+ $ids[] = $id;
+ else
+ $cache[$id] = $cached_object;
+ }
+
+ if ( empty( $ids ) )
+ return $cache;
+
+ // Get meta info
+ $id_list = join(',', $ids);
+ $meta_list = $wpdb->get_results( $wpdb->prepare("SELECT $column, meta_key, meta_value FROM $table WHERE $column IN ($id_list)",
+ $meta_type), ARRAY_A );
+
+ if ( !empty($meta_list) ) {
+ foreach ( $meta_list as $metarow) {
+ $mpid = intval($metarow[$column]);
+ $mkey = $metarow['meta_key'];
+ $mval = $metarow['meta_value'];
+
+ // Force subkeys to be array type:
+ if ( !isset($cache[$mpid]) || !is_array($cache[$mpid]) )
+ $cache[$mpid] = array();
+ if ( !isset($cache[$mpid][$mkey]) || !is_array($cache[$mpid][$mkey]) )
+ $cache[$mpid][$mkey] = array();
+
+ // Add a value to the current pid/key:
+ $cache[$mpid][$mkey][] = $mval;
+ }
+ }
+
+ foreach ( $ids as $id ) {
+ if ( ! isset($cache[$id]) )
+ $cache[$id] = array();
+ wp_cache_add( $id, $cache[$id], $cache_key );
+ }
+
+ return $cache;
+}
+
+/**
+ * Given a meta query, generates SQL clauses to be appended to a main query
+ *
+ * @since 3.2.0
+ *
+ * @see WP_Meta_Query
+ *
+ * @param array $meta_query A meta query
+ * @param string $type Type of meta
+ * @param string $primary_table
+ * @param string $primary_id_column
+ * @param object $context (optional) The main query object
+ * @return array( 'join' => $join_sql, 'where' => $where_sql )
+ */
+function get_meta_sql( $meta_query, $type, $primary_table, $primary_id_column, $context = null ) {
+ $meta_query_obj = new WP_Meta_Query( $meta_query );
+ return $meta_query_obj->get_sql( $type, $primary_table, $primary_id_column, $context );
+}
+
+/**
+ * Container class for a multiple metadata query
+ *
+ * @since 3.2.0
+ */
+class WP_Meta_Query {
+ /**
+ * List of metadata queries. A single query is an associative array:
+ * - 'key' string The meta key
+ * - 'value' string|array The meta value
+ * - 'compare' (optional) string How to compare the key to the value.
+ * Possible values: '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'.
+ * Default: '='
+ * - 'type' string (optional) The type of the value.
+ * Possible values: 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'.
+ * Default: 'CHAR'
+ *
+ * @since 3.2.0
+ * @access public
+ * @var array
+ */
+ public $queries = array();
+
+ /**
+ * The relation between the queries. Can be one of 'AND' or 'OR'.
+ *
+ * @since 3.2.0
+ * @access public
+ * @var string
+ */
+ public $relation;
+
+ /**
+ * Constructor
+ *
+ * @param array $meta_query (optional) A meta query
+ */
+ function __construct( $meta_query = false ) {
+ if ( !$meta_query )
+ return;
+
+ if ( isset( $meta_query['relation'] ) && strtoupper( $meta_query['relation'] ) == 'OR' ) {
+ $this->relation = 'OR';
+ } else {
+ $this->relation = 'AND';
+ }
+
+ $this->queries = array();
+
+ foreach ( $meta_query as $key => $query ) {
+ if ( ! is_array( $query ) )
+ continue;
+
+ $this->queries[] = $query;
+ }
+ }
+
+ /**
+ * Constructs a meta query based on 'meta_*' query vars
+ *
+ * @since 3.2.0
+ * @access public
+ *
+ * @param array $qv The query variables
+ */
+ function parse_query_vars( $qv ) {
+ $meta_query = array();
+
+ // Simple query needs to be first for orderby=meta_value to work correctly
+ foreach ( array( 'key', 'compare', 'type' ) as $key ) {
+ if ( !empty( $qv[ "meta_$key" ] ) )
+ $meta_query[0][ $key ] = $qv[ "meta_$key" ];
+ }
+
+ // WP_Query sets 'meta_value' = '' by default
+ if ( isset( $qv[ 'meta_value' ] ) && '' !== $qv[ 'meta_value' ] && ( ! is_array( $qv[ 'meta_value' ] ) || $qv[ 'meta_value' ] ) )
+ $meta_query[0]['value'] = $qv[ 'meta_value' ];
+
+ if ( !empty( $qv['meta_query'] ) && is_array( $qv['meta_query'] ) ) {
+ $meta_query = array_merge( $meta_query, $qv['meta_query'] );
+ }
+
+ $this->__construct( $meta_query );
+ }
+
+ /**
+ * Generates SQL clauses to be appended to a main query.
+ *
+ * @since 3.2.0
+ * @access public
+ *
+ * @param string $type Type of meta
+ * @param string $primary_table
+ * @param string $primary_id_column
+ * @param object $context (optional) The main query object
+ * @return array( 'join' => $join_sql, 'where' => $where_sql )
+ */
+ function get_sql( $type, $primary_table, $primary_id_column, $context = null ) {
+ global $wpdb;
+
+ if ( ! $meta_table = _get_meta_table( $type ) )
+ return false;
+
+ $meta_id_column = sanitize_key( $type . '_id' );
+
+ $join = array();
+ $where = array();
+
+ $key_only_queries = array();
+ $queries = array();
+
+ // Split out the queries with empty arrays as value
+ foreach ( $this->queries as $k => $q ) {
+ if ( isset( $q['value'] ) && is_array( $q['value'] ) && empty( $q['value'] ) ) {
+ $key_only_queries[$k] = $q;
+ unset( $this->queries[$k] );
+ }
+ }
+
+ // Split out the meta_key only queries (we can only do this for OR)
+ if ( 'OR' == $this->relation ) {
+ foreach ( $this->queries as $k => $q ) {
+ if ( ! isset( $q['value'] ) && ! empty( $q['key'] ) )
+ $key_only_queries[$k] = $q;
+ else
+ $queries[$k] = $q;
+ }
+ } else {
+ $queries = $this->queries;
+ }
+
+ // Specify all the meta_key only queries in one go
+ if ( $key_only_queries ) {
+ $join[] = "INNER JOIN $meta_table ON $primary_table.$primary_id_column = $meta_table.$meta_id_column";
+
+ foreach ( $key_only_queries as $key => $q )
+ $where["key-only-$key"] = $wpdb->prepare( "$meta_table.meta_key = %s", trim( $q['key'] ) );
+ }
+
+ foreach ( $queries as $k => $q ) {
+ $meta_key = isset( $q['key'] ) ? trim( $q['key'] ) : '';
+ $meta_type = isset( $q['type'] ) ? strtoupper( $q['type'] ) : 'CHAR';
+
+ if ( 'NUMERIC' == $meta_type )
+ $meta_type = 'SIGNED';
+ elseif ( ! in_array( $meta_type, array( 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED' ) ) )
+ $meta_type = 'CHAR';
+
+ $meta_value = isset( $q['value'] ) ? $q['value'] : null;
+
+ if ( isset( $q['compare'] ) )
+ $meta_compare = strtoupper( $q['compare'] );
+ else
+ $meta_compare = is_array( $meta_value ) ? 'IN' : '=';
+
+ if ( ! in_array( $meta_compare, array(
+ '=', '!=', '>', '>=', '<', '<=',
+ 'LIKE', 'NOT LIKE',
+ 'IN', 'NOT IN',
+ 'BETWEEN', 'NOT BETWEEN',
+ 'NOT EXISTS'
+ ) ) )
+ $meta_compare = '=';
+
+ $i = count( $join );
+ $alias = $i ? 'mt' . $i : $meta_table;
+
+ if ( 'NOT EXISTS' == $meta_compare ) {
+ $join[$i] = "LEFT JOIN $meta_table";
+ $join[$i] .= $i ? " AS $alias" : '';
+ $join[$i] .= " ON ($primary_table.$primary_id_column = $alias.$meta_id_column AND $alias.meta_key = '$meta_key')";
+
+ $where[$k] = ' ' . $alias . '.' . $meta_id_column . ' IS NULL';
+
+ continue;
+ }
+
+ $join[$i] = "INNER JOIN $meta_table";
+ $join[$i] .= $i ? " AS $alias" : '';
+ $join[$i] .= " ON ($primary_table.$primary_id_column = $alias.$meta_id_column)";
+
+ $where[$k] = '';
+ if ( !empty( $meta_key ) )
+ $where[$k] = $wpdb->prepare( "$alias.meta_key = %s", $meta_key );
+
+ if ( is_null( $meta_value ) ) {
+ if ( empty( $where[$k] ) )
+ unset( $join[$i] );
+ continue;
+ }
+
+ if ( in_array( $meta_compare, array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN' ) ) ) {
+ if ( ! is_array( $meta_value ) )
+ $meta_value = preg_split( '/[,\s]+/', $meta_value );
+
+ if ( empty( $meta_value ) ) {
+ unset( $join[$i] );
+ continue;
+ }
+ } else {
+ $meta_value = trim( $meta_value );
+ }
+
+ if ( 'IN' == substr( $meta_compare, -2) ) {
+ $meta_compare_string = '(' . substr( str_repeat( ',%s', count( $meta_value ) ), 1 ) . ')';
+ } elseif ( 'BETWEEN' == substr( $meta_compare, -7) ) {
+ $meta_value = array_slice( $meta_value, 0, 2 );
+ $meta_compare_string = '%s AND %s';
+ } elseif ( 'LIKE' == substr( $meta_compare, -4 ) ) {
+ $meta_value = '%' . like_escape( $meta_value ) . '%';
+ $meta_compare_string = '%s';
+ } else {
+ $meta_compare_string = '%s';
+ }
+
+ if ( ! empty( $where[$k] ) )
+ $where[$k] .= ' AND ';
+
+ $where[$k] = ' (' . $where[$k] . $wpdb->prepare( "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$meta_compare_string})", $meta_value );
+ }
+
+ $where = array_filter( $where );
+
+ if ( empty( $where ) )
+ $where = '';
+ else
+ $where = ' AND (' . implode( "\n{$this->relation} ", $where ) . ' )';
+
+ $join = implode( "\n", $join );
+ if ( ! empty( $join ) )
+ $join = ' ' . $join;
+
+ return apply_filters_ref_array( 'get_meta_sql', array( compact( 'join', 'where' ), $this->queries, $type, $primary_table, $primary_id_column, $context ) );
+ }
+}
+
+/**
+ * Retrieve the name of the metadata table for the specified object type.
+ *
+ * @since 2.9.0
+ * @uses $wpdb WordPress database object for queries.
+ *
+ * @param string $type Type of object to get metadata table for (e.g., comment, post, or user)
+ * @return mixed Metadata table name, or false if no metadata table exists
+ */
+function _get_meta_table($type) {
+ global $wpdb;
+
+ $table_name = $type . 'meta';
+
+ if ( empty($wpdb->$table_name) )
+ return false;
+
+ return $wpdb->$table_name;
+}
+
+/**
+ * Determine whether a meta key is protected
+ *
+ * @since 3.1.3
+ *
+ * @param string $meta_key Meta key
+ * @return bool True if the key is protected, false otherwise.
+ */
+function is_protected_meta( $meta_key, $meta_type = null ) {
+ $protected = ( '_' == $meta_key[0] );
+
+ return apply_filters( 'is_protected_meta', $protected, $meta_key, $meta_type );
+}
+
+/**
+ * Sanitize meta value
+ *
+ * @since 3.1.3
+ *
+ * @param string $meta_key Meta key
+ * @param mixed $meta_value Meta value to sanitize
+ * @param string $meta_type Type of meta
+ * @return mixed Sanitized $meta_value
+ */
+function sanitize_meta( $meta_key, $meta_value, $meta_type ) {
+ return apply_filters( "sanitize_{$meta_type}_meta_{$meta_key}", $meta_value, $meta_key, $meta_type );
+}
+
+/**
+ * Register meta key
+ *
+ * @since 3.3.0
+ *
+ * @param string $meta_type Type of meta
+ * @param string $meta_key Meta key
+ * @param string|array $sanitize_callback A function or method to call when sanitizing the value of $meta_key.
+ * @param string|array $auth_callback Optional. A function or method to call when performing edit_post_meta, add_post_meta, and delete_post_meta capability checks.
+ * @param array $args Arguments
+ */
+function register_meta( $meta_type, $meta_key, $sanitize_callback, $auth_callback = null ) {
+ if ( is_callable( $sanitize_callback ) )
+ add_filter( "sanitize_{$meta_type}_meta_{$meta_key}", $sanitize_callback, 10, 3 );
+
+ if ( empty( $auth_callback ) ) {
+ if ( is_protected_meta( $meta_key, $meta_type ) )
+ $auth_callback = '__return_false';
+ else
+ $auth_callback = '__return_true';
+ }
+
+ if ( is_callable( $auth_callback ) )
+ add_filter( "auth_{$meta_type}_meta_{$meta_key}", $auth_callback, 10, 6 );
+}
diff --git a/src/wp-includes/ms-blogs.php b/src/wp-includes/ms-blogs.php
new file mode 100644
index 0000000000..95ddedb7f1
--- /dev/null
+++ b/src/wp-includes/ms-blogs.php
@@ -0,0 +1,783 @@
+<?php
+
+/**
+ * Site/blog functions that work with the blogs table and related data.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since MU
+ */
+
+/**
+ * Update the last_updated field for the current blog.
+ *
+ * @since MU
+ */
+function wpmu_update_blogs_date() {
+ global $wpdb;
+
+ update_blog_details( $wpdb->blogid, array('last_updated' => current_time('mysql', true)) );
+
+ do_action( 'wpmu_blog_updated', $wpdb->blogid );
+}
+
+/**
+ * Get a full blog URL, given a blog id.
+ *
+ * @since MU
+ *
+ * @param int $blog_id Blog ID
+ * @return string
+ */
+function get_blogaddress_by_id( $blog_id ) {
+ $bloginfo = get_blog_details( (int) $blog_id, false ); // only get bare details!
+ return esc_url( 'http://' . $bloginfo->domain . $bloginfo->path );
+}
+
+/**
+ * Get a full blog URL, given a blog name.
+ *
+ * @since MU
+ *
+ * @param string $blogname The (subdomain or directory) name
+ * @return string
+ */
+function get_blogaddress_by_name( $blogname ) {
+ if ( is_subdomain_install() ) {
+ if ( $blogname == 'main' )
+ $blogname = 'www';
+ $url = rtrim( network_home_url(), '/' );
+ if ( !empty( $blogname ) )
+ $url = preg_replace( '|^([^\.]+://)|', "\${1}" . $blogname . '.', $url );
+ } else {
+ $url = network_home_url( $blogname );
+ }
+ return esc_url( $url . '/' );
+}
+
+/**
+ * Get a full blog URL, given a domain and a path.
+ *
+ * @since MU
+ *
+ * @param string $domain
+ * @param string $path
+ * @return string
+ */
+function get_blogaddress_by_domain( $domain, $path ) {
+ if ( is_subdomain_install() ) {
+ $url = "http://" . $domain.$path;
+ } else {
+ if ( $domain != $_SERVER['HTTP_HOST'] ) {
+ $blogname = substr( $domain, 0, strpos( $domain, '.' ) );
+ $url = 'http://' . substr( $domain, strpos( $domain, '.' ) + 1 ) . $path;
+ // we're not installing the main blog
+ if ( $blogname != 'www.' )
+ $url .= $blogname . '/';
+ } else { // main blog
+ $url = 'http://' . $domain . $path;
+ }
+ }
+ return esc_url( $url );
+}
+
+/**
+ * Given a blog's (subdomain or directory) slug, retrieve its id.
+ *
+ * @since MU
+ *
+ * @param string $slug
+ * @return int A blog id
+ */
+function get_id_from_blogname( $slug ) {
+ global $wpdb, $current_site;
+
+ $slug = trim( $slug, '/' );
+
+ $blog_id = wp_cache_get( 'get_id_from_blogname_' . $slug, 'blog-details' );
+ if ( $blog_id )
+ return $blog_id;
+
+ if ( is_subdomain_install() ) {
+ $domain = $slug . '.' . $current_site->domain;
+ $path = $current_site->path;
+ } else {
+ $domain = $current_site->domain;
+ $path = $current_site->path . $slug . '/';
+ }
+
+ $blog_id = $wpdb->get_var( $wpdb->prepare("SELECT blog_id FROM {$wpdb->blogs} WHERE domain = %s AND path = %s", $domain, $path) );
+ wp_cache_set( 'get_id_from_blogname_' . $slug, $blog_id, 'blog-details' );
+ return $blog_id;
+}
+
+/**
+ * Retrieve the details for a blog from the blogs table and blog options.
+ *
+ * @since MU
+ *
+ * @param int|string|array $fields A blog ID, a blog slug, or an array of fields to query against. Optional. If not specified the current blog ID is used.
+ * @param bool $get_all Whether to retrieve all details or only the details in the blogs table. Default is true.
+ * @return object Blog details.
+ */
+function get_blog_details( $fields = null, $get_all = true ) {
+ global $wpdb;
+
+ if ( is_array($fields ) ) {
+ if ( isset($fields['blog_id']) ) {
+ $blog_id = $fields['blog_id'];
+ } elseif ( isset($fields['domain']) && isset($fields['path']) ) {
+ $key = md5( $fields['domain'] . $fields['path'] );
+ $blog = wp_cache_get($key, 'blog-lookup');
+ if ( false !== $blog )
+ return $blog;
+ if ( substr( $fields['domain'], 0, 4 ) == 'www.' ) {
+ $nowww = substr( $fields['domain'], 4 );
+ $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s,%s) AND path = %s ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'], $fields['path'] ) );
+ } else {
+ $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s AND path = %s", $fields['domain'], $fields['path'] ) );
+ }
+ if ( $blog ) {
+ wp_cache_set($blog->blog_id . 'short', $blog, 'blog-details');
+ $blog_id = $blog->blog_id;
+ } else {
+ return false;
+ }
+ } elseif ( isset($fields['domain']) && is_subdomain_install() ) {
+ $key = md5( $fields['domain'] );
+ $blog = wp_cache_get($key, 'blog-lookup');
+ if ( false !== $blog )
+ return $blog;
+ if ( substr( $fields['domain'], 0, 4 ) == 'www.' ) {
+ $nowww = substr( $fields['domain'], 4 );
+ $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain IN (%s,%s) ORDER BY CHAR_LENGTH(domain) DESC", $nowww, $fields['domain'] ) );
+ } else {
+ $blog = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE domain = %s", $fields['domain'] ) );
+ }
+ if ( $blog ) {
+ wp_cache_set($blog->blog_id . 'short', $blog, 'blog-details');
+ $blog_id = $blog->blog_id;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ } else {
+ if ( ! $fields )
+ $blog_id = get_current_blog_id();
+ elseif ( ! is_numeric( $fields ) )
+ $blog_id = get_id_from_blogname( $fields );
+ else
+ $blog_id = $fields;
+ }
+
+ $blog_id = (int) $blog_id;
+
+ $all = $get_all == true ? '' : 'short';
+ $details = wp_cache_get( $blog_id . $all, 'blog-details' );
+
+ if ( $details ) {
+ if ( ! is_object( $details ) ) {
+ if ( $details == -1 ) {
+ return false;
+ } else {
+ // Clear old pre-serialized objects. Cache clients do better with that.
+ wp_cache_delete( $blog_id . $all, 'blog-details' );
+ unset($details);
+ }
+ } else {
+ return $details;
+ }
+ }
+
+ // Try the other cache.
+ if ( $get_all ) {
+ $details = wp_cache_get( $blog_id . 'short', 'blog-details' );
+ } else {
+ $details = wp_cache_get( $blog_id, 'blog-details' );
+ // If short was requested and full cache is set, we can return.
+ if ( $details ) {
+ if ( ! is_object( $details ) ) {
+ if ( $details == -1 ) {
+ return false;
+ } else {
+ // Clear old pre-serialized objects. Cache clients do better with that.
+ wp_cache_delete( $blog_id, 'blog-details' );
+ unset($details);
+ }
+ } else {
+ return $details;
+ }
+ }
+ }
+
+ if ( empty($details) ) {
+ $details = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->blogs WHERE blog_id = %d /* get_blog_details */", $blog_id ) );
+ if ( ! $details ) {
+ // Set the full cache.
+ wp_cache_set( $blog_id, -1, 'blog-details' );
+ return false;
+ }
+ }
+
+ if ( ! $get_all ) {
+ wp_cache_set( $blog_id . $all, $details, 'blog-details' );
+ return $details;
+ }
+
+ switch_to_blog( $blog_id );
+ $details->blogname = get_option( 'blogname' );
+ $details->siteurl = get_option( 'siteurl' );
+ $details->post_count = get_option( 'post_count' );
+ restore_current_blog();
+
+ $details = apply_filters( 'blog_details', $details );
+
+ wp_cache_set( $blog_id . $all, $details, 'blog-details' );
+
+ $key = md5( $details->domain . $details->path );
+ wp_cache_set( $key, $details, 'blog-lookup' );
+
+ return $details;
+}
+
+/**
+ * Clear the blog details cache.
+ *
+ * @since MU
+ *
+ * @param int $blog_id Blog ID
+ */
+function refresh_blog_details( $blog_id ) {
+ $blog_id = (int) $blog_id;
+ $details = get_blog_details( $blog_id, false );
+ if ( ! $details ) {
+ // Make sure clean_blog_cache() gets the blog ID
+ // when the blog has been previously cached as
+ // non-existent.
+ $details = (object) array(
+ 'blog_id' => $blog_id,
+ 'domain' => null,
+ 'path' => null
+ );
+ }
+
+ clean_blog_cache( $details );
+
+ do_action( 'refresh_blog_details', $blog_id );
+}
+
+/**
+ * Update the details for a blog. Updates the blogs table for a given blog id.
+ *
+ * @since MU
+ *
+ * @param int $blog_id Blog ID
+ * @param array $details Array of details keyed by blogs table field names.
+ * @return bool True if update succeeds, false otherwise.
+ */
+function update_blog_details( $blog_id, $details = array() ) {
+ global $wpdb;
+
+ if ( empty($details) )
+ return false;
+
+ if ( is_object($details) )
+ $details = get_object_vars($details);
+
+ $current_details = get_blog_details($blog_id, false);
+ if ( empty($current_details) )
+ return false;
+
+ $current_details = get_object_vars($current_details);
+
+ $details = array_merge($current_details, $details);
+ $details['last_updated'] = current_time('mysql', true);
+
+ $update_details = array();
+ $fields = array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id');
+ foreach ( array_intersect( array_keys( $details ), $fields ) as $field )
+ $update_details[$field] = $details[$field];
+
+ $result = $wpdb->update( $wpdb->blogs, $update_details, array('blog_id' => $blog_id) );
+
+ if ( false === $result )
+ return false;
+
+ // If spam status changed, issue actions.
+ if ( $details[ 'spam' ] != $current_details[ 'spam' ] ) {
+ if ( $details[ 'spam' ] == 1 )
+ do_action( 'make_spam_blog', $blog_id );
+ else
+ do_action( 'make_ham_blog', $blog_id );
+ }
+
+ // If mature status changed, issue actions.
+ if ( $details[ 'mature' ] != $current_details[ 'mature' ] ) {
+ if ( $details[ 'mature' ] == 1 )
+ do_action( 'mature_blog', $blog_id );
+ else
+ do_action( 'unmature_blog', $blog_id );
+ }
+
+ // If archived status changed, issue actions.
+ if ( $details[ 'archived' ] != $current_details[ 'archived' ] ) {
+ if ( $details[ 'archived' ] == 1 )
+ do_action( 'archive_blog', $blog_id );
+ else
+ do_action( 'unarchive_blog', $blog_id );
+ }
+
+ // If deleted status changed, issue actions.
+ if ( $details[ 'deleted' ] != $current_details[ 'deleted' ] ) {
+ if ( $details[ 'deleted' ] == 1 )
+ do_action( 'make_delete_blog', $blog_id );
+ else
+ do_action( 'make_undelete_blog', $blog_id );
+ }
+
+ if ( isset( $details[ 'public' ] ) ) {
+ switch_to_blog( $blog_id );
+ update_option( 'blog_public', $details[ 'public' ] );
+ restore_current_blog();
+ }
+
+ refresh_blog_details($blog_id);
+
+ return true;
+}
+
+/**
+ * Clean the blog cache
+ *
+ * @since 3.5.0
+ *
+ * @param stdClass $blog The blog details as returned from get_blog_details()
+ */
+function clean_blog_cache( $blog ) {
+ $blog_id = $blog->blog_id;
+ $domain_path_key = md5( $blog->domain . $blog->path );
+
+ wp_cache_delete( $blog_id , 'blog-details' );
+ wp_cache_delete( $blog_id . 'short' , 'blog-details' );
+ wp_cache_delete( $domain_path_key, 'blog-lookup' );
+ wp_cache_delete( 'current_blog_' . $blog->domain, 'site-options' );
+ wp_cache_delete( 'current_blog_' . $blog->domain . $blog->path, 'site-options' );
+ wp_cache_delete( 'get_id_from_blogname_' . trim( $blog->path, '/' ), 'blog-details' );
+ wp_cache_delete( $domain_path_key, 'blog-id-cache' );
+}
+
+/**
+ * Retrieve option value for a given blog id based on name of option.
+ *
+ * If the option does not exist or does not have a value, then the return value
+ * will be false. This is useful to check whether you need to install an option
+ * and is commonly used during installation of plugin options and to test
+ * whether upgrading is required.
+ *
+ * If the option was serialized then it will be unserialized when it is returned.
+ *
+ * @since MU
+ *
+ * @param int $id A blog ID. Can be null to refer to the current blog.
+ * @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
+ * @param mixed $default Optional. Default value to return if the option does not exist.
+ * @return mixed Value set for the option.
+ */
+function get_blog_option( $id, $option, $default = false ) {
+ $id = (int) $id;
+
+ if ( empty( $id ) )
+ $id = get_current_blog_id();
+
+ if ( get_current_blog_id() == $id )
+ return get_option( $option, $default );
+
+ switch_to_blog( $id );
+ $value = get_option( $option, $default );
+ restore_current_blog();
+
+ return apply_filters( 'blog_option_' . $option, $value, $id );
+}
+
+/**
+ * Add a new option for a given blog id.
+ *
+ * You do not need to serialize values. If the value needs to be serialized, then
+ * it will be serialized before it is inserted into the database. Remember,
+ * resources can not be serialized or added as an option.
+ *
+ * You can create options without values and then update the values later.
+ * Existing options will not be updated and checks are performed to ensure that you
+ * aren't adding a protected WordPress option. Care should be taken to not name
+ * options the same as the ones which are protected.
+ *
+ * @since MU
+ *
+ * @param int $id A blog ID. Can be null to refer to the current blog.
+ * @param string $option Name of option to add. Expected to not be SQL-escaped.
+ * @param mixed $value Optional. Option value, can be anything. Expected to not be SQL-escaped.
+ * @return bool False if option was not added and true if option was added.
+ */
+function add_blog_option( $id, $option, $value ) {
+ $id = (int) $id;
+
+ if ( empty( $id ) )
+ $id = get_current_blog_id();
+
+ if ( get_current_blog_id() == $id )
+ return add_option( $option, $value );
+
+ switch_to_blog( $id );
+ $return = add_option( $option, $value );
+ restore_current_blog();
+
+ return $return;
+}
+
+/**
+ * Removes option by name for a given blog id. Prevents removal of protected WordPress options.
+ *
+ * @since MU
+ *
+ * @param int $id A blog ID. Can be null to refer to the current blog.
+ * @param string $option Name of option to remove. Expected to not be SQL-escaped.
+ * @return bool True, if option is successfully deleted. False on failure.
+ */
+function delete_blog_option( $id, $option ) {
+ $id = (int) $id;
+
+ if ( empty( $id ) )
+ $id = get_current_blog_id();
+
+ if ( get_current_blog_id() == $id )
+ return delete_option( $option );
+
+ switch_to_blog( $id );
+ $return = delete_option( $option );
+ restore_current_blog();
+
+ return $return;
+}
+
+/**
+ * Update an option for a particular blog.
+ *
+ * @since MU
+ *
+ * @param int $id The blog id
+ * @param string $option The option key
+ * @param mixed $value The option value
+ * @return bool True on success, false on failure.
+ */
+function update_blog_option( $id, $option, $value, $deprecated = null ) {
+ $id = (int) $id;
+
+ if ( null !== $deprecated )
+ _deprecated_argument( __FUNCTION__, '3.1' );
+
+ if ( get_current_blog_id() == $id )
+ return update_option( $option, $value );
+
+ switch_to_blog( $id );
+ $return = update_option( $option, $value );
+ restore_current_blog();
+
+ refresh_blog_details( $id );
+
+ return $return;
+}
+
+/**
+ * Switch the current blog.
+ *
+ * This function is useful if you need to pull posts, or other information,
+ * from other blogs. You can switch back afterwards using restore_current_blog().
+ *
+ * Things that aren't switched:
+ * - autoloaded options. See #14992
+ * - plugins. See #14941
+ *
+ * @see restore_current_blog()
+ * @since MU
+ *
+ * @param int $new_blog The id of the blog you want to switch to. Default: current blog
+ * @param bool $deprecated Deprecated argument
+ * @return bool True on success, false if the validation failed
+ */
+function switch_to_blog( $new_blog, $deprecated = null ) {
+ global $wpdb, $wp_roles;
+
+ if ( empty( $new_blog ) )
+ $new_blog = $GLOBALS['blog_id'];
+
+ $GLOBALS['_wp_switched_stack'][] = $GLOBALS['blog_id'];
+
+ /* If we're switching to the same blog id that we're on,
+ * set the right vars, do the associated actions, but skip
+ * the extra unnecessary work */
+ if ( $new_blog == $GLOBALS['blog_id'] ) {
+ do_action( 'switch_blog', $new_blog, $new_blog );
+ $GLOBALS['switched'] = true;
+ return true;
+ }
+
+ $wpdb->set_blog_id( $new_blog );
+ $GLOBALS['table_prefix'] = $wpdb->prefix;
+ $prev_blog_id = $GLOBALS['blog_id'];
+ $GLOBALS['blog_id'] = $new_blog;
+
+ if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
+ wp_cache_switch_to_blog( $new_blog );
+ } else {
+ global $wp_object_cache;
+
+ if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) )
+ $global_groups = $wp_object_cache->global_groups;
+ else
+ $global_groups = false;
+
+ wp_cache_init();
+
+ if ( function_exists( 'wp_cache_add_global_groups' ) ) {
+ if ( is_array( $global_groups ) )
+ wp_cache_add_global_groups( $global_groups );
+ else
+ wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', ' blog-id-cache' ) );
+ wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
+ }
+ }
+
+ if ( did_action( 'init' ) ) {
+ $wp_roles->reinit();
+ $current_user = wp_get_current_user();
+ $current_user->for_blog( $new_blog );
+ }
+
+ do_action( 'switch_blog', $new_blog, $prev_blog_id );
+ $GLOBALS['switched'] = true;
+
+ return true;
+}
+
+/**
+ * Restore the current blog, after calling switch_to_blog()
+ *
+ * @see switch_to_blog()
+ * @since MU
+ *
+ * @return bool True on success, false if we're already on the current blog
+ */
+function restore_current_blog() {
+ global $wpdb, $wp_roles;
+
+ if ( empty( $GLOBALS['_wp_switched_stack'] ) )
+ return false;
+
+ $blog = array_pop( $GLOBALS['_wp_switched_stack'] );
+
+ if ( $GLOBALS['blog_id'] == $blog ) {
+ do_action( 'switch_blog', $blog, $blog );
+ // If we still have items in the switched stack, consider ourselves still 'switched'
+ $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );
+ return true;
+ }
+
+ $wpdb->set_blog_id( $blog );
+ $prev_blog_id = $GLOBALS['blog_id'];
+ $GLOBALS['blog_id'] = $blog;
+ $GLOBALS['table_prefix'] = $wpdb->prefix;
+
+ if ( function_exists( 'wp_cache_switch_to_blog' ) ) {
+ wp_cache_switch_to_blog( $blog );
+ } else {
+ global $wp_object_cache;
+
+ if ( is_object( $wp_object_cache ) && isset( $wp_object_cache->global_groups ) )
+ $global_groups = $wp_object_cache->global_groups;
+ else
+ $global_groups = false;
+
+ wp_cache_init();
+
+ if ( function_exists( 'wp_cache_add_global_groups' ) ) {
+ if ( is_array( $global_groups ) )
+ wp_cache_add_global_groups( $global_groups );
+ else
+ wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', ' blog-id-cache' ) );
+ wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
+ }
+ }
+
+ if ( did_action( 'init' ) ) {
+ $wp_roles->reinit();
+ $current_user = wp_get_current_user();
+ $current_user->for_blog( $blog );
+ }
+
+ do_action( 'switch_blog', $blog, $prev_blog_id );
+
+ // If we still have items in the switched stack, consider ourselves still 'switched'
+ $GLOBALS['switched'] = ! empty( $GLOBALS['_wp_switched_stack'] );
+
+ return true;
+}
+
+/**
+ * Determines if switch_to_blog() is in effect
+ *
+ * @since 3.5.0
+ *
+ * @return bool True if switched, false otherwise.
+ */
+function ms_is_switched() {
+ return ! empty( $GLOBALS['_wp_switched_stack'] );
+}
+
+/**
+ * Check if a particular blog is archived.
+ *
+ * @since MU
+ *
+ * @param int $id The blog id
+ * @return string Whether the blog is archived or not
+ */
+function is_archived( $id ) {
+ return get_blog_status($id, 'archived');
+}
+
+/**
+ * Update the 'archived' status of a particular blog.
+ *
+ * @since MU
+ *
+ * @param int $id The blog id
+ * @param string $archived The new status
+ * @return string $archived
+ */
+function update_archived( $id, $archived ) {
+ update_blog_status($id, 'archived', $archived);
+ return $archived;
+}
+
+/**
+ * Update a blog details field.
+ *
+ * @since MU
+ *
+ * @param int $blog_id BLog ID
+ * @param string $pref A field name
+ * @param string $value Value for $pref
+ * @return string $value
+ */
+function update_blog_status( $blog_id, $pref, $value, $deprecated = null ) {
+ global $wpdb;
+
+ if ( null !== $deprecated )
+ _deprecated_argument( __FUNCTION__, '3.1' );
+
+ if ( ! in_array( $pref, array( 'site_id', 'domain', 'path', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id') ) )
+ return $value;
+
+ $result = $wpdb->update( $wpdb->blogs, array($pref => $value, 'last_updated' => current_time('mysql', true)), array('blog_id' => $blog_id) );
+
+ if ( false === $result )
+ return false;
+
+ refresh_blog_details( $blog_id );
+
+ if ( 'spam' == $pref )
+ ( $value == 1 ) ? do_action( 'make_spam_blog', $blog_id ) : do_action( 'make_ham_blog', $blog_id );
+ elseif ( 'mature' == $pref )
+ ( $value == 1 ) ? do_action( 'mature_blog', $blog_id ) : do_action( 'unmature_blog', $blog_id );
+ elseif ( 'archived' == $pref )
+ ( $value == 1 ) ? do_action( 'archive_blog', $blog_id ) : do_action( 'unarchive_blog', $blog_id );
+ elseif ( 'deleted' == $pref )
+ ( $value == 1 ) ? do_action( 'make_delete_blog', $blog_id ) : do_action( 'make_undelete_blog', $blog_id );
+ elseif ( 'public' == $pref )
+ do_action( 'update_blog_public', $blog_id, $value ); // Moved here from update_blog_public().
+
+ return $value;
+}
+
+/**
+ * Get a blog details field.
+ *
+ * @since MU
+ *
+ * @param int $id The blog id
+ * @param string $pref A field name
+ * @return bool $value
+ */
+function get_blog_status( $id, $pref ) {
+ global $wpdb;
+
+ $details = get_blog_details( $id, false );
+ if ( $details )
+ return $details->$pref;
+
+ return $wpdb->get_var( $wpdb->prepare("SELECT %s FROM {$wpdb->blogs} WHERE blog_id = %d", $pref, $id) );
+}
+
+/**
+ * Get a list of most recently updated blogs.
+ *
+ * @since MU
+ *
+ * @param mixed $deprecated Not used
+ * @param int $start The offset
+ * @param int $quantity The maximum number of blogs to retrieve. Default is 40.
+ * @return array The list of blogs
+ */
+function get_last_updated( $deprecated = '', $start = 0, $quantity = 40 ) {
+ global $wpdb;
+
+ if ( ! empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, 'MU' ); // never used
+
+ return $wpdb->get_results( $wpdb->prepare("SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' AND last_updated != '0000-00-00 00:00:00' ORDER BY last_updated DESC limit %d, %d", $wpdb->siteid, $start, $quantity ) , ARRAY_A );
+}
+
+/**
+ * Handler for updating the blog date when a post is published or an already published post is changed.
+ *
+ * @since 3.3.0
+ *
+ * @param string $new_status The new post status
+ * @param string $old_status The old post status
+ * @param object $post Post object
+ */
+function _update_blog_date_on_post_publish( $new_status, $old_status, $post ) {
+ $post_type_obj = get_post_type_object( $post->post_type );
+ if ( ! $post_type_obj->public )
+ return;
+
+ if ( 'publish' != $new_status && 'publish' != $old_status )
+ return;
+
+ // Post was freshly published, published post was saved, or published post was unpublished.
+
+ wpmu_update_blogs_date();
+}
+
+/**
+ * Handler for updating the blog date when a published post is deleted.
+ *
+ * @since 3.4.0
+ *
+ * @param int $post_id Post ID
+ */
+function _update_blog_date_on_post_delete( $post_id ) {
+ $post = get_post( $post_id );
+
+ $post_type_obj = get_post_type_object( $post->post_type );
+ if ( ! $post_type_obj->public )
+ return;
+
+ if ( 'publish' != $post->post_status )
+ return;
+
+ wpmu_update_blogs_date();
+}
+
diff --git a/src/wp-includes/ms-default-constants.php b/src/wp-includes/ms-default-constants.php
new file mode 100644
index 0000000000..53dfc9b55c
--- /dev/null
+++ b/src/wp-includes/ms-default-constants.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * Defines constants and global variables that can be overridden, generally in wp-config.php.
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/**
+ * Defines Multisite upload constants.
+ *
+ * Exists for backward compatibility with legacy file-serving through
+ * wp-includes/ms-files.php (wp-content/blogs.php in MU).
+ *
+ * @since 3.0.0
+ */
+function ms_upload_constants() {
+ global $wpdb;
+
+ // This filter is attached in ms-default-filters.php but that file is not included during SHORTINIT.
+ add_filter( 'default_site_option_ms_files_rewriting', '__return_true' );
+
+ if ( ! get_site_option( 'ms_files_rewriting' ) )
+ return;
+
+ // Base uploads dir relative to ABSPATH
+ if ( !defined( 'UPLOADBLOGSDIR' ) )
+ define( 'UPLOADBLOGSDIR', 'wp-content/blogs.dir' );
+
+ // Note, the main site in a post-MU network uses wp-content/uploads.
+ // This is handled in wp_upload_dir() by ignoring UPLOADS for this case.
+ if ( ! defined( 'UPLOADS' ) ) {
+ define( 'UPLOADS', UPLOADBLOGSDIR . "/{$wpdb->blogid}/files/" );
+
+ // Uploads dir relative to ABSPATH
+ if ( 'wp-content/blogs.dir' == UPLOADBLOGSDIR && ! defined( 'BLOGUPLOADDIR' ) )
+ define( 'BLOGUPLOADDIR', WP_CONTENT_DIR . "/blogs.dir/{$wpdb->blogid}/files/" );
+ }
+}
+
+/**
+ * Defines Multisite cookie constants.
+ *
+ * @since 3.0.0
+ */
+function ms_cookie_constants( ) {
+ global $current_site;
+
+ /**
+ * @since 1.2.0
+ */
+ if ( !defined( 'COOKIEPATH' ) )
+ define( 'COOKIEPATH', $current_site->path );
+
+ /**
+ * @since 1.5.0
+ */
+ if ( !defined( 'SITECOOKIEPATH' ) )
+ define( 'SITECOOKIEPATH', $current_site->path );
+
+ /**
+ * @since 2.6.0
+ */
+ if ( !defined( 'ADMIN_COOKIE_PATH' ) ) {
+ if ( ! is_subdomain_install() || trim( parse_url( get_option( 'siteurl' ), PHP_URL_PATH ), '/' ) ) {
+ define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH );
+ } else {
+ define( 'ADMIN_COOKIE_PATH', SITECOOKIEPATH . 'wp-admin' );
+ }
+ }
+
+ /**
+ * @since 2.0.0
+ */
+ if ( !defined('COOKIE_DOMAIN') && is_subdomain_install() ) {
+ if ( !empty( $current_site->cookie_domain ) )
+ define('COOKIE_DOMAIN', '.' . $current_site->cookie_domain);
+ else
+ define('COOKIE_DOMAIN', '.' . $current_site->domain);
+ }
+}
+
+/**
+ * Defines Multisite file constants.
+ *
+ * Exists for backward compatibility with legacy file-serving through
+ * wp-includes/ms-files.php (wp-content/blogs.php in MU).
+ *
+ * @since 3.0.0
+ */
+function ms_file_constants() {
+ /**
+ * Optional support for X-Sendfile header
+ * @since 3.0.0
+ */
+ if ( !defined( 'WPMU_SENDFILE' ) )
+ define( 'WPMU_SENDFILE', false );
+
+ /**
+ * Optional support for X-Accel-Redirect header
+ * @since 3.0.0
+ */
+ if ( !defined( 'WPMU_ACCEL_REDIRECT' ) )
+ define( 'WPMU_ACCEL_REDIRECT', false );
+}
+
+/**
+ * Defines Multisite subdomain constants and handles warnings and notices.
+ *
+ * VHOST is deprecated in favor of SUBDOMAIN_INSTALL, which is a bool.
+ *
+ * On first call, the constants are checked and defined. On second call,
+ * we will have translations loaded and can trigger warnings easily.
+ *
+ * @since 3.0.0
+ */
+function ms_subdomain_constants() {
+ static $error = null;
+ static $error_warn = false;
+
+ if ( false === $error )
+ return;
+
+ if ( $error ) {
+ $vhost_deprecated = __( 'The constant <code>VHOST</code> <strong>is deprecated</strong>. Use the boolean constant <code>SUBDOMAIN_INSTALL</code> in wp-config.php to enable a subdomain configuration. Use is_subdomain_install() to check whether a subdomain configuration is enabled.' );
+ if ( $error_warn ) {
+ trigger_error( __( '<strong>Conflicting values for the constants VHOST and SUBDOMAIN_INSTALL.</strong> The value of SUBDOMAIN_INSTALL will be assumed to be your subdomain configuration setting.' ) . ' ' . $vhost_deprecated, E_USER_WARNING );
+ } else {
+ _deprecated_argument( 'define()', '3.0', $vhost_deprecated );
+ }
+ return;
+ }
+
+ if ( defined( 'SUBDOMAIN_INSTALL' ) && defined( 'VHOST' ) ) {
+ if ( SUBDOMAIN_INSTALL == ( 'yes' == VHOST ) ) {
+ $error = true;
+ } else {
+ $error = $error_warn = true;
+ }
+ } elseif ( defined( 'SUBDOMAIN_INSTALL' ) ) {
+ define( 'VHOST', SUBDOMAIN_INSTALL ? 'yes' : 'no' );
+ } elseif ( defined( 'VHOST' ) ) {
+ $error = true;
+ define( 'SUBDOMAIN_INSTALL', 'yes' == VHOST );
+ } else {
+ define( 'SUBDOMAIN_INSTALL', false );
+ define( 'VHOST', 'no' );
+ }
+}
+add_action( 'init', 'ms_subdomain_constants' );
diff --git a/src/wp-includes/ms-default-filters.php b/src/wp-includes/ms-default-filters.php
new file mode 100644
index 0000000000..c4c223a4f7
--- /dev/null
+++ b/src/wp-includes/ms-default-filters.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Sets up the default filters and actions for Multisite.
+ *
+ * If you need to remove a default hook, this file will give you the priority
+ * for which to use to remove the hook.
+ *
+ * Not all of the Multisite default hooks are found in ms-default-filters.php
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @see default-filters.php
+ * @since 3.0.0
+ */
+
+// Users
+add_filter( 'wpmu_validate_user_signup', 'signup_nonce_check' );
+add_action( 'init', 'maybe_add_existing_user_to_blog' );
+add_action( 'wpmu_new_user', 'newuser_notify_siteadmin' );
+add_action( 'wpmu_activate_user', 'add_new_user_to_blog', 10, 3 );
+add_action( 'sanitize_user', 'strtolower' );
+
+// Blogs
+add_filter( 'wpmu_validate_blog_signup', 'signup_nonce_check' );
+add_action( 'wpmu_new_blog', 'wpmu_log_new_registrations', 10, 2 );
+add_action( 'wpmu_new_blog', 'newblog_notify_siteadmin', 10, 2 );
+
+// Register Nonce
+add_action( 'signup_hidden_fields', 'signup_nonce_fields' );
+
+// Template
+add_action( 'template_redirect', 'maybe_redirect_404' );
+add_filter( 'allowed_redirect_hosts', 'redirect_this_site' );
+
+// Administration
+add_filter( 'term_id_filter', 'global_terms', 10, 2 );
+add_action( 'publish_post', 'update_posts_count' );
+add_action( 'delete_post', '_update_blog_date_on_post_delete' );
+add_action( 'transition_post_status', '_update_blog_date_on_post_publish', 10, 3 );
+add_action( 'admin_init', 'wp_schedule_update_network_counts');
+add_action( 'update_network_counts', 'wp_update_network_counts');
+
+// Files
+add_filter( 'wp_upload_bits', 'upload_is_file_too_big' );
+add_filter( 'import_upload_size_limit', 'fix_import_form_size' );
+add_filter( 'upload_mimes', 'check_upload_mimes' );
+add_filter( 'upload_size_limit', 'upload_size_limit_filter' );
+add_action( 'upload_ui_over_quota', 'multisite_over_quota_message' );
+
+// Mail
+add_action( 'phpmailer_init', 'fix_phpmailer_messageid' );
+
+// Disable somethings by default for multisite
+add_filter( 'enable_update_services_configuration', '__return_false' );
+if ( ! defined('POST_BY_EMAIL') || ! POST_BY_EMAIL ) // back compat constant.
+ add_filter( 'enable_post_by_email_configuration', '__return_false' );
+if ( ! defined('EDIT_ANY_USER') || ! EDIT_ANY_USER ) // back compat constant.
+ add_filter( 'enable_edit_any_user_configuration', '__return_false' );
+add_filter( 'force_filtered_html_on_import', '__return_true' );
+
+// WP_HOME and WP_SITEURL should not have any effect in MS
+remove_filter( 'option_siteurl', '_config_wp_siteurl' );
+remove_filter( 'option_home', '_config_wp_home' );
+
+// If the network upgrade hasn't run yet, assume ms-files.php rewriting is used.
+add_filter( 'default_site_option_ms_files_rewriting', '__return_true' );
+
+// Whitelist multisite domains for HTTP requests
+add_filter( 'http_request_host_is_external', 'ms_allowed_http_request_hosts', 20, 2 );
diff --git a/src/wp-includes/ms-deprecated.php b/src/wp-includes/ms-deprecated.php
new file mode 100644
index 0000000000..e5b916cccb
--- /dev/null
+++ b/src/wp-includes/ms-deprecated.php
@@ -0,0 +1,318 @@
+<?php
+/**
+ * Deprecated functions from WordPress MU and the multisite feature. You shouldn't
+ * use these functions and look for the alternatives instead. The functions will be
+ * removed in a later version.
+ *
+ * @package WordPress
+ * @subpackage Deprecated
+ * @since 3.0.0
+ */
+
+/*
+ * Deprecated functions come here to die.
+ */
+
+/**
+ * Get the "dashboard blog", the blog where users without a blog edit their profile data.
+ * Dashboard blog functionality was removed in WordPress 3.1, replaced by the user admin.
+ *
+ * @since MU
+ * @deprecated 3.1.0
+ * @see get_blog_details()
+ * @return int
+ */
+function get_dashboard_blog() {
+ _deprecated_function( __FUNCTION__, '3.1' );
+ if ( $blog = get_site_option( 'dashboard_blog' ) )
+ return get_blog_details( $blog );
+
+ return get_blog_details( $GLOBALS['current_site']->blog_id );
+}
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use wp_generate_password()
+ * @see wp_generate_password()
+ */
+function generate_random_password( $len = 8 ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'wp_generate_password()' );
+ return wp_generate_password( $len );
+}
+
+/**
+ * Determine if user is a site admin.
+ *
+ * Plugins should use is_multisite() instead of checking if this function exists
+ * to determine if multisite is enabled.
+ *
+ * This function must reside in a file included only if is_multisite() due to
+ * legacy function_exists() checks to determine if multisite is enabled.
+ *
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use is_super_admin()
+ * @see is_super_admin()
+ * @see is_multisite()
+ *
+ */
+function is_site_admin( $user_login = '' ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'is_super_admin()' );
+
+ if ( empty( $user_login ) ) {
+ $user_id = get_current_user_id();
+ if ( !$user_id )
+ return false;
+ } else {
+ $user = get_user_by( 'login', $user_login );
+ if ( ! $user->exists() )
+ return false;
+ $user_id = $user->ID;
+ }
+
+ return is_super_admin( $user_id );
+}
+
+if ( !function_exists( 'graceful_fail' ) ) :
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use wp_die()
+ * @see wp_die()
+ */
+function graceful_fail( $message ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'wp_die()' );
+ $message = apply_filters( 'graceful_fail', $message );
+ $message_template = apply_filters( 'graceful_fail_template',
+'<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml"><head profile="http://gmpg.org/xfn/11">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>Error!</title>
+<style type="text/css">
+img {
+ border: 0;
+}
+body {
+line-height: 1.6em; font-family: Georgia, serif; width: 390px; margin: auto;
+text-align: center;
+}
+.message {
+ font-size: 22px;
+ width: 350px;
+ margin: auto;
+}
+</style>
+</head>
+<body>
+<p class="message">%s</p>
+</body>
+</html>' );
+ die( sprintf( $message_template, $message ) );
+}
+endif;
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use get_user_by()
+ * @see get_user_by()
+ */
+function get_user_details( $username ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'get_user_by()' );
+ return get_user_by('login', $username);
+}
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use clean_post_cache()
+ * @see clean_post_cache()
+ */
+function clear_global_post_cache( $post_id ) {
+ _deprecated_function( __FUNCTION__, '3.0', 'clean_post_cache()' );
+}
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use is_main_site()
+ * @see is_main_site()
+ */
+function is_main_blog() {
+ _deprecated_function( __FUNCTION__, '3.0', 'is_main_site()' );
+ return is_main_site();
+}
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated Use is_email()
+ * @see is_email()
+ */
+function validate_email( $email, $check_domain = true) {
+ _deprecated_function( __FUNCTION__, '3.0', 'is_email()' );
+ return is_email( $email, $check_domain );
+}
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated No alternative available. For performance reasons this function is not recommended.
+ */
+function get_blog_list( $start = 0, $num = 10, $deprecated = '' ) {
+ _deprecated_function( __FUNCTION__, '3.0' );
+
+ global $wpdb;
+ $blogs = $wpdb->get_results( $wpdb->prepare("SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND mature = '0' AND spam = '0' AND deleted = '0' ORDER BY registered DESC", $wpdb->siteid), ARRAY_A );
+
+ foreach ( (array) $blogs as $details ) {
+ $blog_list[ $details['blog_id'] ] = $details;
+ $blog_list[ $details['blog_id'] ]['postcount'] = $wpdb->get_var( "SELECT COUNT(ID) FROM " . $wpdb->get_blog_prefix( $details['blog_id'] ). "posts WHERE post_status='publish' AND post_type='post'" );
+ }
+ unset( $blogs );
+ $blogs = $blog_list;
+
+ if ( false == is_array( $blogs ) )
+ return array();
+
+ if ( $num == 'all' )
+ return array_slice( $blogs, $start, count( $blogs ) );
+ else
+ return array_slice( $blogs, $start, $num );
+}
+
+/**
+ * @since MU
+ * @deprecated 3.0.0
+ * @deprecated No alternative available. For performance reasons this function is not recommended.
+ */
+function get_most_active_blogs( $num = 10, $display = true ) {
+ _deprecated_function( __FUNCTION__, '3.0' );
+
+ $blogs = get_blog_list( 0, 'all', false ); // $blog_id -> $details
+ if ( is_array( $blogs ) ) {
+ reset( $blogs );
+ foreach ( (array) $blogs as $key => $details ) {
+ $most_active[ $details['blog_id'] ] = $details['postcount'];
+ $blog_list[ $details['blog_id'] ] = $details; // array_slice() removes keys!!
+ }
+ arsort( $most_active );
+ reset( $most_active );
+ foreach ( (array) $most_active as $key => $details )
+ $t[ $key ] = $blog_list[ $key ];
+
+ unset( $most_active );
+ $most_active = $t;
+ }
+
+ if ( $display == true ) {
+ if ( is_array( $most_active ) ) {
+ reset( $most_active );
+ foreach ( (array) $most_active as $key => $details ) {
+ $url = esc_url('http://' . $details['domain'] . $details['path']);
+ echo '<li>' . $details['postcount'] . " <a href='$url'>$url</a></li>";
+ }
+ }
+ }
+ return array_slice( $most_active, 0, $num );
+}
+
+/**
+ * Redirect a user based on $_GET or $_POST arguments.
+ *
+ * The function looks for redirect arguments in the following order:
+ * 1) $_GET['ref']
+ * 2) $_POST['ref']
+ * 3) $_SERVER['HTTP_REFERER']
+ * 4) $_GET['redirect']
+ * 5) $_POST['redirect']
+ * 6) $url
+ *
+ * @since MU
+ * @deprecated 3.3.0
+ * @deprecated Use wp_redirect()
+ * @uses wpmu_admin_redirect_add_updated_param()
+ *
+ * @param string $url
+ */
+function wpmu_admin_do_redirect( $url = '' ) {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ $ref = '';
+ if ( isset( $_GET['ref'] ) )
+ $ref = $_GET['ref'];
+ if ( isset( $_POST['ref'] ) )
+ $ref = $_POST['ref'];
+
+ if ( $ref ) {
+ $ref = wpmu_admin_redirect_add_updated_param( $ref );
+ wp_redirect( $ref );
+ exit();
+ }
+ if ( empty( $_SERVER['HTTP_REFERER'] ) == false ) {
+ wp_redirect( $_SERVER['HTTP_REFERER'] );
+ exit();
+ }
+
+ $url = wpmu_admin_redirect_add_updated_param( $url );
+ if ( isset( $_GET['redirect'] ) ) {
+ if ( substr( $_GET['redirect'], 0, 2 ) == 's_' )
+ $url .= '&action=blogs&s='. esc_html( substr( $_GET['redirect'], 2 ) );
+ } elseif ( isset( $_POST['redirect'] ) ) {
+ $url = wpmu_admin_redirect_add_updated_param( $_POST['redirect'] );
+ }
+ wp_redirect( $url );
+ exit();
+}
+
+/**
+ * Adds an 'updated=true' argument to a URL.
+ *
+ * @since MU
+ * @deprecated 3.3.0
+ * @deprecated Use add_query_arg()
+ *
+ * @param string $url
+ * @return string
+ */
+function wpmu_admin_redirect_add_updated_param( $url = '' ) {
+ _deprecated_function( __FUNCTION__, '3.3' );
+
+ if ( strpos( $url, 'updated=true' ) === false ) {
+ if ( strpos( $url, '?' ) === false )
+ return $url . '?updated=true';
+ else
+ return $url . '&updated=true';
+ }
+ return $url;
+}
+
+/**
+ * Get a numeric user ID from either an email address or a login.
+ *
+ * A numeric string is considered to be an existing user ID
+ * and is simply returned as such.
+ *
+ * @since MU
+ * @deprecated 3.6.0
+ * @deprecated Use get_user_by()
+ * @uses get_user_by()
+ *
+ * @param string $string Either an email address or a login.
+ * @return int
+ */
+function get_user_id_from_string( $string ) {
+ _deprecated_function( __FUNCTION__, '3.6', 'get_user_by()' );
+
+ if ( is_email( $string ) )
+ $user = get_user_by( 'email', $string );
+ elseif ( is_numeric( $string ) )
+ return $string;
+ else
+ $user = get_user_by( 'login', $string );
+
+ if ( $user )
+ return $user->ID;
+ return 0;
+}
diff --git a/src/wp-includes/ms-files.php b/src/wp-includes/ms-files.php
new file mode 100644
index 0000000000..de6d15dbdd
--- /dev/null
+++ b/src/wp-includes/ms-files.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Multisite upload handler.
+ *
+ * @since 3.0.0
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ */
+
+define( 'SHORTINIT', true );
+require_once( dirname( dirname( __FILE__ ) ) . '/wp-load.php' );
+
+if( !is_multisite() )
+ die( 'Multisite support not enabled' );
+
+ms_file_constants();
+
+error_reporting( 0 );
+
+if ( $current_blog->archived == '1' || $current_blog->spam == '1' || $current_blog->deleted == '1' ) {
+ status_header( 404 );
+ die( '404 &#8212; File not found.' );
+}
+
+$file = rtrim( BLOGUPLOADDIR, '/' ) . '/' . str_replace( '..', '', $_GET[ 'file' ] );
+if ( !is_file( $file ) ) {
+ status_header( 404 );
+ die( '404 &#8212; File not found.' );
+}
+
+$mime = wp_check_filetype( $file );
+if( false === $mime[ 'type' ] && function_exists( 'mime_content_type' ) )
+ $mime[ 'type' ] = mime_content_type( $file );
+
+if( $mime[ 'type' ] )
+ $mimetype = $mime[ 'type' ];
+else
+ $mimetype = 'image/' . substr( $file, strrpos( $file, '.' ) + 1 );
+
+header( 'Content-Type: ' . $mimetype ); // always send this
+if ( false === strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS' ) )
+ header( 'Content-Length: ' . filesize( $file ) );
+
+// Optional support for X-Sendfile and X-Accel-Redirect
+if ( WPMU_ACCEL_REDIRECT ) {
+ header( 'X-Accel-Redirect: ' . str_replace( WP_CONTENT_DIR, '', $file ) );
+ exit;
+} elseif ( WPMU_SENDFILE ) {
+ header( 'X-Sendfile: ' . $file );
+ exit;
+}
+
+$last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file ) );
+$etag = '"' . md5( $last_modified ) . '"';
+header( "Last-Modified: $last_modified GMT" );
+header( 'ETag: ' . $etag );
+header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 100000000 ) . ' GMT' );
+
+// Support for Conditional GET - use stripslashes to avoid formatting.php dependency
+$client_etag = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? stripslashes( $_SERVER['HTTP_IF_NONE_MATCH'] ) : false;
+
+if( ! isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) )
+ $_SERVER['HTTP_IF_MODIFIED_SINCE'] = false;
+
+$client_last_modified = trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
+// If string is empty, return 0. If not, attempt to parse into a timestamp
+$client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
+
+// Make a timestamp for our most recent modification...
+$modified_timestamp = strtotime($last_modified);
+
+if ( ( $client_last_modified && $client_etag )
+ ? ( ( $client_modified_timestamp >= $modified_timestamp) && ( $client_etag == $etag ) )
+ : ( ( $client_modified_timestamp >= $modified_timestamp) || ( $client_etag == $etag ) )
+ ) {
+ status_header( 304 );
+ exit;
+}
+
+// If we made it this far, just serve the file
+readfile( $file );
diff --git a/src/wp-includes/ms-functions.php b/src/wp-includes/ms-functions.php
new file mode 100644
index 0000000000..f29152a3d4
--- /dev/null
+++ b/src/wp-includes/ms-functions.php
@@ -0,0 +1,1982 @@
+<?php
+/**
+ * Multisite WordPress API
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/**
+ * Gets the network's site and user counts.
+ *
+ * @since MU 1.0
+ * @uses get_blog_count()
+ * @uses get_user_count()
+ *
+ * @return array Site and user count for the network.
+ */
+function get_sitestats() {
+ global $wpdb;
+
+ $stats = array(
+ 'blogs' => get_blog_count(),
+ 'users' => get_user_count(),
+ );
+
+ return $stats;
+}
+
+/**
+ * Get the admin for a domain/path combination.
+ *
+ * @since MU 1.0
+ *
+ * @param string $sitedomain Optional. Site domain.
+ * @param string $path Optional. Site path.
+ * @return array The network admins
+ */
+function get_admin_users_for_domain( $sitedomain = '', $path = '' ) {
+ global $wpdb;
+
+ if ( ! $sitedomain )
+ $site_id = $wpdb->siteid;
+ else
+ $site_id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->site WHERE domain = %s AND path = %s", $sitedomain, $path ) );
+
+ if ( $site_id )
+ return $wpdb->get_results( $wpdb->prepare( "SELECT u.ID, u.user_login, u.user_pass FROM $wpdb->users AS u, $wpdb->sitemeta AS sm WHERE sm.meta_key = 'admin_user_id' AND u.ID = sm.meta_value AND sm.site_id = %d", $site_id ), ARRAY_A );
+
+ return false;
+}
+
+/**
+ * Get one of a user's active blogs
+ *
+ * Returns the user's primary blog, if she has one and
+ * it is active. If it's inactive, function returns another
+ * active blog of the user. If none are found, the user
+ * is added as a Subscriber to the Dashboard Blog and that blog
+ * is returned.
+ *
+ * @since MU 1.0
+ * @uses get_blogs_of_user()
+ * @uses add_user_to_blog()
+ * @uses get_blog_details()
+ *
+ * @param int $user_id The unique ID of the user
+ * @return object The blog object
+ */
+function get_active_blog_for_user( $user_id ) {
+ global $wpdb;
+ $blogs = get_blogs_of_user( $user_id );
+ if ( empty( $blogs ) )
+ return null;
+
+ if ( !is_multisite() )
+ return $blogs[$wpdb->blogid];
+
+ $primary_blog = get_user_meta( $user_id, 'primary_blog', true );
+ $first_blog = current($blogs);
+ if ( false !== $primary_blog ) {
+ if ( ! isset( $blogs[ $primary_blog ] ) ) {
+ update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
+ $primary = get_blog_details( $first_blog->userblog_id );
+ } else {
+ $primary = get_blog_details( $primary_blog );
+ }
+ } else {
+ //TODO Review this call to add_user_to_blog too - to get here the user must have a role on this blog?
+ add_user_to_blog( $first_blog->userblog_id, $user_id, 'subscriber' );
+ update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
+ $primary = $first_blog;
+ }
+
+ if ( ( ! is_object( $primary ) ) || ( $primary->archived == 1 || $primary->spam == 1 || $primary->deleted == 1 ) ) {
+ $blogs = get_blogs_of_user( $user_id, true ); // if a user's primary blog is shut down, check their other blogs.
+ $ret = false;
+ if ( is_array( $blogs ) && count( $blogs ) > 0 ) {
+ foreach ( (array) $blogs as $blog_id => $blog ) {
+ if ( $blog->site_id != $wpdb->siteid )
+ continue;
+ $details = get_blog_details( $blog_id );
+ if ( is_object( $details ) && $details->archived == 0 && $details->spam == 0 && $details->deleted == 0 ) {
+ $ret = $blog;
+ if ( get_user_meta( $user_id , 'primary_blog', true ) != $blog_id )
+ update_user_meta( $user_id, 'primary_blog', $blog_id );
+ if ( !get_user_meta($user_id , 'source_domain', true) )
+ update_user_meta( $user_id, 'source_domain', $blog->domain );
+ break;
+ }
+ }
+ } else {
+ return null;
+ }
+ return $ret;
+ } else {
+ return $primary;
+ }
+}
+
+/**
+ * The number of active users in your installation.
+ *
+ * The count is cached and updated twice daily. This is not a live count.
+ *
+ * @since MU 2.7
+ *
+ * @return int
+ */
+function get_user_count() {
+ return get_site_option( 'user_count' );
+}
+
+/**
+ * The number of active sites on your installation.
+ *
+ * The count is cached and updated twice daily. This is not a live count.
+ *
+ * @since MU 1.0
+ *
+ * @param int $id Optional. A site_id.
+ * @return int
+ */
+function get_blog_count( $id = 0 ) {
+ return get_site_option( 'blog_count' );
+}
+
+/**
+ * Get a blog post from any site on the network.
+ *
+ * @since MU 1.0
+ *
+ * @param int $blog_id ID of the blog.
+ * @param int $post_id ID of the post you're looking for.
+ * @return WP_Post|null WP_Post on success or null on failure
+ */
+function get_blog_post( $blog_id, $post_id ) {
+ switch_to_blog( $blog_id );
+ $post = get_post( $post_id );
+ restore_current_blog();
+
+ return $post;
+}
+
+/**
+ * Add a user to a blog.
+ *
+ * Use the 'add_user_to_blog' action to fire an event when
+ * users are added to a blog.
+ *
+ * @since MU 1.0
+ *
+ * @param int $blog_id ID of the blog you're adding the user to.
+ * @param int $user_id ID of the user you're adding.
+ * @param string $role The role you want the user to have
+ * @return bool
+ */
+function add_user_to_blog( $blog_id, $user_id, $role ) {
+ switch_to_blog($blog_id);
+
+ $user = get_userdata( $user_id );
+
+ if ( ! $user ) {
+ restore_current_blog();
+ return new WP_Error( 'user_does_not_exist', __( 'The requested user does not exist.' ) );
+ }
+
+ if ( !get_user_meta($user_id, 'primary_blog', true) ) {
+ update_user_meta($user_id, 'primary_blog', $blog_id);
+ $details = get_blog_details($blog_id);
+ update_user_meta($user_id, 'source_domain', $details->domain);
+ }
+
+ $user->set_role($role);
+
+ do_action('add_user_to_blog', $user_id, $role, $blog_id);
+ wp_cache_delete( $user_id, 'users' );
+ restore_current_blog();
+ return true;
+}
+
+/**
+ * Remove a user from a blog.
+ *
+ * Use the 'remove_user_from_blog' action to fire an event when
+ * users are removed from a blog.
+ *
+ * Accepts an optional $reassign parameter, if you want to
+ * reassign the user's blog posts to another user upon removal.
+ *
+ * @since MU 1.0
+ *
+ * @param int $user_id ID of the user you're removing.
+ * @param int $blog_id ID of the blog you're removing the user from.
+ * @param string $reassign Optional. A user to whom to reassign posts.
+ * @return bool
+ */
+function remove_user_from_blog($user_id, $blog_id = '', $reassign = '') {
+ global $wpdb;
+ switch_to_blog($blog_id);
+ $user_id = (int) $user_id;
+ do_action('remove_user_from_blog', $user_id, $blog_id);
+
+ // If being removed from the primary blog, set a new primary if the user is assigned
+ // to multiple blogs.
+ $primary_blog = get_user_meta($user_id, 'primary_blog', true);
+ if ( $primary_blog == $blog_id ) {
+ $new_id = '';
+ $new_domain = '';
+ $blogs = get_blogs_of_user($user_id);
+ foreach ( (array) $blogs as $blog ) {
+ if ( $blog->userblog_id == $blog_id )
+ continue;
+ $new_id = $blog->userblog_id;
+ $new_domain = $blog->domain;
+ break;
+ }
+
+ update_user_meta($user_id, 'primary_blog', $new_id);
+ update_user_meta($user_id, 'source_domain', $new_domain);
+ }
+
+ // wp_revoke_user($user_id);
+ $user = get_userdata( $user_id );
+ if ( ! $user ) {
+ restore_current_blog();
+ return new WP_Error('user_does_not_exist', __('That user does not exist.'));
+ }
+
+ $user->remove_all_caps();
+
+ $blogs = get_blogs_of_user($user_id);
+ if ( count($blogs) == 0 ) {
+ update_user_meta($user_id, 'primary_blog', '');
+ update_user_meta($user_id, 'source_domain', '');
+ }
+
+ if ( $reassign != '' ) {
+ $reassign = (int) $reassign;
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET post_author = %d WHERE post_author = %d", $reassign, $user_id) );
+ $wpdb->query( $wpdb->prepare("UPDATE $wpdb->links SET link_owner = %d WHERE link_owner = %d", $reassign, $user_id) );
+ }
+
+ restore_current_blog();
+
+ return true;
+}
+
+/**
+ * Create an empty blog.
+ *
+ * @since MU 1.0
+ * @uses install_blog()
+ *
+ * @param string $domain The new blog's domain.
+ * @param string $path The new blog's path.
+ * @param string $weblog_title The new blog's title.
+ * @param int $site_id Optional. Defaults to 1.
+ * @return int The ID of the newly created blog
+ */
+function create_empty_blog( $domain, $path, $weblog_title, $site_id = 1 ) {
+ if ( empty($path) )
+ $path = '/';
+
+ // Check if the domain has been used already. We should return an error message.
+ if ( domain_exists($domain, $path, $site_id) )
+ return __( '<strong>ERROR</strong>: Site URL already taken.' );
+
+ // Need to back up wpdb table names, and create a new wp_blogs entry for new blog.
+ // Need to get blog_id from wp_blogs, and create new table names.
+ // Must restore table names at the end of function.
+
+ if ( ! $blog_id = insert_blog($domain, $path, $site_id) )
+ return __( '<strong>ERROR</strong>: problem creating site entry.' );
+
+ switch_to_blog($blog_id);
+ install_blog($blog_id);
+ restore_current_blog();
+
+ return $blog_id;
+}
+
+/**
+ * Get the permalink for a post on another blog.
+ *
+ * @since MU 1.0
+ *
+ * @param int $blog_id ID of the source blog.
+ * @param int $post_id ID of the desired post.
+ * @return string The post's permalink
+ */
+function get_blog_permalink( $blog_id, $post_id ) {
+ switch_to_blog( $blog_id );
+ $link = get_permalink( $post_id );
+ restore_current_blog();
+
+ return $link;
+}
+
+/**
+ * Get a blog's numeric ID from its URL.
+ *
+ * On a subdirectory installation like example.com/blog1/,
+ * $domain will be the root 'example.com' and $path the
+ * subdirectory '/blog1/'. With subdomains like blog1.example.com,
+ * $domain is 'blog1.example.com' and $path is '/'.
+ *
+ * @since MU 2.6.5
+ *
+ * @param string $domain
+ * @param string $path Optional. Not required for subdomain installations.
+ * @return int 0 if no blog found, otherwise the ID of the matching blog
+ */
+function get_blog_id_from_url( $domain, $path = '/' ) {
+ global $wpdb;
+
+ $domain = strtolower( $domain );
+ $path = strtolower( $path );
+ $id = wp_cache_get( md5( $domain . $path ), 'blog-id-cache' );
+
+ if ( $id == -1 ) // blog does not exist
+ return 0;
+ elseif ( $id )
+ return (int) $id;
+
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s and path = %s /* get_blog_id_from_url */", $domain, $path ) );
+
+ if ( ! $id ) {
+ wp_cache_set( md5( $domain . $path ), -1, 'blog-id-cache' );
+ return 0;
+ }
+
+ wp_cache_set( md5( $domain . $path ), $id, 'blog-id-cache' );
+
+ return $id;
+}
+
+// Admin functions
+
+/**
+ * Checks an email address against a list of banned domains.
+ *
+ * This function checks against the Banned Email Domains list
+ * at wp-admin/network/settings.php. The check is only run on
+ * self-registrations; user creation at wp-admin/network/users.php
+ * bypasses this check.
+ *
+ * @since MU
+ *
+ * @param string $user_email The email provided by the user at registration.
+ * @return bool Returns true when the email address is banned.
+ */
+function is_email_address_unsafe( $user_email ) {
+ $banned_names = get_site_option( 'banned_email_domains' );
+ if ( $banned_names && ! is_array( $banned_names ) )
+ $banned_names = explode( "\n", $banned_names );
+
+ $is_email_address_unsafe = false;
+
+ if ( $banned_names && is_array( $banned_names ) ) {
+ list( $email_local_part, $email_domain ) = explode( '@', $user_email );
+
+ foreach ( $banned_names as $banned_domain ) {
+ if ( ! $banned_domain )
+ continue;
+
+ if ( $email_domain == $banned_domain ) {
+ $is_email_address_unsafe = true;
+ break;
+ }
+
+ $dotted_domain = ".$banned_domain";
+ if ( $dotted_domain === substr( $user_email, -strlen( $dotted_domain ) ) ) {
+ $is_email_address_unsafe = true;
+ break;
+ }
+ }
+ }
+
+ return apply_filters( 'is_email_address_unsafe', $is_email_address_unsafe, $user_email );
+}
+
+/**
+ * Processes new user registrations.
+ *
+ * Checks the data provided by the user during signup. Verifies
+ * the validity and uniqueness of user names and user email addresses,
+ * and checks email addresses against admin-provided domain
+ * whitelists and blacklists.
+ *
+ * The hook 'wpmu_validate_user_signup' provides an easy way
+ * to modify the signup process. The value $result, which is passed
+ * to the hook, contains both the user-provided info and the error
+ * messages created by the function. 'wpmu_validate_user_signup' allows
+ * you to process the data in any way you'd like, and unset the
+ * relevant errors if necessary.
+ *
+ * @since MU
+ * @uses is_email_address_unsafe()
+ * @uses username_exists()
+ * @uses email_exists()
+ *
+ * @param string $user_name The login name provided by the user.
+ * @param string $user_email The email provided by the user.
+ * @return array Contains username, email, and error messages.
+ */
+function wpmu_validate_user_signup($user_name, $user_email) {
+ global $wpdb;
+
+ $errors = new WP_Error();
+
+ $orig_username = $user_name;
+ $user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
+
+ if ( $user_name != $orig_username || preg_match( '/[^a-z0-9]/', $user_name ) ) {
+ $errors->add( 'user_name', __( 'Only lowercase letters (a-z) and numbers are allowed.' ) );
+ $user_name = $orig_username;
+ }
+
+ $user_email = sanitize_email( $user_email );
+
+ if ( empty( $user_name ) )
+ $errors->add('user_name', __( 'Please enter a username.' ) );
+
+ $illegal_names = get_site_option( 'illegal_names' );
+ if ( is_array( $illegal_names ) == false ) {
+ $illegal_names = array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
+ add_site_option( 'illegal_names', $illegal_names );
+ }
+ if ( in_array( $user_name, $illegal_names ) == true )
+ $errors->add('user_name', __( 'That username is not allowed.' ) );
+
+ if ( is_email_address_unsafe( $user_email ) )
+ $errors->add('user_email', __('You cannot use that email address to signup. We are having problems with them blocking some of our email. Please use another email provider.'));
+
+ if ( strlen( $user_name ) < 4 )
+ $errors->add('user_name', __( 'Username must be at least 4 characters.' ) );
+
+ if ( strpos( ' ' . $user_name, '_' ) != false )
+ $errors->add( 'user_name', __( 'Sorry, usernames may not contain the character &#8220;_&#8221;!' ) );
+
+ // all numeric?
+ if ( preg_match( '/^[0-9]*$/', $user_name ) )
+ $errors->add('user_name', __('Sorry, usernames must have letters too!'));
+
+ if ( !is_email( $user_email ) )
+ $errors->add('user_email', __( 'Please enter a valid email address.' ) );
+
+ $limited_email_domains = get_site_option( 'limited_email_domains' );
+ if ( is_array( $limited_email_domains ) && empty( $limited_email_domains ) == false ) {
+ $emaildomain = substr( $user_email, 1 + strpos( $user_email, '@' ) );
+ if ( in_array( $emaildomain, $limited_email_domains ) == false )
+ $errors->add('user_email', __('Sorry, that email address is not allowed!'));
+ }
+
+ // Check if the username has been used already.
+ if ( username_exists($user_name) )
+ $errors->add( 'user_name', __( 'Sorry, that username already exists!' ) );
+
+ // Check if the email address has been used already.
+ if ( email_exists($user_email) )
+ $errors->add( 'user_email', __( 'Sorry, that email address is already used!' ) );
+
+ // Has someone already signed up for this username?
+ $signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_login = %s", $user_name) );
+ if ( $signup != null ) {
+ $registered_at = mysql2date('U', $signup->registered);
+ $now = current_time( 'timestamp', true );
+ $diff = $now - $registered_at;
+ // If registered more than two days ago, cancel registration and let this signup go through.
+ if ( $diff > 2 * DAY_IN_SECONDS )
+ $wpdb->delete( $wpdb->signups, array( 'user_login' => $user_name ) );
+ else
+ $errors->add('user_name', __('That username is currently reserved but may be available in a couple of days.'));
+ }
+
+ $signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE user_email = %s", $user_email) );
+ if ( $signup != null ) {
+ $diff = current_time( 'timestamp', true ) - mysql2date('U', $signup->registered);
+ // If registered more than two days ago, cancel registration and let this signup go through.
+ if ( $diff > 2 * DAY_IN_SECONDS )
+ $wpdb->delete( $wpdb->signups, array( 'user_email' => $user_email ) );
+ else
+ $errors->add('user_email', __('That email address has already been used. Please check your inbox for an activation email. It will become available in a couple of days if you do nothing.'));
+ }
+
+ $result = array('user_name' => $user_name, 'orig_username' => $orig_username, 'user_email' => $user_email, 'errors' => $errors);
+
+ return apply_filters('wpmu_validate_user_signup', $result);
+}
+
+/**
+ * Processes new site registrations.
+ *
+ * Checks the data provided by the user during blog signup. Verifies
+ * the validity and uniqueness of blog paths and domains.
+ *
+ * This function prevents the current user from registering a new site
+ * with a blogname equivalent to another user's login name. Passing the
+ * $user parameter to the function, where $user is the other user, is
+ * effectively an override of this limitation.
+ *
+ * Filter 'wpmu_validate_blog_signup' if you want to modify
+ * the way that WordPress validates new site signups.
+ *
+ * @since MU
+ * @uses domain_exists()
+ * @uses username_exists()
+ *
+ * @param string $blogname The blog name provided by the user. Must be unique.
+ * @param string $blog_title The blog title provided by the user.
+ * @return array Contains the new site data and error messages.
+ */
+function wpmu_validate_blog_signup($blogname, $blog_title, $user = '') {
+ global $wpdb, $domain, $current_site;
+
+ $base = $current_site->path;
+
+ $blog_title = strip_tags( $blog_title );
+ $blog_title = substr( $blog_title, 0, 50 );
+
+ $errors = new WP_Error();
+ $illegal_names = get_site_option( 'illegal_names' );
+ if ( $illegal_names == false ) {
+ $illegal_names = array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator' );
+ add_site_option( 'illegal_names', $illegal_names );
+ }
+
+ // On sub dir installs, Some names are so illegal, only a filter can spring them from jail
+ if (! is_subdomain_install() )
+ $illegal_names = array_merge($illegal_names, apply_filters( 'subdirectory_reserved_names', array( 'page', 'comments', 'blog', 'files', 'feed' ) ) );
+
+ if ( empty( $blogname ) )
+ $errors->add('blogname', __( 'Please enter a site name.' ) );
+
+ if ( preg_match( '/[^a-z0-9]+/', $blogname ) )
+ $errors->add('blogname', __( 'Only lowercase letters (a-z) and numbers are allowed.' ) );
+
+ if ( in_array( $blogname, $illegal_names ) == true )
+ $errors->add('blogname', __( 'That name is not allowed.' ) );
+
+ if ( strlen( $blogname ) < 4 && !is_super_admin() )
+ $errors->add('blogname', __( 'Site name must be at least 4 characters.' ) );
+
+ if ( strpos( $blogname, '_' ) !== false )
+ $errors->add( 'blogname', __( 'Sorry, site names may not contain the character &#8220;_&#8221;!' ) );
+
+ // do not allow users to create a blog that conflicts with a page on the main blog.
+ if ( !is_subdomain_install() && $wpdb->get_var( $wpdb->prepare( "SELECT post_name FROM " . $wpdb->get_blog_prefix( $current_site->blog_id ) . "posts WHERE post_type = 'page' AND post_name = %s", $blogname ) ) )
+ $errors->add( 'blogname', __( 'Sorry, you may not use that site name.' ) );
+
+ // all numeric?
+ if ( preg_match( '/^[0-9]*$/', $blogname ) )
+ $errors->add('blogname', __('Sorry, site names must have letters too!'));
+
+ $blogname = apply_filters( 'newblogname', $blogname );
+
+ $blog_title = wp_unslash( $blog_title );
+
+ if ( empty( $blog_title ) )
+ $errors->add('blog_title', __( 'Please enter a site title.' ) );
+
+ // Check if the domain/path has been used already.
+ if ( is_subdomain_install() ) {
+ $mydomain = $blogname . '.' . preg_replace( '|^www\.|', '', $domain );
+ $path = $base;
+ } else {
+ $mydomain = "$domain";
+ $path = $base.$blogname.'/';
+ }
+ if ( domain_exists($mydomain, $path, $current_site->id) )
+ $errors->add( 'blogname', __( 'Sorry, that site already exists!' ) );
+
+ if ( username_exists( $blogname ) ) {
+ if ( is_object( $user ) == false || ( is_object($user) && ( $user->user_login != $blogname ) ) )
+ $errors->add( 'blogname', __( 'Sorry, that site is reserved!' ) );
+ }
+
+ // Has someone already signed up for this domain?
+ $signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE domain = %s AND path = %s", $mydomain, $path) ); // TODO: Check email too?
+ if ( ! empty($signup) ) {
+ $diff = current_time( 'timestamp', true ) - mysql2date('U', $signup->registered);
+ // If registered more than two days ago, cancel registration and let this signup go through.
+ if ( $diff > 2 * DAY_IN_SECONDS )
+ $wpdb->delete( $wpdb->signups, array( 'domain' => $mydomain , 'path' => $path ) );
+ else
+ $errors->add('blogname', __('That site is currently reserved but may be available in a couple days.'));
+ }
+
+ $result = array('domain' => $mydomain, 'path' => $path, 'blogname' => $blogname, 'blog_title' => $blog_title, 'user' => $user, 'errors' => $errors);
+ return apply_filters('wpmu_validate_blog_signup', $result);
+}
+
+/**
+ * Record site signup information for future activation.
+ *
+ * @since MU
+ * @uses wpmu_signup_blog_notification()
+ *
+ * @param string $domain The requested domain.
+ * @param string $path The requested path.
+ * @param string $title The requested site title.
+ * @param string $user The user's requested login name.
+ * @param string $user_email The user's email address.
+ * @param array $meta By default, contains the requested privacy setting and lang_id.
+ */
+function wpmu_signup_blog($domain, $path, $title, $user, $user_email, $meta = '') {
+ global $wpdb;
+
+ $key = substr( md5( time() . rand() . $domain ), 0, 16 );
+ $meta = serialize($meta);
+
+ $wpdb->insert( $wpdb->signups, array(
+ 'domain' => $domain,
+ 'path' => $path,
+ 'title' => $title,
+ 'user_login' => $user,
+ 'user_email' => $user_email,
+ 'registered' => current_time('mysql', true),
+ 'activation_key' => $key,
+ 'meta' => $meta
+ ) );
+
+ wpmu_signup_blog_notification($domain, $path, $title, $user, $user_email, $key, $meta);
+}
+
+/**
+ * Record user signup information for future activation.
+ *
+ * This function is used when user registration is open but
+ * new site registration is not.
+ *
+ * @since MU
+ * @uses wpmu_signup_user_notification()
+ *
+ * @param string $user The user's requested login name.
+ * @param string $user_email The user's email address.
+ * @param array $meta By default, this is an empty array.
+ */
+function wpmu_signup_user($user, $user_email, $meta = '') {
+ global $wpdb;
+
+ // Format data
+ $user = preg_replace( '/\s+/', '', sanitize_user( $user, true ) );
+ $user_email = sanitize_email( $user_email );
+ $key = substr( md5( time() . rand() . $user_email ), 0, 16 );
+ $meta = serialize($meta);
+
+ $wpdb->insert( $wpdb->signups, array(
+ 'domain' => '',
+ 'path' => '',
+ 'title' => '',
+ 'user_login' => $user,
+ 'user_email' => $user_email,
+ 'registered' => current_time('mysql', true),
+ 'activation_key' => $key,
+ 'meta' => $meta
+ ) );
+
+ wpmu_signup_user_notification($user, $user_email, $key, $meta);
+}
+
+/**
+ * Notify user of signup success.
+ *
+ * This is the notification function used when site registration
+ * is enabled.
+ *
+ * Filter 'wpmu_signup_blog_notification' to bypass this function or
+ * replace it with your own notification behavior.
+ *
+ * Filter 'wpmu_signup_blog_notification_email' and
+ * 'wpmu_signup_blog_notification_subject' to change the content
+ * and subject line of the email sent to newly registered users.
+ *
+ * @since MU
+ *
+ * @param string $domain The new blog domain.
+ * @param string $path The new blog path.
+ * @param string $title The site title.
+ * @param string $user The user's login name.
+ * @param string $user_email The user's email address.
+ * @param array $meta By default, contains the requested privacy setting and lang_id.
+ * @param string $key The activation key created in wpmu_signup_blog()
+ * @return bool
+ */
+function wpmu_signup_blog_notification($domain, $path, $title, $user, $user_email, $key, $meta = '') {
+ global $current_site;
+
+ if ( !apply_filters('wpmu_signup_blog_notification', $domain, $path, $title, $user, $user_email, $key, $meta) )
+ return false;
+
+ // Send email with activation link.
+ if ( !is_subdomain_install() || $current_site->id != 1 )
+ $activate_url = network_site_url("wp-activate.php?key=$key");
+ else
+ $activate_url = "http://{$domain}{$path}wp-activate.php?key=$key"; // @todo use *_url() API
+
+ $activate_url = esc_url($activate_url);
+ $admin_email = get_site_option( 'admin_email' );
+ if ( $admin_email == '' )
+ $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
+ $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
+ $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+ $message = sprintf(
+ apply_filters( 'wpmu_signup_blog_notification_email',
+ __( "To activate your blog, please click the following link:\n\n%s\n\nAfter you activate, you will receive *another email* with your login.\n\nAfter you activate, you can visit your site here:\n\n%s" ),
+ $domain, $path, $title, $user, $user_email, $key, $meta
+ ),
+ $activate_url,
+ esc_url( "http://{$domain}{$path}" ),
+ $key
+ );
+ // TODO: Don't hard code activation link.
+ $subject = sprintf(
+ apply_filters( 'wpmu_signup_blog_notification_subject',
+ __( '[%1$s] Activate %2$s' ),
+ $domain, $path, $title, $user, $user_email, $key, $meta
+ ),
+ $from_name,
+ esc_url( 'http://' . $domain . $path )
+ );
+ wp_mail($user_email, $subject, $message, $message_headers);
+ return true;
+}
+
+/**
+ * Notify user of signup success.
+ *
+ * This is the notification function used when no new site has
+ * been requested.
+ *
+ * Filter 'wpmu_signup_user_notification' to bypass this function or
+ * replace it with your own notification behavior.
+ *
+ * Filter 'wpmu_signup_user_notification_email' and
+ * 'wpmu_signup_user_notification_subject' to change the content
+ * and subject line of the email sent to newly registered users.
+ *
+ * @since MU
+ *
+ * @param string $user The user's login name.
+ * @param string $user_email The user's email address.
+ * @param array $meta By default, an empty array.
+ * @param string $key The activation key created in wpmu_signup_user()
+ * @return bool
+ */
+function wpmu_signup_user_notification($user, $user_email, $key, $meta = '') {
+ if ( !apply_filters('wpmu_signup_user_notification', $user, $user_email, $key, $meta) )
+ return false;
+
+ // Send email with activation link.
+ $admin_email = get_site_option( 'admin_email' );
+ if ( $admin_email == '' )
+ $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
+ $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
+ $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+ $message = sprintf(
+ apply_filters( 'wpmu_signup_user_notification_email',
+ __( "To activate your user, please click the following link:\n\n%s\n\nAfter you activate, you will receive *another email* with your login." ),
+ $user, $user_email, $key, $meta
+ ),
+ site_url( "wp-activate.php?key=$key" )
+ );
+ // TODO: Don't hard code activation link.
+ $subject = sprintf(
+ apply_filters( 'wpmu_signup_user_notification_subject',
+ __( '[%1$s] Activate %2$s' ),
+ $user, $user_email, $key, $meta
+ ),
+ $from_name,
+ $user
+ );
+ wp_mail($user_email, $subject, $message, $message_headers);
+ return true;
+}
+
+/**
+ * Activate a signup.
+ *
+ * Hook to 'wpmu_activate_user' or 'wpmu_activate_blog' for events
+ * that should happen only when users or sites are self-created (since
+ * those actions are not called when users and sites are created
+ * by a Super Admin).
+ *
+ * @since MU
+ * @uses wp_generate_password()
+ * @uses wpmu_welcome_user_notification()
+ * @uses add_user_to_blog()
+ * @uses wpmu_create_user()
+ * @uses wpmu_create_blog()
+ * @uses wpmu_welcome_notification()
+ *
+ * @param string $key The activation key provided to the user.
+ * @return array An array containing information about the activated user and/or blog
+ */
+function wpmu_activate_signup($key) {
+ global $wpdb, $current_site;
+
+ $signup = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->signups WHERE activation_key = %s", $key) );
+
+ if ( empty( $signup ) )
+ return new WP_Error( 'invalid_key', __( 'Invalid activation key.' ) );
+
+ if ( $signup->active ) {
+ if ( empty( $signup->domain ) )
+ return new WP_Error( 'already_active', __( 'The user is already active.' ), $signup );
+ else
+ return new WP_Error( 'already_active', __( 'The site is already active.' ), $signup );
+ }
+
+ $meta = maybe_unserialize($signup->meta);
+ $password = wp_generate_password( 12, false );
+
+ $user_id = username_exists($signup->user_login);
+
+ if ( ! $user_id )
+ $user_id = wpmu_create_user($signup->user_login, $password, $signup->user_email);
+ else
+ $user_already_exists = true;
+
+ if ( ! $user_id )
+ return new WP_Error('create_user', __('Could not create user'), $signup);
+
+ $now = current_time('mysql', true);
+
+ if ( empty($signup->domain) ) {
+ $wpdb->update( $wpdb->signups, array('active' => 1, 'activated' => $now), array('activation_key' => $key) );
+
+ if ( isset( $user_already_exists ) )
+ return new WP_Error( 'user_already_exists', __( 'That username is already activated.' ), $signup);
+
+ wpmu_welcome_user_notification( $user_id, $password, $meta );
+ do_action( 'wpmu_activate_user', $user_id, $password, $meta );
+ return array( 'user_id' => $user_id, 'password' => $password, 'meta' => $meta );
+ }
+
+ $blog_id = wpmu_create_blog( $signup->domain, $signup->path, $signup->title, $user_id, $meta, $wpdb->siteid );
+
+ // TODO: What to do if we create a user but cannot create a blog?
+ if ( is_wp_error($blog_id) ) {
+ // If blog is taken, that means a previous attempt to activate this blog failed in between creating the blog and
+ // setting the activation flag. Let's just set the active flag and instruct the user to reset their password.
+ if ( 'blog_taken' == $blog_id->get_error_code() ) {
+ $blog_id->add_data( $signup );
+ $wpdb->update( $wpdb->signups, array( 'active' => 1, 'activated' => $now ), array( 'activation_key' => $key ) );
+ }
+ return $blog_id;
+ }
+
+ $wpdb->update( $wpdb->signups, array('active' => 1, 'activated' => $now), array('activation_key' => $key) );
+ wpmu_welcome_notification($blog_id, $user_id, $password, $signup->title, $meta);
+ do_action('wpmu_activate_blog', $blog_id, $user_id, $password, $signup->title, $meta);
+
+ return array('blog_id' => $blog_id, 'user_id' => $user_id, 'password' => $password, 'title' => $signup->title, 'meta' => $meta);
+}
+
+/**
+ * Create a user.
+ *
+ * This function runs when a user self-registers as well as when
+ * a Super Admin creates a new user. Hook to 'wpmu_new_user' for events
+ * that should affect all new users, but only on Multisite (otherwise
+ * use 'user_register').
+ *
+ * @since MU
+ * @uses wp_create_user()
+ *
+ * @param string $user_name The new user's login name.
+ * @param string $password The new user's password.
+ * @param string $email The new user's email address.
+ * @return mixed Returns false on failure, or int $user_id on success
+ */
+function wpmu_create_user( $user_name, $password, $email ) {
+ $user_name = preg_replace( '/\s+/', '', sanitize_user( $user_name, true ) );
+
+ $user_id = wp_create_user( $user_name, $password, $email );
+ if ( is_wp_error( $user_id ) )
+ return false;
+
+ $user = new WP_User( $user_id );
+
+ // Newly created users have no roles or caps until they are added to a blog.
+ delete_user_option( $user_id, $user->cap_key );
+ delete_user_option( $user_id, 'user_level' );
+
+ do_action( 'wpmu_new_user', $user_id );
+
+ return $user_id;
+}
+
+/**
+ * Create a site.
+ *
+ * This function runs when a user self-registers a new site as well
+ * as when a Super Admin creates a new site. Hook to 'wpmu_new_blog'
+ * for events that should affect all new sites.
+ *
+ * On subdirectory installs, $domain is the same as the main site's
+ * domain, and the path is the subdirectory name (eg 'example.com'
+ * and '/blog1/'). On subdomain installs, $domain is the new subdomain +
+ * root domain (eg 'blog1.example.com'), and $path is '/'.
+ *
+ * @since MU
+ * @uses domain_exists()
+ * @uses insert_blog()
+ * @uses wp_install_defaults()
+ * @uses add_user_to_blog()
+ *
+ * @param string $domain The new site's domain.
+ * @param string $path The new site's path.
+ * @param string $title The new site's title.
+ * @param int $user_id The user ID of the new site's admin.
+ * @param array $meta Optional. Used to set initial site options.
+ * @param int $site_id Optional. Only relevant on multi-network installs.
+ * @return mixed Returns WP_Error object on failure, int $blog_id on success
+ */
+function wpmu_create_blog($domain, $path, $title, $user_id, $meta = '', $site_id = 1) {
+ $domain = preg_replace( '/\s+/', '', sanitize_user( $domain, true ) );
+
+ if ( is_subdomain_install() )
+ $domain = str_replace( '@', '', $domain );
+
+ $title = strip_tags( $title );
+ $user_id = (int) $user_id;
+
+ if ( empty($path) )
+ $path = '/';
+
+ // Check if the domain has been used already. We should return an error message.
+ if ( domain_exists($domain, $path, $site_id) )
+ return new WP_Error( 'blog_taken', __( 'Sorry, that site already exists!' ) );
+
+ if ( !defined('WP_INSTALLING') )
+ define( 'WP_INSTALLING', true );
+
+ if ( ! $blog_id = insert_blog($domain, $path, $site_id) )
+ return new WP_Error('insert_blog', __('Could not create site.'));
+
+ switch_to_blog($blog_id);
+ install_blog($blog_id, $title);
+ wp_install_defaults($user_id);
+
+ add_user_to_blog($blog_id, $user_id, 'administrator');
+
+ if ( is_array($meta) ) foreach ($meta as $key => $value) {
+ if ( $key == 'public' || $key == 'archived' || $key == 'mature' || $key == 'spam' || $key == 'deleted' || $key == 'lang_id' )
+ update_blog_status( $blog_id, $key, $value );
+ else
+ update_option( $key, $value );
+ }
+
+ add_option( 'WPLANG', get_site_option( 'WPLANG' ) );
+ update_option( 'blog_public', (int)$meta['public'] );
+
+ if ( ! is_super_admin( $user_id ) && ! get_user_meta( $user_id, 'primary_blog', true ) )
+ update_user_meta( $user_id, 'primary_blog', $blog_id );
+
+ restore_current_blog();
+ do_action( 'wpmu_new_blog', $blog_id, $user_id, $domain, $path, $site_id, $meta );
+
+ return $blog_id;
+}
+
+/**
+ * Notifies the network admin that a new site has been activated.
+ *
+ * Filter 'newblog_notify_siteadmin' to change the content of
+ * the notification email.
+ *
+ * @since MU
+ *
+ * @param int $blog_id The new site's ID.
+ * @return bool
+ */
+function newblog_notify_siteadmin( $blog_id, $deprecated = '' ) {
+ if ( get_site_option( 'registrationnotification' ) != 'yes' )
+ return false;
+
+ $email = get_site_option( 'admin_email' );
+ if ( is_email($email) == false )
+ return false;
+
+ $options_site_url = esc_url(network_admin_url('settings.php'));
+
+ switch_to_blog( $blog_id );
+ $blogname = get_option( 'blogname' );
+ $siteurl = site_url();
+ restore_current_blog();
+
+ $msg = sprintf( __( 'New Site: %1$s
+URL: %2$s
+Remote IP: %3$s
+
+Disable these notifications: %4$s' ), $blogname, $siteurl, wp_unslash( $_SERVER['REMOTE_ADDR'] ), $options_site_url);
+ $msg = apply_filters( 'newblog_notify_siteadmin', $msg );
+
+ wp_mail( $email, sprintf( __( 'New Site Registration: %s' ), $siteurl ), $msg );
+ return true;
+}
+
+/**
+ * Notifies the network admin that a new user has been activated.
+ *
+ * Filter 'newuser_notify_siteadmin' to change the content of
+ * the notification email.
+ *
+ * @since MU
+ * @uses apply_filters() Filter newuser_notify_siteadmin to change the content of the email message
+ *
+ * @param int $user_id The new user's ID.
+ * @return bool
+ */
+function newuser_notify_siteadmin( $user_id ) {
+ if ( get_site_option( 'registrationnotification' ) != 'yes' )
+ return false;
+
+ $email = get_site_option( 'admin_email' );
+
+ if ( is_email($email) == false )
+ return false;
+
+ $user = get_userdata( $user_id );
+
+ $options_site_url = esc_url(network_admin_url('settings.php'));
+ $msg = sprintf(__('New User: %1$s
+Remote IP: %2$s
+
+Disable these notifications: %3$s'), $user->user_login, wp_unslash( $_SERVER['REMOTE_ADDR'] ), $options_site_url);
+
+ $msg = apply_filters( 'newuser_notify_siteadmin', $msg, $user );
+ wp_mail( $email, sprintf(__('New User Registration: %s'), $user->user_login), $msg );
+ return true;
+}
+
+/**
+ * Check whether a blogname is already taken.
+ *
+ * Used during the new site registration process to ensure
+ * that each blogname is unique.
+ *
+ * @since MU
+ *
+ * @param string $domain The domain to be checked.
+ * @param string $path The path to be checked.
+ * @param int $site_id Optional. Relevant only on multi-network installs.
+ * @return int
+ */
+function domain_exists($domain, $path, $site_id = 1) {
+ global $wpdb;
+ $result = $wpdb->get_var( $wpdb->prepare("SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s AND site_id = %d", $domain, $path, $site_id) );
+ return apply_filters( 'domain_exists', $result, $domain, $path, $site_id );
+}
+
+/**
+ * Store basic site info in the blogs table.
+ *
+ * This function creates a row in the wp_blogs table and returns
+ * the new blog's ID. It is the first step in creating a new blog.
+ *
+ * @since MU
+ *
+ * @param string $domain The domain of the new site.
+ * @param string $path The path of the new site.
+ * @param int $site_id Unless you're running a multi-network install, be sure to set this value to 1.
+ * @return int The ID of the new row
+ */
+function insert_blog($domain, $path, $site_id) {
+ global $wpdb;
+
+ $path = trailingslashit($path);
+ $site_id = (int) $site_id;
+
+ $result = $wpdb->insert( $wpdb->blogs, array('site_id' => $site_id, 'domain' => $domain, 'path' => $path, 'registered' => current_time('mysql')) );
+ if ( ! $result )
+ return false;
+
+ $blog_id = $wpdb->insert_id;
+ refresh_blog_details( $blog_id );
+ return $blog_id;
+}
+
+/**
+ * Install an empty blog.
+ *
+ * Creates the new blog tables and options. If calling this function
+ * directly, be sure to use switch_to_blog() first, so that $wpdb
+ * points to the new blog.
+ *
+ * @since MU
+ * @uses make_db_current_silent()
+ * @uses populate_roles()
+ *
+ * @param int $blog_id The value returned by insert_blog().
+ * @param string $blog_title The title of the new site.
+ */
+function install_blog($blog_id, $blog_title = '') {
+ global $wpdb, $wp_roles, $current_site;
+
+ // Cast for security
+ $blog_id = (int) $blog_id;
+
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
+
+ $wpdb->suppress_errors();
+ if ( $wpdb->get_results( "DESCRIBE {$wpdb->posts}" ) )
+ die( '<h1>' . __( 'Already Installed' ) . '</h1><p>' . __( 'You appear to have already installed WordPress. To reinstall please clear your old database tables first.' ) . '</p></body></html>' );
+ $wpdb->suppress_errors( false );
+
+ $url = get_blogaddress_by_id( $blog_id );
+
+ // Set everything up
+ make_db_current_silent( 'blog' );
+ populate_options();
+ populate_roles();
+ $wp_roles->_init();
+
+ $url = untrailingslashit( $url );
+
+ update_option( 'siteurl', $url );
+ update_option( 'home', $url );
+
+ if ( get_site_option( 'ms_files_rewriting' ) )
+ update_option( 'upload_path', UPLOADBLOGSDIR . "/$blog_id/files" );
+ else
+ update_option( 'upload_path', get_blog_option( $current_site->blog_id, 'upload_path' ) );
+
+ update_option( 'blogname', wp_unslash( $blog_title ) );
+ update_option( 'admin_email', '' );
+
+ // remove all perms
+ $table_prefix = $wpdb->get_blog_prefix();
+ delete_metadata( 'user', 0, $table_prefix . 'user_level', null, true ); // delete all
+ delete_metadata( 'user', 0, $table_prefix . 'capabilities', null, true ); // delete all
+}
+
+/**
+ * Set blog defaults.
+ *
+ * This function creates a row in the wp_blogs table.
+ *
+ * @since MU
+ * @deprecated MU
+ * @deprecated Use wp_install_defaults()
+ * @uses wp_install_defaults()
+ *
+ * @param int $blog_id Ignored in this function.
+ * @param int $user_id
+ */
+function install_blog_defaults($blog_id, $user_id) {
+ global $wpdb;
+
+ require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
+
+ $wpdb->suppress_errors();
+
+ wp_install_defaults($user_id);
+
+ $wpdb->suppress_errors( false );
+}
+
+/**
+ * Notify a user that her blog activation has been successful.
+ *
+ * Filter 'wpmu_welcome_notification' to disable or bypass.
+ *
+ * Filter 'update_welcome_email' and 'update_welcome_subject' to
+ * modify the content and subject line of the notification email.
+ *
+ * @since MU
+ *
+ * @param int $blog_id
+ * @param int $user_id
+ * @param string $password
+ * @param string $title The new blog's title
+ * @param array $meta Optional. Not used in the default function, but is passed along to hooks for customization.
+ * @return bool
+ */
+function wpmu_welcome_notification($blog_id, $user_id, $password, $title, $meta = '') {
+ global $current_site;
+
+ if ( !apply_filters('wpmu_welcome_notification', $blog_id, $user_id, $password, $title, $meta) )
+ return false;
+
+ $welcome_email = get_site_option( 'welcome_email' );
+ if ( $welcome_email == false )
+ $welcome_email = __( 'Dear User,
+
+Your new SITE_NAME site has been successfully set up at:
+BLOG_URL
+
+You can log in to the administrator account with the following information:
+Username: USERNAME
+Password: PASSWORD
+Log in here: BLOG_URLwp-login.php
+
+We hope you enjoy your new site. Thanks!
+
+--The Team @ SITE_NAME' );
+
+ $url = get_blogaddress_by_id($blog_id);
+ $user = get_userdata( $user_id );
+
+ $welcome_email = str_replace( 'SITE_NAME', $current_site->site_name, $welcome_email );
+ $welcome_email = str_replace( 'BLOG_TITLE', $title, $welcome_email );
+ $welcome_email = str_replace( 'BLOG_URL', $url, $welcome_email );
+ $welcome_email = str_replace( 'USERNAME', $user->user_login, $welcome_email );
+ $welcome_email = str_replace( 'PASSWORD', $password, $welcome_email );
+
+ $welcome_email = apply_filters( 'update_welcome_email', $welcome_email, $blog_id, $user_id, $password, $title, $meta);
+ $admin_email = get_site_option( 'admin_email' );
+
+ if ( $admin_email == '' )
+ $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
+
+ $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
+ $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+ $message = $welcome_email;
+
+ if ( empty( $current_site->site_name ) )
+ $current_site->site_name = 'WordPress';
+
+ $subject = apply_filters( 'update_welcome_subject', sprintf(__('New %1$s Site: %2$s'), $current_site->site_name, wp_unslash( $title ) ) );
+ wp_mail($user->user_email, $subject, $message, $message_headers);
+ return true;
+}
+
+/**
+ * Notify a user that her account activation has been successful.
+ *
+ * Filter 'wpmu_welcome_user_notification' to disable or bypass.
+ *
+ * Filter 'update_welcome_user_email' and 'update_welcome_user_subject' to
+ * modify the content and subject line of the notification email.
+ *
+ * @since MU
+ *
+ * @param int $user_id
+ * @param string $password
+ * @param array $meta Optional. Not used in the default function, but is passed along to hooks for customization.
+ * @return bool
+ */
+function wpmu_welcome_user_notification($user_id, $password, $meta = '') {
+ global $current_site;
+
+ if ( !apply_filters('wpmu_welcome_user_notification', $user_id, $password, $meta) )
+ return false;
+
+ $welcome_email = get_site_option( 'welcome_user_email' );
+
+ $user = get_userdata( $user_id );
+
+ $welcome_email = apply_filters( 'update_welcome_user_email', $welcome_email, $user_id, $password, $meta);
+ $welcome_email = str_replace( 'SITE_NAME', $current_site->site_name, $welcome_email );
+ $welcome_email = str_replace( 'USERNAME', $user->user_login, $welcome_email );
+ $welcome_email = str_replace( 'PASSWORD', $password, $welcome_email );
+ $welcome_email = str_replace( 'LOGINLINK', wp_login_url(), $welcome_email );
+
+ $admin_email = get_site_option( 'admin_email' );
+
+ if ( $admin_email == '' )
+ $admin_email = 'support@' . $_SERVER['SERVER_NAME'];
+
+ $from_name = get_site_option( 'site_name' ) == '' ? 'WordPress' : esc_html( get_site_option( 'site_name' ) );
+ $message_headers = "From: \"{$from_name}\" <{$admin_email}>\n" . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+ $message = $welcome_email;
+
+ if ( empty( $current_site->site_name ) )
+ $current_site->site_name = 'WordPress';
+
+ $subject = apply_filters( 'update_welcome_user_subject', sprintf(__('New %1$s User: %2$s'), $current_site->site_name, $user->user_login) );
+ wp_mail($user->user_email, $subject, $message, $message_headers);
+ return true;
+}
+
+/**
+ * Get the current site info.
+ *
+ * Returns an object containing the ID, domain, path, and site_name
+ * of the site being viewed.
+ *
+ * @since MU
+ *
+ * @return object
+ */
+function get_current_site() {
+ global $current_site;
+ return $current_site;
+}
+
+/**
+ * Get a user's most recent post.
+ *
+ * Walks through each of a user's blogs to find the post with
+ * the most recent post_date_gmt.
+ *
+ * @since MU
+ * @uses get_blogs_of_user()
+ *
+ * @param int $user_id
+ * @return array Contains the blog_id, post_id, post_date_gmt, and post_gmt_ts
+ */
+function get_most_recent_post_of_user( $user_id ) {
+ global $wpdb;
+
+ $user_blogs = get_blogs_of_user( (int) $user_id );
+ $most_recent_post = array();
+
+ // Walk through each blog and get the most recent post
+ // published by $user_id
+ foreach ( (array) $user_blogs as $blog ) {
+ $prefix = $wpdb->get_blog_prefix( $blog->userblog_id );
+ $recent_post = $wpdb->get_row( $wpdb->prepare("SELECT ID, post_date_gmt FROM {$prefix}posts WHERE post_author = %d AND post_type = 'post' AND post_status = 'publish' ORDER BY post_date_gmt DESC LIMIT 1", $user_id ), ARRAY_A);
+
+ // Make sure we found a post
+ if ( isset($recent_post['ID']) ) {
+ $post_gmt_ts = strtotime($recent_post['post_date_gmt']);
+
+ // If this is the first post checked or if this post is
+ // newer than the current recent post, make it the new
+ // most recent post.
+ if ( !isset($most_recent_post['post_gmt_ts']) || ( $post_gmt_ts > $most_recent_post['post_gmt_ts'] ) ) {
+ $most_recent_post = array(
+ 'blog_id' => $blog->userblog_id,
+ 'post_id' => $recent_post['ID'],
+ 'post_date_gmt' => $recent_post['post_date_gmt'],
+ 'post_gmt_ts' => $post_gmt_ts
+ );
+ }
+ }
+ }
+
+ return $most_recent_post;
+}
+
+// Misc functions
+
+/**
+ * Get the size of a directory.
+ *
+ * A helper function that is used primarily to check whether
+ * a blog has exceeded its allowed upload space.
+ *
+ * @since MU
+ * @uses recurse_dirsize()
+ *
+ * @param string $directory
+ * @return int
+ */
+function get_dirsize( $directory ) {
+ $dirsize = get_transient( 'dirsize_cache' );
+ if ( is_array( $dirsize ) && isset( $dirsize[ $directory ][ 'size' ] ) )
+ return $dirsize[ $directory ][ 'size' ];
+
+ if ( false == is_array( $dirsize ) )
+ $dirsize = array();
+
+ $dirsize[ $directory ][ 'size' ] = recurse_dirsize( $directory );
+
+ set_transient( 'dirsize_cache', $dirsize, HOUR_IN_SECONDS );
+ return $dirsize[ $directory ][ 'size' ];
+}
+
+/**
+ * Get the size of a directory recursively.
+ *
+ * Used by get_dirsize() to get a directory's size when it contains
+ * other directories.
+ *
+ * @since MU
+ *
+ * @param string $directory
+ * @return int
+ */
+function recurse_dirsize( $directory ) {
+ $size = 0;
+
+ $directory = untrailingslashit( $directory );
+
+ if ( !file_exists($directory) || !is_dir( $directory ) || !is_readable( $directory ) )
+ return false;
+
+ if ($handle = opendir($directory)) {
+ while(($file = readdir($handle)) !== false) {
+ $path = $directory.'/'.$file;
+ if ($file != '.' && $file != '..') {
+ if (is_file($path)) {
+ $size += filesize($path);
+ } elseif (is_dir($path)) {
+ $handlesize = recurse_dirsize($path);
+ if ($handlesize > 0)
+ $size += $handlesize;
+ }
+ }
+ }
+ closedir($handle);
+ }
+ return $size;
+}
+
+/**
+ * Check an array of MIME types against a whitelist.
+ *
+ * WordPress ships with a set of allowed upload filetypes,
+ * which is defined in wp-includes/functions.php in
+ * get_allowed_mime_types(). This function is used to filter
+ * that list against the filetype whitelist provided by Multisite
+ * Super Admins at wp-admin/network/settings.php.
+ *
+ * @since MU
+ *
+ * @param array $mimes
+ * @return array
+ */
+function check_upload_mimes( $mimes ) {
+ $site_exts = explode( ' ', get_site_option( 'upload_filetypes' ) );
+ foreach ( $site_exts as $ext ) {
+ foreach ( $mimes as $ext_pattern => $mime ) {
+ if ( $ext != '' && strpos( $ext_pattern, $ext ) !== false )
+ $site_mimes[$ext_pattern] = $mime;
+ }
+ }
+ return $site_mimes;
+}
+
+/**
+ * Update a blog's post count.
+ *
+ * WordPress MS stores a blog's post count as an option so as
+ * to avoid extraneous COUNTs when a blog's details are fetched
+ * with get_blog_details(). This function is called when posts
+ * are published to make sure the count stays current.
+ *
+ * @since MU
+ */
+function update_posts_count( $deprecated = '' ) {
+ global $wpdb;
+ update_option( 'post_count', (int) $wpdb->get_var( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish' and post_type = 'post'" ) );
+}
+
+/**
+ * Logs user registrations.
+ *
+ * @since MU
+ *
+ * @param int $blog_id
+ * @param int $user_id
+ */
+function wpmu_log_new_registrations( $blog_id, $user_id ) {
+ global $wpdb;
+ $user = get_userdata( (int) $user_id );
+ $wpdb->insert( $wpdb->registration_log, array('email' => $user->user_email, 'IP' => preg_replace( '/[^0-9., ]/', '', wp_unslash( $_SERVER['REMOTE_ADDR'] ) ), 'blog_id' => $blog_id, 'date_registered' => current_time('mysql')) );
+}
+
+/**
+ * Maintains a canonical list of terms by syncing terms created for each blog with the global terms table.
+ *
+ * @since 3.0.0
+ *
+ * @see term_id_filter
+ *
+ * @param int $term_id An ID for a term on the current blog.
+ * @return int An ID from the global terms table mapped from $term_id.
+ */
+function global_terms( $term_id, $deprecated = '' ) {
+ global $wpdb;
+ static $global_terms_recurse = null;
+
+ if ( !global_terms_enabled() )
+ return $term_id;
+
+ // prevent a race condition
+ $recurse_start = false;
+ if ( $global_terms_recurse === null ) {
+ $recurse_start = true;
+ $global_terms_recurse = 1;
+ } elseif ( 10 < $global_terms_recurse++ ) {
+ return $term_id;
+ }
+
+ $term_id = intval( $term_id );
+ $c = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->terms WHERE term_id = %d", $term_id ) );
+
+ $global_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM $wpdb->sitecategories WHERE category_nicename = %s", $c->slug ) );
+ if ( $global_id == null ) {
+ $used_global_id = $wpdb->get_var( $wpdb->prepare( "SELECT cat_ID FROM $wpdb->sitecategories WHERE cat_ID = %d", $c->term_id ) );
+ if ( null == $used_global_id ) {
+ $wpdb->insert( $wpdb->sitecategories, array( 'cat_ID' => $term_id, 'cat_name' => $c->name, 'category_nicename' => $c->slug ) );
+ $global_id = $wpdb->insert_id;
+ if ( empty( $global_id ) )
+ return $term_id;
+ } else {
+ $max_global_id = $wpdb->get_var( "SELECT MAX(cat_ID) FROM $wpdb->sitecategories" );
+ $max_local_id = $wpdb->get_var( "SELECT MAX(term_id) FROM $wpdb->terms" );
+ $new_global_id = max( $max_global_id, $max_local_id ) + mt_rand( 100, 400 );
+ $wpdb->insert( $wpdb->sitecategories, array( 'cat_ID' => $new_global_id, 'cat_name' => $c->name, 'category_nicename' => $c->slug ) );
+ $global_id = $wpdb->insert_id;
+ }
+ } elseif ( $global_id != $term_id ) {
+ $local_id = $wpdb->get_row( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE term_id = %d", $global_id ) );
+ if ( null != $local_id )
+ $local_id = global_terms( $local_id );
+ if ( 10 < $global_terms_recurse )
+ $global_id = $term_id;
+ }
+
+ if ( $global_id != $term_id ) {
+ if ( get_option( 'default_category' ) == $term_id )
+ update_option( 'default_category', $global_id );
+
+ $wpdb->update( $wpdb->terms, array('term_id' => $global_id), array('term_id' => $term_id) );
+ $wpdb->update( $wpdb->term_taxonomy, array('term_id' => $global_id), array('term_id' => $term_id) );
+ $wpdb->update( $wpdb->term_taxonomy, array('parent' => $global_id), array('parent' => $term_id) );
+
+ clean_term_cache($term_id);
+ }
+ if( $recurse_start )
+ $global_terms_recurse = null;
+
+ return $global_id;
+}
+
+/**
+ * Ensure that the current site's domain is listed in the allowed redirect host list.
+ *
+ * @see wp_validate_redirect()
+ * @since MU
+ *
+ * @return array The current site's domain
+ */
+function redirect_this_site( $deprecated = '' ) {
+ global $current_site;
+ return array( $current_site->domain );
+}
+
+/**
+ * Check whether an upload is too big.
+ *
+ * @since MU
+ *
+ * @param array $upload
+ * @return mixed If the upload is under the size limit, $upload is returned. Otherwise returns an error message.
+ */
+function upload_is_file_too_big( $upload ) {
+ if ( is_array( $upload ) == false || defined( 'WP_IMPORTING' ) || get_site_option( 'upload_space_check_disabled' ) )
+ return $upload;
+
+ if ( strlen( $upload['bits'] ) > ( 1024 * get_site_option( 'fileupload_maxk', 1500 ) ) )
+ return sprintf( __( 'This file is too big. Files must be less than %d KB in size.' ) . '<br />', get_site_option( 'fileupload_maxk', 1500 ));
+
+ return $upload;
+}
+
+/**
+ * Add a nonce field to the signup page.
+ *
+ * @since MU
+ * @uses wp_nonce_field()
+ */
+function signup_nonce_fields() {
+ $id = mt_rand();
+ echo "<input type='hidden' name='signup_form_id' value='{$id}' />";
+ wp_nonce_field('signup_form_' . $id, '_signup_form', false);
+}
+
+/**
+ * Process the signup nonce created in signup_nonce_fields().
+ *
+ * @since MU
+ * @uses wp_create_nonce()
+ *
+ * @param array $result
+ * @return array
+ */
+function signup_nonce_check( $result ) {
+ if ( !strpos( $_SERVER[ 'PHP_SELF' ], 'wp-signup.php' ) )
+ return $result;
+
+ if ( wp_create_nonce('signup_form_' . $_POST[ 'signup_form_id' ]) != $_POST['_signup_form'] )
+ wp_die( __( 'Please try again.' ) );
+
+ return $result;
+}
+
+/**
+ * Correct 404 redirects when NOBLOGREDIRECT is defined.
+ *
+ * @since MU
+ */
+function maybe_redirect_404() {
+ global $current_site;
+ if ( is_main_site() && is_404() && defined( 'NOBLOGREDIRECT' ) && ( $destination = apply_filters( 'blog_redirect_404', NOBLOGREDIRECT ) ) ) {
+ if ( $destination == '%siteurl%' )
+ $destination = network_home_url();
+ wp_redirect( $destination );
+ exit();
+ }
+}
+
+/**
+ * Add a new user to a blog by visiting /newbloguser/username/.
+ *
+ * This will only work when the user's details are saved as an option
+ * keyed as 'new_user_x', where 'x' is the username of the user to be
+ * added, as when a user is invited through the regular WP Add User interface.
+ *
+ * @since MU
+ * @uses add_existing_user_to_blog()
+ */
+function maybe_add_existing_user_to_blog() {
+ if ( false === strpos( $_SERVER[ 'REQUEST_URI' ], '/newbloguser/' ) )
+ return false;
+
+ $parts = explode( '/', $_SERVER[ 'REQUEST_URI' ] );
+ $key = array_pop( $parts );
+
+ if ( $key == '' )
+ $key = array_pop( $parts );
+
+ $details = get_option( 'new_user_' . $key );
+ if ( !empty( $details ) )
+ delete_option( 'new_user_' . $key );
+
+ if ( empty( $details ) || is_wp_error( add_existing_user_to_blog( $details ) ) )
+ wp_die( sprintf(__('An error occurred adding you to this site. Back to the <a href="%s">homepage</a>.'), home_url() ) );
+
+ wp_die( sprintf( __( 'You have been added to this site. Please visit the <a href="%s">homepage</a> or <a href="%s">log in</a> using your username and password.' ), home_url(), admin_url() ), __( 'WordPress &rsaquo; Success' ) );
+}
+
+/**
+ * Add a user to a blog based on details from maybe_add_existing_user_to_blog().
+ *
+ * @since MU
+ * @uses add_user_to_blog()
+ *
+ * @param array $details
+ */
+function add_existing_user_to_blog( $details = false ) {
+ global $blog_id;
+
+ if ( is_array( $details ) ) {
+ $result = add_user_to_blog( $blog_id, $details[ 'user_id' ], $details[ 'role' ] );
+ do_action( 'added_existing_user', $details[ 'user_id' ], $result );
+ }
+ return $result;
+}
+
+/**
+ * Add a newly created user to the appropriate blog
+ *
+ * To add a user in general, use add_user_to_blog(). This function
+ * is specifically hooked into the wpmu_activate_user action.
+ *
+ * @since MU
+ * @see add_user_to_blog()
+ *
+ * @param int $user_id
+ * @param mixed $password Ignored.
+ * @param array $meta
+ */
+function add_new_user_to_blog( $user_id, $password, $meta ) {
+ global $current_site;
+ if ( !empty( $meta[ 'add_to_blog' ] ) ) {
+ $blog_id = $meta[ 'add_to_blog' ];
+ $role = $meta[ 'new_role' ];
+ remove_user_from_blog($user_id, $current_site->blog_id); // remove user from main blog.
+ add_user_to_blog( $blog_id, $user_id, $role );
+ update_user_meta( $user_id, 'primary_blog', $blog_id );
+ }
+}
+
+/**
+ * Correct From host on outgoing mail to match the site domain
+ *
+ * @since MU
+ */
+function fix_phpmailer_messageid( $phpmailer ) {
+ global $current_site;
+ $phpmailer->Hostname = $current_site->domain;
+}
+
+/**
+ * Check to see whether a user is marked as a spammer, based on user login.
+ *
+ * @since MU
+ * @uses get_user_by()
+ *
+ * @param string|WP_User $user Optional. Defaults to current user. WP_User object,
+ * or user login name as a string.
+ * @return bool
+ */
+function is_user_spammy( $user = null ) {
+ if ( ! is_a( $user, 'WP_User' ) ) {
+ if ( $user )
+ $user = get_user_by( 'login', $user );
+ else
+ $user = wp_get_current_user();
+ }
+
+ return $user && isset( $user->spam ) && 1 == $user->spam;
+}
+
+/**
+ * Update this blog's 'public' setting in the global blogs table.
+ *
+ * Public blogs have a setting of 1, private blogs are 0.
+ *
+ * @since MU
+ * @uses update_blog_status()
+ *
+ * @param int $old_value
+ * @param int $value The new public value
+ * @return bool
+ */
+function update_blog_public( $old_value, $value ) {
+ update_blog_status( get_current_blog_id(), 'public', (int) $value );
+}
+add_action('update_option_blog_public', 'update_blog_public', 10, 2);
+
+/**
+ * Check whether a usermeta key has to do with the current blog.
+ *
+ * @since MU
+ * @uses wp_get_current_user()
+ *
+ * @param string $key
+ * @param int $user_id Optional. Defaults to current user.
+ * @param int $blog_id Optional. Defaults to current blog.
+ * @return bool
+ */
+function is_user_option_local( $key, $user_id = 0, $blog_id = 0 ) {
+ global $wpdb;
+
+ $current_user = wp_get_current_user();
+ if ( $user_id == 0 )
+ $user_id = $current_user->ID;
+ if ( $blog_id == 0 )
+ $blog_id = $wpdb->blogid;
+
+ $local_key = $wpdb->get_blog_prefix( $blog_id ) . $key;
+
+ if ( isset( $current_user->$local_key ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Check whether users can self-register, based on Network settings.
+ *
+ * @since MU
+ *
+ * @return bool
+ */
+function users_can_register_signup_filter() {
+ $registration = get_site_option('registration');
+ if ( $registration == 'all' || $registration == 'user' )
+ return true;
+
+ return false;
+}
+add_filter('option_users_can_register', 'users_can_register_signup_filter');
+
+/**
+ * Ensure that the welcome message is not empty. Currently unused.
+ *
+ * @since MU
+ *
+ * @param string $text
+ * @return string
+ */
+function welcome_user_msg_filter( $text ) {
+ if ( !$text ) {
+ remove_filter( 'site_option_welcome_user_email', 'welcome_user_msg_filter' );
+ $text = __( 'Dear User,
+
+Your new account is set up.
+
+You can log in with the following information:
+Username: USERNAME
+Password: PASSWORD
+LOGINLINK
+
+Thanks!
+
+--The Team @ SITE_NAME' );
+ update_site_option( 'welcome_user_email', $text );
+ }
+ return $text;
+}
+add_filter( 'site_option_welcome_user_email', 'welcome_user_msg_filter' );
+
+/**
+ * Whether to force SSL on content.
+ *
+ * @since 2.8.5
+ *
+ * @param string|bool $force
+ * @return bool True if forced, false if not forced.
+ */
+function force_ssl_content( $force = '' ) {
+ static $forced_content;
+
+ if ( '' != $force ) {
+ $old_forced = $forced_content;
+ $forced_content = $force;
+ return $old_forced;
+ }
+
+ return $forced_content;
+}
+
+/**
+ * Formats a URL to use https.
+ *
+ * Useful as a filter.
+ *
+ * @since 2.8.5
+ *
+ * @param string URL
+ * @return string URL with https as the scheme
+ */
+function filter_SSL( $url ) {
+ if ( ! is_string( $url ) )
+ return get_bloginfo( 'url' ); // Return home blog url with proper scheme
+
+ if ( force_ssl_content() && is_ssl() )
+ $url = set_url_scheme( $url, 'https' );
+
+ return $url;
+}
+
+/**
+ * Schedule update of the network-wide counts for the current network.
+ *
+ * @since 3.1.0
+ */
+function wp_schedule_update_network_counts() {
+ if ( !is_main_site() )
+ return;
+
+ if ( !wp_next_scheduled('update_network_counts') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'twicedaily', 'update_network_counts');
+}
+
+/**
+ * Update the network-wide counts for the current network.
+ *
+ * @since 3.1.0
+ */
+function wp_update_network_counts() {
+ global $wpdb;
+
+ $count = $wpdb->get_var( $wpdb->prepare("SELECT COUNT(blog_id) as c FROM $wpdb->blogs WHERE site_id = %d AND spam = '0' AND deleted = '0' and archived = '0'", $wpdb->siteid) );
+ update_site_option( 'blog_count', $count );
+
+ $count = $wpdb->get_var( "SELECT COUNT(ID) as c FROM $wpdb->users WHERE spam = '0' AND deleted = '0'" );
+ update_site_option( 'user_count', $count );
+}
+
+/**
+ * Returns the space used by the current blog.
+ *
+ * @since 3.5.0
+ *
+ * @return int Used space in megabytes
+ */
+function get_space_used() {
+ // Allow for an alternative way of tracking storage space used
+ $space_used = apply_filters( 'pre_get_space_used', false );
+ if ( false === $space_used ) {
+ $upload_dir = wp_upload_dir();
+ $space_used = get_dirsize( $upload_dir['basedir'] ) / 1024 / 1024;
+ }
+
+ return $space_used;
+}
+
+/**
+ * Returns the upload quota for the current blog.
+ *
+ * @since MU
+ *
+ * @return int Quota in megabytes
+ */
+function get_space_allowed() {
+ $space_allowed = get_option( 'blog_upload_space' );
+
+ if ( ! is_numeric( $space_allowed ) )
+ $space_allowed = get_site_option( 'blog_upload_space' );
+
+ if ( empty( $space_allowed ) || ! is_numeric( $space_allowed ) )
+ $space_allowed = 50;
+
+ return $space_allowed;
+}
+
+/**
+ * Determines if there is any upload space left in the current blog's quota.
+ *
+ * @since 3.0.0
+ *
+ * @return int of upload space available in bytes
+ */
+function get_upload_space_available() {
+ $space_allowed = get_space_allowed() * 1024 * 1024;
+ if ( get_site_option( 'upload_space_check_disabled' ) )
+ return $space_allowed;
+
+ $space_used = get_space_used() * 1024 * 1024;
+
+ if ( ( $space_allowed - $space_used ) <= 0 )
+ return 0;
+
+ return $space_allowed - $space_used;
+}
+
+/**
+ * Determines if there is any upload space left in the current blog's quota.
+ *
+ * @since 3.0.0
+ * @return bool True if space is available, false otherwise.
+ */
+function is_upload_space_available() {
+ if ( get_site_option( 'upload_space_check_disabled' ) )
+ return true;
+
+ return (bool) get_upload_space_available();
+}
+
+/**
+ * @since 3.0.0
+ *
+ * @return int of upload size limit in bytes
+ */
+function upload_size_limit_filter( $size ) {
+ $fileupload_maxk = 1024 * get_site_option( 'fileupload_maxk', 1500 );
+ if ( get_site_option( 'upload_space_check_disabled' ) )
+ return min( $size, $fileupload_maxk );
+
+ return min( $size, $fileupload_maxk, get_upload_space_available() );
+}
+
+/**
+ * Whether or not we have a large network.
+ *
+ * The default criteria for a large network is either more than 10,000 users or more than 10,000 sites.
+ * Plugins can alter this criteria using the 'wp_is_large_network' filter.
+ *
+ * @since 3.3.0
+ * @param string $using 'sites or 'users'. Default is 'sites'.
+ * @return bool True if the network meets the criteria for large. False otherwise.
+ */
+function wp_is_large_network( $using = 'sites' ) {
+ if ( 'users' == $using ) {
+ $count = get_user_count();
+ return apply_filters( 'wp_is_large_network', $count > 10000, 'users', $count );
+ }
+
+ $count = get_blog_count();
+ return apply_filters( 'wp_is_large_network', $count > 10000, 'sites', $count );
+}
diff --git a/src/wp-includes/ms-load.php b/src/wp-includes/ms-load.php
new file mode 100644
index 0000000000..55659a2822
--- /dev/null
+++ b/src/wp-includes/ms-load.php
@@ -0,0 +1,258 @@
+<?php
+/**
+ * These functions are needed to load Multisite.
+ *
+ * @since 3.0.0
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ */
+
+/**
+ * Whether a subdomain configuration is enabled.
+ *
+ * @since 3.0.0
+ *
+ * @return bool True if subdomain configuration is enabled, false otherwise.
+ */
+function is_subdomain_install() {
+ if ( defined('SUBDOMAIN_INSTALL') )
+ return SUBDOMAIN_INSTALL;
+
+ if ( defined('VHOST') && VHOST == 'yes' )
+ return true;
+
+ return false;
+}
+
+/**
+ * Returns array of network plugin files to be included in global scope.
+ *
+ * The default directory is wp-content/plugins. To change the default directory
+ * manually, define <code>WP_PLUGIN_DIR</code> and <code>WP_PLUGIN_URL</code>
+ * in wp-config.php.
+ *
+ * @access private
+ * @since 3.1.0
+ * @return array Files to include
+ */
+function wp_get_active_network_plugins() {
+ $active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
+ if ( empty( $active_plugins ) )
+ return array();
+
+ $plugins = array();
+ $active_plugins = array_keys( $active_plugins );
+ sort( $active_plugins );
+
+ foreach ( $active_plugins as $plugin ) {
+ if ( ! validate_file( $plugin ) // $plugin must validate as file
+ && '.php' == substr( $plugin, -4 ) // $plugin must end with '.php'
+ && file_exists( WP_PLUGIN_DIR . '/' . $plugin ) // $plugin must exist
+ )
+ $plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
+ }
+ return $plugins;
+}
+
+/**
+ * Checks status of current blog.
+ *
+ * Checks if the blog is deleted, inactive, archived, or spammed.
+ *
+ * Dies with a default message if the blog does not pass the check.
+ *
+ * To change the default message when a blog does not pass the check,
+ * use the wp-content/blog-deleted.php, blog-inactive.php and
+ * blog-suspended.php drop-ins.
+ *
+ * @return bool|string Returns true on success, or drop-in file to include.
+ */
+function ms_site_check() {
+ global $wpdb, $current_site;
+
+ $blog = get_blog_details();
+
+ // Allow short-circuiting
+ $check = apply_filters('ms_site_check', null);
+ if ( null !== $check )
+ return true;
+
+ // Allow super admins to see blocked sites
+ if ( is_super_admin() )
+ return true;
+
+ if ( '1' == $blog->deleted ) {
+ if ( file_exists( WP_CONTENT_DIR . '/blog-deleted.php' ) )
+ return WP_CONTENT_DIR . '/blog-deleted.php';
+ else
+ wp_die( __( 'This user has elected to delete their account and the content is no longer available.' ), '', array( 'response' => 410 ) );
+ }
+
+ if ( '2' == $blog->deleted ) {
+ if ( file_exists( WP_CONTENT_DIR . '/blog-inactive.php' ) )
+ return WP_CONTENT_DIR . '/blog-inactive.php';
+ else
+ wp_die( sprintf( __( 'This site has not been activated yet. If you are having problems activating your site, please contact <a href="mailto:%1$s">%1$s</a>.' ), str_replace( '@', ' AT ', get_site_option( 'admin_email', "support@{$current_site->domain}" ) ) ) );
+ }
+
+ if ( $blog->archived == '1' || $blog->spam == '1' ) {
+ if ( file_exists( WP_CONTENT_DIR . '/blog-suspended.php' ) )
+ return WP_CONTENT_DIR . '/blog-suspended.php';
+ else
+ wp_die( __( 'This site has been archived or suspended.' ), '', array( 'response' => 410 ) );
+ }
+
+ return true;
+}
+
+/**
+ * Sets current site name.
+ *
+ * @access private
+ * @since 3.0.0
+ * @return object $current_site object with site_name
+ */
+function get_current_site_name( $current_site ) {
+ global $wpdb;
+
+ $current_site->site_name = wp_cache_get( $current_site->id . ':site_name', 'site-options' );
+ if ( ! $current_site->site_name ) {
+ $current_site->site_name = $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM $wpdb->sitemeta WHERE site_id = %d AND meta_key = 'site_name'", $current_site->id ) );
+ if ( ! $current_site->site_name )
+ $current_site->site_name = ucfirst( $current_site->domain );
+ wp_cache_set( $current_site->id . ':site_name', $current_site->site_name, 'site-options' );
+ }
+
+ return $current_site;
+}
+
+/**
+ * Sets current_site object.
+ *
+ * @access private
+ * @since 3.0.0
+ * @return object $current_site object
+ */
+function wpmu_current_site() {
+ global $wpdb, $current_site, $domain, $path, $sites, $cookie_domain;
+
+ if ( empty( $current_site ) )
+ $current_site = new stdClass;
+
+ if ( defined( 'DOMAIN_CURRENT_SITE' ) && defined( 'PATH_CURRENT_SITE' ) ) {
+ $current_site->id = defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : 1;
+ $current_site->domain = DOMAIN_CURRENT_SITE;
+ $current_site->path = $path = PATH_CURRENT_SITE;
+ if ( defined( 'BLOG_ID_CURRENT_SITE' ) )
+ $current_site->blog_id = BLOG_ID_CURRENT_SITE;
+ elseif ( defined( 'BLOGID_CURRENT_SITE' ) ) // deprecated.
+ $current_site->blog_id = BLOGID_CURRENT_SITE;
+ if ( DOMAIN_CURRENT_SITE == $domain )
+ $current_site->cookie_domain = $cookie_domain;
+ elseif ( substr( $current_site->domain, 0, 4 ) == 'www.' )
+ $current_site->cookie_domain = substr( $current_site->domain, 4 );
+ else
+ $current_site->cookie_domain = $current_site->domain;
+
+ wp_load_core_site_options( $current_site->id );
+
+ return $current_site;
+ }
+
+ $current_site = wp_cache_get( 'current_site', 'site-options' );
+ if ( $current_site )
+ return $current_site;
+
+ $sites = $wpdb->get_results( "SELECT * FROM $wpdb->site" ); // usually only one site
+ if ( 1 == count( $sites ) ) {
+ $current_site = $sites[0];
+ wp_load_core_site_options( $current_site->id );
+ $path = $current_site->path;
+ $current_site->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s", $current_site->domain, $current_site->path ) );
+ $current_site = get_current_site_name( $current_site );
+ if ( substr( $current_site->domain, 0, 4 ) == 'www.' )
+ $current_site->cookie_domain = substr( $current_site->domain, 4 );
+ wp_cache_set( 'current_site', $current_site, 'site-options' );
+ return $current_site;
+ }
+ $path = substr( $_SERVER[ 'REQUEST_URI' ], 0, 1 + strpos( $_SERVER[ 'REQUEST_URI' ], '/', 1 ) );
+
+ if ( $domain == $cookie_domain )
+ $current_site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE domain = %s AND path = %s", $domain, $path ) );
+ else
+ $current_site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE domain IN ( %s, %s ) AND path = %s ORDER BY CHAR_LENGTH( domain ) DESC LIMIT 1", $domain, $cookie_domain, $path ) );
+
+ if ( ! $current_site ) {
+ if ( $domain == $cookie_domain )
+ $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain = %s AND path='/'", $domain ) );
+ else
+ $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain IN ( %s, %s ) AND path = '/' ORDER BY CHAR_LENGTH( domain ) DESC LIMIT 1", $domain, $cookie_domain, $path ) );
+ }
+
+ if ( $current_site ) {
+ $path = $current_site->path;
+ $current_site->cookie_domain = $cookie_domain;
+ return $current_site;
+ }
+
+ if ( is_subdomain_install() ) {
+ $sitedomain = substr( $domain, 1 + strpos( $domain, '.' ) );
+ $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain = %s AND path = %s", $sitedomain, $path) );
+ if ( $current_site ) {
+ $current_site->cookie_domain = $current_site->domain;
+ return $current_site;
+ }
+
+ $current_site = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->site WHERE domain = %s AND path='/'", $sitedomain) );
+ }
+
+ if ( $current_site || defined( 'WP_INSTALLING' ) ) {
+ $path = '/';
+ return $current_site;
+ }
+
+ // Still no dice.
+ wp_load_translations_early();
+
+ if ( 1 == count( $sites ) )
+ wp_die( sprintf( __( 'That site does not exist. Please try <a href="%s">%s</a>.' ), 'http://' . $sites[0]->domain . $sites[0]->path ) );
+ else
+ wp_die( __( 'No site defined on this host. If you are the owner of this site, please check <a href="http://codex.wordpress.org/Debugging_a_WordPress_Network">Debugging a WordPress Network</a> for help.' ) );
+}
+
+/**
+ * Displays a failure message.
+ *
+ * Used when a blog's tables do not exist. Checks for a missing $wpdb->site table as well.
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function ms_not_installed() {
+ global $wpdb, $domain, $path;
+
+ wp_load_translations_early();
+
+ $title = __( 'Error establishing a database connection' );
+ $msg = '<h1>' . $title . '</h1>';
+ if ( ! is_admin() )
+ die( $msg );
+ $msg .= '<p>' . __( 'If your site does not display, please contact the owner of this network.' ) . '';
+ $msg .= ' ' . __( 'If you are the owner of this network please check that MySQL is running properly and all tables are error free.' ) . '</p>';
+ if ( ! $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->site'" ) )
+ $msg .= '<p>' . sprintf( __( '<strong>Database tables are missing.</strong> This means that MySQL is not running, WordPress was not installed properly, or someone deleted <code>%s</code>. You really should look at your database now.' ), $wpdb->site ) . '</p>';
+ else
+ $msg .= '<p>' . sprintf( __( '<strong>Could not find site <code>%1$s</code>.</strong> Searched for table <code>%2$s</code> in database <code>%3$s</code>. Is that right?' ), rtrim( $domain . $path, '/' ), $wpdb->blogs, DB_NAME ) . '</p>';
+ $msg .= '<p><strong>' . __( 'What do I do now?' ) . '</strong> ';
+ $msg .= __( 'Read the <a target="_blank" href="http://codex.wordpress.org/Debugging_a_WordPress_Network">bug report</a> page. Some of the guidelines there may help you figure out what went wrong.' );
+ $msg .= ' ' . __( 'If you&#8217;re still stuck with this message, then check that your database contains the following tables:' ) . '</p><ul>';
+ foreach ( $wpdb->tables('global') as $t => $table ) {
+ if ( 'sitecategories' == $t )
+ continue;
+ $msg .= '<li>' . $table . '</li>';
+ }
+ $msg .= '</ul>';
+
+ wp_die( $msg, $title );
+}
diff --git a/src/wp-includes/ms-settings.php b/src/wp-includes/ms-settings.php
new file mode 100644
index 0000000000..af2ea0d97a
--- /dev/null
+++ b/src/wp-includes/ms-settings.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Used to set up and fix common variables and include
+ * the Multisite procedural and class library.
+ *
+ * Allows for some configuration in wp-config.php (see ms-default-constants.php)
+ *
+ * @package WordPress
+ * @subpackage Multisite
+ * @since 3.0.0
+ */
+
+/** Include Multisite initialization functions */
+require( ABSPATH . WPINC . '/ms-load.php' );
+require( ABSPATH . WPINC . '/ms-default-constants.php' );
+
+if ( defined( 'SUNRISE' ) )
+ include_once( WP_CONTENT_DIR . '/sunrise.php' );
+
+/** Check for and define SUBDOMAIN_INSTALL and the deprecated VHOST constant. */
+ms_subdomain_constants();
+
+if ( !isset( $current_site ) || !isset( $current_blog ) ) {
+
+ $domain = addslashes( $_SERVER['HTTP_HOST'] );
+ if ( false !== strpos( $domain, ':' ) ) {
+ if ( substr( $domain, -3 ) == ':80' ) {
+ $domain = substr( $domain, 0, -3 );
+ $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -3 );
+ } elseif ( substr( $domain, -4 ) == ':443' ) {
+ $domain = substr( $domain, 0, -4 );
+ $_SERVER['HTTP_HOST'] = substr( $_SERVER['HTTP_HOST'], 0, -4 );
+ } else {
+ wp_load_translations_early();
+ wp_die( __( 'Multisite only works without the port number in the URL.' ) );
+ }
+ }
+
+ $domain = rtrim( $domain, '.' );
+ $cookie_domain = $domain;
+ if ( substr( $cookie_domain, 0, 4 ) == 'www.' )
+ $cookie_domain = substr( $cookie_domain, 4 );
+
+ $path = preg_replace( '|([a-z0-9-]+.php.*)|', '', $_SERVER['REQUEST_URI'] );
+ $path = str_replace ( '/wp-admin/', '/', $path );
+ $path = preg_replace( '|(/[a-z0-9-]+?/).*|', '$1', $path );
+
+ $current_site = wpmu_current_site();
+ if ( ! isset( $current_site->blog_id ) )
+ $current_site->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s", $current_site->domain, $current_site->path ) );
+
+ if ( is_subdomain_install() ) {
+ $current_blog = wp_cache_get( 'current_blog_' . $domain, 'site-options' );
+ if ( !$current_blog ) {
+ $current_blog = get_blog_details( array( 'domain' => $domain ), false );
+ if ( $current_blog )
+ wp_cache_set( 'current_blog_' . $domain, $current_blog, 'site-options' );
+ }
+ if ( $current_blog && $current_blog->site_id != $current_site->id ) {
+ $current_site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->site WHERE id = %d", $current_blog->site_id ) );
+ if ( ! isset( $current_site->blog_id ) )
+ $current_site->blog_id = $wpdb->get_var( $wpdb->prepare( "SELECT blog_id FROM $wpdb->blogs WHERE domain = %s AND path = %s", $current_site->domain, $current_site->path ) );
+ } else
+ $blogname = substr( $domain, 0, strpos( $domain, '.' ) );
+ } else {
+ $blogname = htmlspecialchars( substr( $_SERVER[ 'REQUEST_URI' ], strlen( $path ) ) );
+ if ( false !== strpos( $blogname, '/' ) )
+ $blogname = substr( $blogname, 0, strpos( $blogname, '/' ) );
+ if ( false !== strpos( $blogname, '?' ) )
+ $blogname = substr( $blogname, 0, strpos( $blogname, '?' ) );
+ $reserved_blognames = array( 'page', 'comments', 'blog', 'wp-admin', 'wp-includes', 'wp-content', 'files', 'feed' );
+ if ( $blogname != '' && ! in_array( $blogname, $reserved_blognames ) && ! is_file( $blogname ) )
+ $path .= $blogname . '/';
+ $current_blog = wp_cache_get( 'current_blog_' . $domain . $path, 'site-options' );
+ if ( ! $current_blog ) {
+ $current_blog = get_blog_details( array( 'domain' => $domain, 'path' => $path ), false );
+ if ( $current_blog )
+ wp_cache_set( 'current_blog_' . $domain . $path, $current_blog, 'site-options' );
+ }
+ unset($reserved_blognames);
+ }
+
+ if ( ! defined( 'WP_INSTALLING' ) && is_subdomain_install() && ! is_object( $current_blog ) ) {
+ if ( defined( 'NOBLOGREDIRECT' ) ) {
+ $destination = NOBLOGREDIRECT;
+ if ( '%siteurl%' == $destination )
+ $destination = "http://" . $current_site->domain . $current_site->path;
+ } else {
+ $destination = 'http://' . $current_site->domain . $current_site->path . 'wp-signup.php?new=' . str_replace( '.' . $current_site->domain, '', $domain );
+ }
+ header( 'Location: ' . $destination );
+ die();
+ }
+
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ if ( $current_site && ! $current_blog ) {
+ if ( $current_site->domain != $_SERVER[ 'HTTP_HOST' ] ) {
+ header( 'Location: http://' . $current_site->domain . $current_site->path );
+ exit;
+ }
+ $current_blog = get_blog_details( array( 'domain' => $current_site->domain, 'path' => $current_site->path ), false );
+ }
+ if ( ! $current_blog || ! $current_site )
+ ms_not_installed();
+ }
+
+ $blog_id = $current_blog->blog_id;
+ $public = $current_blog->public;
+
+ if ( empty( $current_blog->site_id ) )
+ $current_blog->site_id = 1;
+ $site_id = $current_blog->site_id;
+
+ $current_site = get_current_site_name( $current_site );
+
+ if ( ! $blog_id ) {
+ if ( defined( 'WP_INSTALLING' ) ) {
+ $current_blog->blog_id = $blog_id = 1;
+ } else {
+ wp_load_translations_early();
+ $msg = ! $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->site'" ) ? ' ' . __( 'Database tables are missing.' ) : '';
+ wp_die( __( 'No site by that name on this system.' ) . $msg );
+ }
+ }
+}
+$wpdb->set_prefix( $table_prefix, false ); // $table_prefix can be set in sunrise.php
+$wpdb->set_blog_id( $current_blog->blog_id, $current_blog->site_id );
+$table_prefix = $wpdb->get_blog_prefix();
+$_wp_switched_stack = array();
+$switched = false;
+
+// need to init cache again after blog_id is set
+wp_start_object_cache();
+
+// Define upload directory constants
+ms_upload_constants();
diff --git a/src/wp-includes/nav-menu-template.php b/src/wp-includes/nav-menu-template.php
new file mode 100644
index 0000000000..0ac14c328f
--- /dev/null
+++ b/src/wp-includes/nav-menu-template.php
@@ -0,0 +1,509 @@
+<?php
+/**
+ * Navigation Menu template functions
+ *
+ * @package WordPress
+ * @subpackage Nav_Menus
+ * @since 3.0.0
+ */
+
+/**
+ * Create HTML list of nav menu items.
+ *
+ * @package WordPress
+ * @since 3.0.0
+ * @uses Walker
+ */
+class Walker_Nav_Menu extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 3.0.0
+ * @var string
+ */
+ var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
+
+ /**
+ * @see Walker::$db_fields
+ * @since 3.0.0
+ * @todo Decouple this.
+ * @var array
+ */
+ var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
+
+ /**
+ * @see Walker::start_lvl()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of page. Used for padding.
+ */
+ function start_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "\n$indent<ul class=\"sub-menu\">\n";
+ }
+
+ /**
+ * @see Walker::end_lvl()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of page. Used for padding.
+ */
+ function end_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent</ul>\n";
+ }
+
+ /**
+ * @see Walker::start_el()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $item Menu item data object.
+ * @param int $depth Depth of menu item. Used for padding.
+ * @param int $current_page Menu item ID.
+ * @param object $args
+ */
+ function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
+ $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
+
+ $class_names = $value = '';
+
+ $classes = empty( $item->classes ) ? array() : (array) $item->classes;
+ $classes[] = 'menu-item-' . $item->ID;
+
+ $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
+ $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
+
+ $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
+ $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
+
+ $output .= $indent . '<li' . $id . $value . $class_names .'>';
+
+ $atts = array();
+ $atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
+ $atts['target'] = ! empty( $item->target ) ? $item->target : '';
+ $atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
+ $atts['href'] = ! empty( $item->url ) ? $item->url : '';
+
+ $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
+
+ $attributes = '';
+ foreach ( $atts as $attr => $value ) {
+ if ( ! empty( $value ) ) {
+ $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
+ $attributes .= ' ' . $attr . '="' . $value . '"';
+ }
+ }
+
+ $item_output = $args->before;
+ $item_output .= '<a'. $attributes .'>';
+ $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
+ $item_output .= '</a>';
+ $item_output .= $args->after;
+
+ $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
+ }
+
+ /**
+ * @see Walker::end_el()
+ * @since 3.0.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $item Page data object. Not used.
+ * @param int $depth Depth of page. Not Used.
+ */
+ function end_el( &$output, $item, $depth = 0, $args = array() ) {
+ $output .= "</li>\n";
+ }
+}
+
+/**
+ * Displays a navigation menu.
+ *
+ * Optional $args contents:
+ *
+ * menu - The menu that is desired. Accepts (matching in order) id, slug, name. Defaults to blank.
+ * menu_class - CSS class to use for the ul element which forms the menu. Defaults to 'menu'.
+ * menu_id - The ID that is applied to the ul element which forms the menu. Defaults to the menu slug, incremented.
+ * container - Whether to wrap the ul, and what to wrap it with. Defaults to 'div'.
+ * container_class - the class that is applied to the container. Defaults to 'menu-{menu slug}-container'.
+ * container_id - The ID that is applied to the container. Defaults to blank.
+ * fallback_cb - If the menu doesn't exists, a callback function will fire. Defaults to 'wp_page_menu'. Set to false for no fallback.
+ * before - Text before the link text.
+ * after - Text after the link text.
+ * link_before - Text before the link.
+ * link_after - Text after the link.
+ * echo - Whether to echo the menu or return it. Defaults to echo.
+ * depth - how many levels of the hierarchy are to be included. 0 means all. Defaults to 0.
+ * walker - allows a custom walker to be specified.
+ * theme_location - the location in the theme to be used. Must be registered with register_nav_menu() in order to be selectable by the user.
+ * items_wrap - How the list items should be wrapped. Defaults to a ul with an id and class. Uses printf() format with numbered placeholders.
+ *
+ * @since 3.0.0
+ *
+ * @param array $args Arguments
+ */
+function wp_nav_menu( $args = array() ) {
+ static $menu_id_slugs = array();
+
+ $defaults = array( 'menu' => '', 'container' => 'div', 'container_class' => '', 'container_id' => '', 'menu_class' => 'menu', 'menu_id' => '',
+ 'echo' => true, 'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '', 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
+ 'depth' => 0, 'walker' => '', 'theme_location' => '' );
+
+ $args = wp_parse_args( $args, $defaults );
+ $args = apply_filters( 'wp_nav_menu_args', $args );
+ $args = (object) $args;
+
+ // Get the nav menu based on the requested menu
+ $menu = wp_get_nav_menu_object( $args->menu );
+
+ // Get the nav menu based on the theme_location
+ if ( ! $menu && $args->theme_location && ( $locations = get_nav_menu_locations() ) && isset( $locations[ $args->theme_location ] ) )
+ $menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
+
+ // get the first menu that has items if we still can't find a menu
+ if ( ! $menu && !$args->theme_location ) {
+ $menus = wp_get_nav_menus();
+ foreach ( $menus as $menu_maybe ) {
+ if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
+ $menu = $menu_maybe;
+ break;
+ }
+ }
+ }
+
+ // If the menu exists, get its items.
+ if ( $menu && ! is_wp_error($menu) && !isset($menu_items) )
+ $menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
+
+ /*
+ * If no menu was found:
+ * - Fall back (if one was specified), or bail.
+ *
+ * If no menu items were found:
+ * - Fall back, but only if no theme location was specified.
+ * - Otherwise, bail.
+ */
+ if ( ( !$menu || is_wp_error($menu) || ( isset($menu_items) && empty($menu_items) && !$args->theme_location ) )
+ && $args->fallback_cb && is_callable( $args->fallback_cb ) )
+ return call_user_func( $args->fallback_cb, (array) $args );
+
+ if ( ! $menu || is_wp_error( $menu ) )
+ return false;
+
+ $nav_menu = $items = '';
+
+ $show_container = false;
+ if ( $args->container ) {
+ $allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
+ if ( in_array( $args->container, $allowed_tags ) ) {
+ $show_container = true;
+ $class = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-'. $menu->slug .'-container"';
+ $id = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
+ $nav_menu .= '<'. $args->container . $id . $class . '>';
+ }
+ }
+
+ // Set up the $menu_item variables
+ _wp_menu_item_classes_by_context( $menu_items );
+
+ $sorted_menu_items = array();
+ foreach ( (array) $menu_items as $key => $menu_item )
+ $sorted_menu_items[$menu_item->menu_order] = $menu_item;
+
+ unset($menu_items);
+
+ $sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );
+
+ $items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );
+ unset($sorted_menu_items);
+
+ // Attributes
+ if ( ! empty( $args->menu_id ) ) {
+ $wrap_id = $args->menu_id;
+ } else {
+ $wrap_id = 'menu-' . $menu->slug;
+ while ( in_array( $wrap_id, $menu_id_slugs ) ) {
+ if ( preg_match( '#-(\d+)$#', $wrap_id, $matches ) )
+ $wrap_id = preg_replace('#-(\d+)$#', '-' . ++$matches[1], $wrap_id );
+ else
+ $wrap_id = $wrap_id . '-1';
+ }
+ }
+ $menu_id_slugs[] = $wrap_id;
+
+ $wrap_class = $args->menu_class ? $args->menu_class : '';
+
+ // Allow plugins to hook into the menu to add their own <li>'s
+ $items = apply_filters( 'wp_nav_menu_items', $items, $args );
+ $items = apply_filters( "wp_nav_menu_{$menu->slug}_items", $items, $args );
+
+ // Don't print any markup if there are no items at this point.
+ if ( empty( $items ) )
+ return false;
+
+ $nav_menu .= sprintf( $args->items_wrap, esc_attr( $wrap_id ), esc_attr( $wrap_class ), $items );
+ unset( $items );
+
+ if ( $show_container )
+ $nav_menu .= '</' . $args->container . '>';
+
+ $nav_menu = apply_filters( 'wp_nav_menu', $nav_menu, $args );
+
+ if ( $args->echo )
+ echo $nav_menu;
+ else
+ return $nav_menu;
+}
+
+/**
+ * Add the class property classes for the current context, if applicable.
+ *
+ * @access private
+ * @since 3.0
+ *
+ * @param array $menu_items The current menu item objects to which to add the class property information.
+ */
+function _wp_menu_item_classes_by_context( &$menu_items ) {
+ global $wp_query, $wp_rewrite;
+
+ $queried_object = $wp_query->get_queried_object();
+ $queried_object_id = (int) $wp_query->queried_object_id;
+
+ $active_object = '';
+ $active_ancestor_item_ids = array();
+ $active_parent_item_ids = array();
+ $active_parent_object_ids = array();
+ $possible_taxonomy_ancestors = array();
+ $possible_object_parents = array();
+ $home_page_id = (int) get_option( 'page_for_posts' );
+
+ if ( $wp_query->is_singular && ! empty( $queried_object->post_type ) && ! is_post_type_hierarchical( $queried_object->post_type ) ) {
+ foreach ( (array) get_object_taxonomies( $queried_object->post_type ) as $taxonomy ) {
+ if ( is_taxonomy_hierarchical( $taxonomy ) ) {
+ $term_hierarchy = _get_term_hierarchy( $taxonomy );
+ $terms = wp_get_object_terms( $queried_object_id, $taxonomy, array( 'fields' => 'ids' ) );
+ if ( is_array( $terms ) ) {
+ $possible_object_parents = array_merge( $possible_object_parents, $terms );
+ $term_to_ancestor = array();
+ foreach ( (array) $term_hierarchy as $anc => $descs ) {
+ foreach ( (array) $descs as $desc )
+ $term_to_ancestor[ $desc ] = $anc;
+ }
+
+ foreach ( $terms as $desc ) {
+ do {
+ $possible_taxonomy_ancestors[ $taxonomy ][] = $desc;
+ if ( isset( $term_to_ancestor[ $desc ] ) ) {
+ $_desc = $term_to_ancestor[ $desc ];
+ unset( $term_to_ancestor[ $desc ] );
+ $desc = $_desc;
+ } else {
+ $desc = 0;
+ }
+ } while ( ! empty( $desc ) );
+ }
+ }
+ }
+ }
+ } elseif ( ! empty( $queried_object->taxonomy ) && is_taxonomy_hierarchical( $queried_object->taxonomy ) ) {
+ $term_hierarchy = _get_term_hierarchy( $queried_object->taxonomy );
+ $term_to_ancestor = array();
+ foreach ( (array) $term_hierarchy as $anc => $descs ) {
+ foreach ( (array) $descs as $desc )
+ $term_to_ancestor[ $desc ] = $anc;
+ }
+ $desc = $queried_object->term_id;
+ do {
+ $possible_taxonomy_ancestors[ $queried_object->taxonomy ][] = $desc;
+ if ( isset( $term_to_ancestor[ $desc ] ) ) {
+ $_desc = $term_to_ancestor[ $desc ];
+ unset( $term_to_ancestor[ $desc ] );
+ $desc = $_desc;
+ } else {
+ $desc = 0;
+ }
+ } while ( ! empty( $desc ) );
+ }
+
+ $possible_object_parents = array_filter( $possible_object_parents );
+
+ $front_page_url = home_url();
+
+ foreach ( (array) $menu_items as $key => $menu_item ) {
+
+ $menu_items[$key]->current = false;
+
+ $classes = (array) $menu_item->classes;
+ $classes[] = 'menu-item';
+ $classes[] = 'menu-item-type-' . $menu_item->type;
+ $classes[] = 'menu-item-object-' . $menu_item->object;
+
+ // if the menu item corresponds to a taxonomy term for the currently-queried non-hierarchical post object
+ if ( $wp_query->is_singular && 'taxonomy' == $menu_item->type && in_array( $menu_item->object_id, $possible_object_parents ) ) {
+ $active_parent_object_ids[] = (int) $menu_item->object_id;
+ $active_parent_item_ids[] = (int) $menu_item->db_id;
+ $active_object = $queried_object->post_type;
+
+ // if the menu item corresponds to the currently-queried post or taxonomy object
+ } elseif (
+ $menu_item->object_id == $queried_object_id &&
+ (
+ ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && $wp_query->is_home && $home_page_id == $menu_item->object_id ) ||
+ ( 'post_type' == $menu_item->type && $wp_query->is_singular ) ||
+ ( 'taxonomy' == $menu_item->type && ( $wp_query->is_category || $wp_query->is_tag || $wp_query->is_tax ) && $queried_object->taxonomy == $menu_item->object )
+ )
+ ) {
+ $classes[] = 'current-menu-item';
+ $menu_items[$key]->current = true;
+ $_anc_id = (int) $menu_item->db_id;
+
+ while(
+ ( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
+ ! in_array( $_anc_id, $active_ancestor_item_ids )
+ ) {
+ $active_ancestor_item_ids[] = $_anc_id;
+ }
+
+ if ( 'post_type' == $menu_item->type && 'page' == $menu_item->object ) {
+ // Back compat classes for pages to match wp_page_menu()
+ $classes[] = 'page_item';
+ $classes[] = 'page-item-' . $menu_item->object_id;
+ $classes[] = 'current_page_item';
+ }
+ $active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
+ $active_parent_object_ids[] = (int) $menu_item->post_parent;
+ $active_object = $menu_item->object;
+
+ // if the menu item corresponds to the currently-requested URL
+ } elseif ( 'custom' == $menu_item->object ) {
+ $_root_relative_current = untrailingslashit( $_SERVER['REQUEST_URI'] );
+ $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_root_relative_current );
+ $raw_item_url = strpos( $menu_item->url, '#' ) ? substr( $menu_item->url, 0, strpos( $menu_item->url, '#' ) ) : $menu_item->url;
+ $item_url = untrailingslashit( $raw_item_url );
+ $_indexless_current = untrailingslashit( preg_replace( '/' . preg_quote( $wp_rewrite->index, '/' ) . '$/', '', $current_url ) );
+
+ if ( $raw_item_url && in_array( $item_url, array( $current_url, $_indexless_current, $_root_relative_current ) ) ) {
+ $classes[] = 'current-menu-item';
+ $menu_items[$key]->current = true;
+ $_anc_id = (int) $menu_item->db_id;
+
+ while(
+ ( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
+ ! in_array( $_anc_id, $active_ancestor_item_ids )
+ ) {
+ $active_ancestor_item_ids[] = $_anc_id;
+ }
+
+ if ( in_array( home_url(), array( untrailingslashit( $current_url ), untrailingslashit( $_indexless_current ) ) ) ) {
+ // Back compat for home link to match wp_page_menu()
+ $classes[] = 'current_page_item';
+ }
+ $active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
+ $active_parent_object_ids[] = (int) $menu_item->post_parent;
+ $active_object = $menu_item->object;
+
+ // give front page item current-menu-item class when extra query arguments involved
+ } elseif ( $item_url == $front_page_url && is_front_page() ) {
+ $classes[] = 'current-menu-item';
+ }
+
+ if ( untrailingslashit($item_url) == home_url() )
+ $classes[] = 'menu-item-home';
+ }
+
+ // back-compat with wp_page_menu: add "current_page_parent" to static home page link for any non-page query
+ if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id )
+ $classes[] = 'current_page_parent';
+
+ $menu_items[$key]->classes = array_unique( $classes );
+ }
+ $active_ancestor_item_ids = array_filter( array_unique( $active_ancestor_item_ids ) );
+ $active_parent_item_ids = array_filter( array_unique( $active_parent_item_ids ) );
+ $active_parent_object_ids = array_filter( array_unique( $active_parent_object_ids ) );
+
+ // set parent's class
+ foreach ( (array) $menu_items as $key => $parent_item ) {
+ $classes = (array) $parent_item->classes;
+ $menu_items[$key]->current_item_ancestor = false;
+ $menu_items[$key]->current_item_parent = false;
+
+ if (
+ isset( $parent_item->type ) &&
+ (
+ // ancestral post object
+ (
+ 'post_type' == $parent_item->type &&
+ ! empty( $queried_object->post_type ) &&
+ is_post_type_hierarchical( $queried_object->post_type ) &&
+ in_array( $parent_item->object_id, $queried_object->ancestors ) &&
+ $parent_item->object != $queried_object->ID
+ ) ||
+
+ // ancestral term
+ (
+ 'taxonomy' == $parent_item->type &&
+ isset( $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
+ in_array( $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
+ (
+ ! isset( $queried_object->term_id ) ||
+ $parent_item->object_id != $queried_object->term_id
+ )
+ )
+ )
+ ) {
+ $classes[] = empty( $queried_object->taxonomy ) ? 'current-' . $queried_object->post_type . '-ancestor' : 'current-' . $queried_object->taxonomy . '-ancestor';
+ }
+
+ if ( in_array( intval( $parent_item->db_id ), $active_ancestor_item_ids ) ) {
+ $classes[] = 'current-menu-ancestor';
+ $menu_items[$key]->current_item_ancestor = true;
+ }
+ if ( in_array( $parent_item->db_id, $active_parent_item_ids ) ) {
+ $classes[] = 'current-menu-parent';
+ $menu_items[$key]->current_item_parent = true;
+ }
+ if ( in_array( $parent_item->object_id, $active_parent_object_ids ) )
+ $classes[] = 'current-' . $active_object . '-parent';
+
+ if ( 'post_type' == $parent_item->type && 'page' == $parent_item->object ) {
+ // Back compat classes for pages to match wp_page_menu()
+ if ( in_array('current-menu-parent', $classes) )
+ $classes[] = 'current_page_parent';
+ if ( in_array('current-menu-ancestor', $classes) )
+ $classes[] = 'current_page_ancestor';
+ }
+
+ $menu_items[$key]->classes = array_unique( $classes );
+ }
+}
+
+/**
+ * Retrieve the HTML list content for nav menu items.
+ *
+ * @uses Walker_Nav_Menu to create HTML list content.
+ * @since 3.0.0
+ * @see Walker::walk() for parameters and return description.
+ */
+function walk_nav_menu_tree( $items, $depth, $r ) {
+ $walker = ( empty($r->walker) ) ? new Walker_Nav_Menu : $r->walker;
+ $args = array( $items, $depth, $r );
+
+ return call_user_func_array( array($walker, 'walk'), $args );
+}
+
+/**
+ * Prevents a menu item ID from being used more than once.
+ *
+ * @since 3.0.1
+ * @access private
+ */
+function _nav_menu_item_id_use_once( $id, $item ) {
+ static $_used_ids = array();
+ if ( in_array( $item->ID, $_used_ids ) )
+ return '';
+ $_used_ids[] = $item->ID;
+ return $id;
+}
+add_filter( 'nav_menu_item_id', '_nav_menu_item_id_use_once', 10, 2 );
diff --git a/src/wp-includes/nav-menu.php b/src/wp-includes/nav-menu.php
new file mode 100644
index 0000000000..794f4b2d11
--- /dev/null
+++ b/src/wp-includes/nav-menu.php
@@ -0,0 +1,794 @@
+<?php
+/**
+ * Navigation Menu functions
+ *
+ * @package WordPress
+ * @subpackage Nav_Menus
+ * @since 3.0.0
+ */
+
+/**
+ * Returns a navigation menu object.
+ *
+ * @since 3.0.0
+ *
+ * @uses get_term
+ * @uses get_term_by
+ *
+ * @param string $menu Menu id, slug or name
+ * @return mixed false if $menu param isn't supplied or term does not exist, menu object if successful.
+ */
+function wp_get_nav_menu_object( $menu ) {
+ if ( ! $menu )
+ return false;
+
+ $menu_obj = get_term( $menu, 'nav_menu' );
+
+ if ( ! $menu_obj )
+ $menu_obj = get_term_by( 'slug', $menu, 'nav_menu' );
+
+ if ( ! $menu_obj )
+ $menu_obj = get_term_by( 'name', $menu, 'nav_menu' );
+
+ if ( ! $menu_obj )
+ $menu_obj = false;
+
+ return $menu_obj;
+}
+
+/**
+ * Check if the given ID is a navigation menu.
+ *
+ * Returns true if it is; false otherwise.
+ *
+ * @since 3.0.0
+ *
+ * @param int|string $menu The menu to check (id, slug, or name)
+ * @return bool Whether the menu exists.
+ */
+function is_nav_menu( $menu ) {
+ if ( ! $menu )
+ return false;
+
+ $menu_obj = wp_get_nav_menu_object( $menu );
+
+ if (
+ $menu_obj &&
+ ! is_wp_error( $menu_obj ) &&
+ ! empty( $menu_obj->taxonomy ) &&
+ 'nav_menu' == $menu_obj->taxonomy
+ )
+ return true;
+
+ return false;
+}
+
+/**
+ * Register navigation menus for a theme.
+ *
+ * @since 3.0.0
+ *
+ * @param array $locations Associative array of menu location identifiers (like a slug) and descriptive text.
+ */
+function register_nav_menus( $locations = array() ) {
+ global $_wp_registered_nav_menus;
+
+ add_theme_support( 'menus' );
+
+ $_wp_registered_nav_menus = array_merge( (array) $_wp_registered_nav_menus, $locations );
+}
+
+/**
+ * Unregisters a navigation menu for a theme.
+ *
+ * @param array $location the menu location identifier
+ *
+ * @return bool True on success, false on failure.
+ */
+function unregister_nav_menu( $location ) {
+ global $_wp_registered_nav_menus;
+
+ if ( is_array( $_wp_registered_nav_menus ) && isset( $_wp_registered_nav_menus[$location] ) ) {
+ unset( $_wp_registered_nav_menus[$location] );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Register a navigation menu for a theme.
+ *
+ * @since 3.0.0
+ *
+ * @param string $location Menu location identifier, like a slug.
+ * @param string $description Menu location descriptive text.
+ */
+function register_nav_menu( $location, $description ) {
+ register_nav_menus( array( $location => $description ) );
+}
+/**
+ * Returns an array of all registered navigation menus in a theme
+ *
+ * @since 3.0.0
+ * @return array
+ */
+function get_registered_nav_menus() {
+ global $_wp_registered_nav_menus;
+ if ( isset( $_wp_registered_nav_menus ) )
+ return $_wp_registered_nav_menus;
+ return array();
+}
+
+/**
+ * Returns an array with the registered navigation menu locations and the menu assigned to it
+ *
+ * @since 3.0.0
+ * @return array
+ */
+
+function get_nav_menu_locations() {
+ $locations = get_theme_mod( 'nav_menu_locations' );
+ return ( is_array( $locations ) ) ? $locations : array();
+}
+
+/**
+ * Whether a registered nav menu location has a menu assigned to it.
+ *
+ * @since 3.0.0
+ * @param string $location Menu location identifier.
+ * @return bool Whether location has a menu.
+ */
+function has_nav_menu( $location ) {
+ $locations = get_nav_menu_locations();
+ return ( ! empty( $locations[ $location ] ) );
+}
+
+/**
+ * Determine whether the given ID is a nav menu item.
+ *
+ * @since 3.0.0
+ *
+ * @param int $menu_item_id The ID of the potential nav menu item.
+ * @return bool Whether the given ID is that of a nav menu item.
+ */
+function is_nav_menu_item( $menu_item_id = 0 ) {
+ return ( ! is_wp_error( $menu_item_id ) && ( 'nav_menu_item' == get_post_type( $menu_item_id ) ) );
+}
+
+/**
+ * Create a Navigation Menu.
+ *
+ * @since 3.0.0
+ *
+ * @param string $menu_name Menu Name
+ * @return mixed Menu object on success|WP_Error on failure
+ */
+function wp_create_nav_menu( $menu_name ) {
+ return wp_update_nav_menu_object( 0, array( 'menu-name' => $menu_name ) );
+}
+
+/**
+ * Delete a Navigation Menu.
+ *
+ * @since 3.0.0
+ *
+ * @param string $menu name|id|slug
+ * @return mixed Menu object on success|WP_Error on failure
+ */
+function wp_delete_nav_menu( $menu ) {
+ $menu = wp_get_nav_menu_object( $menu );
+ if ( ! $menu )
+ return false;
+
+ $menu_objects = get_objects_in_term( $menu->term_id, 'nav_menu' );
+ if ( ! empty( $menu_objects ) ) {
+ foreach ( $menu_objects as $item ) {
+ wp_delete_post( $item );
+ }
+ }
+
+ $result = wp_delete_term( $menu->term_id, 'nav_menu' );
+
+ // Remove this menu from any locations.
+ $locations = get_theme_mod( 'nav_menu_locations' );
+ foreach ( (array) $locations as $location => $menu_id ) {
+ if ( $menu_id == $menu->term_id )
+ $locations[ $location ] = 0;
+ }
+ set_theme_mod( 'nav_menu_locations', $locations );
+
+ if ( $result && !is_wp_error($result) )
+ do_action( 'wp_delete_nav_menu', $menu->term_id );
+
+ return $result;
+}
+
+/**
+ * Save the properties of a menu or create a new menu with those properties.
+ *
+ * @since 3.0.0
+ *
+ * @param int $menu_id The ID of the menu or "0" to create a new menu.
+ * @param array $menu_data The array of menu data.
+ * @return int|error object The menu's ID or WP_Error object.
+ */
+function wp_update_nav_menu_object( $menu_id = 0, $menu_data = array() ) {
+ $menu_id = (int) $menu_id;
+
+ $_menu = wp_get_nav_menu_object( $menu_id );
+
+ $args = array(
+ 'description' => ( isset( $menu_data['description'] ) ? $menu_data['description'] : '' ),
+ 'name' => ( isset( $menu_data['menu-name'] ) ? $menu_data['menu-name'] : '' ),
+ 'parent' => ( isset( $menu_data['parent'] ) ? (int) $menu_data['parent'] : 0 ),
+ 'slug' => null,
+ );
+
+ // double-check that we're not going to have one menu take the name of another
+ $_possible_existing = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' );
+ if (
+ $_possible_existing &&
+ ! is_wp_error( $_possible_existing ) &&
+ isset( $_possible_existing->term_id ) &&
+ $_possible_existing->term_id != $menu_id
+ )
+ return new WP_Error( 'menu_exists', sprintf( __('The menu name <strong>%s</strong> conflicts with another menu name. Please try another.'), esc_html( $menu_data['menu-name'] ) ) );
+
+ // menu doesn't already exist, so create a new menu
+ if ( ! $_menu || is_wp_error( $_menu ) ) {
+ $menu_exists = get_term_by( 'name', $menu_data['menu-name'], 'nav_menu' );
+
+ if ( $menu_exists )
+ return new WP_Error( 'menu_exists', sprintf( __('The menu name <strong>%s</strong> conflicts with another menu name. Please try another.'), esc_html( $menu_data['menu-name'] ) ) );
+
+ $_menu = wp_insert_term( $menu_data['menu-name'], 'nav_menu', $args );
+
+ if ( is_wp_error( $_menu ) )
+ return $_menu;
+
+ do_action( 'wp_create_nav_menu', $_menu['term_id'], $menu_data );
+
+ return (int) $_menu['term_id'];
+ }
+
+ if ( ! $_menu || ! isset( $_menu->term_id ) )
+ return 0;
+
+ $menu_id = (int) $_menu->term_id;
+
+ $update_response = wp_update_term( $menu_id, 'nav_menu', $args );
+
+ if ( is_wp_error( $update_response ) )
+ return $update_response;
+
+ do_action( 'wp_update_nav_menu', $menu_id, $menu_data );
+ return $menu_id;
+}
+
+/**
+ * Save the properties of a menu item or create a new one.
+ *
+ * @since 3.0.0
+ *
+ * @param int $menu_id The ID of the menu. Required. If "0", makes the menu item a draft orphan.
+ * @param int $menu_item_db_id The ID of the menu item. If "0", creates a new menu item.
+ * @param array $menu_item_data The menu item's data.
+ * @return int The menu item's database ID or WP_Error object on failure.
+ */
+function wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array() ) {
+ $menu_id = (int) $menu_id;
+ $menu_item_db_id = (int) $menu_item_db_id;
+
+ // make sure that we don't convert non-nav_menu_item objects into nav_menu_item objects
+ if ( ! empty( $menu_item_db_id ) && ! is_nav_menu_item( $menu_item_db_id ) )
+ return new WP_Error('update_nav_menu_item_failed', __('The given object ID is not that of a menu item.'));
+
+ $menu = wp_get_nav_menu_object( $menu_id );
+
+ if ( ( ! $menu && 0 !== $menu_id ) || is_wp_error( $menu ) )
+ return $menu;
+
+ $defaults = array(
+ 'menu-item-db-id' => $menu_item_db_id,
+ 'menu-item-object-id' => 0,
+ 'menu-item-object' => '',
+ 'menu-item-parent-id' => 0,
+ 'menu-item-position' => 0,
+ 'menu-item-type' => 'custom',
+ 'menu-item-title' => '',
+ 'menu-item-url' => '',
+ 'menu-item-description' => '',
+ 'menu-item-attr-title' => '',
+ 'menu-item-target' => '',
+ 'menu-item-classes' => '',
+ 'menu-item-xfn' => '',
+ 'menu-item-status' => '',
+ );
+
+ $args = wp_parse_args( $menu_item_data, $defaults );
+
+ if ( 0 == $menu_id ) {
+ $args['menu-item-position'] = 1;
+ } elseif ( 0 == (int) $args['menu-item-position'] ) {
+ $menu_items = 0 == $menu_id ? array() : (array) wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) );
+ $last_item = array_pop( $menu_items );
+ $args['menu-item-position'] = ( $last_item && isset( $last_item->menu_order ) ) ? 1 + $last_item->menu_order : count( $menu_items );
+ }
+
+ $original_parent = 0 < $menu_item_db_id ? get_post_field( 'post_parent', $menu_item_db_id ) : 0;
+
+ if ( 'custom' != $args['menu-item-type'] ) {
+ /* if non-custom menu item, then:
+ * use original object's URL
+ * blank default title to sync with original object's
+ */
+
+ $args['menu-item-url'] = '';
+
+ $original_title = '';
+ if ( 'taxonomy' == $args['menu-item-type'] ) {
+ $original_parent = get_term_field( 'parent', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' );
+ $original_title = get_term_field( 'name', $args['menu-item-object-id'], $args['menu-item-object'], 'raw' );
+ } elseif ( 'post_type' == $args['menu-item-type'] ) {
+
+ $original_object = get_post( $args['menu-item-object-id'] );
+ $original_parent = (int) $original_object->post_parent;
+ $original_title = $original_object->post_title;
+ }
+
+ if ( $args['menu-item-title'] == $original_title )
+ $args['menu-item-title'] = '';
+
+ // hack to get wp to create a post object when too many properties are empty
+ if ( '' == $args['menu-item-title'] && '' == $args['menu-item-description'] )
+ $args['menu-item-description'] = ' ';
+ }
+
+ // Populate the menu item object
+ $post = array(
+ 'menu_order' => $args['menu-item-position'],
+ 'ping_status' => 0,
+ 'post_content' => $args['menu-item-description'],
+ 'post_excerpt' => $args['menu-item-attr-title'],
+ 'post_parent' => $original_parent,
+ 'post_title' => $args['menu-item-title'],
+ 'post_type' => 'nav_menu_item',
+ );
+
+ $update = 0 != $menu_item_db_id;
+
+ // Only set the menu term if it isn't set to avoid unnecessary wp_get_object_terms()
+ if ( $menu_id && ( ! $update || ! is_object_in_term( $menu_item_db_id, 'nav_menu', (int) $menu->term_id ) ) )
+ $post['tax_input'] = array( 'nav_menu' => array( intval( $menu->term_id ) ) );
+
+ // New menu item. Default is draft status
+ if ( ! $update ) {
+ $post['ID'] = 0;
+ $post['post_status'] = 'publish' == $args['menu-item-status'] ? 'publish' : 'draft';
+ $menu_item_db_id = wp_insert_post( $post );
+ if ( ! $menu_item_db_id || is_wp_error( $menu_item_db_id ) )
+ return $menu_item_db_id;
+ }
+
+ if ( 'custom' == $args['menu-item-type'] ) {
+ $args['menu-item-object-id'] = $menu_item_db_id;
+ $args['menu-item-object'] = 'custom';
+ }
+
+ $menu_item_db_id = (int) $menu_item_db_id;
+
+ update_post_meta( $menu_item_db_id, '_menu_item_type', sanitize_key($args['menu-item-type']) );
+ update_post_meta( $menu_item_db_id, '_menu_item_menu_item_parent', strval( (int) $args['menu-item-parent-id'] ) );
+ update_post_meta( $menu_item_db_id, '_menu_item_object_id', strval( (int) $args['menu-item-object-id'] ) );
+ update_post_meta( $menu_item_db_id, '_menu_item_object', sanitize_key($args['menu-item-object']) );
+ update_post_meta( $menu_item_db_id, '_menu_item_target', sanitize_key($args['menu-item-target']) );
+
+ $args['menu-item-classes'] = array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-classes'] ) );
+ $args['menu-item-xfn'] = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['menu-item-xfn'] ) ) );
+ update_post_meta( $menu_item_db_id, '_menu_item_classes', $args['menu-item-classes'] );
+ update_post_meta( $menu_item_db_id, '_menu_item_xfn', $args['menu-item-xfn'] );
+ update_post_meta( $menu_item_db_id, '_menu_item_url', esc_url_raw($args['menu-item-url']) );
+
+ if ( 0 == $menu_id )
+ update_post_meta( $menu_item_db_id, '_menu_item_orphaned', (string) time() );
+ elseif ( get_post_meta( $menu_item_db_id, '_menu_item_orphaned' ) )
+ delete_post_meta( $menu_item_db_id, '_menu_item_orphaned' );
+
+ // Update existing menu item. Default is publish status
+ if ( $update ) {
+ $post['ID'] = $menu_item_db_id;
+ $post['post_status'] = 'draft' == $args['menu-item-status'] ? 'draft' : 'publish';
+ wp_update_post( $post );
+ }
+
+ do_action('wp_update_nav_menu_item', $menu_id, $menu_item_db_id, $args );
+
+ return $menu_item_db_id;
+}
+
+/**
+ * Returns all navigation menu objects.
+ *
+ * @since 3.0.0
+ *
+ * @param array $args Array of arguments passed on to get_terms().
+ * @return array menu objects
+ */
+function wp_get_nav_menus( $args = array() ) {
+ $defaults = array( 'hide_empty' => false, 'orderby' => 'none' );
+ $args = wp_parse_args( $args, $defaults );
+ return apply_filters( 'wp_get_nav_menus', get_terms( 'nav_menu', $args), $args );
+}
+
+/**
+ * Sort menu items by the desired key.
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param object $a The first object to compare
+ * @param object $b The second object to compare
+ * @return int -1, 0, or 1 if $a is considered to be respectively less than, equal to, or greater than $b.
+ */
+function _sort_nav_menu_items( $a, $b ) {
+ global $_menu_item_sort_prop;
+
+ if ( empty( $_menu_item_sort_prop ) )
+ return 0;
+
+ if ( ! isset( $a->$_menu_item_sort_prop ) || ! isset( $b->$_menu_item_sort_prop ) )
+ return 0;
+
+ $_a = (int) $a->$_menu_item_sort_prop;
+ $_b = (int) $b->$_menu_item_sort_prop;
+
+ if ( $a->$_menu_item_sort_prop == $b->$_menu_item_sort_prop )
+ return 0;
+ elseif ( $_a == $a->$_menu_item_sort_prop && $_b == $b->$_menu_item_sort_prop )
+ return $_a < $_b ? -1 : 1;
+ else
+ return strcmp( $a->$_menu_item_sort_prop, $b->$_menu_item_sort_prop );
+}
+
+/**
+ * Returns if a menu item is valid. Bug #13958
+ *
+ * @since 3.2.0
+ * @access private
+ *
+ * @param object $menu_item The menu item to check
+ * @return bool false if invalid, else true.
+ */
+function _is_valid_nav_menu_item( $item ) {
+ if ( ! empty( $item->_invalid ) )
+ return false;
+
+ return true;
+}
+
+/**
+ * Returns all menu items of a navigation menu.
+ *
+ * @since 3.0.0
+ *
+ * @param string $menu menu name, id, or slug
+ * @param string $args
+ * @return mixed $items array of menu items, else false.
+ */
+function wp_get_nav_menu_items( $menu, $args = array() ) {
+ global $_wp_using_ext_object_cache;
+
+ $menu = wp_get_nav_menu_object( $menu );
+
+ if ( ! $menu )
+ return false;
+
+ static $fetched = array();
+
+ $items = get_objects_in_term( $menu->term_id, 'nav_menu' );
+
+ if ( empty( $items ) )
+ return $items;
+
+ $defaults = array( 'order' => 'ASC', 'orderby' => 'menu_order', 'post_type' => 'nav_menu_item',
+ 'post_status' => 'publish', 'output' => ARRAY_A, 'output_key' => 'menu_order', 'nopaging' => true );
+ $args = wp_parse_args( $args, $defaults );
+ if ( count( $items ) > 1 )
+ $args['include'] = implode( ',', $items );
+ else
+ $args['include'] = $items[0];
+
+ $items = get_posts( $args );
+
+ if ( is_wp_error( $items ) || ! is_array( $items ) )
+ return false;
+
+ // Get all posts and terms at once to prime the caches
+ if ( empty( $fetched[$menu->term_id] ) || $_wp_using_ext_object_cache ) {
+ $fetched[$menu->term_id] = true;
+ $posts = array();
+ $terms = array();
+ foreach ( $items as $item ) {
+ $object_id = get_post_meta( $item->ID, '_menu_item_object_id', true );
+ $object = get_post_meta( $item->ID, '_menu_item_object', true );
+ $type = get_post_meta( $item->ID, '_menu_item_type', true );
+
+ if ( 'post_type' == $type )
+ $posts[$object][] = $object_id;
+ elseif ( 'taxonomy' == $type)
+ $terms[$object][] = $object_id;
+ }
+
+ if ( ! empty( $posts ) ) {
+ foreach ( array_keys($posts) as $post_type ) {
+ get_posts( array('post__in' => $posts[$post_type], 'post_type' => $post_type, 'nopaging' => true, 'update_post_term_cache' => false) );
+ }
+ }
+ unset($posts);
+
+ if ( ! empty( $terms ) ) {
+ foreach ( array_keys($terms) as $taxonomy ) {
+ get_terms($taxonomy, array('include' => $terms[$taxonomy]) );
+ }
+ }
+ unset($terms);
+ }
+
+ $items = array_map( 'wp_setup_nav_menu_item', $items );
+
+ if ( ! is_admin() ) // Remove invalid items only in frontend
+ $items = array_filter( $items, '_is_valid_nav_menu_item' );
+
+ if ( ARRAY_A == $args['output'] ) {
+ $GLOBALS['_menu_item_sort_prop'] = $args['output_key'];
+ usort($items, '_sort_nav_menu_items');
+ $i = 1;
+ foreach( $items as $k => $item ) {
+ $items[$k]->$args['output_key'] = $i++;
+ }
+ }
+
+ return apply_filters( 'wp_get_nav_menu_items', $items, $menu, $args );
+}
+
+/**
+ * Decorates a menu item object with the shared navigation menu item properties.
+ *
+ * Properties:
+ * - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist).
+ * - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories.
+ * - type: The family of objects originally represented, such as "post_type" or "taxonomy."
+ * - object: The type of object originally represented, such as "category," "post", or "attachment."
+ * - type_label: The singular label used to describe this type of menu item.
+ * - post_parent: The DB ID of the original object's parent object, if any (0 otherwise).
+ * - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise.
+ * - url: The URL to which this menu item points.
+ * - title: The title of this menu item.
+ * - target: The target attribute of the link element for this menu item.
+ * - attr_title: The title attribute of the link element for this menu item.
+ * - classes: The array of class attribute values for the link element of this menu item.
+ * - xfn: The XFN relationship expressed in the link of this menu item.
+ * - description: The description of this menu item.
+ *
+ * @since 3.0.0
+ *
+ * @param object $menu_item The menu item to modify.
+ * @return object $menu_item The menu item with standard menu item properties.
+ */
+function wp_setup_nav_menu_item( $menu_item ) {
+ if ( isset( $menu_item->post_type ) ) {
+ if ( 'nav_menu_item' == $menu_item->post_type ) {
+ $menu_item->db_id = (int) $menu_item->ID;
+ $menu_item->menu_item_parent = empty( $menu_item->menu_item_parent ) ? get_post_meta( $menu_item->ID, '_menu_item_menu_item_parent', true ) : $menu_item->menu_item_parent;
+ $menu_item->object_id = empty( $menu_item->object_id ) ? get_post_meta( $menu_item->ID, '_menu_item_object_id', true ) : $menu_item->object_id;
+ $menu_item->object = empty( $menu_item->object ) ? get_post_meta( $menu_item->ID, '_menu_item_object', true ) : $menu_item->object;
+ $menu_item->type = empty( $menu_item->type ) ? get_post_meta( $menu_item->ID, '_menu_item_type', true ) : $menu_item->type;
+
+ if ( 'post_type' == $menu_item->type ) {
+ $object = get_post_type_object( $menu_item->object );
+ if ( $object ) {
+ $menu_item->type_label = $object->labels->singular_name;
+ } else {
+ $menu_item->type_label = $menu_item->object;
+ $menu_item->_invalid = true;
+ }
+
+ $menu_item->url = get_permalink( $menu_item->object_id );
+
+ $original_object = get_post( $menu_item->object_id );
+ $original_title = $original_object->post_title;
+ $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title;
+
+ } elseif ( 'taxonomy' == $menu_item->type ) {
+ $object = get_taxonomy( $menu_item->object );
+ if ( $object ) {
+ $menu_item->type_label = $object->labels->singular_name;
+ } else {
+ $menu_item->type_label = $menu_item->object;
+ $menu_item->_invalid = true;
+ }
+
+ $term_url = get_term_link( (int) $menu_item->object_id, $menu_item->object );
+ $menu_item->url = !is_wp_error( $term_url ) ? $term_url : '';
+
+ $original_title = get_term_field( 'name', $menu_item->object_id, $menu_item->object, 'raw' );
+ if ( is_wp_error( $original_title ) )
+ $original_title = false;
+ $menu_item->title = '' == $menu_item->post_title ? $original_title : $menu_item->post_title;
+
+ } else {
+ $menu_item->type_label = __('Custom');
+ $menu_item->title = $menu_item->post_title;
+ $menu_item->url = empty( $menu_item->url ) ? get_post_meta( $menu_item->ID, '_menu_item_url', true ) : $menu_item->url;
+ }
+
+ $menu_item->target = empty( $menu_item->target ) ? get_post_meta( $menu_item->ID, '_menu_item_target', true ) : $menu_item->target;
+
+ $menu_item->attr_title = empty( $menu_item->attr_title ) ? apply_filters( 'nav_menu_attr_title', $menu_item->post_excerpt ) : $menu_item->attr_title;
+
+ if ( empty( $menu_item->description ) )
+ $menu_item->description = apply_filters( 'nav_menu_description', wp_trim_words( $menu_item->post_content, 200 ) );
+
+ $menu_item->classes = empty( $menu_item->classes ) ? (array) get_post_meta( $menu_item->ID, '_menu_item_classes', true ) : $menu_item->classes;
+ $menu_item->xfn = empty( $menu_item->xfn ) ? get_post_meta( $menu_item->ID, '_menu_item_xfn', true ) : $menu_item->xfn;
+ } else {
+ $menu_item->db_id = 0;
+ $menu_item->menu_item_parent = 0;
+ $menu_item->object_id = (int) $menu_item->ID;
+ $menu_item->type = 'post_type';
+
+ $object = get_post_type_object( $menu_item->post_type );
+ $menu_item->object = $object->name;
+ $menu_item->type_label = $object->labels->singular_name;
+
+ if ( '' === $menu_item->post_title )
+ $menu_item->post_title = sprintf( __( '#%d (no title)' ), $menu_item->ID );
+
+ $menu_item->title = $menu_item->post_title;
+ $menu_item->url = get_permalink( $menu_item->ID );
+ $menu_item->target = '';
+
+ $menu_item->attr_title = apply_filters( 'nav_menu_attr_title', '' );
+ $menu_item->description = apply_filters( 'nav_menu_description', '' );
+ $menu_item->classes = array();
+ $menu_item->xfn = '';
+ }
+ } elseif ( isset( $menu_item->taxonomy ) ) {
+ $menu_item->ID = $menu_item->term_id;
+ $menu_item->db_id = 0;
+ $menu_item->menu_item_parent = 0;
+ $menu_item->object_id = (int) $menu_item->term_id;
+ $menu_item->post_parent = (int) $menu_item->parent;
+ $menu_item->type = 'taxonomy';
+
+ $object = get_taxonomy( $menu_item->taxonomy );
+ $menu_item->object = $object->name;
+ $menu_item->type_label = $object->labels->singular_name;
+
+ $menu_item->title = $menu_item->name;
+ $menu_item->url = get_term_link( $menu_item, $menu_item->taxonomy );
+ $menu_item->target = '';
+ $menu_item->attr_title = '';
+ $menu_item->description = get_term_field( 'description', $menu_item->term_id, $menu_item->taxonomy );
+ $menu_item->classes = array();
+ $menu_item->xfn = '';
+
+ }
+
+ return apply_filters( 'wp_setup_nav_menu_item', $menu_item );
+}
+
+/**
+ * Get the menu items associated with a particular object.
+ *
+ * @since 3.0.0
+ *
+ * @param int $object_id The ID of the original object.
+ * @param string $object_type The type of object, such as "taxonomy" or "post_type."
+ * @return array The array of menu item IDs; empty array if none;
+ */
+function wp_get_associated_nav_menu_items( $object_id = 0, $object_type = 'post_type' ) {
+ $object_id = (int) $object_id;
+ $menu_item_ids = array();
+
+ $query = new WP_Query;
+ $menu_items = $query->query(
+ array(
+ 'meta_key' => '_menu_item_object_id',
+ 'meta_value' => $object_id,
+ 'post_status' => 'any',
+ 'post_type' => 'nav_menu_item',
+ 'posts_per_page' => -1,
+ )
+ );
+ foreach( (array) $menu_items as $menu_item ) {
+ if ( isset( $menu_item->ID ) && is_nav_menu_item( $menu_item->ID ) ) {
+ if ( get_post_meta( $menu_item->ID, '_menu_item_type', true ) != $object_type )
+ continue;
+
+ $menu_item_ids[] = (int) $menu_item->ID;
+ }
+ }
+
+ return array_unique( $menu_item_ids );
+}
+
+/**
+ * Callback for handling a menu item when its original object is deleted.
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param int $object_id The ID of the original object being trashed.
+ *
+ */
+function _wp_delete_post_menu_item( $object_id = 0 ) {
+ $object_id = (int) $object_id;
+
+ $menu_item_ids = wp_get_associated_nav_menu_items( $object_id, 'post_type' );
+
+ foreach( (array) $menu_item_ids as $menu_item_id ) {
+ wp_delete_post( $menu_item_id, true );
+ }
+}
+
+/**
+ * Callback for handling a menu item when its original object is deleted.
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param int $object_id The ID of the original object being trashed.
+ *
+ */
+function _wp_delete_tax_menu_item( $object_id = 0 ) {
+ $object_id = (int) $object_id;
+
+ $menu_item_ids = wp_get_associated_nav_menu_items( $object_id, 'taxonomy' );
+
+ foreach( (array) $menu_item_ids as $menu_item_id ) {
+ wp_delete_post( $menu_item_id, true );
+ }
+}
+
+/**
+ * Automatically add newly published page objects to menus with that as an option.
+ *
+ * @since 3.0.0
+ * @access private
+ *
+ * @param string $new_status The new status of the post object.
+ * @param string $old_status The old status of the post object.
+ * @param object $post The post object being transitioned from one status to another.
+ * @return void
+ */
+function _wp_auto_add_pages_to_menu( $new_status, $old_status, $post ) {
+ if ( 'publish' != $new_status || 'publish' == $old_status || 'page' != $post->post_type )
+ return;
+ if ( ! empty( $post->post_parent ) )
+ return;
+ $auto_add = get_option( 'nav_menu_options' );
+ if ( empty( $auto_add ) || ! is_array( $auto_add ) || ! isset( $auto_add['auto_add'] ) )
+ return;
+ $auto_add = $auto_add['auto_add'];
+ if ( empty( $auto_add ) || ! is_array( $auto_add ) )
+ return;
+
+ $args = array(
+ 'menu-item-object-id' => $post->ID,
+ 'menu-item-object' => $post->post_type,
+ 'menu-item-type' => 'post_type',
+ 'menu-item-status' => 'publish',
+ );
+
+ foreach ( $auto_add as $menu_id ) {
+ $items = wp_get_nav_menu_items( $menu_id, array( 'post_status' => 'publish,draft' ) );
+ if ( ! is_array( $items ) )
+ continue;
+ foreach ( $items as $item ) {
+ if ( $post->ID == $item->object_id )
+ continue 2;
+ }
+ wp_update_nav_menu_item( $menu_id, 0, $args );
+ }
+}
diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php
new file mode 100644
index 0000000000..3df89c2c25
--- /dev/null
+++ b/src/wp-includes/option.php
@@ -0,0 +1,1059 @@
+<?php
+/**
+ * Option API
+ *
+ * @package WordPress
+ */
+
+/**
+ * Retrieve option value based on name of option.
+ *
+ * If the option does not exist or does not have a value, then the return value
+ * will be false. This is useful to check whether you need to install an option
+ * and is commonly used during installation of plugin options and to test
+ * whether upgrading is required.
+ *
+ * If the option was serialized then it will be unserialized when it is returned.
+ *
+ * @since 1.5.0
+ * @package WordPress
+ * @subpackage Option
+ * @uses apply_filters() Calls 'pre_option_$option' before checking the option.
+ * Any value other than false will "short-circuit" the retrieval of the option
+ * and return the returned value. You should not try to override special options,
+ * but you will not be prevented from doing so.
+ * @uses apply_filters() Calls 'option_$option', after checking the option, with
+ * the option value.
+ *
+ * @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
+ * @param mixed $default Optional. Default value to return if the option does not exist.
+ * @return mixed Value set for the option.
+ */
+function get_option( $option, $default = false ) {
+ global $wpdb;
+
+ $option = trim( $option );
+ if ( empty( $option ) )
+ return false;
+
+ // Allow plugins to short-circuit options.
+ $pre = apply_filters( 'pre_option_' . $option, false );
+ if ( false !== $pre )
+ return $pre;
+
+ if ( defined( 'WP_SETUP_CONFIG' ) )
+ return false;
+
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ // prevent non-existent options from triggering multiple queries
+ $notoptions = wp_cache_get( 'notoptions', 'options' );
+ if ( isset( $notoptions[$option] ) )
+ return apply_filters( 'default_option_' . $option, $default );
+
+ $alloptions = wp_load_alloptions();
+
+ if ( isset( $alloptions[$option] ) ) {
+ $value = $alloptions[$option];
+ } else {
+ $value = wp_cache_get( $option, 'options' );
+
+ if ( false === $value ) {
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
+
+ // Has to be get_row instead of get_var because of funkiness with 0, false, null values
+ if ( is_object( $row ) ) {
+ $value = $row->option_value;
+ wp_cache_add( $option, $value, 'options' );
+ } else { // option does not exist, so we must cache its non-existence
+ $notoptions[$option] = true;
+ wp_cache_set( 'notoptions', $notoptions, 'options' );
+ return apply_filters( 'default_option_' . $option, $default );
+ }
+ }
+ }
+ } else {
+ $suppress = $wpdb->suppress_errors();
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
+ $wpdb->suppress_errors( $suppress );
+ if ( is_object( $row ) )
+ $value = $row->option_value;
+ else
+ return apply_filters( 'default_option_' . $option, $default );
+ }
+
+ // If home is not set use siteurl.
+ if ( 'home' == $option && '' == $value )
+ return get_option( 'siteurl' );
+
+ if ( in_array( $option, array('siteurl', 'home', 'category_base', 'tag_base') ) )
+ $value = untrailingslashit( $value );
+
+ return apply_filters( 'option_' . $option, maybe_unserialize( $value ) );
+}
+
+/**
+ * Protect WordPress special option from being modified.
+ *
+ * Will die if $option is in protected list. Protected options are 'alloptions'
+ * and 'notoptions' options.
+ *
+ * @since 2.2.0
+ * @package WordPress
+ * @subpackage Option
+ *
+ * @param string $option Option name.
+ */
+function wp_protect_special_option( $option ) {
+ if ( 'alloptions' === $option || 'notoptions' === $option )
+ wp_die( sprintf( __( '%s is a protected WP option and may not be modified' ), esc_html( $option ) ) );
+}
+
+/**
+ * Print option value after sanitizing for forms.
+ *
+ * @uses attr Sanitizes value.
+ * @since 1.5.0
+ * @package WordPress
+ * @subpackage Option
+ *
+ * @param string $option Option name.
+ */
+function form_option( $option ) {
+ echo esc_attr( get_option( $option ) );
+}
+
+/**
+ * Loads and caches all autoloaded options, if available or all options.
+ *
+ * @since 2.2.0
+ * @package WordPress
+ * @subpackage Option
+ *
+ * @return array List of all options.
+ */
+function wp_load_alloptions() {
+ global $wpdb;
+
+ if ( !defined( 'WP_INSTALLING' ) || !is_multisite() )
+ $alloptions = wp_cache_get( 'alloptions', 'options' );
+ else
+ $alloptions = false;
+
+ if ( !$alloptions ) {
+ $suppress = $wpdb->suppress_errors();
+ if ( !$alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE autoload = 'yes'" ) )
+ $alloptions_db = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
+ $wpdb->suppress_errors($suppress);
+ $alloptions = array();
+ foreach ( (array) $alloptions_db as $o ) {
+ $alloptions[$o->option_name] = $o->option_value;
+ }
+ if ( !defined( 'WP_INSTALLING' ) || !is_multisite() )
+ wp_cache_add( 'alloptions', $alloptions, 'options' );
+ }
+
+ return $alloptions;
+}
+
+/**
+ * Loads and caches certain often requested site options if is_multisite() and a persistent cache is not being used.
+ *
+ * @since 3.0.0
+ * @package WordPress
+ * @subpackage Option
+ *
+ * @param int $site_id Optional site ID for which to query the options. Defaults to the current site.
+ */
+function wp_load_core_site_options( $site_id = null ) {
+ global $wpdb, $_wp_using_ext_object_cache;
+
+ if ( !is_multisite() || $_wp_using_ext_object_cache || defined( 'WP_INSTALLING' ) )
+ return;
+
+ if ( empty($site_id) )
+ $site_id = $wpdb->siteid;
+
+ $core_options = array('site_name', 'siteurl', 'active_sitewide_plugins', '_site_transient_timeout_theme_roots', '_site_transient_theme_roots', 'site_admins', 'can_compress_scripts', 'global_terms_enabled', 'ms_files_rewriting' );
+
+ $core_options_in = "'" . implode("', '", $core_options) . "'";
+ $options = $wpdb->get_results( $wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->sitemeta WHERE meta_key IN ($core_options_in) AND site_id = %d", $site_id) );
+
+ foreach ( $options as $option ) {
+ $key = $option->meta_key;
+ $cache_key = "{$site_id}:$key";
+ $option->meta_value = maybe_unserialize( $option->meta_value );
+
+ wp_cache_set( $cache_key, $option->meta_value, 'site-options' );
+ }
+}
+
+/**
+ * Update the value of an option that was already added.
+ *
+ * You do not need to serialize values. If the value needs to be serialized, then
+ * it will be serialized before it is inserted into the database. Remember,
+ * resources can not be serialized or added as an option.
+ *
+ * If the option does not exist, then the option will be added with the option
+ * value, but you will not be able to set whether it is autoloaded. If you want
+ * to set whether an option is autoloaded, then you need to use the add_option().
+ *
+ * @since 1.0.0
+ * @package WordPress
+ * @subpackage Option
+ *
+ * @uses apply_filters() Calls 'pre_update_option_$option' hook to allow overwriting the
+ * option value to be stored.
+ * @uses do_action() Calls 'update_option' hook before updating the option.
+ * @uses do_action() Calls 'update_option_$option' and 'updated_option' hooks on success.
+ *
+ * @param string $option Option name. Expected to not be SQL-escaped.
+ * @param mixed $newvalue Option value. Expected to not be SQL-escaped.
+ * @return bool False if value was not updated and true if value was updated.
+ */
+function update_option( $option, $newvalue ) {
+ global $wpdb;
+
+ $option = trim($option);
+ if ( empty($option) )
+ return false;
+
+ wp_protect_special_option( $option );
+
+ if ( is_object($newvalue) )
+ $newvalue = clone $newvalue;
+
+ $newvalue = sanitize_option( $option, $newvalue );
+ $oldvalue = get_option( $option );
+ $newvalue = apply_filters( 'pre_update_option_' . $option, $newvalue, $oldvalue );
+
+ // If the new and old values are the same, no need to update.
+ if ( $newvalue === $oldvalue )
+ return false;
+
+ if ( false === $oldvalue )
+ return add_option( $option, $newvalue );
+
+ $notoptions = wp_cache_get( 'notoptions', 'options' );
+ if ( is_array( $notoptions ) && isset( $notoptions[$option] ) ) {
+ unset( $notoptions[$option] );
+ wp_cache_set( 'notoptions', $notoptions, 'options' );
+ }
+
+ $_newvalue = $newvalue;
+ $newvalue = maybe_serialize( $newvalue );
+
+ do_action( 'update_option', $option, $oldvalue, $_newvalue );
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ $alloptions = wp_load_alloptions();
+ if ( isset( $alloptions[$option] ) ) {
+ $alloptions[$option] = $newvalue;
+ wp_cache_set( 'alloptions', $alloptions, 'options' );
+ } else {
+ wp_cache_set( $option, $newvalue, 'options' );
+ }
+ }
+
+ $result = $wpdb->update( $wpdb->options, array( 'option_value' => $newvalue ), array( 'option_name' => $option ) );
+
+ if ( $result ) {
+ do_action( "update_option_{$option}", $oldvalue, $_newvalue );
+ do_action( 'updated_option', $option, $oldvalue, $_newvalue );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Add a new option.
+ *
+ * You do not need to serialize values. If the value needs to be serialized, then
+ * it will be serialized before it is inserted into the database. Remember,
+ * resources can not be serialized or added as an option.
+ *
+ * You can create options without values and then update the values later.
+ * Existing options will not be updated and checks are performed to ensure that you
+ * aren't adding a protected WordPress option. Care should be taken to not name
+ * options the same as the ones which are protected.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 1.0.0
+ *
+ * @uses do_action() Calls 'add_option' hook before adding the option.
+ * @uses do_action() Calls 'add_option_$option' and 'added_option' hooks on success.
+ *
+ * @param string $option Name of option to add. Expected to not be SQL-escaped.
+ * @param mixed $value Optional. Option value, can be anything. Expected to not be SQL-escaped.
+ * @param mixed $deprecated Optional. Description. Not used anymore.
+ * @param bool $autoload Optional. Default is enabled. Whether to load the option when WordPress starts up.
+ * @return bool False if option was not added and true if option was added.
+ */
+function add_option( $option, $value = '', $deprecated = '', $autoload = 'yes' ) {
+ global $wpdb;
+
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.3' );
+
+ $option = trim($option);
+ if ( empty($option) )
+ return false;
+
+ wp_protect_special_option( $option );
+
+ if ( is_object($value) )
+ $value = clone $value;
+
+ $value = sanitize_option( $option, $value );
+
+ // Make sure the option doesn't already exist. We can check the 'notoptions' cache before we ask for a db query
+ $notoptions = wp_cache_get( 'notoptions', 'options' );
+ if ( !is_array( $notoptions ) || !isset( $notoptions[$option] ) )
+ if ( false !== get_option( $option ) )
+ return false;
+
+ $_value = $value;
+ $value = maybe_serialize( $value );
+ $autoload = ( 'no' === $autoload ) ? 'no' : 'yes';
+ do_action( 'add_option', $option, $_value );
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ if ( 'yes' == $autoload ) {
+ $alloptions = wp_load_alloptions();
+ $alloptions[$option] = $value;
+ wp_cache_set( 'alloptions', $alloptions, 'options' );
+ } else {
+ wp_cache_set( $option, $value, 'options' );
+ }
+ }
+
+ // This option exists now
+ $notoptions = wp_cache_get( 'notoptions', 'options' ); // yes, again... we need it to be fresh
+ if ( is_array( $notoptions ) && isset( $notoptions[$option] ) ) {
+ unset( $notoptions[$option] );
+ wp_cache_set( 'notoptions', $notoptions, 'options' );
+ }
+
+ $result = $wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", $option, $value, $autoload ) );
+
+ if ( $result ) {
+ do_action( "add_option_{$option}", $option, $_value );
+ do_action( 'added_option', $option, $_value );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Removes option by name. Prevents removal of protected WordPress options.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 1.2.0
+ *
+ * @uses do_action() Calls 'delete_option' hook before option is deleted.
+ * @uses do_action() Calls 'deleted_option' and 'delete_option_$option' hooks on success.
+ *
+ * @param string $option Name of option to remove. Expected to not be SQL-escaped.
+ * @return bool True, if option is successfully deleted. False on failure.
+ */
+function delete_option( $option ) {
+ global $wpdb;
+
+ $option = trim( $option );
+ if ( empty( $option ) )
+ return false;
+
+ wp_protect_special_option( $option );
+
+ // Get the ID, if no ID then return
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT autoload FROM $wpdb->options WHERE option_name = %s", $option ) );
+ if ( is_null( $row ) )
+ return false;
+ do_action( 'delete_option', $option );
+ $result = $wpdb->delete( $wpdb->options, array( 'option_name' => $option ) );
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ if ( 'yes' == $row->autoload ) {
+ $alloptions = wp_load_alloptions();
+ if ( is_array( $alloptions ) && isset( $alloptions[$option] ) ) {
+ unset( $alloptions[$option] );
+ wp_cache_set( 'alloptions', $alloptions, 'options' );
+ }
+ } else {
+ wp_cache_delete( $option, 'options' );
+ }
+ }
+ if ( $result ) {
+ do_action( "delete_option_$option", $option );
+ do_action( 'deleted_option', $option );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Delete a transient.
+ *
+ * @since 2.8.0
+ * @package WordPress
+ * @subpackage Transient
+ *
+ * @uses do_action() Calls 'delete_transient_$transient' hook before transient is deleted.
+ * @uses do_action() Calls 'deleted_transient' hook on success.
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @return bool true if successful, false otherwise
+ */
+function delete_transient( $transient ) {
+ global $_wp_using_ext_object_cache;
+
+ do_action( 'delete_transient_' . $transient, $transient );
+
+ if ( $_wp_using_ext_object_cache ) {
+ $result = wp_cache_delete( $transient, 'transient' );
+ } else {
+ $option_timeout = '_transient_timeout_' . $transient;
+ $option = '_transient_' . $transient;
+ $result = delete_option( $option );
+ if ( $result )
+ delete_option( $option_timeout );
+ }
+
+ if ( $result )
+ do_action( 'deleted_transient', $transient );
+ return $result;
+}
+
+/**
+ * Get the value of a transient.
+ *
+ * If the transient does not exist or does not have a value, then the return value
+ * will be false.
+ *
+ * @uses apply_filters() Calls 'pre_transient_$transient' hook before checking the transient.
+ * Any value other than false will "short-circuit" the retrieval of the transient
+ * and return the returned value.
+ * @uses apply_filters() Calls 'transient_$option' hook, after checking the transient, with
+ * the transient value.
+ *
+ * @since 2.8.0
+ * @package WordPress
+ * @subpackage Transient
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped
+ * @return mixed Value of transient
+ */
+function get_transient( $transient ) {
+ global $_wp_using_ext_object_cache;
+
+ $pre = apply_filters( 'pre_transient_' . $transient, false );
+ if ( false !== $pre )
+ return $pre;
+
+ if ( $_wp_using_ext_object_cache ) {
+ $value = wp_cache_get( $transient, 'transient' );
+ } else {
+ $transient_option = '_transient_' . $transient;
+ if ( ! defined( 'WP_INSTALLING' ) ) {
+ // If option is not in alloptions, it is not autoloaded and thus has a timeout
+ $alloptions = wp_load_alloptions();
+ if ( !isset( $alloptions[$transient_option] ) ) {
+ $transient_timeout = '_transient_timeout_' . $transient;
+ if ( get_option( $transient_timeout ) < time() ) {
+ delete_option( $transient_option );
+ delete_option( $transient_timeout );
+ return false;
+ }
+ }
+ }
+
+ $value = get_option( $transient_option );
+ }
+
+ return apply_filters( 'transient_' . $transient, $value );
+}
+
+/**
+ * Set/update the value of a transient.
+ *
+ * You do not need to serialize values. If the value needs to be serialized, then
+ * it will be serialized before it is set.
+ *
+ * @since 2.8.0
+ * @package WordPress
+ * @subpackage Transient
+ *
+ * @uses apply_filters() Calls 'pre_set_transient_$transient' hook to allow overwriting the
+ * transient value to be stored.
+ * @uses do_action() Calls 'set_transient_$transient' and 'setted_transient' hooks on success.
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @param mixed $value Transient value. Expected to not be SQL-escaped.
+ * @param int $expiration Time until expiration in seconds, default 0
+ * @return bool False if value was not set and true if value was set.
+ */
+function set_transient( $transient, $value, $expiration = 0 ) {
+ global $_wp_using_ext_object_cache;
+
+ $value = apply_filters( 'pre_set_transient_' . $transient, $value );
+
+ if ( $_wp_using_ext_object_cache ) {
+ $result = wp_cache_set( $transient, $value, 'transient', $expiration );
+ } else {
+ $transient_timeout = '_transient_timeout_' . $transient;
+ $transient = '_transient_' . $transient;
+ if ( false === get_option( $transient ) ) {
+ $autoload = 'yes';
+ if ( $expiration ) {
+ $autoload = 'no';
+ add_option( $transient_timeout, time() + $expiration, '', 'no' );
+ }
+ $result = add_option( $transient, $value, '', $autoload );
+ } else {
+ if ( $expiration )
+ update_option( $transient_timeout, time() + $expiration );
+ $result = update_option( $transient, $value );
+ }
+ }
+ if ( $result ) {
+ do_action( 'set_transient_' . $transient, $value, $expiration );
+ do_action( 'setted_transient', $transient, $value, $expiration );
+ }
+ return $result;
+}
+
+/**
+ * Saves and restores user interface settings stored in a cookie.
+ *
+ * Checks if the current user-settings cookie is updated and stores it. When no
+ * cookie exists (different browser used), adds the last saved cookie restoring
+ * the settings.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.7.0
+ */
+function wp_user_settings() {
+
+ if ( ! is_admin() )
+ return;
+
+ if ( defined('DOING_AJAX') )
+ return;
+
+ if ( ! $user = wp_get_current_user() )
+ return;
+
+ if ( is_super_admin( $user->ID ) &&
+ ! in_array( get_current_blog_id(), array_keys( get_blogs_of_user( $user->ID ) ) )
+ )
+ return;
+
+ $settings = get_user_option( 'user-settings', $user->ID );
+
+ if ( isset( $_COOKIE['wp-settings-' . $user->ID] ) ) {
+ $cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE['wp-settings-' . $user->ID] );
+
+ if ( ! empty( $cookie ) && strpos( $cookie, '=' ) ) {
+ if ( $cookie == $settings )
+ return;
+
+ $last_time = (int) get_user_option( 'user-settings-time', $user->ID );
+ $saved = isset( $_COOKIE['wp-settings-time-' . $user->ID]) ? preg_replace( '/[^0-9]/', '', $_COOKIE['wp-settings-time-' . $user->ID] ) : 0;
+
+ if ( $saved > $last_time ) {
+ update_user_option( $user->ID, 'user-settings', $cookie, false );
+ update_user_option( $user->ID, 'user-settings-time', time() - 5, false );
+ return;
+ }
+ }
+ }
+
+ setcookie( 'wp-settings-' . $user->ID, $settings, time() + YEAR_IN_SECONDS, SITECOOKIEPATH );
+ setcookie( 'wp-settings-time-' . $user->ID, time(), time() + YEAR_IN_SECONDS, SITECOOKIEPATH );
+ $_COOKIE['wp-settings-' . $user->ID] = $settings;
+}
+
+/**
+ * Retrieve user interface setting value based on setting name.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.7.0
+ *
+ * @param string $name The name of the setting.
+ * @param string $default Optional default value to return when $name is not set.
+ * @return mixed the last saved user setting or the default value/false if it doesn't exist.
+ */
+function get_user_setting( $name, $default = false ) {
+
+ $all = get_all_user_settings();
+
+ return isset($all[$name]) ? $all[$name] : $default;
+}
+
+/**
+ * Add or update user interface setting.
+ *
+ * Both $name and $value can contain only ASCII letters, numbers and underscores.
+ * This function has to be used before any output has started as it calls setcookie().
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.8.0
+ *
+ * @param string $name The name of the setting.
+ * @param string $value The value for the setting.
+ * @return bool true if set successfully/false if not.
+ */
+function set_user_setting( $name, $value ) {
+
+ if ( headers_sent() )
+ return false;
+
+ $all = get_all_user_settings();
+ $name = preg_replace( '/[^A-Za-z0-9_]+/', '', $name );
+
+ if ( empty($name) )
+ return false;
+
+ $all[$name] = $value;
+
+ return wp_set_all_user_settings($all);
+}
+
+/**
+ * Delete user interface settings.
+ *
+ * Deleting settings would reset them to the defaults.
+ * This function has to be used before any output has started as it calls setcookie().
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.7.0
+ *
+ * @param mixed $names The name or array of names of the setting to be deleted.
+ * @return bool true if deleted successfully/false if not.
+ */
+function delete_user_setting( $names ) {
+
+ if ( headers_sent() )
+ return false;
+
+ $all = get_all_user_settings();
+ $names = (array) $names;
+
+ foreach ( $names as $name ) {
+ if ( isset($all[$name]) ) {
+ unset($all[$name]);
+ $deleted = true;
+ }
+ }
+
+ if ( isset($deleted) )
+ return wp_set_all_user_settings($all);
+
+ return false;
+}
+
+/**
+ * Retrieve all user interface settings.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.7.0
+ *
+ * @return array the last saved user settings or empty array.
+ */
+function get_all_user_settings() {
+ global $_updated_user_settings;
+
+ if ( ! $user = wp_get_current_user() )
+ return array();
+
+ if ( isset($_updated_user_settings) && is_array($_updated_user_settings) )
+ return $_updated_user_settings;
+
+ $all = array();
+ if ( isset($_COOKIE['wp-settings-' . $user->ID]) ) {
+ $cookie = preg_replace( '/[^A-Za-z0-9=&_]/', '', $_COOKIE['wp-settings-' . $user->ID] );
+
+ if ( $cookie && strpos($cookie, '=') ) // the '=' cannot be 1st char
+ parse_str($cookie, $all);
+
+ } else {
+ $option = get_user_option('user-settings', $user->ID);
+ if ( $option && is_string($option) )
+ parse_str( $option, $all );
+ }
+
+ return $all;
+}
+
+/**
+ * Private. Set all user interface settings.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.8.0
+ *
+ * @param unknown $all
+ * @return bool
+ */
+function wp_set_all_user_settings($all) {
+ global $_updated_user_settings;
+
+ if ( ! $user = wp_get_current_user() )
+ return false;
+
+ if ( is_super_admin( $user->ID ) &&
+ ! in_array( get_current_blog_id(), array_keys( get_blogs_of_user( $user->ID ) ) )
+ )
+ return;
+
+ $_updated_user_settings = $all;
+ $settings = '';
+ foreach ( $all as $k => $v ) {
+ $v = preg_replace( '/[^A-Za-z0-9_]+/', '', $v );
+ $settings .= $k . '=' . $v . '&';
+ }
+
+ $settings = rtrim($settings, '&');
+
+ update_user_option( $user->ID, 'user-settings', $settings, false );
+ update_user_option( $user->ID, 'user-settings-time', time(), false );
+
+ return true;
+}
+
+/**
+ * Delete the user settings of the current user.
+ *
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.7.0
+ */
+function delete_all_user_settings() {
+ if ( ! $user = wp_get_current_user() )
+ return;
+
+ update_user_option( $user->ID, 'user-settings', '', false );
+ setcookie('wp-settings-' . $user->ID, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH);
+}
+
+/**
+ * Retrieve site option value based on name of option.
+ *
+ * @see get_option()
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.8.0
+ *
+ * @uses apply_filters() Calls 'pre_site_option_$option' before checking the option.
+ * Any value other than false will "short-circuit" the retrieval of the option
+ * and return the returned value.
+ * @uses apply_filters() Calls 'site_option_$option', after checking the option, with
+ * the option value.
+ *
+ * @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
+ * @param mixed $default Optional value to return if option doesn't exist. Default false.
+ * @param bool $use_cache Whether to use cache. Multisite only. Default true.
+ * @return mixed Value set for the option.
+ */
+function get_site_option( $option, $default = false, $use_cache = true ) {
+ global $wpdb;
+
+ // Allow plugins to short-circuit site options.
+ $pre = apply_filters( 'pre_site_option_' . $option, false );
+ if ( false !== $pre )
+ return $pre;
+
+ if ( ! is_multisite() ) {
+ $default = apply_filters( 'default_site_option_' . $option, $default );
+ $value = get_option($option, $default);
+ } else {
+ $cache_key = "{$wpdb->siteid}:$option";
+ if ( $use_cache )
+ $value = wp_cache_get($cache_key, 'site-options');
+
+ if ( !isset($value) || (false === $value) ) {
+ $row = $wpdb->get_row( $wpdb->prepare("SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s AND site_id = %d", $option, $wpdb->siteid ) );
+
+ // Has to be get_row instead of get_var because of funkiness with 0, false, null values
+ if ( is_object( $row ) ) {
+ $value = $row->meta_value;
+ $value = maybe_unserialize( $value );
+ wp_cache_set( $cache_key, $value, 'site-options' );
+ } else {
+ $value = apply_filters( 'default_site_option_' . $option, $default );
+ }
+ }
+ }
+
+ return apply_filters( 'site_option_' . $option, $value );
+}
+
+/**
+ * Add a new site option.
+ *
+ * Existing options will not be updated. Note that prior to 3.3 this wasn't the case.
+ *
+ * @see add_option()
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.8.0
+ *
+ * @uses apply_filters() Calls 'pre_add_site_option_$option' hook to allow overwriting the
+ * option value to be stored.
+ * @uses do_action() Calls 'add_site_option_$option' and 'add_site_option' hooks on success.
+ *
+ * @param string $option Name of option to add. Expected to not be SQL-escaped.
+ * @param mixed $value Optional. Option value, can be anything. Expected to not be SQL-escaped.
+ * @return bool False if option was not added and true if option was added.
+ */
+function add_site_option( $option, $value ) {
+ global $wpdb;
+
+ $value = apply_filters( 'pre_add_site_option_' . $option, $value );
+
+ if ( !is_multisite() ) {
+ $result = add_option( $option, $value );
+ } else {
+ $cache_key = "{$wpdb->siteid}:$option";
+
+ if ( false !== get_site_option( $option ) )
+ return false;
+
+ $value = sanitize_option( $option, $value );
+ wp_cache_set( $cache_key, $value, 'site-options' );
+
+ $_value = $value;
+ $value = maybe_serialize( $value );
+ $result = $wpdb->insert( $wpdb->sitemeta, array('site_id' => $wpdb->siteid, 'meta_key' => $option, 'meta_value' => $value ) );
+ $value = $_value;
+ }
+
+ if ( $result ) {
+ do_action( "add_site_option_{$option}", $option, $value );
+ do_action( "add_site_option", $option, $value );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Removes site option by name.
+ *
+ * @see delete_option()
+ * @package WordPress
+ * @subpackage Option
+ * @since 2.8.0
+ *
+ * @uses do_action() Calls 'pre_delete_site_option_$option' hook before option is deleted.
+ * @uses do_action() Calls 'delete_site_option' and 'delete_site_option_$option'
+ * hooks on success.
+ *
+ * @param string $option Name of option to remove. Expected to not be SQL-escaped.
+ * @return bool True, if succeed. False, if failure.
+ */
+function delete_site_option( $option ) {
+ global $wpdb;
+
+ // ms_protect_special_option( $option ); @todo
+
+ do_action( 'pre_delete_site_option_' . $option );
+
+ if ( !is_multisite() ) {
+ $result = delete_option( $option );
+ } else {
+ $row = $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM {$wpdb->sitemeta} WHERE meta_key = %s AND site_id = %d", $option, $wpdb->siteid ) );
+ if ( is_null( $row ) || !$row->meta_id )
+ return false;
+ $cache_key = "{$wpdb->siteid}:$option";
+ wp_cache_delete( $cache_key, 'site-options' );
+
+ $result = $wpdb->delete( $wpdb->sitemeta, array( 'meta_key' => $option, 'site_id' => $wpdb->siteid ) );
+ }
+
+ if ( $result ) {
+ do_action( "delete_site_option_{$option}", $option );
+ do_action( "delete_site_option", $option );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Update the value of a site option that was already added.
+ *
+ * @see update_option()
+ * @since 2.8.0
+ * @package WordPress
+ * @subpackage Option
+ *
+ * @uses apply_filters() Calls 'pre_update_site_option_$option' hook to allow overwriting the
+ * option value to be stored.
+ * @uses do_action() Calls 'update_site_option_$option' and 'update_site_option' hooks on success.
+ *
+ * @param string $option Name of option. Expected to not be SQL-escaped.
+ * @param mixed $value Option value. Expected to not be SQL-escaped.
+ * @return bool False if value was not updated and true if value was updated.
+ */
+function update_site_option( $option, $value ) {
+ global $wpdb;
+
+ $oldvalue = get_site_option( $option );
+ $value = apply_filters( 'pre_update_site_option_' . $option, $value, $oldvalue );
+
+ if ( $value === $oldvalue )
+ return false;
+
+ if ( false === $oldvalue )
+ return add_site_option( $option, $value );
+
+ if ( !is_multisite() ) {
+ $result = update_option( $option, $value );
+ } else {
+ $value = sanitize_option( $option, $value );
+ $cache_key = "{$wpdb->siteid}:$option";
+ wp_cache_set( $cache_key, $value, 'site-options' );
+
+ $_value = $value;
+ $value = maybe_serialize( $value );
+ $result = $wpdb->update( $wpdb->sitemeta, array( 'meta_value' => $value ), array( 'site_id' => $wpdb->siteid, 'meta_key' => $option ) );
+ $value = $_value;
+ }
+
+ if ( $result ) {
+ do_action( "update_site_option_{$option}", $option, $value, $oldvalue );
+ do_action( "update_site_option", $option, $value, $oldvalue );
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Delete a site transient.
+ *
+ * @since 2.9.0
+ * @package WordPress
+ * @subpackage Transient
+ *
+ * @uses do_action() Calls 'delete_site_transient_$transient' hook before transient is deleted.
+ * @uses do_action() Calls 'deleted_site_transient' hook on success.
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @return bool True if successful, false otherwise
+ */
+function delete_site_transient( $transient ) {
+ global $_wp_using_ext_object_cache;
+
+ do_action( 'delete_site_transient_' . $transient, $transient );
+ if ( $_wp_using_ext_object_cache ) {
+ $result = wp_cache_delete( $transient, 'site-transient' );
+ } else {
+ $option_timeout = '_site_transient_timeout_' . $transient;
+ $option = '_site_transient_' . $transient;
+ $result = delete_site_option( $option );
+ if ( $result )
+ delete_site_option( $option_timeout );
+ }
+ if ( $result )
+ do_action( 'deleted_site_transient', $transient );
+ return $result;
+}
+
+/**
+ * Get the value of a site transient.
+ *
+ * If the transient does not exist or does not have a value, then the return value
+ * will be false.
+ *
+ * @see get_transient()
+ * @since 2.9.0
+ * @package WordPress
+ * @subpackage Transient
+ *
+ * @uses apply_filters() Calls 'pre_site_transient_$transient' hook before checking the transient.
+ * Any value other than false will "short-circuit" the retrieval of the transient
+ * and return the returned value.
+ * @uses apply_filters() Calls 'site_transient_$option' hook, after checking the transient, with
+ * the transient value.
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @return mixed Value of transient
+ */
+function get_site_transient( $transient ) {
+ global $_wp_using_ext_object_cache;
+
+ $pre = apply_filters( 'pre_site_transient_' . $transient, false );
+ if ( false !== $pre )
+ return $pre;
+
+ if ( $_wp_using_ext_object_cache ) {
+ $value = wp_cache_get( $transient, 'site-transient' );
+ } else {
+ // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided.
+ $no_timeout = array('update_core', 'update_plugins', 'update_themes');
+ $transient_option = '_site_transient_' . $transient;
+ if ( ! in_array( $transient, $no_timeout ) ) {
+ $transient_timeout = '_site_transient_timeout_' . $transient;
+ $timeout = get_site_option( $transient_timeout );
+ if ( false !== $timeout && $timeout < time() ) {
+ delete_site_option( $transient_option );
+ delete_site_option( $transient_timeout );
+ return false;
+ }
+ }
+
+ $value = get_site_option( $transient_option );
+ }
+
+ return apply_filters( 'site_transient_' . $transient, $value );
+}
+
+/**
+ * Set/update the value of a site transient.
+ *
+ * You do not need to serialize values, if the value needs to be serialize, then
+ * it will be serialized before it is set.
+ *
+ * @see set_transient()
+ * @since 2.9.0
+ * @package WordPress
+ * @subpackage Transient
+ *
+ * @uses apply_filters() Calls 'pre_set_site_transient_$transient' hook to allow overwriting the
+ * transient value to be stored.
+ * @uses do_action() Calls 'set_site_transient_$transient' and 'setted_site_transient' hooks on success.
+ *
+ * @param string $transient Transient name. Expected to not be SQL-escaped.
+ * @param mixed $value Transient value. Expected to not be SQL-escaped.
+ * @param int $expiration Time until expiration in seconds, default 0
+ * @return bool False if value was not set and true if value was set.
+ */
+function set_site_transient( $transient, $value, $expiration = 0 ) {
+ global $_wp_using_ext_object_cache;
+
+ $value = apply_filters( 'pre_set_site_transient_' . $transient, $value );
+
+ if ( $_wp_using_ext_object_cache ) {
+ $result = wp_cache_set( $transient, $value, 'site-transient', $expiration );
+ } else {
+ $transient_timeout = '_site_transient_timeout_' . $transient;
+ $transient = '_site_transient_' . $transient;
+ if ( false === get_site_option( $transient ) ) {
+ if ( $expiration )
+ add_site_option( $transient_timeout, time() + $expiration );
+ $result = add_site_option( $transient, $value );
+ } else {
+ if ( $expiration )
+ update_site_option( $transient_timeout, time() + $expiration );
+ $result = update_site_option( $transient, $value );
+ }
+ }
+ if ( $result ) {
+ do_action( 'set_site_transient_' . $transient, $value, $expiration );
+ do_action( 'setted_site_transient', $transient, $value, $expiration );
+ }
+ return $result;
+}
diff --git a/src/wp-includes/pluggable-deprecated.php b/src/wp-includes/pluggable-deprecated.php
new file mode 100644
index 0000000000..02733b2b0f
--- /dev/null
+++ b/src/wp-includes/pluggable-deprecated.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * Deprecated pluggable functions from past WordPress versions. You shouldn't use these
+ * functions and look for the alternatives instead. The functions will be removed in a
+ * later version.
+ *
+ * Deprecated warnings are also thrown if one of these functions is being defined by a plugin.
+ *
+ * @package WordPress
+ * @subpackage Deprecated
+ * @see pluggable.php
+ */
+
+/*
+ * Deprecated functions come here to die.
+ */
+
+if ( !function_exists('set_current_user') ) :
+/**
+ * Changes the current user by ID or name.
+ *
+ * Set $id to null and specify a name if you do not know a user's ID.
+ *
+ * @since 2.0.1
+ * @see wp_set_current_user() An alias of wp_set_current_user()
+ * @deprecated 3.0.0
+ * @deprecated Use wp_set_current_user()
+ *
+ * @param int|null $id User ID.
+ * @param string $name Optional. The user's username
+ * @return object returns wp_set_current_user()
+ */
+function set_current_user($id, $name = '') {
+ _deprecated_function( __FUNCTION__, '3.0', 'wp_set_current_user()' );
+ return wp_set_current_user($id, $name);
+}
+endif;
+
+if ( !function_exists('get_userdatabylogin') ) :
+/**
+ * Retrieve user info by login name.
+ *
+ * @since 0.71
+ * @deprecated 3.3.0
+ * @deprecated Use get_user_by('login')
+ *
+ * @param string $user_login User's username
+ * @return bool|object False on failure, User DB row object
+ */
+function get_userdatabylogin($user_login) {
+ _deprecated_function( __FUNCTION__, '3.3', "get_user_by('login')" );
+ return get_user_by('login', $user_login);
+}
+endif;
+
+if ( !function_exists('get_user_by_email') ) :
+/**
+ * Retrieve user info by email.
+ *
+ * @since 2.5
+ * @deprecated 3.3.0
+ * @deprecated Use get_user_by('email')
+ *
+ * @param string $email User's email address
+ * @return bool|object False on failure, User DB row object
+ */
+function get_user_by_email($email) {
+ _deprecated_function( __FUNCTION__, '3.3', "get_user_by('email')" );
+ return get_user_by('email', $email);
+}
+endif;
+
+if ( !function_exists('wp_setcookie') ) :
+/**
+ * Sets a cookie for a user who just logged in. This function is deprecated.
+ *
+ * @since 1.5
+ * @deprecated 2.5
+ * @deprecated Use wp_set_auth_cookie()
+ * @see wp_set_auth_cookie()
+ *
+ * @param string $username The user's username
+ * @param string $password Optional. The user's password
+ * @param bool $already_md5 Optional. Whether the password has already been through MD5
+ * @param string $home Optional. Will be used instead of COOKIEPATH if set
+ * @param string $siteurl Optional. Will be used instead of SITECOOKIEPATH if set
+ * @param bool $remember Optional. Remember that the user is logged in
+ */
+function wp_setcookie($username, $password = '', $already_md5 = false, $home = '', $siteurl = '', $remember = false) {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_set_auth_cookie()' );
+ $user = get_user_by('login', $username);
+ wp_set_auth_cookie($user->ID, $remember);
+}
+else :
+ _deprecated_function( 'wp_setcookie', '2.5', 'wp_set_auth_cookie()' );
+endif;
+
+if ( !function_exists('wp_clearcookie') ) :
+/**
+ * Clears the authentication cookie, logging the user out. This function is deprecated.
+ *
+ * @since 1.5
+ * @deprecated 2.5
+ * @deprecated Use wp_clear_auth_cookie()
+ * @see wp_clear_auth_cookie()
+ */
+function wp_clearcookie() {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_clear_auth_cookie()' );
+ wp_clear_auth_cookie();
+}
+else :
+ _deprecated_function( 'wp_clearcookie', '2.5', 'wp_clear_auth_cookie()' );
+endif;
+
+if ( !function_exists('wp_get_cookie_login') ):
+/**
+ * Gets the user cookie login. This function is deprecated.
+ *
+ * This function is deprecated and should no longer be extended as it won't be
+ * used anywhere in WordPress. Also, plugins shouldn't use it either.
+ *
+ * @since 2.0.3
+ * @deprecated 2.5
+ * @deprecated No alternative
+ *
+ * @return bool Always returns false
+ */
+function wp_get_cookie_login() {
+ _deprecated_function( __FUNCTION__, '2.5' );
+ return false;
+}
+else :
+ _deprecated_function( 'wp_get_cookie_login', '2.5' );
+endif;
+
+if ( !function_exists('wp_login') ) :
+/**
+ * Checks a users login information and logs them in if it checks out. This function is deprecated.
+ *
+ * Use the global $error to get the reason why the login failed. If the username
+ * is blank, no error will be set, so assume blank username on that case.
+ *
+ * Plugins extending this function should also provide the global $error and set
+ * what the error is, so that those checking the global for why there was a
+ * failure can utilize it later.
+ *
+ * @since 1.2.2
+ * @deprecated Use wp_signon()
+ * @global string $error Error when false is returned
+ *
+ * @param string $username User's username
+ * @param string $password User's password
+ * @param bool $deprecated Not used
+ * @return bool False on login failure, true on successful check
+ */
+function wp_login($username, $password, $deprecated = '') {
+ _deprecated_function( __FUNCTION__, '2.5', 'wp_signon()' );
+ global $error;
+
+ $user = wp_authenticate($username, $password);
+
+ if ( ! is_wp_error($user) )
+ return true;
+
+ $error = $user->get_error_message();
+ return false;
+}
+else :
+ _deprecated_function( 'wp_login', '2.5', 'wp_signon()' );
+endif;
+
+/**
+ * WordPress AtomPub API implementation.
+ *
+ * Originally stored in wp-app.php, and later wp-includes/class-wp-atom-server.php.
+ * It is kept here in case a plugin directly referred to the class.
+ *
+ * @since 2.2.0
+ * @deprecated 3.5.0
+ * @link http://wordpress.org/plugins/atom-publishing-protocol/
+ */
+if ( ! class_exists( 'wp_atom_server' ) ) {
+ class wp_atom_server {
+ public function __call( $name, $arguments ) {
+ _deprecated_function( __CLASS__ . '::' . $name, '3.5', 'the Atom Publishing Protocol plugin' );
+ }
+
+ public static function __callStatic( $name, $arguments ) {
+ _deprecated_function( __CLASS__ . '::' . $name, '3.5', 'the Atom Publishing Protocol plugin' );
+ }
+ }
+} \ No newline at end of file
diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php
new file mode 100644
index 0000000000..effa374dc9
--- /dev/null
+++ b/src/wp-includes/pluggable.php
@@ -0,0 +1,1750 @@
+<?php
+/**
+ * These functions can be replaced via plugins. If plugins do not redefine these
+ * functions, then these will be used instead.
+ *
+ * @package WordPress
+ */
+
+if ( !function_exists('wp_set_current_user') ) :
+/**
+ * Changes the current user by ID or name.
+ *
+ * Set $id to null and specify a name if you do not know a user's ID.
+ *
+ * Some WordPress functionality is based on the current user and not based on
+ * the signed in user. Therefore, it opens the ability to edit and perform
+ * actions on users who aren't signed in.
+ *
+ * @since 2.0.3
+ * @global object $current_user The current user object which holds the user data.
+ * @uses do_action() Calls 'set_current_user' hook after setting the current user.
+ *
+ * @param int $id User ID
+ * @param string $name User's username
+ * @return WP_User Current user User object
+ */
+function wp_set_current_user($id, $name = '') {
+ global $current_user;
+
+ if ( isset( $current_user ) && ( $current_user instanceof WP_User ) && ( $id == $current_user->ID ) )
+ return $current_user;
+
+ $current_user = new WP_User( $id, $name );
+
+ setup_userdata( $current_user->ID );
+
+ do_action('set_current_user');
+
+ return $current_user;
+}
+endif;
+
+if ( !function_exists('wp_get_current_user') ) :
+/**
+ * Retrieve the current user object.
+ *
+ * @since 2.0.3
+ *
+ * @return WP_User Current user WP_User object
+ */
+function wp_get_current_user() {
+ global $current_user;
+
+ get_currentuserinfo();
+
+ return $current_user;
+}
+endif;
+
+if ( !function_exists('get_currentuserinfo') ) :
+/**
+ * Populate global variables with information about the currently logged in user.
+ *
+ * Will set the current user, if the current user is not set. The current user
+ * will be set to the logged in person. If no user is logged in, then it will
+ * set the current user to 0, which is invalid and won't have any permissions.
+ *
+ * @since 0.71
+ * @uses $current_user Checks if the current user is set
+ * @uses wp_validate_auth_cookie() Retrieves current logged in user.
+ *
+ * @return bool|null False on XMLRPC Request and invalid auth cookie. Null when current user set
+ */
+function get_currentuserinfo() {
+ global $current_user;
+
+ if ( ! empty( $current_user ) ) {
+ if ( $current_user instanceof WP_User )
+ return;
+
+ // Upgrade stdClass to WP_User
+ if ( is_object( $current_user ) && isset( $current_user->ID ) ) {
+ $cur_id = $current_user->ID;
+ $current_user = null;
+ wp_set_current_user( $cur_id );
+ return;
+ }
+
+ // $current_user has a junk value. Force to WP_User with ID 0.
+ $current_user = null;
+ wp_set_current_user( 0 );
+ return false;
+ }
+
+ if ( defined('XMLRPC_REQUEST') && XMLRPC_REQUEST ) {
+ wp_set_current_user( 0 );
+ return false;
+ }
+
+ if ( ! $user = wp_validate_auth_cookie() ) {
+ if ( is_blog_admin() || is_network_admin() || empty( $_COOKIE[LOGGED_IN_COOKIE] ) || !$user = wp_validate_auth_cookie( $_COOKIE[LOGGED_IN_COOKIE], 'logged_in' ) ) {
+ wp_set_current_user( 0 );
+ return false;
+ }
+ }
+
+ wp_set_current_user( $user );
+}
+endif;
+
+if ( !function_exists('get_userdata') ) :
+/**
+ * Retrieve user info by user ID.
+ *
+ * @since 0.71
+ *
+ * @param int $user_id User ID
+ * @return bool|object False on failure, WP_User object on success
+ */
+function get_userdata( $user_id ) {
+ return get_user_by( 'id', $user_id );
+}
+endif;
+
+if ( !function_exists('get_user_by') ) :
+/**
+ * Retrieve user info by a given field
+ *
+ * @since 2.8.0
+ *
+ * @param string $field The field to retrieve the user with. id | slug | email | login
+ * @param int|string $value A value for $field. A user ID, slug, email address, or login name.
+ * @return bool|object False on failure, WP_User object on success
+ */
+function get_user_by( $field, $value ) {
+ $userdata = WP_User::get_data_by( $field, $value );
+
+ if ( !$userdata )
+ return false;
+
+ $user = new WP_User;
+ $user->init( $userdata );
+
+ return $user;
+}
+endif;
+
+if ( !function_exists('cache_users') ) :
+/**
+ * Retrieve info for user lists to prevent multiple queries by get_userdata()
+ *
+ * @since 3.0.0
+ *
+ * @param array $user_ids User ID numbers list
+ */
+function cache_users( $user_ids ) {
+ global $wpdb;
+
+ $clean = _get_non_cached_ids( $user_ids, 'users' );
+
+ if ( empty( $clean ) )
+ return;
+
+ $list = implode( ',', $clean );
+
+ $users = $wpdb->get_results( "SELECT * FROM $wpdb->users WHERE ID IN ($list)" );
+
+ $ids = array();
+ foreach ( $users as $user ) {
+ update_user_caches( $user );
+ $ids[] = $user->ID;
+ }
+ update_meta_cache( 'user', $ids );
+}
+endif;
+
+if ( !function_exists( 'wp_mail' ) ) :
+/**
+ * Send mail, similar to PHP's mail
+ *
+ * A true return value does not automatically mean that the user received the
+ * email successfully. It just only means that the method used was able to
+ * process the request without any errors.
+ *
+ * Using the two 'wp_mail_from' and 'wp_mail_from_name' hooks allow from
+ * creating a from address like 'Name <email@address.com>' when both are set. If
+ * just 'wp_mail_from' is set, then just the email address will be used with no
+ * name.
+ *
+ * The default content type is 'text/plain' which does not allow using HTML.
+ * However, you can set the content type of the email by using the
+ * 'wp_mail_content_type' filter.
+ *
+ * The default charset is based on the charset used on the blog. The charset can
+ * be set using the 'wp_mail_charset' filter.
+ *
+ * @since 1.2.1
+ * @uses apply_filters() Calls 'wp_mail' hook on an array of all of the parameters.
+ * @uses apply_filters() Calls 'wp_mail_from' hook to get the from email address.
+ * @uses apply_filters() Calls 'wp_mail_from_name' hook to get the from address name.
+ * @uses apply_filters() Calls 'wp_mail_content_type' hook to get the email content type.
+ * @uses apply_filters() Calls 'wp_mail_charset' hook to get the email charset
+ * @uses do_action_ref_array() Calls 'phpmailer_init' hook on the reference to
+ * phpmailer object.
+ * @uses PHPMailer
+ *
+ * @param string|array $to Array or comma-separated list of email addresses to send message.
+ * @param string $subject Email subject
+ * @param string $message Message contents
+ * @param string|array $headers Optional. Additional headers.
+ * @param string|array $attachments Optional. Files to attach.
+ * @return bool Whether the email contents were sent successfully.
+ */
+function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
+ // Compact the input, apply the filters, and extract them back out
+ extract( apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ) );
+
+ if ( !is_array($attachments) )
+ $attachments = explode( "\n", str_replace( "\r\n", "\n", $attachments ) );
+
+ global $phpmailer;
+
+ // (Re)create it, if it's gone missing
+ if ( !is_object( $phpmailer ) || !is_a( $phpmailer, 'PHPMailer' ) ) {
+ require_once ABSPATH . WPINC . '/class-phpmailer.php';
+ require_once ABSPATH . WPINC . '/class-smtp.php';
+ $phpmailer = new PHPMailer( true );
+ }
+
+ // Headers
+ if ( empty( $headers ) ) {
+ $headers = array();
+ } else {
+ if ( !is_array( $headers ) ) {
+ // Explode the headers out, so this function can take both
+ // string headers and an array of headers.
+ $tempheaders = explode( "\n", str_replace( "\r\n", "\n", $headers ) );
+ } else {
+ $tempheaders = $headers;
+ }
+ $headers = array();
+ $cc = array();
+ $bcc = array();
+
+ // If it's actually got contents
+ if ( !empty( $tempheaders ) ) {
+ // Iterate through the raw headers
+ foreach ( (array) $tempheaders as $header ) {
+ if ( strpos($header, ':') === false ) {
+ if ( false !== stripos( $header, 'boundary=' ) ) {
+ $parts = preg_split('/boundary=/i', trim( $header ) );
+ $boundary = trim( str_replace( array( "'", '"' ), '', $parts[1] ) );
+ }
+ continue;
+ }
+ // Explode them out
+ list( $name, $content ) = explode( ':', trim( $header ), 2 );
+
+ // Cleanup crew
+ $name = trim( $name );
+ $content = trim( $content );
+
+ switch ( strtolower( $name ) ) {
+ // Mainly for legacy -- process a From: header if it's there
+ case 'from':
+ if ( strpos($content, '<' ) !== false ) {
+ // So... making my life hard again?
+ $from_name = substr( $content, 0, strpos( $content, '<' ) - 1 );
+ $from_name = str_replace( '"', '', $from_name );
+ $from_name = trim( $from_name );
+
+ $from_email = substr( $content, strpos( $content, '<' ) + 1 );
+ $from_email = str_replace( '>', '', $from_email );
+ $from_email = trim( $from_email );
+ } else {
+ $from_email = trim( $content );
+ }
+ break;
+ case 'content-type':
+ if ( strpos( $content, ';' ) !== false ) {
+ list( $type, $charset ) = explode( ';', $content );
+ $content_type = trim( $type );
+ if ( false !== stripos( $charset, 'charset=' ) ) {
+ $charset = trim( str_replace( array( 'charset=', '"' ), '', $charset ) );
+ } elseif ( false !== stripos( $charset, 'boundary=' ) ) {
+ $boundary = trim( str_replace( array( 'BOUNDARY=', 'boundary=', '"' ), '', $charset ) );
+ $charset = '';
+ }
+ } else {
+ $content_type = trim( $content );
+ }
+ break;
+ case 'cc':
+ $cc = array_merge( (array) $cc, explode( ',', $content ) );
+ break;
+ case 'bcc':
+ $bcc = array_merge( (array) $bcc, explode( ',', $content ) );
+ break;
+ default:
+ // Add it to our grand headers array
+ $headers[trim( $name )] = trim( $content );
+ break;
+ }
+ }
+ }
+ }
+
+ // Empty out the values that may be set
+ $phpmailer->ClearAddresses();
+ $phpmailer->ClearAllRecipients();
+ $phpmailer->ClearAttachments();
+ $phpmailer->ClearBCCs();
+ $phpmailer->ClearCCs();
+ $phpmailer->ClearCustomHeaders();
+ $phpmailer->ClearReplyTos();
+
+ // From email and name
+ // If we don't have a name from the input headers
+ if ( !isset( $from_name ) )
+ $from_name = 'WordPress';
+
+ /* If we don't have an email from the input headers default to wordpress@$sitename
+ * Some hosts will block outgoing mail from this address if it doesn't exist but
+ * there's no easy alternative. Defaulting to admin_email might appear to be another
+ * option but some hosts may refuse to relay mail from an unknown domain. See
+ * http://trac.wordpress.org/ticket/5007.
+ */
+
+ if ( !isset( $from_email ) ) {
+ // Get the site domain and get rid of www.
+ $sitename = strtolower( $_SERVER['SERVER_NAME'] );
+ if ( substr( $sitename, 0, 4 ) == 'www.' ) {
+ $sitename = substr( $sitename, 4 );
+ }
+
+ $from_email = 'wordpress@' . $sitename;
+ }
+
+ // Plugin authors can override the potentially troublesome default
+ $phpmailer->From = apply_filters( 'wp_mail_from' , $from_email );
+ $phpmailer->FromName = apply_filters( 'wp_mail_from_name', $from_name );
+
+ // Set destination addresses
+ if ( !is_array( $to ) )
+ $to = explode( ',', $to );
+
+ foreach ( (array) $to as $recipient ) {
+ try {
+ // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
+ $recipient_name = '';
+ if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
+ if ( count( $matches ) == 3 ) {
+ $recipient_name = $matches[1];
+ $recipient = $matches[2];
+ }
+ }
+ $phpmailer->AddAddress( $recipient, $recipient_name);
+ } catch ( phpmailerException $e ) {
+ continue;
+ }
+ }
+
+ // Set mail's subject and body
+ $phpmailer->Subject = $subject;
+ $phpmailer->Body = $message;
+
+ // Add any CC and BCC recipients
+ if ( !empty( $cc ) ) {
+ foreach ( (array) $cc as $recipient ) {
+ try {
+ // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
+ $recipient_name = '';
+ if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
+ if ( count( $matches ) == 3 ) {
+ $recipient_name = $matches[1];
+ $recipient = $matches[2];
+ }
+ }
+ $phpmailer->AddCc( $recipient, $recipient_name );
+ } catch ( phpmailerException $e ) {
+ continue;
+ }
+ }
+ }
+
+ if ( !empty( $bcc ) ) {
+ foreach ( (array) $bcc as $recipient) {
+ try {
+ // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>"
+ $recipient_name = '';
+ if( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
+ if ( count( $matches ) == 3 ) {
+ $recipient_name = $matches[1];
+ $recipient = $matches[2];
+ }
+ }
+ $phpmailer->AddBcc( $recipient, $recipient_name );
+ } catch ( phpmailerException $e ) {
+ continue;
+ }
+ }
+ }
+
+ // Set to use PHP's mail()
+ $phpmailer->IsMail();
+
+ // Set Content-Type and charset
+ // If we don't have a content-type from the input headers
+ if ( !isset( $content_type ) )
+ $content_type = 'text/plain';
+
+ $content_type = apply_filters( 'wp_mail_content_type', $content_type );
+
+ $phpmailer->ContentType = $content_type;
+
+ // Set whether it's plaintext, depending on $content_type
+ if ( 'text/html' == $content_type )
+ $phpmailer->IsHTML( true );
+
+ // If we don't have a charset from the input headers
+ if ( !isset( $charset ) )
+ $charset = get_bloginfo( 'charset' );
+
+ // Set the content-type and charset
+ $phpmailer->CharSet = apply_filters( 'wp_mail_charset', $charset );
+
+ // Set custom headers
+ if ( !empty( $headers ) ) {
+ foreach( (array) $headers as $name => $content ) {
+ $phpmailer->AddCustomHeader( sprintf( '%1$s: %2$s', $name, $content ) );
+ }
+
+ if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
+ $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
+ }
+
+ if ( !empty( $attachments ) ) {
+ foreach ( $attachments as $attachment ) {
+ try {
+ $phpmailer->AddAttachment($attachment);
+ } catch ( phpmailerException $e ) {
+ continue;
+ }
+ }
+ }
+
+ do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) );
+
+ // Send!
+ try {
+ return $phpmailer->Send();
+ } catch ( phpmailerException $e ) {
+ return false;
+ }
+}
+endif;
+
+if ( !function_exists('wp_authenticate') ) :
+/**
+ * Checks a user's login information and logs them in if it checks out.
+ *
+ * @since 2.5.0
+ *
+ * @param string $username User's username
+ * @param string $password User's password
+ * @return WP_Error|WP_User WP_User object if login successful, otherwise WP_Error object.
+ */
+function wp_authenticate($username, $password) {
+ $username = sanitize_user($username);
+ $password = trim($password);
+
+ $user = apply_filters('authenticate', null, $username, $password);
+
+ if ( $user == null ) {
+ // TODO what should the error message be? (Or would these even happen?)
+ // Only needed if all authentication handlers fail to return anything.
+ $user = new WP_Error('authentication_failed', __('<strong>ERROR</strong>: Invalid username or incorrect password.'));
+ }
+
+ $ignore_codes = array('empty_username', 'empty_password');
+
+ if (is_wp_error($user) && !in_array($user->get_error_code(), $ignore_codes) ) {
+ do_action('wp_login_failed', $username);
+ }
+
+ return $user;
+}
+endif;
+
+if ( !function_exists('wp_logout') ) :
+/**
+ * Log the current user out.
+ *
+ * @since 2.5.0
+ */
+function wp_logout() {
+ wp_clear_auth_cookie();
+ do_action('wp_logout');
+}
+endif;
+
+if ( !function_exists('wp_validate_auth_cookie') ) :
+/**
+ * Validates authentication cookie.
+ *
+ * The checks include making sure that the authentication cookie is set and
+ * pulling in the contents (if $cookie is not used).
+ *
+ * Makes sure the cookie is not expired. Verifies the hash in cookie is what is
+ * should be and compares the two.
+ *
+ * @since 2.5
+ *
+ * @param string $cookie Optional. If used, will validate contents instead of cookie's
+ * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
+ * @return bool|int False if invalid cookie, User ID if valid.
+ */
+function wp_validate_auth_cookie($cookie = '', $scheme = '') {
+ if ( ! $cookie_elements = wp_parse_auth_cookie($cookie, $scheme) ) {
+ do_action('auth_cookie_malformed', $cookie, $scheme);
+ return false;
+ }
+
+ extract($cookie_elements, EXTR_OVERWRITE);
+
+ $expired = $expiration;
+
+ // Allow a grace period for POST and AJAX requests
+ if ( defined('DOING_AJAX') || 'POST' == $_SERVER['REQUEST_METHOD'] )
+ $expired += HOUR_IN_SECONDS;
+
+ // Quick check to see if an honest cookie has expired
+ if ( $expired < time() ) {
+ do_action('auth_cookie_expired', $cookie_elements);
+ return false;
+ }
+
+ $user = get_user_by('login', $username);
+ if ( ! $user ) {
+ do_action('auth_cookie_bad_username', $cookie_elements);
+ return false;
+ }
+
+ $pass_frag = substr($user->user_pass, 8, 4);
+
+ $key = wp_hash($username . $pass_frag . '|' . $expiration, $scheme);
+ $hash = hash_hmac('md5', $username . '|' . $expiration, $key);
+
+ if ( $hmac != $hash ) {
+ do_action('auth_cookie_bad_hash', $cookie_elements);
+ return false;
+ }
+
+ if ( $expiration < time() ) // AJAX/POST grace period set above
+ $GLOBALS['login_grace_period'] = 1;
+
+ do_action('auth_cookie_valid', $cookie_elements, $user);
+
+ return $user->ID;
+}
+endif;
+
+if ( !function_exists('wp_generate_auth_cookie') ) :
+/**
+ * Generate authentication cookie contents.
+ *
+ * @since 2.5
+ * @uses apply_filters() Calls 'auth_cookie' hook on $cookie contents, User ID
+ * and expiration of cookie.
+ *
+ * @param int $user_id User ID
+ * @param int $expiration Cookie expiration in seconds
+ * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
+ * @return string Authentication cookie contents
+ */
+function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
+ $user = get_userdata($user_id);
+
+ $pass_frag = substr($user->user_pass, 8, 4);
+
+ $key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
+ $hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
+
+ $cookie = $user->user_login . '|' . $expiration . '|' . $hash;
+
+ return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
+}
+endif;
+
+if ( !function_exists('wp_parse_auth_cookie') ) :
+/**
+ * Parse a cookie into its components
+ *
+ * @since 2.7
+ *
+ * @param string $cookie
+ * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
+ * @return array Authentication cookie components
+ */
+function wp_parse_auth_cookie($cookie = '', $scheme = '') {
+ if ( empty($cookie) ) {
+ switch ($scheme){
+ case 'auth':
+ $cookie_name = AUTH_COOKIE;
+ break;
+ case 'secure_auth':
+ $cookie_name = SECURE_AUTH_COOKIE;
+ break;
+ case "logged_in":
+ $cookie_name = LOGGED_IN_COOKIE;
+ break;
+ default:
+ if ( is_ssl() ) {
+ $cookie_name = SECURE_AUTH_COOKIE;
+ $scheme = 'secure_auth';
+ } else {
+ $cookie_name = AUTH_COOKIE;
+ $scheme = 'auth';
+ }
+ }
+
+ if ( empty($_COOKIE[$cookie_name]) )
+ return false;
+ $cookie = $_COOKIE[$cookie_name];
+ }
+
+ $cookie_elements = explode('|', $cookie);
+ if ( count($cookie_elements) != 3 )
+ return false;
+
+ list($username, $expiration, $hmac) = $cookie_elements;
+
+ return compact('username', 'expiration', 'hmac', 'scheme');
+}
+endif;
+
+if ( !function_exists('wp_set_auth_cookie') ) :
+/**
+ * Sets the authentication cookies based User ID.
+ *
+ * The $remember parameter increases the time that the cookie will be kept. The
+ * default the cookie is kept without remembering is two days. When $remember is
+ * set, the cookies will be kept for 14 days or two weeks.
+ *
+ * @since 2.5
+ *
+ * @param int $user_id User ID
+ * @param bool $remember Whether to remember the user
+ */
+function wp_set_auth_cookie($user_id, $remember = false, $secure = '') {
+ if ( $remember ) {
+ $expiration = $expire = time() + apply_filters('auth_cookie_expiration', 14 * DAY_IN_SECONDS, $user_id, $remember);
+ } else {
+ $expiration = time() + apply_filters('auth_cookie_expiration', 2 * DAY_IN_SECONDS, $user_id, $remember);
+ $expire = 0;
+ }
+
+ if ( '' === $secure )
+ $secure = is_ssl();
+
+ $secure = apply_filters('secure_auth_cookie', $secure, $user_id);
+ $secure_logged_in_cookie = apply_filters('secure_logged_in_cookie', false, $user_id, $secure);
+
+ if ( $secure ) {
+ $auth_cookie_name = SECURE_AUTH_COOKIE;
+ $scheme = 'secure_auth';
+ } else {
+ $auth_cookie_name = AUTH_COOKIE;
+ $scheme = 'auth';
+ }
+
+ $auth_cookie = wp_generate_auth_cookie($user_id, $expiration, $scheme);
+ $logged_in_cookie = wp_generate_auth_cookie($user_id, $expiration, 'logged_in');
+
+ do_action('set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme);
+ do_action('set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in');
+
+ setcookie($auth_cookie_name, $auth_cookie, $expire, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
+ setcookie($auth_cookie_name, $auth_cookie, $expire, ADMIN_COOKIE_PATH, COOKIE_DOMAIN, $secure, true);
+ setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, COOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
+ if ( COOKIEPATH != SITECOOKIEPATH )
+ setcookie(LOGGED_IN_COOKIE, $logged_in_cookie, $expire, SITECOOKIEPATH, COOKIE_DOMAIN, $secure_logged_in_cookie, true);
+}
+endif;
+
+if ( !function_exists('wp_clear_auth_cookie') ) :
+/**
+ * Removes all of the cookies associated with authentication.
+ *
+ * @since 2.5
+ */
+function wp_clear_auth_cookie() {
+ do_action('clear_auth_cookie');
+
+ setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
+ setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, ADMIN_COOKIE_PATH, COOKIE_DOMAIN );
+ setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
+ setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, PLUGINS_COOKIE_PATH, COOKIE_DOMAIN );
+ setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ setcookie( LOGGED_IN_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
+
+ // Old cookies
+ setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ setcookie( AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
+ setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ setcookie( SECURE_AUTH_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
+
+ // Even older cookies
+ setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN );
+ setcookie( USER_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
+ setcookie( PASS_COOKIE, ' ', time() - YEAR_IN_SECONDS, SITECOOKIEPATH, COOKIE_DOMAIN );
+}
+endif;
+
+if ( !function_exists('is_user_logged_in') ) :
+/**
+ * Checks if the current visitor is a logged in user.
+ *
+ * @since 2.0.0
+ *
+ * @return bool True if user is logged in, false if not logged in.
+ */
+function is_user_logged_in() {
+ $user = wp_get_current_user();
+
+ if ( ! $user->exists() )
+ return false;
+
+ return true;
+}
+endif;
+
+if ( !function_exists('auth_redirect') ) :
+/**
+ * Checks if a user is logged in, if not it redirects them to the login page.
+ *
+ * @since 1.5
+ */
+function auth_redirect() {
+ // Checks if a user is logged in, if not redirects them to the login page
+
+ $secure = ( is_ssl() || force_ssl_admin() );
+
+ $secure = apply_filters('secure_auth_redirect', $secure);
+
+ // If https is required and request is http, redirect
+ if ( $secure && !is_ssl() && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
+ if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
+ wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
+ exit();
+ } else {
+ wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ exit();
+ }
+ }
+
+ if ( is_user_admin() )
+ $scheme = 'logged_in';
+ else
+ $scheme = apply_filters( 'auth_redirect_scheme', '' );
+
+ if ( $user_id = wp_validate_auth_cookie( '', $scheme) ) {
+ do_action('auth_redirect', $user_id);
+
+ // If the user wants ssl but the session is not ssl, redirect.
+ if ( !$secure && get_user_option('use_ssl', $user_id) && false !== strpos($_SERVER['REQUEST_URI'], 'wp-admin') ) {
+ if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
+ wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
+ exit();
+ } else {
+ wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ exit();
+ }
+ }
+
+ return; // The cookie is good so we're done
+ }
+
+ // The cookie is no good so force login
+ nocache_headers();
+
+ $redirect = ( strpos( $_SERVER['REQUEST_URI'], '/options.php' ) && wp_get_referer() ) ? wp_get_referer() : set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+
+ $login_url = wp_login_url($redirect, true);
+
+ wp_redirect($login_url);
+ exit();
+}
+endif;
+
+if ( !function_exists('check_admin_referer') ) :
+/**
+ * Makes sure that a user was referred from another admin page.
+ *
+ * To avoid security exploits.
+ *
+ * @since 1.2.0
+ * @uses do_action() Calls 'check_admin_referer' on $action.
+ *
+ * @param string $action Action nonce
+ * @param string $query_arg where to look for nonce in $_REQUEST (since 2.5)
+ */
+function check_admin_referer($action = -1, $query_arg = '_wpnonce') {
+ if ( -1 == $action )
+ _doing_it_wrong( __FUNCTION__, __( 'You should specify a nonce action to be verified by using the first parameter.' ), '3.2' );
+
+ $adminurl = strtolower(admin_url());
+ $referer = strtolower(wp_get_referer());
+ $result = isset($_REQUEST[$query_arg]) ? wp_verify_nonce($_REQUEST[$query_arg], $action) : false;
+ if ( !$result && !(-1 == $action && strpos($referer, $adminurl) === 0) ) {
+ wp_nonce_ays($action);
+ die();
+ }
+ do_action('check_admin_referer', $action, $result);
+ return $result;
+}
+endif;
+
+if ( !function_exists('check_ajax_referer') ) :
+/**
+ * Verifies the AJAX request to prevent processing requests external of the blog.
+ *
+ * @since 2.0.3
+ *
+ * @param string $action Action nonce
+ * @param string $query_arg where to look for nonce in $_REQUEST (since 2.5)
+ */
+function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
+ if ( $query_arg )
+ $nonce = $_REQUEST[$query_arg];
+ else
+ $nonce = isset($_REQUEST['_ajax_nonce']) ? $_REQUEST['_ajax_nonce'] : $_REQUEST['_wpnonce'];
+
+ $result = wp_verify_nonce( $nonce, $action );
+
+ if ( $die && false == $result ) {
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX )
+ wp_die( -1 );
+ else
+ die( '-1' );
+ }
+
+ do_action('check_ajax_referer', $action, $result);
+
+ return $result;
+}
+endif;
+
+if ( !function_exists('wp_redirect') ) :
+/**
+ * Redirects to another page.
+ *
+ * @since 1.5.1
+ * @uses apply_filters() Calls 'wp_redirect' hook on $location and $status.
+ *
+ * @param string $location The path to redirect to
+ * @param int $status Status code to use
+ * @return bool False if $location is not provided, true otherwise.
+ */
+function wp_redirect($location, $status = 302) {
+ global $is_IIS;
+
+ $location = apply_filters('wp_redirect', $location, $status);
+ $status = apply_filters('wp_redirect_status', $status, $location);
+
+ if ( !$location ) // allows the wp_redirect filter to cancel a redirect
+ return false;
+
+ $location = wp_sanitize_redirect($location);
+
+ if ( !$is_IIS && php_sapi_name() != 'cgi-fcgi' )
+ status_header($status); // This causes problems on IIS and some FastCGI setups
+
+ header("Location: $location", true, $status);
+
+ return true;
+}
+endif;
+
+if ( !function_exists('wp_sanitize_redirect') ) :
+/**
+ * Sanitizes a URL for use in a redirect.
+ *
+ * @since 2.3
+ *
+ * @return string redirect-sanitized URL
+ **/
+function wp_sanitize_redirect($location) {
+ $location = preg_replace('|[^a-z0-9-~+_.?#=&;,/:%!]|i', '', $location);
+ $location = wp_kses_no_null($location);
+
+ // remove %0d and %0a from location
+ $strip = array('%0d', '%0a', '%0D', '%0A');
+ $location = _deep_replace($strip, $location);
+ return $location;
+}
+endif;
+
+if ( !function_exists('wp_safe_redirect') ) :
+/**
+ * Performs a safe (local) redirect, using wp_redirect().
+ *
+ * Checks whether the $location is using an allowed host, if it has an absolute
+ * path. A plugin can therefore set or remove allowed host(s) to or from the
+ * list.
+ *
+ * If the host is not allowed, then the redirect is to wp-admin on the siteurl
+ * instead. This prevents malicious redirects which redirect to another host,
+ * but only used in a few places.
+ *
+ * @since 2.3
+ * @uses wp_validate_redirect() To validate the redirect is to an allowed host.
+ *
+ * @return void Does not return anything
+ **/
+function wp_safe_redirect($location, $status = 302) {
+
+ // Need to look at the URL the way it will end up in wp_redirect()
+ $location = wp_sanitize_redirect($location);
+
+ $location = wp_validate_redirect($location, admin_url());
+
+ wp_redirect($location, $status);
+}
+endif;
+
+if ( !function_exists('wp_validate_redirect') ) :
+/**
+ * Validates a URL for use in a redirect.
+ *
+ * Checks whether the $location is using an allowed host, if it has an absolute
+ * path. A plugin can therefore set or remove allowed host(s) to or from the
+ * list.
+ *
+ * If the host is not allowed, then the redirect is to $default supplied
+ *
+ * @since 2.8.1
+ * @uses apply_filters() Calls 'allowed_redirect_hosts' on an array containing
+ * WordPress host string and $location host string.
+ *
+ * @param string $location The redirect to validate
+ * @param string $default The value to return if $location is not allowed
+ * @return string redirect-sanitized URL
+ **/
+function wp_validate_redirect($location, $default = '') {
+ // browsers will assume 'http' is your protocol, and will obey a redirect to a URL starting with '//'
+ if ( substr($location, 0, 2) == '//' )
+ $location = 'http:' . $location;
+
+ // In php 5 parse_url may fail if the URL query part contains http://, bug #38143
+ $test = ( $cut = strpos($location, '?') ) ? substr( $location, 0, $cut ) : $location;
+
+ $lp = parse_url($test);
+
+ // Give up if malformed URL
+ if ( false === $lp )
+ return $default;
+
+ // Allow only http and https schemes. No data:, etc.
+ if ( isset($lp['scheme']) && !('http' == $lp['scheme'] || 'https' == $lp['scheme']) )
+ return $default;
+
+ // Reject if scheme is set but host is not. This catches urls like https:host.com for which parse_url does not set the host field.
+ if ( isset($lp['scheme']) && !isset($lp['host']) )
+ return $default;
+
+ $wpp = parse_url(home_url());
+
+ $allowed_hosts = (array) apply_filters('allowed_redirect_hosts', array($wpp['host']), isset($lp['host']) ? $lp['host'] : '');
+
+ if ( isset($lp['host']) && ( !in_array($lp['host'], $allowed_hosts) && $lp['host'] != strtolower($wpp['host'])) )
+ $location = $default;
+
+ return $location;
+}
+endif;
+
+if ( ! function_exists('wp_notify_postauthor') ) :
+/**
+ * Notify an author of a comment/trackback/pingback to one of their posts.
+ *
+ * @since 1.0.0
+ *
+ * @param int $comment_id Comment ID
+ * @param string $comment_type Optional. The comment type either 'comment' (default), 'trackback', or 'pingback'
+ * @return bool False if user email does not exist. True on completion.
+ */
+function wp_notify_postauthor( $comment_id, $comment_type = '' ) {
+ $comment = get_comment( $comment_id );
+ $post = get_post( $comment->comment_post_ID );
+ $author = get_userdata( $post->post_author );
+
+ // The comment was left by the author
+ if ( $comment->user_id == $post->post_author )
+ return false;
+
+ // The author moderated a comment on his own post
+ if ( $post->post_author == get_current_user_id() )
+ return false;
+
+ // The post author is no longer a member of the blog
+ if ( ! user_can( $post->post_author, 'read_post', $post->ID ) )
+ return false;
+
+ // If there's no email to send the comment to
+ if ( '' == $author->user_email )
+ return false;
+
+ $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
+
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
+ // we want to reverse this for the plain text arena of emails.
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
+
+ if ( empty( $comment_type ) ) $comment_type = 'comment';
+
+ if ('comment' == $comment_type) {
+ $notify_message = sprintf( __( 'New comment on your post "%s"' ), $post->post_title ) . "\r\n";
+ /* translators: 1: comment author, 2: author IP, 3: author domain */
+ $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= sprintf( __('Whois : http://whois.arin.net/rest/ip/%s'), $comment->comment_author_IP ) . "\r\n";
+ $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ $notify_message .= __('You can see all comments on this post here: ') . "\r\n";
+ /* translators: 1: blog name, 2: post title */
+ $subject = sprintf( __('[%1$s] Comment: "%2$s"'), $blogname, $post->post_title );
+ } elseif ('trackback' == $comment_type) {
+ $notify_message = sprintf( __( 'New trackback on your post "%s"' ), $post->post_title ) . "\r\n";
+ /* translators: 1: website name, 2: author IP, 3: author domain */
+ $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ $notify_message .= __('You can see all trackbacks on this post here: ') . "\r\n";
+ /* translators: 1: blog name, 2: post title */
+ $subject = sprintf( __('[%1$s] Trackback: "%2$s"'), $blogname, $post->post_title );
+ } elseif ('pingback' == $comment_type) {
+ $notify_message = sprintf( __( 'New pingback on your post "%s"' ), $post->post_title ) . "\r\n";
+ /* translators: 1: comment author, 2: author IP, 3: author domain */
+ $notify_message .= sprintf( __('Website: %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Excerpt: ') . "\r\n" . sprintf('[...] %s [...]', $comment->comment_content ) . "\r\n\r\n";
+ $notify_message .= __('You can see all pingbacks on this post here: ') . "\r\n";
+ /* translators: 1: blog name, 2: post title */
+ $subject = sprintf( __('[%1$s] Pingback: "%2$s"'), $blogname, $post->post_title );
+ }
+ $notify_message .= get_permalink($comment->comment_post_ID) . "#comments\r\n\r\n";
+ $notify_message .= sprintf( __('Permalink: %s'), get_permalink( $comment->comment_post_ID ) . '#comment-' . $comment_id ) . "\r\n";
+
+ if ( user_can( $post->post_author, 'edit_comment', $comment_id ) ) {
+ if ( EMPTY_TRASH_DAYS )
+ $notify_message .= sprintf( __('Trash it: %s'), admin_url("comment.php?action=trash&c=$comment_id") ) . "\r\n";
+ else
+ $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=delete&c=$comment_id") ) . "\r\n";
+ $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=spam&c=$comment_id") ) . "\r\n";
+ }
+
+ $wp_email = 'wordpress@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME']));
+
+ if ( '' == $comment->comment_author ) {
+ $from = "From: \"$blogname\" <$wp_email>";
+ if ( '' != $comment->comment_author_email )
+ $reply_to = "Reply-To: $comment->comment_author_email";
+ } else {
+ $from = "From: \"$comment->comment_author\" <$wp_email>";
+ if ( '' != $comment->comment_author_email )
+ $reply_to = "Reply-To: \"$comment->comment_author_email\" <$comment->comment_author_email>";
+ }
+
+ $message_headers = "$from\n"
+ . "Content-Type: text/plain; charset=\"" . get_option('blog_charset') . "\"\n";
+
+ if ( isset($reply_to) )
+ $message_headers .= $reply_to . "\n";
+
+ $notify_message = apply_filters('comment_notification_text', $notify_message, $comment_id);
+ $subject = apply_filters('comment_notification_subject', $subject, $comment_id);
+ $message_headers = apply_filters('comment_notification_headers', $message_headers, $comment_id);
+
+ @wp_mail( $author->user_email, $subject, $notify_message, $message_headers );
+
+ return true;
+}
+endif;
+
+if ( !function_exists('wp_notify_moderator') ) :
+/**
+ * Notifies the moderator of the blog about a new comment that is awaiting approval.
+ *
+ * @since 1.0
+ * @uses $wpdb
+ *
+ * @param int $comment_id Comment ID
+ * @return bool Always returns true
+ */
+function wp_notify_moderator($comment_id) {
+ global $wpdb;
+
+ if ( 0 == get_option( 'moderation_notify' ) )
+ return true;
+
+ $comment = get_comment($comment_id);
+ $post = get_post($comment->comment_post_ID);
+ $user = get_userdata( $post->post_author );
+ // Send to the administration and to the post author if the author can modify the comment.
+ $email_to = array( get_option('admin_email') );
+ if ( user_can($user->ID, 'edit_comment', $comment_id) && !empty($user->user_email) && ( get_option('admin_email') != $user->user_email) )
+ $email_to[] = $user->user_email;
+
+ $comment_author_domain = @gethostbyaddr($comment->comment_author_IP);
+ $comments_waiting = $wpdb->get_var("SELECT count(comment_ID) FROM $wpdb->comments WHERE comment_approved = '0'");
+
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
+ // we want to reverse this for the plain text arena of emails.
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
+
+ switch ($comment->comment_type)
+ {
+ case 'trackback':
+ $notify_message = sprintf( __('A new trackback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
+ $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Trackback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ break;
+ case 'pingback':
+ $notify_message = sprintf( __('A new pingback on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
+ $notify_message .= sprintf( __('Website : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= __('Pingback excerpt: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ break;
+ default: //Comments
+ $notify_message = sprintf( __('A new comment on the post "%s" is waiting for your approval'), $post->post_title ) . "\r\n";
+ $notify_message .= get_permalink($comment->comment_post_ID) . "\r\n\r\n";
+ $notify_message .= sprintf( __('Author : %1$s (IP: %2$s , %3$s)'), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n";
+ $notify_message .= sprintf( __('E-mail : %s'), $comment->comment_author_email ) . "\r\n";
+ $notify_message .= sprintf( __('URL : %s'), $comment->comment_author_url ) . "\r\n";
+ $notify_message .= sprintf( __('Whois : http://whois.arin.net/rest/ip/%s'), $comment->comment_author_IP ) . "\r\n";
+ $notify_message .= __('Comment: ') . "\r\n" . $comment->comment_content . "\r\n\r\n";
+ break;
+ }
+
+ $notify_message .= sprintf( __('Approve it: %s'), admin_url("comment.php?action=approve&c=$comment_id") ) . "\r\n";
+ if ( EMPTY_TRASH_DAYS )
+ $notify_message .= sprintf( __('Trash it: %s'), admin_url("comment.php?action=trash&c=$comment_id") ) . "\r\n";
+ else
+ $notify_message .= sprintf( __('Delete it: %s'), admin_url("comment.php?action=delete&c=$comment_id") ) . "\r\n";
+ $notify_message .= sprintf( __('Spam it: %s'), admin_url("comment.php?action=spam&c=$comment_id") ) . "\r\n";
+
+ $notify_message .= sprintf( _n('Currently %s comment is waiting for approval. Please visit the moderation panel:',
+ 'Currently %s comments are waiting for approval. Please visit the moderation panel:', $comments_waiting), number_format_i18n($comments_waiting) ) . "\r\n";
+ $notify_message .= admin_url("edit-comments.php?comment_status=moderated") . "\r\n";
+
+ $subject = sprintf( __('[%1$s] Please moderate: "%2$s"'), $blogname, $post->post_title );
+ $message_headers = '';
+
+ $notify_message = apply_filters('comment_moderation_text', $notify_message, $comment_id);
+ $subject = apply_filters('comment_moderation_subject', $subject, $comment_id);
+ $message_headers = apply_filters('comment_moderation_headers', $message_headers);
+
+ foreach ( $email_to as $email )
+ @wp_mail($email, $subject, $notify_message, $message_headers);
+
+ return true;
+}
+endif;
+
+if ( !function_exists('wp_password_change_notification') ) :
+/**
+ * Notify the blog admin of a user changing password, normally via email.
+ *
+ * @since 2.7
+ *
+ * @param object $user User Object
+ */
+function wp_password_change_notification(&$user) {
+ // send a copy of password change notification to the admin
+ // but check to see if it's the admin whose password we're changing, and skip this
+ if ( $user->user_email != get_option('admin_email') ) {
+ $message = sprintf(__('Password Lost and Changed for user: %s'), $user->user_login) . "\r\n";
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
+ // we want to reverse this for the plain text arena of emails.
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
+ wp_mail(get_option('admin_email'), sprintf(__('[%s] Password Lost/Changed'), $blogname), $message);
+ }
+}
+endif;
+
+if ( !function_exists('wp_new_user_notification') ) :
+/**
+ * Notify the blog admin of a new user, normally via email.
+ *
+ * @since 2.0
+ *
+ * @param int $user_id User ID
+ * @param string $plaintext_pass Optional. The user's plaintext password
+ */
+function wp_new_user_notification($user_id, $plaintext_pass = '') {
+ $user = get_userdata( $user_id );
+
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
+ // we want to reverse this for the plain text arena of emails.
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
+
+ $message = sprintf(__('New user registration on your site %s:'), $blogname) . "\r\n\r\n";
+ $message .= sprintf(__('Username: %s'), $user->user_login) . "\r\n\r\n";
+ $message .= sprintf(__('E-mail: %s'), $user->user_email) . "\r\n";
+
+ @wp_mail(get_option('admin_email'), sprintf(__('[%s] New User Registration'), $blogname), $message);
+
+ if ( empty($plaintext_pass) )
+ return;
+
+ $message = sprintf(__('Username: %s'), $user->user_login) . "\r\n";
+ $message .= sprintf(__('Password: %s'), $plaintext_pass) . "\r\n";
+ $message .= wp_login_url() . "\r\n";
+
+ wp_mail($user->user_email, sprintf(__('[%s] Your username and password'), $blogname), $message);
+
+}
+endif;
+
+if ( !function_exists('wp_nonce_tick') ) :
+/**
+ * Get the time-dependent variable for nonce creation.
+ *
+ * A nonce has a lifespan of two ticks. Nonces in their second tick may be
+ * updated, e.g. by autosave.
+ *
+ * @since 2.5
+ *
+ * @return int
+ */
+function wp_nonce_tick() {
+ $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS );
+
+ return ceil(time() / ( $nonce_life / 2 ));
+}
+endif;
+
+if ( !function_exists('wp_verify_nonce') ) :
+/**
+ * Verify that correct nonce was used with time limit.
+ *
+ * The user is given an amount of time to use the token, so therefore, since the
+ * UID and $action remain the same, the independent variable is the time.
+ *
+ * @since 2.0.3
+ *
+ * @param string $nonce Nonce that was used in the form to verify
+ * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
+ * @return bool Whether the nonce check passed or failed.
+ */
+function wp_verify_nonce($nonce, $action = -1) {
+ $user = wp_get_current_user();
+ $uid = (int) $user->ID;
+ if ( ! $uid )
+ $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
+
+ $i = wp_nonce_tick();
+
+ // Nonce generated 0-12 hours ago
+ if ( substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10) === $nonce )
+ return 1;
+ // Nonce generated 12-24 hours ago
+ if ( substr(wp_hash(($i - 1) . $action . $uid, 'nonce'), -12, 10) === $nonce )
+ return 2;
+ // Invalid nonce
+ return false;
+}
+endif;
+
+if ( !function_exists('wp_create_nonce') ) :
+/**
+ * Creates a random, one time use token.
+ *
+ * @since 2.0.3
+ *
+ * @param string|int $action Scalar value to add context to the nonce.
+ * @return string The one use form token
+ */
+function wp_create_nonce($action = -1) {
+ $user = wp_get_current_user();
+ $uid = (int) $user->ID;
+ if ( ! $uid )
+ $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
+
+ $i = wp_nonce_tick();
+
+ return substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10);
+}
+endif;
+
+if ( !function_exists('wp_salt') ) :
+/**
+ * Get salt to add to hashes.
+ *
+ * Salts are created using secret keys. Secret keys are located in two places:
+ * in the database and in the wp-config.php file. The secret key in the database
+ * is randomly generated and will be appended to the secret keys in wp-config.php.
+ *
+ * The secret keys in wp-config.php should be updated to strong, random keys to maximize
+ * security. Below is an example of how the secret key constants are defined.
+ * Do not paste this example directly into wp-config.php. Instead, have a
+ * {@link https://api.wordpress.org/secret-key/1.1/salt/ secret key created} just
+ * for you.
+ *
+ * <code>
+ * define('AUTH_KEY', ' Xakm<o xQy rw4EMsLKM-?!T+,PFF})H4lzcW57AF0U@N@< >M%G4Yt>f`z]MON');
+ * define('SECURE_AUTH_KEY', 'LzJ}op]mr|6+![P}Ak:uNdJCJZd>(Hx.-Mh#Tz)pCIU#uGEnfFz|f ;;eU%/U^O~');
+ * define('LOGGED_IN_KEY', '|i|Ux`9<p-h$aFf(qnT:sDO:D1P^wZ$$/Ra@miTJi9G;ddp_<q}6H1)o|a +&JCM');
+ * define('NONCE_KEY', '%:R{[P|,s.KuMltH5}cI;/k<Gx~j!f0I)m_sIyu+&NJZ)-iO>z7X>QYR0Z_XnZ@|');
+ * define('AUTH_SALT', 'eZyT)-Naw]F8CwA*VaW#q*|.)g@o}||wf~@C-YSt}(dh_r6EbI#A,y|nU2{B#JBW');
+ * define('SECURE_AUTH_SALT', '!=oLUTXh,QW=H `}`L|9/^4-3 STz},T(w}W<I`.JjPi)<Bmf1v,HpGe}T1:Xt7n');
+ * define('LOGGED_IN_SALT', '+XSqHc;@Q*K_b|Z?NC[3H!!EONbh.n<+=uKR:>*c(u`g~EJBf#8u#R{mUEZrozmm');
+ * define('NONCE_SALT', 'h`GXHhD>SLWVfg1(1(N{;.V!MoE(SfbA_ksP@&`+AycHcAV$+?@3q+rxV{%^VyKT');
+ * </code>
+ *
+ * Salting passwords helps against tools which has stored hashed values of
+ * common dictionary strings. The added values makes it harder to crack.
+ *
+ * @since 2.5
+ *
+ * @link https://api.wordpress.org/secret-key/1.1/salt/ Create secrets for wp-config.php
+ *
+ * @param string $scheme Authentication scheme (auth, secure_auth, logged_in, nonce)
+ * @return string Salt value
+ */
+function wp_salt( $scheme = 'auth' ) {
+ static $cached_salts = array();
+ if ( isset( $cached_salts[ $scheme ] ) )
+ return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
+
+ static $duplicated_keys;
+ if ( null === $duplicated_keys ) {
+ $duplicated_keys = array( 'put your unique phrase here' => true );
+ foreach ( array( 'AUTH', 'SECURE_AUTH', 'LOGGED_IN', 'NONCE', 'SECRET' ) as $first ) {
+ foreach ( array( 'KEY', 'SALT' ) as $second ) {
+ if ( ! defined( "{$first}_{$second}" ) )
+ continue;
+ $value = constant( "{$first}_{$second}" );
+ $duplicated_keys[ $value ] = isset( $duplicated_keys[ $value ] );
+ }
+ }
+ }
+
+ $key = $salt = '';
+ if ( defined( 'SECRET_KEY' ) && SECRET_KEY && empty( $duplicated_keys[ SECRET_KEY ] ) )
+ $key = SECRET_KEY;
+ if ( 'auth' == $scheme && defined( 'SECRET_SALT' ) && SECRET_SALT && empty( $duplicated_keys[ SECRET_SALT ] ) )
+ $salt = SECRET_SALT;
+
+ if ( in_array( $scheme, array( 'auth', 'secure_auth', 'logged_in', 'nonce' ) ) ) {
+ foreach ( array( 'key', 'salt' ) as $type ) {
+ $const = strtoupper( "{$scheme}_{$type}" );
+ if ( defined( $const ) && constant( $const ) && empty( $duplicated_keys[ constant( $const ) ] ) ) {
+ $$type = constant( $const );
+ } elseif ( ! $$type ) {
+ $$type = get_site_option( "{$scheme}_{$type}" );
+ if ( ! $$type ) {
+ $$type = wp_generate_password( 64, true, true );
+ update_site_option( "{$scheme}_{$type}", $$type );
+ }
+ }
+ }
+ } else {
+ if ( ! $key ) {
+ $key = get_site_option( 'secret_key' );
+ if ( ! $key ) {
+ $key = wp_generate_password( 64, true, true );
+ update_site_option( 'secret_key', $key );
+ }
+ }
+ $salt = hash_hmac( 'md5', $scheme, $key );
+ }
+
+ $cached_salts[ $scheme ] = $key . $salt;
+ return apply_filters( 'salt', $cached_salts[ $scheme ], $scheme );
+}
+endif;
+
+if ( !function_exists('wp_hash') ) :
+/**
+ * Get hash of given string.
+ *
+ * @since 2.0.3
+ * @uses wp_salt() Get WordPress salt
+ *
+ * @param string $data Plain text to hash
+ * @return string Hash of $data
+ */
+function wp_hash($data, $scheme = 'auth') {
+ $salt = wp_salt($scheme);
+
+ return hash_hmac('md5', $data, $salt);
+}
+endif;
+
+if ( !function_exists('wp_hash_password') ) :
+/**
+ * Create a hash (encrypt) of a plain text password.
+ *
+ * For integration with other applications, this function can be overwritten to
+ * instead use the other package password checking algorithm.
+ *
+ * @since 2.5
+ * @global object $wp_hasher PHPass object
+ * @uses PasswordHash::HashPassword
+ *
+ * @param string $password Plain text user password to hash
+ * @return string The hash string of the password
+ */
+function wp_hash_password($password) {
+ global $wp_hasher;
+
+ if ( empty($wp_hasher) ) {
+ require_once( ABSPATH . 'wp-includes/class-phpass.php');
+ // By default, use the portable hash from phpass
+ $wp_hasher = new PasswordHash(8, true);
+ }
+
+ return $wp_hasher->HashPassword($password);
+}
+endif;
+
+if ( !function_exists('wp_check_password') ) :
+/**
+ * Checks the plaintext password against the encrypted Password.
+ *
+ * Maintains compatibility between old version and the new cookie authentication
+ * protocol using PHPass library. The $hash parameter is the encrypted password
+ * and the function compares the plain text password when encrypted similarly
+ * against the already encrypted password to see if they match.
+ *
+ * For integration with other applications, this function can be overwritten to
+ * instead use the other package password checking algorithm.
+ *
+ * @since 2.5
+ * @global object $wp_hasher PHPass object used for checking the password
+ * against the $hash + $password
+ * @uses PasswordHash::CheckPassword
+ *
+ * @param string $password Plaintext user's password
+ * @param string $hash Hash of the user's password to check against.
+ * @return bool False, if the $password does not match the hashed password
+ */
+function wp_check_password($password, $hash, $user_id = '') {
+ global $wp_hasher;
+
+ // If the hash is still md5...
+ if ( strlen($hash) <= 32 ) {
+ $check = ( $hash == md5($password) );
+ if ( $check && $user_id ) {
+ // Rehash using new hash.
+ wp_set_password($password, $user_id);
+ $hash = wp_hash_password($password);
+ }
+
+ return apply_filters('check_password', $check, $password, $hash, $user_id);
+ }
+
+ // If the stored hash is longer than an MD5, presume the
+ // new style phpass portable hash.
+ if ( empty($wp_hasher) ) {
+ require_once( ABSPATH . 'wp-includes/class-phpass.php');
+ // By default, use the portable hash from phpass
+ $wp_hasher = new PasswordHash(8, true);
+ }
+
+ $check = $wp_hasher->CheckPassword($password, $hash);
+
+ return apply_filters('check_password', $check, $password, $hash, $user_id);
+}
+endif;
+
+if ( !function_exists('wp_generate_password') ) :
+/**
+ * Generates a random password drawn from the defined set of characters.
+ *
+ * @since 2.5
+ *
+ * @param int $length The length of password to generate
+ * @param bool $special_chars Whether to include standard special characters. Default true.
+ * @param bool $extra_special_chars Whether to include other special characters. Used when
+ * generating secret keys and salts. Default false.
+ * @return string The random password
+ **/
+function wp_generate_password( $length = 12, $special_chars = true, $extra_special_chars = false ) {
+ $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ if ( $special_chars )
+ $chars .= '!@#$%^&*()';
+ if ( $extra_special_chars )
+ $chars .= '-_ []{}<>~`+=,.;:/?|';
+
+ $password = '';
+ for ( $i = 0; $i < $length; $i++ ) {
+ $password .= substr($chars, wp_rand(0, strlen($chars) - 1), 1);
+ }
+
+ // random_password filter was previously in random_password function which was deprecated
+ return apply_filters('random_password', $password);
+}
+endif;
+
+if ( !function_exists('wp_rand') ) :
+/**
+ * Generates a random number
+ *
+ * @since 2.6.2
+ *
+ * @param int $min Lower limit for the generated number
+ * @param int $max Upper limit for the generated number
+ * @return int A random number between min and max
+ */
+function wp_rand( $min = 0, $max = 0 ) {
+ global $rnd_value;
+
+ // Reset $rnd_value after 14 uses
+ // 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value
+ if ( strlen($rnd_value) < 8 ) {
+ if ( defined( 'WP_SETUP_CONFIG' ) )
+ static $seed = '';
+ else
+ $seed = get_transient('random_seed');
+ $rnd_value = md5( uniqid(microtime() . mt_rand(), true ) . $seed );
+ $rnd_value .= sha1($rnd_value);
+ $rnd_value .= sha1($rnd_value . $seed);
+ $seed = md5($seed . $rnd_value);
+ if ( ! defined( 'WP_SETUP_CONFIG' ) )
+ set_transient('random_seed', $seed);
+ }
+
+ // Take the first 8 digits for our value
+ $value = substr($rnd_value, 0, 8);
+
+ // Strip the first eight, leaving the remainder for the next call to wp_rand().
+ $rnd_value = substr($rnd_value, 8);
+
+ $value = abs(hexdec($value));
+
+ // Some misconfigured 32bit environments (Entropy PHP, for example) truncate integers larger than PHP_INT_MAX to PHP_INT_MAX rather than overflowing them to floats.
+ $max_random_number = 3000000000 === 2147483647 ? (float) "4294967295" : 4294967295; // 4294967295 = 0xffffffff
+
+ // Reduce the value to be within the min - max range
+ if ( $max != 0 )
+ $value = $min + ( $max - $min + 1 ) * $value / ( $max_random_number + 1 );
+
+ return abs(intval($value));
+}
+endif;
+
+if ( !function_exists('wp_set_password') ) :
+/**
+ * Updates the user's password with a new encrypted one.
+ *
+ * For integration with other applications, this function can be overwritten to
+ * instead use the other package password checking algorithm.
+ *
+ * @since 2.5
+ * @uses $wpdb WordPress database object for queries
+ * @uses wp_hash_password() Used to encrypt the user's password before passing to the database
+ *
+ * @param string $password The plaintext new user password
+ * @param int $user_id User ID
+ */
+function wp_set_password( $password, $user_id ) {
+ global $wpdb;
+
+ $hash = wp_hash_password( trim( $password ) );
+ $wpdb->update($wpdb->users, array('user_pass' => $hash, 'user_activation_key' => ''), array('ID' => $user_id) );
+
+ wp_cache_delete($user_id, 'users');
+}
+endif;
+
+if ( !function_exists( 'get_avatar' ) ) :
+/**
+ * Retrieve the avatar for a user who provided a user ID or email address.
+ *
+ * @since 2.5
+ * @param int|string|object $id_or_email A user ID, email address, or comment object
+ * @param int $size Size of the avatar image
+ * @param string $default URL to a default image to use if no avatar is available
+ * @param string $alt Alternative text to use in image tag. Defaults to blank
+ * @return string <img> tag for the user's avatar
+*/
+function get_avatar( $id_or_email, $size = '96', $default = '', $alt = false ) {
+ if ( ! get_option('show_avatars') )
+ return false;
+
+ if ( false === $alt)
+ $safe_alt = '';
+ else
+ $safe_alt = esc_attr( $alt );
+
+ if ( !is_numeric($size) )
+ $size = '96';
+
+ $email = '';
+ if ( is_numeric($id_or_email) ) {
+ $id = (int) $id_or_email;
+ $user = get_userdata($id);
+ if ( $user )
+ $email = $user->user_email;
+ } elseif ( is_object($id_or_email) ) {
+ // No avatar for pingbacks or trackbacks
+ $allowed_comment_types = apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
+ if ( ! empty( $id_or_email->comment_type ) && ! in_array( $id_or_email->comment_type, (array) $allowed_comment_types ) )
+ return false;
+
+ if ( !empty($id_or_email->user_id) ) {
+ $id = (int) $id_or_email->user_id;
+ $user = get_userdata($id);
+ if ( $user)
+ $email = $user->user_email;
+ } elseif ( !empty($id_or_email->comment_author_email) ) {
+ $email = $id_or_email->comment_author_email;
+ }
+ } else {
+ $email = $id_or_email;
+ }
+
+ if ( empty($default) ) {
+ $avatar_default = get_option('avatar_default');
+ if ( empty($avatar_default) )
+ $default = 'mystery';
+ else
+ $default = $avatar_default;
+ }
+
+ if ( !empty($email) )
+ $email_hash = md5( strtolower( trim( $email ) ) );
+
+ if ( is_ssl() ) {
+ $host = 'https://secure.gravatar.com';
+ } else {
+ if ( !empty($email) )
+ $host = sprintf( "http://%d.gravatar.com", ( hexdec( $email_hash[0] ) % 2 ) );
+ else
+ $host = 'http://0.gravatar.com';
+ }
+
+ if ( 'mystery' == $default )
+ $default = "$host/avatar/ad516503a11cd5ca435acc9bb6523536?s={$size}"; // ad516503a11cd5ca435acc9bb6523536 == md5('unknown@gravatar.com')
+ elseif ( 'blank' == $default )
+ $default = $email ? 'blank' : includes_url( 'images/blank.gif' );
+ elseif ( !empty($email) && 'gravatar_default' == $default )
+ $default = '';
+ elseif ( 'gravatar_default' == $default )
+ $default = "$host/avatar/?s={$size}";
+ elseif ( empty($email) )
+ $default = "$host/avatar/?d=$default&amp;s={$size}";
+ elseif ( strpos($default, 'http://') === 0 )
+ $default = add_query_arg( 's', $size, $default );
+
+ if ( !empty($email) ) {
+ $out = "$host/avatar/";
+ $out .= $email_hash;
+ $out .= '?s='.$size;
+ $out .= '&amp;d=' . urlencode( $default );
+
+ $rating = get_option('avatar_rating');
+ if ( !empty( $rating ) )
+ $out .= "&amp;r={$rating}";
+
+ $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo' height='{$size}' width='{$size}' />";
+ } else {
+ $avatar = "<img alt='{$safe_alt}' src='{$default}' class='avatar avatar-{$size} photo avatar-default' height='{$size}' width='{$size}' />";
+ }
+
+ return apply_filters('get_avatar', $avatar, $id_or_email, $size, $default, $alt);
+}
+endif;
+
+if ( !function_exists( 'wp_text_diff' ) ) :
+/**
+ * Displays a human readable HTML representation of the difference between two strings.
+ *
+ * The Diff is available for getting the changes between versions. The output is
+ * HTML, so the primary use is for displaying the changes. If the two strings
+ * are equivalent, then an empty string will be returned.
+ *
+ * The arguments supported and can be changed are listed below.
+ *
+ * 'title' : Default is an empty string. Titles the diff in a manner compatible
+ * with the output.
+ * 'title_left' : Default is an empty string. Change the HTML to the left of the
+ * title.
+ * 'title_right' : Default is an empty string. Change the HTML to the right of
+ * the title.
+ *
+ * @since 2.6
+ * @see wp_parse_args() Used to change defaults to user defined settings.
+ * @uses Text_Diff
+ * @uses WP_Text_Diff_Renderer_Table
+ *
+ * @param string $left_string "old" (left) version of string
+ * @param string $right_string "new" (right) version of string
+ * @param string|array $args Optional. Change 'title', 'title_left', and 'title_right' defaults.
+ * @return string Empty string if strings are equivalent or HTML with differences.
+ */
+function wp_text_diff( $left_string, $right_string, $args = null ) {
+ $defaults = array( 'title' => '', 'title_left' => '', 'title_right' => '' );
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( !class_exists( 'WP_Text_Diff_Renderer_Table' ) )
+ require( ABSPATH . WPINC . '/wp-diff.php' );
+
+ $left_string = normalize_whitespace($left_string);
+ $right_string = normalize_whitespace($right_string);
+
+ $left_lines = explode("\n", $left_string);
+ $right_lines = explode("\n", $right_string);
+ $text_diff = new Text_Diff($left_lines, $right_lines);
+ $renderer = new WP_Text_Diff_Renderer_Table( $args );
+ $diff = $renderer->render($text_diff);
+
+ if ( !$diff )
+ return '';
+
+ $r = "<table class='diff'>\n";
+
+ if ( ! empty( $args[ 'show_split_view' ] ) ) {
+ $r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
+ } else {
+ $r .= "<col class='content' />";
+ }
+
+ if ( $args['title'] || $args['title_left'] || $args['title_right'] )
+ $r .= "<thead>";
+ if ( $args['title'] )
+ $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
+ if ( $args['title_left'] || $args['title_right'] ) {
+ $r .= "<tr class='diff-sub-title'>\n";
+ $r .= "\t<td></td><th>$args[title_left]</th>\n";
+ $r .= "\t<td></td><th>$args[title_right]</th>\n";
+ $r .= "</tr>\n";
+ }
+ if ( $args['title'] || $args['title_left'] || $args['title_right'] )
+ $r .= "</thead>\n";
+
+ $r .= "<tbody>\n$diff\n</tbody>\n";
+ $r .= "</table>";
+
+ return $r;
+}
+endif;
+
diff --git a/src/wp-includes/plugin.php b/src/wp-includes/plugin.php
new file mode 100644
index 0000000000..c2aebf28a9
--- /dev/null
+++ b/src/wp-includes/plugin.php
@@ -0,0 +1,790 @@
+<?php
+/**
+ * The plugin API is located in this file, which allows for creating actions
+ * and filters and hooking functions, and methods. The functions or methods will
+ * then be run when the action or filter is called.
+ *
+ * The API callback examples reference functions, but can be methods of classes.
+ * To hook methods, you'll need to pass an array one of two ways.
+ *
+ * Any of the syntaxes explained in the PHP documentation for the
+ * {@link http://us2.php.net/manual/en/language.pseudo-types.php#language.types.callback 'callback'}
+ * type are valid.
+ *
+ * Also see the {@link http://codex.wordpress.org/Plugin_API Plugin API} for
+ * more information and examples on how to use a lot of these functions.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.5
+ */
+
+/**
+ * Hooks a function or method to a specific filter action.
+ *
+ * Filters are the hooks that WordPress launches to modify text of various types
+ * before adding it to the database or sending it to the browser screen. Plugins
+ * can specify that one or more of its PHP functions is executed to
+ * modify specific types of text at these times, using the Filter API.
+ *
+ * To use the API, the following code should be used to bind a callback to the
+ * filter.
+ *
+ * <code>
+ * function example_hook($example) { echo $example; }
+ * add_filter('example_filter', 'example_hook');
+ * </code>
+ *
+ * In WordPress 1.5.1+, hooked functions can take extra arguments that are set
+ * when the matching do_action() or apply_filters() call is run. The
+ * $accepted_args allow for calling functions only when the number of args
+ * match. Hooked functions can take extra arguments that are set when the
+ * matching do_action() or apply_filters() call is run. For example, the action
+ * comment_id_not_found will pass any functions that hook onto it the ID of the
+ * requested comment.
+ *
+ * <strong>Note:</strong> the function will return true no matter if the
+ * function was hooked fails or not. There are no checks for whether the
+ * function exists beforehand and no checks to whether the <tt>$function_to_add</tt>
+ * is even a string. It is up to you to take care and this is done for
+ * optimization purposes, so everything is as quick as possible.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 0.71
+ * @global array $wp_filter Stores all of the filters added in the form of
+ * wp_filter['tag']['array of priorities']['array of functions serialized']['array of ['array (functions, accepted_args)']']
+ * @global array $merged_filters Tracks the tags that need to be merged for later. If the hook is added, it doesn't need to run through that process.
+ *
+ * @param string $tag The name of the filter to hook the $function_to_add to.
+ * @param callback $function_to_add The name of the function to be called when the filter is applied.
+ * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
+ * @param int $accepted_args optional. The number of arguments the function accept (default 1).
+ * @return boolean true
+ */
+function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
+ global $wp_filter, $merged_filters;
+
+ $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
+ $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
+ unset( $merged_filters[ $tag ] );
+ return true;
+}
+
+/**
+ * Check if any filter has been registered for a hook.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ * @global array $wp_filter Stores all of the filters
+ *
+ * @param string $tag The name of the filter hook.
+ * @param callback $function_to_check optional.
+ * @return mixed If $function_to_check is omitted, returns boolean for whether the hook has anything registered.
+ * When checking a specific function, the priority of that hook is returned, or false if the function is not attached.
+ * When using the $function_to_check argument, this function may return a non-boolean value that evaluates to false
+ * (e.g.) 0, so use the === operator for testing the return value.
+ */
+function has_filter($tag, $function_to_check = false) {
+ global $wp_filter;
+
+ $has = !empty($wp_filter[$tag]);
+ if ( false === $function_to_check || false == $has )
+ return $has;
+
+ if ( !$idx = _wp_filter_build_unique_id($tag, $function_to_check, false) )
+ return false;
+
+ foreach ( (array) array_keys($wp_filter[$tag]) as $priority ) {
+ if ( isset($wp_filter[$tag][$priority][$idx]) )
+ return $priority;
+ }
+
+ return false;
+}
+
+/**
+ * Call the functions added to a filter hook.
+ *
+ * The callback functions attached to filter hook $tag are invoked by calling
+ * this function. This function can be used to create a new filter hook by
+ * simply calling this function with the name of the new hook specified using
+ * the $tag parameter.
+ *
+ * The function allows for additional arguments to be added and passed to hooks.
+ * <code>
+ * function example_hook($string, $arg1, $arg2)
+ * {
+ * //Do stuff
+ * return $string;
+ * }
+ * $value = apply_filters('example_filter', 'filter me', 'arg1', 'arg2');
+ * </code>
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 0.71
+ * @global array $wp_filter Stores all of the filters
+ * @global array $merged_filters Merges the filter hooks using this function.
+ * @global array $wp_current_filter stores the list of current filters with the current one last
+ *
+ * @param string $tag The name of the filter hook.
+ * @param mixed $value The value on which the filters hooked to <tt>$tag</tt> are applied on.
+ * @param mixed $var,... Additional variables passed to the functions hooked to <tt>$tag</tt>.
+ * @return mixed The filtered value after all hooked functions are applied to it.
+ */
+function apply_filters($tag, $value) {
+ global $wp_filter, $merged_filters, $wp_current_filter;
+
+ $args = array();
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $wp_current_filter[] = $tag;
+ $args = func_get_args();
+ _wp_call_all_hook($args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ if ( isset($wp_filter['all']) )
+ array_pop($wp_current_filter);
+ return $value;
+ }
+
+ if ( !isset($wp_filter['all']) )
+ $wp_current_filter[] = $tag;
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ if ( empty($args) )
+ $args = func_get_args();
+
+ do {
+ foreach( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) ){
+ $args[1] = $value;
+ $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
+ }
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop( $wp_current_filter );
+
+ return $value;
+}
+
+/**
+ * Execute functions hooked on a specific filter hook, specifying arguments in an array.
+ *
+ * @see apply_filters() This function is identical, but the arguments passed to the
+ * functions hooked to <tt>$tag</tt> are supplied using an array.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 3.0.0
+ * @global array $wp_filter Stores all of the filters
+ * @global array $merged_filters Merges the filter hooks using this function.
+ * @global array $wp_current_filter stores the list of current filters with the current one last
+ *
+ * @param string $tag The name of the filter hook.
+ * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt>
+ * @return mixed The filtered value after all hooked functions are applied to it.
+ */
+function apply_filters_ref_array($tag, $args) {
+ global $wp_filter, $merged_filters, $wp_current_filter;
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $wp_current_filter[] = $tag;
+ $all_args = func_get_args();
+ _wp_call_all_hook($all_args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ if ( isset($wp_filter['all']) )
+ array_pop($wp_current_filter);
+ return $args[0];
+ }
+
+ if ( !isset($wp_filter['all']) )
+ $wp_current_filter[] = $tag;
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ do {
+ foreach( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) )
+ $args[0] = call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop( $wp_current_filter );
+
+ return $args[0];
+}
+
+/**
+ * Removes a function from a specified filter hook.
+ *
+ * This function removes a function attached to a specified filter hook. This
+ * method can be used to remove default functions attached to a specific filter
+ * hook and possibly replace them with a substitute.
+ *
+ * To remove a hook, the $function_to_remove and $priority arguments must match
+ * when the hook was added. This goes for both filters and actions. No warning
+ * will be given on removal failure.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ *
+ * @param string $tag The filter hook to which the function to be removed is hooked.
+ * @param callback $function_to_remove The name of the function which should be removed.
+ * @param int $priority optional. The priority of the function (default: 10).
+ * @param int $accepted_args optional. The number of arguments the function accepts (default: 1).
+ * @return boolean Whether the function existed before it was removed.
+ */
+function remove_filter( $tag, $function_to_remove, $priority = 10 ) {
+ $function_to_remove = _wp_filter_build_unique_id($tag, $function_to_remove, $priority);
+
+ $r = isset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
+
+ if ( true === $r) {
+ unset($GLOBALS['wp_filter'][$tag][$priority][$function_to_remove]);
+ if ( empty($GLOBALS['wp_filter'][$tag][$priority]) )
+ unset($GLOBALS['wp_filter'][$tag][$priority]);
+ unset($GLOBALS['merged_filters'][$tag]);
+ }
+
+ return $r;
+}
+
+/**
+ * Remove all of the hooks from a filter.
+ *
+ * @since 2.7
+ *
+ * @param string $tag The filter to remove hooks from.
+ * @param int $priority The priority number to remove.
+ * @return bool True when finished.
+ */
+function remove_all_filters($tag, $priority = false) {
+ global $wp_filter, $merged_filters;
+
+ if( isset($wp_filter[$tag]) ) {
+ if( false !== $priority && isset($wp_filter[$tag][$priority]) )
+ unset($wp_filter[$tag][$priority]);
+ else
+ unset($wp_filter[$tag]);
+ }
+
+ if( isset($merged_filters[$tag]) )
+ unset($merged_filters[$tag]);
+
+ return true;
+}
+
+/**
+ * Retrieve the name of the current filter or action.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ *
+ * @return string Hook name of the current filter or action.
+ */
+function current_filter() {
+ global $wp_current_filter;
+ return end( $wp_current_filter );
+}
+
+/**
+ * Hooks a function on to a specific action.
+ *
+ * Actions are the hooks that the WordPress core launches at specific points
+ * during execution, or when specific events occur. Plugins can specify that
+ * one or more of its PHP functions are executed at these points, using the
+ * Action API.
+ *
+ * @uses add_filter() Adds an action. Parameter list and functionality are the same.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ *
+ * @param string $tag The name of the action to which the $function_to_add is hooked.
+ * @param callback $function_to_add The name of the function you wish to be called.
+ * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
+ * @param int $accepted_args optional. The number of arguments the function accept (default 1).
+ */
+function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
+ return add_filter($tag, $function_to_add, $priority, $accepted_args);
+}
+
+/**
+ * Execute functions hooked on a specific action hook.
+ *
+ * This function invokes all functions attached to action hook $tag. It is
+ * possible to create new action hooks by simply calling this function,
+ * specifying the name of the new hook using the <tt>$tag</tt> parameter.
+ *
+ * You can pass extra arguments to the hooks, much like you can with
+ * apply_filters().
+ *
+ * @see apply_filters() This function works similar with the exception that
+ * nothing is returned and only the functions or methods are called.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ * @global array $wp_filter Stores all of the filters
+ * @global array $wp_actions Increments the amount of times action was triggered.
+ *
+ * @param string $tag The name of the action to be executed.
+ * @param mixed $arg,... Optional additional arguments which are passed on to the functions hooked to the action.
+ * @return null Will return null if $tag does not exist in $wp_filter array
+ */
+function do_action($tag, $arg = '') {
+ global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
+
+ if ( ! isset($wp_actions) )
+ $wp_actions = array();
+
+ if ( ! isset($wp_actions[$tag]) )
+ $wp_actions[$tag] = 1;
+ else
+ ++$wp_actions[$tag];
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $wp_current_filter[] = $tag;
+ $all_args = func_get_args();
+ _wp_call_all_hook($all_args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ if ( isset($wp_filter['all']) )
+ array_pop($wp_current_filter);
+ return;
+ }
+
+ if ( !isset($wp_filter['all']) )
+ $wp_current_filter[] = $tag;
+
+ $args = array();
+ if ( is_array($arg) && 1 == count($arg) && isset($arg[0]) && is_object($arg[0]) ) // array(&$this)
+ $args[] =& $arg[0];
+ else
+ $args[] = $arg;
+ for ( $a = 2; $a < func_num_args(); $a++ )
+ $args[] = func_get_arg($a);
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ do {
+ foreach ( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) )
+ call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop($wp_current_filter);
+}
+
+/**
+ * Retrieve the number of times an action is fired.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.1
+ * @global array $wp_actions Increments the amount of times action was triggered.
+ *
+ * @param string $tag The name of the action hook.
+ * @return int The number of times action hook <tt>$tag</tt> is fired
+ */
+function did_action($tag) {
+ global $wp_actions;
+
+ if ( ! isset( $wp_actions ) || ! isset( $wp_actions[$tag] ) )
+ return 0;
+
+ return $wp_actions[$tag];
+}
+
+/**
+ * Execute functions hooked on a specific action hook, specifying arguments in an array.
+ *
+ * @see do_action() This function is identical, but the arguments passed to the
+ * functions hooked to <tt>$tag</tt> are supplied using an array.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.1
+ * @global array $wp_filter Stores all of the filters
+ * @global array $wp_actions Increments the amount of times action was triggered.
+ *
+ * @param string $tag The name of the action to be executed.
+ * @param array $args The arguments supplied to the functions hooked to <tt>$tag</tt>
+ * @return null Will return null if $tag does not exist in $wp_filter array
+ */
+function do_action_ref_array($tag, $args) {
+ global $wp_filter, $wp_actions, $merged_filters, $wp_current_filter;
+
+ if ( ! isset($wp_actions) )
+ $wp_actions = array();
+
+ if ( ! isset($wp_actions[$tag]) )
+ $wp_actions[$tag] = 1;
+ else
+ ++$wp_actions[$tag];
+
+ // Do 'all' actions first
+ if ( isset($wp_filter['all']) ) {
+ $wp_current_filter[] = $tag;
+ $all_args = func_get_args();
+ _wp_call_all_hook($all_args);
+ }
+
+ if ( !isset($wp_filter[$tag]) ) {
+ if ( isset($wp_filter['all']) )
+ array_pop($wp_current_filter);
+ return;
+ }
+
+ if ( !isset($wp_filter['all']) )
+ $wp_current_filter[] = $tag;
+
+ // Sort
+ if ( !isset( $merged_filters[ $tag ] ) ) {
+ ksort($wp_filter[$tag]);
+ $merged_filters[ $tag ] = true;
+ }
+
+ reset( $wp_filter[ $tag ] );
+
+ do {
+ foreach( (array) current($wp_filter[$tag]) as $the_ )
+ if ( !is_null($the_['function']) )
+ call_user_func_array($the_['function'], array_slice($args, 0, (int) $the_['accepted_args']));
+
+ } while ( next($wp_filter[$tag]) !== false );
+
+ array_pop($wp_current_filter);
+}
+
+/**
+ * Check if any action has been registered for a hook.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ * @see has_filter() has_action() is an alias of has_filter().
+ *
+ * @param string $tag The name of the action hook.
+ * @param callback $function_to_check optional.
+ * @return mixed If $function_to_check is omitted, returns boolean for whether the hook has anything registered.
+ * When checking a specific function, the priority of that hook is returned, or false if the function is not attached.
+ * When using the $function_to_check argument, this function may return a non-boolean value that evaluates to false
+ * (e.g.) 0, so use the === operator for testing the return value.
+ */
+function has_action($tag, $function_to_check = false) {
+ return has_filter($tag, $function_to_check);
+}
+
+/**
+ * Removes a function from a specified action hook.
+ *
+ * This function removes a function attached to a specified action hook. This
+ * method can be used to remove default functions attached to a specific filter
+ * hook and possibly replace them with a substitute.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.2
+ *
+ * @param string $tag The action hook to which the function to be removed is hooked.
+ * @param callback $function_to_remove The name of the function which should be removed.
+ * @param int $priority optional The priority of the function (default: 10).
+ * @return boolean Whether the function is removed.
+ */
+function remove_action( $tag, $function_to_remove, $priority = 10 ) {
+ return remove_filter( $tag, $function_to_remove, $priority );
+}
+
+/**
+ * Remove all of the hooks from an action.
+ *
+ * @since 2.7
+ *
+ * @param string $tag The action to remove hooks from.
+ * @param int $priority The priority number to remove them from.
+ * @return bool True when finished.
+ */
+function remove_all_actions($tag, $priority = false) {
+ return remove_all_filters($tag, $priority);
+}
+
+//
+// Functions for handling plugins.
+//
+
+/**
+ * Gets the basename of a plugin.
+ *
+ * This method extracts the name of a plugin from its filename.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 1.5
+ *
+ * @access private
+ *
+ * @param string $file The filename of plugin.
+ * @return string The name of a plugin.
+ * @uses WP_PLUGIN_DIR
+ */
+function plugin_basename($file) {
+ $file = str_replace('\\','/',$file); // sanitize for Win32 installs
+ $file = preg_replace('|/+|','/', $file); // remove any duplicate slash
+ $plugin_dir = str_replace('\\','/',WP_PLUGIN_DIR); // sanitize for Win32 installs
+ $plugin_dir = preg_replace('|/+|','/', $plugin_dir); // remove any duplicate slash
+ $mu_plugin_dir = str_replace('\\','/',WPMU_PLUGIN_DIR); // sanitize for Win32 installs
+ $mu_plugin_dir = preg_replace('|/+|','/', $mu_plugin_dir); // remove any duplicate slash
+ $file = preg_replace('#^' . preg_quote($plugin_dir, '#') . '/|^' . preg_quote($mu_plugin_dir, '#') . '/#','',$file); // get relative path from plugins dir
+ $file = trim($file, '/');
+ return $file;
+}
+
+/**
+ * Gets the filesystem directory path (with trailing slash) for the plugin __FILE__ passed in
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.8
+ *
+ * @param string $file The filename of the plugin (__FILE__)
+ * @return string the filesystem path of the directory that contains the plugin
+ */
+function plugin_dir_path( $file ) {
+ return trailingslashit( dirname( $file ) );
+}
+
+/**
+ * Gets the URL directory path (with trailing slash) for the plugin __FILE__ passed in
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.8
+ *
+ * @param string $file The filename of the plugin (__FILE__)
+ * @return string the URL path of the directory that contains the plugin
+ */
+function plugin_dir_url( $file ) {
+ return trailingslashit( plugins_url( '', $file ) );
+}
+
+/**
+ * Set the activation hook for a plugin.
+ *
+ * When a plugin is activated, the action 'activate_PLUGINNAME' hook is
+ * called. In the name of this hook, PLUGINNAME is replaced with the name
+ * of the plugin, including the optional subdirectory. For example, when the
+ * plugin is located in wp-content/plugins/sampleplugin/sample.php, then
+ * the name of this hook will become 'activate_sampleplugin/sample.php'.
+ *
+ * When the plugin consists of only one file and is (as by default) located at
+ * wp-content/plugins/sample.php the name of this hook will be
+ * 'activate_sample.php'.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.0
+ *
+ * @param string $file The filename of the plugin including the path.
+ * @param callback $function the function hooked to the 'activate_PLUGIN' action.
+ */
+function register_activation_hook($file, $function) {
+ $file = plugin_basename($file);
+ add_action('activate_' . $file, $function);
+}
+
+/**
+ * Set the deactivation hook for a plugin.
+ *
+ * When a plugin is deactivated, the action 'deactivate_PLUGINNAME' hook is
+ * called. In the name of this hook, PLUGINNAME is replaced with the name
+ * of the plugin, including the optional subdirectory. For example, when the
+ * plugin is located in wp-content/plugins/sampleplugin/sample.php, then
+ * the name of this hook will become 'deactivate_sampleplugin/sample.php'.
+ *
+ * When the plugin consists of only one file and is (as by default) located at
+ * wp-content/plugins/sample.php the name of this hook will be
+ * 'deactivate_sample.php'.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.0
+ *
+ * @param string $file The filename of the plugin including the path.
+ * @param callback $function the function hooked to the 'deactivate_PLUGIN' action.
+ */
+function register_deactivation_hook($file, $function) {
+ $file = plugin_basename($file);
+ add_action('deactivate_' . $file, $function);
+}
+
+/**
+ * Set the uninstallation hook for a plugin.
+ *
+ * Registers the uninstall hook that will be called when the user clicks on the
+ * uninstall link that calls for the plugin to uninstall itself. The link won't
+ * be active unless the plugin hooks into the action.
+ *
+ * The plugin should not run arbitrary code outside of functions, when
+ * registering the uninstall hook. In order to run using the hook, the plugin
+ * will have to be included, which means that any code laying outside of a
+ * function will be run during the uninstall process. The plugin should not
+ * hinder the uninstall process.
+ *
+ * If the plugin can not be written without running code within the plugin, then
+ * the plugin should create a file named 'uninstall.php' in the base plugin
+ * folder. This file will be called, if it exists, during the uninstall process
+ * bypassing the uninstall hook. The plugin, when using the 'uninstall.php'
+ * should always check for the 'WP_UNINSTALL_PLUGIN' constant, before
+ * executing.
+ *
+ * @since 2.7
+ *
+ * @param string $file
+ * @param callback $callback The callback to run when the hook is called. Must be a static method or function.
+ */
+function register_uninstall_hook( $file, $callback ) {
+ if ( is_array( $callback ) && is_object( $callback[0] ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Only a static class method or function can be used in an uninstall hook.' ), '3.1' );
+ return;
+ }
+
+ // The option should not be autoloaded, because it is not needed in most
+ // cases. Emphasis should be put on using the 'uninstall.php' way of
+ // uninstalling the plugin.
+ $uninstallable_plugins = (array) get_option('uninstall_plugins');
+ $uninstallable_plugins[plugin_basename($file)] = $callback;
+ update_option('uninstall_plugins', $uninstallable_plugins);
+}
+
+/**
+ * Calls the 'all' hook, which will process the functions hooked into it.
+ *
+ * The 'all' hook passes all of the arguments or parameters that were used for
+ * the hook, which this function was called for.
+ *
+ * This function is used internally for apply_filters(), do_action(), and
+ * do_action_ref_array() and is not meant to be used from outside those
+ * functions. This function does not check for the existence of the all hook, so
+ * it will fail unless the all hook exists prior to this function call.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @since 2.5
+ * @access private
+ *
+ * @uses $wp_filter Used to process all of the functions in the 'all' hook
+ *
+ * @param array $args The collected parameters from the hook that was called.
+ * @param string $hook Optional. The hook name that was used to call the 'all' hook.
+ */
+function _wp_call_all_hook($args) {
+ global $wp_filter;
+
+ reset( $wp_filter['all'] );
+ do {
+ foreach( (array) current($wp_filter['all']) as $the_ )
+ if ( !is_null($the_['function']) )
+ call_user_func_array($the_['function'], $args);
+
+ } while ( next($wp_filter['all']) !== false );
+}
+
+/**
+ * Build Unique ID for storage and retrieval.
+ *
+ * The old way to serialize the callback caused issues and this function is the
+ * solution. It works by checking for objects and creating an a new property in
+ * the class to keep track of the object and new objects of the same class that
+ * need to be added.
+ *
+ * It also allows for the removal of actions and filters for objects after they
+ * change class properties. It is possible to include the property $wp_filter_id
+ * in your class and set it to "null" or a number to bypass the workaround.
+ * However this will prevent you from adding new classes and any new classes
+ * will overwrite the previous hook by the same class.
+ *
+ * Functions and static method callbacks are just returned as strings and
+ * shouldn't have any speed penalty.
+ *
+ * @package WordPress
+ * @subpackage Plugin
+ * @access private
+ * @since 2.2.3
+ * @link http://trac.wordpress.org/ticket/3875
+ *
+ * @global array $wp_filter Storage for all of the filters and actions
+ * @param string $tag Used in counting how many hooks were applied
+ * @param callback $function Used for creating unique id
+ * @param int|bool $priority Used in counting how many hooks were applied. If === false and $function is an object reference, we return the unique id only if it already has one, false otherwise.
+ * @return string|bool Unique ID for usage as array key or false if $priority === false and $function is an object reference, and it does not already have a unique id.
+ */
+function _wp_filter_build_unique_id($tag, $function, $priority) {
+ global $wp_filter;
+ static $filter_id_count = 0;
+
+ if ( is_string($function) )
+ return $function;
+
+ if ( is_object($function) ) {
+ // Closures are currently implemented as objects
+ $function = array( $function, '' );
+ } else {
+ $function = (array) $function;
+ }
+
+ if (is_object($function[0]) ) {
+ // Object Class Calling
+ if ( function_exists('spl_object_hash') ) {
+ return spl_object_hash($function[0]) . $function[1];
+ } else {
+ $obj_idx = get_class($function[0]).$function[1];
+ if ( !isset($function[0]->wp_filter_id) ) {
+ if ( false === $priority )
+ return false;
+ $obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count;
+ $function[0]->wp_filter_id = $filter_id_count;
+ ++$filter_id_count;
+ } else {
+ $obj_idx .= $function[0]->wp_filter_id;
+ }
+
+ return $obj_idx;
+ }
+ } else if ( is_string($function[0]) ) {
+ // Static Calling
+ return $function[0] . '::' . $function[1];
+ }
+}
diff --git a/src/wp-includes/pomo/entry.php b/src/wp-includes/pomo/entry.php
new file mode 100644
index 0000000000..097e92ca55
--- /dev/null
+++ b/src/wp-includes/pomo/entry.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Contains Translation_Entry class
+ *
+ * @version $Id: entry.php 718 2012-10-31 00:32:02Z nbachiyski $
+ * @package pomo
+ * @subpackage entry
+ */
+
+if ( !class_exists( 'Translation_Entry' ) ):
+/**
+ * Translation_Entry class encapsulates a translatable string
+ */
+class Translation_Entry {
+
+ /**
+ * Whether the entry contains a string and its plural form, default is false
+ *
+ * @var boolean
+ */
+ var $is_plural = false;
+
+ var $context = null;
+ var $singular = null;
+ var $plural = null;
+ var $translations = array();
+ var $translator_comments = '';
+ var $extracted_comments = '';
+ var $references = array();
+ var $flags = array();
+
+ /**
+ * @param array $args associative array, support following keys:
+ * - singular (string) -- the string to translate, if omitted and empty entry will be created
+ * - plural (string) -- the plural form of the string, setting this will set {@link $is_plural} to true
+ * - translations (array) -- translations of the string and possibly -- its plural forms
+ * - context (string) -- a string differentiating two equal strings used in different contexts
+ * - translator_comments (string) -- comments left by translators
+ * - extracted_comments (string) -- comments left by developers
+ * - references (array) -- places in the code this strings is used, in relative_to_root_path/file.php:linenum form
+ * - flags (array) -- flags like php-format
+ */
+ function Translation_Entry($args=array()) {
+ // if no singular -- empty object
+ if (!isset($args['singular'])) {
+ return;
+ }
+ // get member variable values from args hash
+ foreach ($args as $varname => $value) {
+ $this->$varname = $value;
+ }
+ if (isset($args['plural'])) $this->is_plural = true;
+ if (!is_array($this->translations)) $this->translations = array();
+ if (!is_array($this->references)) $this->references = array();
+ if (!is_array($this->flags)) $this->flags = array();
+ }
+
+ /**
+ * Generates a unique key for this entry
+ *
+ * @return string|bool the key or false if the entry is empty
+ */
+ function key() {
+ if (is_null($this->singular)) return false;
+ // prepend context and EOT, like in MO files
+ return is_null($this->context)? $this->singular : $this->context.chr(4).$this->singular;
+ }
+
+ function merge_with(&$other) {
+ $this->flags = array_unique( array_merge( $this->flags, $other->flags ) );
+ $this->references = array_unique( array_merge( $this->references, $other->references ) );
+ if ( $this->extracted_comments != $other->extracted_comments ) {
+ $this->extracted_comments .= $other->extracted_comments;
+ }
+
+ }
+}
+endif; \ No newline at end of file
diff --git a/src/wp-includes/pomo/mo.php b/src/wp-includes/pomo/mo.php
new file mode 100644
index 0000000000..68c0792fdc
--- /dev/null
+++ b/src/wp-includes/pomo/mo.php
@@ -0,0 +1,257 @@
+<?php
+/**
+ * Class for working with MO files
+ *
+ * @version $Id: mo.php 718 2012-10-31 00:32:02Z nbachiyski $
+ * @package pomo
+ * @subpackage mo
+ */
+
+require_once dirname(__FILE__) . '/translations.php';
+require_once dirname(__FILE__) . '/streams.php';
+
+if ( !class_exists( 'MO' ) ):
+class MO extends Gettext_Translations {
+
+ var $_nplurals = 2;
+
+ /**
+ * Fills up with the entries from MO file $filename
+ *
+ * @param string $filename MO file to load
+ */
+ function import_from_file($filename) {
+ $reader = new POMO_FileReader($filename);
+ if (!$reader->is_resource())
+ return false;
+ return $this->import_from_reader($reader);
+ }
+
+ function export_to_file($filename) {
+ $fh = fopen($filename, 'wb');
+ if ( !$fh ) return false;
+ $res = $this->export_to_file_handle( $fh );
+ fclose($fh);
+ return $res;
+ }
+
+ function export() {
+ $tmp_fh = fopen("php://temp", 'r+');
+ if ( !$tmp_fh ) return false;
+ $this->export_to_file_handle( $tmp_fh );
+ rewind( $tmp_fh );
+ return stream_get_contents( $tmp_fh );
+ }
+
+ function is_entry_good_for_export( $entry ) {
+ if ( empty( $entry->translations ) ) {
+ return false;
+ }
+
+ if ( !array_filter( $entry->translations ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function export_to_file_handle($fh) {
+ $entries = array_filter( $this->entries, array( $this, 'is_entry_good_for_export' ) );
+ ksort($entries);
+ $magic = 0x950412de;
+ $revision = 0;
+ $total = count($entries) + 1; // all the headers are one entry
+ $originals_lenghts_addr = 28;
+ $translations_lenghts_addr = $originals_lenghts_addr + 8 * $total;
+ $size_of_hash = 0;
+ $hash_addr = $translations_lenghts_addr + 8 * $total;
+ $current_addr = $hash_addr;
+ fwrite($fh, pack('V*', $magic, $revision, $total, $originals_lenghts_addr,
+ $translations_lenghts_addr, $size_of_hash, $hash_addr));
+ fseek($fh, $originals_lenghts_addr);
+
+ // headers' msgid is an empty string
+ fwrite($fh, pack('VV', 0, $current_addr));
+ $current_addr++;
+ $originals_table = chr(0);
+
+ foreach($entries as $entry) {
+ $originals_table .= $this->export_original($entry) . chr(0);
+ $length = strlen($this->export_original($entry));
+ fwrite($fh, pack('VV', $length, $current_addr));
+ $current_addr += $length + 1; // account for the NULL byte after
+ }
+
+ $exported_headers = $this->export_headers();
+ fwrite($fh, pack('VV', strlen($exported_headers), $current_addr));
+ $current_addr += strlen($exported_headers) + 1;
+ $translations_table = $exported_headers . chr(0);
+
+ foreach($entries as $entry) {
+ $translations_table .= $this->export_translations($entry) . chr(0);
+ $length = strlen($this->export_translations($entry));
+ fwrite($fh, pack('VV', $length, $current_addr));
+ $current_addr += $length + 1;
+ }
+
+ fwrite($fh, $originals_table);
+ fwrite($fh, $translations_table);
+ return true;
+ }
+
+ function export_original($entry) {
+ //TODO: warnings for control characters
+ $exported = $entry->singular;
+ if ($entry->is_plural) $exported .= chr(0).$entry->plural;
+ if (!is_null($entry->context)) $exported = $entry->context . chr(4) . $exported;
+ return $exported;
+ }
+
+ function export_translations($entry) {
+ //TODO: warnings for control characters
+ return implode(chr(0), $entry->translations);
+ }
+
+ function export_headers() {
+ $exported = '';
+ foreach($this->headers as $header => $value) {
+ $exported.= "$header: $value\n";
+ }
+ return $exported;
+ }
+
+ function get_byteorder($magic) {
+ // The magic is 0x950412de
+
+ // bug in PHP 5.0.2, see https://savannah.nongnu.org/bugs/?func=detailitem&item_id=10565
+ $magic_little = (int) - 1794895138;
+ $magic_little_64 = (int) 2500072158;
+ // 0xde120495
+ $magic_big = ((int) - 569244523) & 0xFFFFFFFF;
+ if ($magic_little == $magic || $magic_little_64 == $magic) {
+ return 'little';
+ } else if ($magic_big == $magic) {
+ return 'big';
+ } else {
+ return false;
+ }
+ }
+
+ function import_from_reader($reader) {
+ $endian_string = MO::get_byteorder($reader->readint32());
+ if (false === $endian_string) {
+ return false;
+ }
+ $reader->setEndian($endian_string);
+
+ $endian = ('big' == $endian_string)? 'N' : 'V';
+
+ $header = $reader->read(24);
+ if ($reader->strlen($header) != 24)
+ return false;
+
+ // parse header
+ $header = unpack("{$endian}revision/{$endian}total/{$endian}originals_lenghts_addr/{$endian}translations_lenghts_addr/{$endian}hash_length/{$endian}hash_addr", $header);
+ if (!is_array($header))
+ return false;
+
+ extract( $header );
+
+ // support revision 0 of MO format specs, only
+ if ($revision != 0)
+ return false;
+
+ // seek to data blocks
+ $reader->seekto($originals_lenghts_addr);
+
+ // read originals' indices
+ $originals_lengths_length = $translations_lenghts_addr - $originals_lenghts_addr;
+ if ( $originals_lengths_length != $total * 8 )
+ return false;
+
+ $originals = $reader->read($originals_lengths_length);
+ if ( $reader->strlen( $originals ) != $originals_lengths_length )
+ return false;
+
+ // read translations' indices
+ $translations_lenghts_length = $hash_addr - $translations_lenghts_addr;
+ if ( $translations_lenghts_length != $total * 8 )
+ return false;
+
+ $translations = $reader->read($translations_lenghts_length);
+ if ( $reader->strlen( $translations ) != $translations_lenghts_length )
+ return false;
+
+ // transform raw data into set of indices
+ $originals = $reader->str_split( $originals, 8 );
+ $translations = $reader->str_split( $translations, 8 );
+
+ // skip hash table
+ $strings_addr = $hash_addr + $hash_length * 4;
+
+ $reader->seekto($strings_addr);
+
+ $strings = $reader->read_all();
+ $reader->close();
+
+ for ( $i = 0; $i < $total; $i++ ) {
+ $o = unpack( "{$endian}length/{$endian}pos", $originals[$i] );
+ $t = unpack( "{$endian}length/{$endian}pos", $translations[$i] );
+ if ( !$o || !$t ) return false;
+
+ // adjust offset due to reading strings to separate space before
+ $o['pos'] -= $strings_addr;
+ $t['pos'] -= $strings_addr;
+
+ $original = $reader->substr( $strings, $o['pos'], $o['length'] );
+ $translation = $reader->substr( $strings, $t['pos'], $t['length'] );
+
+ if ('' === $original) {
+ $this->set_headers($this->make_headers($translation));
+ } else {
+ $entry = &$this->make_entry($original, $translation);
+ $this->entries[$entry->key()] = &$entry;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Build a Translation_Entry from original string and translation strings,
+ * found in a MO file
+ *
+ * @static
+ * @param string $original original string to translate from MO file. Might contain
+ * 0x04 as context separator or 0x00 as singular/plural separator
+ * @param string $translation translation string from MO file. Might contain
+ * 0x00 as a plural translations separator
+ */
+ function &make_entry($original, $translation) {
+ $entry = new Translation_Entry();
+ // look for context
+ $parts = explode(chr(4), $original);
+ if (isset($parts[1])) {
+ $original = $parts[1];
+ $entry->context = $parts[0];
+ }
+ // look for plural original
+ $parts = explode(chr(0), $original);
+ $entry->singular = $parts[0];
+ if (isset($parts[1])) {
+ $entry->is_plural = true;
+ $entry->plural = $parts[1];
+ }
+ // plural translations are also separated by \0
+ $entry->translations = explode(chr(0), $translation);
+ return $entry;
+ }
+
+ function select_plural_form($count) {
+ return $this->gettext_select_plural_form($count);
+ }
+
+ function get_plural_forms_count() {
+ return $this->_nplurals;
+ }
+}
+endif; \ No newline at end of file
diff --git a/src/wp-includes/pomo/po.php b/src/wp-includes/pomo/po.php
new file mode 100644
index 0000000000..f76be01139
--- /dev/null
+++ b/src/wp-includes/pomo/po.php
@@ -0,0 +1,384 @@
+<?php
+/**
+ * Class for working with PO files
+ *
+ * @version $Id: po.php 718 2012-10-31 00:32:02Z nbachiyski $
+ * @package pomo
+ * @subpackage po
+ */
+
+require_once dirname(__FILE__) . '/translations.php';
+
+define('PO_MAX_LINE_LEN', 79);
+
+ini_set('auto_detect_line_endings', 1);
+
+/**
+ * Routines for working with PO files
+ */
+if ( !class_exists( 'PO' ) ):
+class PO extends Gettext_Translations {
+
+ var $comments_before_headers = '';
+
+ /**
+ * Exports headers to a PO entry
+ *
+ * @return string msgid/msgstr PO entry for this PO file headers, doesn't contain newline at the end
+ */
+ function export_headers() {
+ $header_string = '';
+ foreach($this->headers as $header => $value) {
+ $header_string.= "$header: $value\n";
+ }
+ $poified = PO::poify($header_string);
+ if ($this->comments_before_headers)
+ $before_headers = $this->prepend_each_line(rtrim($this->comments_before_headers)."\n", '# ');
+ else
+ $before_headers = '';
+ return rtrim("{$before_headers}msgid \"\"\nmsgstr $poified");
+ }
+
+ /**
+ * Exports all entries to PO format
+ *
+ * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end
+ */
+ function export_entries() {
+ //TODO sorting
+ return implode("\n\n", array_map(array('PO', 'export_entry'), $this->entries));
+ }
+
+ /**
+ * Exports the whole PO file as a string
+ *
+ * @param bool $include_headers whether to include the headers in the export
+ * @return string ready for inclusion in PO file string for headers and all the enrtries
+ */
+ function export($include_headers = true) {
+ $res = '';
+ if ($include_headers) {
+ $res .= $this->export_headers();
+ $res .= "\n\n";
+ }
+ $res .= $this->export_entries();
+ return $res;
+ }
+
+ /**
+ * Same as {@link export}, but writes the result to a file
+ *
+ * @param string $filename where to write the PO string
+ * @param bool $include_headers whether to include tje headers in the export
+ * @return bool true on success, false on error
+ */
+ function export_to_file($filename, $include_headers = true) {
+ $fh = fopen($filename, 'w');
+ if (false === $fh) return false;
+ $export = $this->export($include_headers);
+ $res = fwrite($fh, $export);
+ if (false === $res) return false;
+ return fclose($fh);
+ }
+
+ /**
+ * Text to include as a comment before the start of the PO contents
+ *
+ * Doesn't need to include # in the beginning of lines, these are added automatically
+ */
+ function set_comment_before_headers( $text ) {
+ $this->comments_before_headers = $text;
+ }
+
+ /**
+ * Formats a string in PO-style
+ *
+ * @static
+ * @param string $string the string to format
+ * @return string the poified string
+ */
+ function poify($string) {
+ $quote = '"';
+ $slash = '\\';
+ $newline = "\n";
+
+ $replaces = array(
+ "$slash" => "$slash$slash",
+ "$quote" => "$slash$quote",
+ "\t" => '\t',
+ );
+
+ $string = str_replace(array_keys($replaces), array_values($replaces), $string);
+
+ $po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
+ // add empty string on first line for readbility
+ if (false !== strpos($string, $newline) &&
+ (substr_count($string, $newline) > 1 || !($newline === substr($string, -strlen($newline))))) {
+ $po = "$quote$quote$newline$po";
+ }
+ // remove empty strings
+ $po = str_replace("$newline$quote$quote", '', $po);
+ return $po;
+ }
+
+ /**
+ * Gives back the original string from a PO-formatted string
+ *
+ * @static
+ * @param string $string PO-formatted string
+ * @return string enascaped string
+ */
+ function unpoify($string) {
+ $escapes = array('t' => "\t", 'n' => "\n", '\\' => '\\');
+ $lines = array_map('trim', explode("\n", $string));
+ $lines = array_map(array('PO', 'trim_quotes'), $lines);
+ $unpoified = '';
+ $previous_is_backslash = false;
+ foreach($lines as $line) {
+ preg_match_all('/./u', $line, $chars);
+ $chars = $chars[0];
+ foreach($chars as $char) {
+ if (!$previous_is_backslash) {
+ if ('\\' == $char)
+ $previous_is_backslash = true;
+ else
+ $unpoified .= $char;
+ } else {
+ $previous_is_backslash = false;
+ $unpoified .= isset($escapes[$char])? $escapes[$char] : $char;
+ }
+ }
+ }
+ return $unpoified;
+ }
+
+ /**
+ * Inserts $with in the beginning of every new line of $string and
+ * returns the modified string
+ *
+ * @static
+ * @param string $string prepend lines in this string
+ * @param string $with prepend lines with this string
+ */
+ function prepend_each_line($string, $with) {
+ $php_with = var_export($with, true);
+ $lines = explode("\n", $string);
+ // do not prepend the string on the last empty line, artefact by explode
+ if ("\n" == substr($string, -1)) unset($lines[count($lines) - 1]);
+ $res = implode("\n", array_map(create_function('$x', "return $php_with.\$x;"), $lines));
+ // give back the empty line, we ignored above
+ if ("\n" == substr($string, -1)) $res .= "\n";
+ return $res;
+ }
+
+ /**
+ * Prepare a text as a comment -- wraps the lines and prepends #
+ * and a special character to each line
+ *
+ * @access private
+ * @param string $text the comment text
+ * @param string $char character to denote a special PO comment,
+ * like :, default is a space
+ */
+ function comment_block($text, $char=' ') {
+ $text = wordwrap($text, PO_MAX_LINE_LEN - 3);
+ return PO::prepend_each_line($text, "#$char ");
+ }
+
+ /**
+ * Builds a string from the entry for inclusion in PO file
+ *
+ * @static
+ * @param object &$entry the entry to convert to po string
+ * @return string|bool PO-style formatted string for the entry or
+ * false if the entry is empty
+ */
+ function export_entry(&$entry) {
+ if (is_null($entry->singular)) return false;
+ $po = array();
+ if (!empty($entry->translator_comments)) $po[] = PO::comment_block($entry->translator_comments);
+ if (!empty($entry->extracted_comments)) $po[] = PO::comment_block($entry->extracted_comments, '.');
+ if (!empty($entry->references)) $po[] = PO::comment_block(implode(' ', $entry->references), ':');
+ if (!empty($entry->flags)) $po[] = PO::comment_block(implode(", ", $entry->flags), ',');
+ if (!is_null($entry->context)) $po[] = 'msgctxt '.PO::poify($entry->context);
+ $po[] = 'msgid '.PO::poify($entry->singular);
+ if (!$entry->is_plural) {
+ $translation = empty($entry->translations)? '' : $entry->translations[0];
+ $po[] = 'msgstr '.PO::poify($translation);
+ } else {
+ $po[] = 'msgid_plural '.PO::poify($entry->plural);
+ $translations = empty($entry->translations)? array('', '') : $entry->translations;
+ foreach($translations as $i => $translation) {
+ $po[] = "msgstr[$i] ".PO::poify($translation);
+ }
+ }
+ return implode("\n", $po);
+ }
+
+ function import_from_file($filename) {
+ $f = fopen($filename, 'r');
+ if (!$f) return false;
+ $lineno = 0;
+ while (true) {
+ $res = $this->read_entry($f, $lineno);
+ if (!$res) break;
+ if ($res['entry']->singular == '') {
+ $this->set_headers($this->make_headers($res['entry']->translations[0]));
+ } else {
+ $this->add_entry($res['entry']);
+ }
+ }
+ PO::read_line($f, 'clear');
+ if ( false === $res ) {
+ return false;
+ }
+ if ( ! $this->headers && ! $this->entries ) {
+ return false;
+ }
+ return true;
+ }
+
+ function read_entry($f, $lineno = 0) {
+ $entry = new Translation_Entry();
+ // where were we in the last step
+ // can be: comment, msgctxt, msgid, msgid_plural, msgstr, msgstr_plural
+ $context = '';
+ $msgstr_index = 0;
+ $is_final = create_function('$context', 'return $context == "msgstr" || $context == "msgstr_plural";');
+ while (true) {
+ $lineno++;
+ $line = PO::read_line($f);
+ if (!$line) {
+ if (feof($f)) {
+ if ($is_final($context))
+ break;
+ elseif (!$context) // we haven't read a line and eof came
+ return null;
+ else
+ return false;
+ } else {
+ return false;
+ }
+ }
+ if ($line == "\n") continue;
+ $line = trim($line);
+ if (preg_match('/^#/', $line, $m)) {
+ // the comment is the start of a new entry
+ if ($is_final($context)) {
+ PO::read_line($f, 'put-back');
+ $lineno--;
+ break;
+ }
+ // comments have to be at the beginning
+ if ($context && $context != 'comment') {
+ return false;
+ }
+ // add comment
+ $this->add_comment_to_entry($entry, $line);;
+ } elseif (preg_match('/^msgctxt\s+(".*")/', $line, $m)) {
+ if ($is_final($context)) {
+ PO::read_line($f, 'put-back');
+ $lineno--;
+ break;
+ }
+ if ($context && $context != 'comment') {
+ return false;
+ }
+ $context = 'msgctxt';
+ $entry->context .= PO::unpoify($m[1]);
+ } elseif (preg_match('/^msgid\s+(".*")/', $line, $m)) {
+ if ($is_final($context)) {
+ PO::read_line($f, 'put-back');
+ $lineno--;
+ break;
+ }
+ if ($context && $context != 'msgctxt' && $context != 'comment') {
+ return false;
+ }
+ $context = 'msgid';
+ $entry->singular .= PO::unpoify($m[1]);
+ } elseif (preg_match('/^msgid_plural\s+(".*")/', $line, $m)) {
+ if ($context != 'msgid') {
+ return false;
+ }
+ $context = 'msgid_plural';
+ $entry->is_plural = true;
+ $entry->plural .= PO::unpoify($m[1]);
+ } elseif (preg_match('/^msgstr\s+(".*")/', $line, $m)) {
+ if ($context != 'msgid') {
+ return false;
+ }
+ $context = 'msgstr';
+ $entry->translations = array(PO::unpoify($m[1]));
+ } elseif (preg_match('/^msgstr\[(\d+)\]\s+(".*")/', $line, $m)) {
+ if ($context != 'msgid_plural' && $context != 'msgstr_plural') {
+ return false;
+ }
+ $context = 'msgstr_plural';
+ $msgstr_index = $m[1];
+ $entry->translations[$m[1]] = PO::unpoify($m[2]);
+ } elseif (preg_match('/^".*"$/', $line)) {
+ $unpoified = PO::unpoify($line);
+ switch ($context) {
+ case 'msgid':
+ $entry->singular .= $unpoified; break;
+ case 'msgctxt':
+ $entry->context .= $unpoified; break;
+ case 'msgid_plural':
+ $entry->plural .= $unpoified; break;
+ case 'msgstr':
+ $entry->translations[0] .= $unpoified; break;
+ case 'msgstr_plural':
+ $entry->translations[$msgstr_index] .= $unpoified; break;
+ default:
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (array() == array_filter($entry->translations, create_function('$t', 'return $t || "0" === $t;'))) {
+ $entry->translations = array();
+ }
+ return array('entry' => $entry, 'lineno' => $lineno);
+ }
+
+ function read_line($f, $action = 'read') {
+ static $last_line = '';
+ static $use_last_line = false;
+ if ('clear' == $action) {
+ $last_line = '';
+ return true;
+ }
+ if ('put-back' == $action) {
+ $use_last_line = true;
+ return true;
+ }
+ $line = $use_last_line? $last_line : fgets($f);
+ $line = ( "\r\n" == substr( $line, -2 ) ) ? rtrim( $line, "\r\n" ) . "\n" : $line;
+ $last_line = $line;
+ $use_last_line = false;
+ return $line;
+ }
+
+ function add_comment_to_entry(&$entry, $po_comment_line) {
+ $first_two = substr($po_comment_line, 0, 2);
+ $comment = trim(substr($po_comment_line, 2));
+ if ('#:' == $first_two) {
+ $entry->references = array_merge($entry->references, preg_split('/\s+/', $comment));
+ } elseif ('#.' == $first_two) {
+ $entry->extracted_comments = trim($entry->extracted_comments . "\n" . $comment);
+ } elseif ('#,' == $first_two) {
+ $entry->flags = array_merge($entry->flags, preg_split('/,\s*/', $comment));
+ } else {
+ $entry->translator_comments = trim($entry->translator_comments . "\n" . $comment);
+ }
+ }
+
+ function trim_quotes($s) {
+ if ( substr($s, 0, 1) == '"') $s = substr($s, 1);
+ if ( substr($s, -1, 1) == '"') $s = substr($s, 0, -1);
+ return $s;
+ }
+}
+endif;
diff --git a/src/wp-includes/pomo/streams.php b/src/wp-includes/pomo/streams.php
new file mode 100644
index 0000000000..dbb1de809d
--- /dev/null
+++ b/src/wp-includes/pomo/streams.php
@@ -0,0 +1,209 @@
+<?php
+/**
+ * Classes, which help reading streams of data from files.
+ * Based on the classes from Danilo Segan <danilo@kvota.net>
+ *
+ * @version $Id: streams.php 718 2012-10-31 00:32:02Z nbachiyski $
+ * @package pomo
+ * @subpackage streams
+ */
+
+if ( !class_exists( 'POMO_Reader' ) ):
+class POMO_Reader {
+
+ var $endian = 'little';
+ var $_post = '';
+
+ function POMO_Reader() {
+ $this->is_overloaded = ((ini_get("mbstring.func_overload") & 2) != 0) && function_exists('mb_substr');
+ $this->_pos = 0;
+ }
+
+ /**
+ * Sets the endianness of the file.
+ *
+ * @param $endian string 'big' or 'little'
+ */
+ function setEndian($endian) {
+ $this->endian = $endian;
+ }
+
+ /**
+ * Reads a 32bit Integer from the Stream
+ *
+ * @return mixed The integer, corresponding to the next 32 bits from
+ * the stream of false if there are not enough bytes or on error
+ */
+ function readint32() {
+ $bytes = $this->read(4);
+ if (4 != $this->strlen($bytes))
+ return false;
+ $endian_letter = ('big' == $this->endian)? 'N' : 'V';
+ $int = unpack($endian_letter, $bytes);
+ return array_shift($int);
+ }
+
+ /**
+ * Reads an array of 32-bit Integers from the Stream
+ *
+ * @param integer count How many elements should be read
+ * @return mixed Array of integers or false if there isn't
+ * enough data or on error
+ */
+ function readint32array($count) {
+ $bytes = $this->read(4 * $count);
+ if (4*$count != $this->strlen($bytes))
+ return false;
+ $endian_letter = ('big' == $this->endian)? 'N' : 'V';
+ return unpack($endian_letter.$count, $bytes);
+ }
+
+
+ function substr($string, $start, $length) {
+ if ($this->is_overloaded) {
+ return mb_substr($string, $start, $length, 'ascii');
+ } else {
+ return substr($string, $start, $length);
+ }
+ }
+
+ function strlen($string) {
+ if ($this->is_overloaded) {
+ return mb_strlen($string, 'ascii');
+ } else {
+ return strlen($string);
+ }
+ }
+
+ function str_split($string, $chunk_size) {
+ if (!function_exists('str_split')) {
+ $length = $this->strlen($string);
+ $out = array();
+ for ($i = 0; $i < $length; $i += $chunk_size)
+ $out[] = $this->substr($string, $i, $chunk_size);
+ return $out;
+ } else {
+ return str_split( $string, $chunk_size );
+ }
+ }
+
+
+ function pos() {
+ return $this->_pos;
+ }
+
+ function is_resource() {
+ return true;
+ }
+
+ function close() {
+ return true;
+ }
+}
+endif;
+
+if ( !class_exists( 'POMO_FileReader' ) ):
+class POMO_FileReader extends POMO_Reader {
+ function POMO_FileReader($filename) {
+ parent::POMO_Reader();
+ $this->_f = fopen($filename, 'rb');
+ }
+
+ function read($bytes) {
+ return fread($this->_f, $bytes);
+ }
+
+ function seekto($pos) {
+ if ( -1 == fseek($this->_f, $pos, SEEK_SET)) {
+ return false;
+ }
+ $this->_pos = $pos;
+ return true;
+ }
+
+ function is_resource() {
+ return is_resource($this->_f);
+ }
+
+ function feof() {
+ return feof($this->_f);
+ }
+
+ function close() {
+ return fclose($this->_f);
+ }
+
+ function read_all() {
+ $all = '';
+ while ( !$this->feof() )
+ $all .= $this->read(4096);
+ return $all;
+ }
+}
+endif;
+
+if ( !class_exists( 'POMO_StringReader' ) ):
+/**
+ * Provides file-like methods for manipulating a string instead
+ * of a physical file.
+ */
+class POMO_StringReader extends POMO_Reader {
+
+ var $_str = '';
+
+ function POMO_StringReader($str = '') {
+ parent::POMO_Reader();
+ $this->_str = $str;
+ $this->_pos = 0;
+ }
+
+
+ function read($bytes) {
+ $data = $this->substr($this->_str, $this->_pos, $bytes);
+ $this->_pos += $bytes;
+ if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
+ return $data;
+ }
+
+ function seekto($pos) {
+ $this->_pos = $pos;
+ if ($this->strlen($this->_str) < $this->_pos) $this->_pos = $this->strlen($this->_str);
+ return $this->_pos;
+ }
+
+ function length() {
+ return $this->strlen($this->_str);
+ }
+
+ function read_all() {
+ return $this->substr($this->_str, $this->_pos, $this->strlen($this->_str));
+ }
+
+}
+endif;
+
+if ( !class_exists( 'POMO_CachedFileReader' ) ):
+/**
+ * Reads the contents of the file in the beginning.
+ */
+class POMO_CachedFileReader extends POMO_StringReader {
+ function POMO_CachedFileReader($filename) {
+ parent::POMO_StringReader();
+ $this->_str = file_get_contents($filename);
+ if (false === $this->_str)
+ return false;
+ $this->_pos = 0;
+ }
+}
+endif;
+
+if ( !class_exists( 'POMO_CachedIntFileReader' ) ):
+/**
+ * Reads the contents of the file in the beginning.
+ */
+class POMO_CachedIntFileReader extends POMO_CachedFileReader {
+ function POMO_CachedIntFileReader($filename) {
+ parent::POMO_CachedFileReader($filename);
+ }
+}
+endif; \ No newline at end of file
diff --git a/src/wp-includes/pomo/translations.php b/src/wp-includes/pomo/translations.php
new file mode 100644
index 0000000000..106b6da164
--- /dev/null
+++ b/src/wp-includes/pomo/translations.php
@@ -0,0 +1,275 @@
+<?php
+/**
+ * Class for a set of entries for translation and their associated headers
+ *
+ * @version $Id: translations.php 718 2012-10-31 00:32:02Z nbachiyski $
+ * @package pomo
+ * @subpackage translations
+ */
+
+require_once dirname(__FILE__) . '/entry.php';
+
+if ( !class_exists( 'Translations' ) ):
+class Translations {
+ var $entries = array();
+ var $headers = array();
+
+ /**
+ * Add entry to the PO structure
+ *
+ * @param object &$entry
+ * @return bool true on success, false if the entry doesn't have a key
+ */
+ function add_entry($entry) {
+ if (is_array($entry)) {
+ $entry = new Translation_Entry($entry);
+ }
+ $key = $entry->key();
+ if (false === $key) return false;
+ $this->entries[$key] = &$entry;
+ return true;
+ }
+
+ function add_entry_or_merge($entry) {
+ if (is_array($entry)) {
+ $entry = new Translation_Entry($entry);
+ }
+ $key = $entry->key();
+ if (false === $key) return false;
+ if (isset($this->entries[$key]))
+ $this->entries[$key]->merge_with($entry);
+ else
+ $this->entries[$key] = &$entry;
+ return true;
+ }
+
+ /**
+ * Sets $header PO header to $value
+ *
+ * If the header already exists, it will be overwritten
+ *
+ * TODO: this should be out of this class, it is gettext specific
+ *
+ * @param string $header header name, without trailing :
+ * @param string $value header value, without trailing \n
+ */
+ function set_header($header, $value) {
+ $this->headers[$header] = $value;
+ }
+
+ function set_headers($headers) {
+ foreach($headers as $header => $value) {
+ $this->set_header($header, $value);
+ }
+ }
+
+ function get_header($header) {
+ return isset($this->headers[$header])? $this->headers[$header] : false;
+ }
+
+ function translate_entry(&$entry) {
+ $key = $entry->key();
+ return isset($this->entries[$key])? $this->entries[$key] : false;
+ }
+
+ function translate($singular, $context=null) {
+ $entry = new Translation_Entry(array('singular' => $singular, 'context' => $context));
+ $translated = $this->translate_entry($entry);
+ return ($translated && !empty($translated->translations))? $translated->translations[0] : $singular;
+ }
+
+ /**
+ * Given the number of items, returns the 0-based index of the plural form to use
+ *
+ * Here, in the base Translations class, the common logic for English is implemented:
+ * 0 if there is one element, 1 otherwise
+ *
+ * This function should be overrided by the sub-classes. For example MO/PO can derive the logic
+ * from their headers.
+ *
+ * @param integer $count number of items
+ */
+ function select_plural_form($count) {
+ return 1 == $count? 0 : 1;
+ }
+
+ function get_plural_forms_count() {
+ return 2;
+ }
+
+ function translate_plural($singular, $plural, $count, $context = null) {
+ $entry = new Translation_Entry(array('singular' => $singular, 'plural' => $plural, 'context' => $context));
+ $translated = $this->translate_entry($entry);
+ $index = $this->select_plural_form($count);
+ $total_plural_forms = $this->get_plural_forms_count();
+ if ($translated && 0 <= $index && $index < $total_plural_forms &&
+ is_array($translated->translations) &&
+ isset($translated->translations[$index]))
+ return $translated->translations[$index];
+ else
+ return 1 == $count? $singular : $plural;
+ }
+
+ /**
+ * Merge $other in the current object.
+ *
+ * @param Object &$other Another Translation object, whose translations will be merged in this one
+ * @return void
+ **/
+ function merge_with(&$other) {
+ foreach( $other->entries as $entry ) {
+ $this->entries[$entry->key()] = $entry;
+ }
+ }
+
+ function merge_originals_with(&$other) {
+ foreach( $other->entries as $entry ) {
+ if ( !isset( $this->entries[$entry->key()] ) )
+ $this->entries[$entry->key()] = $entry;
+ else
+ $this->entries[$entry->key()]->merge_with($entry);
+ }
+ }
+}
+
+class Gettext_Translations extends Translations {
+ /**
+ * The gettext implementation of select_plural_form.
+ *
+ * It lives in this class, because there are more than one descendand, which will use it and
+ * they can't share it effectively.
+ *
+ */
+ function gettext_select_plural_form($count) {
+ if (!isset($this->_gettext_select_plural_form) || is_null($this->_gettext_select_plural_form)) {
+ list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
+ $this->_nplurals = $nplurals;
+ $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
+ }
+ return call_user_func($this->_gettext_select_plural_form, $count);
+ }
+
+ function nplurals_and_expression_from_header($header) {
+ if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches)) {
+ $nplurals = (int)$matches[1];
+ $expression = trim($this->parenthesize_plural_exression($matches[2]));
+ return array($nplurals, $expression);
+ } else {
+ return array(2, 'n != 1');
+ }
+ }
+
+ /**
+ * Makes a function, which will return the right translation index, according to the
+ * plural forms header
+ */
+ function make_plural_form_function($nplurals, $expression) {
+ $expression = str_replace('n', '$n', $expression);
+ $func_body = "
+ \$index = (int)($expression);
+ return (\$index < $nplurals)? \$index : $nplurals - 1;";
+ return create_function('$n', $func_body);
+ }
+
+ /**
+ * Adds parantheses to the inner parts of ternary operators in
+ * plural expressions, because PHP evaluates ternary oerators from left to right
+ *
+ * @param string $expression the expression without parentheses
+ * @return string the expression with parentheses added
+ */
+ function parenthesize_plural_exression($expression) {
+ $expression .= ';';
+ $res = '';
+ $depth = 0;
+ for ($i = 0; $i < strlen($expression); ++$i) {
+ $char = $expression[$i];
+ switch ($char) {
+ case '?':
+ $res .= ' ? (';
+ $depth++;
+ break;
+ case ':':
+ $res .= ') : (';
+ break;
+ case ';':
+ $res .= str_repeat(')', $depth) . ';';
+ $depth= 0;
+ break;
+ default:
+ $res .= $char;
+ }
+ }
+ return rtrim($res, ';');
+ }
+
+ function make_headers($translation) {
+ $headers = array();
+ // sometimes \ns are used instead of real new lines
+ $translation = str_replace('\n', "\n", $translation);
+ $lines = explode("\n", $translation);
+ foreach($lines as $line) {
+ $parts = explode(':', $line, 2);
+ if (!isset($parts[1])) continue;
+ $headers[trim($parts[0])] = trim($parts[1]);
+ }
+ return $headers;
+ }
+
+ function set_header($header, $value) {
+ parent::set_header($header, $value);
+ if ('Plural-Forms' == $header) {
+ list( $nplurals, $expression ) = $this->nplurals_and_expression_from_header($this->get_header('Plural-Forms'));
+ $this->_nplurals = $nplurals;
+ $this->_gettext_select_plural_form = $this->make_plural_form_function($nplurals, $expression);
+ }
+ }
+}
+endif;
+
+if ( !class_exists( 'NOOP_Translations' ) ):
+/**
+ * Provides the same interface as Translations, but doesn't do anything
+ */
+class NOOP_Translations {
+ var $entries = array();
+ var $headers = array();
+
+ function add_entry($entry) {
+ return true;
+ }
+
+ function set_header($header, $value) {
+ }
+
+ function set_headers($headers) {
+ }
+
+ function get_header($header) {
+ return false;
+ }
+
+ function translate_entry(&$entry) {
+ return false;
+ }
+
+ function translate($singular, $context=null) {
+ return $singular;
+ }
+
+ function select_plural_form($count) {
+ return 1 == $count? 0 : 1;
+ }
+
+ function get_plural_forms_count() {
+ return 2;
+ }
+
+ function translate_plural($singular, $plural, $count, $context = null) {
+ return 1 == $count? $singular : $plural;
+ }
+
+ function merge_with(&$other) {
+ }
+}
+endif;
diff --git a/src/wp-includes/post-formats.php b/src/wp-includes/post-formats.php
new file mode 100644
index 0000000000..a13de3eaa6
--- /dev/null
+++ b/src/wp-includes/post-formats.php
@@ -0,0 +1,243 @@
+<?php
+/**
+ * Post format functions.
+ *
+ * @package WordPress
+ * @subpackage Post
+ */
+
+/**
+ * Retrieve the format slug for a post
+ *
+ * @since 3.1.0
+ *
+ * @param int|object $post Post ID or post object. Optional, default is the current post from the loop.
+ * @return mixed The format if successful. False otherwise.
+ */
+function get_post_format( $post = null ) {
+ if ( ! $post = get_post( $post ) )
+ return false;
+
+ if ( ! post_type_supports( $post->post_type, 'post-formats' ) )
+ return false;
+
+ $_format = get_the_terms( $post->ID, 'post_format' );
+
+ if ( empty( $_format ) )
+ return false;
+
+ $format = array_shift( $_format );
+
+ return str_replace('post-format-', '', $format->slug );
+}
+
+/**
+ * Check if a post has a particular format
+ *
+ * @since 3.1.0
+ *
+ * @uses has_term()
+ *
+ * @param string|array $format The format or formats to check.
+ * @param object|int $post The post to check. If not supplied, defaults to the current post if used in the loop.
+ * @return bool True if the post has the format, false otherwise.
+ */
+function has_post_format( $format, $post = null ) {
+ if ( ! is_array( $format ) )
+ $format = array( $format );
+
+ $prefixed = array();
+ foreach( $format as $single ) {
+ $prefixed[] = 'post-format-' . sanitize_key( $single );
+ }
+
+ return has_term( $prefixed, 'post_format', $post );
+}
+
+/**
+ * Assign a format to a post
+ *
+ * @since 3.1.0
+ *
+ * @param int|object $post The post for which to assign a format.
+ * @param string $format A format to assign. Use an empty string or array to remove all formats from the post.
+ * @return mixed WP_Error on error. Array of affected term IDs on success.
+ */
+function set_post_format( $post, $format ) {
+ $post = get_post( $post );
+
+ if ( empty( $post ) )
+ return new WP_Error( 'invalid_post', __( 'Invalid post' ) );
+
+ if ( ! empty( $format ) ) {
+ $format = sanitize_key( $format );
+ if ( 'standard' === $format || ! in_array( $format, get_post_format_slugs() ) )
+ $format = '';
+ else
+ $format = 'post-format-' . $format;
+ }
+
+ return wp_set_post_terms( $post->ID, $format, 'post_format' );
+}
+
+/**
+ * Returns an array of post format slugs to their translated and pretty display versions
+ *
+ * @since 3.1.0
+ *
+ * @return array The array of translated post format names.
+ */
+function get_post_format_strings() {
+ $strings = array(
+ 'standard' => _x( 'Standard', 'Post format' ), // Special case. any value that evals to false will be considered standard
+ 'aside' => _x( 'Aside', 'Post format' ),
+ 'chat' => _x( 'Chat', 'Post format' ),
+ 'gallery' => _x( 'Gallery', 'Post format' ),
+ 'link' => _x( 'Link', 'Post format' ),
+ 'image' => _x( 'Image', 'Post format' ),
+ 'quote' => _x( 'Quote', 'Post format' ),
+ 'status' => _x( 'Status', 'Post format' ),
+ 'video' => _x( 'Video', 'Post format' ),
+ 'audio' => _x( 'Audio', 'Post format' ),
+ );
+ return $strings;
+}
+
+/**
+ * Retrieves an array of post format slugs.
+ *
+ * @since 3.1.0
+ *
+ * @uses get_post_format_strings()
+ *
+ * @return array The array of post format slugs.
+ */
+function get_post_format_slugs() {
+ $slugs = array_keys( get_post_format_strings() );
+ return array_combine( $slugs, $slugs );
+}
+
+/**
+ * Returns a pretty, translated version of a post format slug
+ *
+ * @since 3.1.0
+ *
+ * @uses get_post_format_strings()
+ *
+ * @param string $slug A post format slug.
+ * @return string The translated post format name.
+ */
+function get_post_format_string( $slug ) {
+ $strings = get_post_format_strings();
+ if ( !$slug )
+ return $strings['standard'];
+ else
+ return ( isset( $strings[$slug] ) ) ? $strings[$slug] : '';
+}
+
+/**
+ * Returns a link to a post format index.
+ *
+ * @since 3.1.0
+ *
+ * @param string $format The post format slug.
+ * @return string The post format term link.
+ */
+function get_post_format_link( $format ) {
+ $term = get_term_by('slug', 'post-format-' . $format, 'post_format' );
+ if ( ! $term || is_wp_error( $term ) )
+ return false;
+ return get_term_link( $term );
+}
+
+/**
+ * Filters the request to allow for the format prefix.
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _post_format_request( $qvs ) {
+ if ( ! isset( $qvs['post_format'] ) )
+ return $qvs;
+ $slugs = get_post_format_slugs();
+ if ( isset( $slugs[ $qvs['post_format'] ] ) )
+ $qvs['post_format'] = 'post-format-' . $slugs[ $qvs['post_format'] ];
+ $tax = get_taxonomy( 'post_format' );
+ if ( ! is_admin() )
+ $qvs['post_type'] = $tax->object_type;
+ return $qvs;
+}
+add_filter( 'request', '_post_format_request' );
+
+/**
+ * Filters the post format term link to remove the format prefix.
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _post_format_link( $link, $term, $taxonomy ) {
+ global $wp_rewrite;
+ if ( 'post_format' != $taxonomy )
+ return $link;
+ if ( $wp_rewrite->get_extra_permastruct( $taxonomy ) ) {
+ return str_replace( "/{$term->slug}", '/' . str_replace( 'post-format-', '', $term->slug ), $link );
+ } else {
+ $link = remove_query_arg( 'post_format', $link );
+ return add_query_arg( 'post_format', str_replace( 'post-format-', '', $term->slug ), $link );
+ }
+}
+add_filter( 'term_link', '_post_format_link', 10, 3 );
+
+/**
+ * Remove the post format prefix from the name property of the term object created by get_term().
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _post_format_get_term( $term ) {
+ if ( isset( $term->slug ) ) {
+ $term->name = get_post_format_string( str_replace( 'post-format-', '', $term->slug ) );
+ }
+ return $term;
+}
+add_filter( 'get_post_format', '_post_format_get_term' );
+
+/**
+ * Remove the post format prefix from the name property of the term objects created by get_terms().
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _post_format_get_terms( $terms, $taxonomies, $args ) {
+ if ( in_array( 'post_format', (array) $taxonomies ) ) {
+ if ( isset( $args['fields'] ) && 'names' == $args['fields'] ) {
+ foreach( $terms as $order => $name ) {
+ $terms[$order] = get_post_format_string( str_replace( 'post-format-', '', $name ) );
+ }
+ } else {
+ foreach ( (array) $terms as $order => $term ) {
+ if ( isset( $term->taxonomy ) && 'post_format' == $term->taxonomy ) {
+ $terms[$order]->name = get_post_format_string( str_replace( 'post-format-', '', $term->slug ) );
+ }
+ }
+ }
+ }
+ return $terms;
+}
+add_filter( 'get_terms', '_post_format_get_terms', 10, 3 );
+
+/**
+ * Remove the post format prefix from the name property of the term objects created by wp_get_object_terms().
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _post_format_wp_get_object_terms( $terms ) {
+ foreach ( (array) $terms as $order => $term ) {
+ if ( isset( $term->taxonomy ) && 'post_format' == $term->taxonomy ) {
+ $terms[$order]->name = get_post_format_string( str_replace( 'post-format-', '', $term->slug ) );
+ }
+ }
+ return $terms;
+}
+add_filter( 'wp_get_object_terms', '_post_format_wp_get_object_terms' );
diff --git a/src/wp-includes/post-template.php b/src/wp-includes/post-template.php
new file mode 100644
index 0000000000..06d259e157
--- /dev/null
+++ b/src/wp-includes/post-template.php
@@ -0,0 +1,1458 @@
+<?php
+/**
+ * WordPress Post Template Functions.
+ *
+ * Gets content for the current post in the loop.
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Display the ID of the current item in the WordPress Loop.
+ *
+ * @since 0.71
+ */
+function the_ID() {
+ echo get_the_ID();
+}
+
+/**
+ * Retrieve the ID of the current item in the WordPress Loop.
+ *
+ * @since 2.1.0
+ * @uses $post
+ *
+ * @return int
+ */
+function get_the_ID() {
+ return get_post()->ID;
+}
+
+/**
+ * Display or retrieve the current post title with optional content.
+ *
+ * @since 0.71
+ *
+ * @param string $before Optional. Content to prepend to the title.
+ * @param string $after Optional. Content to append to the title.
+ * @param bool $echo Optional, default to true.Whether to display or return.
+ * @return null|string Null on no title. String if $echo parameter is false.
+ */
+function the_title($before = '', $after = '', $echo = true) {
+ $title = get_the_title();
+
+ if ( strlen($title) == 0 )
+ return;
+
+ $title = $before . $title . $after;
+
+ if ( $echo )
+ echo $title;
+ else
+ return $title;
+}
+
+/**
+ * Sanitize the current title when retrieving or displaying.
+ *
+ * Works like {@link the_title()}, except the parameters can be in a string or
+ * an array. See the function for what can be override in the $args parameter.
+ *
+ * The title before it is displayed will have the tags stripped and {@link
+ * esc_attr()} before it is passed to the user or displayed. The default
+ * as with {@link the_title()}, is to display the title.
+ *
+ * @since 2.3.0
+ *
+ * @param string|array $args Optional. Override the defaults.
+ * @return string|null Null on failure or display. String when echo is false.
+ */
+function the_title_attribute( $args = '' ) {
+ $defaults = array('before' => '', 'after' => '', 'echo' => true, 'post' => get_post() );
+ $r = wp_parse_args($args, $defaults);
+ extract( $r, EXTR_SKIP );
+
+ $title = get_the_title( $post );
+
+ if ( strlen($title) == 0 )
+ return;
+
+ $title = $before . $title . $after;
+ $title = esc_attr(strip_tags($title));
+
+ if ( $echo )
+ echo $title;
+ else
+ return $title;
+}
+
+/**
+ * Retrieve post title.
+ *
+ * If the post is protected and the visitor is not an admin, then "Protected"
+ * will be displayed before the post title. If the post is private, then
+ * "Private" will be located before the post title.
+ *
+ * @since 0.71
+ *
+ * @param int|object $post Optional. Post ID or object.
+ * @return string
+ */
+function get_the_title( $post = 0 ) {
+ $post = get_post( $post );
+
+ $title = isset( $post->post_title ) ? $post->post_title : '';
+ $id = isset( $post->ID ) ? $post->ID : 0;
+
+ if ( ! is_admin() ) {
+ if ( ! empty( $post->post_password ) ) {
+ $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s' ) );
+ $title = sprintf( $protected_title_format, $title );
+ } else if ( isset( $post->post_status ) && 'private' == $post->post_status ) {
+ $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s' ) );
+ $title = sprintf( $private_title_format, $title );
+ }
+ }
+
+ return apply_filters( 'the_title', $title, $id );
+}
+
+/**
+ * Display the Post Global Unique Identifier (guid).
+ *
+ * The guid will appear to be a link, but should not be used as an link to the
+ * post. The reason you should not use it as a link, is because of moving the
+ * blog across domains.
+ *
+ * Url is escaped to make it xml safe
+ *
+ * @since 1.5.0
+ *
+ * @param int $id Optional. Post ID.
+ */
+function the_guid( $id = 0 ) {
+ echo esc_url( get_the_guid( $id ) );
+}
+
+/**
+ * Retrieve the Post Global Unique Identifier (guid).
+ *
+ * The guid will appear to be a link, but should not be used as an link to the
+ * post. The reason you should not use it as a link, is because of moving the
+ * blog across domains.
+ *
+ * @since 1.5.0
+ *
+ * @param int $id Optional. Post ID.
+ * @return string
+ */
+function get_the_guid( $id = 0 ) {
+ $post = get_post($id);
+
+ return apply_filters('get_the_guid', $post->guid);
+}
+
+/**
+ * Display the post content.
+ *
+ * @since 0.71
+ *
+ * @param string $more_link_text Optional. Content for when there is more text.
+ * @param bool $strip_teaser Optional. Strip teaser content before the more text. Default is false.
+ */
+function the_content( $more_link_text = null, $strip_teaser = false) {
+ $content = get_the_content( $more_link_text, $strip_teaser );
+ $content = apply_filters( 'the_content', $content );
+ $content = str_replace( ']]>', ']]&gt;', $content );
+ echo $content;
+}
+
+/**
+ * Retrieve the post content.
+ *
+ * @since 0.71
+ *
+ * @param string $more_link_text Optional. Content for when there is more text.
+ * @param bool $stripteaser Optional. Strip teaser content before the more text. Default is false.
+ * @return string
+ */
+function get_the_content( $more_link_text = null, $strip_teaser = false ) {
+ global $page, $more, $preview, $pages, $multipage;
+
+ $post = get_post();
+
+ if ( null === $more_link_text )
+ $more_link_text = __( '(more&hellip;)' );
+
+ $output = '';
+ $has_teaser = false;
+
+ // If post password required and it doesn't match the cookie.
+ if ( post_password_required( $post ) )
+ return get_the_password_form( $post );
+
+ if ( $page > count( $pages ) ) // if the requested page doesn't exist
+ $page = count( $pages ); // give them the highest numbered page that DOES exist
+
+ $content = $pages[$page - 1];
+ if ( preg_match( '/<!--more(.*?)?-->/', $content, $matches ) ) {
+ $content = explode( $matches[0], $content, 2 );
+ if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) )
+ $more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) );
+
+ $has_teaser = true;
+ } else {
+ $content = array( $content );
+ }
+
+ if ( false !== strpos( $post->post_content, '<!--noteaser-->' ) && ( ! $multipage || $page == 1 ) )
+ $strip_teaser = true;
+
+ $teaser = $content[0];
+
+ if ( $more && $strip_teaser && $has_teaser )
+ $teaser = '';
+
+ $output .= $teaser;
+
+ if ( count( $content ) > 1 ) {
+ if ( $more ) {
+ $output .= '<span id="more-' . $post->ID . '"></span>' . $content[1];
+ } else {
+ if ( ! empty( $more_link_text ) )
+ $output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink() . "#more-{$post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text );
+ $output = force_balance_tags( $output );
+ }
+ }
+
+ if ( $preview ) // preview fix for javascript bug with foreign languages
+ $output = preg_replace_callback( '/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output );
+
+ return $output;
+}
+
+/**
+ * Preview fix for javascript bug with foreign languages
+ *
+ * @since 3.1.0
+ * @access private
+ * @param array $match Match array from preg_replace_callback
+ * @return string
+ */
+function _convert_urlencoded_to_entities( $match ) {
+ return '&#' . base_convert( $match[1], 16, 10 ) . ';';
+}
+
+/**
+ * Display the post excerpt.
+ *
+ * @since 0.71
+ * @uses apply_filters() Calls 'the_excerpt' hook on post excerpt.
+ */
+function the_excerpt() {
+ echo apply_filters('the_excerpt', get_the_excerpt());
+}
+
+/**
+ * Retrieve the post excerpt.
+ *
+ * @since 0.71
+ *
+ * @param mixed $deprecated Not used.
+ * @return string
+ */
+function get_the_excerpt( $deprecated = '' ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.3' );
+
+ $post = get_post();
+
+ if ( post_password_required() ) {
+ return __( 'There is no excerpt because this is a protected post.' );
+ }
+
+ return apply_filters( 'get_the_excerpt', $post->post_excerpt );
+}
+
+/**
+ * Whether post has excerpt.
+ *
+ * @since 2.3.0
+ *
+ * @param int $id Optional. Post ID.
+ * @return bool
+ */
+function has_excerpt( $id = 0 ) {
+ $post = get_post( $id );
+ return ( !empty( $post->post_excerpt ) );
+}
+
+/**
+ * Display the classes for the post div.
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $class One or more classes to add to the class list.
+ * @param int $post_id An optional post ID.
+ */
+function post_class( $class = '', $post_id = null ) {
+ // Separates classes with a single space, collates classes for post DIV
+ echo 'class="' . join( ' ', get_post_class( $class, $post_id ) ) . '"';
+}
+
+/**
+ * Retrieve the classes for the post div as an array.
+ *
+ * The class names are add are many. If the post is a sticky, then the 'sticky'
+ * class name. The class 'hentry' is always added to each post. For each
+ * category, the class will be added with 'category-' with category slug is
+ * added. The tags are the same way as the categories with 'tag-' before the tag
+ * slug. All classes are passed through the filter, 'post_class' with the list
+ * of classes, followed by $class parameter value, with the post ID as the last
+ * parameter.
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $class One or more classes to add to the class list.
+ * @param int $post_id An optional post ID.
+ * @return array Array of classes.
+ */
+function get_post_class( $class = '', $post_id = null ) {
+ $post = get_post($post_id);
+
+ $classes = array();
+
+ if ( empty($post) )
+ return $classes;
+
+ $classes[] = 'post-' . $post->ID;
+ if ( ! is_admin() )
+ $classes[] = $post->post_type;
+ $classes[] = 'type-' . $post->post_type;
+ $classes[] = 'status-' . $post->post_status;
+
+ // Post Format
+ if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
+ $post_format = get_post_format( $post->ID );
+
+ if ( $post_format && !is_wp_error($post_format) )
+ $classes[] = 'format-' . sanitize_html_class( $post_format );
+ else
+ $classes[] = 'format-standard';
+ }
+
+ // post requires password
+ if ( post_password_required($post->ID) )
+ $classes[] = 'post-password-required';
+
+ // sticky for Sticky Posts
+ if ( is_sticky($post->ID) && is_home() && !is_paged() )
+ $classes[] = 'sticky';
+
+ // hentry for hAtom compliance
+ $classes[] = 'hentry';
+
+ // Categories
+ if ( is_object_in_taxonomy( $post->post_type, 'category' ) ) {
+ foreach ( (array) get_the_category($post->ID) as $cat ) {
+ if ( empty($cat->slug ) )
+ continue;
+ $classes[] = 'category-' . sanitize_html_class($cat->slug, $cat->term_id);
+ }
+ }
+
+ // Tags
+ if ( is_object_in_taxonomy( $post->post_type, 'post_tag' ) ) {
+ foreach ( (array) get_the_tags($post->ID) as $tag ) {
+ if ( empty($tag->slug ) )
+ continue;
+ $classes[] = 'tag-' . sanitize_html_class($tag->slug, $tag->term_id);
+ }
+ }
+
+ if ( !empty($class) ) {
+ if ( !is_array( $class ) )
+ $class = preg_split('#\s+#', $class);
+ $classes = array_merge($classes, $class);
+ }
+
+ $classes = array_map('esc_attr', $classes);
+
+ return apply_filters('post_class', $classes, $class, $post->ID);
+}
+
+/**
+ * Display the classes for the body element.
+ *
+ * @since 2.8.0
+ *
+ * @param string|array $class One or more classes to add to the class list.
+ */
+function body_class( $class = '' ) {
+ // Separates classes with a single space, collates classes for body element
+ echo 'class="' . join( ' ', get_body_class( $class ) ) . '"';
+}
+
+/**
+ * Retrieve the classes for the body element as an array.
+ *
+ * @since 2.8.0
+ *
+ * @param string|array $class One or more classes to add to the class list.
+ * @return array Array of classes.
+ */
+function get_body_class( $class = '' ) {
+ global $wp_query, $wpdb;
+
+ $classes = array();
+
+ if ( is_rtl() )
+ $classes[] = 'rtl';
+
+ if ( is_front_page() )
+ $classes[] = 'home';
+ if ( is_home() )
+ $classes[] = 'blog';
+ if ( is_archive() )
+ $classes[] = 'archive';
+ if ( is_date() )
+ $classes[] = 'date';
+ if ( is_search() ) {
+ $classes[] = 'search';
+ $classes[] = $wp_query->posts ? 'search-results' : 'search-no-results';
+ }
+ if ( is_paged() )
+ $classes[] = 'paged';
+ if ( is_attachment() )
+ $classes[] = 'attachment';
+ if ( is_404() )
+ $classes[] = 'error404';
+
+ if ( is_single() ) {
+ $post_id = $wp_query->get_queried_object_id();
+ $post = $wp_query->get_queried_object();
+
+ $classes[] = 'single';
+ if ( isset( $post->post_type ) ) {
+ $classes[] = 'single-' . sanitize_html_class($post->post_type, $post_id);
+ $classes[] = 'postid-' . $post_id;
+
+ // Post Format
+ if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
+ $post_format = get_post_format( $post->ID );
+
+ if ( $post_format && !is_wp_error($post_format) )
+ $classes[] = 'single-format-' . sanitize_html_class( $post_format );
+ else
+ $classes[] = 'single-format-standard';
+ }
+ }
+
+ if ( is_attachment() ) {
+ $mime_type = get_post_mime_type($post_id);
+ $mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' );
+ $classes[] = 'attachmentid-' . $post_id;
+ $classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type );
+ }
+ } elseif ( is_archive() ) {
+ if ( is_post_type_archive() ) {
+ $classes[] = 'post-type-archive';
+ $classes[] = 'post-type-archive-' . sanitize_html_class( get_query_var( 'post_type' ) );
+ } else if ( is_author() ) {
+ $author = $wp_query->get_queried_object();
+ $classes[] = 'author';
+ if ( isset( $author->user_nicename ) ) {
+ $classes[] = 'author-' . sanitize_html_class( $author->user_nicename, $author->ID );
+ $classes[] = 'author-' . $author->ID;
+ }
+ } elseif ( is_category() ) {
+ $cat = $wp_query->get_queried_object();
+ $classes[] = 'category';
+ if ( isset( $cat->term_id ) ) {
+ $classes[] = 'category-' . sanitize_html_class( $cat->slug, $cat->term_id );
+ $classes[] = 'category-' . $cat->term_id;
+ }
+ } elseif ( is_tag() ) {
+ $tags = $wp_query->get_queried_object();
+ $classes[] = 'tag';
+ if ( isset( $tags->term_id ) ) {
+ $classes[] = 'tag-' . sanitize_html_class( $tags->slug, $tags->term_id );
+ $classes[] = 'tag-' . $tags->term_id;
+ }
+ } elseif ( is_tax() ) {
+ $term = $wp_query->get_queried_object();
+ if ( isset( $term->term_id ) ) {
+ $classes[] = 'tax-' . sanitize_html_class( $term->taxonomy );
+ $classes[] = 'term-' . sanitize_html_class( $term->slug, $term->term_id );
+ $classes[] = 'term-' . $term->term_id;
+ }
+ }
+ } elseif ( is_page() ) {
+ $classes[] = 'page';
+
+ $page_id = $wp_query->get_queried_object_id();
+
+ $post = get_post($page_id);
+
+ $classes[] = 'page-id-' . $page_id;
+
+ if ( $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'page' AND post_status = 'publish' LIMIT 1", $page_id) ) )
+ $classes[] = 'page-parent';
+
+ if ( $post->post_parent ) {
+ $classes[] = 'page-child';
+ $classes[] = 'parent-pageid-' . $post->post_parent;
+ }
+ if ( is_page_template() ) {
+ $classes[] = 'page-template';
+ $classes[] = 'page-template-' . sanitize_html_class( str_replace( '.', '-', get_page_template_slug( $page_id ) ) );
+ } else {
+ $classes[] = 'page-template-default';
+ }
+ }
+
+ if ( is_user_logged_in() )
+ $classes[] = 'logged-in';
+
+ if ( is_admin_bar_showing() ) {
+ $classes[] = 'admin-bar';
+ $classes[] = 'no-customize-support';
+ }
+
+ if ( get_theme_mod( 'background_color' ) || get_background_image() )
+ $classes[] = 'custom-background';
+
+ $page = $wp_query->get( 'page' );
+
+ if ( !$page || $page < 2)
+ $page = $wp_query->get( 'paged' );
+
+ if ( $page && $page > 1 ) {
+ $classes[] = 'paged-' . $page;
+
+ if ( is_single() )
+ $classes[] = 'single-paged-' . $page;
+ elseif ( is_page() )
+ $classes[] = 'page-paged-' . $page;
+ elseif ( is_category() )
+ $classes[] = 'category-paged-' . $page;
+ elseif ( is_tag() )
+ $classes[] = 'tag-paged-' . $page;
+ elseif ( is_date() )
+ $classes[] = 'date-paged-' . $page;
+ elseif ( is_author() )
+ $classes[] = 'author-paged-' . $page;
+ elseif ( is_search() )
+ $classes[] = 'search-paged-' . $page;
+ elseif ( is_post_type_archive() )
+ $classes[] = 'post-type-paged-' . $page;
+ }
+
+ if ( ! empty( $class ) ) {
+ if ( !is_array( $class ) )
+ $class = preg_split( '#\s+#', $class );
+ $classes = array_merge( $classes, $class );
+ } else {
+ // Ensure that we always coerce class to being an array.
+ $class = array();
+ }
+
+ $classes = array_map( 'esc_attr', $classes );
+
+ return apply_filters( 'body_class', $classes, $class );
+}
+
+/**
+ * Whether post requires password and correct password has been provided.
+ *
+ * @since 2.7.0
+ *
+ * @param int|WP_Post $post An optional post. Global $post used if not provided.
+ * @return bool false if a password is not required or the correct password cookie is present, true otherwise.
+ */
+function post_password_required( $post = null ) {
+ $post = get_post($post);
+
+ if ( empty( $post->post_password ) )
+ return false;
+
+ if ( ! isset( $_COOKIE['wp-postpass_' . COOKIEHASH] ) )
+ return true;
+
+ require_once ABSPATH . 'wp-includes/class-phpass.php';
+ $hasher = new PasswordHash( 8, true );
+
+ $hash = wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] );
+ if ( 0 !== strpos( $hash, '$P$B' ) )
+ return true;
+
+ return ! $hasher->CheckPassword( $post->post_password, $hash );
+}
+
+/**
+ * Page Template Functions for usage in Themes
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * The formatted output of a list of pages.
+ *
+ * Displays page links for paginated posts (i.e. includes the <!--nextpage-->.
+ * Quicktag one or more times). This tag must be within The Loop.
+ *
+ * The defaults for overwriting are:
+ * 'before' - Default is '<p> Pages:' (string). The html or text to prepend to
+ * each bookmarks.
+ * 'after' - Default is '</p>' (string). The html or text to append to each
+ * bookmarks.
+ * 'link_before' - Default is '' (string). The html or text to prepend to each
+ * Pages link inside the <a> tag. Also prepended to the current item, which
+ * is not linked.
+ * 'link_after' - Default is '' (string). The html or text to append to each
+ * Pages link inside the <a> tag. Also appended to the current item, which
+ * is not linked.
+ * 'next_or_number' - Default is 'number' (string). Indicates whether page
+ * numbers should be used. Valid values are number and next.
+ * 'separator' - Default is ' ' (string). Text used between pagination links.
+ * 'nextpagelink' - Default is 'Next Page' (string). Text for link to next page.
+ * of the bookmark.
+ * 'previouspagelink' - Default is 'Previous Page' (string). Text for link to
+ * previous page, if available.
+ * 'pagelink' - Default is '%' (String).Format string for page numbers. The % in
+ * the parameter string will be replaced with the page number, so Page %
+ * generates "Page 1", "Page 2", etc. Defaults to %, just the page number.
+ * 'echo' - Default is 1 (integer). When not 0, this triggers the HTML to be
+ * echoed and then returned.
+ *
+ * @since 1.2.0
+ *
+ * @param string|array $args Optional. Overwrite the defaults.
+ * @return string Formatted output in HTML.
+ */
+function wp_link_pages( $args = '' ) {
+ $defaults = array(
+ 'before' => '<p>' . __( 'Pages:' ),
+ 'after' => '</p>',
+ 'link_before' => '',
+ 'link_after' => '',
+ 'next_or_number' => 'number',
+ 'separator' => ' ',
+ 'nextpagelink' => __( 'Next page' ),
+ 'previouspagelink' => __( 'Previous page' ),
+ 'pagelink' => '%',
+ 'echo' => 1
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ $r = apply_filters( 'wp_link_pages_args', $r );
+ extract( $r, EXTR_SKIP );
+
+ global $page, $numpages, $multipage, $more;
+
+ $output = '';
+ if ( $multipage ) {
+ if ( 'number' == $next_or_number ) {
+ $output .= $before;
+ for ( $i = 1; $i <= $numpages; $i++ ) {
+ $link = $link_before . str_replace( '%', $i, $pagelink ) . $link_after;
+ if ( $i != $page || ! $more && 1 == $page )
+ $link = _wp_link_page( $i ) . $link . '</a>';
+ $link = apply_filters( 'wp_link_pages_link', $link, $i );
+ $output .= $separator . $link;
+ }
+ $output .= $after;
+ } elseif ( $more ) {
+ $output .= $before;
+ $i = $page - 1;
+ if ( $i ) {
+ $link = _wp_link_page( $i ) . $link_before . $previouspagelink . $link_after . '</a>';
+ $link = apply_filters( 'wp_link_pages_link', $link, $i );
+ $output .= $separator . $link;
+ }
+ $i = $page + 1;
+ if ( $i <= $numpages ) {
+ $link = _wp_link_page( $i ) . $link_before . $nextpagelink . $link_after . '</a>';
+ $link = apply_filters( 'wp_link_pages_link', $link, $i );
+ $output .= $separator . $link;
+ }
+ $output .= $after;
+ }
+ }
+
+ $output = apply_filters( 'wp_link_pages', $output, $args );
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+/**
+ * Helper function for wp_link_pages().
+ *
+ * @since 3.1.0
+ * @access private
+ *
+ * @param int $i Page number.
+ * @return string Link.
+ */
+function _wp_link_page( $i ) {
+ global $wp_rewrite;
+ $post = get_post();
+
+ if ( 1 == $i ) {
+ $url = get_permalink();
+ } else {
+ if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
+ $url = add_query_arg( 'page', $i, get_permalink() );
+ elseif ( 'page' == get_option('show_on_front') && get_option('page_on_front') == $post->ID )
+ $url = trailingslashit(get_permalink()) . user_trailingslashit("$wp_rewrite->pagination_base/" . $i, 'single_paged');
+ else
+ $url = trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged');
+ }
+
+ return '<a href="' . esc_url( $url ) . '">';
+}
+
+//
+// Post-meta: Custom per-post fields.
+//
+
+/**
+ * Retrieve post custom meta data field.
+ *
+ * @since 1.5.0
+ *
+ * @param string $key Meta data key name.
+ * @return bool|string|array Array of values or single value, if only one element exists. False will be returned if key does not exist.
+ */
+function post_custom( $key = '' ) {
+ $custom = get_post_custom();
+
+ if ( !isset( $custom[$key] ) )
+ return false;
+ elseif ( 1 == count($custom[$key]) )
+ return $custom[$key][0];
+ else
+ return $custom[$key];
+}
+
+/**
+ * Display list of post custom fields.
+ *
+ * @internal This will probably change at some point...
+ * @since 1.2.0
+ * @uses apply_filters() Calls 'the_meta_key' on list item HTML content, with key and value as separate parameters.
+ */
+function the_meta() {
+ if ( $keys = get_post_custom_keys() ) {
+ echo "<ul class='post-meta'>\n";
+ foreach ( (array) $keys as $key ) {
+ $keyt = trim($key);
+ if ( is_protected_meta( $keyt, 'post' ) )
+ continue;
+ $values = array_map('trim', get_post_custom_values($key));
+ $value = implode($values,', ');
+ echo apply_filters('the_meta_key', "<li><span class='post-meta-key'>$key:</span> $value</li>\n", $key, $value);
+ }
+ echo "</ul>\n";
+ }
+}
+
+//
+// Pages
+//
+
+/**
+ * Retrieve or display list of pages as a dropdown (select list).
+ *
+ * @since 2.1.0
+ *
+ * @param array|string $args Optional. Override default arguments.
+ * @return string HTML content, if not displaying.
+ */
+function wp_dropdown_pages($args = '') {
+ $defaults = array(
+ 'depth' => 0, 'child_of' => 0,
+ 'selected' => 0, 'echo' => 1,
+ 'name' => 'page_id', 'id' => '',
+ 'show_option_none' => '', 'show_option_no_change' => '',
+ 'option_none_value' => ''
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $pages = get_pages($r);
+ $output = '';
+ // Back-compat with old system where both id and name were based on $name argument
+ if ( empty($id) )
+ $id = $name;
+
+ if ( ! empty($pages) ) {
+ $output = "<select name='" . esc_attr( $name ) . "' id='" . esc_attr( $id ) . "'>\n";
+ if ( $show_option_no_change )
+ $output .= "\t<option value=\"-1\">$show_option_no_change</option>";
+ if ( $show_option_none )
+ $output .= "\t<option value=\"" . esc_attr($option_none_value) . "\">$show_option_none</option>\n";
+ $output .= walk_page_dropdown_tree($pages, $depth, $r);
+ $output .= "</select>\n";
+ }
+
+ $output = apply_filters('wp_dropdown_pages', $output);
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+/**
+ * Retrieve or display list of pages in list (li) format.
+ *
+ * @since 1.5.0
+ *
+ * @param array|string $args Optional. Override default arguments.
+ * @return string HTML content, if not displaying.
+ */
+function wp_list_pages($args = '') {
+ $defaults = array(
+ 'depth' => 0, 'show_date' => '',
+ 'date_format' => get_option('date_format'),
+ 'child_of' => 0, 'exclude' => '',
+ 'title_li' => __('Pages'), 'echo' => 1,
+ 'authors' => '', 'sort_column' => 'menu_order, post_title',
+ 'link_before' => '', 'link_after' => '', 'walker' => '',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $output = '';
+ $current_page = 0;
+
+ // sanitize, mostly to keep spaces out
+ $r['exclude'] = preg_replace('/[^0-9,]/', '', $r['exclude']);
+
+ // Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array)
+ $exclude_array = ( $r['exclude'] ) ? explode(',', $r['exclude']) : array();
+ $r['exclude'] = implode( ',', apply_filters('wp_list_pages_excludes', $exclude_array) );
+
+ // Query pages.
+ $r['hierarchical'] = 0;
+ $pages = get_pages($r);
+
+ if ( !empty($pages) ) {
+ if ( $r['title_li'] )
+ $output .= '<li class="pagenav">' . $r['title_li'] . '<ul>';
+
+ global $wp_query;
+ if ( is_page() || is_attachment() || $wp_query->is_posts_page )
+ $current_page = $wp_query->get_queried_object_id();
+ $output .= walk_page_tree($pages, $r['depth'], $current_page, $r);
+
+ if ( $r['title_li'] )
+ $output .= '</ul></li>';
+ }
+
+ $output = apply_filters('wp_list_pages', $output, $r);
+
+ if ( $r['echo'] )
+ echo $output;
+ else
+ return $output;
+}
+
+/**
+ * Display or retrieve list of pages with optional home link.
+ *
+ * The arguments are listed below and part of the arguments are for {@link
+ * wp_list_pages()} function. Check that function for more info on those
+ * arguments.
+ *
+ * <ul>
+ * <li><strong>sort_column</strong> - How to sort the list of pages. Defaults
+ * to page title. Use column for posts table.</li>
+ * <li><strong>menu_class</strong> - Class to use for the div ID which contains
+ * the page list. Defaults to 'menu'.</li>
+ * <li><strong>echo</strong> - Whether to echo list or return it. Defaults to
+ * echo.</li>
+ * <li><strong>link_before</strong> - Text before show_home argument text.</li>
+ * <li><strong>link_after</strong> - Text after show_home argument text.</li>
+ * <li><strong>show_home</strong> - If you set this argument, then it will
+ * display the link to the home page. The show_home argument really just needs
+ * to be set to the value of the text of the link.</li>
+ * </ul>
+ *
+ * @since 2.7.0
+ *
+ * @param array|string $args
+ * @return string html menu
+ */
+function wp_page_menu( $args = array() ) {
+ $defaults = array('sort_column' => 'menu_order, post_title', 'menu_class' => 'menu', 'echo' => true, 'link_before' => '', 'link_after' => '');
+ $args = wp_parse_args( $args, $defaults );
+ $args = apply_filters( 'wp_page_menu_args', $args );
+
+ $menu = '';
+
+ $list_args = $args;
+
+ // Show Home in the menu
+ if ( ! empty($args['show_home']) ) {
+ if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] )
+ $text = __('Home');
+ else
+ $text = $args['show_home'];
+ $class = '';
+ if ( is_front_page() && !is_paged() )
+ $class = 'class="current_page_item"';
+ $menu .= '<li ' . $class . '><a href="' . home_url( '/' ) . '" title="' . esc_attr($text) . '">' . $args['link_before'] . $text . $args['link_after'] . '</a></li>';
+ // If the front page is a page, add it to the exclude list
+ if (get_option('show_on_front') == 'page') {
+ if ( !empty( $list_args['exclude'] ) ) {
+ $list_args['exclude'] .= ',';
+ } else {
+ $list_args['exclude'] = '';
+ }
+ $list_args['exclude'] .= get_option('page_on_front');
+ }
+ }
+
+ $list_args['echo'] = false;
+ $list_args['title_li'] = '';
+ $menu .= str_replace( array( "\r", "\n", "\t" ), '', wp_list_pages($list_args) );
+
+ if ( $menu )
+ $menu = '<ul>' . $menu . '</ul>';
+
+ $menu = '<div class="' . esc_attr($args['menu_class']) . '">' . $menu . "</div>\n";
+ $menu = apply_filters( 'wp_page_menu', $menu, $args );
+ if ( $args['echo'] )
+ echo $menu;
+ else
+ return $menu;
+}
+
+//
+// Page helpers
+//
+
+/**
+ * Retrieve HTML list content for page list.
+ *
+ * @uses Walker_Page to create HTML list content.
+ * @since 2.1.0
+ * @see Walker_Page::walk() for parameters and return description.
+ */
+function walk_page_tree($pages, $depth, $current_page, $r) {
+ if ( empty($r['walker']) )
+ $walker = new Walker_Page;
+ else
+ $walker = $r['walker'];
+
+ $args = array($pages, $depth, $r, $current_page);
+ return call_user_func_array(array($walker, 'walk'), $args);
+}
+
+/**
+ * Retrieve HTML dropdown (select) content for page list.
+ *
+ * @uses Walker_PageDropdown to create HTML dropdown content.
+ * @since 2.1.0
+ * @see Walker_PageDropdown::walk() for parameters and return description.
+ */
+function walk_page_dropdown_tree() {
+ $args = func_get_args();
+ if ( empty($args[2]['walker']) ) // the user's options are the third parameter
+ $walker = new Walker_PageDropdown;
+ else
+ $walker = $args[2]['walker'];
+
+ return call_user_func_array(array($walker, 'walk'), $args);
+}
+
+/**
+ * Create HTML list of pages.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_Page extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'page';
+
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this.
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
+
+ /**
+ * @see Walker::start_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of page. Used for padding.
+ * @param array $args
+ */
+ function start_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "\n$indent<ul class='children'>\n";
+ }
+
+ /**
+ * @see Walker::end_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of page. Used for padding.
+ * @param array $args
+ */
+ function end_lvl( &$output, $depth = 0, $args = array() ) {
+ $indent = str_repeat("\t", $depth);
+ $output .= "$indent</ul>\n";
+ }
+
+ /**
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Page data object.
+ * @param int $depth Depth of page. Used for padding.
+ * @param int $current_page Page ID.
+ * @param array $args
+ */
+ function start_el( &$output, $page, $depth = 0, $args = array(), $current_page = 0 ) {
+ if ( $depth )
+ $indent = str_repeat("\t", $depth);
+ else
+ $indent = '';
+
+ extract($args, EXTR_SKIP);
+ $css_class = array('page_item', 'page-item-'.$page->ID);
+ if ( !empty($current_page) ) {
+ $_current_page = get_post( $current_page );
+ if ( in_array( $page->ID, $_current_page->ancestors ) )
+ $css_class[] = 'current_page_ancestor';
+ if ( $page->ID == $current_page )
+ $css_class[] = 'current_page_item';
+ elseif ( $_current_page && $page->ID == $_current_page->post_parent )
+ $css_class[] = 'current_page_parent';
+ } elseif ( $page->ID == get_option('page_for_posts') ) {
+ $css_class[] = 'current_page_parent';
+ }
+
+ $css_class = implode( ' ', apply_filters( 'page_css_class', $css_class, $page, $depth, $args, $current_page ) );
+
+ if ( '' === $page->post_title )
+ $page->post_title = sprintf( __( '#%d (no title)' ), $page->ID );
+
+ $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_permalink($page->ID) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
+
+ if ( !empty($show_date) ) {
+ if ( 'modified' == $show_date )
+ $time = $page->post_modified;
+ else
+ $time = $page->post_date;
+
+ $output .= " " . mysql2date($date_format, $time);
+ }
+ }
+
+ /**
+ * @see Walker::end_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Page data object. Not used.
+ * @param int $depth Depth of page. Not Used.
+ * @param array $args
+ */
+ function end_el( &$output, $page, $depth = 0, $args = array() ) {
+ $output .= "</li>\n";
+ }
+
+}
+
+/**
+ * Create HTML dropdown list of pages.
+ *
+ * @package WordPress
+ * @since 2.1.0
+ * @uses Walker
+ */
+class Walker_PageDropdown extends Walker {
+ /**
+ * @see Walker::$tree_type
+ * @since 2.1.0
+ * @var string
+ */
+ var $tree_type = 'page';
+
+ /**
+ * @see Walker::$db_fields
+ * @since 2.1.0
+ * @todo Decouple this
+ * @var array
+ */
+ var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
+
+ /**
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $page Page data object.
+ * @param int $depth Depth of page in reference to parent pages. Used for padding.
+ * @param array $args Uses 'selected' argument for selected page to set selected HTML attribute for option element.
+ * @param int $id
+ */
+ function start_el( &$output, $page, $depth = 0, $args = array(), $id = 0 ) {
+ $pad = str_repeat('&nbsp;', $depth * 3);
+
+ $output .= "\t<option class=\"level-$depth\" value=\"$page->ID\"";
+ if ( $page->ID == $args['selected'] )
+ $output .= ' selected="selected"';
+ $output .= '>';
+ $title = apply_filters( 'list_pages', $page->post_title, $page );
+ $output .= $pad . esc_html( $title );
+ $output .= "</option>\n";
+ }
+}
+
+//
+// Attachments
+//
+
+/**
+ * Display an attachment page link using an image or icon.
+ *
+ * @since 2.0.0
+ *
+ * @param int $id Optional. Post ID.
+ * @param bool $fullsize Optional, default is false. Whether to use full size.
+ * @param bool $deprecated Deprecated. Not used.
+ * @param bool $permalink Optional, default is false. Whether to include permalink.
+ */
+function the_attachment_link( $id = 0, $fullsize = false, $deprecated = false, $permalink = false ) {
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '2.5' );
+
+ if ( $fullsize )
+ echo wp_get_attachment_link($id, 'full', $permalink);
+ else
+ echo wp_get_attachment_link($id, 'thumbnail', $permalink);
+}
+
+/**
+ * Retrieve an attachment page link using an image or icon, if possible.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'wp_get_attachment_link' filter on HTML content with same parameters as function.
+ *
+ * @param int $id Optional. Post ID.
+ * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string.
+ * @param bool $permalink Optional, default is false. Whether to add permalink to image.
+ * @param bool $icon Optional, default is false. Whether to include icon.
+ * @param string|bool $text Optional, default is false. If string, then will be link text.
+ * @return string HTML content.
+ */
+function wp_get_attachment_link( $id = 0, $size = 'thumbnail', $permalink = false, $icon = false, $text = false ) {
+ $id = intval( $id );
+ $_post = get_post( $id );
+
+ if ( empty( $_post ) || ( 'attachment' != $_post->post_type ) || ! $url = wp_get_attachment_url( $_post->ID ) )
+ return __( 'Missing Attachment' );
+
+ if ( $permalink )
+ $url = get_attachment_link( $_post->ID );
+
+ $post_title = esc_attr( $_post->post_title );
+
+ if ( $text )
+ $link_text = $text;
+ elseif ( $size && 'none' != $size )
+ $link_text = wp_get_attachment_image( $id, $size, $icon );
+ else
+ $link_text = '';
+
+ if ( trim( $link_text ) == '' )
+ $link_text = $_post->post_title;
+
+ return apply_filters( 'wp_get_attachment_link', "<a href='$url' title='$post_title'>$link_text</a>", $id, $size, $permalink, $icon, $text );
+}
+
+/**
+ * Wrap attachment in <<p>> element before content.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'prepend_attachment' hook on HTML content.
+ *
+ * @param string $content
+ * @return string
+ */
+function prepend_attachment($content) {
+ $post = get_post();
+
+ if ( empty($post->post_type) || $post->post_type != 'attachment' )
+ return $content;
+
+ $p = '<p class="attachment">';
+ // show the medium sized image representation of the attachment if available, and link to the raw file
+ $p .= wp_get_attachment_link(0, 'medium', false);
+ $p .= '</p>';
+ $p = apply_filters('prepend_attachment', $p);
+
+ return "$p\n$content";
+}
+
+//
+// Misc
+//
+
+/**
+ * Retrieve protected post password form content.
+ *
+ * @since 1.0.0
+ * @uses apply_filters() Calls 'the_password_form' filter on output.
+ * @param int|WP_Post $post Optional. A post id or post object. Defaults to the current post when in The Loop, undefined otherwise.
+ * @return string HTML content for password form for password protected post.
+ */
+function get_the_password_form( $post = 0 ) {
+ $post = get_post( $post );
+ $label = 'pwbox-' . ( empty($post->ID) ? rand() : $post->ID );
+ $output = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass', 'login_post' ) ) . '" method="post">
+ <p>' . __("This post is password protected. To view it please enter your password below:") . '</p>
+ <p><label for="' . $label . '">' . __("Password:") . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr__("Submit") . '" /></p>
+</form>
+ ';
+ return apply_filters('the_password_form', $output);
+}
+
+/**
+ * Whether currently in a page template.
+ *
+ * This template tag allows you to determine if you are in a page template.
+ * You can optionally provide a template name and then the check will be
+ * specific to that template.
+ *
+ * @since 2.5.0
+ * @uses $wp_query
+ *
+ * @param string $template The specific template name if specific matching is required.
+ * @return bool True on success, false on failure.
+ */
+function is_page_template( $template = '' ) {
+ if ( ! is_page() )
+ return false;
+
+ $page_template = get_page_template_slug( get_queried_object_id() );
+
+ if ( empty( $template ) )
+ return (bool) $page_template;
+
+ if ( $template == $page_template )
+ return true;
+
+ if ( 'default' == $template && ! $page_template )
+ return true;
+
+ return false;
+}
+
+/**
+ * Get the specific template name for a page.
+ *
+ * @since 3.4.0
+ *
+ * @param int $post_id Optional. The page ID to check. Defaults to the current post, when used in the loop.
+ * @return string|bool Page template filename. Returns an empty string when the default page template
+ * is in use. Returns false if the post is not a page.
+ */
+function get_page_template_slug( $post_id = null ) {
+ $post = get_post( $post_id );
+ if ( ! $post || 'page' != $post->post_type )
+ return false;
+ $template = get_post_meta( $post->ID, '_wp_page_template', true );
+ if ( ! $template || 'default' == $template )
+ return '';
+ return $template;
+}
+
+/**
+ * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses date_i18n()
+ *
+ * @param int|object $revision Revision ID or revision object.
+ * @param bool $link Optional, default is true. Link to revisions's page?
+ * @return string i18n formatted datetimestamp or localized 'Current Revision'.
+ */
+function wp_post_revision_title( $revision, $link = true ) {
+ if ( !$revision = get_post( $revision ) )
+ return $revision;
+
+ if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
+ return false;
+
+ /* translators: revision date format, see http://php.net/date */
+ $datef = _x( 'j F, Y @ G:i', 'revision date format');
+ /* translators: 1: date */
+ $autosavef = _x( '%1$s [Autosave]', 'post revision title extra' );
+ /* translators: 1: date */
+ $currentf = _x( '%1$s [Current Revision]', 'post revision title extra' );
+
+ $date = date_i18n( $datef, strtotime( $revision->post_modified ) );
+ if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
+ $date = "<a href='$link'>$date</a>";
+
+ if ( !wp_is_post_revision( $revision ) )
+ $date = sprintf( $currentf, $date );
+ elseif ( wp_is_post_autosave( $revision ) )
+ $date = sprintf( $autosavef, $date );
+
+ return $date;
+}
+
+/**
+ * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 3.6.0
+ *
+ * @uses date_i18n()
+ *
+ * @param int|object $revision Revision ID or revision object.
+ * @param bool $link Optional, default is true. Link to revisions's page?
+ * @return string gravatar, user, i18n formatted datetimestamp or localized 'Current Revision'.
+ */
+function wp_post_revision_title_expanded( $revision, $link = true ) {
+ if ( !$revision = get_post( $revision ) )
+ return $revision;
+
+ if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
+ return false;
+
+ $author = get_the_author_meta( 'display_name', $revision->post_author );
+ /* translators: revision date format, see http://php.net/date */
+ $datef = _x( 'j F, Y @ G:i:s', 'revision date format');
+
+ $gravatar = get_avatar( $revision->post_author, 24 );
+
+ $date = date_i18n( $datef, strtotime( $revision->post_modified ) );
+ if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
+ $date = "<a href='$link'>$date</a>";
+
+ $revision_date_author = sprintf(
+ /* translators: post revision title: 1: author avatar, 2: author name, 3: time ago, 4: date */
+ _x( '%1$s %2$s, %3$s ago (%4$s)', 'post revision title' ),
+ $gravatar,
+ $author,
+ human_time_diff( strtotime( $revision->post_modified ), current_time( 'timestamp' ) ),
+ $date
+ );
+
+ $autosavef = __( '%1$s [Autosave]' );
+ $currentf = __( '%1$s [Current Revision]' );
+
+ if ( !wp_is_post_revision( $revision ) )
+ $revision_date_author = sprintf( $currentf, $revision_date_author );
+ elseif ( wp_is_post_autosave( $revision ) )
+ $revision_date_author = sprintf( $autosavef, $revision_date_author );
+
+ return $revision_date_author;
+}
+
+/**
+ * Display list of a post's revisions.
+ *
+ * Can output either a UL with edit links or a TABLE with diff interface, and
+ * restore action links.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revisions()
+ * @uses wp_post_revision_title_expanded()
+ * @uses get_edit_post_link()
+ * @uses get_the_author_meta()
+ *
+ * @param int|object $post_id Post ID or post object.
+ * @param string $type 'all' (default), 'revision' or 'autosave'
+ * @return null
+ */
+function wp_list_post_revisions( $post_id = 0, $type = 'all' ) {
+ if ( ! $post = get_post( $post_id ) )
+ return;
+
+ // $args array with (parent, format, right, left, type) deprecated since 3.6
+ if ( is_array( $type ) ) {
+ $type = ! empty( $type['type'] ) ? $type['type'] : $type;
+ _deprecated_argument( __FUNCTION__, '3.6' );
+ }
+
+ if ( ! $revisions = wp_get_post_revisions( $post->ID ) )
+ return;
+
+ $rows = '';
+ foreach ( $revisions as $revision ) {
+ if ( ! current_user_can( 'read_post', $revision->ID ) )
+ continue;
+
+ $is_autosave = wp_is_post_autosave( $revision );
+ if ( ( 'revision' === $type && $is_autosave ) || ( 'autosave' === $type && ! $is_autosave ) )
+ continue;
+
+ $rows .= "\t<li>" . wp_post_revision_title_expanded( $revision ) . "</li>\n";
+ }
+
+ echo "<div class='hide-if-js'><p>" . __( 'JavaScript must be enabled to use this feature.' ) . "</p></div>\n";
+
+ echo "<ul class='post-revisions hide-if-no-js'>\n";
+ echo $rows;
+
+ // if the post was previously restored from a revision
+ // show the restore event details
+ if ( $restored_from_meta = get_post_meta( $post->ID, '_post_restored_from', true ) ) {
+ $author = get_user_by( 'id', $restored_from_meta[ 'restored_by_user' ] );
+ /* translators: revision date format, see http://php.net/date */
+ $datef = _x( 'j F, Y @ G:i:s', 'revision date format');
+ $date = date_i18n( $datef, strtotime( $restored_from_meta[ 'restored_time' ] ) );
+ $time_diff = human_time_diff( $restored_from_meta[ 'restored_time' ] ) ;
+ ?>
+ <hr />
+ <div id="revisions-meta-restored">
+ <?php
+ printf(
+ /* translators: restored revision details: 1: gravatar image, 2: author name, 3: time ago, 4: date */
+ __( 'Previously restored by %1$s %2$s, %3$s ago (%4$s)' ),
+ get_avatar( $author->ID, 24 ),
+ $author->display_name,
+ $time_diff,
+ $date
+ );
+ ?>
+ </div>
+ <?php
+ echo "</ul>";
+ }
+
+}
diff --git a/src/wp-includes/post-thumbnail-template.php b/src/wp-includes/post-thumbnail-template.php
new file mode 100644
index 0000000000..dda0e34a1e
--- /dev/null
+++ b/src/wp-includes/post-thumbnail-template.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * WordPress Post Thumbnail Template Functions.
+ *
+ * Support for post thumbnails
+ * Themes function.php must call add_theme_support( 'post-thumbnails' ) to use these.
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Check if post has an image attached.
+ *
+ * @since 2.9.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @return bool Whether post has an image attached.
+ */
+function has_post_thumbnail( $post_id = null ) {
+ return (bool) get_post_thumbnail_id( $post_id );
+}
+
+/**
+ * Retrieve Post Thumbnail ID.
+ *
+ * @since 2.9.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @return int
+ */
+function get_post_thumbnail_id( $post_id = null ) {
+ $post_id = ( null === $post_id ) ? get_the_ID() : $post_id;
+ return get_post_meta( $post_id, '_thumbnail_id', true );
+}
+
+/**
+ * Display Post Thumbnail.
+ *
+ * @since 2.9.0
+ *
+ * @param string|array $size Optional. Image size. Defaults to 'post-thumbnail', which theme sets using set_post_thumbnail_size( $width, $height, $crop_flag );.
+ * @param string|array $attr Optional. Query string or array of attributes.
+ */
+function the_post_thumbnail( $size = 'post-thumbnail', $attr = '' ) {
+ echo get_the_post_thumbnail( null, $size, $attr );
+}
+
+/**
+ * Update cache for thumbnails in the current loop
+ *
+ * @since 3.2
+ *
+ * @param object $wp_query Optional. A WP_Query instance. Defaults to the $wp_query global.
+ */
+function update_post_thumbnail_cache( $wp_query = null ) {
+ if ( ! $wp_query )
+ $wp_query = $GLOBALS['wp_query'];
+
+ if ( $wp_query->thumbnails_cached )
+ return;
+
+ $thumb_ids = array();
+ foreach ( $wp_query->posts as $post ) {
+ if ( $id = get_post_thumbnail_id( $post->ID ) )
+ $thumb_ids[] = $id;
+ }
+
+ if ( ! empty ( $thumb_ids ) ) {
+ _prime_post_caches( $thumb_ids, false, true );
+ }
+
+ $wp_query->thumbnails_cached = true;
+}
+
+/**
+ * Retrieve Post Thumbnail.
+ *
+ * @since 2.9.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @param string $size Optional. Image size. Defaults to 'post-thumbnail'.
+ * @param string|array $attr Optional. Query string or array of attributes.
+ */
+function get_the_post_thumbnail( $post_id = null, $size = 'post-thumbnail', $attr = '' ) {
+ $post_id = ( null === $post_id ) ? get_the_ID() : $post_id;
+ $post_thumbnail_id = get_post_thumbnail_id( $post_id );
+ $size = apply_filters( 'post_thumbnail_size', $size );
+ if ( $post_thumbnail_id ) {
+ do_action( 'begin_fetch_post_thumbnail_html', $post_id, $post_thumbnail_id, $size ); // for "Just In Time" filtering of all of wp_get_attachment_image()'s filters
+ if ( in_the_loop() )
+ update_post_thumbnail_cache();
+ $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, $attr );
+ do_action( 'end_fetch_post_thumbnail_html', $post_id, $post_thumbnail_id, $size );
+ } else {
+ $html = '';
+ }
+ return apply_filters( 'post_thumbnail_html', $html, $post_id, $post_thumbnail_id, $size, $attr );
+}
diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php
new file mode 100644
index 0000000000..03f31ef57e
--- /dev/null
+++ b/src/wp-includes/post.php
@@ -0,0 +1,4966 @@
+<?php
+/**
+ * Post functions and post utility function.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 1.5.0
+ */
+
+//
+// Post Type Registration
+//
+
+/**
+ * Creates the initial post types when 'init' action is fired.
+ *
+ * @since 2.9.0
+ */
+function create_initial_post_types() {
+ register_post_type( 'post', array(
+ 'labels' => array(
+ 'name_admin_bar' => _x( 'Post', 'add new on admin bar' ),
+ ),
+ 'public' => true,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
+ 'capability_type' => 'post',
+ 'map_meta_cap' => true,
+ 'hierarchical' => false,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'delete_with_user' => true,
+ 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ),
+ ) );
+
+ register_post_type( 'page', array(
+ 'labels' => array(
+ 'name_admin_bar' => _x( 'Page', 'add new on admin bar' ),
+ ),
+ 'public' => true,
+ 'publicly_queryable' => false,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
+ 'capability_type' => 'page',
+ 'map_meta_cap' => true,
+ 'hierarchical' => true,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'delete_with_user' => true,
+ 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ),
+ ) );
+
+ register_post_type( 'attachment', array(
+ 'labels' => array(
+ 'name' => _x('Media', 'post type general name'),
+ 'name_admin_bar' => _x( 'Media', 'add new from admin bar' ),
+ 'add_new' => _x( 'Add New', 'add new media' ),
+ 'edit_item' => __( 'Edit Media' ),
+ 'view_item' => __( 'View Attachment Page' ),
+ ),
+ 'public' => true,
+ 'show_ui' => true,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */
+ 'capability_type' => 'post',
+ 'capabilities' => array(
+ 'create_posts' => 'upload_files',
+ ),
+ 'map_meta_cap' => true,
+ 'hierarchical' => false,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'show_in_nav_menus' => false,
+ 'delete_with_user' => true,
+ 'supports' => array( 'title', 'author', 'comments' ),
+ ) );
+
+ register_post_type( 'revision', array(
+ 'labels' => array(
+ 'name' => __( 'Revisions' ),
+ 'singular_name' => __( 'Revision' ),
+ ),
+ 'public' => false,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ '_edit_link' => 'revision.php?revision=%d', /* internal use only. don't use this when registering your own post type. */
+ 'capability_type' => 'post',
+ 'map_meta_cap' => true,
+ 'hierarchical' => false,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'can_export' => false,
+ 'delete_with_user' => true,
+ 'supports' => array( 'author' ),
+ ) );
+
+ register_post_type( 'nav_menu_item', array(
+ 'labels' => array(
+ 'name' => __( 'Navigation Menu Items' ),
+ 'singular_name' => __( 'Navigation Menu Item' ),
+ ),
+ 'public' => false,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ 'hierarchical' => false,
+ 'rewrite' => false,
+ 'delete_with_user' => false,
+ 'query_var' => false,
+ ) );
+
+ register_post_status( 'publish', array(
+ 'label' => _x( 'Published', 'post' ),
+ 'public' => true,
+ '_builtin' => true, /* internal use only. */
+ 'label_count' => _n_noop( 'Published <span class="count">(%s)</span>', 'Published <span class="count">(%s)</span>' ),
+ ) );
+
+ register_post_status( 'future', array(
+ 'label' => _x( 'Scheduled', 'post' ),
+ 'protected' => true,
+ '_builtin' => true, /* internal use only. */
+ 'label_count' => _n_noop('Scheduled <span class="count">(%s)</span>', 'Scheduled <span class="count">(%s)</span>' ),
+ ) );
+
+ register_post_status( 'draft', array(
+ 'label' => _x( 'Draft', 'post' ),
+ 'protected' => true,
+ '_builtin' => true, /* internal use only. */
+ 'label_count' => _n_noop( 'Draft <span class="count">(%s)</span>', 'Drafts <span class="count">(%s)</span>' ),
+ ) );
+
+ register_post_status( 'pending', array(
+ 'label' => _x( 'Pending', 'post' ),
+ 'protected' => true,
+ '_builtin' => true, /* internal use only. */
+ 'label_count' => _n_noop( 'Pending <span class="count">(%s)</span>', 'Pending <span class="count">(%s)</span>' ),
+ ) );
+
+ register_post_status( 'private', array(
+ 'label' => _x( 'Private', 'post' ),
+ 'private' => true,
+ '_builtin' => true, /* internal use only. */
+ 'label_count' => _n_noop( 'Private <span class="count">(%s)</span>', 'Private <span class="count">(%s)</span>' ),
+ ) );
+
+ register_post_status( 'trash', array(
+ 'label' => _x( 'Trash', 'post' ),
+ 'internal' => true,
+ '_builtin' => true, /* internal use only. */
+ 'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>' ),
+ 'show_in_admin_status_list' => true,
+ ) );
+
+ register_post_status( 'auto-draft', array(
+ 'label' => 'auto-draft',
+ 'internal' => true,
+ '_builtin' => true, /* internal use only. */
+ ) );
+
+ register_post_status( 'inherit', array(
+ 'label' => 'inherit',
+ 'internal' => true,
+ '_builtin' => true, /* internal use only. */
+ 'exclude_from_search' => false,
+ ) );
+}
+add_action( 'init', 'create_initial_post_types', 0 ); // highest priority
+
+/**
+ * Retrieve attached file path based on attachment ID.
+ *
+ * By default the path will go through the 'get_attached_file' filter, but
+ * passing a true to the $unfiltered argument of get_attached_file() will
+ * return the file path unfiltered.
+ *
+ * The function works by getting the single post meta name, named
+ * '_wp_attached_file' and returning it. This is a convenience function to
+ * prevent looking up the meta name and provide a mechanism for sending the
+ * attached filename through a filter.
+ *
+ * @since 2.0.0
+ * @uses apply_filters() Calls 'get_attached_file' on file path and attachment ID.
+ *
+ * @param int $attachment_id Attachment ID.
+ * @param bool $unfiltered Whether to apply filters.
+ * @return string|bool The file path to the attached file, or false if the attachment does not exist.
+ */
+function get_attached_file( $attachment_id, $unfiltered = false ) {
+ $file = get_post_meta( $attachment_id, '_wp_attached_file', true );
+ // If the file is relative, prepend upload dir
+ if ( $file && 0 !== strpos($file, '/') && !preg_match('|^.:\\\|', $file) && ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) )
+ $file = $uploads['basedir'] . "/$file";
+ if ( $unfiltered )
+ return $file;
+ return apply_filters( 'get_attached_file', $file, $attachment_id );
+}
+
+/**
+ * Update attachment file path based on attachment ID.
+ *
+ * Used to update the file path of the attachment, which uses post meta name
+ * '_wp_attached_file' to store the path of the attachment.
+ *
+ * @since 2.1.0
+ * @uses apply_filters() Calls 'update_attached_file' on file path and attachment ID.
+ *
+ * @param int $attachment_id Attachment ID
+ * @param string $file File path for the attachment
+ * @return bool True on success, false on failure.
+ */
+function update_attached_file( $attachment_id, $file ) {
+ if ( !get_post( $attachment_id ) )
+ return false;
+
+ $file = apply_filters( 'update_attached_file', $file, $attachment_id );
+ if ( $file = _wp_relative_upload_path( $file ) )
+ return update_post_meta( $attachment_id, '_wp_attached_file', $file );
+ else
+ return delete_post_meta( $attachment_id, '_wp_attached_file' );
+}
+
+/**
+ * Return relative path to an uploaded file.
+ *
+ * The path is relative to the current upload dir.
+ *
+ * @since 2.9.0
+ * @uses apply_filters() Calls '_wp_relative_upload_path' on file path.
+ *
+ * @param string $path Full path to the file
+ * @return string relative path on success, unchanged path on failure.
+ */
+function _wp_relative_upload_path( $path ) {
+ $new_path = $path;
+
+ $uploads = wp_upload_dir();
+ if ( 0 === strpos( $new_path, $uploads['basedir'] ) ) {
+ $new_path = str_replace( $uploads['basedir'], '', $new_path );
+ $new_path = ltrim( $new_path, '/' );
+ }
+
+ return apply_filters( '_wp_relative_upload_path', $new_path, $path );
+}
+
+/**
+ * Retrieve all children of the post parent ID.
+ *
+ * Normally, without any enhancements, the children would apply to pages. In the
+ * context of the inner workings of WordPress, pages, posts, and attachments
+ * share the same table, so therefore the functionality could apply to any one
+ * of them. It is then noted that while this function does not work on posts, it
+ * does not mean that it won't work on posts. It is recommended that you know
+ * what context you wish to retrieve the children of.
+ *
+ * Attachments may also be made the child of a post, so if that is an accurate
+ * statement (which needs to be verified), it would then be possible to get
+ * all of the attachments for a post. Attachments have since changed since
+ * version 2.5, so this is most likely unaccurate, but serves generally as an
+ * example of what is possible.
+ *
+ * The arguments listed as defaults are for this function and also of the
+ * {@link get_posts()} function. The arguments are combined with the
+ * get_children defaults and are then passed to the {@link get_posts()}
+ * function, which accepts additional arguments. You can replace the defaults in
+ * this function, listed below and the additional arguments listed in the
+ * {@link get_posts()} function.
+ *
+ * The 'post_parent' is the most important argument and important attention
+ * needs to be paid to the $args parameter. If you pass either an object or an
+ * integer (number), then just the 'post_parent' is grabbed and everything else
+ * is lost. If you don't specify any arguments, then it is assumed that you are
+ * in The Loop and the post parent will be grabbed for from the current post.
+ *
+ * The 'post_parent' argument is the ID to get the children. The 'numberposts'
+ * is the amount of posts to retrieve that has a default of '-1', which is
+ * used to get all of the posts. Giving a number higher than 0 will only
+ * retrieve that amount of posts.
+ *
+ * The 'post_type' and 'post_status' arguments can be used to choose what
+ * criteria of posts to retrieve. The 'post_type' can be anything, but WordPress
+ * post types are 'post', 'pages', and 'attachments'. The 'post_status'
+ * argument will accept any post status within the write administration panels.
+ *
+ * @see get_posts() Has additional arguments that can be replaced.
+ * @internal Claims made in the long description might be inaccurate.
+ *
+ * @since 2.0.0
+ *
+ * @param mixed $args Optional. User defined arguments for replacing the defaults.
+ * @param string $output Optional. Constant for return type, either OBJECT (default), ARRAY_A, ARRAY_N.
+ * @return array|bool False on failure and the type will be determined by $output parameter.
+ */
+function get_children($args = '', $output = OBJECT) {
+ $kids = array();
+ if ( empty( $args ) ) {
+ if ( isset( $GLOBALS['post'] ) ) {
+ $args = array('post_parent' => (int) $GLOBALS['post']->post_parent );
+ } else {
+ return $kids;
+ }
+ } elseif ( is_object( $args ) ) {
+ $args = array('post_parent' => (int) $args->post_parent );
+ } elseif ( is_numeric( $args ) ) {
+ $args = array('post_parent' => (int) $args);
+ }
+
+ $defaults = array(
+ 'numberposts' => -1, 'post_type' => 'any',
+ 'post_status' => 'any', 'post_parent' => 0,
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ $children = get_posts( $r );
+
+ if ( !$children )
+ return $kids;
+
+ update_post_cache($children);
+
+ foreach ( $children as $key => $child )
+ $kids[$child->ID] = $children[$key];
+
+ if ( $output == OBJECT ) {
+ return $kids;
+ } elseif ( $output == ARRAY_A ) {
+ foreach ( (array) $kids as $kid )
+ $weeuns[$kid->ID] = get_object_vars($kids[$kid->ID]);
+ return $weeuns;
+ } elseif ( $output == ARRAY_N ) {
+ foreach ( (array) $kids as $kid )
+ $babes[$kid->ID] = array_values(get_object_vars($kids[$kid->ID]));
+ return $babes;
+ } else {
+ return $kids;
+ }
+}
+
+/**
+ * Get extended entry info (<!--more-->).
+ *
+ * There should not be any space after the second dash and before the word
+ * 'more'. There can be text or space(s) after the word 'more', but won't be
+ * referenced.
+ *
+ * The returned array has 'main', 'extended', and 'more_text' keys. Main has the text before
+ * the <code><!--more--></code>. The 'extended' key has the content after the
+ * <code><!--more--></code> comment. The 'more_text' key has the custom "Read More" text.
+ *
+ * @since 1.0.0
+ *
+ * @param string $post Post content.
+ * @return array Post before ('main'), after ('extended'), and custom readmore ('more_text').
+ */
+function get_extended($post) {
+ //Match the new style more links
+ if ( preg_match('/<!--more(.*?)?-->/', $post, $matches) ) {
+ list($main, $extended) = explode($matches[0], $post, 2);
+ $more_text = $matches[1];
+ } else {
+ $main = $post;
+ $extended = '';
+ $more_text = '';
+ }
+
+ // ` leading and trailing whitespace
+ $main = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $main);
+ $extended = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $extended);
+ $more_text = preg_replace('/^[\s]*(.*)[\s]*$/', '\\1', $more_text);
+
+ return array( 'main' => $main, 'extended' => $extended, 'more_text' => $more_text );
+}
+
+/**
+ * Retrieves post data given a post ID or post object.
+ *
+ * See {@link sanitize_post()} for optional $filter values. Also, the parameter
+ * $post, must be given as a variable, since it is passed by reference.
+ *
+ * @since 1.5.1
+ * @link http://codex.wordpress.org/Function_Reference/get_post
+ *
+ * @param int|object $post Post ID or post object. Optional, default is the current post from the loop.
+ * @param string $output Optional, default is Object. Either OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter Optional, default is raw.
+ * @return WP_Post|null WP_Post on success or null on failure
+ */
+function get_post( $post = null, $output = OBJECT, $filter = 'raw' ) {
+ if ( empty( $post ) && isset( $GLOBALS['post'] ) )
+ $post = $GLOBALS['post'];
+
+ if ( is_a( $post, 'WP_Post' ) ) {
+ $_post = $post;
+ } elseif ( is_object( $post ) ) {
+ if ( empty( $post->filter ) ) {
+ $_post = sanitize_post( $post, 'raw' );
+ $_post = new WP_Post( $_post );
+ } elseif ( 'raw' == $post->filter ) {
+ $_post = new WP_Post( $post );
+ } else {
+ $_post = WP_Post::get_instance( $post->ID );
+ }
+ } else {
+ $_post = WP_Post::get_instance( $post );
+ }
+
+ if ( ! $_post )
+ return null;
+
+ $_post = $_post->filter( $filter );
+
+ if ( $output == ARRAY_A )
+ return $_post->to_array();
+ elseif ( $output == ARRAY_N )
+ return array_values( $_post->to_array() );
+
+ return $_post;
+}
+
+/**
+ * WordPress Post class.
+ *
+ * @since 3.5.0
+ *
+ */
+final class WP_Post {
+
+ /**
+ *
+ * @var int
+ */
+ public $ID;
+
+ /**
+ *
+ * @var int
+ */
+ public $post_author = 0;
+
+ /**
+ *
+ * @var string
+ */
+ public $post_date = '0000-00-00 00:00:00';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_date_gmt = '0000-00-00 00:00:00';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_content = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_title = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_excerpt = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_status = 'publish';
+
+ /**
+ *
+ * @var string
+ */
+ public $comment_status = 'open';
+
+ /**
+ *
+ * @var string
+ */
+ public $ping_status = 'open';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_password = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_name = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $to_ping = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $pinged = '';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_modified = '0000-00-00 00:00:00';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_modified_gmt = '0000-00-00 00:00:00';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_content_filtered = '';
+
+ /**
+ *
+ * @var int
+ */
+ public $post_parent = 0;
+
+ /**
+ *
+ * @var string
+ */
+ public $guid = '';
+
+ /**
+ *
+ * @var int
+ */
+ public $menu_order = 0;
+
+ /**
+ *
+ * @var string
+ */
+ public $post_type = 'post';
+
+ /**
+ *
+ * @var string
+ */
+ public $post_mime_type = '';
+
+ /**
+ *
+ * @var int
+ */
+ public $comment_count = 0;
+
+ /**
+ *
+ * @var string
+ */
+ public $filter;
+
+ /**
+ * Private variable used by post formats to cache parsed content.
+ *
+ * @since 3.6.0
+ *
+ * @var array
+ * @access private
+ */
+ public $format_content;
+
+
+ public static function get_instance( $post_id ) {
+ global $wpdb;
+
+ $post_id = (int) $post_id;
+ if ( ! $post_id )
+ return false;
+
+ $_post = wp_cache_get( $post_id, 'posts' );
+
+ if ( ! $_post ) {
+ $_post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d LIMIT 1", $post_id ) );
+
+ if ( ! $_post )
+ return false;
+
+ $_post = sanitize_post( $_post, 'raw' );
+ wp_cache_add( $_post->ID, $_post, 'posts' );
+ } elseif ( empty( $_post->filter ) ) {
+ $_post = sanitize_post( $_post, 'raw' );
+ }
+
+ return new WP_Post( $_post );
+ }
+
+ public function __construct( $post ) {
+ foreach ( get_object_vars( $post ) as $key => $value )
+ $this->$key = $value;
+ }
+
+ public function __isset( $key ) {
+ if ( 'ancestors' == $key )
+ return true;
+
+ if ( 'page_template' == $key )
+ return ( 'page' == $this->post_type );
+
+ if ( 'post_category' == $key )
+ return true;
+
+ if ( 'tags_input' == $key )
+ return true;
+
+ return metadata_exists( 'post', $this->ID, $key );
+ }
+
+ public function __get( $key ) {
+ if ( 'page_template' == $key && $this->__isset( $key ) ) {
+ return get_post_meta( $this->ID, '_wp_page_template', true );
+ }
+
+ if ( 'post_category' == $key ) {
+ if ( is_object_in_taxonomy( $this->post_type, 'category' ) )
+ $terms = get_the_terms( $this, 'category' );
+
+ if ( empty( $terms ) )
+ return array();
+
+ return wp_list_pluck( $terms, 'term_id' );
+ }
+
+ if ( 'tags_input' == $key ) {
+ if ( is_object_in_taxonomy( $this->post_type, 'post_tag' ) )
+ $terms = get_the_terms( $this, 'post_tag' );
+
+ if ( empty( $terms ) )
+ return array();
+
+ return wp_list_pluck( $terms, 'name' );
+ }
+
+ // Rest of the values need filtering
+
+ if ( 'ancestors' == $key )
+ $value = get_post_ancestors( $this );
+ else
+ $value = get_post_meta( $this->ID, $key, true );
+
+ if ( $this->filter )
+ $value = sanitize_post_field( $key, $value, $this->ID, $this->filter );
+
+ return $value;
+ }
+
+ public function filter( $filter ) {
+ if ( $this->filter == $filter )
+ return $this;
+
+ if ( $filter == 'raw' )
+ return self::get_instance( $this->ID );
+
+ return sanitize_post( $this, $filter );
+ }
+
+ public function to_array() {
+ $post = get_object_vars( $this );
+
+ foreach ( array( 'ancestors', 'page_template', 'post_category', 'tags_input' ) as $key ) {
+ if ( $this->__isset( $key ) )
+ $post[ $key ] = $this->__get( $key );
+ }
+
+ return $post;
+ }
+}
+
+/**
+ * Retrieve ancestors of a post.
+ *
+ * @since 2.5.0
+ *
+ * @param int|object $post Post ID or post object
+ * @return array Ancestor IDs or empty array if none are found.
+ */
+function get_post_ancestors( $post ) {
+ $post = get_post( $post );
+
+ if ( ! $post || empty( $post->post_parent ) || $post->post_parent == $post->ID )
+ return array();
+
+ $ancestors = array();
+
+ $id = $ancestors[] = $post->post_parent;
+
+ while ( $ancestor = get_post( $id ) ) {
+ // Loop detection: If the ancestor has been seen before, break.
+ if ( empty( $ancestor->post_parent ) || ( $ancestor->post_parent == $post->ID ) || in_array( $ancestor->post_parent, $ancestors ) )
+ break;
+
+ $id = $ancestors[] = $ancestor->post_parent;
+ }
+
+ return $ancestors;
+}
+
+/**
+ * Retrieve data from a post field based on Post ID.
+ *
+ * Examples of the post field will be, 'post_type', 'post_status', 'post_content',
+ * etc and based off of the post object property or key names.
+ *
+ * The context values are based off of the taxonomy filter functions and
+ * supported values are found within those functions.
+ *
+ * @since 2.3.0
+ * @uses sanitize_post_field() See for possible $context values.
+ *
+ * @param string $field Post field name.
+ * @param int|object $post Post ID or post object.
+ * @param string $context Optional. How to filter the field. Default is 'display'.
+ * @return string The value of the post field on success, empty string on failure.
+ */
+function get_post_field( $field, $post, $context = 'display' ) {
+ $post = get_post( $post );
+
+ if ( !$post )
+ return '';
+
+ if ( !isset($post->$field) )
+ return '';
+
+ return sanitize_post_field($field, $post->$field, $post->ID, $context);
+}
+
+/**
+ * Retrieve the mime type of an attachment based on the ID.
+ *
+ * This function can be used with any post type, but it makes more sense with
+ * attachments.
+ *
+ * @since 2.0.0
+ *
+ * @param int $ID Optional. Post ID. Default is the current post from the loop.
+ * @return string|bool The mime type on success, false on failure.
+ */
+function get_post_mime_type($ID = '') {
+ $post = get_post($ID);
+
+ if ( is_object($post) )
+ return $post->post_mime_type;
+
+ return false;
+}
+
+/**
+ * Retrieve the post status based on the Post ID.
+ *
+ * If the post ID is of an attachment, then the parent post status will be given
+ * instead.
+ *
+ * @since 2.0.0
+ *
+ * @param int $ID Optional. Post ID. Default is the current post from the loop.
+ * @return string|bool Post status on success, false on failure.
+ */
+function get_post_status($ID = '') {
+ $post = get_post($ID);
+
+ if ( !is_object($post) )
+ return false;
+
+ if ( 'attachment' == $post->post_type ) {
+ if ( 'private' == $post->post_status )
+ return 'private';
+
+ // Unattached attachments are assumed to be published
+ if ( ( 'inherit' == $post->post_status ) && ( 0 == $post->post_parent) )
+ return 'publish';
+
+ // Inherit status from the parent
+ if ( $post->post_parent && ( $post->ID != $post->post_parent ) )
+ return get_post_status($post->post_parent);
+ }
+
+ return $post->post_status;
+}
+
+/**
+ * Retrieve all of the WordPress supported post statuses.
+ *
+ * Posts have a limited set of valid status values, this provides the
+ * post_status values and descriptions.
+ *
+ * @since 2.5.0
+ *
+ * @return array List of post statuses.
+ */
+function get_post_statuses() {
+ $status = array(
+ 'draft' => __('Draft'),
+ 'pending' => __('Pending Review'),
+ 'private' => __('Private'),
+ 'publish' => __('Published')
+ );
+
+ return $status;
+}
+
+/**
+ * Retrieve all of the WordPress support page statuses.
+ *
+ * Pages have a limited set of valid status values, this provides the
+ * post_status values and descriptions.
+ *
+ * @since 2.5.0
+ *
+ * @return array List of page statuses.
+ */
+function get_page_statuses() {
+ $status = array(
+ 'draft' => __('Draft'),
+ 'private' => __('Private'),
+ 'publish' => __('Published')
+ );
+
+ return $status;
+}
+
+/**
+ * Register a post status. Do not use before init.
+ *
+ * A simple function for creating or modifying a post status based on the
+ * parameters given. The function will accept an array (second optional
+ * parameter), along with a string for the post status name.
+ *
+ *
+ * Optional $args contents:
+ *
+ * label - A descriptive name for the post status marked for translation. Defaults to $post_status.
+ * public - Whether posts of this status should be shown in the front end of the site. Defaults to true.
+ * exclude_from_search - Whether to exclude posts with this post status from search results. Defaults to false.
+ * show_in_admin_all_list - Whether to include posts in the edit listing for their post type
+ * show_in_admin_status_list - Show in the list of statuses with post counts at the top of the edit
+ * listings, e.g. All (12) | Published (9) | My Custom Status (2) ...
+ *
+ * Arguments prefixed with an _underscore shouldn't be used by plugins and themes.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 3.0.0
+ * @uses $wp_post_statuses Inserts new post status object into the list
+ *
+ * @param string $post_status Name of the post status.
+ * @param array|string $args See above description.
+ */
+function register_post_status($post_status, $args = array()) {
+ global $wp_post_statuses;
+
+ if (!is_array($wp_post_statuses))
+ $wp_post_statuses = array();
+
+ // Args prefixed with an underscore are reserved for internal use.
+ $defaults = array(
+ 'label' => false,
+ 'label_count' => false,
+ 'exclude_from_search' => null,
+ '_builtin' => false,
+ 'public' => null,
+ 'internal' => null,
+ 'protected' => null,
+ 'private' => null,
+ 'publicly_queryable' => null,
+ 'show_in_admin_status_list' => null,
+ 'show_in_admin_all_list' => null,
+ );
+ $args = wp_parse_args($args, $defaults);
+ $args = (object) $args;
+
+ $post_status = sanitize_key($post_status);
+ $args->name = $post_status;
+
+ if ( null === $args->public && null === $args->internal && null === $args->protected && null === $args->private )
+ $args->internal = true;
+
+ if ( null === $args->public )
+ $args->public = false;
+
+ if ( null === $args->private )
+ $args->private = false;
+
+ if ( null === $args->protected )
+ $args->protected = false;
+
+ if ( null === $args->internal )
+ $args->internal = false;
+
+ if ( null === $args->publicly_queryable )
+ $args->publicly_queryable = $args->public;
+
+ if ( null === $args->exclude_from_search )
+ $args->exclude_from_search = $args->internal;
+
+ if ( null === $args->show_in_admin_all_list )
+ $args->show_in_admin_all_list = !$args->internal;
+
+ if ( null === $args->show_in_admin_status_list )
+ $args->show_in_admin_status_list = !$args->internal;
+
+ if ( false === $args->label )
+ $args->label = $post_status;
+
+ if ( false === $args->label_count )
+ $args->label_count = array( $args->label, $args->label );
+
+ $wp_post_statuses[$post_status] = $args;
+
+ return $args;
+}
+
+/**
+ * Retrieve a post status object by name
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 3.0.0
+ * @uses $wp_post_statuses
+ * @see register_post_status
+ * @see get_post_statuses
+ *
+ * @param string $post_status The name of a registered post status
+ * @return object A post status object
+ */
+function get_post_status_object( $post_status ) {
+ global $wp_post_statuses;
+
+ if ( empty($wp_post_statuses[$post_status]) )
+ return null;
+
+ return $wp_post_statuses[$post_status];
+}
+
+/**
+ * Get a list of all registered post status objects.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 3.0.0
+ * @uses $wp_post_statuses
+ * @see register_post_status
+ * @see get_post_status_object
+ *
+ * @param array|string $args An array of key => value arguments to match against the post status objects.
+ * @param string $output The type of output to return, either post status 'names' or 'objects'. 'names' is the default.
+ * @param string $operator The logical operation to perform. 'or' means only one element
+ * from the array needs to match; 'and' means all elements must match. The default is 'and'.
+ * @return array A list of post status names or objects
+ */
+function get_post_stati( $args = array(), $output = 'names', $operator = 'and' ) {
+ global $wp_post_statuses;
+
+ $field = ('names' == $output) ? 'name' : false;
+
+ return wp_filter_object_list($wp_post_statuses, $args, $operator, $field);
+}
+
+/**
+ * Whether the post type is hierarchical.
+ *
+ * A false return value might also mean that the post type does not exist.
+ *
+ * @since 3.0.0
+ * @see get_post_type_object
+ *
+ * @param string $post_type Post type name
+ * @return bool Whether post type is hierarchical.
+ */
+function is_post_type_hierarchical( $post_type ) {
+ if ( ! post_type_exists( $post_type ) )
+ return false;
+
+ $post_type = get_post_type_object( $post_type );
+ return $post_type->hierarchical;
+}
+
+/**
+ * Checks if a post type is registered.
+ *
+ * @since 3.0.0
+ * @uses get_post_type_object()
+ *
+ * @param string $post_type Post type name
+ * @return bool Whether post type is registered.
+ */
+function post_type_exists( $post_type ) {
+ return (bool) get_post_type_object( $post_type );
+}
+
+/**
+ * Retrieve the post type of the current post or of a given post.
+ *
+ * @since 2.1.0
+ *
+ * @param int|object $post Optional. Post ID or post object. Default is the current post from the loop.
+ * @return string|bool Post type on success, false on failure.
+ */
+function get_post_type( $post = null ) {
+ if ( $post = get_post( $post ) )
+ return $post->post_type;
+
+ return false;
+}
+
+/**
+ * Retrieve a post type object by name
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 3.0.0
+ * @uses $wp_post_types
+ * @see register_post_type
+ * @see get_post_types
+ *
+ * @param string $post_type The name of a registered post type
+ * @return object A post type object
+ */
+function get_post_type_object( $post_type ) {
+ global $wp_post_types;
+
+ if ( empty($wp_post_types[$post_type]) )
+ return null;
+
+ return $wp_post_types[$post_type];
+}
+
+/**
+ * Get a list of all registered post type objects.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.9.0
+ * @uses $wp_post_types
+ * @see register_post_type
+ *
+ * @param array|string $args An array of key => value arguments to match against the post type objects.
+ * @param string $output The type of output to return, either post type 'names' or 'objects'. 'names' is the default.
+ * @param string $operator The logical operation to perform. 'or' means only one element
+ * from the array needs to match; 'and' means all elements must match. The default is 'and'.
+ * @return array A list of post type names or objects
+ */
+function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) {
+ global $wp_post_types;
+
+ $field = ('names' == $output) ? 'name' : false;
+
+ return wp_filter_object_list($wp_post_types, $args, $operator, $field);
+}
+
+/**
+ * Register a post type. Do not use before init.
+ *
+ * A function for creating or modifying a post type based on the
+ * parameters given. The function will accept an array (second optional
+ * parameter), along with a string for the post type name.
+ *
+ * Optional $args contents:
+ *
+ * - label - Name of the post type shown in the menu. Usually plural. If not set, labels['name'] will be used.
+ * - labels - An array of labels for this post type.
+ * * If not set, post labels are inherited for non-hierarchical types and page labels for hierarchical ones.
+ * * You can see accepted values in {@link get_post_type_labels()}.
+ * - description - A short descriptive summary of what the post type is. Defaults to blank.
+ * - public - Whether a post type is intended for use publicly either via the admin interface or by front-end users.
+ * * Defaults to false.
+ * * While the default settings of exclude_from_search, publicly_queryable, show_ui, and show_in_nav_menus are
+ * inherited from public, each does not rely on this relationship and controls a very specific intention.
+ * - exclude_from_search - Whether to exclude posts with this post type from front end search results.
+ * * If not set, the opposite of public's current value is used.
+ * - publicly_queryable - Whether queries can be performed on the front end for the post type as part of parse_request().
+ * * ?post_type={post_type_key}
+ * * ?{post_type_key}={single_post_slug}
+ * * ?{post_type_query_var}={single_post_slug}
+ * * If not set, the default is inherited from public.
+ * - show_ui - Whether to generate a default UI for managing this post type in the admin.
+ * * If not set, the default is inherited from public.
+ * - show_in_nav_menus - Makes this post type available for selection in navigation menus.
+ * * If not set, the default is inherited from public.
+ * - show_in_menu - Where to show the post type in the admin menu.
+ * * If true, the post type is shown in its own top level menu.
+ * * If false, no menu is shown
+ * * If a string of an existing top level menu (eg. 'tools.php' or 'edit.php?post_type=page'), the post type will
+ * be placed as a sub menu of that.
+ * * show_ui must be true.
+ * * If not set, the default is inherited from show_ui
+ * - show_in_admin_bar - Makes this post type available via the admin bar.
+ * * If not set, the default is inherited from show_in_menu
+ * - menu_position - The position in the menu order the post type should appear.
+ * * show_in_menu must be true
+ * * Defaults to null, which places it at the bottom of its area.
+ * - menu_icon - The url to the icon to be used for this menu. Defaults to use the posts icon.
+ * - capability_type - The string to use to build the read, edit, and delete capabilities. Defaults to 'post'.
+ * * May be passed as an array to allow for alternative plurals when using this argument as a base to construct the
+ * capabilities, e.g. array('story', 'stories').
+ * - capabilities - Array of capabilities for this post type.
+ * * By default the capability_type is used as a base to construct capabilities.
+ * * You can see accepted values in {@link get_post_type_capabilities()}.
+ * - map_meta_cap - Whether to use the internal default meta capability handling. Defaults to false.
+ * - hierarchical - Whether the post type is hierarchical (e.g. page). Defaults to false.
+ * - supports - An alias for calling add_post_type_support() directly. Defaults to title and editor.
+ * * See {@link add_post_type_support()} for documentation.
+ * - register_meta_box_cb - Provide a callback function that will be called when setting up the
+ * meta boxes for the edit form. Do remove_meta_box() and add_meta_box() calls in the callback.
+ * - taxonomies - An array of taxonomy identifiers that will be registered for the post type.
+ * * Default is no taxonomies.
+ * * Taxonomies can be registered later with register_taxonomy() or register_taxonomy_for_object_type().
+ * - has_archive - True to enable post type archives. Default is false.
+ * * Will generate the proper rewrite rules if rewrite is enabled.
+ * - rewrite - Triggers the handling of rewrites for this post type. Defaults to true, using $post_type as slug.
+ * * To prevent rewrite, set to false.
+ * * To specify rewrite rules, an array can be passed with any of these keys
+ * * 'slug' => string Customize the permastruct slug. Defaults to $post_type key
+ * * 'with_front' => bool Should the permastruct be prepended with WP_Rewrite::$front. Defaults to true.
+ * * 'feeds' => bool Should a feed permastruct be built for this post type. Inherits default from has_archive.
+ * * 'pages' => bool Should the permastruct provide for pagination. Defaults to true.
+ * * 'ep_mask' => const Assign an endpoint mask.
+ * * If not specified and permalink_epmask is set, inherits from permalink_epmask.
+ * * If not specified and permalink_epmask is not set, defaults to EP_PERMALINK
+ * - query_var - Sets the query_var key for this post type. Defaults to $post_type key
+ * * If false, a post type cannot be loaded at ?{query_var}={post_slug}
+ * * If specified as a string, the query ?{query_var_string}={post_slug} will be valid.
+ * - can_export - Allows this post type to be exported. Defaults to true.
+ * - delete_with_user - Whether to delete posts of this type when deleting a user.
+ * * If true, posts of this type belonging to the user will be moved to trash when then user is deleted.
+ * * If false, posts of this type belonging to the user will *not* be trashed or deleted.
+ * * If not set (the default), posts are trashed if post_type_supports('author'). Otherwise posts are not trashed or deleted.
+ * - _builtin - true if this post type is a native or "built-in" post_type. THIS IS FOR INTERNAL USE ONLY!
+ * - _edit_link - URL segement to use for edit link of this post type. THIS IS FOR INTERNAL USE ONLY!
+ *
+ * @since 2.9.0
+ * @uses $wp_post_types Inserts new post type object into the list
+ *
+ * @param string $post_type Post type key, must not exceed 20 characters
+ * @param array|string $args See optional args description above.
+ * @return object|WP_Error the registered post type object, or an error object
+ */
+function register_post_type( $post_type, $args = array() ) {
+ global $wp_post_types, $wp_rewrite, $wp;
+
+ if ( !is_array($wp_post_types) )
+ $wp_post_types = array();
+
+ // Args prefixed with an underscore are reserved for internal use.
+ $defaults = array(
+ 'labels' => array(), 'description' => '', 'publicly_queryable' => null, 'exclude_from_search' => null,
+ 'capability_type' => 'post', 'capabilities' => array(), 'map_meta_cap' => null,
+ '_builtin' => false, '_edit_link' => 'post.php?post=%d', 'hierarchical' => false,
+ 'public' => false, 'rewrite' => true, 'has_archive' => false, 'query_var' => true,
+ 'supports' => array(), 'register_meta_box_cb' => null,
+ 'taxonomies' => array(), 'show_ui' => null, 'menu_position' => null, 'menu_icon' => null,
+ 'can_export' => true,
+ 'show_in_nav_menus' => null, 'show_in_menu' => null, 'show_in_admin_bar' => null,
+ 'delete_with_user' => null,
+ );
+ $args = wp_parse_args($args, $defaults);
+ $args = (object) $args;
+
+ $post_type = sanitize_key($post_type);
+ $args->name = $post_type;
+
+ if ( strlen( $post_type ) > 20 )
+ return new WP_Error( 'post_type_too_long', __( 'Post types cannot exceed 20 characters in length' ) );
+
+ // If not set, default to the setting for public.
+ if ( null === $args->publicly_queryable )
+ $args->publicly_queryable = $args->public;
+
+ // If not set, default to the setting for public.
+ if ( null === $args->show_ui )
+ $args->show_ui = $args->public;
+
+ // If not set, default to the setting for show_ui.
+ if ( null === $args->show_in_menu || ! $args->show_ui )
+ $args->show_in_menu = $args->show_ui;
+
+ // If not set, default to the whether the full UI is shown.
+ if ( null === $args->show_in_admin_bar )
+ $args->show_in_admin_bar = true === $args->show_in_menu;
+
+ // Whether to show this type in nav-menus.php. Defaults to the setting for public.
+ if ( null === $args->show_in_nav_menus )
+ $args->show_in_nav_menus = $args->public;
+
+ // If not set, default to true if not public, false if public.
+ if ( null === $args->exclude_from_search )
+ $args->exclude_from_search = !$args->public;
+
+ // Back compat with quirky handling in version 3.0. #14122
+ if ( empty( $args->capabilities ) && null === $args->map_meta_cap && in_array( $args->capability_type, array( 'post', 'page' ) ) )
+ $args->map_meta_cap = true;
+
+ if ( null === $args->map_meta_cap )
+ $args->map_meta_cap = false;
+
+ $args->cap = get_post_type_capabilities( $args );
+ unset($args->capabilities);
+
+ if ( is_array( $args->capability_type ) )
+ $args->capability_type = $args->capability_type[0];
+
+ if ( ! empty($args->supports) ) {
+ add_post_type_support($post_type, $args->supports);
+ unset($args->supports);
+ } elseif ( false !== $args->supports ) {
+ // Add default features
+ add_post_type_support($post_type, array('title', 'editor'));
+ }
+
+ if ( false !== $args->query_var && !empty($wp) ) {
+ if ( true === $args->query_var )
+ $args->query_var = $post_type;
+ else
+ $args->query_var = sanitize_title_with_dashes($args->query_var);
+ $wp->add_query_var($args->query_var);
+ }
+
+ if ( false !== $args->rewrite && ( is_admin() || '' != get_option('permalink_structure') ) ) {
+ if ( ! is_array( $args->rewrite ) )
+ $args->rewrite = array();
+ if ( empty( $args->rewrite['slug'] ) )
+ $args->rewrite['slug'] = $post_type;
+ if ( ! isset( $args->rewrite['with_front'] ) )
+ $args->rewrite['with_front'] = true;
+ if ( ! isset( $args->rewrite['pages'] ) )
+ $args->rewrite['pages'] = true;
+ if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
+ $args->rewrite['feeds'] = (bool) $args->has_archive;
+ if ( ! isset( $args->rewrite['ep_mask'] ) ) {
+ if ( isset( $args->permalink_epmask ) )
+ $args->rewrite['ep_mask'] = $args->permalink_epmask;
+ else
+ $args->rewrite['ep_mask'] = EP_PERMALINK;
+ }
+
+ if ( $args->hierarchical )
+ add_rewrite_tag("%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=");
+ else
+ add_rewrite_tag("%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=");
+
+ if ( $args->has_archive ) {
+ $archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
+ if ( $args->rewrite['with_front'] )
+ $archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
+ else
+ $archive_slug = $wp_rewrite->root . $archive_slug;
+
+ add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
+ if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
+ $feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
+ add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
+ add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
+ }
+ if ( $args->rewrite['pages'] )
+ add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
+ }
+
+ $permastruct_args = $args->rewrite;
+ $permastruct_args['feed'] = $permastruct_args['feeds'];
+ add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
+ }
+
+ if ( $args->register_meta_box_cb )
+ add_action('add_meta_boxes_' . $post_type, $args->register_meta_box_cb, 10, 1);
+
+ $args->labels = get_post_type_labels( $args );
+ $args->label = $args->labels->name;
+
+ $wp_post_types[$post_type] = $args;
+
+ add_action( 'future_' . $post_type, '_future_post_hook', 5, 2 );
+
+ foreach ( $args->taxonomies as $taxonomy ) {
+ register_taxonomy_for_object_type( $taxonomy, $post_type );
+ }
+
+ do_action( 'registered_post_type', $post_type, $args );
+
+ return $args;
+}
+
+/**
+ * Builds an object with all post type capabilities out of a post type object
+ *
+ * Post type capabilities use the 'capability_type' argument as a base, if the
+ * capability is not set in the 'capabilities' argument array or if the
+ * 'capabilities' argument is not supplied.
+ *
+ * The capability_type argument can optionally be registered as an array, with
+ * the first value being singular and the second plural, e.g. array('story, 'stories')
+ * Otherwise, an 's' will be added to the value for the plural form. After
+ * registration, capability_type will always be a string of the singular value.
+ *
+ * By default, seven keys are accepted as part of the capabilities array:
+ *
+ * - edit_post, read_post, and delete_post are meta capabilities, which are then
+ * generally mapped to corresponding primitive capabilities depending on the
+ * context, which would be the post being edited/read/deleted and the user or
+ * role being checked. Thus these capabilities would generally not be granted
+ * directly to users or roles.
+ *
+ * - edit_posts - Controls whether objects of this post type can be edited.
+ * - edit_others_posts - Controls whether objects of this type owned by other users
+ * can be edited. If the post type does not support an author, then this will
+ * behave like edit_posts.
+ * - publish_posts - Controls publishing objects of this post type.
+ * - read_private_posts - Controls whether private objects can be read.
+ *
+ * These four primitive capabilities are checked in core in various locations.
+ * There are also seven other primitive capabilities which are not referenced
+ * directly in core, except in map_meta_cap(), which takes the three aforementioned
+ * meta capabilities and translates them into one or more primitive capabilities
+ * that must then be checked against the user or role, depending on the context.
+ *
+ * - read - Controls whether objects of this post type can be read.
+ * - delete_posts - Controls whether objects of this post type can be deleted.
+ * - delete_private_posts - Controls whether private objects can be deleted.
+ * - delete_published_posts - Controls whether published objects can be deleted.
+ * - delete_others_posts - Controls whether objects owned by other users can be
+ * can be deleted. If the post type does not support an author, then this will
+ * behave like delete_posts.
+ * - edit_private_posts - Controls whether private objects can be edited.
+ * - edit_published_posts - Controls whether published objects can be edited.
+ *
+ * These additional capabilities are only used in map_meta_cap(). Thus, they are
+ * only assigned by default if the post type is registered with the 'map_meta_cap'
+ * argument set to true (default is false).
+ *
+ * @see map_meta_cap()
+ * @since 3.0.0
+ *
+ * @param object $args Post type registration arguments
+ * @return object object with all the capabilities as member variables
+ */
+function get_post_type_capabilities( $args ) {
+ if ( ! is_array( $args->capability_type ) )
+ $args->capability_type = array( $args->capability_type, $args->capability_type . 's' );
+
+ // Singular base for meta capabilities, plural base for primitive capabilities.
+ list( $singular_base, $plural_base ) = $args->capability_type;
+
+ $default_capabilities = array(
+ // Meta capabilities
+ 'edit_post' => 'edit_' . $singular_base,
+ 'read_post' => 'read_' . $singular_base,
+ 'delete_post' => 'delete_' . $singular_base,
+ // Primitive capabilities used outside of map_meta_cap():
+ 'edit_posts' => 'edit_' . $plural_base,
+ 'edit_others_posts' => 'edit_others_' . $plural_base,
+ 'publish_posts' => 'publish_' . $plural_base,
+ 'read_private_posts' => 'read_private_' . $plural_base,
+ );
+
+ // Primitive capabilities used within map_meta_cap():
+ if ( $args->map_meta_cap ) {
+ $default_capabilities_for_mapping = array(
+ 'read' => 'read',
+ 'delete_posts' => 'delete_' . $plural_base,
+ 'delete_private_posts' => 'delete_private_' . $plural_base,
+ 'delete_published_posts' => 'delete_published_' . $plural_base,
+ 'delete_others_posts' => 'delete_others_' . $plural_base,
+ 'edit_private_posts' => 'edit_private_' . $plural_base,
+ 'edit_published_posts' => 'edit_published_' . $plural_base,
+ );
+ $default_capabilities = array_merge( $default_capabilities, $default_capabilities_for_mapping );
+ }
+
+ $capabilities = array_merge( $default_capabilities, $args->capabilities );
+
+ // Post creation capability simply maps to edit_posts by default:
+ if ( ! isset( $capabilities['create_posts'] ) )
+ $capabilities['create_posts'] = $capabilities['edit_posts'];
+
+ // Remember meta capabilities for future reference.
+ if ( $args->map_meta_cap )
+ _post_type_meta_capabilities( $capabilities );
+
+ return (object) $capabilities;
+}
+
+/**
+ * Stores or returns a list of post type meta caps for map_meta_cap().
+ *
+ * @since 3.1.0
+ * @access private
+ */
+function _post_type_meta_capabilities( $capabilities = null ) {
+ static $meta_caps = array();
+ if ( null === $capabilities )
+ return $meta_caps;
+ foreach ( $capabilities as $core => $custom ) {
+ if ( in_array( $core, array( 'read_post', 'delete_post', 'edit_post' ) ) )
+ $meta_caps[ $custom ] = $core;
+ }
+}
+
+/**
+ * Builds an object with all post type labels out of a post type object
+ *
+ * Accepted keys of the label array in the post type object:
+ * - name - general name for the post type, usually plural. The same and overridden by $post_type_object->label. Default is Posts/Pages
+ * - singular_name - name for one object of this post type. Default is Post/Page
+ * - add_new - Default is Add New for both hierarchical and non-hierarchical types. When internationalizing this string, please use a {@link http://codex.wordpress.org/I18n_for_WordPress_Developers#Disambiguation_by_context gettext context} matching your post type. Example: <code>_x('Add New', 'product');</code>
+ * - add_new_item - Default is Add New Post/Add New Page
+ * - edit_item - Default is Edit Post/Edit Page
+ * - new_item - Default is New Post/New Page
+ * - view_item - Default is View Post/View Page
+ * - search_items - Default is Search Posts/Search Pages
+ * - not_found - Default is No posts found/No pages found
+ * - not_found_in_trash - Default is No posts found in Trash/No pages found in Trash
+ * - parent_item_colon - This string isn't used on non-hierarchical types. In hierarchical ones the default is Parent Page:
+ * - all_items - String for the submenu. Default is All Posts/All Pages
+ * - menu_name - Default is the same as <code>name</code>
+ *
+ * Above, the first default value is for non-hierarchical post types (like posts) and the second one is for hierarchical post types (like pages).
+ *
+ * @since 3.0.0
+ * @param object $post_type_object
+ * @return object object with all the labels as member variables
+ */
+function get_post_type_labels( $post_type_object ) {
+ $nohier_vs_hier_defaults = array(
+ 'name' => array( _x('Posts', 'post type general name'), _x('Pages', 'post type general name') ),
+ 'singular_name' => array( _x('Post', 'post type singular name'), _x('Page', 'post type singular name') ),
+ 'add_new' => array( _x('Add New', 'post'), _x('Add New', 'page') ),
+ 'add_new_item' => array( __('Add New Post'), __('Add New Page') ),
+ 'edit_item' => array( __('Edit Post'), __('Edit Page') ),
+ 'new_item' => array( __('New Post'), __('New Page') ),
+ 'view_item' => array( __('View Post'), __('View Page') ),
+ 'search_items' => array( __('Search Posts'), __('Search Pages') ),
+ 'not_found' => array( __('No posts found.'), __('No pages found.') ),
+ 'not_found_in_trash' => array( __('No posts found in Trash.'), __('No pages found in Trash.') ),
+ 'parent_item_colon' => array( null, __('Parent Page:') ),
+ 'all_items' => array( __( 'All Posts' ), __( 'All Pages' ) )
+ );
+ $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
+
+ $labels = _get_custom_object_labels( $post_type_object, $nohier_vs_hier_defaults );
+
+ $post_type = $post_type_object->name;
+ return apply_filters( "post_type_labels_{$post_type}", $labels );
+}
+
+/**
+ * Builds an object with custom-something object (post type, taxonomy) labels out of a custom-something object
+ *
+ * @access private
+ * @since 3.0.0
+ */
+function _get_custom_object_labels( $object, $nohier_vs_hier_defaults ) {
+
+ if ( isset( $object->label ) && empty( $object->labels['name'] ) )
+ $object->labels['name'] = $object->label;
+
+ if ( !isset( $object->labels['singular_name'] ) && isset( $object->labels['name'] ) )
+ $object->labels['singular_name'] = $object->labels['name'];
+
+ if ( ! isset( $object->labels['name_admin_bar'] ) )
+ $object->labels['name_admin_bar'] = isset( $object->labels['singular_name'] ) ? $object->labels['singular_name'] : $object->name;
+
+ if ( !isset( $object->labels['menu_name'] ) && isset( $object->labels['name'] ) )
+ $object->labels['menu_name'] = $object->labels['name'];
+
+ if ( !isset( $object->labels['all_items'] ) && isset( $object->labels['menu_name'] ) )
+ $object->labels['all_items'] = $object->labels['menu_name'];
+
+ foreach ( $nohier_vs_hier_defaults as $key => $value )
+ $defaults[$key] = $object->hierarchical ? $value[1] : $value[0];
+
+ $labels = array_merge( $defaults, $object->labels );
+ return (object)$labels;
+}
+
+/**
+ * Adds submenus for post types.
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _add_post_type_submenus() {
+ foreach ( get_post_types( array( 'show_ui' => true ) ) as $ptype ) {
+ $ptype_obj = get_post_type_object( $ptype );
+ // Submenus only.
+ if ( ! $ptype_obj->show_in_menu || $ptype_obj->show_in_menu === true )
+ continue;
+ add_submenu_page( $ptype_obj->show_in_menu, $ptype_obj->labels->name, $ptype_obj->labels->all_items, $ptype_obj->cap->edit_posts, "edit.php?post_type=$ptype" );
+ }
+}
+add_action( 'admin_menu', '_add_post_type_submenus' );
+
+/**
+ * Register support of certain features for a post type.
+ *
+ * All features are directly associated with a functional area of the edit screen, such as the
+ * editor or a meta box: 'title', 'editor', 'comments', 'revisions', 'trackbacks', 'author',
+ * 'excerpt', 'page-attributes', 'thumbnail', and 'custom-fields'.
+ *
+ * Additionally, the 'revisions' feature dictates whether the post type will store revisions,
+ * and the 'comments' feature dictates whether the comments count will show on the edit screen.
+ *
+ * @since 3.0.0
+ * @param string $post_type The post type for which to add the feature
+ * @param string|array $feature the feature being added, can be an array of feature strings or a single string
+ */
+function add_post_type_support( $post_type, $feature ) {
+ global $_wp_post_type_features;
+
+ $features = (array) $feature;
+ foreach ($features as $feature) {
+ if ( func_num_args() == 2 )
+ $_wp_post_type_features[$post_type][$feature] = true;
+ else
+ $_wp_post_type_features[$post_type][$feature] = array_slice( func_get_args(), 2 );
+ }
+}
+
+/**
+ * Remove support for a feature from a post type.
+ *
+ * @since 3.0.0
+ * @param string $post_type The post type for which to remove the feature
+ * @param string $feature The feature being removed
+ */
+function remove_post_type_support( $post_type, $feature ) {
+ global $_wp_post_type_features;
+
+ if ( isset( $_wp_post_type_features[$post_type][$feature] ) )
+ unset( $_wp_post_type_features[$post_type][$feature] );
+}
+
+/**
+ * Get all the post type features
+ *
+ * @since 3.4.0
+ * @param string $post_type The post type
+ * @return array
+ */
+
+function get_all_post_type_supports( $post_type ) {
+ global $_wp_post_type_features;
+
+ if ( isset( $_wp_post_type_features[$post_type] ) )
+ return $_wp_post_type_features[$post_type];
+
+ return array();
+}
+
+/**
+ * Checks a post type's support for a given feature
+ *
+ * @since 3.0.0
+ * @param string $post_type The post type being checked
+ * @param string $feature the feature being checked
+ * @return boolean
+ */
+
+function post_type_supports( $post_type, $feature ) {
+ global $_wp_post_type_features;
+
+ return ( isset( $_wp_post_type_features[$post_type][$feature] ) );
+}
+
+/**
+ * Updates the post type for the post ID.
+ *
+ * The page or post cache will be cleaned for the post ID.
+ *
+ * @since 2.5.0
+ *
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID to change post type. Not actually optional.
+ * @param string $post_type Optional, default is post. Supported values are 'post' or 'page' to
+ * name a few.
+ * @return int Amount of rows changed. Should be 1 for success and 0 for failure.
+ */
+function set_post_type( $post_id = 0, $post_type = 'post' ) {
+ global $wpdb;
+
+ $post_type = sanitize_post_field('post_type', $post_type, $post_id, 'db');
+ $return = $wpdb->update( $wpdb->posts, array('post_type' => $post_type), array('ID' => $post_id) );
+
+ clean_post_cache( $post_id );
+
+ return $return;
+}
+
+/**
+ * Retrieve list of latest posts or posts matching criteria.
+ *
+ * The defaults are as follows:
+ * 'numberposts' - Default is 5. Total number of posts to retrieve.
+ * 'offset' - Default is 0. See {@link WP_Query::query()} for more.
+ * 'category' - What category to pull the posts from.
+ * 'orderby' - Default is 'post_date'. How to order the posts.
+ * 'order' - Default is 'DESC'. The order to retrieve the posts.
+ * 'include' - See {@link WP_Query::query()} for more.
+ * 'exclude' - See {@link WP_Query::query()} for more.
+ * 'meta_key' - See {@link WP_Query::query()} for more.
+ * 'meta_value' - See {@link WP_Query::query()} for more.
+ * 'post_type' - Default is 'post'. Can be 'page', or 'attachment' to name a few.
+ * 'post_parent' - The parent of the post or post type.
+ * 'post_status' - Default is 'publish'. Post status to retrieve.
+ *
+ * @since 1.2.0
+ * @uses WP_Query::query() See for more default arguments and information.
+ * @link http://codex.wordpress.org/Template_Tags/get_posts
+ *
+ * @param array $args Optional. Overrides defaults.
+ * @return array List of posts.
+ */
+function get_posts($args = null) {
+ $defaults = array(
+ 'numberposts' => 5, 'offset' => 0,
+ 'category' => 0, 'orderby' => 'post_date',
+ 'order' => 'DESC', 'include' => array(),
+ 'exclude' => array(), 'meta_key' => '',
+ 'meta_value' =>'', 'post_type' => 'post',
+ 'suppress_filters' => true
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ if ( empty( $r['post_status'] ) )
+ $r['post_status'] = ( 'attachment' == $r['post_type'] ) ? 'inherit' : 'publish';
+ if ( ! empty($r['numberposts']) && empty($r['posts_per_page']) )
+ $r['posts_per_page'] = $r['numberposts'];
+ if ( ! empty($r['category']) )
+ $r['cat'] = $r['category'];
+ if ( ! empty($r['include']) ) {
+ $incposts = wp_parse_id_list( $r['include'] );
+ $r['posts_per_page'] = count($incposts); // only the number of posts included
+ $r['post__in'] = $incposts;
+ } elseif ( ! empty($r['exclude']) )
+ $r['post__not_in'] = wp_parse_id_list( $r['exclude'] );
+
+ $r['ignore_sticky_posts'] = true;
+ $r['no_found_rows'] = true;
+
+ $get_posts = new WP_Query;
+ return $get_posts->query($r);
+
+}
+
+//
+// Post meta functions
+//
+
+/**
+ * Add meta data field to a post.
+ *
+ * Post meta data is called "Custom Fields" on the Administration Screen.
+ *
+ * @since 1.5.0
+ * @link http://codex.wordpress.org/Function_Reference/add_post_meta
+ *
+ * @param int $post_id Post ID.
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return int|bool Meta ID on success, false on failure.
+ */
+function add_post_meta($post_id, $meta_key, $meta_value, $unique = false) {
+ // make sure meta is added to the post, not a revision
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ return add_metadata('post', $post_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a post.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 1.5.0
+ * @link http://codex.wordpress.org/Function_Reference/delete_post_meta
+ *
+ * @param int $post_id post ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool True on success, false on failure.
+ */
+function delete_post_meta($post_id, $meta_key, $meta_value = '') {
+ // make sure meta is added to the post, not a revision
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ return delete_metadata('post', $post_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve post meta field for a post.
+ *
+ * @since 1.5.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_meta
+ *
+ * @param int $post_id Post ID.
+ * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
+ * is true.
+ */
+function get_post_meta($post_id, $key = '', $single = false) {
+ return get_metadata('post', $post_id, $key, $single);
+}
+
+/**
+ * Update post meta field based on post ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and post ID.
+ *
+ * If the meta field for the post does not exist, it will be added.
+ *
+ * @since 1.5.0
+ * @link http://codex.wordpress.org/Function_Reference/update_post_meta
+ *
+ * @param int $post_id Post ID.
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool True on success, false on failure.
+ */
+function update_post_meta($post_id, $meta_key, $meta_value, $prev_value = '') {
+ // make sure meta is added to the post, not a revision
+ if ( $the_post = wp_is_post_revision($post_id) )
+ $post_id = $the_post;
+
+ return update_metadata('post', $post_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Delete everything from post meta matching meta key.
+ *
+ * @since 2.3.0
+ *
+ * @param string $post_meta_key Key to search for when deleting.
+ * @return bool Whether the post meta key was deleted from the database
+ */
+function delete_post_meta_by_key($post_meta_key) {
+ return delete_metadata( 'post', null, $post_meta_key, '', true );
+}
+
+/**
+ * Retrieve post meta fields, based on post ID.
+ *
+ * The post meta fields are retrieved from the cache where possible,
+ * so the function is optimized to be called more than once.
+ *
+ * @since 1.2.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_custom
+ *
+ * @param int $post_id Post ID.
+ * @return array
+ */
+function get_post_custom( $post_id = 0 ) {
+ $post_id = absint( $post_id );
+ if ( ! $post_id )
+ $post_id = get_the_ID();
+
+ return get_post_meta( $post_id );
+}
+
+/**
+ * Retrieve meta field names for a post.
+ *
+ * If there are no meta fields, then nothing (null) will be returned.
+ *
+ * @since 1.2.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_custom_keys
+ *
+ * @param int $post_id post ID
+ * @return array|null Either array of the keys, or null if keys could not be retrieved.
+ */
+function get_post_custom_keys( $post_id = 0 ) {
+ $custom = get_post_custom( $post_id );
+
+ if ( !is_array($custom) )
+ return;
+
+ if ( $keys = array_keys($custom) )
+ return $keys;
+}
+
+/**
+ * Retrieve values for a custom post field.
+ *
+ * The parameters must not be considered optional. All of the post meta fields
+ * will be retrieved and only the meta field key values returned.
+ *
+ * @since 1.2.0
+ * @link http://codex.wordpress.org/Function_Reference/get_post_custom_values
+ *
+ * @param string $key Meta field key.
+ * @param int $post_id Post ID
+ * @return array Meta field values.
+ */
+function get_post_custom_values( $key = '', $post_id = 0 ) {
+ if ( !$key )
+ return null;
+
+ $custom = get_post_custom($post_id);
+
+ return isset($custom[$key]) ? $custom[$key] : null;
+}
+
+/**
+ * Check if post is sticky.
+ *
+ * Sticky posts should remain at the top of The Loop. If the post ID is not
+ * given, then The Loop ID for the current post will be used.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Optional. Post ID.
+ * @return bool Whether post is sticky.
+ */
+function is_sticky( $post_id = 0 ) {
+ $post_id = absint( $post_id );
+
+ if ( ! $post_id )
+ $post_id = get_the_ID();
+
+ $stickies = get_option( 'sticky_posts' );
+
+ if ( ! is_array( $stickies ) )
+ return false;
+
+ if ( in_array( $post_id, $stickies ) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Sanitize every post field.
+ *
+ * If the context is 'raw', then the post object or array will get minimal santization of the int fields.
+ *
+ * @since 2.3.0
+ * @uses sanitize_post_field() Used to sanitize the fields.
+ *
+ * @param object|WP_Post|array $post The Post Object or Array
+ * @param string $context Optional, default is 'display'. How to sanitize post fields.
+ * @return object|WP_Post|array The now sanitized Post Object or Array (will be the same type as $post)
+ */
+function sanitize_post($post, $context = 'display') {
+ if ( is_object($post) ) {
+ // Check if post already filtered for this context
+ if ( isset($post->filter) && $context == $post->filter )
+ return $post;
+ if ( !isset($post->ID) )
+ $post->ID = 0;
+ foreach ( array_keys(get_object_vars($post)) as $field )
+ $post->$field = sanitize_post_field($field, $post->$field, $post->ID, $context);
+ $post->filter = $context;
+ } else {
+ // Check if post already filtered for this context
+ if ( isset($post['filter']) && $context == $post['filter'] )
+ return $post;
+ if ( !isset($post['ID']) )
+ $post['ID'] = 0;
+ foreach ( array_keys($post) as $field )
+ $post[$field] = sanitize_post_field($field, $post[$field], $post['ID'], $context);
+ $post['filter'] = $context;
+ }
+ return $post;
+}
+
+/**
+ * Sanitize post field based on context.
+ *
+ * Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
+ * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
+ * when calling filters.
+ *
+ * @since 2.3.0
+ * @uses apply_filters() Calls 'edit_$field' and '{$field_no_prefix}_edit_pre' passing $value and
+ * $post_id if $context == 'edit' and field name prefix == 'post_'.
+ *
+ * @uses apply_filters() Calls 'edit_post_$field' passing $value and $post_id if $context == 'db'.
+ * @uses apply_filters() Calls 'pre_$field' passing $value if $context == 'db' and field name prefix == 'post_'.
+ * @uses apply_filters() Calls '{$field}_pre' passing $value if $context == 'db' and field name prefix != 'post_'.
+ *
+ * @uses apply_filters() Calls '$field' passing $value, $post_id and $context if $context == anything
+ * other than 'raw', 'edit' and 'db' and field name prefix == 'post_'.
+ * @uses apply_filters() Calls 'post_$field' passing $value if $context == anything other than 'raw',
+ * 'edit' and 'db' and field name prefix != 'post_'.
+ *
+ * @param string $field The Post Object field name.
+ * @param mixed $value The Post Object value.
+ * @param int $post_id Post ID.
+ * @param string $context How to sanitize post fields. Looks for 'raw', 'edit', 'db', 'display',
+ * 'attribute' and 'js'.
+ * @return mixed Sanitized value.
+ */
+function sanitize_post_field($field, $value, $post_id, $context) {
+ $int_fields = array('ID', 'post_parent', 'menu_order');
+ if ( in_array($field, $int_fields) )
+ $value = (int) $value;
+
+ // Fields which contain arrays of ints.
+ $array_int_fields = array( 'ancestors' );
+ if ( in_array($field, $array_int_fields) ) {
+ $value = array_map( 'absint', $value);
+ return $value;
+ }
+
+ if ( 'raw' == $context )
+ return $value;
+
+ $prefixed = false;
+ if ( false !== strpos($field, 'post_') ) {
+ $prefixed = true;
+ $field_no_prefix = str_replace('post_', '', $field);
+ }
+
+ if ( 'edit' == $context ) {
+ $format_to_edit = array('post_content', 'post_excerpt', 'post_title', 'post_password');
+
+ if ( $prefixed ) {
+ $value = apply_filters("edit_{$field}", $value, $post_id);
+ // Old school
+ $value = apply_filters("{$field_no_prefix}_edit_pre", $value, $post_id);
+ } else {
+ $value = apply_filters("edit_post_{$field}", $value, $post_id);
+ }
+
+ if ( in_array($field, $format_to_edit) ) {
+ if ( 'post_content' == $field )
+ $value = format_to_edit($value, user_can_richedit());
+ else
+ $value = format_to_edit($value);
+ } else {
+ $value = esc_attr($value);
+ }
+ } else if ( 'db' == $context ) {
+ if ( $prefixed ) {
+ $value = apply_filters("pre_{$field}", $value);
+ $value = apply_filters("{$field_no_prefix}_save_pre", $value);
+ } else {
+ $value = apply_filters("pre_post_{$field}", $value);
+ $value = apply_filters("{$field}_pre", $value);
+ }
+ } else {
+ // Use display filters by default.
+ if ( $prefixed )
+ $value = apply_filters($field, $value, $post_id, $context);
+ else
+ $value = apply_filters("post_{$field}", $value, $post_id, $context);
+ }
+
+ if ( 'attribute' == $context )
+ $value = esc_attr($value);
+ else if ( 'js' == $context )
+ $value = esc_js($value);
+
+ return $value;
+}
+
+/**
+ * Make a post sticky.
+ *
+ * Sticky posts should be displayed at the top of the front page.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Post ID.
+ */
+function stick_post($post_id) {
+ $stickies = get_option('sticky_posts');
+
+ if ( !is_array($stickies) )
+ $stickies = array($post_id);
+
+ if ( ! in_array($post_id, $stickies) )
+ $stickies[] = $post_id;
+
+ update_option('sticky_posts', $stickies);
+}
+
+/**
+ * Unstick a post.
+ *
+ * Sticky posts should be displayed at the top of the front page.
+ *
+ * @since 2.7.0
+ *
+ * @param int $post_id Post ID.
+ */
+function unstick_post($post_id) {
+ $stickies = get_option('sticky_posts');
+
+ if ( !is_array($stickies) )
+ return;
+
+ if ( ! in_array($post_id, $stickies) )
+ return;
+
+ $offset = array_search($post_id, $stickies);
+ if ( false === $offset )
+ return;
+
+ array_splice($stickies, $offset, 1);
+
+ update_option('sticky_posts', $stickies);
+}
+
+/**
+ * Count number of posts of a post type and is user has permissions to view.
+ *
+ * This function provides an efficient method of finding the amount of post's
+ * type a blog has. Another method is to count the amount of items in
+ * get_posts(), but that method has a lot of overhead with doing so. Therefore,
+ * when developing for 2.5+, use this function instead.
+ *
+ * The $perm parameter checks for 'readable' value and if the user can read
+ * private posts, it will display that for the user that is signed in.
+ *
+ * @since 2.5.0
+ * @link http://codex.wordpress.org/Template_Tags/wp_count_posts
+ *
+ * @param string $type Optional. Post type to retrieve count
+ * @param string $perm Optional. 'readable' or empty.
+ * @return object Number of posts for each status
+ */
+function wp_count_posts( $type = 'post', $perm = '' ) {
+ global $wpdb;
+
+ if ( ! post_type_exists( $type ) )
+ return new stdClass;
+
+ $user = wp_get_current_user();
+
+ $cache_key = $type;
+
+ $query = "SELECT post_status, COUNT( * ) AS num_posts FROM {$wpdb->posts} WHERE post_type = %s";
+ if ( 'readable' == $perm && is_user_logged_in() ) {
+ $post_type_object = get_post_type_object($type);
+ if ( !current_user_can( $post_type_object->cap->read_private_posts ) ) {
+ $cache_key .= '_' . $perm . '_' . $user->ID;
+ $query .= " AND (post_status != 'private' OR ( post_author = '$user->ID' AND post_status = 'private' ))";
+ }
+ }
+ $query .= ' GROUP BY post_status';
+
+ $count = wp_cache_get($cache_key, 'counts');
+ if ( false !== $count )
+ return $count;
+
+ $count = $wpdb->get_results( $wpdb->prepare( $query, $type ), ARRAY_A );
+
+ $stats = array();
+ foreach ( get_post_stati() as $state )
+ $stats[$state] = 0;
+
+ foreach ( (array) $count as $row )
+ $stats[$row['post_status']] = $row['num_posts'];
+
+ $stats = (object) $stats;
+ wp_cache_set($cache_key, $stats, 'counts');
+
+ return $stats;
+}
+
+/**
+ * Count number of attachments for the mime type(s).
+ *
+ * If you set the optional mime_type parameter, then an array will still be
+ * returned, but will only have the item you are looking for. It does not give
+ * you the number of attachments that are children of a post. You can get that
+ * by counting the number of children that post has.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $mime_type Optional. Array or comma-separated list of MIME patterns.
+ * @return array Number of posts for each mime type.
+ */
+function wp_count_attachments( $mime_type = '' ) {
+ global $wpdb;
+
+ $and = wp_post_mime_type_where( $mime_type );
+ $count = $wpdb->get_results( "SELECT post_mime_type, COUNT( * ) AS num_posts FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status != 'trash' $and GROUP BY post_mime_type", ARRAY_A );
+
+ $stats = array();
+ foreach( (array) $count as $row ) {
+ $stats[$row['post_mime_type']] = $row['num_posts'];
+ }
+ $stats['trash'] = $wpdb->get_var( "SELECT COUNT( * ) FROM $wpdb->posts WHERE post_type = 'attachment' AND post_status = 'trash' $and");
+
+ return (object) $stats;
+}
+
+/**
+ * Get default post mime types
+ *
+ * @since 2.9.0
+ *
+ * @return array
+ */
+function get_post_mime_types() {
+ $post_mime_types = array( // array( adj, noun )
+ 'image' => array(__('Images'), __('Manage Images'), _n_noop('Image <span class="count">(%s)</span>', 'Images <span class="count">(%s)</span>')),
+ 'audio' => array(__('Audio'), __('Manage Audio'), _n_noop('Audio <span class="count">(%s)</span>', 'Audio <span class="count">(%s)</span>')),
+ 'video' => array(__('Video'), __('Manage Video'), _n_noop('Video <span class="count">(%s)</span>', 'Video <span class="count">(%s)</span>')),
+ );
+
+ return apply_filters('post_mime_types', $post_mime_types);
+}
+
+/**
+ * Check a MIME-Type against a list.
+ *
+ * If the wildcard_mime_types parameter is a string, it must be comma separated
+ * list. If the real_mime_types is a string, it is also comma separated to
+ * create the list.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $wildcard_mime_types e.g. audio/mpeg or image (same as image/*) or
+ * flash (same as *flash*).
+ * @param string|array $real_mime_types post_mime_type values
+ * @return array array(wildcard=>array(real types))
+ */
+function wp_match_mime_types($wildcard_mime_types, $real_mime_types) {
+ $matches = array();
+ if ( is_string($wildcard_mime_types) )
+ $wildcard_mime_types = array_map('trim', explode(',', $wildcard_mime_types));
+ if ( is_string($real_mime_types) )
+ $real_mime_types = array_map('trim', explode(',', $real_mime_types));
+ $wild = '[-._a-z0-9]*';
+ foreach ( (array) $wildcard_mime_types as $type ) {
+ $type = str_replace('*', $wild, $type);
+ $patternses[1][$type] = "^$type$";
+ if ( false === strpos($type, '/') ) {
+ $patternses[2][$type] = "^$type/";
+ $patternses[3][$type] = $type;
+ }
+ }
+ asort($patternses);
+ foreach ( $patternses as $patterns )
+ foreach ( $patterns as $type => $pattern )
+ foreach ( (array) $real_mime_types as $real )
+ if ( preg_match("#$pattern#", $real) && ( empty($matches[$type]) || false === array_search($real, $matches[$type]) ) )
+ $matches[$type][] = $real;
+ return $matches;
+}
+
+/**
+ * Convert MIME types into SQL.
+ *
+ * @since 2.5.0
+ *
+ * @param string|array $post_mime_types List of mime types or comma separated string of mime types.
+ * @param string $table_alias Optional. Specify a table alias, if needed.
+ * @return string The SQL AND clause for mime searching.
+ */
+function wp_post_mime_type_where($post_mime_types, $table_alias = '') {
+ $where = '';
+ $wildcards = array('', '%', '%/%');
+ if ( is_string($post_mime_types) )
+ $post_mime_types = array_map('trim', explode(',', $post_mime_types));
+ foreach ( (array) $post_mime_types as $mime_type ) {
+ $mime_type = preg_replace('/\s/', '', $mime_type);
+ $slashpos = strpos($mime_type, '/');
+ if ( false !== $slashpos ) {
+ $mime_group = preg_replace('/[^-*.a-zA-Z0-9]/', '', substr($mime_type, 0, $slashpos));
+ $mime_subgroup = preg_replace('/[^-*.+a-zA-Z0-9]/', '', substr($mime_type, $slashpos + 1));
+ if ( empty($mime_subgroup) )
+ $mime_subgroup = '*';
+ else
+ $mime_subgroup = str_replace('/', '', $mime_subgroup);
+ $mime_pattern = "$mime_group/$mime_subgroup";
+ } else {
+ $mime_pattern = preg_replace('/[^-*.a-zA-Z0-9]/', '', $mime_type);
+ if ( false === strpos($mime_pattern, '*') )
+ $mime_pattern .= '/*';
+ }
+
+ $mime_pattern = preg_replace('/\*+/', '%', $mime_pattern);
+
+ if ( in_array( $mime_type, $wildcards ) )
+ return '';
+
+ if ( false !== strpos($mime_pattern, '%') )
+ $wheres[] = empty($table_alias) ? "post_mime_type LIKE '$mime_pattern'" : "$table_alias.post_mime_type LIKE '$mime_pattern'";
+ else
+ $wheres[] = empty($table_alias) ? "post_mime_type = '$mime_pattern'" : "$table_alias.post_mime_type = '$mime_pattern'";
+ }
+ if ( !empty($wheres) )
+ $where = ' AND (' . join(' OR ', $wheres) . ') ';
+ return $where;
+}
+
+/**
+ * Trashes or deletes a post or page.
+ *
+ * When the post and page is permanently deleted, everything that is tied to it is deleted also.
+ * This includes comments, post meta fields, and terms associated with the post.
+ *
+ * The post or page is moved to trash instead of permanently deleted unless trash is
+ * disabled, item is already in the trash, or $force_delete is true.
+ *
+ * @since 1.0.0
+ * @uses do_action() on 'delete_post' before deletion unless post type is 'attachment'.
+ * @uses do_action() on 'deleted_post' after deletion unless post type is 'attachment'.
+ * @uses wp_delete_attachment() if post type is 'attachment'.
+ * @uses wp_trash_post() if item should be trashed.
+ *
+ * @param int $postid Post ID.
+ * @param bool $force_delete Whether to bypass trash and force deletion. Defaults to false.
+ * @return mixed False on failure
+ */
+function wp_delete_post( $postid = 0, $force_delete = false ) {
+ global $wpdb;
+
+ if ( !$post = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $postid)) )
+ return $post;
+
+ if ( !$force_delete && ( $post->post_type == 'post' || $post->post_type == 'page') && get_post_status( $postid ) != 'trash' && EMPTY_TRASH_DAYS )
+ return wp_trash_post($postid);
+
+ if ( $post->post_type == 'attachment' )
+ return wp_delete_attachment( $postid, $force_delete );
+
+ do_action('before_delete_post', $postid);
+
+ delete_post_meta($postid,'_wp_trash_meta_status');
+ delete_post_meta($postid,'_wp_trash_meta_time');
+
+ wp_delete_object_term_relationships($postid, get_object_taxonomies($post->post_type));
+
+ $parent_data = array( 'post_parent' => $post->post_parent );
+ $parent_where = array( 'post_parent' => $postid );
+
+ if ( is_post_type_hierarchical( $post->post_type ) ) {
+ // Point children of this page to its parent, also clean the cache of affected children
+ $children_query = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $postid, $post->post_type );
+ $children = $wpdb->get_results( $children_query );
+
+ $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => $post->post_type ) );
+ }
+
+ if ( 'page' == $post->post_type) {
+ // if the page is defined in option page_on_front or post_for_posts,
+ // adjust the corresponding options
+ if ( get_option('page_on_front') == $postid ) {
+ update_option('show_on_front', 'posts');
+ delete_option('page_on_front');
+ }
+ if ( get_option('page_for_posts') == $postid ) {
+ delete_option('page_for_posts');
+ }
+ } else {
+ unstick_post($postid);
+ }
+
+ // Do raw query. wp_get_post_revisions() is filtered
+ $revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $postid ) );
+ // Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
+ foreach ( $revision_ids as $revision_id )
+ wp_delete_post_revision( $revision_id );
+
+ // Point all attachments to this post up one level
+ $wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
+
+ $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ));
+ foreach ( $comment_ids as $comment_id )
+ wp_delete_comment( $comment_id, true );
+
+ $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $postid ));
+ foreach ( $post_meta_ids as $mid )
+ delete_metadata_by_mid( 'post', $mid );
+
+ do_action( 'delete_post', $postid );
+ $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) );
+ do_action( 'deleted_post', $postid );
+
+ clean_post_cache( $post );
+
+ if ( is_post_type_hierarchical( $post->post_type ) && $children ) {
+ foreach ( $children as $child )
+ clean_post_cache( $child );
+ }
+
+ wp_clear_scheduled_hook('publish_future_post', array( $postid ) );
+
+ do_action('after_delete_post', $postid);
+
+ return $post;
+}
+
+/**
+ * Moves a post or page to the Trash
+ *
+ * If trash is disabled, the post or page is permanently deleted.
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'trash_post' before trashing
+ * @uses do_action() on 'trashed_post' after trashing
+ * @uses wp_delete_post() if trash is disabled
+ *
+ * @param int $post_id Post ID.
+ * @return mixed False on failure
+ */
+function wp_trash_post($post_id = 0) {
+ if ( !EMPTY_TRASH_DAYS )
+ return wp_delete_post($post_id, true);
+
+ if ( !$post = get_post($post_id, ARRAY_A) )
+ return $post;
+
+ if ( $post['post_status'] == 'trash' )
+ return false;
+
+ do_action('wp_trash_post', $post_id);
+
+ add_post_meta($post_id,'_wp_trash_meta_status', $post['post_status']);
+ add_post_meta($post_id,'_wp_trash_meta_time', time());
+
+ $post['post_status'] = 'trash';
+ wp_insert_post($post);
+
+ wp_trash_post_comments($post_id);
+
+ do_action('trashed_post', $post_id);
+
+ return $post;
+}
+
+/**
+ * Restores a post or page from the Trash
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'untrash_post' before undeletion
+ * @uses do_action() on 'untrashed_post' after undeletion
+ *
+ * @param int $post_id Post ID.
+ * @return mixed False on failure
+ */
+function wp_untrash_post($post_id = 0) {
+ if ( !$post = get_post($post_id, ARRAY_A) )
+ return $post;
+
+ if ( $post['post_status'] != 'trash' )
+ return false;
+
+ do_action('untrash_post', $post_id);
+
+ $post_status = get_post_meta($post_id, '_wp_trash_meta_status', true);
+
+ $post['post_status'] = $post_status;
+
+ delete_post_meta($post_id, '_wp_trash_meta_status');
+ delete_post_meta($post_id, '_wp_trash_meta_time');
+
+ wp_insert_post($post);
+
+ wp_untrash_post_comments($post_id);
+
+ do_action('untrashed_post', $post_id);
+
+ return $post;
+}
+
+/**
+ * Moves comments for a post to the trash
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'trash_post_comments' before trashing
+ * @uses do_action() on 'trashed_post_comments' after trashing
+ *
+ * @param int|object $post Post ID or object.
+ * @return mixed False on failure
+ */
+function wp_trash_post_comments($post = null) {
+ global $wpdb;
+
+ $post = get_post($post);
+ if ( empty($post) )
+ return;
+
+ $post_id = $post->ID;
+
+ do_action('trash_post_comments', $post_id);
+
+ $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_ID, comment_approved FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id) );
+ if ( empty($comments) )
+ return;
+
+ // Cache current status for each comment
+ $statuses = array();
+ foreach ( $comments as $comment )
+ $statuses[$comment->comment_ID] = $comment->comment_approved;
+ add_post_meta($post_id, '_wp_trash_meta_comments_status', $statuses);
+
+ // Set status for all comments to post-trashed
+ $result = $wpdb->update($wpdb->comments, array('comment_approved' => 'post-trashed'), array('comment_post_ID' => $post_id));
+
+ clean_comment_cache( array_keys($statuses) );
+
+ do_action('trashed_post_comments', $post_id, $statuses);
+
+ return $result;
+}
+
+/**
+ * Restore comments for a post from the trash
+ *
+ * @since 2.9.0
+ * @uses do_action() on 'untrash_post_comments' before trashing
+ * @uses do_action() on 'untrashed_post_comments' after trashing
+ *
+ * @param int|object $post Post ID or object.
+ * @return mixed False on failure
+ */
+function wp_untrash_post_comments($post = null) {
+ global $wpdb;
+
+ $post = get_post($post);
+ if ( empty($post) )
+ return;
+
+ $post_id = $post->ID;
+
+ $statuses = get_post_meta($post_id, '_wp_trash_meta_comments_status', true);
+
+ if ( empty($statuses) )
+ return true;
+
+ do_action('untrash_post_comments', $post_id);
+
+ // Restore each comment to its original status
+ $group_by_status = array();
+ foreach ( $statuses as $comment_id => $comment_status )
+ $group_by_status[$comment_status][] = $comment_id;
+
+ foreach ( $group_by_status as $status => $comments ) {
+ // Sanity check. This shouldn't happen.
+ if ( 'post-trashed' == $status )
+ $status = '0';
+ $comments_in = implode( "', '", $comments );
+ $wpdb->query( "UPDATE $wpdb->comments SET comment_approved = '$status' WHERE comment_ID IN ('" . $comments_in . "')" );
+ }
+
+ clean_comment_cache( array_keys($statuses) );
+
+ delete_post_meta($post_id, '_wp_trash_meta_comments_status');
+
+ do_action('untrashed_post_comments', $post_id);
+}
+
+/**
+ * Retrieve the list of categories for a post.
+ *
+ * Compatibility layer for themes and plugins. Also an easy layer of abstraction
+ * away from the complexity of the taxonomy layer.
+ *
+ * @since 2.1.0
+ *
+ * @uses wp_get_object_terms() Retrieves the categories. Args details can be found here.
+ *
+ * @param int $post_id Optional. The Post ID.
+ * @param array $args Optional. Overwrite the defaults.
+ * @return array
+ */
+function wp_get_post_categories( $post_id = 0, $args = array() ) {
+ $post_id = (int) $post_id;
+
+ $defaults = array('fields' => 'ids');
+ $args = wp_parse_args( $args, $defaults );
+
+ $cats = wp_get_object_terms($post_id, 'category', $args);
+ return $cats;
+}
+
+/**
+ * Retrieve the tags for a post.
+ *
+ * There is only one default for this function, called 'fields' and by default
+ * is set to 'all'. There are other defaults that can be overridden in
+ * {@link wp_get_object_terms()}.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.3.0
+ *
+ * @uses wp_get_object_terms() Gets the tags for returning. Args can be found here
+ *
+ * @param int $post_id Optional. The Post ID
+ * @param array $args Optional. Overwrite the defaults
+ * @return array List of post tags.
+ */
+function wp_get_post_tags( $post_id = 0, $args = array() ) {
+ return wp_get_post_terms( $post_id, 'post_tag', $args);
+}
+
+/**
+ * Retrieve the terms for a post.
+ *
+ * There is only one default for this function, called 'fields' and by default
+ * is set to 'all'. There are other defaults that can be overridden in
+ * {@link wp_get_object_terms()}.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.8.0
+ *
+ * @uses wp_get_object_terms() Gets the tags for returning. Args can be found here
+ *
+ * @param int $post_id Optional. The Post ID
+ * @param string $taxonomy The taxonomy for which to retrieve terms. Defaults to post_tag.
+ * @param array $args Optional. Overwrite the defaults
+ * @return array List of post tags.
+ */
+function wp_get_post_terms( $post_id = 0, $taxonomy = 'post_tag', $args = array() ) {
+ $post_id = (int) $post_id;
+
+ $defaults = array('fields' => 'all');
+ $args = wp_parse_args( $args, $defaults );
+
+ $tags = wp_get_object_terms($post_id, $taxonomy, $args);
+
+ return $tags;
+}
+
+/**
+ * Retrieve number of recent posts.
+ *
+ * @since 1.0.0
+ * @uses wp_parse_args()
+ * @uses get_posts()
+ *
+ * @param string $deprecated Deprecated.
+ * @param array $args Optional. Overrides defaults.
+ * @param string $output Optional.
+ * @return unknown.
+ */
+function wp_get_recent_posts( $args = array(), $output = ARRAY_A ) {
+
+ if ( is_numeric( $args ) ) {
+ _deprecated_argument( __FUNCTION__, '3.1', __( 'Passing an integer number of posts is deprecated. Pass an array of arguments instead.' ) );
+ $args = array( 'numberposts' => absint( $args ) );
+ }
+
+ // Set default arguments
+ $defaults = array(
+ 'numberposts' => 10, 'offset' => 0,
+ 'category' => 0, 'orderby' => 'post_date',
+ 'order' => 'DESC', 'include' => '',
+ 'exclude' => '', 'meta_key' => '',
+ 'meta_value' =>'', 'post_type' => 'post', 'post_status' => 'draft, publish, future, pending, private',
+ 'suppress_filters' => true
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+
+ $results = get_posts( $r );
+
+ // Backward compatibility. Prior to 3.1 expected posts to be returned in array
+ if ( ARRAY_A == $output ){
+ foreach( $results as $key => $result ) {
+ $results[$key] = get_object_vars( $result );
+ }
+ return $results ? $results : array();
+ }
+
+ return $results ? $results : false;
+
+}
+
+/**
+ * Insert a post.
+ *
+ * If the $postarr parameter has 'ID' set to a value, then post will be updated.
+ *
+ * You can set the post date manually, by setting the values for 'post_date'
+ * and 'post_date_gmt' keys. You can close the comments or open the comments by
+ * setting the value for 'comment_status' key.
+ *
+ * The defaults for the parameter $postarr are:
+ * 'post_status' - Default is 'draft'.
+ * 'post_type' - Default is 'post'.
+ * 'post_author' - Default is current user ID ($user_ID). The ID of the user who added the post.
+ * 'ping_status' - Default is the value in 'default_ping_status' option.
+ * Whether the attachment can accept pings.
+ * 'post_parent' - Default is 0. Set this for the post it belongs to, if any.
+ * 'menu_order' - Default is 0. The order it is displayed.
+ * 'to_ping' - Whether to ping.
+ * 'pinged' - Default is empty string.
+ * 'post_password' - Default is empty string. The password to access the attachment.
+ * 'guid' - Global Unique ID for referencing the attachment.
+ * 'post_content_filtered' - Post content filtered.
+ * 'post_excerpt' - Post excerpt.
+ *
+ * @since 1.0.0
+ * @uses $wpdb
+ * @uses $user_ID
+ * @uses do_action() Calls 'pre_post_update' on post ID if this is an update.
+ * @uses do_action() Calls 'edit_post' action on post ID and post data if this is an update.
+ * @uses do_action() Calls 'save_post' and 'wp_insert_post' on post id and post data just before returning.
+ * @uses apply_filters() Calls 'wp_insert_post_data' passing $data, $postarr prior to database update or insert.
+ * @uses wp_transition_post_status()
+ *
+ * @param array $postarr Elements that make up post to insert.
+ * @param bool $wp_error Optional. Allow return of WP_Error on failure.
+ * @return int|WP_Error The value 0 or WP_Error on failure. The post ID on success.
+ */
+function wp_insert_post($postarr, $wp_error = false) {
+ global $wpdb, $user_ID;
+
+ $defaults = array('post_status' => 'draft', 'post_type' => 'post', 'post_author' => $user_ID,
+ 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0,
+ 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
+ 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '', 'import_id' => 0,
+ 'post_content' => '', 'post_title' => '');
+
+ $postarr = wp_parse_args($postarr, $defaults);
+
+ unset( $postarr[ 'filter' ] );
+
+ $postarr = sanitize_post($postarr, 'db');
+
+ // export array as variables
+ extract($postarr, EXTR_SKIP);
+
+ // Are we updating or creating?
+ $post_ID = 0;
+ $update = false;
+ if ( ! empty( $ID ) ) {
+ $update = true;
+
+ // Get the post ID and GUID
+ $post_ID = $ID;
+ $post_before = get_post( $post_ID );
+ if ( is_null( $post_before ) ) {
+ if ( $wp_error )
+ return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
+ return 0;
+ }
+
+ $guid = get_post_field( 'guid', $post_ID );
+ $previous_status = get_post_field('post_status', $ID);
+ } else {
+ $previous_status = 'new';
+ }
+
+ $maybe_empty = ! $post_content && ! $post_title && ! $post_excerpt && post_type_supports( $post_type, 'editor' )
+ && post_type_supports( $post_type, 'title' ) && post_type_supports( $post_type, 'excerpt' );
+
+ if ( apply_filters( 'wp_insert_post_empty_content', $maybe_empty, $postarr ) ) {
+ if ( $wp_error )
+ return new WP_Error( 'empty_content', __( 'Content, title, and excerpt are empty.' ) );
+ else
+ return 0;
+ }
+
+ if ( empty($post_type) )
+ $post_type = 'post';
+
+ if ( empty($post_status) )
+ $post_status = 'draft';
+
+ if ( !empty($post_category) )
+ $post_category = array_filter($post_category); // Filter out empty terms
+
+ // Make sure we set a valid category.
+ if ( empty($post_category) || 0 == count($post_category) || !is_array($post_category) ) {
+ // 'post' requires at least one category.
+ if ( 'post' == $post_type && 'auto-draft' != $post_status )
+ $post_category = array( get_option('default_category') );
+ else
+ $post_category = array();
+ }
+
+ if ( empty($post_author) )
+ $post_author = $user_ID;
+
+ // Don't allow contributors to set the post slug for pending review posts
+ if ( 'pending' == $post_status && !current_user_can( 'publish_posts' ) )
+ $post_name = '';
+
+ // Create a valid post name. Drafts and pending posts are allowed to have an empty
+ // post name.
+ if ( empty($post_name) ) {
+ if ( !in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+ $post_name = sanitize_title($post_title);
+ else
+ $post_name = '';
+ } else {
+ // On updates, we need to check to see if it's using the old, fixed sanitization context.
+ $check_name = sanitize_title( $post_name, '', 'old-save' );
+ if ( $update && strtolower( urlencode( $post_name ) ) == $check_name && get_post_field( 'post_name', $ID ) == $check_name )
+ $post_name = $check_name;
+ else // new post, or slug has changed.
+ $post_name = sanitize_title($post_name);
+ }
+
+ // If the post date is empty (due to having been new or a draft) and status is not 'draft' or 'pending', set date to now
+ if ( empty($post_date) || '0000-00-00 00:00:00' == $post_date )
+ $post_date = current_time('mysql');
+
+ // validate the date
+ $mm = substr( $post_date, 5, 2 );
+ $jj = substr( $post_date, 8, 2 );
+ $aa = substr( $post_date, 0, 4 );
+ $valid_date = wp_checkdate( $mm, $jj, $aa, $post_date );
+ if ( !$valid_date ) {
+ if ( $wp_error )
+ return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
+ else
+ return 0;
+ }
+
+ if ( empty($post_date_gmt) || '0000-00-00 00:00:00' == $post_date_gmt ) {
+ if ( !in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) )
+ $post_date_gmt = get_gmt_from_date($post_date);
+ else
+ $post_date_gmt = '0000-00-00 00:00:00';
+ }
+
+ if ( $update || '0000-00-00 00:00:00' == $post_date ) {
+ $post_modified = current_time( 'mysql' );
+ $post_modified_gmt = current_time( 'mysql', 1 );
+ } else {
+ $post_modified = $post_date;
+ $post_modified_gmt = $post_date_gmt;
+ }
+
+ if ( 'publish' == $post_status ) {
+ $now = gmdate('Y-m-d H:i:59');
+ if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) )
+ $post_status = 'future';
+ } elseif( 'future' == $post_status ) {
+ $now = gmdate('Y-m-d H:i:59');
+ if ( mysql2date('U', $post_date_gmt, false) <= mysql2date('U', $now, false) )
+ $post_status = 'publish';
+ }
+
+ if ( empty($comment_status) ) {
+ if ( $update )
+ $comment_status = 'closed';
+ else
+ $comment_status = get_option('default_comment_status');
+ }
+ if ( empty($ping_status) )
+ $ping_status = get_option('default_ping_status');
+
+ if ( isset($to_ping) )
+ $to_ping = sanitize_trackback_urls( $to_ping );
+ else
+ $to_ping = '';
+
+ if ( ! isset($pinged) )
+ $pinged = '';
+
+ if ( isset($post_parent) )
+ $post_parent = (int) $post_parent;
+ else
+ $post_parent = 0;
+
+ // Check the post_parent to see if it will cause a hierarchy loop
+ $post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr );
+
+ if ( isset($menu_order) )
+ $menu_order = (int) $menu_order;
+ else
+ $menu_order = 0;
+
+ if ( !isset($post_password) || 'private' == $post_status )
+ $post_password = '';
+
+ $post_name = wp_unique_post_slug($post_name, $post_ID, $post_status, $post_type, $post_parent);
+
+ // expected_slashed (everything!)
+ $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'guid' ) );
+ $data = apply_filters('wp_insert_post_data', $data, $postarr);
+ $data = wp_unslash( $data );
+ $where = array( 'ID' => $post_ID );
+
+ if ( $update ) {
+ do_action( 'pre_post_update', $post_ID, $data );
+ if ( false === $wpdb->update( $wpdb->posts, $data, $where ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_update_error', __('Could not update post in the database'), $wpdb->last_error);
+ else
+ return 0;
+ }
+ } else {
+ if ( isset($post_mime_type) )
+ $data['post_mime_type'] = wp_unslash( $post_mime_type ); // This isn't in the update
+ // If there is a suggested ID, use it if not already present
+ if ( !empty($import_id) ) {
+ $import_id = (int) $import_id;
+ if ( ! $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE ID = %d", $import_id) ) ) {
+ $data['ID'] = $import_id;
+ }
+ }
+ if ( false === $wpdb->insert( $wpdb->posts, $data ) ) {
+ if ( $wp_error )
+ return new WP_Error('db_insert_error', __('Could not insert post into the database'), $wpdb->last_error);
+ else
+ return 0;
+ }
+ $post_ID = (int) $wpdb->insert_id;
+
+ // use the newly generated $post_ID
+ $where = array( 'ID' => $post_ID );
+ }
+
+ if ( empty($data['post_name']) && !in_array( $data['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) ) {
+ $data['post_name'] = sanitize_title($data['post_title'], $post_ID);
+ $wpdb->update( $wpdb->posts, array( 'post_name' => $data['post_name'] ), $where );
+ }
+
+ if ( is_object_in_taxonomy($post_type, 'category') )
+ wp_set_post_categories( $post_ID, $post_category );
+
+ if ( isset( $tags_input ) && is_object_in_taxonomy($post_type, 'post_tag') )
+ wp_set_post_tags( $post_ID, $tags_input );
+
+ // new-style support for all custom taxonomies
+ if ( !empty($tax_input) ) {
+ foreach ( $tax_input as $taxonomy => $tags ) {
+ $taxonomy_obj = get_taxonomy($taxonomy);
+ if ( is_array($tags) ) // array = hierarchical, string = non-hierarchical.
+ $tags = array_filter($tags);
+ if ( current_user_can($taxonomy_obj->cap->assign_terms) )
+ wp_set_post_terms( $post_ID, $tags, $taxonomy );
+ }
+ }
+
+ $current_guid = get_post_field( 'guid', $post_ID );
+
+ // Set GUID
+ if ( !$update && '' == $current_guid )
+ $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post_ID ) ), $where );
+
+ clean_post_cache( $post_ID );
+
+ $post = get_post($post_ID);
+
+ if ( !empty($page_template) && 'page' == $data['post_type'] ) {
+ $post->page_template = $page_template;
+ $page_templates = wp_get_theme()->get_page_templates();
+ if ( 'default' != $page_template && ! isset( $page_templates[ $page_template ] ) ) {
+ if ( $wp_error )
+ return new WP_Error('invalid_page_template', __('The page template is invalid.'));
+ else
+ return 0;
+ }
+ update_post_meta($post_ID, '_wp_page_template', $page_template);
+ }
+
+ wp_transition_post_status($data['post_status'], $previous_status, $post);
+
+ if ( $update ) {
+ do_action('edit_post', $post_ID, $post);
+ $post_after = get_post($post_ID);
+ do_action( 'post_updated', $post_ID, $post_after, $post_before);
+ }
+
+ do_action( 'save_post', $post_ID, $post, $update );
+ do_action( 'wp_insert_post', $post_ID, $post, $update );
+
+ return $post_ID;
+}
+
+/**
+ * Update a post with new post data.
+ *
+ * The date does not have to be set for drafts. You can set the date and it will
+ * not be overridden.
+ *
+ * @since 1.0.0
+ *
+ * @param array|object $postarr Post data. Arrays are expected to be escaped, objects are not.
+ * @param bool $wp_error Optional. Allow return of WP_Error on failure.
+ * @return int|WP_Error The value 0 or WP_Error on failure. The post ID on success.
+ */
+function wp_update_post( $postarr = array(), $wp_error = false ) {
+ if ( is_object($postarr) ) {
+ // non-escaped post was passed
+ $postarr = get_object_vars($postarr);
+ $postarr = wp_slash($postarr);
+ }
+
+ // First, get all of the original fields
+ $post = get_post($postarr['ID'], ARRAY_A);
+
+ if ( is_null( $post ) ) {
+ if ( $wp_error )
+ return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
+ return 0;
+ }
+
+ // Escape data pulled from DB.
+ $post = wp_slash($post);
+
+ // Passed post category list overwrites existing category list if not empty.
+ if ( isset($postarr['post_category']) && is_array($postarr['post_category'])
+ && 0 != count($postarr['post_category']) )
+ $post_cats = $postarr['post_category'];
+ else
+ $post_cats = $post['post_category'];
+
+ // Drafts shouldn't be assigned a date unless explicitly done so by the user
+ if ( isset( $post['post_status'] ) && in_array($post['post_status'], array('draft', 'pending', 'auto-draft')) && empty($postarr['edit_date']) &&
+ ('0000-00-00 00:00:00' == $post['post_date_gmt']) )
+ $clear_date = true;
+ else
+ $clear_date = false;
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $postarr = array_merge($post, $postarr);
+ $postarr['post_category'] = $post_cats;
+ if ( $clear_date ) {
+ $postarr['post_date'] = current_time('mysql');
+ $postarr['post_date_gmt'] = '';
+ }
+
+ if ($postarr['post_type'] == 'attachment')
+ return wp_insert_attachment($postarr);
+
+ return wp_insert_post( $postarr, $wp_error );
+}
+
+/**
+ * Publish a post by transitioning the post status.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'edit_post', 'save_post', and 'wp_insert_post' on post_id and post data.
+ *
+ * @param int|object $post Post ID or object.
+ */
+function wp_publish_post( $post ) {
+ global $wpdb;
+
+ if ( ! $post = get_post( $post ) )
+ return;
+
+ if ( 'publish' == $post->post_status )
+ return;
+
+ $wpdb->update( $wpdb->posts, array( 'post_status' => 'publish' ), array( 'ID' => $post->ID ) );
+
+ clean_post_cache( $post->ID );
+
+ $old_status = $post->post_status;
+ $post->post_status = 'publish';
+ wp_transition_post_status( 'publish', $old_status, $post );
+
+ do_action( 'edit_post', $post->ID, $post );
+ do_action( 'save_post', $post->ID, $post, true );
+ do_action( 'wp_insert_post', $post->ID, $post, true );
+}
+
+/**
+ * Publish future post and make sure post ID has future post status.
+ *
+ * Invoked by cron 'publish_future_post' event. This safeguard prevents cron
+ * from publishing drafts, etc.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post_id Post ID.
+ * @return null Nothing is returned. Which can mean that no action is required or post was published.
+ */
+function check_and_publish_future_post($post_id) {
+
+ $post = get_post($post_id);
+
+ if ( empty($post) )
+ return;
+
+ if ( 'future' != $post->post_status )
+ return;
+
+ $time = strtotime( $post->post_date_gmt . ' GMT' );
+
+ if ( $time > time() ) { // Uh oh, someone jumped the gun!
+ wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) ); // clear anything else in the system
+ wp_schedule_single_event( $time, 'publish_future_post', array( $post_id ) );
+ return;
+ }
+
+ return wp_publish_post($post_id);
+}
+
+/**
+ * Computes a unique slug for the post, when given the desired slug and some post details.
+ *
+ * @since 2.8.0
+ *
+ * @global wpdb $wpdb
+ * @global WP_Rewrite $wp_rewrite
+ * @param string $slug the desired slug (post_name)
+ * @param integer $post_ID
+ * @param string $post_status no uniqueness checks are made if the post is still draft or pending
+ * @param string $post_type
+ * @param integer $post_parent
+ * @return string unique slug for the post, based on $post_name (with a -1, -2, etc. suffix)
+ */
+function wp_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent ) {
+ if ( in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) || ( 'inherit' == $post_status && 'revision' == $post_type ) )
+ return $slug;
+
+ global $wpdb, $wp_rewrite;
+
+ $original_slug = $slug;
+
+ $feeds = $wp_rewrite->feeds;
+ if ( ! is_array( $feeds ) )
+ $feeds = array();
+
+ $hierarchical_post_types = get_post_types( array('hierarchical' => true) );
+ if ( 'attachment' == $post_type ) {
+ // Attachment slugs must be unique across all types.
+ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND ID != %d LIMIT 1";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID ) );
+
+ if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_attachment_slug', false, $slug ) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID ) );
+ $suffix++;
+ } while ( $post_name_check );
+ $slug = $alt_post_name;
+ }
+ } elseif ( in_array( $post_type, $hierarchical_post_types ) ) {
+ if ( 'nav_menu_item' == $post_type )
+ return $slug;
+ // Page slugs must be unique within their own trees. Pages are in a separate
+ // namespace than posts so page slugs are allowed to overlap post slugs.
+ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type IN ( '" . implode( "', '", esc_sql( $hierarchical_post_types ) ) . "' ) AND ID != %d AND post_parent = %d LIMIT 1";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_ID, $post_parent ) );
+
+ if ( $post_name_check || in_array( $slug, $feeds ) || preg_match( "@^($wp_rewrite->pagination_base)?\d+$@", $slug ) || apply_filters( 'wp_unique_post_slug_is_bad_hierarchical_slug', false, $slug, $post_type, $post_parent ) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_ID, $post_parent ) );
+ $suffix++;
+ } while ( $post_name_check );
+ $slug = $alt_post_name;
+ }
+ } else {
+ // Post slugs must be unique across all posts.
+ $check_sql = "SELECT post_name FROM $wpdb->posts WHERE post_name = %s AND post_type = %s AND ID != %d LIMIT 1";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $slug, $post_type, $post_ID ) );
+
+ if ( $post_name_check || in_array( $slug, $feeds ) || apply_filters( 'wp_unique_post_slug_is_bad_flat_slug', false, $slug, $post_type ) ) {
+ $suffix = 2;
+ do {
+ $alt_post_name = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix";
+ $post_name_check = $wpdb->get_var( $wpdb->prepare( $check_sql, $alt_post_name, $post_type, $post_ID ) );
+ $suffix++;
+ } while ( $post_name_check );
+ $slug = $alt_post_name;
+ }
+ }
+
+ return apply_filters( 'wp_unique_post_slug', $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug );
+}
+
+/**
+ * Truncates a post slug.
+ *
+ * @since 3.6.0
+ * @access private
+ * @uses utf8_uri_encode() Makes sure UTF-8 characters are properly cut and encoded.
+ *
+ * @param string $slug The slug to truncate.
+ * @param int $length Max length of the slug.
+ * @return string The truncated slug.
+ */
+function _truncate_post_slug( $slug, $length = 200 ) {
+ if ( strlen( $slug ) > $length ) {
+ $decoded_slug = urldecode( $slug );
+ if ( $decoded_slug === $slug )
+ $slug = substr( $slug, 0, $length );
+ else
+ $slug = utf8_uri_encode( $decoded_slug, $length );
+ }
+
+ return rtrim( $slug, '-' );
+}
+
+/**
+ * Adds tags to a post.
+ *
+ * @uses wp_set_post_tags() Same first two parameters, but the last parameter is always set to true.
+ *
+ * @package WordPress
+ * @subpackage Post
+ * @since 2.3.0
+ *
+ * @param int $post_id Post ID
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @return bool|null Will return false if $post_id is not an integer or is 0. Will return null otherwise
+ */
+function wp_add_post_tags($post_id = 0, $tags = '') {
+ return wp_set_post_tags($post_id, $tags, true);
+}
+
+/**
+ * Set the tags for a post.
+ *
+ * @since 2.3.0
+ * @uses wp_set_object_terms() Sets the tags for the post.
+ *
+ * @param int $post_id Post ID.
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @param bool $append If true, don't delete existing tags, just add on. If false, replace the tags with the new tags.
+ * @return mixed Array of affected term IDs. WP_Error or false on failure.
+ */
+function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
+ return wp_set_post_terms( $post_id, $tags, 'post_tag', $append);
+}
+
+/**
+ * Set the terms for a post.
+ *
+ * @since 2.8.0
+ * @uses wp_set_object_terms() Sets the tags for the post.
+ *
+ * @param int $post_id Post ID.
+ * @param string $tags The tags to set for the post, separated by commas.
+ * @param string $taxonomy Taxonomy name. Defaults to 'post_tag'.
+ * @param bool $append If true, don't delete existing tags, just add on. If false, replace the tags with the new tags.
+ * @return mixed Array of affected term IDs. WP_Error or false on failure.
+ */
+function wp_set_post_terms( $post_id = 0, $tags = '', $taxonomy = 'post_tag', $append = false ) {
+ $post_id = (int) $post_id;
+
+ if ( !$post_id )
+ return false;
+
+ if ( empty($tags) )
+ $tags = array();
+
+ if ( ! is_array( $tags ) ) {
+ $comma = _x( ',', 'tag delimiter' );
+ if ( ',' !== $comma )
+ $tags = str_replace( $comma, ',', $tags );
+ $tags = explode( ',', trim( $tags, " \n\t\r\0\x0B," ) );
+ }
+
+ // Hierarchical taxonomies must always pass IDs rather than names so that children with the same
+ // names but different parents aren't confused.
+ if ( is_taxonomy_hierarchical( $taxonomy ) ) {
+ $tags = array_unique( array_map( 'intval', $tags ) );
+ }
+
+ return wp_set_object_terms( $post_id, $tags, $taxonomy, $append );
+}
+
+/**
+ * Set categories for a post.
+ *
+ * If the post categories parameter is not set, then the default category is
+ * going used.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_ID Post ID.
+ * @param array $post_categories Optional. List of categories.
+ * @return bool|mixed
+ */
+function wp_set_post_categories($post_ID = 0, $post_categories = array()) {
+ $post_ID = (int) $post_ID;
+ $post_type = get_post_type( $post_ID );
+ $post_status = get_post_status( $post_ID );
+ // If $post_categories isn't already an array, make it one:
+ if ( !is_array($post_categories) || empty($post_categories) ) {
+ if ( 'post' == $post_type && 'auto-draft' != $post_status )
+ $post_categories = array( get_option('default_category') );
+ else
+ $post_categories = array();
+ } else if ( 1 == count($post_categories) && '' == reset($post_categories) ) {
+ return true;
+ }
+
+ return wp_set_post_terms($post_ID, $post_categories, 'category');
+}
+
+/**
+ * Transition the post status of a post.
+ *
+ * Calls hooks to transition post status.
+ *
+ * The first is 'transition_post_status' with new status, old status, and post data.
+ *
+ * The next action called is 'OLDSTATUS_to_NEWSTATUS' the 'NEWSTATUS' is the
+ * $new_status parameter and the 'OLDSTATUS' is $old_status parameter; it has the
+ * post data.
+ *
+ * The final action is named 'NEWSTATUS_POSTTYPE', 'NEWSTATUS' is from the $new_status
+ * parameter and POSTTYPE is post_type post data.
+ *
+ * @since 2.3.0
+ * @link http://codex.wordpress.org/Post_Status_Transitions
+ *
+ * @uses do_action() Calls 'transition_post_status' on $new_status, $old_status and
+ * $post if there is a status change.
+ * @uses do_action() Calls '{$old_status}_to_{$new_status}' on $post if there is a status change.
+ * @uses do_action() Calls '{$new_status}_{$post->post_type}' on post ID and $post.
+ *
+ * @param string $new_status Transition to this post status.
+ * @param string $old_status Previous post status.
+ * @param object $post Post data.
+ */
+function wp_transition_post_status($new_status, $old_status, $post) {
+ do_action('transition_post_status', $new_status, $old_status, $post);
+ do_action("{$old_status}_to_{$new_status}", $post);
+ do_action("{$new_status}_{$post->post_type}", $post->ID, $post);
+}
+
+//
+// Trackback and ping functions
+//
+
+/**
+ * Add a URL to those already pung.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @param string $uri Ping URI.
+ * @return int How many rows were updated.
+ */
+function add_ping($post_id, $uri) {
+ global $wpdb;
+ $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $pung = trim($pung);
+ $pung = preg_split('/\s/', $pung);
+ $pung[] = $uri;
+ $new = implode("\n", $pung);
+ $new = apply_filters('add_ping', $new);
+ // expected_slashed ($new)
+ $new = wp_unslash($new);
+ return $wpdb->update( $wpdb->posts, array( 'pinged' => $new ), array( 'ID' => $post_id ) );
+}
+
+/**
+ * Retrieve enclosures already enclosed for a post.
+ *
+ * @since 1.5.0
+ *
+ * @param int $post_id Post ID.
+ * @return array List of enclosures
+ */
+function get_enclosed($post_id) {
+ $custom_fields = get_post_custom( $post_id );
+ $pung = array();
+ if ( !is_array( $custom_fields ) )
+ return $pung;
+
+ foreach ( $custom_fields as $key => $val ) {
+ if ( 'enclosure' != $key || !is_array( $val ) )
+ continue;
+ foreach( $val as $enc ) {
+ $enclosure = explode( "\n", $enc );
+ $pung[] = trim( $enclosure[ 0 ] );
+ }
+ }
+ $pung = apply_filters('get_enclosed', $pung, $post_id);
+ return $pung;
+}
+
+/**
+ * Retrieve URLs already pinged for a post.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID.
+ * @return array
+ */
+function get_pung($post_id) {
+ global $wpdb;
+ $pung = $wpdb->get_var( $wpdb->prepare( "SELECT pinged FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $pung = trim($pung);
+ $pung = preg_split('/\s/', $pung);
+ $pung = apply_filters('get_pung', $pung);
+ return $pung;
+}
+
+/**
+ * Retrieve URLs that need to be pinged.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param int $post_id Post ID
+ * @return array
+ */
+function get_to_ping($post_id) {
+ global $wpdb;
+ $to_ping = $wpdb->get_var( $wpdb->prepare( "SELECT to_ping FROM $wpdb->posts WHERE ID = %d", $post_id ));
+ $to_ping = sanitize_trackback_urls( $to_ping );
+ $to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
+ $to_ping = apply_filters('get_to_ping', $to_ping);
+ return $to_ping;
+}
+
+/**
+ * Do trackbacks for a list of URLs.
+ *
+ * @since 1.0.0
+ *
+ * @param string $tb_list Comma separated list of URLs
+ * @param int $post_id Post ID
+ */
+function trackback_url_list($tb_list, $post_id) {
+ if ( ! empty( $tb_list ) ) {
+ // get post data
+ $postdata = get_post($post_id, ARRAY_A);
+
+ // import postdata as variables
+ extract($postdata, EXTR_SKIP);
+
+ // form an excerpt
+ $excerpt = strip_tags($post_excerpt ? $post_excerpt : $post_content);
+
+ if (strlen($excerpt) > 255) {
+ $excerpt = substr($excerpt,0,252) . '&hellip;';
+ }
+
+ $trackback_urls = explode(',', $tb_list);
+ foreach( (array) $trackback_urls as $tb_url) {
+ $tb_url = trim($tb_url);
+ trackback($tb_url, wp_unslash($post_title), $excerpt, $post_id);
+ }
+ }
+}
+
+//
+// Page functions
+//
+
+/**
+ * Get a list of page IDs.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ *
+ * @return array List of page IDs.
+ */
+function get_all_page_ids() {
+ global $wpdb;
+
+ $page_ids = wp_cache_get('all_page_ids', 'posts');
+ if ( ! is_array( $page_ids ) ) {
+ $page_ids = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type = 'page'");
+ wp_cache_add('all_page_ids', $page_ids, 'posts');
+ }
+
+ return $page_ids;
+}
+
+/**
+ * Retrieves page data given a page ID or page object.
+ *
+ * Use get_post() instead of get_page().
+ *
+ * @since 1.5.1
+ * @deprecated 3.5.0
+ *
+ * @param mixed $page Page object or page ID. Passed by reference.
+ * @param string $output What to output. OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter How the return value should be filtered.
+ * @return WP_Post|null WP_Post on success or null on failure
+ */
+function get_page( $page, $output = OBJECT, $filter = 'raw') {
+ return get_post( $page, $output, $filter );
+}
+
+/**
+ * Retrieves a page given its path.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $page_path Page path
+ * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
+ * @param string $post_type Optional. Post type. Default page.
+ * @return WP_Post|null WP_Post on success or null on failure
+ */
+function get_page_by_path($page_path, $output = OBJECT, $post_type = 'page') {
+ global $wpdb;
+
+ $page_path = rawurlencode(urldecode($page_path));
+ $page_path = str_replace('%2F', '/', $page_path);
+ $page_path = str_replace('%20', ' ', $page_path);
+ $parts = explode( '/', trim( $page_path, '/' ) );
+ $parts = esc_sql( $parts );
+ $parts = array_map( 'sanitize_title_for_query', $parts );
+
+ $in_string = "'". implode( "','", $parts ) . "'";
+ $post_type_sql = esc_sql( $post_type );
+ $pages = $wpdb->get_results( "SELECT ID, post_name, post_parent, post_type FROM $wpdb->posts WHERE post_name IN ($in_string) AND (post_type = '$post_type_sql' OR post_type = 'attachment')", OBJECT_K );
+
+ $revparts = array_reverse( $parts );
+
+ $foundid = 0;
+ foreach ( (array) $pages as $page ) {
+ if ( $page->post_name == $revparts[0] ) {
+ $count = 0;
+ $p = $page;
+ while ( $p->post_parent != 0 && isset( $pages[ $p->post_parent ] ) ) {
+ $count++;
+ $parent = $pages[ $p->post_parent ];
+ if ( ! isset( $revparts[ $count ] ) || $parent->post_name != $revparts[ $count ] )
+ break;
+ $p = $parent;
+ }
+
+ if ( $p->post_parent == 0 && $count+1 == count( $revparts ) && $p->post_name == $revparts[ $count ] ) {
+ $foundid = $page->ID;
+ if ( $page->post_type == $post_type )
+ break;
+ }
+ }
+ }
+
+ if ( $foundid )
+ return get_post( $foundid, $output );
+
+ return null;
+}
+
+/**
+ * Retrieve a page given its title.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $page_title Page title
+ * @param string $output Optional. Output type. OBJECT, ARRAY_N, or ARRAY_A. Default OBJECT.
+ * @param string $post_type Optional. Post type. Default page.
+ * @return WP_Post|null WP_Post on success or null on failure
+ */
+function get_page_by_title($page_title, $output = OBJECT, $post_type = 'page' ) {
+ global $wpdb;
+ $page = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type= %s", $page_title, $post_type ) );
+ if ( $page )
+ return get_post( $page, $output );
+
+ return null;
+}
+
+/**
+ * Retrieve child pages from list of pages matching page ID.
+ *
+ * Matches against the pages parameter against the page ID. Also matches all
+ * children for the same to retrieve all children of a page. Does not make any
+ * SQL queries to get the children.
+ *
+ * @since 1.5.1
+ *
+ * @param int $page_id Page ID.
+ * @param array $pages List of pages' objects.
+ * @return array
+ */
+function get_page_children($page_id, $pages) {
+ $page_list = array();
+ foreach ( (array) $pages as $page ) {
+ if ( $page->post_parent == $page_id ) {
+ $page_list[] = $page;
+ if ( $children = get_page_children($page->ID, $pages) )
+ $page_list = array_merge($page_list, $children);
+ }
+ }
+ return $page_list;
+}
+
+/**
+ * Order the pages with children under parents in a flat list.
+ *
+ * It uses auxiliary structure to hold parent-children relationships and
+ * runs in O(N) complexity
+ *
+ * @since 2.0.0
+ *
+ * @param array $pages Posts array.
+ * @param int $page_id Parent page ID.
+ * @return array A list arranged by hierarchy. Children immediately follow their parents.
+ */
+function get_page_hierarchy( &$pages, $page_id = 0 ) {
+ if ( empty( $pages ) ) {
+ $result = array();
+ return $result;
+ }
+
+ $children = array();
+ foreach ( (array) $pages as $p ) {
+ $parent_id = intval( $p->post_parent );
+ $children[ $parent_id ][] = $p;
+ }
+
+ $result = array();
+ _page_traverse_name( $page_id, $children, $result );
+
+ return $result;
+}
+
+/**
+ * function to traverse and return all the nested children post names of a root page.
+ * $children contains parent-children relations
+ *
+ * @since 2.9.0
+ */
+function _page_traverse_name( $page_id, &$children, &$result ){
+ if ( isset( $children[ $page_id ] ) ){
+ foreach( (array)$children[ $page_id ] as $child ) {
+ $result[ $child->ID ] = $child->post_name;
+ _page_traverse_name( $child->ID, $children, $result );
+ }
+ }
+}
+
+/**
+ * Builds URI for a page.
+ *
+ * Sub pages will be in the "directory" under the parent page post name.
+ *
+ * @since 1.5.0
+ *
+ * @param mixed $page Page object or page ID.
+ * @return string Page URI.
+ */
+function get_page_uri($page) {
+ $page = get_post( $page );
+
+ $uri = $page->post_name;
+
+ foreach ( $page->ancestors as $parent ) {
+ $uri = get_post( $parent )->post_name . "/" . $uri;
+ }
+
+ return $uri;
+}
+
+/**
+ * Retrieve a list of pages.
+ *
+ * The defaults that can be overridden are the following: 'child_of',
+ * 'sort_order', 'sort_column', 'post_title', 'hierarchical', 'exclude',
+ * 'include', 'meta_key', 'meta_value','authors', 'number', and 'offset'.
+ *
+ * @since 1.5.0
+ * @uses $wpdb
+ *
+ * @param mixed $args Optional. Array or string of options that overrides defaults.
+ * @return array List of pages matching defaults or $args
+ */
+function get_pages($args = '') {
+ global $wpdb;
+
+ $pages = false;
+
+ $defaults = array(
+ 'child_of' => 0, 'sort_order' => 'ASC',
+ 'sort_column' => 'post_title', 'hierarchical' => 1,
+ 'exclude' => array(), 'include' => array(),
+ 'meta_key' => '', 'meta_value' => '',
+ 'authors' => '', 'parent' => -1, 'exclude_tree' => '',
+ 'number' => '', 'offset' => 0,
+ 'post_type' => 'page', 'post_status' => 'publish',
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+ $number = (int) $number;
+ $offset = (int) $offset;
+
+ // Make sure the post type is hierarchical
+ $hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
+ if ( !in_array( $post_type, $hierarchical_post_types ) )
+ return $pages;
+
+ // Make sure we have a valid post status
+ if ( !is_array( $post_status ) )
+ $post_status = explode( ',', $post_status );
+ if ( array_diff( $post_status, get_post_stati() ) )
+ return $pages;
+
+ // $args can be whatever, only use the args defined in defaults to compute the key
+ $key = md5( serialize( compact(array_keys($defaults)) ) );
+ $last_changed = wp_cache_get( 'last_changed', 'posts' );
+ if ( ! $last_changed ) {
+ $last_changed = microtime();
+ wp_cache_set( 'last_changed', $last_changed, 'posts' );
+ }
+
+ $cache_key = "get_pages:$key:$last_changed";
+ if ( $cache = wp_cache_get( $cache_key, 'posts' ) ) {
+ // Convert to WP_Post instances
+ $pages = array_map( 'get_post', $cache );
+ $pages = apply_filters('get_pages', $pages, $r);
+ return $pages;
+ }
+
+ if ( !is_array($cache) )
+ $cache = array();
+
+ $inclusions = '';
+ if ( !empty($include) ) {
+ $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include
+ $parent = -1;
+ $exclude = '';
+ $meta_key = '';
+ $meta_value = '';
+ $hierarchical = false;
+ $incpages = wp_parse_id_list( $include );
+ if ( ! empty( $incpages ) ) {
+ foreach ( $incpages as $incpage ) {
+ if (empty($inclusions))
+ $inclusions = $wpdb->prepare(' AND ( ID = %d ', $incpage);
+ else
+ $inclusions .= $wpdb->prepare(' OR ID = %d ', $incpage);
+ }
+ }
+ }
+ if (!empty($inclusions))
+ $inclusions .= ')';
+
+ $exclusions = '';
+ if ( !empty($exclude) ) {
+ $expages = wp_parse_id_list( $exclude );
+ if ( ! empty( $expages ) ) {
+ foreach ( $expages as $expage ) {
+ if (empty($exclusions))
+ $exclusions = $wpdb->prepare(' AND ( ID <> %d ', $expage);
+ else
+ $exclusions .= $wpdb->prepare(' AND ID <> %d ', $expage);
+ }
+ }
+ }
+ if (!empty($exclusions))
+ $exclusions .= ')';
+
+ $author_query = '';
+ if (!empty($authors)) {
+ $post_authors = preg_split('/[\s,]+/',$authors);
+
+ if ( ! empty( $post_authors ) ) {
+ foreach ( $post_authors as $post_author ) {
+ //Do we have an author id or an author login?
+ if ( 0 == intval($post_author) ) {
+ $post_author = get_user_by('login', $post_author);
+ if ( empty($post_author) )
+ continue;
+ if ( empty($post_author->ID) )
+ continue;
+ $post_author = $post_author->ID;
+ }
+
+ if ( '' == $author_query )
+ $author_query = $wpdb->prepare(' post_author = %d ', $post_author);
+ else
+ $author_query .= $wpdb->prepare(' OR post_author = %d ', $post_author);
+ }
+ if ( '' != $author_query )
+ $author_query = " AND ($author_query)";
+ }
+ }
+
+ $join = '';
+ $where = "$exclusions $inclusions ";
+ if ( '' !== $meta_key || '' !== $meta_value ) {
+ $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )";
+
+ // meta_key and meta_value might be slashed
+ $meta_key = wp_unslash($meta_key);
+ $meta_value = wp_unslash($meta_value);
+ if ( '' !== $meta_key )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
+ if ( '' !== $meta_value )
+ $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
+
+ }
+
+ if ( $parent >= 0 )
+ $where .= $wpdb->prepare(' AND post_parent = %d ', $parent);
+
+ if ( 1 == count( $post_status ) ) {
+ $where_post_type = $wpdb->prepare( "post_type = %s AND post_status = %s", $post_type, array_shift( $post_status ) );
+ } else {
+ $post_status = implode( "', '", $post_status );
+ $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $post_type );
+ }
+
+ $orderby_array = array();
+ $allowed_keys = array('author', 'post_author', 'date', 'post_date', 'title', 'post_title', 'name', 'post_name', 'modified',
+ 'post_modified', 'modified_gmt', 'post_modified_gmt', 'menu_order', 'parent', 'post_parent',
+ 'ID', 'rand', 'comment_count');
+ foreach ( explode( ',', $sort_column ) as $orderby ) {
+ $orderby = trim( $orderby );
+ if ( !in_array( $orderby, $allowed_keys ) )
+ continue;
+
+ switch ( $orderby ) {
+ case 'menu_order':
+ break;
+ case 'ID':
+ $orderby = "$wpdb->posts.ID";
+ break;
+ case 'rand':
+ $orderby = 'RAND()';
+ break;
+ case 'comment_count':
+ $orderby = "$wpdb->posts.comment_count";
+ break;
+ default:
+ if ( 0 === strpos( $orderby, 'post_' ) )
+ $orderby = "$wpdb->posts." . $orderby;
+ else
+ $orderby = "$wpdb->posts.post_" . $orderby;
+ }
+
+ $orderby_array[] = $orderby;
+
+ }
+ $sort_column = ! empty( $orderby_array ) ? implode( ',', $orderby_array ) : "$wpdb->posts.post_title";
+
+ $sort_order = strtoupper( $sort_order );
+ if ( '' !== $sort_order && !in_array( $sort_order, array( 'ASC', 'DESC' ) ) )
+ $sort_order = 'ASC';
+
+ $query = "SELECT * FROM $wpdb->posts $join WHERE ($where_post_type) $where ";
+ $query .= $author_query;
+ $query .= " ORDER BY " . $sort_column . " " . $sort_order ;
+
+ if ( !empty($number) )
+ $query .= ' LIMIT ' . $offset . ',' . $number;
+
+ $pages = $wpdb->get_results($query);
+
+ if ( empty($pages) ) {
+ $pages = apply_filters('get_pages', array(), $r);
+ return $pages;
+ }
+
+ // Sanitize before caching so it'll only get done once
+ $num_pages = count($pages);
+ for ($i = 0; $i < $num_pages; $i++) {
+ $pages[$i] = sanitize_post($pages[$i], 'raw');
+ }
+
+ // Update cache.
+ update_post_cache( $pages );
+
+ if ( $child_of || $hierarchical )
+ $pages = get_page_children($child_of, $pages);
+
+ if ( !empty($exclude_tree) ) {
+ $exclude = (int) $exclude_tree;
+ $children = get_page_children($exclude, $pages);
+ $excludes = array();
+ foreach ( $children as $child )
+ $excludes[] = $child->ID;
+ $excludes[] = $exclude;
+ $num_pages = count($pages);
+ for ( $i = 0; $i < $num_pages; $i++ ) {
+ if ( in_array($pages[$i]->ID, $excludes) )
+ unset($pages[$i]);
+ }
+ }
+
+ $page_structure = array();
+ foreach ( $pages as $page )
+ $page_structure[] = $page->ID;
+
+ wp_cache_set( $cache_key, $page_structure, 'posts' );
+
+ // Convert to WP_Post instances
+ $pages = array_map( 'get_post', $pages );
+
+ $pages = apply_filters('get_pages', $pages, $r);
+
+ return $pages;
+}
+
+//
+// Attachment functions
+//
+
+/**
+ * Check if the attachment URI is local one and is really an attachment.
+ *
+ * @since 2.0.0
+ *
+ * @param string $url URL to check
+ * @return bool True on success, false on failure.
+ */
+function is_local_attachment($url) {
+ if (strpos($url, home_url()) === false)
+ return false;
+ if (strpos($url, home_url('/?attachment_id=')) !== false)
+ return true;
+ if ( $id = url_to_postid($url) ) {
+ $post = get_post($id);
+ if ( 'attachment' == $post->post_type )
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Insert an attachment.
+ *
+ * If you set the 'ID' in the $object parameter, it will mean that you are
+ * updating and attempt to update the attachment. You can also set the
+ * attachment name or title by setting the key 'post_name' or 'post_title'.
+ *
+ * You can set the dates for the attachment manually by setting the 'post_date'
+ * and 'post_date_gmt' keys' values.
+ *
+ * By default, the comments will use the default settings for whether the
+ * comments are allowed. You can close them manually or keep them open by
+ * setting the value for the 'comment_status' key.
+ *
+ * The $object parameter can have the following:
+ * 'post_status' - Default is 'draft'. Can not be overridden, set the same as parent post.
+ * 'post_type' - Default is 'post', will be set to attachment. Can not override.
+ * 'post_author' - Default is current user ID. The ID of the user, who added the attachment.
+ * 'ping_status' - Default is the value in default ping status option. Whether the attachment
+ * can accept pings.
+ * 'post_parent' - Default is 0. Can use $parent parameter or set this for the post it belongs
+ * to, if any.
+ * 'menu_order' - Default is 0. The order it is displayed.
+ * 'to_ping' - Whether to ping.
+ * 'pinged' - Default is empty string.
+ * 'post_password' - Default is empty string. The password to access the attachment.
+ * 'guid' - Global Unique ID for referencing the attachment.
+ * 'post_content_filtered' - Attachment post content filtered.
+ * 'post_excerpt' - Attachment excerpt.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses $user_ID
+ * @uses do_action() Calls 'edit_attachment' on $post_ID if this is an update.
+ * @uses do_action() Calls 'add_attachment' on $post_ID if this is not an update.
+ *
+ * @param string|array $object Arguments to override defaults.
+ * @param string $file Optional filename.
+ * @param int $parent Parent post ID.
+ * @return int Attachment ID.
+ */
+function wp_insert_attachment($object, $file = false, $parent = 0) {
+ global $wpdb, $user_ID;
+
+ $defaults = array('post_status' => 'inherit', 'post_type' => 'post', 'post_author' => $user_ID,
+ 'ping_status' => get_option('default_ping_status'), 'post_parent' => 0, 'post_title' => '',
+ 'menu_order' => 0, 'to_ping' => '', 'pinged' => '', 'post_password' => '',
+ 'guid' => '', 'post_content_filtered' => '', 'post_excerpt' => '', 'import_id' => 0, 'context' => '');
+
+ $object = wp_parse_args($object, $defaults);
+ if ( !empty($parent) )
+ $object['post_parent'] = $parent;
+
+ unset( $object[ 'filter' ] );
+
+ $object = sanitize_post($object, 'db');
+
+ // export array as variables
+ extract($object, EXTR_SKIP);
+
+ if ( empty($post_author) )
+ $post_author = $user_ID;
+
+ $post_type = 'attachment';
+
+ if ( ! in_array( $post_status, array( 'inherit', 'private' ) ) )
+ $post_status = 'inherit';
+
+ if ( !empty($post_category) )
+ $post_category = array_filter($post_category); // Filter out empty terms
+
+ // Make sure we set a valid category.
+ if ( empty($post_category) || 0 == count($post_category) || !is_array($post_category) ) {
+ $post_category = array();
+ }
+
+ // Are we updating or creating?
+ if ( !empty($ID) ) {
+ $update = true;
+ $post_ID = (int) $ID;
+ } else {
+ $update = false;
+ $post_ID = 0;
+ }
+
+ // Create a valid post name.
+ if ( empty($post_name) )
+ $post_name = sanitize_title($post_title);
+ else
+ $post_name = sanitize_title($post_name);
+
+ // expected_slashed ($post_name)
+ $post_name = wp_unique_post_slug($post_name, $post_ID, $post_status, $post_type, $post_parent);
+
+ if ( empty($post_date) )
+ $post_date = current_time('mysql');
+ if ( empty($post_date_gmt) )
+ $post_date_gmt = current_time('mysql', 1);
+
+ if ( empty($post_modified) )
+ $post_modified = $post_date;
+ if ( empty($post_modified_gmt) )
+ $post_modified_gmt = $post_date_gmt;
+
+ if ( empty($comment_status) ) {
+ if ( $update )
+ $comment_status = 'closed';
+ else
+ $comment_status = get_option('default_comment_status');
+ }
+ if ( empty($ping_status) )
+ $ping_status = get_option('default_ping_status');
+
+ if ( isset($to_ping) )
+ $to_ping = preg_replace('|\s+|', "\n", $to_ping);
+ else
+ $to_ping = '';
+
+ if ( isset($post_parent) )
+ $post_parent = (int) $post_parent;
+ else
+ $post_parent = 0;
+
+ if ( isset($menu_order) )
+ $menu_order = (int) $menu_order;
+ else
+ $menu_order = 0;
+
+ if ( !isset($post_password) )
+ $post_password = '';
+
+ if ( ! isset($pinged) )
+ $pinged = '';
+
+ // expected_slashed (everything!)
+ $data = compact( array( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ) );
+ $data = wp_unslash( $data );
+
+ if ( $update ) {
+ $wpdb->update( $wpdb->posts, $data, array( 'ID' => $post_ID ) );
+ } else {
+ // If there is a suggested ID, use it if not already present
+ if ( !empty($import_id) ) {
+ $import_id = (int) $import_id;
+ if ( ! $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE ID = %d", $import_id) ) ) {
+ $data['ID'] = $import_id;
+ }
+ }
+
+ $wpdb->insert( $wpdb->posts, $data );
+ $post_ID = (int) $wpdb->insert_id;
+ }
+
+ if ( empty($post_name) ) {
+ $post_name = sanitize_title($post_title, $post_ID);
+ $wpdb->update( $wpdb->posts, compact("post_name"), array( 'ID' => $post_ID ) );
+ }
+
+ if ( is_object_in_taxonomy($post_type, 'category') )
+ wp_set_post_categories( $post_ID, $post_category );
+
+ if ( isset( $tags_input ) && is_object_in_taxonomy($post_type, 'post_tag') )
+ wp_set_post_tags( $post_ID, $tags_input );
+
+ // support for all custom taxonomies
+ if ( !empty($tax_input) ) {
+ foreach ( $tax_input as $taxonomy => $tags ) {
+ $taxonomy_obj = get_taxonomy($taxonomy);
+ if ( is_array($tags) ) // array = hierarchical, string = non-hierarchical.
+ $tags = array_filter($tags);
+ if ( current_user_can($taxonomy_obj->cap->assign_terms) )
+ wp_set_post_terms( $post_ID, $tags, $taxonomy );
+ }
+ }
+
+ if ( $file )
+ update_attached_file( $post_ID, $file );
+
+ clean_post_cache( $post_ID );
+
+ if ( ! empty( $context ) )
+ add_post_meta( $post_ID, '_wp_attachment_context', $context, true );
+
+ if ( $update) {
+ do_action('edit_attachment', $post_ID);
+ } else {
+ do_action('add_attachment', $post_ID);
+ }
+
+ return $post_ID;
+}
+
+/**
+ * Trashes or deletes an attachment.
+ *
+ * When an attachment is permanently deleted, the file will also be removed.
+ * Deletion removes all post meta fields, taxonomy, comments, etc. associated
+ * with the attachment (except the main post).
+ *
+ * The attachment is moved to the trash instead of permanently deleted unless trash
+ * for media is disabled, item is already in the trash, or $force_delete is true.
+ *
+ * @since 2.0.0
+ * @uses $wpdb
+ * @uses do_action() Calls 'delete_attachment' hook on Attachment ID.
+ *
+ * @param int $post_id Attachment ID.
+ * @param bool $force_delete Whether to bypass trash and force deletion. Defaults to false.
+ * @return mixed False on failure. Post data on success.
+ */
+function wp_delete_attachment( $post_id, $force_delete = false ) {
+ global $wpdb;
+
+ if ( !$post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) ) )
+ return $post;
+
+ if ( 'attachment' != $post->post_type )
+ return false;
+
+ if ( !$force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' != $post->post_status )
+ return wp_trash_post( $post_id );
+
+ delete_post_meta($post_id, '_wp_trash_meta_status');
+ delete_post_meta($post_id, '_wp_trash_meta_time');
+
+ $meta = wp_get_attachment_metadata( $post_id );
+ $backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
+ $file = get_attached_file( $post_id );
+
+ $intermediate_sizes = array();
+ foreach ( get_intermediate_image_sizes() as $size ) {
+ if ( $intermediate = image_get_intermediate_size( $post_id, $size ) )
+ $intermediate_sizes[] = $intermediate;
+ }
+
+ if ( is_multisite() )
+ delete_transient( 'dirsize_cache' );
+
+ do_action('delete_attachment', $post_id);
+
+ wp_delete_object_term_relationships($post_id, array('category', 'post_tag'));
+ wp_delete_object_term_relationships($post_id, get_object_taxonomies($post->post_type));
+
+ delete_metadata( 'post', null, '_thumbnail_id', $post_id, true ); // delete all for any posts.
+
+ $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ));
+ foreach ( $comment_ids as $comment_id )
+ wp_delete_comment( $comment_id, true );
+
+ $post_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id ));
+ foreach ( $post_meta_ids as $mid )
+ delete_metadata_by_mid( 'post', $mid );
+
+ do_action( 'delete_post', $post_id );
+ $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) );
+ do_action( 'deleted_post', $post_id );
+
+ $uploadpath = wp_upload_dir();
+
+ if ( ! empty($meta['thumb']) ) {
+ // Don't delete the thumb if another attachment uses it
+ if (! $wpdb->get_row( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_wp_attachment_metadata' AND meta_value LIKE %s AND post_id <> %d", '%' . $meta['thumb'] . '%', $post_id)) ) {
+ $thumbfile = str_replace(basename($file), $meta['thumb'], $file);
+ $thumbfile = apply_filters('wp_delete_file', $thumbfile);
+ @ unlink( path_join($uploadpath['basedir'], $thumbfile) );
+ }
+ }
+
+ // remove intermediate and backup images if there are any
+ foreach ( $intermediate_sizes as $intermediate ) {
+ $intermediate_file = apply_filters( 'wp_delete_file', $intermediate['path'] );
+ @ unlink( path_join($uploadpath['basedir'], $intermediate_file) );
+ }
+
+ if ( is_array($backup_sizes) ) {
+ foreach ( $backup_sizes as $size ) {
+ $del_file = path_join( dirname($meta['file']), $size['file'] );
+ $del_file = apply_filters('wp_delete_file', $del_file);
+ @ unlink( path_join($uploadpath['basedir'], $del_file) );
+ }
+ }
+
+ $file = apply_filters('wp_delete_file', $file);
+
+ if ( ! empty($file) )
+ @ unlink($file);
+
+ clean_post_cache( $post );
+
+ return $post;
+}
+
+/**
+ * Retrieve attachment meta field for attachment ID.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID
+ * @param bool $unfiltered Optional, default is false. If true, filters are not run.
+ * @return string|bool Attachment meta field. False on failure.
+ */
+function wp_get_attachment_metadata( $post_id = 0, $unfiltered = false ) {
+ $post_id = (int) $post_id;
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ $data = get_post_meta( $post->ID, '_wp_attachment_metadata', true );
+
+ if ( $unfiltered )
+ return $data;
+
+ return apply_filters( 'wp_get_attachment_metadata', $data, $post->ID );
+}
+
+/**
+ * Update metadata for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID.
+ * @param array $data Attachment data.
+ * @return int
+ */
+function wp_update_attachment_metadata( $post_id, $data ) {
+ $post_id = (int) $post_id;
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ if ( $data = apply_filters( 'wp_update_attachment_metadata', $data, $post->ID ) )
+ return update_post_meta( $post->ID, '_wp_attachment_metadata', $data );
+ else
+ return delete_post_meta( $post->ID, '_wp_attachment_metadata' );
+}
+
+/**
+ * Retrieve the URL for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID.
+ * @return string
+ */
+function wp_get_attachment_url( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ if ( 'attachment' != $post->post_type )
+ return false;
+
+ $url = '';
+ if ( $file = get_post_meta( $post->ID, '_wp_attached_file', true) ) { //Get attached file
+ if ( ($uploads = wp_upload_dir()) && false === $uploads['error'] ) { //Get upload directory
+ if ( 0 === strpos($file, $uploads['basedir']) ) //Check that the upload base exists in the file location
+ $url = str_replace($uploads['basedir'], $uploads['baseurl'], $file); //replace file location with url location
+ elseif ( false !== strpos($file, 'wp-content/uploads') )
+ $url = $uploads['baseurl'] . substr( $file, strpos($file, 'wp-content/uploads') + 18 );
+ else
+ $url = $uploads['baseurl'] . "/$file"; //Its a newly uploaded file, therefor $file is relative to the basedir.
+ }
+ }
+
+ if ( empty($url) ) //If any of the above options failed, Fallback on the GUID as used pre-2.7, not recommended to rely upon this.
+ $url = get_the_guid( $post->ID );
+
+ $url = apply_filters( 'wp_get_attachment_url', $url, $post->ID );
+
+ if ( empty( $url ) )
+ return false;
+
+ return $url;
+}
+
+/**
+ * Retrieve thumbnail for an attachment.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID.
+ * @return mixed False on failure. Thumbnail file path on success.
+ */
+function wp_get_attachment_thumb_file( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post = get_post( $post_id ) )
+ return false;
+ if ( !is_array( $imagedata = wp_get_attachment_metadata( $post->ID ) ) )
+ return false;
+
+ $file = get_attached_file( $post->ID );
+
+ if ( !empty($imagedata['thumb']) && ($thumbfile = str_replace(basename($file), $imagedata['thumb'], $file)) && file_exists($thumbfile) )
+ return apply_filters( 'wp_get_attachment_thumb_file', $thumbfile, $post->ID );
+ return false;
+}
+
+/**
+ * Retrieve URL for an attachment thumbnail.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID
+ * @return string|bool False on failure. Thumbnail URL on success.
+ */
+function wp_get_attachment_thumb_url( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post = get_post( $post_id ) )
+ return false;
+ if ( !$url = wp_get_attachment_url( $post->ID ) )
+ return false;
+
+ $sized = image_downsize( $post_id, 'thumbnail' );
+ if ( $sized )
+ return $sized[0];
+
+ if ( !$thumb = wp_get_attachment_thumb_file( $post->ID ) )
+ return false;
+
+ $url = str_replace(basename($url), basename($thumb), $url);
+
+ return apply_filters( 'wp_get_attachment_thumb_url', $url, $post->ID );
+}
+
+/**
+ * Check if the attachment is an image.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Attachment ID
+ * @return bool
+ */
+function wp_attachment_is_image( $post_id = 0 ) {
+ $post_id = (int) $post_id;
+ if ( !$post = get_post( $post_id ) )
+ return false;
+
+ if ( !$file = get_attached_file( $post->ID ) )
+ return false;
+
+ $ext = preg_match('/\.([^.]+)$/', $file, $matches) ? strtolower($matches[1]) : false;
+
+ $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
+
+ if ( 'image/' == substr($post->post_mime_type, 0, 6) || $ext && 'import' == $post->post_mime_type && in_array($ext, $image_exts) )
+ return true;
+ return false;
+}
+
+/**
+ * Retrieve the icon for a MIME type.
+ *
+ * @since 2.1.0
+ *
+ * @param string|int $mime MIME type or attachment ID.
+ * @return string|bool
+ */
+function wp_mime_type_icon( $mime = 0 ) {
+ if ( !is_numeric($mime) )
+ $icon = wp_cache_get("mime_type_icon_$mime");
+
+ $post_id = 0;
+ if ( empty($icon) ) {
+ $post_mimes = array();
+ if ( is_numeric($mime) ) {
+ $mime = (int) $mime;
+ if ( $post = get_post( $mime ) ) {
+ $post_id = (int) $post->ID;
+ $ext = preg_replace('/^.+?\.([^.]+)$/', '$1', $post->guid);
+ if ( !empty($ext) ) {
+ $post_mimes[] = $ext;
+ if ( $ext_type = wp_ext2type( $ext ) )
+ $post_mimes[] = $ext_type;
+ }
+ $mime = $post->post_mime_type;
+ } else {
+ $mime = 0;
+ }
+ } else {
+ $post_mimes[] = $mime;
+ }
+
+ $icon_files = wp_cache_get('icon_files');
+
+ if ( !is_array($icon_files) ) {
+ $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
+ $icon_dir_uri = apply_filters( 'icon_dir_uri', includes_url('images/crystal') );
+ $dirs = apply_filters( 'icon_dirs', array($icon_dir => $icon_dir_uri) );
+ $icon_files = array();
+ while ( $dirs ) {
+ $keys = array_keys( $dirs );
+ $dir = array_shift( $keys );
+ $uri = array_shift($dirs);
+ if ( $dh = opendir($dir) ) {
+ while ( false !== $file = readdir($dh) ) {
+ $file = basename($file);
+ if ( substr($file, 0, 1) == '.' )
+ continue;
+ if ( !in_array(strtolower(substr($file, -4)), array('.png', '.gif', '.jpg') ) ) {
+ if ( is_dir("$dir/$file") )
+ $dirs["$dir/$file"] = "$uri/$file";
+ continue;
+ }
+ $icon_files["$dir/$file"] = "$uri/$file";
+ }
+ closedir($dh);
+ }
+ }
+ wp_cache_add( 'icon_files', $icon_files, 'default', 600 );
+ }
+
+ // Icon basename - extension = MIME wildcard
+ foreach ( $icon_files as $file => $uri )
+ $types[ preg_replace('/^([^.]*).*$/', '$1', basename($file)) ] =& $icon_files[$file];
+
+ if ( ! empty($mime) ) {
+ $post_mimes[] = substr($mime, 0, strpos($mime, '/'));
+ $post_mimes[] = substr($mime, strpos($mime, '/') + 1);
+ $post_mimes[] = str_replace('/', '_', $mime);
+ }
+
+ $matches = wp_match_mime_types(array_keys($types), $post_mimes);
+ $matches['default'] = array('default');
+
+ foreach ( $matches as $match => $wilds ) {
+ if ( isset($types[$wilds[0]])) {
+ $icon = $types[$wilds[0]];
+ if ( !is_numeric($mime) )
+ wp_cache_add("mime_type_icon_$mime", $icon);
+ break;
+ }
+ }
+ }
+
+ return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id ); // Last arg is 0 if function pass mime type.
+}
+
+/**
+ * Checked for changed slugs for published post objects and save the old slug.
+ *
+ * The function is used when a post object of any type is updated,
+ * by comparing the current and previous post objects.
+ *
+ * If the slug was changed and not already part of the old slugs then it will be
+ * added to the post meta field ('_wp_old_slug') for storing old slugs for that
+ * post.
+ *
+ * The most logically usage of this function is redirecting changed post objects, so
+ * that those that linked to an changed post will be redirected to the new post.
+ *
+ * @since 2.1.0
+ *
+ * @param int $post_id Post ID.
+ * @param object $post The Post Object
+ * @param object $post_before The Previous Post Object
+ * @return int Same as $post_id
+ */
+function wp_check_for_changed_slugs($post_id, $post, $post_before) {
+ // dont bother if it hasnt changed
+ if ( $post->post_name == $post_before->post_name )
+ return;
+
+ // we're only concerned with published, non-hierarchical objects
+ if ( $post->post_status != 'publish' || is_post_type_hierarchical( $post->post_type ) )
+ return;
+
+ $old_slugs = (array) get_post_meta($post_id, '_wp_old_slug');
+
+ // if we haven't added this old slug before, add it now
+ if ( !empty( $post_before->post_name ) && !in_array($post_before->post_name, $old_slugs) )
+ add_post_meta($post_id, '_wp_old_slug', $post_before->post_name);
+
+ // if the new slug was used previously, delete it from the list
+ if ( in_array($post->post_name, $old_slugs) )
+ delete_post_meta($post_id, '_wp_old_slug', $post->post_name);
+}
+
+/**
+ * Retrieve the private post SQL based on capability.
+ *
+ * This function provides a standardized way to appropriately select on the
+ * post_status of a post type. The function will return a piece of SQL code
+ * that can be added to a WHERE clause; this SQL is constructed to allow all
+ * published posts, and all private posts to which the user has access.
+ *
+ * @since 2.2.0
+ *
+ * @uses $user_ID
+ *
+ * @param string $post_type currently only supports 'post' or 'page'.
+ * @return string SQL code that can be added to a where clause.
+ */
+function get_private_posts_cap_sql( $post_type ) {
+ return get_posts_by_author_sql( $post_type, false );
+}
+
+/**
+ * Retrieve the post SQL based on capability, author, and type.
+ *
+ * @see get_private_posts_cap_sql() for full description.
+ *
+ * @since 3.0.0
+ * @param string $post_type Post type.
+ * @param bool $full Optional. Returns a full WHERE statement instead of just an 'andalso' term.
+ * @param int $post_author Optional. Query posts having a single author ID.
+ * @param bool $public_only Optional. Only return public posts. Skips cap checks for $current_user. Default is false.
+ * @return string SQL WHERE code that can be added to a query.
+ */
+function get_posts_by_author_sql( $post_type, $full = true, $post_author = null, $public_only = false ) {
+ global $user_ID, $wpdb;
+
+ // Private posts
+ $post_type_obj = get_post_type_object( $post_type );
+ if ( ! $post_type_obj )
+ return $full ? 'WHERE 1 = 0' : ' 1 = 0 ';
+
+ // This hook is deprecated. Why you'd want to use it, I dunno.
+ if ( ! $cap = apply_filters( 'pub_priv_sql_capability', '' ) )
+ $cap = $post_type_obj->cap->read_private_posts;
+
+ if ( $full ) {
+ if ( null === $post_author ) {
+ $sql = $wpdb->prepare( 'WHERE post_type = %s AND ', $post_type );
+ } else {
+ $sql = $wpdb->prepare( 'WHERE post_author = %d AND post_type = %s AND ', $post_author, $post_type );
+ }
+ } else {
+ $sql = '';
+ }
+
+ $sql .= "(post_status = 'publish'";
+
+ // Only need to check the cap if $public_only is false
+ if ( false === $public_only ) {
+ if ( current_user_can( $cap ) ) {
+ // Does the user have the capability to view private posts? Guess so.
+ $sql .= " OR post_status = 'private'";
+ } elseif ( is_user_logged_in() ) {
+ // Users can view their own private posts.
+ $id = (int) $user_ID;
+ if ( null === $post_author || ! $full ) {
+ $sql .= " OR post_status = 'private' AND post_author = $id";
+ } elseif ( $id == (int) $post_author ) {
+ $sql .= " OR post_status = 'private'";
+ } // else none
+ } // else none
+ }
+
+ $sql .= ')';
+
+ return $sql;
+}
+
+/**
+ * Retrieve the date that the last post was published.
+ *
+ * The server timezone is the default and is the difference between GMT and
+ * server time. The 'blog' value is the date when the last post was posted. The
+ * 'gmt' is when the last post was posted in GMT formatted date.
+ *
+ * @since 0.71
+ *
+ * @uses apply_filters() Calls 'get_lastpostdate' filter
+ *
+ * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
+ * @return string The date of the last post.
+ */
+function get_lastpostdate($timezone = 'server') {
+ return apply_filters( 'get_lastpostdate', _get_last_post_time( $timezone, 'date' ), $timezone );
+}
+
+/**
+ * Retrieve last post modified date depending on timezone.
+ *
+ * The server timezone is the default and is the difference between GMT and
+ * server time. The 'blog' value is just when the last post was modified. The
+ * 'gmt' is when the last post was modified in GMT time.
+ *
+ * @since 1.2.0
+ * @uses apply_filters() Calls 'get_lastpostmodified' filter
+ *
+ * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
+ * @return string The date the post was last modified.
+ */
+function get_lastpostmodified($timezone = 'server') {
+ $lastpostmodified = _get_last_post_time( $timezone, 'modified' );
+
+ $lastpostdate = get_lastpostdate($timezone);
+ if ( $lastpostdate > $lastpostmodified )
+ $lastpostmodified = $lastpostdate;
+
+ return apply_filters( 'get_lastpostmodified', $lastpostmodified, $timezone );
+}
+
+/**
+ * Retrieve latest post date data based on timezone.
+ *
+ * @access private
+ * @since 3.1.0
+ *
+ * @param string $timezone The location to get the time. Can be 'gmt', 'blog', or 'server'.
+ * @param string $field Field to check. Can be 'date' or 'modified'.
+ * @return string The date.
+ */
+function _get_last_post_time( $timezone, $field ) {
+ global $wpdb;
+
+ if ( !in_array( $field, array( 'date', 'modified' ) ) )
+ return false;
+
+ $timezone = strtolower( $timezone );
+
+ $key = "lastpost{$field}:$timezone";
+
+ $date = wp_cache_get( $key, 'timeinfo' );
+
+ if ( !$date ) {
+ $add_seconds_server = date('Z');
+
+ $post_types = get_post_types( array( 'public' => true ) );
+ array_walk( $post_types, array( &$wpdb, 'escape_by_ref' ) );
+ $post_types = "'" . implode( "', '", $post_types ) . "'";
+
+ switch ( $timezone ) {
+ case 'gmt':
+ $date = $wpdb->get_var("SELECT post_{$field}_gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
+ break;
+ case 'blog':
+ $date = $wpdb->get_var("SELECT post_{$field} FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
+ break;
+ case 'server':
+ $date = $wpdb->get_var("SELECT DATE_ADD(post_{$field}_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
+ break;
+ }
+
+ if ( $date )
+ wp_cache_set( $key, $date, 'timeinfo' );
+ }
+
+ return $date;
+}
+
+/**
+ * Updates posts in cache.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 1.5.1
+ *
+ * @param array $posts Array of post objects
+ */
+function update_post_cache( &$posts ) {
+ if ( ! $posts )
+ return;
+
+ foreach ( $posts as $post )
+ wp_cache_add( $post->ID, $post, 'posts' );
+}
+
+/**
+ * Will clean the post in the cache.
+ *
+ * Cleaning means delete from the cache of the post. Will call to clean the term
+ * object cache associated with the post ID.
+ *
+ * This function not run if $_wp_suspend_cache_invalidation is not empty. See
+ * wp_suspend_cache_invalidation().
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 2.0.0
+ *
+ * @uses do_action() Calls 'clean_post_cache' on $id before adding children (if any).
+ *
+ * @param int|object $post Post ID or object to remove from the cache
+ */
+function clean_post_cache( $post ) {
+ global $_wp_suspend_cache_invalidation, $wpdb;
+
+ if ( ! empty( $_wp_suspend_cache_invalidation ) )
+ return;
+
+ $post = get_post( $post );
+ if ( empty( $post ) )
+ return;
+
+ wp_cache_delete( $post->ID, 'posts' );
+ wp_cache_delete( $post->ID, 'post_meta' );
+
+ clean_object_term_cache( $post->ID, $post->post_type );
+
+ wp_cache_delete( 'wp_get_archives', 'general' );
+
+ do_action( 'clean_post_cache', $post->ID, $post );
+
+ if ( is_post_type_hierarchical( $post->post_type ) )
+ wp_cache_delete( 'get_pages', 'posts' );
+
+ if ( 'page' == $post->post_type ) {
+ wp_cache_delete( 'all_page_ids', 'posts' );
+ do_action( 'clean_page_cache', $post->ID );
+ }
+
+ wp_cache_set( 'last_changed', microtime(), 'posts' );
+}
+
+/**
+ * Call major cache updating functions for list of Post objects.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 1.5.0
+ *
+ * @uses update_post_cache()
+ * @uses update_object_term_cache()
+ * @uses update_postmeta_cache()
+ *
+ * @param array $posts Array of Post objects
+ * @param string $post_type The post type of the posts in $posts. Default is 'post'.
+ * @param bool $update_term_cache Whether to update the term cache. Default is true.
+ * @param bool $update_meta_cache Whether to update the meta cache. Default is true.
+ */
+function update_post_caches(&$posts, $post_type = 'post', $update_term_cache = true, $update_meta_cache = true) {
+ // No point in doing all this work if we didn't match any posts.
+ if ( !$posts )
+ return;
+
+ update_post_cache($posts);
+
+ $post_ids = array();
+ foreach ( $posts as $post )
+ $post_ids[] = $post->ID;
+
+ if ( ! $post_type )
+ $post_type = 'any';
+
+ if ( $update_term_cache ) {
+ if ( is_array($post_type) ) {
+ $ptypes = $post_type;
+ } elseif ( 'any' == $post_type ) {
+ // Just use the post_types in the supplied posts.
+ foreach ( $posts as $post )
+ $ptypes[] = $post->post_type;
+ $ptypes = array_unique($ptypes);
+ } else {
+ $ptypes = array($post_type);
+ }
+
+ if ( ! empty($ptypes) )
+ update_object_term_cache($post_ids, $ptypes);
+ }
+
+ if ( $update_meta_cache )
+ update_postmeta_cache($post_ids);
+}
+
+/**
+ * Updates metadata cache for list of post IDs.
+ *
+ * Performs SQL query to retrieve the metadata for the post IDs and updates the
+ * metadata cache for the posts. Therefore, the functions, which call this
+ * function, do not need to perform SQL queries on their own.
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 2.1.0
+ *
+ * @param array $post_ids List of post IDs.
+ * @return bool|array Returns false if there is nothing to update or an array of metadata.
+ */
+function update_postmeta_cache($post_ids) {
+ return update_meta_cache('post', $post_ids);
+}
+
+/**
+ * Will clean the attachment in the cache.
+ *
+ * Cleaning means delete from the cache. Optionally will clean the term
+ * object cache associated with the attachment ID.
+ *
+ * This function will not run if $_wp_suspend_cache_invalidation is not empty. See
+ * wp_suspend_cache_invalidation().
+ *
+ * @package WordPress
+ * @subpackage Cache
+ * @since 3.0.0
+ *
+ * @uses do_action() Calls 'clean_attachment_cache' on $id.
+ *
+ * @param int $id The attachment ID in the cache to clean
+ * @param bool $clean_terms optional. Whether to clean terms cache
+ */
+function clean_attachment_cache($id, $clean_terms = false) {
+ global $_wp_suspend_cache_invalidation;
+
+ if ( !empty($_wp_suspend_cache_invalidation) )
+ return;
+
+ $id = (int) $id;
+
+ wp_cache_delete($id, 'posts');
+ wp_cache_delete($id, 'post_meta');
+
+ if ( $clean_terms )
+ clean_object_term_cache($id, 'attachment');
+
+ do_action('clean_attachment_cache', $id);
+}
+
+//
+// Hooks
+//
+
+/**
+ * Hook for managing future post transitions to published.
+ *
+ * @since 2.3.0
+ * @access private
+ * @uses $wpdb
+ * @uses do_action() Calls 'private_to_published' on post ID if this is a 'private_to_published' call.
+ * @uses wp_clear_scheduled_hook() with 'publish_future_post' and post ID.
+ *
+ * @param string $new_status New post status
+ * @param string $old_status Previous post status
+ * @param object $post Object type containing the post information
+ */
+function _transition_post_status($new_status, $old_status, $post) {
+ global $wpdb;
+
+ if ( $old_status != 'publish' && $new_status == 'publish' ) {
+ // Reset GUID if transitioning to publish and it is empty
+ if ( '' == get_the_guid($post->ID) )
+ $wpdb->update( $wpdb->posts, array( 'guid' => get_permalink( $post->ID ) ), array( 'ID' => $post->ID ) );
+ do_action('private_to_published', $post->ID); // Deprecated, use private_to_publish
+ }
+
+ // If published posts changed clear the lastpostmodified cache
+ if ( 'publish' == $new_status || 'publish' == $old_status) {
+ foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
+ wp_cache_delete( "lastpostmodified:$timezone", 'timeinfo' );
+ wp_cache_delete( "lastpostdate:$timezone", 'timeinfo' );
+ }
+ }
+
+ // Always clears the hook in case the post status bounced from future to draft.
+ wp_clear_scheduled_hook('publish_future_post', array( $post->ID ) );
+}
+
+/**
+ * Hook used to schedule publication for a post marked for the future.
+ *
+ * The $post properties used and must exist are 'ID' and 'post_date_gmt'.
+ *
+ * @since 2.3.0
+ * @access private
+ *
+ * @param int $deprecated Not used. Can be set to null. Never implemented.
+ * Not marked as deprecated with _deprecated_argument() as it conflicts with
+ * wp_transition_post_status() and the default filter for _future_post_hook().
+ * @param object $post Object type containing the post information
+ */
+function _future_post_hook( $deprecated, $post ) {
+ wp_clear_scheduled_hook( 'publish_future_post', array( $post->ID ) );
+ wp_schedule_single_event( strtotime( get_gmt_from_date( $post->post_date ) . ' GMT') , 'publish_future_post', array( $post->ID ) );
+}
+
+/**
+ * Hook to schedule pings and enclosures when a post is published.
+ *
+ * @since 2.3.0
+ * @access private
+ * @uses XMLRPC_REQUEST and WP_IMPORTING constants.
+ * @uses do_action() Calls 'xmlrpc_publish_post' on post ID if XMLRPC_REQUEST is defined.
+ *
+ * @param int $post_id The ID in the database table of the post being published
+ */
+function _publish_post_hook($post_id) {
+ if ( defined('XMLRPC_REQUEST') )
+ do_action('xmlrpc_publish_post', $post_id);
+
+ if ( defined('WP_IMPORTING') )
+ return;
+
+ if ( get_option('default_pingback_flag') )
+ add_post_meta( $post_id, '_pingme', '1' );
+ add_post_meta( $post_id, '_encloseme', '1' );
+
+ wp_schedule_single_event(time(), 'do_pings');
+}
+
+/**
+ * Returns the post's parent's post_ID
+ *
+ * @since 3.1.0
+ *
+ * @param int $post_id
+ *
+ * @return int|bool false on error
+ */
+function wp_get_post_parent_id( $post_ID ) {
+ $post = get_post( $post_ID );
+ if ( !$post || is_wp_error( $post ) )
+ return false;
+ return (int) $post->post_parent;
+}
+
+/**
+ * Checks the given subset of the post hierarchy for hierarchy loops.
+ * Prevents loops from forming and breaks those that it finds.
+ *
+ * Attached to the wp_insert_post_parent filter.
+ *
+ * @since 3.1.0
+ * @uses wp_find_hierarchy_loop()
+ *
+ * @param int $post_parent ID of the parent for the post we're checking.
+ * @param int $post_ID ID of the post we're checking.
+ *
+ * @return int The new post_parent for the post.
+ */
+function wp_check_post_hierarchy_for_loops( $post_parent, $post_ID ) {
+ // Nothing fancy here - bail
+ if ( !$post_parent )
+ return 0;
+
+ // New post can't cause a loop
+ if ( empty( $post_ID ) )
+ return $post_parent;
+
+ // Can't be its own parent
+ if ( $post_parent == $post_ID )
+ return 0;
+
+ // Now look for larger loops
+
+ if ( !$loop = wp_find_hierarchy_loop( 'wp_get_post_parent_id', $post_ID, $post_parent ) )
+ return $post_parent; // No loop
+
+ // Setting $post_parent to the given value causes a loop
+ if ( isset( $loop[$post_ID] ) )
+ return 0;
+
+ // There's a loop, but it doesn't contain $post_ID. Break the loop.
+ foreach ( array_keys( $loop ) as $loop_member )
+ wp_update_post( array( 'ID' => $loop_member, 'post_parent' => 0 ) );
+
+ return $post_parent;
+}
+
+/**
+ * Sets a post thumbnail.
+ *
+ * @since 3.1.0
+ *
+ * @param int|object $post Post ID or object where thumbnail should be attached.
+ * @param int $thumbnail_id Thumbnail to attach.
+ * @return bool True on success, false on failure.
+ */
+function set_post_thumbnail( $post, $thumbnail_id ) {
+ $post = get_post( $post );
+ $thumbnail_id = absint( $thumbnail_id );
+ if ( $post && $thumbnail_id && get_post( $thumbnail_id ) ) {
+ if ( $thumbnail_html = wp_get_attachment_image( $thumbnail_id, 'thumbnail' ) )
+ return update_post_meta( $post->ID, '_thumbnail_id', $thumbnail_id );
+ else
+ return delete_post_meta( $post->ID, '_thumbnail_id' );
+ }
+ return false;
+}
+
+/**
+ * Removes a post thumbnail.
+ *
+ * @since 3.3.0
+ *
+ * @param int|object $post Post ID or object where thumbnail should be removed from.
+ * @return bool True on success, false on failure.
+ */
+function delete_post_thumbnail( $post ) {
+ $post = get_post( $post );
+ if ( $post )
+ return delete_post_meta( $post->ID, '_thumbnail_id' );
+ return false;
+}
+
+/**
+ * Deletes auto-drafts for new posts that are > 7 days old
+ *
+ * @since 3.4.0
+ */
+function wp_delete_auto_drafts() {
+ global $wpdb;
+
+ // Cleanup old auto-drafts more than 7 days old
+ $old_posts = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_status = 'auto-draft' AND DATE_SUB( NOW(), INTERVAL 7 DAY ) > post_date" );
+ foreach ( (array) $old_posts as $delete )
+ wp_delete_post( $delete, true ); // Force delete
+}
+
+/**
+ * Update the custom taxonomies' term counts when a post's status is changed. For example, default posts term counts (for custom taxonomies) don't include private / draft posts.
+ *
+ * @access private
+ * @param string $new_status
+ * @param string $old_status
+ * @param object $post
+ * @since 3.3.0
+ */
+function _update_term_count_on_transition_post_status( $new_status, $old_status, $post ) {
+ // Update counts for the post's terms.
+ foreach ( (array) get_object_taxonomies( $post->post_type ) as $taxonomy ) {
+ $tt_ids = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'tt_ids' ) );
+ wp_update_term_count( $tt_ids, $taxonomy );
+ }
+}
+
+/**
+ * Adds any posts from the given ids to the cache that do not already exist in cache
+ *
+ * @since 3.4.0
+ *
+ * @access private
+ *
+ * @param array $post_ids ID list
+ * @param bool $update_term_cache Whether to update the term cache. Default is true.
+ * @param bool $update_meta_cache Whether to update the meta cache. Default is true.
+ */
+function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache = true ) {
+ global $wpdb;
+
+ $non_cached_ids = _get_non_cached_ids( $ids, 'posts' );
+ if ( !empty( $non_cached_ids ) ) {
+ $fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.* FROM $wpdb->posts WHERE ID IN (%s)", join( ",", $non_cached_ids ) ) );
+
+ update_post_caches( $fresh_posts, 'any', $update_term_cache, $update_meta_cache );
+ }
+}
diff --git a/src/wp-includes/query.php b/src/wp-includes/query.php
new file mode 100644
index 0000000000..04286aa517
--- /dev/null
+++ b/src/wp-includes/query.php
@@ -0,0 +1,3679 @@
+<?php
+/**
+ * WordPress Query API
+ *
+ * The query API attempts to get which part of WordPress the user is on. It
+ * also provides functionality for getting URL query information.
+ *
+ * @link http://codex.wordpress.org/The_Loop More information on The Loop.
+ *
+ * @package WordPress
+ * @subpackage Query
+ */
+
+/**
+ * Retrieve variable in the WP_Query class.
+ *
+ * @see WP_Query::get()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param string $var The variable key to retrieve.
+ * @return mixed
+ */
+function get_query_var($var) {
+ global $wp_query;
+
+ return $wp_query->get($var);
+}
+
+/**
+ * Retrieve the currently-queried object. Wrapper for $wp_query->get_queried_object()
+ *
+ * @uses WP_Query::get_queried_object
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return object
+ */
+function get_queried_object() {
+ global $wp_query;
+ return $wp_query->get_queried_object();
+}
+
+/**
+ * Retrieve ID of the current queried object. Wrapper for $wp_query->get_queried_object_id()
+ *
+ * @uses WP_Query::get_queried_object_id()
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return int
+ */
+function get_queried_object_id() {
+ global $wp_query;
+ return $wp_query->get_queried_object_id();
+}
+
+/**
+ * Set query variable.
+ *
+ * @see WP_Query::set()
+ * @since 2.2.0
+ * @uses $wp_query
+ *
+ * @param string $var Query variable key.
+ * @param mixed $value
+ * @return null
+ */
+function set_query_var($var, $value) {
+ global $wp_query;
+
+ return $wp_query->set($var, $value);
+}
+
+/**
+ * Set up The Loop with query parameters.
+ *
+ * This will override the current WordPress Loop and shouldn't be used more than
+ * once. This must not be used within the WordPress Loop.
+ *
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param string $query
+ * @return array List of posts
+ */
+function query_posts($query) {
+ $GLOBALS['wp_query'] = new WP_Query();
+ return $GLOBALS['wp_query']->query($query);
+}
+
+/**
+ * Destroy the previous query and set up a new query.
+ *
+ * This should be used after {@link query_posts()} and before another {@link
+ * query_posts()}. This will remove obscure bugs that occur when the previous
+ * wp_query object is not destroyed properly before another is set up.
+ *
+ * @since 2.3.0
+ * @uses $wp_query
+ */
+function wp_reset_query() {
+ $GLOBALS['wp_query'] = $GLOBALS['wp_the_query'];
+ wp_reset_postdata();
+}
+
+/**
+ * After looping through a separate query, this function restores
+ * the $post global to the current post in the main query
+ *
+ * @since 3.0.0
+ * @uses $wp_query
+ */
+function wp_reset_postdata() {
+ global $wp_query;
+ if ( !empty($wp_query->post) ) {
+ $GLOBALS['post'] = $wp_query->post;
+ setup_postdata($wp_query->post);
+ }
+}
+
+/*
+ * Query type checks.
+ */
+
+/**
+ * Is the query for an existing archive page?
+ *
+ * Month, Year, Category, Author, Post Type archive...
+ *
+ * @see WP_Query::is_archive()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_archive() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_archive();
+}
+
+/**
+ * Is the query for an existing post type archive page?
+ *
+ * @see WP_Query::is_post_type_archive()
+ * @since 3.1.0
+ * @uses $wp_query
+ *
+ * @param mixed $post_types Optional. Post type or array of posts types to check against.
+ * @return bool
+ */
+function is_post_type_archive( $post_types = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_post_type_archive( $post_types );
+}
+
+/**
+ * Is the query for an existing attachment page?
+ *
+ * @see WP_Query::is_attachment()
+ * @since 2.0.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_attachment() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_attachment();
+}
+
+/**
+ * Is the query for an existing author archive page?
+ *
+ * If the $author parameter is specified, this function will additionally
+ * check if the query is for one of the authors specified.
+ *
+ * @see WP_Query::is_author()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
+ * @return bool
+ */
+function is_author( $author = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_author( $author );
+}
+
+/**
+ * Is the query for an existing category archive page?
+ *
+ * If the $category parameter is specified, this function will additionally
+ * check if the query is for one of the categories specified.
+ *
+ * @see WP_Query::is_category()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
+ * @return bool
+ */
+function is_category( $category = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_category( $category );
+}
+
+/**
+ * Is the query for an existing tag archive page?
+ *
+ * If the $tag parameter is specified, this function will additionally
+ * check if the query is for one of the tags specified.
+ *
+ * @see WP_Query::is_tag()
+ * @since 2.3.0
+ * @uses $wp_query
+ *
+ * @param mixed $slug Optional. Tag slug or array of slugs.
+ * @return bool
+ */
+function is_tag( $slug = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_tag( $slug );
+}
+
+/**
+ * Is the query for an existing taxonomy archive page?
+ *
+ * If the $taxonomy parameter is specified, this function will additionally
+ * check if the query is for that specific $taxonomy.
+ *
+ * If the $term parameter is specified in addition to the $taxonomy parameter,
+ * this function will additionally check if the query is for one of the terms
+ * specified.
+ *
+ * @see WP_Query::is_tax()
+ * @since 2.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
+ * @param mixed $term Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
+ * @return bool
+ */
+function is_tax( $taxonomy = '', $term = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_tax( $taxonomy, $term );
+}
+
+/**
+ * Whether the current URL is within the comments popup window.
+ *
+ * @see WP_Query::is_comments_popup()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_comments_popup() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_comments_popup();
+}
+
+/**
+ * Is the query for an existing date archive?
+ *
+ * @see WP_Query::is_date()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_date() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_date();
+}
+
+/**
+ * Is the query for an existing day archive?
+ *
+ * @see WP_Query::is_day()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_day() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_day();
+}
+
+/**
+ * Is the query for a feed?
+ *
+ * @see WP_Query::is_feed()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param string|array $feeds Optional feed types to check.
+ * @return bool
+ */
+function is_feed( $feeds = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_feed( $feeds );
+}
+
+/**
+ * Is the query for a comments feed?
+ *
+ * @see WP_Query::is_comments_feed()
+ * @since 3.0.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_comment_feed() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_comment_feed();
+}
+
+/**
+ * Is the query for the front page of the site?
+ *
+ * This is for what is displayed at your site's main URL.
+ *
+ * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
+ *
+ * If you set a static page for the front page of your site, this function will return
+ * true when viewing that page.
+ *
+ * Otherwise the same as @see is_home()
+ *
+ * @see WP_Query::is_front_page()
+ * @since 2.5.0
+ * @uses is_home()
+ * @uses get_option()
+ *
+ * @return bool True, if front of site.
+ */
+function is_front_page() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_front_page();
+}
+
+/**
+ * Is the query for the blog homepage?
+ *
+ * This is the page which shows the time based blog content of your site.
+ *
+ * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
+ *
+ * If you set a static page for the front page of your site, this function will return
+ * true only on the page you set as the "Posts page".
+ *
+ * @see is_front_page()
+ *
+ * @see WP_Query::is_home()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool True if blog view homepage.
+ */
+function is_home() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_home();
+}
+
+/**
+ * Is the query for an existing month archive?
+ *
+ * @see WP_Query::is_month()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_month() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_month();
+}
+
+/**
+ * Is the query for an existing single page?
+ *
+ * If the $page parameter is specified, this function will additionally
+ * check if the query is for one of the pages specified.
+ *
+ * @see is_single()
+ * @see is_singular()
+ *
+ * @see WP_Query::is_page()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $page Page ID, title, slug, or array of such.
+ * @return bool
+ */
+function is_page( $page = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_page( $page );
+}
+
+/**
+ * Is the query for paged result and not for the first page?
+ *
+ * @see WP_Query::is_paged()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_paged() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_paged();
+}
+
+/**
+ * Is the query for a post or page preview?
+ *
+ * @see WP_Query::is_preview()
+ * @since 2.0.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_preview() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_preview();
+}
+
+/**
+ * Is the query for the robots file?
+ *
+ * @see WP_Query::is_robots()
+ * @since 2.1.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_robots() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_robots();
+}
+
+/**
+ * Is the query for a search?
+ *
+ * @see WP_Query::is_search()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_search() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_search();
+}
+
+/**
+ * Is the query for an existing single post?
+ *
+ * Works for any post type, except attachments and pages
+ *
+ * If the $post parameter is specified, this function will additionally
+ * check if the query is for one of the Posts specified.
+ *
+ * @see is_page()
+ * @see is_singular()
+ *
+ * @see WP_Query::is_single()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $post Post ID, title, slug, or array of such.
+ * @return bool
+ */
+function is_single( $post = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_single( $post );
+}
+
+/**
+ * Is the query for an existing single post of any post type (post, attachment, page, ... )?
+ *
+ * If the $post_types parameter is specified, this function will additionally
+ * check if the query is for one of the Posts Types specified.
+ *
+ * @see is_page()
+ * @see is_single()
+ *
+ * @see WP_Query::is_singular()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @param mixed $post_types Optional. Post Type or array of Post Types
+ * @return bool
+ */
+function is_singular( $post_types = '' ) {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_singular( $post_types );
+}
+
+/**
+ * Is the query for a specific time?
+ *
+ * @see WP_Query::is_time()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_time() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_time();
+}
+
+/**
+ * Is the query for a trackback endpoint call?
+ *
+ * @see WP_Query::is_trackback()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_trackback() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_trackback();
+}
+
+/**
+ * Is the query for an existing year archive?
+ *
+ * @see WP_Query::is_year()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_year() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_year();
+}
+
+/**
+ * Is the query a 404 (returns no results)?
+ *
+ * @see WP_Query::is_404()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function is_404() {
+ global $wp_query;
+
+ if ( ! isset( $wp_query ) ) {
+ _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1' );
+ return false;
+ }
+
+ return $wp_query->is_404();
+}
+
+/**
+ * Is the query the main query?
+ *
+ * @since 3.3.0
+ *
+ * @return bool
+ */
+function is_main_query() {
+ global $wp_query;
+ return $wp_query->is_main_query();
+}
+
+/*
+ * The Loop. Post loop control.
+ */
+
+/**
+ * Whether current WordPress query has results to loop over.
+ *
+ * @see WP_Query::have_posts()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function have_posts() {
+ global $wp_query;
+
+ return $wp_query->have_posts();
+}
+
+/**
+ * Whether the caller is in the Loop.
+ *
+ * @since 2.0.0
+ * @uses $wp_query
+ *
+ * @return bool True if caller is within loop, false if loop hasn't started or ended.
+ */
+function in_the_loop() {
+ global $wp_query;
+
+ return $wp_query->in_the_loop;
+}
+
+/**
+ * Rewind the loop posts.
+ *
+ * @see WP_Query::rewind_posts()
+ * @since 1.5.0
+ * @uses $wp_query
+ *
+ * @return null
+ */
+function rewind_posts() {
+ global $wp_query;
+
+ return $wp_query->rewind_posts();
+}
+
+/**
+ * Iterate the post index in the loop.
+ *
+ * @see WP_Query::the_post()
+ * @since 1.5.0
+ * @uses $wp_query
+ */
+function the_post() {
+ global $wp_query;
+
+ $wp_query->the_post();
+}
+
+/*
+ * Comments loop.
+ */
+
+/**
+ * Whether there are comments to loop over.
+ *
+ * @see WP_Query::have_comments()
+ * @since 2.2.0
+ * @uses $wp_query
+ *
+ * @return bool
+ */
+function have_comments() {
+ global $wp_query;
+ return $wp_query->have_comments();
+}
+
+/**
+ * Iterate comment index in the comment loop.
+ *
+ * @see WP_Query::the_comment()
+ * @since 2.2.0
+ * @uses $wp_query
+ *
+ * @return object
+ */
+function the_comment() {
+ global $wp_query;
+ return $wp_query->the_comment();
+}
+
+/*
+ * WP_Query
+ */
+
+/**
+ * The WordPress Query class.
+ *
+ * @link http://codex.wordpress.org/Function_Reference/WP_Query Codex page.
+ *
+ * @since 1.5.0
+ */
+class WP_Query {
+
+ /**
+ * Query vars set by the user
+ *
+ * @since 1.5.0
+ * @access public
+ * @var array
+ */
+ var $query;
+
+ /**
+ * Query vars, after parsing
+ *
+ * @since 1.5.0
+ * @access public
+ * @var array
+ */
+ var $query_vars = array();
+
+ /**
+ * Taxonomy query, as passed to get_tax_sql()
+ *
+ * @since 3.1.0
+ * @access public
+ * @var object WP_Tax_Query
+ */
+ var $tax_query;
+
+ /**
+ * Metadata query container
+ *
+ * @since 3.2.0
+ * @access public
+ * @var object WP_Meta_Query
+ */
+ var $meta_query = false;
+
+ /**
+ * Holds the data for a single object that is queried.
+ *
+ * Holds the contents of a post, page, category, attachment.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var object|array
+ */
+ var $queried_object;
+
+ /**
+ * The ID of the queried object.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $queried_object_id;
+
+ /**
+ * Get post database query.
+ *
+ * @since 2.0.1
+ * @access public
+ * @var string
+ */
+ var $request;
+
+ /**
+ * List of posts.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var array
+ */
+ var $posts;
+
+ /**
+ * The amount of posts for the current query.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $post_count = 0;
+
+ /**
+ * Index of the current item in the loop.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var int
+ */
+ var $current_post = -1;
+
+ /**
+ * Whether the loop has started and the caller is in the loop.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $in_the_loop = false;
+
+ /**
+ * The current post ID.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var object
+ */
+ var $post;
+
+ /**
+ * The list of comments for current post.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var array
+ */
+ var $comments;
+
+ /**
+ * The amount of comments for the posts.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var int
+ */
+ var $comment_count = 0;
+
+ /**
+ * The index of the comment in the comment loop.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var int
+ */
+ var $current_comment = -1;
+
+ /**
+ * Current comment ID.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var int
+ */
+ var $comment;
+
+ /**
+ * The amount of found posts for the current query.
+ *
+ * If limit clause was not used, equals $post_count.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var int
+ */
+ var $found_posts = 0;
+
+ /**
+ * The amount of pages.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var int
+ */
+ var $max_num_pages = 0;
+
+ /**
+ * The amount of comment pages.
+ *
+ * @since 2.7.0
+ * @access public
+ * @var int
+ */
+ var $max_num_comment_pages = 0;
+
+ /**
+ * Set if query is single post.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_single = false;
+
+ /**
+ * Set if query is preview of blog.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $is_preview = false;
+
+ /**
+ * Set if query returns a page.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_page = false;
+
+ /**
+ * Set if query is an archive list.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_archive = false;
+
+ /**
+ * Set if query is part of a date.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_date = false;
+
+ /**
+ * Set if query contains a year.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_year = false;
+
+ /**
+ * Set if query contains a month.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_month = false;
+
+ /**
+ * Set if query contains a day.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_day = false;
+
+ /**
+ * Set if query contains time.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_time = false;
+
+ /**
+ * Set if query contains an author.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_author = false;
+
+ /**
+ * Set if query contains category.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_category = false;
+
+ /**
+ * Set if query contains tag.
+ *
+ * @since 2.3.0
+ * @access public
+ * @var bool
+ */
+ var $is_tag = false;
+
+ /**
+ * Set if query contains taxonomy.
+ *
+ * @since 2.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_tax = false;
+
+ /**
+ * Set if query was part of a search result.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_search = false;
+
+ /**
+ * Set if query is feed display.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_feed = false;
+
+ /**
+ * Set if query is comment feed display.
+ *
+ * @since 2.2.0
+ * @access public
+ * @var bool
+ */
+ var $is_comment_feed = false;
+
+ /**
+ * Set if query is trackback.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_trackback = false;
+
+ /**
+ * Set if query is blog homepage.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_home = false;
+
+ /**
+ * Set if query couldn't found anything.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_404 = false;
+
+ /**
+ * Set if query is within comments popup window.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_comments_popup = false;
+
+ /**
+ * Set if query is paged
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_paged = false;
+
+ /**
+ * Set if query is part of administration page.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var bool
+ */
+ var $is_admin = false;
+
+ /**
+ * Set if query is an attachment.
+ *
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $is_attachment = false;
+
+ /**
+ * Set if is single, is a page, or is an attachment.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_singular = false;
+
+ /**
+ * Set if query is for robots.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_robots = false;
+
+ /**
+ * Set if query contains posts.
+ *
+ * Basically, the homepage if the option isn't set for the static homepage.
+ *
+ * @since 2.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_posts_page = false;
+
+ /**
+ * Set if query is for a post type archive.
+ *
+ * @since 3.1.0
+ * @access public
+ * @var bool
+ */
+ var $is_post_type_archive = false;
+
+ /**
+ * Stores the ->query_vars state like md5(serialize( $this->query_vars ) ) so we know
+ * whether we have to re-parse because something has changed
+ *
+ * @since 3.1.0
+ * @access private
+ */
+ var $query_vars_hash = false;
+
+ /**
+ * Whether query vars have changed since the initial parse_query() call. Used to catch modifications to query vars made
+ * via pre_get_posts hooks.
+ *
+ * @since 3.1.1
+ * @access private
+ */
+ var $query_vars_changed = true;
+
+ /**
+ * Set if post thumbnails are cached
+ *
+ * @since 3.2.0
+ * @access public
+ * @var bool
+ */
+ var $thumbnails_cached = false;
+
+ /**
+ * Resets query flags to false.
+ *
+ * The query flags are what page info WordPress was able to figure out.
+ *
+ * @since 2.0.0
+ * @access private
+ */
+ function init_query_flags() {
+ $this->is_single = false;
+ $this->is_preview = false;
+ $this->is_page = false;
+ $this->is_archive = false;
+ $this->is_date = false;
+ $this->is_year = false;
+ $this->is_month = false;
+ $this->is_day = false;
+ $this->is_time = false;
+ $this->is_author = false;
+ $this->is_category = false;
+ $this->is_tag = false;
+ $this->is_tax = false;
+ $this->is_search = false;
+ $this->is_feed = false;
+ $this->is_comment_feed = false;
+ $this->is_trackback = false;
+ $this->is_home = false;
+ $this->is_404 = false;
+ $this->is_comments_popup = false;
+ $this->is_paged = false;
+ $this->is_admin = false;
+ $this->is_attachment = false;
+ $this->is_singular = false;
+ $this->is_robots = false;
+ $this->is_posts_page = false;
+ $this->is_post_type_archive = false;
+ }
+
+ /**
+ * Initiates object properties and sets default values.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function init() {
+ unset($this->posts);
+ unset($this->query);
+ $this->query_vars = array();
+ unset($this->queried_object);
+ unset($this->queried_object_id);
+ $this->post_count = 0;
+ $this->current_post = -1;
+ $this->in_the_loop = false;
+ unset( $this->request );
+ unset( $this->post );
+ unset( $this->comments );
+ unset( $this->comment );
+ $this->comment_count = 0;
+ $this->current_comment = -1;
+ $this->found_posts = 0;
+ $this->max_num_pages = 0;
+ $this->max_num_comment_pages = 0;
+
+ $this->init_query_flags();
+ }
+
+ /**
+ * Reparse the query vars.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function parse_query_vars() {
+ $this->parse_query();
+ }
+
+ /**
+ * Fills in the query variables, which do not exist within the parameter.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param array $array Defined query variables.
+ * @return array Complete query variables with undefined ones filled in empty.
+ */
+ function fill_query_vars($array) {
+ $keys = array(
+ 'error'
+ , 'm'
+ , 'p'
+ , 'post_parent'
+ , 'subpost'
+ , 'subpost_id'
+ , 'attachment'
+ , 'attachment_id'
+ , 'name'
+ , 'static'
+ , 'pagename'
+ , 'page_id'
+ , 'second'
+ , 'minute'
+ , 'hour'
+ , 'day'
+ , 'monthnum'
+ , 'year'
+ , 'w'
+ , 'category_name'
+ , 'tag'
+ , 'cat'
+ , 'tag_id'
+ , 'author_name'
+ , 'feed'
+ , 'tb'
+ , 'paged'
+ , 'comments_popup'
+ , 'meta_key'
+ , 'meta_value'
+ , 'preview'
+ , 's'
+ , 'sentence'
+ , 'fields'
+ , 'menu_order'
+ );
+
+ foreach ( $keys as $key ) {
+ if ( !isset($array[$key]) )
+ $array[$key] = '';
+ }
+
+ $array_keys = array( 'category__in', 'category__not_in', 'category__and', 'post__in', 'post__not_in',
+ 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'post_parent__in', 'post_parent__not_in' );
+
+ foreach ( $array_keys as $key ) {
+ if ( !isset($array[$key]) )
+ $array[$key] = array();
+ }
+ return $array;
+ }
+
+ /**
+ * Parse a query string and set query type booleans.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string|array $query Optional query.
+ */
+ function parse_query( $query = '' ) {
+ if ( ! empty( $query ) ) {
+ $this->init();
+ $this->query = $this->query_vars = wp_parse_args( $query );
+ } elseif ( ! isset( $this->query ) ) {
+ $this->query = $this->query_vars;
+ }
+
+ $this->query_vars = $this->fill_query_vars($this->query_vars);
+ $qv = &$this->query_vars;
+ $this->query_vars_changed = true;
+
+ if ( ! empty($qv['robots']) )
+ $this->is_robots = true;
+
+ $qv['p'] = absint($qv['p']);
+ $qv['page_id'] = absint($qv['page_id']);
+ $qv['year'] = absint($qv['year']);
+ $qv['monthnum'] = absint($qv['monthnum']);
+ $qv['day'] = absint($qv['day']);
+ $qv['w'] = absint($qv['w']);
+ $qv['m'] = absint($qv['m']);
+ $qv['paged'] = absint($qv['paged']);
+ $qv['cat'] = preg_replace( '|[^0-9,-]|', '', $qv['cat'] ); // comma separated list of positive or negative integers
+ $qv['pagename'] = trim( $qv['pagename'] );
+ $qv['name'] = trim( $qv['name'] );
+ if ( '' !== $qv['hour'] ) $qv['hour'] = absint($qv['hour']);
+ if ( '' !== $qv['minute'] ) $qv['minute'] = absint($qv['minute']);
+ if ( '' !== $qv['second'] ) $qv['second'] = absint($qv['second']);
+ if ( '' !== $qv['menu_order'] ) $qv['menu_order'] = absint($qv['menu_order']);
+
+ // Compat. Map subpost to attachment.
+ if ( '' != $qv['subpost'] )
+ $qv['attachment'] = $qv['subpost'];
+ if ( '' != $qv['subpost_id'] )
+ $qv['attachment_id'] = $qv['subpost_id'];
+
+ $qv['attachment_id'] = absint($qv['attachment_id']);
+
+ if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
+ $this->is_single = true;
+ $this->is_attachment = true;
+ } elseif ( '' != $qv['name'] ) {
+ $this->is_single = true;
+ } elseif ( $qv['p'] ) {
+ $this->is_single = true;
+ } elseif ( ('' !== $qv['hour']) && ('' !== $qv['minute']) &&('' !== $qv['second']) && ('' != $qv['year']) && ('' != $qv['monthnum']) && ('' != $qv['day']) ) {
+ // If year, month, day, hour, minute, and second are set, a single
+ // post is being queried.
+ $this->is_single = true;
+ } elseif ( '' != $qv['static'] || '' != $qv['pagename'] || !empty($qv['page_id']) ) {
+ $this->is_page = true;
+ $this->is_single = false;
+ } else {
+ // Look for archive queries. Dates, categories, authors, search, post type archives.
+
+ if ( !empty($qv['s']) ) {
+ $this->is_search = true;
+ }
+
+ if ( '' !== $qv['second'] ) {
+ $this->is_time = true;
+ $this->is_date = true;
+ }
+
+ if ( '' !== $qv['minute'] ) {
+ $this->is_time = true;
+ $this->is_date = true;
+ }
+
+ if ( '' !== $qv['hour'] ) {
+ $this->is_time = true;
+ $this->is_date = true;
+ }
+
+ if ( $qv['day'] ) {
+ if ( ! $this->is_date ) {
+ $this->is_day = true;
+ $this->is_date = true;
+ }
+ }
+
+ if ( $qv['monthnum'] ) {
+ if ( ! $this->is_date ) {
+ $this->is_month = true;
+ $this->is_date = true;
+ }
+ }
+
+ if ( $qv['year'] ) {
+ if ( ! $this->is_date ) {
+ $this->is_year = true;
+ $this->is_date = true;
+ }
+ }
+
+ if ( $qv['m'] ) {
+ $this->is_date = true;
+ if ( strlen($qv['m']) > 9 ) {
+ $this->is_time = true;
+ } else if ( strlen($qv['m']) > 7 ) {
+ $this->is_day = true;
+ } else if ( strlen($qv['m']) > 5 ) {
+ $this->is_month = true;
+ } else {
+ $this->is_year = true;
+ }
+ }
+
+ if ( '' != $qv['w'] ) {
+ $this->is_date = true;
+ }
+
+ $this->query_vars_hash = false;
+ $this->parse_tax_query( $qv );
+
+ foreach ( $this->tax_query->queries as $tax_query ) {
+ if ( 'NOT IN' != $tax_query['operator'] ) {
+ switch ( $tax_query['taxonomy'] ) {
+ case 'category':
+ $this->is_category = true;
+ break;
+ case 'post_tag':
+ $this->is_tag = true;
+ break;
+ default:
+ $this->is_tax = true;
+ }
+ }
+ }
+ unset( $tax_query );
+
+ if ( empty($qv['author']) || ($qv['author'] == '0') ) {
+ $this->is_author = false;
+ } else {
+ $this->is_author = true;
+ }
+
+ if ( '' != $qv['author_name'] )
+ $this->is_author = true;
+
+ if ( !empty( $qv['post_type'] ) && ! is_array( $qv['post_type'] ) ) {
+ $post_type_obj = get_post_type_object( $qv['post_type'] );
+ if ( ! empty( $post_type_obj->has_archive ) )
+ $this->is_post_type_archive = true;
+ }
+
+ if ( $this->is_post_type_archive || $this->is_date || $this->is_author || $this->is_category || $this->is_tag || $this->is_tax )
+ $this->is_archive = true;
+ }
+
+ if ( '' != $qv['feed'] )
+ $this->is_feed = true;
+
+ if ( '' != $qv['tb'] )
+ $this->is_trackback = true;
+
+ if ( '' != $qv['paged'] && ( intval($qv['paged']) > 1 ) )
+ $this->is_paged = true;
+
+ if ( '' != $qv['comments_popup'] )
+ $this->is_comments_popup = true;
+
+ // if we're previewing inside the write screen
+ if ( '' != $qv['preview'] )
+ $this->is_preview = true;
+
+ if ( is_admin() )
+ $this->is_admin = true;
+
+ if ( false !== strpos($qv['feed'], 'comments-') ) {
+ $qv['feed'] = str_replace('comments-', '', $qv['feed']);
+ $qv['withcomments'] = 1;
+ }
+
+ $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
+
+ if ( $this->is_feed && ( !empty($qv['withcomments']) || ( empty($qv['withoutcomments']) && $this->is_singular ) ) )
+ $this->is_comment_feed = true;
+
+ if ( !( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed || $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_comments_popup || $this->is_robots ) )
+ $this->is_home = true;
+
+ // Correct is_* for page_on_front and page_for_posts
+ if ( $this->is_home && 'page' == get_option('show_on_front') && get_option('page_on_front') ) {
+ $_query = wp_parse_args($this->query);
+ // pagename can be set and empty depending on matched rewrite rules. Ignore an empty pagename.
+ if ( isset($_query['pagename']) && '' == $_query['pagename'] )
+ unset($_query['pagename']);
+ if ( empty($_query) || !array_diff( array_keys($_query), array('preview', 'page', 'paged', 'cpage') ) ) {
+ $this->is_page = true;
+ $this->is_home = false;
+ $qv['page_id'] = get_option('page_on_front');
+ // Correct <!--nextpage--> for page_on_front
+ if ( !empty($qv['paged']) ) {
+ $qv['page'] = $qv['paged'];
+ unset($qv['paged']);
+ }
+ }
+ }
+
+ if ( '' != $qv['pagename'] ) {
+ $this->queried_object = get_page_by_path($qv['pagename']);
+ if ( !empty($this->queried_object) )
+ $this->queried_object_id = (int) $this->queried_object->ID;
+ else
+ unset($this->queried_object);
+
+ if ( 'page' == get_option('show_on_front') && isset($this->queried_object_id) && $this->queried_object_id == get_option('page_for_posts') ) {
+ $this->is_page = false;
+ $this->is_home = true;
+ $this->is_posts_page = true;
+ }
+ }
+
+ if ( $qv['page_id'] ) {
+ if ( 'page' == get_option('show_on_front') && $qv['page_id'] == get_option('page_for_posts') ) {
+ $this->is_page = false;
+ $this->is_home = true;
+ $this->is_posts_page = true;
+ }
+ }
+
+ if ( !empty($qv['post_type']) ) {
+ if ( is_array($qv['post_type']) )
+ $qv['post_type'] = array_map('sanitize_key', $qv['post_type']);
+ else
+ $qv['post_type'] = sanitize_key($qv['post_type']);
+ }
+
+ if ( ! empty( $qv['post_status'] ) ) {
+ if ( is_array( $qv['post_status'] ) )
+ $qv['post_status'] = array_map('sanitize_key', $qv['post_status']);
+ else
+ $qv['post_status'] = preg_replace('|[^a-z0-9_,-]|', '', $qv['post_status']);
+ }
+
+ if ( $this->is_posts_page && ( ! isset($qv['withcomments']) || ! $qv['withcomments'] ) )
+ $this->is_comment_feed = false;
+
+ $this->is_singular = $this->is_single || $this->is_page || $this->is_attachment;
+ // Done correcting is_* for page_on_front and page_for_posts
+
+ if ( '404' == $qv['error'] )
+ $this->set_404();
+
+ $this->query_vars_hash = md5( serialize( $this->query_vars ) );
+ $this->query_vars_changed = false;
+
+ do_action_ref_array('parse_query', array(&$this));
+ }
+
+ /*
+ * Parses various taxonomy related query vars.
+ *
+ * @access protected
+ * @since 3.1.0
+ *
+ * @param array &$q The query variables
+ */
+ function parse_tax_query( &$q ) {
+ if ( ! empty( $q['tax_query'] ) && is_array( $q['tax_query'] ) ) {
+ $tax_query = $q['tax_query'];
+ } else {
+ $tax_query = array();
+ }
+
+ if ( !empty($q['taxonomy']) && !empty($q['term']) ) {
+ $tax_query[] = array(
+ 'taxonomy' => $q['taxonomy'],
+ 'terms' => array( $q['term'] ),
+ 'field' => 'slug',
+ );
+ }
+
+ foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t ) {
+ if ( 'post_tag' == $taxonomy )
+ continue; // Handled further down in the $q['tag'] block
+
+ if ( $t->query_var && !empty( $q[$t->query_var] ) ) {
+ $tax_query_defaults = array(
+ 'taxonomy' => $taxonomy,
+ 'field' => 'slug',
+ );
+
+ if ( isset( $t->rewrite['hierarchical'] ) && $t->rewrite['hierarchical'] ) {
+ $q[$t->query_var] = wp_basename( $q[$t->query_var] );
+ }
+
+ $term = $q[$t->query_var];
+
+ if ( strpos($term, '+') !== false ) {
+ $terms = preg_split( '/[+]+/', $term );
+ foreach ( $terms as $term ) {
+ $tax_query[] = array_merge( $tax_query_defaults, array(
+ 'terms' => array( $term )
+ ) );
+ }
+ } else {
+ $tax_query[] = array_merge( $tax_query_defaults, array(
+ 'terms' => preg_split( '/[,]+/', $term )
+ ) );
+ }
+ }
+ }
+
+ // Category stuff
+ if ( !empty($q['cat']) && '0' != $q['cat'] && !$this->is_singular && $this->query_vars_changed ) {
+ $q['cat'] = ''.urldecode($q['cat']).'';
+ $q['cat'] = addslashes_gpc($q['cat']);
+ $cat_array = preg_split('/[,\s]+/', $q['cat']);
+ $q['cat'] = '';
+ $req_cats = array();
+ foreach ( (array) $cat_array as $cat ) {
+ $cat = intval($cat);
+ $req_cats[] = $cat;
+ $in = ($cat > 0);
+ $cat = abs($cat);
+ if ( $in ) {
+ $q['category__in'][] = $cat;
+ $q['category__in'] = array_merge( $q['category__in'], get_term_children($cat, 'category') );
+ } else {
+ $q['category__not_in'][] = $cat;
+ $q['category__not_in'] = array_merge( $q['category__not_in'], get_term_children($cat, 'category') );
+ }
+ }
+ $q['cat'] = implode(',', $req_cats);
+ }
+
+ if ( !empty($q['category__in']) ) {
+ $q['category__in'] = array_map('absint', array_unique( (array) $q['category__in'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'category',
+ 'terms' => $q['category__in'],
+ 'field' => 'term_id',
+ 'include_children' => false
+ );
+ }
+
+ if ( !empty($q['category__not_in']) ) {
+ $q['category__not_in'] = array_map('absint', array_unique( (array) $q['category__not_in'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'category',
+ 'terms' => $q['category__not_in'],
+ 'operator' => 'NOT IN',
+ 'include_children' => false
+ );
+ }
+
+ if ( !empty($q['category__and']) ) {
+ $q['category__and'] = array_map('absint', array_unique( (array) $q['category__and'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'category',
+ 'terms' => $q['category__and'],
+ 'field' => 'term_id',
+ 'operator' => 'AND',
+ 'include_children' => false
+ );
+ }
+
+ // Tag stuff
+ if ( '' != $q['tag'] && !$this->is_singular && $this->query_vars_changed ) {
+ if ( strpos($q['tag'], ',') !== false ) {
+ $tags = preg_split('/[,\r\n\t ]+/', $q['tag']);
+ foreach ( (array) $tags as $tag ) {
+ $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
+ $q['tag_slug__in'][] = $tag;
+ }
+ } else if ( preg_match('/[+\r\n\t ]+/', $q['tag']) || !empty($q['cat']) ) {
+ $tags = preg_split('/[+\r\n\t ]+/', $q['tag']);
+ foreach ( (array) $tags as $tag ) {
+ $tag = sanitize_term_field('slug', $tag, 0, 'post_tag', 'db');
+ $q['tag_slug__and'][] = $tag;
+ }
+ } else {
+ $q['tag'] = sanitize_term_field('slug', $q['tag'], 0, 'post_tag', 'db');
+ $q['tag_slug__in'][] = $q['tag'];
+ }
+ }
+
+ if ( !empty($q['tag_id']) ) {
+ $q['tag_id'] = absint( $q['tag_id'] );
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $q['tag_id']
+ );
+ }
+
+ if ( !empty($q['tag__in']) ) {
+ $q['tag__in'] = array_map('absint', array_unique( (array) $q['tag__in'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $q['tag__in']
+ );
+ }
+
+ if ( !empty($q['tag__not_in']) ) {
+ $q['tag__not_in'] = array_map('absint', array_unique( (array) $q['tag__not_in'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $q['tag__not_in'],
+ 'operator' => 'NOT IN'
+ );
+ }
+
+ if ( !empty($q['tag__and']) ) {
+ $q['tag__and'] = array_map('absint', array_unique( (array) $q['tag__and'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $q['tag__and'],
+ 'operator' => 'AND'
+ );
+ }
+
+ if ( !empty($q['tag_slug__in']) ) {
+ $q['tag_slug__in'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__in'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $q['tag_slug__in'],
+ 'field' => 'slug'
+ );
+ }
+
+ if ( !empty($q['tag_slug__and']) ) {
+ $q['tag_slug__and'] = array_map('sanitize_title_for_query', array_unique( (array) $q['tag_slug__and'] ) );
+ $tax_query[] = array(
+ 'taxonomy' => 'post_tag',
+ 'terms' => $q['tag_slug__and'],
+ 'field' => 'slug',
+ 'operator' => 'AND'
+ );
+ }
+
+ $this->tax_query = new WP_Tax_Query( $tax_query );
+ }
+
+ /**
+ * Sets the 404 property and saves whether query is feed.
+ *
+ * @since 2.0.0
+ * @access public
+ */
+ function set_404() {
+ $is_feed = $this->is_feed;
+
+ $this->init_query_flags();
+ $this->is_404 = true;
+
+ $this->is_feed = $is_feed;
+ }
+
+ /**
+ * Retrieve query variable.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query_var Query variable key.
+ * @return mixed
+ */
+ function get($query_var) {
+ if ( isset($this->query_vars[$query_var]) )
+ return $this->query_vars[$query_var];
+
+ return '';
+ }
+
+ /**
+ * Set query variable.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query_var Query variable key.
+ * @param mixed $value Query variable value.
+ */
+ function set($query_var, $value) {
+ $this->query_vars[$query_var] = $value;
+ }
+
+ /**
+ * Retrieve the posts based on query variables.
+ *
+ * There are a few filters and actions that can be used to modify the post
+ * database query.
+ *
+ * @since 1.5.0
+ * @access public
+ * @uses do_action_ref_array() Calls 'pre_get_posts' hook before retrieving posts.
+ *
+ * @return array List of posts.
+ */
+ function get_posts() {
+ global $wpdb, $user_ID, $_wp_using_ext_object_cache;
+
+ $this->parse_query();
+
+ do_action_ref_array('pre_get_posts', array(&$this));
+
+ // Shorthand.
+ $q = &$this->query_vars;
+
+ // Fill again in case pre_get_posts unset some vars.
+ $q = $this->fill_query_vars($q);
+
+ // Parse meta query
+ $this->meta_query = new WP_Meta_Query();
+ $this->meta_query->parse_query_vars( $q );
+
+ // Set a flag if a pre_get_posts hook changed the query vars.
+ $hash = md5( serialize( $this->query_vars ) );
+ if ( $hash != $this->query_vars_hash ) {
+ $this->query_vars_changed = true;
+ $this->query_vars_hash = $hash;
+ }
+ unset($hash);
+
+ // First let's clear some variables
+ $distinct = '';
+ $whichauthor = '';
+ $whichmimetype = '';
+ $where = '';
+ $limits = '';
+ $join = '';
+ $search = '';
+ $groupby = '';
+ $fields = '';
+ $post_status_join = false;
+ $page = 1;
+
+ if ( isset( $q['caller_get_posts'] ) ) {
+ _deprecated_argument( 'WP_Query', '3.1', __( '"caller_get_posts" is deprecated. Use "ignore_sticky_posts" instead.' ) );
+ if ( !isset( $q['ignore_sticky_posts'] ) )
+ $q['ignore_sticky_posts'] = $q['caller_get_posts'];
+ }
+
+ if ( !isset( $q['ignore_sticky_posts'] ) )
+ $q['ignore_sticky_posts'] = false;
+
+ if ( !isset($q['suppress_filters']) )
+ $q['suppress_filters'] = false;
+
+ if ( !isset($q['cache_results']) ) {
+ if ( $_wp_using_ext_object_cache )
+ $q['cache_results'] = false;
+ else
+ $q['cache_results'] = true;
+ }
+
+ if ( !isset($q['update_post_term_cache']) )
+ $q['update_post_term_cache'] = true;
+
+ if ( !isset($q['update_post_meta_cache']) )
+ $q['update_post_meta_cache'] = true;
+
+ if ( !isset($q['post_type']) ) {
+ if ( $this->is_search )
+ $q['post_type'] = 'any';
+ else
+ $q['post_type'] = '';
+ }
+ $post_type = $q['post_type'];
+ if ( !isset($q['posts_per_page']) || $q['posts_per_page'] == 0 )
+ $q['posts_per_page'] = get_option('posts_per_page');
+ if ( isset($q['showposts']) && $q['showposts'] ) {
+ $q['showposts'] = (int) $q['showposts'];
+ $q['posts_per_page'] = $q['showposts'];
+ }
+ if ( (isset($q['posts_per_archive_page']) && $q['posts_per_archive_page'] != 0) && ($this->is_archive || $this->is_search) )
+ $q['posts_per_page'] = $q['posts_per_archive_page'];
+ if ( !isset($q['nopaging']) ) {
+ if ( $q['posts_per_page'] == -1 ) {
+ $q['nopaging'] = true;
+ } else {
+ $q['nopaging'] = false;
+ }
+ }
+ if ( $this->is_feed ) {
+ $q['posts_per_page'] = get_option('posts_per_rss');
+ $q['nopaging'] = false;
+ }
+ $q['posts_per_page'] = (int) $q['posts_per_page'];
+ if ( $q['posts_per_page'] < -1 )
+ $q['posts_per_page'] = abs($q['posts_per_page']);
+ else if ( $q['posts_per_page'] == 0 )
+ $q['posts_per_page'] = 1;
+
+ if ( !isset($q['comments_per_page']) || $q['comments_per_page'] == 0 )
+ $q['comments_per_page'] = get_option('comments_per_page');
+
+ if ( $this->is_home && (empty($this->query) || $q['preview'] == 'true') && ( 'page' == get_option('show_on_front') ) && get_option('page_on_front') ) {
+ $this->is_page = true;
+ $this->is_home = false;
+ $q['page_id'] = get_option('page_on_front');
+ }
+
+ if ( isset($q['page']) ) {
+ $q['page'] = trim($q['page'], '/');
+ $q['page'] = absint($q['page']);
+ }
+
+ // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present.
+ if ( isset($q['no_found_rows']) )
+ $q['no_found_rows'] = (bool) $q['no_found_rows'];
+ else
+ $q['no_found_rows'] = false;
+
+ switch ( $q['fields'] ) {
+ case 'ids':
+ $fields = "$wpdb->posts.ID";
+ break;
+ case 'id=>parent':
+ $fields = "$wpdb->posts.ID, $wpdb->posts.post_parent";
+ break;
+ default:
+ $fields = "$wpdb->posts.*";
+ }
+
+ if ( '' !== $q['menu_order'] )
+ $where .= " AND $wpdb->posts.menu_order = " . $q['menu_order'];
+
+ // If a month is specified in the querystring, load that month
+ if ( $q['m'] ) {
+ $q['m'] = '' . preg_replace('|[^0-9]|', '', $q['m']);
+ $where .= " AND YEAR($wpdb->posts.post_date)=" . substr($q['m'], 0, 4);
+ if ( strlen($q['m']) > 5 )
+ $where .= " AND MONTH($wpdb->posts.post_date)=" . substr($q['m'], 4, 2);
+ if ( strlen($q['m']) > 7 )
+ $where .= " AND DAYOFMONTH($wpdb->posts.post_date)=" . substr($q['m'], 6, 2);
+ if ( strlen($q['m']) > 9 )
+ $where .= " AND HOUR($wpdb->posts.post_date)=" . substr($q['m'], 8, 2);
+ if ( strlen($q['m']) > 11 )
+ $where .= " AND MINUTE($wpdb->posts.post_date)=" . substr($q['m'], 10, 2);
+ if ( strlen($q['m']) > 13 )
+ $where .= " AND SECOND($wpdb->posts.post_date)=" . substr($q['m'], 12, 2);
+ }
+
+ if ( '' !== $q['hour'] )
+ $where .= " AND HOUR($wpdb->posts.post_date)='" . $q['hour'] . "'";
+
+ if ( '' !== $q['minute'] )
+ $where .= " AND MINUTE($wpdb->posts.post_date)='" . $q['minute'] . "'";
+
+ if ( '' !== $q['second'] )
+ $where .= " AND SECOND($wpdb->posts.post_date)='" . $q['second'] . "'";
+
+ if ( $q['year'] )
+ $where .= " AND YEAR($wpdb->posts.post_date)='" . $q['year'] . "'";
+
+ if ( $q['monthnum'] )
+ $where .= " AND MONTH($wpdb->posts.post_date)='" . $q['monthnum'] . "'";
+
+ if ( $q['day'] )
+ $where .= " AND DAYOFMONTH($wpdb->posts.post_date)='" . $q['day'] . "'";
+
+ // If we've got a post_type AND it's not "any" post_type.
+ if ( !empty($q['post_type']) && 'any' != $q['post_type'] ) {
+ foreach ( (array)$q['post_type'] as $_post_type ) {
+ $ptype_obj = get_post_type_object($_post_type);
+ if ( !$ptype_obj || !$ptype_obj->query_var || empty($q[ $ptype_obj->query_var ]) )
+ continue;
+
+ if ( ! $ptype_obj->hierarchical || strpos($q[ $ptype_obj->query_var ], '/') === false ) {
+ // Non-hierarchical post_types & parent-level-hierarchical post_types can directly use 'name'
+ $q['name'] = $q[ $ptype_obj->query_var ];
+ } else {
+ // Hierarchical post_types will operate through the
+ $q['pagename'] = $q[ $ptype_obj->query_var ];
+ $q['name'] = '';
+ }
+
+ // Only one request for a slug is possible, this is why name & pagename are overwritten above.
+ break;
+ } //end foreach
+ unset($ptype_obj);
+ }
+
+ if ( '' != $q['name'] ) {
+ $q['name'] = sanitize_title_for_query( $q['name'] );
+ $where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
+ } elseif ( '' != $q['pagename'] ) {
+ if ( isset($this->queried_object_id) ) {
+ $reqpage = $this->queried_object_id;
+ } else {
+ if ( 'page' != $q['post_type'] ) {
+ foreach ( (array)$q['post_type'] as $_post_type ) {
+ $ptype_obj = get_post_type_object($_post_type);
+ if ( !$ptype_obj || !$ptype_obj->hierarchical )
+ continue;
+
+ $reqpage = get_page_by_path($q['pagename'], OBJECT, $_post_type);
+ if ( $reqpage )
+ break;
+ }
+ unset($ptype_obj);
+ } else {
+ $reqpage = get_page_by_path($q['pagename']);
+ }
+ if ( !empty($reqpage) )
+ $reqpage = $reqpage->ID;
+ else
+ $reqpage = 0;
+ }
+
+ $page_for_posts = get_option('page_for_posts');
+ if ( ('page' != get_option('show_on_front') ) || empty($page_for_posts) || ( $reqpage != $page_for_posts ) ) {
+ $q['pagename'] = sanitize_title_for_query( wp_basename( $q['pagename'] ) );
+ $q['name'] = $q['pagename'];
+ $where .= " AND ($wpdb->posts.ID = '$reqpage')";
+ $reqpage_obj = get_post( $reqpage );
+ if ( is_object($reqpage_obj) && 'attachment' == $reqpage_obj->post_type ) {
+ $this->is_attachment = true;
+ $post_type = $q['post_type'] = 'attachment';
+ $this->is_page = true;
+ $q['attachment_id'] = $reqpage;
+ }
+ }
+ } elseif ( '' != $q['attachment'] ) {
+ $q['attachment'] = sanitize_title_for_query( wp_basename( $q['attachment'] ) );
+ $q['name'] = $q['attachment'];
+ $where .= " AND $wpdb->posts.post_name = '" . $q['attachment'] . "'";
+ }
+
+ if ( $q['w'] )
+ $where .= ' AND ' . _wp_mysql_week( "`$wpdb->posts`.`post_date`" ) . " = '" . $q['w'] . "'";
+
+ if ( intval($q['comments_popup']) )
+ $q['p'] = absint($q['comments_popup']);
+
+ // If an attachment is requested by number, let it supersede any post number.
+ if ( $q['attachment_id'] )
+ $q['p'] = absint($q['attachment_id']);
+
+ // If a post number is specified, load that post
+ if ( $q['p'] ) {
+ $where .= " AND {$wpdb->posts}.ID = " . $q['p'];
+ } elseif ( $q['post__in'] ) {
+ $post__in = implode(',', array_map( 'absint', $q['post__in'] ));
+ $where .= " AND {$wpdb->posts}.ID IN ($post__in)";
+ } elseif ( $q['post__not_in'] ) {
+ $post__not_in = implode(',', array_map( 'absint', $q['post__not_in'] ));
+ $where .= " AND {$wpdb->posts}.ID NOT IN ($post__not_in)";
+ }
+
+ if ( is_numeric( $q['post_parent'] ) ) {
+ $where .= $wpdb->prepare( " AND $wpdb->posts.post_parent = %d ", $q['post_parent'] );
+ } elseif ( $q['post_parent__in'] ) {
+ $post_parent__in = implode( ',', array_map( 'absint', $q['post_parent__in'] ) );
+ $where .= " AND {$wpdb->posts}.post_parent IN ($post_parent__in)";
+ } elseif ( $q['post_parent__not_in'] ) {
+ $post_parent__not_in = implode( ',', array_map( 'absint', $q['post_parent__not_in'] ) );
+ $where .= " AND {$wpdb->posts}.post_parent NOT IN ($post_parent__not_in)";
+ }
+
+ if ( $q['page_id'] ) {
+ if ( ('page' != get_option('show_on_front') ) || ( $q['page_id'] != get_option('page_for_posts') ) ) {
+ $q['p'] = $q['page_id'];
+ $where = " AND {$wpdb->posts}.ID = " . $q['page_id'];
+ }
+ }
+
+ // If a search pattern is specified, load the posts that match
+ if ( !empty($q['s']) ) {
+ // added slashes screw with quote grouping when done early, so done later
+ $q['s'] = stripslashes($q['s']);
+ if ( empty( $_GET['s'] ) && $this->is_main_query() )
+ $q['s'] = urldecode($q['s']);
+ if ( !empty($q['sentence']) ) {
+ $q['search_terms'] = array($q['s']);
+ } else {
+ preg_match_all('/".*?("|$)|((?<=[\r\n\t ",+])|^)[^\r\n\t ",+]+/', $q['s'], $matches);
+ $q['search_terms'] = array_map('_search_terms_tidy', $matches[0]);
+ }
+ $n = !empty($q['exact']) ? '' : '%';
+ $searchand = '';
+ foreach( (array) $q['search_terms'] as $term ) {
+ $term = esc_sql( like_escape( $term ) );
+ $search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";
+ $searchand = ' AND ';
+ }
+
+ if ( !empty($search) ) {
+ $search = " AND ({$search}) ";
+ if ( !is_user_logged_in() )
+ $search .= " AND ($wpdb->posts.post_password = '') ";
+ }
+ }
+
+ // Allow plugins to contextually add/remove/modify the search section of the database query
+ $search = apply_filters_ref_array('posts_search', array( $search, &$this ) );
+
+ // Taxonomies
+ if ( !$this->is_singular ) {
+ $this->parse_tax_query( $q );
+
+ $clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );
+
+ $join .= $clauses['join'];
+ $where .= $clauses['where'];
+ }
+
+ if ( $this->is_tax ) {
+ if ( empty($post_type) ) {
+ // Do a fully inclusive search for currently registered post types of queried taxonomies
+ $post_type = array();
+ $taxonomies = wp_list_pluck( $this->tax_query->queries, 'taxonomy' );
+ foreach ( get_post_types( array( 'exclude_from_search' => false ) ) as $pt ) {
+ $object_taxonomies = $pt === 'attachment' ? get_taxonomies_for_attachments() : get_object_taxonomies( $pt );
+ if ( array_intersect( $taxonomies, $object_taxonomies ) )
+ $post_type[] = $pt;
+ }
+ if ( ! $post_type )
+ $post_type = 'any';
+ elseif ( count( $post_type ) == 1 )
+ $post_type = $post_type[0];
+
+ $post_status_join = true;
+ } elseif ( in_array('attachment', (array) $post_type) ) {
+ $post_status_join = true;
+ }
+ }
+
+ // Back-compat
+ if ( !empty($this->tax_query->queries) ) {
+ $tax_query_in_and = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'NOT IN' ), 'NOT' );
+ if ( !empty( $tax_query_in_and ) ) {
+ if ( !isset( $q['taxonomy'] ) ) {
+ foreach ( $tax_query_in_and as $a_tax_query ) {
+ if ( !in_array( $a_tax_query['taxonomy'], array( 'category', 'post_tag' ) ) ) {
+ $q['taxonomy'] = $a_tax_query['taxonomy'];
+ if ( 'slug' == $a_tax_query['field'] )
+ $q['term'] = $a_tax_query['terms'][0];
+ else
+ $q['term_id'] = $a_tax_query['terms'][0];
+
+ break;
+ }
+ }
+ }
+
+ $cat_query = wp_list_filter( $tax_query_in_and, array( 'taxonomy' => 'category' ) );
+ if ( ! empty( $cat_query ) ) {
+ $cat_query = reset( $cat_query );
+
+ if ( ! empty( $cat_query['terms'][0] ) ) {
+ $the_cat = get_term_by( $cat_query['field'], $cat_query['terms'][0], 'category' );
+ if ( $the_cat ) {
+ $this->set( 'cat', $the_cat->term_id );
+ $this->set( 'category_name', $the_cat->slug );
+ }
+ unset( $the_cat );
+ }
+ }
+ unset( $cat_query );
+
+ $tag_query = wp_list_filter( $tax_query_in_and, array( 'taxonomy' => 'post_tag' ) );
+ if ( ! empty( $tag_query ) ) {
+ $tag_query = reset( $tag_query );
+
+ if ( ! empty( $tag_query['terms'][0] ) ) {
+ $the_tag = get_term_by( $tag_query['field'], $tag_query['terms'][0], 'post_tag' );
+ if ( $the_tag )
+ $this->set( 'tag_id', $the_tag->term_id );
+ unset( $the_tag );
+ }
+ }
+ unset( $tag_query );
+ }
+ }
+
+ if ( !empty( $this->tax_query->queries ) || !empty( $this->meta_query->queries ) ) {
+ $groupby = "{$wpdb->posts}.ID";
+ }
+
+ // Author/user stuff
+
+ if ( empty($q['author']) || ($q['author'] == '0') ) {
+ $whichauthor = '';
+ } else {
+ $q['author'] = (string)urldecode($q['author']);
+ $q['author'] = addslashes_gpc($q['author']);
+ if ( strpos($q['author'], '-') !== false ) {
+ $eq = '!=';
+ $andor = 'AND';
+ $q['author'] = explode('-', $q['author']);
+ $q['author'] = (string)absint($q['author'][1]);
+ } else {
+ $eq = '=';
+ $andor = 'OR';
+ }
+ $author_array = preg_split('/[,\s]+/', $q['author']);
+ $_author_array = array();
+ foreach ( $author_array as $key => $_author )
+ $_author_array[] = "$wpdb->posts.post_author " . $eq . ' ' . absint($_author);
+ $whichauthor .= ' AND (' . implode(" $andor ", $_author_array) . ')';
+ unset($author_array, $_author_array);
+ }
+
+ // Author stuff for nice URLs
+
+ if ( '' != $q['author_name'] ) {
+ if ( strpos($q['author_name'], '/') !== false ) {
+ $q['author_name'] = explode('/', $q['author_name']);
+ if ( $q['author_name'][ count($q['author_name'])-1 ] ) {
+ $q['author_name'] = $q['author_name'][count($q['author_name'])-1]; // no trailing slash
+ } else {
+ $q['author_name'] = $q['author_name'][count($q['author_name'])-2]; // there was a trailing slash
+ }
+ }
+ $q['author_name'] = sanitize_title_for_query( $q['author_name'] );
+ $q['author'] = get_user_by('slug', $q['author_name']);
+ if ( $q['author'] )
+ $q['author'] = $q['author']->ID;
+ $whichauthor .= " AND ($wpdb->posts.post_author = " . absint($q['author']) . ')';
+ }
+
+ // MIME-Type stuff for attachment browsing
+
+ if ( isset( $q['post_mime_type'] ) && '' != $q['post_mime_type'] )
+ $whichmimetype = wp_post_mime_type_where( $q['post_mime_type'], $wpdb->posts );
+
+ $where .= $search . $whichauthor . $whichmimetype;
+
+ if ( empty($q['order']) || ((strtoupper($q['order']) != 'ASC') && (strtoupper($q['order']) != 'DESC')) )
+ $q['order'] = 'DESC';
+
+ // Order by
+ if ( empty($q['orderby']) ) {
+ $orderby = "$wpdb->posts.post_date " . $q['order'];
+ } elseif ( 'none' == $q['orderby'] ) {
+ $orderby = '';
+ } elseif ( $q['orderby'] == 'post__in' && ! empty( $post__in ) ) {
+ $orderby = "FIELD( {$wpdb->posts}.ID, $post__in )";
+ } elseif ( $q['orderby'] == 'post_parent__in' && ! empty( $post_parent__in ) ) {
+ $orderby = "FIELD( {$wpdb->posts}.post_parent, $post_parent__in )";
+ } else {
+ // Used to filter values
+ $allowed_keys = array('name', 'author', 'date', 'title', 'modified', 'menu_order', 'parent', 'ID', 'rand', 'comment_count');
+ if ( !empty($q['meta_key']) ) {
+ $allowed_keys[] = $q['meta_key'];
+ $allowed_keys[] = 'meta_value';
+ $allowed_keys[] = 'meta_value_num';
+ }
+ $q['orderby'] = urldecode($q['orderby']);
+ $q['orderby'] = addslashes_gpc($q['orderby']);
+
+ $orderby_array = array();
+ foreach ( explode( ' ', $q['orderby'] ) as $i => $orderby ) {
+ // Only allow certain values for safety
+ if ( ! in_array($orderby, $allowed_keys) )
+ continue;
+
+ switch ( $orderby ) {
+ case 'menu_order':
+ $orderby = "$wpdb->posts.menu_order";
+ break;
+ case 'ID':
+ $orderby = "$wpdb->posts.ID";
+ break;
+ case 'rand':
+ $orderby = 'RAND()';
+ break;
+ case $q['meta_key']:
+ case 'meta_value':
+ $orderby = "$wpdb->postmeta.meta_value";
+ break;
+ case 'meta_value_num':
+ $orderby = "$wpdb->postmeta.meta_value+0";
+ break;
+ case 'comment_count':
+ $orderby = "$wpdb->posts.comment_count";
+ break;
+ default:
+ $orderby = "$wpdb->posts.post_" . $orderby;
+ }
+
+ $orderby_array[] = $orderby;
+ }
+ $orderby = implode( ',', $orderby_array );
+
+ if ( empty( $orderby ) )
+ $orderby = "$wpdb->posts.post_date ".$q['order'];
+ else
+ $orderby .= " {$q['order']}";
+ }
+
+ if ( is_array( $post_type ) && count( $post_type ) > 1 ) {
+ $post_type_cap = 'multiple_post_type';
+ } else {
+ if ( is_array( $post_type ) )
+ $post_type = reset( $post_type );
+ $post_type_object = get_post_type_object( $post_type );
+ if ( empty( $post_type_object ) )
+ $post_type_cap = $post_type;
+ }
+
+ if ( 'any' == $post_type ) {
+ $in_search_post_types = get_post_types( array('exclude_from_search' => false) );
+ if ( ! empty( $in_search_post_types ) )
+ $where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $in_search_post_types ) . "')";
+ } elseif ( !empty( $post_type ) && is_array( $post_type ) ) {
+ $where .= " AND $wpdb->posts.post_type IN ('" . join("', '", $post_type) . "')";
+ } elseif ( ! empty( $post_type ) ) {
+ $where .= " AND $wpdb->posts.post_type = '$post_type'";
+ $post_type_object = get_post_type_object ( $post_type );
+ } elseif ( $this->is_attachment ) {
+ $where .= " AND $wpdb->posts.post_type = 'attachment'";
+ $post_type_object = get_post_type_object ( 'attachment' );
+ } elseif ( $this->is_page ) {
+ $where .= " AND $wpdb->posts.post_type = 'page'";
+ $post_type_object = get_post_type_object ( 'page' );
+ } else {
+ $where .= " AND $wpdb->posts.post_type = 'post'";
+ $post_type_object = get_post_type_object ( 'post' );
+ }
+
+ $edit_cap = 'edit_post';
+ $read_cap = 'read_post';
+
+ if ( ! empty( $post_type_object ) ) {
+ $edit_others_cap = $post_type_object->cap->edit_others_posts;
+ $read_private_cap = $post_type_object->cap->read_private_posts;
+ } else {
+ $edit_others_cap = 'edit_others_' . $post_type_cap . 's';
+ $read_private_cap = 'read_private_' . $post_type_cap . 's';
+ }
+
+ if ( ! empty( $q['post_status'] ) ) {
+ $statuswheres = array();
+ $q_status = $q['post_status'];
+ if ( ! is_array( $q_status ) )
+ $q_status = explode(',', $q_status);
+ $r_status = array();
+ $p_status = array();
+ $e_status = array();
+ if ( in_array('any', $q_status) ) {
+ foreach ( get_post_stati( array('exclude_from_search' => true) ) as $status )
+ $e_status[] = "$wpdb->posts.post_status <> '$status'";
+ } else {
+ foreach ( get_post_stati() as $status ) {
+ if ( in_array( $status, $q_status ) ) {
+ if ( 'private' == $status )
+ $p_status[] = "$wpdb->posts.post_status = '$status'";
+ else
+ $r_status[] = "$wpdb->posts.post_status = '$status'";
+ }
+ }
+ }
+
+ if ( empty($q['perm'] ) || 'readable' != $q['perm'] ) {
+ $r_status = array_merge($r_status, $p_status);
+ unset($p_status);
+ }
+
+ if ( !empty($e_status) ) {
+ $statuswheres[] = "(" . join( ' AND ', $e_status ) . ")";
+ }
+ if ( !empty($r_status) ) {
+ if ( !empty($q['perm'] ) && 'editable' == $q['perm'] && !current_user_can($edit_others_cap) )
+ $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $r_status ) . "))";
+ else
+ $statuswheres[] = "(" . join( ' OR ', $r_status ) . ")";
+ }
+ if ( !empty($p_status) ) {
+ if ( !empty($q['perm'] ) && 'readable' == $q['perm'] && !current_user_can($read_private_cap) )
+ $statuswheres[] = "($wpdb->posts.post_author = $user_ID " . "AND (" . join( ' OR ', $p_status ) . "))";
+ else
+ $statuswheres[] = "(" . join( ' OR ', $p_status ) . ")";
+ }
+ if ( $post_status_join ) {
+ $join .= " LEFT JOIN $wpdb->posts AS p2 ON ($wpdb->posts.post_parent = p2.ID) ";
+ foreach ( $statuswheres as $index => $statuswhere )
+ $statuswheres[$index] = "($statuswhere OR ($wpdb->posts.post_status = 'inherit' AND " . str_replace($wpdb->posts, 'p2', $statuswhere) . "))";
+ }
+ foreach ( $statuswheres as $statuswhere )
+ $where .= " AND $statuswhere";
+ } elseif ( !$this->is_singular ) {
+ $where .= " AND ($wpdb->posts.post_status = 'publish'";
+
+ // Add public states.
+ $public_states = get_post_stati( array('public' => true) );
+ foreach ( (array) $public_states as $state ) {
+ if ( 'publish' == $state ) // Publish is hard-coded above.
+ continue;
+ $where .= " OR $wpdb->posts.post_status = '$state'";
+ }
+
+ if ( $this->is_admin ) {
+ // Add protected states that should show in the admin all list.
+ $admin_all_states = get_post_stati( array('protected' => true, 'show_in_admin_all_list' => true) );
+ foreach ( (array) $admin_all_states as $state )
+ $where .= " OR $wpdb->posts.post_status = '$state'";
+ }
+
+ if ( is_user_logged_in() ) {
+ // Add private states that are limited to viewing by the author of a post or someone who has caps to read private states.
+ $private_states = get_post_stati( array('private' => true) );
+ foreach ( (array) $private_states as $state )
+ $where .= current_user_can( $read_private_cap ) ? " OR $wpdb->posts.post_status = '$state'" : " OR $wpdb->posts.post_author = $user_ID AND $wpdb->posts.post_status = '$state'";
+ }
+
+ $where .= ')';
+ }
+
+ if ( !empty( $this->meta_query->queries ) ) {
+ $clauses = $this->meta_query->get_sql( 'post', $wpdb->posts, 'ID', $this );
+ $join .= $clauses['join'];
+ $where .= $clauses['where'];
+ }
+
+ // Apply filters on where and join prior to paging so that any
+ // manipulations to them are reflected in the paging by day queries.
+ if ( !$q['suppress_filters'] ) {
+ $where = apply_filters_ref_array('posts_where', array( $where, &$this ) );
+ $join = apply_filters_ref_array('posts_join', array( $join, &$this ) );
+ }
+
+ // Paging
+ if ( empty($q['nopaging']) && !$this->is_singular ) {
+ $page = absint($q['paged']);
+ if ( !$page )
+ $page = 1;
+
+ if ( empty($q['offset']) ) {
+ $pgstrt = ($page - 1) * $q['posts_per_page'] . ', ';
+ } else { // we're ignoring $page and using 'offset'
+ $q['offset'] = absint($q['offset']);
+ $pgstrt = $q['offset'] . ', ';
+ }
+ $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
+ }
+
+ // Comments feeds
+ if ( $this->is_comment_feed && ( $this->is_archive || $this->is_search || !$this->is_singular ) ) {
+ if ( $this->is_archive || $this->is_search ) {
+ $cjoin = "JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID = $wpdb->posts.ID) $join ";
+ $cwhere = "WHERE comment_approved = '1' $where";
+ $cgroupby = "$wpdb->comments.comment_id";
+ } else { // Other non singular e.g. front
+ $cjoin = "JOIN $wpdb->posts ON ( $wpdb->comments.comment_post_ID = $wpdb->posts.ID )";
+ $cwhere = "WHERE post_status = 'publish' AND comment_approved = '1'";
+ $cgroupby = '';
+ }
+
+ if ( !$q['suppress_filters'] ) {
+ $cjoin = apply_filters_ref_array('comment_feed_join', array( $cjoin, &$this ) );
+ $cwhere = apply_filters_ref_array('comment_feed_where', array( $cwhere, &$this ) );
+ $cgroupby = apply_filters_ref_array('comment_feed_groupby', array( $cgroupby, &$this ) );
+ $corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
+ $climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
+ }
+ $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
+ $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
+
+ $this->comments = (array) $wpdb->get_results("SELECT $distinct $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits");
+ $this->comment_count = count($this->comments);
+
+ $post_ids = array();
+
+ foreach ( $this->comments as $comment )
+ $post_ids[] = (int) $comment->comment_post_ID;
+
+ $post_ids = join(',', $post_ids);
+ $join = '';
+ if ( $post_ids )
+ $where = "AND $wpdb->posts.ID IN ($post_ids) ";
+ else
+ $where = "AND 0";
+ }
+
+ $pieces = array( 'where', 'groupby', 'join', 'orderby', 'distinct', 'fields', 'limits' );
+
+ // Apply post-paging filters on where and join. Only plugins that
+ // manipulate paging queries should use these hooks.
+ if ( !$q['suppress_filters'] ) {
+ $where = apply_filters_ref_array( 'posts_where_paged', array( $where, &$this ) );
+ $groupby = apply_filters_ref_array( 'posts_groupby', array( $groupby, &$this ) );
+ $join = apply_filters_ref_array( 'posts_join_paged', array( $join, &$this ) );
+ $orderby = apply_filters_ref_array( 'posts_orderby', array( $orderby, &$this ) );
+ $distinct = apply_filters_ref_array( 'posts_distinct', array( $distinct, &$this ) );
+ $limits = apply_filters_ref_array( 'post_limits', array( $limits, &$this ) );
+ $fields = apply_filters_ref_array( 'posts_fields', array( $fields, &$this ) );
+
+ // Filter all clauses at once, for convenience
+ $clauses = (array) apply_filters_ref_array( 'posts_clauses', array( compact( $pieces ), &$this ) );
+ foreach ( $pieces as $piece )
+ $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
+ }
+
+ // Announce current selection parameters. For use by caching plugins.
+ do_action( 'posts_selection', $where . $groupby . $orderby . $limits . $join );
+
+ // Filter again for the benefit of caching plugins. Regular plugins should use the hooks above.
+ if ( !$q['suppress_filters'] ) {
+ $where = apply_filters_ref_array( 'posts_where_request', array( $where, &$this ) );
+ $groupby = apply_filters_ref_array( 'posts_groupby_request', array( $groupby, &$this ) );
+ $join = apply_filters_ref_array( 'posts_join_request', array( $join, &$this ) );
+ $orderby = apply_filters_ref_array( 'posts_orderby_request', array( $orderby, &$this ) );
+ $distinct = apply_filters_ref_array( 'posts_distinct_request', array( $distinct, &$this ) );
+ $fields = apply_filters_ref_array( 'posts_fields_request', array( $fields, &$this ) );
+ $limits = apply_filters_ref_array( 'post_limits_request', array( $limits, &$this ) );
+
+ // Filter all clauses at once, for convenience
+ $clauses = (array) apply_filters_ref_array( 'posts_clauses_request', array( compact( $pieces ), &$this ) );
+ foreach ( $pieces as $piece )
+ $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
+ }
+
+ if ( ! empty($groupby) )
+ $groupby = 'GROUP BY ' . $groupby;
+ if ( !empty( $orderby ) )
+ $orderby = 'ORDER BY ' . $orderby;
+
+ $found_rows = '';
+ if ( !$q['no_found_rows'] && !empty($limits) )
+ $found_rows = 'SQL_CALC_FOUND_ROWS';
+
+ $this->request = $old_request = "SELECT $found_rows $distinct $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
+
+ if ( !$q['suppress_filters'] ) {
+ $this->request = apply_filters_ref_array( 'posts_request', array( $this->request, &$this ) );
+ }
+
+ if ( 'ids' == $q['fields'] ) {
+ $this->posts = $wpdb->get_col( $this->request );
+ $this->post_count = count( $this->posts );
+ $this->set_found_posts( $q, $limits );
+
+ return $this->posts;
+ }
+
+ if ( 'id=>parent' == $q['fields'] ) {
+ $this->posts = $wpdb->get_results( $this->request );
+ $this->post_count = count( $this->posts );
+ $this->set_found_posts( $q, $limits );
+
+ $r = array();
+ foreach ( $this->posts as $post )
+ $r[ $post->ID ] = $post->post_parent;
+
+ return $r;
+ }
+
+ $split_the_query = ( $old_request == $this->request && "$wpdb->posts.*" == $fields && !empty( $limits ) && $q['posts_per_page'] < 500 );
+ $split_the_query = apply_filters( 'split_the_query', $split_the_query, $this );
+
+ if ( $split_the_query ) {
+ // First get the IDs and then fill in the objects
+
+ $this->request = "SELECT $found_rows $distinct $wpdb->posts.ID FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits";
+
+ $this->request = apply_filters( 'posts_request_ids', $this->request, $this );
+
+ $ids = $wpdb->get_col( $this->request );
+
+ if ( $ids ) {
+ $this->posts = $ids;
+ $this->set_found_posts( $q, $limits );
+ _prime_post_caches( $ids, $q['update_post_term_cache'], $q['update_post_meta_cache'] );
+ } else {
+ $this->posts = array();
+ }
+ } else {
+ $this->posts = $wpdb->get_results( $this->request );
+ $this->set_found_posts( $q, $limits );
+ }
+
+ // Convert to WP_Post objects
+ if ( $this->posts )
+ $this->posts = array_map( 'get_post', $this->posts );
+
+ // Raw results filter. Prior to status checks.
+ if ( !$q['suppress_filters'] )
+ $this->posts = apply_filters_ref_array('posts_results', array( $this->posts, &$this ) );
+
+ if ( !empty($this->posts) && $this->is_comment_feed && $this->is_singular ) {
+ $cjoin = apply_filters_ref_array('comment_feed_join', array( '', &$this ) );
+ $cwhere = apply_filters_ref_array('comment_feed_where', array( "WHERE comment_post_ID = '{$this->posts[0]->ID}' AND comment_approved = '1'", &$this ) );
+ $cgroupby = apply_filters_ref_array('comment_feed_groupby', array( '', &$this ) );
+ $cgroupby = ( ! empty( $cgroupby ) ) ? 'GROUP BY ' . $cgroupby : '';
+ $corderby = apply_filters_ref_array('comment_feed_orderby', array( 'comment_date_gmt DESC', &$this ) );
+ $corderby = ( ! empty( $corderby ) ) ? 'ORDER BY ' . $corderby : '';
+ $climits = apply_filters_ref_array('comment_feed_limits', array( 'LIMIT ' . get_option('posts_per_rss'), &$this ) );
+ $comments_request = "SELECT $wpdb->comments.* FROM $wpdb->comments $cjoin $cwhere $cgroupby $corderby $climits";
+ $this->comments = $wpdb->get_results($comments_request);
+ $this->comment_count = count($this->comments);
+ }
+
+ // Check post status to determine if post should be displayed.
+ if ( !empty($this->posts) && ($this->is_single || $this->is_page) ) {
+ $status = get_post_status($this->posts[0]);
+ $post_status_obj = get_post_status_object($status);
+ //$type = get_post_type($this->posts[0]);
+ if ( !$post_status_obj->public ) {
+ if ( ! is_user_logged_in() ) {
+ // User must be logged in to view unpublished posts.
+ $this->posts = array();
+ } else {
+ if ( $post_status_obj->protected ) {
+ // User must have edit permissions on the draft to preview.
+ if ( ! current_user_can($edit_cap, $this->posts[0]->ID) ) {
+ $this->posts = array();
+ } else {
+ $this->is_preview = true;
+ if ( 'future' != $status )
+ $this->posts[0]->post_date = current_time('mysql');
+ }
+ } elseif ( $post_status_obj->private ) {
+ if ( ! current_user_can($read_cap, $this->posts[0]->ID) )
+ $this->posts = array();
+ } else {
+ $this->posts = array();
+ }
+ }
+ }
+
+ if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) )
+ $this->posts[0] = get_post( apply_filters_ref_array( 'the_preview', array( $this->posts[0], &$this ) ) );
+ }
+
+ // Put sticky posts at the top of the posts array
+ $sticky_posts = get_option('sticky_posts');
+ if ( $this->is_home && $page <= 1 && is_array($sticky_posts) && !empty($sticky_posts) && !$q['ignore_sticky_posts'] ) {
+ $num_posts = count($this->posts);
+ $sticky_offset = 0;
+ // Loop over posts and relocate stickies to the front.
+ for ( $i = 0; $i < $num_posts; $i++ ) {
+ if ( in_array($this->posts[$i]->ID, $sticky_posts) ) {
+ $sticky_post = $this->posts[$i];
+ // Remove sticky from current position
+ array_splice($this->posts, $i, 1);
+ // Move to front, after other stickies
+ array_splice($this->posts, $sticky_offset, 0, array($sticky_post));
+ // Increment the sticky offset. The next sticky will be placed at this offset.
+ $sticky_offset++;
+ // Remove post from sticky posts array
+ $offset = array_search($sticky_post->ID, $sticky_posts);
+ unset( $sticky_posts[$offset] );
+ }
+ }
+
+ // If any posts have been excluded specifically, Ignore those that are sticky.
+ if ( !empty($sticky_posts) && !empty($q['post__not_in']) )
+ $sticky_posts = array_diff($sticky_posts, $q['post__not_in']);
+
+ // Fetch sticky posts that weren't in the query results
+ if ( !empty($sticky_posts) ) {
+ $stickies = get_posts( array(
+ 'post__in' => $sticky_posts,
+ 'post_type' => $post_type,
+ 'post_status' => 'publish',
+ 'nopaging' => true
+ ) );
+
+ foreach ( $stickies as $sticky_post ) {
+ array_splice( $this->posts, $sticky_offset, 0, array( $sticky_post ) );
+ $sticky_offset++;
+ }
+ }
+ }
+
+ if ( !$q['suppress_filters'] )
+ $this->posts = apply_filters_ref_array('the_posts', array( $this->posts, &$this ) );
+
+ // Ensure that any posts added/modified via one of the filters above are
+ // of the type WP_Post and are filtered.
+ if ( $this->posts ) {
+ $this->post_count = count( $this->posts );
+
+ $this->posts = array_map( 'get_post', $this->posts );
+
+ if ( $q['cache_results'] )
+ update_post_caches($this->posts, $post_type, $q['update_post_term_cache'], $q['update_post_meta_cache']);
+
+ $this->post = reset( $this->posts );
+ } else {
+ $this->post_count = 0;
+ $this->posts = array();
+ }
+
+ return $this->posts;
+ }
+
+ /**
+ * Set up the amount of found posts and the number of pages (if limit clause was used)
+ * for the current query.
+ *
+ * @since 3.5.0
+ * @access private
+ */
+ function set_found_posts( $q, $limits ) {
+ global $wpdb;
+
+ // Bail if posts is an empty array. Continue if posts is an empty string,
+ // null, or false to accommodate caching plugins that fill posts later.
+ if ( $q['no_found_rows'] || ( is_array( $this->posts ) && ! $this->posts ) )
+ return;
+
+ if ( ! empty( $limits ) )
+ $this->found_posts = $wpdb->get_var( apply_filters_ref_array( 'found_posts_query', array( 'SELECT FOUND_ROWS()', &$this ) ) );
+ else
+ $this->found_posts = count( $this->posts );
+
+ $this->found_posts = apply_filters_ref_array( 'found_posts', array( $this->found_posts, &$this ) );
+
+ if ( ! empty( $limits ) )
+ $this->max_num_pages = ceil( $this->found_posts / $q['posts_per_page'] );
+ }
+
+ /**
+ * Set up the next post and iterate current post index.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return WP_Post Next post.
+ */
+ function next_post() {
+
+ $this->current_post++;
+
+ $this->post = $this->posts[$this->current_post];
+ return $this->post;
+ }
+
+ /**
+ * Sets up the current post.
+ *
+ * Retrieves the next post, sets up the post, sets the 'in the loop'
+ * property to true.
+ *
+ * @since 1.5.0
+ * @access public
+ * @uses $post
+ * @uses do_action_ref_array() Calls 'loop_start' if loop has just started
+ */
+ function the_post() {
+ global $post;
+ $this->in_the_loop = true;
+
+ if ( $this->current_post == -1 ) // loop has just started
+ do_action_ref_array('loop_start', array(&$this));
+
+ $post = $this->next_post();
+ setup_postdata($post);
+ }
+
+ /**
+ * Whether there are more posts available in the loop.
+ *
+ * Calls action 'loop_end', when the loop is complete.
+ *
+ * @since 1.5.0
+ * @access public
+ * @uses do_action_ref_array() Calls 'loop_end' if loop is ended
+ *
+ * @return bool True if posts are available, false if end of loop.
+ */
+ function have_posts() {
+ if ( $this->current_post + 1 < $this->post_count ) {
+ return true;
+ } elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
+ do_action_ref_array('loop_end', array(&$this));
+ // Do some cleaning up after the loop
+ $this->rewind_posts();
+ }
+
+ $this->in_the_loop = false;
+ return false;
+ }
+
+ /**
+ * Rewind the posts and reset post index.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function rewind_posts() {
+ $this->current_post = -1;
+ if ( $this->post_count > 0 ) {
+ $this->post = $this->posts[0];
+ }
+ }
+
+ /**
+ * Iterate current comment index and return comment object.
+ *
+ * @since 2.2.0
+ * @access public
+ *
+ * @return object Comment object.
+ */
+ function next_comment() {
+ $this->current_comment++;
+
+ $this->comment = $this->comments[$this->current_comment];
+ return $this->comment;
+ }
+
+ /**
+ * Sets up the current comment.
+ *
+ * @since 2.2.0
+ * @access public
+ * @global object $comment Current comment.
+ * @uses do_action() Calls 'comment_loop_start' hook when first comment is processed.
+ */
+ function the_comment() {
+ global $comment;
+
+ $comment = $this->next_comment();
+
+ if ( $this->current_comment == 0 ) {
+ do_action('comment_loop_start');
+ }
+ }
+
+ /**
+ * Whether there are more comments available.
+ *
+ * Automatically rewinds comments when finished.
+ *
+ * @since 2.2.0
+ * @access public
+ *
+ * @return bool True, if more comments. False, if no more posts.
+ */
+ function have_comments() {
+ if ( $this->current_comment + 1 < $this->comment_count ) {
+ return true;
+ } elseif ( $this->current_comment + 1 == $this->comment_count ) {
+ $this->rewind_comments();
+ }
+
+ return false;
+ }
+
+ /**
+ * Rewind the comments, resets the comment index and comment to first.
+ *
+ * @since 2.2.0
+ * @access public
+ */
+ function rewind_comments() {
+ $this->current_comment = -1;
+ if ( $this->comment_count > 0 ) {
+ $this->comment = $this->comments[0];
+ }
+ }
+
+ /**
+ * Sets up the WordPress query by parsing query string.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query URL query string.
+ * @return array List of posts.
+ */
+ function query( $query ) {
+ $this->init();
+ $this->query = $this->query_vars = wp_parse_args( $query );
+ return $this->get_posts();
+ }
+
+ /**
+ * Retrieve queried object.
+ *
+ * If queried object is not set, then the queried object will be set from
+ * the category, tag, taxonomy, posts page, single post, page, or author
+ * query variable. After it is set up, it will be returned.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return object
+ */
+ function get_queried_object() {
+ if ( isset($this->queried_object) )
+ return $this->queried_object;
+
+ $this->queried_object = null;
+ $this->queried_object_id = 0;
+
+ if ( $this->is_category || $this->is_tag || $this->is_tax ) {
+ $tax_query_in_and = wp_list_filter( $this->tax_query->queries, array( 'operator' => 'NOT IN' ), 'NOT' );
+
+ $query = reset( $tax_query_in_and );
+
+ if ( 'term_id' == $query['field'] )
+ $term = get_term( reset( $query['terms'] ), $query['taxonomy'] );
+ elseif ( $query['terms'] )
+ $term = get_term_by( $query['field'], reset( $query['terms'] ), $query['taxonomy'] );
+
+ if ( ! empty( $term ) && ! is_wp_error( $term ) ) {
+ $this->queried_object = $term;
+ $this->queried_object_id = (int) $term->term_id;
+
+ if ( $this->is_category )
+ _make_cat_compat( $this->queried_object );
+ }
+ } elseif ( $this->is_post_type_archive ) {
+ $this->queried_object = get_post_type_object( $this->get('post_type') );
+ } elseif ( $this->is_posts_page ) {
+ $page_for_posts = get_option('page_for_posts');
+ $this->queried_object = get_post( $page_for_posts );
+ $this->queried_object_id = (int) $this->queried_object->ID;
+ } elseif ( $this->is_singular && !is_null($this->post) ) {
+ $this->queried_object = $this->post;
+ $this->queried_object_id = (int) $this->post->ID;
+ } elseif ( $this->is_author ) {
+ $this->queried_object_id = (int) $this->get('author');
+ $this->queried_object = get_userdata( $this->queried_object_id );
+ }
+
+ return $this->queried_object;
+ }
+
+ /**
+ * Retrieve ID of the current queried object.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return int
+ */
+ function get_queried_object_id() {
+ $this->get_queried_object();
+
+ if ( isset($this->queried_object_id) ) {
+ return $this->queried_object_id;
+ }
+
+ return 0;
+ }
+
+ /**
+ * Constructor.
+ *
+ * Sets up the WordPress query, if parameter is not empty.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $query URL query string.
+ * @return WP_Query
+ */
+ function __construct($query = '') {
+ if ( ! empty($query) ) {
+ $this->query($query);
+ }
+ }
+
+ /**
+ * Is the query for an existing archive page?
+ *
+ * Month, Year, Category, Author, Post Type archive...
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_archive() {
+ return (bool) $this->is_archive;
+ }
+
+ /**
+ * Is the query for an existing post type archive page?
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $post_types Optional. Post type or array of posts types to check against.
+ * @return bool
+ */
+ function is_post_type_archive( $post_types = '' ) {
+ if ( empty( $post_types ) || !$this->is_post_type_archive )
+ return (bool) $this->is_post_type_archive;
+
+ $post_type_object = $this->get_queried_object();
+
+ return in_array( $post_type_object->name, (array) $post_types );
+ }
+
+ /**
+ * Is the query for an existing attachment page?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_attachment() {
+ return (bool) $this->is_attachment;
+ }
+
+ /**
+ * Is the query for an existing author archive page?
+ *
+ * If the $author parameter is specified, this function will additionally
+ * check if the query is for one of the authors specified.
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $author Optional. User ID, nickname, nicename, or array of User IDs, nicknames, and nicenames
+ * @return bool
+ */
+ function is_author( $author = '' ) {
+ if ( !$this->is_author )
+ return false;
+
+ if ( empty($author) )
+ return true;
+
+ $author_obj = $this->get_queried_object();
+
+ $author = (array) $author;
+
+ if ( in_array( $author_obj->ID, $author ) )
+ return true;
+ elseif ( in_array( $author_obj->nickname, $author ) )
+ return true;
+ elseif ( in_array( $author_obj->user_nicename, $author ) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Is the query for an existing category archive page?
+ *
+ * If the $category parameter is specified, this function will additionally
+ * check if the query is for one of the categories specified.
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $category Optional. Category ID, name, slug, or array of Category IDs, names, and slugs.
+ * @return bool
+ */
+ function is_category( $category = '' ) {
+ if ( !$this->is_category )
+ return false;
+
+ if ( empty($category) )
+ return true;
+
+ $cat_obj = $this->get_queried_object();
+
+ $category = (array) $category;
+
+ if ( in_array( $cat_obj->term_id, $category ) )
+ return true;
+ elseif ( in_array( $cat_obj->name, $category ) )
+ return true;
+ elseif ( in_array( $cat_obj->slug, $category ) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Is the query for an existing tag archive page?
+ *
+ * If the $tag parameter is specified, this function will additionally
+ * check if the query is for one of the tags specified.
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $slug Optional. Tag slug or array of slugs.
+ * @return bool
+ */
+ function is_tag( $slug = '' ) {
+ if ( !$this->is_tag )
+ return false;
+
+ if ( empty( $slug ) )
+ return true;
+
+ $tag_obj = $this->get_queried_object();
+
+ $slug = (array) $slug;
+
+ if ( in_array( $tag_obj->slug, $slug ) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Is the query for an existing taxonomy archive page?
+ *
+ * If the $taxonomy parameter is specified, this function will additionally
+ * check if the query is for that specific $taxonomy.
+ *
+ * If the $term parameter is specified in addition to the $taxonomy parameter,
+ * this function will additionally check if the query is for one of the terms
+ * specified.
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $taxonomy Optional. Taxonomy slug or slugs.
+ * @param mixed $term. Optional. Term ID, name, slug or array of Term IDs, names, and slugs.
+ * @return bool
+ */
+ function is_tax( $taxonomy = '', $term = '' ) {
+ global $wp_taxonomies;
+
+ if ( !$this->is_tax )
+ return false;
+
+ if ( empty( $taxonomy ) )
+ return true;
+
+ $queried_object = $this->get_queried_object();
+ $tax_array = array_intersect( array_keys( $wp_taxonomies ), (array) $taxonomy );
+ $term_array = (array) $term;
+
+ // Check that the taxonomy matches.
+ if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
+ return false;
+
+ // Only a Taxonomy provided.
+ if ( empty( $term ) )
+ return true;
+
+ return isset( $queried_object->term_id ) &&
+ count( array_intersect(
+ array( $queried_object->term_id, $queried_object->name, $queried_object->slug ),
+ $term_array
+ ) );
+ }
+
+ /**
+ * Whether the current URL is within the comments popup window.
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_comments_popup() {
+ return (bool) $this->is_comments_popup;
+ }
+
+ /**
+ * Is the query for an existing date archive?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_date() {
+ return (bool) $this->is_date;
+ }
+
+ /**
+ * Is the query for an existing day archive?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_day() {
+ return (bool) $this->is_day;
+ }
+
+ /**
+ * Is the query for a feed?
+ *
+ * @since 3.1.0
+ *
+ * @param string|array $feeds Optional feed types to check.
+ * @return bool
+ */
+ function is_feed( $feeds = '' ) {
+ if ( empty( $feeds ) || ! $this->is_feed )
+ return (bool) $this->is_feed;
+ $qv = $this->get( 'feed' );
+ if ( 'feed' == $qv )
+ $qv = get_default_feed();
+ return in_array( $qv, (array) $feeds );
+ }
+
+ /**
+ * Is the query for a comments feed?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_comment_feed() {
+ return (bool) $this->is_comment_feed;
+ }
+
+ /**
+ * Is the query for the front page of the site?
+ *
+ * This is for what is displayed at your site's main URL.
+ *
+ * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_on_front'.
+ *
+ * If you set a static page for the front page of your site, this function will return
+ * true when viewing that page.
+ *
+ * Otherwise the same as @see WP_Query::is_home()
+ *
+ * @since 3.1.0
+ * @uses is_home()
+ * @uses get_option()
+ *
+ * @return bool True, if front of site.
+ */
+ function is_front_page() {
+ // most likely case
+ if ( 'posts' == get_option( 'show_on_front') && $this->is_home() )
+ return true;
+ elseif ( 'page' == get_option( 'show_on_front') && get_option( 'page_on_front' ) && $this->is_page( get_option( 'page_on_front' ) ) )
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Is the query for the blog homepage?
+ *
+ * This is the page which shows the time based blog content of your site.
+ *
+ * Depends on the site's "Front page displays" Reading Settings 'show_on_front' and 'page_for_posts'.
+ *
+ * If you set a static page for the front page of your site, this function will return
+ * true only on the page you set as the "Posts page".
+ *
+ * @see WP_Query::is_front_page()
+ *
+ * @since 3.1.0
+ *
+ * @return bool True if blog view homepage.
+ */
+ function is_home() {
+ return (bool) $this->is_home;
+ }
+
+ /**
+ * Is the query for an existing month archive?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_month() {
+ return (bool) $this->is_month;
+ }
+
+ /**
+ * Is the query for an existing single page?
+ *
+ * If the $page parameter is specified, this function will additionally
+ * check if the query is for one of the pages specified.
+ *
+ * @see WP_Query::is_single()
+ * @see WP_Query::is_singular()
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $page Page ID, title, slug, or array of such.
+ * @return bool
+ */
+ function is_page( $page = '' ) {
+ if ( !$this->is_page )
+ return false;
+
+ if ( empty( $page ) )
+ return true;
+
+ $page_obj = $this->get_queried_object();
+
+ $page = (array) $page;
+
+ if ( in_array( $page_obj->ID, $page ) )
+ return true;
+ elseif ( in_array( $page_obj->post_title, $page ) )
+ return true;
+ else if ( in_array( $page_obj->post_name, $page ) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Is the query for paged result and not for the first page?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_paged() {
+ return (bool) $this->is_paged;
+ }
+
+ /**
+ * Is the query for a post or page preview?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_preview() {
+ return (bool) $this->is_preview;
+ }
+
+ /**
+ * Is the query for the robots file?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_robots() {
+ return (bool) $this->is_robots;
+ }
+
+ /**
+ * Is the query for a search?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_search() {
+ return (bool) $this->is_search;
+ }
+
+ /**
+ * Is the query for an existing single post?
+ *
+ * Works for any post type, except attachments and pages
+ *
+ * If the $post parameter is specified, this function will additionally
+ * check if the query is for one of the Posts specified.
+ *
+ * @see WP_Query::is_page()
+ * @see WP_Query::is_singular()
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $post Post ID, title, slug, or array of such.
+ * @return bool
+ */
+ function is_single( $post = '' ) {
+ if ( !$this->is_single )
+ return false;
+
+ if ( empty($post) )
+ return true;
+
+ $post_obj = $this->get_queried_object();
+
+ $post = (array) $post;
+
+ if ( in_array( $post_obj->ID, $post ) )
+ return true;
+ elseif ( in_array( $post_obj->post_title, $post ) )
+ return true;
+ elseif ( in_array( $post_obj->post_name, $post ) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Is the query for an existing single post of any post type (post, attachment, page, ... )?
+ *
+ * If the $post_types parameter is specified, this function will additionally
+ * check if the query is for one of the Posts Types specified.
+ *
+ * @see WP_Query::is_page()
+ * @see WP_Query::is_single()
+ *
+ * @since 3.1.0
+ *
+ * @param mixed $post_types Optional. Post Type or array of Post Types
+ * @return bool
+ */
+ function is_singular( $post_types = '' ) {
+ if ( empty( $post_types ) || !$this->is_singular )
+ return (bool) $this->is_singular;
+
+ $post_obj = $this->get_queried_object();
+
+ return in_array( $post_obj->post_type, (array) $post_types );
+ }
+
+ /**
+ * Is the query for a specific time?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_time() {
+ return (bool) $this->is_time;
+ }
+
+ /**
+ * Is the query for a trackback endpoint call?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_trackback() {
+ return (bool) $this->is_trackback;
+ }
+
+ /**
+ * Is the query for an existing year archive?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_year() {
+ return (bool) $this->is_year;
+ }
+
+ /**
+ * Is the query a 404 (returns no results)?
+ *
+ * @since 3.1.0
+ *
+ * @return bool
+ */
+ function is_404() {
+ return (bool) $this->is_404;
+ }
+
+ /**
+ * Is the query the main query?
+ *
+ * @since 3.3.0
+ *
+ * @return bool
+ */
+ function is_main_query() {
+ global $wp_the_query;
+ return $wp_the_query === $this;
+ }
+}
+
+/**
+ * Redirect old slugs to the correct permalink.
+ *
+ * Attempts to find the current slug from the past slugs.
+ *
+ * @since 2.1.0
+ * @uses $wp_query
+ * @uses $wpdb
+ *
+ * @return null If no link is found, null is returned.
+ */
+function wp_old_slug_redirect() {
+ global $wp_query;
+ if ( is_404() && '' != $wp_query->query_vars['name'] ) :
+ global $wpdb;
+
+ // Guess the current post_type based on the query vars.
+ if ( get_query_var('post_type') )
+ $post_type = get_query_var('post_type');
+ elseif ( !empty($wp_query->query_vars['pagename']) )
+ $post_type = 'page';
+ else
+ $post_type = 'post';
+
+ if ( is_array( $post_type ) ) {
+ if ( count( $post_type ) > 1 )
+ return;
+ $post_type = array_shift( $post_type );
+ }
+
+ // Do not attempt redirect for hierarchical post types
+ if ( is_post_type_hierarchical( $post_type ) )
+ return;
+
+ $query = $wpdb->prepare("SELECT post_id FROM $wpdb->postmeta, $wpdb->posts WHERE ID = post_id AND post_type = %s AND meta_key = '_wp_old_slug' AND meta_value = %s", $post_type, $wp_query->query_vars['name']);
+
+ // if year, monthnum, or day have been specified, make our query more precise
+ // just in case there are multiple identical _wp_old_slug values
+ if ( '' != $wp_query->query_vars['year'] )
+ $query .= $wpdb->prepare(" AND YEAR(post_date) = %d", $wp_query->query_vars['year']);
+ if ( '' != $wp_query->query_vars['monthnum'] )
+ $query .= $wpdb->prepare(" AND MONTH(post_date) = %d", $wp_query->query_vars['monthnum']);
+ if ( '' != $wp_query->query_vars['day'] )
+ $query .= $wpdb->prepare(" AND DAYOFMONTH(post_date) = %d", $wp_query->query_vars['day']);
+
+ $id = (int) $wpdb->get_var($query);
+
+ if ( ! $id )
+ return;
+
+ $link = get_permalink($id);
+
+ if ( !$link )
+ return;
+
+ wp_redirect( $link, 301 ); // Permanent redirect
+ exit;
+ endif;
+}
+
+/**
+ * Set up global post data.
+ *
+ * @since 1.5.0
+ *
+ * @param object $post Post data.
+ * @uses do_action_ref_array() Calls 'the_post'
+ * @return bool True when finished.
+ */
+function setup_postdata( $post ) {
+ global $id, $authordata, $currentday, $currentmonth, $page, $pages, $multipage, $more, $numpages;
+
+ $id = (int) $post->ID;
+
+ $authordata = get_userdata($post->post_author);
+
+ $currentday = mysql2date('d.m.y', $post->post_date, false);
+ $currentmonth = mysql2date('m', $post->post_date, false);
+ $numpages = 1;
+ $multipage = 0;
+ $page = get_query_var('page');
+ if ( ! $page )
+ $page = 1;
+ if ( is_single() || is_page() || is_feed() )
+ $more = 1;
+ $content = $post->post_content;
+ if ( false !== strpos( $content, '<!--nextpage-->' ) ) {
+ if ( $page > 1 )
+ $more = 1;
+ $content = str_replace( "\n<!--nextpage-->\n", '<!--nextpage-->', $content );
+ $content = str_replace( "\n<!--nextpage-->", '<!--nextpage-->', $content );
+ $content = str_replace( "<!--nextpage-->\n", '<!--nextpage-->', $content );
+ // Ignore nextpage at the beginning of the content.
+ if ( 0 === strpos( $content, '<!--nextpage-->' ) )
+ $content = substr( $content, 15 );
+ $pages = explode('<!--nextpage-->', $content);
+ $numpages = count($pages);
+ if ( $numpages > 1 )
+ $multipage = 1;
+ } else {
+ $pages = array( $post->post_content );
+ }
+
+ do_action_ref_array('the_post', array(&$post));
+
+ return true;
+}
diff --git a/src/wp-includes/registration-functions.php b/src/wp-includes/registration-functions.php
new file mode 100644
index 0000000000..9fee68601d
--- /dev/null
+++ b/src/wp-includes/registration-functions.php
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Deprecated. No longer needed.
+ *
+ * @package WordPress
+ */
+_deprecated_file( basename(__FILE__), '2.1', null, __( 'This file no longer needs to be included.' ) );
diff --git a/src/wp-includes/registration.php b/src/wp-includes/registration.php
new file mode 100644
index 0000000000..a0ffabf9fc
--- /dev/null
+++ b/src/wp-includes/registration.php
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Deprecated. No longer needed.
+ *
+ * @package WordPress
+ */
+_deprecated_file( basename(__FILE__), '3.1', null, __( 'This file no longer needs to be included.' ) );
diff --git a/src/wp-includes/revision.php b/src/wp-includes/revision.php
new file mode 100644
index 0000000000..5f441d3f5a
--- /dev/null
+++ b/src/wp-includes/revision.php
@@ -0,0 +1,603 @@
+<?php
+/**
+ * Post revision functions.
+ *
+ * @package WordPress
+ * @subpackage Post_Revisions
+ */
+
+/**
+ * Determines which fields of posts are to be saved in revisions.
+ *
+ * Does two things. If passed a post *array*, it will return a post array ready
+ * to be inserted into the posts table as a post revision. Otherwise, returns
+ * an array whose keys are the post fields to be saved for post revisions.
+ *
+ * @since 2.6.0
+ * @access private
+ *
+ * @uses apply_filters() Calls '_wp_post_revision_fields' on 'title', 'content' and 'excerpt' fields.
+ *
+ * @param array $post Optional a post array to be processed for insertion as a post revision.
+ * @param bool $autosave optional Is the revision an autosave?
+ * @return array Post array ready to be inserted as a post revision or array of fields that can be versioned.
+ */
+function _wp_post_revision_fields( $post = null, $autosave = false ) {
+ static $fields = false;
+
+ if ( !$fields ) {
+ // Allow these to be versioned
+ $fields = array(
+ 'post_title' => __( 'Title' ),
+ 'post_content' => __( 'Content' ),
+ 'post_excerpt' => __( 'Excerpt' ),
+ );
+
+ // Runs only once
+ $fields = apply_filters( '_wp_post_revision_fields', $fields );
+
+ // WP uses these internally either in versioning or elsewhere - they cannot be versioned
+ foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count', 'post_author' ) as $protect )
+ unset( $fields[$protect] );
+ }
+
+ if ( !is_array($post) )
+ return $fields;
+
+ $return = array();
+ foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field )
+ $return[$field] = $post[$field];
+
+ $return['post_parent'] = $post['ID'];
+ $return['post_status'] = 'inherit';
+ $return['post_type'] = 'revision';
+ $return['post_name'] = $autosave ? "$post[ID]-autosave-v1" : "$post[ID]-revision-v1"; // "1" is the revisioning system version
+ $return['post_date'] = isset($post['post_modified']) ? $post['post_modified'] : '';
+ $return['post_date_gmt'] = isset($post['post_modified_gmt']) ? $post['post_modified_gmt'] : '';
+
+ return $return;
+}
+
+/**
+ * Saves an already existing post as a post revision.
+ *
+ * Typically used immediately after post updates.
+ * Adds a copy of the current post as a revision, so latest revision always matches current post
+ *
+ * @since 2.6.0
+ *
+ * @uses _wp_put_post_revision()
+ *
+ * @param int $post_id The ID of the post to save as a revision.
+ * @return mixed Null or 0 if error, new revision ID, if success.
+ */
+function wp_save_post_revision( $post_id ) {
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
+ return;
+
+ if ( ! $post = get_post( $post_id ) )
+ return;
+
+ if ( ! post_type_supports( $post->post_type, 'revisions' ) )
+ return;
+
+ if ( 'auto-draft' == $post->post_status )
+ return;
+
+ if ( ! wp_revisions_enabled( $post ) )
+ return;
+
+ // Compare the proposed update with the last stored revision verifying that
+ // they are different, unless a plugin tells us to always save regardless.
+ // If no previous revisions, save one
+ if ( $revisions = wp_get_post_revisions( $post_id ) ) {
+ // grab the last revision, but not an autosave
+ foreach ( $revisions as $revision ) {
+ if ( false !== strpos( $revision->post_name, "{$revision->post_parent}-revision" ) ) {
+ $last_revision = $revision;
+ break;
+ }
+ }
+
+ if ( isset( $last_revision ) && apply_filters( 'wp_save_post_revision_check_for_changes', true, $last_revision, $post ) ) {
+ $post_has_changed = false;
+
+ foreach ( array_keys( _wp_post_revision_fields() ) as $field ) {
+ if ( normalize_whitespace( $post->$field ) != normalize_whitespace( $last_revision->$field ) ) {
+ $post_has_changed = true;
+ break;
+ }
+ }
+ //don't save revision if post unchanged
+ if( ! $post_has_changed )
+ return;
+ }
+ }
+
+ $return = _wp_put_post_revision( $post );
+
+ $revisions_to_keep = wp_revisions_to_keep( $post );
+
+ if ( $revisions_to_keep < 0 )
+ return $return;
+
+ // all revisions and autosaves
+ $revisions = wp_get_post_revisions( $post_id, array( 'order' => 'ASC' ) );
+
+ $delete = count($revisions) - $revisions_to_keep;
+
+ if ( $delete < 1 )
+ return $return;
+
+ $revisions = array_slice( $revisions, 0, $delete );
+
+ for ( $i = 0; isset( $revisions[$i] ); $i++ ) {
+ if ( false !== strpos( $revisions[ $i ]->post_name, 'autosave' ) )
+ continue;
+
+ wp_delete_post_revision( $revisions[ $i ]->ID );
+ }
+
+ return $return;
+}
+
+/**
+ * Retrieve the autosaved data of the specified post.
+ *
+ * Returns a post object containing the information that was autosaved for the
+ * specified post. If the optional $user_id is passed, returns the autosave for that user
+ * otherwise returns the latest autosave.
+ *
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revisions()
+ *
+ * @param int $post_id The post ID.
+ * @param int $user_id optional The post author ID.
+ * @return object|bool The autosaved data or false on failure or when no autosave exists.
+ */
+function wp_get_post_autosave( $post_id, $user_id = 0 ) {
+ $revisions = wp_get_post_revisions( $post_id, array( 'check_enabled' => false ) );
+
+ foreach ( $revisions as $revision ) {
+ if ( false !== strpos( $revision->post_name, "{$post_id}-autosave" ) ) {
+ if ( $user_id && $user_id != $revision->post_author )
+ continue;
+
+ return $revision;
+ break;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Determines if the specified post is a revision.
+ *
+ * @since 2.6.0
+ *
+ * @param int|object $post Post ID or post object.
+ * @return bool|int False if not a revision, ID of revision's parent otherwise.
+ */
+function wp_is_post_revision( $post ) {
+ if ( !$post = wp_get_post_revision( $post ) )
+ return false;
+
+ return (int) $post->post_parent;
+}
+
+/**
+ * Determines if the specified post is an autosave.
+ *
+ * @since 2.6.0
+ *
+ * @param int|object $post Post ID or post object.
+ * @return bool|int False if not a revision, ID of autosave's parent otherwise
+ */
+function wp_is_post_autosave( $post ) {
+ if ( !$post = wp_get_post_revision( $post ) )
+ return false;
+
+ if ( false !== strpos( $post->post_name, "{$post->post_parent}-autosave" ) )
+ return (int) $post->post_parent;
+
+ return false;
+}
+
+/**
+ * Inserts post data into the posts table as a post revision.
+ *
+ * @since 2.6.0
+ * @access private
+ *
+ * @uses wp_insert_post()
+ *
+ * @param int|object|array $post Post ID, post object OR post array.
+ * @param bool $autosave Optional. Is the revision an autosave?
+ * @return mixed Null or 0 if error, new revision ID if success.
+ */
+function _wp_put_post_revision( $post = null, $autosave = false ) {
+ if ( is_object($post) )
+ $post = get_object_vars( $post );
+ elseif ( !is_array($post) )
+ $post = get_post($post, ARRAY_A);
+
+ if ( !$post || empty($post['ID']) )
+ return;
+
+ if ( isset($post['post_type']) && 'revision' == $post['post_type'] )
+ return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) );
+
+ $post_id = $post['ID'];
+ $post = _wp_post_revision_fields( $post, $autosave );
+ $post = wp_slash($post); //since data is from db
+
+ $revision_id = wp_insert_post( $post );
+ if ( is_wp_error($revision_id) )
+ return $revision_id;
+
+ if ( $revision_id )
+ do_action( '_wp_put_post_revision', $revision_id );
+
+ return $revision_id;
+}
+
+/**
+ * Gets a post revision.
+ *
+ * @since 2.6.0
+ *
+ * @uses get_post()
+ *
+ * @param int|object $post The post ID or object.
+ * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N.
+ * @param string $filter Optional sanitation filter. @see sanitize_post().
+ * @return mixed Null if error or post object if success.
+ */
+function wp_get_post_revision(&$post, $output = OBJECT, $filter = 'raw') {
+ $null = null;
+ if ( !$revision = get_post( $post, OBJECT, $filter ) )
+ return $revision;
+ if ( 'revision' !== $revision->post_type )
+ return $null;
+
+ if ( $output == OBJECT ) {
+ return $revision;
+ } elseif ( $output == ARRAY_A ) {
+ $_revision = get_object_vars($revision);
+ return $_revision;
+ } elseif ( $output == ARRAY_N ) {
+ $_revision = array_values(get_object_vars($revision));
+ return $_revision;
+ }
+
+ return $revision;
+}
+
+/**
+ * Restores a post to the specified revision.
+ *
+ * Can restore a past revision using all fields of the post revision, or only selected fields.
+ *
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revision()
+ * @uses wp_update_post()
+ * @uses do_action() Calls 'wp_restore_post_revision' on post ID and revision ID if wp_update_post()
+ * is successful.
+ *
+ * @param int|object $revision_id Revision ID or revision object.
+ * @param array $fields Optional. What fields to restore from. Defaults to all.
+ * @return mixed Null if error, false if no fields to restore, (int) post ID if success.
+ */
+function wp_restore_post_revision( $revision_id, $fields = null ) {
+ if ( !$revision = wp_get_post_revision( $revision_id, ARRAY_A ) )
+ return $revision;
+
+ if ( !is_array( $fields ) )
+ $fields = array_keys( _wp_post_revision_fields() );
+
+ $update = array();
+ foreach( array_intersect( array_keys( $revision ), $fields ) as $field ) {
+ $update[$field] = $revision[$field];
+ }
+
+ if ( !$update )
+ return false;
+
+ $update['ID'] = $revision['post_parent'];
+
+ $update = wp_slash( $update ); //since data is from db
+
+ $post_id = wp_update_post( $update );
+ if ( ! $post_id || is_wp_error( $post_id ) )
+ return $post_id;
+
+ // Add restore from details
+ $restore_details = array(
+ 'restored_revision_id' => $revision_id,
+ 'restored_by_user' => get_current_user_id(),
+ 'restored_time' => time()
+ );
+ update_post_meta( $post_id, '_post_restored_from', $restore_details );
+
+ // Update last edit user
+ update_post_meta( $post_id, '_edit_last', get_current_user_id() );
+
+ do_action( 'wp_restore_post_revision', $post_id, $revision['ID'] );
+
+ return $post_id;
+}
+
+/**
+ * Deletes a revision.
+ *
+ * Deletes the row from the posts table corresponding to the specified revision.
+ *
+ * @since 2.6.0
+ *
+ * @uses wp_get_post_revision()
+ * @uses wp_delete_post()
+ *
+ * @param int|object $revision_id Revision ID or revision object.
+ * @return mixed Null or WP_Error if error, deleted post if success.
+ */
+function wp_delete_post_revision( $revision_id ) {
+ if ( !$revision = wp_get_post_revision( $revision_id ) )
+ return $revision;
+
+ $delete = wp_delete_post( $revision->ID );
+ if ( is_wp_error( $delete ) )
+ return $delete;
+
+ if ( $delete )
+ do_action( 'wp_delete_post_revision', $revision->ID, $revision );
+
+ return $delete;
+}
+
+/**
+ * Returns all revisions of specified post.
+ *
+ * @since 2.6.0
+ *
+ * @uses get_children()
+ *
+ * @param int|object $post_id Post ID or post object
+ * @return array An array of revisions, or an empty array if none.
+ */
+function wp_get_post_revisions( $post_id = 0, $args = null ) {
+ $post = get_post( $post_id );
+ if ( ! $post || empty( $post->ID ) )
+ return array();
+
+ $defaults = array( 'order' => 'DESC', 'orderby' => 'date', 'check_enabled' => true );
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) )
+ return array();
+
+ $args = array_merge( $args, array( 'post_parent' => $post->ID, 'post_type' => 'revision', 'post_status' => 'inherit' ) );
+
+ if ( ! $revisions = get_children( $args ) )
+ return array();
+
+ return $revisions;
+}
+
+/**
+ * Determine if revisions are enabled for a given post.
+ *
+ * @since 3.6.0
+ *
+ * @uses wp_revisions_to_keep()
+ *
+ * @param object $post The post object.
+ * @return bool True if number of revisions to keep isn't zero, false otherwise.
+ */
+function wp_revisions_enabled( $post ) {
+ return wp_revisions_to_keep( $post ) != 0;
+}
+
+/**
+ * Determine how many revisions to retain for a given post.
+ * By default, an infinite number of revisions are stored if a post type supports revisions.
+ *
+ * @since 3.6.0
+ *
+ * @uses post_type_supports()
+ * @uses apply_filters() Calls 'wp_revisions_to_keep' hook on the number of revisions.
+ *
+ * @param object $post The post object.
+ * @return int The number of revisions to keep.
+ */
+function wp_revisions_to_keep( $post ) {
+ $num = WP_POST_REVISIONS;
+
+ if ( true === $num )
+ $num = -1;
+ else
+ $num = intval( $num );
+
+ if ( ! post_type_supports( $post->post_type, 'revisions' ) )
+ $num = 0;
+
+ return (int) apply_filters( 'wp_revisions_to_keep', $num, $post );
+}
+
+/**
+ * Sets up the post object for preview based on the post autosave.
+ *
+ * @since 2.7.0
+ * @access private
+ */
+function _set_preview($post) {
+
+ if ( ! is_object($post) )
+ return $post;
+
+ $preview = wp_get_post_autosave($post->ID);
+
+ if ( ! is_object($preview) )
+ return $post;
+
+ $preview = sanitize_post($preview);
+
+ $post->post_content = $preview->post_content;
+ $post->post_title = $preview->post_title;
+ $post->post_excerpt = $preview->post_excerpt;
+
+ add_filter( 'get_the_terms', '_wp_preview_terms_filter', 10, 3 );
+
+ return $post;
+}
+
+/**
+ * Filters the latest content for preview from the post autosave.
+ *
+ * @since 2.7.0
+ * @access private
+ */
+function _show_post_preview() {
+
+ if ( isset($_GET['preview_id']) && isset($_GET['preview_nonce']) ) {
+ $id = (int) $_GET['preview_id'];
+
+ if ( false == wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . $id ) )
+ wp_die( __('You do not have permission to preview drafts.') );
+
+ add_filter('the_preview', '_set_preview');
+ }
+}
+
+/**
+ * Filters terms lookup to set the post format.
+ *
+ * @since 3.6.0
+ * @access private
+ */
+function _wp_preview_terms_filter( $terms, $post_id, $taxonomy ) {
+ if ( ! $post = get_post() )
+ return $terms;
+
+ if ( empty( $_REQUEST['post_format'] ) || $post->ID != $post_id || 'post_format' != $taxonomy || 'revision' == $post->post_type )
+ return $terms;
+
+ if ( 'standard' == $_REQUEST['post_format'] )
+ $terms = array();
+ elseif ( $term = get_term_by( 'slug', 'post-format-' . sanitize_key( $_REQUEST['post_format'] ), 'post_format' ) )
+ $terms = array( $term ); // Can only have one post format
+
+ return $terms;
+}
+
+/**
+ * Gets the post revision version.
+ *
+ * @since 3.6.0
+ * @access private
+*/
+function _wp_get_post_revision_version( $revision ) {
+ if ( is_object( $revision ) )
+ $revision = get_object_vars( $revision );
+ elseif ( !is_array( $revision ) )
+ return false;
+
+ if ( preg_match( '/^\d+-(?:autosave|revision)-v(\d+)$/', $revision['post_name'], $matches ) )
+ return (int) $matches[1];
+
+ return 0;
+}
+
+/**
+ * Upgrade the revisions author, add the current post as a revision and set the revisions version to 1
+ *
+ * @since 3.6.0
+ * @access private
+ *
+ * @uses wp_get_post_revisions()
+ *
+ * @param object $post Post object
+ * @param array $revisions Current revisions of the post
+ * @return bool true if the revisions were upgraded, false if problems
+ */
+function _wp_upgrade_revisions_of_post( $post, $revisions ) {
+ global $wpdb;
+
+ // Add post option exclusively
+ $lock = "revision-upgrade-{$post->ID}";
+ $now = time();
+ $result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, 'no') /* LOCK */", $lock, $now ) );
+ if ( ! $result ) {
+ // If we couldn't get a lock, see how old the previous lock is
+ $locked = get_option( $lock );
+ if ( ! $locked ) {
+ // Can't write to the lock, and can't read the lock.
+ // Something broken has happened
+ return false;
+ }
+
+ if ( $locked > $now - 3600 ) {
+ // Lock is not too old: some other process may be upgrading this post. Bail.
+ return false;
+ }
+
+ // Lock is too old - update it (below) and continue
+ }
+
+ // If we could get a lock, re-"add" the option to fire all the correct filters.
+ update_option( $lock, $now );
+
+ reset( $revisions );
+ $add_last = true;
+
+ do {
+ $this_revision = current( $revisions );
+ $prev_revision = next( $revisions );
+
+ $this_revision_version = _wp_get_post_revision_version( $this_revision );
+
+ // Something terrible happened
+ if ( false === $this_revision_version )
+ continue;
+
+ // 1 is the latest revision version, so we're already up to date.
+ // No need to add a copy of the post as latest revision.
+ if ( 0 < $this_revision_version ) {
+ $add_last = false;
+ continue;
+ }
+
+ // Always update the revision version
+ $update = array(
+ 'post_name' => preg_replace( '/^(\d+-(?:autosave|revision))[\d-]*$/', '$1-v1', $this_revision->post_name ),
+ );
+
+ // If this revision is the oldest revision of the post, i.e. no $prev_revision,
+ // the correct post_author is probably $post->post_author, but that's only a good guess.
+ // Update the revision version only and Leave the author as-is.
+ if ( $prev_revision ) {
+ $prev_revision_version = _wp_get_post_revision_version( $prev_revision );
+
+ // If the previous revision is already up to date, it no longer has the information we need :(
+ if ( $prev_revision_version < 1 )
+ $update['post_author'] = $prev_revision->post_author;
+ }
+
+ // Upgrade this revision
+ $result = $wpdb->update( $wpdb->posts, $update, array( 'ID' => $this_revision->ID ) );
+
+ if ( $result )
+ wp_cache_delete( $this_revision->ID, 'posts' );
+
+ } while ( $prev_revision );
+
+ delete_option( $lock );
+
+ // Add a copy of the post as latest revision.
+ if ( $add_last )
+ wp_save_post_revision( $post->ID );
+
+ return true;
+}
diff --git a/src/wp-includes/rewrite.php b/src/wp-includes/rewrite.php
new file mode 100644
index 0000000000..e2dbc802a4
--- /dev/null
+++ b/src/wp-includes/rewrite.php
@@ -0,0 +1,2006 @@
+<?php
+/**
+ * WordPress Rewrite API
+ *
+ * @package WordPress
+ * @subpackage Rewrite
+ */
+
+/**
+ * Add a straight rewrite rule.
+ *
+ * @see WP_Rewrite::add_rule() for long description.
+ * @since 2.1.0
+ *
+ * @param string $regex Regular Expression to match request against.
+ * @param string $redirect Page to redirect to.
+ * @param string $after Optional, default is 'bottom'. Where to add rule, can also be 'top'.
+ */
+function add_rewrite_rule($regex, $redirect, $after = 'bottom') {
+ global $wp_rewrite;
+ $wp_rewrite->add_rule($regex, $redirect, $after);
+}
+
+/**
+ * Add a new rewrite tag (like %postname%).
+ *
+ * The $query parameter is optional. If it is omitted you must ensure that
+ * you call this on, or before, the 'init' hook. This is because $query defaults
+ * to "$tag=", and for this to work a new query var has to be added.
+ *
+ * @see WP_Rewrite::add_rewrite_tag()
+ * @since 2.1.0
+ *
+ * @param string $tag Name of the new rewrite tag.
+ * @param string $regex Regular expression to substitute the tag for in rewrite rules.
+ * @param string $query String to append to the rewritten query. Must end in '='. Optional.
+ */
+function add_rewrite_tag( $tag, $regex, $query = '' ) {
+ // validate the tag's name
+ if ( strlen( $tag ) < 3 || $tag[0] != '%' || $tag[ strlen($tag) - 1 ] != '%' )
+ return;
+
+ global $wp_rewrite, $wp;
+
+ if ( empty( $query ) ) {
+ $qv = trim( $tag, '%' );
+ $wp->add_query_var( $qv );
+ $query = $qv . '=';
+ }
+
+ $wp_rewrite->add_rewrite_tag( $tag, $regex, $query );
+}
+
+/**
+ * Add permalink structure.
+ *
+ * @see WP_Rewrite::add_permastruct()
+ * @since 3.0.0
+ *
+ * @param string $name Name for permalink structure.
+ * @param string $struct Permalink structure.
+ * @param array $args Optional configuration for building the rules from the permalink structure,
+ * see {@link WP_Rewrite::add_permastruct()} for full details.
+ */
+function add_permastruct( $name, $struct, $args = array() ) {
+ global $wp_rewrite;
+
+ // backwards compatibility for the old parameters: $with_front and $ep_mask
+ if ( ! is_array( $args ) )
+ $args = array( 'with_front' => $args );
+ if ( func_num_args() == 4 )
+ $args['ep_mask'] = func_get_arg( 3 );
+
+ return $wp_rewrite->add_permastruct( $name, $struct, $args );
+}
+
+/**
+ * Add a new feed type like /atom1/.
+ *
+ * @since 2.1.0
+ *
+ * @param string $feedname
+ * @param callback $function Callback to run on feed display.
+ * @return string Feed action name.
+ */
+function add_feed($feedname, $function) {
+ global $wp_rewrite;
+ if ( ! in_array($feedname, $wp_rewrite->feeds) ) //override the file if it is
+ $wp_rewrite->feeds[] = $feedname;
+ $hook = 'do_feed_' . $feedname;
+ // Remove default function hook
+ remove_action($hook, $hook);
+ add_action($hook, $function, 10, 1);
+ return $hook;
+}
+
+/**
+ * Remove rewrite rules and then recreate rewrite rules.
+ *
+ * @see WP_Rewrite::flush_rules()
+ * @since 3.0.0
+ *
+ * @param bool $hard Whether to update .htaccess (hard flush) or just update
+ * rewrite_rules transient (soft flush). Default is true (hard).
+ */
+function flush_rewrite_rules( $hard = true ) {
+ global $wp_rewrite;
+ $wp_rewrite->flush_rules( $hard );
+}
+
+/**
+ * Endpoint Mask for default, which is nothing.
+ *
+ * @since 2.1.0
+ */
+define('EP_NONE', 0);
+
+/**
+ * Endpoint Mask for Permalink.
+ *
+ * @since 2.1.0
+ */
+define('EP_PERMALINK', 1);
+
+/**
+ * Endpoint Mask for Attachment.
+ *
+ * @since 2.1.0
+ */
+define('EP_ATTACHMENT', 2);
+
+/**
+ * Endpoint Mask for date.
+ *
+ * @since 2.1.0
+ */
+define('EP_DATE', 4);
+
+/**
+ * Endpoint Mask for year
+ *
+ * @since 2.1.0
+ */
+define('EP_YEAR', 8);
+
+/**
+ * Endpoint Mask for month.
+ *
+ * @since 2.1.0
+ */
+define('EP_MONTH', 16);
+
+/**
+ * Endpoint Mask for day.
+ *
+ * @since 2.1.0
+ */
+define('EP_DAY', 32);
+
+/**
+ * Endpoint Mask for root.
+ *
+ * @since 2.1.0
+ */
+define('EP_ROOT', 64);
+
+/**
+ * Endpoint Mask for comments.
+ *
+ * @since 2.1.0
+ */
+define('EP_COMMENTS', 128);
+
+/**
+ * Endpoint Mask for searches.
+ *
+ * @since 2.1.0
+ */
+define('EP_SEARCH', 256);
+
+/**
+ * Endpoint Mask for categories.
+ *
+ * @since 2.1.0
+ */
+define('EP_CATEGORIES', 512);
+
+/**
+ * Endpoint Mask for tags.
+ *
+ * @since 2.3.0
+ */
+define('EP_TAGS', 1024);
+
+/**
+ * Endpoint Mask for authors.
+ *
+ * @since 2.1.0
+ */
+define('EP_AUTHORS', 2048);
+
+/**
+ * Endpoint Mask for pages.
+ *
+ * @since 2.1.0
+ */
+define('EP_PAGES', 4096);
+
+/**
+ * Endpoint Mask for all archive views.
+ *
+ * @since 3.7.0
+ */
+define( 'EP_ALL_ARCHIVES', EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS );
+
+/**
+ * Endpoint Mask for everything.
+ *
+ * @since 2.1.0
+ */
+define( 'EP_ALL', EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES );
+
+/**
+ * Add an endpoint, like /trackback/.
+ *
+ * Adding an endpoint creates extra rewrite rules for each of the matching
+ * places specified by the provided bitmask. For example:
+ *
+ * <code>
+ * add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );
+ * </code>
+ *
+ * will add a new rewrite rule ending with "json(/(.*))?/?$" for every permastruct
+ * that describes a permalink (post) or page. This is rewritten to "json=$match"
+ * where $match is the part of the URL matched by the endpoint regex (e.g. "foo" in
+ * "<permalink>/json/foo/").
+ *
+ * A new query var with the same name as the endpoint will also be created.
+ *
+ * When specifying $places ensure that you are using the EP_* constants (or a
+ * combination of them using the bitwise OR operator) as their values are not
+ * guaranteed to remain static (especially EP_ALL).
+ *
+ * Be sure to flush the rewrite rules - flush_rewrite_rules() - when your plugin gets
+ * activated and deactivated.
+ *
+ * @since 2.1.0
+ * @see WP_Rewrite::add_endpoint()
+ * @global object $wp_rewrite
+ *
+ * @param string $name Name of the endpoint.
+ * @param int $places Endpoint mask describing the places the endpoint should be added.
+ */
+function add_rewrite_endpoint( $name, $places ) {
+ global $wp_rewrite;
+ $wp_rewrite->add_endpoint( $name, $places );
+}
+
+/**
+ * Filter the URL base for taxonomies.
+ *
+ * To remove any manually prepended /index.php/.
+ *
+ * @access private
+ * @since 2.6.0
+ *
+ * @param string $base The taxonomy base that we're going to filter
+ * @return string
+ */
+function _wp_filter_taxonomy_base( $base ) {
+ if ( !empty( $base ) ) {
+ $base = preg_replace( '|^/index\.php/|', '', $base );
+ $base = trim( $base, '/' );
+ }
+ return $base;
+}
+
+/**
+ * Examine a url and try to determine the post ID it represents.
+ *
+ * Checks are supposedly from the hosted site blog.
+ *
+ * @since 1.0.0
+ *
+ * @param string $url Permalink to check.
+ * @return int Post ID, or 0 on failure.
+ */
+function url_to_postid($url) {
+ global $wp_rewrite;
+
+ $url = apply_filters('url_to_postid', $url);
+
+ // First, check to see if there is a 'p=N' or 'page_id=N' to match against
+ if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) {
+ $id = absint($values[2]);
+ if ( $id )
+ return $id;
+ }
+
+ // Check to see if we are using rewrite rules
+ $rewrite = $wp_rewrite->wp_rewrite_rules();
+
+ // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
+ if ( empty($rewrite) )
+ return 0;
+
+ // Get rid of the #anchor
+ $url_split = explode('#', $url);
+ $url = $url_split[0];
+
+ // Get rid of URL ?query=string
+ $url_split = explode('?', $url);
+ $url = $url_split[0];
+
+ // Add 'www.' if it is absent and should be there
+ if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') )
+ $url = str_replace('://', '://www.', $url);
+
+ // Strip 'www.' if it is present and shouldn't be
+ if ( false === strpos(home_url(), '://www.') )
+ $url = str_replace('://www.', '://', $url);
+
+ // Strip 'index.php/' if we're not using path info permalinks
+ if ( !$wp_rewrite->using_index_permalinks() )
+ $url = str_replace( $wp_rewrite->index . '/', '', $url );
+
+ if ( false !== strpos($url, home_url()) ) {
+ // Chop off http://domain.com
+ $url = str_replace(home_url(), '', $url);
+ } else {
+ // Chop off /path/to/blog
+ $home_path = parse_url(home_url());
+ $home_path = isset( $home_path['path'] ) ? $home_path['path'] : '' ;
+ $url = str_replace($home_path, '', $url);
+ }
+
+ // Trim leading and lagging slashes
+ $url = trim($url, '/');
+
+ $request = $url;
+
+ // Look for matches.
+ $request_match = $request;
+ foreach ( (array)$rewrite as $match => $query) {
+
+ // If the requesting file is the anchor of the match, prepend it
+ // to the path info.
+ if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) )
+ $request_match = $url . '/' . $request;
+
+ if ( preg_match("!^$match!", $request_match, $matches) ) {
+
+ if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
+ // this is a verbose page match, lets check to be sure about it
+ if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
+ continue;
+ }
+
+ // Got a match.
+ // Trim the query of everything up to the '?'.
+ $query = preg_replace("!^.+\?!", '', $query);
+
+ // Substitute the substring matches into the query.
+ $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
+
+ // Filter out non-public query vars
+ global $wp;
+ parse_str($query, $query_vars);
+ $query = array();
+ foreach ( (array) $query_vars as $key => $value ) {
+ if ( in_array($key, $wp->public_query_vars) )
+ $query[$key] = $value;
+ }
+
+ // Do the query
+ $query = new WP_Query($query);
+ if ( !empty($query->posts) && $query->is_singular )
+ return $query->post->ID;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/**
+ * WordPress Rewrite Component.
+ *
+ * The WordPress Rewrite class writes the rewrite module rules to the .htaccess
+ * file. It also handles parsing the request to get the correct setup for the
+ * WordPress Query class.
+ *
+ * The Rewrite along with WP class function as a front controller for WordPress.
+ * You can add rules to trigger your page view and processing using this
+ * component. The full functionality of a front controller does not exist,
+ * meaning you can't define how the template files load based on the rewrite
+ * rules.
+ *
+ * @since 1.5.0
+ */
+class WP_Rewrite {
+ /**
+ * Permalink structure for posts.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $permalink_structure;
+
+ /**
+ * Whether to add trailing slashes.
+ *
+ * @since 2.2.0
+ * @access private
+ * @var bool
+ */
+ var $use_trailing_slashes;
+
+ /**
+ * Base for the author permalink structure (example.com/$author_base/authorname).
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $author_base = 'author';
+
+ /**
+ * Permalink structure for author archives.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $author_structure;
+
+ /**
+ * Permalink structure for date archives.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $date_structure;
+
+ /**
+ * Permalink structure for pages.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $page_structure;
+
+ /**
+ * Base of the search permalink structure (example.com/$search_base/query).
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $search_base = 'search';
+
+ /**
+ * Permalink structure for searches.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $search_structure;
+
+ /**
+ * Comments permalink base.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $comments_base = 'comments';
+
+ /**
+ * Pagination permalink base.
+ *
+ * @since 3.1.0
+ * @access private
+ * @var string
+ */
+ var $pagination_base = 'page';
+
+ /**
+ * Feed permalink base.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $feed_base = 'feed';
+
+ /**
+ * Comments feed permalink structure.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $comments_feed_structure;
+
+ /**
+ * Feed request permalink structure.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $feed_structure;
+
+ /**
+ * The static portion of the post permalink structure.
+ *
+ * If the permalink structure is "/archive/%post_id%" then the front
+ * is "/archive/". If the permalink structure is "/%year%/%postname%/"
+ * then the front is "/".
+ *
+ * @see WP_Rewrite::init()
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $front;
+
+ /**
+ * The prefix for all permalink structures.
+ *
+ * If PATHINFO/index permalinks are in use then the root is the value of
+ * {@link WP_Rewrite::$index} with a trailing slash appended. Otherwise
+ * the root will be empty.
+ *
+ * @see WP_Rewrite::init()
+ * @see WP_Rewrite::using_index_permalinks()
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $root = '';
+
+ /**
+ * The name of the index file which is the entry point to all requests.
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $index = 'index.php';
+
+ /**
+ * Variable name to use for regex matches in the rewritten query.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var string
+ */
+ var $matches = '';
+
+ /**
+ * Rewrite rules to match against the request to find the redirect or query.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $rules;
+
+ /**
+ * Additional rules added external to the rewrite class.
+ *
+ * Those not generated by the class, see add_rewrite_rule().
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $extra_rules = array();
+
+ /**
+ * Additional rules that belong at the beginning to match first.
+ *
+ * Those not generated by the class, see add_rewrite_rule().
+ *
+ * @since 2.3.0
+ * @access private
+ * @var array
+ */
+ var $extra_rules_top = array();
+
+ /**
+ * Rules that don't redirect to WordPress' index.php.
+ *
+ * These rules are written to the mod_rewrite portion of the .htaccess,
+ * and are added by {@link add_external_rule()}.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $non_wp_rules = array();
+
+ /**
+ * Extra permalink structures, e.g. categories, added by {@link add_permastruct()}.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $extra_permastructs = array();
+
+ /**
+ * Endpoints (like /trackback/) added by {@link add_rewrite_endpoint()}.
+ *
+ * @since 2.1.0
+ * @access private
+ * @var array
+ */
+ var $endpoints;
+
+ /**
+ * Whether to write every mod_rewrite rule for WordPress into the .htaccess file.
+ *
+ * This is off by default, turning it on might print a lot of rewrite rules
+ * to the .htaccess file.
+ *
+ * @see WP_Rewrite::mod_rewrite_rules()
+ * @since 2.0.0
+ * @access public
+ * @var bool
+ */
+ var $use_verbose_rules = false;
+
+ /**
+ * Could post permalinks be confused with those of pages?
+ *
+ * If the first rewrite tag in the post permalink structure is one that could
+ * also match a page name (e.g. %postname% or %author%) then this flag is
+ * set to true. Prior to WordPress 3.3 this flag indicated that every page
+ * would have a set of rules added to the top of the rewrite rules array.
+ * Now it tells {@link WP::parse_request()} to check if a URL matching the
+ * page permastruct is actually a page before accepting it.
+ *
+ * @link http://core.trac.wordpress.org/ticket/16687
+ * @see WP_Rewrite::init()
+ * @since 2.5.0
+ * @access public
+ * @var bool
+ */
+ var $use_verbose_page_rules = true;
+
+ /**
+ * Rewrite tags that can be used in permalink structures.
+ *
+ * These are translated into the regular expressions stored in
+ * {@link WP_Rewrite::$rewritereplace} and are rewritten to the
+ * query variables listed in {@link WP_Rewrite::$queryreplace}.
+ *
+ * Additional tags can be added with {@link add_rewrite_tag()}.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $rewritecode = array(
+ '%year%',
+ '%monthnum%',
+ '%day%',
+ '%hour%',
+ '%minute%',
+ '%second%',
+ '%postname%',
+ '%post_id%',
+ '%author%',
+ '%pagename%',
+ '%search%'
+ );
+
+ /**
+ * Regular expressions to be substituted into rewrite rules in place
+ * of rewrite tags, see {@link WP_Rewrite::$rewritecode}.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $rewritereplace = array(
+ '([0-9]{4})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([0-9]{1,2})',
+ '([^/]+)',
+ '([0-9]+)',
+ '([^/]+)',
+ '([^/]+?)',
+ '(.+)'
+ );
+
+ /**
+ * Query variables that rewrite tags map to, see {@link WP_Rewrite::$rewritecode}.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $queryreplace = array(
+ 'year=',
+ 'monthnum=',
+ 'day=',
+ 'hour=',
+ 'minute=',
+ 'second=',
+ 'name=',
+ 'p=',
+ 'author_name=',
+ 'pagename=',
+ 's='
+ );
+
+ /**
+ * Supported default feeds.
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $feeds = array( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
+
+ /**
+ * Whether permalinks are being used.
+ *
+ * This can be either rewrite module or permalink in the HTTP query string.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool True, if permalinks are enabled.
+ */
+ function using_permalinks() {
+ return ! empty($this->permalink_structure);
+ }
+
+ /**
+ * Whether permalinks are being used and rewrite module is not enabled.
+ *
+ * Means that permalink links are enabled and index.php is in the URL.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool
+ */
+ function using_index_permalinks() {
+ if ( empty($this->permalink_structure) )
+ return false;
+
+ // If the index is not in the permalink, we're using mod_rewrite.
+ if ( preg_match('#^/*' . $this->index . '#', $this->permalink_structure) )
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Whether permalinks are being used and rewrite module is enabled.
+ *
+ * Using permalinks and index.php is not in the URL.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool
+ */
+ function using_mod_rewrite_permalinks() {
+ if ( $this->using_permalinks() && ! $this->using_index_permalinks() )
+ return true;
+ else
+ return false;
+ }
+
+ /**
+ * Index for matches for usage in preg_*() functions.
+ *
+ * The format of the string is, with empty matches property value, '$NUM'.
+ * The 'NUM' will be replaced with the value in the $number parameter. With
+ * the matches property not empty, the value of the returned string will
+ * contain that value of the matches property. The format then will be
+ * '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the
+ * value of the $number parameter.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param int $number Index number.
+ * @return string
+ */
+ function preg_index($number) {
+ $match_prefix = '$';
+ $match_suffix = '';
+
+ if ( ! empty($this->matches) ) {
+ $match_prefix = '$' . $this->matches . '[';
+ $match_suffix = ']';
+ }
+
+ return "$match_prefix$number$match_suffix";
+ }
+
+ /**
+ * Retrieve all page and attachments for pages URIs.
+ *
+ * The attachments are for those that have pages as parents and will be
+ * retrieved.
+ *
+ * @since 2.5.0
+ * @access public
+ *
+ * @return array Array of page URIs as first element and attachment URIs as second element.
+ */
+ function page_uri_index() {
+ global $wpdb;
+
+ //get pages in order of hierarchy, i.e. children after parents
+ $posts = get_page_hierarchy( $wpdb->get_results("SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page' AND post_status != 'auto-draft'") );
+
+ // If we have no pages get out quick
+ if ( !$posts )
+ return array( array(), array() );
+
+ //now reverse it, because we need parents after children for rewrite rules to work properly
+ $posts = array_reverse($posts, true);
+
+ $page_uris = array();
+ $page_attachment_uris = array();
+
+ foreach ( $posts as $id => $post ) {
+ // URL => page name
+ $uri = get_page_uri($id);
+ $attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id ));
+ if ( !empty($attachments) ) {
+ foreach ( $attachments as $attachment ) {
+ $attach_uri = get_page_uri($attachment->ID);
+ $page_attachment_uris[$attach_uri] = $attachment->ID;
+ }
+ }
+
+ $page_uris[$uri] = $id;
+ }
+
+ return array( $page_uris, $page_attachment_uris );
+ }
+
+ /**
+ * Retrieve all of the rewrite rules for pages.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return array
+ */
+ function page_rewrite_rules() {
+ // the extra .? at the beginning prevents clashes with other regular expressions in the rules array
+ $this->add_rewrite_tag( '%pagename%', '(.?.+?)', 'pagename=' );
+
+ return $this->generate_rewrite_rules( $this->get_page_permastruct(), EP_PAGES, true, true, false, false );
+ }
+
+ /**
+ * Retrieve date permalink structure, with year, month, and day.
+ *
+ * The permalink structure for the date, if not set already depends on the
+ * permalink structure. It can be one of three formats. The first is year,
+ * month, day; the second is day, month, year; and the last format is month,
+ * day, year. These are matched against the permalink structure for which
+ * one is used. If none matches, then the default will be used, which is
+ * year, month, day.
+ *
+ * Prevents post ID and date permalinks from overlapping. In the case of
+ * post_id, the date permalink will be prepended with front permalink with
+ * 'date/' before the actual permalink to form the complete date permalink
+ * structure.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on no permalink structure. Date permalink structure.
+ */
+ function get_date_permastruct() {
+ if ( isset($this->date_structure) )
+ return $this->date_structure;
+
+ if ( empty($this->permalink_structure) ) {
+ $this->date_structure = '';
+ return false;
+ }
+
+ // The date permalink must have year, month, and day separated by slashes.
+ $endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%');
+
+ $this->date_structure = '';
+ $date_endian = '';
+
+ foreach ( $endians as $endian ) {
+ if ( false !== strpos($this->permalink_structure, $endian) ) {
+ $date_endian= $endian;
+ break;
+ }
+ }
+
+ if ( empty($date_endian) )
+ $date_endian = '%year%/%monthnum%/%day%';
+
+ // Do not allow the date tags and %post_id% to overlap in the permalink
+ // structure. If they do, move the date tags to $front/date/.
+ $front = $this->front;
+ preg_match_all('/%.+?%/', $this->permalink_structure, $tokens);
+ $tok_index = 1;
+ foreach ( (array) $tokens[0] as $token) {
+ if ( '%post_id%' == $token && ($tok_index <= 3) ) {
+ $front = $front . 'date/';
+ break;
+ }
+ $tok_index++;
+ }
+
+ $this->date_structure = $front . $date_endian;
+
+ return $this->date_structure;
+ }
+
+ /**
+ * Retrieve the year permalink structure without month and day.
+ *
+ * Gets the date permalink structure and strips out the month and day
+ * permalink structures.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Year structure on success.
+ */
+ function get_year_permastruct() {
+ $structure = $this->get_date_permastruct();
+
+ if ( empty($structure) )
+ return false;
+
+ $structure = str_replace('%monthnum%', '', $structure);
+ $structure = str_replace('%day%', '', $structure);
+
+ $structure = preg_replace('#/+#', '/', $structure);
+
+ return $structure;
+ }
+
+ /**
+ * Retrieve the month permalink structure without day and with year.
+ *
+ * Gets the date permalink structure and strips out the day permalink
+ * structures. Keeps the year permalink structure.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Year/Month structure on success.
+ */
+ function get_month_permastruct() {
+ $structure = $this->get_date_permastruct();
+
+ if ( empty($structure) )
+ return false;
+
+ $structure = str_replace('%day%', '', $structure);
+
+ $structure = preg_replace('#/+#', '/', $structure);
+
+ return $structure;
+ }
+
+ /**
+ * Retrieve the day permalink structure with month and year.
+ *
+ * Keeps date permalink structure with all year, month, and day.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Year/Month/Day structure on success.
+ */
+ function get_day_permastruct() {
+ return $this->get_date_permastruct();
+ }
+
+ /**
+ * Retrieve the permalink structure for categories.
+ *
+ * If the category_base property has no value, then the category structure
+ * will have the front property value, followed by 'category', and finally
+ * '%category%'. If it does, then the root property will be used, along with
+ * the category_base property value.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return bool|string False on failure. Category permalink structure.
+ */
+ function get_category_permastruct() {
+ return $this->get_extra_permastruct('category');
+ }
+
+ /**
+ * Retrieve the permalink structure for tags.
+ *
+ * If the tag_base property has no value, then the tag structure will have
+ * the front property value, followed by 'tag', and finally '%tag%'. If it
+ * does, then the root property will be used, along with the tag_base
+ * property value.
+ *
+ * @since 2.3.0
+ * @access public
+ *
+ * @return bool|string False on failure. Tag permalink structure.
+ */
+ function get_tag_permastruct() {
+ return $this->get_extra_permastruct('post_tag');
+ }
+
+ /**
+ * Retrieve extra permalink structure by name.
+ *
+ * @since 2.5.0
+ * @access public
+ *
+ * @param string $name Permalink structure name.
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_extra_permastruct($name) {
+ if ( empty($this->permalink_structure) )
+ return false;
+
+ if ( isset($this->extra_permastructs[$name]) )
+ return $this->extra_permastructs[$name]['struct'];
+
+ return false;
+ }
+
+ /**
+ * Retrieve the author permalink structure.
+ *
+ * The permalink structure is front property, author base, and finally
+ * '/%author%'. Will set the author_structure property and then return it
+ * without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_author_permastruct() {
+ if ( isset($this->author_structure) )
+ return $this->author_structure;
+
+ if ( empty($this->permalink_structure) ) {
+ $this->author_structure = '';
+ return false;
+ }
+
+ $this->author_structure = $this->front . $this->author_base . '/%author%';
+
+ return $this->author_structure;
+ }
+
+ /**
+ * Retrieve the search permalink structure.
+ *
+ * The permalink structure is root property, search base, and finally
+ * '/%search%'. Will set the search_structure property and then return it
+ * without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_search_permastruct() {
+ if ( isset($this->search_structure) )
+ return $this->search_structure;
+
+ if ( empty($this->permalink_structure) ) {
+ $this->search_structure = '';
+ return false;
+ }
+
+ $this->search_structure = $this->root . $this->search_base . '/%search%';
+
+ return $this->search_structure;
+ }
+
+ /**
+ * Retrieve the page permalink structure.
+ *
+ * The permalink structure is root property, and '%pagename%'. Will set the
+ * page_structure property and then return it without attempting to set the
+ * value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_page_permastruct() {
+ if ( isset($this->page_structure) )
+ return $this->page_structure;
+
+ if (empty($this->permalink_structure)) {
+ $this->page_structure = '';
+ return false;
+ }
+
+ $this->page_structure = $this->root . '%pagename%';
+
+ return $this->page_structure;
+ }
+
+ /**
+ * Retrieve the feed permalink structure.
+ *
+ * The permalink structure is root property, feed base, and finally
+ * '/%feed%'. Will set the feed_structure property and then return it
+ * without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_feed_permastruct() {
+ if ( isset($this->feed_structure) )
+ return $this->feed_structure;
+
+ if ( empty($this->permalink_structure) ) {
+ $this->feed_structure = '';
+ return false;
+ }
+
+ $this->feed_structure = $this->root . $this->feed_base . '/%feed%';
+
+ return $this->feed_structure;
+ }
+
+ /**
+ * Retrieve the comment feed permalink structure.
+ *
+ * The permalink structure is root property, comment base property, feed
+ * base and finally '/%feed%'. Will set the comment_feed_structure property
+ * and then return it without attempting to set the value again.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string|bool False if not found. Permalink structure string.
+ */
+ function get_comment_feed_permastruct() {
+ if ( isset($this->comment_feed_structure) )
+ return $this->comment_feed_structure;
+
+ if (empty($this->permalink_structure)) {
+ $this->comment_feed_structure = '';
+ return false;
+ }
+
+ $this->comment_feed_structure = $this->root . $this->comments_base . '/' . $this->feed_base . '/%feed%';
+
+ return $this->comment_feed_structure;
+ }
+
+ /**
+ * Add or update existing rewrite tags (e.g. %postname%).
+ *
+ * If the tag already exists, replace the existing pattern and query for
+ * that tag, otherwise add the new tag.
+ *
+ * @see WP_Rewrite::$rewritecode
+ * @see WP_Rewrite::$rewritereplace
+ * @see WP_Rewrite::$queryreplace
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $tag Name of the rewrite tag to add or update.
+ * @param string $regex Regular expression to substitute the tag for in rewrite rules.
+ * @param string $query String to append to the rewritten query. Must end in '='.
+ */
+ function add_rewrite_tag( $tag, $regex, $query ) {
+ $position = array_search( $tag, $this->rewritecode );
+ if ( false !== $position && null !== $position ) {
+ $this->rewritereplace[ $position ] = $regex;
+ $this->queryreplace[ $position ] = $query;
+ } else {
+ $this->rewritecode[] = $tag;
+ $this->rewritereplace[] = $regex;
+ $this->queryreplace[] = $query;
+ }
+ }
+
+ /**
+ * Generate rewrite rules from a permalink structure.
+ *
+ * The main WP_Rewrite function for building the rewrite rule list. The
+ * contents of the function is a mix of black magic and regular expressions,
+ * so best just ignore the contents and move to the parameters.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $permalink_structure The permalink structure.
+ * @param int $ep_mask Endpoint mask defining what endpoints are added to the structure. Default is EP_NONE.
+ * @param bool $paged Should archive pagination rules be added for the structure? Default is true.
+ * @param bool $feed Should feed rewrite rules be added for the structure? Default is true.
+ * @param bool $forcomments Should the feed rules be a query for a comments feed? Default is false.
+ * @param bool $walk_dirs Should the 'directories' making up the structure be walked over and rewrite rules
+ * built for each in turn? Default is true.
+ * @param bool $endpoints Should endpoints be applied to the generated rewrite rules? Default is true.
+ * @return array Rewrite rule list.
+ */
+ function generate_rewrite_rules($permalink_structure, $ep_mask = EP_NONE, $paged = true, $feed = true, $forcomments = false, $walk_dirs = true, $endpoints = true) {
+ //build a regex to match the feed section of URLs, something like (feed|atom|rss|rss2)/?
+ $feedregex2 = '';
+ foreach ( (array) $this->feeds as $feed_name)
+ $feedregex2 .= $feed_name . '|';
+ $feedregex2 = '(' . trim($feedregex2, '|') . ')/?$';
+
+ //$feedregex is identical but with /feed/ added on as well, so URLs like <permalink>/feed/atom
+ //and <permalink>/atom are both possible
+ $feedregex = $this->feed_base . '/' . $feedregex2;
+
+ //build a regex to match the trackback and page/xx parts of URLs
+ $trackbackregex = 'trackback/?$';
+ $pageregex = $this->pagination_base . '/?([0-9]{1,})/?$';
+ $commentregex = 'comment-page-([0-9]{1,})/?$';
+
+ //build up an array of endpoint regexes to append => queries to append
+ if ( $endpoints ) {
+ $ep_query_append = array ();
+ foreach ( (array) $this->endpoints as $endpoint) {
+ //match everything after the endpoint name, but allow for nothing to appear there
+ $epmatch = $endpoint[1] . '(/(.*))?/?$';
+ //this will be appended on to the rest of the query for each dir
+ $epquery = '&' . $endpoint[1] . '=';
+ $ep_query_append[$epmatch] = array ( $endpoint[0], $epquery );
+ }
+ }
+
+ //get everything up to the first rewrite tag
+ $front = substr($permalink_structure, 0, strpos($permalink_structure, '%'));
+ //build an array of the tags (note that said array ends up being in $tokens[0])
+ preg_match_all('/%.+?%/', $permalink_structure, $tokens);
+
+ $num_tokens = count($tokens[0]);
+
+ $index = $this->index; //probably 'index.php'
+ $feedindex = $index;
+ $trackbackindex = $index;
+ //build a list from the rewritecode and queryreplace arrays, that will look something like
+ //tagname=$matches[i] where i is the current $i
+ for ( $i = 0; $i < $num_tokens; ++$i ) {
+ if ( 0 < $i )
+ $queries[$i] = $queries[$i - 1] . '&';
+ else
+ $queries[$i] = '';
+
+ $query_token = str_replace($this->rewritecode, $this->queryreplace, $tokens[0][$i]) . $this->preg_index($i+1);
+ $queries[$i] .= $query_token;
+ }
+
+ //get the structure, minus any cruft (stuff that isn't tags) at the front
+ $structure = $permalink_structure;
+ if ( $front != '/' )
+ $structure = str_replace($front, '', $structure);
+
+ //create a list of dirs to walk over, making rewrite rules for each level
+ //so for example, a $structure of /%year%/%monthnum%/%postname% would create
+ //rewrite rules for /%year%/, /%year%/%monthnum%/ and /%year%/%monthnum%/%postname%
+ $structure = trim($structure, '/');
+ $dirs = $walk_dirs ? explode('/', $structure) : array( $structure );
+ $num_dirs = count($dirs);
+
+ //strip slashes from the front of $front
+ $front = preg_replace('|^/+|', '', $front);
+
+ //the main workhorse loop
+ $post_rewrite = array();
+ $struct = $front;
+ for ( $j = 0; $j < $num_dirs; ++$j ) {
+ //get the struct for this dir, and trim slashes off the front
+ $struct .= $dirs[$j] . '/'; //accumulate. see comment near explode('/', $structure) above
+ $struct = ltrim($struct, '/');
+
+ //replace tags with regexes
+ $match = str_replace($this->rewritecode, $this->rewritereplace, $struct);
+
+ //make a list of tags, and store how many there are in $num_toks
+ $num_toks = preg_match_all('/%.+?%/', $struct, $toks);
+
+ //get the 'tagname=$matches[i]'
+ $query = ( isset($queries) && is_array($queries) && !empty($num_toks) ) ? $queries[$num_toks - 1] : '';
+
+ //set up $ep_mask_specific which is used to match more specific URL types
+ switch ( $dirs[$j] ) {
+ case '%year%':
+ $ep_mask_specific = EP_YEAR;
+ break;
+ case '%monthnum%':
+ $ep_mask_specific = EP_MONTH;
+ break;
+ case '%day%':
+ $ep_mask_specific = EP_DAY;
+ break;
+ default:
+ $ep_mask_specific = EP_NONE;
+ }
+
+ //create query for /page/xx
+ $pagematch = $match . $pageregex;
+ $pagequery = $index . '?' . $query . '&paged=' . $this->preg_index($num_toks + 1);
+
+ //create query for /comment-page-xx
+ $commentmatch = $match . $commentregex;
+ $commentquery = $index . '?' . $query . '&cpage=' . $this->preg_index($num_toks + 1);
+
+ if ( get_option('page_on_front') ) {
+ //create query for Root /comment-page-xx
+ $rootcommentmatch = $match . $commentregex;
+ $rootcommentquery = $index . '?' . $query . '&page_id=' . get_option('page_on_front') . '&cpage=' . $this->preg_index($num_toks + 1);
+ }
+
+ //create query for /feed/(feed|atom|rss|rss2|rdf)
+ $feedmatch = $match . $feedregex;
+ $feedquery = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
+
+ //create query for /(feed|atom|rss|rss2|rdf) (see comment near creation of $feedregex)
+ $feedmatch2 = $match . $feedregex2;
+ $feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
+
+ //if asked to, turn the feed queries into comment feed ones
+ if ( $forcomments ) {
+ $feedquery .= '&withcomments=1';
+ $feedquery2 .= '&withcomments=1';
+ }
+
+ //start creating the array of rewrites for this dir
+ $rewrite = array();
+ if ( $feed ) //...adding on /feed/ regexes => queries
+ $rewrite = array($feedmatch => $feedquery, $feedmatch2 => $feedquery2);
+ if ( $paged ) //...and /page/xx ones
+ $rewrite = array_merge($rewrite, array($pagematch => $pagequery));
+
+ //only on pages with comments add ../comment-page-xx/
+ if ( EP_PAGES & $ep_mask || EP_PERMALINK & $ep_mask )
+ $rewrite = array_merge($rewrite, array($commentmatch => $commentquery));
+ else if ( EP_ROOT & $ep_mask && get_option('page_on_front') )
+ $rewrite = array_merge($rewrite, array($rootcommentmatch => $rootcommentquery));
+
+ //do endpoints
+ if ( $endpoints ) {
+ foreach ( (array) $ep_query_append as $regex => $ep) {
+ //add the endpoints on if the mask fits
+ if ( $ep[0] & $ep_mask || $ep[0] & $ep_mask_specific )
+ $rewrite[$match . $regex] = $index . '?' . $query . $ep[1] . $this->preg_index($num_toks + 2);
+ }
+ }
+
+ //if we've got some tags in this dir
+ if ( $num_toks ) {
+ $post = false;
+ $page = false;
+
+ //check to see if this dir is permalink-level: i.e. the structure specifies an
+ //individual post. Do this by checking it contains at least one of 1) post name,
+ //2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and
+ //minute all present). Set these flags now as we need them for the endpoints.
+ if ( strpos($struct, '%postname%') !== false
+ || strpos($struct, '%post_id%') !== false
+ || strpos($struct, '%pagename%') !== false
+ || (strpos($struct, '%year%') !== false && strpos($struct, '%monthnum%') !== false && strpos($struct, '%day%') !== false && strpos($struct, '%hour%') !== false && strpos($struct, '%minute%') !== false && strpos($struct, '%second%') !== false)
+ ) {
+ $post = true;
+ if ( strpos($struct, '%pagename%') !== false )
+ $page = true;
+ }
+
+ if ( ! $post ) {
+ // For custom post types, we need to add on endpoints as well.
+ foreach ( get_post_types( array('_builtin' => false ) ) as $ptype ) {
+ if ( strpos($struct, "%$ptype%") !== false ) {
+ $post = true;
+ $page = is_post_type_hierarchical( $ptype ); // This is for page style attachment url's
+ break;
+ }
+ }
+ }
+
+ //if we're creating rules for a permalink, do all the endpoints like attachments etc
+ if ( $post ) {
+ //create query and regex for trackback
+ $trackbackmatch = $match . $trackbackregex;
+ $trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
+ //trim slashes from the end of the regex for this dir
+ $match = rtrim($match, '/');
+ //get rid of brackets
+ $submatchbase = str_replace( array('(', ')'), '', $match);
+
+ //add a rule for at attachments, which take the form of <permalink>/some-text
+ $sub1 = $submatchbase . '/([^/]+)/';
+ $sub1tb = $sub1 . $trackbackregex; //add trackback regex <permalink>/trackback/...
+ $sub1feed = $sub1 . $feedregex; //and <permalink>/feed/(atom|...)
+ $sub1feed2 = $sub1 . $feedregex2; //and <permalink>/(feed|atom...)
+ $sub1comment = $sub1 . $commentregex; //and <permalink>/comment-page-xx
+
+ //add another rule to match attachments in the explicit form:
+ //<permalink>/attachment/some-text
+ $sub2 = $submatchbase . '/attachment/([^/]+)/';
+ $sub2tb = $sub2 . $trackbackregex; //and add trackbacks <permalink>/attachment/trackback
+ $sub2feed = $sub2 . $feedregex; //feeds, <permalink>/attachment/feed/(atom|...)
+ $sub2feed2 = $sub2 . $feedregex2; //and feeds again on to this <permalink>/attachment/(feed|atom...)
+ $sub2comment = $sub2 . $commentregex; //and <permalink>/comment-page-xx
+
+ //create queries for these extra tag-ons we've just dealt with
+ $subquery = $index . '?attachment=' . $this->preg_index(1);
+ $subtbquery = $subquery . '&tb=1';
+ $subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
+ $subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
+
+ //do endpoints for attachments
+ if ( !empty($endpoints) ) {
+ foreach ( (array) $ep_query_append as $regex => $ep ) {
+ if ( $ep[0] & EP_ATTACHMENT ) {
+ $rewrite[$sub1 . $regex] = $subquery . $ep[1] . $this->preg_index(3);
+ $rewrite[$sub2 . $regex] = $subquery . $ep[1] . $this->preg_index(3);
+ }
+ }
+ }
+
+ //now we've finished with endpoints, finish off the $sub1 and $sub2 matches
+ //add a ? as we don't have to match that last slash, and finally a $ so we
+ //match to the end of the URL
+ $sub1 .= '?$';
+ $sub2 .= '?$';
+
+ //post pagination, e.g. <permalink>/2/
+ $match = $match . '(/[0-9]+)?/?$';
+ $query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1);
+ } else { //not matching a permalink so this is a lot simpler
+ //close the match and finalise the query
+ $match .= '?$';
+ $query = $index . '?' . $query;
+ }
+
+ //create the final array for this dir by joining the $rewrite array (which currently
+ //only contains rules/queries for trackback, pages etc) to the main regex/query for
+ //this dir
+ $rewrite = array_merge($rewrite, array($match => $query));
+
+ //if we're matching a permalink, add those extras (attachments etc) on
+ if ( $post ) {
+ //add trackback
+ $rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
+
+ //add regexes/queries for attachments, attachment trackbacks and so on
+ if ( ! $page ) //require <permalink>/attachment/stuff form for pages because of confusion with subpages
+ $rewrite = array_merge($rewrite, array($sub1 => $subquery, $sub1tb => $subtbquery, $sub1feed => $subfeedquery, $sub1feed2 => $subfeedquery, $sub1comment => $subcommentquery));
+ $rewrite = array_merge(array($sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery), $rewrite);
+ }
+ } //if($num_toks)
+ //add the rules for this dir to the accumulating $post_rewrite
+ $post_rewrite = array_merge($rewrite, $post_rewrite);
+ } //foreach ($dir)
+ return $post_rewrite; //the finished rules. phew!
+ }
+
+ /**
+ * Generate Rewrite rules with permalink structure and walking directory only.
+ *
+ * Shorten version of {@link WP_Rewrite::generate_rewrite_rules()} that
+ * allows for shorter list of parameters. See the method for longer
+ * description of what generating rewrite rules does.
+ *
+ * @uses WP_Rewrite::generate_rewrite_rules() See for long description and rest of parameters.
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $permalink_structure The permalink structure to generate rules.
+ * @param bool $walk_dirs Optional, default is false. Whether to create list of directories to walk over.
+ * @return array
+ */
+ function generate_rewrite_rule($permalink_structure, $walk_dirs = false) {
+ return $this->generate_rewrite_rules($permalink_structure, EP_NONE, false, false, false, $walk_dirs);
+ }
+
+ /**
+ * Construct rewrite matches and queries from permalink structure.
+ *
+ * Runs the action 'generate_rewrite_rules' with the parameter that is an
+ * reference to the current WP_Rewrite instance to further manipulate the
+ * permalink structures and rewrite rules. Runs the 'rewrite_rules_array'
+ * filter on the full rewrite rule array.
+ *
+ * There are two ways to manipulate the rewrite rules, one by hooking into
+ * the 'generate_rewrite_rules' action and gaining full control of the
+ * object or just manipulating the rewrite rule array before it is passed
+ * from the function.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return array An associate array of matches and queries.
+ */
+ function rewrite_rules() {
+ $rewrite = array();
+
+ if ( empty($this->permalink_structure) )
+ return $rewrite;
+
+ // robots.txt -only if installed at the root
+ $home_path = parse_url( home_url() );
+ $robots_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'robots\.txt$' => $this->index . '?robots=1' ) : array();
+
+ // Old feed and service files
+ $deprecated_files = array(
+ '.*wp-(atom|rdf|rss|rss2|feed|commentsrss2)\.php$' => $this->index . '?feed=old',
+ '.*wp-app\.php(/.*)?$' => $this->index . '?error=403',
+ );
+
+ // Registration rules
+ $registration_pages = array();
+ if ( is_multisite() && is_main_site() ) {
+ $registration_pages['.*wp-signup.php$'] = $this->index . '?signup=true';
+ $registration_pages['.*wp-activate.php$'] = $this->index . '?activate=true';
+ }
+ $registration_pages['.*wp-register.php$'] = $this->index . '?register=true'; // Deprecated
+
+ // Post
+ $post_rewrite = $this->generate_rewrite_rules( $this->permalink_structure, EP_PERMALINK );
+ $post_rewrite = apply_filters('post_rewrite_rules', $post_rewrite);
+
+ // Date
+ $date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct(), EP_DATE);
+ $date_rewrite = apply_filters('date_rewrite_rules', $date_rewrite);
+
+ // Root
+ $root_rewrite = $this->generate_rewrite_rules($this->root . '/', EP_ROOT);
+ $root_rewrite = apply_filters('root_rewrite_rules', $root_rewrite);
+
+ // Comments
+ $comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, EP_COMMENTS, false, true, true, false);
+ $comments_rewrite = apply_filters('comments_rewrite_rules', $comments_rewrite);
+
+ // Search
+ $search_structure = $this->get_search_permastruct();
+ $search_rewrite = $this->generate_rewrite_rules($search_structure, EP_SEARCH);
+ $search_rewrite = apply_filters('search_rewrite_rules', $search_rewrite);
+
+ // Authors
+ $author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct(), EP_AUTHORS);
+ $author_rewrite = apply_filters('author_rewrite_rules', $author_rewrite);
+
+ // Pages
+ $page_rewrite = $this->page_rewrite_rules();
+ $page_rewrite = apply_filters('page_rewrite_rules', $page_rewrite);
+
+ // Extra permastructs
+ foreach ( $this->extra_permastructs as $permastructname => $struct ) {
+ if ( is_array( $struct ) ) {
+ if ( count( $struct ) == 2 )
+ $rules = $this->generate_rewrite_rules( $struct[0], $struct[1] );
+ else
+ $rules = $this->generate_rewrite_rules( $struct['struct'], $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
+ } else {
+ $rules = $this->generate_rewrite_rules( $struct );
+ }
+
+ $rules = apply_filters($permastructname . '_rewrite_rules', $rules);
+ if ( 'post_tag' == $permastructname )
+ $rules = apply_filters('tag_rewrite_rules', $rules);
+
+ $this->extra_rules_top = array_merge($this->extra_rules_top, $rules);
+ }
+
+ // Put them together.
+ if ( $this->use_verbose_page_rules )
+ $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $author_rewrite, $date_rewrite, $page_rewrite, $post_rewrite, $this->extra_rules);
+ else
+ $this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite, $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules);
+
+ do_action_ref_array('generate_rewrite_rules', array(&$this));
+ $this->rules = apply_filters('rewrite_rules_array', $this->rules);
+
+ return $this->rules;
+ }
+
+ /**
+ * Retrieve the rewrite rules.
+ *
+ * The difference between this method and {@link
+ * WP_Rewrite::rewrite_rules()} is that this method stores the rewrite rules
+ * in the 'rewrite_rules' option and retrieves it. This prevents having to
+ * process all of the permalinks to get the rewrite rules in the form of
+ * caching.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return array Rewrite rules.
+ */
+ function wp_rewrite_rules() {
+ $this->rules = get_option('rewrite_rules');
+ if ( empty($this->rules) ) {
+ $this->matches = 'matches';
+ $this->rewrite_rules();
+ update_option('rewrite_rules', $this->rules);
+ }
+
+ return $this->rules;
+ }
+
+ /**
+ * Retrieve mod_rewrite formatted rewrite rules to write to .htaccess.
+ *
+ * Does not actually write to the .htaccess file, but creates the rules for
+ * the process that will.
+ *
+ * Will add the non_wp_rules property rules to the .htaccess file before
+ * the WordPress rewrite rules one.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return string
+ */
+ function mod_rewrite_rules() {
+ if ( ! $this->using_permalinks() )
+ return '';
+
+ $site_root = parse_url( site_url() );
+ if ( isset( $site_root['path'] ) )
+ $site_root = trailingslashit($site_root['path']);
+
+ $home_root = parse_url(home_url());
+ if ( isset( $home_root['path'] ) )
+ $home_root = trailingslashit($home_root['path']);
+ else
+ $home_root = '/';
+
+ $rules = "<IfModule mod_rewrite.c>\n";
+ $rules .= "RewriteEngine On\n";
+ $rules .= "RewriteBase $home_root\n";
+ $rules .= "RewriteRule ^index\.php$ - [L]\n"; // Prevent -f checks on index.php.
+
+ //add in the rules that don't redirect to WP's index.php (and thus shouldn't be handled by WP at all)
+ foreach ( (array) $this->non_wp_rules as $match => $query) {
+ // Apache 1.3 does not support the reluctant (non-greedy) modifier.
+ $match = str_replace('.+?', '.+', $match);
+
+ // If the match is unanchored and greedy, prepend rewrite conditions
+ // to avoid infinite redirects and eclipsing of real files.
+ //if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
+ //nada.
+ //}
+
+ $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
+ }
+
+ if ( $this->use_verbose_rules ) {
+ $this->matches = '';
+ $rewrite = $this->rewrite_rules();
+ $num_rules = count($rewrite);
+ $rules .= "RewriteCond %{REQUEST_FILENAME} -f [OR]\n" .
+ "RewriteCond %{REQUEST_FILENAME} -d\n" .
+ "RewriteRule ^.*$ - [S=$num_rules]\n";
+
+ foreach ( (array) $rewrite as $match => $query) {
+ // Apache 1.3 does not support the reluctant (non-greedy) modifier.
+ $match = str_replace('.+?', '.+', $match);
+
+ // If the match is unanchored and greedy, prepend rewrite conditions
+ // to avoid infinite redirects and eclipsing of real files.
+ //if ($match == '(.+)/?$' || $match == '([^/]+)/?$' ) {
+ //nada.
+ //}
+
+ if ( strpos($query, $this->index) !== false )
+ $rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
+ else
+ $rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
+ }
+ } else {
+ $rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" .
+ "RewriteCond %{REQUEST_FILENAME} !-d\n" .
+ "RewriteRule . {$home_root}{$this->index} [L]\n";
+ }
+
+ $rules .= "</IfModule>\n";
+
+ $rules = apply_filters('mod_rewrite_rules', $rules);
+ $rules = apply_filters('rewrite_rules', $rules); // Deprecated
+
+ return $rules;
+ }
+
+ /**
+ * Retrieve IIS7 URL Rewrite formatted rewrite rules to write to web.config file.
+ *
+ * Does not actually write to the web.config file, but creates the rules for
+ * the process that will.
+ *
+ * @since 2.8.0
+ * @access public
+ *
+ * @return string
+ */
+ function iis7_url_rewrite_rules( $add_parent_tags = false ) {
+
+ if ( ! $this->using_permalinks() )
+ return '';
+ $rules = '';
+ if ( $add_parent_tags ) {
+ $rules .= '<configuration>
+ <system.webServer>
+ <rewrite>
+ <rules>';
+ }
+
+ $rules .= '
+ <rule name="wordpress" patternSyntax="Wildcard">
+ <match url="*" />
+ <conditions>
+ <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
+ <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
+ </conditions>
+ <action type="Rewrite" url="index.php" />
+ </rule>';
+
+ if ( $add_parent_tags ) {
+ $rules .= '
+ </rules>
+ </rewrite>
+ </system.webServer>
+</configuration>';
+ }
+
+ $rules = apply_filters('iis7_url_rewrite_rules', $rules);
+
+ return $rules;
+ }
+
+ /**
+ * Add a straight rewrite rule.
+ *
+ * Any value in the $after parameter that isn't 'bottom' will be placed at
+ * the top of the rules.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $regex Regular expression to match against request.
+ * @param string $redirect URL regex redirects to when regex matches request.
+ * @param string $after Optional, default is bottom. Location to place rule.
+ */
+ function add_rule($regex, $redirect, $after = 'bottom') {
+ //get everything up to the first ?
+ $index = (strpos($redirect, '?') == false ? strlen($redirect) : strpos($redirect, '?'));
+ $front = substr($redirect, 0, $index);
+ if ( $front != $this->index ) { //it doesn't redirect to WP's index.php
+ $this->add_external_rule($regex, $redirect);
+ } else {
+ if ( 'bottom' == $after)
+ $this->extra_rules = array_merge($this->extra_rules, array($regex => $redirect));
+ else
+ $this->extra_rules_top = array_merge($this->extra_rules_top, array($regex => $redirect));
+ //$this->extra_rules[$regex] = $redirect;
+ }
+ }
+
+ /**
+ * Add a rule that doesn't redirect to index.php.
+ *
+ * Can redirect to any place.
+ *
+ * @since 2.1.0
+ * @access public
+ *
+ * @param string $regex Regular expression to match against request.
+ * @param string $redirect URL regex redirects to when regex matches request.
+ */
+ function add_external_rule($regex, $redirect) {
+ $this->non_wp_rules[$regex] = $redirect;
+ }
+
+ /**
+ * Add an endpoint, like /trackback/.
+ *
+ * See {@link add_rewrite_endpoint()} for full documentation.
+ *
+ * @see add_rewrite_endpoint()
+ * @since 2.1.0
+ * @access public
+ * @uses WP::add_query_var()
+ *
+ * @param string $name Name of the endpoint.
+ * @param int $places Endpoint mask describing the places the endpoint should be added.
+ */
+ function add_endpoint($name, $places) {
+ global $wp;
+ $this->endpoints[] = array ( $places, $name );
+ $wp->add_query_var($name);
+ }
+
+ /**
+ * Add a new permalink structure.
+ *
+ * A permalink structure (permastruct) is an abstract definition of a set of rewrite rules; it
+ * is an easy way of expressing a set of regular expressions that rewrite to a set of query strings.
+ * The new permastruct is added to the {@link WP_Rewrite::$extra_permastructs} array. When the
+ * rewrite rules are built by {@link WP_Rewrite::rewrite_rules()} all of these extra permastructs
+ * are passed to {@link WP_Rewrite::generate_rewrite_rules()} which transforms them into the
+ * regular expressions that many love to hate.
+ *
+ * The $args parameter gives you control over how {@link WP_Rewrite::generate_rewrite_rules()}
+ * works on the new permastruct.
+ *
+ * @since 2.5.0
+ * @access public
+ *
+ * @param string $name Name for permalink structure.
+ * @param string $struct Permalink structure (e.g. category/%category%)
+ * @param array $args Optional configuration for building the rules from the permalink structure:
+ * - with_front (bool) - Should the structure be prepended with WP_Rewrite::$front? Default is true.
+ * - ep_mask (int) - Endpoint mask defining what endpoints are added to the structure. Default is EP_NONE.
+ * - paged (bool) - Should archive pagination rules be added for the structure? Default is true.
+ * - feed (bool) - Should feed rewrite rules be added for the structure? Default is true.
+ * - forcomments (bool) - Should the feed rules be a query for a comments feed? Default is false.
+ * - walk_dirs (bool) - Should the 'directories' making up the structure be walked over and rewrite
+ * rules built for each in turn? Default is true.
+ * - endpoints (bool) - Should endpoints be applied to the generated rewrite rules? Default is true.
+ */
+ function add_permastruct( $name, $struct, $args = array() ) {
+ // backwards compatibility for the old parameters: $with_front and $ep_mask
+ if ( ! is_array( $args ) )
+ $args = array( 'with_front' => $args );
+ if ( func_num_args() == 4 )
+ $args['ep_mask'] = func_get_arg( 3 );
+
+ $defaults = array(
+ 'with_front' => true,
+ 'ep_mask' => EP_NONE,
+ 'paged' => true,
+ 'feed' => true,
+ 'forcomments' => false,
+ 'walk_dirs' => true,
+ 'endpoints' => true,
+ );
+ $args = array_intersect_key( $args, $defaults );
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( $args['with_front'] )
+ $struct = $this->front . $struct;
+ else
+ $struct = $this->root . $struct;
+ $args['struct'] = $struct;
+
+ $this->extra_permastructs[ $name ] = $args;
+ }
+
+ /**
+ * Remove rewrite rules and then recreate rewrite rules.
+ *
+ * Calls {@link WP_Rewrite::wp_rewrite_rules()} after removing the
+ * 'rewrite_rules' option. If the function named 'save_mod_rewrite_rules'
+ * exists, it will be called.
+ *
+ * @since 2.0.1
+ * @access public
+ * @param bool $hard Whether to update .htaccess (hard flush) or just update rewrite_rules option (soft flush). Default is true (hard).
+ */
+ function flush_rules($hard = true) {
+ delete_option('rewrite_rules');
+ $this->wp_rewrite_rules();
+ if ( $hard && function_exists('save_mod_rewrite_rules') )
+ save_mod_rewrite_rules();
+ if ( $hard && function_exists('iis7_save_url_rewrite_rules') )
+ iis7_save_url_rewrite_rules();
+ }
+
+ /**
+ * Sets up the object's properties.
+ *
+ * The 'use_verbose_page_rules' object property will be set to true if the
+ * permalink structure begins with one of the following: '%postname%', '%category%',
+ * '%tag%', or '%author%'.
+ *
+ * @since 1.5.0
+ * @access public
+ */
+ function init() {
+ $this->extra_rules = $this->non_wp_rules = $this->endpoints = array();
+ $this->permalink_structure = get_option('permalink_structure');
+ $this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%'));
+ $this->root = '';
+ if ( $this->using_index_permalinks() )
+ $this->root = $this->index . '/';
+ unset($this->author_structure);
+ unset($this->date_structure);
+ unset($this->page_structure);
+ unset($this->search_structure);
+ unset($this->feed_structure);
+ unset($this->comment_feed_structure);
+ $this->use_trailing_slashes = ( '/' == substr($this->permalink_structure, -1, 1) );
+
+ // Enable generic rules for pages if permalink structure doesn't begin with a wildcard.
+ if ( preg_match("/^[^%]*%(?:postname|category|tag|author)%/", $this->permalink_structure) )
+ $this->use_verbose_page_rules = true;
+ else
+ $this->use_verbose_page_rules = false;
+ }
+
+ /**
+ * Set the main permalink structure for the blog.
+ *
+ * Will update the 'permalink_structure' option, if there is a difference
+ * between the current permalink structure and the parameter value. Calls
+ * {@link WP_Rewrite::init()} after the option is updated.
+ *
+ * Fires the 'permalink_structure_changed' action once the init call has
+ * processed passing the old and new values
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $permalink_structure Permalink structure.
+ */
+ function set_permalink_structure($permalink_structure) {
+ if ( $permalink_structure != $this->permalink_structure ) {
+ $old_permalink_structure = $this->permalink_structure;
+ update_option('permalink_structure', $permalink_structure);
+ $this->init();
+ do_action('permalink_structure_changed', $old_permalink_structure, $permalink_structure);
+ }
+ }
+
+ /**
+ * Set the category base for the category permalink.
+ *
+ * Will update the 'category_base' option, if there is a difference between
+ * the current category base and the parameter value. Calls
+ * {@link WP_Rewrite::init()} after the option is updated.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @param string $category_base Category permalink structure base.
+ */
+ function set_category_base($category_base) {
+ if ( $category_base != get_option('category_base') ) {
+ update_option('category_base', $category_base);
+ $this->init();
+ }
+ }
+
+ /**
+ * Set the tag base for the tag permalink.
+ *
+ * Will update the 'tag_base' option, if there is a difference between the
+ * current tag base and the parameter value. Calls
+ * {@link WP_Rewrite::init()} after the option is updated.
+ *
+ * @since 2.3.0
+ * @access public
+ *
+ * @param string $tag_base Tag permalink structure base.
+ */
+ function set_tag_base( $tag_base ) {
+ if ( $tag_base != get_option( 'tag_base') ) {
+ update_option( 'tag_base', $tag_base );
+ $this->init();
+ }
+ }
+
+ /**
+ * Constructor - Calls init(), which runs setup.
+ *
+ * @since 1.5.0
+ * @access public
+ *
+ * @return WP_Rewrite
+ */
+ function __construct() {
+ $this->init();
+ }
+}
diff --git a/src/wp-includes/rss-functions.php b/src/wp-includes/rss-functions.php
new file mode 100644
index 0000000000..86458479df
--- /dev/null
+++ b/src/wp-includes/rss-functions.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Deprecated. Use rss.php instead.
+ *
+ * @package WordPress
+ */
+
+_deprecated_file( basename(__FILE__), '2.1', WPINC . '/rss.php' );
+require_once (ABSPATH . WPINC . '/rss.php');
diff --git a/src/wp-includes/rss.php b/src/wp-includes/rss.php
new file mode 100644
index 0000000000..cd08ec99e6
--- /dev/null
+++ b/src/wp-includes/rss.php
@@ -0,0 +1,932 @@
+<?php
+/**
+ * MagpieRSS: a simple RSS integration tool
+ *
+ * A compiled file for RSS syndication
+ *
+ * @author Kellan Elliott-McCrea <kellan@protest.net>
+ * @version 0.51
+ * @license GPL
+ *
+ * @package External
+ * @subpackage MagpieRSS
+ */
+
+/**
+ * Deprecated. Use SimplePie (class-simplepie.php) instead.
+ */
+_deprecated_file( basename( __FILE__ ), '3.0', WPINC . '/class-simplepie.php' );
+
+/*
+ * Hook to use another RSS object instead of MagpieRSS
+ */
+do_action('load_feed_engine');
+
+/** RSS feed constant. */
+define('RSS', 'RSS');
+define('ATOM', 'Atom');
+define('MAGPIE_USER_AGENT', 'WordPress/' . $GLOBALS['wp_version']);
+
+class MagpieRSS {
+ var $parser;
+ var $current_item = array(); // item currently being parsed
+ var $items = array(); // collection of parsed items
+ var $channel = array(); // hash of channel fields
+ var $textinput = array();
+ var $image = array();
+ var $feed_type;
+ var $feed_version;
+
+ // parser variables
+ var $stack = array(); // parser stack
+ var $inchannel = false;
+ var $initem = false;
+ var $incontent = false; // if in Atom <content mode="xml"> field
+ var $intextinput = false;
+ var $inimage = false;
+ var $current_field = '';
+ var $current_namespace = false;
+
+ //var $ERROR = "";
+
+ var $_CONTENT_CONSTRUCTS = array('content', 'summary', 'info', 'title', 'tagline', 'copyright');
+
+ function MagpieRSS ($source) {
+
+ # if PHP xml isn't compiled in, die
+ #
+ if ( !function_exists('xml_parser_create') )
+ trigger_error( "Failed to load PHP's XML Extension. http://www.php.net/manual/en/ref.xml.php" );
+
+ $parser = @xml_parser_create();
+
+ if ( !is_resource($parser) )
+ trigger_error( "Failed to create an instance of PHP's XML parser. http://www.php.net/manual/en/ref.xml.php");
+
+ $this->parser = $parser;
+
+ # pass in parser, and a reference to this object
+ # set up handlers
+ #
+ xml_set_object( $this->parser, $this );
+ xml_set_element_handler($this->parser,
+ 'feed_start_element', 'feed_end_element' );
+
+ xml_set_character_data_handler( $this->parser, 'feed_cdata' );
+
+ $status = xml_parse( $this->parser, $source );
+
+ if (! $status ) {
+ $errorcode = xml_get_error_code( $this->parser );
+ if ( $errorcode != XML_ERROR_NONE ) {
+ $xml_error = xml_error_string( $errorcode );
+ $error_line = xml_get_current_line_number($this->parser);
+ $error_col = xml_get_current_column_number($this->parser);
+ $errormsg = "$xml_error at line $error_line, column $error_col";
+
+ $this->error( $errormsg );
+ }
+ }
+
+ xml_parser_free( $this->parser );
+
+ $this->normalize();
+ }
+
+ function feed_start_element($p, $element, &$attrs) {
+ $el = $element = strtolower($element);
+ $attrs = array_change_key_case($attrs, CASE_LOWER);
+
+ // check for a namespace, and split if found
+ $ns = false;
+ if ( strpos( $element, ':' ) ) {
+ list($ns, $el) = split( ':', $element, 2);
+ }
+ if ( $ns and $ns != 'rdf' ) {
+ $this->current_namespace = $ns;
+ }
+
+ # if feed type isn't set, then this is first element of feed
+ # identify feed from root element
+ #
+ if (!isset($this->feed_type) ) {
+ if ( $el == 'rdf' ) {
+ $this->feed_type = RSS;
+ $this->feed_version = '1.0';
+ }
+ elseif ( $el == 'rss' ) {
+ $this->feed_type = RSS;
+ $this->feed_version = $attrs['version'];
+ }
+ elseif ( $el == 'feed' ) {
+ $this->feed_type = ATOM;
+ $this->feed_version = $attrs['version'];
+ $this->inchannel = true;
+ }
+ return;
+ }
+
+ if ( $el == 'channel' )
+ {
+ $this->inchannel = true;
+ }
+ elseif ($el == 'item' or $el == 'entry' )
+ {
+ $this->initem = true;
+ if ( isset($attrs['rdf:about']) ) {
+ $this->current_item['about'] = $attrs['rdf:about'];
+ }
+ }
+
+ // if we're in the default namespace of an RSS feed,
+ // record textinput or image fields
+ elseif (
+ $this->feed_type == RSS and
+ $this->current_namespace == '' and
+ $el == 'textinput' )
+ {
+ $this->intextinput = true;
+ }
+
+ elseif (
+ $this->feed_type == RSS and
+ $this->current_namespace == '' and
+ $el == 'image' )
+ {
+ $this->inimage = true;
+ }
+
+ # handle atom content constructs
+ elseif ( $this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
+ {
+ // avoid clashing w/ RSS mod_content
+ if ($el == 'content' ) {
+ $el = 'atom_content';
+ }
+
+ $this->incontent = $el;
+
+ }
+
+ // if inside an Atom content construct (e.g. content or summary) field treat tags as text
+ elseif ($this->feed_type == ATOM and $this->incontent )
+ {
+ // if tags are inlined, then flatten
+ $attrs_str = join(' ',
+ array_map(array('MagpieRSS', 'map_attrs'),
+ array_keys($attrs),
+ array_values($attrs) ) );
+
+ $this->append_content( "<$element $attrs_str>" );
+
+ array_unshift( $this->stack, $el );
+ }
+
+ // Atom support many links per containging element.
+ // Magpie treats link elements of type rel='alternate'
+ // as being equivalent to RSS's simple link element.
+ //
+ elseif ($this->feed_type == ATOM and $el == 'link' )
+ {
+ if ( isset($attrs['rel']) and $attrs['rel'] == 'alternate' )
+ {
+ $link_el = 'link';
+ }
+ else {
+ $link_el = 'link_' . $attrs['rel'];
+ }
+
+ $this->append($link_el, $attrs['href']);
+ }
+ // set stack[0] to current element
+ else {
+ array_unshift($this->stack, $el);
+ }
+ }
+
+ function feed_cdata ($p, $text) {
+
+ if ($this->feed_type == ATOM and $this->incontent)
+ {
+ $this->append_content( $text );
+ }
+ else {
+ $current_el = join('_', array_reverse($this->stack));
+ $this->append($current_el, $text);
+ }
+ }
+
+ function feed_end_element ($p, $el) {
+ $el = strtolower($el);
+
+ if ( $el == 'item' or $el == 'entry' )
+ {
+ $this->items[] = $this->current_item;
+ $this->current_item = array();
+ $this->initem = false;
+ }
+ elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'textinput' )
+ {
+ $this->intextinput = false;
+ }
+ elseif ($this->feed_type == RSS and $this->current_namespace == '' and $el == 'image' )
+ {
+ $this->inimage = false;
+ }
+ elseif ($this->feed_type == ATOM and in_array($el, $this->_CONTENT_CONSTRUCTS) )
+ {
+ $this->incontent = false;
+ }
+ elseif ($el == 'channel' or $el == 'feed' )
+ {
+ $this->inchannel = false;
+ }
+ elseif ($this->feed_type == ATOM and $this->incontent ) {
+ // balance tags properly
+ // note: i don't think this is actually neccessary
+ if ( $this->stack[0] == $el )
+ {
+ $this->append_content("</$el>");
+ }
+ else {
+ $this->append_content("<$el />");
+ }
+
+ array_shift( $this->stack );
+ }
+ else {
+ array_shift( $this->stack );
+ }
+
+ $this->current_namespace = false;
+ }
+
+ function concat (&$str1, $str2="") {
+ if (!isset($str1) ) {
+ $str1="";
+ }
+ $str1 .= $str2;
+ }
+
+ function append_content($text) {
+ if ( $this->initem ) {
+ $this->concat( $this->current_item[ $this->incontent ], $text );
+ }
+ elseif ( $this->inchannel ) {
+ $this->concat( $this->channel[ $this->incontent ], $text );
+ }
+ }
+
+ // smart append - field and namespace aware
+ function append($el, $text) {
+ if (!$el) {
+ return;
+ }
+ if ( $this->current_namespace )
+ {
+ if ( $this->initem ) {
+ $this->concat(
+ $this->current_item[ $this->current_namespace ][ $el ], $text);
+ }
+ elseif ($this->inchannel) {
+ $this->concat(
+ $this->channel[ $this->current_namespace][ $el ], $text );
+ }
+ elseif ($this->intextinput) {
+ $this->concat(
+ $this->textinput[ $this->current_namespace][ $el ], $text );
+ }
+ elseif ($this->inimage) {
+ $this->concat(
+ $this->image[ $this->current_namespace ][ $el ], $text );
+ }
+ }
+ else {
+ if ( $this->initem ) {
+ $this->concat(
+ $this->current_item[ $el ], $text);
+ }
+ elseif ($this->intextinput) {
+ $this->concat(
+ $this->textinput[ $el ], $text );
+ }
+ elseif ($this->inimage) {
+ $this->concat(
+ $this->image[ $el ], $text );
+ }
+ elseif ($this->inchannel) {
+ $this->concat(
+ $this->channel[ $el ], $text );
+ }
+
+ }
+ }
+
+ function normalize () {
+ // if atom populate rss fields
+ if ( $this->is_atom() ) {
+ $this->channel['descripton'] = $this->channel['tagline'];
+ for ( $i = 0; $i < count($this->items); $i++) {
+ $item = $this->items[$i];
+ if ( isset($item['summary']) )
+ $item['description'] = $item['summary'];
+ if ( isset($item['atom_content']))
+ $item['content']['encoded'] = $item['atom_content'];
+
+ $this->items[$i] = $item;
+ }
+ }
+ elseif ( $this->is_rss() ) {
+ $this->channel['tagline'] = $this->channel['description'];
+ for ( $i = 0; $i < count($this->items); $i++) {
+ $item = $this->items[$i];
+ if ( isset($item['description']))
+ $item['summary'] = $item['description'];
+ if ( isset($item['content']['encoded'] ) )
+ $item['atom_content'] = $item['content']['encoded'];
+
+ $this->items[$i] = $item;
+ }
+ }
+ }
+
+ function is_rss () {
+ if ( $this->feed_type == RSS ) {
+ return $this->feed_version;
+ }
+ else {
+ return false;
+ }
+ }
+
+ function is_atom() {
+ if ( $this->feed_type == ATOM ) {
+ return $this->feed_version;
+ }
+ else {
+ return false;
+ }
+ }
+
+ function map_attrs($k, $v) {
+ return "$k=\"$v\"";
+ }
+
+ function error( $errormsg, $lvl = E_USER_WARNING ) {
+ // append PHP's error message if track_errors enabled
+ if ( isset($php_errormsg) ) {
+ $errormsg .= " ($php_errormsg)";
+ }
+ if ( MAGPIE_DEBUG ) {
+ trigger_error( $errormsg, $lvl);
+ } else {
+ error_log( $errormsg, 0);
+ }
+ }
+
+}
+
+if ( !function_exists('fetch_rss') ) :
+/**
+ * Build Magpie object based on RSS from URL.
+ *
+ * @since 1.5.0
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL to retrieve feed
+ * @return bool|MagpieRSS false on failure or MagpieRSS object on success.
+ */
+function fetch_rss ($url) {
+ // initialize constants
+ init();
+
+ if ( !isset($url) ) {
+ // error("fetch_rss called without a url");
+ return false;
+ }
+
+ // if cache is disabled
+ if ( !MAGPIE_CACHE_ON ) {
+ // fetch file, and parse it
+ $resp = _fetch_remote_file( $url );
+ if ( is_success( $resp->status ) ) {
+ return _response_to_rss( $resp );
+ }
+ else {
+ // error("Failed to fetch $url and cache is off");
+ return false;
+ }
+ }
+ // else cache is ON
+ else {
+ // Flow
+ // 1. check cache
+ // 2. if there is a hit, make sure it's fresh
+ // 3. if cached obj fails freshness check, fetch remote
+ // 4. if remote fails, return stale object, or error
+
+ $cache = new RSSCache( MAGPIE_CACHE_DIR, MAGPIE_CACHE_AGE );
+
+ if (MAGPIE_DEBUG and $cache->ERROR) {
+ debug($cache->ERROR, E_USER_WARNING);
+ }
+
+ $cache_status = 0; // response of check_cache
+ $request_headers = array(); // HTTP headers to send with fetch
+ $rss = 0; // parsed RSS object
+ $errormsg = 0; // errors, if any
+
+ if (!$cache->ERROR) {
+ // return cache HIT, MISS, or STALE
+ $cache_status = $cache->check_cache( $url );
+ }
+
+ // if object cached, and cache is fresh, return cached obj
+ if ( $cache_status == 'HIT' ) {
+ $rss = $cache->get( $url );
+ if ( isset($rss) and $rss ) {
+ $rss->from_cache = 1;
+ if ( MAGPIE_DEBUG > 1) {
+ debug("MagpieRSS: Cache HIT", E_USER_NOTICE);
+ }
+ return $rss;
+ }
+ }
+
+ // else attempt a conditional get
+
+ // set up headers
+ if ( $cache_status == 'STALE' ) {
+ $rss = $cache->get( $url );
+ if ( isset($rss->etag) and $rss->last_modified ) {
+ $request_headers['If-None-Match'] = $rss->etag;
+ $request_headers['If-Last-Modified'] = $rss->last_modified;
+ }
+ }
+
+ $resp = _fetch_remote_file( $url, $request_headers );
+
+ if (isset($resp) and $resp) {
+ if ($resp->status == '304' ) {
+ // we have the most current copy
+ if ( MAGPIE_DEBUG > 1) {
+ debug("Got 304 for $url");
+ }
+ // reset cache on 304 (at minutillo insistent prodding)
+ $cache->set($url, $rss);
+ return $rss;
+ }
+ elseif ( is_success( $resp->status ) ) {
+ $rss = _response_to_rss( $resp );
+ if ( $rss ) {
+ if (MAGPIE_DEBUG > 1) {
+ debug("Fetch successful");
+ }
+ // add object to cache
+ $cache->set( $url, $rss );
+ return $rss;
+ }
+ }
+ else {
+ $errormsg = "Failed to fetch $url. ";
+ if ( $resp->error ) {
+ # compensate for Snoopy's annoying habbit to tacking
+ # on '\n'
+ $http_error = substr($resp->error, 0, -2);
+ $errormsg .= "(HTTP Error: $http_error)";
+ }
+ else {
+ $errormsg .= "(HTTP Response: " . $resp->response_code .')';
+ }
+ }
+ }
+ else {
+ $errormsg = "Unable to retrieve RSS file for unknown reasons.";
+ }
+
+ // else fetch failed
+
+ // attempt to return cached object
+ if ($rss) {
+ if ( MAGPIE_DEBUG ) {
+ debug("Returning STALE object for $url");
+ }
+ return $rss;
+ }
+
+ // else we totally failed
+ // error( $errormsg );
+
+ return false;
+
+ } // end if ( !MAGPIE_CACHE_ON ) {
+} // end fetch_rss()
+endif;
+
+/**
+ * Retrieve URL headers and content using WP HTTP Request API.
+ *
+ * @since 1.5.0
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL to retrieve
+ * @param array $headers Optional. Headers to send to the URL.
+ * @return Snoopy style response
+ */
+function _fetch_remote_file($url, $headers = "" ) {
+ $resp = wp_safe_remote_request( $url, array( 'headers' => $headers, 'timeout' => MAGPIE_FETCH_TIME_OUT ) );
+ if ( is_wp_error($resp) ) {
+ $error = array_shift($resp->errors);
+
+ $resp = new stdClass;
+ $resp->status = 500;
+ $resp->response_code = 500;
+ $resp->error = $error[0] . "\n"; //\n = Snoopy compatibility
+ return $resp;
+ }
+
+ // Snoopy returns headers unprocessed.
+ // Also note, WP_HTTP lowercases all keys, Snoopy did not.
+ $return_headers = array();
+ foreach ( wp_remote_retrieve_headers( $resp ) as $key => $value ) {
+ if ( !is_array($value) ) {
+ $return_headers[] = "$key: $value";
+ } else {
+ foreach ( $value as $v )
+ $return_headers[] = "$key: $v";
+ }
+ }
+
+ $response = new stdClass;
+ $response->status = wp_remote_retrieve_response_code( $resp );
+ $response->response_code = wp_remote_retrieve_response_code( $resp );
+ $response->headers = $return_headers;
+ $response->results = wp_remote_retrieve_body( $resp );
+
+ return $response;
+}
+
+/**
+ * Retrieve
+ *
+ * @since 1.5.0
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param unknown_type $resp
+ * @return unknown
+ */
+function _response_to_rss ($resp) {
+ $rss = new MagpieRSS( $resp->results );
+
+ // if RSS parsed successfully
+ if ( $rss && (!isset($rss->ERROR) || !$rss->ERROR) ) {
+
+ // find Etag, and Last-Modified
+ foreach( (array) $resp->headers as $h) {
+ // 2003-03-02 - Nicola Asuni (www.tecnick.com) - fixed bug "Undefined offset: 1"
+ if (strpos($h, ": ")) {
+ list($field, $val) = explode(": ", $h, 2);
+ }
+ else {
+ $field = $h;
+ $val = "";
+ }
+
+ if ( $field == 'etag' ) {
+ $rss->etag = $val;
+ }
+
+ if ( $field == 'last-modified' ) {
+ $rss->last_modified = $val;
+ }
+ }
+
+ return $rss;
+ } // else construct error message
+ else {
+ $errormsg = "Failed to parse RSS file.";
+
+ if ($rss) {
+ $errormsg .= " (" . $rss->ERROR . ")";
+ }
+ // error($errormsg);
+
+ return false;
+ } // end if ($rss and !$rss->error)
+}
+
+/**
+ * Set up constants with default values, unless user overrides.
+ *
+ * @since 1.5.0
+ * @package External
+ * @subpackage MagpieRSS
+ */
+function init () {
+ if ( defined('MAGPIE_INITALIZED') ) {
+ return;
+ }
+ else {
+ define('MAGPIE_INITALIZED', 1);
+ }
+
+ if ( !defined('MAGPIE_CACHE_ON') ) {
+ define('MAGPIE_CACHE_ON', 1);
+ }
+
+ if ( !defined('MAGPIE_CACHE_DIR') ) {
+ define('MAGPIE_CACHE_DIR', './cache');
+ }
+
+ if ( !defined('MAGPIE_CACHE_AGE') ) {
+ define('MAGPIE_CACHE_AGE', 60*60); // one hour
+ }
+
+ if ( !defined('MAGPIE_CACHE_FRESH_ONLY') ) {
+ define('MAGPIE_CACHE_FRESH_ONLY', 0);
+ }
+
+ if ( !defined('MAGPIE_DEBUG') ) {
+ define('MAGPIE_DEBUG', 0);
+ }
+
+ if ( !defined('MAGPIE_USER_AGENT') ) {
+ $ua = 'WordPress/' . $GLOBALS['wp_version'];
+
+ if ( MAGPIE_CACHE_ON ) {
+ $ua = $ua . ')';
+ }
+ else {
+ $ua = $ua . '; No cache)';
+ }
+
+ define('MAGPIE_USER_AGENT', $ua);
+ }
+
+ if ( !defined('MAGPIE_FETCH_TIME_OUT') ) {
+ define('MAGPIE_FETCH_TIME_OUT', 2); // 2 second timeout
+ }
+
+ // use gzip encoding to fetch rss files if supported?
+ if ( !defined('MAGPIE_USE_GZIP') ) {
+ define('MAGPIE_USE_GZIP', true);
+ }
+}
+
+function is_info ($sc) {
+ return $sc >= 100 && $sc < 200;
+}
+
+function is_success ($sc) {
+ return $sc >= 200 && $sc < 300;
+}
+
+function is_redirect ($sc) {
+ return $sc >= 300 && $sc < 400;
+}
+
+function is_error ($sc) {
+ return $sc >= 400 && $sc < 600;
+}
+
+function is_client_error ($sc) {
+ return $sc >= 400 && $sc < 500;
+}
+
+function is_server_error ($sc) {
+ return $sc >= 500 && $sc < 600;
+}
+
+class RSSCache {
+ var $BASE_CACHE; // where the cache files are stored
+ var $MAX_AGE = 43200; // when are files stale, default twelve hours
+ var $ERROR = ''; // accumulate error messages
+
+ function RSSCache ($base='', $age='') {
+ $this->BASE_CACHE = WP_CONTENT_DIR . '/cache';
+ if ( $base ) {
+ $this->BASE_CACHE = $base;
+ }
+ if ( $age ) {
+ $this->MAX_AGE = $age;
+ }
+
+ }
+
+/*=======================================================================*\
+ Function: set
+ Purpose: add an item to the cache, keyed on url
+ Input: url from wich the rss file was fetched
+ Output: true on sucess
+\*=======================================================================*/
+ function set ($url, $rss) {
+ $cache_option = 'rss_' . $this->file_name( $url );
+
+ set_transient($cache_option, $rss, $this->MAX_AGE);
+
+ return $cache_option;
+ }
+
+/*=======================================================================*\
+ Function: get
+ Purpose: fetch an item from the cache
+ Input: url from wich the rss file was fetched
+ Output: cached object on HIT, false on MISS
+\*=======================================================================*/
+ function get ($url) {
+ $this->ERROR = "";
+ $cache_option = 'rss_' . $this->file_name( $url );
+
+ if ( ! $rss = get_transient( $cache_option ) ) {
+ $this->debug(
+ "Cache doesn't contain: $url (cache option: $cache_option)"
+ );
+ return 0;
+ }
+
+ return $rss;
+ }
+
+/*=======================================================================*\
+ Function: check_cache
+ Purpose: check a url for membership in the cache
+ and whether the object is older then MAX_AGE (ie. STALE)
+ Input: url from wich the rss file was fetched
+ Output: cached object on HIT, false on MISS
+\*=======================================================================*/
+ function check_cache ( $url ) {
+ $this->ERROR = "";
+ $cache_option = 'rss_' . $this->file_name( $url );
+
+ if ( get_transient($cache_option) ) {
+ // object exists and is current
+ return 'HIT';
+ } else {
+ // object does not exist
+ return 'MISS';
+ }
+ }
+
+/*=======================================================================*\
+ Function: serialize
+\*=======================================================================*/
+ function serialize ( $rss ) {
+ return serialize( $rss );
+ }
+
+/*=======================================================================*\
+ Function: unserialize
+\*=======================================================================*/
+ function unserialize ( $data ) {
+ return unserialize( $data );
+ }
+
+/*=======================================================================*\
+ Function: file_name
+ Purpose: map url to location in cache
+ Input: url from wich the rss file was fetched
+ Output: a file name
+\*=======================================================================*/
+ function file_name ($url) {
+ return md5( $url );
+ }
+
+/*=======================================================================*\
+ Function: error
+ Purpose: register error
+\*=======================================================================*/
+ function error ($errormsg, $lvl=E_USER_WARNING) {
+ // append PHP's error message if track_errors enabled
+ if ( isset($php_errormsg) ) {
+ $errormsg .= " ($php_errormsg)";
+ }
+ $this->ERROR = $errormsg;
+ if ( MAGPIE_DEBUG ) {
+ trigger_error( $errormsg, $lvl);
+ }
+ else {
+ error_log( $errormsg, 0);
+ }
+ }
+ function debug ($debugmsg, $lvl=E_USER_NOTICE) {
+ if ( MAGPIE_DEBUG ) {
+ $this->error("MagpieRSS [debug] $debugmsg", $lvl);
+ }
+ }
+}
+
+if ( !function_exists('parse_w3cdtf') ) :
+function parse_w3cdtf ( $date_str ) {
+
+ # regex to match wc3dtf
+ $pat = "/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(:(\d{2}))?(?:([-+])(\d{2}):?(\d{2})|(Z))?/";
+
+ if ( preg_match( $pat, $date_str, $match ) ) {
+ list( $year, $month, $day, $hours, $minutes, $seconds) =
+ array( $match[1], $match[2], $match[3], $match[4], $match[5], $match[7]);
+
+ # calc epoch for current date assuming GMT
+ $epoch = gmmktime( $hours, $minutes, $seconds, $month, $day, $year);
+
+ $offset = 0;
+ if ( $match[11] == 'Z' ) {
+ # zulu time, aka GMT
+ }
+ else {
+ list( $tz_mod, $tz_hour, $tz_min ) =
+ array( $match[8], $match[9], $match[10]);
+
+ # zero out the variables
+ if ( ! $tz_hour ) { $tz_hour = 0; }
+ if ( ! $tz_min ) { $tz_min = 0; }
+
+ $offset_secs = (($tz_hour*60)+$tz_min)*60;
+
+ # is timezone ahead of GMT? then subtract offset
+ #
+ if ( $tz_mod == '+' ) {
+ $offset_secs = $offset_secs * -1;
+ }
+
+ $offset = $offset_secs;
+ }
+ $epoch = $epoch + $offset;
+ return $epoch;
+ }
+ else {
+ return -1;
+ }
+}
+endif;
+
+if ( !function_exists('wp_rss') ) :
+/**
+ * Display all RSS items in a HTML ordered list.
+ *
+ * @since 1.5.0
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL of feed to display. Will not auto sense feed URL.
+ * @param int $num_items Optional. Number of items to display, default is all.
+ */
+function wp_rss( $url, $num_items = -1 ) {
+ if ( $rss = fetch_rss( $url ) ) {
+ echo '<ul>';
+
+ if ( $num_items !== -1 ) {
+ $rss->items = array_slice( $rss->items, 0, $num_items );
+ }
+
+ foreach ( (array) $rss->items as $item ) {
+ printf(
+ '<li><a href="%1$s" title="%2$s">%3$s</a></li>',
+ esc_url( $item['link'] ),
+ esc_attr( strip_tags( $item['description'] ) ),
+ esc_html( $item['title'] )
+ );
+ }
+
+ echo '</ul>';
+ } else {
+ _e( 'An error has occurred, which probably means the feed is down. Try again later.' );
+ }
+}
+endif;
+
+if ( !function_exists('get_rss') ) :
+/**
+ * Display RSS items in HTML list items.
+ *
+ * You have to specify which HTML list you want, either ordered or unordered
+ * before using the function. You also have to specify how many items you wish
+ * to display. You can't display all of them like you can with wp_rss()
+ * function.
+ *
+ * @since 1.5.0
+ * @package External
+ * @subpackage MagpieRSS
+ *
+ * @param string $url URL of feed to display. Will not auto sense feed URL.
+ * @param int $num_items Optional. Number of items to display, default is all.
+ * @return bool False on failure.
+ */
+function get_rss ($url, $num_items = 5) { // Like get posts, but for RSS
+ $rss = fetch_rss($url);
+ if ( $rss ) {
+ $rss->items = array_slice($rss->items, 0, $num_items);
+ foreach ( (array) $rss->items as $item ) {
+ echo "<li>\n";
+ echo "<a href='$item[link]' title='$item[description]'>";
+ echo esc_html($item['title']);
+ echo "</a><br />\n";
+ echo "</li>\n";
+ }
+ } else {
+ return false;
+ }
+}
+endif;
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
new file mode 100644
index 0000000000..35d8b35553
--- /dev/null
+++ b/src/wp-includes/script-loader.php
@@ -0,0 +1,917 @@
+<?php
+/**
+ * WordPress scripts and styles default loader.
+ *
+ * Most of the functionality that existed here was moved to
+ * {@link http://backpress.automattic.com/ BackPress}. WordPress themes and
+ * plugins will only be concerned about the filters and actions set in this
+ * file.
+ *
+ * Several constants are used to manage the loading, concatenating and compression of scripts and CSS:
+ * define('SCRIPT_DEBUG', true); loads the development (non-minified) versions of all scripts and CSS, and disables compression and concatenation,
+ * define('CONCATENATE_SCRIPTS', false); disables compression and concatenation of scripts and CSS,
+ * define('COMPRESS_SCRIPTS', false); disables compression of scripts,
+ * define('COMPRESS_CSS', false); disables compression of CSS,
+ * define('ENFORCE_GZIP', true); forces gzip for compression (default is deflate).
+ *
+ * The globals $concatenate_scripts, $compress_scripts and $compress_css can be set by plugins
+ * to temporarily override the above settings. Also a compression test is run once and the result is saved
+ * as option 'can_compress_scripts' (0/1). The test will run again if that option is deleted.
+ *
+ * @package WordPress
+ */
+
+/** BackPress: WordPress Dependencies Class */
+require( ABSPATH . WPINC . '/class.wp-dependencies.php' );
+
+/** BackPress: WordPress Scripts Class */
+require( ABSPATH . WPINC . '/class.wp-scripts.php' );
+
+/** BackPress: WordPress Scripts Functions */
+require( ABSPATH . WPINC . '/functions.wp-scripts.php' );
+
+/** BackPress: WordPress Styles Class */
+require( ABSPATH . WPINC . '/class.wp-styles.php' );
+
+/** BackPress: WordPress Styles Functions */
+require( ABSPATH . WPINC . '/functions.wp-styles.php' );
+
+/**
+ * Register all WordPress scripts.
+ *
+ * Localizes some of them.
+ * args order: $scripts->add( 'handle', 'url', 'dependencies', 'query-string', 1 );
+ * when last arg === 1 queues the script for the footer
+ *
+ * @since 2.6.0
+ *
+ * @param object $scripts WP_Scripts object.
+ */
+function wp_default_scripts( &$scripts ) {
+
+ if ( !$guessurl = site_url() )
+ $guessurl = wp_guess_url();
+
+ $scripts->base_url = $guessurl;
+ $scripts->content_url = defined('WP_CONTENT_URL')? WP_CONTENT_URL : '';
+ $scripts->default_version = get_bloginfo( 'version' );
+ $scripts->default_dirs = array('/wp-admin/js/', '/wp-includes/js/');
+
+ $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
+
+ $scripts->add( 'utils', "/wp-includes/js/utils$suffix.js" );
+ did_action( 'init' ) && $scripts->localize( 'utils', 'userSettings', array(
+ 'url' => (string) SITECOOKIEPATH,
+ 'uid' => (string) get_current_user_id(),
+ 'time' => (string) time(),
+ ) );
+
+ $scripts->add( 'common', "/wp-admin/js/common$suffix.js", array('jquery', 'hoverIntent', 'utils'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'common', 'commonL10n', array(
+ 'warnDelete' => __("You are about to permanently delete the selected items.\n 'Cancel' to stop, 'OK' to delete.")
+ ) );
+
+ $scripts->add( 'sack', "/wp-includes/js/tw-sack$suffix.js", array(), '1.6.1', 1 );
+
+ $scripts->add( 'quicktags', "/wp-includes/js/quicktags$suffix.js", array(), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'quicktags', 'quicktagsL10n', array(
+ 'closeAllOpenTags' => esc_attr(__('Close all open tags')),
+ 'closeTags' => esc_attr(__('close tags')),
+ 'enterURL' => __('Enter the URL'),
+ 'enterImageURL' => __('Enter the URL of the image'),
+ 'enterImageDescription' => __('Enter a description of the image'),
+ 'fullscreen' => __('fullscreen'),
+ 'toggleFullscreen' => esc_attr( __('Toggle fullscreen mode') ),
+ 'textdirection' => esc_attr( __('text direction') ),
+ 'toggleTextdirection' => esc_attr( __('Toggle Editor Text Direction') )
+ ) );
+
+ $scripts->add( 'colorpicker', "/wp-includes/js/colorpicker$suffix.js", array('prototype'), '3517m' );
+
+ $scripts->add( 'editor', "/wp-admin/js/editor$suffix.js", array('utils','jquery'), false, 1 );
+
+ $scripts->add( 'wp-fullscreen', "/wp-admin/js/wp-fullscreen$suffix.js", array('jquery'), false, 1 );
+
+ $scripts->add( 'wp-ajax-response', "/wp-includes/js/wp-ajax-response$suffix.js", array('jquery'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-ajax-response', 'wpAjax', array(
+ 'noPerm' => __('You do not have permission to do that.'),
+ 'broken' => __('An unidentified error has occurred.')
+ ) );
+
+ $scripts->add( 'wp-pointer', "/wp-includes/js/wp-pointer$suffix.js", array( 'jquery-ui-widget', 'jquery-ui-position' ), '20111129a', 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-pointer', 'wpPointerL10n', array(
+ 'dismiss' => __('Dismiss'),
+ ) );
+
+ $scripts->add( 'autosave', "/wp-includes/js/autosave$suffix.js", array('schedule', 'wp-ajax-response'), false, 1 );
+
+ $scripts->add( 'heartbeat', "/wp-includes/js/heartbeat$suffix.js", array('jquery'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'heartbeat', 'heartbeatSettings',
+ apply_filters( 'heartbeat_settings', array() )
+ );
+
+ $scripts->add( 'wp-auth-check', "/wp-includes/js/wp-auth-check$suffix.js", array('heartbeat'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-auth-check', 'authcheckL10n', array(
+ 'beforeunload' => __('Your session has expired. You can log in again from this page or go to the login page.'),
+ 'interval' => apply_filters( 'wp_auth_check_interval', 3 * MINUTE_IN_SECONDS ),
+ ) );
+
+ $scripts->add( 'wp-lists', "/wp-includes/js/wp-lists$suffix.js", array( 'wp-ajax-response', 'jquery-color' ), false, 1 );
+
+ // WordPress no longer uses or bundles Prototype or script.aculo.us. These are now pulled from an external source.
+ $scripts->add( 'prototype', '//ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js', array(), '1.7.1');
+ $scripts->add( 'scriptaculous-root', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js', array('prototype'), '1.9.0');
+ $scripts->add( 'scriptaculous-builder', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/builder.js', array('scriptaculous-root'), '1.9.0');
+ $scripts->add( 'scriptaculous-dragdrop', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/dragdrop.js', array('scriptaculous-builder', 'scriptaculous-effects'), '1.9.0');
+ $scripts->add( 'scriptaculous-effects', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/effects.js', array('scriptaculous-root'), '1.9.0');
+ $scripts->add( 'scriptaculous-slider', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/slider.js', array('scriptaculous-effects'), '1.9.0');
+ $scripts->add( 'scriptaculous-sound', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/sound.js', array( 'scriptaculous-root' ), '1.9.0' );
+ $scripts->add( 'scriptaculous-controls', '//ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/controls.js', array('scriptaculous-root'), '1.9.0');
+ $scripts->add( 'scriptaculous', false, array('scriptaculous-dragdrop', 'scriptaculous-slider', 'scriptaculous-controls') );
+
+ // not used in core, replaced by Jcrop.js
+ $scripts->add( 'cropper', '/wp-includes/js/crop/cropper.js', array('scriptaculous-dragdrop') );
+
+ // jQuery
+ $scripts->add( 'jquery', false, array( 'jquery-core', 'jquery-migrate' ), '1.10.2' );
+ $scripts->add( 'jquery-core', '/wp-includes/js/jquery/jquery.js', array(), '1.10.2' );
+ $scripts->add( 'jquery-migrate', "/wp-includes/js/jquery/jquery-migrate$suffix.js", array(), '1.2.1' );
+
+ // full jQuery UI
+ $scripts->add( 'jquery-ui-core', '/wp-includes/js/jquery/ui/jquery.ui.core.min.js', array('jquery'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-core', '/wp-includes/js/jquery/ui/jquery.ui.effect.min.js', array('jquery'), '1.10.3', 1 );
+
+ $scripts->add( 'jquery-effects-blind', '/wp-includes/js/jquery/ui/jquery.ui.effect-blind.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-bounce', '/wp-includes/js/jquery/ui/jquery.ui.effect-bounce.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-clip', '/wp-includes/js/jquery/ui/jquery.ui.effect-clip.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-drop', '/wp-includes/js/jquery/ui/jquery.ui.effect-drop.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-explode', '/wp-includes/js/jquery/ui/jquery.ui.effect-explode.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-fade', '/wp-includes/js/jquery/ui/jquery.ui.effect-fade.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-fold', '/wp-includes/js/jquery/ui/jquery.ui.effect-fold.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-highlight', '/wp-includes/js/jquery/ui/jquery.ui.effect-highlight.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-pulsate', '/wp-includes/js/jquery/ui/jquery.ui.effect-pulsate.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-scale', '/wp-includes/js/jquery/ui/jquery.ui.effect-scale.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-shake', '/wp-includes/js/jquery/ui/jquery.ui.effect-shake.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-slide', '/wp-includes/js/jquery/ui/jquery.ui.effect-slide.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-effects-transfer', '/wp-includes/js/jquery/ui/jquery.ui.effect-transfer.min.js', array('jquery-effects-core'), '1.10.3', 1 );
+
+ $scripts->add( 'jquery-ui-accordion', '/wp-includes/js/jquery/ui/jquery.ui.accordion.min.js', array('jquery-ui-core', 'jquery-ui-widget'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-autocomplete', '/wp-includes/js/jquery/ui/jquery.ui.autocomplete.min.js', array('jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-position', 'jquery-ui-menu'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-button', '/wp-includes/js/jquery/ui/jquery.ui.button.min.js', array('jquery-ui-core', 'jquery-ui-widget'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-datepicker', '/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js', array('jquery-ui-core'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-dialog', '/wp-includes/js/jquery/ui/jquery.ui.dialog.min.js', array('jquery-ui-resizable', 'jquery-ui-draggable', 'jquery-ui-button', 'jquery-ui-position'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-draggable', '/wp-includes/js/jquery/ui/jquery.ui.draggable.min.js', array('jquery-ui-core', 'jquery-ui-mouse'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-droppable', '/wp-includes/js/jquery/ui/jquery.ui.droppable.min.js', array('jquery-ui-draggable'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-menu', '/wp-includes/js/jquery/ui/jquery.ui.menu.min.js', array( 'jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-position' ), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-mouse', '/wp-includes/js/jquery/ui/jquery.ui.mouse.min.js', array('jquery-ui-widget'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-position', '/wp-includes/js/jquery/ui/jquery.ui.position.min.js', array('jquery'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-progressbar', '/wp-includes/js/jquery/ui/jquery.ui.progressbar.min.js', array('jquery-ui-widget'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-resizable', '/wp-includes/js/jquery/ui/jquery.ui.resizable.min.js', array('jquery-ui-core', 'jquery-ui-mouse'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-selectable', '/wp-includes/js/jquery/ui/jquery.ui.selectable.min.js', array('jquery-ui-core', 'jquery-ui-mouse'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-slider', '/wp-includes/js/jquery/ui/jquery.ui.slider.min.js', array('jquery-ui-core', 'jquery-ui-mouse'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-sortable', '/wp-includes/js/jquery/ui/jquery.ui.sortable.min.js', array('jquery-ui-core', 'jquery-ui-mouse'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-spinner', '/wp-includes/js/jquery/ui/jquery.ui.spinner.min.js', array( 'jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-button' ), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-tabs', '/wp-includes/js/jquery/ui/jquery.ui.tabs.min.js', array('jquery-ui-core', 'jquery-ui-widget'), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-tooltip', '/wp-includes/js/jquery/ui/jquery.ui.tooltip.min.js', array( 'jquery-ui-core', 'jquery-ui-widget', 'jquery-ui-position' ), '1.10.3', 1 );
+ $scripts->add( 'jquery-ui-widget', '/wp-includes/js/jquery/ui/jquery.ui.widget.min.js', array('jquery'), '1.10.3', 1 );
+
+ // deprecated, not used in core, most functionality is included in jQuery 1.3
+ $scripts->add( 'jquery-form', "/wp-includes/js/jquery/jquery.form$suffix.js", array('jquery'), '2.73', 1 );
+
+ // jQuery plugins
+ $scripts->add( 'jquery-color', "/wp-includes/js/jquery/jquery.color.min.js", array('jquery'), '2.1.1', 1 );
+ $scripts->add( 'suggest', "/wp-includes/js/jquery/suggest$suffix.js", array('jquery'), '1.1-20110113', 1 );
+ $scripts->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array('jquery'), '20m', 1 );
+ $scripts->add( 'jquery-query', "/wp-includes/js/jquery/jquery.query.js", array('jquery'), '2.1.7', 1 );
+ $scripts->add( 'jquery-serialize-object', "/wp-includes/js/jquery/jquery.serialize-object.js", array('jquery'), '0.2', 1 );
+ $scripts->add( 'jquery-hotkeys', "/wp-includes/js/jquery/jquery.hotkeys$suffix.js", array('jquery'), '0.0.2m', 1 );
+ $scripts->add( 'jquery-table-hotkeys', "/wp-includes/js/jquery/jquery.table-hotkeys$suffix.js", array('jquery', 'jquery-hotkeys'), false, 1 );
+ $scripts->add( 'jquery-touch-punch', "/wp-includes/js/jquery/jquery.ui.touch-punch.js", array('jquery-ui-widget', 'jquery-ui-mouse'), '0.2.2', 1 );
+ $scripts->add( 'jquery-masonry', "/wp-includes/js/jquery/jquery.masonry.min.js", array('jquery'), '2.1.05', 1 );
+
+ $scripts->add( 'thickbox', "/wp-includes/js/thickbox/thickbox.js", array('jquery'), '3.1-20121105', 1 );
+ did_action( 'init' ) && $scripts->localize( 'thickbox', 'thickboxL10n', array(
+ 'next' => __('Next &gt;'),
+ 'prev' => __('&lt; Prev'),
+ 'image' => __('Image'),
+ 'of' => __('of'),
+ 'close' => __('Close'),
+ 'noiframes' => __('This feature requires inline frames. You have iframes disabled or your browser does not support them.'),
+ 'loadingAnimation' => includes_url('js/thickbox/loadingAnimation.gif'),
+ 'closeImage' => includes_url('js/thickbox/tb-close.png')
+ ) );
+
+ $scripts->add( 'jcrop', "/wp-includes/js/jcrop/jquery.Jcrop.min.js", array('jquery'), '0.9.10');
+
+ $scripts->add( 'swfobject', "/wp-includes/js/swfobject.js", array(), '2.2-20120417');
+
+ // common bits for both uploaders
+ $max_upload_size = ( (int) ( $max_up = @ini_get('upload_max_filesize') ) < (int) ( $max_post = @ini_get('post_max_size') ) ) ? $max_up : $max_post;
+
+ if ( empty($max_upload_size) )
+ $max_upload_size = __('not configured');
+
+ // error message for both plupload and swfupload
+ $uploader_l10n = array(
+ 'queue_limit_exceeded' => __('You have attempted to queue too many files.'),
+ 'file_exceeds_size_limit' => __('%s exceeds the maximum upload size for this site.'),
+ 'zero_byte_file' => __('This file is empty. Please try another.'),
+ 'invalid_filetype' => __('This file type is not allowed. Please try another.'),
+ 'not_an_image' => __('This file is not an image. Please try another.'),
+ 'image_memory_exceeded' => __('Memory exceeded. Please try another smaller file.'),
+ 'image_dimensions_exceeded' => __('This is larger than the maximum size. Please try another.'),
+ 'default_error' => __('An error occurred in the upload. Please try again later.'),
+ 'missing_upload_url' => __('There was a configuration error. Please contact the server administrator.'),
+ 'upload_limit_exceeded' => __('You may only upload 1 file.'),
+ 'http_error' => __('HTTP error.'),
+ 'upload_failed' => __('Upload failed.'),
+ 'big_upload_failed' => __('Please try uploading this file with the %1$sbrowser uploader%2$s.'),
+ 'big_upload_queued' => __('%s exceeds the maximum upload size for the multi-file uploader when used in your browser.'),
+ 'io_error' => __('IO error.'),
+ 'security_error' => __('Security error.'),
+ 'file_cancelled' => __('File canceled.'),
+ 'upload_stopped' => __('Upload stopped.'),
+ 'dismiss' => __('Dismiss'),
+ 'crunching' => __('Crunching&hellip;'),
+ 'deleted' => __('moved to the trash.'),
+ 'error_uploading' => __('&#8220;%s&#8221; has failed to upload.')
+ );
+
+ $scripts->add( 'plupload', '/wp-includes/js/plupload/plupload.js', array(), '1.5.7' );
+ $scripts->add( 'plupload-html5', '/wp-includes/js/plupload/plupload.html5.js', array('plupload'), '1.5.7' );
+ $scripts->add( 'plupload-flash', '/wp-includes/js/plupload/plupload.flash.js', array('plupload'), '1.5.7' );
+ $scripts->add( 'plupload-silverlight', '/wp-includes/js/plupload/plupload.silverlight.js', array('plupload'), '1.5.7' );
+ $scripts->add( 'plupload-html4', '/wp-includes/js/plupload/plupload.html4.js', array('plupload'), '1.5.7' );
+
+ // cannot use the plupload.full.js, as it loads browserplus init JS from Yahoo
+ $scripts->add( 'plupload-all', false, array('plupload', 'plupload-html5', 'plupload-flash', 'plupload-silverlight', 'plupload-html4'), '1.5.7' );
+
+ $scripts->add( 'plupload-handlers', "/wp-includes/js/plupload/handlers$suffix.js", array('plupload-all', 'jquery') );
+ did_action( 'init' ) && $scripts->localize( 'plupload-handlers', 'pluploadL10n', $uploader_l10n );
+
+ $scripts->add( 'wp-plupload', "/wp-includes/js/plupload/wp-plupload$suffix.js", array('plupload-all', 'jquery', 'json2', 'media-models'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-plupload', 'pluploadL10n', $uploader_l10n );
+
+ // keep 'swfupload' for back-compat.
+ $scripts->add( 'swfupload', '/wp-includes/js/swfupload/swfupload.js', array(), '2201-20110113');
+ $scripts->add( 'swfupload-swfobject', '/wp-includes/js/swfupload/plugins/swfupload.swfobject.js', array('swfupload', 'swfobject'), '2201a');
+ $scripts->add( 'swfupload-queue', '/wp-includes/js/swfupload/plugins/swfupload.queue.js', array('swfupload'), '2201');
+ $scripts->add( 'swfupload-speed', '/wp-includes/js/swfupload/plugins/swfupload.speed.js', array('swfupload'), '2201');
+ $scripts->add( 'swfupload-all', false, array('swfupload', 'swfupload-swfobject', 'swfupload-queue'), '2201');
+ $scripts->add( 'swfupload-handlers', "/wp-includes/js/swfupload/handlers$suffix.js", array('swfupload-all', 'jquery'), '2201-20110524');
+ did_action( 'init' ) && $scripts->localize( 'swfupload-handlers', 'swfuploadL10n', $uploader_l10n );
+
+ $scripts->add( 'comment-reply', "/wp-includes/js/comment-reply$suffix.js" );
+
+ $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2011-02-23');
+
+ $scripts->add( 'underscore', '/wp-includes/js/underscore.min.js', array(), '1.4.4', 1 );
+ $scripts->add( 'backbone', '/wp-includes/js/backbone.min.js', array('underscore','jquery'), '1.0.0', 1 );
+
+ $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array('underscore', 'jquery'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-util', '_wpUtilSettings', array(
+ 'ajax' => array(
+ 'url' => admin_url( 'admin-ajax.php', 'relative' ),
+ ),
+ ) );
+
+ $scripts->add( 'wp-backbone', "/wp-includes/js/wp-backbone$suffix.js", array('backbone', 'wp-util'), false, 1 );
+
+ $scripts->add( 'revisions', "/wp-admin/js/revisions$suffix.js", array( 'wp-backbone', 'jquery-ui-slider', 'hoverIntent' ), false, 1 );
+
+ $scripts->add( 'imgareaselect', "/wp-includes/js/imgareaselect/jquery.imgareaselect$suffix.js", array('jquery'), '0.9.8', 1 );
+
+ $scripts->add( 'mediaelement', "/wp-includes/js/mediaelement/mediaelement-and-player.min.js", array('jquery'), '2.13.0', 1 );
+ did_action( 'init' ) && $scripts->localize( 'mediaelement', 'mejsL10n', array(
+ 'language' => get_bloginfo( 'language' ),
+ 'strings' => array(
+ 'Close' => __( 'Close' ),
+ 'Fullscreen' => __( 'Fullscreen' ),
+ 'Download File' => __( 'Download File' ),
+ 'Download Video' => __( 'Download Video' ),
+ 'Play/Pause' => __( 'Play/Pause' ),
+ 'Mute Toggle' => __( 'Mute Toggle' ),
+ 'None' => __( 'None' ),
+ 'Turn off Fullscreen' => __( 'Turn off Fullscreen' ),
+ 'Go Fullscreen' => __( 'Go Fullscreen' ),
+ 'Unmute' => __( 'Unmute' ),
+ 'Mute' => __( 'Mute' ),
+ 'Captions/Subtitles' => __( 'Captions/Subtitles' )
+ ),
+ ) );
+
+
+ $scripts->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement.js", array('mediaelement'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-mediaelement', '_wpmejsSettings', array(
+ 'pluginPath' => includes_url( 'js/mediaelement/', 'relative' ),
+ ) );
+
+ $scripts->add( 'password-strength-meter', "/wp-admin/js/password-strength-meter$suffix.js", array('jquery'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'password-strength-meter', 'pwsL10n', array(
+ 'empty' => __('Strength indicator'),
+ 'short' => __('Very weak'),
+ 'bad' => __('Weak'),
+ /* translators: password strength */
+ 'good' => _x('Medium', 'password strength'),
+ 'strong' => __('Strong'),
+ 'mismatch' => __('Mismatch')
+ ) );
+
+ $scripts->add( 'user-profile', "/wp-admin/js/user-profile$suffix.js", array( 'jquery', 'password-strength-meter' ), false, 1 );
+
+ $scripts->add( 'user-suggest', "/wp-admin/js/user-suggest$suffix.js", array( 'jquery-ui-autocomplete' ), false, 1 );
+
+ $scripts->add( 'admin-bar', "/wp-includes/js/admin-bar$suffix.js", array(), false, 1 );
+
+ $scripts->add( 'wplink', "/wp-includes/js/wplink$suffix.js", array( 'jquery', 'wpdialogs' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wplink', 'wpLinkL10n', array(
+ 'title' => __('Insert/edit link'),
+ 'update' => __('Update'),
+ 'save' => __('Add Link'),
+ 'noTitle' => __('(no title)'),
+ 'noMatchesFound' => __('No matches found.')
+ ) );
+
+ $scripts->add( 'wpdialogs', "/wp-includes/js/tinymce/plugins/wpdialogs/js/wpdialog$suffix.js", array( 'jquery-ui-dialog' ), false, 1 );
+
+ $scripts->add( 'wpdialogs-popup', "/wp-includes/js/tinymce/plugins/wpdialogs/js/popup$suffix.js", array( 'wpdialogs' ), false, 1 );
+
+ $scripts->add( 'word-count', "/wp-admin/js/word-count$suffix.js", array( 'jquery' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'word-count', 'wordCountL10n', array(
+ /* translators: If your word count is based on single characters (East Asian characters),
+ enter 'characters'. Otherwise, enter 'words'. Do not translate into your own language. */
+ 'type' => 'characters' == _x( 'words', 'word count: words or characters?' ) ? 'c' : 'w',
+ ) );
+
+ $scripts->add( 'media-upload', "/wp-admin/js/media-upload$suffix.js", array( 'thickbox', 'shortcode' ), false, 1 );
+
+ $scripts->add( 'hoverIntent', "/wp-includes/js/hoverIntent$suffix.js", array('jquery'), 'r7', 1 );
+
+ $scripts->add( 'customize-base', "/wp-includes/js/customize-base$suffix.js", array( 'jquery', 'json2' ), false, 1 );
+ $scripts->add( 'customize-loader', "/wp-includes/js/customize-loader$suffix.js", array( 'customize-base' ), false, 1 );
+ $scripts->add( 'customize-preview', "/wp-includes/js/customize-preview$suffix.js", array( 'customize-base' ), false, 1 );
+ $scripts->add( 'customize-controls', "/wp-admin/js/customize-controls$suffix.js", array( 'customize-base' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'customize-controls', '_wpCustomizeControlsL10n', array(
+ 'activate' => __( 'Save &amp; Activate' ),
+ 'save' => __( 'Save &amp; Publish' ),
+ 'saved' => __( 'Saved' ),
+ 'cancel' => __( 'Cancel' ),
+ 'close' => __( 'Close' ),
+ 'cheatin' => __( 'Cheatin&#8217; uh?' ),
+
+ // Used for overriding the file types allowed in plupload.
+ 'allowedFiles' => __( 'Allowed Files' ),
+ ) );
+
+ $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 );
+
+ $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 );
+ $scripts->add( 'media-models', "/wp-includes/js/media-models$suffix.js", array( 'wp-backbone' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'media-models', '_wpMediaModelsL10n', array(
+ 'settings' => array(
+ 'ajaxurl' => admin_url( 'admin-ajax.php', 'relative' ),
+ 'post' => array( 'id' => 0 ),
+ ),
+ ) );
+
+ // To enqueue media-views or media-editor, call wp_enqueue_media().
+ // Both rely on numerous settings, styles, and templates to operate correctly.
+ $scripts->add( 'media-views', "/wp-includes/js/media-views$suffix.js", array( 'utils', 'media-models', 'wp-plupload', 'jquery-ui-sortable' ), false, 1 );
+ $scripts->add( 'media-editor', "/wp-includes/js/media-editor$suffix.js", array( 'shortcode', 'media-views' ), false, 1 );
+ $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models' ), false, 1 );
+
+ if ( is_admin() ) {
+ $scripts->add( 'ajaxcat', "/wp-admin/js/cat$suffix.js", array( 'wp-lists' ) );
+ $scripts->add_data( 'ajaxcat', 'group', 1 );
+ did_action( 'init' ) && $scripts->localize( 'ajaxcat', 'catL10n', array(
+ 'add' => esc_attr(__('Add')),
+ 'how' => __('Separate multiple categories with commas.')
+ ) );
+
+ $scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array('jquery', 'wp-ajax-response'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'admin-tags', 'tagsl10n', array(
+ 'noPerm' => __('You do not have permission to do that.'),
+ 'broken' => __('An unidentified error has occurred.')
+ ));
+
+ $scripts->add( 'admin-comments', "/wp-admin/js/edit-comments$suffix.js", array('wp-lists', 'quicktags', 'jquery-query'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'admin-comments', 'adminCommentsL10n', array(
+ 'hotkeys_highlight_first' => isset($_GET['hotkeys_highlight_first']),
+ 'hotkeys_highlight_last' => isset($_GET['hotkeys_highlight_last']),
+ 'replyApprove' => __( 'Approve and Reply' ),
+ 'reply' => __( 'Reply' )
+ ) );
+
+ $scripts->add( 'xfn', "/wp-admin/js/xfn$suffix.js", array('jquery'), false, 1 );
+
+ $scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array('jquery-ui-sortable'), false, 1 );
+
+ $scripts->add( 'post', "/wp-admin/js/post$suffix.js", array('suggest', 'wp-lists', 'postbox', 'heartbeat'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'post', 'postL10n', array(
+ 'ok' => __('OK'),
+ 'cancel' => __('Cancel'),
+ 'publishOn' => __('Publish on:'),
+ 'publishOnFuture' => __('Schedule for:'),
+ 'publishOnPast' => __('Published on:'),
+ /* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
+ 'dateFormat' => __('%1$s %2$s, %3$s @ %4$s : %5$s'),
+ 'showcomm' => __('Show more comments'),
+ 'endcomm' => __('No more comments found.'),
+ 'publish' => __('Publish'),
+ 'schedule' => __('Schedule'),
+ 'update' => __('Update'),
+ 'savePending' => __('Save as Pending'),
+ 'saveDraft' => __('Save Draft'),
+ 'private' => __('Private'),
+ 'public' => __('Public'),
+ 'publicSticky' => __('Public, Sticky'),
+ 'password' => __('Password Protected'),
+ 'privatelyPublished' => __('Privately Published'),
+ 'published' => __('Published'),
+ 'comma' => _x( ',', 'tag delimiter' ),
+ ) );
+
+ $scripts->add( 'link', "/wp-admin/js/link$suffix.js", array( 'wp-lists', 'postbox' ), false, 1 );
+
+ $scripts->add( 'comment', "/wp-admin/js/comment$suffix.js", array( 'jquery', 'postbox' ) );
+ $scripts->add_data( 'comment', 'group', 1 );
+ did_action( 'init' ) && $scripts->localize( 'comment', 'commentL10n', array(
+ 'submittedOn' => __('Submitted on:')
+ ) );
+
+ $scripts->add( 'admin-gallery', "/wp-admin/js/gallery$suffix.js", array( 'jquery-ui-sortable' ) );
+
+ $scripts->add( 'admin-widgets', "/wp-admin/js/widgets$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable' ), false, 1 );
+
+ $scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'jquery' ), false, 1 );
+
+ // @todo: Core no longer uses theme-preview.js. Remove?
+ $scripts->add( 'theme-preview', "/wp-admin/js/theme-preview$suffix.js", array( 'thickbox', 'jquery' ), false, 1 );
+
+ $scripts->add( 'inline-edit-post', "/wp-admin/js/inline-edit-post$suffix.js", array( 'jquery', 'suggest', 'heartbeat' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'inline-edit-post', 'inlineEditL10n', array(
+ 'error' => __('Error while saving the changes.'),
+ 'ntdeltitle' => __('Remove From Bulk Edit'),
+ 'notitle' => __('(no title)'),
+ 'comma' => _x( ',', 'tag delimiter' ),
+ ) );
+
+ $scripts->add( 'inline-edit-tax', "/wp-admin/js/inline-edit-tax$suffix.js", array( 'jquery' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'inline-edit-tax', 'inlineEditL10n', array(
+ 'error' => __('Error while saving the changes.')
+ ) );
+
+ $scripts->add( 'plugin-install', "/wp-admin/js/plugin-install$suffix.js", array( 'jquery', 'thickbox' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'plugin-install', 'plugininstallL10n', array(
+ 'plugin_information' => __('Plugin Information:'),
+ 'ays' => __('Are you sure you want to install this plugin?')
+ ) );
+
+ $scripts->add( 'farbtastic', '/wp-admin/js/farbtastic.js', array('jquery'), '1.2' );
+
+ $scripts->add( 'iris', '/wp-admin/js/iris.min.js', array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), false, 1 );
+ $scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'wp-color-picker', 'wpColorPickerL10n', array(
+ 'clear' => __( 'Clear' ),
+ 'defaultString' => __( 'Default' ),
+ 'pick' => __( 'Select Color' ),
+ 'current' => __( 'Current Color' ),
+ ) );
+
+ $scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox' ), false, 1 );
+
+ $scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
+
+ $scripts->add( 'media', "/wp-admin/js/media$suffix.js", array( 'jquery-ui-draggable' ), false, 1 );
+
+ $scripts->add( 'image-edit', "/wp-admin/js/image-edit$suffix.js", array('jquery', 'json2', 'imgareaselect'), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'image-edit', 'imageEditL10n', array(
+ 'error' => __( 'Could not load the preview image. Please reload the page and try again.' )
+ ));
+
+ $scripts->add( 'set-post-thumbnail', "/wp-admin/js/set-post-thumbnail$suffix.js", array( 'jquery' ), false, 1 );
+ did_action( 'init' ) && $scripts->localize( 'set-post-thumbnail', 'setPostThumbnailL10n', array(
+ 'setThumbnail' => __( 'Use as featured image' ),
+ 'saving' => __( 'Saving...' ),
+ 'error' => __( 'Could not set that as the thumbnail image. Try a different attachment.' ),
+ 'done' => __( 'Done' )
+ ) );
+
+ // Navigation Menus
+ $scripts->add( 'nav-menu', "/wp-admin/js/nav-menu$suffix.js", array( 'jquery-ui-sortable', 'jquery-ui-draggable', 'jquery-ui-droppable', 'wp-lists', 'postbox' ) );
+ did_action( 'init' ) && $scripts->localize( 'nav-menu', 'navMenuL10n', array(
+ 'noResultsFound' => _x('No results found.', 'search results'),
+ 'warnDeleteMenu' => __( "You are about to permanently delete this menu. \n 'Cancel' to stop, 'OK' to delete." ),
+ 'saveAlert' => __('The changes you made will be lost if you navigate away from this page.')
+ ) );
+
+ $scripts->add( 'custom-header', "/wp-admin/js/custom-header.js", array( 'jquery-masonry' ), false, 1 );
+ $scripts->add( 'custom-background', "/wp-admin/js/custom-background$suffix.js", array( 'wp-color-picker', 'media-views' ), false, 1 );
+ $scripts->add( 'media-gallery', "/wp-admin/js/media-gallery$suffix.js", array('jquery'), false, 1 );
+ }
+}
+
+/**
+ * Assign default styles to $styles object.
+ *
+ * Nothing is returned, because the $styles parameter is passed by reference.
+ * Meaning that whatever object is passed will be updated without having to
+ * reassign the variable that was passed back to the same value. This saves
+ * memory.
+ *
+ * Adding default styles is not the only task, it also assigns the base_url
+ * property, the default version, and text direction for the object.
+ *
+ * @since 2.6.0
+ *
+ * @param object $styles
+ */
+function wp_default_styles( &$styles ) {
+
+ if ( ! $guessurl = site_url() )
+ $guessurl = wp_guess_url();
+
+ $styles->base_url = $guessurl;
+ $styles->content_url = defined('WP_CONTENT_URL')? WP_CONTENT_URL : '';
+ $styles->default_version = get_bloginfo( 'version' );
+ $styles->text_direction = function_exists( 'is_rtl' ) && is_rtl() ? 'rtl' : 'ltr';
+ $styles->default_dirs = array('/wp-admin/', '/wp-includes/css/');
+
+ $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
+
+ $rtl_styles = array( 'wp-admin', 'ie', 'media', 'admin-bar', 'customize-controls', 'media-views', 'wp-color-picker' );
+ // Any rtl stylesheets that don't have a .min version
+ $no_suffix = array( 'farbtastic' );
+
+ $styles->add( 'wp-admin', "/wp-admin/css/wp-admin$suffix.css" );
+
+ $styles->add( 'ie', "/wp-admin/css/ie$suffix.css" );
+ $styles->add_data( 'ie', 'conditional', 'lte IE 7' );
+
+ // Register "meta" stylesheet for admin colors. All colors-* style sheets should have the same version string.
+ $styles->add( 'colors', true, array('wp-admin', 'buttons') );
+
+ // do not refer to these directly, the right one is queued by the above "meta" colors handle
+ $styles->add( 'colors-fresh', "/wp-admin/css/colors-fresh$suffix.css", array('wp-admin', 'buttons') );
+ $styles->add( 'colors-classic', "/wp-admin/css/colors-classic$suffix.css", array('wp-admin', 'buttons') );
+
+ $styles->add( 'media', "/wp-admin/css/media$suffix.css" );
+ $styles->add( 'install', "/wp-admin/css/install$suffix.css", array('buttons') );
+ $styles->add( 'thickbox', '/wp-includes/js/thickbox/thickbox.css', array(), '20121105' );
+ $styles->add( 'farbtastic', '/wp-admin/css/farbtastic.css', array(), '1.3u1' );
+ $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" );
+ $styles->add( 'jcrop', "/wp-includes/js/jcrop/jquery.Jcrop.min.css", array(), '0.9.10' );
+ $styles->add( 'imgareaselect', '/wp-includes/js/imgareaselect/imgareaselect.css', array(), '0.9.8' );
+ $styles->add( 'admin-bar', "/wp-includes/css/admin-bar$suffix.css" );
+ $styles->add( 'wp-jquery-ui-dialog', "/wp-includes/css/jquery-ui-dialog$suffix.css" );
+ $styles->add( 'editor-buttons', "/wp-includes/css/editor$suffix.css" );
+ $styles->add( 'wp-pointer', "/wp-includes/css/wp-pointer$suffix.css" );
+ $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie' ) );
+ $styles->add( 'media-views', "/wp-includes/css/media-views$suffix.css", array( 'buttons' ) );
+ $styles->add( 'buttons', "/wp-includes/css/buttons$suffix.css" );
+ $styles->add( 'wp-auth-check', "/wp-includes/css/wp-auth-check$suffix.css" );
+
+ $styles->add( 'mediaelement', "/wp-includes/js/mediaelement/mediaelementplayer.min.css", array(), '2.13.0' );
+ $styles->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement.css", array( 'mediaelement' ) );
+
+ foreach ( $rtl_styles as $rtl_style ) {
+ $styles->add_data( $rtl_style, 'rtl', true );
+ if ( $suffix && ! in_array( $rtl_style, $no_suffix ) )
+ $styles->add_data( $rtl_style, 'suffix', $suffix );
+ }
+}
+
+/**
+ * Reorder JavaScript scripts array to place prototype before jQuery.
+ *
+ * @since 2.3.1
+ *
+ * @param array $js_array JavaScript scripts array
+ * @return array Reordered array, if needed.
+ */
+function wp_prototype_before_jquery( $js_array ) {
+ if ( false === $prototype = array_search( 'prototype', $js_array, true ) )
+ return $js_array;
+
+ if ( false === $jquery = array_search( 'jquery', $js_array, true ) )
+ return $js_array;
+
+ if ( $prototype < $jquery )
+ return $js_array;
+
+ unset($js_array[$prototype]);
+
+ array_splice( $js_array, $jquery, 0, 'prototype' );
+
+ return $js_array;
+}
+
+/**
+ * Load localized data on print rather than initialization.
+ *
+ * These localizations require information that may not be loaded even by init.
+ *
+ * @since 2.5.0
+ */
+function wp_just_in_time_script_localization() {
+
+ wp_localize_script( 'autosave', 'autosaveL10n', array(
+ 'autosaveInterval' => AUTOSAVE_INTERVAL,
+ 'savingText' => __('Saving Draft&#8230;'),
+ 'saveAlert' => __('The changes you made will be lost if you navigate away from this page.'),
+ 'blog_id' => get_current_blog_id(),
+ ) );
+
+}
+
+/**
+ * Administration Screen CSS for changing the styles.
+ *
+ * If installing the 'wp-admin/' directory will be replaced with './'.
+ *
+ * The $_wp_admin_css_colors global manages the Administration Screens CSS
+ * stylesheet that is loaded. The option that is set is 'admin_color' and is the
+ * color and key for the array. The value for the color key is an object with
+ * a 'url' parameter that has the URL path to the CSS file.
+ *
+ * The query from $src parameter will be appended to the URL that is given from
+ * the $_wp_admin_css_colors array value URL.
+ *
+ * @since 2.6.0
+ * @uses $_wp_admin_css_colors
+ *
+ * @param string $src Source URL.
+ * @param string $handle Either 'colors' or 'colors-rtl'.
+ * @return string URL path to CSS stylesheet for Administration Screens.
+ */
+function wp_style_loader_src( $src, $handle ) {
+ if ( defined('WP_INSTALLING') )
+ return preg_replace( '#^wp-admin/#', './', $src );
+
+ if ( 'colors' == $handle || 'colors-rtl' == $handle ) {
+ global $_wp_admin_css_colors;
+ $color = get_user_option('admin_color');
+
+ if ( empty($color) || !isset($_wp_admin_css_colors[$color]) )
+ $color = 'fresh';
+
+ $color = $_wp_admin_css_colors[$color];
+ $parsed = parse_url( $src );
+ $url = $color->url;
+
+ if ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG )
+ $url = preg_replace( '/.min.css$|.min.css(?=\?)/', '.css', $url );
+
+ if ( isset($parsed['query']) && $parsed['query'] ) {
+ wp_parse_str( $parsed['query'], $qv );
+ $url = add_query_arg( $qv, $url );
+ }
+
+ return $url;
+ }
+
+ return $src;
+}
+
+/**
+ * Prints the script queue in the HTML head on admin pages.
+ *
+ * Postpones the scripts that were queued for the footer.
+ * print_footer_scripts() is called in the footer to print these scripts.
+ *
+ * @since 2.8
+ * @see wp_print_scripts()
+ */
+function print_head_scripts() {
+ global $wp_scripts, $concatenate_scripts;
+
+ if ( ! did_action('wp_print_scripts') )
+ do_action('wp_print_scripts');
+
+ if ( !is_a($wp_scripts, 'WP_Scripts') )
+ $wp_scripts = new WP_Scripts();
+
+ script_concat_settings();
+ $wp_scripts->do_concat = $concatenate_scripts;
+ $wp_scripts->do_head_items();
+
+ if ( apply_filters('print_head_scripts', true) )
+ _print_scripts();
+
+ $wp_scripts->reset();
+ return $wp_scripts->done;
+}
+
+/**
+ * Prints the scripts that were queued for the footer or too late for the HTML head.
+ *
+ * @since 2.8
+ */
+function print_footer_scripts() {
+ global $wp_scripts, $concatenate_scripts;
+
+ if ( !is_a($wp_scripts, 'WP_Scripts') )
+ return array(); // No need to run if not instantiated.
+
+ script_concat_settings();
+ $wp_scripts->do_concat = $concatenate_scripts;
+ $wp_scripts->do_footer_items();
+
+ if ( apply_filters('print_footer_scripts', true) )
+ _print_scripts();
+
+ $wp_scripts->reset();
+ return $wp_scripts->done;
+}
+
+/**
+ * @internal use
+ */
+function _print_scripts() {
+ global $wp_scripts, $compress_scripts;
+
+ $zip = $compress_scripts ? 1 : 0;
+ if ( $zip && defined('ENFORCE_GZIP') && ENFORCE_GZIP )
+ $zip = 'gzip';
+
+ if ( $concat = trim( $wp_scripts->concat, ', ' ) ) {
+
+ if ( !empty($wp_scripts->print_code) ) {
+ echo "\n<script type='text/javascript'>\n";
+ echo "/* <![CDATA[ */\n"; // not needed in HTML 5
+ echo $wp_scripts->print_code;
+ echo "/* ]]> */\n";
+ echo "</script>\n";
+ }
+
+ $concat = str_split( $concat, 128 );
+ $concat = 'load%5B%5D=' . implode( '&load%5B%5D=', $concat );
+
+ $src = $wp_scripts->base_url . "/wp-admin/load-scripts.php?c={$zip}&" . $concat . '&ver=' . $wp_scripts->default_version;
+ echo "<script type='text/javascript' src='" . esc_attr($src) . "'></script>\n";
+ }
+
+ if ( !empty($wp_scripts->print_html) )
+ echo $wp_scripts->print_html;
+}
+
+/**
+ * Prints the script queue in the HTML head on the front end.
+ *
+ * Postpones the scripts that were queued for the footer.
+ * wp_print_footer_scripts() is called in the footer to print these scripts.
+ *
+ * @since 2.8
+ */
+function wp_print_head_scripts() {
+ if ( ! did_action('wp_print_scripts') )
+ do_action('wp_print_scripts');
+
+ global $wp_scripts;
+
+ if ( !is_a($wp_scripts, 'WP_Scripts') )
+ return array(); // no need to run if nothing is queued
+
+ return print_head_scripts();
+}
+
+/**
+ * Private, for use in *_footer_scripts hooks
+ *
+ * @since 3.3.0
+ */
+function _wp_footer_scripts() {
+ print_late_styles();
+ print_footer_scripts();
+}
+
+/**
+ * Hooks to print the scripts and styles in the footer.
+ *
+ * @since 2.8
+ */
+function wp_print_footer_scripts() {
+ do_action('wp_print_footer_scripts');
+}
+
+/**
+ * Wrapper for do_action('wp_enqueue_scripts')
+ *
+ * Allows plugins to queue scripts for the front end using wp_enqueue_script().
+ * Runs first in wp_head() where all is_home(), is_page(), etc. functions are available.
+ *
+ * @since 2.8
+ */
+function wp_enqueue_scripts() {
+ do_action('wp_enqueue_scripts');
+}
+
+/**
+ * Prints the styles queue in the HTML head on admin pages.
+ *
+ * @since 2.8
+ */
+function print_admin_styles() {
+ global $wp_styles, $concatenate_scripts, $compress_css;
+
+ if ( !is_a($wp_styles, 'WP_Styles') )
+ $wp_styles = new WP_Styles();
+
+ script_concat_settings();
+ $wp_styles->do_concat = $concatenate_scripts;
+ $zip = $compress_css ? 1 : 0;
+ if ( $zip && defined('ENFORCE_GZIP') && ENFORCE_GZIP )
+ $zip = 'gzip';
+
+ $wp_styles->do_items(false);
+
+ if ( apply_filters('print_admin_styles', true) )
+ _print_styles();
+
+ $wp_styles->reset();
+ return $wp_styles->done;
+}
+
+/**
+ * Prints the styles that were queued too late for the HTML head.
+ *
+ * @since 3.3.0
+ */
+function print_late_styles() {
+ global $wp_styles, $concatenate_scripts;
+
+ if ( !is_a($wp_styles, 'WP_Styles') )
+ return;
+
+ $wp_styles->do_concat = $concatenate_scripts;
+ $wp_styles->do_footer_items();
+
+ if ( apply_filters('print_late_styles', true) )
+ _print_styles();
+
+ $wp_styles->reset();
+ return $wp_styles->done;
+}
+
+/**
+ * @internal use
+ */
+function _print_styles() {
+ global $wp_styles, $compress_css;
+
+ $zip = $compress_css ? 1 : 0;
+ if ( $zip && defined('ENFORCE_GZIP') && ENFORCE_GZIP )
+ $zip = 'gzip';
+
+ if ( !empty($wp_styles->concat) ) {
+ $dir = $wp_styles->text_direction;
+ $ver = $wp_styles->default_version;
+ $href = $wp_styles->base_url . "/wp-admin/load-styles.php?c={$zip}&dir={$dir}&load=" . trim($wp_styles->concat, ', ') . '&ver=' . $ver;
+ echo "<link rel='stylesheet' href='" . esc_attr($href) . "' type='text/css' media='all' />\n";
+
+ if ( !empty($wp_styles->print_code) ) {
+ echo "<style type='text/css'>\n";
+ echo $wp_styles->print_code;
+ echo "\n</style>\n";
+ }
+ }
+
+ if ( !empty($wp_styles->print_html) )
+ echo $wp_styles->print_html;
+}
+
+/**
+ * Determine the concatenation and compression settings for scripts and styles.
+ *
+ * @since 2.8
+ */
+function script_concat_settings() {
+ global $concatenate_scripts, $compress_scripts, $compress_css;
+
+ $compressed_output = ( ini_get('zlib.output_compression') || 'ob_gzhandler' == ini_get('output_handler') );
+
+ if ( ! isset($concatenate_scripts) ) {
+ $concatenate_scripts = defined('CONCATENATE_SCRIPTS') ? CONCATENATE_SCRIPTS : true;
+ if ( ! is_admin() || ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) )
+ $concatenate_scripts = false;
+ }
+
+ if ( ! isset($compress_scripts) ) {
+ $compress_scripts = defined('COMPRESS_SCRIPTS') ? COMPRESS_SCRIPTS : true;
+ if ( $compress_scripts && ( ! get_site_option('can_compress_scripts') || $compressed_output ) )
+ $compress_scripts = false;
+ }
+
+ if ( ! isset($compress_css) ) {
+ $compress_css = defined('COMPRESS_CSS') ? COMPRESS_CSS : true;
+ if ( $compress_css && ( ! get_site_option('can_compress_scripts') || $compressed_output ) )
+ $compress_css = false;
+ }
+}
+
+add_action( 'wp_default_scripts', 'wp_default_scripts' );
+add_filter( 'wp_print_scripts', 'wp_just_in_time_script_localization' );
+add_filter( 'print_scripts_array', 'wp_prototype_before_jquery' );
+
+add_action( 'wp_default_styles', 'wp_default_styles' );
+add_filter( 'style_loader_src', 'wp_style_loader_src', 10, 2 );
diff --git a/src/wp-includes/shortcodes.php b/src/wp-includes/shortcodes.php
new file mode 100644
index 0000000000..a40959491b
--- /dev/null
+++ b/src/wp-includes/shortcodes.php
@@ -0,0 +1,377 @@
+<?php
+/**
+ * WordPress API for creating bbcode like tags or what WordPress calls
+ * "shortcodes." The tag and attribute parsing or regular expression code is
+ * based on the Textpattern tag parser.
+ *
+ * A few examples are below:
+ *
+ * [shortcode /]
+ * [shortcode foo="bar" baz="bing" /]
+ * [shortcode foo="bar"]content[/shortcode]
+ *
+ * Shortcode tags support attributes and enclosed content, but does not entirely
+ * support inline shortcodes in other shortcodes. You will have to call the
+ * shortcode parser in your function to account for that.
+ *
+ * {@internal
+ * Please be aware that the above note was made during the beta of WordPress 2.6
+ * and in the future may not be accurate. Please update the note when it is no
+ * longer the case.}}
+ *
+ * To apply shortcode tags to content:
+ *
+ * <code>
+ * $out = do_shortcode($content);
+ * </code>
+ *
+ * @link http://codex.wordpress.org/Shortcode_API
+ *
+ * @package WordPress
+ * @subpackage Shortcodes
+ * @since 2.5
+ */
+
+/**
+ * Container for storing shortcode tags and their hook to call for the shortcode
+ *
+ * @since 2.5
+ * @name $shortcode_tags
+ * @var array
+ * @global array $shortcode_tags
+ */
+$shortcode_tags = array();
+
+/**
+ * Add hook for shortcode tag.
+ *
+ * There can only be one hook for each shortcode. Which means that if another
+ * plugin has a similar shortcode, it will override yours or yours will override
+ * theirs depending on which order the plugins are included and/or ran.
+ *
+ * Simplest example of a shortcode tag using the API:
+ *
+ * <code>
+ * // [footag foo="bar"]
+ * function footag_func($atts) {
+ * return "foo = {$atts[foo]}";
+ * }
+ * add_shortcode('footag', 'footag_func');
+ * </code>
+ *
+ * Example with nice attribute defaults:
+ *
+ * <code>
+ * // [bartag foo="bar"]
+ * function bartag_func($atts) {
+ * extract(shortcode_atts(array(
+ * 'foo' => 'no foo',
+ * 'baz' => 'default baz',
+ * ), $atts));
+ *
+ * return "foo = {$foo}";
+ * }
+ * add_shortcode('bartag', 'bartag_func');
+ * </code>
+ *
+ * Example with enclosed content:
+ *
+ * <code>
+ * // [baztag]content[/baztag]
+ * function baztag_func($atts, $content='') {
+ * return "content = $content";
+ * }
+ * add_shortcode('baztag', 'baztag_func');
+ * </code>
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @param string $tag Shortcode tag to be searched in post content.
+ * @param callable $func Hook to run when shortcode is found.
+ */
+function add_shortcode($tag, $func) {
+ global $shortcode_tags;
+
+ if ( is_callable($func) )
+ $shortcode_tags[$tag] = $func;
+}
+
+/**
+ * Removes hook for shortcode.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @param string $tag shortcode tag to remove hook for.
+ */
+function remove_shortcode($tag) {
+ global $shortcode_tags;
+
+ unset($shortcode_tags[$tag]);
+}
+
+/**
+ * Clear all shortcodes.
+ *
+ * This function is simple, it clears all of the shortcode tags by replacing the
+ * shortcodes global by a empty array. This is actually a very efficient method
+ * for removing all shortcodes.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ */
+function remove_all_shortcodes() {
+ global $shortcode_tags;
+
+ $shortcode_tags = array();
+}
+
+/**
+ * Whether a registered shortcode exists named $tag
+ *
+ * @since 3.6.0
+ *
+ * @global array $shortcode_tags
+ * @param string $tag
+ * @return boolean
+ */
+function shortcode_exists( $tag ) {
+ global $shortcode_tags;
+ return array_key_exists( $tag, $shortcode_tags );
+}
+
+/**
+ * Whether the passed content contains the specified shortcode
+ *
+ * @since 3.6.0
+ *
+ * @global array $shortcode_tags
+ * @param string $tag
+ * @return boolean
+ */
+function has_shortcode( $content, $tag ) {
+ if ( shortcode_exists( $tag ) ) {
+ preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );
+ if ( empty( $matches ) )
+ return false;
+
+ foreach ( $matches as $shortcode ) {
+ if ( $tag === $shortcode[2] )
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Search content for shortcodes and filter shortcodes through their hooks.
+ *
+ * If there are no shortcode tags defined, then the content will be returned
+ * without any filtering. This might cause issues when plugins are disabled but
+ * the shortcode will still show up in the post or content.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ * @uses get_shortcode_regex() Gets the search pattern for searching shortcodes.
+ *
+ * @param string $content Content to search for shortcodes
+ * @return string Content with shortcodes filtered out.
+ */
+function do_shortcode($content) {
+ global $shortcode_tags;
+
+ if (empty($shortcode_tags) || !is_array($shortcode_tags))
+ return $content;
+
+ $pattern = get_shortcode_regex();
+ return preg_replace_callback( "/$pattern/s", 'do_shortcode_tag', $content );
+}
+
+/**
+ * Retrieve the shortcode regular expression for searching.
+ *
+ * The regular expression combines the shortcode tags in the regular expression
+ * in a regex class.
+ *
+ * The regular expression contains 6 different sub matches to help with parsing.
+ *
+ * 1 - An extra [ to allow for escaping shortcodes with double [[]]
+ * 2 - The shortcode name
+ * 3 - The shortcode argument list
+ * 4 - The self closing /
+ * 5 - The content of a shortcode when it wraps some content.
+ * 6 - An extra ] to allow for escaping shortcodes with double [[]]
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @return string The shortcode search regular expression
+ */
+function get_shortcode_regex() {
+ global $shortcode_tags;
+ $tagnames = array_keys($shortcode_tags);
+ $tagregexp = join( '|', array_map('preg_quote', $tagnames) );
+
+ // WARNING! Do not change this regex without changing do_shortcode_tag() and strip_shortcode_tag()
+ // Also, see shortcode_unautop() and shortcode.js.
+ return
+ '\\[' // Opening bracket
+ . '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
+ . "($tagregexp)" // 2: Shortcode name
+ . '(?![\\w-])' // Not followed by word character or hyphen
+ . '(' // 3: Unroll the loop: Inside the opening shortcode tag
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash
+ . '(?:'
+ . '\\/(?!\\])' // A forward slash not followed by a closing bracket
+ . '[^\\]\\/]*' // Not a closing bracket or forward slash
+ . ')*?'
+ . ')'
+ . '(?:'
+ . '(\\/)' // 4: Self closing tag ...
+ . '\\]' // ... and closing bracket
+ . '|'
+ . '\\]' // Closing bracket
+ . '(?:'
+ . '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
+ . '[^\\[]*+' // Not an opening bracket
+ . '(?:'
+ . '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag
+ . '[^\\[]*+' // Not an opening bracket
+ . ')*+'
+ . ')'
+ . '\\[\\/\\2\\]' // Closing shortcode tag
+ . ')?'
+ . ')'
+ . '(\\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
+}
+
+/**
+ * Regular Expression callable for do_shortcode() for calling shortcode hook.
+ * @see get_shortcode_regex for details of the match array contents.
+ *
+ * @since 2.5
+ * @access private
+ * @uses $shortcode_tags
+ *
+ * @param array $m Regular expression match array
+ * @return mixed False on failure.
+ */
+function do_shortcode_tag( $m ) {
+ global $shortcode_tags;
+
+ // allow [[foo]] syntax for escaping a tag
+ if ( $m[1] == '[' && $m[6] == ']' ) {
+ return substr($m[0], 1, -1);
+ }
+
+ $tag = $m[2];
+ $attr = shortcode_parse_atts( $m[3] );
+
+ if ( isset( $m[5] ) ) {
+ // enclosing tag - extra parameter
+ return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, $m[5], $tag ) . $m[6];
+ } else {
+ // self-closing tag
+ return $m[1] . call_user_func( $shortcode_tags[$tag], $attr, null, $tag ) . $m[6];
+ }
+}
+
+/**
+ * Retrieve all attributes from the shortcodes tag.
+ *
+ * The attributes list has the attribute name as the key and the value of the
+ * attribute as the value in the key/value pair. This allows for easier
+ * retrieval of the attributes, since all attributes have to be known.
+ *
+ * @since 2.5
+ *
+ * @param string $text
+ * @return array List of attributes and their value.
+ */
+function shortcode_parse_atts($text) {
+ $atts = array();
+ $pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
+ $text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text);
+ if ( preg_match_all($pattern, $text, $match, PREG_SET_ORDER) ) {
+ foreach ($match as $m) {
+ if (!empty($m[1]))
+ $atts[strtolower($m[1])] = stripcslashes($m[2]);
+ elseif (!empty($m[3]))
+ $atts[strtolower($m[3])] = stripcslashes($m[4]);
+ elseif (!empty($m[5]))
+ $atts[strtolower($m[5])] = stripcslashes($m[6]);
+ elseif (isset($m[7]) and strlen($m[7]))
+ $atts[] = stripcslashes($m[7]);
+ elseif (isset($m[8]))
+ $atts[] = stripcslashes($m[8]);
+ }
+ } else {
+ $atts = ltrim($text);
+ }
+ return $atts;
+}
+
+/**
+ * Combine user attributes with known attributes and fill in defaults when needed.
+ *
+ * The pairs should be considered to be all of the attributes which are
+ * supported by the caller and given as a list. The returned attributes will
+ * only contain the attributes in the $pairs list.
+ *
+ * If the $atts list has unsupported attributes, then they will be ignored and
+ * removed from the final returned list.
+ *
+ * @since 2.5
+ *
+ * @param array $pairs Entire list of supported attributes and their defaults.
+ * @param array $atts User defined attributes in shortcode tag.
+ * @param string $shortcode Optional. The name of the shortcode, provided for context to enable filtering
+ * @return array Combined and filtered attribute list.
+ */
+function shortcode_atts( $pairs, $atts, $shortcode = '' ) {
+ $atts = (array)$atts;
+ $out = array();
+ foreach($pairs as $name => $default) {
+ if ( array_key_exists($name, $atts) )
+ $out[$name] = $atts[$name];
+ else
+ $out[$name] = $default;
+ }
+
+ if ( $shortcode )
+ $out = apply_filters( "shortcode_atts_{$shortcode}", $out, $pairs, $atts );
+
+ return $out;
+}
+
+/**
+ * Remove all shortcode tags from the given content.
+ *
+ * @since 2.5
+ * @uses $shortcode_tags
+ *
+ * @param string $content Content to remove shortcode tags.
+ * @return string Content without shortcode tags.
+ */
+function strip_shortcodes( $content ) {
+ global $shortcode_tags;
+
+ if (empty($shortcode_tags) || !is_array($shortcode_tags))
+ return $content;
+
+ $pattern = get_shortcode_regex();
+
+ return preg_replace_callback( "/$pattern/s", 'strip_shortcode_tag', $content );
+}
+
+function strip_shortcode_tag( $m ) {
+ // allow [[foo]] syntax for escaping a tag
+ if ( $m[1] == '[' && $m[6] == ']' ) {
+ return substr($m[0], 1, -1);
+ }
+
+ return $m[1] . $m[6];
+}
+
+add_filter('the_content', 'do_shortcode', 11); // AFTER wpautop()
diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php
new file mode 100644
index 0000000000..955369e228
--- /dev/null
+++ b/src/wp-includes/taxonomy.php
@@ -0,0 +1,3388 @@
+<?php
+/**
+ * Taxonomy API
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ */
+
+//
+// Taxonomy Registration
+//
+
+/**
+ * Creates the initial taxonomies.
+ *
+ * This function fires twice: in wp-settings.php before plugins are loaded (for
+ * backwards compatibility reasons), and again on the 'init' action. We must avoid
+ * registering rewrite rules before the 'init' action.
+ */
+function create_initial_taxonomies() {
+ global $wp_rewrite;
+
+ if ( ! did_action( 'init' ) ) {
+ $rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false );
+ } else {
+ $post_format_base = apply_filters( 'post_format_rewrite_base', 'type' );
+ $rewrite = array(
+ 'category' => array(
+ 'hierarchical' => true,
+ 'slug' => get_option('category_base') ? get_option('category_base') : 'category',
+ 'with_front' => ! get_option('category_base') || $wp_rewrite->using_index_permalinks(),
+ 'ep_mask' => EP_CATEGORIES,
+ ),
+ 'post_tag' => array(
+ 'slug' => get_option('tag_base') ? get_option('tag_base') : 'tag',
+ 'with_front' => ! get_option('tag_base') || $wp_rewrite->using_index_permalinks(),
+ 'ep_mask' => EP_TAGS,
+ ),
+ 'post_format' => $post_format_base ? array( 'slug' => $post_format_base ) : false,
+ );
+ }
+
+ register_taxonomy( 'category', 'post', array(
+ 'hierarchical' => true,
+ 'query_var' => 'category_name',
+ 'rewrite' => $rewrite['category'],
+ 'public' => true,
+ 'show_ui' => true,
+ 'show_admin_column' => true,
+ '_builtin' => true,
+ ) );
+
+ register_taxonomy( 'post_tag', 'post', array(
+ 'hierarchical' => false,
+ 'query_var' => 'tag',
+ 'rewrite' => $rewrite['post_tag'],
+ 'public' => true,
+ 'show_ui' => true,
+ 'show_admin_column' => true,
+ '_builtin' => true,
+ ) );
+
+ register_taxonomy( 'nav_menu', 'nav_menu_item', array(
+ 'public' => false,
+ 'hierarchical' => false,
+ 'labels' => array(
+ 'name' => __( 'Navigation Menus' ),
+ 'singular_name' => __( 'Navigation Menu' ),
+ ),
+ 'query_var' => false,
+ 'rewrite' => false,
+ 'show_ui' => false,
+ '_builtin' => true,
+ 'show_in_nav_menus' => false,
+ ) );
+
+ register_taxonomy( 'link_category', 'link', array(
+ 'hierarchical' => false,
+ 'labels' => array(
+ 'name' => __( 'Link Categories' ),
+ 'singular_name' => __( 'Link Category' ),
+ 'search_items' => __( 'Search Link Categories' ),
+ 'popular_items' => null,
+ 'all_items' => __( 'All Link Categories' ),
+ 'edit_item' => __( 'Edit Link Category' ),
+ 'update_item' => __( 'Update Link Category' ),
+ 'add_new_item' => __( 'Add New Link Category' ),
+ 'new_item_name' => __( 'New Link Category Name' ),
+ 'separate_items_with_commas' => null,
+ 'add_or_remove_items' => null,
+ 'choose_from_most_used' => null,
+ ),
+ 'capabilities' => array(
+ 'manage_terms' => 'manage_links',
+ 'edit_terms' => 'manage_links',
+ 'delete_terms' => 'manage_links',
+ 'assign_terms' => 'manage_links',
+ ),
+ 'query_var' => false,
+ 'rewrite' => false,
+ 'public' => false,
+ 'show_ui' => false,
+ '_builtin' => true,
+ ) );
+
+ register_taxonomy( 'post_format', 'post', array(
+ 'public' => true,
+ 'hierarchical' => false,
+ 'labels' => array(
+ 'name' => _x( 'Format', 'post format' ),
+ 'singular_name' => _x( 'Format', 'post format' ),
+ ),
+ 'query_var' => true,
+ 'rewrite' => $rewrite['post_format'],
+ 'show_ui' => false,
+ '_builtin' => true,
+ 'show_in_nav_menus' => current_theme_supports( 'post-formats' ),
+ ) );
+}
+add_action( 'init', 'create_initial_taxonomies', 0 ); // highest priority
+
+/**
+ * Get a list of registered taxonomy objects.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.0.0
+ * @uses $wp_taxonomies
+ * @see register_taxonomy
+ *
+ * @param array $args An array of key => value arguments to match against the taxonomy objects.
+ * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
+ * @param string $operator The logical operation to perform. 'or' means only one element
+ * from the array needs to match; 'and' means all elements must match. The default is 'and'.
+ * @return array A list of taxonomy names or objects
+ */
+function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
+ global $wp_taxonomies;
+
+ $field = ('names' == $output) ? 'name' : false;
+
+ return wp_filter_object_list($wp_taxonomies, $args, $operator, $field);
+}
+
+/**
+ * Return all of the taxonomy names that are of $object_type.
+ *
+ * It appears that this function can be used to find all of the names inside of
+ * $wp_taxonomies global variable.
+ *
+ * <code><?php $taxonomies = get_object_taxonomies('post'); ?></code> Should
+ * result in <code>Array('category', 'post_tag')</code>
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wp_taxonomies
+ *
+ * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts)
+ * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
+ * @return array The names of all taxonomy of $object_type.
+ */
+function get_object_taxonomies($object, $output = 'names') {
+ global $wp_taxonomies;
+
+ if ( is_object($object) ) {
+ if ( $object->post_type == 'attachment' )
+ return get_attachment_taxonomies($object);
+ $object = $object->post_type;
+ }
+
+ $object = (array) $object;
+
+ $taxonomies = array();
+ foreach ( (array) $wp_taxonomies as $tax_name => $tax_obj ) {
+ if ( array_intersect($object, (array) $tax_obj->object_type) ) {
+ if ( 'names' == $output )
+ $taxonomies[] = $tax_name;
+ else
+ $taxonomies[ $tax_name ] = $tax_obj;
+ }
+ }
+
+ return $taxonomies;
+}
+
+/**
+ * Retrieves the taxonomy object of $taxonomy.
+ *
+ * The get_taxonomy function will first check that the parameter string given
+ * is a taxonomy object and if it is, it will return it.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wp_taxonomies
+ * @uses taxonomy_exists() Checks whether taxonomy exists
+ *
+ * @param string $taxonomy Name of taxonomy object to return
+ * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
+ */
+function get_taxonomy( $taxonomy ) {
+ global $wp_taxonomies;
+
+ if ( ! taxonomy_exists( $taxonomy ) )
+ return false;
+
+ return $wp_taxonomies[$taxonomy];
+}
+
+/**
+ * Checks that the taxonomy name exists.
+ *
+ * Formerly is_taxonomy(), introduced in 2.3.0.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.0.0
+ *
+ * @uses $wp_taxonomies
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @return bool Whether the taxonomy exists.
+ */
+function taxonomy_exists( $taxonomy ) {
+ global $wp_taxonomies;
+
+ return isset( $wp_taxonomies[$taxonomy] );
+}
+
+/**
+ * Whether the taxonomy object is hierarchical.
+ *
+ * Checks to make sure that the taxonomy is an object first. Then Gets the
+ * object, and finally returns the hierarchical value in the object.
+ *
+ * A false return value might also mean that the taxonomy does not exist.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses taxonomy_exists() Checks whether taxonomy exists
+ * @uses get_taxonomy() Used to get the taxonomy object
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @return bool Whether the taxonomy is hierarchical
+ */
+function is_taxonomy_hierarchical($taxonomy) {
+ if ( ! taxonomy_exists($taxonomy) )
+ return false;
+
+ $taxonomy = get_taxonomy($taxonomy);
+ return $taxonomy->hierarchical;
+}
+
+/**
+ * Create or modify a taxonomy object. Do not use before init.
+ *
+ * A simple function for creating or modifying a taxonomy object based on the
+ * parameters given. The function will accept an array (third optional
+ * parameter), along with strings for the taxonomy name and another string for
+ * the object type.
+ *
+ * Nothing is returned, so expect error maybe or use taxonomy_exists() to check
+ * whether taxonomy exists.
+ *
+ * Optional $args contents:
+ *
+ * label - Name of the taxonomy shown in the menu. Usually plural. If not set, labels['name'] will be used.
+ *
+ * hierarchical - has some defined purpose at other parts of the API and is a
+ * boolean value.
+ *
+ * update_count_callback - works much like a hook, in that it will be called when the count is updated.
+ * Defaults to _update_post_term_count() for taxonomies attached to post types, which then confirms
+ * that the objects are published before counting them.
+ * Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links.
+ *
+ * rewrite - false to prevent rewrite, or array('slug'=>$slug) to customize
+ * permastruct; default will use $taxonomy as slug.
+ *
+ * query_var - false to prevent queries, or string to customize query var
+ * (?$query_var=$term); default will use $taxonomy as query var.
+ *
+ * public - If the taxonomy should be publicly queryable; //@TODO not implemented.
+ * defaults to true.
+ *
+ * show_ui - If the WordPress UI admin tags UI should apply to this taxonomy;
+ * defaults to public.
+ *
+ * show_in_nav_menus - true makes this taxonomy available for selection in navigation menus.
+ * Defaults to public.
+ *
+ * show_tagcloud - false to prevent the taxonomy being listed in the Tag Cloud Widget;
+ * defaults to show_ui which defaults to public.
+ *
+ * labels - An array of labels for this taxonomy. You can see accepted values in {@link get_taxonomy_labels()}. By default tag labels are used for non-hierarchical types and category labels for hierarchical ones.
+ *
+ * description - A short descriptive summary of what the taxonomy is for. Defaults to blank.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wp_taxonomies Inserts new taxonomy object into the list
+ * @uses $wp Adds query vars
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @param array|string $object_type Name of the object type for the taxonomy object.
+ * @param array|string $args See above description for the two keys values.
+ * @return null|WP_Error WP_Error if errors, otherwise null.
+ */
+function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
+ global $wp_taxonomies, $wp;
+
+ if ( ! is_array($wp_taxonomies) )
+ $wp_taxonomies = array();
+
+ $defaults = array(
+ 'hierarchical' => false,
+ 'update_count_callback' => '',
+ 'rewrite' => true,
+ 'query_var' => $taxonomy,
+ 'public' => true,
+ 'show_ui' => null,
+ 'show_tagcloud' => null,
+ '_builtin' => false,
+ 'labels' => array(),
+ 'capabilities' => array(),
+ 'show_in_nav_menus' => null,
+ 'description' => '',
+ );
+ $args = wp_parse_args($args, $defaults);
+
+ if ( strlen( $taxonomy ) > 32 )
+ return new WP_Error( 'taxonomy_too_long', __( 'Taxonomies cannot exceed 32 characters in length' ) );
+
+ if ( false !== $args['query_var'] && !empty($wp) ) {
+ if ( true === $args['query_var'] )
+ $args['query_var'] = $taxonomy;
+ else
+ $args['query_var'] = sanitize_title_with_dashes($args['query_var']);
+ $wp->add_query_var($args['query_var']);
+ }
+
+ if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option('permalink_structure') ) ) {
+ $args['rewrite'] = wp_parse_args($args['rewrite'], array(
+ 'slug' => sanitize_title_with_dashes($taxonomy),
+ 'with_front' => true,
+ 'hierarchical' => false,
+ 'ep_mask' => EP_NONE,
+ ));
+
+ if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] )
+ $tag = '(.+?)';
+ else
+ $tag = '([^/]+)';
+
+ add_rewrite_tag( "%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=" );
+ add_permastruct( $taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite'] );
+ }
+
+ if ( is_null($args['show_ui']) )
+ $args['show_ui'] = $args['public'];
+
+ // Whether to show this type in nav-menus.php. Defaults to the setting for public.
+ if ( null === $args['show_in_nav_menus'] )
+ $args['show_in_nav_menus'] = $args['public'];
+
+ if ( is_null($args['show_tagcloud']) )
+ $args['show_tagcloud'] = $args['show_ui'];
+
+ $default_caps = array(
+ 'manage_terms' => 'manage_categories',
+ 'edit_terms' => 'manage_categories',
+ 'delete_terms' => 'manage_categories',
+ 'assign_terms' => 'edit_posts',
+ );
+ $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] );
+ unset( $args['capabilities'] );
+
+ $args['name'] = $taxonomy;
+ $args['object_type'] = array_unique( (array)$object_type );
+
+ $args['labels'] = get_taxonomy_labels( (object) $args );
+ $args['label'] = $args['labels']->name;
+
+ $wp_taxonomies[$taxonomy] = (object) $args;
+
+ // register callback handling for metabox
+ add_filter('wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term');
+
+ do_action( 'registered_taxonomy', $taxonomy, $object_type, $args );
+}
+
+/**
+ * Builds an object with all taxonomy labels out of a taxonomy object
+ *
+ * Accepted keys of the label array in the taxonomy object:
+ * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories
+ * - singular_name - name for one object of this taxonomy. Default is Tag/Category
+ * - search_items - Default is Search Tags/Search Categories
+ * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags
+ * - all_items - Default is All Tags/All Categories
+ * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category
+ * - parent_item_colon - The same as <code>parent_item</code>, but with colon <code>:</code> in the end
+ * - edit_item - Default is Edit Tag/Edit Category
+ * - view_item - Default is View Tag/View Category
+ * - update_item - Default is Update Tag/Update Category
+ * - add_new_item - Default is Add New Tag/Add New Category
+ * - new_item_name - Default is New Tag Name/New Category Name
+ * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box.
+ * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled.
+ * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box.
+ * - not_found - This string isn't used on hierarchical taxonomies. Default is "No tags found", used in the meta box.
+ *
+ * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
+ *
+ * @since 3.0.0
+ * @param object $tax Taxonomy object
+ * @return object object with all the labels as member variables
+ */
+
+function get_taxonomy_labels( $tax ) {
+ if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) )
+ $tax->labels['separate_items_with_commas'] = $tax->helps;
+
+ if ( isset( $tax->no_tagcloud ) && empty( $tax->labels['not_found'] ) )
+ $tax->labels['not_found'] = $tax->no_tagcloud;
+
+ $nohier_vs_hier_defaults = array(
+ 'name' => array( _x( 'Tags', 'taxonomy general name' ), _x( 'Categories', 'taxonomy general name' ) ),
+ 'singular_name' => array( _x( 'Tag', 'taxonomy singular name' ), _x( 'Category', 'taxonomy singular name' ) ),
+ 'search_items' => array( __( 'Search Tags' ), __( 'Search Categories' ) ),
+ 'popular_items' => array( __( 'Popular Tags' ), null ),
+ 'all_items' => array( __( 'All Tags' ), __( 'All Categories' ) ),
+ 'parent_item' => array( null, __( 'Parent Category' ) ),
+ 'parent_item_colon' => array( null, __( 'Parent Category:' ) ),
+ 'edit_item' => array( __( 'Edit Tag' ), __( 'Edit Category' ) ),
+ 'view_item' => array( __( 'View Tag' ), __( 'View Category' ) ),
+ 'update_item' => array( __( 'Update Tag' ), __( 'Update Category' ) ),
+ 'add_new_item' => array( __( 'Add New Tag' ), __( 'Add New Category' ) ),
+ 'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ),
+ 'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ),
+ 'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
+ 'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
+ 'not_found' => array( __( 'No tags found.' ), null ),
+ );
+ $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
+
+ return _get_custom_object_labels( $tax, $nohier_vs_hier_defaults );
+}
+
+/**
+ * Add an already registered taxonomy to an object type.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.0.0
+ * @uses $wp_taxonomies Modifies taxonomy object
+ *
+ * @param string $taxonomy Name of taxonomy object
+ * @param string $object_type Name of the object type
+ * @return bool True if successful, false if not
+ */
+function register_taxonomy_for_object_type( $taxonomy, $object_type) {
+ global $wp_taxonomies;
+
+ if ( !isset($wp_taxonomies[$taxonomy]) )
+ return false;
+
+ if ( ! get_post_type_object($object_type) )
+ return false;
+
+ if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
+ $wp_taxonomies[$taxonomy]->object_type[] = $object_type;
+
+ return true;
+}
+
+//
+// Term API
+//
+
+/**
+ * Retrieve object_ids of valid taxonomy and term.
+ *
+ * The strings of $taxonomies must exist before this function will continue. On
+ * failure of finding a valid taxonomy, it will return an WP_Error class, kind
+ * of like Exceptions in PHP 5, except you can't catch them. Even so, you can
+ * still test for the WP_Error class and get the error message.
+ *
+ * The $terms aren't checked the same as $taxonomies, but still need to exist
+ * for $object_ids to be returned.
+ *
+ * It is possible to change the order that object_ids is returned by either
+ * using PHP sort family functions or using the database by using $args with
+ * either ASC or DESC array. The value should be in the key named 'order'.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses wp_parse_args() Creates an array from string $args.
+ *
+ * @param int|array $term_ids Term id or array of term ids of terms that will be used
+ * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names
+ * @param array|string $args Change the order of the object_ids, either ASC or DESC
+ * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success
+ * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
+ */
+function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
+ global $wpdb;
+
+ if ( ! is_array( $term_ids ) )
+ $term_ids = array( $term_ids );
+
+ if ( ! is_array( $taxonomies ) )
+ $taxonomies = array( $taxonomies );
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ if ( ! taxonomy_exists( $taxonomy ) )
+ return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
+ }
+
+ $defaults = array( 'order' => 'ASC' );
+ $args = wp_parse_args( $args, $defaults );
+ extract( $args, EXTR_SKIP );
+
+ $order = ( 'desc' == strtolower( $order ) ) ? 'DESC' : 'ASC';
+
+ $term_ids = array_map('intval', $term_ids );
+
+ $taxonomies = "'" . implode( "', '", $taxonomies ) . "'";
+ $term_ids = "'" . implode( "', '", $term_ids ) . "'";
+
+ $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order");
+
+ if ( ! $object_ids )
+ return array();
+
+ return $object_ids;
+}
+
+/**
+ * Given a taxonomy query, generates SQL to be appended to a main query.
+ *
+ * @since 3.1.0
+ *
+ * @see WP_Tax_Query
+ *
+ * @param array $tax_query A compact tax query
+ * @param string $primary_table
+ * @param string $primary_id_column
+ * @return array
+ */
+function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) {
+ $tax_query_obj = new WP_Tax_Query( $tax_query );
+ return $tax_query_obj->get_sql( $primary_table, $primary_id_column );
+}
+
+/**
+ * Container class for a multiple taxonomy query.
+ *
+ * @since 3.1.0
+ */
+class WP_Tax_Query {
+
+ /**
+ * List of taxonomy queries. A single taxonomy query is an associative array:
+ * - 'taxonomy' string The taxonomy being queried
+ * - 'terms' string|array The list of terms
+ * - 'field' string (optional) Which term field is being used.
+ * Possible values: 'term_id', 'slug' or 'name'
+ * Default: 'term_id'
+ * - 'operator' string (optional)
+ * Possible values: 'AND', 'IN' or 'NOT IN'.
+ * Default: 'IN'
+ * - 'include_children' bool (optional) Whether to include child terms.
+ * Default: true
+ *
+ * @since 3.1.0
+ * @access public
+ * @var array
+ */
+ public $queries = array();
+
+ /**
+ * The relation between the queries. Can be one of 'AND' or 'OR'.
+ *
+ * @since 3.1.0
+ * @access public
+ * @var string
+ */
+ public $relation;
+
+ /**
+ * Standard response when the query should not return any rows.
+ *
+ * @since 3.2.0
+ * @access private
+ * @var string
+ */
+ private static $no_results = array( 'join' => '', 'where' => ' AND 0 = 1' );
+
+ /**
+ * Constructor.
+ *
+ * Parses a compact tax query and sets defaults.
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @param array $tax_query A compact tax query:
+ * array(
+ * 'relation' => 'OR',
+ * array(
+ * 'taxonomy' => 'tax1',
+ * 'terms' => array( 'term1', 'term2' ),
+ * 'field' => 'slug',
+ * ),
+ * array(
+ * 'taxonomy' => 'tax2',
+ * 'terms' => array( 'term-a', 'term-b' ),
+ * 'field' => 'slug',
+ * ),
+ * )
+ */
+ public function __construct( $tax_query ) {
+ if ( isset( $tax_query['relation'] ) && strtoupper( $tax_query['relation'] ) == 'OR' ) {
+ $this->relation = 'OR';
+ } else {
+ $this->relation = 'AND';
+ }
+
+ $defaults = array(
+ 'taxonomy' => '',
+ 'terms' => array(),
+ 'include_children' => true,
+ 'field' => 'term_id',
+ 'operator' => 'IN',
+ );
+
+ foreach ( $tax_query as $query ) {
+ if ( ! is_array( $query ) )
+ continue;
+
+ $query = array_merge( $defaults, $query );
+
+ $query['terms'] = (array) $query['terms'];
+
+ $this->queries[] = $query;
+ }
+ }
+
+ /**
+ * Generates SQL clauses to be appended to a main query.
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @param string $primary_table
+ * @param string $primary_id_column
+ * @return array
+ */
+ public function get_sql( $primary_table, $primary_id_column ) {
+ global $wpdb;
+
+ $join = '';
+ $where = array();
+ $i = 0;
+ $count = count( $this->queries );
+
+ foreach ( $this->queries as $index => $query ) {
+ $this->clean_query( $query );
+
+ if ( is_wp_error( $query ) )
+ return self::$no_results;
+
+ extract( $query );
+
+ if ( 'IN' == $operator ) {
+
+ if ( empty( $terms ) ) {
+ if ( 'OR' == $this->relation ) {
+ if ( ( $index + 1 === $count ) && empty( $where ) )
+ return self::$no_results;
+ continue;
+ } else {
+ return self::$no_results;
+ }
+ }
+
+ $terms = implode( ',', $terms );
+
+ $alias = $i ? 'tt' . $i : $wpdb->term_relationships;
+
+ $join .= " INNER JOIN $wpdb->term_relationships";
+ $join .= $i ? " AS $alias" : '';
+ $join .= " ON ($primary_table.$primary_id_column = $alias.object_id)";
+
+ $where[] = "$alias.term_taxonomy_id $operator ($terms)";
+ } elseif ( 'NOT IN' == $operator ) {
+
+ if ( empty( $terms ) )
+ continue;
+
+ $terms = implode( ',', $terms );
+
+ $where[] = "$primary_table.$primary_id_column NOT IN (
+ SELECT object_id
+ FROM $wpdb->term_relationships
+ WHERE term_taxonomy_id IN ($terms)
+ )";
+ } elseif ( 'AND' == $operator ) {
+
+ if ( empty( $terms ) )
+ continue;
+
+ $num_terms = count( $terms );
+
+ $terms = implode( ',', $terms );
+
+ $where[] = "(
+ SELECT COUNT(1)
+ FROM $wpdb->term_relationships
+ WHERE term_taxonomy_id IN ($terms)
+ AND object_id = $primary_table.$primary_id_column
+ ) = $num_terms";
+ }
+
+ $i++;
+ }
+
+ if ( ! empty( $where ) )
+ $where = ' AND ( ' . implode( " $this->relation ", $where ) . ' )';
+ else
+ $where = '';
+
+ return compact( 'join', 'where' );
+ }
+
+ /**
+ * Validates a single query.
+ *
+ * @since 3.2.0
+ * @access private
+ *
+ * @param array &$query The single query
+ */
+ private function clean_query( &$query ) {
+ if ( ! taxonomy_exists( $query['taxonomy'] ) ) {
+ $query = new WP_Error( 'Invalid taxonomy' );
+ return;
+ }
+
+ $query['terms'] = array_unique( (array) $query['terms'] );
+
+ if ( is_taxonomy_hierarchical( $query['taxonomy'] ) && $query['include_children'] ) {
+ $this->transform_query( $query, 'term_id' );
+
+ if ( is_wp_error( $query ) )
+ return;
+
+ $children = array();
+ foreach ( $query['terms'] as $term ) {
+ $children = array_merge( $children, get_term_children( $term, $query['taxonomy'] ) );
+ $children[] = $term;
+ }
+ $query['terms'] = $children;
+ }
+
+ $this->transform_query( $query, 'term_taxonomy_id' );
+ }
+
+ /**
+ * Transforms a single query, from one field to another.
+ *
+ * @since 3.2.0
+ *
+ * @param array &$query The single query
+ * @param string $resulting_field The resulting field
+ */
+ public function transform_query( &$query, $resulting_field ) {
+ global $wpdb;
+
+ if ( empty( $query['terms'] ) )
+ return;
+
+ if ( $query['field'] == $resulting_field )
+ return;
+
+ $resulting_field = sanitize_key( $resulting_field );
+
+ switch ( $query['field'] ) {
+ case 'slug':
+ case 'name':
+ $terms = "'" . implode( "','", array_map( 'sanitize_title_for_query', $query['terms'] ) ) . "'";
+ $terms = $wpdb->get_col( "
+ SELECT $wpdb->term_taxonomy.$resulting_field
+ FROM $wpdb->term_taxonomy
+ INNER JOIN $wpdb->terms USING (term_id)
+ WHERE taxonomy = '{$query['taxonomy']}'
+ AND $wpdb->terms.{$query['field']} IN ($terms)
+ " );
+ break;
+ case 'term_taxonomy_id':
+ $terms = implode( ',', array_map( 'intval', $query['terms'] ) );
+ $terms = $wpdb->get_col( "
+ SELECT $resulting_field
+ FROM $wpdb->term_taxonomy
+ WHERE term_taxonomy_id IN ($terms)
+ " );
+ break;
+ default:
+ $terms = implode( ',', array_map( 'intval', $query['terms'] ) );
+ $terms = $wpdb->get_col( "
+ SELECT $resulting_field
+ FROM $wpdb->term_taxonomy
+ WHERE taxonomy = '{$query['taxonomy']}'
+ AND term_id IN ($terms)
+ " );
+ }
+
+ if ( 'AND' == $query['operator'] && count( $terms ) < count( $query['terms'] ) ) {
+ $query = new WP_Error( 'Inexistent terms' );
+ return;
+ }
+
+ $query['terms'] = $terms;
+ $query['field'] = $resulting_field;
+ }
+}
+
+/**
+ * Get all Term data from database by Term ID.
+ *
+ * The usage of the get_term function is to apply filters to a term object. It
+ * is possible to get a term object from the database before applying the
+ * filters.
+ *
+ * $term ID must be part of $taxonomy, to get from the database. Failure, might
+ * be able to be captured by the hooks. Failure would be the same value as $wpdb
+ * returns for the get_row method.
+ *
+ * There are two hooks, one is specifically for each term, named 'get_term', and
+ * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the
+ * term object, and the taxonomy name as parameters. Both hooks are expected to
+ * return a Term object.
+ *
+ * 'get_term' hook - Takes two parameters the term Object and the taxonomy name.
+ * Must return term object. Used in get_term() as a catch-all filter for every
+ * $term.
+ *
+ * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
+ * name. Must return term object. $taxonomy will be the taxonomy name, so for
+ * example, if 'category', it would be 'get_category' as the filter name. Useful
+ * for custom taxonomies or plugging into default taxonomies.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses sanitize_term() Cleanses the term based on $filter context before returning.
+ * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
+ *
+ * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
+ * @param string $taxonomy Taxonomy name that $term is part of.
+ * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
+ * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
+ * exist then WP_Error will be returned.
+ */
+function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
+ global $wpdb;
+ $null = null;
+
+ if ( empty($term) ) {
+ $error = new WP_Error('invalid_term', __('Empty Term'));
+ return $error;
+ }
+
+ if ( ! taxonomy_exists($taxonomy) ) {
+ $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+ return $error;
+ }
+
+ if ( is_object($term) && empty($term->filter) ) {
+ wp_cache_add($term->term_id, $term, $taxonomy);
+ $_term = $term;
+ } else {
+ if ( is_object($term) )
+ $term = $term->term_id;
+ if ( !$term = (int) $term )
+ return $null;
+ if ( ! $_term = wp_cache_get($term, $taxonomy) ) {
+ $_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) );
+ if ( ! $_term )
+ return $null;
+ wp_cache_add($term, $_term, $taxonomy);
+ }
+ }
+
+ $_term = apply_filters('get_term', $_term, $taxonomy);
+ $_term = apply_filters("get_$taxonomy", $_term, $taxonomy);
+ $_term = sanitize_term($_term, $taxonomy, $filter);
+
+ if ( $output == OBJECT ) {
+ return $_term;
+ } elseif ( $output == ARRAY_A ) {
+ $__term = get_object_vars($_term);
+ return $__term;
+ } elseif ( $output == ARRAY_N ) {
+ $__term = array_values(get_object_vars($_term));
+ return $__term;
+ } else {
+ return $_term;
+ }
+}
+
+/**
+ * Get all Term data from database by Term field and data.
+ *
+ * Warning: $value is not escaped for 'name' $field. You must do it yourself, if
+ * required.
+ *
+ * The default $field is 'id', therefore it is possible to also use null for
+ * field, but not recommended that you do so.
+ *
+ * If $value does not exist, the return value will be false. If $taxonomy exists
+ * and $field and $value combinations exist, the Term will be returned.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses sanitize_term() Cleanses the term based on $filter context before returning.
+ * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
+ *
+ * @param string $field Either 'slug', 'name', or 'id'
+ * @param string|int $value Search for this term value
+ * @param string $taxonomy Taxonomy Name
+ * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
+ * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
+ * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
+ */
+function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
+ global $wpdb;
+
+ if ( ! taxonomy_exists($taxonomy) )
+ return false;
+
+ if ( 'slug' == $field ) {
+ $field = 't.slug';
+ $value = sanitize_title($value);
+ if ( empty($value) )
+ return false;
+ } else if ( 'name' == $field ) {
+ // Assume already escaped
+ $value = wp_unslash($value);
+ $field = 't.name';
+ } else {
+ $term = get_term( (int) $value, $taxonomy, $output, $filter);
+ if ( is_wp_error( $term ) )
+ $term = false;
+ return $term;
+ }
+
+ $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value) );
+ if ( !$term )
+ return false;
+
+ wp_cache_add($term->term_id, $term, $taxonomy);
+
+ $term = apply_filters('get_term', $term, $taxonomy);
+ $term = apply_filters("get_$taxonomy", $term, $taxonomy);
+ $term = sanitize_term($term, $taxonomy, $filter);
+
+ if ( $output == OBJECT ) {
+ return $term;
+ } elseif ( $output == ARRAY_A ) {
+ return get_object_vars($term);
+ } elseif ( $output == ARRAY_N ) {
+ return array_values(get_object_vars($term));
+ } else {
+ return $term;
+ }
+}
+
+/**
+ * Merge all term children into a single array of their IDs.
+ *
+ * This recursive function will merge all of the children of $term into the same
+ * array of term IDs. Only useful for taxonomies which are hierarchical.
+ *
+ * Will return an empty array if $term does not exist in $taxonomy.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses _get_term_hierarchy()
+ * @uses get_term_children() Used to get the children of both $taxonomy and the parent $term
+ *
+ * @param string $term_id ID of Term to get children
+ * @param string $taxonomy Taxonomy Name
+ * @return array|WP_Error List of Term Objects. WP_Error returned if $taxonomy does not exist
+ */
+function get_term_children( $term_id, $taxonomy ) {
+ if ( ! taxonomy_exists($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+ $term_id = intval( $term_id );
+
+ $terms = _get_term_hierarchy($taxonomy);
+
+ if ( ! isset($terms[$term_id]) )
+ return array();
+
+ $children = $terms[$term_id];
+
+ foreach ( (array) $terms[$term_id] as $child ) {
+ if ( isset($terms[$child]) )
+ $children = array_merge($children, get_term_children($child, $taxonomy));
+ }
+
+ return $children;
+}
+
+/**
+ * Get sanitized Term field.
+ *
+ * Does checks for $term, based on the $taxonomy. The function is for contextual
+ * reasons and for simplicity of usage. See sanitize_term_field() for more
+ * information.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses sanitize_term_field() Passes the return value in sanitize_term_field on success.
+ *
+ * @param string $field Term field to fetch
+ * @param int $term Term ID
+ * @param string $taxonomy Taxonomy Name
+ * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
+ * @return mixed Will return an empty string if $term is not an object or if $field is not set in $term.
+ */
+function get_term_field( $field, $term, $taxonomy, $context = 'display' ) {
+ $term = (int) $term;
+ $term = get_term( $term, $taxonomy );
+ if ( is_wp_error($term) )
+ return $term;
+
+ if ( !is_object($term) )
+ return '';
+
+ if ( !isset($term->$field) )
+ return '';
+
+ return sanitize_term_field($field, $term->$field, $term->term_id, $taxonomy, $context);
+}
+
+/**
+ * Sanitizes Term for editing.
+ *
+ * Return value is sanitize_term() and usage is for sanitizing the term for
+ * editing. Function is for contextual and simplicity.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses sanitize_term() Passes the return value on success
+ *
+ * @param int|object $id Term ID or Object
+ * @param string $taxonomy Taxonomy Name
+ * @return mixed|null|WP_Error Will return empty string if $term is not an object.
+ */
+function get_term_to_edit( $id, $taxonomy ) {
+ $term = get_term( $id, $taxonomy );
+
+ if ( is_wp_error($term) )
+ return $term;
+
+ if ( !is_object($term) )
+ return '';
+
+ return sanitize_term($term, $taxonomy, 'edit');
+}
+
+/**
+ * Retrieve the terms in a given taxonomy or list of taxonomies.
+ *
+ * You can fully inject any customizations to the query before it is sent, as
+ * well as control the output with a filter.
+ *
+ * The 'get_terms' filter will be called when the cache has the term and will
+ * pass the found term along with the array of $taxonomies and array of $args.
+ * This filter is also called before the array of terms is passed and will pass
+ * the array of terms, along with the $taxonomies and $args.
+ *
+ * The 'list_terms_exclusions' filter passes the compiled exclusions along with
+ * the $args.
+ *
+ * The 'get_terms_orderby' filter passes the ORDER BY clause for the query
+ * along with the $args array.
+ *
+ * The 'get_terms_fields' filter passes the fields for the SELECT query
+ * along with the $args array.
+ *
+ * The list of arguments that $args can contain, which will overwrite the defaults:
+ *
+ * orderby - Default is 'name'. Can be name, count, term_group, slug or nothing
+ * (will use term_id), Passing a custom value other than these will cause it to
+ * order based on the custom value.
+ *
+ * order - Default is ASC. Can use DESC.
+ *
+ * hide_empty - Default is true. Will not return empty terms, which means
+ * terms whose count is 0 according to the given taxonomy.
+ *
+ * exclude - Default is an empty array. An array, comma- or space-delimited string
+ * of term ids to exclude from the return array. If 'include' is non-empty,
+ * 'exclude' is ignored.
+ *
+ * exclude_tree - Default is an empty array. An array, comma- or space-delimited
+ * string of term ids to exclude from the return array, along with all of their
+ * descendant terms according to the primary taxonomy. If 'include' is non-empty,
+ * 'exclude_tree' is ignored.
+ *
+ * include - Default is an empty array. An array, comma- or space-delimited string
+ * of term ids to include in the return array.
+ *
+ * number - The maximum number of terms to return. Default is to return them all.
+ *
+ * offset - The number by which to offset the terms query.
+ *
+ * fields - Default is 'all', which returns an array of term objects.
+ * If 'fields' is 'ids' or 'names', returns an array of
+ * integers or strings, respectively.
+ *
+ * slug - Returns terms whose "slug" matches this value. Default is empty string.
+ *
+ * hierarchical - Whether to include terms that have non-empty descendants
+ * (even if 'hide_empty' is set to true).
+ *
+ * search - Returned terms' names will contain the value of 'search',
+ * case-insensitive. Default is an empty string.
+ *
+ * name__like - Returned terms' names will begin with the value of 'name__like',
+ * case-insensitive. Default is empty string.
+ *
+ * The argument 'pad_counts', if set to true will include the quantity of a term's
+ * children in the quantity of each term's "count" object variable.
+ *
+ * The 'get' argument, if set to 'all' instead of its default empty string,
+ * returns terms regardless of ancestry or whether the terms are empty.
+ *
+ * The 'child_of' argument, when used, should be set to the integer of a term ID. Its default
+ * is 0. If set to a non-zero value, all returned terms will be descendants
+ * of that term according to the given taxonomy. Hence 'child_of' is set to 0
+ * if more than one taxonomy is passed in $taxonomies, because multiple taxonomies
+ * make term ancestry ambiguous.
+ *
+ * The 'parent' argument, when used, should be set to the integer of a term ID. Its default is
+ * the empty string '', which has a different meaning from the integer 0.
+ * If set to an integer value, all returned terms will have as an immediate
+ * ancestor the term whose ID is specified by that integer according to the given taxonomy.
+ * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent'
+ * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc.
+ *
+ * The 'cache_domain' argument enables a unique cache key to be produced when this query is stored
+ * in object cache. For instance, if you are using one of this function's filters to modify the
+ * query (such as 'terms_clauses'), setting 'cache_domain' to a unique value will not overwrite
+ * the cache for similar queries. Default value is 'core'.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses wp_parse_args() Merges the defaults with those defined by $args and allows for strings.
+ *
+ * @param string|array $taxonomies Taxonomy name or list of Taxonomy names
+ * @param string|array $args The values of what to search for when returning terms
+ * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies do not exist.
+ */
+function get_terms($taxonomies, $args = '') {
+ global $wpdb;
+ $empty_array = array();
+
+ $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies );
+ if ( ! is_array( $taxonomies ) )
+ $taxonomies = array( $taxonomies );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( ! taxonomy_exists($taxonomy) ) {
+ $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+ return $error;
+ }
+ }
+
+ $defaults = array('orderby' => 'name', 'order' => 'ASC',
+ 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
+ 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '',
+ 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '',
+ 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
+ $args = wp_parse_args( $args, $defaults );
+ $args['number'] = absint( $args['number'] );
+ $args['offset'] = absint( $args['offset'] );
+ if ( !$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) ||
+ '' !== $args['parent'] ) {
+ $args['child_of'] = 0;
+ $args['hierarchical'] = false;
+ $args['pad_counts'] = false;
+ }
+
+ if ( 'all' == $args['get'] ) {
+ $args['child_of'] = 0;
+ $args['hide_empty'] = 0;
+ $args['hierarchical'] = false;
+ $args['pad_counts'] = false;
+ }
+
+ $args = apply_filters( 'get_terms_args', $args, $taxonomies );
+
+ extract($args, EXTR_SKIP);
+
+ if ( $child_of ) {
+ $hierarchy = _get_term_hierarchy($taxonomies[0]);
+ if ( !isset($hierarchy[$child_of]) )
+ return $empty_array;
+ }
+
+ if ( $parent ) {
+ $hierarchy = _get_term_hierarchy($taxonomies[0]);
+ if ( !isset($hierarchy[$parent]) )
+ return $empty_array;
+ }
+
+ // $args can be whatever, only use the args defined in defaults to compute the key
+ $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
+ $key = md5( serialize( compact(array_keys($defaults)) ) . serialize( $taxonomies ) . $filter_key );
+ $last_changed = wp_cache_get( 'last_changed', 'terms' );
+ if ( ! $last_changed ) {
+ $last_changed = microtime();
+ wp_cache_set( 'last_changed', $last_changed, 'terms' );
+ }
+ $cache_key = "get_terms:$key:$last_changed";
+ $cache = wp_cache_get( $cache_key, 'terms' );
+ if ( false !== $cache ) {
+ $cache = apply_filters('get_terms', $cache, $taxonomies, $args);
+ return $cache;
+ }
+
+ $_orderby = strtolower($orderby);
+ if ( 'count' == $_orderby )
+ $orderby = 'tt.count';
+ else if ( 'name' == $_orderby )
+ $orderby = 't.name';
+ else if ( 'slug' == $_orderby )
+ $orderby = 't.slug';
+ else if ( 'term_group' == $_orderby )
+ $orderby = 't.term_group';
+ else if ( 'none' == $_orderby )
+ $orderby = '';
+ elseif ( empty($_orderby) || 'id' == $_orderby )
+ $orderby = 't.term_id';
+ else
+ $orderby = 't.name';
+
+ $orderby = apply_filters( 'get_terms_orderby', $orderby, $args );
+
+ if ( !empty($orderby) )
+ $orderby = "ORDER BY $orderby";
+ else
+ $order = '';
+
+ $order = strtoupper( $order );
+ if ( '' !== $order && !in_array( $order, array( 'ASC', 'DESC' ) ) )
+ $order = 'ASC';
+
+ $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')";
+ $inclusions = '';
+ if ( !empty($include) ) {
+ $exclude = '';
+ $exclude_tree = '';
+ $interms = wp_parse_id_list($include);
+ foreach ( $interms as $interm ) {
+ if ( empty($inclusions) )
+ $inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
+ else
+ $inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
+ }
+ }
+
+ if ( !empty($inclusions) )
+ $inclusions .= ')';
+ $where .= $inclusions;
+
+ $exclusions = '';
+ if ( !empty( $exclude_tree ) ) {
+ $excluded_trunks = wp_parse_id_list($exclude_tree);
+ foreach ( $excluded_trunks as $extrunk ) {
+ $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0));
+ $excluded_children[] = $extrunk;
+ foreach( $excluded_children as $exterm ) {
+ if ( empty($exclusions) )
+ $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
+ else
+ $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
+ }
+ }
+ }
+
+ if ( !empty($exclude) ) {
+ $exterms = wp_parse_id_list($exclude);
+ foreach ( $exterms as $exterm ) {
+ if ( empty($exclusions) )
+ $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
+ else
+ $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
+ }
+ }
+
+ if ( !empty($exclusions) )
+ $exclusions .= ')';
+ $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args );
+ $where .= $exclusions;
+
+ if ( !empty($slug) ) {
+ $slug = sanitize_title($slug);
+ $where .= " AND t.slug = '$slug'";
+ }
+
+ if ( !empty($name__like) ) {
+ $name__like = like_escape( $name__like );
+ $where .= $wpdb->prepare( " AND t.name LIKE %s", $name__like . '%' );
+ }
+
+ if ( '' !== $parent ) {
+ $parent = (int) $parent;
+ $where .= " AND tt.parent = '$parent'";
+ }
+
+ if ( $hide_empty && !$hierarchical )
+ $where .= ' AND tt.count > 0';
+
+ // don't limit the query results when we have to descend the family tree
+ if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) {
+ if ( $offset )
+ $limits = 'LIMIT ' . $offset . ',' . $number;
+ else
+ $limits = 'LIMIT ' . $number;
+ } else {
+ $limits = '';
+ }
+
+ if ( !empty($search) ) {
+ $search = like_escape($search);
+ $where .= $wpdb->prepare( " AND (t.name LIKE %s)", '%' . $search . '%');
+ }
+
+ $selects = array();
+ switch ( $fields ) {
+ case 'all':
+ $selects = array('t.*', 'tt.*');
+ break;
+ case 'ids':
+ case 'id=>parent':
+ $selects = array('t.term_id', 'tt.parent', 'tt.count');
+ break;
+ case 'names':
+ $selects = array('t.term_id', 'tt.parent', 'tt.count', 't.name');
+ break;
+ case 'count':
+ $orderby = '';
+ $order = '';
+ $selects = array('COUNT(*)');
+ }
+
+ $_fields = $fields;
+
+ $fields = implode(', ', apply_filters( 'get_terms_fields', $selects, $args ));
+
+ $join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
+
+ $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
+ $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
+ foreach ( $pieces as $piece )
+ $$piece = isset( $clauses[ $piece ] ) ? $clauses[ $piece ] : '';
+
+ $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
+
+ $fields = $_fields;
+
+ if ( 'count' == $fields ) {
+ $term_count = $wpdb->get_var($query);
+ return $term_count;
+ }
+
+ $terms = $wpdb->get_results($query);
+ if ( 'all' == $fields ) {
+ update_term_cache($terms);
+ }
+
+ if ( empty($terms) ) {
+ wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
+ $terms = apply_filters('get_terms', array(), $taxonomies, $args);
+ return $terms;
+ }
+
+ if ( $child_of ) {
+ $children = _get_term_hierarchy($taxonomies[0]);
+ if ( ! empty($children) )
+ $terms = _get_term_children($child_of, $terms, $taxonomies[0]);
+ }
+
+ // Update term counts to include children.
+ if ( $pad_counts && 'all' == $fields )
+ _pad_term_counts($terms, $taxonomies[0]);
+
+ // Make sure we show empty categories that have children.
+ if ( $hierarchical && $hide_empty && is_array($terms) ) {
+ foreach ( $terms as $k => $term ) {
+ if ( ! $term->count ) {
+ $children = _get_term_children($term->term_id, $terms, $taxonomies[0]);
+ if ( is_array($children) )
+ foreach ( $children as $child )
+ if ( $child->count )
+ continue 2;
+
+ // It really is empty
+ unset($terms[$k]);
+ }
+ }
+ }
+ reset ( $terms );
+
+ $_terms = array();
+ if ( 'id=>parent' == $fields ) {
+ while ( $term = array_shift($terms) )
+ $_terms[$term->term_id] = $term->parent;
+ $terms = $_terms;
+ } elseif ( 'ids' == $fields ) {
+ while ( $term = array_shift($terms) )
+ $_terms[] = $term->term_id;
+ $terms = $_terms;
+ } elseif ( 'names' == $fields ) {
+ while ( $term = array_shift($terms) )
+ $_terms[] = $term->name;
+ $terms = $_terms;
+ }
+
+ if ( $number && is_array( $terms ) && count( $terms ) > $number )
+ $terms = array_slice( $terms, $offset, $number );
+
+ wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS );
+
+ $terms = apply_filters('get_terms', $terms, $taxonomies, $args);
+ return $terms;
+}
+
+/**
+ * Check if Term exists.
+ *
+ * Formerly is_term(), introduced in 2.3.0.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.0.0
+ *
+ * @uses $wpdb
+ *
+ * @param int|string $term The term to check
+ * @param string $taxonomy The taxonomy name to use
+ * @param int $parent ID of parent term under which to confine the exists search.
+ * @return mixed Returns 0 if the term does not exist. Returns the term ID if no taxonomy is specified
+ * and the term ID exists. Returns an array of the term ID and the taxonomy if the pairing exists.
+ */
+function term_exists($term, $taxonomy = '', $parent = 0) {
+ global $wpdb;
+
+ $select = "SELECT term_id FROM $wpdb->terms as t WHERE ";
+ $tax_select = "SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE ";
+
+ if ( is_int($term) ) {
+ if ( 0 == $term )
+ return 0;
+ $where = 't.term_id = %d';
+ if ( !empty($taxonomy) )
+ return $wpdb->get_row( $wpdb->prepare( $tax_select . $where . " AND tt.taxonomy = %s", $term, $taxonomy ), ARRAY_A );
+ else
+ return $wpdb->get_var( $wpdb->prepare( $select . $where, $term ) );
+ }
+
+ $term = trim( wp_unslash( $term ) );
+
+ if ( '' === $slug = sanitize_title($term) )
+ return 0;
+
+ $where = 't.slug = %s';
+ $else_where = 't.name = %s';
+ $where_fields = array($slug);
+ $else_where_fields = array($term);
+ if ( !empty($taxonomy) ) {
+ $parent = (int) $parent;
+ if ( $parent > 0 ) {
+ $where_fields[] = $parent;
+ $else_where_fields[] = $parent;
+ $where .= ' AND tt.parent = %d';
+ $else_where .= ' AND tt.parent = %d';
+ }
+
+ $where_fields[] = $taxonomy;
+ $else_where_fields[] = $taxonomy;
+
+ if ( $result = $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $where AND tt.taxonomy = %s", $where_fields), ARRAY_A) )
+ return $result;
+
+ return $wpdb->get_row( $wpdb->prepare("SELECT tt.term_id, tt.term_taxonomy_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy as tt ON tt.term_id = t.term_id WHERE $else_where AND tt.taxonomy = %s", $else_where_fields), ARRAY_A);
+ }
+
+ if ( $result = $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $where", $where_fields) ) )
+ return $result;
+
+ return $wpdb->get_var( $wpdb->prepare("SELECT term_id FROM $wpdb->terms as t WHERE $else_where", $else_where_fields) );
+}
+
+/**
+ * Check if a term is an ancestor of another term.
+ *
+ * You can use either an id or the term object for both parameters.
+ *
+ * @since 3.4.0
+ *
+ * @param int|object $term1 ID or object to check if this is the parent term.
+ * @param int|object $term2 The child term.
+ * @param string $taxonomy Taxonomy name that $term1 and $term2 belong to.
+ * @return bool Whether $term2 is child of $term1
+ */
+function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
+ if ( ! isset( $term1->term_id ) )
+ $term1 = get_term( $term1, $taxonomy );
+ if ( ! isset( $term2->parent ) )
+ $term2 = get_term( $term2, $taxonomy );
+
+ if ( empty( $term1->term_id ) || empty( $term2->parent ) )
+ return false;
+ if ( $term2->parent == $term1->term_id )
+ return true;
+
+ return term_is_ancestor_of( $term1, get_term( $term2->parent, $taxonomy ), $taxonomy );
+}
+
+/**
+ * Sanitize Term all fields.
+ *
+ * Relies on sanitize_term_field() to sanitize the term. The difference is that
+ * this function will sanitize <strong>all</strong> fields. The context is based
+ * on sanitize_term_field().
+ *
+ * The $term is expected to be either an array or an object.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses sanitize_term_field Used to sanitize all fields in a term
+ *
+ * @param array|object $term The term to check
+ * @param string $taxonomy The taxonomy name to use
+ * @param string $context Default is 'display'.
+ * @return array|object Term with all fields sanitized
+ */
+function sanitize_term($term, $taxonomy, $context = 'display') {
+
+ if ( 'raw' == $context )
+ return $term;
+
+ $fields = array('term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group');
+
+ $do_object = false;
+ if ( is_object($term) )
+ $do_object = true;
+
+ $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0);
+
+ foreach ( (array) $fields as $field ) {
+ if ( $do_object ) {
+ if ( isset($term->$field) )
+ $term->$field = sanitize_term_field($field, $term->$field, $term_id, $taxonomy, $context);
+ } else {
+ if ( isset($term[$field]) )
+ $term[$field] = sanitize_term_field($field, $term[$field], $term_id, $taxonomy, $context);
+ }
+ }
+
+ if ( $do_object )
+ $term->filter = $context;
+ else
+ $term['filter'] = $context;
+
+ return $term;
+}
+
+/**
+ * Cleanse the field value in the term based on the context.
+ *
+ * Passing a term field value through the function should be assumed to have
+ * cleansed the value for whatever context the term field is going to be used.
+ *
+ * If no context or an unsupported context is given, then default filters will
+ * be applied.
+ *
+ * There are enough filters for each context to support a custom filtering
+ * without creating your own filter function. Simply create a function that
+ * hooks into the filter you need.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ *
+ * @param string $field Term field to sanitize
+ * @param string $value Search for this term value
+ * @param int $term_id Term ID
+ * @param string $taxonomy Taxonomy Name
+ * @param string $context Either edit, db, display, attribute, or js.
+ * @return mixed sanitized field
+ */
+function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
+ if ( 'parent' == $field || 'term_id' == $field || 'count' == $field || 'term_group' == $field ) {
+ $value = (int) $value;
+ if ( $value < 0 )
+ $value = 0;
+ }
+
+ if ( 'raw' == $context )
+ return $value;
+
+ if ( 'edit' == $context ) {
+ $value = apply_filters("edit_term_{$field}", $value, $term_id, $taxonomy);
+ $value = apply_filters("edit_{$taxonomy}_{$field}", $value, $term_id);
+ if ( 'description' == $field )
+ $value = esc_html($value); // textarea_escaped
+ else
+ $value = esc_attr($value);
+ } else if ( 'db' == $context ) {
+ $value = apply_filters("pre_term_{$field}", $value, $taxonomy);
+ $value = apply_filters("pre_{$taxonomy}_{$field}", $value);
+ // Back compat filters
+ if ( 'slug' == $field )
+ $value = apply_filters('pre_category_nicename', $value);
+
+ } else if ( 'rss' == $context ) {
+ $value = apply_filters("term_{$field}_rss", $value, $taxonomy);
+ $value = apply_filters("{$taxonomy}_{$field}_rss", $value);
+ } else {
+ // Use display filters by default.
+ $value = apply_filters("term_{$field}", $value, $term_id, $taxonomy, $context);
+ $value = apply_filters("{$taxonomy}_{$field}", $value, $term_id, $context);
+ }
+
+ if ( 'attribute' == $context )
+ $value = esc_attr($value);
+ else if ( 'js' == $context )
+ $value = esc_js($value);
+
+ return $value;
+}
+
+/**
+ * Count how many terms are in Taxonomy.
+ *
+ * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true).
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses get_terms()
+ * @uses wp_parse_args() Turns strings into arrays and merges defaults into an array.
+ *
+ * @param string $taxonomy Taxonomy name
+ * @param array|string $args Overwrite defaults. See get_terms()
+ * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
+ */
+function wp_count_terms( $taxonomy, $args = array() ) {
+ $defaults = array('hide_empty' => false);
+ $args = wp_parse_args($args, $defaults);
+
+ // backwards compatibility
+ if ( isset($args['ignore_empty']) ) {
+ $args['hide_empty'] = $args['ignore_empty'];
+ unset($args['ignore_empty']);
+ }
+
+ $args['fields'] = 'count';
+
+ return get_terms($taxonomy, $args);
+}
+
+/**
+ * Will unlink the object from the taxonomy or taxonomies.
+ *
+ * Will remove all relationships between the object and any terms in
+ * a particular taxonomy or taxonomies. Does not remove the term or
+ * taxonomy itself.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses wp_remove_object_terms()
+ *
+ * @param int $object_id The term Object Id that refers to the term
+ * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
+ */
+function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
+ $object_id = (int) $object_id;
+
+ if ( !is_array($taxonomies) )
+ $taxonomies = array($taxonomies);
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ $term_ids = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids' ) );
+ $term_ids = array_map( 'intval', $term_ids );
+ wp_remove_object_terms( $object_id, $term_ids, $taxonomy );
+ }
+}
+
+/**
+ * Removes a term from the database.
+ *
+ * If the term is a parent of other terms, then the children will be updated to
+ * that term's parent.
+ *
+ * The $args 'default' will only override the terms found, if there is only one
+ * term found. Any other and the found terms are used.
+ *
+ * The $args 'force_default' will force the term supplied as default to be
+ * assigned even if the object was not going to be termless
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses do_action() Calls both 'delete_term' and 'delete_$taxonomy' action
+ * hooks, passing term ID, term taxonomy ID, and deleted term object. 'delete_term'
+ * also gets taxonomy as the third parameter.
+ *
+ * @param int $term Term ID
+ * @param string $taxonomy Taxonomy Name
+ * @param array|string $args Optional. Change 'default' term id and override found term ids.
+ * @return bool|WP_Error Returns false if not term; true if completes delete action.
+ */
+function wp_delete_term( $term, $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ $term = (int) $term;
+
+ if ( ! $ids = term_exists($term, $taxonomy) )
+ return false;
+ if ( is_wp_error( $ids ) )
+ return $ids;
+
+ $tt_id = $ids['term_taxonomy_id'];
+
+ $defaults = array();
+
+ if ( 'category' == $taxonomy ) {
+ $defaults['default'] = get_option( 'default_category' );
+ if ( $defaults['default'] == $term )
+ return 0; // Don't delete the default category
+ }
+
+ $args = wp_parse_args($args, $defaults);
+ extract($args, EXTR_SKIP);
+
+ if ( isset( $default ) ) {
+ $default = (int) $default;
+ if ( ! term_exists($default, $taxonomy) )
+ unset($default);
+ }
+
+ // Update children to point to new parent
+ if ( is_taxonomy_hierarchical($taxonomy) ) {
+ $term_obj = get_term($term, $taxonomy);
+ if ( is_wp_error( $term_obj ) )
+ return $term_obj;
+ $parent = $term_obj->parent;
+
+ $edit_tt_ids = $wpdb->get_col( "SELECT `term_taxonomy_id` FROM $wpdb->term_taxonomy WHERE `parent` = " . (int)$term_obj->term_id );
+ do_action( 'edit_term_taxonomies', $edit_tt_ids );
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
+ do_action( 'edited_term_taxonomies', $edit_tt_ids );
+ }
+
+ $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
+
+ foreach ( (array) $objects as $object ) {
+ $terms = wp_get_object_terms($object, $taxonomy, array('fields' => 'ids', 'orderby' => 'none'));
+ if ( 1 == count($terms) && isset($default) ) {
+ $terms = array($default);
+ } else {
+ $terms = array_diff($terms, array($term));
+ if (isset($default) && isset($force_default) && $force_default)
+ $terms = array_merge($terms, array($default));
+ }
+ $terms = array_map('intval', $terms);
+ wp_set_object_terms($object, $terms, $taxonomy);
+ }
+
+ // Clean the relationship caches for all object types using this term
+ $tax_object = get_taxonomy( $taxonomy );
+ foreach ( $tax_object->object_type as $object_type )
+ clean_object_term_cache( $objects, $object_type );
+
+ // Get the object before deletion so we can pass to actions below
+ $deleted_term = get_term( $term, $taxonomy );
+
+ do_action( 'delete_term_taxonomy', $tt_id );
+ $wpdb->delete( $wpdb->term_taxonomy, array( 'term_taxonomy_id' => $tt_id ) );
+ do_action( 'deleted_term_taxonomy', $tt_id );
+
+ // Delete the term if no taxonomies use it.
+ if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term) ) )
+ $wpdb->delete( $wpdb->terms, array( 'term_id' => $term ) );
+
+ clean_term_cache($term, $taxonomy);
+
+ do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term );
+ do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term );
+
+ return true;
+}
+
+/**
+ * Deletes one existing category.
+ *
+ * @since 2.0.0
+ * @uses wp_delete_term()
+ *
+ * @param int $cat_ID
+ * @return mixed Returns true if completes delete action; false if term doesn't exist;
+ * Zero on attempted deletion of default Category; WP_Error object is also a possibility.
+ */
+function wp_delete_category( $cat_ID ) {
+ return wp_delete_term( $cat_ID, 'category' );
+}
+
+/**
+ * Retrieves the terms associated with the given object(s), in the supplied taxonomies.
+ *
+ * The following information has to do the $args parameter and for what can be
+ * contained in the string or array of that parameter, if it exists.
+ *
+ * The first argument is called, 'orderby' and has the default value of 'name'.
+ * The other value that is supported is 'count'.
+ *
+ * The second argument is called, 'order' and has the default value of 'ASC'.
+ * The only other value that will be acceptable is 'DESC'.
+ *
+ * The final argument supported is called, 'fields' and has the default value of
+ * 'all'. There are multiple other options that can be used instead. Supported
+ * values are as follows: 'all', 'ids', 'names', and finally
+ * 'all_with_object_id'.
+ *
+ * The fields argument also decides what will be returned. If 'all' or
+ * 'all_with_object_id' is chosen or the default kept intact, then all matching
+ * terms objects will be returned. If either 'ids' or 'names' is used, then an
+ * array of all matching term ids or term names will be returned respectively.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $object_ids The ID(s) of the object(s) to retrieve.
+ * @param string|array $taxonomies The taxonomies to retrieve terms from.
+ * @param array|string $args Change what is returned
+ * @return array|WP_Error The requested term data or empty array if no terms found. WP_Error if any of the $taxonomies don't exist.
+ */
+function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
+ global $wpdb;
+
+ if ( empty( $object_ids ) || empty( $taxonomies ) )
+ return array();
+
+ if ( !is_array($taxonomies) )
+ $taxonomies = array($taxonomies);
+
+ foreach ( (array) $taxonomies as $taxonomy ) {
+ if ( ! taxonomy_exists($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+ }
+
+ if ( !is_array($object_ids) )
+ $object_ids = array($object_ids);
+ $object_ids = array_map('intval', $object_ids);
+
+ $defaults = array('orderby' => 'name', 'order' => 'ASC', 'fields' => 'all');
+ $args = wp_parse_args( $args, $defaults );
+
+ $terms = array();
+ if ( count($taxonomies) > 1 ) {
+ foreach ( $taxonomies as $index => $taxonomy ) {
+ $t = get_taxonomy($taxonomy);
+ if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) {
+ unset($taxonomies[$index]);
+ $terms = array_merge($terms, wp_get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args)));
+ }
+ }
+ } else {
+ $t = get_taxonomy($taxonomies[0]);
+ if ( isset($t->args) && is_array($t->args) )
+ $args = array_merge($args, $t->args);
+ }
+
+ extract($args, EXTR_SKIP);
+
+ if ( 'count' == $orderby )
+ $orderby = 'tt.count';
+ else if ( 'name' == $orderby )
+ $orderby = 't.name';
+ else if ( 'slug' == $orderby )
+ $orderby = 't.slug';
+ else if ( 'term_group' == $orderby )
+ $orderby = 't.term_group';
+ else if ( 'term_order' == $orderby )
+ $orderby = 'tr.term_order';
+ else if ( 'none' == $orderby ) {
+ $orderby = '';
+ $order = '';
+ } else {
+ $orderby = 't.term_id';
+ }
+
+ // tt_ids queries can only be none or tr.term_taxonomy_id
+ if ( ('tt_ids' == $fields) && !empty($orderby) )
+ $orderby = 'tr.term_taxonomy_id';
+
+ if ( !empty($orderby) )
+ $orderby = "ORDER BY $orderby";
+
+ $order = strtoupper( $order );
+ if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) )
+ $order = 'ASC';
+
+ $taxonomies = "'" . implode("', '", $taxonomies) . "'";
+ $object_ids = implode(', ', $object_ids);
+
+ $select_this = '';
+ if ( 'all' == $fields )
+ $select_this = 't.*, tt.*';
+ else if ( 'ids' == $fields )
+ $select_this = 't.term_id';
+ else if ( 'names' == $fields )
+ $select_this = 't.name';
+ else if ( 'slugs' == $fields )
+ $select_this = 't.slug';
+ else if ( 'all_with_object_id' == $fields )
+ $select_this = 't.*, tt.*, tr.object_id';
+
+ $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tr.object_id IN ($object_ids) $orderby $order";
+
+ if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
+ $terms = array_merge($terms, $wpdb->get_results($query));
+ update_term_cache($terms);
+ } else if ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) {
+ $terms = array_merge($terms, $wpdb->get_col($query));
+ } else if ( 'tt_ids' == $fields ) {
+ $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order");
+ }
+
+ if ( ! $terms )
+ $terms = array();
+
+ return apply_filters('wp_get_object_terms', $terms, $object_ids, $taxonomies, $args);
+}
+
+/**
+ * Adds a new term to the database. Optionally marks it as an alias of an existing term.
+ *
+ * Error handling is assigned for the nonexistence of the $taxonomy and $term
+ * parameters before inserting. If both the term id and taxonomy exist
+ * previously, then an array will be returned that contains the term id and the
+ * contents of what is returned. The keys of the array are 'term_id' and
+ * 'term_taxonomy_id' containing numeric values.
+ *
+ * It is assumed that the term does not yet exist or the above will apply. The
+ * term will be first added to the term table and then related to the taxonomy
+ * if everything is well. If everything is correct, then several actions will be
+ * run prior to a filter and then several actions will be run after the filter
+ * is run.
+ *
+ * The arguments decide how the term is handled based on the $args parameter.
+ * The following is a list of the available overrides and the defaults.
+ *
+ * 'alias_of'. There is no default, but if added, expected is the slug that the
+ * term will be an alias of. Expected to be a string.
+ *
+ * 'description'. There is no default. If exists, will be added to the database
+ * along with the term. Expected to be a string.
+ *
+ * 'parent'. Expected to be numeric and default is 0 (zero). Will assign value
+ * of 'parent' to the term.
+ *
+ * 'slug'. Expected to be a string. There is no default.
+ *
+ * If 'slug' argument exists then the slug will be checked to see if it is not
+ * a valid term. If that check succeeds (it is not a valid term), then it is
+ * added and the term id is given. If it fails, then a check is made to whether
+ * the taxonomy is hierarchical and the parent argument is not empty. If the
+ * second check succeeds, the term will be inserted and the term id will be
+ * given.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @uses apply_filters() Calls 'pre_insert_term' hook with term and taxonomy as parameters.
+ * @uses do_action() Calls 'create_term' hook with the term id and taxonomy id as parameters.
+ * @uses do_action() Calls 'create_$taxonomy' hook with term id and taxonomy id as parameters.
+ * @uses apply_filters() Calls 'term_id_filter' hook with term id and taxonomy id as parameters.
+ * @uses do_action() Calls 'created_term' hook with the term id and taxonomy id as parameters.
+ * @uses do_action() Calls 'created_$taxonomy' hook with term id and taxonomy id as parameters.
+ *
+ * @param string $term The term to add or update.
+ * @param string $taxonomy The taxonomy to which to add the term
+ * @param array|string $args Change the values of the inserted term
+ * @return array|WP_Error The Term ID and Term Taxonomy ID
+ */
+function wp_insert_term( $term, $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ if ( ! taxonomy_exists($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+ $term = apply_filters( 'pre_insert_term', $term, $taxonomy );
+ if ( is_wp_error( $term ) )
+ return $term;
+
+ if ( is_int($term) && 0 == $term )
+ return new WP_Error('invalid_term_id', __('Invalid term ID'));
+
+ if ( '' == trim($term) )
+ return new WP_Error('empty_term_name', __('A name is required for this term'));
+
+ $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
+ $args = wp_parse_args($args, $defaults);
+ $args['name'] = $term;
+ $args['taxonomy'] = $taxonomy;
+ $args = sanitize_term($args, $taxonomy, 'db');
+ extract($args, EXTR_SKIP);
+
+ // expected_slashed ($name)
+ $name = wp_unslash($name);
+ $description = wp_unslash($description);
+
+ if ( empty($slug) )
+ $slug = sanitize_title($name);
+
+ $term_group = 0;
+ if ( $alias_of ) {
+ $alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) );
+ if ( $alias->term_group ) {
+ // The alias we want is already in a group, so let's use that one.
+ $term_group = $alias->term_group;
+ } else {
+ // The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
+ $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
+ do_action( 'edit_terms', $alias->term_id, $taxonomy );
+ $wpdb->update($wpdb->terms, compact('term_group'), array('term_id' => $alias->term_id) );
+ do_action( 'edited_terms', $alias->term_id, $taxonomy );
+ }
+ }
+
+ if ( $term_id = term_exists($slug) ) {
+ $existing_term = $wpdb->get_row( $wpdb->prepare( "SELECT name FROM $wpdb->terms WHERE term_id = %d", $term_id), ARRAY_A );
+ // We've got an existing term in the same taxonomy, which matches the name of the new term:
+ if ( is_taxonomy_hierarchical($taxonomy) && $existing_term['name'] == $name && $exists = term_exists( (int) $term_id, $taxonomy ) ) {
+ // Hierarchical, and it matches an existing term, Do not allow same "name" in the same level.
+ $siblings = get_terms($taxonomy, array('fields' => 'names', 'get' => 'all', 'parent' => (int)$parent) );
+ if ( in_array($name, $siblings) ) {
+ return new WP_Error('term_exists', __('A term with the name provided already exists with this parent.'), $exists['term_id']);
+ } else {
+ $slug = wp_unique_term_slug($slug, (object) $args);
+ if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
+ return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
+ $term_id = (int) $wpdb->insert_id;
+ }
+ } elseif ( $existing_term['name'] != $name ) {
+ // We've got an existing term, with a different name, Create the new term.
+ $slug = wp_unique_term_slug($slug, (object) $args);
+ if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
+ return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
+ $term_id = (int) $wpdb->insert_id;
+ } elseif ( $exists = term_exists( (int) $term_id, $taxonomy ) ) {
+ // Same name, same slug.
+ return new WP_Error('term_exists', __('A term with the name provided already exists.'), $exists['term_id']);
+ }
+ } else {
+ // This term does not exist at all in the database, Create it.
+ $slug = wp_unique_term_slug($slug, (object) $args);
+ if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) )
+ return new WP_Error('db_insert_error', __('Could not insert term into the database'), $wpdb->last_error);
+ $term_id = (int) $wpdb->insert_id;
+ }
+
+ // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string.
+ if ( empty($slug) ) {
+ $slug = sanitize_title($slug, $term_id);
+ do_action( 'edit_terms', $term_id, $taxonomy );
+ $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
+ do_action( 'edited_terms', $term_id, $taxonomy );
+ }
+
+ $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id ) );
+
+ if ( !empty($tt_id) )
+ return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+
+ $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent') + array( 'count' => 0 ) );
+ $tt_id = (int) $wpdb->insert_id;
+
+ do_action("create_term", $term_id, $tt_id, $taxonomy);
+ do_action("create_$taxonomy", $term_id, $tt_id);
+
+ $term_id = apply_filters('term_id_filter', $term_id, $tt_id);
+
+ clean_term_cache($term_id, $taxonomy);
+
+ do_action("created_term", $term_id, $tt_id, $taxonomy);
+ do_action("created_$taxonomy", $term_id, $tt_id);
+
+ return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+}
+
+/**
+ * Create Term and Taxonomy Relationships.
+ *
+ * Relates an object (post, link etc) to a term and taxonomy type. Creates the
+ * term and taxonomy relationship if it doesn't already exist. Creates a term if
+ * it doesn't exist (using the slug).
+ *
+ * A relationship means that the term is grouped in or belongs to the taxonomy.
+ * A term has no meaning until it is given context by defining which taxonomy it
+ * exists under.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses wp_remove_object_terms()
+ *
+ * @param int $object_id The object to relate to.
+ * @param array|int|string $terms The slug or id of the term, will replace all existing
+ * related terms in this taxonomy.
+ * @param array|string $taxonomy The context in which to relate the term to the object.
+ * @param bool $append If false will delete difference of terms.
+ * @return array|WP_Error Affected Term IDs
+ */
+function wp_set_object_terms($object_id, $terms, $taxonomy, $append = false) {
+ global $wpdb;
+
+ $object_id = (int) $object_id;
+
+ if ( ! taxonomy_exists($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+ if ( !is_array($terms) )
+ $terms = array($terms);
+
+ if ( ! $append )
+ $old_tt_ids = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids', 'orderby' => 'none'));
+ else
+ $old_tt_ids = array();
+
+ $tt_ids = array();
+ $term_ids = array();
+ $new_tt_ids = array();
+
+ foreach ( (array) $terms as $term) {
+ if ( !strlen(trim($term)) )
+ continue;
+
+ if ( !$term_info = term_exists($term, $taxonomy) ) {
+ // Skip if a non-existent term ID is passed.
+ if ( is_int($term) )
+ continue;
+ $term_info = wp_insert_term($term, $taxonomy);
+ }
+ if ( is_wp_error($term_info) )
+ return $term_info;
+ $term_ids[] = $term_info['term_id'];
+ $tt_id = $term_info['term_taxonomy_id'];
+ $tt_ids[] = $tt_id;
+
+ if ( $wpdb->get_var( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id = %d", $object_id, $tt_id ) ) )
+ continue;
+ do_action( 'add_term_relationship', $object_id, $tt_id );
+ $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );
+ do_action( 'added_term_relationship', $object_id, $tt_id );
+ $new_tt_ids[] = $tt_id;
+ }
+
+ if ( $new_tt_ids )
+ wp_update_term_count( $new_tt_ids, $taxonomy );
+
+ if ( ! $append ) {
+ $delete_tt_ids = array_diff( $old_tt_ids, $tt_ids );
+
+ if ( $delete_tt_ids ) {
+ $in_delete_tt_ids = "'" . implode( "', '", $delete_tt_ids ) . "'";
+ $delete_term_ids = $wpdb->get_col( $wpdb->prepare( "SELECT tt.term_id FROM $wpdb->term_taxonomy AS tt WHERE tt.taxonomy = %s AND tt.term_taxonomy_id IN ($in_delete_tt_ids)", $taxonomy ) );
+ $delete_term_ids = array_map( 'intval', $delete_term_ids );
+
+ $remove = wp_remove_object_terms( $object_id, $delete_term_ids, $taxonomy );
+ if ( is_wp_error( $remove ) ) {
+ return $remove;
+ }
+ }
+ }
+
+ $t = get_taxonomy($taxonomy);
+ if ( ! $append && isset($t->sort) && $t->sort ) {
+ $values = array();
+ $term_order = 0;
+ $final_tt_ids = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'tt_ids'));
+ foreach ( $tt_ids as $tt_id )
+ if ( in_array($tt_id, $final_tt_ids) )
+ $values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order);
+ if ( $values )
+ if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)" ) )
+ return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database' ), $wpdb->last_error );
+ }
+
+ wp_cache_delete( $object_id, $taxonomy . '_relationships' );
+
+ do_action('set_object_terms', $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids);
+ return $tt_ids;
+}
+
+/**
+ * Add term(s) associated with a given object.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.6
+ * @uses wp_set_object_terms()
+ *
+ * @param int $object_id The ID of the object to which the terms will be added.
+ * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to add.
+ * @param array|string $taxonomy Taxonomy name.
+ * @return array|WP_Error Affected Term IDs
+ */
+function wp_add_object_terms( $object_id, $terms, $taxonomy ) {
+ return wp_set_object_terms( $object_id, $terms, $taxonomy, true );
+}
+
+/**
+ * Remove term(s) associated with a given object.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.6
+ * @uses $wpdb
+ *
+ * @uses apply_filters() Calls 'delete_term_relationships' hook with object_id and tt_ids as parameters.
+ * @uses apply_filters() Calls 'deleted_term_relationships' hook with object_id and tt_ids as parameters.
+ *
+ * @param int $object_id The ID of the object from which the terms will be removed.
+ * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to remove.
+ * @param array|string $taxonomy Taxonomy name.
+ * @return bool|WP_Error True on success, false or WP_Error on failure.
+ */
+function wp_remove_object_terms( $object_id, $terms, $taxonomy ) {
+ global $wpdb;
+
+ $object_id = (int) $object_id;
+
+ if ( ! taxonomy_exists( $taxonomy ) ) {
+ return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) );
+ }
+
+ if ( ! is_array( $terms ) ) {
+ $terms = array( $terms );
+ }
+
+ $tt_ids = array();
+
+ foreach ( (array) $terms as $term ) {
+ if ( ! strlen( trim( $term ) ) ) {
+ continue;
+ }
+
+ if ( ! $term_info = term_exists( $term, $taxonomy ) ) {
+ // Skip if a non-existent term ID is passed.
+ if ( is_int( $term ) ) {
+ continue;
+ }
+ }
+
+ if ( is_wp_error( $term_info ) ) {
+ return $term_info;
+ }
+
+ $tt_ids[] = $term_info['term_taxonomy_id'];
+ }
+
+ if ( $tt_ids ) {
+ $in_tt_ids = "'" . implode( "', '", $tt_ids ) . "'";
+ do_action( 'delete_term_relationships', $object_id, $tt_ids );
+ $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) );
+ do_action( 'deleted_term_relationships', $object_id, $tt_ids );
+ wp_update_term_count( $tt_ids, $taxonomy );
+
+ return (bool) $deleted;
+ }
+
+ return false;
+}
+
+/**
+ * Will make slug unique, if it isn't already.
+ *
+ * The $slug has to be unique global to every taxonomy, meaning that one
+ * taxonomy term can't have a matching slug with another taxonomy term. Each
+ * slug has to be globally unique for every taxonomy.
+ *
+ * The way this works is that if the taxonomy that the term belongs to is
+ * hierarchical and has a parent, it will append that parent to the $slug.
+ *
+ * If that still doesn't return an unique slug, then it try to append a number
+ * until it finds a number that is truly unique.
+ *
+ * The only purpose for $term is for appending a parent, if one exists.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param string $slug The string that will be tried for a unique slug
+ * @param object $term The term object that the $slug will belong too
+ * @return string Will return a true unique slug.
+ */
+function wp_unique_term_slug($slug, $term) {
+ global $wpdb;
+
+ if ( ! term_exists( $slug ) )
+ return $slug;
+
+ // If the taxonomy supports hierarchy and the term has a parent, make the slug unique
+ // by incorporating parent slugs.
+ if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) {
+ $the_parent = $term->parent;
+ while ( ! empty($the_parent) ) {
+ $parent_term = get_term($the_parent, $term->taxonomy);
+ if ( is_wp_error($parent_term) || empty($parent_term) )
+ break;
+ $slug .= '-' . $parent_term->slug;
+ if ( ! term_exists( $slug ) )
+ return $slug;
+
+ if ( empty($parent_term->parent) )
+ break;
+ $the_parent = $parent_term->parent;
+ }
+ }
+
+ // If we didn't get a unique slug, try appending a number to make it unique.
+ if ( !empty($args['term_id']) )
+ $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $args['term_id'] );
+ else
+ $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
+
+ if ( $wpdb->get_var( $query ) ) {
+ $num = 2;
+ do {
+ $alt_slug = $slug . "-$num";
+ $num++;
+ $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
+ } while ( $slug_check );
+ $slug = $alt_slug;
+ }
+
+ return $slug;
+}
+
+/**
+ * Update term based on arguments provided.
+ *
+ * The $args will indiscriminately override all values with the same field name.
+ * Care must be taken to not override important information need to update or
+ * update will fail (or perhaps create a new term, neither would be acceptable).
+ *
+ * Defaults will set 'alias_of', 'description', 'parent', and 'slug' if not
+ * defined in $args already.
+ *
+ * 'alias_of' will create a term group, if it doesn't already exist, and update
+ * it for the $term.
+ *
+ * If the 'slug' argument in $args is missing, then the 'name' in $args will be
+ * used. It should also be noted that if you set 'slug' and it isn't unique then
+ * a WP_Error will be passed back. If you don't pass any slug, then a unique one
+ * will be created for you.
+ *
+ * For what can be overrode in $args, check the term scheme can contain and stay
+ * away from the term keys.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses $wpdb
+ * @uses do_action() Will call both 'edit_term' and 'edit_$taxonomy' twice.
+ * @uses apply_filters() Will call the 'term_id_filter' filter and pass the term
+ * id and taxonomy id.
+ *
+ * @param int $term_id The ID of the term
+ * @param string $taxonomy The context in which to relate the term to the object.
+ * @param array|string $args Overwrite term field values
+ * @return array|WP_Error Returns Term ID and Taxonomy Term ID
+ */
+function wp_update_term( $term_id, $taxonomy, $args = array() ) {
+ global $wpdb;
+
+ if ( ! taxonomy_exists($taxonomy) )
+ return new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
+
+ $term_id = (int) $term_id;
+
+ // First, get all of the original args
+ $term = get_term ($term_id, $taxonomy, ARRAY_A);
+
+ if ( is_wp_error( $term ) )
+ return $term;
+
+ // Escape data pulled from DB.
+ $term = wp_slash($term);
+
+ // Merge old and new args with new args overwriting old ones.
+ $args = array_merge($term, $args);
+
+ $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => '');
+ $args = wp_parse_args($args, $defaults);
+ $args = sanitize_term($args, $taxonomy, 'db');
+ extract($args, EXTR_SKIP);
+
+ // expected_slashed ($name)
+ $name = wp_unslash($name);
+ $description = wp_unslash($description);
+
+ if ( '' == trim($name) )
+ return new WP_Error('empty_term_name', __('A name is required for this term'));
+
+ $empty_slug = false;
+ if ( empty($slug) ) {
+ $empty_slug = true;
+ $slug = sanitize_title($name);
+ }
+
+ if ( $alias_of ) {
+ $alias = $wpdb->get_row( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $alias_of) );
+ if ( $alias->term_group ) {
+ // The alias we want is already in a group, so let's use that one.
+ $term_group = $alias->term_group;
+ } else {
+ // The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
+ $term_group = $wpdb->get_var("SELECT MAX(term_group) FROM $wpdb->terms") + 1;
+ do_action( 'edit_terms', $alias->term_id, $taxonomy );
+ $wpdb->update( $wpdb->terms, compact('term_group'), array( 'term_id' => $alias->term_id ) );
+ do_action( 'edited_terms', $alias->term_id, $taxonomy );
+ }
+ }
+
+ // Check $parent to see if it will cause a hierarchy loop
+ $parent = apply_filters( 'wp_update_term_parent', $parent, $term_id, $taxonomy, compact( array_keys( $args ) ), $args );
+
+ // Check for duplicate slug
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) );
+ if ( $id && ($id != $term_id) ) {
+ // If an empty slug was passed or the parent changed, reset the slug to something unique.
+ // Otherwise, bail.
+ if ( $empty_slug || ( $parent != $term['parent']) )
+ $slug = wp_unique_term_slug($slug, (object) $args);
+ else
+ return new WP_Error('duplicate_term_slug', sprintf(__('The slug &#8220;%s&#8221; is already in use by another term'), $slug));
+ }
+ do_action( 'edit_terms', $term_id, $taxonomy );
+ $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) );
+ if ( empty($slug) ) {
+ $slug = sanitize_title($name, $term_id);
+ $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) );
+ }
+ do_action( 'edited_terms', $term_id, $taxonomy );
+
+ $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) );
+ do_action( 'edit_term_taxonomy', $tt_id, $taxonomy );
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
+ do_action( 'edited_term_taxonomy', $tt_id, $taxonomy );
+
+ do_action("edit_term", $term_id, $tt_id, $taxonomy);
+ do_action("edit_$taxonomy", $term_id, $tt_id);
+
+ $term_id = apply_filters('term_id_filter', $term_id, $tt_id);
+
+ clean_term_cache($term_id, $taxonomy);
+
+ do_action("edited_term", $term_id, $tt_id, $taxonomy);
+ do_action("edited_$taxonomy", $term_id, $tt_id);
+
+ return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id);
+}
+
+/**
+ * Enable or disable term counting.
+ *
+ * @since 2.5.0
+ *
+ * @param bool $defer Optional. Enable if true, disable if false.
+ * @return bool Whether term counting is enabled or disabled.
+ */
+function wp_defer_term_counting($defer=null) {
+ static $_defer = false;
+
+ if ( is_bool($defer) ) {
+ $_defer = $defer;
+ // flush any deferred counts
+ if ( !$defer )
+ wp_update_term_count( null, null, true );
+ }
+
+ return $_defer;
+}
+
+/**
+ * Updates the amount of terms in taxonomy.
+ *
+ * If there is a taxonomy callback applied, then it will be called for updating
+ * the count.
+ *
+ * The default action is to count what the amount of terms have the relationship
+ * of term ID. Once that is done, then update the database.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $terms The term_taxonomy_id of the terms
+ * @param string $taxonomy The context of the term.
+ * @return bool If no terms will return false, and if successful will return true.
+ */
+function wp_update_term_count( $terms, $taxonomy, $do_deferred=false ) {
+ static $_deferred = array();
+
+ if ( $do_deferred ) {
+ foreach ( (array) array_keys($_deferred) as $tax ) {
+ wp_update_term_count_now( $_deferred[$tax], $tax );
+ unset( $_deferred[$tax] );
+ }
+ }
+
+ if ( empty($terms) )
+ return false;
+
+ if ( !is_array($terms) )
+ $terms = array($terms);
+
+ if ( wp_defer_term_counting() ) {
+ if ( !isset($_deferred[$taxonomy]) )
+ $_deferred[$taxonomy] = array();
+ $_deferred[$taxonomy] = array_unique( array_merge($_deferred[$taxonomy], $terms) );
+ return true;
+ }
+
+ return wp_update_term_count_now( $terms, $taxonomy );
+}
+
+/**
+ * Perform term count update immediately.
+ *
+ * @since 2.5.0
+ *
+ * @param array $terms The term_taxonomy_id of terms to update.
+ * @param string $taxonomy The context of the term.
+ * @return bool Always true when complete.
+ */
+function wp_update_term_count_now( $terms, $taxonomy ) {
+ global $wpdb;
+
+ $terms = array_map('intval', $terms);
+
+ $taxonomy = get_taxonomy($taxonomy);
+ if ( !empty($taxonomy->update_count_callback) ) {
+ call_user_func($taxonomy->update_count_callback, $terms, $taxonomy);
+ } else {
+ $object_types = (array) $taxonomy->object_type;
+ foreach ( $object_types as &$object_type ) {
+ if ( 0 === strpos( $object_type, 'attachment:' ) )
+ list( $object_type ) = explode( ':', $object_type );
+ }
+
+ if ( $object_types == array_filter( $object_types, 'post_type_exists' ) ) {
+ // Only post types are attached to this taxonomy
+ _update_post_term_count( $terms, $taxonomy );
+ } else {
+ // Default count updater
+ _update_generic_term_count( $terms, $taxonomy );
+ }
+ }
+
+ clean_term_cache($terms, '', false);
+
+ return true;
+}
+
+//
+// Cache
+//
+
+/**
+ * Removes the taxonomy relationship to terms from the cache.
+ *
+ * Will remove the entire taxonomy relationship containing term $object_id. The
+ * term IDs have to exist within the taxonomy $object_type for the deletion to
+ * take place.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @see get_object_taxonomies() for more on $object_type
+ * @uses do_action() Will call action hook named, 'clean_object_term_cache' after completion.
+ * Passes, function params in same order.
+ *
+ * @param int|array $object_ids Single or list of term object ID(s)
+ * @param array|string $object_type The taxonomy object type
+ */
+function clean_object_term_cache($object_ids, $object_type) {
+ if ( !is_array($object_ids) )
+ $object_ids = array($object_ids);
+
+ $taxonomies = get_object_taxonomies( $object_type );
+
+ foreach ( $object_ids as $id )
+ foreach ( $taxonomies as $taxonomy )
+ wp_cache_delete($id, "{$taxonomy}_relationships");
+
+ do_action('clean_object_term_cache', $object_ids, $object_type);
+}
+
+/**
+ * Will remove all of the term ids from the cache.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param int|array $ids Single or list of Term IDs
+ * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
+ * @param bool $clean_taxonomy Whether to clean taxonomy wide caches (true), or just individual term object caches (false). Default is true.
+ */
+function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
+ global $wpdb;
+ static $cleaned = array();
+
+ if ( !is_array($ids) )
+ $ids = array($ids);
+
+ $taxonomies = array();
+ // If no taxonomy, assume tt_ids.
+ if ( empty($taxonomy) ) {
+ $tt_ids = array_map('intval', $ids);
+ $tt_ids = implode(', ', $tt_ids);
+ $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)");
+ $ids = array();
+ foreach ( (array) $terms as $term ) {
+ $taxonomies[] = $term->taxonomy;
+ $ids[] = $term->term_id;
+ wp_cache_delete($term->term_id, $term->taxonomy);
+ }
+ $taxonomies = array_unique($taxonomies);
+ } else {
+ $taxonomies = array($taxonomy);
+ foreach ( $taxonomies as $taxonomy ) {
+ foreach ( $ids as $id ) {
+ wp_cache_delete($id, $taxonomy);
+ }
+ }
+ }
+
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( isset($cleaned[$taxonomy]) )
+ continue;
+ $cleaned[$taxonomy] = true;
+
+ if ( $clean_taxonomy ) {
+ wp_cache_delete('all_ids', $taxonomy);
+ wp_cache_delete('get', $taxonomy);
+ delete_option("{$taxonomy}_children");
+ // Regenerate {$taxonomy}_children
+ _get_term_hierarchy($taxonomy);
+ }
+
+ do_action('clean_term_cache', $ids, $taxonomy);
+ }
+
+ wp_cache_set( 'last_changed', microtime(), 'terms' );
+}
+
+/**
+ * Retrieves the taxonomy relationship to the term object id.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @uses wp_cache_get() Retrieves taxonomy relationship from cache
+ *
+ * @param int|array $id Term object ID
+ * @param string $taxonomy Taxonomy Name
+ * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id.
+ */
+function get_object_term_cache($id, $taxonomy) {
+ $cache = wp_cache_get($id, "{$taxonomy}_relationships");
+ return $cache;
+}
+
+/**
+ * Updates the cache for Term ID(s).
+ *
+ * Will only update the cache for terms not already cached.
+ *
+ * The $object_ids expects that the ids be separated by commas, if it is a
+ * string.
+ *
+ * It should be noted that update_object_term_cache() is very time extensive. It
+ * is advised that the function is not called very often or at least not for a
+ * lot of terms that exist in a lot of taxonomies. The amount of time increases
+ * for each term and it also increases for each taxonomy the term belongs to.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ * @uses wp_get_object_terms() Used to get terms from the database to update
+ *
+ * @param string|array $object_ids Single or list of term object ID(s)
+ * @param array|string $object_type The taxonomy object type
+ * @return null|bool Null value is given with empty $object_ids. False if
+ */
+function update_object_term_cache($object_ids, $object_type) {
+ if ( empty($object_ids) )
+ return;
+
+ if ( !is_array($object_ids) )
+ $object_ids = explode(',', $object_ids);
+
+ $object_ids = array_map('intval', $object_ids);
+
+ $taxonomies = get_object_taxonomies($object_type);
+
+ $ids = array();
+ foreach ( (array) $object_ids as $id ) {
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( false === wp_cache_get($id, "{$taxonomy}_relationships") ) {
+ $ids[] = $id;
+ break;
+ }
+ }
+ }
+
+ if ( empty( $ids ) )
+ return false;
+
+ $terms = wp_get_object_terms($ids, $taxonomies, array('fields' => 'all_with_object_id'));
+
+ $object_terms = array();
+ foreach ( (array) $terms as $term )
+ $object_terms[$term->object_id][$term->taxonomy][$term->term_id] = $term;
+
+ foreach ( $ids as $id ) {
+ foreach ( $taxonomies as $taxonomy ) {
+ if ( ! isset($object_terms[$id][$taxonomy]) ) {
+ if ( !isset($object_terms[$id]) )
+ $object_terms[$id] = array();
+ $object_terms[$id][$taxonomy] = array();
+ }
+ }
+ }
+
+ foreach ( $object_terms as $id => $value ) {
+ foreach ( $value as $taxonomy => $terms ) {
+ wp_cache_add( $id, $terms, "{$taxonomy}_relationships" );
+ }
+ }
+}
+
+/**
+ * Updates Terms to Taxonomy in cache.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 2.3.0
+ *
+ * @param array $terms List of Term objects to change
+ * @param string $taxonomy Optional. Update Term to this taxonomy in cache
+ */
+function update_term_cache($terms, $taxonomy = '') {
+ foreach ( (array) $terms as $term ) {
+ $term_taxonomy = $taxonomy;
+ if ( empty($term_taxonomy) )
+ $term_taxonomy = $term->taxonomy;
+
+ wp_cache_add($term->term_id, $term, $term_taxonomy);
+ }
+}
+
+//
+// Private
+//
+
+/**
+ * Retrieves children of taxonomy as Term IDs.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ *
+ * @uses update_option() Stores all of the children in "$taxonomy_children"
+ * option. That is the name of the taxonomy, immediately followed by '_children'.
+ *
+ * @param string $taxonomy Taxonomy Name
+ * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
+ */
+function _get_term_hierarchy($taxonomy) {
+ if ( !is_taxonomy_hierarchical($taxonomy) )
+ return array();
+ $children = get_option("{$taxonomy}_children");
+
+ if ( is_array($children) )
+ return $children;
+ $children = array();
+ $terms = get_terms($taxonomy, array('get' => 'all', 'orderby' => 'id', 'fields' => 'id=>parent'));
+ foreach ( $terms as $term_id => $parent ) {
+ if ( $parent > 0 )
+ $children[$parent][] = $term_id;
+ }
+ update_option("{$taxonomy}_children", $children);
+
+ return $children;
+}
+
+/**
+ * Get the subset of $terms that are descendants of $term_id.
+ *
+ * If $terms is an array of objects, then _get_term_children returns an array of objects.
+ * If $terms is an array of IDs, then _get_term_children returns an array of IDs.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ *
+ * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id.
+ * @param array $terms The set of terms---either an array of term objects or term IDs---from which those that are descendants of $term_id will be chosen.
+ * @param string $taxonomy The taxonomy which determines the hierarchy of the terms.
+ * @return array The subset of $terms that are descendants of $term_id.
+ */
+function _get_term_children($term_id, $terms, $taxonomy) {
+ $empty_array = array();
+ if ( empty($terms) )
+ return $empty_array;
+
+ $term_list = array();
+ $has_children = _get_term_hierarchy($taxonomy);
+
+ if ( ( 0 != $term_id ) && ! isset($has_children[$term_id]) )
+ return $empty_array;
+
+ foreach ( (array) $terms as $term ) {
+ $use_id = false;
+ if ( !is_object($term) ) {
+ $term = get_term($term, $taxonomy);
+ if ( is_wp_error( $term ) )
+ return $term;
+ $use_id = true;
+ }
+
+ if ( $term->term_id == $term_id )
+ continue;
+
+ if ( $term->parent == $term_id ) {
+ if ( $use_id )
+ $term_list[] = $term->term_id;
+ else
+ $term_list[] = $term;
+
+ if ( !isset($has_children[$term->term_id]) )
+ continue;
+
+ if ( $children = _get_term_children($term->term_id, $terms, $taxonomy) )
+ $term_list = array_merge($term_list, $children);
+ }
+ }
+
+ return $term_list;
+}
+
+/**
+ * Add count of children to parent count.
+ *
+ * Recalculates term counts by including items from child terms. Assumes all
+ * relevant children are already in the $terms argument.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param array $terms List of Term IDs
+ * @param string $taxonomy Term Context
+ * @return null Will break from function if conditions are not met.
+ */
+function _pad_term_counts(&$terms, $taxonomy) {
+ global $wpdb;
+
+ // This function only works for hierarchical taxonomies like post categories.
+ if ( !is_taxonomy_hierarchical( $taxonomy ) )
+ return;
+
+ $term_hier = _get_term_hierarchy($taxonomy);
+
+ if ( empty($term_hier) )
+ return;
+
+ $term_items = array();
+
+ foreach ( (array) $terms as $key => $term ) {
+ $terms_by_id[$term->term_id] = & $terms[$key];
+ $term_ids[$term->term_taxonomy_id] = $term->term_id;
+ }
+
+ // Get the object and term ids and stick them in a lookup table
+ $tax_obj = get_taxonomy($taxonomy);
+ $object_types = esc_sql($tax_obj->object_type);
+ $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'");
+ foreach ( $results as $row ) {
+ $id = $term_ids[$row->term_taxonomy_id];
+ $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
+ }
+
+ // Touch every ancestor's lookup row for each post in each term
+ foreach ( $term_ids as $term_id ) {
+ $child = $term_id;
+ while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) {
+ if ( !empty( $term_items[$term_id] ) )
+ foreach ( $term_items[$term_id] as $item_id => $touches ) {
+ $term_items[$parent][$item_id] = isset($term_items[$parent][$item_id]) ? ++$term_items[$parent][$item_id]: 1;
+ }
+ $child = $parent;
+ }
+ }
+
+ // Transfer the touched cells
+ foreach ( (array) $term_items as $id => $items )
+ if ( isset($terms_by_id[$id]) )
+ $terms_by_id[$id]->count = count($items);
+}
+
+//
+// Default callbacks
+//
+
+/**
+ * Will update term count based on object types of the current taxonomy.
+ *
+ * Private function for the default callback for post_tag and category
+ * taxonomies.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @access private
+ * @since 2.3.0
+ * @uses $wpdb
+ *
+ * @param array $terms List of Term taxonomy IDs
+ * @param object $taxonomy Current taxonomy object of terms
+ */
+function _update_post_term_count( $terms, $taxonomy ) {
+ global $wpdb;
+
+ $object_types = (array) $taxonomy->object_type;
+
+ foreach ( $object_types as &$object_type )
+ list( $object_type ) = explode( ':', $object_type );
+
+ $object_types = array_unique( $object_types );
+
+ if ( false !== ( $check_attachments = array_search( 'attachment', $object_types ) ) ) {
+ unset( $object_types[ $check_attachments ] );
+ $check_attachments = true;
+ }
+
+ if ( $object_types )
+ $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
+
+ foreach ( (array) $terms as $term ) {
+ $count = 0;
+
+ // Attachments can be 'inherit' status, we need to base count off the parent's status if so
+ if ( $check_attachments )
+ $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) );
+
+ if ( $object_types )
+ $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) );
+
+ do_action( 'edit_term_taxonomy', $term, $taxonomy );
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
+ do_action( 'edited_term_taxonomy', $term, $taxonomy );
+ }
+}
+
+/**
+ * Will update term count based on number of objects.
+ *
+ * Default callback for the link_category taxonomy.
+ *
+ * @package WordPress
+ * @subpackage Taxonomy
+ * @since 3.3.0
+ * @uses $wpdb
+ *
+ * @param array $terms List of Term taxonomy IDs
+ * @param object $taxonomy Current taxonomy object of terms
+ */
+function _update_generic_term_count( $terms, $taxonomy ) {
+ global $wpdb;
+
+ foreach ( (array) $terms as $term ) {
+ $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term ) );
+
+ do_action( 'edit_term_taxonomy', $term, $taxonomy );
+ $wpdb->update( $wpdb->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );
+ do_action( 'edited_term_taxonomy', $term, $taxonomy );
+ }
+}
+
+/**
+ * Generates a permalink for a taxonomy term archive.
+ *
+ * @since 2.5.0
+ *
+ * @uses apply_filters() Calls 'term_link' with term link and term object, and taxonomy parameters.
+ * @uses apply_filters() For the post_tag Taxonomy, Calls 'tag_link' with tag link and tag ID as parameters.
+ * @uses apply_filters() For the category Taxonomy, Calls 'category_link' filter on category link and category ID.
+ *
+ * @param object|int|string $term
+ * @param string $taxonomy (optional if $term is object)
+ * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
+ */
+function get_term_link( $term, $taxonomy = '') {
+ global $wp_rewrite;
+
+ if ( !is_object($term) ) {
+ if ( is_int($term) ) {
+ $term = get_term($term, $taxonomy);
+ } else {
+ $term = get_term_by('slug', $term, $taxonomy);
+ }
+ }
+
+ if ( !is_object($term) )
+ $term = new WP_Error('invalid_term', __('Empty Term'));
+
+ if ( is_wp_error( $term ) )
+ return $term;
+
+ $taxonomy = $term->taxonomy;
+
+ $termlink = $wp_rewrite->get_extra_permastruct($taxonomy);
+
+ $slug = $term->slug;
+ $t = get_taxonomy($taxonomy);
+
+ if ( empty($termlink) ) {
+ if ( 'category' == $taxonomy )
+ $termlink = '?cat=' . $term->term_id;
+ elseif ( $t->query_var )
+ $termlink = "?$t->query_var=$slug";
+ else
+ $termlink = "?taxonomy=$taxonomy&term=$slug";
+ $termlink = home_url($termlink);
+ } else {
+ if ( $t->rewrite['hierarchical'] ) {
+ $hierarchical_slugs = array();
+ $ancestors = get_ancestors($term->term_id, $taxonomy);
+ foreach ( (array)$ancestors as $ancestor ) {
+ $ancestor_term = get_term($ancestor, $taxonomy);
+ $hierarchical_slugs[] = $ancestor_term->slug;
+ }
+ $hierarchical_slugs = array_reverse($hierarchical_slugs);
+ $hierarchical_slugs[] = $slug;
+ $termlink = str_replace("%$taxonomy%", implode('/', $hierarchical_slugs), $termlink);
+ } else {
+ $termlink = str_replace("%$taxonomy%", $slug, $termlink);
+ }
+ $termlink = home_url( user_trailingslashit($termlink, 'category') );
+ }
+ // Back Compat filters.
+ if ( 'post_tag' == $taxonomy )
+ $termlink = apply_filters( 'tag_link', $termlink, $term->term_id );
+ elseif ( 'category' == $taxonomy )
+ $termlink = apply_filters( 'category_link', $termlink, $term->term_id );
+
+ return apply_filters('term_link', $termlink, $term, $taxonomy);
+}
+
+/**
+ * Display the taxonomies of a post with available options.
+ *
+ * This function can be used within the loop to display the taxonomies for a
+ * post without specifying the Post ID. You can also use it outside the Loop to
+ * display the taxonomies for a specific post.
+ *
+ * The available defaults are:
+ * 'post' : default is 0. The post ID to get taxonomies of.
+ * 'before' : default is empty string. Display before taxonomies list.
+ * 'sep' : default is empty string. Separate every taxonomy with value in this.
+ * 'after' : default is empty string. Display this after the taxonomies list.
+ * 'template' : The template to use for displaying the taxonomy terms.
+ *
+ * @since 2.5.0
+ * @uses get_the_taxonomies()
+ *
+ * @param array $args Override the defaults.
+ */
+function the_taxonomies($args = array()) {
+ $defaults = array(
+ 'post' => 0,
+ 'before' => '',
+ 'sep' => ' ',
+ 'after' => '',
+ 'template' => '%s: %l.'
+ );
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ echo $before . join($sep, get_the_taxonomies($post, $r)) . $after;
+}
+
+/**
+ * Retrieve all taxonomies associated with a post.
+ *
+ * This function can be used within the loop. It will also return an array of
+ * the taxonomies with links to the taxonomy and name.
+ *
+ * @since 2.5.0
+ *
+ * @param int $post Optional. Post ID or will use Global Post ID (in loop).
+ * @param array $args Override the defaults.
+ * @return array
+ */
+function get_the_taxonomies($post = 0, $args = array() ) {
+ $post = get_post( $post );
+
+ $args = wp_parse_args( $args, array(
+ 'template' => '%s: %l.',
+ ) );
+ extract( $args, EXTR_SKIP );
+
+ $taxonomies = array();
+
+ if ( !$post )
+ return $taxonomies;
+
+ foreach ( get_object_taxonomies($post) as $taxonomy ) {
+ $t = (array) get_taxonomy($taxonomy);
+ if ( empty($t['label']) )
+ $t['label'] = $taxonomy;
+ if ( empty($t['args']) )
+ $t['args'] = array();
+ if ( empty($t['template']) )
+ $t['template'] = $template;
+
+ $terms = get_object_term_cache($post->ID, $taxonomy);
+ if ( false === $terms )
+ $terms = wp_get_object_terms($post->ID, $taxonomy, $t['args']);
+
+ $links = array();
+
+ foreach ( $terms as $term )
+ $links[] = "<a href='" . esc_attr( get_term_link($term) ) . "'>$term->name</a>";
+
+ if ( $links )
+ $taxonomies[$taxonomy] = wp_sprintf($t['template'], $t['label'], $links, $terms);
+ }
+ return $taxonomies;
+}
+
+/**
+ * Retrieve all taxonomies of a post with just the names.
+ *
+ * @since 2.5.0
+ * @uses get_object_taxonomies()
+ *
+ * @param int $post Optional. Post ID
+ * @return array
+ */
+function get_post_taxonomies($post = 0) {
+ $post = get_post( $post );
+
+ return get_object_taxonomies($post);
+}
+
+/**
+ * Determine if the given object is associated with any of the given terms.
+ *
+ * The given terms are checked against the object's terms' term_ids, names and slugs.
+ * Terms given as integers will only be checked against the object's terms' term_ids.
+ * If no terms are given, determines if object is associated with any terms in the given taxonomy.
+ *
+ * @since 2.7.0
+ * @uses get_object_term_cache()
+ * @uses wp_get_object_terms()
+ *
+ * @param int $object_id ID of the object (post ID, link ID, ...)
+ * @param string $taxonomy Single taxonomy name
+ * @param int|string|array $terms Optional. Term term_id, name, slug or array of said
+ * @return bool|WP_Error. WP_Error on input error.
+ */
+function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
+ if ( !$object_id = (int) $object_id )
+ return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) );
+
+ $object_terms = get_object_term_cache( $object_id, $taxonomy );
+ if ( false === $object_terms )
+ $object_terms = wp_get_object_terms( $object_id, $taxonomy );
+
+ if ( is_wp_error( $object_terms ) )
+ return $object_terms;
+ if ( empty( $object_terms ) )
+ return false;
+ if ( empty( $terms ) )
+ return ( !empty( $object_terms ) );
+
+ $terms = (array) $terms;
+
+ if ( $ints = array_filter( $terms, 'is_int' ) )
+ $strs = array_diff( $terms, $ints );
+ else
+ $strs =& $terms;
+
+ foreach ( $object_terms as $object_term ) {
+ if ( $ints && in_array( $object_term->term_id, $ints ) ) return true; // If int, check against term_id
+ if ( $strs ) {
+ if ( in_array( $object_term->term_id, $strs ) ) return true;
+ if ( in_array( $object_term->name, $strs ) ) return true;
+ if ( in_array( $object_term->slug, $strs ) ) return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Determine if the given object type is associated with the given taxonomy.
+ *
+ * @since 3.0.0
+ * @uses get_object_taxonomies()
+ *
+ * @param string $object_type Object type string
+ * @param string $taxonomy Single taxonomy name
+ * @return bool True if object is associated with the taxonomy, otherwise false.
+ */
+function is_object_in_taxonomy($object_type, $taxonomy) {
+ $taxonomies = get_object_taxonomies($object_type);
+
+ if ( empty($taxonomies) )
+ return false;
+
+ if ( in_array($taxonomy, $taxonomies) )
+ return true;
+
+ return false;
+}
+
+/**
+ * Get an array of ancestor IDs for a given object.
+ *
+ * @param int $object_id The ID of the object
+ * @param string $object_type The type of object for which we'll be retrieving ancestors.
+ * @return array of ancestors from lowest to highest in the hierarchy.
+ */
+function get_ancestors($object_id = 0, $object_type = '') {
+ $object_id = (int) $object_id;
+
+ $ancestors = array();
+
+ if ( empty( $object_id ) ) {
+ return apply_filters('get_ancestors', $ancestors, $object_id, $object_type);
+ }
+
+ if ( is_taxonomy_hierarchical( $object_type ) ) {
+ $term = get_term($object_id, $object_type);
+ while ( ! is_wp_error($term) && ! empty( $term->parent ) && ! in_array( $term->parent, $ancestors ) ) {
+ $ancestors[] = (int) $term->parent;
+ $term = get_term($term->parent, $object_type);
+ }
+ } elseif ( post_type_exists( $object_type ) ) {
+ $ancestors = get_post_ancestors($object_id);
+ }
+
+ return apply_filters('get_ancestors', $ancestors, $object_id, $object_type);
+}
+
+/**
+ * Returns the term's parent's term_ID
+ *
+ * @since 3.1.0
+ *
+ * @param int $term_id
+ * @param string $taxonomy
+ *
+ * @return int|bool false on error
+ */
+function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) {
+ $term = get_term( $term_id, $taxonomy );
+ if ( !$term || is_wp_error( $term ) )
+ return false;
+ return (int) $term->parent;
+}
+
+/**
+ * Checks the given subset of the term hierarchy for hierarchy loops.
+ * Prevents loops from forming and breaks those that it finds.
+ *
+ * Attached to the wp_update_term_parent filter.
+ *
+ * @since 3.1.0
+ * @uses wp_find_hierarchy_loop()
+ *
+ * @param int $parent term_id of the parent for the term we're checking.
+ * @param int $term_id The term we're checking.
+ * @param string $taxonomy The taxonomy of the term we're checking.
+ *
+ * @return int The new parent for the term.
+ */
+function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) {
+ // Nothing fancy here - bail
+ if ( !$parent )
+ return 0;
+
+ // Can't be its own parent
+ if ( $parent == $term_id )
+ return 0;
+
+ // Now look for larger loops
+
+ if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) )
+ return $parent; // No loop
+
+ // Setting $parent to the given value causes a loop
+ if ( isset( $loop[$term_id] ) )
+ return 0;
+
+ // There's a loop, but it doesn't contain $term_id. Break the loop.
+ foreach ( array_keys( $loop ) as $loop_member )
+ wp_update_term( $loop_member, $taxonomy, array( 'parent' => 0 ) );
+
+ return $parent;
+}
diff --git a/src/wp-includes/template-loader.php b/src/wp-includes/template-loader.php
new file mode 100644
index 0000000000..7051f3452b
--- /dev/null
+++ b/src/wp-includes/template-loader.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Loads the correct template based on the visitor's url
+ * @package WordPress
+ */
+if ( defined('WP_USE_THEMES') && WP_USE_THEMES )
+ do_action('template_redirect');
+
+// Halt template load for HEAD requests. Performance bump. See #14348
+if ( 'HEAD' === $_SERVER['REQUEST_METHOD'] && apply_filters( 'exit_on_http_head', true ) )
+ exit();
+
+// Process feeds and trackbacks even if not using themes.
+if ( is_robots() ) :
+ do_action('do_robots');
+ return;
+elseif ( is_feed() ) :
+ do_feed();
+ return;
+elseif ( is_trackback() ) :
+ include( ABSPATH . 'wp-trackback.php' );
+ return;
+endif;
+
+if ( defined('WP_USE_THEMES') && WP_USE_THEMES ) :
+ $template = false;
+ if ( is_404() && $template = get_404_template() ) :
+ elseif ( is_search() && $template = get_search_template() ) :
+ elseif ( is_tax() && $template = get_taxonomy_template() ) :
+ elseif ( is_front_page() && $template = get_front_page_template() ) :
+ elseif ( is_home() && $template = get_home_template() ) :
+ elseif ( is_attachment() && $template = get_attachment_template() ) :
+ remove_filter('the_content', 'prepend_attachment');
+ elseif ( is_single() && $template = get_single_template() ) :
+ elseif ( is_page() && $template = get_page_template() ) :
+ elseif ( is_category() && $template = get_category_template() ) :
+ elseif ( is_tag() && $template = get_tag_template() ) :
+ elseif ( is_author() && $template = get_author_template() ) :
+ elseif ( is_date() && $template = get_date_template() ) :
+ elseif ( is_archive() && $template = get_archive_template() ) :
+ elseif ( is_comments_popup() && $template = get_comments_popup_template() ) :
+ elseif ( is_paged() && $template = get_paged_template() ) :
+ else :
+ $template = get_index_template();
+ endif;
+ if ( $template = apply_filters( 'template_include', $template ) )
+ include( $template );
+ return;
+endif;
diff --git a/src/wp-includes/template.php b/src/wp-includes/template.php
new file mode 100644
index 0000000000..5bee8ad52d
--- /dev/null
+++ b/src/wp-includes/template.php
@@ -0,0 +1,411 @@
+<?php
+/**
+ * Template loading functions.
+ *
+ * @package WordPress
+ * @subpackage Template
+ */
+
+/**
+ * Retrieve path to a template
+ *
+ * Used to quickly retrieve the path of a template without including the file
+ * extension. It will also check the parent theme, if the file exists, with
+ * the use of {@link locate_template()}. Allows for more generic template location
+ * without the use of the other get_*_template() functions.
+ *
+ * @since 1.5.0
+ *
+ * @param string $type Filename without extension.
+ * @param array $templates An optional list of template candidates
+ * @return string Full path to file.
+ */
+function get_query_template( $type, $templates = array() ) {
+ $type = preg_replace( '|[^a-z0-9-]+|', '', $type );
+
+ if ( empty( $templates ) )
+ $templates = array("{$type}.php");
+
+ return apply_filters( "{$type}_template", locate_template( $templates ) );
+}
+
+/**
+ * Retrieve path of index template in current or parent template.
+ *
+ * @since 3.0.0
+ *
+ * @return string
+ */
+function get_index_template() {
+ return get_query_template('index');
+}
+
+/**
+ * Retrieve path of 404 template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_404_template() {
+ return get_query_template('404');
+}
+
+/**
+ * Retrieve path of archive template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_archive_template() {
+ $post_types = array_filter( (array) get_query_var( 'post_type' ) );
+
+ $templates = array();
+
+ if ( count( $post_types ) == 1 ) {
+ $post_type = reset( $post_types );
+ $templates[] = "archive-{$post_type}.php";
+ }
+ $templates[] = 'archive.php';
+
+ return get_query_template( 'archive', $templates );
+}
+
+/**
+ * Retrieve path of author template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_author_template() {
+ $author = get_queried_object();
+
+ $templates = array();
+
+ if ( $author ) {
+ $templates[] = "author-{$author->user_nicename}.php";
+ $templates[] = "author-{$author->ID}.php";
+ }
+ $templates[] = 'author.php';
+
+ return get_query_template( 'author', $templates );
+}
+
+/**
+ * Retrieve path of category template in current or parent template.
+ *
+ * Works by first retrieving the current slug, for example 'category-default.php', and then
+ * trying category ID, for example 'category-1.php', and will finally fall back to category.php
+ * template, if those files don't exist.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'category_template' on file path of category template.
+ *
+ * @return string
+ */
+function get_category_template() {
+ $category = get_queried_object();
+
+ $templates = array();
+
+ if ( $category ) {
+ $templates[] = "category-{$category->slug}.php";
+ $templates[] = "category-{$category->term_id}.php";
+ }
+ $templates[] = 'category.php';
+
+ return get_query_template( 'category', $templates );
+}
+
+/**
+ * Retrieve path of tag template in current or parent template.
+ *
+ * Works by first retrieving the current tag name, for example 'tag-wordpress.php', and then
+ * trying tag ID, for example 'tag-1.php', and will finally fall back to tag.php
+ * template, if those files don't exist.
+ *
+ * @since 2.3.0
+ * @uses apply_filters() Calls 'tag_template' on file path of tag template.
+ *
+ * @return string
+ */
+function get_tag_template() {
+ $tag = get_queried_object();
+
+ $templates = array();
+
+ if ( $tag ) {
+ $templates[] = "tag-{$tag->slug}.php";
+ $templates[] = "tag-{$tag->term_id}.php";
+ }
+ $templates[] = 'tag.php';
+
+ return get_query_template( 'tag', $templates );
+}
+
+/**
+ * Retrieve path of taxonomy template in current or parent template.
+ *
+ * Retrieves the taxonomy and term, if term is available. The template is
+ * prepended with 'taxonomy-' and followed by both the taxonomy string and
+ * the taxonomy string followed by a dash and then followed by the term.
+ *
+ * The taxonomy and term template is checked and used first, if it exists.
+ * Second, just the taxonomy template is checked, and then finally, taxonomy.php
+ * template is used. If none of the files exist, then it will fall back on to
+ * index.php.
+ *
+ * @since 2.5.0
+ * @uses apply_filters() Calls 'taxonomy_template' filter on found path.
+ *
+ * @return string
+ */
+function get_taxonomy_template() {
+ $term = get_queried_object();
+
+ $templates = array();
+
+ if ( $term ) {
+ $taxonomy = $term->taxonomy;
+ $templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
+ $templates[] = "taxonomy-$taxonomy.php";
+ }
+ $templates[] = 'taxonomy.php';
+
+ return get_query_template( 'taxonomy', $templates );
+}
+
+/**
+ * Retrieve path of date template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_date_template() {
+ return get_query_template('date');
+}
+
+/**
+ * Retrieve path of home template in current or parent template.
+ *
+ * This is the template used for the page containing the blog posts.
+ *
+ * Attempts to locate 'home.php' first before falling back to 'index.php'.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'home_template' on file path of home template.
+ *
+ * @return string
+ */
+function get_home_template() {
+ $templates = array( 'home.php', 'index.php' );
+
+ return get_query_template( 'home', $templates );
+}
+
+/**
+ * Retrieve path of front-page template in current or parent template.
+ *
+ * Looks for 'front-page.php'.
+ *
+ * @since 3.0.0
+ * @uses apply_filters() Calls 'front_page_template' on file path of template.
+ *
+ * @return string
+ */
+function get_front_page_template() {
+ $templates = array('front-page.php');
+
+ return get_query_template( 'front_page', $templates );
+}
+
+/**
+ * Retrieve path of page template in current or parent template.
+ *
+ * Will first look for the specifically assigned page template.
+ * Then will search for 'page-{slug}.php', followed by 'page-{id}.php',
+ * and finally 'page.php'.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_page_template() {
+ $id = get_queried_object_id();
+ $template = get_page_template_slug();
+ $pagename = get_query_var('pagename');
+
+ if ( ! $pagename && $id ) {
+ // If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
+ $post = get_queried_object();
+ $pagename = $post->post_name;
+ }
+
+ $templates = array();
+ if ( $template && 0 === validate_file( $template ) )
+ $templates[] = $template;
+ if ( $pagename )
+ $templates[] = "page-$pagename.php";
+ if ( $id )
+ $templates[] = "page-$id.php";
+ $templates[] = 'page.php';
+
+ return get_query_template( 'page', $templates );
+}
+
+/**
+ * Retrieve path of paged template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_paged_template() {
+ return get_query_template('paged');
+}
+
+/**
+ * Retrieve path of search template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_search_template() {
+ return get_query_template('search');
+}
+
+/**
+ * Retrieve path of single template in current or parent template.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_single_template() {
+ $object = get_queried_object();
+
+ $templates = array();
+
+ if ( $object )
+ $templates[] = "single-{$object->post_type}.php";
+ $templates[] = "single.php";
+
+ return get_query_template( 'single', $templates );
+}
+
+/**
+ * Retrieve path of attachment template in current or parent template.
+ *
+ * The attachment path first checks if the first part of the mime type exists.
+ * The second check is for the second part of the mime type. The last check is
+ * for both types separated by an underscore. If neither are found then the file
+ * 'attachment.php' is checked and returned.
+ *
+ * Some examples for the 'text/plain' mime type are 'text.php', 'plain.php', and
+ * finally 'text_plain.php'.
+ *
+ * @since 2.0.0
+ *
+ * @return string
+ */
+function get_attachment_template() {
+ global $posts;
+
+ if ( ! empty( $posts ) && isset( $posts[0]->post_mime_type ) ) {
+ $type = explode( '/', $posts[0]->post_mime_type );
+
+ if ( ! empty( $type ) ) {
+ if ( $template = get_query_template( $type[0] ) )
+ return $template;
+ elseif ( $template = get_query_template( $type[1] ) )
+ return $template;
+ elseif ( $template = get_query_template( "$type[0]_$type[1]" ) )
+ return $template;
+ }
+ }
+
+ return get_query_template( 'attachment' );
+}
+
+/**
+ * Retrieve path of comment popup template in current or parent template.
+ *
+ * Checks for comment popup template in current template, if it exists or in the
+ * parent template.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'comments_popup_template' filter on path.
+ *
+ * @return string
+ */
+function get_comments_popup_template() {
+ $template = get_query_template( 'comments_popup', array( 'comments-popup.php' ) );
+
+ // Backward compat code will be removed in a future release
+ if ('' == $template)
+ $template = ABSPATH . WPINC . '/theme-compat/comments-popup.php';
+
+ return $template;
+}
+
+/**
+ * Retrieve the name of the highest priority template file that exists.
+ *
+ * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
+ * inherit from a parent theme can just overload one file.
+ *
+ * @since 2.7.0
+ *
+ * @param string|array $template_names Template file(s) to search for, in order.
+ * @param bool $load If true the template file will be loaded if it is found.
+ * @param bool $require_once Whether to require_once or require. Default true. Has no effect if $load is false.
+ * @return string The template filename if one is located.
+ */
+function locate_template($template_names, $load = false, $require_once = true ) {
+ $located = '';
+ foreach ( (array) $template_names as $template_name ) {
+ if ( !$template_name )
+ continue;
+ if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
+ $located = STYLESHEETPATH . '/' . $template_name;
+ break;
+ } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
+ $located = TEMPLATEPATH . '/' . $template_name;
+ break;
+ }
+ }
+
+ if ( $load && '' != $located )
+ load_template( $located, $require_once );
+
+ return $located;
+}
+
+/**
+ * Require the template file with WordPress environment.
+ *
+ * The globals are set up for the template file to ensure that the WordPress
+ * environment is available from within the function. The query variables are
+ * also available.
+ *
+ * @since 1.5.0
+ *
+ * @param string $_template_file Path to template file.
+ * @param bool $require_once Whether to require_once or require. Default true.
+ */
+function load_template( $_template_file, $require_once = true ) {
+ global $posts, $post, $wp_did_header, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
+
+ if ( is_array( $wp_query->query_vars ) )
+ extract( $wp_query->query_vars, EXTR_SKIP );
+
+ if ( $require_once )
+ require_once( $_template_file );
+ else
+ require( $_template_file );
+}
+
diff --git a/src/wp-includes/theme-compat/comments-popup.php b/src/wp-includes/theme-compat/comments-popup.php
new file mode 100644
index 0000000000..eb74834cd3
--- /dev/null
+++ b/src/wp-includes/theme-compat/comments-popup.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Theme_Compat
+ * @deprecated 3.0
+ *
+ * This file is here for Backwards compatibility with old themes and will be removed in a future version
+ *
+ */
+_deprecated_file( sprintf( __( 'Theme without %1$s' ), basename(__FILE__) ), '3.0', null, sprintf( __('Please include a %1$s template in your theme.'), basename(__FILE__) ) );
+?><!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title><?php printf(__('%1$s - Comments on %2$s'), get_option('blogname'), the_title('','',false)); ?></title>
+
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php echo get_option('blog_charset'); ?>" />
+ <style type="text/css" media="screen">
+ @import url( <?php bloginfo('stylesheet_url'); ?> );
+ body { margin: 3px; }
+ </style>
+
+</head>
+<body id="commentspopup">
+
+<h1 id="header"><a href="" title="<?php echo get_option('blogname'); ?>"><?php echo get_option('blogname'); ?></a></h1>
+
+<?php
+/* Don't remove these lines. */
+add_filter('comment_text', 'popuplinks');
+if ( have_posts() ) :
+while( have_posts()) : the_post();
+?>
+<h2 id="comments"><?php _e('Comments'); ?></h2>
+
+<p><a href="<?php echo esc_url( get_post_comments_feed_link($post->ID) ); ?>"><?php _e('<abbr title="Really Simple Syndication">RSS</abbr> feed for comments on this post.'); ?></a></p>
+
+<?php if ( pings_open() ) { ?>
+<p><?php printf(__('The <abbr title="Universal Resource Locator">URL</abbr> to TrackBack this entry is: <em>%s</em>'), get_trackback_url()); ?></p>
+<?php } ?>
+
+<?php
+// this line is WordPress' motor, do not delete it.
+$commenter = wp_get_current_commenter();
+extract($commenter);
+$comments = get_approved_comments($id);
+$post = get_post($id);
+if ( post_password_required($post) ) { // and it doesn't match the cookie
+ echo(get_the_password_form());
+} else { ?>
+
+<?php if ($comments) { ?>
+<ol id="commentlist">
+<?php foreach ($comments as $comment) { ?>
+ <li id="comment-<?php comment_ID() ?>">
+ <?php comment_text() ?>
+ <p><cite><?php comment_type(); ?> <?php printf(__('by %1$s &#8212; %2$s @ <a href="#comment-%3$s">%4$s</a>'), get_comment_author_link(), get_comment_date(), get_comment_ID(), get_comment_time()); ?></cite></p>
+ </li>
+
+<?php } // end for each comment ?>
+</ol>
+<?php } else { // this is displayed if there are no comments so far ?>
+ <p><?php _e('No comments yet.'); ?></p>
+<?php } ?>
+
+<?php if ( comments_open() ) { ?>
+<h2><?php _e('Leave a comment'); ?></h2>
+<p><?php printf(__('Line and paragraph breaks automatic, e-mail address never displayed, <acronym title="Hypertext Markup Language">HTML</acronym> allowed: <code>%s</code>'), allowed_tags()); ?></p>
+
+<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
+<?php if ( $user_ID ) : ?>
+ <p><?php printf(__('Logged in as <a href="%1$s">%2$s</a>. <a href="%3$s" title="Log out of this account">Log out &raquo;</a>'), get_edit_user_link(), $user_identity, wp_logout_url(get_permalink())); ?></p>
+<?php else : ?>
+ <p>
+ <input type="text" name="author" id="author" class="textarea" value="<?php echo esc_attr($comment_author); ?>" size="28" tabindex="1" />
+ <label for="author"><?php _e('Name'); ?></label>
+ </p>
+
+ <p>
+ <input type="text" name="email" id="email" value="<?php echo esc_attr($comment_author_email); ?>" size="28" tabindex="2" />
+ <label for="email"><?php _e('E-mail'); ?></label>
+ </p>
+
+ <p>
+ <input type="text" name="url" id="url" value="<?php echo esc_attr($comment_author_url); ?>" size="28" tabindex="3" />
+ <label for="url"><?php _e('<abbr title="Universal Resource Locator">URL</abbr>'); ?></label>
+ </p>
+<?php endif; ?>
+
+ <p>
+ <label for="comment"><?php _e('Your Comment'); ?></label>
+ <br />
+ <textarea name="comment" id="comment" cols="70" rows="4" tabindex="4"></textarea>
+ </p>
+
+ <p>
+ <input type="hidden" name="comment_post_ID" value="<?php echo $id; ?>" />
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($_SERVER["REQUEST_URI"]); ?>" />
+ <input name="submit" type="submit" tabindex="5" value="<?php esc_attr_e('Say It!' ); ?>" />
+ </p>
+ <?php do_action('comment_form', $post->ID); ?>
+</form>
+<?php } else { // comments are closed ?>
+<p><?php _e('Sorry, the comment form is closed at this time.'); ?></p>
+<?php }
+} // end password check
+?>
+
+<div><strong><a href="javascript:window.close()"><?php _e('Close this window.'); ?></a></strong></div>
+
+<?php // if you delete this the sky will fall on your head
+endwhile; // have_posts()
+else: // have_posts()
+?>
+<p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
+<?php endif; ?>
+<!-- // this is just the end of the motor - don't touch that line either :) -->
+<?php //} ?>
+<p class="credit"><?php timer_stop(1); ?> <cite><?php printf(__('Powered by <a href="%s" title="Powered by WordPress, state-of-the-art semantic personal publishing platform"><strong>WordPress</strong></a>'), 'http://wordpress.org/'); ?></cite></p>
+<?php // Seen at http://www.mijnkopthee.nl/log2/archive/2003/05/28/esc(18) ?>
+<script type="text/javascript">
+<!--
+document.onkeypress = function esc(e) {
+ if(typeof(e) == "undefined") { e=event; }
+ if (e.keyCode == 27) { self.close(); }
+}
+// -->
+</script>
+</body>
+</html>
diff --git a/src/wp-includes/theme-compat/comments.php b/src/wp-includes/theme-compat/comments.php
new file mode 100644
index 0000000000..75a85ed46e
--- /dev/null
+++ b/src/wp-includes/theme-compat/comments.php
@@ -0,0 +1,101 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Theme_Compat
+ * @deprecated 3.0
+ *
+ * This file is here for Backwards compatibility with old themes and will be removed in a future version
+ *
+ */
+_deprecated_file( sprintf( __( 'Theme without %1$s' ), basename(__FILE__) ), '3.0', null, sprintf( __('Please include a %1$s template in your theme.'), basename(__FILE__) ) );
+
+// Do not delete these lines
+ if (!empty($_SERVER['SCRIPT_FILENAME']) && 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']))
+ die ('Please do not load this page directly. Thanks!');
+
+ if ( post_password_required() ) { ?>
+ <p class="nocomments"><?php _e('This post is password protected. Enter the password to view comments.'); ?></p>
+ <?php
+ return;
+ }
+?>
+
+<!-- You can start editing here. -->
+
+<?php if ( have_comments() ) : ?>
+ <h3 id="comments"><?php printf( _n( 'One Response to %2$s', '%1$s Responses to %2$s', get_comments_number() ),
+ number_format_i18n( get_comments_number() ), '&#8220;' . get_the_title() . '&#8221;' ); ?></h3>
+
+ <div class="navigation">
+ <div class="alignleft"><?php previous_comments_link() ?></div>
+ <div class="alignright"><?php next_comments_link() ?></div>
+ </div>
+
+ <ol class="commentlist">
+ <?php wp_list_comments();?>
+ </ol>
+
+ <div class="navigation">
+ <div class="alignleft"><?php previous_comments_link() ?></div>
+ <div class="alignright"><?php next_comments_link() ?></div>
+ </div>
+ <?php else : // this is displayed if there are no comments so far ?>
+
+ <?php if ( comments_open() ) : ?>
+ <!-- If comments are open, but there are no comments. -->
+
+ <?php else : // comments are closed ?>
+ <!-- If comments are closed. -->
+ <p class="nocomments"><?php _e('Comments are closed.'); ?></p>
+
+ <?php endif; ?>
+<?php endif; ?>
+
+<?php if ( comments_open() ) : ?>
+
+<div id="respond">
+
+<h3><?php comment_form_title( __('Leave a Reply'), __('Leave a Reply to %s' ) ); ?></h3>
+
+<div id="cancel-comment-reply">
+ <small><?php cancel_comment_reply_link() ?></small>
+</div>
+
+<?php if ( get_option('comment_registration') && !is_user_logged_in() ) : ?>
+<p><?php printf(__('You must be <a href="%s">logged in</a> to post a comment.'), wp_login_url( get_permalink() )); ?></p>
+<?php else : ?>
+
+<form action="<?php echo get_option('siteurl'); ?>/wp-comments-post.php" method="post" id="commentform">
+
+<?php if ( is_user_logged_in() ) : ?>
+
+<p><?php printf(__('Logged in as <a href="%1$s">%2$s</a>.'), get_edit_user_link(), $user_identity); ?> <a href="<?php echo wp_logout_url(get_permalink()); ?>" title="<?php esc_attr_e('Log out of this account'); ?>"><?php _e('Log out &raquo;'); ?></a></p>
+
+<?php else : ?>
+
+<p><input type="text" name="author" id="author" value="<?php echo esc_attr($comment_author); ?>" size="22" tabindex="1" <?php if ($req) echo "aria-required='true'"; ?> />
+<label for="author"><small><?php _e('Name'); ?> <?php if ($req) _e('(required)'); ?></small></label></p>
+
+<p><input type="text" name="email" id="email" value="<?php echo esc_attr($comment_author_email); ?>" size="22" tabindex="2" <?php if ($req) echo "aria-required='true'"; ?> />
+<label for="email"><small><?php _e('Mail (will not be published)'); ?> <?php if ($req) _e('(required)'); ?></small></label></p>
+
+<p><input type="text" name="url" id="url" value="<?php echo esc_attr($comment_author_url); ?>" size="22" tabindex="3" />
+<label for="url"><small><?php _e('Website'); ?></small></label></p>
+
+<?php endif; ?>
+
+<!--<p><small><?php printf(__('<strong>XHTML:</strong> You can use these tags: <code>%s</code>'), allowed_tags()); ?></small></p>-->
+
+<p><textarea name="comment" id="comment" cols="58" rows="10" tabindex="4"></textarea></p>
+
+<p><input name="submit" type="submit" id="submit" tabindex="5" value="<?php esc_attr_e('Submit Comment'); ?>" />
+<?php comment_id_fields(); ?>
+</p>
+<?php do_action('comment_form', $post->ID); ?>
+
+</form>
+
+<?php endif; // If registration required and not logged in ?>
+</div>
+
+<?php endif; // if you delete this the sky will fall on your head ?>
diff --git a/src/wp-includes/theme-compat/footer.php b/src/wp-includes/theme-compat/footer.php
new file mode 100644
index 0000000000..0e987edef4
--- /dev/null
+++ b/src/wp-includes/theme-compat/footer.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Theme_Compat
+ * @deprecated 3.0
+ *
+ * This file is here for Backwards compatibility with old themes and will be removed in a future version
+ *
+ */
+_deprecated_file( sprintf( __( 'Theme without %1$s' ), basename(__FILE__) ), '3.0', null, sprintf( __('Please include a %1$s template in your theme.'), basename(__FILE__) ) );
+?>
+
+<hr />
+<div id="footer" role="contentinfo">
+<!-- If you'd like to support WordPress, having the "powered by" link somewhere on your blog is the best way; it's our only promotion or advertising. -->
+ <p>
+ <?php printf(__('%1$s is proudly powered by %2$s'), get_bloginfo('name'),
+ '<a href="http://wordpress.org/">WordPress</a>'); ?>
+ <br /><?php printf(__('%1$s and %2$s.'), '<a href="' . get_bloginfo('rss2_url') . '">' . __('Entries (RSS)') . '</a>', '<a href="' . get_bloginfo('comments_rss2_url') . '">' . __('Comments (RSS)') . '</a>'); ?>
+ <!-- <?php printf(__('%d queries. %s seconds.'), get_num_queries(), timer_stop(0, 3)); ?> -->
+ </p>
+</div>
+</div>
+
+<!-- Gorgeous design by Michael Heilemann - http://binarybonsai.com/kubrick/ -->
+<?php /* "Just what do you think you're doing Dave?" */ ?>
+
+ <?php wp_footer(); ?>
+</body>
+</html>
diff --git a/src/wp-includes/theme-compat/header.php b/src/wp-includes/theme-compat/header.php
new file mode 100644
index 0000000000..2758773b1e
--- /dev/null
+++ b/src/wp-includes/theme-compat/header.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Theme_Compat
+ * @deprecated 3.0
+ *
+ * This file is here for Backwards compatibility with old themes and will be removed in a future version
+ *
+ */
+_deprecated_file( sprintf( __( 'Theme without %1$s' ), basename(__FILE__) ), '3.0', null, sprintf( __('Please include a %1$s template in your theme.'), basename(__FILE__) ) );
+?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+
+<head profile="http://gmpg.org/xfn/11">
+<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
+
+<title><?php wp_title('&laquo;', true, 'right'); ?> <?php bloginfo('name'); ?></title>
+
+<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css" media="screen" />
+<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />
+
+<style type="text/css" media="screen">
+
+<?php
+// Checks to see whether it needs a sidebar
+if ( empty($withcomments) && !is_single() ) {
+?>
+ #page { background: url("<?php bloginfo('stylesheet_directory'); ?>/images/kubrickbg-<?php bloginfo('text_direction'); ?>.jpg") repeat-y top; border: none; }
+<?php } else { // No sidebar ?>
+ #page { background: url("<?php bloginfo('stylesheet_directory'); ?>/images/kubrickbgwide.jpg") repeat-y top; border: none; }
+<?php } ?>
+
+</style>
+
+<?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); ?>
+
+<?php wp_head(); ?>
+</head>
+<body <?php body_class(); ?>>
+<div id="page">
+
+<div id="header" role="banner">
+ <div id="headerimg">
+ <h1><a href="<?php echo home_url(); ?>/"><?php bloginfo('name'); ?></a></h1>
+ <div class="description"><?php bloginfo('description'); ?></div>
+ </div>
+</div>
+<hr />
diff --git a/src/wp-includes/theme-compat/sidebar.php b/src/wp-includes/theme-compat/sidebar.php
new file mode 100644
index 0000000000..7c0939b6b8
--- /dev/null
+++ b/src/wp-includes/theme-compat/sidebar.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * @package WordPress
+ * @subpackage Theme_Compat
+ * @deprecated 3.0
+ *
+ * This file is here for Backwards compatibility with old themes and will be removed in a future version
+ *
+ */
+_deprecated_file( sprintf( __( 'Theme without %1$s' ), basename(__FILE__) ), '3.0', null, sprintf( __('Please include a %1$s template in your theme.'), basename(__FILE__) ) );
+?>
+ <div id="sidebar" role="complementary">
+ <ul>
+ <?php /* Widgetized sidebar, if you have the plugin installed. */
+ if ( !function_exists('dynamic_sidebar') || !dynamic_sidebar() ) : ?>
+ <li>
+ <?php get_search_form(); ?>
+ </li>
+
+ <!-- Author information is disabled per default. Uncomment and fill in your details if you want to use it.
+ <li><h2><?php _e('Author'); ?></h2>
+ <p>A little something about you, the author. Nothing lengthy, just an overview.</p>
+ </li>
+ -->
+
+ <?php if ( is_404() || is_category() || is_day() || is_month() ||
+ is_year() || is_search() || is_paged() ) {
+ ?> <li>
+
+ <?php /* If this is a 404 page */ if (is_404()) { ?>
+ <?php /* If this is a category archive */ } elseif (is_category()) { ?>
+ <p><?php printf(__('You are currently browsing the archives for the %s category.'), single_cat_title('', false)); ?></p>
+
+ <?php /* If this is a daily archive */ } elseif (is_day()) { ?>
+ <p><?php printf(__('You are currently browsing the <a href="%1$s/">%2$s</a> blog archives for the day %3$s.'), get_bloginfo('url'), get_bloginfo('name'), get_the_time(__('l, F jS, Y'))); ?></p>
+
+ <?php /* If this is a monthly archive */ } elseif (is_month()) { ?>
+ <p><?php printf(__('You are currently browsing the <a href="%1$s/">%2$s</a> blog archives for %3$s.'), get_bloginfo('url'), get_bloginfo('name'), get_the_time(__('F, Y'))); ?></p>
+
+ <?php /* If this is a yearly archive */ } elseif (is_year()) { ?>
+ <p><?php printf(__('You are currently browsing the <a href="%1$s/">%2$s</a> blog archives for the year %3$s.'), get_bloginfo('url'), get_bloginfo('name'), get_the_time('Y')); ?></p>
+
+ <?php /* If this is a search result */ } elseif (is_search()) { ?>
+ <p><?php printf(__('You have searched the <a href="%1$s/">%2$s</a> blog archives for <strong>&#8216;%3$s&#8217;</strong>. If you are unable to find anything in these search results, you can try one of these links.'), get_bloginfo('url'), get_bloginfo('name'), esc_html( get_search_query() ) ); ?></p>
+
+ <?php /* If this set is paginated */ } elseif (isset($_GET['paged']) && !empty($_GET['paged'])) { ?>
+ <p><?php printf(__('You are currently browsing the <a href="%1$s/">%2$s</a> blog archives.'), get_bloginfo('url'), get_bloginfo('name')); ?></p>
+
+ <?php } ?>
+
+ </li>
+ <?php }?>
+ </ul>
+ <ul role="navigation">
+ <?php wp_list_pages('title_li=<h2>' . __('Pages') . '</h2>' ); ?>
+
+ <li><h2><?php _e('Archives'); ?></h2>
+ <ul>
+ <?php wp_get_archives(array('type' => 'monthly')); ?>
+ </ul>
+ </li>
+
+ <?php wp_list_categories(array('show_count' => 1, 'title_li' => '<h2>' . __('Categories') . '</h2>')); ?>
+ </ul>
+ <ul>
+ <?php /* If this is the frontpage */ if ( is_home() || is_page() ) { ?>
+ <?php wp_list_bookmarks(); ?>
+
+ <li><h2><?php _e('Meta'); ?></h2>
+ <ul>
+ <?php wp_register(); ?>
+ <li><?php wp_loginout(); ?></li>
+ <li><a href="http://validator.w3.org/check/referer" title="<?php esc_attr_e('This page validates as XHTML 1.0 Transitional'); ?>"><?php _e('Valid <abbr title="eXtensible HyperText Markup Language">XHTML</abbr>'); ?></a></li>
+ <li><a href="http://gmpg.org/xfn/"><abbr title="<?php esc_attr_e('XHTML Friends Network'); ?>"><?php _e('XFN'); ?></abbr></a></li>
+ <li><a href="http://wordpress.org/" title="<?php esc_attr_e('Powered by WordPress, state-of-the-art semantic personal publishing platform.'); ?>">WordPress</a></li>
+ <?php wp_meta(); ?>
+ </ul>
+ </li>
+ <?php } ?>
+
+ <?php endif; ?>
+ </ul>
+ </div>
diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php
new file mode 100644
index 0000000000..68863a382a
--- /dev/null
+++ b/src/wp-includes/theme.php
@@ -0,0 +1,1730 @@
+<?php
+/**
+ * Theme, template, and stylesheet functions.
+ *
+ * @package WordPress
+ * @subpackage Theme
+ */
+
+/**
+ * Returns an array of WP_Theme objects based on the arguments.
+ *
+ * Despite advances over get_themes(), this function is quite expensive, and grows
+ * linearly with additional themes. Stick to wp_get_theme() if possible.
+ *
+ * @since 3.4.0
+ *
+ * @param array $args The search arguments. Optional.
+ * - errors mixed True to return themes with errors, false to return themes without errors, null
+ * to return all themes. Defaults to false.
+ * - allowed mixed (Multisite) True to return only allowed themes for a site. False to return only
+ * disallowed themes for a site. 'site' to return only site-allowed themes. 'network'
+ * to return only network-allowed themes. Null to return all themes. Defaults to null.
+ * - blog_id int (Multisite) The blog ID used to calculate which themes are allowed. Defaults to 0,
+ * synonymous for the current blog.
+ * @return Array of WP_Theme objects.
+ */
+function wp_get_themes( $args = array() ) {
+ global $wp_theme_directories;
+
+ $defaults = array( 'errors' => false, 'allowed' => null, 'blog_id' => 0 );
+ $args = wp_parse_args( $args, $defaults );
+
+ $theme_directories = search_theme_directories();
+
+ if ( count( $wp_theme_directories ) > 1 ) {
+ // Make sure the current theme wins out, in case search_theme_directories() picks the wrong
+ // one in the case of a conflict. (Normally, last registered theme root wins.)
+ $current_theme = get_stylesheet();
+ if ( isset( $theme_directories[ $current_theme ] ) ) {
+ $root_of_current_theme = get_raw_theme_root( $current_theme );
+ if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) )
+ $root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
+ $theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
+ }
+ }
+
+ if ( empty( $theme_directories ) )
+ return array();
+
+ if ( is_multisite() && null !== $args['allowed'] ) {
+ $allowed = $args['allowed'];
+ if ( 'network' === $allowed )
+ $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
+ elseif ( 'site' === $allowed )
+ $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
+ elseif ( $allowed )
+ $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
+ else
+ $theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
+ }
+
+ $themes = array();
+ static $_themes = array();
+
+ foreach ( $theme_directories as $theme => $theme_root ) {
+ if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) )
+ $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
+ else
+ $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
+ }
+
+ if ( null !== $args['errors'] ) {
+ foreach ( $themes as $theme => $wp_theme ) {
+ if ( $wp_theme->errors() != $args['errors'] )
+ unset( $themes[ $theme ] );
+ }
+ }
+
+ return $themes;
+}
+
+/**
+ * Gets a WP_Theme object for a theme.
+ *
+ * @since 3.4.0
+ *
+ * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
+ * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root()
+ * is used to calculate the theme root for the $stylesheet provided (or current theme).
+ * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence.
+ */
+function wp_get_theme( $stylesheet = null, $theme_root = null ) {
+ global $wp_theme_directories;
+
+ if ( empty( $stylesheet ) )
+ $stylesheet = get_stylesheet();
+
+ if ( empty( $theme_root ) ) {
+ $theme_root = get_raw_theme_root( $stylesheet );
+ if ( false === $theme_root )
+ $theme_root = WP_CONTENT_DIR . '/themes';
+ elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
+ $theme_root = WP_CONTENT_DIR . $theme_root;
+ }
+
+ return new WP_Theme( $stylesheet, $theme_root );
+}
+
+/**
+ * Clears the cache held by get_theme_roots() and WP_Theme.
+ *
+ * @since 3.5.0
+ */
+function wp_clean_themes_cache() {
+ delete_site_transient('update_themes');
+ search_theme_directories( true );
+ foreach ( wp_get_themes( array( 'errors' => null ) ) as $theme )
+ $theme->cache_delete();
+}
+
+/**
+ * Whether a child theme is in use.
+ *
+ * @since 3.0.0
+ *
+ * @return bool true if a child theme is in use, false otherwise.
+ **/
+function is_child_theme() {
+ return ( TEMPLATEPATH !== STYLESHEETPATH );
+}
+
+/**
+ * Retrieve name of the current stylesheet.
+ *
+ * The theme name that the administrator has currently set the front end theme
+ * as.
+ *
+ * For all extensive purposes, the template name and the stylesheet name are
+ * going to be the same for most cases.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
+ *
+ * @return string Stylesheet name.
+ */
+function get_stylesheet() {
+ return apply_filters('stylesheet', get_option('stylesheet'));
+}
+
+/**
+ * Retrieve stylesheet directory path for current theme.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
+ *
+ * @return string Path to current theme directory.
+ */
+function get_stylesheet_directory() {
+ $stylesheet = get_stylesheet();
+ $theme_root = get_theme_root( $stylesheet );
+ $stylesheet_dir = "$theme_root/$stylesheet";
+
+ return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
+}
+
+/**
+ * Retrieve stylesheet directory URI.
+ *
+ * @since 1.5.0
+ *
+ * @return string
+ */
+function get_stylesheet_directory_uri() {
+ $stylesheet = get_stylesheet();
+ $theme_root_uri = get_theme_root_uri( $stylesheet );
+ $stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
+
+ return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
+}
+
+/**
+ * Retrieve URI of current theme stylesheet.
+ *
+ * The stylesheet file name is 'style.css' which is appended to {@link
+ * get_stylesheet_directory_uri() stylesheet directory URI} path.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
+ *
+ * @return string
+ */
+function get_stylesheet_uri() {
+ $stylesheet_dir_uri = get_stylesheet_directory_uri();
+ $stylesheet_uri = $stylesheet_dir_uri . '/style.css';
+ return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
+}
+
+/**
+ * Retrieve localized stylesheet URI.
+ *
+ * The stylesheet directory for the localized stylesheet files are located, by
+ * default, in the base theme directory. The name of the locale file will be the
+ * locale followed by '.css'. If that does not exist, then the text direction
+ * stylesheet will be checked for existence, for example 'ltr.css'.
+ *
+ * The theme may change the location of the stylesheet directory by either using
+ * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
+ * If you want to change the location of the stylesheet files for the entire
+ * WordPress workflow, then change the former. If you just have the locale in a
+ * separate folder, then change the latter.
+ *
+ * @since 2.1.0
+ * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
+ *
+ * @return string
+ */
+function get_locale_stylesheet_uri() {
+ global $wp_locale;
+ $stylesheet_dir_uri = get_stylesheet_directory_uri();
+ $dir = get_stylesheet_directory();
+ $locale = get_locale();
+ if ( file_exists("$dir/$locale.css") )
+ $stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
+ elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
+ $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
+ else
+ $stylesheet_uri = '';
+ return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
+}
+
+/**
+ * Retrieve name of the current theme.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'template' filter on template option.
+ *
+ * @return string Template name.
+ */
+function get_template() {
+ return apply_filters('template', get_option('template'));
+}
+
+/**
+ * Retrieve current theme directory.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
+ *
+ * @return string Template directory path.
+ */
+function get_template_directory() {
+ $template = get_template();
+ $theme_root = get_theme_root( $template );
+ $template_dir = "$theme_root/$template";
+
+ return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
+}
+
+/**
+ * Retrieve theme directory URI.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
+ *
+ * @return string Template directory URI.
+ */
+function get_template_directory_uri() {
+ $template = get_template();
+ $theme_root_uri = get_theme_root_uri( $template );
+ $template_dir_uri = "$theme_root_uri/$template";
+
+ return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
+}
+
+/**
+ * Retrieve theme roots.
+ *
+ * @since 2.9.0
+ *
+ * @return array|string An array of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
+ */
+function get_theme_roots() {
+ global $wp_theme_directories;
+
+ if ( count($wp_theme_directories) <= 1 )
+ return '/themes';
+
+ $theme_roots = get_site_transient( 'theme_roots' );
+ if ( false === $theme_roots ) {
+ search_theme_directories( true ); // Regenerate the transient.
+ $theme_roots = get_site_transient( 'theme_roots' );
+ }
+ return $theme_roots;
+}
+
+/**
+ * Register a directory that contains themes.
+ *
+ * @since 2.9.0
+ *
+ * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
+ * @return bool
+ */
+function register_theme_directory( $directory ) {
+ global $wp_theme_directories;
+
+ if ( ! file_exists( $directory ) ) {
+ // Try prepending as the theme directory could be relative to the content directory
+ $directory = WP_CONTENT_DIR . '/' . $directory;
+ // If this directory does not exist, return and do not register
+ if ( ! file_exists( $directory ) )
+ return false;
+ }
+
+ $wp_theme_directories[] = $directory;
+
+ return true;
+}
+
+/**
+ * Search all registered theme directories for complete and valid themes.
+ *
+ * @since 2.9.0
+ *
+ * @param bool $force Optional. Whether to force a new directory scan. Defaults to false.
+ * @return array Valid themes found
+ */
+function search_theme_directories( $force = false ) {
+ global $wp_theme_directories;
+ if ( empty( $wp_theme_directories ) )
+ return false;
+
+ static $found_themes;
+ if ( ! $force && isset( $found_themes ) )
+ return $found_themes;
+
+ $found_themes = array();
+
+ $wp_theme_directories = (array) $wp_theme_directories;
+
+ // Set up maybe-relative, maybe-absolute array of theme directories.
+ // We always want to return absolute, but we need to cache relative
+ // to use in get_theme_root().
+ foreach ( $wp_theme_directories as $theme_root ) {
+ if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
+ $relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
+ else
+ $relative_theme_roots[ $theme_root ] = $theme_root;
+ }
+
+ if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
+ $cached_roots = get_site_transient( 'theme_roots' );
+ if ( is_array( $cached_roots ) ) {
+ foreach ( $cached_roots as $theme_dir => $theme_root ) {
+ // A cached theme root is no longer around, so skip it.
+ if ( ! isset( $relative_theme_roots[ $theme_root ] ) )
+ continue;
+ $found_themes[ $theme_dir ] = array(
+ 'theme_file' => $theme_dir . '/style.css',
+ 'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
+ );
+ }
+ return $found_themes;
+ }
+ if ( ! is_int( $cache_expiration ) )
+ $cache_expiration = 1800; // half hour
+ } else {
+ $cache_expiration = 1800; // half hour
+ }
+
+ /* Loop the registered theme directories and extract all themes */
+ foreach ( $wp_theme_directories as $theme_root ) {
+
+ // Start with directories in the root of the current theme directory.
+ $dirs = @ scandir( $theme_root );
+ if ( ! $dirs ) {
+ trigger_error( "$theme_root is not readable", E_USER_NOTICE );
+ continue;
+ }
+ foreach ( $dirs as $dir ) {
+ if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
+ continue;
+ if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
+ // wp-content/themes/a-single-theme
+ // wp-content/themes is $theme_root, a-single-theme is $dir
+ $found_themes[ $dir ] = array(
+ 'theme_file' => $dir . '/style.css',
+ 'theme_root' => $theme_root,
+ );
+ } else {
+ $found_theme = false;
+ // wp-content/themes/a-folder-of-themes/*
+ // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs
+ $sub_dirs = @ scandir( $theme_root . '/' . $dir );
+ if ( ! $sub_dirs ) {
+ trigger_error( "$theme_root/$dir is not readable", E_USER_NOTICE );
+ continue;
+ }
+ foreach ( $sub_dirs as $sub_dir ) {
+ if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' )
+ continue;
+ if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) )
+ continue;
+ $found_themes[ $dir . '/' . $sub_dir ] = array(
+ 'theme_file' => $dir . '/' . $sub_dir . '/style.css',
+ 'theme_root' => $theme_root,
+ );
+ $found_theme = true;
+ }
+ // Never mind the above, it's just a theme missing a style.css.
+ // Return it; WP_Theme will catch the error.
+ if ( ! $found_theme )
+ $found_themes[ $dir ] = array(
+ 'theme_file' => $dir . '/style.css',
+ 'theme_root' => $theme_root,
+ );
+ }
+ }
+ }
+
+ asort( $found_themes );
+
+ $theme_roots = array();
+ $relative_theme_roots = array_flip( $relative_theme_roots );
+
+ foreach ( $found_themes as $theme_dir => $theme_data ) {
+ $theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
+ }
+
+ if ( $theme_roots != get_site_transient( 'theme_roots' ) )
+ set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
+
+ return $found_themes;
+}
+
+/**
+ * Retrieve path to themes directory.
+ *
+ * Does not have trailing slash.
+ *
+ * @since 1.5.0
+ * @uses apply_filters() Calls 'theme_root' filter on path.
+ *
+ * @param string $stylesheet_or_template The stylesheet or template name of the theme
+ * @return string Theme path.
+ */
+function get_theme_root( $stylesheet_or_template = false ) {
+ global $wp_theme_directories;
+
+ if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) {
+ // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
+ // This gives relative theme roots the benefit of the doubt when things go haywire.
+ if ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
+ $theme_root = WP_CONTENT_DIR . $theme_root;
+ } else {
+ $theme_root = WP_CONTENT_DIR . '/themes';
+ }
+
+ return apply_filters( 'theme_root', $theme_root );
+}
+
+/**
+ * Retrieve URI for themes directory.
+ *
+ * Does not have trailing slash.
+ *
+ * @since 1.5.0
+ *
+ * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
+ * Default is to leverage the main theme root.
+ * @param string $theme_root Optional. The theme root for which calculations will be based, preventing
+ * the need for a get_raw_theme_root() call.
+ * @return string Themes URI.
+ */
+function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
+ global $wp_theme_directories;
+
+ if ( $stylesheet_or_template && ! $theme_root )
+ $theme_root = get_raw_theme_root( $stylesheet_or_template );
+
+ if ( $stylesheet_or_template && $theme_root ) {
+ if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
+ // Absolute path. Make an educated guess. YMMV -- but note the filter below.
+ if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
+ $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
+ elseif ( 0 === strpos( $theme_root, ABSPATH ) )
+ $theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
+ elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) )
+ $theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
+ else
+ $theme_root_uri = $theme_root;
+ } else {
+ $theme_root_uri = content_url( $theme_root );
+ }
+ } else {
+ $theme_root_uri = content_url( 'themes' );
+ }
+
+ return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
+}
+
+/**
+ * Get the raw theme root relative to the content directory with no filters applied.
+ *
+ * @since 3.1.0
+ *
+ * @param string $stylesheet_or_template The stylesheet or template name of the theme
+ * @param bool $skip_cache Optional. Whether to skip the cache. Defaults to false, meaning the cache is used.
+ * @return string Theme root
+ */
+function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
+ global $wp_theme_directories;
+
+ if ( count($wp_theme_directories) <= 1 )
+ return '/themes';
+
+ $theme_root = false;
+
+ // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
+ if ( ! $skip_cache ) {
+ if ( get_option('stylesheet') == $stylesheet_or_template )
+ $theme_root = get_option('stylesheet_root');
+ elseif ( get_option('template') == $stylesheet_or_template )
+ $theme_root = get_option('template_root');
+ }
+
+ if ( empty($theme_root) ) {
+ $theme_roots = get_theme_roots();
+ if ( !empty($theme_roots[$stylesheet_or_template]) )
+ $theme_root = $theme_roots[$stylesheet_or_template];
+ }
+
+ return $theme_root;
+}
+
+/**
+ * Display localized stylesheet link element.
+ *
+ * @since 2.1.0
+ */
+function locale_stylesheet() {
+ $stylesheet = get_locale_stylesheet_uri();
+ if ( empty($stylesheet) )
+ return;
+ echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
+}
+
+/**
+ * Start preview theme output buffer.
+ *
+ * Will only perform task if the user has permissions and template and preview
+ * query variables exist.
+ *
+ * @since 2.6.0
+ */
+function preview_theme() {
+ if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
+ return;
+
+ if ( !current_user_can( 'switch_themes' ) )
+ return;
+
+ // Admin Thickbox requests
+ if ( isset( $_GET['preview_iframe'] ) )
+ show_admin_bar( false );
+
+ $_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
+
+ if ( validate_file($_GET['template']) )
+ return;
+
+ add_filter( 'template', '_preview_theme_template_filter' );
+
+ if ( isset($_GET['stylesheet']) ) {
+ $_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
+ if ( validate_file($_GET['stylesheet']) )
+ return;
+ add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
+ }
+
+ // Prevent theme mods to current theme being used on theme being previewed
+ add_filter( 'pre_option_theme_mods_' . get_option( 'stylesheet' ), '__return_empty_array' );
+
+ ob_start( 'preview_theme_ob_filter' );
+}
+add_action('setup_theme', 'preview_theme');
+
+/**
+ * Private function to modify the current template when previewing a theme
+ *
+ * @since 2.9.0
+ * @access private
+ *
+ * @return string
+ */
+function _preview_theme_template_filter() {
+ return isset($_GET['template']) ? $_GET['template'] : '';
+}
+
+/**
+ * Private function to modify the current stylesheet when previewing a theme
+ *
+ * @since 2.9.0
+ * @access private
+ *
+ * @return string
+ */
+function _preview_theme_stylesheet_filter() {
+ return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
+}
+
+/**
+ * Callback function for ob_start() to capture all links in the theme.
+ *
+ * @since 2.6.0
+ * @access private
+ *
+ * @param string $content
+ * @return string
+ */
+function preview_theme_ob_filter( $content ) {
+ return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
+}
+
+/**
+ * Manipulates preview theme links in order to control and maintain location.
+ *
+ * Callback function for preg_replace_callback() to accept and filter matches.
+ *
+ * @since 2.6.0
+ * @access private
+ *
+ * @param array $matches
+ * @return string
+ */
+function preview_theme_ob_filter_callback( $matches ) {
+ if ( strpos($matches[4], 'onclick') !== false )
+ $matches[4] = preg_replace('#onclick=([\'"]).*?(?<!\\\)\\1#i', '', $matches[4]); //Strip out any onclicks from rest of <a>. (?<!\\\) means to ignore the '" if it's escaped by \ to prevent breaking mid-attribute.
+ if (
+ ( false !== strpos($matches[3], '/wp-admin/') )
+ ||
+ ( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
+ ||
+ ( false !== strpos($matches[3], '/feed/') )
+ ||
+ ( false !== strpos($matches[3], '/trackback/') )
+ )
+ return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
+
+ $link = add_query_arg( array( 'preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'], 'preview_iframe' => 1 ), $matches[3] );
+ if ( 0 === strpos($link, 'preview=1') )
+ $link = "?$link";
+ return $matches[1] . esc_attr( $link ) . $matches[4];
+}
+
+/**
+ * Switches the theme.
+ *
+ * Accepts one argument: $stylesheet of the theme. It also accepts an additional function signature
+ * of two arguments: $template then $stylesheet. This is for backwards compatibility.
+ *
+ * @since 2.5.0
+ * @uses do_action() Calls 'switch_theme' action, passing the new theme.
+ *
+ * @param string $stylesheet Stylesheet name
+ */
+function switch_theme( $stylesheet ) {
+ global $wp_theme_directories, $sidebars_widgets;
+
+ if ( is_array( $sidebars_widgets ) )
+ set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $sidebars_widgets ) );
+
+ $old_theme = wp_get_theme();
+ $new_theme = wp_get_theme( $stylesheet );
+
+ if ( func_num_args() > 1 ) {
+ $template = $stylesheet;
+ $stylesheet = func_get_arg( 1 );
+ } else {
+ $template = $new_theme->get_template();
+ }
+
+ update_option( 'template', $template );
+ update_option( 'stylesheet', $stylesheet );
+
+ if ( count( $wp_theme_directories ) > 1 ) {
+ update_option( 'template_root', get_raw_theme_root( $template, true ) );
+ update_option( 'stylesheet_root', get_raw_theme_root( $stylesheet, true ) );
+ } else {
+ delete_option( 'template_root' );
+ delete_option( 'stylesheet_root' );
+ }
+
+ $new_name = $new_theme->get('Name');
+
+ update_option( 'current_theme', $new_name );
+
+ if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
+ $default_theme_mods = (array) get_option( 'mods_' . $new_name );
+ add_option( "theme_mods_$stylesheet", $default_theme_mods );
+ }
+
+ update_option( 'theme_switched', $old_theme->get_stylesheet() );
+ do_action( 'switch_theme', $new_name, $new_theme );
+}
+
+/**
+ * Checks that current theme files 'index.php' and 'style.css' exists.
+ *
+ * Does not check the default theme, which is the fallback and should always exist.
+ * Will switch theme to the fallback theme if current theme does not validate.
+ * You can use the 'validate_current_theme' filter to return false to
+ * disable this functionality.
+ *
+ * @since 1.5.0
+ * @see WP_DEFAULT_THEME
+ *
+ * @return bool
+ */
+function validate_current_theme() {
+ // Don't validate during an install/upgrade.
+ if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
+ return true;
+
+ if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
+ switch_theme( WP_DEFAULT_THEME );
+ return false;
+ }
+
+ if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
+ switch_theme( WP_DEFAULT_THEME );
+ return false;
+ }
+
+ if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
+ switch_theme( WP_DEFAULT_THEME );
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Retrieve all theme modifications.
+ *
+ * @since 3.1.0
+ *
+ * @return array Theme modifications.
+ */
+function get_theme_mods() {
+ $theme_slug = get_option( 'stylesheet' );
+ if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
+ $theme_name = get_option( 'current_theme' );
+ if ( false === $theme_name )
+ $theme_name = wp_get_theme()->get('Name');
+ $mods = get_option( "mods_$theme_name" ); // Deprecated location.
+ if ( is_admin() && false !== $mods ) {
+ update_option( "theme_mods_$theme_slug", $mods );
+ delete_option( "mods_$theme_name" );
+ }
+ }
+ return $mods;
+}
+
+/**
+ * Retrieve theme modification value for the current theme.
+ *
+ * If the modification name does not exist, then the $default will be passed
+ * through {@link http://php.net/sprintf sprintf()} PHP function with the first
+ * string the template directory URI and the second string the stylesheet
+ * directory URI.
+ *
+ * @since 2.1.0
+ * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
+ *
+ * @param string $name Theme modification name.
+ * @param bool|string $default
+ * @return string
+ */
+function get_theme_mod( $name, $default = false ) {
+ $mods = get_theme_mods();
+
+ if ( isset( $mods[ $name ] ) )
+ return apply_filters( "theme_mod_$name", $mods[ $name ] );
+
+ if ( is_string( $default ) )
+ $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
+
+ return apply_filters( "theme_mod_$name", $default );
+}
+
+/**
+ * Update theme modification value for the current theme.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ * @param string $value theme modification value.
+ */
+function set_theme_mod( $name, $value ) {
+ $mods = get_theme_mods();
+
+ $mods[ $name ] = $value;
+
+ $theme = get_option( 'stylesheet' );
+ update_option( "theme_mods_$theme", $mods );
+}
+
+/**
+ * Remove theme modification name from current theme list.
+ *
+ * If removing the name also removes all elements, then the entire option will
+ * be removed.
+ *
+ * @since 2.1.0
+ *
+ * @param string $name Theme modification name.
+ * @return null
+ */
+function remove_theme_mod( $name ) {
+ $mods = get_theme_mods();
+
+ if ( ! isset( $mods[ $name ] ) )
+ return;
+
+ unset( $mods[ $name ] );
+
+ if ( empty( $mods ) )
+ return remove_theme_mods();
+
+ $theme = get_option( 'stylesheet' );
+ update_option( "theme_mods_$theme", $mods );
+}
+
+/**
+ * Remove theme modifications option for current theme.
+ *
+ * @since 2.1.0
+ */
+function remove_theme_mods() {
+ delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
+
+ // Old style.
+ $theme_name = get_option( 'current_theme' );
+ if ( false === $theme_name )
+ $theme_name = wp_get_theme()->get('Name');
+ delete_option( 'mods_' . $theme_name );
+}
+
+/**
+ * Retrieve text color for custom header.
+ *
+ * @since 2.1.0
+ *
+ * @return string
+ */
+function get_header_textcolor() {
+ return get_theme_mod('header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
+}
+
+/**
+ * Display text color for custom header.
+ *
+ * @since 2.1.0
+ */
+function header_textcolor() {
+ echo get_header_textcolor();
+}
+
+/**
+ * Whether to display the header text.
+ *
+ * @since 3.4.0
+ *
+ * @return bool
+ */
+function display_header_text() {
+ if ( ! current_theme_supports( 'custom-header', 'header-text' ) )
+ return false;
+
+ $text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
+ return 'blank' != $text_color;
+}
+
+/**
+ * Retrieve header image for custom header.
+ *
+ * @since 2.1.0
+ *
+ * @return string
+ */
+function get_header_image() {
+ $url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
+
+ if ( 'remove-header' == $url )
+ return false;
+
+ if ( is_random_header_image() )
+ $url = get_random_header_image();
+
+ return esc_url_raw( set_url_scheme( $url ) );
+}
+
+/**
+ * Get random header image data from registered images in theme.
+ *
+ * @since 3.4.0
+ *
+ * @access private
+ *
+ * @return string Path to header image
+ */
+
+function _get_random_header_data() {
+ static $_wp_random_header;
+
+ if ( empty( $_wp_random_header ) ) {
+ global $_wp_default_headers;
+ $header_image_mod = get_theme_mod( 'header_image', '' );
+ $headers = array();
+
+ if ( 'random-uploaded-image' == $header_image_mod )
+ $headers = get_uploaded_header_images();
+ elseif ( ! empty( $_wp_default_headers ) ) {
+ if ( 'random-default-image' == $header_image_mod ) {
+ $headers = $_wp_default_headers;
+ } else {
+ if ( current_theme_supports( 'custom-header', 'random-default' ) )
+ $headers = $_wp_default_headers;
+ }
+ }
+
+ if ( empty( $headers ) )
+ return new stdClass;
+
+ $_wp_random_header = (object) $headers[ array_rand( $headers ) ];
+
+ $_wp_random_header->url = sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
+ $_wp_random_header->thumbnail_url = sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
+ }
+ return $_wp_random_header;
+}
+
+/**
+ * Get random header image url from registered images in theme.
+ *
+ * @since 3.2.0
+ *
+ * @return string Path to header image
+ */
+
+function get_random_header_image() {
+ $random_image = _get_random_header_data();
+ if ( empty( $random_image->url ) )
+ return '';
+ return $random_image->url;
+}
+
+/**
+ * Check if random header image is in use.
+ *
+ * Always true if user expressly chooses the option in Appearance > Header.
+ * Also true if theme has multiple header images registered, no specific header image
+ * is chosen, and theme turns on random headers with add_theme_support().
+ *
+ * @since 3.2.0
+ *
+ * @param string $type The random pool to use. any|default|uploaded
+ * @return boolean
+ */
+function is_random_header_image( $type = 'any' ) {
+ $header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
+
+ if ( 'any' == $type ) {
+ if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
+ return true;
+ } else {
+ if ( "random-$type-image" == $header_image_mod )
+ return true;
+ elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Display header image URL.
+ *
+ * @since 2.1.0
+ */
+function header_image() {
+ echo esc_url( get_header_image() );
+}
+
+/**
+ * Get the header images uploaded for the current theme.
+ *
+ * @since 3.2.0
+ *
+ * @return array
+ */
+function get_uploaded_header_images() {
+ $header_images = array();
+
+ // @todo caching
+ $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
+
+ if ( empty( $headers ) )
+ return array();
+
+ foreach ( (array) $headers as $header ) {
+ $url = esc_url_raw( $header->guid );
+ $header_data = wp_get_attachment_metadata( $header->ID );
+ $header_index = basename($url);
+ $header_images[$header_index] = array();
+ $header_images[$header_index]['attachment_id'] = $header->ID;
+ $header_images[$header_index]['url'] = $url;
+ $header_images[$header_index]['thumbnail_url'] = $url;
+ if ( isset( $header_data['width'] ) )
+ $header_images[$header_index]['width'] = $header_data['width'];
+ if ( isset( $header_data['height'] ) )
+ $header_images[$header_index]['height'] = $header_data['height'];
+ }
+
+ return $header_images;
+}
+
+/**
+ * Get the header image data.
+ *
+ * @since 3.4.0
+ *
+ * @return object
+ */
+function get_custom_header() {
+ global $_wp_default_headers;
+
+ if ( is_random_header_image() ) {
+ $data = _get_random_header_data();
+ } else {
+ $data = get_theme_mod( 'header_image_data' );
+ if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
+ $directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
+ $data = array();
+ $data['url'] = $data['thumbnail_url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
+ if ( ! empty( $_wp_default_headers ) ) {
+ foreach ( (array) $_wp_default_headers as $default_header ) {
+ $url = vsprintf( $default_header['url'], $directory_args );
+ if ( $data['url'] == $url ) {
+ $data = $default_header;
+ $data['url'] = $url;
+ $data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ $default = array(
+ 'url' => '',
+ 'thumbnail_url' => '',
+ 'width' => get_theme_support( 'custom-header', 'width' ),
+ 'height' => get_theme_support( 'custom-header', 'height' ),
+ );
+ return (object) wp_parse_args( $data, $default );
+}
+
+/**
+ * Register a selection of default headers to be displayed by the custom header admin UI.
+ *
+ * @since 3.0.0
+ *
+ * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
+ */
+function register_default_headers( $headers ) {
+ global $_wp_default_headers;
+
+ $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
+}
+
+/**
+ * Unregister default headers.
+ *
+ * This function must be called after register_default_headers() has already added the
+ * header you want to remove.
+ *
+ * @see register_default_headers()
+ * @since 3.0.0
+ *
+ * @param string|array $header The header string id (key of array) to remove, or an array thereof.
+ * @return True on success, false on failure.
+ */
+function unregister_default_headers( $header ) {
+ global $_wp_default_headers;
+ if ( is_array( $header ) ) {
+ array_map( 'unregister_default_headers', $header );
+ } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
+ unset( $_wp_default_headers[ $header ] );
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Retrieve background image for custom background.
+ *
+ * @since 3.0.0
+ *
+ * @return string
+ */
+function get_background_image() {
+ return get_theme_mod('background_image', get_theme_support( 'custom-background', 'default-image' ) );
+}
+
+/**
+ * Display background image path.
+ *
+ * @since 3.0.0
+ */
+function background_image() {
+ echo get_background_image();
+}
+
+/**
+ * Retrieve value for custom background color.
+ *
+ * @since 3.0.0
+ *
+ * @return string
+ */
+function get_background_color() {
+ return get_theme_mod('background_color', get_theme_support( 'custom-background', 'default-color' ) );
+}
+
+/**
+ * Display background color value.
+ *
+ * @since 3.0.0
+ */
+function background_color() {
+ echo get_background_color();
+}
+
+/**
+ * Default custom background callback.
+ *
+ * @since 3.0.0
+ * @access protected
+ */
+function _custom_background_cb() {
+ // $background is the saved custom image, or the default image.
+ $background = set_url_scheme( get_background_image() );
+
+ // $color is the saved custom color.
+ // A default has to be specified in style.css. It will not be printed here.
+ $color = get_theme_mod( 'background_color' );
+
+ if ( ! $background && ! $color )
+ return;
+
+ $style = $color ? "background-color: #$color;" : '';
+
+ if ( $background ) {
+ $image = " background-image: url('$background');";
+
+ $repeat = get_theme_mod( 'background_repeat', 'repeat' );
+ if ( ! in_array( $repeat, array( 'no-repeat', 'repeat-x', 'repeat-y', 'repeat' ) ) )
+ $repeat = 'repeat';
+ $repeat = " background-repeat: $repeat;";
+
+ $position = get_theme_mod( 'background_position_x', 'left' );
+ if ( ! in_array( $position, array( 'center', 'right', 'left' ) ) )
+ $position = 'left';
+ $position = " background-position: top $position;";
+
+ $attachment = get_theme_mod( 'background_attachment', 'scroll' );
+ if ( ! in_array( $attachment, array( 'fixed', 'scroll' ) ) )
+ $attachment = 'scroll';
+ $attachment = " background-attachment: $attachment;";
+
+ $style .= $image . $repeat . $position . $attachment;
+ }
+?>
+<style type="text/css" id="custom-background-css">
+body.custom-background { <?php echo trim( $style ); ?> }
+</style>
+<?php
+}
+
+/**
+ * Add callback for custom TinyMCE editor stylesheets.
+ *
+ * The parameter $stylesheet is the name of the stylesheet, relative to
+ * the theme root. It also accepts an array of stylesheets.
+ * It is optional and defaults to 'editor-style.css'.
+ *
+ * This function automatically adds another stylesheet with -rtl prefix, e.g. editor-style-rtl.css.
+ * If that file doesn't exist, it is removed before adding the stylesheet(s) to TinyMCE.
+ * If an array of stylesheets is passed to add_editor_style(),
+ * RTL is only added for the first stylesheet.
+ *
+ * Since version 3.4 the TinyMCE body has .rtl CSS class.
+ * It is a better option to use that class and add any RTL styles to the main stylesheet.
+ *
+ * @since 3.0.0
+ *
+ * @param mixed $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
+ * Defaults to 'editor-style.css'
+ */
+function add_editor_style( $stylesheet = 'editor-style.css' ) {
+
+ add_theme_support( 'editor-style' );
+
+ if ( ! is_admin() )
+ return;
+
+ global $editor_styles;
+ $editor_styles = (array) $editor_styles;
+ $stylesheet = (array) $stylesheet;
+ if ( is_rtl() ) {
+ $rtl_stylesheet = str_replace('.css', '-rtl.css', $stylesheet[0]);
+ $stylesheet[] = $rtl_stylesheet;
+ }
+
+ $editor_styles = array_merge( $editor_styles, $stylesheet );
+}
+
+/**
+ * Removes all visual editor stylesheets.
+ *
+ * @since 3.1.0
+ *
+ * @return bool True on success, false if there were no stylesheets to remove.
+ */
+function remove_editor_styles() {
+ if ( ! current_theme_supports( 'editor-style' ) )
+ return false;
+ _remove_theme_support( 'editor-style' );
+ if ( is_admin() )
+ $GLOBALS['editor_styles'] = array();
+ return true;
+}
+
+/**
+ * Allows a theme to register its support of a certain feature
+ *
+ * Must be called in the theme's functions.php file to work.
+ * If attached to a hook, it must be after_setup_theme.
+ * The init hook may be too late for some features.
+ *
+ * @since 2.9.0
+ * @param string $feature the feature being added
+ */
+function add_theme_support( $feature ) {
+ global $_wp_theme_features;
+
+ if ( func_num_args() == 1 )
+ $args = true;
+ else
+ $args = array_slice( func_get_args(), 1 );
+
+ switch ( $feature ) {
+ case 'post-formats' :
+ if ( is_array( $args[0] ) )
+ $args[0] = array_intersect( $args[0], array_keys( get_post_format_slugs() ) );
+ break;
+
+ case 'custom-header-uploads' :
+ return add_theme_support( 'custom-header', array( 'uploads' => true ) );
+ break;
+
+ case 'custom-header' :
+ if ( ! is_array( $args ) )
+ $args = array( 0 => array() );
+
+ $defaults = array(
+ 'default-image' => '',
+ 'random-default' => false,
+ 'width' => 0,
+ 'height' => 0,
+ 'flex-height' => false,
+ 'flex-width' => false,
+ 'default-text-color' => '',
+ 'header-text' => true,
+ 'uploads' => true,
+ 'wp-head-callback' => '',
+ 'admin-head-callback' => '',
+ 'admin-preview-callback' => '',
+ );
+
+ $jit = isset( $args[0]['__jit'] );
+ unset( $args[0]['__jit'] );
+
+ // Merge in data from previous add_theme_support() calls.
+ // The first value registered wins. (A child theme is set up first.)
+ if ( isset( $_wp_theme_features['custom-header'] ) )
+ $args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] );
+
+ // Load in the defaults at the end, as we need to insure first one wins.
+ // This will cause all constants to be defined, as each arg will then be set to the default.
+ if ( $jit )
+ $args[0] = wp_parse_args( $args[0], $defaults );
+
+ // If a constant was defined, use that value. Otherwise, define the constant to ensure
+ // the constant is always accurate (and is not defined later, overriding our value).
+ // As stated above, the first value wins.
+ // Once we get to wp_loaded (just-in-time), define any constants we haven't already.
+ // Constants are lame. Don't reference them. This is just for backwards compatibility.
+
+ if ( defined( 'NO_HEADER_TEXT' ) )
+ $args[0]['header-text'] = ! NO_HEADER_TEXT;
+ elseif ( isset( $args[0]['header-text'] ) )
+ define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
+
+ if ( defined( 'HEADER_IMAGE_WIDTH' ) )
+ $args[0]['width'] = (int) HEADER_IMAGE_WIDTH;
+ elseif ( isset( $args[0]['width'] ) )
+ define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] );
+
+ if ( defined( 'HEADER_IMAGE_HEIGHT' ) )
+ $args[0]['height'] = (int) HEADER_IMAGE_HEIGHT;
+ elseif ( isset( $args[0]['height'] ) )
+ define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] );
+
+ if ( defined( 'HEADER_TEXTCOLOR' ) )
+ $args[0]['default-text-color'] = HEADER_TEXTCOLOR;
+ elseif ( isset( $args[0]['default-text-color'] ) )
+ define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] );
+
+ if ( defined( 'HEADER_IMAGE' ) )
+ $args[0]['default-image'] = HEADER_IMAGE;
+ elseif ( isset( $args[0]['default-image'] ) )
+ define( 'HEADER_IMAGE', $args[0]['default-image'] );
+
+ if ( $jit && ! empty( $args[0]['default-image'] ) )
+ $args[0]['random-default'] = false;
+
+ // If headers are supported, and we still don't have a defined width or height,
+ // we have implicit flex sizes.
+ if ( $jit ) {
+ if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) )
+ $args[0]['flex-width'] = true;
+ if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) )
+ $args[0]['flex-height'] = true;
+ }
+
+ break;
+
+ case 'custom-background' :
+ if ( ! is_array( $args ) )
+ $args = array( 0 => array() );
+
+ $defaults = array(
+ 'default-image' => '',
+ 'default-color' => '',
+ 'wp-head-callback' => '_custom_background_cb',
+ 'admin-head-callback' => '',
+ 'admin-preview-callback' => '',
+ );
+
+ $jit = isset( $args[0]['__jit'] );
+ unset( $args[0]['__jit'] );
+
+ // Merge in data from previous add_theme_support() calls. The first value registered wins.
+ if ( isset( $_wp_theme_features['custom-background'] ) )
+ $args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] );
+
+ if ( $jit )
+ $args[0] = wp_parse_args( $args[0], $defaults );
+
+ if ( defined( 'BACKGROUND_COLOR' ) )
+ $args[0]['default-color'] = BACKGROUND_COLOR;
+ elseif ( isset( $args[0]['default-color'] ) || $jit )
+ define( 'BACKGROUND_COLOR', $args[0]['default-color'] );
+
+ if ( defined( 'BACKGROUND_IMAGE' ) )
+ $args[0]['default-image'] = BACKGROUND_IMAGE;
+ elseif ( isset( $args[0]['default-image'] ) || $jit )
+ define( 'BACKGROUND_IMAGE', $args[0]['default-image'] );
+
+ break;
+ }
+
+ $_wp_theme_features[ $feature ] = $args;
+}
+
+/**
+ * Registers the internal custom header and background routines.
+ *
+ * @since 3.4.0
+ * @access private
+ */
+function _custom_header_background_just_in_time() {
+ global $custom_image_header, $custom_background;
+
+ if ( current_theme_supports( 'custom-header' ) ) {
+ // In case any constants were defined after an add_custom_image_header() call, re-run.
+ add_theme_support( 'custom-header', array( '__jit' => true ) );
+
+ $args = get_theme_support( 'custom-header' );
+ if ( $args[0]['wp-head-callback'] )
+ add_action( 'wp_head', $args[0]['wp-head-callback'] );
+
+ if ( is_admin() ) {
+ require_once( ABSPATH . 'wp-admin/custom-header.php' );
+ $custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
+ }
+ }
+
+ if ( current_theme_supports( 'custom-background' ) ) {
+ // In case any constants were defined after an add_custom_background() call, re-run.
+ add_theme_support( 'custom-background', array( '__jit' => true ) );
+
+ $args = get_theme_support( 'custom-background' );
+ add_action( 'wp_head', $args[0]['wp-head-callback'] );
+
+ if ( is_admin() ) {
+ require_once( ABSPATH . 'wp-admin/custom-background.php' );
+ $custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
+ }
+ }
+}
+add_action( 'wp_loaded', '_custom_header_background_just_in_time' );
+
+/**
+ * Gets the theme support arguments passed when registering that support
+ *
+ * @since 3.1
+ * @param string $feature the feature to check
+ * @return array The array of extra arguments
+ */
+function get_theme_support( $feature ) {
+ global $_wp_theme_features;
+ if ( ! isset( $_wp_theme_features[ $feature ] ) )
+ return false;
+
+ if ( func_num_args() <= 1 )
+ return $_wp_theme_features[ $feature ];
+
+ $args = array_slice( func_get_args(), 1 );
+ switch ( $feature ) {
+ case 'custom-header' :
+ case 'custom-background' :
+ if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) )
+ return $_wp_theme_features[ $feature ][0][ $args[0] ];
+ return false;
+ break;
+ default :
+ return $_wp_theme_features[ $feature ];
+ break;
+ }
+}
+
+/**
+ * Allows a theme to de-register its support of a certain feature
+ *
+ * Should be called in the theme's functions.php file. Generally would
+ * be used for child themes to override support from the parent theme.
+ *
+ * @since 3.0.0
+ * @see add_theme_support()
+ * @param string $feature the feature being added
+ * @return bool Whether feature was removed.
+ */
+function remove_theme_support( $feature ) {
+ // Blacklist: for internal registrations not used directly by themes.
+ if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ) ) )
+ return false;
+
+ return _remove_theme_support( $feature );
+}
+
+/**
+ * Do not use. Removes theme support internally, ignorant of the blacklist.
+ *
+ * @access private
+ * @since 3.1.0
+ */
+function _remove_theme_support( $feature ) {
+ global $_wp_theme_features;
+
+ switch ( $feature ) {
+ case 'custom-header-uploads' :
+ if ( ! isset( $_wp_theme_features['custom-header'] ) )
+ return false;
+ add_theme_support( 'custom-header', array( 'uploads' => false ) );
+ return; // Do not continue - custom-header-uploads no longer exists.
+ }
+
+ if ( ! isset( $_wp_theme_features[ $feature ] ) )
+ return false;
+
+ switch ( $feature ) {
+ case 'custom-header' :
+ if ( ! did_action( 'wp_loaded' ) )
+ break;
+ $support = get_theme_support( 'custom-header' );
+ if ( $support[0]['wp-head-callback'] )
+ remove_action( 'wp_head', $support[0]['wp-head-callback'] );
+ remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
+ unset( $GLOBALS['custom_image_header'] );
+ break;
+
+ case 'custom-background' :
+ if ( ! did_action( 'wp_loaded' ) )
+ break;
+ $support = get_theme_support( 'custom-background' );
+ remove_action( 'wp_head', $support[0]['wp-head-callback'] );
+ remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
+ unset( $GLOBALS['custom_background'] );
+ break;
+ }
+
+ unset( $_wp_theme_features[ $feature ] );
+ return true;
+}
+
+/**
+ * Checks a theme's support for a given feature
+ *
+ * @since 2.9.0
+ * @param string $feature the feature being checked
+ * @return boolean
+ */
+function current_theme_supports( $feature ) {
+ global $_wp_theme_features;
+
+ if ( 'custom-header-uploads' == $feature )
+ return current_theme_supports( 'custom-header', 'uploads' );
+
+ if ( !isset( $_wp_theme_features[$feature] ) )
+ return false;
+
+ // If no args passed then no extra checks need be performed
+ if ( func_num_args() <= 1 )
+ return true;
+
+ $args = array_slice( func_get_args(), 1 );
+
+ switch ( $feature ) {
+ case 'post-thumbnails':
+ // post-thumbnails can be registered for only certain content/post types by passing
+ // an array of types to add_theme_support(). If no array was passed, then
+ // any type is accepted
+ if ( true === $_wp_theme_features[$feature] ) // Registered for all types
+ return true;
+ $content_type = $args[0];
+ return in_array( $content_type, $_wp_theme_features[$feature][0] );
+ break;
+
+ case 'post-formats':
+ // specific post formats can be registered by passing an array of types to
+ // add_theme_support()
+ $post_format = $args[0];
+ return in_array( $post_format, $_wp_theme_features[$feature][0] );
+ break;
+
+ case 'custom-header':
+ case 'custom-background' :
+ // specific custom header and background capabilities can be registered by passing
+ // an array to add_theme_support()
+ $header_support = $args[0];
+ return ( isset( $_wp_theme_features[$feature][0][$header_support] ) && $_wp_theme_features[$feature][0][$header_support] );
+ break;
+ }
+
+ return apply_filters('current_theme_supports-' . $feature, true, $args, $_wp_theme_features[$feature]);
+}
+
+/**
+ * Checks a theme's support for a given feature before loading the functions which implement it.
+ *
+ * @since 2.9.0
+ * @param string $feature the feature being checked
+ * @param string $include the file containing the functions that implement the feature
+ */
+function require_if_theme_supports( $feature, $include) {
+ if ( current_theme_supports( $feature ) )
+ require ( $include );
+}
+
+/**
+ * Checks an attachment being deleted to see if it's a header or background image.
+ *
+ * If true it removes the theme modification which would be pointing at the deleted
+ * attachment
+ *
+ * @access private
+ * @since 3.0.0
+ * @param int $id the attachment id
+ */
+function _delete_attachment_theme_mod( $id ) {
+ $attachment_image = wp_get_attachment_url( $id );
+ $header_image = get_header_image();
+ $background_image = get_background_image();
+
+ if ( $header_image && $header_image == $attachment_image )
+ remove_theme_mod( 'header_image' );
+
+ if ( $background_image && $background_image == $attachment_image )
+ remove_theme_mod( 'background_image' );
+}
+
+add_action( 'delete_attachment', '_delete_attachment_theme_mod' );
+
+/**
+ * Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load
+ *
+ * @since 3.3.0
+ */
+function check_theme_switched() {
+ if ( $stylesheet = get_option( 'theme_switched' ) ) {
+ $old_theme = wp_get_theme( $stylesheet );
+
+ if ( $old_theme->exists() )
+ do_action( 'after_switch_theme', $old_theme->get('Name'), $old_theme );
+ else
+ do_action( 'after_switch_theme', $stylesheet );
+
+ update_option( 'theme_switched', false );
+ }
+}
+
+/**
+ * Includes and instantiates the WP_Customize_Manager class.
+ *
+ * Fires when ?wp_customize=on or on wp-admin/customize.php.
+ *
+ * @since 3.4.0
+ */
+function _wp_customize_include() {
+ if ( ! ( ( isset( $_REQUEST['wp_customize'] ) && 'on' == $_REQUEST['wp_customize'] )
+ || ( is_admin() && 'customize.php' == basename( $_SERVER['PHP_SELF'] ) )
+ ) )
+ return;
+
+ require( ABSPATH . WPINC . '/class-wp-customize-manager.php' );
+ // Init Customize class
+ $GLOBALS['wp_customize'] = new WP_Customize_Manager;
+}
+add_action( 'plugins_loaded', '_wp_customize_include' );
+
+/**
+ * Adds settings for the customize-loader script.
+ *
+ * @since 3.4.0
+ */
+function _wp_customize_loader_settings() {
+ global $wp_scripts;
+
+ $admin_origin = parse_url( admin_url() );
+ $home_origin = parse_url( home_url() );
+ $cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
+
+ $browser = array(
+ 'mobile' => wp_is_mobile(),
+ 'ios' => wp_is_mobile() && preg_match( '/iPad|iPod|iPhone/', $_SERVER['HTTP_USER_AGENT'] ),
+ );
+
+ $settings = array(
+ 'url' => esc_url( admin_url( 'customize.php' ) ),
+ 'isCrossDomain' => $cross_domain,
+ 'browser' => $browser,
+ );
+
+ $script = 'var _wpCustomizeLoaderSettings = ' . json_encode( $settings ) . ';';
+
+ $data = $wp_scripts->get_data( 'customize-loader', 'data' );
+ if ( $data )
+ $script = "$data\n$script";
+
+ $wp_scripts->add_data( 'customize-loader', 'data', $script );
+}
+add_action( 'admin_enqueue_scripts', '_wp_customize_loader_settings' );
+
+/**
+ * Returns a URL to load the theme customizer.
+ *
+ * @since 3.4.0
+ *
+ * @param string $stylesheet Optional. Theme to customize. Defaults to current theme.
+ * The theme's stylesheet will be urlencoded if necessary.
+ */
+function wp_customize_url( $stylesheet = null ) {
+ $url = admin_url( 'customize.php' );
+ if ( $stylesheet )
+ $url .= '?theme=' . urlencode( $stylesheet );
+ return esc_url( $url );
+}
+
+/**
+ * Prints a script to check whether or not the customizer is supported,
+ * and apply either the no-customize-support or customize-support class
+ * to the body.
+ *
+ * This function MUST be called inside the body tag.
+ *
+ * Ideally, call this function immediately after the body tag is opened.
+ * This prevents a flash of unstyled content.
+ *
+ * It is also recommended that you add the "no-customize-support" class
+ * to the body tag by default.
+ *
+ * @since 3.4.0
+ */
+function wp_customize_support_script() {
+ $admin_origin = parse_url( admin_url() );
+ $home_origin = parse_url( home_url() );
+ $cross_domain = ( strtolower( $admin_origin[ 'host' ] ) != strtolower( $home_origin[ 'host' ] ) );
+
+ ?>
+ <script type="text/javascript">
+ (function() {
+ var request, b = document.body, c = 'className', cs = 'customize-support', rcs = new RegExp('(^|\\s+)(no-)?'+cs+'(\\s+|$)');
+
+<?php if ( $cross_domain ): ?>
+ request = (function(){ var xhr = new XMLHttpRequest(); return ('withCredentials' in xhr); })();
+<?php else: ?>
+ request = true;
+<?php endif; ?>
+
+ b[c] = b[c].replace( rcs, ' ' );
+ b[c] += ( window.postMessage && request ? ' ' : ' no-' ) + cs;
+ }());
+ </script>
+ <?php
+} \ No newline at end of file
diff --git a/src/wp-includes/update.php b/src/wp-includes/update.php
new file mode 100644
index 0000000000..61d163aaf4
--- /dev/null
+++ b/src/wp-includes/update.php
@@ -0,0 +1,449 @@
+<?php
+/**
+ * A simple set of functions to check our version 1.0 update service.
+ *
+ * @package WordPress
+ * @since 2.3.0
+ */
+
+/**
+ * Check WordPress version against the newest version.
+ *
+ * The WordPress version, PHP version, and Locale is sent. Checks against the
+ * WordPress server at api.wordpress.org server. Will only check if WordPress
+ * isn't installing.
+ *
+ * @package WordPress
+ * @since 2.3.0
+ * @uses $wp_version Used to check against the newest WordPress version.
+ *
+ * @return mixed Returns null if update is unsupported. Returns false if check is too soon.
+ */
+function wp_version_check() {
+ if ( defined('WP_INSTALLING') )
+ return;
+
+ global $wpdb, $wp_local_package;
+ include ABSPATH . WPINC . '/version.php'; // include an unmodified $wp_version
+ $php_version = phpversion();
+
+ $current = get_site_transient( 'update_core' );
+ if ( ! is_object($current) ) {
+ $current = new stdClass;
+ $current->updates = array();
+ $current->version_checked = $wp_version;
+ }
+
+ // Wait 60 seconds between multiple version check requests
+ $timeout = 60;
+ $time_not_changed = isset( $current->last_checked ) && $timeout > ( time() - $current->last_checked );
+ if ( $time_not_changed )
+ return false;
+
+ $locale = apply_filters( 'core_version_check_locale', get_locale() );
+
+ // Update last_checked for current to prevent multiple blocking requests if request hangs
+ $current->last_checked = time();
+ set_site_transient( 'update_core', $current );
+
+ if ( method_exists( $wpdb, 'db_version' ) )
+ $mysql_version = preg_replace('/[^0-9.].*/', '', $wpdb->db_version());
+ else
+ $mysql_version = 'N/A';
+
+ if ( is_multisite() ) {
+ $user_count = get_user_count();
+ $num_blogs = get_blog_count();
+ $wp_install = network_site_url();
+ $multisite_enabled = 1;
+ } else {
+ $user_count = count_users();
+ $user_count = $user_count['total_users'];
+ $multisite_enabled = 0;
+ $num_blogs = 1;
+ $wp_install = home_url( '/' );
+ }
+
+ $query = array(
+ 'version' => $wp_version,
+ 'php' => $php_version,
+ 'locale' => $locale,
+ 'mysql' => $mysql_version,
+ 'local_package' => isset( $wp_local_package ) ? $wp_local_package : '',
+ 'blogs' => $num_blogs,
+ 'users' => $user_count,
+ 'multisite_enabled' => $multisite_enabled
+ );
+
+ $url = 'http://api.wordpress.org/core/version-check/1.6/?' . http_build_query( $query, null, '&' );
+
+ $options = array(
+ 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ),
+ 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' ),
+ 'headers' => array(
+ 'wp_install' => $wp_install,
+ 'wp_blog' => home_url( '/' )
+ )
+ );
+
+ $response = wp_remote_get($url, $options);
+
+ if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
+ return false;
+
+ $body = trim( wp_remote_retrieve_body( $response ) );
+ $body = maybe_unserialize( $body );
+
+ if ( ! is_array( $body ) || ! isset( $body['offers'] ) )
+ return false;
+
+ $offers = $body['offers'];
+
+ foreach ( $offers as &$offer ) {
+ foreach ( $offer as $offer_key => $value ) {
+ if ( 'packages' == $offer_key )
+ $offer['packages'] = (object) array_intersect_key( array_map( 'esc_url', $offer['packages'] ),
+ array_fill_keys( array( 'full', 'no_content', 'new_bundled', 'partial' ), '' ) );
+ elseif ( 'download' == $offer_key )
+ $offer['download'] = esc_url( $value );
+ else
+ $offer[ $offer_key ] = esc_html( $value );
+ }
+ $offer = (object) array_intersect_key( $offer, array_fill_keys( array( 'response', 'download', 'locale',
+ 'packages', 'current', 'php_version', 'mysql_version', 'new_bundled', 'partial_version' ), '' ) );
+ }
+
+ $updates = new stdClass();
+ $updates->updates = $offers;
+ $updates->last_checked = time();
+ $updates->version_checked = $wp_version;
+ set_site_transient( 'update_core', $updates);
+}
+
+/**
+ * Check plugin versions against the latest versions hosted on WordPress.org.
+ *
+ * The WordPress version, PHP version, and Locale is sent along with a list of
+ * all plugins installed. Checks against the WordPress server at
+ * api.wordpress.org. Will only check if WordPress isn't installing.
+ *
+ * @package WordPress
+ * @since 2.3.0
+ * @uses $wp_version Used to notify the WordPress version.
+ *
+ * @return mixed Returns null if update is unsupported. Returns false if check is too soon.
+ */
+function wp_update_plugins() {
+ include ABSPATH . WPINC . '/version.php'; // include an unmodified $wp_version
+
+ if ( defined('WP_INSTALLING') )
+ return false;
+
+ // If running blog-side, bail unless we've not checked in the last 12 hours
+ if ( !function_exists( 'get_plugins' ) )
+ require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
+
+ $plugins = get_plugins();
+ $active = get_option( 'active_plugins', array() );
+ $current = get_site_transient( 'update_plugins' );
+ if ( ! is_object($current) )
+ $current = new stdClass;
+
+ $new_option = new stdClass;
+ $new_option->last_checked = time();
+
+ // Check for update on a different schedule, depending on the page.
+ switch ( current_filter() ) {
+ case 'load-update-core.php' :
+ $timeout = MINUTE_IN_SECONDS;
+ break;
+ case 'load-plugins.php' :
+ case 'load-update.php' :
+ $timeout = HOUR_IN_SECONDS;
+ break;
+ default :
+ $timeout = 12 * HOUR_IN_SECONDS;
+ }
+
+ $time_not_changed = isset( $current->last_checked ) && $timeout > ( time() - $current->last_checked );
+
+ if ( $time_not_changed ) {
+ $plugin_changed = false;
+ foreach ( $plugins as $file => $p ) {
+ $new_option->checked[ $file ] = $p['Version'];
+
+ if ( !isset( $current->checked[ $file ] ) || strval($current->checked[ $file ]) !== strval($p['Version']) )
+ $plugin_changed = true;
+ }
+
+ if ( isset ( $current->response ) && is_array( $current->response ) ) {
+ foreach ( $current->response as $plugin_file => $update_details ) {
+ if ( ! isset($plugins[ $plugin_file ]) ) {
+ $plugin_changed = true;
+ break;
+ }
+ }
+ }
+
+ // Bail if we've checked recently and if nothing has changed
+ if ( ! $plugin_changed )
+ return false;
+ }
+
+ // Update last_checked for current to prevent multiple blocking requests if request hangs
+ $current->last_checked = time();
+ set_site_transient( 'update_plugins', $current );
+
+ $to_send = (object) compact('plugins', 'active');
+
+ $options = array(
+ 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3),
+ 'body' => array( 'plugins' => serialize( $to_send ) ),
+ 'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
+ );
+
+ $raw_response = wp_remote_post('http://api.wordpress.org/plugins/update-check/1.0/', $options);
+
+ if ( is_wp_error( $raw_response ) || 200 != wp_remote_retrieve_response_code( $raw_response ) )
+ return false;
+
+ $response = maybe_unserialize( wp_remote_retrieve_body( $raw_response ) );
+
+ if ( is_array( $response ) )
+ $new_option->response = $response;
+ else
+ $new_option->response = array();
+
+ set_site_transient( 'update_plugins', $new_option );
+}
+
+/**
+ * Check theme versions against the latest versions hosted on WordPress.org.
+ *
+ * A list of all themes installed in sent to WP. Checks against the
+ * WordPress server at api.wordpress.org. Will only check if WordPress isn't
+ * installing.
+ *
+ * @package WordPress
+ * @since 2.7.0
+ * @uses $wp_version Used to notify the WordPress version.
+ *
+ * @return mixed Returns null if update is unsupported. Returns false if check is too soon.
+ */
+function wp_update_themes() {
+ include ABSPATH . WPINC . '/version.php'; // include an unmodified $wp_version
+
+ if ( defined( 'WP_INSTALLING' ) )
+ return false;
+
+ $installed_themes = wp_get_themes();
+ $last_update = get_site_transient( 'update_themes' );
+ if ( ! is_object($last_update) )
+ $last_update = new stdClass;
+
+ $themes = array();
+ $checked = array();
+
+ // Put slug of current theme into request.
+ $themes['current_theme'] = get_option( 'stylesheet' );
+
+ foreach ( $installed_themes as $theme ) {
+ $checked[ $theme->get_stylesheet() ] = $theme->get('Version');
+
+ $themes[ $theme->get_stylesheet() ] = array(
+ 'Name' => $theme->get('Name'),
+ 'Title' => $theme->get('Name'),
+ 'Version' => $theme->get('Version'),
+ 'Author' => $theme->get('Author'),
+ 'Author URI' => $theme->get('AuthorURI'),
+ 'Template' => $theme->get_template(),
+ 'Stylesheet' => $theme->get_stylesheet(),
+ );
+ }
+
+ // Check for update on a different schedule, depending on the page.
+ switch ( current_filter() ) {
+ case 'load-update-core.php' :
+ $timeout = MINUTE_IN_SECONDS;
+ break;
+ case 'load-themes.php' :
+ case 'load-update.php' :
+ $timeout = HOUR_IN_SECONDS;
+ break;
+ default :
+ $timeout = 12 * HOUR_IN_SECONDS;
+ }
+
+ $time_not_changed = isset( $last_update->last_checked ) && $timeout > ( time() - $last_update->last_checked );
+
+ if ( $time_not_changed ) {
+ $theme_changed = false;
+ foreach ( $checked as $slug => $v ) {
+ if ( !isset( $last_update->checked[ $slug ] ) || strval($last_update->checked[ $slug ]) !== strval($v) )
+ $theme_changed = true;
+ }
+
+ if ( isset ( $last_update->response ) && is_array( $last_update->response ) ) {
+ foreach ( $last_update->response as $slug => $update_details ) {
+ if ( ! isset($checked[ $slug ]) ) {
+ $theme_changed = true;
+ break;
+ }
+ }
+ }
+
+ // Bail if we've checked recently and if nothing has changed
+ if ( ! $theme_changed )
+ return false;
+ }
+
+ // Update last_checked for current to prevent multiple blocking requests if request hangs
+ $last_update->last_checked = time();
+ set_site_transient( 'update_themes', $last_update );
+
+ $options = array(
+ 'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3),
+ 'body' => array( 'themes' => serialize( $themes ) ),
+ 'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
+ );
+
+ $raw_response = wp_remote_post( 'http://api.wordpress.org/themes/update-check/1.0/', $options );
+
+ if ( is_wp_error( $raw_response ) || 200 != wp_remote_retrieve_response_code( $raw_response ) )
+ return false;
+
+ $new_update = new stdClass;
+ $new_update->last_checked = time();
+ $new_update->checked = $checked;
+
+ $response = maybe_unserialize( wp_remote_retrieve_body( $raw_response ) );
+ if ( is_array( $response ) )
+ $new_update->response = $response;
+
+ set_site_transient( 'update_themes', $new_update );
+}
+
+/*
+ * Collect counts and UI strings for available updates
+ *
+ * @since 3.3.0
+ *
+ * @return array
+ */
+function wp_get_update_data() {
+ $counts = array( 'plugins' => 0, 'themes' => 0, 'wordpress' => 0 );
+
+ if ( current_user_can( 'update_plugins' ) ) {
+ $update_plugins = get_site_transient( 'update_plugins' );
+ if ( ! empty( $update_plugins->response ) )
+ $counts['plugins'] = count( $update_plugins->response );
+ }
+
+ if ( current_user_can( 'update_themes' ) ) {
+ $update_themes = get_site_transient( 'update_themes' );
+ if ( ! empty( $update_themes->response ) )
+ $counts['themes'] = count( $update_themes->response );
+ }
+
+ if ( function_exists( 'get_core_updates' ) && current_user_can( 'update_core' ) ) {
+ $update_wordpress = get_core_updates( array('dismissed' => false) );
+ if ( ! empty( $update_wordpress ) && ! in_array( $update_wordpress[0]->response, array('development', 'latest') ) && current_user_can('update_core') )
+ $counts['wordpress'] = 1;
+ }
+
+ $counts['total'] = $counts['plugins'] + $counts['themes'] + $counts['wordpress'];
+ $titles = array();
+ if ( $counts['wordpress'] )
+ $titles['wordpress'] = sprintf( __( '%d WordPress Update'), $counts['wordpress'] );
+ if ( $counts['plugins'] )
+ $titles['plugins'] = sprintf( _n( '%d Plugin Update', '%d Plugin Updates', $counts['plugins'] ), $counts['plugins'] );
+ if ( $counts['themes'] )
+ $titles['themes'] = sprintf( _n( '%d Theme Update', '%d Theme Updates', $counts['themes'] ), $counts['themes'] );
+
+ $update_title = $titles ? esc_attr( implode( ', ', $titles ) ) : '';
+
+ return apply_filters( 'wp_get_update_data', array( 'counts' => $counts, 'title' => $update_title ), $titles );
+}
+
+function _maybe_update_core() {
+ include ABSPATH . WPINC . '/version.php'; // include an unmodified $wp_version
+
+ $current = get_site_transient( 'update_core' );
+
+ if ( isset( $current->last_checked ) &&
+ 12 * HOUR_IN_SECONDS > ( time() - $current->last_checked ) &&
+ isset( $current->version_checked ) &&
+ $current->version_checked == $wp_version )
+ return;
+
+ wp_version_check();
+}
+/**
+ * Check the last time plugins were run before checking plugin versions.
+ *
+ * This might have been backported to WordPress 2.6.1 for performance reasons.
+ * This is used for the wp-admin to check only so often instead of every page
+ * load.
+ *
+ * @since 2.7.0
+ * @access private
+ */
+function _maybe_update_plugins() {
+ $current = get_site_transient( 'update_plugins' );
+ if ( isset( $current->last_checked ) && 12 * HOUR_IN_SECONDS > ( time() - $current->last_checked ) )
+ return;
+ wp_update_plugins();
+}
+
+/**
+ * Check themes versions only after a duration of time.
+ *
+ * This is for performance reasons to make sure that on the theme version
+ * checker is not run on every page load.
+ *
+ * @since 2.7.0
+ * @access private
+ */
+function _maybe_update_themes() {
+ $current = get_site_transient( 'update_themes' );
+ if ( isset( $current->last_checked ) && 12 * HOUR_IN_SECONDS > ( time() - $current->last_checked ) )
+ return;
+
+ wp_update_themes();
+}
+
+/**
+ * Schedule core, theme, and plugin update checks.
+ *
+ * @since 3.1.0
+ */
+function wp_schedule_update_checks() {
+ if ( !wp_next_scheduled('wp_version_check') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'twicedaily', 'wp_version_check');
+
+ if ( !wp_next_scheduled('wp_update_plugins') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'twicedaily', 'wp_update_plugins');
+
+ if ( !wp_next_scheduled('wp_update_themes') && !defined('WP_INSTALLING') )
+ wp_schedule_event(time(), 'twicedaily', 'wp_update_themes');
+}
+
+if ( ( ! is_main_site() && ! is_network_admin() ) || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) )
+ return;
+
+add_action( 'admin_init', '_maybe_update_core' );
+add_action( 'wp_version_check', 'wp_version_check' );
+
+add_action( 'load-plugins.php', 'wp_update_plugins' );
+add_action( 'load-update.php', 'wp_update_plugins' );
+add_action( 'load-update-core.php', 'wp_update_plugins' );
+add_action( 'admin_init', '_maybe_update_plugins' );
+add_action( 'wp_update_plugins', 'wp_update_plugins' );
+
+add_action( 'load-themes.php', 'wp_update_themes' );
+add_action( 'load-update.php', 'wp_update_themes' );
+add_action( 'load-update-core.php', 'wp_update_themes' );
+add_action( 'admin_init', '_maybe_update_themes' );
+add_action( 'wp_update_themes', 'wp_update_themes' );
+
+add_action('init', 'wp_schedule_update_checks');
diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php
new file mode 100644
index 0000000000..be11b736da
--- /dev/null
+++ b/src/wp-includes/user.php
@@ -0,0 +1,1552 @@
+<?php
+/**
+ * WordPress User API
+ *
+ * @package WordPress
+ */
+
+/**
+ * Authenticate user with remember capability.
+ *
+ * The credentials is an array that has 'user_login', 'user_password', and
+ * 'remember' indices. If the credentials is not given, then the log in form
+ * will be assumed and used if set.
+ *
+ * The various authentication cookies will be set by this function and will be
+ * set for a longer period depending on if the 'remember' credential is set to
+ * true.
+ *
+ * @since 2.5.0
+ *
+ * @param array $credentials Optional. User info in order to sign on.
+ * @param bool $secure_cookie Optional. Whether to use secure cookie.
+ * @return object Either WP_Error on failure, or WP_User on success.
+ */
+function wp_signon( $credentials = '', $secure_cookie = '' ) {
+ if ( empty($credentials) ) {
+ if ( ! empty($_POST['log']) )
+ $credentials['user_login'] = $_POST['log'];
+ if ( ! empty($_POST['pwd']) )
+ $credentials['user_password'] = $_POST['pwd'];
+ if ( ! empty($_POST['rememberme']) )
+ $credentials['remember'] = $_POST['rememberme'];
+ }
+
+ if ( !empty($credentials['remember']) )
+ $credentials['remember'] = true;
+ else
+ $credentials['remember'] = false;
+
+ // TODO do we deprecate the wp_authentication action?
+ do_action_ref_array('wp_authenticate', array(&$credentials['user_login'], &$credentials['user_password']));
+
+ if ( '' === $secure_cookie )
+ $secure_cookie = is_ssl();
+
+ $secure_cookie = apply_filters('secure_signon_cookie', $secure_cookie, $credentials);
+
+ global $auth_secure_cookie; // XXX ugly hack to pass this to wp_authenticate_cookie
+ $auth_secure_cookie = $secure_cookie;
+
+ add_filter('authenticate', 'wp_authenticate_cookie', 30, 3);
+
+ $user = wp_authenticate($credentials['user_login'], $credentials['user_password']);
+
+ if ( is_wp_error($user) ) {
+ if ( $user->get_error_codes() == array('empty_username', 'empty_password') ) {
+ $user = new WP_Error('', '');
+ }
+
+ return $user;
+ }
+
+ wp_set_auth_cookie($user->ID, $credentials['remember'], $secure_cookie);
+ do_action('wp_login', $user->user_login, $user);
+ return $user;
+}
+
+/**
+ * Authenticate the user using the username and password.
+ */
+add_filter('authenticate', 'wp_authenticate_username_password', 20, 3);
+function wp_authenticate_username_password($user, $username, $password) {
+ if ( is_a($user, 'WP_User') ) { return $user; }
+
+ if ( empty($username) || empty($password) ) {
+ if ( is_wp_error( $user ) )
+ return $user;
+
+ $error = new WP_Error();
+
+ if ( empty($username) )
+ $error->add('empty_username', __('<strong>ERROR</strong>: The username field is empty.'));
+
+ if ( empty($password) )
+ $error->add('empty_password', __('<strong>ERROR</strong>: The password field is empty.'));
+
+ return $error;
+ }
+
+ $user = get_user_by('login', $username);
+
+ if ( !$user )
+ return new WP_Error( 'invalid_username', sprintf( __( '<strong>ERROR</strong>: Invalid username. <a href="%s" title="Password Lost and Found">Lost your password</a>?' ), wp_lostpassword_url() ) );
+
+ $user = apply_filters('wp_authenticate_user', $user, $password);
+ if ( is_wp_error($user) )
+ return $user;
+
+ if ( !wp_check_password($password, $user->user_pass, $user->ID) )
+ return new WP_Error( 'incorrect_password', sprintf( __( '<strong>ERROR</strong>: The password you entered for the username <strong>%1$s</strong> is incorrect. <a href="%2$s" title="Password Lost and Found">Lost your password</a>?' ),
+ $username, wp_lostpassword_url() ) );
+
+ return $user;
+}
+
+/**
+ * Authenticate the user using the WordPress auth cookie.
+ */
+function wp_authenticate_cookie($user, $username, $password) {
+ if ( is_a($user, 'WP_User') ) { return $user; }
+
+ if ( empty($username) && empty($password) ) {
+ $user_id = wp_validate_auth_cookie();
+ if ( $user_id )
+ return new WP_User($user_id);
+
+ global $auth_secure_cookie;
+
+ if ( $auth_secure_cookie )
+ $auth_cookie = SECURE_AUTH_COOKIE;
+ else
+ $auth_cookie = AUTH_COOKIE;
+
+ if ( !empty($_COOKIE[$auth_cookie]) )
+ return new WP_Error('expired_session', __('Please log in again.'));
+
+ // If the cookie is not set, be silent.
+ }
+
+ return $user;
+}
+
+/**
+ * For multisite blogs, check if the authenticated user has been marked as a
+ * spammer, or if the user's primary blog has been marked as spam.
+ *
+ * @since 3.7.0
+ */
+function wp_authenticate_spam_check( $user ) {
+ if ( $user && is_a( $user, 'WP_User' ) && is_multisite() ) {
+ $spammed = apply_filters( 'check_is_user_spammed', is_user_spammy(), $user );
+
+ if ( $spammed )
+ return new WP_Error( 'spammer_account', __( '<strong>ERROR</strong>: Your account has been marked as a spammer.' ) );
+ }
+ return $user;
+}
+
+/**
+ * Number of posts user has written.
+ *
+ * @since 3.0.0
+ * @uses $wpdb WordPress database object for queries.
+ *
+ * @param int $userid User ID.
+ * @return int Amount of posts user has written.
+ */
+function count_user_posts($userid) {
+ global $wpdb;
+
+ $where = get_posts_by_author_sql('post', true, $userid);
+
+ $count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->posts $where" );
+
+ return apply_filters('get_usernumposts', $count, $userid);
+}
+
+/**
+ * Number of posts written by a list of users.
+ *
+ * @since 3.0.0
+ *
+ * @param array $users Array of user IDs.
+ * @param string $post_type Optional. Post type to check. Defaults to post.
+ * @param bool $public_only Optional. Only return counts for public posts. Defaults to false.
+ * @return array Amount of posts each user has written.
+ */
+function count_many_users_posts( $users, $post_type = 'post', $public_only = false ) {
+ global $wpdb;
+
+ $count = array();
+ if ( empty( $users ) || ! is_array( $users ) )
+ return $count;
+
+ $userlist = implode( ',', array_map( 'absint', $users ) );
+ $where = get_posts_by_author_sql( $post_type, true, null, $public_only );
+
+ $result = $wpdb->get_results( "SELECT post_author, COUNT(*) FROM $wpdb->posts $where AND post_author IN ($userlist) GROUP BY post_author", ARRAY_N );
+ foreach ( $result as $row ) {
+ $count[ $row[0] ] = $row[1];
+ }
+
+ foreach ( $users as $id ) {
+ if ( ! isset( $count[ $id ] ) )
+ $count[ $id ] = 0;
+ }
+
+ return $count;
+}
+
+//
+// User option functions
+//
+
+/**
+ * Get the current user's ID
+ *
+ * @since MU
+ *
+ * @uses wp_get_current_user
+ *
+ * @return int The current user's ID
+ */
+function get_current_user_id() {
+ $user = wp_get_current_user();
+ return ( isset( $user->ID ) ? (int) $user->ID : 0 );
+}
+
+/**
+ * Retrieve user option that can be either per Site or per Network.
+ *
+ * If the user ID is not given, then the current user will be used instead. If
+ * the user ID is given, then the user data will be retrieved. The filter for
+ * the result, will also pass the original option name and finally the user data
+ * object as the third parameter.
+ *
+ * The option will first check for the per site name and then the per Network name.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries.
+ * @uses apply_filters() Calls 'get_user_option_$option' hook with result,
+ * option parameter, and user data object.
+ *
+ * @param string $option User option name.
+ * @param int $user Optional. User ID.
+ * @param bool $deprecated Use get_option() to check for an option in the options table.
+ * @return mixed
+ */
+function get_user_option( $option, $user = 0, $deprecated = '' ) {
+ global $wpdb;
+
+ if ( !empty( $deprecated ) )
+ _deprecated_argument( __FUNCTION__, '3.0' );
+
+ if ( empty( $user ) )
+ $user = get_current_user_id();
+
+ if ( ! $user = get_userdata( $user ) )
+ return false;
+
+ if ( $user->has_prop( $wpdb->prefix . $option ) ) // Blog specific
+ $result = $user->get( $wpdb->prefix . $option );
+ elseif ( $user->has_prop( $option ) ) // User specific and cross-blog
+ $result = $user->get( $option );
+ else
+ $result = false;
+
+ return apply_filters("get_user_option_{$option}", $result, $option, $user);
+}
+
+/**
+ * Update user option with global blog capability.
+ *
+ * User options are just like user metadata except that they have support for
+ * global blog options. If the 'global' parameter is false, which it is by default
+ * it will prepend the WordPress table prefix to the option name.
+ *
+ * Deletes the user option if $newvalue is empty.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param int $user_id User ID
+ * @param string $option_name User option name.
+ * @param mixed $newvalue User option value.
+ * @param bool $global Optional. Whether option name is global or blog specific. Default false (blog specific).
+ * @return unknown
+ */
+function update_user_option( $user_id, $option_name, $newvalue, $global = false ) {
+ global $wpdb;
+
+ if ( !$global )
+ $option_name = $wpdb->prefix . $option_name;
+
+ return update_user_meta( $user_id, $option_name, $newvalue );
+}
+
+/**
+ * Delete user option with global blog capability.
+ *
+ * User options are just like user metadata except that they have support for
+ * global blog options. If the 'global' parameter is false, which it is by default
+ * it will prepend the WordPress table prefix to the option name.
+ *
+ * @since 3.0.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param int $user_id User ID
+ * @param string $option_name User option name.
+ * @param bool $global Optional. Whether option name is global or blog specific. Default false (blog specific).
+ * @return unknown
+ */
+function delete_user_option( $user_id, $option_name, $global = false ) {
+ global $wpdb;
+
+ if ( !$global )
+ $option_name = $wpdb->prefix . $option_name;
+ return delete_user_meta( $user_id, $option_name );
+}
+
+/**
+ * WordPress User Query class.
+ *
+ * @since 3.1.0
+ */
+class WP_User_Query {
+
+ /**
+ * Query vars, after parsing
+ *
+ * @since 3.5.0
+ * @access public
+ * @var array
+ */
+ var $query_vars = array();
+
+ /**
+ * List of found user ids
+ *
+ * @since 3.1.0
+ * @access private
+ * @var array
+ */
+ var $results;
+
+ /**
+ * Total number of found users for the current query
+ *
+ * @since 3.1.0
+ * @access private
+ * @var int
+ */
+ var $total_users = 0;
+
+ // SQL clauses
+ var $query_fields;
+ var $query_from;
+ var $query_where;
+ var $query_orderby;
+ var $query_limit;
+
+ /**
+ * PHP5 constructor
+ *
+ * @since 3.1.0
+ *
+ * @param string|array $args The query variables
+ * @return WP_User_Query
+ */
+ function __construct( $query = null ) {
+ if ( !empty( $query ) ) {
+ $this->query_vars = wp_parse_args( $query, array(
+ 'blog_id' => $GLOBALS['blog_id'],
+ 'role' => '',
+ 'meta_key' => '',
+ 'meta_value' => '',
+ 'meta_compare' => '',
+ 'include' => array(),
+ 'exclude' => array(),
+ 'search' => '',
+ 'search_columns' => array(),
+ 'orderby' => 'login',
+ 'order' => 'ASC',
+ 'offset' => '',
+ 'number' => '',
+ 'count_total' => true,
+ 'fields' => 'all',
+ 'who' => ''
+ ) );
+
+ $this->prepare_query();
+ $this->query();
+ }
+ }
+
+ /**
+ * Prepare the query variables
+ *
+ * @since 3.1.0
+ * @access private
+ */
+ function prepare_query() {
+ global $wpdb;
+
+ $qv =& $this->query_vars;
+
+ if ( is_array( $qv['fields'] ) ) {
+ $qv['fields'] = array_unique( $qv['fields'] );
+
+ $this->query_fields = array();
+ foreach ( $qv['fields'] as $field ) {
+ $field = 'ID' === $field ? 'ID' : sanitize_key( $field );
+ $this->query_fields[] = "$wpdb->users.$field";
+ }
+ $this->query_fields = implode( ',', $this->query_fields );
+ } elseif ( 'all' == $qv['fields'] ) {
+ $this->query_fields = "$wpdb->users.*";
+ } else {
+ $this->query_fields = "$wpdb->users.ID";
+ }
+
+ if ( $qv['count_total'] )
+ $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
+
+ $this->query_from = "FROM $wpdb->users";
+ $this->query_where = "WHERE 1=1";
+
+ // sorting
+ if ( in_array( $qv['orderby'], array('nicename', 'email', 'url', 'registered') ) ) {
+ $orderby = 'user_' . $qv['orderby'];
+ } elseif ( in_array( $qv['orderby'], array('user_nicename', 'user_email', 'user_url', 'user_registered') ) ) {
+ $orderby = $qv['orderby'];
+ } elseif ( 'name' == $qv['orderby'] || 'display_name' == $qv['orderby'] ) {
+ $orderby = 'display_name';
+ } elseif ( 'post_count' == $qv['orderby'] ) {
+ // todo: avoid the JOIN
+ $where = get_posts_by_author_sql('post');
+ $this->query_from .= " LEFT OUTER JOIN (
+ SELECT post_author, COUNT(*) as post_count
+ FROM $wpdb->posts
+ $where
+ GROUP BY post_author
+ ) p ON ({$wpdb->users}.ID = p.post_author)
+ ";
+ $orderby = 'post_count';
+ } elseif ( 'ID' == $qv['orderby'] || 'id' == $qv['orderby'] ) {
+ $orderby = 'ID';
+ } else {
+ $orderby = 'user_login';
+ }
+
+ $qv['order'] = strtoupper( $qv['order'] );
+ if ( 'ASC' == $qv['order'] )
+ $order = 'ASC';
+ else
+ $order = 'DESC';
+ $this->query_orderby = "ORDER BY $orderby $order";
+
+ // limit
+ if ( $qv['number'] ) {
+ if ( $qv['offset'] )
+ $this->query_limit = $wpdb->prepare("LIMIT %d, %d", $qv['offset'], $qv['number']);
+ else
+ $this->query_limit = $wpdb->prepare("LIMIT %d", $qv['number']);
+ }
+
+ $search = trim( $qv['search'] );
+ if ( $search ) {
+ $leading_wild = ( ltrim($search, '*') != $search );
+ $trailing_wild = ( rtrim($search, '*') != $search );
+ if ( $leading_wild && $trailing_wild )
+ $wild = 'both';
+ elseif ( $leading_wild )
+ $wild = 'leading';
+ elseif ( $trailing_wild )
+ $wild = 'trailing';
+ else
+ $wild = false;
+ if ( $wild )
+ $search = trim($search, '*');
+
+ $search_columns = array();
+ if ( $qv['search_columns'] )
+ $search_columns = array_intersect( $qv['search_columns'], array( 'ID', 'user_login', 'user_email', 'user_url', 'user_nicename' ) );
+ if ( ! $search_columns ) {
+ if ( false !== strpos( $search, '@') )
+ $search_columns = array('user_email');
+ elseif ( is_numeric($search) )
+ $search_columns = array('user_login', 'ID');
+ elseif ( preg_match('|^https?://|', $search) && ! ( is_multisite() && wp_is_large_network( 'users' ) ) )
+ $search_columns = array('user_url');
+ else
+ $search_columns = array('user_login', 'user_nicename');
+ }
+
+ $search_columns = apply_filters( 'user_search_columns', $search_columns, $search, $this );
+
+ $this->query_where .= $this->get_search_sql( $search, $search_columns, $wild );
+ }
+
+ $blog_id = absint( $qv['blog_id'] );
+
+ if ( 'authors' == $qv['who'] && $blog_id ) {
+ $qv['meta_key'] = $wpdb->get_blog_prefix( $blog_id ) . 'user_level';
+ $qv['meta_value'] = 0;
+ $qv['meta_compare'] = '!=';
+ $qv['blog_id'] = $blog_id = 0; // Prevent extra meta query
+ }
+
+ $role = trim( $qv['role'] );
+
+ if ( $blog_id && ( $role || is_multisite() ) ) {
+ $cap_meta_query = array();
+ $cap_meta_query['key'] = $wpdb->get_blog_prefix( $blog_id ) . 'capabilities';
+
+ if ( $role ) {
+ $cap_meta_query['value'] = '"' . $role . '"';
+ $cap_meta_query['compare'] = 'like';
+ }
+
+ $qv['meta_query'][] = $cap_meta_query;
+ }
+
+ $meta_query = new WP_Meta_Query();
+ $meta_query->parse_query_vars( $qv );
+
+ if ( !empty( $meta_query->queries ) ) {
+ $clauses = $meta_query->get_sql( 'user', $wpdb->users, 'ID', $this );
+ $this->query_from .= $clauses['join'];
+ $this->query_where .= $clauses['where'];
+
+ if ( 'OR' == $meta_query->relation )
+ $this->query_fields = 'DISTINCT ' . $this->query_fields;
+ }
+
+ if ( !empty( $qv['include'] ) ) {
+ $ids = implode( ',', wp_parse_id_list( $qv['include'] ) );
+ $this->query_where .= " AND $wpdb->users.ID IN ($ids)";
+ } elseif ( !empty($qv['exclude']) ) {
+ $ids = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
+ $this->query_where .= " AND $wpdb->users.ID NOT IN ($ids)";
+ }
+
+ do_action_ref_array( 'pre_user_query', array( &$this ) );
+ }
+
+ /**
+ * Execute the query, with the current variables
+ *
+ * @since 3.1.0
+ * @access private
+ */
+ function query() {
+ global $wpdb;
+
+ $qv =& $this->query_vars;
+
+ if ( is_array( $qv['fields'] ) || 'all' == $qv['fields'] ) {
+ $this->results = $wpdb->get_results("SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit");
+ } else {
+ $this->results = $wpdb->get_col("SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit");
+ }
+
+ if ( $qv['count_total'] )
+ $this->total_users = $wpdb->get_var( apply_filters( 'found_users_query', 'SELECT FOUND_ROWS()' ) );
+
+ if ( !$this->results )
+ return;
+
+ if ( 'all_with_meta' == $qv['fields'] ) {
+ cache_users( $this->results );
+
+ $r = array();
+ foreach ( $this->results as $userid )
+ $r[ $userid ] = new WP_User( $userid, '', $qv['blog_id'] );
+
+ $this->results = $r;
+ } elseif ( 'all' == $qv['fields'] ) {
+ foreach ( $this->results as $key => $user ) {
+ $this->results[ $key ] = new WP_User( $user );
+ }
+ }
+ }
+
+ /**
+ * Retrieve query variable.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $query_var Query variable key.
+ * @return mixed
+ */
+ function get( $query_var ) {
+ if ( isset( $this->query_vars[$query_var] ) )
+ return $this->query_vars[$query_var];
+
+ return null;
+ }
+
+ /**
+ * Set query variable.
+ *
+ * @since 3.5.0
+ * @access public
+ *
+ * @param string $query_var Query variable key.
+ * @param mixed $value Query variable value.
+ */
+ function set( $query_var, $value ) {
+ $this->query_vars[$query_var] = $value;
+ }
+
+ /*
+ * Used internally to generate an SQL string for searching across multiple columns
+ *
+ * @access protected
+ * @since 3.1.0
+ *
+ * @param string $string
+ * @param array $cols
+ * @param bool $wild Whether to allow wildcard searches. Default is false for Network Admin, true for
+ * single site. Single site allows leading and trailing wildcards, Network Admin only trailing.
+ * @return string
+ */
+ function get_search_sql( $string, $cols, $wild = false ) {
+ $string = esc_sql( $string );
+
+ $searches = array();
+ $leading_wild = ( 'leading' == $wild || 'both' == $wild ) ? '%' : '';
+ $trailing_wild = ( 'trailing' == $wild || 'both' == $wild ) ? '%' : '';
+ foreach ( $cols as $col ) {
+ if ( 'ID' == $col )
+ $searches[] = "$col = '$string'";
+ else
+ $searches[] = "$col LIKE '$leading_wild" . like_escape($string) . "$trailing_wild'";
+ }
+
+ return ' AND (' . implode(' OR ', $searches) . ')';
+ }
+
+ /**
+ * Return the list of users
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return array
+ */
+ function get_results() {
+ return $this->results;
+ }
+
+ /**
+ * Return the total number of users for the current query
+ *
+ * @since 3.1.0
+ * @access public
+ *
+ * @return array
+ */
+ function get_total() {
+ return $this->total_users;
+ }
+}
+
+/**
+ * Retrieve list of users matching criteria.
+ *
+ * @since 3.1.0
+ * @uses $wpdb
+ * @uses WP_User_Query See for default arguments and information.
+ *
+ * @param array $args Optional.
+ * @return array List of users.
+ */
+function get_users( $args = array() ) {
+
+ $args = wp_parse_args( $args );
+ $args['count_total'] = false;
+
+ $user_search = new WP_User_Query($args);
+
+ return (array) $user_search->get_results();
+}
+
+/**
+ * Get the blogs a user belongs to.
+ *
+ * @since 3.0.0
+ *
+ * @param int $user_id User ID
+ * @param bool $all Whether to retrieve all blogs, or only blogs that are not marked as deleted, archived, or spam.
+ * @return array A list of the user's blogs. An empty array if the user doesn't exist or belongs to no blogs.
+ */
+function get_blogs_of_user( $user_id, $all = false ) {
+ global $wpdb;
+
+ $user_id = (int) $user_id;
+
+ // Logged out users can't have blogs
+ if ( empty( $user_id ) )
+ return array();
+
+ $keys = get_user_meta( $user_id );
+ if ( empty( $keys ) )
+ return array();
+
+ if ( ! is_multisite() ) {
+ $blog_id = get_current_blog_id();
+ $blogs = array( $blog_id => new stdClass );
+ $blogs[ $blog_id ]->userblog_id = $blog_id;
+ $blogs[ $blog_id ]->blogname = get_option('blogname');
+ $blogs[ $blog_id ]->domain = '';
+ $blogs[ $blog_id ]->path = '';
+ $blogs[ $blog_id ]->site_id = 1;
+ $blogs[ $blog_id ]->siteurl = get_option('siteurl');
+ $blogs[ $blog_id ]->archived = 0;
+ $blogs[ $blog_id ]->spam = 0;
+ $blogs[ $blog_id ]->deleted = 0;
+ return $blogs;
+ }
+
+ $blogs = array();
+
+ if ( isset( $keys[ $wpdb->base_prefix . 'capabilities' ] ) && defined( 'MULTISITE' ) ) {
+ $blog = get_blog_details( 1 );
+ if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
+ $blogs[ 1 ] = (object) array(
+ 'userblog_id' => 1,
+ 'blogname' => $blog->blogname,
+ 'domain' => $blog->domain,
+ 'path' => $blog->path,
+ 'site_id' => $blog->site_id,
+ 'siteurl' => $blog->siteurl,
+ 'archived' => 0,
+ 'spam' => 0,
+ 'deleted' => 0
+ );
+ }
+ unset( $keys[ $wpdb->base_prefix . 'capabilities' ] );
+ }
+
+ $keys = array_keys( $keys );
+
+ foreach ( $keys as $key ) {
+ if ( 'capabilities' !== substr( $key, -12 ) )
+ continue;
+ if ( $wpdb->base_prefix && 0 !== strpos( $key, $wpdb->base_prefix ) )
+ continue;
+ $blog_id = str_replace( array( $wpdb->base_prefix, '_capabilities' ), '', $key );
+ if ( ! is_numeric( $blog_id ) )
+ continue;
+
+ $blog_id = (int) $blog_id;
+ $blog = get_blog_details( $blog_id );
+ if ( $blog && isset( $blog->domain ) && ( $all || ( ! $blog->archived && ! $blog->spam && ! $blog->deleted ) ) ) {
+ $blogs[ $blog_id ] = (object) array(
+ 'userblog_id' => $blog_id,
+ 'blogname' => $blog->blogname,
+ 'domain' => $blog->domain,
+ 'path' => $blog->path,
+ 'site_id' => $blog->site_id,
+ 'siteurl' => $blog->siteurl,
+ 'archived' => 0,
+ 'spam' => 0,
+ 'deleted' => 0
+ );
+ }
+ }
+
+ return apply_filters( 'get_blogs_of_user', $blogs, $user_id, $all );
+}
+
+/**
+ * Find out whether a user is a member of a given blog.
+ *
+ * @since MU 1.1
+ * @uses get_blogs_of_user()
+ *
+ * @param int $user_id Optional. The unique ID of the user. Defaults to the current user.
+ * @param int $blog_id Optional. ID of the blog to check. Defaults to the current site.
+ * @return bool
+ */
+function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
+ $user_id = (int) $user_id;
+ $blog_id = (int) $blog_id;
+
+ if ( empty( $user_id ) )
+ $user_id = get_current_user_id();
+
+ if ( empty( $blog_id ) )
+ $blog_id = get_current_blog_id();
+
+ $blogs = get_blogs_of_user( $user_id );
+ return array_key_exists( $blog_id, $blogs );
+}
+
+/**
+ * Add meta data field to a user.
+ *
+ * Post meta data is called "Custom Fields" on the Administration Screens.
+ *
+ * @since 3.0.0
+ * @uses add_metadata()
+ * @link http://codex.wordpress.org/Function_Reference/add_user_meta
+ *
+ * @param int $user_id Post ID.
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Metadata value.
+ * @param bool $unique Optional, default is false. Whether the same key should not be added.
+ * @return int|bool Meta ID on success, false on failure.
+ */
+function add_user_meta($user_id, $meta_key, $meta_value, $unique = false) {
+ return add_metadata('user', $user_id, $meta_key, $meta_value, $unique);
+}
+
+/**
+ * Remove metadata matching criteria from a user.
+ *
+ * You can match based on the key, or key and value. Removing based on key and
+ * value, will keep from removing duplicate metadata with the same key. It also
+ * allows removing all metadata matching key, if needed.
+ *
+ * @since 3.0.0
+ * @uses delete_metadata()
+ * @link http://codex.wordpress.org/Function_Reference/delete_user_meta
+ *
+ * @param int $user_id user ID
+ * @param string $meta_key Metadata name.
+ * @param mixed $meta_value Optional. Metadata value.
+ * @return bool True on success, false on failure.
+ */
+function delete_user_meta($user_id, $meta_key, $meta_value = '') {
+ return delete_metadata('user', $user_id, $meta_key, $meta_value);
+}
+
+/**
+ * Retrieve user meta field for a user.
+ *
+ * @since 3.0.0
+ * @uses get_metadata()
+ * @link http://codex.wordpress.org/Function_Reference/get_user_meta
+ *
+ * @param int $user_id Post ID.
+ * @param string $key Optional. The meta key to retrieve. By default, returns data for all keys.
+ * @param bool $single Whether to return a single value.
+ * @return mixed Will be an array if $single is false. Will be value of meta data field if $single
+ * is true.
+ */
+function get_user_meta($user_id, $key = '', $single = false) {
+ return get_metadata('user', $user_id, $key, $single);
+}
+
+/**
+ * Update user meta field based on user ID.
+ *
+ * Use the $prev_value parameter to differentiate between meta fields with the
+ * same key and user ID.
+ *
+ * If the meta field for the user does not exist, it will be added.
+ *
+ * @since 3.0.0
+ * @uses update_metadata
+ * @link http://codex.wordpress.org/Function_Reference/update_user_meta
+ *
+ * @param int $user_id Post ID.
+ * @param string $meta_key Metadata key.
+ * @param mixed $meta_value Metadata value.
+ * @param mixed $prev_value Optional. Previous value to check before removing.
+ * @return bool True on success, false on failure.
+ */
+function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = '') {
+ return update_metadata('user', $user_id, $meta_key, $meta_value, $prev_value);
+}
+
+/**
+ * Count number of users who have each of the user roles.
+ *
+ * Assumes there are neither duplicated nor orphaned capabilities meta_values.
+ * Assumes role names are unique phrases. Same assumption made by WP_User_Query::prepare_query()
+ * Using $strategy = 'time' this is CPU-intensive and should handle around 10^7 users.
+ * Using $strategy = 'memory' this is memory-intensive and should handle around 10^5 users, but see WP Bug #12257.
+ *
+ * @since 3.0.0
+ * @param string $strategy 'time' or 'memory'
+ * @return array Includes a grand total and an array of counts indexed by role strings.
+ */
+function count_users($strategy = 'time') {
+ global $wpdb, $wp_roles;
+
+ // Initialize
+ $id = get_current_blog_id();
+ $blog_prefix = $wpdb->get_blog_prefix($id);
+ $result = array();
+
+ if ( 'time' == $strategy ) {
+ global $wp_roles;
+
+ if ( ! isset( $wp_roles ) )
+ $wp_roles = new WP_Roles();
+
+ $avail_roles = $wp_roles->get_names();
+
+ // Build a CPU-intensive query that will return concise information.
+ $select_count = array();
+ foreach ( $avail_roles as $this_role => $name ) {
+ $select_count[] = "COUNT(NULLIF(`meta_value` LIKE '%\"" . like_escape( $this_role ) . "\"%', false))";
+ }
+ $select_count = implode(', ', $select_count);
+
+ // Add the meta_value index to the selection list, then run the query.
+ $row = $wpdb->get_row( "SELECT $select_count, COUNT(*) FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'", ARRAY_N );
+
+ // Run the previous loop again to associate results with role names.
+ $col = 0;
+ $role_counts = array();
+ foreach ( $avail_roles as $this_role => $name ) {
+ $count = (int) $row[$col++];
+ if ($count > 0) {
+ $role_counts[$this_role] = $count;
+ }
+ }
+
+ // Get the meta_value index from the end of the result set.
+ $total_users = (int) $row[$col];
+
+ $result['total_users'] = $total_users;
+ $result['avail_roles'] =& $role_counts;
+ } else {
+ $avail_roles = array();
+
+ $users_of_blog = $wpdb->get_col( "SELECT meta_value FROM $wpdb->usermeta WHERE meta_key = '{$blog_prefix}capabilities'" );
+
+ foreach ( $users_of_blog as $caps_meta ) {
+ $b_roles = maybe_unserialize($caps_meta);
+ if ( ! is_array( $b_roles ) )
+ continue;
+ foreach ( $b_roles as $b_role => $val ) {
+ if ( isset($avail_roles[$b_role]) ) {
+ $avail_roles[$b_role]++;
+ } else {
+ $avail_roles[$b_role] = 1;
+ }
+ }
+ }
+
+ $result['total_users'] = count( $users_of_blog );
+ $result['avail_roles'] =& $avail_roles;
+ }
+
+ return $result;
+}
+
+//
+// Private helper functions
+//
+
+/**
+ * Set up global user vars.
+ *
+ * Used by wp_set_current_user() for back compat. Might be deprecated in the future.
+ *
+ * @since 2.0.4
+ * @global string $userdata User description.
+ * @global string $user_login The user username for logging in
+ * @global int $user_level The level of the user
+ * @global int $user_ID The ID of the user
+ * @global string $user_email The email address of the user
+ * @global string $user_url The url in the user's profile
+ * @global string $user_identity The display name of the user
+ *
+ * @param int $for_user_id Optional. User ID to set up global data.
+ */
+function setup_userdata($for_user_id = '') {
+ global $user_login, $userdata, $user_level, $user_ID, $user_email, $user_url, $user_identity;
+
+ if ( '' == $for_user_id )
+ $for_user_id = get_current_user_id();
+ $user = get_userdata( $for_user_id );
+
+ if ( ! $user ) {
+ $user_ID = 0;
+ $user_level = 0;
+ $userdata = null;
+ $user_login = $user_email = $user_url = $user_identity = '';
+ return;
+ }
+
+ $user_ID = (int) $user->ID;
+ $user_level = (int) $user->user_level;
+ $userdata = $user;
+ $user_login = $user->user_login;
+ $user_email = $user->user_email;
+ $user_url = $user->user_url;
+ $user_identity = $user->display_name;
+}
+
+/**
+ * Create dropdown HTML content of users.
+ *
+ * The content can either be displayed, which it is by default or retrieved by
+ * setting the 'echo' argument. The 'include' and 'exclude' arguments do not
+ * need to be used; all users will be displayed in that case. Only one can be
+ * used, either 'include' or 'exclude', but not both.
+ *
+ * The available arguments are as follows:
+ * <ol>
+ * <li>show_option_all - Text to show all and whether HTML option exists.</li>
+ * <li>show_option_none - Text for show none and whether HTML option exists.</li>
+ * <li>hide_if_only_one_author - Don't create the dropdown if there is only one user.</li>
+ * <li>orderby - SQL order by clause for what order the users appear. Default is 'display_name'.</li>
+ * <li>order - Default is 'ASC'. Can also be 'DESC'.</li>
+ * <li>include - User IDs to include.</li>
+ * <li>exclude - User IDs to exclude.</li>
+ * <li>multi - Default is 'false'. Whether to skip the ID attribute on the 'select' element. A 'true' value is overridden when id argument is set.</li>
+ * <li>show - Default is 'display_name'. User table column to display. If the selected item is empty then the user_login will be displayed in parentheses</li>
+ * <li>echo - Default is '1'. Whether to display or retrieve content.</li>
+ * <li>selected - Which User ID is selected.</li>
+ * <li>include_selected - Always include the selected user ID in the dropdown. Default is false.</li>
+ * <li>name - Default is 'user'. Name attribute of select element.</li>
+ * <li>id - Default is the value of the 'name' parameter. ID attribute of select element.</li>
+ * <li>class - Class attribute of select element.</li>
+ * <li>blog_id - ID of blog (Multisite only). Defaults to ID of current blog.</li>
+ * <li>who - Which users to query. Currently only 'authors' is supported. Default is all users.</li>
+ * </ol>
+ *
+ * @since 2.3.0
+ * @uses $wpdb WordPress database object for queries
+ *
+ * @param string|array $args Optional. Override defaults.
+ * @return string|null Null on display. String of HTML content on retrieve.
+ */
+function wp_dropdown_users( $args = '' ) {
+ $defaults = array(
+ 'show_option_all' => '', 'show_option_none' => '', 'hide_if_only_one_author' => '',
+ 'orderby' => 'display_name', 'order' => 'ASC',
+ 'include' => '', 'exclude' => '', 'multi' => 0,
+ 'show' => 'display_name', 'echo' => 1,
+ 'selected' => 0, 'name' => 'user', 'class' => '', 'id' => '',
+ 'blog_id' => $GLOBALS['blog_id'], 'who' => '', 'include_selected' => false
+ );
+
+ $defaults['selected'] = is_author() ? get_query_var( 'author' ) : 0;
+
+ $r = wp_parse_args( $args, $defaults );
+ extract( $r, EXTR_SKIP );
+
+ $query_args = wp_array_slice_assoc( $r, array( 'blog_id', 'include', 'exclude', 'orderby', 'order', 'who' ) );
+ $query_args['fields'] = array( 'ID', 'user_login', $show );
+ $users = get_users( $query_args );
+
+ $output = '';
+ if ( !empty($users) && ( empty($hide_if_only_one_author) || count($users) > 1 ) ) {
+ $name = esc_attr( $name );
+ if ( $multi && ! $id )
+ $id = '';
+ else
+ $id = $id ? " id='" . esc_attr( $id ) . "'" : " id='$name'";
+
+ $output = "<select name='{$name}'{$id} class='$class'>\n";
+
+ if ( $show_option_all )
+ $output .= "\t<option value='0'>$show_option_all</option>\n";
+
+ if ( $show_option_none ) {
+ $_selected = selected( -1, $selected, false );
+ $output .= "\t<option value='-1'$_selected>$show_option_none</option>\n";
+ }
+
+ $found_selected = false;
+ foreach ( (array) $users as $user ) {
+ $user->ID = (int) $user->ID;
+ $_selected = selected( $user->ID, $selected, false );
+ if ( $_selected )
+ $found_selected = true;
+ $display = !empty($user->$show) ? $user->$show : '('. $user->user_login . ')';
+ $output .= "\t<option value='$user->ID'$_selected>" . esc_html($display) . "</option>\n";
+ }
+
+ if ( $include_selected && ! $found_selected && ( $selected > 0 ) ) {
+ $user = get_userdata( $selected );
+ $_selected = selected( $user->ID, $selected, false );
+ $display = !empty($user->$show) ? $user->$show : '('. $user->user_login . ')';
+ $output .= "\t<option value='$user->ID'$_selected>" . esc_html($display) . "</option>\n";
+ }
+
+ $output .= "</select>";
+ }
+
+ $output = apply_filters('wp_dropdown_users', $output);
+
+ if ( $echo )
+ echo $output;
+
+ return $output;
+}
+
+/**
+ * Sanitize user field based on context.
+ *
+ * Possible context values are: 'raw', 'edit', 'db', 'display', 'attribute' and 'js'. The
+ * 'display' context is used by default. 'attribute' and 'js' contexts are treated like 'display'
+ * when calling filters.
+ *
+ * @since 2.3.0
+ * @uses apply_filters() Calls 'edit_$field' passing $value and $user_id if $context == 'edit'.
+ * $field is prefixed with 'user_' if it isn't already.
+ * @uses apply_filters() Calls 'pre_$field' passing $value if $context == 'db'. $field is prefixed with
+ * 'user_' if it isn't already.
+ * @uses apply_filters() Calls '$field' passing $value, $user_id and $context if $context == anything
+ * other than 'raw', 'edit' and 'db'. $field is prefixed with 'user_' if it isn't already.
+ *
+ * @param string $field The user Object field name.
+ * @param mixed $value The user Object value.
+ * @param int $user_id user ID.
+ * @param string $context How to sanitize user fields. Looks for 'raw', 'edit', 'db', 'display',
+ * 'attribute' and 'js'.
+ * @return mixed Sanitized value.
+ */
+function sanitize_user_field($field, $value, $user_id, $context) {
+ $int_fields = array('ID');
+ if ( in_array($field, $int_fields) )
+ $value = (int) $value;
+
+ if ( 'raw' == $context )
+ return $value;
+
+ if ( !is_string($value) && !is_numeric($value) )
+ return $value;
+
+ $prefixed = false !== strpos( $field, 'user_' );
+
+ if ( 'edit' == $context ) {
+ if ( $prefixed ) {
+ $value = apply_filters("edit_{$field}", $value, $user_id);
+ } else {
+ $value = apply_filters("edit_user_{$field}", $value, $user_id);
+ }
+
+ if ( 'description' == $field )
+ $value = esc_html( $value ); // textarea_escaped?
+ else
+ $value = esc_attr($value);
+ } else if ( 'db' == $context ) {
+ if ( $prefixed ) {
+ $value = apply_filters("pre_{$field}", $value);
+ } else {
+ $value = apply_filters("pre_user_{$field}", $value);
+ }
+ } else {
+ // Use display filters by default.
+ if ( $prefixed )
+ $value = apply_filters($field, $value, $user_id, $context);
+ else
+ $value = apply_filters("user_{$field}", $value, $user_id, $context);
+ }
+
+ if ( 'user_url' == $field )
+ $value = esc_url($value);
+
+ if ( 'attribute' == $context )
+ $value = esc_attr($value);
+ else if ( 'js' == $context )
+ $value = esc_js($value);
+
+ return $value;
+}
+
+/**
+ * Update all user caches
+ *
+ * @since 3.0.0
+ *
+ * @param object $user User object to be cached
+ */
+function update_user_caches($user) {
+ wp_cache_add($user->ID, $user, 'users');
+ wp_cache_add($user->user_login, $user->ID, 'userlogins');
+ wp_cache_add($user->user_email, $user->ID, 'useremail');
+ wp_cache_add($user->user_nicename, $user->ID, 'userslugs');
+}
+
+/**
+ * Clean all user caches
+ *
+ * @since 3.0.0
+ *
+ * @param WP_User|int $user User object or ID to be cleaned from the cache
+ */
+function clean_user_cache( $user ) {
+ if ( is_numeric( $user ) )
+ $user = new WP_User( $user );
+
+ if ( ! $user->exists() )
+ return;
+
+ wp_cache_delete( $user->ID, 'users' );
+ wp_cache_delete( $user->user_login, 'userlogins' );
+ wp_cache_delete( $user->user_email, 'useremail' );
+ wp_cache_delete( $user->user_nicename, 'userslugs' );
+}
+
+/**
+ * Checks whether the given username exists.
+ *
+ * @since 2.0.0
+ *
+ * @param string $username Username.
+ * @return null|int The user's ID on success, and null on failure.
+ */
+function username_exists( $username ) {
+ if ( $user = get_user_by('login', $username ) ) {
+ return $user->ID;
+ } else {
+ return null;
+ }
+}
+
+/**
+ * Checks whether the given email exists.
+ *
+ * @since 2.1.0
+ * @uses $wpdb
+ *
+ * @param string $email Email.
+ * @return bool|int The user's ID on success, and false on failure.
+ */
+function email_exists( $email ) {
+ if ( $user = get_user_by('email', $email) )
+ return $user->ID;
+
+ return false;
+}
+
+/**
+ * Checks whether an username is valid.
+ *
+ * @since 2.0.1
+ * @uses apply_filters() Calls 'validate_username' hook on $valid check and $username as parameters
+ *
+ * @param string $username Username.
+ * @return bool Whether username given is valid
+ */
+function validate_username( $username ) {
+ $sanitized = sanitize_user( $username, true );
+ $valid = ( $sanitized == $username );
+ return apply_filters( 'validate_username', $valid, $username );
+}
+
+/**
+ * Insert an user into the database.
+ *
+ * Can update a current user or insert a new user based on whether the user's ID
+ * is present.
+ *
+ * Can be used to update the user's info (see below), set the user's role, and
+ * set the user's preference on whether they want the rich editor on.
+ *
+ * Most of the $userdata array fields have filters associated with the values.
+ * The exceptions are 'rich_editing', 'role', 'jabber', 'aim', 'yim',
+ * 'user_registered', and 'ID'. The filters have the prefix 'pre_user_' followed
+ * by the field name. An example using 'description' would have the filter
+ * called, 'pre_user_description' that can be hooked into.
+ *
+ * The $userdata array can contain the following fields:
+ * 'ID' - An integer that will be used for updating an existing user.
+ * 'user_pass' - A string that contains the plain text password for the user.
+ * 'user_login' - A string that contains the user's username for logging in.
+ * 'user_nicename' - A string that contains a URL-friendly name for the user.
+ * The default is the user's username.
+ * 'user_url' - A string containing the user's URL for the user's web site.
+ * 'user_email' - A string containing the user's email address.
+ * 'display_name' - A string that will be shown on the site. Defaults to user's
+ * username. It is likely that you will want to change this, for appearance.
+ * 'nickname' - The user's nickname, defaults to the user's username.
+ * 'first_name' - The user's first name.
+ * 'last_name' - The user's last name.
+ * 'description' - A string containing content about the user.
+ * 'rich_editing' - A string for whether to enable the rich editor. False
+ * if not empty.
+ * 'user_registered' - The date the user registered. Format is 'Y-m-d H:i:s'.
+ * 'role' - A string used to set the user's role.
+ * 'jabber' - User's Jabber account.
+ * 'aim' - User's AOL IM account.
+ * 'yim' - User's Yahoo IM account.
+ *
+ * @since 2.0.0
+ * @uses $wpdb WordPress database layer.
+ * @uses apply_filters() Calls filters for most of the $userdata fields with the prefix 'pre_user'. See note above.
+ * @uses do_action() Calls 'profile_update' hook when updating giving the user's ID
+ * @uses do_action() Calls 'user_register' hook when creating a new user giving the user's ID
+ *
+ * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
+ * @return int|WP_Error The newly created user's ID or a WP_Error object if the user could not be created.
+ */
+function wp_insert_user( $userdata ) {
+ global $wpdb;
+
+ if ( is_a( $userdata, 'stdClass' ) )
+ $userdata = get_object_vars( $userdata );
+ elseif ( is_a( $userdata, 'WP_User' ) )
+ $userdata = $userdata->to_array();
+
+ extract( $userdata, EXTR_SKIP );
+
+ // Are we updating or creating?
+ if ( !empty($ID) ) {
+ $ID = (int) $ID;
+ $update = true;
+ $old_user_data = WP_User::get_data_by( 'id', $ID );
+ } else {
+ $update = false;
+ // Hash the password
+ $user_pass = wp_hash_password($user_pass);
+ }
+
+ $user_login = sanitize_user($user_login, true);
+ $user_login = apply_filters('pre_user_login', $user_login);
+
+ //Remove any non-printable chars from the login string to see if we have ended up with an empty username
+ $user_login = trim($user_login);
+
+ if ( empty($user_login) )
+ return new WP_Error('empty_user_login', __('Cannot create a user with an empty login name.') );
+
+ if ( !$update && username_exists( $user_login ) )
+ return new WP_Error( 'existing_user_login', __( 'Sorry, that username already exists!' ) );
+
+ if ( empty($user_nicename) )
+ $user_nicename = sanitize_title( $user_login );
+ $user_nicename = apply_filters('pre_user_nicename', $user_nicename);
+
+ if ( empty($user_url) )
+ $user_url = '';
+ $user_url = apply_filters('pre_user_url', $user_url);
+
+ if ( empty($user_email) )
+ $user_email = '';
+ $user_email = apply_filters('pre_user_email', $user_email);
+
+ if ( !$update && ! defined( 'WP_IMPORTING' ) && email_exists($user_email) )
+ return new WP_Error( 'existing_user_email', __( 'Sorry, that email address is already used!' ) );
+
+ if ( empty($nickname) )
+ $nickname = $user_login;
+ $nickname = apply_filters('pre_user_nickname', $nickname);
+
+ if ( empty($first_name) )
+ $first_name = '';
+ $first_name = apply_filters('pre_user_first_name', $first_name);
+
+ if ( empty($last_name) )
+ $last_name = '';
+ $last_name = apply_filters('pre_user_last_name', $last_name);
+
+ if ( empty( $display_name ) ) {
+ if ( $update )
+ $display_name = $user_login;
+ elseif ( $first_name && $last_name )
+ /* translators: 1: first name, 2: last name */
+ $display_name = sprintf( _x( '%1$s %2$s', 'Display name based on first name and last name' ), $first_name, $last_name );
+ elseif ( $first_name )
+ $display_name = $first_name;
+ elseif ( $last_name )
+ $display_name = $last_name;
+ else
+ $display_name = $user_login;
+ }
+ $display_name = apply_filters( 'pre_user_display_name', $display_name );
+
+ if ( empty($description) )
+ $description = '';
+ $description = apply_filters('pre_user_description', $description);
+
+ if ( empty($rich_editing) )
+ $rich_editing = 'true';
+
+ if ( empty($comment_shortcuts) )
+ $comment_shortcuts = 'false';
+
+ if ( empty($admin_color) )
+ $admin_color = 'fresh';
+ $admin_color = preg_replace('|[^a-z0-9 _.\-@]|i', '', $admin_color);
+
+ if ( empty($use_ssl) )
+ $use_ssl = 0;
+
+ if ( empty($user_registered) )
+ $user_registered = gmdate('Y-m-d H:i:s');
+
+ if ( empty($show_admin_bar_front) )
+ $show_admin_bar_front = 'true';
+
+ $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $user_nicename, $user_login));
+
+ if ( $user_nicename_check ) {
+ $suffix = 2;
+ while ($user_nicename_check) {
+ $alt_user_nicename = $user_nicename . "-$suffix";
+ $user_nicename_check = $wpdb->get_var( $wpdb->prepare("SELECT ID FROM $wpdb->users WHERE user_nicename = %s AND user_login != %s LIMIT 1" , $alt_user_nicename, $user_login));
+ $suffix++;
+ }
+ $user_nicename = $alt_user_nicename;
+ }
+
+ $data = compact( 'user_pass', 'user_email', 'user_url', 'user_nicename', 'display_name', 'user_registered' );
+ $data = wp_unslash( $data );
+
+ if ( $update ) {
+ $wpdb->update( $wpdb->users, $data, compact( 'ID' ) );
+ $user_id = (int) $ID;
+ } else {
+ $wpdb->insert( $wpdb->users, $data + compact( 'user_login' ) );
+ $user_id = (int) $wpdb->insert_id;
+ }
+
+ $user = new WP_User( $user_id );
+
+ foreach ( _get_additional_user_keys( $user ) as $key ) {
+ if ( isset( $$key ) )
+ update_user_meta( $user_id, $key, $$key );
+ }
+
+ if ( isset($role) )
+ $user->set_role($role);
+ elseif ( !$update )
+ $user->set_role(get_option('default_role'));
+
+ wp_cache_delete($user_id, 'users');
+ wp_cache_delete($user_login, 'userlogins');
+
+ if ( $update )
+ do_action('profile_update', $user_id, $old_user_data);
+ else
+ do_action('user_register', $user_id);
+
+ return $user_id;
+}
+
+/**
+ * Update an user in the database.
+ *
+ * It is possible to update a user's password by specifying the 'user_pass'
+ * value in the $userdata parameter array.
+ *
+ * If current user's password is being updated, then the cookies will be
+ * cleared.
+ *
+ * @since 2.0.0
+ * @see wp_insert_user() For what fields can be set in $userdata
+ * @uses wp_insert_user() Used to update existing user or add new one if user doesn't exist already
+ *
+ * @param mixed $userdata An array of user data or a user object of type stdClass or WP_User.
+ * @return int|WP_Error The updated user's ID or a WP_Error object if the user could not be updated.
+ */
+function wp_update_user($userdata) {
+ if ( is_a( $userdata, 'stdClass' ) )
+ $userdata = get_object_vars( $userdata );
+ elseif ( is_a( $userdata, 'WP_User' ) )
+ $userdata = $userdata->to_array();
+
+ $ID = (int) $userdata['ID'];
+
+ // First, get all of the original fields
+ $user_obj = get_userdata( $ID );
+ if ( ! $user_obj )
+ return new WP_Error( 'invalid_user_id', __( 'Invalid user ID.' ) );
+
+ $user = $user_obj->to_array();
+
+ // Add additional custom fields
+ foreach ( _get_additional_user_keys( $user_obj ) as $key ) {
+ $user[ $key ] = get_user_meta( $ID, $key, true );
+ }
+
+ // Escape data pulled from DB.
+ $user = add_magic_quotes( $user );
+
+ // If password is changing, hash it now.
+ if ( ! empty($userdata['user_pass']) ) {
+ $plaintext_pass = $userdata['user_pass'];
+ $userdata['user_pass'] = wp_hash_password($userdata['user_pass']);
+ }
+
+ wp_cache_delete($user[ 'user_email' ], 'useremail');
+
+ // Merge old and new fields with new fields overwriting old ones.
+ $userdata = array_merge($user, $userdata);
+ $user_id = wp_insert_user($userdata);
+
+ // Update the cookies if the password changed.
+ $current_user = wp_get_current_user();
+ if ( $current_user->ID == $ID ) {
+ if ( isset($plaintext_pass) ) {
+ wp_clear_auth_cookie();
+ wp_set_auth_cookie($ID);
+ }
+ }
+
+ return $user_id;
+}
+
+/**
+ * A simpler way of inserting an user into the database.
+ *
+ * Creates a new user with just the username, password, and email. For more
+ * complex user creation use wp_insert_user() to specify more information.
+ *
+ * @since 2.0.0
+ * @see wp_insert_user() More complete way to create a new user
+ *
+ * @param string $username The user's username.
+ * @param string $password The user's password.
+ * @param string $email The user's email (optional).
+ * @return int The new user's ID.
+ */
+function wp_create_user($username, $password, $email = '') {
+ $user_login = wp_slash( $username );
+ $user_email = wp_slash( $email );
+ $user_pass = $password;
+
+ $userdata = compact('user_login', 'user_email', 'user_pass');
+ return wp_insert_user($userdata);
+}
+
+/**
+ * Return a list of meta keys that wp_insert_user() is supposed to set.
+ *
+ * @since 3.3.0
+ * @access private
+ *
+ * @param object $user WP_User instance.
+ * @return array
+ */
+function _get_additional_user_keys( $user ) {
+ $keys = array( 'first_name', 'last_name', 'nickname', 'description', 'rich_editing', 'comment_shortcuts', 'admin_color', 'use_ssl', 'show_admin_bar_front' );
+ return array_merge( $keys, array_keys( _wp_get_user_contactmethods( $user ) ) );
+}
+
+/**
+ * Set up the contact methods.
+ *
+ * Default contact methods were removed in 3.6. A filter dictates contact methods.
+ *
+ * @since 2.9.0
+ * @access private
+ *
+ * @param object $user User data object (optional).
+ * @return array $user_contactmethods Array of contact methods and their labels.
+ */
+function _wp_get_user_contactmethods( $user = null ) {
+ $user_contactmethods = array();
+ if ( get_site_option( 'initial_db_version' ) < 23588 ) {
+ $user_contactmethods = array(
+ 'aim' => __( 'AIM' ),
+ 'yim' => __( 'Yahoo IM' ),
+ 'jabber' => __( 'Jabber / Google Talk' )
+ );
+ }
+ return apply_filters( 'user_contactmethods', $user_contactmethods, $user );
+}
diff --git a/src/wp-includes/vars.php b/src/wp-includes/vars.php
new file mode 100644
index 0000000000..f55cdbd9fd
--- /dev/null
+++ b/src/wp-includes/vars.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * Creates common globals for the rest of WordPress
+ *
+ * Sets $pagenow global which is the current page. Checks
+ * for the browser to set which one is currently being used.
+ *
+ * Detects which user environment WordPress is being used on.
+ * Only attempts to check for Apache and IIS. Two web servers
+ * with known permalink capability.
+ *
+ * @package WordPress
+ */
+
+global $pagenow,
+ $is_lynx, $is_gecko, $is_winIE, $is_macIE, $is_opera, $is_NS4, $is_safari, $is_chrome, $is_iphone, $is_IE,
+ $is_apache, $is_IIS, $is_iis7;
+
+// On which page are we ?
+if ( is_admin() ) {
+ // wp-admin pages are checked more carefully
+ if ( is_network_admin() )
+ preg_match('#/wp-admin/network/?(.*?)$#i', $_SERVER['PHP_SELF'], $self_matches);
+ elseif ( is_user_admin() )
+ preg_match('#/wp-admin/user/?(.*?)$#i', $_SERVER['PHP_SELF'], $self_matches);
+ else
+ preg_match('#/wp-admin/?(.*?)$#i', $_SERVER['PHP_SELF'], $self_matches);
+ $pagenow = $self_matches[1];
+ $pagenow = trim($pagenow, '/');
+ $pagenow = preg_replace('#\?.*?$#', '', $pagenow);
+ if ( '' === $pagenow || 'index' === $pagenow || 'index.php' === $pagenow ) {
+ $pagenow = 'index.php';
+ } else {
+ preg_match('#(.*?)(/|$)#', $pagenow, $self_matches);
+ $pagenow = strtolower($self_matches[1]);
+ if ( '.php' !== substr($pagenow, -4, 4) )
+ $pagenow .= '.php'; // for Options +Multiviews: /wp-admin/themes/index.php (themes.php is queried)
+ }
+} else {
+ if ( preg_match('#([^/]+\.php)([?/].*?)?$#i', $_SERVER['PHP_SELF'], $self_matches) )
+ $pagenow = strtolower($self_matches[1]);
+ else
+ $pagenow = 'index.php';
+}
+unset($self_matches);
+
+// Simple browser detection
+$is_lynx = $is_gecko = $is_winIE = $is_macIE = $is_opera = $is_NS4 = $is_safari = $is_chrome = $is_iphone = false;
+
+if ( isset($_SERVER['HTTP_USER_AGENT']) ) {
+ if ( strpos($_SERVER['HTTP_USER_AGENT'], 'Lynx') !== false ) {
+ $is_lynx = true;
+ } elseif ( stripos($_SERVER['HTTP_USER_AGENT'], 'chrome') !== false ) {
+ if ( stripos( $_SERVER['HTTP_USER_AGENT'], 'chromeframe' ) !== false ) {
+ if ( $is_chrome = apply_filters( 'use_google_chrome_frame', is_admin() ) )
+ header( 'X-UA-Compatible: chrome=1' );
+ $is_winIE = ! $is_chrome;
+ } else {
+ $is_chrome = true;
+ }
+ } elseif ( stripos($_SERVER['HTTP_USER_AGENT'], 'safari') !== false ) {
+ $is_safari = true;
+ } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false ) {
+ $is_gecko = true;
+ } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false && strpos($_SERVER['HTTP_USER_AGENT'], 'Win') !== false ) {
+ $is_winIE = true;
+ } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false && strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') !== false ) {
+ $is_macIE = true;
+ } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false ) {
+ $is_opera = true;
+ } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'Nav') !== false && strpos($_SERVER['HTTP_USER_AGENT'], 'Mozilla/4.') !== false ) {
+ $is_NS4 = true;
+ }
+}
+
+if ( $is_safari && stripos($_SERVER['HTTP_USER_AGENT'], 'mobile') !== false )
+ $is_iphone = true;
+
+$is_IE = ( $is_macIE || $is_winIE );
+
+// Server detection
+
+/**
+ * Whether the server software is Apache or something else
+ * @global bool $is_apache
+ */
+$is_apache = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false);
+
+/**
+ * Whether the server software is IIS or something else
+ * @global bool $is_IIS
+ */
+$is_IIS = !$is_apache && (strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false || strpos($_SERVER['SERVER_SOFTWARE'], 'ExpressionDevServer') !== false);
+
+/**
+ * Whether the server software is IIS 7.X or greater
+ * @global bool $is_iis7
+ */
+$is_iis7 = $is_IIS && intval( substr( $_SERVER['SERVER_SOFTWARE'], strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/' ) + 14 ) ) >= 7;
+
+/**
+ * Test if the current browser runs on a mobile device (smart phone, tablet, etc.)
+ *
+ * @return bool true|false
+ */
+function wp_is_mobile() {
+ static $is_mobile;
+
+ if ( isset($is_mobile) )
+ return $is_mobile;
+
+ if ( empty($_SERVER['HTTP_USER_AGENT']) ) {
+ $is_mobile = false;
+ } elseif ( strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false // many mobile devices (all iPhone, iPad, etc.)
+ || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false
+ || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false
+ || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false
+ || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false
+ || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false
+ || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) {
+ $is_mobile = true;
+ } else {
+ $is_mobile = false;
+ }
+
+ return $is_mobile;
+}
diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php
new file mode 100644
index 0000000000..7ea94663c9
--- /dev/null
+++ b/src/wp-includes/version.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * The WordPress version string
+ *
+ * @global string $wp_version
+ */
+$wp_version = '3.7-alpha-25000';
+
+/**
+ * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
+ *
+ * @global int $wp_db_version
+ */
+$wp_db_version = 24448;
+
+/**
+ * Holds the TinyMCE version
+ *
+ * @global string $tinymce_version
+ */
+$tinymce_version = '358-24485';
+
+/**
+ * Holds the required PHP version
+ *
+ * @global string $required_php_version
+ */
+$required_php_version = '5.2.4';
+
+/**
+ * Holds the required MySQL version
+ *
+ * @global string $required_mysql_version
+ */
+$required_mysql_version = '5.0';
diff --git a/src/wp-includes/widgets.php b/src/wp-includes/widgets.php
new file mode 100644
index 0000000000..233360f642
--- /dev/null
+++ b/src/wp-includes/widgets.php
@@ -0,0 +1,1263 @@
+<?php
+/**
+ * API for creating dynamic sidebar without hardcoding functionality into
+ * themes. Includes both internal WordPress routines and theme use routines.
+ *
+ * This functionality was found in a plugin before WordPress 2.2 release which
+ * included it in the core from that point on.
+ *
+ * @link http://codex.wordpress.org/Plugins/WordPress_Widgets WordPress Widgets
+ * @link http://codex.wordpress.org/Plugins/WordPress_Widgets_Api Widgets API
+ *
+ * @package WordPress
+ * @subpackage Widgets
+ */
+
+/**
+ * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
+ * and WP_Widget::form() need to be over-ridden.
+ *
+ * @package WordPress
+ * @subpackage Widgets
+ * @since 2.8
+ */
+class WP_Widget {
+
+ var $id_base; // Root id for all widgets of this type.
+ var $name; // Name for this widget type.
+ var $widget_options; // Option array passed to wp_register_sidebar_widget()
+ var $control_options; // Option array passed to wp_register_widget_control()
+
+ var $number = false; // Unique ID number of the current instance.
+ var $id = false; // Unique ID string of the current instance (id_base-number)
+ var $updated = false; // Set true when we update the data after a POST submit - makes sure we don't do it twice.
+
+ // Member functions that you must over-ride.
+
+ /** Echo the widget content.
+ *
+ * Subclasses should over-ride this function to generate their widget code.
+ *
+ * @param array $args Display arguments including before_title, after_title, before_widget, and after_widget.
+ * @param array $instance The settings for the particular instance of the widget
+ */
+ function widget($args, $instance) {
+ die('function WP_Widget::widget() must be over-ridden in a sub-class.');
+ }
+
+ /** Update a particular instance.
+ *
+ * This function should check that $new_instance is set correctly.
+ * The newly calculated value of $instance should be returned.
+ * If "false" is returned, the instance won't be saved/updated.
+ *
+ * @param array $new_instance New settings for this instance as input by the user via form()
+ * @param array $old_instance Old settings for this instance
+ * @return array Settings to save or bool false to cancel saving
+ */
+ function update($new_instance, $old_instance) {
+ return $new_instance;
+ }
+
+ /** Echo the settings update form
+ *
+ * @param array $instance Current settings
+ */
+ function form($instance) {
+ echo '<p class="no-options-widget">' . __('There are no options for this widget.') . '</p>';
+ return 'noform';
+ }
+
+ // Functions you'll need to call.
+
+ /**
+ * PHP5 constructor
+ *
+ * @param string $id_base Optional Base ID for the widget, lower case,
+ * if left empty a portion of the widget's class name will be used. Has to be unique.
+ * @param string $name Name for the widget displayed on the configuration page.
+ * @param array $widget_options Optional Passed to wp_register_sidebar_widget()
+ * - description: shown on the configuration page
+ * - classname
+ * @param array $control_options Optional Passed to wp_register_widget_control()
+ * - width: required if more than 250px
+ * - height: currently not used but may be needed in the future
+ */
+ function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) {
+ $this->id_base = empty($id_base) ? preg_replace( '/(wp_)?widget_/', '', strtolower(get_class($this)) ) : strtolower($id_base);
+ $this->name = $name;
+ $this->option_name = 'widget_' . $this->id_base;
+ $this->widget_options = wp_parse_args( $widget_options, array('classname' => $this->option_name) );
+ $this->control_options = wp_parse_args( $control_options, array('id_base' => $this->id_base) );
+ }
+
+ /**
+ * PHP4 constructor
+ */
+ function WP_Widget( $id_base, $name, $widget_options = array(), $control_options = array() ) {
+ WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );
+ }
+
+ /**
+ * Constructs name attributes for use in form() fields
+ *
+ * This function should be used in form() methods to create name attributes for fields to be saved by update()
+ *
+ * @param string $field_name Field name
+ * @return string Name attribute for $field_name
+ */
+ function get_field_name($field_name) {
+ return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';
+ }
+
+ /**
+ * Constructs id attributes for use in form() fields
+ *
+ * This function should be used in form() methods to create id attributes for fields to be saved by update()
+ *
+ * @param string $field_name Field name
+ * @return string ID attribute for $field_name
+ */
+ function get_field_id($field_name) {
+ return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name;
+ }
+
+ // Private Functions. Don't worry about these.
+
+ function _register() {
+ $settings = $this->get_settings();
+ $empty = true;
+
+ if ( is_array($settings) ) {
+ foreach ( array_keys($settings) as $number ) {
+ if ( is_numeric($number) ) {
+ $this->_set($number);
+ $this->_register_one($number);
+ $empty = false;
+ }
+ }
+ }
+
+ if ( $empty ) {
+ // If there are none, we register the widget's existence with a
+ // generic template
+ $this->_set(1);
+ $this->_register_one();
+ }
+ }
+
+ function _set($number) {
+ $this->number = $number;
+ $this->id = $this->id_base . '-' . $number;
+ }
+
+ function _get_display_callback() {
+ return array($this, 'display_callback');
+ }
+
+ function _get_update_callback() {
+ return array($this, 'update_callback');
+ }
+
+ function _get_form_callback() {
+ return array($this, 'form_callback');
+ }
+
+ /** Generate the actual widget content.
+ * Just finds the instance and calls widget().
+ * Do NOT over-ride this function. */
+ function display_callback( $args, $widget_args = 1 ) {
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ $this->_set( $widget_args['number'] );
+ $instance = $this->get_settings();
+
+ if ( array_key_exists( $this->number, $instance ) ) {
+ $instance = $instance[$this->number];
+ // filters the widget's settings, return false to stop displaying the widget
+ $instance = apply_filters('widget_display_callback', $instance, $this, $args);
+ if ( false !== $instance )
+ $this->widget($args, $instance);
+ }
+ }
+
+ /** Deal with changed settings.
+ * Do NOT over-ride this function. */
+ function update_callback( $widget_args = 1 ) {
+ global $wp_registered_widgets;
+
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ $all_instances = $this->get_settings();
+
+ // We need to update the data
+ if ( $this->updated )
+ return;
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+
+ if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
+ // Delete the settings for this instance of the widget
+ if ( isset($_POST['the-widget-id']) )
+ $del_id = $_POST['the-widget-id'];
+ else
+ return;
+
+ if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {
+ $number = $wp_registered_widgets[$del_id]['params'][0]['number'];
+
+ if ( $this->id_base . '-' . $number == $del_id )
+ unset($all_instances[$number]);
+ }
+ } else {
+ if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {
+ $settings = $_POST['widget-' . $this->id_base];
+ } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {
+ $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];
+ $settings = array( $num => array() );
+ } else {
+ return;
+ }
+
+ foreach ( $settings as $number => $new_instance ) {
+ $new_instance = stripslashes_deep($new_instance);
+ $this->_set($number);
+
+ $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();
+
+ $instance = $this->update($new_instance, $old_instance);
+
+ // filters the widget's settings before saving, return false to cancel saving (keep the old settings if updating)
+ $instance = apply_filters('widget_update_callback', $instance, $new_instance, $old_instance, $this);
+ if ( false !== $instance )
+ $all_instances[$number] = $instance;
+
+ break; // run only once
+ }
+ }
+
+ $this->save_settings($all_instances);
+ $this->updated = true;
+ }
+
+ /** Generate the control form.
+ * Do NOT over-ride this function. */
+ function form_callback( $widget_args = 1 ) {
+ if ( is_numeric($widget_args) )
+ $widget_args = array( 'number' => $widget_args );
+
+ $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
+ $all_instances = $this->get_settings();
+
+ if ( -1 == $widget_args['number'] ) {
+ // We echo out a form where 'number' can be set later
+ $this->_set('__i__');
+ $instance = array();
+ } else {
+ $this->_set($widget_args['number']);
+ $instance = $all_instances[ $widget_args['number'] ];
+ }
+
+ // filters the widget admin form before displaying, return false to stop displaying it
+ $instance = apply_filters('widget_form_callback', $instance, $this);
+
+ $return = null;
+ if ( false !== $instance ) {
+ $return = $this->form($instance);
+ // add extra fields in the widget form - be sure to set $return to null if you add any
+ // if the widget has no form the text echoed from the default form method can be hidden using css
+ do_action_ref_array( 'in_widget_form', array(&$this, &$return, $instance) );
+ }
+ return $return;
+ }
+
+ /** Helper function: Registers a single instance. */
+ function _register_one($number = -1) {
+ wp_register_sidebar_widget( $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );
+ _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );
+ _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );
+ }
+
+ function save_settings($settings) {
+ $settings['_multiwidget'] = 1;
+ update_option( $this->option_name, $settings );
+ }
+
+ function get_settings() {
+ $settings = get_option($this->option_name);
+
+ if ( false === $settings && isset($this->alt_option_name) )
+ $settings = get_option($this->alt_option_name);
+
+ if ( !is_array($settings) )
+ $settings = array();
+
+ if ( !empty($settings) && !array_key_exists('_multiwidget', $settings) ) {
+ // old format, convert if single widget
+ $settings = wp_convert_widget_settings($this->id_base, $this->option_name, $settings);
+ }
+
+ unset($settings['_multiwidget'], $settings['__i__']);
+ return $settings;
+ }
+}
+
+/**
+ * Singleton that registers and instantiates WP_Widget classes.
+ *
+ * @package WordPress
+ * @subpackage Widgets
+ * @since 2.8
+ */
+class WP_Widget_Factory {
+ var $widgets = array();
+
+ function WP_Widget_Factory() {
+ add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 );
+ }
+
+ function register($widget_class) {
+ $this->widgets[$widget_class] = new $widget_class();
+ }
+
+ function unregister($widget_class) {
+ if ( isset($this->widgets[$widget_class]) )
+ unset($this->widgets[$widget_class]);
+ }
+
+ function _register_widgets() {
+ global $wp_registered_widgets;
+ $keys = array_keys($this->widgets);
+ $registered = array_keys($wp_registered_widgets);
+ $registered = array_map('_get_widget_id_base', $registered);
+
+ foreach ( $keys as $key ) {
+ // don't register new widget if old widget with the same id is already registered
+ if ( in_array($this->widgets[$key]->id_base, $registered, true) ) {
+ unset($this->widgets[$key]);
+ continue;
+ }
+
+ $this->widgets[$key]->_register();
+ }
+ }
+}
+
+/* Global Variables */
+
+/** @ignore */
+global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
+
+/**
+ * Stores the sidebars, since many themes can have more than one.
+ *
+ * @global array $wp_registered_sidebars
+ * @since 2.2.0
+ */
+$wp_registered_sidebars = array();
+
+/**
+ * Stores the registered widgets.
+ *
+ * @global array $wp_registered_widgets
+ * @since 2.2.0
+ */
+$wp_registered_widgets = array();
+
+/**
+ * Stores the registered widget control (options).
+ *
+ * @global array $wp_registered_widget_controls
+ * @since 2.2.0
+ */
+$wp_registered_widget_controls = array();
+$wp_registered_widget_updates = array();
+
+/**
+ * Private
+ */
+$_wp_sidebars_widgets = array();
+
+/**
+ * Private
+ */
+ $GLOBALS['_wp_deprecated_widgets_callbacks'] = array(
+ 'wp_widget_pages',
+ 'wp_widget_pages_control',
+ 'wp_widget_calendar',
+ 'wp_widget_calendar_control',
+ 'wp_widget_archives',
+ 'wp_widget_archives_control',
+ 'wp_widget_links',
+ 'wp_widget_meta',
+ 'wp_widget_meta_control',
+ 'wp_widget_search',
+ 'wp_widget_recent_entries',
+ 'wp_widget_recent_entries_control',
+ 'wp_widget_tag_cloud',
+ 'wp_widget_tag_cloud_control',
+ 'wp_widget_categories',
+ 'wp_widget_categories_control',
+ 'wp_widget_text',
+ 'wp_widget_text_control',
+ 'wp_widget_rss',
+ 'wp_widget_rss_control',
+ 'wp_widget_recent_comments',
+ 'wp_widget_recent_comments_control'
+ );
+
+/* Template tags & API functions */
+
+/**
+ * Register a widget
+ *
+ * Registers a WP_Widget widget
+ *
+ * @since 2.8.0
+ *
+ * @see WP_Widget
+ * @see WP_Widget_Factory
+ * @uses WP_Widget_Factory
+ *
+ * @param string $widget_class The name of a class that extends WP_Widget
+ */
+function register_widget($widget_class) {
+ global $wp_widget_factory;
+
+ $wp_widget_factory->register($widget_class);
+}
+
+/**
+ * Unregister a widget
+ *
+ * Unregisters a WP_Widget widget. Useful for unregistering default widgets.
+ * Run within a function hooked to the widgets_init action.
+ *
+ * @since 2.8.0
+ *
+ * @see WP_Widget
+ * @see WP_Widget_Factory
+ * @uses WP_Widget_Factory
+ *
+ * @param string $widget_class The name of a class that extends WP_Widget
+ */
+function unregister_widget($widget_class) {
+ global $wp_widget_factory;
+
+ $wp_widget_factory->unregister($widget_class);
+}
+
+/**
+ * Creates multiple sidebars.
+ *
+ * If you wanted to quickly create multiple sidebars for a theme or internally.
+ * This function will allow you to do so. If you don't pass the 'name' and/or
+ * 'id' in $args, then they will be built for you.
+ *
+ * The default for the name is "Sidebar #", with '#' being replaced with the
+ * number the sidebar is currently when greater than one. If first sidebar, the
+ * name will be just "Sidebar". The default for id is "sidebar-" followed by the
+ * number the sidebar creation is currently at. If the id is provided, and multiple
+ * sidebars are being defined, the id will have "-2" appended, and so on.
+ *
+ * @since 2.2.0
+ *
+ * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here.
+ * @uses parse_str() Converts a string to an array to be used in the rest of the function.
+ * @uses register_sidebar() Sends single sidebar information [name, id] to this
+ * function to handle building the sidebar.
+ *
+ * @param int $number Number of sidebars to create.
+ * @param string|array $args Builds Sidebar based off of 'name' and 'id' values.
+ */
+function register_sidebars($number = 1, $args = array()) {
+ global $wp_registered_sidebars;
+ $number = (int) $number;
+
+ if ( is_string($args) )
+ parse_str($args, $args);
+
+ for ( $i = 1; $i <= $number; $i++ ) {
+ $_args = $args;
+
+ if ( $number > 1 )
+ $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i);
+ else
+ $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar');
+
+ // Custom specified ID's are suffixed if they exist already.
+ // Automatically generated sidebar names need to be suffixed regardless starting at -0
+ if ( isset($args['id']) ) {
+ $_args['id'] = $args['id'];
+ $n = 2; // Start at -2 for conflicting custom ID's
+ while ( isset($wp_registered_sidebars[$_args['id']]) )
+ $_args['id'] = $args['id'] . '-' . $n++;
+ } else {
+ $n = count($wp_registered_sidebars);
+ do {
+ $_args['id'] = 'sidebar-' . ++$n;
+ } while ( isset($wp_registered_sidebars[$_args['id']]) );
+ }
+ register_sidebar($_args);
+ }
+}
+
+/**
+ * Builds the definition for a single sidebar and returns the ID.
+ *
+ * Accepts either a string or an array and then parses that against a set
+ * of default arguments for the new sidebar. WordPress will automatically
+ * generate a sidebar ID and name based on the current number of registered
+ * sidebars if those arguments are not included.
+ *
+ * When allowing for automatic generation of the name and ID parameters, keep
+ * in mind that the incrementor for your sidebar can change over time depending
+ * on what other plugins and themes are installed.
+ *
+ * If theme support for 'widgets' has not yet been added when this function is
+ * called, it will be automatically enabled through the use of add_theme_support()
+ *
+ * Arguments passed as a string should be separated by '&':
+ *
+ * e.g. 'name=Sidebar&id=my_prefix_sidebar'
+ *
+ * The same arguments passed as an array:
+ *
+ * array(
+ * 'name' => 'Sidebar',
+ * 'id' => 'my_prefix_sidebar',
+ * )
+ *
+ * Arguments:
+ * name - The name or title of the sidebar displayed in the admin dashboard.
+ * id - The unique identifier by which the sidebar will be called.
+ * before_widget - HTML content that will be prepended to each widget's HTML output
+ * when assigned to this sidebar.
+ * after_widget - HTML content that will be appended to each widget's HTML output
+ * when assigned to this sidebar.
+ * before_title - HTML content that will be prepended to the sidebar title when displayed.
+ * after_title - HTML content that will be appended to the sidebar title when displayed.
+ *
+ * @since 2.2.0
+ * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
+ * @uses add_theme_support() to ensure widget support has been added.
+ *
+ * @param string|array $args Arguments for the sidebar being registered.
+ * @return string Sidebar ID added to $wp_registered_sidebars global.
+ */
+function register_sidebar($args = array()) {
+ global $wp_registered_sidebars;
+
+ $i = count($wp_registered_sidebars) + 1;
+
+ $defaults = array(
+ 'name' => sprintf(__('Sidebar %d'), $i ),
+ 'id' => "sidebar-$i",
+ 'description' => '',
+ 'class' => '',
+ 'before_widget' => '<li id="%1$s" class="widget %2$s">',
+ 'after_widget' => "</li>\n",
+ 'before_title' => '<h2 class="widgettitle">',
+ 'after_title' => "</h2>\n",
+ );
+
+ $sidebar = wp_parse_args( $args, $defaults );
+
+ $wp_registered_sidebars[$sidebar['id']] = $sidebar;
+
+ add_theme_support('widgets');
+
+ do_action( 'register_sidebar', $sidebar );
+
+ return $sidebar['id'];
+}
+
+/**
+ * Removes a sidebar from the list.
+ *
+ * @since 2.2.0
+ *
+ * @uses $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID.
+ *
+ * @param string $name The ID of the sidebar when it was added.
+ */
+function unregister_sidebar( $name ) {
+ global $wp_registered_sidebars;
+
+ if ( isset( $wp_registered_sidebars[$name] ) )
+ unset( $wp_registered_sidebars[$name] );
+}
+
+/**
+ * Register widget for use in sidebars.
+ *
+ * The default widget option is 'classname' that can be override.
+ *
+ * The function can also be used to unregister widgets when $output_callback
+ * parameter is an empty string.
+ *
+ * @since 2.2.0
+ *
+ * @uses $wp_registered_widgets Uses stored registered widgets.
+ * @uses $wp_register_widget_defaults Retrieves widget defaults.
+ *
+ * @param int|string $id Widget ID.
+ * @param string $name Widget display title.
+ * @param callback $output_callback Run when widget is called.
+ * @param array|string $options Optional. Widget Options.
+ * @param mixed $params,... Widget parameters to add to widget.
+ * @return null Will return if $output_callback is empty after removing widget.
+ */
+function wp_register_sidebar_widget($id, $name, $output_callback, $options = array()) {
+ global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates, $_wp_deprecated_widgets_callbacks;
+
+ $id = strtolower($id);
+
+ if ( empty($output_callback) ) {
+ unset($wp_registered_widgets[$id]);
+ return;
+ }
+
+ $id_base = _get_widget_id_base($id);
+ if ( in_array($output_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($output_callback) ) {
+ if ( isset($wp_registered_widget_controls[$id]) )
+ unset($wp_registered_widget_controls[$id]);
+
+ if ( isset($wp_registered_widget_updates[$id_base]) )
+ unset($wp_registered_widget_updates[$id_base]);
+
+ return;
+ }
+
+ $defaults = array('classname' => $output_callback);
+ $options = wp_parse_args($options, $defaults);
+ $widget = array(
+ 'name' => $name,
+ 'id' => $id,
+ 'callback' => $output_callback,
+ 'params' => array_slice(func_get_args(), 4)
+ );
+ $widget = array_merge($widget, $options);
+
+ if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) {
+ do_action( 'wp_register_sidebar_widget', $widget );
+ $wp_registered_widgets[$id] = $widget;
+ }
+}
+
+/**
+ * Retrieve description for widget.
+ *
+ * When registering widgets, the options can also include 'description' that
+ * describes the widget for display on the widget administration panel or
+ * in the theme.
+ *
+ * @since 2.5.0
+ *
+ * @param int|string $id Widget ID.
+ * @return string Widget description, if available. Null on failure to retrieve description.
+ */
+function wp_widget_description( $id ) {
+ if ( !is_scalar($id) )
+ return;
+
+ global $wp_registered_widgets;
+
+ if ( isset($wp_registered_widgets[$id]['description']) )
+ return esc_html( $wp_registered_widgets[$id]['description'] );
+}
+
+/**
+ * Retrieve description for a sidebar.
+ *
+ * When registering sidebars a 'description' parameter can be included that
+ * describes the sidebar for display on the widget administration panel.
+ *
+ * @since 2.9.0
+ *
+ * @param int|string $id sidebar ID.
+ * @return string Sidebar description, if available. Null on failure to retrieve description.
+ */
+function wp_sidebar_description( $id ) {
+ if ( !is_scalar($id) )
+ return;
+
+ global $wp_registered_sidebars;
+
+ if ( isset($wp_registered_sidebars[$id]['description']) )
+ return esc_html( $wp_registered_sidebars[$id]['description'] );
+}
+
+/**
+ * Remove widget from sidebar.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Widget ID.
+ */
+function wp_unregister_sidebar_widget($id) {
+ do_action( 'wp_unregister_sidebar_widget', $id );
+
+ wp_register_sidebar_widget($id, '', '');
+ wp_unregister_widget_control($id);
+}
+
+/**
+ * Registers widget control callback for customizing options.
+ *
+ * The options contains the 'height', 'width', and 'id_base' keys. The 'height'
+ * option is never used. The 'width' option is the width of the fully expanded
+ * control form, but try hard to use the default width. The 'id_base' is for
+ * multi-widgets (widgets which allow multiple instances such as the text
+ * widget), an id_base must be provided. The widget id will end up looking like
+ * {$id_base}-{$unique_number}.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $id Sidebar ID.
+ * @param string $name Sidebar display name.
+ * @param callback $control_callback Run when sidebar is displayed.
+ * @param array|string $options Optional. Widget options. See above long description.
+ * @param mixed $params,... Optional. Additional parameters to add to widget.
+ */
+function wp_register_widget_control($id, $name, $control_callback, $options = array()) {
+ global $wp_registered_widget_controls, $wp_registered_widget_updates, $wp_registered_widgets, $_wp_deprecated_widgets_callbacks;
+
+ $id = strtolower($id);
+ $id_base = _get_widget_id_base($id);
+
+ if ( empty($control_callback) ) {
+ unset($wp_registered_widget_controls[$id]);
+ unset($wp_registered_widget_updates[$id_base]);
+ return;
+ }
+
+ if ( in_array($control_callback, $_wp_deprecated_widgets_callbacks, true) && !is_callable($control_callback) ) {
+ if ( isset($wp_registered_widgets[$id]) )
+ unset($wp_registered_widgets[$id]);
+
+ return;
+ }
+
+ if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
+ return;
+
+ $defaults = array('width' => 250, 'height' => 200 ); // height is never used
+ $options = wp_parse_args($options, $defaults);
+ $options['width'] = (int) $options['width'];
+ $options['height'] = (int) $options['height'];
+
+ $widget = array(
+ 'name' => $name,
+ 'id' => $id,
+ 'callback' => $control_callback,
+ 'params' => array_slice(func_get_args(), 4)
+ );
+ $widget = array_merge($widget, $options);
+
+ $wp_registered_widget_controls[$id] = $widget;
+
+ if ( isset($wp_registered_widget_updates[$id_base]) )
+ return;
+
+ if ( isset($widget['params'][0]['number']) )
+ $widget['params'][0]['number'] = -1;
+
+ unset($widget['width'], $widget['height'], $widget['name'], $widget['id']);
+ $wp_registered_widget_updates[$id_base] = $widget;
+}
+
+function _register_widget_update_callback($id_base, $update_callback, $options = array()) {
+ global $wp_registered_widget_updates;
+
+ if ( isset($wp_registered_widget_updates[$id_base]) ) {
+ if ( empty($update_callback) )
+ unset($wp_registered_widget_updates[$id_base]);
+ return;
+ }
+
+ $widget = array(
+ 'callback' => $update_callback,
+ 'params' => array_slice(func_get_args(), 3)
+ );
+
+ $widget = array_merge($widget, $options);
+ $wp_registered_widget_updates[$id_base] = $widget;
+}
+
+function _register_widget_form_callback($id, $name, $form_callback, $options = array()) {
+ global $wp_registered_widget_controls;
+
+ $id = strtolower($id);
+
+ if ( empty($form_callback) ) {
+ unset($wp_registered_widget_controls[$id]);
+ return;
+ }
+
+ if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) )
+ return;
+
+ $defaults = array('width' => 250, 'height' => 200 );
+ $options = wp_parse_args($options, $defaults);
+ $options['width'] = (int) $options['width'];
+ $options['height'] = (int) $options['height'];
+
+ $widget = array(
+ 'name' => $name,
+ 'id' => $id,
+ 'callback' => $form_callback,
+ 'params' => array_slice(func_get_args(), 4)
+ );
+ $widget = array_merge($widget, $options);
+
+ $wp_registered_widget_controls[$id] = $widget;
+}
+
+/**
+ * Remove control callback for widget.
+ *
+ * @since 2.2.0
+ * @uses wp_register_widget_control() Unregisters by using empty callback.
+ *
+ * @param int|string $id Widget ID.
+ */
+function wp_unregister_widget_control($id) {
+ return wp_register_widget_control($id, '', '');
+}
+
+/**
+ * Display dynamic sidebar.
+ *
+ * By default this displays the default sidebar or 'sidebar-1'. If your theme specifies the 'id' or
+ * 'name' parameter for its registered sidebars you can pass an id or name as the $index parameter.
+ * Otherwise, you can pass in a numerical index to display the sidebar at that index.
+ *
+ * @since 2.2.0
+ *
+ * @param int|string $index Optional, default is 1. Index, name or ID of dynamic sidebar.
+ * @return bool True, if widget sidebar was found and called. False if not found or not called.
+ */
+function dynamic_sidebar($index = 1) {
+ global $wp_registered_sidebars, $wp_registered_widgets;
+
+ if ( is_int($index) ) {
+ $index = "sidebar-$index";
+ } else {
+ $index = sanitize_title($index);
+ foreach ( (array) $wp_registered_sidebars as $key => $value ) {
+ if ( sanitize_title($value['name']) == $index ) {
+ $index = $key;
+ break;
+ }
+ }
+ }
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ if ( empty( $sidebars_widgets ) )
+ return false;
+
+ if ( empty($wp_registered_sidebars[$index]) || !array_key_exists($index, $sidebars_widgets) || !is_array($sidebars_widgets[$index]) || empty($sidebars_widgets[$index]) )
+ return false;
+
+ $sidebar = $wp_registered_sidebars[$index];
+
+ $did_one = false;
+ foreach ( (array) $sidebars_widgets[$index] as $id ) {
+
+ if ( !isset($wp_registered_widgets[$id]) ) continue;
+
+ $params = array_merge(
+ array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
+ (array) $wp_registered_widgets[$id]['params']
+ );
+
+ // Substitute HTML id and class attributes into before_widget
+ $classname_ = '';
+ foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
+ if ( is_string($cn) )
+ $classname_ .= '_' . $cn;
+ elseif ( is_object($cn) )
+ $classname_ .= '_' . get_class($cn);
+ }
+ $classname_ = ltrim($classname_, '_');
+ $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
+
+ $params = apply_filters( 'dynamic_sidebar_params', $params );
+
+ $callback = $wp_registered_widgets[$id]['callback'];
+
+ do_action( 'dynamic_sidebar', $wp_registered_widgets[$id] );
+
+ if ( is_callable($callback) ) {
+ call_user_func_array($callback, $params);
+ $did_one = true;
+ }
+ }
+
+ return $did_one;
+}
+
+/**
+ * Whether widget is displayed on the front-end.
+ *
+ * Either $callback or $id_base can be used
+ * $id_base is the first argument when extending WP_Widget class
+ * Without the optional $widget_id parameter, returns the ID of the first sidebar
+ * in which the first instance of the widget with the given callback or $id_base is found.
+ * With the $widget_id parameter, returns the ID of the sidebar where
+ * the widget with that callback/$id_base AND that ID is found.
+ *
+ * NOTE: $widget_id and $id_base are the same for single widgets. To be effective
+ * this function has to run after widgets have initialized, at action 'init' or later.
+ *
+ * @since 2.2.0
+ *
+ * @param string $callback Optional, Widget callback to check.
+ * @param int $widget_id Optional, but needed for checking. Widget ID.
+ * @param string $id_base Optional, the base ID of a widget created by extending WP_Widget.
+ * @param bool $skip_inactive Optional, whether to check in 'wp_inactive_widgets'.
+ * @return mixed false if widget is not active or id of sidebar in which the widget is active.
+ */
+function is_active_widget($callback = false, $widget_id = false, $id_base = false, $skip_inactive = true) {
+ global $wp_registered_widgets;
+
+ $sidebars_widgets = wp_get_sidebars_widgets();
+
+ if ( is_array($sidebars_widgets) ) {
+ foreach ( $sidebars_widgets as $sidebar => $widgets ) {
+ if ( $skip_inactive && 'wp_inactive_widgets' == $sidebar )
+ continue;
+
+ if ( is_array($widgets) ) {
+ foreach ( $widgets as $widget ) {
+ if ( ( $callback && isset($wp_registered_widgets[$widget]['callback']) && $wp_registered_widgets[$widget]['callback'] == $callback ) || ( $id_base && _get_widget_id_base($widget) == $id_base ) ) {
+ if ( !$widget_id || $widget_id == $wp_registered_widgets[$widget]['id'] )
+ return $sidebar;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Whether the dynamic sidebar is enabled and used by theme.
+ *
+ * @since 2.2.0
+ *
+ * @return bool True, if using widgets. False, if not using widgets.
+ */
+function is_dynamic_sidebar() {
+ global $wp_registered_widgets, $wp_registered_sidebars;
+ $sidebars_widgets = get_option('sidebars_widgets');
+ foreach ( (array) $wp_registered_sidebars as $index => $sidebar ) {
+ if ( count($sidebars_widgets[$index]) ) {
+ foreach ( (array) $sidebars_widgets[$index] as $widget )
+ if ( array_key_exists($widget, $wp_registered_widgets) )
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Whether a sidebar is in use.
+ *
+ * @since 2.8
+ *
+ * @param mixed $index Sidebar name, id or number to check.
+ * @return bool true if the sidebar is in use, false otherwise.
+ */
+function is_active_sidebar( $index ) {
+ $index = ( is_int($index) ) ? "sidebar-$index" : sanitize_title($index);
+ $sidebars_widgets = wp_get_sidebars_widgets();
+ if ( !empty($sidebars_widgets[$index]) )
+ return true;
+
+ return false;
+}
+
+/* Internal Functions */
+
+/**
+ * Retrieve full list of sidebars and their widgets.
+ *
+ * Will upgrade sidebar widget list, if needed. Will also save updated list, if
+ * needed.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @param bool $deprecated Not used (deprecated).
+ * @return array Upgraded list of widgets to version 3 array format when called from the admin.
+ */
+function wp_get_sidebars_widgets($deprecated = true) {
+ if ( $deprecated !== true )
+ _deprecated_argument( __FUNCTION__, '2.8.1' );
+
+ global $_wp_sidebars_widgets, $sidebars_widgets;
+
+ // If loading from front page, consult $_wp_sidebars_widgets rather than options
+ // to see if wp_convert_widget_settings() has made manipulations in memory.
+ if ( !is_admin() ) {
+ if ( empty($_wp_sidebars_widgets) )
+ $_wp_sidebars_widgets = get_option('sidebars_widgets', array());
+
+ $sidebars_widgets = $_wp_sidebars_widgets;
+ } else {
+ $sidebars_widgets = get_option('sidebars_widgets', array());
+ }
+
+ if ( is_array( $sidebars_widgets ) && isset($sidebars_widgets['array_version']) )
+ unset($sidebars_widgets['array_version']);
+
+ $sidebars_widgets = apply_filters('sidebars_widgets', $sidebars_widgets);
+ return $sidebars_widgets;
+}
+
+/**
+ * Set the sidebar widget option to update sidebars.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @param array $sidebars_widgets Sidebar widgets and their settings.
+ */
+function wp_set_sidebars_widgets( $sidebars_widgets ) {
+ if ( !isset( $sidebars_widgets['array_version'] ) )
+ $sidebars_widgets['array_version'] = 3;
+ update_option( 'sidebars_widgets', $sidebars_widgets );
+}
+
+/**
+ * Retrieve default registered sidebars list.
+ *
+ * @since 2.2.0
+ * @access private
+ *
+ * @return array
+ */
+function wp_get_widget_defaults() {
+ global $wp_registered_sidebars;
+
+ $defaults = array();
+
+ foreach ( (array) $wp_registered_sidebars as $index => $sidebar )
+ $defaults[$index] = array();
+
+ return $defaults;
+}
+
+/**
+ * Convert the widget settings from single to multi-widget format.
+ *
+ * @since 2.8.0
+ *
+ * @return array
+ */
+function wp_convert_widget_settings($base_name, $option_name, $settings) {
+ // This test may need expanding.
+ $single = $changed = false;
+ if ( empty($settings) ) {
+ $single = true;
+ } else {
+ foreach ( array_keys($settings) as $number ) {
+ if ( 'number' == $number )
+ continue;
+ if ( !is_numeric($number) ) {
+ $single = true;
+ break;
+ }
+ }
+ }
+
+ if ( $single ) {
+ $settings = array( 2 => $settings );
+
+ // If loading from the front page, update sidebar in memory but don't save to options
+ if ( is_admin() ) {
+ $sidebars_widgets = get_option('sidebars_widgets');
+ } else {
+ if ( empty($GLOBALS['_wp_sidebars_widgets']) )
+ $GLOBALS['_wp_sidebars_widgets'] = get_option('sidebars_widgets', array());
+ $sidebars_widgets = &$GLOBALS['_wp_sidebars_widgets'];
+ }
+
+ foreach ( (array) $sidebars_widgets as $index => $sidebar ) {
+ if ( is_array($sidebar) ) {
+ foreach ( $sidebar as $i => $name ) {
+ if ( $base_name == $name ) {
+ $sidebars_widgets[$index][$i] = "$name-2";
+ $changed = true;
+ break 2;
+ }
+ }
+ }
+ }
+
+ if ( is_admin() && $changed )
+ update_option('sidebars_widgets', $sidebars_widgets);
+ }
+
+ $settings['_multiwidget'] = 1;
+ if ( is_admin() )
+ update_option( $option_name, $settings );
+
+ return $settings;
+}
+
+/**
+ * Output an arbitrary widget as a template tag
+ *
+ * @since 2.8
+ *
+ * @param string $widget the widget's PHP class name (see default-widgets.php)
+ * @param array $instance the widget's instance settings
+ * @param array $args the widget's sidebar args
+ * @return void
+ **/
+function the_widget($widget, $instance = array(), $args = array()) {
+ global $wp_widget_factory;
+
+ $widget_obj = $wp_widget_factory->widgets[$widget];
+ if ( !is_a($widget_obj, 'WP_Widget') )
+ return;
+
+ $before_widget = sprintf('<div class="widget %s">', $widget_obj->widget_options['classname'] );
+ $default_args = array( 'before_widget' => $before_widget, 'after_widget' => "</div>", 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>' );
+
+ $args = wp_parse_args($args, $default_args);
+ $instance = wp_parse_args($instance);
+
+ do_action( 'the_widget', $widget, $instance, $args );
+
+ $widget_obj->_set(-1);
+ $widget_obj->widget($args, $instance);
+}
+
+/**
+ * Private
+ */
+function _get_widget_id_base($id) {
+ return preg_replace( '/-[0-9]+$/', '', $id );
+}
+
+/**
+ * Handle sidebars config after theme change
+ *
+ * @access private
+ * @since 3.3.0
+ */
+function _wp_sidebars_changed() {
+ global $sidebars_widgets;
+
+ if ( ! is_array( $sidebars_widgets ) )
+ $sidebars_widgets = wp_get_sidebars_widgets();
+
+ retrieve_widgets(true);
+}
+
+// look for "lost" widgets, this has to run at least on each theme change
+function retrieve_widgets($theme_changed = false) {
+ global $wp_registered_sidebars, $sidebars_widgets, $wp_registered_widgets;
+
+ $registered_sidebar_keys = array_keys( $wp_registered_sidebars );
+ $orphaned = 0;
+
+ $old_sidebars_widgets = get_theme_mod( 'sidebars_widgets' );
+ if ( is_array( $old_sidebars_widgets ) ) {
+ // time() that sidebars were stored is in $old_sidebars_widgets['time']
+ $_sidebars_widgets = $old_sidebars_widgets['data'];
+ remove_theme_mod( 'sidebars_widgets' );
+
+ foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
+ if ( 'wp_inactive_widgets' == $sidebar || 'orphaned_widgets' == substr( $sidebar, 0, 16 ) )
+ continue;
+
+ if ( !in_array( $sidebar, $registered_sidebar_keys ) ) {
+ $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $widgets;
+ unset( $_sidebars_widgets[$sidebar] );
+ }
+ }
+ } else {
+ if ( empty( $sidebars_widgets ) )
+ return;
+
+ unset( $sidebars_widgets['array_version'] );
+
+ $old = array_keys($sidebars_widgets);
+ sort($old);
+ sort($registered_sidebar_keys);
+
+ if ( $old == $registered_sidebar_keys )
+ return;
+
+ $_sidebars_widgets = array(
+ 'wp_inactive_widgets' => !empty( $sidebars_widgets['wp_inactive_widgets'] ) ? $sidebars_widgets['wp_inactive_widgets'] : array()
+ );
+
+ unset( $sidebars_widgets['wp_inactive_widgets'] );
+
+ foreach ( $wp_registered_sidebars as $id => $settings ) {
+ if ( $theme_changed ) {
+ $_sidebars_widgets[$id] = array_shift( $sidebars_widgets );
+ } else {
+ // no theme change, grab only sidebars that are currently registered
+ if ( isset( $sidebars_widgets[$id] ) ) {
+ $_sidebars_widgets[$id] = $sidebars_widgets[$id];
+ unset( $sidebars_widgets[$id] );
+ }
+ }
+ }
+
+ foreach ( $sidebars_widgets as $val ) {
+ if ( is_array($val) && ! empty( $val ) )
+ $_sidebars_widgets['orphaned_widgets_' . ++$orphaned] = $val;
+ }
+ }
+
+ // discard invalid, theme-specific widgets from sidebars
+ $shown_widgets = array();
+
+ foreach ( $_sidebars_widgets as $sidebar => $widgets ) {
+ if ( !is_array($widgets) )
+ continue;
+
+ $_widgets = array();
+ foreach ( $widgets as $widget ) {
+ if ( isset($wp_registered_widgets[$widget]) )
+ $_widgets[] = $widget;
+ }
+
+ $_sidebars_widgets[$sidebar] = $_widgets;
+ $shown_widgets = array_merge($shown_widgets, $_widgets);
+ }
+
+ $sidebars_widgets = $_sidebars_widgets;
+ unset($_sidebars_widgets, $_widgets);
+
+ // find hidden/lost multi-widget instances
+ $lost_widgets = array();
+ foreach ( $wp_registered_widgets as $key => $val ) {
+ if ( in_array($key, $shown_widgets, true) )
+ continue;
+
+ $number = preg_replace('/.+?-([0-9]+)$/', '$1', $key);
+
+ if ( 2 > (int) $number )
+ continue;
+
+ $lost_widgets[] = $key;
+ }
+
+ $sidebars_widgets['wp_inactive_widgets'] = array_merge($lost_widgets, (array) $sidebars_widgets['wp_inactive_widgets']);
+ wp_set_sidebars_widgets($sidebars_widgets);
+
+ return $sidebars_widgets;
+}
diff --git a/src/wp-includes/wlwmanifest.xml b/src/wp-includes/wlwmanifest.xml
new file mode 100644
index 0000000000..98504ee407
--- /dev/null
+++ b/src/wp-includes/wlwmanifest.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8" ?>
+
+<manifest xmlns="http://schemas.microsoft.com/wlw/manifest/weblog">
+
+ <options>
+ <clientType>WordPress</clientType>
+ <supportsKeywords>Yes</supportsKeywords>
+ <supportsGetTags>Yes</supportsGetTags>
+ </options>
+
+ <weblog>
+ <serviceName>WordPress</serviceName>
+ <imageUrl>images/wlw/wp-icon.png</imageUrl>
+ <watermarkImageUrl>images/wlw/wp-watermark.png</watermarkImageUrl>
+ <homepageLinkText>View site</homepageLinkText>
+ <adminLinkText>Dashboard</adminLinkText>
+ <adminUrl>
+ <![CDATA[
+ {blog-postapi-url}/../wp-admin/
+ ]]>
+ </adminUrl>
+ <postEditingUrl>
+ <![CDATA[
+ {blog-postapi-url}/../wp-admin/post.php?action=edit&post={post-id}
+ ]]>
+ </postEditingUrl>
+ </weblog>
+
+ <buttons>
+ <button>
+ <id>0</id>
+ <text>Manage Comments</text>
+ <imageUrl>images/wlw/wp-comments.png</imageUrl>
+ <clickUrl>
+ <![CDATA[
+ {blog-postapi-url}/../wp-admin/edit-comments.php
+ ]]>
+ </clickUrl>
+ </button>
+
+ </buttons>
+
+</manifest>
diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php
new file mode 100644
index 0000000000..2398002e32
--- /dev/null
+++ b/src/wp-includes/wp-db.php
@@ -0,0 +1,1746 @@
+<?php
+/**
+ * WordPress DB Class
+ *
+ * Original code from {@link http://php.justinvincent.com Justin Vincent (justin@visunet.ie)}
+ *
+ * @package WordPress
+ * @subpackage Database
+ * @since 0.71
+ */
+
+/**
+ * @since 0.71
+ */
+define( 'EZSQL_VERSION', 'WP1.25' );
+
+/**
+ * @since 0.71
+ */
+define( 'OBJECT', 'OBJECT', true );
+
+/**
+ * @since 2.5.0
+ */
+define( 'OBJECT_K', 'OBJECT_K' );
+
+/**
+ * @since 0.71
+ */
+define( 'ARRAY_A', 'ARRAY_A' );
+
+/**
+ * @since 0.71
+ */
+define( 'ARRAY_N', 'ARRAY_N' );
+
+/**
+ * WordPress Database Access Abstraction Object
+ *
+ * It is possible to replace this class with your own
+ * by setting the $wpdb global variable in wp-content/db.php
+ * file to your class. The wpdb class will still be included,
+ * so you can extend it or simply use your own.
+ *
+ * @link http://codex.wordpress.org/Function_Reference/wpdb_Class
+ *
+ * @package WordPress
+ * @subpackage Database
+ * @since 0.71
+ */
+class wpdb {
+
+ /**
+ * Whether to show SQL/DB errors
+ *
+ * @since 0.71
+ * @access private
+ * @var bool
+ */
+ var $show_errors = false;
+
+ /**
+ * Whether to suppress errors during the DB bootstrapping.
+ *
+ * @access private
+ * @since 2.5.0
+ * @var bool
+ */
+ var $suppress_errors = false;
+
+ /**
+ * The last error during query.
+ *
+ * @since 2.5.0
+ * @var string
+ */
+ var $last_error = '';
+
+ /**
+ * Amount of queries made
+ *
+ * @since 1.2.0
+ * @access private
+ * @var int
+ */
+ var $num_queries = 0;
+
+ /**
+ * Count of rows returned by previous query
+ *
+ * @since 0.71
+ * @access private
+ * @var int
+ */
+ var $num_rows = 0;
+
+ /**
+ * Count of affected rows by previous query
+ *
+ * @since 0.71
+ * @access private
+ * @var int
+ */
+ var $rows_affected = 0;
+
+ /**
+ * The ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).
+ *
+ * @since 0.71
+ * @access public
+ * @var int
+ */
+ var $insert_id = 0;
+
+ /**
+ * Last query made
+ *
+ * @since 0.71
+ * @access private
+ * @var array
+ */
+ var $last_query;
+
+ /**
+ * Results of the last query made
+ *
+ * @since 0.71
+ * @access private
+ * @var array|null
+ */
+ var $last_result;
+
+ /**
+ * MySQL result, which is either a resource or boolean.
+ *
+ * @since 0.71
+ * @access protected
+ * @var mixed
+ */
+ protected $result;
+
+ /**
+ * Saved info on the table column
+ *
+ * @since 0.71
+ * @access protected
+ * @var array
+ */
+ protected $col_info;
+
+ /**
+ * Saved queries that were executed
+ *
+ * @since 1.5.0
+ * @access private
+ * @var array
+ */
+ var $queries;
+
+ /**
+ * WordPress table prefix
+ *
+ * You can set this to have multiple WordPress installations
+ * in a single database. The second reason is for possible
+ * security precautions.
+ *
+ * @since 2.5.0
+ * @access private
+ * @var string
+ */
+ var $prefix = '';
+
+ /**
+ * Whether the database queries are ready to start executing.
+ *
+ * @since 2.3.2
+ * @access private
+ * @var bool
+ */
+ var $ready = false;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 3.0.0
+ * @access public
+ * @var int
+ */
+ var $blogid = 0;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @since 3.0.0
+ * @access public
+ * @var int
+ */
+ var $siteid = 0;
+
+ /**
+ * List of WordPress per-blog tables
+ *
+ * @since 2.5.0
+ * @access private
+ * @see wpdb::tables()
+ * @var array
+ */
+ var $tables = array( 'posts', 'comments', 'links', 'options', 'postmeta',
+ 'terms', 'term_taxonomy', 'term_relationships', 'commentmeta' );
+
+ /**
+ * List of deprecated WordPress tables
+ *
+ * categories, post2cat, and link2cat were deprecated in 2.3.0, db version 5539
+ *
+ * @since 2.9.0
+ * @access private
+ * @see wpdb::tables()
+ * @var array
+ */
+ var $old_tables = array( 'categories', 'post2cat', 'link2cat' );
+
+ /**
+ * List of WordPress global tables
+ *
+ * @since 3.0.0
+ * @access private
+ * @see wpdb::tables()
+ * @var array
+ */
+ var $global_tables = array( 'users', 'usermeta' );
+
+ /**
+ * List of Multisite global tables
+ *
+ * @since 3.0.0
+ * @access private
+ * @see wpdb::tables()
+ * @var array
+ */
+ var $ms_global_tables = array( 'blogs', 'signups', 'site', 'sitemeta',
+ 'sitecategories', 'registration_log', 'blog_versions' );
+
+ /**
+ * WordPress Comments table
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $comments;
+
+ /**
+ * WordPress Comment Metadata table
+ *
+ * @since 2.9.0
+ * @access public
+ * @var string
+ */
+ var $commentmeta;
+
+ /**
+ * WordPress Links table
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $links;
+
+ /**
+ * WordPress Options table
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $options;
+
+ /**
+ * WordPress Post Metadata table
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $postmeta;
+
+ /**
+ * WordPress Posts table
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $posts;
+
+ /**
+ * WordPress Terms table
+ *
+ * @since 2.3.0
+ * @access public
+ * @var string
+ */
+ var $terms;
+
+ /**
+ * WordPress Term Relationships table
+ *
+ * @since 2.3.0
+ * @access public
+ * @var string
+ */
+ var $term_relationships;
+
+ /**
+ * WordPress Term Taxonomy table
+ *
+ * @since 2.3.0
+ * @access public
+ * @var string
+ */
+ var $term_taxonomy;
+
+ /*
+ * Global and Multisite tables
+ */
+
+ /**
+ * WordPress User Metadata table
+ *
+ * @since 2.3.0
+ * @access public
+ * @var string
+ */
+ var $usermeta;
+
+ /**
+ * WordPress Users table
+ *
+ * @since 1.5.0
+ * @access public
+ * @var string
+ */
+ var $users;
+
+ /**
+ * Multisite Blogs table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $blogs;
+
+ /**
+ * Multisite Blog Versions table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $blog_versions;
+
+ /**
+ * Multisite Registration Log table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $registration_log;
+
+ /**
+ * Multisite Signups table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $signups;
+
+ /**
+ * Multisite Sites table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $site;
+
+ /**
+ * Multisite Sitewide Terms table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $sitecategories;
+
+ /**
+ * Multisite Site Metadata table
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $sitemeta;
+
+ /**
+ * Format specifiers for DB columns. Columns not listed here default to %s. Initialized during WP load.
+ *
+ * Keys are column names, values are format types: 'ID' => '%d'
+ *
+ * @since 2.8.0
+ * @see wpdb::prepare()
+ * @see wpdb::insert()
+ * @see wpdb::update()
+ * @see wpdb::delete()
+ * @see wp_set_wpdb_vars()
+ * @access public
+ * @var array
+ */
+ var $field_types = array();
+
+ /**
+ * Database table columns charset
+ *
+ * @since 2.2.0
+ * @access public
+ * @var string
+ */
+ var $charset;
+
+ /**
+ * Database table columns collate
+ *
+ * @since 2.2.0
+ * @access public
+ * @var string
+ */
+ var $collate;
+
+ /**
+ * Database Username
+ *
+ * @since 2.9.0
+ * @access protected
+ * @var string
+ */
+ protected $dbuser;
+
+ /**
+ * Database Password
+ *
+ * @since 3.1.0
+ * @access protected
+ * @var string
+ */
+ protected $dbpassword;
+
+ /**
+ * Database Name
+ *
+ * @since 3.1.0
+ * @access protected
+ * @var string
+ */
+ protected $dbname;
+
+ /**
+ * Database Host
+ *
+ * @since 3.1.0
+ * @access protected
+ * @var string
+ */
+ protected $dbhost;
+
+ /**
+ * Database Handle
+ *
+ * @since 0.71
+ * @access protected
+ * @var string
+ */
+ protected $dbh;
+
+ /**
+ * A textual description of the last query/get_row/get_var call
+ *
+ * @since 3.0.0
+ * @access public
+ * @var string
+ */
+ var $func_call;
+
+ /**
+ * Whether MySQL is used as the database engine.
+ *
+ * Set in WPDB::db_connect() to true, by default. This is used when checking
+ * against the required MySQL version for WordPress. Normally, a replacement
+ * database drop-in (db.php) will skip these checks, but setting this to true
+ * will force the checks to occur.
+ *
+ * @since 3.3.0
+ * @access public
+ * @var bool
+ */
+ public $is_mysql = null;
+
+ /**
+ * Connects to the database server and selects a database
+ *
+ * PHP5 style constructor for compatibility with PHP5. Does
+ * the actual setting up of the class properties and connection
+ * to the database.
+ *
+ * @link http://core.trac.wordpress.org/ticket/3354
+ * @since 2.0.8
+ *
+ * @param string $dbuser MySQL database user
+ * @param string $dbpassword MySQL database password
+ * @param string $dbname MySQL database name
+ * @param string $dbhost MySQL database host
+ */
+ function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
+ register_shutdown_function( array( $this, '__destruct' ) );
+
+ if ( WP_DEBUG && WP_DEBUG_DISPLAY )
+ $this->show_errors();
+
+ $this->init_charset();
+
+ $this->dbuser = $dbuser;
+ $this->dbpassword = $dbpassword;
+ $this->dbname = $dbname;
+ $this->dbhost = $dbhost;
+
+ $this->db_connect();
+ }
+
+ /**
+ * PHP5 style destructor and will run when database object is destroyed.
+ *
+ * @see wpdb::__construct()
+ * @since 2.0.8
+ * @return bool true
+ */
+ function __destruct() {
+ return true;
+ }
+
+ /**
+ * PHP5 style magic getter, used to lazy-load expensive data.
+ *
+ * @since 3.5.0
+ *
+ * @param string $name The private member to get, and optionally process
+ * @return mixed The private member
+ */
+ function __get( $name ) {
+ if ( 'col_info' == $name )
+ $this->load_col_info();
+
+ return $this->$name;
+ }
+
+ /**
+ * Magic function, for backwards compatibility
+ *
+ * @since 3.5.0
+ *
+ * @param string $name The private member to set
+ * @param mixed $value The value to set
+ */
+ function __set( $name, $value ) {
+ $this->$name = $value;
+ }
+
+ /**
+ * Magic function, for backwards compatibility
+ *
+ * @since 3.5.0
+ *
+ * @param string $name The private member to check
+ *
+ * @return bool If the member is set or not
+ */
+ function __isset( $name ) {
+ return isset( $this->$name );
+ }
+
+ /**
+ * Magic function, for backwards compatibility
+ *
+ * @since 3.5.0
+ *
+ * @param string $name The private member to unset
+ */
+ function __unset( $name ) {
+ unset( $this->$name );
+ }
+
+ /**
+ * Set $this->charset and $this->collate
+ *
+ * @since 3.1.0
+ */
+ function init_charset() {
+ if ( function_exists('is_multisite') && is_multisite() ) {
+ $this->charset = 'utf8';
+ if ( defined( 'DB_COLLATE' ) && DB_COLLATE )
+ $this->collate = DB_COLLATE;
+ else
+ $this->collate = 'utf8_general_ci';
+ } elseif ( defined( 'DB_COLLATE' ) ) {
+ $this->collate = DB_COLLATE;
+ }
+
+ if ( defined( 'DB_CHARSET' ) )
+ $this->charset = DB_CHARSET;
+ }
+
+ /**
+ * Sets the connection's character set.
+ *
+ * @since 3.1.0
+ *
+ * @param resource $dbh The resource given by mysql_connect
+ * @param string $charset The character set (optional)
+ * @param string $collate The collation (optional)
+ */
+ function set_charset( $dbh, $charset = null, $collate = null ) {
+ if ( ! isset( $charset ) )
+ $charset = $this->charset;
+ if ( ! isset( $collate ) )
+ $collate = $this->collate;
+ if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) {
+ if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
+ mysql_set_charset( $charset, $dbh );
+ } else {
+ $query = $this->prepare( 'SET NAMES %s', $charset );
+ if ( ! empty( $collate ) )
+ $query .= $this->prepare( ' COLLATE %s', $collate );
+ mysql_query( $query, $dbh );
+ }
+ }
+ }
+
+ /**
+ * Sets the table prefix for the WordPress tables.
+ *
+ * @since 2.5.0
+ *
+ * @param string $prefix Alphanumeric name for the new prefix.
+ * @param bool $set_table_names Optional. Whether the table names, e.g. wpdb::$posts, should be updated or not.
+ * @return string|WP_Error Old prefix or WP_Error on error
+ */
+ function set_prefix( $prefix, $set_table_names = true ) {
+
+ if ( preg_match( '|[^a-z0-9_]|i', $prefix ) )
+ return new WP_Error('invalid_db_prefix', 'Invalid database prefix' );
+
+ $old_prefix = is_multisite() ? '' : $prefix;
+
+ if ( isset( $this->base_prefix ) )
+ $old_prefix = $this->base_prefix;
+
+ $this->base_prefix = $prefix;
+
+ if ( $set_table_names ) {
+ foreach ( $this->tables( 'global' ) as $table => $prefixed_table )
+ $this->$table = $prefixed_table;
+
+ if ( is_multisite() && empty( $this->blogid ) )
+ return $old_prefix;
+
+ $this->prefix = $this->get_blog_prefix();
+
+ foreach ( $this->tables( 'blog' ) as $table => $prefixed_table )
+ $this->$table = $prefixed_table;
+
+ foreach ( $this->tables( 'old' ) as $table => $prefixed_table )
+ $this->$table = $prefixed_table;
+ }
+ return $old_prefix;
+ }
+
+ /**
+ * Sets blog id.
+ *
+ * @since 3.0.0
+ * @access public
+ * @param int $blog_id
+ * @param int $site_id Optional.
+ * @return string previous blog id
+ */
+ function set_blog_id( $blog_id, $site_id = 0 ) {
+ if ( ! empty( $site_id ) )
+ $this->siteid = $site_id;
+
+ $old_blog_id = $this->blogid;
+ $this->blogid = $blog_id;
+
+ $this->prefix = $this->get_blog_prefix();
+
+ foreach ( $this->tables( 'blog' ) as $table => $prefixed_table )
+ $this->$table = $prefixed_table;
+
+ foreach ( $this->tables( 'old' ) as $table => $prefixed_table )
+ $this->$table = $prefixed_table;
+
+ return $old_blog_id;
+ }
+
+ /**
+ * Gets blog prefix.
+ *
+ * @uses is_multisite()
+ * @since 3.0.0
+ * @param int $blog_id Optional.
+ * @return string Blog prefix.
+ */
+ function get_blog_prefix( $blog_id = null ) {
+ if ( is_multisite() ) {
+ if ( null === $blog_id )
+ $blog_id = $this->blogid;
+ $blog_id = (int) $blog_id;
+ if ( defined( 'MULTISITE' ) && ( 0 == $blog_id || 1 == $blog_id ) )
+ return $this->base_prefix;
+ else
+ return $this->base_prefix . $blog_id . '_';
+ } else {
+ return $this->base_prefix;
+ }
+ }
+
+ /**
+ * Returns an array of WordPress tables.
+ *
+ * Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to
+ * override the WordPress users and usermeta tables that would otherwise
+ * be determined by the prefix.
+ *
+ * The scope argument can take one of the following:
+ *
+ * 'all' - returns 'all' and 'global' tables. No old tables are returned.
+ * 'blog' - returns the blog-level tables for the queried blog.
+ * 'global' - returns the global tables for the installation, returning multisite tables only if running multisite.
+ * 'ms_global' - returns the multisite global tables, regardless if current installation is multisite.
+ * 'old' - returns tables which are deprecated.
+ *
+ * @since 3.0.0
+ * @uses wpdb::$tables
+ * @uses wpdb::$old_tables
+ * @uses wpdb::$global_tables
+ * @uses wpdb::$ms_global_tables
+ * @uses is_multisite()
+ *
+ * @param string $scope Optional. Can be all, global, ms_global, blog, or old tables. Defaults to all.
+ * @param bool $prefix Optional. Whether to include table prefixes. Default true. If blog
+ * prefix is requested, then the custom users and usermeta tables will be mapped.
+ * @param int $blog_id Optional. The blog_id to prefix. Defaults to wpdb::$blogid. Used only when prefix is requested.
+ * @return array Table names. When a prefix is requested, the key is the unprefixed table name.
+ */
+ function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) {
+ switch ( $scope ) {
+ case 'all' :
+ $tables = array_merge( $this->global_tables, $this->tables );
+ if ( is_multisite() )
+ $tables = array_merge( $tables, $this->ms_global_tables );
+ break;
+ case 'blog' :
+ $tables = $this->tables;
+ break;
+ case 'global' :
+ $tables = $this->global_tables;
+ if ( is_multisite() )
+ $tables = array_merge( $tables, $this->ms_global_tables );
+ break;
+ case 'ms_global' :
+ $tables = $this->ms_global_tables;
+ break;
+ case 'old' :
+ $tables = $this->old_tables;
+ break;
+ default :
+ return array();
+ break;
+ }
+
+ if ( $prefix ) {
+ if ( ! $blog_id )
+ $blog_id = $this->blogid;
+ $blog_prefix = $this->get_blog_prefix( $blog_id );
+ $base_prefix = $this->base_prefix;
+ $global_tables = array_merge( $this->global_tables, $this->ms_global_tables );
+ foreach ( $tables as $k => $table ) {
+ if ( in_array( $table, $global_tables ) )
+ $tables[ $table ] = $base_prefix . $table;
+ else
+ $tables[ $table ] = $blog_prefix . $table;
+ unset( $tables[ $k ] );
+ }
+
+ if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) )
+ $tables['users'] = CUSTOM_USER_TABLE;
+
+ if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) )
+ $tables['usermeta'] = CUSTOM_USER_META_TABLE;
+ }
+
+ return $tables;
+ }
+
+ /**
+ * Selects a database using the current database connection.
+ *
+ * The database name will be changed based on the current database
+ * connection. On failure, the execution will bail and display an DB error.
+ *
+ * @since 0.71
+ *
+ * @param string $db MySQL database name
+ * @param resource $dbh Optional link identifier.
+ * @return null Always null.
+ */
+ function select( $db, $dbh = null ) {
+ if ( is_null($dbh) )
+ $dbh = $this->dbh;
+
+ if ( !@mysql_select_db( $db, $dbh ) ) {
+ $this->ready = false;
+ wp_load_translations_early();
+ $this->bail( sprintf( __( '<h1>Can&#8217;t select database</h1>
+<p>We were able to connect to the database server (which means your username and password is okay) but not able to select the <code>%1$s</code> database.</p>
+<ul>
+<li>Are you sure it exists?</li>
+<li>Does the user <code>%2$s</code> have permission to use the <code>%1$s</code> database?</li>
+<li>On some systems the name of your database is prefixed with your username, so it would be like <code>username_%1$s</code>. Could that be the problem?</li>
+</ul>
+<p>If you don\'t know how to set up a database you should <strong>contact your host</strong>. If all else fails you may find help at the <a href="http://wordpress.org/support/">WordPress Support Forums</a>.</p>' ), htmlspecialchars( $db, ENT_QUOTES ), htmlspecialchars( $this->dbuser, ENT_QUOTES ) ), 'db_select_fail' );
+ return;
+ }
+ }
+
+ /**
+ * Do not use, deprecated.
+ *
+ * Use esc_sql() or wpdb::prepare() instead.
+ *
+ * @since 2.8.0
+ * @deprecated 3.6.0
+ * @see wpdb::prepare
+ * @see esc_sql()
+ * @access private
+ *
+ * @param string $string
+ * @return string
+ */
+ function _weak_escape( $string ) {
+ if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) )
+ _deprecated_function( __METHOD__, '3.6', 'wpdb::prepare() or esc_sql()' );
+ return addslashes( $string );
+ }
+
+ /**
+ * Real escape, using mysql_real_escape_string()
+ *
+ * @see mysql_real_escape_string()
+ * @since 2.8.0
+ * @access private
+ *
+ * @param string $string to escape
+ * @return string escaped
+ */
+ function _real_escape( $string ) {
+ if ( $this->dbh )
+ return mysql_real_escape_string( $string, $this->dbh );
+
+ $class = get_class( $this );
+ _doing_it_wrong( $class, "$class must set a database connection for use with escaping.", E_USER_NOTICE );
+ return addslashes( $string );
+ }
+
+ /**
+ * Escape data. Works on arrays.
+ *
+ * @uses wpdb::_real_escape()
+ * @since 2.8.0
+ * @access private
+ *
+ * @param string|array $data
+ * @return string|array escaped
+ */
+ function _escape( $data ) {
+ if ( is_array( $data ) ) {
+ foreach ( $data as $k => $v ) {
+ if ( is_array($v) )
+ $data[$k] = $this->_escape( $v );
+ else
+ $data[$k] = $this->_real_escape( $v );
+ }
+ } else {
+ $data = $this->_real_escape( $data );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Do not use, deprecated.
+ *
+ * Use esc_sql() or wpdb::prepare() instead.
+ *
+ * @since 0.71
+ * @deprecated 3.6.0
+ * @see wpdb::prepare()
+ * @see esc_sql()
+ *
+ * @param mixed $data
+ * @return mixed
+ */
+ function escape( $data ) {
+ if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) )
+ _deprecated_function( __METHOD__, '3.6', 'wpdb::prepare() or esc_sql()' );
+ if ( is_array( $data ) ) {
+ foreach ( $data as $k => $v ) {
+ if ( is_array( $v ) )
+ $data[$k] = $this->escape( $v, 'recursive' );
+ else
+ $data[$k] = $this->_weak_escape( $v, 'internal' );
+ }
+ } else {
+ $data = $this->_weak_escape( $data, 'internal' );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Escapes content by reference for insertion into the database, for security
+ *
+ * @uses wpdb::_real_escape()
+ * @since 2.3.0
+ * @param string $string to escape
+ * @return void
+ */
+ function escape_by_ref( &$string ) {
+ if ( ! is_float( $string ) )
+ $string = $this->_real_escape( $string );
+ }
+
+ /**
+ * Prepares a SQL query for safe execution. Uses sprintf()-like syntax.
+ *
+ * The following directives can be used in the query format string:
+ * %d (integer)
+ * %f (float)
+ * %s (string)
+ * %% (literal percentage sign - no argument needed)
+ *
+ * All of %d, %f, and %s are to be left unquoted in the query string and they need an argument passed for them.
+ * Literals (%) as parts of the query must be properly written as %%.
+ *
+ * This function only supports a small subset of the sprintf syntax; it only supports %d (integer), %f (float), and %s (string).
+ * Does not support sign, padding, alignment, width or precision specifiers.
+ * Does not support argument numbering/swapping.
+ *
+ * May be called like {@link http://php.net/sprintf sprintf()} or like {@link http://php.net/vsprintf vsprintf()}.
+ *
+ * Both %d and %s should be left unquoted in the query string.
+ *
+ * <code>
+ * wpdb::prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d", 'foo', 1337 )
+ * wpdb::prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );
+ * </code>
+ *
+ * @link http://php.net/sprintf Description of syntax.
+ * @since 2.3.0
+ *
+ * @param string $query Query statement with sprintf()-like placeholders
+ * @param array|mixed $args The array of variables to substitute into the query's placeholders if being called like
+ * {@link http://php.net/vsprintf vsprintf()}, or the first variable to substitute into the query's placeholders if
+ * being called like {@link http://php.net/sprintf sprintf()}.
+ * @param mixed $args,... further variables to substitute into the query's placeholders if being called like
+ * {@link http://php.net/sprintf sprintf()}.
+ * @return null|false|string Sanitized query string, null if there is no query, false if there is an error and string
+ * if there was something to prepare
+ */
+ function prepare( $query, $args ) {
+ if ( is_null( $query ) )
+ return;
+
+ $args = func_get_args();
+ array_shift( $args );
+ // If args were passed as an array (as in vsprintf), move them up
+ if ( isset( $args[0] ) && is_array($args[0]) )
+ $args = $args[0];
+ $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
+ $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
+ $query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
+ $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
+ array_walk( $args, array( $this, 'escape_by_ref' ) );
+ return @vsprintf( $query, $args );
+ }
+
+ /**
+ * Print SQL/DB error.
+ *
+ * @since 0.71
+ * @global array $EZSQL_ERROR Stores error information of query and error string
+ *
+ * @param string $str The error to display
+ * @return bool False if the showing of errors is disabled.
+ */
+ function print_error( $str = '' ) {
+ global $EZSQL_ERROR;
+
+ if ( !$str )
+ $str = mysql_error( $this->dbh );
+ $EZSQL_ERROR[] = array( 'query' => $this->last_query, 'error_str' => $str );
+
+ if ( $this->suppress_errors )
+ return false;
+
+ wp_load_translations_early();
+
+ if ( $caller = $this->get_caller() )
+ $error_str = sprintf( __( 'WordPress database error %1$s for query %2$s made by %3$s' ), $str, $this->last_query, $caller );
+ else
+ $error_str = sprintf( __( 'WordPress database error %1$s for query %2$s' ), $str, $this->last_query );
+
+ error_log( $error_str );
+
+ // Are we showing errors?
+ if ( ! $this->show_errors )
+ return false;
+
+ // If there is an error then take note of it
+ if ( is_multisite() ) {
+ $msg = "WordPress database error: [$str]\n{$this->last_query}\n";
+ if ( defined( 'ERRORLOGFILE' ) )
+ error_log( $msg, 3, ERRORLOGFILE );
+ if ( defined( 'DIEONDBERROR' ) )
+ wp_die( $msg );
+ } else {
+ $str = htmlspecialchars( $str, ENT_QUOTES );
+ $query = htmlspecialchars( $this->last_query, ENT_QUOTES );
+
+ print "<div id='error'>
+ <p class='wpdberror'><strong>WordPress database error:</strong> [$str]<br />
+ <code>$query</code></p>
+ </div>";
+ }
+ }
+
+ /**
+ * Enables showing of database errors.
+ *
+ * This function should be used only to enable showing of errors.
+ * wpdb::hide_errors() should be used instead for hiding of errors. However,
+ * this function can be used to enable and disable showing of database
+ * errors.
+ *
+ * @since 0.71
+ * @see wpdb::hide_errors()
+ *
+ * @param bool $show Whether to show or hide errors
+ * @return bool Old value for showing errors.
+ */
+ function show_errors( $show = true ) {
+ $errors = $this->show_errors;
+ $this->show_errors = $show;
+ return $errors;
+ }
+
+ /**
+ * Disables showing of database errors.
+ *
+ * By default database errors are not shown.
+ *
+ * @since 0.71
+ * @see wpdb::show_errors()
+ *
+ * @return bool Whether showing of errors was active
+ */
+ function hide_errors() {
+ $show = $this->show_errors;
+ $this->show_errors = false;
+ return $show;
+ }
+
+ /**
+ * Whether to suppress database errors.
+ *
+ * By default database errors are suppressed, with a simple
+ * call to this function they can be enabled.
+ *
+ * @since 2.5.0
+ * @see wpdb::hide_errors()
+ * @param bool $suppress Optional. New value. Defaults to true.
+ * @return bool Old value
+ */
+ function suppress_errors( $suppress = true ) {
+ $errors = $this->suppress_errors;
+ $this->suppress_errors = (bool) $suppress;
+ return $errors;
+ }
+
+ /**
+ * Kill cached query results.
+ *
+ * @since 0.71
+ * @return void
+ */
+ function flush() {
+ $this->last_result = array();
+ $this->col_info = null;
+ $this->last_query = null;
+ $this->rows_affected = $this->num_rows = 0;
+ $this->last_error = '';
+
+ if ( is_resource( $this->result ) )
+ mysql_free_result( $this->result );
+ }
+
+ /**
+ * Connect to and select database
+ *
+ * @since 3.0.0
+ */
+ function db_connect() {
+
+ $this->is_mysql = true;
+
+ $new_link = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true;
+ $client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;
+
+ if ( WP_DEBUG ) {
+ $this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
+ } else {
+ $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
+ }
+
+ if ( !$this->dbh ) {
+ wp_load_translations_early();
+ $this->bail( sprintf( __( "
+<h1>Error establishing a database connection</h1>
+<p>This either means that the username and password information in your <code>wp-config.php</code> file is incorrect or we can't contact the database server at <code>%s</code>. This could mean your host's database server is down.</p>
+<ul>
+ <li>Are you sure you have the correct username and password?</li>
+ <li>Are you sure that you have typed the correct hostname?</li>
+ <li>Are you sure that the database server is running?</li>
+</ul>
+<p>If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href='http://wordpress.org/support/'>WordPress Support Forums</a>.</p>
+" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' );
+
+ return;
+ }
+
+ $this->set_charset( $this->dbh );
+
+ $this->ready = true;
+
+ $this->select( $this->dbname, $this->dbh );
+ }
+
+ /**
+ * Perform a MySQL database query, using current database connection.
+ *
+ * More information can be found on the codex page.
+ *
+ * @since 0.71
+ *
+ * @param string $query Database query
+ * @return int|false Number of rows affected/selected or false on error
+ */
+ function query( $query ) {
+ if ( ! $this->ready )
+ return false;
+
+ // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method
+ $query = apply_filters( 'query', $query );
+
+ $return_val = 0;
+ $this->flush();
+
+ // Log how the function was called
+ $this->func_call = "\$db->query(\"$query\")";
+
+ // Keep track of the last query for debug..
+ $this->last_query = $query;
+
+ if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
+ $this->timer_start();
+
+ $this->result = @mysql_query( $query, $this->dbh );
+ $this->num_queries++;
+
+ if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES )
+ $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
+
+ // If there is an error then take note of it..
+ if ( $this->last_error = mysql_error( $this->dbh ) ) {
+ // Clear insert_id on a subsequent failed insert.
+ if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) )
+ $this->insert_id = 0;
+
+ $this->print_error();
+ return false;
+ }
+
+ if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) {
+ $return_val = $this->result;
+ } elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) {
+ $this->rows_affected = mysql_affected_rows( $this->dbh );
+ // Take note of the insert_id
+ if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
+ $this->insert_id = mysql_insert_id($this->dbh);
+ }
+ // Return number of rows affected
+ $return_val = $this->rows_affected;
+ } else {
+ $num_rows = 0;
+ while ( $row = @mysql_fetch_object( $this->result ) ) {
+ $this->last_result[$num_rows] = $row;
+ $num_rows++;
+ }
+
+ // Log number of rows the query returned
+ // and return number of rows selected
+ $this->num_rows = $num_rows;
+ $return_val = $num_rows;
+ }
+
+ return $return_val;
+ }
+
+ /**
+ * Insert a row into a table.
+ *
+ * <code>
+ * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
+ * wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
+ * </code>
+ *
+ * @since 2.5.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @param string $table table name
+ * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
+ * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data.
+ * A format is one of '%d', '%f', '%s' (integer, float, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @return int|false The number of rows inserted, or false on error.
+ */
+ function insert( $table, $data, $format = null ) {
+ return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
+ }
+
+ /**
+ * Replace a row into a table.
+ *
+ * <code>
+ * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
+ * wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
+ * </code>
+ *
+ * @since 3.0.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @param string $table table name
+ * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
+ * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data.
+ * A format is one of '%d', '%f', '%s' (integer, float, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @return int|false The number of rows affected, or false on error.
+ */
+ function replace( $table, $data, $format = null ) {
+ return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' );
+ }
+
+ /**
+ * Helper function for insert and replace.
+ *
+ * Runs an insert or replace query based on $type argument.
+ *
+ * @access private
+ * @since 3.0.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @param string $table table name
+ * @param array $data Data to insert (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
+ * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data.
+ * A format is one of '%d', '%f', '%s' (integer, float, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @param string $type Optional. What type of operation is this? INSERT or REPLACE. Defaults to INSERT.
+ * @return int|false The number of rows affected, or false on error.
+ */
+ function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
+ if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) )
+ return false;
+ $this->insert_id = 0;
+ $formats = $format = (array) $format;
+ $fields = array_keys( $data );
+ $formatted_fields = array();
+ foreach ( $fields as $field ) {
+ if ( !empty( $format ) )
+ $form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
+ elseif ( isset( $this->field_types[$field] ) )
+ $form = $this->field_types[$field];
+ else
+ $form = '%s';
+ $formatted_fields[] = $form;
+ }
+ $sql = "{$type} INTO `$table` (`" . implode( '`,`', $fields ) . "`) VALUES (" . implode( ",", $formatted_fields ) . ")";
+ return $this->query( $this->prepare( $sql, $data ) );
+ }
+
+ /**
+ * Update a row in the table
+ *
+ * <code>
+ * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) )
+ * wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) )
+ * </code>
+ *
+ * @since 2.5.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @param string $table table name
+ * @param array $data Data to update (in column => value pairs). Both $data columns and $data values should be "raw" (neither should be SQL escaped).
+ * @param array $where A named array of WHERE clauses (in column => value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be "raw".
+ * @param array|string $format Optional. An array of formats to be mapped to each of the values in $data. If string, that format will be used for all of the values in $data.
+ * A format is one of '%d', '%f', '%s' (integer, float, string). If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where. If string, that format will be used for all of the items in $where. A format is one of '%d', '%f', '%s' (integer, float, string). If omitted, all values in $where will be treated as strings.
+ * @return int|false The number of rows updated, or false on error.
+ */
+ function update( $table, $data, $where, $format = null, $where_format = null ) {
+ if ( ! is_array( $data ) || ! is_array( $where ) )
+ return false;
+
+ $formats = $format = (array) $format;
+ $bits = $wheres = array();
+ foreach ( (array) array_keys( $data ) as $field ) {
+ if ( !empty( $format ) )
+ $form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
+ elseif ( isset($this->field_types[$field]) )
+ $form = $this->field_types[$field];
+ else
+ $form = '%s';
+ $bits[] = "`$field` = {$form}";
+ }
+
+ $where_formats = $where_format = (array) $where_format;
+ foreach ( (array) array_keys( $where ) as $field ) {
+ if ( !empty( $where_format ) )
+ $form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0];
+ elseif ( isset( $this->field_types[$field] ) )
+ $form = $this->field_types[$field];
+ else
+ $form = '%s';
+ $wheres[] = "`$field` = {$form}";
+ }
+
+ $sql = "UPDATE `$table` SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres );
+ return $this->query( $this->prepare( $sql, array_merge( array_values( $data ), array_values( $where ) ) ) );
+ }
+
+ /**
+ * Delete a row in the table
+ *
+ * <code>
+ * wpdb::delete( 'table', array( 'ID' => 1 ) )
+ * wpdb::delete( 'table', array( 'ID' => 1 ), array( '%d' ) )
+ * </code>
+ *
+ * @since 3.4.0
+ * @see wpdb::prepare()
+ * @see wpdb::$field_types
+ * @see wp_set_wpdb_vars()
+ *
+ * @param string $table table name
+ * @param array $where A named array of WHERE clauses (in column => value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be "raw".
+ * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where. If string, that format will be used for all of the items in $where. A format is one of '%d', '%f', '%s' (integer, float, string). If omitted, all values in $where will be treated as strings unless otherwise specified in wpdb::$field_types.
+ * @return int|false The number of rows updated, or false on error.
+ */
+ function delete( $table, $where, $where_format = null ) {
+ if ( ! is_array( $where ) )
+ return false;
+
+ $bits = $wheres = array();
+
+ $where_formats = $where_format = (array) $where_format;
+
+ foreach ( array_keys( $where ) as $field ) {
+ if ( !empty( $where_format ) ) {
+ $form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0];
+ } elseif ( isset( $this->field_types[ $field ] ) ) {
+ $form = $this->field_types[ $field ];
+ } else {
+ $form = '%s';
+ }
+
+ $wheres[] = "$field = $form";
+ }
+
+ $sql = "DELETE FROM $table WHERE " . implode( ' AND ', $wheres );
+ return $this->query( $this->prepare( $sql, $where ) );
+ }
+
+
+ /**
+ * Retrieve one variable from the database.
+ *
+ * Executes a SQL query and returns the value from the SQL result.
+ * If the SQL result contains more than one column and/or more than one row, this function returns the value in the column and row specified.
+ * If $query is null, this function returns the value in the specified column and row from the previous SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
+ * @param int $x Optional. Column of value to return. Indexed from 0.
+ * @param int $y Optional. Row of value to return. Indexed from 0.
+ * @return string|null Database query result (as string), or null on failure
+ */
+ function get_var( $query = null, $x = 0, $y = 0 ) {
+ $this->func_call = "\$db->get_var(\"$query\", $x, $y)";
+ if ( $query )
+ $this->query( $query );
+
+ // Extract var out of cached results based x,y vals
+ if ( !empty( $this->last_result[$y] ) ) {
+ $values = array_values( get_object_vars( $this->last_result[$y] ) );
+ }
+
+ // If there is a value return it else return null
+ return ( isset( $values[$x] ) && $values[$x] !== '' ) ? $values[$x] : null;
+ }
+
+ /**
+ * Retrieve one row from the database.
+ *
+ * Executes a SQL query and returns the row from the SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query SQL query.
+ * @param string $output Optional. one of ARRAY_A | ARRAY_N | OBJECT constants. Return an associative array (column => value, ...),
+ * a numerically indexed array (0 => value, ...) or an object ( ->column = value ), respectively.
+ * @param int $y Optional. Row to return. Indexed from 0.
+ * @return mixed Database query result in format specified by $output or null on failure
+ */
+ function get_row( $query = null, $output = OBJECT, $y = 0 ) {
+ $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
+ if ( $query )
+ $this->query( $query );
+ else
+ return null;
+
+ if ( !isset( $this->last_result[$y] ) )
+ return null;
+
+ if ( $output == OBJECT ) {
+ return $this->last_result[$y] ? $this->last_result[$y] : null;
+ } elseif ( $output == ARRAY_A ) {
+ return $this->last_result[$y] ? get_object_vars( $this->last_result[$y] ) : null;
+ } elseif ( $output == ARRAY_N ) {
+ return $this->last_result[$y] ? array_values( get_object_vars( $this->last_result[$y] ) ) : null;
+ } else {
+ $this->print_error( " \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N" );
+ }
+ }
+
+ /**
+ * Retrieve one column from the database.
+ *
+ * Executes a SQL query and returns the column from the SQL result.
+ * If the SQL result contains more than one column, this function returns the column specified.
+ * If $query is null, this function returns the specified column from the previous SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string|null $query Optional. SQL query. Defaults to previous query.
+ * @param int $x Optional. Column to return. Indexed from 0.
+ * @return array Database query result. Array indexed from 0 by SQL result row number.
+ */
+ function get_col( $query = null , $x = 0 ) {
+ if ( $query )
+ $this->query( $query );
+
+ $new_array = array();
+ // Extract the column values
+ for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) {
+ $new_array[$i] = $this->get_var( null, $x, $i );
+ }
+ return $new_array;
+ }
+
+ /**
+ * Retrieve an entire SQL result set from the database (i.e., many rows)
+ *
+ * Executes a SQL query and returns the entire SQL result.
+ *
+ * @since 0.71
+ *
+ * @param string $query SQL query.
+ * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants. With one of the first three, return an array of rows indexed from 0 by SQL result row number.
+ * Each row is an associative array (column => value, ...), a numerically indexed array (0 => value, ...), or an object. ( ->column = value ), respectively.
+ * With OBJECT_K, return an associative array of row objects keyed by the value of each row's first column's value. Duplicate keys are discarded.
+ * @return mixed Database query results
+ */
+ function get_results( $query = null, $output = OBJECT ) {
+ $this->func_call = "\$db->get_results(\"$query\", $output)";
+
+ if ( $query )
+ $this->query( $query );
+ else
+ return null;
+
+ $new_array = array();
+ if ( $output == OBJECT ) {
+ // Return an integer-keyed array of row objects
+ return $this->last_result;
+ } elseif ( $output == OBJECT_K ) {
+ // Return an array of row objects with keys from column 1
+ // (Duplicates are discarded)
+ foreach ( $this->last_result as $row ) {
+ $var_by_ref = get_object_vars( $row );
+ $key = array_shift( $var_by_ref );
+ if ( ! isset( $new_array[ $key ] ) )
+ $new_array[ $key ] = $row;
+ }
+ return $new_array;
+ } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
+ // Return an integer-keyed array of...
+ if ( $this->last_result ) {
+ foreach( (array) $this->last_result as $row ) {
+ if ( $output == ARRAY_N ) {
+ // ...integer-keyed row arrays
+ $new_array[] = array_values( get_object_vars( $row ) );
+ } else {
+ // ...column name-keyed row arrays
+ $new_array[] = get_object_vars( $row );
+ }
+ }
+ }
+ return $new_array;
+ }
+ return null;
+ }
+
+ /**
+ * Load the column metadata from the last query.
+ *
+ * @since 3.5.0
+ *
+ * @access protected
+ */
+ protected function load_col_info() {
+ if ( $this->col_info )
+ return;
+
+ for ( $i = 0; $i < @mysql_num_fields( $this->result ); $i++ ) {
+ $this->col_info[ $i ] = @mysql_fetch_field( $this->result, $i );
+ }
+ }
+
+ /**
+ * Retrieve column metadata from the last query.
+ *
+ * @since 0.71
+ *
+ * @param string $info_type Optional. Type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill
+ * @param int $col_offset Optional. 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type
+ * @return mixed Column Results
+ */
+ function get_col_info( $info_type = 'name', $col_offset = -1 ) {
+ $this->load_col_info();
+
+ if ( $this->col_info ) {
+ if ( $col_offset == -1 ) {
+ $i = 0;
+ $new_array = array();
+ foreach( (array) $this->col_info as $col ) {
+ $new_array[$i] = $col->{$info_type};
+ $i++;
+ }
+ return $new_array;
+ } else {
+ return $this->col_info[$col_offset]->{$info_type};
+ }
+ }
+ }
+
+ /**
+ * Starts the timer, for debugging purposes.
+ *
+ * @since 1.5.0
+ *
+ * @return true
+ */
+ function timer_start() {
+ $this->time_start = microtime( true );
+ return true;
+ }
+
+ /**
+ * Stops the debugging timer.
+ *
+ * @since 1.5.0
+ *
+ * @return float Total time spent on the query, in seconds
+ */
+ function timer_stop() {
+ return ( microtime( true ) - $this->time_start );
+ }
+
+ /**
+ * Wraps errors in a nice header and footer and dies.
+ *
+ * Will not die if wpdb::$show_errors is false.
+ *
+ * @since 1.5.0
+ *
+ * @param string $message The Error message
+ * @param string $error_code Optional. A Computer readable string to identify the error.
+ * @return false|void
+ */
+ function bail( $message, $error_code = '500' ) {
+ if ( !$this->show_errors ) {
+ if ( class_exists( 'WP_Error' ) )
+ $this->error = new WP_Error($error_code, $message);
+ else
+ $this->error = $message;
+ return false;
+ }
+ wp_die($message);
+ }
+
+ /**
+ * Whether MySQL database is at least the required minimum version.
+ *
+ * @since 2.5.0
+ * @uses $wp_version
+ * @uses $required_mysql_version
+ *
+ * @return WP_Error
+ */
+ function check_database_version() {
+ global $wp_version, $required_mysql_version;
+ // Make sure the server has the required MySQL version
+ if ( version_compare($this->db_version(), $required_mysql_version, '<') )
+ return new WP_Error('database_version', sprintf( __( '<strong>ERROR</strong>: WordPress %1$s requires MySQL %2$s or higher' ), $wp_version, $required_mysql_version ));
+ }
+
+ /**
+ * Whether the database supports collation.
+ *
+ * Called when WordPress is generating the table scheme.
+ *
+ * @since 2.5.0
+ * @deprecated 3.5.0
+ * @deprecated Use wpdb::has_cap( 'collation' )
+ *
+ * @return bool True if collation is supported, false if version does not
+ */
+ function supports_collation() {
+ _deprecated_function( __FUNCTION__, '3.5', 'wpdb::has_cap( \'collation\' )' );
+ return $this->has_cap( 'collation' );
+ }
+
+ /**
+ * The database character collate.
+ *
+ * @since 3.5.0
+ *
+ * @return string The database character collate.
+ */
+ public function get_charset_collate() {
+ $charset_collate = '';
+
+ if ( ! empty( $this->charset ) )
+ $charset_collate = "DEFAULT CHARACTER SET $this->charset";
+ if ( ! empty( $this->collate ) )
+ $charset_collate .= " COLLATE $this->collate";
+
+ return $charset_collate;
+ }
+
+ /**
+ * Determine if a database supports a particular feature.
+ *
+ * @since 2.7.0
+ * @see wpdb::db_version()
+ *
+ * @param string $db_cap The feature to check for.
+ * @return bool
+ */
+ function has_cap( $db_cap ) {
+ $version = $this->db_version();
+
+ switch ( strtolower( $db_cap ) ) {
+ case 'collation' : // @since 2.5.0
+ case 'group_concat' : // @since 2.7.0
+ case 'subqueries' : // @since 2.7.0
+ return version_compare( $version, '4.1', '>=' );
+ case 'set_charset' :
+ return version_compare( $version, '5.0.7', '>=' );
+ };
+
+ return false;
+ }
+
+ /**
+ * Retrieve the name of the function that called wpdb.
+ *
+ * Searches up the list of functions until it reaches
+ * the one that would most logically had called this method.
+ *
+ * @since 2.5.0
+ *
+ * @return string The name of the calling function
+ */
+ function get_caller() {
+ return wp_debug_backtrace_summary( __CLASS__ );
+ }
+
+ /**
+ * The database version number.
+ *
+ * @since 2.7.0
+ *
+ * @return false|string false on failure, version number on success
+ */
+ function db_version() {
+ return preg_replace( '/[^0-9.].*/', '', mysql_get_server_info( $this->dbh ) );
+ }
+}
diff --git a/src/wp-includes/wp-diff.php b/src/wp-includes/wp-diff.php
new file mode 100644
index 0000000000..62f4162fa3
--- /dev/null
+++ b/src/wp-includes/wp-diff.php
@@ -0,0 +1,500 @@
+<?php
+/**
+ * WordPress Diff bastard child of old MediaWiki Diff Formatter.
+ *
+ * Basically all that remains is the table structure and some method names.
+ *
+ * @package WordPress
+ * @subpackage Diff
+ */
+
+if ( !class_exists( 'Text_Diff' ) ) {
+ /** Text_Diff class */
+ require( dirname(__FILE__).'/Text/Diff.php' );
+ /** Text_Diff_Renderer class */
+ require( dirname(__FILE__).'/Text/Diff/Renderer.php' );
+ /** Text_Diff_Renderer_inline class */
+ require( dirname(__FILE__).'/Text/Diff/Renderer/inline.php' );
+}
+
+/**
+ * Table renderer to display the diff lines.
+ *
+ * @since 2.6.0
+ * @uses Text_Diff_Renderer Extends
+ */
+class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer {
+
+ /**
+ * @see Text_Diff_Renderer::_leading_context_lines
+ * @var int
+ * @access protected
+ * @since 2.6.0
+ */
+ var $_leading_context_lines = 10000;
+
+ /**
+ * @see Text_Diff_Renderer::_trailing_context_lines
+ * @var int
+ * @access protected
+ * @since 2.6.0
+ */
+ var $_trailing_context_lines = 10000;
+
+ /**
+ * {@internal Missing Description}}
+ *
+ * @var float
+ * @access protected
+ * @since 2.6.0
+ */
+ var $_diff_threshold = 0.6;
+
+ /**
+ * Inline display helper object name.
+ *
+ * @var string
+ * @access protected
+ * @since 2.6.0
+ */
+ var $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline';
+
+ /**
+ * Should we show the split view or not
+ *
+ * @var string
+ * @access protected
+ * @since 3.6.0
+ */
+ var $_show_split_view = true;
+
+ /**
+ * Constructor - Call parent constructor with params array.
+ *
+ * This will set class properties based on the key value pairs in the array.
+ *
+ * @since 2.6.0
+ *
+ * @param array $params
+ */
+ function __construct( $params = array() ) {
+ parent::__construct( $params );
+ if ( isset( $params[ 'show_split_view' ] ) )
+ $this->_show_split_view = $params[ 'show_split_view' ];
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $header
+ * @return string
+ */
+ function _startBlock( $header ) {
+ return '';
+ }
+
+ /**
+ * @ignore
+ *
+ * @param array $lines
+ * @param string $prefix
+ */
+ function _lines( $lines, $prefix=' ' ) {
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $line HTML-escape the value.
+ * @return string
+ */
+ function addedLine( $line ) {
+ return "<td class='diff-addedline'>{$line}</td>";
+
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $line HTML-escape the value.
+ * @return string
+ */
+ function deletedLine( $line ) {
+ return "<td class='diff-deletedline'>{$line}</td>";
+ }
+
+ /**
+ * @ignore
+ *
+ * @param string $line HTML-escape the value.
+ * @return string
+ */
+ function contextLine( $line ) {
+ return "<td class='diff-context'>{$line}</td>";
+ }
+
+ /**
+ * @ignore
+ *
+ * @return string
+ */
+ function emptyLine() {
+ return '<td>&nbsp;</td>';
+ }
+
+ /**
+ * @ignore
+ * @access private
+ *
+ * @param array $lines
+ * @param bool $encode
+ * @return string
+ */
+ function _added( $lines, $encode = true ) {
+ $r = '';
+ foreach ($lines as $line) {
+ if ( $encode )
+ $line = htmlspecialchars( $line );
+ if ( $this->_show_split_view ) {
+ $r .= '<tr>' . $this->emptyLine() . $this->emptyLine() . $this->addedLine( $line ) . "</tr>\n";
+ } else {
+ $r .= '<tr>' . $this->addedLine( $line ) . "</tr>\n";
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * @ignore
+ * @access private
+ *
+ * @param array $lines
+ * @param bool $encode
+ * @return string
+ */
+ function _deleted( $lines, $encode = true ) {
+ $r = '';
+ foreach ($lines as $line) {
+ if ( $encode )
+ $line = htmlspecialchars( $line );
+ if ( $this->_show_split_view ) {
+ $r .= '<tr>' . $this->deletedLine( $line ) . $this->emptyLine() . $this->emptyLine() . "</tr>\n";
+ } else {
+ $r .= '<tr>' . $this->deletedLine( $line ) . "</tr>\n";
+ }
+
+ }
+ return $r;
+ }
+
+ /**
+ * @ignore
+ * @access private
+ *
+ * @param array $lines
+ * @param bool $encode
+ * @return string
+ */
+ function _context( $lines, $encode = true ) {
+ $r = '';
+ foreach ($lines as $line) {
+ if ( $encode )
+ $line = htmlspecialchars( $line );
+ if ( $this->_show_split_view ) {
+ $r .= '<tr>' . $this->contextLine( $line ) . $this->emptyLine() . $this->contextLine( $line ) . "</tr>\n";
+ } else {
+ $r .= '<tr>' . $this->contextLine( $line ) . "</tr>\n";
+ }
+ }
+ return $r;
+ }
+
+ /**
+ * Process changed lines to do word-by-word diffs for extra highlighting.
+ *
+ * (TRAC style) sometimes these lines can actually be deleted or added rows.
+ * We do additional processing to figure that out
+ *
+ * @access private
+ * @since 2.6.0
+ *
+ * @param array $orig
+ * @param array $final
+ * @return string
+ */
+ function _changed( $orig, $final ) {
+ $r = '';
+
+ // Does the aforementioned additional processing
+ // *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes
+ // match is numeric: an index in other column
+ // match is 'X': no match. It is a new row
+ // *_rows are column vectors for the orig column and the final column.
+ // row >= 0: an indix of the $orig or $final array
+ // row < 0: a blank row for that column
+ list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
+
+ // These will hold the word changes as determined by an inline diff
+ $orig_diffs = array();
+ $final_diffs = array();
+
+ // Compute word diffs for each matched pair using the inline diff
+ foreach ( $orig_matches as $o => $f ) {
+ if ( is_numeric($o) && is_numeric($f) ) {
+ $text_diff = new Text_Diff( 'auto', array( array($orig[$o]), array($final[$f]) ) );
+ $renderer = new $this->inline_diff_renderer;
+ $diff = $renderer->render( $text_diff );
+
+ // If they're too different, don't include any <ins> or <dels>
+ if ( $diff_count = preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
+ // length of all text between <ins> or <del>
+ $stripped_matches = strlen(strip_tags( join(' ', $diff_matches[0]) ));
+ // since we count lengith of text between <ins> or <del> (instead of picking just one),
+ // we double the length of chars not in those tags.
+ $stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches;
+ $diff_ratio = $stripped_matches / $stripped_diff;
+ if ( $diff_ratio > $this->_diff_threshold )
+ continue; // Too different. Don't save diffs.
+ }
+
+ // Un-inline the diffs by removing del or ins
+ $orig_diffs[$o] = preg_replace( '|<ins>.*?</ins>|', '', $diff );
+ $final_diffs[$f] = preg_replace( '|<del>.*?</del>|', '', $diff );
+ }
+ }
+
+ foreach ( array_keys($orig_rows) as $row ) {
+ // Both columns have blanks. Ignore them.
+ if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 )
+ continue;
+
+ // If we have a word based diff, use it. Otherwise, use the normal line.
+ if ( isset( $orig_diffs[$orig_rows[$row]] ) )
+ $orig_line = $orig_diffs[$orig_rows[$row]];
+ elseif ( isset( $orig[$orig_rows[$row]] ) )
+ $orig_line = htmlspecialchars($orig[$orig_rows[$row]]);
+ else
+ $orig_line = '';
+
+ if ( isset( $final_diffs[$final_rows[$row]] ) )
+ $final_line = $final_diffs[$final_rows[$row]];
+ elseif ( isset( $final[$final_rows[$row]] ) )
+ $final_line = htmlspecialchars($final[$final_rows[$row]]);
+ else
+ $final_line = '';
+
+ if ( $orig_rows[$row] < 0 ) { // Orig is blank. This is really an added row.
+ $r .= $this->_added( array($final_line), false );
+ } elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row.
+ $r .= $this->_deleted( array($orig_line), false );
+ } else { // A true changed row.
+ if ( $this->_show_split_view ) {
+ $r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->emptyLine() . $this->addedLine( $final_line ) . "</tr>\n";
+ } else {
+ $r .= '<tr>' . $this->deletedLine( $orig_line ) . "</tr><tr>" . $this->addedLine( $final_line ) . "</tr>\n";
+ }
+ }
+ }
+
+ return $r;
+ }
+
+ /**
+ * Takes changed blocks and matches which rows in orig turned into which rows in final.
+ *
+ * Returns
+ * *_matches ( which rows match with which )
+ * *_rows ( order of rows in each column interleaved with blank rows as
+ * necessary )
+ *
+ * @since 2.6.0
+ *
+ * @param unknown_type $orig
+ * @param unknown_type $final
+ * @return unknown
+ */
+ function interleave_changed_lines( $orig, $final ) {
+
+ // Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
+ $matches = array();
+ foreach ( array_keys($orig) as $o ) {
+ foreach ( array_keys($final) as $f ) {
+ $matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] );
+ }
+ }
+ asort($matches); // Order by string distance.
+
+ $orig_matches = array();
+ $final_matches = array();
+
+ foreach ( $matches as $keys => $difference ) {
+ list($o, $f) = explode(',', $keys);
+ $o = (int) $o;
+ $f = (int) $f;
+
+ // Already have better matches for these guys
+ if ( isset($orig_matches[$o]) && isset($final_matches[$f]) )
+ continue;
+
+ // First match for these guys. Must be best match
+ if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) {
+ $orig_matches[$o] = $f;
+ $final_matches[$f] = $o;
+ continue;
+ }
+
+ // Best match of this final is already taken? Must mean this final is a new row.
+ if ( isset($orig_matches[$o]) )
+ $final_matches[$f] = 'x';
+
+ // Best match of this orig is already taken? Must mean this orig is a deleted row.
+ elseif ( isset($final_matches[$f]) )
+ $orig_matches[$o] = 'x';
+ }
+
+ // We read the text in this order
+ ksort($orig_matches);
+ ksort($final_matches);
+
+ // Stores rows and blanks for each column.
+ $orig_rows = $orig_rows_copy = array_keys($orig_matches);
+ $final_rows = array_keys($final_matches);
+
+ // Interleaves rows with blanks to keep matches aligned.
+ // We may end up with some extraneous blank rows, but we'll just ignore them later.
+ foreach ( $orig_rows_copy as $orig_row ) {
+ $final_pos = array_search($orig_matches[$orig_row], $final_rows, true);
+ $orig_pos = (int) array_search($orig_row, $orig_rows, true);
+
+ if ( false === $final_pos ) { // This orig is paired with a blank final.
+ array_splice( $final_rows, $orig_pos, 0, -1 );
+ } elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows.
+ $diff_pos = $final_pos - $orig_pos;
+ while ( $diff_pos < 0 )
+ array_splice( $final_rows, $orig_pos, 0, $diff_pos++ );
+ } elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows.
+ $diff_pos = $orig_pos - $final_pos;
+ while ( $diff_pos < 0 )
+ array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ );
+ }
+ }
+
+ // Pad the ends with blank rows if the columns aren't the same length
+ $diff_count = count($orig_rows) - count($final_rows);
+ if ( $diff_count < 0 ) {
+ while ( $diff_count < 0 )
+ array_push($orig_rows, $diff_count++);
+ } elseif ( $diff_count > 0 ) {
+ $diff_count = -1 * $diff_count;
+ while ( $diff_count < 0 )
+ array_push($final_rows, $diff_count++);
+ }
+
+ return array($orig_matches, $final_matches, $orig_rows, $final_rows);
+
+/*
+ // Debug
+ echo "\n\n\n\n\n";
+
+ echo "-- DEBUG Matches: Orig -> Final --";
+
+ foreach ( $orig_matches as $o => $f ) {
+ echo "\n\n\n\n\n";
+ echo "ORIG: $o, FINAL: $f\n";
+ var_dump($orig[$o],$final[$f]);
+ }
+ echo "\n\n\n\n\n";
+
+ echo "-- DEBUG Matches: Final -> Orig --";
+
+ foreach ( $final_matches as $f => $o ) {
+ echo "\n\n\n\n\n";
+ echo "FINAL: $f, ORIG: $o\n";
+ var_dump($final[$f],$orig[$o]);
+ }
+ echo "\n\n\n\n\n";
+
+ echo "-- DEBUG Rows: Orig -- Final --";
+
+ echo "\n\n\n\n\n";
+ foreach ( $orig_rows as $row => $o ) {
+ if ( $o < 0 )
+ $o = 'X';
+ $f = $final_rows[$row];
+ if ( $f < 0 )
+ $f = 'X';
+ echo "$o -- $f\n";
+ }
+ echo "\n\n\n\n\n";
+
+ echo "-- END DEBUG --";
+
+ echo "\n\n\n\n\n";
+
+ return array($orig_matches, $final_matches, $orig_rows, $final_rows);
+*/
+ }
+
+ /**
+ * Computes a number that is intended to reflect the "distance" between two strings.
+ *
+ * @since 2.6.0
+ *
+ * @param string $string1
+ * @param string $string2
+ * @return int
+ */
+ function compute_string_distance( $string1, $string2 ) {
+ // Vectors containing character frequency for all chars in each string
+ $chars1 = count_chars($string1);
+ $chars2 = count_chars($string2);
+
+ // L1-norm of difference vector.
+ $difference = array_sum( array_map( array($this, 'difference'), $chars1, $chars2 ) );
+
+ // $string1 has zero length? Odd. Give huge penalty by not dividing.
+ if ( !$string1 )
+ return $difference;
+
+ // Return distance per charcter (of string1)
+ return $difference / strlen($string1);
+ }
+
+ /**
+ * @ignore
+ * @since 2.6.0
+ *
+ * @param int $a
+ * @param int $b
+ * @return int
+ */
+ function difference( $a, $b ) {
+ return abs( $a - $b );
+ }
+
+}
+
+/**
+ * Better word splitting than the PEAR package provides.
+ *
+ * @since 2.6.0
+ * @uses Text_Diff_Renderer_inline Extends
+ */
+class WP_Text_Diff_Renderer_inline extends Text_Diff_Renderer_inline {
+
+ /**
+ * @ignore
+ * @since 2.6.0
+ *
+ * @param string $string
+ * @param string $newlineEscape
+ * @return string
+ */
+ function _splitOnWords($string, $newlineEscape = "\n") {
+ $string = str_replace("\0", '', $string);
+ $words = preg_split( '/([^\w])/u', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
+ $words = str_replace( "\n", $newlineEscape, $words );
+ return $words;
+ }
+
+}
diff --git a/src/wp-links-opml.php b/src/wp-links-opml.php
new file mode 100644
index 0000000000..e30869bdc8
--- /dev/null
+++ b/src/wp-links-opml.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Outputs the OPML XML format for getting the links defined in the link
+ * administration. This can be used to export links from one blog over to
+ * another. Links aren't exported by the WordPress export, so this file handles
+ * that.
+ *
+ * This file is not added by default to WordPress theme pages when outputting
+ * feed links. It will have to be added manually for browsers and users to pick
+ * up that this file exists.
+ *
+ * @package WordPress
+ */
+
+require_once('./wp-load.php');
+
+header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
+$link_cat = '';
+if ( !empty($_GET['link_cat']) ) {
+ $link_cat = $_GET['link_cat'];
+ if ( !in_array($link_cat, array('all', '0')) )
+ $link_cat = absint( (string)urldecode($link_cat) );
+}
+
+echo '<?xml version="1.0"?'.">\n";
+?>
+<opml version="1.0">
+ <head>
+ <title><?php printf( __('Links for %s'), esc_attr(get_bloginfo('name', 'display')) ); ?></title>
+ <dateCreated><?php echo gmdate("D, d M Y H:i:s"); ?> GMT</dateCreated>
+ <?php do_action('opml_head'); ?>
+ </head>
+ <body>
+<?php
+if ( empty($link_cat) )
+ $cats = get_categories(array('taxonomy' => 'link_category', 'hierarchical' => 0));
+else
+ $cats = get_categories(array('taxonomy' => 'link_category', 'hierarchical' => 0, 'include' => $link_cat));
+
+foreach ( (array)$cats as $cat ) :
+ $catname = apply_filters('link_category', $cat->name);
+
+?>
+<outline type="category" title="<?php echo esc_attr($catname); ?>">
+<?php
+ $bookmarks = get_bookmarks(array("category" => $cat->term_id));
+ foreach ( (array)$bookmarks as $bookmark ) :
+ $title = apply_filters('link_title', $bookmark->link_name);
+?>
+ <outline text="<?php echo esc_attr($title); ?>" type="link" xmlUrl="<?php echo esc_attr($bookmark->link_rss); ?>" htmlUrl="<?php echo esc_attr($bookmark->link_url); ?>" updated="<?php if ('0000-00-00 00:00:00' != $bookmark->link_updated) echo $bookmark->link_updated; ?>" />
+<?php
+ endforeach; // $bookmarks
+?>
+</outline>
+<?php
+endforeach; // $cats
+?>
+</body>
+</opml> \ No newline at end of file
diff --git a/src/wp-load.php b/src/wp-load.php
new file mode 100644
index 0000000000..983558abd1
--- /dev/null
+++ b/src/wp-load.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Bootstrap file for setting the ABSPATH constant
+ * and loading the wp-config.php file. The wp-config.php
+ * file will then load the wp-settings.php file, which
+ * will then set up the WordPress environment.
+ *
+ * If the wp-config.php file is not found then an error
+ * will be displayed asking the visitor to set up the
+ * wp-config.php file.
+ *
+ * Will also search for wp-config.php in WordPress' parent
+ * directory to allow the WordPress directory to remain
+ * untouched.
+ *
+ * @internal This file must be parsable by PHP4.
+ *
+ * @package WordPress
+ */
+
+/** Define ABSPATH as this file's directory */
+define( 'ABSPATH', dirname(__FILE__) . '/' );
+
+error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
+
+if ( file_exists( ABSPATH . 'wp-config.php') ) {
+
+ /** The config file resides in ABSPATH */
+ require_once( ABSPATH . 'wp-config.php' );
+
+} elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {
+
+ /** The config file resides one level above ABSPATH but is not part of another install */
+ require_once( dirname(ABSPATH) . '/wp-config.php' );
+
+} else {
+
+ // A config file doesn't exist
+
+ // Set a path for the link to the installer
+ if ( strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false )
+ $path = 'setup-config.php';
+ else
+ $path = 'wp-admin/setup-config.php';
+
+ define( 'WPINC', 'wp-includes' );
+ define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
+ require_once( ABSPATH . WPINC . '/load.php' );
+ require_once( ABSPATH . WPINC . '/version.php' );
+
+ wp_check_php_mysql_versions();
+ wp_load_translations_early();
+
+ require_once( ABSPATH . WPINC . '/functions.php' );
+
+ // Die with an error message
+ $die = __( "There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started." ) . '</p>';
+ $die .= '<p>' . __( "Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>." ) . '</p>';
+ $die .= '<p>' . __( "You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file." ) . '</p>';
+ $die .= '<p><a href="' . $path . '" class="button button-large">' . __( "Create a Configuration File" ) . '</a>';
+
+ wp_die( $die, __( 'WordPress &rsaquo; Error' ) );
+}
diff --git a/src/wp-login.php b/src/wp-login.php
new file mode 100644
index 0000000000..532ffd970d
--- /dev/null
+++ b/src/wp-login.php
@@ -0,0 +1,770 @@
+<?php
+/**
+ * WordPress User Page
+ *
+ * Handles authentication, registering, resetting passwords, forgot password,
+ * and other user handling.
+ *
+ * @package WordPress
+ */
+
+/** Make sure that the WordPress bootstrap has run before continuing. */
+require( dirname(__FILE__) . '/wp-load.php' );
+
+// Redirect to https login if forced to use SSL
+if ( force_ssl_admin() && ! is_ssl() ) {
+ if ( 0 === strpos($_SERVER['REQUEST_URI'], 'http') ) {
+ wp_redirect( set_url_scheme( $_SERVER['REQUEST_URI'], 'https' ) );
+ exit();
+ } else {
+ wp_redirect( 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
+ exit();
+ }
+}
+
+/**
+ * Outputs the header for the login page.
+ *
+ * @uses do_action() Calls the 'login_head' for outputting HTML in the Log In
+ * header.
+ * @uses apply_filters() Calls 'login_headerurl' for the top login link.
+ * @uses apply_filters() Calls 'login_headertitle' for the top login title.
+ * @uses apply_filters() Calls 'login_message' on the message to display in the
+ * header.
+ * @uses $error The error global, which is checked for displaying errors.
+ *
+ * @param string $title Optional. WordPress Log In Page title to display in
+ * <title/> element.
+ * @param string $message Optional. Message to display in header.
+ * @param WP_Error $wp_error Optional. WordPress Error Object
+ */
+function login_header($title = 'Log In', $message = '', $wp_error = '') {
+ global $error, $interim_login, $current_site, $action;
+
+ // Don't index any of these forms
+ add_action( 'login_head', 'wp_no_robots' );
+
+ if ( empty($wp_error) )
+ $wp_error = new WP_Error();
+
+ // Shake it!
+ $shake_error_codes = array( 'empty_password', 'empty_email', 'invalid_email', 'invalidcombo', 'empty_username', 'invalid_username', 'incorrect_password' );
+ $shake_error_codes = apply_filters( 'shake_error_codes', $shake_error_codes );
+
+ if ( $shake_error_codes && $wp_error->get_error_code() && in_array( $wp_error->get_error_code(), $shake_error_codes ) )
+ add_action( 'login_head', 'wp_shake_js', 12 );
+
+ ?><!DOCTYPE html>
+ <html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>>
+ <head>
+ <meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />
+ <title><?php bloginfo('name'); ?> &rsaquo; <?php echo $title; ?></title>
+ <?php
+
+ wp_admin_css( 'wp-admin', true );
+ wp_admin_css( 'colors-fresh', true );
+
+ if ( wp_is_mobile() ) { ?>
+ <meta name="viewport" content="width=320, initial-scale=0.9, maximum-scale=1.0, user-scalable=0" /><?php
+ }
+
+ // Remove all stored post data on logging out.
+ // This could be added by add_action('login_head'...) like wp_shake_js()
+ // but maybe better if it's not removable by plugins
+ if ( 'loggedout' == $wp_error->get_error_code() ) {
+ ?>
+ <script>if("sessionStorage" in window){try{for(var key in sessionStorage){if(key.indexOf("wp-autosave-")!=-1){sessionStorage.removeItem(key)}}}catch(e){}};</script>
+ <?php
+ }
+
+ do_action( 'login_enqueue_scripts' );
+ do_action( 'login_head' );
+
+ if ( is_multisite() ) {
+ $login_header_url = network_home_url();
+ $login_header_title = $current_site->site_name;
+ } else {
+ $login_header_url = __( 'http://wordpress.org/' );
+ $login_header_title = __( 'Powered by WordPress' );
+ }
+
+ $login_header_url = apply_filters( 'login_headerurl', $login_header_url );
+ $login_header_title = apply_filters( 'login_headertitle', $login_header_title );
+
+ $classes = array( 'login-action-' . $action, 'wp-core-ui' );
+ if ( wp_is_mobile() )
+ $classes[] = 'mobile';
+ if ( is_rtl() )
+ $classes[] = 'rtl';
+ if ( $interim_login ) {
+ $classes[] = 'interim-login';
+ ?>
+ <style type="text/css">html{background-color: transparent;}</style>
+ <?php
+
+ if ( 'success' === $interim_login )
+ $classes[] = 'interim-login-success';
+ }
+
+ $classes = apply_filters( 'login_body_class', $classes, $action );
+
+ ?>
+ </head>
+ <body class="login <?php echo esc_attr( implode( ' ', $classes ) ); ?>">
+ <div id="login">
+ <h1><a href="<?php echo esc_url( $login_header_url ); ?>" title="<?php echo esc_attr( $login_header_title ); ?>"><?php bloginfo( 'name' ); ?></a></h1>
+ <?php
+
+ unset( $login_header_url, $login_header_title );
+
+ $message = apply_filters('login_message', $message);
+ if ( !empty( $message ) )
+ echo $message . "\n";
+
+ // In case a plugin uses $error rather than the $wp_errors object
+ if ( !empty( $error ) ) {
+ $wp_error->add('error', $error);
+ unset($error);
+ }
+
+ if ( $wp_error->get_error_code() ) {
+ $errors = '';
+ $messages = '';
+ foreach ( $wp_error->get_error_codes() as $code ) {
+ $severity = $wp_error->get_error_data($code);
+ foreach ( $wp_error->get_error_messages($code) as $error ) {
+ if ( 'message' == $severity )
+ $messages .= ' ' . $error . "<br />\n";
+ else
+ $errors .= ' ' . $error . "<br />\n";
+ }
+ }
+ if ( !empty($errors) )
+ echo '<div id="login_error">' . apply_filters('login_errors', $errors) . "</div>\n";
+ if ( !empty($messages) )
+ echo '<p class="message">' . apply_filters('login_messages', $messages) . "</p>\n";
+ }
+} // End of login_header()
+
+/**
+ * Outputs the footer for the login page.
+ *
+ * @param string $input_id Which input to auto-focus
+ */
+function login_footer($input_id = '') {
+ global $interim_login;
+
+ // Don't allow interim logins to navigate away from the page.
+ if ( ! $interim_login ): ?>
+ <p id="backtoblog"><a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php esc_attr_e( 'Are you lost?' ); ?>"><?php printf( __( '&larr; Back to %s' ), get_bloginfo( 'title', 'display' ) ); ?></a></p>
+ <?php endif; ?>
+
+ </div>
+
+ <?php if ( !empty($input_id) ) : ?>
+ <script type="text/javascript">
+ try{document.getElementById('<?php echo $input_id; ?>').focus();}catch(e){}
+ if(typeof wpOnload=='function')wpOnload();
+ </script>
+ <?php endif; ?>
+
+ <?php do_action('login_footer'); ?>
+ <div class="clear"></div>
+ </body>
+ </html>
+ <?php
+}
+
+function wp_shake_js() {
+ if ( wp_is_mobile() )
+ return;
+?>
+<script type="text/javascript">
+addLoadEvent = function(func){if(typeof jQuery!="undefined")jQuery(document).ready(func);else if(typeof wpOnload!='function'){wpOnload=func;}else{var oldonload=wpOnload;wpOnload=function(){oldonload();func();}}};
+function s(id,pos){g(id).left=pos+'px';}
+function g(id){return document.getElementById(id).style;}
+function shake(id,a,d){c=a.shift();s(id,c);if(a.length>0){setTimeout(function(){shake(id,a,d);},d);}else{try{g(id).position='static';wp_attempt_focus();}catch(e){}}}
+addLoadEvent(function(){ var p=new Array(15,30,15,0,-15,-30,-15,0);p=p.concat(p.concat(p));var i=document.forms[0].id;g(i).position='relative';shake(i,p,20);});
+</script>
+<?php
+}
+
+/**
+ * Handles sending password retrieval email to user.
+ *
+ * @uses $wpdb WordPress Database object
+ *
+ * @return bool|WP_Error True: when finish. WP_Error on error
+ */
+function retrieve_password() {
+ global $wpdb, $current_site;
+
+ $errors = new WP_Error();
+
+ if ( empty( $_POST['user_login'] ) ) {
+ $errors->add('empty_username', __('<strong>ERROR</strong>: Enter a username or e-mail address.'));
+ } else if ( strpos( $_POST['user_login'], '@' ) ) {
+ $user_data = get_user_by( 'email', trim( $_POST['user_login'] ) );
+ if ( empty( $user_data ) )
+ $errors->add('invalid_email', __('<strong>ERROR</strong>: There is no user registered with that email address.'));
+ } else {
+ $login = trim($_POST['user_login']);
+ $user_data = get_user_by('login', $login);
+ }
+
+ do_action('lostpassword_post');
+
+ if ( $errors->get_error_code() )
+ return $errors;
+
+ if ( !$user_data ) {
+ $errors->add('invalidcombo', __('<strong>ERROR</strong>: Invalid username or e-mail.'));
+ return $errors;
+ }
+
+ // redefining user_login ensures we return the right case in the email
+ $user_login = $user_data->user_login;
+ $user_email = $user_data->user_email;
+
+ do_action('retreive_password', $user_login); // Misspelled and deprecated
+ do_action('retrieve_password', $user_login);
+
+ $allow = apply_filters('allow_password_reset', true, $user_data->ID);
+
+ if ( ! $allow )
+ return new WP_Error('no_password_reset', __('Password reset is not allowed for this user'));
+ else if ( is_wp_error($allow) )
+ return $allow;
+
+ $key = $wpdb->get_var($wpdb->prepare("SELECT user_activation_key FROM $wpdb->users WHERE user_login = %s", $user_login));
+ if ( empty($key) ) {
+ // Generate something random for a key...
+ $key = wp_generate_password(20, false);
+ do_action('retrieve_password_key', $user_login, $key);
+ // Now insert the new md5 key into the db
+ $wpdb->update($wpdb->users, array('user_activation_key' => $key), array('user_login' => $user_login));
+ }
+ $message = __('Someone requested that the password be reset for the following account:') . "\r\n\r\n";
+ $message .= network_home_url( '/' ) . "\r\n\r\n";
+ $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
+ $message .= __('If this was a mistake, just ignore this email and nothing will happen.') . "\r\n\r\n";
+ $message .= __('To reset your password, visit the following address:') . "\r\n\r\n";
+ $message .= '<' . network_site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user_login), 'login') . ">\r\n";
+
+ if ( is_multisite() )
+ $blogname = $GLOBALS['current_site']->site_name;
+ else
+ // The blogname option is escaped with esc_html on the way into the database in sanitize_option
+ // we want to reverse this for the plain text arena of emails.
+ $blogname = wp_specialchars_decode(get_option('blogname'), ENT_QUOTES);
+
+ $title = sprintf( __('[%s] Password Reset'), $blogname );
+
+ $title = apply_filters('retrieve_password_title', $title);
+ $message = apply_filters('retrieve_password_message', $message, $key);
+
+ if ( $message && !wp_mail($user_email, $title, $message) )
+ wp_die( __('The e-mail could not be sent.') . "<br />\n" . __('Possible reason: your host may have disabled the mail() function.') );
+
+ return true;
+}
+
+/**
+ * Retrieves a user row based on password reset key and login
+ *
+ * @uses $wpdb WordPress Database object
+ *
+ * @param string $key Hash to validate sending user's password
+ * @param string $login The user login
+ * @return object|WP_Error User's database row on success, error object for invalid keys
+ */
+function check_password_reset_key($key, $login) {
+ global $wpdb;
+
+ $key = preg_replace('/[^a-z0-9]/i', '', $key);
+
+ if ( empty( $key ) || !is_string( $key ) )
+ return new WP_Error('invalid_key', __('Invalid key'));
+
+ if ( empty($login) || !is_string($login) )
+ return new WP_Error('invalid_key', __('Invalid key'));
+
+ $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s AND user_login = %s", $key, $login));
+
+ if ( empty( $user ) )
+ return new WP_Error('invalid_key', __('Invalid key'));
+
+ return $user;
+}
+
+/**
+ * Handles resetting the user's password.
+ *
+ * @param object $user The user
+ * @param string $new_pass New password for the user in plaintext
+ */
+function reset_password($user, $new_pass) {
+ do_action('password_reset', $user, $new_pass);
+
+ wp_set_password($new_pass, $user->ID);
+
+ wp_password_change_notification($user);
+}
+
+/**
+ * Handles registering a new user.
+ *
+ * @param string $user_login User's username for logging in
+ * @param string $user_email User's email address to send password and add
+ * @return int|WP_Error Either user's ID or error on failure.
+ */
+function register_new_user( $user_login, $user_email ) {
+ $errors = new WP_Error();
+
+ $sanitized_user_login = sanitize_user( $user_login );
+ $user_email = apply_filters( 'user_registration_email', $user_email );
+
+ // Check the username
+ if ( $sanitized_user_login == '' ) {
+ $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
+ } elseif ( ! validate_username( $user_login ) ) {
+ $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
+ $sanitized_user_login = '';
+ } elseif ( username_exists( $sanitized_user_login ) ) {
+ $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
+ }
+
+ // Check the e-mail address
+ if ( $user_email == '' ) {
+ $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your e-mail address.' ) );
+ } elseif ( ! is_email( $user_email ) ) {
+ $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
+ $user_email = '';
+ } elseif ( email_exists( $user_email ) ) {
+ $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
+ }
+
+ do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
+
+ $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
+
+ if ( $errors->get_error_code() )
+ return $errors;
+
+ $user_pass = wp_generate_password( 12, false);
+ $user_id = wp_create_user( $sanitized_user_login, $user_pass, $user_email );
+ if ( ! $user_id ) {
+ $errors->add( 'registerfail', sprintf( __( '<strong>ERROR</strong>: Couldn&#8217;t register you&hellip; please contact the <a href="mailto:%s">webmaster</a> !' ), get_option( 'admin_email' ) ) );
+ return $errors;
+ }
+
+ update_user_option( $user_id, 'default_password_nag', true, true ); //Set up the Password change nag.
+
+ wp_new_user_notification( $user_id, $user_pass );
+
+ return $user_id;
+}
+
+//
+// Main
+//
+
+$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login';
+$errors = new WP_Error();
+
+if ( isset($_GET['key']) )
+ $action = 'resetpass';
+
+// validate action so as to default to the login screen
+if ( !in_array( $action, array( 'postpass', 'logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login' ), true ) && false === has_filter( 'login_form_' . $action ) )
+ $action = 'login';
+
+nocache_headers();
+
+header('Content-Type: '.get_bloginfo('html_type').'; charset='.get_bloginfo('charset'));
+
+if ( defined( 'RELOCATE' ) && RELOCATE ) { // Move flag is set
+ if ( isset( $_SERVER['PATH_INFO'] ) && ($_SERVER['PATH_INFO'] != $_SERVER['PHP_SELF']) )
+ $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] );
+
+ $url = dirname( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'] ) );
+ if ( $url != get_option( 'siteurl' ) )
+ update_option( 'siteurl', $url );
+}
+
+//Set a cookie now to see if they are supported by the browser.
+setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN);
+if ( SITECOOKIEPATH != COOKIEPATH )
+ setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN);
+
+// allow plugins to override the default actions, and to add extra actions if they want
+do_action( 'login_init' );
+do_action( 'login_form_' . $action );
+
+$http_post = ('POST' == $_SERVER['REQUEST_METHOD']);
+$interim_login = isset($_REQUEST['interim-login']);
+
+switch ($action) {
+
+case 'postpass' :
+ require_once ABSPATH . 'wp-includes/class-phpass.php';
+ $hasher = new PasswordHash( 8, true );
+
+ // 10 days
+ setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), time() + 10 * DAY_IN_SECONDS, COOKIEPATH );
+
+ wp_safe_redirect( wp_get_referer() );
+ exit();
+
+break;
+
+case 'logout' :
+ check_admin_referer('log-out');
+ wp_logout();
+
+ $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?loggedout=true';
+ wp_safe_redirect( $redirect_to );
+ exit();
+
+break;
+
+case 'lostpassword' :
+case 'retrievepassword' :
+
+ if ( $http_post ) {
+ $errors = retrieve_password();
+ if ( !is_wp_error($errors) ) {
+ $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm';
+ wp_safe_redirect( $redirect_to );
+ exit();
+ }
+ }
+
+ if ( isset($_GET['error']) && 'invalidkey' == $_GET['error'] ) $errors->add('invalidkey', __('Sorry, that key does not appear to be valid.'));
+ $redirect_to = apply_filters( 'lostpassword_redirect', !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '' );
+
+ do_action('lost_password');
+ login_header(__('Lost Password'), '<p class="message">' . __('Please enter your username or email address. You will receive a link to create a new password via email.') . '</p>', $errors);
+
+ $user_login = isset($_POST['user_login']) ? wp_unslash($_POST['user_login']) : '';
+
+?>
+
+<form name="lostpasswordform" id="lostpasswordform" action="<?php echo esc_url( site_url( 'wp-login.php?action=lostpassword', 'login_post' ) ); ?>" method="post">
+ <p>
+ <label for="user_login" ><?php _e('Username or E-mail:') ?><br />
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" /></label>
+ </p>
+<?php do_action('lostpassword_form'); ?>
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
+ <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Get New Password'); ?>" /></p>
+</form>
+
+<p id="nav">
+<a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e('Log in') ?></a>
+<?php if ( get_option( 'users_can_register' ) ) : ?>
+ | <?php echo apply_filters( 'register', sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) ) ); ?>
+<?php endif; ?>
+</p>
+
+<?php
+login_footer('user_login');
+break;
+
+case 'resetpass' :
+case 'rp' :
+ $user = check_password_reset_key($_GET['key'], $_GET['login']);
+
+ if ( is_wp_error($user) ) {
+ wp_redirect( site_url('wp-login.php?action=lostpassword&error=invalidkey') );
+ exit;
+ }
+
+ $errors = new WP_Error();
+
+ if ( isset($_POST['pass1']) && $_POST['pass1'] != $_POST['pass2'] )
+ $errors->add( 'password_reset_mismatch', __( 'The passwords do not match.' ) );
+
+ do_action( 'validate_password_reset', $errors, $user );
+
+ if ( ( ! $errors->get_error_code() ) && isset( $_POST['pass1'] ) && !empty( $_POST['pass1'] ) ) {
+ reset_password($user, $_POST['pass1']);
+ login_header( __( 'Password Reset' ), '<p class="message reset-pass">' . __( 'Your password has been reset.' ) . ' <a href="' . esc_url( wp_login_url() ) . '">' . __( 'Log in' ) . '</a></p>' );
+ login_footer();
+ exit;
+ }
+
+ wp_enqueue_script('utils');
+ wp_enqueue_script('user-profile');
+
+ login_header(__('Reset Password'), '<p class="message reset-pass">' . __('Enter your new password below.') . '</p>', $errors );
+
+?>
+<form name="resetpassform" id="resetpassform" action="<?php echo esc_url( site_url( 'wp-login.php?action=resetpass&key=' . urlencode( $_GET['key'] ) . '&login=' . urlencode( $_GET['login'] ), 'login_post' ) ); ?>" method="post" autocomplete="off">
+ <input type="hidden" id="user_login" value="<?php echo esc_attr( $_GET['login'] ); ?>" autocomplete="off" />
+
+ <p>
+ <label for="pass1"><?php _e('New password') ?><br />
+ <input type="password" name="pass1" id="pass1" class="input" size="20" value="" autocomplete="off" /></label>
+ </p>
+ <p>
+ <label for="pass2"><?php _e('Confirm new password') ?><br />
+ <input type="password" name="pass2" id="pass2" class="input" size="20" value="" autocomplete="off" /></label>
+ </p>
+
+ <div id="pass-strength-result" class="hide-if-no-js"><?php _e('Strength indicator'); ?></div>
+ <p class="description indicator-hint"><?php _e('Hint: The password should be at least seven characters long. To make it stronger, use upper and lower case letters, numbers and symbols like ! " ? $ % ^ &amp; ).'); ?></p>
+
+ <br class="clear" />
+ <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Reset Password'); ?>" /></p>
+</form>
+
+<p id="nav">
+<a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a>
+<?php if ( get_option( 'users_can_register' ) ) : ?>
+ | <?php echo apply_filters( 'register', sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) ) ); ?>
+<?php endif; ?>
+</p>
+
+<?php
+login_footer('user_pass');
+break;
+
+case 'register' :
+ if ( is_multisite() ) {
+ // Multisite uses wp-signup.php
+ wp_redirect( apply_filters( 'wp_signup_location', network_site_url('wp-signup.php') ) );
+ exit;
+ }
+
+ if ( !get_option('users_can_register') ) {
+ wp_redirect( site_url('wp-login.php?registration=disabled') );
+ exit();
+ }
+
+ $user_login = '';
+ $user_email = '';
+ if ( $http_post ) {
+ $user_login = $_POST['user_login'];
+ $user_email = $_POST['user_email'];
+ $errors = register_new_user($user_login, $user_email);
+ if ( !is_wp_error($errors) ) {
+ $redirect_to = !empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered';
+ wp_safe_redirect( $redirect_to );
+ exit();
+ }
+ }
+
+ $redirect_to = apply_filters( 'registration_redirect', !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '' );
+ login_header(__('Registration Form'), '<p class="message register">' . __('Register For This Site') . '</p>', $errors);
+?>
+
+<form name="registerform" id="registerform" action="<?php echo esc_url( site_url('wp-login.php?action=register', 'login_post') ); ?>" method="post">
+ <p>
+ <label for="user_login"><?php _e('Username') ?><br />
+ <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr(wp_unslash($user_login)); ?>" size="20" /></label>
+ </p>
+ <p>
+ <label for="user_email"><?php _e('E-mail') ?><br />
+ <input type="text" name="user_email" id="user_email" class="input" value="<?php echo esc_attr(wp_unslash($user_email)); ?>" size="25" /></label>
+ </p>
+<?php do_action('register_form'); ?>
+ <p id="reg_passmail"><?php _e('A password will be e-mailed to you.') ?></p>
+ <br class="clear" />
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" />
+ <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Register'); ?>" /></p>
+</form>
+
+<p id="nav">
+<a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log in' ); ?></a> |
+<a href="<?php echo esc_url( wp_lostpassword_url() ); ?>" title="<?php esc_attr_e( 'Password Lost and Found' ) ?>"><?php _e( 'Lost your password?' ); ?></a>
+</p>
+
+<?php
+login_footer('user_login');
+break;
+
+case 'login' :
+default:
+ $secure_cookie = '';
+ $customize_login = isset( $_REQUEST['customize-login'] );
+ if ( $customize_login )
+ wp_enqueue_script( 'customize-base' );
+
+ // If the user wants ssl but the session is not ssl, force a secure cookie.
+ if ( !empty($_POST['log']) && !force_ssl_admin() ) {
+ $user_name = sanitize_user($_POST['log']);
+ if ( $user = get_user_by('login', $user_name) ) {
+ if ( get_user_option('use_ssl', $user->ID) ) {
+ $secure_cookie = true;
+ force_ssl_admin(true);
+ }
+ }
+ }
+
+ if ( isset( $_REQUEST['redirect_to'] ) ) {
+ $redirect_to = $_REQUEST['redirect_to'];
+ // Redirect to https if user wants ssl
+ if ( $secure_cookie && false !== strpos($redirect_to, 'wp-admin') )
+ $redirect_to = preg_replace('|^http://|', 'https://', $redirect_to);
+ } else {
+ $redirect_to = admin_url();
+ }
+
+ $reauth = empty($_REQUEST['reauth']) ? false : true;
+
+ // If the user was redirected to a secure login form from a non-secure admin page, and secure login is required but secure admin is not, then don't use a secure
+ // cookie and redirect back to the referring non-secure admin page. This allows logins to always be POSTed over SSL while allowing the user to choose visiting
+ // the admin via http or https.
+ if ( !$secure_cookie && is_ssl() && force_ssl_login() && !force_ssl_admin() && ( 0 !== strpos($redirect_to, 'https') ) && ( 0 === strpos($redirect_to, 'http') ) )
+ $secure_cookie = false;
+
+ $user = wp_signon('', $secure_cookie);
+
+ $redirect_to = apply_filters('login_redirect', $redirect_to, isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '', $user);
+
+ if ( !is_wp_error($user) && !$reauth ) {
+ if ( $interim_login ) {
+ $message = '<p class="message">' . __('You have logged in successfully.') . '</p>';
+ $interim_login = 'success';
+ login_header( '', $message ); ?>
+ </div>
+ <?php do_action( 'login_footer' ); ?>
+ <?php if ( $customize_login ) : ?>
+ <script type="text/javascript">setTimeout( function(){ new wp.customize.Messenger({ url: '<?php echo wp_customize_url(); ?>', channel: 'login' }).send('login') }, 1000 );</script>
+ <?php endif; ?>
+ </body></html>
+<?php exit;
+ }
+
+ if ( ( empty( $redirect_to ) || $redirect_to == 'wp-admin/' || $redirect_to == admin_url() ) ) {
+ // If the user doesn't belong to a blog, send them to user admin. If the user can't edit posts, send them to their profile.
+ if ( is_multisite() && !get_active_blog_for_user($user->ID) && !is_super_admin( $user->ID ) )
+ $redirect_to = user_admin_url();
+ elseif ( is_multisite() && !$user->has_cap('read') )
+ $redirect_to = get_dashboard_url( $user->ID );
+ elseif ( !$user->has_cap('edit_posts') )
+ $redirect_to = admin_url('profile.php');
+ }
+ wp_safe_redirect($redirect_to);
+ exit();
+ }
+
+ $errors = $user;
+ // Clear errors if loggedout is set.
+ if ( !empty($_GET['loggedout']) || $reauth )
+ $errors = new WP_Error();
+
+ // If cookies are disabled we can't log in even with a valid user+pass
+ if ( isset($_POST['testcookie']) && empty($_COOKIE[TEST_COOKIE]) )
+ $errors->add('test_cookie', __("<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href='http://www.google.com/cookies.html'>enable cookies</a> to use WordPress."));
+
+ if ( $interim_login ) {
+ if ( ! $errors->get_error_code() )
+ $errors->add('expired', __('Session expired. Please log in again. You will not move away from this page.'), 'message');
+ } else {
+ // Some parts of this script use the main login form to display a message
+ if ( isset($_GET['loggedout']) && true == $_GET['loggedout'] )
+ $errors->add('loggedout', __('You are now logged out.'), 'message');
+ elseif ( isset($_GET['registration']) && 'disabled' == $_GET['registration'] )
+ $errors->add('registerdisabled', __('User registration is currently not allowed.'));
+ elseif ( isset($_GET['checkemail']) && 'confirm' == $_GET['checkemail'] )
+ $errors->add('confirm', __('Check your e-mail for the confirmation link.'), 'message');
+ elseif ( isset($_GET['checkemail']) && 'newpass' == $_GET['checkemail'] )
+ $errors->add('newpass', __('Check your e-mail for your new password.'), 'message');
+ elseif ( isset($_GET['checkemail']) && 'registered' == $_GET['checkemail'] )
+ $errors->add('registered', __('Registration complete. Please check your e-mail.'), 'message');
+ elseif ( strpos( $redirect_to, 'about.php?updated' ) )
+ $errors->add('updated', __( '<strong>You have successfully updated WordPress!</strong> Please log back in to experience the awesomeness.' ), 'message' );
+ }
+
+ $errors = apply_filters( 'wp_login_errors', $errors, $redirect_to );
+
+ // Clear any stale cookies.
+ if ( $reauth )
+ wp_clear_auth_cookie();
+
+ login_header(__('Log In'), '', $errors);
+
+ if ( isset($_POST['log']) )
+ $user_login = ( 'incorrect_password' == $errors->get_error_code() || 'empty_password' == $errors->get_error_code() ) ? esc_attr(wp_unslash($_POST['log'])) : '';
+ $rememberme = ! empty( $_POST['rememberme'] );
+?>
+
+<form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ); ?>" method="post">
+ <p>
+ <label for="user_login"><?php _e('Username') ?><br />
+ <input type="text" name="log" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" /></label>
+ </p>
+ <p>
+ <label for="user_pass"><?php _e('Password') ?><br />
+ <input type="password" name="pwd" id="user_pass" class="input" value="" size="20" /></label>
+ </p>
+<?php do_action('login_form'); ?>
+ <p class="forgetmenot"><label for="rememberme"><input name="rememberme" type="checkbox" id="rememberme" value="forever" <?php checked( $rememberme ); ?> /> <?php esc_attr_e('Remember Me'); ?></label></p>
+ <p class="submit">
+ <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="<?php esc_attr_e('Log In'); ?>" />
+<?php if ( $interim_login ) { ?>
+ <input type="hidden" name="interim-login" value="1" />
+<?php } else { ?>
+ <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" />
+<?php } ?>
+<?php if ( $customize_login ) : ?>
+ <input type="hidden" name="customize-login" value="1" />
+<?php endif; ?>
+ <input type="hidden" name="testcookie" value="1" />
+ </p>
+</form>
+
+<?php if ( ! $interim_login ) { ?>
+<p id="nav">
+<?php if ( ! isset( $_GET['checkemail'] ) || ! in_array( $_GET['checkemail'], array( 'confirm', 'newpass' ) ) ) : ?>
+ <?php if ( get_option( 'users_can_register' ) ) : ?>
+ <?php echo apply_filters( 'register', sprintf( '<a href="%s">%s</a>', esc_url( wp_registration_url() ), __( 'Register' ) ) ); ?> |
+ <?php endif; ?>
+ <a href="<?php echo esc_url( wp_lostpassword_url() ); ?>" title="<?php esc_attr_e( 'Password Lost and Found' ); ?>"><?php _e( 'Lost your password?' ); ?></a>
+<?php endif; ?>
+</p>
+<?php } ?>
+
+<script type="text/javascript">
+function wp_attempt_focus(){
+setTimeout( function(){ try{
+<?php if ( $user_login || $interim_login ) { ?>
+d = document.getElementById('user_pass');
+d.value = '';
+<?php } else { ?>
+d = document.getElementById('user_login');
+<?php if ( 'invalid_username' == $errors->get_error_code() ) { ?>
+if( d.value != '' )
+d.value = '';
+<?php
+}
+}?>
+d.focus();
+d.select();
+} catch(e){}
+}, 200);
+}
+
+<?php if ( !$error ) { ?>
+wp_attempt_focus();
+<?php } ?>
+if(typeof wpOnload=='function')wpOnload();
+<?php if ( $interim_login ) { ?>
+(function(){
+try {
+ var i, links = document.getElementsByTagName('a');
+ for ( i in links ) {
+ if ( links[i].href )
+ links[i].target = '_blank';
+ }
+} catch(e){}
+}());
+<?php } ?>
+</script>
+
+<?php
+login_footer();
+break;
+} // end action switch
diff --git a/src/wp-mail.php b/src/wp-mail.php
new file mode 100644
index 0000000000..27290b1115
--- /dev/null
+++ b/src/wp-mail.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * Gets the email message from the user's mailbox to add as
+ * a WordPress post. Mailbox connection information must be
+ * configured under Settings > Writing
+ *
+ * @package WordPress
+ */
+
+/** Make sure that the WordPress bootstrap has run before continuing. */
+require(dirname(__FILE__) . '/wp-load.php');
+
+if ( ! apply_filters( 'enable_post_by_email_configuration', true ) )
+ wp_die( __( 'This action has been disabled by the administrator.' ) );
+
+/** Allow a plugin to do a complete takeover of Post by Email **/
+do_action('wp-mail.php');
+
+/** Get the POP3 class with which to access the mailbox. */
+require_once( ABSPATH . WPINC . '/class-pop3.php' );
+
+/** Only check at this interval for new messages. */
+if ( !defined('WP_MAIL_INTERVAL') )
+ define('WP_MAIL_INTERVAL', 300); // 5 minutes
+
+$last_checked = get_transient('mailserver_last_checked');
+
+if ( $last_checked )
+ wp_die(__('Slow down cowboy, no need to check for new mails so often!'));
+
+set_transient('mailserver_last_checked', true, WP_MAIL_INTERVAL);
+
+$time_difference = get_option('gmt_offset') * HOUR_IN_SECONDS;
+
+$phone_delim = '::';
+
+$pop3 = new POP3();
+
+if ( !$pop3->connect( get_option('mailserver_url'), get_option('mailserver_port') ) || !$pop3->user( get_option('mailserver_login') ) )
+ wp_die( esc_html( $pop3->ERROR ) );
+
+$count = $pop3->pass( get_option('mailserver_pass') );
+
+if( false === $count )
+ wp_die( esc_html( $pop3->ERROR ) );
+
+if( 0 === $count ) {
+ $pop3->quit();
+ wp_die( __('There doesn&#8217;t seem to be any new mail.') );
+}
+
+for ( $i = 1; $i <= $count; $i++ ) {
+
+ $message = $pop3->get($i);
+
+ $bodysignal = false;
+ $boundary = '';
+ $charset = '';
+ $content = '';
+ $content_type = '';
+ $content_transfer_encoding = '';
+ $post_author = 1;
+ $author_found = false;
+ $dmonths = array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
+ foreach ($message as $line) {
+ // body signal
+ if ( strlen($line) < 3 )
+ $bodysignal = true;
+ if ( $bodysignal ) {
+ $content .= $line;
+ } else {
+ if ( preg_match('/Content-Type: /i', $line) ) {
+ $content_type = trim($line);
+ $content_type = substr($content_type, 14, strlen($content_type) - 14);
+ $content_type = explode(';', $content_type);
+ if ( ! empty( $content_type[1] ) ) {
+ $charset = explode('=', $content_type[1]);
+ $charset = ( ! empty( $charset[1] ) ) ? trim($charset[1]) : '';
+ }
+ $content_type = $content_type[0];
+ }
+ if ( preg_match('/Content-Transfer-Encoding: /i', $line) ) {
+ $content_transfer_encoding = trim($line);
+ $content_transfer_encoding = substr($content_transfer_encoding, 27, strlen($content_transfer_encoding) - 27);
+ $content_transfer_encoding = explode(';', $content_transfer_encoding);
+ $content_transfer_encoding = $content_transfer_encoding[0];
+ }
+ if ( ( $content_type == 'multipart/alternative' ) && ( false !== strpos($line, 'boundary="') ) && ( '' == $boundary ) ) {
+ $boundary = trim($line);
+ $boundary = explode('"', $boundary);
+ $boundary = $boundary[1];
+ }
+ if (preg_match('/Subject: /i', $line)) {
+ $subject = trim($line);
+ $subject = substr($subject, 9, strlen($subject) - 9);
+ // Captures any text in the subject before $phone_delim as the subject
+ if ( function_exists('iconv_mime_decode') ) {
+ $subject = iconv_mime_decode($subject, 2, get_option('blog_charset'));
+ } else {
+ $subject = wp_iso_descrambler($subject);
+ }
+ $subject = explode($phone_delim, $subject);
+ $subject = $subject[0];
+ }
+
+ // Set the author using the email address (From or Reply-To, the last used)
+ // otherwise use the site admin
+ if ( ! $author_found && preg_match( '/^(From|Reply-To): /', $line ) ) {
+ if ( preg_match('|[a-z0-9_.-]+@[a-z0-9_.-]+(?!.*<)|i', $line, $matches) )
+ $author = $matches[0];
+ else
+ $author = trim($line);
+ $author = sanitize_email($author);
+ if ( is_email($author) ) {
+ echo '<p>' . sprintf(__('Author is %s'), $author) . '</p>';
+ $userdata = get_user_by('email', $author);
+ if ( ! empty( $userdata ) ) {
+ $post_author = $userdata->ID;
+ $author_found = true;
+ }
+ }
+ }
+
+ if (preg_match('/Date: /i', $line)) { // of the form '20 Mar 2002 20:32:37'
+ $ddate = trim($line);
+ $ddate = str_replace('Date: ', '', $ddate);
+ if (strpos($ddate, ',')) {
+ $ddate = trim(substr($ddate, strpos($ddate, ',') + 1, strlen($ddate)));
+ }
+ $date_arr = explode(' ', $ddate);
+ $date_time = explode(':', $date_arr[3]);
+
+ $ddate_H = $date_time[0];
+ $ddate_i = $date_time[1];
+ $ddate_s = $date_time[2];
+
+ $ddate_m = $date_arr[1];
+ $ddate_d = $date_arr[0];
+ $ddate_Y = $date_arr[2];
+ for ( $j = 0; $j < 12; $j++ ) {
+ if ( $ddate_m == $dmonths[$j] ) {
+ $ddate_m = $j+1;
+ }
+ }
+
+ $time_zn = intval($date_arr[4]) * 36;
+ $ddate_U = gmmktime($ddate_H, $ddate_i, $ddate_s, $ddate_m, $ddate_d, $ddate_Y);
+ $ddate_U = $ddate_U - $time_zn;
+ $post_date = gmdate('Y-m-d H:i:s', $ddate_U + $time_difference);
+ $post_date_gmt = gmdate('Y-m-d H:i:s', $ddate_U);
+ }
+ }
+ }
+
+ // Set $post_status based on $author_found and on author's publish_posts capability
+ if ( $author_found ) {
+ $user = new WP_User($post_author);
+ $post_status = ( $user->has_cap('publish_posts') ) ? 'publish' : 'pending';
+ } else {
+ // Author not found in DB, set status to pending. Author already set to admin.
+ $post_status = 'pending';
+ }
+
+ $subject = trim($subject);
+
+ if ( $content_type == 'multipart/alternative' ) {
+ $content = explode('--'.$boundary, $content);
+ $content = $content[2];
+ // match case-insensitive content-transfer-encoding
+ if ( preg_match( '/Content-Transfer-Encoding: quoted-printable/i', $content, $delim) ) {
+ $content = explode($delim[0], $content);
+ $content = $content[1];
+ }
+ $content = strip_tags($content, '<img><p><br><i><b><u><em><strong><strike><font><span><div>');
+ }
+ $content = trim($content);
+
+ //Give Post-By-Email extending plugins full access to the content
+ //Either the raw content or the content of the last quoted-printable section
+ $content = apply_filters('wp_mail_original_content', $content);
+
+ if ( false !== stripos($content_transfer_encoding, "quoted-printable") ) {
+ $content = quoted_printable_decode($content);
+ }
+
+ if ( function_exists('iconv') && ! empty( $charset ) ) {
+ $content = iconv($charset, get_option('blog_charset'), $content);
+ }
+
+ // Captures any text in the body after $phone_delim as the body
+ $content = explode($phone_delim, $content);
+ $content = empty( $content[1] ) ? $content[0] : $content[1];
+
+ $content = trim($content);
+
+ $post_content = apply_filters('phone_content', $content);
+
+ $post_title = xmlrpc_getposttitle($content);
+
+ if ($post_title == '') $post_title = $subject;
+
+ $post_category = array(get_option('default_email_category'));
+
+ $post_data = compact('post_content','post_title','post_date','post_date_gmt','post_author','post_category', 'post_status');
+ $post_data = wp_slash($post_data);
+
+ $post_ID = wp_insert_post($post_data);
+ if ( is_wp_error( $post_ID ) )
+ echo "\n" . $post_ID->get_error_message();
+
+ // We couldn't post, for whatever reason. Better move forward to the next email.
+ if ( empty( $post_ID ) )
+ continue;
+
+ do_action('publish_phone', $post_ID);
+
+ echo "\n<p>" . sprintf(__('<strong>Author:</strong> %s'), esc_html($post_author)) . '</p>';
+ echo "\n<p>" . sprintf(__('<strong>Posted title:</strong> %s'), esc_html($post_title)) . '</p>';
+
+ if(!$pop3->delete($i)) {
+ echo '<p>' . sprintf(__('Oops: %s'), esc_html($pop3->ERROR)) . '</p>';
+ $pop3->reset();
+ exit;
+ } else {
+ echo '<p>' . sprintf(__('Mission complete. Message <strong>%s</strong> deleted.'), $i) . '</p>';
+ }
+
+}
+
+$pop3->quit();
diff --git a/src/wp-settings.php b/src/wp-settings.php
new file mode 100644
index 0000000000..1094749e35
--- /dev/null
+++ b/src/wp-settings.php
@@ -0,0 +1,329 @@
+<?php
+/**
+ * Used to set up and fix common variables and include
+ * the WordPress procedural and class library.
+ *
+ * Allows for some configuration in wp-config.php (see default-constants.php)
+ *
+ * @internal This file must be parsable by PHP4.
+ *
+ * @package WordPress
+ */
+
+/**
+ * Stores the location of the WordPress directory of functions, classes, and core content.
+ *
+ * @since 1.0.0
+ */
+define( 'WPINC', 'wp-includes' );
+
+// Include files required for initialization.
+require( ABSPATH . WPINC . '/load.php' );
+require( ABSPATH . WPINC . '/default-constants.php' );
+require( ABSPATH . WPINC . '/version.php' );
+
+// Set initial default constants including WP_MEMORY_LIMIT, WP_MAX_MEMORY_LIMIT, WP_DEBUG, WP_CONTENT_DIR and WP_CACHE.
+wp_initial_constants();
+
+// Check for the required PHP version and for the MySQL extension or a database drop-in.
+wp_check_php_mysql_versions();
+
+// Disable magic quotes at runtime. Magic quotes are added using wpdb later in wp-settings.php.
+@ini_set( 'magic_quotes_runtime', 0 );
+@ini_set( 'magic_quotes_sybase', 0 );
+
+// WordPress calculates offsets from UTC.
+date_default_timezone_set( 'UTC' );
+
+// Turn register_globals off.
+wp_unregister_GLOBALS();
+
+// Standardize $_SERVER variables across setups.
+wp_fix_server_vars();
+
+// Check if we have received a request due to missing favicon.ico
+wp_favicon_request();
+
+// Check if we're in maintenance mode.
+wp_maintenance();
+
+// Start loading timer.
+timer_start();
+
+// Check if we're in WP_DEBUG mode.
+wp_debug_mode();
+
+// For an advanced caching plugin to use. Uses a static drop-in because you would only want one.
+if ( WP_CACHE )
+ WP_DEBUG ? include( WP_CONTENT_DIR . '/advanced-cache.php' ) : @include( WP_CONTENT_DIR . '/advanced-cache.php' );
+
+// Define WP_LANG_DIR if not set.
+wp_set_lang_dir();
+
+// Load early WordPress files.
+require( ABSPATH . WPINC . '/compat.php' );
+require( ABSPATH . WPINC . '/functions.php' );
+require( ABSPATH . WPINC . '/class-wp.php' );
+require( ABSPATH . WPINC . '/class-wp-error.php' );
+require( ABSPATH . WPINC . '/plugin.php' );
+require( ABSPATH . WPINC . '/pomo/mo.php' );
+
+// Include the wpdb class and, if present, a db.php database drop-in.
+require_wp_db();
+
+// Set the database table prefix and the format specifiers for database table columns.
+$GLOBALS['table_prefix'] = $table_prefix;
+wp_set_wpdb_vars();
+
+// Start the WordPress object cache, or an external object cache if the drop-in is present.
+wp_start_object_cache();
+
+// Attach the default filters.
+require( ABSPATH . WPINC . '/default-filters.php' );
+
+// Initialize multisite if enabled.
+if ( is_multisite() ) {
+ require( ABSPATH . WPINC . '/ms-blogs.php' );
+ require( ABSPATH . WPINC . '/ms-settings.php' );
+} elseif ( ! defined( 'MULTISITE' ) ) {
+ define( 'MULTISITE', false );
+}
+
+register_shutdown_function( 'shutdown_action_hook' );
+
+// Stop most of WordPress from being loaded if we just want the basics.
+if ( SHORTINIT )
+ return false;
+
+// Load the L10n library.
+require_once( ABSPATH . WPINC . '/l10n.php' );
+
+// Run the installer if WordPress is not installed.
+wp_not_installed();
+
+// Load most of WordPress.
+require( ABSPATH . WPINC . '/class-wp-walker.php' );
+require( ABSPATH . WPINC . '/class-wp-ajax-response.php' );
+require( ABSPATH . WPINC . '/formatting.php' );
+require( ABSPATH . WPINC . '/capabilities.php' );
+require( ABSPATH . WPINC . '/query.php' );
+require( ABSPATH . WPINC . '/theme.php' );
+require( ABSPATH . WPINC . '/class-wp-theme.php' );
+require( ABSPATH . WPINC . '/template.php' );
+require( ABSPATH . WPINC . '/user.php' );
+require( ABSPATH . WPINC . '/meta.php' );
+require( ABSPATH . WPINC . '/general-template.php' );
+require( ABSPATH . WPINC . '/link-template.php' );
+require( ABSPATH . WPINC . '/author-template.php' );
+require( ABSPATH . WPINC . '/post.php' );
+require( ABSPATH . WPINC . '/post-template.php' );
+require( ABSPATH . WPINC . '/revision.php' );
+require( ABSPATH . WPINC . '/post-formats.php' );
+require( ABSPATH . WPINC . '/post-thumbnail-template.php' );
+require( ABSPATH . WPINC . '/category.php' );
+require( ABSPATH . WPINC . '/category-template.php' );
+require( ABSPATH . WPINC . '/comment.php' );
+require( ABSPATH . WPINC . '/comment-template.php' );
+require( ABSPATH . WPINC . '/rewrite.php' );
+require( ABSPATH . WPINC . '/feed.php' );
+require( ABSPATH . WPINC . '/bookmark.php' );
+require( ABSPATH . WPINC . '/bookmark-template.php' );
+require( ABSPATH . WPINC . '/kses.php' );
+require( ABSPATH . WPINC . '/cron.php' );
+require( ABSPATH . WPINC . '/deprecated.php' );
+require( ABSPATH . WPINC . '/script-loader.php' );
+require( ABSPATH . WPINC . '/taxonomy.php' );
+require( ABSPATH . WPINC . '/update.php' );
+require( ABSPATH . WPINC . '/canonical.php' );
+require( ABSPATH . WPINC . '/shortcodes.php' );
+require( ABSPATH . WPINC . '/class-wp-embed.php' );
+require( ABSPATH . WPINC . '/media.php' );
+require( ABSPATH . WPINC . '/http.php' );
+require( ABSPATH . WPINC . '/class-http.php' );
+require( ABSPATH . WPINC . '/widgets.php' );
+require( ABSPATH . WPINC . '/nav-menu.php' );
+require( ABSPATH . WPINC . '/nav-menu-template.php' );
+require( ABSPATH . WPINC . '/admin-bar.php' );
+
+// Load multisite-specific files.
+if ( is_multisite() ) {
+ require( ABSPATH . WPINC . '/ms-functions.php' );
+ require( ABSPATH . WPINC . '/ms-default-filters.php' );
+ require( ABSPATH . WPINC . '/ms-deprecated.php' );
+}
+
+// Define constants that rely on the API to obtain the default value.
+// Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in.
+wp_plugin_directory_constants();
+
+// Load must-use plugins.
+foreach ( wp_get_mu_plugins() as $mu_plugin ) {
+ include_once( $mu_plugin );
+}
+unset( $mu_plugin );
+
+// Load network activated plugins.
+if ( is_multisite() ) {
+ foreach( wp_get_active_network_plugins() as $network_plugin ) {
+ include_once( $network_plugin );
+ }
+ unset( $network_plugin );
+}
+
+do_action( 'muplugins_loaded' );
+
+if ( is_multisite() )
+ ms_cookie_constants( );
+
+// Define constants after multisite is loaded. Cookie-related constants may be overridden in ms_network_cookies().
+wp_cookie_constants();
+
+// Define and enforce our SSL constants
+wp_ssl_constants();
+
+// Create common globals.
+require( ABSPATH . WPINC . '/vars.php' );
+
+// Make taxonomies and posts available to plugins and themes.
+// @plugin authors: warning: these get registered again on the init hook.
+create_initial_taxonomies();
+create_initial_post_types();
+
+// Register the default theme directory root
+register_theme_directory( get_theme_root() );
+
+// Load active plugins.
+foreach ( wp_get_active_and_valid_plugins() as $plugin )
+ include_once( $plugin );
+unset( $plugin );
+
+// Load pluggable functions.
+require( ABSPATH . WPINC . '/pluggable.php' );
+require( ABSPATH . WPINC . '/pluggable-deprecated.php' );
+
+// Set internal encoding.
+wp_set_internal_encoding();
+
+// Run wp_cache_postload() if object cache is enabled and the function exists.
+if ( WP_CACHE && function_exists( 'wp_cache_postload' ) )
+ wp_cache_postload();
+
+do_action( 'plugins_loaded' );
+
+// Define constants which affect functionality if not already defined.
+wp_functionality_constants();
+
+// Add magic quotes and set up $_REQUEST ( $_GET + $_POST )
+wp_magic_quotes();
+
+do_action( 'sanitize_comment_cookies' );
+
+/**
+ * WordPress Query object
+ * @global object $wp_the_query
+ * @since 2.0.0
+ */
+$wp_the_query = new WP_Query();
+
+/**
+ * Holds the reference to @see $wp_the_query
+ * Use this global for WordPress queries
+ * @global object $wp_query
+ * @since 1.5.0
+ */
+$wp_query = $wp_the_query;
+
+/**
+ * Holds the WordPress Rewrite object for creating pretty URLs
+ * @global object $wp_rewrite
+ * @since 1.5.0
+ */
+$GLOBALS['wp_rewrite'] = new WP_Rewrite();
+
+/**
+ * WordPress Object
+ * @global object $wp
+ * @since 2.0.0
+ */
+$wp = new WP();
+
+/**
+ * WordPress Widget Factory Object
+ * @global object $wp_widget_factory
+ * @since 2.8.0
+ */
+$GLOBALS['wp_widget_factory'] = new WP_Widget_Factory();
+
+/**
+ * WordPress User Roles
+ * @global object $wp_roles
+ * @since 2.0.0
+ */
+$GLOBALS['wp_roles'] = new WP_Roles();
+
+do_action( 'setup_theme' );
+
+// Define the template related constants.
+wp_templating_constants( );
+
+// Load the default text localization domain.
+load_default_textdomain();
+
+$locale = get_locale();
+$locale_file = WP_LANG_DIR . "/$locale.php";
+if ( ( 0 === validate_file( $locale ) ) && is_readable( $locale_file ) )
+ require( $locale_file );
+unset( $locale_file );
+
+// Pull in locale data after loading text domain.
+require_once( ABSPATH . WPINC . '/locale.php' );
+
+/**
+ * WordPress Locale object for loading locale domain date and various strings.
+ * @global object $wp_locale
+ * @since 2.1.0
+ */
+$GLOBALS['wp_locale'] = new WP_Locale();
+
+// Load the functions for the active theme, for both parent and child theme if applicable.
+if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) {
+ if ( TEMPLATEPATH !== STYLESHEETPATH && file_exists( STYLESHEETPATH . '/functions.php' ) )
+ include( STYLESHEETPATH . '/functions.php' );
+ if ( file_exists( TEMPLATEPATH . '/functions.php' ) )
+ include( TEMPLATEPATH . '/functions.php' );
+}
+
+do_action( 'after_setup_theme' );
+
+// Set up current user.
+$wp->init();
+
+/**
+ * Most of WP is loaded at this stage, and the user is authenticated. WP continues
+ * to load on the init hook that follows (e.g. widgets), and many plugins instantiate
+ * themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.).
+ *
+ * If you wish to plug an action once WP is loaded, use the wp_loaded hook below.
+ */
+do_action( 'init' );
+
+// Check site status
+if ( is_multisite() ) {
+ if ( true !== ( $file = ms_site_check() ) ) {
+ require( $file );
+ die();
+ }
+ unset($file);
+}
+
+/**
+ * This hook is fired once WP, all plugins, and the theme are fully loaded and instantiated.
+ *
+ * AJAX requests should use wp-admin/admin-ajax.php. admin-ajax.php can handle requests for
+ * users not logged in.
+ *
+ * @link http://codex.wordpress.org/AJAX_in_Plugins
+ *
+ * @since 3.0.0
+ */
+do_action('wp_loaded');
diff --git a/src/wp-signup.php b/src/wp-signup.php
new file mode 100644
index 0000000000..9dd2c3da95
--- /dev/null
+++ b/src/wp-signup.php
@@ -0,0 +1,584 @@
+<?php
+
+/** Sets up the WordPress Environment. */
+require( dirname(__FILE__) . '/wp-load.php' );
+
+add_action( 'wp_head', 'wp_no_robots' );
+
+require( './wp-blog-header.php' );
+
+if ( is_array( get_site_option( 'illegal_names' )) && isset( $_GET[ 'new' ] ) && in_array( $_GET[ 'new' ], get_site_option( 'illegal_names' ) ) == true ) {
+ wp_redirect( network_home_url() );
+ die();
+}
+
+/**
+ * Prints signup_header via wp_head
+ *
+ * @since MU
+ */
+function do_signup_header() {
+ do_action( 'signup_header' );
+}
+add_action( 'wp_head', 'do_signup_header' );
+
+if ( !is_multisite() ) {
+ wp_redirect( site_url('wp-login.php?action=register') );
+ die();
+}
+
+if ( !is_main_site() ) {
+ wp_redirect( network_site_url( 'wp-signup.php' ) );
+ die();
+}
+
+// Fix for page title
+$wp_query->is_404 = false;
+
+/**
+ * Prints styles for front-end Multisite signup pages
+ *
+ * @since MU
+ */
+function wpmu_signup_stylesheet() {
+ ?>
+ <style type="text/css">
+ .mu_register { width: 90%; margin:0 auto; }
+ .mu_register form { margin-top: 2em; }
+ .mu_register .error { font-weight:700; padding:10px; color:#333333; background:#FFEBE8; border:1px solid #CC0000; }
+ .mu_register input[type="submit"],
+ .mu_register #blog_title,
+ .mu_register #user_email,
+ .mu_register #blogname,
+ .mu_register #user_name { width:100%; font-size: 24px; margin:5px 0; }
+ .mu_register .prefix_address,
+ .mu_register .suffix_address {font-size: 18px;display:inline; }
+ .mu_register label { font-weight:700; font-size:15px; display:block; margin:10px 0; }
+ .mu_register label.checkbox { display:inline; }
+ .mu_register .mu_alert { font-weight:700; padding:10px; color:#333333; background:#ffffe0; border:1px solid #e6db55; }
+ </style>
+ <?php
+}
+
+add_action( 'wp_head', 'wpmu_signup_stylesheet' );
+get_header();
+
+do_action( 'before_signup_form' );
+?>
+<div id="content" class="widecolumn">
+<div class="mu_register">
+<?php
+/**
+ * Generates and displays the Signup and Create Site forms
+ *
+ * @since MU
+ *
+ * @param string $blogname The new site name
+ * @param string $blog_title The new site title
+ * @param array $errors
+ */
+function show_blog_form($blogname = '', $blog_title = '', $errors = '') {
+ global $current_site;
+ // Blog name
+ if ( !is_subdomain_install() )
+ echo '<label for="blogname">' . __('Site Name:') . '</label>';
+ else
+ echo '<label for="blogname">' . __('Site Domain:') . '</label>';
+
+ if ( $errmsg = $errors->get_error_message('blogname') ) { ?>
+ <p class="error"><?php echo $errmsg ?></p>
+ <?php }
+
+ if ( !is_subdomain_install() )
+ echo '<span class="prefix_address">' . $current_site->domain . $current_site->path . '</span><input name="blogname" type="text" id="blogname" value="'. esc_attr($blogname) .'" maxlength="60" /><br />';
+ else
+ echo '<input name="blogname" type="text" id="blogname" value="'.esc_attr($blogname).'" maxlength="60" /><span class="suffix_address">.' . ( $site_domain = preg_replace( '|^www\.|', '', $current_site->domain ) ) . '</span><br />';
+
+ if ( !is_user_logged_in() ) {
+ if ( !is_subdomain_install() )
+ $site = $current_site->domain . $current_site->path . __( 'sitename' );
+ else
+ $site = __( 'domain' ) . '.' . $site_domain . $current_site->path;
+ echo '<p>(<strong>' . sprintf( __('Your address will be %s.'), $site ) . '</strong>) ' . __( 'Must be at least 4 characters, letters and numbers only. It cannot be changed, so choose carefully!' ) . '</p>';
+ }
+
+ // Blog Title
+ ?>
+ <label for="blog_title"><?php _e('Site Title:') ?></label>
+ <?php if ( $errmsg = $errors->get_error_message('blog_title') ) { ?>
+ <p class="error"><?php echo $errmsg ?></p>
+ <?php }
+ echo '<input name="blog_title" type="text" id="blog_title" value="'.esc_attr($blog_title).'" />';
+ ?>
+
+ <div id="privacy">
+ <p class="privacy-intro">
+ <label for="blog_public_on"><?php _e('Privacy:') ?></label>
+ <?php _e( 'Allow search engines to index this site.' ); ?>
+ <br style="clear:both" />
+ <label class="checkbox" for="blog_public_on">
+ <input type="radio" id="blog_public_on" name="blog_public" value="1" <?php if ( !isset( $_POST['blog_public'] ) || $_POST['blog_public'] == '1' ) { ?>checked="checked"<?php } ?> />
+ <strong><?php _e( 'Yes' ); ?></strong>
+ </label>
+ <label class="checkbox" for="blog_public_off">
+ <input type="radio" id="blog_public_off" name="blog_public" value="0" <?php if ( isset( $_POST['blog_public'] ) && $_POST['blog_public'] == '0' ) { ?>checked="checked"<?php } ?> />
+ <strong><?php _e( 'No' ); ?></strong>
+ </label>
+ </p>
+ </div>
+
+ <?php
+ do_action('signup_blogform', $errors);
+}
+
+/**
+ * Validate the new site signup
+ *
+ * @since MU
+ *
+ * @uses wp_get_current_user() to retrieve the current user
+ * @uses wpmu_validate_blog_signup() to validate new site signup for the current user
+ * @return array Contains the new site data and error messages.
+ */
+function validate_blog_form() {
+ $user = '';
+ if ( is_user_logged_in() )
+ $user = wp_get_current_user();
+
+ return wpmu_validate_blog_signup($_POST['blogname'], $_POST['blog_title'], $user);
+}
+
+/**
+ * Display user registration form
+ *
+ * @since MU
+ *
+ * @param string $user_name The entered username
+ * @param string $user_email The entered email address
+ * @param array $errors
+ */
+function show_user_form($user_name = '', $user_email = '', $errors = '') {
+ // User name
+ echo '<label for="user_name">' . __('Username:') . '</label>';
+ if ( $errmsg = $errors->get_error_message('user_name') ) {
+ echo '<p class="error">'.$errmsg.'</p>';
+ }
+ echo '<input name="user_name" type="text" id="user_name" value="'. esc_attr($user_name) .'" maxlength="60" /><br />';
+ _e( '(Must be at least 4 characters, letters and numbers only.)' );
+ ?>
+
+ <label for="user_email"><?php _e( 'Email&nbsp;Address:' ) ?></label>
+ <?php if ( $errmsg = $errors->get_error_message('user_email') ) { ?>
+ <p class="error"><?php echo $errmsg ?></p>
+ <?php } ?>
+ <input name="user_email" type="text" id="user_email" value="<?php echo esc_attr($user_email) ?>" maxlength="200" /><br /><?php _e('We send your registration email to this address. (Double-check your email address before continuing.)') ?>
+ <?php
+ if ( $errmsg = $errors->get_error_message('generic') ) {
+ echo '<p class="error">' . $errmsg . '</p>';
+ }
+ do_action( 'signup_extra_fields', $errors );
+}
+
+/**
+ * Validate user signup name and email
+ *
+ * @since MU
+ *
+ * @uses wpmu_validate_user_signup() to retrieve an array of user data
+ * @return array Contains username, email, and error messages.
+ */
+function validate_user_form() {
+ return wpmu_validate_user_signup($_POST['user_name'], $_POST['user_email']);
+}
+
+/**
+ * Allow returning users to sign up for another site
+ *
+ * @since MU
+ *
+ * @uses wp_get_current_user() to get the current user
+ * @param string $blogname The new site name
+ * @param string $blog_title The new blog title
+ * @param array $errors
+ */
+function signup_another_blog($blogname = '', $blog_title = '', $errors = '') {
+ global $current_site;
+ $current_user = wp_get_current_user();
+
+ if ( ! is_wp_error($errors) ) {
+ $errors = new WP_Error();
+ }
+
+ // allow definition of default variables
+ $filtered_results = apply_filters('signup_another_blog_init', array('blogname' => $blogname, 'blog_title' => $blog_title, 'errors' => $errors ));
+ $blogname = $filtered_results['blogname'];
+ $blog_title = $filtered_results['blog_title'];
+ $errors = $filtered_results['errors'];
+
+ echo '<h2>' . sprintf( __( 'Get <em>another</em> %s site in seconds' ), $current_site->site_name ) . '</h2>';
+
+ if ( $errors->get_error_code() ) {
+ echo '<p>' . __( 'There was a problem, please correct the form below and try again.' ) . '</p>';
+ }
+ ?>
+ <p><?php printf( __( 'Welcome back, %s. By filling out the form below, you can <strong>add another site to your account</strong>. There is no limit to the number of sites you can have, so create to your heart&#8217;s content, but write responsibly!' ), $current_user->display_name ) ?></p>
+
+ <?php
+ $blogs = get_blogs_of_user($current_user->ID);
+ if ( !empty($blogs) ) { ?>
+
+ <p><?php _e( 'Sites you are already a member of:' ) ?></p>
+ <ul>
+ <?php foreach ( $blogs as $blog ) {
+ $home_url = get_home_url( $blog->userblog_id );
+ echo '<li><a href="' . esc_url( $home_url ) . '">' . $home_url . '</a></li>';
+ } ?>
+ </ul>
+ <?php } ?>
+
+ <p><?php _e( 'If you&#8217;re not going to use a great site domain, leave it for a new user. Now have at it!' ) ?></p>
+ <form id="setupform" method="post" action="wp-signup.php">
+ <input type="hidden" name="stage" value="gimmeanotherblog" />
+ <?php do_action( 'signup_hidden_fields' ); ?>
+ <?php show_blog_form($blogname, $blog_title, $errors); ?>
+ <p class="submit"><input type="submit" name="submit" class="submit" value="<?php esc_attr_e( 'Create Site' ) ?>" /></p>
+ </form>
+ <?php
+}
+
+/**
+ * Validate a new blog signup
+ *
+ * @since MU
+ *
+ * @uses wp_get_current_user() to retrieve the current user
+ * @uses wpmu_create_blog() to add a new site
+ * @uses confirm_another_blog_signup() to confirm the user's new site signup
+ * @return bool True if blog signup was validated, false if error
+ */
+function validate_another_blog_signup() {
+ global $wpdb, $blogname, $blog_title, $errors, $domain, $path;
+ $current_user = wp_get_current_user();
+ if ( !is_user_logged_in() )
+ die();
+
+ $result = validate_blog_form();
+ extract($result);
+
+ if ( $errors->get_error_code() ) {
+ signup_another_blog($blogname, $blog_title, $errors);
+ return false;
+ }
+
+ $public = (int) $_POST['blog_public'];
+ $meta = apply_filters( 'signup_create_blog_meta', array( 'lang_id' => 1, 'public' => $public ) ); // deprecated
+ $meta = apply_filters( 'add_signup_meta', $meta );
+
+ wpmu_create_blog( $domain, $path, $blog_title, $current_user->ID, $meta, $wpdb->siteid );
+ confirm_another_blog_signup($domain, $path, $blog_title, $current_user->user_login, $current_user->user_email, $meta);
+ return true;
+}
+
+/**
+ * Confirm a new site signup
+ *
+ * @since MU
+ *
+ * @param string $domain The domain URL
+ * @param string $path The site root path
+ * @param string $user_name The username
+ * @param string $user_email The user's email address
+ * @param array $meta Any additional meta from the 'add_signup_meta' filter in validate_blog_signup()
+ */
+function confirm_another_blog_signup( $domain, $path, $blog_title, $user_name, $user_email = '', $meta = array() ) {
+ ?>
+ <h2><?php printf( __( 'The site %s is yours.' ), "<a href='http://{$domain}{$path}'>{$blog_title}</a>" ) ?></h2>
+ <p>
+ <?php printf( __( '<a href="http://%1$s">http://%2$s</a> is your new site. <a href="%3$s">Log in</a> as &#8220;%4$s&#8221; using your existing password.' ), $domain.$path, $domain.$path, "http://" . $domain.$path . "wp-login.php", $user_name ) ?>
+ </p>
+ <?php
+ do_action( 'signup_finished' );
+}
+
+/**
+ * Setup the new user signup process
+ *
+ * @since MU
+ *
+ * @uses apply_filters() filter $filtered_results
+ * @uses show_user_form() to display the user registration form
+ * @param string $user_name The username
+ * @param string $user_email The user's email
+ * @param array $errors
+ */
+function signup_user($user_name = '', $user_email = '', $errors = '') {
+ global $current_site, $active_signup;
+
+ if ( !is_wp_error($errors) )
+ $errors = new WP_Error();
+
+ $signup_for = isset( $_POST[ 'signup_for' ] ) ? esc_html( $_POST[ 'signup_for' ] ) : 'blog';
+
+ // allow definition of default variables
+ $filtered_results = apply_filters('signup_user_init', array('user_name' => $user_name, 'user_email' => $user_email, 'errors' => $errors ));
+ $user_name = $filtered_results['user_name'];
+ $user_email = $filtered_results['user_email'];
+ $errors = $filtered_results['errors'];
+
+ ?>
+
+ <h2><?php printf( __( 'Get your own %s account in seconds' ), $current_site->site_name ) ?></h2>
+ <form id="setupform" method="post" action="wp-signup.php">
+ <input type="hidden" name="stage" value="validate-user-signup" />
+ <?php do_action( 'signup_hidden_fields' ); ?>
+ <?php show_user_form($user_name, $user_email, $errors); ?>
+
+ <p>
+ <?php if ( $active_signup == 'blog' ) { ?>
+ <input id="signupblog" type="hidden" name="signup_for" value="blog" />
+ <?php } elseif ( $active_signup == 'user' ) { ?>
+ <input id="signupblog" type="hidden" name="signup_for" value="user" />
+ <?php } else { ?>
+ <input id="signupblog" type="radio" name="signup_for" value="blog" <?php checked( $signup_for, 'blog' ); ?> />
+ <label class="checkbox" for="signupblog"><?php _e('Gimme a site!') ?></label>
+ <br />
+ <input id="signupuser" type="radio" name="signup_for" value="user" <?php checked( $signup_for, 'user' ); ?> />
+ <label class="checkbox" for="signupuser"><?php _e('Just a username, please.') ?></label>
+ <?php } ?>
+ </p>
+
+ <p class="submit"><input type="submit" name="submit" class="submit" value="<?php esc_attr_e('Next') ?>" /></p>
+ </form>
+ <?php
+}
+
+/**
+ * Validate the new user signup
+ *
+ * @since MU
+ *
+ * @uses validate_user_form() to retrieve an array of the user data
+ * @uses wpmu_signup_user() to signup the new user
+ * @uses confirm_user_signup() to confirm the new user signup
+ * @return bool True if new user signup was validated, false if error
+ */
+function validate_user_signup() {
+ $result = validate_user_form();
+ extract($result);
+
+ if ( $errors->get_error_code() ) {
+ signup_user($user_name, $user_email, $errors);
+ return false;
+ }
+
+ if ( 'blog' == $_POST['signup_for'] ) {
+ signup_blog($user_name, $user_email);
+ return false;
+ }
+
+ wpmu_signup_user($user_name, $user_email, apply_filters( 'add_signup_meta', array() ) );
+
+ confirm_user_signup($user_name, $user_email);
+ return true;
+}
+
+/**
+ * New user signup confirmation
+ *
+ * @since MU
+ *
+ * @param string $user_name The username
+ * @param string $user_email The user's email address
+ */
+function confirm_user_signup($user_name, $user_email) {
+ ?>
+ <h2><?php printf( __( '%s is your new username' ), $user_name) ?></h2>
+ <p><?php _e( 'But, before you can start using your new username, <strong>you must activate it</strong>.' ) ?></p>
+ <p><?php printf( __( 'Check your inbox at <strong>%s</strong> and click the link given.' ), $user_email ); ?></p>
+ <p><?php _e( 'If you do not activate your username within two days, you will have to sign up again.' ); ?></p>
+ <?php
+ do_action( 'signup_finished' );
+}
+
+/**
+ * Setup the new site signup
+ *
+ * @since MU
+ *
+ * @uses apply_filters() to filter $filtered_results
+ * @uses show_blog_form() to display the blog signup form
+ * @param string $user_name The username
+ * @param string $user_email The user's email address
+ * @param string $blogname The site name
+ * @param string $blog_title The site title
+ * @param array $errors
+ */
+function signup_blog($user_name = '', $user_email = '', $blogname = '', $blog_title = '', $errors = '') {
+ if ( !is_wp_error($errors) )
+ $errors = new WP_Error();
+
+ // allow definition of default variables
+ $filtered_results = apply_filters('signup_blog_init', array('user_name' => $user_name, 'user_email' => $user_email, 'blogname' => $blogname, 'blog_title' => $blog_title, 'errors' => $errors ));
+ $user_name = $filtered_results['user_name'];
+ $user_email = $filtered_results['user_email'];
+ $blogname = $filtered_results['blogname'];
+ $blog_title = $filtered_results['blog_title'];
+ $errors = $filtered_results['errors'];
+
+ if ( empty($blogname) )
+ $blogname = $user_name;
+ ?>
+ <form id="setupform" method="post" action="wp-signup.php">
+ <input type="hidden" name="stage" value="validate-blog-signup" />
+ <input type="hidden" name="user_name" value="<?php echo esc_attr($user_name) ?>" />
+ <input type="hidden" name="user_email" value="<?php echo esc_attr($user_email) ?>" />
+ <?php do_action( 'signup_hidden_fields' ); ?>
+ <?php show_blog_form($blogname, $blog_title, $errors); ?>
+ <p class="submit"><input type="submit" name="submit" class="submit" value="<?php esc_attr_e('Signup') ?>" /></p>
+ </form>
+ <?php
+}
+
+/**
+ * Validate new site signup
+ *
+ * @since MU
+ *
+ * @uses wpmu_validate_user_signup() to retrieve an array of the new user data and errors
+ * @uses wpmu_validate_blog_signup() to retrieve an array of the new site data and errors
+ * @uses apply_filters() to make signup $meta filterable
+ * @uses signup_user() to signup a new user
+ * @uses signup_blog() to signup a the new user to a new site
+ * @return bool True if the site signup was validated, false if error
+ */
+function validate_blog_signup() {
+ // Re-validate user info.
+ $result = wpmu_validate_user_signup($_POST['user_name'], $_POST['user_email']);
+ extract($result);
+
+ if ( $errors->get_error_code() ) {
+ signup_user($user_name, $user_email, $errors);
+ return false;
+ }
+
+ $result = wpmu_validate_blog_signup($_POST['blogname'], $_POST['blog_title']);
+ extract($result);
+
+ if ( $errors->get_error_code() ) {
+ signup_blog($user_name, $user_email, $blogname, $blog_title, $errors);
+ return false;
+ }
+
+ $public = (int) $_POST['blog_public'];
+ $meta = array ('lang_id' => 1, 'public' => $public);
+ $meta = apply_filters( 'add_signup_meta', $meta );
+
+ wpmu_signup_blog($domain, $path, $blog_title, $user_name, $user_email, $meta);
+ confirm_blog_signup($domain, $path, $blog_title, $user_name, $user_email, $meta);
+ return true;
+}
+
+/**
+ * New site signup confirmation
+ *
+ * @since MU
+ *
+ * @param string $domain The domain URL
+ * @param string $path The site root path
+ * @param string $blog_title The new site title
+ * @param string $user_name The user's username
+ * @param string $user_email The user's email address
+ * @param array $meta Any additional meta from the 'add_signup_meta' filter in validate_blog_signup()
+ */
+function confirm_blog_signup( $domain, $path, $blog_title, $user_name = '', $user_email = '', $meta = array() ) {
+ ?>
+ <h2><?php printf( __( 'Congratulations! Your new site, %s, is almost ready.' ), "<a href='http://{$domain}{$path}'>{$blog_title}</a>" ) ?></h2>
+
+ <p><?php _e( 'But, before you can start using your site, <strong>you must activate it</strong>.' ) ?></p>
+ <p><?php printf( __( 'Check your inbox at <strong>%s</strong> and click the link given.' ), $user_email) ?></p>
+ <p><?php _e( 'If you do not activate your site within two days, you will have to sign up again.' ); ?></p>
+ <h2><?php _e( 'Still waiting for your email?' ); ?></h2>
+ <p>
+ <?php _e( 'If you haven&#8217;t received your email yet, there are a number of things you can do:' ) ?>
+ <ul id="noemail-tips">
+ <li><p><strong><?php _e( 'Wait a little longer. Sometimes delivery of email can be delayed by processes outside of our control.' ) ?></strong></p></li>
+ <li><p><?php _e( 'Check the junk or spam folder of your email client. Sometime emails wind up there by mistake.' ) ?></p></li>
+ <li><?php printf( __( 'Have you entered your email correctly? You have entered %s, if it&#8217;s incorrect, you will not receive your email.' ), $user_email ) ?></li>
+ </ul>
+ </p>
+ <?php
+ do_action( 'signup_finished' );
+}
+
+// Main
+$active_signup = get_site_option( 'registration' );
+if ( !$active_signup )
+ $active_signup = 'all';
+
+$active_signup = apply_filters( 'wpmu_active_signup', $active_signup ); // return "all", "none", "blog" or "user"
+
+// Make the signup type translatable.
+$i18n_signup['all'] = _x('all', 'Multisite active signup type');
+$i18n_signup['none'] = _x('none', 'Multisite active signup type');
+$i18n_signup['blog'] = _x('blog', 'Multisite active signup type');
+$i18n_signup['user'] = _x('user', 'Multisite active signup type');
+
+if ( is_super_admin() )
+ echo '<div class="mu_alert">' . sprintf( __( 'Greetings Site Administrator! You are currently allowing &#8220;%s&#8221; registrations. To change or disable registration go to your <a href="%s">Options page</a>.' ), $i18n_signup[$active_signup], esc_url( network_admin_url( 'settings.php' ) ) ) . '</div>';
+
+$newblogname = isset($_GET['new']) ? strtolower(preg_replace('/^-|-$|[^-a-zA-Z0-9]/', '', $_GET['new'])) : null;
+
+$current_user = wp_get_current_user();
+if ( $active_signup == 'none' ) {
+ _e( 'Registration has been disabled.' );
+} elseif ( $active_signup == 'blog' && !is_user_logged_in() ) {
+ $login_url = site_url( 'wp-login.php?redirect_to=' . urlencode( network_site_url( 'wp-signup.php' ) ) );
+ echo sprintf( __( 'You must first <a href="%s">log in</a>, and then you can create a new site.' ), $login_url );
+} else {
+ $stage = isset( $_POST['stage'] ) ? $_POST['stage'] : 'default';
+ switch ( $stage ) {
+ case 'validate-user-signup' :
+ if ( $active_signup == 'all' || $_POST[ 'signup_for' ] == 'blog' && $active_signup == 'blog' || $_POST[ 'signup_for' ] == 'user' && $active_signup == 'user' )
+ validate_user_signup();
+ else
+ _e( 'User registration has been disabled.' );
+ break;
+ case 'validate-blog-signup':
+ if ( $active_signup == 'all' || $active_signup == 'blog' )
+ validate_blog_signup();
+ else
+ _e( 'Site registration has been disabled.' );
+ break;
+ case 'gimmeanotherblog':
+ validate_another_blog_signup();
+ break;
+ case 'default':
+ default :
+ $user_email = isset( $_POST[ 'user_email' ] ) ? $_POST[ 'user_email' ] : '';
+ do_action( 'preprocess_signup_form' ); // populate the form from invites, elsewhere?
+ if ( is_user_logged_in() && ( $active_signup == 'all' || $active_signup == 'blog' ) )
+ signup_another_blog($newblogname);
+ elseif ( is_user_logged_in() == false && ( $active_signup == 'all' || $active_signup == 'user' ) )
+ signup_user( $newblogname, $user_email );
+ elseif ( is_user_logged_in() == false && ( $active_signup == 'blog' ) )
+ _e( 'Sorry, new registrations are not allowed at this time.' );
+ else
+ _e( 'You are logged in already. No need to register again!' );
+
+ if ( $newblogname ) {
+ $newblog = get_blogaddress_by_name( $newblogname );
+
+ if ( $active_signup == 'blog' || $active_signup == 'all' )
+ printf( '<p><em>' . __( 'The site you were looking for, <strong>%s</strong>, does not exist, but you can create it now!' ) . '</em></p>', $newblog );
+ else
+ printf( '<p><em>' . __( 'The site you were looking for, <strong>%s</strong>, does not exist.' ) . '</em></p>', $newblog );
+ }
+ break;
+ }
+}
+?>
+</div>
+</div>
+<?php do_action( 'after_signup_form' ); ?>
+
+<?php get_footer(); ?>
diff --git a/src/wp-trackback.php b/src/wp-trackback.php
new file mode 100644
index 0000000000..8b41505f2b
--- /dev/null
+++ b/src/wp-trackback.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Handle Trackbacks and Pingbacks sent to WordPress
+ *
+ * @package WordPress
+ */
+
+if (empty($wp)) {
+ require_once('./wp-load.php');
+ wp( array( 'tb' => '1' ) );
+}
+
+/**
+ * trackback_response() - Respond with an error or success XML message
+ *
+ * @param int|bool $error Whether there was an error
+ * @param string $error_message Error message if an error occurred
+ */
+function trackback_response($error = 0, $error_message = '') {
+ header('Content-Type: text/xml; charset=' . get_option('blog_charset') );
+ if ($error) {
+ echo '<?xml version="1.0" encoding="utf-8"?'.">\n";
+ echo "<response>\n";
+ echo "<error>1</error>\n";
+ echo "<message>$error_message</message>\n";
+ echo "</response>";
+ die();
+ } else {
+ echo '<?xml version="1.0" encoding="utf-8"?'.">\n";
+ echo "<response>\n";
+ echo "<error>0</error>\n";
+ echo "</response>";
+ }
+}
+
+// trackback is done by a POST
+$request_array = 'HTTP_POST_VARS';
+
+if ( !isset($_GET['tb_id']) || !$_GET['tb_id'] ) {
+ $tb_id = explode('/', $_SERVER['REQUEST_URI']);
+ $tb_id = intval( $tb_id[ count($tb_id) - 1 ] );
+}
+
+$tb_url = isset($_POST['url']) ? $_POST['url'] : '';
+$charset = isset($_POST['charset']) ? $_POST['charset'] : '';
+
+// These three are stripslashed here so that they can be properly escaped after mb_convert_encoding()
+$title = isset($_POST['title']) ? wp_unslash($_POST['title']) : '';
+$excerpt = isset($_POST['excerpt']) ? wp_unslash($_POST['excerpt']) : '';
+$blog_name = isset($_POST['blog_name']) ? wp_unslash($_POST['blog_name']) : '';
+
+if ($charset)
+ $charset = str_replace( array(',', ' '), '', strtoupper( trim($charset) ) );
+else
+ $charset = 'ASCII, UTF-8, ISO-8859-1, JIS, EUC-JP, SJIS';
+
+// No valid uses for UTF-7
+if ( false !== strpos($charset, 'UTF-7') )
+ die;
+
+if ( function_exists('mb_convert_encoding') ) { // For international trackbacks
+ $title = mb_convert_encoding($title, get_option('blog_charset'), $charset);
+ $excerpt = mb_convert_encoding($excerpt, get_option('blog_charset'), $charset);
+ $blog_name = mb_convert_encoding($blog_name, get_option('blog_charset'), $charset);
+}
+
+// Now that mb_convert_encoding() has been given a swing, we need to escape these three
+$title = wp_slash($title);
+$excerpt = wp_slash($excerpt);
+$blog_name = wp_slash($blog_name);
+
+if ( is_single() || is_page() )
+ $tb_id = $posts[0]->ID;
+
+if ( !isset($tb_id) || !intval( $tb_id ) )
+ trackback_response(1, 'I really need an ID for this to work.');
+
+if (empty($title) && empty($tb_url) && empty($blog_name)) {
+ // If it doesn't look like a trackback at all...
+ wp_redirect(get_permalink($tb_id));
+ exit;
+}
+
+if ( !empty($tb_url) && !empty($title) ) {
+ header('Content-Type: text/xml; charset=' . get_option('blog_charset') );
+
+ if ( !pings_open($tb_id) )
+ trackback_response(1, 'Sorry, trackbacks are closed for this item.');
+
+ $title = wp_html_excerpt( $title, 250, '&#8230;' );
+ $excerpt = wp_html_excerpt( $excerpt, 252, '&#8230;' );
+
+ $comment_post_ID = (int) $tb_id;
+ $comment_author = $blog_name;
+ $comment_author_email = '';
+ $comment_author_url = $tb_url;
+ $comment_content = "<strong>$title</strong>\n\n$excerpt";
+ $comment_type = 'trackback';
+
+ $dupe = $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $comment_post_ID, $comment_author_url) );
+ if ( $dupe )
+ trackback_response(1, 'We already have a ping from that URL for this post.');
+
+ $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_type');
+
+ wp_new_comment($commentdata);
+
+ do_action('trackback_post', $wpdb->insert_id);
+ trackback_response(0);
+}
diff --git a/src/xmlrpc.php b/src/xmlrpc.php
new file mode 100644
index 0000000000..59674df727
--- /dev/null
+++ b/src/xmlrpc.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * XML-RPC protocol support for WordPress
+ *
+ * @package WordPress
+ */
+
+/**
+ * Whether this is an XML-RPC Request
+ *
+ * @var bool
+ */
+define('XMLRPC_REQUEST', true);
+
+// Some browser-embedded clients send cookies. We don't want them.
+$_COOKIE = array();
+
+// A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
+// but we can do it ourself.
+if ( !isset( $HTTP_RAW_POST_DATA ) ) {
+ $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
+}
+
+// fix for mozBlog and other cases where '<?xml' isn't on the very first line
+if ( isset($HTTP_RAW_POST_DATA) )
+ $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
+
+/** Include the bootstrap for setting up WordPress environment */
+include('./wp-load.php');
+
+if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd
+header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
+?>
+<?php echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
+<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
+ <service>
+ <engineName>WordPress</engineName>
+ <engineLink>http://wordpress.org/</engineLink>
+ <homePageLink><?php bloginfo_rss('url') ?></homePageLink>
+ <apis>
+ <api name="WordPress" blogID="1" preferred="true" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
+ <api name="Movable Type" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
+ <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
+ <api name="Blogger" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
+ <?php do_action( 'xmlrpc_rsd_apis' ); ?>
+ </apis>
+ </service>
+</rsd>
+<?php
+exit;
+}
+
+include_once(ABSPATH . 'wp-admin/includes/admin.php');
+include_once(ABSPATH . WPINC . '/class-IXR.php');
+include_once(ABSPATH . WPINC . '/class-wp-xmlrpc-server.php');
+
+/**
+ * Posts submitted via the XML-RPC interface get that title
+ * @name post_default_title
+ * @var string
+ */
+$post_default_title = "";
+
+// Allow for a plugin to insert a different class to handle requests.
+$wp_xmlrpc_server_class = apply_filters('wp_xmlrpc_server_class', 'wp_xmlrpc_server');
+$wp_xmlrpc_server = new $wp_xmlrpc_server_class;
+
+// Fire off the request
+$wp_xmlrpc_server->serve_request();
+
+exit;
+
+/**
+ * logIO() - Writes logging info to a file.
+ *
+ * @deprecated 3.4.0
+ * @deprecated Use error_log()
+ *
+ * @param string $io Whether input or output
+ * @param string $msg Information describing logging reason.
+ */
+function logIO( $io, $msg ) {
+ _deprecated_function( __FUNCTION__, '3.4', 'error_log()' );
+ if ( ! empty( $GLOBALS['xmlrpc_logging'] ) )
+ error_log( $io . ' - ' . $msg );
+} \ No newline at end of file